merge mozilla-inbound to mozilla-central. a=merge
authorSebastian Hengst <archaeopteryx@coole-files.de>
Wed, 28 Feb 2018 12:54:12 +0200
changeset 405690 ee326c976eeb
parent 405642 9b1228043619 (current diff)
parent 405689 825fd04dacc6 (diff)
child 405691 7bbd1a09eacb
child 405712 c73600671aaa
child 405751 5347f06b4438
push id33526
push userarchaeopteryx@coole-files.de
push dateWed, 28 Feb 2018 10:55:04 +0000
treeherdermozilla-central@ee326c976eeb [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone60.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
merge mozilla-inbound to mozilla-central. a=merge
browser/base/content/browser.js
browser/base/content/tabbrowser.js
browser/base/content/tabbrowser.xml
netwerk/base/nsStandardURL.h
testing/mochitest/BrowserTestUtils/BrowserTestUtils.jsm
testing/web-platform/meta/css/css-grid/grid-items/grid-minimum-size-grid-items-007.html.ini
testing/web-platform/meta/css/css-grid/grid-items/grid-minimum-size-grid-items-009.html.ini
testing/web-platform/meta/css/css-grid/grid-items/grid-minimum-size-grid-items-021.html.ini
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1673,17 +1673,17 @@ pref("print.use_simplify_page", true);
 
 // Space separated list of URLS that are allowed to send objects (instead of
 // only strings) through webchannels. This list is duplicated in mobile/android/app/mobile.js
 pref("webchannel.allowObject.urlWhitelist", "https://content.cdn.mozilla.net https://input.mozilla.org https://support.mozilla.org https://install.mozilla.org");
 
 // Whether or not the browser should scan for unsubmitted
 // crash reports, and then show a notification for submitting
 // those reports.
-#ifdef EARLY_BETA_OR_EARLIER
+#ifdef NIGHTLY_BUILD
 pref("browser.crashReports.unsubmittedCheck.enabled", true);
 #else
 pref("browser.crashReports.unsubmittedCheck.enabled", false);
 #endif
 
 // chancesUntilSuppress is how many times we'll show the unsubmitted
 // crash report notification across different days and shutdown
 // without a user choice before we suppress the notification for
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -30,16 +30,17 @@ XPCOMUtils.defineLazyModuleGetters(this,
   ExtensionsUI: "resource:///modules/ExtensionsUI.jsm",
   FormValidationHandler: "resource:///modules/FormValidationHandler.jsm",
   LanguagePrompt: "resource://gre/modules/LanguagePrompt.jsm",
   LightweightThemeConsumer: "resource://gre/modules/LightweightThemeConsumer.jsm",
   LightweightThemeManager: "resource://gre/modules/LightweightThemeManager.jsm",
   Log: "resource://gre/modules/Log.jsm",
   LoginManagerParent: "resource://gre/modules/LoginManagerParent.jsm",
   NewTabUtils: "resource://gre/modules/NewTabUtils.jsm",
+  OpenInTabsUtils: "resource:///modules/OpenInTabsUtils.jsm",
   PageActions: "resource:///modules/PageActions.jsm",
   PageThumbs: "resource://gre/modules/PageThumbs.jsm",
   PanelMultiView: "resource:///modules/PanelMultiView.jsm",
   PanelView: "resource:///modules/PanelMultiView.jsm",
   PluralForm: "resource://gre/modules/PluralForm.jsm",
   PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.jsm",
   ProcessHangMonitor: "resource:///modules/ProcessHangMonitor.jsm",
   PromiseUtils: "resource://gre/modules/PromiseUtils.jsm",
@@ -3510,27 +3511,48 @@ var browserDragAndDrop = {
       aEvent.preventDefault();
     }
   },
 
   getTriggeringPrincipal(aEvent) {
     return Services.droppedLinkHandler.getTriggeringPrincipal(aEvent);
   },
 
+  validateURIsForDrop(aEvent, aURIsCount, aURIs) {
+    return Services.droppedLinkHandler.validateURIsForDrop(aEvent,
+                                                           aURIsCount,
+                                                           aURIs);
+  },
+
   dropLinks(aEvent, aDisallowInherit) {
     return Services.droppedLinkHandler.dropLinks(aEvent, aDisallowInherit);
   }
 };
 
 var homeButtonObserver = {
   onDrop(aEvent) {
       // disallow setting home pages that inherit the principal
       let links = browserDragAndDrop.dropLinks(aEvent, true);
       if (links.length) {
-        setTimeout(openHomeDialog, 0, links.map(link => link.url).join("|"));
+        let urls = [];
+        for (let link of links) {
+          if (link.url.includes("|")) {
+            urls.push(...link.url.split("|"));
+          } else {
+            urls.push(link.url);
+          }
+        }
+
+        try {
+          browserDragAndDrop.validateURIsForDrop(aEvent, urls.length, urls);
+        } catch (e) {
+          return;
+        }
+
+        setTimeout(openHomeDialog, 0, urls.join("|"));
       }
     },
 
   onDragOver(aEvent) {
       if (Services.prefs.prefIsLocked("browser.startup.homepage")) {
         return;
       }
       browserDragAndDrop.dragOver(aEvent);
@@ -3563,39 +3585,70 @@ function openHomeDialog(aURL) {
 }
 
 var newTabButtonObserver = {
   onDragOver(aEvent) {
     browserDragAndDrop.dragOver(aEvent);
   },
   onDragExit(aEvent) {},
   async onDrop(aEvent) {
+    let shiftKey = aEvent.shiftKey;
     let links = browserDragAndDrop.dropLinks(aEvent);
+    let triggeringPrincipal = browserDragAndDrop.getTriggeringPrincipal(aEvent);
+
+    if (links.length >= Services.prefs.getIntPref("browser.tabs.maxOpenBeforeWarn")) {
+      // Sync dialog cannot be used inside drop event handler.
+      let answer = await OpenInTabsUtils.promiseConfirmOpenInTabs(links.length,
+                                                                  window);
+      if (!answer) {
+        return;
+      }
+    }
+
     for (let link of links) {
       if (link.url) {
         let data = await getShortcutOrURIAndPostData(link.url);
         // Allow third-party services to fixup this URL.
-        openNewTabWith(data.url, null, data.postData, aEvent, true);
+        openNewTabWith(data.url, shiftKey, {
+          postData: data.postData,
+          allowThirdPartyFixup: true,
+          triggeringPrincipal,
+        });
       }
     }
   }
 };
 
 var newWindowButtonObserver = {
   onDragOver(aEvent) {
     browserDragAndDrop.dragOver(aEvent);
   },
   onDragExit(aEvent) {},
   async onDrop(aEvent) {
     let links = browserDragAndDrop.dropLinks(aEvent);
+    let triggeringPrincipal = browserDragAndDrop.getTriggeringPrincipal(aEvent);
+
+    if (links.length >= Services.prefs.getIntPref("browser.tabs.maxOpenBeforeWarn")) {
+      // Sync dialog cannot be used inside drop event handler.
+      let answer = await OpenInTabsUtils.promiseConfirmOpenInTabs(links.length,
+                                                                  window);
+      if (!answer) {
+        return;
+      }
+    }
+
     for (let link of links) {
       if (link.url) {
         let data = await getShortcutOrURIAndPostData(link.url);
         // Allow third-party services to fixup this URL.
-        openNewWindowWith(data.url, null, data.postData, true);
+        openNewWindowWith(data.url, {
+          postData: data.postData,
+          allowThirdPartyFixup: true,
+          triggeringPrincipal,
+        });
       }
     }
   }
 };
 const DOMEventHandler = {
   init() {
     let mm = window.messageManager;
     mm.addMessageListener("Link:AddFeed", this);
@@ -6103,16 +6156,25 @@ function handleDroppedLink(event, urlOrL
   let inBackground = false;
   if (event) {
     inBackground = Services.prefs.getBoolPref("browser.tabs.loadInBackground");
     if (event.shiftKey)
       inBackground = !inBackground;
   }
 
   (async function() {
+    if (links.length >= Services.prefs.getIntPref("browser.tabs.maxOpenBeforeWarn")) {
+      // Sync dialog cannot be used inside drop event handler.
+      let answer = await OpenInTabsUtils.promiseConfirmOpenInTabs(links.length,
+                                                                  window);
+      if (!answer) {
+        return;
+      }
+    }
+
     let urls = [];
     let postDatas = [];
     for (let link of links) {
       let data = await getShortcutOrURIAndPostData(link.url);
       urls.push(data.url);
       postDatas.push(data.postData);
     }
     if (lastLocationChange == gBrowser.selectedBrowser.lastLocationChange) {
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -1385,36 +1385,47 @@
           try {
             links = browserDragAndDrop.dropLinks(event, true);
           } catch (ex) {}
 
           if (!links || links.length === 0)
             return;
 
           let inBackground = Services.prefs.getBoolPref("browser.tabs.loadInBackground");
-
           if (event.shiftKey)
             inBackground = !inBackground;
 
           let targetTab = this._getDragTargetTab(event, true);
           let userContextId = this.selectedItem.getAttribute("usercontextid");
           let replace = !!targetTab;
           let newIndex = this._getDropIndex(event, true);
           let urls = links.map(link => link.url);
 
           let triggeringPrincipal = browserDragAndDrop.getTriggeringPrincipal(event);
-          this.tabbrowser.loadTabs(urls, {
-            inBackground,
-            replace,
-            allowThirdPartyFixup: true,
-            targetTab,
-            newIndex,
-            userContextId,
-            triggeringPrincipal,
-          });
+
+          (async () => {
+            if (urls.length >= Services.prefs.getIntPref("browser.tabs.maxOpenBeforeWarn")) {
+              // Sync dialog cannot be used inside drop event handler.
+              let answer = await OpenInTabsUtils.promiseConfirmOpenInTabs(urls.length,
+                                                                          window);
+              if (!answer) {
+                return;
+              }
+            }
+
+            this.tabbrowser.loadTabs(urls, {
+              inBackground,
+              replace,
+              allowThirdPartyFixup: true,
+              targetTab,
+              newIndex,
+              userContextId,
+              triggeringPrincipal,
+            });
+          })();
         }
 
         if (draggedTab) {
           delete draggedTab._dragData;
         }
       ]]></handler>
 
       <handler event="dragend"><![CDATA[
--- a/browser/base/content/test/general/browser_newTabDrop.js
+++ b/browser/base/content/test/general/browser_newTabDrop.js
@@ -48,16 +48,77 @@ add_task(async function() {
 // Single item with multiple types.
 add_task(async function() {
   await drop([[{type: "text/plain",
                 data: "mochi.test/10"},
                {type: "text/x-moz-url",
                 data: "mochi.test/11\nTITLE11"}]], 1);
 });
 
+// Warn when too many URLs are dropped.
+add_task(async function multiple_tabs_under_max() {
+  let urls = [];
+  for (let i = 0; i < 5; i++) {
+    urls.push("mochi.test/multi" + i);
+  }
+  await dropText(urls.join("\n"), 5);
+});
+add_task(async function multiple_tabs_over_max_accept() {
+  await pushPrefs(["browser.tabs.maxOpenBeforeWarn", 4]);
+
+  let confirmPromise = BrowserTestUtils.promiseAlertDialog("accept");
+
+  let urls = [];
+  for (let i = 0; i < 5; i++) {
+    urls.push("mochi.test/accept" + i);
+  }
+  await dropText(urls.join("\n"), 5);
+
+  await confirmPromise;
+
+  await popPrefs();
+});
+add_task(async function multiple_tabs_over_max_cancel() {
+  await pushPrefs(["browser.tabs.maxOpenBeforeWarn", 4]);
+
+  let confirmPromise = BrowserTestUtils.promiseAlertDialog("cancel");
+
+  let urls = [];
+  for (let i = 0; i < 5; i++) {
+    urls.push("mochi.test/cancel" + i);
+  }
+  await dropText(urls.join("\n"), 0);
+
+  await confirmPromise;
+
+  await popPrefs();
+});
+
+// Open URLs ignoring non-URL.
+add_task(async function multiple_urls() {
+  await dropText(`
+    mochi.test/urls0
+    mochi.test/urls1
+    mochi.test/urls2
+    non-url0
+    mochi.test/urls3
+    non-url1
+    non-url2
+`, 4);
+});
+
+// Open single search if there's no URL.
+add_task(async function multiple_text() {
+  await dropText(`
+    non-url0
+    non-url1
+    non-url2
+`, 1);
+});
+
 function dropText(text, expectedTabOpenCount = 0) {
   return drop([[{type: "text/plain", data: text}]], expectedTabOpenCount);
 }
 
 async function drop(dragData, expectedTabOpenCount = 0) {
   let dragDataString = JSON.stringify(dragData);
   info(`Starting test for datagData:${dragDataString}; expectedTabOpenCount:${expectedTabOpenCount}`);
   let EventUtils = {};
--- a/browser/base/content/test/general/browser_newWindowDrop.js
+++ b/browser/base/content/test/general/browser_newWindowDrop.js
@@ -61,21 +61,63 @@ add_task(async function() {
 // Single item with multiple types.
 add_task(async function() {
   await drop([[{type: "text/plain",
                 data: "mochi.test/10"},
                {type: "text/x-moz-url",
                 data: "mochi.test/11\nTITLE11"}]], 1);
 });
 
-function dropText(text, expectedWindowOpenCount = 0) {
-  return drop([[{type: "text/plain", data: text}]], expectedWindowOpenCount);
+// Warn when too many URLs are dropped.
+add_task(async function multiple_tabs_under_max() {
+  let urls = [];
+  for (let i = 0; i < 5; i++) {
+    urls.push("mochi.test/multi" + i);
+  }
+  await dropText(urls.join("\n"), 5);
+});
+add_task(async function multiple_tabs_over_max_accept() {
+  await pushPrefs(["browser.tabs.maxOpenBeforeWarn", 4]);
+
+  let confirmPromise = BrowserTestUtils.promiseAlertDialog("accept");
+
+  let urls = [];
+  for (let i = 0; i < 5; i++) {
+    urls.push("mochi.test/accept" + i);
+  }
+  await dropText(urls.join("\n"), 5, true);
+
+  await confirmPromise;
+
+  await popPrefs();
+});
+add_task(async function multiple_tabs_over_max_cancel() {
+  await pushPrefs(["browser.tabs.maxOpenBeforeWarn", 4]);
+
+  let confirmPromise = BrowserTestUtils.promiseAlertDialog("cancel");
+
+  let urls = [];
+  for (let i = 0; i < 5; i++) {
+    urls.push("mochi.test/cancel" + i);
+  }
+  await dropText(urls.join("\n"), 0, true);
+
+  await confirmPromise;
+
+  await popPrefs();
+});
+
+function dropText(text, expectedWindowOpenCount = 0,
+                  ignoreFirstWindow = false) {
+  return drop([[{type: "text/plain", data: text}]], expectedWindowOpenCount,
+              ignoreFirstWindow);
 }
 
-async function drop(dragData, expectedWindowOpenCount = 0) {
+async function drop(dragData, expectedWindowOpenCount = 0,
+                    ignoreFirstWindow = false) {
   let dragDataString = JSON.stringify(dragData);
   info(`Starting test for datagData:${dragDataString}; expectedWindowOpenCount:${expectedWindowOpenCount}`);
   let EventUtils = {};
   Services.scriptloader.loadSubScript("chrome://mochikit/content/tests/SimpleTest/EventUtils.js", EventUtils);
 
   // Since synthesizeDrop triggers the srcElement, need to use another button.
   let dragSrcElement = document.getElementById("downloads-button");
   ok(dragSrcElement, "Downloads button exists");
@@ -84,16 +126,24 @@ async function drop(dragData, expectedWi
 
   let tmp = {};
   ChromeUtils.import("resource://testing-common/TestUtils.jsm", tmp);
 
   let awaitDrop = BrowserTestUtils.waitForEvent(newWindowButton, "drop");
   let actualWindowOpenCount = 0;
   let openedWindows = [];
   let checkCount = function(window) {
+    if (ignoreFirstWindow) {
+      // When dropping too many dialog, the confirm dialog is opened and
+      // domwindowopened notification is dispatched for it, before opening
+      // windows for dropped items.  Ignore it.
+      ignoreFirstWindow = false;
+      return false;
+    }
+
     // Add observer as soon as domWindow is opened to avoid missing the topic.
     let awaitStartup = tmp.TestUtils.topicObserved("browser-delayed-startup-finished",
                                                    subject => subject == window);
     openedWindows.push([window, awaitStartup]);
     actualWindowOpenCount++;
     return actualWindowOpenCount == expectedWindowOpenCount;
   };
   let awaitWindowOpen = expectedWindowOpenCount && BrowserTestUtils.domWindowOpened(null, checkCount);
--- a/browser/base/content/test/general/browser_tabDrop.js
+++ b/browser/base/content/test/general/browser_tabDrop.js
@@ -48,16 +48,55 @@ add_task(async function() {
 // Single item with multiple types.
 add_task(async function() {
   await drop([[{type: "text/plain",
                 data: "mochi.test/10"},
                {type: "text/x-moz-url",
                 data: "mochi.test/11\nTITLE11"}]], 1);
 });
 
+// Warn when too many URLs are dropped.
+add_task(async function multiple_tabs_under_max() {
+  let urls = [];
+  for (let i = 0; i < 5; i++) {
+    urls.push("mochi.test/multi" + i);
+  }
+  await dropText(urls.join("\n"), 5);
+});
+add_task(async function multiple_tabs_over_max_accept() {
+  await pushPrefs(["browser.tabs.maxOpenBeforeWarn", 4]);
+
+  let confirmPromise = BrowserTestUtils.promiseAlertDialog("accept");
+
+  let urls = [];
+  for (let i = 0; i < 5; i++) {
+    urls.push("mochi.test/accept" + i);
+  }
+  await dropText(urls.join("\n"), 5, true);
+
+  await confirmPromise;
+
+  await popPrefs();
+});
+add_task(async function multiple_tabs_over_max_cancel() {
+  await pushPrefs(["browser.tabs.maxOpenBeforeWarn", 4]);
+
+  let confirmPromise = BrowserTestUtils.promiseAlertDialog("cancel");
+
+  let urls = [];
+  for (let i = 0; i < 5; i++) {
+    urls.push("mochi.test/cancel" + i);
+  }
+  await dropText(urls.join("\n"), 0, true);
+
+  await confirmPromise;
+
+  await popPrefs();
+});
+
 function dropText(text, expectedTabOpenCount = 0) {
   return drop([[{type: "text/plain", data: text}]], expectedTabOpenCount);
 }
 
 async function drop(dragData, expectedTabOpenCount = 0) {
   let dragDataString = JSON.stringify(dragData);
   info(`Starting test for datagData:${dragDataString}; expectedTabOpenCount:${expectedTabOpenCount}`);
   let EventUtils = {};
--- a/browser/base/content/test/general/head.js
+++ b/browser/base/content/test/general/head.js
@@ -164,16 +164,22 @@ function setTestPluginEnabledState(newEn
 }
 
 function pushPrefs(...aPrefs) {
   return new Promise(resolve => {
     SpecialPowers.pushPrefEnv({"set": aPrefs}, resolve);
   });
 }
 
+function popPrefs() {
+  return new Promise(resolve => {
+    SpecialPowers.popPrefEnv(resolve);
+  });
+}
+
 function updateBlocklist(aCallback) {
   var blocklistNotifier = Cc["@mozilla.org/extensions/blocklist;1"]
                           .getService(Ci.nsITimerCallback);
   var observer = function() {
     Services.obs.removeObserver(observer, "blocklist-updated");
     SimpleTest.executeSoon(aCallback);
   };
   Services.obs.addObserver(observer, "blocklist-updated");
--- a/browser/base/content/urlbarBindings.xml
+++ b/browser/base/content/urlbarBindings.xml
@@ -654,16 +654,17 @@ file, You can obtain one at http://mozil
                Optional.  The parameters to pass to openUILinkIn.  As with
                "where", this method computes the appropriate parameters, but
                any parameters you supply here will override those.
       -->
       <method name="handleCommand">
         <parameter name="event"/>
         <parameter name="openUILinkWhere"/>
         <parameter name="openUILinkParams"/>
+        <parameter name="triggeringPrincipal"/>
         <body><![CDATA[
           let isMouseEvent = event instanceof MouseEvent;
           if (isMouseEvent && event.button == 2) {
             // Do nothing for right clicks.
             return;
           }
 
           BrowserUsageTelemetry.recordUrlbarSelectedResultMethod(event);
@@ -784,25 +785,26 @@ file, You can obtain one at http://mozil
             try {
               new URL(url);
             } catch (ex) {
               let lastLocationChange = browser.lastLocationChange;
               getShortcutOrURIAndPostData(url).then(data => {
                 if (where != "current" ||
                     browser.lastLocationChange == lastLocationChange) {
                   this._loadURL(data.url, browser, data.postData, where,
-                                openUILinkParams, data.mayInheritPrincipal);
+                                openUILinkParams, data.mayInheritPrincipal,
+                                triggeringPrincipal);
                 }
               });
               return;
             }
           }
 
           this._loadURL(url, browser, postData, where, openUILinkParams,
-                        mayInheritPrincipal);
+                        mayInheritPrincipal, triggeringPrincipal);
         ]]></body>
       </method>
 
       <property name="oneOffSearchQuery">
         <getter><![CDATA[
           // If the user has selected a search suggestion, chances are they
           // want to use the one off search engine to search for that suggestion,
           // not the string that they manually entered into the location bar.
@@ -821,16 +823,17 @@ file, You can obtain one at http://mozil
 
       <method name="_loadURL">
         <parameter name="url"/>
         <parameter name="browser"/>
         <parameter name="postData"/>
         <parameter name="openUILinkWhere"/>
         <parameter name="openUILinkParams"/>
         <parameter name="mayInheritPrincipal"/>
+        <parameter name="triggeringPrincipal"/>
         <body><![CDATA[
           this.value = url;
           browser.userTypedValue = url;
           if (gInitialPages.includes(url)) {
             browser.initialPageLoadedFromURLBar = url;
           }
           try {
             addToUrlbarHistory(url);
@@ -838,16 +841,17 @@ file, You can obtain one at http://mozil
             // Things may go wrong when adding url to session history,
             // but don't let that interfere with the loading of the url.
             Cu.reportError(ex);
           }
 
           let params = {
             postData,
             allowThirdPartyFixup: true,
+            triggeringPrincipal,
           };
           if (openUILinkWhere == "current") {
             params.targetBrowser = browser;
             params.indicateErrorPageLoad = true;
             params.allowPinnedTabHostChange = true;
             params.disallowInheritPrincipal = !mayInheritPrincipal;
             params.allowPopups = url.startsWith("javascript:");
           } else {
@@ -1003,16 +1007,17 @@ file, You can obtain one at http://mozil
             // this is possibly a security exception, in which case we should return
             // null. Always return null because we can't *know* what exception is
             // being returned.
             return null;
           }
           // The URL bar automatically handles inputs with newline characters,
           // so we can get away with treating text/x-moz-url flavours as text/plain.
           if (links.length > 0 && links[0].url) {
+            let triggeringPrincipal = browserDragAndDrop.getTriggeringPrincipal(aEvent);
             aEvent.preventDefault();
             let url = links[0].url;
             let strippedURL = stripUnsafeProtocolOnPaste(url);
             if (strippedURL != url) {
               aEvent.stopImmediatePropagation();
               return null;
             }
             let urlObj;
@@ -1021,17 +1026,17 @@ file, You can obtain one at http://mozil
               // does with things that don't pass the IO service's newURI constructor
               // without fixup. It's conceivable we may want to relax this check in
               // the future (so e.g. www.foo.com gets fixed up), but not right now.
               urlObj = new URL(url);
               // If we succeed, try to pass security checks. If this works, return the
               // URL object. If the *security checks* fail, return null.
               try {
                 urlSecurityCheck(url,
-                                 gBrowser.contentPrincipal,
+                                 triggeringPrincipal,
                                  Ci.nsIScriptSecurityManager.DISALLOW_INHERIT_PRINCIPAL);
                 return urlObj;
               } catch (ex) {
                 return null;
               }
             } catch (ex) {
               // We couldn't make a URL out of this. Continue on, and return text below.
             }
@@ -1049,20 +1054,21 @@ file, You can obtain one at http://mozil
         ]]></body>
       </method>
 
       <method name="onDrop">
         <parameter name="aEvent"/>
         <body><![CDATA[
           let droppedItem = this._getDroppableItem(aEvent);
           if (droppedItem) {
+            let triggeringPrincipal = browserDragAndDrop.getTriggeringPrincipal(aEvent);
             this.value = droppedItem instanceof URL ? droppedItem.href : droppedItem;
             SetPageProxyState("invalid");
             this.focus();
-            this.handleCommand();
+            this.handleCommand(null, undefined, undefined, triggeringPrincipal);
             // Force not showing the dropped URI immediately.
             gBrowser.userTypedValue = null;
             URLBarSetURI();
           }
         ]]></body>
       </method>
 
       <method name="makeURIReadable">
--- a/browser/base/content/utilityOverlay.js
+++ b/browser/base/content/utilityOverlay.js
@@ -850,70 +850,43 @@ function makeURLAbsolute(aBase, aUrl) {
   return makeURI(aUrl, null, makeURI(aBase)).spec;
 }
 
 /**
  * openNewTabWith: opens a new tab with the given URL.
  *
  * @param aURL
  *        The URL to open (as a string).
- * @param aDocument
- *        Note this parameter is now ignored. There is no security check & no
- *        referrer header derived from aDocument (null case).
- * @param aPostData
- *        Form POST data, or null.
- * @param aEvent
- *        The triggering event (for the purpose of determining whether to open
- *        in the background), or null.
- * @param aAllowThirdPartyFixup
- *        If true, then we allow the URL text to be sent to third party services
- *        (e.g., Google's I Feel Lucky) for interpretation. This parameter may
- *        be undefined in which case it is treated as false.
- * @param [optional] aReferrer
- *        This will be used as the referrer. There will be no security check.
- * @param [optional] aReferrerPolicy
- *        Referrer policy - Ci.nsIHttpChannel.REFERRER_POLICY_*.
+ * @param aShiftKey
+ *        True if shift key is held.  This value is used for the purpose of
+ *        determining whether to open in the background.
+ * @param aParams
+ *        parameters passed to openLinkIn
  */
-function openNewTabWith(aURL, aDocument, aPostData, aEvent,
-                        aAllowThirdPartyFixup, aReferrer, aReferrerPolicy) {
+function openNewTabWith(aURL, aShiftKey, aParams = {}) {
 
   // As in openNewWindowWith(), we want to pass the charset of the
   // current document over to a new tab.
-  let originCharset = null;
   if (document.documentElement.getAttribute("windowtype") == "navigator:browser")
-    originCharset = gBrowser.selectedBrowser.characterSet;
+    aParams.charset = gBrowser.selectedBrowser.characterSet;
 
-  openLinkIn(aURL, aEvent && aEvent.shiftKey ? "tabshifted" : "tab",
-             { charset: originCharset,
-               postData: aPostData,
-               allowThirdPartyFixup: aAllowThirdPartyFixup,
-               referrerURI: aReferrer,
-               referrerPolicy: aReferrerPolicy,
-             });
+  openLinkIn(aURL, aShiftKey ? "tabshifted" : "tab", aParams);
 }
 
 /**
- * @param aDocument
- *        Note this parameter is ignored. See openNewTabWith()
+ * openNewWindowWith: opens a new window with the given URL.
+ * See openNewTabWith for parameters.
  */
-function openNewWindowWith(aURL, aDocument, aPostData, aAllowThirdPartyFixup,
-                           aReferrer, aReferrerPolicy) {
+function openNewWindowWith(aURL, aParams = {}) {
   // Extract the current charset menu setting from the current document and
   // use it to initialize the new browser window...
-  let originCharset = null;
   if (document.documentElement.getAttribute("windowtype") == "navigator:browser")
-    originCharset = gBrowser.selectedBrowser.characterSet;
+    aParams.charset = gBrowser.selectedBrowser.characterSet;
 
-  openLinkIn(aURL, "window",
-             { charset: originCharset,
-               postData: aPostData,
-               allowThirdPartyFixup: aAllowThirdPartyFixup,
-               referrerURI: aReferrer,
-               referrerPolicy: aReferrerPolicy,
-             });
+  openLinkIn(aURL, "window", aParams);
 }
 
 function getHelpLinkURL(aHelpTopic) {
   var url = Services.urlFormatter.formatURLPref("app.support.baseURL");
   return url + aHelpTopic;
 }
 
 // aCalledFromModal is optional
--- a/browser/components/downloads/test/browser/browser_confirm_unblock_download.js
+++ b/browser/components/downloads/test/browser/browser_confirm_unblock_download.js
@@ -3,17 +3,17 @@
 
 "use strict";
 
 // Tests the dialog which allows the user to unblock a downloaded file.
 
 registerCleanupFunction(() => {});
 
 async function assertDialogResult({ args, buttonToClick, expectedResult }) {
-  promiseAlertDialogOpen(buttonToClick);
+  BrowserTestUtils.promiseAlertDialogOpen(buttonToClick);
   is(await DownloadsCommon.confirmUnblockDownload(args), expectedResult);
 }
 
 /**
  * Tests the "unblock" dialog, for each of the possible verdicts.
  */
 add_task(async function test_unblock_dialog_unblock() {
   for (let verdict of [Downloads.Error.BLOCK_VERDICT_MALWARE,
--- a/browser/components/downloads/test/browser/head.js
+++ b/browser/components/downloads/test/browser/head.js
@@ -168,42 +168,16 @@ function openLibrary(aLeftPaneRoot) {
                                   "", "chrome,toolbar=yes,dialog=no,resizable",
                                   aLeftPaneRoot);
 
   return new Promise(resolve => {
     waitForFocus(resolve, library);
   });
 }
 
-function promiseAlertDialogOpen(buttonAction) {
-  return new Promise(resolve => {
-    Services.ww.registerNotification(function onOpen(subj, topic, data) {
-      if (topic == "domwindowopened" && subj instanceof Ci.nsIDOMWindow) {
-        // The test listens for the "load" event which guarantees that the alert
-        // class has already been added (it is added when "DOMContentLoaded" is
-        // fired).
-        subj.addEventListener("load", function() {
-          if (subj.document.documentURI ==
-              "chrome://global/content/commonDialog.xul") {
-            Services.ww.unregisterNotification(onOpen);
-
-            let dialog = subj.document.getElementById("commonDialog");
-            ok(dialog.classList.contains("alert-dialog"),
-               "The dialog element should contain an alert class.");
-
-            let doc = subj.document.documentElement;
-            doc.getButton(buttonAction).click();
-            resolve();
-          }
-        }, {once: true});
-      }
-    });
-  });
-}
-
 /**
  * Waits for a given button to become visible.
  */
 function promiseButtonShown(id) {
   let dwu = window.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
   return BrowserTestUtils.waitForCondition(() => {
     let target = document.getElementById(id);
     let bounds = dwu.getBoundsWithoutFlushing(target);
--- a/browser/components/enterprisepolicies/tests/browser/browser_policy_disable_masterpassword.js
+++ b/browser/components/enterprisepolicies/tests/browser/browser_policy_disable_masterpassword.js
@@ -5,19 +5,17 @@
 
 const MASTER_PASSWORD = "omgsecret!";
 const mpToken = Cc["@mozilla.org/security/pk11tokendb;1"]
                   .getService(Ci.nsIPK11TokenDB)
                   .getInternalKeyToken();
 
 async function checkDeviceManager({buttonIsDisabled}) {
   let deviceManagerWindow = window.openDialog("chrome://pippki/content/device_manager.xul", "", "");
-  await new Promise(resolve => {
-    deviceManagerWindow.addEventListener("load", resolve, {once: true});
-  });
+  await BrowserTestUtils.waitForEvent(deviceManagerWindow, "load");
 
   let tree = deviceManagerWindow.document.getElementById("device_tree");
   ok(tree, "The device tree exists");
 
   // Find and select the item related to the internal key token
   for (let i = 0; i < tree.view.rowCount; i++) {
     tree.view.selection.select(i);
 
--- a/browser/components/places/PlacesUIUtils.jsm
+++ b/browser/components/places/PlacesUIUtils.jsm
@@ -5,16 +5,17 @@
 
 var EXPORTED_SYMBOLS = ["PlacesUIUtils"];
 
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 ChromeUtils.import("resource://gre/modules/Services.jsm");
 ChromeUtils.import("resource://gre/modules/Timer.jsm");
 
 XPCOMUtils.defineLazyModuleGetters(this, {
+  OpenInTabsUtils: "resource:///modules/OpenInTabsUtils.jsm",
   PlacesUtils: "resource://gre/modules/PlacesUtils.jsm",
   PluralForm: "resource://gre/modules/PluralForm.jsm",
   PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.jsm",
   RecentWindow: "resource:///modules/RecentWindow.jsm",
   PromiseUtils: "resource://gre/modules/PromiseUtils.jsm",
   PlacesTransactions: "resource://gre/modules/PlacesTransactions.jsm",
   Weave: "resource://services-sync/main.js",
 });
@@ -585,57 +586,16 @@ var PlacesUIUtils = {
     // because the only way to access the left pane contents goes through
     // "resolving" the leftPaneFolderId getter.
     if (typeof Object.getOwnPropertyDescriptor(this, "leftPaneFolderId").get == "function") {
       return false;
     }
     return itemId == this.leftPaneFolderId;
   },
 
-  /**
-   * Gives the user a chance to cancel loading lots of tabs at once
-   */
-  confirmOpenInTabs(numTabsToOpen, aWindow) {
-    const WARN_ON_OPEN_PREF = "browser.tabs.warnOnOpen";
-    var reallyOpen = true;
-
-    if (Services.prefs.getBoolPref(WARN_ON_OPEN_PREF)) {
-      if (numTabsToOpen >= Services.prefs.getIntPref("browser.tabs.maxOpenBeforeWarn")) {
-        // default to true: if it were false, we wouldn't get this far
-        var warnOnOpen = { value: true };
-
-        var messageKey = "tabs.openWarningMultipleBranded";
-        var openKey = "tabs.openButtonMultiple";
-        const BRANDING_BUNDLE_URI = "chrome://branding/locale/brand.properties";
-        var brandShortName = Services.strings.
-                             createBundle(BRANDING_BUNDLE_URI).
-                             GetStringFromName("brandShortName");
-
-        var buttonPressed = Services.prompt.confirmEx(
-          aWindow,
-          this.getString("tabs.openWarningTitle"),
-          this.getFormattedString(messageKey, [numTabsToOpen, brandShortName]),
-          (Services.prompt.BUTTON_TITLE_IS_STRING * Services.prompt.BUTTON_POS_0) +
-            (Services.prompt.BUTTON_TITLE_CANCEL * Services.prompt.BUTTON_POS_1),
-          this.getString(openKey), null, null,
-          this.getFormattedString("tabs.openWarningPromptMeBranded",
-                                  [brandShortName]),
-          warnOnOpen
-        );
-
-        reallyOpen = (buttonPressed == 0);
-        // don't set the pref unless they press OK and it's false
-        if (reallyOpen && !warnOnOpen.value)
-          Services.prefs.setBoolPref(WARN_ON_OPEN_PREF, false);
-      }
-    }
-
-    return reallyOpen;
-  },
-
   /** aItemsToOpen needs to be an array of objects of the form:
     * {uri: string, isBookmark: boolean}
     */
   _openTabset: function PUIU__openTabset(aItemsToOpen, aEvent, aWindow) {
     if (!aItemsToOpen.length)
       return;
 
     // Prefer the caller window if it's a browser window, otherwise use
@@ -694,28 +654,28 @@ var PlacesUIUtils = {
       .then(aLivemark => {
         let urlsToOpen = [];
 
         let nodes = aLivemark.getNodesForContainer(aNode);
         for (let node of nodes) {
           urlsToOpen.push({uri: node.uri, isBookmark: false});
         }
 
-        if (this.confirmOpenInTabs(urlsToOpen.length, window)) {
+        if (OpenInTabsUtils.confirmOpenInTabs(urlsToOpen.length, window)) {
           this._openTabset(urlsToOpen, aEvent, window);
         }
       }, Cu.reportError);
   },
 
   openContainerNodeInTabs:
   function PUIU_openContainerInTabs(aNode, aEvent, aView) {
     let window = aView.ownerWindow;
 
     let urlsToOpen = PlacesUtils.getURLsForContainerNode(aNode);
-    if (this.confirmOpenInTabs(urlsToOpen.length, window)) {
+    if (OpenInTabsUtils.confirmOpenInTabs(urlsToOpen.length, window)) {
       this._openTabset(urlsToOpen, aEvent, window);
     }
   },
 
   openURINodesInTabs: function PUIU_openURINodesInTabs(aNodes, aEvent, aView) {
     let window = aView.ownerWindow;
 
     let urlsToOpen = [];
--- a/browser/components/preferences/in-content/tests/head.js
+++ b/browser/components/preferences/in-content/tests/head.js
@@ -140,34 +140,21 @@ function openPreferencesViaOpenPreferenc
         resolve({ selectedPane });
       }, { once: true });
     }, { capture: true, once: true });
 
   });
 }
 
 function promiseWindowDialogOpen(buttonAction, url) {
-  return new Promise(resolve => {
-    Services.ww.registerNotification(function onOpen(subj, topic, data) {
-      if (topic == "domwindowopened" && subj instanceof Ci.nsIDOMWindow) {
-        subj.addEventListener("load", function onLoad() {
-          if (subj.document.documentURI == url) {
-            Services.ww.unregisterNotification(onOpen);
-            let doc = subj.document.documentElement;
-            doc.getButton(buttonAction).click();
-            resolve();
-          }
-        }, { once: true });
-      }
-    });
-  });
+  return BrowserTestUtils.promiseAlertDialogOpen(buttonAction, url);
 }
 
 function promiseAlertDialogOpen(buttonAction) {
-  return promiseWindowDialogOpen(buttonAction, "chrome://global/content/commonDialog.xul");
+  return BrowserTestUtils.promiseAlertDialogOpen(buttonAction);
 }
 
 function promiseSiteDataManagerSitesUpdated() {
   return TestUtils.topicObserved("sitedatamanager:sites-updated", () => true);
 }
 
 function openSiteDataSettingsDialog() {
   let doc = gBrowser.selectedBrowser.contentDocument;
--- a/browser/components/sessionstore/test/browser_354894_perwindowpb.js
+++ b/browser/components/sessionstore/test/browser_354894_perwindowpb.js
@@ -136,17 +136,17 @@ let setupTest = async function(options, 
 
   for (let o in observing) {
     Services.obs.addObserver(observer, o);
   }
 
   let private = options.private || false;
   let newWin = await promiseNewWindowLoaded({ private });
 
-  injectTestTabs(newWin);
+  await injectTestTabs(newWin);
 
   await testFunction(newWin, observing);
 
   let count = getBrowserWindowsCount();
   is(count.open, 0, "Got right number of open windows");
   is(count.winstates, 1, "Got right number of stored window states");
 
   for (let o in observing) {
@@ -158,19 +158,19 @@ let setupTest = async function(options, 
 
 /**
  * Loads a TEST_URLS into a browser window.
  *
  * @param win (Window)
  *        The browser window to load the tabs in
  */
 function injectTestTabs(win) {
-  TEST_URLS.forEach(function(url) {
-    win.gBrowser.addTab(url);
-  });
+  let promises = TEST_URLS.map(url => win.gBrowser.addTab(url))
+                          .map(tab => BrowserTestUtils.browserLoaded(tab.linkedBrowser));
+  return Promise.all(promises);
 }
 
 /**
  * Attempts to close a window via BrowserTryToCloseWindow so that
  * we get the browser-lastwindow-close-requested and
  * browser-lastwindow-close-granted observer notifications.
  *
  * @param win (Window)
--- a/browser/components/syncedtabs/TabListComponent.js
+++ b/browser/components/syncedtabs/TabListComponent.js
@@ -1,25 +1,24 @@
 /* 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/. */
 
 "use strict";
 
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
+ChromeUtils.import("resource://gre/modules/Services.jsm");
 
 let log = ChromeUtils.import("resource://gre/modules/Log.jsm", {})
             .Log.repository.getLogger("Sync.RemoteTabs");
 
-ChromeUtils.defineModuleGetter(this, "BrowserUITelemetry",
-  "resource:///modules/BrowserUITelemetry.jsm");
-ChromeUtils.defineModuleGetter(this, "PlacesUIUtils",
-  "resource:///modules/PlacesUIUtils.jsm");
-ChromeUtils.defineModuleGetter(this, "Services",
-  "resource://gre/modules/Services.jsm");
+XPCOMUtils.defineLazyModuleGetters(this, {
+  BrowserUITelemetry: "resource:///modules/BrowserUITelemetry.jsm",
+  OpenInTabsUtils: "resource:///modules/OpenInTabsUtils.jsm",
+});
 
 var EXPORTED_SYMBOLS = [
   "TabListComponent"
 ];
 
 /**
  * TabListComponent
  *
@@ -114,17 +113,17 @@ TabListComponent.prototype = {
   },
 
   onOpenTab(url, where, params) {
     this._window.openUILinkIn(url, where, params);
     BrowserUITelemetry.countSyncedTabEvent("open", "sidebar");
   },
 
   onOpenTabs(urls, where) {
-    if (!PlacesUIUtils.confirmOpenInTabs(urls.length, this._window)) {
+    if (!OpenInTabsUtils.confirmOpenInTabs(urls.length, this._window)) {
       return;
     }
     if (where == "window") {
       this._window.openDialog(this._window.getBrowserURL(), "_blank",
                               "chrome,dialog=no,all", urls.join("|"));
     } else {
       let loadInBackground = where == "tabshifted";
       this._getChromeWindow(this._window).gBrowser.loadTabs(urls, {
--- a/browser/locales/en-US/chrome/browser/places/places.properties
+++ b/browser/locales/en-US/chrome/browser/places/places.properties
@@ -44,21 +44,16 @@ view.sortBy.1.lastModified.label=Sort by
 view.sortBy.1.lastModified.accesskey=M
 view.sortBy.1.tags.label=Sort by Tags
 view.sortBy.1.tags.accesskey=T
 
 searchBookmarks=Search Bookmarks
 searchHistory=Search History
 searchDownloads=Search Downloads
 
-tabs.openWarningTitle=Confirm open
-tabs.openWarningMultipleBranded=You are about to open %S tabs.  This might slow down %S while the pages are loading.  Are you sure you want to continue?
-tabs.openButtonMultiple=Open tabs
-tabs.openWarningPromptMeBranded=Warn me when opening multiple tabs might slow down %S
-
 SelectImport=Import Bookmarks File
 EnterExport=Export Bookmarks File
 
 detailsPane.noItems=No items
 # LOCALIZATION NOTE (detailsPane.itemsCountLabel): Semicolon-separated list of plural forms.
 # See: http://developer.mozilla.org/en/docs/Localization_and_Plurals
 # #1 number of items
 # example: 111 items
--- a/browser/locales/en-US/chrome/browser/tabbrowser.properties
+++ b/browser/locales/en-US/chrome/browser/tabbrowser.properties
@@ -35,8 +35,16 @@ tabs.unblockAudio.tooltip=Play tab
 # %S is the hostname of the site where dialogs are allowed to switch tabs
 tabs.allowTabFocusByPromptForSite=Allow dialogs from %S to take you to their tab
 
 # LOCALIZATION NOTE (tabs.containers.tooltip):
 # Displayed as a tooltip on container tabs
 # %1$S is the title of the current tab
 # %2$S is the name of the current container
 tabs.containers.tooltip=%1$S - %2$S
+
+# LOCALIZATION NOTE (tabs.openWarningTitle, tabs.openWarningMultipleBranded, tabs.openButtonMultiple, tabs.openWarningPromptMeBranded):
+# These items are moved from chrome/browser/places/places.properties
+# Now they are not specific to bookmark.
+tabs.openWarningTitle=Confirm open
+tabs.openWarningMultipleBranded=You are about to open %S tabs.  This might slow down %S while the pages are loading.  Are you sure you want to continue?
+tabs.openButtonMultiple=Open tabs
+tabs.openWarningPromptMeBranded=Warn me when opening multiple tabs might slow down %S
--- a/browser/modules/BrowserErrorReporter.jsm
+++ b/browser/modules/BrowserErrorReporter.jsm
@@ -9,23 +9,26 @@ ChromeUtils.import("resource://gre/modul
 
 ChromeUtils.defineModuleGetter(this, "Log", "resource://gre/modules/Log.jsm");
 ChromeUtils.defineModuleGetter(this, "UpdateUtils", "resource://gre/modules/UpdateUtils.jsm");
 
 Cu.importGlobalProperties(["fetch", "URL"]);
 
 var EXPORTED_SYMBOLS = ["BrowserErrorReporter"];
 
+const CONTEXT_LINES = 5;
 const ERROR_PREFIX_RE = /^[^\W]+:/m;
 const PREF_ENABLED = "browser.chrome.errorReporter.enabled";
 const PREF_LOG_LEVEL = "browser.chrome.errorReporter.logLevel";
 const PREF_PROJECT_ID = "browser.chrome.errorReporter.projectId";
 const PREF_PUBLIC_KEY = "browser.chrome.errorReporter.publicKey";
 const PREF_SAMPLE_RATE = "browser.chrome.errorReporter.sampleRate";
 const PREF_SUBMIT_URL = "browser.chrome.errorReporter.submitUrl";
+const SDK_NAME = "firefox-error-reporter";
+const SDK_VERSION = "1.0.0";
 
 // https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XPCOM/Reference/Interface/nsIScriptError#Categories
 const REPORTED_CATEGORIES = new Set([
   "XPConnect JavaScript",
   "component javascript",
   "chrome javascript",
   "chrome registration",
   "XBL",
@@ -39,38 +42,42 @@ const REPORTED_CATEGORIES = new Set([
  * Collects nsIScriptError messages logged to the browser console and reports
  * them to a remotely-hosted error collection service.
  *
  * This is a PROTOTYPE; it will be removed in the future and potentially
  * replaced with a more robust implementation. It is meant to only collect
  * errors from Nightly (and local builds if enabled for development purposes)
  * and has not been reviewed for use outside of Nightly.
  *
- * The outgoing requests are designed to be compatible with version 7 of Sentry.
+ * The outgoing requests are designed to be compatible with Sentry. See
+ * https://docs.sentry.io/clientdev/ for details on the data format that Sentry
+ * expects.
+ *
+ * Errors may contain PII, such as in messages or local file paths in stack
+ * traces; see bug 1426482 for privacy review and server-side mitigation.
  */
 class BrowserErrorReporter {
   constructor(fetchMethod = this._defaultFetch) {
     // A fake fetch is passed by the tests to avoid network connections
     this.fetch = fetchMethod;
 
     // Values that don't change between error reports.
     this.requestBodyTemplate = {
-      request: {
-        headers: {
-          "User-Agent": Services.appShell.hiddenDOMWindow.navigator.userAgent,
-        },
-      },
       logger: "javascript",
       platform: "javascript",
       release: Services.appinfo.version,
       environment: UpdateUtils.getUpdateChannel(false),
       tags: {
         appBuildID: Services.appinfo.appBuildID,
         changeset: AppConstants.SOURCE_REVISION_URL,
       },
+      sdk: {
+        name: SDK_NAME,
+        version: SDK_VERSION,
+      },
     };
 
     XPCOMUtils.defineLazyPreferenceGetter(
       this,
       "collectionEnabled",
       PREF_ENABLED,
       false,
       this.handleEnabledPrefChanged.bind(this),
@@ -140,54 +147,45 @@ class BrowserErrorReporter {
     let errorMessage = message.errorMessage;
     let errorName = "Error";
     if (message.errorMessage.match(ERROR_PREFIX_RE)) {
       const parts = message.errorMessage.split(":");
       errorName = parts[0];
       errorMessage = parts.slice(1).join(":").trim();
     }
 
-    // Pull and normalize stacktrace frames from the message
     const frames = [];
     let frame = message.stack;
-
     // Avoid an infinite loop by limiting traces to 100 frames.
     while (frame && frames.length < 100) {
-      frames.push({
-        function: frame.functionDisplayName,
-        filename: frame.source,
-        lineno: frame.line,
-        colno: frame.column,
-        in_app: true,
-      });
+      frames.push(await this.normalizeStackFrame(frame));
       frame = frame.parent;
     }
+    // Frames are sent in order from oldest to newest.
+    frames.reverse();
 
-    // Sentry-compatible request body copied from an example generated by Raven.js 3.22.1.
     const requestBody = Object.assign({}, this.requestBodyTemplate, {
+      timestamp: new Date().toISOString().slice(0, -1), // Remove trailing "Z"
       project: Services.prefs.getCharPref(PREF_PROJECT_ID),
       exception: {
         values: [
           {
             type: errorName,
-            // Error messages may contain PII; see bug 1426482 for privacy
-            // review and server-side mitigation.
             value: errorMessage,
             stacktrace: {
               frames,
             }
           },
         ],
       },
       culprit: message.sourceName,
     });
-    requestBody.request.url = message.sourceName;
 
     const url = new URL(Services.prefs.getCharPref(PREF_SUBMIT_URL));
-    url.searchParams.set("sentry_client", "firefox-error-reporter/1.0.0");
+    url.searchParams.set("sentry_client", `${SDK_NAME}/${SDK_VERSION}`);
     url.searchParams.set("sentry_version", "7");
     url.searchParams.set("sentry_key", Services.prefs.getCharPref(PREF_PUBLIC_KEY));
 
     try {
       await this.fetch(url, {
         method: "POST",
         headers: {
           "Content-Type": "application/json",
@@ -198,16 +196,54 @@ class BrowserErrorReporter {
         body: JSON.stringify(requestBody)
       });
       this.logger.debug("Sent error successfully.");
     } catch (error) {
       this.logger.warn(`Failed to send error: ${error}`);
     }
   }
 
+  async normalizeStackFrame(frame) {
+    const normalizedFrame = {
+      function: frame.functionDisplayName,
+      module: frame.source,
+      lineno: frame.line,
+      colno: frame.column,
+    };
+
+    try {
+      const response = await fetch(frame.source);
+      const sourceCode = await response.text();
+      const sourceLines = sourceCode.split(/\r?\n/);
+      // HTML pages and some inline event handlers have 0 as their line number
+      let lineIndex = Math.max(frame.line - 1, 0);
+
+      // XBL line numbers are off by one, and pretty much every XML file with JS
+      // in it is an XBL file.
+      if (frame.source.endsWith(".xml") && lineIndex > 0) {
+        lineIndex--;
+      }
+
+      normalizedFrame.context_line = sourceLines[lineIndex];
+      normalizedFrame.pre_context = sourceLines.slice(
+        Math.max(lineIndex - CONTEXT_LINES, 0),
+        lineIndex,
+      );
+      normalizedFrame.post_context = sourceLines.slice(
+        lineIndex + 1,
+        Math.min(lineIndex + 1 + CONTEXT_LINES, sourceLines.length),
+      );
+    } catch (err) {
+      // Could be a fetch issue, could be a line index issue. Not much we can
+      // do to recover in either case.
+    }
+
+    return normalizedFrame;
+  }
+
   async _defaultFetch(...args) {
     // Do not make network requests while running in automation
     if (Cu.isInAutomation) {
       return null;
     }
 
     return fetch(...args);
   }
new file mode 100644
--- /dev/null
+++ b/browser/modules/OpenInTabsUtils.jsm
@@ -0,0 +1,82 @@
+/* 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/. */
+
+"use strict";
+
+this.EXPORTED_SYMBOLS = ["OpenInTabsUtils"];
+
+ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
+ChromeUtils.import("resource://gre/modules/Services.jsm");
+
+XPCOMUtils.defineLazyGetter(this, "bundle", function() {
+  return Services.strings.createBundle("chrome://browser/locale/tabbrowser.properties");
+});
+
+/**
+ * Utility functions that can be used when opening multiple tabs, that can be
+ * called without any tabbrowser instance.
+ */
+this.OpenInTabsUtils = {
+  getString(key) {
+    return bundle.GetStringFromName(key);
+  },
+
+  getFormattedString(key, params) {
+    return bundle.formatStringFromName(key, params, params.length);
+  },
+
+  /**
+   * Gives the user a chance to cancel loading lots of tabs at once.
+   */
+  confirmOpenInTabs(numTabsToOpen, aWindow) {
+    const WARN_ON_OPEN_PREF = "browser.tabs.warnOnOpen";
+    const MAX_OPNE_PREF = "browser.tabs.maxOpenBeforeWarn";
+    if (!Services.prefs.getBoolPref(WARN_ON_OPEN_PREF)) {
+      return true;
+    }
+    if (numTabsToOpen < Services.prefs.getIntPref(MAX_OPNE_PREF)) {
+      return true;
+    }
+
+    // default to true: if it were false, we wouldn't get this far
+    let warnOnOpen = { value: true };
+
+    const messageKey = "tabs.openWarningMultipleBranded";
+    const openKey = "tabs.openButtonMultiple";
+    const BRANDING_BUNDLE_URI = "chrome://branding/locale/brand.properties";
+    let brandShortName = Services.strings.createBundle(BRANDING_BUNDLE_URI).
+                         GetStringFromName("brandShortName");
+
+    let buttonPressed = Services.prompt.confirmEx(
+      aWindow,
+      this.getString("tabs.openWarningTitle"),
+      this.getFormattedString(messageKey, [numTabsToOpen, brandShortName]),
+      (Services.prompt.BUTTON_TITLE_IS_STRING * Services.prompt.BUTTON_POS_0) +
+        (Services.prompt.BUTTON_TITLE_CANCEL * Services.prompt.BUTTON_POS_1),
+      this.getString(openKey), null, null,
+      this.getFormattedString("tabs.openWarningPromptMeBranded",
+                              [brandShortName]),
+      warnOnOpen
+    );
+
+    let reallyOpen = (buttonPressed == 0);
+    // don't set the pref unless they press OK and it's false
+    if (reallyOpen && !warnOnOpen.value) {
+      Services.prefs.setBoolPref(WARN_ON_OPEN_PREF, false);
+    }
+
+    return reallyOpen;
+  },
+
+  /*
+   * Async version of confirmOpenInTabs.
+   */
+  promiseConfirmOpenInTabs(numTabsToOpen, aWindow) {
+    return new Promise(resolve => {
+      Services.tm.dispatchToMainThread(() => {
+        resolve(this.confirmOpenInTabs(numTabsToOpen, aWindow));
+      });
+    });
+  }
+};
--- a/browser/modules/moz.build
+++ b/browser/modules/moz.build
@@ -83,16 +83,19 @@ with Files("ReaderParent.jsm"):
     BUG_COMPONENT = ("Toolkit", "Reader Mode")
 
 with Files("Sanitizer.jsm"):
     BUG_COMPONENT = ("Firefox", "Preferences")
 
 with Files("SitePermissions.jsm"):
     BUG_COMPONENT = ("Firefox", "Site Identity and Permission Panels")
 
+with Files("OpenInTabsUtils.jsm"):
+    BUG_COMPONENT = ("Firefox", "Tabbed Browser")
+
 with Files("ThemeVariableMap.jsm"):
     BUG_COMPONENT = ("Toolkit", "WebExtensions: Themes")
 
 with Files("TransientPrefs.jsm"):
     BUG_COMPONENT = ("Firefox", "Preferences")
 
 with Files("Windows8WindowFrameColor.jsm"):
     BUG_COMPONENT = ("Firefox", "Theme")
@@ -139,16 +142,17 @@ EXTRA_JS_MODULES += [
     'ContextMenu.jsm',
     'DirectoryLinksProvider.jsm',
     'ExtensionsUI.jsm',
     'Feeds.jsm',
     'FormSubmitObserver.jsm',
     'FormValidationHandler.jsm',
     'LaterRun.jsm',
     'offlineAppCache.jsm',
+    'OpenInTabsUtils.jsm',
     'PageActions.jsm',
     'PermissionUI.jsm',
     'PingCentre.jsm',
     'PluginContent.jsm',
     'ProcessHangMonitor.jsm',
     'ReaderParent.jsm',
     'RecentWindow.jsm',
     'RemotePrompt.jsm',
--- a/browser/modules/test/browser/browser_BrowserErrorReporter.js
+++ b/browser/modules/test/browser/browser_BrowserErrorReporter.js
@@ -1,14 +1,16 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 "use strict";
 
 ChromeUtils.import("resource:///modules/BrowserErrorReporter.jsm", this);
 
+Cu.importGlobalProperties(["fetch"]);
+
 /* global sinon */
 Services.scriptloader.loadSubScript("resource://testing-common/sinon-2.3.2.js");
 registerCleanupFunction(function() {
   delete window.sinon;
 });
 
 const PREF_ENABLED = "browser.chrome.errorReporter.enabled";
 const PREF_PROJECT_ID = "browser.chrome.errorReporter.projectId";
@@ -82,326 +84,326 @@ function fetchCallForMessage(fetchSpy, m
 
 // Helper to test if a fetch spy was called with the given error message.
 // Used in tests where unrelated JS errors from other code are logged.
 function fetchPassedError(fetchSpy, message) {
   return fetchCallForMessage(fetchSpy, message) !== null;
 }
 
 add_task(async function testInitPrefDisabled() {
-  const fetch = sinon.spy();
-  const reporter = new BrowserErrorReporter(fetch);
+  const fetchSpy = sinon.spy();
+  const reporter = new BrowserErrorReporter(fetchSpy);
   await SpecialPowers.pushPrefEnv({set: [
     [PREF_ENABLED, false],
     [PREF_SAMPLE_RATE, "1.0"],
   ]});
 
   reporter.init();
   await logMessage(createScriptError({message: "Logged while disabled"}));
   ok(
-    !fetchPassedError(fetch, "Logged while disabled"),
+    !fetchPassedError(fetchSpy, "Logged while disabled"),
     "Reporter does not listen for errors if the enabled pref is false.",
   );
   reporter.uninit();
   resetConsole();
 });
 
 add_task(async function testInitUninitPrefEnabled() {
-  const fetch = sinon.spy();
-  const reporter = new BrowserErrorReporter(fetch);
+  const fetchSpy = sinon.spy();
+  const reporter = new BrowserErrorReporter(fetchSpy);
   await SpecialPowers.pushPrefEnv({set: [
     [PREF_ENABLED, true],
     [PREF_SAMPLE_RATE, "1.0"],
   ]});
 
   reporter.init();
   await logMessage(createScriptError({message: "Logged after init"}));
   ok(
-    fetchPassedError(fetch, "Logged after init"),
+    fetchPassedError(fetchSpy, "Logged after init"),
     "Reporter listens for errors if the enabled pref is true.",
   );
 
-  fetch.reset();
-  ok(!fetch.called, "Fetch spy was reset.");
+  fetchSpy.reset();
+  ok(!fetchSpy.called, "Fetch spy was reset.");
   reporter.uninit();
   await logMessage(createScriptError({message: "Logged after uninit"}));
   ok(
-    !fetchPassedError(fetch, "Logged after uninit"),
+    !fetchPassedError(fetchSpy, "Logged after uninit"),
     "Reporter does not listen for errors after uninit.",
   );
 
   resetConsole();
 });
 
 add_task(async function testInitPastMessages() {
-  const fetch = sinon.spy();
-  const reporter = new BrowserErrorReporter(fetch);
+  const fetchSpy = sinon.spy();
+  const reporter = new BrowserErrorReporter(fetchSpy);
   await SpecialPowers.pushPrefEnv({set: [
     [PREF_ENABLED, true],
     [PREF_SAMPLE_RATE, "1.0"],
   ]});
 
   await logMessage(createScriptError({message: "Logged before init"}));
   reporter.init();
   ok(
-    fetchPassedError(fetch, "Logged before init"),
+    fetchPassedError(fetchSpy, "Logged before init"),
     "Reporter collects errors logged before initialization.",
   );
   reporter.uninit();
   resetConsole();
 });
 
 add_task(async function testEnabledPrefWatcher() {
-  const fetch = sinon.spy();
-  const reporter = new BrowserErrorReporter(fetch);
+  const fetchSpy = sinon.spy();
+  const reporter = new BrowserErrorReporter(fetchSpy);
   await SpecialPowers.pushPrefEnv({set: [
     [PREF_ENABLED, false],
     [PREF_SAMPLE_RATE, "1.0"],
   ]});
 
   reporter.init();
   await logMessage(createScriptError({message: "Shouldn't report"}));
   ok(
-    !fetchPassedError(fetch, "Shouldn't report"),
+    !fetchPassedError(fetchSpy, "Shouldn't report"),
     "Reporter does not collect errors if the enable pref is false.",
   );
 
   await SpecialPowers.pushPrefEnv({set: [
     [PREF_ENABLED, true],
   ]});
   ok(
-    !fetchPassedError(fetch, "Shouldn't report"),
+    !fetchPassedError(fetchSpy, "Shouldn't report"),
     "Reporter does not collect past-logged errors if it is enabled mid-run.",
   );
   await logMessage(createScriptError({message: "Should report"}));
   ok(
-    fetchPassedError(fetch, "Should report"),
+    fetchPassedError(fetchSpy, "Should report"),
     "Reporter collects errors logged after the enabled pref is turned on mid-run",
   );
 
   reporter.uninit();
   resetConsole();
 });
 
 add_task(async function testNonErrorLogs() {
-  const fetch = sinon.spy();
-  const reporter = new BrowserErrorReporter(fetch);
+  const fetchSpy = sinon.spy();
+  const reporter = new BrowserErrorReporter(fetchSpy);
   await SpecialPowers.pushPrefEnv({set: [
     [PREF_ENABLED, true],
     [PREF_SAMPLE_RATE, "1.0"],
   ]});
 
   reporter.init();
 
   await logStringMessage("Not a scripterror instance.");
   ok(
-    !fetchPassedError(fetch, "Not a scripterror instance."),
+    !fetchPassedError(fetchSpy, "Not a scripterror instance."),
     "Reporter does not collect normal log messages or warnings.",
   );
 
   await logMessage(createScriptError({
     message: "Warning message",
     flags: Ci.nsIScriptError.warningFlag,
   }));
   ok(
-    !fetchPassedError(fetch, "Warning message"),
+    !fetchPassedError(fetchSpy, "Warning message"),
     "Reporter does not collect normal log messages or warnings.",
   );
 
   await logMessage(createScriptError({
     message: "Non-chrome category",
     category: "totally from a website",
   }));
   ok(
-    !fetchPassedError(fetch, "Non-chrome category"),
+    !fetchPassedError(fetchSpy, "Non-chrome category"),
     "Reporter does not collect normal log messages or warnings.",
   );
 
   await logMessage(createScriptError({message: "Is error"}));
   ok(
-    fetchPassedError(fetch, "Is error"),
+    fetchPassedError(fetchSpy, "Is error"),
     "Reporter collects error messages.",
   );
 
   reporter.uninit();
   resetConsole();
 });
 
 add_task(async function testSampling() {
-  const fetch = sinon.spy();
-  const reporter = new BrowserErrorReporter(fetch);
+  const fetchSpy = sinon.spy();
+  const reporter = new BrowserErrorReporter(fetchSpy);
   await SpecialPowers.pushPrefEnv({set: [
     [PREF_ENABLED, true],
     [PREF_SAMPLE_RATE, "1.0"],
   ]});
 
   reporter.init();
   await logMessage(createScriptError({message: "Should log"}));
   ok(
-    fetchPassedError(fetch, "Should log"),
+    fetchPassedError(fetchSpy, "Should log"),
     "A 1.0 sample rate will cause the reporter to always collect errors.",
   );
 
   await SpecialPowers.pushPrefEnv({set: [
     [PREF_SAMPLE_RATE, "0.0"],
   ]});
   await logMessage(createScriptError({message: "Shouldn't log"}));
   ok(
-    !fetchPassedError(fetch, "Shouldn't log"),
+    !fetchPassedError(fetchSpy, "Shouldn't log"),
     "A 0.0 sample rate will cause the reporter to never collect errors.",
   );
 
   await SpecialPowers.pushPrefEnv({set: [
     [PREF_SAMPLE_RATE, ")fasdf"],
   ]});
   await logMessage(createScriptError({message: "Also shouldn't log"}));
   ok(
-    !fetchPassedError(fetch, "Also shouldn't log"),
+    !fetchPassedError(fetchSpy, "Also shouldn't log"),
     "An invalid sample rate will cause the reporter to never collect errors.",
   );
 
   reporter.uninit();
   resetConsole();
 });
 
 add_task(async function testNameMessage() {
-  const fetch = sinon.spy();
-  const reporter = new BrowserErrorReporter(fetch);
+  const fetchSpy = sinon.spy();
+  const reporter = new BrowserErrorReporter(fetchSpy);
   await SpecialPowers.pushPrefEnv({set: [
     [PREF_ENABLED, true],
     [PREF_SAMPLE_RATE, "1.0"],
   ]});
 
   reporter.init();
   await logMessage(createScriptError({message: "No name"}));
-  let call = fetchCallForMessage(fetch, "No name");
+  let call = fetchCallForMessage(fetchSpy, "No name");
   let body = JSON.parse(call.args[1].body);
   is(
     body.exception.values[0].type,
     "Error",
     "Reporter uses a generic type when no name is in the message.",
   );
   is(
     body.exception.values[0].value,
     "No name",
     "Reporter uses error message as the exception value.",
   );
 
   await logMessage(createScriptError({message: "FooError: Has name"}));
-  call = fetchCallForMessage(fetch, "Has name");
+  call = fetchCallForMessage(fetchSpy, "Has name");
   body = JSON.parse(call.args[1].body);
   is(
     body.exception.values[0].type,
     "FooError",
     "Reporter uses the error type from the message.",
   );
   is(
     body.exception.values[0].value,
     "Has name",
     "Reporter uses error message as the value parameter.",
   );
 
   await logMessage(createScriptError({message: "FooError: Has :extra: colons"}));
-  call = fetchCallForMessage(fetch, "Has :extra: colons");
+  call = fetchCallForMessage(fetchSpy, "Has :extra: colons");
   body = JSON.parse(call.args[1].body);
   is(
     body.exception.values[0].type,
     "FooError",
     "Reporter uses the error type from the message.",
   );
   is(
     body.exception.values[0].value,
     "Has :extra: colons",
     "Reporter uses error message as the value parameter.",
   );
   reporter.uninit();
   resetConsole();
 });
 
 add_task(async function testFetchArguments() {
-  const fetch = sinon.spy();
-  const reporter = new BrowserErrorReporter(fetch);
+  const fetchSpy = sinon.spy();
+  const reporter = new BrowserErrorReporter(fetchSpy);
   await SpecialPowers.pushPrefEnv({set: [
     [PREF_ENABLED, true],
     [PREF_SAMPLE_RATE, "1.0"],
     [PREF_PROJECT_ID, "123"],
     [PREF_PUBLIC_KEY, "foobar"],
     [PREF_SUBMIT_URL, "https://errors.example.com/api/123/store/"],
   ]});
 
   reporter.init();
   const testPageUrl = (
     "chrome://mochitests/content/browser/browser/modules/test/browser/" +
     "browser_BrowserErrorReporter.html"
   );
-  const errorRaisedPromise = new Promise(resolve => {
-    Services.console.registerListener({
-      observe(loggedMessage) {
-        if (loggedMessage.message.toString().includes("testFetchArguments error")) {
-          Services.console.unregisterListener(this);
-          resolve();
-        }
-      },
-    });
-  });
 
   SimpleTest.expectUncaughtException();
   await BrowserTestUtils.withNewTab(testPageUrl, async () => {
-    await errorRaisedPromise;
-
-    const call = fetchCallForMessage(fetch, "testFetchArguments error");
+    const call = await TestUtils.waitForCondition(
+      () => fetchCallForMessage(fetchSpy, "testFetchArguments error"),
+      "Wait for error from browser_BrowserErrorReporter.html to be logged",
+    );
     const body = JSON.parse(call.args[1].body);
     const url = new URL(call.args[0]);
 
     is(url.origin, "https://errors.example.com", "Reporter builds API url from DSN pref.");
     is(url.pathname, "/api/123/store/", "Reporter builds API url from DSN pref.");
     is(
       url.searchParams.get("sentry_client"),
       "firefox-error-reporter/1.0.0",
       "Reporter identifies itself in the outgoing request",
     );
     is(url.searchParams.get("sentry_version"), "7", "Reporter is compatible with Sentry 7.");
     is(url.searchParams.get("sentry_key"), "foobar", "Reporter pulls API key from DSN pref.");
     is(body.project, "123", "Reporter pulls project ID from DSN pref.");
     is(call.args[1].referrer, "https://fake.mozilla.org", "Reporter uses a fake referer.");
 
+    const response = await fetch(testPageUrl);
+    const pageText = await response.text();
+    const pageLines = pageText.split("\n");
     Assert.deepEqual(
       body.exception,
       {
         values: [
           {
             type: "Error",
             value: "testFetchArguments error",
             stacktrace: {
               frames: [
                 {
-                  function: "madeToFail2",
-                  filename: testPageUrl,
-                  lineno: 15,
-                  colno: 15,
-                  in_app: true,
+                  function: null,
+                  module: testPageUrl,
+                  lineno: 17,
+                  colno: 7,
+                  pre_context: pageLines.slice(11, 16),
+                  context_line: pageLines[16],
+                  post_context: pageLines.slice(17, 22),
                 },
                 {
                   function: "madeToFail",
-                  filename: testPageUrl,
+                  module: testPageUrl,
                   lineno: 12,
                   colno: 9,
-                  in_app: true,
+                  pre_context: pageLines.slice(6, 11),
+                  context_line: pageLines[11],
+                  post_context: pageLines.slice(12, 17),
                 },
                 {
-                  function: null,
-                  filename: testPageUrl,
-                  lineno: 17,
-                  colno: 7,
-                  in_app: true,
-                }
-              ]
-            }
-          }
-        ]
+                  function: "madeToFail2",
+                  module: testPageUrl,
+                  lineno: 15,
+                  colno: 15,
+                  pre_context: pageLines.slice(9, 14),
+                  context_line: pageLines[14],
+                  post_context: pageLines.slice(15, 20),
+                },
+              ],
+            },
+          },
+        ],
       },
       "Reporter builds stack trace from scriptError correctly.",
     );
   });
 
   reporter.uninit();
   resetConsole();
 });
--- a/build/moz.configure/toolchain.configure
+++ b/build/moz.configure/toolchain.configure
@@ -641,16 +641,24 @@ def vc_compiler_path(host, target, vs_ma
 
 
 @depends(vc_compiler_path)
 @imports('os')
 def toolchain_search_path(vc_compiler_path):
     if vc_compiler_path:
         result = [os.environ.get('PATH')]
         result.extend(vc_compiler_path)
+
+        # Also add in the location to which `mach bootstrap` or
+        # `mach artifact toolchain` installs clang.
+        mozbuild_state_dir = os.environ.get('MOZBUILD_STATE_PATH',
+                                            os.path.expanduser(os.path.join('~', '.mozbuild')))
+        bootstrap_clang_path = os.path.join(mozbuild_state_dir, 'clang', 'bin')
+        result.append(bootstrap_clang_path)
+
         # We're going to alter PATH for good in windows.configure, but we also
         # need to do it for the valid_compiler() check below.
         os.environ['PATH'] = os.pathsep.join(result)
         return result
 
 
 @template
 def default_c_compilers(host_or_target):
--- a/caps/NullPrincipalURI.h
+++ b/caps/NullPrincipalURI.h
@@ -48,17 +48,17 @@ private:
 
   ~NullPrincipalURI() {}
 
   nsresult Init();
 
   nsAutoCStringN<NSID_LENGTH> mPath;
 
 public:
-  class Mutator
+  class Mutator final
       : public nsIURIMutator
       , public BaseURIMutator<NullPrincipalURI>
   {
     NS_DECL_ISUPPORTS
     NS_FORWARD_SAFE_NSIURISETTERS_RET(mURI)
 
     NS_IMETHOD Deserialize(const mozilla::ipc::URIParams& aParams) override
     {
--- a/docshell/base/nsDocShellTreeOwner.cpp
+++ b/docshell/base/nsDocShellTreeOwner.cpp
@@ -934,62 +934,69 @@ nsDocShellTreeOwner::HandleEvent(nsIDOME
   bool defaultPrevented;
   aEvent->GetDefaultPrevented(&defaultPrevented);
   if (defaultPrevented) {
     return NS_OK;
   }
 
   nsCOMPtr<nsIDroppedLinkHandler> handler =
     do_GetService("@mozilla.org/content/dropped-link-handler;1");
-  if (handler) {
-    nsAutoString eventType;
-    aEvent->GetType(eventType);
-    if (eventType.EqualsLiteral("dragover")) {
-      bool canDropLink = false;
-      handler->CanDropLink(dragEvent, false, &canDropLink);
-      if (canDropLink) {
-        aEvent->PreventDefault();
-      }
-    } else if (eventType.EqualsLiteral("drop")) {
-      nsIWebNavigation* webnav = static_cast<nsIWebNavigation*>(mWebBrowser);
+  if (!handler) {
+    return NS_OK;
+  }
 
-      uint32_t linksCount;
-      nsIDroppedLinkItem** links;
-      if (webnav &&
-          NS_SUCCEEDED(handler->DropLinks(dragEvent, true, &linksCount, &links))) {
-        if (linksCount >= 1) {
+  nsAutoString eventType;
+  aEvent->GetType(eventType);
+  if (eventType.EqualsLiteral("dragover")) {
+    bool canDropLink = false;
+    handler->CanDropLink(dragEvent, false, &canDropLink);
+    if (canDropLink) {
+      aEvent->PreventDefault();
+    }
+  } else if (eventType.EqualsLiteral("drop")) {
+    nsIWebNavigation* webnav = static_cast<nsIWebNavigation*>(mWebBrowser);
+
+    uint32_t linksCount;
+    nsIDroppedLinkItem** links;
+    if (webnav &&
+        NS_SUCCEEDED(handler->DropLinks(dragEvent, true, &linksCount, &links))) {
+      if (linksCount >= 1) {
+        nsCOMPtr<nsIPrincipal> triggeringPrincipal;
+        handler->GetTriggeringPrincipal(dragEvent,
+                                        getter_AddRefs(triggeringPrincipal));
+        if (triggeringPrincipal) {
           nsCOMPtr<nsIWebBrowserChrome> webBrowserChrome = GetWebBrowserChrome();
           if (webBrowserChrome) {
             nsCOMPtr<nsITabChild> tabChild = do_QueryInterface(webBrowserChrome);
             if (tabChild) {
               nsresult rv = tabChild->RemoteDropLinks(linksCount, links);
               for (uint32_t i = 0; i < linksCount; i++) {
                 NS_RELEASE(links[i]);
               }
               free(links);
               return rv;
             }
           }
           nsAutoString url;
           if (NS_SUCCEEDED(links[0]->GetUrl(url))) {
             if (!url.IsEmpty()) {
               webnav->LoadURI(url.get(), 0, nullptr, nullptr, nullptr,
-                              nsContentUtils::GetSystemPrincipal());
+                              triggeringPrincipal);
             }
           }
 
           for (uint32_t i = 0; i < linksCount; i++) {
             NS_RELEASE(links[i]);
           }
           free(links);
         }
-      } else {
-        aEvent->StopPropagation();
-        aEvent->PreventDefault();
       }
+    } else {
+      aEvent->StopPropagation();
+      aEvent->PreventDefault();
     }
   }
 
   return NS_OK;
 }
 
 already_AddRefed<nsIWebBrowserChrome>
 nsDocShellTreeOwner::GetWebBrowserChrome()
--- a/dom/base/contentAreaDropListener.js
+++ b/dom/base/contentAreaDropListener.js
@@ -1,12 +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/. */
 
+ChromeUtils.import("resource://gre/modules/Services.jsm");
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 ChromeUtils.import("resource://gre/modules/osfile.jsm");
 
 // This component is used for handling dragover and drop of urls.
 //
 // It checks to see whether a drop of a url is allowed. For instance, a url
 // cannot be dropped if it is not a valid uri or the source of the drag cannot
 // access the uri. This prevents, for example, a source document from tricking
@@ -57,18 +58,42 @@ ContentAreaDropListener.prototype =
       }
     }
 
     for (let type of ["text/plain", "text/x-moz-text-internal"]) {
       if (types.contains(type)) {
         data = dt.mozGetDataAt(type, i);
         if (data) {
           let lines = data.replace(/^\s+|\s+$/mg, "").split("\n");
+          if (!lines.length) {
+            return;
+          }
+
+          // For plain text, there are 2 cases:
+          //   * if there is at least one URI:
+          //       Add all URIs, ignoring non-URI lines, so that all URIs
+          //       are opened in tabs.
+          //   * if there's no URI:
+          //       Add the entire text as a single entry, so that the entire
+          //       text is searched.
+          let hasURI = false;
+          let flags = Ci.nsIURIFixup.FIXUP_FLAG_FIX_SCHEME_TYPOS |
+              Ci.nsIURIFixup.FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP;
           for (let line of lines) {
-            this._addLink(links, line, line, type);
+            let info = Services.uriFixup.getFixupURIInfo(line, flags);
+            if (info.fixedURI) {
+              // Use the original line here, and let the caller decide
+              // whether to perform fixup or not.
+              hasURI = true;
+              this._addLink(links, line, line, type);
+            }
+          }
+
+          if (!hasURI) {
+            this._addLink(links, data, data, type);
           }
           return;
         }
       }
     }
 
     // For shortcuts, we want to check for the file type last, so that the
     // url pointed to in one of the url types is found first before the file
@@ -84,49 +109,51 @@ ContentAreaDropListener.prototype =
   {
     let links = [];
     for (let i = 0; i < dt.mozItemCount; i++) {
       this._addLinksFromItem(links, dt, i);
     }
     return links;
   },
 
-  _validateURI: function(dataTransfer, uriString, disallowInherit)
+  _validateURI: function(dataTransfer, uriString, disallowInherit,
+                         triggeringPrincipal)
   {
     if (!uriString)
       return "";
 
     // Strip leading and trailing whitespace, then try to create a
     // URI from the dropped string. If that succeeds, we're
     // dropping a URI and we need to do a security check to make
     // sure the source document can load the dropped URI.
     uriString = uriString.replace(/^\s*|\s*$/g, '');
 
-    let uri;
-    let ioService = Cc["@mozilla.org/network/io-service;1"]
-                      .getService(Components.interfaces.nsIIOService);
-    try {
-      // Check that the uri is valid first and return an empty string if not.
-      // It may just be plain text and should be ignored here
-      uri = ioService.newURI(uriString);
-    } catch (ex) { }
-    if (!uri)
+    // Apply URI fixup so that this validation prevents bad URIs even if the
+    // similar fixup is applied later, especialy fixing typos up will convert
+    // non-URI to URI.
+    let fixupFlags = Ci.nsIURIFixup.FIXUP_FLAG_FIX_SCHEME_TYPOS |
+        Ci.nsIURIFixup.FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP;
+    let info = Services.uriFixup.getFixupURIInfo(uriString, fixupFlags);
+    if (!info.fixedURI || info.keywordProviderName) {
+      // Loading a keyword search should always be fine for all cases.
       return uriString;
+    }
+    let uri = info.fixedURI;
 
-    // uriString is a valid URI, so do the security check.
     let secMan = Cc["@mozilla.org/scriptsecuritymanager;1"].
                    getService(Ci.nsIScriptSecurityManager);
     let flags = secMan.STANDARD;
     if (disallowInherit)
       flags |= secMan.DISALLOW_INHERIT_PRINCIPAL;
 
-    let principal = this._getTriggeringPrincipalFromDataTransfer(dataTransfer, false);
-    secMan.checkLoadURIStrWithPrincipal(principal, uriString, flags);
+    secMan.checkLoadURIWithPrincipal(triggeringPrincipal, uri, flags);
 
-    return uriString;
+    // Once we validated, return the URI after fixup, instead of the original
+    // uriString.
+    return uri.spec;
   },
 
   _getTriggeringPrincipalFromDataTransfer: function(aDataTransfer,
                                                     fallbackToSystemPrincipal)
   {
     let sourceNode = aDataTransfer.mozSourceNode;
     if (sourceNode &&
         (sourceNode.localName !== "browser" ||
@@ -231,34 +258,47 @@ ContentAreaDropListener.prototype =
 
   dropLinks: function(aEvent, aDisallowInherit, aCount)
   {
     if (aEvent && this._eventTargetIsDisabled(aEvent))
       return [];
 
     let dataTransfer = aEvent.dataTransfer;
     let links = this._getDropLinks(dataTransfer);
+    let triggeringPrincipal = this._getTriggeringPrincipalFromDataTransfer(dataTransfer, false);
 
     for (let link of links) {
       try {
-        link.url = this._validateURI(dataTransfer, link.url, aDisallowInherit);
+        link.url = this._validateURI(dataTransfer, link.url, aDisallowInherit,
+                                     triggeringPrincipal);
       } catch (ex) {
         // Prevent the drop entirely if any of the links are invalid even if
         // one of them is valid.
         aEvent.stopPropagation();
         aEvent.preventDefault();
         throw ex;
       }
     }
     if (aCount)
       aCount.value = links.length;
 
     return links;
   },
 
+  validateURIsForDrop: function(aEvent, aURIsCount, aURIs, aDisallowInherit)
+  {
+    let dataTransfer = aEvent.dataTransfer;
+    let triggeringPrincipal = this._getTriggeringPrincipalFromDataTransfer(dataTransfer, false);
+
+    for (let uri of aURIs) {
+      this._validateURI(dataTransfer, uri, aDisallowInherit,
+                        triggeringPrincipal);
+    }
+  },
+
   queryLinks: function(aDataTransfer, aCount)
   {
     let links = this._getDropLinks(aDataTransfer);
     if (aCount) {
       aCount.value = links.length;
     }
     return links;
   },
--- a/dom/base/nsIDroppedLinkHandler.idl
+++ b/dom/base/nsIDroppedLinkHandler.idl
@@ -76,16 +76,26 @@ interface nsIDroppedLinkHandler : nsISup
    *    current document's security context (URI_INHERITS_SECURITY_CONTEXT).
    */
   void dropLinks(in nsIDOMDragEvent aEvent,
                  [optional] in boolean aDisallowInherit,
                  [optional] out unsigned long aCount,
                  [retval, array, size_is(aCount)] out nsIDroppedLinkItem aLinks);
 
   /**
+   * Given a drop event aEvent, validate the extra URIs for the event,
+   * this is used when the caller extracts yet another URIs from the dropped
+   * text, like home button that splits the text with "|".
+   */
+  void validateURIsForDrop(in nsIDOMDragEvent aEvent,
+                           in unsigned long aURIsCount,
+                           [array, size_is(aURIsCount)] in wstring aURIs,
+                           [optional] in boolean aDisallowInherit);
+
+  /**
    * Given a dataTransfer, allows caller to determine and verify links being
    * dragged. Since drag/drop performs a roundtrip of parent, child, parent,
    * it allows the parent to verify that the child did not modify links
    * being dropped.
    */
   void queryLinks(in nsIDOMDataTransfer aDataTransfer,
                   [optional] out unsigned long aCount,
                   [retval, array, size_is(aCount)] out nsIDroppedLinkItem aLinks);
--- a/dom/file/nsHostObjectURI.h
+++ b/dom/file/nsHostObjectURI.h
@@ -20,20 +20,21 @@
 #include "nsWeakReference.h"
 
 
 /**
  * These URIs refer to host objects: Blobs, with scheme "blob",
  * MediaStreams, with scheme "mediastream", and MediaSources, with scheme
  * "mediasource".
  */
-class nsHostObjectURI : public mozilla::net::nsSimpleURI
-                      , public nsIURIWithPrincipal
-                      , public nsIURIWithBlobImpl
-                      , public nsSupportsWeakReference
+class nsHostObjectURI final
+  : public mozilla::net::nsSimpleURI
+  , public nsIURIWithPrincipal
+  , public nsIURIWithBlobImpl
+  , public nsSupportsWeakReference
 {
 public:
   nsHostObjectURI(nsIPrincipal* aPrincipal,
                   mozilla::dom::BlobImpl* aBlobImpl)
     : mozilla::net::nsSimpleURI()
     , mPrincipal(aPrincipal)
     , mBlobImpl(aBlobImpl)
   {}
@@ -73,17 +74,17 @@ public:
 
   nsCOMPtr<nsIPrincipal> mPrincipal;
   RefPtr<mozilla::dom::BlobImpl> mBlobImpl;
 
 protected:
   virtual ~nsHostObjectURI() {}
 
 public:
-  class Mutator
+  class Mutator final
     : public nsIURIMutator
     , public BaseURIMutator<nsHostObjectURI>
     , public nsIBlobURIMutator
     , public nsIPrincipalURIMutator
   {
     NS_DECL_ISUPPORTS
     NS_FORWARD_SAFE_NSIURISETTERS_RET(mURI)
     NS_DEFINE_NSIMUTATOR_COMMON
--- a/dom/jsurl/nsJSProtocolHandler.h
+++ b/dom/jsurl/nsJSProtocolHandler.h
@@ -56,17 +56,18 @@ protected:
 
     nsresult EnsureUTF8Spec(const nsCString& aSpec, const char *aCharset,
                             nsACString &aUTF8Spec);
 
     nsCOMPtr<nsITextToSubURI>  mTextToSubURI;
 };
 
 
-class nsJSURI : public mozilla::net::nsSimpleURI
+class nsJSURI final
+    : public mozilla::net::nsSimpleURI
 {
 public:
     using mozilla::net::nsSimpleURI::Read;
     using mozilla::net::nsSimpleURI::Write;
 
     nsJSURI() {}
 
     explicit nsJSURI(nsIURI* aBaseURI) : mBaseURI(aBaseURI) {}
@@ -100,17 +101,17 @@ protected:
 
     virtual nsresult EqualsInternal(nsIURI* other,
                                     RefHandlingEnum refHandlingMode,
                                     bool* result) override;
 private:
     nsCOMPtr<nsIURI> mBaseURI;
 
 public:
-    class Mutator
+    class Mutator final
         : public nsIURIMutator
         , public BaseURIMutator<nsJSURI>
     {
         NS_DECL_ISUPPORTS
         NS_FORWARD_SAFE_NSIURISETTERS_RET(mURI)
         NS_DEFINE_NSIMUTATOR_COMMON
 
         explicit Mutator() { }
--- a/dom/media/webspeech/synth/SpeechSynthesis.cpp
+++ b/dom/media/webspeech/synth/SpeechSynthesis.cpp
@@ -132,16 +132,20 @@ bool SpeechSynthesis::HasVoices() const
   }
 
   return voiceCount != 0;
 }
 
 void
 SpeechSynthesis::Speak(SpeechSynthesisUtterance& aUtterance)
 {
+  if (!mInnerID) {
+    return;
+  }
+
   if (aUtterance.mState != SpeechSynthesisUtterance::STATE_NONE) {
     // XXX: Should probably raise an error
     return;
   }
 
   mSpeechQueue.AppendElement(&aUtterance);
   aUtterance.mState = SpeechSynthesisUtterance::STATE_PENDING;
 
@@ -312,16 +316,17 @@ SpeechSynthesis::Observe(nsISupports* aS
     nsCOMPtr<nsISupportsPRUint64> wrapper = do_QueryInterface(aSubject);
     NS_ENSURE_TRUE(wrapper, NS_ERROR_FAILURE);
 
     uint64_t innerID;
     nsresult rv = wrapper->GetData(&innerID);
     NS_ENSURE_SUCCESS(rv, rv);
 
     if (innerID == mInnerID) {
+      mInnerID = 0;
       Cancel();
 
       nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
       if (obs) {
         obs->RemoveObserver(this, "inner-window-destroyed");
       }
     }
   } else if (strcmp(aTopic, "synth-voices-changed") == 0) {
--- a/dom/serviceworkers/test/browser_download_canceled.js
+++ b/dom/serviceworkers/test/browser_download_canceled.js
@@ -28,54 +28,35 @@ const { Downloads } = ChromeUtils.import
 async function clearDownloads() {
   const downloads = await Downloads.getList(Downloads.ALL);
   downloads.removeFinished();
 }
 
 /**
  * Returns a Promise that will be resolved once the download dialog shows up and
  * we have clicked the given button.
- *
- * Derived from browser/components/downloads/test/browser/head.js's
- * self-contained promiseAlertDialogOpen helper, but modified to work on the
- * download dialog instead of commonDialog.xul.
  */
 function promiseClickDownloadDialogButton(buttonAction) {
-  return new Promise(resolve => {
-    Services.ww.registerNotification(function onOpen(win, topic, data) {
-      if (topic === "domwindowopened" && win instanceof Ci.nsIDOMWindow) {
-        // The test listens for the "load" event which guarantees that the alert
-        // class has already been added (it is added when "DOMContentLoaded" is
-        // fired).
-        win.addEventListener("load", function() {
-          info(`found window of type: ${win.document.documentURI}`);
-          if (win.document.documentURI ===
-                "chrome://mozapps/content/downloads/unknownContentType.xul") {
-            Services.ww.unregisterNotification(onOpen);
+  const uri = "chrome://mozapps/content/downloads/unknownContentType.xul";
+  BrowserTestUtils.promiseAlertDialogOpen(buttonAction, uri, async win => {
+    // nsHelperAppDlg.js currently uses an eval-based setTimeout(0) to invoke
+    // its postShowCallback that results in a misleading error to the console
+    // if we close the dialog before it gets a chance to run.  Just a
+    // setTimeout is not sufficient because it appears we get our "load"
+    // listener before the document's, so we use TestUtils.waitForTick() to
+    // defer until after its load handler runs, then use setTimeout(0) to end
+    // up after its eval.
+    await TestUtils.waitForTick();
 
-            // nsHelperAppDlg.js currently uses an eval-based setTimeout(0) to
-            // invoke its postShowCallback that results in a misleading error to
-            // the console if we close the dialog before it gets a chance to
-            // run.  Just a setTimeout is not sufficient because it appears we
-            // get our "load" listener before the document's, so we use
-            // executeSoon to defer until after its load handler runs, then
-            // use setTimeout(0) to end up after its eval.
-            executeSoon(function() {
-              setTimeout(function() {
-                const button = win.document.documentElement.getButton(buttonAction);
-                button.disabled = false;
-                info(`clicking ${buttonAction} button`);
-                button.click();
-                resolve();
-              }, 0);
-            });
-          }
-        }, {once: true});
-      }
-    });
+    await new Promise(resolve => setTimeout(resolve, 0));
+
+    const button = win.document.documentElement.getButton(buttonAction);
+    button.disabled = false;
+    info(`clicking ${buttonAction} button`);
+    button.click();
   });
 }
 
 async function performCanceledDownload(tab, path) {
   // Start waiting for the download dialog before triggering the download.
   info("watching for download popup");
   const cancelDownload = promiseClickDownloadDialogButton("cancel");
 
@@ -158,9 +139,9 @@ add_task(async function interruptedDownl
   await ContentTask.spawn(
     tab.linkedBrowser,
     null,
     function() {
       return content.wrappedJSObject.registration.unregister();
     });
   await BrowserTestUtils.removeTab(tab);
   await clearDownloads();
-});
\ No newline at end of file
+});
--- a/gfx/harfbuzz/NEWS
+++ b/gfx/harfbuzz/NEWS
@@ -1,8 +1,17 @@
+Overview of changes leading to 1.7.5
+Tuesday, January 30, 2018
+====================================
+
+- Separate Khmer shaper from Indic.
+- First stab at AAT morx. Not hooked up.
+- Misc bug fixes.
+
+
 Overview of changes leading to 1.7.4
 Wednesday, December 20, 2017
 ====================================
 
 - Fix collect_glyphs() regression caused by hb_set_t changes.
 
 
 Overview of changes leading to 1.7.3
--- a/gfx/harfbuzz/README
+++ b/gfx/harfbuzz/README
@@ -1,11 +1,12 @@
 [![Build Status](https://travis-ci.org/harfbuzz/harfbuzz.svg)](https://travis-ci.org/harfbuzz/harfbuzz)
 [![Build status](https://ci.appveyor.com/api/projects/status/0t0flrxpstj9lb9w?svg=true)](https://ci.appveyor.com/project/harfbuzz/harfbuzz)
 [![CircleCI](https://circleci.com/gh/harfbuzz/harfbuzz.svg?style=svg)](https://circleci.com/gh/harfbuzz/harfbuzz)
+[![Coverity](https://img.shields.io/coverity/scan/5450.svg)](https://scan.coverity.com/projects/behdad-harfbuzz)
 [![Coverage Status](https://img.shields.io/coveralls/harfbuzz/harfbuzz.svg)](https://coveralls.io/r/harfbuzz/harfbuzz)
 [ABI Tracker](http://abi-laboratory.pro/tracker/timeline/harfbuzz/)
 
 This is HarfBuzz, a text shaping library.
 
 For bug reports, mailing list, and other information please visit:
 
   http://harfbuzz.org/
--- a/gfx/harfbuzz/README-mozilla
+++ b/gfx/harfbuzz/README-mozilla
@@ -1,14 +1,14 @@
-gfx/harfbuzz status as of 2017-12-20:
+gfx/harfbuzz status as of 2018-01-30:
 
 This directory contains the HarfBuzz source from the 'master' branch of
 https://github.com/behdad/harfbuzz.
 
-Current version: 1.7.4
+Current version: 1.7.5
 
 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/autogen.sh
+++ b/gfx/harfbuzz/autogen.sh
@@ -37,10 +37,12 @@ which autoreconf || {
 	echo "*** No autoreconf (autoconf) found, please install it ***"
 	exit 1
 }
 
 echo "running autoreconf --force --install --verbose"
 autoreconf --force --install --verbose || exit $?
 
 cd $olddir
-echo "running configure $@"
-test -n "$NOCONFIGURE" || "$srcdir/configure" "$@"
+test -n "$NOCONFIGURE" || {
+	echo "running configure $@"
+	"$srcdir/configure" "$@"
+}
--- a/gfx/harfbuzz/configure.ac
+++ b/gfx/harfbuzz/configure.ac
@@ -1,34 +1,33 @@
 AC_PREREQ([2.64])
 AC_INIT([HarfBuzz],
-        [1.7.4],
+        [1.7.5],
         [https://github.com/harfbuzz/harfbuzz/issues/new],
         [harfbuzz],
         [http://harfbuzz.org/])
 
 AC_CONFIG_MACRO_DIR([m4])
 AC_CONFIG_SRCDIR([src/harfbuzz.pc.in])
 AC_CONFIG_HEADERS([config.h])
 
-AM_INIT_AUTOMAKE([1.11.1 gnits tar-ustar dist-bzip2 no-dist-gzip -Wall no-define color-tests -Wno-portability])
-AM_CONDITIONAL(AUTOMAKE_OLDER_THAN_1_13, test $am__api_version = 1.11 -o $am__api_version = 1.12)
+AM_INIT_AUTOMAKE([1.13.0 gnits tar-ustar dist-bzip2 no-dist-gzip -Wall no-define color-tests -Wno-portability])
 AM_SILENT_RULES([yes])
 
 # Initialize libtool
 m4_ifdef([AM_PROG_AR], [AM_PROG_AR])
 LT_PREREQ([2.2])
 LT_INIT([disable-static])
 
 # Check for programs
 AC_USE_SYSTEM_EXTENSIONS
 AC_PROG_CC
 AM_PROG_CC_C_O
 AC_PROG_CXX
-AX_CXX_COMPILE_STDCXX(11, noext, optional)
+dnl AX_CXX_COMPILE_STDCXX(11, noext, optional)
 AC_SYS_LARGEFILE
 PKG_PROG_PKG_CONFIG([0.20])
 AM_MISSING_PROG([RAGEL], [ragel])
 AM_MISSING_PROG([GIT], [git])
 
 # Version
 m4_define(hb_version_triplet,m4_split(AC_PACKAGE_VERSION,[[.]]))
 m4_define(hb_version_major,m4_argn(1,hb_version_triplet))
@@ -79,16 +78,19 @@ AC_CHECK_ALIGNOF([struct{char;}])
 if test "x$GCC" = "xyes"; then
 
 	# Make symbols link locally
 	LDFLAGS="$LDFLAGS -Bsymbolic-functions"
 
 	# Make sure we don't link to libstdc++
 	CXXFLAGS="$CXXFLAGS -fno-rtti -fno-exceptions"
 
+	# No threadsafe statics and C++ as we do it ourselves
+	CXXFLAGS="$CXXFLAGS -fno-threadsafe-statics"
+
 	# Assorted warnings
 	CXXFLAGS="$CXXFLAGS -Wcast-align"
 
 	case "$host" in
 		*-*-mingw*)
 		;;
 		*)
 			# Hide inline methods
@@ -350,16 +352,17 @@ if test "x$with_freetype" = "xyes" -a "x
 	AC_MSG_ERROR([FreeType support requested but libfreetype2 not found])
 fi
 if $have_freetype; then
 	AC_DEFINE(HAVE_FREETYPE, 1, [Have FreeType 2 library])
 	save_libs=$LIBS
 	LIBS="$LIBS $FREETYPE_LIBS"
 	AC_CHECK_FUNCS(FT_Get_Var_Blend_Coordinates)
 	AC_CHECK_FUNCS(FT_Set_Var_Blend_Coordinates)
+	AC_CHECK_FUNCS(FT_Done_MM_Var)
 	LIBS=$save_libs
 fi
 AM_CONDITIONAL(HAVE_FREETYPE, $have_freetype)
 
 dnl ===========================================================================
 
 AC_ARG_WITH(uniscribe,
 	[AS_HELP_STRING([--with-uniscribe=@<:@yes/no/auto@:>@],
@@ -424,17 +427,17 @@ if test "x$with_coretext" = "xyes" -o "x
 		# On iOS CoreText and CoreGraphics are stand-alone frameworks
 		if test "x$have_coretext" != "xtrue"; then
 			# Check for a different symbol to avoid getting cached result.
 			AC_CHECK_TYPE(CTRunRef, have_coretext=true,, [#include <CoreText/CoreText.h>])
 		fi
 
 		if $have_coretext; then
 			CORETEXT_CFLAGS=
-			CORETEXT_LIBS="-framework CoreText -framework CoreGraphics"
+			CORETEXT_LIBS="-framework CoreText -framework CoreGraphics -framework CoreFoundation"
 			AC_SUBST(CORETEXT_CFLAGS)
 			AC_SUBST(CORETEXT_LIBS)
 		fi
 	fi
 fi
 if test "x$with_coretext" = "xyes" -a "x$have_coretext" != "xtrue"; then
 	AC_MSG_ERROR([CoreText support requested but libcoretext not found])
 fi
@@ -489,16 +492,19 @@ Makefile
 src/Makefile
 src/hb-version.h
 src/hb-ucdn/Makefile
 util/Makefile
 test/Makefile
 test/api/Makefile
 test/fuzzing/Makefile
 test/shaping/Makefile
+test/shaping/data/Makefile
+test/shaping/data/in-house/Makefile
+test/shaping/data/text-rendering-tests/Makefile
 docs/Makefile
 docs/version.xml
 ])
 
 AC_OUTPUT
 
 AC_MSG_NOTICE([
 
--- a/gfx/harfbuzz/src/Makefile.am
+++ b/gfx/harfbuzz/src/Makefile.am
@@ -1,10 +1,11 @@
 # Process this file with automake to produce Makefile.in
 
+NULL =
 SUBDIRS =
 DIST_SUBDIRS =
 BUILT_SOURCES =
 EXTRA_DIST =
 CLEANFILES =
 DISTCLEANFILES =
 MAINTAINERCLEANFILES =
 DISTCHECK_CONFIGURE_FLAGS = --enable-introspection
@@ -129,17 +130,17 @@ libharfbuzz_la_LDFLAGS = $(AM_LDFLAGS) -
 libharfbuzz_la_LIBADD = $(HBLIBS)
 EXTRA_libharfbuzz_la_DEPENDENCIES = $(harfbuzz_def_dependency)
 pkginclude_HEADERS = $(HBHEADERS)
 nodist_pkginclude_HEADERS = $(HBNODISTHEADERS)
 pkgconfigdir = $(libdir)/pkgconfig
 pkgconfig_DATA = harfbuzz.pc
 EXTRA_DIST += harfbuzz.pc.in
 
-FUZZING_CPPFLAGS= \
+FUZZING_CPPFLAGS = \
 	-DHB_NDEBUG \
 	-DHB_MAX_NESTING_LEVEL=3 \
 	-DHB_SANITIZE_MAX_EDITS=3 \
 	-DHB_BUFFER_MAX_LEN_FACTOR=3 \
 	-DHB_BUFFER_MAX_LEN_MIN=8 \
 	-DHB_BUFFER_MAX_LEN_DEFAULT=128 \
 	-DHB_BUFFER_MAX_OPS_FACTOR=8 \
 	-DHB_BUFFER_MAX_OPS_MIN=64 \
@@ -217,31 +218,24 @@ EXTRA_DIST += \
 	"$<" > "$@" \
 	|| ($(RM) "$@"; false)
 
 CLEANFILES += $(pkgconfig_DATA)
 
 
 CLEANFILES += harfbuzz.def
 harfbuzz.def: $(HBHEADERS) $(HBNODISTHEADERS)
-	$(AM_V_GEN) (echo EXPORTS; \
-	(cat $^ || echo 'hb_ERROR ()' ) | \
-	$(EGREP) '^hb_.* \(' | \
-	sed -e 's/ (.*//' | \
-	LC_ALL=C sort; \
-	echo LIBRARY libharfbuzz-0.dll; \
-	) >"$@"
-	@ ! grep -q hb_ERROR "$@" \
-	|| ($(RM) "$@"; false)
+	$(AM_V_GEN) headers="$^" $(srcdir)/gen-def.py $@
 
 
 GENERATORS = \
 	gen-arabic-table.py \
 	gen-indic-table.py \
 	gen-use-table.py \
+	gen-def.py \
 	$(NULL)
 EXTRA_DIST += $(GENERATORS)
 
 unicode-tables: arabic-table indic-table use-table
 
 arabic-table: gen-arabic-table.py ArabicShaping.txt UnicodeData.txt Blocks.txt
 	$(AM_V_GEN) $(builddir)/$^ > hb-ot-shape-complex-arabic-table.hh \
 	|| ($(RM) hb-ot-shape-complex-arabic-table.hh; false)
--- a/gfx/harfbuzz/src/check-c-linkage-decls.sh
+++ b/gfx/harfbuzz/src/check-c-linkage-decls.sh
@@ -2,18 +2,17 @@
 
 LC_ALL=C
 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'`
-
+test "x$HBSOURCES" = x && HBSOURCES=`cd "$srcdir"; find . -maxdepth 1 -name 'hb*.cc'`
 
 for x in $HBHEADERS; do
 	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
--- a/gfx/harfbuzz/src/check-defs.sh
+++ b/gfx/harfbuzz/src/check-defs.sh
@@ -1,44 +1,54 @@
 #!/bin/sh
 
 LC_ALL=C
 export LC_ALL
 
 test -z "$srcdir" && srcdir=.
-test -z "$MAKE" && MAKE=make
+test -z "$libs" && libs=.libs
 stat=0
 
 if which nm 2>/dev/null >/dev/null; then
 	:
 else
 	echo "check-defs.sh: 'nm' not found; skipping test"
 	exit 77
 fi
 
 defs="harfbuzz.def"
-$MAKE $defs > /dev/null
+if ! test -f "$defs"; then
+	echo "check-defs.sh: '$defs' not found; skipping test"
+	exit 77
+fi
+
 tested=false
 for def in $defs; do
 	lib=`echo "$def" | sed 's/[.]def$//;s@.*/@@'`
-	so=.libs/lib${lib}.so
+	for suffix in so dylib; do
+		so=$libs/lib${lib}.$suffix
+		if ! test -f "$so"; then continue; fi
 
-	EXPORTED_SYMBOLS="`nm "$so" | grep ' [BCDGINRSTVW] .' | grep -v ' _fini\>\| _init\>\| _fdata\>\| _ftext\>\| _fbss\>\| __bss_start\>\| __bss_start__\>\| __bss_end__\>\| _edata\>\| _end\>\| _bss_end__\>\| __end__\>\| __gcov_flush\>\| llvm_' | cut -d' ' -f3`"
+		# On mac, C symbols are prefixed with _
+		if test $suffix = dylib; then prefix="_"; fi
 
-	if test -f "$so"; then
+		EXPORTED_SYMBOLS="`nm "$so" | grep ' [BCDGINRSTVW] .' | grep -v " $prefix"'\(_fini\>\|_init\>\|_fdata\>\|_ftext\>\|_fbss\>\|__bss_start\>\|__bss_start__\>\|__bss_end__\>\|_edata\>\|_end\>\|_bss_end__\>\|__end__\>\|__gcov_flush\>\|llvm_\)' | cut -d' ' -f3`"
+
+		if test -f "$so"; then
 
-		echo "Checking that $so has the same symbol list as $def"
-		{
-			echo EXPORTS
-			echo "$EXPORTED_SYMBOLS"
-			# cheat: copy the last line from the def file!
-			tail -n1 "$def"
-		} | diff "$def" - >&2 || stat=1
+			echo "Checking that $so has the same symbol list as $def"
+			{
+				echo EXPORTS
+				echo "$EXPORTED_SYMBOLS" | sed -e "s/^${prefix}hb/hb/g"
+				# cheat: copy the last line from the def file!
+				tail -n1 "$def"
+			} | diff "$def" - >&2 || stat=1
 
-		tested=true
-	fi
+			tested=true
+		fi
+	done
 done
 if ! $tested; then
 	echo "check-defs.sh: libharfbuzz shared library not found; skipping test"
 	exit 77
 fi
 
 exit $stat
--- a/gfx/harfbuzz/src/check-header-guards.sh
+++ b/gfx/harfbuzz/src/check-header-guards.sh
@@ -1,17 +1,17 @@
 #!/bin/sh
 
 LC_ALL=C
 export LC_ALL
 
 test -z "$srcdir" && srcdir=.
 stat=0
 
-test "x$HBHEADERS" = x && HBHEADERS=`cd "$srcdir"; find . -maxdepth 1 -name 'hb*.h'`
+test "x$HBHEADERS" = x && HBHEADERS=`cd "$srcdir"; find . -maxdepth 1 -name 'hb*.h' ! -name 'hb-gobject-structs.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" -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'`
--- a/gfx/harfbuzz/src/check-libstdc++.sh
+++ b/gfx/harfbuzz/src/check-libstdc++.sh
@@ -1,31 +1,37 @@
 #!/bin/sh
 
 LC_ALL=C
 export LC_ALL
 
 test -z "$srcdir" && srcdir=.
+test -z "$libs" && libs=.libs
 stat=0
 
 
 if which ldd 2>/dev/null >/dev/null; then
-	:
+	LDD=ldd
 else
-	echo "check-libstdc++.sh: 'ldd' not found; skipping test"
-	exit 77
+	# macOS specific tool
+	if which otool 2>/dev/null >/dev/null; then
+		LDD="otool -L"
+	else
+		echo "check-libstdc++.sh: 'ldd' not found; skipping test"
+		exit 77
+	fi
 fi
 
 tested=false
 for suffix in so dylib; do
-	so=.libs/libharfbuzz.$suffix
+	so=$libs/libharfbuzz.$suffix
 	if ! test -f "$so"; then continue; fi
 
 	echo "Checking that we are not linking to libstdc++ or libc++"
-	if ldd $so | grep 'libstdc[+][+]\|libc[+][+]'; then
+	if $LDD $so | grep 'libstdc[+][+]\|libc[+][+]'; then
 		echo "Ouch, linked to libstdc++ or libc++"
 		stat=1
 	fi
 	tested=true
 done
 if ! $tested; then
 	echo "check-libstdc++.sh: libharfbuzz shared library not found; skipping test"
 	exit 77
--- a/gfx/harfbuzz/src/check-static-inits.sh
+++ b/gfx/harfbuzz/src/check-static-inits.sh
@@ -1,25 +1,26 @@
 #!/bin/sh
 
 LC_ALL=C
 export LC_ALL
 
 test -z "$srcdir" && srcdir=.
+test -z "$libs" && libs=.libs
 stat=0
 
 
 if which objdump 2>/dev/null >/dev/null; then
 	:
 else
 	echo "check-static-inits.sh: 'objdump' not found; skipping test"
 	exit 77
 fi
 
-OBJS=.libs/*.o
+OBJS=$libs/*.o
 if test "x`echo $OBJS`" = "x$OBJS" 2>/dev/null >/dev/null; then
 	echo "check-static-inits.sh: object files not found; skipping test"
 	exit 77
 fi
 
 echo "Checking that no object file has static initializers"
 for obj in $OBJS; do
 	if objdump -t "$obj" | grep '[.][cd]tors' | grep -v '\<00*\>'; then
--- a/gfx/harfbuzz/src/check-symbols.sh
+++ b/gfx/harfbuzz/src/check-symbols.sh
@@ -1,28 +1,29 @@
 #!/bin/sh
 
 LC_ALL=C
 export LC_ALL
 
 test -z "$srcdir" && srcdir=.
+test -z "$libs" && libs=.libs
 stat=0
 
 
 if which nm 2>/dev/null >/dev/null; then
 	:
 else
 	echo "check-symbols.sh: 'nm' not found; skipping test"
 	exit 77
 fi
 
 echo "Checking that we are not exposing internal symbols"
 tested=false
 for suffix in so dylib; do
-	so=.libs/libharfbuzz.$suffix
+	so=$libs/libharfbuzz.$suffix
 	if ! test -f "$so"; then continue; fi
 
 	EXPORTED_SYMBOLS="`nm "$so" | grep ' [BCDGINRSTVW] .' | grep -v ' _fini\>\| _init\>\| _fdata\>\| _ftext\>\| _fbss\>\| __bss_start\>\| __bss_start__\>\| __bss_end__\>\| _edata\>\| _end\>\| _bss_end__\>\| __end__\>\| __gcov_flush\>\| ___gcov_flush\>\| llvm_\| _llvm_' | cut -d' ' -f3`"
 
 	prefix=`basename "$so" | sed 's/libharfbuzz/hb/; s/-/_/g; s/[.].*//'`
 
 	# On mac, C symbols are prefixed with _
 	if test $suffix = dylib; then prefix="_$prefix"; fi
new file mode 100755
--- /dev/null
+++ b/gfx/harfbuzz/src/gen-def.py
@@ -0,0 +1,16 @@
+#!/usr/bin/env python
+
+from __future__ import print_function
+
+import io, os, re, sys
+
+headers_content = []
+for h in os.environ["headers"].split (' '):
+	if h.endswith (".h"):
+		with io.open(h, encoding='utf8') as f: headers_content.append (f.read ())
+
+result = ("EXPORTS\n" +
+	"\n".join (sorted (re.findall (r"^hb_\w+(?= \()", "\n".join (headers_content), re.M))) +
+	"\nLIBRARY libharfbuzz-0.dll")
+
+with open (sys.argv[1], "w") as f: f.write (result)
--- a/gfx/harfbuzz/src/gen-indic-table.py
+++ b/gfx/harfbuzz/src/gen-indic-table.py
@@ -224,23 +224,23 @@ print
 print "INDIC_TABLE_ELEMENT_TYPE"
 print "hb_indic_get_categories (hb_codepoint_t u)"
 print "{"
 print "  switch (u >> %d)" % page_bits
 print "  {"
 pages = set([u>>page_bits for u in starts+ends+singles.keys()])
 for p in sorted(pages):
 	print "    case 0x%0Xu:" % p
+	for u,d in singles.items ():
+		if p != u>>page_bits: continue
+		print "      if (unlikely (u == 0x%04Xu)) return _(%s,%s);" % (u, short[0][d[0]], short[1][d[1]])
 	for (start,end) in zip (starts, ends):
 		if p not in [start>>page_bits, end>>page_bits]: continue
 		offset = "indic_offset_0x%04xu" % start
 		print "      if (hb_in_range<hb_codepoint_t> (u, 0x%04Xu, 0x%04Xu)) return indic_table[u - 0x%04Xu + %s];" % (start, end-1, start, offset)
-	for u,d in singles.items ():
-		if p != u>>page_bits: continue
-		print "      if (unlikely (u == 0x%04Xu)) return _(%s,%s);" % (u, short[0][d[0]], short[1][d[1]])
 	print "      break;"
 	print ""
 print "    default:"
 print "      break;"
 print "  }"
 print "  return _(x,x);"
 print "}"
 print
--- a/gfx/harfbuzz/src/gen-use-table.py
+++ b/gfx/harfbuzz/src/gen-use-table.py
@@ -292,16 +292,19 @@ def map_to_use(data):
 
 		# Resolve Indic_Syllabic_Category
 
 		# TODO: These don't have UISC assigned in Unicode 8.0, but
 		# have UIPC
 		if U == 0x17DD: UISC = Vowel_Dependent
 		if 0x1CE2 <= U <= 0x1CE8: UISC = Cantillation_Mark
 
+		# TODO: https://github.com/harfbuzz/harfbuzz/pull/627
+		if 0x1BF2 <= U <= 0x1BF3: UISC = Nukta; UIPC = Bottom
+
 		# TODO: U+1CED should only be allowed after some of
 		# the nasalization marks, maybe only for U+1CE9..U+1CF1.
 		if U == 0x1CED: UISC = Tone_Mark
 
 		# TODO: https://github.com/harfbuzz/harfbuzz/issues/525
 		if U == 0x1A7F: UISC = Consonant_Final; UIPC = Bottom
 
 		# TODO: https://github.com/harfbuzz/harfbuzz/pull/609
@@ -344,22 +347,16 @@ def map_to_use(data):
 			USE = USE + values[0]
 
 		out[U] = (USE, UBlock)
 	return out
 
 defaults = ('O', 'No_Block')
 data = map_to_use(data)
 
-# Remove the outliers
-singles = {}
-for u in [0x034F, 0x25CC, 0x1107F]:
-	singles[u] = data[u]
-	del data[u]
-
 print "/* == Start of generated table == */"
 print "/*"
 print " * The following table is generated by running:"
 print " *"
 print " *   ./gen-use-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt UnicodeData.txt Blocks.txt"
 print " *"
 print " * on files with these headers:"
 print " *"
@@ -451,26 +448,23 @@ occupancy = used * 100. / total
 page_bits = 12
 print "}; /* Table items: %d; occupancy: %d%% */" % (offset, occupancy)
 print
 print "USE_TABLE_ELEMENT_TYPE"
 print "hb_use_get_categories (hb_codepoint_t u)"
 print "{"
 print "  switch (u >> %d)" % page_bits
 print "  {"
-pages = set([u>>page_bits for u in starts+ends+singles.keys()])
+pages = set([u>>page_bits for u in starts+ends])
 for p in sorted(pages):
 	print "    case 0x%0Xu:" % p
 	for (start,end) in zip (starts, ends):
 		if p not in [start>>page_bits, end>>page_bits]: continue
 		offset = "use_offset_0x%04xu" % start
 		print "      if (hb_in_range<hb_codepoint_t> (u, 0x%04Xu, 0x%04Xu)) return use_table[u - 0x%04Xu + %s];" % (start, end-1, start, offset)
-	for u,d in singles.items ():
-		if p != u>>page_bits: continue
-		print "      if (unlikely (u == 0x%04Xu)) return %s;" % (u, d[0])
 	print "      break;"
 	print ""
 print "    default:"
 print "      break;"
 print "  }"
 print "  return USE_O;"
 print "}"
 print
--- a/gfx/harfbuzz/src/harfbuzz-icu.pc
+++ b/gfx/harfbuzz/src/harfbuzz-icu.pc
@@ -1,13 +1,13 @@
 prefix=/usr/local
 exec_prefix=/usr/local
 libdir=/usr/local/lib
 includedir=/usr/local/include
 
 Name: harfbuzz
 Description: HarfBuzz text shaping library ICU integration
-Version: 1.7.4
+Version: 1.7.5
 
 Requires: harfbuzz
 Requires.private: icu-uc
 Libs: -L${libdir} -lharfbuzz-icu
 Cflags: -I${includedir}/harfbuzz
--- a/gfx/harfbuzz/src/harfbuzz.pc
+++ b/gfx/harfbuzz/src/harfbuzz.pc
@@ -1,13 +1,13 @@
 prefix=/usr/local
 exec_prefix=/usr/local
 libdir=/usr/local/lib
 includedir=/usr/local/include
 
 Name: harfbuzz
 Description: HarfBuzz text shaping library
-Version: 1.7.4
+Version: 1.7.5
 
 Libs: -L${libdir} -lharfbuzz
 Libs.private: -lm    
 Requires.private: glib-2.0 >= 2.19.1 
 Cflags: -I${includedir}/harfbuzz
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/src/hb-aat-layout-common-private.hh
@@ -0,0 +1,708 @@
+/*
+ * Copyright © 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.
+ *
+ * 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_AAT_LAYOUT_COMMON_PRIVATE_HH
+#define HB_AAT_LAYOUT_COMMON_PRIVATE_HH
+
+#include "hb-aat-layout-private.hh"
+
+
+namespace AAT {
+
+using namespace OT;
+
+
+/*
+ * Binary Searching Tables
+ */
+
+struct BinSearchHeader
+{
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this));
+  }
+
+  HBUINT16	unitSize;	/* Size of a lookup unit for this search in bytes. */
+  HBUINT16	nUnits;		/* Number of units of the preceding size to be searched. */
+  HBUINT16	searchRange;	/* The value of unitSize times the largest power of 2
+				 * that is less than or equal to the value of nUnits. */
+  HBUINT16	entrySelector;	/* The log base 2 of the largest power of 2 less than
+				 * or equal to the value of nUnits. */
+  HBUINT16	rangeShift;	/* The value of unitSize times the difference of the
+				 * value of nUnits minus the largest power of 2 less
+				 * than or equal to the value of nUnits. */
+  public:
+  DEFINE_SIZE_STATIC (10);
+};
+
+template <typename Type>
+struct BinSearchArrayOf
+{
+  inline const Type& operator [] (unsigned int i) const
+  {
+    if (unlikely (i >= header.nUnits)) return Null(Type);
+    return StructAtOffset<Type> (bytes, i * header.unitSize);
+  }
+  inline Type& operator [] (unsigned int i)
+  {
+    return StructAtOffset<Type> (bytes, i * header.unitSize);
+  }
+  inline unsigned int get_size (void) const
+  { return header.static_size + header.nUnits * header.unitSize; }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    if (unlikely (!sanitize_shallow (c))) return_trace (false);
+
+    /* Note: for structs that do not reference other structs,
+     * we do not need to call their sanitize() as we already did
+     * a bound check on the aggregate array size.  We just include
+     * a small unreachable expression to make sure the structs
+     * pointed to do have a simple sanitize(), ie. they do not
+     * reference other structs via offsets.
+     */
+    (void) (false && StructAtOffset<Type> (bytes, 0).sanitize (c));
+
+    return_trace (true);
+  }
+  inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
+  {
+    TRACE_SANITIZE (this);
+    if (unlikely (!sanitize_shallow (c))) return_trace (false);
+    unsigned int count = header.nUnits;
+    for (unsigned int i = 0; i < count; i++)
+      if (unlikely (!(*this)[i].sanitize (c, base)))
+        return_trace (false);
+    return_trace (true);
+  }
+
+  template <typename T>
+  inline const Type *bsearch (const T &key) const
+  {
+    unsigned int size = header.unitSize;
+    int min = 0, max = (int) header.nUnits - 1;
+    while (min <= max)
+    {
+      int mid = (min + max) / 2;
+      const Type *p = (const Type *) (((const char *) bytes) + (mid * size));
+      int c = p->cmp (key);
+      if (c < 0)
+	max = mid - 1;
+      else if (c > 0)
+	min = mid + 1;
+      else
+	return p;
+    }
+    return NULL;
+  }
+
+  private:
+  inline bool sanitize_shallow (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (header.sanitize (c) &&
+		  Type::static_size >= header.unitSize &&
+		  c->check_array (bytes, header.unitSize, header.nUnits));
+  }
+
+  protected:
+  BinSearchHeader	header;
+  HBUINT8			bytes[VAR];
+  public:
+  DEFINE_SIZE_ARRAY (10, bytes);
+};
+
+
+/* TODO Move this to hb-open-type-private.hh and use it in ArrayOf, HeadlessArrayOf,
+ * and other places around the code base?? */
+template <typename Type>
+struct UnsizedArrayOf
+{
+  inline const Type& operator [] (unsigned int i) const { return arrayZ[i]; }
+  inline Type& operator [] (unsigned int i) { return arrayZ[i]; }
+
+  inline bool sanitize (hb_sanitize_context_t *c, unsigned int count) const
+  {
+    TRACE_SANITIZE (this);
+    if (unlikely (!sanitize_shallow (c, count))) return_trace (false);
+
+    /* Note: for structs that do not reference other structs,
+     * we do not need to call their sanitize() as we already did
+     * a bound check on the aggregate array size.  We just include
+     * a small unreachable expression to make sure the structs
+     * pointed to do have a simple sanitize(), ie. they do not
+     * reference other structs via offsets.
+     */
+    (void) (false && arrayZ[0].sanitize (c));
+
+    return_trace (true);
+  }
+  inline bool sanitize (hb_sanitize_context_t *c, unsigned int count, const void *base) const
+  {
+    TRACE_SANITIZE (this);
+    if (unlikely (!sanitize_shallow (c, count))) return_trace (false);
+    for (unsigned int i = 0; i < count; i++)
+      if (unlikely (!arrayZ[i].sanitize (c, base)))
+        return_trace (false);
+    return_trace (true);
+  }
+  template <typename T>
+  inline bool sanitize (hb_sanitize_context_t *c, unsigned int count, const void *base, T user_data) const
+  {
+    TRACE_SANITIZE (this);
+    if (unlikely (!sanitize_shallow (c, count))) return_trace (false);
+    for (unsigned int i = 0; i < count; i++)
+      if (unlikely (!arrayZ[i].sanitize (c, base, user_data)))
+        return_trace (false);
+    return_trace (true);
+  }
+
+  private:
+  inline bool sanitize_shallow (hb_sanitize_context_t *c, unsigned int count) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_array (arrayZ, arrayZ[0].static_size, count));
+  }
+
+  public:
+  Type	arrayZ[VAR];
+  public:
+  DEFINE_SIZE_ARRAY (0, arrayZ);
+};
+
+/* Unsized array of offset's */
+template <typename Type, typename OffsetType>
+struct UnsizedOffsetArrayOf : UnsizedArrayOf<OffsetTo<Type, OffsetType> > {};
+
+/* Unsized array of offsets relative to the beginning of the array itself. */
+template <typename Type, typename OffsetType>
+struct UnsizedOffsetListOf : UnsizedOffsetArrayOf<Type, OffsetType>
+{
+  inline const Type& operator [] (unsigned int i) const
+  {
+    return this+this->arrayZ[i];
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c, unsigned int count) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace ((UnsizedOffsetArrayOf<Type, OffsetType>::sanitize (c, count, this)));
+  }
+  template <typename T>
+  inline bool sanitize (hb_sanitize_context_t *c, unsigned int count, T user_data) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace ((UnsizedOffsetArrayOf<Type, OffsetType>::sanitize (c, count, this, user_data)));
+  }
+};
+
+
+/*
+ * Lookup Table
+ */
+
+template <typename T> struct Lookup;
+
+template <typename T>
+struct LookupFormat0
+{
+  friend struct Lookup<T>;
+
+  private:
+  inline const T* get_value (hb_codepoint_t glyph_id, unsigned int num_glyphs) const
+  {
+    if (unlikely (glyph_id >= num_glyphs)) return nullptr;
+    return &arrayZ[glyph_id];
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (arrayZ.sanitize (c, c->num_glyphs));
+  }
+
+  protected:
+  HBUINT16	format;		/* Format identifier--format = 0 */
+  UnsizedArrayOf<T>
+		arrayZ;		/* Array of lookup values, indexed by glyph index. */
+  public:
+  DEFINE_SIZE_ARRAY (2, arrayZ);
+};
+
+
+template <typename T>
+struct LookupSegmentSingle
+{
+  inline int cmp (hb_codepoint_t g) const {
+    return g < first ? -1 : g <= last ? 0 : +1 ;
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) && value.sanitize (c));
+  }
+
+  GlyphID	last;		/* Last GlyphID in this segment */
+  GlyphID	first;		/* First GlyphID in this segment */
+  T		value;		/* The lookup value (only one) */
+  public:
+  DEFINE_SIZE_STATIC (4 + T::static_size);
+};
+
+template <typename T>
+struct LookupFormat2
+{
+  friend struct Lookup<T>;
+
+  private:
+  inline const T* get_value (hb_codepoint_t glyph_id) const
+  {
+    const LookupSegmentSingle<T> *v = segments.bsearch (glyph_id);
+    return v ? &v->value : nullptr;
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (segments.sanitize (c));
+  }
+
+  protected:
+  HBUINT16	format;		/* Format identifier--format = 2 */
+  BinSearchArrayOf<LookupSegmentSingle<T> >
+		segments;	/* The actual segments. These must already be sorted,
+				 * according to the first word in each one (the last
+				 * glyph in each segment). */
+  public:
+  DEFINE_SIZE_ARRAY (8, segments);
+};
+
+template <typename T>
+struct LookupSegmentArray
+{
+  inline const T* get_value (hb_codepoint_t glyph_id, const void *base) const
+  {
+    return first <= glyph_id && glyph_id <= last ? &(base+valuesZ)[glyph_id - first] : nullptr;
+  }
+
+  inline int cmp (hb_codepoint_t g) const {
+    return g < first ? -1 : g <= last ? 0 : +1 ;
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) &&
+		  first <= last &&
+		  valuesZ.sanitize (c, base, last - first + 1));
+  }
+
+  GlyphID	last;		/* Last GlyphID in this segment */
+  GlyphID	first;		/* First GlyphID in this segment */
+  OffsetTo<UnsizedArrayOf<T> >
+		valuesZ;	/* A 16-bit offset from the start of
+				 * the table to the data. */
+  public:
+  DEFINE_SIZE_STATIC (6);
+};
+
+template <typename T>
+struct LookupFormat4
+{
+  friend struct Lookup<T>;
+
+  private:
+  inline const T* get_value (hb_codepoint_t glyph_id) const
+  {
+    const LookupSegmentArray<T> *v = segments.bsearch (glyph_id);
+    return v ? v->get_value (glyph_id, this) : nullptr;
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (segments.sanitize (c, this));
+  }
+
+  protected:
+  HBUINT16	format;		/* Format identifier--format = 2 */
+  BinSearchArrayOf<LookupSegmentArray<T> >
+		segments;	/* The actual segments. These must already be sorted,
+				 * according to the first word in each one (the last
+				 * glyph in each segment). */
+  public:
+  DEFINE_SIZE_ARRAY (8, segments);
+};
+
+template <typename T>
+struct LookupSingle
+{
+  inline int cmp (hb_codepoint_t g) const { return glyph.cmp (g); }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) && value.sanitize (c));
+  }
+
+  GlyphID	glyph;		/* Last GlyphID */
+  T		value;		/* The lookup value (only one) */
+  public:
+  DEFINE_SIZE_STATIC (4 + T::static_size);
+};
+
+template <typename T>
+struct LookupFormat6
+{
+  friend struct Lookup<T>;
+
+  private:
+  inline const T* get_value (hb_codepoint_t glyph_id) const
+  {
+    const LookupSingle<T> *v = entries.bsearch (glyph_id);
+    return v ? &v->value : nullptr;
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (entries.sanitize (c));
+  }
+
+  protected:
+  HBUINT16	format;		/* Format identifier--format = 6 */
+  BinSearchArrayOf<LookupSingle<T> >
+		entries;	/* The actual entries, sorted by glyph index. */
+  public:
+  DEFINE_SIZE_ARRAY (8, entries);
+};
+
+template <typename T>
+struct LookupFormat8
+{
+  friend struct Lookup<T>;
+
+  private:
+  inline const T* get_value (hb_codepoint_t glyph_id) const
+  {
+    return firstGlyph <= glyph_id && glyph_id - firstGlyph < glyphCount ? &valueArrayZ[glyph_id - firstGlyph] : nullptr;
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) && valueArrayZ.sanitize (c, glyphCount));
+  }
+
+  protected:
+  HBUINT16	format;		/* Format identifier--format = 6 */
+  GlyphID	firstGlyph;	/* First glyph index included in the trimmed array. */
+  HBUINT16	glyphCount;	/* Total number of glyphs (equivalent to the last
+				 * glyph minus the value of firstGlyph plus 1). */
+  UnsizedArrayOf<T>
+		valueArrayZ;	/* The lookup values (indexed by the glyph index
+				 * minus the value of firstGlyph). */
+  public:
+  DEFINE_SIZE_ARRAY (6, valueArrayZ);
+};
+
+template <typename T>
+struct Lookup
+{
+  inline const T* get_value (hb_codepoint_t glyph_id, unsigned int num_glyphs) const
+  {
+    switch (u.format) {
+    case 0: return u.format0.get_value (glyph_id, num_glyphs);
+    case 2: return u.format2.get_value (glyph_id);
+    case 4: return u.format4.get_value (glyph_id);
+    case 6: return u.format6.get_value (glyph_id);
+    case 8: return u.format8.get_value (glyph_id);
+    default:return nullptr;
+    }
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    if (!u.format.sanitize (c)) return_trace (false);
+    switch (u.format) {
+    case 0: return_trace (u.format0.sanitize (c));
+    case 2: return_trace (u.format2.sanitize (c));
+    case 4: return_trace (u.format4.sanitize (c));
+    case 6: return_trace (u.format6.sanitize (c));
+    case 8: return_trace (u.format8.sanitize (c));
+    default:return_trace (true);
+    }
+  }
+
+  protected:
+  union {
+  HBUINT16		format;		/* Format identifier */
+  LookupFormat0<T>	format0;
+  LookupFormat2<T>	format2;
+  LookupFormat4<T>	format4;
+  LookupFormat6<T>	format6;
+  LookupFormat8<T>	format8;
+  } u;
+  public:
+  DEFINE_SIZE_UNION (2, format);
+};
+
+
+/*
+ * Extended State Table
+ */
+
+template <typename T>
+struct Entry
+{
+  inline bool sanitize (hb_sanitize_context_t *c, unsigned int count) const
+  {
+    TRACE_SANITIZE (this);
+    /* Note, we don't recurse-sanitize data because we don't access it.
+     * That said, in our DEFINE_SIZE_STATIC we access T::static_size,
+     * which ensures that data has a simple sanitize(). To be determined
+     * if I need to remove that as well. */
+    return_trace (c->check_struct (this));
+  }
+
+  public:
+  HBUINT16	newState;	/* Byte offset from beginning of state table
+				 * to the new state. Really?!?! Or just state
+				 * number?  The latter in morx for sure. */
+  HBUINT16	flags;		/* Table specific. */
+  T		data;		/* Optional offsets to per-glyph tables. */
+  public:
+  DEFINE_SIZE_STATIC (4 + T::static_size);
+};
+
+template <>
+struct Entry<void>
+{
+  inline bool sanitize (hb_sanitize_context_t *c, unsigned int count) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this));
+  }
+
+  public:
+  HBUINT16	newState;	/* Byte offset from beginning of state table to the new state. */
+  HBUINT16	flags;		/* Table specific. */
+  public:
+  DEFINE_SIZE_STATIC (4);
+};
+
+template <typename Extra>
+struct StateTable
+{
+  inline unsigned int get_class (hb_codepoint_t glyph_id, unsigned int num_glyphs) const
+  {
+    const HBUINT16 *v = (this+classTable).get_value (glyph_id, num_glyphs);
+    return v ? *v : 1;
+  }
+
+  inline const Entry<Extra> *get_entries () const
+  {
+    return (this+entryTable).arrayZ;
+  }
+
+  inline const Entry<Extra> *get_entryZ (unsigned int state, unsigned int klass) const
+  {
+    if (unlikely (klass >= nClasses)) return nullptr;
+
+    const HBUINT16 *states = (this+stateArrayTable).arrayZ;
+    const Entry<Extra> *entries = (this+entryTable).arrayZ;
+
+    unsigned int entry = states[state * nClasses + klass];
+
+    return &entries[entry];
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c,
+			unsigned int *num_entries_out = nullptr) const
+  {
+    TRACE_SANITIZE (this);
+    if (unlikely (!(c->check_struct (this) &&
+		    classTable.sanitize (c, this)))) return_trace (false);
+
+    const HBUINT16 *states = (this+stateArrayTable).arrayZ;
+    const Entry<Extra> *entries = (this+entryTable).arrayZ;
+
+    unsigned int num_states = 1;
+    unsigned int num_entries = 0;
+
+    unsigned int state = 0;
+    unsigned int entry = 0;
+    while (state < num_states)
+    {
+      if (unlikely (!c->check_array (states + state * nClasses,
+				     states[0].static_size,
+				     nClasses * (num_states - state))))
+	return_trace (false);
+      { /* Sweep new states. */
+	const HBUINT16 *stop = &states[num_states * nClasses];
+	for (const HBUINT16 *p = &states[state * nClasses]; p < stop; p++)
+	  num_entries = MAX<unsigned int> (num_entries, *p + 1);
+	state = num_states;
+      }
+
+      if (unlikely (!c->check_array (entries + entry,
+				     entries[0].static_size,
+				     num_entries - entry)))
+	return_trace (false);
+      { /* Sweep new entries. */
+	const Entry<Extra> *stop = &entries[num_entries];
+	for (const Entry<Extra> *p = &entries[entry]; p < stop; p++)
+	  num_states = MAX<unsigned int> (num_states, p->newState + 1);
+	entry = num_entries;
+      }
+    }
+
+    if (num_entries_out)
+      *num_entries_out = num_entries;
+
+    return_trace (true);
+  }
+
+  protected:
+  HBUINT32	nClasses;	/* Number of classes, which is the number of indices
+				 * in a single line in the state array. */
+  OffsetTo<Lookup<HBUINT16>, HBUINT32>
+		classTable;	/* Offset to the class table. */
+  OffsetTo<UnsizedArrayOf<HBUINT16>, HBUINT32>
+		stateArrayTable;/* Offset to the state array. */
+  OffsetTo<UnsizedArrayOf<Entry<Extra> >, HBUINT32>
+		entryTable;	/* Offset to the entry array. */
+
+  public:
+  DEFINE_SIZE_STATIC (16);
+};
+
+template <typename EntryData>
+struct StateTableDriver
+{
+  inline StateTableDriver (const StateTable<EntryData> &machine_,
+			   hb_buffer_t *buffer_,
+			   hb_face_t *face_) :
+	      machine (machine_),
+	      buffer (buffer_),
+	      num_glyphs (face_->get_num_glyphs ()),
+	      last_zero (0) {}
+
+  template <typename context_t>
+  inline void drive (context_t *c)
+  {
+    hb_glyph_info_t *info = buffer->info;
+
+    if (!c->in_place)
+      buffer->clear_output ();
+
+    unsigned int state = 0;
+    bool last_was_dont_advance = false;
+    for (buffer->idx = 0;;)
+    {
+      if (!state)
+	last_zero = buffer->idx;
+
+      unsigned int klass = buffer->idx < buffer->len ?
+			   machine.get_class (info[buffer->idx].codepoint, num_glyphs) :
+			   0 /* End of text */;
+      const Entry<EntryData> *entry = machine.get_entryZ (state, klass);
+      if (unlikely (!entry))
+	break;
+
+      if (unlikely (!c->transition (this, entry)))
+        break;
+
+      last_was_dont_advance = (entry->flags & context_t::DontAdvance) && buffer->max_ops--;
+
+      state = entry->newState;
+
+      if (buffer->idx == buffer->len)
+        break;
+
+      if (!last_was_dont_advance)
+        buffer->next_glyph ();
+    }
+
+    if (!c->in_place)
+    {
+      for (; buffer->idx < buffer->len;)
+        buffer->next_glyph ();
+      buffer->swap_buffers ();
+    }
+  }
+
+  public:
+  const StateTable<EntryData> &machine;
+  hb_buffer_t *buffer;
+  unsigned int num_glyphs;
+  unsigned int last_zero;
+};
+
+
+
+struct hb_aat_apply_context_t :
+       hb_dispatch_context_t<hb_aat_apply_context_t, bool, HB_DEBUG_APPLY>
+{
+  inline const char *get_name (void) { return "APPLY"; }
+  template <typename T>
+  inline return_t dispatch (const T &obj) { return obj.apply (this); }
+  static return_t default_return_value (void) { return false; }
+  bool stop_sublookup_iteration (return_t r) const { return r; }
+
+  hb_font_t *font;
+  hb_face_t *face;
+  hb_buffer_t *buffer;
+  hb_sanitize_context_t sanitizer;
+
+  inline hb_aat_apply_context_t (hb_font_t *font_,
+				 hb_buffer_t *buffer_,
+				 hb_blob_t *table) :
+		font (font_), face (font->face), buffer (buffer_),
+		sanitizer ()
+  {
+    sanitizer.init (table);
+    sanitizer.num_glyphs = face->get_num_glyphs ();
+    sanitizer.start_processing ();
+  }
+
+  inline ~hb_aat_apply_context_t (void)
+  {
+    sanitizer.end_processing ();
+  }
+};
+
+
+} /* namespace AAT */
+
+
+#endif /* HB_AAT_LAYOUT_COMMON_PRIVATE_HH */
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/src/hb-aat-layout-morx-table.hh
@@ -0,0 +1,694 @@
+/*
+ * Copyright © 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.
+ *
+ * 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_AAT_LAYOUT_MORX_TABLE_HH
+#define HB_AAT_LAYOUT_MORX_TABLE_HH
+
+#include "hb-open-type-private.hh"
+#include "hb-aat-layout-common-private.hh"
+
+#define HB_AAT_TAG_MORX HB_TAG('m','o','r','x')
+
+
+namespace AAT {
+
+using namespace OT;
+
+
+struct RearrangementSubtable
+{
+  struct driver_context_t
+  {
+    static const bool in_place = true;
+    enum Flags {
+      MarkFirst		= 0x8000,	/* If set, make the current glyph the first
+					 * glyph to be rearranged. */
+      DontAdvance	= 0x4000,	/* If set, don't advance to the next glyph
+					 * before going to the new state. This means
+					 * that the glyph index doesn't change, even
+					 * if the glyph at that index has changed. */
+      MarkLast		= 0x2000,	/* If set, make the current glyph the last
+					 * glyph to be rearranged. */
+      Reserved		= 0x1FF0,	/* These bits are reserved and should be set to 0. */
+      Verb		= 0x000F,	/* The type of rearrangement specified. */
+    };
+
+    inline driver_context_t (const RearrangementSubtable *table) :
+	ret (false),
+	start (0), end (0),
+	last_zero_before_start (0) {}
+
+    inline bool transition (StateTableDriver<void> *driver,
+			    const Entry<void> *entry)
+    {
+      hb_buffer_t *buffer = driver->buffer;
+      unsigned int flags = entry->flags;
+
+      if (flags & MarkFirst)
+      {
+	start = buffer->idx;
+	last_zero_before_start = driver->last_zero;
+      }
+
+      if (flags & MarkLast)
+	end = MIN (buffer->idx + 1, buffer->len);
+
+      if ((flags & Verb) && start < end)
+      {
+	/* The following map has two nibbles, for start-side
+	 * and end-side. Values of 0,1,2 mean move that many
+	 * to the other side. Value of 3 means move 2 and
+	 * flip them. */
+	const unsigned char map[16] =
+	{
+	  0x00,	/* 0	no change */
+	  0x10,	/* 1	Ax => xA */
+	  0x01,	/* 2	xD => Dx */
+	  0x11,	/* 3	AxD => DxA */
+	  0x20,	/* 4	ABx => xAB */
+	  0x30,	/* 5	ABx => xBA */
+	  0x02,	/* 6	xCD => CDx */
+	  0x03,	/* 7	xCD => DCx */
+	  0x12,	/* 8	AxCD => CDxA */
+	  0x13,	/* 9	AxCD => DCxA */
+	  0x21,	/* 10	ABxD => DxAB */
+	  0x31,	/* 11	ABxD => DxBA */
+	  0x22,	/* 12	ABxCD => CDxAB */
+	  0x32,	/* 13	ABxCD => CDxBA */
+	  0x23,	/* 14	ABxCD => DCxAB */
+	  0x33,	/* 15	ABxCD => DCxBA */
+	};
+
+	unsigned int m = map[flags & Verb];
+	unsigned int l = MIN<unsigned int> (2, m >> 4);
+	unsigned int r = MIN<unsigned int> (2, m & 0x0F);
+	bool reverse_l = 3 == (m >> 4);
+	bool reverse_r = 3 == (m & 0x0F);
+
+	if (end - start >= l + r)
+	{
+	  buffer->unsafe_to_break (last_zero_before_start, MIN (buffer->idx + 1, buffer->len));
+	  buffer->merge_clusters (start, end);
+
+	  hb_glyph_info_t *info = buffer->info;
+	  hb_glyph_info_t buf[4];
+
+	  memcpy (buf, info + start, l * sizeof (buf[0]));
+	  memcpy (buf + 2, info + end - r, r * sizeof (buf[0]));
+
+	  if (l != r)
+	    memmove (info + start + r, info + start + l, (end - start - l - r) * sizeof (buf[0]));
+
+	  memcpy (info + start, buf + 2, r * sizeof (buf[0]));
+	  memcpy (info + end - l, buf, l * sizeof (buf[0]));
+	  if (reverse_l)
+	  {
+	    buf[0] = info[end - 1];
+	    info[end - 1] = info[end - 2];
+	    info[end - 2] = buf[0];
+	  }
+	  if (reverse_r)
+	  {
+	    buf[0] = info[start];
+	    info[start] = info[start + 1];
+	    info[start + 1] = buf[0];
+	  }
+	}
+      }
+
+      return true;
+    }
+
+    public:
+    bool ret;
+    private:
+    unsigned int start;
+    unsigned int end;
+    unsigned int last_zero_before_start;
+  };
+
+  inline bool apply (hb_aat_apply_context_t *c) const
+  {
+    TRACE_APPLY (this);
+
+    driver_context_t dc (this);
+
+    StateTableDriver<void> driver (machine, c->buffer, c->face);
+    driver.drive (&dc);
+
+    return_trace (dc.ret);
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (machine.sanitize (c));
+  }
+
+  protected:
+  StateTable<void>	machine;
+  public:
+  DEFINE_SIZE_STATIC (16);
+};
+
+struct ContextualSubtable
+{
+  struct EntryData
+  {
+    HBUINT16	markIndex;	/* Index of the substitution table for the
+				 * marked glyph (use 0xFFFF for none). */
+    HBUINT16	currentIndex;	/* Index of the substitution table for the
+				 * current glyph (use 0xFFFF for none). */
+    public:
+    DEFINE_SIZE_STATIC (4);
+  };
+
+  struct driver_context_t
+  {
+    static const bool in_place = true;
+    enum Flags {
+      SetMark		= 0x8000,	/* If set, make the current glyph the marked glyph. */
+      DontAdvance	= 0x4000,	/* If set, don't advance to the next glyph before
+					 * going to the new state. */
+      Reserved		= 0x3FFF,	/* These bits are reserved and should be set to 0. */
+    };
+
+    inline driver_context_t (const ContextualSubtable *table) :
+	ret (false),
+	mark (0),
+	last_zero_before_mark (0),
+	subs (table+table->substitutionTables) {}
+
+    inline bool transition (StateTableDriver<EntryData> *driver,
+			    const Entry<EntryData> *entry)
+    {
+      hb_buffer_t *buffer = driver->buffer;
+
+      if (entry->flags & SetMark)
+      {
+	mark = buffer->idx;
+	last_zero_before_mark = driver->last_zero;
+      }
+
+      if (entry->data.markIndex != 0xFFFF)
+      {
+	const Lookup<GlyphID> &lookup = subs[entry->data.markIndex];
+	hb_glyph_info_t *info = buffer->info;
+	const GlyphID *replacement = lookup.get_value (info[mark].codepoint, driver->num_glyphs);
+	if (replacement)
+	{
+	  buffer->unsafe_to_break (last_zero_before_mark, MIN (buffer->idx + 1, buffer->len));
+	  info[mark].codepoint = *replacement;
+	  ret = true;
+	}
+      }
+      if (entry->data.currentIndex != 0xFFFF)
+      {
+	const Lookup<GlyphID> &lookup = subs[entry->data.currentIndex];
+	hb_glyph_info_t *info = buffer->info;
+	const GlyphID *replacement = lookup.get_value (info[buffer->idx].codepoint, driver->num_glyphs);
+	if (replacement)
+	{
+	  buffer->unsafe_to_break (driver->last_zero, MIN (buffer->idx + 1, buffer->len));
+	  info[buffer->idx].codepoint = *replacement;
+	  ret = true;
+	}
+      }
+
+      return true;
+    }
+
+    public:
+    bool ret;
+    private:
+    unsigned int mark;
+    unsigned int last_zero_before_mark;
+    const UnsizedOffsetListOf<Lookup<GlyphID>, HBUINT32> &subs;
+  };
+
+  inline bool apply (hb_aat_apply_context_t *c) const
+  {
+    TRACE_APPLY (this);
+
+    driver_context_t dc (this);
+
+    StateTableDriver<EntryData> driver (machine, c->buffer, c->face);
+    driver.drive (&dc);
+
+    return_trace (dc.ret);
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+
+    unsigned int num_entries;
+    if (unlikely (!machine.sanitize (c, &num_entries))) return false;
+
+    unsigned int num_lookups = 0;
+
+    const Entry<EntryData> *entries = machine.get_entries ();
+    for (unsigned int i = 0; i < num_entries; i++)
+    {
+      const EntryData &data = entries[i].data;
+
+      num_lookups = MAX<unsigned int> (num_lookups, 1 + data.markIndex);
+      num_lookups = MAX<unsigned int> (num_lookups, 1 + data.currentIndex);
+    }
+
+    return_trace (substitutionTables.sanitize (c, this, num_lookups));
+  }
+
+  protected:
+  StateTable<EntryData>	machine;
+  OffsetTo<UnsizedOffsetListOf<Lookup<GlyphID>, HBUINT32>, HBUINT32>
+			substitutionTables;
+  public:
+  DEFINE_SIZE_STATIC (20);
+};
+
+struct LigatureSubtable
+{
+  struct EntryData
+  {
+    HBUINT16	ligActionIndex;	/* Index to the first ligActionTable entry
+				 * for processing this group, if indicated
+				 * by the flags. */
+    public:
+    DEFINE_SIZE_STATIC (2);
+  };
+
+  struct driver_context_t
+  {
+    static const bool in_place = false;
+    enum Flags {
+      SetComponent	= 0x8000,	/* Push this glyph onto the component stack for
+					 * eventual processing. */
+      DontAdvance	= 0x4000,	/* Leave the glyph pointer at this glyph for the
+					   next iteration. */
+      PerformAction	= 0x2000,	/* Use the ligActionIndex to process a ligature
+					 * group. */
+      Reserved		= 0x1FFF,	/* These bits are reserved and should be set to 0. */
+    };
+    enum LigActionFlags {
+      LigActionLast	= 0x80000000,	/* This is the last action in the list. This also
+					 * implies storage. */
+      LigActionStore	= 0x40000000,	/* Store the ligature at the current cumulated index
+					 * in the ligature table in place of the marked
+					 * (i.e. currently-popped) glyph. */
+      LigActionOffset	= 0x3FFFFFFF,	/* A 30-bit value which is sign-extended to 32-bits
+					 * and added to the glyph ID, resulting in an index
+					 * into the component table. */
+    };
+
+    inline driver_context_t (const LigatureSubtable *table,
+			     hb_aat_apply_context_t *c_) :
+	ret (false),
+	c (c_),
+	ligAction (table+table->ligAction),
+	component (table+table->component),
+	ligature (table+table->ligature),
+	match_length (0) {}
+
+    inline bool transition (StateTableDriver<EntryData> *driver,
+			    const Entry<EntryData> *entry)
+    {
+      hb_buffer_t *buffer = driver->buffer;
+      unsigned int flags = entry->flags;
+
+      if (flags & SetComponent)
+      {
+        if (unlikely (match_length >= ARRAY_LENGTH (match_positions)))
+	  return false;
+
+	/* Never mark same index twice, in case DontAdvance was used... */
+	if (match_length && match_positions[match_length - 1] == buffer->out_len)
+	  match_length--;
+
+	match_positions[match_length++] = buffer->out_len;
+      }
+
+      if (flags & PerformAction)
+      {
+	unsigned int end = buffer->out_len;
+	unsigned int action_idx = entry->data.ligActionIndex;
+	unsigned int action;
+	unsigned int ligature_idx = 0;
+        do
+	{
+	  if (unlikely (!match_length))
+	    return false;
+
+	  buffer->move_to (match_positions[--match_length]);
+
+	  const HBUINT32 &actionData = ligAction[action_idx];
+	  if (unlikely (!actionData.sanitize (&c->sanitizer))) return false;
+	  action = actionData;
+
+	  uint32_t uoffset = action & LigActionOffset;
+	  if (uoffset & 0x20000000)
+	    uoffset += 0xC0000000;
+	  int32_t offset = (int32_t) uoffset;
+	  unsigned int component_idx = buffer->cur().codepoint + offset;
+
+	  const HBUINT16 &componentData = component[component_idx];
+	  if (unlikely (!componentData.sanitize (&c->sanitizer))) return false;
+	  ligature_idx += componentData;
+
+	  if (action & (LigActionStore | LigActionLast))
+	  {
+	    const GlyphID &ligatureData = ligature[ligature_idx];
+	    if (unlikely (!ligatureData.sanitize (&c->sanitizer))) return false;
+	    hb_codepoint_t lig = ligatureData;
+
+	    match_positions[match_length++] = buffer->out_len;
+	    buffer->replace_glyph (lig);
+
+	    //ligature_idx = 0; // XXX Yes or no?
+	  }
+	  else
+	  {
+	    buffer->skip_glyph ();
+	    end--;
+	  }
+	  /* TODO merge_clusters / unsafe_to_break */
+
+	  action_idx++;
+	}
+	while (!(action & LigActionLast));
+	buffer->move_to (end);
+      }
+
+      return true;
+    }
+
+    public:
+    bool ret;
+    private:
+    hb_aat_apply_context_t *c;
+    const UnsizedArrayOf<HBUINT32> &ligAction;
+    const UnsizedArrayOf<HBUINT16> &component;
+    const UnsizedArrayOf<GlyphID> &ligature;
+    unsigned int match_length;
+    unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
+  };
+
+  inline bool apply (hb_aat_apply_context_t *c) const
+  {
+    TRACE_APPLY (this);
+
+    driver_context_t dc (this, c);
+
+    StateTableDriver<EntryData> driver (machine, c->buffer, c->face);
+    driver.drive (&dc);
+
+    return_trace (dc.ret);
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    /* The rest of array sanitizations are done at run-time. */
+    return c->check_struct (this) && machine.sanitize (c) &&
+	   ligAction && component && ligature;
+    return_trace (true);
+  }
+
+  protected:
+  StateTable<EntryData>	machine;
+  OffsetTo<UnsizedArrayOf<HBUINT32>, HBUINT32>
+		ligAction;	/* Offset to the ligature action table. */
+  OffsetTo<UnsizedArrayOf<HBUINT16>, HBUINT32>
+		component;	/* Offset to the component table. */
+  OffsetTo<UnsizedArrayOf<GlyphID>, HBUINT32>
+		ligature;	/* Offset to the actual ligature lists. */
+  public:
+  DEFINE_SIZE_STATIC (28);
+};
+
+struct NoncontextualSubtable
+{
+  inline bool apply (hb_aat_apply_context_t *c) const
+  {
+    TRACE_APPLY (this);
+
+    bool ret = false;
+    unsigned int num_glyphs = c->face->get_num_glyphs ();
+
+    hb_glyph_info_t *info = c->buffer->info;
+    unsigned int count = c->buffer->len;
+    for (unsigned int i = 0; i < count; i++)
+    {
+      const GlyphID *replacement = substitute.get_value (info[i].codepoint, num_glyphs);
+      if (replacement)
+      {
+	info[i].codepoint = *replacement;
+	ret = true;
+      }
+    }
+
+    return_trace (ret);
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (substitute.sanitize (c));
+  }
+
+  protected:
+  Lookup<GlyphID>	substitute;
+  public:
+  DEFINE_SIZE_MIN (2);
+};
+
+struct InsertionSubtable
+{
+  inline bool apply (hb_aat_apply_context_t *c) const
+  {
+    TRACE_APPLY (this);
+    /* TODO */
+    return_trace (false);
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    /* TODO */
+    return_trace (true);
+  }
+};
+
+
+struct Feature
+{
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this));
+  }
+
+  public:
+  HBUINT16	featureType;	/* The type of feature. */
+  HBUINT16	featureSetting;	/* The feature's setting (aka selector). */
+  HBUINT32	enableFlags;	/* Flags for the settings that this feature
+				 * and setting enables. */
+  HBUINT32	disableFlags;	/* Complement of flags for the settings that this
+				 * feature and setting disable. */
+
+  public:
+  DEFINE_SIZE_STATIC (12);
+};
+
+
+struct ChainSubtable
+{
+  friend struct Chain;
+
+  inline unsigned int get_size (void) const { return length; }
+  inline unsigned int get_type (void) const { return coverage & 0xFF; }
+
+  enum Type {
+    Rearrangement	= 0,
+    Contextual		= 1,
+    Ligature		= 2,
+    Noncontextual	= 4,
+    Insertion		= 5
+  };
+
+  inline void apply (hb_aat_apply_context_t *c) const
+  {
+    dispatch (c);
+  }
+
+  template <typename context_t>
+  inline typename context_t::return_t dispatch (context_t *c) const
+  {
+    unsigned int subtable_type = get_type ();
+    TRACE_DISPATCH (this, subtable_type);
+    switch (subtable_type) {
+    case Rearrangement:		return_trace (c->dispatch (u.rearrangement));
+    case Contextual:		return_trace (c->dispatch (u.contextual));
+    case Ligature:		return_trace (c->dispatch (u.ligature));
+    case Noncontextual:		return_trace (c->dispatch (u.noncontextual));
+    case Insertion:		return_trace (c->dispatch (u.insertion));
+    default:			return_trace (c->default_return_value ());
+    }
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    if (!length.sanitize (c) ||
+	length < min_size ||
+	!c->check_range (this, length))
+      return_trace (false);
+
+    return_trace (dispatch (c));
+  }
+
+  protected:
+  HBUINT32	length;		/* Total subtable length, including this header. */
+  HBUINT32	coverage;	/* Coverage flags and subtable type. */
+  HBUINT32	subFeatureFlags;/* The 32-bit mask identifying which subtable this is. */
+  union {
+  RearrangementSubtable		rearrangement;
+  ContextualSubtable		contextual;
+  LigatureSubtable		ligature;
+  NoncontextualSubtable		noncontextual;
+  InsertionSubtable		insertion;
+  } u;
+  public:
+  DEFINE_SIZE_MIN (12);
+};
+
+struct Chain
+{
+  inline void apply (hb_aat_apply_context_t *c) const
+  {
+    const ChainSubtable *subtable = &StructAtOffset<ChainSubtable> (featureZ, featureZ[0].static_size * featureCount);
+    unsigned int count = subtableCount;
+    for (unsigned int i = 0; i < count; i++)
+    {
+      subtable->apply (c);
+      subtable = &StructAfter<ChainSubtable> (*subtable);
+    }
+  }
+
+  inline unsigned int get_size (void) const { return length; }
+
+  inline bool sanitize (hb_sanitize_context_t *c, unsigned int major) const
+  {
+    TRACE_SANITIZE (this);
+    if (!length.sanitize (c) ||
+	length < min_size ||
+	!c->check_range (this, length))
+      return_trace (false);
+
+    if (!c->check_array (featureZ, featureZ[0].static_size, featureCount))
+      return_trace (false);
+
+    const ChainSubtable *subtable = &StructAtOffset<ChainSubtable> (featureZ, featureZ[0].static_size * featureCount);
+    unsigned int count = subtableCount;
+    for (unsigned int i = 0; i < count; i++)
+    {
+      if (!subtable->sanitize (c))
+	return_trace (false);
+      subtable = &StructAfter<ChainSubtable> (*subtable);
+    }
+
+    return_trace (true);
+  }
+
+  protected:
+  HBUINT32	defaultFlags;	/* The default specification for subtables. */
+  HBUINT32	length;		/* Total byte count, including this header. */
+  HBUINT32	featureCount;	/* Number of feature subtable entries. */
+  HBUINT32	subtableCount;	/* The number of subtables in the chain. */
+
+  Feature	featureZ[VAR];	/* Features. */
+  ChainSubtable	subtableX[VAR];	/* Subtables. */
+  // subtableGlyphCoverageArray if major == 3
+
+  public:
+  DEFINE_SIZE_MIN (16);
+};
+
+
+/*
+ * The 'mort'/'morx' Tables
+ */
+
+struct morx
+{
+  static const hb_tag_t tableTag = HB_AAT_TAG_MORX;
+
+  inline void apply (hb_aat_apply_context_t *c) const
+  {
+    const Chain *chain = chains;
+    unsigned int count = chainCount;
+    for (unsigned int i = 0; i < count; i++)
+    {
+      chain->apply (c);
+      chain = &StructAfter<Chain> (*chain);
+    }
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    if (!version.sanitize (c) ||
+	(version.major >> (sizeof (HBUINT32) == 4 ? 1 : 0)) != 1 ||
+	!chainCount.sanitize (c))
+      return_trace (false);
+
+    const Chain *chain = chains;
+    unsigned int count = chainCount;
+    for (unsigned int i = 0; i < count; i++)
+    {
+      if (!chain->sanitize (c, version.major))
+	return_trace (false);
+      chain = &StructAfter<Chain> (*chain);
+    }
+
+    return_trace (true);
+  }
+
+  protected:
+  FixedVersion<>version;	/* Version number of the glyph metamorphosis table.
+				 * 1 for mort, 2 or 3 for morx. */
+  HBUINT32	chainCount;	/* Number of metamorphosis chains contained in this
+				 * table. */
+  Chain		chains[VAR];	/* Chains. */
+
+  public:
+  DEFINE_SIZE_MIN (8);
+};
+
+} /* namespace AAT */
+
+
+#endif /* HB_AAT_LAYOUT_MORX_TABLE_HH */
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/src/hb-aat-layout-private.hh
@@ -0,0 +1,40 @@
+/*
+ * Copyright © 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.
+ *
+ * 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_AAT_LAYOUT_PRIVATE_HH
+#define HB_AAT_LAYOUT_PRIVATE_HH
+
+#include "hb-private.hh"
+
+#include "hb-font-private.hh"
+#include "hb-buffer-private.hh"
+#include "hb-open-type-private.hh"
+
+
+HB_INTERNAL void
+hb_aat_layout_substitute (hb_font_t *font, hb_buffer_t *buffer);
+
+#endif /* HB_AAT_LAYOUT_PRIVATE_HH */
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/src/hb-aat-layout.cc
@@ -0,0 +1,78 @@
+/*
+ * Copyright © 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.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#include "hb-open-type-private.hh"
+
+#include "hb-ot-layout-private.hh"
+#include "hb-ot-layout-gsubgpos-private.hh"
+
+#include "hb-aat-layout-private.hh"
+#include "hb-aat-layout-morx-table.hh"
+
+/*
+ * mort/morx
+ */
+
+static inline const AAT::morx&
+_get_morx (hb_face_t *face, hb_blob_t **blob = nullptr)
+{
+  if (unlikely (!hb_ot_shaper_face_data_ensure (face)))
+  {
+    if (blob)
+      *blob = hb_blob_get_empty ();
+    return OT::Null(AAT::morx);
+  }
+  hb_ot_layout_t * layout = hb_ot_layout_from_face (face);
+  /* XXX this doesn't call set_num_glyphs on sanitizer. */
+  const AAT::morx& morx = *(layout->morx.get ());
+  if (blob)
+    *blob = layout->morx.blob;
+  return morx;
+}
+
+static inline void
+_hb_aat_layout_create (hb_face_t *face)
+{
+  OT::Sanitizer<AAT::morx> sanitizer;
+  sanitizer.set_num_glyphs (face->get_num_glyphs ());
+  hb_blob_t *morx_blob = sanitizer.sanitize (face->reference_table (HB_AAT_TAG_MORX));
+  OT::Sanitizer<AAT::morx>::lock_instance (morx_blob);
+
+  if (0)
+  {
+    OT::Sanitizer<AAT::Lookup<OT::GlyphID> >::lock_instance (morx_blob)->get_value (1, face->get_num_glyphs ());
+  }
+}
+
+void
+hb_aat_layout_substitute (hb_font_t *font, hb_buffer_t *buffer)
+{
+  hb_blob_t *blob;
+  const AAT::morx& morx = _get_morx (font->face, &blob);
+
+  AAT::hb_aat_apply_context_t c (font, buffer, blob);
+  morx.apply (&c);
+}
--- a/gfx/harfbuzz/src/hb-atomic-private.hh
+++ b/gfx/harfbuzz/src/hb-atomic-private.hh
@@ -65,16 +65,39 @@ static inline void _HBMemoryBarrier (voi
 typedef LONG hb_atomic_int_impl_t;
 #define HB_ATOMIC_INT_IMPL_INIT(V) (V)
 #define hb_atomic_int_impl_add(AI, V)		InterlockedExchangeAdd (&(AI), (V))
 
 #define hb_atomic_ptr_impl_get(P)		(_HBMemoryBarrier (), (void *) *(P))
 #define hb_atomic_ptr_impl_cmpexch(P,O,N)	(InterlockedCompareExchangePointer ((void **) (P), (void *) (N), (void *) (O)) == (void *) (O))
 
 
+#elif !defined(HB_NO_MT) && defined(HAVE_INTEL_ATOMIC_PRIMITIVES)
+
+typedef int hb_atomic_int_impl_t;
+#define HB_ATOMIC_INT_IMPL_INIT(V) (V)
+#define hb_atomic_int_impl_add(AI, V)		__sync_fetch_and_add (&(AI), (V))
+
+#define hb_atomic_ptr_impl_get(P)		(void *) (__sync_synchronize (), *(P))
+#define hb_atomic_ptr_impl_cmpexch(P,O,N)	__sync_bool_compare_and_swap ((P), (O), (N))
+
+
+#elif !defined(HB_NO_MT) && defined(HAVE_SOLARIS_ATOMIC_OPS)
+
+#include <atomic.h>
+#include <mbarrier.h>
+
+typedef unsigned int hb_atomic_int_impl_t;
+#define HB_ATOMIC_INT_IMPL_INIT(V) (V)
+#define hb_atomic_int_impl_add(AI, V)		( ({__machine_rw_barrier ();}), atomic_add_int_nv (&(AI), (V)) - (V))
+
+#define hb_atomic_ptr_impl_get(P)		( ({__machine_rw_barrier ();}), (void *) *(P))
+#define hb_atomic_ptr_impl_cmpexch(P,O,N)	( ({__machine_rw_barrier ();}), atomic_cas_ptr ((void **) (P), (void *) (O), (void *) (N)) == (void *) (O) ? true : false)
+
+
 #elif !defined(HB_NO_MT) && defined(__APPLE__)
 
 #include <libkern/OSAtomic.h>
 #ifdef __MAC_OS_X_MIN_REQUIRED
 #include <AvailabilityMacros.h>
 #elif defined(__IPHONE_OS_MIN_REQUIRED)
 #include <Availability.h>
 #endif
@@ -91,39 +114,16 @@ typedef int32_t hb_atomic_int_impl_t;
 #if __ppc64__ || __x86_64__ || __aarch64__
 #define hb_atomic_ptr_impl_cmpexch(P,O,N)	OSAtomicCompareAndSwap64Barrier ((int64_t) (void *) (O), (int64_t) (void *) (N), (int64_t*) (P))
 #else
 #define hb_atomic_ptr_impl_cmpexch(P,O,N)	OSAtomicCompareAndSwap32Barrier ((int32_t) (void *) (O), (int32_t) (void *) (N), (int32_t*) (P))
 #endif
 #endif
 
 
-#elif !defined(HB_NO_MT) && defined(HAVE_INTEL_ATOMIC_PRIMITIVES)
-
-typedef int hb_atomic_int_impl_t;
-#define HB_ATOMIC_INT_IMPL_INIT(V) (V)
-#define hb_atomic_int_impl_add(AI, V)		__sync_fetch_and_add (&(AI), (V))
-
-#define hb_atomic_ptr_impl_get(P)		(void *) (__sync_synchronize (), *(P))
-#define hb_atomic_ptr_impl_cmpexch(P,O,N)	__sync_bool_compare_and_swap ((P), (O), (N))
-
-
-#elif !defined(HB_NO_MT) && defined(HAVE_SOLARIS_ATOMIC_OPS)
-
-#include <atomic.h>
-#include <mbarrier.h>
-
-typedef unsigned int hb_atomic_int_impl_t;
-#define HB_ATOMIC_INT_IMPL_INIT(V) (V)
-#define hb_atomic_int_impl_add(AI, V)		( ({__machine_rw_barrier ();}), atomic_add_int_nv (&(AI), (V)) - (V))
-
-#define hb_atomic_ptr_impl_get(P)		( ({__machine_rw_barrier ();}), (void *) *(P))
-#define hb_atomic_ptr_impl_cmpexch(P,O,N)	( ({__machine_rw_barrier ();}), atomic_cas_ptr ((void **) (P), (void *) (O), (void *) (N)) == (void *) (O) ? true : false)
-
-
 #elif !defined(HB_NO_MT) && defined(_AIX) && defined(__IBMCPP__)
 
 #include <builtins.h>
 
 
 static inline int _hb_fetch_and_add(volatile int* AI, unsigned int V) {
   __lwsync();
   int result = __fetch_and_add(AI, V);
--- a/gfx/harfbuzz/src/hb-blob.cc
+++ b/gfx/harfbuzz/src/hb-blob.cc
@@ -21,17 +21,17 @@
  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  *
  * Red Hat Author(s): Behdad Esfahbod
  */
 
 /* http://www.oracle.com/technetwork/articles/servers-storage-dev/standardheaderfiles-453865.html */
 #ifndef _POSIX_C_SOURCE
-#define _POSIX_C_SOURCE 199309L
+#define _POSIX_C_SOURCE 200809L
 #endif
 
 #include "hb-private.hh"
 #include "hb-debug.hh"
 
 #include "hb-object-private.hh"
 
 #ifdef HAVE_SYS_MMAN_H
--- a/gfx/harfbuzz/src/hb-blob.h
+++ b/gfx/harfbuzz/src/hb-blob.h
@@ -39,17 +39,17 @@ HB_BEGIN_DECLS
 /*
  * Note re various memory-modes:
  *
  * - In no case shall the HarfBuzz client modify memory
  *   that is passed to HarfBuzz in a blob.  If there is
  *   any such possibility, MODE_DUPLICATE should be used
  *   such that HarfBuzz makes a copy immediately,
  *
- * - Use MODE_READONLY otherse, unless you really really
+ * - Use MODE_READONLY otherwise, unless you really really
  *   really know what you are doing,
  *
  * - MODE_WRITABLE is appropriate if you really made a
  *   copy of data solely for the purpose of passing to
  *   HarfBuzz and doing that just once (no reuse!),
  *
  * - If the font is mmap()ed, it's ok to use
  *   READONLY_MAY_MAKE_WRITABLE, however, using that mode
--- a/gfx/harfbuzz/src/hb-buffer-private.hh
+++ b/gfx/harfbuzz/src/hb-buffer-private.hh
@@ -64,16 +64,17 @@ HB_MARK_AS_FLAG_T (hb_buffer_diff_flags_
 
 enum hb_buffer_scratch_flags_t {
   HB_BUFFER_SCRATCH_FLAG_DEFAULT			= 0x00000000u,
   HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII			= 0x00000001u,
   HB_BUFFER_SCRATCH_FLAG_HAS_DEFAULT_IGNORABLES		= 0x00000002u,
   HB_BUFFER_SCRATCH_FLAG_HAS_SPACE_FALLBACK		= 0x00000004u,
   HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT		= 0x00000008u,
   HB_BUFFER_SCRATCH_FLAG_HAS_UNSAFE_TO_BREAK		= 0x00000010u,
+  HB_BUFFER_SCRATCH_FLAG_HAS_CGJ			= 0x00000020u,
 
   /* Reserved for complex shapers' internal use. */
   HB_BUFFER_SCRATCH_FLAG_COMPLEX0			= 0x01000000u,
   HB_BUFFER_SCRATCH_FLAG_COMPLEX1			= 0x02000000u,
   HB_BUFFER_SCRATCH_FLAG_COMPLEX2			= 0x04000000u,
   HB_BUFFER_SCRATCH_FLAG_COMPLEX3			= 0x08000000u,
 };
 HB_MARK_AS_FLAG_T (hb_buffer_scratch_flags_t);
@@ -301,47 +302,47 @@ struct hb_buffer_t {
     va_start (ap, fmt);
     bool ret = message_impl (font, fmt, ap);
     va_end (ap);
     return ret;
   }
   HB_INTERNAL bool message_impl (hb_font_t *font, const char *fmt, va_list ap) HB_PRINTF_FUNC(3, 0);
 
   static inline void
-  set_cluster (hb_glyph_info_t &info, unsigned int cluster, unsigned int mask = 0)
+  set_cluster (hb_glyph_info_t &inf, unsigned int cluster, unsigned int mask = 0)
   {
-    if (info.cluster != cluster)
+    if (inf.cluster != cluster)
     {
       if (mask & HB_GLYPH_FLAG_UNSAFE_TO_BREAK)
-	info.mask |= HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
+	inf.mask |= HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
       else
-	info.mask &= ~HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
+	inf.mask &= ~HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
     }
-    info.cluster = cluster;
+    inf.cluster = cluster;
   }
 
   inline int
-  _unsafe_to_break_find_min_cluster (const hb_glyph_info_t *info,
+  _unsafe_to_break_find_min_cluster (const hb_glyph_info_t *infos,
 				     unsigned int start, unsigned int end,
 				     unsigned int cluster) const
   {
     for (unsigned int i = start; i < end; i++)
-      cluster = MIN<unsigned int> (cluster, info[i].cluster);
+      cluster = MIN<unsigned int> (cluster, infos[i].cluster);
     return cluster;
   }
   inline void
-  _unsafe_to_break_set_mask (hb_glyph_info_t *info,
+  _unsafe_to_break_set_mask (hb_glyph_info_t *infos,
 			     unsigned int start, unsigned int end,
 			     unsigned int cluster)
   {
     for (unsigned int i = start; i < end; i++)
-      if (cluster != info[i].cluster)
+      if (cluster != infos[i].cluster)
       {
 	scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_UNSAFE_TO_BREAK;
-	info[i].mask |= HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
+	infos[i].mask |= HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
       }
   }
 
   inline void
   unsafe_to_break_all (void)
   {
     for (unsigned int i = 0; i < len; i++)
       info[i].mask |= HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
--- a/gfx/harfbuzz/src/hb-buffer-serialize.cc
+++ b/gfx/harfbuzz/src/hb-buffer-serialize.cc
@@ -104,16 +104,17 @@ static unsigned int
 				  hb_font_t *font,
 				  hb_buffer_serialize_flags_t flags)
 {
   hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, nullptr);
   hb_glyph_position_t *pos = (flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS) ?
 			     nullptr : hb_buffer_get_glyph_positions (buffer, nullptr);
 
   *buf_consumed = 0;
+  hb_position_t x = 0, y = 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. */
 
 #define APPEND(s) HB_STMT_START { strcpy (p, s); p += strlen (s); } HB_STMT_END
@@ -141,19 +142,20 @@ static unsigned int
 
     if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS)) {
       p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"cl\":%u", info[i].cluster));
     }
 
     if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS))
     {
       p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"dx\":%d,\"dy\":%d",
-			     pos[i].x_offset, pos[i].y_offset));
-      p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"ax\":%d,\"ay\":%d",
-			     pos[i].x_advance, pos[i].y_advance));
+			     x+pos[i].x_offset, y+pos[i].y_offset));
+      if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES))
+	p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"ax\":%d,\"ay\":%d",
+			       pos[i].x_advance, pos[i].y_advance));
     }
 
     if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_FLAGS)
     {
       if (info[i].mask & HB_GLYPH_FLAG_DEFINED)
 	p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"fl\":%u", info[i].mask & HB_GLYPH_FLAG_DEFINED));
     }
 
@@ -174,16 +176,22 @@ static unsigned int
     {
       memcpy (buf, b, l);
       buf += l;
       buf_size -= l;
       *buf_consumed += l;
       *buf = '\0';
     } else
       return i - start;
+
+    if (pos && (flags & HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES))
+    {
+      x += pos[i].x_advance;
+      y += pos[i].y_advance;
+    }
   }
 
   return end - start;
 }
 
 static unsigned int
 _hb_buffer_serialize_glyphs_text (hb_buffer_t *buffer,
 				  unsigned int start,
@@ -194,16 +202,17 @@ static unsigned int
 				  hb_font_t *font,
 				  hb_buffer_serialize_flags_t flags)
 {
   hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, nullptr);
   hb_glyph_position_t *pos = (flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS) ?
 			     nullptr : hb_buffer_get_glyph_positions (buffer, nullptr);
 
   *buf_consumed = 0;
+  hb_position_t x = 0, y = 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. */
 
     if (i)
@@ -218,23 +227,26 @@ static unsigned int
       p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%u", info[i].codepoint));
 
     if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS)) {
       p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "=%u", info[i].cluster));
     }
 
     if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS))
     {
-      if (pos[i].x_offset || pos[i].y_offset)
-	p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "@%d,%d", pos[i].x_offset, pos[i].y_offset));
+      if (x+pos[i].x_offset || y+pos[i].y_offset)
+	p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "@%d,%d", x+pos[i].x_offset, y+pos[i].y_offset));
 
-      *p++ = '+';
-      p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%d", pos[i].x_advance));
-      if (pos[i].y_advance)
-	p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",%d", pos[i].y_advance));
+      if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES))
+      {
+	*p++ = '+';
+	p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%d", pos[i].x_advance));
+	if (pos[i].y_advance)
+	  p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",%d", pos[i].y_advance));
+      }
     }
 
     if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_FLAGS)
     {
       if (info[i].mask &HB_GLYPH_FLAG_DEFINED)
 	p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "#%X", info[i].mask &HB_GLYPH_FLAG_DEFINED));
     }
 
@@ -250,16 +262,22 @@ static unsigned int
     {
       memcpy (buf, b, l);
       buf += l;
       buf_size -= l;
       *buf_consumed += l;
       *buf = '\0';
     } else
       return i - start;
+
+    if (pos && (flags & HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES))
+    {
+      x += pos[i].x_advance;
+      y += pos[i].y_advance;
+    }
   }
 
   return end - start;
 }
 
 /**
  * hb_buffer_serialize_glyphs:
  * @buffer: an #hb_buffer_t buffer.
--- a/gfx/harfbuzz/src/hb-buffer.h
+++ b/gfx/harfbuzz/src/hb-buffer.h
@@ -242,31 +242,40 @@ hb_buffer_guess_segment_properties (hb_b
  * hb_buffer_flags_t:
  * @HB_BUFFER_FLAG_DEFAULT: the default buffer flag.
  * @HB_BUFFER_FLAG_BOT: flag indicating that special handling of the beginning
  *                      of text paragraph can be applied to this buffer. Should usually
  *                      be set, unless you are passing to the buffer only part
  *                      of the text without the full context.
  * @HB_BUFFER_FLAG_EOT: flag indicating that special handling of the end of text
  *                      paragraph can be applied to this buffer, similar to
- *                      @HB_BUFFER_FLAG_EOT.
+ *                      @HB_BUFFER_FLAG_BOT.
  * @HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES:
  *                      flag indication that character with Default_Ignorable
  *                      Unicode property should use the corresponding glyph
- *                      from the font, instead of hiding them (currently done
- *                      by replacing them with the space glyph and zeroing the
- *                      advance width.)
+ *                      from the font, instead of hiding them (done by
+ *                      replacing them with the space glyph and zeroing the
+ *                      advance width.)  This flag takes precedence over
+ *                      @HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES.
+ * @HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES:
+ *                      flag indication that character with Default_Ignorable
+ *                      Unicode property should be removed from glyph string
+ *                      instead of hiding them (done by replacing them with the
+ *                      space glyph and zeroing the advance width.)
+ *                      @HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES takes
+ *                      precedence over this flag. Since: 1.8.0
  *
  * Since: 0.9.20
  */
 typedef enum { /*< flags >*/
   HB_BUFFER_FLAG_DEFAULT			= 0x00000000u,
   HB_BUFFER_FLAG_BOT				= 0x00000001u, /* Beginning-of-text */
   HB_BUFFER_FLAG_EOT				= 0x00000002u, /* End-of-text */
-  HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES	= 0x00000004u
+  HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES	= 0x00000004u,
+  HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES	= 0x00000008u
 } hb_buffer_flags_t;
 
 HB_EXTERN void
 hb_buffer_set_flags (hb_buffer_t       *buffer,
 		     hb_buffer_flags_t  flags);
 
 HB_EXTERN hb_buffer_flags_t
 hb_buffer_get_flags (hb_buffer_t *buffer);
@@ -407,28 +416,32 @@ hb_buffer_normalize_glyphs (hb_buffer_t 
 
 /**
  * hb_buffer_serialize_flags_t:
  * @HB_BUFFER_SERIALIZE_FLAG_DEFAULT: serialize glyph names, clusters and positions.
  * @HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS: do not serialize glyph cluster.
  * @HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS: do not serialize glyph position information.
  * @HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES: do no serialize glyph name.
  * @HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS: serialize glyph extents.
+ * @HB_BUFFER_SERIALIZE_FLAG_GLYPH_FLAGS: serialize glyph flags. Since: 1.5.0
+ * @HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES: do not serialize glyph advances,
+ *  glyph offsets will reflect absolute glyph positions. Since: 1.8.0
  *
  * Flags that control what glyph information are serialized in hb_buffer_serialize_glyphs().
  *
  * Since: 0.9.20
  */
 typedef enum { /*< flags >*/
   HB_BUFFER_SERIALIZE_FLAG_DEFAULT		= 0x00000000u,
   HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS		= 0x00000001u,
   HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS		= 0x00000002u,
   HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES	= 0x00000004u,
   HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS	= 0x00000008u,
-  HB_BUFFER_SERIALIZE_FLAG_GLYPH_FLAGS		= 0x00000010u
+  HB_BUFFER_SERIALIZE_FLAG_GLYPH_FLAGS		= 0x00000010u,
+  HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES		= 0x00000020u
 } hb_buffer_serialize_flags_t;
 
 /**
  * hb_buffer_serialize_format_t:
  * @HB_BUFFER_SERIALIZE_FORMAT_TEXT: a human-readable, plain text format.
  * @HB_BUFFER_SERIALIZE_FORMAT_JSON: a machine-readable JSON format.
  * @HB_BUFFER_SERIALIZE_FORMAT_INVALID: invalid format.
  *
--- a/gfx/harfbuzz/src/hb-common.cc
+++ b/gfx/harfbuzz/src/hb-common.cc
@@ -519,16 +519,17 @@ hb_script_get_horizontal_direction (hb_s
     case HB_SCRIPT_MANICHAEAN:
     case HB_SCRIPT_MENDE_KIKAKUI:
     case HB_SCRIPT_NABATAEAN:
     case HB_SCRIPT_OLD_NORTH_ARABIAN:
     case HB_SCRIPT_PALMYRENE:
     case HB_SCRIPT_PSALTER_PAHLAVI:
 
     /* Unicode-8.0 additions */
+    case HB_SCRIPT_HATRAN:
     case HB_SCRIPT_OLD_HUNGARIAN:
 
     /* Unicode-9.0 additions */
     case HB_SCRIPT_ADLAM:
 
       return HB_DIRECTION_RTL;
   }
 
--- a/gfx/harfbuzz/src/hb-face.cc
+++ b/gfx/harfbuzz/src/hb-face.cc
@@ -159,17 +159,17 @@ hb_face_t *
 hb_face_create (hb_blob_t    *blob,
 		unsigned int  index)
 {
   hb_face_t *face;
 
   if (unlikely (!blob))
     blob = hb_blob_get_empty ();
 
-  hb_face_for_data_closure_t *closure = _hb_face_for_data_closure_create (OT::Sanitizer<OT::OpenTypeFontFile>::sanitize (hb_blob_reference (blob)), index);
+  hb_face_for_data_closure_t *closure = _hb_face_for_data_closure_create (OT::Sanitizer<OT::OpenTypeFontFile>().sanitize (hb_blob_reference (blob)), index);
 
   if (unlikely (!closure))
     return hb_face_get_empty ();
 
   face = hb_face_create_for_tables (_hb_face_for_data_reference_table,
 				    closure,
 				    _hb_face_for_data_closure_destroy);
 
@@ -419,17 +419,17 @@ unsigned int
 hb_face_get_upem (hb_face_t *face)
 {
   return face->get_upem ();
 }
 
 void
 hb_face_t::load_upem (void) const
 {
-  hb_blob_t *head_blob = OT::Sanitizer<OT::head>::sanitize (reference_table (HB_OT_TAG_head));
+  hb_blob_t *head_blob = OT::Sanitizer<OT::head>().sanitize (reference_table (HB_OT_TAG_head));
   const OT::head *head_table = OT::Sanitizer<OT::head>::lock_instance (head_blob);
   upem = head_table->get_upem ();
   hb_blob_destroy (head_blob);
 }
 
 /**
  * hb_face_set_glyph_count:
  * @face: a face.
@@ -463,17 +463,17 @@ unsigned int
 hb_face_get_glyph_count (hb_face_t *face)
 {
   return face->get_num_glyphs ();
 }
 
 void
 hb_face_t::load_num_glyphs (void) const
 {
-  hb_blob_t *maxp_blob = OT::Sanitizer<OT::maxp>::sanitize (reference_table (HB_OT_TAG_maxp));
+  hb_blob_t *maxp_blob = OT::Sanitizer<OT::maxp>().sanitize (reference_table (HB_OT_TAG_maxp));
   const OT::maxp *maxp_table = OT::Sanitizer<OT::maxp>::lock_instance (maxp_blob);
   num_glyphs = maxp_table->get_num_glyphs ();
   hb_blob_destroy (maxp_blob);
 }
 
 /**
  * hb_face_get_table_tags:
  * @face: a face.
--- a/gfx/harfbuzz/src/hb-font-private.hh
+++ b/gfx/harfbuzz/src/hb-font-private.hh
@@ -123,16 +123,18 @@ struct hb_font_t {
 
   /* Convert from font-space to user-space */
   inline int dir_scale (hb_direction_t direction)
   { return HB_DIRECTION_IS_VERTICAL(direction) ? y_scale : x_scale; }
   inline hb_position_t em_scale_x (int16_t v) { return em_scale (v, x_scale); }
   inline hb_position_t em_scale_y (int16_t v) { return em_scale (v, y_scale); }
   inline hb_position_t em_scalef_x (float v) { return em_scalef (v, this->x_scale); }
   inline hb_position_t em_scalef_y (float v) { return em_scalef (v, this->y_scale); }
+  inline float em_fscale_x (int16_t v) { return em_fscale (v, x_scale); }
+  inline float em_fscale_y (int16_t v) { return em_fscale (v, y_scale); }
   inline hb_position_t em_scale_dir (int16_t v, hb_direction_t direction)
   { return em_scale (v, dir_scale (direction)); }
 
   /* Convert from parent-font user-space to our user-space */
   inline hb_position_t parent_scale_x_distance (hb_position_t v) {
     if (unlikely (parent && parent->x_scale != x_scale))
       return (hb_position_t) (v * (int64_t) this->x_scale / this->parent->x_scale);
     return v;
@@ -536,17 +538,21 @@ struct hb_font_t {
   {
     int upem = face->get_upem ();
     int64_t scaled = v * (int64_t) scale;
     scaled += scaled >= 0 ? upem/2 : -upem/2; /* Round. */
     return (hb_position_t) (scaled / upem);
   }
   inline hb_position_t em_scalef (float v, int scale)
   {
-    return (hb_position_t) (v * scale / face->get_upem ());
+    return (hb_position_t) round (v * scale / face->get_upem ());
+  }
+  inline float em_fscale (int16_t v, int scale)
+  {
+    return (float) v * scale / face->get_upem ();
   }
 };
 
 #define HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS
 #define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_PROTOTYPE(shaper, font);
 #include "hb-shaper-list.hh"
 #undef HB_SHAPER_IMPLEMENT
 #undef HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS
--- a/gfx/harfbuzz/src/hb-font.h
+++ b/gfx/harfbuzz/src/hb-font.h
@@ -451,17 +451,17 @@ HB_EXTERN hb_bool_t
 hb_font_get_glyph_from_name (hb_font_t *font,
 			     const char *name, int len, /* -1 means nul-terminated */
 			     hb_codepoint_t *glyph);
 
 
 /* high-level funcs, with fallback */
 
 /* Calls either hb_font_get_nominal_glyph() if variation_selector is 0,
- * otherwise callse hb_font_get_variation_glyph(). */
+ * otherwise calls hb_font_get_variation_glyph(). */
 HB_EXTERN hb_bool_t
 hb_font_get_glyph (hb_font_t *font,
 		   hb_codepoint_t unicode, hb_codepoint_t variation_selector,
 		   hb_codepoint_t *glyph);
 
 HB_EXTERN void
 hb_font_get_extents_for_direction (hb_font_t *font,
 				   hb_direction_t direction,
--- a/gfx/harfbuzz/src/hb-ft.cc
+++ b/gfx/harfbuzz/src/hb-ft.cc
@@ -630,25 +630,37 @@ hb_ft_font_changed (hb_font_t *font)
   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))
       {
+	bool nonzero = false;
+
 	for (unsigned int i = 0; i < mm_var->num_axis; ++i)
+	 {
 	  coords[i] = ft_coords[i] >>= 2;
+	  nonzero = nonzero || coords[i];
+	 }
 
-	hb_font_set_var_coords_normalized (font, coords, mm_var->num_axis);
+	if (nonzero)
+	  hb_font_set_var_coords_normalized (font, coords, mm_var->num_axis);
+	else
+	  hb_font_set_var_coords_normalized (font, nullptr, 0);
       }
     }
     free (coords);
     free (ft_coords);
+#ifdef HAVE_FT_DONE_MM_VAR
+    FT_Done_MM_Var (ft_face->glyph->library, mm_var);
+#else
     free (mm_var);
+#endif
   }
 #endif
 }
 
 /**
  * hb_ft_font_create_referenced:
  * @ft_face:
  *
--- a/gfx/harfbuzz/src/hb-open-file-private.hh
+++ b/gfx/harfbuzz/src/hb-open-file-private.hh
@@ -59,19 +59,19 @@ typedef struct TableRecord
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this));
   }
 
   Tag		tag;		/* 4-byte identifier. */
   CheckSum	checkSum;	/* CheckSum for this table. */
-  UINT32		offset;		/* Offset from beginning of TrueType font
+  HBUINT32		offset;		/* Offset from beginning of TrueType font
 				 * file. */
-  UINT32		length;		/* Length of this table. */
+  HBUINT32		length;		/* Length of this table. */
   public:
   DEFINE_SIZE_STATIC (16);
 } OpenTypeTable;
 
 typedef struct OffsetTable
 {
   friend struct OpenTypeFontFile;
 
@@ -149,17 +149,17 @@ struct TTCHeaderVersion1
     TRACE_SANITIZE (this);
     return_trace (table.sanitize (c, this));
   }
 
   protected:
   Tag		ttcTag;		/* TrueType Collection ID string: 'ttcf' */
   FixedVersion<>version;	/* Version of the TTC Header (1.0),
 				 * 0x00010000u */
-  ArrayOf<LOffsetTo<OffsetTable>, UINT32>
+  ArrayOf<LOffsetTo<OffsetTable>, HBUINT32>
 		table;		/* Array of offsets to the OffsetTable for each font
 				 * from the beginning of the file */
   public:
   DEFINE_SIZE_ARRAY (12, table);
 };
 
 struct TTCHeader
 {
--- a/gfx/harfbuzz/src/hb-open-type-private.hh
+++ b/gfx/harfbuzz/src/hb-open-type-private.hh
@@ -182,17 +182,18 @@ struct hb_dispatch_context_t
 
 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 (nullptr), end (nullptr),
 	writable (false), edit_count (0),
-	blob (nullptr) {}
+	blob (nullptr),
+	num_glyphs (0) {}
 
   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; }
@@ -293,26 +294,28 @@ struct hb_sanitize_context_t :
     return false;
   }
 
   mutable unsigned int debug_depth;
   const char *start, *end;
   bool writable;
   unsigned int edit_count;
   hb_blob_t *blob;
+  unsigned int num_glyphs;
 };
 
 
 
 /* Template to sanitize an object. */
 template <typename Type>
 struct Sanitizer
 {
-  static hb_blob_t *sanitize (hb_blob_t *blob) {
-    hb_sanitize_context_t c[1];
+  inline Sanitizer (void) {}
+
+  inline hb_blob_t *sanitize (hb_blob_t *blob) {
     bool sane;
 
     /* TODO is_sane() stuff */
 
     c->init (blob);
 
   retry:
     DEBUG_MSG_FUNC (SANITIZE, c->start, "start");
@@ -365,16 +368,21 @@ struct Sanitizer
     }
   }
 
   static const Type* lock_instance (hb_blob_t *blob) {
     hb_blob_make_immutable (blob);
     const char *base = hb_blob_get_data (blob, nullptr);
     return unlikely (!base) ? &Null(Type) : CastP<Type> (base);
   }
+
+  inline void set_num_glyphs (unsigned int num_glyphs) { c->num_glyphs = num_glyphs; }
+
+  private:
+  hb_sanitize_context_t c[1];
 };
 
 
 
 /*
  * Serialize
  */
 
@@ -514,18 +522,16 @@ struct Supplier
   inline Supplier (const Supplier<Type> &); /* Disallow copy */
   inline Supplier<Type>& operator= (const Supplier<Type> &); /* Disallow copy */
 
   unsigned int len;
   const Type *head;
 };
 
 
-
-
 /*
  *
  * The OpenType Font File: Data Types
  */
 
 
 /* "The following data types are used in the OpenType font file.
  *  All OpenType fonts use Motorola-style byte ordering (Big Endian):" */
@@ -630,41 +636,41 @@ struct IntType
     return_trace (likely (c->check_struct (this)));
   }
   protected:
   BEInt<Type, Size> v;
   public:
   DEFINE_SIZE_STATIC (Size);
 };
 
-typedef IntType<uint8_t,  1> UINT8;	/* 8-bit unsigned integer. */
-typedef IntType<int8_t,   1> INT8;	/* 8-bit signed integer. */
-typedef IntType<uint16_t, 2> UINT16;	/* 16-bit unsigned integer. */
-typedef IntType<int16_t,  2> INT16;	/* 16-bit signed integer. */
-typedef IntType<uint32_t, 4> UINT32;	/* 32-bit unsigned integer. */
-typedef IntType<int32_t,  4> INT32;	/* 32-bit signed integer. */
+typedef IntType<uint8_t,  1> HBUINT8;	/* 8-bit unsigned integer. */
+typedef IntType<int8_t,   1> HBINT8;	/* 8-bit signed integer. */
+typedef IntType<uint16_t, 2> HBUINT16;	/* 16-bit unsigned integer. */
+typedef IntType<int16_t,  2> HBINT16;	/* 16-bit signed integer. */
+typedef IntType<uint32_t, 4> HBUINT32;	/* 32-bit unsigned integer. */
+typedef IntType<int32_t,  4> HBINT32;	/* 32-bit signed integer. */
 typedef IntType<uint32_t, 3> UINT24;	/* 24-bit unsigned integer. */
 
-/* 16-bit signed integer (INT16) that describes a quantity in FUnits. */
-typedef INT16 FWORD;
+/* 16-bit signed integer (HBINT16) that describes a quantity in FUnits. */
+typedef HBINT16 FWORD;
 
-/* 16-bit unsigned integer (UINT16) that describes a quantity in FUnits. */
-typedef UINT16 UFWORD;
+/* 16-bit unsigned integer (HBUINT16) that describes a quantity in FUnits. */
+typedef HBUINT16 UFWORD;
 
 /* 16-bit signed fixed number with the low 14 bits of fraction (2.14). */
-struct F2DOT14 : INT16
+struct F2DOT14 : HBINT16
 {
   //inline float to_float (void) const { return ???; }
   //inline void set_float (float f) { v.set (f * ???); }
   public:
   DEFINE_SIZE_STATIC (2);
 };
 
 /* 32-bit signed fixed-point number (16.16). */
-struct Fixed: INT32
+struct Fixed: HBINT32
 {
   //inline float to_float (void) const { return ???; }
   //inline void set_float (float f) { v.set (f * ???); }
   public:
   DEFINE_SIZE_STATIC (4);
 };
 
 /* Date represented in number of seconds since 12:00 midnight, January 1,
@@ -672,84 +678,84 @@ struct Fixed: INT32
 struct LONGDATETIME
 {
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (likely (c->check_struct (this)));
   }
   protected:
-  INT32 major;
-  UINT32 minor;
+  HBINT32 major;
+  HBUINT32 minor;
   public:
   DEFINE_SIZE_STATIC (8);
 };
 
 /* Array of four uint8s (length = 32 bits) used to identify a script, language
  * system, feature, or baseline */
-struct Tag : UINT32
+struct Tag : HBUINT32
 {
   /* What the char* converters return is NOT nul-terminated.  Print using "%.4s" */
   inline operator const char* (void) const { return reinterpret_cast<const char *> (&this->v); }
   inline operator char* (void) { return reinterpret_cast<char *> (&this->v); }
   public:
   DEFINE_SIZE_STATIC (4);
 };
 DEFINE_NULL_DATA (Tag, "    ");
 
 /* Glyph index number, same as uint16 (length = 16 bits) */
-typedef UINT16 GlyphID;
+typedef HBUINT16 GlyphID;
 
 /* Script/language-system/feature index */
-struct Index : UINT16 {
+struct Index : HBUINT16 {
   static const unsigned int NOT_FOUND_INDEX = 0xFFFFu;
 };
 DEFINE_NULL_DATA (Index, "\xff\xff");
 
 /* Offset, Null offset = 0 */
 template <typename Type>
 struct Offset : Type
 {
   inline bool is_null (void) const { return 0 == *this; }
   public:
   DEFINE_SIZE_STATIC (sizeof(Type));
 };
 
-typedef Offset<UINT16> Offset16;
-typedef Offset<UINT32> Offset32;
+typedef Offset<HBUINT16> Offset16;
+typedef Offset<HBUINT32> Offset32;
 
 
 /* CheckSum */
-struct CheckSum : UINT32
+struct CheckSum : HBUINT32
 {
   /* This is reference implementation from the spec. */
-  static inline uint32_t CalcTableChecksum (const UINT32 *Table, uint32_t Length)
+  static inline uint32_t CalcTableChecksum (const HBUINT32 *Table, uint32_t Length)
   {
     uint32_t Sum = 0L;
-    const UINT32 *EndPtr = Table+((Length+3) & ~3) / UINT32::static_size;
+    const HBUINT32 *EndPtr = Table+((Length+3) & ~3) / HBUINT32::static_size;
 
     while (Table < EndPtr)
       Sum += *Table++;
     return Sum;
   }
 
   /* Note: data should be 4byte aligned and have 4byte padding at the end. */
   inline void set_for_data (const void *data, unsigned int length)
-  { set (CalcTableChecksum ((const UINT32 *) data, length)); }
+  { set (CalcTableChecksum ((const HBUINT32 *) data, length)); }
 
   public:
   DEFINE_SIZE_STATIC (4);
 };
 
 
 /*
  * Version Numbers
  */
 
-template <typename FixedType=UINT16>
+template <typename FixedType=HBUINT16>
 struct FixedVersion
 {
   inline uint32_t to_int (void) const { return (major << (sizeof(FixedType) * 8)) + minor; }
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this));
@@ -763,17 +769,17 @@ struct FixedVersion
 
 
 
 /*
  * Template subclasses of Offset that do the dereferencing.
  * Use: (base+offset)
  */
 
-template <typename Type, typename OffsetType=UINT16>
+template <typename Type, typename OffsetType=HBUINT16>
 struct OffsetTo : Offset<OffsetType>
 {
   inline const Type& operator () (const void *base) const
   {
     unsigned int offset = *this;
     if (unlikely (!offset)) return Null(Type);
     return StructAtOffset<Type> (base, offset);
   }
@@ -808,29 +814,29 @@ struct OffsetTo : Offset<OffsetType>
   }
 
   /* Set the offset to Null */
   inline bool neuter (hb_sanitize_context_t *c) const {
     return c->try_set (this, 0);
   }
   DEFINE_SIZE_STATIC (sizeof(OffsetType));
 };
-template <typename Type> struct LOffsetTo : OffsetTo<Type, UINT32> {};
+template <typename Type> struct LOffsetTo : OffsetTo<Type, HBUINT32> {};
 template <typename Base, typename OffsetType, typename Type>
 static inline const Type& operator + (const Base &base, const OffsetTo<Type, OffsetType> &offset) { return offset (base); }
 template <typename Base, typename OffsetType, typename Type>
 static inline Type& operator + (Base &base, OffsetTo<Type, OffsetType> &offset) { return offset (base); }
 
 
 /*
  * Array Types
  */
 
 /* An array with a number of elements. */
-template <typename Type, typename LenType=UINT16>
+template <typename Type, typename LenType=HBUINT16>
 struct ArrayOf
 {
   const Type *sub_array (unsigned int start_offset, unsigned int *pcount /* IN/OUT */) const
   {
     unsigned int count = len;
     if (unlikely (start_offset > count))
       count = 0;
     else
@@ -930,20 +936,20 @@ struct ArrayOf
   }
 
   public:
   LenType len;
   Type array[VAR];
   public:
   DEFINE_SIZE_ARRAY (sizeof (LenType), array);
 };
-template <typename Type> struct LArrayOf : ArrayOf<Type, UINT32> {};
+template <typename Type> struct LArrayOf : ArrayOf<Type, HBUINT32> {};
 
 /* Array of Offset's */
-template <typename Type, typename OffsetType=UINT16>
+template <typename Type, typename OffsetType=HBUINT16>
 struct OffsetArrayOf : ArrayOf<OffsetTo<Type, OffsetType> > {};
 
 /* Array of offsets relative to the beginning of the array itself. */
 template <typename Type>
 struct OffsetListOf : OffsetArrayOf<Type>
 {
   inline const Type& operator [] (unsigned int i) const
   {
@@ -961,17 +967,17 @@ struct OffsetListOf : OffsetArrayOf<Type
   {
     TRACE_SANITIZE (this);
     return_trace (OffsetArrayOf<Type>::sanitize (c, this, user_data));
   }
 };
 
 
 /* An array starting at second element. */
-template <typename Type, typename LenType=UINT16>
+template <typename Type, typename LenType=HBUINT16>
 struct HeadlessArrayOf
 {
   inline const Type& operator [] (unsigned int i) const
   {
     if (unlikely (i >= len || !i)) return Null(Type);
     return array[i-1];
   }
   inline unsigned int get_size (void) const
@@ -1023,29 +1029,29 @@ struct HeadlessArrayOf
   public:
   DEFINE_SIZE_ARRAY (sizeof (LenType), array);
 };
 
 
 /*
  * An array with sorted elements.  Supports binary searching.
  */
-template <typename Type, typename LenType=UINT16>
+template <typename Type, typename LenType=HBUINT16>
 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;
+    const Type *arr = this->array;
     int min = 0, max = (int) this->len - 1;
     while (min <= max)
     {
       int mid = (min + max) / 2;
-      int c = array[mid].cmp (x);
+      int c = arr[mid].cmp (x);
       if (c < 0)
         max = mid - 1;
       else if (c > 0)
         min = mid + 1;
       else
         return mid;
     }
     return -1;
@@ -1062,20 +1068,20 @@ struct BinSearchHeader
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this));
   }
 
   protected:
-  UINT16	len;
-  UINT16	searchRangeZ;
-  UINT16	entrySelectorZ;
-  UINT16	rangeShiftZ;
+  HBUINT16	len;
+  HBUINT16	searchRangeZ;
+  HBUINT16	entrySelectorZ;
+  HBUINT16	rangeShiftZ;
 
   public:
   DEFINE_SIZE_STATIC (8);
 };
 
 template <typename Type>
 struct BinSearchArrayOf : SortedArrayOf<Type, BinSearchHeader> {};
 
@@ -1134,51 +1140,51 @@ 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_;
+    blob = nullptr;
     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));
+      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), nullptr, p))
       {
 	hb_blob_destroy (blob_);
 	goto retry;
       }
       blob = blob_;
     }
     return p;
   }
 
   inline const T* operator-> (void) const
   {
     return get();
   }
 
+  hb_face_t *face;
+  mutable hb_blob_t *blob;
   private:
-  hb_face_t *face;
-  T *instance;
-  mutable hb_blob_t *blob;
+  mutable T *instance;
 };
 
 
 } /* namespace OT */
 
 
 #endif /* HB_OPEN_TYPE_PRIVATE_HH */
--- a/gfx/harfbuzz/src/hb-ot-cbdt-table.hh
+++ b/gfx/harfbuzz/src/hb-ot-cbdt-table.hh
@@ -42,54 +42,54 @@ struct SmallGlyphMetrics
   inline void get_extents (hb_glyph_extents_t *extents) const
   {
     extents->x_bearing = bearingX;
     extents->y_bearing = bearingY;
     extents->width = width;
     extents->height = -height;
   }
 
-  UINT8 height;
-  UINT8 width;
-  INT8 bearingX;
-  INT8 bearingY;
-  UINT8 advance;
+  HBUINT8 height;
+  HBUINT8 width;
+  HBINT8 bearingX;
+  HBINT8 bearingY;
+  HBUINT8 advance;
 
   DEFINE_SIZE_STATIC(5);
 };
 
 struct BigGlyphMetrics : SmallGlyphMetrics
 {
-  INT8 vertBearingX;
-  INT8 vertBearingY;
-  UINT8 vertAdvance;
+  HBINT8 vertBearingX;
+  HBINT8 vertBearingY;
+  HBUINT8 vertAdvance;
 
   DEFINE_SIZE_STATIC(8);
 };
 
 struct SBitLineMetrics
 {
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this));
   }
 
-  INT8 ascender;
-  INT8 decender;
-  UINT8 widthMax;
-  INT8 caretSlopeNumerator;
-  INT8 caretSlopeDenominator;
-  INT8 caretOffset;
-  INT8 minOriginSB;
-  INT8 minAdvanceSB;
-  INT8 maxBeforeBL;
-  INT8 minAfterBL;
-  INT8 padding1;
-  INT8 padding2;
+  HBINT8 ascender;
+  HBINT8 decender;
+  HBUINT8 widthMax;
+  HBINT8 caretSlopeNumerator;
+  HBINT8 caretSlopeDenominator;
+  HBINT8 caretOffset;
+  HBINT8 minOriginSB;
+  HBINT8 minAdvanceSB;
+  HBINT8 maxBeforeBL;
+  HBINT8 minAfterBL;
+  HBINT8 padding1;
+  HBINT8 padding2;
 
   DEFINE_SIZE_STATIC(12);
 };
 
 
 /*
  * Index Subtables.
  */
@@ -97,19 +97,19 @@ struct SBitLineMetrics
 struct IndexSubtableHeader
 {
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this));
   }
 
-  UINT16 indexFormat;
-  UINT16 imageFormat;
-  UINT32 imageDataOffset;
+  HBUINT16 indexFormat;
+  HBUINT16 imageFormat;
+  HBUINT32 imageDataOffset;
 
   DEFINE_SIZE_STATIC(8);
 };
 
 template <typename OffsetType>
 struct IndexSubtableFormat1Or3
 {
   inline bool sanitize (hb_sanitize_context_t *c, unsigned int glyph_count) const
@@ -132,18 +132,18 @@ struct IndexSubtableFormat1Or3
   }
 
   IndexSubtableHeader header;
   Offset<OffsetType> offsetArrayZ[VAR];
 
   DEFINE_SIZE_ARRAY(8, offsetArrayZ);
 };
 
-struct IndexSubtableFormat1 : IndexSubtableFormat1Or3<UINT32> {};
-struct IndexSubtableFormat3 : IndexSubtableFormat1Or3<UINT16> {};
+struct IndexSubtableFormat1 : IndexSubtableFormat1Or3<HBUINT32> {};
+struct IndexSubtableFormat3 : IndexSubtableFormat1Or3<HBUINT16> {};
 
 struct IndexSubtable
 {
   inline bool sanitize (hb_sanitize_context_t *c, unsigned int glyph_count) const
   {
     TRACE_SANITIZE (this);
     if (!u.header.sanitize (c)) return_trace (false);
     switch (u.header.indexFormat) {
@@ -209,18 +209,18 @@ struct IndexSubtableRecord
     if (gid < firstGlyphIndex || gid > lastGlyphIndex)
     {
       return false;
     }
     return (this+offsetToSubtable).get_image_data (gid - firstGlyphIndex,
 						   offset, length, format);
   }
 
-  UINT16 firstGlyphIndex;
-  UINT16 lastGlyphIndex;
+  HBUINT16 firstGlyphIndex;
+  HBUINT16 lastGlyphIndex;
   LOffsetTo<IndexSubtable> offsetToSubtable;
 
   DEFINE_SIZE_STATIC(8);
 };
 
 struct IndexSubtableArray
 {
   inline bool sanitize (hb_sanitize_context_t *c, unsigned int count) const
@@ -271,42 +271,42 @@ struct BitmapSizeTable
 
   const IndexSubtableRecord *find_table (hb_codepoint_t glyph, const void *base) const
   {
     return (base+indexSubtableArrayOffset).find_table (glyph, numberOfIndexSubtables);
   }
 
   protected:
   LOffsetTo<IndexSubtableArray> indexSubtableArrayOffset;
-  UINT32 indexTablesSize;
-  UINT32 numberOfIndexSubtables;
-  UINT32 colorRef;
+  HBUINT32 indexTablesSize;
+  HBUINT32 numberOfIndexSubtables;
+  HBUINT32 colorRef;
   SBitLineMetrics horizontal;
   SBitLineMetrics vertical;
-  UINT16 startGlyphIndex;
-  UINT16 endGlyphIndex;
-  UINT8 ppemX;
-  UINT8 ppemY;
-  UINT8 bitDepth;
-  INT8 flags;
+  HBUINT16 startGlyphIndex;
+  HBUINT16 endGlyphIndex;
+  HBUINT8 ppemX;
+  HBUINT8 ppemY;
+  HBUINT8 bitDepth;
+  HBINT8 flags;
 
   public:
   DEFINE_SIZE_STATIC(48);
 };
 
 
 /*
  * Glyph Bitmap Data Formats.
  */
 
 struct GlyphBitmapDataFormat17
 {
   SmallGlyphMetrics glyphMetrics;
-  UINT32 dataLen;
-  UINT8 dataZ[VAR];
+  HBUINT32 dataLen;
+  HBUINT8 dataZ[VAR];
 
   DEFINE_SIZE_ARRAY(9, dataZ);
 };
 
 
 /*
  * CBLC -- Color Bitmap Location Table
  */
@@ -374,18 +374,18 @@ struct CBDT
   }
 
   struct accelerator_t
   {
     inline void init (hb_face_t *face)
     {
       upem = face->get_upem();
 
-      cblc_blob = Sanitizer<CBLC>::sanitize (face->reference_table (HB_OT_TAG_CBLC));
-      cbdt_blob = Sanitizer<CBDT>::sanitize (face->reference_table (HB_OT_TAG_CBDT));
+      cblc_blob = Sanitizer<CBLC>().sanitize (face->reference_table (HB_OT_TAG_CBLC));
+      cbdt_blob = Sanitizer<CBDT>().sanitize (face->reference_table (HB_OT_TAG_CBDT));
       cbdt_len = hb_blob_get_length (cbdt_blob);
 
       if (hb_blob_get_length (cblc_blob) == 0) {
 	cblc = nullptr;
 	cbdt = nullptr;
 	return;  /* Not a bitmap font. */
       }
       cblc = Sanitizer<CBLC>::lock_instance (cblc_blob);
@@ -455,17 +455,17 @@ struct CBDT
 
     unsigned int cbdt_len;
     unsigned int upem;
   };
 
 
   protected:
   FixedVersion<>version;
-  UINT8 dataZ[VAR];
+  HBUINT8 dataZ[VAR];
 
   public:
   DEFINE_SIZE_ARRAY(4, dataZ);
 };
 
 } /* namespace OT */
 
 #endif /* HB_OT_CBDT_TABLE_HH */
--- a/gfx/harfbuzz/src/hb-ot-cmap-table.hh
+++ b/gfx/harfbuzz/src/hb-ot-cmap-table.hh
@@ -53,20 +53,20 @@ struct CmapSubtableFormat0
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this));
   }
 
   protected:
-  UINT16	format;		/* Format number is set to 0. */
-  UINT16	lengthZ;	/* Byte length of this subtable. */
-  UINT16	languageZ;	/* Ignore. */
-  UINT8		glyphIdArray[256];/* An array that maps character
+  HBUINT16	format;		/* Format number is set to 0. */
+  HBUINT16	lengthZ;	/* Byte length of this subtable. */
+  HBUINT16	languageZ;	/* Ignore. */
+  HBUINT8		glyphIdArray[256];/* An array that maps character
 				 * code to glyph index values. */
   public:
   DEFINE_SIZE_STATIC (6 + 256);
 };
 
 struct CmapSubtableFormat4
 {
   struct accelerator_t
@@ -83,18 +83,18 @@ struct CmapSubtableFormat4
     }
 
     static inline bool get_glyph_func (const void *obj, hb_codepoint_t codepoint, hb_codepoint_t *glyph)
     {
       const accelerator_t *thiz = (const accelerator_t *) obj;
 
       /* Custom two-array bsearch. */
       int min = 0, max = (int) thiz->segCount - 1;
-      const UINT16 *startCount = thiz->startCount;
-      const UINT16 *endCount = thiz->endCount;
+      const HBUINT16 *startCount = thiz->startCount;
+      const HBUINT16 *endCount = thiz->endCount;
       unsigned int i;
       while (min <= max)
       {
 	int mid = (min + max) / 2;
 	if (codepoint < startCount[mid])
 	  max = mid - 1;
 	else if (codepoint > endCount[mid])
 	  min = mid + 1;
@@ -122,21 +122,21 @@ struct CmapSubtableFormat4
 	  return false;
 	gid += thiz->idDelta[i];
       }
 
       *glyph = gid & 0xFFFFu;
       return true;
     }
 
-    const UINT16 *endCount;
-    const UINT16 *startCount;
-    const UINT16 *idDelta;
-    const UINT16 *idRangeOffset;
-    const UINT16 *glyphIdArray;
+    const HBUINT16 *endCount;
+    const HBUINT16 *startCount;
+    const HBUINT16 *idDelta;
+    const HBUINT16 *idRangeOffset;
+    const HBUINT16 *glyphIdArray;
     unsigned int segCount;
     unsigned int glyphIdArrayLength;
   };
 
   inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
   {
     accelerator_t accel;
     accel.init (this);
@@ -160,34 +160,34 @@ struct CmapSubtableFormat4
       if (!c->try_set (&length, new_length))
 	return_trace (false);
     }
 
     return_trace (16 + 4 * (unsigned int) segCountX2 <= length);
   }
 
   protected:
-  UINT16	format;		/* Format number is set to 4. */
-  UINT16	length;		/* This is the length in bytes of the
+  HBUINT16	format;		/* Format number is set to 4. */
+  HBUINT16	length;		/* This is the length in bytes of the
 				 * subtable. */
-  UINT16	languageZ;	/* Ignore. */
-  UINT16	segCountX2;	/* 2 x segCount. */
-  UINT16	searchRangeZ;	/* 2 * (2**floor(log2(segCount))) */
-  UINT16	entrySelectorZ;	/* log2(searchRange/2) */
-  UINT16	rangeShiftZ;	/* 2 x segCount - searchRange */
+  HBUINT16	languageZ;	/* Ignore. */
+  HBUINT16	segCountX2;	/* 2 x segCount. */
+  HBUINT16	searchRangeZ;	/* 2 * (2**floor(log2(segCount))) */
+  HBUINT16	entrySelectorZ;	/* log2(searchRange/2) */
+  HBUINT16	rangeShiftZ;	/* 2 x segCount - searchRange */
 
-  UINT16	values[VAR];
+  HBUINT16	values[VAR];
 #if 0
-  UINT16	endCount[segCount];	/* End characterCode for each segment,
+  HBUINT16	endCount[segCount];	/* End characterCode for each segment,
 					 * last=0xFFFFu. */
-  UINT16	reservedPad;		/* Set to 0. */
-  UINT16	startCount[segCount];	/* Start character code for each segment. */
-  INT16		idDelta[segCount];	/* Delta for all character codes in segment. */
-  UINT16	idRangeOffset[segCount];/* Offsets into glyphIdArray or 0 */
-  UINT16	glyphIdArray[VAR];	/* Glyph index array (arbitrary length) */
+  HBUINT16	reservedPad;		/* Set to 0. */
+  HBUINT16	startCount[segCount];	/* Start character code for each segment. */
+  HBINT16		idDelta[segCount];	/* Delta for all character codes in segment. */
+  HBUINT16	idRangeOffset[segCount];/* Offsets into glyphIdArray or 0 */
+  HBUINT16	glyphIdArray[VAR];	/* Glyph index array (arbitrary length) */
 #endif
 
   public:
   DEFINE_SIZE_ARRAY (14, values);
 };
 
 struct CmapSubtableLongGroup
 {
@@ -203,19 +203,19 @@ struct CmapSubtableLongGroup
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this));
   }
 
   private:
-  UINT32		startCharCode;	/* First character code in this group. */
-  UINT32		endCharCode;	/* Last character code in this group. */
-  UINT32		glyphID;	/* Glyph index; interpretation depends on
+  HBUINT32		startCharCode;	/* First character code in this group. */
+  HBUINT32		endCharCode;	/* Last character code in this group. */
+  HBUINT32		glyphID;	/* Glyph index; interpretation depends on
 				 * subtable format. */
   public:
   DEFINE_SIZE_STATIC (12);
 };
 
 template <typename UINT>
 struct CmapSubtableTrimmed
 {
@@ -242,18 +242,18 @@ struct CmapSubtableTrimmed
   UINT		startCharCode;	/* First character code covered. */
   ArrayOf<GlyphID, UINT>
 		glyphIdArray;	/* Array of glyph index values for character
 				 * codes in the range. */
   public:
   DEFINE_SIZE_ARRAY (5 * sizeof (UINT), glyphIdArray);
 };
 
-struct CmapSubtableFormat6  : CmapSubtableTrimmed<UINT16> {};
-struct CmapSubtableFormat10 : CmapSubtableTrimmed<UINT32 > {};
+struct CmapSubtableFormat6  : CmapSubtableTrimmed<HBUINT16> {};
+struct CmapSubtableFormat10 : CmapSubtableTrimmed<HBUINT32 > {};
 
 template <typename T>
 struct CmapSubtableLongSegmented
 {
   inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
   {
     int i = groups.bsearch (codepoint);
     if (i == -1)
@@ -264,21 +264,21 @@ struct CmapSubtableLongSegmented
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) && groups.sanitize (c));
   }
 
   protected:
-  UINT16	format;		/* Subtable format; set to 12. */
-  UINT16	reservedZ;	/* Reserved; set to 0. */
-  UINT32		lengthZ;	/* Byte length of this subtable. */
-  UINT32		languageZ;	/* Ignore. */
-  SortedArrayOf<CmapSubtableLongGroup, UINT32>
+  HBUINT16	format;		/* Subtable format; set to 12. */
+  HBUINT16	reservedZ;	/* Reserved; set to 0. */
+  HBUINT32		lengthZ;	/* Byte length of this subtable. */
+  HBUINT32		languageZ;	/* Ignore. */
+  SortedArrayOf<CmapSubtableLongGroup, HBUINT32>
 		groups;		/* Groupings. */
   public:
   DEFINE_SIZE_ARRAY (16, groups);
 };
 
 struct CmapSubtableFormat12 : CmapSubtableLongSegmented<CmapSubtableFormat12>
 {
   static inline hb_codepoint_t group_get_glyph (const CmapSubtableLongGroup &group,
@@ -311,23 +311,23 @@ struct UnicodeValueRange
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this));
   }
 
   UINT24	startUnicodeValue;	/* First value in this range. */
-  UINT8		additionalCount;	/* Number of additional values in this
+  HBUINT8		additionalCount;	/* Number of additional values in this
 					 * range. */
   public:
   DEFINE_SIZE_STATIC (4);
 };
 
-typedef SortedArrayOf<UnicodeValueRange, UINT32> DefaultUVS;
+typedef SortedArrayOf<UnicodeValueRange, HBUINT32> DefaultUVS;
 
 struct UVSMapping
 {
   inline int cmp (const hb_codepoint_t &codepoint) const
   {
     return unicodeValue.cmp (codepoint);
   }
 
@@ -338,17 +338,17 @@ struct UVSMapping
   }
 
   UINT24	unicodeValue;	/* Base Unicode value of the UVS */
   GlyphID	glyphID;	/* Glyph ID of the UVS */
   public:
   DEFINE_SIZE_STATIC (5);
 };
 
-typedef SortedArrayOf<UVSMapping, UINT32> NonDefaultUVS;
+typedef SortedArrayOf<UVSMapping, HBUINT32> NonDefaultUVS;
 
 struct VariationSelectorRecord
 {
   inline glyph_variant_t get_glyph (hb_codepoint_t codepoint,
 				    hb_codepoint_t *glyph,
 				    const void *base) const
   {
     int i;
@@ -400,19 +400,19 @@ struct CmapSubtableFormat14
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) &&
 		  record.sanitize (c, this));
   }
 
   protected:
-  UINT16	format;		/* Format number is set to 14. */
-  UINT32		lengthZ;	/* Byte length of this subtable. */
-  SortedArrayOf<VariationSelectorRecord, UINT32>
+  HBUINT16	format;		/* Format number is set to 14. */
+  HBUINT32		lengthZ;	/* Byte length of this subtable. */
+  SortedArrayOf<VariationSelectorRecord, HBUINT32>
 		record;		/* Variation selector records; sorted
 				 * in increasing order of `varSelector'. */
   public:
   DEFINE_SIZE_ARRAY (10, record);
 };
 
 struct CmapSubtable
 {
@@ -446,17 +446,17 @@ struct CmapSubtable
     case 13: return_trace (u.format13.sanitize (c));
     case 14: return_trace (u.format14.sanitize (c));
     default:return_trace (true);
     }
   }
 
   public:
   union {
-  UINT16		format;		/* Format identifier */
+  HBUINT16		format;		/* Format identifier */
   CmapSubtableFormat0	format0;
   CmapSubtableFormat4	format4;
   CmapSubtableFormat6	format6;
   CmapSubtableFormat10	format10;
   CmapSubtableFormat12	format12;
   CmapSubtableFormat13	format13;
   CmapSubtableFormat14	format14;
   } u;
@@ -479,18 +479,18 @@ struct EncodingRecord
 
   inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) &&
 		  subtable.sanitize (c, base));
   }
 
-  UINT16	platformID;	/* Platform ID. */
-  UINT16	encodingID;	/* Platform-specific encoding ID. */
+  HBUINT16	platformID;	/* Platform ID. */
+  HBUINT16	encodingID;	/* Platform-specific encoding ID. */
   LOffsetTo<CmapSubtable>
 		subtable;	/* Byte offset from beginning of table to the subtable for this encoding. */
   public:
   DEFINE_SIZE_STATIC (8);
 };
 
 struct cmap
 {
@@ -503,17 +503,17 @@ struct cmap
 		  likely (version == 0) &&
 		  encodingRecord.sanitize (c, this));
   }
 
   struct accelerator_t
   {
     inline void init (hb_face_t *face)
     {
-      this->blob = OT::Sanitizer<OT::cmap>::sanitize (face->reference_table (HB_OT_TAG_cmap));
+      this->blob = OT::Sanitizer<OT::cmap>().sanitize (face->reference_table (HB_OT_TAG_cmap));
       const OT::cmap *cmap = OT::Sanitizer<OT::cmap>::lock_instance (this->blob);
       const OT::CmapSubtable *subtable = nullptr;
       const OT::CmapSubtableFormat14 *subtable_uvs = nullptr;
 
       bool symbol = false;
       /* 32-bit subtables. */
       if (!subtable) subtable = cmap->find_subtable (3, 10);
       if (!subtable) subtable = cmap->find_subtable (0, 6);
@@ -649,17 +649,17 @@ struct cmap
     int result = encodingRecord./*bsearch*/lsearch (key);
     if (result == -1 || !encodingRecord[result].subtable)
       return nullptr;
 
     return &(this+encodingRecord[result].subtable);
   }
 
   protected:
-  UINT16		version;	/* Table version number (0). */
+  HBUINT16		version;	/* Table version number (0). */
   SortedArrayOf<EncodingRecord>
 			encodingRecord;	/* Encoding tables. */
   public:
   DEFINE_SIZE_ARRAY (4, encodingRecord);
 };
 
 
 } /* namespace OT */
--- a/gfx/harfbuzz/src/hb-ot-glyf-table.hh
+++ b/gfx/harfbuzz/src/hb-ot-glyf-table.hh
@@ -49,17 +49,17 @@ struct loca
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (true);
   }
 
   protected:
-  UINT8		dataX[VAR];		/* Location data. */
+  HBUINT8		dataX[VAR];		/* Location data. */
   DEFINE_SIZE_ARRAY (0, dataX);
 };
 
 
 /*
  * glyf -- TrueType Glyph Data
  */
 
@@ -75,46 +75,46 @@ struct glyf
     TRACE_SANITIZE (this);
     /* We don't check for anything specific here.  The users of the
      * struct do all the hard work... */
     return_trace (true);
   }
 
   struct GlyphHeader
   {
-    INT16		numberOfContours;	/* If the number of contours is
+    HBINT16		numberOfContours;	/* If the number of contours is
 					   * greater than or equal to zero,
 					   * this is a simple glyph; if negative,
 					   * this is a composite glyph. */
     FWORD		xMin;			/* Minimum x for coordinate data. */
     FWORD		yMin;			/* Minimum y for coordinate data. */
     FWORD		xMax;			/* Maximum x for coordinate data. */
     FWORD		yMax;			/* Maximum y for coordinate data. */
 
     DEFINE_SIZE_STATIC (10);
   };
 
   struct accelerator_t
   {
     inline void init (hb_face_t *face)
     {
-      hb_blob_t *head_blob = Sanitizer<head>::sanitize (face->reference_table (HB_OT_TAG_head));
+      hb_blob_t *head_blob = Sanitizer<head>().sanitize (face->reference_table (HB_OT_TAG_head));
       const head *head_table = Sanitizer<head>::lock_instance (head_blob);
       if ((unsigned int) head_table->indexToLocFormat > 1 || head_table->glyphDataFormat != 0)
       {
 	/* Unknown format.  Leave num_glyphs=0, that takes care of disabling us. */
 	hb_blob_destroy (head_blob);
 	return;
       }
       short_offset = 0 == head_table->indexToLocFormat;
       hb_blob_destroy (head_blob);
 
-      loca_blob = Sanitizer<loca>::sanitize (face->reference_table (HB_OT_TAG_loca));
+      loca_blob = Sanitizer<loca>().sanitize (face->reference_table (HB_OT_TAG_loca));
       loca_table = Sanitizer<loca>::lock_instance (loca_blob);
-      glyf_blob = Sanitizer<glyf>::sanitize (face->reference_table (HB_OT_TAG_glyf));
+      glyf_blob = Sanitizer<glyf>().sanitize (face->reference_table (HB_OT_TAG_glyf));
       glyf_table = Sanitizer<glyf>::lock_instance (glyf_blob);
 
       num_glyphs = MAX (1u, hb_blob_get_length (loca_blob) / (short_offset ? 2 : 4)) - 1;
       glyf_len = hb_blob_get_length (glyf_blob);
     }
 
     inline void fini (void)
     {
@@ -126,23 +126,23 @@ struct glyf
 			     hb_glyph_extents_t *extents) const
     {
       if (unlikely (glyph >= num_glyphs))
 	return false;
 
       unsigned int start_offset, end_offset;
       if (short_offset)
       {
-        const UINT16 *offsets = (const UINT16 *) loca_table->dataX;
+        const HBUINT16 *offsets = (const HBUINT16 *) loca_table->dataX;
 	start_offset = 2 * offsets[glyph];
 	end_offset   = 2 * offsets[glyph + 1];
       }
       else
       {
-        const UINT32 *offsets = (const UINT32 *) loca_table->dataX;
+        const HBUINT32 *offsets = (const HBUINT32 *) loca_table->dataX;
 	start_offset = offsets[glyph];
 	end_offset   = offsets[glyph + 1];
       }
 
       if (start_offset > end_offset || end_offset > glyf_len)
 	return false;
 
       if (end_offset - start_offset < GlyphHeader::static_size)
@@ -164,17 +164,17 @@ struct glyf
     const loca *loca_table;
     const glyf *glyf_table;
     hb_blob_t *loca_blob;
     hb_blob_t *glyf_blob;
     unsigned int glyf_len;
   };
 
   protected:
-  UINT8		dataX[VAR];		/* Glyphs data. */
+  HBUINT8		dataX[VAR];		/* Glyphs data. */
 
   DEFINE_SIZE_ARRAY (0, dataX);
 };
 
 } /* namespace OT */
 
 
 #endif /* HB_OT_GLYF_TABLE_HH */
--- a/gfx/harfbuzz/src/hb-ot-head-table.hh
+++ b/gfx/harfbuzz/src/hb-ot-head-table.hh
@@ -59,29 +59,28 @@ struct head
 		  version.major == 1 &&
 		  magicNumber == 0x5F0F3CF5u);
   }
 
   protected:
   FixedVersion<>version;		/* Version of the head table--currently
 					 * 0x00010000u for version 1.0. */
   FixedVersion<>fontRevision;		/* Set by font manufacturer. */
-  UINT32		checkSumAdjustment;	/* To compute: set it to 0, sum the
-					 * entire font as UINT32, then store
+  HBUINT32	checkSumAdjustment;	/* To compute: set it to 0, sum the
+					 * entire font as HBUINT32, then store
 					 * 0xB1B0AFBAu - sum. */
-  UINT32		magicNumber;		/* Set to 0x5F0F3CF5u. */
-  UINT16	flags;			/* Bit 0: Baseline for font at y=0;
+  HBUINT32	magicNumber;		/* Set to 0x5F0F3CF5u. */
+  HBUINT16	flags;			/* Bit 0: Baseline for font at y=0;
 					 * Bit 1: Left sidebearing point at x=0;
 					 * Bit 2: Instructions may depend on point size;
 					 * Bit 3: Force ppem to integer values for all
 					 *   internal scaler math; may use fractional
 					 *   ppem sizes if this bit is clear;
 					 * Bit 4: Instructions may alter advance width
 					 *   (the advance widths might not scale linearly);
-
 					 * Bits 5-10: These should be set according to
 					 *   Apple's specification. However, they are not
 					 *   implemented in OpenType.
 					 * Bit 5: This bit should be set in fonts that are
 					 *   intended to e laid out vertically, and in
 					 *   which the glyphs have been drawn such that an
 					 *   x-coordinate of 0 corresponds to the desired
 					 *   vertical baseline.
@@ -91,17 +90,16 @@ struct head
 					 *   rendering (e.g. Arabic fonts).
 					 * Bit 8: This bit should be set for a GX font
 					 *   which has one or more metamorphosis effects
 					 *   designated as happening by default.
 					 * Bit 9: This bit should be set if the font
 					 *   contains any strong right-to-left glyphs.
 					 * Bit 10: This bit should be set if the font
 					 *   contains Indic-style rearrangement effects.
-
 					 * Bit 11: Font data is 'lossless,' as a result
 					 *   of having been compressed and decompressed
 					 *   with the Agfa MicroType Express engine.
 					 * Bit 12: Font converted (produce compatible metrics)
 					 * Bit 13: Font optimized for ClearType™.
 					 *   Note, fonts that rely on embedded bitmaps (EBDT)
 					 *   for rendering should not be considered optimized
 					 *   for ClearType, and therefore should keep this bit
@@ -109,45 +107,45 @@ struct head
 					 * Bit 14: Last Resort font. If set, indicates that
 					 * the glyphs encoded in the cmap subtables are simply
 					 * generic symbolic representations of code point
 					 * ranges and don’t truly represent support for those
 					 * code points. If unset, indicates that the glyphs
 					 * encoded in the cmap subtables represent proper
 					 * support for those code points.
 					 * Bit 15: Reserved, set to 0. */
-  UINT16	unitsPerEm;		/* Valid range is from 16 to 16384. This value
+  HBUINT16	unitsPerEm;		/* Valid range is from 16 to 16384. This value
 					 * should be a power of 2 for fonts that have
 					 * TrueType outlines. */
   LONGDATETIME	created;		/* Number of seconds since 12:00 midnight,
 					   January 1, 1904. 64-bit integer */
   LONGDATETIME	modified;		/* Number of seconds since 12:00 midnight,
 					   January 1, 1904. 64-bit integer */
-  INT16		xMin;			/* For all glyph bounding boxes. */
-  INT16		yMin;			/* For all glyph bounding boxes. */
-  INT16		xMax;			/* For all glyph bounding boxes. */
-  INT16		yMax;			/* For all glyph bounding boxes. */
-  UINT16	macStyle;		/* Bit 0: Bold (if set to 1);
+  HBINT16	xMin;			/* For all glyph bounding boxes. */
+  HBINT16	yMin;			/* For all glyph bounding boxes. */
+  HBINT16	xMax;			/* For all glyph bounding boxes. */
+  HBINT16	yMax;			/* For all glyph bounding boxes. */
+  HBUINT16	macStyle;		/* Bit 0: Bold (if set to 1);
 					 * Bit 1: Italic (if set to 1)
 					 * Bit 2: Underline (if set to 1)
 					 * Bit 3: Outline (if set to 1)
 					 * Bit 4: Shadow (if set to 1)
 					 * Bit 5: Condensed (if set to 1)
 					 * Bit 6: Extended (if set to 1)
 					 * Bits 7-15: Reserved (set to 0). */
-  UINT16	lowestRecPPEM;		/* Smallest readable size in pixels. */
-  INT16		fontDirectionHint;	/* Deprecated (Set to 2).
+  HBUINT16	lowestRecPPEM;		/* Smallest readable size in pixels. */
+  HBINT16	fontDirectionHint;	/* Deprecated (Set to 2).
 					 * 0: Fully mixed directional glyphs;
 					 * 1: Only strongly left to right;
 					 * 2: Like 1 but also contains neutrals;
 					 * -1: Only strongly right to left;
 					 * -2: Like -1 but also contains neutrals. */
   public:
-  INT16		indexToLocFormat;	/* 0 for short offsets, 1 for long. */
-  INT16		glyphDataFormat;	/* 0 for current format. */
+  HBINT16	indexToLocFormat;	/* 0 for short offsets, 1 for long. */
+  HBINT16	glyphDataFormat;	/* 0 for current format. */
 
   DEFINE_SIZE_STATIC (54);
 };
 
 
 } /* namespace OT */
 
 
--- a/gfx/harfbuzz/src/hb-ot-hhea-table.hh
+++ b/gfx/harfbuzz/src/hb-ot-hhea-table.hh
@@ -59,31 +59,31 @@ struct _hea
 					 * metrics table. */
   FWORD		minLeadingBearing;	/* Minimum left/top sidebearing value in
 					 * metrics table. */
   FWORD		minTrailingBearing;	/* Minimum right/bottom sidebearing value;
 					 * calculated as Min(aw - lsb -
 					 * (xMax - xMin)) for horizontal. */
   FWORD		maxExtent;		/* horizontal: Max(lsb + (xMax - xMin)),
 					 * vertical: minLeadingBearing+(yMax-yMin). */
-  INT16		caretSlopeRise;		/* Used to calculate the slope of the
+  HBINT16		caretSlopeRise;		/* Used to calculate the slope of the
 					 * cursor (rise/run); 1 for vertical caret,
 					 * 0 for horizontal.*/
-  INT16		caretSlopeRun;		/* 0 for vertical caret, 1 for horizontal. */
-  INT16		caretOffset;		/* The amount by which a slanted
+  HBINT16		caretSlopeRun;		/* 0 for vertical caret, 1 for horizontal. */
+  HBINT16		caretOffset;		/* The amount by which a slanted
 					 * highlight on a glyph needs
 					 * to be shifted to produce the
 					 * best appearance. Set to 0 for
 					 * non-slanted fonts. */
-  INT16		reserved1;		/* Set to 0. */
-  INT16		reserved2;		/* Set to 0. */
-  INT16		reserved3;		/* Set to 0. */
-  INT16		reserved4;		/* Set to 0. */
-  INT16		metricDataFormat;	/* 0 for current format. */
-  UINT16	numberOfLongMetrics;	/* Number of LongMetric entries in metric
+  HBINT16		reserved1;		/* Set to 0. */
+  HBINT16		reserved2;		/* Set to 0. */
+  HBINT16		reserved3;		/* Set to 0. */
+  HBINT16		reserved4;		/* Set to 0. */
+  HBINT16		metricDataFormat;	/* 0 for current format. */
+  HBUINT16	numberOfLongMetrics;	/* Number of LongMetric entries in metric
 					 * table. */
   public:
   DEFINE_SIZE_STATIC (36);
 };
 
 struct hhea : _hea {
   static const hb_tag_t tableTag	= HB_OT_TAG_hhea;
 };
--- a/gfx/harfbuzz/src/hb-ot-hmtx-table.hh
+++ b/gfx/harfbuzz/src/hb-ot-hmtx-table.hh
@@ -69,44 +69,44 @@ struct hmtxvmtx
     inline void init (hb_face_t *face,
 		      unsigned int default_advance_ = 0)
     {
       default_advance = default_advance_ ? default_advance_ : face->get_upem ();
 
       bool got_font_extents = false;
       if (T::os2Tag)
       {
-	hb_blob_t *os2_blob = Sanitizer<os2>::sanitize (face->reference_table (T::os2Tag));
+	hb_blob_t *os2_blob = Sanitizer<os2>().sanitize (face->reference_table (T::os2Tag));
 	const os2 *os2_table = Sanitizer<os2>::lock_instance (os2_blob);
 #define USE_TYPO_METRICS (1u<<7)
 	if (0 != (os2_table->fsSelection & USE_TYPO_METRICS))
 	{
 	  ascender = os2_table->sTypoAscender;
 	  descender = os2_table->sTypoDescender;
 	  line_gap = os2_table->sTypoLineGap;
 	  got_font_extents = (ascender | descender) != 0;
 	}
 	hb_blob_destroy (os2_blob);
       }
 
-      hb_blob_t *_hea_blob = Sanitizer<_hea>::sanitize (face->reference_table (T::headerTag));
+      hb_blob_t *_hea_blob = Sanitizer<_hea>().sanitize (face->reference_table (T::headerTag));
       const _hea *_hea_table = Sanitizer<_hea>::lock_instance (_hea_blob);
       num_advances = _hea_table->numberOfLongMetrics;
       if (!got_font_extents)
       {
 	ascender = _hea_table->ascender;
 	descender = _hea_table->descender;
 	line_gap = _hea_table->lineGap;
 	got_font_extents = (ascender | descender) != 0;
       }
       hb_blob_destroy (_hea_blob);
 
       has_font_extents = got_font_extents;
 
-      blob = Sanitizer<hmtxvmtx>::sanitize (face->reference_table (T::tableTag));
+      blob = Sanitizer<hmtxvmtx>().sanitize (face->reference_table (T::tableTag));
 
       /* Cap num_metrics() and num_advances() based on table length. */
       unsigned int len = hb_blob_get_length (blob);
       if (unlikely (num_advances * 4 > len))
 	num_advances = len / 4;
       num_metrics = num_advances + (len - 4 * num_advances) / 2;
 
       /* We MUST set num_metrics to zero if num_advances is zero.
@@ -114,17 +114,17 @@ struct hmtxvmtx
       if (unlikely (!num_advances))
       {
 	num_metrics = num_advances = 0;
 	hb_blob_destroy (blob);
 	blob = hb_blob_get_empty ();
       }
       table = Sanitizer<hmtxvmtx>::lock_instance (blob);
 
-      var_blob = Sanitizer<HVARVVAR>::sanitize (face->reference_table (T::variationsTag));
+      var_blob = Sanitizer<HVARVVAR>().sanitize (face->reference_table (T::variationsTag));
       var_table = Sanitizer<HVARVVAR>::lock_instance (var_blob);
     }
 
     inline void fini (void)
     {
       hb_blob_destroy (blob);
       hb_blob_destroy (var_blob);
     }
@@ -139,17 +139,17 @@ struct hmtxvmtx
 	 * glyph index is out of bound: return zero. */
 	if (num_metrics)
 	  return 0;
 	else
 	  return default_advance;
       }
 
       return table->longMetric[MIN (glyph, (uint32_t) num_advances - 1)].advance
-	   + var_table->get_advance_var (glyph, font->coords, font->num_coords); // TODO Optimize?!
+	   + (font->num_coords ? var_table->get_advance_var (glyph, font->coords, font->num_coords) : 0); // TODO Optimize?!
     }
 
     public:
     bool has_font_extents;
     unsigned short ascender;
     unsigned short descender;
     unsigned short line_gap;
 
--- a/gfx/harfbuzz/src/hb-ot-kern-table.hh
+++ b/gfx/harfbuzz/src/hb-ot-kern-table.hh
@@ -99,28 +99,28 @@ struct KernClassTable
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (firstGlyph.sanitize (c) && classes.sanitize (c));
   }
 
   protected:
-  UINT16		firstGlyph;	/* First glyph in class range. */
-  ArrayOf<UINT16>	classes;	/* Glyph classes. */
+  HBUINT16		firstGlyph;	/* First glyph in class range. */
+  ArrayOf<HBUINT16>	classes;	/* Glyph classes. */
   public:
   DEFINE_SIZE_ARRAY (4, classes);
 };
 
 struct KernSubTableFormat2
 {
   inline int get_kerning (hb_codepoint_t left, hb_codepoint_t right, const char *end) const
   {
     unsigned int l = (this+leftClassTable).get_class (left);
-    unsigned int r = (this+leftClassTable).get_class (left);
+    unsigned int r = (this+rightClassTable).get_class (right);
     unsigned int offset = l * rowWidth + r * sizeof (FWORD);
     const FWORD *arr = &(this+array);
     if (unlikely ((const void *) arr < (const void *) this || (const void *) arr >= (const void *) end))
       return 0;
     const FWORD *v = &StructAtOffset<FWORD> (arr, offset);
     if (unlikely ((const void *) v < (const void *) arr || (const void *) (v + 1) > (const void *) end))
       return 0;
     return *v;
@@ -131,17 +131,17 @@ struct KernSubTableFormat2
     TRACE_SANITIZE (this);
     return_trace (rowWidth.sanitize (c) &&
 		  leftClassTable.sanitize (c, this) &&
 		  rightClassTable.sanitize (c, this) &&
 		  array.sanitize (c, this));
   }
 
   protected:
-  UINT16	rowWidth;	/* The width, in bytes, of a row in the table. */
+  HBUINT16	rowWidth;	/* The width, in bytes, of a row in the table. */
   OffsetTo<KernClassTable>
 		leftClassTable;	/* Offset from beginning of this subtable to
 				 * left-hand class table. */
   OffsetTo<KernClassTable>
 		rightClassTable;/* Offset from beginning of this subtable to
 				 * right-hand class table. */
   OffsetTo<FWORD>
 		array;		/* Offset from beginning of this subtable to
@@ -270,29 +270,29 @@ struct KernOT : KernTable<KernOT>
 
       COVERAGE_VARIATION_FLAG	= 0x00u, /* Not supported. */
 
       COVERAGE_CHECK_FLAGS	= 0x07u,
       COVERAGE_CHECK_HORIZONTAL	= 0x01u
     };
 
     protected:
-    UINT16	versionZ;	/* Unused. */
-    UINT16	length;		/* Length of the subtable (including this header). */
-    UINT8	format;		/* Subtable format. */
-    UINT8	coverage;	/* Coverage bits. */
+    HBUINT16	versionZ;	/* Unused. */
+    HBUINT16	length;		/* Length of the subtable (including this header). */
+    HBUINT8	format;		/* Subtable format. */
+    HBUINT8	coverage;	/* Coverage bits. */
     KernSubTable subtable;	/* Subtable data. */
     public:
     DEFINE_SIZE_MIN (6);
   };
 
   protected:
-  UINT16	version;	/* Version--0x0000u */
-  UINT16	nTables;	/* Number of subtables in the kerning table. */
-  UINT8		data[VAR];
+  HBUINT16	version;	/* Version--0x0000u */
+  HBUINT16	nTables;	/* Number of subtables in the kerning table. */
+  HBUINT8		data[VAR];
   public:
   DEFINE_SIZE_ARRAY (4, data);
 };
 
 struct KernAAT : KernTable<KernAAT>
 {
   friend struct KernTable<KernAAT>;
 
@@ -309,30 +309,30 @@ struct KernAAT : KernTable<KernAAT>
 
       COVERAGE_OVERRIDE_FLAG	= 0x00u, /* Not supported. */
 
       COVERAGE_CHECK_FLAGS	= 0xE0u,
       COVERAGE_CHECK_HORIZONTAL	= 0x00u
     };
 
     protected:
-    UINT32	length;		/* Length of the subtable (including this header). */
-    UINT8	coverage;	/* Coverage bits. */
-    UINT8	format;		/* Subtable format. */
-    UINT16	tupleIndex;	/* The tuple index (used for variations fonts).
+    HBUINT32	length;		/* Length of the subtable (including this header). */
+    HBUINT8	coverage;	/* Coverage bits. */
+    HBUINT8	format;		/* Subtable format. */
+    HBUINT16	tupleIndex;	/* The tuple index (used for variations fonts).
 				 * This value specifies which tuple this subtable covers. */
     KernSubTable subtable;	/* Subtable data. */
     public:
     DEFINE_SIZE_MIN (8);
   };
 
   protected:
-  UINT32		version;	/* Version--0x00010000u */
-  UINT32		nTables;	/* Number of subtables in the kerning table. */
-  UINT8		data[VAR];
+  HBUINT32		version;	/* Version--0x00010000u */
+  HBUINT32		nTables;	/* Number of subtables in the kerning table. */
+  HBUINT8		data[VAR];
   public:
   DEFINE_SIZE_ARRAY (8, data);
 };
 
 struct kern
 {
   static const hb_tag_t tableTag = HB_OT_TAG_kern;
 
@@ -355,17 +355,17 @@ struct kern
     default:return_trace (true);
     }
   }
 
   struct accelerator_t
   {
     inline void init (hb_face_t *face)
     {
-      blob = Sanitizer<kern>::sanitize (face->reference_table (HB_OT_TAG_kern));
+      blob = Sanitizer<kern>().sanitize (face->reference_table (HB_OT_TAG_kern));
       table = Sanitizer<kern>::lock_instance (blob);
       table_length = hb_blob_get_length (blob);
     }
     inline void fini (void)
     {
       hb_blob_destroy (blob);
     }
 
@@ -375,17 +375,17 @@ struct kern
     private:
     hb_blob_t *blob;
     const kern *table;
     unsigned int table_length;
   };
 
   protected:
   union {
-  UINT16		major;
+  HBUINT16		major;
   KernOT		ot;
   KernAAT		aat;
   } u;
   public:
   DEFINE_SIZE_UNION (2, major);
 };
 
 } /* namespace OT */
--- a/gfx/harfbuzz/src/hb-ot-layout-common-private.hh
+++ b/gfx/harfbuzz/src/hb-ot-layout-common-private.hh
@@ -156,31 +156,31 @@ struct RangeRecord
 
   template <typename set_t>
   inline bool add_coverage (set_t *glyphs) const {
     return glyphs->add_range (start, end);
   }
 
   GlyphID	start;		/* First GlyphID in the range */
   GlyphID	end;		/* Last GlyphID in the range */
-  UINT16	value;		/* Value */
+  HBUINT16	value;		/* Value */
   public:
   DEFINE_SIZE_STATIC (6);
 };
 DEFINE_NULL_DATA (RangeRecord, "\000\001");
 
 
 struct IndexArray : ArrayOf<Index>
 {
   inline unsigned int get_indexes (unsigned int start_offset,
 				   unsigned int *_count /* IN/OUT */,
 				   unsigned int *_indexes /* OUT */) const
   {
     if (_count) {
-      const UINT16 *arr = this->sub_array (start_offset, _count);
+      const HBUINT16 *arr = this->sub_array (start_offset, _count);
       unsigned int count = *_count;
       for (unsigned int i = 0; i < count; i++)
 	_indexes[i] = arr[i];
     }
     return this->len;
   }
 };
 
@@ -213,17 +213,17 @@ struct LangSys
 			const Record<LangSys>::sanitize_closure_t * = nullptr) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) && featureIndex.sanitize (c));
   }
 
   Offset16	lookupOrderZ;	/* = Null (reserved for an offset to a
 				 * reordering table) */
-  UINT16	reqFeatureIndex;/* Index of a feature required for this
+  HBUINT16	reqFeatureIndex;/* Index of a feature required for this
 				 * language system--if no required features
 				 * = 0xFFFFu */
   IndexArray	featureIndex;	/* Array of indices into the FeatureList */
   public:
   DEFINE_SIZE_ARRAY (6, featureIndex);
 };
 DEFINE_NULL_DATA (LangSys, "\0\0\xFF\xFF");
 
@@ -338,49 +338,49 @@ struct FeatureParamsSize
 	     designSize > rangeEnd ||
 	     subfamilyNameID < 256 ||
 	     subfamilyNameID > 32767)
       return_trace (false);
     else
       return_trace (true);
   }
 
-  UINT16	designSize;	/* Represents the design size in 720/inch
+  HBUINT16	designSize;	/* Represents the design size in 720/inch
 				 * units (decipoints).  The design size entry
 				 * must be non-zero.  When there is a design
 				 * size but no recommended size range, the
 				 * rest of the array will consist of zeros. */
-  UINT16	subfamilyID;	/* Has no independent meaning, but serves
+  HBUINT16	subfamilyID;	/* Has no independent meaning, but serves
 				 * as an identifier that associates fonts
 				 * in a subfamily. All fonts which share a
 				 * Preferred or Font Family name and which
 				 * differ only by size range shall have the
 				 * same subfamily value, and no fonts which
 				 * differ in weight or style shall have the
 				 * same subfamily value. If this value is
 				 * zero, the remaining fields in the array
 				 * will be ignored. */
-  UINT16	subfamilyNameID;/* If the preceding value is non-zero, this
+  HBUINT16	subfamilyNameID;/* If the preceding value is non-zero, this
 				 * value must be set in the range 256 - 32767
 				 * (inclusive). It records the value of a
 				 * field in the name table, which must
 				 * contain English-language strings encoded
 				 * in Windows Unicode and Macintosh Roman,
 				 * and may contain additional strings
 				 * localized to other scripts and languages.
 				 * Each of these strings is the name an
 				 * application should use, in combination
 				 * with the family name, to represent the
 				 * subfamily in a menu.  Applications will
 				 * choose the appropriate version based on
 				 * their selection criteria. */
-  UINT16	rangeStart;	/* Large end of the recommended usage range
+  HBUINT16	rangeStart;	/* Large end of the recommended usage range
 				 * (inclusive), stored in 720/inch units
 				 * (decipoints). */
-  UINT16	rangeEnd;	/* Small end of the recommended usage range
+  HBUINT16	rangeEnd;	/* Small end of the recommended usage range
 				   (exclusive), stored in 720/inch units
 				 * (decipoints). */
   public:
   DEFINE_SIZE_STATIC (10);
 };
 
 /* http://www.microsoft.com/typography/otspec/features_pt.htm#ssxx */
 struct FeatureParamsStylisticSet
@@ -388,22 +388,22 @@ struct FeatureParamsStylisticSet
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     /* Right now minorVersion is at zero.  Which means, any table supports
      * the uiNameID field. */
     return_trace (c->check_struct (this));
   }
 
-  UINT16	version;	/* (set to 0): This corresponds to a “minor”
+  HBUINT16	version;	/* (set to 0): This corresponds to a “minor”
 				 * version number. Additional data may be
 				 * added to the end of this Feature Parameters
 				 * table in the future. */
 
-  UINT16	uiNameID;	/* The 'name' table name ID that specifies a
+  HBUINT16	uiNameID;	/* The 'name' table name ID that specifies a
 				 * string (or strings, for multiple languages)
 				 * for a user-interface label for this
 				 * feature.  The values of uiLabelNameId and
 				 * sampleTextNameId are expected to be in the
 				 * font-specific name ID range (256-32767),
 				 * though that is not a requirement in this
 				 * Feature Parameters specification. The
 				 * user-interface label for the feature can
@@ -421,35 +421,35 @@ struct FeatureParamsCharacterVariants
 {
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) &&
 		  characters.sanitize (c));
   }
 
-  UINT16	format;			/* Format number is set to 0. */
-  UINT16	featUILableNameID;	/* The ‘name’ table name ID that
+  HBUINT16	format;			/* Format number is set to 0. */
+  HBUINT16	featUILableNameID;	/* The ‘name’ table name ID that
 					 * specifies a string (or strings,
 					 * for multiple languages) for a
 					 * user-interface label for this
 					 * feature. (May be nullptr.) */
-  UINT16	featUITooltipTextNameID;/* The ‘name’ table name ID that
+  HBUINT16	featUITooltipTextNameID;/* The ‘name’ table name ID that
 					 * specifies a string (or strings,
 					 * for multiple languages) that an
 					 * application can use for tooltip
 					 * text for this feature. (May be
 					 * nullptr.) */
-  UINT16	sampleTextNameID;	/* The ‘name’ table name ID that
+  HBUINT16	sampleTextNameID;	/* The ‘name’ table name ID that
 					 * specifies sample text that
 					 * illustrates the effect of this
 					 * feature. (May be nullptr.) */
-  UINT16	numNamedParameters;	/* Number of named parameters. (May
+  HBUINT16	numNamedParameters;	/* Number of named parameters. (May
 					 * be zero.) */
-  UINT16	firstParamUILabelNameID;/* The first ‘name’ table name ID
+  HBUINT16	firstParamUILabelNameID;/* The first ‘name’ table name ID
 					 * used to specify strings for
 					 * user-interface labels for the
 					 * feature parameters. (Must be zero
 					 * if numParameters is zero.) */
   ArrayOf<UINT24>
 		characters;		/* Array of the Unicode Scalar Value
 					 * of the characters for which this
 					 * feature provides glyph variants.
@@ -557,17 +557,17 @@ struct Feature
   IndexArray	 lookupIndex;	/* Array of LookupList indices */
   public:
   DEFINE_SIZE_ARRAY (4, lookupIndex);
 };
 
 typedef RecordListOf<Feature> FeatureList;
 
 
-struct LookupFlag : UINT16
+struct LookupFlag : HBUINT16
 {
   enum Flags {
     RightToLeft		= 0x0001u,
     IgnoreBaseGlyphs	= 0x0002u,
     IgnoreLigatures	= 0x0004u,
     IgnoreMarks		= 0x0008u,
     IgnoreFlags		= 0x000Eu,
     UseMarkFilteringSet	= 0x0010u,
@@ -603,17 +603,17 @@ struct Lookup
   /* lookup_props is a 32-bit integer where the lower 16-bit is LookupFlag and
    * higher 16-bit is mark-filtering-set if the lookup uses one.
    * Not to be confused with glyph_props which is very similar. */
   inline uint32_t get_props (void) const
   {
     unsigned int flag = lookupFlag;
     if (unlikely (flag & LookupFlag::UseMarkFilteringSet))
     {
-      const UINT16 &markFilteringSet = StructAfter<UINT16> (subTable);
+      const HBUINT16 &markFilteringSet = StructAfter<HBUINT16> (subTable);
       flag += (markFilteringSet << 16);
     }
     return flag;
   }
 
   template <typename SubTableType, typename context_t>
   inline typename context_t::return_t dispatch (context_t *c) const
   {
@@ -635,41 +635,41 @@ struct Lookup
   {
     TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (*this))) return_trace (false);
     lookupType.set (lookup_type);
     lookupFlag.set (lookup_props & 0xFFFFu);
     if (unlikely (!subTable.serialize (c, num_subtables))) return_trace (false);
     if (lookupFlag & LookupFlag::UseMarkFilteringSet)
     {
-      UINT16 &markFilteringSet = StructAfter<UINT16> (subTable);
+      HBUINT16 &markFilteringSet = StructAfter<HBUINT16> (subTable);
       markFilteringSet.set (lookup_props >> 16);
     }
     return_trace (true);
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     /* Real sanitize of the subtables is done by GSUB/GPOS/... */
     if (!(c->check_struct (this) && subTable.sanitize (c))) return_trace (false);
     if (lookupFlag & LookupFlag::UseMarkFilteringSet)
     {
-      const UINT16 &markFilteringSet = StructAfter<UINT16> (subTable);
+      const HBUINT16 &markFilteringSet = StructAfter<HBUINT16> (subTable);
       if (!markFilteringSet.sanitize (c)) return_trace (false);
     }
     return_trace (true);
   }
 
   private:
-  UINT16	lookupType;		/* Different enumerations for GSUB and GPOS */
-  UINT16	lookupFlag;		/* Lookup qualifiers */
+  HBUINT16	lookupType;		/* Different enumerations for GSUB and GPOS */
+  HBUINT16	lookupFlag;		/* Lookup qualifiers */
   ArrayOf<Offset16>
 		subTable;		/* Array of SubTables */
-  UINT16	markFilteringSetX[VAR];	/* Index (base 0) into GDEF mark glyph sets
+  HBUINT16	markFilteringSetX[VAR];	/* Index (base 0) into GDEF mark glyph sets
 					 * structure. This field is only present if bit
 					 * UseMarkFilteringSet of lookup flags is set. */
   public:
   DEFINE_SIZE_ARRAY2 (6, subTable, markFilteringSetX);
 };
 
 typedef OffsetListOf<Lookup> LookupList;
 
@@ -730,17 +730,17 @@ struct CoverageFormat1
 
     private:
     const struct CoverageFormat1 *c;
     unsigned int i;
   };
   private:
 
   protected:
-  UINT16	coverageFormat;	/* Format identifier--format = 1 */
+  HBUINT16	coverageFormat;	/* Format identifier--format = 1 */
   SortedArrayOf<GlyphID>
 		glyphArray;	/* Array of GlyphIDs--in numerical order */
   public:
   DEFINE_SIZE_ARRAY (4, glyphArray);
 };
 
 struct CoverageFormat2
 {
@@ -855,32 +855,32 @@ struct CoverageFormat2
 
     private:
     const struct CoverageFormat2 *c;
     unsigned int i, j, coverage;
   };
   private:
 
   protected:
-  UINT16	coverageFormat;	/* Format identifier--format = 2 */
+  HBUINT16	coverageFormat;	/* Format identifier--format = 2 */
   SortedArrayOf<RangeRecord>
 		rangeRecord;	/* Array of glyph ranges--ordered by
 				 * Start GlyphID. rangeCount entries
 				 * long */
   public:
   DEFINE_SIZE_ARRAY (4, rangeRecord);
 };
 
 struct Coverage
 {
   inline unsigned int get_coverage (hb_codepoint_t glyph_id) const
   {
     switch (u.format) {
-    case 1: return u.format1.get_coverage(glyph_id);
-    case 2: return u.format2.get_coverage(glyph_id);
+    case 1: return u.format1.get_coverage (glyph_id);
+    case 2: return u.format2.get_coverage (glyph_id);
     default:return NOT_COVERED;
     }
   }
 
   inline bool serialize (hb_serialize_context_t *c,
 			 Supplier<GlyphID> &glyphs,
 			 unsigned int num_glyphs)
   {
@@ -982,17 +982,17 @@ struct Coverage
     union {
     CoverageFormat2::Iter	format2; /* Put this one first since it's larger; helps shut up compiler. */
     CoverageFormat1::Iter	format1;
     } u;
   };
 
   protected:
   union {
-  UINT16		format;		/* Format identifier */
+  HBUINT16		format;		/* Format identifier */
   CoverageFormat1	format1;
   CoverageFormat2	format2;
   } u;
   public:
   DEFINE_SIZE_UNION (2, format);
 };
 
 
@@ -1069,19 +1069,19 @@ struct ClassDefFormat1
     }
     for (unsigned int i = 0; i < count; i++)
       if (classValue[i] == klass && glyphs->has (startGlyph + i))
         return true;
     return false;
   }
 
   protected:
-  UINT16	classFormat;		/* Format identifier--format = 1 */
+  HBUINT16	classFormat;		/* Format identifier--format = 1 */
   GlyphID	startGlyph;		/* First GlyphID of the classValueArray */
-  ArrayOf<UINT16>
+  ArrayOf<HBUINT16>
 		classValue;		/* Array of Class Values--one per GlyphID */
   public:
   DEFINE_SIZE_ARRAY (6, classValue);
 };
 
 struct ClassDefFormat2
 {
   friend struct ClassDef;
@@ -1143,31 +1143,31 @@ struct ClassDefFormat2
     }
     for (unsigned int i = 0; i < count; i++)
       if (rangeRecord[i].value == klass && rangeRecord[i].intersects (glyphs))
         return true;
     return false;
   }
 
   protected:
-  UINT16	classFormat;	/* Format identifier--format = 2 */
+  HBUINT16	classFormat;	/* Format identifier--format = 2 */
   SortedArrayOf<RangeRecord>
 		rangeRecord;	/* Array of glyph ranges--ordered by
 				 * Start GlyphID */
   public:
   DEFINE_SIZE_ARRAY (4, rangeRecord);
 };
 
 struct ClassDef
 {
   inline unsigned int get_class (hb_codepoint_t glyph_id) const
   {
     switch (u.format) {
-    case 1: return u.format1.get_class(glyph_id);
-    case 2: return u.format2.get_class(glyph_id);
+    case 1: return u.format1.get_class (glyph_id);
+    case 2: return u.format2.get_class (glyph_id);
     default:return 0;
     }
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     if (!u.format.sanitize (c)) return_trace (false);
@@ -1205,17 +1205,17 @@ struct ClassDef
     case 1: return u.format1.intersects_class (glyphs, klass);
     case 2: return u.format2.intersects_class (glyphs, klass);
     default:return false;
     }
   }
 
   protected:
   union {
-  UINT16		format;		/* Format identifier */
+  HBUINT16		format;		/* Format identifier */
   ClassDefFormat1	format1;
   ClassDefFormat2	format2;
   } u;
   public:
   DEFINE_SIZE_UNION (2, format);
 };
 
 
@@ -1270,38 +1270,39 @@ struct VarRegionList
 			 int *coords, unsigned int coord_len) const
   {
     if (unlikely (region_index >= regionCount))
       return 0.;
 
     const VarRegionAxis *axes = axesZ + (region_index * axisCount);
 
     float v = 1.;
-    unsigned int count = MIN (coord_len, (unsigned int) axisCount);
+    unsigned int count = axisCount;
     for (unsigned int i = 0; i < count; i++)
     {
-      float factor = axes[i].evaluate (coords[i]);
+      int coord = i < coord_len ? coords[i] : 0;
+      float factor = axes[i].evaluate (coord);
       if (factor == 0.)
         return 0.;
       v *= factor;
     }
     return v;
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) &&
 		  c->check_array (axesZ, axesZ[0].static_size,
 				  (unsigned int) axisCount * (unsigned int) regionCount));
   }
 
   protected:
-  UINT16	axisCount;
-  UINT16	regionCount;
+  HBUINT16	axisCount;
+  HBUINT16	regionCount;
   VarRegionAxis	axesZ[VAR];
   public:
   DEFINE_SIZE_ARRAY (4, axesZ);
 };
 
 struct VarData
 {
   inline unsigned int get_row_size (void) const
@@ -1315,53 +1316,53 @@ struct VarData
 			  const VarRegionList &regions) const
   {
     if (unlikely (inner >= itemCount))
       return 0.;
 
    unsigned int count = regionIndices.len;
    unsigned int scount = shortCount;
 
-   const UINT8 *bytes = &StructAfter<UINT8> (regionIndices);
-   const UINT8 *row = bytes + inner * (scount + count);
+   const HBUINT8 *bytes = &StructAfter<HBUINT8> (regionIndices);
+   const HBUINT8 *row = bytes + inner * (scount + count);
 
    float delta = 0.;
    unsigned int i = 0;
 
-   const INT16 *scursor = reinterpret_cast<const INT16 *> (row);
+   const HBINT16 *scursor = reinterpret_cast<const HBINT16 *> (row);
    for (; i < scount; i++)
    {
      float scalar = regions.evaluate (regionIndices.array[i], coords, coord_count);
      delta += scalar * *scursor++;
    }
-   const INT8 *bcursor = reinterpret_cast<const INT8 *> (scursor);
+   const HBINT8 *bcursor = reinterpret_cast<const HBINT8 *> (scursor);
    for (; i < count; i++)
    {
      float scalar = regions.evaluate (regionIndices.array[i], coords, coord_count);
      delta += scalar * *bcursor++;
    }
 
    return delta;
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) &&
 		  regionIndices.sanitize(c) &&
 		  shortCount <= regionIndices.len &&
-		  c->check_array (&StructAfter<UINT8> (regionIndices),
+		  c->check_array (&StructAfter<HBUINT8> (regionIndices),
 				  get_row_size (), itemCount));
   }
 
   protected:
-  UINT16		itemCount;
-  UINT16		shortCount;
-  ArrayOf<UINT16>	regionIndices;
-  UINT8			bytesX[VAR];
+  HBUINT16		itemCount;
+  HBUINT16		shortCount;
+  ArrayOf<HBUINT16>	regionIndices;
+  HBUINT8			bytesX[VAR];
   public:
   DEFINE_SIZE_ARRAY2 (6, regionIndices, bytesX);
 };
 
 struct VariationStore
 {
   inline float get_delta (unsigned int outer, unsigned int inner,
 			  int *coords, unsigned int coord_count) const
@@ -1387,19 +1388,19 @@ struct VariationStore
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) &&
 		  format == 1 &&
 		  regions.sanitize (c, this) &&
 		  dataSets.sanitize (c, this));
   }
 
   protected:
-  UINT16				format;
+  HBUINT16				format;
   LOffsetTo<VarRegionList>		regions;
-  OffsetArrayOf<VarData, UINT32>		dataSets;
+  OffsetArrayOf<VarData, HBUINT32>	dataSets;
   public:
   DEFINE_SIZE_ARRAY (8, dataSets);
 };
 
 /*
  * Feature Variations
  */
 
@@ -1416,18 +1417,18 @@ struct ConditionFormat1
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this));
   }
 
   protected:
-  UINT16	format;		/* Format identifier--format = 1 */
-  UINT16	axisIndex;
+  HBUINT16	format;		/* Format identifier--format = 1 */
+  HBUINT16	axisIndex;
   F2DOT14	filterRangeMinValue;
   F2DOT14	filterRangeMaxValue;
   public:
   DEFINE_SIZE_STATIC (8);
 };
 
 struct Condition
 {
@@ -1446,17 +1447,17 @@ struct Condition
     switch (u.format) {
     case 1: return_trace (u.format1.sanitize (c));
     default:return_trace (true);
     }
   }
 
   protected:
   union {
-  UINT16		format;		/* Format identifier */
+  HBUINT16		format;		/* Format identifier */
   ConditionFormat1	format1;
   } u;
   public:
   DEFINE_SIZE_UNION (2, format);
 };
 
 struct ConditionSet
 {
@@ -1471,33 +1472,33 @@ struct ConditionSet
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (conditions.sanitize (c, this));
   }
 
   protected:
-  OffsetArrayOf<Condition, UINT32> conditions;
+  OffsetArrayOf<Condition, HBUINT32> conditions;
   public:
   DEFINE_SIZE_ARRAY (2, conditions);
 };
 
 struct FeatureTableSubstitutionRecord
 {
   friend struct FeatureTableSubstitution;
 
   inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) && feature.sanitize (c, base));
   }
 
   protected:
-  UINT16		featureIndex;
+  HBUINT16		featureIndex;
   LOffsetTo<Feature>	feature;
   public:
   DEFINE_SIZE_STATIC (6);
 };
 
 struct FeatureTableSubstitution
 {
   inline const Feature *find_substitute (unsigned int feature_index) const
@@ -1607,18 +1608,18 @@ struct HintingDevice
   { return get_delta (font->x_ppem, font->x_scale); }
 
   inline hb_position_t get_y_delta (hb_font_t *font) const
   { return get_delta (font->y_ppem, font->y_scale); }
 
   inline unsigned int get_size (void) const
   {
     unsigned int f = deltaFormat;
-    if (unlikely (f < 1 || f > 3 || startSize > endSize)) return 3 * UINT16::static_size;
-    return UINT16::static_size * (4 + ((endSize - startSize) >> (4 - f)));
+    if (unlikely (f < 1 || f > 3 || startSize > endSize)) return 3 * HBUINT16::static_size;
+    return HBUINT16::static_size * (4 + ((endSize - startSize) >> (4 - f)));
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) && c->check_range (this, this->get_size ()));
   }
 
@@ -1653,24 +1654,24 @@ struct HintingDevice
 
     if ((unsigned int) delta >= ((mask + 1) >> 1))
       delta -= mask + 1;
 
     return delta;
   }
 
   protected:
-  UINT16	startSize;		/* Smallest size to correct--in ppem */
-  UINT16	endSize;		/* Largest size to correct--in ppem */
-  UINT16	deltaFormat;		/* Format of DeltaValue array data: 1, 2, or 3
+  HBUINT16	startSize;		/* Smallest size to correct--in ppem */
+  HBUINT16	endSize;		/* Largest size to correct--in ppem */
+  HBUINT16	deltaFormat;		/* Format of DeltaValue array data: 1, 2, or 3
 					 * 1	Signed 2-bit value, 8 values per uint16
 					 * 2	Signed 4-bit value, 4 values per uint16
 					 * 3	Signed 8-bit value, 2 values per uint16
 					 */
-  UINT16	deltaValue[VAR];	/* Array of compressed data */
+  HBUINT16	deltaValue[VAR];	/* Array of compressed data */
   public:
   DEFINE_SIZE_ARRAY (6, deltaValue);
 };
 
 struct VariationDevice
 {
   friend struct Device;
 
@@ -1691,30 +1692,30 @@ struct VariationDevice
   private:
 
   inline float get_delta (hb_font_t *font, const VariationStore &store) const
   {
     return store.get_delta (outerIndex, innerIndex, font->coords, font->num_coords);
   }
 
   protected:
-  UINT16	outerIndex;
-  UINT16	innerIndex;
-  UINT16	deltaFormat;	/* Format identifier for this table: 0x0x8000 */
+  HBUINT16	outerIndex;
+  HBUINT16	innerIndex;
+  HBUINT16	deltaFormat;	/* Format identifier for this table: 0x0x8000 */
   public:
   DEFINE_SIZE_STATIC (6);
 };
 
 struct DeviceHeader
 {
   protected:
-  UINT16		reserved1;
-  UINT16		reserved2;
+  HBUINT16		reserved1;
+  HBUINT16		reserved2;
   public:
-  UINT16		format;		/* Format identifier */
+  HBUINT16		format;		/* Format identifier */
   public:
   DEFINE_SIZE_STATIC (6);
 };
 
 struct Device
 {
   inline hb_position_t get_x_delta (hb_font_t *font, const VariationStore &store=Null(VariationStore)) const
   {
--- a/gfx/harfbuzz/src/hb-ot-layout-gdef-table.hh
+++ b/gfx/harfbuzz/src/hb-ot-layout-gdef-table.hh
@@ -36,17 +36,17 @@
 
 namespace OT {
 
 
 /*
  * Attachment List Table
  */
 
-typedef ArrayOf<UINT16> AttachPoint;	/* Array of contour point indices--in
+typedef ArrayOf<HBUINT16> AttachPoint;	/* Array of contour point indices--in
 					 * increasing numerical order */
 
 struct AttachList
 {
   inline unsigned int get_attach_points (hb_codepoint_t glyph_id,
 					 unsigned int start_offset,
 					 unsigned int *point_count /* IN/OUT */,
 					 unsigned int *point_array /* OUT */) const
@@ -57,17 +57,17 @@ struct AttachList
       if (point_count)
 	*point_count = 0;
       return 0;
     }
 
     const AttachPoint &points = this+attachPoint[index];
 
     if (point_count) {
-      const UINT16 *array = points.sub_array (start_offset, point_count);
+      const HBUINT16 *array = points.sub_array (start_offset, point_count);
       unsigned int count = *point_count;
       for (unsigned int i = 0; i < count; i++)
 	point_array[i] = array[i];
     }
 
     return points.len;
   }
 
@@ -104,18 +104,18 @@ struct CaretValueFormat1
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this));
   }
 
   protected:
-  UINT16	caretValueFormat;	/* Format identifier--format = 1 */
-  INT16		coordinate;		/* X or Y value, in design units */
+  HBUINT16	caretValueFormat;	/* Format identifier--format = 1 */
+  HBINT16		coordinate;		/* X or Y value, in design units */
   public:
   DEFINE_SIZE_STATIC (4);
 };
 
 struct CaretValueFormat2
 {
   friend struct CaretValue;
 
@@ -131,18 +131,18 @@ struct CaretValueFormat2
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this));
   }
 
   protected:
-  UINT16	caretValueFormat;	/* Format identifier--format = 2 */
-  UINT16	caretValuePoint;	/* Contour point index on glyph */
+  HBUINT16	caretValueFormat;	/* Format identifier--format = 2 */
+  HBUINT16	caretValuePoint;	/* Contour point index on glyph */
   public:
   DEFINE_SIZE_STATIC (4);
 };
 
 struct CaretValueFormat3
 {
   friend struct CaretValue;
 
@@ -155,18 +155,18 @@ struct CaretValueFormat3
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) && deviceTable.sanitize (c, this));
   }
 
   protected:
-  UINT16	caretValueFormat;	/* Format identifier--format = 3 */
-  INT16		coordinate;		/* X or Y value, in design units */
+  HBUINT16	caretValueFormat;	/* Format identifier--format = 3 */
+  HBINT16		coordinate;		/* X or Y value, in design units */
   OffsetTo<Device>
 		deviceTable;		/* Offset to Device table for X or Y
 					 * value--from beginning of CaretValue
 					 * table */
   public:
   DEFINE_SIZE_STATIC (6);
 };
 
@@ -194,17 +194,17 @@ struct CaretValue
     case 2: return_trace (u.format2.sanitize (c));
     case 3: return_trace (u.format3.sanitize (c));
     default:return_trace (true);
     }
   }
 
   protected:
   union {
-  UINT16		format;		/* Format identifier */
+  HBUINT16		format;		/* Format identifier */
   CaretValueFormat1	format1;
   CaretValueFormat2	format2;
   CaretValueFormat3	format3;
   } u;
   public:
   DEFINE_SIZE_UNION (2, format);
 };
 
@@ -289,17 +289,17 @@ struct MarkGlyphSetsFormat1
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (coverage.sanitize (c, this));
   }
 
   protected:
-  UINT16	format;			/* Format identifier--format = 1 */
+  HBUINT16	format;			/* Format identifier--format = 1 */
   ArrayOf<LOffsetTo<Coverage> >
 		coverage;		/* Array of long offsets to mark set
 					 * coverage tables */
   public:
   DEFINE_SIZE_ARRAY (4, coverage);
 };
 
 struct MarkGlyphSets
@@ -319,17 +319,17 @@ struct MarkGlyphSets
     switch (u.format) {
     case 1: return_trace (u.format1.sanitize (c));
     default:return_trace (true);
     }
   }
 
   protected:
   union {
-  UINT16		format;		/* Format identifier */
+  HBUINT16		format;		/* Format identifier */
   MarkGlyphSetsFormat1	format1;
   } u;
   public:
   DEFINE_SIZE_UNION (2, format);
 };
 
 
 /*
--- a/gfx/harfbuzz/src/hb-ot-layout-gpos-table.hh
+++ b/gfx/harfbuzz/src/hb-ot-layout-gpos-table.hh
@@ -46,21 +46,21 @@ enum attach_type_t {
   /* Each attachment should be either a mark or a cursive; can't be both. */
   ATTACH_TYPE_MARK	= 0X01,
   ATTACH_TYPE_CURSIVE	= 0X02,
 };
 
 
 /* Shared Tables: ValueRecord, Anchor Table, and MarkArray */
 
-typedef UINT16 Value;
+typedef HBUINT16 Value;
 
 typedef Value ValueRecord[VAR];
 
-struct ValueFormat : UINT16
+struct ValueFormat : HBUINT16
 {
   enum Flags {
     xPlacement	= 0x0001u,	/* Includes horizontal adjustment for placement */
     yPlacement	= 0x0002u,	/* Includes vertical adjustment for placement */
     xAdvance	= 0x0004u,	/* Includes horizontal adjustment for advance */
     yAdvance	= 0x0008u,	/* Includes vertical adjustment for advance */
     xPlaDevice	= 0x0010u,	/* Includes horizontal Device table for placement */
     yPlaDevice	= 0x0020u,	/* Includes vertical Device table for placement */
@@ -69,24 +69,24 @@ struct ValueFormat : UINT16
     ignored	= 0x0F00u,	/* Was used in TrueType Open for MM fonts */
     reserved	= 0xF000u,	/* For future use */
 
     devices	= 0x00F0u	/* Mask for having any Device table */
   };
 
 /* All fields are options.  Only those available advance the value pointer. */
 #if 0
-  INT16		xPlacement;		/* Horizontal adjustment for
+  HBINT16		xPlacement;		/* Horizontal adjustment for
 					 * placement--in design units */
-  INT16		yPlacement;		/* Vertical adjustment for
+  HBINT16		yPlacement;		/* Vertical adjustment for
 					 * placement--in design units */
-  INT16		xAdvance;		/* Horizontal adjustment for
+  HBINT16		xAdvance;		/* Horizontal adjustment for
 					 * advance--in design units (only used
 					 * for horizontal writing) */
-  INT16		yAdvance;		/* Vertical adjustment for advance--in
+  HBINT16		yAdvance;		/* Vertical adjustment for advance--in
 					 * design units (only used for vertical
 					 * writing) */
   Offset	xPlaDevice;		/* Offset to Device table for
 					 * horizontal placement--measured from
 					 * beginning of PosTable (may be NULL) */
   Offset	yPlaDevice;		/* Offset to Device table for vertical
 					 * placement--measured from beginning
 					 * of PosTable (may be NULL) */
@@ -98,17 +98,17 @@ struct ValueFormat : UINT16
 					 * PosTable (may be NULL) */
 #endif
 
   inline unsigned int get_len (void) const
   { return _hb_popcount32 ((unsigned int) *this); }
   inline unsigned int get_size (void) const
   { return get_len () * Value::static_size; }
 
-  void apply_value (hb_apply_context_t   *c,
+  void apply_value (hb_ot_apply_context_t   *c,
 		    const void           *base,
 		    const Value          *values,
 		    hb_glyph_position_t  &glyph_pos) const
   {
     unsigned int format = *this;
     if (!format) return;
 
     hb_font_t *font = c->font;
@@ -173,18 +173,18 @@ struct ValueFormat : UINT16
     return true;
   }
 
   static inline OffsetTo<Device>& get_device (Value* value)
   { return *CastP<OffsetTo<Device> > (value); }
   static inline const OffsetTo<Device>& get_device (const Value* value)
   { return *CastP<OffsetTo<Device> > (value); }
 
-  static inline const INT16& get_short (const Value* value)
-  { return *CastP<INT16> (value); }
+  static inline const HBINT16& get_short (const Value* value)
+  { return *CastP<HBINT16> (value); }
 
   public:
 
   inline bool has_device (void) const {
     unsigned int format = *this;
     return (format & devices) != 0;
   }
 
@@ -227,118 +227,118 @@ struct ValueFormat : UINT16
 
     return_trace (true);
   }
 };
 
 
 struct AnchorFormat1
 {
-  inline void get_anchor (hb_apply_context_t *c, hb_codepoint_t glyph_id HB_UNUSED,
-			  hb_position_t *x, hb_position_t *y) const
+  inline void get_anchor (hb_ot_apply_context_t *c, hb_codepoint_t glyph_id HB_UNUSED,
+			  float *x, float *y) const
   {
     hb_font_t *font = c->font;
-    *x = font->em_scale_x (xCoordinate);
-    *y = font->em_scale_y (yCoordinate);
+    *x = font->em_fscale_x (xCoordinate);
+    *y = font->em_fscale_y (yCoordinate);
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this));
   }
 
   protected:
-  UINT16	format;			/* Format identifier--format = 1 */
-  INT16		xCoordinate;		/* Horizontal value--in design units */
-  INT16		yCoordinate;		/* Vertical value--in design units */
+  HBUINT16	format;			/* Format identifier--format = 1 */
+  HBINT16		xCoordinate;		/* Horizontal value--in design units */
+  HBINT16		yCoordinate;		/* Vertical value--in design units */
   public:
   DEFINE_SIZE_STATIC (6);
 };
 
 struct AnchorFormat2
 {
-  inline void get_anchor (hb_apply_context_t *c, hb_codepoint_t glyph_id,
-			  hb_position_t *x, hb_position_t *y) const
+  inline void get_anchor (hb_ot_apply_context_t *c, hb_codepoint_t glyph_id,
+			  float *x, float *y) const
   {
     hb_font_t *font = c->font;
     unsigned int x_ppem = font->x_ppem;
     unsigned int y_ppem = font->y_ppem;
     hb_position_t cx, cy;
     hb_bool_t ret;
 
     ret = (x_ppem || y_ppem) &&
 	   font->get_glyph_contour_point_for_origin (glyph_id, anchorPoint, HB_DIRECTION_LTR, &cx, &cy);
-    *x = ret && x_ppem ? cx : font->em_scale_x (xCoordinate);
-    *y = ret && y_ppem ? cy : font->em_scale_y (yCoordinate);
+    *x = ret && x_ppem ? cx : font->em_fscale_x (xCoordinate);
+    *y = ret && y_ppem ? cy : font->em_fscale_y (yCoordinate);
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this));
   }
 
   protected:
-  UINT16	format;			/* Format identifier--format = 2 */
-  INT16		xCoordinate;		/* Horizontal value--in design units */
-  INT16		yCoordinate;		/* Vertical value--in design units */
-  UINT16	anchorPoint;		/* Index to glyph contour point */
+  HBUINT16	format;			/* Format identifier--format = 2 */
+  HBINT16		xCoordinate;		/* Horizontal value--in design units */
+  HBINT16		yCoordinate;		/* Vertical value--in design units */
+  HBUINT16	anchorPoint;		/* Index to glyph contour point */
   public:
   DEFINE_SIZE_STATIC (8);
 };
 
 struct AnchorFormat3
 {
-  inline void get_anchor (hb_apply_context_t *c, hb_codepoint_t glyph_id HB_UNUSED,
-			  hb_position_t *x, hb_position_t *y) const
+  inline void get_anchor (hb_ot_apply_context_t *c, hb_codepoint_t glyph_id HB_UNUSED,
+			  float *x, float *y) const
   {
     hb_font_t *font = c->font;
-    *x = font->em_scale_x (xCoordinate);
-    *y = font->em_scale_y (yCoordinate);
+    *x = font->em_fscale_x (xCoordinate);
+    *y = font->em_fscale_y (yCoordinate);
 
     if (font->x_ppem || font->num_coords)
       *x += (this+xDeviceTable).get_x_delta (font, c->var_store);
     if (font->y_ppem || font->num_coords)
       *y += (this+yDeviceTable).get_y_delta (font, c->var_store);
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) && xDeviceTable.sanitize (c, this) && yDeviceTable.sanitize (c, this));
   }
 
   protected:
-  UINT16	format;			/* Format identifier--format = 3 */
-  INT16		xCoordinate;		/* Horizontal value--in design units */
-  INT16		yCoordinate;		/* Vertical value--in design units */
+  HBUINT16	format;			/* Format identifier--format = 3 */
+  HBINT16		xCoordinate;		/* Horizontal value--in design units */
+  HBINT16		yCoordinate;		/* Vertical value--in design units */
   OffsetTo<Device>
 		xDeviceTable;		/* Offset to Device table for X
 					 * coordinate-- from beginning of
 					 * Anchor table (may be NULL) */
   OffsetTo<Device>
 		yDeviceTable;		/* Offset to Device table for Y
 					 * coordinate-- from beginning of
 					 * Anchor table (may be NULL) */
   public:
   DEFINE_SIZE_STATIC (10);
 };
 
 struct Anchor
 {
-  inline void get_anchor (hb_apply_context_t *c, hb_codepoint_t glyph_id,
-			  hb_position_t *x, hb_position_t *y) const
+  inline void get_anchor (hb_ot_apply_context_t *c, hb_codepoint_t glyph_id,
+			  float *x, float *y) const
   {
     *x = *y = 0;
     switch (u.format) {
     case 1: u.format1.get_anchor (c, glyph_id, x, y); return;
     case 2: u.format2.get_anchor (c, glyph_id, x, y); return;
     case 3: u.format3.get_anchor (c, glyph_id, x, y); return;
-    default:						 return;
+    default:					      return;
     }
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     if (!u.format.sanitize (c)) return_trace (false);
     switch (u.format) {
@@ -346,17 +346,17 @@ struct Anchor
     case 2: return_trace (u.format2.sanitize (c));
     case 3: return_trace (u.format3.sanitize (c));
     default:return_trace (true);
     }
   }
 
   protected:
   union {
-  UINT16		format;		/* Format identifier */
+  HBUINT16		format;		/* Format identifier */
   AnchorFormat1		format1;
   AnchorFormat2		format2;
   AnchorFormat3		format3;
   } u;
   public:
   DEFINE_SIZE_UNION (2, format);
 };
 
@@ -377,17 +377,17 @@ struct AnchorMatrix
     if (unlikely (_hb_unsigned_int_mul_overflows (rows, cols))) return_trace (false);
     unsigned int count = rows * cols;
     if (!c->check_array (matrixZ, matrixZ[0].static_size, count)) return_trace (false);
     for (unsigned int i = 0; i < count; i++)
       if (!matrixZ[i].sanitize (c, this)) return_trace (false);
     return_trace (true);
   }
 
-  UINT16	rows;			/* Number of rows */
+  HBUINT16	rows;			/* Number of rows */
   protected:
   OffsetTo<Anchor>
 		matrixZ[VAR];		/* Matrix of offsets to Anchor tables--
 					 * from beginning of AnchorMatrix table */
   public:
   DEFINE_SIZE_ARRAY (2, matrixZ);
 };
 
@@ -398,52 +398,52 @@ struct MarkRecord
 
   inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) && markAnchor.sanitize (c, base));
   }
 
   protected:
-  UINT16	klass;			/* Class defined for this mark */
+  HBUINT16	klass;			/* Class defined for this mark */
   OffsetTo<Anchor>
 		markAnchor;		/* Offset to Anchor table--from
 					 * beginning of MarkArray table */
   public:
   DEFINE_SIZE_STATIC (4);
 };
 
 struct MarkArray : ArrayOf<MarkRecord>	/* Array of MarkRecords--in Coverage order */
 {
-  inline bool apply (hb_apply_context_t *c,
+  inline bool apply (hb_ot_apply_context_t *c,
 		     unsigned int mark_index, unsigned int glyph_index,
 		     const AnchorMatrix &anchors, unsigned int class_count,
 		     unsigned int glyph_pos) const
   {
     TRACE_APPLY (this);
     hb_buffer_t *buffer = c->buffer;
     const MarkRecord &record = ArrayOf<MarkRecord>::operator[](mark_index);
     unsigned int mark_class = record.klass;
 
     const Anchor& mark_anchor = this + record.markAnchor;
     bool found;
     const Anchor& glyph_anchor = anchors.get_anchor (glyph_index, mark_class, class_count, &found);
     /* If this subtable doesn't have an anchor for this base and this class,
      * return false such that the subsequent subtables have a chance at it. */
     if (unlikely (!found)) return_trace (false);
 
-    hb_position_t mark_x, mark_y, base_x, base_y;
+    float mark_x, mark_y, base_x, base_y;
 
     buffer->unsafe_to_break (glyph_pos, buffer->idx);
     mark_anchor.get_anchor (c, buffer->cur().codepoint, &mark_x, &mark_y);
     glyph_anchor.get_anchor (c, buffer->info[glyph_pos].codepoint, &base_x, &base_y);
 
     hb_glyph_position_t &o = buffer->cur_pos();
-    o.x_offset = base_x - mark_x;
-    o.y_offset = base_y - mark_y;
+    o.x_offset = round (base_x - mark_x);
+    o.y_offset = round (base_y - mark_y);
     o.attach_type() = ATTACH_TYPE_MARK;
     o.attach_chain() = (int) glyph_pos - (int) buffer->idx;
     buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
 
     buffer->idx++;
     return_trace (true);
   }
 
@@ -465,17 +465,17 @@ struct SinglePosFormat1
     if (unlikely (!(this+coverage).add_coverage (c->input))) return;
   }
 
   inline const Coverage &get_coverage (void) const
   {
     return this+coverage;
   }
 
-  inline bool apply (hb_apply_context_t *c) const
+  inline bool apply (hb_ot_apply_context_t *c) const
   {
     TRACE_APPLY (this);
     hb_buffer_t *buffer = c->buffer;
     unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint);
     if (likely (index == NOT_COVERED)) return_trace (false);
 
     valueFormat.apply_value (c, this, values, buffer->cur_pos());
 
@@ -487,17 +487,17 @@ struct SinglePosFormat1
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) &&
 		  coverage.sanitize (c, this) &&
 		  valueFormat.sanitize_value (c, this, values));
   }
 
   protected:
-  UINT16	format;			/* Format identifier--format = 1 */
+  HBUINT16	format;			/* Format identifier--format = 1 */
   OffsetTo<Coverage>
 		coverage;		/* Offset to Coverage table--from
 					 * beginning of subtable */
   ValueFormat	valueFormat;		/* Defines the types of data in the
 					 * ValueRecord */
   ValueRecord	values;			/* Defines positioning
 					 * value(s)--applied to all glyphs in
 					 * the Coverage table */
@@ -513,17 +513,17 @@ struct SinglePosFormat2
     if (unlikely (!(this+coverage).add_coverage (c->input))) return;
   }
 
   inline const Coverage &get_coverage (void) const
   {
     return this+coverage;
   }
 
-  inline bool apply (hb_apply_context_t *c) const
+  inline bool apply (hb_ot_apply_context_t *c) const
   {
     TRACE_APPLY (this);
     hb_buffer_t *buffer = c->buffer;
     unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint);
     if (likely (index == NOT_COVERED)) return_trace (false);
 
     if (likely (index >= valueCount)) return_trace (false);
 
@@ -539,23 +539,23 @@ struct SinglePosFormat2
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) &&
 		  coverage.sanitize (c, this) &&
 		  valueFormat.sanitize_values (c, this, values, valueCount));
   }
 
   protected:
-  UINT16	format;			/* Format identifier--format = 2 */
+  HBUINT16	format;			/* Format identifier--format = 2 */
   OffsetTo<Coverage>
 		coverage;		/* Offset to Coverage table--from
 					 * beginning of subtable */
   ValueFormat	valueFormat;		/* Defines the types of data in the
 					 * ValueRecord */
-  UINT16	valueCount;		/* Number of ValueRecords */
+  HBUINT16	valueCount;		/* Number of ValueRecords */
   ValueRecord	values;			/* Array of ValueRecords--positioning
 					 * values applied to glyphs */
   public:
   DEFINE_SIZE_ARRAY (8, values);
 };
 
 struct SinglePos
 {
@@ -568,17 +568,17 @@ struct SinglePos
     case 1: return_trace (c->dispatch (u.format1));
     case 2: return_trace (c->dispatch (u.format2));
     default:return_trace (c->default_return_value ());
     }
   }
 
   protected:
   union {
-  UINT16		format;		/* Format identifier */
+  HBUINT16		format;		/* Format identifier */
   SinglePosFormat1	format1;
   SinglePosFormat2	format2;
   } u;
 };
 
 
 struct PairValueRecord
 {
@@ -599,31 +599,31 @@ struct PairSet
   friend struct PairPosFormat1;
 
   inline void collect_glyphs (hb_collect_glyphs_context_t *c,
 			      const ValueFormat *valueFormats) const
   {
     TRACE_COLLECT_GLYPHS (this);
     unsigned int len1 = valueFormats[0].get_len ();
     unsigned int len2 = valueFormats[1].get_len ();
-    unsigned int record_size = UINT16::static_size * (1 + len1 + len2);
+    unsigned int record_size = HBUINT16::static_size * (1 + len1 + len2);
 
     const PairValueRecord *record = CastP<PairValueRecord> (arrayZ);
     c->input->add_array (&record->secondGlyph, len, record_size);
   }
 
-  inline bool apply (hb_apply_context_t *c,
+  inline bool apply (hb_ot_apply_context_t *c,
 		     const ValueFormat *valueFormats,
 		     unsigned int pos) const
   {
     TRACE_APPLY (this);
     hb_buffer_t *buffer = c->buffer;
     unsigned int len1 = valueFormats[0].get_len ();
     unsigned int len2 = valueFormats[1].get_len ();
-    unsigned int record_size = UINT16::static_size * (1 + len1 + len2);
+    unsigned int record_size = HBUINT16::static_size * (1 + len1 + len2);
 
     const PairValueRecord *record_array = CastP<PairValueRecord> (arrayZ);
     unsigned int count = len;
 
     /* Hand-coded bsearch. */
     if (unlikely (!count))
       return_trace (false);
     hb_codepoint_t x = buffer->info[pos].codepoint;
@@ -658,27 +658,27 @@ struct PairSet
     unsigned int len1; /* valueFormats[0].get_len() */
     unsigned int stride; /* 1 + len1 + len2 */
   };
 
   inline bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *closure) const
   {
     TRACE_SANITIZE (this);
     if (!(c->check_struct (this)
-       && c->check_array (arrayZ, UINT16::static_size * closure->stride, len))) return_trace (false);
+       && c->check_array (arrayZ, HBUINT16::static_size * closure->stride, len))) return_trace (false);
 
     unsigned int count = len;
     const PairValueRecord *record = CastP<PairValueRecord> (arrayZ);
     return_trace (closure->valueFormats[0].sanitize_values_stride_unsafe (c, closure->base, &record->values[0], count, closure->stride) &&
 		  closure->valueFormats[1].sanitize_values_stride_unsafe (c, closure->base, &record->values[closure->len1], count, closure->stride));
   }
 
   protected:
-  UINT16	len;			/* Number of PairValueRecords */
-  UINT16	arrayZ[VAR];		/* Array of PairValueRecords--ordered
+  HBUINT16	len;			/* Number of PairValueRecords */
+  HBUINT16	arrayZ[VAR];		/* Array of PairValueRecords--ordered
 					 * by GlyphID of the second glyph */
   public:
   DEFINE_SIZE_ARRAY (2, arrayZ);
 };
 
 struct PairPosFormat1
 {
   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
@@ -690,24 +690,24 @@ struct PairPosFormat1
       (this+pairSet[i]).collect_glyphs (c, valueFormat);
   }
 
   inline const Coverage &get_coverage (void) const
   {
     return this+coverage;
   }
 
-  inline bool apply (hb_apply_context_t *c) const
+  inline bool apply (hb_ot_apply_context_t *c) const
   {
     TRACE_APPLY (this);
     hb_buffer_t *buffer = c->buffer;
     unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint);
     if (likely (index == NOT_COVERED)) return_trace (false);
 
-    hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
+    hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
     skippy_iter.reset (buffer->idx, 1);
     if (!skippy_iter.next ()) return_trace (false);
 
     return_trace ((this+pairSet[index]).apply (c, valueFormat, skippy_iter.idx));
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
@@ -723,17 +723,17 @@ struct PairPosFormat1
       len1,
       1 + len1 + len2
     };
 
     return_trace (coverage.sanitize (c, this) && pairSet.sanitize (c, this, &closure));
   }
 
   protected:
-  UINT16	format;			/* Format identifier--format = 1 */
+  HBUINT16	format;			/* Format identifier--format = 1 */
   OffsetTo<Coverage>
 		coverage;		/* Offset to Coverage table--from
 					 * beginning of subtable */
   ValueFormat	valueFormat[2];		/* [0] Defines the types of data in
 					 * ValueRecord1--for the first glyph
 					 * in the pair--may be zero (0) */
 					/* [1] Defines the types of data in
 					 * ValueRecord2--for the second glyph
@@ -754,24 +754,24 @@ struct PairPosFormat2
     if (unlikely (!(this+classDef2).add_coverage (c->input))) return;
   }
 
   inline const Coverage &get_coverage (void) const
   {
     return this+coverage;
   }
 
-  inline bool apply (hb_apply_context_t *c) const
+  inline bool apply (hb_ot_apply_context_t *c) const
   {
     TRACE_APPLY (this);
     hb_buffer_t *buffer = c->buffer;
     unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint);
     if (likely (index == NOT_COVERED)) return_trace (false);
 
-    hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
+    hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
     skippy_iter.reset (buffer->idx, 1);
     if (!skippy_iter.next ()) return_trace (false);
 
     unsigned int len1 = valueFormat1.get_len ();
     unsigned int len2 = valueFormat2.get_len ();
     unsigned int record_len = len1 + len2;
 
     unsigned int klass1 = (this+classDef1).get_class (buffer->cur().codepoint);
@@ -804,17 +804,17 @@ struct PairPosFormat2
     unsigned int record_size = valueFormat1.get_size () + valueFormat2.get_size ();
     unsigned int count = (unsigned int) class1Count * (unsigned int) class2Count;
     return_trace (c->check_array (values, record_size, count) &&
 		  valueFormat1.sanitize_values_stride_unsafe (c, this, &values[0], count, stride) &&
 		  valueFormat2.sanitize_values_stride_unsafe (c, this, &values[len1], count, stride));
   }
 
   protected:
-  UINT16	format;			/* Format identifier--format = 2 */
+  HBUINT16	format;			/* Format identifier--format = 2 */
   OffsetTo<Coverage>
 		coverage;		/* Offset to Coverage table--from
 					 * beginning of subtable */
   ValueFormat	valueFormat1;		/* ValueRecord definition--for the
 					 * first glyph of the pair--may be zero
 					 * (0) */
   ValueFormat	valueFormat2;		/* ValueRecord definition--for the
 					 * second glyph of the pair--may be
@@ -822,19 +822,19 @@ struct PairPosFormat2
   OffsetTo<ClassDef>
 		classDef1;		/* Offset to ClassDef table--from
 					 * beginning of PairPos subtable--for
 					 * the first glyph of the pair */
   OffsetTo<ClassDef>
 		classDef2;		/* Offset to ClassDef table--from
 					 * beginning of PairPos subtable--for
 					 * the second glyph of the pair */
-  UINT16	class1Count;		/* Number of classes in ClassDef1
+  HBUINT16	class1Count;		/* Number of classes in ClassDef1
 					 * table--includes Class0 */
-  UINT16	class2Count;		/* Number of classes in ClassDef2
+  HBUINT16	class2Count;		/* Number of classes in ClassDef2
 					 * table--includes Class0 */
   ValueRecord	values;			/* Matrix of value pairs:
 					 * class1-major, class2-minor,
 					 * Each entry has value1 and value2 */
   public:
   DEFINE_SIZE_ARRAY (16, values);
 };
 
@@ -849,17 +849,17 @@ struct PairPos
     case 1: return_trace (c->dispatch (u.format1));
     case 2: return_trace (c->dispatch (u.format2));
     default:return_trace (c->default_return_value ());
     }
   }
 
   protected:
   union {
-  UINT16		format;		/* Format identifier */
+  HBUINT16		format;		/* Format identifier */
   PairPosFormat1	format1;
   PairPosFormat2	format2;
   } u;
 };
 
 
 struct EntryExitRecord
 {
@@ -895,71 +895,71 @@ struct CursivePosFormat1
     if (unlikely (!(this+coverage).add_coverage (c->input))) return;
   }
 
   inline const Coverage &get_coverage (void) const
   {
     return this+coverage;
   }
 
-  inline bool apply (hb_apply_context_t *c) const
+  inline bool apply (hb_ot_apply_context_t *c) const
   {
     TRACE_APPLY (this);
     hb_buffer_t *buffer = c->buffer;
 
     const EntryExitRecord &this_record = entryExitRecord[(this+coverage).get_coverage  (buffer->cur().codepoint)];
     if (!this_record.exitAnchor) return_trace (false);
 
-    hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
+    hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
     skippy_iter.reset (buffer->idx, 1);
     if (!skippy_iter.next ()) return_trace (false);
 
     const EntryExitRecord &next_record = entryExitRecord[(this+coverage).get_coverage  (buffer->info[skippy_iter.idx].codepoint)];
     if (!next_record.entryAnchor) return_trace (false);
 
     unsigned int i = buffer->idx;
     unsigned int j = skippy_iter.idx;
 
     buffer->unsafe_to_break (i, j);
-    hb_position_t entry_x, entry_y, exit_x, exit_y;
+    float entry_x, entry_y, exit_x, exit_y;
     (this+this_record.exitAnchor).get_anchor (c, buffer->info[i].codepoint, &exit_x, &exit_y);
     (this+next_record.entryAnchor).get_anchor (c, buffer->info[j].codepoint, &entry_x, &entry_y);
 
     hb_glyph_position_t *pos = buffer->pos;
 
     hb_position_t d;
     /* Main-direction adjustment */
     switch (c->direction) {
       case HB_DIRECTION_LTR:
-	pos[i].x_advance  =  exit_x + pos[i].x_offset;
+	pos[i].x_advance  = round (exit_x) + pos[i].x_offset;
 
-	d = entry_x + pos[j].x_offset;
+	d = round (entry_x) + pos[j].x_offset;
 	pos[j].x_advance -= d;
 	pos[j].x_offset  -= d;
 	break;
       case HB_DIRECTION_RTL:
-	d = exit_x + pos[i].x_offset;
+	d = round (exit_x) + pos[i].x_offset;
 	pos[i].x_advance -= d;
 	pos[i].x_offset  -= d;
 
-	pos[j].x_advance  =  entry_x + pos[j].x_offset;
+	pos[j].x_advance  = round (entry_x) + pos[j].x_offset;
 	break;
       case HB_DIRECTION_TTB:
-	pos[i].y_advance  =  exit_y + pos[i].y_offset;
+	pos[i].y_advance  = round (exit_y) + pos[i].y_offset;
 
-	d = entry_y + pos[j].y_offset;
+	d = round (entry_y) + pos[j].y_offset;
 	pos[j].y_advance -= d;
 	pos[j].y_offset  -= d;
 	break;
       case HB_DIRECTION_BTT:
-	d = exit_y + pos[i].y_offset;
+	d = round (exit_y) + pos[i].y_offset;
 	pos[i].y_advance -= d;
 	pos[i].y_offset  -= d;
 
-	pos[j].y_advance  =  entry_y;
+	pos[j].y_advance  = round (entry_y);
 	break;
       case HB_DIRECTION_INVALID:
       default:
 	break;
     }
 
     /* Cross-direction adjustment */
 
@@ -1003,17 +1003,17 @@ struct CursivePosFormat1
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (coverage.sanitize (c, this) && entryExitRecord.sanitize (c, this));
   }
 
   protected:
-  UINT16	format;			/* Format identifier--format = 1 */
+  HBUINT16	format;			/* Format identifier--format = 1 */
   OffsetTo<Coverage>
 		coverage;		/* Offset to Coverage table--from
 					 * beginning of subtable */
   ArrayOf<EntryExitRecord>
 		entryExitRecord;	/* Array of EntryExit records--in
 					 * Coverage Index order */
   public:
   DEFINE_SIZE_ARRAY (6, entryExitRecord);
@@ -1029,17 +1029,17 @@ struct CursivePos
     switch (u.format) {
     case 1: return_trace (c->dispatch (u.format1));
     default:return_trace (c->default_return_value ());
     }
   }
 
   protected:
   union {
-  UINT16		format;		/* Format identifier */
+  HBUINT16		format;		/* Format identifier */
   CursivePosFormat1	format1;
   } u;
 };
 
 
 typedef AnchorMatrix BaseArray;		/* base-major--
 					 * in order of BaseCoverage Index--,
 					 * mark-minor--
@@ -1054,25 +1054,25 @@ struct MarkBasePosFormat1
     if (unlikely (!(this+baseCoverage).add_coverage (c->input))) return;
   }
 
   inline const Coverage &get_coverage (void) const
   {
     return this+markCoverage;
   }
 
-  inline bool apply (hb_apply_context_t *c) const
+  inline bool apply (hb_ot_apply_context_t *c) const
   {
     TRACE_APPLY (this);
     hb_buffer_t *buffer = c->buffer;
     unsigned int mark_index = (this+markCoverage).get_coverage  (buffer->cur().codepoint);
     if (likely (mark_index == NOT_COVERED)) return_trace (false);
 
     /* Now we search backwards for a non-mark glyph */
-    hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
+    hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
     skippy_iter.reset (buffer->idx, 1);
     skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks);
     do {
       if (!skippy_iter.prev ()) return_trace (false);
       /* We only want to attach to the first of a MultipleSubst sequence.  Reject others. */
       if (!_hb_glyph_info_multiplied (&buffer->info[skippy_iter.idx]) ||
 	  0 == _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]))
 	break;
@@ -1094,24 +1094,24 @@ struct MarkBasePosFormat1
     return_trace (c->check_struct (this) &&
 		  markCoverage.sanitize (c, this) &&
 		  baseCoverage.sanitize (c, this) &&
 		  markArray.sanitize (c, this) &&
 		  baseArray.sanitize (c, this, (unsigned int) classCount));
   }
 
   protected:
-  UINT16	format;			/* Format identifier--format = 1 */
+  HBUINT16	format;			/* Format identifier--format = 1 */
   OffsetTo<Coverage>
 		markCoverage;		/* Offset to MarkCoverage table--from
 					 * beginning of MarkBasePos subtable */
   OffsetTo<Coverage>
 		baseCoverage;		/* Offset to BaseCoverage table--from
 					 * beginning of MarkBasePos subtable */
-  UINT16	classCount;		/* Number of classes defined for marks */
+  HBUINT16	classCount;		/* Number of classes defined for marks */
   OffsetTo<MarkArray>
 		markArray;		/* Offset to MarkArray table--from
 					 * beginning of MarkBasePos subtable */
   OffsetTo<BaseArray>
 		baseArray;		/* Offset to BaseArray table--from
 					 * beginning of MarkBasePos subtable */
   public:
   DEFINE_SIZE_STATIC (12);
@@ -1127,17 +1127,17 @@ struct MarkBasePos
     switch (u.format) {
     case 1: return_trace (c->dispatch (u.format1));
     default:return_trace (c->default_return_value ());
     }
   }
 
   protected:
   union {
-  UINT16		format;		/* Format identifier */
+  HBUINT16		format;		/* Format identifier */
   MarkBasePosFormat1	format1;
   } u;
 };
 
 
 typedef AnchorMatrix LigatureAttach;	/* component-major--
 					 * in order of writing direction--,
 					 * mark-minor--
@@ -1157,25 +1157,25 @@ struct MarkLigPosFormat1
     if (unlikely (!(this+ligatureCoverage).add_coverage (c->input))) return;
   }
 
   inline const Coverage &get_coverage (void) const
   {
     return this+markCoverage;
   }
 
-  inline bool apply (hb_apply_context_t *c) const
+  inline bool apply (hb_ot_apply_context_t *c) const
   {
     TRACE_APPLY (this);
     hb_buffer_t *buffer = c->buffer;
     unsigned int mark_index = (this+markCoverage).get_coverage  (buffer->cur().codepoint);
     if (likely (mark_index == NOT_COVERED)) return_trace (false);
 
     /* Now we search backwards for a non-mark glyph */
-    hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
+    hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
     skippy_iter.reset (buffer->idx, 1);
     skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks);
     if (!skippy_iter.prev ()) return_trace (false);
 
     /* Checking that matched glyph is actually a ligature by GDEF is too strong; disabled */
     //if (!_hb_glyph_info_is_ligature (&buffer->info[skippy_iter.idx])) { return_trace (false); }
 
     unsigned int j = skippy_iter.idx;
@@ -1211,25 +1211,25 @@ struct MarkLigPosFormat1
     return_trace (c->check_struct (this) &&
 		  markCoverage.sanitize (c, this) &&
 		  ligatureCoverage.sanitize (c, this) &&
 		  markArray.sanitize (c, this) &&
 		  ligatureArray.sanitize (c, this, (unsigned int) classCount));
   }
 
   protected:
-  UINT16	format;			/* Format identifier--format = 1 */
+  HBUINT16	format;			/* Format identifier--format = 1 */
   OffsetTo<Coverage>
 		markCoverage;		/* Offset to Mark Coverage table--from
 					 * beginning of MarkLigPos subtable */
   OffsetTo<Coverage>
 		ligatureCoverage;	/* Offset to Ligature Coverage
 					 * table--from beginning of MarkLigPos
 					 * subtable */
-  UINT16	classCount;		/* Number of defined mark classes */
+  HBUINT16	classCount;		/* Number of defined mark classes */
   OffsetTo<MarkArray>
 		markArray;		/* Offset to MarkArray table--from
 					 * beginning of MarkLigPos subtable */
   OffsetTo<LigatureArray>
 		ligatureArray;		/* Offset to LigatureArray table--from
 					 * beginning of MarkLigPos subtable */
   public:
   DEFINE_SIZE_STATIC (12);
@@ -1245,17 +1245,17 @@ struct MarkLigPos
     switch (u.format) {
     case 1: return_trace (c->dispatch (u.format1));
     default:return_trace (c->default_return_value ());
     }
   }
 
   protected:
   union {
-  UINT16		format;		/* Format identifier */
+  HBUINT16		format;		/* Format identifier */
   MarkLigPosFormat1	format1;
   } u;
 };
 
 
 typedef AnchorMatrix Mark2Array;	/* mark2-major--
 					 * in order of Mark2Coverage Index--,
 					 * mark1-minor--
@@ -1270,25 +1270,25 @@ struct MarkMarkPosFormat1
     if (unlikely (!(this+mark2Coverage).add_coverage (c->input))) return;
   }
 
   inline const Coverage &get_coverage (void) const
   {
     return this+mark1Coverage;
   }
 
-  inline bool apply (hb_apply_context_t *c) const
+  inline bool apply (hb_ot_apply_context_t *c) const
   {
     TRACE_APPLY (this);
     hb_buffer_t *buffer = c->buffer;
     unsigned int mark1_index = (this+mark1Coverage).get_coverage  (buffer->cur().codepoint);
     if (likely (mark1_index == NOT_COVERED)) return_trace (false);
 
     /* now we search backwards for a suitable mark glyph until a non-mark glyph */
-    hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
+    hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
     skippy_iter.reset (buffer->idx, 1);
     skippy_iter.set_lookup_props (c->lookup_props & ~LookupFlag::IgnoreFlags);
     if (!skippy_iter.prev ()) return_trace (false);
 
     if (!_hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx])) { return_trace (false); }
 
     unsigned int j = skippy_iter.idx;
 
@@ -1325,26 +1325,26 @@ struct MarkMarkPosFormat1
     return_trace (c->check_struct (this) &&
 		  mark1Coverage.sanitize (c, this) &&
 		  mark2Coverage.sanitize (c, this) &&
 		  mark1Array.sanitize (c, this) &&
 		  mark2Array.sanitize (c, this, (unsigned int) classCount));
   }
 
   protected:
-  UINT16	format;			/* Format identifier--format = 1 */
+  HBUINT16	format;			/* Format identifier--format = 1 */
   OffsetTo<Coverage>
 		mark1Coverage;		/* Offset to Combining Mark1 Coverage
 					 * table--from beginning of MarkMarkPos
 					 * subtable */
   OffsetTo<Coverage>
 		mark2Coverage;		/* Offset to Combining Mark2 Coverage
 					 * table--from beginning of MarkMarkPos
 					 * subtable */
-  UINT16	classCount;		/* Number of defined mark classes */
+  HBUINT16	classCount;		/* Number of defined mark classes */
   OffsetTo<MarkArray>
 		mark1Array;		/* Offset to Mark1Array table--from
 					 * beginning of MarkMarkPos subtable */
   OffsetTo<Mark2Array>
 		mark2Array;		/* Offset to Mark2Array table--from
 					 * beginning of MarkMarkPos subtable */
   public:
   DEFINE_SIZE_STATIC (12);
@@ -1360,17 +1360,17 @@ struct MarkMarkPos
     switch (u.format) {
     case 1: return_trace (c->dispatch (u.format1));
     default:return_trace (c->default_return_value ());
     }
   }
 
   protected:
   union {
-  UINT16		format;		/* Format identifier */
+  HBUINT16		format;		/* Format identifier */
   MarkMarkPosFormat1	format1;
   } u;
 };
 
 
 struct ContextPos : Context {};
 
 struct ChainContextPos : ChainContext {};
@@ -1419,17 +1419,17 @@ struct PosLookupSubTable
     case ChainContext:		return_trace (u.chainContext.dispatch (c));
     case Extension:		return_trace (u.extension.dispatch (c));
     default:			return_trace (c->default_return_value ());
     }
   }
 
   protected:
   union {
-  UINT16		sub_format;
+  HBUINT16		sub_format;
   SinglePos		single;
   PairPos		pair;
   CursivePos		cursive;
   MarkBasePos		markBase;
   MarkLigPos		markLig;
   MarkMarkPos		markMark;
   ContextPos		context;
   ChainContextPos	chainContext;
@@ -1445,17 +1445,17 @@ struct PosLookup : Lookup
   inline const PosLookupSubTable& get_subtable (unsigned int i) const
   { return Lookup::get_subtable<PosLookupSubTable> (i); }
 
   inline bool is_reverse (void) const
   {
     return false;
   }
 
-  inline bool apply (hb_apply_context_t *c) const
+  inline bool apply (hb_ot_apply_context_t *c) const
   {
     TRACE_APPLY (this);
     return_trace (dispatch (c));
   }
 
   inline hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
     TRACE_COLLECT_GLYPHS (this);
@@ -1464,17 +1464,17 @@ struct PosLookup : Lookup
 
   template <typename set_t>
   inline void add_coverage (set_t *glyphs) const
   {
     hb_add_coverage_context_t<set_t> c (glyphs);
     dispatch (&c);
   }
 
-  static bool apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index);
+  static bool apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index);
 
   template <typename context_t>
   static inline typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index);
 
   template <typename context_t>
   inline typename context_t::return_t dispatch (context_t *c) const
   { return Lookup::dispatch<PosLookupSubTable> (c); }
 
@@ -1616,17 +1616,17 @@ GPOS::position_finish_offsets (hb_font_t
 template <typename context_t>
 /*static*/ inline typename context_t::return_t PosLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index)
 {
   const GPOS &gpos = *(hb_ot_layout_from_face (c->face)->gpos);
   const PosLookup &l = gpos.get_lookup (lookup_index);
   return l.dispatch (c);
 }
 
-/*static*/ inline bool PosLookup::apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index)
+/*static*/ inline bool PosLookup::apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index)
 {
   const GPOS &gpos = *(hb_ot_layout_from_face (c->face)->gpos);
   const PosLookup &l = gpos.get_lookup (lookup_index);
   unsigned int saved_lookup_props = c->lookup_props;
   unsigned int saved_lookup_index = c->lookup_index;
   c->set_lookup_index (lookup_index);
   c->set_lookup_props (l.get_props ());
   bool ret = l.dispatch (c);
--- a/gfx/harfbuzz/src/hb-ot-layout-gsub-table.hh
+++ b/gfx/harfbuzz/src/hb-ot-layout-gsub-table.hh
@@ -71,17 +71,17 @@ struct SingleSubstFormat1
   }
 
   inline bool would_apply (hb_would_apply_context_t *c) const
   {
     TRACE_WOULD_APPLY (this);
     return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
   }
 
-  inline bool apply (hb_apply_context_t *c) const
+  inline bool apply (hb_ot_apply_context_t *c) const
   {
     TRACE_APPLY (this);
     hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
     unsigned int index = (this+coverage).get_coverage (glyph_id);
     if (likely (index == NOT_COVERED)) return_trace (false);
 
     /* According to the Adobe Annotated OpenType Suite, result is always
      * limited to 16bit. */
@@ -105,21 +105,21 @@ struct SingleSubstFormat1
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (coverage.sanitize (c, this) && deltaGlyphID.sanitize (c));
   }
 
   protected:
-  UINT16	format;			/* Format identifier--format = 1 */
+  HBUINT16	format;			/* Format identifier--format = 1 */
   OffsetTo<Coverage>
 		coverage;		/* Offset to Coverage table--from
 					 * beginning of Substitution table */
-  INT16		deltaGlyphID;		/* Add to original GlyphID to get
+  HBINT16		deltaGlyphID;		/* Add to original GlyphID to get
 					 * substitute GlyphID */
   public:
   DEFINE_SIZE_STATIC (6);
 };
 
 struct SingleSubstFormat2
 {
   inline void closure (hb_closure_context_t *c) const
@@ -156,17 +156,17 @@ struct SingleSubstFormat2
   }
 
   inline bool would_apply (hb_would_apply_context_t *c) const
   {
     TRACE_WOULD_APPLY (this);
     return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
   }
 
-  inline bool apply (hb_apply_context_t *c) const
+  inline bool apply (hb_ot_apply_context_t *c) const
   {
     TRACE_APPLY (this);
     hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
     unsigned int index = (this+coverage).get_coverage (glyph_id);
     if (likely (index == NOT_COVERED)) return_trace (false);
 
     if (unlikely (index >= substitute.len)) return_trace (false);
 
@@ -190,17 +190,17 @@ struct SingleSubstFormat2
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (coverage.sanitize (c, this) && substitute.sanitize (c));
   }
 
   protected:
-  UINT16	format;			/* Format identifier--format = 2 */
+  HBUINT16	format;			/* Format identifier--format = 2 */
   OffsetTo<Coverage>
 		coverage;		/* Offset to Coverage table--from
 					 * beginning of Substitution table */
   ArrayOf<GlyphID>
 		substitute;		/* Array of substitute
 					 * GlyphIDs--ordered by Coverage Index */
   public:
   DEFINE_SIZE_ARRAY (6, substitute);
@@ -244,17 +244,17 @@ struct SingleSubst
     case 1: return_trace (c->dispatch (u.format1));
     case 2: return_trace (c->dispatch (u.format2));
     default:return_trace (c->default_return_value ());
     }
   }
 
   protected:
   union {
-  UINT16		format;		/* Format identifier */
+  HBUINT16		format;		/* Format identifier */
   SingleSubstFormat1	format1;
   SingleSubstFormat2	format2;
   } u;
 };
 
 
 struct Sequence
 {
@@ -267,17 +267,17 @@ struct Sequence
   }
 
   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
     TRACE_COLLECT_GLYPHS (this);
     c->output->add_array (substitute.array, substitute.len);
   }
 
-  inline bool apply (hb_apply_context_t *c) const
+  inline bool apply (hb_ot_apply_context_t *c) const
   {
     TRACE_APPLY (this);
     unsigned int count = substitute.len;
 
     /* Special-case to make it in-place and not consider this
      * as a "multiplied" substitution. */
     if (unlikely (count == 1))
     {
@@ -358,17 +358,17 @@ struct MultipleSubstFormat1
   }
 
   inline bool would_apply (hb_would_apply_context_t *c) const
   {
     TRACE_WOULD_APPLY (this);
     return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
   }
 
-  inline bool apply (hb_apply_context_t *c) const
+  inline bool apply (hb_ot_apply_context_t *c) const
   {
     TRACE_APPLY (this);
 
     unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
     if (likely (index == NOT_COVERED)) return_trace (false);
 
     return_trace ((this+sequence[index]).apply (c));
   }
@@ -393,17 +393,17 @@ struct MultipleSubstFormat1
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (coverage.sanitize (c, this) && sequence.sanitize (c, this));
   }
 
   protected:
-  UINT16	format;			/* Format identifier--format = 1 */
+  HBUINT16	format;			/* Format identifier--format = 1 */
   OffsetTo<Coverage>
 		coverage;		/* Offset to Coverage table--from
 					 * beginning of Substitution table */
   OffsetArrayOf<Sequence>
 		sequence;		/* Array of Sequence tables
 					 * ordered by Coverage Index */
   public:
   DEFINE_SIZE_ARRAY (6, sequence);
@@ -435,17 +435,17 @@ struct MultipleSubst
     switch (u.format) {
     case 1: return_trace (c->dispatch (u.format1));
     default:return_trace (c->default_return_value ());
     }
   }
 
   protected:
   union {
-  UINT16		format;		/* Format identifier */
+  HBUINT16		format;		/* Format identifier */
   MultipleSubstFormat1	format1;
   } u;
 };
 
 
 typedef ArrayOf<GlyphID> AlternateSet;	/* Array of alternate GlyphIDs--in
 					 * arbitrary order */
 
@@ -490,17 +490,17 @@ struct AlternateSubstFormat1
   }
 
   inline bool would_apply (hb_would_apply_context_t *c) const
   {
     TRACE_WOULD_APPLY (this);
     return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
   }
 
-  inline bool apply (hb_apply_context_t *c) const
+  inline bool apply (hb_ot_apply_context_t *c) const
   {
     TRACE_APPLY (this);
     hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
 
     unsigned int index = (this+coverage).get_coverage (glyph_id);
     if (likely (index == NOT_COVERED)) return_trace (false);
 
     const AlternateSet &alt_set = this+alternateSet[index];
@@ -543,17 +543,17 @@ struct AlternateSubstFormat1
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (coverage.sanitize (c, this) && alternateSet.sanitize (c, this));
   }
 
   protected:
-  UINT16	format;			/* Format identifier--format = 1 */
+  HBUINT16	format;			/* Format identifier--format = 1 */
   OffsetTo<Coverage>
 		coverage;		/* Offset to Coverage table--from
 					 * beginning of Substitution table */
   OffsetArrayOf<AlternateSet>
 		alternateSet;		/* Array of AlternateSet tables
 					 * ordered by Coverage Index */
   public:
   DEFINE_SIZE_ARRAY (6, alternateSet);
@@ -585,17 +585,17 @@ struct AlternateSubst
     switch (u.format) {
     case 1: return_trace (c->dispatch (u.format1));
     default:return_trace (c->default_return_value ());
     }
   }
 
   protected:
   union {
-  UINT16		format;		/* Format identifier */
+  HBUINT16		format;		/* Format identifier */
   AlternateSubstFormat1	format1;
   } u;
 };
 
 
 struct Ligature
 {
   inline void closure (hb_closure_context_t *c) const
@@ -623,17 +623,17 @@ struct Ligature
 
     for (unsigned int i = 1; i < c->len; i++)
       if (likely (c->glyphs[i] != component[i]))
 	return_trace (false);
 
     return_trace (true);
   }
 
-  inline bool apply (hb_apply_context_t *c) const
+  inline bool apply (hb_ot_apply_context_t *c) const
   {
     TRACE_APPLY (this);
     unsigned int count = component.len;
 
     if (unlikely (!count)) return_trace (false);
 
     /* Special-case to make it in-place and not consider this
      * as a "ligated" substitution. */
@@ -725,17 +725,17 @@ struct LigatureSet
     {
       const Ligature &lig = this+ligature[i];
       if (lig.would_apply (c))
         return_trace (true);
     }
     return_trace (false);
   }
 
-  inline bool apply (hb_apply_context_t *c) const
+  inline bool apply (hb_ot_apply_context_t *c) const
   {
     TRACE_APPLY (this);
     unsigned int num_ligs = ligature.len;
     for (unsigned int i = 0; i < num_ligs; i++)
     {
       const Ligature &lig = this+ligature[i];
       if (lig.apply (c)) return_trace (true);
     }
@@ -816,17 +816,17 @@ struct LigatureSubstFormat1
     TRACE_WOULD_APPLY (this);
     unsigned int index = (this+coverage).get_coverage (c->glyphs[0]);
     if (likely (index == NOT_COVERED)) return_trace (false);
 
     const LigatureSet &lig_set = this+ligatureSet[index];
     return_trace (lig_set.would_apply (c));
   }
 
-  inline bool apply (hb_apply_context_t *c) const
+  inline bool apply (hb_ot_apply_context_t *c) const
   {
     TRACE_APPLY (this);
     hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
 
     unsigned int index = (this+coverage).get_coverage (glyph_id);
     if (likely (index == NOT_COVERED)) return_trace (false);
 
     const LigatureSet &lig_set = this+ligatureSet[index];
@@ -857,17 +857,17 @@ struct LigatureSubstFormat1
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (coverage.sanitize (c, this) && ligatureSet.sanitize (c, this));
   }
 
   protected:
-  UINT16	format;			/* Format identifier--format = 1 */
+  HBUINT16	format;			/* Format identifier--format = 1 */
   OffsetTo<Coverage>
 		coverage;		/* Offset to Coverage table--from
 					 * beginning of Substitution table */
   OffsetArrayOf<LigatureSet>
 		ligatureSet;		/* Array LigatureSet tables
 					 * ordered by Coverage Index */
   public:
   DEFINE_SIZE_ARRAY (6, ligatureSet);
@@ -907,17 +907,17 @@ struct LigatureSubst
     switch (u.format) {
     case 1: return_trace (c->dispatch (u.format1));
     default:return_trace (c->default_return_value ());
     }
   }
 
   protected:
   union {
-  UINT16		format;		/* Format identifier */
+  HBUINT16		format;		/* Format identifier */
   LigatureSubstFormat1	format1;
   } u;
 };
 
 
 struct ContextSubst : Context {};
 
 struct ChainContextSubst : ChainContext {};
@@ -988,35 +988,35 @@ struct ReverseChainSingleSubstFormat1
   }
 
   inline bool would_apply (hb_would_apply_context_t *c) const
   {
     TRACE_WOULD_APPLY (this);
     return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
   }
 
-  inline bool apply (hb_apply_context_t *c) const
+  inline bool apply (hb_ot_apply_context_t *c) const
   {
     TRACE_APPLY (this);
     if (unlikely (c->nesting_level_left != HB_MAX_NESTING_LEVEL))
       return_trace (false); /* No chaining to this type */
 
     unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
     if (likely (index == NOT_COVERED)) return_trace (false);
 
     const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
     const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
 
   unsigned int start_index = 0, end_index = 0;
     if (match_backtrack (c,
-			 backtrack.len, (UINT16 *) backtrack.array,
+			 backtrack.len, (HBUINT16 *) backtrack.array,
 			 match_coverage, this,
 			 &start_index) &&
         match_lookahead (c,
-			 lookahead.len, (UINT16 *) lookahead.array,
+			 lookahead.len, (HBUINT16 *) lookahead.array,
 			 match_coverage, this,
 			 1, &end_index))
     {
       c->buffer->unsafe_to_break_from_outbuffer (start_index, end_index);
       c->replace_glyph_inplace (substitute[index]);
       /* Note: We DON'T decrease buffer->idx.  The main loop does it
        * for us.  This is useful for preventing surprises if someone
        * calls us through a Context lookup. */
@@ -1034,17 +1034,17 @@ struct ReverseChainSingleSubstFormat1
     const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
     if (!lookahead.sanitize (c, this))
       return_trace (false);
     const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
     return_trace (substitute.sanitize (c));
   }
 
   protected:
-  UINT16	format;			/* Format identifier--format = 1 */
+  HBUINT16	format;			/* Format identifier--format = 1 */
   OffsetTo<Coverage>
 		coverage;		/* Offset to Coverage table--from
 					 * beginning of table */
   OffsetArrayOf<Coverage>
 		backtrack;		/* Array of coverage tables
 					 * in backtracking sequence, in  glyph
 					 * sequence order */
   OffsetArrayOf<Coverage>
@@ -1068,17 +1068,17 @@ struct ReverseChainSingleSubst
     switch (u.format) {
     case 1: return_trace (c->dispatch (u.format1));
     default:return_trace (c->default_return_value ());
     }
   }
 
   protected:
   union {
-  UINT16				format;		/* Format identifier */
+  HBUINT16				format;		/* Format identifier */
   ReverseChainSingleSubstFormat1	format1;
   } u;
 };
 
 
 
 /*
  * SubstLookup
@@ -1114,17 +1114,17 @@ struct SubstLookupSubTable
     case Extension:		return_trace (u.extension.dispatch (c));
     case ReverseChainSingle:	return_trace (u.reverseChainContextSingle.dispatch (c));
     default:			return_trace (c->default_return_value ());
     }
   }
 
   protected:
   union {
-  UINT16			sub_format;
+  HBUINT16			sub_format;
   SingleSubst			single;
   MultipleSubst			multiple;
   AlternateSubst		alternate;
   LigatureSubst			ligature;
   ContextSubst			context;
   ChainContextSubst		chainContext;
   ExtensionSubst		extension;
   ReverseChainSingleSubst	reverseChainContextSingle;
@@ -1145,17 +1145,17 @@ struct SubstLookup : Lookup
   inline bool is_reverse (void) const
   {
     unsigned int type = get_type ();
     if (unlikely (type == SubstLookupSubTable::Extension))
       return CastR<ExtensionSubst> (get_subtable(0)).is_reverse ();
     return lookup_type_is_reverse (type);
   }
 
-  inline bool apply (hb_apply_context_t *c) const
+  inline bool apply (hb_ot_apply_context_t *c) const
   {
     TRACE_APPLY (this);
     return_trace (dispatch (c));
   }
 
   inline hb_closure_context_t::return_t closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE (this);
@@ -1181,17 +1181,17 @@ struct SubstLookup : Lookup
 			   const hb_ot_layout_lookup_accelerator_t *accel) const
   {
     TRACE_WOULD_APPLY (this);
     if (unlikely (!c->len))  return_trace (false);
     if (!accel->may_have (c->glyphs[0]))  return_trace (false);
       return_trace (dispatch (c));
   }
 
-  static bool apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index);
+  static bool apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index);
 
   inline SubstLookupSubTable& serialize_subtable (hb_serialize_context_t *c,
 						  unsigned int i)
   { return get_subtables<SubstLookupSubTable> ()[i].serialize (c, this); }
 
   inline bool serialize_single (hb_serialize_context_t *c,
 				uint32_t lookup_props,
 			        Supplier<GlyphID> &glyphs,
@@ -1267,20 +1267,19 @@ struct SubstLookup : Lookup
     TRACE_SANITIZE (this);
     if (unlikely (!Lookup::sanitize (c))) return_trace (false);
     if (unlikely (!dispatch (c))) return_trace (false);
 
     if (unlikely (get_type () == SubstLookupSubTable::Extension))
     {
       /* The spec says all subtables of an Extension lookup should
        * have the same type, which shall not be the Extension type
-       * itself. This is specially important if one has a reverse type! */
+       * itself (but we already checked for that).
+       * This is specially important if one has a reverse type! */
       unsigned int type = get_subtable (0).u.extension.get_type ();
-      if (unlikely (type == SubstLookupSubTable::Extension))
-	return_trace (false);
       unsigned int count = get_subtable_count ();
       for (unsigned int i = 1; i < count; i++)
         if (get_subtable (i).u.extension.get_type () != type)
 	  return_trace (false);
     }
     return_trace (true);
   }
 };
@@ -1339,17 +1338,17 @@ GSUB::substitute_start (hb_font_t *font,
 template <typename context_t>
 /*static*/ inline typename context_t::return_t SubstLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index)
 {
   const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub);
   const SubstLookup &l = gsub.get_lookup (lookup_index);
   return l.dispatch (c);
 }
 
-/*static*/ inline bool SubstLookup::apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index)
+/*static*/ inline bool SubstLookup::apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index)
 {
   const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub);
   const SubstLookup &l = gsub.get_lookup (lookup_index);
   unsigned int saved_lookup_props = c->lookup_props;
   unsigned int saved_lookup_index = c->lookup_index;
   c->set_lookup_index (lookup_index);
   c->set_lookup_props (l.get_props ());
   bool ret = l.dispatch (c);
--- a/gfx/harfbuzz/src/hb-ot-layout-gsubgpos-private.hh
+++ b/gfx/harfbuzz/src/hb-ot-layout-gsubgpos-private.hh
@@ -213,33 +213,33 @@ struct hb_add_coverage_context_t :
 			    set (set_),
 			    debug_depth (0) {}
 
   set_t *set;
   unsigned int debug_depth;
 };
 
 
-struct hb_apply_context_t :
-       hb_dispatch_context_t<hb_apply_context_t, bool, HB_DEBUG_APPLY>
+struct hb_ot_apply_context_t :
+       hb_dispatch_context_t<hb_ot_apply_context_t, bool, HB_DEBUG_APPLY>
 {
   struct matcher_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 (nullptr),
 	     match_data (nullptr) {};
 
-    typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const UINT16 &value, const void *data);
+    typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data);
 
     inline void set_ignore_zwnj (bool ignore_zwnj_) { ignore_zwnj = ignore_zwnj_; }
     inline void set_ignore_zwj (bool ignore_zwj_) { ignore_zwj = ignore_zwj_; }
     inline void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; }
     inline void set_mask (hb_mask_t mask_) { mask = mask_; }
     inline void set_syllable (uint8_t syllable_)  { syllable = syllable_; }
     inline void set_match_func (match_func_t match_func_,
 				const void *match_data_)
@@ -247,17 +247,17 @@ struct hb_apply_context_t :
 
     enum may_match_t {
       MATCH_NO,
       MATCH_YES,
       MATCH_MAYBE
     };
 
     inline may_match_t may_match (const hb_glyph_info_t &info,
-				  const UINT16          *glyph_data) const
+				  const HBUINT16          *glyph_data) const
     {
       if (!(info.mask & mask) ||
 	  (syllable && syllable != info.syllable ()))
 	return MATCH_NO;
 
       if (match_func)
         return match_func (info.codepoint, *glyph_data, match_data) ? MATCH_YES : MATCH_NO;
 
@@ -266,17 +266,17 @@ struct hb_apply_context_t :
 
     enum may_skip_t {
       SKIP_NO,
       SKIP_YES,
       SKIP_MAYBE
     };
 
     inline may_skip_t
-    may_skip (const hb_apply_context_t *c,
+    may_skip (const hb_ot_apply_context_t *c,
 	      const hb_glyph_info_t    &info) const
     {
       if (!c->check_glyph_property (&info, lookup_props))
 	return SKIP_YES;
 
       if (unlikely (_hb_glyph_info_is_default_ignorable_and_not_hidden (&info) &&
 		    (ignore_zwnj || !_hb_glyph_info_is_zwnj (&info)) &&
 		    (ignore_zwj || !_hb_glyph_info_is_zwj (&info))))
@@ -292,17 +292,17 @@ struct hb_apply_context_t :
     hb_mask_t mask;
     uint8_t syllable;
     match_func_t match_func;
     const void *match_data;
   };
 
   struct skipping_iterator_t
   {
-    inline void init (hb_apply_context_t *c_, bool context_match = false)
+    inline void init (hb_ot_apply_context_t *c_, bool context_match = false)
     {
       c = c_;
       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. */
@@ -310,17 +310,17 @@ struct hb_apply_context_t :
       matcher.set_mask (context_match ? -1 : c->lookup_mask);
     }
     inline void set_lookup_props (unsigned int lookup_props)
     {
       matcher.set_lookup_props (lookup_props);
     }
     inline void set_match_func (matcher_t::match_func_t match_func_,
 				const void *match_data_,
-				const UINT16 glyph_data[])
+				const HBUINT16 glyph_data[])
     {
       matcher.set_match_func (match_func_, match_data_);
       match_glyph_data = glyph_data;
     }
 
     inline void reset (unsigned int start_index_,
 		       unsigned int num_items_)
     {
@@ -328,18 +328,17 @@ struct hb_apply_context_t :
       num_items = num_items_;
       end = c->buffer->len;
       matcher.set_syllable (start_index_ == c->buffer->idx ? c->buffer->cur().syllable () : 0);
     }
 
     inline void reject (void) { num_items++; match_glyph_data--; }
 
     inline matcher_t::may_skip_t
-    may_skip (const hb_apply_context_t *c,
-	      const hb_glyph_info_t    &info) const
+    may_skip (const hb_glyph_info_t    &info) const
     {
       return matcher.may_skip (c, info);
     }
 
     inline bool next (void)
     {
       assert (num_items > 0);
       while (idx + num_items < end)
@@ -391,38 +390,38 @@ struct hb_apply_context_t :
 	if (skip == matcher_t::SKIP_NO)
 	  return false;
       }
       return false;
     }
 
     unsigned int idx;
     protected:
-    hb_apply_context_t *c;
+    hb_ot_apply_context_t *c;
     matcher_t matcher;
-    const UINT16 *match_glyph_data;
+    const HBUINT16 *match_glyph_data;
 
     unsigned int num_items;
     unsigned int end;
   };
 
 
   inline const char *get_name (void) { return "APPLY"; }
-  typedef return_t (*recurse_func_t) (hb_apply_context_t *c, unsigned int lookup_index);
+  typedef return_t (*recurse_func_t) (hb_ot_apply_context_t *c, unsigned int lookup_index);
   template <typename T>
   inline return_t dispatch (const T &obj) { return obj.apply (this); }
   static return_t default_return_value (void) { return false; }
   bool stop_sublookup_iteration (return_t r) const { return r; }
-  return_t recurse (unsigned int lookup_index)
+  return_t recurse (unsigned int sub_lookup_index)
   {
     if (unlikely (nesting_level_left == 0 || !recurse_func || buffer->max_ops-- <= 0))
       return default_return_value ();
 
     nesting_level_left--;
-    bool ret = recurse_func (this, lookup_index);
+    bool ret = recurse_func (this, sub_lookup_index);
     nesting_level_left++;
     return ret;
   }
 
   skipping_iterator_t iter_input, iter_context;
 
   hb_font_t *font;
   hb_face_t *face;
@@ -439,17 +438,17 @@ struct hb_apply_context_t :
   unsigned int nesting_level_left;
   unsigned int debug_depth;
 
   bool auto_zwnj;
   bool auto_zwj;
   bool has_glyph_classes;
 
 
-  hb_apply_context_t (unsigned int table_index_,
+  hb_ot_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 (nullptr),
 			gdef (*hb_ot_layout_from_face (face)->gdef),
 			var_store (gdef.get_var_store ()),
 			direction (buffer_->props.direction),
@@ -563,135 +562,135 @@ struct hb_apply_context_t :
   {
     _set_glyph_props (glyph_index, class_guess, false, true);
     buffer->output_glyph (glyph_index);
   }
 };
 
 
 
-typedef bool (*intersects_func_t) (hb_set_t *glyphs, const UINT16 &value, const void *data);
-typedef void (*collect_glyphs_func_t) (hb_set_t *glyphs, const UINT16 &value, const void *data);
-typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const UINT16 &value, const void *data);
+typedef bool (*intersects_func_t) (hb_set_t *glyphs, const HBUINT16 &value, const void *data);
+typedef void (*collect_glyphs_func_t) (hb_set_t *glyphs, const HBUINT16 &value, const void *data);
+typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data);
 
 struct ContextClosureFuncs
 {
   intersects_func_t intersects;
 };
 struct ContextCollectGlyphsFuncs
 {
   collect_glyphs_func_t collect;
 };
 struct ContextApplyFuncs
 {
   match_func_t match;
 };
 
 
-static inline bool intersects_glyph (hb_set_t *glyphs, const UINT16 &value, const void *data HB_UNUSED)
+static inline bool intersects_glyph (hb_set_t *glyphs, const HBUINT16 &value, const void *data HB_UNUSED)
 {
   return glyphs->has (value);
 }
-static inline bool intersects_class (hb_set_t *glyphs, const UINT16 &value, const void *data)
+static inline bool intersects_class (hb_set_t *glyphs, const HBUINT16 &value, const void *data)
 {
   const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
   return class_def.intersects_class (glyphs, value);
 }
-static inline bool intersects_coverage (hb_set_t *glyphs, const UINT16 &value, const void *data)
+static inline bool intersects_coverage (hb_set_t *glyphs, const HBUINT16 &value, const void *data)
 {
   const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
   return (data+coverage).intersects (glyphs);
 }
 
 static inline bool intersects_array (hb_closure_context_t *c,
 				     unsigned int count,
-				     const UINT16 values[],
+				     const HBUINT16 values[],
 				     intersects_func_t intersects_func,
 				     const void *intersects_data)
 {
   for (unsigned int i = 0; i < count; i++)
     if (likely (!intersects_func (c->glyphs, values[i], intersects_data)))
       return false;
   return true;
 }
 
 
-static inline void collect_glyph (hb_set_t *glyphs, const UINT16 &value, const void *data HB_UNUSED)
+static inline void collect_glyph (hb_set_t *glyphs, const HBUINT16 &value, const void *data HB_UNUSED)
 {
   glyphs->add (value);
 }
-static inline void collect_class (hb_set_t *glyphs, const UINT16 &value, const void *data)
+static inline void collect_class (hb_set_t *glyphs, const HBUINT16 &value, const void *data)
 {
   const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
   class_def.add_class (glyphs, value);
 }
-static inline void collect_coverage (hb_set_t *glyphs, const UINT16 &value, const void *data)
+static inline void collect_coverage (hb_set_t *glyphs, const HBUINT16 &value, const void *data)
 {
   const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
   (data+coverage).add_coverage (glyphs);
 }
 static inline void collect_array (hb_collect_glyphs_context_t *c HB_UNUSED,
 				  hb_set_t *glyphs,
 				  unsigned int count,
-				  const UINT16 values[],
+				  const HBUINT16 values[],
 				  collect_glyphs_func_t collect_func,
 				  const void *collect_data)
 {
   for (unsigned int i = 0; i < count; i++)
     collect_func (glyphs, values[i], collect_data);
 }
 
 
-static inline bool match_glyph (hb_codepoint_t glyph_id, const UINT16 &value, const void *data HB_UNUSED)
+static inline bool match_glyph (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data HB_UNUSED)
 {
   return glyph_id == value;
 }
-static inline bool match_class (hb_codepoint_t glyph_id, const UINT16 &value, const void *data)
+static inline bool match_class (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data)
 {
   const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
   return class_def.get_class (glyph_id) == value;
 }
-static inline bool match_coverage (hb_codepoint_t glyph_id, const UINT16 &value, const void *data)
+static inline bool match_coverage (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data)
 {
   const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
   return (data+coverage).get_coverage (glyph_id) != NOT_COVERED;
 }
 
 static inline bool would_match_input (hb_would_apply_context_t *c,
 				      unsigned int count, /* Including the first glyph (not matched) */
-				      const UINT16 input[], /* Array of input values--start with second glyph */
+				      const HBUINT16 input[], /* Array of input values--start with second glyph */
 				      match_func_t match_func,
 				      const void *match_data)
 {
   if (count != c->len)
     return false;
 
   for (unsigned int i = 1; i < count; i++)
     if (likely (!match_func (c->glyphs[i], input[i - 1], match_data)))
       return false;
 
   return true;
 }
-static inline bool match_input (hb_apply_context_t *c,
+static inline bool match_input (hb_ot_apply_context_t *c,
 				unsigned int count, /* Including the first glyph (not matched) */
-				const UINT16 input[], /* Array of input values--start with second glyph */
+				const HBUINT16 input[], /* Array of input values--start with second glyph */
 				match_func_t match_func,
 				const void *match_data,
 				unsigned int *end_offset,
 				unsigned int match_positions[HB_MAX_CONTEXT_LENGTH],
 				bool *p_is_mark_ligature = nullptr,
 				unsigned int *p_total_component_count = nullptr)
 {
   TRACE_APPLY (nullptr);
 
   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;
+  hb_ot_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);
 
   /*
    * This is perhaps the trickiest part of OpenType...  Remarks:
    *
    * - If all components of the ligature were marks, we call this a mark ligature.
    *
@@ -758,17 +757,17 @@ static inline bool match_input (hb_apply
 	    {
 	      j--;
 	      found = true;
 	      break;
 	    }
 	    j--;
 	  }
 
-	  if (found && skippy_iter.may_skip (c, out[j]) == hb_apply_context_t::matcher_t::SKIP_YES)
+	  if (found && skippy_iter.may_skip (out[j]) == hb_ot_apply_context_t::matcher_t::SKIP_YES)
 	    ligbase = LIGBASE_MAY_SKIP;
 	  else
 	    ligbase = LIGBASE_MAY_NOT_SKIP;
 	}
 
         if (ligbase == LIGBASE_MAY_NOT_SKIP)
 	  return_trace (false);
       }
@@ -791,17 +790,17 @@ static inline bool match_input (hb_apply
   if (p_is_mark_ligature)
     *p_is_mark_ligature = is_mark_ligature;
 
   if (p_total_component_count)
     *p_total_component_count = total_component_count;
 
   return_trace (true);
 }
-static inline bool ligate_input (hb_apply_context_t *c,
+static inline bool ligate_input (hb_ot_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 (nullptr);
@@ -889,49 +888,49 @@ static inline bool ligate_input (hb_appl
 	_hb_glyph_info_set_lig_props_for_mark (&buffer->info[i], lig_id, new_lig_comp);
       } else
 	break;
     }
   }
   return_trace (true);
 }
 
-static inline bool match_backtrack (hb_apply_context_t *c,
+static inline bool match_backtrack (hb_ot_apply_context_t *c,
 				    unsigned int count,
-				    const UINT16 backtrack[],
+				    const HBUINT16 backtrack[],
 				    match_func_t match_func,
 				    const void *match_data,
 				    unsigned int *match_start)
 {
   TRACE_APPLY (nullptr);
 
-  hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context;
+  hb_ot_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);
 
   *match_start = skippy_iter.idx;
 
   return_trace (true);
 }
 
-static inline bool match_lookahead (hb_apply_context_t *c,
+static inline bool match_lookahead (hb_ot_apply_context_t *c,
 				    unsigned int count,
-				    const UINT16 lookahead[],
+				    const HBUINT16 lookahead[],
 				    match_func_t match_func,
 				    const void *match_data,
 				    unsigned int offset,
 				    unsigned int *end_index)
 {
   TRACE_APPLY (nullptr);
 
-  hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context;
+  hb_ot_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);
 
   *end_index = skippy_iter.idx + 1;
@@ -944,35 +943,35 @@ static inline bool match_lookahead (hb_a
 struct LookupRecord
 {
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this));
   }
 
-  UINT16	sequenceIndex;		/* Index into current glyph
+  HBUINT16	sequenceIndex;		/* Index into current glyph
 					 * sequence--first glyph = 0 */
-  UINT16	lookupListIndex;	/* Lookup to apply to that
+  HBUINT16	lookupListIndex;	/* Lookup to apply to that
 					 * position--zero--based */
   public:
   DEFINE_SIZE_STATIC (4);
 };
 
 
 template <typename context_t>
 static inline void recurse_lookups (context_t *c,
 				    unsigned int lookupCount,
 				    const LookupRecord lookupRecord[] /* Array of LookupRecords--in design order */)
 {
   for (unsigned int i = 0; i < lookupCount; i++)
     c->recurse (lookupRecord[i].lookupListIndex);
 }
 
-static inline bool apply_lookup (hb_apply_context_t *c,
+static inline bool apply_lookup (hb_ot_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 (nullptr);
 
@@ -1107,56 +1106,56 @@ struct ContextCollectGlyphsLookupContext
 struct ContextApplyLookupContext
 {
   ContextApplyFuncs funcs;
   const void *match_data;
 };
 
 static inline void context_closure_lookup (hb_closure_context_t *c,
 					   unsigned int inputCount, /* Including the first glyph (not matched) */
-					   const UINT16 input[], /* Array of input values--start with second glyph */
+					   const HBUINT16 input[], /* Array of input values--start with second glyph */
 					   unsigned int lookupCount,
 					   const LookupRecord lookupRecord[],
 					   ContextClosureLookupContext &lookup_context)
 {
   if (intersects_array (c,
 			inputCount ? inputCount - 1 : 0, input,
 			lookup_context.funcs.intersects, lookup_context.intersects_data))
     recurse_lookups (c,
 		     lookupCount, lookupRecord);
 }
 
 static inline void context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c,
 						  unsigned int inputCount, /* Including the first glyph (not matched) */
-						  const UINT16 input[], /* Array of input values--start with second glyph */
+						  const HBUINT16 input[], /* Array of input values--start with second glyph */
 						  unsigned int lookupCount,
 						  const LookupRecord lookupRecord[],
 						  ContextCollectGlyphsLookupContext &lookup_context)
 {
   collect_array (c, c->input,
 		 inputCount ? inputCount - 1 : 0, input,
 		 lookup_context.funcs.collect, lookup_context.collect_data);
   recurse_lookups (c,
 		   lookupCount, lookupRecord);
 }
 
 static inline bool context_would_apply_lookup (hb_would_apply_context_t *c,
 					       unsigned int inputCount, /* Including the first glyph (not matched) */
-					       const UINT16 input[], /* Array of input values--start with second glyph */
+					       const HBUINT16 input[], /* Array of input values--start with second glyph */
 					       unsigned int lookupCount HB_UNUSED,
 					       const LookupRecord lookupRecord[] HB_UNUSED,
 					       ContextApplyLookupContext &lookup_context)
 {
   return would_match_input (c,
 			    inputCount, input,
 			    lookup_context.funcs.match, lookup_context.match_data);
 }
-static inline bool context_apply_lookup (hb_apply_context_t *c,
+static inline bool context_apply_lookup (hb_ot_apply_context_t *c,
 					 unsigned int inputCount, /* Including the first glyph (not matched) */
-					 const UINT16 input[], /* Array of input values--start with second glyph */
+					 const HBUINT16 input[], /* Array of input values--start with second glyph */
 					 unsigned int lookupCount,
 					 const LookupRecord lookupRecord[],
 					 ContextApplyLookupContext &lookup_context)
 {
   unsigned int match_length = 0;
   unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
   return match_input (c,
 		      inputCount, input,
@@ -1193,17 +1192,17 @@ struct Rule
 
   inline bool would_apply (hb_would_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
   {
     TRACE_WOULD_APPLY (this);
     const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (inputZ, inputZ[0].static_size * (inputCount ? inputCount - 1 : 0));
     return_trace (context_would_apply_lookup (c, inputCount, inputZ, lookupCount, lookupRecord, lookup_context));
   }
 
-  inline bool apply (hb_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
+  inline bool apply (hb_ot_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
   {
     TRACE_APPLY (this);
     const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (inputZ, inputZ[0].static_size * (inputCount ? inputCount - 1 : 0));
     return_trace (context_apply_lookup (c, inputCount, inputZ, lookupCount, lookupRecord, lookup_context));
   }
 
   public:
   inline bool sanitize (hb_sanitize_context_t *c) const
@@ -1212,21 +1211,21 @@ struct Rule
     return_trace (inputCount.sanitize (c) &&
 		  lookupCount.sanitize (c) &&
 		  c->check_range (inputZ,
 				  inputZ[0].static_size * inputCount +
 				  lookupRecordX[0].static_size * lookupCount));
   }
 
   protected:
-  UINT16	inputCount;		/* Total number of glyphs in input
+  HBUINT16	inputCount;		/* Total number of glyphs in input
 					 * glyph sequence--includes the first
 					 * glyph */
-  UINT16	lookupCount;		/* Number of LookupRecords */
-  UINT16	inputZ[VAR];		/* Array of match inputs--start with
+  HBUINT16	lookupCount;		/* Number of LookupRecords */
+  HBUINT16	inputZ[VAR];		/* Array of match inputs--start with
 					 * second glyph */
   LookupRecord	lookupRecordX[VAR];	/* Array of LookupRecords--in
 					 * design order */
   public:
   DEFINE_SIZE_ARRAY2 (4, inputZ, lookupRecordX);
 };
 
 struct RuleSet
@@ -1254,17 +1253,17 @@ struct RuleSet
     for (unsigned int i = 0; i < num_rules; i++)
     {
       if ((this+rule[i]).would_apply (c, lookup_context))
         return_trace (true);
     }
     return_trace (false);
   }
 
-  inline bool apply (hb_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
+  inline bool apply (hb_ot_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
   {
     TRACE_APPLY (this);
     unsigned int num_rules = rule.len;
     for (unsigned int i = 0; i < num_rules; i++)
     {
       if ((this+rule[i]).apply (c, lookup_context))
         return_trace (true);
     }
@@ -1334,17 +1333,17 @@ struct ContextFormat1
     return_trace (rule_set.would_apply (c, lookup_context));
   }
 
   inline const Coverage &get_coverage (void) const
   {
     return this+coverage;
   }
 
-  inline bool apply (hb_apply_context_t *c) const
+  inline bool apply (hb_ot_apply_context_t *c) const
   {
     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 = {
@@ -1356,17 +1355,17 @@ struct ContextFormat1
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
   }
 
   protected:
-  UINT16	format;			/* Format identifier--format = 1 */
+  HBUINT16	format;			/* Format identifier--format = 1 */
   OffsetTo<Coverage>
 		coverage;		/* Offset to Coverage table--from
 					 * beginning of table */
   OffsetArrayOf<RuleSet>
 		ruleSet;		/* Array of RuleSet tables
 					 * ordered by Coverage Index */
   public:
   DEFINE_SIZE_ARRAY (6, ruleSet);
@@ -1426,17 +1425,17 @@ struct ContextFormat2
     return_trace (rule_set.would_apply (c, lookup_context));
   }
 
   inline const Coverage &get_coverage (void) const
   {
     return this+coverage;
   }
 
-  inline bool apply (hb_apply_context_t *c) const
+  inline bool apply (hb_ot_apply_context_t *c) const
   {
     TRACE_APPLY (this);
     unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
     if (likely (index == NOT_COVERED)) return_trace (false);
 
     const ClassDef &class_def = this+classDef;
     index = class_def.get_class (c->buffer->cur().codepoint);
     const RuleSet &rule_set = this+ruleSet[index];
@@ -1449,17 +1448,17 @@ struct ContextFormat2
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (coverage.sanitize (c, this) && classDef.sanitize (c, this) && ruleSet.sanitize (c, this));
   }
 
   protected:
-  UINT16	format;			/* Format identifier--format = 2 */
+  HBUINT16	format;			/* Format identifier--format = 2 */
   OffsetTo<Coverage>
 		coverage;		/* Offset to Coverage table--from
 					 * beginning of table */
   OffsetTo<ClassDef>
 		classDef;		/* Offset to glyph ClassDef table--from
 					 * beginning of table */
   OffsetArrayOf<RuleSet>
 		ruleSet;		/* Array of RuleSet tables
@@ -1478,87 +1477,87 @@ struct ContextFormat3
       return;
 
     const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ, coverageZ[0].static_size * glyphCount);
     struct ContextClosureLookupContext lookup_context = {
       {intersects_coverage},
       this
     };
     context_closure_lookup (c,
-			    glyphCount, (const UINT16 *) (coverageZ + 1),
+			    glyphCount, (const HBUINT16 *) (coverageZ + 1),
 			    lookupCount, lookupRecord,
 			    lookup_context);
   }
 
   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
     TRACE_COLLECT_GLYPHS (this);
     (this+coverageZ[0]).add_coverage (c->input);
 
     const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ, coverageZ[0].static_size * glyphCount);
     struct ContextCollectGlyphsLookupContext lookup_context = {
       {collect_coverage},
       this
     };
 
     context_collect_glyphs_lookup (c,
-				   glyphCount, (const UINT16 *) (coverageZ + 1),
+				   glyphCount, (const HBUINT16 *) (coverageZ + 1),
 				   lookupCount, lookupRecord,
 				   lookup_context);
   }
 
   inline bool would_apply (hb_would_apply_context_t *c) const
   {
     TRACE_WOULD_APPLY (this);
 
     const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ, coverageZ[0].static_size * glyphCount);
     struct ContextApplyLookupContext lookup_context = {
       {match_coverage},
       this
     };
-    return_trace (context_would_apply_lookup (c, glyphCount, (const UINT16 *) (coverageZ + 1), lookupCount, lookupRecord, lookup_context));
+    return_trace (context_would_apply_lookup (c, glyphCount, (const HBUINT16 *) (coverageZ + 1), lookupCount, lookupRecord, lookup_context));
   }
 
   inline const Coverage &get_coverage (void) const
   {
     return this+coverageZ[0];
   }
 
-  inline bool apply (hb_apply_context_t *c) const
+  inline bool apply (hb_ot_apply_context_t *c) const
   {
     TRACE_APPLY (this);
     unsigned int index = (this+coverageZ[0]).get_coverage (c->buffer->cur().codepoint);
     if (likely (index == NOT_COVERED)) return_trace (false);
 
     const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ, coverageZ[0].static_size * glyphCount);
     struct ContextApplyLookupContext lookup_context = {
       {match_coverage},
       this
     };
-    return_trace (context_apply_lookup (c, glyphCount, (const UINT16 *) (coverageZ + 1), lookupCount, lookupRecord, lookup_context));
+    return_trace (context_apply_lookup (c, glyphCount, (const HBUINT16 *) (coverageZ + 1), lookupCount, lookupRecord, lookup_context));
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     if (!c->check_struct (this)) return_trace (false);
     unsigned int count = glyphCount;
     if (!count) return_trace (false); /* We want to access coverageZ[0] freely. */
     if (!c->check_array (coverageZ, coverageZ[0].static_size, count)) return_trace (false);
     for (unsigned int i = 0; i < count; i++)
       if (!coverageZ[i].sanitize (c, this)) return_trace (false);
     const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ, coverageZ[0].static_size * count);
     return_trace (c->check_array (lookupRecord, lookupRecord[0].static_size, lookupCount));
   }
 
   protected:
-  UINT16	format;			/* Format identifier--format = 3 */
-  UINT16	glyphCount;		/* Number of glyphs in the input glyph
+  HBUINT16	format;			/* Format identifier--format = 3 */
+  HBUINT16	glyphCount;		/* Number of glyphs in the input glyph
 					 * sequence */
-  UINT16	lookupCount;		/* Number of LookupRecords */
+  HBUINT16	lookupCount;		/* Number of LookupRecords */
   OffsetTo<Coverage>
 		coverageZ[VAR];		/* Array of offsets to Coverage
 					 * table in glyph sequence order */
   LookupRecord	lookupRecordX[VAR];	/* Array of LookupRecords--in
 					 * design order */
   public:
   DEFINE_SIZE_ARRAY2 (6, coverageZ, lookupRecordX);
 };
@@ -1575,17 +1574,17 @@ struct Context
     case 2: return_trace (c->dispatch (u.format2));
     case 3: return_trace (c->dispatch (u.format3));
     default:return_trace (c->default_return_value ());
     }
   }
 
   protected:
   union {
-  UINT16		format;		/* Format identifier */
+  HBUINT16		format;		/* Format identifier */
   ContextFormat1	format1;
   ContextFormat2	format2;
   ContextFormat3	format3;
   } u;
 };
 
 
 /* Chaining Contextual lookups */
@@ -1605,21 +1604,21 @@ struct ChainContextCollectGlyphsLookupCo
 struct ChainContextApplyLookupContext
 {
   ContextApplyFuncs funcs;
   const void *match_data[3];
 };
 
 static inline void chain_context_closure_lookup (hb_closure_context_t *c,
 						 unsigned int backtrackCount,
-						 const UINT16 backtrack[],
+						 const HBUINT16 backtrack[],
 						 unsigned int inputCount, /* Including the first glyph (not matched) */
-						 const UINT16 input[], /* Array of input values--start with second glyph */
+						 const HBUINT16 input[], /* Array of input values--start with second glyph */
 						 unsigned int lookaheadCount,
-						 const UINT16 lookahead[],
+						 const HBUINT16 lookahead[],
 						 unsigned int lookupCount,
 						 const LookupRecord lookupRecord[],
 						 ChainContextClosureLookupContext &lookup_context)
 {
   if (intersects_array (c,
 			backtrackCount, backtrack,
 			lookup_context.funcs.intersects, lookup_context.intersects_data[0])
    && intersects_array (c,
@@ -1629,21 +1628,21 @@ static inline void chain_context_closure
 		       lookaheadCount, lookahead,
 		       lookup_context.funcs.intersects, lookup_context.intersects_data[2]))
     recurse_lookups (c,
 		     lookupCount, lookupRecord);
 }
 
 static inline void chain_context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c,
 						        unsigned int backtrackCount,
-						        const UINT16 backtrack[],
+						        const HBUINT16 backtrack[],
 						        unsigned int inputCount, /* Including the first glyph (not matched) */
-						        const UINT16 input[], /* Array of input values--start with second glyph */
+						        const HBUINT16 input[], /* Array of input values--start with second glyph */
 						        unsigned int lookaheadCount,
-						        const UINT16 lookahead[],
+						        const HBUINT16 lookahead[],
 						        unsigned int lookupCount,
 						        const LookupRecord lookupRecord[],
 						        ChainContextCollectGlyphsLookupContext &lookup_context)
 {
   collect_array (c, c->before,
 		 backtrackCount, backtrack,
 		 lookup_context.funcs.collect, lookup_context.collect_data[0]);
   collect_array (c, c->input,
@@ -1653,38 +1652,38 @@ static inline void chain_context_collect
 		 lookaheadCount, lookahead,
 		 lookup_context.funcs.collect, lookup_context.collect_data[2]);
   recurse_lookups (c,
 		   lookupCount, lookupRecord);
 }
 
 static inline bool chain_context_would_apply_lookup (hb_would_apply_context_t *c,
 						     unsigned int backtrackCount,
-						     const UINT16 backtrack[] HB_UNUSED,
+						     const HBUINT16 backtrack[] HB_UNUSED,
 						     unsigned int inputCount, /* Including the first glyph (not matched) */
-						     const UINT16 input[], /* Array of input values--start with second glyph */
+						     const HBUINT16 input[], /* Array of input values--start with second glyph */
 						     unsigned int lookaheadCount,
-						     const UINT16 lookahead[] HB_UNUSED,
+						     const HBUINT16 lookahead[] HB_UNUSED,
 						     unsigned int lookupCount HB_UNUSED,
 						     const LookupRecord lookupRecord[] HB_UNUSED,
 						     ChainContextApplyLookupContext &lookup_context)
 {
   return (c->zero_context ? !backtrackCount && !lookaheadCount : true)
       && would_match_input (c,
 			    inputCount, input,
 			    lookup_context.funcs.match, lookup_context.match_data[1]);
 }
 
-static inline bool chain_context_apply_lookup (hb_apply_context_t *c,
+static inline bool chain_context_apply_lookup (hb_ot_apply_context_t *c,
 					       unsigned int backtrackCount,
-					       const UINT16 backtrack[],
+					       const HBUINT16 backtrack[],
 					       unsigned int inputCount, /* Including the first glyph (not matched) */
-					       const UINT16 input[], /* Array of input values--start with second glyph */
+					       const HBUINT16 input[], /* Array of input values--start with second glyph */
 					       unsigned int lookaheadCount,
-					       const UINT16 lookahead[],
+					       const HBUINT16 lookahead[],
 					       unsigned int lookupCount,
 					       const LookupRecord lookupRecord[],
 					       ChainContextApplyLookupContext &lookup_context)
 {
   unsigned int start_index = 0, match_length = 0, end_index = 0;
   unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
   return match_input (c,
 		      inputCount, input,
@@ -1705,88 +1704,88 @@ static inline bool chain_context_apply_l
 		       match_length));
 }
 
 struct ChainRule
 {
   inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
   {
     TRACE_CLOSURE (this);
-    const HeadlessArrayOf<UINT16> &input = StructAfter<HeadlessArrayOf<UINT16> > (backtrack);
-    const ArrayOf<UINT16> &lookahead = StructAfter<ArrayOf<UINT16> > (input);
+    const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
+    const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
     chain_context_closure_lookup (c,
 				  backtrack.len, backtrack.array,
 				  input.len, input.array,
 				  lookahead.len, lookahead.array,
 				  lookup.len, lookup.array,
 				  lookup_context);
   }
 
   inline void collect_glyphs (hb_collect_glyphs_context_t *c, ChainContextCollectGlyphsLookupContext &lookup_context) const
   {
     TRACE_COLLECT_GLYPHS (this);
-    const HeadlessArrayOf<UINT16> &input = StructAfter<HeadlessArrayOf<UINT16> > (backtrack);
-    const ArrayOf<UINT16> &lookahead = StructAfter<ArrayOf<UINT16> > (input);
+    const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
+    const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
     chain_context_collect_glyphs_lookup (c,
 					 backtrack.len, backtrack.array,
 					 input.len, input.array,
 					 lookahead.len, lookahead.array,
 					 lookup.len, lookup.array,
 					 lookup_context);
   }
 
   inline bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
   {
     TRACE_WOULD_APPLY (this);
-    const HeadlessArrayOf<UINT16> &input = StructAfter<HeadlessArrayOf<UINT16> > (backtrack);
-    const ArrayOf<UINT16> &lookahead = StructAfter<ArrayOf<UINT16> > (input);
+    const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
+    const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
     return_trace (chain_context_would_apply_lookup (c,
 						    backtrack.len, backtrack.array,
 						    input.len, input.array,
 						    lookahead.len, lookahead.array, lookup.len,
 						    lookup.array, lookup_context));
   }
 
-  inline bool apply (hb_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
+  inline bool apply (hb_ot_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
   {
     TRACE_APPLY (this);
-    const HeadlessArrayOf<UINT16> &input = StructAfter<HeadlessArrayOf<UINT16> > (backtrack);
-    const ArrayOf<UINT16> &lookahead = StructAfter<ArrayOf<UINT16> > (input);
+    const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
+    const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
     return_trace (chain_context_apply_lookup (c,
 					      backtrack.len, backtrack.array,
 					      input.len, input.array,
 					      lookahead.len, lookahead.array, lookup.len,
 					      lookup.array, lookup_context));
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     if (!backtrack.sanitize (c)) return_trace (false);
-    const HeadlessArrayOf<UINT16> &input = StructAfter<HeadlessArrayOf<UINT16> > (backtrack);
+    const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
     if (!input.sanitize (c)) return_trace (false);
-    const ArrayOf<UINT16> &lookahead = StructAfter<ArrayOf<UINT16> > (input);
+    const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
     if (!lookahead.sanitize (c)) return_trace (false);
     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
     return_trace (lookup.sanitize (c));
   }
 
   protected:
-  ArrayOf<UINT16>
+  ArrayOf<HBUINT16>
 		backtrack;		/* Array of backtracking values
 					 * (to be matched before the input
 					 * sequence) */
-  HeadlessArrayOf<UINT16>
+  HeadlessArrayOf<HBUINT16>
 		inputX;			/* Array of input values (start with
 					 * second glyph) */
-  ArrayOf<UINT16>
+  ArrayOf<HBUINT16>
 		lookaheadX;		/* Array of lookahead values's (to be
 					 * matched after the input sequence) */
   ArrayOf<LookupRecord>
 		lookupX;		/* Array of LookupRecords--in
 					 * design order) */
   public:
   DEFINE_SIZE_MIN (8);
 };
@@ -1815,17 +1814,17 @@ struct ChainRuleSet
     unsigned int num_rules = rule.len;
     for (unsigned int i = 0; i < num_rules; i++)
       if ((this+rule[i]).would_apply (c, lookup_context))
         return_trace (true);
 
     return_trace (false);
   }
 
-  inline bool apply (hb_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
+  inline bool apply (hb_ot_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
   {
     TRACE_APPLY (this);
     unsigned int num_rules = rule.len;
     for (unsigned int i = 0; i < num_rules; i++)
       if ((this+rule[i]).apply (c, lookup_context))
         return_trace (true);
 
     return_trace (false);
@@ -1892,17 +1891,17 @@ struct ChainContextFormat1
     return_trace (rule_set.would_apply (c, lookup_context));
   }
 
   inline const Coverage &get_coverage (void) const
   {
     return this+coverage;
   }
 
-  inline bool apply (hb_apply_context_t *c) const
+  inline bool apply (hb_ot_apply_context_t *c) const
   {
     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},
@@ -1913,17 +1912,17 @@ struct ChainContextFormat1
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
   }
 
   protected:
-  UINT16	format;			/* Format identifier--format = 1 */
+  HBUINT16	format;			/* Format identifier--format = 1 */
   OffsetTo<Coverage>
 		coverage;		/* Offset to Coverage table--from
 					 * beginning of table */
   OffsetArrayOf<ChainRuleSet>
 		ruleSet;		/* Array of ChainRuleSet tables
 					 * ordered by Coverage Index */
   public:
   DEFINE_SIZE_ARRAY (6, ruleSet);
@@ -1996,17 +1995,17 @@ struct ChainContextFormat2
     return_trace (rule_set.would_apply (c, lookup_context));
   }
 
   inline const Coverage &get_coverage (void) const
   {
     return this+coverage;
   }
 
-  inline bool apply (hb_apply_context_t *c) const
+  inline bool apply (hb_ot_apply_context_t *c) const
   {
     TRACE_APPLY (this);
     unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
     if (likely (index == NOT_COVERED)) return_trace (false);
 
     const ClassDef &backtrack_class_def = this+backtrackClassDef;
     const ClassDef &input_class_def = this+inputClassDef;
     const ClassDef &lookahead_class_def = this+lookaheadClassDef;
@@ -2028,17 +2027,17 @@ struct ChainContextFormat2
     return_trace (coverage.sanitize (c, this) &&
 		  backtrackClassDef.sanitize (c, this) &&
 		  inputClassDef.sanitize (c, this) &&
 		  lookaheadClassDef.sanitize (c, this) &&
 		  ruleSet.sanitize (c, this));
   }
 
   protected:
-  UINT16	format;			/* Format identifier--format = 2 */
+  HBUINT16	format;			/* Format identifier--format = 2 */
   OffsetTo<Coverage>
 		coverage;		/* Offset to Coverage table--from
 					 * beginning of table */
   OffsetTo<ClassDef>
 		backtrackClassDef;	/* Offset to glyph ClassDef table
 					 * containing backtrack sequence
 					 * data--from beginning of table */
   OffsetTo<ClassDef>
@@ -2068,19 +2067,19 @@ struct ChainContextFormat3
 
     const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
     struct ChainContextClosureLookupContext lookup_context = {
       {intersects_coverage},
       {this, this, this}
     };
     chain_context_closure_lookup (c,
-				  backtrack.len, (const UINT16 *) backtrack.array,
-				  input.len, (const UINT16 *) input.array + 1,
-				  lookahead.len, (const UINT16 *) lookahead.array,
+				  backtrack.len, (const HBUINT16 *) backtrack.array,
+				  input.len, (const HBUINT16 *) input.array + 1,
+				  lookahead.len, (const HBUINT16 *) lookahead.array,
 				  lookup.len, lookup.array,
 				  lookup_context);
   }
 
   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
     TRACE_COLLECT_GLYPHS (this);
     const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
@@ -2089,65 +2088,65 @@ struct ChainContextFormat3
 
     const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
     struct ChainContextCollectGlyphsLookupContext lookup_context = {
       {collect_coverage},
       {this, this, this}
     };
     chain_context_collect_glyphs_lookup (c,
-					 backtrack.len, (const UINT16 *) backtrack.array,
-					 input.len, (const UINT16 *) input.array + 1,
-					 lookahead.len, (const UINT16 *) lookahead.array,
+					 backtrack.len, (const HBUINT16 *) backtrack.array,
+					 input.len, (const HBUINT16 *) input.array + 1,
+					 lookahead.len, (const HBUINT16 *) lookahead.array,
 					 lookup.len, lookup.array,
 					 lookup_context);
   }
 
   inline bool would_apply (hb_would_apply_context_t *c) const
   {
     TRACE_WOULD_APPLY (this);
 
     const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
     const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
     struct ChainContextApplyLookupContext lookup_context = {
       {match_coverage},
       {this, this, this}
     };
     return_trace (chain_context_would_apply_lookup (c,
-						    backtrack.len, (const UINT16 *) backtrack.array,
-						    input.len, (const UINT16 *) input.array + 1,
-						    lookahead.len, (const UINT16 *) lookahead.array,
+						    backtrack.len, (const HBUINT16 *) backtrack.array,
+						    input.len, (const HBUINT16 *) input.array + 1,
+						    lookahead.len, (const HBUINT16 *) lookahead.array,
 						    lookup.len, lookup.array, lookup_context));
   }
 
   inline const Coverage &get_coverage (void) const
   {
     const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
     return this+input[0];
   }
 
-  inline bool apply (hb_apply_context_t *c) const
+  inline bool apply (hb_ot_apply_context_t *c) const
   {
     TRACE_APPLY (this);
     const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
 
     unsigned int index = (this+input[0]).get_coverage (c->buffer->cur().codepoint);
     if (likely (index == NOT_COVERED)) return_trace (false);
 
     const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
     struct ChainContextApplyLookupContext lookup_context = {
       {match_coverage},
       {this, this, this}
     };
     return_trace (chain_context_apply_lookup (c,
-					      backtrack.len, (const UINT16 *) backtrack.array,
-					      input.len, (const UINT16 *) input.array + 1,
-					      lookahead.len, (const UINT16 *) lookahead.array,
+					      backtrack.len, (const HBUINT16 *) backtrack.array,
+					      input.len, (const HBUINT16 *) input.array + 1,
+					      lookahead.len, (const HBUINT16 *) lookahead.array,
 					      lookup.len, lookup.array, lookup_context));
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     if (!backtrack.sanitize (c, this)) return_trace (false);
     const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
@@ -2155,17 +2154,17 @@ struct ChainContextFormat3
     if (!input.len) return_trace (false); /* To be consistent with Context. */
     const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
     if (!lookahead.sanitize (c, this)) return_trace (false);
     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
     return_trace (lookup.sanitize (c));
   }
 
   protected:
-  UINT16	format;			/* Format identifier--format = 3 */
+  HBUINT16	format;			/* Format identifier--format = 3 */
   OffsetArrayOf<Coverage>
 		backtrack;		/* Array of coverage tables
 					 * in backtracking sequence, in  glyph
 					 * sequence order */
   OffsetArrayOf<Coverage>
 		inputX		;	/* Array of coverage
 					 * tables in input sequence, in glyph
 					 * sequence order */
@@ -2192,17 +2191,17 @@ struct ChainContext
     case 2: return_trace (c->dispatch (u.format2));
     case 3: return_trace (c->dispatch (u.format3));
     default:return_trace (c->default_return_value ());
     }
   }
 
   protected:
   union {
-  UINT16		format;	/* Format identifier */
+  HBUINT16		format;	/* Format identifier */
   ChainContextFormat1	format1;
   ChainContextFormat2	format2;
   ChainContextFormat3	format3;
   } u;
 };
 
 
 template <typename T>
@@ -2225,25 +2224,27 @@ struct ExtensionFormat1
     if (unlikely (!c->may_dispatch (this, this))) return_trace (c->no_dispatch_return_value ());
     return_trace (get_subtable<typename T::LookupSubTable> ().dispatch (c, get_type ()));
   }
 
   /* This is called from may_dispatch() above with hb_sanitize_context_t. */
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (c->check_struct (this) && extensionOffset != 0);
+    return_trace (c->check_struct (this) &&
+		  extensionOffset != 0 &&
+		  extensionLookupType != T::LookupSubTable::Extension);
   }
 
   protected:
-  UINT16	format;			/* Format identifier. Set to 1. */
-  UINT16	extensionLookupType;	/* Lookup type of subtable referenced
+  HBUINT16	format;			/* Format identifier. Set to 1. */
+  HBUINT16	extensionLookupType;	/* Lookup type of subtable referenced
 					 * by ExtensionOffset (i.e. the
 					 * extension subtable). */
-  UINT32		extensionOffset;	/* Offset to the extension subtable,
+  HBUINT32	extensionOffset;	/* Offset to the extension subtable,
 					 * of lookup type subtable. */
   public:
   DEFINE_SIZE_STATIC (8);
 };
 
 template <typename T>
 struct Extension
 {
@@ -2271,17 +2272,17 @@ struct Extension
     switch (u.format) {
     case 1: return_trace (u.format1.dispatch (c));
     default:return_trace (c->default_return_value ());
     }
   }
 
   protected:
   union {
-  UINT16		format;		/* Format identifier */
+  HBUINT16		format;		/* Format identifier */
   ExtensionFormat1<T>	format1;
   } u;
 };
 
 
 /*
  * GSUB/GPOS Common
  */
--- a/gfx/harfbuzz/src/hb-ot-layout-private.hh
+++ b/gfx/harfbuzz/src/hb-ot-layout-private.hh
@@ -85,22 +85,22 @@ hb_ot_layout_lookup_would_substitute_fas
 HB_INTERNAL void
 hb_ot_layout_substitute_start (hb_font_t    *font,
 			       hb_buffer_t  *buffer);
 
 
 struct hb_ot_layout_lookup_accelerator_t;
 
 namespace OT {
-  struct hb_apply_context_t;
+  struct hb_ot_apply_context_t;
   struct SubstLookup;
 }
 
 HB_INTERNAL void
-hb_ot_layout_substitute_lookup (OT::hb_apply_context_t *c,
+hb_ot_layout_substitute_lookup (OT::hb_ot_apply_context_t *c,
 				const OT::SubstLookup &lookup,
 				const hb_ot_layout_lookup_accelerator_t &accel);
 
 
 /* Should be called before all the position_lookup's are done. */
 HB_INTERNAL void
 hb_ot_layout_position_start (hb_font_t    *font,
 			     hb_buffer_t  *buffer);
@@ -125,16 +125,20 @@ namespace OT {
   struct GDEF;
   struct GSUB;
   struct GPOS;
   struct MATH;
   struct fvar;
   struct avar;
 }
 
+namespace AAT {
+  struct morx;
+}
+
 struct hb_ot_layout_lookup_accelerator_t
 {
   template <typename TLookup>
   inline void init (const TLookup &lookup)
   {
     digest.init ();
     lookup.add_coverage (&digest);
   }
@@ -160,16 +164,17 @@ struct hb_ot_layout_t
   const struct OT::GDEF *gdef;
   const struct OT::GSUB *gsub;
   const struct OT::GPOS *gpos;
 
   /* TODO Move the following out of this struct. */
   OT::hb_lazy_table_loader_t<struct OT::MATH> math;
   OT::hb_lazy_table_loader_t<struct OT::fvar> fvar;
   OT::hb_lazy_table_loader_t<struct OT::avar> avar;
+  OT::hb_lazy_table_loader_t<struct AAT::morx> morx;
 
   unsigned int gsub_lookup_count;
   unsigned int gpos_lookup_count;
 
   hb_ot_layout_lookup_accelerator_t *gsub_accels;
   hb_ot_layout_lookup_accelerator_t *gpos_accels;
 };
 
@@ -275,17 +280,21 @@ static inline void
        * Fixes:
        * https://github.com/harfbuzz/harfbuzz/issues/234 */
       else if (unlikely (hb_in_range (u, 0x180Bu, 0x180Du))) props |= UPROPS_MASK_HIDDEN;
       /* TAG characters need similar treatment. Fixes:
        * https://github.com/harfbuzz/harfbuzz/issues/463 */
       else if (unlikely (hb_in_range (u, 0xE0020u, 0xE007Fu))) props |= UPROPS_MASK_HIDDEN;
       /* COMBINING GRAPHEME JOINER should not be skipped; at least some times.
        * https://github.com/harfbuzz/harfbuzz/issues/554 */
-      else if (unlikely (u == 0x034Fu)) props |= UPROPS_MASK_HIDDEN;
+      else if (unlikely (u == 0x034Fu))
+      {
+	buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_CGJ;
+	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
@@ -383,16 +392,21 @@ static inline hb_bool_t
 }
 static inline hb_bool_t
 _hb_glyph_info_is_default_ignorable_and_not_hidden (const hb_glyph_info_t *info)
 {
   return ((info->unicode_props() & (UPROPS_MASK_IGNORABLE|UPROPS_MASK_HIDDEN))
 	  == UPROPS_MASK_IGNORABLE) &&
 	 !_hb_glyph_info_ligated (info);
 }
+static inline void
+_hb_glyph_info_unhide (hb_glyph_info_t *info)
+{
+  info->unicode_props() &= ~ UPROPS_MASK_HIDDEN;
+}
 
 static inline bool
 _hb_glyph_info_is_unicode_format (const hb_glyph_info_t *info)
 {
   return _hb_glyph_info_get_general_category (info) ==
 	 HB_UNICODE_GENERAL_CATEGORY_FORMAT;
 }
 static inline hb_bool_t
--- a/gfx/harfbuzz/src/hb-ot-layout.cc
+++ b/gfx/harfbuzz/src/hb-ot-layout.cc
@@ -45,28 +45,29 @@ const void * const OT::_hb_NullPool[HB_N
 
 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 nullptr;
 
-  layout->gdef_blob = OT::Sanitizer<OT::GDEF>::sanitize (face->reference_table (HB_OT_TAG_GDEF));
+  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_blob = OT::Sanitizer<OT::GSUB>().sanitize (face->reference_table (HB_OT_TAG_GSUB));
   layout->gsub = OT::Sanitizer<OT::GSUB>::lock_instance (layout->gsub_blob);
 
-  layout->gpos_blob = OT::Sanitizer<OT::GPOS>::sanitize (face->reference_table (HB_OT_TAG_GPOS));
+  layout->gpos_blob = OT::Sanitizer<OT::GPOS>().sanitize (face->reference_table (HB_OT_TAG_GPOS));
   layout->gpos = OT::Sanitizer<OT::GPOS>::lock_instance (layout->gpos_blob);
 
   layout->math.init (face);
   layout->fvar.init (face);
   layout->avar.init (face);
+  layout->morx.init (face);
 
   {
     /*
      * The ugly business of blacklisting individual fonts' tables happen here!
      * See this thread for why we finally had to bend in and do this:
      * https://lists.freedesktop.org/archives/harfbuzz/2016-February/005489.html
      */
     unsigned int gdef_len = hb_blob_get_length (layout->gdef_blob);
@@ -204,16 +205,17 @@ void
 
   hb_blob_destroy (layout->gdef_blob);
   hb_blob_destroy (layout->gsub_blob);
   hb_blob_destroy (layout->gpos_blob);
 
   layout->math.fini ();
   layout->fvar.fini ();
   layout->avar.fini ();
+  layout->morx.fini ();
 
   free (layout);
 }
 
 static inline const OT::GDEF&
 _get_gdef (hb_face_t *face)
 {
   if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return OT::Null(OT::GDEF);
@@ -1050,33 +1052,33 @@ struct GPOSProxy
   const hb_ot_layout_lookup_accelerator_t *accels;
 };
 
 
 struct hb_get_subtables_context_t :
        OT::hb_dispatch_context_t<hb_get_subtables_context_t, hb_void_t, HB_DEBUG_APPLY>
 {
   template <typename Type>
-  static inline bool apply_to (const void *obj, OT::hb_apply_context_t *c)
+  static inline bool apply_to (const void *obj, OT::hb_ot_apply_context_t *c)
   {
     const Type *typed_obj = (const Type *) obj;
     return typed_obj->apply (c);
   }
 
-  typedef bool (*hb_apply_func_t) (const void *obj, OT::hb_apply_context_t *c);
+  typedef bool (*hb_apply_func_t) (const void *obj, OT::hb_ot_apply_context_t *c);
 
   struct hb_applicable_t
   {
     inline void init (const void *obj_, hb_apply_func_t apply_func_)
     {
       obj = obj_;
       apply_func = apply_func_;
     }
 
-    inline bool apply (OT::hb_apply_context_t *c) const { return apply_func (obj, c); }
+    inline bool apply (OT::hb_ot_apply_context_t *c) const { return apply_func (obj, c); }
 
     private:
     const void *obj;
     hb_apply_func_t apply_func;
   };
 
   typedef hb_auto_array_t<hb_applicable_t> array_t;
 
@@ -1097,17 +1099,17 @@ struct hb_get_subtables_context_t :
 			      array (array_),
 			      debug_depth (0) {}
 
   array_t &array;
   unsigned int debug_depth;
 };
 
 static inline bool
-apply_forward (OT::hb_apply_context_t *c,
+apply_forward (OT::hb_ot_apply_context_t *c,
 	       const hb_ot_layout_lookup_accelerator_t &accel,
 	       const hb_get_subtables_context_t::array_t &subtables)
 {
   bool ret = false;
   hb_buffer_t *buffer = c->buffer;
   while (buffer->idx < buffer->len && !buffer->in_error)
   {
     bool applied = false;
@@ -1127,17 +1129,17 @@ apply_forward (OT::hb_apply_context_t *c
       ret = true;
     else
       buffer->next_glyph ();
   }
   return ret;
 }
 
 static inline bool
-apply_backward (OT::hb_apply_context_t *c,
+apply_backward (OT::hb_ot_apply_context_t *c,
 	       const hb_ot_layout_lookup_accelerator_t &accel,
 	       const hb_get_subtables_context_t::array_t &subtables)
 {
   bool ret = false;
   hb_buffer_t *buffer = c->buffer;
   do
   {
     if (accel.may_have (buffer->cur().codepoint) &&
@@ -1156,17 +1158,17 @@ apply_backward (OT::hb_apply_context_t *
 
   }
   while ((int) buffer->idx >= 0);
   return ret;
 }
 
 template <typename Proxy>
 static inline void
-apply_string (OT::hb_apply_context_t *c,
+apply_string (OT::hb_ot_apply_context_t *c,
 	      const typename Proxy::Lookup &lookup,
 	      const hb_ot_layout_lookup_accelerator_t &accel)
 {
   hb_buffer_t *buffer = c->buffer;
 
   if (unlikely (!buffer->len || !c->lookup_mask))
     return;
 
@@ -1207,17 +1209,17 @@ apply_string (OT::hb_apply_context_t *c,
 template <typename Proxy>
 inline void hb_ot_map_t::apply (const Proxy &proxy,
 				const hb_ot_shape_plan_t *plan,
 				hb_font_t *font,
 				hb_buffer_t *buffer) const
 {
   const unsigned int table_index = proxy.table_index;
   unsigned int i = 0;
-  OT::hb_apply_context_t c (table_index, font, buffer);
+  OT::hb_ot_apply_context_t c (table_index, font, buffer);
   c.set_recurse_func (Proxy::Lookup::apply_recurse_func);
 
   for (unsigned int stage_index = 0; stage_index < stages[table_index].len; stage_index++) {
     const stage_map_t *stage = &stages[table_index][stage_index];
     for (; i < stage->last_lookup; i++)
     {
       unsigned int lookup_index = lookups[table_index][i].index;
       if (!buffer->message (font, "start lookup %d", lookup_index)) continue;
@@ -1247,14 +1249,14 @@ void hb_ot_map_t::substitute (const hb_o
 
 void hb_ot_map_t::position (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const
 {
   GPOSProxy proxy (font->face);
   apply (proxy, plan, font, buffer);
 }
 
 HB_INTERNAL void
-hb_ot_layout_substitute_lookup (OT::hb_apply_context_t *c,
+hb_ot_layout_substitute_lookup (OT::hb_ot_apply_context_t *c,
 				const OT::SubstLookup &lookup,
 				const hb_ot_layout_lookup_accelerator_t &accel)
 {
   apply_string<GSUBProxy> (c, lookup, accel);
 }
--- a/gfx/harfbuzz/src/hb-ot-map-private.hh
+++ b/gfx/harfbuzz/src/hb-ot-map-private.hh
@@ -193,17 +193,16 @@ struct hb_ot_map_builder_t
     {
       stages[table_index].finish ();
     }
   }
 
   private:
 
   HB_INTERNAL void add_lookups (hb_ot_map_t  &m,
-				hb_face_t    *face,
 				unsigned int  table_index,
 				unsigned int  feature_index,
 				unsigned int  variations_index,
 				hb_mask_t     mask,
 				bool          auto_zwnj = true,
 				bool          auto_zwj = true);
 
   struct feature_info_t {
--- a/gfx/harfbuzz/src/hb-ot-map.cc
+++ b/gfx/harfbuzz/src/hb-ot-map.cc
@@ -75,17 +75,16 @@ void hb_ot_map_builder_t::add_feature (h
   info->flags = flags;
   info->default_value = (flags & F_GLOBAL) ? value : 0;
   info->stage[0] = current_stage[0];
   info->stage[1] = current_stage[1];
 }
 
 void
 hb_ot_map_builder_t::add_lookups (hb_ot_map_t  &m,
-				  hb_face_t    *face,
 				  unsigned int  table_index,
 				  unsigned int  feature_index,
 				  unsigned int  variations_index,
 				  hb_mask_t     mask,
 				  bool          auto_zwnj,
 				  bool          auto_zwj)
 {
   unsigned int lookup_indices[32];
@@ -284,24 +283,24 @@ hb_ot_map_builder_t::compile (hb_ot_map_
 						&variations_index);
 
     unsigned int stage_index = 0;
     unsigned int last_num_lookups = 0;
     for (unsigned stage = 0; stage < current_stage[table_index]; stage++)
     {
       if (required_feature_index[table_index] != HB_OT_LAYOUT_NO_FEATURE_INDEX &&
 	  required_feature_stage[table_index] == stage)
-	add_lookups (m, face, table_index,
+	add_lookups (m, table_index,
 		     required_feature_index[table_index],
 		     variations_index,
 		     global_bit_mask);
 
       for (unsigned i = 0; i < m.features.len; i++)
         if (m.features[i].stage[table_index] == stage)
-	  add_lookups (m, face, table_index,
+	  add_lookups (m, table_index,
 		       m.features[i].index[table_index],
 		       variations_index,
 		       m.features[i].mask,
 		       m.features[i].auto_zwnj,
 		       m.features[i].auto_zwj);
 
       /* Sort lookups and merge duplicates */
       if (last_num_lookups < m.lookups[table_index].len)
--- a/gfx/harfbuzz/src/hb-ot-math-table.hh
+++ b/gfx/harfbuzz/src/hb-ot-math-table.hh
@@ -43,17 +43,17 @@ struct MathValueRecord
 
   inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) && deviceTable.sanitize (c, base));
   }
 
   protected:
-  INT16			value;		/* The X or Y value in design units */
+  HBINT16			value;		/* The X or Y value in design units */
   OffsetTo<Device>	deviceTable;	/* Offset to the device table - from the
 					 * beginning of parent table. May be nullptr.
 					 * Suggested format for device table is 1. */
 
   public:
   DEFINE_SIZE_STATIC (4);
 };
 
@@ -149,20 +149,20 @@ struct MathConstants
       return radicalDegreeBottomRaisePercent;
 
     default:
       return 0;
     }
   }
 
   protected:
-  INT16 percentScaleDown[2];
-  UINT16 minHeight[2];
+  HBINT16 percentScaleDown[2];
+  HBUINT16 minHeight[2];
   MathValueRecord mathValueRecords[51];
-  INT16 radicalDegreeBottomRaisePercent;
+  HBINT16 radicalDegreeBottomRaisePercent;
 
   public:
   DEFINE_SIZE_STATIC (214);
 };
 
 struct MathItalicsCorrectionInfo
 {
   inline bool sanitize (hb_sanitize_context_t *c) const
@@ -274,17 +274,17 @@ struct MathKern
 	count -= half + 1;
       } else
 	count = half;
     }
     return kernValue[i].get_x_value(font, this);
   }
 
   protected:
-  UINT16	  heightCount;
+  HBUINT16	  heightCount;
   MathValueRecord mathValueRecords[VAR]; /* Array of correction heights at
 					  * which the kern value changes.
 					  * Sorted by the height value in
 					  * design units (heightCount entries),
 					  * Followed by:
 					  * Array of kern values corresponding
 					  * to heights. (heightCount+1 entries).
 					  */
@@ -420,25 +420,25 @@ struct MathGlyphVariantRecord
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this));
   }
 
   protected:
   GlyphID variantGlyph;       /* Glyph ID for the variant. */
-  UINT16  advanceMeasurement; /* Advance width/height, in design units, of the
+  HBUINT16  advanceMeasurement; /* Advance width/height, in design units, of the
 			       * variant, in the direction of requested
 			       * glyph extension. */
 
   public:
   DEFINE_SIZE_STATIC (4);
 };
 
-struct PartFlags : UINT16
+struct PartFlags : HBUINT16
 {
   enum Flags {
     Extender	= 0x0001u, /* If set, the part can be skipped or repeated. */
 
     Defined	= 0x0001u, /* All defined flags. */
   };
 
   public:
@@ -468,25 +468,25 @@ struct MathGlyphPartRecord
 
     out.flags = (hb_ot_math_glyph_part_flags_t)
 		(unsigned int)
 		(partFlags & PartFlags::Defined);
   }
 
   protected:
   GlyphID   glyph;		  /* Glyph ID for the part. */
-  UINT16    startConnectorLength; /* Advance width/ height of the straight bar
+  HBUINT16    startConnectorLength; /* Advance width/ height of the straight bar
 				   * connector material, in design units, is at
 				   * the beginning of the glyph, in the
 				   * direction of the extension. */
-  UINT16    endConnectorLength;   /* Advance width/ height of the straight bar
+  HBUINT16    endConnectorLength;   /* Advance width/ height of the straight bar
 				   * connector material, in design units, is at
 				   * the end of the glyph, in the direction of
 				   * the extension. */
-  UINT16    fullAdvance;	  /* Full advance width/height for this part,
+  HBUINT16    fullAdvance;	  /* Full advance width/height for this part,
 				   * in the direction of the extension.
 				   * In design units. */
   PartFlags partFlags;		  /* Part qualifiers. */
 
   public:
   DEFINE_SIZE_STATIC (10);
 };
 
@@ -646,29 +646,29 @@ struct MathVariants
 
     if (!vertical)
       index += vertGlyphCount;
 
     return this+glyphConstruction[index];
   }
 
   protected:
-  UINT16	     minConnectorOverlap; /* Minimum overlap of connecting
+  HBUINT16	     minConnectorOverlap; /* Minimum overlap of connecting
 					   * glyphs during glyph construction,
 					   * in design units. */
   OffsetTo<Coverage> vertGlyphCoverage;   /* Offset to Coverage table -
 					   * from the beginning of MathVariants
 					   * table. */
   OffsetTo<Coverage> horizGlyphCoverage;  /* Offset to Coverage table -
 					   * from the beginning of MathVariants
 					   * table. */
-  UINT16	     vertGlyphCount;      /* Number of glyphs for which
+  HBUINT16	     vertGlyphCount;      /* Number of glyphs for which
 					   * information is provided for
 					   * vertically growing variants. */
-  UINT16	     horizGlyphCount;     /* Number of glyphs for which
+  HBUINT16	     horizGlyphCount;     /* Number of glyphs for which
 					   * information is provided for
 					   * horizontally growing variants. */
 
   /* Array of offsets to MathGlyphConstruction tables - from the beginning of
      the MathVariants table, for shapes growing in vertical/horizontal
      direction. */
   OffsetTo<MathGlyphConstruction> glyphConstruction[VAR];
 
--- a/gfx/harfbuzz/src/hb-ot-maxp-table.hh
+++ b/gfx/harfbuzz/src/hb-ot-maxp-table.hh
@@ -55,17 +55,17 @@ struct maxp
 		  likely (version.major == 1 ||
 			  (version.major == 0 && version.minor == 0x5000u)));
   }
 
   /* We only implement version 0.5 as none of the extra fields in version 1.0 are useful. */
   protected:
   FixedVersion<>version;		/* Version of the maxp table (0.5 or 1.0),
 					 * 0x00005000u or 0x00010000u. */
-  UINT16	numGlyphs;		/* The number of glyphs in the font. */
+  HBUINT16	numGlyphs;		/* The number of glyphs in the font. */
   public:
   DEFINE_SIZE_STATIC (6);
 };
 
 
 } /* namespace OT */
 
 
--- a/gfx/harfbuzz/src/hb-ot-name-table.hh
+++ b/gfx/harfbuzz/src/hb-ot-name-table.hh
@@ -60,22 +60,22 @@ struct NameRecord
 
   inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
   {
     TRACE_SANITIZE (this);
     /* We can check from base all the way up to the end of string... */
     return_trace (c->check_struct (this) && c->check_range ((char *) base, (unsigned int) length + offset));
   }
 
-  UINT16	platformID;	/* Platform ID. */
-  UINT16	encodingID;	/* Platform-specific encoding ID. */
-  UINT16	languageID;	/* Language ID. */
-  UINT16	nameID;		/* Name ID. */
-  UINT16	length;		/* String length (in bytes). */
-  UINT16	offset;		/* String offset from start of storage area (in bytes). */
+  HBUINT16	platformID;	/* Platform ID. */
+  HBUINT16	encodingID;	/* Platform-specific encoding ID. */
+  HBUINT16	languageID;	/* Language ID. */
+  HBUINT16	nameID;		/* Name ID. */
+  HBUINT16	length;		/* String length (in bytes). */
+  HBUINT16	offset;		/* String offset from start of storage area (in bytes). */
   public:
   DEFINE_SIZE_STATIC (12);
 };
 
 struct name
 {
   static const hb_tag_t tableTag	= HB_OT_TAG_name;
 
@@ -118,18 +118,18 @@ struct name
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) &&
 		  likely (format == 0 || format == 1) &&
 		  c->check_array (nameRecord, nameRecord[0].static_size, count) &&
 		  sanitize_records (c));
   }
 
   /* We only implement format 0 for now. */
-  UINT16	format;			/* Format selector (=0/1). */
-  UINT16	count;			/* Number of name records. */
+  HBUINT16	format;			/* Format selector (=0/1). */
+  HBUINT16	count;			/* Number of name records. */
   Offset16	stringOffset;		/* Offset to start of string storage (from start of table). */
   NameRecord	nameRecord[VAR];	/* The name records where count is the number of records. */
   public:
   DEFINE_SIZE_ARRAY (6, nameRecord);
 };
 
 
 } /* namespace OT */
--- a/gfx/harfbuzz/src/hb-ot-os2-table.hh
+++ b/gfx/harfbuzz/src/hb-ot-os2-table.hh
@@ -45,60 +45,60 @@ struct os2
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this));
   }
 
   public:
-  UINT16	version;
+  HBUINT16	version;
 
   /* Version 0 */
-  INT16		xAvgCharWidth;
-  UINT16	usWeightClass;
-  UINT16	usWidthClass;
-  UINT16	fsType;
-  INT16		ySubscriptXSize;
-  INT16		ySubscriptYSize;
-  INT16		ySubscriptXOffset;
-  INT16		ySubscriptYOffset;
-  INT16		ySuperscriptXSize;
-  INT16		ySuperscriptYSize;
-  INT16		ySuperscriptXOffset;
-  INT16		ySuperscriptYOffset;
-  INT16		yStrikeoutSize;
-  INT16		yStrikeoutPosition;
-  INT16		sFamilyClass;
-  UINT8		panose[10];
-  UINT32		ulUnicodeRange[4];
+  HBINT16		xAvgCharWidth;
+  HBUINT16	usWeightClass;
+  HBUINT16	usWidthClass;
+  HBUINT16	fsType;
+  HBINT16		ySubscriptXSize;
+  HBINT16		ySubscriptYSize;
+  HBINT16		ySubscriptXOffset;
+  HBINT16		ySubscriptYOffset;
+  HBINT16		ySuperscriptXSize;
+  HBINT16		ySuperscriptYSize;
+  HBINT16		ySuperscriptXOffset;
+  HBINT16		ySuperscriptYOffset;
+  HBINT16		yStrikeoutSize;
+  HBINT16		yStrikeoutPosition;
+  HBINT16		sFamilyClass;
+  HBUINT8		panose[10];
+  HBUINT32		ulUnicodeRange[4];
   Tag		achVendID;
-  UINT16	fsSelection;
-  UINT16	usFirstCharIndex;
-  UINT16	usLastCharIndex;
-  INT16		sTypoAscender;
-  INT16		sTypoDescender;
-  INT16		sTypoLineGap;
-  UINT16	usWinAscent;
-  UINT16	usWinDescent;
+  HBUINT16	fsSelection;
+  HBUINT16	usFirstCharIndex;
+  HBUINT16	usLastCharIndex;
+  HBINT16		sTypoAscender;
+  HBINT16		sTypoDescender;
+  HBINT16		sTypoLineGap;
+  HBUINT16	usWinAscent;
+  HBUINT16	usWinDescent;
 
   /* Version 1 */
-  //UINT32 ulCodePageRange1;
-  //UINT32 ulCodePageRange2;
+  //HBUINT32 ulCodePageRange1;
+  //HBUINT32 ulCodePageRange2;
 
   /* Version 2 */
-  //INT16 sxHeight;
-  //INT16 sCapHeight;
-  //UINT16  usDefaultChar;
-  //UINT16  usBreakChar;
-  //UINT16  usMaxContext;
+  //HBINT16 sxHeight;
+  //HBINT16 sCapHeight;
+  //HBUINT16  usDefaultChar;
+  //HBUINT16  usBreakChar;
+  //HBUINT16  usMaxContext;
 
   /* Version 5 */
-  //UINT16  usLowerOpticalPointSize;
-  //UINT16  usUpperOpticalPointSize;
+  //HBUINT16  usLowerOpticalPointSize;
+  //HBUINT16  usUpperOpticalPointSize;
 
   public:
   DEFINE_SIZE_STATIC (78);
 };
 
 } /* namespace OT */
 
 
--- a/gfx/harfbuzz/src/hb-ot-post-table.hh
+++ b/gfx/harfbuzz/src/hb-ot-post-table.hh
@@ -51,20 +51,20 @@ namespace OT {
 struct postV2Tail
 {
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (glyphNameIndex.sanitize (c));
   }
 
-  ArrayOf<UINT16>glyphNameIndex;	/* This is not an offset, but is the
+  ArrayOf<HBUINT16>glyphNameIndex;	/* This is not an offset, but is the
 					 * ordinal number of the glyph in 'post'
 					 * string tables. */
-  UINT8		namesX[VAR];		/* Glyph names with length bytes [variable]
+  HBUINT8		namesX[VAR];		/* Glyph names with length bytes [variable]
 					 * (a Pascal string). */
 
   DEFINE_SIZE_ARRAY2 (2, glyphNameIndex, namesX);
 };
 
 struct post
 {
   static const hb_tag_t tableTag = HB_OT_TAG_post;
@@ -81,17 +81,17 @@ struct post
     }
     return_trace (true);
   }
 
   struct accelerator_t
   {
     inline void init (hb_face_t *face)
     {
-      blob = Sanitizer<post>::sanitize (face->reference_table (HB_OT_TAG_post));
+      blob = Sanitizer<post>().sanitize (face->reference_table (HB_OT_TAG_post));
       const post *table = Sanitizer<post>::lock_instance (blob);
       unsigned int table_length = hb_blob_get_length (blob);
 
       version = table->version.to_int ();
       index_to_offset.init ();
       if (version != 0x00020000)
         return;
 
@@ -229,17 +229,17 @@ struct post
       data++;
 
       return hb_string_t ((const char *) data, name_length);
     }
 
     private:
     hb_blob_t *blob;
     uint32_t version;
-    const ArrayOf<UINT16> *glyphNameIndex;
+    const ArrayOf<HBUINT16> *glyphNameIndex;
     hb_prealloced_array_t<uint32_t, 1> index_to_offset;
     const uint8_t *pool;
     mutable uint16_t *gids_sorted_by_name;
   };
 
   public:
   FixedVersion<>version;		/* 0x00010000 for version 1.0
 					 * 0x00020000 for version 2.0
@@ -256,26 +256,26 @@ struct post
 					 * dictionary key (the y coordinate of the
 					 * center of the stroke) is not used for
 					 * historical reasons. The value of the
 					 * PostScript key may be calculated by
 					 * subtracting half the underlineThickness
 					 * from the value of this field. */
   FWORD		underlineThickness;	/* Suggested values for the underline
 					   thickness. */
-  UINT32		isFixedPitch;		/* Set to 0 if the font is proportionally
+  HBUINT32	isFixedPitch;		/* Set to 0 if the font is proportionally
 					 * spaced, non-zero if the font is not
 					 * proportionally spaced (i.e. monospaced). */
-  UINT32		minMemType42;		/* Minimum memory usage when an OpenType font
+  HBUINT32	minMemType42;		/* Minimum memory usage when an OpenType font
 					 * is downloaded. */
-  UINT32		maxMemType42;		/* Maximum memory usage when an OpenType fon