Bug 1251203 - Update harfbuzz to release 1.2.6. r=jrmuizel
authorJonathan Kew <jkew@mozilla.com>
Wed, 13 Apr 2016 11:07:08 +0100
changeset 293005 aeb302aeff162e1d0f7b80359a9e9a8de1ce086b
parent 293004 03be6d926fac7a1eb2828d6168edcea83a187912
child 293006 2c9daa36cfd7d8ba0a75220cb9453817f816acde
push id30172
push userkwierso@gmail.com
push dateWed, 13 Apr 2016 21:18:48 +0000
treeherdermozilla-central@bc2373295e31 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjrmuizel
bugs1251203
milestone48.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1251203 - Update harfbuzz to release 1.2.6. r=jrmuizel
gfx/harfbuzz/README-mozilla
gfx/harfbuzz/src/Makefile.am
gfx/harfbuzz/src/hb-buffer-private.hh
gfx/harfbuzz/src/hb-buffer.cc
gfx/harfbuzz/src/hb-coretext.cc
gfx/harfbuzz/src/hb-deprecated.h
gfx/harfbuzz/src/hb-directwrite.cc
gfx/harfbuzz/src/hb-fallback-shape.cc
gfx/harfbuzz/src/hb-font-private.hh
gfx/harfbuzz/src/hb-font.cc
gfx/harfbuzz/src/hb-font.h
gfx/harfbuzz/src/hb-ft.cc
gfx/harfbuzz/src/hb-icu.cc
gfx/harfbuzz/src/hb-open-type-private.hh
gfx/harfbuzz/src/hb-ot-cmap-table.hh
gfx/harfbuzz/src/hb-ot-font.cc
gfx/harfbuzz/src/hb-ot-glyf-table.hh
gfx/harfbuzz/src/hb-ot-hmtx-table.hh
gfx/harfbuzz/src/hb-ot-layout-gsub-table.hh
gfx/harfbuzz/src/hb-ot-layout.cc
gfx/harfbuzz/src/hb-ot-map.cc
gfx/harfbuzz/src/hb-ot-shape-complex-indic.cc
gfx/harfbuzz/src/hb-ot-shape-complex-myanmar.cc
gfx/harfbuzz/src/hb-ot-shape-complex-thai.cc
gfx/harfbuzz/src/hb-ot-shape-complex-use.cc
gfx/harfbuzz/src/hb-ot-shape-fallback.cc
gfx/harfbuzz/src/hb-ot-shape-normalize.cc
gfx/harfbuzz/src/hb-ot-shape.cc
gfx/harfbuzz/src/hb-private.hh
gfx/harfbuzz/src/hb-unicode-private.hh
gfx/harfbuzz/src/hb-version.h
--- a/gfx/harfbuzz/README-mozilla
+++ b/gfx/harfbuzz/README-mozilla
@@ -1,16 +1,14 @@
-gfx/harfbuzz status as of 2016-04-07:
+gfx/harfbuzz status as of 2016-04-12:
 
 This directory contains the harfbuzz source from the 'master' branch of
 https://github.com/behdad/harfbuzz.
 
-Current version: 1.2.2
-Plus cherry-picked commit 6dd80faf0dcb3e8a8915c3a25da44e2a67cb0cd8 to fix
-broken mark filter set support.
+Current version: 1.2.6
 
 
 UPDATING:
 
 Note that gfx/harfbuzz/src/hb-version.h is not present in the upstream Git
 repository. It is created at build time by the harfbuzz build system;
 but as we don't use that build system in mozilla, it is necessary to refresh
 this file when updating harfbuzz, and check it into the mozilla tree.
--- a/gfx/harfbuzz/src/Makefile.am
+++ b/gfx/harfbuzz/src/Makefile.am
@@ -125,40 +125,48 @@ libharfbuzz_la_LIBADD = $(HBLIBS)
 EXTRA_libharfbuzz_la_DEPENDENCIES = $(harfbuzz_def_dependency)
 pkginclude_HEADERS = $(HBHEADERS)
 nodist_pkginclude_HEADERS = $(HBNODISTHEADERS)
 pkgconfigdir = $(libdir)/pkgconfig
 pkgconfig_DATA = harfbuzz.pc
 EXTRA_DIST += harfbuzz.pc.in
 
 FUZZING_CPPFLAGS= \
+	-DHB_NDEBUG \
 	-DHB_MAX_NESTING_LEVEL=3 \
 	-DHB_SANITIZE_MAX_EDITS=3 \
 	-DHB_BUFFER_MAX_EXPANSION_FACTOR=3 \
 	-DHB_BUFFER_MAX_LEN_MIN=8 \
 	-DHB_BUFFER_MAX_LEN_DEFAULT=128 \
 	$(NULL)
 EXTRA_LTLIBRARIES = libharfbuzz-fuzzing.la
 libharfbuzz_fuzzing_la_LINK = $(libharfbuzz_la_LINK)
 libharfbuzz_fuzzing_la_SOURCES = $(libharfbuzz_la_SOURCES)
 libharfbuzz_fuzzing_la_CPPFLAGS = $(libharfbuzz_la_CPPFLAGS) $(FUZZING_CPPFLAGS)
 libharfbuzz_fuzzing_la_LDFLAGS = $(libharfbuzz_la_LDFLAGS)
 libharfbuzz_fuzzing_la_LIBADD = $(libharfbuzz_la_LIBADD)
 EXTRA_libharfbuzz_fuzzing_la_DEPENDENCIES = $(EXTRA_libharfbuzz_la_DEPENDENCIES)
 CLEANFILES += libharfbuzz-fuzzing.la
 
 if HAVE_ICU
+if HAVE_ICU_BUILTIN
+HBCFLAGS += $(ICU_CFLAGS)
+HBLIBS += $(ICU_LIBS)
+HBSOURCES += $(HB_ICU_sources)
+HBHEADERS += $(HB_ICU_headers)
+else
 lib_LTLIBRARIES += libharfbuzz-icu.la
 libharfbuzz_icu_la_SOURCES = $(HB_ICU_sources)
 libharfbuzz_icu_la_CPPFLAGS = $(ICU_CFLAGS)
 libharfbuzz_icu_la_LDFLAGS = $(AM_LDFLAGS) -version-info $(HB_LIBTOOL_VERSION_INFO) -no-undefined
 libharfbuzz_icu_la_LIBADD = $(ICU_LIBS) libharfbuzz.la
 pkginclude_HEADERS += $(HB_ICU_headers)
 pkgconfig_DATA += harfbuzz-icu.pc
 endif
+endif
 EXTRA_DIST += harfbuzz-icu.pc.in
 
 if HAVE_GOBJECT
 lib_LTLIBRARIES += libharfbuzz-gobject.la
 libharfbuzz_gobject_la_SOURCES = $(HB_GOBJECT_sources)
 nodist_libharfbuzz_gobject_la_SOURCES = $(HB_GOBJECT_ENUM_sources)
 libharfbuzz_gobject_la_CPPFLAGS = $(GOBJECT_CFLAGS)
 libharfbuzz_gobject_la_LDFLAGS = $(AM_LDFLAGS) -version-info $(HB_LIBTOOL_VERSION_INFO) -no-undefined
--- a/gfx/harfbuzz/src/hb-buffer-private.hh
+++ b/gfx/harfbuzz/src/hb-buffer-private.hh
@@ -107,49 +107,81 @@ struct hb_buffer_t {
 
   inline hb_glyph_info_t &prev (void) { return out_info[out_len ? out_len - 1 : 0]; }
   inline hb_glyph_info_t prev (void) const { return out_info[out_len ? out_len - 1 : 0]; }
 
   inline bool has_separate_output (void) const { return info != out_info; }
 
   unsigned int serial;
 
-  /* These reflect current allocations of the bytes in glyph_info_t's var1 and var2. */
-  uint8_t allocated_var_bytes[8];
-  const char *allocated_var_owner[8];
-
   /* Text before / after the main buffer contents.
    * Always in Unicode, and ordered outward.
    * Index 0 is for "pre-context", 1 for "post-context". */
   static const unsigned int CONTEXT_LENGTH = 5;
   hb_codepoint_t context[2][CONTEXT_LENGTH];
   unsigned int context_len[2];
 
-  /* Debugging */
+  /* Debugging API */
   hb_buffer_message_func_t message_func;
   void *message_data;
   hb_destroy_func_t message_destroy;
 
+  /* Internal debugging. */
+  /* The bits here reflect current allocations of the bytes in glyph_info_t's var1 and var2. */
+#ifndef HB_NDEBUG
+  uint8_t allocated_var_bits;
+#endif
+  inline void allocate_var (unsigned int start, unsigned int count)
+  {
+#ifndef HB_NDEBUG
+    unsigned int end = start + count;
+    assert (end <= 8);
+    unsigned int bits = (1<<end) - (1<<start);
+    assert (0 == (allocated_var_bits & bits));
+    allocated_var_bits |= bits;
+#endif
+  }
+  inline void deallocate_var (unsigned int start, unsigned int count)
+  {
+#ifndef HB_NDEBUG
+    unsigned int end = start + count;
+    assert (end <= 8);
+    unsigned int bits = (1<<end) - (1<<start);
+    assert (bits == (allocated_var_bits & bits));
+    allocated_var_bits &= ~bits;
+#endif
+  }
+  inline void assert_var (unsigned int start, unsigned int count)
+  {
+#ifndef HB_NDEBUG
+    unsigned int end = start + count;
+    assert (end <= 8);
+    unsigned int bits = (1<<end) - (1<<start);
+    assert (bits == (allocated_var_bits & bits));
+#endif
+  }
+  inline void deallocate_var_all (void)
+  {
+#ifndef HB_NDEBUG
+    allocated_var_bits = 0;
+#endif
+  }
+
 
   /* Methods */
 
   HB_INTERNAL void reset (void);
   HB_INTERNAL void clear (void);
 
   inline unsigned int backtrack_len (void) const
   { return have_output? out_len : idx; }
   inline unsigned int lookahead_len (void) const
   { return len - idx; }
   inline unsigned int next_serial (void) { return serial++; }
 
-  HB_INTERNAL void allocate_var (unsigned int byte_i, unsigned int count, const char *owner);
-  HB_INTERNAL void deallocate_var (unsigned int byte_i, unsigned int count, const char *owner);
-  HB_INTERNAL void assert_var (unsigned int byte_i, unsigned int count, const char *owner);
-  HB_INTERNAL void deallocate_var_all (void);
-
   HB_INTERNAL void add (hb_codepoint_t  codepoint,
 			unsigned int    cluster);
   HB_INTERNAL void add_info (const hb_glyph_info_t &glyph_info);
 
   HB_INTERNAL void reverse_range (unsigned int start, unsigned int end);
   HB_INTERNAL void reverse (void);
   HB_INTERNAL void reverse_clusters (void);
   HB_INTERNAL void guess_segment_properties (void);
@@ -248,20 +280,17 @@ struct hb_buffer_t {
     bool ret = message_impl (font, fmt, ap);
     va_end (ap);
     return ret;
   }
   HB_INTERNAL bool message_impl (hb_font_t *font, const char *fmt, va_list ap) HB_PRINTF_FUNC(3, 0);
 };
 
 
-#define HB_BUFFER_XALLOCATE_VAR(b, func, var, owner) \
+#define HB_BUFFER_XALLOCATE_VAR(b, func, var) \
   b->func (offsetof (hb_glyph_info_t, var) - offsetof(hb_glyph_info_t, var1), \
-	   sizeof (b->info[0].var), owner)
-#define HB_BUFFER_ALLOCATE_VAR(b, var) \
-	HB_BUFFER_XALLOCATE_VAR (b, allocate_var, var (), #var)
-#define HB_BUFFER_DEALLOCATE_VAR(b, var) \
-	HB_BUFFER_XALLOCATE_VAR (b, deallocate_var, var (), #var)
-#define HB_BUFFER_ASSERT_VAR(b, var) \
-	HB_BUFFER_XALLOCATE_VAR (b, assert_var, var (), #var)
+	   sizeof (b->info[0].var))
+#define HB_BUFFER_ALLOCATE_VAR(b, var)		HB_BUFFER_XALLOCATE_VAR (b, allocate_var,   var ())
+#define HB_BUFFER_DEALLOCATE_VAR(b, var)	HB_BUFFER_XALLOCATE_VAR (b, deallocate_var, var ())
+#define HB_BUFFER_ASSERT_VAR(b, var)		HB_BUFFER_XALLOCATE_VAR (b, assert_var,     var ())
 
 
 #endif /* HB_BUFFER_PRIVATE_HH */
--- a/gfx/harfbuzz/src/hb-buffer.cc
+++ b/gfx/harfbuzz/src/hb-buffer.cc
@@ -237,21 +237,21 @@ hb_buffer_t::clear (void)
   have_positions = false;
 
   idx = 0;
   len = 0;
   out_len = 0;
   out_info = info;
 
   serial = 0;
-  memset (allocated_var_bytes, 0, sizeof allocated_var_bytes);
-  memset (allocated_var_owner, 0, sizeof allocated_var_owner);
 
   memset (context, 0, sizeof context);
   memset (context_len, 0, sizeof context_len);
+
+  deallocate_var_all ();
 }
 
 void
 hb_buffer_t::add (hb_codepoint_t  codepoint,
 		  unsigned int    cluster)
 {
   hb_glyph_info_t *glyph;
 
@@ -656,84 +656,16 @@ hb_buffer_t::guess_segment_properties (v
   /* If language is not set, use default language from locale */
   if (props.language == HB_LANGUAGE_INVALID) {
     /* TODO get_default_for_script? using $LANGUAGE */
     props.language = hb_language_get_default ();
   }
 }
 
 
-static inline void
-dump_var_allocation (const hb_buffer_t *buffer)
-{
-  char buf[80];
-  for (unsigned int i = 0; i < 8; i++)
-    buf[i] = '0' + buffer->allocated_var_bytes[7 - i];
-  buf[8] = '\0';
-  DEBUG_MSG (BUFFER, buffer,
-	     "Current var allocation: %s",
-	     buf);
-}
-
-void hb_buffer_t::allocate_var (unsigned int byte_i, unsigned int count, const char *owner)
-{
-  assert (byte_i < 8 && byte_i + count <= 8);
-
-  if (DEBUG_ENABLED (BUFFER))
-    dump_var_allocation (this);
-  DEBUG_MSG (BUFFER, this,
-	     "Allocating var bytes %d..%d for %s",
-	     byte_i, byte_i + count - 1, owner);
-
-  for (unsigned int i = byte_i; i < byte_i + count; i++) {
-    assert (!allocated_var_bytes[i]);
-    allocated_var_bytes[i]++;
-    allocated_var_owner[i] = owner;
-  }
-}
-
-void hb_buffer_t::deallocate_var (unsigned int byte_i, unsigned int count, const char *owner)
-{
-  if (DEBUG_ENABLED (BUFFER))
-    dump_var_allocation (this);
-
-  DEBUG_MSG (BUFFER, this,
-	     "Deallocating var bytes %d..%d for %s",
-	     byte_i, byte_i + count - 1, owner);
-
-  assert (byte_i < 8 && byte_i + count <= 8);
-  for (unsigned int i = byte_i; i < byte_i + count; i++) {
-    assert (allocated_var_bytes[i]);
-    assert (0 == strcmp (allocated_var_owner[i], owner));
-    allocated_var_bytes[i]--;
-  }
-}
-
-void hb_buffer_t::assert_var (unsigned int byte_i, unsigned int count, const char *owner)
-{
-  if (DEBUG_ENABLED (BUFFER))
-    dump_var_allocation (this);
-
-  DEBUG_MSG (BUFFER, this,
-	     "Asserting var bytes %d..%d for %s",
-	     byte_i, byte_i + count - 1, owner);
-
-  assert (byte_i < 8 && byte_i + count <= 8);
-  for (unsigned int i = byte_i; i < byte_i + count; i++) {
-    assert (allocated_var_bytes[i]);
-    assert (0 == strcmp (allocated_var_owner[i], owner));
-  }
-}
-
-void hb_buffer_t::deallocate_var_all (void)
-{
-  memset (allocated_var_bytes, 0, sizeof (allocated_var_bytes));
-  memset (allocated_var_owner, 0, sizeof (allocated_var_owner));
-}
-
 /* Public API */
 
 /**
  * hb_buffer_create: (Xconstructor)
  *
  * Creates a new #hb_buffer_t with all properties to defaults.
  *
  * Return value: (transfer full):
--- a/gfx/harfbuzz/src/hb-coretext.cc
+++ b/gfx/harfbuzz/src/hb-coretext.cc
@@ -899,23 +899,21 @@ resize_and_retry:
 	 *
 	 * Finally, we compare PS names, which I don't think are unique...
 	 *
 	 * Looks like if we really want to be sure here we have to modify the
 	 * font to change the name table, similar to what we do in the uniscribe
 	 * backend.
 	 *
 	 * However, even that wouldn't work if we were passed in the CGFont to
-	 * begin with.
-	 *
-	 * We might switch to checking PS name against "LastResort".  That would
-	 * be safe for all fonts except for those named "Last Resort".  Might be
-	 * better than what we have right now.
+	 * construct a hb_face to begin with.
 	 *
 	 * See: http://github.com/behdad/harfbuzz/pull/36
+	 *
+	 * Also see: https://bugs.chromium.org/p/chromium/issues/detail?id=597098
 	 */
 	bool matched = false;
 	for (unsigned int i = 0; i < range_records.len; i++)
 	  if (range_records[i].font && CFEqual (run_ct_font, range_records[i].font))
 	  {
 	    matched = true;
 	    break;
 	  }
--- a/gfx/harfbuzz/src/hb-deprecated.h
+++ b/gfx/harfbuzz/src/hb-deprecated.h
@@ -39,13 +39,23 @@ HB_BEGIN_DECLS
 
 #ifndef HB_DISABLE_DEPRECATED
 
 #define HB_SCRIPT_CANADIAN_ABORIGINAL		HB_SCRIPT_CANADIAN_SYLLABICS
 
 #define HB_BUFFER_FLAGS_DEFAULT			HB_BUFFER_FLAG_DEFAULT
 #define HB_BUFFER_SERIALIZE_FLAGS_DEFAULT	HB_BUFFER_SERIALIZE_FLAG_DEFAULT
 
+typedef hb_bool_t (*hb_font_get_glyph_func_t) (hb_font_t *font, void *font_data,
+					       hb_codepoint_t unicode, hb_codepoint_t variation_selector,
+					       hb_codepoint_t *glyph,
+					       void *user_data);
+
+HB_EXTERN void
+hb_font_funcs_set_glyph_func (hb_font_funcs_t *ffuncs,
+			      hb_font_get_glyph_func_t func,
+			      void *user_data, hb_destroy_func_t destroy);
+
 #endif
 
 HB_END_DECLS
 
 #endif /* HB_DEPRECATED_H */
--- a/gfx/harfbuzz/src/hb-directwrite.cc
+++ b/gfx/harfbuzz/src/hb-directwrite.cc
@@ -1,10 +1,10 @@
 /*
- * Copyright © 2015  Ebrahim Byagowi
+ * Copyright © 2015-2016  Ebrahim Byagowi
  *
  *  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.
@@ -20,17 +20,21 @@
  * 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.
  */
 
 #define HB_SHAPER directwrite
 #include "hb-shaper-impl-private.hh"
 
-#include <dwrite.h>
+#ifndef HB_DIRECTWRITE_EXPERIMENTAL_JUSTIFICATION
+  #include <DWrite.h>
+#else
+  #include <DWrite_1.h>
+#endif
 
 #include "hb-directwrite.h"
 
 #include "hb-open-file-private.hh"
 #include "hb-ot-name-table.hh"
 #include "hb-ot-tag.h"
 
 
@@ -171,17 +175,18 @@ static hb_blob_t *
   hb_blob_destroy (blob);
   return hb_blob_create ((const char *)new_sfnt_data, new_length,
     HB_MEMORY_MODE_WRITABLE, NULL, free);
 }
 
 hb_directwrite_shaper_face_data_t *
 _hb_directwrite_shaper_face_data_create(hb_face_t *face)
 {
-  hb_directwrite_shaper_face_data_t *data = (hb_directwrite_shaper_face_data_t *)calloc(1, sizeof (hb_directwrite_shaper_face_data_t));
+  hb_directwrite_shaper_face_data_t *data =
+    (hb_directwrite_shaper_face_data_t *) calloc (1, sizeof (hb_directwrite_shaper_face_data_t));
   if (unlikely (!data))
     return NULL;
 
   hb_blob_t *blob = hb_face_reference_blob (face);
   if (unlikely (!hb_blob_get_length (blob)))
     DEBUG_MSG(DIRECTWRITE, face, "Face has empty blob");
 
   blob = _hb_rename_font (blob, data->face_name);
@@ -239,36 +244,40 @@ populate_log_font (LOGFONTW  *lf,
   return true;
 }
 
 hb_directwrite_shaper_font_data_t *
 _hb_directwrite_shaper_font_data_create (hb_font_t *font)
 {
   if (unlikely (!hb_directwrite_shaper_face_data_ensure (font->face))) return NULL;
 
-  hb_directwrite_shaper_font_data_t *data = (hb_directwrite_shaper_font_data_t *) calloc (1, sizeof (hb_directwrite_shaper_font_data_t));
+  hb_directwrite_shaper_font_data_t *data =
+    (hb_directwrite_shaper_font_data_t *) calloc (1, sizeof (hb_directwrite_shaper_font_data_t));
   if (unlikely (!data))
     return NULL;
 
   data->hdc = GetDC (NULL);
 
-  if (unlikely (!populate_log_font (&data->log_font, font))) {
+  if (unlikely (!populate_log_font (&data->log_font, font)))
+  {
     DEBUG_MSG (DIRECTWRITE, font, "Font populate_log_font() failed");
     _hb_directwrite_shaper_font_data_destroy (data);
     return NULL;
   }
 
   data->hfont = CreateFontIndirectW (&data->log_font);
-  if (unlikely (!data->hfont)) {
+  if (unlikely (!data->hfont))
+  {
     DEBUG_MSG (DIRECTWRITE, font, "Font CreateFontIndirectW() failed");
     _hb_directwrite_shaper_font_data_destroy (data);
      return NULL;
   }
 
-  if (!SelectObject (data->hdc, data->hfont)) {
+  if (!SelectObject (data->hdc, data->hfont))
+  {
     DEBUG_MSG (DIRECTWRITE, font, "Font SelectObject() failed");
     _hb_directwrite_shaper_font_data_destroy (data);
      return NULL;
   }
 
   return data;
 }
 
@@ -328,51 +337,51 @@ public:
   IFACEMETHOD(QueryInterface)(IID const& iid, OUT void** ppObject) { return S_OK; }
   IFACEMETHOD_(ULONG, AddRef)() { return 1; }
   IFACEMETHOD_(ULONG, Release)() { return 1; }
 
   // A single contiguous run of characters containing the same analysis 
   // results.
   struct Run
   {
-    UINT32 mTextStart;   // starting text position of this run
-    UINT32 mTextLength;  // number of contiguous code units covered
-    UINT32 mGlyphStart;  // starting glyph in the glyphs array
-    UINT32 mGlyphCount;  // number of glyphs associated with this run of 
+    uint32_t mTextStart;   // starting text position of this run
+    uint32_t mTextLength;  // number of contiguous code units covered
+    uint32_t mGlyphStart;  // starting glyph in the glyphs array
+    uint32_t mGlyphCount;  // number of glyphs associated with this run of 
     // text
     DWRITE_SCRIPT_ANALYSIS mScript;
-    UINT8 mBidiLevel;
+    uint8_t mBidiLevel;
     bool mIsSideways;
 
-    inline bool ContainsTextPosition(UINT32 aTextPosition) const
+    inline bool ContainsTextPosition(uint32_t aTextPosition) const
     {
       return aTextPosition >= mTextStart
         && aTextPosition <  mTextStart + mTextLength;
     }
 
     Run *nextRun;
   };
 
 public:
   TextAnalysis(const wchar_t* text,
-    UINT32 textLength,
+    uint32_t textLength,
     const wchar_t* localeName,
     DWRITE_READING_DIRECTION readingDirection)
     : mText(text)
     , mTextLength(textLength)
     , mLocaleName(localeName)
     , mReadingDirection(readingDirection)
     , mCurrentRun(NULL) { };
 
   ~TextAnalysis() {
     // delete runs, except mRunHead which is part of the TextAnalysis object
     for (Run *run = mRunHead.nextRun; run;) {
       Run *origRun = run;
       run = run->nextRun;
-      delete origRun;
+      free (origRun);
     }
   }
 
   STDMETHODIMP GenerateResults(IDWriteTextAnalyzer* textAnalyzer,
     Run **runHead) {
     // Analyzes the text using the script analyzer and returns
     // the result as a series of runs.
 
@@ -383,47 +392,44 @@ public:
     mRunHead.mTextStart = 0;
     mRunHead.mTextLength = mTextLength;
     mRunHead.mBidiLevel =
       (mReadingDirection == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT);
     mRunHead.nextRun = NULL;
     mCurrentRun = &mRunHead;
 
     // Call each of the analyzers in sequence, recording their results.
-    if (SUCCEEDED(hr = textAnalyzer->AnalyzeScript(this,
-      0,
-      mTextLength,
-      this))) {
+    if (SUCCEEDED (hr = textAnalyzer->AnalyzeScript (this, 0, mTextLength, this))) {
       *runHead = &mRunHead;
     }
 
     return hr;
   }
 
   // IDWriteTextAnalysisSource implementation
 
-  IFACEMETHODIMP GetTextAtPosition(UINT32 textPosition,
-    OUT WCHAR const** textString,
-    OUT UINT32* textLength)
+  IFACEMETHODIMP GetTextAtPosition(uint32_t textPosition,
+    OUT wchar_t const** textString,
+    OUT uint32_t* textLength)
   {
     if (textPosition >= mTextLength) {
       // No text at this position, valid query though.
       *textString = NULL;
       *textLength = 0;
     }
     else {
       *textString = mText + textPosition;
       *textLength = mTextLength - textPosition;
     }
     return S_OK;
   }
 
-  IFACEMETHODIMP GetTextBeforePosition(UINT32 textPosition,
-    OUT WCHAR const** textString,
-    OUT UINT32* textLength)
+  IFACEMETHODIMP GetTextBeforePosition(uint32_t textPosition,
+    OUT wchar_t const** textString,
+    OUT uint32_t* textLength)
   {
     if (textPosition == 0 || textPosition > mTextLength) {
       // Either there is no text before here (== 0), or this
       // is an invalid position. The query is considered valid thouh.
       *textString = NULL;
       *textLength = 0;
     }
     else {
@@ -431,68 +437,68 @@ public:
       *textLength = textPosition;
     }
     return S_OK;
   }
 
   IFACEMETHODIMP_(DWRITE_READING_DIRECTION)
     GetParagraphReadingDirection() { return mReadingDirection; }
 
-  IFACEMETHODIMP GetLocaleName(UINT32 textPosition,
-    UINT32* textLength,
-    WCHAR const** localeName) {
+  IFACEMETHODIMP GetLocaleName(uint32_t textPosition,
+    uint32_t* textLength,
+    wchar_t const** localeName) {
     return S_OK;
   }
 
   IFACEMETHODIMP
-    GetNumberSubstitution(UINT32 textPosition,
-    OUT UINT32* textLength,
+    GetNumberSubstitution(uint32_t textPosition,
+    OUT uint32_t* textLength,
     OUT IDWriteNumberSubstitution** numberSubstitution)
   {
     // We do not support number substitution.
     *numberSubstitution = NULL;
     *textLength = mTextLength - textPosition;
 
     return S_OK;
   }
 
   // IDWriteTextAnalysisSink implementation
 
   IFACEMETHODIMP
-    SetScriptAnalysis(UINT32 textPosition,
-    UINT32 textLength,
+    SetScriptAnalysis(uint32_t textPosition,
+    uint32_t textLength,
     DWRITE_SCRIPT_ANALYSIS const* scriptAnalysis)
   {
     SetCurrentRun(textPosition);
     SplitCurrentRun(textPosition);
     while (textLength > 0) {
       Run *run = FetchNextRun(&textLength);
       run->mScript = *scriptAnalysis;
     }
 
     return S_OK;
   }
 
   IFACEMETHODIMP
-    SetLineBreakpoints(UINT32 textPosition,
-    UINT32 textLength,
+    SetLineBreakpoints(uint32_t textPosition,
+    uint32_t textLength,
     const DWRITE_LINE_BREAKPOINT* lineBreakpoints) { return S_OK; }
 
-  IFACEMETHODIMP SetBidiLevel(UINT32 textPosition,
-    UINT32 textLength,
-    UINT8 explicitLevel,
-    UINT8 resolvedLevel) { return S_OK; }
+  IFACEMETHODIMP SetBidiLevel(uint32_t textPosition,
+    uint32_t textLength,
+    uint8_t explicitLevel,
+    uint8_t resolvedLevel) { return S_OK; }
 
   IFACEMETHODIMP
-    SetNumberSubstitution(UINT32 textPosition,
-    UINT32 textLength,
+    SetNumberSubstitution(uint32_t textPosition,
+    uint32_t textLength,
     IDWriteNumberSubstitution* numberSubstitution) { return S_OK; }
 
 protected:
-  Run *FetchNextRun(IN OUT UINT32* textLength)
+  Run *FetchNextRun(IN OUT uint32_t* textLength)
   {
     // Used by the sink setters, this returns a reference to the next run.
     // Position and length are adjusted to now point after the current run
     // being returned.
 
     Run *origRun = mCurrentRun;
     // Split the tail if needed (the length remaining is less than the
     // current run's size).
@@ -504,17 +510,17 @@ protected:
       mCurrentRun = mCurrentRun->nextRun;
     }
     *textLength -= origRun->mTextLength;
 
     // Return a reference to the run that was just current.
     return origRun;
   }
 
-  void SetCurrentRun(UINT32 textPosition)
+  void SetCurrentRun(uint32_t textPosition)
   {
     // Move the current run to the given position.
     // Since the analyzers generally return results in a forward manner,
     // this will usually just return early. If not, find the
     // corresponding run for the text position.
 
     if (mCurrentRun && mCurrentRun->ContainsTextPosition(textPosition)) {
       return;
@@ -525,61 +531,65 @@ protected:
         mCurrentRun = run;
         return;
       }
     }
     //NS_NOTREACHED("We should always be able to find the text position in one \
             //                of our runs");
   }
 
-  void SplitCurrentRun(UINT32 splitPosition)
+  void SplitCurrentRun(uint32_t splitPosition)
   {
     if (!mCurrentRun) {
       //NS_ASSERTION(false, "SplitCurrentRun called without current run.");
       // Shouldn't be calling this when no current run is set!
       return;
     }
     // Split the current run.
     if (splitPosition <= mCurrentRun->mTextStart) {
       // No need to split, already the start of a run
       // or before it. Usually the first.
       return;
     }
-    Run *newRun = new Run;
+    Run *newRun = (Run*) malloc (sizeof (Run));
 
     *newRun = *mCurrentRun;
 
     // Insert the new run in our linked list.
     newRun->nextRun = mCurrentRun->nextRun;
     mCurrentRun->nextRun = newRun;
 
     // Adjust runs' text positions and lengths.
-    UINT32 splitPoint = splitPosition - mCurrentRun->mTextStart;
+    uint32_t splitPoint = splitPosition - mCurrentRun->mTextStart;
     newRun->mTextStart += splitPoint;
     newRun->mTextLength -= splitPoint;
     mCurrentRun->mTextLength = splitPoint;
     mCurrentRun = newRun;
   }
 
 protected:
   // Input
   // (weak references are fine here, since this class is a transient
   //  stack-based helper that doesn't need to copy data)
-  UINT32 mTextLength;
-  const WCHAR* mText;
-  const WCHAR* mLocaleName;
+  uint32_t mTextLength;
+  const wchar_t* mText;
+  const wchar_t* mLocaleName;
   DWRITE_READING_DIRECTION mReadingDirection;
 
   // Current processing state.
   Run *mCurrentRun;
 
   // Output is a list of runs starting here
   Run  mRunHead;
 };
 
+static inline uint16_t hb_uint16_swap (const uint16_t v)
+{ return (v >> 8) | (v << 8); }
+static inline uint32_t hb_uint32_swap (const uint32_t v)
+{ return (hb_uint16_swap(v) << 16) | hb_uint16_swap(v >> 16); }
 
 /*
  * shaper
  */
 
 hb_bool_t
 _hb_directwrite_shape(hb_shape_plan_t    *shape_plan,
   hb_font_t          *font,
@@ -587,63 +597,73 @@ hb_bool_t
   const hb_feature_t *features,
   unsigned int        num_features)
 {
   hb_face_t *face = font->face;
   hb_directwrite_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
   hb_directwrite_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font);
 
   // factory probably should be cached
+#ifndef HB_DIRECTWRITE_EXPERIMENTAL_JUSTIFICATION
   IDWriteFactory* dwriteFactory;
-  DWriteCreateFactory(
+#else
+  IDWriteFactory1* dwriteFactory;
+#endif
+  DWriteCreateFactory (
     DWRITE_FACTORY_TYPE_SHARED,
-    __uuidof(IDWriteFactory),
-    reinterpret_cast<IUnknown**>(&dwriteFactory)
-    );
+    __uuidof (IDWriteFactory),
+    (IUnknown**) &dwriteFactory
+  );
 
   IDWriteGdiInterop *gdiInterop;
   dwriteFactory->GetGdiInterop (&gdiInterop);
   IDWriteFontFace* fontFace;
   gdiInterop->CreateFontFaceFromHdc (font_data->hdc, &fontFace);
 
+#ifndef HB_DIRECTWRITE_EXPERIMENTAL_JUSTIFICATION
   IDWriteTextAnalyzer* analyzer;
-  dwriteFactory->CreateTextAnalyzer (&analyzer);
+  dwriteFactory->CreateTextAnalyzer(&analyzer);
+#else
+  IDWriteTextAnalyzer* analyzer0;
+  dwriteFactory->CreateTextAnalyzer (&analyzer0);
+  IDWriteTextAnalyzer1* analyzer = (IDWriteTextAnalyzer1*) analyzer0;
+#endif
 
   unsigned int scratch_size;
   hb_buffer_t::scratch_buffer_t *scratch = buffer->get_scratch_buffer (&scratch_size);
 #define ALLOCATE_ARRAY(Type, name, len) \
   Type *name = (Type *) scratch; \
   { \
     unsigned int _consumed = DIV_CEIL ((len) * sizeof (Type), sizeof (*scratch)); \
     assert (_consumed <= scratch_size); \
     scratch += _consumed; \
     scratch_size -= _consumed; \
   }
 
 #define utf16_index() var1.u32
 
-  ALLOCATE_ARRAY(WCHAR, pchars, buffer->len * 2);
+  ALLOCATE_ARRAY(wchar_t, textString, buffer->len * 2);
 
   unsigned int chars_len = 0;
   for (unsigned int i = 0; i < buffer->len; i++)
   {
     hb_codepoint_t c = buffer->info[i].codepoint;
     buffer->info[i].utf16_index() = chars_len;
     if (likely(c <= 0xFFFFu))
-      pchars[chars_len++] = c;
+      textString[chars_len++] = c;
     else if (unlikely(c > 0x10FFFFu))
-      pchars[chars_len++] = 0xFFFDu;
+      textString[chars_len++] = 0xFFFDu;
     else {
-      pchars[chars_len++] = 0xD800u + ((c - 0x10000u) >> 10);
-      pchars[chars_len++] = 0xDC00u + ((c - 0x10000u) & ((1 << 10) - 1));
+      textString[chars_len++] = 0xD800u + ((c - 0x10000u) >> 10);
+      textString[chars_len++] = 0xDC00u + ((c - 0x10000u) & ((1 << 10) - 1));
     }
   }
 
   ALLOCATE_ARRAY(WORD, log_clusters, chars_len);
-  if (num_features)
+  // if (num_features)
   {
     /* Need log_clusters to assign features. */
     chars_len = 0;
     for (unsigned int i = 0; i < buffer->len; i++)
     {
       hb_codepoint_t c = buffer->info[i].codepoint;
       unsigned int cluster = buffer->info[i].cluster;
       log_clusters[chars_len++] = cluster;
@@ -659,169 +679,292 @@ hb_bool_t
     DWRITE_READING_DIRECTION_RIGHT_TO_LEFT :
     DWRITE_READING_DIRECTION_LEFT_TO_RIGHT;
 
   /*
   * There's an internal 16-bit limit on some things inside the analyzer,
   * but we never attempt to shape a word longer than 64K characters
   * in a single gfxShapedWord, so we cannot exceed that limit.
   */
-  UINT32 length = buffer->len;
+  uint32_t textLength = buffer->len;
 
-  TextAnalysis analysis(pchars, length, NULL, readingDirection);
+  TextAnalysis analysis(textString, textLength, NULL, readingDirection);
   TextAnalysis::Run *runHead;
   hr = analysis.GenerateResults(analyzer, &runHead);
 
-  if (FAILED(hr)) {
-    //NS_WARNING("Analyzer failed to generate results.");
+#define FAIL(...) \
+  HB_STMT_START { \
+    DEBUG_MSG (DIRECTWRITE, NULL, __VA_ARGS__); \
+    return false; \
+  } HB_STMT_END;
+
+  if (FAILED (hr))
+  {
+    FAIL ("Analyzer failed to generate results.");
+    return false;
+  }
+
+  uint32_t maxGlyphCount = 3 * textLength / 2 + 16;
+  uint32_t glyphCount;
+  bool isRightToLeft = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);
+
+  const wchar_t localeName[20] = {0};
+  if (buffer->props.language != NULL)
+  {
+    mbstowcs ((wchar_t*) localeName,
+      hb_language_to_string (buffer->props.language), 20);
+  }
+
+  DWRITE_TYPOGRAPHIC_FEATURES singleFeatures;
+  singleFeatures.featureCount = num_features;
+  if (num_features)
+  {
+    DWRITE_FONT_FEATURE* dwfeatureArray = (DWRITE_FONT_FEATURE*)
+      malloc (sizeof (DWRITE_FONT_FEATURE) * num_features);
+    for (unsigned int i = 0; i < num_features; ++i)
+    {
+      dwfeatureArray[i].nameTag = (DWRITE_FONT_FEATURE_TAG)
+        hb_uint32_swap (features[i].tag);
+      dwfeatureArray[i].parameter = features[i].value;
+    }
+    singleFeatures.features = dwfeatureArray;
+  }
+  const DWRITE_TYPOGRAPHIC_FEATURES* dwFeatures =
+    (const DWRITE_TYPOGRAPHIC_FEATURES*) &singleFeatures;
+  const uint32_t featureRangeLengths[] = { textLength };
+
+retry_getglyphs:
+  uint16_t* clusterMap = (uint16_t*) malloc (maxGlyphCount * sizeof (uint16_t));
+  uint16_t* glyphIndices = (uint16_t*) malloc (maxGlyphCount * sizeof (uint16_t));
+  DWRITE_SHAPING_TEXT_PROPERTIES* textProperties = (DWRITE_SHAPING_TEXT_PROPERTIES*)
+    malloc (maxGlyphCount * sizeof (DWRITE_SHAPING_TEXT_PROPERTIES));
+  DWRITE_SHAPING_GLYPH_PROPERTIES* glyphProperties = (DWRITE_SHAPING_GLYPH_PROPERTIES*)
+    malloc (maxGlyphCount * sizeof (DWRITE_SHAPING_GLYPH_PROPERTIES));
+
+  hr = analyzer->GetGlyphs (textString, textLength, fontFace, FALSE,
+    isRightToLeft, &runHead->mScript, localeName, NULL, &dwFeatures,
+    featureRangeLengths, 1, maxGlyphCount, clusterMap, textProperties, glyphIndices,
+    glyphProperties, &glyphCount);
+
+  if (unlikely (hr == HRESULT_FROM_WIN32 (ERROR_INSUFFICIENT_BUFFER)))
+  {
+    free (clusterMap);
+    free (glyphIndices);
+    free (textProperties);
+    free (glyphProperties);
+
+    maxGlyphCount *= 2;
+
+    goto retry_getglyphs;
+  }
+  if (FAILED (hr))
+  {
+    FAIL ("Analyzer failed to get glyphs.");
     return false;
   }
 
-  UINT32 maxGlyphs = 3 * length / 2 + 16;
+  float* glyphAdvances = (float*) malloc (maxGlyphCount * sizeof (float));
+  DWRITE_GLYPH_OFFSET* glyphOffsets = (DWRITE_GLYPH_OFFSET*)
+    malloc(maxGlyphCount * sizeof (DWRITE_GLYPH_OFFSET));
 
-#define INITIAL_GLYPH_SIZE 400
-  UINT16* clusters = (UINT16*)malloc(INITIAL_GLYPH_SIZE * sizeof(UINT16));
-  UINT16* glyphs = (UINT16*)malloc(INITIAL_GLYPH_SIZE * sizeof(UINT16));
-  DWRITE_SHAPING_TEXT_PROPERTIES* textProperties = (DWRITE_SHAPING_TEXT_PROPERTIES*)
-    malloc(INITIAL_GLYPH_SIZE * sizeof(DWRITE_SHAPING_TEXT_PROPERTIES));
-  DWRITE_SHAPING_GLYPH_PROPERTIES* glyphProperties = (DWRITE_SHAPING_GLYPH_PROPERTIES*)
-    malloc(INITIAL_GLYPH_SIZE * sizeof(DWRITE_SHAPING_GLYPH_PROPERTIES));
+  /* The -2 in the following is to compensate for possible
+   * alignment needed after the WORD array.  sizeof(WORD) == 2. */
+  unsigned int glyphs_size = (scratch_size * sizeof(int) - 2)
+         / (sizeof(WORD) +
+            sizeof(DWRITE_SHAPING_GLYPH_PROPERTIES) +
+            sizeof(int) +
+            sizeof(DWRITE_GLYPH_OFFSET) +
+            sizeof(uint32_t));
+  ALLOCATE_ARRAY (uint32_t, vis_clusters, glyphs_size);
+
+#undef ALLOCATE_ARRAY
 
-  UINT32 actualGlyphs;
-
-  bool backward = HB_DIRECTION_IS_BACKWARD(buffer->props.direction);
+  int fontEmSize = font->face->get_upem();
+  if (fontEmSize < 0)
+    fontEmSize = -fontEmSize;
 
-  wchar_t lang[4];
-  mbstowcs(lang, hb_language_to_string(buffer->props.language), 4);
-  hr = analyzer->GetGlyphs(pchars, length,
-    fontFace, FALSE,
-    buffer->props.direction,
-    &runHead->mScript, (const wchar_t*)lang, NULL, NULL, NULL, 0,
-    maxGlyphs, clusters, textProperties,
-    glyphs, glyphProperties, &actualGlyphs);
+  if (fontEmSize < 0)
+    fontEmSize = -fontEmSize;
+  double x_mult = (double) font->x_scale / fontEmSize;
+  double y_mult = (double) font->y_scale / fontEmSize;
+
+  hr = analyzer->GetGlyphPlacements (textString,
+    clusterMap, textProperties, textLength, glyphIndices,
+    glyphProperties, glyphCount, fontFace, fontEmSize,
+    FALSE, isRightToLeft, &runHead->mScript, localeName,
+    &dwFeatures, featureRangeLengths, 1,
+    glyphAdvances, glyphOffsets);
 
-  if (hr == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) {
-    free(clusters);
-    free(glyphs);
-    free(textProperties);
-    free(glyphProperties);
+  if (FAILED (hr))
+  {
+    FAIL ("Analyzer failed to get glyph placements.");
+    return false;
+  }
+
+#ifdef HB_DIRECTWRITE_EXPERIMENTAL_JUSTIFICATION
+
+  DWRITE_JUSTIFICATION_OPPORTUNITY* justificationOpportunities =
+    (DWRITE_JUSTIFICATION_OPPORTUNITY*)
+    malloc (maxGlyphCount * sizeof (DWRITE_JUSTIFICATION_OPPORTUNITY));
+  hr = analyzer->GetJustificationOpportunities (fontFace, fontEmSize,
+    runHead->mScript, textLength, glyphCount, textString, clusterMap,
+    glyphProperties, justificationOpportunities);
 
-    clusters = (UINT16*)malloc(INITIAL_GLYPH_SIZE * sizeof(UINT16));
-    glyphs = (UINT16*)malloc(INITIAL_GLYPH_SIZE * sizeof(UINT16));
-    textProperties = (DWRITE_SHAPING_TEXT_PROPERTIES*)
-      malloc(INITIAL_GLYPH_SIZE * sizeof(DWRITE_SHAPING_TEXT_PROPERTIES));
-    glyphProperties = (DWRITE_SHAPING_GLYPH_PROPERTIES*)
-      malloc(INITIAL_GLYPH_SIZE * sizeof(DWRITE_SHAPING_GLYPH_PROPERTIES));
+  if (FAILED (hr))
+  {
+    FAIL ("Analyzer failed to get justification opportunities.");
+    return false;
+  }
+
+  // TODO: get lineWith from somewhere
+  float lineWidth = 60000;
 
-    hr = analyzer->GetGlyphs(pchars, length,
-      fontFace, FALSE,
-      buffer->props.direction,
-      &runHead->mScript, (const wchar_t*)lang, NULL, NULL, NULL, 0,
-      maxGlyphs, clusters, textProperties,
-      glyphs, glyphProperties, &actualGlyphs);
-  }
-  if (FAILED(hr)) {
-    //NS_WARNING("Analyzer failed to get glyphs.");
+  float* justifiedGlyphAdvances =
+    (float*) malloc (maxGlyphCount * sizeof (float));
+  DWRITE_GLYPH_OFFSET* justifiedGlyphOffsets = (DWRITE_GLYPH_OFFSET*)
+    malloc (glyphCount * sizeof (DWRITE_GLYPH_OFFSET));
+  hr = analyzer->JustifyGlyphAdvances (lineWidth, glyphCount, justificationOpportunities,
+    glyphAdvances, glyphOffsets, justifiedGlyphAdvances, justifiedGlyphOffsets);
+
+  if (FAILED (hr))
+  {
+    FAIL ("Analyzer failed to get justified glyph advances.");
     return false;
   }
 
-  FLOAT advances[400];
-  DWRITE_GLYPH_OFFSET offsets[400];
-
-
-  /* The -2 in the following is to compensate for possible
-   * alignment needed after the WORD array.  sizeof(WORD) == 2. */
-  unsigned int glyphs_size = (scratch_size * sizeof (int)-2)
-    / (sizeof (WORD) +
-    4 + // sizeof (SCRIPT_GLYPHPROP) +
-    sizeof (int) +
-    8 + // sizeof (GOFFSET) +
-    sizeof (uint32_t));
-  ALLOCATE_ARRAY(uint32_t, vis_clusters, glyphs_size);
-
-#undef ALLOCATE_ARRAY
-
-  hr = analyzer->GetGlyphPlacements(pchars,
-    clusters,
-    textProperties,
-    length,
-    glyphs,
-    glyphProperties,
-    actualGlyphs,
-    fontFace,
-    face->get_upem(),
-    FALSE,
-    FALSE,
-    &runHead->mScript,
-    NULL,
-    NULL,
-    NULL,
-    0,
-    advances,
-    offsets);
-
-  if (FAILED(hr)) {
-    //NS_WARNING("Analyzer failed to get glyph placements.");
+  DWRITE_SCRIPT_PROPERTIES scriptProperties;
+  hr = analyzer->GetScriptProperties (runHead->mScript, &scriptProperties);
+  if (FAILED (hr))
+  {
+    FAIL ("Analyzer failed to get script properties.");
     return false;
   }
+  uint32_t justificationCharacter = scriptProperties.justificationCharacter;
 
-  unsigned int glyphs_len = actualGlyphs;
+  // if a script justificationCharacter is not space, it can have GetJustifiedGlyphs
+  if (justificationCharacter != 32)
+  {
+retry_getjustifiedglyphs:
+    uint16_t* modifiedClusterMap = (uint16_t*) malloc (maxGlyphCount * sizeof (uint16_t));
+    uint16_t* modifiedGlyphIndices = (uint16_t*) malloc (maxGlyphCount * sizeof (uint16_t));
+    float* modifiedGlyphAdvances = (float*) malloc (maxGlyphCount * sizeof (float));
+    DWRITE_GLYPH_OFFSET* modifiedGlyphOffsets = (DWRITE_GLYPH_OFFSET*)
+      malloc (maxGlyphCount * sizeof (DWRITE_GLYPH_OFFSET));
+    uint32_t actualGlyphsCount;
+    hr = analyzer->GetJustifiedGlyphs (fontFace, fontEmSize, runHead->mScript,
+        textLength, glyphCount, maxGlyphCount, clusterMap, glyphIndices,
+        glyphAdvances, justifiedGlyphAdvances, justifiedGlyphOffsets,
+        glyphProperties, &actualGlyphsCount, modifiedClusterMap, modifiedGlyphIndices,
+        modifiedGlyphAdvances, modifiedGlyphOffsets);
+
+    if (hr == HRESULT_FROM_WIN32 (ERROR_INSUFFICIENT_BUFFER))
+    {
+      maxGlyphCount = actualGlyphsCount;
+      free (modifiedClusterMap);
+      free (modifiedGlyphIndices);
+      free (modifiedGlyphAdvances);
+      free (modifiedGlyphOffsets);
+
+      maxGlyphCount = actualGlyphsCount;
+
+      goto retry_getjustifiedglyphs;
+    }
+    if (FAILED (hr))
+    {
+      FAIL ("Analyzer failed to get justified glyphs.");
+      return false;
+    }
+
+    free (clusterMap);
+    free (glyphIndices);
+    free (glyphAdvances);
+    free (glyphOffsets);
+
+    glyphCount = actualGlyphsCount;
+    clusterMap = modifiedClusterMap;
+    glyphIndices = modifiedGlyphIndices;
+    glyphAdvances = modifiedGlyphAdvances;
+    glyphOffsets = modifiedGlyphOffsets;
+
+    free(justifiedGlyphAdvances);
+    free(justifiedGlyphOffsets);
+  }
+  else
+  {
+    free(glyphAdvances);
+    free(glyphOffsets);
+
+    glyphAdvances = justifiedGlyphAdvances;
+    glyphOffsets = justifiedGlyphOffsets;
+  }
+
+  free(justificationOpportunities);
+
+#endif
 
   /* Ok, we've got everything we need, now compose output buffer,
    * very, *very*, carefully! */
 
   /* Calculate visual-clusters.  That's what we ship. */
-  for (unsigned int i = 0; i < glyphs_len; i++)
+  for (unsigned int i = 0; i < glyphCount; i++)
     vis_clusters[i] = -1;
-  for (unsigned int i = 0; i < buffer->len; i++) {
-    uint32_t *p = &vis_clusters[log_clusters[buffer->info[i].utf16_index()]];
-    //*p = MIN (*p, buffer->info[i].cluster);
+  for (unsigned int i = 0; i < buffer->len; i++)
+  {
+    uint32_t *p =
+      &vis_clusters[log_clusters[buffer->info[i].utf16_index()]];
+    *p = MIN (*p, buffer->info[i].cluster);
   }
-  for (unsigned int i = 1; i < glyphs_len; i++)
+  for (unsigned int i = 1; i < glyphCount; i++)
     if (vis_clusters[i] == -1)
       vis_clusters[i] = vis_clusters[i - 1];
 
 #undef utf16_index
 
-  //if (unlikely (!buffer->ensure (glyphs_len)))
-  //  FAIL ("Buffer in error");
+  if (unlikely (!buffer->ensure (glyphCount)))
+    FAIL ("Buffer in error");
 
 #undef FAIL
 
   /* Set glyph infos */
   buffer->len = 0;
-  for (unsigned int i = 0; i < glyphs_len; i++)
+  for (unsigned int i = 0; i < glyphCount; i++)
   {
     hb_glyph_info_t *info = &buffer->info[buffer->len++];
 
-    info->codepoint = glyphs[i];
+    info->codepoint = glyphIndices[i];
     info->cluster = vis_clusters[i];
 
     /* The rest is crap.  Let's store position info there for now. */
-    info->mask = advances[i];
-    info->var1.u32 = offsets[i].ascenderOffset;
-    info->var2.u32 = -offsets[i].advanceOffset;
+    info->mask = glyphAdvances[i];
+    info->var1.i32 = glyphOffsets[i].advanceOffset;
+    info->var2.i32 = glyphOffsets[i].ascenderOffset;
   }
 
-  free(clusters);
-  free(glyphs);
-  free(textProperties);
-  free(glyphProperties);
-
   /* Set glyph positions */
   buffer->clear_positions ();
-  for (unsigned int i = 0; i < glyphs_len; i++)
+  for (unsigned int i = 0; i < glyphCount; i++)
   {
     hb_glyph_info_t *info = &buffer->info[i];
     hb_glyph_position_t *pos = &buffer->pos[i];
 
     /* TODO vertical */
-    pos->x_advance = info->mask;
-    pos->x_offset = backward ? -info->var1.u32 : info->var1.u32;
-    pos->y_offset = info->var2.u32;
+    pos->x_advance = x_mult * (int32_t) info->mask;
+    pos->x_offset =
+      x_mult * (isRightToLeft ? -info->var1.i32 : info->var1.i32);
+    pos->y_offset = y_mult * info->var2.i32;
   }
 
-  if (backward)
+  if (isRightToLeft)
     hb_buffer_reverse (buffer);
 
+  free (clusterMap);
+  free (glyphIndices);
+  free (textProperties);
+  free (glyphProperties);
+  free (glyphAdvances);
+  free (glyphOffsets);
+
+  if (num_features)
+    free (singleFeatures.features);
+
   /* Wow, done! */
   return true;
 }
--- a/gfx/harfbuzz/src/hb-fallback-shape.cc
+++ b/gfx/harfbuzz/src/hb-fallback-shape.cc
@@ -101,34 +101,34 @@ hb_bool_t
    * - Handle Variation Selectors?
    * - Apply normalization?
    *
    * This will make the fallback shaper into a dumb "TrueType"
    * shaper which many people unfortunately still request.
    */
 
   hb_codepoint_t space;
-  bool has_space = (bool) font->get_glyph (' ', 0, &space);
+  bool has_space = (bool) font->get_nominal_glyph (' ', &space);
 
   buffer->clear_positions ();
 
   hb_direction_t direction = buffer->props.direction;
   hb_unicode_funcs_t *unicode = buffer->unicode;
   unsigned int count = buffer->len;
   hb_glyph_info_t *info = buffer->info;
   hb_glyph_position_t *pos = buffer->pos;
   for (unsigned int i = 0; i < count; i++)
   {
     if (has_space && unicode->is_default_ignorable (info[i].codepoint)) {
       info[i].codepoint = space;
       pos[i].x_advance = 0;
       pos[i].y_advance = 0;
       continue;
     }
-    font->get_glyph (info[i].codepoint, 0, &info[i].codepoint);
+    font->get_nominal_glyph (info[i].codepoint, &info[i].codepoint);
     font->get_glyph_advance_for_direction (info[i].codepoint,
 					   direction,
 					   &pos[i].x_advance,
 					   &pos[i].y_advance);
     font->subtract_glyph_origin_for_direction (info[i].codepoint,
 					       direction,
 					       &pos[i].x_offset,
 					       &pos[i].y_offset);
--- a/gfx/harfbuzz/src/hb-font-private.hh
+++ b/gfx/harfbuzz/src/hb-font-private.hh
@@ -39,17 +39,18 @@
 
 /*
  * hb_font_funcs_t
  */
 
 #define HB_FONT_FUNCS_IMPLEMENT_CALLBACKS \
   HB_FONT_FUNC_IMPLEMENT (font_h_extents) \
   HB_FONT_FUNC_IMPLEMENT (font_v_extents) \
-  HB_FONT_FUNC_IMPLEMENT (glyph) \
+  HB_FONT_FUNC_IMPLEMENT (nominal_glyph) \
+  HB_FONT_FUNC_IMPLEMENT (variation_glyph) \
   HB_FONT_FUNC_IMPLEMENT (glyph_h_advance) \
   HB_FONT_FUNC_IMPLEMENT (glyph_v_advance) \
   HB_FONT_FUNC_IMPLEMENT (glyph_h_origin) \
   HB_FONT_FUNC_IMPLEMENT (glyph_v_origin) \
   HB_FONT_FUNC_IMPLEMENT (glyph_h_kerning) \
   HB_FONT_FUNC_IMPLEMENT (glyph_v_kerning) \
   HB_FONT_FUNC_IMPLEMENT (glyph_extents) \
   HB_FONT_FUNC_IMPLEMENT (glyph_contour_point) \
@@ -175,26 +176,35 @@ struct hb_font_t {
     return klass->get.f.font_v_extents (this, user_data,
 					extents,
 					klass->user_data.font_v_extents);
   }
 
   inline bool has_glyph (hb_codepoint_t unicode)
   {
     hb_codepoint_t glyph;
-    return get_glyph (unicode, 0, &glyph);
+    return get_nominal_glyph (unicode, &glyph);
   }
 
-  inline hb_bool_t get_glyph (hb_codepoint_t unicode, hb_codepoint_t variation_selector,
-			      hb_codepoint_t *glyph)
+  inline hb_bool_t get_nominal_glyph (hb_codepoint_t unicode,
+				      hb_codepoint_t *glyph)
   {
     *glyph = 0;
-    return klass->get.f.glyph (this, user_data,
-			       unicode, variation_selector, glyph,
-			       klass->user_data.glyph);
+    return klass->get.f.nominal_glyph (this, user_data,
+				       unicode, glyph,
+				       klass->user_data.nominal_glyph);
+  }
+
+  inline hb_bool_t get_variation_glyph (hb_codepoint_t unicode, hb_codepoint_t variation_selector,
+					hb_codepoint_t *glyph)
+  {
+    *glyph = 0;
+    return klass->get.f.variation_glyph (this, user_data,
+					 unicode, variation_selector, glyph,
+					 klass->user_data.variation_glyph);
   }
 
   inline hb_position_t get_glyph_h_advance (hb_codepoint_t glyph)
   {
     return klass->get.f.glyph_h_advance (this, user_data,
 					 glyph,
 					 klass->user_data.glyph_h_advance);
   }
@@ -482,17 +492,17 @@ struct hb_font_t {
       if (0 == strncmp (s, "gid", 3) &&
 	  hb_codepoint_parse (s + 3, len - 3, 10, glyph))
 	return true;
 
       /* uniUUUU and other Unicode character indices. */
       hb_codepoint_t unichar;
       if (0 == strncmp (s, "uni", 3) &&
 	  hb_codepoint_parse (s + 3, len - 3, 16, &unichar) &&
-	  get_glyph (unichar, 0, glyph))
+	  get_nominal_glyph (unichar, glyph))
 	return true;
     }
 
     return false;
   }
 
   private:
   inline hb_position_t em_scale (int16_t v, int scale) { return (hb_position_t) (v * (int64_t) scale / face->get_upem ()); }
--- a/gfx/harfbuzz/src/hb-font.cc
+++ b/gfx/harfbuzz/src/hb-font.cc
@@ -88,37 +88,58 @@ hb_font_get_font_v_extents_parent (hb_fo
     metrics->ascender = font->parent_scale_x_distance (metrics->ascender);
     metrics->descender = font->parent_scale_x_distance (metrics->descender);
     metrics->line_gap = font->parent_scale_x_distance (metrics->line_gap);
   }
   return ret;
 }
 
 static hb_bool_t
-hb_font_get_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 *glyph,
-		       void *user_data HB_UNUSED)
+hb_font_get_nominal_glyph_nil (hb_font_t *font HB_UNUSED,
+			       void *font_data HB_UNUSED,
+			       hb_codepoint_t unicode,
+			       hb_codepoint_t *glyph,
+			       void *user_data HB_UNUSED)
 {
   *glyph = 0;
   return false;
 }
 static hb_bool_t
-hb_font_get_glyph_parent (hb_font_t *font,
-			  void *font_data HB_UNUSED,
-			  hb_codepoint_t unicode,
-			  hb_codepoint_t variation_selector,
-			  hb_codepoint_t *glyph,
-			  void *user_data HB_UNUSED)
+hb_font_get_nominal_glyph_parent (hb_font_t *font,
+				  void *font_data HB_UNUSED,
+				  hb_codepoint_t unicode,
+				  hb_codepoint_t *glyph,
+				  void *user_data HB_UNUSED)
 {
-  return font->parent->get_glyph (unicode, variation_selector, glyph);
+  return font->parent->get_nominal_glyph (unicode, glyph);
 }
 
+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 *glyph,
+				 void *user_data HB_UNUSED)
+{
+  *glyph = 0;
+  return false;
+}
+static hb_bool_t
+hb_font_get_variation_glyph_parent (hb_font_t *font,
+				    void *font_data HB_UNUSED,
+				    hb_codepoint_t unicode,
+				    hb_codepoint_t variation_selector,
+				    hb_codepoint_t *glyph,
+				    void *user_data HB_UNUSED)
+{
+  return font->parent->get_variation_glyph (unicode, variation_selector, glyph);
+}
+
+
 static hb_position_t
 hb_font_get_glyph_h_advance_nil (hb_font_t *font HB_UNUSED,
 				 void *font_data HB_UNUSED,
 				 hb_codepoint_t glyph,
 				 void *user_data HB_UNUSED)
 {
   return font->x_scale;
 }
@@ -617,17 +638,60 @@ hb_font_get_v_extents (hb_font_t *font,
  *
  * Since: 0.9.2
  **/
 hb_bool_t
 hb_font_get_glyph (hb_font_t *font,
 		   hb_codepoint_t unicode, hb_codepoint_t variation_selector,
 		   hb_codepoint_t *glyph)
 {
-  return font->get_glyph (unicode, variation_selector, glyph);
+  if (unlikely (variation_selector))
+    return font->get_variation_glyph (unicode, variation_selector, glyph);
+  return font->get_nominal_glyph (unicode, glyph);
+}
+
+/**
+ * hb_font_get_nominal_glyph:
+ * @font: a font.
+ * @unicode: 
+ * @glyph: (out): 
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.2.3
+ **/
+hb_bool_t
+hb_font_get_nominal_glyph (hb_font_t *font,
+			   hb_codepoint_t unicode,
+			   hb_codepoint_t *glyph)
+{
+  return font->get_nominal_glyph (unicode, glyph);
+}
+
+/**
+ * hb_font_get_variation_glyph:
+ * @font: a font.
+ * @unicode: 
+ * @variation_selector: 
+ * @glyph: (out): 
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.2.3
+ **/
+hb_bool_t
+hb_font_get_variation_glyph (hb_font_t *font,
+			     hb_codepoint_t unicode, hb_codepoint_t variation_selector,
+			     hb_codepoint_t *glyph)
+{
+  return font->get_variation_glyph (unicode, variation_selector, glyph);
 }
 
 /**
  * hb_font_get_glyph_h_advance:
  * @font: a font.
  * @glyph: 
  *
  * 
@@ -1467,8 +1531,136 @@ hb_font_set_ppem (hb_font_t *font,
 void
 hb_font_get_ppem (hb_font_t *font,
 		  unsigned int *x_ppem,
 		  unsigned int *y_ppem)
 {
   if (x_ppem) *x_ppem = font->x_ppem;
   if (y_ppem) *y_ppem = font->y_ppem;
 }
+
+
+#ifndef HB_DISABLE_DEPRECATED
+
+/*
+ * Deprecated get_glyph_func():
+ */
+
+struct hb_trampoline_closure_t
+{
+  void *user_data;
+  hb_destroy_func_t destroy;
+  unsigned int ref_count;
+};
+
+template <typename FuncType>
+struct hb_trampoline_t
+{
+  hb_trampoline_closure_t closure; /* Must be first. */
+  FuncType func;
+};
+
+template <typename FuncType>
+static hb_trampoline_t<FuncType> *
+trampoline_create (FuncType           func,
+		   void              *user_data,
+		   hb_destroy_func_t  destroy)
+{
+  typedef hb_trampoline_t<FuncType> trampoline_t;
+
+  trampoline_t *trampoline = (trampoline_t *) calloc (1, sizeof (trampoline_t));
+
+  if (unlikely (!trampoline))
+    return NULL;
+
+  trampoline->closure.user_data = user_data;
+  trampoline->closure.destroy = destroy;
+  trampoline->closure.ref_count = 1;
+  trampoline->func = func;
+
+  return trampoline;
+}
+
+static void
+trampoline_reference (hb_trampoline_closure_t *closure)
+{
+  closure->ref_count++;
+}
+
+static void
+trampoline_destroy (void *user_data)
+{
+  hb_trampoline_closure_t *closure = (hb_trampoline_closure_t *) user_data;
+
+  if (--closure->ref_count)
+    return;
+
+  if (closure->destroy)
+    closure->destroy (closure->user_data);
+  free (closure);
+}
+
+typedef hb_trampoline_t<hb_font_get_glyph_func_t> hb_font_get_glyph_trampoline_t;
+
+static hb_bool_t
+hb_font_get_nominal_glyph_trampoline (hb_font_t *font,
+				      void *font_data,
+				      hb_codepoint_t unicode,
+				      hb_codepoint_t *glyph,
+				      void *user_data)
+{
+  hb_font_get_glyph_trampoline_t *trampoline = (hb_font_get_glyph_trampoline_t *) user_data;
+  return trampoline->func (font, font_data, unicode, 0, glyph, trampoline->closure.user_data);
+}
+
+static hb_bool_t
+hb_font_get_variation_glyph_trampoline (hb_font_t *font,
+					void *font_data,
+					hb_codepoint_t unicode,
+					hb_codepoint_t variation_selector,
+					hb_codepoint_t *glyph,
+					void *user_data)
+{
+  hb_font_get_glyph_trampoline_t *trampoline = (hb_font_get_glyph_trampoline_t *) user_data;
+  return trampoline->func (font, font_data, unicode, variation_selector, glyph, trampoline->closure.user_data);
+}
+
+/**
+ * hb_font_funcs_set_glyph_func:
+ * @ffuncs: font functions.
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ * Deprecated.  Use hb_font_funcs_set_nominal_glyph_func() and
+ * hb_font_funcs_set_variation_glyph_func() instead.
+ *
+ * Since: 0.9.2
+ * Deprecated: 1.2.3
+ **/
+void
+hb_font_funcs_set_glyph_func (hb_font_funcs_t *ffuncs,
+			      hb_font_get_glyph_func_t func,
+			      void *user_data, hb_destroy_func_t destroy)
+{
+  hb_font_get_glyph_trampoline_t *trampoline;
+
+  trampoline = trampoline_create (func, user_data, destroy);
+  if (unlikely (!trampoline))
+  {
+    if (destroy)
+      destroy (user_data);
+    return;
+  }
+
+  hb_font_funcs_set_nominal_glyph_func (ffuncs,
+					hb_font_get_nominal_glyph_trampoline,
+					trampoline,
+					trampoline_destroy);
+
+  trampoline_reference (&trampoline->closure);
+  hb_font_funcs_set_variation_glyph_func (ffuncs,
+					  hb_font_get_variation_glyph_trampoline,
+					  trampoline,
+					  trampoline_destroy);
+}
+
+#endif /* HB_DISABLE_DEPRECATED */
--- a/gfx/harfbuzz/src/hb-font.h
+++ b/gfx/harfbuzz/src/hb-font.h
@@ -111,20 +111,24 @@ typedef struct hb_glyph_extents_t
 
 typedef hb_bool_t (*hb_font_get_font_extents_func_t) (hb_font_t *font, void *font_data,
 						       hb_font_extents_t *metrics,
 						       void *user_data);
 typedef hb_font_get_font_extents_func_t hb_font_get_font_h_extents_func_t;
 typedef hb_font_get_font_extents_func_t hb_font_get_font_v_extents_func_t;
 
 
-typedef hb_bool_t (*hb_font_get_glyph_func_t) (hb_font_t *font, void *font_data,
-					       hb_codepoint_t unicode, hb_codepoint_t variation_selector,
-					       hb_codepoint_t *glyph,
-					       void *user_data);
+typedef hb_bool_t (*hb_font_get_nominal_glyph_func_t) (hb_font_t *font, void *font_data,
+						       hb_codepoint_t unicode,
+						       hb_codepoint_t *glyph,
+						       void *user_data);
+typedef hb_bool_t (*hb_font_get_variation_glyph_func_t) (hb_font_t *font, void *font_data,
+							 hb_codepoint_t unicode, hb_codepoint_t variation_selector,
+							 hb_codepoint_t *glyph,
+							 void *user_data);
 
 
 typedef hb_position_t (*hb_font_get_glyph_advance_func_t) (hb_font_t *font, void *font_data,
 							   hb_codepoint_t glyph,
 							   void *user_data);
 typedef hb_font_get_glyph_advance_func_t hb_font_get_glyph_h_advance_func_t;
 typedef hb_font_get_glyph_advance_func_t hb_font_get_glyph_v_advance_func_t;
 
@@ -192,30 +196,46 @@ hb_font_funcs_set_font_h_extents_func (h
  * Since: 1.1.2
  **/
 HB_EXTERN void
 hb_font_funcs_set_font_v_extents_func (hb_font_funcs_t *ffuncs,
 				       hb_font_get_font_v_extents_func_t func,
 				       void *user_data, hb_destroy_func_t destroy);
 
 /**
- * hb_font_funcs_set_glyph_func:
+ * hb_font_funcs_set_nominal_glyph_func:
  * @ffuncs: font functions.
  * @func: (closure user_data) (destroy destroy) (scope notified):
  * @user_data:
  * @destroy:
  *
  * 
  *
- * Since: 0.9.2
+ * Since: 1.2.3
  **/
 HB_EXTERN void
-hb_font_funcs_set_glyph_func (hb_font_funcs_t *ffuncs,
-			      hb_font_get_glyph_func_t func,
-			      void *user_data, hb_destroy_func_t destroy);
+hb_font_funcs_set_nominal_glyph_func (hb_font_funcs_t *ffuncs,
+				      hb_font_get_nominal_glyph_func_t func,
+				      void *user_data, hb_destroy_func_t destroy);
+
+/**
+ * hb_font_funcs_set_variation_glyph_func:
+ * @ffuncs: font functions.
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ * 
+ *
+ * Since: 1.2.3
+ **/
+HB_EXTERN void
+hb_font_funcs_set_variation_glyph_func (hb_font_funcs_t *ffuncs,
+					hb_font_get_variation_glyph_func_t func,
+					void *user_data, hb_destroy_func_t destroy);
 
 /**
  * hb_font_funcs_set_glyph_h_advance_func:
  * @ffuncs: font functions.
  * @func: (closure user_data) (destroy destroy) (scope notified):
  * @user_data:
  * @destroy:
  *
@@ -377,19 +397,23 @@ hb_font_funcs_set_glyph_from_name_func (
 HB_EXTERN hb_bool_t
 hb_font_get_h_extents (hb_font_t *font,
 		       hb_font_extents_t *extents);
 HB_EXTERN hb_bool_t
 hb_font_get_v_extents (hb_font_t *font,
 		       hb_font_extents_t *extents);
 
 HB_EXTERN hb_bool_t
-hb_font_get_glyph (hb_font_t *font,
-		   hb_codepoint_t unicode, hb_codepoint_t variation_selector,
-		   hb_codepoint_t *glyph);
+hb_font_get_nominal_glyph (hb_font_t *font,
+			   hb_codepoint_t unicode,
+			   hb_codepoint_t *glyph);
+HB_EXTERN hb_bool_t
+hb_font_get_variation_glyph (hb_font_t *font,
+			     hb_codepoint_t unicode, hb_codepoint_t variation_selector,
+			     hb_codepoint_t *glyph);
 
 HB_EXTERN hb_position_t
 hb_font_get_glyph_h_advance (hb_font_t *font,
 			     hb_codepoint_t glyph);
 HB_EXTERN hb_position_t
 hb_font_get_glyph_v_advance (hb_font_t *font,
 			     hb_codepoint_t glyph);
 
@@ -426,16 +450,23 @@ hb_font_get_glyph_name (hb_font_t *font,
 HB_EXTERN hb_bool_t
 hb_font_get_glyph_from_name (hb_font_t *font,
 			     const char *name, int len, /* -1 means nul-terminated */
 			     hb_codepoint_t *glyph);
 
 
 /* high-level funcs, with fallback */
 
+/* Calls either hb_font_get_nominal_glyph() if variation_selector is 0,
+ * otherwise callse hb_font_get_variation_glyph(). */
+HB_EXTERN hb_bool_t
+hb_font_get_glyph (hb_font_t *font,
+		   hb_codepoint_t unicode, hb_codepoint_t variation_selector,
+		   hb_codepoint_t *glyph);
+
 HB_EXTERN void
 hb_font_get_extents_for_direction (hb_font_t *font,
 				   hb_direction_t direction,
 				   hb_font_extents_t *extents);
 HB_EXTERN void
 hb_font_get_glyph_advance_for_direction (hb_font_t *font,
 					 hb_codepoint_t glyph,
 					 hb_direction_t direction,
--- a/gfx/harfbuzz/src/hb-ft.cc
+++ b/gfx/harfbuzz/src/hb-ft.cc
@@ -150,31 +150,42 @@ hb_ft_font_get_face (hb_font_t *font)
   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font->user_data;
 
   return ft_font->ft_face;
 }
 
 
 
 static hb_bool_t
-hb_ft_get_glyph (hb_font_t *font HB_UNUSED,
-		 void *font_data,
-		 hb_codepoint_t unicode,
-		 hb_codepoint_t variation_selector,
-		 hb_codepoint_t *glyph,
-		 void *user_data HB_UNUSED)
-
+hb_ft_get_nominal_glyph (hb_font_t *font HB_UNUSED,
+			 void *font_data,
+			 hb_codepoint_t unicode,
+			 hb_codepoint_t *glyph,
+			 void *user_data HB_UNUSED)
 {
   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
-  unsigned int g;
+  unsigned int g = FT_Get_Char_Index (ft_font->ft_face, unicode);
+
+  if (unlikely (!g))
+    return false;
+
+  *glyph = g;
+  return true;
+}
 
-  if (likely (!variation_selector))
-    g = FT_Get_Char_Index (ft_font->ft_face, unicode);
-  else
-    g = FT_Face_GetCharVariantIndex (ft_font->ft_face, unicode, variation_selector);
+static hb_bool_t
+hb_ft_get_variation_glyph (hb_font_t *font HB_UNUSED,
+			   void *font_data,
+			   hb_codepoint_t unicode,
+			   hb_codepoint_t variation_selector,
+			   hb_codepoint_t *glyph,
+			   void *user_data HB_UNUSED)
+{
+  const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
+  unsigned int g = FT_Face_GetCharVariantIndex (ft_font->ft_face, unicode, variation_selector);
 
   if (unlikely (!g))
     return false;
 
   *glyph = g;
   return true;
 }
 
@@ -403,17 +414,18 @@ retry:
   hb_font_funcs_t *funcs = (hb_font_funcs_t *) hb_atomic_ptr_get (&static_ft_funcs);
 
   if (unlikely (!funcs))
   {
     funcs = hb_font_funcs_create ();
 
     hb_font_funcs_set_font_h_extents_func (funcs, hb_ft_get_font_h_extents, NULL, NULL);
     //hb_font_funcs_set_font_v_extents_func (funcs, hb_ft_get_font_v_extents, NULL, NULL);
-    hb_font_funcs_set_glyph_func (funcs, hb_ft_get_glyph, NULL, NULL);
+    hb_font_funcs_set_nominal_glyph_func (funcs, hb_ft_get_nominal_glyph, NULL, NULL);
+    hb_font_funcs_set_variation_glyph_func (funcs, hb_ft_get_variation_glyph, NULL, NULL);
     hb_font_funcs_set_glyph_h_advance_func (funcs, hb_ft_get_glyph_h_advance, NULL, NULL);
     hb_font_funcs_set_glyph_v_advance_func (funcs, hb_ft_get_glyph_v_advance, NULL, NULL);
     //hb_font_funcs_set_glyph_h_origin_func (funcs, hb_ft_get_glyph_h_origin, NULL, NULL);
     hb_font_funcs_set_glyph_v_origin_func (funcs, hb_ft_get_glyph_v_origin, NULL, NULL);
     hb_font_funcs_set_glyph_h_kerning_func (funcs, hb_ft_get_glyph_h_kerning, NULL, NULL);
     //hb_font_funcs_set_glyph_v_kerning_func (funcs, hb_ft_get_glyph_v_kerning, NULL, NULL);
     hb_font_funcs_set_glyph_extents_func (funcs, hb_ft_get_glyph_extents, NULL, NULL);
     hb_font_funcs_set_glyph_contour_point_func (funcs, hb_ft_get_glyph_contour_point, NULL, NULL);
--- a/gfx/harfbuzz/src/hb-icu.cc
+++ b/gfx/harfbuzz/src/hb-icu.cc
@@ -31,16 +31,17 @@
 
 #include "hb-icu.h"
 
 #include "hb-unicode-private.hh"
 
 #include <unicode/uchar.h>
 #include <unicode/unorm.h>
 #include <unicode/ustring.h>
+#include <unicode/utf16.h>
 #include <unicode/uversion.h>
 
 
 hb_script_t
 hb_icu_script_to_script (UScriptCode script)
 {
   if (unlikely (script == USCRIPT_INVALID_CODE))
     return HB_SCRIPT_INVALID;
--- a/gfx/harfbuzz/src/hb-open-type-private.hh
+++ b/gfx/harfbuzz/src/hb-open-type-private.hh
@@ -657,16 +657,25 @@ typedef IntType<int32_t,  4> LONG;	/* 32
 typedef IntType<uint32_t, 3> UINT24;	/* 24-bit unsigned integer. */
 
 /* 16-bit signed integer (SHORT) that describes a quantity in FUnits. */
 typedef SHORT FWORD;
 
 /* 16-bit unsigned integer (USHORT) that describes a quantity in FUnits. */
 typedef USHORT UFWORD;
 
+/* 16-bit signed fixed number with the low 14 bits of fraction (2.14). */
+struct F2DOT14 : SHORT
+{
+  //inline float to_float (void) const { return ???; }
+  //inline void set_float (float f) { v.set (f * ???); }
+  public:
+  DEFINE_SIZE_STATIC (2);
+};
+
 /* Date represented in number of seconds since 12:00 midnight, January 1,
  * 1904. The value is represented as a signed 64-bit integer. */
 struct LONGDATETIME
 {
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (likely (c->check_struct (this)));
--- a/gfx/harfbuzz/src/hb-ot-cmap-table.hh
+++ b/gfx/harfbuzz/src/hb-ot-cmap-table.hh
@@ -64,71 +64,88 @@ struct CmapSubtableFormat0
   BYTE		glyphIdArray[256];/* An array that maps character
 				 * code to glyph index values. */
   public:
   DEFINE_SIZE_STATIC (6 + 256);
 };
 
 struct CmapSubtableFormat4
 {
-  inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
+  struct accelerator_t
   {
-    unsigned int segCount;
+    inline void init (const CmapSubtableFormat4 *subtable)
+    {
+      segCount = subtable->segCountX2 / 2;
+      endCount = subtable->values;
+      startCount = endCount + segCount + 1;
+      idDelta = startCount + segCount;
+      idRangeOffset = idDelta + segCount;
+      glyphIdArray = idRangeOffset + segCount;
+      glyphIdArrayLength = (subtable->length - 16 - 8 * segCount) / 2;
+    }
+
+    static inline bool get_glyph_func (const void *obj, hb_codepoint_t codepoint, hb_codepoint_t *glyph)
+    {
+      const accelerator_t *thiz = (const accelerator_t *) obj;
+
+      /* Custom two-array bsearch. */
+      int min = 0, max = (int) thiz->segCount - 1;
+      const USHORT *startCount = thiz->startCount;
+      const USHORT *endCount = thiz->endCount;
+      unsigned int i;
+      while (min <= max)
+      {
+	int mid = (min + max) / 2;
+	if (codepoint < startCount[mid])
+	  max = mid - 1;
+	else if (codepoint > endCount[mid])
+	  min = mid + 1;
+	else
+	{
+	  i = mid;
+	  goto found;
+	}
+      }
+      return false;
+
+    found:
+      hb_codepoint_t gid;
+      unsigned int rangeOffset = thiz->idRangeOffset[i];
+      if (rangeOffset == 0)
+	gid = codepoint + thiz->idDelta[i];
+      else
+      {
+	/* Somebody has been smoking... */
+	unsigned int index = rangeOffset / 2 + (codepoint - thiz->startCount[i]) + i - thiz->segCount;
+	if (unlikely (index >= thiz->glyphIdArrayLength))
+	  return false;
+	gid = thiz->glyphIdArray[index];
+	if (unlikely (!gid))
+	  return false;
+	gid += thiz->idDelta[i];
+      }
+
+      *glyph = gid & 0xFFFFu;
+      return true;
+    }
+
     const USHORT *endCount;
     const USHORT *startCount;
     const USHORT *idDelta;
     const USHORT *idRangeOffset;
     const USHORT *glyphIdArray;
+    unsigned int segCount;
     unsigned int glyphIdArrayLength;
-
-    segCount = this->segCountX2 / 2;
-    endCount = this->values;
-    startCount = endCount + segCount + 1;
-    idDelta = startCount + segCount;
-    idRangeOffset = idDelta + segCount;
-    glyphIdArray = idRangeOffset + segCount;
-    glyphIdArrayLength = (this->length - 16 - 8 * segCount) / 2;
+  };
 
-    /* Custom two-array bsearch. */
-    int min = 0, max = (int) segCount - 1;
-    unsigned int i;
-    while (min <= max)
-    {
-      int mid = (min + max) / 2;
-      if (codepoint < startCount[mid])
-        max = mid - 1;
-      else if (codepoint > endCount[mid])
-        min = mid + 1;
-      else
-      {
-	i = mid;
-	goto found;
-      }
-    }
-    return false;
-
-  found:
-    hb_codepoint_t gid;
-    unsigned int rangeOffset = idRangeOffset[i];
-    if (rangeOffset == 0)
-      gid = codepoint + idDelta[i];
-    else
-    {
-      /* Somebody has been smoking... */
-      unsigned int index = rangeOffset / 2 + (codepoint - startCount[i]) + i - segCount;
-      if (unlikely (index >= glyphIdArrayLength))
-	return false;
-      gid = glyphIdArray[index];
-      if (unlikely (!gid))
-	return false;
-      gid += idDelta[i];
-    }
-
-    *glyph = gid & 0xFFFFu;
-    return true;
+  inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
+  {
+    accelerator_t accel;
+    accel.init (this);
+    return accel.get_glyph_func (&accel, codepoint, glyph);
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     if (unlikely (!c->check_struct (this)))
       return_trace (false);
 
@@ -383,17 +400,17 @@ struct CmapSubtableFormat14
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) &&
 		  record.sanitize (c, this));
   }
 
   protected:
-  USHORT	format;		/* Format number is set to 0. */
+  USHORT	format;		/* Format number is set to 14. */
   ULONG		lengthZ;	/* Byte length of this subtable. */
   SortedArrayOf<VariationSelectorRecord, ULONG>
 		record;		/* Variation selector records; sorted
 				 * in increasing order of `varSelector'. */
   public:
   DEFINE_SIZE_ARRAY (10, record);
 };
 
@@ -411,43 +428,33 @@ struct CmapSubtable
     case 10: return u.format10.get_glyph(codepoint, glyph);
     case 12: return u.format12.get_glyph(codepoint, glyph);
     case 13: return u.format13.get_glyph(codepoint, glyph);
     case 14:
     default: return false;
     }
   }
 
-  inline glyph_variant_t get_glyph_variant (hb_codepoint_t codepoint,
-					    hb_codepoint_t variation_selector,
-					    hb_codepoint_t *glyph) const
-  {
-    switch (u.format) {
-    case 14: return u.format14.get_glyph_variant(codepoint, variation_selector, glyph);
-    default: return GLYPH_VARIANT_NOT_FOUND;
-    }
-  }
-
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     if (!u.format.sanitize (c)) return_trace (false);
     switch (u.format) {
     case  0: return_trace (u.format0 .sanitize (c));
     case  4: return_trace (u.format4 .sanitize (c));
     case  6: return_trace (u.format6 .sanitize (c));
     case 10: return_trace (u.format10.sanitize (c));
     case 12: return_trace (u.format12.sanitize (c));
     case 13: return_trace (u.format13.sanitize (c));
     case 14: return_trace (u.format14.sanitize (c));
     default:return_trace (true);
     }
   }
 
-  protected:
+  public:
   union {
   USHORT		format;		/* Format identifier */
   CmapSubtableFormat0	format0;
   CmapSubtableFormat4	format4;
   CmapSubtableFormat6	format6;
   CmapSubtableFormat10	format10;
   CmapSubtableFormat12	format12;
   CmapSubtableFormat13	format13;
--- a/gfx/harfbuzz/src/hb-ot-font.cc
+++ b/gfx/harfbuzz/src/hb-ot-font.cc
@@ -196,74 +196,111 @@ struct hb_ot_face_glyf_accelerator_t
     extents->y_bearing = MAX (glyph_header.yMin, glyph_header.yMax);
     extents->width     = MAX (glyph_header.xMin, glyph_header.xMax) - extents->x_bearing;
     extents->height    = MIN (glyph_header.yMin, glyph_header.yMax) - extents->y_bearing;
 
     return true;
   }
 };
 
+typedef bool (*hb_cmap_get_glyph_func_t) (const void *obj,
+					  hb_codepoint_t codepoint,
+					  hb_codepoint_t *glyph);
+
+template <typename Type>
+static inline bool get_glyph_from (const void *obj,
+				   hb_codepoint_t codepoint,
+				   hb_codepoint_t *glyph)
+{
+  const Type *typed_obj = (const Type *) obj;
+  return typed_obj->get_glyph (codepoint, glyph);
+}
+
 struct hb_ot_face_cmap_accelerator_t
 {
-  const OT::CmapSubtable *table;
-  const OT::CmapSubtable *uvs_table;
+  hb_cmap_get_glyph_func_t get_glyph_func;
+  const void *get_glyph_data;
+  OT::CmapSubtableFormat4::accelerator_t format4_accel;
+
+  const OT::CmapSubtableFormat14 *uvs_table;
   hb_blob_t *blob;
 
   inline void init (hb_face_t *face)
   {
     this->blob = OT::Sanitizer<OT::cmap>::sanitize (face->reference_table (HB_OT_TAG_cmap));
     const OT::cmap *cmap = OT::Sanitizer<OT::cmap>::lock_instance (this->blob);
     const OT::CmapSubtable *subtable = NULL;
-    const OT::CmapSubtable *subtable_uvs = NULL;
+    const OT::CmapSubtableFormat14 *subtable_uvs = NULL;
 
     /* 32-bit subtables. */
     if (!subtable) subtable = cmap->find_subtable (3, 10);
     if (!subtable) subtable = cmap->find_subtable (0, 6);
     if (!subtable) subtable = cmap->find_subtable (0, 4);
     /* 16-bit subtables. */
     if (!subtable) subtable = cmap->find_subtable (3, 1);
     if (!subtable) subtable = cmap->find_subtable (0, 3);
     if (!subtable) subtable = cmap->find_subtable (0, 2);
     if (!subtable) subtable = cmap->find_subtable (0, 1);
     if (!subtable) subtable = cmap->find_subtable (0, 0);
     if (!subtable) subtable = cmap->find_subtable (3, 0);
     /* Meh. */
     if (!subtable) subtable = &OT::Null(OT::CmapSubtable);
 
     /* UVS subtable. */
-    if (!subtable_uvs) subtable_uvs = cmap->find_subtable (0, 5);
+    if (!subtable_uvs)
+    {
+      const OT::CmapSubtable *st = cmap->find_subtable (0, 5);
+      if (st && st->u.format == 14)
+        subtable_uvs = &st->u.format14;
+    }
     /* Meh. */
-    if (!subtable_uvs) subtable_uvs = &OT::Null(OT::CmapSubtable);
+    if (!subtable_uvs) subtable_uvs = &OT::Null(OT::CmapSubtableFormat14);
+
+    this->uvs_table = subtable_uvs;
 
-    this->table = subtable;
-    this->uvs_table = subtable_uvs;
+    this->get_glyph_data = subtable;
+    switch (subtable->u.format) {
+    /* Accelerate format 4 and format 12. */
+    default: this->get_glyph_func = get_glyph_from<OT::CmapSubtable>;		break;
+    case 12: this->get_glyph_func = get_glyph_from<OT::CmapSubtableFormat12>;	break;
+    case  4:
+      {
+        this->format4_accel.init (&subtable->u.format4);
+	this->get_glyph_data = &this->format4_accel;
+        this->get_glyph_func = this->format4_accel.get_glyph_func;
+      }
+      break;
+    }
   }
 
   inline void fini (void)
   {
     hb_blob_destroy (this->blob);
   }
 
-  inline bool get_glyph (hb_codepoint_t  unicode,
-			 hb_codepoint_t  variation_selector,
-			 hb_codepoint_t *glyph) const
+  inline bool get_nominal_glyph (hb_codepoint_t  unicode,
+				 hb_codepoint_t *glyph) const
   {
-    if (unlikely (variation_selector))
+    return this->get_glyph_func (this->get_glyph_data, unicode, glyph);
+  }
+
+  inline bool get_variation_glyph (hb_codepoint_t  unicode,
+				   hb_codepoint_t  variation_selector,
+				   hb_codepoint_t *glyph) const
+  {
+    switch (this->uvs_table->get_glyph_variant (unicode,
+						variation_selector,
+						glyph))
     {
-      switch (this->uvs_table->get_glyph_variant (unicode,
-						  variation_selector,
-						  glyph))
-      {
-	case OT::GLYPH_VARIANT_NOT_FOUND:	return false;
-	case OT::GLYPH_VARIANT_FOUND:		return true;
-	case OT::GLYPH_VARIANT_USE_DEFAULT:	break;
-      }
+      case OT::GLYPH_VARIANT_NOT_FOUND:		return false;
+      case OT::GLYPH_VARIANT_FOUND:		return true;
+      case OT::GLYPH_VARIANT_USE_DEFAULT:	break;
     }
 
-    return this->table->get_glyph (unicode, glyph);
+    return get_nominal_glyph (unicode, glyph);
   }
 };
 
 
 struct hb_ot_font_t
 {
   hb_ot_face_cmap_accelerator_t cmap;
   hb_ot_face_metrics_accelerator_t h_metrics;
@@ -296,26 +333,37 @@ static void
   ot_font->v_metrics.fini ();
   ot_font->glyf.fini ();
 
   free (ot_font);
 }
 
 
 static hb_bool_t
-hb_ot_get_glyph (hb_font_t *font HB_UNUSED,
-		 void *font_data,
-		 hb_codepoint_t unicode,
-		 hb_codepoint_t variation_selector,
-		 hb_codepoint_t *glyph,
-		 void *user_data HB_UNUSED)
+hb_ot_get_nominal_glyph (hb_font_t *font HB_UNUSED,
+			 void *font_data,
+			 hb_codepoint_t unicode,
+			 hb_codepoint_t *glyph,
+			 void *user_data HB_UNUSED)
 
 {
   const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
-  return ot_font->cmap.get_glyph (unicode, variation_selector, glyph);
+  return ot_font->cmap.get_nominal_glyph (unicode, glyph);
+}
+
+static hb_bool_t
+hb_ot_get_variation_glyph (hb_font_t *font HB_UNUSED,
+			   void *font_data,
+			   hb_codepoint_t unicode,
+			   hb_codepoint_t variation_selector,
+			   hb_codepoint_t *glyph,
+			   void *user_data HB_UNUSED)
+{
+  const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
+  return ot_font->cmap.get_variation_glyph (unicode, variation_selector, glyph);
 }
 
 static hb_position_t
 hb_ot_get_glyph_h_advance (hb_font_t *font HB_UNUSED,
 			   void *font_data,
 			   hb_codepoint_t glyph,
 			   void *user_data HB_UNUSED)
 {
@@ -392,17 +440,18 @@ retry:
   hb_font_funcs_t *funcs = (hb_font_funcs_t *) hb_atomic_ptr_get (&static_ot_funcs);
 
   if (unlikely (!funcs))
   {
     funcs = hb_font_funcs_create ();
 
     hb_font_funcs_set_font_h_extents_func (funcs, hb_ot_get_font_h_extents, NULL, NULL);
     hb_font_funcs_set_font_v_extents_func (funcs, hb_ot_get_font_v_extents, NULL, NULL);
-    hb_font_funcs_set_glyph_func (funcs, hb_ot_get_glyph, NULL, NULL);
+    hb_font_funcs_set_nominal_glyph_func (funcs, hb_ot_get_nominal_glyph, NULL, NULL);
+    hb_font_funcs_set_variation_glyph_func (funcs, hb_ot_get_variation_glyph, NULL, NULL);
     hb_font_funcs_set_glyph_h_advance_func (funcs, hb_ot_get_glyph_h_advance, NULL, NULL);
     hb_font_funcs_set_glyph_v_advance_func (funcs, hb_ot_get_glyph_v_advance, NULL, NULL);
     //hb_font_funcs_set_glyph_h_origin_func (funcs, hb_ot_get_glyph_h_origin, NULL, NULL);
     //hb_font_funcs_set_glyph_v_origin_func (funcs, hb_ot_get_glyph_v_origin, NULL, NULL);
     //hb_font_funcs_set_glyph_h_kerning_func (funcs, hb_ot_get_glyph_h_kerning, NULL, NULL); TODO
     //hb_font_funcs_set_glyph_v_kerning_func (funcs, hb_ot_get_glyph_v_kerning, NULL, NULL);
     hb_font_funcs_set_glyph_extents_func (funcs, hb_ot_get_glyph_extents, NULL, NULL);
     //hb_font_funcs_set_glyph_contour_point_func (funcs, hb_ot_get_glyph_contour_point, NULL, NULL); TODO
--- a/gfx/harfbuzz/src/hb-ot-glyf-table.hh
+++ b/gfx/harfbuzz/src/hb-ot-glyf-table.hh
@@ -85,20 +85,20 @@ struct glyf
 };
 
 struct glyfGlyphHeader
 {
   SHORT		numberOfContours;	/* If the number of contours is
 					 * greater than or equal to zero,
 					 * this is a simple glyph; if negative,
 					 * this is a composite glyph. */
-  SHORT		xMin;			/* Minimum x for coordinate data. */
-  SHORT		yMin;			/* Minimum y for coordinate data. */
-  SHORT		xMax;			/* Maximum x for coordinate data. */
-  SHORT		yMax;			/* Maximum y for coordinate data. */
+  FWORD		xMin;			/* Minimum x for coordinate data. */
+  FWORD		yMin;			/* Minimum y for coordinate data. */
+  FWORD		xMax;			/* Maximum x for coordinate data. */
+  FWORD		yMax;			/* Maximum y for coordinate data. */
 
   DEFINE_SIZE_STATIC (10);
 };
 
 } /* namespace OT */
 
 
 #endif /* HB_OT_GLYF_TABLE_HH */
--- a/gfx/harfbuzz/src/hb-ot-hmtx-table.hh
+++ b/gfx/harfbuzz/src/hb-ot-hmtx-table.hh
@@ -39,18 +39,18 @@ namespace OT {
  */
 
 #define HB_OT_TAG_hmtx HB_TAG('h','m','t','x')
 #define HB_OT_TAG_vmtx HB_TAG('v','m','t','x')
 
 
 struct LongMetric
 {
-  USHORT	advance; /* Advance width/height. */
-  SHORT		lsb; /* Leading (left/top) side bearing. */
+  UFWORD	advance; /* Advance width/height. */
+  FWORD		lsb; /* Leading (left/top) side bearing. */
   public:
   DEFINE_SIZE_STATIC (4);
 };
 
 struct _mtx
 {
   static const hb_tag_t tableTag = HB_TAG('_','m','t','x');
 
@@ -69,17 +69,17 @@ struct _mtx
   LongMetric	longMetric[VAR];	/* Paired advance width and leading
 					 * bearing values for each glyph. The
 					 * value numOfHMetrics comes from
 					 * the 'hhea' table. If the font is
 					 * monospaced, only one entry need
 					 * be in the array, but that entry is
 					 * required. The last entry applies to
 					 * all subsequent glyphs. */
-  SHORT		leadingBearingX[VAR];	/* Here the advance is assumed
+  FWORD		leadingBearingX[VAR];	/* Here the advance is assumed
 					 * to be the same as the advance
 					 * for the last entry above. The
 					 * number of entries in this array is
 					 * derived from numGlyphs (from 'maxp'
 					 * table) minus numberOfLongMetrics.
 					 * This generally is used with a run
 					 * of monospaced glyphs (e.g., Kanji
 					 * fonts or Courier fonts). Only one
--- a/gfx/harfbuzz/src/hb-ot-layout-gsub-table.hh
+++ b/gfx/harfbuzz/src/hb-ot-layout-gsub-table.hh
@@ -1283,20 +1283,38 @@ struct GSUB : GSUBGPOS
 
 void
 GSUB::substitute_start (hb_font_t *font, hb_buffer_t *buffer)
 {
   _hb_buffer_assert_gsubgpos_vars (buffer);
 
   const GDEF &gdef = *hb_ot_layout_from_face (font->face)->gdef;
   unsigned int count = buffer->len;
+  hb_glyph_info_t *info = buffer->info;
   for (unsigned int i = 0; i < count; i++)
   {
-    _hb_glyph_info_set_glyph_props (&buffer->info[i], gdef.get_glyph_props (buffer->info[i].codepoint));
-    _hb_glyph_info_clear_lig_props (&buffer->info[i]);
+    unsigned int props = gdef.get_glyph_props (info[i].codepoint);
+    if (!props)
+    {
+      /* Never mark default-ignorables as marks.
+       * They won't get in the way of lookups anyway,
+       * but having them as mark will cause them to be skipped
+       * over if the lookup-flag says so, but at least for the
+       * Mongolian variation selectors, looks like Uniscribe
+       * marks them as non-mark.  Some Mongolian fonts without
+       * GDEF rely on this.  Another notable character that
+       * this applies to is COMBINING GRAPHEME JOINER. */
+      props = (_hb_glyph_info_get_general_category (&info[i]) !=
+	       HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK ||
+	       _hb_glyph_info_is_default_ignorable (&info[i])) ?
+	      HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH :
+	      HB_OT_LAYOUT_GLYPH_PROPS_MARK;
+    }
+    _hb_glyph_info_set_glyph_props (&info[i], props);
+    _hb_glyph_info_clear_lig_props (&info[i]);
     buffer->info[i].syllable() = 0;
   }
 }
 
 
 /* Out-of-class implementation for methods recursing */
 
 /*static*/ inline bool ExtensionSubst::is_reverse (void) const
--- a/gfx/harfbuzz/src/hb-ot-layout.cc
+++ b/gfx/harfbuzz/src/hb-ot-layout.cc
@@ -55,16 +55,45 @@ hb_ot_layout_t *
   layout->gdef = OT::Sanitizer<OT::GDEF>::lock_instance (layout->gdef_blob);
 
   layout->gsub_blob = OT::Sanitizer<OT::GSUB>::sanitize (face->reference_table (HB_OT_TAG_GSUB));
   layout->gsub = OT::Sanitizer<OT::GSUB>::lock_instance (layout->gsub_blob);
 
   layout->gpos_blob = OT::Sanitizer<OT::GPOS>::sanitize (face->reference_table (HB_OT_TAG_GPOS));
   layout->gpos = OT::Sanitizer<OT::GPOS>::lock_instance (layout->gpos_blob);
 
+  {
+    /*
+     * The ugly business of blacklisting individual fonts' tables happen here!
+     * See this thread for why we finally had to bend in and do this:
+     * https://lists.freedesktop.org/archives/harfbuzz/2016-February/005489.html
+     */
+    unsigned int gdef_len = hb_blob_get_length (layout->gdef_blob);
+    unsigned int gsub_len = hb_blob_get_length (layout->gsub_blob);
+    unsigned int gpos_len = hb_blob_get_length (layout->gpos_blob);
+    if (0
+      || (442 == gdef_len && 42038 == gpos_len && 2874 == gsub_len) /* Windows 7 timesi.ttf */
+      || (430 == gdef_len && 40662 == gpos_len && 2874 == gsub_len) /* Windows 7 timesbi.ttf */
+      || (442 == gdef_len && 39116 == gpos_len && 2874 == gsub_len) /* Windows ??? timesi.ttf */
+      || (430 == gdef_len && 39374 == gpos_len && 2874 == gsub_len) /* Windows ??? timesbi.ttf */
+      || (490 == gdef_len && 41638 == gpos_len && 3046 == gsub_len) /* OS X 10.11.3 Times New Roman Italic.ttf */
+      || (478 == gdef_len && 41902 == gpos_len && 3046 == gsub_len) /* OS X 10.11.3 Times New Roman Bold Italic.ttf */
+    )
+    {
+      /* In certain versions of Times New Roman Italic and Bold Italic,
+       * ASCII double quotation mark U+0022, mapped to glyph 5, has wrong
+       * glyph class 3 (mark) in GDEF.  Nuke the GDEF to avoid zero-width
+       * double-quote.  See:
+       * https://lists.freedesktop.org/archives/harfbuzz/2016-February/005489.html
+       */
+     if (3 == layout->gdef->get_glyph_class (5))
+       layout->gdef = &OT::Null(OT::GDEF);
+    }
+  }
+
   layout->gsub_lookup_count = layout->gsub->get_lookup_count ();
   layout->gpos_lookup_count = layout->gpos->get_lookup_count ();
 
   layout->gsub_accels = (hb_ot_layout_lookup_accelerator_t *) calloc (layout->gsub->get_lookup_count (), sizeof (hb_ot_layout_lookup_accelerator_t));
   layout->gpos_accels = (hb_ot_layout_lookup_accelerator_t *) calloc (layout->gpos->get_lookup_count (), sizeof (hb_ot_layout_lookup_accelerator_t));
 
   if (unlikely ((layout->gsub_lookup_count && !layout->gsub_accels) ||
 		(layout->gpos_lookup_count && !layout->gpos_accels)))
--- a/gfx/harfbuzz/src/hb-ot-map.cc
+++ b/gfx/harfbuzz/src/hb-ot-map.cc
@@ -199,21 +199,18 @@ hb_ot_map_builder_t::compile (hb_ot_map_
       continue; /* Feature disabled, or not enough bits. */
 
 
     hb_bool_t found = false;
     unsigned int feature_index[2];
     for (unsigned int table_index = 0; table_index < 2; table_index++)
     {
       if (required_feature_tag[table_index] == info->tag)
-      {
 	required_feature_stage[table_index] = info->stage[table_index];
-	found = true;
-	continue;
-      }
+
       found |= hb_ot_layout_language_find_feature (face,
 						   table_tags[table_index],
 						   script_index[table_index],
 						   language_index[table_index],
 						   info->tag,
 						   &feature_index[table_index]);
     }
     if (!found && (info->flags & F_GLOBAL_SEARCH))
--- a/gfx/harfbuzz/src/hb-ot-shape-complex-indic.cc
+++ b/gfx/harfbuzz/src/hb-ot-shape-complex-indic.cc
@@ -488,22 +488,22 @@ struct indic_shape_plan_t
 {
   ASSERT_POD ();
 
   inline bool get_virama_glyph (hb_font_t *font, hb_codepoint_t *pglyph) const
   {
     hb_codepoint_t glyph = virama_glyph;
     if (unlikely (virama_glyph == (hb_codepoint_t) -1))
     {
-      if (!config->virama || !font->get_glyph (config->virama, 0, &glyph))
+      if (!config->virama || !font->get_nominal_glyph (config->virama, &glyph))
 	glyph = 0;
       /* Technically speaking, the spec says we should apply 'locl' to virama too.
        * Maybe one day... */
 
-      /* Our get_glyph() function needs a font, so we can't get the virama glyph
+      /* Our get_nominal_glyph() function needs a font, so we can't get the virama glyph
        * during shape planning...  Instead, overwrite it here.  It's safe.  Don't worry! */
       (const_cast<indic_shape_plan_t *> (this))->virama_glyph = glyph;
     }
 
     *pglyph = glyph;
     return glyph != 0;
   }
 
@@ -737,20 +737,16 @@ initial_reordering_consonant_syllable (c
 	while (limit < end && is_joiner (info[limit]))
 	  limit++;
 	base = start;
 	has_reph = true;
     }
 
     switch (indic_plan->config->base_pos)
     {
-      default:
-        assert (false);
-	HB_FALLTHROUGH;
-
       case BASE_POS_LAST:
       {
 	/* -> starting from the end of the syllable, move backwards */
 	unsigned int i = end;
 	bool seen_below = false;
 	do {
 	  i--;
 	  /* -> until a consonant is found */
@@ -1214,17 +1210,17 @@ insert_dotted_circles (const hb_ot_shape
       has_broken_syllables = true;
       break;
     }
   if (likely (!has_broken_syllables))
     return;
 
 
   hb_codepoint_t dottedcircle_glyph;
-  if (!font->get_glyph (0x25CCu, 0, &dottedcircle_glyph))
+  if (!font->get_nominal_glyph (0x25CCu, &dottedcircle_glyph))
     return;
 
   hb_glyph_info_t dottedcircle = {0};
   dottedcircle.codepoint = 0x25CCu;
   set_indic_properties (dottedcircle);
   dottedcircle.codepoint = dottedcircle_glyph;
 
   buffer->clear_output ();
@@ -1798,17 +1794,17 @@ decompose_indic (const hb_ot_shape_norma
      *   http://www.microsoft.com/typography/OpenTypeDev/sinhala/intro.htm#shaping
      */
 
     const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) c->plan->data;
 
     hb_codepoint_t glyph;
 
     if (hb_options ().uniscribe_bug_compatible ||
-	(c->font->get_glyph (ab, 0, &glyph) &&
+	(c->font->get_nominal_glyph (ab, &glyph) &&
 	 indic_plan->pstf.would_substitute (&glyph, 1, c->font->face)))
     {
       /* Ok, safe to use Uniscribe-style decomposition. */
       *a = 0x0DD9u;
       *b = ab;
       return true;
     }
   }
--- a/gfx/harfbuzz/src/hb-ot-shape-complex-myanmar.cc
+++ b/gfx/harfbuzz/src/hb-ot-shape-complex-myanmar.cc
@@ -434,17 +434,17 @@ insert_dotted_circles (const hb_ot_shape
       has_broken_syllables = true;
       break;
     }
   if (likely (!has_broken_syllables))
     return;
 
 
   hb_codepoint_t dottedcircle_glyph;
-  if (!font->get_glyph (0x25CCu, 0, &dottedcircle_glyph))
+  if (!font->get_nominal_glyph (0x25CCu, &dottedcircle_glyph))
     return;
 
   hb_glyph_info_t dottedcircle = {0};
   dottedcircle.codepoint = 0x25CCu;
   set_myanmar_properties (dottedcircle);
   dottedcircle.codepoint = dottedcircle_glyph;
 
   buffer->clear_output ();
--- a/gfx/harfbuzz/src/hb-ot-shape-complex-thai.cc
+++ b/gfx/harfbuzz/src/hb-ot-shape-complex-thai.cc
@@ -134,17 +134,16 @@ thai_pua_shape (hb_codepoint_t u, thai_a
   };
   static const thai_pua_mapping_t RD_mappings[] = {
     {0x0E0Du, 0xF70Fu, 0xF89Au}, /* YO YING */
     {0x0E10u, 0xF700u, 0xF89Eu}, /* THO THAN */
     {0x0000u, 0x0000u, 0x0000u}
   };
 
   switch (action) {
-    default: assert (false); HB_FALLTHROUGH;
     case NOP: return u;
     case SD:  pua_mappings = SD_mappings; break;
     case SDL: pua_mappings = SDL_mappings; break;
     case SL:  pua_mappings = SL_mappings; break;
     case RD:  pua_mappings = RD_mappings; break;
   }
   for (; pua_mappings->u; pua_mappings++)
     if (pua_mappings->u == u)
--- a/gfx/harfbuzz/src/hb-ot-shape-complex-use.cc
+++ b/gfx/harfbuzz/src/hb-ot-shape-complex-use.cc
@@ -494,17 +494,17 @@ insert_dotted_circles (const hb_ot_shape
     {
       has_broken_syllables = true;
       break;
     }
   if (likely (!has_broken_syllables))
     return;
 
   hb_glyph_info_t dottedcircle = {0};
-  if (!font->get_glyph (0x25CCu, 0, &dottedcircle.codepoint))
+  if (!font->get_nominal_glyph (0x25CCu, &dottedcircle.codepoint))
     return;
   dottedcircle.use_category() = hb_use_get_categories (0x25CC);
 
   buffer->clear_output ();
 
   buffer->idx = 0;
   unsigned int last_syllable = 0;
   while (buffer->idx < buffer->len && !buffer->in_error)
--- a/gfx/harfbuzz/src/hb-ot-shape-fallback.cc
+++ b/gfx/harfbuzz/src/hb-ot-shape-fallback.cc
@@ -521,27 +521,27 @@ void
 	  break;
 
 	case t::SPACE_4_EM_18:
 	  pos[i].x_advance = font->x_scale * 4 / 18;
 	  break;
 
 	case t::SPACE_FIGURE:
 	  for (char u = '0'; u <= '9'; u++)
-	    if (font->get_glyph (u, 0, &glyph))
+	    if (font->get_nominal_glyph (u, &glyph))
 	    {
 	      pos[i].x_advance = font->get_glyph_h_advance (glyph);
 	      break;
 	    }
 	  break;
 
 	case t::SPACE_PUNCTUATION:
-	  if (font->get_glyph ('.', 0, &glyph))
+	  if (font->get_nominal_glyph ('.', &glyph))
 	    pos[i].x_advance = font->get_glyph_h_advance (glyph);
-	  else if (font->get_glyph (',', 0, &glyph))
+	  else if (font->get_nominal_glyph (',', &glyph))
 	    pos[i].x_advance = font->get_glyph_h_advance (glyph);
 	  break;
 
 	case t::SPACE_NARROW:
 	  /* Half-space?
 	   * Unicode doc http://www.unicode.org/charts/PDF/U2000.pdf says ~1/4 or 1/5 of EM.
 	   * However, in my testing, many fonts have their regular space being about that
 	   * size.  To me, a percentage of the space width makes more sense.  Half is as
--- a/gfx/harfbuzz/src/hb-ot-shape-normalize.cc
+++ b/gfx/harfbuzz/src/hb-ot-shape-normalize.cc
@@ -86,17 +86,17 @@ compose_unicode (const hb_ot_shape_norma
 		 hb_codepoint_t *ab)
 {
   return (bool) c->unicode->compose (a, b, ab);
 }
 
 static inline void
 set_glyph (hb_glyph_info_t &info, hb_font_t *font)
 {
-  font->get_glyph (info.codepoint, 0, &info.glyph_index());
+  font->get_nominal_glyph (info.codepoint, &info.glyph_index());
 }
 
 static inline void
 output_char (hb_buffer_t *buffer, hb_codepoint_t unichar, hb_codepoint_t glyph)
 {
   buffer->cur().glyph_index() = glyph;
   buffer->output_glyph (unichar); /* This is very confusing indeed. */
   _hb_glyph_info_set_unicode_props (&buffer->prev(), buffer);
@@ -119,20 +119,20 @@ skip_char (hb_buffer_t *buffer)
 static inline unsigned int
 decompose (const hb_ot_shape_normalize_context_t *c, bool shortest, hb_codepoint_t ab)
 {
   hb_codepoint_t a, b, a_glyph, b_glyph;
   hb_buffer_t * const buffer = c->buffer;
   hb_font_t * const font = c->font;
 
   if (!c->decompose (c, ab, &a, &b) ||
-      (b && !font->get_glyph (b, 0, &b_glyph)))
+      (b && !font->get_nominal_glyph (b, &b_glyph)))
     return 0;
 
-  bool has_a = (bool) font->get_glyph (a, 0, &a_glyph);
+  bool has_a = (bool) font->get_nominal_glyph (a, &a_glyph);
   if (shortest && has_a) {
     /* Output a and b */
     output_char (buffer, a, a_glyph);
     if (likely (b)) {
       output_char (buffer, b, b_glyph);
       return 2;
     }
     return 1;
@@ -161,53 +161,53 @@ decompose (const hb_ot_shape_normalize_c
 
 static inline void
 decompose_current_character (const hb_ot_shape_normalize_context_t *c, bool shortest)
 {
   hb_buffer_t * const buffer = c->buffer;
   hb_codepoint_t u = buffer->cur().codepoint;
   hb_codepoint_t glyph;
 
-  if (shortest && c->font->get_glyph (u, 0, &glyph))
+  if (shortest && c->font->get_nominal_glyph (u, &glyph))
   {
     next_char (buffer, glyph);
     return;
   }
 
   if (decompose (c, shortest, u))
   {
     skip_char (buffer);
     return;
   }
 
-  if (!shortest && c->font->get_glyph (u, 0, &glyph))
+  if (!shortest && c->font->get_nominal_glyph (u, &glyph))
   {
     next_char (buffer, glyph);
     return;
   }
 
   if (_hb_glyph_info_is_unicode_space (&buffer->cur()))
   {
     hb_codepoint_t space_glyph;
     hb_unicode_funcs_t::space_t space_type = buffer->unicode->space_fallback_type (u);
-    if (space_type != hb_unicode_funcs_t::NOT_SPACE && c->font->get_glyph (0x0020u, 0, &space_glyph))
+    if (space_type != hb_unicode_funcs_t::NOT_SPACE && c->font->get_nominal_glyph (0x0020u, &space_glyph))
     {
       _hb_glyph_info_set_unicode_space_fallback_type (&buffer->cur(), space_type);
       next_char (buffer, space_glyph);
       buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_SPACE_FALLBACK;
       return;
     }
   }
 
   if (u == 0x2011u)
   {
     /* U+2011 is the only sensible character that is a no-break version of another character
      * and not a space.  The space ones are handled already.  Handle this lone one. */
     hb_codepoint_t other_glyph;
-    if (c->font->get_glyph (0x2010u, 0, &other_glyph))
+    if (c->font->get_nominal_glyph (0x2010u, &other_glyph))
     {
       next_char (buffer, other_glyph);
       return;
     }
   }
 
   next_char (buffer, glyph); /* glyph is initialized in earlier branches. */
 }
@@ -216,17 +216,17 @@ static inline void
 handle_variation_selector_cluster (const hb_ot_shape_normalize_context_t *c, unsigned int end, bool short_circuit)
 {
   /* TODO Currently if there's a variation-selector we give-up, it's just too hard. */
   hb_buffer_t * const buffer = c->buffer;
   hb_font_t * const font = c->font;
   for (; buffer->idx < end - 1 && !buffer->in_error;) {
     if (unlikely (buffer->unicode->is_variation_selector (buffer->cur(+1).codepoint))) {
       /* The next two lines are some ugly lines... But work. */
-      if (font->get_glyph (buffer->cur().codepoint, buffer->cur(+1).codepoint, &buffer->cur().glyph_index()))
+      if (font->get_variation_glyph (buffer->cur().codepoint, buffer->cur(+1).codepoint, &buffer->cur().glyph_index()))
       {
 	buffer->replace_glyphs (2, 1, &buffer->cur().codepoint);
       }
       else
       {
         /* Just pass on the two characters separately, let GSUB do its magic. */
 	set_glyph (buffer->cur(), font);
 	buffer->next_glyph ();
@@ -383,17 +383,17 @@ void
 	(starter == buffer->out_len - 1 ||
 	 _hb_glyph_info_get_modified_combining_class (&buffer->prev()) < _hb_glyph_info_get_modified_combining_class (&buffer->cur())) &&
 	/* And compose. */
 	c.compose (&c,
 		   buffer->out_info[starter].codepoint,
 		   buffer->cur().codepoint,
 		   &composed) &&
 	/* And the font has glyph for the composite. */
-	font->get_glyph (composed, 0, &glyph))
+	font->get_nominal_glyph (composed, &glyph))
     {
       /* Composes. */
       buffer->next_glyph (); /* Copy to out-buffer. */
       if (unlikely (buffer->in_error))
         return;
       buffer->merge_out_clusters (starter, buffer->out_len);
       buffer->out_len--; /* Remove the second composable. */
       /* Modify starter and carry on. */
--- a/gfx/harfbuzz/src/hb-ot-shape.cc
+++ b/gfx/harfbuzz/src/hb-ot-shape.cc
@@ -451,17 +451,17 @@ hb_ot_hide_default_ignorables (hb_ot_sha
       break;
   }
 
   /* No default-ignorables found; return. */
   if (i == count)
     return;
 
   hb_codepoint_t space;
-  if (c->font->get_glyph (' ', 0, &space))
+  if (c->font->get_nominal_glyph (' ', &space))
   {
     /* Replace default-ignorables with a zero-advance space glyph. */
     for (/*continue*/; i < count; i++)
     {
       if (_hb_glyph_info_is_default_ignorable (&info[i]))
 	info[i].codepoint = space;
     }
   }
@@ -519,42 +519,16 @@ hb_ot_map_glyphs_fast (hb_buffer_t  *buf
   hb_glyph_info_t *info = buffer->info;
   for (unsigned int i = 0; i < count; i++)
     info[i].codepoint = info[i].glyph_index();
 
   buffer->content_type = HB_BUFFER_CONTENT_TYPE_GLYPHS;
 }
 
 static inline void
-hb_synthesize_glyph_classes (hb_ot_shape_context_t *c)
-{
-  unsigned int count = c->buffer->len;
-  hb_glyph_info_t *info = c->buffer->info;
-  for (unsigned int i = 0; i < count; i++)
-  {
-    hb_ot_layout_glyph_props_flags_t klass;
-
-    /* Never mark default-ignorables as marks.
-     * They won't get in the way of lookups anyway,
-     * but having them as mark will cause them to be skipped
-     * over if the lookup-flag says so, but at least for the
-     * Mongolian variation selectors, looks like Uniscribe
-     * marks them as non-mark.  Some Mongolian fonts without
-     * GDEF rely on this.  Another notable character that
-     * this applies to is COMBINING GRAPHEME JOINER. */
-    klass = (_hb_glyph_info_get_general_category (&info[i]) !=
-	     HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK ||
-	     _hb_glyph_info_is_default_ignorable (&info[i])) ?
-	    HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH :
-	    HB_OT_LAYOUT_GLYPH_PROPS_MARK;
-    _hb_glyph_info_set_glyph_props (&info[i], klass);
-  }
-}
-
-static inline void
 hb_ot_substitute_default (hb_ot_shape_context_t *c)
 {
   hb_buffer_t *buffer = c->buffer;
 
   hb_ot_shape_initialize_masks (c);
 
   hb_ot_mirror_chars (c);
 
@@ -575,19 +549,16 @@ hb_ot_substitute_default (hb_ot_shape_co
 
 static inline void
 hb_ot_substitute_complex (hb_ot_shape_context_t *c)
 {
   hb_buffer_t *buffer = c->buffer;
 
   hb_ot_layout_substitute_start (c->font, buffer);
 
-  if (!hb_ot_layout_has_glyph_classes (c->face))
-    hb_synthesize_glyph_classes (c);
-
   c->plan->substitute (c->font, buffer);
 
   return;
 }
 
 static inline void
 hb_ot_substitute (hb_ot_shape_context_t *c)
 {
@@ -843,22 +814,22 @@ hb_ot_shape_plan_collect_lookups (hb_sha
 static void
 add_char (hb_font_t          *font,
 	  hb_unicode_funcs_t *unicode,
 	  hb_bool_t           mirror,
 	  hb_codepoint_t      u,
 	  hb_set_t           *glyphs)
 {
   hb_codepoint_t glyph;
-  if (font->get_glyph (u, 0, &glyph))
+  if (font->get_nominal_glyph (u, &glyph))
     glyphs->add (glyph);
   if (mirror)
   {
     hb_codepoint_t m = unicode->mirroring (u);
-    if (m != u && font->get_glyph (m, 0, &glyph))
+    if (m != u && font->get_nominal_glyph (m, &glyph))
       glyphs->add (glyph);
   }
 }
 
 
 /**
  * hb_ot_shape_glyphs_closure:
  *
--- a/gfx/harfbuzz/src/hb-private.hh
+++ b/gfx/harfbuzz/src/hb-private.hh
@@ -606,16 +606,25 @@ static inline unsigned char TOLOWER (uns
 #define NO_COPY(T) \
   T (const T &o); \
   T &operator = (const T &o)
 
 
 /* Debug */
 
 
+/* HB_NDEBUG disables some sanity checks that are very safe to disable and
+ * should be disabled in production systems.  If NDEBUG is defined, enable
+ * HB_NDEBUG; but if it's desirable that normal assert()s (which are very
+ * light-weight) to be enabled, then HB_DEBUG can be defined to disable
+ * the costlier checks. */
+#ifdef NDEBUG
+#define HB_NDEBUG
+#endif
+
 #ifndef HB_DEBUG
 #define HB_DEBUG 0
 #endif
 
 static inline bool
 _hb_debug (unsigned int level,
 	   unsigned int max_level)
 {
--- a/gfx/harfbuzz/src/hb-unicode-private.hh
+++ b/gfx/harfbuzz/src/hb-unicode-private.hh
@@ -219,17 +219,17 @@ HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS_SIM
     SPACE_NARROW,
   };
   static inline space_t
   space_fallback_type (hb_codepoint_t u)
   {
     switch (u)
     {
       /* All GC=Zs chars that can use a fallback. */
-      default:	    return NOT_SPACE;	/* Shouldn't happen. */
+      default:	    return NOT_SPACE;	/* U+1680 OGHAM SPACE MARK */
       case 0x0020u: return SPACE;	/* U+0020 SPACE */
       case 0x00A0u: return SPACE;	/* U+00A0 NO-BREAK SPACE */
       case 0x2000u: return SPACE_EM_2;	/* U+2000 EN QUAD */
       case 0x2001u: return SPACE_EM;	/* U+2001 EM QUAD */
       case 0x2002u: return SPACE_EM_2;	/* U+2002 EN SPACE */
       case 0x2003u: return SPACE_EM;	/* U+2003 EM SPACE */
       case 0x2004u: return SPACE_EM_3;	/* U+2004 THREE-PER-EM SPACE */
       case 0x2005u: return SPACE_EM_4;	/* U+2005 FOUR-PER-EM SPACE */
--- a/gfx/harfbuzz/src/hb-version.h
+++ b/gfx/harfbuzz/src/hb-version.h
@@ -33,19 +33,19 @@
 
 #include "hb-common.h"
 
 HB_BEGIN_DECLS
 
 
 #define HB_VERSION_MAJOR 1
 #define HB_VERSION_MINOR 2
-#define HB_VERSION_MICRO 2
+#define HB_VERSION_MICRO 6
 
-#define HB_VERSION_STRING "1.2.2"
+#define HB_VERSION_STRING "1.2.6"
 
 #define HB_VERSION_ATLEAST(major,minor,micro) \
 	((major)*10000+(minor)*100+(micro) <= \
 	 HB_VERSION_MAJOR*10000+HB_VERSION_MINOR*100+HB_VERSION_MICRO)
 
 
 HB_EXTERN void
 hb_version (unsigned int *major,