merge mozilla-inbound to mozilla-central. r=merge a=merge
authorSebastian Hengst <archaeopteryx@coole-files.de>
Fri, 27 Oct 2017 23:30:52 +0200
changeset 388813 d58424c244c38f88357a26fb61c333d3c6e552d7
parent 388773 b66c75b4aa617fc7a37c889f0fc9a9934c6f07d6 (current diff)
parent 388812 2a8eb883a2792c876a03bd2053863d7639387fbe (diff)
child 388814 8400adbffaa11c5b4b2357c3973f4a2f371b3081
child 388841 ad08d9064a7d4334dd33315622b58719ec4d0dac
child 388855 256cdd526080d0897ebd89491d5e11141f6ea5b4
push id54263
push userarchaeopteryx@coole-files.de
push dateFri, 27 Oct 2017 21:32:43 +0000
treeherderautoland@8400adbffaa1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge, merge
milestone58.0a1
first release with
nightly linux32
d58424c244c3 / 58.0a1 / 20171027220059 / files
nightly linux64
d58424c244c3 / 58.0a1 / 20171027220059 / files
nightly mac
d58424c244c3 / 58.0a1 / 20171027220059 / files
nightly win32
d58424c244c3 / 58.0a1 / 20171027220059 / files
nightly win64
d58424c244c3 / 58.0a1 / 20171027220059 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
merge mozilla-inbound to mozilla-central. r=merge a=merge MozReview-Commit-ID: DasxLYlgq0N
dom/base/FragmentOrElement.cpp
gfx/harfbuzz/src/hb-cache-private.hh
ipc/dbus/DBusConnectionDelete.h
ipc/dbus/DBusConnectionRefPtr.h
ipc/dbus/DBusHelpers.cpp
ipc/dbus/DBusHelpers.h
ipc/dbus/DBusMessageRefPtr.h
ipc/dbus/DBusPendingCallRefPtr.h
ipc/dbus/DBusUtils.cpp
ipc/dbus/DBusUtils.h
ipc/dbus/DBusWatcher.cpp
ipc/dbus/DBusWatcher.h
ipc/dbus/RawDBusConnection.cpp
ipc/dbus/RawDBusConnection.h
ipc/dbus/moz.build
ipc/ril/Ril.cpp
ipc/ril/Ril.h
ipc/ril/RilConnector.cpp
ipc/ril/RilConnector.h
ipc/ril/RilSocket.cpp
ipc/ril/RilSocket.h
ipc/ril/RilSocketConsumer.cpp
ipc/ril/RilSocketConsumer.h
ipc/ril/moz.build
uriloader/exthandler/tests/mochitest/blob.html
uriloader/exthandler/tests/mochitest/browser_ext_helper_pb.js
--- a/CLOBBER
+++ b/CLOBBER
@@ -17,9 +17,9 @@
 #
 # Modifying this file will now automatically clobber the buildbot machines \o/
 #
 
 # Are you updating CLOBBER because you think it's needed for your WebIDL
 # changes to stick? As of bug 928195, this shouldn't be necessary! Please
 # don't change CLOBBER for WebIDL changes any more.
 
-Bug 1409329 works better after a clobber.
+Bug 1408789, Windows compiler change
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -691,17 +691,17 @@ pref("network.protocol-handler.expose.nn
 
 pref("accessibility.typeaheadfind", false);
 pref("accessibility.typeaheadfind.timeout", 5000);
 pref("accessibility.typeaheadfind.linksonly", false);
 pref("accessibility.typeaheadfind.flashBar", 1);
 
 // Accessibility indicator preferences such as support URL, enabled flag.
 pref("accessibility.support.url", "https://support.mozilla.org/%LOCALE%/kb/accessibility-services");
-pref("accessibility.indicator.enabled", true);
+pref("accessibility.indicator.enabled", false);
 
 pref("plugins.click_to_play", true);
 pref("plugins.testmode", false);
 
 // Should plugins that are hidden show the infobar UI?
 pref("plugins.show_infobar", false);
 
 // Should dismissing the hidden plugin infobar suppress it permanently?
--- a/browser/base/content/test/tabs/browser_accessibility_indicator.js
+++ b/browser/base/content/test/tabs/browser_accessibility_indicator.js
@@ -77,16 +77,19 @@ async function shutdownAccessibilityServ
  */
 function forceGC() {
   SpecialPowers.gc();
   SpecialPowers.forceShrinkingGC();
   SpecialPowers.forceCC();
 }
 
 add_task(async function test_accessibility_indicator() {
+  info("Preff on accessibility indicator.");
+  Services.prefs.setBoolPref(A11Y_INDICATOR_ENABLED_PREF, true);
+
   info("Test default accessibility indicator state.");
   let newWin = await BrowserTestUtils.openNewBrowserWindow();
   testIndicatorState(window, true, false);
   testIndicatorState(newWin, true, false);
 
   info("Enable accessibility and ensure the indicator is shown in all windows.");
   let accService = await initAccessibilityService(); // eslint-disable-line no-unused-vars
   testIndicatorState(window, true, true);
--- a/browser/base/content/test/tabs/browser_tabCloseProbes.js
+++ b/browser/base/content/test/tabs/browser_tabCloseProbes.js
@@ -22,20 +22,16 @@ function assertCount(snapshot, expectedC
   // snapshot.count entries
   Assert.equal(snapshot.counts.reduce((a, b) => a + b), expectedCount,
                `Should only be ${expectedCount} collected value.`);
 }
 
 add_task(async function setup() {
   // These probes are opt-in, meaning we only capture them if extended
   // Telemetry recording is enabled.
-  await SpecialPowers.pushPrefEnv({
-    set: [["toolkit.telemetry.enabled", true]]
-  });
-
   let oldCanRecord = Services.telemetry.canRecordExtended;
   Services.telemetry.canRecordExtended = true;
   registerCleanupFunction(() => {
     Services.telemetry.canRecordExtended = oldCanRecord;
   });
 });
 
 /**
--- a/browser/components/search/test/browser_contextSearchTabPosition.js
+++ b/browser/components/search/test/browser_contextSearchTabPosition.js
@@ -1,14 +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/. */
 
 add_task(async function test() {
-  await SpecialPowers.pushPrefEnv({set: [["toolkit.telemetry.enabled", true]]});
   let engine = await promiseNewEngine("testEngine.xml");
   let histogramKey = "other-" + engine.name + ".contextmenu";
   let numSearchesBefore = 0;
 
   try {
     let hs = Services.telemetry.getKeyedHistogramById("SEARCH_COUNTS").snapshot();
     if (histogramKey in hs) {
       numSearchesBefore = hs[histogramKey].sum;
--- a/browser/components/search/test/browser_healthreport.js
+++ b/browser/components/search/test/browser_healthreport.js
@@ -71,17 +71,16 @@ function test() {
         Services.obs.removeObserver(observer, "browser-search-engine-modified");
         finish();
         break;
     }
   }
 
   Services.obs.addObserver(observer, "browser-search-engine-modified");
   SpecialPowers.pushPrefEnv({set: [
-    ["toolkit.telemetry.enabled", true],
     ["browser.search.widget.inNavBar", true],
   ]}).then(function() {
     Services.search.addEngine("http://mochi.test:8888/browser/browser/components/search/test/testEngine.xml",
                               null, "data:image/x-icon,%00", false);
   });
 }
 
 function resetPreferences() {
--- a/browser/components/translation/test/browser_translation_telemetry.js
+++ b/browser/components/translation/test/browser_translation_telemetry.js
@@ -148,17 +148,16 @@ add_task(async function setup() {
 
   const restorePrefs = (prefs, backup) => {
     for (let p of prefs) {
       Services.prefs.setBoolPref(p, backup[p]);
     }
   };
 
   const prefs = [
-    "toolkit.telemetry.enabled",
     "browser.translation.detectLanguage",
     "browser.translation.ui.show"
   ];
 
   let prefsBackup = setupPrefs(prefs);
 
   let oldCanRecord = Telemetry.canRecordExtended;
   Telemetry.canRecordExtended = true;
--- a/browser/config/mozconfigs/win32/clang
+++ b/browser/config/mozconfigs/win32/clang
@@ -4,12 +4,12 @@ MOZ_AUTOMATION_L10N_CHECK=0
 
 . "$topsrcdir/build/mozconfig.win-common"
 . "$topsrcdir/browser/config/mozconfigs/common"
 
 ac_add_options --enable-optimize
 
 ac_add_options --enable-clang-plugin
 
-. $topsrcdir/build/win32/mozconfig.vs-latest
+. $topsrcdir/build/win32/mozconfig.vs2015-win64
 
 . "$topsrcdir/build/mozconfig.common.override"
 . "$topsrcdir/build/mozconfig.clang-cl"
--- a/browser/config/mozconfigs/win32/clang-debug
+++ b/browser/config/mozconfigs/win32/clang-debug
@@ -5,12 +5,12 @@ MOZ_AUTOMATION_L10N_CHECK=0
 . "$topsrcdir/build/mozconfig.win-common"
 . "$topsrcdir/browser/config/mozconfigs/common"
 
 ac_add_options --enable-optimize
 ac_add_options --enable-debug
 
 ac_add_options --enable-clang-plugin
 
-. $topsrcdir/build/win32/mozconfig.vs-latest
+. $topsrcdir/build/win32/mozconfig.vs2015-win64
 
 . "$topsrcdir/build/mozconfig.common.override"
 . "$topsrcdir/build/mozconfig.clang-cl"
--- a/browser/config/mozconfigs/win32/debug-static-analysis
+++ b/browser/config/mozconfigs/win32/debug-static-analysis
@@ -5,12 +5,12 @@ MOZ_AUTOMATION_L10N_CHECK=0
 . "$topsrcdir/build/mozconfig.win-common"
 . "$topsrcdir/browser/config/mozconfigs/common"
 
 ac_add_options --enable-debug
 ac_add_options --enable-dmd
 
 ac_add_options --enable-clang-plugin
 
-. $topsrcdir/build/win32/mozconfig.vs-latest
+. $topsrcdir/build/win32/mozconfig.vs2015-win64
 
 . "$topsrcdir/build/mozconfig.common.override"
 . "$topsrcdir/build/mozconfig.clang-cl"
--- a/browser/config/mozconfigs/win64/clang
+++ b/browser/config/mozconfigs/win64/clang
@@ -6,12 +6,12 @@ MOZ_AUTOMATION_PACKAGE_TEST=0
 
 ac_add_options --target=x86_64-pc-mingw32
 ac_add_options --host=x86_64-pc-mingw32
 
 ac_add_options --enable-optimize
 
 ac_add_options --enable-clang-plugin
 
-. $topsrcdir/build/win64/mozconfig.vs-latest
+. $topsrcdir/build/win64/mozconfig.vs2015
 
 . "$topsrcdir/build/mozconfig.common.override"
 . "$topsrcdir/build/mozconfig.clang-cl"
--- a/browser/config/mozconfigs/win64/clang-debug
+++ b/browser/config/mozconfigs/win64/clang-debug
@@ -7,12 +7,12 @@ MOZ_AUTOMATION_PACKAGE_TEST=0
 ac_add_options --target=x86_64-pc-mingw32
 ac_add_options --host=x86_64-pc-mingw32
 
 ac_add_options --enable-optimize
 ac_add_options --enable-debug
 
 ac_add_options --enable-clang-plugin
 
-. $topsrcdir/build/win64/mozconfig.vs-latest
+. $topsrcdir/build/win64/mozconfig.vs2015
 
 . "$topsrcdir/build/mozconfig.common.override"
 . "$topsrcdir/build/mozconfig.clang-cl"
--- a/browser/config/mozconfigs/win64/debug-asan
+++ b/browser/config/mozconfigs/win64/debug-asan
@@ -1,16 +1,16 @@
 MOZ_AUTOMATION_L10N_CHECK=0
 
 . "$topsrcdir/build/mozconfig.win-common"
 . "$topsrcdir/browser/config/mozconfigs/common"
 
 ac_add_options --enable-debug
 ac_add_options --enable-optimize="-O1"
 
-. "$topsrcdir/build/win64/mozconfig.vs-latest"
+. "$topsrcdir/build/win64/mozconfig.vs2015"
 
 . "$topsrcdir/build/win64/mozconfig.asan"
 
 export MOZ_PACKAGE_JSSHELL=1
 export MOZ_PKG_SPECIAL=asan
 
 . "$topsrcdir/build/mozconfig.common.override"
--- a/browser/config/mozconfigs/win64/nightly-asan
+++ b/browser/config/mozconfigs/win64/nightly-asan
@@ -1,16 +1,16 @@
 MOZ_AUTOMATION_L10N_CHECK=0
 
 . "$topsrcdir/build/mozconfig.win-common"
 . "$topsrcdir/browser/config/mozconfigs/common"
 
 ac_add_options --disable-debug
 ac_add_options --enable-optimize="-O2 -gline-tables-only"
 
-. "$topsrcdir/build/win64/mozconfig.vs-latest"
+. "$topsrcdir/build/win64/mozconfig.vs2015"
 
 . "$topsrcdir/build/win64/mozconfig.asan"
 
 export MOZ_PACKAGE_JSSHELL=1
 export MOZ_PKG_SPECIAL=asan
 
 . "$topsrcdir/build/mozconfig.common.override"
--- a/browser/config/tooltool-manifests/win32/releng.manifest
+++ b/browser/config/tooltool-manifests/win32/releng.manifest
@@ -1,21 +1,21 @@
 [
   {
     "size": 266240,
     "digest": "bb345b0e700ffab4d09436981f14b5de84da55a3f18a7f09ebc4364a4488acdeab8d46f447b12ac70f2da1444a68b8ce8b8675f0dae2ccf845e966d1df0f0869",
     "algorithm": "sha512",
     "filename": "mozmake.exe"
   },
   {
-    "version": "Visual Studio 2015 Update 3 14.0.25425.01 / SDK 10.0.14393.0",
-    "size": 326656969,
-    "digest": "babc414ffc0457d27f5a1ed24a8e4873afbe2f1c1a4075469a27c005e1babc3b2a788f643f825efedff95b79686664c67ec4340ed535487168a3482e68559bc7",
+    "version": "Visual Studio 2017 15.4.1 / SDK 10.0.16299.0",
+    "digest": "b22783f94d8c1304f9640e0cf0c614175c3f2e21f084bb08a31d5b3dc2f387e38a6917170eeb37e6446f191f2d685ca69c5e935f9d18ef41d16abf3a3b981d63",
+    "size": 322544627,
     "algorithm": "sha512",
-    "filename": "vs2015u3.zip",
+    "filename": "vs2017_15.4.1.zip",
     "unpack": true
   },
   {
     "version": "makecab rev d2bc6797648b7a834782714a55d339d2fd4e58c8",
     "algorithm": "sha512",
     "visibility": "public",
     "filename": "makecab.tar.bz2",
     "unpack": true,
copy from browser/config/tooltool-manifests/win32/releng.manifest
copy to browser/config/tooltool-manifests/win32/vs2015.manifest
--- a/browser/config/tooltool-manifests/win64/releng.manifest
+++ b/browser/config/tooltool-manifests/win64/releng.manifest
@@ -1,21 +1,21 @@
 [
   {
     "size": 266240,
     "digest": "bb345b0e700ffab4d09436981f14b5de84da55a3f18a7f09ebc4364a4488acdeab8d46f447b12ac70f2da1444a68b8ce8b8675f0dae2ccf845e966d1df0f0869",
     "algorithm": "sha512",
     "filename": "mozmake.exe"
   },
   {
-    "version": "Visual Studio 2015 Update 3 14.0.25425.01 / SDK 10.0.14393.0",
-    "size": 326656969,
-    "digest": "babc414ffc0457d27f5a1ed24a8e4873afbe2f1c1a4075469a27c005e1babc3b2a788f643f825efedff95b79686664c67ec4340ed535487168a3482e68559bc7",
+    "version": "Visual Studio 2017 15.4.1 / SDK 10.0.16299.0",
+    "digest": "b22783f94d8c1304f9640e0cf0c614175c3f2e21f084bb08a31d5b3dc2f387e38a6917170eeb37e6446f191f2d685ca69c5e935f9d18ef41d16abf3a3b981d63",
+    "size": 322544627,
     "algorithm": "sha512",
-    "filename": "vs2015u3.zip",
+    "filename": "vs2017_15.4.1.zip",
     "unpack": true
   },
   {
     "version": "makecab rev d2bc6797648b7a834782714a55d339d2fd4e58c8",
     "algorithm": "sha512",
     "visibility": "public",
     "filename": "makecab.tar.bz2",
     "unpack": true,
copy from browser/config/tooltool-manifests/win64/releng.manifest
copy to browser/config/tooltool-manifests/win64/vs2015.manifest
--- a/browser/experiments/Experiments.jsm
+++ b/browser/experiments/Experiments.jsm
@@ -21,18 +21,16 @@ XPCOMUtils.defineLazyModuleGetter(this, 
 XPCOMUtils.defineLazyModuleGetter(this, "AddonManager",
                                   "resource://gre/modules/AddonManager.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "AddonManagerPrivate",
                                   "resource://gre/modules/AddonManager.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "TelemetryEnvironment",
                                   "resource://gre/modules/TelemetryEnvironment.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "TelemetryLog",
                                   "resource://gre/modules/TelemetryLog.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "TelemetryUtils",
-                                  "resource://gre/modules/TelemetryUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "CommonUtils",
                                   "resource://services-common/utils.js");
 
 XPCOMUtils.defineLazyServiceGetter(this, "gCrashReporter",
                                    "@mozilla.org/xre/app-info;1",
                                    "nsICrashReporter");
 
 const FILE_CACHE                = "experiments.json";
@@ -47,18 +45,16 @@ const PREF_BRANCH               = "exper
 const PREF_ENABLED              = "enabled"; // experiments.enabled
 const PREF_ACTIVE_EXPERIMENT    = "activeExperiment"; // whether we have an active experiment
 const PREF_LOGGING              = "logging";
 const PREF_LOGGING_LEVEL        = PREF_LOGGING + ".level"; // experiments.logging.level
 const PREF_LOGGING_DUMP         = PREF_LOGGING + ".dump"; // experiments.logging.dump
 const PREF_MANIFEST_URI         = "manifest.uri"; // experiments.logging.manifest.uri
 const PREF_FORCE_SAMPLE         = "force-sample-value"; // experiments.force-sample-value
 
-const PREF_TELEMETRY_ENABLED      = "toolkit.telemetry.enabled";
-
 const URI_EXTENSION_STRINGS     = "chrome://mozapps/locale/extensions/extensions.properties";
 
 const CACHE_WRITE_RETRY_DELAY_SEC = 60 * 3;
 const MANIFEST_FETCH_TIMEOUT_MSEC = 60 * 3 * 1000; // 3 minutes
 
 const TELEMETRY_LOG = {
   // log(key, [kind, experimentId, details])
   ACTIVATION_KEY: "EXPERIMENT_ACTIVATION",
@@ -381,36 +377,32 @@ Experiments.Experiments.prototype = {
 
   observe(subject, topic, data) {
     switch (topic) {
       case PREF_CHANGED_TOPIC:
         if (data == PREF_BRANCH + PREF_MANIFEST_URI) {
           this.updateManifest();
         } else if (data == PREF_BRANCH + PREF_ENABLED) {
           this._toggleExperimentsEnabled(gPrefs.getBoolPref(PREF_ENABLED, false));
-        } else if (data == PREF_TELEMETRY_ENABLED) {
-          this._telemetryStatusChanged();
         }
         break;
     }
   },
 
   init() {
     this._shutdown = false;
     configureLogging();
 
-    gExperimentsEnabled = gPrefs.getBoolPref(PREF_ENABLED, false) && TelemetryUtils.isTelemetryEnabled;
+    gExperimentsEnabled = gPrefs.getBoolPref(PREF_ENABLED, false) && Services.telemetry.canRecordExtended;
     this._log.trace("enabled=" + gExperimentsEnabled + ", " + this.enabled);
 
     Services.prefs.addObserver(PREF_BRANCH + PREF_LOGGING, configureLogging);
     Services.prefs.addObserver(PREF_BRANCH + PREF_MANIFEST_URI, this, true);
     Services.prefs.addObserver(PREF_BRANCH + PREF_ENABLED, this, true);
 
-    Services.prefs.addObserver(PREF_TELEMETRY_ENABLED, this, true);
-
     AddonManager.shutdown.addBlocker("Experiments.jsm shutdown",
       this.uninit.bind(this),
       this._getState.bind(this)
     );
 
     this._registerWithAddonManager();
 
     this._loadTask = this._loadFromCache();
@@ -448,18 +440,16 @@ Experiments.Experiments.prototype = {
     if (!this._shutdown) {
       this._log.trace("uninit: no previous shutdown");
       this._unregisterWithAddonManager();
 
       Services.prefs.removeObserver(PREF_BRANCH + PREF_LOGGING, configureLogging);
       Services.prefs.removeObserver(PREF_BRANCH + PREF_MANIFEST_URI, this);
       Services.prefs.removeObserver(PREF_BRANCH + PREF_ENABLED, this);
 
-      Services.prefs.removeObserver(PREF_TELEMETRY_ENABLED, this);
-
       if (this._timer) {
         this._timer.clear();
       }
     }
 
     this._shutdown = true;
     if (this._mainTask) {
       if (this._networkRequest) {
@@ -593,36 +583,32 @@ Experiments.Experiments.prototype = {
   set enabled(enabled) {
     this._log.trace("set enabled(" + enabled + ")");
     gPrefs.setBoolPref(PREF_ENABLED, enabled);
   },
 
   async _toggleExperimentsEnabled(enabled) {
     this._log.trace("_toggleExperimentsEnabled(" + enabled + ")");
     let wasEnabled = gExperimentsEnabled;
-    gExperimentsEnabled = enabled && TelemetryUtils.isTelemetryEnabled;
+    gExperimentsEnabled = enabled && Services.telemetry.canRecordExtended;
 
     if (wasEnabled == gExperimentsEnabled) {
       return;
     }
 
     if (gExperimentsEnabled) {
       await this.updateManifest();
     } else {
       await this.disableExperiment(TELEMETRY_LOG.TERMINATION.SERVICE_DISABLED);
       if (this._timer) {
         this._timer.clear();
       }
     }
   },
 
-  _telemetryStatusChanged() {
-    this._toggleExperimentsEnabled(gPrefs.getBoolPref(PREF_ENABLED, false));
-  },
-
   /**
    * Returns a promise that is resolved with an array of `ExperimentInfo` objects,
    * which provide info on the currently and recently active experiments.
    * The array is in chronological order.
    *
    * The experiment info is of the form:
    * {
    *   id: <string>,
--- a/browser/experiments/test/xpcshell/head.js
+++ b/browser/experiments/test/xpcshell/head.js
@@ -21,17 +21,16 @@ Cu.import("resource://testing-common/Add
 XPCOMUtils.defineLazyModuleGetter(this, "AddonManager",
                                   "resource://gre/modules/AddonManager.jsm");
 
 const PREF_EXPERIMENTS_ENABLED  = "experiments.enabled";
 const PREF_LOGGING_LEVEL        = "experiments.logging.level";
 const PREF_LOGGING_DUMP         = "experiments.logging.dump";
 const PREF_MANIFEST_URI         = "experiments.manifest.uri";
 const PREF_FETCHINTERVAL        = "experiments.manifest.fetchIntervalSeconds";
-const PREF_TELEMETRY_ENABLED    = "toolkit.telemetry.enabled";
 
 function getExperimentPath(base) {
   let p = do_get_cwd();
   p.append(base);
   return p.path;
 }
 
 function sha1File(path) {
@@ -188,11 +187,9 @@ function replaceExperiments(experiment, 
   Object.defineProperty(experiment, "getExperiments", {
     writable: true,
     value: () => {
       return Promise.resolve(list);
     },
   });
 }
 
-// Experiments require Telemetry to be enabled, and that's not true for debug
-// builds. Let's just enable it here instead of going through each test.
-Services.prefs.setBoolPref(PREF_TELEMETRY_ENABLED, true);
+Services.telemetry.canRecordExtended = true;
--- a/browser/experiments/test/xpcshell/test_telemetry_disabled.js
+++ b/browser/experiments/test/xpcshell/test_telemetry_disabled.js
@@ -5,24 +5,16 @@
 
 Cu.import("resource:///modules/experiments/Experiments.jsm");
 
 add_test(function test_experiments_activation() {
   do_get_profile();
   loadAddonManager();
 
   Services.prefs.setBoolPref(PREF_EXPERIMENTS_ENABLED, true);
-  Services.prefs.setBoolPref(PREF_TELEMETRY_ENABLED, false);
+  Services.telemetry.canRecordExtended = false;
 
   let experiments = Experiments.instance();
 
   Assert.ok(!experiments.enabled, "Experiments must be disabled if Telemetry is disabled.");
 
-  // Patch updateManifest to not do anything when the pref is switched back to true,
-  // otherwise it attempts to connect to the server.
-  experiments.updateManifest = () => Promise.resolve();
-
-  Services.prefs.setBoolPref(PREF_TELEMETRY_ENABLED, true);
-
-  Assert.ok(experiments.enabled, "Experiments must be re-enabled if Telemetry is re-enabled");
-
   run_next_test();
 });
--- a/browser/modules/test/browser/browser_UsageTelemetry_content.js
+++ b/browser/modules/test/browser/browser_UsageTelemetry_content.js
@@ -20,17 +20,16 @@ add_task(async function setup() {
   Services.search.currentEngine = engineDefault;
 
   // Move the second engine at the beginning of the one-off list.
   let engineOneOff = Services.search.getEngineByName("MozSearch2");
   Services.search.moveEngine(engineOneOff, 0);
 
   await SpecialPowers.pushPrefEnv({"set": [
     ["dom.select_events.enabled", true], // We want select events to be fired.
-    ["toolkit.telemetry.enabled", true]  // And Extended Telemetry to be enabled.
   ]});
 
   // Enable event recording for the events tested here.
   Services.telemetry.setEventRecordingEnabled("navigation", true);
 
   // Make sure to restore the engine once we're done.
   registerCleanupFunction(async function() {
     Services.search.currentEngine = originalEngine;
--- a/browser/modules/test/browser/browser_UsageTelemetry_content_aboutHome.js
+++ b/browser/modules/test/browser/browser_UsageTelemetry_content_aboutHome.js
@@ -22,19 +22,16 @@ add_task(async function setup() {
   let engineDefault = Services.search.getEngineByName("MozSearch");
   let originalEngine = Services.search.currentEngine;
   Services.search.currentEngine = engineDefault;
 
   // Move the second engine at the beginning of the one-off list.
   let engineOneOff = Services.search.getEngineByName("MozSearch2");
   Services.search.moveEngine(engineOneOff, 0);
 
-  // Enable Extended Telemetry.
-  await SpecialPowers.pushPrefEnv({"set": [["toolkit.telemetry.enabled", true]]});
-
   // Enable event recording for the events tested here.
   Services.telemetry.setEventRecordingEnabled("navigation", true);
 
   // Make sure to restore the engine once we're done.
   registerCleanupFunction(async function() {
     Services.search.currentEngine = originalEngine;
     Services.search.removeEngine(engineDefault);
     Services.search.removeEngine(engineOneOff);
--- a/browser/modules/test/browser/browser_UsageTelemetry_searchbar.js
+++ b/browser/modules/test/browser/browser_UsageTelemetry_searchbar.js
@@ -85,19 +85,16 @@ add_task(async function setup() {
   // Move the second engine at the beginning of the one-off list.
   let engineOneOff = Services.search.getEngineByName("MozSearch2");
   Services.search.moveEngine(engineOneOff, 0);
 
   // Enable local telemetry recording for the duration of the tests.
   let oldCanRecord = Services.telemetry.canRecordExtended;
   Services.telemetry.canRecordExtended = true;
 
-  // Enable Extended Telemetry.
-  await SpecialPowers.pushPrefEnv({"set": [["toolkit.telemetry.enabled", true]]});
-
   // Enable event recording for the events tested here.
   Services.telemetry.setEventRecordingEnabled("navigation", true);
 
   // Make sure to restore the engine once we're done.
   registerCleanupFunction(function() {
     Services.telemetry.canRecordExtended = oldCanRecord;
     Services.search.currentEngine = originalEngine;
     Services.search.removeEngine(engineDefault);
--- a/browser/modules/test/browser/browser_UsageTelemetry_urlbar.js
+++ b/browser/modules/test/browser/browser_UsageTelemetry_urlbar.js
@@ -84,19 +84,16 @@ add_task(async function setup() {
 
   // Enable search suggestions in the urlbar.
   let suggestionsEnabled = Services.prefs.getBoolPref(SUGGEST_URLBAR_PREF);
   Services.prefs.setBoolPref(SUGGEST_URLBAR_PREF, true);
 
   // Enable the urlbar one-off buttons.
   Services.prefs.setBoolPref(ONEOFF_URLBAR_PREF, true);
 
-  // Enable Extended Telemetry.
-  await SpecialPowers.pushPrefEnv({"set": [["toolkit.telemetry.enabled", true]]});
-
   // Enable local telemetry recording for the duration of the tests.
   let oldCanRecord = Services.telemetry.canRecordExtended;
   Services.telemetry.canRecordExtended = true;
 
   // Enable event recording for the events tested here.
   Services.telemetry.setEventRecordingEnabled("navigation", true);
 
   // Clear history so that history added by previous tests doesn't mess up this
--- a/build/win32/mozconfig.vs-latest
+++ b/build/win32/mozconfig.vs-latest
@@ -1,1 +1,1 @@
-. $topsrcdir/build/win32/mozconfig.vs2015-win64
+. $topsrcdir/build/win32/mozconfig.vs2017
--- a/build/win64/mozconfig.vs-latest
+++ b/build/win64/mozconfig.vs-latest
@@ -1,1 +1,1 @@
-. $topsrcdir/build/win64/mozconfig.vs2015
+. $topsrcdir/build/win64/mozconfig.vs2017
--- a/dom/base/FragmentOrElement.cpp
+++ b/dom/base/FragmentOrElement.cpp
@@ -489,92 +489,164 @@ static bool
 NeedsScriptTraverse(nsINode* aNode)
 {
   return aNode->PreservingWrapper() && aNode->GetWrapperPreserveColor() &&
          !aNode->HasKnownLiveWrapperAndDoesNotNeedTracing(aNode);
 }
 
 //----------------------------------------------------------------------
 
-NS_IMPL_CYCLE_COLLECTING_ADDREF(nsChildContentList)
-NS_IMPL_CYCLE_COLLECTING_RELEASE(nsChildContentList)
+NS_IMPL_CYCLE_COLLECTING_ADDREF(nsAttrChildContentList)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(nsAttrChildContentList)
 
-// If nsChildContentList is changed so that any additional fields are
+// If nsAttrChildContentList is changed so that any additional fields are
 // traversed by the cycle collector, then CAN_SKIP must be updated to
 // check that the additional fields are null.
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(nsChildContentList)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(nsAttrChildContentList)
 
-// nsChildContentList only ever has a single child, its wrapper, so if
+// nsAttrChildContentList only ever has a single child, its wrapper, so if
 // the wrapper is known-live, the list can't be part of a garbage cycle.
-NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsChildContentList)
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsAttrChildContentList)
   return tmp->HasKnownLiveWrapper();
 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
 
-NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsChildContentList)
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsAttrChildContentList)
   return tmp->HasKnownLiveWrapperAndDoesNotNeedTracing(tmp);
 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
 
 // CanSkipThis returns false to avoid problems with incomplete unlinking.
-NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(nsChildContentList)
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(nsAttrChildContentList)
 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
 
-NS_INTERFACE_TABLE_HEAD(nsChildContentList)
+NS_INTERFACE_TABLE_HEAD(nsAttrChildContentList)
   NS_WRAPPERCACHE_INTERFACE_TABLE_ENTRY
-  NS_INTERFACE_TABLE(nsChildContentList, nsINodeList, nsIDOMNodeList)
-  NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(nsChildContentList)
+  NS_INTERFACE_TABLE(nsAttrChildContentList, nsINodeList, nsIDOMNodeList)
+  NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(nsAttrChildContentList)
 NS_INTERFACE_MAP_END
 
 JSObject*
-nsChildContentList::WrapObject(JSContext *cx, JS::Handle<JSObject*> aGivenProto)
+nsAttrChildContentList::WrapObject(JSContext *cx,
+                                   JS::Handle<JSObject*> aGivenProto)
 {
   return NodeListBinding::Wrap(cx, this, aGivenProto);
 }
 
 NS_IMETHODIMP
-nsChildContentList::GetLength(uint32_t* aLength)
+nsAttrChildContentList::GetLength(uint32_t* aLength)
 {
   *aLength = mNode ? mNode->GetChildCount() : 0;
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsChildContentList::Item(uint32_t aIndex, nsIDOMNode** aReturn)
+nsAttrChildContentList::Item(uint32_t aIndex, nsIDOMNode** aReturn)
 {
   nsINode* node = Item(aIndex);
   if (!node) {
     *aReturn = nullptr;
 
     return NS_OK;
   }
 
   return CallQueryInterface(node, aReturn);
 }
 
 nsIContent*
-nsChildContentList::Item(uint32_t aIndex)
+nsAttrChildContentList::Item(uint32_t aIndex)
 {
   if (mNode) {
     return mNode->GetChildAt(aIndex);
   }
 
   return nullptr;
 }
 
 int32_t
-nsChildContentList::IndexOf(nsIContent* aContent)
+nsAttrChildContentList::IndexOf(nsIContent* aContent)
 {
   if (mNode) {
     return mNode->IndexOf(aContent);
   }
 
   return -1;
 }
 
 //----------------------------------------------------------------------
+NS_IMETHODIMP
+nsParentNodeChildContentList::GetLength(uint32_t* aLength)
+{
+  if (!mIsCacheValid && !ValidateCache()) {
+    *aLength = 0;
+    return NS_OK;
+  }
+
+  MOZ_ASSERT(mIsCacheValid);
+
+  *aLength = mCachedChildArray.Length();
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsParentNodeChildContentList::Item(uint32_t aIndex, nsIDOMNode** aReturn)
+{
+  nsINode* node = Item(aIndex);
+  if (!node) {
+    *aReturn = nullptr;
+    return NS_OK;
+  }
+
+  return CallQueryInterface(node, aReturn);
+}
+
+nsIContent*
+nsParentNodeChildContentList::Item(uint32_t aIndex)
+{
+  if (!mIsCacheValid && !ValidateCache()) {
+    return nullptr;
+  }
+
+  MOZ_ASSERT(mIsCacheValid);
+
+  return mCachedChildArray.SafeElementAt(aIndex, nullptr);
+}
+
+int32_t
+nsParentNodeChildContentList::IndexOf(nsIContent* aContent)
+{
+  if (!mIsCacheValid && !ValidateCache()) {
+    return -1;
+  }
+
+  MOZ_ASSERT(mIsCacheValid);
+
+  return mCachedChildArray.IndexOf(aContent);
+}
+
+bool
+nsParentNodeChildContentList::ValidateCache()
+{
+  MOZ_ASSERT(!mIsCacheValid);
+  MOZ_ASSERT(mCachedChildArray.IsEmpty());
+
+  nsINode* parent = GetParentObject();
+  if (!parent) {
+    return false;
+  }
+
+  for (nsIContent* node = parent->GetFirstChild(); node;
+       node = node->GetNextSibling()) {
+    mCachedChildArray.AppendElement(node);
+  }
+  mIsCacheValid = true;
+
+  return true;
+}
+
+//----------------------------------------------------------------------
 
 nsIHTMLCollection*
 FragmentOrElement::Children()
 {
   FragmentOrElement::nsDOMSlots *slots = DOMSlots();
 
   if (!slots->mChildrenList) {
     slots->mChildrenList = new nsContentList(this, kNameSpaceID_Wildcard,
@@ -1364,16 +1436,19 @@ public:
   {
     if (aNode->NodeType() != nsIDOMNode::ELEMENT_NODE &&
         aNode->NodeType() != nsIDOMNode::DOCUMENT_FRAGMENT_NODE) {
       return;
     }
     FragmentOrElement* container = static_cast<FragmentOrElement*>(aNode);
     uint32_t childCount = container->mAttrsAndChildren.ChildCount();
     if (childCount) {
+      // Invalidate cached array of child nodes
+      container->InvalidateChildNodes();
+
       while (childCount-- > 0) {
         // Hold a strong ref to the node when we remove it, because we may be
         // the last reference to it.  We need to call TakeChildAt() and
         // update mFirstChild before calling UnbindFromTree, since this last
         // can notify various observers and they should really see consistent
         // tree state.
         // If this code changes, change the corresponding code in
         // FragmentOrElement's and nsDocument's unlink impls.
--- a/dom/base/nsAttrAndChildArray.h
+++ b/dom/base/nsAttrAndChildArray.h
@@ -58,20 +58,16 @@ public:
   }
   nsIContent* ChildAt(uint32_t aPos) const
   {
     NS_ASSERTION(aPos < ChildCount(), "out-of-bounds access in nsAttrAndChildArray");
     return reinterpret_cast<nsIContent*>(mImpl->mBuffer[AttrSlotsSize() + aPos]);
   }
   nsIContent* GetSafeChildAt(uint32_t aPos) const;
   nsIContent * const * GetChildArray(uint32_t* aChildCount) const;
-  nsresult AppendChild(nsIContent* aChild)
-  {
-    return InsertChildAt(aChild, ChildCount());
-  }
   nsresult InsertChildAt(nsIContent* aChild, uint32_t aPos);
   void RemoveChildAt(uint32_t aPos);
   // Like RemoveChildAt but hands the reference to the child being
   // removed back to the caller instead of just releasing it.
   already_AddRefed<nsIContent> TakeChildAt(uint32_t aPos);
   int32_t IndexOfChild(const nsINode* aPossibleChild) const;
 
   bool HasAttrs() const
--- a/dom/base/nsChildContentList.h
+++ b/dom/base/nsChildContentList.h
@@ -3,61 +3,105 @@
 /* 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/. */
 
 #ifndef nsChildContentList_h__
 #define nsChildContentList_h__
 
 #include "nsISupportsImpl.h"
-#include "nsINodeList.h"            // base class
+#include "nsINodeList.h"      // base class
 #include "js/TypeDecls.h"     // for Handle, Value, JSObject, JSContext
 
 class nsIContent;
 class nsINode;
 
 /**
  * Class that implements the nsIDOMNodeList interface (a list of children of
  * the content), by holding a reference to the content and delegating GetLength
  * and Item to its existing child list.
  * @see nsIDOMNodeList
  */
-class nsChildContentList final : public nsINodeList
+class nsAttrChildContentList : public nsINodeList
 {
 public:
-  explicit nsChildContentList(nsINode* aNode)
+  explicit nsAttrChildContentList(nsINode* aNode)
     : mNode(aNode)
   {
   }
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
-  NS_DECL_CYCLE_COLLECTION_SKIPPABLE_SCRIPT_HOLDER_CLASS(nsChildContentList)
+  NS_DECL_CYCLE_COLLECTION_SKIPPABLE_SCRIPT_HOLDER_CLASS(nsAttrChildContentList)
 
   // nsWrapperCache
-  virtual JSObject* WrapObject(JSContext *cx, JS::Handle<JSObject*> aGivenProto) override;
+  virtual JSObject* WrapObject(JSContext *cx,
+                               JS::Handle<JSObject*> aGivenProto) override;
 
   // nsIDOMNodeList interface
   NS_DECL_NSIDOMNODELIST
 
   // nsINodeList interface
   virtual int32_t IndexOf(nsIContent* aContent) override;
   virtual nsIContent* Item(uint32_t aIndex) override;
 
-  void DropReference()
+  virtual void DropReference()
   {
     mNode = nullptr;
   }
 
   virtual nsINode* GetParentObject() override
   {
     return mNode;
   }
 
+protected:
+  virtual ~nsAttrChildContentList() {}
+
 private:
-  ~nsChildContentList() {}
-
   // The node whose children make up the list.
   // This is a non-owning ref which is safe because it's set to nullptr by
   // DropReference() by the node slots get destroyed.
   nsINode* MOZ_NON_OWNING_REF mNode;
 };
 
+class nsParentNodeChildContentList final : public nsAttrChildContentList
+{
+public:
+  explicit nsParentNodeChildContentList(nsINode* aNode)
+    : nsAttrChildContentList(aNode)
+    , mIsCacheValid(false)
+  {
+    ValidateCache();
+  }
+
+  // nsIDOMNodeList interface
+  NS_DECL_NSIDOMNODELIST
+
+  // nsINodeList interface
+  virtual int32_t IndexOf(nsIContent* aContent) override;
+  virtual nsIContent* Item(uint32_t aIndex) override;
+
+  void DropReference() override
+  {
+    InvalidateCache();
+    nsAttrChildContentList::DropReference();
+  }
+
+  void InvalidateCache()
+  {
+    mIsCacheValid = false;
+    mCachedChildArray.Clear();
+  }
+
+private:
+  ~nsParentNodeChildContentList() {}
+
+  // Return true if validation succeeds, false otherwise
+  bool ValidateCache();
+
+  // Whether cached array of child nodes is valid
+  bool mIsCacheValid;
+
+  // Cached array of child nodes
+  AutoTArray<nsIContent*, 8> mCachedChildArray;
+};
+
 #endif /* nsChildContentList_h__ */
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -1557,16 +1557,17 @@ nsIDocument::nsIDocument()
     mDidFireDOMContentLoaded(true),
     mHasScrollLinkedEffect(false),
     mFrameRequestCallbacksScheduled(false),
     mIsTopLevelContentDocument(false),
     mIsContentDocument(false),
     mMightHaveStaleServoData(false),
     mDidCallBeginLoad(false),
     mBufferingCSPViolations(false),
+    mAllowPaymentRequest(false),
     mIsScopedStyleEnabled(eScopedStyle_Unknown),
     mCompatMode(eCompatibility_FullStandards),
     mReadyState(ReadyState::READYSTATE_UNINITIALIZED),
     mStyleBackendType(StyleBackendType::None),
 #ifdef MOZILLA_INTERNAL_API
     mVisibilityState(dom::VisibilityState::Hidden),
 #else
     mDummy(0),
@@ -1809,16 +1810,19 @@ nsDocument::~nsDocument()
   mSubDocuments = nullptr;
 
   // Destroy link map now so we don't waste time removing
   // links one by one
   DestroyElementMaps();
 
   nsAutoScriptBlocker scriptBlocker;
 
+  // Invalidate cached array of child nodes
+  InvalidateChildNodes();
+
   for (uint32_t indx = mChildren.ChildCount(); indx-- != 0; ) {
     mChildren.ChildAt(indx)->UnbindFromTree();
     mChildren.RemoveChildAt(indx);
   }
   mFirstChild = nullptr;
   mCachedRootElement = nullptr;
 
   // Let the stylesheets know we're going away
@@ -2363,16 +2367,20 @@ nsDocument::ResetToURI(nsIURI *aURI, nsI
   // links one by one
   DestroyElementMaps();
 
   bool oldVal = mInUnlinkOrDeletion;
   mInUnlinkOrDeletion = true;
   uint32_t count = mChildren.ChildCount();
   { // Scope for update
     MOZ_AUTO_DOC_UPDATE(this, UPDATE_CONTENT_MODEL, true);
+
+    // Invalidate cached array of child nodes
+    InvalidateChildNodes();
+
     for (int32_t i = int32_t(count) - 1; i >= 0; i--) {
       nsCOMPtr<nsIContent> content = mChildren.ChildAt(i);
 
       nsIContent* previousSibling = content->GetPreviousSibling();
 
       if (nsINode::GetFirstChild() == content) {
         mFirstChild = content->GetNextSibling();
       }
@@ -4291,25 +4299,41 @@ SubDocInitEntry(PLDHashEntryHdr *entry, 
               (static_cast<const SubDocMapEntry *>(entry));
 
   e->mKey = const_cast<Element*>(static_cast<const Element*>(key));
   NS_ADDREF(e->mKey);
 
   e->mSubDocument = nullptr;
 }
 
+bool
+nsDocument::AllowPaymentRequest() const
+{
+  return mAllowPaymentRequest;
+}
+
+void
+nsDocument::SetAllowPaymentRequest(bool aAllowPaymentRequest)
+{
+  mAllowPaymentRequest = aAllowPaymentRequest;
+}
+
 nsresult
 nsDocument::SetSubDocumentFor(Element* aElement, nsIDocument* aSubDoc)
 {
   NS_ENSURE_TRUE(aElement, NS_ERROR_UNEXPECTED);
 
   if (!aSubDoc) {
     // aSubDoc is nullptr, remove the mapping
 
     if (mSubDocuments) {
+      nsIDocument* subDoc = GetSubDocumentFor(aElement);
+      if (subDoc) {
+        subDoc->SetAllowPaymentRequest(false);
+      }
       mSubDocuments->Remove(aElement);
     }
   } else {
     if (!mSubDocuments) {
       // Create a new hashtable
 
       static const PLDHashTableOps hash_table_ops =
       {
@@ -4327,25 +4351,43 @@ nsDocument::SetSubDocumentFor(Element* a
     auto entry =
       static_cast<SubDocMapEntry*>(mSubDocuments->Add(aElement, fallible));
 
     if (!entry) {
       return NS_ERROR_OUT_OF_MEMORY;
     }
 
     if (entry->mSubDocument) {
+      entry->mSubDocument->SetAllowPaymentRequest(false);
       entry->mSubDocument->SetParentDocument(nullptr);
 
       // Release the old sub document
       NS_RELEASE(entry->mSubDocument);
     }
 
     entry->mSubDocument = aSubDoc;
     NS_ADDREF(entry->mSubDocument);
 
+    // set allowpaymentrequest for the binding subdocument
+    if (!mAllowPaymentRequest) {
+      aSubDoc->SetAllowPaymentRequest(false);
+    } else {
+      nsresult rv = nsContentUtils::CheckSameOrigin(aElement, aSubDoc);
+      if (NS_SUCCEEDED(rv)) {
+        aSubDoc->SetAllowPaymentRequest(true);
+      } else {
+        if (aElement->IsHTMLElement(nsGkAtoms::iframe) &&
+            aElement->GetBoolAttr(nsGkAtoms::allowpaymentrequest)) {
+          aSubDoc->SetAllowPaymentRequest(true);
+        } else {
+          aSubDoc->SetAllowPaymentRequest(false);
+        }
+      }
+    }
+
     aSubDoc->SetParentDocument(this);
   }
 
   return NS_OK;
 }
 
 nsIDocument*
 nsDocument::GetSubDocumentFor(nsIContent *aContent) const
--- a/dom/base/nsDocument.h
+++ b/dom/base/nsDocument.h
@@ -955,16 +955,19 @@ public:
 
   // Returns the top element from the full-screen stack.
   Element* FullScreenStackTop();
 
   // DOM-exposed fullscreen API
   bool FullscreenEnabled(mozilla::dom::CallerType aCallerType) override;
   Element* GetFullscreenElement() override;
 
+  virtual bool AllowPaymentRequest() const override;
+  virtual void SetAllowPaymentRequest(bool aIsAllowPaymentRequest) override;
+
   void RequestPointerLock(Element* aElement,
                           mozilla::dom::CallerType aCallerType) override;
   bool SetPointerLock(Element* aElement, int aCursorStyle);
   static void UnlockPointer(nsIDocument* aDoc = nullptr);
 
   void SetCurrentOrientation(mozilla::dom::OrientationType aType,
                              uint16_t aAngle) override;
   uint16_t CurrentOrientationAngle() const override;
--- a/dom/base/nsIDocument.h
+++ b/dom/base/nsIDocument.h
@@ -1841,16 +1841,22 @@ public:
   }
 
   virtual bool IsScriptEnabled() = 0;
 
   bool IsTopLevelContentDocument() const { return mIsTopLevelContentDocument; }
   void SetIsTopLevelContentDocument(bool aIsTopLevelContentDocument)
   {
     mIsTopLevelContentDocument = aIsTopLevelContentDocument;
+    // When a document is set as TopLevelContentDocument, it must be
+    // allowpaymentrequest. We handle the false case while a document is appended
+    // in SetSubDocumentFor
+    if (aIsTopLevelContentDocument) {
+      SetAllowPaymentRequest(true);
+    }
   }
 
   bool IsContentDocument() const { return mIsContentDocument; }
   void SetIsContentDocument(bool aIsContentDocument)
   {
     mIsContentDocument = aIsContentDocument;
   }
 
@@ -3206,16 +3212,19 @@ public:
   }
 
   void DecrementThrowOnDynamicMarkupInsertionCounter()
   {
     MOZ_ASSERT(mThrowOnDynamicMarkupInsertionCounter);
     --mThrowOnDynamicMarkupInsertionCounter;
   }
 
+  virtual bool AllowPaymentRequest() const = 0;
+  virtual void SetAllowPaymentRequest(bool aAllowPaymentRequest) = 0;
+
 protected:
   bool GetUseCounter(mozilla::UseCounter aUseCounter)
   {
     return mUseCounters[aUseCounter];
   }
 
   void SetChildDocumentUseCounter(mozilla::UseCounter aUseCounter)
   {
@@ -3546,16 +3555,19 @@ protected:
 
   // True if we have called BeginLoad and are expecting a paired EndLoad call.
   bool mDidCallBeginLoad : 1;
 
   // True if any CSP violation reports for this doucment will be buffered in
   // mBufferedCSPViolations instead of being sent immediately.
   bool mBufferingCSPViolations : 1;
 
+  // True if the document is allowed to use PaymentRequest.
+  bool mAllowPaymentRequest : 1;
+
   // Whether <style scoped> support is enabled in this document.
   enum { eScopedStyle_Unknown, eScopedStyle_Disabled, eScopedStyle_Enabled };
   unsigned int mIsScopedStyleEnabled : 2;
 
   // Compatibility mode
   nsCompatibility mCompatMode;
 
   // Our readyState
--- a/dom/base/nsINode.cpp
+++ b/dom/base/nsINode.cpp
@@ -404,23 +404,42 @@ nsINode::GetSelectionRootContent(nsIPres
   return content;
 }
 
 nsINodeList*
 nsINode::ChildNodes()
 {
   nsSlots* slots = Slots();
   if (!slots->mChildNodes) {
-    slots->mChildNodes = new nsChildContentList(this);
+    // Check |!IsElement()| first to catch the common case
+    // without virtual call |IsNodeOfType|
+    slots->mChildNodes = !IsElement() && IsNodeOfType(nsINode::eATTRIBUTE) ?
+                           new nsAttrChildContentList(this) :
+                           new nsParentNodeChildContentList(this);
   }
 
   return slots->mChildNodes;
 }
 
 void
+nsINode::InvalidateChildNodes()
+{
+  MOZ_ASSERT(IsElement() || !IsNodeOfType(nsINode::eATTRIBUTE));
+
+  nsSlots* slots = GetExistingSlots();
+  if (!slots || !slots->mChildNodes) {
+    return;
+  }
+
+  auto childNodes =
+    static_cast<nsParentNodeChildContentList*>(slots->mChildNodes.get());
+  childNodes->InvalidateCache();
+}
+
+void
 nsINode::GetTextContentInternal(nsAString& aTextContent, OOMReporter& aError)
 {
   SetDOMStringToNull(aTextContent);
 }
 
 nsIDocument*
 nsINode::GetComposedDocInternal() const
 {
@@ -1547,18 +1566,18 @@ CheckForOutdatedParent(nsINode* aParent,
     }
   }
 }
 
 nsresult
 nsINode::doInsertChildAt(nsIContent* aKid, uint32_t aIndex,
                          bool aNotify, nsAttrAndChildArray& aChildArray)
 {
-  NS_PRECONDITION(!aKid->GetParentNode(),
-                  "Inserting node that already has parent");
+  MOZ_ASSERT(!aKid->GetParentNode(), "Inserting node that already has parent");
+  MOZ_ASSERT(!IsNodeOfType(nsINode::eATTRIBUTE));
 
   // The id-handling code, and in the future possibly other code, need to
   // react to unexpected attribute changes.
   nsMutationGuard::DidMutate();
 
   // Do this before checking the child-count since this could cause mutations
   nsIDocument* doc = GetUncomposedDoc();
   mozAutoDocUpdate updateBatch(GetComposedDoc(), UPDATE_CONTENT_MODEL, aNotify);
@@ -1607,16 +1626,19 @@ nsINode::doInsertChildAt(nsIContent* aKi
     if (GetFirstChild() == aKid) {
       mFirstChild = aKid->GetNextSibling();
     }
     aChildArray.RemoveChildAt(aIndex);
     aKid->UnbindFromTree();
     return rv;
   }
 
+  // Invalidate cached array of child nodes
+  InvalidateChildNodes();
+
   NS_ASSERTION(aKid->GetParentNode() == this,
                "Did we run script inappropriately?");
 
   if (aNotify) {
     // Note that we always want to call ContentInserted when things are added
     // as kids to documents
     if (parent && isAppend) {
       nsNodeUtils::ContentAppended(parent, aKid);
@@ -1897,31 +1919,35 @@ nsINode::Append(const Sequence<OwningNod
 void
 nsINode::doRemoveChildAt(uint32_t aIndex, bool aNotify,
                          nsIContent* aKid, nsAttrAndChildArray& aChildArray)
 {
   // NOTE: This function must not trigger any calls to
   // nsIDocument::GetRootElement() calls until *after* it has removed aKid from
   // aChildArray. Any calls before then could potentially restore a stale
   // value for our cached root element, per note in nsDocument::RemoveChildAt().
-  NS_PRECONDITION(aKid && aKid->GetParentNode() == this &&
-                  aKid == GetChildAt(aIndex) &&
-                  IndexOf(aKid) == (int32_t)aIndex, "Bogus aKid");
+  MOZ_ASSERT(aKid && aKid->GetParentNode() == this &&
+             aKid == GetChildAt(aIndex) &&
+             IndexOf(aKid) == (int32_t)aIndex, "Bogus aKid");
+  MOZ_ASSERT(!IsNodeOfType(nsINode::eATTRIBUTE));
 
   nsMutationGuard::DidMutate();
   mozAutoDocUpdate updateBatch(GetComposedDoc(), UPDATE_CONTENT_MODEL, aNotify);
 
   nsIContent* previousSibling = aKid->GetPreviousSibling();
 
   if (GetFirstChild() == aKid) {
     mFirstChild = aKid->GetNextSibling();
   }
 
   aChildArray.RemoveChildAt(aIndex);
 
+  // Invalidate cached array of child nodes
+  InvalidateChildNodes();
+
   if (aNotify) {
     nsNodeUtils::ContentRemoved(this, aKid, previousSibling);
   }
 
   aKid->UnbindFromTree();
 }
 
 // When replacing, aRefChild is the content being replaced; when
--- a/dom/base/nsINode.h
+++ b/dom/base/nsINode.h
@@ -31,17 +31,17 @@
 // Including 'windows.h' will #define GetClassInfo to something else.
 #ifdef XP_WIN
 #ifdef GetClassInfo
 #undef GetClassInfo
 #endif
 #endif
 
 class nsAttrAndChildArray;
-class nsChildContentList;
+class nsAttrChildContentList;
 struct nsCSSSelectorList;
 class nsDOMAttributeMap;
 class nsIAnimationObserver;
 class nsIContent;
 class nsIDocument;
 class nsIDOMElement;
 class nsIDOMNodeList;
 class nsIFrame;
@@ -1107,17 +1107,17 @@ public:
      */
     nsAutoTObserverArray<nsIMutationObserver*, 1> mMutationObservers;
 
     /**
      * An object implementing nsIDOMNodeList for this content (childNodes)
      * @see nsIDOMNodeList
      * @see nsGenericHTMLElement::GetChildNodes
      */
-    RefPtr<nsChildContentList> mChildNodes;
+    RefPtr<nsAttrChildContentList> mChildNodes;
 
     /**
      * Weak reference to this node.  This is cleared by the destructor of
      * nsNodeWeakReference.
      */
     nsNodeWeakReference* MOZ_NON_OWNING_REF mWeakReference;
 
     /**
@@ -1973,16 +1973,22 @@ protected:
     return GetExistingSlots();
   }
 
   nsAutoTObserverArray<nsIMutationObserver*, 1> *GetMutationObservers()
   {
     return HasSlots() ? &GetExistingSlots()->mMutationObservers : nullptr;
   }
 
+  /**
+   * Invalidate cached child array inside mChildNodes
+   * of type nsParentNodeChildContentList.
+   */
+  void InvalidateChildNodes();
+
   bool IsEditableInternal() const;
   virtual bool IsEditableExternal() const
   {
     return IsEditableInternal();
   }
 
   virtual void GetTextContentInternal(nsAString& aTextContent,
                                       mozilla::OOMReporter& aError);
--- a/dom/base/test/mochitest.ini
+++ b/dom/base/test/mochitest.ini
@@ -621,16 +621,17 @@ skip-if = toolkit == 'android'
 [test_bug1307730.html]
 [test_bug1308069.html]
 [test_bug1314032.html]
 [test_bug1318303.html]
 [test_bug1375050.html]
 [test_bug1381710.html]
 [test_bug1384658.html]
 skip-if = toolkit == 'android'
+[test_bug1384661.html]
 [test_bug1399603.html]
 [test_bug1399605.html]
 [test_bug1404385.html]
 [test_bug1406102.html]
 [test_caretPositionFromPoint.html]
 [test_change_policy.html]
 [test_clearTimeoutIntervalNoArg.html]
 [test_constructor-assignment.html]
new file mode 100644
--- /dev/null
+++ b/dom/base/test/test_bug1384661.html
@@ -0,0 +1,49 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1384661
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 1384661</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+  <script type="application/javascript">
+
+  /** Test for Bug 1384661 **/
+
+  SimpleTest.waitForExplicitFinish();
+
+  function runTest() {
+    for (var p in document) {
+      typeof(document[p]);
+    }
+
+    // Overwrite document
+    var doc = document.implementation.createDocument(null, 'xml', null);
+    doc.load("");
+    var str = new XMLSerializer().serializeToString(doc);
+    document.write(str);
+
+    // Check if childNodes of overwritten document is changed accordingly
+    is(document.childNodes.length, 0,
+       "childNodes.length of overwritten document should be 0");
+    is(document.childNodes[0], undefined,
+       "childNodes[0] of overwritten document should be undefined");
+
+    SimpleTest.finish();
+  }
+
+
+  </script>
+</head>
+<body onload="runTest()">
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1384661">Mozilla Bug 1384661</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
--- a/dom/file/MutableBlobStorage.cpp
+++ b/dom/file/MutableBlobStorage.cpp
@@ -647,18 +647,20 @@ MutableBlobStorage::AskForBlob(Temporary
 }
 
 void
 MutableBlobStorage::ErrorPropagated(nsresult aRv)
 {
   MOZ_ASSERT(NS_IsMainThread());
   mErrorResult = aRv;
 
-  mActor->SendOperationDone(false, EmptyCString());
-  mActor = nullptr;
+  if (mActor) {
+    mActor->SendOperationDone(false, EmptyCString());
+    mActor = nullptr;
+  }
 }
 
 void
 MutableBlobStorage::DispatchToIOThread(already_AddRefed<nsIRunnable> aRunnable)
 {
   if (!mTaskQueue) {
     nsCOMPtr<nsIEventTarget> target
       = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
--- a/dom/ipc/tests/browser_memory_distribution_telemetry.js
+++ b/dom/ipc/tests/browser_memory_distribution_telemetry.js
@@ -21,17 +21,16 @@ add_task(async function test_memory_dist
   waitForExplicitFinish();
 
   if (SpecialPowers.getIntPref("dom.ipc.processCount", 1) < 2) {
     ok(true, "Skip this test if e10s-multi is disabled.");
     finish();
     return;
   }
 
-  await SpecialPowers.pushPrefEnv({set: [["toolkit.telemetry.enabled", true]]});
   Services.telemetry.canRecordExtended = true;
 
   let histogram = Services.telemetry.getKeyedHistogramById("MEMORY_DISTRIBUTION_AMONG_CONTENT");
   histogram.clear();
 
   let tab1 = await BrowserTestUtils.openNewForegroundTab(gBrowser, DUMMY_PAGE_DATA_URI);
   let tab2 = await BrowserTestUtils.openNewForegroundTab(gBrowser, DUMMY_PAGE_DATA_URI);
   let tab3 = await BrowserTestUtils.openNewForegroundTab(gBrowser, DUMMY_PAGE_DATA_URI);
--- a/dom/ipc/tests/browser_remote_navigation_delay_telemetry.js
+++ b/dom/ipc/tests/browser_remote_navigation_delay_telemetry.js
@@ -3,17 +3,16 @@
 var session = Cu.import("resource://gre/modules/TelemetrySession.jsm", {});
 
 add_task(async function test_memory_distribution() {
   if (Services.prefs.getIntPref("dom.ipc.processCount", 1) < 2) {
     ok(true, "Skip this test if e10s-multi is disabled.");
     return;
   }
 
-  await SpecialPowers.pushPrefEnv({set: [["toolkit.telemetry.enabled", true]]});
   let canRecordExtended = Services.telemetry.canRecordExtended;
   Services.telemetry.canRecordExtended = true;
   registerCleanupFunction(() => Services.telemetry.canRecordExtended = canRecordExtended);
 
   Services.telemetry.snapshotKeyedHistograms(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN,
                                              true /* subsession */,
                                              true /* clear */);
 
--- a/dom/payments/PaymentRequest.cpp
+++ b/dom/payments/PaymentRequest.cpp
@@ -536,43 +536,33 @@ PaymentRequest::Constructor(const Global
   }
 
   // the feature can only be used in an active document
   if (!window->IsCurrentInnerWindow()) {
     aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
     return nullptr;
   }
 
-  // If the node has the same origin as the parent node, the feature is allowed-to-use.
-  // Otherwise, only allow-to-use this feature when the browsing context container is
-  // an iframe with "allowpaymentrequest" attribute.
+
   nsCOMPtr<nsIDocument> doc = window->GetExtantDoc();
-  nsINode* node = static_cast<nsINode*>(doc);
-  if (!node) {
+  if (!doc) {
     aRv.Throw(NS_ERROR_UNEXPECTED);
     return nullptr;
   }
 
-  nsCOMPtr<nsIPrincipal> topLevelPrincipal;
-  do {
-    nsINode* parentNode = nsContentUtils::GetCrossDocParentNode(node);
-    if (parentNode) {
-      nsresult rv = nsContentUtils::CheckSameOrigin(node, parentNode);
-      if (NS_FAILED(rv)) {
-        nsIContent* content = static_cast<nsIContent*>(parentNode);
-        if (!content->IsHTMLElement(nsGkAtoms::iframe) ||
-            !content->HasAttr(kNameSpaceID_None, nsGkAtoms::allowpaymentrequest)) {
-          aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
-          return nullptr;
-        }
-      }
-    }
-    topLevelPrincipal = node->NodePrincipal();
-    node = parentNode;
-  } while (node);
+  // Check if AllowPaymentRequest on the owner document
+  if (!doc->AllowPaymentRequest()) {
+    aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
+    return nullptr;
+  }
+
+  // Get the top level principal
+  nsCOMPtr<nsIDocument> topLevelDoc = doc->GetTopLevelContentDocument();
+  MOZ_ASSERT(topLevelDoc);
+  nsCOMPtr<nsIPrincipal> topLevelPrincipal = topLevelDoc->NodePrincipal();
 
   // Check payment methods and details
   nsAutoString message;
   nsresult rv = IsValidMethodData(aGlobal.Context(),
                                   aMethodData,
                                   message);
   if (NS_FAILED(rv)) {
     if (rv == NS_ERROR_TYPE_ERR) {
new file mode 100644
--- /dev/null
+++ b/dom/payments/test/echo_payment_request.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>Payment Request Testing</title>
+    <meta content="text/html;charset=utf-8" http-equiv="Content-Type">
+    <meta content="utf-8" http-equiv="encoding">
+</head>
+<body>
+  <script>
+    window.onmessage = (e) => {
+      const paymentArgs = [[{supportedMethods: 'basic-card'}], {total: {label: 'label', amount: {currency: 'USD', value: '5.00'}}}];
+
+    if (e.data === 'new PaymentRequest') {
+      try {
+        new PaymentRequest(...paymentArgs);
+        if (window.parent) {
+          window.parent.postMessage("successful", '*');
+        }
+      } catch(ex) {
+        if (window.parent) {
+          window.parent.postMessage(ex.name, '*');
+        }
+      }
+    } else if (e.data === 'new PaymentRequest in a new iframe') {
+      var ifrr = document.createElement('iframe');
+      ifrr.setAttribute('allowpaymentrequest', 'true');
+      ifrr.src = "https://example.com/tests/dom/payments/test/simple_payment_request.html";
+      document.body.appendChild(ifrr);
+    } else {
+      if (window.parent) {
+        window.parent.postMessage(e.data, '*');
+      }
+    }
+  }
+  </script>
+</body>
+</html>
--- a/dom/payments/test/mochitest.ini
+++ b/dom/payments/test/mochitest.ini
@@ -1,14 +1,15 @@
 [DEFAULT]
 # skip-if !e10s will be removed once non-e10s is supported
 skip-if = !e10s
 scheme = https
 support-files =
   simple_payment_request.html
+  echo_payment_request.html
   BasiccardChromeScript.js
   ConstructorChromeScript.js
   CurrencyAmountValidationChromeScript.js
   GeneralChromeScript.js
   PMIValidationChromeScript.js
   ShowPaymentChromeScript.js
 
 [test_abortPayment.html]
--- a/dom/payments/test/test_payment-request-in-iframe.html
+++ b/dom/payments/test/test_payment-request-in-iframe.html
@@ -54,32 +54,103 @@ https://bugzilla.mozilla.org/show_bug.cg
       });
     });
   }
 
   function testRequestInIFrameWithAttribute() {
     return new Promise((resolve, reject) => {
       var ifrr = document.createElement('iframe');
 
-      window.addEventListener("message", function(event) {
+      let listener = function(event) {
         is(event.data, "successful",
           "Expected 'successful', but got '" + event.data + "'");
         resolve();
+      };
+
+      window.addEventListener("message", listener);
+
+      ifrr.setAttribute('allowpaymentrequest', 'true');
+      ifrr.src = "https://test1.example.com:443/tests/dom/payments/test/simple_payment_request.html";
+      document.body.appendChild(ifrr);
+
+      ifrr.addEventListener('load', function() {
+        window.removeEventListener("message", listener);
+      });
+    });
+  }
+
+  function testRequestWithAttributeChanged() {
+    return new Promise((resolve, reject) => {
+      var ifrr = document.createElement('iframe');
+
+      let i = 0;
+
+      ifrr.addEventListener('load', function() {
+        if (i === 0) {
+          ifrr.removeAttribute("allowpaymentrequest");
+        }
+        ifrr.contentWindow.postMessage('new PaymentRequest', '*');
       });
 
-      ifrr.setAttribute('allowpaymentrequest', '');
-      ifrr.src = "https://test1.example.com:443/tests/dom/payments/test/simple_payment_request.html";
+      let listener = function(event) {
+        i++;
+        if (i === 1) {
+          is(event.data, "successful",
+             "Expected successful when running with allowpayment attribute.");
+          ifrr.contentWindow.location.href = ifrr.src;
+        } else {
+          is(event.data, "SecurityError",
+             "Expected SecurityError when running without allowpayment attribute.");
+          window.removeEventListener("message", listener);
+          resolve();
+        }
+      }
+      window.addEventListener("message", listener);
+
+      ifrr.setAttribute('allowpaymentrequest', "true");
+      ifrr.src = "https://test1.example.com:443/tests/dom/payments/test/echo_payment_request.html";
+
+      document.body.appendChild(ifrr);
+    });
+  }
+
+  function testRequestInCrossOriginNestedIFrame() {
+    return new Promise((resolve, reject) => {
+      var ifrr = document.createElement('iframe');
+
+      let listener = function(event) {
+        if (!ifrr.hasAttribute('allowpaymentrequest')) {
+          is(event.data, "SecurityError",
+            "Expected 'SecurityError' without allowpaymentrequest in nested iframe");
+          ifrr.setAttribute('allowpaymentrequest', true);
+          ifrr.contentWindow.location.href = ifrr.src;
+        } else {
+          is(event.data, "successful",
+             "Expected 'successful' with allowpaymentrequest in nested iframe");
+          window.removeEventListener("message", listener);
+          resolve();
+        }
+      };
+      window.addEventListener("message", listener);
+
+      ifrr.addEventListener("load", function() {
+        ifrr.contentWindow.postMessage('new PaymentRequest in a new iframe', '*');
+      })
+
+      ifrr.src = "https://test1.example.com:443/tests/dom/payments/test/echo_payment_request.html";
       document.body.appendChild(ifrr);
     });
   }
 
   function runTests() {
     testRequestInSameOrigin()
     .then(testRequestInIFrame)
     .then(testRequestInIFrameWithAttribute)
+    .then(testRequestWithAttributeChanged)
+    .then(testRequestInCrossOriginNestedIFrame)
     .then(SimpleTest.finish)
     .catch( e => {
       ok(false, "Unexpected error: " + e.name);
       SimpleTest.finish();
     });
   }
 
   window.addEventListener('load', function() {
--- a/dom/security/test/hsts/head.js
+++ b/dom/security/test/hsts/head.js
@@ -403,17 +403,16 @@ function SetupPrefTestEnvironment(which,
   var prefs = [["security.mixed_content.block_active_content",
                 settings.block_active],
                ["security.mixed_content.block_display_content",
                 settings.block_display],
                ["security.mixed_content.use_hsts",
                 settings.use_hsts],
                ["security.mixed_content.send_hsts_priming",
                 settings.send_hsts_priming],
-               ["toolkit.telemetry.enabled", true],
   ];
 
   if (additional_prefs) {
     for (let idx in additional_prefs) {
       prefs.push(additional_prefs[idx]);
     }
   }
 
--- a/dom/webidl/ServiceWorkerRegistration.webidl
+++ b/dom/webidl/ServiceWorkerRegistration.webidl
@@ -12,16 +12,17 @@
 [Func="mozilla::dom::ServiceWorkerRegistration::Visible",
  Exposed=(Window,Worker)]
 interface ServiceWorkerRegistration : EventTarget {
   [Unforgeable] readonly attribute ServiceWorker? installing;
   [Unforgeable] readonly attribute ServiceWorker? waiting;
   [Unforgeable] readonly attribute ServiceWorker? active;
 
   readonly attribute USVString scope;
+  [Throws]
   readonly attribute ServiceWorkerUpdateViaCache updateViaCache;
 
   [Throws, NewObject]
   Promise<void> update();
 
   [Throws, NewObject]
   Promise<boolean> unregister();
 
--- a/dom/workers/ServiceWorkerRegistration.cpp
+++ b/dom/workers/ServiceWorkerRegistration.cpp
@@ -135,31 +135,42 @@ public:
 
   void
   GetScope(nsAString& aScope) const override
   {
     aScope = mScope;
   }
 
   ServiceWorkerUpdateViaCache
-  UpdateViaCache() const override
+  GetUpdateViaCache(ErrorResult& aRv) const override
   {
     RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
     MOZ_ASSERT(swm);
 
     nsCOMPtr<nsPIDOMWindowInner> window = GetOwner();
     MOZ_ASSERT(window);
 
     nsCOMPtr<nsIDocument> doc = window->GetExtantDoc();
     MOZ_ASSERT(doc);
 
     nsCOMPtr<nsIServiceWorkerRegistrationInfo> registration;
     nsresult rv = swm->GetRegistrationByPrincipal(doc->NodePrincipal(), mScope,
                                                   getter_AddRefs(registration));
-    MOZ_ASSERT(NS_SUCCEEDED(rv) && registration);
+
+    /*
+     *  xxx: We should probably store the `updateViaCache` value on the
+     *  ServiceWorkerRegistration object and update it when necessary.
+     *  We don't have a good way to reach all ServiceWorkerRegistration objects
+     *  from the ServiceWorkerRegistratinInfo right now, though.
+     *  This is a short term fix to avoid crashing.
+     */
+    if (NS_FAILED(rv) || !registration) {
+      aRv = NS_ERROR_DOM_INVALID_STATE_ERR;
+      return ServiceWorkerUpdateViaCache::None;
+    }
 
     uint16_t updateViaCache;
     rv = registration->GetUpdateViaCache(&updateViaCache);
     MOZ_ASSERT(NS_SUCCEEDED(rv));
 
     // Silence possible compiler warnings.
     Unused << rv;
 
@@ -939,17 +950,17 @@ public:
 
   void
   GetScope(nsAString& aScope) const override
   {
     aScope = mScope;
   }
 
   ServiceWorkerUpdateViaCache
-  UpdateViaCache() const override
+  GetUpdateViaCache(ErrorResult& aRv) const override
   {
     // FIXME(hopang): Will be implemented after Bug 1113522.
     return ServiceWorkerUpdateViaCache::Imports;
   }
 
   bool
   Notify(Status aStatus) override;
 
--- a/dom/workers/ServiceWorkerRegistration.h
+++ b/dom/workers/ServiceWorkerRegistration.h
@@ -87,17 +87,17 @@ public:
 
   virtual already_AddRefed<workers::ServiceWorker>
   GetActive() = 0;
 
   virtual void
   GetScope(nsAString& aScope) const = 0;
 
   virtual ServiceWorkerUpdateViaCache
-  UpdateViaCache() const = 0;
+  GetUpdateViaCache(ErrorResult& aRv) const = 0;
 
   virtual already_AddRefed<Promise>
   Update(ErrorResult& aRv) = 0;
 
   virtual already_AddRefed<Promise>
   Unregister(ErrorResult& aRv) = 0;
 
   virtual already_AddRefed<PushManager>
--- a/dom/workers/test/serviceworkers/mochitest.ini
+++ b/dom/workers/test/serviceworkers/mochitest.ini
@@ -220,16 +220,17 @@ support-files =
   service_worker.js
   service_worker_client.html
   utils.js
   bug1290951_worker_main.sjs
   bug1290951_worker_imported.sjs
 
 [test_bug1151916.html]
 [test_bug1240436.html]
+[test_bug1408734.html]
 [test_claim.html]
 [test_claim_oninstall.html]
 [test_controller.html]
 [test_cookie_fetch.html]
 [test_cross_origin_url_after_redirect.html]
 skip-if = debug # Bug 1262224
 [test_csp_upgrade-insecure_intercept.html]
 [test_devtools_bypass_serviceworker.html]
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/serviceworkers/test_bug1408734.html
@@ -0,0 +1,65 @@
+<!--
+  Any copyright is dedicated to the Public Domain.
+  http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Bug 1408734</title>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+  <script src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script src="/tests/SimpleTest/SpawnTask.js"></script>
+  <script src="error_reporting_helpers.js"></script>
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none"></div>
+<pre id="test"></pre>
+<script class="testbody" type="text/javascript">
+
+// setup prefs
+add_task(() => {
+  return SpecialPowers.pushPrefEnv({"set": [
+    ["dom.serviceWorkers.enabled", true],
+    ["dom.serviceWorkers.testing.enabled", true],
+  ]});
+});
+
+// test for bug 1408734
+add_task(async () => {
+  let waitForControlled = new Promise((resolve) => {
+    navigator.serviceWorker.oncontrollerchange = resolve;
+  });
+
+  // register a service worker
+  let registration = await navigator.serviceWorker.register("fetch.js", {scope: "./"});
+  let worker = registration.installing || registration.active;
+
+  // wait for control changed
+  worker.postMessage('claim');
+  await waitForControlled;
+
+  // get the ServiceWorkerRegistration we just register through GetRegistration
+  registration = await navigator.serviceWorker.getRegistration("./");
+  ok(registration, "should get the registration under scope './'");
+
+  // call unregister()
+  await registration.unregister();
+
+  // access registration.updateViaCache to trigger the bug
+  // we really care that we don't crash. In the future we will fix
+  // updateViaCache to be accessible after unregister().
+  try {
+    if (registration.updateViaCache) {
+      ok(false,
+         "Expected InvalidStateError when accessing registration.updateViaCache after unregister()");
+    }
+  } catch (err) {
+    is(err.name, "InvalidStateError", "Expected InvalidStateError.");
+  }
+});
+
+</script>
+</pre>
+</body>
+</html>
--- a/dom/workers/test/serviceworkers/test_devtools_bypass_serviceworker.html
+++ b/dom/workers/test/serviceworkers/test_devtools_bypass_serviceworker.html
@@ -5,16 +5,17 @@
   <script src="/tests/SimpleTest/SimpleTest.js"></script>
   <script src="/tests/SimpleTest/SpawnTask.js"></script>
   <script src="error_reporting_helpers.js"></script>
   <link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
   <meta http-equiv="Content-type" content="text/html;charset=UTF-8">
 </head>
 <body>
 <div id="content" style="display: none"></div>
+<script src="utils.js"></script>
 <script type="text/javascript">
 "use strict";
 
 async function testBypassSW () {
   // Bypass SW imitates the "Disable Cache" option in dev-tools.
   // Note: if we put the setter/getter into dev-tools, we should take care of
   // the implementation of enabling/disabling cache since it just overwrite the
   // defaultLoadFlags of docShell.
@@ -89,25 +90,22 @@ add_task(function setupPrefs() {
     ["dom.serviceWorkers.testing.enabled", true],
   ]});
 });
 
 add_task(async function test_bypassServiceWorker() {
   const swURL = "fetch.js";
   let registration = await navigator.serviceWorker.register(swURL);
 
-  // Wait for the service worker to control the document
-  let waitForControlled = new Promise(resolve => {
-    navigator.serviceWorker.oncontrollerchange = resolve;
-  });
-
   let sw =
     registration.active || registration.waiting || registration.installing;
+
+  await waitForState(sw, 'activated');
   sw.postMessage("claim");
-  await waitForControlled;
+  await waitForControlled(window);
 
   try {
     await testBypassSW();
   } catch (e) {
     ok(false, "Reason:" + e);
   }
 
   await registration.unregister();
--- a/dom/workers/test/serviceworkers/test_fetch_integrity.html
+++ b/dom/workers/test/serviceworkers/test_fetch_integrity.html
@@ -5,16 +5,17 @@
   <script src="/tests/SimpleTest/SimpleTest.js"></script>
   <script src="/tests/SimpleTest/SpawnTask.js"></script>
   <script src="error_reporting_helpers.js"></script>
   <link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
   <meta http-equiv="Content-type" content="text/html;charset=UTF-8">
 </head>
 <body>
 <div id="content" style="display: none"></div>
+<script src="utils.js"></script>
 <script type="text/javascript">
 "use strict";
 
 let security_localizer =
   stringBundleService.createBundle("chrome://global/locale/security/security.properties");
 
 function expect_security_console_message(/* msgId, args, ... */) {
   let expectations = [];
@@ -44,26 +45,22 @@ add_task(function setupPrefs() {
     ["browser.newtab.preload", false],
   ]});
 });
 
 add_task(async function test_integrity_serviceWorker() {
   var filename = make_absolute_url("fetch.js");
   var filename2 = make_absolute_url("fake.html");
 
-  // The SW will claim us once it activates; this is async, start listening now.
-  let waitForControlled = new Promise((resolve) => {
-    navigator.serviceWorker.oncontrollerchange = resolve;
-  });
-
   let registration = await navigator.serviceWorker.register("fetch.js",
                                                             { scope: "./" });
   let worker = registration.installing || registration.active;
+  await waitForState(worker, 'activated');
   worker.postMessage('claim');
-  await waitForControlled;
+  await waitForControlled(window);
 
   info("Test for mNavigationInterceptions.")
   // The client_win will reload to another URL after opening filename2.
   let client_win = window.open(filename2);
 
   // XXX windowID should be innerWindowID
   let mainWindowID = SpecialPowers.getDOMWindowUtils(window).outerWindowID;
   let clientWindowID = SpecialPowers.getDOMWindowUtils(client_win).outerWindowID;
--- a/dom/workers/test/serviceworkers/test_unresolved_fetch_interception.html
+++ b/dom/workers/test/serviceworkers/test_unresolved_fetch_interception.html
@@ -17,16 +17,17 @@
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1188545">Mozilla Bug 118845</a>
 <p id="display"></p>
 <div id="content" style="display: none">
 
 </div>
 <pre id="test">
 </pre>
 
+<script src="utils.js"></script>
 <script class="testbody" type="text/javascript">
 // (This doesn't really need to be its own task, but it allows the actual test
 // case to be self-contained.)
 add_task(function setupPrefs() {
   return SpecialPowers.pushPrefEnv({"set": [
     ["dom.serviceWorkers.enabled", true],
     ["dom.serviceWorkers.testing.enabled", true],
   ]});
@@ -34,24 +35,23 @@ add_task(function setupPrefs() {
 
 add_task(async function grace_timeout_termination_with_interrupted_intercept() {
   // Setup timeouts so that the service worker will go into grace timeout after
   // a zero-length idle timeout.
   await SpecialPowers.pushPrefEnv({"set": [
     ["dom.serviceWorkers.idle_timeout", 0],
     ["dom.serviceWorkers.idle_extended_timeout", 299999]]});
 
-  // The SW will claim us once it activates; this is async, start listening now.
-  let waitForControlled = new Promise((resolve) => {
-    navigator.serviceWorker.oncontrollerchange = resolve;
-  });
-
   let registration = await navigator.serviceWorker.register(
     "unresolved_fetch_worker.js", { scope: "./"} );
-  await waitForControlled;
+
+  let worker = registration.installing || registration.active;
+  await waitForState(worker, 'activated');
+  worker.postMessage('claim');
+  await waitForControlled(window);
   ok(navigator.serviceWorker.controller, "Controlled"); // double check!
 
   // We want to make sure the SW is active and processing the fetch before we
   // try and kill it.  It sends us a message when it has done so.
   let waitForFetchActive = new Promise((resolve) => {
     navigator.serviceWorker.onmessage = resolve;
   });
 
--- a/dom/workers/test/serviceworkers/unresolved_fetch_worker.js
+++ b/dom/workers/test/serviceworkers/unresolved_fetch_worker.js
@@ -9,11 +9,13 @@ onfetch = function(event) {
            })
   );
 
   // Never resolve, and keep it alive on our global so it can't get GC'ed and
   // make this test weird and intermittent.
   event.respondWith((keepPromiseAlive = new Promise(function(res, rej) {})));
 }
 
-onactivate = function(event) {
-  event.waitUntil(clients.claim());
+onmessage = function(event) {
+  if (event.data === 'claim') {
+    event.waitUntil(clients.claim());
+  }
 }
--- a/gfx/harfbuzz/Makefile.am
+++ b/gfx/harfbuzz/Makefile.am
@@ -8,16 +8,17 @@ SUBDIRS = src util test docs
 
 EXTRA_DIST = \
 	autogen.sh \
 	harfbuzz.doap \
 	README.python \
 	BUILD.md \
 	RELEASING.md \
 	CMakeLists.txt \
+	replace-enum-strings.cmake \
 	$(NULL)
 
 MAINTAINERCLEANFILES = \
 	$(GITIGNORE_MAINTAINERCLEANFILES_TOPLEVEL) \
 	$(GITIGNORE_MAINTAINERCLEANFILES_M4_LIBTOOL) \
 	$(GITIGNORE_MAINTAINERCLEANFILES_MAKEFILE_IN) \
 	$(srcdir)/INSTALL \
 	$(srcdir)/ChangeLog \
--- a/gfx/harfbuzz/NEWS
+++ b/gfx/harfbuzz/NEWS
@@ -1,8 +1,40 @@
+Overview of changes leading to 1.6.3
+Thursday, October 26th, 2017
+====================================
+
+- Fix hb_set_t some more.  Should be solid now.
+- Implement get_glyph_name() for hb-ot-font.
+- Misc fixes.
+
+
+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
+- 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
+- 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
 Friday, October the 13th, 2017
 ====================================
 
 - Update to Unicode 10.
 
 - Various Indic and Universal Shaping Engine fixes as a result of
   HarfBuzz Hackfest with Jonathan Kew at Web Engines Hackfest at
--- a/gfx/harfbuzz/README-mozilla
+++ b/gfx/harfbuzz/README-mozilla
@@ -1,14 +1,14 @@
-gfx/harfbuzz status as of 2017-10-13:
+gfx/harfbuzz status as of 2017-10-26:
 
 This directory contains the harfbuzz source from the 'master' branch of
 https://github.com/behdad/harfbuzz.
 
-Current version: 1.6.0
+Current version: 1.6.3
 
 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,11 +1,11 @@
 AC_PREREQ([2.64])
 AC_INIT([HarfBuzz],
-        [1.6.0],
+        [1.6.3],
         [https://github.com/behdad/harfbuzz/issues/new],
         [harfbuzz],
         [http://harfbuzz.org/])
 
 AC_CONFIG_MACRO_DIR([m4])
 AC_CONFIG_SRCDIR([src/harfbuzz.pc.in])
 AC_CONFIG_HEADERS([config.h])
 
@@ -75,16 +75,19 @@ AC_CHECK_HEADERS(unistd.h sys/mman.h xlo
 # Compiler flags
 AC_CANONICAL_HOST
 AC_CHECK_ALIGNOF([struct{char;}])
 if test "x$GCC" = "xyes"; then
 
 	# Make symbols link locally
 	LDFLAGS="$LDFLAGS -Bsymbolic-functions"
 
+	# Choose C++ version
+	CXXFLAGS="$CXXFLAGS -std=c++11"
+
 	# Make sure we don't link to libstdc++
 	CXXFLAGS="$CXXFLAGS -fno-rtti -fno-exceptions"
 
 	# Assorted warnings
 	CXXFLAGS="$CXXFLAGS -Wcast-align"
 
 	case "$host" in
 		*-*-mingw*)
--- 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="http://bugs.freedesktop.org/enter_bug.cgi?product=harfbuzz"/>
+  rdf:resource="https://github.com/behdad/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/check-c-linkage-decls.sh
+++ b/gfx/harfbuzz/src/check-c-linkage-decls.sh
@@ -6,23 +6,23 @@ export LC_ALL
 test -z "$srcdir" && srcdir=.
 stat=0
 
 test "x$HBHEADERS" = x && HBHEADERS=`cd "$srcdir"; find . -maxdepth 1 -name 'hb*.h'`
 test "x$HBSOURCES" = x && HBSOURCES=`cd "$srcdir"; find . -maxdepth 1 -name 'hb*.h'`
 
 
 for x in $HBHEADERS; do
-	test -f $srcdir/$x && x=$srcdir/$x
+	test -f "$srcdir/$x" -a ! -f "$x" && x="$srcdir/$x"
 	if ! grep -q HB_BEGIN_DECLS "$x" || ! grep -q HB_END_DECLS "$x"; then
 		echo "Ouch, file $x does not have HB_BEGIN_DECLS / HB_END_DECLS, but it should"
 		stat=1
 	fi
 done
 for x in $HBSOURCES; do
-	test -f $srcdir/$x && x=$srcdir/$x
+	test -f "$srcdir/$x" -a ! -f "$x" && x="$srcdir/$x"
 	if grep -q HB_BEGIN_DECLS "$x" || grep -q HB_END_DECLS "$x"; then
 		echo "Ouch, file $x has HB_BEGIN_DECLS / HB_END_DECLS, but it shouldn't"
 		stat=1
 	fi
 done
 
 exit $stat
--- a/gfx/harfbuzz/src/check-externs.sh
+++ b/gfx/harfbuzz/src/check-externs.sh
@@ -8,14 +8,15 @@ stat=0
 
 test "x$HBHEADERS" = x && HBHEADERS=`cd "$srcdir"; find . -maxdepth 1 -name 'hb*.h'`
 test "x$EGREP" = x && EGREP='grep -E'
 
 
 echo 'Checking that all public symbols are exported with HB_EXTERN'
 
 for x in $HBHEADERS; do
-	test -f "$srcdir/$x" && x="$srcdir/$x"
-	$EGREP -B1 '^hb_' "$x" | $EGREP -E -v '^(--|hb_|HB_EXTERN )' -A1
+	test -f "$srcdir/$x" -a ! -f "$x" && x="$srcdir/$x"
+	$EGREP -B1 -n '^hb_' /dev/null "$x" |
+	$EGREP -v '(^--|:hb_|-HB_EXTERN )' -A1
 done |
 grep . >&2 && stat=1
 
 exit $stat
--- a/gfx/harfbuzz/src/check-header-guards.sh
+++ b/gfx/harfbuzz/src/check-header-guards.sh
@@ -5,17 +5,17 @@ export LC_ALL
 
 test -z "$srcdir" && srcdir=.
 stat=0
 
 test "x$HBHEADERS" = x && HBHEADERS=`cd "$srcdir"; find . -maxdepth 1 -name 'hb*.h'`
 test "x$HBSOURCES" = x && HBSOURCES=`cd "$srcdir"; find . -maxdepth 1 -name 'hb-*.cc' -or -name 'hb-*.hh'`
 
 for x in $HBHEADERS $HBSOURCES; do
-	test -f "$srcdir/$x" && x="$srcdir/$x"
+	test -f "$srcdir/$x" -a ! -f "$x" && x="$srcdir/$x"
 	echo "$x" | grep -q '[^h]$' && continue;
 	xx=`echo "$x" | sed 's@.*/@@'`
 	tag=`echo "$xx" | tr 'a-z.-' 'A-Z_'`
 	lines=`grep -w "$tag" "$x" | wc -l | sed 's/[ 	]*//g'`
 	if test "x$lines" != x3; then
 		echo "Ouch, header file $x does not have correct preprocessor guards"
 		stat=1
 	fi
--- a/gfx/harfbuzz/src/check-includes.sh
+++ b/gfx/harfbuzz/src/check-includes.sh
@@ -8,30 +8,30 @@ stat=0
 
 test "x$HBHEADERS" = x && HBHEADERS=`cd "$srcdir"; find . -maxdepth 1 -name 'hb*.h'`
 test "x$HBSOURCES" = x && HBSOURCES=`cd "$srcdir"; find . -maxdepth 1 -name 'hb-*.cc' -or -name 'hb-*.hh'`
 
 
 echo 'Checking that public header files #include "hb-common.h" or "hb.h" first (or none)'
 
 for x in $HBHEADERS; do
-	test -f "$srcdir/$x" && x="$srcdir/$x"
+	test -f "$srcdir/$x" -a ! -f "$x" && x="$srcdir/$x"
 	grep '#.*\<include\>' "$x" /dev/null | head -n 1
 done |
 grep -v '"hb-common[.]h"' |
 grep -v '"hb[.]h"' |
 grep -v 'hb-common[.]h:' |
 grep -v 'hb[.]h:' |
 grep . >&2 && stat=1
 
 
 echo 'Checking that source files #include "hb-*private.hh" first (or none)'
 
 for x in $HBSOURCES; do
-	test -f "$srcdir/$x" && x="$srcdir/$x"
+	test -f "$srcdir/$x" -a ! -f "$x" && x="$srcdir/$x"
 	grep '#.*\<include\>' "$x" /dev/null | grep -v 'include _' | head -n 1
 done |
 grep -v '"hb-.*private[.]hh"' |
 grep -v 'hb-private[.]hh:' |
 grep . >&2 && stat=1
 
 
 echo 'Checking that there is no #include <hb.*.h>'
--- 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.6.0
+Version: 1.6.3
 
 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.6.0
+Version: 1.6.3
 
 Libs: -L${libdir} -lharfbuzz
 Libs.private: -lm    
 Requires.private: glib-2.0 >= 2.19.1 
 Cflags: -I${includedir}/harfbuzz
--- a/gfx/harfbuzz/src/hb-blob.cc
+++ b/gfx/harfbuzz/src/hb-blob.cc
@@ -67,18 +67,18 @@ struct hb_blob_t {
 
 static bool _try_writable (hb_blob_t *blob);
 
 static void
 _hb_blob_destroy_user_data (hb_blob_t *blob)
 {
   if (blob->destroy) {
     blob->destroy (blob->user_data);
-    blob->user_data = NULL;
-    blob->destroy = NULL;
+    blob->user_data = nullptr;
+    blob->destroy = nullptr;
   }
 }
 
 /**
  * hb_blob_create: (skip)
  * @data: Pointer to blob data.
  * @length: Length of @data in bytes.
  * @mode: Memory mode for @data.
@@ -189,22 +189,22 @@ hb_blob_create_sub_blob (hb_blob_t    *p
 hb_blob_t *
 hb_blob_get_empty (void)
 {
   static const hb_blob_t _hb_blob_nil = {
     HB_OBJECT_HEADER_STATIC,
 
     true, /* immutable */
 
-    NULL, /* data */
+    nullptr, /* data */
     0, /* length */
     HB_MEMORY_MODE_READONLY, /* mode */
 
-    NULL, /* user_data */
-    NULL  /* destroy */
+    nullptr, /* user_data */
+    nullptr  /* destroy */
   };
 
   return const_cast<hb_blob_t *> (&_hb_blob_nil);
 }
 
 /**
  * hb_blob_reference: (skip)
  * @blob: a blob.
@@ -374,17 +374,17 @@ hb_blob_get_data (hb_blob_t *blob, unsig
  **/
 char *
 hb_blob_get_data_writable (hb_blob_t *blob, unsigned int *length)
 {
   if (!_try_writable (blob)) {
     if (length)
       *length = 0;
 
-    return NULL;
+    return nullptr;
   }
 
   if (length)
     *length = blob->length;
 
   return const_cast<char *> (blob->data);
 }
 
--- a/gfx/harfbuzz/src/hb-buffer-private.hh
+++ b/gfx/harfbuzz/src/hb-buffer-private.hh
@@ -40,18 +40,18 @@
 #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
 
-ASSERT_STATIC (sizeof (hb_glyph_info_t) == 20);
-ASSERT_STATIC (sizeof (hb_glyph_info_t) == sizeof (hb_glyph_position_t));
+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 {
   HB_BUFFER_SCRATCH_FLAG_DEFAULT			= 0x00000000u,
   HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII			= 0x00000001u,
--- a/gfx/harfbuzz/src/hb-buffer-serialize.cc
+++ b/gfx/harfbuzz/src/hb-buffer-serialize.cc
@@ -25,17 +25,17 @@
  */
 
 #include "hb-buffer-private.hh"
 
 
 static const char *serialize_formats[] = {
   "text",
   "json",
-  NULL
+  nullptr
 };
 
 /**
  * hb_buffer_serialize_list_formats:
  *
  * Returns a list of supported buffer serialization formats.
  *
  * Return value: (transfer none):
@@ -85,33 +85,33 @@ hb_buffer_serialize_format_from_string (
 const char *
 hb_buffer_serialize_format_to_string (hb_buffer_serialize_format_t format)
 {
   switch (format)
   {
     case HB_BUFFER_SERIALIZE_FORMAT_TEXT:	return serialize_formats[0];
     case HB_BUFFER_SERIALIZE_FORMAT_JSON:	return serialize_formats[1];
     default:
-    case HB_BUFFER_SERIALIZE_FORMAT_INVALID:	return NULL;
+    case HB_BUFFER_SERIALIZE_FORMAT_INVALID:	return nullptr;
   }
 }
 
 static unsigned int
 _hb_buffer_serialize_glyphs_json (hb_buffer_t *buffer,
 				  unsigned int start,
 				  unsigned int end,
 				  char *buf,
 				  unsigned int buf_size,
 				  unsigned int *buf_consumed,
 				  hb_font_t *font,
 				  hb_buffer_serialize_flags_t flags)
 {
-  hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, NULL);
+  hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, nullptr);
   hb_glyph_position_t *pos = (flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS) ?
-			     NULL : hb_buffer_get_glyph_positions (buffer, NULL);
+			     nullptr : hb_buffer_get_glyph_positions (buffer, nullptr);
 
   *buf_consumed = 0;
   for (unsigned int i = start; i < end; i++)
   {
     char b[1024];
     char *p = b;
 
     /* In the following code, we know b is large enough that no overflow can happen. */
@@ -189,19 +189,19 @@ static unsigned int
 				  unsigned int start,
 				  unsigned int end,
 				  char *buf,
 				  unsigned int buf_size,
 				  unsigned int *buf_consumed,
 				  hb_font_t *font,
 				  hb_buffer_serialize_flags_t flags)
 {
-  hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, NULL);
+  hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, nullptr);
   hb_glyph_position_t *pos = (flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS) ?
-			     NULL : hb_buffer_get_glyph_positions (buffer, NULL);
+			     nullptr : hb_buffer_get_glyph_positions (buffer, nullptr);
 
   *buf_consumed = 0;
   for (unsigned int i = start; i < end; i++)
   {
     char b[1024];
     char *p = b;
 
     /* In the following code, we know b is large enough that no overflow can happen. */
@@ -417,18 +417,18 @@ parse_int (const char *pp, const char *e
  * Return value: 
  *
  * Since: 0.9.7
  **/
 hb_bool_t
 hb_buffer_deserialize_glyphs (hb_buffer_t *buffer,
 			      const char *buf,
 			      int buf_len, /* -1 means nul-terminated */
-			      const char **end_ptr, /* May be NULL */
-			      hb_font_t *font, /* May be NULL */
+			      const char **end_ptr, /* May be nullptr */
+			      hb_font_t *font, /* May be nullptr */
 			      hb_buffer_serialize_format_t format)
 {
   const char *end;
   if (!end_ptr)
     end_ptr = &end;
   *end_ptr = buf;
 
   assert ((!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID) ||
--- a/gfx/harfbuzz/src/hb-buffer.cc
+++ b/gfx/harfbuzz/src/hb-buffer.cc
@@ -115,27 +115,27 @@ hb_buffer_t::enlarge (unsigned int size)
     return false;
   if (unlikely (size > max_len))
   {
     in_error = true;
     return false;
   }
 
   unsigned int new_allocated = allocated;
-  hb_glyph_position_t *new_pos = NULL;
-  hb_glyph_info_t *new_info = NULL;
+  hb_glyph_position_t *new_pos = nullptr;
+  hb_glyph_info_t *new_info = nullptr;
   bool separate_out = out_info != info;
 
   if (unlikely (_hb_unsigned_int_mul_overflows (size, sizeof (info[0]))))
     goto done;
 
   while (size >= new_allocated)
     new_allocated += (new_allocated >> 1) + 32;
 
-  ASSERT_STATIC (sizeof (info[0]) == sizeof (pos[0]));
+  static_assert ((sizeof (info[0]) == sizeof (pos[0])), "");
   if (unlikely (_hb_unsigned_int_mul_overflows (new_allocated, sizeof (info[0]))))
     goto done;
 
   new_pos = (hb_glyph_position_t *) realloc (pos, new_allocated * sizeof (pos[0]));
   new_info = (hb_glyph_info_t *) realloc (info, new_allocated * sizeof (info[0]));
 
 done:
   if (unlikely (!new_pos || !new_info))
@@ -1988,19 +1988,19 @@ hb_buffer_set_message_func (hb_buffer_t 
   if (buffer->message_destroy)
     buffer->message_destroy (buffer->message_data);
 
   if (func) {
     buffer->message_func = func;
     buffer->message_data = user_data;
     buffer->message_destroy = destroy;
   } else {
-    buffer->message_func = NULL;
-    buffer->message_data = NULL;
-    buffer->message_destroy = NULL;
+    buffer->message_func = nullptr;
+    buffer->message_data = nullptr;
+    buffer->message_destroy = nullptr;
   }
 }
 
 bool
 hb_buffer_t::message_impl (hb_font_t *font, const char *fmt, va_list ap)
 {
   char buf[100];
   vsnprintf (buf, sizeof (buf),  fmt, ap);
--- a/gfx/harfbuzz/src/hb-buffer.h
+++ b/gfx/harfbuzz/src/hb-buffer.h
@@ -127,18 +127,18 @@ typedef struct hb_segment_properties_t {
   /*< private >*/
   void           *reserved1;
   void           *reserved2;
 } hb_segment_properties_t;
 
 #define HB_SEGMENT_PROPERTIES_DEFAULT {HB_DIRECTION_INVALID, \
 				       HB_SCRIPT_INVALID, \
 				       HB_LANGUAGE_INVALID, \
-				       NULL, \
-				       NULL}
+				       (void *) 0, \
+				       (void *) 0}
 
 HB_EXTERN hb_bool_t
 hb_segment_properties_equal (const hb_segment_properties_t *a,
 			     const hb_segment_properties_t *b);
 
 HB_EXTERN unsigned int
 hb_segment_properties_hash (const hb_segment_properties_t *p);
 
deleted file mode 100644
--- a/gfx/harfbuzz/src/hb-cache-private.hh
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright © 2012  Google, Inc.
- *
- *  This is part of HarfBuzz, a text shaping library.
- *
- * Permission is hereby granted, without written agreement and without
- * license or royalty fees, to use, copy, modify, and distribute this
- * software and its documentation for any purpose, provided that the
- * above copyright notice and the following two paragraphs appear in
- * all copies of this software.
- *
- * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
- * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
- * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
- * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
- * DAMAGE.
- *
- * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
- * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
- * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
- * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
- *
- * Google Author(s): Behdad Esfahbod
- */
-
-#ifndef HB_CACHE_PRIVATE_HH
-#define HB_CACHE_PRIVATE_HH
-
-#include "hb-private.hh"
-
-
-/* Implements a lock-free cache for int->int functions. */
-
-template <unsigned int key_bits, unsigned int value_bits, unsigned int cache_bits>
-struct hb_cache_t
-{
-  ASSERT_STATIC (key_bits >= cache_bits);
-  ASSERT_STATIC (key_bits + value_bits - cache_bits < 8 * sizeof (unsigned int));
-
-  inline void clear (void)
-  {
-    memset (values, 255, sizeof (values));
-  }
-
-  inline bool get (unsigned int key, unsigned int *value)
-  {
-    unsigned int k = key & ((1u<<cache_bits)-1);
-    unsigned int v = values[k];
-    if ((v >> value_bits) != (key >> cache_bits))
-      return false;
-    *value = v & ((1u<<value_bits)-1);
-    return true;
-  }
-
-  inline bool set (unsigned int key, unsigned int value)
-  {
-    if (unlikely ((key >> key_bits) || (value >> value_bits)))
-      return false; /* Overflows */
-    unsigned int k = key & ((1u<<cache_bits)-1);
-    unsigned int v = ((key>>cache_bits)<<value_bits) | value;
-    values[k] = v;
-    return true;
-  }
-
-  private:
-  unsigned int values[1u<<cache_bits];
-};
-
-typedef hb_cache_t<21, 16, 8> hb_cmap_cache_t;
-typedef hb_cache_t<16, 24, 8> hb_advance_cache_t;
-
-
-#endif /* HB_CACHE_PRIVATE_HH */
--- a/gfx/harfbuzz/src/hb-common.cc
+++ b/gfx/harfbuzz/src/hb-common.cc
@@ -269,23 +269,23 @@ retry:
 
   for (hb_language_item_t *lang = first_lang; lang; lang = lang->next)
     if (*lang == key)
       return lang;
 
   /* Not found; allocate one. */
   hb_language_item_t *lang = (hb_language_item_t *) calloc (1, sizeof (hb_language_item_t));
   if (unlikely (!lang))
-    return NULL;
+    return nullptr;
   lang->next = first_lang;
   *lang = key;
   if (unlikely (!lang->lang))
   {
     free (lang);
-    return NULL;
+    return nullptr;
   }
 
   if (!hb_atomic_ptr_cmpexch (&langs, first_lang, lang)) {
     lang->finish ();
     free (lang);
     goto retry;
   }
 
@@ -313,17 +313,17 @@ retry:
  * Since: 0.9.2
  **/
 hb_language_t
 hb_language_from_string (const char *str, int len)
 {
   if (!str || !len || !*str)
     return HB_LANGUAGE_INVALID;
 
-  hb_language_item_t *item = NULL;
+  hb_language_item_t *item = nullptr;
   if (len >= 0)
   {
     /* NUL-terminate it. */
     char strbuf[64];
     len = MIN (len, (int) sizeof (strbuf) - 1);
     memcpy (strbuf, str, len);
     strbuf[len] = '\0';
     item = lang_find_or_insert (strbuf);
@@ -344,17 +344,17 @@ hb_language_from_string (const char *str
  * A %NULL-terminated string representing the @language. Must not be freed by
  * the caller.
  *
  * Since: 0.9.2
  **/
 const char *
 hb_language_to_string (hb_language_t language)
 {
-  /* This is actually NULL-safe! */
+  /* This is actually nullptr-safe! */
   return language->s;
 }
 
 /**
  * hb_language_get_default:
  *
  * 
  *
@@ -364,17 +364,17 @@ hb_language_to_string (hb_language_t lan
  **/
 hb_language_t
 hb_language_get_default (void)
 {
   static hb_language_t default_language = HB_LANGUAGE_INVALID;
 
   hb_language_t language = (hb_language_t) hb_atomic_ptr_get (&default_language);
   if (unlikely (language == HB_LANGUAGE_INVALID)) {
-    language = hb_language_from_string (setlocale (LC_CTYPE, NULL), -1);
+    language = hb_language_from_string (setlocale (LC_CTYPE, nullptr), -1);
     (void) hb_atomic_ptr_cmpexch (&default_language, HB_LANGUAGE_INVALID, language);
   }
 
   return default_language;
 }
 
 
 /* hb_script_t */
@@ -557,19 +557,19 @@ hb_user_data_array_t::set (hb_user_data_
   bool ret = !!items.replace_or_insert (item, lock, (bool) replace);
 
   return ret;
 }
 
 void *
 hb_user_data_array_t::get (hb_user_data_key_t *key)
 {
-  hb_user_data_item_t item = {NULL, NULL, NULL};
+  hb_user_data_item_t item = {nullptr, nullptr, nullptr};
 
-  return items.find (key, &item, lock) ? item.data : NULL;
+  return items.find (key, &item, lock) ? item.data : nullptr;
 }
 
 
 /* hb_version */
 
 /**
  * hb_version:
  * @major: (out): Library major version component.
@@ -717,19 +717,19 @@ free_C_locale (void)
 static locale_t
 get_C_locale (void)
 {
 retry:
   locale_t C = (locale_t) hb_atomic_ptr_get (&C_locale);
 
   if (unlikely (!C))
   {
-    C = newlocale (LC_ALL_MASK, "C", NULL);
+    C = newlocale (LC_ALL_MASK, "C", nullptr);
 
-    if (!hb_atomic_ptr_cmpexch (&C_locale, NULL, C))
+    if (!hb_atomic_ptr_cmpexch (&C_locale, nullptr, C))
     {
       freelocale (C_locale);
       goto retry;
     }
 
 #ifdef HB_USE_ATEXIT
     atexit (free_C_locale); /* First person registers atexit() callback. */
 #endif
--- a/gfx/harfbuzz/src/hb-common.h
+++ b/gfx/harfbuzz/src/hb-common.h
@@ -129,17 +129,17 @@ hb_direction_to_string (hb_direction_t d
 typedef const struct hb_language_impl_t *hb_language_t;
 
 HB_EXTERN hb_language_t
 hb_language_from_string (const char *str, int len);
 
 HB_EXTERN const char *
 hb_language_to_string (hb_language_t language);
 
-#define HB_LANGUAGE_INVALID ((hb_language_t) NULL)
+#define HB_LANGUAGE_INVALID ((hb_language_t) 0)
 
 HB_EXTERN hb_language_t
 hb_language_get_default (void);
 
 
 /* hb_script_t */
 
 /* http://unicode.org/iso15924/ */
--- a/gfx/harfbuzz/src/hb-coretext.cc
+++ b/gfx/harfbuzz/src/hb-coretext.cc
@@ -60,22 +60,22 @@ release_table_data (void *user_data)
 }
 
 static hb_blob_t *
 reference_table  (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
 {
   CGFontRef cg_font = reinterpret_cast<CGFontRef> (user_data);
   CFDataRef cf_data = CGFontCopyTableForTag (cg_font, tag);
   if (unlikely (!cf_data))
-    return NULL;
+    return nullptr;
 
   const char *data = reinterpret_cast<const char*> (CFDataGetBytePtr (cf_data));
   const size_t length = CFDataGetLength (cf_data);
   if (!data || !length)
-    return NULL;
+    return nullptr;
 
   return hb_blob_create (data, length, HB_MEMORY_MODE_READONLY,
 			 reinterpret_cast<void *> (const_cast<__CFData *> (cf_data)),
 			 release_table_data);
 }
 
 static void
 _hb_cg_font_release (void *data)
@@ -120,25 +120,25 @@ get_last_resort_font_desc (void)
   CFRelease (attributes);
   return font_desc;
 }
 
 static void
 release_data (void *info, const void *data, size_t size)
 {
   assert (hb_blob_get_length ((hb_blob_t *) info) == size &&
-          hb_blob_get_data ((hb_blob_t *) info, NULL) == data);
+          hb_blob_get_data ((hb_blob_t *) info, nullptr) == data);
 
   hb_blob_destroy ((hb_blob_t *) info);
 }
 
 static CGFontRef
 create_cg_font (hb_face_t *face)
 {
-  CGFontRef cg_font = NULL;
+  CGFontRef cg_font = nullptr;
   if (face->destroy == _hb_cg_font_release)
   {
     cg_font = CGFontRetain ((CGFontRef) face->user_data);
   }
   else
   {
     hb_blob_t *blob = hb_face_reference_blob (face);
     unsigned int blob_length;
@@ -156,70 +156,70 @@ create_cg_font (hb_face_t *face)
     }
   }
   return cg_font;
 }
 
 static CTFontRef
 create_ct_font (CGFontRef cg_font, CGFloat font_size)
 {
-  CTFontRef ct_font = NULL;
+  CTFontRef ct_font = nullptr;
 
   /* CoreText does not enable trak table usage / tracking when creating a CTFont
    * using CTFontCreateWithGraphicsFont. The only way of enabling tracking seems
    * to be through the CTFontCreateUIFontForLanguage call. */
   CFStringRef cg_postscript_name = CGFontCopyPostScriptName (cg_font);
   if (CFStringHasPrefix (cg_postscript_name, CFSTR (".SFNSText")) ||
       CFStringHasPrefix (cg_postscript_name, CFSTR (".SFNSDisplay")))
   {
     CTFontUIFontType font_type = kCTFontUIFontSystem;
     if (CFStringHasSuffix (cg_postscript_name, CFSTR ("-Bold")))
       font_type = kCTFontUIFontEmphasizedSystem;
 
-    ct_font = CTFontCreateUIFontForLanguage (font_type, font_size, NULL);
+    ct_font = CTFontCreateUIFontForLanguage (font_type, font_size, nullptr);
     CFStringRef ct_result_name = CTFontCopyPostScriptName(ct_font);
     if (CFStringCompare (ct_result_name, cg_postscript_name, 0) != kCFCompareEqualTo)
     {
       CFRelease(ct_font);
-      ct_font = NULL;
+      ct_font = nullptr;
     }
     CFRelease (ct_result_name);
   }
   CFRelease (cg_postscript_name);
 
   if (!ct_font)
-    ct_font = CTFontCreateWithGraphicsFont (cg_font, font_size, NULL, NULL);
+    ct_font = CTFontCreateWithGraphicsFont (cg_font, font_size, nullptr, nullptr);
 
   if (unlikely (!ct_font)) {
     DEBUG_MSG (CORETEXT, cg_font, "Font CTFontCreateWithGraphicsFont() failed");
-    return NULL;
+    return nullptr;
   }
 
   /* crbug.com/576941 and crbug.com/625902 and the investigation in the latter
    * bug indicate that the cascade list reconfiguration occasionally causes
    * crashes in CoreText on OS X 10.9, thus let's skip this step on older
    * operating system versions. Except for the emoji font, where _not_
    * reconfiguring the cascade list causes CoreText crashes. For details, see
    * crbug.com/549610 */
   // 0x00070000 stands for "kCTVersionNumber10_10", see CoreText.h
-  if (&CTGetCoreTextVersion != NULL && CTGetCoreTextVersion() < 0x00070000) {
+  if (&CTGetCoreTextVersion != nullptr && CTGetCoreTextVersion() < 0x00070000) {
     CFStringRef fontName = CTFontCopyPostScriptName (ct_font);
     bool isEmojiFont = CFStringCompare (fontName, CFSTR("AppleColorEmoji"), 0) == kCFCompareEqualTo;
     CFRelease (fontName);
     if (!isEmojiFont)
       return ct_font;
   }
 
   CFURLRef original_url = (CFURLRef)CTFontCopyAttribute(ct_font, kCTFontURLAttribute);
 
   /* Create font copy with cascade list that has LastResort first; this speeds up CoreText
    * font fallback which we don't need anyway. */
   {
     CTFontDescriptorRef last_resort_font_desc = get_last_resort_font_desc ();
-    CTFontRef new_ct_font = CTFontCreateCopyWithAttributes (ct_font, 0.0, NULL, last_resort_font_desc);
+    CTFontRef new_ct_font = CTFontCreateCopyWithAttributes (ct_font, 0.0, nullptr, last_resort_font_desc);
     CFRelease (last_resort_font_desc);
     if (new_ct_font)
     {
       /* The CTFontCreateCopyWithAttributes call fails to stay on the same font
        * when reconfiguring the cascade list and may switch to a different font
        * when there are fonts that go by the same name, since the descriptor is
        * just name and size.
        *
@@ -252,17 +252,17 @@ create_ct_font (CGFontRef cg_font, CGFlo
 hb_coretext_shaper_face_data_t *
 _hb_coretext_shaper_face_data_create (hb_face_t *face)
 {
   CGFontRef cg_font = create_cg_font (face);
 
   if (unlikely (!cg_font))
   {
     DEBUG_MSG (CORETEXT, face, "CGFont creation failed..");
-    return NULL;
+    return nullptr;
   }
 
   return (hb_coretext_shaper_face_data_t *) cg_font;
 }
 
 void
 _hb_coretext_shaper_face_data_destroy (hb_coretext_shaper_face_data_t *data)
 {
@@ -270,38 +270,38 @@ void
 }
 
 /*
  * 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 NULL;
+  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 NULL;
+  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));
 
   if (unlikely (!ct_font))
   {
     DEBUG_MSG (CORETEXT, font, "CGFont creation failed..");
-    return NULL;
+    return nullptr;
   }
 
   return (hb_coretext_shaper_font_data_t *) ct_font;
 }
 
 void
 _hb_coretext_shaper_font_data_destroy (hb_coretext_shaper_font_data_t *data)
 {
@@ -328,17 +328,17 @@ hb_coretext_shaper_shape_plan_data_t *
 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 NULL;
+  if (unlikely (!hb_coretext_shaper_font_data_ensure (font))) return nullptr;
   return (CTFontRef)HB_SHAPER_DATA_GET (font);
 }
 
 
 /*
  * shaper
  */
 
@@ -673,17 +673,17 @@ hb_bool_t
 	    CFStringRef keys[] = {
 	      kCTFontFeatureTypeIdentifierKey,
 	      kCTFontFeatureSelectorIdentifierKey
 	    };
 	    CFNumberRef values[] = {
 	      CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &active_features[j].rec.feature),
 	      CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &active_features[j].rec.setting)
 	    };
-	    ASSERT_STATIC (ARRAY_LENGTH (keys) == ARRAY_LENGTH (values));
+	    static_assert ((ARRAY_LENGTH_CONST (keys) == ARRAY_LENGTH_CONST (values)), "");
 	    CFDictionaryRef dict = CFDictionaryCreate (kCFAllocatorDefault,
 						       (const void **) keys,
 						       (const void **) values,
 						       ARRAY_LENGTH (keys),
 						       &kCFTypeDictionaryKeyCallBacks,
 						       &kCFTypeDictionaryValueCallBacks);
 	    for (unsigned int i = 0; i < ARRAY_LENGTH (values); i++)
 	      CFRelease (values[i]);
@@ -699,22 +699,22 @@ hb_bool_t
 							   1,
 							   &kCFTypeDictionaryKeyCallBacks,
 							   &kCFTypeDictionaryValueCallBacks);
 	  CFRelease (features_array);
 
 	  CTFontDescriptorRef font_desc = CTFontDescriptorCreateWithAttributes (attributes);
 	  CFRelease (attributes);
 
-	  range->font = CTFontCreateCopyWithAttributes (ct_font, 0.0, NULL, font_desc);
+	  range->font = CTFontCreateCopyWithAttributes (ct_font, 0.0, nullptr, font_desc);
 	  CFRelease (font_desc);
 	}
 	else
 	{
-	  range->font = NULL;
+	  range->font = nullptr;
 	}
 
 	range->index_first = last_index;
 	range->index_last  = event->index - 1;
 
 	last_index = event->index;
       }
 
@@ -774,37 +774,37 @@ hb_bool_t
     unsigned int cluster = buffer->info[i].cluster;
     log_clusters[chars_len++] = cluster;
     if (hb_in_range (c, 0x10000u, 0x10FFFFu))
       log_clusters[chars_len++] = cluster; /* Surrogates. */
   }
 
 #define FAIL(...) \
   HB_STMT_START { \
-    DEBUG_MSG (CORETEXT, NULL, __VA_ARGS__); \
+    DEBUG_MSG (CORETEXT, nullptr, __VA_ARGS__); \
     ret = false; \
     goto fail; \
   } HB_STMT_END;
 
   bool ret = true;
-  CFStringRef string_ref = NULL;
-  CTLineRef line = NULL;
+  CFStringRef string_ref = nullptr;
+  CTLineRef line = nullptr;
 
   if (0)
   {
 resize_and_retry:
     DEBUG_MSG (CORETEXT, buffer, "Buffer resize");
     /* string_ref uses the scratch-buffer for backing store, and line references
      * string_ref (via attr_string).  We must release those before resizing buffer. */
     assert (string_ref);
     assert (line);
     CFRelease (string_ref);
     CFRelease (line);
-    string_ref = NULL;
-    line = NULL;
+    string_ref = nullptr;
+    line = nullptr;
 
     /* Get previous start-of-scratch-area, that we use later for readjusting
      * our existing scratch arrays. */
     unsigned int old_scratch_used;
     hb_buffer_t::scratch_buffer_t *old_scratch;
     old_scratch = buffer->get_scratch_buffer (&old_scratch_used);
     old_scratch_used = scratch - old_scratch;
 
@@ -815,17 +815,17 @@ resize_and_retry:
      * cleanest way to do without completely restructuring the rest of this shaper. */
     scratch = buffer->get_scratch_buffer (&scratch_size);
     pchars = reinterpret_cast<UniChar *> (((char *) scratch + ((char *) pchars - (char *) old_scratch)));
     log_clusters = reinterpret_cast<unsigned int *> (((char *) scratch + ((char *) log_clusters - (char *) old_scratch)));
     scratch += old_scratch_used;
     scratch_size -= old_scratch_used;
   }
   {
-    string_ref = CFStringCreateWithCharactersNoCopy (NULL,
+    string_ref = CFStringCreateWithCharactersNoCopy (nullptr,
 						     pchars, chars_len,
 						     kCFAllocatorNull);
     if (unlikely (!string_ref))
       FAIL ("CFStringCreateWithCharactersNoCopy failed");
 
     /* Create an attributed string, populate it, and create a line from it, then release attributed string. */
     {
       CFMutableAttributedStringRef attr_string = CFAttributedStringCreateMutable (kCFAllocatorDefault,
@@ -932,17 +932,17 @@ resize_and_retry:
       line = CTTypesetterCreateLine (typesetter, CFRangeMake(0, 0));
       CFRelease (typesetter);
       if (unlikely (!line))
 	FAIL ("CTTypesetterCreateLine failed");
     }
 
     CFArrayRef glyph_runs = CTLineGetGlyphRuns (line);
     unsigned int num_runs = CFArrayGetCount (glyph_runs);
-    DEBUG_MSG (CORETEXT, NULL, "Num runs: %d", num_runs);
+    DEBUG_MSG (CORETEXT, nullptr, "Num runs: %d", num_runs);
 
     buffer->len = 0;
     uint32_t status_and = ~0, status_or = 0;
     double advances_so_far = 0;
     /* For right-to-left runs, CoreText returns the glyphs positioned such that
      * any trailing whitespace is to the left of (0,0).  Adjust coordinate system
      * to fix for that.  Test with any RTL string with trailing spaces.
      * https://code.google.com/p/chromium/issues/detail?id=469028
@@ -958,17 +958,17 @@ resize_and_retry:
 
     for (unsigned int i = 0; i < num_runs; i++)
     {
       CTRunRef run = static_cast<CTRunRef>(CFArrayGetValueAtIndex (glyph_runs, i));
       CTRunStatus run_status = CTRunGetStatus (run);
       status_or  |= run_status;
       status_and &= run_status;
       DEBUG_MSG (CORETEXT, run, "CTRunStatus: %x", run_status);
-      double run_advance = CTRunGetTypographicBounds (run, range_all, NULL, NULL, NULL);
+      double run_advance = CTRunGetTypographicBounds (run, range_all, nullptr, nullptr, nullptr);
       if (HB_DIRECTION_IS_VERTICAL (buffer->props.direction))
 	  run_advance = -run_advance;
       DEBUG_MSG (CORETEXT, run, "Run advance: %g", run_advance);
 
       /* CoreText does automatic font fallback (AKA "cascading") for  characters
        * not supported by the requested font, and provides no way to turn it off,
        * so we must detect if the returned run uses a font other than the requested
        * one and fill in the buffer with .notdef glyphs instead of random glyph
@@ -1084,39 +1084,39 @@ resize_and_retry:
 
       if (!buffer->ensure_inplace (buffer->len + num_glyphs))
 	goto resize_and_retry;
 
       hb_glyph_info_t *run_info = buffer->info + buffer->len;
 
       /* Testing used to indicate that CTRunGetGlyphsPtr, etc (almost?) always
        * succeed, and so copying data to our own buffer will be rare.  Reports
-       * have it that this changed in OS X 10.10 Yosemite, and NULL is returned
+       * have it that this changed in OS X 10.10 Yosemite, and nullptr is returned
        * frequently.  At any rate, we can test that codepath by setting USE_PTR
        * to false. */
 
 #define USE_PTR true
 
 #define SCRATCH_SAVE() \
   unsigned int scratch_size_saved = scratch_size; \
   hb_buffer_t::scratch_buffer_t *scratch_saved = scratch
 
 #define SCRATCH_RESTORE() \
   scratch_size = scratch_size_saved; \
   scratch = scratch_saved;
 
       { /* Setup glyphs */
         SCRATCH_SAVE();
-	const CGGlyph* glyphs = USE_PTR ? CTRunGetGlyphsPtr (run) : NULL;
+	const CGGlyph* glyphs = USE_PTR ? CTRunGetGlyphsPtr (run) : nullptr;
 	if (!glyphs) {
 	  ALLOCATE_ARRAY (CGGlyph, glyph_buf, num_glyphs, goto resize_and_retry);
 	  CTRunGetGlyphs (run, range_all, glyph_buf);
 	  glyphs = glyph_buf;
 	}
-	const CFIndex* string_indices = USE_PTR ? CTRunGetStringIndicesPtr (run) : NULL;
+	const CFIndex* string_indices = USE_PTR ? CTRunGetStringIndicesPtr (run) : nullptr;
 	if (!string_indices) {
 	  ALLOCATE_ARRAY (CFIndex, index_buf, num_glyphs, goto resize_and_retry);
 	  CTRunGetStringIndices (run, range_all, index_buf);
 	  string_indices = index_buf;
 	}
 	hb_glyph_info_t *info = run_info;
 	for (unsigned int j = 0; j < num_glyphs; j++)
 	{
@@ -1128,17 +1128,17 @@ resize_and_retry:
       }
       {
         /* Setup positions.
 	 * Note that CoreText does not return advances for glyphs.  As such,
 	 * for all but last glyph, we use the delta position to next glyph as
 	 * advance (in the advance direction only), and for last glyph we set
 	 * whatever is needed to make the whole run's advance add up. */
         SCRATCH_SAVE();
-	const CGPoint* positions = USE_PTR ? CTRunGetPositionsPtr (run) : NULL;
+	const CGPoint* positions = USE_PTR ? CTRunGetPositionsPtr (run) : nullptr;
 	if (!positions) {
 	  ALLOCATE_ARRAY (CGPoint, position_buf, num_glyphs, goto resize_and_retry);
 	  CTRunGetPositions (run, range_all, position_buf);
 	  positions = position_buf;
 	}
 	hb_glyph_info_t *info = run_info;
 	if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction))
 	{
@@ -1295,22 +1295,22 @@ hb_coretext_aat_shaper_face_data_t *
   static const hb_tag_t tags[] = {HB_CORETEXT_TAG_MORX, HB_CORETEXT_TAG_MORT, HB_CORETEXT_TAG_KERX};
 
   for (unsigned int i = 0; i < ARRAY_LENGTH (tags); i++)
   {
     hb_blob_t *blob = face->reference_table (tags[i]);
     if (hb_blob_get_length (blob))
     {
       hb_blob_destroy (blob);
-      return hb_coretext_shaper_face_data_ensure (face) ? (hb_coretext_aat_shaper_face_data_t *) HB_SHAPER_DATA_SUCCEEDED : NULL;
+      return hb_coretext_shaper_face_data_ensure (face) ? (hb_coretext_aat_shaper_face_data_t *) HB_SHAPER_DATA_SUCCEEDED : nullptr;
     }
     hb_blob_destroy (blob);
   }
 
-  return NULL;
+  return nullptr;
 }
 
 void
 _hb_coretext_aat_shaper_face_data_destroy (hb_coretext_aat_shaper_face_data_t *data HB_UNUSED)
 {
 }
 
 
@@ -1318,17 +1318,17 @@ void
  * shaper font data
  */
 
 struct hb_coretext_aat_shaper_font_data_t {};
 
 hb_coretext_aat_shaper_font_data_t *
 _hb_coretext_aat_shaper_font_data_create (hb_font_t *font)
 {
-  return hb_coretext_shaper_font_data_ensure (font) ? (hb_coretext_aat_shaper_font_data_t *) HB_SHAPER_DATA_SUCCEEDED : NULL;
+  return hb_coretext_shaper_font_data_ensure (font) ? (hb_coretext_aat_shaper_font_data_t *) HB_SHAPER_DATA_SUCCEEDED : nullptr;
 }
 
 void
 _hb_coretext_aat_shaper_font_data_destroy (hb_coretext_aat_shaper_font_data_t *data HB_UNUSED)
 {
 }
 
 
--- a/gfx/harfbuzz/src/hb-deprecated.h
+++ b/gfx/harfbuzz/src/hb-deprecated.h
@@ -29,16 +29,17 @@
 #endif
 
 #ifndef HB_DEPRECATED_H
 #define HB_DEPRECATED_H
 
 #include "hb-common.h"
 #include "hb-unicode.h"
 #include "hb-font.h"
+#include "hb-set.h"
 
 HB_BEGIN_DECLS
 
 #ifndef HB_DISABLE_DEPRECATED
 
 #define HB_SCRIPT_CANADIAN_ABORIGINAL		HB_SCRIPT_CANADIAN_SYLLABICS
 
 #define HB_BUFFER_FLAGS_DEFAULT			HB_BUFFER_FLAG_DEFAULT
@@ -49,13 +50,16 @@ typedef hb_bool_t (*hb_font_get_glyph_fu
 					       hb_codepoint_t *glyph,
 					       void *user_data);
 
 HB_EXTERN void
 hb_font_funcs_set_glyph_func (hb_font_funcs_t *ffuncs,
 			      hb_font_get_glyph_func_t func,
 			      void *user_data, hb_destroy_func_t destroy);
 
+HB_EXTERN void
+hb_set_invert (hb_set_t *set);
+
 #endif
 
 HB_END_DECLS
 
 #endif /* HB_DEPRECATED_H */
--- a/gfx/harfbuzz/src/hb-directwrite.cc
+++ b/gfx/harfbuzz/src/hb-directwrite.cc
@@ -135,42 +135,42 @@ struct hb_directwrite_shaper_face_data_t
 };
 
 hb_directwrite_shaper_face_data_t *
 _hb_directwrite_shaper_face_data_create(hb_face_t *face)
 {
   hb_directwrite_shaper_face_data_t *data =
     (hb_directwrite_shaper_face_data_t *) malloc (sizeof (hb_directwrite_shaper_face_data_t));
   if (unlikely (!data))
-    return NULL;
+    return nullptr;
 
   // TODO: factory and fontFileLoader should be cached separately
   IDWriteFactory* dwriteFactory;
   DWriteCreateFactory (
     DWRITE_FACTORY_TYPE_SHARED,
     __uuidof (IDWriteFactory),
     (IUnknown**) &dwriteFactory
   );
 
   HRESULT hr;
   hb_blob_t *blob = hb_face_reference_blob (face);
   IDWriteFontFileStream *fontFileStream = new DWriteFontFileStream (
-    (uint8_t*) hb_blob_get_data (blob, NULL), hb_blob_get_length (blob));
+    (uint8_t*) hb_blob_get_data (blob, nullptr), hb_blob_get_length (blob));
 
   IDWriteFontFileLoader *fontFileLoader = new DWriteFontFileLoader (fontFileStream);
   dwriteFactory->RegisterFontFileLoader (fontFileLoader);
 
   IDWriteFontFile *fontFile;
   uint64_t fontFileKey = 0;
   hr = dwriteFactory->CreateCustomFontFileReference (&fontFileKey, sizeof (fontFileKey),
       fontFileLoader, &fontFile);
 
 #define FAIL(...) \
   HB_STMT_START { \
-    DEBUG_MSG (DIRECTWRITE, NULL, __VA_ARGS__); \
+    DEBUG_MSG (DIRECTWRITE, nullptr, __VA_ARGS__); \
     return false; \
   } HB_STMT_END;
 
   if (FAILED (hr)) {
     FAIL ("Failed to load font file from data!");
     return false;
   }
 
@@ -228,22 +228,22 @@ void
  */
 
 struct hb_directwrite_shaper_font_data_t {
 };
 
 hb_directwrite_shaper_font_data_t *
 _hb_directwrite_shaper_font_data_create (hb_font_t *font)
 {
-  if (unlikely (!hb_directwrite_shaper_face_data_ensure (font->face))) return NULL;
+  if (unlikely (!hb_directwrite_shaper_face_data_ensure (font->face))) return nullptr;
 
   hb_directwrite_shaper_font_data_t *data =
     (hb_directwrite_shaper_font_data_t *) malloc (sizeof (hb_directwrite_shaper_font_data_t));
   if (unlikely (!data))
-    return NULL;
+    return nullptr;
 
   return data;
 }
 
 void
 _hb_directwrite_shaper_font_data_destroy (hb_directwrite_shaper_font_data_t *data)
 {
   free (data);
@@ -308,17 +308,17 @@ public:
   TextAnalysis(const wchar_t* text,
     uint32_t textLength,
     const wchar_t* localeName,
     DWRITE_READING_DIRECTION readingDirection)
     : mText(text)
     , mTextLength(textLength)
     , mLocaleName(localeName)
     , mReadingDirection(readingDirection)
-    , mCurrentRun(NULL) { };
+    , mCurrentRun(nullptr) { };
 
   ~TextAnalysis() {
     // delete runs, except mRunHead which is part of the TextAnalysis object
     for (Run *run = mRunHead.nextRun; run;) {
       Run *origRun = run;
       run = run->nextRun;
       free (origRun);
     }
@@ -332,17 +332,17 @@ public:
     HRESULT hr = S_OK;
 
     // Initially start out with one result that covers the entire range.
     // This result will be subdivided by the analysis processes.
     mRunHead.mTextStart = 0;
     mRunHead.mTextLength = mTextLength;
     mRunHead.mBidiLevel =
       (mReadingDirection == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT);
-    mRunHead.nextRun = NULL;
+    mRunHead.nextRun = nullptr;
     mCurrentRun = &mRunHead;
 
     // Call each of the analyzers in sequence, recording their results.
     if (SUCCEEDED (hr = textAnalyzer->AnalyzeScript (this, 0, mTextLength, this))) {
       *runHead = &mRunHead;
     }
 
     return hr;
@@ -351,34 +351,34 @@ public:
   // IDWriteTextAnalysisSource implementation
 
   IFACEMETHODIMP GetTextAtPosition(uint32_t textPosition,
     OUT wchar_t const** textString,
     OUT uint32_t* textLength)
   {
     if (textPosition >= mTextLength) {
       // No text at this position, valid query though.
-      *textString = NULL;
+      *textString = nullptr;
       *textLength = 0;
     }
     else {
       *textString = mText + textPosition;
       *textLength = mTextLength - textPosition;
     }
     return S_OK;
   }
 
   IFACEMETHODIMP GetTextBeforePosition(uint32_t textPosition,
     OUT wchar_t const** textString,
     OUT uint32_t* textLength)
   {
     if (textPosition == 0 || textPosition > mTextLength) {
       // Either there is no text before here (== 0), or this
       // is an invalid position. The query is considered valid thouh.
-      *textString = NULL;
+      *textString = nullptr;
       *textLength = 0;
     }
     else {
       *textString = mText;
       *textLength = textPosition;
     }
     return S_OK;
   }
@@ -394,17 +394,17 @@ public:
   }
 
   IFACEMETHODIMP
     GetNumberSubstitution(uint32_t textPosition,
     OUT uint32_t* textLength,
     OUT IDWriteNumberSubstitution** numberSubstitution)
   {
     // We do not support number substitution.
-    *numberSubstitution = NULL;
+    *numberSubstitution = nullptr;
     *textLength = mTextLength - textPosition;
 
     return S_OK;
   }
 
   // IDWriteTextAnalysisSink implementation
 
   IFACEMETHODIMP
@@ -612,39 +612,39 @@ static hb_bool_t
 
   /*
   * There's an internal 16-bit limit on some things inside the analyzer,
   * but we never attempt to shape a word longer than 64K characters
   * in a single gfxShapedWord, so we cannot exceed that limit.
   */
   uint32_t textLength = buffer->len;
 
-  TextAnalysis analysis(textString, textLength, NULL, readingDirection);
+  TextAnalysis analysis(textString, textLength, nullptr, readingDirection);
   TextAnalysis::Run *runHead;
   HRESULT hr;
   hr = analysis.GenerateResults(analyzer, &runHead);
 
 #define FAIL(...) \
   HB_STMT_START { \
-    DEBUG_MSG (DIRECTWRITE, NULL, __VA_ARGS__); \
+    DEBUG_MSG (DIRECTWRITE, nullptr, __VA_ARGS__); \
     return false; \
   } HB_STMT_END;
 
   if (FAILED (hr))
   {
     FAIL ("Analyzer failed to generate results.");
     return false;
   }
 
   uint32_t maxGlyphCount = 3 * textLength / 2 + 16;
   uint32_t glyphCount;
   bool isRightToLeft = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);
 
   const wchar_t localeName[20] = {0};
-  if (buffer->props.language != NULL)
+  if (buffer->props.language != nullptr)
   {
     mbstowcs ((wchar_t*) localeName,
       hb_language_to_string (buffer->props.language), 20);
   }
 
   DWRITE_TYPOGRAPHIC_FEATURES singleFeatures;
   singleFeatures.featureCount = num_features;
   if (num_features)
@@ -667,17 +667,17 @@ static hb_bool_t
   DWRITE_SHAPING_TEXT_PROPERTIES* textProperties = (DWRITE_SHAPING_TEXT_PROPERTIES*)
     malloc (textLength * sizeof (DWRITE_SHAPING_TEXT_PROPERTIES));
 retry_getglyphs:
   uint16_t* glyphIndices = (uint16_t*) malloc (maxGlyphCount * sizeof (uint16_t));
   DWRITE_SHAPING_GLYPH_PROPERTIES* glyphProperties = (DWRITE_SHAPING_GLYPH_PROPERTIES*)
     malloc (maxGlyphCount * sizeof (DWRITE_SHAPING_GLYPH_PROPERTIES));
 
   hr = analyzer->GetGlyphs (textString, textLength, fontFace, false,
-    isRightToLeft, &runHead->mScript, localeName, NULL, &dwFeatures,
+    isRightToLeft, &runHead->mScript, localeName, nullptr, &dwFeatures,
     featureRangeLengths, 1, maxGlyphCount, clusterMap, textProperties, glyphIndices,
     glyphProperties, &glyphCount);
 
   if (unlikely (hr == HRESULT_FROM_WIN32 (ERROR_INSUFFICIENT_BUFFER)))
   {
     free (glyphIndices);
     free (glyphProperties);
 
--- a/gfx/harfbuzz/src/hb-face.cc
+++ b/gfx/harfbuzz/src/hb-face.cc
@@ -38,31 +38,31 @@
  * hb_face_t
  */
 
 const hb_face_t _hb_face_nil = {
   HB_OBJECT_HEADER_STATIC,
 
   true, /* immutable */
 
-  NULL, /* reference_table_func */
-  NULL, /* user_data */
-  NULL, /* destroy */
+  nullptr, /* reference_table_func */
+  nullptr, /* user_data */
+  nullptr, /* destroy */
 
   0,    /* index */
   1000, /* upem */
   0,    /* num_glyphs */
 
   {
 #define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_INVALID,
 #include "hb-shaper-list.hh"
 #undef HB_SHAPER_IMPLEMENT
   },
 
-  NULL, /* shape_plans */
+  nullptr, /* shape_plans */
 };
 
 
 /**
  * hb_face_create_for_tables:
  * @reference_table_func: (closure user_data) (destroy destroy) (scope notified):
  * @user_data: 
  * @destroy: 
@@ -104,17 +104,17 @@ typedef struct hb_face_for_data_closure_
 
 static hb_face_for_data_closure_t *
 _hb_face_for_data_closure_create (hb_blob_t *blob, unsigned int index)
 {
   hb_face_for_data_closure_t *closure;
 
   closure = (hb_face_for_data_closure_t *) calloc (1, sizeof (hb_face_for_data_closure_t));
   if (unlikely (!closure))
-    return NULL;
+    return nullptr;
 
   closure->blob = blob;
   closure->index = index;
 
   return closure;
 }
 
 static void
--- a/gfx/harfbuzz/src/hb-font.cc
+++ b/gfx/harfbuzz/src/hb-font.cc
@@ -31,17 +31,17 @@
 #include "hb-font-private.hh"
 
 
 /*
  * hb_font_funcs_t
  */
 
 static hb_bool_t
-hb_font_get_font_h_extents_nil (hb_font_t *font,
+hb_font_get_font_h_extents_nil (hb_font_t *font HB_UNUSED,
 				void *font_data HB_UNUSED,
 				hb_font_extents_t *metrics,
 				void *user_data HB_UNUSED)
 {
   memset (metrics, 0, sizeof (*metrics));
   return false;
 }
 static hb_bool_t
@@ -55,17 +55,17 @@ hb_font_get_font_h_extents_parent (hb_fo
     metrics->ascender = font->parent_scale_y_distance (metrics->ascender);
     metrics->descender = font->parent_scale_y_distance (metrics->descender);
     metrics->line_gap = font->parent_scale_y_distance (metrics->line_gap);
   }
   return ret;
 }
 
 static hb_bool_t
-hb_font_get_font_v_extents_nil (hb_font_t *font,
+hb_font_get_font_v_extents_nil (hb_font_t *font HB_UNUSED,
 				void *font_data HB_UNUSED,
 				hb_font_extents_t *metrics,
 				void *user_data HB_UNUSED)
 {
   memset (metrics, 0, sizeof (*metrics));
   return false;
 }
 static hb_bool_t
@@ -342,22 +342,22 @@ hb_font_get_glyph_from_name_parent (hb_f
 }
 
 static const hb_font_funcs_t _hb_font_funcs_nil = {
   HB_OBJECT_HEADER_STATIC,
 
   true, /* immutable */
 
   {
-#define HB_FONT_FUNC_IMPLEMENT(name) NULL,
+#define HB_FONT_FUNC_IMPLEMENT(name) nullptr,
     HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
 #undef HB_FONT_FUNC_IMPLEMENT
   },
   {
-#define HB_FONT_FUNC_IMPLEMENT(name) NULL,
+#define HB_FONT_FUNC_IMPLEMENT(name) nullptr,
     HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
 #undef HB_FONT_FUNC_IMPLEMENT
   },
   {
     {
 #define HB_FONT_FUNC_IMPLEMENT(name) hb_font_get_##name##_nil,
       HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
 #undef HB_FONT_FUNC_IMPLEMENT
@@ -365,22 +365,22 @@ static const hb_font_funcs_t _hb_font_fu
   }
 };
 static const hb_font_funcs_t _hb_font_funcs_parent = {
   HB_OBJECT_HEADER_STATIC,
 
   true, /* immutable */
 
   {
-#define HB_FONT_FUNC_IMPLEMENT(name) NULL,
+#define HB_FONT_FUNC_IMPLEMENT(name) nullptr,
     HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
 #undef HB_FONT_FUNC_IMPLEMENT
   },
   {
-#define HB_FONT_FUNC_IMPLEMENT(name) NULL,
+#define HB_FONT_FUNC_IMPLEMENT(name) nullptr,
     HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
 #undef HB_FONT_FUNC_IMPLEMENT
   },
   {
     {
 #define HB_FONT_FUNC_IMPLEMENT(name) hb_font_get_##name##_parent,
       HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
 #undef HB_FONT_FUNC_IMPLEMENT
@@ -558,18 +558,18 @@ hb_font_funcs_set_##name##_func (hb_font
     ffuncs->destroy.name (ffuncs->user_data.name);                       \
                                                                          \
   if (func) {                                                            \
     ffuncs->get.f.name = func;                                           \
     ffuncs->user_data.name = user_data;                                  \
     ffuncs->destroy.name = destroy;                                      \
   } else {                                                               \
     ffuncs->get.f.name = hb_font_get_##name##_parent;                    \
-    ffuncs->user_data.name = NULL;                                       \
-    ffuncs->destroy.name = NULL;                                         \
+    ffuncs->user_data.name = nullptr;                                       \
+    ffuncs->destroy.name = nullptr;                                         \
   }                                                                      \
 }
 
 HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
 #undef HB_FONT_FUNC_IMPLEMENT
 
 bool
 hb_font_t::has_func (unsigned int i)
@@ -1156,17 +1156,17 @@ hb_font_create_sub_font (hb_font_t *pare
   font->x_scale = parent->x_scale;
   font->y_scale = parent->y_scale;
   font->x_ppem = parent->x_ppem;
   font->y_ppem = parent->y_ppem;
   font->ptem = parent->ptem;
 
   font->num_coords = parent->num_coords;
   if (!font->num_coords)
-    font->coords = NULL;
+    font->coords = nullptr;
   else
   {
     unsigned int size = parent->num_coords * sizeof (parent->coords[0]);
     font->coords = (int *) malloc (size);
     if (unlikely (!font->coords))
       font->num_coords = 0;
     else
       memcpy (font->coords, parent->coords, size);
@@ -1187,32 +1187,32 @@ hb_font_create_sub_font (hb_font_t *pare
 hb_font_t *
 hb_font_get_empty (void)
 {
   static const hb_font_t _hb_font_nil = {
     HB_OBJECT_HEADER_STATIC,
 
     true, /* immutable */
 
-    NULL, /* parent */
+    nullptr, /* parent */
     const_cast<hb_face_t *> (&_hb_face_nil),
 
     1000, /* x_scale */
     1000, /* y_scale */
 
     0, /* x_ppem */
     0, /* y_ppem */
     0, /* ptem */
 
     0, /* num_coords */
-    NULL, /* coords */
+    nullptr, /* coords */
 
     const_cast<hb_font_funcs_t *> (&_hb_font_funcs_nil), /* klass */
-    NULL, /* user_data */
-    NULL, /* destroy */
+    nullptr, /* user_data */
+    nullptr, /* destroy */
 
     {
 #define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_INVALID,
 #include "hb-shaper-list.hh"
 #undef HB_SHAPER_IMPLEMENT
     }
   };
 
@@ -1634,23 +1634,23 @@ hb_font_set_variations (hb_font_t *font,
 			const hb_variation_t *variations,
 			unsigned int variations_length)
 {
   if (font->immutable)
     return;
 
   if (!variations_length)
   {
-    hb_font_set_var_coords_normalized (font, NULL, 0);
+    hb_font_set_var_coords_normalized (font, nullptr, 0);
     return;
   }
 
   unsigned int coords_length = hb_ot_var_get_axis_count (font->face);
 
-  int *normalized = coords_length ? (int *) calloc (coords_length, sizeof (int)) : NULL;
+  int *normalized = coords_length ? (int *) calloc (coords_length, sizeof (int)) : nullptr;
   if (unlikely (coords_length && !normalized))
     return;
 
   hb_ot_var_normalize_variations (font->face,
 				  variations, variations_length,
 				  normalized, coords_length);
   _hb_font_adopt_var_coords_normalized (font, normalized, coords_length);
 }
@@ -1663,17 +1663,17 @@ hb_font_set_variations (hb_font_t *font,
 void
 hb_font_set_var_coords_design (hb_font_t *font,
 			       const float *coords,
 			       unsigned int coords_length)
 {
   if (font->immutable)
     return;
 
-  int *normalized = coords_length ? (int *) calloc (coords_length, sizeof (int)) : NULL;
+  int *normalized = coords_length ? (int *) calloc (coords_length, sizeof (int)) : nullptr;
   if (unlikely (coords_length && !normalized))
     return;
 
   hb_ot_var_normalize_coords (font->face, coords_length, coords, normalized);
   _hb_font_adopt_var_coords_normalized (font, normalized, coords_length);
 }
 
 /**
@@ -1684,17 +1684,17 @@ hb_font_set_var_coords_design (hb_font_t
 void
 hb_font_set_var_coords_normalized (hb_font_t *font,
 				   const int *coords, /* 2.14 normalized */
 				   unsigned int coords_length)
 {
   if (font->immutable)
     return;
 
-  int *copy = coords_length ? (int *) calloc (coords_length, sizeof (coords[0])) : NULL;
+  int *copy = coords_length ? (int *) calloc (coords_length, sizeof (coords[0])) : nullptr;
   if (unlikely (coords_length && !copy))
     return;
 
   if (coords_length)
     memcpy (copy, coords, coords_length * sizeof (coords[0]));
 
   _hb_font_adopt_var_coords_normalized (font, copy, coords_length);
 }
@@ -1744,17 +1744,17 @@ trampoline_create (FuncType           fu
 		   void              *user_data,
 		   hb_destroy_func_t  destroy)
 {
   typedef hb_trampoline_t<FuncType> trampoline_t;
 
   trampoline_t *trampoline = (trampoline_t *) calloc (1, sizeof (trampoline_t));
 
   if (unlikely (!trampoline))
-    return NULL;
+    return nullptr;
 
   trampoline->closure.user_data = user_data;
   trampoline->closure.destroy = destroy;
   trampoline->closure.ref_count = 1;
   trampoline->func = func;
 
   return trampoline;
 }
--- a/gfx/harfbuzz/src/hb-ft.cc
+++ b/gfx/harfbuzz/src/hb-ft.cc
@@ -28,18 +28,16 @@
  */
 
 #include "hb-private.hh"
 
 #include "hb-ft.h"
 
 #include "hb-font-private.hh"
 
-#include "hb-cache-private.hh" // Maybe use in the future?
-
 #include FT_ADVANCES_H
 #include FT_MULTIPLE_MASTERS_H
 #include FT_TRUETYPE_TABLES_H
 
 
 
 #ifndef HB_DEBUG_FT
 #define HB_DEBUG_FT (HB_DEBUG+0)
@@ -78,17 +76,17 @@ struct hb_ft_font_t
 };
 
 static hb_ft_font_t *
 _hb_ft_font_create (FT_Face ft_face, bool symbol, bool unref)
 {
   hb_ft_font_t *ft_font = (hb_ft_font_t *) calloc (1, sizeof (hb_ft_font_t));
 
   if (unlikely (!ft_font))
-    return NULL;
+    return nullptr;
 
   ft_font->ft_face = ft_face;
   ft_font->symbol = symbol;
   ft_font->unref = unref;
 
   ft_font->load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING;
 
   return ft_font;
@@ -153,17 +151,17 @@ hb_ft_font_get_load_flags (hb_font_t *fo
 
   return ft_font->load_flags;
 }
 
 FT_Face
 hb_ft_font_get_face (hb_font_t *font)
 {
   if (font->destroy != _hb_ft_font_destroy)
-    return NULL;
+    return nullptr;
 
   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font->user_data;
 
   return ft_font->ft_face;
 }
 
 
 
@@ -419,17 +417,17 @@ hb_ft_get_font_h_extents (hb_font_t *fon
   {
     metrics->ascender = -metrics->ascender;
     metrics->descender = -metrics->descender;
     metrics->line_gap = -metrics->line_gap;
   }
   return true;
 }
 
-static hb_font_funcs_t *static_ft_funcs = NULL;
+static hb_font_funcs_t *static_ft_funcs = nullptr;
 
 #ifdef HB_USE_ATEXIT
 static
 void free_static_ft_funcs (void)
 {
   hb_font_funcs_destroy (static_ft_funcs);
 }
 #endif
@@ -439,34 +437,34 @@ static void
 {
 retry:
   hb_font_funcs_t *funcs = (hb_font_funcs_t *) hb_atomic_ptr_get (&static_ft_funcs);
 
   if (unlikely (!funcs))
   {
     funcs = hb_font_funcs_create ();
 
-    hb_font_funcs_set_font_h_extents_func (funcs, hb_ft_get_font_h_extents, NULL, NULL);
-    //hb_font_funcs_set_font_v_extents_func (funcs, hb_ft_get_font_v_extents, NULL, NULL);
-    hb_font_funcs_set_nominal_glyph_func (funcs, hb_ft_get_nominal_glyph, NULL, NULL);
-    hb_font_funcs_set_variation_glyph_func (funcs, hb_ft_get_variation_glyph, NULL, NULL);
-    hb_font_funcs_set_glyph_h_advance_func (funcs, hb_ft_get_glyph_h_advance, NULL, NULL);
-    hb_font_funcs_set_glyph_v_advance_func (funcs, hb_ft_get_glyph_v_advance, NULL, NULL);
-    //hb_font_funcs_set_glyph_h_origin_func (funcs, hb_ft_get_glyph_h_origin, NULL, NULL);
-    hb_font_funcs_set_glyph_v_origin_func (funcs, hb_ft_get_glyph_v_origin, NULL, NULL);
-    hb_font_funcs_set_glyph_h_kerning_func (funcs, hb_ft_get_glyph_h_kerning, NULL, NULL);
-    //hb_font_funcs_set_glyph_v_kerning_func (funcs, hb_ft_get_glyph_v_kerning, NULL, NULL);
-    hb_font_funcs_set_glyph_extents_func (funcs, hb_ft_get_glyph_extents, NULL, NULL);
-    hb_font_funcs_set_glyph_contour_point_func (funcs, hb_ft_get_glyph_contour_point, NULL, NULL);
-    hb_font_funcs_set_glyph_name_func (funcs, hb_ft_get_glyph_name, NULL, NULL);
-    hb_font_funcs_set_glyph_from_name_func (funcs, hb_ft_get_glyph_from_name, NULL, NULL);
+    hb_font_funcs_set_font_h_extents_func (funcs, hb_ft_get_font_h_extents, nullptr, nullptr);
+    //hb_font_funcs_set_font_v_extents_func (funcs, hb_ft_get_font_v_extents, nullptr, nullptr);
+    hb_font_funcs_set_nominal_glyph_func (funcs, hb_ft_get_nominal_glyph, nullptr, nullptr);
+    hb_font_funcs_set_variation_glyph_func (funcs, hb_ft_get_variation_glyph, nullptr, nullptr);
+    hb_font_funcs_set_glyph_h_advance_func (funcs, hb_ft_get_glyph_h_advance, nullptr, nullptr);
+    hb_font_funcs_set_glyph_v_advance_func (funcs, hb_ft_get_glyph_v_advance, nullptr, nullptr);
+    //hb_font_funcs_set_glyph_h_origin_func (funcs, hb_ft_get_glyph_h_origin, nullptr, nullptr);
+    hb_font_funcs_set_glyph_v_origin_func (funcs, hb_ft_get_glyph_v_origin, nullptr, nullptr);
+    hb_font_funcs_set_glyph_h_kerning_func (funcs, hb_ft_get_glyph_h_kerning, nullptr, nullptr);
+    //hb_font_funcs_set_glyph_v_kerning_func (funcs, hb_ft_get_glyph_v_kerning, nullptr, nullptr);
+    hb_font_funcs_set_glyph_extents_func (funcs, hb_ft_get_glyph_extents, nullptr, nullptr);
+    hb_font_funcs_set_glyph_contour_point_func (funcs, hb_ft_get_glyph_contour_point, nullptr, nullptr);
+    hb_font_funcs_set_glyph_name_func (funcs, hb_ft_get_glyph_name, nullptr, nullptr);
+    hb_font_funcs_set_glyph_from_name_func (funcs, hb_ft_get_glyph_from_name, nullptr, nullptr);
 
     hb_font_funcs_make_immutable (funcs);
 
-    if (!hb_atomic_ptr_cmpexch (&static_ft_funcs, NULL, funcs)) {
+    if (!hb_atomic_ptr_cmpexch (&static_ft_funcs, nullptr, funcs)) {
       hb_font_funcs_destroy (funcs);
       goto retry;
     }
 
 #ifdef HB_USE_ATEXIT
     atexit (free_static_ft_funcs); /* First person registers atexit() callback. */
 #endif
   };
@@ -485,27 +483,27 @@ reference_table  (hb_face_t *face HB_UNU
 {
   FT_Face ft_face = (FT_Face) user_data;
   FT_Byte *buffer;
   FT_ULong  length = 0;
   FT_Error error;
 
   /* Note: FreeType like HarfBuzz uses the NONE tag for fetching the entire blob */
 
-  error = FT_Load_Sfnt_Table (ft_face, tag, 0, NULL, &length);
+  error = FT_Load_Sfnt_Table (ft_face, tag, 0, nullptr, &length);
   if (error)
-    return NULL;
+    return nullptr;
 
   buffer = (FT_Byte *) malloc (length);
   if (!buffer)
-    return NULL;
+    return nullptr;
 
   error = FT_Load_Sfnt_Table (ft_face, tag, 0, buffer, &length);
   if (error)
-    return NULL;
+    return nullptr;
 
   return hb_blob_create ((const char *) buffer, length,
 			 HB_MEMORY_MODE_WRITABLE,
 			 buffer, free);
 }
 
 /**
  * hb_ft_face_create:
@@ -576,17 +574,17 @@ hb_ft_face_finalize (FT_Face ft_face)
 hb_face_t *
 hb_ft_face_create_cached (FT_Face ft_face)
 {
   if (unlikely (!ft_face->generic.data || ft_face->generic.finalizer != (FT_Generic_Finalizer) hb_ft_face_finalize))
   {
     if (ft_face->generic.finalizer)
       ft_face->generic.finalizer (ft_face);
 
-    ft_face->generic.data = hb_ft_face_create (ft_face, NULL);
+    ft_face->generic.data = hb_ft_face_create (ft_face, nullptr);
     ft_face->generic.finalizer = (FT_Generic_Finalizer) hb_ft_face_finalize;
   }
 
   return hb_face_reference ((hb_face_t *) ft_face->generic.data);
 }
 
 
 /**
@@ -628,17 +626,17 @@ hb_ft_font_changed (hb_font_t *font)
 		     (int) (((uint64_t) ft_face->size->metrics.y_scale * (uint64_t) ft_face->units_per_EM + (1u<<15)) >> 16));
 #if 0 /* hb-ft works in no-hinting model */
   hb_font_set_ppem (font,
 		    ft_face->size->metrics.x_ppem,
 		    ft_face->size->metrics.y_ppem);
 #endif
 
 #ifdef HAVE_FT_GET_VAR_BLEND_COORDINATES
-  FT_MM_Var *mm_var = NULL;
+  FT_MM_Var *mm_var = nullptr;
   if (!FT_Get_MM_Var (ft_face, &mm_var))
   {
     FT_Fixed *ft_coords = (FT_Fixed *) calloc (mm_var->num_axis, sizeof (FT_Fixed));
     int *coords = (int *) calloc (mm_var->num_axis, sizeof (int));
     if (coords && ft_coords)
     {
       if (!FT_Get_Var_Blend_Coordinates (ft_face, mm_var->num_axis, ft_coords))
       {
@@ -689,19 +687,19 @@ get_ft_library (void)
 {
 retry:
   FT_Library library = (FT_Library) hb_atomic_ptr_get (&ft_library);
 
   if (unlikely (!library))
   {
     /* Not found; allocate one. */
     if (FT_Init_FreeType (&library))
-      return NULL;
+      return nullptr;
 
-    if (!hb_atomic_ptr_cmpexch (&ft_library, NULL, library)) {
+    if (!hb_atomic_ptr_cmpexch (&ft_library, nullptr, library)) {
       FT_Done_FreeType (library);
       goto retry;
     }
 
 #ifdef HB_USE_ATEXIT
     atexit (free_ft_library); /* First person registers atexit() callback. */
 #endif
   }
@@ -719,17 +717,17 @@ void
 hb_ft_font_set_funcs (hb_font_t *font)
 {
   hb_blob_t *blob = hb_face_reference_blob (font->face);
   unsigned int blob_length;
   const char *blob_data = hb_blob_get_data (blob, &blob_length);
   if (unlikely (!blob_length))
     DEBUG_MSG (FT, font, "Font face has empty blob");
 
-  FT_Face ft_face = NULL;
+  FT_Face ft_face = nullptr;
   FT_Error err = FT_New_Memory_Face (get_ft_library (),
 				     (const FT_Byte *) blob_data,
 				     blob_length,
 				     hb_face_get_index (font->face),
 				     &ft_face);
 
   if (unlikely (err)) {
     hb_blob_destroy (blob);
@@ -746,17 +744,17 @@ hb_ft_font_set_funcs (hb_font_t *font)
 #if 0
 		    font->x_ppem * 72 * 64 / font->x_scale,
 		    font->y_ppem * 72 * 64 / font->y_scale);
 #endif
   if (font->x_scale < 0 || font->y_scale < 0)
   {
     FT_Matrix matrix = { font->x_scale < 0 ? -1 : +1, 0,
 			  0, font->y_scale < 0 ? -1 : +1};
-    FT_Set_Transform (ft_face, &matrix, NULL);
+    FT_Set_Transform (ft_face, &matrix, nullptr);
   }
 
   unsigned int num_coords;
   const int *coords = hb_font_get_var_coords_normalized (font, &num_coords);
   if (num_coords)
   {
     FT_Fixed *ft_coords = (FT_Fixed *) calloc (num_coords, sizeof (FT_Fixed));
     if (ft_coords)
--- a/gfx/harfbuzz/src/hb-glib.cc
+++ b/gfx/harfbuzz/src/hb-glib.cc
@@ -365,17 +365,17 @@ hb_glib_unicode_decompose_compatibility 
 }
 
 hb_unicode_funcs_t *
 hb_glib_get_unicode_funcs (void)
 {
   static const hb_unicode_funcs_t _hb_glib_unicode_funcs = {
     HB_OBJECT_HEADER_STATIC,
 
-    NULL, /* parent */
+    nullptr, /* parent */
     true, /* immutable */
     {
 #define HB_UNICODE_FUNC_IMPLEMENT(name) hb_glib_unicode_##name,
       HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS
 #undef HB_UNICODE_FUNC_IMPLEMENT
     }
   };
 
--- a/gfx/harfbuzz/src/hb-gobject-structs.cc
+++ b/gfx/harfbuzz/src/hb-gobject-structs.cc
@@ -53,17 +53,17 @@ hb_gobject_##name##_get_type (void) \
 
 #define HB_DEFINE_OBJECT_TYPE(name) \
 	HB_DEFINE_BOXED_TYPE (name, hb_##name##_reference, hb_##name##_destroy);
 
 #define HB_DEFINE_VALUE_TYPE(name) \
 	static hb_##name##_t *_hb_##name##_reference (const hb_##name##_t *l) \
 	{ \
 	  hb_##name##_t *c = (hb_##name##_t *) calloc (1, sizeof (hb_##name##_t)); \
-	  if (unlikely (!c)) return NULL; \
+	  if (unlikely (!c)) return nullptr; \
 	  *c = *l; \
 	  return c; \
 	} \
 	static void _hb_##name##_destroy (hb_##name##_t *l) { free (l); } \
 	HB_DEFINE_BOXED_TYPE (name, _hb_##name##_reference, _hb_##name##_destroy);
 
 HB_DEFINE_OBJECT_TYPE (buffer)
 HB_DEFINE_OBJECT_TYPE (blob)
--- a/gfx/harfbuzz/src/hb-graphite2.cc
+++ b/gfx/harfbuzz/src/hb-graphite2.cc
@@ -54,32 +54,32 @@ struct hb_graphite2_shaper_face_data_t {
   hb_graphite2_tablelist_t *tlist;
 };
 
 static const void *hb_graphite2_get_table (const void *data, unsigned int tag, size_t *len)
 {
   hb_graphite2_shaper_face_data_t *face_data = (hb_graphite2_shaper_face_data_t *) data;
   hb_graphite2_tablelist_t *tlist = face_data->tlist;
 
-  hb_blob_t *blob = NULL;
+  hb_blob_t *blob = nullptr;
 
   for (hb_graphite2_tablelist_t *p = tlist; p; p = p->next)
     if (p->tag == tag) {
       blob = p->blob;
       break;
     }
 
   if (unlikely (!blob))
   {
     blob = face_data->face->reference_table (tag);
 
     hb_graphite2_tablelist_t *p = (hb_graphite2_tablelist_t *) calloc (1, sizeof (hb_graphite2_tablelist_t));
     if (unlikely (!p)) {
       hb_blob_destroy (blob);
-      return NULL;
+      return nullptr;
     }
     p->blob = blob;
     p->tag = tag;
 
     /* TODO Not thread-safe, but fairly harmless.
      * We can do the double-chcked pointer cmpexch thing here. */
     p->next = face_data->tlist;
     face_data->tlist = p;
@@ -95,30 +95,30 @@ hb_graphite2_shaper_face_data_t *
 _hb_graphite2_shaper_face_data_create (hb_face_t *face)
 {
   hb_blob_t *silf_blob = face->reference_table (HB_GRAPHITE2_TAG_SILF);
   /* Umm, we just reference the table to check whether it exists.
    * Maybe add better API for this? */
   if (!hb_blob_get_length (silf_blob))
   {
     hb_blob_destroy (silf_blob);
-    return NULL;
+    return nullptr;
   }
   hb_blob_destroy (silf_blob);
 
   hb_graphite2_shaper_face_data_t *data = (hb_graphite2_shaper_face_data_t *) calloc (1, sizeof (hb_graphite2_shaper_face_data_t));
   if (unlikely (!data))
-    return NULL;
+    return nullptr;
 
   data->face = face;
   data->grface = gr_make_face (data, &hb_graphite2_get_table, gr_face_preloadAll);
 
   if (unlikely (!data->grface)) {
     free (data);
-    return NULL;
+    return nullptr;
   }
 
   return data;
 }
 
 void
 _hb_graphite2_shaper_face_data_destroy (hb_graphite2_shaper_face_data_t *data)
 {
@@ -138,17 +138,17 @@ void
 }
 
 /*
  * Since: 0.9.10
  */
 gr_face *
 hb_graphite2_face_get_gr_face (hb_face_t *face)
 {
-  if (unlikely (!hb_graphite2_shaper_face_data_ensure (face))) return NULL;
+  if (unlikely (!hb_graphite2_shaper_face_data_ensure (face))) return nullptr;
   return HB_SHAPER_DATA_GET (face)->grface;
 }
 
 
 /*
  * shaper font data
  */
 
@@ -166,17 +166,17 @@ void
 }
 
 /*
  * Since: 0.9.10
  */
 gr_font *
 hb_graphite2_font_get_gr_font (hb_font_t *font)
 {
-  return NULL;
+  return nullptr;
 }
 
 
 /*
  * shaper shape_plan data
  */
 
 struct hb_graphite2_shaper_shape_plan_data_t {};
@@ -216,28 +216,28 @@ hb_bool_t
 		     hb_buffer_t        *buffer,
 		     const hb_feature_t *features,
 		     unsigned int        num_features)
 {
   hb_face_t *face = font->face;
   gr_face *grface = HB_SHAPER_DATA_GET (face)->grface;
 
   const char *lang = hb_language_to_string (hb_buffer_get_language (buffer));
-  const char *lang_end = lang ? strchr (lang, '-') : NULL;
+  const char *lang_end = lang ? strchr (lang, '-') : nullptr;
   int lang_len = lang_end ? lang_end - lang : -1;
   gr_feature_val *feats = gr_face_featureval_for_lang (grface, lang ? hb_tag_from_string (lang, lang_len) : 0);
 
   for (unsigned int i = 0; i < num_features; i++)
   {
     const gr_feature_ref *fref = gr_face_find_fref (grface, features[i].tag);
     if (fref)
       gr_fref_set_feature_value (fref, features[i].value, feats);
   }
 
-  gr_segment *seg = NULL;
+  gr_segment *seg = nullptr;
   const gr_slot *is;
   unsigned int ci = 0, ic = 0;
   float curradvx = 0., curradvy = 0.;
 
   unsigned int scratch_size;
   hb_buffer_t::scratch_buffer_t *scratch = buffer->get_scratch_buffer (&scratch_size);
 
   uint32_t *chars = (uint32_t *) scratch;
@@ -245,17 +245,17 @@ hb_bool_t
   for (unsigned int i = 0; i < buffer->len; ++i)
     chars[i] = buffer->info[i].codepoint;
 
   /* TODO ensure_native_direction. */
 
   hb_tag_t script_tag[2];
   hb_ot_tags_from_script (hb_buffer_get_script (buffer), &script_tag[0], &script_tag[1]);
 
-  seg = gr_make_seg (NULL, grface,
+  seg = gr_make_seg (nullptr, grface,
 		     script_tag[1] == HB_TAG_NONE ? script_tag[0] : script_tag[1],
 		     feats,
 		     gr_utf32, chars, buffer->len,
 		     2 | (hb_buffer_get_direction (buffer) == HB_DIRECTION_RTL ? 1 : 0));
 
   if (unlikely (!seg)) {
     if (feats) gr_featureval_destroy (feats);
     return false;
@@ -363,49 +363,49 @@ hb_bool_t
 
   unsigned int upem = hb_face_get_upem (face);
   float xscale = (float) font->x_scale / upem;
   float yscale = (float) font->y_scale / upem;
   yscale *= yscale / xscale;
   /* Positioning. */
   unsigned int currclus = (unsigned int) -1;
   const hb_glyph_info_t *info = buffer->info;
-  hb_glyph_position_t *pPos = hb_buffer_get_glyph_positions (buffer, NULL);
+  hb_glyph_position_t *pPos = hb_buffer_get_glyph_positions (buffer, nullptr);
   if (!HB_DIRECTION_IS_BACKWARD(buffer->props.direction))
   {
     curradvx = 0;
     for (is = gr_seg_first_slot (seg); is; pPos++, ++info, is = gr_slot_next_in_segment (is))
     {
       pPos->x_offset = gr_slot_origin_X (is) * xscale - curradvx;
       pPos->y_offset = gr_slot_origin_Y (is) * yscale - curradvy;
       if (info->cluster != currclus) {
         pPos->x_advance = info->var1.i32 * xscale;
         curradvx += pPos->x_advance;
         currclus = info->cluster;
       } else
         pPos->x_advance = 0.;
 
-      pPos->y_advance = gr_slot_advance_Y (is, grface, NULL) * yscale;
+      pPos->y_advance = gr_slot_advance_Y (is, grface, nullptr) * yscale;
       curradvy += pPos->y_advance;
     }
   }
   else
   {
     curradvx = gr_seg_advance_X(seg) * xscale;
     for (is = gr_seg_first_slot (seg); is; pPos++, info++, is = gr_slot_next_in_segment (is))
     {
       if (info->cluster != currclus)
       {
         pPos->x_advance = info->var1.i32 * xscale;
         curradvx -= pPos->x_advance;
         currclus = info->cluster;
       } else
         pPos->x_advance = 0.;
 
-      pPos->y_advance = gr_slot_advance_Y (is, grface, NULL) * yscale;
+      pPos->y_advance = gr_slot_advance_Y (is, grface, nullptr) * yscale;
       curradvy -= pPos->y_advance;
       pPos->x_offset = (gr_slot_origin_X (is) - info->var1.i32) * xscale - curradvx + pPos->x_advance;
       pPos->y_offset = gr_slot_origin_Y (is) * yscale - curradvy;
     }
     hb_buffer_reverse_clusters (buffer);
   }
 
   if (feats) gr_featureval_destroy (feats);
--- a/gfx/harfbuzz/src/hb-icu.cc
+++ b/gfx/harfbuzz/src/hb-icu.cc
@@ -29,17 +29,17 @@
 
 #include "hb-private.hh"
 
 #include "hb-icu.h"
 
 #include "hb-unicode-private.hh"
 
 #include <unicode/uchar.h>
-#include <unicode/unorm.h>
+#include <unicode/unorm2.h>
 #include <unicode/ustring.h>
 #include <unicode/utf16.h>
 #include <unicode/uversion.h>
 
 
 hb_script_t
 hb_icu_script_to_script (UScriptCode script)
 {
@@ -195,17 +195,17 @@ hb_icu_unicode_compose (hb_unicode_funcs
   len = 0;
   err = false;
   U16_APPEND (utf16, len, ARRAY_LENGTH (utf16), a, err);
   if (err) return false;
   U16_APPEND (utf16, len, ARRAY_LENGTH (utf16), b, err);
   if (err) return false;
 
   icu_err = U_ZERO_ERROR;
-  len = unorm_normalize (utf16, len, UNORM_NFC, 0, normalized, ARRAY_LENGTH (normalized), &icu_err);
+  len = unorm2_normalize (unorm2_getNFCInstance (&icu_err), utf16, len, normalized, ARRAY_LENGTH (normalized), &icu_err);
   if (U_FAILURE (icu_err))
     return false;
   if (u_countChar32 (normalized, len) == 1) {
     U16_GET_UNSAFE (normalized, 0, *ab);
     ret = true;
   } else {
     ret = false;
   }
@@ -256,17 +256,17 @@ hb_icu_unicode_decompose (hb_unicode_fun
   /* Watchout for the dragons.  Err, watchout for macros changing len. */
 
   len = 0;
   err = false;
   U16_APPEND (utf16, len, ARRAY_LENGTH (utf16), ab, err);
   if (err) return false;
 
   icu_err = U_ZERO_ERROR;
-  len = unorm_normalize (utf16, len, UNORM_NFD, 0, normalized, ARRAY_LENGTH (normalized), &icu_err);
+  len = unorm2_normalize (unorm2_getNFDInstance (&icu_err), utf16, len, normalized, ARRAY_LENGTH (normalized), &icu_err);
   if (U_FAILURE (icu_err))
     return false;
 
   len = u_countChar32 (normalized, len);
 
   if (len == 1) {
     U16_GET_UNSAFE (normalized, 0, *a);
     *b = 0;
@@ -276,33 +276,33 @@ hb_icu_unicode_decompose (hb_unicode_fun
     U16_NEXT_UNSAFE (normalized, len, *a);
     U16_NEXT_UNSAFE (normalized, len, *b);
 
     /* Here's the ugly part: if ab decomposes to a single character and
      * that character decomposes again, we have to detect that and undo
      * the second part :-(. */
     UChar recomposed[20];
     icu_err = U_ZERO_ERROR;
-    unorm_normalize (normalized, len, UNORM_NFC, 0, recomposed, ARRAY_LENGTH (recomposed), &icu_err);
+    unorm2_normalize (unorm2_getNFCInstance (&icu_err), normalized, len, recomposed, ARRAY_LENGTH (recomposed), &icu_err);
     if (U_FAILURE (icu_err))
       return false;
     hb_codepoint_t c;
     U16_GET_UNSAFE (recomposed, 0, c);
     if (c != *a && c != ab) {
       *a = c;
       *b = 0;
     }
     ret = true;
   } else {
     /* If decomposed to more than two characters, take the last one,
      * and recompose the rest to get the first component. */
     U16_PREV_UNSAFE (normalized, len, *b); /* Changes len in-place. */
     UChar recomposed[18 * 2];
     icu_err = U_ZERO_ERROR;
-    len = unorm_normalize (normalized, len, UNORM_NFC, 0, recomposed, ARRAY_LENGTH (recomposed), &icu_err);
+    len = unorm2_normalize (unorm2_getNFCInstance (&icu_err), normalized, len, recomposed, ARRAY_LENGTH (recomposed), &icu_err);
     if (U_FAILURE (icu_err))
       return false;
     /* We expect that recomposed has exactly one character now. */
     if (unlikely (u_countChar32 (recomposed, len) != 1))
       return false;
     U16_GET_UNSAFE (recomposed, 0, *a);
     ret = true;
   }
@@ -326,46 +326,46 @@ hb_icu_unicode_decompose_compatibility (
   len = 0;
   err = false;
   U16_APPEND (utf16, len, ARRAY_LENGTH (utf16), u, err);
   if (err)
     return 0;
 
   /* Normalise the codepoint using NFKD mode. */
   icu_err = U_ZERO_ERROR;
-  len = unorm_normalize (utf16, len, UNORM_NFKD, 0, normalized, ARRAY_LENGTH (normalized), &icu_err);
-  if (icu_err)
+  len = unorm2_normalize (unorm2_getNFKDInstance (&icu_err), utf16, len, normalized, ARRAY_LENGTH (normalized), &icu_err);
+  if (U_FAILURE (icu_err))
     return 0;
 
   /* Convert the decomposed form from UTF-16 to UTF-32. */
   icu_err = U_ZERO_ERROR;
   u_strToUTF32 ((UChar32*) decomposed, HB_UNICODE_MAX_DECOMPOSITION_LEN, &utf32_len, normalized, len, &icu_err);
-  if (icu_err)
+  if (U_FAILURE (icu_err))
     return 0;
 
   return utf32_len;
 }
 
 
 hb_unicode_funcs_t *
 hb_icu_get_unicode_funcs (void)
 {
   static const hb_unicode_funcs_t _hb_icu_unicode_funcs = {
     HB_OBJECT_HEADER_STATIC,
 
-    NULL, /* parent */
+    nullptr, /* parent */
     true, /* immutable */
     {
 #define HB_UNICODE_FUNC_IMPLEMENT(name) hb_icu_unicode_##name,
       HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS
 #undef HB_UNICODE_FUNC_IMPLEMENT
     }
   };
 
 #if U_ICU_VERSION_MAJOR_NUM >= 49
   if (!hb_atomic_ptr_get (&normalizer)) {
     UErrorCode icu_err = U_ZERO_ERROR;
     /* We ignore failure in getNFCInstace(). */
-    (void) hb_atomic_ptr_cmpexch (&normalizer, NULL, unorm2_getNFCInstance (&icu_err));
+    (void) hb_atomic_ptr_cmpexch (&normalizer, nullptr, unorm2_getNFCInstance (&icu_err));
   }
 #endif
   return const_cast<hb_unicode_funcs_t *> (&_hb_icu_unicode_funcs);
 }
--- a/gfx/harfbuzz/src/hb-mutex-private.hh
+++ b/gfx/harfbuzz/src/hb-mutex-private.hh
@@ -63,17 +63,17 @@ typedef CRITICAL_SECTION hb_mutex_impl_t
 #define hb_mutex_impl_finish(M)	DeleteCriticalSection (M)
 
 
 #elif !defined(HB_NO_MT) && (defined(HAVE_PTHREAD) || defined(__APPLE__))
 
 #include <pthread.h>
 typedef pthread_mutex_t hb_mutex_impl_t;
 #define HB_MUTEX_IMPL_INIT	PTHREAD_MUTEX_INITIALIZER
-#define hb_mutex_impl_init(M)	pthread_mutex_init (M, NULL)
+#define hb_mutex_impl_init(M)	pthread_mutex_init (M, nullptr)
 #define hb_mutex_impl_lock(M)	pthread_mutex_lock (M)
 #define hb_mutex_impl_unlock(M)	pthread_mutex_unlock (M)
 #define hb_mutex_impl_finish(M)	pthread_mutex_destroy (M)
 
 
 #elif !defined(HB_NO_MT) && defined(HAVE_INTEL_ATOMIC_PRIMITIVES)
 
 #if defined(HAVE_SCHED_H) && defined(HAVE_SCHED_YIELD)
--- a/gfx/harfbuzz/src/hb-object-private.hh
+++ b/gfx/harfbuzz/src/hb-object-private.hh
@@ -188,15 +188,15 @@ static inline bool hb_object_set_user_da
   return obj->header.user_data.set (key, data, destroy, replace);
 }
 
 template <typename Type>
 static inline void *hb_object_get_user_data (Type               *obj,
 					     hb_user_data_key_t *key)
 {
   if (unlikely (!obj || hb_object_is_inert (obj)))
-    return NULL;
+    return nullptr;
   assert (hb_object_is_valid (obj));
   return obj->header.user_data.get (key);
 }
 
 
 #endif /* HB_OBJECT_PRIVATE_HH */
--- a/gfx/harfbuzz/src/hb-open-type-private.hh
+++ b/gfx/harfbuzz/src/hb-open-type-private.hh
@@ -80,17 +80,17 @@ static inline Type& StructAfter(TObject 
 /*
  * Size checking
  */
 
 /* Check _assertion in a method environment */
 #define _DEFINE_INSTANCE_ASSERTION1(_line, _assertion) \
   inline void _instance_assertion_on_line_##_line (void) const \
   { \
-    ASSERT_STATIC (_assertion); \
+    static_assert ((_assertion), ""); \
     ASSERT_INSTANCE_POD (*this); /* Make sure it's POD. */ \
   }
 # define _DEFINE_INSTANCE_ASSERTION0(_line, _assertion) _DEFINE_INSTANCE_ASSERTION1 (_line, _assertion)
 # define DEFINE_INSTANCE_ASSERTION(_assertion) _DEFINE_INSTANCE_ASSERTION0 (__LINE__, _assertion)
 
 /* Check that _code compiles in a method environment */
 #define _DEFINE_COMPILES_ASSERTION1(_line, _code) \
   inline void _compiles_assertion_on_line_##_line (void) const \
@@ -131,28 +131,28 @@ static inline Type& StructAfter(TObject 
 
 /* Global nul-content Null pool.  Enlarge as necessary. */
 /* TODO This really should be a extern HB_INTERNAL and defined somewhere... */
 static const void *_NullPool[(256+8) / sizeof (void *)];
 
 /* Generic nul-content Null objects. */
 template <typename Type>
 static inline const Type& Null (void) {
-  ASSERT_STATIC (sizeof (Type) <= sizeof (_NullPool));
+  static_assert ((sizeof (Type) <= sizeof (_NullPool)), "");
   return *CastP<Type> (_NullPool);
 }
 
 /* Specializaiton for arbitrary-content arbitrary-sized Null objects. */
 #define DEFINE_NULL_DATA(Type, data) \
 static const char _Null##Type[sizeof (Type) + 1] = data; /* +1 is for nul-termination in data */ \
 template <> \
 /*static*/ inline const Type& Null<Type> (void) { \
   return *CastP<Type> (_Null##Type); \
 } /* The following line really exists such that we end in a place needing semicolon */ \
-ASSERT_STATIC (Type::min_size + 1 <= sizeof (_Null##Type))
+static_assert (Type::min_size + 1 <= sizeof (_Null##Type), "Null pool too small.  Enlarge.")
 
 /* Accessor macro. */
 #define Null(Type) Null<Type>()
 
 
 /*
  * Dispatch
  */
@@ -187,19 +187,19 @@ struct hb_dispatch_context_t
 #define HB_SANITIZE_MAX_EDITS 32
 #endif
 
 struct hb_sanitize_context_t :
        hb_dispatch_context_t<hb_sanitize_context_t, bool, HB_DEBUG_SANITIZE>
 {
   inline hb_sanitize_context_t (void) :
 	debug_depth (0),
-	start (NULL), end (NULL),
+	start (nullptr), end (nullptr),
 	writable (false), edit_count (0),
-	blob (NULL) {}
+	blob (nullptr) {}
 
   inline const char *get_name (void) { return "SANITIZE"; }
   template <typename T, typename F>
   inline bool may_dispatch (const T *obj, const F *format)
   { return format->sanitize (this); }
   template <typename T>
   inline return_t dispatch (const T &obj) { return obj.sanitize (this); }
   static return_t default_return_value (void) { return true; }
@@ -209,17 +209,17 @@ struct hb_sanitize_context_t :
   inline void init (hb_blob_t *b)
   {
     this->blob = hb_blob_reference (b);
     this->writable = false;
   }
 
   inline void start_processing (void)
   {
-    this->start = hb_blob_get_data (this->blob, NULL);
+    this->start = hb_blob_get_data (this->blob, nullptr);
     this->end = this->start + hb_blob_get_length (this->blob);
     assert (this->start <= this->end); /* Must not overflow. */
     this->edit_count = 0;
     this->debug_depth = 0;
 
     DEBUG_MSG_LEVEL (SANITIZE, start, 0, +1,
 		     "start [%p..%p] (%lu bytes)",
 		     this->start, this->end,
@@ -228,18 +228,18 @@ struct hb_sanitize_context_t :
 
   inline void end_processing (void)
   {
     DEBUG_MSG_LEVEL (SANITIZE, this->start, 0, -1,
 		     "end [%p..%p] %u edit requests",
 		     this->start, this->end, this->edit_count);
 
     hb_blob_destroy (this->blob);
-    this->blob = NULL;
-    this->start = this->end = NULL;
+    this->blob = nullptr;
+    this->start = this->end = nullptr;
   }
 
   inline bool check_range (const void *base, unsigned int len) const
   {
     const char *p = (const char *) base;
     bool ok = this->start <= p && p <= this->end && (unsigned int) (this->end - p) >= len;
 
     DEBUG_MSG_LEVEL (SANITIZE, p, this->debug_depth+1, 0,
@@ -344,17 +344,17 @@ struct Sanitizer
 	if (c->edit_count) {
 	  DEBUG_MSG_FUNC (SANITIZE, c->start, "requested %d edits in second round; FAILLING", c->edit_count);
 	  sane = false;
 	}
       }
     } else {
       unsigned int edit_count = c->edit_count;
       if (edit_count && !c->writable) {
-        c->start = hb_blob_get_data_writable (blob, NULL);
+        c->start = hb_blob_get_data_writable (blob, nullptr);
 	c->end = c->start + hb_blob_get_length (blob);
 
 	if (c->start) {
 	  c->writable = true;
 	  /* ok, we made it writable by relocating.  try again */
 	  DEBUG_MSG_FUNC (SANITIZE, c->start, "retry");
 	  goto retry;
 	}
@@ -369,17 +369,17 @@ struct Sanitizer
     else {
       hb_blob_destroy (blob);
       return hb_blob_get_empty ();
     }
   }
 
   static const Type* lock_instance (hb_blob_t *blob) {
     hb_blob_make_immutable (blob);
-    const char *base = hb_blob_get_data (blob, NULL);
+    const char *base = hb_blob_get_data (blob, nullptr);
     return unlikely (!base) ? &Null(Type) : CastP<Type> (base);
   }
 };
 
 
 
 /*
  * Serialize
@@ -440,17 +440,17 @@ struct hb_serialize_context_t
     return reinterpret_cast<Type *> (p);
   }
 
   template <typename Type>
   inline Type *allocate_size (unsigned int size)
   {
     if (unlikely (this->ran_out_of_room || this->end - this->head < ptrdiff_t (size))) {
       this->ran_out_of_room = true;
-      return NULL;
+      return nullptr;
     }
     memset (this->head, 0, size);
     char *ret = this->head;
     this->head += size;
     return reinterpret_cast<Type *> (ret);
   }
 
   template <typename Type>
@@ -466,36 +466,36 @@ struct hb_serialize_context_t
     return ret;
   }
 
   template <typename Type>
   inline Type *embed (const Type &obj)
   {
     unsigned int size = obj.get_size ();
     Type *ret = this->allocate_size<Type> (size);
-    if (unlikely (!ret)) return NULL;
+    if (unlikely (!ret)) return nullptr;
     memcpy (ret, obj, size);
     return ret;
   }
 
   template <typename Type>
   inline Type *extend_min (Type &obj)
   {
     unsigned int size = obj.min_size;
     assert (this->start <= (char *) &obj && (char *) &obj <= this->head && (char *) &obj + size >= this->head);
-    if (unlikely (!this->allocate_size<Type> (((char *) &obj) + size - this->head))) return NULL;
+    if (unlikely (!this->allocate_size<Type> (((char *) &obj) + size - this->head))) return nullptr;
     return reinterpret_cast<Type *> (&obj);
   }
 
   template <typename Type>
   inline Type *extend (Type &obj)
   {
     unsigned int size = obj.get_size ();
     assert (this->start < (char *) &obj && (char *) &obj <= this->head && (char *) &obj + size >= this->head);
-    if (unlikely (!this->allocate_size<Type> (((char *) &obj) + size - this->head))) return NULL;
+    if (unlikely (!this->allocate_size<Type> (((char *) &obj) + size - this->head))) return nullptr;
     return reinterpret_cast<Type *> (&obj);
   }
 
   inline void truncate (void *new_head)
   {
     assert (this->start < new_head && new_head <= this->head);
     this->head = (char *) new_head;
   }
@@ -1042,21 +1042,22 @@ struct HeadlessArrayOf
 /* An array with sorted elements.  Supports binary searching. */
 template <typename Type, typename LenType=USHORT>
 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;
     while (min <= max)
     {
       int mid = (min + max) / 2;
-      int c = this->array[mid].cmp (x);
+      int c = array[mid].cmp (x);
       if (c < 0)
         max = mid - 1;
       else if (c > 0)
         min = mid + 1;
       else
         return mid;
     }
     return -1;
@@ -1068,17 +1069,17 @@ struct SortedArrayOf : ArrayOf<Type, Len
 
 /* Logic is shared between hb_lazy_loader_t and hb_lazy_table_loader_t */
 template <typename T>
 struct hb_lazy_loader_t
 {
   inline void init (hb_face_t *face_)
   {
     face = face_;
-    instance = NULL;
+    instance = nullptr;
   }
 
   inline void fini (void)
   {
     if (instance && instance != &OT::Null(T))
     {
       instance->fini();
       free (instance);
@@ -1091,17 +1092,17 @@ struct hb_lazy_loader_t
     T *p = (T *) hb_atomic_ptr_get (&instance);
     if (unlikely (!p))
     {
       p = (T *) calloc (1, sizeof (T));
       if (unlikely (!p))
         p = const_cast<T *> (&OT::Null(T));
       else
 	p->init (face);
-      if (unlikely (!hb_atomic_ptr_cmpexch (const_cast<T **>(&instance), NULL, p)))
+      if (unlikely (!hb_atomic_ptr_cmpexch (const_cast<T **>(&instance), nullptr, p)))
       {
 	if (p != &OT::Null(T))
 	  p->fini ();
 	goto retry;
       }
     }
     return p;
   }
@@ -1118,34 +1119,34 @@ struct hb_lazy_loader_t
 
 /* Logic is shared between hb_lazy_loader_t and hb_lazy_table_loader_t */
 template <typename T>
 struct hb_lazy_table_loader_t
 {
   inline void init (hb_face_t *face_)
   {
     face = face_;
-    instance = NULL;
-    blob = NULL;
+    instance = nullptr;
+    blob = nullptr;
   }
 
   inline void fini (void)
   {
     hb_blob_destroy (blob);
   }
 
   inline const T* get (void) const
   {
   retry:
     T *p = (T *) hb_atomic_ptr_get (&instance);
     if (unlikely (!p))
     {
       hb_blob_t *blob_ = OT::Sanitizer<T>::sanitize (face->reference_table (T::tableTag));
       p = const_cast<T *>(OT::Sanitizer<T>::lock_instance (blob_));
-      if (!hb_atomic_ptr_cmpexch (const_cast<T **>(&instance), NULL, p))
+      if (!hb_atomic_ptr_cmpexch (const_cast<T **>(&instance), nullptr, p))
       {
 	hb_blob_destroy (blob_);
 	goto retry;
       }
       blob = blob_;
     }
     return p;
   }
--- a/gfx/harfbuzz/src/hb-ot-cbdt-table.hh
+++ b/gfx/harfbuzz/src/hb-ot-cbdt-table.hh
@@ -240,17 +240,17 @@ struct IndexSubtableArray
     for (unsigned int i = 0; i < numTables; ++i)
     {
       unsigned int firstGlyphIndex = indexSubtablesZ[i].firstGlyphIndex;
       unsigned int lastGlyphIndex = indexSubtablesZ[i].lastGlyphIndex;
       if (firstGlyphIndex <= glyph && glyph <= lastGlyphIndex) {
         return &indexSubtablesZ[i];
       }
     }
-    return NULL;
+    return nullptr;
   }
 
   protected:
   IndexSubtableRecord indexSubtablesZ[VAR];
 
   public:
   DEFINE_SIZE_ARRAY(0, indexSubtablesZ);
 };
@@ -339,17 +339,17 @@ struct CBLC
       if (startGlyphIndex <= glyph && glyph <= endGlyphIndex)
       {
 	*x_ppem = sizeTables[i].ppemX;
 	*y_ppem = sizeTables[i].ppemY;
 	return sizeTables[i].find_table (glyph, this);
       }
     }
 
-    return NULL;
+    return nullptr;
   }
 
   protected:
   FixedVersion<>		version;
   LArrayOf<BitmapSizeTable>	sizeTables;
 
   public:
   DEFINE_SIZE_ARRAY(8, sizeTables);
--- a/gfx/harfbuzz/src/hb-ot-cmap-table.hh
+++ b/gfx/harfbuzz/src/hb-ot-cmap-table.hh
@@ -503,17 +503,17 @@ struct cmap
     key.platformID.set (platform_id);
     key.encodingID.set (encoding_id);
 
     /* Note: We can use bsearch, but since it has no performance
      * implications, we use lsearch and as such accept fonts with
      * unsorted subtable list. */
     int result = encodingRecord./*bsearch*/lsearch (key);
     if (result == -1 || !encodingRecord[result].subtable)
-      return NULL;
+      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) &&
--- a/gfx/harfbuzz/src/hb-ot-font.cc
+++ b/gfx/harfbuzz/src/hb-ot-font.cc
@@ -33,17 +33,17 @@
 #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-os2-table.hh"
 #include "hb-ot-var-hvar-table.hh"
-//#include "hb-ot-post-table.hh"
+#include "hb-ot-post-table.hh"
 
 
 struct hb_ot_face_metrics_accelerator_t
 {
   unsigned int num_metrics;
   unsigned int num_advances;
   unsigned int default_advance;
   unsigned short ascender;
@@ -230,18 +230,18 @@ struct hb_ot_face_cbdt_accelerator_t
   {
     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 = NULL;
-      cbdt = NULL;
+      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)
@@ -296,16 +296,50 @@ struct hb_ot_face_cbdt_accelerator_t
     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;
+  unsigned int post_len;
+  const OT::post *post;
+
+  inline void init (hb_face_t *face)
+  {
+    this->post_blob = OT::Sanitizer<OT::post>::sanitize (face->reference_table (HB_OT_TAG_post));
+    this->post = OT::Sanitizer<OT::post>::lock_instance (this->post_blob);
+    this->post_len = hb_blob_get_length (this->post_blob);
+  }
+
+  inline void fini (void)
+  {
+    hb_blob_destroy (this->post_blob);
+  }
+
+  inline bool get_glyph_name (hb_codepoint_t glyph,
+			      char *name, unsigned int size) const
+  {
+    return this->post->get_glyph_name (glyph, name, size, this->post_len);
+  }
+
+  inline bool get_glyph_from_name (const char *name, int len,
+				   hb_codepoint_t *glyph) const
+  {
+    if (unlikely (!len))
+      return false;
+
+    return this->post->get_glyph_from_name (name, len, glyph, this->post_len);
+  }
+};
+
 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)
@@ -344,18 +378,18 @@ struct hb_ot_face_cmap_accelerator_t
 
   const OT::CmapSubtableFormat14 *uvs_table;
   hb_blob_t *blob;
 
   inline void init (hb_face_t *face)
   {
     this->blob = OT::Sanitizer<OT::cmap>::sanitize (face->reference_table (HB_OT_TAG_cmap));
     const OT::cmap *cmap = OT::Sanitizer<OT::cmap>::lock_instance (this->blob);
-    const OT::CmapSubtable *subtable = NULL;
-    const OT::CmapSubtableFormat14 *subtable_uvs = NULL;
+    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);
@@ -431,47 +465,50 @@ struct hb_ot_face_cmap_accelerator_t
 
 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;
 };
 
 
 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 NULL;
+    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->glyf.init (face);
   ot_font->cbdt.init (face);
+  ot_font->post.init (face);
 
   return ot_font;
 }
 
 static void
 _hb_ot_font_destroy (void *data)
 {
   hb_ot_font_t *ot_font = (hb_ot_font_t *) data;
 
   ot_font->cmap.fini ();
   ot_font->h_metrics.fini ();
   ot_font->v_metrics.fini ();
   ot_font->glyf.fini ();
   ot_font->cbdt.fini ();
+  ot_font->post.fini ();
 
   free (ot_font);
 }
 
 
 static hb_bool_t
 hb_ot_get_nominal_glyph (hb_font_t *font HB_UNUSED,
 			 void *font_data,
@@ -531,16 +568,38 @@ hb_ot_get_glyph_extents (hb_font_t *font
   extents->x_bearing = font->em_scale_x (extents->x_bearing);
   extents->y_bearing = font->em_scale_y (extents->y_bearing);
   extents->width     = font->em_scale_x (extents->width);
   extents->height    = font->em_scale_y (extents->height);
   return ret;
 }
 
 static hb_bool_t
+hb_ot_get_glyph_name (hb_font_t *font HB_UNUSED,
+                      void *font_data,
+                      hb_codepoint_t glyph,
+                      char *name, unsigned int size,
+                      void *user_data HB_UNUSED)
+{
+  const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
+  return ot_font->post->get_glyph_name (glyph, name, size);
+}
+
+static hb_bool_t
+hb_ot_get_glyph_from_name (hb_font_t *font HB_UNUSED,
+                           void *font_data,
+                           const char *name, int len,
+                           hb_codepoint_t *glyph,
+                           void *user_data HB_UNUSED)
+{
+  const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
+  return ot_font->post->get_glyph_from_name (name, len, glyph);
+}
+
+static hb_bool_t
 hb_ot_get_font_h_extents (hb_font_t *font HB_UNUSED,
 			  void *font_data,
 			  hb_font_extents_t *metrics,
 			  void *user_data HB_UNUSED)
 {
   const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
   metrics->ascender = font->em_scale_y (ot_font->h_metrics.ascender);
   metrics->descender = font->em_scale_y (ot_font->h_metrics.descender);
@@ -558,17 +617,17 @@ hb_ot_get_font_v_extents (hb_font_t *fon
   const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
   metrics->ascender = font->em_scale_x (ot_font->v_metrics.ascender);
   metrics->descender = font->em_scale_x (ot_font->v_metrics.descender);
   metrics->line_gap = font->em_scale_x (ot_font->v_metrics.line_gap);
   // TODO Hook up variations.
   return ot_font->v_metrics.has_font_extents;
 }
 
-static hb_font_funcs_t *static_ot_funcs = NULL;
+static hb_font_funcs_t *static_ot_funcs = nullptr;
 
 #ifdef HB_USE_ATEXIT
 static
 void free_static_ot_funcs (void)
 {
   hb_font_funcs_destroy (static_ot_funcs);
 }
 #endif
@@ -578,34 +637,34 @@ static hb_font_funcs_t *
 {
 retry:
   hb_font_funcs_t *funcs = (hb_font_funcs_t *) hb_atomic_ptr_get (&static_ot_funcs);
 
   if (unlikely (!funcs))
   {
     funcs = hb_font_funcs_create ();
 
-    hb_font_funcs_set_font_h_extents_func (funcs, hb_ot_get_font_h_extents, NULL, NULL);
-    hb_font_funcs_set_font_v_extents_func (funcs, hb_ot_get_font_v_extents, NULL, NULL);
-    hb_font_funcs_set_nominal_glyph_func (funcs, hb_ot_get_nominal_glyph, NULL, NULL);
-    hb_font_funcs_set_variation_glyph_func (funcs, hb_ot_get_variation_glyph, NULL, NULL);
-    hb_font_funcs_set_glyph_h_advance_func (funcs, hb_ot_get_glyph_h_advance, NULL, NULL);
-    hb_font_funcs_set_glyph_v_advance_func (funcs, hb_ot_get_glyph_v_advance, NULL, NULL);
-    //hb_font_funcs_set_glyph_h_origin_func (funcs, hb_ot_get_glyph_h_origin, NULL, NULL);
-    //hb_font_funcs_set_glyph_v_origin_func (funcs, hb_ot_get_glyph_v_origin, NULL, NULL);
-    //hb_font_funcs_set_glyph_h_kerning_func (funcs, hb_ot_get_glyph_h_kerning, NULL, NULL); TODO
-    //hb_font_funcs_set_glyph_v_kerning_func (funcs, hb_ot_get_glyph_v_kerning, NULL, NULL);
-    hb_font_funcs_set_glyph_extents_func (funcs, hb_ot_get_glyph_extents, NULL, NULL);
-    //hb_font_funcs_set_glyph_contour_point_func (funcs, hb_ot_get_glyph_contour_point, NULL, NULL); TODO
-    //hb_font_funcs_set_glyph_name_func (funcs, hb_ot_get_glyph_name, NULL, NULL); TODO
-    //hb_font_funcs_set_glyph_from_name_func (funcs, hb_ot_get_glyph_from_name, NULL, NULL); TODO
+    hb_font_funcs_set_font_h_extents_func (funcs, hb_ot_get_font_h_extents, nullptr, nullptr);
+    hb_font_funcs_set_font_v_extents_func (funcs, hb_ot_get_font_v_extents, nullptr, nullptr);
+    hb_font_funcs_set_nominal_glyph_func (funcs, hb_ot_get_nominal_glyph, nullptr, nullptr);
+    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); TODO
+    //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_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, NULL, funcs)) {
+    if (!hb_atomic_ptr_cmpexch (&static_ot_funcs, nullptr, funcs)) {
       hb_font_funcs_destroy (funcs);
       goto retry;
     }
 
 #ifdef HB_USE_ATEXIT
     atexit (free_static_ot_funcs); /* First person registers atexit() callback. */
 #endif
   };
--- a/gfx/harfbuzz/src/hb-ot-layout-common-private.hh
+++ b/gfx/harfbuzz/src/hb-ot-layout-common-private.hh
@@ -209,17 +209,17 @@ struct LangSys
   inline unsigned int get_required_feature_index (void) const
   {
     if (reqFeatureIndex == 0xFFFFu)
       return Index::NOT_FOUND_INDEX;
    return reqFeatureIndex;;
   }
 
   inline bool sanitize (hb_sanitize_context_t *c,
-			const Record<LangSys>::sanitize_closure_t * = NULL) const
+			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
 				 * reordering table) */
   USHORT	reqFeatureIndex;/* Index of a feature required for this
@@ -249,17 +249,17 @@ struct Script
   }
   inline bool find_lang_sys_index (hb_tag_t tag, unsigned int *index) const
   { return langSys.find_index (tag, index); }
 
   inline bool has_default_lang_sys (void) const { return defaultLangSys != 0; }
   inline const LangSys& get_default_lang_sys (void) const { return this+defaultLangSys; }
 
   inline bool sanitize (hb_sanitize_context_t *c,
-			const Record<Script>::sanitize_closure_t * = NULL) const
+			const Record<Script>::sanitize_closure_t * = nullptr) const
   {
     TRACE_SANITIZE (this);
     return_trace (defaultLangSys.sanitize (c, this) && langSys.sanitize (c, this));
   }
 
   protected:
   OffsetTo<LangSys>
 		defaultLangSys;	/* Offset to DefaultLangSys table--from
@@ -430,27 +430,27 @@ struct FeatureParamsCharacterVariants
 		  characters.sanitize (c));
   }
 
   USHORT	format;			/* Format number is set to 0. */
   USHORT	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 NULL.) */
+					 * feature. (May be nullptr.) */
   USHORT	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
-					 * NULL.) */
+					 * nullptr.) */
   USHORT	sampleTextNameID;	/* The ‘name’ table name ID that
 					 * specifies sample text that
 					 * illustrates the effect of this
-					 * feature. (May be NULL.) */
+					 * feature. (May be nullptr.) */
   USHORT	numNamedParameters;	/* Number of named parameters. (May
 					 * be zero.) */
   USHORT	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>
@@ -502,17 +502,17 @@ struct Feature
 					  unsigned int *lookup_count /* IN/OUT */,
 					  unsigned int *lookup_tags /* OUT */) const
   { return lookupIndex.get_indexes (start_index, lookup_count, lookup_tags); }
 
   inline const FeatureParams &get_feature_params (void) const
   { return this+featureParams; }
 
   inline bool sanitize (hb_sanitize_context_t *c,
-			const Record<Feature>::sanitize_closure_t *closure = NULL) const
+			const Record<Feature>::sanitize_closure_t *closure = nullptr) const
   {
     TRACE_SANITIZE (this);
     if (unlikely (!(c->check_struct (this) && lookupIndex.sanitize (c))))
       return_trace (false);
 
     /* Some earlier versions of Adobe tools calculated the offset of the
      * FeatureParams subtable from the beginning of the FeatureList table!
      *
@@ -685,17 +685,17 @@ typedef OffsetListOf<Lookup> LookupList;
 struct CoverageFormat1
 {
   friend struct Coverage;
 
   private:
   inline unsigned int get_coverage (hb_codepoint_t glyph_id) const
   {
     int i = glyphArray.bsearch (glyph_id);
-    ASSERT_STATIC (((unsigned int) -1) == NOT_COVERED);
+    static_assert ((((unsigned int) -1) == NOT_COVERED), "");
     return i;
   }
 
   inline bool serialize (hb_serialize_context_t *c,
 			 Supplier<GlyphID> &glyphs,
 			 unsigned int num_glyphs)
   {
     TRACE_SERIALIZE (this);
@@ -1453,17 +1453,17 @@ struct FeatureTableSubstitution
   {
     unsigned int count = substitutions.len;
     for (unsigned int i = 0; i < count; i++)
     {
       const FeatureTableSubstitutionRecord &record = substitutions.array[i];
       if (record.featureIndex == feature_index)
 	return &(this+record.feature);
     }
-    return NULL;
+    return nullptr;
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (version.sanitize (c) &&
 		  likely (version.major == 1) &&
 		  substitutions.sanitize (c, this));
--- a/gfx/harfbuzz/src/hb-ot-layout-gdef-table.hh
+++ b/gfx/harfbuzz/src/hb-ot-layout-gdef-table.hh
@@ -399,19 +399,19 @@ struct GDEF
 
   /* glyph_props is a 16-bit integer where the lower 8-bit have bits representing
    * glyph class and other bits, and high 8-bit gthe mark attachment type (if any).
    * Not to be confused with lookup_props which is very similar. */
   inline unsigned int get_glyph_props (hb_codepoint_t glyph) const
   {
     unsigned int klass = get_glyph_class (glyph);
 
-    ASSERT_STATIC ((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH == (unsigned int) LookupFlag::IgnoreBaseGlyphs);
-    ASSERT_STATIC ((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE == (unsigned int) LookupFlag::IgnoreLigatures);
-    ASSERT_STATIC ((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_MARK == (unsigned int) LookupFlag::IgnoreMarks);
+    static_assert (((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH == (unsigned int) LookupFlag::IgnoreBaseGlyphs), "");
+    static_assert (((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE == (unsigned int) LookupFlag::IgnoreLigatures), "");
+    static_assert (((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_MARK == (unsigned int) LookupFlag::IgnoreMarks), "");
 
     switch (klass) {
     default:			return 0;
     case BaseGlyph:		return HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH;
     case LigatureGlyph:		return HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE;
     case MarkGlyph:
 	  klass = get_mark_attachment_type (glyph);
 	  return HB_OT_LAYOUT_GLYPH_PROPS_MARK | (klass << 8);
--- a/gfx/harfbuzz/src/hb-ot-layout-gsub-table.hh
+++ b/gfx/harfbuzz/src/hb-ot-layout-gsub-table.hh
@@ -653,17 +653,17 @@ struct Ligature
     unsigned int total_component_count = 0;
 
     unsigned int match_length = 0;
     unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
 
     if (likely (!match_input (c, count,
 			      &component[1],
 			      match_glyph,
-			      NULL,
+			      nullptr,
 			      &match_length,
 			      match_positions,
 			      &is_mark_ligature,
 			      &total_component_count)))
       return_trace (false);
 
     ligate_input (c,
 		  count,
--- a/gfx/harfbuzz/src/hb-ot-layout-gsubgpos-private.hh
+++ b/gfx/harfbuzz/src/hb-ot-layout-gsubgpos-private.hh
@@ -72,17 +72,17 @@ struct hb_closure_context_t :
   unsigned int nesting_level_left;
   unsigned int debug_depth;
 
   hb_closure_context_t (hb_face_t *face_,
 			hb_set_t *glyphs_,
 		        unsigned int nesting_level_left_ = HB_MAX_NESTING_LEVEL) :
 			  face (face_),
 			  glyphs (glyphs_),
-			  recurse_func (NULL),
+			  recurse_func (nullptr),
 			  nesting_level_left (nesting_level_left_),
 			  debug_depth (0) {}
 
   void set_recurse_func (recurse_func_t func) { recurse_func = func; }
 };
 
 
 
@@ -141,82 +141,82 @@ struct hb_collect_glyphs_context_t :
   inline return_t dispatch (const T &obj) { obj.collect_glyphs (this); return HB_VOID; }
   static return_t default_return_value (void) { return HB_VOID; }
   bool stop_sublookup_iteration (return_t r HB_UNUSED) const { return false; }
   return_t recurse (unsigned int lookup_index)
   {
     if (unlikely (nesting_level_left == 0 || !recurse_func))
       return default_return_value ();
 
-    /* Note that GPOS sets recurse_func to NULL already, so it doesn't get
+    /* Note that GPOS sets recurse_func to nullptr already, so it doesn't get
      * past the previous check.  For GSUB, we only want to collect the output
      * glyphs in the recursion.  If output is not requested, we can go home now.
      *
      * Note further, that the above is not exactly correct.  A recursed lookup
      * is allowed to match input that is not matched in the context, but that's
      * not how most fonts are built.  It's possible to relax that and recurse
      * with all sets here if it proves to be an issue.
      */
 
     if (output == hb_set_get_empty ())
       return HB_VOID;
 
     /* Return if new lookup was recursed to before. */
-    if (recursed_lookups.has (lookup_index))
+    if (recursed_lookups->has (lookup_index))
       return HB_VOID;
 
     hb_set_t *old_before = before;
     hb_set_t *old_input  = input;
     hb_set_t *old_after  = after;
     before = input = after = hb_set_get_empty ();
 
     nesting_level_left--;
     recurse_func (this, lookup_index);
     nesting_level_left++;
 
     before = old_before;
     input  = old_input;
     after  = old_after;
 
-    recursed_lookups.add (lookup_index);
+    recursed_lookups->add (lookup_index);
 
     return HB_VOID;
   }
 
   hb_face_t *face;
   hb_set_t *before;
   hb_set_t *input;
   hb_set_t *after;
   hb_set_t *output;
   recurse_func_t recurse_func;
-  hb_set_t recursed_lookups;
+  hb_set_t *recursed_lookups;
   unsigned int nesting_level_left;
   unsigned int debug_depth;
 
   hb_collect_glyphs_context_t (hb_face_t *face_,
-			       hb_set_t  *glyphs_before, /* OUT. May be NULL */
-			       hb_set_t  *glyphs_input,  /* OUT. May be NULL */
-			       hb_set_t  *glyphs_after,  /* OUT. May be NULL */
-			       hb_set_t  *glyphs_output, /* OUT. May be NULL */
+			       hb_set_t  *glyphs_before, /* OUT. May be nullptr */
+			       hb_set_t  *glyphs_input,  /* OUT. May be nullptr */
+			       hb_set_t  *glyphs_after,  /* OUT. May be nullptr */
+			       hb_set_t  *glyphs_output, /* OUT. May be nullptr */
 			       unsigned int nesting_level_left_ = HB_MAX_NESTING_LEVEL) :
 			      face (face_),
 			      before (glyphs_before ? glyphs_before : hb_set_get_empty ()),
 			      input  (glyphs_input  ? glyphs_input  : hb_set_get_empty ()),
 			      after  (glyphs_after  ? glyphs_after  : hb_set_get_empty ()),
 			      output (glyphs_output ? glyphs_output : hb_set_get_empty ()),
-			      recurse_func (NULL),
-			      recursed_lookups (),
+			      recurse_func (nullptr),
+			      recursed_lookups (nullptr),
 			      nesting_level_left (nesting_level_left_),
 			      debug_depth (0)
   {
-    recursed_lookups.init ();
+    recursed_lookups = hb_set_create ();
   }
   ~hb_collect_glyphs_context_t (void)
   {
-    recursed_lookups.fini ();
+    hb_set_destroy (recursed_lookups);
   }
 
   void set_recurse_func (recurse_func_t func) { recurse_func = func; }
 };
 
 
 
 #ifndef HB_DEBUG_GET_COVERAGE
@@ -268,18 +268,18 @@ struct hb_apply_context_t :
     inline matcher_t (void) :
 	     lookup_props (0),
 	     ignore_zwnj (false),
 	     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 (NULL),
-	     match_data (NULL) {};
+	     match_func (nullptr),
+	     match_data (nullptr) {};
 
     typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const USHORT &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_; }
@@ -337,18 +337,18 @@ struct hb_apply_context_t :
     const void *match_data;
   };
 
   struct skipping_iterator_t
   {
     inline void init (hb_apply_context_t *c_, bool context_match = false)
     {
       c = c_;
-      match_glyph_data = NULL;
-      matcher.set_match_func (NULL, NULL);
+      match_glyph_data = nullptr;
+      matcher.set_match_func (nullptr, nullptr);
       matcher.set_lookup_props (c->lookup_props);
       /* Ignore ZWNJ if we are matching GSUB context, or matching GPOS. */
       matcher.set_ignore_zwnj (c->table_index == 1 || (context_match && c->auto_zwnj));
       /* Ignore ZWJ if we are matching GSUB context, or matching GPOS, or if asked to. */
       matcher.set_ignore_zwj  (c->table_index == 1 || (context_match || c->auto_zwj));
       matcher.set_mask (context_match ? -1 : c->lookup_mask);
     }
     inline void set_lookup_props (unsigned int lookup_props)
@@ -486,17 +486,17 @@ struct hb_apply_context_t :
   bool has_glyph_classes;
 
 
   hb_apply_context_t (unsigned int table_index_,
 		      hb_font_t *font_,
 		      hb_buffer_t *buffer_) :
 			iter_input (), iter_context (),
 			font (font_), face (font->face), buffer (buffer_),
-			recurse_func (NULL),
+			recurse_func (nullptr),
 			gdef (*hb_ot_layout_from_face (face)->gdef),
 			var_store (gdef.get_var_store ()),
 			direction (buffer_->props.direction),
 			lookup_mask (1),
 			table_index (table_index_),
 			lookup_index ((unsigned int) -1),
 			lookup_props (0),
 			nesting_level_left (HB_MAX_NESTING_LEVEL),
@@ -714,20 +714,20 @@ static inline bool would_match_input (hb
 }
 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 */
 				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 = NULL,
-				unsigned int *p_total_component_count = NULL)
+				bool *p_is_mark_ligature = nullptr,
+				unsigned int *p_total_component_count = nullptr)
 {
-  TRACE_APPLY (NULL);
+  TRACE_APPLY (nullptr);
 
   if (unlikely (count > HB_MAX_CONTEXT_LENGTH)) return_trace (false);
 
   hb_buffer_t *buffer = c->buffer;
 
   hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
   skippy_iter.reset (buffer->idx, count - 1);
   skippy_iter.set_match_func (match_func, match_data, input);
@@ -841,17 +841,17 @@ static inline bool match_input (hb_apply
 static inline bool ligate_input (hb_apply_context_t *c,
 				 unsigned int count, /* Including the first glyph */
 				 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], /* Including the first glyph */
 				 unsigned int match_length,
 				 hb_codepoint_t lig_glyph,
 				 bool is_mark_ligature,
 				 unsigned int total_component_count)
 {
-  TRACE_APPLY (NULL);
+  TRACE_APPLY (nullptr);
 
   hb_buffer_t *buffer = c->buffer;
 
   buffer->merge_clusters (buffer->idx, buffer->idx + match_length);
 
   /*
    * - If it *is* a mark ligature, we don't allocate a new ligature id, and leave
    *   the ligature to keep its old ligature id.  This will allow it to attach to
@@ -938,17 +938,17 @@ static inline bool ligate_input (hb_appl
 
 static inline bool match_backtrack (hb_apply_context_t *c,
 				    unsigned int count,
 				    const USHORT backtrack[],
 				    match_func_t match_func,
 				    const void *match_data,
 				    unsigned int *match_start)
 {
-  TRACE_APPLY (NULL);
+  TRACE_APPLY (nullptr);
 
   hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context;
   skippy_iter.reset (c->buffer->backtrack_len (), count);
   skippy_iter.set_match_func (match_func, match_data, backtrack);
 
   for (unsigned int i = 0; i < count; i++)
     if (!skippy_iter.prev ())
       return_trace (false);
@@ -961,17 +961,17 @@ static inline bool match_backtrack (hb_a
 static inline bool match_lookahead (hb_apply_context_t *c,
 				    unsigned int count,
 				    const USHORT lookahead[],
 				    match_func_t match_func,
 				    const void *match_data,
 				    unsigned int offset,
 				    unsigned int *end_index)
 {
-  TRACE_APPLY (NULL);
+  TRACE_APPLY (nullptr);
 
   hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context;
   skippy_iter.reset (c->buffer->idx + offset - 1, count);
   skippy_iter.set_match_func (match_func, match_data, lookahead);
 
   for (unsigned int i = 0; i < count; i++)
     if (!skippy_iter.next ())
       return_trace (false);
@@ -1011,17 +1011,17 @@ static inline void recurse_lookups (cont
 
 static inline bool apply_lookup (hb_apply_context_t *c,
 				 unsigned int count, /* Including the first glyph */
 				 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], /* Including the first glyph */
 				 unsigned int lookupCount,
 				 const LookupRecord lookupRecord[], /* Array of LookupRecords--in design order */
 				 unsigned int match_length)
 {
-  TRACE_APPLY (NULL);
+  TRACE_APPLY (nullptr);
 
   hb_buffer_t *buffer = c->buffer;
   int end;
 
   /* All positions are distance from beginning of *output* buffer.
    * Adjust. */
   {
     unsigned int bl = buffer->backtrack_len ();
@@ -1329,17 +1329,17 @@ struct ContextFormat1
   inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE (this);
 
     const Coverage &cov = (this+coverage);
 
     struct ContextClosureLookupContext lookup_context = {
       {intersects_glyph},
-      NULL
+      nullptr
     };
 
     unsigned int count = ruleSet.len;
     for (unsigned int i = 0; i < count; i++)
       if (cov.intersects_coverage (c->glyphs, i)) {
 	const RuleSet &rule_set = this+ruleSet[i];
 	rule_set.closure (c, lookup_context);
       }
@@ -1347,32 +1347,32 @@ struct ContextFormat1
 
   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
     TRACE_COLLECT_GLYPHS (this);
     (this+coverage).add_coverage (c->input);
 
     struct ContextCollectGlyphsLookupContext lookup_context = {
       {collect_glyph},
-      NULL
+      nullptr
     };
 
     unsigned int count = ruleSet.len;
     for (unsigned int i = 0; i < count; i++)
       (this+ruleSet[i]).collect_glyphs (c, lookup_context);
   }
 
   inline bool would_apply (hb_would_apply_context_t *c) const
   {
     TRACE_WOULD_APPLY (this);
 
     const RuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])];
     struct ContextApplyLookupContext lookup_context = {
       {match_glyph},
-      NULL
+      nullptr
     };
     return_trace (rule_set.would_apply (c, lookup_context));
   }
 
   inline const Coverage &get_coverage (void) const
   {
     return this+coverage;
   }
@@ -1382,17 +1382,17 @@ struct ContextFormat1
     TRACE_APPLY (this);
     unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
     if (likely (index == NOT_COVERED))
       return_trace (false);
 
     const RuleSet &rule_set = this+ruleSet[index];
     struct ContextApplyLookupContext lookup_context = {
       {match_glyph},
-      NULL
+      nullptr
     };
     return_trace (rule_set.apply (c, lookup_context));
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
@@ -1887,17 +1887,17 @@ struct ChainContextFormat1
 {
   inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE (this);
     const Coverage &cov = (this+coverage);
 
     struct ChainContextClosureLookupContext lookup_context = {
       {intersects_glyph},
-      {NULL, NULL, NULL}
+      {nullptr, nullptr, nullptr}
     };
 
     unsigned int count = ruleSet.len;
     for (unsigned int i = 0; i < count; i++)
       if (cov.intersects_coverage (c->glyphs, i)) {
 	const ChainRuleSet &rule_set = this+ruleSet[i];
 	rule_set.closure (c, lookup_context);
       }
@@ -1905,32 +1905,32 @@ struct ChainContextFormat1
 
   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
     TRACE_COLLECT_GLYPHS (this);
     (this+coverage).add_coverage (c->input);
 
     struct ChainContextCollectGlyphsLookupContext lookup_context = {
       {collect_glyph},
-      {NULL, NULL, NULL}
+      {nullptr, nullptr, nullptr}
     };
 
     unsigned int count = ruleSet.len;
     for (unsigned int i = 0; i < count; i++)
       (this+ruleSet[i]).collect_glyphs (c, lookup_context);
   }
 
   inline bool would_apply (hb_would_apply_context_t *c) const
   {
     TRACE_WOULD_APPLY (this);
 
     const ChainRuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])];
     struct ChainContextApplyLookupContext lookup_context = {
       {match_glyph},
-      {NULL, NULL, NULL}
+      {nullptr, nullptr, nullptr}
     };
     return_trace (rule_set.would_apply (c, lookup_context));
   }
 
   inline const Coverage &get_coverage (void) const
   {
     return this+coverage;
   }
@@ -1939,17 +1939,17 @@ struct ChainContextFormat1
   {
     TRACE_APPLY (this);
     unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
     if (likely (index == NOT_COVERED)) return_trace (false);
 
     const ChainRuleSet &rule_set = this+ruleSet[index];
     struct ChainContextApplyLookupContext lookup_context = {
       {match_glyph},
-      {NULL, NULL, NULL}
+      {nullptr, nullptr, nullptr}
     };
     return_trace (rule_set.apply (c, lookup_context));
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
--- a/gfx/harfbuzz/src/hb-ot-layout-jstf-table.hh
+++ b/gfx/harfbuzz/src/hb-ot-layout-jstf-table.hh
@@ -119,17 +119,17 @@ struct JstfPriority
 
 /*
  * JstfLangSys -- Justification Language System Table
  */
 
 struct JstfLangSys : OffsetListOf<JstfPriority>
 {
   inline bool sanitize (hb_sanitize_context_t *c,
-			const Record<JstfLangSys>::sanitize_closure_t * = NULL) const
+			const Record<JstfLangSys>::sanitize_closure_t * = nullptr) const
   {
     TRACE_SANITIZE (this);
     return_trace (OffsetListOf<JstfPriority>::sanitize (c));
   }
 };
 
 
 /*
@@ -160,17 +160,17 @@ struct JstfScript
   }
   inline bool find_lang_sys_index (hb_tag_t tag, unsigned int *index) const
   { return langSys.find_index (tag, index); }
 
   inline bool has_default_lang_sys (void) const { return defaultLangSys != 0; }
   inline const JstfLangSys& get_default_lang_sys (void) const { return this+defaultLangSys; }
 
   inline bool sanitize (hb_sanitize_context_t *c,
-			const Record<JstfScript>::sanitize_closure_t * = NULL) const
+			const Record<JstfScript>::sanitize_closure_t * = nullptr) const
   {
     TRACE_SANITIZE (this);
     return_trace (extenderGlyphs.sanitize (c, this) &&
 		  defaultLangSys.sanitize (c, this) &&
 		  langSys.sanitize (c, this));
   }
 
   protected:
--- a/gfx/harfbuzz/src/hb-ot-layout-private.hh
+++ b/gfx/harfbuzz/src/hb-ot-layout-private.hh
@@ -28,17 +28,17 @@
 
 #ifndef HB_OT_LAYOUT_PRIVATE_HH
 #define HB_OT_LAYOUT_PRIVATE_HH
 
 #include "hb-private.hh"
 
 #include "hb-font-private.hh"
 #include "hb-buffer-private.hh"
-#include "hb-set-private.hh"
+#include "hb-set-digest-private.hh"
 #include "hb-open-type-private.hh"
 
 
 /* Private API corresponding to hb-ot-layout.h: */
 
 HB_INTERNAL hb_bool_t
 hb_ot_layout_table_find_feature (hb_face_t    *face,
 				 hb_tag_t      table_tag,
@@ -221,17 +221,19 @@ static inline unsigned int
 
 /* unicode_props */
 
 /* Design:
  * unicode_props() is a two-byte number.  The low byte includes:
  * - General_Category: 5 bits.
  * - A bit each for:
  *   * Is it Default_Ignorable(); we have a modified Default_Ignorable().
- *   * Whether it's one of the three Mongolian Free Variation Selectors.
+ *   * Whether it's one of the three Mongolian Free Variation Selectors,
+ *     CGJ, or other characters that are hidden but should not be ignored
+ *     like most other Default_Ignorable()s do during matching.
  *   * One free bit right now.
  *
  * The high-byte has different meanings, switched by the Gen-Cat:
  * - For Mn,Mc,Me: the modified Combining_Class.
  * - For Cf: whether it's ZWJ, ZWNJ, or something else.
  * - For Ws: index of which space character this is, if space fallback
  *   is needed, ie. we don't set this by default, only if asked to.
  */
@@ -259,30 +261,31 @@ static inline void
   if (u >= 0x80)
   {
     buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII;
     if (unlikely (unicode->is_default_ignorable (u)))
     {
       buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_DEFAULT_IGNORABLES;
       props |=  UPROPS_MASK_IGNORABLE;
       if (u == 0x200Cu) props |= UPROPS_MASK_Cf_ZWNJ;
-      if (u == 0x200Du) props |= UPROPS_MASK_Cf_ZWJ;
+      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
-       */
-      if (unlikely (hb_in_range (u, 0x180Bu, 0x180Du))) props |= UPROPS_MASK_HIDDEN;
+       * https://github.com/behdad/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
-       */
-      if (unlikely (hb_in_range (u, 0xE0020u, 0xE007Fu))) props |= UPROPS_MASK_HIDDEN;
+       * https://github.com/behdad/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 */
+      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:
        * http://www.unicode.org/policies/stability_policy.html#Property_Value
--- a/gfx/harfbuzz/src/hb-ot-layout.cc
+++ b/gfx/harfbuzz/src/hb-ot-layout.cc
@@ -39,17 +39,17 @@
 #include "hb-ot-map-private.hh"
 
 
 hb_ot_layout_t *
 _hb_ot_layout_create (hb_face_t *face)
 {
   hb_ot_layout_t *layout = (hb_ot_layout_t *) calloc (1, sizeof (hb_ot_layout_t));
   if (unlikely (!layout))
-    return NULL;
+    return nullptr;
 
   layout->gdef_blob = OT::Sanitizer<OT::GDEF>::sanitize (face->reference_table (HB_OT_TAG_GDEF));
   layout->gdef = OT::Sanitizer<OT::GDEF>::lock_instance (layout->gdef_blob);
 
   layout->gsub_blob = OT::Sanitizer<OT::GSUB>::sanitize (face->reference_table (HB_OT_TAG_GSUB));
   layout->gsub = OT::Sanitizer<OT::GSUB>::lock_instance (layout->gsub_blob);
 
   layout->gpos_blob = OT::Sanitizer<OT::GPOS>::sanitize (face->reference_table (HB_OT_TAG_GPOS));
@@ -171,17 +171,17 @@ hb_ot_layout_t *
 
   layout->gsub_accels = (hb_ot_layout_lookup_accelerator_t *) calloc (layout->gsub->get_lookup_count (), sizeof (hb_ot_layout_lookup_accelerator_t));
   layout->gpos_accels = (hb_ot_layout_lookup_accelerator_t *) calloc (layout->gpos->get_lookup_count (), sizeof (hb_ot_layout_lookup_accelerator_t));
 
   if (unlikely ((layout->gsub_lookup_count && !layout->gsub_accels) ||
 		(layout->gpos_lookup_count && !layout->gpos_accels)))
   {
     _hb_ot_layout_destroy (layout);
-    return NULL;
+    return nullptr;
   }
 
   for (unsigned int i = 0; i < layout->gsub_lookup_count; i++)
     layout->gsub_accels[i].init (layout->gsub->get_lookup (i));
   for (unsigned int i = 0; i < layout->gpos_lookup_count; i++)
     layout->gpos_accels[i].init (layout->gpos->get_lookup (i));
 
   return layout;
@@ -316,17 +316,17 @@ hb_ot_layout_table_get_script_tags (hb_f
 #define HB_OT_TAG_LATIN_SCRIPT		HB_TAG ('l', 'a', 't', 'n')
 
 hb_bool_t
 hb_ot_layout_table_find_script (hb_face_t    *face,
 				hb_tag_t      table_tag,
 				hb_tag_t      script_tag,
 				unsigned int *script_index)
 {
-  ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX);
+  static_assert ((OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX), "");
   const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
 
   if (g.find_script_index (script_tag, script_index))
     return true;
 
   /* try finding 'DFLT' */
   if (g.find_script_index (HB_OT_TAG_DEFAULT_SCRIPT, script_index))
     return false;
@@ -347,17 +347,17 @@ hb_ot_layout_table_find_script (hb_face_
 
 hb_bool_t
 hb_ot_layout_table_choose_script (hb_face_t      *face,
 				  hb_tag_t        table_tag,
 				  const hb_tag_t *script_tags,
 				  unsigned int   *script_index,
 				  hb_tag_t       *chosen_script)
 {
-  ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX);
+  static_assert ((OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX), "");
   const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
 
   while (*script_tags)
   {
     if (g.find_script_index (*script_tags, script_index)) {
       if (chosen_script)
         *chosen_script = *script_tags;
       return true;
@@ -406,17 +406,17 @@ hb_ot_layout_table_get_feature_tags (hb_
 }
 
 hb_bool_t
 hb_ot_layout_table_find_feature (hb_face_t    *face,
 				 hb_tag_t      table_tag,
 				 hb_tag_t      feature_tag,
 				 unsigned int *feature_index)
 {
-  ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_FEATURE_INDEX);
+  static_assert ((OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_FEATURE_INDEX), "");
   const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
 
   unsigned int num_features = g.get_feature_count ();
   for (unsigned int i = 0; i < num_features; i++)
   {
     if (feature_tag == g.get_feature_tag (i)) {
       if (feature_index) *feature_index = i;
       return true;
@@ -443,17 +443,17 @@ hb_ot_layout_script_get_language_tags (h
 
 hb_bool_t
 hb_ot_layout_script_find_language (hb_face_t    *face,
 				   hb_tag_t      table_tag,
 				   unsigned int  script_index,
 				   hb_tag_t      language_tag,
 				   unsigned int *language_index)
 {
-  ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX);
+  static_assert ((OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX), "");
   const OT::Script &s = get_gsubgpos_table (face, table_tag).get_script (script_index);
 
   if (s.find_lang_sys_index (language_tag, language_index))
     return true;
 
   /* try with 'dflt'; MS site has had typos and many fonts use it now :( */
   if (s.find_lang_sys_index (HB_OT_TAG_DEFAULT_LANGUAGE, language_index))
     return false;
@@ -469,17 +469,17 @@ hb_ot_layout_language_get_required_featu
 						  unsigned int  language_index,
 						  unsigned int *feature_index)
 {
   return hb_ot_layout_language_get_required_feature (face,
 						     table_tag,
 						     script_index,
 						     language_index,
 						     feature_index,
-						     NULL);
+						     nullptr);
 }
 
 /**
  * hb_ot_layout_language_get_required_feature:
  *
  * Since: 0.9.30
  **/
 hb_bool_t
@@ -522,17 +522,17 @@ hb_ot_layout_language_get_feature_tags (
 					unsigned int  language_index,
 					unsigned int  start_offset,
 					unsigned int *feature_count /* IN/OUT */,
 					hb_tag_t     *feature_tags /* OUT */)
 {
   const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
   const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
 
-  ASSERT_STATIC (sizeof (unsigned int) == sizeof (hb_tag_t));
+  static_assert ((sizeof (unsigned int) == sizeof (hb_tag_t)), "");
   unsigned int ret = l.get_feature_indexes (start_offset, feature_count, (unsigned int *) feature_tags);
 
   if (feature_tags) {
     unsigned int count = *feature_count;
     for (unsigned int i = 0; i < count; i++)
       feature_tags[i] = g.get_feature_tag ((unsigned int) feature_tags[i]);
   }
 
@@ -543,17 +543,17 @@ hb_ot_layout_language_get_feature_tags (
 hb_bool_t
 hb_ot_layout_language_find_feature (hb_face_t    *face,
 				    hb_tag_t      table_tag,
 				    unsigned int  script_index,
 				    unsigned int  language_index,
 				    hb_tag_t      feature_tag,
 				    unsigned int *feature_index)
 {
-  ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_FEATURE_INDEX);
+  static_assert ((OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_FEATURE_INDEX), "");
   const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
   const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
 
   unsigned int num_features = l.get_feature_count ();
   for (unsigned int i = 0; i < num_features; i++) {
     unsigned int f_index = l.get_feature_index (i);
 
     if (feature_tag == g.get_feature_tag (f_index)) {
@@ -647,17 +647,17 @@ static void
   if (!features)
   {
     unsigned int required_feature_index;
     if (hb_ot_layout_language_get_required_feature (face,
 						    table_tag,
 						    script_index,
 						    language_index,
 						    &required_feature_index,
-						    NULL))
+						    nullptr))
       _hb_ot_layout_collect_lookups_lookups (face,
 					     table_tag,
 					     required_feature_index,
 					     lookup_indexes);
 
     /* All features */
     unsigned int feature_indices[32];
     unsigned int offset, len;
@@ -716,17 +716,17 @@ static void
 					  lookup_indexes);
 
   if (!languages)
   {
     /* All languages */
     unsigned int count = hb_ot_layout_script_get_language_tags (face,
 								table_tag,
 								script_index,
-								0, NULL, NULL);
+								0, nullptr, nullptr);
     for (unsigned int language_index = 0; language_index < count; language_index++)
       _hb_ot_layout_collect_lookups_features (face,
 					      table_tag,
 					      script_index,
 					      language_index,
 					      features,
 					      lookup_indexes);
   }
@@ -763,17 +763,17 @@ hb_ot_layout_collect_lookups (hb_face_t 
 			      const hb_tag_t *features,
 			      hb_set_t       *lookup_indexes /* OUT */)
 {
   if (!scripts)
   {
     /* All scripts */
     unsigned int count = hb_ot_layout_table_get_script_tags (face,
 							     table_tag,
-							     0, NULL, NULL);
+							     0, nullptr, nullptr);
     for (unsigned int script_index = 0; script_index < count; script_index++)
       _hb_ot_layout_collect_lookups_languages (face,
 					       table_tag,
 					       script_index,
 					       languages,
 					       features,
 					       lookup_indexes);
   }
@@ -800,20 +800,20 @@ hb_ot_layout_collect_lookups (hb_face_t 
  * hb_ot_layout_lookup_collect_glyphs:
  *
  * Since: 0.9.7
  **/
 void
 hb_ot_layout_lookup_collect_glyphs (hb_face_t    *face,
 				    hb_tag_t      table_tag,
 				    unsigned int  lookup_index,
-				    hb_set_t     *glyphs_before, /* OUT. May be NULL */
-				    hb_set_t     *glyphs_input,  /* OUT. May be NULL */
-				    hb_set_t     *glyphs_after,  /* OUT. May be NULL */
-				    hb_set_t     *glyphs_output  /* OUT. May be NULL */)
+				    hb_set_t     *glyphs_before, /* OUT. May be nullptr */
+				    hb_set_t     *glyphs_input,  /* OUT. May be nullptr */
+				    hb_set_t     *glyphs_after,  /* OUT. May be nullptr */
+				    hb_set_t     *glyphs_output  /* OUT. May be nullptr */)
 {
   if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return;
 
   OT::hb_collect_glyphs_context_t c (face,
 				     glyphs_before,
 				     glyphs_input,
 				     glyphs_after,
 				     glyphs_output);
@@ -854,17 +854,17 @@ unsigned int
 hb_ot_layout_feature_with_variations_get_lookups (hb_face_t    *face,
 						  hb_tag_t      table_tag,
 						  unsigned int  feature_index,
 						  unsigned int  variations_index,
 						  unsigned int  start_offset,
 						  unsigned int *lookup_count /* IN/OUT */,
 						  unsigned int *lookup_indexes /* OUT */)
 {
-  ASSERT_STATIC (OT::FeatureVariations::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_VARIATIONS_INDEX);
+  static_assert ((OT::FeatureVariations::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_VARIATIONS_INDEX), "");
   const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
 
   const OT::Feature &f = g.get_feature_variation (feature_index, variations_index);
 
   return f.get_lookup_indexes (start_offset, lookup_count, lookup_indexes);
 }
 
 
@@ -962,21 +962,21 @@ hb_ot_layout_position_finish_offsets (hb
 
 /**
  * hb_ot_layout_get_size_params:
  *
  * Since: 0.9.10
  **/
 hb_bool_t
 hb_ot_layout_get_size_params (hb_face_t    *face,
-			      unsigned int *design_size,       /* OUT.  May be NULL */
-			      unsigned int *subfamily_id,      /* OUT.  May be NULL */
-			      unsigned int *subfamily_name_id, /* OUT.  May be NULL */
-			      unsigned int *range_start,       /* OUT.  May be NULL */
-			      unsigned int *range_end          /* OUT.  May be NULL */)
+			      unsigned int *design_size,       /* OUT.  May be nullptr */
+			      unsigned int *subfamily_id,      /* OUT.  May be nullptr */
+			      unsigned int *subfamily_name_id, /* OUT.  May be nullptr */
+			      unsigned int *range_start,       /* OUT.  May be nullptr */
+			      unsigned int *range_end          /* OUT.  May be nullptr */)
 {
   const OT::GPOS &gpos = _get_gpos (face);
   const hb_tag_t tag = HB_TAG ('s','i','z','e');
 
   unsigned int num_features = gpos.get_feature_count ();
   for (unsigned int i = 0; i < num_features; i++)
   {
     if (tag == gpos.get_feature_tag (i))
--- a/gfx/harfbuzz/src/hb-ot-map-private.hh
+++ b/gfx/harfbuzz/src/hb-ot-map-private.hh
@@ -48,18 +48,18 @@ struct hb_ot_map_t
     unsigned int stage[2]; /* GSUB/GPOS */
     unsigned int shift;
     hb_mask_t mask;
     hb_mask_t _1_mask; /* mask for value=1, for quick access */
     unsigned int needs_fallback : 1;
     unsigned int auto_zwnj : 1;
     unsigned int auto_zwj : 1;
 
-    static int cmp (const feature_map_t *a, const feature_map_t *b)
-    { return a->tag < b->tag ? -1 : a->tag > b->tag ? 1 : 0; }
+    inline int cmp (const hb_tag_t *tag_) const
+    { return *tag_ < tag ? -1 : *tag_ > tag ? 1 : 0; }
   };
 
   struct lookup_map_t {
     unsigned short index;
     unsigned short auto_zwnj : 1;
     unsigned short auto_zwj : 1;
     hb_mask_t mask;
 
@@ -74,17 +74,17 @@ struct hb_ot_map_t
     pause_func_t pause_func;
   };
 
 
   hb_ot_map_t (void) { memset (this, 0, sizeof (*this)); }
 
   inline hb_mask_t get_global_mask (void) const { return global_mask; }
 
-  inline hb_mask_t get_mask (hb_tag_t feature_tag, unsigned int *shift = NULL) const {
+  inline hb_mask_t get_mask (hb_tag_t feature_tag, unsigned int *shift = nullptr) const {
     const feature_map_t *map = features.bsearch (&feature_tag);
     if (shift) *shift = map ? map->shift : 0;
     return map ? map->mask : 0;
   }
 
   inline bool needs_fallback (hb_tag_t feature_tag) const {
     const feature_map_t *map = features.bsearch (&feature_tag);
     return map ? map->needs_fallback : false;
@@ -103,24 +103,24 @@ struct hb_ot_map_t
   inline unsigned int get_feature_stage (unsigned int table_index, hb_tag_t feature_tag) const {
     const feature_map_t *map = features.bsearch (&feature_tag);
     return map ? map->stage[table_index] : (unsigned int) -1;
   }
 
   inline void get_stage_lookups (unsigned int table_index, unsigned int stage,
 				 const struct lookup_map_t **plookups, unsigned int *lookup_count) const {
     if (unlikely (stage == (unsigned int) -1)) {
-      *plookups = NULL;
+      *plookups = nullptr;
       *lookup_count = 0;
       return;
     }
     assert (stage <= stages[table_index].len);
     unsigned int start = stage ? stages[table_index][stage - 1].last_lookup : 0;
     unsigned int end   = stage < stages[table_index].len ? stages[table_index][stage].last_lookup : lookups[table_index].len;
-    *plookups = end == start ? NULL : &lookups[table_index][start];
+    *plookups = end == start ? nullptr : &lookups[table_index][start];
     *lookup_count = end - start;
   }
 
   HB_INTERNAL void collect_lookups (unsigned int table_index, hb_set_t *lookups) const;
   template <typename Proxy>
   HB_INTERNAL inline void apply (const Proxy &proxy,
 				 const struct hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const;
   HB_INTERNAL void substitute (const struct hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const;
--- a/gfx/harfbuzz/src/hb-ot-map.cc
+++ b/gfx/harfbuzz/src/hb-ot-map.cc
@@ -133,17 +133,17 @@ void hb_ot_map_builder_t::add_pause (uns
   current_stage[table_index]++;
 }
 
 void
 hb_ot_map_builder_t::compile (hb_ot_map_t  &m,
 			      const int    *coords,
 			      unsigned int  num_coords)
 {
-  ASSERT_STATIC (!(HB_GLYPH_FLAG_DEFINED & (HB_GLYPH_FLAG_DEFINED + 1)));
+  static_assert ((!(HB_GLYPH_FLAG_DEFINED & (HB_GLYPH_FLAG_DEFINED + 1))), "");
   unsigned int global_bit_mask = HB_GLYPH_FLAG_DEFINED + 1;
   unsigned int global_bit_shift = _hb_popcount32 (HB_GLYPH_FLAG_DEFINED);
 
   m.global_mask = global_bit_mask;
 
   unsigned int required_feature_index[2];
   hb_tag_t required_feature_tag[2];
   /* We default to applying required feature in stage 0.  If the required
@@ -264,18 +264,18 @@ hb_ot_map_builder_t::compile (hb_ot_map_
     }
     map->_1_mask = (1u << map->shift) & map->mask;
     map->needs_fallback = !found;
 
   }
   feature_infos.shrink (0); /* Done with these */
 
 
-  add_gsub_pause (NULL);
-  add_gpos_pause (NULL);
+  add_gsub_pause (nullptr);
+  add_gpos_pause (nullptr);
 
   for (unsigned int table_index = 0; table_index < 2; table_index++)
   {
     /* Collect lookup indices for features */
 
     unsigned int variations_index;
     hb_ot_layout_table_find_feature_variations (face,
 						table_tags[table_index],
--- a/gfx/harfbuzz/src/hb-ot-math-table.hh
+++ b/gfx/harfbuzz/src/hb-ot-math-table.hh
@@ -45,17 +45,17 @@ struct MathValueRecord
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) && deviceTable.sanitize (c, base));
   }
 
   protected:
   SHORT			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 NULL.
+					 * beginning of parent table. May be nullptr.
 					 * Suggested format for device table is 1. */
 
   public:
   DEFINE_SIZE_STATIC (4);
 };
 
 struct MathConstants
 {
@@ -314,17 +314,17 @@ struct MathKernInfoRecord
   {
     unsigned int idx = kern;
     if (unlikely (idx >= ARRAY_LENGTH (mathKern))) return 0;
     return (base+mathKern[idx]).get_value (correction_height, font);
   }
 
   protected:
   /* Offset to MathKern table for each corner -
-   * from the beginning of MathKernInfo table. May be NULL. */
+   * from the beginning of MathKernInfo table. May be nullptr. */
   OffsetTo<MathKern> mathKern[4];
 
   public:
   DEFINE_SIZE_STATIC (8);
 };
 
 struct MathKernInfo
 {
@@ -397,17 +397,17 @@ struct MathGlyphInfo
   /* Offset to MathTopAccentAttachment table -
    * from the beginning of MathGlyphInfo table. */
   OffsetTo<MathTopAccentAttachment> mathTopAccentAttachment;
 
   /* Offset to coverage table for Extended Shape glyphs -
    * from the beginning of MathGlyphInfo table. When the left or right glyph of
    * a box is an extended shape variant, the (ink) box (and not the default
    * position defined by values in MathConstants table) should be used for
-   * vertical positioning purposes. May be NULL.. */
+   * vertical positioning purposes. May be nullptr.. */
   OffsetTo<Coverage> extendedShapeCoverage;
 
    /* Offset to MathKernInfo table -
     * from the beginning of MathGlyphInfo table. */
   OffsetTo<MathKernInfo> mathKernInfo;
 
   public:
   DEFINE_SIZE_STATIC (8);
@@ -458,18 +458,18 @@ struct MathGlyphPartRecord
 		       hb_font_t *font) const
   {
     out.glyph			= glyph;
 
     out.start_connector_length	= font->em_scale (startConnectorLength, scale);
     out.end_connector_length	= font->em_scale (endConnectorLength, scale);
     out.full_advance		= font->em_scale (fullAdvance, scale);
 
-    ASSERT_STATIC ((unsigned int) HB_MATH_GLYPH_PART_FLAG_EXTENDER ==
-		   (unsigned int) PartFlags::Extender);
+    static_assert ((unsigned int) HB_MATH_GLYPH_PART_FLAG_EXTENDER ==
+		   (unsigned int) PartFlags::Extender, "");
 
     out.flags = (hb_ot_math_glyph_part_flags_t)
 		(unsigned int)
 		(partFlags & PartFlags::Defined);
   }
 
   protected:
   GlyphID   glyph;		  /* Glyph ID for the part. */
@@ -566,17 +566,17 @@ struct MathGlyphConstruction
 	variants[i].advance = font->em_scale (arr[i].advanceMeasurement, scale);
       }
     }
     return mathGlyphVariantRecord.len;
   }
 
   protected:
   /* Offset to MathGlyphAssembly table for this shape - from the beginning of
-     MathGlyphConstruction table. May be NULL. */
+     MathGlyphConstruction table. May be nullptr. */
   OffsetTo<MathGlyphAssembly>	  glyphAssembly;
 
   /* MathGlyphVariantRecords for alternative variants of the glyphs. */
   ArrayOf<MathGlyphVariantRecord> mathGlyphVariantRecord;
 
   public:
   DEFINE_SIZE_ARRAY (4, mathGlyphVariantRecord);
 };
--- a/gfx/harfbuzz/src/hb-ot-post-table.hh
+++ b/gfx/harfbuzz/src/hb-ot-post-table.hh
@@ -24,16 +24,58 @@
  * Google Author(s): Behdad Esfahbod
  */
 
 #ifndef HB_OT_POST_TABLE_HH
 #define HB_OT_POST_TABLE_HH
 
 #include "hb-open-type-private.hh"
 
+#define NUM_FORMAT1_NAMES 258
+
+static const char* const format1_names[NUM_FORMAT1_NAMES] =
+{
+  ".notdef", ".null", "nonmarkingreturn", "space", "exclam", "quotedbl",
+  "numbersign", "dollar", "percent", "ampersand", "quotesingle", "parenleft",
+  "parenright", "asterisk", "plus", "comma", "hyphen", "period", "slash",
+  "zero", "one", "two", "three", "four", "five", "six", "seven", "eight",
+  "nine", "colon", "semicolon", "less", "equal", "greater", "question", "at",
+  "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O",
+  "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "bracketleft",
+  "backslash", "bracketright", "asciicircum", "underscore", "grave", "a", "b",
+  "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q",
+  "r", "s", "t", "u", "v", "w", "x", "y", "z", "braceleft", "bar",
+  "braceright", "asciitilde", "Adieresis", "Aring", "Ccedilla", "Eacute",
+  "Ntilde", "Odieresis", "Udieresis", "aacute", "agrave", "acircumflex",
+  "adieresis", "atilde", "aring", "ccedilla", "eacute", "egrave",
+  "ecircumflex", "edieresis", "iacute", "igrave", "icircumflex", "idieresis",
+  "ntilde", "oacute", "ograve", "ocircumflex", "odieresis", "otilde", "uacute",
+  "ugrave", "ucircumflex", "udieresis", "dagger", "degree", "cent", "sterling",
+  "section", "bullet", "paragraph", "germandbls", "registered", "copyright",
+  "trademark", "acute", "dieresis", "notequal", "AE", "Oslash", "infinity",
+  "plusminus", "lessequal", "greaterequal", "yen", "mu", "partialdiff",
+  "summation", "product", "pi", "integral", "ordfeminine", "ordmasculine",
+  "Omega", "ae", "oslash", "questiondown", "exclamdown", "logicalnot",
+  "radical", "florin", "approxequal", "Delta", "guillemotleft",
+  "guillemotright", "ellipsis", "nonbreakingspace", "Agrave", "Atilde",
+  "Otilde", "OE", "oe", "endash", "emdash", "quotedblleft", "quotedblright",
+  "quoteleft", "quoteright", "divide", "lozenge", "ydieresis", "Ydieresis",
+  "fraction", "currency", "guilsinglleft", "guilsinglright", "fi", "fl",
+  "daggerdbl", "periodcentered", "quotesinglbase", "quotedblbase",
+  "perthousand", "Acircumflex", "Ecircumflex", "Aacute", "Edieresis", "Egrave",
+  "Iacute", "Icircumflex", "Idieresis", "Igrave", "Oacute", "Ocircumflex",
+  "apple", "Ograve", "Uacute", "Ucircumflex", "Ugrave", "dotlessi",
+  "circumflex", "tilde", "macron", "breve", "dotaccent", "ring", "cedilla",
+  "hungarumlaut", "ogonek", "caron", "Lslash", "lslash", "Scaron", "scaron",
+  "Zcaron", "zcaron", "brokenbar", "Eth", "eth", "Yacute", "yacute", "Thorn",
+  "thorn", "minus", "multiply", "onesuperior", "twosuperior", "threesuperior",
+  "onehalf", "onequarter", "threequarters", "franc", "Gbreve", "gbreve",
+  "Idotaccent", "Scedilla", "scedilla", "Cacute", "cacute", "Ccaron", "ccaron",
+  "dcroat",
+};
 
 namespace OT {
 
 
 /*
  * post -- PostScript
  */
 
@@ -66,22 +108,151 @@ struct post
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     if (unlikely (!c->check_struct (this)))
       return_trace (false);
     if (version.to_int () == 0x00020000)
     {
-      const postV2Tail &v2 = StructAfter<postV2Tail>(*this);
+      const postV2Tail &v2 = StructAfter<postV2Tail> (*this);
       return_trace (v2.sanitize (c));
     }
     return_trace (true);
   }
 
+  inline bool get_glyph_name (hb_codepoint_t glyph,
+			      char *buffer, unsigned int buffer_length,
+			      unsigned int blob_len) const
+  {
+    if (version.to_int () == 0x00010000)
+    {
+      if (glyph >= NUM_FORMAT1_NAMES)
+	return false;
+
+      if (!buffer_length)
+	return true;
+      strncpy (buffer, format1_names[glyph], buffer_length);
+      buffer[buffer_length - 1] = '\0';
+      return true;
+    }
+
+    if (version.to_int () == 0x00020000)
+    {
+      const postV2Tail &v2 = StructAfter<postV2Tail> (*this);
+
+      if (glyph >= v2.numberOfGlyphs)
+	return false;
+
+      if (!buffer_length)
+	return true;
+
+      unsigned int index = v2.glyphNameIndex[glyph];
+      if (index < NUM_FORMAT1_NAMES)
+      {
+	if (!buffer_length)
+	  return true;
+	strncpy (buffer, format1_names[index], buffer_length);
+	buffer[buffer_length - 1] = '\0';
+	return true;
+      }
+      index -= NUM_FORMAT1_NAMES;
+
+      unsigned int offset = min_size + v2.min_size + 2 * v2.numberOfGlyphs;
+      unsigned char *data = (unsigned char *) this + offset;
+      unsigned char *end = (unsigned char *) this + blob_len;
+      for (unsigned int i = 0; data < end; i++)
+      {
+	unsigned int name_length = data[0];
+	data++;
+	if (i == index)
+	{
+	  if (unlikely (!name_length))
+	    return false;
+
+	  unsigned int remaining = end - data;
+	  name_length = MIN (name_length, buffer_length - 1);
+	  name_length = MIN (name_length, remaining);
+	  memcpy (buffer, data, name_length);
+	  buffer[name_length] = '\0';
+	  return true;
+	}
+	data += name_length;
+      }
+
+      return false;
+    }
+
+    return false;
+  }
+
+  inline bool get_glyph_from_name (const char *name, int len,
+				   hb_codepoint_t *glyph,
+				   unsigned int blob_len) const
+  {
+    if (len < 0)
+      len = strlen (name);
+
+    if (version.to_int () == 0x00010000)
+    {
+      for (int i = 0; i < NUM_FORMAT1_NAMES; i++)
+      {
+	if (strncmp (name, format1_names[i], len) == 0 && format1_names[i][len] == '\0')
+	{
+	  *glyph = i;
+	  return true;
+	}
+      }
+      return false;
+    }
+
+    if (version.to_int () == 0x00020000)
+    {
+      const postV2Tail &v2 = StructAfter<postV2Tail> (*this);
+      unsigned int offset = min_size + v2.min_size + 2 * v2.numberOfGlyphs;
+      char* data = (char*) this + offset;
+
+
+      /* XXX The following code is wrong. */
+      return false;
+      for (hb_codepoint_t gid = 0; gid < v2.numberOfGlyphs; gid++)
+      {
+	unsigned int index = v2.glyphNameIndex[gid];
+	if (index < NUM_FORMAT1_NAMES)
+	{
+	  if (strncmp (name, format1_names[index], len) == 0 && format1_names[index][len] == '\0')
+	  {
+	    *glyph = gid;
+	    return true;
+	  }
+	  continue;
+	}
+	index -= NUM_FORMAT1_NAMES;
+
+	for (unsigned int i = 0; data < (char*) this + blob_len; i++)
+	{
+	  unsigned int name_length = data[0];
+	  unsigned int remaining = (char*) this + blob_len - data - 1;
+	  name_length = MIN (name_length, remaining);
+	  if (name_length == (unsigned int) len && strncmp (name, data + 1, len) == 0)
+	  {
+	    *glyph = gid;
+	    return true;
+	  }
+	  data += name_length + 1;
+	}
+	return false;
+      }
+
+      return false;
+    }
+
+    return false;
+  }
+
   public:
   FixedVersion<>version;		/* 0x00010000 for version 1.0
 					 * 0x00020000 for version 2.0
 					 * 0x00025000 for version 2.5 (deprecated)
 					 * 0x00030000 for version 3.0 */
   Fixed		italicAngle;		/* Italic angle in counter-clockwise degrees
 					 * from the vertical. Zero for upright text,
 					 * negative for text that leans to the right
--- a/gfx/harfbuzz/src/hb-ot-shape-complex-arabic-fallback.hh
+++ b/gfx/harfbuzz/src/hb-ot-shape-complex-arabic-fallback.hh
@@ -68,17 +68,17 @@ arabic_fallback_synthesize_lookup_single
 
     glyphs[num_glyphs].set (u_glyph);
     substitutes[num_glyphs].set (s_glyph);
 
     num_glyphs++;
   }
 
   if (!num_glyphs)
-    return NULL;
+    return nullptr;
 
   /* Bubble-sort or something equally good!
    * May not be good-enough for presidential candidate interviews, but good-enough for us... */
   hb_stable_sort (&glyphs[0], num_glyphs, OT::GlyphID::cmp, &substitutes[0]);
 
   OT::Supplier<OT::GlyphID> glyphs_supplier      (glyphs, num_glyphs);
   OT::Supplier<OT::GlyphID> substitutes_supplier (substitutes, num_glyphs);
 
@@ -89,17 +89,17 @@ arabic_fallback_synthesize_lookup_single
   bool ret = lookup->serialize_single (&c,
 				       OT::LookupFlag::IgnoreMarks,
 				       glyphs_supplier,
 				       substitutes_supplier,
 				       num_glyphs);
   c.end_serialize ();
   /* TODO sanitize the results? */
 
-  return ret ? c.copy<OT::SubstLookup> () : NULL;
+  return ret ? c.copy<OT::SubstLookup> () : nullptr;
 }
 
 static OT::SubstLookup *
 arabic_fallback_synthesize_lookup_ligature (const hb_ot_shape_plan_t *plan HB_UNUSED,
 					    hb_font_t *font)
 {
   OT::GlyphID first_glyphs[ARRAY_LENGTH_CONST (ligature_table)];
   unsigned int first_glyphs_indirection[ARRAY_LENGTH_CONST (ligature_table)];
@@ -148,17 +148,17 @@ arabic_fallback_synthesize_lookup_ligatu
       ligature_list[num_ligatures].set (ligature_glyph);
       component_count_list[num_ligatures] = 2;
       component_list[num_ligatures].set (second_glyph);
       num_ligatures++;
     }
   }
 
   if (!num_ligatures)
-    return NULL;
+    return nullptr;
 
   OT::Supplier<OT::GlyphID>   first_glyphs_supplier                      (first_glyphs, num_first_glyphs);
   OT::Supplier<unsigned int > ligature_per_first_glyph_count_supplier    (ligature_per_first_glyph_count_list, num_first_glyphs);
   OT::Supplier<OT::GlyphID>   ligatures_supplier                         (ligature_list, num_ligatures);
   OT::Supplier<unsigned int > component_count_supplier                   (component_count_list, num_ligatures);
   OT::Supplier<OT::GlyphID>   component_supplier                         (component_list, num_ligatures);
 
   /* 16 bytes per ligature ought to be enough... */
@@ -172,17 +172,17 @@ arabic_fallback_synthesize_lookup_ligatu
 					 num_first_glyphs,
 					 ligatures_supplier,
 					 component_count_supplier,
 					 component_supplier);
 
   c.end_serialize ();
   /* TODO sanitize the results? */
 
-  return ret ? c.copy<OT::SubstLookup> () : NULL;
+  return ret ? c.copy<OT::SubstLookup> () : nullptr;
 }
 
 static OT::SubstLookup *
 arabic_fallback_synthesize_lookup (const hb_ot_shape_plan_t *plan,
 				   hb_font_t *font,
 				   unsigned int feature_index)
 {
   if (feature_index < 4)
@@ -232,18 +232,18 @@ arabic_fallback_plan_init_win1256 (arabi
   if (!(hb_font_get_glyph (font, 0x0627u, 0, &g) && g == 199 /* ALEF */ &&
 	hb_font_get_glyph (font, 0x0644u, 0, &g) && g == 225 /* LAM */ &&
 	hb_font_get_glyph (font, 0x0649u, 0, &g) && g == 236 /* ALEF MAKSURA */ &&
 	hb_font_get_glyph (font, 0x064Au, 0, &g) && g == 237 /* YEH */ &&
 	hb_font_get_glyph (font, 0x0652u, 0, &g) && g == 250 /* SUKUN */))
     return false;
 
   const Manifest &manifest = reinterpret_cast<const Manifest&> (arabic_win1256_gsub_lookups.manifest);
-  ASSERT_STATIC (sizeof (arabic_win1256_gsub_lookups.manifestData) / sizeof (ManifestLookup)
-		 <= ARABIC_FALLBACK_MAX_LOOKUPS);
+  static_assert (sizeof (arabic_win1256_gsub_lookups.manifestData) / sizeof (ManifestLookup)
+		 <= ARABIC_FALLBACK_MAX_LOOKUPS, "");
   /* TODO sanitize the table? */
 
   unsigned j = 0;
   unsigned int count = manifest.len;
   for (unsigned int i = 0; i < count; i++)
   {
     fallback_plan->mask_array[j] = plan->map.get_1_mask (manifest[i].tag);
     if (fallback_plan->mask_array[j])
@@ -266,17 +266,17 @@ arabic_fallback_plan_init_win1256 (arabi
 #endif
 }
 
 static bool
 arabic_fallback_plan_init_unicode (arabic_fallback_plan_t *fallback_plan,
 				   const hb_ot_shape_plan_t *plan,
 				   hb_font_t *font)
 {
-  ASSERT_STATIC (ARRAY_LENGTH_CONST(arabic_fallback_features) <= ARABIC_FALLBACK_MAX_LOOKUPS);
+  static_assert ((ARRAY_LENGTH_CONST(arabic_fallback_features) <= ARABIC_FALLBACK_MAX_LOOKUPS), "");
   unsigned int j = 0;
   for (unsigned int i = 0; i < ARRAY_LENGTH(arabic_fallback_features) ; i++)
   {
     fallback_plan->mask_array[j] = plan->map.get_1_mask (arabic_fallback_features[i]);
     if (fallback_plan->mask_array[j])
     {
       fallback_plan->lookup_array[j] = arabic_fallback_synthesize_lookup (plan, font, i);
       if (fallback_plan->lookup_array[j])
--- a/gfx/harfbuzz/src/hb-ot-shape-complex-arabic.cc
+++ b/gfx/harfbuzz/src/hb-ot-shape-complex-arabic.cc
@@ -36,17 +36,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 */
 #define HB_ARABIC_GENERAL_CATEGORY_IS_WORD(gen_cat) \
-	(FLAG_SAFE (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) |*/ \
 	  /*FLAG (HB_UNICODE_GENERAL_CATEGORY_UPPERCASE_LETTER) |*/ \
 	  FLAG (HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK) | \
@@ -85,17 +85,17 @@ enum hb_arabic_joining_type_t {
 #include "hb-ot-shape-complex-arabic-table.hh"
 
 static unsigned int get_joining_type (hb_codepoint_t u, hb_unicode_general_category_t gen_cat)
 {
   unsigned int j_type = joining_type(u);
   if (likely (j_type != JOINING_TYPE_X))
     return j_type;
 
-  return (FLAG_SAFE(gen_cat) &
+  return (FLAG_UNSAFE(gen_cat) &
 	  (FLAG(HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) |
 	   FLAG(HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK) |
 	   FLAG(HB_UNICODE_GENERAL_CATEGORY_FORMAT))
 	 ) ?  JOINING_TYPE_T : JOINING_TYPE_U;
 }
 
 #define FEATURE_IS_SYRIAC(tag) hb_in_range<unsigned char> ((unsigned char) (tag), '2', '3')
 
@@ -207,33 +207,33 @@ collect_features_arabic (hb_ot_shape_pla
   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'));
   map->add_global_bool_feature (HB_TAG('l','o','c','l'));
 
-  map->add_gsub_pause (NULL);
+  map->add_gsub_pause (nullptr);
 
   for (unsigned int i = 0; i < ARABIC_NUM_FEATURES; i++)
   {
     bool has_fallback = plan->props.script == HB_SCRIPT_ARABIC && !FEATURE_IS_SYRIAC (arabic_features[i]);
     map->add_feature (arabic_features[i], 1, has_fallback ? F_HAS_FALLBACK : F_NONE);
-    map->add_gsub_pause (NULL);
+    map->add_gsub_pause (nullptr);
   }
 
   map->add_feature (HB_TAG('r','l','i','g'), 1, F_GLOBAL|F_HAS_FALLBACK);
   if (plan->props.script == HB_SCRIPT_ARABIC)
     map->add_gsub_pause (arabic_fallback_shape);
 
   /* No pause after rclt.  See 98460779bae19e4d64d29461ff154b3527bf8420. */
   map->add_global_bool_feature (HB_TAG('r','c','l','t'));
   map->add_global_bool_feature (HB_TAG('c','a','l','t'));
-  map->add_gsub_pause (NULL);
+  map->add_gsub_pause (nullptr);
 
   /* The spec includes 'cswh'.  Earlier versions of Windows
    * used to enable this by default, but testing suggests
    * that Windows 8 and later do not enable it by default,
    * and spec now says 'Off by default'.
    * We disabled this in ae23c24c32.
    * Note that IranNastaliq uses this feature extensively
    * to fixup broken glyph sequences.  Oh well...
@@ -260,17 +260,17 @@ struct arabic_shape_plan_t
   unsigned int has_stch : 1;
 };
 
 void *
 data_create_arabic (const hb_ot_shape_plan_t *plan)
 {
   arabic_shape_plan_t *arabic_plan = (arabic_shape_plan_t *) calloc (1, sizeof (arabic_shape_plan_t));
   if (unlikely (!arabic_plan))
-    return NULL;
+    return nullptr;
 
   arabic_plan->do_fallback = plan->props.script == HB_SCRIPT_ARABIC;
   arabic_plan->has_stch = !!plan->map.get_1_mask (HB_TAG ('s','t','c','h'));
   for (unsigned int i = 0; i < ARABIC_NUM_FEATURES; i++) {
     arabic_plan->mask_array[i] = plan->map.get_1_mask (arabic_features[i]);
     arabic_plan->do_fallback = arabic_plan->do_fallback &&
 			       (FEATURE_IS_SYRIAC (arabic_features[i]) ||
 			        plan->map.needs_fallback (arabic_features[i]));
@@ -407,17 +407,17 @@ arabic_fallback_shape (const hb_ot_shape
     return;
 
 retry:
   arabic_fallback_plan_t *fallback_plan = (arabic_fallback_plan_t *) hb_atomic_ptr_get (&arabic_plan->fallback_plan);
   if (unlikely (!fallback_plan))
   {
     /* This sucks.  We need a font to build the fallback plan... */
     fallback_plan = arabic_fallback_plan_create (plan, font);
-    if (unlikely (!hb_atomic_ptr_cmpexch (&(const_cast<arabic_shape_plan_t *> (arabic_plan))->fallback_plan, NULL, fallback_plan))) {
+    if (unlikely (!hb_atomic_ptr_cmpexch (&(const_cast<arabic_shape_plan_t *> (arabic_plan))->fallback_plan, nullptr, fallback_plan))) {
       arabic_fallback_plan_destroy (fallback_plan);
       goto retry;
     }
   }
 
   arabic_fallback_plan_shape (fallback_plan, font, buffer);
 }
 
@@ -527,21 +527,21 @@ apply_stch (const hb_ot_shape_plan_t *pl
 	     (_hb_glyph_info_is_default_ignorable (&info[context - 1]) ||
 	      HB_ARABIC_GENERAL_CATEGORY_IS_WORD (_hb_glyph_info_get_general_category (&info[context - 1]))))
       {
 	context--;
 	w_total += pos[context].x_advance;
       }
       i++; // Don't touch i again.
 
-      DEBUG_MSG (ARABIC, NULL, "%s stretch at (%d,%d,%d)",
+      DEBUG_MSG (ARABIC, nullptr, "%s stretch at (%d,%d,%d)",
 		 step == MEASURE ? "measuring" : "cutting", context, start, end);
-      DEBUG_MSG (ARABIC, NULL, "rest of word:    count=%d width %d", start - context, w_total);
-      DEBUG_MSG (ARABIC, NULL, "fixed tiles:     count=%d width=%d", n_fixed, w_fixed);
-      DEBUG_MSG (ARABIC, NULL, "repeating tiles: count=%d width=%d", n_repeating, w_repeating);
+      DEBUG_MSG (ARABIC, nullptr, "rest of word:    count=%d width %d", start - context, w_total);
+      DEBUG_MSG (ARABIC, nullptr, "fixed tiles:     count=%d width=%d", n_fixed, w_fixed);
+      DEBUG_MSG (ARABIC, nullptr, "repeating tiles: count=%d width=%d", n_repeating, w_repeating);
 
       /* Number of additional times to repeat each repeating tile. */
       int n_copies = 0;
 
       hb_position_t w_remaining = w_total - w_fixed;
       if (sign * w_remaining > sign * w_repeating && sign * w_repeating > 0)
 	n_copies = (sign * w_remaining) / (sign * w_repeating) - 1;
 
@@ -554,30 +554,30 @@ apply_stch (const hb_ot_shape_plan_t *pl
         hb_position_t excess = (n_copies + 1) * sign * w_repeating - sign * w_remaining;
         if (excess > 0)
           extra_repeat_overlap = excess / (n_copies * n_repeating);
       }
 
       if (step == MEASURE)
       {
 	extra_glyphs_needed += n_copies * n_repeating;
-	DEBUG_MSG (ARABIC, NULL, "will add extra %d copies of repeating tiles", n_copies);
+	DEBUG_MSG (ARABIC, nullptr, "will add extra %d copies of repeating tiles", n_copies);
       }
       else
       {
 	hb_position_t x_offset = 0;
 	for (unsigned int k = end; k > start; k--)
 	{
 	  hb_position_t width = font->get_glyph_h_advance (info[k - 1].codepoint);
 
 	  unsigned int repeat = 1;
 	  if (info[k - 1].arabic_shaping_action() == STCH_REPEATING)
 	    repeat += n_copies;
 
-	  DEBUG_MSG (ARABIC, NULL, "appending %d copies of glyph %d; j=%d",
+	  DEBUG_MSG (ARABIC, nullptr, "appending %d copies of glyph %d; j=%d",
 		     repeat, info[k - 1].codepoint, j);
 	  for (unsigned int n = 0; n < repeat; n++)
 	  {
 	    x_offset -= width;
 	    if (n > 0)
 	      x_offset += extra_repeat_overlap;
 	    pos[k - 1].x_offset = x_offset;
 	    /* Append copy. */
@@ -686,22 +686,22 @@ reorder_marks_arabic (const hb_ot_shape_
     i = j;
   }
 }
 
 const hb_ot_complex_shaper_t _hb_ot_complex_shaper_arabic =
 {
   "arabic",
   collect_features_arabic,
-  NULL, /* override_features */
+  nullptr, /* override_features */
   data_create_arabic,
   data_destroy_arabic,
-  NULL, /* preprocess_text */
+  nullptr, /* preprocess_text */
   postprocess_glyphs_arabic,
   HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
-  NULL, /* decompose */
-  NULL, /* compose */
+  nullptr, /* decompose */
+  nullptr, /* compose */
   setup_masks_arabic,
-  NULL, /* disable_otl */
+  nullptr, /* disable_otl */
   reorder_marks_arabic,
   HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
   true, /* fallback_position */
 };
--- a/gfx/harfbuzz/src/hb-ot-shape-complex-default.cc
+++ b/gfx/harfbuzz/src/hb-ot-shape-complex-default.cc
@@ -25,23 +25,23 @@
  */
 
 #include "hb-ot-shape-complex-private.hh"
 
 
 const hb_ot_complex_shaper_t _hb_ot_complex_shaper_default =
 {
   "default",
-  NULL, /* collect_features */
-  NULL, /* override_features */
-  NULL, /* data_create */
-  NULL, /* data_destroy */
-  NULL, /* preprocess_text */
-  NULL, /* postprocess_glyphs */
+  nullptr, /* collect_features */
+  nullptr, /* override_features */
+  nullptr, /* data_create */
+  nullptr, /* data_destroy */
+  nullptr, /* preprocess_text */
+  nullptr, /* postprocess_glyphs */
   HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
-  NULL, /* decompose */
-  NULL, /* compose */
-  NULL, /* setup_masks */
-  NULL, /* disable_otl */
-  NULL, /* reorder_marks */
+  nullptr, /* decompose */
+  nullptr, /* compose */
+  nullptr, /* setup_masks */
+  nullptr, /* disable_otl */
+  nullptr, /* reorder_marks */
   HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
   true, /* fallback_position */
 };
--- a/gfx/harfbuzz/src/hb-ot-shape-complex-hangul.cc
+++ b/gfx/harfbuzz/src/hb-ot-shape-complex-hangul.cc
@@ -75,17 +75,17 @@ struct hangul_shape_plan_t
   hb_mask_t mask_array[HANGUL_FEATURE_COUNT];
 };
 
 static void *
 data_create_hangul (const hb_ot_shape_plan_t *plan)
 {
   hangul_shape_plan_t *hangul_plan = (hangul_shape_plan_t *) calloc (1, sizeof (hangul_shape_plan_t));
   if (unlikely (!hangul_plan))
-    return NULL;
+    return nullptr;
 
   for (unsigned int i = 0; i < HANGUL_FEATURE_COUNT; i++)
     hangul_plan->mask_array[i] = plan->map.get_1_mask (hangul_features[i]);
 
   return hangul_plan;
 }
 
 static void
@@ -415,18 +415,18 @@ setup_masks_hangul (const hb_ot_shape_pl
 const hb_ot_complex_shaper_t _hb_ot_complex_shaper_hangul =
 {
   "hangul",
   collect_features_hangul,
   override_features_hangul,
   data_create_hangul,
   data_destroy_hangul,
   preprocess_text_hangul,
-  NULL, /* postprocess_glyphs */
+  nullptr, /* postprocess_glyphs */
   HB_OT_SHAPE_NORMALIZATION_MODE_NONE,
-  NULL, /* decompose */
-  NULL, /* compose */
+  nullptr, /* decompose */
+  nullptr, /* compose */
   setup_masks_hangul,
-  NULL, /* disable_otl */
-  NULL, /* reorder_marks */
+  nullptr, /* disable_otl */
+  nullptr, /* reorder_marks */
   HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE,
   false, /* fallback_position */
 };
--- a/gfx/harfbuzz/src/hb-ot-shape-complex-hebrew.cc
+++ b/gfx/harfbuzz/src/hb-ot-shape-complex-hebrew.cc
@@ -165,23 +165,23 @@ disable_otl_hebrew (const hb_ot_shape_pl
    */
   return plan->map.chosen_script[1] != HB_TAG ('h','e','b','r');
 }
 
 
 const hb_ot_complex_shaper_t _hb_ot_complex_shaper_hebrew =
 {
   "hebrew",
-  NULL, /* collect_features */
-  NULL, /* override_features */
-  NULL, /* data_create */
-  NULL, /* data_destroy */
-  NULL, /* preprocess_text */
-  NULL, /* postprocess_glyphs */
+  nullptr, /* collect_features */
+  nullptr, /* override_features */
+  nullptr, /* data_create */
+  nullptr, /* data_destroy */
+  nullptr, /* preprocess_text */
+  nullptr, /* postprocess_glyphs */
   HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
-  NULL, /* decompose */
+  nullptr, /* decompose */
   compose_hebrew,
-  NULL, /* setup_masks */
+  nullptr, /* setup_masks */
   disable_otl_hebrew,
-  NULL, /* reorder_marks */
+  nullptr, /* reorder_marks */
   HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
   true, /* fallback_position */
 };
--- a/gfx/harfbuzz/src/hb-ot-shape-complex-indic.cc
+++ b/gfx/harfbuzz/src/hb-ot-shape-complex-indic.cc
@@ -137,17 +137,17 @@ is_ra (hb_codepoint_t u)
   return false;
 }
 
 static inline bool
 is_one_of (const hb_glyph_info_t &info, unsigned int flags)
 {
   /* If it ligated, all bets are off. */
   if (_hb_glyph_info_ligated (&info)) return false;
-  return !!(FLAG_SAFE (info.indic_category()) & flags);
+  return !!(FLAG_UNSAFE (info.indic_category()) & flags);
 }
 
 static inline bool
 is_joiner (const hb_glyph_info_t &info)
 {
   return is_one_of (info, JOINER_FLAGS);
 }
 
@@ -193,17 +193,17 @@ set_indic_properties (hb_glyph_info_t &i
   else if (unlikely (u == 0x1CEDu))
     cat = OT_A;
   /* The following take marks in standalone clusters, similar to Avagraha. */
   else if (unlikely (hb_in_ranges<hb_codepoint_t> (u, 0xA8F2u, 0xA8F7u,
 				      0x1CE9u, 0x1CECu,
 				      0x1CEEu, 0x1CF1u)))
   {
     cat = OT_Symbol;
-    ASSERT_STATIC ((int) INDIC_SYLLABIC_CATEGORY_AVAGRAHA == OT_Symbol);
+    static_assert (((int) INDIC_SYLLABIC_CATEGORY_AVAGRAHA == OT_Symbol), "");
   }
   else if (unlikely (hb_in_range<hb_codepoint_t> (u, 0x17CDu, 0x17D1u) ||
 		     u == 0x17CBu || u == 0x17D3u || u == 0x17DDu)) /* Khmer Various signs */
   {
     /* 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;
@@ -228,27 +228,27 @@ set_indic_properties (hb_glyph_info_t &i
 				    cat = OT_PLACEHOLDER;
   else if (unlikely (u == 0x25CCu)) cat = OT_DOTTEDCIRCLE;
 
 
   /*
    * Re-assign position.
    */
 
-  if ((FLAG_SAFE (cat) & CONSONANT_FLAGS))
+  if ((FLAG_UNSAFE (cat) & CONSONANT_FLAGS))
   {
     pos = POS_BASE_C;
     if (is_ra (u))
       cat = OT_Ra;
   }
   else if (cat == OT_M)
   {
     pos = matra_position (u, pos);
   }
-  else if ((FLAG_SAFE (cat) & (FLAG (OT_SM) | FLAG (OT_VD) | FLAG (OT_A) | FLAG (OT_Symbol))))
+  else if ((FLAG_UNSAFE (cat) & (FLAG (OT_SM) | FLAG (OT_VD) | FLAG (OT_A) | FLAG (OT_Symbol))))
   {
     pos = POS_SMVD;
   }
 
   if (unlikely (u == 0x0B01u)) pos = POS_BEFORE_SUB; /* Oriya Bindu is BeforeSub in the spec. */
 
 
 
@@ -430,17 +430,17 @@ collect_features_indic (hb_ot_shape_plan
    * there is a use of it, it's typically at the beginning. */
   map->add_global_bool_feature (HB_TAG('c','c','m','p'));
 
 
   unsigned int i = 0;
   map->add_gsub_pause (initial_reordering);
   for (; i < INDIC_BASIC_FEATURES; i++) {
     map->add_feature (indic_features[i].tag, 1, indic_features[i].flags | F_MANUAL_ZWJ | F_MANUAL_ZWNJ);
-    map->add_gsub_pause (NULL);
+    map->add_gsub_pause (nullptr);
   }
   map->add_gsub_pause (final_reordering);
   for (; i < INDIC_NUM_FEATURES; i++) {
     map->add_feature (indic_features[i].tag, 1, indic_features[i].flags | F_MANUAL_ZWJ | F_MANUAL_ZWNJ);
   }
 
   map->add_global_bool_feature (HB_TAG('c','a','l','t'));
   map->add_global_bool_feature (HB_TAG('c','l','i','g'));
@@ -528,17 +528,17 @@ struct indic_shape_plan_t
   hb_mask_t mask_array[INDIC_NUM_FEATURES];
 };
 
 static void *
 data_create_indic (const hb_ot_shape_plan_t *plan)
 {
   indic_shape_plan_t *indic_plan = (indic_shape_plan_t *) calloc (1, sizeof (indic_shape_plan_t));
   if (unlikely (!indic_plan))
-    return NULL;
+    return nullptr;
 
   indic_plan->config = &indic_configs[0];
   for (unsigned int i = 1; i < ARRAY_LENGTH (indic_configs); i++)
     if (plan->props.script == indic_configs[i].script) {
       indic_plan->config = &indic_configs[i];
       break;
     }
 
@@ -963,17 +963,17 @@ initial_reordering_consonant_syllable (c
       }
   }
 
   /* Attach misc marks to previous char to move with them. */
   {
     indic_position_t last_pos = POS_START;
     for (unsigned int i = start; i < end; i++)
     {
-      if ((FLAG_SAFE (info[i].indic_category()) & (JOINER_FLAGS | FLAG (OT_N) | FLAG (OT_RS) | MEDIAL_FLAGS | HALANT_OR_COENG_FLAGS)))
+      if ((FLAG_UNSAFE (info[i].indic_category()) & (JOINER_FLAGS | FLAG (OT_N) | FLAG (OT_RS) | MEDIAL_FLAGS | HALANT_OR_COENG_FLAGS)))
       {
 	info[i].indic_position() = last_pos;
 	if (unlikely (info[i].indic_category() == OT_H &&
 		      info[i].indic_position() == POS_PRE_M))
 	{
 	  /*
 	   * Uniscribe doesn't move the Halant with Left Matra.
 	   * TEST: U+092B,U+093F,U+094DE
@@ -1533,17 +1533,17 @@ final_reordering_syllable (const hb_ot_s
      *          consonant is found, the target position should be before the
      *          first matra, syllable modifier sign or vedic sign.
      */
     /* This is our take on what step 4 is trying to say (and failing, BADLY). */
     if (reph_pos == REPH_POS_AFTER_SUB)
     {
       new_reph_pos = base;
       while (new_reph_pos + 1 < end &&
-	     !( FLAG_SAFE (info[new_reph_pos + 1].indic_position()) & (FLAG (POS_POST_C) | FLAG (POS_AFTER_POST) | FLAG (POS_SMVD))))
+	     !( FLAG_UNSAFE (info[new_reph_pos + 1].indic_position()) & (FLAG (POS_POST_C) | FLAG (POS_AFTER_POST) | FLAG (POS_SMVD))))
 	new_reph_pos++;
       if (new_reph_pos < end)
         goto reph_move;
     }
 
     /*       5. If no consonant is found in steps 3 or 4, move reph to a position
      *          immediately before the first post-base matra, syllable modifier
      *          sign or vedic sign that has a reordering class after the intended
@@ -1683,17 +1683,17 @@ final_reordering_syllable (const hb_ot_s
         break;
       }
   }
 
 
   /* Apply 'init' to the Left Matra if it's a word start. */
   if (info[start].indic_position () == POS_PRE_M &&
       (!start ||
-       !(FLAG_SAFE (_hb_glyph_info_get_general_category (&info[start - 1])) &
+       !(FLAG_UNSAFE (_hb_glyph_info_get_general_category (&info[start - 1])) &
 	 FLAG_RANGE (HB_UNICODE_GENERAL_CATEGORY_FORMAT, HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK))))
     info[start].mask |= indic_plan->mask_array[INIT];
 
 
   /*
    * Finish off the clusters and go home!
    */
   if (hb_options ().uniscribe_bug_compatible)
@@ -1843,19 +1843,19 @@ compose_indic (const hb_ot_shape_normali
 
 const hb_ot_complex_shaper_t _hb_ot_complex_shaper_indic =
 {
   "indic",
   collect_features_indic,
   override_features_indic,
   data_create_indic,
   data_destroy_indic,
-  NULL, /* preprocess_text */
-  NULL, /* postprocess_glyphs */
+  nullptr, /* preprocess_text */
+  nullptr, /* postprocess_glyphs */
   HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT,
   decompose_indic,
   compose_indic,
   setup_masks_indic,
-  NULL, /* disable_otl */
-  NULL, /* reorder_marks */
+  nullptr, /* disable_otl */
+  nullptr, /* reorder_marks */
   HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE,
   false, /* fallback_position */
 };
--- a/gfx/harfbuzz/src/hb-ot-shape-complex-myanmar.cc
+++ b/gfx/harfbuzz/src/hb-ot-shape-complex-myanmar.cc
@@ -98,17 +98,17 @@ collect_features_myanmar (hb_ot_shape_pl
    * there is a use of it, it's typically at the beginning. */
   map->add_global_bool_feature (HB_TAG('c','c','m','p'));
 
 
   map->add_gsub_pause (initial_reordering);
   for (unsigned int i = 0; i < ARRAY_LENGTH (basic_features); i++)
   {
     map->add_feature (basic_features[i], 1, F_GLOBAL | F_MANUAL_ZWJ);
-    map->add_gsub_pause (NULL);
+    map->add_gsub_pause (nullptr);
   }
   map->add_gsub_pause (final_reordering);
   for (unsigned int i = 0; i < ARRAY_LENGTH (other_features); i++)
     map->add_feature (other_features[i], 1, F_GLOBAL | F_MANUAL_ZWJ);
 }
 
 static void
 override_features_myanmar (hb_ot_shape_planner_t *plan)
@@ -149,17 +149,17 @@ enum myanmar_category_t {
 };
 
 
 static inline bool
 is_one_of (const hb_glyph_info_t &info, unsigned int flags)
 {
   /* If it ligated, all bets are off. */
   if (_hb_glyph_info_ligated (&info)) return false;
-  return !!(FLAG_SAFE (info.myanmar_category()) & flags);
+  return !!(FLAG_UNSAFE (info.myanmar_category()) & flags);
 }
 
 static inline bool
 is_consonant (const hb_glyph_info_t &info)
 {
   return is_one_of (info, CONSONANT_FLAGS);
 }
 
@@ -508,42 +508,42 @@ final_reordering (const hb_ot_shape_plan
 }
 
 
 /* Uniscribe seems to have a shaper for 'mymr' that is like the
  * generic shaper, except that it zeros mark advances GDEF_LATE. */
 const hb_ot_complex_shaper_t _hb_ot_complex_shaper_myanmar_old =
 {
   "default",
-  NULL, /* collect_features */
-  NULL, /* override_features */
-  NULL, /* data_create */
-  NULL, /* data_destroy */
-  NULL, /* preprocess_text */
-  NULL, /* postprocess_glyphs */
+  nullptr, /* collect_features */
+  nullptr, /* override_features */
+  nullptr, /* data_create */
+  nullptr, /* data_destroy */
+  nullptr, /* preprocess_text */
+  nullptr, /* postprocess_glyphs */
   HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
-  NULL, /* decompose */
-  NULL, /* compose */
-  NULL, /* setup_masks */
-  NULL, /* disable_otl */
-  NULL, /* reorder_marks */
+  nullptr, /* decompose */
+  nullptr, /* compose */
+  nullptr, /* setup_masks */
+  nullptr, /* disable_otl */
+  nullptr, /* reorder_marks */
   HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
   true, /* fallback_position */
 };
 
 const hb_ot_complex_shaper_t _hb_ot_complex_shaper_myanmar =
 {
   "myanmar",
   collect_features_myanmar,
   override_features_myanmar,
-  NULL, /* data_create */
-  NULL, /* data_destroy */
-  NULL, /* preprocess_text */
-  NULL, /* postprocess_glyphs */
+  nullptr, /* data_create */
+  nullptr, /* data_destroy */
+  nullptr, /* preprocess_text */
+  nullptr, /* postprocess_glyphs */
   HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT,
-  NULL, /* decompose */
-  NULL, /* compose */
+  nullptr, /* decompose */
+  nullptr, /* compose */
   setup_masks_myanmar,
-  NULL, /* disable_otl */
-  NULL, /* reorder_marks */
+  nullptr, /* disable_otl */
+  nullptr, /* reorder_marks */
   HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY,
   false, /* fallback_position */
 };
--- a/gfx/harfbuzz/src/hb-ot-shape-complex-private.hh
+++ b/gfx/harfbuzz/src/hb-ot-shape-complex-private.hh
@@ -65,106 +65,106 @@ enum hb_ot_shape_zero_width_marks_type_t
 
 struct hb_ot_complex_shaper_t
 {
   char name[8];
 
   /* collect_features()
    * Called during shape_plan().
    * Shapers should use plan->map to add their features and callbacks.
-   * May be NULL.
+   * May be nullptr.
    */
   void (*collect_features) (hb_ot_shape_planner_t *plan);
 
   /* override_features()
    * Called during shape_plan().
    * Shapers should use plan->map to override features and add callbacks after
    * common features are added.
-   * May be NULL.
+   * May be nullptr.
    */
   void (*override_features) (hb_ot_shape_planner_t *plan);
 
 
   /* data_create()
    * Called at the end of shape_plan().
    * Whatever shapers return will be accessible through plan->data later.
-   * If NULL is returned, means a plan failure.
+   * If nullptr is returned, means a plan failure.
    */
   void *(*data_create) (const hb_ot_shape_plan_t *plan);
 
   /* data_destroy()
    * Called when the shape_plan is being destroyed.
    * plan->data is passed here for destruction.
-   * If NULL is returned, means a plan failure.
-   * May be NULL.
+   * If nullptr is returned, means a plan failure.
+   * May be nullptr.
    */
   void (*data_destroy) (void *data);
 
 
   /* preprocess_text()
    * Called during shape().
    * Shapers can use to modify text before shaping starts.
-   * May be NULL.
+   * May be nullptr.
    */
   void (*preprocess_text) (const hb_ot_shape_plan_t *plan,
 			   hb_buffer_t              *buffer,
 			   hb_font_t                *font);
 
   /* postprocess_glyphs()
    * Called during shape().
    * Shapers can use to modify glyphs after shaping ends.
-   * May be NULL.
+   * May be nullptr.
    */
   void (*postprocess_glyphs) (const hb_ot_shape_plan_t *plan,
 			      hb_buffer_t              *buffer,
 			      hb_font_t                *font);
 
 
   hb_ot_shape_normalization_mode_t normalization_preference;
 
   /* decompose()
    * Called during shape()'s normalization.
-   * May be NULL.
+   * May be nullptr.
    */
   bool (*decompose) (const hb_ot_shape_normalize_context_t *c,
 		     hb_codepoint_t  ab,
 		     hb_codepoint_t *a,
 		     hb_codepoint_t *b);
 
   /* compose()
    * Called during shape()'s normalization.
-   * May be NULL.
+   * May be nullptr.
    */
   bool (*compose) (const hb_ot_shape_normalize_context_t *c,
 		   hb_codepoint_t  a,
 		   hb_codepoint_t  b,
 		   hb_codepoint_t *ab);
 
   /* setup_masks()
    * Called during shape().
    * Shapers should use map to get feature masks and set on buffer.
    * Shapers may NOT modify characters.
-   * May be NULL.
+   * May be nullptr.
    */
   void (*setup_masks) (const hb_ot_shape_plan_t *plan,
 		       hb_buffer_t              *buffer,
 		       hb_font_t                *font);
 
   /* disable_otl()
    * Called during shape().
    * If set and returns true, GDEF/GSUB/GPOS of the font are ignored
    * and fallback operations used.
-   * May be NULL.
+   * May be nullptr.
    */
   bool (*disable_otl) (const hb_ot_shape_plan_t *plan);
 
   /* reorder_marks()
    * Called during shape().
    * Shapers can use to modify ordering of combining marks.
-   * May be NULL.
+   * May be nullptr.
    */
   void (*reorder_marks) (const hb_ot_shape_plan_t *plan,
 			 hb_buffer_t              *buffer,
 			 unsigned int              start,
 			 unsigned int              end);
 
   hb_ot_shape_zero_width_marks_type_t zero_width_marks;
 
@@ -281,17 +281,17 @@ hb_ot_shape_complex_categorize (const hb
        * however, they typically have 'liga' / 'clig' features that implement
        * the necessary "reordering" by means of ligature substitutions.
        * So we send such pref-less fonts through the generic shaper instead. */
       if (planner->map.found_script[0] &&
 	  hb_ot_layout_language_find_feature (planner->face, HB_OT_TAG_GSUB,
 					      planner->map.script_index[0],
 					      planner->map.language_index[0],
 					      HB_TAG ('p','r','e','f'),
-					      NULL))
+					      nullptr))
 	return &_hb_ot_complex_shaper_indic;
       else
 	return &_hb_ot_complex_shaper_default;
 
     case HB_SCRIPT_MYANMAR:
       if (planner->map.chosen_script[0] == HB_TAG ('m','y','m','2'))
 	return &_hb_ot_complex_shaper_myanmar;
       else if (planner->map.chosen_script[0] == HB_TAG ('m','y','m','r'))
--- a/gfx/harfbuzz/src/hb-ot-shape-complex-thai.cc
+++ b/gfx/harfbuzz/src/hb-ot-shape-complex-thai.cc
@@ -92,17 +92,17 @@ enum thai_action_t
 
 static hb_codepoint_t
 thai_pua_shape (hb_codepoint_t u, thai_action_t action, hb_font_t *font)
 {
   struct thai_pua_mapping_t {
     hb_codepoint_t u;
     hb_codepoint_t win_pua;
     hb_codepoint_t mac_pua;
-  } const *pua_mappings = NULL;
+  } const *pua_mappings = nullptr;
   static const thai_pua_mapping_t SD_mappings[] = {
     {0x0E48u, 0xF70Au, 0xF88Bu}, /* MAI EK */
     {0x0E49u, 0xF70Bu, 0xF88Eu}, /* MAI THO */
     {0x0E4Au, 0xF70Cu, 0xF891u}, /* MAI TRI */
     {0x0E4Bu, 0xF70Du, 0xF894u}, /* MAI CHATTAWA */
     {0x0E4Cu, 0xF70Eu, 0xF897u}, /* THANTHAKHAT */
     {0x0E38u, 0xF718u, 0xF89Bu}, /* SARA U */
     {0x0E39u, 0xF719u, 0xF89Cu}, /* SARA UU */
@@ -362,23 +362,23 @@ preprocess_text_thai (const hb_ot_shape_
   /* If font has Thai GSUB, we are done. */
   if (plan->props.script == HB_SCRIPT_THAI && !plan->map.found_script[0])
     do_thai_pua_shaping (plan, buffer, font);
 }
 
 const hb_ot_complex_shaper_t _hb_ot_complex_shaper_thai =
 {
   "thai",
-  NULL, /* collect_features */
-  NULL, /* override_features */
-  NULL, /* data_create */
-  NULL, /* data_destroy */
+  nullptr, /* collect_features */
+  nullptr, /* override_features */
+  nullptr, /* data_create */
+  nullptr, /* data_destroy */
   preprocess_text_thai,
-  NULL, /* postprocess_glyphs */
+  nullptr, /* postprocess_glyphs */
   HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
-  NULL, /* decompose */
-  NULL, /* compose */
-  NULL, /* setup_masks */
-  NULL, /* disable_otl */
-  NULL, /* reorder_marks */
+  nullptr, /* decompose */
+  nullptr, /* compose */
+  nullptr, /* setup_masks */
+  nullptr, /* disable_otl */
+  nullptr, /* reorder_marks */
   HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
   false,/* fallback_position */
 };
--- a/gfx/harfbuzz/src/hb-ot-shape-complex-tibetan.cc
+++ b/gfx/harfbuzz/src/hb-ot-shape-complex-tibetan.cc
@@ -43,22 +43,22 @@ collect_features_tibetan (hb_ot_shape_pl
     plan->map.add_global_bool_feature (*script_features);
 }
 
 
 const hb_ot_complex_shaper_t _hb_ot_complex_shaper_tibetan =
 {
   "default",
   collect_features_tibetan,
-  NULL, /* override_features */
-  NULL, /* data_create */
-  NULL, /* data_destroy */
-  NULL, /* preprocess_text */
-  NULL, /* postprocess_glyphs */
+  nullptr, /* override_features */
+  nullptr, /* data_create */
+  nullptr, /* data_destroy */
+  nullptr, /* preprocess_text */
+  nullptr, /* postprocess_glyphs */
   HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
-  NULL, /* decompose */
-  NULL, /* compose */
-  NULL, /* setup_masks */
-  NULL, /* disable_otl */
-  NULL, /* reorder_marks */
+  nullptr, /* decompose */
+  nullptr, /* compose */
+  nullptr, /* setup_masks */
+  nullptr, /* disable_otl */
+  nullptr, /* reorder_marks */
   HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
   true, /* fallback_position */
 };
--- a/gfx/harfbuzz/src/hb-ot-shape-complex-use.cc
+++ b/gfx/harfbuzz/src/hb-ot-shape-complex-use.cc
@@ -139,17 +139,17 @@ collect_features_use (hb_ot_shape_planne
   for (unsigned int i = 0; i < ARRAY_LENGTH (basic_features); i++)
     map->add_feature (basic_features[i], 1, F_GLOBAL | F_MANUAL_ZWJ);
 
   map->add_gsub_pause (reorder);
 
   /* "Topographical features" */
   for (unsigned int i = 0; i < ARRAY_LENGTH (arabic_features); i++)
     map->add_feature (arabic_features[i], 1, F_NONE);
-  map->add_gsub_pause (NULL);
+  map->add_gsub_pause (nullptr);
 
   /* "Standard typographic presentation" and "Positional feature application" */
   for (unsigned int i = 0; i < ARRAY_LENGTH (other_features); i++)
     map->add_feature (other_features[i], 1, F_GLOBAL | F_MANUAL_ZWJ);
 }
 
 struct use_shape_plan_t
 {
@@ -194,27 +194,27 @@ has_arabic_joining (hb_script_t script)
   }
 }
 
 static void *
 data_create_use (const hb_ot_shape_plan_t *plan)
 {
   use_shape_plan_t *use_plan = (use_shape_plan_t *) calloc (1, sizeof (use_shape_plan_t));
   if (unlikely (!use_plan))
-    return NULL;
+    return nullptr;
 
   use_plan->rphf_mask = plan->map.get_1_mask (HB_TAG('r','p','h','f'));
 
   if (has_arabic_joining (plan->props.script))
   {
     use_plan->arabic_plan = (arabic_shape_plan_t *) data_create_arabic (plan);
     if (unlikely (!use_plan->arabic_plan))
     {
       free (use_plan);
-      return NULL;
+      return nullptr;
     }
   }
 
   return use_plan;
 }
 
 static void
 data_destroy_use (void *data)
@@ -287,17 +287,17 @@ setup_rphf_mask (const hb_ot_shape_plan_
 static void
 setup_topographical_masks (const hb_ot_shape_plan_t *plan,
 			   hb_buffer_t *buffer)
 {
   const use_shape_plan_t *use_plan = (const use_shape_plan_t *) plan->data;
   if (use_plan->arabic_plan)
     return;
 
-  ASSERT_STATIC (INIT < 4 && ISOL < 4 && MEDI < 4 && FINA < 4);
+  static_assert ((INIT < 4 && ISOL < 4 && MEDI < 4 && FINA < 4), "");
   hb_mask_t masks[4], all_masks = 0;
   for (unsigned int i = 0; i < 4; i++)
   {
     masks[i] = plan->map.get_1_mask (arabic_features[i]);
     if (masks[i] == plan->map.get_global_mask ())
       masks[i] = 0;
     all_masks |= masks[i];
   }
@@ -419,17 +419,17 @@ is_halant (const hb_glyph_info_t &info)
   return info.use_category() == USE_H && !_hb_glyph_info_ligated (&info);
 }
 
 static void
 reorder_syllable (hb_buffer_t *buffer, unsigned int start, unsigned int end)
 {
   syllable_type_t syllable_type = (syllable_type_t) (buffer->info[start].syllable() & 0x0F);
   /* Only a few syllable types need reordering. */
-  if (unlikely (!(FLAG_SAFE (syllable_type) &
+  if (unlikely (!(FLAG_UNSAFE (syllable_type) &
 		  (FLAG (virama_terminated_cluster) |
 		   FLAG (standard_cluster) |
 		   FLAG (broken_cluster) |
 		   0))))
     return;
 
   hb_glyph_info_t *info = buffer->info;
 
@@ -592,22 +592,22 @@ compose_use (const hb_ot_shape_normalize
   return (bool)c->unicode->compose (a, b, ab);
 }
 
 
 const hb_ot_complex_shaper_t _hb_ot_complex_shaper_use =
 {
   "use",
   collect_features_use,
-  NULL, /* override_features */
+  nullptr, /* override_features */
   data_create_use,
   data_destroy_use,
-  NULL, /* preprocess_text */
-  NULL, /* postprocess_glyphs */
+  nullptr, /* preprocess_text */
+  nullptr, /* postprocess_glyphs */
   HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT,
   decompose_use,
   compose_use,
   setup_masks_use,
-  NULL, /* disable_otl */
-  NULL, /* reorder_marks */
+  nullptr, /* disable_otl */
+  nullptr, /* reorder_marks */
   HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY,
   false, /* fallback_position */
 };
--- a/gfx/harfbuzz/src/hb-ot-shape-private.hh
+++ b/gfx/harfbuzz/src/hb-ot-shape-private.hh
@@ -68,17 +68,17 @@ struct hb_ot_shape_planner_t
   hb_face_t *face;
   hb_segment_properties_t props;
   const struct hb_ot_complex_shaper_t *shaper;
   hb_ot_map_builder_t map;
 
   hb_ot_shape_planner_t (const hb_shape_plan_t *master_plan) :
 			 face (master_plan->face_unsafe),
 			 props (master_plan->props),
-			 shaper (NULL),
+			 shaper (nullptr),
 			 map (face, &props) {}
   ~hb_ot_shape_planner_t (void) { map.finish (); }
 
   inline void compile (hb_ot_shape_plan_t &plan,
 		       const int          *coords,
 		       unsigned int        num_coords)
   {
     plan.props = props;
--- a/gfx/harfbuzz/src/hb-ot-shape.cc
+++ b/gfx/harfbuzz/src/hb-ot-shape.cc
@@ -65,17 +65,17 @@ static void
 hb_ot_shape_collect_features (hb_ot_shape_planner_t          *planner,
 			      const hb_segment_properties_t  *props,
 			      const hb_feature_t             *user_features,
 			      unsigned int                    num_user_features)
 {
   hb_ot_map_builder_t *map = &planner->map;
 
   map->add_global_bool_feature (HB_TAG('r','v','r','n'));
-  map->add_gsub_pause (NULL);
+  map->add_gsub_pause (nullptr);
 
   switch (props->direction) {
     case HB_DIRECTION_LTR:
       map->add_global_bool_feature (HB_TAG ('l','t','r','a'));
       map->add_global_bool_feature (HB_TAG ('l','t','r','m'));
       break;
     case HB_DIRECTION_RTL:
       map->add_global_bool_feature (HB_TAG ('r','t','l','a'));
@@ -171,31 +171,31 @@ hb_ot_shaper_shape_plan_data_t *
 _hb_ot_shaper_shape_plan_data_create (hb_shape_plan_t    *shape_plan,
 				      const hb_feature_t *user_features,
 				      unsigned int        num_user_features,
 				      const int          *coords,
 				      unsigned int        num_coords)
 {
   hb_ot_shape_plan_t *plan = (hb_ot_shape_plan_t *) calloc (1, sizeof (hb_ot_shape_plan_t));
   if (unlikely (!plan))
-    return NULL;
+    return nullptr;
 
   hb_ot_shape_planner_t planner (shape_plan);
 
   planner.shaper = hb_ot_shape_complex_categorize (&planner);
 
   hb_ot_shape_collect_features (&planner, &shape_plan->props,
 				user_features, num_user_features);
 
   planner.compile (*plan, coords, num_coords);
 
   if (plan->shaper->data_create) {
     plan->data = plan->shaper->data_create (plan);
     if (unlikely (!plan->data))
-      return NULL;
+      return nullptr;
   }
 
   return plan;
 }
 
 void
 _hb_ot_shaper_shape_plan_data_destroy (hb_ot_shaper_shape_plan_data_t *plan)
 {
@@ -923,34 +923,35 @@ void
 hb_ot_shape_glyphs_closure (hb_font_t          *font,
 			    hb_buffer_t        *buffer,
 			    const hb_feature_t *features,
 			    unsigned int        num_features,
 			    hb_set_t           *glyphs)
 {
   hb_ot_shape_plan_t plan;
 
-  const char *shapers[] = {"ot", NULL};
+  const char *shapers[] = {"ot", nullptr};
   hb_shape_plan_t *shape_plan = hb_shape_plan_create_cached (font->face, &buffer->props,
 							     features, num_features, shapers);
 
   bool mirror = hb_script_get_horizontal_direction (buffer->props.script) == HB_DIRECTION_RTL;
 
   unsigned int count = buffer->len;
   hb_glyph_info_t *info = buffer->info;
   for (unsigned int i = 0; i < count; i++)
     add_char (font, buffer->unicode, mirror, info[i].codepoint, glyphs);
 
-  hb_set_t lookups;
-  lookups.init ();
-  hb_ot_shape_plan_collect_lookups (shape_plan, HB_OT_TAG_GSUB, &lookups);
+  hb_set_t *lookups = hb_set_create ();
+  hb_ot_shape_plan_collect_lookups (shape_plan, HB_OT_TAG_GSUB, lookups);
 
   /* And find transitive closure. */
-  hb_set_t copy;
-  copy.init ();
+  hb_set_t *copy = hb_set_create ();
   do {
-    copy.set (glyphs);
-    for (hb_codepoint_t lookup_index = -1; hb_set_next (&lookups, &lookup_index);)
+    copy->set (glyphs);
+    for (hb_codepoint_t lookup_index = -1; hb_set_next (lookups, &lookup_index);)
       hb_ot_layout_lookup_substitute_closure (font->face, lookup_index, glyphs);
-  } while (!copy.is_equal (glyphs));
+  } while (!copy->is_equal (glyphs));
+  hb_set_destroy (copy);
+
+  hb_set_destroy (lookups);
 
   hb_shape_plan_destroy (shape_plan);
 }
--- a/gfx/harfbuzz/src/hb-ot-tag.cc
+++ b/gfx/harfbuzz/src/hb-ot-tag.cc
@@ -1015,17 +1015,17 @@ hb_ot_tag_from_language (hb_language_t l
  * Since: 0.9.2
  **/
 hb_language_t
 hb_ot_tag_to_language (hb_tag_t tag)
 {
   unsigned int i;
 
   if (tag == HB_OT_TAG_DEFAULT_LANGUAGE)
-    return NULL;
+    return nullptr;
 
   /* struct LangTag has only room for 3-letter language tags. */
   switch (tag) {
   case HB_TAG('A','P','P','H'):  /* Phonetic transcription—Americanist conventions */
     return hb_language_from_string ("und-fonnapa", -1);
   case HB_TAG('I','P','P','H'):  /* Phonetic transcription—IPA conventions */
     return hb_language_from_string ("und-fonipa", -1);
   case HB_TAG('S','Y','R',' '):  /* Syriac [macrolanguage] */
--- a/gfx/harfbuzz/src/hb-ot-var.cc
+++ b/gfx/harfbuzz/src/hb-ot-var.cc
@@ -125,17 +125,17 @@ hb_ot_var_normalize_variations (hb_face_
 {
   for (unsigned int i = 0; i < coords_length; i++)
     coords[i] = 0;
 
   const OT::fvar &fvar = _get_fvar (face);
   for (unsigned int i = 0; i < variations_length; i++)
   {
     unsigned int axis_index;
-    if (hb_ot_var_find_axis (face, variations[i].tag, &axis_index, NULL) &&
+    if (hb_ot_var_find_axis (face, variations[i].tag, &axis_index, nullptr) &&
 	axis_index < coords_length)
       coords[axis_index] = fvar.normalize_axis_value (axis_index, variations[i].value);
   }
 
   const OT::avar &avar = _get_avar (face);
   avar.map_coords (coords, coords_length);
 }
 
--- a/gfx/harfbuzz/src/hb-private.hh
+++ b/gfx/harfbuzz/src/hb-private.hh
@@ -69,16 +69,49 @@ extern "C" void  hb_free_impl(void *ptr)
 #define realloc hb_realloc_impl
 #define free hb_free_impl
 #endif
 
 
 /* Compiler attributes */
 
 
+#if __cplusplus < 201103L
+
+// Null pointer literal
+// Source: SC22/WG21/N2431 = J16/07-0301
+// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2431.pdf
+
+const                        // this is a const object...
+class {
+public:
+    template<class T>          // convertible to any type
+    operator T*() const {    // of null non-member
+        return 0;    // pointer...
+    }
+    template<class C, class T> // or any type of null
+    operator T C::*() const { // member pointer...
+        return 0;
+    }
+private:
+    void operator&() const;    // whose address can't be taken
+} _hb_nullptr = {};            // and whose name is nullptr
+#define nullptr _hb_nullptr
+
+// Static assertions
+#ifndef static_assert
+#define _PASTE1(a,b) a##b
+#define _PASTE(a,b) _PASTE1(a,b)
+#define static_assert(e, msg) \
+	HB_UNUSED typedef int _PASTE(static_assertion_failed_at_line_, __LINE__) [(e) ? 1 : -1]
+#endif // static_assert
+
+#endif // __cplusplus < 201103L
+
+
 #if (defined(__GNUC__) || defined(__clang__)) && defined(__OPTIMIZE__)
 #define likely(expr) (__builtin_expect (!!(expr), 1))
 #define unlikely(expr) (__builtin_expect (!!(expr), 0))
 #else
 #define likely(expr) (expr)
 #define unlikely(expr) (expr)
 #endif
 
@@ -163,23 +196,23 @@ extern "C" void  hb_free_impl(void *ptr)
 #  endif
 #  ifndef STRICT
 #    define STRICT 1
 #  endif
 
 #  if defined(_WIN32_WCE)
      /* Some things not defined on Windows CE. */
 #    define vsnprintf _vsnprintf
-#    define getenv(Name) NULL
+#    define getenv(Name) nullptr
 #    if _WIN32_WCE < 0x800
 #      define setlocale(Category, Locale) "C"
 static int errno = 0; /* Use something better? */
 #    endif
 #  elif defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_PC_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP)
-#    define getenv(Name) NULL
+#    define getenv(Name) nullptr
 #  endif
 #  if defined(_MSC_VER) && _MSC_VER < 1900
 #    define snprintf _snprintf
 #  endif
 #endif
 
 #if HAVE_ATEXIT
 /* atexit() is only safe to be called from shared libraries on certain
@@ -204,21 +237,16 @@ static int errno = 0; /* Use something b
  * https://developer.android.com/tools/sdk/ndk/index.html
  */
 #    define HB_USE_ATEXIT 1
 #  endif
 #endif
 
 /* Basics */
 
-
-#ifndef NULL
-# define NULL ((void *) 0)
-#endif
-
 #undef MIN
 template <typename Type>
 static inline Type MIN (const Type &a, const Type &b) { return a < b ? a : b; }
 
 #undef MAX
 template <typename Type>
 static inline Type MAX (const Type &a, const Type &b) { return a > b ? a : b; }
 
@@ -230,42 +258,36 @@ static inline unsigned int DIV_CEIL (con
 template <typename Type, unsigned int n>
 static inline unsigned int ARRAY_LENGTH (const Type (&)[n]) { return n; }
 /* A const version, but does not detect erratically being called on pointers. */
 #define ARRAY_LENGTH_CONST(__array) ((signed int) (sizeof (__array) / sizeof (__array[0])))
 
 #define HB_STMT_START do
 #define HB_STMT_END   while (0)
 
-#define _ASSERT_STATIC1(_line, _cond)	HB_UNUSED typedef int _static_assert_on_line_##_line##_failed[(_cond)?1:-1]
-#define _ASSERT_STATIC0(_line, _cond)	_ASSERT_STATIC1 (_line, (_cond))
-#define ASSERT_STATIC(_cond)		_ASSERT_STATIC0 (__LINE__, (_cond))
-
-template <unsigned int cond> class hb_assert_constant_t {};
+template <unsigned int cond> class hb_assert_constant_t;
+template <> class hb_assert_constant_t<1> {};
 
 #define ASSERT_STATIC_EXPR_ZERO(_cond) (0 * (unsigned int) sizeof (hb_assert_constant_t<_cond>))
 
-#define _PASTE1(a,b) a##b
-#define PASTE(a,b) _PASTE1(a,b)
-
 /* Lets assert int types.  Saves trouble down the road. */
 
-ASSERT_STATIC (sizeof (int8_t) == 1);
-ASSERT_STATIC (sizeof (uint8_t) == 1);
-ASSERT_STATIC (sizeof (int16_t) == 2);
-ASSERT_STATIC (sizeof (uint16_t) == 2);
-ASSERT_STATIC (sizeof (int32_t) == 4);
-ASSERT_STATIC (sizeof (uint32_t) == 4);
-ASSERT_STATIC (sizeof (int64_t) == 8);
-ASSERT_STATIC (sizeof (uint64_t) == 8);
+static_assert ((sizeof (int8_t) == 1), "");
+static_assert ((sizeof (uint8_t) == 1), "");
+static_assert ((sizeof (int16_t) == 2), "");
+static_assert ((sizeof (uint16_t) == 2), "");
+static_assert ((sizeof (int32_t) == 4), "");
+static_assert ((sizeof (uint32_t) == 4), "");
+static_assert ((sizeof (int64_t) == 8), "");
+static_assert ((sizeof (uint64_t) == 8), "");
 
-ASSERT_STATIC (sizeof (hb_codepoint_t) == 4);
-ASSERT_STATIC (sizeof (hb_position_t) == 4);
-ASSERT_STATIC (sizeof (hb_mask_t) == 4);
-ASSERT_STATIC (sizeof (hb_var_int_t) == 4);
+static_assert ((sizeof (hb_codepoint_t) == 4), "");
+static_assert ((sizeof (hb_position_t) == 4), "");
+static_assert ((sizeof (hb_mask_t) == 4), "");
+static_assert ((sizeof (hb_var_int_t) == 4), "");
 
 
 /* We like our types POD */
 
 #define _ASSERT_TYPE_POD1(_line, _type)	union _type_##_type##_on_line_##_line##_is_not_POD { _type instance; }
 #define _ASSERT_TYPE_POD0(_line, _type)	_ASSERT_TYPE_POD1 (_line, _type)
 #define ASSERT_TYPE_POD(_type)		_ASSERT_TYPE_POD0 (__LINE__, _type)
 
@@ -290,32 +312,44 @@ ASSERT_STATIC (sizeof (hb_var_int_t) == 
 
 
 
 /* Misc */
 
 /* Void! */
 struct _hb_void_t {};
 typedef const _hb_void_t *hb_void_t;
-#define HB_VOID ((const _hb_void_t *) NULL)
+#define HB_VOID ((const _hb_void_t *) nullptr)
 
 /* Return the number of 1 bits in mask. */
 static inline HB_CONST_FUNC unsigned int
 _hb_popcount32 (uint32_t mask)
 {
 #if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
   return __builtin_popcount (mask);
 #else
   /* "HACKMEM 169" */
   uint32_t y;
   y = (mask >> 1) &033333333333;
   y = mask - y - ((y >>1) & 033333333333);
   return (((y + (y >> 3)) & 030707070707) % 077);
 #endif
 }
+static inline HB_CONST_FUNC unsigned int
+_hb_popcount64 (uint64_t mask)
+{
+#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
+  if (sizeof (long) >= sizeof (mask))
+    return __builtin_popcountl (mask);
+#endif
+  return _hb_popcount32 (mask & 0xFFFFFFFF) + _hb_popcount32 (mask >> 32);
+}
+template <typename T> static inline unsigned int _hb_popcount (T mask);
+template <> inline unsigned int _hb_popcount<uint32_t> (uint32_t mask) { return _hb_popcount32 (mask); }
+template <> inline unsigned int _hb_popcount<uint64_t> (uint64_t mask) { return _hb_popcount64 (mask); }
 
 /* Returns the number of bits needed to store number */
 static inline HB_CONST_FUNC unsigned int
 _hb_bit_storage (unsigned int number)
 {
 #if defined(__GNUC__) && (__GNUC__ >= 4) && defined(__OPTIMIZE__)
   return likely (number) ? (sizeof (unsigned int) * 8 - __builtin_clz (number)) : 0;
 #else
@@ -356,60 +390,75 @@ static inline bool
 typedef int (*hb_compare_func_t) (const void *, const void *);
 
 
 
 
 /* arrays and maps */
 
 
-#define HB_PREALLOCED_ARRAY_INIT {0, 0, NULL}
+#define HB_PREALLOCED_ARRAY_INIT {0, 0, nullptr}
 template <typename Type, unsigned int StaticSize=16>
 struct hb_prealloced_array_t
 {
   unsigned int len;
   unsigned int allocated;
   Type *array;
   Type static_array[StaticSize];
 
-  void init (void) { memset (this, 0, sizeof (*this)); }
+  void init (void)
+  {
+    len = 0;
+    allocated = ARRAY_LENGTH (static_array);
+    array = static_array;
+  }
 
   inline Type& operator [] (unsigned int i) { return array[i]; }
   inline const Type& operator [] (unsigned int i) const { return array[i]; }
 
   inline Type *push (void)
   {
-    if (!array) {
-      array = static_array;
-      allocated = ARRAY_LENGTH (static_array);
-    }
-    if (likely (len < allocated))
-      return &array[len++];
+    if (unlikely (!resize (len + 1)))
+      return nullptr;
+
+    return &array[len - 1];
+  }
+
+  inline bool resize (unsigned int size)
+  {
+    if (unlikely (size > allocated))
+    {
+      /* Need to reallocate */
+
+      unsigned int new_allocated = allocated;
+      while (size >= new_allocated)
+        new_allocated += (new_allocated >> 1) + 8;
 
-    /* Need to reallocate */
-    unsigned int new_allocated = allocated + (allocated >> 1) + 8;
-    Type *new_array = NULL;
+      Type *new_array = nullptr;
 
-    if (array == static_array) {
-      new_array = (Type *) calloc (new_allocated, sizeof (Type));
-      if (new_array)
-        memcpy (new_array, array, len * sizeof (Type));
-    } else {
-      bool overflows = (new_allocated < allocated) || _hb_unsigned_int_mul_overflows (new_allocated, sizeof (Type));
-      if (likely (!overflows)) {
-	new_array = (Type *) realloc (array, new_allocated * sizeof (Type));
+      if (array == static_array) {
+	new_array = (Type *) calloc (new_allocated, sizeof (Type));
+	if (new_array)
+	  memcpy (new_array, array, len * sizeof (Type));
+      } else {
+	bool overflows = (new_allocated < allocated) || _hb_unsigned_int_mul_overflows (new_allocated, sizeof (Type));
+	if (likely (!overflows)) {
+	  new_array = (Type *) realloc (array, new_allocated * sizeof (Type));
+	}
       }
+
+      if (unlikely (!new_array))
+	return false;
+
+      array = new_array;
+      allocated = new_allocated;
     }
 
-    if (unlikely (!new_array))
-      return NULL;
-
-    array = new_array;
-    allocated = new_allocated;
-    return &array[len++];
+    len = size;
+    return true;
   }
 
   inline void pop (void)
   {
     len--;
   }
 
   inline void remove (unsigned int i)
@@ -428,52 +477,77 @@ struct hb_prealloced_array_t
        len = l;
   }
 
   template <typename T>
   inline Type *find (T v) {
     for (unsigned int i = 0; i < len; i++)
       if (array[i] == v)
 	return &array[i];
-    return NULL;
+    return nullptr;
   }
   template <typename T>
   inline const Type *find (T v) const {
     for (unsigned int i = 0; i < len; i++)
       if (array[i] == v)
 	return &array[i];
-    return NULL;
+    return nullptr;
   }
 
   inline void qsort (void)
   {
     ::qsort (array, len, sizeof (Type), (hb_compare_func_t) Type::cmp);
   }
 
   inline void qsort (unsigned int start, unsigned int end)
   {
     ::qsort (array + start, end - start, sizeof (Type), (hb_compare_func_t) Type::cmp);
   }
 
   template <typename T>
-  inline Type *bsearch (T *key)
+  inline Type *bsearch (T *x)
   {
-    return (Type *) ::bsearch (key, array, len, sizeof (Type), (hb_compare_func_t) Type::cmp);
+    unsigned int i;
+    return bfind (x, &i) ? &array[i] : nullptr;
+  }
+  template <typename T>
+  inline const Type *bsearch (T *x) const
+  {
+    unsigned int i;
+    return bfind (x, &i) ? &array[i] : nullptr;
   }
   template <typename T>
-  inline const Type *bsearch (T *key) const
+  inline bool bfind (T *x, unsigned int *i) const
   {
-    return (const Type *) ::bsearch (key, array, len, sizeof (Type), (hb_compare_func_t) Type::cmp);
+    int min = 0, max = (int) this->len - 1;
+    while (min <= max)
+    {
+      int mid = (min + max) / 2;
+      int c = this->array[mid].cmp (x);
+      if (c < 0)
+        max = mid - 1;
+      else if (c > 0)
+        min = mid + 1;
+      else
+      {
+        *i = mid;
+	return true;
+      }
+    }
+    if (max < 0 || (max < (int) this->len && this->array[max].cmp (x) > 0))
+      max++;
+    *i = max;
+    return false;
   }
 
   inline void finish (void)
   {
     if (array != static_array)
       free (array);
-    array = NULL;
+    array = nullptr;
     allocated = len = 0;
   }
 };
 
 template <typename Type>
 struct hb_auto_array_t : hb_prealloced_array_t <Type>
 {
   hb_auto_array_t (void) { hb_prealloced_array_t<Type>::init (); }
@@ -497,17 +571,17 @@ struct hb_lockable_set_t
     if (item) {
       if (replace) {
 	item_t old = *item;
 	*item = v;
 	l.unlock ();
 	old.finish ();
       }
       else {
-        item = NULL;
+        item = nullptr;
 	l.unlock ();
       }
     } else {
       item = items.push ();
       if (likely (item))
 	*item = v;
       l.unlock ();
     }
@@ -760,18 +834,18 @@ template <> inline void
 		  const void *obj HB_UNUSED,
 		  const char *func HB_UNUSED,
 		  bool indented HB_UNUSED,
 		  unsigned int level HB_UNUSED,
 		  int level_dir HB_UNUSED,
 		  const char *message HB_UNUSED,
 		  ...) {}
 
-#define DEBUG_MSG_LEVEL(WHAT, OBJ, LEVEL, LEVEL_DIR, ...)	_hb_debug_msg<HB_DEBUG_##WHAT> (#WHAT, (OBJ), NULL,    true, (LEVEL), (LEVEL_DIR), __VA_ARGS__)
-#define DEBUG_MSG(WHAT, OBJ, ...) 				_hb_debug_msg<HB_DEBUG_##WHAT> (#WHAT, (OBJ), NULL,    false, 0, 0, __VA_ARGS__)
+#define DEBUG_MSG_LEVEL(WHAT, OBJ, LEVEL, LEVEL_DIR, ...)	_hb_debug_msg<HB_DEBUG_##WHAT> (#WHAT, (OBJ), nullptr,    true, (LEVEL), (LEVEL_DIR), __VA_ARGS__)
+#define DEBUG_MSG(WHAT, OBJ, ...) 				_hb_debug_msg<HB_DEBUG_##WHAT> (#WHAT, (OBJ), nullptr,    false, 0, 0, __VA_ARGS__)
 #define DEBUG_MSG_FUNC(WHAT, OBJ, ...)				_hb_debug_msg<HB_DEBUG_##WHAT> (#WHAT, (OBJ), HB_FUNC, false, 0, 0, __VA_ARGS__)
 
 
 /*
  * Printer
  */
 
 template <typename T>
@@ -820,33 +894,33 @@ struct hb_auto_trace_t {
     va_start (ap, message);
     _hb_debug_msg_va<max_level> (what, obj, func, true, plevel ? *plevel : 0, +1, message, ap);
     va_end (ap);
   }
   inline ~hb_auto_trace_t (void)
   {
     _hb_warn_no_return<ret_t> (returned);
     if (!returned) {
-      _hb_debug_msg<max_level> (what, obj, NULL, true, plevel ? *plevel : 1, -1, " ");
+      _hb_debug_msg<max_level> (what, obj, nullptr, true, plevel ? *plevel : 1, -1, " ");
     }
     if (plevel) --*plevel;
   }
 
   inline ret_t ret (ret_t v, unsigned int line = 0)
   {
     if (unlikely (returned)) {
       fprintf (stderr, "OUCH, double calls to return_trace().  This is a bug, please report.\n");
       return v;
     }
 
-    _hb_debug_msg<max_level> (what, obj, NULL, true, plevel ? *plevel : 1, -1,
+    _hb_debug_msg<max_level> (what, obj, nullptr, true, plevel ? *plevel : 1, -1,
 			      "return %s (line %d)",
 			      hb_printer_t<ret_t>().print (v), line);
     if (plevel) --*plevel;
-    plevel = NULL;
+    plevel = nullptr;
     returned = true;
     return v;
   }
 
   private:
   unsigned int *plevel;
   const char *what;
   const void *obj;
@@ -877,17 +951,17 @@ template <> class hb_assert_unsigned_t<u
 template <typename T> static inline bool
 hb_in_range (T u, T lo, T hi)
 {
   /* The sizeof() is here to force template instantiation.
    * I'm sure there are better ways to do this but can't think of
    * one right now.  Declaring a variable won't work as HB_UNUSED
    * is unusable on some platforms and unused types are less likely
    * to generate a warning than unused variables. */
-  ASSERT_STATIC (sizeof (hb_assert_unsigned_t<T>) >= 0);
+  static_assert ((sizeof (hb_assert_unsigned_t<T>) >= 0), "");
 
   /* The casts below are important as if T is smaller than int,
    * the subtract results will become a signed int! */
   return (T)(u - lo) <= (T)(hi - lo);
 }
 
 template <typename T> static inline bool
 hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2)
@@ -922,21 +996,20 @@ hb_in_ranges (T u, T lo1, T hi1, T lo2, 
 	  static inline T& operator |= (T &l, T r) { l = l | r; return l; } \
 	  static inline T& operator &= (T& l, T r) { l = l & r; return l; } \
 	  static inline T& operator ^= (T& l, T r) { l = l ^ r; return l; } \
 	}
 
 
 /* Useful for set-operations on small enums.
  * For example, for testing "x ∈ {x1, x2, x3}" use:
- * (FLAG_SAFE(x) & (FLAG(x1) | FLAG(x2) | FLAG(x3)))
+ * (FLAG_UNSAFE(x) & (FLAG(x1) | FLAG(x2) | FLAG(x3)))
  */
-#define FLAG(x) (ASSERT_STATIC_EXPR_ZERO ((x) < 32) + (1U << (x)))
-#define FLAG_SAFE(x) (1U << (x))
-#define FLAG_UNSAFE(x) ((x) < 32 ? FLAG_SAFE(x) : 0)
+#define FLAG(x) (ASSERT_STATIC_EXPR_ZERO ((unsigned int)(x) < 32) + (1U << (unsigned int)(x)))
+#define FLAG_UNSAFE(x) ((unsigned int)(x) < 32 ? (1U << (unsigned int)(x)) : 0)
 #define FLAG_RANGE(x,y) (ASSERT_STATIC_EXPR_ZERO ((x) < (y)) + FLAG(y+1) - FLAG(x))
 
 
 template <typename T, typename T2> static inline void
 hb_stable_sort (T *array, unsigned int len, int(*compar)(const T *, const T *), T2 *array2)
 {
   for (unsigned int i = 1; i < len; i++)
   {
@@ -958,17 +1031,17 @@ hb_stable_sort (T *array, unsigned int l
       array2[j] = t;
     }
   }
 }
 
 template <typename T> static inline void
 hb_stable_sort (T *array, unsigned int len, int(*compar)(const T *, const T *))
 {
-  hb_stable_sort (array, len, compar, (int *) NULL);
+  hb_stable_sort (array, len, compar, (int *) nullptr);
 }
 
 static inline hb_bool_t
 hb_codepoint_parse (const char *s, unsigned int len, int base, hb_codepoint_t *out)
 {
   /* Pain because we don't know whether s is nul-terminated. */
   char buf[64];
   len = MIN (ARRAY_LENGTH (buf) - 1, len);
@@ -980,29 +1053,96 @@ hb_codepoint_parse (const char *s, unsig
   unsigned long v = strtoul (buf, &end, base);
   if (errno) return false;
   if (*end) return false;
   *out = v;
   return true;
 }
 
 
+/* Vectorization */
+
+struct HbOpOr
+{
+  static const bool passthru_left = true;
+  static const bool passthru_right = true;
+  template <typename T> static void process (T &o, const T &a, const T &b) { o = a | b; }
+};
+struct HbOpAnd
+{
+  static const bool passthru_left = false;
+  static const bool passthru_right = false;
+  template <typename T> static void process (T &o, const T &a, const T &b) { o = a & b; }
+};
+struct HbOpMinus
+{
+  static const bool passthru_left = true;
+  static const bool passthru_right = false;
+  template <typename T> static void process (T &o, const T &a, const T &b) { o = a & ~b; }
+};
+struct HbOpXor
+{
+  static const bool passthru_left = true;
+  static const bool passthru_right = true;
+  template <typename T> static void process (T &o, const T &a, const T &b) { o = a ^ b; }
+};
+
+/* Type behaving similar to vectorized vars defined using __attribute__((vector_size(...))). */
+template <typename elt_t, unsigned int byte_size>
+struct hb_vector_size_t
+{
+  elt_t& operator [] (unsigned int i) { return v[i]; }
+  const elt_t& operator [] (unsigned int i) const { return v[i]; }
+
+  template <class Op>
+  inline hb_vector_size_t process (const hb_vector_size_t &o) const
+  {
+    hb_vector_size_t r;
+    for (unsigned int i = 0; i < ARRAY_LENGTH (v); i++)
+      Op::process (r.v[i], v[i], o.v[i]);
+    return r;
+  }
+  inline hb_vector_size_t operator | (const hb_vector_size_t &o) const
+  { return process<HbOpOr> (o); }
+  inline hb_vector_size_t operator & (const hb_vector_size_t &o) const
+  { return process<HbOpAnd> (o); }
+  inline hb_vector_size_t operator ^ (const hb_vector_size_t &o) const
+  { return process<HbOpXor> (o); }
+  inline hb_vector_size_t operator ~ () const
+  {
+    hb_vector_size_t r;
+    for (unsigned int i = 0; i < ARRAY_LENGTH (v); i++)
+      r.v[i] = ~v[i];
+    return r;
+  }
+
+  private:
+  static_assert (byte_size / sizeof (elt_t) * sizeof (elt_t) == byte_size, "");
+  elt_t v[byte_size / sizeof (elt_t)];
+};
+
+/* The `vector_size' attribute was introduced in gcc 3.1. */
+#if defined( __GNUC__ ) && ( __GNUC__ >= 4 )
+#define HAVE_VECTOR_SIZE 1
+#endif
+
+
 /* Global runtime options. */
 
 struct hb_options_t
 {
   unsigned int initialized : 1;
   unsigned int uniscribe_bug_compatible : 1;
 };
 
 union hb_options_union_t {
   unsigned int i;
   hb_options_t opts;
 };
-ASSERT_STATIC (sizeof (int) == sizeof (hb_options_union_t));
+static_assert ((sizeof (int) == sizeof (hb_options_union_t)), "");
 
 HB_INTERNAL void
 _hb_options_init (void);
 
 extern HB_INTERNAL hb_options_union_t _hb_options;
 
 static inline hb_options_t
 hb_options (void)
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/src/hb-set-digest-private.hh
@@ -0,0 +1,144 @@
+/*
+ * Copyright © 2012  Google, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_SET_DIGEST_PRIVATE_HH
+#define HB_SET_DIGEST_PRIVATE_HH
+
+#include "hb-private.hh"
+
+/*
+ * The set digests here implement various "filters" that support
+ * "approximate member query".  Conceptually these are like Bloom
+ * Filter and Quotient Filter, however, much smaller, faster, and
+ * designed to fit the requirements of our uses for glyph coverage
+ * queries.
+ *
+ * Our filters are highly accurate if the lookup covers fairly local
+ * set of glyphs, but fully flooded and ineffective if coverage is
+ * all over the place.
+ *
+ * The frozen-set can be used instead of a digest, to trade more
+ * memory for 100% accuracy, but in practice, that doesn't look like
+ * an attractive trade-off.
+ */
+
+template <typename mask_t, unsigned int shift>
+struct hb_set_digest_lowest_bits_t
+{
+  ASSERT_POD ();
+
+  static const unsigned int mask_bytes = sizeof (mask_t);
+  static const unsigned int mask_bits = sizeof (mask_t) * 8;
+  static const unsigned int num_bits = 0
+				     + (mask_bytes >= 1 ? 3 : 0)
+				     + (mask_bytes >= 2 ? 1 : 0)
+				     + (mask_bytes >= 4 ? 1 : 0)
+				     + (mask_bytes >= 8 ? 1 : 0)
+				     + (mask_bytes >= 16? 1 : 0)
+				     + 0;
+
+  static_assert ((shift < sizeof (hb_codepoint_t) * 8), "");
+  static_assert ((shift + num_bits <= sizeof (hb_codepoint_t) * 8), "");
+
+  inline void init (void) {
+    mask = 0;
+  }
+
+  inline void add (hb_codepoint_t g) {
+    mask |= mask_for (g);
+  }
+
+  inline void add_range (hb_codepoint_t a, hb_codepoint_t b) {
+    if ((b >> shift) - (a >> shift) >= mask_bits - 1)
+      mask = (mask_t) -1;
+    else {
+      mask_t ma = mask_for (a);
+      mask_t mb = mask_for (b);
+      mask |= mb + (mb - ma) - (mb < ma);
+    }
+  }
+
+  inline bool may_have (hb_codepoint_t g) const {
+    return !!(mask & mask_for (g));
+  }
+
+  private:
+
+  static inline mask_t mask_for (hb_codepoint_t g) {
+    return ((mask_t) 1) << ((g >> shift) & (mask_bits - 1));
+  }
+  mask_t mask;
+};
+
+template <typename head_t, typename tail_t>
+struct hb_set_digest_combiner_t
+{
+  ASSERT_POD ();
+
+  inline void init (void) {
+    head.init ();
+    tail.init ();
+  }
+
+  inline void add (hb_codepoint_t g) {
+    head.add (g);
+    tail.add (g);
+  }
+
+  inline void add_range (hb_codepoint_t a, hb_codepoint_t b) {
+    head.add_range (a, b);
+    tail.add_range (a, b);
+  }
+
+  inline bool may_have (hb_codepoint_t g) const {
+    return head.may_have (g) && tail.may_have (g);
+  }
+
+  private:
+  head_t head;
+  tail_t tail;
+};
+
+
+/*
+ * hb_set_digest_t
+ *
+ * This is a combination of digests that performs "best".
+ * There is not much science to this: it's a result of intuition
+ * and testing.
+ */
+typedef hb_set_digest_combiner_t
+<
+  hb_set_digest_lowest_bits_t<unsigned long, 4>,
+  hb_set_digest_combiner_t
+  <
+    hb_set_digest_lowest_bits_t<unsigned long, 0>,
+    hb_set_digest_lowest_bits_t<unsigned long, 9>
+  >
+> hb_set_digest_t;
+
+
+#endif /* HB_SET_DIGEST_PRIVATE_HH */
--- a/gfx/harfbuzz/src/hb-set-private.hh
+++ b/gfx/harfbuzz/src/hb-set-private.hh
@@ -1,10 +1,10 @@
 /*
- * Copyright © 2012  Google, Inc.
+ * Copyright © 2012,2017  Google, Inc.
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
  * Permission is hereby granted, without written agreement and without
  * license or royalty fees, to use, copy, modify, and distribute this
  * software and its documentation for any purpose, provided that the
  * above copyright notice and the following two paragraphs appear in
  * all copies of this software.
@@ -27,264 +27,369 @@
 #ifndef HB_SET_PRIVATE_HH
 #define HB_SET_PRIVATE_HH
 
 #include "hb-private.hh"
 #include "hb-object-private.hh"
 
 
 /*
- * The set digests here implement various "filters" that support
- * "approximate member query".  Conceptually these are like Bloom
- * Filter and Quotient Filter, however, much smaller, faster, and
- * designed to fit the requirements of our uses for glyph coverage
- * queries.
- *
- * Our filters are highly accurate if the lookup covers fairly local
- * set of glyphs, but fully flooded and ineffective if coverage is
- * all over the place.
- *
- * The frozen-set can be used instead of a digest, to trade more
- * memory for 100% accuracy, but in practice, that doesn't look like
- * an attractive trade-off.
- */
-
-template <typename mask_t, unsigned int shift>
-struct hb_set_digest_lowest_bits_t
-{
-  ASSERT_POD ();
-
-  static const unsigned int mask_bytes = sizeof (mask_t);
-  static const unsigned int mask_bits = sizeof (mask_t) * 8;
-  static const unsigned int num_bits = 0
-				     + (mask_bytes >= 1 ? 3 : 0)
-				     + (mask_bytes >= 2 ? 1 : 0)
-				     + (mask_bytes >= 4 ? 1 : 0)
-				     + (mask_bytes >= 8 ? 1 : 0)
-				     + (mask_bytes >= 16? 1 : 0)
-				     + 0;
-
-  ASSERT_STATIC (shift < sizeof (hb_codepoint_t) * 8);
-  ASSERT_STATIC (shift + num_bits <= sizeof (hb_codepoint_t) * 8);
-
-  inline void init (void) {
-    mask = 0;
-  }
-
-  inline void add (hb_codepoint_t g) {
-    mask |= mask_for (g);
-  }
-
-  inline void add_range (hb_codepoint_t a, hb_codepoint_t b) {
-    if ((b >> shift) - (a >> shift) >= mask_bits - 1)
-      mask = (mask_t) -1;
-    else {
-      mask_t ma = mask_for (a);
-      mask_t mb = mask_for (b);
-      mask |= mb + (mb - ma) - (mb < ma);
-    }
-  }
-
-  inline bool may_have (hb_codepoint_t g) const {
-    return !!(mask & mask_for (g));
-  }
-
-  private:
-
-  static inline mask_t mask_for (hb_codepoint_t g) {
-    return ((mask_t) 1) << ((g >> shift) & (mask_bits - 1));
-  }
-  mask_t mask;
-};
-
-template <typename head_t, typename tail_t>
-struct hb_set_digest_combiner_t
-{
-  ASSERT_POD ();
-
-  inline void init (void) {
-    head.init ();
-    tail.init ();
-  }
-
-  inline void add (hb_codepoint_t g) {
-    head.add (g);
-    tail.add (g);
-  }
-
-  inline void add_range (hb_codepoint_t a, hb_codepoint_t b) {
-    head.add_range (a, b);
-    tail.add_range (a, b);
-  }
-
-  inline bool may_have (hb_codepoint_t g) const {
-    return head.may_have (g) && tail.may_have (g);
-  }
-
-  private:
-  head_t head;
-  tail_t tail;
-};
-
-
-/*
- * hb_set_digest_t
- *
- * This is a combination of digests that performs "best".
- * There is not much science to this: it's a result of intuition
- * and testing.
- */
-typedef hb_set_digest_combiner_t
-<
-  hb_set_digest_lowest_bits_t<unsigned long, 4>,
-  hb_set_digest_combiner_t
-  <
-    hb_set_digest_lowest_bits_t<unsigned long, 0>,
-    hb_set_digest_lowest_bits_t<unsigned long, 9>
-  >
-> hb_set_digest_t;
-
-
-
-/*
  * hb_set_t
  */
 
-
-/* TODO Make this faster and memmory efficient. */
-
 struct hb_set_t
 {
-  friend struct hb_frozen_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 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 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;
+      for (unsigned int i = 0; i < len (); i++)
+        pop += _hb_popcount (v[i]);
+      return pop;
+    }
+
+    inline bool next (hb_codepoint_t *codepoint) const
+    {
+      unsigned int m = (*codepoint + 1) & MASK;
+      if (!m)
+      {
+	*codepoint = INVALID;
+	return false;
+      }
+      unsigned int i = m / ELT_BITS;
+      unsigned int j = m & ELT_MASK;
+
+      for (; j < ELT_BITS; j++)
+        if (v[i] & (elt_t (1) << j))
+	  goto found;
+      for (i++; i < len (); i++)
+        if (v[i])
+	  for (j = 0; j < ELT_BITS; j++)
+	    if (v[i] & (elt_t (1) << j))
+	      goto found;
+
+      *codepoint = INVALID;
+      return false;
+
+    found:
+      *codepoint = i * ELT_BITS + j;
+      return true;
+    }
+    inline hb_codepoint_t get_min (void) const
+    {
+      for (unsigned int i = 0; i < len (); i++)
+        if (v[i])
+	{
+	  elt_t e = v[i];
+	  for (unsigned int j = 0; j < ELT_BITS; j++)
+	    if (e & (elt_t (1) << j))
+	      return i * ELT_BITS + j;
+	}
+      return INVALID;
+    }
+    inline hb_codepoint_t get_max (void) const
+    {
+      for (int i = len () - 1; i >= 0; i--)
+        if (v[i])
+	{
+	  elt_t e = v[i];
+	  for (int j = ELT_BITS - 1; j >= 0; j--)
+	    if (e & (elt_t (1) << j))
+	      return i * ELT_BITS + j;
+	}
+      return 0;
+    }
+
+    static const unsigned int PAGE_BITS = 512; /* Use to tune. */
+    static_assert ((PAGE_BITS & ((PAGE_BITS) - 1)) == 0, "");
+
+    typedef uint64_t elt_t;
+
+#if 0 && HAVE_VECTOR_SIZE
+    /* The vectorized version does not work with clang as non-const
+     * elt() errs "non-const reference cannot bind to vector element". */
+    typedef elt_t vector_t __attribute__((vector_size (PAGE_BITS / 8)));
+#else
+    typedef hb_vector_size_t<elt_t, PAGE_BITS / 8> vector_t;
+#endif
+
+    vector_t v;
+
+    static const unsigned int ELT_BITS = sizeof (elt_t) * 8;
+    static const unsigned int ELT_MASK = ELT_BITS - 1;
+    static const unsigned int BITS = sizeof (vector_t) * 8;
+    static const unsigned int MASK = BITS - 1;
+    static_assert (PAGE_BITS == BITS, "");
+
+    elt_t &elt (hb_codepoint_t g) { return v[(g & MASK) / ELT_BITS]; }
+    elt_t const &elt (hb_codepoint_t g) const { return v[(g & MASK) / ELT_BITS]; }
+    elt_t mask (hb_codepoint_t g) const { return elt_t (1) << (g & ELT_MASK); }
+  };
+  static_assert (page_t::PAGE_BITS == sizeof (page_t) * 8, "");
 
   hb_object_header_t header;
   ASSERT_POD ();
   bool in_error;
+  hb_prealloced_array_t<page_map_t, 8> page_map;
+  hb_prealloced_array_t<page_t, 8> pages;
 
-  inline void init (void) {
-    hb_object_init (this);
-    clear ();
+  inline bool resize (unsigned int count)
+  {
+    if (unlikely (in_error)) return false;
+    if (!pages.resize (count) || !page_map.resize (count))
+    {
+      pages.resize (page_map.len);
+      in_error = true;
+      return false;
+    }
+    return true;
   }
-  inline void fini (void) {
-  }
+
   inline void clear (void) {
     if (unlikely (hb_object_is_inert (this)))
       return;
     in_error = false;
-    memset (elts, 0, sizeof elts);
+    page_map.resize (0);
+    pages.resize (0);
   }
   inline bool is_empty (void) const {
-    for (unsigned int i = 0; i < ARRAY_LENGTH (elts); i++)
-      if (elts[i])
+    unsigned int count = pages.len;
+    for (unsigned int i = 0; i < count; i++)
+      if (!pages[i].is_empty ())
         return false;
     return true;
   }
+
   inline void add (hb_codepoint_t g)
   {
     if (unlikely (in_error)) return;
     if (unlikely (g == INVALID)) return;
-    if (unlikely (g > MAX_G)) return;
-    elt (g) |= mask (g);
+    page_t *page = page_for_insert (g);
+    if (!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);
   }
   inline void del (hb_codepoint_t g)
   {
     if (unlikely (in_error)) return;
-    if (unlikely (g > MAX_G)) return;
-    elt (g) &= ~mask (g);
+    page_t *p = page_for (g);
+    if (!p)
+      return;
+    p->del (g);
   }
   inline void del_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++)
       del (i);
   }
   inline bool has (hb_codepoint_t g) const
   {
-    if (unlikely (g > MAX_G)) return false;
-    return !!(elt (g) & mask (g));
+    const page_t *p = page_for (g);
+    if (!p)
+      return false;
+    return p->has (g);
   }
   inline bool intersects (hb_codepoint_t first,
 			  hb_codepoint_t last) const
   {
-    if (unlikely (first > MAX_G)) return false;
-    if (unlikely (last  > MAX_G)) last = MAX_G;
-    unsigned int end = last + 1;
-    for (hb_codepoint_t i = first; i < end; i++)
-      if (has (i))
-        return true;
-    return false;
-  }
-  inline bool is_equal (const hb_set_t *other) const
-  {
-    for (unsigned int i = 0; i < ELTS; i++)
-      if (elts[i] != other->elts[i])
-        return false;
-    return true;
+    hb_codepoint_t c = first - 1;
+    return next (&c) && c <= last;
   }
   inline void set (const hb_set_t *other)
   {
     if (unlikely (in_error)) return;
-    for (unsigned int i = 0; i < ELTS; i++)
-      elts[i] = other->elts[i];
+    unsigned int count = other->pages.len;
+    if (!resize (count))
+      return;
+
+    memcpy (pages.array, other->pages.array, count * sizeof (pages.array[0]));
+    memcpy (page_map.array, other->page_map.array, count * sizeof (page_map.array[0]));
+  }
+
+  inline bool is_equal (const hb_set_t *other) const
+  {
+    unsigned int na = pages.len;
+    unsigned int nb = other->pages.len;
+
+    unsigned int a = 0, b = 0;
+    for (; a < na && b < nb; )
+    {
+      if (page_at (a).is_empty ()) { a++; continue; }
+      if (other->page_at (b).is_empty ()) { b++; continue; }
+      if (page_map[a].major != other->page_map[b].major ||
+	  !page_at (a).is_equal (&other->page_at (b)))
+        return false;
+      a++;
+      b++;
+    }
+    for (; a < na; a++)
+      if (!page_at (a).is_empty ()) { return false; }
+    for (; b < nb; b++)
+      if (!other->page_at (b).is_empty ()) { return false; }
+
+    return true;
   }
+
+  template <class Op>
+  inline void process (const hb_set_t *other)
+  {
+    if (unlikely (in_error)) return;
+
+    unsigned int na = pages.len;
+    unsigned int nb = other->pages.len;
+
+    unsigned int count = 0;
+    unsigned int a = 0, b = 0;
+    for (; a < na && b < nb; )
+    {
+      if (page_map[a].major == other->page_map[b].major)
+      {
+        count++;
+	a++;
+	b++;
+      }
+      else if (page_map[a].major < other->page_map[b].major)
+      {
+        if (Op::passthru_left)
+	  count++;
+        a++;
+      }
+      else
+      {
+        if (Op::passthru_right)
+	  count++;
+        b++;
+      }
+    }
+    if (Op::passthru_left)
+      count += na - a;
+    if (Op::passthru_right)
+      count += nb - b;
+
+    if (!resize (count))
+      return;
+
+    /* Process in-place backward. */
+    a = na;
+    b = nb;
+    for (; a && b; )
+    {
+      if (page_map[a - 1].major == other->page_map[b - 1].major)
+      {
+	a--;
+	b--;
+        Op::process (page_at (--count).v, page_at (a).v, other->page_at (b).v);
+      }
+      else if (page_map[a - 1].major > other->page_map[b - 1].major)
+      {
+        a--;
+        if (Op::passthru_left)
+	  page_at (--count).v = page_at (a).v;
+      }
+      else
+      {
+        b--;
+        if (Op::passthru_right)
+	  page_at (--count).v = other->page_at (b).v;
+      }
+    }
+    if (Op::passthru_left)
+      while (a)
+	page_at (--count).v = page_at (--a).v;
+    if (Op::passthru_right)
+      while (b)
+	page_at (--count).v = other->page_at (--b).v;
+    assert (!count);
+  }
+
   inline void union_ (const hb_set_t *other)
   {
-    if (unlikely (in_error)) return;
-    for (unsigned int i = 0; i < ELTS; i++)
-      elts[i] |= other->elts[i];
+    process<HbOpOr> (other);
   }
   inline void intersect (const hb_set_t *other)
   {
-    if (unlikely (in_error)) return;
-    for (unsigned int i = 0; i < ELTS; i++)
-      elts[i] &= other->elts[i];
+    process<HbOpAnd> (other);
   }
   inline void subtract (const hb_set_t *other)
   {
-    if (unlikely (in_error)) return;
-    for (unsigned int i = 0; i < ELTS; i++)
-      elts[i] &= ~other->elts[i];
+    process<HbOpMinus> (other);
   }
   inline void symmetric_difference (const hb_set_t *other)
   {
-    if (unlikely (in_error)) return;
-    for (unsigned int i = 0; i < ELTS; i++)
-      elts[i] ^= other->elts[i];
-  }
-  inline void invert (void)
-  {
-    if (unlikely (in_error)) return;
-    for (unsigned int i = 0; i < ELTS; i++)
-      elts[i] = ~elts[i];
+    process<HbOpXor> (other);
   }
   inline bool next (hb_codepoint_t *codepoint) const
   {
     if (unlikely (*codepoint == INVALID)) {
-      hb_codepoint_t i = get_min ();
-      if (i != INVALID) {
-        *codepoint = i;
+      *codepoint = get_min ();
+      return *codepoint != INVALID;
+    }
+
+    page_map_t map = {get_major (*codepoint), 0};
+    unsigned int i;
+    page_map.bfind (&map, &i);
+    if (i < page_map.len)
+    {
+      if (pages[page_map[i].index].next (codepoint))
+      {
+	*codepoint += page_map[i].major * page_t::PAGE_BITS;
+        return true;
+      }
+      i++;
+    }
+    for (; i < page_map.len; i++)
+    {
+      hb_codepoint_t m = pages[page_map[i].index].get_min ();
+      if (m != INVALID)
+      {
+	*codepoint = page_map[i].major * page_t::PAGE_BITS + m;
 	return true;
-      } else {
-	*codepoint = INVALID;
-        return false;
       }
     }
-    for (hb_codepoint_t i = *codepoint + 1; i < MAX_G + 1; i++)
-      if (has (i)) {
-        *codepoint = i;
-	return true;
-      }
     *codepoint = INVALID;
     return false;
   }
   inline bool next_range (hb_codepoint_t *first, hb_codepoint_t *last) const
   {
     hb_codepoint_t i;
 
     i = *last;
@@ -298,105 +403,71 @@ struct hb_set_t
     while (next (&i) && i == *last + 1)
       (*last)++;
 
     return true;
   }
 
   inline unsigned int get_population (void) const
   {
-    unsigned int count = 0;
-    for (unsigned int i = 0; i < ELTS; i++)
-      count += _hb_popcount32 (elts[i]);
-    return count;
+    unsigned int pop = 0;
+    unsigned int count = pages.len;
+    for (unsigned int i = 0; i < count; i++)
+      pop += pages[i].get_population ();
+    return pop;
   }
   inline hb_codepoint_t get_min (void) const
   {
-    for (unsigned int i = 0; i < ELTS; i++)
-      if (elts[i])
-	for (unsigned int j = 0; j < BITS; j++)
-	  if (elts[i] & (1u << j))
-	    return i * BITS + j;
+    unsigned int count = pages.len;
+    for (unsigned int i = 0; i < count; i++)
+      if (!page_at (i).is_empty ())
+        return page_map[i].major * page_t::PAGE_BITS + page_at (i).get_min ();
     return INVALID;
   }
   inline hb_codepoint_t get_max (void) const
   {
-    for (unsigned int i = ELTS; i; i--)
-      if (elts[i - 1])
-	for (unsigned int j = BITS; j; j--)
-	  if (elts[i - 1] & (1u << (j - 1)))
-	    return (i - 1) * BITS + (j - 1);
+    unsigned int count = pages.len;
+    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;
   }
 
-  typedef uint32_t elt_t;
-  static const unsigned int MAX_G = 65536 - 1; /* XXX Fix this... */
-  static const unsigned int SHIFT = 5;
-  static const unsigned int BITS = (1 << SHIFT);
-  static const unsigned int MASK = BITS - 1;
-  static const unsigned int ELTS = (MAX_G + 1 + (BITS - 1)) / BITS;
   static  const hb_codepoint_t INVALID = HB_SET_VALUE_INVALID;
 
-  elt_t &elt (hb_codepoint_t g) { return elts[g >> SHIFT]; }
-  elt_t const &elt (hb_codepoint_t g) const { return elts[g >> SHIFT]; }
-  elt_t mask (hb_codepoint_t g) const { return elt_t (1) << (g & MASK); }
-
-  elt_t elts[ELTS]; /* XXX 8kb */
-
-  ASSERT_STATIC (sizeof (elt_t) * 8 == BITS);
-  ASSERT_STATIC (sizeof (elt_t) * 8 * ELTS > MAX_G);
-};
-
-struct hb_frozen_set_t
-{
-  static const unsigned int SHIFT = hb_set_t::SHIFT;
-  static const unsigned int BITS = hb_set_t::BITS;
-  static const unsigned int MASK = hb_set_t::MASK;
-  typedef hb_set_t::elt_t elt_t;
-
-  inline void init (const hb_set_t &set)
+  page_t *page_for_insert (hb_codepoint_t g)
   {
-    start = count = 0;
-    elts = NULL;
-
-    unsigned int max = set.get_max ();
-    if (max == set.INVALID)
-      return;
-    unsigned int min = set.get_min ();
-    const elt_t &min_elt = set.elt (min);
+    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;
 
-    start = min & ~MASK;
-    count = max - start + 1;
-    unsigned int num_elts = (count + BITS - 1) / BITS;
-    unsigned int elts_size = num_elts * sizeof (elt_t);
-    elts = (elt_t *) malloc (elts_size);
-    if (unlikely (!elts))
-    {
-      start = count = 0;
-      return;
+      pages[map.index].init ();
+      memmove (&page_map[i + 1], &page_map[i], (page_map.len - 1 - i) * sizeof (page_map[0]));
+      page_map[i] = map;
     }
-    memcpy (elts, &min_elt, elts_size);
+    return &pages[page_map[i].index];
   }
-
-  inline void fini (void)
+  page_t *page_for (hb_codepoint_t g)
   {
-    if (elts)
-      free (elts);
+    page_map_t key = {get_major (g)};
+    const page_map_t *found = page_map.bsearch (&key);
+    if (found)
+      return &pages[found->index];
+    return nullptr;
   }
-
-  inline bool has (hb_codepoint_t g) const
+  const page_t *page_for (hb_codepoint_t g) const
   {
-    /* hb_codepoint_t is unsigned. */
-    g -= start;
-    if (unlikely (g > count)) return false;
-    return !!(elt (g) & mask (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;
   }
-
-  elt_t const &elt (hb_codepoint_t g) const { return elts[g >> SHIFT]; }
-  elt_t mask (hb_codepoint_t g) const { return elt_t (1) << (g & MASK); }
-
-  private:
-  hb_codepoint_t start, count;
-  elt_t *elts;
+  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; }
 };
 
 
 #endif /* HB_SET_PRIVATE_HH */
--- a/gfx/harfbuzz/src/hb-set.cc
+++ b/gfx/harfbuzz/src/hb-set.cc
@@ -40,17 +40,18 @@
 hb_set_t *
 hb_set_create (void)
 {
   hb_set_t *set;
 
   if (!(set = hb_object_create<hb_set_t> ()))
     return hb_set_get_empty ();
 
-  set->clear ();
+  set->page_map.init ();
+  set->pages.init ();
 
   return set;
 }
 
 /**
  * hb_set_get_empty:
  *
  * Return value: (transfer full):
@@ -90,17 +91,18 @@ hb_set_reference (hb_set_t *set)
  *
  * Since: 0.9.2
  **/
 void
 hb_set_destroy (hb_set_t *set)
 {
   if (!hb_object_destroy (set)) return;
 
-  set->fini ();
+  set->page_map.finish ();
+  set->pages.finish ();
 
   free (set);
 }
 
 /**
  * hb_set_set_user_data: (skip)
  * @set: a set.
  * @key:
@@ -371,21 +373,22 @@ hb_set_symmetric_difference (hb_set_t   
 
 /**
  * hb_set_invert:
  * @set: a set.
  *
  * 
  *
  * Since: 0.9.10
+ *
+ * Deprecated: 1.6.1
  **/
 void
 hb_set_invert (hb_set_t *set)
 {
-  set->invert ();
 }
 
 /**
  * hb_set_get_population:
  * @set: a set.
  *
  * Returns the number of numbers in the set.
  *
--- a/gfx/harfbuzz/src/hb-set.h
+++ b/gfx/harfbuzz/src/hb-set.h
@@ -121,19 +121,16 @@ hb_set_intersect (hb_set_t       *set,
 HB_EXTERN void
 hb_set_subtract (hb_set_t       *set,
 		 const hb_set_t *other);
 
 HB_EXTERN void
 hb_set_symmetric_difference (hb_set_t       *set,
 			     const hb_set_t *other);
 
-HB_EXTERN void
-hb_set_invert (hb_set_t *set);
-
 HB_EXTERN unsigned int
 hb_set_get_population (const hb_set_t *set);
 
 /* Returns -1 if set empty. */
 HB_EXTERN hb_codepoint_t
 hb_set_get_min (const hb_set_t *set);
 
 /* Returns -1 if set empty. */
--- a/gfx/harfbuzz/src/hb-shape-plan.cc
+++ b/gfx/harfbuzz/src/hb-shape-plan.cc
@@ -110,39 +110,39 @@ hb_shape_plan_t *
 hb_shape_plan_create (hb_face_t                     *face,
 		      const hb_segment_properties_t *props,
 		      const hb_feature_t            *user_features,
 		      unsigned int                   num_user_features,
 		      const char * const            *shaper_list)
 {
   return hb_shape_plan_create2 (face, props,
 				user_features, num_user_features,
-				NULL, 0,
+				nullptr, 0,
 				shaper_list);
 }
 
 hb_shape_plan_t *
 hb_shape_plan_create2 (hb_face_t                     *face,
 		       const hb_segment_properties_t *props,
 		       const hb_feature_t            *user_features,
 		       unsigned int                   num_user_features,
 		       const int                     *orig_coords,
 		       unsigned int                   num_coords,
 		       const char * const            *shaper_list)
 {
-  DEBUG_MSG_FUNC (SHAPE_PLAN, NULL,
+  DEBUG_MSG_FUNC (SHAPE_PLAN, nullptr,
 		  "face=%p num_features=%d num_coords=%d shaper_list=%p",
 		  face,
 		  num_user_features,
 		  num_coords,
 		  shaper_list);
 
   hb_shape_plan_t *shape_plan;
-  hb_feature_t *features = NULL;
-  int *coords = NULL;
+  hb_feature_t *features = nullptr;
+  int *coords = nullptr;
 
   if (unlikely (!face))
     face = hb_face_get_empty ();
   if (unlikely (!props))
     return hb_shape_plan_get_empty ();
   if (num_user_features && !(features = (hb_feature_t *) calloc (num_user_features, sizeof (hb_feature_t))))
     return hb_shape_plan_get_empty ();
   if (num_coords && !(coords = (int *) calloc (num_coords, sizeof (int))))
@@ -191,26 +191,26 @@ hb_shape_plan_create2 (hb_face_t        
  **/
 hb_shape_plan_t *
 hb_shape_plan_get_empty (void)
 {
   static const hb_shape_plan_t _hb_shape_plan_nil = {
     HB_OBJECT_HEADER_STATIC,
 
     true, /* default_shaper_list */
-    NULL, /* face */
+    nullptr, /* face */
     HB_SEGMENT_PROPERTIES_DEFAULT, /* props */
 
-    NULL, /* shaper_func */
-    NULL, /* shaper_name */
+    nullptr, /* shaper_func */
+    nullptr, /* shaper_name */
 
-    NULL, /* user_features */
+    nullptr, /* user_features */
     0,    /* num_user_featurs */
 
-    NULL, /* coords */
+    nullptr, /* coords */
     0,    /* num_coords */
 
     {
 #define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_INVALID,
 #include "hb-shaper-list.hh"
 #undef HB_SHAPER_IMPLEMENT
     }
   };
@@ -465,41 +465,41 @@ hb_shape_plan_t *
 hb_shape_plan_create_cached (hb_face_t                     *face,
 			     const hb_segment_properties_t *props,
 			     const hb_feature_t            *user_features,
 			     unsigned int                   num_user_features,
 			     const char * const            *shaper_list)
 {
   return hb_shape_plan_create_cached2 (face, props,
 				       user_features, num_user_features,
-				       NULL, 0,
+				       nullptr, 0,
 				       shaper_list);
 }
 
 hb_shape_plan_t *
 hb_shape_plan_create_cached2 (hb_face_t                     *face,
 			      const hb_segment_properties_t *props,
 			      const hb_feature_t            *user_features,
 			      unsigned int                   num_user_features,
 			      const int                     *coords,
 			      unsigned int                   num_coords,
 			      const char * const            *shaper_list)
 {
-  DEBUG_MSG_FUNC (SHAPE_PLAN, NULL,
+  DEBUG_MSG_FUNC (SHAPE_PLAN, nullptr,
 		  "face=%p num_features=%d shaper_list=%p",
 		  face,
 		  num_user_features,
 		  shaper_list);
 
   hb_shape_plan_proposal_t proposal = {
     *props,
     shaper_list,
     user_features,
     num_user_features,
-    NULL
+    nullptr
   };
 
   if (shaper_list) {
     /* Choose shaper.  Adapted from hb_shape_plan_plan().
      * Must choose shaper exactly the same way as that function. */
     for (const char * const *shaper_item = shaper_list; *shaper_item; shaper_item++)
       if (0)
 	;
--- a/gfx/harfbuzz/src/hb-shape.cc
+++ b/gfx/harfbuzz/src/hb-shape.cc
@@ -71,27 +71,27 @@ hb_shape_list_shapers (void)
 retry:
   const char **shaper_list = (const char **) hb_atomic_ptr_get (&static_shaper_list);
 
   if (unlikely (!shaper_list))
   {
     /* Not found; allocate one. */
     shaper_list = (const char **) calloc (1 + HB_SHAPERS_COUNT, sizeof (const char *));
     if (unlikely (!shaper_list)) {
-      static const char *nil_shaper_list[] = {NULL};
+      static const char *nil_shaper_list[] = {nullptr};
       return nil_shaper_list;
     }
 
     const hb_shaper_pair_t *shapers = _hb_shapers_get ();
     unsigned int i;
     for (i = 0; i < HB_SHAPERS_COUNT; i++)
       shaper_list[i] = shapers[i].name;
-    shaper_list[i] = NULL;
+    shaper_list[i] = nullptr;
 
-    if (!hb_atomic_ptr_cmpexch (&static_shaper_list, NULL, shaper_list)) {
+    if (!hb_atomic_ptr_cmpexch (&static_shaper_list, nullptr, shaper_list)) {
       free (shaper_list);
       goto retry;
     }
 
 #ifdef HB_USE_ATEXIT
     atexit (free_static_shaper_list); /* First person registers atexit() callback. */
 #endif
   }
@@ -152,10 +152,10 @@ hb_shape_full (hb_font_t          *font,
  * Since: 0.9.2
  **/
 void
 hb_shape (hb_font_t           *font,
 	  hb_buffer_t         *buffer,
 	  const hb_feature_t  *features,
 	  unsigned int         num_features)
 {
-  hb_shape_full (font, buffer, features, num_features, NULL);
+  hb_shape_full (font, buffer, features, num_features, nullptr);
 }
--- a/gfx/harfbuzz/src/hb-shaper-private.hh
+++ b/gfx/harfbuzz/src/hb-shaper-private.hh
@@ -95,30 +95,30 @@ bool \
 HB_SHAPER_DATA_ENSURE_FUNC(shaper, object) (hb_##object##_t *object) \
 {\
   retry: \
   HB_SHAPER_DATA_TYPE (shaper, object) *data = (HB_SHAPER_DATA_TYPE (shaper, object) *) hb_atomic_ptr_get (&HB_SHAPER_DATA (shaper, object)); \
   if (likely (data) && !(condition)) { \
     /* Drop and recreate. */ \
     /* If someone dropped it in the mean time, throw it away and don't touch it. \
      * Otherwise, destruct it. */ \
-    if (hb_atomic_ptr_cmpexch (&HB_SHAPER_DATA (shaper, object), data, NULL)) { \
+    if (hb_atomic_ptr_cmpexch (&HB_SHAPER_DATA (shaper, object), data, nullptr)) { \
       HB_SHAPER_DATA_DESTROY_FUNC (shaper, object) (data); \
     } \
     goto retry; \
   } \
   if (unlikely (!data)) { \
     data = HB_SHAPER_DATA_CREATE_FUNC (shaper, object) (object); \
     if (unlikely (!data)) \
       data = (HB_SHAPER_DATA_TYPE (shaper, object) *) HB_SHAPER_DATA_INVALID; \
-    if (!hb_atomic_ptr_cmpexch (&HB_SHAPER_DATA (shaper, object), NULL, data)) { \
+    if (!hb_atomic_ptr_cmpexch (&HB_SHAPER_DATA (shaper, object), nullptr, data)) { \
       if (data && \
 	  data != HB_SHAPER_DATA_INVALID && \
 	  data != HB_SHAPER_DATA_SUCCEEDED) \
 	HB_SHAPER_DATA_DESTROY_FUNC (shaper, object) (data); \
       goto retry; \
     } \
   } \
-  return data != NULL && !HB_SHAPER_DATA_IS_INVALID (data); \
+  return data != nullptr && !HB_SHAPER_DATA_IS_INVALID (data); \
 }
 
 
 #endif /* HB_SHAPER_PRIVATE_HH */
--- a/gfx/harfbuzz/src/hb-shaper.cc
+++ b/gfx/harfbuzz/src/hb-shaper.cc
@@ -54,24 +54,24 @@ const hb_shaper_pair_t *
 {
 retry:
   hb_shaper_pair_t *shapers = (hb_shaper_pair_t *) hb_atomic_ptr_get (&static_shapers);
 
   if (unlikely (!shapers))
   {
     char *env = getenv ("HB_SHAPER_LIST");
     if (!env || !*env) {
-      (void) hb_atomic_ptr_cmpexch (&static_shapers, NULL, &all_shapers[0]);
+      (void) hb_atomic_ptr_cmpexch (&static_shapers, nullptr, &all_shapers[0]);
       return (const hb_shaper_pair_t *) all_shapers;
     }
 
     /* Not found; allocate one. */
     shapers = (hb_shaper_pair_t *) calloc (1, sizeof (all_shapers));
     if (unlikely (!shapers)) {
-      (void) hb_atomic_ptr_cmpexch (&static_shapers, NULL, &all_shapers[0]);
+      (void) hb_atomic_ptr_cmpexch (&static_shapers, nullptr, &all_shapers[0]);
       return (const hb_shaper_pair_t *) all_shapers;
     }
 
     memcpy (shapers, all_shapers, sizeof (all_shapers));
 
      /* Reorder shaper list to prefer requested shapers. */
     unsigned int i = 0;
     char *end, *p = env;
@@ -92,17 +92,17 @@ retry:
 	}
 
       if (!*end)
 	break;
       else
 	p = end + 1;
     }
 
-    if (!hb_atomic_ptr_cmpexch (&static_shapers, NULL, shapers)) {
+    if (!hb_atomic_ptr_cmpexch (&static_shapers, nullptr, shapers)) {
       free (shapers);
       goto retry;
     }
 
 #ifdef HB_USE_ATEXIT
     atexit (free_static_shapers); /* First person registers atexit() callback. */
 #endif
   }
--- a/gfx/harfbuzz/src/hb-ucdn.cc
+++ b/gfx/harfbuzz/src/hb-ucdn.cc
@@ -233,17 +233,17 @@ hb_ucdn_decompose_compatibility(hb_unico
 
 extern "C" HB_INTERNAL
 hb_unicode_funcs_t *
 hb_ucdn_get_unicode_funcs (void)
 {
   static const hb_unicode_funcs_t _hb_ucdn_unicode_funcs = {
     HB_OBJECT_HEADER_STATIC,
 
-    NULL, /* parent */
+    nullptr, /* parent */
     true, /* immutable */
     {
 #define HB_UNICODE_FUNC_IMPLEMENT(name) hb_ucdn_##name,
       HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS
 #undef HB_UNICODE_FUNC_IMPLEMENT
     }
   };
 
--- a/gfx/harfbuzz/src/hb-unicode-private.hh
+++ b/gfx/harfbuzz/src/hb-unicode-private.hh
@@ -352,20 +352,20 @@ extern HB_INTERNAL const hb_unicode_func
  */
 #define HB_MODIFIED_COMBINING_CLASS_CCC129 129 /* sign aa */
 #define HB_MODIFIED_COMBINING_CLASS_CCC130 132 /* sign i */
 #define HB_MODIFIED_COMBINING_CLASS_CCC132 131 /* sign u */
 
 /* Misc */
 
 #define HB_UNICODE_GENERAL_CATEGORY_IS_MARK(gen_cat) \
-	(FLAG_SAFE (gen_cat) & \
+	(FLAG_UNSAFE (gen_cat) & \
 	 (FLAG (HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK) | \
 	  FLAG (HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK) | \
 	  FLAG (HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)))
 
 #define HB_UNICODE_GENERAL_CATEGORY_IS_NON_ENCLOSING_MARK_OR_MODIFIER_SYMBOL(gen_cat) \
-	(FLAG_SAFE (gen_cat) & \
+	(FLAG_UNSAFE (gen_cat) & \
 	 (FLAG (HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK) | \
 	  FLAG (HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) | \
 	  FLAG (HB_UNICODE_GENERAL_CATEGORY_MODIFIER_SYMBOL)))
 
 #endif /* HB_UNICODE_PRIVATE_HH */
--- a/gfx/harfbuzz/src/hb-unicode.cc
+++ b/gfx/harfbuzz/src/hb-unicode.cc
@@ -183,17 +183,17 @@ hb_unicode_funcs_create (hb_unicode_func
 
   return ufuncs;
 }
 
 
 const hb_unicode_funcs_t _hb_unicode_funcs_nil = {
   HB_OBJECT_HEADER_STATIC,
 
-  NULL, /* parent */
+  nullptr, /* parent */
   true, /* immutable */
   {
 #define HB_UNICODE_FUNC_IMPLEMENT(name) hb_unicode_##name##_nil,
     HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS
 #undef HB_UNICODE_FUNC_IMPLEMENT
   }
 };
 
@@ -360,17 +360,17 @@ hb_unicode_funcs_set_##name##_func (hb_u
 										\
   if (func) {									\
     ufuncs->func.name = func;							\
     ufuncs->user_data.name = user_data;						\
     ufuncs->destroy.name = destroy;						\
   } else {									\
     ufuncs->func.name = ufuncs->parent->func.name;				\
     ufuncs->user_data.name = ufuncs->parent->user_data.name;			\
-    ufuncs->destroy.name = NULL;						\
+    ufuncs->destroy.name = nullptr;						\
   }										\
 }
 
 HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS
 #undef HB_UNICODE_FUNC_IMPLEMENT
 
 
 #define HB_UNICODE_FUNC_IMPLEMENT(return_type, name)				\
--- a/gfx/harfbuzz/src/hb-uniscribe.cc
+++ b/gfx/harfbuzz/src/hb-uniscribe.cc
@@ -197,32 +197,32 @@ hb_ScriptPlaceOpenType(
 struct hb_uniscribe_shaper_funcs_t {
   SIOT ScriptItemizeOpenType;
   SSOT ScriptShapeOpenType;
   SPOT ScriptPlaceOpenType;
 
   inline void init (void)
   {
     HMODULE hinstLib;
-    this->ScriptItemizeOpenType = NULL;
-    this->ScriptShapeOpenType   = NULL;
-    this->ScriptPlaceOpenType   = NULL;
+    this->ScriptItemizeOpenType = nullptr;
+    this->ScriptShapeOpenType   = nullptr;
+    this->ScriptPlaceOpenType   = nullptr;
 
     hinstLib = GetModuleHandle (TEXT ("usp10.dll"));
     if (hinstLib)
     {
       this->ScriptItemizeOpenType = (SIOT) GetProcAddress (hinstLib, "ScriptItemizeOpenType");
       this->ScriptShapeOpenType   = (SSOT) GetProcAddress (hinstLib, "ScriptShapeOpenType");
       this->ScriptPlaceOpenType   = (SPOT) GetProcAddress (hinstLib, "ScriptPlaceOpenType");
     }
     if (!this->ScriptItemizeOpenType ||
 	!this->ScriptShapeOpenType   ||
 	!this->ScriptPlaceOpenType)
     {
-      DEBUG_MSG (UNISCRIBE, NULL, "OpenType versions of functions not found; falling back.");
+      DEBUG_MSG (UNISCRIBE, nullptr, "OpenType versions of functions not found; falling back.");
       this->ScriptItemizeOpenType = hb_ScriptItemizeOpenType;
       this->ScriptShapeOpenType   = hb_ScriptShapeOpenType;
       this->ScriptPlaceOpenType   = hb_ScriptPlaceOpenType;
     }
   }
 };
 static hb_uniscribe_shaper_funcs_t *uniscribe_funcs;
 
@@ -237,21 +237,21 @@ hb_uniscribe_shaper_get_funcs (void)
 {
 retry:
   hb_uniscribe_shaper_funcs_t *funcs = (hb_uniscribe_shaper_funcs_t *) hb_atomic_ptr_get (&uniscribe_funcs);
 
   if (unlikely (!funcs))
   {
     funcs = (hb_uniscribe_shaper_funcs_t *) calloc (1, sizeof (hb_uniscribe_shaper_funcs_t));
     if (unlikely (!funcs))
-      return NULL;
+      return nullptr;
 
     funcs->init ();
 
-    if (!hb_atomic_ptr_cmpexch (&uniscribe_funcs, NULL, funcs)) {
+    if (!hb_atomic_ptr_cmpexch (&uniscribe_funcs, nullptr, funcs)) {
       free (funcs);
       goto retry;
     }
 
 #ifdef HB_USE_ATEXIT
     atexit (free_uniscribe_funcs); /* First person registers atexit() callback. */
 #endif
   }
@@ -311,17 +311,17 @@ struct hb_uniscribe_shaper_face_data_t {
 static void
 _hb_generate_unique_face_name (wchar_t *face_name, unsigned int *plen)
 {
   /* We'll create a private name for the font from a UUID using a simple,
    * somewhat base64-like encoding scheme */
   const char *enc = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-";
   UUID id;
   UuidCreate ((UUID*) &id);
-  ASSERT_STATIC (2 + 3 * (16/2) < LF_FACESIZE);
+  static_assert ((2 + 3 * (16/2) < LF_FACESIZE), "");
   unsigned int name_str_len = 0;
   face_name[name_str_len++] = 'F';
   face_name[name_str_len++] = '_';
   unsigned char *p = (unsigned char *) &id;
   for (unsigned int i = 0; i < 16; i += 2)
   {
     /* Spread the 16 bits from two bytes of the UUID across three chars of face_name,
      * using the bits in groups of 5,5,6 to select chars from enc.
@@ -364,17 +364,17 @@ static hb_blob_t *
                                    name_str_len * 2; /* for name data in UTF16BE form */
   unsigned int name_table_offset = (length + 3) & ~3;
 
   new_length = name_table_offset + ((name_table_length + 3) & ~3);
   void *new_sfnt_data = calloc (1, new_length);
   if (!new_sfnt_data)
   {
     hb_blob_destroy (blob);
-    return NULL;
+    return nullptr;
   }
 
   memcpy(new_sfnt_data, orig_sfnt_data, length);
 
   OT::name &name = OT::StructAtOffset<OT::name> (new_sfnt_data, name_table_offset);
   name.format.set (0);
   name.count.set (ARRAY_LENGTH (name_IDs));
   name.stringOffset.set (name.get_size ());
@@ -412,63 +412,63 @@ static hb_blob_t *
       record.checkSum.set_for_data (&name, name_table_length);
       record.offset.set (name_table_offset);
       record.length.set (name_table_length);
     }
     else if (face_index == 0) /* Fail if first face doesn't have 'name' table. */
     {
       free (new_sfnt_data);
       hb_blob_destroy (blob);
-      return NULL;
+      return nullptr;
     }
   }
 
   /* The checkSumAdjustment field in the 'head' table is now wrong,
    * but that doesn't actually seem to cause any problems so we don't
    * bother. */
 
   hb_blob_destroy (blob);
   return hb_blob_create ((const char *) new_sfnt_data, new_length,
-			 HB_MEMORY_MODE_WRITABLE, NULL, free);
+			 HB_MEMORY_MODE_WRITABLE, nullptr, free);
 }
 
 hb_uniscribe_shaper_face_data_t *
 _hb_uniscribe_shaper_face_data_create (hb_face_t *face)
 {
   hb_uniscribe_shaper_face_data_t *data = (hb_uniscribe_shaper_face_data_t *) calloc (1, sizeof (hb_uniscribe_shaper_face_data_t));
   if (unlikely (!data))
-    return NULL;
+    return nullptr;
 
   data->funcs = hb_uniscribe_shaper_get_funcs ();
   if (unlikely (!data->funcs))
   {
     free (data);
-    return NULL;
+    return nullptr;
   }
 
   hb_blob_t *blob = hb_face_reference_blob (face);
   if (unlikely (!hb_blob_get_length (blob)))
     DEBUG_MSG (UNISCRIBE, face, "Face has empty blob");
 
   blob = _hb_rename_font (blob, data->face_name);
   if (unlikely (!blob))
   {
     free (data);
-    return NULL;
+    return nullptr;
   }
 
   DWORD num_fonts_installed;
-  data->fh = AddFontMemResourceEx ((void *) hb_blob_get_data (blob, NULL),
+  data->fh = AddFontMemResourceEx ((void *) hb_blob_get_data (blob, nullptr),
 				   hb_blob_get_length (blob),
 				   0, &num_fonts_installed);
   if (unlikely (!data->fh))
   {
     DEBUG_MSG (UNISCRIBE, face, "Face AddFontMemResourceEx() failed");
     free (data);
-    return NULL;
+    return nullptr;
   }
 
   return data;
 }
 
 void
 _hb_uniscribe_shaper_face_data_destroy (hb_uniscribe_shaper_face_data_t *data)
 {
@@ -504,80 +504,80 @@ populate_log_font (LOGFONTW  *lf,
   memcpy (lf->lfFaceName, face_data->face_name, sizeof (lf->lfFaceName));
 
   return true;
 }
 
 hb_uniscribe_shaper_font_data_t *
 _hb_uniscribe_shaper_font_data_create (hb_font_t *font)
 {
-  if (unlikely (!hb_uniscribe_shaper_face_data_ensure (font->face))) return NULL;
+  if (unlikely (!hb_uniscribe_shaper_face_data_ensure (font->face))) return nullptr;
 
   hb_uniscribe_shaper_font_data_t *data = (hb_uniscribe_shaper_font_data_t *) calloc (1, sizeof (hb_uniscribe_shaper_font_data_t));
   if (unlikely (!data))
-    return NULL;
+    return nullptr;
 
   int font_size = font->face->get_upem (); /* Default... */
   /* No idea if the following is even a good idea. */
   if (font->y_ppem)
     font_size = font->y_ppem;
 
   if (font_size < 0)
     font_size = -font_size;
   data->x_mult = (double) font->x_scale / font_size;
   data->y_mult = (double) font->y_scale / font_size;
 
-  data->hdc = GetDC (NULL);
+  data->hdc = GetDC (nullptr);
 
   if (unlikely (!populate_log_font (&data->log_font, font, font_size))) {
     DEBUG_MSG (UNISCRIBE, font, "Font populate_log_font() failed");
     _hb_uniscribe_shaper_font_data_destroy (data);
-    return NULL;
+    return nullptr;
   }
 
   data->hfont = CreateFontIndirectW (&data->log_font);
   if (unlikely (!data->hfont)) {
     DEBUG_MSG (UNISCRIBE, font, "Font CreateFontIndirectW() failed");
     _hb_uniscribe_shaper_font_data_destroy (data);
-     return NULL;
+     return nullptr;
   }
 
   if (!SelectObject (data->hdc, data->hfont)) {
     DEBUG_MSG (UNISCRIBE, font, "Font SelectObject() failed");
     _hb_uniscribe_shaper_font_data_destroy (data);
-     return NULL;
+     return nullptr;
   }
 
   return data;
 }
 
 void
 _hb_uniscribe_shaper_font_data_destroy (hb_uniscribe_shaper_font_data_t *data)
 {
   if (data->hdc)
-    ReleaseDC (NULL, data->hdc);
+    ReleaseDC (nullptr, data->hdc);
   if (data->hfont)
     DeleteObject (data->hfont);
   if (data->script_cache)
     ScriptFreeCache (&data->script_cache);
   free (data);
 }
 
 LOGFONTW *
 hb_uniscribe_font_get_logfontw (hb_font_t *font)
 {
-  if (unlikely (!hb_uniscribe_shaper_font_data_ensure (font))) return NULL;
+  if (unlikely (!hb_uniscribe_shaper_font_data_ensure (font))) return nullptr;
   hb_uniscribe_shaper_font_data_t *font_data =  HB_SHAPER_DATA_GET (font);
   return &font_data->log_font;
 }
 
 HFONT
 hb_uniscribe_font_get_hfont (hb_font_t *font)
 {
-  if (unlikely (!hb_uniscribe_shaper_font_data_ensure (font))) return NULL;
+  if (unlikely (!hb_uniscribe_shaper_font_data_ensure (font))) return nullptr;
   hb_uniscribe_shaper_font_data_t *font_data =  HB_SHAPER_DATA_GET (font);
   return font_data->hfont;
 }
 
 
 /*
  * shaper shape_plan data
  */
@@ -733,17 +733,17 @@ hb_bool_t
   else
   {
   fail_features:
     num_features = 0;
   }
 
 #define FAIL(...) \
   HB_STMT_START { \
-    DEBUG_MSG (UNISCRIBE, NULL, __VA_ARGS__); \
+    DEBUG_MSG (UNISCRIBE, nullptr, __VA_ARGS__); \
     return false; \
   } HB_STMT_END;
 
   HRESULT hr;
 
 retry:
 
   unsigned int scratch_size;
@@ -955,17 +955,17 @@ retry:
 				     char_props + chars_offset,
 				     item_chars_len,
 				     glyphs + glyphs_offset,
 				     glyph_props + glyphs_offset,
 				     glyphs_len,
 				     /* out */
 				     advances + glyphs_offset,
 				     offsets + glyphs_offset,
-				     NULL);
+				     nullptr);
     if (unlikely (FAILED (hr)))
       FAIL ("ScriptPlaceOpenType() failed: 0x%08xL", hr);
 
     if (DEBUG_ENABLED (UNISCRIBE))
       fprintf (stderr, "Item %d RTL %d LayoutRTL %d LogicalOrder %d ScriptTag %c%c%c%c\n",
 	       i,
 	       items[i].a.fRTL,
 	       items[i].a.fLayoutRTL,
--- 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 6
-#define HB_VERSION_MICRO 0
+#define HB_VERSION_MICRO 3
 
-#define HB_VERSION_STRING "1.6.0"
+#define HB_VERSION_STRING "1.6.3"
 
 #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
@@ -42,21 +42,21 @@ using namespace OT;
 int
 main (int argc, char **argv)
 {
   if (argc != 2) {
     fprintf (stderr, "usage: %s font-file.ttf\n", argv[0]);
     exit (1);
   }
 
-  const char *font_data = NULL;
+  const char *font_data = nullptr;
   int len = 0;
 
 #ifdef HAVE_GLIB
-  GMappedFile *mf = g_mapped_file_new (argv[1], false, NULL);
+  GMappedFile *mf = g_mapped_file_new (argv[1], false, nullptr);
   font_data = g_mapped_file_get_contents (mf);
   len = g_mapped_file_get_length (mf);
 #else
   FILE *f = fopen (argv[1], "rb");
   fseek (f, 0, SEEK_END);
   len = ftell (f);
   fseek (f, 0, SEEK_SET);
   font_data = (const char *) malloc (len);
--- a/gfx/harfbuzz/src/test-buffer-serialize.cc
+++ b/gfx/harfbuzz/src/test-buffer-serialize.cc
@@ -40,33 +40,33 @@
 # endif
 #endif
 #include <stdlib.h>
 #include <stdio.h>
 
 int
 main (int argc, char **argv)
 {
-  hb_blob_t *blob = NULL;
+  hb_blob_t *blob = nullptr;
 
   if (argc != 2) {
     fprintf (stderr, "usage: %s font-file\n", argv[0]);
     exit (1);
   }
 
   /* Create the blob */
   {
     const char *font_data;
     unsigned int len;
     hb_destroy_func_t destroy;
     void *user_data;
     hb_memory_mode_t mm;
 
 #ifdef HAVE_GLIB
-    GMappedFile *mf = g_mapped_file_new (argv[1], false, NULL);
+    GMappedFile *mf = g_mapped_file_new (argv[1], false, nullptr);
     font_data = g_mapped_file_get_contents (mf);
     len = g_mapped_file_get_length (mf);
     destroy = (hb_destroy_func_t) g_mapped_file_unref;
     user_data = (void *) mf;
     mm = HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE;
 #else
     FILE *f = fopen (argv[1], "rb");
     fseek (f, 0, SEEK_END);
@@ -81,17 +81,17 @@ main (int argc, char **argv)
     mm = HB_MEMORY_MODE_WRITABLE;
 #endif
 
     blob = hb_blob_create (font_data, len, mm, user_data, destroy);
   }
 
   hb_face_t *face = hb_face_create (blob, 0 /* first face */);
   hb_blob_destroy (blob);
-  blob = NULL;
+  blob = nullptr;
 
   unsigned int upem = hb_face_get_upem (face);
   hb_font_t *font = hb_font_create (face);
   hb_face_destroy (face);
   hb_font_set_scale (font, upem, upem);
 #ifdef HAVE_FREETYPE
   hb_ft_font_set_funcs (font);
 #endif
@@ -110,17 +110,17 @@ main (int argc, char **argv)
 					 p, -1, &p,
 					 font,
 					 HB_BUFFER_SERIALIZE_FORMAT_JSON))
       ;
     if (*p && *p != '\n')
       ret = false;
 
     hb_buffer_serialize_glyphs (buf, 0, hb_buffer_get_length (buf),
-				out, sizeof (out), NULL,
+				out, sizeof (out), nullptr,
 				font, HB_BUFFER_SERIALIZE_FORMAT_JSON,
 				HB_BUFFER_SERIALIZE_FLAG_DEFAULT);
     puts (out);
   }
 
   hb_buffer_destroy (buf);
 
   hb_font_destroy (font);
--- a/gfx/harfbuzz/src/test-size-params.cc
+++ b/gfx/harfbuzz/src/test-size-params.cc
@@ -38,33 +38,33 @@
 # endif
 #endif
 #include <stdlib.h>
 #include <stdio.h>
 
 int
 main (int argc, char **argv)
 {
-  hb_blob_t *blob = NULL;
+  hb_blob_t *blob = nullptr;
 
   if (argc != 2) {
     fprintf (stderr, "usage: %s font-file\n", argv[0]);
     exit (1);
   }
 
   /* Create the blob */
   {
     const char *font_data;
     unsigned int len;
     hb_destroy_func_t destroy;
     void *user_data;
     hb_memory_mode_t mm;
 
 #ifdef HAVE_GLIB
-    GMappedFile *mf = g_mapped_file_new (argv[1], false, NULL);
+    GMappedFile *mf = g_mapped_file_new (argv[1], false, nullptr);
     font_data = g_mapped_file_get_contents (mf);
     len = g_mapped_file_get_length (mf);
     destroy = (hb_destroy_func_t) g_mapped_file_unref;
     user_data = (void *) mf;
     mm = HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE;
 #else
     FILE *f = fopen (argv[1], "rb");
     fseek (f, 0, SEEK_END);
@@ -80,17 +80,17 @@ main (int argc, char **argv)
 #endif
 
     blob = hb_blob_create (font_data, len, mm, user_data, destroy);
   }
 
   /* Create the face */
   hb_face_t *face = hb_face_create (blob, 0 /* first face */);
   hb_blob_destroy (blob);
-  blob = NULL;
+  blob = nullptr;
 
   unsigned int p[5];
   bool ret = hb_ot_layout_get_size_params (face, p, p+1, p+2, p+3, p+4);
 
   printf ("%g %u %u %g %g\n", p[0]/10., p[1], p[2], p[3]/10., p[4]/10.);
 
   return !ret;
 }
--- a/gfx/harfbuzz/src/test-would-substitute.cc
+++ b/gfx/harfbuzz/src/test-would-substitute.cc
@@ -42,33 +42,33 @@
 
 #ifdef HAVE_FREETYPE
 #include "hb-ft.h"
 #endif
 
 int
 main (int argc, char **argv)
 {
-  hb_blob_t *blob = NULL;
+  hb_blob_t *blob = nullptr;
 
   if (argc != 4 && argc != 5) {
     fprintf (stderr, "usage: %s font-file lookup-index first-glyph [second-glyph]\n", argv[0]);
     exit (1);
   }
 
   /* Create the blob */
   {
     const char *font_data;
     unsigned int len;
     hb_destroy_func_t destroy;
     void *user_data;
     hb_memory_mode_t mm;
 
 #ifdef HAVE_GLIB
-    GMappedFile *mf = g_mapped_file_new (argv[1], false, NULL);
+    GMappedFile *mf = g_mapped_file_new (argv[1], false, nullptr);
     font_data = g_mapped_file_get_contents (mf);
     len = g_mapped_file_get_length (mf);
     destroy = (hb_destroy_func_t) g_mapped_file_unref;
     user_data = (void *) mf;
     mm = HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE;
 #else
     FILE *f = fopen (argv[1], "rb");
     fseek (f, 0, SEEK_END);
@@ -84,23 +84,23 @@ main (int argc, char **argv)
 #endif
 
     blob = hb_blob_create (font_data, len, mm, user_data, destroy);
   }
 
   /* Create the face */
   hb_face_t *face = hb_face_create (blob, 0 /* first face */);
   hb_blob_destroy (blob);
-  blob = NULL;
+  blob = nullptr;
 
   hb_font_t *font = hb_font_create (face);
 #ifdef HAVE_FREETYPE
   hb_ft_font_set_funcs (font);
 #endif
 
   unsigned int len = argc - 3;
   hb_codepoint_t glyphs[2];
   if (!hb_font_glyph_from_string (font, argv[3], -1, &glyphs[0]) ||
       (argc > 4 &&
        !hb_font_glyph_from_string (font, argv[4], -1, &glyphs[1])))
     return 2;
-  return !hb_ot_layout_lookup_would_substitute (face, strtol (argv[2], NULL, 0), glyphs, len, false);
+  return !hb_ot_layout_lookup_would_substitute (face, strtol (argv[2], nullptr, 0), glyphs, len, false);
 }
--- a/gfx/harfbuzz/src/test.cc
+++ b/gfx/harfbuzz/src/test.cc
@@ -41,33 +41,33 @@
 
 #ifdef HAVE_FREETYPE
 #include "hb-ft.h"
 #endif
 
 int
 main (int argc, char **argv)
 {
-  hb_blob_t *blob = NULL;
+  hb_blob_t *blob = nullptr;
 
   if (argc != 2) {
     fprintf (stderr, "usage: %s font-file.ttf\n", argv[0]);
     exit (1);
   }
 
   /* Create the blob */
   {
     const char *font_data;
     unsigned int len;
     hb_destroy_func_t destroy;
     void *user_data;
     hb_memory_mode_t mm;
 
 #ifdef HAVE_GLIB
-    GMappedFile *mf = g_mapped_file_new (argv[1], false, NULL);
+    GMappedFile *mf = g_mapped_file_new (argv[1], false, nullptr);
     font_data = g_mapped_file_get_contents (mf);
     len = g_mapped_file_get_length (mf);
     destroy = (hb_destroy_func_t) g_mapped_file_unref;
     user_data = (void *) mf;
     mm = HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE;
 #else
     FILE *f = fopen (argv[1], "rb");
     fseek (f, 0, SEEK_END);
@@ -85,36 +85,36 @@ main (int argc, char **argv)
     blob = hb_blob_create (font_data, len, mm, user_data, destroy);
   }
 
   printf ("Opened font file %s: %u bytes long\n", argv[1], hb_blob_get_length (blob));
 
   /* Create the face */
   hb_face_t *face = hb_face_create (blob, 0 /* first face */);
   hb_blob_destroy (blob);
-  blob = NULL;
+  blob = nullptr;
   unsigned int upem = hb_face_get_upem (face);
 
   hb_font_t *font = hb_font_create (face);
   hb_font_set_scale (font, upem, upem);
 
 #ifdef HAVE_FREETYPE
   hb_ft_font_set_funcs (font);
 #endif
 
   hb_buffer_t *buffer = hb_buffer_create ();
 
   hb_buffer_add_utf8 (buffer, "\xe0\xa4\x95\xe0\xa5\x8d\xe0\xa4\xb0\xe0\xa5\x8d\xe0\xa4\x95", -1, 0, -1);
   hb_buffer_guess_segment_properties (buffer);
 
-  hb_shape (font, buffer, NULL, 0);
+  hb_shape (font, buffer, nullptr, 0);
 
   unsigned int count = hb_buffer_get_length (buffer);
-  hb_glyph_info_t *infos = hb_buffer_get_glyph_infos (buffer, NULL);
-  hb_glyph_position_t *positions = hb_buffer_get_glyph_positions (buffer, NULL);
+  hb_glyph_info_t *infos = hb_buffer_get_glyph_infos (buffer, nullptr);
+  hb_glyph_position_t *positions = hb_buffer_get_glyph_positions (buffer, nullptr);
 
   for (unsigned int i = 0; i < count; i++)
   {
     hb_glyph_info_t *info = &infos[i];
     hb_glyph_position_t *pos = &positions[i];
 
     printf ("cluster %d	glyph 0x%x at	(%d,%d)+(%d,%d)\n",
 	    info->cluster,
--- a/gfx/thebes/gfxFont.cpp
+++ b/gfx/thebes/gfxFont.cpp
@@ -1858,27 +1858,27 @@ private:
 };
 
 // Bug 674909. When synthetic bolding text by drawing twice, need to
 // render using a pixel offset in device pixels, otherwise text
 // doesn't appear bolded, it appears as if a bad text shadow exists
 // when a non-identity transform exists.  Use an offset factor so that
 // the second draw occurs at a constant offset in device pixels.
 
-double
+gfx::Float
 gfxFont::CalcXScale(DrawTarget* aDrawTarget)
 {
     // determine magnitude of a 1px x offset in device space
     Size t = aDrawTarget->GetTransform().TransformSize(Size(1.0, 0.0));
     if (t.width == 1.0 && t.height == 0.0) {
         // short-circuit the most common case to avoid sqrt() and division
         return 1.0;
     }
 
-    double m = sqrt(t.width * t.width + t.height * t.height);
+    gfx::Float m = sqrtf(t.width * t.width + t.height * t.height);
 
     NS_ASSERTION(m != 0.0, "degenerate transform while synthetic bolding");
     if (m == 0.0) {
         return 0.0; // effectively disables offset
     }
 
     // scale factor so that offsets are 1px in device pixels
     return 1.0 / m;
@@ -2211,17 +2211,17 @@ gfxFont::Draw(const gfxTextRun *aTextRun
             new SimpleTextContextPaint(fillPattern, nullptr,
                                        aRunParams.context->CurrentMatrix());
         fontParams.contextPaint = contextPaint.get();
     }
 
     // Synthetic-bold strikes are each offset one device pixel in run direction.
     // (these values are only needed if IsSyntheticBold() is true)
     if (IsSyntheticBold()) {
-        double xscale = CalcXScale(aRunParams.context->GetDrawTarget());
+        gfx::Float xscale = CalcXScale(aRunParams.context->GetDrawTarget());
         fontParams.synBoldOnePixelOffset = aRunParams.direction * xscale;
         if (xscale != 0.0) {
             // use as many strikes as needed for the the increased advance
             fontParams.extraStrikes =
                 std::max(1, NS_lroundf(GetSyntheticBoldOffset() / xscale));
 
             if (textDrawer) {
                 textDrawer->FoundUnsupportedFeature();
--- a/gfx/thebes/gfxFont.h
+++ b/gfx/thebes/gfxFont.h
@@ -2279,34 +2279,34 @@ protected:
 
     // Bug 674909. When synthetic bolding text by drawing twice, need to
     // render using a pixel offset in device pixels, otherwise text
     // doesn't appear bolded, it appears as if a bad text shadow exists
     // when a non-identity transform exists.  Use an offset factor so that
     // the second draw occurs at a constant offset in device pixels.
     // This helper calculates the scale factor we need to apply to the
     // synthetic-bold offset.
-    static double CalcXScale(DrawTarget* aDrawTarget);
+    static mozilla::gfx::Float CalcXScale(DrawTarget* aDrawTarget);
 };
 
 // proportion of ascent used for x-height, if unable to read value from font
 #define DEFAULT_XHEIGHT_FACTOR 0.56f
 
 // Parameters passed to gfxFont methods for drawing glyphs from a textrun.
 // The TextRunDrawParams are set up once per textrun; the FontDrawParams
 // are dependent on the specific font, so they are set per GlyphRun.
 
 struct MOZ_STACK_CLASS TextRunDrawParams {
     RefPtr<mozilla::gfx::DrawTarget> dt;
     gfxContext              *context;
     gfxFont::Spacing        *spacing;
     gfxTextRunDrawCallbacks *callbacks;
     mozilla::SVGContextPaint *runContextPaint;
     mozilla::gfx::Color      fontSmoothingBGColor;
-    gfxFloat                 direction;
+    mozilla::gfx::Float      direction;
     double                   devPerApp;
     nscolor                  textStrokeColor;
     gfxPattern              *textStrokePattern;
     const mozilla::gfx::StrokeOptions *strokeOpts;
     const mozilla::gfx::DrawOptions   *drawOpts;
     DrawMode                 drawMode;
     bool                     isVerticalRun;
     bool                     isRTL;
@@ -2314,17 +2314,17 @@ struct MOZ_STACK_CLASS TextRunDrawParams
 };
 
 struct MOZ_STACK_CLASS FontDrawParams {
     RefPtr<mozilla::gfx::ScaledFont>            scaledFont;
     RefPtr<mozilla::gfx::GlyphRenderingOptions> renderingOptions;
     mozilla::SVGContextPaint *contextPaint;
     mozilla::gfx::Matrix     *passedInvMatrix;
     mozilla::gfx::Matrix      matInv;
-    double                    synBoldOnePixelOffset;
+    mozilla::gfx::Float       synBoldOnePixelOffset;
     int32_t                   extraStrikes;
     mozilla::gfx::DrawOptions drawOptions;
     bool                      isVerticalFont;
     bool                      haveSVGGlyphs;
     bool                      haveColorGlyphs;
 };
 
 struct MOZ_STACK_CLASS EmphasisMarkDrawParams {
--- a/gfx/thebes/gfxHarfBuzzShaper.cpp
+++ b/gfx/thebes/gfxHarfBuzzShaper.cpp
@@ -416,27 +416,24 @@ hb_bool_t
 gfxHarfBuzzShaper::HBGetGlyphVOrigin(hb_font_t *font, void *font_data,
                                      hb_codepoint_t glyph,
                                      hb_position_t *x, hb_position_t *y,
                                      void *user_data)
 {
     const gfxHarfBuzzShaper::FontCallbackData *fcd =
         static_cast<const gfxHarfBuzzShaper::FontCallbackData*>(font_data);
     fcd->mShaper->GetGlyphVOrigin(glyph, x, y);
-    // Negate the value we computed from font data (see comment re coordinate
-    // system orientation in HBGetGlyphVAdvance).
-    *y = -*y;
     return true;
 }
 
 void
 gfxHarfBuzzShaper::GetGlyphVOrigin(hb_codepoint_t aGlyph,
                                    hb_position_t *aX, hb_position_t *aY) const
 {
-    *aX = -0.5 * GetGlyphHAdvance(aGlyph);
+    *aX = 0.5 * GetGlyphHAdvance(aGlyph);
 
     if (mVORGTable) {
         // We checked in Initialize() that the VORG table is safely readable,
         // so no length/bounds-check needed here.
         const VORG* vorg =
             reinterpret_cast<const VORG*>(hb_blob_get_data(mVORGTable, nullptr));
 
         const VORGrec *lo = reinterpret_cast<const VORGrec*>(vorg + 1);
@@ -447,21 +444,21 @@ gfxHarfBuzzShaper::GetGlyphVOrigin(hb_co
             if (uint16_t(mid->glyphIndex) < aGlyph) {
                 lo = mid + 1;
             } else {
                 hi = mid;
             }
         }
 
         if (lo < limit && uint16_t(lo->glyphIndex) == aGlyph) {
-            *aY = -FloatToFixed(GetFont()->FUnitsToDevUnitsFactor() *
-                                int16_t(lo->vertOriginY));
+            *aY = FloatToFixed(GetFont()->FUnitsToDevUnitsFactor() *
+                               int16_t(lo->vertOriginY));
         } else {
-            *aY = -FloatToFixed(GetFont()->FUnitsToDevUnitsFactor() *
-                                int16_t(vorg->defaultVertOriginY));
+            *aY = FloatToFixed(GetFont()->FUnitsToDevUnitsFactor() *
+                               int16_t(vorg->defaultVertOriginY));
         }
         return;
     }
 
     if (mVmtxTable) {
         bool emptyGlyf;
         const Glyf *glyf = FindGlyf(aGlyph, &emptyGlyf);
         if (glyf) {
@@ -479,18 +476,18 @@ gfxHarfBuzzShaper::GetGlyphVOrigin(hb_co
                 lsb = int16_t(metrics->metrics[aGlyph].lsb);
             } else {
                 // Glyph is covered by the second (sidebearing-only) array
                 const AutoSwap_PRInt16* sidebearings =
                     reinterpret_cast<const AutoSwap_PRInt16*>
                         (&metrics->metrics[mNumLongVMetrics]);
                 lsb = int16_t(sidebearings[aGlyph - mNumLongVMetrics]);
             }
-            *aY = -FloatToFixed(mFont->FUnitsToDevUnitsFactor() *
-                                (lsb + int16_t(glyf->yMax)));
+            *aY = FloatToFixed(mFont->FUnitsToDevUnitsFactor() *
+                               (lsb + int16_t(glyf->yMax)));
             return;
         } else {
             // XXX TODO: not a truetype font; need to get glyph extents
             // via some other API?
             // For now, fall through to default code below.
         }
     }
 
@@ -503,23 +500,23 @@ gfxHarfBuzzShaper::GetGlyphVOrigin(hb_co
         const MetricsHeader* hhea =
             reinterpret_cast<const MetricsHeader*>(hb_blob_get_data(hheaTable,
                                                                     &len));
         if (len >= sizeof(MetricsHeader)) {
             // divide up the default advance we're using (1em) in proportion
             // to ascender:descender from the hhea table
             int16_t a = int16_t(hhea->ascender);
             int16_t d = int16_t(hhea->descender);
-            *aY = -FloatToFixed(GetFont()->GetAdjustedSize() * a / (a - d));
+            *aY = FloatToFixed(GetFont()->GetAdjustedSize() * a / (a - d));
             return;
         }
     }
 
     NS_NOTREACHED("we shouldn't be here!");
-    *aY = -FloatToFixed(GetFont()->GetAdjustedSize() / 2);
+    *aY = FloatToFixed(GetFont()->GetAdjustedSize() / 2);
 }
 
 static hb_bool_t
 HBGetGlyphExtents(hb_font_t *font, void *font_data,
                   hb_codepoint_t glyph,
                   hb_glyph_extents_t *extents,
                   void *user_data)
 {
@@ -1688,21 +1685,22 @@ gfxHarfBuzzShaper::SetGlyphsFromRun(gfxS
         }
 
         // HarfBuzz gives us physical x- and y-coordinates, but we will store
         // them as logical inline- and block-direction values in the textrun.
 
         hb_position_t i_offset, i_advance; // inline-direction offset/advance
         hb_position_t b_offset, b_advance; // block-direction offset/advance
         if (aVertical) {
-            // our inline coordinate direction is the opposite of harfbuzz's
+            // our coordinate directions are the opposite of harfbuzz's
+            // when doing top-to-bottom shaping
             i_offset = -posInfo[glyphStart].y_offset;
             i_advance = -posInfo[glyphStart].y_advance;
-            b_offset = posInfo[glyphStart].x_offset;
-            b_advance = posInfo[glyphStart].x_advance;
+            b_offset = -posInfo[glyphStart].x_offset;
+            b_advance = -posInfo[glyphStart].x_advance;
         } else {
             i_offset = posInfo[glyphStart].x_offset;
             i_advance = posInfo[glyphStart].x_advance;
             b_offset = posInfo[glyphStart].y_offset;
             b_advance = posInfo[glyphStart].y_advance;
         }
 
         nscoord iOffset, advance;
@@ -1728,24 +1726,16 @@ gfxHarfBuzzShaper::SetGlyphsFromRun(gfxS
         {
             charGlyphs[baseCharIndex].SetSimpleGlyph(advance,
                                                      ginfo[glyphStart].codepoint);
         } else {
             // Collect all glyphs in a list to be assigned to the first char;
             // there must be at least one in the clump, and we already measured
             // its advance, hence the placement of the loop-exit test and the
             // measurement of the next glyph.
-            // For vertical orientation, we add a "base offset" to compensate
-            // for the positioning within the cluster being based on horizontal
-            // glyph origin/offset.
-            hb_position_t baseIOffset, baseBOffset;
-            if (aVertical) {
-                baseIOffset = 2 * (i_offset - i_advance);
-                baseBOffset = GetGlyphHAdvance(ginfo[glyphStart].codepoint);
-            }
             while (1) {
                 gfxTextRun::DetailedGlyph* details =
                     detailedGlyphs.AppendElement();
                 details->mGlyphID = ginfo[glyphStart].codepoint;
 
                 details->mXOffset = iOffset;
                 details->mAdvance = advance;
 
@@ -1758,21 +1748,20 @@ gfxHarfBuzzShaper::SetGlyphsFromRun(gfxS
                         roundB ? appUnitsPerDevUnit * FixedToIntRound(b_advance)
                         : floor(hb2appUnits * b_advance + 0.5);
                 }
                 if (++glyphStart >= glyphEnd) {
                     break;
                 }
 
                 if (aVertical) {
-                    // our inline coordinate direction is the opposite of HB's
-                    i_offset = baseIOffset + posInfo[glyphStart].y_offset;
+                    i_offset = -posInfo[glyphStart].y_offset;
                     i_advance = -posInfo[glyphStart].y_advance;
-                    b_offset = baseBOffset - posInfo[glyphStart].x_offset;
-                    b_advance = posInfo[glyphStart].x_advance;
+                    b_offset = -posInfo[glyphStart].x_offset;
+                    b_advance = -posInfo[glyphStart].x_advance;
                 } else {
                     i_offset = posInfo[glyphStart].x_offset;
                     i_advance = posInfo[glyphStart].x_advance;
                     b_offset = posInfo[glyphStart].y_offset;
                     b_advance = posInfo[glyphStart].y_advance;
                 }
 
                 if (roundI) {
deleted file mode 100644
--- a/ipc/dbus/DBusConnectionDelete.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
-/* vim: set ts=2 et sw=2 tw=80: */
-/* 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/. */
-
-#ifndef mozilla_ipc_DBusConnectionDelete_h
-#define mozilla_ipc_DBusConnectionDelete_h
-
-#include <dbus/dbus.h>
-#include "mozilla/UniquePtr.h"
-
-namespace mozilla {
-
-/*
- * |DBusConnectionDelete| is a deleter for managing instances
- * of |DBusConnection| in |UniquePtr|. Upon destruction, it
- * will close an open connection before unref'ing the data
- * structure.
- *
- * Do not use |UniquePtr| with shared DBus connections. For
- * shared connections, use |RefPtr|.
- */
-class DBusConnectionDelete
-{
-public:
-  constexpr DBusConnectionDelete()
-  { }
-
-  void operator()(DBusConnection* aConnection) const
-  {
-    MOZ_ASSERT(aConnection);
-    if (dbus_connection_get_is_connected(aConnection)) {
-      dbus_connection_close(aConnection);
-    }
-    dbus_connection_unref(aConnection);
-  }
-};
-
-} // namespace mozilla
-
-#endif // mozilla_ipc_DBusConnectionDelete_h
deleted file mode 100644
--- a/ipc/dbus/DBusHelpers.cpp
+++ /dev/null
@@ -1,241 +0,0 @@
-/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
-/* vim: set ts=2 et sw=2 tw=80: */
-/* 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/. */
-
-#include "DBusHelpers.h"
-#include "mozilla/ipc/DBusMessageRefPtr.h"
-#include "mozilla/ipc/DBusPendingCallRefPtr.h"
-#include "mozilla/ipc/DBusWatcher.h"
-#include "mozilla/RefPtr.h"
-#include "mozilla/UniquePtr.h"
-#include "mozilla/Unused.h"
-#include "nsThreadUtils.h"
-
-#undef CHROMIUM_LOG
-#define CHROMIUM_LOG(args...)  printf(args);
-
-namespace mozilla {
-namespace ipc {
-
-//
-// DBus I/O
-//
-
-namespace {
-
-class Notification final
-{
-public:
-  Notification(DBusReplyCallback aCallback, void* aData)
-    : mCallback(aCallback)
-    , mData(aData)
-  { }
-
-  // Callback function for DBus replies. Only run it on I/O thread.
-  //
-  static void Handle(DBusPendingCall* aCall, void* aData)
-  {
-    MOZ_ASSERT(!NS_IsMainThread());
-
-    RefPtr<DBusPendingCall> call = already_AddRefed<DBusPendingCall>(aCall);
-
-    UniquePtr<Notification> ntfn(static_cast<Notification*>(aData));
-
-    RefPtr<DBusMessage> reply = already_AddRefed<DBusMessage>(
-      dbus_pending_call_steal_reply(call));
-
-    // The reply can be null if the timeout has been reached.
-    if (reply) {
-      ntfn->RunCallback(reply);
-    }
-
-    dbus_pending_call_cancel(call);
-  }
-
-private:
-  void RunCallback(DBusMessage* aMessage)
-  {
-    if (mCallback) {
-      mCallback(aMessage, mData);
-    }
-  }
-
-  DBusReplyCallback mCallback;
-  void*             mData;
-};
-
-static already_AddRefed<DBusMessage>
-BuildDBusMessage(const char* aDestination,
-                 const char* aPath,
-                 const char* aIntf,
-                 const char* aFunc,
-                 int aFirstArgType,
-                 va_list aArgs)
-{
-  RefPtr<DBusMessage> msg = already_AddRefed<DBusMessage>(
-    dbus_message_new_method_call(aDestination, aPath, aIntf, aFunc));
-
-  if (!msg) {
-    CHROMIUM_LOG("dbus_message_new_method_call failed");
-    return nullptr;
-  }
-
-  auto success = dbus_message_append_args_valist(msg, aFirstArgType, aArgs);
-
-  if (!success) {
-    CHROMIUM_LOG("dbus_message_append_args_valist failed");
-    return nullptr;
-  }
-
-  return msg.forget();
-}
-
-} // anonymous namespace
-
-nsresult
-DBusWatchConnection(DBusConnection* aConnection)
-{
-  MOZ_ASSERT(!NS_IsMainThread());
-  MOZ_ASSERT(aConnection);
-
-  auto success =
-    dbus_connection_set_watch_functions(aConnection,
-                                        DBusWatcher::AddWatchFunction,
-                                        DBusWatcher::RemoveWatchFunction,
-                                        DBusWatcher::ToggleWatchFunction,
-                                        aConnection, nullptr);
-  if (!success) {
-    CHROMIUM_LOG("dbus_connection_set_watch_functions failed");
-    return NS_ERROR_FAILURE;
-  }
-
-  return NS_OK;
-}
-
-void
-DBusUnwatchConnection(DBusConnection* aConnection)
-{
-  MOZ_ASSERT(!NS_IsMainThread());
-  MOZ_ASSERT(aConnection);
-
-  auto success = dbus_connection_set_watch_functions(aConnection,
-                                                     nullptr, nullptr, nullptr,
-                                                     nullptr, nullptr);
-  if (!success) {
-    CHROMIUM_LOG("dbus_connection_set_watch_functions failed");
-  }
-}
-
-nsresult
-DBusSendMessage(DBusConnection* aConnection, DBusMessage* aMessage)
-{
-  MOZ_ASSERT(!NS_IsMainThread());
-  MOZ_ASSERT(aConnection);
-  MOZ_ASSERT(aMessage);
-
-  auto success = dbus_connection_send(aConnection, aMessage, nullptr);
-
-  if (!success) {
-    CHROMIUM_LOG("dbus_connection_send failed");
-    return NS_ERROR_FAILURE;
-  }
-
-  return NS_OK;
-}
-
-nsresult
-DBusSendMessageWithReply(DBusConnection* aConnection,
-                         DBusReplyCallback aCallback, void* aData,
-                         int aTimeout,
-                         DBusMessage* aMessage)
-{
-  MOZ_ASSERT(!NS_IsMainThread());
-  MOZ_ASSERT(aConnection);
-  MOZ_ASSERT(aMessage);
-
-  UniquePtr<Notification> ntfn = MakeUnique<Notification>(aCallback, aData);
-
-  auto call = static_cast<DBusPendingCall*>(nullptr);
-
-  auto success = dbus_connection_send_with_reply(aConnection,
-                                                 aMessage,
-                                                 &call,
-                                                 aTimeout);
-  if (!success) {
-    CHROMIUM_LOG("dbus_connection_send_with_reply failed");
-    return NS_ERROR_FAILURE;
-  }
-
-  success = dbus_pending_call_set_notify(call, Notification::Handle,
-                                         ntfn.get(), nullptr);
-  if (!success) {
-    CHROMIUM_LOG("dbus_pending_call_set_notify failed");
-    return NS_ERROR_FAILURE;
-  }
-
-  Unused << ntfn.release(); // Picked up in |Notification::Handle|
-
-  return NS_OK;
-}
-
-nsresult
-DBusSendMessageWithReply(DBusConnection* aConnection,
-                         DBusReplyCallback aCallback,
-                         void* aData,
-                         int aTimeout,
-                         const char* aDestination,
-                         const char* aPath,
-                         const char* aIntf,
-                         const char* aFunc,
-                         int aFirstArgType,
-                         va_list aArgs)
-{
-  MOZ_ASSERT(!NS_IsMainThread());
-  MOZ_ASSERT(aConnection);
-
-  RefPtr<DBusMessage> msg =
-    BuildDBusMessage(aDestination, aPath, aIntf, aFunc, aFirstArgType, aArgs);
-
-  if (!msg) {
-    return NS_ERROR_FAILURE;
-  }
-
-  return DBusSendMessageWithReply(aConnection, aCallback, aData, aTimeout, msg);
-}
-
-nsresult
-DBusSendMessageWithReply(DBusConnection* aConnection,
-                         DBusReplyCallback aCallback,
-                         void* aData,
-                         int aTimeout,
-                         const char* aDestination,
-                         const char* aPath,
-                         const char* aIntf,
-                         const char* aFunc,
-                         int aFirstArgType,
-                         ...)
-{
-  MOZ_ASSERT(!NS_IsMainThread());
-  MOZ_ASSERT(aConnection);
-
-  va_list args;
-  va_start(args, aFirstArgType);
-
-  auto rv = DBusSendMessageWithReply(aConnection,
-                                     aCallback, aData,
-                                     aTimeout,
-                                     aDestination, aPath, aIntf, aFunc,
-                                     aFirstArgType, args);
-  va_end(args);
-
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
-
-  return NS_OK;
-}
-
-}
-}
deleted file mode 100644
--- a/ipc/dbus/DBusHelpers.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
-/* vim: set ts=2 et sw=2 tw=80: */
-/* 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/. */
-
-#ifndef mozilla_ipc_DBusHelpers_h
-#define mozilla_ipc_DBusHelpers_h
-
-#include <dbus/dbus.h>
-#include <stdarg.h>
-#include "nsError.h"
-
-namespace mozilla {
-namespace ipc {
-
-//
-// DBus I/O
-//
-
-typedef void (*DBusReplyCallback)(DBusMessage*, void*);
-
-nsresult
-DBusWatchConnection(DBusConnection* aConnection);
-
-void
-DBusUnwatchConnection(DBusConnection* aConnection);
-
-nsresult
-DBusSendMessage(DBusConnection* aConnection, DBusMessage* aMessage);
-
-nsresult
-DBusSendMessageWithReply(DBusConnection* aConnection,
-                         DBusReplyCallback aCallback, void* aData,
-                         int aTimeout,
-                         DBusMessage* aMessage);
-
-nsresult
-DBusSendMessageWithReply(DBusConnection* aConnection,
-                         DBusReplyCallback aCallback,
-                         void* aData,
-                         int aTimeout,
-                         const char* aDestination,
-                         const char* aPath,
-                         const char* aIntf,
-                         const char* aFunc,
-                         int aFirstArgType,
-                         va_list aArgs);
-
-nsresult
-DBusSendMessageWithReply(DBusConnection* aConnection,
-                         DBusReplyCallback aCallback,
-                         void* aData,
-                         int aTimeout,
-                         const char* aDestination,
-                         const char* aPath,
-                         const char* aIntf,
-                         const char* aFunc,
-                         int aFirstArgType,
-                         ...);
-
-} // namespace ipc
-} // namespace mozilla
-
-#endif // mozilla_ipc_DBusHelpers_h
deleted file mode 100644
--- a/ipc/dbus/DBusMessageRefPt