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

Behdad Esfahbod behdad at kemper.freedesktop.org
Sat Oct 27 04:22:35 UTC 2018


 src/Makefile.am                                                                    |   18 
 src/Makefile.sources                                                               |    3 
 src/gen-vowel-constraints.py                                                       |    4 
 src/hb-aat-layout-common.hh                                                        |    7 
 src/hb-aat-layout-kerx-table.hh                                                    |    4 
 src/hb-aat-layout-morx-table.hh                                                    |   10 
 src/hb-aat-layout.cc                                                               |   15 
 src/hb-aat-layout.hh                                                               |    5 
 src/hb-aat-ltag-table.hh                                                           |   17 
 src/hb-buffer.cc                                                                   |    4 
 src/hb-dsalgs.hh                                                                   |   83 +
 src/hb-face.cc                                                                     |    2 
 src/hb-font.cc                                                                     |   29 
 src/hb-graphite2.cc                                                                |    9 
 src/hb-machinery.hh                                                                |    4 
 src/hb-ot-color-cbdt-table.hh                                                      |    2 
 src/hb-ot-face.cc                                                                  |    1 
 src/hb-ot-face.hh                                                                  |    8 
 src/hb-ot-glyf-table.hh                                                            |    4 
 src/hb-ot-hmtx-table.hh                                                            |    2 
 src/hb-ot-layout-gpos-table.hh                                                     |    2 
 src/hb-ot-math-table.hh                                                            |    2 
 src/hb-ot-maxp-table.hh                                                            |    2 
 src/hb-ot-name-language.cc                                                         |  457 ++++++++++
 src/hb-ot-name-language.hh                                                         |   40 
 src/hb-ot-name-table.hh                                                            |  217 +++-
 src/hb-ot-name.cc                                                                  |  163 +++
 src/hb-ot-name.h                                                                   |   66 +
 src/hb-ot-os2-unicode-ranges.hh                                                    |   10 
 src/hb-ot-shape-complex-arabic-fallback.hh                                         |    6 
 src/hb-ot-shape-complex-arabic.cc                                                  |    6 
 src/hb-ot-shape-complex-hangul.cc                                                  |    2 
 src/hb-ot-shape-complex-indic.cc                                                   |    2 
 src/hb-ot-shape-complex-khmer.cc                                                   |    2 
 src/hb-ot-shape-complex-myanmar.cc                                                 |    6 
 src/hb-ot-shape-complex-use.cc                                                     |    8 
 src/hb-ot-shape-complex-vowel-constraints.cc                                       |    4 
 src/hb-ot-shape-fallback.cc                                                        |    4 
 src/hb-ot-shape-normalize.cc                                                       |    4 
 src/hb-ot-shape.cc                                                                 |    2 
 src/hb-ot-tag.cc                                                                   |    3 
 src/hb-ot-vorg-table.hh                                                            |    2 
 src/hb-set.cc                                                                      |    2 
 src/hb-shape-plan.cc                                                               |    2 
 src/hb-subset.hh                                                                   |    2 
 src/hb-unicode.cc                                                                  |    8 
 src/hb-unicode.hh                                                                  |    2 
 src/hb-utf.hh                                                                      |  241 ++++-
 src/test-name-table.cc                                                             |   67 +
 test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5659690013556736 |binary
 50 files changed, 1374 insertions(+), 191 deletions(-)

New commits:
commit 79b2fa62ca7eb5a875778d3a2ecae63350083ba3
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri Oct 26 21:21:18 2018 -0700

    [indic] Fix infinite loop
    
    Fixes https://bugs.chromium.org/p/chromium/issues/detail?id=863044

diff --git a/src/hb-ot-shape-complex-indic.cc b/src/hb-ot-shape-complex-indic.cc
index f145a34c..918e0d7e 100644
--- a/src/hb-ot-shape-complex-indic.cc
+++ b/src/hb-ot-shape-complex-indic.cc
@@ -789,7 +789,7 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
      * We could use buffer->sort() for this, if there was no special
      * reordering of pre-base stuff happening later...
      */
-    if (indic_plan->is_old_spec || end - base > 127)
+    if (indic_plan->is_old_spec || end - start > 127)
       buffer->merge_clusters (base, end);
     else
     {
commit 39bd07aed5fe6ccddde53206bafceec32d56dcc1
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri Oct 26 21:01:11 2018 -0700

    Fix bunch of unused parameter warnings
    
    Show up with gcc -O0.
    
    There's a few more but those are functions that need to be filled in.
    
    Maybe this is a lost battle...

diff --git a/src/gen-vowel-constraints.py b/src/gen-vowel-constraints.py
index 02a338fa..c4e75aa9 100755
--- a/src/gen-vowel-constraints.py
+++ b/src/gen-vowel-constraints.py
@@ -176,9 +176,9 @@ print ('}')
 print ()
 
 print ('void')
-print ('_hb_preprocess_text_vowel_constraints (const hb_ot_shape_plan_t *plan,')
+print ('_hb_preprocess_text_vowel_constraints (const hb_ot_shape_plan_t *plan HB_UNUSED,')
 print ('\t\t\t\t       hb_buffer_t              *buffer,')
-print ('\t\t\t\t       hb_font_t                *font)')
+print ('\t\t\t\t       hb_font_t                *font HB_UNUSED)')
 print ('{')
 print ('  /* UGLY UGLY UGLY business of adding dotted-circle in the middle of')
 print ('   * vowel-sequences that look like another vowel.  Data for each script')
diff --git a/src/hb-aat-layout-common.hh b/src/hb-aat-layout-common.hh
index 406a36d8..ce40abd5 100644
--- a/src/hb-aat-layout-common.hh
+++ b/src/hb-aat-layout-common.hh
@@ -377,7 +377,10 @@ struct Entry
     /* Note, we don't recurse-sanitize data because we don't access it.
      * That said, in our DEFINE_SIZE_STATIC we access T::static_size,
      * which ensures that data has a simple sanitize(). To be determined
-     * if I need to remove that as well. */
+     * if I need to remove that as well.
+     *
+     * XXX Because we are a template, our DEFINE_SIZE_STATIC assertion
+     * wouldn't be checked. */
     return_trace (c->check_struct (this));
   }
 
@@ -394,7 +397,7 @@ struct Entry
 template <>
 struct Entry<void>
 {
-  inline bool sanitize (hb_sanitize_context_t *c, unsigned int count) const
+  inline bool sanitize (hb_sanitize_context_t *c, unsigned int count /*XXX Unused?*/) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this));
diff --git a/src/hb-aat-layout-kerx-table.hh b/src/hb-aat-layout-kerx-table.hh
index 960c37e1..a8831250 100644
--- a/src/hb-aat-layout-kerx-table.hh
+++ b/src/hb-aat-layout-kerx-table.hh
@@ -163,7 +163,7 @@ struct KerxSubTableFormat1
 	kernAction (&table->machine + table->kernAction),
 	depth (0) {}
 
-    inline bool is_actionable (StateTableDriver<EntryData> *driver,
+    inline bool is_actionable (StateTableDriver<EntryData> *driver HB_UNUSED,
 			       const Entry<EntryData> *entry)
     {
       return entry->data.kernActionIndex != 0xFFFF;
@@ -365,7 +365,7 @@ struct KerxSubTableFormat4
 	mark_set (false),
 	mark (0) {}
 
-    inline bool is_actionable (StateTableDriver<EntryData> *driver,
+    inline bool is_actionable (StateTableDriver<EntryData> *driver HB_UNUSED,
 			       const Entry<EntryData> *entry)
     {
       return entry->data.ankrActionIndex != 0xFFFF;
diff --git a/src/hb-aat-layout-morx-table.hh b/src/hb-aat-layout-morx-table.hh
index 84e321ed..22a99443 100644
--- a/src/hb-aat-layout-morx-table.hh
+++ b/src/hb-aat-layout-morx-table.hh
@@ -65,11 +65,11 @@ struct RearrangementSubtable
       Verb		= 0x000F,	/* The type of rearrangement specified. */
     };
 
-    inline driver_context_t (const RearrangementSubtable *table) :
+    inline driver_context_t (const RearrangementSubtable *table HB_UNUSED) :
 	ret (false),
 	start (0), end (0) {}
 
-    inline bool is_actionable (StateTableDriver<EntryData> *driver,
+    inline bool is_actionable (StateTableDriver<EntryData> *driver HB_UNUSED,
 			       const Entry<EntryData> *entry)
     {
       return (entry->flags & Verb) && start < end;
@@ -363,7 +363,7 @@ struct LigatureSubtable
 	ligature (table+table->ligature),
 	match_length (0) {}
 
-    inline bool is_actionable (StateTableDriver<EntryData> *driver,
+    inline bool is_actionable (StateTableDriver<EntryData> *driver HB_UNUSED,
 			       const Entry<EntryData> *entry)
     {
       return entry->flags & PerformAction;
@@ -620,7 +620,7 @@ struct InsertionSubtable
 	mark (0),
 	insertionAction (table+table->insertionAction) {}
 
-    inline bool is_actionable (StateTableDriver<EntryData> *driver,
+    inline bool is_actionable (StateTableDriver<EntryData> *driver HB_UNUSED,
 			       const Entry<EntryData> *entry)
     {
       return (entry->flags & (CurrentInsertCount | MarkedInsertCount)) &&
@@ -937,7 +937,7 @@ struct Chain
 
   inline unsigned int get_size (void) const { return length; }
 
-  inline bool sanitize (hb_sanitize_context_t *c, unsigned int version) const
+  inline bool sanitize (hb_sanitize_context_t *c, unsigned int version HB_UNUSED) const
   {
     TRACE_SANITIZE (this);
     if (!length.sanitize (c) ||
diff --git a/src/hb-face.cc b/src/hb-face.cc
index bba1ee3f..74c77721 100644
--- a/src/hb-face.cc
+++ b/src/hb-face.cc
@@ -666,7 +666,7 @@ _hb_face_builder_data_reference_blob (hb_face_builder_data_t *data)
 }
 
 static hb_blob_t *
-_hb_face_builder_reference_table (hb_face_t *face, hb_tag_t tag, void *user_data)
+_hb_face_builder_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
 {
   hb_face_builder_data_t *data = (hb_face_builder_data_t *) user_data;
 
diff --git a/src/hb-font.cc b/src/hb-font.cc
index b6b668dd..e38c2fbd 100644
--- a/src/hb-font.cc
+++ b/src/hb-font.cc
@@ -89,7 +89,7 @@ hb_font_get_font_v_extents_default (hb_font_t *font,
 static hb_bool_t
 hb_font_get_nominal_glyph_nil (hb_font_t *font HB_UNUSED,
 			       void *font_data HB_UNUSED,
-			       hb_codepoint_t unicode,
+			       hb_codepoint_t unicode HB_UNUSED,
 			       hb_codepoint_t *glyph,
 			       void *user_data HB_UNUSED)
 {
@@ -142,8 +142,8 @@ hb_font_get_nominal_glyphs_default (hb_font_t *font,
 static hb_bool_t
 hb_font_get_variation_glyph_nil (hb_font_t *font HB_UNUSED,
 				 void *font_data HB_UNUSED,
-				 hb_codepoint_t unicode,
-				 hb_codepoint_t variation_selector,
+				 hb_codepoint_t unicode HB_UNUSED,
+				 hb_codepoint_t variation_selector HB_UNUSED,
 				 hb_codepoint_t *glyph,
 				 void *user_data HB_UNUSED)
 {
@@ -276,7 +276,7 @@ hb_font_get_glyph_v_advances_default (hb_font_t* font,
 static hb_bool_t
 hb_font_get_glyph_h_origin_nil (hb_font_t *font HB_UNUSED,
 				void *font_data HB_UNUSED,
-				hb_codepoint_t glyph,
+				hb_codepoint_t glyph HB_UNUSED,
 				hb_position_t *x,
 				hb_position_t *y,
 				void *user_data HB_UNUSED)
@@ -301,7 +301,7 @@ hb_font_get_glyph_h_origin_default (hb_font_t *font,
 static hb_bool_t
 hb_font_get_glyph_v_origin_nil (hb_font_t *font HB_UNUSED,
 				void *font_data HB_UNUSED,
-				hb_codepoint_t glyph,
+				hb_codepoint_t glyph HB_UNUSED,
 				hb_position_t *x,
 				hb_position_t *y,
 				void *user_data HB_UNUSED)
@@ -326,8 +326,8 @@ hb_font_get_glyph_v_origin_default (hb_font_t *font,
 static hb_position_t
 hb_font_get_glyph_h_kerning_nil (hb_font_t *font HB_UNUSED,
 				 void *font_data HB_UNUSED,
-				 hb_codepoint_t left_glyph,
-				 hb_codepoint_t right_glyph,
+				 hb_codepoint_t left_glyph HB_UNUSED,
+				 hb_codepoint_t right_glyph HB_UNUSED,
 				 void *user_data HB_UNUSED)
 {
   return 0;
@@ -345,8 +345,8 @@ hb_font_get_glyph_h_kerning_default (hb_font_t *font,
 static hb_position_t
 hb_font_get_glyph_v_kerning_nil (hb_font_t *font HB_UNUSED,
 				 void *font_data HB_UNUSED,
-				 hb_codepoint_t top_glyph,
-				 hb_codepoint_t bottom_glyph,
+				 hb_codepoint_t top_glyph HB_UNUSED,
+				 hb_codepoint_t bottom_glyph HB_UNUSED,
 				 void *user_data HB_UNUSED)
 {
   return 0;
@@ -364,7 +364,7 @@ hb_font_get_glyph_v_kerning_default (hb_font_t *font,
 static hb_bool_t
 hb_font_get_glyph_extents_nil (hb_font_t *font HB_UNUSED,
 			       void *font_data HB_UNUSED,
-			       hb_codepoint_t glyph,
+			       hb_codepoint_t glyph HB_UNUSED,
 			       hb_glyph_extents_t *extents,
 			       void *user_data HB_UNUSED)
 {
@@ -389,8 +389,8 @@ hb_font_get_glyph_extents_default (hb_font_t *font,
 static hb_bool_t
 hb_font_get_glyph_contour_point_nil (hb_font_t *font HB_UNUSED,
 				     void *font_data HB_UNUSED,
-				     hb_codepoint_t glyph,
-				     unsigned int point_index,
+				     hb_codepoint_t glyph HB_UNUSED,
+				     unsigned int point_index HB_UNUSED,
 				     hb_position_t *x,
 				     hb_position_t *y,
 				     void *user_data HB_UNUSED)
@@ -416,7 +416,7 @@ hb_font_get_glyph_contour_point_default (hb_font_t *font,
 static hb_bool_t
 hb_font_get_glyph_name_nil (hb_font_t *font HB_UNUSED,
 			    void *font_data HB_UNUSED,
-			    hb_codepoint_t glyph,
+			    hb_codepoint_t glyph HB_UNUSED,
 			    char *name, unsigned int size,
 			    void *user_data HB_UNUSED)
 {
@@ -436,7 +436,8 @@ hb_font_get_glyph_name_default (hb_font_t *font,
 static hb_bool_t
 hb_font_get_glyph_from_name_nil (hb_font_t *font HB_UNUSED,
 				 void *font_data HB_UNUSED,
-				 const char *name, int len, /* -1 means nul-terminated */
+				 const char *name HB_UNUSED,
+				 int len HB_UNUSED, /* -1 means nul-terminated */
 				 hb_codepoint_t *glyph,
 				 void *user_data HB_UNUSED)
 {
diff --git a/src/hb-graphite2.cc b/src/hb-graphite2.cc
index 6b2b6f19..1b73f9f4 100644
--- a/src/hb-graphite2.cc
+++ b/src/hb-graphite2.cc
@@ -197,11 +197,14 @@ _hb_graphite2_shaper_font_data_destroy (hb_graphite2_font_data_t *data HB_UNUSED
 {
 }
 
-/*
+/**
+ * hb_graphite2_font_get_gr_font:
+ *
  * Since: 0.9.10
+ * Deprecated: 1.4.2
  */
 gr_font *
-hb_graphite2_font_get_gr_font (hb_font_t *font)
+hb_graphite2_font_get_gr_font (hb_font_t *font HB_UNUSED)
 {
   return nullptr;
 }
@@ -243,7 +246,7 @@ struct hb_graphite2_cluster_t {
 };
 
 hb_bool_t
-_hb_graphite2_shape (hb_shape_plan_t    *shape_plan,
+_hb_graphite2_shape (hb_shape_plan_t    *shape_plan HB_UNUSED,
 		     hb_font_t          *font,
 		     hb_buffer_t        *buffer,
 		     const hb_feature_t *features,
diff --git a/src/hb-machinery.hh b/src/hb-machinery.hh
index 35cbc155..2b238131 100644
--- a/src/hb-machinery.hh
+++ b/src/hb-machinery.hh
@@ -136,7 +136,7 @@ struct hb_dispatch_context_t
   enum { max_debug_depth = MaxDebugDepth };
   typedef Return return_t;
   template <typename T, typename F>
-  inline bool may_dispatch (const T *obj, const F *format) { return true; }
+  inline bool may_dispatch (const T *obj HB_UNUSED, const F *format HB_UNUSED) { return true; }
   static return_t no_dispatch_return_value (void) { return Context::default_return_value (); }
 };
 
@@ -235,7 +235,7 @@ struct hb_sanitize_context_t :
 
   inline const char *get_name (void) { return "SANITIZE"; }
   template <typename T, typename F>
-  inline bool may_dispatch (const T *obj, const F *format)
+  inline bool may_dispatch (const T *obj HB_UNUSED, const F *format)
   { return format->sanitize (this); }
   template <typename T>
   inline return_t dispatch (const T &obj) { return obj.sanitize (this); }
diff --git a/src/hb-ot-color-cbdt-table.hh b/src/hb-ot-color-cbdt-table.hh
index 1e1fe095..f807d612 100644
--- a/src/hb-ot-color-cbdt-table.hh
+++ b/src/hb-ot-color-cbdt-table.hh
@@ -166,7 +166,7 @@ struct IndexSubtable
     }
   }
 
-  inline bool get_extents (hb_glyph_extents_t *extents) const
+  inline bool get_extents (hb_glyph_extents_t *extents HB_UNUSED) const
   {
     switch (u.header.indexFormat) {
     case 2: case 5: /* TODO */
diff --git a/src/hb-ot-glyf-table.hh b/src/hb-ot-glyf-table.hh
index 2145ac02..9437a83d 100644
--- a/src/hb-ot-glyf-table.hh
+++ b/src/hb-ot-glyf-table.hh
@@ -47,7 +47,7 @@ struct loca
 
   static const hb_tag_t tableTag = HB_OT_TAG_loca;
 
-  inline bool sanitize (hb_sanitize_context_t *c) const
+  inline bool sanitize (hb_sanitize_context_t *c HB_UNUSED) const
   {
     TRACE_SANITIZE (this);
     return_trace (true);
@@ -70,7 +70,7 @@ struct glyf
 {
   static const hb_tag_t tableTag = HB_OT_TAG_glyf;
 
-  inline bool sanitize (hb_sanitize_context_t *c) const
+  inline bool sanitize (hb_sanitize_context_t *c HB_UNUSED) const
   {
     TRACE_SANITIZE (this);
     /* We don't check for anything specific here.  The users of the
diff --git a/src/hb-ot-hmtx-table.hh b/src/hb-ot-hmtx-table.hh
index 935ddd72..60735858 100644
--- a/src/hb-ot-hmtx-table.hh
+++ b/src/hb-ot-hmtx-table.hh
@@ -56,7 +56,7 @@ struct LongMetric
 template <typename T, typename H>
 struct hmtxvmtx
 {
-  inline bool sanitize (hb_sanitize_context_t *c) const
+  inline bool sanitize (hb_sanitize_context_t *c HB_UNUSED) const
   {
     TRACE_SANITIZE (this);
     /* We don't check for anything specific here.  The users of the
diff --git a/src/hb-ot-layout-gpos-table.hh b/src/hb-ot-layout-gpos-table.hh
index dd4e6279..8a6c0278 100644
--- a/src/hb-ot-layout-gpos-table.hh
+++ b/src/hb-ot-layout-gpos-table.hh
@@ -1715,7 +1715,7 @@ GPOS::position_start (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
 }
 
 void
-GPOS::position_finish_advances (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
+GPOS::position_finish_advances (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer HB_UNUSED)
 {
   //_hb_buffer_assert_gsubgpos_vars (buffer);
 }
diff --git a/src/hb-ot-math-table.hh b/src/hb-ot-math-table.hh
index 2f871124..e2093597 100644
--- a/src/hb-ot-math-table.hh
+++ b/src/hb-ot-math-table.hh
@@ -631,7 +631,7 @@ struct MathVariants
   inline const MathGlyphConstruction &
 		get_glyph_construction (hb_codepoint_t glyph,
 					hb_direction_t direction,
-					hb_font_t *font) const
+					hb_font_t *font HB_UNUSED) const
   {
     bool vertical = HB_DIRECTION_IS_VERTICAL (direction);
     unsigned int count = vertical ? vertGlyphCount : horizGlyphCount;
diff --git a/src/hb-ot-maxp-table.hh b/src/hb-ot-maxp-table.hh
index 2572ad28..648f232d 100644
--- a/src/hb-ot-maxp-table.hh
+++ b/src/hb-ot-maxp-table.hh
@@ -117,7 +117,7 @@ struct maxp
     return result;
   }
 
-  static inline void drop_hint_fields (hb_subset_plan_t *plan, maxp *maxp_prime)
+  static inline void drop_hint_fields (hb_subset_plan_t *plan HB_UNUSED, maxp *maxp_prime)
   {
     if (maxp_prime->version.major == 1)
     {
diff --git a/src/hb-ot-shape-complex-arabic-fallback.hh b/src/hb-ot-shape-complex-arabic-fallback.hh
index 2aa03672..f64e2dd6 100644
--- a/src/hb-ot-shape-complex-arabic-fallback.hh
+++ b/src/hb-ot-shape-complex-arabic-fallback.hh
@@ -220,9 +220,9 @@ struct ManifestLookup
 typedef OT::ArrayOf<ManifestLookup> Manifest;
 
 static bool
-arabic_fallback_plan_init_win1256 (arabic_fallback_plan_t *fallback_plan,
-				   const hb_ot_shape_plan_t *plan,
-				   hb_font_t *font)
+arabic_fallback_plan_init_win1256 (arabic_fallback_plan_t *fallback_plan HB_UNUSED,
+				   const hb_ot_shape_plan_t *plan HB_UNUSED,
+				   hb_font_t *font HB_UNUSED)
 {
 #ifdef HB_WITH_WIN1256
   /* Does this font look like it's Windows-1256-encoded? */
diff --git a/src/hb-ot-shape-complex-arabic.cc b/src/hb-ot-shape-complex-arabic.cc
index b5644391..1fbd14a4 100644
--- a/src/hb-ot-shape-complex-arabic.cc
+++ b/src/hb-ot-shape-complex-arabic.cc
@@ -416,7 +416,7 @@ retry:
 
 static void
 record_stch (const hb_ot_shape_plan_t *plan,
-	     hb_font_t *font,
+	     hb_font_t *font HB_UNUSED,
 	     hb_buffer_t *buffer)
 {
   const arabic_shape_plan_t *arabic_plan = (const arabic_shape_plan_t *) plan->data;
@@ -440,7 +440,7 @@ record_stch (const hb_ot_shape_plan_t *plan,
 }
 
 static void
-apply_stch (const hb_ot_shape_plan_t *plan,
+apply_stch (const hb_ot_shape_plan_t *plan HB_UNUSED,
 	    hb_buffer_t              *buffer,
 	    hb_font_t                *font)
 {
@@ -626,7 +626,7 @@ info_is_mcm (const hb_glyph_info_t &info)
 }
 
 static void
-reorder_marks_arabic (const hb_ot_shape_plan_t *plan,
+reorder_marks_arabic (const hb_ot_shape_plan_t *plan HB_UNUSED,
 		      hb_buffer_t              *buffer,
 		      unsigned int              start,
 		      unsigned int              end)
diff --git a/src/hb-ot-shape-complex-hangul.cc b/src/hb-ot-shape-complex-hangul.cc
index 95954025..38e4dbba 100644
--- a/src/hb-ot-shape-complex-hangul.cc
+++ b/src/hb-ot-shape-complex-hangul.cc
@@ -128,7 +128,7 @@ is_zero_width_char (hb_font_t *font,
 }
 
 static void
-preprocess_text_hangul (const hb_ot_shape_plan_t *plan,
+preprocess_text_hangul (const hb_ot_shape_plan_t *plan HB_UNUSED,
 			hb_buffer_t              *buffer,
 			hb_font_t                *font)
 {
diff --git a/src/hb-ot-shape-complex-khmer.cc b/src/hb-ot-shape-complex-khmer.cc
index 21db351f..ecb80195 100644
--- a/src/hb-ot-shape-complex-khmer.cc
+++ b/src/hb-ot-shape-complex-khmer.cc
@@ -267,7 +267,7 @@ setup_syllables (const hb_ot_shape_plan_t *plan HB_UNUSED,
 
 static void
 reorder_consonant_syllable (const hb_ot_shape_plan_t *plan,
-			    hb_face_t *face,
+			    hb_face_t *face HB_UNUSED,
 			    hb_buffer_t *buffer,
 			    unsigned int start, unsigned int end)
 {
diff --git a/src/hb-ot-shape-complex-myanmar.cc b/src/hb-ot-shape-complex-myanmar.cc
index 30fa8257..dcada261 100644
--- a/src/hb-ot-shape-complex-myanmar.cc
+++ b/src/hb-ot-shape-complex-myanmar.cc
@@ -274,8 +274,8 @@ initial_reordering_consonant_syllable (hb_buffer_t *buffer,
 }
 
 static void
-initial_reordering_syllable (const hb_ot_shape_plan_t *plan,
-			     hb_face_t *face,
+initial_reordering_syllable (const hb_ot_shape_plan_t *plan HB_UNUSED,
+			     hb_face_t *face HB_UNUSED,
 			     hb_buffer_t *buffer,
 			     unsigned int start, unsigned int end)
 {
@@ -362,7 +362,7 @@ reorder (const hb_ot_shape_plan_t *plan,
 }
 
 static void
-clear_syllables (const hb_ot_shape_plan_t *plan,
+clear_syllables (const hb_ot_shape_plan_t *plan HB_UNUSED,
 		 hb_font_t *font HB_UNUSED,
 		 hb_buffer_t *buffer)
 {
diff --git a/src/hb-ot-shape-complex-use.cc b/src/hb-ot-shape-complex-use.cc
index 7814e2c6..1bbf9805 100644
--- a/src/hb-ot-shape-complex-use.cc
+++ b/src/hb-ot-shape-complex-use.cc
@@ -379,7 +379,7 @@ setup_syllables (const hb_ot_shape_plan_t *plan,
 }
 
 static void
-clear_substitution_flags (const hb_ot_shape_plan_t *plan,
+clear_substitution_flags (const hb_ot_shape_plan_t *plan HB_UNUSED,
 			  hb_font_t *font HB_UNUSED,
 			  hb_buffer_t *buffer)
 {
@@ -391,7 +391,7 @@ clear_substitution_flags (const hb_ot_shape_plan_t *plan,
 
 static void
 record_rphf (const hb_ot_shape_plan_t *plan,
-	     hb_font_t *font,
+	     hb_font_t *font HB_UNUSED,
 	     hb_buffer_t *buffer)
 {
   const use_shape_plan_t *use_plan = (const use_shape_plan_t *) plan->data;
@@ -413,8 +413,8 @@ record_rphf (const hb_ot_shape_plan_t *plan,
 }
 
 static void
-record_pref (const hb_ot_shape_plan_t *plan,
-	     hb_font_t *font,
+record_pref (const hb_ot_shape_plan_t *plan HB_UNUSED,
+	     hb_font_t *font HB_UNUSED,
 	     hb_buffer_t *buffer)
 {
   hb_glyph_info_t *info = buffer->info;
diff --git a/src/hb-ot-shape-complex-vowel-constraints.cc b/src/hb-ot-shape-complex-vowel-constraints.cc
index aae5936a..20af8711 100644
--- a/src/hb-ot-shape-complex-vowel-constraints.cc
+++ b/src/hb-ot-shape-complex-vowel-constraints.cc
@@ -30,9 +30,9 @@ _output_with_dotted_circle (hb_buffer_t *buffer)
 }
 
 void
-_hb_preprocess_text_vowel_constraints (const hb_ot_shape_plan_t *plan,
+_hb_preprocess_text_vowel_constraints (const hb_ot_shape_plan_t *plan HB_UNUSED,
 				       hb_buffer_t              *buffer,
-				       hb_font_t                *font)
+				       hb_font_t                *font HB_UNUSED)
 {
   /* UGLY UGLY UGLY business of adding dotted-circle in the middle of
    * vowel-sequences that look like another vowel.  Data for each script
diff --git a/src/hb-ot-shape-fallback.cc b/src/hb-ot-shape-fallback.cc
index 4c5ccc97..94bc4afb 100644
--- a/src/hb-ot-shape-fallback.cc
+++ b/src/hb-ot-shape-fallback.cc
@@ -192,7 +192,7 @@ zero_mark_advances (hb_buffer_t *buffer,
 }
 
 static inline void
-position_mark (const hb_ot_shape_plan_t *plan,
+position_mark (const hb_ot_shape_plan_t *plan HB_UNUSED,
 	       hb_font_t *font,
 	       hb_buffer_t  *buffer,
 	       hb_glyph_extents_t &base_extents,
@@ -472,7 +472,7 @@ _hb_ot_shape_fallback_kern (const hb_ot_shape_plan_t *plan,
 
 /* Adjusts width of various spaces. */
 void
-_hb_ot_shape_fallback_spaces (const hb_ot_shape_plan_t *plan,
+_hb_ot_shape_fallback_spaces (const hb_ot_shape_plan_t *plan HB_UNUSED,
 			      hb_font_t *font,
 			      hb_buffer_t  *buffer)
 {
diff --git a/src/hb-ot-shape-normalize.cc b/src/hb-ot-shape-normalize.cc
index a8229a98..2164f7ad 100644
--- a/src/hb-ot-shape-normalize.cc
+++ b/src/hb-ot-shape-normalize.cc
@@ -213,7 +213,9 @@ decompose_current_character (const hb_ot_shape_normalize_context_t *c, bool shor
 }
 
 static inline void
-handle_variation_selector_cluster (const hb_ot_shape_normalize_context_t *c, unsigned int end, bool short_circuit)
+handle_variation_selector_cluster (const hb_ot_shape_normalize_context_t *c,
+				   unsigned int end,
+				   bool short_circuit HB_UNUSED)
 {
   /* TODO Currently if there's a variation-selector we give-up, it's just too hard. */
   hb_buffer_t * const buffer = c->buffer;
diff --git a/src/hb-ot-shape.cc b/src/hb-ot-shape.cc
index 065b4d4b..32c50204 100644
--- a/src/hb-ot-shape.cc
+++ b/src/hb-ot-shape.cc
@@ -276,7 +276,7 @@ _hb_ot_shaper_font_data_create (hb_font_t *font HB_UNUSED)
 }
 
 void
-_hb_ot_shaper_font_data_destroy (hb_ot_font_data_t *data)
+_hb_ot_shaper_font_data_destroy (hb_ot_font_data_t *data HB_UNUSED)
 {
 }
 
diff --git a/src/hb-ot-tag.cc b/src/hb-ot-tag.cc
index 4dba9c31..a569b8c2 100644
--- a/src/hb-ot-tag.cc
+++ b/src/hb-ot-tag.cc
@@ -242,7 +242,6 @@ hb_ot_tag_from_language (hb_language_t language)
 static void
 hb_ot_tags_from_language (const char   *lang_str,
 			  const char   *limit,
-			  const char   *private_use_subtag,
 			  unsigned int *count,
 			  hb_tag_t     *tags)
 {
@@ -389,7 +388,7 @@ hb_ot_tags_from_script_and_language (hb_script_t   script,
     needs_language = parse_private_use_subtag (private_use_subtag, language_count, language_tags, "-hbot", TOUPPER);
 
     if (needs_language && language_count && language_tags && *language_count)
-      hb_ot_tags_from_language (lang_str, limit, private_use_subtag, language_count, language_tags);
+      hb_ot_tags_from_language (lang_str, limit, language_count, language_tags);
   }
 
   if (needs_script && script_count && script_tags && *script_count)
diff --git a/src/hb-ot-vorg-table.hh b/src/hb-ot-vorg-table.hh
index b6494b51..98af00e1 100644
--- a/src/hb-ot-vorg-table.hh
+++ b/src/hb-ot-vorg-table.hh
@@ -70,7 +70,7 @@ struct VORG
     return defaultVertOriginY;
   }
 
-  inline bool _subset (const hb_subset_plan_t *plan,
+  inline bool _subset (const hb_subset_plan_t *plan HB_UNUSED,
                        const VORG *vorg_table,
                        const hb_vector_t<VertOriginMetric> &subset_metrics,
                        unsigned int dest_sz,
diff --git a/src/hb-set.cc b/src/hb-set.cc
index 09dc4b48..25c19147 100644
--- a/src/hb-set.cc
+++ b/src/hb-set.cc
@@ -391,7 +391,7 @@ hb_set_symmetric_difference (hb_set_t       *set,
  * Deprecated: 1.6.1
  **/
 void
-hb_set_invert (hb_set_t *set)
+hb_set_invert (hb_set_t *set HB_UNUSED)
 {
 }
 
diff --git a/src/hb-shape-plan.cc b/src/hb-shape-plan.cc
index b2289f86..dea2c8c7 100644
--- a/src/hb-shape-plan.cc
+++ b/src/hb-shape-plan.cc
@@ -441,7 +441,7 @@ hb_non_global_user_features_present (const hb_feature_t *user_features,
 }
 
 static inline hb_bool_t
-hb_coords_present (const int *coords,
+hb_coords_present (const int *coords HB_UNUSED,
 		   unsigned int num_coords)
 {
   return num_coords != 0;
diff --git a/src/hb-utf.hh b/src/hb-utf.hh
index b45bcd97..54ede3c1 100644
--- a/src/hb-utf.hh
+++ b/src/hb-utf.hh
@@ -365,7 +365,7 @@ struct hb_latin1_t
   prev (const codepoint_t *text,
 	const codepoint_t *start HB_UNUSED,
 	hb_codepoint_t *unicode,
-	hb_codepoint_t replacement)
+	hb_codepoint_t replacement HB_UNUSED)
   {
     *unicode = *--text;
     return text;
commit b2e1ec374cbd2a6e4d79419bd5601a4e2ecb9864
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri Oct 26 20:45:28 2018 -0700

    [subset] Fix warning

diff --git a/src/hb-subset.hh b/src/hb-subset.hh
index 9cdd388d..e43c79f5 100644
--- a/src/hb-subset.hh
+++ b/src/hb-subset.hh
@@ -43,7 +43,7 @@ struct hb_subset_context_t :
   template <typename T>
   inline bool dispatch (const T &obj) { return obj.subset (this); }
   static bool default_return_value (void) { return true; }
-  bool stop_sublookup_iteration (bool r) const { return false; }
+  bool stop_sublookup_iteration (bool r HB_UNUSED) const { return false; }
 
   hb_subset_plan_t *plan;
   hb_serialize_context_t *serializer;
commit 337ea0b7175793305e9d8935aecf385b707a5bc4
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri Oct 26 20:31:14 2018 -0700

    [fuzzing] Remove HB_NDEBUG
    
    Not sure why it ever was added.

diff --git a/src/Makefile.am b/src/Makefile.am
index fab703a1..0d614ee0 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -170,7 +170,6 @@ pkgconfig_DATA += harfbuzz-subset.pc
 EXTRA_DIST += harfbuzz-subset.pc.in
 
 FUZZING_CPPFLAGS = \
-	-DHB_NDEBUG \
 	-DHB_MAX_NESTING_LEVEL=3 \
 	-DHB_SANITIZE_MAX_EDITS=3 \
 	-DHB_SANITIZE_MAX_OPS_FACTOR=3 \
commit 12058e44d100c28816f42c91c63a0f960a662181
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri Oct 26 16:23:50 2018 -0700

    [fuzzing] Add more test

diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5659690013556736 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5659690013556736
new file mode 100644
index 00000000..9293c46c
Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5659690013556736 differ
commit c965eeadbc71943f2336a20dc16ac691c805b90e
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Thu Oct 25 13:43:25 2018 -0700

    [name] Default to "en" if language is not specified

diff --git a/src/hb-ot-name.cc b/src/hb-ot-name.cc
index ec3d8794..f1c1f76e 100644
--- a/src/hb-ot-name.cc
+++ b/src/hb-ot-name.cc
@@ -106,6 +106,9 @@ hb_ot_name_get_utf (hb_face_t     *face,
 {
   const OT::name_accelerator_t &name = _get_name (face);
 
+  if (!language)
+    language = hb_language_from_string ("en", 2);
+
   unsigned int width;
   int idx = name.get_index (name_id, language, &width);
   if (idx != -1)
commit 3fd6e5dbefe52a4a2e604c28a4edfbd40ed16027
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Wed Oct 24 13:42:38 2018 -0700

    [name] Add pre-defined nameIDs

diff --git a/src/hb-ot-name.h b/src/hb-ot-name.h
index ff1ae24d..66af5b64 100644
--- a/src/hb-ot-name.h
+++ b/src/hb-ot-name.h
@@ -34,6 +34,35 @@
 HB_BEGIN_DECLS
 
 
+enum {
+  HB_NAME_ID_COPYRIGHT			= 0,
+  HB_NAME_ID_FONT_FAMILY		= 1,
+  HB_NAME_ID_FONT_SUBFAMILY		= 2,
+  HB_NAME_ID_UNIQUE_ID			= 3,
+  HB_NAME_ID_FULL_NAME			= 4,
+  HB_NAME_ID_VERSION_STRING		= 5,
+  HB_NAME_ID_POSTSCRIPT_NAME		= 6,
+  HB_NAME_ID_TRADEMARK			= 7,
+  HB_NAME_ID_MANUFACTURER		= 8,
+  HB_NAME_ID_DESIGNER			= 9,
+  HB_NAME_ID_DESCRIPTION		= 10,
+  HB_NAME_ID_VENDOR_URL			= 11,
+  HB_NAME_ID_DESIGNER_URL		= 12,
+  HB_NAME_ID_LICENSE			= 13,
+  HB_NAME_ID_LICENSE_URL		= 14,
+/*HB_NAME_ID_RESERVED			= 15,*/
+  HB_NAME_ID_TYPOGRAPHIC_FAMILY		= 16,
+  HB_NAME_ID_TYPOGRAPHIC_SUBFAMILY	= 17,
+  HB_NAME_ID_MAC_FULL_NAME		= 18,
+  HB_NAME_ID_SAMPLE_TEXT		= 19,
+  HB_NAME_ID_CID_FINDFONT_NAME		= 20,
+  HB_NAME_ID_WWS_FAMILY			= 21,
+  HB_NAME_ID_WWS_SUBFAMILY		= 22,
+  HB_NAME_ID_LIGHT_BACKGROUND		= 23,
+  HB_NAME_ID_DARK_BACKGROUND		= 24,
+  HB_NAME_ID_VARIATIONS_PS_PREFIX	= 25
+};
+
 /**
  * hb_name_id_t:
  *
commit 20d0171d20cf9f3f93bdd6878bbc1d7d8329e75f
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Wed Oct 24 13:20:19 2018 -0700

    [name] Fill out most missing language codes

diff --git a/src/hb-ot-name-language.cc b/src/hb-ot-name-language.cc
index 8b79d4d6..0e37e0ac 100644
--- a/src/hb-ot-name-language.cc
+++ b/src/hb-ot-name-language.cc
@@ -27,7 +27,10 @@
 #include "hb-ot-name-language.hh"
 
 /* Following two tables were generated by joining FreeType, FontConfig,
- * and OpenType specification language lists. */
+ * and OpenType specification language lists, then filled in missing
+ * entries using:
+ * https://docs.microsoft.com/en-us/windows/desktop/intl/language-identifier-constants-and-strings
+ */
 
 struct hb_ot_language_map_t
 {
@@ -50,7 +53,7 @@ hb_ms_language_map[] =
   {0x0009,	"en"},	/* ??? */
   {0x0401,	"ar"},	/* Arabic (Saudi Arabia) */
   {0x0402,	"bg"},	/* Bulgarian (Bulgaria) */
-//{0x0403,	""},	/* Catalan (Catalan) */
+  {0x0403,	"ca"},	/* Catalan (Catalan) */
   {0x0404,	"zh-tw"},	/* Chinese (Taiwan) */
   {0x0405,	"cs"},	/* Czech (Czech Republic) */
   {0x0406,	"da"},	/* Danish (Denmark) */
@@ -65,12 +68,12 @@ hb_ms_language_map[] =
   {0x040F,	"is"},	/* Icelandic (Iceland) */
   {0x0410,	"it"},	/* Italian (Italy) */
   {0x0411,	"ja"},	/* Japanese (Japan) */
-//{0x0412,	""},	/* Korean (Korea) */
+  {0x0412,	"ko"},	/* Korean (Korea) */
   {0x0413,	"nl"},	/* Dutch (Netherlands) */
   {0x0414,	"no"},	/* Norwegian (Bokmal) (Norway) */
   {0x0415,	"pl"},	/* Polish (Poland) */
   {0x0416,	"pt"},	/* Portuguese (Brazil) */
-//{0x0417,	""},	/* Romansh (Switzerland) */
+  {0x0417,	"rm"},	/* Romansh (Switzerland) */
   {0x0418,	"ro"},	/* Romanian (Romania) */
   {0x0419,	"ru"},	/* Russian (Russia) */
   {0x041A,	"hr"},	/* Croatian (Croatia) */
@@ -83,24 +86,24 @@ hb_ms_language_map[] =
   {0x0421,	"id"},	/* Indonesian (Indonesia) */
   {0x0422,	"uk"},	/* Ukrainian (Ukraine) */
   {0x0423,	"be"},	/* Belarusian (Belarus) */
-//{0x0424,	""},	/* Slovenian (Slovenia) */
+  {0x0424,	"sl"},	/* Slovenian (Slovenia) */
   {0x0425,	"et"},	/* Estonian (Estonia) */
   {0x0426,	"lv"},	/* Latvian (Latvia) */
   {0x0427,	"lt"},	/* Lithuanian (Lithuania) */
   {0x0428,	"tg"},	/* Tajik (Cyrillic) (Tajikistan) */
-  {0x0429,	"fa"},	/* ??? */
+  {0x0429,	"fa"},	/* Persian (Iran) */
   {0x042A,	"vi"},	/* Vietnamese (Vietnam) */
   {0x042B,	"hy"},	/* Armenian (Armenia) */
   {0x042C,	"az"},	/* Azeri (Latin) (Azerbaijan) */
-//{0x042D,	""},	/* Basque (Basque) */
-//{0x042E,	""},	/* Upper Sorbian (Germany) */
+  {0x042D,	"eu"},	/* Basque (Basque) */
+  {0x042E,	"hsb"},	/* Upper Sorbian (Germany) */
   {0x042F,	"mk"},	/* Macedonian (FYROM) (Former Yugoslav Republic of Macedonia) */
   {0x0430,	"st"},	/* ??? */
   {0x0431,	"ts"},	/* ??? */
-//{0x0432,	""},	/* Setswana (South Africa) */
+  {0x0432,	"tn"},	/* Setswana (South Africa) */
   {0x0433,	"ven"},	/* ??? */
-//{0x0434,	""},	/* isiXhosa (South Africa) */
-//{0x0435,	""},	/* isiZulu (South Africa) */
+  {0x0434,	"xh"},	/* isiXhosa (South Africa) */
+  {0x0435,	"zu"},	/* isiZulu (South Africa) */
   {0x0436,	"af"},	/* Afrikaans (South Africa) */
   {0x0437,	"ka"},	/* Georgian (Georgia) */
   {0x0438,	"fo"},	/* Faroese (Faroe Islands) */
@@ -110,16 +113,16 @@ hb_ms_language_map[] =
   {0x043C,	"ga"},	/* ??? */
   {0x043D,	"yi"},	/* ??? */
   {0x043E,	"ms"},	/* Malay (Malaysia) */
-//{0x043F,	""},	/* Kazakh (Kazakhstan) */
-//{0x0440,	""},	/* Kyrgyz (Kyrgyzstan) */
-//{0x0441,	""},	/* Kiswahili (Kenya) */
+  {0x043F,	"kk"},	/* Kazakh (Kazakhstan) */
+  {0x0440,	"ky"},	/* Kyrgyz (Kyrgyzstan) */
+  {0x0441,	"sw"},	/* Kiswahili (Kenya) */
   {0x0442,	"tk"},	/* Turkmen (Turkmenistan) */
   {0x0443,	"uz"},	/* Uzbek (Latin) (Uzbekistan) */
-//{0x0444,	""},	/* Tatar (Russia) */
+  {0x0444,	"tt"},	/* Tatar (Russia) */
   {0x0445,	"bn"},	/* Bengali (India) */
   {0x0446,	"pa"},	/* Punjabi (India) */
   {0x0447,	"gu"},	/* Gujarati (India) */
-//{0x0448,	""},	/* Odia (formerly Oriya) (India) */
+  {0x0448,	"or"},	/* Odia (formerly Oriya) (India) */
   {0x0449,	"ta"},	/* Tamil (India) */
   {0x044A,	"te"},	/* Telugu (India) */
   {0x044B,	"kn"},	/* Kannada (India) */
@@ -128,17 +131,17 @@ hb_ms_language_map[] =
   {0x044E,	"mr"},	/* Marathi (India) */
   {0x044F,	"sa"},	/* Sanskrit (India) */
   {0x0450,	"mn"},	/* Mongolian (Cyrillic) (Mongolia) */
-//{0x0451,	""},	/* Tibetan (PRC) */
-//{0x0452,	""},	/* Welsh (United Kingdom) */
+  {0x0451,	"bo"},	/* Tibetan (PRC) */
+  {0x0452,	"cy"},	/* Welsh (United Kingdom) */
   {0x0453,	"km"},	/* Khmer (Cambodia) */
   {0x0454,	"lo"},	/* Lao (Lao P.D.R.) */
   {0x0455,	"my"},	/* ??? */
-//{0x0456,	""},	/* Galician (Galician) */
+  {0x0456,	"gl"},	/* Galician (Galician) */
   {0x0457,	"kok"},	/* Konkani (India) */
   {0x0458,	"mni"},	/* ??? */
   {0x0459,	"sd"},	/* ??? */
   {0x045A,	"syr"},	/* Syriac (Syria) */
-//{0x045B,	""},	/* Sinhala (Sri Lanka) */
+  {0x045B,	"si"},	/* Sinhala (Sri Lanka) */
   {0x045C,	"chr"},	/* ??? */
   {0x045D,	"iu"},	/* Inuktitut (Canada) */
   {0x045E,	"am"},	/* Amharic (Ethiopia) */
@@ -150,11 +153,11 @@ hb_ms_language_map[] =
   {0x0465,	"div"},	/* Divehi (Maldives) */
   {0x0468,	"ha"},	/* Hausa (Latin) (Nigeria) */
   {0x046A,	"yo"},	/* Yoruba (Nigeria) */
-//{0x046B,	""},	/* Quechua (Bolivia) */
-//{0x046C,	""},	/* Sesotho sa Leboa (South Africa) */
-//{0x046D,	""},	/* Bashkir (Russia) */
-//{0x046E,	""},	/* Luxembourgish (Luxembourg) */
-//{0x046F,	""},	/* Greenlandic (Greenland) */
+  {0x046B,	"quz"},	/* Quechua (Bolivia) */
+  {0x046C,	"nso"},	/* Sesotho sa Leboa (South Africa) */
+  {0x046D,	"ba"},	/* Bashkir (Russia) */
+  {0x046E,	"lb"},	/* Luxembourgish (Luxembourg) */
+  {0x046F,	"kl"},	/* Greenlandic (Greenland) */
   {0x0470,	"ibo"},	/* Igbo (Nigeria) */
   {0x0471,	"kau"},	/* ??? */
   {0x0472,	"om"},	/* ??? */
@@ -163,21 +166,21 @@ hb_ms_language_map[] =
   {0x0475,	"haw"},	/* ??? */
   {0x0476,	"la"},	/* ??? */
   {0x0477,	"so"},	/* ??? */
-//{0x0478,	""},	/* Yi (PRC) */
+  {0x0478,	"ii"},	/* Yi (PRC) */
   {0x0479,	"pap"},	/* ??? */
-//{0x047A,	""},	/* Mapudungun (Chile) */
-//{0x047C,	""},	/* Mohawk (Mohawk) */
-//{0x047E,	""},	/* Breton (France) */
-//{0x0480,	""},	/* Uighur (PRC) */
+  {0x047A,	"arn"},	/* Mapudungun (Chile) */
+  {0x047C,	"moh"},	/* Mohawk (Mohawk) */
+  {0x047E,	"br"},	/* Breton (France) */
+  {0x0480,	"ug"},	/* Uighur (PRC) */
   {0x0481,	"mi"},	/* Maori (New Zealand) */
-//{0x0482,	""},	/* Occitan (France) */
-//{0x0483,	""},	/* Corsican (France) */
-//{0x0484,	""},	/* Alsatian (France) */
-//{0x0485,	""},	/* Yakut (Russia) */
-//{0x0486,	""},	/* K'iche (Guatemala) */
-//{0x0487,	""},	/* Kinyarwanda (Rwanda) */
-//{0x0488,	""},	/* Wolof (Senegal) */
-//{0x048C,	""},	/* Dari (Afghanistan) */
+  {0x0482,	"oc"},	/* Occitan (France) */
+  {0x0483,	"co"},	/* Corsican (France) */
+  {0x0484,	"gsw"},	/* Alsatian (France) */
+  {0x0485,	"sah"},	/* Yakut (Russia) */
+  {0x0486,	"qut"},	/* K'iche (Guatemala) */
+  {0x0487,	"rw"},	/* Kinyarwanda (Rwanda) */
+  {0x0488,	"wo"},	/* Wolof (Senegal) */
+  {0x048C,	"fa"},	/* Dari (Afghanistan) */
   {0x0801,	"ar"},	/* Arabic (Iraq) */
   {0x0804,	"zh-cn"},	/* Chinese (People’s Republic of China) */
   {0x0807,	"de"},	/* German (Switzerland) */
@@ -196,17 +199,17 @@ hb_ms_language_map[] =
   {0x0820,	"ur"},	/* ??? */
   {0x0827,	"lt"},	/* ??? */
   {0x082C,	"az"},	/* Azeri (Cyrillic) (Azerbaijan) */
-//{0x082E,	""},	/* Lower Sorbian (Germany) */
+  {0x082E,	"dsb"},	/* Lower Sorbian (Germany) */
 //{0x083B,	""},	/* Sami (Northern) (Sweden) */
   {0x083C,	"gd"},	/* Irish (Ireland) */
   {0x083E,	"ms"},	/* Malay (Brunei Darussalam) */
   {0x0843,	"uz"},	/* Uzbek (Cyrillic) (Uzbekistan) */
   {0x0845,	"bn"},	/* Bengali (Bangladesh) */
   {0x0846,	"ar"},	/* ??? */
-//{0x0850,	""},	/* Mongolian (Traditional) (People’s Republic of China) */
+  {0x0850,	"mn"},	/* Mongolian (Traditional) (People’s Republic of China) */
   {0x0851,	"dz"},	/* ??? */
-//{0x085D,	""},	/* Inuktitut (Latin) (Canada) */
-//{0x085F,	""},	/* Tamazight (Latin) (Algeria) */
+  {0x085D,	"iu"},	/* Inuktitut (Latin) (Canada) */
+  {0x085F,	"tzm"},	/* Tamazight (Latin) (Algeria) */
   {0x0861,	"ne"},	/* ??? */
 //{0x086B,	""},	/* Quechua (Ecuador) */
   {0x0873,	"ti"},	/* ??? */
@@ -214,10 +217,10 @@ hb_ms_language_map[] =
   {0x0C04,	"zh-hk"},	/* Chinese (Hong Kong S.A.R.) */
   {0x0C07,	"de"},	/* German (Austria) */
   {0x0C09,	"en"},	/* English (Australia) */
-//{0x0C0A,	""},	/* Spanish (Modern Sort) (Spain) */
+  {0x0C0A,	"es"},	/* Spanish (Modern Sort) (Spain) */
   {0x0C0C,	"fr"},	/* French (Canada) */
   {0x0C1A,	"sr"},	/* Serbian (Cyrillic) (Serbia) */
-//{0x0C3B,	""},	/* Sami (Northern) (Finland) */
+  {0x0C3B,	"se"},	/* Sami (Northern) (Finland) */
 //{0x0C6B,	""},	/* Quechua (Peru) */
   {0x1001,	"ar"},	/* Arabic (Libya) */
   {0x1004,	"zh-sg"},	/* Chinese (Singapore) */
@@ -225,15 +228,14 @@ hb_ms_language_map[] =
   {0x1009,	"en"},	/* English (Canada) */
   {0x100A,	"es"},	/* Spanish (Guatemala) */
   {0x100C,	"fr"},	/* French (Switzerland) */
-//{0x101A,	""},	/* Croatian (Latin) (Bosnia and Herzegovina) */
-//{0x103B,	""},	/* Sami (Lule) (Norway) */
+  {0x101A,	"hr"},	/* Croatian (Latin) (Bosnia and Herzegovina) */
+  {0x103B,	"smj"},	/* Sami (Lule) (Norway) */
   {0x1401,	"ar"},	/* Arabic (Algeria) */
 //{0x1404,	""},	/* Chinese (Macao S.A.R.) */
-//{0x1407,	""},	/* German (Liechtenstein) */
+  {0x1407,	"de"},	/* German (Liechtenstein) */
   {0x1409,	"en"},	/* English (New Zealand) */
   {0x140A,	"es"},	/* Spanish (Costa Rica) */
-  {0x140C,	"fr"},	/* ??? */
-//{0x140c,	""},	/* French (Luxembourg) */
+  {0x140C,	"fr"},	/* French (Luxembourg) */
   {0x141A,	"bs"},	/* Bosnian (Latin) (Bosnia and Herzegovina) */
 //{0x143B,	""},	/* Sami (Lule) (Sweden) */
   {0x1801,	"ar"},	/* Arabic (Morocco) */
@@ -241,7 +243,7 @@ hb_ms_language_map[] =
   {0x180A,	"es"},	/* Spanish (Panama) */
   {0x180C,	"fr"},	/* French (Principality of Monaco) */
 //{0x181A,	""},	/* Serbian (Latin) (Bosnia and Herzegovina) */
-//{0x183B,	""},	/* Sami (Southern) (Norway) */
+  {0x183B,	"sma"},	/* Sami (Southern) (Norway) */
   {0x1C01,	"ar"},	/* Arabic (Tunisia) */
   {0x1C09,	"en"},	/* English (South Africa) */
   {0x1C0A,	"es"},	/* Spanish (Dominican Republic) */
@@ -252,13 +254,13 @@ hb_ms_language_map[] =
   {0x2009,	"en"},	/* English (Jamaica) */
   {0x200A,	"es"},	/* Spanish (Venezuela) */
   {0x200C,	"fr"},	/* ??? */
-//{0x201A,	""},	/* Bosnian (Cyrillic) (Bosnia and Herzegovina) */
-//{0x203B,	""},	/* Sami (Skolt) (Finland) */
+  {0x201A,	"bs"},	/* Bosnian (Cyrillic) (Bosnia and Herzegovina) */
+  {0x203B,	"sms"},	/* Sami (Skolt) (Finland) */
   {0x2401,	"ar"},	/* Arabic (Yemen) */
   {0x2409,	"en"},	/* English (Caribbean) */
   {0x240A,	"es"},	/* Spanish (Colombia) */
   {0x240C,	"fr"},	/* ??? */
-//{0x243B,	""},	/* Sami (Inari) (Finland) */
+  {0x243B,	"smn"},	/* Sami (Inari) (Finland) */
   {0x2801,	"ar"},	/* Arabic (Syria) */
   {0x2809,	"en"},	/* English (Belize) */
   {0x280A,	"es"},	/* Spanish (Peru) */
@@ -349,15 +351,15 @@ hb_mac_language_map[] =
   { 47,	"uz"},	/* Uzbek */
   { 48,	"kk"},	/* Kazakh */
   { 49,	"az"},	/* Azerbaijani (Cyrillic script) */
-  { 50,	"ar"},	/* Azerbaijani (Arabic script) */
+  { 50,	"az"},	/* Azerbaijani (Arabic script) */
   { 51,	"hy"},	/* Armenian */
   { 52,	"ka"},	/* Georgian */
   { 53,	"mo"},	/* Moldavian */
   { 54,	"ky"},	/* Kirghiz */
   { 55,	"tg"},	/* Tajiki */
   { 56,	"tk"},	/* Turkmen */
-  { 57,	"mo"},	/* Mongolian (Mongolian script) */
-  { 58,	"mo"},	/* Mongolian (Cyrillic script) */
+  { 57,	"mn"},	/* Mongolian (Mongolian script) */
+  { 58,	"mn"},	/* Mongolian (Cyrillic script) */
   { 59,	"ps"},	/* Pashto */
   { 60,	"ku"},	/* Kurdish */
   { 61,	"ks"},	/* Kashmiri */
commit 622b014faf7bbe7a97f9aff959c434d1664c10d0
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Wed Oct 24 12:40:15 2018 -0700

    [name] Skip enumerating names with unknown language

diff --git a/src/hb-ot-name-table.hh b/src/hb-ot-name-table.hh
index e5809084..b84edd18 100644
--- a/src/hb-ot-name-table.hh
+++ b/src/hb-ot-name-table.hh
@@ -206,7 +206,8 @@ struct name
       unsigned int j = 0;
       for (unsigned int i = 0; i < this->names.len; i++)
       {
-        if (this->names[i].entry_score == UNSUPPORTED)
+        if (this->names[i].entry_score == UNSUPPORTED ||
+	    this->names[i].language == HB_LANGUAGE_INVALID)
 	  continue;
         if (i &&
 	    this->names[i - 1].name_id  == this->names[i].name_id &&
commit 2c39f359e4a7312e3b518f76815d79e42ee96a32
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Wed Oct 24 12:34:30 2018 -0700

    [utf] Remove unused typedef

diff --git a/src/hb-utf.hh b/src/hb-utf.hh
index 52bc8b76..b45bcd97 100644
--- a/src/hb-utf.hh
+++ b/src/hb-utf.hh
@@ -345,7 +345,6 @@ struct hb_utf32_xe_t
 
 typedef hb_utf32_xe_t<uint32_t> hb_utf32_t;
 typedef hb_utf32_xe_t<uint32_t, false> hb_utf32_novalidate_t;
-typedef hb_utf32_xe_t<OT::HBUINT32> hb_utf32_be_t;
 
 
 struct hb_latin1_t
commit ce81c7429810ad3902c37e50016ca54b9bae6f91
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Wed Oct 24 12:34:03 2018 -0700

    [utf] Fix ASCII

diff --git a/src/hb-utf.hh b/src/hb-utf.hh
index f78d5499..52bc8b76 100644
--- a/src/hb-utf.hh
+++ b/src/hb-utf.hh
@@ -410,7 +410,7 @@ struct hb_ascii_t
 	hb_codepoint_t replacement HB_UNUSED)
   {
     *unicode = *text++;
-    if (*unicode >= 0x100)
+    if (*unicode >= 0x0080u)
       *unicode = replacement;
     return text;
   }
@@ -422,7 +422,7 @@ struct hb_ascii_t
 	hb_codepoint_t replacement)
   {
     *unicode = *--text;
-    if (*unicode >= 0x0080)
+    if (*unicode >= 0x0080u)
       *unicode = replacement;
     return text;
   }
commit 327546e633b590d6dedfb901810ccf490a0bf922
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Tue Oct 23 23:33:44 2018 -0700

    [name] Hook up ltag table

diff --git a/src/hb-aat-layout.cc b/src/hb-aat-layout.cc
index 1e1c7b4f..ec053938 100644
--- a/src/hb-aat-layout.cc
+++ b/src/hb-aat-layout.cc
@@ -34,7 +34,7 @@
 #include "hb-aat-layout-kerx-table.hh"
 #include "hb-aat-layout-morx-table.hh"
 #include "hb-aat-layout-trak-table.hh"
-#include "hb-aat-ltag-table.hh" // Just so we compile it; unused otherwise.
+#include "hb-aat-ltag-table.hh"
 
 
 /* Table data courtesy of Apple.  Converted from mnemonics to integers
@@ -181,6 +181,12 @@ _get_trak (hb_face_t *face)
   if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return Null(AAT::trak);
   return *(hb_ot_face_data (face)->trak.get ());
 }
+static inline const AAT::ltag&
+_get_ltag (hb_face_t *face)
+{
+  if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return Null(AAT::ltag);
+  return *(hb_ot_face_data (face)->ltag.get ());
+}
 
 
 void
@@ -248,3 +254,10 @@ hb_aat_layout_track (hb_ot_shape_plan_t *plan,
   AAT::hb_aat_apply_context_t c (plan, font, buffer);
   trak.apply (&c);
 }
+
+hb_language_t
+_hb_aat_language_get (hb_face_t *face,
+		      unsigned int i)
+{
+  return _get_ltag (face).get_language (i);
+}
diff --git a/src/hb-aat-layout.hh b/src/hb-aat-layout.hh
index aea54568..8a558e6a 100644
--- a/src/hb-aat-layout.hh
+++ b/src/hb-aat-layout.hh
@@ -80,4 +80,9 @@ hb_aat_layout_track (hb_ot_shape_plan_t *plan,
 		     hb_font_t *font,
 		     hb_buffer_t *buffer);
 
+HB_INTERNAL hb_language_t
+_hb_aat_language_get (hb_face_t *face,
+		      unsigned int i);
+
+
 #endif /* HB_AAT_LAYOUT_HH */
diff --git a/src/hb-aat-ltag-table.hh b/src/hb-aat-ltag-table.hh
index 08a1b51a..8a42b351 100644
--- a/src/hb-aat-ltag-table.hh
+++ b/src/hb-aat-ltag-table.hh
@@ -25,7 +25,7 @@
 #ifndef HB_AAT_LTAG_TABLE_HH
 #define HB_AAT_LTAG_TABLE_HH
 
-#include "hb-aat-layout-common.hh"
+#include "hb-open-type.hh"
 
 /*
  * ltag -- Language Tag
@@ -36,9 +36,13 @@
 
 namespace AAT {
 
+using namespace OT;
+
 
 struct FTStringRange
 {
+  friend struct ltag;
+
   inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
   {
     TRACE_SANITIZE (this);
@@ -58,10 +62,19 @@ struct ltag
 {
   static const hb_tag_t tableTag = HB_AAT_TAG_ltag;
 
+  inline hb_language_t get_language (unsigned int i) const
+  {
+    const FTStringRange &range = tagRanges[i];
+    return hb_language_from_string ((const char *) (this+range.tag).arrayZ,
+				    range.length);
+  }
+
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (likely (c->check_struct (this) && tagRanges.sanitize (c, this)));
+    return_trace (likely (c->check_struct (this) &&
+			  version >= 1 &&
+			  tagRanges.sanitize (c, this)));
   }
 
   protected:
diff --git a/src/hb-ot-face.hh b/src/hb-ot-face.hh
index c810e9fb..4c84f0a5 100644
--- a/src/hb-ot-face.hh
+++ b/src/hb-ot-face.hh
@@ -66,10 +66,11 @@
     HB_OT_ACCELERATOR(OT, hmtx) \
     HB_OT_ACCELERATOR(OT, vmtx) \
     HB_OT_ACCELERATOR(OT, post) \
-    HB_OT_ACCELERATOR(OT, name) \
     HB_OT_ACCELERATOR(OT, kern) \
     HB_OT_ACCELERATOR(OT, glyf) \
     HB_OT_TABLE(OT, VORG) \
+    HB_OT_ACCELERATOR(OT, name) \
+    HB_OT_TABLE(AAT, ltag) \
     /* OpenType color fonts. */ \
     HB_OT_TABLE(OT, COLR) \
     HB_OT_TABLE(OT, CPAL) \
diff --git a/src/hb-ot-name-table.hh b/src/hb-ot-name-table.hh
index f42c0db8..e5809084 100644
--- a/src/hb-ot-name-table.hh
+++ b/src/hb-ot-name-table.hh
@@ -29,6 +29,7 @@
 
 #include "hb-open-type.hh"
 #include "hb-ot-name-language.hh"
+#include "hb-aat-layout.hh"
 
 
 namespace OT {
@@ -48,7 +49,7 @@ namespace OT {
 
 struct NameRecord
 {
-  inline hb_language_t language (void) const
+  inline hb_language_t language (hb_face_t *face) const
   {
     unsigned int p = platformID;
     unsigned int l = languageID;
@@ -59,8 +60,8 @@ struct NameRecord
     if (p == 1)
       return _hb_ot_name_language_for_mac_code (l);
 
-    //if (p == 0)
-      /* TODO use 'ltag' table? */
+    if (p == 0)
+      return _hb_aat_language_get (face, l);
 
     return HB_LANGUAGE_INVALID;
   }
@@ -194,7 +195,7 @@ struct name
 	hb_ot_name_entry_t *entry = this->names.push ();
 
 	entry->name_id = all_names[i].nameID;
-	entry->language = all_names[i].language ();
+	entry->language = all_names[i].language (face);
 	entry->entry_score =  all_names[i].score ();
 	entry->entry_index = i;
       }
commit dc9a5f88b401fcad598946fcf735010c563741ac
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Tue Oct 23 23:16:06 2018 -0700

    [name] Do record sanitization at run-time

diff --git a/src/hb-dsalgs.hh b/src/hb-dsalgs.hh
index 265651b7..837bb86b 100644
--- a/src/hb-dsalgs.hh
+++ b/src/hb-dsalgs.hh
@@ -530,6 +530,35 @@ struct hb_auto_t : Type
   void fini (void) {}
 };
 
+
+struct hb_bytes_t
+{
+  inline hb_bytes_t (void) : arrayZ (nullptr), len (0) {}
+  inline hb_bytes_t (const char *bytes_, unsigned int len_) : arrayZ (bytes_), len (len_) {}
+  inline hb_bytes_t (const void *bytes_, unsigned int len_) : arrayZ ((const char *) bytes_), len (len_) {}
+  template <typename T>
+  inline hb_bytes_t (const T& array) : arrayZ ((const char *) array.arrayZ), len (array.len) {}
+
+  inline void free (void) { ::free ((void *) arrayZ); arrayZ = nullptr; len = 0; }
+
+  inline int cmp (const hb_bytes_t &a) const
+  {
+    if (len != a.len)
+      return (int) a.len - (int) len;
+
+    return memcmp (a.arrayZ, arrayZ, len);
+  }
+  static inline int cmp (const void *pa, const void *pb)
+  {
+    hb_bytes_t *a = (hb_bytes_t *) pa;
+    hb_bytes_t *b = (hb_bytes_t *) pb;
+    return b->cmp (*a);
+  }
+
+  const char *arrayZ;
+  unsigned int len;
+};
+
 template <typename T>
 struct hb_array_t
 {
@@ -553,6 +582,11 @@ struct hb_array_t
     return hb_array_t<T> (arrayZ + start_offset, count);
   }
 
+  inline hb_bytes_t as_bytes (void) const
+  {
+    return hb_bytes_t (arrayZ, len * sizeof (T));
+  }
+
   inline void free (void) { ::free ((void *) arrayZ); arrayZ = nullptr; len = 0; }
 
   T *arrayZ;
@@ -561,34 +595,6 @@ struct hb_array_t
 template <typename T> static inline
 hb_array_t<T> hb_array (T *array, unsigned int len) { return hb_array_t<T> (array, len); }
 
-struct hb_bytes_t
-{
-  inline hb_bytes_t (void) : arrayZ (nullptr), len (0) {}
-  inline hb_bytes_t (const char *bytes_, unsigned int len_) : arrayZ (bytes_), len (len_) {}
-  inline hb_bytes_t (const void *bytes_, unsigned int len_) : arrayZ ((const char *) bytes_), len (len_) {}
-  template <typename T>
-  inline hb_bytes_t (const T& array) : arrayZ ((const char *) array.arrayZ), len (array.len) {}
-
-  inline void free (void) { ::free ((void *) arrayZ); arrayZ = nullptr; len = 0; }
-
-  inline int cmp (const hb_bytes_t &a) const
-  {
-    if (len != a.len)
-      return (int) a.len - (int) len;
-
-    return memcmp (a.arrayZ, arrayZ, len);
-  }
-  static inline int cmp (const void *pa, const void *pb)
-  {
-    hb_bytes_t *a = (hb_bytes_t *) pa;
-    hb_bytes_t *b = (hb_bytes_t *) pb;
-    return b->cmp (*a);
-  }
-
-  const char *arrayZ;
-  unsigned int len;
-};
-
 
 struct HbOpOr
 {
diff --git a/src/hb-ot-name-table.hh b/src/hb-ot-name-table.hh
index 9b283552..f42c0db8 100644
--- a/src/hb-ot-name-table.hh
+++ b/src/hb-ot-name-table.hh
@@ -152,13 +152,6 @@ struct name
 {
   static const hb_tag_t tableTag	= HB_OT_TAG_name;
 
-  inline hb_bytes_t get_name (unsigned int idx) const
-  {
-    const hb_array_t<const NameRecord> all_names (nameRecordZ.arrayZ, count);
-    const NameRecord &record = all_names[idx];
-    return hb_bytes_t ((const char *) (this+stringOffset).arrayZ + record.offset, record.length);
-  }
-
   inline unsigned int get_size (void) const
   { return min_size + count * nameRecordZ[0].min_size; }
 
@@ -178,7 +171,7 @@ struct name
     return_trace (c->check_struct (this) &&
 		  likely (format == 0 || format == 1) &&
 		  c->check_array (nameRecordZ.arrayZ, count) &&
-		  sanitize_records (c));
+		  c->check_range (this, stringOffset));
   }
 
   struct accelerator_t
@@ -187,6 +180,9 @@ struct name
     {
       this->blob = hb_sanitize_context_t().reference_table<name> (face);
       this->table = this->blob->as<name> ();
+      assert (this->blob->length >= this->table->stringOffset);
+      this->pool = (this->table+this->table->stringOffset).arrayZ;
+      this->pool_len = this->blob->length - this->table->stringOffset;
       const hb_array_t<const NameRecord> all_names (this->table->nameRecordZ.arrayZ,
 						    this->table->count);
 
@@ -246,8 +242,18 @@ struct name
       return entry->entry_index;
     }
 
+    inline hb_bytes_t get_name (unsigned int idx) const
+    {
+      const hb_array_t<const NameRecord> all_names (table->nameRecordZ.arrayZ, table->count);
+      const NameRecord &record = all_names[idx];
+      const hb_array_t<const char> string_pool ((const char *) pool, pool_len);
+      return string_pool.sub_array (record.offset, record.length).as_bytes ();
+    }
+
     private:
     hb_blob_t *blob;
+    const void *pool;
+    unsigned int pool_len;
     public:
     const name *table;
     hb_vector_t<hb_ot_name_entry_t> names;
diff --git a/src/hb-ot-name.cc b/src/hb-ot-name.cc
index 7962d8b8..ec3d8794 100644
--- a/src/hb-ot-name.cc
+++ b/src/hb-ot-name.cc
@@ -110,7 +110,7 @@ hb_ot_name_get_utf (hb_face_t     *face,
   int idx = name.get_index (name_id, language, &width);
   if (idx != -1)
   {
-    hb_bytes_t bytes = name.table->get_name (idx);
+    hb_bytes_t bytes = name.get_name (idx);
 
     if (width == 2) /* UTF16-BE */
       return hb_ot_name_convert_utf<hb_utf16_be_t, utf_t> (&bytes, text_size, text);
commit a53d301b1c9f72cb42cc0fc321e2ad4dbac8e064
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Tue Oct 23 23:05:55 2018 -0700

    [name] Minor

diff --git a/src/hb-ot-name-table.hh b/src/hb-ot-name-table.hh
index be9c5e36..9b283552 100644
--- a/src/hb-ot-name-table.hh
+++ b/src/hb-ot-name-table.hh
@@ -156,7 +156,7 @@ struct name
   {
     const hb_array_t<const NameRecord> all_names (nameRecordZ.arrayZ, count);
     const NameRecord &record = all_names[idx];
-    return hb_bytes_t ((char *) this + stringOffset + record.offset, record.length);
+    return hb_bytes_t ((const char *) (this+stringOffset).arrayZ + record.offset, record.length);
   }
 
   inline unsigned int get_size (void) const
@@ -164,7 +164,7 @@ struct name
 
   inline bool sanitize_records (hb_sanitize_context_t *c) const {
     TRACE_SANITIZE (this);
-    char *string_pool = (char *) this + stringOffset;
+    const void *string_pool = (this+stringOffset).arrayZ;
     unsigned int _count = count;
     /* Move to run-time?! */
     for (unsigned int i = 0; i < _count; i++)
@@ -256,7 +256,8 @@ struct name
   /* We only implement format 0 for now. */
   HBUINT16	format;			/* Format selector (=0/1). */
   HBUINT16	count;			/* Number of name records. */
-  Offset16	stringOffset;		/* Offset to start of string storage (from start of table). */
+  OffsetTo<UnsizedArrayOf<HBUINT8>, HBUINT16, false>
+		stringOffset;		/* Offset to start of string storage (from start of table). */
   UnsizedArrayOf<NameRecord>
 		nameRecordZ;		/* The name records where count is the number of records. */
   public:
commit c442fd9a10b3e91ab18720188afff08325adf6dc
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Tue Oct 23 22:45:45 2018 -0700

    [name] Add src/test-name-table tool to show all font names

diff --git a/src/Makefile.am b/src/Makefile.am
index ac03890b..fab703a1 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -348,6 +348,7 @@ noinst_PROGRAMS = \
 	main \
 	test \
 	test-buffer-serialize \
+	test-name-table \
 	test-size-params \
 	test-would-substitute \
 	$(NULL)
@@ -361,17 +362,21 @@ test_SOURCES = test.cc
 test_CPPFLAGS = $(HBCFLAGS) $(FREETYPE_CFLAGS)
 test_LDADD = libharfbuzz.la $(HBLIBS) $(FREETYPE_LIBS)
 
-test_would_substitute_SOURCES = test-would-substitute.cc
-test_would_substitute_CPPFLAGS = $(HBCFLAGS) $(FREETYPE_CFLAGS)
-test_would_substitute_LDADD = libharfbuzz.la $(HBLIBS) $(FREETYPE_LIBS)
+test_buffer_serialize_SOURCES = test-buffer-serialize.cc
+test_buffer_serialize_CPPFLAGS = $(HBCFLAGS)
+test_buffer_serialize_LDADD = libharfbuzz.la $(HBLIBS)
+
+test_name_table_SOURCES = test-name-table.cc
+test_name_table_CPPFLAGS = $(HBCFLAGS)
+test_name_table_LDADD = libharfbuzz.la $(HBLIBS)
 
 test_size_params_SOURCES = test-size-params.cc
 test_size_params_CPPFLAGS = $(HBCFLAGS)
 test_size_params_LDADD = libharfbuzz.la $(HBLIBS)
 
-test_buffer_serialize_SOURCES = test-buffer-serialize.cc
-test_buffer_serialize_CPPFLAGS = $(HBCFLAGS)
-test_buffer_serialize_LDADD = libharfbuzz.la $(HBLIBS)
+test_would_substitute_SOURCES = test-would-substitute.cc
+test_would_substitute_CPPFLAGS = $(HBCFLAGS) $(FREETYPE_CFLAGS)
+test_would_substitute_LDADD = libharfbuzz.la $(HBLIBS) $(FREETYPE_LIBS)
 
 dist_check_SCRIPTS = \
 	check-c-linkage-decls.sh \
diff --git a/src/test-name-table.cc b/src/test-name-table.cc
new file mode 100644
index 00000000..66596fe4
--- /dev/null
+++ b/src/test-name-table.cc
@@ -0,0 +1,67 @@
+/*
+ * Copyright © 2018  Google, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#include "hb.h"
+#include "hb-ot.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+
+int
+main (int argc, char **argv)
+{
+  if (argc != 2) {
+    fprintf (stderr, "usage: %s font-file\n", argv[0]);
+    exit (1);
+  }
+
+  hb_blob_t *blob = hb_blob_create_from_file (argv[1]);
+  hb_face_t *face = hb_face_create (blob, 0 /* first face */);
+  hb_blob_destroy (blob);
+  blob = nullptr;
+
+  const hb_ot_name_entry_t *entries;
+  unsigned int count = hb_ot_name_get_names (face, &entries);
+
+  for (unsigned int i = 0; i < count; i++)
+  {
+    printf ("%d	%s	",
+	    entries[i].name_id,
+	    hb_language_to_string (entries[i].language));
+
+    char buf[64];
+    unsigned int buf_size = sizeof (buf);
+    hb_ot_name_get_utf8 (face,
+			 entries[i].name_id,
+			 entries[i].language,
+			 &buf_size,
+			 buf);
+
+    printf ("%s\n", buf);
+  }
+
+  return count ? 0 : 1;
+}
commit 7007bd9dff9f8eef3263f1b39327552ff1ebae3f
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Tue Oct 23 22:44:36 2018 -0700

    [name] Rebuild language list, include missing entries

diff --git a/src/hb-ot-name-language.cc b/src/hb-ot-name-language.cc
index 19ffc004..8b79d4d6 100644
--- a/src/hb-ot-name-language.cc
+++ b/src/hb-ot-name-language.cc
@@ -26,6 +26,9 @@
 
 #include "hb-ot-name-language.hh"
 
+/* Following two tables were generated by joining FreeType, FontConfig,
+ * and OpenType specification language lists. */
+
 struct hb_ot_language_map_t
 {
   static int cmp (const void *key, const void *item)
@@ -42,275 +45,378 @@ struct hb_ot_language_map_t
 static const hb_ot_language_map_t
 hb_ms_language_map[] =
 {
-  {0x0401,	"ar"}, /* Arabic (Saudi Arabia) */
-  {0x0402,	"bg"}, /* Bulgarian (Bulgaria) */
-  {0x0404,	"zh-tw"}, /* Chinese (Taiwan) */
-  {0x0405,	"cs"}, /* Czech (Czech Republic) */
-  {0x0406,	"da"}, /* Danish (Denmark) */
-  {0x0407,	"de"}, /* German (Germany) */
-  {0x0408,	"el"}, /* Greek (Greece) */
-  {0x0409,	"en"}, /* English (United States) */
-  {0x040A,	"es"}, /* Spanish (Traditional Sort) (Spain) */
-  {0x040B,	"fi"}, /* Finnish (Finland) */
-  {0x040C,	"fr"}, /* French (France) */
-  {0x040D,	"he"}, /* Hebrew (Israel) */
-  {0x040E,	"hu"}, /* Hungarian (Hungary) */
-  {0x040F,	"is"}, /* Icelandic (Iceland) */
-  {0x0410,	"it"}, /* Italian (Italy) */
-  {0x0411,	"ja"}, /* Japanese (Japan) */
-  {0x0413,	"nl"}, /* Dutch (Netherlands) */
-  {0x0414,	"no"}, /* Norwegian (Bokmal) (Norway) */
-  {0x0415,	"pl"}, /* Polish (Poland) */
-  {0x0416,	"pt"}, /* Portuguese (Brazil) */
-  {0x0418,	"ro"}, /* Romanian (Romania) */
-  {0x0419,	"ru"}, /* Russian (Russia) */
-  {0x041A,	"hr"}, /* Croatian (Croatia) */
-  {0x041B,	"sk"}, /* Slovak (Slovakia) */
-  {0x041C,	"sq"}, /* Albanian (Albania) */
-  {0x041D,	"sv"}, /* Swedish (Sweden) */
-  {0x041E,	"th"}, /* Thai (Thailand) */
-  {0x041F,	"tr"}, /* Turkish (Turkey) */
-  {0x0420,	"ur"}, /* Urdu (Islamic Republic of Pakistan) */
-  {0x0421,	"id"}, /* Indonesian (Indonesia) */
-  {0x0422,	"uk"}, /* Ukrainian (Ukraine) */
-  {0x0423,	"be"}, /* Belarusian (Belarus) */
-  {0x0425,	"et"}, /* Estonian (Estonia) */
-  {0x0426,	"lv"}, /* Latvian (Latvia) */
-  {0x0427,	"lt"}, /* Lithuanian (Lithuania) */
-  {0x0428,	"tg"}, /* Tajik (Cyrillic) (Tajikistan) */
-  {0x042A,	"vi"}, /* Vietnamese (Vietnam) */
-  {0x042B,	"hy"}, /* Armenian (Armenia) */
-  {0x042C,	"az"}, /* Azeri (Latin) (Azerbaijan) */
-  {0x042F,	"mk"}, /* Macedonian (FYROM) (Former Yugoslav Republic of Macedonia) */
-  {0x0436,	"af"}, /* Afrikaans (South Africa) */
-  {0x0437,	"ka"}, /* Georgian (Georgia) */
-  {0x0438,	"fo"}, /* Faroese (Faroe Islands) */
-  {0x0439,	"hi"}, /* Hindi (India) */
-  {0x043A,	"mt"}, /* Maltese (Malta) */
-  {0x043E,	"ms"}, /* Malay (Malaysia) */
-  {0x0442,	"tk"}, /* Turkmen (Turkmenistan) */
-  {0x0443,	"uz"}, /* Uzbek (Latin) (Uzbekistan) */
-  {0x0445,	"bn"}, /* Bengali (India) */
-  {0x0446,	"pa"}, /* Punjabi (India) */
-  {0x0447,	"gu"}, /* Gujarati (India) */
-  {0x0449,	"ta"}, /* Tamil (India) */
-  {0x044A,	"te"}, /* Telugu (India) */
-  {0x044B,	"kn"}, /* Kannada (India) */
-  {0x044C,	"ml"}, /* Malayalam (India) */
-  {0x044D,	"as"}, /* Assamese (India) */
-  {0x044E,	"mr"}, /* Marathi (India) */
-  {0x044F,	"sa"}, /* Sanskrit (India) */
-  {0x0450,	"mn"}, /* Mongolian (Cyrillic) (Mongolia) */
-  {0x0453,	"km"}, /* Khmer (Cambodia) */
-  {0x0454,	"lo"}, /* Lao (Lao P.D.R.) */
-  {0x0457,	"kok"}, /* Konkani (India) */
-  {0x045A,	"syr"}, /* Syriac (Syria) */
-  {0x045D,	"iu"}, /* Inuktitut (Canada) */
-  {0x045E,	"am"}, /* Amharic (Ethiopia) */
-  {0x0461,	"ne"}, /* Nepali (Nepal) */
-  {0x0462,	"fy"}, /* Frisian (Netherlands) */
-  {0x0463,	"ps"}, /* Pashto (Afghanistan) */
-  {0x0464,	"phi"}, /* Filipino (Philippines) */
-  {0x0465,	"div"}, /* Divehi (Maldives) */
-  {0x0468,	"ha"}, /* Hausa (Latin) (Nigeria) */
-  {0x046A,	"yo"}, /* Yoruba (Nigeria) */
-  {0x0470,	"ibo"}, /* Igbo (Nigeria) */
-  {0x0481,	"mi"}, /* Maori (New Zealand) */
-  {0x0801,	"ar"}, /* Arabic (Iraq) */
-  {0x0804,	"zh-cn"}, /* Chinese (People’s Republic of China) */
-  {0x0807,	"de"}, /* German (Switzerland) */
-  {0x0809,	"en"}, /* English (United Kingdom) */
-  {0x080A,	"es"}, /* Spanish (Mexico) */
-  {0x080C,	"fr"}, /* French (Belgium) */
-  {0x0810,	"it"}, /* Italian (Switzerland) */
-  {0x0813,	"nl"}, /* Dutch (Belgium) */
-  {0x0814,	"nn"}, /* Norwegian (Nynorsk) (Norway) */
-  {0x0816,	"pt"}, /* Portuguese (Portugal) */
-  {0x081A,	"sr"}, /* Serbian (Latin) (Serbia) */
-  {0x081D,	"sv"}, /* Sweden (Finland) */
-  {0x082C,	"az"}, /* Azeri (Cyrillic) (Azerbaijan) */
-  {0x083E,	"ms"}, /* Malay (Brunei Darussalam) */
-  {0x0843,	"uz"}, /* Uzbek (Cyrillic) (Uzbekistan) */
-  {0x0845,	"bn"}, /* Bengali (Bangladesh) */
-  {0x0C01,	"ar"}, /* Arabic (Egypt) */
-  {0x0C04,	"zh-hk"}, /* Chinese (Hong Kong S.A.R.) */
-  {0x0C07,	"de"}, /* German (Austria) */
-  {0x0C09,	"en"}, /* English (Australia) */
-  {0x0C0C,	"fr"}, /* French (Canada) */
-  {0x0C1A,	"sr"}, /* Serbian (Cyrillic) (Serbia) */
-  {0x1001,	"ar"}, /* Arabic (Libya) */
-  {0x1004,	"zh-sg"}, /* Chinese (Singapore) */
-  {0x1007,	"de"}, /* German (Luxembourg) */
-  {0x1009,	"en"}, /* English (Canada) */
-  {0x100A,	"es"}, /* Spanish (Guatemala) */
-  {0x100C,	"fr"}, /* French (Switzerland) */
-  {0x1401,	"ar"}, /* Arabic (Algeria) */
-  {0x1409,	"en"}, /* English (New Zealand) */
-  {0x140A,	"es"}, /* Spanish (Costa Rica) */
-  {0x141A,	"bs"}, /* Bosnian (Latin) (Bosnia and Herzegovina) */
-  {0x1801,	"ar"}, /* Arabic (Morocco) */
-  {0x1809,	"en"}, /* English (Ireland) */
-  {0x180A,	"es"}, /* Spanish (Panama) */
-  {0x180C,	"fr"}, /* French (Principality of Monaco) */
-  {0x1C01,	"ar"}, /* Arabic (Tunisia) */
-  {0x1C09,	"en"}, /* English (South Africa) */
-  {0x1C0A,	"es"}, /* Spanish (Dominican Republic) */
-  {0x2001,	"ar"}, /* Arabic (Oman) */
-  {0x2009,	"en"}, /* English (Jamaica) */
-  {0x200A,	"es"}, /* Spanish (Venezuela) */
-  {0x2401,	"ar"}, /* Arabic (Yemen) */
-  {0x2409,	"en"}, /* English (Caribbean) */
-  {0x240A,	"es"}, /* Spanish (Colombia) */
-  {0x2801,	"ar"}, /* Arabic (Syria) */
-  {0x2809,	"en"}, /* English (Belize) */
-  {0x280A,	"es"}, /* Spanish (Peru) */
-  {0x2C01,	"ar"}, /* Arabic (Jordan) */
-  {0x2C09,	"en"}, /* English (Trinidad and Tobago) */
-  {0x2C0A,	"es"}, /* Spanish (Argentina) */
-  {0x3001,	"ar"}, /* Arabic (Lebanon) */
-  {0x3009,	"en"}, /* English (Zimbabwe) */
-  {0x300A,	"es"}, /* Spanish (Ecuador) */
-  {0x3401,	"ar"}, /* Arabic (Kuwait) */
-  {0x3409,	"en"}, /* English (Republic of the Philippines) */
-  {0x340A,	"es"}, /* Spanish (Chile) */
-  {0x3801,	"ar"}, /* Arabic (U.A.E.) */
-  {0x380A,	"es"}, /* Spanish (Uruguay) */
-  {0x3C01,	"ar"}, /* Arabic (Bahrain) */
-  {0x3C0A,	"es"}, /* Spanish (Paraguay) */
-  {0x4001,	"ar"}, /* Arabic (Qatar) */
-  {0x4009,	"en"}, /* English (India) */
-  {0x400A,	"es"}, /* Spanish (Bolivia) */
-  {0x4409,	"en"}, /* English (Malaysia) */
-  {0x440A,	"es"}, /* Spanish (El Salvador) */
-  {0x4809,	"en"}, /* English (Singapore) */
-  {0x480A,	"es"}, /* Spanish (Honduras) */
-  {0x4C0A,	"es"}, /* Spanish (Nicaragua) */
-  {0x500A,	"es"}, /* Spanish (Puerto Rico) */
-  {0x540A,	"es"}, /* Spanish (United States) */
+  {0x0001,	"ar"},	/* ??? */
+  {0x0004,	"zh"},	/* ??? */
+  {0x0009,	"en"},	/* ??? */
+  {0x0401,	"ar"},	/* Arabic (Saudi Arabia) */
+  {0x0402,	"bg"},	/* Bulgarian (Bulgaria) */
+//{0x0403,	""},	/* Catalan (Catalan) */
+  {0x0404,	"zh-tw"},	/* Chinese (Taiwan) */
+  {0x0405,	"cs"},	/* Czech (Czech Republic) */
+  {0x0406,	"da"},	/* Danish (Denmark) */
+  {0x0407,	"de"},	/* German (Germany) */
+  {0x0408,	"el"},	/* Greek (Greece) */
+  {0x0409,	"en"},	/* English (United States) */
+  {0x040A,	"es"},	/* Spanish (Traditional Sort) (Spain) */
+  {0x040B,	"fi"},	/* Finnish (Finland) */
+  {0x040C,	"fr"},	/* French (France) */
+  {0x040D,	"he"},	/* Hebrew (Israel) */
+  {0x040E,	"hu"},	/* Hungarian (Hungary) */
+  {0x040F,	"is"},	/* Icelandic (Iceland) */
+  {0x0410,	"it"},	/* Italian (Italy) */
+  {0x0411,	"ja"},	/* Japanese (Japan) */
+//{0x0412,	""},	/* Korean (Korea) */
+  {0x0413,	"nl"},	/* Dutch (Netherlands) */
+  {0x0414,	"no"},	/* Norwegian (Bokmal) (Norway) */
+  {0x0415,	"pl"},	/* Polish (Poland) */
+  {0x0416,	"pt"},	/* Portuguese (Brazil) */
+//{0x0417,	""},	/* Romansh (Switzerland) */
+  {0x0418,	"ro"},	/* Romanian (Romania) */
+  {0x0419,	"ru"},	/* Russian (Russia) */
+  {0x041A,	"hr"},	/* Croatian (Croatia) */
+  {0x041B,	"sk"},	/* Slovak (Slovakia) */
+  {0x041C,	"sq"},	/* Albanian (Albania) */
+  {0x041D,	"sv"},	/* Swedish (Sweden) */
+  {0x041E,	"th"},	/* Thai (Thailand) */
+  {0x041F,	"tr"},	/* Turkish (Turkey) */
+  {0x0420,	"ur"},	/* Urdu (Islamic Republic of Pakistan) */
+  {0x0421,	"id"},	/* Indonesian (Indonesia) */
+  {0x0422,	"uk"},	/* Ukrainian (Ukraine) */
+  {0x0423,	"be"},	/* Belarusian (Belarus) */
+//{0x0424,	""},	/* Slovenian (Slovenia) */
+  {0x0425,	"et"},	/* Estonian (Estonia) */
+  {0x0426,	"lv"},	/* Latvian (Latvia) */
+  {0x0427,	"lt"},	/* Lithuanian (Lithuania) */
+  {0x0428,	"tg"},	/* Tajik (Cyrillic) (Tajikistan) */
+  {0x0429,	"fa"},	/* ??? */
+  {0x042A,	"vi"},	/* Vietnamese (Vietnam) */
+  {0x042B,	"hy"},	/* Armenian (Armenia) */
+  {0x042C,	"az"},	/* Azeri (Latin) (Azerbaijan) */
+//{0x042D,	""},	/* Basque (Basque) */
+//{0x042E,	""},	/* Upper Sorbian (Germany) */
+  {0x042F,	"mk"},	/* Macedonian (FYROM) (Former Yugoslav Republic of Macedonia) */
+  {0x0430,	"st"},	/* ??? */
+  {0x0431,	"ts"},	/* ??? */
+//{0x0432,	""},	/* Setswana (South Africa) */
+  {0x0433,	"ven"},	/* ??? */
+//{0x0434,	""},	/* isiXhosa (South Africa) */
+//{0x0435,	""},	/* isiZulu (South Africa) */
+  {0x0436,	"af"},	/* Afrikaans (South Africa) */
+  {0x0437,	"ka"},	/* Georgian (Georgia) */
+  {0x0438,	"fo"},	/* Faroese (Faroe Islands) */
+  {0x0439,	"hi"},	/* Hindi (India) */
+  {0x043A,	"mt"},	/* Maltese (Malta) */
+  {0x043B,	"se"},	/* Sami (Northern) (Norway) */
+  {0x043C,	"ga"},	/* ??? */
+  {0x043D,	"yi"},	/* ??? */
+  {0x043E,	"ms"},	/* Malay (Malaysia) */
+//{0x043F,	""},	/* Kazakh (Kazakhstan) */
+//{0x0440,	""},	/* Kyrgyz (Kyrgyzstan) */
+//{0x0441,	""},	/* Kiswahili (Kenya) */
+  {0x0442,	"tk"},	/* Turkmen (Turkmenistan) */
+  {0x0443,	"uz"},	/* Uzbek (Latin) (Uzbekistan) */
+//{0x0444,	""},	/* Tatar (Russia) */
+  {0x0445,	"bn"},	/* Bengali (India) */
+  {0x0446,	"pa"},	/* Punjabi (India) */
+  {0x0447,	"gu"},	/* Gujarati (India) */
+//{0x0448,	""},	/* Odia (formerly Oriya) (India) */
+  {0x0449,	"ta"},	/* Tamil (India) */
+  {0x044A,	"te"},	/* Telugu (India) */
+  {0x044B,	"kn"},	/* Kannada (India) */
+  {0x044C,	"ml"},	/* Malayalam (India) */
+  {0x044D,	"as"},	/* Assamese (India) */
+  {0x044E,	"mr"},	/* Marathi (India) */
+  {0x044F,	"sa"},	/* Sanskrit (India) */
+  {0x0450,	"mn"},	/* Mongolian (Cyrillic) (Mongolia) */
+//{0x0451,	""},	/* Tibetan (PRC) */
+//{0x0452,	""},	/* Welsh (United Kingdom) */
+  {0x0453,	"km"},	/* Khmer (Cambodia) */
+  {0x0454,	"lo"},	/* Lao (Lao P.D.R.) */
+  {0x0455,	"my"},	/* ??? */
+//{0x0456,	""},	/* Galician (Galician) */
+  {0x0457,	"kok"},	/* Konkani (India) */
+  {0x0458,	"mni"},	/* ??? */
+  {0x0459,	"sd"},	/* ??? */
+  {0x045A,	"syr"},	/* Syriac (Syria) */
+//{0x045B,	""},	/* Sinhala (Sri Lanka) */
+  {0x045C,	"chr"},	/* ??? */
+  {0x045D,	"iu"},	/* Inuktitut (Canada) */
+  {0x045E,	"am"},	/* Amharic (Ethiopia) */
+  {0x0460,	"ks"},	/* ??? */
+  {0x0461,	"ne"},	/* Nepali (Nepal) */
+  {0x0462,	"fy"},	/* Frisian (Netherlands) */
+  {0x0463,	"ps"},	/* Pashto (Afghanistan) */
+  {0x0464,	"phi"},	/* Filipino (Philippines) */
+  {0x0465,	"div"},	/* Divehi (Maldives) */
+  {0x0468,	"ha"},	/* Hausa (Latin) (Nigeria) */
+  {0x046A,	"yo"},	/* Yoruba (Nigeria) */
+//{0x046B,	""},	/* Quechua (Bolivia) */
+//{0x046C,	""},	/* Sesotho sa Leboa (South Africa) */
+//{0x046D,	""},	/* Bashkir (Russia) */
+//{0x046E,	""},	/* Luxembourgish (Luxembourg) */
+//{0x046F,	""},	/* Greenlandic (Greenland) */
+  {0x0470,	"ibo"},	/* Igbo (Nigeria) */
+  {0x0471,	"kau"},	/* ??? */
+  {0x0472,	"om"},	/* ??? */
+  {0x0473,	"ti"},	/* ??? */
+  {0x0474,	"gn"},	/* ??? */
+  {0x0475,	"haw"},	/* ??? */
+  {0x0476,	"la"},	/* ??? */
+  {0x0477,	"so"},	/* ??? */
+//{0x0478,	""},	/* Yi (PRC) */
+  {0x0479,	"pap"},	/* ??? */
+//{0x047A,	""},	/* Mapudungun (Chile) */
+//{0x047C,	""},	/* Mohawk (Mohawk) */
+//{0x047E,	""},	/* Breton (France) */
+//{0x0480,	""},	/* Uighur (PRC) */
+  {0x0481,	"mi"},	/* Maori (New Zealand) */
+//{0x0482,	""},	/* Occitan (France) */
+//{0x0483,	""},	/* Corsican (France) */
+//{0x0484,	""},	/* Alsatian (France) */
+//{0x0485,	""},	/* Yakut (Russia) */
+//{0x0486,	""},	/* K'iche (Guatemala) */
+//{0x0487,	""},	/* Kinyarwanda (Rwanda) */
+//{0x0488,	""},	/* Wolof (Senegal) */
+//{0x048C,	""},	/* Dari (Afghanistan) */
+  {0x0801,	"ar"},	/* Arabic (Iraq) */
+  {0x0804,	"zh-cn"},	/* Chinese (People’s Republic of China) */
+  {0x0807,	"de"},	/* German (Switzerland) */
+  {0x0809,	"en"},	/* English (United Kingdom) */
+  {0x080A,	"es"},	/* Spanish (Mexico) */
+  {0x080C,	"fr"},	/* French (Belgium) */
+  {0x0810,	"it"},	/* Italian (Switzerland) */
+  {0x0812,	"ko"},	/* ??? */
+  {0x0813,	"nl"},	/* Dutch (Belgium) */
+  {0x0814,	"nn"},	/* Norwegian (Nynorsk) (Norway) */
+  {0x0816,	"pt"},	/* Portuguese (Portugal) */
+  {0x0818,	"mo"},	/* ??? */
+  {0x0819,	"ru"},	/* ??? */
+  {0x081A,	"sr"},	/* Serbian (Latin) (Serbia) */
+  {0x081D,	"sv"},	/* Sweden (Finland) */
+  {0x0820,	"ur"},	/* ??? */
+  {0x0827,	"lt"},	/* ??? */
+  {0x082C,	"az"},	/* Azeri (Cyrillic) (Azerbaijan) */
+//{0x082E,	""},	/* Lower Sorbian (Germany) */
+//{0x083B,	""},	/* Sami (Northern) (Sweden) */
+  {0x083C,	"gd"},	/* Irish (Ireland) */
+  {0x083E,	"ms"},	/* Malay (Brunei Darussalam) */
+  {0x0843,	"uz"},	/* Uzbek (Cyrillic) (Uzbekistan) */
+  {0x0845,	"bn"},	/* Bengali (Bangladesh) */
+  {0x0846,	"ar"},	/* ??? */
+//{0x0850,	""},	/* Mongolian (Traditional) (People’s Republic of China) */
+  {0x0851,	"dz"},	/* ??? */
+//{0x085D,	""},	/* Inuktitut (Latin) (Canada) */
+//{0x085F,	""},	/* Tamazight (Latin) (Algeria) */
+  {0x0861,	"ne"},	/* ??? */
+//{0x086B,	""},	/* Quechua (Ecuador) */
+  {0x0873,	"ti"},	/* ??? */
+  {0x0C01,	"ar"},	/* Arabic (Egypt) */
+  {0x0C04,	"zh-hk"},	/* Chinese (Hong Kong S.A.R.) */
+  {0x0C07,	"de"},	/* German (Austria) */
+  {0x0C09,	"en"},	/* English (Australia) */
+//{0x0C0A,	""},	/* Spanish (Modern Sort) (Spain) */
+  {0x0C0C,	"fr"},	/* French (Canada) */
+  {0x0C1A,	"sr"},	/* Serbian (Cyrillic) (Serbia) */
+//{0x0C3B,	""},	/* Sami (Northern) (Finland) */
+//{0x0C6B,	""},	/* Quechua (Peru) */
+  {0x1001,	"ar"},	/* Arabic (Libya) */
+  {0x1004,	"zh-sg"},	/* Chinese (Singapore) */
+  {0x1007,	"de"},	/* German (Luxembourg) */
+  {0x1009,	"en"},	/* English (Canada) */
+  {0x100A,	"es"},	/* Spanish (Guatemala) */
+  {0x100C,	"fr"},	/* French (Switzerland) */
+//{0x101A,	""},	/* Croatian (Latin) (Bosnia and Herzegovina) */
+//{0x103B,	""},	/* Sami (Lule) (Norway) */
+  {0x1401,	"ar"},	/* Arabic (Algeria) */
+//{0x1404,	""},	/* Chinese (Macao S.A.R.) */
+//{0x1407,	""},	/* German (Liechtenstein) */
+  {0x1409,	"en"},	/* English (New Zealand) */
+  {0x140A,	"es"},	/* Spanish (Costa Rica) */
+  {0x140C,	"fr"},	/* ??? */
+//{0x140c,	""},	/* French (Luxembourg) */
+  {0x141A,	"bs"},	/* Bosnian (Latin) (Bosnia and Herzegovina) */
+//{0x143B,	""},	/* Sami (Lule) (Sweden) */
+  {0x1801,	"ar"},	/* Arabic (Morocco) */
+  {0x1809,	"en"},	/* English (Ireland) */
+  {0x180A,	"es"},	/* Spanish (Panama) */
+  {0x180C,	"fr"},	/* French (Principality of Monaco) */
+//{0x181A,	""},	/* Serbian (Latin) (Bosnia and Herzegovina) */
+//{0x183B,	""},	/* Sami (Southern) (Norway) */
+  {0x1C01,	"ar"},	/* Arabic (Tunisia) */
+  {0x1C09,	"en"},	/* English (South Africa) */
+  {0x1C0A,	"es"},	/* Spanish (Dominican Republic) */
+  {0x1C0C,	"fr"},	/* ??? */
+//{0x1C1A,	""},	/* Serbian (Cyrillic) (Bosnia and Herzegovina) */
+//{0x1C3B,	""},	/* Sami (Southern) (Sweden) */
+  {0x2001,	"ar"},	/* Arabic (Oman) */
+  {0x2009,	"en"},	/* English (Jamaica) */
+  {0x200A,	"es"},	/* Spanish (Venezuela) */
+  {0x200C,	"fr"},	/* ??? */
+//{0x201A,	""},	/* Bosnian (Cyrillic) (Bosnia and Herzegovina) */
+//{0x203B,	""},	/* Sami (Skolt) (Finland) */
+  {0x2401,	"ar"},	/* Arabic (Yemen) */
+  {0x2409,	"en"},	/* English (Caribbean) */
+  {0x240A,	"es"},	/* Spanish (Colombia) */
+  {0x240C,	"fr"},	/* ??? */
+//{0x243B,	""},	/* Sami (Inari) (Finland) */
+  {0x2801,	"ar"},	/* Arabic (Syria) */
+  {0x2809,	"en"},	/* English (Belize) */
+  {0x280A,	"es"},	/* Spanish (Peru) */
+  {0x280C,	"fr"},	/* ??? */
+  {0x2C01,	"ar"},	/* Arabic (Jordan) */
+  {0x2C09,	"en"},	/* English (Trinidad and Tobago) */
+  {0x2C0A,	"es"},	/* Spanish (Argentina) */
+  {0x2C0C,	"fr"},	/* ??? */
+  {0x3001,	"ar"},	/* Arabic (Lebanon) */
+  {0x3009,	"en"},	/* English (Zimbabwe) */
+  {0x300A,	"es"},	/* Spanish (Ecuador) */
+  {0x300C,	"fr"},	/* ??? */
+  {0x3401,	"ar"},	/* Arabic (Kuwait) */
+  {0x3409,	"en"},	/* English (Republic of the Philippines) */
+  {0x340A,	"es"},	/* Spanish (Chile) */
+  {0x340C,	"fr"},	/* ??? */
+  {0x3801,	"ar"},	/* Arabic (U.A.E.) */
+  {0x380A,	"es"},	/* Spanish (Uruguay) */
+  {0x380C,	"fr"},	/* ??? */
+  {0x3C01,	"ar"},	/* Arabic (Bahrain) */
+  {0x3C09,	"en"},	/* ??? */
+  {0x3C0A,	"es"},	/* Spanish (Paraguay) */
+  {0x3C0C,	"fr"},	/* ??? */
+  {0x4001,	"ar"},	/* Arabic (Qatar) */
+  {0x4009,	"en"},	/* English (India) */
+  {0x400A,	"es"},	/* Spanish (Bolivia) */
+  {0x4409,	"en"},	/* English (Malaysia) */
+  {0x440A,	"es"},	/* Spanish (El Salvador) */
+  {0x4809,	"en"},	/* English (Singapore) */
+  {0x480A,	"es"},	/* Spanish (Honduras) */
+  {0x4C0A,	"es"},	/* Spanish (Nicaragua) */
+  {0x500A,	"es"},	/* Spanish (Puerto Rico) */
+  {0x540A,	"es"},	/* Spanish (United States) */
+  {0xE40A,	"es"},	/* ??? */
+  {0xE40C,	"fr"},	/* ??? */
 };
 
 static const hb_ot_language_map_t
 hb_mac_language_map[] =
 {
-  {0,	"en"}, /* English */
-  {1,	"fr"}, /* French */
-  {2,	"de"}, /* German */
-  {3,	"it"}, /* Italian */
-  {4,	"nl"}, /* Dutch */
-  {5,	"sv"}, /* Swedish */
-  {6,	"es"}, /* Spanish */
-  {7,	"da"}, /* Danish */
-  {8,	"pt"}, /* Portuguese */
-  {9,	"no"}, /* Norwegian */
-  {10,	"he"}, /* Hebrew */
-  {11,	"ja"}, /* Japanese */
-  {12,	"ar"}, /* Arabic */
-  {13,	"fi"}, /* Finnish */
-  {14,	"el"}, /* Greek */
-  {15,	"is"}, /* Icelandic */
-  {16,	"mt"}, /* Maltese */
-  {17,	"tr"}, /* Turkish */
-  {18,	"hr"}, /* Croatian */
-  {19,	"zh-tw"}, /* Chinese (Traditional) */
-  {20,	"ur"}, /* Urdu */
-  {21,	"hi"}, /* Hindi */
-  {22,	"th"}, /* Thai */
-  {23,	"ko"}, /* Korean */
-  {24,	"lt"}, /* Lithuanian */
-  {25,	"pl"}, /* Polish */
-  {26,	"hu"}, /* Hungarian */
-  {27,	"et"}, /* Estonian */
-  {28,	"lv"}, /* Latvian */
-  {30,	"fo"}, /* Faroese */
-  {31,	"fa"}, /* Farsi/Persian */
-  {32,	"ru"}, /* Russian */
-  {33,	"zh-cn"}, /* Chinese (Simplified) */
-  {34,	"nl"}, /* Flemish */
-  {35,	"ga"}, /* Irish Gaelic */
-  {36,	"sq"}, /* Albanian */
-  {37,	"ro"}, /* Romanian */
-  {38,	"cs"}, /* Czech */
-  {39,	"sk"}, /* Slovak */
-  {40,	"sl"}, /* Slovenian */
-  {41,	"yi"}, /* Yiddish */
-  {42,	"sr"}, /* Serbian */
-  {43,	"mk"}, /* Macedonian */
-  {44,	"bg"}, /* Bulgarian */
-  {45,	"uk"}, /* Ukrainian */
-  {46,	"be"}, /* Byelorussian */
-  {47,	"uz"}, /* Uzbek */
-  {48,	"kk"}, /* Kazakh */
-  {49,	"az"}, /* Azerbaijani (Cyrillic script) */
-  {49,	"az"}, /* Azerbaijani (Cyrillic script) */
-  {50,	"ar"}, /* Azerbaijani (Arabic script) */
-  {51,	"hy"}, /* Armenian */
-  {52,	"ka"}, /* Georgian */
-  {53,	"mo"}, /* Moldavian */
-  {54,	"ky"}, /* Kirghiz */
-  {55,	"tg"}, /* Tajiki */
-  {56,	"tk"}, /* Turkmen */
-  {57,	"mo"}, /* Mongolian (Mongolian script) */
-  {57,	"mo"}, /* Mongolian (Mongolian script) */
-  {58,	"mo"}, /* Mongolian (Cyrillic script) */
-  {59,	"ps"}, /* Pashto */
-  {60,	"ku"}, /* Kurdish */
-  {61,	"ks"}, /* Kashmiri */
-  {62,	"sd"}, /* Sindhi */
-  {63,	"bo"}, /* Tibetan */
-  {64,	"ne"}, /* Nepali */
-  {65,	"sa"}, /* Sanskrit */
-  {66,	"mr"}, /* Marathi */
-  {67,	"bn"}, /* Bengali */
-  {68,	"as"}, /* Assamese */
-  {69,	"gu"}, /* Gujarati */
-  {70,	"pa"}, /* Punjabi */
-  {71,	"or"}, /* Oriya */
-  {72,	"ml"}, /* Malayalam */
-  {73,	"kn"}, /* Kannada */
-  {74,	"ta"}, /* Tamil */
-  {75,	"te"}, /* Telugu */
-  {76,	"si"}, /* Sinhalese */
-  {77,	"my"}, /* Burmese */
-  {78,	"km"}, /* Khmer */
-  {79,	"lo"}, /* Lao */
-  {80,	"vi"}, /* Vietnamese */
-  {81,	"id"}, /* Indonesian */
-  {82,	"tl"}, /* Tagalog */
-  {83,	"ms"}, /* Malay (Roman script) */
-  {84,	"ms"}, /* Malay (Arabic script) */
-  {85,	"am"}, /* Amharic */
-  {86,	"ti"}, /* Tigrinya */
-  {87,	"om"}, /* Galla */
-  {88,	"so"}, /* Somali */
-  {89,	"sw"}, /* Swahili */
-  {90,	"rw"}, /* Kinyarwanda/Ruanda */
-  {91,	"rn"}, /* Rundi */
-  {92,	"ny"}, /* Nyanja/Chewa */
-  {93,	"mg"}, /* Malagasy */
-  {94,	"eo"}, /* Esperanto */
-  {128,	"cy"}, /* Welsh */
-  {129,	"eu"}, /* Basque */
-  {130,	"ca"}, /* Catalan */
-  {131,	"la"}, /* Latin */
-  {132,	"qu"}, /* Quechua */
-  {133,	"gn"}, /* Guarani */
-  {134,	"ay"}, /* Aymara */
-  {135,	"tt"}, /* Tatar */
-  {136,	"ug"}, /* Uighur */
-  {137,	"dz"}, /* Dzongkha */
-  {138,	"jw"}, /* Javanese (Roman script) */
-  {139,	"su"}, /* Sundanese (Roman script) */
-  {140,	"gl"}, /* Galician */
-  {141,	"af"}, /* Afrikaans */
-  {142,	"br"}, /* Breton */
-  {143,	"iu"}, /* Inuktitut */
-  {144,	"gd"}, /* Scottish Gaelic */
-  {145,	"gv"}, /* Manx Gaelic */
-  {146,	"ga"}, /* Irish Gaelic (with dot above) */
-  {147,	"to"}, /* Tongan */
-  {148,	"el"}, /* Greek (polytonic) */
-  {149,	"ik"}, /* Greenlandic */
-  {150,	"az"}, /* Azerbaijani (Roman script) */
+  {  0,	"en"},	/* English */
+  {  1,	"fr"},	/* French */
+  {  2,	"de"},	/* German */
+  {  3,	"it"},	/* Italian */
+  {  4,	"nl"},	/* Dutch */
+  {  5,	"sv"},	/* Swedish */
+  {  6,	"es"},	/* Spanish */
+  {  7,	"da"},	/* Danish */
+  {  8,	"pt"},	/* Portuguese */
+  {  9,	"no"},	/* Norwegian */
+  { 10,	"he"},	/* Hebrew */
+  { 11,	"ja"},	/* Japanese */
+  { 12,	"ar"},	/* Arabic */
+  { 13,	"fi"},	/* Finnish */
+  { 14,	"el"},	/* Greek */
+  { 15,	"is"},	/* Icelandic */
+  { 16,	"mt"},	/* Maltese */
+  { 17,	"tr"},	/* Turkish */
+  { 18,	"hr"},	/* Croatian */
+  { 19,	"zh-tw"},	/* Chinese (Traditional) */
+  { 20,	"ur"},	/* Urdu */
+  { 21,	"hi"},	/* Hindi */
+  { 22,	"th"},	/* Thai */
+  { 23,	"ko"},	/* Korean */
+  { 24,	"lt"},	/* Lithuanian */
+  { 25,	"pl"},	/* Polish */
+  { 26,	"hu"},	/* Hungarian */
+  { 27,	"et"},	/* Estonian */
+  { 28,	"lv"},	/* Latvian */
+//{ 29,	""},	/* Sami */
+  { 30,	"fo"},	/* Faroese */
+  { 31,	"fa"},	/* Farsi/Persian */
+  { 32,	"ru"},	/* Russian */
+  { 33,	"zh-cn"},	/* Chinese (Simplified) */
+  { 34,	"nl"},	/* Flemish */
+  { 35,	"ga"},	/* Irish Gaelic */
+  { 36,	"sq"},	/* Albanian */
+  { 37,	"ro"},	/* Romanian */
+  { 38,	"cs"},	/* Czech */
+  { 39,	"sk"},	/* Slovak */
+  { 40,	"sl"},	/* Slovenian */
+  { 41,	"yi"},	/* Yiddish */
+  { 42,	"sr"},	/* Serbian */
+  { 43,	"mk"},	/* Macedonian */
+  { 44,	"bg"},	/* Bulgarian */
+  { 45,	"uk"},	/* Ukrainian */
+  { 46,	"be"},	/* Byelorussian */
+  { 47,	"uz"},	/* Uzbek */
+  { 48,	"kk"},	/* Kazakh */
+  { 49,	"az"},	/* Azerbaijani (Cyrillic script) */
+  { 50,	"ar"},	/* Azerbaijani (Arabic script) */
+  { 51,	"hy"},	/* Armenian */
+  { 52,	"ka"},	/* Georgian */
+  { 53,	"mo"},	/* Moldavian */
+  { 54,	"ky"},	/* Kirghiz */
+  { 55,	"tg"},	/* Tajiki */
+  { 56,	"tk"},	/* Turkmen */
+  { 57,	"mo"},	/* Mongolian (Mongolian script) */
+  { 58,	"mo"},	/* Mongolian (Cyrillic script) */
+  { 59,	"ps"},	/* Pashto */
+  { 60,	"ku"},	/* Kurdish */
+  { 61,	"ks"},	/* Kashmiri */
+  { 62,	"sd"},	/* Sindhi */
+  { 63,	"bo"},	/* Tibetan */
+  { 64,	"ne"},	/* Nepali */
+  { 65,	"sa"},	/* Sanskrit */
+  { 66,	"mr"},	/* Marathi */
+  { 67,	"bn"},	/* Bengali */
+  { 68,	"as"},	/* Assamese */
+  { 69,	"gu"},	/* Gujarati */
+  { 70,	"pa"},	/* Punjabi */
+  { 71,	"or"},	/* Oriya */
+  { 72,	"ml"},	/* Malayalam */
+  { 73,	"kn"},	/* Kannada */
+  { 74,	"ta"},	/* Tamil */
+  { 75,	"te"},	/* Telugu */
+  { 76,	"si"},	/* Sinhalese */
+  { 77,	"my"},	/* Burmese */
+  { 78,	"km"},	/* Khmer */
+  { 79,	"lo"},	/* Lao */
+  { 80,	"vi"},	/* Vietnamese */
+  { 81,	"id"},	/* Indonesian */
+  { 82,	"tl"},	/* Tagalog */
+  { 83,	"ms"},	/* Malay (Roman script) */
+  { 84,	"ms"},	/* Malay (Arabic script) */
+  { 85,	"am"},	/* Amharic */
+  { 86,	"ti"},	/* Tigrinya */
+  { 87,	"om"},	/* Galla */
+  { 88,	"so"},	/* Somali */
+  { 89,	"sw"},	/* Swahili */
+  { 90,	"rw"},	/* Kinyarwanda/Ruanda */
+  { 91,	"rn"},	/* Rundi */
+  { 92,	"ny"},	/* Nyanja/Chewa */
+  { 93,	"mg"},	/* Malagasy */
+  { 94,	"eo"},	/* Esperanto */
+  {128,	"cy"},	/* Welsh */
+  {129,	"eu"},	/* Basque */
+  {130,	"ca"},	/* Catalan */
+  {131,	"la"},	/* Latin */
+  {132,	"qu"},	/* Quechua */
+  {133,	"gn"},	/* Guarani */
+  {134,	"ay"},	/* Aymara */
+  {135,	"tt"},	/* Tatar */
+  {136,	"ug"},	/* Uighur */
+  {137,	"dz"},	/* Dzongkha */
+  {138,	"jw"},	/* Javanese (Roman script) */
+  {139,	"su"},	/* Sundanese (Roman script) */
+  {140,	"gl"},	/* Galician */
+  {141,	"af"},	/* Afrikaans */
+  {142,	"br"},	/* Breton */
+  {143,	"iu"},	/* Inuktitut */
+  {144,	"gd"},	/* Scottish Gaelic */
+  {145,	"gv"},	/* Manx Gaelic */
+  {146,	"ga"},	/* Irish Gaelic (with dot above) */
+  {147,	"to"},	/* Tongan */
+  {148,	"el"},	/* Greek (polytonic) */
+  {149,	"ik"},	/* Greenlandic */
+  {150,	"az"},	/* Azerbaijani (Roman script) */
 };
 
 
commit 68f172101c1228a7d669d71da1d0eeb96a10565e
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Tue Oct 23 22:19:09 2018 -0700

    [name] Fix cmp for invalid language

diff --git a/src/hb-ot-name-table.hh b/src/hb-ot-name-table.hh
index 14a8efab..be9c5e36 100644
--- a/src/hb-ot-name-table.hh
+++ b/src/hb-ot-name-table.hh
@@ -120,6 +120,9 @@ _hb_ot_name_entry_cmp_key (const void *pa, const void *pb)
   if (a->name_id != b->name_id)
     return a->name_id < b->name_id ? -1 : +1;
 
+  if (a->language == b->language) return 0;
+  if (!a->language) return -1;
+  if (!b->language) return +1;
   return strcmp (hb_language_to_string (a->language),
 		 hb_language_to_string (b->language));
 }
commit 888a65615c7b11222749ae85c124aaa9a36fe863
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Tue Oct 23 22:16:32 2018 -0700

    [name] Fix nul-termination bug

diff --git a/src/hb-ot-name.cc b/src/hb-ot-name.cc
index 56f89335..7962d8b8 100644
--- a/src/hb-ot-name.cc
+++ b/src/hb-ot-name.cc
@@ -83,7 +83,7 @@ hb_ot_name_convert_utf (const hb_bytes_t                *bytes,
     };
 
     *text_size = dst - text;
-    *text = 0; /* NUL-terminate. */
+    *dst = 0; /* NUL-terminate. */
   }
 
   /* Accumulate length of rest. */
commit 9b532e2ed432611005b19c40cac7e626afcccd08
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Tue Oct 23 22:00:19 2018 -0700

    [name] Add language mapping

diff --git a/src/Makefile.sources b/src/Makefile.sources
index 0ee79a47..fe140b04 100644
--- a/src/Makefile.sources
+++ b/src/Makefile.sources
@@ -33,6 +33,8 @@ HB_BASE_sources = \
 	hb-ot-hmtx-table.hh \
 	hb-ot-kern-table.hh \
 	hb-ot-maxp-table.hh \
+	hb-ot-name-language.cc \
+	hb-ot-name-language.hh \
 	hb-ot-name-table.hh \
 	hb-ot-name.cc \
 	hb-ot-os2-table.hh \
diff --git a/src/hb-ot-name-language.cc b/src/hb-ot-name-language.cc
new file mode 100644
index 00000000..19ffc004
--- /dev/null
+++ b/src/hb-ot-name-language.cc
@@ -0,0 +1,349 @@
+/*
+ * Copyright © 2018  Google, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#include "hb-ot-name-language.hh"
+
+struct hb_ot_language_map_t
+{
+  static int cmp (const void *key, const void *item)
+  {
+    unsigned int a = * (unsigned int *) key;
+    unsigned int b = ((const hb_ot_language_map_t *) item)->code;
+    return a < b ? -1 : a > b ? +1 : 0;
+  }
+
+  uint16_t	code;
+  char		lang[6];
+};
+
+static const hb_ot_language_map_t
+hb_ms_language_map[] =
+{
+  {0x0401,	"ar"}, /* Arabic (Saudi Arabia) */
+  {0x0402,	"bg"}, /* Bulgarian (Bulgaria) */
+  {0x0404,	"zh-tw"}, /* Chinese (Taiwan) */
+  {0x0405,	"cs"}, /* Czech (Czech Republic) */
+  {0x0406,	"da"}, /* Danish (Denmark) */
+  {0x0407,	"de"}, /* German (Germany) */
+  {0x0408,	"el"}, /* Greek (Greece) */
+  {0x0409,	"en"}, /* English (United States) */
+  {0x040A,	"es"}, /* Spanish (Traditional Sort) (Spain) */
+  {0x040B,	"fi"}, /* Finnish (Finland) */
+  {0x040C,	"fr"}, /* French (France) */
+  {0x040D,	"he"}, /* Hebrew (Israel) */
+  {0x040E,	"hu"}, /* Hungarian (Hungary) */
+  {0x040F,	"is"}, /* Icelandic (Iceland) */
+  {0x0410,	"it"}, /* Italian (Italy) */
+  {0x0411,	"ja"}, /* Japanese (Japan) */
+  {0x0413,	"nl"}, /* Dutch (Netherlands) */
+  {0x0414,	"no"}, /* Norwegian (Bokmal) (Norway) */
+  {0x0415,	"pl"}, /* Polish (Poland) */
+  {0x0416,	"pt"}, /* Portuguese (Brazil) */
+  {0x0418,	"ro"}, /* Romanian (Romania) */
+  {0x0419,	"ru"}, /* Russian (Russia) */
+  {0x041A,	"hr"}, /* Croatian (Croatia) */
+  {0x041B,	"sk"}, /* Slovak (Slovakia) */
+  {0x041C,	"sq"}, /* Albanian (Albania) */
+  {0x041D,	"sv"}, /* Swedish (Sweden) */
+  {0x041E,	"th"}, /* Thai (Thailand) */
+  {0x041F,	"tr"}, /* Turkish (Turkey) */
+  {0x0420,	"ur"}, /* Urdu (Islamic Republic of Pakistan) */
+  {0x0421,	"id"}, /* Indonesian (Indonesia) */
+  {0x0422,	"uk"}, /* Ukrainian (Ukraine) */
+  {0x0423,	"be"}, /* Belarusian (Belarus) */
+  {0x0425,	"et"}, /* Estonian (Estonia) */
+  {0x0426,	"lv"}, /* Latvian (Latvia) */
+  {0x0427,	"lt"}, /* Lithuanian (Lithuania) */
+  {0x0428,	"tg"}, /* Tajik (Cyrillic) (Tajikistan) */
+  {0x042A,	"vi"}, /* Vietnamese (Vietnam) */
+  {0x042B,	"hy"}, /* Armenian (Armenia) */
+  {0x042C,	"az"}, /* Azeri (Latin) (Azerbaijan) */
+  {0x042F,	"mk"}, /* Macedonian (FYROM) (Former Yugoslav Republic of Macedonia) */
+  {0x0436,	"af"}, /* Afrikaans (South Africa) */
+  {0x0437,	"ka"}, /* Georgian (Georgia) */
+  {0x0438,	"fo"}, /* Faroese (Faroe Islands) */
+  {0x0439,	"hi"}, /* Hindi (India) */
+  {0x043A,	"mt"}, /* Maltese (Malta) */
+  {0x043E,	"ms"}, /* Malay (Malaysia) */
+  {0x0442,	"tk"}, /* Turkmen (Turkmenistan) */
+  {0x0443,	"uz"}, /* Uzbek (Latin) (Uzbekistan) */
+  {0x0445,	"bn"}, /* Bengali (India) */
+  {0x0446,	"pa"}, /* Punjabi (India) */
+  {0x0447,	"gu"}, /* Gujarati (India) */
+  {0x0449,	"ta"}, /* Tamil (India) */
+  {0x044A,	"te"}, /* Telugu (India) */
+  {0x044B,	"kn"}, /* Kannada (India) */
+  {0x044C,	"ml"}, /* Malayalam (India) */
+  {0x044D,	"as"}, /* Assamese (India) */
+  {0x044E,	"mr"}, /* Marathi (India) */
+  {0x044F,	"sa"}, /* Sanskrit (India) */
+  {0x0450,	"mn"}, /* Mongolian (Cyrillic) (Mongolia) */
+  {0x0453,	"km"}, /* Khmer (Cambodia) */
+  {0x0454,	"lo"}, /* Lao (Lao P.D.R.) */
+  {0x0457,	"kok"}, /* Konkani (India) */
+  {0x045A,	"syr"}, /* Syriac (Syria) */
+  {0x045D,	"iu"}, /* Inuktitut (Canada) */
+  {0x045E,	"am"}, /* Amharic (Ethiopia) */
+  {0x0461,	"ne"}, /* Nepali (Nepal) */
+  {0x0462,	"fy"}, /* Frisian (Netherlands) */
+  {0x0463,	"ps"}, /* Pashto (Afghanistan) */
+  {0x0464,	"phi"}, /* Filipino (Philippines) */
+  {0x0465,	"div"}, /* Divehi (Maldives) */
+  {0x0468,	"ha"}, /* Hausa (Latin) (Nigeria) */
+  {0x046A,	"yo"}, /* Yoruba (Nigeria) */
+  {0x0470,	"ibo"}, /* Igbo (Nigeria) */
+  {0x0481,	"mi"}, /* Maori (New Zealand) */
+  {0x0801,	"ar"}, /* Arabic (Iraq) */
+  {0x0804,	"zh-cn"}, /* Chinese (People’s Republic of China) */
+  {0x0807,	"de"}, /* German (Switzerland) */
+  {0x0809,	"en"}, /* English (United Kingdom) */
+  {0x080A,	"es"}, /* Spanish (Mexico) */
+  {0x080C,	"fr"}, /* French (Belgium) */
+  {0x0810,	"it"}, /* Italian (Switzerland) */
+  {0x0813,	"nl"}, /* Dutch (Belgium) */
+  {0x0814,	"nn"}, /* Norwegian (Nynorsk) (Norway) */
+  {0x0816,	"pt"}, /* Portuguese (Portugal) */
+  {0x081A,	"sr"}, /* Serbian (Latin) (Serbia) */
+  {0x081D,	"sv"}, /* Sweden (Finland) */
+  {0x082C,	"az"}, /* Azeri (Cyrillic) (Azerbaijan) */
+  {0x083E,	"ms"}, /* Malay (Brunei Darussalam) */
+  {0x0843,	"uz"}, /* Uzbek (Cyrillic) (Uzbekistan) */
+  {0x0845,	"bn"}, /* Bengali (Bangladesh) */
+  {0x0C01,	"ar"}, /* Arabic (Egypt) */
+  {0x0C04,	"zh-hk"}, /* Chinese (Hong Kong S.A.R.) */
+  {0x0C07,	"de"}, /* German (Austria) */
+  {0x0C09,	"en"}, /* English (Australia) */
+  {0x0C0C,	"fr"}, /* French (Canada) */
+  {0x0C1A,	"sr"}, /* Serbian (Cyrillic) (Serbia) */
+  {0x1001,	"ar"}, /* Arabic (Libya) */
+  {0x1004,	"zh-sg"}, /* Chinese (Singapore) */
+  {0x1007,	"de"}, /* German (Luxembourg) */
+  {0x1009,	"en"}, /* English (Canada) */
+  {0x100A,	"es"}, /* Spanish (Guatemala) */
+  {0x100C,	"fr"}, /* French (Switzerland) */
+  {0x1401,	"ar"}, /* Arabic (Algeria) */
+  {0x1409,	"en"}, /* English (New Zealand) */
+  {0x140A,	"es"}, /* Spanish (Costa Rica) */
+  {0x141A,	"bs"}, /* Bosnian (Latin) (Bosnia and Herzegovina) */
+  {0x1801,	"ar"}, /* Arabic (Morocco) */
+  {0x1809,	"en"}, /* English (Ireland) */
+  {0x180A,	"es"}, /* Spanish (Panama) */
+  {0x180C,	"fr"}, /* French (Principality of Monaco) */
+  {0x1C01,	"ar"}, /* Arabic (Tunisia) */
+  {0x1C09,	"en"}, /* English (South Africa) */
+  {0x1C0A,	"es"}, /* Spanish (Dominican Republic) */
+  {0x2001,	"ar"}, /* Arabic (Oman) */
+  {0x2009,	"en"}, /* English (Jamaica) */
+  {0x200A,	"es"}, /* Spanish (Venezuela) */
+  {0x2401,	"ar"}, /* Arabic (Yemen) */
+  {0x2409,	"en"}, /* English (Caribbean) */
+  {0x240A,	"es"}, /* Spanish (Colombia) */
+  {0x2801,	"ar"}, /* Arabic (Syria) */
+  {0x2809,	"en"}, /* English (Belize) */
+  {0x280A,	"es"}, /* Spanish (Peru) */
+  {0x2C01,	"ar"}, /* Arabic (Jordan) */
+  {0x2C09,	"en"}, /* English (Trinidad and Tobago) */
+  {0x2C0A,	"es"}, /* Spanish (Argentina) */
+  {0x3001,	"ar"}, /* Arabic (Lebanon) */
+  {0x3009,	"en"}, /* English (Zimbabwe) */
+  {0x300A,	"es"}, /* Spanish (Ecuador) */
+  {0x3401,	"ar"}, /* Arabic (Kuwait) */
+  {0x3409,	"en"}, /* English (Republic of the Philippines) */
+  {0x340A,	"es"}, /* Spanish (Chile) */
+  {0x3801,	"ar"}, /* Arabic (U.A.E.) */
+  {0x380A,	"es"}, /* Spanish (Uruguay) */
+  {0x3C01,	"ar"}, /* Arabic (Bahrain) */
+  {0x3C0A,	"es"}, /* Spanish (Paraguay) */
+  {0x4001,	"ar"}, /* Arabic (Qatar) */
+  {0x4009,	"en"}, /* English (India) */
+  {0x400A,	"es"}, /* Spanish (Bolivia) */
+  {0x4409,	"en"}, /* English (Malaysia) */
+  {0x440A,	"es"}, /* Spanish (El Salvador) */
+  {0x4809,	"en"}, /* English (Singapore) */
+  {0x480A,	"es"}, /* Spanish (Honduras) */
+  {0x4C0A,	"es"}, /* Spanish (Nicaragua) */
+  {0x500A,	"es"}, /* Spanish (Puerto Rico) */
+  {0x540A,	"es"}, /* Spanish (United States) */
+};
+
+static const hb_ot_language_map_t
+hb_mac_language_map[] =
+{
+  {0,	"en"}, /* English */
+  {1,	"fr"}, /* French */
+  {2,	"de"}, /* German */
+  {3,	"it"}, /* Italian */
+  {4,	"nl"}, /* Dutch */
+  {5,	"sv"}, /* Swedish */
+  {6,	"es"}, /* Spanish */
+  {7,	"da"}, /* Danish */
+  {8,	"pt"}, /* Portuguese */
+  {9,	"no"}, /* Norwegian */
+  {10,	"he"}, /* Hebrew */
+  {11,	"ja"}, /* Japanese */
+  {12,	"ar"}, /* Arabic */
+  {13,	"fi"}, /* Finnish */
+  {14,	"el"}, /* Greek */
+  {15,	"is"}, /* Icelandic */
+  {16,	"mt"}, /* Maltese */
+  {17,	"tr"}, /* Turkish */
+  {18,	"hr"}, /* Croatian */
+  {19,	"zh-tw"}, /* Chinese (Traditional) */
+  {20,	"ur"}, /* Urdu */
+  {21,	"hi"}, /* Hindi */
+  {22,	"th"}, /* Thai */
+  {23,	"ko"}, /* Korean */
+  {24,	"lt"}, /* Lithuanian */
+  {25,	"pl"}, /* Polish */
+  {26,	"hu"}, /* Hungarian */
+  {27,	"et"}, /* Estonian */
+  {28,	"lv"}, /* Latvian */
+  {30,	"fo"}, /* Faroese */
+  {31,	"fa"}, /* Farsi/Persian */
+  {32,	"ru"}, /* Russian */
+  {33,	"zh-cn"}, /* Chinese (Simplified) */
+  {34,	"nl"}, /* Flemish */
+  {35,	"ga"}, /* Irish Gaelic */
+  {36,	"sq"}, /* Albanian */
+  {37,	"ro"}, /* Romanian */
+  {38,	"cs"}, /* Czech */
+  {39,	"sk"}, /* Slovak */
+  {40,	"sl"}, /* Slovenian */
+  {41,	"yi"}, /* Yiddish */
+  {42,	"sr"}, /* Serbian */
+  {43,	"mk"}, /* Macedonian */
+  {44,	"bg"}, /* Bulgarian */
+  {45,	"uk"}, /* Ukrainian */
+  {46,	"be"}, /* Byelorussian */
+  {47,	"uz"}, /* Uzbek */
+  {48,	"kk"}, /* Kazakh */
+  {49,	"az"}, /* Azerbaijani (Cyrillic script) */
+  {49,	"az"}, /* Azerbaijani (Cyrillic script) */
+  {50,	"ar"}, /* Azerbaijani (Arabic script) */
+  {51,	"hy"}, /* Armenian */
+  {52,	"ka"}, /* Georgian */
+  {53,	"mo"}, /* Moldavian */
+  {54,	"ky"}, /* Kirghiz */
+  {55,	"tg"}, /* Tajiki */
+  {56,	"tk"}, /* Turkmen */
+  {57,	"mo"}, /* Mongolian (Mongolian script) */
+  {57,	"mo"}, /* Mongolian (Mongolian script) */
+  {58,	"mo"}, /* Mongolian (Cyrillic script) */
+  {59,	"ps"}, /* Pashto */
+  {60,	"ku"}, /* Kurdish */
+  {61,	"ks"}, /* Kashmiri */
+  {62,	"sd"}, /* Sindhi */
+  {63,	"bo"}, /* Tibetan */
+  {64,	"ne"}, /* Nepali */
+  {65,	"sa"}, /* Sanskrit */
+  {66,	"mr"}, /* Marathi */
+  {67,	"bn"}, /* Bengali */
+  {68,	"as"}, /* Assamese */
+  {69,	"gu"}, /* Gujarati */
+  {70,	"pa"}, /* Punjabi */
+  {71,	"or"}, /* Oriya */
+  {72,	"ml"}, /* Malayalam */
+  {73,	"kn"}, /* Kannada */
+  {74,	"ta"}, /* Tamil */
+  {75,	"te"}, /* Telugu */
+  {76,	"si"}, /* Sinhalese */
+  {77,	"my"}, /* Burmese */
+  {78,	"km"}, /* Khmer */
+  {79,	"lo"}, /* Lao */
+  {80,	"vi"}, /* Vietnamese */
+  {81,	"id"}, /* Indonesian */
+  {82,	"tl"}, /* Tagalog */
+  {83,	"ms"}, /* Malay (Roman script) */
+  {84,	"ms"}, /* Malay (Arabic script) */
+  {85,	"am"}, /* Amharic */
+  {86,	"ti"}, /* Tigrinya */
+  {87,	"om"}, /* Galla */
+  {88,	"so"}, /* Somali */
+  {89,	"sw"}, /* Swahili */
+  {90,	"rw"}, /* Kinyarwanda/Ruanda */
+  {91,	"rn"}, /* Rundi */
+  {92,	"ny"}, /* Nyanja/Chewa */
+  {93,	"mg"}, /* Malagasy */
+  {94,	"eo"}, /* Esperanto */
+  {128,	"cy"}, /* Welsh */
+  {129,	"eu"}, /* Basque */
+  {130,	"ca"}, /* Catalan */
+  {131,	"la"}, /* Latin */
+  {132,	"qu"}, /* Quechua */
+  {133,	"gn"}, /* Guarani */
+  {134,	"ay"}, /* Aymara */
+  {135,	"tt"}, /* Tatar */
+  {136,	"ug"}, /* Uighur */
+  {137,	"dz"}, /* Dzongkha */
+  {138,	"jw"}, /* Javanese (Roman script) */
+  {139,	"su"}, /* Sundanese (Roman script) */
+  {140,	"gl"}, /* Galician */
+  {141,	"af"}, /* Afrikaans */
+  {142,	"br"}, /* Breton */
+  {143,	"iu"}, /* Inuktitut */
+  {144,	"gd"}, /* Scottish Gaelic */
+  {145,	"gv"}, /* Manx Gaelic */
+  {146,	"ga"}, /* Irish Gaelic (with dot above) */
+  {147,	"to"}, /* Tongan */
+  {148,	"el"}, /* Greek (polytonic) */
+  {149,	"ik"}, /* Greenlandic */
+  {150,	"az"}, /* Azerbaijani (Roman script) */
+};
+
+
+static hb_language_t
+_hb_ot_name_language_for (unsigned int code,
+			  const hb_ot_language_map_t *array,
+			  unsigned int len)
+{
+  const hb_ot_language_map_t *entry = (const hb_ot_language_map_t *)
+				      hb_bsearch (&code,
+						  array,
+						  len,
+						  sizeof (array[0]),
+						  hb_ot_language_map_t::cmp);
+
+  if (entry)
+    return hb_language_from_string (entry->lang, -1);
+
+  return HB_LANGUAGE_INVALID;
+}
+
+hb_language_t
+_hb_ot_name_language_for_ms_code (unsigned int code)
+{
+  return _hb_ot_name_language_for (code,
+				   hb_ms_language_map,
+				   ARRAY_LENGTH (hb_ms_language_map));
+}
+
+hb_language_t
+_hb_ot_name_language_for_mac_code (unsigned int code)
+{
+  return _hb_ot_name_language_for (code,
+				   hb_mac_language_map,
+				   ARRAY_LENGTH (hb_mac_language_map));
+}
diff --git a/src/hb-ot-name-language.hh b/src/hb-ot-name-language.hh
new file mode 100644
index 00000000..903076c0
--- /dev/null
+++ b/src/hb-ot-name-language.hh
@@ -0,0 +1,40 @@
+/*
+ * Copyright © 2018  Google, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_OT_NAME_LANGUAGE_HH
+#define HB_OT_NAME_LANGUAGE_HH
+
+#include "hb.hh"
+
+
+HB_INTERNAL hb_language_t
+_hb_ot_name_language_for_ms_code (unsigned int code);
+
+HB_INTERNAL hb_language_t
+_hb_ot_name_language_for_mac_code (unsigned int code);
+
+
+#endif /* HB_OT_NAME_LANGUAGE_HH */
diff --git a/src/hb-ot-name-table.hh b/src/hb-ot-name-table.hh
index c6b7796e..14a8efab 100644
--- a/src/hb-ot-name-table.hh
+++ b/src/hb-ot-name-table.hh
@@ -28,6 +28,7 @@
 #define HB_OT_NAME_TABLE_HH
 
 #include "hb-open-type.hh"
+#include "hb-ot-name-language.hh"
 
 
 namespace OT {
@@ -53,19 +54,13 @@ struct NameRecord
     unsigned int l = languageID;
 
     if (p == 3)
-    {
-      switch (l)
-      {
-        case 0x0409:	return hb_language_from_string ("en", -1);
-      }
-    }
-    else if (p == 1)
-    {
-      switch (l)
-      {
-        case 0:		return hb_language_from_string ("en", -1);
-      }
-    }
+      return _hb_ot_name_language_for_ms_code (l);
+
+    if (p == 1)
+      return _hb_ot_name_language_for_mac_code (l);
+
+    //if (p == 0)
+      /* TODO use 'ltag' table? */
 
     return HB_LANGUAGE_INVALID;
   }
commit e2f9b657758cda3708c0a9db971c467ca59d5c19
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Tue Oct 23 21:19:56 2018 -0700

    [name] Start adding language support

diff --git a/src/hb-ot-name-table.hh b/src/hb-ot-name-table.hh
index c1e89a99..c6b7796e 100644
--- a/src/hb-ot-name-table.hh
+++ b/src/hb-ot-name-table.hh
@@ -47,6 +47,29 @@ namespace OT {
 
 struct NameRecord
 {
+  inline hb_language_t language (void) const
+  {
+    unsigned int p = platformID;
+    unsigned int l = languageID;
+
+    if (p == 3)
+    {
+      switch (l)
+      {
+        case 0x0409:	return hb_language_from_string ("en", -1);
+      }
+    }
+    else if (p == 1)
+    {
+      switch (l)
+      {
+        case 0:		return hb_language_from_string ("en", -1);
+      }
+    }
+
+    return HB_LANGUAGE_INVALID;
+  }
+
   inline uint16_t score (void) const
   {
     /* Same order as in cmap::find_best_subtable(). */
@@ -177,7 +200,7 @@ struct name
 	hb_ot_name_entry_t *entry = this->names.push ();
 
 	entry->name_id = all_names[i].nameID;
-	entry->language = HB_LANGUAGE_INVALID; /* XXX */
+	entry->language = all_names[i].language ();
 	entry->entry_score =  all_names[i].score ();
 	entry->entry_index = i;
       }
commit 6db6bbe64bd63554919647c5b527e03aedbaee4e
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Tue Oct 23 21:12:58 2018 -0700

    [name] Remove unused cmp function

diff --git a/src/hb-ot-name-table.hh b/src/hb-ot-name-table.hh
index 26906671..c1e89a99 100644
--- a/src/hb-ot-name-table.hh
+++ b/src/hb-ot-name-table.hh
@@ -47,22 +47,6 @@ namespace OT {
 
 struct NameRecord
 {
-  static int cmp (const void *pa, const void *pb)
-  {
-    const NameRecord *a = (const NameRecord *) pa;
-    const NameRecord *b = (const NameRecord *) pb;
-    int ret;
-    ret = b->platformID.cmp (a->platformID);
-    if (ret) return ret;
-    ret = b->encodingID.cmp (a->encodingID);
-    if (ret) return ret;
-    ret = b->languageID.cmp (a->languageID);
-    if (ret) return ret;
-    ret = b->nameID.cmp (a->nameID);
-    if (ret) return ret;
-    return 0;
-  }
-
   inline uint16_t score (void) const
   {
     /* Same order as in cmap::find_best_subtable(). */
commit 4668a05006e6c4797df19651489b4589817e1e01
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Tue Oct 23 20:51:53 2018 -0700

    [name] Hook things up
    
    Accept Mac Latin name entries as ASCII as well.

diff --git a/src/hb-ot-name-table.hh b/src/hb-ot-name-table.hh
index f2eb4968..26906671 100644
--- a/src/hb-ot-name-table.hh
+++ b/src/hb-ot-name-table.hh
@@ -84,7 +84,8 @@ struct NameRecord
     /* Symbol. */
     if (p == 3 && e ==  0) return 8;
 
-    /* TODO Apple MacRoman (0:1). */
+    /* We treat all Mac Latin names as ASCII only. */
+    if (p == 1 && e ==  0) return 10; /* 10 is magic number :| */
 
     return UNSUPPORTED;
   }
@@ -198,11 +199,15 @@ struct name
       }
 
       this->names.qsort (_hb_ot_name_entry_cmp);
-      /* Walk and pick best only for each name_id,language pair... */
+      /* Walk and pick best only for each name_id,language pair,
+       * while dropping unsupported encodings. */
       unsigned int j = 0;
-      for (unsigned int i = 1; i < this->names.len; i++)
+      for (unsigned int i = 0; i < this->names.len; i++)
       {
-        if (this->names[i - 1].name_id  == this->names[i].name_id &&
+        if (this->names[i].entry_score == UNSUPPORTED)
+	  continue;
+        if (i &&
+	    this->names[i - 1].name_id  == this->names[i].name_id &&
 	    this->names[i - 1].language == this->names[i].language)
 	  continue;
 	this->names[j++] = this->names[i];
@@ -217,7 +222,8 @@ struct name
     }
 
     inline int get_index (hb_name_id_t   name_id,
-			  hb_language_t  language) const
+			  hb_language_t  language,
+			  unsigned int  *width=nullptr) const
     {
       const hb_ot_name_entry_t key = {name_id, {0}, language};
       const hb_ot_name_entry_t *entry = (const hb_ot_name_entry_t *)
@@ -226,7 +232,13 @@ struct name
 						    this->names.len,
 						    sizeof (key),
 						    _hb_ot_name_entry_cmp_key);
-      return entry ? entry->entry_index : -1;
+      if (!entry)
+        return -1;
+
+      if (width)
+        *width = entry->entry_score < 10 ? 2 : 1;
+
+      return entry->entry_index;
     }
 
     private:
diff --git a/src/hb-ot-name.cc b/src/hb-ot-name.cc
index 626e0637..56f89335 100644
--- a/src/hb-ot-name.cc
+++ b/src/hb-ot-name.cc
@@ -106,13 +106,17 @@ hb_ot_name_get_utf (hb_face_t     *face,
 {
   const OT::name_accelerator_t &name = _get_name (face);
 
-  int idx = name.get_index (name_id, language);
+  unsigned int width;
+  int idx = name.get_index (name_id, language, &width);
   if (idx != -1)
   {
     hb_bytes_t bytes = name.table->get_name (idx);
 
-    if (true /*UTF16-BE*/)
+    if (width == 2) /* UTF16-BE */
       return hb_ot_name_convert_utf<hb_utf16_be_t, utf_t> (&bytes, text_size, text);
+
+    if (width == 1) /* ASCII */
+      return hb_ot_name_convert_utf<hb_ascii_t, utf_t> (&bytes, text_size, text);
   }
 
   if (text_size)
diff --git a/src/hb-utf.hh b/src/hb-utf.hh
index 5e2faebb..f78d5499 100644
--- a/src/hb-utf.hh
+++ b/src/hb-utf.hh
@@ -398,4 +398,59 @@ struct hb_latin1_t
   }
 };
 
+
+struct hb_ascii_t
+{
+  typedef uint8_t codepoint_t;
+
+  static inline const codepoint_t *
+  next (const codepoint_t *text,
+	const codepoint_t *end HB_UNUSED,
+	hb_codepoint_t *unicode,
+	hb_codepoint_t replacement HB_UNUSED)
+  {
+    *unicode = *text++;
+    if (*unicode >= 0x100)
+      *unicode = replacement;
+    return text;
+  }
+
+  static inline const codepoint_t *
+  prev (const codepoint_t *text,
+	const codepoint_t *start HB_UNUSED,
+	hb_codepoint_t *unicode,
+	hb_codepoint_t replacement)
+  {
+    *unicode = *--text;
+    if (*unicode >= 0x0080)
+      *unicode = replacement;
+    return text;
+  }
+
+  static inline unsigned int
+  strlen (const codepoint_t *text)
+  {
+    unsigned int l = 0;
+    while (*text++) l++;
+    return l;
+  }
+
+  static inline unsigned int
+  encode_len (hb_codepoint_t unicode HB_UNUSED)
+  {
+    return 1;
+  }
+
+  static inline codepoint_t *
+  encode (codepoint_t *text,
+	  const codepoint_t *end HB_UNUSED,
+	  hb_codepoint_t unicode)
+  {
+    if (unlikely (unicode >= 0x0080u))
+      unicode = '?';
+    *text++ = unicode;
+    return text;
+  }
+};
+
 #endif /* HB_UTF_HH */
commit 69f5da0629f1e5a307fc49fe58490aa92d1bd0e2
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Tue Oct 23 20:30:40 2018 -0700

    [name] More
    
    It assumes all names are encoded in UTF16-BE.  Other than that, and not
    listing languages correctly, it's *supposed* to work.

diff --git a/src/hb-dsalgs.hh b/src/hb-dsalgs.hh
index d22e8809..265651b7 100644
--- a/src/hb-dsalgs.hh
+++ b/src/hb-dsalgs.hh
@@ -313,6 +313,27 @@ hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2, T lo3, T hi3)
  */
 
 static inline void *
+hb_bsearch (const void *key, const void *base,
+	    size_t nmemb, size_t size,
+	    int (*compar)(const void *_key, const void *_item))
+{
+  int min = 0, max = (int) nmemb - 1;
+  while (min <= max)
+  {
+    int mid = (min + max) / 2;
+    const void *p = (const void *) (((const char *) base) + (mid * size));
+    int c = compar (key, p);
+    if (c < 0)
+      max = mid - 1;
+    else if (c > 0)
+      min = mid + 1;
+    else
+      return (void *) p;
+  }
+  return nullptr;
+}
+
+static inline void *
 hb_bsearch_r (const void *key, const void *base,
 	      size_t nmemb, size_t size,
 	      int (*compar)(const void *_key, const void *_item, void *_arg),
diff --git a/src/hb-ot-name-table.hh b/src/hb-ot-name-table.hh
index 8967fcbd..f2eb4968 100644
--- a/src/hb-ot-name-table.hh
+++ b/src/hb-ot-name-table.hh
@@ -107,20 +107,31 @@ struct NameRecord
 };
 
 static int
-_hb_ot_name_entry_cmp (const void *pa, const void *pb)
+_hb_ot_name_entry_cmp_key (const void *pa, const void *pb)
 {
   const hb_ot_name_entry_t *a = (const hb_ot_name_entry_t *) pa;
   const hb_ot_name_entry_t *b = (const hb_ot_name_entry_t *) pb;
 
-  /* Sort by name_id, then language, then score, then index. */
+  /* Compare by name_id, then language. */
 
   if (a->name_id != b->name_id)
     return a->name_id < b->name_id ? -1 : +1;
 
-  int e = strcmp (hb_language_to_string (a->language),
-		  hb_language_to_string (b->language));
-  if (e)
-    return e;
+  return strcmp (hb_language_to_string (a->language),
+		 hb_language_to_string (b->language));
+}
+
+static int
+_hb_ot_name_entry_cmp (const void *pa, const void *pb)
+{
+  /* Compare by name_id, then language, then score, then index. */
+
+  int v = _hb_ot_name_entry_cmp_key (pa, pb);
+  if (v)
+    return v;
+
+  const hb_ot_name_entry_t *a = (const hb_ot_name_entry_t *) pa;
+  const hb_ot_name_entry_t *b = (const hb_ot_name_entry_t *) pb;
 
   if (a->entry_score != b->entry_score)
     return a->entry_score < b->entry_score ? -1 : +1;
@@ -199,13 +210,25 @@ struct name
       this->names.resize (j);
     }
 
-
     inline void fini (void)
     {
       this->names.fini ();
       hb_blob_destroy (this->blob);
     }
 
+    inline int get_index (hb_name_id_t   name_id,
+			  hb_language_t  language) const
+    {
+      const hb_ot_name_entry_t key = {name_id, {0}, language};
+      const hb_ot_name_entry_t *entry = (const hb_ot_name_entry_t *)
+					hb_bsearch (&key,
+						    this->names.arrayZ(),
+						    this->names.len,
+						    sizeof (key),
+						    _hb_ot_name_entry_cmp_key);
+      return entry ? entry->entry_index : -1;
+    }
+
     private:
     hb_blob_t *blob;
     public:
diff --git a/src/hb-ot-name.cc b/src/hb-ot-name.cc
index fe1276c3..626e0637 100644
--- a/src/hb-ot-name.cc
+++ b/src/hb-ot-name.cc
@@ -105,11 +105,15 @@ hb_ot_name_get_utf (hb_face_t     *face,
 		    typename utf_t::codepoint_t *text /* OUT */)
 {
   const OT::name_accelerator_t &name = _get_name (face);
-  unsigned int idx = 0; // XXX bsearch and find
-  hb_bytes_t bytes = name.table->get_name (idx);
 
-  if (true /*UTF16-BE*/)
-    return hb_ot_name_convert_utf<hb_utf16_be_t, utf_t> (&bytes, text_size, text);
+  int idx = name.get_index (name_id, language);
+  if (idx != -1)
+  {
+    hb_bytes_t bytes = name.table->get_name (idx);
+
+    if (true /*UTF16-BE*/)
+      return hb_ot_name_convert_utf<hb_utf16_be_t, utf_t> (&bytes, text_size, text);
+  }
 
   if (text_size)
   {
diff --git a/src/hb-ot-os2-unicode-ranges.hh b/src/hb-ot-os2-unicode-ranges.hh
index 19780088..b0ccd00d 100644
--- a/src/hb-ot-os2-unicode-ranges.hh
+++ b/src/hb-ot-os2-unicode-ranges.hh
@@ -34,7 +34,7 @@ namespace OT {
 struct OS2Range
 {
   static int
-  cmp (const void *_key, const void *_item, void *_arg)
+  cmp (const void *_key, const void *_item)
   {
     hb_codepoint_t cp = *((hb_codepoint_t *) _key);
     const OS2Range *range = (OS2Range *) _item;
@@ -233,10 +233,10 @@ static const OS2Range _hb_os2_unicode_ranges[] =
 static unsigned int
 _hb_ot_os2_get_unicode_range_bit (hb_codepoint_t cp)
 {
-  OS2Range *range = (OS2Range*) hb_bsearch_r (&cp, _hb_os2_unicode_ranges,
-					      ARRAY_LENGTH (_hb_os2_unicode_ranges),
-					      sizeof (OS2Range),
-					      OS2Range::cmp, nullptr);
+  OS2Range *range = (OS2Range*) hb_bsearch (&cp, _hb_os2_unicode_ranges,
+					    ARRAY_LENGTH (_hb_os2_unicode_ranges),
+					    sizeof (OS2Range),
+					    OS2Range::cmp);
   if (range != nullptr)
     return range->bit;
   return -1;
diff --git a/src/hb-unicode.cc b/src/hb-unicode.cc
index 596e76d0..a08f8882 100644
--- a/src/hb-unicode.cc
+++ b/src/hb-unicode.cc
@@ -576,8 +576,8 @@ _hb_modified_combining_class[256] =
 bool
 _hb_unicode_is_emoji_Extended_Pictographic (hb_codepoint_t cp)
 {
-  return hb_bsearch_r (&cp, _hb_unicode_emoji_Extended_Pictographic_table,
-		       ARRAY_LENGTH (_hb_unicode_emoji_Extended_Pictographic_table),
-		       sizeof (hb_unicode_range_t),
-		       hb_unicode_range_t::cmp, nullptr);
+  return hb_bsearch (&cp, _hb_unicode_emoji_Extended_Pictographic_table,
+		     ARRAY_LENGTH (_hb_unicode_emoji_Extended_Pictographic_table),
+		     sizeof (hb_unicode_range_t),
+		     hb_unicode_range_t::cmp);
 }
diff --git a/src/hb-unicode.hh b/src/hb-unicode.hh
index 6d6a4fa0..4326798d 100644
--- a/src/hb-unicode.hh
+++ b/src/hb-unicode.hh
@@ -369,7 +369,7 @@ DECLARE_NULL_INSTANCE (hb_unicode_funcs_t);
 struct hb_unicode_range_t
 {
   static int
-  cmp (const void *_key, const void *_item, void *_arg)
+  cmp (const void *_key, const void *_item)
   {
     hb_codepoint_t cp = *((hb_codepoint_t *) _key);
     const hb_unicode_range_t *range = (hb_unicode_range_t *) _item;
commit 64334aff8c2ea5aa066d77a95844bc6f84efe725
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Tue Oct 23 20:15:53 2018 -0700

    [name] Fix check

diff --git a/src/hb-ot-name.h b/src/hb-ot-name.h
index f2d2e4a6..ff1ae24d 100644
--- a/src/hb-ot-name.h
+++ b/src/hb-ot-name.h
@@ -49,7 +49,7 @@ typedef unsigned int hb_name_id_t;
 #define HB_NAME_ID_INVALID 0xFFFF
 
 
-unsigned int
+HB_EXTERN unsigned int
 hb_ot_name_get_utf8 (hb_face_t     *face,
 		     hb_name_id_t   name_id,
 		     hb_language_t  language,
commit 5531bd068e759a5acb3b8d301c0ff9c64844166e
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Tue Oct 23 20:04:05 2018 -0700

    [name] Flesh out UTF-X to UTF-X conversion routines

diff --git a/src/hb-ot-name.cc b/src/hb-ot-name.cc
index 3cb4a923..fe1276c3 100644
--- a/src/hb-ot-name.cc
+++ b/src/hb-ot-name.cc
@@ -51,6 +51,51 @@ hb_ot_name_get_names (hb_face_t                 *face,
 }
 
 
+template <typename in_utf_t, typename out_utf_t>
+static inline unsigned int
+hb_ot_name_convert_utf (const hb_bytes_t                *bytes,
+			unsigned int                    *text_size /* IN/OUT */,
+			typename out_utf_t::codepoint_t *text /* OUT */)
+{
+  unsigned int src_len = bytes->len / sizeof (typename in_utf_t::codepoint_t);
+  const typename in_utf_t::codepoint_t *src = (const typename in_utf_t::codepoint_t *) bytes->arrayZ;
+  const typename in_utf_t::codepoint_t *src_end = src + src_len;
+
+  typename out_utf_t::codepoint_t *dst = text;
+
+  hb_codepoint_t unicode;
+  const hb_codepoint_t replacement = HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT;
+
+  if (text_size && *text_size)
+  {
+    (*text_size)--; /* Same room for NUL-termination. */
+    const typename out_utf_t::codepoint_t *dst_end = text + *text_size;
+
+    while (src < src_end && dst < dst_end)
+    {
+      const typename in_utf_t::codepoint_t *src_next = in_utf_t::next (src, src_end, &unicode, replacement);
+      typename out_utf_t::codepoint_t *dst_next = out_utf_t::encode (dst, dst_end, unicode);
+      if (dst_next == dst)
+        break; /* Out-of-room. */
+
+      dst = dst_next;
+      src = src_next;
+    };
+
+    *text_size = dst - text;
+    *text = 0; /* NUL-terminate. */
+  }
+
+  /* Accumulate length of rest. */
+  unsigned int dst_len = dst - text;
+  while (src < src_end)
+  {
+    src = in_utf_t::next (src, src_end, &unicode, replacement);
+    dst_len += out_utf_t::encode_len (unicode);
+  };
+  return dst_len;
+}
+
 template <typename utf_t>
 static inline unsigned int
 hb_ot_name_get_utf (hb_face_t     *face,
@@ -63,22 +108,27 @@ hb_ot_name_get_utf (hb_face_t     *face,
   unsigned int idx = 0; // XXX bsearch and find
   hb_bytes_t bytes = name.table->get_name (idx);
 
-  unsigned int full_length = 0;
-  const typename utf_t::codepoint_t *src = (const typename utf_t::codepoint_t *) bytes.arrayZ;
-  unsigned int src_len = bytes.len / sizeof (typename utf_t::codepoint_t);
+  if (true /*UTF16-BE*/)
+    return hb_ot_name_convert_utf<hb_utf16_be_t, utf_t> (&bytes, text_size, text);
 
-  if (text_size && *text_size)
+  if (text_size)
   {
-    *text_size--; /* Leave room for nul-termination. */
-    /* TODO Switch to walking string and validating. */
-    memcpy (text,
-	    src,
-	    MIN (*text_size, src_len) * sizeof (typename utf_t::codepoint_t));
+    if (*text_size)
+      *text = 0;
+    *text_size = 0;
   }
+  return 0;
+}
 
-  /* Walk the rest, accumulate the full length. */
-
-  return *text_size; //XXX
+unsigned int
+hb_ot_name_get_utf8 (hb_face_t     *face,
+		     hb_name_id_t   name_id,
+		     hb_language_t  language,
+		     unsigned int  *text_size /* IN/OUT */,
+		     char          *text      /* OUT */)
+{
+  return hb_ot_name_get_utf<hb_utf8_t> (face, name_id, language, text_size,
+					(hb_utf8_t::codepoint_t *) text);
 }
 
 unsigned int
@@ -90,3 +140,13 @@ hb_ot_name_get_utf16 (hb_face_t     *face,
 {
   return hb_ot_name_get_utf<hb_utf16_t> (face, name_id, language, text_size, text);
 }
+
+unsigned int
+hb_ot_name_get_utf32 (hb_face_t     *face,
+		      hb_name_id_t   name_id,
+		      hb_language_t  language,
+		      unsigned int  *text_size /* IN/OUT */,
+		      uint32_t      *text      /* OUT */)
+{
+  return hb_ot_name_get_utf<hb_utf32_t> (face, name_id, language, text_size, text);
+}
diff --git a/src/hb-ot-name.h b/src/hb-ot-name.h
index 0afcd3fc..f2d2e4a6 100644
--- a/src/hb-ot-name.h
+++ b/src/hb-ot-name.h
@@ -49,14 +49,12 @@ typedef unsigned int hb_name_id_t;
 #define HB_NAME_ID_INVALID 0xFFFF
 
 
-#if 0
-HB_EXTERN unsigned int
-Xhb_ot_name_get_utf8 (hb_face_t     *face,
+unsigned int
+hb_ot_name_get_utf8 (hb_face_t     *face,
 		     hb_name_id_t   name_id,
 		     hb_language_t  language,
 		     unsigned int  *text_size /* IN/OUT */,
 		     char          *text      /* OUT */);
-#endif
 
 HB_EXTERN unsigned int
 hb_ot_name_get_utf16 (hb_face_t     *face,
@@ -65,14 +63,12 @@ hb_ot_name_get_utf16 (hb_face_t     *face,
 		      unsigned int  *text_size /* IN/OUT */,
 		      uint16_t      *text      /* OUT */);
 
-#if 0
 HB_EXTERN unsigned int
-Xhb_ot_name_get_utf32 (hb_face_t     *face,
+hb_ot_name_get_utf32 (hb_face_t     *face,
 		      hb_name_id_t   name_id,
 		      hb_language_t  language,
 		      unsigned int  *text_size /* IN/OUT */,
 		      uint32_t      *text      /* OUT */);
-#endif
 
 
 typedef struct hb_ot_name_entry_t
diff --git a/src/hb-utf.hh b/src/hb-utf.hh
index d8b7114a..5e2faebb 100644
--- a/src/hb-utf.hh
+++ b/src/hb-utf.hh
@@ -127,6 +127,55 @@ struct hb_utf8_t
   {
     return ::strlen ((const char *) text);
   }
+
+  static inline unsigned int
+  encode_len (hb_codepoint_t unicode)
+  {
+    if (unicode <   0x0080u) return 1;
+    if (unicode <   0x0800u) return 2;
+    if (unicode <  0x10000u) return 3;
+    if (unicode < 0x110000u) return 4;
+    return 3;
+  }
+
+  static inline codepoint_t *
+  encode (codepoint_t *text,
+	  const codepoint_t *end,
+	  hb_codepoint_t unicode)
+  {
+    if (unlikely (unicode >= 0xD800u && (unicode <= 0xDFFFu || unicode > 0x10FFFFu)))
+      unicode = 0xFFFDu;
+    if (unicode < 0x0080u)
+     *text++ = unicode;
+    else if (unicode < 0x0800u)
+    {
+      if (end - text >= 2)
+      {
+	*text++ =  0xC0u + (0x1Fu & (unicode >>  6));
+	*text++ =  0x80u + (0x3Fu & (unicode      ));
+      }
+    }
+    else if (unicode < 0x10000u)
+    {
+      if (end - text >= 3)
+      {
+	*text++ =  0xE0u + (0x0Fu & (unicode >> 12));
+	*text++ =  0x80u + (0x3Fu & (unicode >>  6));
+	*text++ =  0x80u + (0x3Fu & (unicode      ));
+      }
+    }
+    else
+    {
+      if (end - text >= 4)
+      {
+	*text++ =  0xF0u + (0x07u & (unicode >> 18));
+	*text++ =  0x80u + (0x3Fu & (unicode >> 12));
+	*text++ =  0x80u + (0x3Fu & (unicode >>  6));
+	*text++ =  0x80u + (0x3Fu & (unicode      ));
+      }
+    }
+    return text;
+  }
 };
 
 
@@ -208,6 +257,30 @@ struct hb_utf16_xe_t
     while (*text++) l++;
     return l;
   }
+
+  static inline unsigned int
+  encode_len (hb_codepoint_t unicode)
+  {
+    return unicode < 0x10000 ? 1 : 2;
+  }
+
+  static inline codepoint_t *
+  encode (codepoint_t *text,
+	  const codepoint_t *end,
+	  hb_codepoint_t unicode)
+  {
+    if (unlikely (unicode >= 0xD800u && (unicode <= 0xDFFFu || unicode > 0x10FFFFu)))
+      unicode = 0xFFFDu;
+    if (unicode < 0x10000u)
+     *text++ = unicode;
+    else if (end - text >= 2)
+    {
+      unicode -= 0x10000u;
+      *text++ =  0xD800u + (unicode >> 10);
+      *text++ =  0xDC00u + (unicode & 0x03FFu);
+    }
+    return text;
+  }
 };
 
 typedef hb_utf16_xe_t<uint16_t> hb_utf16_t;
@@ -251,6 +324,23 @@ struct hb_utf32_xe_t
     while (*text++) l++;
     return l;
   }
+
+  static inline unsigned int
+  encode_len (hb_codepoint_t unicode HB_UNUSED)
+  {
+    return 1;
+  }
+
+  static inline codepoint_t *
+  encode (codepoint_t *text,
+	  const codepoint_t *end HB_UNUSED,
+	  hb_codepoint_t unicode)
+  {
+    if (validate && unlikely (unicode >= 0xD800u && (unicode <= 0xDFFFu || unicode > 0x10FFFFu)))
+      unicode = 0xFFFDu;
+    *text++ = unicode;
+    return text;
+  }
 };
 
 typedef hb_utf32_xe_t<uint32_t> hb_utf32_t;
@@ -289,6 +379,23 @@ struct hb_latin1_t
     while (*text++) l++;
     return l;
   }
+
+  static inline unsigned int
+  encode_len (hb_codepoint_t unicode HB_UNUSED)
+  {
+    return 1;
+  }
+
+  static inline codepoint_t *
+  encode (codepoint_t *text,
+	  const codepoint_t *end HB_UNUSED,
+	  hb_codepoint_t unicode)
+  {
+    if (unlikely (unicode >= 0x0100u))
+      unicode = '?';
+    *text++ = unicode;
+    return text;
+  }
 };
 
 #endif /* HB_UTF_HH */
commit 84811a06a26508effe9f4a9eaf1be15297ecf0cb
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Tue Oct 23 03:16:03 2018 -0700

    [name] Fix for rebase changes to hb_array_t

diff --git a/src/hb-ot-name-table.hh b/src/hb-ot-name-table.hh
index f0b5a5e6..8967fcbd 100644
--- a/src/hb-ot-name-table.hh
+++ b/src/hb-ot-name-table.hh
@@ -137,7 +137,7 @@ struct name
 
   inline hb_bytes_t get_name (unsigned int idx) const
   {
-    const hb_array_t<NameRecord> &all_names = hb_array_t<NameRecord> (nameRecordZ.arrayZ, count);
+    const hb_array_t<const NameRecord> all_names (nameRecordZ.arrayZ, count);
     const NameRecord &record = all_names[idx];
     return hb_bytes_t ((char *) this + stringOffset + record.offset, record.length);
   }
@@ -170,8 +170,8 @@ struct name
     {
       this->blob = hb_sanitize_context_t().reference_table<name> (face);
       this->table = this->blob->as<name> ();
-      const hb_array_t<NameRecord> &all_names = hb_array_t<NameRecord> (this->table->nameRecordZ.arrayZ,
-									this->table->count);
+      const hb_array_t<const NameRecord> all_names (this->table->nameRecordZ.arrayZ,
+						    this->table->count);
 
       this->names.init ();
       this->names.alloc (all_names.len);
commit 1046b1938b16ab6be861b0828b446fa13cf0377b
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Wed Oct 17 05:42:23 2018 -0700

    [name] Some more

diff --git a/src/hb-ot-name.cc b/src/hb-ot-name.cc
index 3494cb7f..3cb4a923 100644
--- a/src/hb-ot-name.cc
+++ b/src/hb-ot-name.cc
@@ -60,17 +60,24 @@ hb_ot_name_get_utf (hb_face_t     *face,
 		    typename utf_t::codepoint_t *text /* OUT */)
 {
   const OT::name_accelerator_t &name = _get_name (face);
-  unsigned int idx = 0; //XXX
+  unsigned int idx = 0; // XXX bsearch and find
   hb_bytes_t bytes = name.table->get_name (idx);
+
+  unsigned int full_length = 0;
+  const typename utf_t::codepoint_t *src = (const typename utf_t::codepoint_t *) bytes.arrayZ;
+  unsigned int src_len = bytes.len / sizeof (typename utf_t::codepoint_t);
+
   if (text_size && *text_size)
   {
+    *text_size--; /* Leave room for nul-termination. */
     /* TODO Switch to walking string and validating. */
-    memcpy (text, bytes.arrayZ, MIN (*text_size * 2, bytes.len));
+    memcpy (text,
+	    src,
+	    MIN (*text_size, src_len) * sizeof (typename utf_t::codepoint_t));
   }
-  /* XXX Null-terminate. */
-  if (text_size)
-    *text_size = bytes.len / 2; //TODO
-  /* TODO Fallback? */
+
+  /* Walk the rest, accumulate the full length. */
+
   return *text_size; //XXX
 }
 
commit b4d4d1ea787c829dea023d99f974a38bdc3de0ae
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Tue Oct 16 19:55:17 2018 -0700

    [name] Return full string length from API

diff --git a/src/hb-ot-name.cc b/src/hb-ot-name.cc
index e6dbe0a4..3494cb7f 100644
--- a/src/hb-ot-name.cc
+++ b/src/hb-ot-name.cc
@@ -52,7 +52,7 @@ hb_ot_name_get_names (hb_face_t                 *face,
 
 
 template <typename utf_t>
-static inline hb_bool_t
+static inline unsigned int
 hb_ot_name_get_utf (hb_face_t     *face,
 		    hb_name_id_t   name_id,
 		    hb_language_t  language,
@@ -71,10 +71,10 @@ hb_ot_name_get_utf (hb_face_t     *face,
   if (text_size)
     *text_size = bytes.len / 2; //TODO
   /* TODO Fallback? */
-  return true; //XXX
+  return *text_size; //XXX
 }
 
-hb_bool_t
+unsigned int
 hb_ot_name_get_utf16 (hb_face_t     *face,
 		      hb_name_id_t   name_id,
 		      hb_language_t  language,
diff --git a/src/hb-ot-name.h b/src/hb-ot-name.h
index fb494802..0afcd3fc 100644
--- a/src/hb-ot-name.h
+++ b/src/hb-ot-name.h
@@ -50,7 +50,7 @@ typedef unsigned int hb_name_id_t;
 
 
 #if 0
-HB_EXTERN hb_bool_t
+HB_EXTERN unsigned int
 Xhb_ot_name_get_utf8 (hb_face_t     *face,
 		     hb_name_id_t   name_id,
 		     hb_language_t  language,
@@ -58,7 +58,7 @@ Xhb_ot_name_get_utf8 (hb_face_t     *face,
 		     char          *text      /* OUT */);
 #endif
 
-HB_EXTERN hb_bool_t
+HB_EXTERN unsigned int
 hb_ot_name_get_utf16 (hb_face_t     *face,
 		      hb_name_id_t   name_id,
 		      hb_language_t  language,
@@ -66,7 +66,7 @@ hb_ot_name_get_utf16 (hb_face_t     *face,
 		      uint16_t      *text      /* OUT */);
 
 #if 0
-HB_EXTERN hb_bool_t
+HB_EXTERN unsigned int
 Xhb_ot_name_get_utf32 (hb_face_t     *face,
 		      hb_name_id_t   name_id,
 		      hb_language_t  language,
commit 8d304ef7f9094a71fabc3efd87b37a030c437adf
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Tue Oct 16 19:04:48 2018 -0700

    [utf] Add UTF16-BE and UTF32-BE

diff --git a/src/hb-buffer.cc b/src/hb-buffer.cc
index ce9b0530..f905c63a 100644
--- a/src/hb-buffer.cc
+++ b/src/hb-buffer.cc
@@ -1665,7 +1665,7 @@ hb_buffer_add_utf32 (hb_buffer_t    *buffer,
 		     unsigned int    item_offset,
 		     int             item_length)
 {
-  hb_buffer_add_utf<hb_utf32_t<> > (buffer, text, text_length, item_offset, item_length);
+  hb_buffer_add_utf<hb_utf32_t> (buffer, text, text_length, item_offset, item_length);
 }
 
 /**
@@ -1726,7 +1726,7 @@ hb_buffer_add_codepoints (hb_buffer_t          *buffer,
 			  unsigned int          item_offset,
 			  int                   item_length)
 {
-  hb_buffer_add_utf<hb_utf32_t<false> > (buffer, text, text_length, item_offset, item_length);
+  hb_buffer_add_utf<hb_utf32_novalidate_t> (buffer, text, text_length, item_offset, item_length);
 }
 
 
diff --git a/src/hb-utf.hh b/src/hb-utf.hh
index eccb632e..d8b7114a 100644
--- a/src/hb-utf.hh
+++ b/src/hb-utf.hh
@@ -29,14 +29,16 @@
 
 #include "hb.hh"
 
+#include "hb-open-type.hh"
+
 
 struct hb_utf8_t
 {
   typedef uint8_t codepoint_t;
 
-  static inline const uint8_t *
-  next (const uint8_t *text,
-	const uint8_t *end,
+  static inline const codepoint_t *
+  next (const codepoint_t *text,
+	const codepoint_t *end,
 	hb_codepoint_t *unicode,
 	hb_codepoint_t replacement)
   {
@@ -103,13 +105,13 @@ struct hb_utf8_t
     return text;
   }
 
-  static inline const uint8_t *
-  prev (const uint8_t *text,
-	const uint8_t *start,
+  static inline const codepoint_t *
+  prev (const codepoint_t *text,
+	const codepoint_t *start,
 	hb_codepoint_t *unicode,
 	hb_codepoint_t replacement)
   {
-    const uint8_t *end = text--;
+    const codepoint_t *end = text--;
     while (start < text && (*text & 0xc0) == 0x80 && end - text < 4)
       text--;
 
@@ -121,20 +123,22 @@ struct hb_utf8_t
   }
 
   static inline unsigned int
-  strlen (const uint8_t *text)
+  strlen (const codepoint_t *text)
   {
     return ::strlen ((const char *) text);
   }
 };
 
 
-struct hb_utf16_t
+template <typename TCodepoint>
+struct hb_utf16_xe_t
 {
-  typedef uint16_t codepoint_t;
+  static_assert (sizeof (TCodepoint) == 2, "");
+  typedef TCodepoint codepoint_t;
 
-  static inline const uint16_t *
-  next (const uint16_t *text,
-	const uint16_t *end,
+  static inline const codepoint_t *
+  next (const codepoint_t *text,
+	const codepoint_t *end,
 	hb_codepoint_t *unicode,
 	hb_codepoint_t replacement)
   {
@@ -164,9 +168,9 @@ struct hb_utf16_t
     return text;
   }
 
-  static inline const uint16_t *
-  prev (const uint16_t *text,
-	const uint16_t *start,
+  static inline const codepoint_t *
+  prev (const codepoint_t *text,
+	const codepoint_t *start,
 	hb_codepoint_t *unicode,
 	hb_codepoint_t replacement)
   {
@@ -198,7 +202,7 @@ struct hb_utf16_t
 
 
   static inline unsigned int
-  strlen (const uint16_t *text)
+  strlen (const codepoint_t *text)
   {
     unsigned int l = 0;
     while (*text++) l++;
@@ -206,15 +210,19 @@ struct hb_utf16_t
   }
 };
 
+typedef hb_utf16_xe_t<uint16_t> hb_utf16_t;
+typedef hb_utf16_xe_t<OT::HBUINT16> hb_utf16_be_t;
+
 
-template <bool validate=true>
-struct hb_utf32_t
+template <typename TCodepoint, bool validate=true>
+struct hb_utf32_xe_t
 {
-  typedef uint32_t codepoint_t;
+  static_assert (sizeof (TCodepoint) == 4, "");
+  typedef TCodepoint codepoint_t;
 
-  static inline const uint32_t *
-  next (const uint32_t *text,
-	const uint32_t *end HB_UNUSED,
+  static inline const TCodepoint *
+  next (const TCodepoint *text,
+	const TCodepoint *end HB_UNUSED,
 	hb_codepoint_t *unicode,
 	hb_codepoint_t replacement)
   {
@@ -224,9 +232,9 @@ struct hb_utf32_t
     return text;
   }
 
-  static inline const uint32_t *
-  prev (const uint32_t *text,
-	const uint32_t *start HB_UNUSED,
+  static inline const TCodepoint *
+  prev (const TCodepoint *text,
+	const TCodepoint *start HB_UNUSED,
 	hb_codepoint_t *unicode,
 	hb_codepoint_t replacement)
   {
@@ -237,7 +245,7 @@ struct hb_utf32_t
   }
 
   static inline unsigned int
-  strlen (const uint32_t *text)
+  strlen (const TCodepoint *text)
   {
     unsigned int l = 0;
     while (*text++) l++;
@@ -245,14 +253,18 @@ struct hb_utf32_t
   }
 };
 
+typedef hb_utf32_xe_t<uint32_t> hb_utf32_t;
+typedef hb_utf32_xe_t<uint32_t, false> hb_utf32_novalidate_t;
+typedef hb_utf32_xe_t<OT::HBUINT32> hb_utf32_be_t;
+
 
 struct hb_latin1_t
 {
   typedef uint8_t codepoint_t;
 
-  static inline const uint8_t *
-  next (const uint8_t *text,
-	const uint8_t *end HB_UNUSED,
+  static inline const codepoint_t *
+  next (const codepoint_t *text,
+	const codepoint_t *end HB_UNUSED,
 	hb_codepoint_t *unicode,
 	hb_codepoint_t replacement HB_UNUSED)
   {
@@ -260,9 +272,9 @@ struct hb_latin1_t
     return text;
   }
 
-  static inline const uint8_t *
-  prev (const uint8_t *text,
-	const uint8_t *start HB_UNUSED,
+  static inline const codepoint_t *
+  prev (const codepoint_t *text,
+	const codepoint_t *start HB_UNUSED,
 	hb_codepoint_t *unicode,
 	hb_codepoint_t replacement)
   {
@@ -271,7 +283,7 @@ struct hb_latin1_t
   }
 
   static inline unsigned int
-  strlen (const uint8_t *text)
+  strlen (const codepoint_t *text)
   {
     unsigned int l = 0;
     while (*text++) l++;
commit a826a8730f21ae996ae8f4d12c44dc18b9e8e933
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Tue Oct 16 13:06:56 2018 -0700

    [name] Hide internal details from public API

diff --git a/src/hb-ot-name-table.hh b/src/hb-ot-name-table.hh
index 14ac4ef2..f0b5a5e6 100644
--- a/src/hb-ot-name-table.hh
+++ b/src/hb-ot-name-table.hh
@@ -33,6 +33,10 @@
 namespace OT {
 
 
+#define entry_score var.u16[0]
+#define entry_index var.u16[1]
+
+
 /*
  * name -- Naming
  * https://docs.microsoft.com/en-us/typography/opentype/spec/name
@@ -118,11 +122,11 @@ _hb_ot_name_entry_cmp (const void *pa, const void *pb)
   if (e)
     return e;
 
-  if (a->score != b->score)
-    return a->score < b->score ? -1 : +1;
+  if (a->entry_score != b->entry_score)
+    return a->entry_score < b->entry_score ? -1 : +1;
 
-  if (a->index != b->index)
-    return a->index < b->index ? -1 : +1;
+  if (a->entry_index != b->entry_index)
+    return a->entry_index < b->entry_index ? -1 : +1;
 
   return 0;
 }
@@ -174,13 +178,12 @@ struct name
 
       for (uint16_t i = 0; i < all_names.len; i++)
       {
-	unsigned int name_id = all_names[i].nameID;
-	uint16_t score = all_names[i].score ();
-	hb_language_t language = HB_LANGUAGE_INVALID; /* XXX */
-
-	hb_ot_name_entry_t entry = {name_id, score, i, language};
+	hb_ot_name_entry_t *entry = this->names.push ();
 
-	this->names.push (entry);
+	entry->name_id = all_names[i].nameID;
+	entry->language = HB_LANGUAGE_INVALID; /* XXX */
+	entry->entry_score =  all_names[i].score ();
+	entry->entry_index = i;
       }
 
       this->names.qsort (_hb_ot_name_entry_cmp);
diff --git a/src/hb-ot-name.h b/src/hb-ot-name.h
index 013ce8dd..fb494802 100644
--- a/src/hb-ot-name.h
+++ b/src/hb-ot-name.h
@@ -79,8 +79,7 @@ typedef struct hb_ot_name_entry_t
 {
   hb_name_id_t  name_id;
   /*< private >*/
-  uint16_t      score;
-  uint16_t      index;
+  hb_var_int_t  var;
   /*< public >*/
   hb_language_t language;
 } hb_ot_name_entry_t;
commit e7c595a9f09ba1552b2de1f8d56cbdcf376b9cad
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Mon Oct 15 23:34:54 2018 -0700

    [name] More

diff --git a/src/hb-ot-name.cc b/src/hb-ot-name.cc
index 22149e44..e6dbe0a4 100644
--- a/src/hb-ot-name.cc
+++ b/src/hb-ot-name.cc
@@ -62,13 +62,14 @@ hb_ot_name_get_utf (hb_face_t     *face,
   const OT::name_accelerator_t &name = _get_name (face);
   unsigned int idx = 0; //XXX
   hb_bytes_t bytes = name.table->get_name (idx);
-  if (*text_size)
+  if (text_size && *text_size)
   {
     /* TODO Switch to walking string and validating. */
     memcpy (text, bytes.arrayZ, MIN (*text_size * 2, bytes.len));
   }
   /* XXX Null-terminate. */
-  *text_size = bytes.len / 2; //TODO
+  if (text_size)
+    *text_size = bytes.len / 2; //TODO
   /* TODO Fallback? */
   return true; //XXX
 }
commit 75cd8c86bd9b0973864bb92e0244bf038980765e
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Mon Oct 15 23:32:08 2018 -0700

    [name] Add hb_ot_name_get_utf()

diff --git a/src/hb-ot-name.cc b/src/hb-ot-name.cc
index b5143d3d..22149e44 100644
--- a/src/hb-ot-name.cc
+++ b/src/hb-ot-name.cc
@@ -29,6 +29,7 @@
 #include "hb-ot-name-table.hh"
 
 #include "hb-ot-face.hh"
+#include "hb-utf.hh"
 
 
 static inline const OT::name_accelerator_t&
@@ -50,12 +51,13 @@ hb_ot_name_get_names (hb_face_t                 *face,
 }
 
 
-hb_bool_t
-hb_ot_name_get_utf16 (hb_face_t     *face,
-		      hb_name_id_t   name_id,
-		      hb_language_t  language,
-		      unsigned int  *text_size /* IN/OUT */,
-		      uint16_t      *text      /* OUT */)
+template <typename utf_t>
+static inline hb_bool_t
+hb_ot_name_get_utf (hb_face_t     *face,
+		    hb_name_id_t   name_id,
+		    hb_language_t  language,
+		    unsigned int  *text_size /* IN/OUT */,
+		    typename utf_t::codepoint_t *text /* OUT */)
 {
   const OT::name_accelerator_t &name = _get_name (face);
   unsigned int idx = 0; //XXX
@@ -70,3 +72,13 @@ hb_ot_name_get_utf16 (hb_face_t     *face,
   /* TODO Fallback? */
   return true; //XXX
 }
+
+hb_bool_t
+hb_ot_name_get_utf16 (hb_face_t     *face,
+		      hb_name_id_t   name_id,
+		      hb_language_t  language,
+		      unsigned int  *text_size /* IN/OUT */,
+		      uint16_t      *text      /* OUT */)
+{
+  return hb_ot_name_get_utf<hb_utf16_t> (face, name_id, language, text_size, text);
+}
commit c783d36324dd1e2031d3387064afab1ce5d90b6f
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Mon Oct 15 23:28:49 2018 -0700

    [name] Pre-allocate array

diff --git a/src/hb-ot-name-table.hh b/src/hb-ot-name-table.hh
index 3d7b7311..14ac4ef2 100644
--- a/src/hb-ot-name-table.hh
+++ b/src/hb-ot-name-table.hh
@@ -170,6 +170,7 @@ struct name
 									this->table->count);
 
       this->names.init ();
+      this->names.alloc (all_names.len);
 
       for (uint16_t i = 0; i < all_names.len; i++)
       {
commit c2aa409537c3e8a7b8592ef90f8304bd6588561d
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Mon Oct 15 23:09:28 2018 -0700

    [name] Start implementing hb_ot_name_get_utf16()

diff --git a/src/hb-ot-name-table.hh b/src/hb-ot-name-table.hh
index 37a2d42f..3d7b7311 100644
--- a/src/hb-ot-name-table.hh
+++ b/src/hb-ot-name-table.hh
@@ -165,8 +165,9 @@ struct name
     inline void init (hb_face_t *face)
     {
       this->blob = hb_sanitize_context_t().reference_table<name> (face);
-      const name *table = this->blob->as<name> ();
-      const hb_array_t<NameRecord> &all_names = hb_array_t<NameRecord> (table->nameRecordZ.arrayZ, table->count);
+      this->table = this->blob->as<name> ();
+      const hb_array_t<NameRecord> &all_names = hb_array_t<NameRecord> (this->table->nameRecordZ.arrayZ,
+									this->table->count);
 
       this->names.init ();
 
@@ -204,6 +205,7 @@ struct name
     private:
     hb_blob_t *blob;
     public:
+    const name *table;
     hb_vector_t<hb_ot_name_entry_t> names;
   };
 
diff --git a/src/hb-ot-name.cc b/src/hb-ot-name.cc
index 85995f8c..b5143d3d 100644
--- a/src/hb-ot-name.cc
+++ b/src/hb-ot-name.cc
@@ -48,3 +48,25 @@ hb_ot_name_get_names (hb_face_t                 *face,
     *entries = name.names.arrayZ();
   return name.names.len;
 }
+
+
+hb_bool_t
+hb_ot_name_get_utf16 (hb_face_t     *face,
+		      hb_name_id_t   name_id,
+		      hb_language_t  language,
+		      unsigned int  *text_size /* IN/OUT */,
+		      uint16_t      *text      /* OUT */)
+{
+  const OT::name_accelerator_t &name = _get_name (face);
+  unsigned int idx = 0; //XXX
+  hb_bytes_t bytes = name.table->get_name (idx);
+  if (*text_size)
+  {
+    /* TODO Switch to walking string and validating. */
+    memcpy (text, bytes.arrayZ, MIN (*text_size * 2, bytes.len));
+  }
+  /* XXX Null-terminate. */
+  *text_size = bytes.len / 2; //TODO
+  /* TODO Fallback? */
+  return true; //XXX
+}
diff --git a/src/hb-ot-name.h b/src/hb-ot-name.h
index 4c0db0fc..013ce8dd 100644
--- a/src/hb-ot-name.h
+++ b/src/hb-ot-name.h
@@ -49,12 +49,14 @@ typedef unsigned int hb_name_id_t;
 #define HB_NAME_ID_INVALID 0xFFFF
 
 
+#if 0
 HB_EXTERN hb_bool_t
-hb_ot_name_get_utf8 (hb_face_t     *face,
+Xhb_ot_name_get_utf8 (hb_face_t     *face,
 		     hb_name_id_t   name_id,
 		     hb_language_t  language,
 		     unsigned int  *text_size /* IN/OUT */,
 		     char          *text      /* OUT */);
+#endif
 
 HB_EXTERN hb_bool_t
 hb_ot_name_get_utf16 (hb_face_t     *face,
@@ -63,12 +65,14 @@ hb_ot_name_get_utf16 (hb_face_t     *face,
 		      unsigned int  *text_size /* IN/OUT */,
 		      uint16_t      *text      /* OUT */);
 
+#if 0
 HB_EXTERN hb_bool_t
-hb_ot_name_get_utf32 (hb_face_t     *face,
+Xhb_ot_name_get_utf32 (hb_face_t     *face,
 		      hb_name_id_t   name_id,
 		      hb_language_t  language,
 		      unsigned int  *text_size /* IN/OUT */,
 		      uint32_t      *text      /* OUT */);
+#endif
 
 
 typedef struct hb_ot_name_entry_t
commit 740cde8991283b8b4e1e77e022175251eb37d3d1
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Mon Oct 15 23:00:27 2018 -0700

    [name] Implement hb_bytes_t get_name()

diff --git a/src/hb-ot-name-table.hh b/src/hb-ot-name-table.hh
index 5625ab2c..37a2d42f 100644
--- a/src/hb-ot-name-table.hh
+++ b/src/hb-ot-name-table.hh
@@ -131,26 +131,11 @@ struct name
 {
   static const hb_tag_t tableTag	= HB_OT_TAG_name;
 
-  inline unsigned int get_name (unsigned int platform_id,
-				unsigned int encoding_id,
-				unsigned int language_id,
-				unsigned int name_id,
-				void *buffer,
-				unsigned int buffer_length) const
+  inline hb_bytes_t get_name (unsigned int idx) const
   {
-    NameRecord key;
-    key.platformID.set (platform_id);
-    key.encodingID.set (encoding_id);
-    key.languageID.set (language_id);
-    key.nameID.set (name_id);
-    NameRecord *match = (NameRecord *) bsearch (&key, nameRecordZ.arrayZ, count, sizeof (nameRecordZ[0]), NameRecord::cmp);
-
-    if (!match)
-      return 0;
-
-    unsigned int length = MIN (buffer_length, (unsigned int) match->length);
-    memcpy (buffer, (char *) this + stringOffset + match->offset, length);
-    return length;
+    const hb_array_t<NameRecord> &all_names = hb_array_t<NameRecord> (nameRecordZ.arrayZ, count);
+    const NameRecord &record = all_names[idx];
+    return hb_bytes_t ((char *) this + stringOffset + record.offset, record.length);
   }
 
   inline unsigned int get_size (void) const
@@ -160,6 +145,7 @@ struct name
     TRACE_SANITIZE (this);
     char *string_pool = (char *) this + stringOffset;
     unsigned int _count = count;
+    /* Move to run-time?! */
     for (unsigned int i = 0; i < _count; i++)
       if (!nameRecordZ[i].sanitize (c, string_pool)) return_trace (false);
     return_trace (true);
commit c3425f2401dffb1f3b5bd6fdbc0c3e9aad0f4306
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Mon Oct 15 22:53:40 2018 -0700

    [name] Add hb-ot-name.cc for realz

diff --git a/src/hb-ot-name.cc b/src/hb-ot-name.cc
new file mode 100644
index 00000000..85995f8c
--- /dev/null
+++ b/src/hb-ot-name.cc
@@ -0,0 +1,50 @@
+/*
+ * Copyright © 2018  Google, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#include "hb.hh"
+
+#include "hb-ot-name-table.hh"
+
+#include "hb-ot-face.hh"
+
+
+static inline const OT::name_accelerator_t&
+_get_name (hb_face_t *face)
+{
+  if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return Null(OT::name_accelerator_t);
+  return *(hb_ot_face_data (face)->name.get ());
+}
+
+
+unsigned int
+hb_ot_name_get_names (hb_face_t                 *face,
+		      const hb_ot_name_entry_t **entries /* OUT */)
+{
+  const OT::name_accelerator_t &name = _get_name (face);
+  if (entries)
+    *entries = name.names.arrayZ();
+  return name.names.len;
+}
commit 90420ed8cb297f1ceff75f5a75c8fa7b6ea6f65e
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Mon Oct 15 22:48:48 2018 -0700

    [name] Implement hb_ot_name_get_names()

diff --git a/src/Makefile.sources b/src/Makefile.sources
index e13bd4f0..0ee79a47 100644
--- a/src/Makefile.sources
+++ b/src/Makefile.sources
@@ -34,6 +34,7 @@ HB_BASE_sources = \
 	hb-ot-kern-table.hh \
 	hb-ot-maxp-table.hh \
 	hb-ot-name-table.hh \
+	hb-ot-name.cc \
 	hb-ot-os2-table.hh \
 	hb-ot-os2-unicode-ranges.hh \
 	hb-ot-post-macroman.hh \
diff --git a/src/hb-ot-name-table.hh b/src/hb-ot-name-table.hh
index a6a1e5f3..5625ab2c 100644
--- a/src/hb-ot-name-table.hh
+++ b/src/hb-ot-name-table.hh
@@ -217,9 +217,8 @@ struct name
 
     private:
     hb_blob_t *blob;
+    public:
     hb_vector_t<hb_ot_name_entry_t> names;
-
-    unsigned int names_count;
   };
 
   /* We only implement format 0 for now. */
diff --git a/src/hb-ot-name.h b/src/hb-ot-name.h
index 257b346d..4c0db0fc 100644
--- a/src/hb-ot-name.h
+++ b/src/hb-ot-name.h
@@ -82,8 +82,8 @@ typedef struct hb_ot_name_entry_t
 } hb_ot_name_entry_t;
 
 HB_EXTERN unsigned int
-hb_ot_name_get_names (hb_face_t           *face,
-		      hb_ot_name_entry_t **entries /* OUT */);
+hb_ot_name_get_names (hb_face_t                 *face,
+		      const hb_ot_name_entry_t **entries /* OUT */);
 
 
 HB_END_DECLS
commit 9a6c87c17d51fd57e4225c776a0fabbfd313f4f4
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Mon Oct 15 22:42:04 2018 -0700

    [name] Finish accelerator sorting

diff --git a/src/hb-ot-name-table.hh b/src/hb-ot-name-table.hh
index 45726ab5..a6a1e5f3 100644
--- a/src/hb-ot-name-table.hh
+++ b/src/hb-ot-name-table.hh
@@ -39,6 +39,7 @@ namespace OT {
  */
 #define HB_OT_TAG_name HB_TAG('n','a','m','e')
 
+#define UNSUPPORTED	42
 
 struct NameRecord
 {
@@ -58,11 +59,30 @@ struct NameRecord
     return 0;
   }
 
-  inline bool supported (void) const
+  inline uint16_t score (void) const
   {
-    return platformID == 0 ||
-           platformID == 3;
-    /* TODO Add Apple MacRoman (0:1). */
+    /* Same order as in cmap::find_best_subtable(). */
+    unsigned int p = platformID;
+    unsigned int e = encodingID;
+
+    /* 32-bit. */
+    if (p == 3 && e == 10) return 0;
+    if (p == 0 && e ==  6) return 1;
+    if (p == 0 && e ==  4) return 2;
+
+    /* 16-bit. */
+    if (p == 3 && e ==  1) return 3;
+    if (p == 0 && e ==  3) return 4;
+    if (p == 0 && e ==  2) return 5;
+    if (p == 0 && e ==  1) return 6;
+    if (p == 0 && e ==  0) return 7;
+
+    /* Symbol. */
+    if (p == 3 && e ==  0) return 8;
+
+    /* TODO Apple MacRoman (0:1). */
+
+    return UNSUPPORTED;
   }
 
   inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
@@ -87,10 +107,23 @@ _hb_ot_name_entry_cmp (const void *pa, const void *pb)
 {
   const hb_ot_name_entry_t *a = (const hb_ot_name_entry_t *) pa;
   const hb_ot_name_entry_t *b = (const hb_ot_name_entry_t *) pb;
+
+  /* Sort by name_id, then language, then score, then index. */
+
   if (a->name_id != b->name_id)
     return a->name_id < b->name_id ? -1 : +1;
+
+  int e = strcmp (hb_language_to_string (a->language),
+		  hb_language_to_string (b->language));
+  if (e)
+    return e;
+
+  if (a->score != b->score)
+    return a->score < b->score ? -1 : +1;
+
   if (a->index != b->index)
     return a->index < b->index ? -1 : +1;
+
   return 0;
 }
 
@@ -151,23 +184,31 @@ struct name
 
       this->names.init ();
 
-      for (unsigned int i = 0; i < all_names.len; i++)
+      for (uint16_t i = 0; i < all_names.len; i++)
       {
-	if (!all_names[i].supported ()) continue;
-
 	unsigned int name_id = all_names[i].nameID;
+	uint16_t score = all_names[i].score ();
 	hb_language_t language = HB_LANGUAGE_INVALID; /* XXX */
 
-	hb_ot_name_entry_t entry = {name_id, i, language};
+	hb_ot_name_entry_t entry = {name_id, score, i, language};
 
 	this->names.push (entry);
       }
 
       this->names.qsort (_hb_ot_name_entry_cmp);
-
-      /* Walk and pick best... */
+      /* Walk and pick best only for each name_id,language pair... */
+      unsigned int j = 0;
+      for (unsigned int i = 1; i < this->names.len; i++)
+      {
+        if (this->names[i - 1].name_id  == this->names[i].name_id &&
+	    this->names[i - 1].language == this->names[i].language)
+	  continue;
+	this->names[j++] = this->names[i];
+      }
+      this->names.resize (j);
     }
 
+
     inline void fini (void)
     {
       this->names.fini ();
diff --git a/src/hb-ot-name.h b/src/hb-ot-name.h
index 8b2c02b6..257b346d 100644
--- a/src/hb-ot-name.h
+++ b/src/hb-ot-name.h
@@ -75,7 +75,8 @@ typedef struct hb_ot_name_entry_t
 {
   hb_name_id_t  name_id;
   /*< private >*/
-  unsigned int  index;
+  uint16_t      score;
+  uint16_t      index;
   /*< public >*/
   hb_language_t language;
 } hb_ot_name_entry_t;
commit 2157e56b34e7b932dd144ee3563f5bd682bbed30
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Mon Oct 15 22:22:50 2018 -0700

    [name] Start implementing public API infrastructure

diff --git a/src/hb-ot-face.cc b/src/hb-ot-face.cc
index 1bc68d36..dd17faf6 100644
--- a/src/hb-ot-face.cc
+++ b/src/hb-ot-face.cc
@@ -30,6 +30,7 @@
 #include "hb-ot-glyf-table.hh"
 #include "hb-ot-hmtx-table.hh"
 #include "hb-ot-kern-table.hh"
+#include "hb-ot-name-table.hh"
 #include "hb-ot-post-table.hh"
 #include "hb-ot-color-cbdt-table.hh"
 #include "hb-ot-layout-gdef-table.hh"
diff --git a/src/hb-ot-face.hh b/src/hb-ot-face.hh
index a45a4936..c810e9fb 100644
--- a/src/hb-ot-face.hh
+++ b/src/hb-ot-face.hh
@@ -45,6 +45,9 @@
  * This is as good as any place. */
 #define HB_OT_TABLES \
     /* OpenType shaping. */ \
+    HB_OT_ACCELERATOR(OT, GDEF) \
+    HB_OT_ACCELERATOR(OT, GSUB) \
+    HB_OT_ACCELERATOR(OT, GPOS) \
     HB_OT_TABLE(OT, JSTF) \
     HB_OT_TABLE(OT, BASE) \
     /* AAT shaping. */ \
@@ -59,13 +62,11 @@
     /* OpenType math. */ \
     HB_OT_TABLE(OT, MATH) \
     /* OpenType fundamentals. */ \
-    HB_OT_ACCELERATOR(OT, GDEF) \
-    HB_OT_ACCELERATOR(OT, GSUB) \
-    HB_OT_ACCELERATOR(OT, GPOS) \
     HB_OT_ACCELERATOR(OT, cmap) \
     HB_OT_ACCELERATOR(OT, hmtx) \
     HB_OT_ACCELERATOR(OT, vmtx) \
     HB_OT_ACCELERATOR(OT, post) \
+    HB_OT_ACCELERATOR(OT, name) \
     HB_OT_ACCELERATOR(OT, kern) \
     HB_OT_ACCELERATOR(OT, glyf) \
     HB_OT_TABLE(OT, VORG) \
diff --git a/src/hb-ot-name-table.hh b/src/hb-ot-name-table.hh
index bb49c2cb..45726ab5 100644
--- a/src/hb-ot-name-table.hh
+++ b/src/hb-ot-name-table.hh
@@ -58,6 +58,13 @@ struct NameRecord
     return 0;
   }
 
+  inline bool supported (void) const
+  {
+    return platformID == 0 ||
+           platformID == 3;
+    /* TODO Add Apple MacRoman (0:1). */
+  }
+
   inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
   {
     TRACE_SANITIZE (this);
@@ -75,6 +82,18 @@ struct NameRecord
   DEFINE_SIZE_STATIC (12);
 };
 
+static int
+_hb_ot_name_entry_cmp (const void *pa, const void *pb)
+{
+  const hb_ot_name_entry_t *a = (const hb_ot_name_entry_t *) pa;
+  const hb_ot_name_entry_t *b = (const hb_ot_name_entry_t *) pb;
+  if (a->name_id != b->name_id)
+    return a->name_id < b->name_id ? -1 : +1;
+  if (a->index != b->index)
+    return a->index < b->index ? -1 : +1;
+  return 0;
+}
+
 struct name
 {
   static const hb_tag_t tableTag	= HB_OT_TAG_name;
@@ -122,6 +141,46 @@ struct name
 		  sanitize_records (c));
   }
 
+  struct accelerator_t
+  {
+    inline void init (hb_face_t *face)
+    {
+      this->blob = hb_sanitize_context_t().reference_table<name> (face);
+      const name *table = this->blob->as<name> ();
+      const hb_array_t<NameRecord> &all_names = hb_array_t<NameRecord> (table->nameRecordZ.arrayZ, table->count);
+
+      this->names.init ();
+
+      for (unsigned int i = 0; i < all_names.len; i++)
+      {
+	if (!all_names[i].supported ()) continue;
+
+	unsigned int name_id = all_names[i].nameID;
+	hb_language_t language = HB_LANGUAGE_INVALID; /* XXX */
+
+	hb_ot_name_entry_t entry = {name_id, i, language};
+
+	this->names.push (entry);
+      }
+
+      this->names.qsort (_hb_ot_name_entry_cmp);
+
+      /* Walk and pick best... */
+    }
+
+    inline void fini (void)
+    {
+      this->names.fini ();
+      hb_blob_destroy (this->blob);
+    }
+
+    private:
+    hb_blob_t *blob;
+    hb_vector_t<hb_ot_name_entry_t> names;
+
+    unsigned int names_count;
+  };
+
   /* We only implement format 0 for now. */
   HBUINT16	format;			/* Format selector (=0/1). */
   HBUINT16	count;			/* Number of name records. */
@@ -132,6 +191,7 @@ struct name
   DEFINE_SIZE_ARRAY (6, nameRecordZ);
 };
 
+struct name_accelerator_t : name::accelerator_t {};
 
 } /* namespace OT */
 
diff --git a/src/hb-ot-name.h b/src/hb-ot-name.h
index 1f643d53..8b2c02b6 100644
--- a/src/hb-ot-name.h
+++ b/src/hb-ot-name.h
@@ -74,6 +74,9 @@ hb_ot_name_get_utf32 (hb_face_t     *face,
 typedef struct hb_ot_name_entry_t
 {
   hb_name_id_t  name_id;
+  /*< private >*/
+  unsigned int  index;
+  /*< public >*/
   hb_language_t language;
 } hb_ot_name_entry_t;
 
commit 0bf93ec0fb549d838b0a246de02a95559a9b2772
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Mon Oct 15 21:34:10 2018 -0700

    [name] Add public API declarations

diff --git a/src/hb-ot-name.h b/src/hb-ot-name.h
index 49423e87..1f643d53 100644
--- a/src/hb-ot-name.h
+++ b/src/hb-ot-name.h
@@ -48,6 +48,40 @@ typedef unsigned int hb_name_id_t;
  **/
 #define HB_NAME_ID_INVALID 0xFFFF
 
+
+HB_EXTERN hb_bool_t
+hb_ot_name_get_utf8 (hb_face_t     *face,
+		     hb_name_id_t   name_id,
+		     hb_language_t  language,
+		     unsigned int  *text_size /* IN/OUT */,
+		     char          *text      /* OUT */);
+
+HB_EXTERN hb_bool_t
+hb_ot_name_get_utf16 (hb_face_t     *face,
+		      hb_name_id_t   name_id,
+		      hb_language_t  language,
+		      unsigned int  *text_size /* IN/OUT */,
+		      uint16_t      *text      /* OUT */);
+
+HB_EXTERN hb_bool_t
+hb_ot_name_get_utf32 (hb_face_t     *face,
+		      hb_name_id_t   name_id,
+		      hb_language_t  language,
+		      unsigned int  *text_size /* IN/OUT */,
+		      uint32_t      *text      /* OUT */);
+
+
+typedef struct hb_ot_name_entry_t
+{
+  hb_name_id_t  name_id;
+  hb_language_t language;
+} hb_ot_name_entry_t;
+
+HB_EXTERN unsigned int
+hb_ot_name_get_names (hb_face_t           *face,
+		      hb_ot_name_entry_t **entries /* OUT */);
+
+
 HB_END_DECLS
 
 #endif /* HB_OT_NAME_H */


More information about the HarfBuzz mailing list