Merge mozilla-inbound to mozilla-central r=merge a=merge
authorCosmin Sabou <csabou@mozilla.com>
Wed, 06 Dec 2017 00:09:01 +0200
changeset 395169 a426845468e729a29229c3f181837118b18ca9cf
parent 395168 f84f292333c9f8970edd6c760e135a4666580528 (current diff)
parent 394996 72958e6e0e4ab94ed63da9afb0d4e51510d07076 (diff)
child 395170 a928be5dacc3b544e29c0612b3f8cda6447df802
push id98021
push usernbeleuzu@mozilla.com
push dateTue, 05 Dec 2017 23:49:57 +0000
treeherdermozilla-inbound@78a9a1962684 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge, merge
milestone59.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
Merge mozilla-inbound to mozilla-central r=merge a=merge
browser/locales/Makefile.in
python/mozbuild/mozbuild/frontend/context.py
python/mozbuild/mozbuild/frontend/emitter.py
python/mozbuild/mozbuild/test/frontend/test_emitter.py
toolkit/locales/update.locale
--- a/browser/components/places/tests/browser/browser.ini
+++ b/browser/components/places/tests/browser/browser.ini
@@ -10,16 +10,17 @@ support-files =
   frameRight.html
   sidebarpanels_click_test_page.html
   keyword_form.html
 
 [browser_0_library_left_pane_migration.js]
 [browser_addBookmarkForFrame.js]
 [browser_bookmark_folder_moveability.js]
 [browser_bookmarklet_windowOpen.js]
+[browser_bookmarks_sidebar_search.js]
 support-files =
   pageopeningwindow.html
 [browser_bookmarkProperties_addFolderDefaultButton.js]
 [browser_bookmarkProperties_addKeywordForThisSearch.js]
 [browser_bookmarkProperties_addLivemark.js]
 [browser_bookmarkProperties_bookmarkAllTabs.js]
 [browser_bookmarkProperties_cancel.js]
 [browser_bookmarkProperties_editTagContainer.js]
new file mode 100644
--- /dev/null
+++ b/browser/components/places/tests/browser/browser_bookmarks_sidebar_search.js
@@ -0,0 +1,60 @@
+/**
+ *  Test searching for bookmarks (by title and by tag) from the Bookmarks sidebar.
+ */
+"use strict";
+
+let sidebar = document.getElementById("sidebar");
+
+const TEST_URI = "http://example.com/";
+const BOOKMARKS_COUNT = 4;
+
+function assertBookmarks(searchValue) {
+  let found = 0;
+
+  let searchBox = sidebar.contentDocument.getElementById("search-box");
+
+  ok(searchBox, "search box is in context");
+
+  searchBox.value = searchValue;
+  searchBox.doCommand();
+
+  let tree = sidebar.contentDocument.getElementById("bookmarks-view");
+
+  for (let i = 0; i < tree.view.rowCount; i++) {
+    let cellText = tree.view.getCellText(i, tree.columns.getColumnAt(0));
+
+    if (cellText.indexOf("example page") != -1) {
+      found++;
+    }
+  }
+
+  info("Reset the search");
+  searchBox.value = "";
+  searchBox.doCommand();
+
+  is(found, BOOKMARKS_COUNT, "found expected site");
+}
+
+add_task(async function test() {
+  // Add bookmarks and tags.
+  for (let i = 0; i < BOOKMARKS_COUNT; i++) {
+    let url = Services.io.newURI(TEST_URI + i);
+
+    await PlacesUtils.bookmarks.insert({
+      url,
+      title: "example page " + i,
+      parentGuid: PlacesUtils.bookmarks.toolbarGuid
+    });
+    PlacesUtils.tagging.tagURI(url, ["test"]);
+  }
+
+  await withSidebarTree("bookmarks", function() {
+    // Search a bookmark by its title.
+    assertBookmarks("example.com");
+    // Search a bookmark by its tag.
+    assertBookmarks("test");
+  });
+
+  // Cleanup.
+  await PlacesUtils.bookmarks.eraseEverything();
+});
--- a/browser/locales/Makefile.in
+++ b/browser/locales/Makefile.in
@@ -147,33 +147,16 @@ installers-%:
 	@$(MAKE) libs-$*
 	@$(MAKE) package-langpack-$*
 	@$(MAKE) repackage-zip-$*
 ifeq (WINNT,$(OS_ARCH))
 	@$(MAKE) package-win32-installer AB_CD=$* MOZ_PKG_FORMAT=SFX7Z
 endif
 	@echo 'repackaging done'
 
-ifdef MOZ_UPDATER
-# Note that we want updater.ini to be in the top directory, not the browser/
-# subdirectory, because that's where the updater is installed and runs.
-libs:: $(call MERGE_FILE,updater/updater.ini) $(call mkdir_deps,$(DIST)/bin)
-ifeq ($(OS_ARCH),WINNT)
-	cat $< $(srcdir)/../installer/windows/nsis/updater_append.ini | \
-	  sed -e 's/^InfoText=/Info=/' -e 's/^TitleText=/Title=/' | \
-	  sed -e 's/%MOZ_APP_DISPLAYNAME%/$(MOZ_APP_DISPLAYNAME)/' > \
-	  $(FINAL_TARGET)/../updater.ini
-else
-	cat $< | \
-	  sed -e 's/^InfoText=/Info=/' -e 's/^TitleText=/Title=/' | \
-	  sed -e 's/%MOZ_APP_DISPLAYNAME%/$(MOZ_APP_DISPLAYNAME)/' > \
-	  $(FINAL_TARGET)/../updater.ini
-endif
-endif
-
 ident:
 	@printf 'fx_revision '
 	@$(PYTHON) $(topsrcdir)/config/printconfigsetting.py \
 	    $(STAGEDIST)/application.ini App SourceStamp
 	@printf 'buildid '
 	@$(PYTHON) $(topsrcdir)/config/printconfigsetting.py \
 	    $(STAGEDIST)/application.ini App BuildID
 
new file mode 100644
--- /dev/null
+++ b/browser/locales/generate_updater_ini.py
@@ -0,0 +1,27 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+# Generate updater.ini by doing some light substitution on the localized updater.ini input,
+# and appending the contents of updater_ini_append on Windows.
+
+from __future__ import absolute_import, unicode_literals, print_function
+
+import buildconfig
+import codecs
+import re
+import shutil
+
+def main(output, updater_ini, updater_ini_append, locale=None):
+    assert(locale is not None)
+    fixup_re = re.compile('^(Info|Title)Text=')
+    # updater.ini is always utf-8.
+    with codecs.open(updater_ini, 'rb', 'utf_8') as f:
+        for line in f:
+            line = fixup_re.sub(r'\1=', line)
+            line = line.replace('%MOZ_APP_DISPLAYNAME%', buildconfig.substs['MOZ_APP_DISPLAYNAME'])
+            output.write(line)
+    if buildconfig.substs['OS_TARGET'] == 'WINNT':
+        # Also append the contents of `updater_ini_append`.
+        with codecs.open(updater_ini_append, 'rb', 'utf_8') as f:
+            shutil.copyfileobj(f, output)
--- a/browser/locales/moz.build
+++ b/browser/locales/moz.build
@@ -7,16 +7,29 @@
 JAR_MANIFESTS += ['jar.mn']
 
 # If DIST_SUBDIR ever gets unset in browser this path might be wrong due to PREF_DIR changing.
 LOCALIZED_PP_FILES.defaults.preferences += ['en-US/firefox-l10n.js']
 
 if CONFIG['MOZ_CRASHREPORTER']:
     LOCALIZED_FILES += ['en-US/crashreporter/crashreporter-override.ini']
 
+if CONFIG['MOZ_UPDATER']:
+    LOCALIZED_GENERATED_FILES += ['updater.ini']
+    updater = LOCALIZED_GENERATED_FILES['updater.ini']
+    updater.script = 'generate_updater_ini.py'
+    updater.inputs = [
+        'en-US/updater/updater.ini',
+        '../installer/windows/nsis/updater_append.ini',
+    ]
+    # Yes, this is weird, but what can you do? This file doesn't want to be in the DIST_SUBDIR,
+    # but we can't really move it to a different directory until we change how locale repacks
+    # work.
+    LOCALIZED_FILES['..'] += ['!updater.ini']
+
 with Files("**"):
     BUG_COMPONENT = ("Toolkit", "Build Config")
 
 with Files("all-locales"):
     BUG_COMPONENT = ("Core", "Localization")
 
 with Files("en-US/**"):
     BUG_COMPONENT = ("Core", "Localization")
--- a/devtools/shared/css/generated/properties-db.js
+++ b/devtools/shared/css/generated/properties-db.js
@@ -3048,17 +3048,18 @@ exports.CSS_PROPERTIES = {
       "outline-color",
       "outline-offset",
       "-moz-outline-radius-bottomleft",
       "-moz-outline-radius-bottomright",
       "-moz-outline-radius-topleft",
       "-moz-outline-radius-topright",
       "outline-style",
       "outline-width",
-      "overflow-clip-box",
+      "overflow-clip-box-block",
+      "overflow-clip-box-inline",
       "overflow-x",
       "overflow-y",
       "padding-block-end",
       "padding-block-start",
       "padding-bottom",
       "padding-inline-end",
       "padding-inline-start",
       "padding-left",
@@ -9950,16 +9951,24 @@ exports.PREFERENCES = [
     "-moz-osx-font-smoothing",
     "layout.css.osx-font-smoothing.enabled"
   ],
   [
     "overflow-clip-box",
     "layout.css.overflow-clip-box.enabled"
   ],
   [
+    "overflow-clip-box-block",
+    "layout.css.overflow-clip-box.enabled"
+  ],
+  [
+    "overflow-clip-box-inline",
+    "layout.css.overflow-clip-box.enabled"
+  ],
+  [
     "paint-order",
     "svg.paint-order.enabled"
   ],
   [
     "scroll-behavior",
     "layout.css.scroll-behavior.property-enabled"
   ],
   [
--- a/dom/base/crashtests/504224.html
+++ b/dom/base/crashtests/504224.html
@@ -1,23 +1,29 @@
 <html class="reftest-wait">
 <head>
 <title>Crash [@ nsFocusManager::GetCommonAncestor], part 2</title>
 </head>
 <body>
-<iframe src="file_504224.html" id="content"></iframe>
 <script>
-var src=document.getElementById('src');
+function oniframeload() {
+  window.frames[0].location.reload();
+};
+</script>
+<iframe src="file_504224.html" id="content" onload="oniframeload();" ></iframe>
+<script>
+var src='file_504224.html';
 setInterval(function() {
-  if (!document.getElementById('content')) {
-    var x=document.createElement('iframe');
+  var x = document.getElementById('content');
+  if (!x) {
+    x=document.createElement('iframe');
     x.src=src;
     x.id = 'content';
     document.body.appendChild(x);
-    setTimeout(function() { window.focus(); document.documentElement.removeAttribute('class'); }, 100);
-  } else {
-    window.frames[0].location.reload();
+    setTimeout(function() {
+      window.focus();
+      document.documentElement.removeAttribute('class');
+    }, 100);
   }
 }, 500);
 </script>
 </body>
 </html>
-
--- a/gfx/harfbuzz/NEWS
+++ b/gfx/harfbuzz/NEWS
@@ -1,8 +1,18 @@
+Overview of changes leading to 1.7.2
+Monday, December 4, 2017
+====================================
+
+- Optimize hb_set_add_range().
+- Misc fixes.
+- New API:
+hb_coretext_font_create()
+
+
 Overview of changes leading to 1.7.1
 Tuesday, November 14, 2017
 ====================================
 
 - Fix atexit object destruction regression.
 - Fix minor integer-overflow.
 
 
@@ -28,26 +38,26 @@ Thursday, October 26th, 2017
 
 
 Overview of changes leading to 1.6.2
 Monday, October 23nd, 2017
 ====================================
 
 - Yesterday's release had a bad crasher; don't use it.  That's what
   happens when one works on Sunday...
-  https://github.com/behdad/harfbuzz/issues/578
+  https://github.com/harfbuzz/harfbuzz/issues/578
 - Build fixes for FreeBSD and Chrome Android.
 
 
 Overview of changes leading to 1.6.1
 Sunday, October 22nd, 2017
 ====================================
 
 - Don't skip over COMBINING GRAPHEME JOINER when ligating, etc.
-  To be refined: https://github.com/behdad/harfbuzz/issues/554
+  To be refined: https://github.com/harfbuzz/harfbuzz/issues/554
 - Faster hb_set_t implementation.
 - Don't use deprecated ICU API.
 - Fix undefined-behavior in Myanmar shaper, introduced in 1.6.0
 - Deprecated API:
   hb_set_invert()
 
 
 Overview of changes leading to 1.6.0
@@ -438,34 +448,34 @@ Overview of changes leading to 1.2.1
 Tuesday, February 23, 2016
 ====================================
 
 - CoreText: Fix bug with wrong scale if font scale was changed later.
   https://github.com/libass/libass/issues/212
 - CoreText: Drastically speed up font initialization.
 - CoreText: Fix tiny leak.
 - Group ZWJ/ZWNJ with previous syllable under cluster-level=0.
-  https://github.com/behdad/harfbuzz/issues/217
+  https://github.com/harfbuzz/harfbuzz/issues/217
 - Add test/shaping/README.md about how to add tests to the suite.
 
 
 Overview of changes leading to 1.2.0
 Friday, February 19, 2016
 ====================================
 
 - Fix various issues (hangs mostly) in case of memory allocation failure.
 - Change mark zeroing types of most shapers from BY_UNICODE_LATE to
   BY_GDEF_LATE.  This seems to be what Uniscribe does.
 - Change mark zeroing of USE shaper from NONE to BY_GDEF_EARLY.  That's
   what Windows does.
 - Allow GPOS cursive connection on marks, and fix the interaction with
   mark attachment.  This work resulted in some changes to how mark
   attachments work.  See:
-  https://github.com/behdad/harfbuzz/issues/211
-  https://github.com/behdad/harfbuzz/commit/86c68c7a2c971efe8e35b1f1bd99401dc8b688d2
+  https://github.com/harfbuzz/harfbuzz/issues/211
+  https://github.com/harfbuzz/harfbuzz/commit/86c68c7a2c971efe8e35b1f1bd99401dc8b688d2
 - Graphite2 shaper: improved negative advance handling (eg. Nastaliq).
 - Add nmake-based build system for Windows.
 - Minor speedup.
 - Misc. improvements.
 
 
 Overview of changes leading to 1.1.3
 Monday, January 11, 2016
@@ -496,17 +506,17 @@ Monday, January 11, 2016
     Actual message protocol to be fleshed out later.
 
 
 Overview of changes leading to 1.1.2
 Wednesday, November 26, 2015
 ====================================
 
 - Fix badly-broken fallback shaper that affected terminology.
-  https://github.com/behdad/harfbuzz/issues/187
+  https://github.com/harfbuzz/harfbuzz/issues/187
 - Fix y_scaling in Graphite shaper.
 - API changes:
   * An unset glyph_h_origin() function in font-funcs now (sensibly)
     implies horizontal origin at 0,0.  Ie, the nil callback returns
     true instead of false.  As such, implementations that have a
     glyph_h_origin() that simply returns true, can remove that function
     with HarfBuzz >= 1.1.2.  This results in a tiny speedup.
 
@@ -518,21 +528,21 @@ Wednesday, November 24, 2015
 - Build fixes, specially for hb-coretext.
 
 
 Overview of changes leading to 1.1.0
 Wednesday, November 18, 2015
 ====================================
 
 - Implement 'stch' stretch feature for Syriac Abbreviation Mark.
-  https://github.com/behdad/harfbuzz/issues/141
+  https://github.com/harfbuzz/harfbuzz/issues/141
 - Disable use of decompose_compatibility() callback.
 - Implement "shaping" of various Unicode space characters, even
   if the font does not support them.
-  https://github.com/behdad/harfbuzz/issues/153
+  https://github.com/harfbuzz/harfbuzz/issues/153
 - If font does not support U+2011 NO-BREAK HYPHEN, fallback to
   U+2010 HYPHEN.
 - Changes resulting from libFuzzer continuous fuzzing:
   * Reject font tables that need more than 8 edits,
   * Bound buffer growth during shaping to 32x,
   * Fix assertions and other issues at OOM / buffer max-growth.
 - Misc fixes and optimizations.
 - API changes:
@@ -545,25 +555,25 @@ Thursday, October 15, 2015
 ====================================
 
 - Reduce max nesting level in OT lookups from 8 to 6.
   Should not affect any real font as far as I know.
 - Fix memory access issue in ot-font.
 - Revert default load-flags of fonts created using hb_ft_font_create()
   back to FT_LOAD_DEFAULT|FT_LOAD_NO_HINTING.  This was changed in
   last release (1.0.5), but caused major issues, so revert.
-  https://github.com/behdad/harfbuzz/issues/143
+  https://github.com/harfbuzz/harfbuzz/issues/143
 
 
 Overview of changes leading to 1.0.5
 Tuesday, October 13, 2015
 ====================================
 
 - Fix multiple memory access bugs discovered using libFuzzer.
-  https://github.com/behdad/harfbuzz/issues/139
+  https://github.com/harfbuzz/harfbuzz/issues/139
   Everyone should upgrade to this version as soon as possible.
   We now have continuous fuzzing set up, to avoid issues like
   these creeping in again.
 - Misc fixes.
 
 - New API:
   * hb_font_set_parent().
   * hb_ft_font_[sg]et_load_flags()
--- a/gfx/harfbuzz/README
+++ b/gfx/harfbuzz/README
@@ -1,13 +1,15 @@
-[![Build Status](https://travis-ci.org/behdad/harfbuzz.svg)](https://travis-ci.org/behdad/harfbuzz)
-[![Build Status](https://ci.appveyor.com/api/projects/status/4oaq58ns2h0m2soa?svg=true)](https://ci.appveyor.com/project/behdad/harfbuzz)
-[![CircleCI](https://circleci.com/gh/behdad/harfbuzz.svg?style=svg)](https://circleci.com/gh/behdad/harfbuzz)
-[![Coverage Status](https://img.shields.io/coveralls/behdad/harfbuzz.svg)](https://coveralls.io/r/behdad/harfbuzz)
+[![Build Status](https://travis-ci.org/harfbuzz/harfbuzz.svg)](https://travis-ci.org/harfbuzz/harfbuzz)
+[![Build Status](https://ci.appveyor.com/api/projects/status/4oaq58ns2h0m2soa?svg=true)](https://ci.appveyor.com/project/harfbuzz/harfbuzz)
+[![CircleCI](https://circleci.com/gh/harfbuzz/harfbuzz.svg?style=svg)](https://circleci.com/gh/harfbuzz/harfbuzz)
+[![Coverage Status](https://img.shields.io/coveralls/harfbuzz/harfbuzz.svg)](https://coveralls.io/r/harfbuzz/harfbuzz)
 [ABI Tracker](http://abi-laboratory.pro/tracker/timeline/harfbuzz/)
 
 This is HarfBuzz, a text shaping library.
 
 For bug reports, mailing list, and other information please visit:
 
   http://harfbuzz.org/
 
 For license information, see the file COPYING.
+
+Documentation: https://harfbuzz.github.io
--- a/gfx/harfbuzz/README-mozilla
+++ b/gfx/harfbuzz/README-mozilla
@@ -1,14 +1,14 @@
-gfx/harfbuzz status as of 2017-11-14:
+gfx/harfbuzz status as of 2017-12-04:
 
 This directory contains the HarfBuzz source from the 'master' branch of
 https://github.com/behdad/harfbuzz.
 
-Current version: 1.7.1
+Current version: 1.7.2
 
 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/configure.ac
+++ b/gfx/harfbuzz/configure.ac
@@ -1,12 +1,12 @@
 AC_PREREQ([2.64])
 AC_INIT([HarfBuzz],
-        [1.7.1],
-        [https://github.com/behdad/harfbuzz/issues/new],
+        [1.7.2],
+        [https://github.com/harfbuzz/harfbuzz/issues/new],
         [harfbuzz],
         [http://harfbuzz.org/])
 
 AC_CONFIG_MACRO_DIR([m4])
 AC_CONFIG_SRCDIR([src/harfbuzz.pc.in])
 AC_CONFIG_HEADERS([config.h])
 
 AM_INIT_AUTOMAKE([1.11.1 gnits tar-ustar dist-bzip2 no-dist-gzip -Wall no-define color-tests -Wno-portability])
--- a/gfx/harfbuzz/harfbuzz.doap
+++ b/gfx/harfbuzz/harfbuzz.doap
@@ -8,17 +8,17 @@
 
   <homepage
   rdf:resource="http://harfbuzz.org/" />
   <mailing-list
   rdf:resource="http://lists.freedesktop.org/mailman/listinfo/harfbuzz" />
   <!--download-page
   rdf:resource=""/-->
   <bug-database
-  rdf:resource="https://github.com/behdad/harfbuzz/issues" />
+  rdf:resource="https://github.com/harfbuzz/harfbuzz/issues" />
 
   <maintainer>
     <foaf:Person>
       <foaf:name>Behdad Esfahbod</foaf:name>
       <foaf:mbox rdf:resource="mailto:harfbuzz@behdad.org" />
     </foaf:Person>
   </maintainer>
 </Project>
--- a/gfx/harfbuzz/src/Makefile.am
+++ b/gfx/harfbuzz/src/Makefile.am
@@ -94,16 +94,19 @@ HBSOURCES += $(HB_CORETEXT_sources)
 HBHEADERS += $(HB_CORETEXT_headers)
 endif
 
 if HAVE_UCDN
 SUBDIRS += hb-ucdn
 HBCFLAGS += -I$(srcdir)/hb-ucdn
 HBLIBS   += hb-ucdn/libhb-ucdn.la
 HBSOURCES += $(HB_UCDN_sources)
+hb-ucdn/libhb-ucdn.la: ucdn
+ucdn:
+	@$(MAKE) $(AM_MAKEFLAGS) -C hb-ucdn
 endif
 DIST_SUBDIRS += hb-ucdn
 
 
 # Put the library together
 
 HBLIBS += $(HBNONPCLIBS)
 
@@ -130,19 +133,22 @@ nodist_pkginclude_HEADERS = $(HBNODISTHE
 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_FACTOR=3 \
 	-DHB_BUFFER_MAX_LEN_MIN=8 \
 	-DHB_BUFFER_MAX_LEN_DEFAULT=128 \
+	-DHB_BUFFER_MAX_OPS_FACTOR=8 \
+	-DHB_BUFFER_MAX_OPS_MIN=64 \
+	-DHB_BUFFER_MAX_OPS_DEFAULT=1024 \
 	$(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)
--- a/gfx/harfbuzz/src/gen-use-table.py
+++ b/gfx/harfbuzz/src/gen-use-table.py
@@ -39,16 +39,17 @@ for i, f in enumerate (files):
 			data[i][u] = t
 		values[i][t] = values[i].get (t, 0) + end - start + 1
 
 defaults = ('Other', 'Not_Applicable', 'Cn', 'No_Block')
 
 # TODO Characters that are not in Unicode Indic files, but used in USE
 data[0][0x034F] = defaults[0]
 data[0][0x2060] = defaults[0]
+data[0][0x20F0] = defaults[0]
 for u in range (0xFE00, 0xFE0F + 1):
 	data[0][u] = defaults[0]
 
 # Merge data into one dict:
 for i,v in enumerate (defaults):
 	values[i][v] = values[i].get (v, 0) + 1
 combined = {}
 for i,d in enumerate (data):
@@ -295,19 +296,25 @@ def map_to_use(data):
 		# have UIPC
 		if U == 0x17DD: UISC = Vowel_Dependent
 		if 0x1CE2 <= U <= 0x1CE8: UISC = Cantillation_Mark
 
 		# TODO: U+1CED should only be allowed after some of
 		# the nasalization marks, maybe only for U+1CE9..U+1CF1.
 		if U == 0x1CED: UISC = Tone_Mark
 
-		# TODO: https://github.com/behdad/harfbuzz/issues/525
+		# TODO: https://github.com/harfbuzz/harfbuzz/issues/525
 		if U == 0x1A7F: UISC = Consonant_Final; UIPC = Bottom
 
+		# TODO: https://github.com/harfbuzz/harfbuzz/pull/609
+		if U == 0x20F0: UISC = Cantillation_Mark; UIPC = Top
+
+		# TODO: https://github.com/harfbuzz/harfbuzz/pull/626
+		if U == 0xA8B4: UISC = Consonant_Medial
+
 		values = [k for k,v in items if v(U,UISC,UGC)]
 		assert len(values) == 1, "%s %s %s %s" % (hex(U), UISC, UGC, values)
 		USE = values[0]
 
 		# Resolve Indic_Positional_Category
 
 		# TODO: Not in Unicode 8.0 yet, but in spec.
 		if U == 0x1B6C: UIPC = Bottom
--- a/gfx/harfbuzz/src/harfbuzz-icu.pc
+++ b/gfx/harfbuzz/src/harfbuzz-icu.pc
@@ -1,13 +1,13 @@
 prefix=/usr/local
 exec_prefix=/usr/local
 libdir=/usr/local/lib
 includedir=/usr/local/include
 
 Name: harfbuzz
 Description: HarfBuzz text shaping library ICU integration
-Version: 1.7.1
+Version: 1.7.2
 
 Requires: harfbuzz
 Requires.private: icu-uc
 Libs: -L${libdir} -lharfbuzz-icu
 Cflags: -I${includedir}/harfbuzz
--- a/gfx/harfbuzz/src/harfbuzz.pc
+++ b/gfx/harfbuzz/src/harfbuzz.pc
@@ -1,13 +1,13 @@
 prefix=/usr/local
 exec_prefix=/usr/local
 libdir=/usr/local/lib
 includedir=/usr/local/include
 
 Name: harfbuzz
 Description: HarfBuzz text shaping library
-Version: 1.7.1
+Version: 1.7.2
 
 Libs: -L${libdir} -lharfbuzz
 Libs.private: -lm    
 Requires.private: glib-2.0 >= 2.19.1 
 Cflags: -I${includedir}/harfbuzz
--- a/gfx/harfbuzz/src/hb-buffer-private.hh
+++ b/gfx/harfbuzz/src/hb-buffer-private.hh
@@ -30,26 +30,36 @@
 #ifndef HB_BUFFER_PRIVATE_HH
 #define HB_BUFFER_PRIVATE_HH
 
 #include "hb-private.hh"
 #include "hb-object-private.hh"
 #include "hb-unicode-private.hh"
 
 
-#ifndef HB_BUFFER_MAX_EXPANSION_FACTOR
-#define HB_BUFFER_MAX_EXPANSION_FACTOR 32
+#ifndef HB_BUFFER_MAX_LEN_FACTOR
+#define HB_BUFFER_MAX_LEN_FACTOR 32
 #endif
 #ifndef HB_BUFFER_MAX_LEN_MIN
 #define HB_BUFFER_MAX_LEN_MIN 8192
 #endif
 #ifndef HB_BUFFER_MAX_LEN_DEFAULT
 #define HB_BUFFER_MAX_LEN_DEFAULT 0x3FFFFFFF /* Shaping more than a billion chars? Let us know! */
 #endif
 
+#ifndef HB_BUFFER_MAX_OPS_FACTOR
+#define HB_BUFFER_MAX_OPS_FACTOR 64
+#endif
+#ifndef HB_BUFFER_MAX_OPS_MIN
+#define HB_BUFFER_MAX_OPS_MIN 1024
+#endif
+#ifndef HB_BUFFER_MAX_OPS_DEFAULT
+#define HB_BUFFER_MAX_OPS_DEFAULT 0x1FFFFFFF /* Shaping more than a billion operations? Let us know! */
+#endif
+
 static_assert ((sizeof (hb_glyph_info_t) == 20), "");
 static_assert ((sizeof (hb_glyph_info_t) == sizeof (hb_glyph_position_t)), "");
 
 HB_MARK_AS_FLAG_T (hb_buffer_flags_t);
 HB_MARK_AS_FLAG_T (hb_buffer_serialize_flags_t);
 HB_MARK_AS_FLAG_T (hb_buffer_diff_flags_t);
 
 enum hb_buffer_scratch_flags_t {
@@ -79,16 +89,17 @@ struct hb_buffer_t {
 
   /* Information about how the text in the buffer should be treated */
   hb_unicode_funcs_t *unicode; /* Unicode functions */
   hb_buffer_flags_t flags; /* BOT / EOT / etc. */
   hb_buffer_cluster_level_t cluster_level;
   hb_codepoint_t replacement; /* U+FFFD or something else. */
   hb_buffer_scratch_flags_t scratch_flags; /* Have space-flallback, etc. */
   unsigned int max_len; /* Maximum allowed len. */
+  int max_ops; /* Maximum allowed operations. */
 
   /* Buffer contents */
   hb_buffer_content_type_t content_type;
   hb_segment_properties_t props; /* Script, language, direction */
 
   bool in_error; /* Allocation failed */
   bool have_output; /* Whether we have an output buffer going on */
   bool have_positions; /* Whether we have positions */
@@ -97,27 +108,16 @@ struct hb_buffer_t {
   unsigned int len; /* Length of ->info and ->pos arrays */
   unsigned int out_len; /* Length of ->out array if have_output */
 
   unsigned int allocated; /* Length of allocated arrays */
   hb_glyph_info_t     *info;
   hb_glyph_info_t     *out_info;
   hb_glyph_position_t *pos;
 
-  inline hb_glyph_info_t &cur (unsigned int i = 0) { return info[idx + i]; }
-  inline hb_glyph_info_t cur (unsigned int i = 0) const { return info[idx + i]; }
-
-  inline hb_glyph_position_t &cur_pos (unsigned int i = 0) { return pos[idx + i]; }
-  inline hb_glyph_position_t cur_pos (unsigned int i = 0) const { return pos[idx + i]; }
-
-  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;
 
   /* 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];
@@ -127,16 +127,20 @@ struct hb_buffer_t {
   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
+
+
+  /* Methods */
+
   inline void allocate_var (unsigned int start, unsigned int count)
   {
 #ifndef HB_NDEBUG
     unsigned int end = start + count;
     assert (end <= 8);
     unsigned int bits = (1u<<end) - (1u<<start);
     assert (0 == (allocated_var_bits & bits));
     allocated_var_bits |= bits;
@@ -163,18 +167,27 @@ struct hb_buffer_t {
   }
   inline void deallocate_var_all (void)
   {
 #ifndef HB_NDEBUG
     allocated_var_bits = 0;
 #endif
   }
 
+  inline hb_glyph_info_t &cur (unsigned int i = 0) { return info[idx + i]; }
+  inline hb_glyph_info_t cur (unsigned int i = 0) const { return info[idx + i]; }
 
-  /* Methods */
+  inline hb_glyph_position_t &cur_pos (unsigned int i = 0) { return pos[idx + i]; }
+  inline hb_glyph_position_t cur_pos (unsigned int i = 0) const { return pos[idx + i]; }
+
+  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; }
+
 
   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; }
--- a/gfx/harfbuzz/src/hb-buffer.cc
+++ b/gfx/harfbuzz/src/hb-buffer.cc
@@ -717,16 +717,17 @@ hb_buffer_t *
 hb_buffer_create (void)
 {
   hb_buffer_t *buffer;
 
   if (!(buffer = hb_object_create<hb_buffer_t> ()))
     return hb_buffer_get_empty ();
 
   buffer->max_len = HB_BUFFER_MAX_LEN_DEFAULT;
+  buffer->max_ops = HB_BUFFER_MAX_OPS_DEFAULT;
 
   buffer->reset ();
 
   return buffer;
 }
 
 /**
  * hb_buffer_get_empty:
@@ -744,16 +745,17 @@ hb_buffer_get_empty (void)
     HB_OBJECT_HEADER_STATIC,
 
     const_cast<hb_unicode_funcs_t *> (&_hb_unicode_funcs_nil),
     HB_BUFFER_FLAG_DEFAULT,
     HB_BUFFER_CLUSTER_LEVEL_DEFAULT,
     HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT,
     HB_BUFFER_SCRATCH_FLAG_DEFAULT,
     HB_BUFFER_MAX_LEN_DEFAULT,
+    HB_BUFFER_MAX_OPS_DEFAULT,
 
     HB_BUFFER_CONTENT_TYPE_INVALID,
     HB_SEGMENT_PROPERTIES_DEFAULT,
     true, /* in_error */
     true, /* have_output */
     true  /* have_positions */
 
     /* Zero is good enough for everything else. */
--- a/gfx/harfbuzz/src/hb-coretext.cc
+++ b/gfx/harfbuzz/src/hb-coretext.cc
@@ -76,31 +76,22 @@ reference_table  (hb_face_t *face HB_UNU
 }
 
 static void
 _hb_cg_font_release (void *data)
 {
   CGFontRelease ((CGFontRef) data);
 }
 
-hb_face_t *
-hb_coretext_face_create (CGFontRef cg_font)
-{
-  return hb_face_create_for_tables (reference_table, CGFontRetain (cg_font), _hb_cg_font_release);
-}
 
 HB_SHAPER_DATA_ENSURE_DEFINE(coretext, face)
 HB_SHAPER_DATA_ENSURE_DEFINE_WITH_CONDITION(coretext, font,
 	fabs (CTFontGetSize((CTFontRef) data) - coretext_font_size (font->ptem)) <= .5
 )
 
-/*
- * shaper face data
- */
-
 static CTFontDescriptorRef
 get_last_resort_font_desc (void)
 {
   // TODO Handle allocation failures?
   CTFontDescriptorRef last_resort = CTFontDescriptorCreateWithNameAndSize (CFSTR("LastResort"), 0);
   CFArrayRef cascade_list = CFArrayCreate (kCFAllocatorDefault,
 					   (const void **) &last_resort,
 					   1,
@@ -262,31 +253,33 @@ hb_coretext_shaper_face_data_t *
 }
 
 void
 _hb_coretext_shaper_face_data_destroy (hb_coretext_shaper_face_data_t *data)
 {
   CFRelease ((CGFontRef) data);
 }
 
+hb_face_t *
+hb_coretext_face_create (CGFontRef cg_font)
+{
+  return hb_face_create_for_tables (reference_table, CGFontRetain (cg_font), _hb_cg_font_release);
+}
+
 /*
  * Since: 0.9.10
  */
 CGFontRef
 hb_coretext_face_get_cg_font (hb_face_t *face)
 {
   if (unlikely (!hb_coretext_shaper_face_data_ensure (face))) return nullptr;
   return (CGFontRef) HB_SHAPER_DATA_GET (face);
 }
 
 
-/*
- * shaper font data
- */
-
 hb_coretext_shaper_font_data_t *
 _hb_coretext_shaper_font_data_create (hb_font_t *font)
 {
   hb_face_t *face = font->face;
   if (unlikely (!hb_coretext_shaper_face_data_ensure (face))) return nullptr;
   CGFontRef cg_font = (CGFontRef) HB_SHAPER_DATA_GET (face);
 
   CTFontRef ct_font = create_ct_font (cg_font, coretext_font_size (font->ptem));
@@ -301,16 +294,45 @@ hb_coretext_shaper_font_data_t *
 }
 
 void
 _hb_coretext_shaper_font_data_destroy (hb_coretext_shaper_font_data_t *data)
 {
   CFRelease ((CTFontRef) data);
 }
 
+/*
+ * Since: 1.7.2
+ */
+hb_font_t *
+hb_coretext_font_create (CTFontRef ct_font)
+{
+  CGFontRef cg_font = CTFontCopyGraphicsFont (ct_font, 0);
+  hb_face_t *face = hb_coretext_face_create (cg_font);
+  CFRelease (cg_font);
+  hb_font_t *font = hb_font_create (face);
+  hb_face_destroy (face);
+
+  if (unlikely (hb_object_is_inert (font)))
+    return font;
+
+  /* Let there be dragons here... */
+  HB_SHAPER_DATA_GET (font) = (hb_coretext_shaper_font_data_t *) CFRetain (ct_font);
+
+  return font;
+}
+
+CTFontRef
+hb_coretext_font_get_ct_font (hb_font_t *font)
+{
+  if (unlikely (!hb_coretext_shaper_font_data_ensure (font))) return nullptr;
+  return (CTFontRef) HB_SHAPER_DATA_GET (font);
+}
+
+
 
 /*
  * shaper shape_plan data
  */
 
 struct hb_coretext_shaper_shape_plan_data_t {};
 
 hb_coretext_shaper_shape_plan_data_t *
@@ -323,23 +345,16 @@ hb_coretext_shaper_shape_plan_data_t *
   return (hb_coretext_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
 }
 
 void
 _hb_coretext_shaper_shape_plan_data_destroy (hb_coretext_shaper_shape_plan_data_t *data HB_UNUSED)
 {
 }
 
-CTFontRef
-hb_coretext_font_get_ct_font (hb_font_t *font)
-{
-  if (unlikely (!hb_coretext_shaper_font_data_ensure (font))) return nullptr;
-  return (CTFontRef)HB_SHAPER_DATA_GET (font);
-}
-
 
 /*
  * shaper
  */
 
 struct feature_record_t {
   unsigned int feature;
   unsigned int setting;
@@ -995,17 +1010,17 @@ resize_and_retry:
 	 *
 	 * 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
 	 * construct a hb_face to begin with.
 	 *
-	 * See: http://github.com/behdad/harfbuzz/pull/36
+	 * See: http://github.com/harfbuzz/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;
--- a/gfx/harfbuzz/src/hb-coretext.h
+++ b/gfx/harfbuzz/src/hb-coretext.h
@@ -43,16 +43,19 @@ HB_BEGIN_DECLS
 #define HB_CORETEXT_TAG_MORT HB_TAG('m','o','r','t')
 #define HB_CORETEXT_TAG_MORX HB_TAG('m','o','r','x')
 #define HB_CORETEXT_TAG_KERX HB_TAG('k','e','r','x')
 
 
 HB_EXTERN hb_face_t *
 hb_coretext_face_create (CGFontRef cg_font);
 
+HB_EXTERN hb_font_t *
+hb_coretext_font_create (CTFontRef ct_font);
+
 
 HB_EXTERN CGFontRef
 hb_coretext_face_get_cg_font (hb_face_t *face);
 
 HB_EXTERN CTFontRef
 hb_coretext_font_get_ct_font (hb_font_t *font);
 
 
--- a/gfx/harfbuzz/src/hb-debug.hh
+++ b/gfx/harfbuzz/src/hb-debug.hh
@@ -216,22 +216,24 @@ static inline void _hb_warn_no_return (b
   }
 }
 template <>
 /*static*/ inline void _hb_warn_no_return<hb_void_t> (bool returned HB_UNUSED)
 {}
 
 template <int max_level, typename ret_t>
 struct hb_auto_trace_t {
+
   explicit inline hb_auto_trace_t (unsigned int *plevel_,
 				   const char *what_,
 				   const void *obj_,
 				   const char *func,
 				   const char *message,
-				   ...) : plevel (plevel_), what (what_), obj (obj_), returned (false)
+				   ...) HB_PRINTF_FUNC(6, 7)
+				   : plevel (plevel_), what (what_), obj (obj_), returned (false)
   {
     if (plevel) ++*plevel;
 
     va_list ap;
     va_start (ap, message);
     _hb_debug_msg_va<max_level> (what, obj, func, true, plevel ? *plevel : 0, +1, message, ap);
     va_end (ap);
   }
@@ -265,17 +267,17 @@ struct hb_auto_trace_t {
   const char *what;
   const void *obj;
   bool returned;
 };
 template <typename ret_t> /* Make sure we don't use hb_auto_trace_t when not tracing. */
 struct hb_auto_trace_t<0, ret_t>;
 
 /* For disabled tracing; optimize out everything.
- * https://github.com/behdad/harfbuzz/pull/605 */
+ * https://github.com/harfbuzz/harfbuzz/pull/605 */
 template <typename ret_t>
 struct hb_no_trace_t {
   inline ret_t ret (ret_t v, unsigned int line HB_UNUSED = 0) { return v; }
 };
 
 #define return_trace(RET) return trace.ret (RET, __LINE__)
 
 
@@ -338,53 +340,53 @@ struct hb_no_trace_t {
 
 #ifndef HB_DEBUG_CLOSURE
 #define HB_DEBUG_CLOSURE (HB_DEBUG+0)
 #endif
 #if HB_DEBUG_CLOSURE
 #define TRACE_CLOSURE(this) \
 	hb_auto_trace_t<HB_DEBUG_CLOSURE, hb_void_t> trace \
 	(&c->debug_depth, c->get_name (), this, HB_FUNC, \
-	 "")
+	 " ")
 #else
 #define TRACE_CLOSURE(this) hb_no_trace_t<hb_void_t> trace HB_UNUSED
 #endif
 
 #ifndef HB_DEBUG_COLLECT_GLYPHS
 #define HB_DEBUG_COLLECT_GLYPHS (HB_DEBUG+0)
 #endif
 #if HB_DEBUG_COLLECT_GLYPHS
 #define TRACE_COLLECT_GLYPHS(this) \
 	hb_auto_trace_t<HB_DEBUG_COLLECT_GLYPHS, hb_void_t> trace \
 	(&c->debug_depth, c->get_name (), this, HB_FUNC, \
-	 "")
+	 " ")
 #else
 #define TRACE_COLLECT_GLYPHS(this) hb_no_trace_t<hb_void_t> trace HB_UNUSED
 #endif
 
 #ifndef HB_DEBUG_SANITIZE
 #define HB_DEBUG_SANITIZE (HB_DEBUG+0)
 #endif
 #if HB_DEBUG_SANITIZE
 #define TRACE_SANITIZE(this) \
 	hb_auto_trace_t<HB_DEBUG_SANITIZE, bool> trace \
 	(&c->debug_depth, c->get_name (), this, HB_FUNC, \
-	 "");
+	 " ");
 #else
 #define TRACE_SANITIZE(this) hb_no_trace_t<bool> trace
 #endif
 
 #ifndef HB_DEBUG_SERIALIZE
 #define HB_DEBUG_SERIALIZE (HB_DEBUG+0)
 #endif
 #if HB_DEBUG_SERIALIZE
 #define TRACE_SERIALIZE(this) \
 	hb_auto_trace_t<HB_DEBUG_SERIALIZE, bool> trace \
 	(&c->debug_depth, "SERIALIZE", c, HB_FUNC, \
-	 "");
+	 " ");
 #else
 #define TRACE_SERIALIZE(this) hb_no_trace_t<bool> trace
 #endif
 
 #ifndef HB_DEBUG_WOULD_APPLY
 #define HB_DEBUG_WOULD_APPLY (HB_DEBUG+0)
 #endif
 #if HB_DEBUG_WOULD_APPLY
--- a/gfx/harfbuzz/src/hb-open-file-private.hh
+++ b/gfx/harfbuzz/src/hb-open-file-private.hh
@@ -59,19 +59,19 @@ typedef struct TableRecord
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this));
   }
 
   Tag		tag;		/* 4-byte identifier. */
   CheckSum	checkSum;	/* CheckSum for this table. */
-  ULONG		offset;		/* Offset from beginning of TrueType font
+  UINT32		offset;		/* Offset from beginning of TrueType font
 				 * file. */
-  ULONG		length;		/* Length of this table. */
+  UINT32		length;		/* Length of this table. */
   public:
   DEFINE_SIZE_STATIC (16);
 } OpenTypeTable;
 
 typedef struct OffsetTable
 {
   friend struct OpenTypeFontFile;
 
@@ -149,17 +149,17 @@ struct TTCHeaderVersion1
     TRACE_SANITIZE (this);
     return_trace (table.sanitize (c, this));
   }
 
   protected:
   Tag		ttcTag;		/* TrueType Collection ID string: 'ttcf' */
   FixedVersion<>version;	/* Version of the TTC Header (1.0),
 				 * 0x00010000u */
-  ArrayOf<LOffsetTo<OffsetTable>, ULONG>
+  ArrayOf<LOffsetTo<OffsetTable>, UINT32>
 		table;		/* Array of offsets to the OffsetTable for each font
 				 * from the beginning of the file */
   public:
   DEFINE_SIZE_ARRAY (12, table);
 };
 
 struct TTCHeader
 {
--- a/gfx/harfbuzz/src/hb-open-type-private.hh
+++ b/gfx/harfbuzz/src/hb-open-type-private.hh
@@ -630,42 +630,41 @@ struct IntType
     return_trace (likely (c->check_struct (this)));
   }
   protected:
   BEInt<Type, Size> v;
   public:
   DEFINE_SIZE_STATIC (Size);
 };
 
-typedef IntType<int8_t,   1> CHAR;	/* 8-bit signed integer. */
-typedef IntType<uint8_t,  1> BYTE;	/* 8-bit unsigned integer. */
+typedef IntType<uint8_t,  1> UINT8;	/* 8-bit unsigned integer. */
 typedef IntType<int8_t,   1> INT8;	/* 8-bit signed integer. */
-typedef IntType<uint16_t, 2> USHORT;	/* 16-bit unsigned integer. */
-typedef IntType<int16_t,  2> SHORT;	/* 16-bit signed integer. */
-typedef IntType<uint32_t, 4> ULONG;	/* 32-bit unsigned integer. */
-typedef IntType<int32_t,  4> LONG;	/* 32-bit signed integer. */
+typedef IntType<uint16_t, 2> UINT16;	/* 16-bit unsigned integer. */
+typedef IntType<int16_t,  2> INT16;	/* 16-bit signed integer. */
+typedef IntType<uint32_t, 4> UINT32;	/* 32-bit unsigned integer. */
+typedef IntType<int32_t,  4> INT32;	/* 32-bit signed integer. */
 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 signed integer (INT16) that describes a quantity in FUnits. */
+typedef INT16 FWORD;
 
-/* 16-bit unsigned integer (USHORT) that describes a quantity in FUnits. */
-typedef USHORT UFWORD;
+/* 16-bit unsigned integer (UINT16) that describes a quantity in FUnits. */
+typedef UINT16 UFWORD;
 
 /* 16-bit signed fixed number with the low 14 bits of fraction (2.14). */
-struct F2DOT14 : SHORT
+struct F2DOT14 : INT16
 {
   //inline float to_float (void) const { return ???; }
   //inline void set_float (float f) { v.set (f * ???); }
   public:
   DEFINE_SIZE_STATIC (2);
 };
 
 /* 32-bit signed fixed-point number (16.16). */
-struct Fixed: LONG
+struct Fixed: INT32
 {
   //inline float to_float (void) const { return ???; }
   //inline void set_float (float f) { v.set (f * ???); }
   public:
   DEFINE_SIZE_STATIC (4);
 };
 
 /* Date represented in number of seconds since 12:00 midnight, January 1,
@@ -673,81 +672,84 @@ struct Fixed: LONG
 struct LONGDATETIME
 {
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (likely (c->check_struct (this)));
   }
   protected:
-  LONG major;
-  ULONG minor;
+  INT32 major;
+  UINT32 minor;
   public:
   DEFINE_SIZE_STATIC (8);
 };
 
 /* Array of four uint8s (length = 32 bits) used to identify a script, language
  * system, feature, or baseline */
-struct Tag : ULONG
+struct Tag : UINT32
 {
   /* What the char* converters return is NOT nul-terminated.  Print using "%.4s" */
   inline operator const char* (void) const { return reinterpret_cast<const char *> (&this->v); }
   inline operator char* (void) { return reinterpret_cast<char *> (&this->v); }
   public:
   DEFINE_SIZE_STATIC (4);
 };
 DEFINE_NULL_DATA (Tag, "    ");
 
 /* Glyph index number, same as uint16 (length = 16 bits) */
-typedef USHORT GlyphID;
+typedef UINT16 GlyphID;
 
 /* Script/language-system/feature index */
-struct Index : USHORT {
+struct Index : UINT16 {
   static const unsigned int NOT_FOUND_INDEX = 0xFFFFu;
 };
 DEFINE_NULL_DATA (Index, "\xff\xff");
 
 /* Offset, Null offset = 0 */
-template <typename Type=USHORT>
+template <typename Type>
 struct Offset : Type
 {
   inline bool is_null (void) const { return 0 == *this; }
   public:
   DEFINE_SIZE_STATIC (sizeof(Type));
 };
 
+typedef Offset<UINT16> Offset16;
+typedef Offset<UINT32> Offset32;
+
 
 /* CheckSum */
-struct CheckSum : ULONG
+struct CheckSum : UINT32
 {
   /* This is reference implementation from the spec. */
-  static inline uint32_t CalcTableChecksum (const ULONG *Table, uint32_t Length)
+  static inline uint32_t CalcTableChecksum (const UINT32 *Table, uint32_t Length)
   {
     uint32_t Sum = 0L;
-    const ULONG *EndPtr = Table+((Length+3) & ~3) / ULONG::static_size;
+    const UINT32 *EndPtr = Table+((Length+3) & ~3) / UINT32::static_size;
 
     while (Table < EndPtr)
       Sum += *Table++;
     return Sum;
   }
 
   /* Note: data should be 4byte aligned and have 4byte padding at the end. */
   inline void set_for_data (const void *data, unsigned int length)
-  { set (CalcTableChecksum ((const ULONG *) data, length)); }
+  { set (CalcTableChecksum ((const UINT32 *) data, length)); }
 
   public:
   DEFINE_SIZE_STATIC (4);
 };
 
 
 /*
  * Version Numbers
  */
 
-template <typename FixedType=USHORT>
+template <typename FixedType=UINT16>
 struct FixedVersion
 {
   inline uint32_t to_int (void) const { return (major << (sizeof(FixedType) * 8)) + minor; }
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this));
@@ -761,17 +763,17 @@ struct FixedVersion
 
 
 
 /*
  * Template subclasses of Offset that do the dereferencing.
  * Use: (base+offset)
  */
 
-template <typename Type, typename OffsetType=USHORT>
+template <typename Type, typename OffsetType=UINT16>
 struct OffsetTo : Offset<OffsetType>
 {
   inline const Type& operator () (const void *base) const
   {
     unsigned int offset = *this;
     if (unlikely (!offset)) return Null(Type);
     return StructAtOffset<Type> (base, offset);
   }
@@ -806,29 +808,29 @@ struct OffsetTo : Offset<OffsetType>
   }
 
   /* Set the offset to Null */
   inline bool neuter (hb_sanitize_context_t *c) const {
     return c->try_set (this, 0);
   }
   DEFINE_SIZE_STATIC (sizeof(OffsetType));
 };
-template <typename Type> struct LOffsetTo : OffsetTo<Type, ULONG> {};
+template <typename Type> struct LOffsetTo : OffsetTo<Type, UINT32> {};
 template <typename Base, typename OffsetType, typename Type>
 static inline const Type& operator + (const Base &base, const OffsetTo<Type, OffsetType> &offset) { return offset (base); }
 template <typename Base, typename OffsetType, typename Type>
 static inline Type& operator + (Base &base, OffsetTo<Type, OffsetType> &offset) { return offset (base); }
 
 
 /*
  * Array Types
  */
 
 /* An array with a number of elements. */
-template <typename Type, typename LenType=USHORT>
+template <typename Type, typename LenType=UINT16>
 struct ArrayOf
 {
   const Type *sub_array (unsigned int start_offset, unsigned int *pcount /* IN/OUT */) const
   {
     unsigned int count = len;
     if (unlikely (start_offset > count))
       count = 0;
     else
@@ -928,20 +930,20 @@ struct ArrayOf
   }
 
   public:
   LenType len;
   Type array[VAR];
   public:
   DEFINE_SIZE_ARRAY (sizeof (LenType), array);
 };
-template <typename Type> struct LArrayOf : ArrayOf<Type, ULONG> {};
+template <typename Type> struct LArrayOf : ArrayOf<Type, UINT32> {};
 
 /* Array of Offset's */
-template <typename Type, typename OffsetType=USHORT>
+template <typename Type, typename OffsetType=UINT16>
 struct OffsetArrayOf : ArrayOf<OffsetTo<Type, OffsetType> > {};
 
 /* Array of offsets relative to the beginning of the array itself. */
 template <typename Type>
 struct OffsetListOf : OffsetArrayOf<Type>
 {
   inline const Type& operator [] (unsigned int i) const
   {
@@ -959,17 +961,17 @@ struct OffsetListOf : OffsetArrayOf<Type
   {
     TRACE_SANITIZE (this);
     return_trace (OffsetArrayOf<Type>::sanitize (c, this, user_data));
   }
 };
 
 
 /* An array starting at second element. */
-template <typename Type, typename LenType=USHORT>
+template <typename Type, typename LenType=UINT16>
 struct HeadlessArrayOf
 {
   inline const Type& operator [] (unsigned int i) const
   {
     if (unlikely (i >= len || !i)) return Null(Type);
     return array[i-1];
   }
   inline unsigned int get_size (void) const
@@ -1021,17 +1023,17 @@ struct HeadlessArrayOf
   public:
   DEFINE_SIZE_ARRAY (sizeof (LenType), array);
 };
 
 
 /*
  * An array with sorted elements.  Supports binary searching.
  */
-template <typename Type, typename LenType=USHORT>
+template <typename Type, typename LenType=UINT16>
 struct SortedArrayOf : ArrayOf<Type, LenType>
 {
   template <typename SearchType>
   inline int bsearch (const SearchType &x) const
   {
     /* Hand-coded bsearch here since this is in the hot inner loop. */
     const Type *array = this->array;
     int min = 0, max = (int) this->len - 1;
@@ -1060,20 +1062,20 @@ struct BinSearchHeader
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this));
   }
 
   protected:
-  USHORT	len;
-  USHORT	searchRangeZ;
-  USHORT	entrySelectorZ;
-  USHORT	rangeShiftZ;
+  UINT16	len;
+  UINT16	searchRangeZ;
+  UINT16	entrySelectorZ;
+  UINT16	rangeShiftZ;
 
   public:
   DEFINE_SIZE_STATIC (8);
 };
 
 template <typename Type>
 struct BinSearchArrayOf : SortedArrayOf<Type, BinSearchHeader> {};
 
--- a/gfx/harfbuzz/src/hb-ot-cbdt-table.hh
+++ b/gfx/harfbuzz/src/hb-ot-cbdt-table.hh
@@ -42,54 +42,54 @@ struct SmallGlyphMetrics
   inline void get_extents (hb_glyph_extents_t *extents) const
   {
     extents->x_bearing = bearingX;
     extents->y_bearing = bearingY;
     extents->width = width;
     extents->height = -height;
   }
 
-  BYTE height;
-  BYTE width;
-  CHAR bearingX;
-  CHAR bearingY;
-  BYTE advance;
+  UINT8 height;
+  UINT8 width;
+  INT8 bearingX;
+  INT8 bearingY;
+  UINT8 advance;
 
   DEFINE_SIZE_STATIC(5);
 };
 
 struct BigGlyphMetrics : SmallGlyphMetrics
 {
-  CHAR vertBearingX;
-  CHAR vertBearingY;
-  BYTE vertAdvance;
+  INT8 vertBearingX;
+  INT8 vertBearingY;
+  UINT8 vertAdvance;
 
   DEFINE_SIZE_STATIC(8);
 };
 
 struct SBitLineMetrics
 {
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this));
   }
 
-  CHAR ascender;
-  CHAR decender;
-  BYTE widthMax;
-  CHAR caretSlopeNumerator;
-  CHAR caretSlopeDenominator;
-  CHAR caretOffset;
-  CHAR minOriginSB;
-  CHAR minAdvanceSB;
-  CHAR maxBeforeBL;
-  CHAR minAfterBL;
-  CHAR padding1;
-  CHAR padding2;
+  INT8 ascender;
+  INT8 decender;
+  UINT8 widthMax;
+  INT8 caretSlopeNumerator;
+  INT8 caretSlopeDenominator;
+  INT8 caretOffset;
+  INT8 minOriginSB;
+  INT8 minAdvanceSB;
+  INT8 maxBeforeBL;
+  INT8 minAfterBL;
+  INT8 padding1;
+  INT8 padding2;
 
   DEFINE_SIZE_STATIC(12);
 };
 
 
 /*
  * Index Subtables.
  */
@@ -97,19 +97,19 @@ struct SBitLineMetrics
 struct IndexSubtableHeader
 {
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this));
   }
 
-  USHORT indexFormat;
-  USHORT imageFormat;
-  ULONG imageDataOffset;
+  UINT16 indexFormat;
+  UINT16 imageFormat;
+  UINT32 imageDataOffset;
 
   DEFINE_SIZE_STATIC(8);
 };
 
 template <typename OffsetType>
 struct IndexSubtableFormat1Or3
 {
   inline bool sanitize (hb_sanitize_context_t *c, unsigned int glyph_count) const
@@ -132,18 +132,18 @@ struct IndexSubtableFormat1Or3
   }
 
   IndexSubtableHeader header;
   Offset<OffsetType> offsetArrayZ[VAR];
 
   DEFINE_SIZE_ARRAY(8, offsetArrayZ);
 };
 
-struct IndexSubtableFormat1 : IndexSubtableFormat1Or3<ULONG> {};
-struct IndexSubtableFormat3 : IndexSubtableFormat1Or3<USHORT> {};
+struct IndexSubtableFormat1 : IndexSubtableFormat1Or3<UINT32> {};
+struct IndexSubtableFormat3 : IndexSubtableFormat1Or3<UINT16> {};
 
 struct IndexSubtable
 {
   inline bool sanitize (hb_sanitize_context_t *c, unsigned int glyph_count) const
   {
     TRACE_SANITIZE (this);
     if (!u.header.sanitize (c)) return_trace (false);
     switch (u.header.indexFormat) {
@@ -209,18 +209,18 @@ struct IndexSubtableRecord
     if (gid < firstGlyphIndex || gid > lastGlyphIndex)
     {
       return false;
     }
     return (this+offsetToSubtable).get_image_data (gid - firstGlyphIndex,
 						   offset, length, format);
   }
 
-  USHORT firstGlyphIndex;
-  USHORT lastGlyphIndex;
+  UINT16 firstGlyphIndex;
+  UINT16 lastGlyphIndex;
   LOffsetTo<IndexSubtable> offsetToSubtable;
 
   DEFINE_SIZE_STATIC(8);
 };
 
 struct IndexSubtableArray
 {
   inline bool sanitize (hb_sanitize_context_t *c, unsigned int count) const
@@ -271,66 +271,68 @@ struct BitmapSizeTable
 
   const IndexSubtableRecord *find_table (hb_codepoint_t glyph, const void *base) const
   {
     return (base+indexSubtableArrayOffset).find_table (glyph, numberOfIndexSubtables);
   }
 
   protected:
   LOffsetTo<IndexSubtableArray> indexSubtableArrayOffset;
-  ULONG indexTablesSize;
-  ULONG numberOfIndexSubtables;
-  ULONG colorRef;
+  UINT32 indexTablesSize;
+  UINT32 numberOfIndexSubtables;
+  UINT32 colorRef;
   SBitLineMetrics horizontal;
   SBitLineMetrics vertical;
-  USHORT startGlyphIndex;
-  USHORT endGlyphIndex;
-  BYTE ppemX;
-  BYTE ppemY;
-  BYTE bitDepth;
-  CHAR flags;
+  UINT16 startGlyphIndex;
+  UINT16 endGlyphIndex;
+  UINT8 ppemX;
+  UINT8 ppemY;
+  UINT8 bitDepth;
+  INT8 flags;
 
-public:
+  public:
   DEFINE_SIZE_STATIC(48);
 };
 
 
 /*
  * Glyph Bitmap Data Formats.
  */
 
 struct GlyphBitmapDataFormat17
 {
   SmallGlyphMetrics glyphMetrics;
-  ULONG dataLen;
-  BYTE dataZ[VAR];
+  UINT32 dataLen;
+  UINT8 dataZ[VAR];
 
   DEFINE_SIZE_ARRAY(9, dataZ);
 };
 
 
 /*
  * CBLC -- Color Bitmap Location Table
  */
 
 #define HB_OT_TAG_CBLC HB_TAG('C','B','L','C')
 
 struct CBLC
 {
+  friend struct CBDT;
+
   static const hb_tag_t tableTag = HB_OT_TAG_CBLC;
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) &&
 		  likely (version.major == 2 || version.major == 3) &&
 		  sizeTables.sanitize (c, this));
   }
 
-  public:
+  protected:
   const IndexSubtableRecord *find_table (hb_codepoint_t glyph,
 					 unsigned int *x_ppem, unsigned int *y_ppem) const
   {
     /* TODO: Make it possible to select strike. */
 
     unsigned int count = sizeTables.len;
     for (uint32_t i = 0; i < count; ++i)
     {
@@ -366,19 +368,104 @@ struct CBDT
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) &&
 		  likely (version.major == 2 || version.major == 3));
   }
 
+  struct accelerator_t
+  {
+    inline void init (hb_face_t *face)
+    {
+      upem = face->get_upem();
+
+      cblc_blob = Sanitizer<CBLC>::sanitize (face->reference_table (HB_OT_TAG_CBLC));
+      cbdt_blob = Sanitizer<CBDT>::sanitize (face->reference_table (HB_OT_TAG_CBDT));
+      cbdt_len = hb_blob_get_length (cbdt_blob);
+
+      if (hb_blob_get_length (cblc_blob) == 0) {
+	cblc = nullptr;
+	cbdt = nullptr;
+	return;  /* Not a bitmap font. */
+      }
+      cblc = Sanitizer<CBLC>::lock_instance (cblc_blob);
+      cbdt = Sanitizer<CBDT>::lock_instance (cbdt_blob);
+
+    }
+
+    inline void fini (void)
+    {
+      hb_blob_destroy (this->cblc_blob);
+      hb_blob_destroy (this->cbdt_blob);
+    }
+
+    inline bool get_extents (hb_codepoint_t glyph, hb_glyph_extents_t *extents) const
+    {
+      unsigned int x_ppem = upem, y_ppem = upem; /* TODO Use font ppem if available. */
+
+      if (!cblc)
+	return false;  // Not a color bitmap font.
+
+      const IndexSubtableRecord *subtable_record = this->cblc->find_table(glyph, &x_ppem, &y_ppem);
+      if (!subtable_record || !x_ppem || !y_ppem)
+	return false;
+
+      if (subtable_record->get_extents (extents))
+	return true;
+
+      unsigned int image_offset = 0, image_length = 0, image_format = 0;
+      if (!subtable_record->get_image_data (glyph, &image_offset, &image_length, &image_format))
+	return false;
+
+      {
+	if (unlikely (image_offset > cbdt_len || cbdt_len - image_offset < image_length))
+	  return false;
+
+	switch (image_format)
+	{
+	  case 17: {
+	    if (unlikely (image_length < GlyphBitmapDataFormat17::min_size))
+	      return false;
+
+	    const GlyphBitmapDataFormat17& glyphFormat17 =
+		StructAtOffset<GlyphBitmapDataFormat17> (this->cbdt, image_offset);
+	    glyphFormat17.glyphMetrics.get_extents (extents);
+	  }
+	  break;
+	  default:
+	    // TODO: Support other image formats.
+	    return false;
+	}
+      }
+
+      /* Convert to the font units. */
+      extents->x_bearing *= upem / (float) x_ppem;
+      extents->y_bearing *= upem / (float) y_ppem;
+      extents->width *= upem / (float) x_ppem;
+      extents->height *= upem / (float) y_ppem;
+
+      return true;
+    }
+
+    private:
+    hb_blob_t *cblc_blob;
+    hb_blob_t *cbdt_blob;
+    const CBLC *cblc;
+    const CBDT *cbdt;
+
+    unsigned int cbdt_len;
+    unsigned int upem;
+  };
+
+
   protected:
   FixedVersion<>version;
-  BYTE dataZ[VAR];
+  UINT8 dataZ[VAR];
 
   public:
   DEFINE_SIZE_ARRAY(4, dataZ);
 };
 
 } /* namespace OT */
 
 #endif /* HB_OT_CBDT_TABLE_HH */
--- a/gfx/harfbuzz/src/hb-ot-cmap-table.hh
+++ b/gfx/harfbuzz/src/hb-ot-cmap-table.hh
@@ -53,20 +53,20 @@ struct CmapSubtableFormat0
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this));
   }
 
   protected:
-  USHORT	format;		/* Format number is set to 0. */
-  USHORT	lengthZ;	/* Byte length of this subtable. */
-  USHORT	languageZ;	/* Ignore. */
-  BYTE		glyphIdArray[256];/* An array that maps character
+  UINT16	format;		/* Format number is set to 0. */
+  UINT16	lengthZ;	/* Byte length of this subtable. */
+  UINT16	languageZ;	/* Ignore. */
+  UINT8		glyphIdArray[256];/* An array that maps character
 				 * code to glyph index values. */
   public:
   DEFINE_SIZE_STATIC (6 + 256);
 };
 
 struct CmapSubtableFormat4
 {
   struct accelerator_t
@@ -83,18 +83,18 @@ struct CmapSubtableFormat4
     }
 
     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;
+      const UINT16 *startCount = thiz->startCount;
+      const UINT16 *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;
@@ -122,21 +122,21 @@ struct CmapSubtableFormat4
 	  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;
+    const UINT16 *endCount;
+    const UINT16 *startCount;
+    const UINT16 *idDelta;
+    const UINT16 *idRangeOffset;
+    const UINT16 *glyphIdArray;
     unsigned int segCount;
     unsigned int glyphIdArrayLength;
   };
 
   inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
   {
     accelerator_t accel;
     accel.init (this);
@@ -160,34 +160,34 @@ struct CmapSubtableFormat4
       if (!c->try_set (&length, new_length))
 	return_trace (false);
     }
 
     return_trace (16 + 4 * (unsigned int) segCountX2 <= length);
   }
 
   protected:
-  USHORT	format;		/* Format number is set to 4. */
-  USHORT	length;		/* This is the length in bytes of the
+  UINT16	format;		/* Format number is set to 4. */
+  UINT16	length;		/* This is the length in bytes of the
 				 * subtable. */
-  USHORT	languageZ;	/* Ignore. */
-  USHORT	segCountX2;	/* 2 x segCount. */
-  USHORT	searchRangeZ;	/* 2 * (2**floor(log2(segCount))) */
-  USHORT	entrySelectorZ;	/* log2(searchRange/2) */
-  USHORT	rangeShiftZ;	/* 2 x segCount - searchRange */
+  UINT16	languageZ;	/* Ignore. */
+  UINT16	segCountX2;	/* 2 x segCount. */
+  UINT16	searchRangeZ;	/* 2 * (2**floor(log2(segCount))) */
+  UINT16	entrySelectorZ;	/* log2(searchRange/2) */
+  UINT16	rangeShiftZ;	/* 2 x segCount - searchRange */
 
-  USHORT	values[VAR];
+  UINT16	values[VAR];
 #if 0
-  USHORT	endCount[segCount];	/* End characterCode for each segment,
+  UINT16	endCount[segCount];	/* End characterCode for each segment,
 					 * last=0xFFFFu. */
-  USHORT	reservedPad;		/* Set to 0. */
-  USHORT	startCount[segCount];	/* Start character code for each segment. */
-  SHORT		idDelta[segCount];	/* Delta for all character codes in segment. */
-  USHORT	idRangeOffset[segCount];/* Offsets into glyphIdArray or 0 */
-  USHORT	glyphIdArray[VAR];	/* Glyph index array (arbitrary length) */
+  UINT16	reservedPad;		/* Set to 0. */
+  UINT16	startCount[segCount];	/* Start character code for each segment. */
+  INT16		idDelta[segCount];	/* Delta for all character codes in segment. */
+  UINT16	idRangeOffset[segCount];/* Offsets into glyphIdArray or 0 */
+  UINT16	glyphIdArray[VAR];	/* Glyph index array (arbitrary length) */
 #endif
 
   public:
   DEFINE_SIZE_ARRAY (14, values);
 };
 
 struct CmapSubtableLongGroup
 {
@@ -203,19 +203,19 @@ struct CmapSubtableLongGroup
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this));
   }
 
   private:
-  ULONG		startCharCode;	/* First character code in this group. */
-  ULONG		endCharCode;	/* Last character code in this group. */
-  ULONG		glyphID;	/* Glyph index; interpretation depends on
+  UINT32		startCharCode;	/* First character code in this group. */
+  UINT32		endCharCode;	/* Last character code in this group. */
+  UINT32		glyphID;	/* Glyph index; interpretation depends on
 				 * subtable format. */
   public:
   DEFINE_SIZE_STATIC (12);
 };
 
 template <typename UINT>
 struct CmapSubtableTrimmed
 {
@@ -242,18 +242,18 @@ struct CmapSubtableTrimmed
   UINT		startCharCode;	/* First character code covered. */
   ArrayOf<GlyphID, UINT>
 		glyphIdArray;	/* Array of glyph index values for character
 				 * codes in the range. */
   public:
   DEFINE_SIZE_ARRAY (5 * sizeof (UINT), glyphIdArray);
 };
 
-struct CmapSubtableFormat6  : CmapSubtableTrimmed<USHORT> {};
-struct CmapSubtableFormat10 : CmapSubtableTrimmed<ULONG > {};
+struct CmapSubtableFormat6  : CmapSubtableTrimmed<UINT16> {};
+struct CmapSubtableFormat10 : CmapSubtableTrimmed<UINT32 > {};
 
 template <typename T>
 struct CmapSubtableLongSegmented
 {
   inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
   {
     int i = groups.bsearch (codepoint);
     if (i == -1)
@@ -264,21 +264,21 @@ struct CmapSubtableLongSegmented
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) && groups.sanitize (c));
   }
 
   protected:
-  USHORT	format;		/* Subtable format; set to 12. */
-  USHORT	reservedZ;	/* Reserved; set to 0. */
-  ULONG		lengthZ;	/* Byte length of this subtable. */
-  ULONG		languageZ;	/* Ignore. */
-  SortedArrayOf<CmapSubtableLongGroup, ULONG>
+  UINT16	format;		/* Subtable format; set to 12. */
+  UINT16	reservedZ;	/* Reserved; set to 0. */
+  UINT32		lengthZ;	/* Byte length of this subtable. */
+  UINT32		languageZ;	/* Ignore. */
+  SortedArrayOf<CmapSubtableLongGroup, UINT32>
 		groups;		/* Groupings. */
   public:
   DEFINE_SIZE_ARRAY (16, groups);
 };
 
 struct CmapSubtableFormat12 : CmapSubtableLongSegmented<CmapSubtableFormat12>
 {
   static inline hb_codepoint_t group_get_glyph (const CmapSubtableLongGroup &group,
@@ -311,23 +311,23 @@ struct UnicodeValueRange
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this));
   }
 
   UINT24	startUnicodeValue;	/* First value in this range. */
-  BYTE		additionalCount;	/* Number of additional values in this
+  UINT8		additionalCount;	/* Number of additional values in this
 					 * range. */
   public:
   DEFINE_SIZE_STATIC (4);
 };
 
-typedef SortedArrayOf<UnicodeValueRange, ULONG> DefaultUVS;
+typedef SortedArrayOf<UnicodeValueRange, UINT32> DefaultUVS;
 
 struct UVSMapping
 {
   inline int cmp (const hb_codepoint_t &codepoint) const
   {
     return unicodeValue.cmp (codepoint);
   }
 
@@ -338,17 +338,17 @@ struct UVSMapping
   }
 
   UINT24	unicodeValue;	/* Base Unicode value of the UVS */
   GlyphID	glyphID;	/* Glyph ID of the UVS */
   public:
   DEFINE_SIZE_STATIC (5);
 };
 
-typedef SortedArrayOf<UVSMapping, ULONG> NonDefaultUVS;
+typedef SortedArrayOf<UVSMapping, UINT32> NonDefaultUVS;
 
 struct VariationSelectorRecord
 {
   inline glyph_variant_t get_glyph (hb_codepoint_t codepoint,
 				    hb_codepoint_t *glyph,
 				    const void *base) const
   {
     int i;
@@ -400,19 +400,19 @@ 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 14. */
-  ULONG		lengthZ;	/* Byte length of this subtable. */
-  SortedArrayOf<VariationSelectorRecord, ULONG>
+  UINT16	format;		/* Format number is set to 14. */
+  UINT32		lengthZ;	/* Byte length of this subtable. */
+  SortedArrayOf<VariationSelectorRecord, UINT32>
 		record;		/* Variation selector records; sorted
 				 * in increasing order of `varSelector'. */
   public:
   DEFINE_SIZE_ARRAY (10, record);
 };
 
 struct CmapSubtable
 {
@@ -446,17 +446,17 @@ struct CmapSubtable
     case 13: return_trace (u.format13.sanitize (c));
     case 14: return_trace (u.format14.sanitize (c));
     default:return_trace (true);
     }
   }
 
   public:
   union {
-  USHORT		format;		/* Format identifier */
+  UINT16		format;		/* Format identifier */
   CmapSubtableFormat0	format0;
   CmapSubtableFormat4	format4;
   CmapSubtableFormat6	format6;
   CmapSubtableFormat10	format10;
   CmapSubtableFormat12	format12;
   CmapSubtableFormat13	format13;
   CmapSubtableFormat14	format14;
   } u;
@@ -479,28 +479,168 @@ struct EncodingRecord
 
   inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) &&
 		  subtable.sanitize (c, base));
   }
 
-  USHORT	platformID;	/* Platform ID. */
-  USHORT	encodingID;	/* Platform-specific encoding ID. */
+  UINT16	platformID;	/* Platform ID. */
+  UINT16	encodingID;	/* Platform-specific encoding ID. */
   LOffsetTo<CmapSubtable>
 		subtable;	/* Byte offset from beginning of table to the subtable for this encoding. */
   public:
   DEFINE_SIZE_STATIC (8);
 };
 
 struct cmap
 {
   static const hb_tag_t tableTag	= HB_OT_TAG_cmap;
 
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) &&
+		  likely (version == 0) &&
+		  encodingRecord.sanitize (c, this));
+  }
+
+  struct accelerator_t
+  {
+    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 = nullptr;
+      const OT::CmapSubtableFormat14 *subtable_uvs = nullptr;
+
+      bool symbol = false;
+      /* 32-bit subtables. */
+      if (!subtable) subtable = cmap->find_subtable (3, 10);
+      if (!subtable) subtable = cmap->find_subtable (0, 6);
+      if (!subtable) subtable = cmap->find_subtable (0, 4);
+      /* 16-bit subtables. */
+      if (!subtable) subtable = cmap->find_subtable (3, 1);
+      if (!subtable) subtable = cmap->find_subtable (0, 3);
+      if (!subtable) subtable = cmap->find_subtable (0, 2);
+      if (!subtable) subtable = cmap->find_subtable (0, 1);
+      if (!subtable) subtable = cmap->find_subtable (0, 0);
+      if (!subtable)
+      {
+	subtable = cmap->find_subtable (3, 0);
+	if (subtable) symbol = true;
+      }
+      /* Meh. */
+      if (!subtable) subtable = &OT::Null(OT::CmapSubtable);
+
+      /* UVS subtable. */
+      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::CmapSubtableFormat14);
+
+      this->uvs_table = subtable_uvs;
+
+      this->get_glyph_data = subtable;
+      if (unlikely (symbol))
+	this->get_glyph_func = get_glyph_from_symbol<OT::CmapSubtable>;
+      else
+	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_nominal_glyph (hb_codepoint_t  unicode,
+				   hb_codepoint_t *glyph) const
+    {
+      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))
+      {
+	case OT::GLYPH_VARIANT_NOT_FOUND:		return false;
+	case OT::GLYPH_VARIANT_FOUND:		return true;
+	case OT::GLYPH_VARIANT_USE_DEFAULT:	break;
+      }
+
+      return get_nominal_glyph (unicode, glyph);
+    }
+
+    protected:
+    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);
+    }
+
+    template <typename Type>
+    static inline bool get_glyph_from_symbol (const void *obj,
+					      hb_codepoint_t codepoint,
+					      hb_codepoint_t *glyph)
+    {
+      const Type *typed_obj = (const Type *) obj;
+      if (likely (typed_obj->get_glyph (codepoint, glyph)))
+	return true;
+
+      if (codepoint <= 0x00FFu)
+      {
+	/* For symbol-encoded OpenType fonts, we duplicate the
+	 * U+F000..F0FF range at U+0000..U+00FF.  That's what
+	 * Windows seems to do, and that's hinted about at:
+	 * http://www.microsoft.com/typography/otspec/recom.htm
+	 * under "Non-Standard (Symbol) Fonts". */
+	return typed_obj->get_glyph (0xF000u + codepoint, glyph);
+      }
+
+      return false;
+    }
+
+    private:
+    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;
+  };
+
+  protected:
+
   inline const CmapSubtable *find_subtable (unsigned int platform_id,
 					    unsigned int encoding_id) const
   {
     EncodingRecord key;
     key.platformID.set (platform_id);
     key.encodingID.set (encoding_id);
 
     /* Note: We can use bsearch, but since it has no performance
@@ -508,25 +648,18 @@ struct cmap
      * unsorted subtable list. */
     int result = encodingRecord./*bsearch*/lsearch (key);
     if (result == -1 || !encodingRecord[result].subtable)
       return nullptr;
 
     return &(this+encodingRecord[result].subtable);
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (c->check_struct (this) &&
-		  likely (version == 0) &&
-		  encodingRecord.sanitize (c, this));
-  }
-
-  USHORT		version;	/* Table version number (0). */
+  protected:
+  UINT16		version;	/* Table version number (0). */
   SortedArrayOf<EncodingRecord>
 			encodingRecord;	/* Encoding tables. */
   public:
   DEFINE_SIZE_ARRAY (4, encodingRecord);
 };
 
 
 } /* namespace OT */
--- a/gfx/harfbuzz/src/hb-ot-font.cc
+++ b/gfx/harfbuzz/src/hb-ot-font.cc
@@ -28,491 +28,44 @@
 
 #include "hb-ot.h"
 
 #include "hb-font-private.hh"
 
 #include "hb-ot-cmap-table.hh"
 #include "hb-ot-cbdt-table.hh"
 #include "hb-ot-glyf-table.hh"
-#include "hb-ot-head-table.hh"
-#include "hb-ot-hhea-table.hh"
 #include "hb-ot-hmtx-table.hh"
 #include "hb-ot-kern-table.hh"
-#include "hb-ot-os2-table.hh"
 #include "hb-ot-post-table.hh"
-#include "hb-ot-var-hvar-table.hh"
-
-
-struct hb_ot_face_metrics_accelerator_t
-{
-  unsigned int num_metrics;
-  unsigned int num_advances;
-  unsigned int default_advance;
-  unsigned short ascender;
-  unsigned short descender;
-  unsigned short line_gap;
-  bool has_font_extents;
-
-  const OT::hmtxvmtx *table;
-  hb_blob_t *blob;
-
-  const OT::HVARVVAR *var;
-  hb_blob_t *var_blob;
-
-  inline void init (hb_face_t *face,
-		    hb_tag_t _hea_tag,
-		    hb_tag_t _mtx_tag,
-		    hb_tag_t _var_tag,
-		    hb_tag_t os2_tag,
-		    unsigned int default_advance = 0)
-  {
-    this->default_advance = default_advance ? default_advance : face->get_upem ();
-
-    bool got_font_extents = false;
-    if (os2_tag)
-    {
-      hb_blob_t *os2_blob = OT::Sanitizer<OT::os2>::sanitize (face->reference_table (os2_tag));
-      const OT::os2 *os2 = OT::Sanitizer<OT::os2>::lock_instance (os2_blob);
-#define USE_TYPO_METRICS (1u<<7)
-      if (0 != (os2->fsSelection & USE_TYPO_METRICS))
-      {
-	this->ascender = os2->sTypoAscender;
-	this->descender = os2->sTypoDescender;
-	this->line_gap = os2->sTypoLineGap;
-	got_font_extents = (this->ascender | this->descender) != 0;
-      }
-      hb_blob_destroy (os2_blob);
-    }
-
-    hb_blob_t *_hea_blob = OT::Sanitizer<OT::_hea>::sanitize (face->reference_table (_hea_tag));
-    const OT::_hea *_hea = OT::Sanitizer<OT::_hea>::lock_instance (_hea_blob);
-    this->num_advances = _hea->numberOfLongMetrics;
-    if (!got_font_extents)
-    {
-      this->ascender = _hea->ascender;
-      this->descender = _hea->descender;
-      this->line_gap = _hea->lineGap;
-      got_font_extents = (this->ascender | this->descender) != 0;
-    }
-    hb_blob_destroy (_hea_blob);
-
-    this->has_font_extents = got_font_extents;
-
-    this->blob = OT::Sanitizer<OT::hmtxvmtx>::sanitize (face->reference_table (_mtx_tag));
-
-    /* Cap num_metrics() and num_advances() based on table length. */
-    unsigned int len = hb_blob_get_length (this->blob);
-    if (unlikely (this->num_advances * 4 > len))
-      this->num_advances = len / 4;
-    this->num_metrics = this->num_advances + (len - 4 * this->num_advances) / 2;
-
-    /* We MUST set num_metrics to zero if num_advances is zero.
-     * Our get_advance() depends on that. */
-    if (unlikely (!this->num_advances))
-    {
-      this->num_metrics = this->num_advances = 0;
-      hb_blob_destroy (this->blob);
-      this->blob = hb_blob_get_empty ();
-    }
-    this->table = OT::Sanitizer<OT::hmtxvmtx>::lock_instance (this->blob);
-
-    this->var_blob = OT::Sanitizer<OT::HVARVVAR>::sanitize (face->reference_table (_var_tag));
-    this->var = OT::Sanitizer<OT::HVARVVAR>::lock_instance (this->var_blob);
-  }
-
-  inline void fini (void)
-  {
-    hb_blob_destroy (this->blob);
-    hb_blob_destroy (this->var_blob);
-  }
-
-  inline unsigned int get_advance (hb_codepoint_t  glyph,
-				   hb_font_t      *font) const
-  {
-    if (unlikely (glyph >= this->num_metrics))
-    {
-      /* If this->num_metrics is zero, it means we don't have the metrics table
-       * for this direction: return default advance.  Otherwise, it means that the
-       * glyph index is out of bound: return zero. */
-      if (this->num_metrics)
-	return 0;
-      else
-	return this->default_advance;
-    }
-
-    return this->table->longMetric[MIN (glyph, (uint32_t) this->num_advances - 1)].advance
-	 + this->var->get_advance_var (glyph, font->coords, font->num_coords); // TODO Optimize?!
-  }
-};
-
-struct hb_ot_face_glyf_accelerator_t
-{
-  bool short_offset;
-  unsigned int num_glyphs;
-  const OT::loca *loca;
-  const OT::glyf *glyf;
-  hb_blob_t *loca_blob;
-  hb_blob_t *glyf_blob;
-  unsigned int glyf_len;
-
-  inline void init (hb_face_t *face)
-  {
-    hb_blob_t *head_blob = OT::Sanitizer<OT::head>::sanitize (face->reference_table (HB_OT_TAG_head));
-    const OT::head *head = OT::Sanitizer<OT::head>::lock_instance (head_blob);
-    if ((unsigned int) head->indexToLocFormat > 1 || head->glyphDataFormat != 0)
-    {
-      /* Unknown format.  Leave num_glyphs=0, that takes care of disabling us. */
-      hb_blob_destroy (head_blob);
-      return;
-    }
-    this->short_offset = 0 == head->indexToLocFormat;
-    hb_blob_destroy (head_blob);
-
-    this->loca_blob = OT::Sanitizer<OT::loca>::sanitize (face->reference_table (HB_OT_TAG_loca));
-    this->loca = OT::Sanitizer<OT::loca>::lock_instance (this->loca_blob);
-    this->glyf_blob = OT::Sanitizer<OT::glyf>::sanitize (face->reference_table (HB_OT_TAG_glyf));
-    this->glyf = OT::Sanitizer<OT::glyf>::lock_instance (this->glyf_blob);
-
-    this->num_glyphs = MAX (1u, hb_blob_get_length (this->loca_blob) / (this->short_offset ? 2 : 4)) - 1;
-    this->glyf_len = hb_blob_get_length (this->glyf_blob);
-  }
-
-  inline void fini (void)
-  {
-    hb_blob_destroy (this->loca_blob);
-    hb_blob_destroy (this->glyf_blob);
-  }
-
-  inline bool get_extents (hb_codepoint_t glyph,
-			   hb_glyph_extents_t *extents) const
-  {
-    if (unlikely (glyph >= this->num_glyphs))
-      return false;
-
-    unsigned int start_offset, end_offset;
-    if (this->short_offset)
-    {
-      start_offset = 2 * this->loca->u.shortsZ[glyph];
-      end_offset   = 2 * this->loca->u.shortsZ[glyph + 1];
-    }
-    else
-    {
-      start_offset = this->loca->u.longsZ[glyph];
-      end_offset   = this->loca->u.longsZ[glyph + 1];
-    }
-
-    if (start_offset > end_offset || end_offset > this->glyf_len)
-      return false;
-
-    if (end_offset - start_offset < OT::glyfGlyphHeader::static_size)
-      return true; /* Empty glyph; zero extents. */
-
-    const OT::glyfGlyphHeader &glyph_header = OT::StructAtOffset<OT::glyfGlyphHeader> (this->glyf, start_offset);
-
-    extents->x_bearing = MIN (glyph_header.xMin, glyph_header.xMax);
-    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;
-  }
-};
-
-struct hb_ot_face_cbdt_accelerator_t
-{
-  hb_blob_t *cblc_blob;
-  hb_blob_t *cbdt_blob;
-  const OT::CBLC *cblc;
-  const OT::CBDT *cbdt;
-
-  unsigned int cbdt_len;
-  unsigned int upem;
-
-  inline void init (hb_face_t *face)
-  {
-    upem = face->get_upem();
-
-    cblc_blob = OT::Sanitizer<OT::CBLC>::sanitize (face->reference_table (HB_OT_TAG_CBLC));
-    cbdt_blob = OT::Sanitizer<OT::CBDT>::sanitize (face->reference_table (HB_OT_TAG_CBDT));
-    cbdt_len = hb_blob_get_length (cbdt_blob);
-
-    if (hb_blob_get_length (cblc_blob) == 0) {
-      cblc = nullptr;
-      cbdt = nullptr;
-      return;  /* Not a bitmap font. */
-    }
-    cblc = OT::Sanitizer<OT::CBLC>::lock_instance (cblc_blob);
-    cbdt = OT::Sanitizer<OT::CBDT>::lock_instance (cbdt_blob);
-
-  }
-
-  inline void fini (void)
-  {
-    hb_blob_destroy (this->cblc_blob);
-    hb_blob_destroy (this->cbdt_blob);
-  }
-
-  inline bool get_extents (hb_codepoint_t glyph, hb_glyph_extents_t *extents) const
-  {
-    unsigned int x_ppem = upem, y_ppem = upem; /* TODO Use font ppem if available. */
-
-    if (!cblc)
-      return false;  // Not a color bitmap font.
 
-    const OT::IndexSubtableRecord *subtable_record = this->cblc->find_table(glyph, &x_ppem, &y_ppem);
-    if (!subtable_record || !x_ppem || !y_ppem)
-      return false;
-
-    if (subtable_record->get_extents (extents))
-      return true;
-
-    unsigned int image_offset = 0, image_length = 0, image_format = 0;
-    if (!subtable_record->get_image_data (glyph, &image_offset, &image_length, &image_format))
-      return false;
-
-    {
-      /* TODO Move the following into CBDT struct when adding more formats. */
-
-      if (unlikely (image_offset > cbdt_len || cbdt_len - image_offset < image_length))
-	return false;
-
-      switch (image_format)
-      {
-	case 17: {
-	  if (unlikely (image_length < OT::GlyphBitmapDataFormat17::min_size))
-	    return false;
-
-	  const OT::GlyphBitmapDataFormat17& glyphFormat17 =
-	      OT::StructAtOffset<OT::GlyphBitmapDataFormat17> (this->cbdt, image_offset);
-	  glyphFormat17.glyphMetrics.get_extents (extents);
-	}
-	break;
-	default:
-	  // TODO: Support other image formats.
-	  return false;
-      }
-    }
-
-    /* Convert to the font units. */
-    extents->x_bearing *= upem / (float) x_ppem;
-    extents->y_bearing *= upem / (float) y_ppem;
-    extents->width *= upem / (float) x_ppem;
-    extents->height *= upem / (float) y_ppem;
-
-    return true;
-  }
-};
-
-struct hb_ot_face_post_accelerator_t
-{
-  hb_blob_t *post_blob;
-  OT::post::accelerator_t accel;
-
-  inline void init (hb_face_t *face)
-  {
-    hb_blob_t *blob = this->post_blob = OT::Sanitizer<OT::post>::sanitize (face->reference_table (HB_OT_TAG_post));
-    accel.init (OT::Sanitizer<OT::post>::lock_instance (blob), hb_blob_get_length (blob));
-  }
-
-  inline void fini (void)
-  {
-    accel.fini ();
-    hb_blob_destroy (this->post_blob);
-  }
-
-  inline bool get_glyph_name (hb_codepoint_t glyph,
-			      char *name, unsigned int size) const
-  {
-    return this->accel.get_glyph_name (glyph, name, size);
-  }
-
-  inline bool get_glyph_from_name (const char *name, int len,
-				   hb_codepoint_t *glyph) const
-  {
-    if (unlikely (!len))
-      return false;
-
-    return this->accel.get_glyph_from_name (name, len, glyph);
-  }
-};
-
-struct hb_ot_face_kern_accelerator_t
-{
-  hb_blob_t *kern_blob;
-  OT::kern::accelerator_t accel;
-
-  inline void init (hb_face_t *face)
-  {
-    hb_blob_t *blob = this->kern_blob = OT::Sanitizer<OT::kern>::sanitize (face->reference_table (HB_OT_TAG_kern));
-    accel.init (OT::Sanitizer<OT::kern>::lock_instance (blob), hb_blob_get_length (blob));
-  }
-
-  inline void fini (void)
-  {
-    accel.fini ();
-    hb_blob_destroy (this->kern_blob);
-  }
-
-  inline int get_h_kerning (hb_codepoint_t left, hb_codepoint_t right) const
-  { return accel.get_h_kerning (left, right); }
-};
-
-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);
-}
-
-template <typename Type>
-static inline bool get_glyph_from_symbol (const void *obj,
-					  hb_codepoint_t codepoint,
-					  hb_codepoint_t *glyph)
-{
-  const Type *typed_obj = (const Type *) obj;
-  if (likely (typed_obj->get_glyph (codepoint, glyph)))
-    return true;
-
-  if (codepoint <= 0x00FFu)
-  {
-    /* For symbol-encoded OpenType fonts, we duplicate the
-     * U+F000..F0FF range at U+0000..U+00FF.  That's what
-     * Windows seems to do, and that's hinted about at:
-     * http://www.microsoft.com/typography/otspec/recom.htm
-     * under "Non-Standard (Symbol) Fonts". */
-    return typed_obj->get_glyph (0xF000u + codepoint, glyph);
-  }
-
-  return false;
-}
-
-struct hb_ot_face_cmap_accelerator_t
-{
-  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 = nullptr;
-    const OT::CmapSubtableFormat14 *subtable_uvs = nullptr;
-
-    bool symbol = false;
-    /* 32-bit subtables. */
-    if (!subtable) subtable = cmap->find_subtable (3, 10);
-    if (!subtable) subtable = cmap->find_subtable (0, 6);
-    if (!subtable) subtable = cmap->find_subtable (0, 4);
-    /* 16-bit subtables. */
-    if (!subtable) subtable = cmap->find_subtable (3, 1);
-    if (!subtable) subtable = cmap->find_subtable (0, 3);
-    if (!subtable) subtable = cmap->find_subtable (0, 2);
-    if (!subtable) subtable = cmap->find_subtable (0, 1);
-    if (!subtable) subtable = cmap->find_subtable (0, 0);
-    if (!subtable)
-    {
-      subtable = cmap->find_subtable (3, 0);
-      if (subtable) symbol = true;
-    }
-    /* Meh. */
-    if (!subtable) subtable = &OT::Null(OT::CmapSubtable);
-
-    /* UVS subtable. */
-    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::CmapSubtableFormat14);
-
-    this->uvs_table = subtable_uvs;
-
-    this->get_glyph_data = subtable;
-    if (unlikely (symbol))
-      this->get_glyph_func = get_glyph_from_symbol<OT::CmapSubtable>;
-    else
-      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_nominal_glyph (hb_codepoint_t  unicode,
-				 hb_codepoint_t *glyph) const
-  {
-    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))
-    {
-      case OT::GLYPH_VARIANT_NOT_FOUND:		return false;
-      case OT::GLYPH_VARIANT_FOUND:		return true;
-      case OT::GLYPH_VARIANT_USE_DEFAULT:	break;
-    }
-
-    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;
-  hb_ot_face_metrics_accelerator_t v_metrics;
-  OT::hb_lazy_loader_t<hb_ot_face_glyf_accelerator_t> glyf;
-  OT::hb_lazy_loader_t<hb_ot_face_cbdt_accelerator_t> cbdt;
-  OT::hb_lazy_loader_t<hb_ot_face_post_accelerator_t> post;
-  OT::hb_lazy_loader_t<hb_ot_face_kern_accelerator_t> kern;
+  OT::cmap::accelerator_t cmap;
+  OT::hmtx::accelerator_t h_metrics;
+  OT::vmtx::accelerator_t v_metrics;
+  OT::hb_lazy_loader_t<OT::glyf::accelerator_t> glyf;
+  OT::hb_lazy_loader_t<OT::CBDT::accelerator_t> cbdt;
+  OT::hb_lazy_loader_t<OT::post::accelerator_t> post;
+  OT::hb_lazy_loader_t<OT::kern::accelerator_t> kern;
 };
 
 
 static hb_ot_font_t *
 _hb_ot_font_create (hb_face_t *face)
 {
   hb_ot_font_t *ot_font = (hb_ot_font_t *) calloc (1, sizeof (hb_ot_font_t));
 
   if (unlikely (!ot_font))
     return nullptr;
 
   ot_font->cmap.init (face);
-  ot_font->h_metrics.init (face, HB_OT_TAG_hhea, HB_OT_TAG_hmtx, HB_OT_TAG_HVAR, HB_OT_TAG_os2);
-  ot_font->v_metrics.init (face, HB_OT_TAG_vhea, HB_OT_TAG_vmtx, HB_OT_TAG_VVAR, HB_TAG_NONE,
-			   ot_font->h_metrics.ascender - ot_font->h_metrics.descender); /* TODO Can we do this lazily? */
+  ot_font->h_metrics.init (face);
+  ot_font->v_metrics.init (face, ot_font->h_metrics.ascender - ot_font->h_metrics.descender); /* TODO Can we do this lazily? */
   ot_font->glyf.init (face);
   ot_font->cbdt.init (face);
   ot_font->post.init (face);
   ot_font->kern.init (face);
 
   return ot_font;
 }
 
@@ -683,17 +236,17 @@ retry:
     hb_font_funcs_set_variation_glyph_func (funcs, hb_ot_get_variation_glyph, nullptr, nullptr);
     hb_font_funcs_set_glyph_h_advance_func (funcs, hb_ot_get_glyph_h_advance, nullptr, nullptr);
     hb_font_funcs_set_glyph_v_advance_func (funcs, hb_ot_get_glyph_v_advance, nullptr, nullptr);
     //hb_font_funcs_set_glyph_h_origin_func (funcs, hb_ot_get_glyph_h_origin, nullptr, nullptr);
     //hb_font_funcs_set_glyph_v_origin_func (funcs, hb_ot_get_glyph_v_origin, nullptr, nullptr);
     hb_font_funcs_set_glyph_h_kerning_func (funcs, hb_ot_get_glyph_h_kerning, nullptr, nullptr);
     //hb_font_funcs_set_glyph_v_kerning_func (funcs, hb_ot_get_glyph_v_kerning, nullptr, nullptr);
     hb_font_funcs_set_glyph_extents_func (funcs, hb_ot_get_glyph_extents, nullptr, nullptr);
-    //hb_font_funcs_set_glyph_contour_point_func (funcs, hb_ot_get_glyph_contour_point, nullptr, nullptr); TODO
+    //hb_font_funcs_set_glyph_contour_point_func (funcs, hb_ot_get_glyph_contour_point, nullptr, nullptr);
     hb_font_funcs_set_glyph_name_func (funcs, hb_ot_get_glyph_name, nullptr, nullptr);
     hb_font_funcs_set_glyph_from_name_func (funcs, hb_ot_get_glyph_from_name, nullptr, nullptr);
 
     hb_font_funcs_make_immutable (funcs);
 
     if (!hb_atomic_ptr_cmpexch (&static_ot_funcs, nullptr, funcs)) {
       hb_font_funcs_destroy (funcs);
       goto retry;
--- a/gfx/harfbuzz/src/hb-ot-glyf-table.hh
+++ b/gfx/harfbuzz/src/hb-ot-glyf-table.hh
@@ -23,44 +23,44 @@
  *
  * Google Author(s): Behdad Esfahbod
  */
 
 #ifndef HB_OT_GLYF_TABLE_HH
 #define HB_OT_GLYF_TABLE_HH
 
 #include "hb-open-type-private.hh"
+#include "hb-ot-head-table.hh"
 
 
 namespace OT {
 
 
 /*
  * loca -- Index to Location
  */
 
 #define HB_OT_TAG_loca HB_TAG('l','o','c','a')
 
 
 struct loca
 {
+  friend struct glyf;
+
   static const hb_tag_t tableTag = HB_OT_TAG_loca;
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (true);
   }
 
-  public:
-  union {
-    USHORT	shortsZ[VAR];		/* Location offset divided by 2. */
-    ULONG	longsZ[VAR];		/* Location offset. */
-  } u;
-  DEFINE_SIZE_ARRAY (0, u.longsZ);
+  protected:
+  UINT8		dataX[VAR];		/* Location data. */
+  DEFINE_SIZE_ARRAY (0, dataX);
 };
 
 
 /*
  * glyf -- TrueType Glyph Data
  */
 
 #define HB_OT_TAG_glyf HB_TAG('g','l','y','f')
@@ -73,32 +73,108 @@ struct glyf
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     /* We don't check for anything specific here.  The users of the
      * struct do all the hard work... */
     return_trace (true);
   }
 
-  public:
-  BYTE		dataX[VAR];		/* Glyphs data. */
+  struct GlyphHeader
+  {
+    INT16		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. */
+    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);
+  };
+
+  struct accelerator_t
+  {
+    inline void init (hb_face_t *face)
+    {
+      hb_blob_t *head_blob = Sanitizer<head>::sanitize (face->reference_table (HB_OT_TAG_head));
+      const head *head_table = Sanitizer<head>::lock_instance (head_blob);
+      if ((unsigned int) head_table->indexToLocFormat > 1 || head_table->glyphDataFormat != 0)
+      {
+	/* Unknown format.  Leave num_glyphs=0, that takes care of disabling us. */
+	hb_blob_destroy (head_blob);
+	return;
+      }
+      short_offset = 0 == head_table->indexToLocFormat;
+      hb_blob_destroy (head_blob);
+
+      loca_blob = Sanitizer<loca>::sanitize (face->reference_table (HB_OT_TAG_loca));
+      loca_table = Sanitizer<loca>::lock_instance (loca_blob);
+      glyf_blob = Sanitizer<glyf>::sanitize (face->reference_table (HB_OT_TAG_glyf));
+      glyf_table = Sanitizer<glyf>::lock_instance (glyf_blob);
+
+      num_glyphs = MAX (1u, hb_blob_get_length (loca_blob) / (short_offset ? 2 : 4)) - 1;
+      glyf_len = hb_blob_get_length (glyf_blob);
+    }
+
+    inline void fini (void)
+    {
+      hb_blob_destroy (loca_blob);
+      hb_blob_destroy (glyf_blob);
+    }
+
+    inline bool get_extents (hb_codepoint_t glyph,
+			     hb_glyph_extents_t *extents) const
+    {
+      if (unlikely (glyph >= num_glyphs))
+	return false;
+
+      unsigned int start_offset, end_offset;
+      if (short_offset)
+      {
+        const UINT16 *offsets = (const UINT16 *) loca_table->dataX;
+	start_offset = 2 * offsets[glyph];
+	end_offset   = 2 * offsets[glyph + 1];
+      }
+      else
+      {
+        const UINT32 *offsets = (const UINT32 *) loca_table->dataX;
+	start_offset = offsets[glyph];
+	end_offset   = offsets[glyph + 1];
+      }
+
+      if (start_offset > end_offset || end_offset > glyf_len)
+	return false;
+
+      if (end_offset - start_offset < GlyphHeader::static_size)
+	return true; /* Empty glyph; zero extents. */
+
+      const GlyphHeader &glyph_header = StructAtOffset<GlyphHeader> (glyf_table, start_offset);
+
+      extents->x_bearing = MIN (glyph_header.xMin, glyph_header.xMax);
+      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;
+    }
+
+    private:
+    bool short_offset;
+    unsigned int num_glyphs;
+    const loca *loca_table;
+    const glyf *glyf_table;
+    hb_blob_t *loca_blob;
+    hb_blob_t *glyf_blob;
+    unsigned int glyf_len;
+  };
+
+  protected:
+  UINT8		dataX[VAR];		/* Glyphs data. */
 
   DEFINE_SIZE_ARRAY (0, dataX);
 };
 
-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. */
-  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-head-table.hh
+++ b/gfx/harfbuzz/src/hb-ot-head-table.hh
@@ -59,21 +59,21 @@ struct head
 		  version.major == 1 &&
 		  magicNumber == 0x5F0F3CF5u);
   }
 
   protected:
   FixedVersion<>version;		/* Version of the head table--currently
 					 * 0x00010000u for version 1.0. */
   FixedVersion<>fontRevision;		/* Set by font manufacturer. */
-  ULONG		checkSumAdjustment;	/* To compute: set it to 0, sum the
-					 * entire font as ULONG, then store
+  UINT32		checkSumAdjustment;	/* To compute: set it to 0, sum the
+					 * entire font as UINT32, then store
 					 * 0xB1B0AFBAu - sum. */
-  ULONG		magicNumber;		/* Set to 0x5F0F3CF5u. */
-  USHORT	flags;			/* Bit 0: Baseline for font at y=0;
+  UINT32		magicNumber;		/* Set to 0x5F0F3CF5u. */
+  UINT16	flags;			/* Bit 0: Baseline for font at y=0;
 					 * Bit 1: Left sidebearing point at x=0;
 					 * Bit 2: Instructions may depend on point size;
 					 * Bit 3: Force ppem to integer values for all
 					 *   internal scaler math; may use fractional
 					 *   ppem sizes if this bit is clear;
 					 * Bit 4: Instructions may alter advance width
 					 *   (the advance widths might not scale linearly);
 
@@ -109,45 +109,45 @@ struct head
 					 * Bit 14: Last Resort font. If set, indicates that
 					 * the glyphs encoded in the cmap subtables are simply
 					 * generic symbolic representations of code point
 					 * ranges and don’t truly represent support for those
 					 * code points. If unset, indicates that the glyphs
 					 * encoded in the cmap subtables represent proper
 					 * support for those code points.
 					 * Bit 15: Reserved, set to 0. */
-  USHORT	unitsPerEm;		/* Valid range is from 16 to 16384. This value
+  UINT16	unitsPerEm;		/* Valid range is from 16 to 16384. This value
 					 * should be a power of 2 for fonts that have
 					 * TrueType outlines. */
   LONGDATETIME	created;		/* Number of seconds since 12:00 midnight,
 					   January 1, 1904. 64-bit integer */
   LONGDATETIME	modified;		/* Number of seconds since 12:00 midnight,
 					   January 1, 1904. 64-bit integer */
-  SHORT		xMin;			/* For all glyph bounding boxes. */
-  SHORT		yMin;			/* For all glyph bounding boxes. */
-  SHORT		xMax;			/* For all glyph bounding boxes. */
-  SHORT		yMax;			/* For all glyph bounding boxes. */
-  USHORT	macStyle;		/* Bit 0: Bold (if set to 1);
+  INT16		xMin;			/* For all glyph bounding boxes. */
+  INT16		yMin;			/* For all glyph bounding boxes. */
+  INT16		xMax;			/* For all glyph bounding boxes. */
+  INT16		yMax;			/* For all glyph bounding boxes. */
+  UINT16	macStyle;		/* Bit 0: Bold (if set to 1);
 					 * Bit 1: Italic (if set to 1)
 					 * Bit 2: Underline (if set to 1)
 					 * Bit 3: Outline (if set to 1)
 					 * Bit 4: Shadow (if set to 1)
 					 * Bit 5: Condensed (if set to 1)
 					 * Bit 6: Extended (if set to 1)
 					 * Bits 7-15: Reserved (set to 0). */
-  USHORT	lowestRecPPEM;		/* Smallest readable size in pixels. */
-  SHORT		fontDirectionHint;	/* Deprecated (Set to 2).
+  UINT16	lowestRecPPEM;		/* Smallest readable size in pixels. */
+  INT16		fontDirectionHint;	/* Deprecated (Set to 2).
 					 * 0: Fully mixed directional glyphs;
 					 * 1: Only strongly left to right;
 					 * 2: Like 1 but also contains neutrals;
 					 * -1: Only strongly right to left;
 					 * -2: Like -1 but also contains neutrals. */
   public:
-  SHORT		indexToLocFormat;	/* 0 for short offsets, 1 for long. */
-  SHORT		glyphDataFormat;	/* 0 for current format. */
+  INT16		indexToLocFormat;	/* 0 for short offsets, 1 for long. */
+  INT16		glyphDataFormat;	/* 0 for current format. */
 
   DEFINE_SIZE_STATIC (54);
 };
 
 
 } /* namespace OT */
 
 
--- a/gfx/harfbuzz/src/hb-ot-hhea-table.hh
+++ b/gfx/harfbuzz/src/hb-ot-hhea-table.hh
@@ -39,21 +39,16 @@ namespace OT {
  */
 
 #define HB_OT_TAG_hhea HB_TAG('h','h','e','a')
 #define HB_OT_TAG_vhea HB_TAG('v','h','e','a')
 
 
 struct _hea
 {
-  static const hb_tag_t tableTag = HB_TAG('_','h','e','a');
-
-  static const hb_tag_t hheaTag	= HB_OT_TAG_hhea;
-  static const hb_tag_t vheaTag	= HB_OT_TAG_vhea;
-
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) && likely (version.major == 1));
   }
 
   public:
   FixedVersion<>version;		/* 0x00010000u for version 1.0. */
@@ -64,31 +59,31 @@ struct _hea
 					 * metrics table. */
   FWORD		minLeadingBearing;	/* Minimum left/top sidebearing value in
 					 * metrics table. */
   FWORD		minTrailingBearing;	/* Minimum right/bottom sidebearing value;
 					 * calculated as Min(aw - lsb -
 					 * (xMax - xMin)) for horizontal. */
   FWORD		maxExtent;		/* horizontal: Max(lsb + (xMax - xMin)),
 					 * vertical: minLeadingBearing+(yMax-yMin). */
-  SHORT		caretSlopeRise;		/* Used to calculate the slope of the
+  INT16		caretSlopeRise;		/* Used to calculate the slope of the
 					 * cursor (rise/run); 1 for vertical caret,
 					 * 0 for horizontal.*/
-  SHORT		caretSlopeRun;		/* 0 for vertical caret, 1 for horizontal. */
-  SHORT		caretOffset;		/* The amount by which a slanted
+  INT16		caretSlopeRun;		/* 0 for vertical caret, 1 for horizontal. */
+  INT16		caretOffset;		/* The amount by which a slanted
 					 * highlight on a glyph needs
 					 * to be shifted to produce the
 					 * best appearance. Set to 0 for
 					 * non-slanted fonts. */
-  SHORT		reserved1;		/* Set to 0. */
-  SHORT		reserved2;		/* Set to 0. */
-  SHORT		reserved3;		/* Set to 0. */
-  SHORT		reserved4;		/* Set to 0. */
-  SHORT		metricDataFormat;	/* 0 for current format. */
-  USHORT	numberOfLongMetrics;	/* Number of LongMetric entries in metric
+  INT16		reserved1;		/* Set to 0. */
+  INT16		reserved2;		/* Set to 0. */
+  INT16		reserved3;		/* Set to 0. */
+  INT16		reserved4;		/* Set to 0. */
+  INT16		metricDataFormat;	/* 0 for current format. */
+  UINT16	numberOfLongMetrics;	/* Number of LongMetric entries in metric
 					 * table. */
   public:
   DEFINE_SIZE_STATIC (36);
 };
 
 struct hhea : _hea {
   static const hb_tag_t tableTag	= HB_OT_TAG_hhea;
 };
--- a/gfx/harfbuzz/src/hb-ot-hmtx-table.hh
+++ b/gfx/harfbuzz/src/hb-ot-hmtx-table.hh
@@ -23,16 +23,19 @@
  *
  * Google Author(s): Behdad Esfahbod
  */
 
 #ifndef HB_OT_HMTX_TABLE_HH
 #define HB_OT_HMTX_TABLE_HH
 
 #include "hb-open-type-private.hh"
+#include "hb-ot-hhea-table.hh"
+#include "hb-ot-os2-table.hh"
+#include "hb-ot-var-hvar-table.hh"
 
 
 namespace OT {
 
 
 /*
  * hmtx -- The Horizontal Metrics Table
  * vmtx -- The Vertical Metrics Table
@@ -45,30 +48,128 @@ namespace OT {
 struct LongMetric
 {
   UFWORD	advance; /* Advance width/height. */
   FWORD		lsb; /* Leading (left/top) side bearing. */
   public:
   DEFINE_SIZE_STATIC (4);
 };
 
+template <typename T>
 struct hmtxvmtx
 {
-  static const hb_tag_t hmtxTag	= HB_OT_TAG_hmtx;
-  static const hb_tag_t vmtxTag	= HB_OT_TAG_vmtx;
-
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     /* We don't check for anything specific here.  The users of the
      * struct do all the hard work... */
     return_trace (true);
   }
 
-  public:
+  struct accelerator_t
+  {
+    inline void init (hb_face_t *face,
+		      unsigned int default_advance_ = 0)
+    {
+      default_advance = default_advance_ ? default_advance_ : face->get_upem ();
+
+      bool got_font_extents = false;
+      if (T::os2Tag)
+      {
+	hb_blob_t *os2_blob = Sanitizer<os2>::sanitize (face->reference_table (T::os2Tag));
+	const os2 *os2_table = Sanitizer<os2>::lock_instance (os2_blob);
+#define USE_TYPO_METRICS (1u<<7)
+	if (0 != (os2_table->fsSelection & USE_TYPO_METRICS))
+	{
+	  ascender = os2_table->sTypoAscender;
+	  descender = os2_table->sTypoDescender;
+	  line_gap = os2_table->sTypoLineGap;
+	  got_font_extents = (ascender | descender) != 0;
+	}
+	hb_blob_destroy (os2_blob);
+      }
+
+      hb_blob_t *_hea_blob = Sanitizer<_hea>::sanitize (face->reference_table (T::headerTag));
+      const _hea *_hea_table = Sanitizer<_hea>::lock_instance (_hea_blob);
+      num_advances = _hea_table->numberOfLongMetrics;
+      if (!got_font_extents)
+      {
+	ascender = _hea_table->ascender;
+	descender = _hea_table->descender;
+	line_gap = _hea_table->lineGap;
+	got_font_extents = (ascender | descender) != 0;
+      }
+      hb_blob_destroy (_hea_blob);
+
+      has_font_extents = got_font_extents;
+
+      blob = Sanitizer<hmtxvmtx>::sanitize (face->reference_table (T::tableTag));
+
+      /* Cap num_metrics() and num_advances() based on table length. */
+      unsigned int len = hb_blob_get_length (blob);
+      if (unlikely (num_advances * 4 > len))
+	num_advances = len / 4;
+      num_metrics = num_advances + (len - 4 * num_advances) / 2;
+
+      /* We MUST set num_metrics to zero if num_advances is zero.
+       * Our get_advance() depends on that. */
+      if (unlikely (!num_advances))
+      {
+	num_metrics = num_advances = 0;
+	hb_blob_destroy (blob);
+	blob = hb_blob_get_empty ();
+      }
+      table = Sanitizer<hmtxvmtx>::lock_instance (blob);
+
+      var_blob = Sanitizer<HVARVVAR>::sanitize (face->reference_table (T::variationsTag));
+      var_table = Sanitizer<HVARVVAR>::lock_instance (var_blob);
+    }
+
+    inline void fini (void)
+    {
+      hb_blob_destroy (blob);
+      hb_blob_destroy (var_blob);
+    }
+
+    inline unsigned int get_advance (hb_codepoint_t  glyph,
+				     hb_font_t      *font) const
+    {
+      if (unlikely (glyph >= num_metrics))
+      {
+	/* If num_metrics is zero, it means we don't have the metrics table
+	 * for this direction: return default advance.  Otherwise, it means that the
+	 * glyph index is out of bound: return zero. */
+	if (num_metrics)
+	  return 0;
+	else
+	  return default_advance;
+      }
+
+      return table->longMetric[MIN (glyph, (uint32_t) num_advances - 1)].advance
+	   + var_table->get_advance_var (glyph, font->coords, font->num_coords); // TODO Optimize?!
+    }
+
+    public:
+    bool has_font_extents;
+    unsigned short ascender;
+    unsigned short descender;
+    unsigned short line_gap;
+
+    private:
+    unsigned int num_metrics;
+    unsigned int num_advances;
+    unsigned int default_advance;
+
+    const hmtxvmtx *table;
+    hb_blob_t *blob;
+    const HVARVVAR *var_table;
+    hb_blob_t *var_blob;
+  };
+
+  protected:
   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. */
@@ -84,19 +185,25 @@ struct hmtxvmtx
 					 * run is allowed and it must be at
 					 * the end. This allows a monospaced
 					 * font to vary the side bearing
 					 * values for each glyph. */
   public:
   DEFINE_SIZE_ARRAY2 (0, longMetric, leadingBearingX);
 };
 
-struct hmtx : hmtxvmtx {
+struct hmtx : hmtxvmtx<hmtx> {
   static const hb_tag_t tableTag	= HB_OT_TAG_hmtx;
+  static const hb_tag_t headerTag	= HB_OT_TAG_hhea;
+  static const hb_tag_t variationsTag	= HB_OT_TAG_HVAR;
+  static const hb_tag_t os2Tag		= HB_OT_TAG_os2;
 };
-struct vmtx : hmtxvmtx {
+struct vmtx : hmtxvmtx<vmtx> {
   static const hb_tag_t tableTag	= HB_OT_TAG_vmtx;
+  static const hb_tag_t headerTag	= HB_OT_TAG_vhea;
+  static const hb_tag_t variationsTag	= HB_OT_TAG_VVAR;
+  static const hb_tag_t os2Tag		= HB_TAG_NONE;
 };
 
 } /* namespace OT */
 
 
 #endif /* HB_OT_HMTX_TABLE_HH */
--- a/gfx/harfbuzz/src/hb-ot-kern-table.hh
+++ b/gfx/harfbuzz/src/hb-ot-kern-table.hh
@@ -99,18 +99,18 @@ struct KernClassTable
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (firstGlyph.sanitize (c) && classes.sanitize (c));
   }
 
   protected:
-  USHORT		firstGlyph;	/* First glyph in class range. */
-  ArrayOf<USHORT>	classes;	/* Glyph classes. */
+  UINT16		firstGlyph;	/* First glyph in class range. */
+  ArrayOf<UINT16>	classes;	/* Glyph classes. */
   public:
   DEFINE_SIZE_ARRAY (4, classes);
 };
 
 struct KernSubTableFormat2
 {
   inline int get_kerning (hb_codepoint_t left, hb_codepoint_t right, const char *end) const
   {
@@ -131,17 +131,17 @@ struct KernSubTableFormat2
     TRACE_SANITIZE (this);
     return_trace (rowWidth.sanitize (c) &&
 		  leftClassTable.sanitize (c, this) &&
 		  rightClassTable.sanitize (c, this) &&
 		  array.sanitize (c, this));
   }
 
   protected:
-  USHORT	rowWidth;	/* The width, in bytes, of a row in the table. */
+  UINT16	rowWidth;	/* The width, in bytes, of a row in the table. */
   OffsetTo<KernClassTable>
 		leftClassTable;	/* Offset from beginning of this subtable to
 				 * left-hand class table. */
   OffsetTo<KernClassTable>
 		rightClassTable;/* Offset from beginning of this subtable to
 				 * right-hand class table. */
   OffsetTo<FWORD>
 		array;		/* Offset from beginning of this subtable to
@@ -270,29 +270,29 @@ struct KernOT : KernTable<KernOT>
 
       COVERAGE_VARIATION_FLAG	= 0x00u, /* Not supported. */
 
       COVERAGE_CHECK_FLAGS	= 0x07u,
       COVERAGE_CHECK_HORIZONTAL	= 0x01u
     };
 
     protected:
-    USHORT	versionZ;	/* Unused. */
-    USHORT	length;		/* Length of the subtable (including this header). */
-    BYTE	format;		/* Subtable format. */
-    BYTE	coverage;	/* Coverage bits. */
+    UINT16	versionZ;	/* Unused. */
+    UINT16	length;		/* Length of the subtable (including this header). */
+    UINT8	format;		/* Subtable format. */
+    UINT8	coverage;	/* Coverage bits. */
     KernSubTable subtable;	/* Subtable data. */
     public:
     DEFINE_SIZE_MIN (6);
   };
 
   protected:
-  USHORT	version;	/* Version--0x0000u */
-  USHORT	nTables;	/* Number of subtables in the kerning table. */
-  BYTE		data[VAR];
+  UINT16	version;	/* Version--0x0000u */
+  UINT16	nTables;	/* Number of subtables in the kerning table. */
+  UINT8		data[VAR];
   public:
   DEFINE_SIZE_ARRAY (4, data);
 };
 
 struct KernAAT : KernTable<KernAAT>
 {
   friend struct KernTable<KernAAT>;
 
@@ -309,30 +309,30 @@ struct KernAAT : KernTable<KernAAT>
 
       COVERAGE_OVERRIDE_FLAG	= 0x00u, /* Not supported. */
 
       COVERAGE_CHECK_FLAGS	= 0xE0u,
       COVERAGE_CHECK_HORIZONTAL	= 0x00u
     };
 
     protected:
-    ULONG	length;		/* Length of the subtable (including this header). */
-    BYTE	coverage;	/* Coverage bits. */
-    BYTE	format;		/* Subtable format. */
-    USHORT	tupleIndex;	/* The tuple index (used for variations fonts).
+    UINT32	length;		/* Length of the subtable (including this header). */
+    UINT8	coverage;	/* Coverage bits. */
+    UINT8	format;		/* Subtable format. */
+    UINT16	tupleIndex;	/* The tuple index (used for variations fonts).
 				 * This value specifies which tuple this subtable covers. */
     KernSubTable subtable;	/* Subtable data. */
     public:
     DEFINE_SIZE_MIN (8);
   };
 
   protected:
-  ULONG		version;	/* Version--0x00010000u */
-  ULONG		nTables;	/* Number of subtables in the kerning table. */
-  BYTE		data[VAR];
+  UINT32		version;	/* Version--0x00010000u */
+  UINT32		nTables;	/* Number of subtables in the kerning table. */
+  UINT8		data[VAR];
   public:
   DEFINE_SIZE_ARRAY (8, data);
 };
 
 struct kern
 {
   static const hb_tag_t tableTag = HB_OT_TAG_kern;
 
@@ -353,34 +353,39 @@ struct kern
     case 0: return_trace (u.ot.sanitize (c));
     case 1: return_trace (u.aat.sanitize (c));
     default:return_trace (true);
     }
   }
 
   struct accelerator_t
   {
-    inline void init (const kern *table_, unsigned int table_length_)
+    inline void init (hb_face_t *face)
     {
-      table = table_;
-      table_length = table_length_;
+      blob = Sanitizer<kern>::sanitize (face->reference_table (HB_OT_TAG_kern));
+      table = Sanitizer<kern>::lock_instance (blob);
+      table_length = hb_blob_get_length (blob);
     }
-    inline void fini (void) {}
+    inline void fini (void)
+    {
+      hb_blob_destroy (blob);
+    }
 
     inline int get_h_kerning (hb_codepoint_t left, hb_codepoint_t right) const
     { return table->get_h_kerning (left, right, table_length); }
 
     private:
+    hb_blob_t *blob;
     const kern *table;
     unsigned int table_length;
   };
 
   protected:
   union {
-  USHORT		major;
+  UINT16		major;
   KernOT		ot;
   KernAAT		aat;
   } u;
   public:
   DEFINE_SIZE_UNION (2, major);
 };
 
 } /* namespace OT */
--- a/gfx/harfbuzz/src/hb-ot-layout-common-private.hh
+++ b/gfx/harfbuzz/src/hb-ot-layout-common-private.hh
@@ -156,31 +156,31 @@ struct RangeRecord
 
   template <typename set_t>
   inline void add_coverage (set_t *glyphs) const {
     glyphs->add_range (start, end);
   }
 
   GlyphID	start;		/* First GlyphID in the range */
   GlyphID	end;		/* Last GlyphID in the range */
-  USHORT	value;		/* Value */
+  UINT16	value;		/* Value */
   public:
   DEFINE_SIZE_STATIC (6);
 };
 DEFINE_NULL_DATA (RangeRecord, "\000\001");
 
 
 struct IndexArray : ArrayOf<Index>
 {
   inline unsigned int get_indexes (unsigned int start_offset,
 				   unsigned int *_count /* IN/OUT */,
 				   unsigned int *_indexes /* OUT */) const
   {
     if (_count) {
-      const USHORT *arr = this->sub_array (start_offset, _count);
+      const UINT16 *arr = this->sub_array (start_offset, _count);
       unsigned int count = *_count;
       for (unsigned int i = 0; i < count; i++)
 	_indexes[i] = arr[i];
     }
     return this->len;
   }
 };
 
@@ -211,19 +211,19 @@ struct LangSys
 
   inline bool sanitize (hb_sanitize_context_t *c,
 			const Record<LangSys>::sanitize_closure_t * = nullptr) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) && featureIndex.sanitize (c));
   }
 
-  Offset<>	lookupOrderZ;	/* = Null (reserved for an offset to a
+  Offset16	lookupOrderZ;	/* = Null (reserved for an offset to a
 				 * reordering table) */
-  USHORT	reqFeatureIndex;/* Index of a feature required for this
+  UINT16	reqFeatureIndex;/* Index of a feature required for this
 				 * language system--if no required features
 				 * = 0xFFFFu */
   IndexArray	featureIndex;	/* Array of indices into the FeatureList */
   public:
   DEFINE_SIZE_ARRAY (6, featureIndex);
 };
 DEFINE_NULL_DATA (LangSys, "\0\0\xFF\xFF");
 
@@ -338,49 +338,49 @@ struct FeatureParamsSize
 	     designSize > rangeEnd ||
 	     subfamilyNameID < 256 ||
 	     subfamilyNameID > 32767)
       return_trace (false);
     else
       return_trace (true);
   }
 
-  USHORT	designSize;	/* Represents the design size in 720/inch
+  UINT16	designSize;	/* Represents the design size in 720/inch
 				 * units (decipoints).  The design size entry
 				 * must be non-zero.  When there is a design
 				 * size but no recommended size range, the
 				 * rest of the array will consist of zeros. */
-  USHORT	subfamilyID;	/* Has no independent meaning, but serves
+  UINT16	subfamilyID;	/* Has no independent meaning, but serves
 				 * as an identifier that associates fonts
 				 * in a subfamily. All fonts which share a
 				 * Preferred or Font Family name and which
 				 * differ only by size range shall have the
 				 * same subfamily value, and no fonts which
 				 * differ in weight or style shall have the
 				 * same subfamily value. If this value is
 				 * zero, the remaining fields in the array
 				 * will be ignored. */
-  USHORT	subfamilyNameID;/* If the preceding value is non-zero, this
+  UINT16	subfamilyNameID;/* If the preceding value is non-zero, this
 				 * value must be set in the range 256 - 32767
 				 * (inclusive). It records the value of a
 				 * field in the name table, which must
 				 * contain English-language strings encoded
 				 * in Windows Unicode and Macintosh Roman,
 				 * and may contain additional strings
 				 * localized to other scripts and languages.
 				 * Each of these strings is the name an
 				 * application should use, in combination
 				 * with the family name, to represent the
 				 * subfamily in a menu.  Applications will
 				 * choose the appropriate version based on
 				 * their selection criteria. */
-  USHORT	rangeStart;	/* Large end of the recommended usage range
+  UINT16	rangeStart;	/* Large end of the recommended usage range
 				 * (inclusive), stored in 720/inch units
 				 * (decipoints). */
-  USHORT	rangeEnd;	/* Small end of the recommended usage range
+  UINT16	rangeEnd;	/* Small end of the recommended usage range
 				   (exclusive), stored in 720/inch units
 				 * (decipoints). */
   public:
   DEFINE_SIZE_STATIC (10);
 };
 
 /* http://www.microsoft.com/typography/otspec/features_pt.htm#ssxx */
 struct FeatureParamsStylisticSet
@@ -388,22 +388,22 @@ struct FeatureParamsStylisticSet
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     /* Right now minorVersion is at zero.  Which means, any table supports
      * the uiNameID field. */
     return_trace (c->check_struct (this));
   }
 
-  USHORT	version;	/* (set to 0): This corresponds to a “minor”
+  UINT16	version;	/* (set to 0): This corresponds to a “minor”
 				 * version number. Additional data may be
 				 * added to the end of this Feature Parameters
 				 * table in the future. */
 
-  USHORT	uiNameID;	/* The 'name' table name ID that specifies a
+  UINT16	uiNameID;	/* The 'name' table name ID that specifies a
 				 * string (or strings, for multiple languages)
 				 * for a user-interface label for this
 				 * feature.  The values of uiLabelNameId and
 				 * sampleTextNameId are expected to be in the
 				 * font-specific name ID range (256-32767),
 				 * though that is not a requirement in this
 				 * Feature Parameters specification. The
 				 * user-interface label for the feature can
@@ -421,35 +421,35 @@ struct FeatureParamsCharacterVariants
 {
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) &&
 		  characters.sanitize (c));
   }
 
-  USHORT	format;			/* Format number is set to 0. */
-  USHORT	featUILableNameID;	/* The ‘name’ table name ID that
+  UINT16	format;			/* Format number is set to 0. */
+  UINT16	featUILableNameID;	/* The ‘name’ table name ID that
 					 * specifies a string (or strings,
 					 * for multiple languages) for a
 					 * user-interface label for this
 					 * feature. (May be nullptr.) */
-  USHORT	featUITooltipTextNameID;/* The ‘name’ table name ID that
+  UINT16	featUITooltipTextNameID;/* The ‘name’ table name ID that
 					 * specifies a string (or strings,
 					 * for multiple languages) that an
 					 * application can use for tooltip
 					 * text for this feature. (May be
 					 * nullptr.) */
-  USHORT	sampleTextNameID;	/* The ‘name’ table name ID that
+  UINT16	sampleTextNameID;	/* The ‘name’ table name ID that
 					 * specifies sample text that
 					 * illustrates the effect of this
 					 * feature. (May be nullptr.) */
-  USHORT	numNamedParameters;	/* Number of named parameters. (May
+  UINT16	numNamedParameters;	/* Number of named parameters. (May
 					 * be zero.) */
-  USHORT	firstParamUILabelNameID;/* The first ‘name’ table name ID
+  UINT16	firstParamUILabelNameID;/* The first ‘name’ table name ID
 					 * used to specify strings for
 					 * user-interface labels for the
 					 * feature parameters. (Must be zero
 					 * if numParameters is zero.) */
   ArrayOf<UINT24>
 		characters;		/* Array of the Unicode Scalar Value
 					 * of the characters for which this
 					 * feature provides glyph variants.
@@ -557,17 +557,17 @@ struct Feature
   IndexArray	 lookupIndex;	/* Array of LookupList indices */
   public:
   DEFINE_SIZE_ARRAY (4, lookupIndex);
 };
 
 typedef RecordListOf<Feature> FeatureList;
 
 
-struct LookupFlag : USHORT
+struct LookupFlag : UINT16
 {
   enum Flags {
     RightToLeft		= 0x0001u,
     IgnoreBaseGlyphs	= 0x0002u,
     IgnoreLigatures	= 0x0004u,
     IgnoreMarks		= 0x0008u,
     IgnoreFlags		= 0x000Eu,
     UseMarkFilteringSet	= 0x0010u,
@@ -603,17 +603,17 @@ struct Lookup
   /* lookup_props is a 32-bit integer where the lower 16-bit is LookupFlag and
    * higher 16-bit is mark-filtering-set if the lookup uses one.
    * Not to be confused with glyph_props which is very similar. */
   inline uint32_t get_props (void) const
   {
     unsigned int flag = lookupFlag;
     if (unlikely (flag & LookupFlag::UseMarkFilteringSet))
     {
-      const USHORT &markFilteringSet = StructAfter<USHORT> (subTable);
+      const UINT16 &markFilteringSet = StructAfter<UINT16> (subTable);
       flag += (markFilteringSet << 16);
     }
     return flag;
   }
 
   template <typename SubTableType, typename context_t>
   inline typename context_t::return_t dispatch (context_t *c) const
   {
@@ -635,41 +635,41 @@ struct Lookup
   {
     TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (*this))) return_trace (false);
     lookupType.set (lookup_type);
     lookupFlag.set (lookup_props & 0xFFFFu);
     if (unlikely (!subTable.serialize (c, num_subtables))) return_trace (false);
     if (lookupFlag & LookupFlag::UseMarkFilteringSet)
     {
-      USHORT &markFilteringSet = StructAfter<USHORT> (subTable);
+      UINT16 &markFilteringSet = StructAfter<UINT16> (subTable);
       markFilteringSet.set (lookup_props >> 16);
     }
     return_trace (true);
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     /* Real sanitize of the subtables is done by GSUB/GPOS/... */
     if (!(c->check_struct (this) && subTable.sanitize (c))) return_trace (false);
     if (lookupFlag & LookupFlag::UseMarkFilteringSet)
     {
-      const USHORT &markFilteringSet = StructAfter<USHORT> (subTable);
+      const UINT16 &markFilteringSet = StructAfter<UINT16> (subTable);
       if (!markFilteringSet.sanitize (c)) return_trace (false);
     }
     return_trace (true);
   }
 
   private:
-  USHORT	lookupType;		/* Different enumerations for GSUB and GPOS */
-  USHORT	lookupFlag;		/* Lookup qualifiers */
-  ArrayOf<Offset<> >
+  UINT16	lookupType;		/* Different enumerations for GSUB and GPOS */
+  UINT16	lookupFlag;		/* Lookup qualifiers */
+  ArrayOf<Offset16>
 		subTable;		/* Array of SubTables */
-  USHORT	markFilteringSetX[VAR];	/* Index (base 0) into GDEF mark glyph sets
+  UINT16	markFilteringSetX[VAR];	/* Index (base 0) into GDEF mark glyph sets
 					 * structure. This field is only present if bit
 					 * UseMarkFilteringSet of lookup flags is set. */
   public:
   DEFINE_SIZE_ARRAY2 (6, subTable, markFilteringSetX);
 };
 
 typedef OffsetListOf<Lookup> LookupList;
 
@@ -732,17 +732,17 @@ struct CoverageFormat1
 
     private:
     const struct CoverageFormat1 *c;
     unsigned int i;
   };
   private:
 
   protected:
-  USHORT	coverageFormat;	/* Format identifier--format = 1 */
+  UINT16	coverageFormat;	/* Format identifier--format = 1 */
   SortedArrayOf<GlyphID>
 		glyphArray;	/* Array of GlyphIDs--in numerical order */
   public:
   DEFINE_SIZE_ARRAY (4, glyphArray);
 };
 
 struct CoverageFormat2
 {
@@ -855,17 +855,17 @@ struct CoverageFormat2
 
     private:
     const struct CoverageFormat2 *c;
     unsigned int i, j, coverage;
   };
   private:
 
   protected:
-  USHORT	coverageFormat;	/* Format identifier--format = 2 */
+  UINT16	coverageFormat;	/* Format identifier--format = 2 */
   SortedArrayOf<RangeRecord>
 		rangeRecord;	/* Array of glyph ranges--ordered by
 				 * Start GlyphID. rangeCount entries
 				 * long */
   public:
   DEFINE_SIZE_ARRAY (4, rangeRecord);
 };
 
@@ -980,17 +980,17 @@ struct Coverage
     union {
     CoverageFormat2::Iter	format2; /* Put this one first since it's larger; helps shut up compiler. */
     CoverageFormat1::Iter	format1;
     } u;
   };
 
   protected:
   union {
-  USHORT		format;		/* Format identifier */
+  UINT16		format;		/* Format identifier */
   CoverageFormat1	format1;
   CoverageFormat2	format2;
   } u;
   public:
   DEFINE_SIZE_UNION (2, format);
 };
 
 
@@ -1042,19 +1042,19 @@ struct ClassDefFormat1
     }
     for (unsigned int i = 0; i < count; i++)
       if (classValue[i] == klass && glyphs->has (startGlyph + i))
         return true;
     return false;
   }
 
   protected:
-  USHORT	classFormat;		/* Format identifier--format = 1 */
+  UINT16	classFormat;		/* Format identifier--format = 1 */
   GlyphID	startGlyph;		/* First GlyphID of the classValueArray */
-  ArrayOf<USHORT>
+  ArrayOf<UINT16>
 		classValue;		/* Array of Class Values--one per GlyphID */
   public:
   DEFINE_SIZE_ARRAY (6, classValue);
 };
 
 struct ClassDefFormat2
 {
   friend struct ClassDef;
@@ -1102,17 +1102,17 @@ struct ClassDefFormat2
     }
     for (unsigned int i = 0; i < count; i++)
       if (rangeRecord[i].value == klass && rangeRecord[i].intersects (glyphs))
         return true;
     return false;
   }
 
   protected:
-  USHORT	classFormat;	/* Format identifier--format = 2 */
+  UINT16	classFormat;	/* Format identifier--format = 2 */
   SortedArrayOf<RangeRecord>
 		rangeRecord;	/* Array of glyph ranges--ordered by
 				 * Start GlyphID */
   public:
   DEFINE_SIZE_ARRAY (4, rangeRecord);
 };
 
 struct ClassDef
@@ -1150,17 +1150,17 @@ struct ClassDef
     case 1: return u.format1.intersects_class (glyphs, klass);
     case 2: return u.format2.intersects_class (glyphs, klass);
     default:return false;
     }
   }
 
   protected:
   union {
-  USHORT		format;		/* Format identifier */
+  UINT16		format;		/* Format identifier */
   ClassDefFormat1	format1;
   ClassDefFormat2	format2;
   } u;
   public:
   DEFINE_SIZE_UNION (2, format);
 };
 
 
@@ -1235,18 +1235,18 @@ struct VarRegionList
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) &&
 		  c->check_array (axesZ, axesZ[0].static_size,
 				  (unsigned int) axisCount * (unsigned int) regionCount));
   }
 
   protected:
-  USHORT	axisCount;
-  USHORT	regionCount;
+  UINT16	axisCount;
+  UINT16	regionCount;
   VarRegionAxis	axesZ[VAR];
   public:
   DEFINE_SIZE_ARRAY (4, axesZ);
 };
 
 struct VarData
 {
   inline unsigned int get_row_size (void) const
@@ -1260,23 +1260,23 @@ struct VarData
 			  const VarRegionList &regions) const
   {
     if (unlikely (inner >= itemCount))
       return 0.;
 
    unsigned int count = regionIndices.len;
    unsigned int scount = shortCount;
 
-   const BYTE *bytes = &StructAfter<BYTE> (regionIndices);
-   const BYTE *row = bytes + inner * (scount + count);
+   const UINT8 *bytes = &StructAfter<UINT8> (regionIndices);
+   const UINT8 *row = bytes + inner * (scount + count);
 
    float delta = 0.;
    unsigned int i = 0;
 
-   const SHORT *scursor = reinterpret_cast<const SHORT *> (row);
+   const INT16 *scursor = reinterpret_cast<const INT16 *> (row);
    for (; i < scount; i++)
    {
      float scalar = regions.evaluate (regionIndices.array[i], coords, coord_count);
      delta += scalar * *scursor++;
    }
    const INT8 *bcursor = reinterpret_cast<const INT8 *> (scursor);
    for (; i < count; i++)
    {
@@ -1288,25 +1288,25 @@ struct VarData
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) &&
 		  regionIndices.sanitize(c) &&
 		  shortCount <= regionIndices.len &&
-		  c->check_array (&StructAfter<BYTE> (regionIndices),
+		  c->check_array (&StructAfter<UINT8> (regionIndices),
 				  get_row_size (), itemCount));
   }
 
   protected:
-  USHORT		itemCount;
-  USHORT		shortCount;
-  ArrayOf<USHORT>	regionIndices;
-  BYTE			bytesX[VAR];
+  UINT16		itemCount;
+  UINT16		shortCount;
+  ArrayOf<UINT16>	regionIndices;
+  UINT8			bytesX[VAR];
   public:
   DEFINE_SIZE_ARRAY2 (6, regionIndices, bytesX);
 };
 
 struct VariationStore
 {
   inline float get_delta (unsigned int outer, unsigned int inner,
 			  int *coords, unsigned int coord_count) const
@@ -1332,19 +1332,19 @@ struct VariationStore
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) &&
 		  format == 1 &&
 		  regions.sanitize (c, this) &&
 		  dataSets.sanitize (c, this));
   }
 
   protected:
-  USHORT				format;
+  UINT16				format;
   LOffsetTo<VarRegionList>		regions;
-  OffsetArrayOf<VarData, ULONG>		dataSets;
+  OffsetArrayOf<VarData, UINT32>		dataSets;
   public:
   DEFINE_SIZE_ARRAY (8, dataSets);
 };
 
 /*
  * Feature Variations
  */
 
@@ -1361,18 +1361,18 @@ struct ConditionFormat1
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this));
   }
 
   protected:
-  USHORT	format;		/* Format identifier--format = 1 */
-  USHORT	axisIndex;
+  UINT16	format;		/* Format identifier--format = 1 */
+  UINT16	axisIndex;
   F2DOT14	filterRangeMinValue;
   F2DOT14	filterRangeMaxValue;
   public:
   DEFINE_SIZE_STATIC (8);
 };
 
 struct Condition
 {
@@ -1391,17 +1391,17 @@ struct Condition
     switch (u.format) {
     case 1: return_trace (u.format1.sanitize (c));
     default:return_trace (true);
     }
   }
 
   protected:
   union {
-  USHORT		format;		/* Format identifier */
+  UINT16		format;		/* Format identifier */
   ConditionFormat1	format1;
   } u;
   public:
   DEFINE_SIZE_UNION (2, format);
 };
 
 struct ConditionSet
 {
@@ -1416,33 +1416,33 @@ struct ConditionSet
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (conditions.sanitize (c, this));
   }
 
   protected:
-  OffsetArrayOf<Condition, ULONG> conditions;
+  OffsetArrayOf<Condition, UINT32> conditions;
   public:
   DEFINE_SIZE_ARRAY (2, conditions);
 };
 
 struct FeatureTableSubstitutionRecord
 {
   friend struct FeatureTableSubstitution;
 
   inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) && feature.sanitize (c, base));
   }
 
   protected:
-  USHORT		featureIndex;
+  UINT16		featureIndex;
   LOffsetTo<Feature>	feature;
   public:
   DEFINE_SIZE_STATIC (6);
 };
 
 struct FeatureTableSubstitution
 {
   inline const Feature *find_substitute (unsigned int feature_index) const
@@ -1552,18 +1552,18 @@ struct HintingDevice
   { return get_delta (font->x_ppem, font->x_scale); }
 
   inline hb_position_t get_y_delta (hb_font_t *font) const
   { return get_delta (font->y_ppem, font->y_scale); }
 
   inline unsigned int get_size (void) const
   {
     unsigned int f = deltaFormat;
-    if (unlikely (f < 1 || f > 3 || startSize > endSize)) return 3 * USHORT::static_size;
-    return USHORT::static_size * (4 + ((endSize - startSize) >> (4 - f)));
+    if (unlikely (f < 1 || f > 3 || startSize > endSize)) return 3 * UINT16::static_size;
+    return UINT16::static_size * (4 + ((endSize - startSize) >> (4 - f)));
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) && c->check_range (this, this->get_size ()));
   }
 
@@ -1598,24 +1598,24 @@ struct HintingDevice
 
     if ((unsigned int) delta >= ((mask + 1) >> 1))
       delta -= mask + 1;
 
     return delta;
   }
 
   protected:
-  USHORT	startSize;		/* Smallest size to correct--in ppem */
-  USHORT	endSize;		/* Largest size to correct--in ppem */
-  USHORT	deltaFormat;		/* Format of DeltaValue array data: 1, 2, or 3
+  UINT16	startSize;		/* Smallest size to correct--in ppem */
+  UINT16	endSize;		/* Largest size to correct--in ppem */
+  UINT16	deltaFormat;		/* Format of DeltaValue array data: 1, 2, or 3
 					 * 1	Signed 2-bit value, 8 values per uint16
 					 * 2	Signed 4-bit value, 4 values per uint16
 					 * 3	Signed 8-bit value, 2 values per uint16
 					 */
-  USHORT	deltaValue[VAR];	/* Array of compressed data */
+  UINT16	deltaValue[VAR];	/* Array of compressed data */
   public:
   DEFINE_SIZE_ARRAY (6, deltaValue);
 };
 
 struct VariationDevice
 {
   friend struct Device;
 
@@ -1636,30 +1636,30 @@ struct VariationDevice
   private:
 
   inline float get_delta (hb_font_t *font, const VariationStore &store) const
   {
     return store.get_delta (outerIndex, innerIndex, font->coords, font->num_coords);
   }
 
   protected:
-  USHORT	outerIndex;
-  USHORT	innerIndex;
-  USHORT	deltaFormat;	/* Format identifier for this table: 0x0x8000 */
+  UINT16	outerIndex;
+  UINT16	innerIndex;
+  UINT16	deltaFormat;	/* Format identifier for this table: 0x0x8000 */
   public:
   DEFINE_SIZE_STATIC (6);
 };
 
 struct DeviceHeader
 {
   protected:
-  USHORT		reserved1;
-  USHORT		reserved2;
+  UINT16		reserved1;
+  UINT16		reserved2;
   public:
-  USHORT		format;		/* Format identifier */
+  UINT16		format;		/* Format identifier */
   public:
   DEFINE_SIZE_STATIC (6);
 };
 
 struct Device
 {
   inline hb_position_t get_x_delta (hb_font_t *font, const VariationStore &store=Null(VariationStore)) const
   {
--- a/gfx/harfbuzz/src/hb-ot-layout-gdef-table.hh
+++ b/gfx/harfbuzz/src/hb-ot-layout-gdef-table.hh
@@ -36,17 +36,17 @@
 
 namespace OT {
 
 
 /*
  * Attachment List Table
  */
 
-typedef ArrayOf<USHORT> AttachPoint;	/* Array of contour point indices--in
+typedef ArrayOf<UINT16> AttachPoint;	/* Array of contour point indices--in
 					 * increasing numerical order */
 
 struct AttachList
 {
   inline unsigned int get_attach_points (hb_codepoint_t glyph_id,
 					 unsigned int start_offset,
 					 unsigned int *point_count /* IN/OUT */,
 					 unsigned int *point_array /* OUT */) const
@@ -57,17 +57,17 @@ struct AttachList
       if (point_count)
 	*point_count = 0;
       return 0;
     }
 
     const AttachPoint &points = this+attachPoint[index];
 
     if (point_count) {
-      const USHORT *array = points.sub_array (start_offset, point_count);
+      const UINT16 *array = points.sub_array (start_offset, point_count);
       unsigned int count = *point_count;
       for (unsigned int i = 0; i < count; i++)
 	point_array[i] = array[i];
     }
 
     return points.len;
   }
 
@@ -104,18 +104,18 @@ struct CaretValueFormat1
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this));
   }
 
   protected:
-  USHORT	caretValueFormat;	/* Format identifier--format = 1 */
-  SHORT		coordinate;		/* X or Y value, in design units */
+  UINT16	caretValueFormat;	/* Format identifier--format = 1 */
+  INT16		coordinate;		/* X or Y value, in design units */
   public:
   DEFINE_SIZE_STATIC (4);
 };
 
 struct CaretValueFormat2
 {
   friend struct CaretValue;
 
@@ -131,18 +131,18 @@ struct CaretValueFormat2
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this));
   }
 
   protected:
-  USHORT	caretValueFormat;	/* Format identifier--format = 2 */
-  USHORT	caretValuePoint;	/* Contour point index on glyph */
+  UINT16	caretValueFormat;	/* Format identifier--format = 2 */
+  UINT16	caretValuePoint;	/* Contour point index on glyph */
   public:
   DEFINE_SIZE_STATIC (4);
 };
 
 struct CaretValueFormat3
 {
   friend struct CaretValue;
 
@@ -155,18 +155,18 @@ struct CaretValueFormat3
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) && deviceTable.sanitize (c, this));
   }
 
   protected:
-  USHORT	caretValueFormat;	/* Format identifier--format = 3 */
-  SHORT		coordinate;		/* X or Y value, in design units */
+  UINT16	caretValueFormat;	/* Format identifier--format = 3 */
+  INT16		coordinate;		/* X or Y value, in design units */
   OffsetTo<Device>
 		deviceTable;		/* Offset to Device table for X or Y
 					 * value--from beginning of CaretValue
 					 * table */
   public:
   DEFINE_SIZE_STATIC (6);
 };
 
@@ -194,17 +194,17 @@ struct CaretValue
     case 2: return_trace (u.format2.sanitize (c));
     case 3: return_trace (u.format3.sanitize (c));
     default:return_trace (true);
     }
   }
 
   protected:
   union {
-  USHORT		format;		/* Format identifier */
+  UINT16		format;		/* Format identifier */
   CaretValueFormat1	format1;
   CaretValueFormat2	format2;
   CaretValueFormat3	format3;
   } u;
   public:
   DEFINE_SIZE_UNION (2, format);
 };
 
@@ -289,17 +289,17 @@ struct MarkGlyphSetsFormat1
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (coverage.sanitize (c, this));
   }
 
   protected:
-  USHORT	format;			/* Format identifier--format = 1 */
+  UINT16	format;			/* Format identifier--format = 1 */
   ArrayOf<LOffsetTo<Coverage> >
 		coverage;		/* Array of long offsets to mark set
 					 * coverage tables */
   public:
   DEFINE_SIZE_ARRAY (4, coverage);
 };
 
 struct MarkGlyphSets
@@ -319,17 +319,17 @@ struct MarkGlyphSets
     switch (u.format) {
     case 1: return_trace (u.format1.sanitize (c));
     default:return_trace (true);
     }
   }
 
   protected:
   union {
-  USHORT		format;		/* Format identifier */
+  UINT16		format;		/* Format identifier */
   MarkGlyphSetsFormat1	format1;
   } u;
   public:
   DEFINE_SIZE_UNION (2, format);
 };
 
 
 /*
--- a/gfx/harfbuzz/src/hb-ot-layout-gpos-table.hh
+++ b/gfx/harfbuzz/src/hb-ot-layout-gpos-table.hh
@@ -46,21 +46,21 @@ enum attach_type_t {
   /* Each attachment should be either a mark or a cursive; can't be both. */
   ATTACH_TYPE_MARK	= 0X01,
   ATTACH_TYPE_CURSIVE	= 0X02,
 };
 
 
 /* Shared Tables: ValueRecord, Anchor Table, and MarkArray */
 
-typedef USHORT Value;
+typedef UINT16 Value;
 
 typedef Value ValueRecord[VAR];
 
-struct ValueFormat : USHORT
+struct ValueFormat : UINT16
 {
   enum Flags {
     xPlacement	= 0x0001u,	/* Includes horizontal adjustment for placement */
     yPlacement	= 0x0002u,	/* Includes vertical adjustment for placement */
     xAdvance	= 0x0004u,	/* Includes horizontal adjustment for advance */
     yAdvance	= 0x0008u,	/* Includes vertical adjustment for advance */
     xPlaDevice	= 0x0010u,	/* Includes horizontal Device table for placement */
     yPlaDevice	= 0x0020u,	/* Includes vertical Device table for placement */
@@ -69,24 +69,24 @@ struct ValueFormat : USHORT
     ignored	= 0x0F00u,	/* Was used in TrueType Open for MM fonts */
     reserved	= 0xF000u,	/* For future use */
 
     devices	= 0x00F0u	/* Mask for having any Device table */
   };
 
 /* All fields are options.  Only those available advance the value pointer. */
 #if 0
-  SHORT		xPlacement;		/* Horizontal adjustment for
+  INT16		xPlacement;		/* Horizontal adjustment for
 					 * placement--in design units */
-  SHORT		yPlacement;		/* Vertical adjustment for
+  INT16		yPlacement;		/* Vertical adjustment for
 					 * placement--in design units */
-  SHORT		xAdvance;		/* Horizontal adjustment for
+  INT16		xAdvance;		/* Horizontal adjustment for
 					 * advance--in design units (only used
 					 * for horizontal writing) */
-  SHORT		yAdvance;		/* Vertical adjustment for advance--in
+  INT16		yAdvance;		/* Vertical adjustment for advance--in
 					 * design units (only used for vertical
 					 * writing) */
   Offset	xPlaDevice;		/* Offset to Device table for
 					 * horizontal placement--measured from
 					 * beginning of PosTable (may be NULL) */
   Offset	yPlaDevice;		/* Offset to Device table for vertical
 					 * placement--measured from beginning
 					 * of PosTable (may be NULL) */
@@ -173,18 +173,18 @@ struct ValueFormat : USHORT
     return true;
   }
 
   static inline OffsetTo<Device>& get_device (Value* value)
   { return *CastP<OffsetTo<Device> > (value); }
   static inline const OffsetTo<Device>& get_device (const Value* value)
   { return *CastP<OffsetTo<Device> > (value); }
 
-  static inline const SHORT& get_short (const Value* value)
-  { return *CastP<SHORT> (value); }
+  static inline const INT16& get_short (const Value* value)
+  { return *CastP<INT16> (value); }
 
   public:
 
   inline bool has_device (void) const {
     unsigned int format = *this;
     return (format & devices) != 0;
   }
 
@@ -242,19 +242,19 @@ struct AnchorFormat1
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this));
   }
 
   protected:
-  USHORT	format;			/* Format identifier--format = 1 */
-  SHORT		xCoordinate;		/* Horizontal value--in design units */
-  SHORT		yCoordinate;		/* Vertical value--in design units */
+  UINT16	format;			/* Format identifier--format = 1 */
+  INT16		xCoordinate;		/* Horizontal value--in design units */
+  INT16		yCoordinate;		/* Vertical value--in design units */
   public:
   DEFINE_SIZE_STATIC (6);
 };
 
 struct AnchorFormat2
 {
   inline void get_anchor (hb_apply_context_t *c, hb_codepoint_t glyph_id,
 			  hb_position_t *x, hb_position_t *y) const
@@ -273,20 +273,20 @@ struct AnchorFormat2
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this));
   }
 
   protected:
-  USHORT	format;			/* Format identifier--format = 2 */
-  SHORT		xCoordinate;		/* Horizontal value--in design units */
-  SHORT		yCoordinate;		/* Vertical value--in design units */
-  USHORT	anchorPoint;		/* Index to glyph contour point */
+  UINT16	format;			/* Format identifier--format = 2 */
+  INT16		xCoordinate;		/* Horizontal value--in design units */
+  INT16		yCoordinate;		/* Vertical value--in design units */
+  UINT16	anchorPoint;		/* Index to glyph contour point */
   public:
   DEFINE_SIZE_STATIC (8);
 };
 
 struct AnchorFormat3
 {
   inline void get_anchor (hb_apply_context_t *c, hb_codepoint_t glyph_id HB_UNUSED,
 			  hb_position_t *x, hb_position_t *y) const
@@ -303,19 +303,19 @@ struct AnchorFormat3
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) && xDeviceTable.sanitize (c, this) && yDeviceTable.sanitize (c, this));
   }
 
   protected:
-  USHORT	format;			/* Format identifier--format = 3 */
-  SHORT		xCoordinate;		/* Horizontal value--in design units */
-  SHORT		yCoordinate;		/* Vertical value--in design units */
+  UINT16	format;			/* Format identifier--format = 3 */
+  INT16		xCoordinate;		/* Horizontal value--in design units */
+  INT16		yCoordinate;		/* Vertical value--in design units */
   OffsetTo<Device>
 		xDeviceTable;		/* Offset to Device table for X
 					 * coordinate-- from beginning of
 					 * Anchor table (may be NULL) */
   OffsetTo<Device>
 		yDeviceTable;		/* Offset to Device table for Y
 					 * coordinate-- from beginning of
 					 * Anchor table (may be NULL) */
@@ -346,17 +346,17 @@ struct Anchor
     case 2: return_trace (u.format2.sanitize (c));
     case 3: return_trace (u.format3.sanitize (c));
     default:return_trace (true);
     }
   }
 
   protected:
   union {
-  USHORT		format;		/* Format identifier */
+  UINT16		format;		/* Format identifier */
   AnchorFormat1		format1;
   AnchorFormat2		format2;
   AnchorFormat3		format3;
   } u;
   public:
   DEFINE_SIZE_UNION (2, format);
 };
 
@@ -377,17 +377,17 @@ struct AnchorMatrix
     if (unlikely (_hb_unsigned_int_mul_overflows (rows, cols))) return_trace (false);
     unsigned int count = rows * cols;
     if (!c->check_array (matrixZ, matrixZ[0].static_size, count)) return_trace (false);
     for (unsigned int i = 0; i < count; i++)
       if (!matrixZ[i].sanitize (c, this)) return_trace (false);
     return_trace (true);
   }
 
-  USHORT	rows;			/* Number of rows */
+  UINT16	rows;			/* Number of rows */
   protected:
   OffsetTo<Anchor>
 		matrixZ[VAR];		/* Matrix of offsets to Anchor tables--
 					 * from beginning of AnchorMatrix table */
   public:
   DEFINE_SIZE_ARRAY (2, matrixZ);
 };
 
@@ -398,17 +398,17 @@ struct MarkRecord
 
   inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) && markAnchor.sanitize (c, base));
   }
 
   protected:
-  USHORT	klass;			/* Class defined for this mark */
+  UINT16	klass;			/* Class defined for this mark */
   OffsetTo<Anchor>
 		markAnchor;		/* Offset to Anchor table--from
 					 * beginning of MarkArray table */
   public:
   DEFINE_SIZE_STATIC (4);
 };
 
 struct MarkArray : ArrayOf<MarkRecord>	/* Array of MarkRecords--in Coverage order */
@@ -487,17 +487,17 @@ struct SinglePosFormat1
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) &&
 		  coverage.sanitize (c, this) &&
 		  valueFormat.sanitize_value (c, this, values));
   }
 
   protected:
-  USHORT	format;			/* Format identifier--format = 1 */
+  UINT16	format;			/* Format identifier--format = 1 */
   OffsetTo<Coverage>
 		coverage;		/* Offset to Coverage table--from
 					 * beginning of subtable */
   ValueFormat	valueFormat;		/* Defines the types of data in the
 					 * ValueRecord */
   ValueRecord	values;			/* Defines positioning
 					 * value(s)--applied to all glyphs in
 					 * the Coverage table */
@@ -539,23 +539,23 @@ struct SinglePosFormat2
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) &&
 		  coverage.sanitize (c, this) &&
 		  valueFormat.sanitize_values (c, this, values, valueCount));
   }
 
   protected:
-  USHORT	format;			/* Format identifier--format = 2 */
+  UINT16	format;			/* Format identifier--format = 2 */
   OffsetTo<Coverage>
 		coverage;		/* Offset to Coverage table--from
 					 * beginning of subtable */
   ValueFormat	valueFormat;		/* Defines the types of data in the
 					 * ValueRecord */
-  USHORT	valueCount;		/* Number of ValueRecords */
+  UINT16	valueCount;		/* Number of ValueRecords */
   ValueRecord	values;			/* Array of ValueRecords--positioning
 					 * values applied to glyphs */
   public:
   DEFINE_SIZE_ARRAY (8, values);
 };
 
 struct SinglePos
 {
@@ -568,17 +568,17 @@ struct SinglePos
     case 1: return_trace (c->dispatch (u.format1));
     case 2: return_trace (c->dispatch (u.format2));
     default:return_trace (c->default_return_value ());
     }
   }
 
   protected:
   union {
-  USHORT		format;		/* Format identifier */
+  UINT16		format;		/* Format identifier */
   SinglePosFormat1	format1;
   SinglePosFormat2	format2;
   } u;
 };
 
 
 struct PairValueRecord
 {
@@ -599,17 +599,17 @@ struct PairSet
   friend struct PairPosFormat1;
 
   inline void collect_glyphs (hb_collect_glyphs_context_t *c,
 			      const ValueFormat *valueFormats) const
   {
     TRACE_COLLECT_GLYPHS (this);
     unsigned int len1 = valueFormats[0].get_len ();
     unsigned int len2 = valueFormats[1].get_len ();
-    unsigned int record_size = USHORT::static_size * (1 + len1 + len2);
+    unsigned int record_size = UINT16::static_size * (1 + len1 + len2);
 
     const PairValueRecord *record = CastP<PairValueRecord> (arrayZ);
     unsigned int count = len;
     for (unsigned int i = 0; i < count; i++)
     {
       c->input->add (record->secondGlyph);
       record = &StructAtOffset<PairValueRecord> (record, record_size);
     }
@@ -618,17 +618,17 @@ struct PairSet
   inline bool apply (hb_apply_context_t *c,
 		     const ValueFormat *valueFormats,
 		     unsigned int pos) const
   {
     TRACE_APPLY (this);
     hb_buffer_t *buffer = c->buffer;
     unsigned int len1 = valueFormats[0].get_len ();
     unsigned int len2 = valueFormats[1].get_len ();
-    unsigned int record_size = USHORT::static_size * (1 + len1 + len2);
+    unsigned int record_size = UINT16::static_size * (1 + len1 + len2);
 
     const PairValueRecord *record_array = CastP<PairValueRecord> (arrayZ);
     unsigned int count = len;
 
     /* Hand-coded bsearch. */
     if (unlikely (!count))
       return_trace (false);
     hb_codepoint_t x = buffer->info[pos].codepoint;
@@ -663,27 +663,27 @@ struct PairSet
     unsigned int len1; /* valueFormats[0].get_len() */
     unsigned int stride; /* 1 + len1 + len2 */
   };
 
   inline bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *closure) const
   {
     TRACE_SANITIZE (this);
     if (!(c->check_struct (this)
-       && c->check_array (arrayZ, USHORT::static_size * closure->stride, len))) return_trace (false);
+       && c->check_array (arrayZ, UINT16::static_size * closure->stride, len))) return_trace (false);
 
     unsigned int count = len;
     const PairValueRecord *record = CastP<PairValueRecord> (arrayZ);
     return_trace (closure->valueFormats[0].sanitize_values_stride_unsafe (c, closure->base, &record->values[0], count, closure->stride) &&
 		  closure->valueFormats[1].sanitize_values_stride_unsafe (c, closure->base, &record->values[closure->len1], count, closure->stride));
   }
 
   protected:
-  USHORT	len;			/* Number of PairValueRecords */
-  USHORT	arrayZ[VAR];		/* Array of PairValueRecords--ordered
+  UINT16	len;			/* Number of PairValueRecords */
+  UINT16	arrayZ[VAR];		/* Array of PairValueRecords--ordered
 					 * by GlyphID of the second glyph */
   public:
   DEFINE_SIZE_ARRAY (2, arrayZ);
 };
 
 struct PairPosFormat1
 {
   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
@@ -728,17 +728,17 @@ struct PairPosFormat1
       len1,
       1 + len1 + len2
     };
 
     return_trace (coverage.sanitize (c, this) && pairSet.sanitize (c, this, &closure));
   }
 
   protected:
-  USHORT	format;			/* Format identifier--format = 1 */
+  UINT16	format;			/* Format identifier--format = 1 */
   OffsetTo<Coverage>
 		coverage;		/* Offset to Coverage table--from
 					 * beginning of subtable */
   ValueFormat	valueFormat[2];		/* [0] Defines the types of data in
 					 * ValueRecord1--for the first glyph
 					 * in the pair--may be zero (0) */
 					/* [1] Defines the types of data in
 					 * ValueRecord2--for the second glyph
@@ -818,17 +818,17 @@ struct PairPosFormat2
     unsigned int record_size = valueFormat1.get_size () + valueFormat2.get_size ();
     unsigned int count = (unsigned int) class1Count * (unsigned int) class2Count;
     return_trace (c->check_array (values, record_size, count) &&
 		  valueFormat1.sanitize_values_stride_unsafe (c, this, &values[0], count, stride) &&
 		  valueFormat2.sanitize_values_stride_unsafe (c, this, &values[len1], count, stride));
   }
 
   protected:
-  USHORT	format;			/* Format identifier--format = 2 */
+  UINT16	format;			/* Format identifier--format = 2 */
   OffsetTo<Coverage>
 		coverage;		/* Offset to Coverage table--from
 					 * beginning of subtable */
   ValueFormat	valueFormat1;		/* ValueRecord definition--for the
 					 * first glyph of the pair--may be zero
 					 * (0) */
   ValueFormat	valueFormat2;		/* ValueRecord definition--for the
 					 * second glyph of the pair--may be
@@ -836,19 +836,19 @@ struct PairPosFormat2
   OffsetTo<ClassDef>
 		classDef1;		/* Offset to ClassDef table--from
 					 * beginning of PairPos subtable--for
 					 * the first glyph of the pair */
   OffsetTo<ClassDef>
 		classDef2;		/* Offset to ClassDef table--from
 					 * beginning of PairPos subtable--for
 					 * the second glyph of the pair */
-  USHORT	class1Count;		/* Number of classes in ClassDef1
+  UINT16	class1Count;		/* Number of classes in ClassDef1
 					 * table--includes Class0 */
-  USHORT	class2Count;		/* Number of classes in ClassDef2
+  UINT16	class2Count;		/* Number of classes in ClassDef2
 					 * table--includes Class0 */
   ValueRecord	values;			/* Matrix of value pairs:
 					 * class1-major, class2-minor,
 					 * Each entry has value1 and value2 */
   public:
   DEFINE_SIZE_ARRAY (16, values);
 };
 
@@ -863,17 +863,17 @@ struct PairPos
     case 1: return_trace (c->dispatch (u.format1));
     case 2: return_trace (c->dispatch (u.format2));
     default:return_trace (c->default_return_value ());
     }
   }
 
   protected:
   union {
-  USHORT		format;		/* Format identifier */
+  UINT16		format;		/* Format identifier */
   PairPosFormat1	format1;
   PairPosFormat2	format2;
   } u;
 };
 
 
 struct EntryExitRecord
 {
@@ -1017,17 +1017,17 @@ struct CursivePosFormat1
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (coverage.sanitize (c, this) && entryExitRecord.sanitize (c, this));
   }
 
   protected:
-  USHORT	format;			/* Format identifier--format = 1 */
+  UINT16	format;			/* Format identifier--format = 1 */
   OffsetTo<Coverage>
 		coverage;		/* Offset to Coverage table--from
 					 * beginning of subtable */
   ArrayOf<EntryExitRecord>
 		entryExitRecord;	/* Array of EntryExit records--in
 					 * Coverage Index order */
   public:
   DEFINE_SIZE_ARRAY (6, entryExitRecord);
@@ -1043,17 +1043,17 @@ struct CursivePos
     switch (u.format) {
     case 1: return_trace (c->dispatch (u.format1));
     default:return_trace (c->default_return_value ());
     }
   }
 
   protected:
   union {
-  USHORT		format;		/* Format identifier */
+  UINT16		format;		/* Format identifier */
   CursivePosFormat1	format1;
   } u;
 };
 
 
 typedef AnchorMatrix BaseArray;		/* base-major--
 					 * in order of BaseCoverage Index--,
 					 * mark-minor--
@@ -1108,24 +1108,24 @@ struct MarkBasePosFormat1
     return_trace (c->check_struct (this) &&
 		  markCoverage.sanitize (c, this) &&
 		  baseCoverage.sanitize (c, this) &&
 		  markArray.sanitize (c, this) &&
 		  baseArray.sanitize (c, this, (unsigned int) classCount));
   }
 
   protected:
-  USHORT	format;			/* Format identifier--format = 1 */
+  UINT16	format;			/* Format identifier--format = 1 */
   OffsetTo<Coverage>
 		markCoverage;		/* Offset to MarkCoverage table--from
 					 * beginning of MarkBasePos subtable */
   OffsetTo<Coverage>
 		baseCoverage;		/* Offset to BaseCoverage table--from
 					 * beginning of MarkBasePos subtable */
-  USHORT	classCount;		/* Number of classes defined for marks */
+  UINT16	classCount;		/* Number of classes defined for marks */
   OffsetTo<MarkArray>
 		markArray;		/* Offset to MarkArray table--from
 					 * beginning of MarkBasePos subtable */
   OffsetTo<BaseArray>
 		baseArray;		/* Offset to BaseArray table--from
 					 * beginning of MarkBasePos subtable */
   public:
   DEFINE_SIZE_STATIC (12);
@@ -1141,17 +1141,17 @@ struct MarkBasePos
     switch (u.format) {
     case 1: return_trace (c->dispatch (u.format1));
     default:return_trace (c->default_return_value ());
     }
   }
 
   protected:
   union {
-  USHORT		format;		/* Format identifier */
+  UINT16		format;		/* Format identifier */
   MarkBasePosFormat1	format1;
   } u;
 };
 
 
 typedef AnchorMatrix LigatureAttach;	/* component-major--
 					 * in order of writing direction--,
 					 * mark-minor--
@@ -1225,25 +1225,25 @@ struct MarkLigPosFormat1
     return_trace (c->check_struct (this) &&
 		  markCoverage.sanitize (c, this) &&
 		  ligatureCoverage.sanitize (c, this) &&
 		  markArray.sanitize (c, this) &&
 		  ligatureArray.sanitize (c, this, (unsigned int) classCount));
   }
 
   protected:
-  USHORT	format;			/* Format identifier--format = 1 */
+  UINT16	format;			/* Format identifier--format = 1 */
   OffsetTo<Coverage>
 		markCoverage;		/* Offset to Mark Coverage table--from
 					 * beginning of MarkLigPos subtable */
   OffsetTo<Coverage>
 		ligatureCoverage;	/* Offset to Ligature Coverage
 					 * table--from beginning of MarkLigPos
 					 * subtable */
-  USHORT	classCount;		/* Number of defined mark classes */
+  UINT16	classCount;		/* Number of defined mark classes */
   OffsetTo<MarkArray>
 		markArray;		/* Offset to MarkArray table--from
 					 * beginning of MarkLigPos subtable */
   OffsetTo<LigatureArray>
 		ligatureArray;		/* Offset to LigatureArray table--from
 					 * beginning of MarkLigPos subtable */
   public:
   DEFINE_SIZE_STATIC (12);
@@ -1259,17 +1259,17 @@ struct MarkLigPos
     switch (u.format) {
     case 1: return_trace (c->dispatch (u.format1));
     default:return_trace (c->default_return_value ());
     }
   }
 
   protected:
   union {
-  USHORT		format;		/* Format identifier */
+  UINT16		format;		/* Format identifier */
   MarkLigPosFormat1	format1;
   } u;
 };
 
 
 typedef AnchorMatrix Mark2Array;	/* mark2-major--
 					 * in order of Mark2Coverage Index--,
 					 * mark1-minor--
@@ -1339,26 +1339,26 @@ struct MarkMarkPosFormat1
     return_trace (c->check_struct (this) &&
 		  mark1Coverage.sanitize (c, this) &&
 		  mark2Coverage.sanitize (c, this) &&
 		  mark1Array.sanitize (c, this) &&
 		  mark2Array.sanitize (c, this, (unsigned int) classCount));
   }
 
   protected:
-  USHORT	format;			/* Format identifier--format = 1 */
+  UINT16	format;			/* Format identifier--format = 1 */
   OffsetTo<Coverage>
 		mark1Coverage;		/* Offset to Combining Mark1 Coverage
 					 * table--from beginning of MarkMarkPos
 					 * subtable */
   OffsetTo<Coverage>
 		mark2Coverage;		/* Offset to Combining Mark2 Coverage
 					 * table--from beginning of MarkMarkPos
 					 * subtable */
-  USHORT	classCount;		/* Number of defined mark classes */
+  UINT16	classCount;		/* Number of defined mark classes */
   OffsetTo<MarkArray>
 		mark1Array;		/* Offset to Mark1Array table--from
 					 * beginning of MarkMarkPos subtable */
   OffsetTo<Mark2Array>
 		mark2Array;		/* Offset to Mark2Array table--from
 					 * beginning of MarkMarkPos subtable */
   public:
   DEFINE_SIZE_STATIC (12);
@@ -1374,17 +1374,17 @@ struct MarkMarkPos
     switch (u.format) {
     case 1: return_trace (c->dispatch (u.format1));
     default:return_trace (c->default_return_value ());
     }
   }
 
   protected:
   union {
-  USHORT		format;		/* Format identifier */
+  UINT16		format;		/* Format identifier */
   MarkMarkPosFormat1	format1;
   } u;
 };
 
 
 struct ContextPos : Context {};
 
 struct ChainContextPos : ChainContext {};
@@ -1433,17 +1433,17 @@ struct PosLookupSubTable
     case ChainContext:		return_trace (u.chainContext.dispatch (c));
     case Extension:		return_trace (u.extension.dispatch (c));
     default:			return_trace (c->default_return_value ());
     }
   }
 
   protected:
   union {
-  USHORT		sub_format;
+  UINT16		sub_format;
   SinglePos		single;
   PairPos		pair;
   CursivePos		cursive;
   MarkBasePos		markBase;
   MarkLigPos		markLig;
   MarkMarkPos		markMark;
   ContextPos		context;
   ChainContextPos	chainContext;
--- a/gfx/harfbuzz/src/hb-ot-layout-gsub-table.hh
+++ b/gfx/harfbuzz/src/hb-ot-layout-gsub-table.hh
@@ -39,31 +39,31 @@ struct SingleSubstFormat1
 {
   inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE (this);
     Coverage::Iter iter;
     for (iter.init (this+coverage); iter.more (); iter.next ())
     {
       /* TODO Switch to range-based API to work around malicious fonts.
-       * https://github.com/behdad/harfbuzz/issues/363 */
+       * https://github.com/harfbuzz/harfbuzz/issues/363 */
       hb_codepoint_t glyph_id = iter.get_glyph ();
       if (c->glyphs->has (glyph_id))
 	c->glyphs->add ((glyph_id + deltaGlyphID) & 0xFFFFu);
     }
   }
 
   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
     TRACE_COLLECT_GLYPHS (this);
     Coverage::Iter iter;
     for (iter.init (this+coverage); iter.more (); iter.next ())
     {
       /* TODO Switch to range-based API to work around malicious fonts.
-       * https://github.com/behdad/harfbuzz/issues/363 */
+       * https://github.com/harfbuzz/harfbuzz/issues/363 */
       hb_codepoint_t glyph_id = iter.get_glyph ();
       c->input->add (glyph_id);
       c->output->add ((glyph_id + deltaGlyphID) & 0xFFFFu);
     }
   }
 
   inline const Coverage &get_coverage (void) const
   {
@@ -105,51 +105,51 @@ struct SingleSubstFormat1
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (coverage.sanitize (c, this) && deltaGlyphID.sanitize (c));
   }
 
   protected:
-  USHORT	format;			/* Format identifier--format = 1 */
+  UINT16	format;			/* Format identifier--format = 1 */
   OffsetTo<Coverage>
 		coverage;		/* Offset to Coverage table--from
 					 * beginning of Substitution table */
-  SHORT		deltaGlyphID;		/* Add to original GlyphID to get
+  INT16		deltaGlyphID;		/* Add to original GlyphID to get
 					 * substitute GlyphID */
   public:
   DEFINE_SIZE_STATIC (6);
 };
 
 struct SingleSubstFormat2
 {
   inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE (this);
     Coverage::Iter iter;
     unsigned int count = substitute.len;
     for (iter.init (this+coverage); iter.more (); iter.next ())
     {
       if (unlikely (iter.get_coverage () >= count))
-        break; /* Work around malicious fonts. https://github.com/behdad/harfbuzz/issues/363 */
+        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
       if (c->glyphs->has (iter.get_glyph ()))
 	c->glyphs->add (substitute[iter.get_coverage ()]);
     }
   }
 
   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
     TRACE_COLLECT_GLYPHS (this);
     Coverage::Iter iter;
     unsigned int count = substitute.len;
     for (iter.init (this+coverage); iter.more (); iter.next ())
     {
       if (unlikely (iter.get_coverage () >= count))
-        break; /* Work around malicious fonts. https://github.com/behdad/harfbuzz/issues/363 */
+        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
       c->input->add (iter.get_glyph ());
       c->output->add (substitute[iter.get_coverage ()]);
     }
   }
 
   inline const Coverage &get_coverage (void) const
   {
     return this+coverage;
@@ -190,17 +190,17 @@ struct SingleSubstFormat2
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (coverage.sanitize (c, this) && substitute.sanitize (c));
   }
 
   protected:
-  USHORT	format;			/* Format identifier--format = 2 */
+  UINT16	format;			/* Format identifier--format = 2 */
   OffsetTo<Coverage>
 		coverage;		/* Offset to Coverage table--from
 					 * beginning of Substitution table */
   ArrayOf<GlyphID>
 		substitute;		/* Array of substitute
 					 * GlyphIDs--ordered by Coverage Index */
   public:
   DEFINE_SIZE_ARRAY (6, substitute);
@@ -244,17 +244,17 @@ struct SingleSubst
     case 1: return_trace (c->dispatch (u.format1));
     case 2: return_trace (c->dispatch (u.format2));
     default:return_trace (c->default_return_value ());
     }
   }
 
   protected:
   union {
-  USHORT		format;		/* Format identifier */
+  UINT16		format;		/* Format identifier */
   SingleSubstFormat1	format1;
   SingleSubstFormat2	format2;
   } u;
 };
 
 
 struct Sequence
 {
@@ -282,17 +282,17 @@ struct Sequence
     /* Special-case to make it in-place and not consider this
      * as a "multiplied" substitution. */
     if (unlikely (count == 1))
     {
       c->replace_glyph (substitute.array[0]);
       return_trace (true);
     }
     /* Spec disallows this, but Uniscribe allows it.
-     * https://github.com/behdad/harfbuzz/issues/253 */
+     * https://github.com/harfbuzz/harfbuzz/issues/253 */
     else if (unlikely (count == 0))
     {
       c->buffer->delete_glyph ();
       return_trace (true);
     }
 
     unsigned int klass = _hb_glyph_info_is_ligature (&c->buffer->cur()) ?
 			 HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH : 0;
@@ -334,17 +334,17 @@ struct MultipleSubstFormat1
   inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE (this);
     Coverage::Iter iter;
     unsigned int count = sequence.len;
     for (iter.init (this+coverage); iter.more (); iter.next ())
     {
       if (unlikely (iter.get_coverage () >= count))
-        break; /* Work around malicious fonts. https://github.com/behdad/harfbuzz/issues/363 */
+        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
       if (c->glyphs->has (iter.get_glyph ()))
 	(this+sequence[iter.get_coverage ()]).closure (c);
     }
   }
 
   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
     TRACE_COLLECT_GLYPHS (this);
@@ -395,17 +395,17 @@ struct MultipleSubstFormat1
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (coverage.sanitize (c, this) && sequence.sanitize (c, this));
   }
 
   protected:
-  USHORT	format;			/* Format identifier--format = 1 */
+  UINT16	format;			/* Format identifier--format = 1 */
   OffsetTo<Coverage>
 		coverage;		/* Offset to Coverage table--from
 					 * beginning of Substitution table */
   OffsetArrayOf<Sequence>
 		sequence;		/* Array of Sequence tables
 					 * ordered by Coverage Index */
   public:
   DEFINE_SIZE_ARRAY (6, sequence);
@@ -437,17 +437,17 @@ struct MultipleSubst
     switch (u.format) {
     case 1: return_trace (c->dispatch (u.format1));
     default:return_trace (c->default_return_value ());
     }
   }
 
   protected:
   union {
-  USHORT		format;		/* Format identifier */
+  UINT16		format;		/* Format identifier */
   MultipleSubstFormat1	format1;
   } u;
 };
 
 
 typedef ArrayOf<GlyphID> AlternateSet;	/* Array of alternate GlyphIDs--in
 					 * arbitrary order */
 
@@ -456,17 +456,17 @@ struct AlternateSubstFormat1
   inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE (this);
     Coverage::Iter iter;
     unsigned int count = alternateSet.len;
     for (iter.init (this+coverage); iter.more (); iter.next ())
     {
       if (unlikely (iter.get_coverage () >= count))
-        break; /* Work around malicious fonts. https://github.com/behdad/harfbuzz/issues/363 */
+        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
       if (c->glyphs->has (iter.get_glyph ())) {
 	const AlternateSet &alt_set = this+alternateSet[iter.get_coverage ()];
 	unsigned int count = alt_set.len;
 	for (unsigned int i = 0; i < count; i++)
 	  c->glyphs->add (alt_set[i]);
       }
     }
   }
@@ -474,17 +474,17 @@ struct AlternateSubstFormat1
   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
     TRACE_COLLECT_GLYPHS (this);
     Coverage::Iter iter;
     unsigned int count = alternateSet.len;
     for (iter.init (this+coverage); iter.more (); iter.next ())
     {
       if (unlikely (iter.get_coverage () >= count))
-        break; /* Work around malicious fonts. https://github.com/behdad/harfbuzz/issues/363 */
+        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
       c->input->add (iter.get_glyph ());
       const AlternateSet &alt_set = this+alternateSet[iter.get_coverage ()];
       unsigned int count = alt_set.len;
       for (unsigned int i = 0; i < count; i++)
 	c->output->add (alt_set[i]);
     }
   }
 
@@ -547,17 +547,17 @@ struct AlternateSubstFormat1
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (coverage.sanitize (c, this) && alternateSet.sanitize (c, this));
   }
 
   protected:
-  USHORT	format;			/* Format identifier--format = 1 */
+  UINT16	format;			/* Format identifier--format = 1 */
   OffsetTo<Coverage>
 		coverage;		/* Offset to Coverage table--from
 					 * beginning of Substitution table */
   OffsetArrayOf<AlternateSet>
 		alternateSet;		/* Array of AlternateSet tables
 					 * ordered by Coverage Index */
   public:
   DEFINE_SIZE_ARRAY (6, alternateSet);
@@ -589,17 +589,17 @@ struct AlternateSubst
     switch (u.format) {
     case 1: return_trace (c->dispatch (u.format1));
     default:return_trace (c->default_return_value ());
     }
   }
 
   protected:
   union {
-  USHORT		format;		/* Format identifier */
+  UINT16		format;		/* Format identifier */
   AlternateSubstFormat1	format1;
   } u;
 };
 
 
 struct Ligature
 {
   inline void closure (hb_closure_context_t *c) const
@@ -787,31 +787,31 @@ struct LigatureSubstFormat1
   inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE (this);
     Coverage::Iter iter;
     unsigned int count = ligatureSet.len;
     for (iter.init (this+coverage); iter.more (); iter.next ())
     {
       if (unlikely (iter.get_coverage () >= count))
-        break; /* Work around malicious fonts. https://github.com/behdad/harfbuzz/issues/363 */
+        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
       if (c->glyphs->has (iter.get_glyph ()))
 	(this+ligatureSet[iter.get_coverage ()]).closure (c);
     }
   }
 
   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
     TRACE_COLLECT_GLYPHS (this);
     Coverage::Iter iter;
     unsigned int count = ligatureSet.len;
     for (iter.init (this+coverage); iter.more (); iter.next ())
     {
       if (unlikely (iter.get_coverage () >= count))
-        break; /* Work around malicious fonts. https://github.com/behdad/harfbuzz/issues/363 */
+        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
       c->input->add (iter.get_glyph ());
       (this+ligatureSet[iter.get_coverage ()]).collect_glyphs (c);
     }
   }
 
   inline const Coverage &get_coverage (void) const
   {
     return this+coverage;
@@ -863,17 +863,17 @@ struct LigatureSubstFormat1
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (coverage.sanitize (c, this) && ligatureSet.sanitize (c, this));
   }
 
   protected:
-  USHORT	format;			/* Format identifier--format = 1 */
+  UINT16	format;			/* Format identifier--format = 1 */
   OffsetTo<Coverage>
 		coverage;		/* Offset to Coverage table--from
 					 * beginning of Substitution table */
   OffsetArrayOf<LigatureSet>
 		ligatureSet;		/* Array LigatureSet tables
 					 * ordered by Coverage Index */
   public:
   DEFINE_SIZE_ARRAY (6, ligatureSet);
@@ -913,17 +913,17 @@ struct LigatureSubst
     switch (u.format) {
     case 1: return_trace (c->dispatch (u.format1));
     default:return_trace (c->default_return_value ());
     }
   }
 
   protected:
   union {
-  USHORT		format;		/* Format identifier */
+  UINT16		format;		/* Format identifier */
   LigatureSubstFormat1	format1;
   } u;
 };
 
 
 struct ContextSubst : Context {};
 
 struct ChainContextSubst : ChainContext {};
@@ -956,17 +956,17 @@ struct ReverseChainSingleSubstFormat1
         return;
 
     const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
     Coverage::Iter iter;
     count = substitute.len;
     for (iter.init (this+coverage); iter.more (); iter.next ())
     {
       if (unlikely (iter.get_coverage () >= count))
-        break; /* Work around malicious fonts. https://github.com/behdad/harfbuzz/issues/363 */
+        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
       if (c->glyphs->has (iter.get_glyph ()))
 	c->glyphs->add (substitute[iter.get_coverage ()]);
     }
   }
 
   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
     TRACE_COLLECT_GLYPHS (this);
@@ -1011,21 +1011,21 @@ struct ReverseChainSingleSubstFormat1
     unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
     if (likely (index == NOT_COVERED)) return_trace (false);
 
     const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
     const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
 
   unsigned int start_index = 0, end_index = 0;
     if (match_backtrack (c,
-			 backtrack.len, (USHORT *) backtrack.array,
+			 backtrack.len, (UINT16 *) backtrack.array,
 			 match_coverage, this,
 			 &start_index) &&
         match_lookahead (c,
-			 lookahead.len, (USHORT *) lookahead.array,
+			 lookahead.len, (UINT16 *) lookahead.array,
 			 match_coverage, this,
 			 1, &end_index))
     {
       c->buffer->unsafe_to_break_from_outbuffer (start_index, end_index);
       c->replace_glyph_inplace (substitute[index]);
       /* Note: We DON'T decrease buffer->idx.  The main loop does it
        * for us.  This is useful for preventing surprises if someone
        * calls us through a Context lookup. */
@@ -1043,17 +1043,17 @@ struct ReverseChainSingleSubstFormat1
     const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
     if (!lookahead.sanitize (c, this))
       return_trace (false);
     const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
     return_trace (substitute.sanitize (c));
   }
 
   protected:
-  USHORT	format;			/* Format identifier--format = 1 */
+  UINT16	format;			/* Format identifier--format = 1 */
   OffsetTo<Coverage>
 		coverage;		/* Offset to Coverage table--from
 					 * beginning of table */
   OffsetArrayOf<Coverage>
 		backtrack;		/* Array of coverage tables
 					 * in backtracking sequence, in  glyph
 					 * sequence order */
   OffsetArrayOf<Coverage>
@@ -1077,17 +1077,17 @@ struct ReverseChainSingleSubst
     switch (u.format) {
     case 1: return_trace (c->dispatch (u.format1));
     default:return_trace (c->default_return_value ());
     }
   }
 
   protected:
   union {
-  USHORT				format;		/* Format identifier */
+  UINT16				format;		/* Format identifier */
   ReverseChainSingleSubstFormat1	format1;
   } u;
 };
 
 
 
 /*
  * SubstLookup
@@ -1123,17 +1123,17 @@ struct SubstLookupSubTable
     case Extension:		return_trace (u.extension.dispatch (c));
     case ReverseChainSingle:	return_trace (u.reverseChainContextSingle.dispatch (c));
     default:			return_trace (c->default_return_value ());
     }
   }
 
   protected:
   union {
-  USHORT			sub_format;
+  UINT16			sub_format;
   SingleSubst			single;
   MultipleSubst			multiple;
   AlternateSubst		alternate;
   LigatureSubst			ligature;
   ContextSubst			context;
   ChainContextSubst		chainContext;
   ExtensionSubst		extension;
   ReverseChainSingleSubst	reverseChainContextSingle;
@@ -1275,19 +1275,21 @@ struct SubstLookup : Lookup
   {
     TRACE_SANITIZE (this);
     if (unlikely (!Lookup::sanitize (c))) return_trace (false);
     if (unlikely (!dispatch (c))) return_trace (false);
 
     if (unlikely (get_type () == SubstLookupSubTable::Extension))
     {
       /* The spec says all subtables of an Extension lookup should
-       * have the same type.  This is specially important if one has
-       * a reverse type! */
+       * have the same type, which shall not be the Extension type
+       * itself. This is specially important if one has a reverse type! */
       unsigned int type = get_subtable (0).u.extension.get_type ();
+      if (unlikely (type == SubstLookupSubTable::Extension))
+	return_trace (false);
       unsigned int count = get_subtable_count ();
       for (unsigned int i = 1; i < count; i++)
         if (get_subtable (i).u.extension.get_type () != type)
 	  return_trace (false);
     }
     return_trace (true);
   }
 };
--- a/gfx/harfbuzz/src/hb-ot-layout-gsubgpos-private.hh
+++ b/gfx/harfbuzz/src/hb-ot-layout-gsubgpos-private.hh
@@ -229,17 +229,17 @@ struct hb_apply_context_t :
 	     ignore_zwj (false),
 	     mask (-1),
 #define arg1(arg) (arg) /* Remove the macro to see why it's needed! */
 	     syllable arg1(0),
 #undef arg1
 	     match_func (nullptr),
 	     match_data (nullptr) {};
 
-    typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const USHORT &value, const void *data);
+    typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const UINT16 &value, const void *data);
 
     inline void set_ignore_zwnj (bool ignore_zwnj_) { ignore_zwnj = ignore_zwnj_; }
     inline void set_ignore_zwj (bool ignore_zwj_) { ignore_zwj = ignore_zwj_; }
     inline void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; }
     inline void set_mask (hb_mask_t mask_) { mask = mask_; }
     inline void set_syllable (uint8_t syllable_)  { syllable = syllable_; }
     inline void set_match_func (match_func_t match_func_,
 				const void *match_data_)
@@ -247,17 +247,17 @@ struct hb_apply_context_t :
 
     enum may_match_t {
       MATCH_NO,
       MATCH_YES,
       MATCH_MAYBE
     };
 
     inline may_match_t may_match (const hb_glyph_info_t &info,
-				  const USHORT          *glyph_data) const
+				  const UINT16          *glyph_data) const
     {
       if (!(info.mask & mask) ||
 	  (syllable && syllable != info.syllable ()))
 	return MATCH_NO;
 
       if (match_func)
         return match_func (info.codepoint, *glyph_data, match_data) ? MATCH_YES : MATCH_NO;
 
@@ -310,17 +310,17 @@ struct hb_apply_context_t :
       matcher.set_mask (context_match ? -1 : c->lookup_mask);
     }
     inline void set_lookup_props (unsigned int lookup_props)
     {
       matcher.set_lookup_props (lookup_props);
     }
     inline void set_match_func (matcher_t::match_func_t match_func_,
 				const void *match_data_,
-				const USHORT glyph_data[])
+				const UINT16 glyph_data[])
     {
       matcher.set_match_func (match_func_, match_data_);
       match_glyph_data = glyph_data;
     }
 
     inline void reset (unsigned int start_index_,
 		       unsigned int num_items_)
     {
@@ -393,32 +393,32 @@ struct hb_apply_context_t :
       }
       return false;
     }
 
     unsigned int idx;
     protected:
     hb_apply_context_t *c;
     matcher_t matcher;
-    const USHORT *match_glyph_data;
+    const UINT16 *match_glyph_data;
 
     unsigned int num_items;
     unsigned int end;
   };
 
 
   inline const char *get_name (void) { return "APPLY"; }
   typedef return_t (*recurse_func_t) (hb_apply_context_t *c, unsigned int lookup_index);
   template <typename T>
   inline return_t dispatch (const T &obj) { return obj.apply (this); }
   static return_t default_return_value (void) { return false; }
   bool stop_sublookup_iteration (return_t r) const { return r; }
   return_t recurse (unsigned int lookup_index)
   {
-    if (unlikely (nesting_level_left == 0 || !recurse_func))
+    if (unlikely (nesting_level_left == 0 || !recurse_func || buffer->max_ops-- <= 0))
       return default_return_value ();
 
     nesting_level_left--;
     bool ret = recurse_func (this, lookup_index);
     nesting_level_left++;
     return ret;
   }
 
@@ -563,121 +563,121 @@ struct hb_apply_context_t :
   {
     _set_glyph_props (glyph_index, class_guess, false, true);
     buffer->output_glyph (glyph_index);
   }
 };
 
 
 
-typedef bool (*intersects_func_t) (hb_set_t *glyphs, const USHORT &value, const void *data);
-typedef void (*collect_glyphs_func_t) (hb_set_t *glyphs, const USHORT &value, const void *data);
-typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const USHORT &value, const void *data);
+typedef bool (*intersects_func_t) (hb_set_t *glyphs, const UINT16 &value, const void *data);
+typedef void (*collect_glyphs_func_t) (hb_set_t *glyphs, const UINT16 &value, const void *data);
+typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const UINT16 &value, const void *data);
 
 struct ContextClosureFuncs
 {
   intersects_func_t intersects;
 };
 struct ContextCollectGlyphsFuncs
 {
   collect_glyphs_func_t collect;
 };
 struct ContextApplyFuncs
 {
   match_func_t match;
 };
 
 
-static inline bool intersects_glyph (hb_set_t *glyphs, const USHORT &value, const void *data HB_UNUSED)
+static inline bool intersects_glyph (hb_set_t *glyphs, const UINT16 &value, const void *data HB_UNUSED)
 {
   return glyphs->has (value);
 }
-static inline bool intersects_class (hb_set_t *glyphs, const USHORT &value, const void *data)
+static inline bool intersects_class (hb_set_t *glyphs, const UINT16 &value, const void *data)
 {
   const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
   return class_def.intersects_class (glyphs, value);
 }
-static inline bool intersects_coverage (hb_set_t *glyphs, const USHORT &value, const void *data)
+static inline bool intersects_coverage (hb_set_t *glyphs, const UINT16 &value, const void *data)
 {
   const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
   return (data+coverage).intersects (glyphs);
 }
 
 static inline bool intersects_array (hb_closure_context_t *c,
 				     unsigned int count,
-				     const USHORT values[],
+				     const UINT16 values[],
 				     intersects_func_t intersects_func,
 				     const void *intersects_data)
 {
   for (unsigned int i = 0; i < count; i++)
     if (likely (!intersects_func (c->glyphs, values[i], intersects_data)))
       return false;
   return true;
 }
 
 
-static inline void collect_glyph (hb_set_t *glyphs, const USHORT &value, const void *data HB_UNUSED)
+static inline void collect_glyph (hb_set_t *glyphs, const UINT16 &value, const void *data HB_UNUSED)
 {
   glyphs->add (value);
 }
-static inline void collect_class (hb_set_t *glyphs, const USHORT &value, const void *data)
+static inline void collect_class (hb_set_t *glyphs, const UINT16 &value, const void *data)
 {
   const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
   class_def.add_class (glyphs, value);
 }
-static inline void collect_coverage (hb_set_t *glyphs, const USHORT &value, const void *data)
+static inline void collect_coverage (hb_set_t *glyphs, const UINT16 &value, const void *data)
 {
   const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
   (data+coverage).add_coverage (glyphs);
 }
 static inline void collect_array (hb_collect_glyphs_context_t *c HB_UNUSED,
 				  hb_set_t *glyphs,
 				  unsigned int count,
-				  const USHORT values[],
+				  const UINT16 values[],
 				  collect_glyphs_func_t collect_func,
 				  const void *collect_data)
 {
   for (unsigned int i = 0; i < count; i++)
     collect_func (glyphs, values[i], collect_data);
 }
 
 
-static inline bool match_glyph (hb_codepoint_t glyph_id, const USHORT &value, const void *data HB_UNUSED)
+static inline bool match_glyph (hb_codepoint_t glyph_id, const UINT16 &value, const void *data HB_UNUSED)
 {
   return glyph_id == value;
 }
-static inline bool match_class (hb_codepoint_t glyph_id, const USHORT &value, const void *data)
+static inline bool match_class (hb_codepoint_t glyph_id, const UINT16 &value, const void *data)
 {
   const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
   return class_def.get_class (glyph_id) == value;
 }
-static inline bool match_coverage (hb_codepoint_t glyph_id, const USHORT &value, const void *data)
+static inline bool match_coverage (hb_codepoint_t glyph_id, const UINT16 &value, const void *data)
 {
   const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
   return (data+coverage).get_coverage (glyph_id) != NOT_COVERED;
 }
 
 static inline bool would_match_input (hb_would_apply_context_t *c,
 				      unsigned int count, /* Including the first glyph (not matched) */
-				      const USHORT input[], /* Array of input values--start with second glyph */
+				      const UINT16 input[], /* Array of input values--start with second glyph */
 				      match_func_t match_func,
 				      const void *match_data)
 {
   if (count != c->len)
     return false;
 
   for (unsigned int i = 1; i < count; i++)
     if (likely (!match_func (c->glyphs[i], input[i - 1], match_data)))
       return false;
 
   return true;
 }
 static inline bool match_input (hb_apply_context_t *c,
 				unsigned int count, /* Including the first glyph (not matched) */
-				const USHORT input[], /* Array of input values--start with second glyph */
+				const UINT16 input[], /* Array of input values--start with second glyph */
 				match_func_t match_func,
 				const void *match_data,
 				unsigned int *end_offset,
 				unsigned int match_positions[HB_MAX_CONTEXT_LENGTH],
 				bool *p_is_mark_ligature = nullptr,
 				unsigned int *p_total_component_count = nullptr)
 {
   TRACE_APPLY (nullptr);
@@ -706,17 +706,17 @@ static inline bool match_input (hb_apply
    *
    *   o If a ligature tries ligating with marks that belong to it itself, go ahead,
    *     assuming that the font designer knows what they are doing (otherwise it can
    *     break Indic stuff when a matra wants to ligate with a conjunct,
    *
    *   o If two marks want to ligate and they belong to different components of the
    *     same ligature glyph, and said ligature glyph is to be ignored according to
    *     mark-filtering rules, then allow.
-   *     https://github.com/behdad/harfbuzz/issues/545
+   *     https://github.com/harfbuzz/harfbuzz/issues/545
    */
 
   bool is_mark_ligature = _hb_glyph_info_is_mark (&buffer->cur());
 
   unsigned int total_component_count = 0;
   total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->cur());
 
   unsigned int first_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
@@ -891,17 +891,17 @@ static inline bool ligate_input (hb_appl
 	break;
     }
   }
   return_trace (true);
 }
 
 static inline bool match_backtrack (hb_apply_context_t *c,
 				    unsigned int count,
-				    const USHORT backtrack[],
+				    const UINT16 backtrack[],
 				    match_func_t match_func,
 				    const void *match_data,
 				    unsigned int *match_start)
 {
   TRACE_APPLY (nullptr);
 
   hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context;
   skippy_iter.reset (c->buffer->backtrack_len (), count);
@@ -913,17 +913,17 @@ static inline bool match_backtrack (hb_a
 
   *match_start = skippy_iter.idx;
 
   return_trace (true);
 }
 
 static inline bool match_lookahead (hb_apply_context_t *c,
 				    unsigned int count,
-				    const USHORT lookahead[],
+				    const UINT16 lookahead[],
 				    match_func_t match_func,
 				    const void *match_data,
 				    unsigned int offset,
 				    unsigned int *end_index)
 {
   TRACE_APPLY (nullptr);
 
   hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context;
@@ -944,19 +944,19 @@ static inline bool match_lookahead (hb_a
 struct LookupRecord
 {
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this));
   }
 
-  USHORT	sequenceIndex;		/* Index into current glyph
+  UINT16	sequenceIndex;		/* Index into current glyph
 					 * sequence--first glyph = 0 */
-  USHORT	lookupListIndex;	/* Lookup to apply to that
+  UINT16	lookupListIndex;	/* Lookup to apply to that
 					 * position--zero--based */
   public:
   DEFINE_SIZE_STATIC (4);
 };
 
 
 template <typename context_t>
 static inline void recurse_lookups (context_t *c,
@@ -997,17 +997,21 @@ static inline bool apply_lookup (hb_appl
     if (idx >= count)
       continue;
 
     /* Don't recurse to ourself at same position.
      * Note that this test is too naive, it doesn't catch longer loops. */
     if (idx == 0 && lookupRecord[i].lookupListIndex == c->lookup_index)
       continue;
 
-    buffer->move_to (match_positions[idx]);
+    if (unlikely (!buffer->move_to (match_positions[idx])))
+      break;
+
+    if (unlikely (buffer->max_ops <= 0))
+      break;
 
     unsigned int orig_len = buffer->backtrack_len () + buffer->lookahead_len ();
     if (!c->recurse (lookupRecord[i].lookupListIndex))
       continue;
 
     unsigned int new_len = buffer->backtrack_len () + buffer->lookahead_len ();
     int delta = new_len - orig_len;
 
@@ -1103,56 +1107,56 @@ struct ContextCollectGlyphsLookupContext
 struct ContextApplyLookupContext
 {
   ContextApplyFuncs funcs;
   const void *match_data;
 };
 
 static inline void context_closure_lookup (hb_closure_context_t *c,
 					   unsigned int inputCount, /* Including the first glyph (not matched) */
-					   const USHORT input[], /* Array of input values--start with second glyph */
+					   const UINT16 input[], /* Array of input values--start with second glyph */
 					   unsigned int lookupCount,
 					   const LookupRecord lookupRecord[],
 					   ContextClosureLookupContext &lookup_context)
 {
   if (intersects_array (c,
 			inputCount ? inputCount - 1 : 0, input,
 			lookup_context.funcs.intersects, lookup_context.intersects_data))
     recurse_lookups (c,
 		     lookupCount, lookupRecord);
 }
 
 static inline void context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c,
 						  unsigned int inputCount, /* Including the first glyph (not matched) */
-						  const USHORT input[], /* Array of input values--start with second glyph */
+						  const UINT16 input[], /* Array of input values--start with second glyph */
 						  unsigned int lookupCount,
 						  const LookupRecord lookupRecord[],
 						  ContextCollectGlyphsLookupContext &lookup_context)
 {
   collect_array (c, c->input,
 		 inputCount ? inputCount - 1 : 0, input,
 		 lookup_context.funcs.collect, lookup_context.collect_data);
   recurse_lookups (c,
 		   lookupCount, lookupRecord);
 }
 
 static inline bool context_would_apply_lookup (hb_would_apply_context_t *c,
 					       unsigned int inputCount, /* Including the first glyph (not matched) */
-					       const USHORT input[], /* Array of input values--start with second glyph */
+					       const UINT16 input[], /* Array of input values--start with second glyph */
 					       unsigned int lookupCount HB_UNUSED,
 					       const LookupRecord lookupRecord[] HB_UNUSED,
 					       ContextApplyLookupContext &lookup_context)
 {
   return would_match_input (c,
 			    inputCount, input,
 			    lookup_context.funcs.match, lookup_context.match_data);
 }
 static inline bool context_apply_lookup (hb_apply_context_t *c,
 					 unsigned int inputCount, /* Including the first glyph (not matched) */
-					 const USHORT input[], /* Array of input values--start with second glyph */
+					 const UINT16 input[], /* Array of input values--start with second glyph */
 					 unsigned int lookupCount,
 					 const LookupRecord lookupRecord[],
 					 ContextApplyLookupContext &lookup_context)
 {
   unsigned int match_length = 0;
   unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
   return match_input (c,
 		      inputCount, input,
@@ -1208,21 +1212,21 @@ struct Rule
     return_trace (inputCount.sanitize (c) &&
 		  lookupCount.sanitize (c) &&
 		  c->check_range (inputZ,
 				  inputZ[0].static_size * inputCount +
 				  lookupRecordX[0].static_size * lookupCount));
   }
 
   protected:
-  USHORT	inputCount;		/* Total number of glyphs in input
+  UINT16	inputCount;		/* Total number of glyphs in input
 					 * glyph sequence--includes the first
 					 * glyph */
-  USHORT	lookupCount;		/* Number of LookupRecords */
-  USHORT	inputZ[VAR];		/* Array of match inputs--start with
+  UINT16	lookupCount;		/* Number of LookupRecords */
+  UINT16	inputZ[VAR];		/* Array of match inputs--start with
 					 * second glyph */
   LookupRecord	lookupRecordX[VAR];	/* Array of LookupRecords--in
 					 * design order */
   public:
   DEFINE_SIZE_ARRAY2 (4, inputZ, lookupRecordX);
 };
 
 struct RuleSet
@@ -1352,17 +1356,17 @@ struct ContextFormat1
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
   }
 
   protected:
-  USHORT	format;			/* Format identifier--format = 1 */
+  UINT16	format;			/* Format identifier--format = 1 */
   OffsetTo<Coverage>
 		coverage;		/* Offset to Coverage table--from
 					 * beginning of table */
   OffsetArrayOf<RuleSet>
 		ruleSet;		/* Array of RuleSet tables
 					 * ordered by Coverage Index */
   public:
   DEFINE_SIZE_ARRAY (6, ruleSet);
@@ -1445,17 +1449,17 @@ struct ContextFormat2
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (coverage.sanitize (c, this) && classDef.sanitize (c, this) && ruleSet.sanitize (c, this));
   }
 
   protected:
-  USHORT	format;			/* Format identifier--format = 2 */
+  UINT16	format;			/* Format identifier--format = 2 */
   OffsetTo<Coverage>
 		coverage;		/* Offset to Coverage table--from
 					 * beginning of table */
   OffsetTo<ClassDef>
 		classDef;		/* Offset to glyph ClassDef table--from
 					 * beginning of table */
   OffsetArrayOf<RuleSet>
 		ruleSet;		/* Array of RuleSet tables
@@ -1474,48 +1478,48 @@ struct ContextFormat3
       return;
 
     const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ, coverageZ[0].static_size * glyphCount);
     struct ContextClosureLookupContext lookup_context = {
       {intersects_coverage},
       this
     };
     context_closure_lookup (c,
-			    glyphCount, (const USHORT *) (coverageZ + 1),
+			    glyphCount, (const UINT16 *) (coverageZ + 1),
 			    lookupCount, lookupRecord,
 			    lookup_context);
   }
 
   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
     TRACE_COLLECT_GLYPHS (this);
     (this+coverageZ[0]).add_coverage (c->input);
 
     const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ, coverageZ[0].static_size * glyphCount);
     struct ContextCollectGlyphsLookupContext lookup_context = {
       {collect_coverage},
       this
     };
 
     context_collect_glyphs_lookup (c,
-				   glyphCount, (const USHORT *) (coverageZ + 1),
+				   glyphCount, (const UINT16 *) (coverageZ + 1),
 				   lookupCount, lookupRecord,
 				   lookup_context);
   }
 
   inline bool would_apply (hb_would_apply_context_t *c) const
   {
     TRACE_WOULD_APPLY (this);
 
     const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ, coverageZ[0].static_size * glyphCount);
     struct ContextApplyLookupContext lookup_context = {
       {match_coverage},
       this
     };
-    return_trace (context_would_apply_lookup (c, glyphCount, (const USHORT *) (coverageZ + 1), lookupCount, lookupRecord, lookup_context));
+    return_trace (context_would_apply_lookup (c, glyphCount, (const UINT16 *) (coverageZ + 1), lookupCount, lookupRecord, lookup_context));
   }
 
   inline const Coverage &get_coverage (void) const
   {
     return this+coverageZ[0];
   }
 
   inline bool apply (hb_apply_context_t *c) const
@@ -1524,37 +1528,37 @@ struct ContextFormat3
     unsigned int index = (this+coverageZ[0]).get_coverage (c->buffer->cur().codepoint);
     if (likely (index == NOT_COVERED)) return_trace (false);
 
     const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ, coverageZ[0].static_size * glyphCount);
     struct ContextApplyLookupContext lookup_context = {
       {match_coverage},
       this
     };
-    return_trace (context_apply_lookup (c, glyphCount, (const USHORT *) (coverageZ + 1), lookupCount, lookupRecord, lookup_context));
+    return_trace (context_apply_lookup (c, glyphCount, (const UINT16 *) (coverageZ + 1), lookupCount, lookupRecord, lookup_context));
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     if (!c->check_struct (this)) return_trace (false);
     unsigned int count = glyphCount;
     if (!count) return_trace (false); /* We want to access coverageZ[0] freely. */
     if (!c->check_array (coverageZ, coverageZ[0].static_size, count)) return_trace (false);
     for (unsigned int i = 0; i < count; i++)
       if (!coverageZ[i].sanitize (c, this)) return_trace (false);
     const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ, coverageZ[0].static_size * count);
     return_trace (c->check_array (lookupRecord, lookupRecord[0].static_size, lookupCount));
   }
 
   protected:
-  USHORT	format;			/* Format identifier--format = 3 */
-  USHORT	glyphCount;		/* Number of glyphs in the input glyph
+  UINT16	format;			/* Format identifier--format = 3 */
+  UINT16	glyphCount;		/* Number of glyphs in the input glyph
 					 * sequence */
-  USHORT	lookupCount;		/* Number of LookupRecords */
+  UINT16	lookupCount;		/* Number of LookupRecords */
   OffsetTo<Coverage>
 		coverageZ[VAR];		/* Array of offsets to Coverage
 					 * table in glyph sequence order */
   LookupRecord	lookupRecordX[VAR];	/* Array of LookupRecords--in
 					 * design order */
   public:
   DEFINE_SIZE_ARRAY2 (6, coverageZ, lookupRecordX);
 };
@@ -1571,17 +1575,17 @@ struct Context
     case 2: return_trace (c->dispatch (u.format2));
     case 3: return_trace (c->dispatch (u.format3));
     default:return_trace (c->default_return_value ());
     }
   }
 
   protected:
   union {
-  USHORT		format;		/* Format identifier */
+  UINT16		format;		/* Format identifier */
   ContextFormat1	format1;
   ContextFormat2	format2;
   ContextFormat3	format3;
   } u;
 };
 
 
 /* Chaining Contextual lookups */
@@ -1601,21 +1605,21 @@ struct ChainContextCollectGlyphsLookupCo
 struct ChainContextApplyLookupContext
 {
   ContextApplyFuncs funcs;
   const void *match_data[3];
 };
 
 static inline void chain_context_closure_lookup (hb_closure_context_t *c,
 						 unsigned int backtrackCount,
-						 const USHORT backtrack[],
+						 const UINT16 backtrack[],
 						 unsigned int inputCount, /* Including the first glyph (not matched) */
-						 const USHORT input[], /* Array of input values--start with second glyph */
+						 const UINT16 input[], /* Array of input values--start with second glyph */
 						 unsigned int lookaheadCount,
-						 const USHORT lookahead[],
+						 const UINT16 lookahead[],
 						 unsigned int lookupCount,
 						 const LookupRecord lookupRecord[],
 						 ChainContextClosureLookupContext &lookup_context)
 {
   if (intersects_array (c,
 			backtrackCount, backtrack,
 			lookup_context.funcs.intersects, lookup_context.intersects_data[0])
    && intersects_array (c,
@@ -1625,21 +1629,21 @@ static inline void chain_context_closure
 		       lookaheadCount, lookahead,
 		       lookup_context.funcs.intersects, lookup_context.intersects_data[2]))
     recurse_lookups (c,
 		     lookupCount, lookupRecord);
 }
 
 static inline void chain_context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c,
 						        unsigned int backtrackCount,
-						        const USHORT backtrack[],
+						        const UINT16 backtrack[],
 						        unsigned int inputCount, /* Including the first glyph (not matched) */
-						        const USHORT input[], /* Array of input values--start with second glyph */
+						        const UINT16 input[], /* Array of input values--start with second glyph */
 						        unsigned int lookaheadCount,
-						        const USHORT lookahead[],
+						        const UINT16 lookahead[],
 						        unsigned int lookupCount,
 						        const LookupRecord lookupRecord[],
 						        ChainContextCollectGlyphsLookupContext &lookup_context)
 {
   collect_array (c, c->before,
 		 backtrackCount, backtrack,
 		 lookup_context.funcs.collect, lookup_context.collect_data[0]);
   collect_array (c, c->input,
@@ -1649,38 +1653,38 @@ static inline void chain_context_collect
 		 lookaheadCount, lookahead,
 		 lookup_context.funcs.collect, lookup_context.collect_data[2]);
   recurse_lookups (c,
 		   lookupCount, lookupRecord);
 }
 
 static inline bool chain_context_would_apply_lookup (hb_would_apply_context_t *c,
 						     unsigned int backtrackCount,
-						     const USHORT backtrack[] HB_UNUSED,
+						     const UINT16 backtrack[] HB_UNUSED,
 						     unsigned int inputCount, /* Including the first glyph (not matched) */
-						     const USHORT input[], /* Array of input values--start with second glyph */
+						     const UINT16 input[], /* Array of input values--start with second glyph */
 						     unsigned int lookaheadCount,
-						     const USHORT lookahead[] HB_UNUSED,
+						     const UINT16 lookahead[] HB_UNUSED,
 						     unsigned int lookupCount HB_UNUSED,
 						     const LookupRecord lookupRecord[] HB_UNUSED,
 						     ChainContextApplyLookupContext &lookup_context)
 {
   return (c->zero_context ? !backtrackCount && !lookaheadCount : true)
       && would_match_input (c,
 			    inputCount, input,
 			    lookup_context.funcs.match, lookup_context.match_data[1]);
 }
 
 static inline bool chain_context_apply_lookup (hb_apply_context_t *c,
 					       unsigned int backtrackCount,
-					       const USHORT backtrack[],
+					       const UINT16 backtrack[],
 					       unsigned int inputCount, /* Including the first glyph (not matched) */
-					       const USHORT input[], /* Array of input values--start with second glyph */
+					       const UINT16 input[], /* Array of input values--start with second glyph */
 					       unsigned int lookaheadCount,
-					       const USHORT lookahead[],
+					       const UINT16 lookahead[],
 					       unsigned int lookupCount,
 					       const LookupRecord lookupRecord[],
 					       ChainContextApplyLookupContext &lookup_context)
 {
   unsigned int start_index = 0, match_length = 0, end_index = 0;
   unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
   return match_input (c,
 		      inputCount, input,
@@ -1701,88 +1705,88 @@ static inline bool chain_context_apply_l
 		       match_length));
 }
 
 struct ChainRule
 {
   inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
   {
     TRACE_CLOSURE (this);
-    const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
-    const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
+    const HeadlessArrayOf<UINT16> &input = StructAfter<HeadlessArrayOf<UINT16> > (backtrack);
+    const ArrayOf<UINT16> &lookahead = StructAfter<ArrayOf<UINT16> > (input);
     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
     chain_context_closure_lookup (c,
 				  backtrack.len, backtrack.array,
 				  input.len, input.array,
 				  lookahead.len, lookahead.array,
 				  lookup.len, lookup.array,
 				  lookup_context);
   }
 
   inline void collect_glyphs (hb_collect_glyphs_context_t *c, ChainContextCollectGlyphsLookupContext &lookup_context) const
   {
     TRACE_COLLECT_GLYPHS (this);
-    const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
-    const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
+    const HeadlessArrayOf<UINT16> &input = StructAfter<HeadlessArrayOf<UINT16> > (backtrack);
+    const ArrayOf<UINT16> &lookahead = StructAfter<ArrayOf<UINT16> > (input);
     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
     chain_context_collect_glyphs_lookup (c,
 					 backtrack.len, backtrack.array,
 					 input.len, input.array,
 					 lookahead.len, lookahead.array,
 					 lookup.len, lookup.array,
 					 lookup_context);
   }
 
   inline bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
   {
     TRACE_WOULD_APPLY (this);
-    const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
-    const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
+    const HeadlessArrayOf<UINT16> &input = StructAfter<HeadlessArrayOf<UINT16> > (backtrack);
+    const ArrayOf<UINT16> &lookahead = StructAfter<ArrayOf<UINT16> > (input);
     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
     return_trace (chain_context_would_apply_lookup (c,
 						    backtrack.len, backtrack.array,
 						    input.len, input.array,
 						    lookahead.len, lookahead.array, lookup.len,
 						    lookup.array, lookup_context));
   }
 
   inline bool apply (hb_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
   {
     TRACE_APPLY (this);
-    const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
-    const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
+    const HeadlessArrayOf<UINT16> &input = StructAfter<HeadlessArrayOf<UINT16> > (backtrack);
+    const ArrayOf<UINT16> &lookahead = StructAfter<ArrayOf<UINT16> > (input);
     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
     return_trace (chain_context_apply_lookup (c,
 					      backtrack.len, backtrack.array,
 					      input.len, input.array,
 					      lookahead.len, lookahead.array, lookup.len,
 					      lookup.array, lookup_context));
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     if (!backtrack.sanitize (c)) return_trace (false);
-    const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
+    const HeadlessArrayOf<UINT16> &input = StructAfter<HeadlessArrayOf<UINT16> > (backtrack);
     if (!input.sanitize (c)) return_trace (false);
-    const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
+    const ArrayOf<UINT16> &lookahead = StructAfter<ArrayOf<UINT16> > (input);
     if (!lookahead.sanitize (c)) return_trace (false);
     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
     return_trace (lookup.sanitize (c));
   }
 
   protected:
-  ArrayOf<USHORT>
+  ArrayOf<UINT16>
 		backtrack;		/* Array of backtracking values
 					 * (to be matched before the input
 					 * sequence) */
-  HeadlessArrayOf<USHORT>
+  HeadlessArrayOf<UINT16>
 		inputX;			/* Array of input values (start with
 					 * second glyph) */
-  ArrayOf<USHORT>
+  ArrayOf<UINT16>
 		lookaheadX;		/* Array of lookahead values's (to be
 					 * matched after the input sequence) */
   ArrayOf<LookupRecord>
 		lookupX;		/* Array of LookupRecords--in
 					 * design order) */
   public:
   DEFINE_SIZE_MIN (8);
 };
@@ -1909,17 +1913,17 @@ struct ChainContextFormat1
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
   }
 
   protected:
-  USHORT	format;			/* Format identifier--format = 1 */
+  UINT16	format;			/* Format identifier--format = 1 */
   OffsetTo<Coverage>
 		coverage;		/* Offset to Coverage table--from
 					 * beginning of table */
   OffsetArrayOf<ChainRuleSet>
 		ruleSet;		/* Array of ChainRuleSet tables
 					 * ordered by Coverage Index */
   public:
   DEFINE_SIZE_ARRAY (6, ruleSet);
@@ -2024,17 +2028,17 @@ struct ChainContextFormat2
     return_trace (coverage.sanitize (c, this) &&
 		  backtrackClassDef.sanitize (c, this) &&
 		  inputClassDef.sanitize (c, this) &&
 		  lookaheadClassDef.sanitize (c, this) &&
 		  ruleSet.sanitize (c, this));
   }
 
   protected:
-  USHORT	format;			/* Format identifier--format = 2 */
+  UINT16	format;			/* Format identifier--format = 2 */
   OffsetTo<Coverage>
 		coverage;		/* Offset to Coverage table--from
 					 * beginning of table */
   OffsetTo<ClassDef>
 		backtrackClassDef;	/* Offset to glyph ClassDef table
 					 * containing backtrack sequence
 					 * data--from beginning of table */
   OffsetTo<ClassDef>
@@ -2064,19 +2068,19 @@ struct ChainContextFormat3
 
     const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
     struct ChainContextClosureLookupContext lookup_context = {
       {intersects_coverage},
       {this, this, this}
     };
     chain_context_closure_lookup (c,
-				  backtrack.len, (const USHORT *) backtrack.array,
-				  input.len, (const USHORT *) input.array + 1,
-				  lookahead.len, (const USHORT *) lookahead.array,
+				  backtrack.len, (const UINT16 *) backtrack.array,
+				  input.len, (const UINT16 *) input.array + 1,
+				  lookahead.len, (const UINT16 *) lookahead.array,
 				  lookup.len, lookup.array,
 				  lookup_context);
   }
 
   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
     TRACE_COLLECT_GLYPHS (this);
     const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
@@ -2085,38 +2089,38 @@ struct ChainContextFormat3
 
     const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
     struct ChainContextCollectGlyphsLookupContext lookup_context = {
       {collect_coverage},
       {this, this, this}
     };
     chain_context_collect_glyphs_lookup (c,
-					 backtrack.len, (const USHORT *) backtrack.array,
-					 input.len, (const USHORT *) input.array + 1,
-					 lookahead.len, (const USHORT *) lookahead.array,
+					 backtrack.len, (const UINT16 *) backtrack.array,
+					 input.len, (const UINT16 *) input.array + 1,
+					 lookahead.len, (const UINT16 *) lookahead.array,
 					 lookup.len, lookup.array,
 					 lookup_context);
   }
 
   inline bool would_apply (hb_would_apply_context_t *c) const
   {
     TRACE_WOULD_APPLY (this);
 
     const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
     const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
     struct ChainContextApplyLookupContext lookup_context = {
       {match_coverage},
       {this, this, this}
     };
     return_trace (chain_context_would_apply_lookup (c,
-						    backtrack.len, (const USHORT *) backtrack.array,
-						    input.len, (const USHORT *) input.array + 1,
-						    lookahead.len, (const USHORT *) lookahead.array,
+						    backtrack.len, (const UINT16 *) backtrack.array,
+						    input.len, (const UINT16 *) input.array + 1,
+						    lookahead.len, (const UINT16 *) lookahead.array,
 						    lookup.len, lookup.array, lookup_context));
   }
 
   inline const Coverage &get_coverage (void) const
   {
     const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
     return this+input[0];
   }
@@ -2131,19 +2135,19 @@ struct ChainContextFormat3
 
     const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
     struct ChainContextApplyLookupContext lookup_context = {
       {match_coverage},
       {this, this, this}
     };
     return_trace (chain_context_apply_lookup (c,
-					      backtrack.len, (const USHORT *) backtrack.array,
-					      input.len, (const USHORT *) input.array + 1,
-					      lookahead.len, (const USHORT *) lookahead.array,
+					      backtrack.len, (const UINT16 *) backtrack.array,
+					      input.len, (const UINT16 *) input.array + 1,
+					      lookahead.len, (const UINT16 *) lookahead.array,
 					      lookup.len, lookup.array, lookup_context));
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     if (!backtrack.sanitize (c, this)) return_trace (false);
     const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
@@ -2151,17 +2155,17 @@ struct ChainContextFormat3
     if (!input.len) return_trace (false); /* To be consistent with Context. */
     const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
     if (!lookahead.sanitize (c, this)) return_trace (false);
     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
     return_trace (lookup.sanitize (c));
   }
 
   protected:
-  USHORT	format;			/* Format identifier--format = 3 */
+  UINT16	format;			/* Format identifier--format = 3 */
   OffsetArrayOf<Coverage>
 		backtrack;		/* Array of coverage tables
 					 * in backtracking sequence, in  glyph
 					 * sequence order */
   OffsetArrayOf<Coverage>
 		inputX		;	/* Array of coverage
 					 * tables in input sequence, in glyph
 					 * sequence order */
@@ -2188,17 +2192,17 @@ struct ChainContext
     case 2: return_trace (c->dispatch (u.format2));
     case 3: return_trace (c->dispatch (u.format3));
     default:return_trace (c->default_return_value ());
     }
   }
 
   protected:
   union {
-  USHORT		format;	/* Format identifier */
+  UINT16		format;	/* Format identifier */
   ChainContextFormat1	format1;
   ChainContextFormat2	format2;
   ChainContextFormat3	format3;
   } u;
 };
 
 
 template <typename T>
@@ -2225,21 +2229,21 @@ struct ExtensionFormat1
   /* This is called from may_dispatch() above with hb_sanitize_context_t. */
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) && extensionOffset != 0);
   }
 
   protected:
-  USHORT	format;			/* Format identifier. Set to 1. */
-  USHORT	extensionLookupType;	/* Lookup type of subtable referenced
+  UINT16	format;			/* Format identifier. Set to 1. */
+  UINT16	extensionLookupType;	/* Lookup type of subtable referenced
 					 * by ExtensionOffset (i.e. the
 					 * extension subtable). */
-  ULONG		extensionOffset;	/* Offset to the extension subtable,
+  UINT32		extensionOffset;	/* Offset to the extension subtable,
 					 * of lookup type subtable. */
   public:
   DEFINE_SIZE_STATIC (8);
 };
 
 template <typename T>
 struct Extension
 {
@@ -2267,31 +2271,28 @@ struct Extension
     switch (u.format) {
     case 1: return_trace (u.format1.dispatch (c));
     default:return_trace (c->default_return_value ());
     }
   }
 
   protected:
   union {
-  USHORT		format;		/* Format identifier */
+  UINT16		format;		/* Format identifier */
   ExtensionFormat1<T>	format1;
   } u;
 };
 
 
 /*
  * GSUB/GPOS Common
  */
 
 struct GSUBGPOS
 {
-  static const hb_tag_t GSUBTag	= HB_OT_TAG_GSUB;
-  static const hb_tag_t GPOSTag	= HB_OT_TAG_GPOS;
-
   inline unsigned int get_script_count (void) const
   { return (this+scriptList).len; }
   inline const Tag& get_script_tag (unsigned int i) const
   { return (this+scriptList).get_tag (i); }
   inline unsigned int get_script_tags (unsigned int start_offset,
 				       unsigned int *script_count /* IN/OUT */,
 				       hb_tag_t     *script_tags /* OUT */) const
   { return (this+scriptList).get_tags (start_offset, script_count, script_tags); }
--- a/gfx/harfbuzz/src/hb-ot-layout-private.hh
+++ b/gfx/harfbuzz/src/hb-ot-layout-private.hh
@@ -268,23 +268,23 @@ static inline void
       if (u == 0x200Cu) props |= UPROPS_MASK_Cf_ZWNJ;
       else if (u == 0x200Du) props |= UPROPS_MASK_Cf_ZWJ;
       /* Mongolian Free Variation Selectors need to be remembered
        * because although we need to hide them like default-ignorables,
        * they need to non-ignorable during shaping.  This is similar to
        * what we do for joiners in Indic-like shapers, but since the
        * FVSes are GC=Mn, we have use a separate bit to remember them.
        * Fixes:
-       * https://github.com/behdad/harfbuzz/issues/234 */
+       * https://github.com/harfbuzz/harfbuzz/issues/234 */
       else if (unlikely (hb_in_range (u, 0x180Bu, 0x180Du))) props |= UPROPS_MASK_HIDDEN;
       /* TAG characters need similar treatment. Fixes:
-       * https://github.com/behdad/harfbuzz/issues/463 */
+       * https://github.com/harfbuzz/harfbuzz/issues/463 */
       else if (unlikely (hb_in_range (u, 0xE0020u, 0xE007Fu))) props |= UPROPS_MASK_HIDDEN;
       /* COMBINING GRAPHEME JOINER should not be skipped; at least some times.
-       * https://github.com/behdad/harfbuzz/issues/554 */
+       * https://github.com/harfbuzz/harfbuzz/issues/554 */
       else if (unlikely (u == 0x034Fu)) props |= UPROPS_MASK_HIDDEN;
     }
     else if (unlikely (HB_UNICODE_GENERAL_CATEGORY_IS_NON_ENCLOSING_MARK_OR_MODIFIER_SYMBOL (gen_cat)))
     {
       /* The above check is just an optimization to let in only things we need further
        * processing on. */
 
       /* Only Mn and Mc can have non-zero ccc:
@@ -300,17 +300,17 @@ static inline void
        * Also, all Mn's that are Default_Ignorable, have ccc=0, hence
        * the "else if".
        */
       props |= unicode->modified_combining_class (info->codepoint)<<8;
 
       /* Recategorize emoji skin-tone modifiers as Unicode mark, so they
        * behave correctly in non-native directionality.  They originally
        * are MODIFIER_SYMBOL.  Fixes:
-       * https://github.com/behdad/harfbuzz/issues/169
+       * https://github.com/harfbuzz/harfbuzz/issues/169
        */
       if (unlikely (hb_in_range (u, 0x1F3FBu, 0x1F3FFu)))
       {
 	props = gen_cat = HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK;
       }
     }
   }
 
--- a/gfx/harfbuzz/src/hb-ot-layout.cc
+++ b/gfx/harfbuzz/src/hb-ot-layout.cc
@@ -596,16 +596,17 @@ hb_ot_layout_feature_get_lookups (hb_fac
  * hb_ot_layout_table_get_lookup_count:
  *
  * Since: 0.9.22
  **/
 unsigned int
 hb_ot_layout_table_get_lookup_count (hb_face_t    *face,
 				     hb_tag_t      table_tag)
 {
+  if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return 0;
   switch (table_tag)
   {
     case HB_OT_TAG_GSUB:
     {
       return hb_ot_layout_from_face (face)->gsub_lookup_count;
     }
     case HB_OT_TAG_GPOS:
     {
--- a/gfx/harfbuzz/src/hb-ot-math-table.hh
+++ b/gfx/harfbuzz/src/hb-ot-math-table.hh
@@ -43,17 +43,17 @@ struct MathValueRecord
 
   inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) && deviceTable.sanitize (c, base));
   }
 
   protected:
-  SHORT			value;		/* The X or Y value in design units */
+  INT16			value;		/* The X or Y value in design units */
   OffsetTo<Device>	deviceTable;	/* Offset to the device table - from the
 					 * beginning of parent table. May be nullptr.
 					 * Suggested format for device table is 1. */
 
   public:
   DEFINE_SIZE_STATIC (4);
 };
 
@@ -149,20 +149,20 @@ struct MathConstants
       return radicalDegreeBottomRaisePercent;
 
     default:
       return 0;
     }
   }
 
   protected:
-  SHORT percentScaleDown[2];
-  USHORT minHeight[2];
+  INT16 percentScaleDown[2];
+  UINT16 minHeight[2];
   MathValueRecord mathValueRecords[51];
-  SHORT radicalDegreeBottomRaisePercent;
+  INT16 radicalDegreeBottomRaisePercent;
 
   public:
   DEFINE_SIZE_STATIC (214);
 };
 
 struct MathItalicsCorrectionInfo
 {
   inline bool sanitize (hb_sanitize_context_t *c) const
@@ -274,17 +274,17 @@ struct MathKern
 	count -= half + 1;
       } else
 	count = half;
     }
     return kernValue[i].get_x_value(font, this);
   }
 
   protected:
-  USHORT	  heightCount;
+  UINT16	  heightCount;
   MathValueRecord mathValueRecords[VAR]; /* Array of correction heights at
 					  * which the kern value changes.
 					  * Sorted by the height value in
 					  * design units (heightCount entries),
 					  * Followed by:
 					  * Array of kern values corresponding
 					  * to heights. (heightCount+1 entries).
 					  */
@@ -420,25 +420,25 @@ struct MathGlyphVariantRecord
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this));
   }
 
   protected:
   GlyphID variantGlyph;       /* Glyph ID for the variant. */
-  USHORT  advanceMeasurement; /* Advance width/height, in design units, of the
+  UINT16  advanceMeasurement; /* Advance width/height, in design units, of the
 			       * variant, in the direction of requested
 			       * glyph extension. */
 
   public:
   DEFINE_SIZE_STATIC (4);
 };
 
-struct PartFlags : USHORT
+struct PartFlags : UINT16
 {
   enum Flags {
     Extender	= 0x0001u, /* If set, the part can be skipped or repeated. */
 
     Defined	= 0x0001u, /* All defined flags. */
   };
 
   public:
@@ -468,25 +468,25 @@ struct MathGlyphPartRecord
 
     out.flags = (hb_ot_math_glyph_part_flags_t)
 		(unsigned int)
 		(partFlags & PartFlags::Defined);
   }
 
   protected:
   GlyphID   glyph;		  /* Glyph ID for the part. */
-  USHORT    startConnectorLength; /* Advance width/ height of the straight bar
+  UINT16    startConnectorLength; /* Advance width/ height of the straight bar
 				   * connector material, in design units, is at
 				   * the beginning of the glyph, in the
 				   * direction of the extension. */
-  USHORT    endConnectorLength;   /* Advance width/ height of the straight bar
+  UINT16    endConnectorLength;   /* Advance width/ height of the straight bar
 				   * connector material, in design units, is at
 				   * the end of the glyph, in the direction of
 				   * the extension. */
-  USHORT    fullAdvance;	  /* Full advance width/height for this part,
+  UINT16    fullAdvance;	  /* Full advance width/height for this part,
 				   * in the direction of the extension.
 				   * In design units. */
   PartFlags partFlags;		  /* Part qualifiers. */
 
   public:
   DEFINE_SIZE_STATIC (10);
 };
 
@@ -646,29 +646,29 @@ struct MathVariants
 
     if (!vertical)
       index += vertGlyphCount;
 
     return this+glyphConstruction[index];
   }
 
   protected:
-  USHORT	     minConnectorOverlap; /* Minimum overlap of connecting
+  UINT16	     minConnectorOverlap; /* Minimum overlap of connecting
 					   * glyphs during glyph construction,
 					   * in design units. */
   OffsetTo<Coverage> vertGlyphCoverage;   /* Offset to Coverage table -
 					   * from the beginning of MathVariants
 					   * table. */
   OffsetTo<Coverage> horizGlyphCoverage;  /* Offset to Coverage table -
 					   * from the beginning of MathVariants
 					   * table. */
-  USHORT	     vertGlyphCount;      /* Number of glyphs for which
+  UINT16	     vertGlyphCount;      /* Number of glyphs for which
 					   * information is provided for
 					   * vertically growing variants. */
-  USHORT	     horizGlyphCount;     /* Number of glyphs for which
+  UINT16	     horizGlyphCount;     /* Number of glyphs for which
 					   * information is provided for
 					   * horizontally growing variants. */
 
   /* Array of offsets to MathGlyphConstruction tables - from the beginning of
      the MathVariants table, for shapes growing in vertical/horizontal
      direction. */
   OffsetTo<MathGlyphConstruction> glyphConstruction[VAR];
 
--- a/gfx/harfbuzz/src/hb-ot-maxp-table.hh
+++ b/gfx/harfbuzz/src/hb-ot-maxp-table.hh
@@ -55,17 +55,17 @@ struct maxp
 		  likely (version.major == 1 ||
 			  (version.major == 0 && version.minor == 0x5000u)));
   }
 
   /* We only implement version 0.5 as none of the extra fields in version 1.0 are useful. */
   protected:
   FixedVersion<>version;		/* Version of the maxp table (0.5 or 1.0),
 					 * 0x00005000u or 0x00010000u. */
-  USHORT	numGlyphs;		/* The number of glyphs in the font. */
+  UINT16	numGlyphs;		/* The number of glyphs in the font. */
   public:
   DEFINE_SIZE_STATIC (6);
 };
 
 
 } /* namespace OT */
 
 
--- a/gfx/harfbuzz/src/hb-ot-name-table.hh
+++ b/gfx/harfbuzz/src/hb-ot-name-table.hh
@@ -60,22 +60,22 @@ struct NameRecord
 
   inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
   {
     TRACE_SANITIZE (this);
     /* We can check from base all the way up to the end of string... */
     return_trace (c->check_struct (this) && c->check_range ((char *) base, (unsigned int) length + offset));
   }
 
-  USHORT	platformID;	/* Platform ID. */
-  USHORT	encodingID;	/* Platform-specific encoding ID. */
-  USHORT	languageID;	/* Language ID. */
-  USHORT	nameID;		/* Name ID. */
-  USHORT	length;		/* String length (in bytes). */
-  USHORT	offset;		/* String offset from start of storage area (in bytes). */
+  UINT16	platformID;	/* Platform ID. */
+  UINT16	encodingID;	/* Platform-specific encoding ID. */
+  UINT16	languageID;	/* Language ID. */
+  UINT16	nameID;		/* Name ID. */
+  UINT16	length;		/* String length (in bytes). */
+  UINT16	offset;		/* String offset from start of storage area (in bytes). */
   public:
   DEFINE_SIZE_STATIC (12);
 };
 
 struct name
 {
   static const hb_tag_t tableTag	= HB_OT_TAG_name;
 
@@ -118,19 +118,19 @@ struct name
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) &&
 		  likely (format == 0 || format == 1) &&
 		  c->check_array (nameRecord, nameRecord[0].static_size, count) &&
 		  sanitize_records (c));
   }
 
   /* We only implement format 0 for now. */
-  USHORT	format;			/* Format selector (=0/1). */
-  USHORT	count;			/* Number of name records. */
-  Offset<>	stringOffset;		/* Offset to start of string storage (from start of table). */
+  UINT16	format;			/* Format selector (=0/1). */
+  UINT16	count;			/* Number of name records. */
+  Offset16	stringOffset;		/* Offset to start of string storage (from start of table). */
   NameRecord	nameRecord[VAR];	/* The name records where count is the number of records. */
   public:
   DEFINE_SIZE_ARRAY (6, nameRecord);
 };
 
 
 } /* namespace OT */
 
--- a/gfx/harfbuzz/src/hb-ot-os2-table.hh
+++ b/gfx/harfbuzz/src/hb-ot-os2-table.hh
@@ -45,60 +45,60 @@ struct os2
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this));
   }
 
   public:
-  USHORT	version;
+  UINT16	version;
 
   /* Version 0 */
-  SHORT		xAvgCharWidth;
-  USHORT	usWeightClass;
-  USHORT	usWidthClass;
-  USHORT	fsType;
-  SHORT		ySubscriptXSize;
-  SHORT		ySubscriptYSize;
-  SHORT		ySubscriptXOffset;
-  SHORT		ySubscriptYOffset;
-  SHORT		ySuperscriptXSize;
-  SHORT		ySuperscriptYSize;
-  SHORT		ySuperscriptXOffset;
-  SHORT		ySuperscriptYOffset;
-  SHORT		yStrikeoutSize;
-  SHORT		yStrikeoutPosition;
-  SHORT		sFamilyClass;
-  BYTE		panose[10];
-  ULONG		ulUnicodeRange[4];
+  INT16		xAvgCharWidth;
+  UINT16	usWeightClass;
+  UINT16	usWidthClass;
+  UINT16	fsType;
+  INT16		ySubscriptXSize;
+  INT16		ySubscriptYSize;
+  INT16		ySubscriptXOffset;
+  INT16		ySubscriptYOffset;
+  INT16		ySuperscriptXSize;
+  INT16		ySuperscriptYSize;
+  INT16		ySuperscriptXOffset;
+  INT16		ySuperscriptYOffset;
+  INT16		yStrikeoutSize;
+  INT16		yStrikeoutPosition;
+  INT16		sFamilyClass;
+  UINT8		panose[10];
+  UINT32		ulUnicodeRange[4];
   Tag		achVendID;
-  USHORT	fsSelection;
-  USHORT	usFirstCharIndex;
-  USHORT	usLastCharIndex;
-  SHORT		sTypoAscender;
-  SHORT		sTypoDescender;
-  SHORT		sTypoLineGap;
-  USHORT	usWinAscent;
-  USHORT	usWinDescent;
+  UINT16	fsSelection;
+  UINT16	usFirstCharIndex;
+  UINT16	usLastCharIndex;
+  INT16		sTypoAscender;
+  INT16		sTypoDescender;
+  INT16		sTypoLineGap;
+  UINT16	usWinAscent;
+  UINT16	usWinDescent;
 
   /* Version 1 */
-  //ULONG ulCodePageRange1;
-  //ULONG ulCodePageRange2;
+  //UINT32 ulCodePageRange1;
+  //UINT32 ulCodePageRange2;
 
   /* Version 2 */
-  //SHORT sxHeight;
-  //SHORT sCapHeight;
-  //USHORT  usDefaultChar;
-  //USHORT  usBreakChar;
-  //USHORT  usMaxContext;
+  //INT16 sxHeight;
+  //INT16 sCapHeight;
+  //UINT16  usDefaultChar;
+  //UINT16  usBreakChar;
+  //UINT16  usMaxContext;
 
   /* Version 5 */
-  //USHORT  usLowerOpticalPointSize;
-  //USHORT  usUpperOpticalPointSize;
+  //UINT16  usLowerOpticalPointSize;
+  //UINT16  usUpperOpticalPointSize;
 
   public:
   DEFINE_SIZE_STATIC (78);
 };
 
 } /* namespace OT */
 
 
--- a/gfx/harfbuzz/src/hb-ot-post-table.hh
+++ b/gfx/harfbuzz/src/hb-ot-post-table.hh
@@ -51,20 +51,20 @@ namespace OT {
 struct postV2Tail
 {
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (glyphNameIndex.sanitize (c));
   }
 
-  ArrayOf<USHORT>glyphNameIndex;	/* This is not an offset, but is the
+  ArrayOf<UINT16>glyphNameIndex;	/* This is not an offset, but is the
 					 * ordinal number of the glyph in 'post'
 					 * string tables. */
-  BYTE		namesX[VAR];		/* Glyph names with length bytes [variable]
+  UINT8		namesX[VAR];		/* Glyph names with length bytes [variable]
 					 * (a Pascal string). */
 
   DEFINE_SIZE_ARRAY2 (2, glyphNameIndex, namesX);
 };
 
 struct post
 {
   static const hb_tag_t tableTag = HB_OT_TAG_post;
@@ -79,29 +79,33 @@ struct post
       const postV2Tail &v2 = StructAfter<postV2Tail> (*this);
       return_trace (v2.sanitize (c));
     }
     return_trace (true);
   }
 
   struct accelerator_t
   {
-    inline void init (const post *table, unsigned int post_len)
+    inline void init (hb_face_t *face)
     {
+      blob = Sanitizer<post>::sanitize (face->reference_table (HB_OT_TAG_post));
+      const post *table = Sanitizer<post>::lock_instance (blob);
+      unsigned int table_length = hb_blob_get_length (blob);
+
       version = table->version.to_int ();
       index_to_offset.init ();
       if (version != 0x00020000)
         return;
 
       const postV2Tail &v2 = StructAfter<postV2Tail> (*table);
 
       glyphNameIndex = &v2.glyphNameIndex;
       pool = &StructAfter<uint8_t> (v2.glyphNameIndex);
 
-      const uint8_t *end = (uint8_t *) table + post_len;
+      const uint8_t *end = (uint8_t *) table + table_length;
       for (const uint8_t *data = pool; data < end && data + *data <= end; data += 1 + *data)
       {
 	uint32_t *offset = index_to_offset.push ();
 	if (unlikely (!offset))
 	  break;
 	*offset = data - pool;
       }
     }
@@ -222,18 +226,20 @@ struct post
 
       const uint8_t *data = pool + offset;
       unsigned int name_length = *data;
       data++;
 
       return hb_string_t ((const char *) data, name_length);
     }
 
+    private:
+    hb_blob_t *blob;
     uint32_t version;
-    const ArrayOf<USHORT> *glyphNameIndex;
+    const ArrayOf<UINT16> *glyphNameIndex;
     hb_prealloced_array_t<uint32_t, 1> index_to_offset;
     const uint8_t *pool;
     mutable uint16_t *gids_sorted_by_name;
   };
 
   public:
   FixedVersion<>version;		/* 0x00010000 for version 1.0
 					 * 0x00020000 for version 2.0
@@ -250,26 +256,26 @@ struct post
 					 * dictionary key (the y coordinate of the
 					 * center of the stroke) is not used for
 					 * historical reasons. The value of the
 					 * PostScript key may be calculated by
 					 * subtracting half the underlineThickness
 					 * from the value of this field. */
   FWORD		underlineThickness;	/* Suggested values for the underline
 					   thickness. */
-  ULONG		isFixedPitch;		/* Set to 0 if the font is proportionally
+  UINT32		isFixedPitch;		/* Set to 0 if the font is proportionally
 					 * spaced, non-zero if the font is not
 					 * proportionally spaced (i.e. monospaced). */
-  ULONG		minMemType42;		/* Minimum memory usage when an OpenType font
+  UINT32		minMemType42;		/* Minimum memory usage when an OpenType font
 					 * is downloaded. */
-  ULONG		maxMemType42;		/* Maximum memory usage when an OpenType font
+  UINT32		maxMemType42;		/* Maximum memory usage when an OpenType font
 					 * is downloaded. */
-  ULONG		minMemType1;		/* Minimum memory usage when an OpenType font
+  UINT32		minMemType1;		/* Minimum memory usage when an OpenType font
 					 * is downloaded as a Type 1 font. */
-  ULONG		maxMemType1;		/* Maximum memory usage when an OpenType font
+  UINT32		maxMemType1;		/* Maximum memory usage when an OpenType font
 					 * is downloaded as a Type 1 font. */
 /*postV2Tail	v2[VAR];*/
   DEFINE_SIZE_STATIC (32);
 };
 
 } /* namespace OT */
 
 
--- a/gfx/harfbuzz/src/hb-ot-shape-complex-arabic-win1256.hh
+++ b/gfx/harfbuzz/src/hb-ot-shape-complex-arabic-win1256.hh
@@ -38,26 +38,26 @@
 
 /* First we measure, then we cut. */
 #ifndef OT_MEASURE
 #define OT_MEASURE
 #define OT_TABLE_START			static const struct TABLE_NAME {
 #define OT_TABLE_END			}
 #define OT_LABEL_START(Name)		unsigned char Name[
 #define OT_LABEL_END			];
-#define OT_BYTE(u8)			+1/*byte*/
-#define OT_USHORT(u16)			+2/*bytes*/
+#define OT_UINT8(u8)			+1/*byte*/
+#define OT_UINT16(u16)			+2/*bytes*/
 #else
 #undef  OT_MEASURE
 #define OT_TABLE_START			TABLE_NAME = {
 #define OT_TABLE_END			};
 #define OT_LABEL_START(Name)		{
 #define OT_LABEL_END			},
-#define OT_BYTE(u8)			(u8),
-#define OT_USHORT(u16)			(unsigned char)((u16)>>8), (unsigned char)((u16)&0xFFu),
+#define OT_UINT8(u8)			(u8),
+#define OT_UINT16(u16)			(unsigned char)((u16)>>8), (unsigned char)((u16)&0xFFu),
 #define OT_COUNT(Name, ItemSize)	((unsigned int) sizeof(((struct TABLE_NAME*)0)->Name) \
 					 / (unsigned int)(ItemSize) \
 					 /* OT_ASSERT it's divisible (and positive). */)
 #define OT_DISTANCE(From,To)		((unsigned int) \
 					 ((char*)(&((struct TABLE_NAME*)0)->To) - \
 					  (char*)(&((struct TABLE_NAME*)0)->From)) \
 					 /* OT_ASSERT it's positive. */)
 #endif
@@ -75,60 +75,60 @@
 #define OT_LIST(...) __VA_ARGS__
 
 
 /*
  * Basic Types
  */
 
 #define OT_TAG(a,b,c,d) \
-	OT_BYTE(a) OT_BYTE(b) OT_BYTE(c) OT_BYTE(d)
+	OT_UINT8(a) OT_UINT8(b) OT_UINT8(c) OT_UINT8(d)
 
 #define OT_OFFSET(From, To) /* Offset from From to To in bytes */ \
-	OT_USHORT(OT_DISTANCE(From, To))
+	OT_UINT16(OT_DISTANCE(From, To))
 
 #define OT_GLYPHID /* GlyphID */ \
-	OT_USHORT
+	OT_UINT16
 
 #define OT_UARRAY(Name, Items) \
 	OT_LABEL_START(Name) \
-	OT_USHORT(OT_COUNT(Name##Data, 2)) \
+	OT_UINT16(OT_COUNT(Name##Data, 2)) \
 	OT_LABEL(Name##Data) \
 	Items \
 	OT_LABEL_END
 
 #define OT_UHEADLESSARRAY(Name, Items) \
 	OT_LABEL_START(Name) \
-	OT_USHORT(OT_COUNT(Name##Data, 2) + 1) \
+	OT_UINT16(OT_COUNT(Name##Data, 2) + 1) \
 	OT_LABEL(Name##Data) \
 	Items \
 	OT_LABEL_END
 
 
 /*
  * Common Types
  */
 
 #define OT_LOOKUP_FLAG_IGNORE_MARKS	0x08u
 
 #define OT_LOOKUP(Name, LookupType, LookupFlag, SubLookupOffsets) \
 	OT_LABEL_START(Name) \
-	OT_USHORT(LookupType) \
-	OT_USHORT(LookupFlag) \
+	OT_UINT16(LookupType) \
+	OT_UINT16(LookupFlag) \
 	OT_LABEL_END \
 	OT_UARRAY(Name##SubLookupOffsetsArray, OT_LIST(SubLookupOffsets))
 
 #define OT_SUBLOOKUP(Name, SubFormat, Items) \
 	OT_LABEL_START(Name) \
-	OT_USHORT(SubFormat) \
+	OT_UINT16(SubFormat) \
 	Items
 
 #define OT_COVERAGE1(Name, Items) \
 	OT_LABEL_START(Name) \
-	OT_USHORT(1) \
+	OT_UINT16(1) \
 	OT_LABEL_END \
 	OT_UARRAY(Name##Glyphs, OT_LIST(Items))
 
 
 /*
  * GSUB
  */
 
@@ -169,17 +169,17 @@
  */
 
 /* Table name. */
 #define TABLE_NAME arabic_win1256_gsub_lookups
 
 /* Table manifest. */
 #define MANIFEST(Items) \
 	OT_LABEL_START(manifest) \
-	OT_USHORT(OT_COUNT(manifestData, 6)) \
+	OT_UINT16(OT_COUNT(manifestData, 6)) \
 	OT_LABEL(manifestData) \
 	Items \
 	OT_LABEL_END
 
 #define MANIFEST_LOOKUP(Tag, Name) \
 	Tag \
 	OT_OFFSET(manifest, Name)
 
@@ -299,18 +299,18 @@ OT_TABLE_END
 
 /*
  * Clean up
  */
 #undef OT_TABLE_START
 #undef OT_TABLE_END
 #undef OT_LABEL_START
 #undef OT_LABEL_END
-#undef OT_BYTE
-#undef OT_USHORT
+#undef OT_UINT8
+#undef OT_UINT16
 #undef OT_DISTANCE
 #undef OT_COUNT
 
 /*
  * Include a second time to get the table data...
  */
 #if 0
 #include "hb-private.hh" /* Make check-includes.sh happy. */
--- a/gfx/harfbuzz/src/hb-ot-shape-complex-arabic.cc
+++ b/gfx/harfbuzz/src/hb-ot-shape-complex-arabic.cc
@@ -31,17 +31,17 @@
 
 
 /* buffer var allocations */
 #define arabic_shaping_action() complex_var_u8_0() /* arabic shaping action */
 
 #define HB_BUFFER_SCRATCH_FLAG_ARABIC_HAS_STCH HB_BUFFER_SCRATCH_FLAG_COMPLEX0
 
 /* See:
- * https://github.com/behdad/harfbuzz/commit/6e6f82b6f3dde0fc6c3c7d991d9ec6cfff57823d#commitcomment-14248516 */
+ * https://github.com/harfbuzz/harfbuzz/commit/6e6f82b6f3dde0fc6c3c7d991d9ec6cfff57823d#commitcomment-14248516 */
 #define HB_ARABIC_GENERAL_CATEGORY_IS_WORD(gen_cat) \
 	(FLAG_UNSAFE (gen_cat) & \
 	 (FLAG (HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED) | \
 	  FLAG (HB_UNICODE_GENERAL_CATEGORY_PRIVATE_USE) | \
 	  /*FLAG (HB_UNICODE_GENERAL_CATEGORY_LOWERCASE_LETTER) |*/ \
 	  FLAG (HB_UNICODE_GENERAL_CATEGORY_MODIFIER_LETTER) | \
 	  FLAG (HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER) | \
 	  /*FLAG (HB_UNICODE_GENERAL_CATEGORY_TITLECASE_LETTER) |*/ \
@@ -193,17 +193,17 @@ collect_features_arabic (hb_ot_shape_pla
    *
    * At least for Arabic, looks like Uniscribe has a pause between
    * rlig and calt.  Otherwise the IranNastaliq's ALLAH ligature won't
    * work.  However, testing shows that rlig and calt are applied
    * together for Mongolian in Uniscribe.  As such, we only add a
    * pause for Arabic, not other scripts.
    *
    * A pause after calt is required to make KFGQPC Uthmanic Script HAFS
-   * work correctly.  See https://github.com/behdad/harfbuzz/issues/505
+   * work correctly.  See https://github.com/harfbuzz/harfbuzz/issues/505
    */
 
   map->add_gsub_pause (nuke_joiners);
 
   map->add_global_bool_feature (HB_TAG('s','t','c','h'));
   map->add_gsub_pause (record_stch);
 
   map->add_global_bool_feature (HB_TAG('c','c','m','p'));
--- a/gfx/harfbuzz/src/hb-ot-shape-complex-hebrew.cc
+++ b/gfx/harfbuzz/src/hb-ot-shape-complex-hebrew.cc
@@ -156,17 +156,17 @@ compose_hebrew (const hb_ot_shape_normal
 
 static bool
 disable_otl_hebrew (const hb_ot_shape_plan_t *plan)
 {
   /* For Hebrew shaper, use fallback if GPOS does not have 'hebr'
    * script.  This matches Uniscribe better, and makes fonts like
    * Arial that have GSUB/GPOS/GDEF but no data for Hebrew work.
    * See:
-   * https://github.com/behdad/harfbuzz/issues/347#issuecomment-267838368
+   * https://github.com/harfbuzz/harfbuzz/issues/347#issuecomment-267838368
    */
   return plan->map.chosen_script[1] != HB_TAG ('h','e','b','r');
 }
 
 
 const hb_ot_complex_shaper_t _hb_ot_complex_shaper_hebrew =
 {
   nullptr, /* collect_features */
--- a/gfx/harfbuzz/src/hb-ot-shape-complex-indic-private.hh
+++ b/gfx/harfbuzz/src/hb-ot-shape-complex-indic-private.hh
@@ -118,17 +118,17 @@ enum indic_syllabic_category_t {
   INDIC_SYLLABIC_CATEGORY_CONSONANT_KILLER		= OT_M, /* U+17CD only. */
   INDIC_SYLLABIC_CATEGORY_CONSONANT_MEDIAL		= OT_CM,
   INDIC_SYLLABIC_CATEGORY_CONSONANT_PLACEHOLDER		= OT_PLACEHOLDER,
   INDIC_SYLLABIC_CATEGORY_CONSONANT_PRECEDING_REPHA	= OT_Repha,
   INDIC_SYLLABIC_CATEGORY_CONSONANT_PREFIXED		= OT_X, /* Don't care. */
   INDIC_SYLLABIC_CATEGORY_CONSONANT_SUBJOINED		= OT_CM,
   INDIC_SYLLABIC_CATEGORY_CONSONANT_SUCCEEDING_REPHA	= OT_N,
   INDIC_SYLLABIC_CATEGORY_CONSONANT_WITH_STACKER	= OT_CS,
-  INDIC_SYLLABIC_CATEGORY_GEMINATION_MARK		= OT_SM, /* https://github.com/behdad/harfbuzz/issues/552 */
+  INDIC_SYLLABIC_CATEGORY_GEMINATION_MARK		= OT_SM, /* https://github.com/harfbuzz/harfbuzz/issues/552 */
   INDIC_SYLLABIC_CATEGORY_INVISIBLE_STACKER		= OT_Coeng,
   INDIC_SYLLABIC_CATEGORY_JOINER			= OT_ZWJ,
   INDIC_SYLLABIC_CATEGORY_MODIFYING_LETTER		= OT_X,
   INDIC_SYLLABIC_CATEGORY_NON_JOINER			= OT_ZWNJ,
   INDIC_SYLLABIC_CATEGORY_NUKTA				= OT_N,
   INDIC_SYLLABIC_CATEGORY_NUMBER			= OT_PLACEHOLDER,
   INDIC_SYLLABIC_CATEGORY_NUMBER_JOINER			= OT_PLACEHOLDER, /* Don't care. */
   INDIC_SYLLABIC_CATEGORY_PURE_KILLER			= OT_M, /* Is like a vowel matra. */
--- a/gfx/harfbuzz/src/hb-ot-shape-complex-indic.cc
+++ b/gfx/harfbuzz/src/hb-ot-shape-complex-indic.cc
@@ -205,29 +205,30 @@ set_indic_properties (hb_glyph_info_t &i
   {
     /* These can occur mid-syllable (eg. before matras), even though Unicode marks them as Syllable_Modifier.
      * https://github.com/roozbehp/unicode-data/issues/5 */
     cat = OT_M;
     pos = POS_ABOVE_C;
   }
   else if (unlikely (u == 0x0A51u))
   {
-    /* https://github.com/behdad/harfbuzz/issues/524 */
+    /* https://github.com/harfbuzz/harfbuzz/issues/524 */
     cat = OT_M;
     pos = POS_BELOW_C;
   }
 
   /* According to ScriptExtensions.txt, these Grantha marks may also be used in Tamil,
    * so the Indic shaper needs to know their categories. */
   else if (unlikely (u == 0x11301u || u == 0x11303u)) cat = OT_SM;
   else if (unlikely (u == 0x1133cu)) cat = OT_N;
 
-  else if (unlikely (u == 0x0AFBu)) cat = OT_N; /* https://github.com/behdad/harfbuzz/issues/552 */
+  else if (unlikely (u == 0x0AFBu)) cat = OT_N; /* https://github.com/harfbuzz/harfbuzz/issues/552 */
 
-  else if (unlikely (u == 0x0980u)) cat = OT_PLACEHOLDER; /* https://github.com/behdad/harfbuzz/issues/538 */
+  else if (unlikely (u == 0x0980u)) cat = OT_PLACEHOLDER; /* https://github.com/harfbuzz/harfbuzz/issues/538 */
+  else if (unlikely (u == 0x0C80u)) cat = OT_PLACEHOLDER; /* https://github.com/harfbuzz/harfbuzz/pull/623 */
   else if (unlikely (u == 0x17C6u)) cat = OT_N; /* Khmer Bindu doesn't like to be repositioned. */
   else if (unlikely (hb_in_range<hb_codepoint_t> (u, 0x2010u, 0x2011u)))
 				    cat = OT_PLACEHOLDER;
   else if (unlikely (u == 0x25CCu)) cat = OT_DOTTEDCIRCLE;
 
 
   /*
    * Re-assign position.
@@ -686,17 +687,17 @@ static void
 initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
 				       hb_face_t *face,
 				       hb_buffer_t *buffer,
 				       unsigned int start, unsigned int end)
 {
   const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data;
   hb_glyph_info_t *info = buffer->info;
 
-  /* https://github.com/behdad/harfbuzz/issues/435#issuecomment-335560167
+  /* https://github.com/harfbuzz/harfbuzz/issues/435#issuecomment-335560167
    * // For compatibility with legacy usage in Kannada,
    * // Ra+h+ZWJ must behave like Ra+ZWJ+h...
    */
   if (buffer->props.script == HB_SCRIPT_KANNADA &&
       start + 3 <= end &&
       is_one_of (info[start  ], FLAG (OT_Ra)) &&
       is_one_of (info[start+1], FLAG (OT_H)) &&
       is_one_of (info[start+2], FLAG (OT_ZWJ)))
--- a/gfx/harfbuzz/src/hb-ot-shape-complex-use-machine.rl
+++ b/gfx/harfbuzz/src/hb-ot-shape-complex-use-machine.rl
@@ -85,17 +85,17 @@ VMBlw	= 38; # VOWEL_MOD_BELOW
 VMPst	= 39; # VOWEL_MOD_POST
 VMPre	= 23; # VOWEL_MOD_PRE
 SMAbv	= 41; # SYM_MOD_ABOVE
 SMBlw	= 42; # SYM_MOD_BELOW
 CS	= 43; # CONS_WITH_STACKER
 
 
 consonant_modifiers = CMAbv* CMBlw* ((H B | SUB) VS? CMAbv? CMBlw*)*;
-# Override: Allow two MBlw. https://github.com/behdad/harfbuzz/issues/376
+# Override: Allow two MBlw. https://github.com/harfbuzz/harfbuzz/issues/376
 medial_consonants = MPre? MAbv? MBlw?.MBlw? MPst?;
 dependent_vowels = VPre* VAbv* VBlw* VPst*;
 vowel_modifiers = VMPre* VMAbv* VMBlw* VMPst*;
 final_consonants = FAbv* FBlw* FPst* FM?;
 
 virama_terminated_cluster =
 	(R|CS)? (B | GB) VS?
 	consonant_modifiers
--- a/gfx/harfbuzz/src/hb-ot-shape-complex-use-table.cc
+++ b/gfx/harfbuzz/src/hb-ot-shape-complex-use-table.cc
@@ -343,17 +343,24 @@ static const USE_TABLE_ELEMENT_TYPE use_
 
   /* 2060 */    WJ,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
 
   /* Superscripts and Subscripts */
 
   /* 2070 */     O,     O,     O,     O,    FM,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
   /* 2080 */     O,     O,    FM,    FM,    FM,     O,     O,     O,
 
-#define use_offset_0xa800u 2616
+#define use_offset_0x20f0u 2616
+
+
+  /* Combining Diacritical Marks for Symbols */
+
+  /* 20F0 */ VMAbv,     O,     O,     O,     O,     O,     O,     O,
+
+#define use_offset_0xa800u 2624
 
 
   /* Syloti Nagri */
 
   /* A800 */     B,     B,     O,     B,     B,     B,  VAbv,     B,     B,     B,     B, VMAbv,     B,     B,     B,     B,
   /* A810 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* A820 */     B,     B,     B,  VPst,  VPst,  VBlw,  VAbv,  VPst,     O,     O,     O,     O,     O,     O,     O,     O,
   /* A830 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
@@ -365,17 +372,17 @@ static const USE_TABLE_ELEMENT_TYPE use_
   /* A860 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* A870 */     B,     B,     B,     B,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
 
   /* Saurashtra */
 
   /* A880 */ VMPst, VMPst,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* A890 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* A8A0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* A8B0 */     B,     B,     B,     B,  FPst,  VPst,  VPst,  VPst,  VPst,  VPst,  VPst,  VPst,  VPst,  VPst,  VPst,  VPst,
+  /* A8B0 */     B,     B,     B,     B,  MPst,  VPst,  VPst,  VPst,  VPst,  VPst,  VPst,  VPst,  VPst,  VPst,  VPst,  VPst,
   /* A8C0 */  VPst,  VPst,  VPst,  VPst,     H, VMAbv,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
   /* A8D0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,     O,     O,
 
   /* Devanagari Extended */
 
   /* A8E0 */ VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv,
   /* A8F0 */ VMAbv, VMAbv,     B,     B,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
 
@@ -430,45 +437,45 @@ static const USE_TABLE_ELEMENT_TYPE use_
   /* AAC0 */     B, VMAbv,     B,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
   /* AAD0 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
 
   /* Meetei Mayek Extensions */
 
   /* AAE0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,  VPre,  VBlw,  VAbv,  VPre,  VPst,
   /* AAF0 */     O,     O,     O,     O,     O, VMPst,     H,     O,
 
-#define use_offset_0xabc0u 3376
+#define use_offset_0xabc0u 3384
 
 
   /* Meetei Mayek */
 
   /* ABC0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* ABD0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* ABE0 */     B,     B,     B,  VPst,  VPst,  VAbv,  VPst,  VPst,  VBlw,  VPst,  VPst,     O, VMPst,  VBlw,     O,     O,
   /* ABF0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,     O,     O,
 
-#define use_offset_0xfe00u 3440
+#define use_offset_0xfe00u 3448
 
 
   /* Variation Selectors */
 
   /* FE00 */    VS,    VS,    VS,    VS,    VS,    VS,    VS,    VS,    VS,    VS,    VS,    VS,    VS,    VS,    VS,    VS,
 
-#define use_offset_0x10a00u 3456
+#define use_offset_0x10a00u 3464
 
 
   /* Kharoshthi */
 
   /* 10A00 */     B,  VBlw,  VBlw,  VBlw,     O,  VAbv,  VBlw,     O,     O,     O,     O,     O,  VBlw,  VBlw, VMBlw, VMAbv,
   /* 10A10 */     B,     B,     B,     B,     O,     B,     B,     B,     O,     B,     B,     B,     B,     B,     B,     B,
   /* 10A20 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 10A30 */     B,     B,     B,     B,     O,     O,     O,     O, CMAbv, CMBlw, CMBlw,     O,     O,     O,     O,     H,
   /* 10A40 */     B,     B,     B,     B,     B,     B,     B,     B,
 
-#define use_offset_0x11000u 3528
+#define use_offset_0x11000u 3536
 
 
   /* Brahmi */
 
   /* 11000 */ VMPst, VMAbv, VMPst,    CS,    CS,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 11010 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 11020 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 11030 */     B,     B,     B,     B,     B,     B,     B,     B,  VAbv,  VAbv,  VAbv,  VAbv,  VBlw,  VBlw,  VBlw,  VBlw,
@@ -479,17 +486,17 @@ static const USE_TABLE_ELEMENT_TYPE use_
 
   /* Kaithi */
 
   /* 11080 */ VMAbv, VMAbv, VMPst,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 11090 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 110A0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 110B0 */  VPst,  VPre,  VPst,  VBlw,  VBlw,  VAbv,  VAbv,  VPst,  VPst,     H, CMBlw,     O,     O,     O,     O,     O,
 
-#define use_offset_0x11100u 3720
+#define use_offset_0x11100u 3728
 
 
   /* Chakma */
 
   /* 11100 */ VMAbv, VMAbv, VMAbv,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 11110 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 11120 */     B,     B,     B,     B,     B,     B,     B,  VAbv,  VAbv,  VAbv,  VBlw,  VBlw,  VPre,  VAbv,  VAbv,  VAbv,
   /* 11130 */  VAbv,  VBlw,  VBlw,     H,  VAbv,     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
@@ -517,17 +524,17 @@ static const USE_TABLE_ELEMENT_TYPE use_
 
   /* Khojki */
 
   /* 11200 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 11210 */     B,     B,     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 11220 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,  VPst,  VPst,  VPst,  VBlw,
   /* 11230 */  VAbv,  VAbv,  VAbv,  VAbv, VMAbv,     H, CMAbv, CMAbv,     O,     O,     O,     O,     O,     O, VMAbv,     O,
 
-#define use_offset_0x11280u 4040
+#define use_offset_0x11280u 4048
 
 
   /* Multani */
 
   /* 11280 */     B,     B,     B,     B,     B,     B,     B,     O,     B,     O,     B,     B,     B,     B,     O,     B,
   /* 11290 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     B,
   /* 112A0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,     O,     O,     O,
 
@@ -545,17 +552,17 @@ static const USE_TABLE_ELEMENT_TYPE use_
   /* 11310 */     B,     O,     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 11320 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     B,     B,     B,     B,     B,     B,
   /* 11330 */     B,     O,     B,     B,     O,     B,     B,     B,     B,     B,     O,     O, CMBlw,     B,  VPst,  VPst,
   /* 11340 */  VAbv,  VPst,  VPst,  VPst,  VPst,     O,     O,  VPre,  VPre,     O,     O,  VPre,  VPre,     H,     O,     O,
   /* 11350 */     O,     O,     O,     O,     O,     O,     O,  VPst,     O,     O,     O,     O,     O,     O,     B,     B,
   /* 11360 */     B,     B,  VPst,  VPst,     O,     O, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv,     O,     O,     O,
   /* 11370 */ VMAbv, VMAbv, VMAbv, VMAbv, VMAbv,     O,     O,     O,
 
-#define use_offset_0x11400u 4288
+#define use_offset_0x11400u 4296
 
 
   /* Newa */
 
   /* 11400 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 11410 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 11420 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 11430 */     B,     B,     B,     B,     B,  VPst,  VPre,  VPst,  VBlw,  VBlw,  VBlw,  VBlw,  VBlw,  VBlw,  VAbv,  VAbv,
@@ -568,17 +575,17 @@ static const USE_TABLE_ELEMENT_TYPE use_
 
   /* 11480 */     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 11490 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 114A0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 114B0 */  VPst,  VPre,  VPst,  VBlw,  VBlw,  VBlw,  VBlw,  VBlw,  VBlw,  VPre,  VAbv,  VPre,  VPre,  VPst,  VPre, VMAbv,
   /* 114C0 */ VMAbv, VMPst,     H, CMBlw,     B,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
   /* 114D0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,     O,     O,
 
-#define use_offset_0x11580u 4512
+#define use_offset_0x11580u 4520
 
 
   /* Siddham */
 
   /* 11580 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 11590 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 115A0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,  VPst,
   /* 115B0 */  VPre,  VPst,  VBlw,  VBlw,  VBlw,  VBlw,     O,     O,  VPre,  VPre,  VPre,  VPre, VMAbv, VMAbv, VMPst,     H,
@@ -611,17 +618,17 @@ static const USE_TABLE_ELEMENT_TYPE use_
 
   /* Ahom */
 
   /* 11700 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 11710 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,  MBlw,  MPre,  MAbv,
   /* 11720 */  VPst,  VPst,  VAbv,  VAbv,  VBlw,  VBlw,  VPre,  VAbv,  VBlw,  VAbv,  VAbv,  VAbv,     O,     O,     O,     O,
   /* 11730 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,
 
-#define use_offset_0x11a00u 4960
+#define use_offset_0x11a00u 4968
 
 
   /* Zanabazar Square */
 
   /* 11A00 */     B,  VAbv,  VBlw,  VBlw,  VAbv,  VAbv,  VAbv,  VAbv,  VAbv,  VAbv,  VBlw,     B,     B,     B,     B,     B,
   /* 11A10 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 11A20 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 11A30 */     B,     B,     B,    FM,  VBlw, VMAbv, VMAbv, VMAbv, VMAbv, VMPst,     R,  MBlw,  MBlw,  MBlw,  MBlw,    GB,
@@ -630,17 +637,17 @@ static const USE_TABLE_ELEMENT_TYPE use_
   /* Soyombo */
 
   /* 11A50 */     B,  VAbv,  VBlw,  VBlw,  VAbv,  VAbv,  VAbv,  VPst,  VPst,  VBlw,  VBlw,  VBlw,     B,     B,     B,     B,
   /* 11A60 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 11A70 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 11A80 */     B,     B,     B,     B,     O,     O,     R,     R,     R,     R,  FBlw,  FBlw,  FBlw,  FBlw,  FBlw,  FBlw,
   /* 11A90 */  FBlw,  FBlw,  FBlw,  FBlw,  FBlw,  FBlw, VMAbv, VMPst, CMAbv,     H,     O,     O,     O,     O,     O,     O,
 
-#define use_offset_0x11c00u 5120
+#define use_offset_0x11c00u 5128
 
 
   /* Bhaiksuki */
 
   /* 11C00 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     B,     B,     B,     B,     B,     B,
   /* 11C10 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 11C20 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,  VPst,
   /* 11C30 */  VAbv,  VAbv,  VBlw,  VBlw,  VBlw,  VBlw,  VBlw,     O,  VAbv,  VAbv,  VAbv,  VAbv, VMAbv, VMAbv, VMPst,     H,
@@ -651,29 +658,29 @@ static const USE_TABLE_ELEMENT_TYPE use_
   /* Marchen */
 
   /* 11C70 */     O,     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 11C80 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 11C90 */     O,     O,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,
   /* 11CA0 */   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,     O,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,
   /* 11CB0 */  VBlw,  VPre,  VBlw,  VAbv,  VPst, VMAbv, VMAbv,     O,
 
-#define use_offset_0x11d00u 5304
+#define use_offset_0x11d00u 5312
 
 
   /* Masaram Gondi */
 
   /* 11D00 */     B,     B,     B,     B,     B,     B,     B,     O,     B,     B,     O,     B,     B,     B,     B,     B,
   /* 11D10 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 11D20 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 11D30 */     B,  VAbv,  VAbv,  VAbv,  VAbv,  VAbv,  VBlw,     O,     O,     O,  VAbv,     O,  VAbv,  VAbv,     O,  VAbv,
   /* 11D40 */ VMAbv, VMAbv, CMBlw,  VAbv,  VBlw,     H,     R,  MBlw,     O,     O,     O,     O,     O,     O,     O,     O,
   /* 11D50 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,     O,     O,
 
-}; /* Table items: 5400; occupancy: 73% */
+}; /* Table items: 5408; occupancy: 73% */
 
 USE_TABLE_ELEMENT_TYPE
 hb_use_get_categories (hb_codepoint_t u)
 {
   switch (u >> 12)
   {
     case 0x0u:
       if (hb_in_range<hb_codepoint_t> (u, 0x0028u, 0x003Fu)) return use_table[u - 0x0028u + use_offset_0x0028u];
@@ -689,16 +696,17 @@ hb_use_get_categories (hb_codepoint_t u)
       if (hb_in_range<hb_codepoint_t> (u, 0x1B00u, 0x1C4Fu)) return use_table[u - 0x1B00u + use_offset_0x1b00u];
       if (hb_in_range<hb_codepoint_t> (u, 0x1CD0u, 0x1CFFu)) return use_table[u - 0x1CD0u + use_offset_0x1cd0u];
       if (hb_in_range<hb_codepoint_t> (u, 0x1DF8u, 0x1DFFu)) return use_table[u - 0x1DF8u + use_offset_0x1df8u];
       break;
 
     case 0x2u:
       if (hb_in_range<hb_codepoint_t> (u, 0x2008u, 0x2017u)) return use_table[u - 0x2008u + use_offset_0x2008u];
       if (hb_in_range<hb_codepoint_t> (u, 0x2060u, 0x2087u)) return use_table[u - 0x2060u + use_offset_0x2060u];
+      if (hb_in_range<hb_codepoint_t> (u, 0x20F0u, 0x20F7u)) return use_table[u - 0x20F0u + use_offset_0x20f0u];
       if (unlikely (u == 0x25CCu)) return GB;
       break;
 
     case 0xAu:
       if (hb_in_range<hb_codepoint_t> (u, 0xA800u, 0xAAF7u)) return use_table[u - 0xA800u + use_offset_0xa800u];
       if (hb_in_range<hb_codepoint_t> (u, 0xABC0u, 0xABFFu)) return use_table[u - 0xABC0u + use_offset_0xabc0u];
       break;
 
--- a/gfx/harfbuzz/src/hb-ot-shape-fallback.cc
+++ b/gfx/harfbuzz/src/hb-ot-shape-fallback.cc
@@ -213,20 +213,20 @@ position_mark (const hb_ot_shape_plan_t 
   /* We don't position LEFT and RIGHT marks. */
 
   /* X positioning */
   switch (combining_class)
   {
     case HB_UNICODE_COMBINING_CLASS_DOUBLE_BELOW:
     case HB_UNICODE_COMBINING_CLASS_DOUBLE_ABOVE:
       if (buffer->props.direction == HB_DIRECTION_LTR) {
-	pos.x_offset += base_extents.x_bearing - mark_extents.width / 2 - mark_extents.x_bearing;
+	pos.x_offset += base_extents.x_bearing + base_extents.width - mark_extents.width / 2 - mark_extents.x_bearing;
         break;
       } else if (buffer->props.direction == HB_DIRECTION_RTL) {
-	pos.x_offset += base_extents.x_bearing + base_extents.width - mark_extents.width / 2 - mark_extents.x_bearing;
+	pos.x_offset += base_extents.x_bearing - mark_extents.width / 2 - mark_extents.x_bearing;
         break;
       }
       HB_FALLTHROUGH;
 
     default:
     case HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW:
     case HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE:
     case HB_UNICODE_COMBINING_CLASS_BELOW:
--- a/gfx/harfbuzz/src/hb-ot-shape.cc
+++ b/gfx/harfbuzz/src/hb-ot-shape.cc
@@ -103,17 +103,17 @@ hb_ot_shape_collect_features (hb_ot_shap
       map->add_feature (horizontal_features[i], 1, F_GLOBAL |
 			(horizontal_features[i] == HB_TAG('k','e','r','n') ?
 			 F_HAS_FALLBACK : F_NONE));
   else
   {
     /* We really want to find a 'vert' feature if there's any in the font, no
      * matter which script/langsys it is listed (or not) under.
      * See various bugs referenced from:
-     * https://github.com/behdad/harfbuzz/issues/63 */
+     * https://github.com/harfbuzz/harfbuzz/issues/63 */
     map->add_feature (HB_TAG ('v','e','r','t'), 1, F_GLOBAL | F_GLOBAL_SEARCH);
   }
 
   if (planner->shaper->override_features)
     planner->shaper->override_features (planner);
 
   for (unsigned int i = 0; i < num_user_features; i++) {
     const hb_feature_t *feature = &user_features[i];
@@ -812,21 +812,26 @@ hb_propagate_flags (hb_buffer_t *buffer)
 
 /* Pull it all together! */
 
 static void
 hb_ot_shape_internal (hb_ot_shape_context_t *c)
 {
   c->buffer->deallocate_var_all ();
   c->buffer->scratch_flags = HB_BUFFER_SCRATCH_FLAG_DEFAULT;
-  if (likely (!_hb_unsigned_int_mul_overflows (c->buffer->len, HB_BUFFER_MAX_EXPANSION_FACTOR)))
+  if (likely (!_hb_unsigned_int_mul_overflows (c->buffer->len, HB_BUFFER_MAX_LEN_FACTOR)))
   {
-    c->buffer->max_len = MAX (c->buffer->len * HB_BUFFER_MAX_EXPANSION_FACTOR,
+    c->buffer->max_len = MAX (c->buffer->len * HB_BUFFER_MAX_LEN_FACTOR,
 			      (unsigned) HB_BUFFER_MAX_LEN_MIN);
   }
+  if (likely (!_hb_unsigned_int_mul_overflows (c->buffer->len, HB_BUFFER_MAX_OPS_FACTOR)))
+  {
+    c->buffer->max_ops = MAX (c->buffer->len * HB_BUFFER_MAX_OPS_FACTOR,
+			      (unsigned) HB_BUFFER_MAX_OPS_MIN);
+  }
 
   bool disable_otl = c->plan->shaper->disable_otl && c->plan->shaper->disable_otl (c->plan);
   //c->fallback_substitute     = disable_otl || !hb_ot_layout_has_substitution (c->face);
   c->fallback_positioning    = disable_otl || !hb_ot_layout_has_positioning (c->face);
   c->fallback_glyph_classes  = disable_otl || !hb_ot_layout_has_glyph_classes (c->face);
 
   /* Save the original direction, we use it later. */
   c->target_direction = c->buffer->props.direction;
@@ -856,16 +861,17 @@ hb_ot_shape_internal (hb_ot_shape_contex
 
   hb_propagate_flags (c->buffer);
 
   _hb_buffer_deallocate_unicode_vars (c->buffer);
 
   c->buffer->props.direction = c->target_direction;
 
   c->buffer->max_len = HB_BUFFER_MAX_LEN_DEFAULT;
+  c->buffer->max_ops = HB_BUFFER_MAX_OPS_DEFAULT;
   c->buffer->deallocate_var_all ();
 }
 
 
 hb_bool_t
 _hb_ot_shape (hb_shape_plan_t    *shape_plan,
 	      hb_font_t          *font,
 	      hb_buffer_t        *buffer,
--- a/gfx/harfbuzz/src/hb-ot-var-avar-table.hh
+++ b/gfx/harfbuzz/src/hb-ot-var-avar-table.hh
@@ -128,18 +128,18 @@ struct avar
       coords[i] = map->map (coords[i]);
       map = &StructAfter<SegmentMaps> (*map);
     }
   }
 
   protected:
   FixedVersion<>version;	/* Version of the avar table
 				 * initially set to 0x00010000u */
-  USHORT	reserved;	/* This field is permanently reserved. Set to 0. */
-  USHORT	axisCount;	/* The number of variation axes in the font. This
+  UINT16	reserved;	/* This field is permanently reserved. Set to 0. */
+  UINT16	axisCount;	/* The number of variation axes in the font. This
 				 * must be the same number as axisCount in the
 				 * 'fvar' table. */
   SegmentMaps	axisSegmentMapsZ;
 
   public:
   DEFINE_SIZE_MIN (8);
 };
 
--- a/gfx/harfbuzz/src/hb-ot-var-fvar-table.hh
+++ b/gfx/harfbuzz/src/hb-ot-var-fvar-table.hh
@@ -37,21 +37,21 @@ struct InstanceRecord
   inline bool sanitize (hb_sanitize_context_t *c, unsigned int axis_count) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) &&
 		  c->check_array (coordinates, coordinates[0].static_size, axis_count));
   }
 
   protected:
-  USHORT	subfamilyNameID;/* The name ID for entries in the 'name' table
+  UINT16	subfamilyNameID;/* The name ID for entries in the 'name' table
 				 * that provide subfamily names for this instance. */
-  USHORT	reserved;	/* Reserved for future use — set to 0. */
+  UINT16	reserved;	/* Reserved for future use — set to 0. */
   Fixed		coordinates[VAR];/* The coordinates array for this instance. */
-  //USHORT	postScriptNameIDX;/*Optional. The name ID for entries in the 'name'
+  //UINT16	postScriptNameIDX;/*Optional. The name ID for entries in the 'name'
   //				  * table that provide PostScript names for this
   //				  * instance. */
 
   public:
   DEFINE_SIZE_ARRAY (4, coordinates);
 };
 
 struct AxisRecord
@@ -62,18 +62,18 @@ struct AxisRecord
     return_trace (c->check_struct (this));
   }
 
   public:
   Tag		axisTag;	/* Tag identifying the design variation for the axis. */
   Fixed		minValue;	/* The minimum coordinate value for the axis. */
   Fixed		defaultValue;	/* The default coordinate value for the axis. */
   Fixed		maxValue;	/* The maximum coordinate value for the axis. */
-  USHORT	reserved;	/* Reserved for future use — set to 0. */
-  USHORT	axisNameID;	/* The name ID for entries in the 'name' table that
+  UINT16	reserved;	/* Reserved for future use — set to 0. */
+  UINT16	axisNameID;	/* The name ID for entries in the 'name' table that
 				 * provide a display name for this axis. */
 
   public:
   DEFINE_SIZE_STATIC (20);
 };
 
 
 /*
@@ -181,26 +181,26 @@ struct fvar
   { return &StructAtOffset<AxisRecord> (this, things); }
 
   inline const InstanceRecord * get_instances (void) const
   { return &StructAtOffset<InstanceRecord> (get_axes () + axisCount, 0); }
 
   protected:
   FixedVersion<>version;	/* Version of the fvar table
 				 * initially set to 0x00010000u */
-  Offset<>	things;		/* Offset in bytes from the beginning of the table
+  Offset16	things;		/* Offset in bytes from the beginning of the table
 				 * to the start of the AxisRecord array. */
-  USHORT	reserved;	/* This field is permanently reserved. Set to 2. */
-  USHORT	axisCount;	/* The number of variation axes in the font (the
+  UINT16	reserved;	/* This field is permanently reserved. Set to 2. */
+  UINT16	axisCount;	/* The number of variation axes in the font (the
 				 * number of records in the axes array). */
-  USHORT	axisSize;	/* The size in bytes of each VariationAxisRecord —
+  UINT16	axisSize;	/* The size in bytes of each VariationAxisRecord —
 				 * set to 20 (0x0014) for this version. */
-  USHORT	instanceCount;	/* The number of named instances defined in the font
+  UINT16	instanceCount;	/* The number of named instances defined in the font
 				 * (the number of records in the instances array). */
-  USHORT	instanceSize;	/* The size in bytes of each InstanceRecord — set
+  UINT16	instanceSize;	/* The size in bytes of each InstanceRecord — set
 				 * to either axisCount * sizeof(Fixed) + 4, or to
 				 * axisCount * sizeof(Fixed) + 6. */
 
   public:
   DEFINE_SIZE_STATIC (16);
 };
 
 } /* namespace OT */
--- a/gfx/harfbuzz/src/hb-ot-var-hvar-table.hh
+++ b/gfx/harfbuzz/src/hb-ot-var-hvar-table.hh
@@ -50,17 +50,17 @@ struct DeltaSetIndexMap
       return v;
 
     if (v >= mapCount)
       v = mapCount - 1;
 
     unsigned int u = 0;
     { /* Fetch it. */
       unsigned int w = get_width ();
-      const BYTE *p = mapData + w * v;
+      const UINT8 *p = mapData + w * v;
       for (; w; w--)
 	u = (u << 8) + *p++;
     }
 
     { /* Repack it. */
       unsigned int n = get_inner_bitcount ();
       unsigned int outer = u >> n;
       unsigned int inner = u & ((1 << n) - 1);
@@ -73,20 +73,20 @@ struct DeltaSetIndexMap
   protected:
   inline unsigned int get_width (void) const
   { return ((format >> 4) & 3) + 1; }
 
   inline unsigned int get_inner_bitcount (void) const
   { return (format & 0xF) + 1; }
 
   protected:
-  USHORT	format;		/* A packed field that describes the compressed
+  UINT16	format;		/* A packed field that describes the compressed
 				 * representation of delta-set indices. */
-  USHORT	mapCount;	/* The number of mapping entries. */
-  BYTE		mapData[VAR];	/* The delta-set index mapping data. */
+  UINT16	mapCount;	/* The number of mapping entries. */
+  UINT8		mapData[VAR];	/* The delta-set index mapping data. */
 
   public:
   DEFINE_SIZE_ARRAY (4, mapData);
 };
 
 
 /*
  * HVAR -- The Horizontal Metrics Variations Table
--- a/gfx/harfbuzz/src/hb-ot-var-mvar-table.hh
+++ b/gfx/harfbuzz/src/hb-ot-var-mvar-table.hh
@@ -38,17 +38,17 @@ struct VariationValueRecord
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this));
   }
 
   public:
   Tag		valueTag;	/* Four-byte tag identifying a font-wide measure. */
-  ULONG		varIdx;		/* Outer/inner index into VariationStore item. */
+  UINT32		varIdx;		/* Outer/inner index into VariationStore item. */
 
   public:
   DEFINE_SIZE_STATIC (8);
 };
 
 
 /*
  * MVAR -- Metrics Variations Table
@@ -90,23 +90,23 @@ protected:
     const hb_tag_t *a = (const hb_tag_t *) pa;
     const Tag *b = (const Tag *) pb;
     return b->cmp (*a);
   }
 
   protected:
   FixedVersion<>version;	/* Version of the metrics variation table
 				 * initially set to 0x00010000u */
-  USHORT	reserved;	/* Not used; set to 0. */
-  USHORT	valueRecordSize;/* The size in bytes of each value record —
+  UINT16	reserved;	/* Not used; set to 0. */
+  UINT16	valueRecordSize;/* The size in bytes of each value record —
 				 * must be greater than zero. */
-  USHORT	valueRecordCount;/* The number of value records — may be zero. */
+  UINT16	valueRecordCount;/* The number of value records — may be zero. */
   OffsetTo<VariationStore>
 		varStore;	/* Offset to item variation store table. */
-  BYTE		values[VAR];	/* Array of value records. The records must be
+  UINT8		values[VAR];	/* Array of value records. The records must be
 				 * in binary order of their valueTag field. */
 
   public:
   DEFINE_SIZE_ARRAY (12, values);
 };
 
 } /* namespace OT */
 
--- a/gfx/harfbuzz/src/hb-private.hh
+++ b/gfx/harfbuzz/src/hb-private.hh
@@ -687,17 +687,17 @@ hb_in_ranges (T u, T lo1, T hi1, T lo2, 
 }
 
 
 /* Enable bitwise ops on enums marked as flags_t */
 /* To my surprise, looks like the function resolver is happy to silently cast
  * one enum to another...  So this doesn't provide the type-checking that I
  * originally had in mind... :(.
  *
- * For MSVC warnings, see: https://github.com/behdad/harfbuzz/pull/163
+ * For MSVC warnings, see: https://github.com/harfbuzz/harfbuzz/pull/163
  */
 #ifdef _MSC_VER
 # pragma warning(disable:4200)
 # pragma warning(disable:4800)
 #endif
 #define HB_MARK_AS_FLAG_T(T) \
 	extern "C++" { \
 	  static inline T operator | (T l, T r) { return T ((unsigned) l | (unsigned) r); } \
--- a/gfx/harfbuzz/src/hb-set-private.hh
+++ b/gfx/harfbuzz/src/hb-set-private.hh
@@ -30,47 +30,67 @@
 #include "hb-private.hh"
 #include "hb-object-private.hh"
 
 
 /*
  * hb_set_t
  */
 
+/* TODO Keep a free-list so we can free pages that are completely zeroed.  At that
+ * point maybe also use a sentinel value for "all-1" pages? */
+
 struct hb_set_t
 {
   struct page_map_t
   {
     inline int cmp (const page_map_t *o) const { return (int) o->major - (int) major; }
 
     uint32_t major;
     uint32_t index;
   };
 
   struct page_t
   {
-    inline void init (void) {
-      memset (&v, 0, sizeof (v));
-    }
+    inline void init0 (void) { memset (&v, 0, sizeof (v)); }
+    inline void init1 (void) { memset (&v, 0xff, sizeof (v)); }
 
     inline unsigned int len (void) const
     { return ARRAY_LENGTH_CONST (v); }
 
     inline bool is_empty (void) const
     {
       for (unsigned int i = 0; i < len (); i++)
         if (v[i])
 	  return false;
       return true;
     }
 
     inline void add (hb_codepoint_t g) { elt (g) |= mask (g); }
     inline void del (hb_codepoint_t g) { elt (g) &= ~mask (g); }
     inline bool has (hb_codepoint_t g) const { return !!(elt (g) & mask (g)); }
 
+    inline void add_range (hb_codepoint_t a, hb_codepoint_t b)
+    {
+     elt_t *la = &elt (a);
+     elt_t *lb = &elt (b);
+     if (la == lb)
+       *la |= (mask (b) << 1) - mask(a);
+     else
+     {
+       *la |= ~(mask (a) - 1);
+       la++;
+
+       memset (la, 0xff, (char *) lb - (char *) la);
+
+       *lb |= ((mask (b) << 1) - 1);
+
+     }
+    }
+
     inline bool is_equal (const page_t *other) const
     {
       return 0 == memcmp (&v, &other->v, sizeof (v));
     }
 
     inline unsigned int get_population (void) const
     {
       unsigned int pop = 0;
@@ -191,37 +211,59 @@ struct hb_set_t
     return true;
   }
 
   inline void add (hb_codepoint_t g)
   {
     if (unlikely (in_error)) return;
     if (unlikely (g == INVALID)) return;
     page_t *page = page_for_insert (g);
-    if (!page)
-      return;
+    if (unlikely (!page)) return;
     page->add (g);
   }
   inline void add_range (hb_codepoint_t a, hb_codepoint_t b)
   {
-    if (unlikely (in_error)) return;
-    /* TODO Speedup */
-    for (unsigned int i = a; i < b + 1; i++)
-      add (i);
+    if (unlikely (in_error || a > b || a == INVALID || b == INVALID)) return;
+    unsigned int ma = get_major (a);
+    unsigned int mb = get_major (b);
+    if (ma == mb)
+    {
+      page_t *page = page_for_insert (a);
+      if (unlikely (!page)) return;
+      page->add_range (a, b);
+    }
+    else
+    {
+      page_t *page = page_for_insert (a);
+      if (unlikely (!page)) return;
+      page->add_range (a, major_start (ma + 1) - 1);
+
+      for (unsigned int m = ma + 1; m < mb; m++)
+      {
+	page = page_for_insert (major_start (m));
+	if (unlikely (!page)) return;
+	page->init1 ();
+      }
+
+      page = page_for_insert (b);
+      if (unlikely (!page)) return;
+      page->add_range (major_start (mb), b);
+    }
   }
   inline void del (hb_codepoint_t g)
   {
     if (unlikely (in_error)) return;
     page_t *p = page_for (g);
     if (!p)
       return;
     p->del (g);
   }
   inline void del_range (hb_codepoint_t a, hb_codepoint_t b)
   {
+    /* TODO Optimize, like add_range(). */
     if (unlikely (in_error)) return;
     for (unsigned int i = a; i < b + 1; i++)
       del (i);
   }
   inline bool has (hb_codepoint_t g) const
   {
     const page_t *p = page_for (g);
     if (!p)
@@ -428,46 +470,47 @@ struct hb_set_t
     for (int i = count - 1; i >= 0; i++)
       if (!page_at (i).is_empty ())
         return page_map[i].major * page_t::PAGE_BITS + page_at (i).get_max ();
     return INVALID;
   }
 
   static  const hb_codepoint_t INVALID = HB_SET_VALUE_INVALID;
 
-  page_t *page_for_insert (hb_codepoint_t g)
+  inline page_t *page_for_insert (hb_codepoint_t g)
   {
     page_map_t map = {get_major (g), pages.len};
     unsigned int i;
     if (!page_map.bfind (&map, &i))
     {
       if (!resize (pages.len + 1))
 	return nullptr;
 
-      pages[map.index].init ();
+      pages[map.index].init0 ();
       memmove (&page_map[i + 1], &page_map[i], (page_map.len - 1 - i) * sizeof (page_map[0]));
       page_map[i] = map;
     }
     return &pages[page_map[i].index];
   }
-  page_t *page_for (hb_codepoint_t g)
+  inline page_t *page_for (hb_codepoint_t g)
   {
     page_map_t key = {get_major (g)};
     const page_map_t *found = page_map.bsearch (&key);
     if (found)
       return &pages[found->index];
     return nullptr;
   }
-  const page_t *page_for (hb_codepoint_t g) const
+  inline const page_t *page_for (hb_codepoint_t g) const
   {
     page_map_t key = {get_major (g)};
     const page_map_t *found = page_map.bsearch (&key);
     if (found)
       return &pages[found->index];
     return nullptr;
   }
-  page_t &page_at (unsigned int i) { return pages[page_map[i].index]; }
-  const page_t &page_at (unsigned int i) const { return pages[page_map[i].index]; }
-  unsigned int get_major (hb_codepoint_t g) const { return g / page_t::PAGE_BITS; }
+  inline page_t &page_at (unsigned int i) { return pages[page_map[i].index]; }
+  inline const page_t &page_at (unsigned int i) const { return pages[page_map[i].index]; }
+  inline unsigned int get_major (hb_codepoint_t g) const { return g / page_t::PAGE_BITS; }
+  inline hb_codepoint_t major_start (unsigned int major) const { return major * page_t::PAGE_BITS; }
 };
 
 
 #endif /* HB_SET_PRIVATE_HH */
--- a/gfx/harfbuzz/src/hb-string-array.hh
+++ b/gfx/harfbuzz/src/hb-string-array.hh
@@ -43,17 +43,17 @@ static const union HB_STRING_ARRAY_TYPE_
 /* I like to avoid storing the nul-termination byte since we don't need it,
  * but C++ does not allow that.
  * https://stackoverflow.com/questions/28433862/why-initializer-string-for-array-of-chars-is-too-long-compiles-fine-in-c-not
  */
 #define _S(s) char HB_PASTE (str, __LINE__)[sizeof (s)];
 #include HB_STRING_ARRAY_LIST
 #undef _S
   } st;
-  char str[0];
+  char str[VAR];
 }
 HB_STRING_ARRAY_POOL_NAME =
 {
   {
 #define _S(s) s,
 #include HB_STRING_ARRAY_LIST
 #undef _S
   }
--- a/gfx/harfbuzz/src/hb-unicode-private.hh
+++ b/gfx/harfbuzz/src/hb-unicode-private.hh
@@ -132,17 +132,17 @@ HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS_SIM
   }
 
   /* Default_Ignorable codepoints:
    *
    * Note: While U+115F, U+1160, U+3164 and U+FFA0 are Default_Ignorable,
    * we do NOT want to hide them, as the way Uniscribe has implemented them
    * is with regular spacing glyphs, and that's the way fonts are made to work.
    * As such, we make exceptions for those four.
-   * Also ignoring U+1BCA0..1BCA3. https://github.com/behdad/harfbuzz/issues/503
+   * Also ignoring U+1BCA0..1BCA3. https://github.com/harfbuzz/harfbuzz/issues/503
    *
    * Unicode 7.0:
    * $ grep '; Default_Ignorable_Code_Point ' DerivedCoreProperties.txt | sed 's/;.*#/#/'
    * 00AD          # Cf       SOFT HYPHEN
    * 034F          # Mn       COMBINING GRAPHEME JOINER
    * 061C          # Cf       ARABIC LETTER MARK
    * 115F..1160    # Lo   [2] HANGUL CHOSEONG FILLER..HANGUL JUNGSEONG FILLER
    * 17B4..17B5    # Mn   [2] KHMER VOWEL INHERENT AQ..KHMER VOWEL INHERENT AA
--- 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 7
-#define HB_VERSION_MICRO 1
+#define HB_VERSION_MICRO 2
 
-#define HB_VERSION_STRING "1.7.1"
+#define HB_VERSION_STRING "1.7.2"
 
 #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,
--- a/gfx/harfbuzz/src/main.cc
+++ b/gfx/harfbuzz/src/main.cc
@@ -101,18 +101,18 @@ main (int argc, char **argv)
       const OpenTypeTable &table = font.get_table (n_table);
       printf ("  Table %2d of %2d: %.4s (0x%08x+0x%08x)\n", n_table, num_tables,
 	      (const char *)table.tag,
 	      (unsigned int) table.offset,
 	      (unsigned int) table.length);
 
       switch (table.tag) {
 
-      case GSUBGPOS::GSUBTag:
-      case GSUBGPOS::GPOSTag:
+      case HB_OT_TAG_GSUB:
+      case HB_OT_TAG_GPOS:
 	{
 
 	const GSUBGPOS &g = *CastP<GSUBGPOS> (font_data + table.offset);
 
 	int num_scripts = g.get_script_count ();
 	printf ("    %d script(s) found in table\n", num_scripts);
 	for (int n_script = 0; n_script < num_scripts; n_script++) {
 	  const Script &script = g.get_script (n_script);
--- a/gfx/harfbuzz/src/sample.py
+++ b/gfx/harfbuzz/src/sample.py
@@ -40,17 +40,17 @@ class Debugger(object):
 		return True
 debugger = Debugger()
 hb.buffer_set_message_func (buf, debugger.message, 1, 0)
 
 ##
 ## Add text to buffer
 ##
 #
-# See https://github.com/behdad/harfbuzz/pull/271
+# See https://github.com/harfbuzz/harfbuzz/pull/271
 #
 if False:
 	# If you do not care about cluster values reflecting Python
 	# string indices, then this is quickest way to add text to
 	# buffer:
 	hb.buffer_add_utf8 (buf, text.encode('utf-8'), 0, -1)
 	# Otherwise, then following handles both narrow and wide
 	# Python builds:
--- a/js/src/jsapi-tests/tests.h
+++ b/js/src/jsapi-tests/tests.h
@@ -150,20 +150,16 @@ class JSAPITest
         return JSAPITestString(v ? "true" : "false");
     }
 
     JSAPITestString toSource(JSAtom* v) {
         JS::RootedValue val(cx, JS::StringValue((JSString*)v));
         return jsvalToSource(val);
     }
 
-    JSAPITestString toSource(JSVersion v) {
-        return JSAPITestString(JS_VersionToString(v));
-    }
-
     // Note that in some still-supported GCC versions (we think anything before
     // GCC 4.6), this template does not work when the second argument is
     // nullptr. It infers type U = long int. Use CHECK_NULL instead.
     template <typename T, typename U>
     bool checkEqual(const T& actual, const U& expected,
                     const char* actualExpr, const char* expectedExpr,
                     const char* filename, int lineno)
     {
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -589,57 +589,16 @@ JS_PUBLIC_API(void)
 JS::SetSingleThreadedExecutionCallbacks(JSContext* cx,
                                         BeginSingleThreadedExecutionCallback begin,
                                         EndSingleThreadedExecutionCallback end)
 {
     cx->runtime()->beginSingleThreadedExecutionCallback = begin;
     cx->runtime()->endSingleThreadedExecutionCallback = end;
 }
 
-static const struct v2smap {
-    JSVersion   version;
-    const char* string;
-} v2smap[] = {
-    {JSVERSION_ECMA_3,  "ECMAv3"},
-    {JSVERSION_1_6,     "1.6"},
-    {JSVERSION_1_7,     "1.7"},
-    {JSVERSION_1_8,     "1.8"},
-    {JSVERSION_ECMA_5,  "ECMAv5"},
-    {JSVERSION_DEFAULT, js_default_str},
-    {JSVERSION_DEFAULT, "1.0"},
-    {JSVERSION_DEFAULT, "1.1"},
-    {JSVERSION_DEFAULT, "1.2"},
-    {JSVERSION_DEFAULT, "1.3"},
-    {JSVERSION_DEFAULT, "1.4"},
-    {JSVERSION_DEFAULT, "1.5"},
-    {JSVERSION_UNKNOWN, nullptr},          /* must be last, nullptr is sentinel */
-};
-
-JS_PUBLIC_API(const char*)
-JS_VersionToString(JSVersion version)
-{
-    int i;
-
-    for (i = 0; v2smap[i].string; i++)
-        if (v2smap[i].version == version)
-            return v2smap[i].string;
-    return "unknown";
-}
-
-JS_PUBLIC_API(JSVersion)
-JS_StringToVersion(const char* string)
-{
-    int i;
-
-    for (i = 0; v2smap[i].string; i++)
-        if (strcmp(v2smap[i].string, string) == 0)
-            return v2smap[i].version;
-    return JSVERSION_UNKNOWN;
-}
-
 JS_PUBLIC_API(JS::ContextOptions&)
 JS::ContextOptionsRef(JSContext* cx)
 {
     return cx->options();
 }
 
 JS_PUBLIC_API(bool)
 JS::InitSelfHostedCode(JSContext* cx)
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -1071,22 +1071,16 @@ class MOZ_RAII JSAutoRequest
 
 #if 0
   private:
     static void* operator new(size_t) CPP_THROW_NEW { return 0; }
     static void operator delete(void*, size_t) { }
 #endif
 };
 
-extern JS_PUBLIC_API(const char*)
-JS_VersionToString(JSVersion version);
-
-extern JS_PUBLIC_API(JSVersion)
-JS_StringToVersion(const char* string);
-
 namespace JS {
 
 class JS_PUBLIC_API(ContextOptions) {
   public:
     ContextOptions()
       : baseline_(true),
         ion_(true),
         asmJS_(true),
--- a/js/src/jspubtd.h
+++ b/js/src/jspubtd.h
@@ -41,32 +41,16 @@ class JS_FRIEND_API(OwningCompileOptions
 class JS_FRIEND_API(TransitiveCompileOptions);
 class JS_PUBLIC_API(CompartmentOptions);
 
 class Value;
 struct Zone;
 
 } // namespace JS
 
-/*
- * Run-time version enumeration.  For compile-time version checking, please use
- * the JS_HAS_* macros in jsversion.h, or use MOZJS_MAJOR_VERSION,
- * MOZJS_MINOR_VERSION, MOZJS_PATCH_VERSION, and MOZJS_ALPHA definitions.
- */
-enum JSVersion {
-    JSVERSION_ECMA_3  = 148,
-    JSVERSION_1_6     = 160,
-    JSVERSION_1_7     = 170,
-    JSVERSION_1_8     = 180,
-    JSVERSION_ECMA_5  = 185,
-    JSVERSION_DEFAULT = 0,
-    JSVERSION_UNKNOWN = -1,
-    JSVERSION_LATEST  = JSVERSION_ECMA_5
-};
-
 /* Result of typeof operator enumeration. */
 enum JSType {
     JSTYPE_UNDEFINED,           /* undefined */
     JSTYPE_OBJECT,              /* object */
     JSTYPE_FUNCTION,            /* function */
     JSTYPE_STRING,              /* string */
     JSTYPE_NUMBER,              /* number */
     JSTYPE_BOOLEAN,             /* boolean */
--- a/js/src/vm/Runtime.cpp
+++ b/js/src/vm/Runtime.cpp
@@ -134,17 +134,16 @@ JSRuntime::JSRuntime(JSRuntime* parentRu
     exclusiveAccessLock(mutexid::RuntimeExclusiveAccess),
 #ifdef DEBUG
     activeThreadHasExclusiveAccess(false),
 #endif
     numActiveHelperThreadZones(0),
     numCompartments(0),
     localeCallbacks(nullptr),
     defaultLocale(nullptr),
-    defaultVersion_(JSVERSION_DEFAULT),
     profilingScripts(false),
     scriptAndCountsVector(nullptr),
     lcovOutput_(),
     jitRuntime_(nullptr),
     selfHostingGlobal_(nullptr),
     gc(thisFromCtor()),
     gcInitialized(false),
     NaNValue(DoubleNaNValue()),
--- a/js/src/vm/Runtime.h
+++ b/js/src/vm/Runtime.h
@@ -637,19 +637,16 @@ struct JSRuntime : public js::MallocProv
     js::ActiveThreadData<size_t> numCompartments;
 
     /* Locale-specific callbacks for string conversion. */
     js::ActiveThreadData<const JSLocaleCallbacks*> localeCallbacks;
 
     /* Default locale for Internationalization API */
     js::ActiveThreadData<char*> defaultLocale;
 
-    /* Default JSVersion. */
-    js::ActiveThreadData<JSVersion> defaultVersion_;
-
     /* If true, new scripts must be created with PC counter information. */
     js::ActiveThreadOrIonCompileData<bool> profilingScripts;
 
     /* Strong references on scripts held for PCCount profiling API. */
     js::ActiveThreadData<JS::PersistentRooted<js::ScriptAndCountsVector>*> scriptAndCountsVector;
 
   private:
     /* Code coverage output. */
@@ -736,19 +733,16 @@ struct JSRuntime : public js::MallocProv
     bool setDefaultLocale(const char* locale);
 
     /* Reset the default locale to OS defaults. */
     void resetDefaultLocale();
 
     /* Gets current default locale. String remains owned by context. */
     const char* getDefaultLocale();
 
-    JSVersion defaultVersion() const { return defaultVersion_; }
-    void setDefaultVersion(JSVersion v) { defaultVersion_ = v; }
-
     /* Garbage collector state, used by jsgc.c. */
     js::gc::GCRuntime   gc;
 
     /* Garbage collector state has been successfully initialized. */
     js::WriteOnceData<bool> gcInitialized;
 
     bool hasZealMode(js::gc::ZealMode mode) { return gc.hasZealMode(mode); }
 
--- a/js/xpconnect/src/Sandbox.cpp
+++ b/js/xpconnect/src/Sandbox.cpp
@@ -1838,17 +1838,17 @@ nsXPCComponents_utils_Sandbox::CallOrCon
 
     *_retval = true;
     return NS_OK;
 }
 
 nsresult
 xpc::EvalInSandbox(JSContext* cx, HandleObject sandboxArg, const nsAString& source,
                    const nsACString& filename, int32_t lineNo,
-                   JSVersion jsVersion, MutableHandleValue rval)
+                   MutableHandleValue rval)
 {
     JS_AbortIfWrongThread(cx);
     rval.set(UndefinedValue());
 
     bool waiveXray = xpc::WrapperFactory::HasWaiveXrayFlag(sandboxArg);
     RootedObject sandbox(cx, js::CheckedUnwrap(sandboxArg));
     if (!sandbox || !IsSandbox(sandbox)) {
         return NS_ERROR_INVALID_ARG;
--- a/js/xpconnect/src/XPCComponents.cpp
+++ b/js/xpconnect/src/XPCComponents.cpp
@@ -2206,34 +2206,17 @@ nsXPCComponents_Utils::EvalInSandbox(con
                                      JSContext* cx,
                                      uint8_t optionalArgc,
                                      MutableHandleValue retval)
 {
     RootedObject sandbox(cx);
     if (!JS_ValueToObject(cx, sandboxVal, &sandbox) || !sandbox)
         return NS_ERROR_INVALID_ARG;
 
-    // Optional third argument: JS version, as a string.
-    JSVersion jsVersion = JSVERSION_DEFAULT;
-    if (optionalArgc >= 1) {
-        JSString* jsVersionStr = ToString(cx, version);
-        if (!jsVersionStr)
-            return NS_ERROR_INVALID_ARG;
-
-        JSAutoByteString bytes(cx, jsVersionStr);
-        if (!bytes)
-            return NS_ERROR_INVALID_ARG;
-
-        // Treat non-default version designation as default.
-        if (JS_StringToVersion(bytes.ptr()) == JSVERSION_UNKNOWN &&
-            strcmp(bytes.ptr(), "latest"))
-        {
-            return NS_ERROR_INVALID_ARG;
-        }
-    }
+    // Optional third argument: JS version, as a string, is unused.
 
     // Optional fourth and fifth arguments: filename and line number.
     int32_t lineNo = (optionalArgc >= 3) ? lineNumber : 1;
     nsCString filename;
     if (!filenameArg.IsVoid()) {
         filename.Assign(filenameArg);
     } else {
         // Get the current source info.
@@ -2241,18 +2224,17 @@ nsXPCComponents_Utils::EvalInSandbox(con
         if (frame) {
             nsString frameFile;
             frame->GetFilename(cx, frameFile);
             CopyUTF16toUTF8(frameFile, filename);
             frame->GetLineNumber(cx, &lineNo);
         }
     }
 
-    return xpc::EvalInSandbox(cx, sandbox, source, filename, lineNo,
-                              jsVersion, retval);
+    return xpc::EvalInSandbox(cx, sandbox, source, filename, lineNo, retval);
 }
 
 NS_IMETHODIMP
 nsXPCComponents_Utils::GetSandboxAddonId(HandleValue sandboxVal,
                                          JSContext* cx, MutableHandleValue rval)
 {
     if (!sandboxVal.isObject())
         return NS_ERROR_INVALID_ARG;
--- a/js/xpconnect/src/nsXPConnect.cpp
+++ b/js/xpconnect/src/nsXPConnect.cpp
@@ -793,18 +793,17 @@ nsXPConnect::EvalInSandboxObject(const n
 
     RootedObject sandbox(cx, sandboxArg);
     nsCString filenameStr;
     if (filename) {
         filenameStr.Assign(filename);
     } else {
         filenameStr = NS_LITERAL_CSTRING("x-bogus://XPConnect/Sandbox");
     }
-    return EvalInSandbox(cx, sandbox, source, filenameStr, 1,
-                         JSVERSION_DEFAULT, rval);
+    return EvalInSandbox(cx, sandbox, source, filenameStr, 1, rval);
 }
 
 NS_IMETHODIMP
 nsXPConnect::GetWrappedNativePrototype(JSContext* aJSContext,
                                        JSObject* aScopeArg,
                                        nsIClassInfo* aClassInfo,
                                        JSObject** aRetVal)
 {
--- a/js/xpconnect/src/xpcprivate.h
+++ b/js/xpconnect/src/xpcprivate.h
@@ -2911,17 +2911,17 @@ CreateSandboxObject(JSContext* cx, JS::M
 // CreateSandboxObject(). The caller is responsible of ensuring
 // that *rval doesn't get collected during the call or usage after the
 // call. This helper will use filename and lineNo for error reporting,
 // and if no filename is provided it will use the codebase from the
 // principal and line number 1 as a fallback.
 nsresult
 EvalInSandbox(JSContext* cx, JS::HandleObject sandbox, const nsAString& source,
               const nsACString& filename, int32_t lineNo,
-              JSVersion jsVersion, JS::MutableHandleValue rval);
+              JS::MutableHandleValue rval);
 
 nsresult
 GetSandboxAddonId(JSContext* cx, JS::HandleObject sandboxArg,
                   JS::MutableHandleValue rval);
 
 // Helper for retrieving metadata stored in a reserved slot. The metadata
 // is set during the sandbox creation using the "metadata" option.
 nsresult
--- a/layout/base/PresShell.cpp
+++ b/layout/base/PresShell.cpp
@@ -3622,19 +3622,37 @@ PresShell::ScrollFrameRectIntoView(nsIFr
   nsIFrame* container = aFrame;
   // Walk up the frame hierarchy scrolling the rect into view and
   // keeping rect relative to container
   do {
     nsIScrollableFrame* sf = do_QueryFrame(container);
     if (sf) {
       nsPoint oldPosition = sf->GetScrollPosition();
       nsRect targetRect = rect;
-      if (container->StyleDisplay()->mOverflowClipBox ==
+      // Inflate the scrolled rect by the container's padding in each dimension,
+      // unless we have 'overflow-clip-box-*: content-box' in that dimension.
+      auto* disp = container->StyleDisplay();
+      if (disp->mOverflowClipBoxBlock ==
+            NS_STYLE_OVERFLOW_CLIP_BOX_CONTENT_BOX ||
+          disp->mOverflowClipBoxInline ==
             NS_STYLE_OVERFLOW_CLIP_BOX_CONTENT_BOX) {
+        WritingMode wm = container->GetWritingMode();
+        bool cbH = (wm.IsVertical() ? disp->mOverflowClipBoxBlock
+                                    : disp->mOverflowClipBoxInline) ==
+                   NS_STYLE_OVERFLOW_CLIP_BOX_CONTENT_BOX;
+        bool cbV = (wm.IsVertical() ? disp->mOverflowClipBoxInline
+                                    : disp->mOverflowClipBoxBlock) ==
+                   NS_STYLE_OVERFLOW_CLIP_BOX_CONTENT_BOX;
         nsMargin padding = container->GetUsedPadding();
+        if (!cbH) {
+          padding.left = padding.right = nscoord(0);
+        }
+        if (!cbV) {
+          padding.top = padding.bottom = nscoord(0);
+        }
         targetRect.Inflate(padding);
       }
       ScrollToShowRect(sf, targetRect - sf->GetScrolledFrame()->GetPosition(),
                        aVertical, aHorizontal, aFlags);
       nsPoint newPosition = sf->LastScrollDestination();
       // If the scroll position increased, that means our content moved up,
       // so our rect's offset should decrease
       rect += oldPosition - newPosition;
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -2431,24 +2431,44 @@ ApplyOverflowClipping(nsDisplayListBuild
   // is required by comboboxes which make their display text (an inline frame)
   // have clipping.
   if (!nsFrame::ShouldApplyOverflowClipping(aFrame, aDisp)) {
     return false;
   }
   nsRect clipRect;
   bool haveRadii = false;
   nscoord radii[8];
-  if (aFrame->StyleDisplay()->mOverflowClipBox ==
-        NS_STYLE_OVERFLOW_CLIP_BOX_PADDING_BOX) {
+  auto* disp = aFrame->StyleDisplay();
+  if (disp->mOverflowClipBoxBlock == NS_STYLE_OVERFLOW_CLIP_BOX_PADDING_BOX &&
+      disp->mOverflowClipBoxInline == NS_STYLE_OVERFLOW_CLIP_BOX_PADDING_BOX) {
     clipRect = aFrame->GetPaddingRectRelativeToSelf() +
       aBuilder->ToReferenceFrame(aFrame);
     haveRadii = aFrame->GetPaddingBoxBorderRadii(radii);
   } else {
-    clipRect = aFrame->GetContentRectRelativeToSelf() +
-      aBuilder->ToReferenceFrame(aFrame);
+    // Only deflate the padding if we clip to the content-box in that axis.
+    auto wm = aFrame->GetWritingMode();
+    bool cbH = (wm.IsVertical() ? disp->mOverflowClipBoxBlock
+                                : disp->mOverflowClipBoxInline) ==
+               NS_STYLE_OVERFLOW_CLIP_BOX_CONTENT_BOX;
+    bool cbV = (wm.IsVertical() ? disp->mOverflowClipBoxInline
+                                : disp->mOverflowClipBoxBlock) ==
+               NS_STYLE_OVERFLOW_CLIP_BOX_CONTENT_BOX;
+    nsMargin bp = aFrame->GetUsedPadding();
+    if (!cbH) {
+      bp.left = bp.right = nscoord(0);
+    }
+    if (!cbV) {
+      bp.top = bp.bottom = nscoord(0);
+    }
+
+    bp += aFrame->GetUsedBorder();
+    bp.ApplySkipSides(aFrame->GetSkipSides());
+    nsRect rect(nsPoint(0, 0), aFrame->GetSize());
+    rect.Deflate(bp);
+    clipRect = rect + aBuilder->ToReferenceFrame(aFrame);
     // XXX border-radius
   }
   aClipState.ClipContainingBlockDescendantsExtra(clipRect, haveRadii ? radii : nullptr);
   return true;
 }
 
 #ifdef DEBUG
 static void PaintDebugBorder(nsIFrame* aFrame, DrawTarget* aDrawTarget,
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -570,21 +570,32 @@ nsHTMLScrollFrame::ReflowScrolledFrame(S
   // setting their mOverflowArea. This is wrong because every frame should
   // always set mOverflowArea. In fact nsPluginFrame and nsFrameFrame don't
   // support the 'outline' property because of this. Rather than fix the world
   // right now, just fix up the overflow area if necessary. Note that we don't
   // check HasOverflowRect() because it could be set even though the
   // overflow area doesn't include the frame bounds.
   aMetrics->UnionOverflowAreasWithDesiredBounds();
 
-  if (MOZ_UNLIKELY(StyleDisplay()->mOverflowClipBox ==
+  auto* disp = StyleDisplay();
+  if (MOZ_UNLIKELY(disp->mOverflowClipBoxBlock ==
+                     NS_STYLE_OVERFLOW_CLIP_BOX_CONTENT_BOX ||
+                   disp->mOverflowClipBoxInline ==
                      NS_STYLE_OVERFLOW_CLIP_BOX_CONTENT_BOX)) {
     nsOverflowAreas childOverflow;
     nsLayoutUtils::UnionChildOverflow(mHelper.mScrolledFrame, childOverflow);
     nsRect childScrollableOverflow = childOverflow.ScrollableOverflow();
+    if (disp->mOverflowClipBoxBlock == NS_STYLE_OVERFLOW_CLIP_BOX_PADDING_BOX) {
+      padding.BStart(wm) = nscoord(0);
+      padding.BEnd(wm) = nscoord(0);
+    }
+    if (disp->mOverflowClipBoxInline == NS_STYLE_OVERFLOW_CLIP_BOX_PADDING_BOX) {
+      padding.IStart(wm) = nscoord(0);
+      padding.IEnd(wm) = nscoord(0);
+    }
     childScrollableOverflow.Inflate(padding.GetPhysicalMargin(wm));
     nsRect contentArea =
       wm.IsVertical() ? nsRect(0, 0, computedBSize, availISize)
                       : nsRect(0, 0, availISize, computedBSize);
     if (!contentArea.Contains(childScrollableOverflow)) {
       aMetrics->mOverflowAreas.ScrollableOverflow() = childScrollableOverflow;
     }
   }
@@ -3453,25 +3464,41 @@ ScrollFrameHelper::BuildDisplayList(nsDi
   if (disp && (disp->mWillChangeBitField & NS_STYLE_WILL_CHANGE_SCROLL)) {
     aBuilder->AddToWillChangeBudget(mOuter, GetScrollPositionClampingScrollPortSize());
   }
 
   mScrollParentID = aBuilder->GetCurrentScrollParentId();
 
   Maybe<nsRect> contentBoxClip;
   Maybe<const DisplayItemClipChain*> extraContentBoxClipForNonCaretContent;
-  if (MOZ_UNLIKELY(mOuter->StyleDisplay()->mOverflowClipBox ==
-                     NS_STYLE_OVERFLOW_CLIP_BOX_CONTENT_BOX)) {
+  if (MOZ_UNLIKELY(disp->mOverflowClipBoxBlock ==
+                     NS_STYLE_OVERFLOW_CLIP_BOX_CONTENT_BOX ||
+                   disp->mOverflowClipBoxInline ==
+                      NS_STYLE_OVERFLOW_CLIP_BOX_CONTENT_BOX)) {
+    WritingMode wm = mScrolledFrame->GetWritingMode();
+    bool cbH = (wm.IsVertical() ? disp->mOverflowClipBoxBlock
+                                : disp->mOverflowClipBoxInline) ==
+               NS_STYLE_OVERFLOW_CLIP_BOX_CONTENT_BOX;
+    bool cbV = (wm.IsVertical() ? disp->mOverflowClipBoxInline
+                                : disp->mOverflowClipBoxBlock) ==
+               NS_STYLE_OVERFLOW_CLIP_BOX_CONTENT_BOX;
     // We only clip if there is *scrollable* overflow, to avoid clipping
     // *visual* overflow unnecessarily.
     nsRect clipRect = mScrollPort + aBuilder->ToReferenceFrame(mOuter);
     nsRect so = mScrolledFrame->GetScrollableOverflowRect();
-    if (clipRect.width != so.width || clipRect.height != so.height ||
-        so.x < 0 || so.y < 0) {
-      clipRect.Deflate(mOuter->GetUsedPadding());
+    if ((cbH && (clipRect.width != so.width || so.x < 0)) ||
+        (cbV && (clipRect.height != so.height || so.y < 0))) {
+      nsMargin padding = mOuter->GetUsedPadding();
+      if (!cbH) {
+        padding.left = padding.right = nscoord(0);
+      }
+      if (!cbV) {
+        padding.top = padding.bottom = nscoord(0);
+      }
+      clipRect.Deflate(padding);
 
       // The non-inflated clip needs to be set on all non-caret items.
       // We prepare an extra DisplayItemClipChain here that will be intersected
       // with those items after they've been created.
       const ActiveScrolledRoot* asr = aBuilder->CurrentActiveScrolledRoot();
 
       DisplayItemClip newClip;
       newClip.SetTo(clipRect);
new file mode 100644
--- /dev/null
+++ b/layout/painting/crashtests/1418177-1.html
@@ -0,0 +1,34 @@
+<html>
+  <head>
+    <style>
+      * {
+        background: url(16.png), url(16.png) transparent;
+        -webkit-background-clip: text, text;
+        -moz-tab-size: calc(1 + 1) !important;
+        background-blend-mode: screen;
+        align-content: baseline;
+        background-color: green;
+      }
+    </style>
+    <script>
+      function fun_0() {
+        try { o3 = document.createElement('th') } catch (e) {};
+        try { o1.appendChild(o3) } catch (e) {}
+      }
+
+      try { o1 = document.createElement('tr') } catch (e) {}
+      try { o2 = document.createElement('ol') } catch (e) {}
+      try { xhr = new XMLHttpRequest({mozAnon: false }) } catch (e) {}
+      try { document.documentElement.appendChild(o1) } catch (e) {}
+      try { document.documentElement.appendChild(o2) } catch (e) {}
+      for (let i = 0; i < 100; i++) {
+        try { xhr.open('GET', 'data:text/html,1', false); } catch (e) {};
+        try { xhr.send(); } catch (e) {};
+        try { fuzzPriv.GC(); fuzzPriv.CC(); fuzzPriv.GC(); fuzzPriv.CC(); } catch (e) {};
+        try { xhr.addEventListener('readystatechange', fun_0, true) } catch (e) {};
+        try { o2.offsetLeft } catch (e) {};
+        try { document.styleSheets[0].cssRules[0].style['background-origin'] = 'border-box, border-box' } catch (e) {}
+      }
+    </script>
+  </head>
+</html>
--- a/layout/painting/crashtests/crashtests.list
+++ b/layout/painting/crashtests/crashtests.list
@@ -1,7 +1,8 @@
 load 1402183-1.html
 skip-if(!(stylo||styloVsGecko)||Android) load 1407470-1.html
 load 1413073-1.html
 load 1413073-2.html
 load 1405881-1.html
+load 1418177-1.html
 load 1418722-1.html
 load 1419917.html
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -3769,28 +3769,41 @@ nsDisplayBackgroundImage::AppendBackgrou
       thisItemList.AppendNewToTop(bgItem);
     }
 
     if (bg->mImage.mLayers[i].mBlendMode != NS_STYLE_BLEND_NORMAL) {
       DisplayListClipState::AutoSaveRestore blendClip(aBuilder);
       // asr is scrolled. Even if we wrap a fixed background layer, that's
       // fine, because the item will have a scrolled clip that limits the
       // item with respect to asr.
-      thisItemList.AppendNewToTop(
-        new (aBuilder) nsDisplayBlendMode(aBuilder, aFrame, &thisItemList,
-                                          bg->mImage.mLayers[i].mBlendMode,
-                                          asr, i + 1));
+      if (aSecondaryReferenceFrame) {
+        thisItemList.AppendNewToTop(
+          new (aBuilder) nsDisplayTableBlendMode(aBuilder, aSecondaryReferenceFrame, &thisItemList,
+                                                 bg->mImage.mLayers[i].mBlendMode,
+                                                 asr, i + 1, aFrame));
+      } else {
+        thisItemList.AppendNewToTop(
+          new (aBuilder) nsDisplayBlendMode(aBuilder, aFrame, &thisItemList,
+                                            bg->mImage.mLayers[i].mBlendMode,
+                                            asr, i + 1));
+      }
     }
     bgItemList.AppendToTop(&thisItemList);
   }
 
   if (needBlendContainer) {
     DisplayListClipState::AutoSaveRestore blendContainerClip(aBuilder);
-    bgItemList.AppendNewToTop(
-      nsDisplayBlendContainer::CreateForBackgroundBlendMode(aBuilder, aFrame, &bgItemList, asr));
+    if (aSecondaryReferenceFrame) {
+      bgItemList.AppendNewToTop(
+        nsDisplayTableBlendContainer::CreateForBackgroundBlendMode(aBuilder, aSecondaryReferenceFrame,
+                                                                   &bgItemList, asr, aFrame));
+    } else {
+      bgItemList.AppendNewToTop(
+        nsDisplayBlendContainer::CreateForBackgroundBlendMode(aBuilder, aFrame, &bgItemList, asr));
+    }
   }
 
   aList->AppendToTop(&bgItemList);
   return false;
 }
 
 // Check that the rounded border of aFrame, added to aToReferenceFrame,
 // intersects aRect.  Assumes that the unrounded border has already
@@ -6936,16 +6949,25 @@ nsDisplayBlendContainer::CreateWebRender
                                                  nsDisplayListBuilder* aDisplayListBuilder)
 {
   StackingContextHelper sc(aSc, aBuilder);
 
   return nsDisplayWrapList::CreateWebRenderCommands(aBuilder, aResources, sc,
                                                     aManager, aDisplayListBuilder);
 }
 
+/* static */ nsDisplayTableBlendContainer*
+nsDisplayTableBlendContainer::CreateForBackgroundBlendMode(nsDisplayListBuilder* aBuilder,
+                                                           nsIFrame* aFrame, nsDisplayList* aList,
+                                                           const ActiveScrolledRoot* aActiveScrolledRoot,
+                                                           nsIFrame* aAncestorFrame)
+{
+  return new (aBuilder) nsDisplayTableBlendContainer(aBuilder, aFrame, aList, aActiveScrolledRoot, true, aAncestorFrame);
+}
+
 nsDisplayOwnLayer::nsDisplayOwnLayer(nsDisplayListBuilder* aBuilder,
                                      nsIFrame* aFrame, nsDisplayList* aList,
                                      const ActiveScrolledRoot* aActiveScrolledRoot,
                                      nsDisplayOwnLayerFlags aFlags, ViewID aScrollTarget,
                                      const ScrollThumbData& aThumbData,
                                      bool aForceActive,
                                      bool aClearClipChain)
     : nsDisplayWrapList(aBuilder, aFrame, aList, aActiveScrolledRoot, aClearClipChain)
--- a/layout/painting/nsDisplayList.h
+++ b/layout/painting/nsDisplayList.h
@@ -5009,21 +5009,48 @@ public:
 
   virtual bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) override
   {
     return false;
   }
 
   NS_DISPLAY_DECL_NAME("BlendMode", TYPE_BLEND_MODE)
 
-private:
+protected:
   uint8_t mBlendMode;
   uint32_t mIndex;
 };
 
+class nsDisplayTableBlendMode : public nsDisplayBlendMode
+{
+public:
+  nsDisplayTableBlendMode(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
+                          nsDisplayList* aList, uint8_t aBlendMode,
+                          const ActiveScrolledRoot* aActiveScrolledRoot,
+                          uint32_t aIndex, nsIFrame* aAncestorFrame)
+    : nsDisplayBlendMode(aBuilder, aFrame, aList, aBlendMode, aActiveScrolledRoot, aIndex)
+    , mAncestorFrame(aAncestorFrame)
+    , mTableType(GetTableTypeFromFrame(aAncestorFrame))
+  { }
+
+  virtual nsIFrame* FrameForInvalidation() const override { return mAncestorFrame; }
+
+  virtual uint32_t GetPerFrameKey() const override {
+    return (mIndex << (TYPE_BITS + static_cast<uint8_t>(TableTypeBits::COUNT))) |
+           (static_cast<uint8_t>(mTableType) << TYPE_BITS) |
+           nsDisplayItem::GetPerFrameKey();
+  }
+
+  NS_DISPLAY_DECL_NAME("BlendMode", TYPE_BLEND_MODE)
+
+protected:
+  nsIFrame* mAncestorFrame;
+  TableType mTableType;
+};
+
 class nsDisplayBlendContainer : public nsDisplayWrapList {
 public:
     static nsDisplayBlendContainer*
     CreateForMixBlendMode(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
                           nsDisplayList* aList,
                           const ActiveScrolledRoot* aActiveScrolledRoot);
 
     static nsDisplayBlendContainer*
@@ -5065,32 +5092,64 @@ public:
     {
       return false;
     }
     virtual uint32_t GetPerFrameKey() const override {
       return (mIsForBackground ? 1 << TYPE_BITS : 0) | nsDisplayItem::GetPerFrameKey();
     }
     NS_DISPLAY_DECL_NAME("BlendContainer", TYPE_BLEND_CONTAINER)
 
-private:
+protected:
     nsDisplayBlendContainer(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
                             nsDisplayList* aList,
                             const ActiveScrolledRoot* aActiveScrolledRoot,
                             bool aIsForBackground);
     nsDisplayBlendContainer(nsDisplayListBuilder* aBuilder,
                             const nsDisplayBlendContainer& aOther)
       : nsDisplayWrapList(aBuilder, aOther)
       , mIsForBackground(aOther.mIsForBackground)
     {}
 
     // Used to distinguish containers created at building stacking
     // context or appending background.
     bool mIsForBackground;
 };
 
+class nsDisplayTableBlendContainer : public nsDisplayBlendContainer
+{
+public:
+  static nsDisplayTableBlendContainer*
+  CreateForBackgroundBlendMode(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
+                               nsDisplayList* aList,
+                               const ActiveScrolledRoot* aActiveScrolledRoot,
+                               nsIFrame* aAncestorFrame);
+  virtual nsIFrame* FrameForInvalidation() const override { return mAncestorFrame; }
+
+  virtual uint32_t GetPerFrameKey() const override {
+    return (static_cast<uint8_t>(mTableType) << TYPE_BITS) |
+           nsDisplayItem::GetPerFrameKey();
+  }
+
+  NS_DISPLAY_DECL_NAME("BlendContainer", TYPE_BLEND_CONTAINER)
+
+protected:
+  nsDisplayTableBlendContainer(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
+                               nsDisplayList* aList,
+                               const ActiveScrolledRoot* aActiveScrolledRoot,
+                               bool aIsForBackground, nsIFrame* aAncestorFrame)
+    : nsDisplayBlendContainer(aBuilder, aFrame, aList, aActiveScrolledRoot, aIsForBackground)
+    , mAncestorFrame(aAncestorFrame)
+    , mTableType(GetTableTypeFromFrame(aAncestorFrame))
+  { }
+
+  nsIFrame* mAncestorFrame;
+  TableType mTableType;
+};
+
+
 /**
  * nsDisplayOwnLayer constructor flags. If we nest this class inside
  * nsDisplayOwnLayer then we can't forward-declare it up at the top of this
  * file and that makes it hard to use in all the places that we need to use it.
  */
 enum class nsDisplayOwnLayerFlags {
   eNone = 0,
   eGenerateSubdocInvalidations = 1 << 0,
new file mode 100644
--- /dev/null
+++ b/layout/reftests/box-properties/overflow-clip-box-1-ref.html
@@ -0,0 +1,99 @@
+<!DOCTYPE HTML>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html><head>
+  <meta charset="utf-8">
+  <title>Reference: Testcase for bug 1422839</title>
+  <style type="text/css">
+html,body {
+  color:black; background-color:white; font:16px/1 monospace; line-height:1; padding:0; margin:0;
+}
+
+div {
+  width: 0;
+  height: 0;
+  white-space: pre;
+  overflow: hidden;
+  border: 1px solid;
+  width: 100px;
+  height: 100px;
+}
+.h > div { height: 120px; }
+.w > div { width: 120px; }
+
+c {
+  display: block;
+  width: 100px;
+  height: 40px;
+  border: 1px solid black;
+}
+
+.float { float: left; }
+
+x {
+  display: block;
+  overflow: hidden;
+  padding-left: 50px;
+  padding-top: 50px;
+  width: 50px;
+  height: 50px;
+}
+
+.w x { width: 20px; }
+.h x { height: 20px; }
+.w.h x {
+  background-color: lime;
+  background-clip: content-box;
+  overflow: visible;
+}
+y {
+  display: block;
+  overflow: hidden;
+  width: 20px;
+  height: 20px;
+}
+
+  </style>
+</head>
+<body>
+
+<span class="float">
+<div><x><c></c></x></div>
+<div></div>
+<div></div>
+<div></div>
+<div><x><c></c></x></div>
+<div></div>
+</span>
+
+<span class="float h">
+<div><x style="height:70px"><c></c></x></div>
+<div></div>
+<div></div>
+<div><x><c></c></x></div>
+<div><x style="height:70px"><c></c></x></div>
+<div></div>
+</span>
+
+<span class="float w">
+<div><x style="width:70px"><c></c></x></div>
+<div></div>
+<div><x><c></c></x></div>
+<div></div>
+<div><x style="width:70px"><c></c></x></div>
+<div></div>
+</span>
+
+<span class="float w h">
+<div><x><y style="height:70px; width:70px"><c></c></y></x></div>
+<div><x><y><c></c></y></x></div>
+<div><x><y style="height:70px"><c></c></y></x></div>
+<div><x><y style="width:70px"><c></c></y></x></div>
+<div><x><y style="height:70px; width:70px"><c></c></y></x></div>
+<div><x><y><c></c></y></x></div>
+</span>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/box-properties/overflow-clip-box-1.html
@@ -0,0 +1,76 @@
+<!DOCTYPE HTML>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html><head>
+  <meta charset="utf-8">
+  <title>Testcase for bug 1422839</title>
+  <style type="text/css">
+html,body {
+  color:black; background-color:white; font:16px/1 monospace; line-height:1; padding:0; margin:0;
+}
+
+div {
+  width: 0;
+  height: 0;
+  padding: 50px;
+  white-space: pre;
+  overflow: hidden;
+  background-color: lime;
+  background-clip: content-box;
+  border: 1px solid;
+}
+
+.float { float: left; }
+.w > div { width: 20px; }
+.h > div { height: 20px; }
+
+c {
+  display: block;
+  width: 100px;
+  height: 40px;
+  border: 1px solid black;
+}
+  </style>
+</head>
+<body>
+
+<span class="float">
+<div style="overflow-clip-box: padding-box"><c></c></div>
+<div style="overflow-clip-box: content-box"><c></c></div>
+<div style="overflow-clip-box: padding-box content-box"><c></c></div>
+<div style="overflow-clip-box: content-box padding-box"><c></c></div>
+<div style="overflow-clip-box: padding-box padding-box"><c></c></div>
+<div style="overflow-clip-box: content-box content-box"><c></c></div>
+</span>
+
+<span class="float h">
+<div style="overflow-clip-box: padding-box"><c></c></div>
+<div style="overflow-clip-box: content-box"><c></c></div>
+<div style="overflow-clip-box: padding-box content-box"><c></c></div>
+<div style="overflow-clip-box: content-box padding-box"><c></c></div>
+<div style="overflow-clip-box: padding-box padding-box"><c></c></div>
+<div style="overflow-clip-box: content-box content-box"><c></c></div>
+</span>
+
+<span class="float w">
+<div style="overflow-clip-box: padding-box"><c></c></div>
+<div style="overflow-clip-box: content-box"><c></c></div>
+<div style="overflow-clip-box: padding-box content-box"><c></c></div>
+<div style="overflow-clip-box: content-box padding-box"><c></c></div>
+<div style="overflow-clip-box: padding-box padding-box"><c></c></div>
+<div style="overflow-clip-box: content-box content-box"><c></c></div>
+</span>
+
+<span class="float w h">
+<div style="overflow-clip-box: padding-box"><c></c></div>
+<div style="overflow-clip-box: content-box"><c></c></div>
+<div style="overflow-clip-box: padding-box content-box"><c></c></div>
+<div style="overflow-clip-box: content-box padding-box"><c></c></div>
+<div style="overflow-clip-box: padding-box padding-box"><c></c></div>
+<div style="overflow-clip-box: content-box content-box"><c></c></div>
+</span>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/box-properties/overflow-clip-box-2-ref.html
@@ -0,0 +1,101 @@
+<!DOCTYPE HTML>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html><head>
+  <meta charset="utf-8">
+  <title>Reference: Testcase for bug 1422839</title>
+  <style type="text/css">
+html,body {
+  color:black; background-color:white; font:16px/1 monospace; line-height:1; padding:0; margin:0;
+}
+
+div {
+  width: 0;
+  height: 0;
+  white-space: pre;
+  overflow: hidden;
+  border: 1px solid;
+  width: 100px;
+  height: 100px;
+  direction: rtl;
+}
+.h > div { height: 120px; }
+.w > div { width: 120px; }
+
+c {
+  display: block;
+  width: 100px;
+  height: 40px;
+  border: 1px solid black;
+  margin-top: -10px;
+}
+
+.float { float: left; }
+
+x {
+  display: block;
+  overflow: hidden;
+  padding-right: 50px;
+  padding-top: 50px;
+  width: 50px;
+  height: 50px;
+}
+
+.w x { width: 20px; }
+.h x { height: 20px; }
+.w.h x {
+  background-color: lime;
+  background-clip: content-box;
+  overflow: visible;
+}
+y {
+  display: block;
+  overflow: hidden;
+  width: 20px;
+  height: 20px;
+}
+
+  </style>
+</head>
+<body>
+
+<span class="float">
+<div><x><c></c></x></div>
+<div></div>
+<div></div>
+<div></div>
+<div><x><c></c></x></div>
+<div></div>
+</span>
+
+<span class="float h">
+<div><x style="height:70px"><c></c></x></div>
+<div></div>
+<div></div>
+<div><x style="height:20px"><c style="margin:0; border-top-width:0"></c></x></div>
+<div><x style="height:70px"><c></c></x></div>
+<div></div>
+</span>
+
+<span class="float w">
+<div><x style="width:70px"><c></c></x></div>
+<div></div>
+<div><x><c></c></x></div>
+<div></div>
+<div><x style="width:70px"><c></c></x></div>
+<div></div>
+</span>
+
+<span class="float w h">
+<div><x><y style="height:70px; width:70px; margin-top:-10px"><c style="margin-top:0px"></c></y></x></div>
+<div><x><y><c></c></y></x></div>
+<div><x><y style="height:70px; margin-top:-10px"><c style="margin-top:0px"></c></y></x></div>
+<div><x><y style="width:70px"><c></c></y></x></div>
+<div><x><y style="height:70px; width:70px; margin-top:-10px"><c style="margin-top:0px"></c></y></x></div>
+<div><x><y><c></c></y></x></div>
+</span>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/box-properties/overflow-clip-box-2.html
@@ -0,0 +1,78 @@
+<!DOCTYPE HTML>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html><head>
+  <meta charset="utf-8">
+  <title>Testcase for bug 1422839</title>
+  <style type="text/css">
+html,body {
+  color:black; background-color:white; font:16px/1 monospace; line-height:1; padding:0; margin:0;
+}
+
+div {
+  width: 0;
+  height: 0;
+  padding: 50px;
+  white-space: pre;
+  overflow: hidden;
+  background-color: lime;
+  background-clip: content-box;
+  border: 1px solid;
+  direction: rtl;
+}
+
+.float { float: left; }
+.w > div { width: 20px; }
+.h > div { height: 20px; }
+
+c {
+  display: block;
+  width: 100px;
+  height: 40px;
+  border: 1px solid black;
+  margin-top: -10px;
+}
+  </style>
+</head>
+<body>
+
+<span class="float">
+<div style="overflow-clip-box: padding-box"><c></c></div>
+<div style="overflow-clip-box: content-box"><c></c></div>
+<div style="overflow-clip-box: padding-box content-box"><c></c></div>
+<div style="overflow-clip-box: content-box padding-box"><c></c></div>
+<div style="overflow-clip-box: padding-box padding-box"><c></c></div>
+<div style="overflow-clip-box: content-box content-box"><c></c></div>
+</span>
+
+<span class="float h">
+<div style="overflow-clip-box: padding-box"><c></c></div>
+<div style="overflow-clip-box: content-box"><c></c></div>
+<div style="overflow-clip-box: padding-box content-box"><c></c></div>
+<div style="overflow-clip-box: content-box padding-box"><c></c></div>
+<div style="overflow-clip-box: padding-box padding-box"><c></c></div>
+<div style="overflow-clip-box: content-box content-box"><c></c></div>
+</span>
+
+<span class="float w">
+<div style="overflow-clip-box: padding-box"><c></c></div>
+<div style="overflow-clip-box: content-box"><c></c></div>
+<div style="overflow-clip-box: padding-box content-box"><c></c></div>
+<div style="overflow-clip-box: content-box padding-box"><c></c></div>
+<div style="overflow-clip-box: padding-box padding-box"><c></c></div>
+<div style="overflow-clip-box: content-box content-box"><c></c></div>
+</span>
+
+<span class="float w h">
+<div style="overflow-clip-box: padding-box"><c></c></div>
+<div style="overflow-clip-box: content-box"><c></c></div>
+<div style="overflow-clip-box: padding-box content-box"><c></c></div>
+<div style="overflow-clip-box: content-box padding-box"><c></c></div>
+<div style="overflow-clip-box: padding-box padding-box"><c></c></div>
+<div style="overflow-clip-box: content-box content-box"><c></c></div>
+</span>
+
+</body>
+</html>
--- a/layout/reftests/box-properties/reftest.list
+++ b/layout/reftests/box-properties/reftest.list
@@ -23,8 +23,10 @@
 == abspos-replaced-width-offset-margin.html abspos-replaced-width-offset-margin-ref.html
 == CSS21-t100301.xhtml CSS21-t100301-ref.xhtml
 == CSS21-t100303.xhtml CSS21-t100303-ref.xhtml
 == CSS21-t100303-simple.xhtml CSS21-t100303-ref.xhtml
 == CSS21-t100801-vertical-align.xhtml CSS21-t100801-vertical-align-ref.xhtml
 == clip-auto.html clip-auto-ref.html
 == clip-rect-auto.html clip-rect-auto-ref.html
 == width-rounding.html width-rounding-ref.html
+pref(layout.css.overflow-clip-box.enabled,true) == overflow-clip-box-1.html overflow-clip-box-1-ref.html
+pref(layout.css.overflow-clip-box.enabled,true) == overflow-clip-box-2.html overflow-clip-box-2-ref.html
new file mode 100644
--- /dev/null
+++ b/layout/reftests/table-bordercollapse/bug1405929-2-ref.html
@@ -0,0 +1,35 @@
+<!DOCTYPE HTML>
+<title>Bug 1405929 reftest reference</title>
+<style>
+
+table {
+  border-collapse: collapse;
+  display: inline-table;
+  vertical-align: top;
+  margin: 20px;
+  width: 20px;
+}
+
+td {
+  background: green border-box;
+  padding: 20px;
+  width: 10px;
+}
+
+.bb {
+  border-bottom: 5px dashed fuchsia;
+}
+
+</style>
+
+<table>
+  <tbody>
+    <tr>
+      <td>
+      <td>
+    <tr>
+      <td colspan="2" class=bb>
+    <tr>
+      <td colspan="2">
+  </tbody>
+</table>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/table-bordercollapse/bug1405929-2.html
@@ -0,0 +1,35 @@
+<!DOCTYPE HTML>
+<title>Bug 1405929 reftest</title>
+<style>
+
+table {
+  border-collapse: collapse;
+  display: inline-table;
+  vertical-align: top;
+  margin: 20px;
+  width: 20px;
+}
+
+td {
+  background: green border-box;
+  padding: 20px;
+  width: 10px;
+}
+
+.bb {
+  border-bottom: 5px dashed fuchsia;
+}
+
+</style>
+
+<table>
+  <tbody>
+    <tr>
+      <td>
+      <td rowspan="2" class=bb>
+    <tr>
+      <td class=bb>
+    <tr>
+      <td colspan="2">
+  </tbody>
+</table>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/table-bordercollapse/bug1405929-ref.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Bug 1405929 reftest reference</title>
+<style type="text/css">
+table { border-collapse: collapse; }
+td    { padding-left: 1em; }
+td:first-child {
+  border-bottom: 1px solid black;
+}
+.x {
+  border-bottom: 1px solid black;
+}
+</style>
+
+</head>
+<body>
+<table>
+  <tr> <td>1 </td> <td class="x" rowspan="2">Spans 1-2</td>   </tr>
+  <tr> <td>2 </td>                                            </tr>
+  <tr> <td>3 </td> <td class="x" rowspan="3">Spans 3-5</td>   </tr>
+  <tr> <td>4 </td>                                            </tr>
+  <tr> <td>5 </td>                                            </tr>
+  <tr> <td>6 </td> <td class="x">Nospan</td>                  </tr>
+  <tr> <td>7 </td> <td class="x" rowspan="2">Spans 7-8</td>   </tr>
+  <tr> <td>8 </td>                                            </tr>
+  <tr> <td>9 </td> <td></td>                                  </tr>
+  <tr> <td>10</td> <td class="x"></td>                        </tr>
+  <tr> <td>11</td> <td class="x" rowspan="4">Spans 11-14</td> </tr>
+  <tr> <td>12</td>                                            </tr>
+  <tr> <td>13</td>                                            </tr>
+  <tr> <td>14</td>                                            </tr>
+  <tr> <td>13</td> <td class="x">Nospan</td>                  </tr>
+</table>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/table-bordercollapse/bug1405929.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<head>
+<title>Bug 1405929 reftest</title>
+<style type="text/css">
+table { border-collapse: collapse; }
+tr    { border-bottom: 1px solid black; }
+td    { padding-left: 1em; }
+</style>
+
+</head>
+<body>
+
+<table>
+  <tr> <td>1 </td> <td rowspan="2">Spans 1-2  </td> </tr>
+  <tr> <td>2 </td>                                  </tr>
+  <tr> <td>3 </td> <td rowspan="3">Spans 3-5  </td> </tr>
+  <tr> <td>4 </td>                                  </tr>
+  <tr> <td>5 </td>                                  </tr>
+  <tr> <td>6 </td> <td>            Nospan     </td> </tr>
+  <tr> <td>7 </td> <td rowspan="2">Spans 7-8  </td> </tr>
+  <tr> <td>8 </td>                                  </tr>
+  <tr> <td>9 </td> <td rowspan="2"></td>            </tr>
+  <tr> <td>10</td>                                  </tr>
+  <tr> <td>11</td> <td rowspan="4">Spans 11-14</td> </tr>
+  <tr> <td>12</td>                                  </tr>
+  <tr> <td>13</td>                                  </tr>
+  <tr> <td>14</td>                                  </tr>
+  <tr> <td>13</td> <td>            Nospan     </td> </tr>
+</table>
+
+</body>
+</html>
+
+
--- a/layout/reftests/table-bordercollapse/reftest.list
+++ b/layout/reftests/table-bordercollapse/reftest.list
@@ -1,16 +1,18 @@
 == bug1375518.html bug1375518-ref.html
 == bug1375518-2.html bug1375518-ref.html
 == bug1375518-3.html bug1375518-ref.html
 == bug1375518-4.html bug1375518-4-ref.html
 == bug1375518-5.html bug1375518-5-ref.html
 == bug1379306.html bug1379306-ref.html
 == bug1394226.html bug1394226-ref.html
 != bug1394226.html bug1394226-notref.html
+== bug1405929.html bug1405929-ref.html
+== bug1405929-2.html bug1405929-2-ref.html
 == bc_dyn_cell1.html bc_dyn_cell1_ref.html
 == bc_dyn_cell2.html bc_dyn_cell2_ref.html
 == bc_dyn_cell3.html bc_dyn_cell3_ref.html
 == bc_dyn_cell4.html bc_dyn_cell4_ref.html
 == bc_dyn_cell5.html bc_dyn_cell5_ref.html
 == bc_dyn_row1.html bc_dyn_rg1_ref.html
 == bc_dyn_row2.html bc_dyn_rg2_ref.html
 == bc_dyn_row3.html bc_dyn_rg3_ref.html
--- a/layout/style/Declaration.cpp
+++ b/layout/style/Declaration.cpp
@@ -1409,16 +1409,17 @@ Declaration::GetPropertyValueInternal(
       const nsCSSValue* align = data->ValueFor(subprops[0]);
       const nsCSSValue* justify = data->ValueFor(subprops[1]);
       if (!align || !IsSingleValue(*align) ||
           !justify || !IsSingleValue(*justify)) {
         return; // Not serializable, bail.
       }
       MOZ_FALLTHROUGH;
     }
+    case eCSSProperty_overflow_clip_box:
     case eCSSProperty_grid_gap: {
       const nsCSSPropertyID* subprops =
         nsCSSProps::SubpropertyEntryFor(aProperty);
       MOZ_ASSERT(subprops[2] == eCSSProperty_UNKNOWN,
                  "must have exactly two subproperties");
 
       nsAutoString val1, val2;
       AppendValueToString(subprops[0], val1);
--- a/layout/style/nsCSSParser.cpp
+++ b/layout/style/nsCSSParser.cpp
@@ -932,16 +932,17 @@ protected:
   bool ParseListStyleType(nsCSSValue& aValue);
   bool ParseMargin();
   bool ParseClipPath(nsCSSValue& aValue);
   bool ParseTransform(bool aIsPrefixed, nsCSSPropertyID aProperty,
                       bool aDisallowRelativeValues = false);
   bool ParseObjectPosition();
   bool ParseOutline();
   bool ParseOverflow();
+  bool ParseOverflowClipBox();
   bool ParsePadding();
   bool ParseQuotes();
   bool ParseTextAlign(nsCSSValue& aValue,
                       const KTableEntry aTable[]);
   bool ParseTextAlign(nsCSSValue& aValue);
   bool ParseTextAlignLast(nsCSSValue& aValue);
   bool ParseTextDecoration();
   bool ParseTextDecorationLine(nsCSSValue& aValue);
@@ -11769,16 +11770,18 @@ CSSParserImpl::ParsePropertyByFunction(n
   case eCSSProperty_margin:
     return ParseMargin();
   case eCSSProperty_object_position:
     return ParseObjectPosition();
   case eCSSProperty_outline:
     return ParseOutline();
   case eCSSProperty_overflow:
     return ParseOverflow();
+  case eCSSProperty_overflow_clip_box:
+    return ParseOverflowClipBox();
   case eCSSProperty_padding:
     return ParsePadding();
   case eCSSProperty_quotes:
     return ParseQuotes();
   case eCSSProperty_text_decoration:
     return ParseTextDecoration();
   case eCSSProperty_text_emphasis:
     return ParseTextEmphasis();
@@ -15340,16 +15343,41 @@ CSSParserImpl::ParseOverflow()
         break;
     }
   AppendValue(eCSSProperty_overflow_x, overflowX);
   AppendValue(eCSSProperty_overflow_y, overflowY);
   return true;
 }
 
 bool
+CSSParserImpl::ParseOverflowClipBox()
+{
+  nsCSSValue first;
+  if (ParseSingleTokenVariant(first, VARIANT_INHERIT, nullptr)) {
+    AppendValue(eCSSProperty_overflow_clip_box_block, first);
+    AppendValue(eCSSProperty_overflow_clip_box_inline, first);
+    return true;
+  }
+  const auto& kTable = nsCSSProps::kOverflowClipBoxKTable;
+  auto result = ParseVariant(first, VARIANT_KEYWORD, kTable);
+  if (result != CSSParseResult::Ok) {
+    return false;
+  }
+  nsCSSValue second;
+  result = ParseVariant(second, VARIANT_KEYWORD, kTable);
+  if (result == CSSParseResult::Error) {
+    return false;
+  }
+  AppendValue(eCSSProperty_overflow_clip_box_block, first);
+  AppendValue(eCSSProperty_overflow_clip_box_inline,
+              result == CSSParseResult::NotFound ? first : second);
+  return true;
+}
+
+bool
 CSSParserImpl::ParsePadding()
 {
   static const nsCSSPropertyID kPaddingSideIDs[] = {
     eCSSProperty_padding_top,
     eCSSProperty_padding_right,
     eCSSProperty_padding_bottom,
     eCSSProperty_padding_left
   };
--- a/layout/style/nsCSSPropList.h
+++ b/layout/style/nsCSSPropList.h
@@ -3259,20 +3259,40 @@ CSS_PROP_OUTLINE(
     offsetof(nsStyleOutline, mOutlineWidth),
     eStyleAnimType_nscoord)
 CSS_PROP_SHORTHAND(
     overflow,
     overflow,
     Overflow,
     CSS_PROPERTY_PARSE_FUNCTION,
     "")
-CSS_PROP_DISPLAY(
+CSS_PROP_SHORTHAND(
     overflow-clip-box,
     overflow_clip_box,
     OverflowClipBox,
+    CSS_PROPERTY_PARSE_FUNCTION |
+        CSS_PROPERTY_ENABLED_IN_UA_SHEETS |
+        CSS_PROPERTY_APPLIES_TO_PLACEHOLDER,
+    "layout.css.overflow-clip-box.enabled")
+CSS_PROP_DISPLAY(
+    overflow-clip-box-block,
+    overflow_clip_box_block,
+    OverflowClipBoxBlock,
+    CSS_PROPERTY_PARSE_VALUE |
+        CSS_PROPERTY_ENABLED_IN_UA_SHEETS |
+        CSS_PROPERTY_APPLIES_TO_PLACEHOLDER,
+    "layout.css.overflow-clip-box.enabled",
+    VARIANT_HK,
+    kOverflowClipBoxKTable,
+    CSS_PROP_NO_OFFSET,
+    eStyleAnimType_Discrete)
+CSS_PROP_DISPLAY(
+    overflow-clip-box-inline,
+    overflow_clip_box_inline,
+    OverflowClipBoxInline,
     CSS_PROPERTY_PARSE_VALUE |
         CSS_PROPERTY_ENABLED_IN_UA_SHEETS |
         CSS_PROPERTY_APPLIES_TO_PLACEHOLDER,
     "layout.css.overflow-clip-box.enabled",
     VARIANT_HK,
     kOverflowClipBoxKTable,
     CSS_PROP_NO_OFFSET,
     eStyleAnimType_Discrete)
--- a/layout/style/nsCSSProps.cpp
+++ b/layout/style/nsCSSProps.cpp
@@ -2925,16 +2925,22 @@ static const nsCSSPropertyID gGridGapSub
 };
 
 static const nsCSSPropertyID gOverflowSubpropTable[] = {
   eCSSProperty_overflow_x,
   eCSSProperty_overflow_y,
   eCSSProperty_UNKNOWN
 };
 
+static const nsCSSPropertyID gOverflowClipBoxSubpropTable[] = {
+  eCSSProperty_overflow_clip_box_block,
+  eCSSProperty_overflow_clip_box_inline,
+  eCSSProperty_UNKNOWN
+};
+
 static const nsCSSPropertyID gPaddingSubpropTable[] = {
   // Code relies on these being in top-right-bottom-left order.
   eCSSProperty_padding_top,
   eCSSProperty_padding_right,
   eCSSProperty_padding_bottom,
   eCSSProperty_padding_left,
   eCSSProperty_UNKNOWN
 };
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -5132,21 +5132,31 @@ nsComputedDOMStyle::DoGetOverflowY()
   RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(
     nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mOverflowY,
                                    nsCSSProps::kOverflowSubKTable));
   return val.forget();
 }
 
 already_AddRefed<CSSValue>
-nsComputedDOMStyle::DoGetOverflowClipBox()
+nsComputedDOMStyle::DoGetOverflowClipBoxBlock()
 {
   RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(
-    nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mOverflowClipBox,
+    nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mOverflowClipBoxBlock,
+                                   nsCSSProps::kOverflowClipBoxKTable));
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetOverflowClipBoxInline()
+{
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+  val->SetIdent(
+    nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mOverflowClipBoxInline,
                                    nsCSSProps::kOverflowClipBoxKTable));
   return val.forget();
 }
 
 already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetResize()
 {
   RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
--- a/layout/style/nsComputedDOMStyle.h
+++ b/layout/style/nsComputedDOMStyle.h
@@ -496,17 +496,18 @@ private:
   already_AddRefed<CSSValue> DoGetContain();
   already_AddRefed<CSSValue> DoGetPosition();
   already_AddRefed<CSSValue> DoGetClip();
   already_AddRefed<CSSValue> DoGetImageOrientation();
   already_AddRefed<CSSValue> DoGetWillChange();
   already_AddRefed<CSSValue> DoGetOverflow();
   already_AddRefed<CSSValue> DoGetOverflowX();
   already_AddRefed<CSSValue> DoGetOverflowY();
-  already_AddRefed<CSSValue> DoGetOverflowClipBox();
+  already_AddRefed<CSSValue> DoGetOverflowClipBoxBlock();
+  already_AddRefed<CSSValue> DoGetOverflowClipBoxInline();
   already_AddRefed<CSSValue> DoGetResize();
   already_AddRefed<CSSValue> DoGetPageBreakAfter();
   already_AddRefed<CSSValue> DoGetPageBreakBefore();
   already_AddRefed<CSSValue> DoGetPageBreakInside();
   already_AddRefed<CSSValue> DoGetTouchAction();
   already_AddRefed<CSSValue> DoGetTransform();
   already_AddRefed<CSSValue> DoGetTransformBox();
   already_AddRefed<CSSValue> DoGetTransformOrigin();
--- a/layout/style/nsComputedDOMStylePropertyList.h
+++ b/layout/style/nsComputedDOMStylePropertyList.h
@@ -194,17 +194,18 @@ COMPUTED_STYLE_PROP(opacity,            
 // COMPUTED_STYLE_PROP(orphans,                    Orphans)
 //// COMPUTED_STYLE_PROP(outline,                  Outline)
 COMPUTED_STYLE_PROP(order,                         Order)
 COMPUTED_STYLE_PROP(outline_color,                 OutlineColor)
 COMPUTED_STYLE_PROP(outline_offset,                OutlineOffset)
 COMPUTED_STYLE_PROP(outline_style,                 OutlineStyle)
 COMPUTED_STYLE_PROP(outline_width,                 OutlineWidth)
 COMPUTED_STYLE_PROP(overflow,                      Overflow)
-COMPUTED_STYLE_PROP(overflow_clip_box,             OverflowClipBox)
+COMPUTED_STYLE_PROP(overflow_clip_box_block,       OverflowClipBoxBlock)
+COMPUTED_STYLE_PROP(overflow_clip_box_inline,      OverflowClipBoxInline)
 COMPUTED_STYLE_PROP(overflow_wrap,                 OverflowWrap)
 COMPUTED_STYLE_PROP(overflow_x,                    OverflowX)
 COMPUTED_STYLE_PROP(overflow_y,                    OverflowY)
 COMPUTED_STYLE_PROP(overscroll_behavior_x,         OverscrollBehaviorX)
 COMPUTED_STYLE_PROP(overscroll_behavior_y,         OverscrollBehaviorY)
 //// COMPUTED_STYLE_PROP(padding,                  Padding)
 COMPUTED_STYLE_PROP(padding_bottom,                PaddingBottom)
 COMPUTED_STYLE_PROP(padding_left,                  PaddingLeft)
--- a/layout/style/nsRuleNode.cpp
+++ b/layout/style/nsRuleNode.cpp
@@ -6138,20 +6138,27 @@ nsRuleNode::ComputeDisplayData(void* aSt
       conditions.SetUncacheable();
     }
     if (display->mOverflowY == NS_STYLE_OVERFLOW_VISIBLE) {
       display->mOverflowY = NS_STYLE_OVERFLOW_CLIP;
       conditions.SetUncacheable();
     }
   }
 
-  SetValue(*aRuleData->ValueForOverflowClipBox(), display->mOverflowClipBox,
+  SetValue(*aRuleData->ValueForOverflowClipBoxBlock(),
+           display->mOverflowClipBoxBlock,
            conditions,
            SETVAL_ENUMERATED | SETVAL_UNSET_INITIAL,
-           parentDisplay->mOverflowClipBox,
+           parentDisplay->mOverflowClipBoxBlock,
+           NS_STYLE_OVERFLOW_CLIP_BOX_PADDING_BOX);
+  SetValue(*aRuleData->ValueForOverflowClipBoxInline(),
+           display->mOverflowClipBoxInline,
+           conditions,
+           SETVAL_ENUMERATED | SETVAL_UNSET_INITIAL,
+           parentDisplay->mOverflowClipBoxInline,
            NS_STYLE_OVERFLOW_CLIP_BOX_PADDING_BOX);
 
   SetValue(*aRuleData->ValueForResize(), display->mResize, conditions,
            SETVAL_ENUMERATED | SETVAL_UNSET_INITIAL,
            parentDisplay->mResize,
            NS_STYLE_RESIZE_NONE);
 
   if (display->mDisplay != StyleDisplay::None) {
--- a/layout/style/nsStyleStruct.cpp
+++ b/layout/style/nsStyleStruct.cpp
@@ -3573,17 +3573,18 @@ nsStyleDisplay::nsStyleDisplay(const nsP
   , mFloat(StyleFloat::None)
   , mOriginalFloat(StyleFloat::None)
   , mBreakType(StyleClear::None)
   , mBreakInside(NS_STYLE_PAGE_BREAK_AUTO)
   , mBreakBefore(false)
   , mBreakAfter(false)
   , mOverflowX(NS_STYLE_OVERFLOW_VISIBLE)
   , mOverflowY(NS_STYLE_OVERFLOW_VISIBLE)
-  , mOverflowClipBox(NS_STYLE_OVERFLOW_CLIP_BOX_PADDING_BOX)
+  , mOverflowClipBoxBlock(NS_STYLE_OVERFLOW_CLIP_BOX_PADDING_BOX)
+  , mOverflowClipBoxInline(NS_STYLE_OVERFLOW_CLIP_BOX_PADDING_BOX)
   , mResize(NS_STYLE_RESIZE_NONE)
   , mOrient(StyleOrient::Inline)
   , mIsolation(NS_STYLE_ISOLATION_AUTO)
   , mTopLayer(NS_STYLE_TOP_LAYER_NONE)
   , mWillChangeBitField(0)
   , mTouchAction(NS_STYLE_TOUCH_ACTION_AUTO)
   , mScrollBehavior(NS_STYLE_SCROLL_BEHAVIOR_AUTO)
   , mOverscrollBehaviorX(StyleOverscrollBehavior::Auto)
@@ -3637,17 +3638,18 @@ nsStyleDisplay::nsStyleDisplay(const nsS
   , mFloat(aSource.mFloat)
   , mOriginalFloat(aSource.mOriginalFloat)
   , mBreakType(aSource.mBreakType)
   , mBreakInside(aSource.mBreakInside)
   , mBreakBefore(aSource.mBreakBefore)
   , mBreakAfter(aSource.mBreakAfter)
   , mOverflowX(aSource.mOverflowX)
   , mOverflowY(aSource.mOverflowY)
-  , mOverflowClipBox(aSource.mOverflowClipBox)
+  , mOverflowClipBoxBlock(aSource.mOverflowClipBoxBlock)
+  , mOverflowClipBoxInline(aSource.mOverflowClipBoxInline)
   , mResize(aSource.mResize)
   , mOrient(aSource.mOrient)
   , mIsolation(aSource.mIsolation)
   , mTopLayer(aSource.mTopLayer)
   , mWillChangeBitField(aSource.mWillChangeBitField)
   , mWillChange(aSource.mWillChange)
   , mTouchAction(aSource.mTouchAction)
   , mScrollBehavior(aSource.mScrollBehavior)
@@ -3820,17 +3822,18 @@ nsStyleDisplay::CalcDifference(const nsS
   // XXX the following is conservative, for now: changing float breaking shouldn't
   // necessarily require a repaint, reflow should suffice.
   if (mBreakType != aNewData.mBreakType
       || mBreakInside != aNewData.mBreakInside
       || mBreakBefore != aNewData.mBreakBefore
       || mBreakAfter != aNewData.mBreakAfter
       || mAppearance != aNewData.mAppearance
       || mOrient != aNewData.mOrient
-      || mOverflowClipBox != aNewData.mOverflowClipBox) {
+      || mOverflowClipBoxBlock != aNewData.mOverflowClipBoxBlock
+      || mOverflowClipBoxInline != aNewData.mOverflowClipBoxInline) {
     hint |= nsChangeHint_AllReflowHints |
             nsChangeHint_RepaintFrame;
   }
 
   if (mIsolation != aNewData.mIsolation) {
     hint |= nsChangeHint_RepaintFrame;
   }
 
--- a/layout/style/nsStyleStruct.h
+++ b/layout/style/nsStyleStruct.h
@@ -2557,17 +2557,18 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsSt
   mozilla::StyleFloat mOriginalFloat;
 
   mozilla::StyleClear mBreakType;  // [reset]
   uint8_t mBreakInside;         // [reset] NS_STYLE_PAGE_BREAK_AUTO/AVOID
   bool mBreakBefore;    // [reset]
   bool mBreakAfter;     // [reset]
   uint8_t mOverflowX;           // [reset] see nsStyleConsts.h
   uint8_t mOverflowY;           // [reset] see nsStyleConsts.h
-  uint8_t mOverflowClipBox;     // [reset] see nsStyleConsts.h
+  uint8_t mOverflowClipBoxBlock;     // [reset] see nsStyleConsts.h
+  uint8_t mOverflowClipBoxInline;    // [reset] see nsStyleConsts.h
   uint8_t mResize;              // [reset] see nsStyleConsts.h
   mozilla::StyleOrient mOrient; // [reset] see nsStyleConsts.h
   uint8_t mIsolation;           // [reset] see nsStyleConsts.h
   uint8_t mTopLayer;            // [reset] see nsStyleConsts.h
   uint8_t mWillChangeBitField;  // [reset] see nsStyleConsts.h. Stores a
                                 // bitfield representation of the properties
                                 // that are frequently queried. This should
                                 // match mWillChange. Also tracks if any of the
--- a/layout/style/test/property_database.js
+++ b/layout/style/test/property_database.js
@@ -7405,24 +7405,44 @@ if (IsCSSPropertyPrefEnabled("layout.css
     initial_values: [ "normal" ],
     other_values: [ "multiply", "screen", "overlay", "darken", "lighten", "color-dodge", "color-burn",
       "hard-light", "soft-light", "difference", "exclusion", "hue", "saturation", "color", "luminosity" ],
     invalid_values: ["none", "10px", "multiply multiply"]
   };
 }
 
 if (IsCSSPropertyPrefEnabled("layout.css.overflow-clip-box.enabled")) {
-  gCSSProperties["overflow-clip-box"] = {
-    domProp: "overflowClipBox",
+  gCSSProperties["overflow-clip-box-block"] = {
+    domProp: "overflowClipBoxBlock",
     inherited: false,
     type: CSS_TYPE_LONGHAND,
     applies_to_placeholder: true,
     initial_values: [ "padding-box" ],
     other_values: [ "content-box" ],
-    invalid_values: [ "none", "auto", "border-box", "0" ]
+    invalid_values: [ "auto", "border-box", "0", "padding-box padding-box" ]
+  };
+  gCSSProperties["overflow-clip-box-inline"] = {
+    domProp: "overflowClipBoxInline",
+    inherited: false,
+    type: CSS_TYPE_LONGHAND,
+    applies_to_placeholder: true,
+    initial_values: [ "padding-box" ],
+    other_values: [ "content-box" ],
+    invalid_values: [ "none", "border-box", "0", "content-box content-box" ]
+  };
+  gCSSProperties["overflow-clip-box"] = {
+    domProp: "overflowClipBox",
+    inherited: false,
+    type: CSS_TYPE_TRUE_SHORTHAND,
+    subproperties: [ "overflow-clip-box-block", "overflow-clip-box-inline" ],
+    initial_values: [ "padding-box" ],
+    other_values: [ "content-box", "padding-box content-box", "content-box padding-box",
+                    "content-box content-box" ],
+    invalid_values: [ "none", "auto", "content-box none", "border-box", "0",
+                      "content-box, content-box" ]
   };
 }
 
 if (IsCSSPropertyPrefEnabled("layout.css.box-decoration-break.enabled")) {
   gCSSProperties["box-decoration-break"] = {
     domProp: "boxDecorationBreak",
     inherited: false,
     type: CSS_TYPE_LONGHAND,
--- a/layout/tables/nsTableFrame.cpp
+++ b/layout/tables/nsTableFrame.cpp
@@ -6448,22 +6448,24 @@ nsTableFrame::CalcBCBorders()
         //the last row in the row group, but only a cell with rowspan=1
         //will know whether *this* row is at the bEnd
         const nsIFrame* nextRowGroup =
           ajaInfo.mRgAtStart ? ajaInfo.mRowGroup : nullptr;
         info.SetInnerRowGroupBEndContBCBorder(nextRowGroup, ajaInfo.mStartRow);
         gotRowBorder = true;
       }
     }
-
-    // see if the cell to the iEnd side had a rowspan and its bEnd-iStart border
-    // needs be joined with this one's bEnd
-    // if  there is a cell to the iEnd and the cell to iEnd side was a rowspan
-    if ((info.mNumTableCols != info.GetCellEndColIndex() + 1) &&
-        (lastBEndBorders[info.GetCellEndColIndex() + 1].rowSpan > 1)) {
+    // In the function, we try to join two cells' BEnd.
+    // We normally do this work when processing the cell on the iEnd side,
+    // but when the cell on the iEnd side has a rowspan, the cell on the
+    // iStart side gets processed later (now), so we have to do this work now.
+    const auto nextColIndex = info.GetCellEndColIndex() + 1;
+    if ((info.mNumTableCols != nextColIndex) &&
+        (lastBEndBorders[nextColIndex].rowSpan > 1) &&
+        (lastBEndBorders[nextColIndex].rowIndex == info.GetCellEndRowIndex() + 1)) {
       BCCornerInfo& corner = bEndCorners[info.GetCellEndColIndex() + 1];
       if (!IsBlock(LogicalSide(corner.ownerSide))) {
         // not a block-dir owner
         BCCellBorder& thisBorder = lastBEndBorder;
         BCCellBorder& nextBorder = lastBEndBorders[info.mColIndex + 1];
         if ((thisBorder.color == nextBorder.color) &&
             (thisBorder.width == nextBorder.width) &&
             (thisBorder.style == nextBorder.style)) {
--- a/mozglue/build/WindowsDllBlocklist.cpp
+++ b/mozglue/build/WindowsDllBlocklist.cpp
@@ -255,16 +255,19 @@ static const DllBlockInfo sWindowsDllBlo
   { "klsihk64.dll", MAKE_VERSION(14, 0, 456, 0xffff), DllBlockInfo::BLOCK_WIN8_ONLY },
 
   // Bug 1407337, crashes with OpenSC < 0.16.0
   { "onepin-opensc-pkcs11.dll", MAKE_VERSION(0, 15, 0xffff, 0xffff) },
 
   // Avecto Privilege Guard causes crashes, bug 1385542
   { "pghook.dll", ALL_VERSIONS },
 
+  // Old versions of G DATA BankGuard, bug 1421991
+  { "banksafe64.dll", MAKE_VERSION(1, 2, 15299, 65535) },
+
   { nullptr, 0 }
 };
 
 #ifndef STATUS_DLL_NOT_FOUND
 #define STATUS_DLL_NOT_FOUND ((DWORD)0xC0000135L)
 #endif
 
 // define this for very verbose dll load debug spew
--- a/netwerk/protocol/http/nsHttpChannel.cpp
+++ b/netwerk/protocol/http/nsHttpChannel.cpp
@@ -4113,16 +4113,23 @@ nsHttpChannel::OnCacheEntryCheck(nsICach
                      "LOAD_BYPASS_LOCAL_CACHE_IF_BUSY specified"));
 
                 *aResult = ENTRY_NOT_WANTED;
                 return NS_OK;
             }
 
             // Ignore !(size > 0) from the resumability condition
             if (!IsResumable(size, contentLength, true)) {
+                if (IsNavigation()) {
+                    LOG(("  bypassing wait for the entry, "
+                         "this is a navigational load"));
+                    *aResult = ENTRY_NOT_WANTED;
+                    return NS_OK;
+                }
+
                 LOG(("  wait for entry completion, "
                      "response is not resumable"));
 
                 wantCompleteEntry = true;
             }
             else {
                 mConcurrentCacheAccess = 1;
             }
--- a/python/mozbuild/mozbuild/action/file_generate.py
+++ b/python/mozbuild/mozbuild/action/file_generate.py
@@ -18,30 +18,35 @@ from mozbuild.pythonutil import iter_mod
 from mozbuild.makeutil import Makefile
 from mozbuild.util import FileAvoidWrite
 import buildconfig
 
 
 def main(argv):
     parser = argparse.ArgumentParser('Generate a file from a Python script',
                                      add_help=False)
+    parser.add_argument('--locale', metavar='locale', type=str,
+                        help='The locale in use.')
     parser.add_argument('python_script', metavar='python-script', type=str,
                         help='The Python script to run')
     parser.add_argument('method_name', metavar='method-name', type=str,
                         help='The method of the script to invoke')
     parser.add_argument('output_file', metavar='output-file', type=str,
                         help='The file to generate')
     parser.add_argument('dep_file', metavar='dep-file', type=str,
                         help='File to write any additional make dependencies to')
     parser.add_argument('additional_arguments', metavar='arg',
                         nargs=argparse.REMAINDER,
                         help="Additional arguments to the script's main() method")
 
     args = parser.parse_args(argv)
 
+    kwargs = {}
+    if args.locale:
+        kwargs['locale'] = args.locale
     script = args.python_script
     # Permit the script to import modules from the same directory in which it
     # resides.  The justification for doing this is that if we were invoking
     # the script as:
     #
     #    python script arg1...
     #
     # then importing modules from the script's directory would come for free.
@@ -54,18 +59,18 @@ def main(argv):
     method = args.method_name
     if not hasattr(module, method):
         print('Error: script "{0}" is missing a {1} method'.format(script, method),
               file=sys.stderr)
         return 1
 
     ret = 1
     try:
-        with FileAvoidWrite(args.output_file) as output:
-            ret = module.__dict__[method](output, *args.additional_arguments)
+        with FileAvoidWrite(args.output_file, mode='rb') as output:
+            ret = module.__dict__[method](output, *args.additional_arguments, **kwargs)
             # The following values indicate a statement of success:
             #  - a set() (see below)
             #  - 0
             #  - False
             #  - None
             #
             # Everything else is an error (so scripts can conveniently |return
             # 1| or similar). If a set is returned, the elements of the set
--- a/python/mozbuild/mozbuild/backend/recursivemake.py
+++ b/python/mozbuild/mozbuild/backend/recursivemake.py
@@ -515,42 +515,70 @@ class RecursiveMakeBackend(CommonBackend
                 else:
                     backend_file.write('%s := %s\n' % (k, v))
         elif isinstance(obj, HostDefines):
             self._process_defines(obj, backend_file, which='HOST_DEFINES')
         elif isinstance(obj, Defines):
             self._process_defines(obj, backend_file)
 
         elif isinstance(obj, GeneratedFile):
-            tier = 'export' if obj.required_for_compile else 'misc'
+            if obj.required_for_compile:
+                tier = 'export'
+            elif obj.localized:
+                tier = 'libs'
+            else:
+                tier = 'misc'
             self._no_skip[tier].add(backend_file.relobjdir)
             first_output = obj.outputs[0]
             dep_file = "%s.pp" % first_output
 
+            if obj.inputs:
+                if obj.localized:
+                    # Localized generated files can have locale-specific inputs, which are
+                    # indicated by paths starting with `en-US/`.
+                    def srcpath(p):
+                        bits = p.split('en-US/', 1)
+                        if len(bits) == 2:
+                            e, f = bits
+                            assert(not e)
+                            return '$(call MERGE_FILE,%s)' % f
+                        return self._pretty_path(p, backend_file)
+                    inputs = [srcpath(f) for f in obj.inputs]
+                else:
+                    inputs = [self._pretty_path(f, backend_file) for f in obj.inputs]
+            else:
+                inputs = []
+
             # If we're doing this during export that means we need it during
             # compile, but if we have an artifact build we don't run compile,
             # so we can skip it altogether or let the rule run as the result of
             # something depending on it.
-            if tier == 'misc' or not self.environment.is_artifact_build:
+            if tier != 'export' or not self.environment.is_artifact_build:
                 backend_file.write('%s:: %s\n' % (tier, first_output))
             for output in obj.outputs:
                 if output != first_output:
                     backend_file.write('%s: %s ;\n' % (output, first_output))
                 backend_file.write('GARBAGE += %s\n' % output)
             backend_file.write('EXTRA_MDDEPEND_FILES += %s\n' % dep_file)
             if obj.script:
-                backend_file.write("""{output}: {script}{inputs}{backend}
+                backend_file.write("""{output}: {script}{inputs}{backend}{repack_force}
 \t$(REPORT_BUILD)
-\t$(call py_action,file_generate,{script} {method} {output} $(MDDEPDIR)/{dep_file}{inputs}{flags})
+\t$(call py_action,file_generate,{locale}{script} {method} {output} $(MDDEPDIR)/{dep_file}{inputs}{flags})
 
 """.format(output=first_output,
            dep_file=dep_file,
-           inputs=' ' + ' '.join([self._pretty_path(f, backend_file) for f in obj.inputs]) if obj.inputs else '',
+           inputs=' ' + ' '.join(inputs) if inputs else '',
            flags=' ' + ' '.join(shell_quote(f) for f in obj.flags) if obj.flags else '',
            backend=' backend.mk' if obj.flags else '',
+           # Locale repacks repack multiple locales from a single configured objdir,
+           # so standard mtime dependencies won't work properly when the build is re-run
+           # with a different locale as input. IS_LANGUAGE_REPACK will reliably be set
+           # in this situation, so simply force the generation to run in that case.
+           repack_force=' $(if $(IS_LANGUAGE_REPACK),FORCE)' if obj.localized else '',
+           locale='--locale=$(AB_CD) ' if obj.localized else '',
            script=obj.script,
            method=obj.method))
 
         elif isinstance(obj, JARManifest):
             self._no_skip['libs'].add(backend_file.relobjdir)
             backend_file.write('JAR_MANIFEST := %s\n' % obj.path.full_path)
 
         elif isinstance(obj, RustProgram):
@@ -1449,27 +1477,31 @@ class RecursiveMakeBackend(CommonBackend
                     var, self._pretty_path(f, backend_file)))
             backend_file.write('%s_PATH := $(DEPTH)/%s\n'
                                % (var, mozpath.join(obj.install_target, path)))
             backend_file.write('%s_TARGET := misc\n' % var)
             backend_file.write('PP_TARGETS += %s\n' % var)
 
     def _write_localized_files_files(self, files, name, backend_file):
         for f in files:
-            # The emitter asserts that all files start with `en-US/`
-            e, f = f.split('en-US/')
-            assert(not e)
-            if '*' in f:
-                # We can't use MERGE_FILE for wildcards because it takes
-                # only the first match internally. This is only used
-                # in one place in the tree currently so we'll hardcode
-                # that specific behavior for now.
-                backend_file.write('%s += $(wildcard $(LOCALE_SRCDIR)/%s)\n' % (name, f))
+            if not isinstance(f, ObjDirPath):
+                # The emitter asserts that all srcdir files start with `en-US/`
+                e, f = f.split('en-US/')
+                assert(not e)
+                if '*' in f:
+                    # We can't use MERGE_FILE for wildcards because it takes
+                    # only the first match internally. This is only used
+                    # in one place in the tree currently so we'll hardcode
+                    # that specific behavior for now.
+                    backend_file.write('%s += $(wildcard $(LOCALE_SRCDIR)/%s)\n' % (name, f))
+                else:
+                    backend_file.write('%s += $(call MERGE_FILE,%s)\n' % (name, f))
             else:
-                backend_file.write('%s += $(call MERGE_FILE,%s)\n' % (name, f))
+                # Objdir files are allowed from LOCALIZED_GENERATED_FILES
+                backend_file.write('%s += %s\n' % (name, self._pretty_path(f, backend_file)))
 
     def _process_localized_files(self, obj, files, backend_file):
         target = obj.install_target
         path = mozpath.basedir(target, ('dist/bin', ))
         if not path:
             raise Exception('Cannot install localized files to ' + target)
         for i, (path, files) in enumerate(files.walk()):
             name = 'LOCALIZED_FILES_%d' % i
--- a/python/mozbuild/mozbuild/frontend/context.py
+++ b/python/mozbuild/mozbuild/frontend/context.py
@@ -905,16 +905,21 @@ DependentTestsEntry = ContextDerivedType
                                                 ('tags', OrderedStringList),
                                                 ('flavors', OrderedTestFlavorList))
 BugzillaComponent = TypedNamedTuple('BugzillaComponent',
                         [('product', unicode), ('component', unicode)])
 SchedulingComponents = ContextDerivedTypedRecord(
         ('inclusive', TypedList(unicode, StrictOrderingOnAppendList)),
         ('exclusive', TypedList(unicode, StrictOrderingOnAppendList)))
 
+GeneratedFilesList = StrictOrderingOnAppendListWithFlagsFactory({
+    'script': unicode,
+    'inputs': list,
+    'flags': list, })
+
 
 class Files(SubContext):
     """Metadata attached to files.
 
     It is common to want to annotate files with metadata, such as which
     Bugzilla component tracks issues with certain files. This sub-context is
     where we stick that metadata.
 
@@ -1286,20 +1291,17 @@ VARIABLES = {
         """Source code files that can be compiled together.
 
         This variable contains a list of source code files to compile,
         that can be concatenated all together and built as a single source
         file. This can help make the build faster and reduce the debug info
         size.
         """),
 
-    'GENERATED_FILES': (StrictOrderingOnAppendListWithFlagsFactory({
-                'script': unicode,
-                'inputs': list,
-                'flags': list, }), list,
+    'GENERATED_FILES': (GeneratedFilesList, list,
         """Generic generated files.
 
         This variable contains a list of files for the build system to
         generate at export time. The generation method may be declared
         with optional ``script``, ``inputs`` and ``flags`` attributes on
         individual entries.
         If the optional ``script`` attribute is not present on an entry, it
         is assumed that rules for generating the file are present in
@@ -1434,20 +1436,22 @@ VARIABLES = {
         ``FINAL_TARGET_FILES``. For a build with ``--enable-ui-locale``,
         the file will be taken from ``$LOCALE_SRCDIR``, with the leading
         ``en-US`` removed. For a l10n repack of an en-US build, the file
         will be taken from the first location where it exists from:
         * the merged locale directory if it exists
         * ``$LOCALE_SRCDIR`` with the leading ``en-US`` removed
         * the in-tree en-US location
 
-        Paths specified here must be relative to the source directory and must
-        include a leading ``en-US``. Wildcards are allowed, and will be
-        expanded at the time of locale packaging to match files in the
-        locale directory.
+        Source directory paths specified here must must include a leading ``en-US``.
+        Wildcards are allowed, and will be expanded at the time of locale packaging to match
+        files in the locale directory.
+
+        Object directory paths are allowed here only if the path matches an entry in
+        ``LOCALIZED_GENERATED_FILES``.
 
         Files that are missing from a locale will typically have the en-US
         version used, but for wildcard expansions only files from the
         locale directory will be used, even if that means no files will
         be copied.
 
         Example::
 
@@ -1466,16 +1470,33 @@ VARIABLES = {
 
     'LOCALIZED_PP_FILES': (ContextDerivedTypedHierarchicalStringList(Path), list,
         """Like ``LOCALIZED_FILES``, with preprocessing.
 
         Note that the ``AB_CD`` define is available and expands to the current
         locale being packaged, as with preprocessed entries in jar manifests.
         """),
 
+    'LOCALIZED_GENERATED_FILES': (GeneratedFilesList, list,
+        """Like ``GENERATED_FILES``, but for files whose content varies based on the locale in use.
+
+        For simple cases of text substitution, prefer ``LOCALIZED_PP_FILES``.
+
+        Refer to the documentation of ``GENERATED_FILES``; for the most part things work the same.
+        The two major differences are:
+        1. The function in the Python script will be passed an additional keyword argument `locale`
+           which provides the locale in use, i.e. ``en-US``.
+        2. The ``inputs`` list may contain paths to files that will be taken from the locale
+           source directory (see ``LOCALIZED_FILES`` for a discussion of the specifics). Paths
+           in ``inputs`` starting with ``en-US/`` are considered localized files.
+
+        To place the generated output file in a specific location, list its objdir path in
+        ``LOCALIZED_FILES``.
+        """),
+
     'OBJDIR_FILES': (ContextDerivedTypedHierarchicalStringList(Path), list,
         """List of files to be installed anywhere in the objdir. Use sparingly.
 
         ``OBJDIR_FILES`` is similar to FINAL_TARGET_FILES, but it allows copying
         anywhere in the object directory. This is intended for various one-off
         cases, not for general use. If you wish to add entries to OBJDIR_FILES,
         please consult a build peer.
         """),
--- a/python/mozbuild/mozbuild/frontend/data.py
+++ b/python/mozbuild/mozbuild/frontend/data.py
@@ -1052,25 +1052,27 @@ class GeneratedFile(ContextDerived):
 
     __slots__ = (
         'script',
         'method',
         'outputs',
         'inputs',
         'flags',
         'required_for_compile',
+        'localized',
     )
 
-    def __init__(self, context, script, method, outputs, inputs, flags=()):
+    def __init__(self, context, script, method, outputs, inputs, flags=(), localized=False):
         ContextDerived.__init__(self, context)
         self.script = script
         self.method = method
         self.outputs = outputs if isinstance(outputs, tuple) else (outputs,)
         self.inputs = inputs
         self.flags = flags
+        self.localized = localized
 
         suffixes = (
             '.c',
             '.cpp',
             '.h',
             '.inc',
             '.py',
             '.rs',
--- a/python/mozbuild/mozbuild/frontend/emitter.py
+++ b/python/mozbuild/mozbuild/frontend/emitter.py
@@ -1017,19 +1017,22 @@ class TreeMetadataEmitter(LoggingMixin):
             if (context.config.substs.get('MOZ_DEBUG') and
                     not context.config.substs.get('MOZ_NO_DEBUG_RTL')):
                 rtl_flag += 'd'
             computed_flags.resolve_flags('RTL', [rtl_flag])
             if not context.config.substs.get('CROSS_COMPILE'):
                 computed_host_flags.resolve_flags('RTL', [rtl_flag])
 
         generated_files = set()
+        localized_generated_files = set()
         for obj in self._process_generated_files(context):
             for f in obj.outputs:
                 generated_files.add(f)
+                if obj.localized:
+                    localized_generated_files.add(f)
             yield obj
 
         for path in context['CONFIGURE_SUBST_FILES']:
             sub = self._create_substitution(ConfigFileSubstitution, context,
                 path)
             generated_files.add(str(sub.relpath))
             yield sub
 
@@ -1115,27 +1118,27 @@ class TreeMetadataEmitter(LoggingMixin):
                     components.extend(files)
                 if base == 'defaults/pref':
                     has_prefs = True
                 if mozpath.split(base)[0] == 'res':
                     has_resources = True
                 for f in files:
                     if (var in ('FINAL_TARGET_PP_FILES',
                                 'OBJDIR_PP_FILES',
-                                'LOCALIZED_FILES',
                                 'LOCALIZED_PP_FILES') and
                         not isinstance(f, SourcePath)):
                         raise SandboxValidationError(
                                 ('Only source directory paths allowed in ' +
                                  '%s: %s')
                                 % (var, f,), context)
-                    if var.startswith('LOCALIZED_') and not f.startswith('en-US/'):
-                        raise SandboxValidationError(
-                                '%s paths must start with `en-US/`: %s'
-                                % (var, f,), context)
+                    if var.startswith('LOCALIZED_'):
+                        if isinstance(f, SourcePath) and not f.startswith('en-US/'):
+                            raise SandboxValidationError(
+                                    '%s paths must start with `en-US/`: %s'
+                                    % (var, f,), context)
                     if not isinstance(f, ObjDirPath):
                         path = f.full_path
                         if '*' not in path and not os.path.exists(path):
                             raise SandboxValidationError(
                                 'File listed in %s does not exist: %s'
                                 % (var, path), context)
                     else:
                         # TODO: Bug 1254682 - The '/' check is to allow
@@ -1143,16 +1146,31 @@ class TreeMetadataEmitter(LoggingMixin):
                         # which is done occasionally for tests. However, it
                         # means we don't fail early if the file isn't actually
                         # created by the other moz.build file.
                         if f.target_basename not in generated_files and '/' not in f:
                             raise SandboxValidationError(
                                 ('Objdir file listed in %s not in ' +
                                  'GENERATED_FILES: %s') % (var, f), context)
 
+                        if var.startswith('LOCALIZED_'):
+                            # Further require that LOCALIZED_FILES are from
+                            # LOCALIZED_GENERATED_FILES.
+                            if f.target_basename not in localized_generated_files:
+                                raise SandboxValidationError(
+                                    ('Objdir file listed in %s not in ' +
+                                     'LOCALIZED_GENERATED_FILES: %s') % (var, f), context)
+                        else:
+                            # Additionally, don't allow LOCALIZED_GENERATED_FILES to be used
+                            # in anything *but* LOCALIZED_FILES.
+                            if f.target_basename in localized_generated_files:
+                                raise SandboxValidationError(
+                                    ('Outputs of LOCALIZED_GENERATED_FILES cannot be used in %s: ' +
+                                     '%s') % (var, f), context)
+
             # Addons (when XPI_NAME is defined) and Applications (when
             # DIST_SUBDIR is defined) use a different preferences directory
             # (default/preferences) from the one the GRE uses (defaults/pref).
             # Hence, we move the files from the latter to the former in that
             # case.
             if has_prefs and (context.get('XPI_NAME') or
                               context.get('DIST_SUBDIR')):
                 all_files.defaults.preferences += all_files.defaults.pref
@@ -1282,55 +1300,57 @@ class TreeMetadataEmitter(LoggingMixin):
     def _process_generated_files(self, context):
         for path in context['CONFIGURE_DEFINE_FILES']:
             script = mozpath.join(mozpath.dirname(mozpath.dirname(__file__)),
                                   'action', 'process_define_files.py')
             yield GeneratedFile(context, script, 'process_define_file',
                                 unicode(path),
                                 [Path(context, path + '.in')])
 
-        generated_files = context.get('GENERATED_FILES')
-        if not generated_files:
+        generated_files = context.get('GENERATED_FILES') or []
+        localized_generated_files = context.get('LOCALIZED_GENERATED_FILES') or []
+        if not (generated_files or localized_generated_files):
             return
 
-        for f in generated_files:
-            flags = generated_files[f]
-            outputs = f
-            inputs = []
-            if flags.script:
-                method = "main"
-                script = SourcePath(context, flags.script).full_path
+        for (localized, gen) in ((False, generated_files), (True, localized_generated_files)):
+            for f in gen:
+                flags = gen[f]
+                outputs = f
+                inputs = []
+                if flags.script:
+                    method = "main"
+                    script = SourcePath(context, flags.script).full_path
 
-                # Deal with cases like "C:\\path\\to\\script.py:function".
-                if '.py:' in script:
-                    script, method = script.rsplit('.py:', 1)
-                    script += '.py'
+                    # Deal with cases like "C:\\path\\to\\script.py:function".
+                    if '.py:' in script:
+                        script, method = script.rsplit('.py:', 1)
+                        script += '.py'
 
-                if not os.path.exists(script):
-                    raise SandboxValidationError(
-                        'Script for generating %s does not exist: %s'
-                        % (f, script), context)
-                if os.path.splitext(script)[1] != '.py':
-                    raise SandboxValidationError(
-                        'Script for generating %s does not end in .py: %s'
-                        % (f, script), context)
+                    if not os.path.exists(script):
+                        raise SandboxValidationError(
+                            'Script for generating %s does not exist: %s'
+                            % (f, script), context)
+                    if os.path.splitext(script)[1] != '.py':
+                        raise SandboxValidationError(
+                            'Script for generating %s does not end in .py: %s'
+                            % (f, script), context)
 
-                for i in flags.inputs:
-                    p = Path(context, i)
-                    if (isinstance(p, SourcePath) and
-                            not os.path.exists(p.full_path)):
-                        raise SandboxValidationError(
-                            'Input for generating %s does not exist: %s'
-                            % (f, p.full_path), context)
-                    inputs.append(p)
-            else:
-                script = None
-                method = None
-            yield GeneratedFile(context, script, method, outputs, inputs,
-                                flags.flags)
+                    for i in flags.inputs:
+                        p = Path(context, i)
+                        if (isinstance(p, SourcePath) and
+                                not os.path.exists(p.full_path)):
+                            raise SandboxValidationError(
+                                'Input for generating %s does not exist: %s'
+                                % (f, p.full_path), context)
+                        inputs.append(p)
+                else:
+                    script = None
+                    method = None
+                yield GeneratedFile(context, script, method, outputs, inputs,
+                                    flags.flags, localized=localized)
 
     def _process_test_manifests(self, context):
         for prefix, info in TEST_MANIFESTS.items():
             for path, manifest in context.get('%s_MANIFESTS' % prefix, []):
                 for obj in self._process_test_manifest(context, info, path, manifest):
                     yield obj
 
         for flavor in REFTEST_FLAVORS:
new file mode 100644
copy from python/mozbuild/mozbuild/test/backend/data/generated-files/foo-data
copy to python/mozbuild/mozbuild/test/backend/data/localized-generated-files/foo-data
copy from python/mozbuild/mozbuild/test/backend/data/generated-files/generate-foo.py
copy to python/mozbuild/mozbuild/test/backend/data/localized-generated-files/generate-foo.py
copy from python/mozbuild/mozbuild/test/backend/data/generated-files/moz.build
copy to python/mozbuild/mozbuild/test/backend/data/localized-generated-files/moz.build
--- a/python/mozbuild/mozbuild/test/backend/data/generated-files/moz.build
+++ b/python/mozbuild/mozbuild/test/backend/data/localized-generated-files/moz.build
@@ -1,12 +1,15 @@
 # -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
 # Any copyright is dedicated to the Public Domain.
 # http://creativecommons.org/publicdomain/zero/1.0/
 
-GENERATED_FILES += [ 'bar.c', 'foo.c', 'quux.c' ]
+LOCALIZED_GENERATED_FILES += [ 'foo.xyz' ]
 
-bar = GENERATED_FILES['bar.c']
-bar.script = 'generate-bar.py:baz'
+foo = LOCALIZED_GENERATED_FILES['foo.xyz']
+foo.script = 'generate-foo.py'
+foo.inputs = [
+    'en-US/localized-input',
+    'non-localized-input',
+]
 
-foo = GENERATED_FILES['foo.c']
-foo.script = 'generate-foo.py'
-foo.inputs = ['foo-data']
+# Also check that using it in LOCALIZED_FILES does the right thing.
+LOCALIZED_FILES += [ '!foo.xyz' ]
new file mode 100644
--- a/python/mozbuild/mozbuild/test/backend/test_recursivemake.py
+++ b/python/mozbuild/mozbuild/test/backend/test_recursivemake.py
@@ -413,16 +413,40 @@ class TestRecursiveMakeBackend(BackendTe
             'export:: quux.c',
             'GARBAGE += quux.c',
             'EXTRA_MDDEPEND_FILES += quux.c.pp',
         ]
 
         self.maxDiff = None
         self.assertEqual(lines, expected)
 
+    def test_localized_generated_files(self):
+        """Ensure LOCALIZED_GENERATED_FILES is handled properly."""
+        env = self._consume('localized-generated-files', RecursiveMakeBackend)
+
+        backend_path = mozpath.join(env.topobjdir, 'backend.mk')
+        lines = [l.strip() for l in open(backend_path, 'rt').readlines()[2:]]
+
+        expected = [
+            'libs:: foo.xyz',
+            'GARBAGE += foo.xyz',
+            'EXTRA_MDDEPEND_FILES += foo.xyz.pp',
+            'foo.xyz: %s/generate-foo.py $(call MERGE_FILE,localized-input) $(srcdir)/non-localized-input $(if $(IS_LANGUAGE_REPACK),FORCE)' % env.topsrcdir,
+            '$(REPORT_BUILD)',
+            '$(call py_action,file_generate,--locale=$(AB_CD) %s/generate-foo.py main foo.xyz $(MDDEPDIR)/foo.xyz.pp $(call MERGE_FILE,localized-input) $(srcdir)/non-localized-input)' % env.topsrcdir,
+            '',
+            'LOCALIZED_FILES_0_FILES += foo.xyz',
+            'LOCALIZED_FILES_0_DEST = $(FINAL_TARGET)/',
+            'LOCALIZED_FILES_0_TARGET := libs',
+            'INSTALL_TARGETS += LOCALIZED_FILES_0',
+        ]
+
+        self.maxDiff = None
+        self.assertEqual(lines, expected)
+
     def test_exports_generated(self):
         """Ensure EXPORTS that are listed in GENERATED_FILES
         are handled properly."""
         env = self._consume('exports-generated', RecursiveMakeBackend)
 
         # EXPORTS files should appear in the dist_include install manifest.
         m = InstallManifest(path=mozpath.join(env.topobjdir,
             '_build_manifests', 'install', 'dist_include'))
copy from python/mozbuild/mozbuild/test/frontend/data/generated-files/moz.build
copy to python/mozbuild/mozbuild/test/frontend/data/localized-files-from-generated/moz.build
--- a/python/mozbuild/mozbuild/test/frontend/data/generated-files/moz.build
+++ b/python/mozbuild/mozbuild/test/frontend/data/localized-files-from-generated/moz.build
@@ -1,5 +1,6 @@
 # -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
 # Any copyright is dedicated to the Public Domain.
 # http://creativecommons.org/publicdomain/zero/1.0/
 
-GENERATED_FILES += [ 'bar.c', 'foo.c', ('xpidllex.py', 'xpidlyacc.py'), ]
+LOCALIZED_GENERATED_FILES += [ 'abc.ini' ]
+LOCALIZED_FILES += [ '!abc.ini' ]
copy from python/mozbuild/mozbuild/test/frontend/data/generated-files/moz.build
copy to python/mozbuild/mozbuild/test/frontend/data/localized-files-not-localized-generated/moz.build
--- a/python/mozbuild/mozbuild/test/frontend/data/generated-files/moz.build
+++ b/python/mozbuild/mozbuild/test/frontend/data/localized-files-not-localized-generated/moz.build
@@ -1,5 +1,6 @@
 # -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
 # Any copyright is dedicated to the Public Domain.
 # http://creativecommons.org/publicdomain/zero/1.0/
 
-GENERATED_FILES += [ 'bar.c', 'foo.c', ('xpidllex.py', 'xpidlyacc.py'), ]
+GENERATED_FILES += [ 'abc.ini' ]
+LOCALIZED_FILES += [ '!abc.ini' ]
new file mode 100644
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/localized-generated-files-final-target-files/moz.build
@@ -0,0 +1,6 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+LOCALIZED_GENERATED_FILES += [ 'abc.ini' ]
+FINAL_TARGET_FILES += [ '!abc.ini' ]
copy from python/mozbuild/mozbuild/test/frontend/data/generated-files/moz.build
copy to python/mozbuild/mozbuild/test/frontend/data/localized-generated-files/moz.build
--- a/python/mozbuild/mozbuild/test/frontend/data/generated-files/moz.build
+++ b/python/mozbuild/mozbuild/test/frontend/data/localized-generated-files/moz.build
@@ -1,5 +1,5 @@
 # -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
 # Any copyright is dedicated to the Public Domain.
 # http://creativecommons.org/publicdomain/zero/1.0/
 
-GENERATED_FILES += [ 'bar.c', 'foo.c', ('xpidllex.py', 'xpidlyacc.py'), ]
+LOCALIZED_GENERATED_FILES += [ 'abc.ini', ('bar', 'baz') ]
--- a/python/mozbuild/mozbuild/test/frontend/test_emitter.py
+++ b/python/mozbuild/mozbuild/test/frontend/test_emitter.py
@@ -456,25 +456,73 @@ class TestEmitterBasic(unittest.TestCase
 
     def test_generated_files(self):
         reader = self.reader('generated-files')
         objs = self.read_topsrcdir(reader)
 
         self.assertEqual(len(objs), 3)
         for o in objs:
             self.assertIsInstance(o, GeneratedFile)
+            self.assertFalse(o.localized)
 
         expected = ['bar.c', 'foo.c', ('xpidllex.py', 'xpidlyacc.py'), ]
         for o, f in zip(objs, expected):
             expected_filename = f if isinstance(f, tuple) else (f,)
             self.assertEqual(o.outputs, expected_filename)
             self.assertEqual(o.script, None)
             self.assertEqual(o.method, None)
             self.assertEqual(o.inputs, [])
 
+    def test_localized_generated_files(self):
+        reader = self.reader('localized-generated-files')
+        objs = self.read_topsrcdir(reader)
+
+        self.assertEqual(len(objs), 2)
+        for o in objs:
+            self.assertIsInstance(o, GeneratedFile)
+            self.assertTrue(o.localized)
+
+        expected = ['abc.ini', ('bar', 'baz'), ]
+        for o, f in zip(objs, expected):
+            expected_filename = f if isinstance(f, tuple) else (f,)
+            self.assertEqual(o.outputs, expected_filename)
+            self.assertEqual(o.script, None)
+            self.assertEqual(o.method, None)
+            self.assertEqual(o.inputs, [])
+
+    def test_localized_files_from_generated(self):
+        """Test that using LOCALIZED_GENERATED_FILES and then putting the output in
+        LOCALIZED_FILES as an objdir path works.
+        """
+        reader = self.reader('localized-files-from-generated')
+        objs = self.read_topsrcdir(reader)
+
+        self.assertEqual(len(objs), 2)
+        self.assertIsInstance(objs[0], GeneratedFile)
+        self.assertIsInstance(objs[1], LocalizedFiles)
+
+    def test_localized_files_not_localized_generated(self):
+        """Test that using GENERATED_FILES and then putting the output in
+        LOCALIZED_FILES as an objdir path produces an error.
+        """
+        reader = self.reader('localized-files-not-localized-generated')
+        with self.assertRaisesRegexp(SandboxValidationError,
+            'Objdir file listed in LOCALIZED_FILES not in LOCALIZED_GENERATED_FILES:'):
+            objs = self.read_topsrcdir(reader)
+
+
+    def test_localized_generated_files_final_target_files(self):
+        """Test that using LOCALIZED_GENERATED_FILES and then putting the output in
+        FINAL_TARGET_FILES as an objdir path produces an error.
+        """
+        reader = self.reader('localized-generated-files-final-target-files')
+        with self.assertRaisesRegexp(SandboxValidationError,
+            'Outputs of LOCALIZED_GENERATED_FILES cannot be used in FINAL_TARGET_FILES:'):
+            objs = self.read_topsrcdir(reader)
+
     def test_generated_files_method_names(self):
         reader = self.reader('generated-files-method-names')
         objs = self.read_topsrcdir(reader)
 
         self.assertEqual(len(objs), 2)
         for o in objs:
             self.assertIsInstance(o, GeneratedFile)
 
--- a/servo/components/style/properties/longhand/box.mako.rs
+++ b/servo/components/style/properties/longhand/box.mako.rs
@@ -368,19 +368,28 @@
 
 // CSS 2.1, Section 11 - Visual effects
 
 ${helpers.single_keyword("-servo-overflow-clip-box", "padding-box content-box",
     products="servo", animation_value_type="none", enabled_in="ua",
     spec="Internal, not web-exposed, \
           may be standardized in the future (https://developer.mozilla.org/en-US/docs/Web/CSS/overflow-clip-box)")}
 
-${helpers.single_keyword("overflow-clip-box", "padding-box content-box",
+${helpers.single_keyword("overflow-clip-box-block", "padding-box content-box",
     products="gecko", animation_value_type="discrete", enabled_in="ua",
     gecko_pref="layout.css.overflow-clip-box.enabled",
+    gecko_constant_prefix="NS_STYLE_OVERFLOW_CLIP_BOX",
+    flags="APPLIES_TO_PLACEHOLDER",
+    spec="Internal, not web-exposed, \
+          may be standardized in the future (https://developer.mozilla.org/en-US/docs/Web/CSS/overflow-clip-box)")}
+
+${helpers.single_keyword("overflow-clip-box-inline", "padding-box content-box",
+    products="gecko", animation_value_type="discrete", enabled_in="ua",
+    gecko_pref="layout.css.overflow-clip-box.enabled",
+    gecko_constant_prefix="NS_STYLE_OVERFLOW_CLIP_BOX",
     flags="APPLIES_TO_PLACEHOLDER",
     spec="Internal, not web-exposed, \
           may be standardized in the future (https://developer.mozilla.org/en-US/docs/Web/CSS/overflow-clip-box)")}
 
 <%
     overflow_custom_consts = { "-moz-hidden-unscrollable": "CLIP" }
 %>
 
--- a/servo/components/style/properties/shorthand/box.mako.rs
+++ b/servo/components/style/properties/shorthand/box.mako.rs
@@ -53,16 +53,58 @@
                 self.overflow_x.to_css(dest)
             } else {
                 Ok(())
             }
         }
     }
 </%helpers:shorthand>
 
+<%helpers:shorthand name="overflow-clip-box" sub_properties="overflow-clip-box-block overflow-clip-box-inline"
+                    enabled_in="ua" gecko_pref="layout.css.overflow-clip-box.enabled"
+                    spec="Internal, not web-exposed, may be standardized in the future (https://developer.mozilla.org/en-US/docs/Web/CSS/overflow-clip-box)"
+                    products="gecko">
+  use properties::longhands::{overflow_clip_box_block, overflow_clip_box_inline};
+
+  pub fn to_inline_value(block_value: overflow_clip_box_block::SpecifiedValue)
+                         -> overflow_clip_box_inline::SpecifiedValue {
+      match block_value {
+          overflow_clip_box_block::SpecifiedValue::padding_box =>
+              overflow_clip_box_inline::SpecifiedValue::padding_box,
+          overflow_clip_box_block::SpecifiedValue::content_box =>
+              overflow_clip_box_inline::SpecifiedValue::content_box
+      }
+  }
+
+  pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
+                             -> Result<Longhands, ParseError<'i>> {
+      let block_value = overflow_clip_box_block::parse(context, input)?;
+      let inline_value = input.try(|input| overflow_clip_box_inline::parse(context, input)).unwrap_or(
+          to_inline_value(block_value));
+
+      Ok(expanded! {
+        overflow_clip_box_block: block_value,
+        overflow_clip_box_inline: inline_value,
+      })
+  }
+
+  impl<'a> ToCss for LonghandsToSerialize<'a>  {
+      fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+          if to_inline_value(*self.overflow_clip_box_block) == *self.overflow_clip_box_inline {
+            self.overflow_clip_box_block.to_css(dest)
+          } else {
+            self.overflow_clip_box_block.to_css(dest)?;
+            dest.write_str(" ")?;
+            self.overflow_clip_box_inline.to_css(dest)
+          }
+      }
+  }
+
+</%helpers:shorthand>
+
 macro_rules! try_parse_one {
     ($input: expr, $var: ident, $prop_module: ident) => {
         if $var.is_none() {
             if let Ok(value) = $input.try($prop_module::SingleSpecifiedValue::parse) {
                 $var = Some(value);
                 continue;
             }
         }
--- a/testing/web-platform/tests/web-animations/animation-model/animation-types/property-list.js
+++ b/testing/web-platform/tests/web-animations/animation-model/animation-types/property-list.js
@@ -1049,22 +1049,16 @@ const gCSSProperties = {
       return element;
     }
   },
   'overflow': {
     // https://drafts.csswg.org/css-overflow/#propdef-overflow
     types: [
     ]
   },
-  'overflow-clip-box': {
-    // https://developer.mozilla.org/en/docs/Web/CSS/overflow-clip-box
-    types: [
-      { type: 'discrete', options: [ [ 'padding-box', 'content-box' ] ] }
-    ]
-  },
   'overflow-wrap': {
     // https://drafts.csswg.org/css-text-3/#propdef-overflow-wrap
     types: [
       { type: 'discrete', options: [ [ 'normal', 'break-word' ] ] }
     ]
   },
   'overflow-x': {
     // https://drafts.csswg.org/css-overflow-3/#propdef-overflow-x
--- a/toolkit/locales/Makefile.in
+++ b/toolkit/locales/Makefile.in
@@ -15,11 +15,8 @@ libs-%:
 # target to be used by multi-locale l10n builds, just add this locale
 # like regular chrome code
 chrome-%: AB_CD=$*
 chrome-%:
 	@$(MAKE) -C $(DEPTH)/netwerk/locales/ chrome AB_CD=$*
 	@$(MAKE) -C $(DEPTH)/dom/locales/ chrome AB_CD=$*
 	@$(MAKE) -C $(DEPTH)/security/manager/locales/ chrome AB_CD=$*
 	@$(MAKE) chrome AB_CD=$*
-
-libs:: update.locale
-	sed -e 's/%AB_CD%/$(AB_CD)/' $< > $(FINAL_TARGET)/update.locale
new file mode 100644
--- /dev/null
+++ b/toolkit/locales/generate_update_locale.py
@@ -0,0 +1,13 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+# Generate update.locale, which simply contains the name of the current locale.
+
+from __future__ import unicode_literals, print_function
+
+def main(output, locale=None):
+    assert(locale is not None)
+    # update.locale is a trivial file but let's be unicode aware anyway.
+    locale = unicode(locale, 'utf_8')
+    print(locale, file=output)
--- a/toolkit/locales/moz.build
+++ b/toolkit/locales/moz.build
@@ -29,8 +29,13 @@ if CONFIG['MOZ_CRASHREPORTER']:
         # TODO: fixing bug 1223748 should let us remove this special case
         LOCALIZED_FILES['crashreporter.app'].Contents.Resources += [
             'en-US/crashreporter/crashreporter.ini'
         ]
     else:
         LOCALIZED_FILES += [
             'en-US/crashreporter/crashreporter.ini'
         ]
+
+LOCALIZED_GENERATED_FILES += ['update.locale']
+update_locale = LOCALIZED_GENERATED_FILES['update.locale']
+update_locale.script = 'generate_update_locale.py'
+LOCALIZED_FILES += ['!update.locale']
deleted file mode 100644
--- a/toolkit/locales/update.locale
+++ /dev/null
@@ -1,1 +0,0 @@
-%AB_CD%