Merge mozilla-central to autoland
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Fri, 09 Sep 2016 12:19:59 +0200
changeset 313396 68ae5adc423221684ad87a2dc94f7cb864a148f4
parent 313395 9cd8e43dd653f826383cc42a4debc1050b966560 (current diff)
parent 313389 feff79e5b1374439f17c5ea10a559acf1380a8d5 (diff)
child 313397 287ff570b1a18bc84c82309e23163557cb9fae6d
push id30681
push userphilringnalda@gmail.com
push dateSat, 10 Sep 2016 07:13:06 +0000
treeherdermozilla-central@61cc64967515 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone51.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-central to autoland
build/autoconf/rust.m4
layout/base/nsLayoutUtils.cpp
layout/generic/nsFrame.cpp
layout/style/nsComputedDOMStyle.cpp
layout/style/nsStyleStruct.cpp
testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_escaping.html
testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_helper.html
testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_nonescaping.html
--- a/addon-sdk/source/lib/sdk/panel/utils.js
+++ b/addon-sdk/source/lib/sdk/panel/utils.js
@@ -236,16 +236,17 @@ function onPanelClick(event) {
        getMostRecentBrowserWindow().openUILink(link.href, event)
   }
 }
 
 function setupPanelFrame(frame) {
   frame.setAttribute("flex", 1);
   frame.setAttribute("transparent", "transparent");
   frame.setAttribute("autocompleteenabled", true);
+  frame.setAttribute("tooltip", "aHTMLTooltip");
   if (platform === "darwin") {
     frame.style.borderRadius = "6px";
     frame.style.padding = "1px";
   }
 }
 
 function make(document, options) {
   document = document || getMostRecentBrowserWindow().document;
--- a/browser/base/content/contentSearchUI.js
+++ b/browser/base/content/contentSearchUI.js
@@ -269,19 +269,21 @@ ContentSearchUIController.prototype = {
       searchString: searchTerms,
       healthReportKey: this._healthReportKey,
       searchPurpose: this._searchPurpose,
       originalEvent: {
         shiftKey: aEvent.shiftKey,
         ctrlKey: aEvent.ctrlKey,
         metaKey: aEvent.metaKey,
         altKey: aEvent.altKey,
-        button: aEvent.button,
       },
     };
+    if ("button" in aEvent) {
+      eventData.originalEvent.button = aEvent.button;
+    }
 
     if (this.suggestionAtIndex(this.selectedIndex)) {
       eventData.selection = {
         index: this.selectedIndex,
         kind: undefined,
       };
       if (aEvent instanceof MouseEvent) {
         eventData.selection.kind = "mouse";
--- a/browser/components/nsBrowserGlue.js
+++ b/browser/components/nsBrowserGlue.js
@@ -2630,16 +2630,55 @@ ContentPermissionPrompt.prototype = {
     }
 
     secHistogram.add(Ci.nsISecurityUITelemetry.WARNING_GEOLOCATION_REQUEST);
 
     this._showPrompt(aRequest, message, "geo", actions, "geolocation",
                      "geo-notification-icon", options);
   },
 
+  _promptFlyWebPublishServer : function(aRequest) {
+    var message = "Would you like to let this site start a server accessible to nearby devices and people?";
+    var actions = [
+      {
+        stringId: "flyWebPublishServer.allowPublishServer",
+        action: Ci.nsIPermissionManager.ALLOW_ACTION,
+        expireType: Ci.nsIPermissionManager.EXPIRE_SESSION
+      },
+      {
+        stringId: "flyWebPublishServer.denyPublishServer",
+        action: Ci.nsIPermissionManager.DENY_ACTION,
+        expireType: Ci.nsIPermissionManager.EXPIRE_SESSION
+      }
+    ];
+
+    let options = {
+      learnMoreURL: "https://flyweb.github.io",
+      popupIconURL: "chrome://flyweb/skin/icon-64.png"
+    };
+
+    let browser = this._getBrowserForRequest(aRequest);
+    let chromeDoc = browser.ownerDocument;
+    let iconElem = chromeDoc.getElementById("flyweb-publish-server-notification-icon");
+    if (!iconElem) {
+      let notificationPopupBox = chromeDoc.getElementById("notification-popup-box");
+      let notificationIcon = chromeDoc.createElement("image");
+      notificationIcon.setAttribute("id", "flyweb-publish-server-notification-icon");
+      notificationIcon.setAttribute("src", "chrome://flyweb/skin/icon-64.png");
+      notificationIcon.setAttribute("class", "notification-anchor-icon flyweb-publish-server-icon");
+      notificationIcon.setAttribute("style", "filter: url(chrome://browser/skin/filters.svg#fill); fill: currentColor; opacity: .4;");
+      notificationIcon.setAttribute("role", "button");
+      notificationIcon.setAttribute("aria-label", "View the publish-server request");
+      notificationPopupBox.appendChild(notificationIcon);
+    }
+
+    this._showPrompt(aRequest, message, "flyweb-publish-server", actions, "flyweb-publish-server",
+                     "flyweb-publish-server-notification-icon", options);
+  },
+
   _promptWebNotifications : function(aRequest) {
     var message = gBrowserBundle.GetStringFromName("webNotifications.receiveFromSite");
 
     var actions;
 
     var browser = this._getBrowserForRequest(aRequest);
     // Only show "allow for session" in PB mode, we don't
     // support "allow for session" in non-PB mode.
@@ -2694,17 +2733,18 @@ ContentPermissionPrompt.prototype = {
     let types = request.types.QueryInterface(Ci.nsIArray);
     if (types.length != 1) {
       request.cancel();
       return;
     }
     let perm = types.queryElementAt(0, Ci.nsIContentPermissionType);
 
     const kFeatureKeys = { "geolocation" : "geo",
-                           "desktop-notification" : "desktop-notification"
+                           "desktop-notification" : "desktop-notification",
+                           "flyweb-publish-server": "flyweb-publish-server"
                          };
 
     // Make sure that we support the request.
     if (!(perm.type in kFeatureKeys)) {
       return;
     }
 
     var requestingPrincipal = request.principal;
@@ -2737,16 +2777,21 @@ ContentPermissionPrompt.prototype = {
     // Show the prompt.
     switch (perm.type) {
     case "geolocation":
       this._promptGeo(request);
       break;
     case "desktop-notification":
       this._promptWebNotifications(request);
       break;
+    case "flyweb-publish-server":
+      if (AppConstants.NIGHTLY_BUILD) {
+        this._promptFlyWebPublishServer(request);
+      }
+      break;
     }
   },
 
 };
 
 var DefaultBrowserCheck = {
   get OPTIONPOPUP() { return "defaultBrowserNotificationPopup" },
   _setAsDefaultTimer: null,
--- a/browser/components/preferences/in-content/search.js
+++ b/browser/components/preferences/in-content/search.js
@@ -218,16 +218,18 @@ var gSearchPane = {
     if (tree.hasAttribute("editing"))
       return;
 
     if (aEvent.charCode == KeyEvent.DOM_VK_SPACE) {
       // Space toggles the checkbox.
       let newValue = !gEngineView._engineStore.engines[index].shown;
       gEngineView.setCellValue(index, tree.columns.getFirstColumn(),
                                newValue.toString());
+      // Prevent page from scrolling on the space key.
+      aEvent.preventDefault();
     }
     else {
       let isMac = Services.appinfo.OS == "Darwin";
       if ((isMac && aEvent.keyCode == KeyEvent.DOM_VK_RETURN) ||
           (!isMac && aEvent.keyCode == KeyEvent.DOM_VK_F2)) {
         tree.startEditing(index, tree.columns.getLastColumn());
       } else if (aEvent.keyCode == KeyEvent.DOM_VK_DELETE ||
                  (isMac && aEvent.shiftKey &&
--- a/browser/components/preferences/in-content/sync.js
+++ b/browser/components/preferences/in-content/sync.js
@@ -554,22 +554,26 @@ var gSyncPane = {
   openChangeProfileImage: function(event) {
     if (this.clickOrSpaceOrEnterPressed(event)) {
       fxAccounts.promiseAccountsChangeProfileURI(this._getEntryPoint(), "avatar")
           .then(url => {
         this.openContentInBrowser(url, {
           replaceQueryString: true
         });
       });
+      // Prevent page from scrolling on the space key.
+      event.preventDefault();
     }
   },
 
   openManageFirefoxAccount: function(event) {
     if (this.clickOrSpaceOrEnterPressed(event)) {
       this.manageFirefoxAccount();
+      // Prevent page from scrolling on the space key.
+      event.preventDefault();
     }
   },
 
   manageFirefoxAccount: function() {
     fxAccounts.promiseAccountsManageURI(this._getEntryPoint())
       .then(url => {
         this.openContentInBrowser(url, {
           replaceQueryString: true
@@ -662,9 +666,8 @@ var gSyncPane = {
     let textbox = document.getElementById("fxaSyncComputerName");
     if (!textbox.hasAttribute("placeholder")) {
       textbox.setAttribute("placeholder",
                            Weave.Utils.getDefaultDeviceName());
     }
     textbox.value = value;
   },
 };
-
--- a/browser/components/preferences/in-content/tests/browser.ini
+++ b/browser/components/preferences/in-content/tests/browser.ini
@@ -7,16 +7,19 @@ support-files =
 [browser_advanced_update.js]
 [browser_basic_rebuild_fonts_test.js]
 [browser_bug410900.js]
 [browser_bug705422.js]
 [browser_bug731866.js]
 [browser_bug795764_cachedisabled.js]
 [browser_bug1018066_resetScrollPosition.js]
 [browser_bug1020245_openPreferences_to_paneContent.js]
+[browser_bug1184989_prevent_scrolling_when_preferences_flipped.js]
+support-files =
+  browser_bug1184989_prevent_scrolling_when_preferences_flipped.xul
 [browser_change_app_handler.js]
 skip-if = os != "win" # This test tests the windows-specific app selection dialog, so can't run on non-Windows
 [browser_connection.js]
 [browser_connection_bug388287.js]
 [browser_cookies_exceptions.js]
 [browser_defaultbrowser_alwayscheck.js]
 [browser_healthreport.js]
 skip-if = true || !healthreport # Bug 1185403 for the "true"
new file mode 100644
--- /dev/null
+++ b/browser/components/preferences/in-content/tests/browser_bug1184989_prevent_scrolling_when_preferences_flipped.js
@@ -0,0 +1,92 @@
+const ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
+
+add_task(function* () {
+  waitForExplicitFinish();
+
+  const tabURL = getRootDirectory(gTestPath) + "browser_bug1184989_prevent_scrolling_when_preferences_flipped.xul";
+
+  yield BrowserTestUtils.withNewTab({ gBrowser, url: tabURL }, function* (browser) {
+    let doc = browser.contentDocument;
+    let container = doc.getElementById("container");
+
+    // Test button
+    let button = doc.getElementById("button");
+    button.focus();
+    EventUtils.synthesizeKey(" ", {});
+    yield checkPageScrolling(container, "button");
+
+    // Test checkbox
+    let checkbox = doc.getElementById("checkbox");
+    checkbox.focus();
+    EventUtils.synthesizeKey(" ", {});
+    ok(checkbox.checked, "Checkbox is checked");
+    yield checkPageScrolling(container, "checkbox");
+
+    // Test listbox
+    let listbox = doc.getElementById("listbox");
+    let listitem = doc.getElementById("listitem");
+    listbox.focus();
+    EventUtils.synthesizeKey(" ", {});
+    ok(listitem.selected, "Listitem is selected");
+    yield checkPageScrolling(container, "listbox");
+
+    // Test radio
+    let radiogroup = doc.getElementById("radiogroup");
+    radiogroup.focus();
+    EventUtils.synthesizeKey(" ", {});
+    yield checkPageScrolling(container, "radio");
+  });
+
+  yield BrowserTestUtils.withNewTab({ gBrowser, url: "about:preferences#search" }, function* (browser) {
+    let doc = browser.contentDocument;
+    let container = doc.getElementsByClassName("main-content")[0];
+
+    // Test search
+    let engineList = doc.getElementById("engineList");
+    engineList.focus();
+    EventUtils.synthesizeKey(" ", {});
+    is(engineList.view.selection.currentIndex, 0, "Search engineList is selected");
+    EventUtils.synthesizeKey(" ", {});
+    yield checkPageScrolling(container, "search engineList");
+  });
+
+  // Test session restore
+  const CRASH_URL = "about:mozilla";
+  const CRASH_FAVICON = "chrome://branding/content/icon32.png";
+  const CRASH_SHENTRY = {url: CRASH_URL};
+  const CRASH_TAB = {entries: [CRASH_SHENTRY], image: CRASH_FAVICON};
+  const CRASH_STATE = {windows: [{tabs: [CRASH_TAB]}]};
+
+  const TAB_URL = "about:sessionrestore";
+  const TAB_FORMDATA = {url: TAB_URL, id: {sessionData: CRASH_STATE}};
+  const TAB_SHENTRY = {url: TAB_URL};
+  const TAB_STATE = {entries: [TAB_SHENTRY], formdata: TAB_FORMDATA};
+
+  let tab = gBrowser.selectedTab = gBrowser.addTab("about:blank");
+
+  // Fake a post-crash tab
+  ss.setTabState(tab, JSON.stringify(TAB_STATE));
+
+  yield BrowserTestUtils.browserLoaded(tab.linkedBrowser);
+  let doc = tab.linkedBrowser.contentDocument;
+
+  // Make body scrollable
+  doc.body.style.height = (doc.body.clientHeight + 100) + "px";
+
+  let tabList = doc.getElementById("tabList");
+  tabList.focus();
+  EventUtils.synthesizeKey(" ", {});
+  yield checkPageScrolling(doc.documentElement, "session restore");
+
+  gBrowser.removeCurrentTab();
+  finish();
+});
+
+function checkPageScrolling(container, type) {
+  return new Promise(resolve => {
+    setTimeout(() => {
+      is(container.scrollTop, 0, "Page should not scroll when " + type + " flipped");
+      resolve();
+    }, 0);
+  });
+}
new file mode 100644
--- /dev/null
+++ b/browser/components/preferences/in-content/tests/browser_bug1184989_prevent_scrolling_when_preferences_flipped.xul
@@ -0,0 +1,33 @@
+<?xml version="1.0"?>
+<!--
+  XUL Widget Test for Bug 1184989
+  -->
+<page title="Bug 1184989 Test"
+      xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+<vbox id="container" style="height: 200px; overflow: auto;">
+  <vbox style="height: 500px;">
+    <hbox>
+      <button id="button" label="button" />
+    </hbox>
+
+    <hbox>
+      <checkbox id="checkbox" label="checkbox" />
+    </hbox>
+
+    <hbox style="height: 50px;">
+      <listbox id="listbox">
+        <listitem id="listitem" label="listitem" />
+        <listitem label="listitem" />
+      </listbox>
+    </hbox>
+
+    <hbox>
+      <radiogroup id="radiogroup">
+        <radio id="radio" label="radio" />
+      </radiogroup>
+    </hbox>
+  </vbox>
+</vbox>
+
+</page>
--- a/browser/components/sessionstore/content/aboutSessionRestore.js
+++ b/browser/components/sessionstore/content/aboutSessionRestore.js
@@ -200,16 +200,18 @@ function onListClick(aEvent) {
   }
 }
 
 function onListKeyDown(aEvent) {
   switch (aEvent.keyCode)
   {
   case KeyEvent.DOM_VK_SPACE:
     toggleRowChecked(document.getElementById("tabList").currentIndex);
+    // Prevent page from scrolling on the space key.
+    aEvent.preventDefault();
     break;
   case KeyEvent.DOM_VK_RETURN:
     var ix = document.getElementById("tabList").currentIndex;
     if (aEvent.ctrlKey && !treeView.isContainer(ix))
       restoreSingleTab(ix, aEvent.shiftKey);
     break;
   }
 }
--- a/browser/extensions/pdfjs/README.mozilla
+++ b/browser/extensions/pdfjs/README.mozilla
@@ -1,3 +1,3 @@
 This is the pdf.js project output, https://github.com/mozilla/pdf.js
 
-Current extension version is: 1.5.413
+Current extension version is: 1.5.437
--- a/browser/extensions/pdfjs/content/PdfJs.jsm
+++ b/browser/extensions/pdfjs/content/PdfJs.jsm
@@ -86,17 +86,18 @@ function initializeDefaultPreferences() 
   "enableWebGL": false,
   "pdfBugEnabled": false,
   "disableRange": false,
   "disableStream": false,
   "disableAutoFetch": false,
   "disableFontFace": false,
   "disableTextLayer": false,
   "useOnlyCssZoom": false,
-  "externalLinkTarget": 0
+  "externalLinkTarget": 0,
+  "renderInteractiveForms": false
 }
 
 
   var defaultBranch = Services.prefs.getDefaultBranch(PREF_PREFIX + '.');
   var defaultValue;
   for (var key in DEFAULT_PREFERENCES) {
     defaultValue = DEFAULT_PREFERENCES[key];
     switch (typeof defaultValue) {
--- a/browser/extensions/pdfjs/content/PdfjsChromeUtils.jsm
+++ b/browser/extensions/pdfjs/content/PdfjsChromeUtils.jsm
@@ -44,17 +44,18 @@ var DEFAULT_PREFERENCES =
   "enableWebGL": false,
   "pdfBugEnabled": false,
   "disableRange": false,
   "disableStream": false,
   "disableAutoFetch": false,
   "disableFontFace": false,
   "disableTextLayer": false,
   "useOnlyCssZoom": false,
-  "externalLinkTarget": 0
+  "externalLinkTarget": 0,
+  "renderInteractiveForms": false
 }
 
 
 var PdfjsChromeUtils = {
   // For security purposes when running remote, we restrict preferences
   // content can access.
   _allowedPrefNames: Object.keys(DEFAULT_PREFERENCES),
   _ppmm: null,
--- a/browser/extensions/pdfjs/content/build/pdf.js
+++ b/browser/extensions/pdfjs/content/build/pdf.js
@@ -23,18 +23,18 @@ define('pdfjs-dist/build/pdf', ['exports
     factory(exports);
   } else {
 factory((root.pdfjsDistBuildPdf = {}));
   }
 }(this, function (exports) {
   // Use strict in our context only - users might not want it
   'use strict';
 
-var pdfjsVersion = '1.5.413';
-var pdfjsBuild = '6bb95e3';
+var pdfjsVersion = '1.5.437';
+var pdfjsBuild = 'ca61ccc';
 
   var pdfjsFilePath =
     typeof document !== 'undefined' && document.currentScript ?
       document.currentScript.src : null;
 
   var pdfjsLibs = {};
 
   (function pdfjsWrapper() {
@@ -1153,16 +1153,17 @@ function createPromiseCapability() {
         return globalScope.Promise.prototype.then(undefined, onReject);
       };
     }
     return;
   }
   throw new Error('DOM Promise is not present');
 })();
 
+
 var StatTimer = (function StatTimerClosure() {
   function rpad(str, pad, length) {
     while (str.length < length) {
       str += pad;
     }
     return str;
   }
   function StatTimer() {
@@ -1933,16 +1934,18 @@ var getDefaultSetting = displayDOMUtils.
 /**
  * @typedef {Object} AnnotationElementParameters
  * @property {Object} data
  * @property {HTMLDivElement} layer
  * @property {PDFPage} page
  * @property {PageViewport} viewport
  * @property {IPDFLinkService} linkService
  * @property {DownloadManager} downloadManager
+ * @property {string} imageResourcesPath
+ * @property {boolean} renderInteractiveForms
  */
 
 /**
  * @class
  * @alias AnnotationElementFactory
  */
 function AnnotationElementFactory() {}
 AnnotationElementFactory.prototype =
@@ -1957,16 +1960,22 @@ AnnotationElementFactory.prototype =
     switch (subtype) {
       case AnnotationType.LINK:
         return new LinkAnnotationElement(parameters);
 
       case AnnotationType.TEXT:
         return new TextAnnotationElement(parameters);
 
       case AnnotationType.WIDGET:
+        var fieldType = parameters.data.fieldType;
+
+        switch (fieldType) {
+          case 'Tx':
+            return new TextWidgetAnnotationElement(parameters);
+        }
         return new WidgetAnnotationElement(parameters);
 
       case AnnotationType.POPUP:
         return new PopupAnnotationElement(parameters);
 
       case AnnotationType.HIGHLIGHT:
         return new HighlightAnnotationElement(parameters);
 
@@ -1997,16 +2006,17 @@ var AnnotationElement = (function Annota
     this.isRenderable = isRenderable || false;
     this.data = parameters.data;
     this.layer = parameters.layer;
     this.page = parameters.page;
     this.viewport = parameters.viewport;
     this.linkService = parameters.linkService;
     this.downloadManager = parameters.downloadManager;
     this.imageResourcesPath = parameters.imageResourcesPath;
+    this.renderInteractiveForms = parameters.renderInteractiveForms;
 
     if (isRenderable) {
       this.container = this._createContainer();
     }
   }
 
   AnnotationElement.prototype = /** @lends AnnotationElement.prototype */ {
     /**
@@ -2280,55 +2290,90 @@ var TextAnnotationElement = (function Te
 })();
 
 /**
  * @class
  * @alias WidgetAnnotationElement
  */
 var WidgetAnnotationElement = (function WidgetAnnotationElementClosure() {
   function WidgetAnnotationElement(parameters) {
-    var isRenderable = !parameters.data.hasAppearance &&
-                       !!parameters.data.fieldValue;
-    AnnotationElement.call(this, parameters, isRenderable);
+    AnnotationElement.call(this, parameters, true);
   }
 
   Util.inherit(WidgetAnnotationElement, AnnotationElement, {
     /**
      * Render the widget annotation's HTML element in the empty container.
      *
      * @public
      * @memberof WidgetAnnotationElement
      * @returns {HTMLSectionElement}
      */
     render: function WidgetAnnotationElement_render() {
-      var content = document.createElement('div');
-      content.textContent = this.data.fieldValue;
-      var textAlignment = this.data.textAlignment;
-      content.style.textAlign = ['left', 'center', 'right'][textAlignment];
-      content.style.verticalAlign = 'middle';
-      content.style.display = 'table-cell';
-
-      var font = (this.data.fontRefName ?
-        this.page.commonObjs.getData(this.data.fontRefName) : null);
-      this._setTextStyle(content, font);
-
-      this.container.appendChild(content);
+      // Show only the container for unsupported field types.
+      return this.container;
+    }
+  });
+
+  return WidgetAnnotationElement;
+})();
+
+/**
+ * @class
+ * @alias TextWidgetAnnotationElement
+ */
+var TextWidgetAnnotationElement = (
+    function TextWidgetAnnotationElementClosure() {
+  function TextWidgetAnnotationElement(parameters) {
+    WidgetAnnotationElement.call(this, parameters);
+  }
+
+  Util.inherit(TextWidgetAnnotationElement, WidgetAnnotationElement, {
+    /**
+     * Render the text widget annotation's HTML element in the empty container.
+     *
+     * @public
+     * @memberof TextWidgetAnnotationElement
+     * @returns {HTMLSectionElement}
+     */
+    render: function TextWidgetAnnotationElement_render() {
+      this.container.className = 'textWidgetAnnotation';
+
+      if (this.renderInteractiveForms) {
+        var input = document.createElement('input');
+        input.type = 'text';
+        input.value = this.data.fieldValue;
+
+        this.container.appendChild(input);
+      } else {
+        var content = document.createElement('div');
+        content.textContent = this.data.fieldValue;
+        var textAlignment = this.data.textAlignment;
+        content.style.textAlign = ['left', 'center', 'right'][textAlignment];
+        content.style.verticalAlign = 'middle';
+        content.style.display = 'table-cell';
+
+        var font = (this.data.fontRefName ?
+          this.page.commonObjs.getData(this.data.fontRefName) : null);
+        this._setTextStyle(content, font);
+
+        this.container.appendChild(content);
+      }
       return this.container;
     },
 
     /**
      * Apply text styles to the text in the element.
      *
      * @private
      * @param {HTMLDivElement} element
      * @param {Object} font
-     * @memberof WidgetAnnotationElement
+     * @memberof TextWidgetAnnotationElement
      */
     _setTextStyle:
-        function WidgetAnnotationElement_setTextStyle(element, font) {
+        function TextWidgetAnnotationElement_setTextStyle(element, font) {
       // TODO: This duplicates some of the logic in CanvasGraphics.setFont().
       var style = element.style;
       style.fontSize = this.data.fontSize + 'px';
       style.direction = (this.data.fontDirection < 0 ? 'rtl': 'ltr');
 
       if (!font) {
         return;
       }
@@ -2340,17 +2385,17 @@ var WidgetAnnotationElement = (function 
 
       // Use a reasonable default font if the font doesn't specify a fallback.
       var fontFamily = font.loadedName ? '"' + font.loadedName + '", ' : '';
       var fallbackName = font.fallbackName || 'Helvetica, sans-serif';
       style.fontFamily = fontFamily + fallbackName;
     }
   });
 
-  return WidgetAnnotationElement;
+  return TextWidgetAnnotationElement;
 })();
 
 /**
  * @class
  * @alias PopupAnnotationElement
  */
 var PopupAnnotationElement = (function PopupAnnotationElementClosure() {
   function PopupAnnotationElement(parameters) {
@@ -2732,16 +2777,17 @@ var FileAttachmentAnnotationElement = (
 /**
  * @typedef {Object} AnnotationLayerParameters
  * @property {PageViewport} viewport
  * @property {HTMLDivElement} div
  * @property {Array} annotations
  * @property {PDFPage} page
  * @property {IPDFLinkService} linkService
  * @property {string} imageResourcesPath
+ * @property {boolean} renderInteractiveForms
  */
 
 /**
  * @class
  * @alias AnnotationLayer
  */
 var AnnotationLayer = (function AnnotationLayerClosure() {
   return {
@@ -2764,17 +2810,18 @@ var AnnotationLayer = (function Annotati
         var properties = {
           data: data,
           layer: parameters.div,
           page: parameters.page,
           viewport: parameters.viewport,
           linkService: parameters.linkService,
           downloadManager: parameters.downloadManager,
           imageResourcesPath: parameters.imageResourcesPath ||
-                              getDefaultSetting('imageResourcesPath')
+                              getDefaultSetting('imageResourcesPath'),
+          renderInteractiveForms: parameters.renderInteractiveForms || false,
         };
         var element = annotationElementFactory.create(properties);
         if (element.isRenderable) {
           parameters.div.appendChild(element.render());
         }
       }
     },
 
@@ -2825,37 +2872,53 @@ var getDefaultSetting = displayDOMUtils.
  * @property {HTMLElement} container - HTML element that will contain text runs.
  * @property {PageViewport} viewport - The target viewport to properly
  *   layout the text runs.
  * @property {Array} textDivs - (optional) HTML elements that are correspond
  *   the text items of the textContent input. This is output and shall be
  *   initially be set to empty array.
  * @property {number} timeout - (optional) Delay in milliseconds before
  *   rendering of the text  runs occurs.
+ * @property {boolean} enhanceTextSelection - (optional) Whether to turn on the
+ *   text selection enhancement.
  */
 var renderTextLayer = (function renderTextLayerClosure() {
   var MAX_TEXT_DIVS_TO_RENDER = 100000;
 
   var NonWhitespaceRegexp = /\S/;
 
   function isAllWhitespace(str) {
     return !NonWhitespaceRegexp.test(str);
   }
 
-  function appendText(textDivs, viewport, geom, styles, bounds,
-                      enhanceTextSelection) {
-    var style = styles[geom.fontName];
+  function appendText(task, geom, styles) {
+    // Initialize all used properties to keep the caches monomorphic.
     var textDiv = document.createElement('div');
-    textDivs.push(textDiv);
+    var textDivProperties = {
+      angle: 0,
+      canvasWidth: 0,
+      isWhitespace: false,
+      originalTransform: '',
+      paddingBottom: 0,
+      paddingLeft: 0,
+      paddingRight: 0,
+      paddingTop: 0,
+      scale: 1,
+    };
+
+    task._textDivs.push(textDiv);
     if (isAllWhitespace(geom.str)) {
-      textDiv.dataset.isWhitespace = true;
+      textDivProperties.isWhitespace = true;
+      task._textDivProperties.set(textDiv, textDivProperties);
       return;
     }
-    var tx = Util.transform(viewport.transform, geom.transform);
+
+    var tx = Util.transform(task._viewport.transform, geom.transform);
     var angle = Math.atan2(tx[1], tx[0]);
+    var style = styles[geom.fontName];
     if (style.vertical) {
       angle += Math.PI / 2;
     }
     var fontHeight = Math.sqrt((tx[2] * tx[2]) + (tx[3] * tx[3]));
     var fontAscent = fontHeight;
     if (style.ascent) {
       fontAscent = style.ascent * fontAscent;
     } else if (style.descent) {
@@ -2874,53 +2937,55 @@ var renderTextLayer = (function renderTe
     textDiv.style.left = left + 'px';
     textDiv.style.top = top + 'px';
     textDiv.style.fontSize = fontHeight + 'px';
     textDiv.style.fontFamily = style.fontFamily;
 
     textDiv.textContent = geom.str;
     // |fontName| is only used by the Font Inspector. This test will succeed
     // when e.g. the Font Inspector is off but the Stepper is on, but it's
-    // not worth the effort to do a more accurate test.
+    // not worth the effort to do a more accurate test. We only use `dataset`
+    // here to make the font name available for the debugger.
     if (getDefaultSetting('pdfBug')) {
       textDiv.dataset.fontName = geom.fontName;
     }
-    // Storing into dataset will convert number into string.
     if (angle !== 0) {
-      textDiv.dataset.angle = angle * (180 / Math.PI);
+      textDivProperties.angle = angle * (180 / Math.PI);
     }
     // We don't bother scaling single-char text divs, because it has very
     // little effect on text highlighting. This makes scrolling on docs with
     // lots of such divs a lot faster.
     if (geom.str.length > 1) {
       if (style.vertical) {
-        textDiv.dataset.canvasWidth = geom.height * viewport.scale;
+        textDivProperties.canvasWidth = geom.height * task._viewport.scale;
       } else {
-        textDiv.dataset.canvasWidth = geom.width * viewport.scale;
-      }
-    }
-    if (enhanceTextSelection) {
+        textDivProperties.canvasWidth = geom.width * task._viewport.scale;
+      }
+    }
+    task._textDivProperties.set(textDiv, textDivProperties);
+
+    if (task._enhanceTextSelection) {
       var angleCos = 1, angleSin = 0;
       if (angle !== 0) {
         angleCos = Math.cos(angle);
         angleSin = Math.sin(angle);
       }
       var divWidth = (style.vertical ? geom.height : geom.width) *
-                     viewport.scale;
+                     task._viewport.scale;
       var divHeight = fontHeight;
 
       var m, b;
       if (angle !== 0) {
         m = [angleCos, angleSin, -angleSin, angleCos, left, top];
         b = Util.getAxialAlignedBoundingBox([0, 0, divWidth, divHeight], m);
       } else {
         b = [left, top, left + divWidth, top + divHeight];
       }
 
-      bounds.push({
+      task._bounds.push({
         left: b[0],
         top: b[1],
         right: b[2],
         bottom: b[3],
         div: textDiv,
         size: [divWidth, divHeight],
         m: m
       });
@@ -2947,63 +3012,66 @@ var renderTextLayer = (function renderTe
     var canvas = document.createElement('canvas');
     canvas.mozOpaque = true;
     var ctx = canvas.getContext('2d', {alpha: false});
 
     var lastFontSize;
     var lastFontFamily;
     for (var i = 0; i < textDivsLength; i++) {
       var textDiv = textDivs[i];
-      if (textDiv.dataset.isWhitespace !== undefined) {
+      var textDivProperties = task._textDivProperties.get(textDiv);
+      if (textDivProperties.isWhitespace) {
         continue;
       }
 
       var fontSize = textDiv.style.fontSize;
       var fontFamily = textDiv.style.fontFamily;
 
       // Only build font string and set to context if different from last.
       if (fontSize !== lastFontSize || fontFamily !== lastFontFamily) {
         ctx.font = fontSize + ' ' + fontFamily;
         lastFontSize = fontSize;
         lastFontFamily = fontFamily;
       }
 
       var width = ctx.measureText(textDiv.textContent).width;
-      textDiv.dataset.originalWidth = width;
       textLayerFrag.appendChild(textDiv);
-       var transform;
-       if (textDiv.dataset.canvasWidth !== undefined && width > 0) {
-        //  Dataset values come of type string.
-         var textScale = textDiv.dataset.canvasWidth / width;
-         transform = 'scaleX(' + textScale + ')';
-       } else {
-         transform = '';
-       }
-       var rotation = textDiv.dataset.angle;
-       if (rotation) {
-         transform = 'rotate(' + rotation + 'deg) ' + transform;
-       }
-       if (transform) {
-         textDiv.dataset.originalTransform = transform;
-         CustomStyle.setProp('transform' , textDiv, transform);
-       }
+
+      var transform = '';
+      if (textDivProperties.canvasWidth !== 0 && width > 0) {
+        textDivProperties.scale = textDivProperties.canvasWidth / width;
+        transform = 'scaleX(' + textDivProperties.scale + ')';
+      }
+      if (textDivProperties.angle !== 0) {
+        transform = 'rotate(' + textDivProperties.angle + 'deg) ' + transform;
+      }
+      if (transform !== '') {
+        textDivProperties.originalTransform = transform;
+        CustomStyle.setProp('transform', textDiv, transform);
+      }
+      task._textDivProperties.set(textDiv, textDivProperties);
     }
     task._renderingDone = true;
     capability.resolve();
   }
 
-  function expand(bounds, viewport) {
+  function expand(task) {
+    var bounds = task._bounds;
+    var viewport = task._viewport;
+
     var expanded = expandBounds(viewport.width, viewport.height, bounds);
     for (var i = 0; i < expanded.length; i++) {
       var div = bounds[i].div;
-      if (!div.dataset.angle) {
-        div.dataset.paddingLeft = bounds[i].left - expanded[i].left;
-        div.dataset.paddingTop = bounds[i].top - expanded[i].top;
-        div.dataset.paddingRight = expanded[i].right - bounds[i].right;
-        div.dataset.paddingBottom = expanded[i].bottom - bounds[i].bottom;
+      var divProperties = task._textDivProperties.get(div);
+      if (divProperties.angle === 0) {
+        divProperties.paddingLeft = bounds[i].left - expanded[i].left;
+        divProperties.paddingTop = bounds[i].top - expanded[i].top;
+        divProperties.paddingRight = expanded[i].right - bounds[i].right;
+        divProperties.paddingBottom = expanded[i].bottom - bounds[i].bottom;
+        task._textDivProperties.set(div, divProperties);
         continue;
       }
       // Box is rotated -- trying to find padding so rotated div will not
       // exceed its expanded bounds.
       var e = expanded[i], b = bounds[i];
       var m = b.m, c = m[0], s = m[1];
       // Finding intersections with expanded box.
       var points = [[0, 0], [0, b.size[1]], [b.size[0], 0], b.size];
@@ -3027,31 +3095,32 @@ var renderTextLayer = (function renderTe
 
         ts[i + 48] = s && (e.left - t[0]) / s;
         ts[i + 52] = c && (e.top - t[1]) / -c;
         ts[i + 56] = s && (e.right - t[0]) / s;
         ts[i + 60] = c && (e.bottom - t[1]) / -c;
       });
       var findPositiveMin = function (ts, offset, count) {
         var result = 0;
-          for (var i = 0; i < count; i++) {
-            var t = ts[offset++];
-            if (t > 0) {
-              result = result ? Math.min(t, result) : t;
-            }
+        for (var i = 0; i < count; i++) {
+          var t = ts[offset++];
+          if (t > 0) {
+            result = result ? Math.min(t, result) : t;
           }
-          return result;
+        }
+        return result;
       };
       // Not based on math, but to simplify calculations, using cos and sin
       // absolute values to not exceed the box (it can but insignificantly).
       var boxScale = 1 + Math.min(Math.abs(c), Math.abs(s));
-      div.dataset.paddingLeft = findPositiveMin(ts, 32, 16) / boxScale;
-      div.dataset.paddingTop = findPositiveMin(ts, 48, 16) / boxScale;
-      div.dataset.paddingRight = findPositiveMin(ts, 0, 16) / boxScale;
-      div.dataset.paddingBottom = findPositiveMin(ts, 16, 16) / boxScale;
+      divProperties.paddingLeft = findPositiveMin(ts, 32, 16) / boxScale;
+      divProperties.paddingTop = findPositiveMin(ts, 48, 16) / boxScale;
+      divProperties.paddingRight = findPositiveMin(ts, 0, 16) / boxScale;
+      divProperties.paddingBottom = findPositiveMin(ts, 16, 16) / boxScale;
+      task._textDivProperties.set(div, divProperties);
     }
   }
 
   function expandBounds(width, height, boxes) {
     var bounds = boxes.map(function (box, i) {
       return {
         x1: box.left,
         y1: box.top,
@@ -3263,18 +3332,18 @@ var renderTextLayer = (function renderTe
    * @param {boolean} enhanceTextSelection
    * @private
    */
   function TextLayerRenderTask(textContent, container, viewport, textDivs,
                                enhanceTextSelection) {
     this._textContent = textContent;
     this._container = container;
     this._viewport = viewport;
-    textDivs = textDivs || [];
-    this._textDivs = textDivs;
+    this._textDivs = textDivs || [];
+    this._textDivProperties = new WeakMap();
     this._renderingDone = false;
     this._canceled = false;
     this._capability = createPromiseCapability();
     this._renderTimer = null;
     this._bounds = [];
     this._enhanceTextSelection = !!enhanceTextSelection;
     this._expanded = false;
   }
@@ -3289,24 +3358,19 @@ var renderTextLayer = (function renderTe
         clearTimeout(this._renderTimer);
         this._renderTimer = null;
       }
       this._capability.reject('canceled');
     },
 
     _render: function TextLayer_render(timeout) {
       var textItems = this._textContent.items;
-      var styles = this._textContent.styles;
-      var textDivs = this._textDivs;
-      var viewport = this._viewport;
-      var enhanceTextSelection = this._enhanceTextSelection;
-
+      var textStyles = this._textContent.styles;
       for (var i = 0, len = textItems.length; i < len; i++) {
-        appendText(textDivs, viewport, textItems[i], styles, this._bounds,
-                   enhanceTextSelection);
+        appendText(this, textItems[i], textStyles);
       }
 
       if (!timeout) { // Render right away
         render(this);
       } else { // Schedule
         var self = this;
         this._renderTimer = setTimeout(function() {
           render(self);
@@ -3315,69 +3379,63 @@ var renderTextLayer = (function renderTe
       }
     },
 
     expandTextDivs: function TextLayer_expandTextDivs(expandDivs) {
       if (!this._enhanceTextSelection || !this._renderingDone) {
         return;
       }
       if (!this._expanded) {
-        expand(this._bounds, this._viewport);
+        expand(this);
         this._expanded = true;
         this._bounds.length = 0;
       }
-      if (expandDivs) {
-        for (var i = 0, ii = this._textDivs.length; i < ii; i++) {
-          var div = this._textDivs[i];
-          var transform;
-          var width = div.dataset.originalWidth;
-          if (div.dataset.canvasWidth !== undefined && width > 0) {
-            // Dataset values come of type string.
-            var textScale = div.dataset.canvasWidth / width;
-            transform = 'scaleX(' + textScale + ')';
-          } else {
-            transform = '';
+
+      for (var i = 0, ii = this._textDivs.length; i < ii; i++) {
+        var div = this._textDivs[i];
+        var divProperties = this._textDivProperties.get(div);
+
+        if (expandDivs) {
+          var transform = '';
+
+          if (divProperties.scale !== 1) {
+            transform = 'scaleX(' + divProperties.scale + ')';
           }
-          var rotation = div.dataset.angle;
-          if (rotation) {
-            transform = 'rotate(' + rotation + 'deg) ' + transform;
-          }
-          if (div.dataset.paddingLeft) {
-            div.style.paddingLeft =
-              (div.dataset.paddingLeft / textScale) + 'px';
-            transform += ' translateX(' +
-              (-div.dataset.paddingLeft / textScale) + 'px)';
+          if (divProperties.angle !== 0) {
+            transform = 'rotate(' + divProperties.angle + 'deg) ' + transform;
           }
-          if (div.dataset.paddingTop) {
-            div.style.paddingTop = div.dataset.paddingTop + 'px';
-            transform += ' translateY(' + (-div.dataset.paddingTop) + 'px)';
+          if (divProperties.paddingLeft !== 0) {
+            div.style.paddingLeft =
+              (divProperties.paddingLeft / divProperties.scale) + 'px';
+            transform += ' translateX(' +
+              (-divProperties.paddingLeft / divProperties.scale) + 'px)';
           }
-          if (div.dataset.paddingRight) {
-            div.style.paddingRight =
-            div.dataset.paddingRight / textScale + 'px';
-          }
-          if (div.dataset.paddingBottom) {
-            div.style.paddingBottom = div.dataset.paddingBottom + 'px';
+          if (divProperties.paddingTop !== 0) {
+            div.style.paddingTop = divProperties.paddingTop + 'px';
+            transform += ' translateY(' + (-divProperties.paddingTop) + 'px)';
           }
-          if (transform) {
-            CustomStyle.setProp('transform' , div, transform);
+          if (divProperties.paddingRight !== 0) {
+            div.style.paddingRight =
+              (divProperties.paddingRight / divProperties.scale) + 'px';
+          }
+          if (divProperties.paddingBottom !== 0) {
+            div.style.paddingBottom = divProperties.paddingBottom + 'px';
           }
-        }
-      } else {
-        for (i = 0, ii = this._textDivs.length; i < ii; i++) {
-          div = this._textDivs[i];
+          if (transform !== '') {
+            CustomStyle.setProp('transform', div, transform);
+          }
+        } else {
           div.style.padding = 0;
-          transform = div.dataset.originalTransform || '';
-          CustomStyle.setProp('transform', div, transform);
+          CustomStyle.setProp('transform', div,
+                              divProperties.originalTransform);
         }
       }
     },
   };
 
-
   /**
    * Starts rendering of the text layer.
    *
    * @param {TextLayerRenderParameters} renderParameters
    * @returns {TextLayerRenderTask}
    */
   function renderTextLayer(renderParameters) {
     var task = new TextLayerRenderTask(renderParameters.textContent,
@@ -6589,16 +6647,17 @@ var StatTimer = sharedUtil.StatTimer;
 var UnexpectedResponseException = sharedUtil.UnexpectedResponseException;
 var UnknownErrorException = sharedUtil.UnknownErrorException;
 var Util = sharedUtil.Util;
 var createPromiseCapability = sharedUtil.createPromiseCapability;
 var error = sharedUtil.error;
 var deprecated = sharedUtil.deprecated;
 var getVerbosityLevel = sharedUtil.getVerbosityLevel;
 var info = sharedUtil.info;
+var isInt = sharedUtil.isInt;
 var isArrayBuffer = sharedUtil.isArrayBuffer;
 var isSameOrigin = sharedUtil.isSameOrigin;
 var loadJpegStream = sharedUtil.loadJpegStream;
 var stringToBytes = sharedUtil.stringToBytes;
 var globalScope = sharedUtil.globalScope;
 var warn = sharedUtil.warn;
 var FontFaceObject = displayFontLoader.FontFaceObject;
 var FontLoader = displayFontLoader.FontLoader;
@@ -8110,17 +8169,17 @@ var WorkerTransport = (function WorkerTr
         if (loadingTask.onUnsupportedFeature) {
           loadingTask.onUnsupportedFeature(featureId);
         }
         _UnsupportedManager.notify(featureId);
       }, this);
 
       messageHandler.on('JpegDecode', function(data) {
         if (this.destroyed) {
-          return Promise.reject('Worker was terminated');
+          return Promise.reject(new Error('Worker was destroyed'));
         }
 
         var imageUrl = data[0];
         var components = data[1];
         if (components !== 3 && components !== 1) {
           return Promise.reject(
             new Error('Only 3 components or 1 component can be returned'));
         }
@@ -8160,18 +8219,17 @@ var WorkerTransport = (function WorkerTr
       }, this);
     },
 
     getData: function WorkerTransport_getData() {
       return this.messageHandler.sendWithPromise('GetData', null);
     },
 
     getPage: function WorkerTransport_getPage(pageNumber, capability) {
-      if (pageNumber <= 0 || pageNumber > this.numPages ||
-          (pageNumber|0) !== pageNumber) {
+      if (!isInt(pageNumber) || pageNumber <= 0 || pageNumber > this.numPages) {
         return Promise.reject(new Error('Invalid page request'));
       }
 
       var pageIndex = pageNumber - 1;
       if (pageIndex in this.pagePromises) {
         return this.pagePromises[pageIndex];
       }
       var promise = this.messageHandler.sendWithPromise('GetPage', {
@@ -8184,22 +8242,21 @@ var WorkerTransport = (function WorkerTr
         this.pageCache[pageIndex] = page;
         return page;
       }.bind(this));
       this.pagePromises[pageIndex] = promise;
       return promise;
     },
 
     getPageIndex: function WorkerTransport_getPageIndexByRef(ref) {
-      return this.messageHandler.sendWithPromise('GetPageIndex', { ref: ref }).
-        then(function (pageIndex) {
-          return pageIndex;
-        }, function (reason) {
-          return Promise.reject(new Error(reason));
-        });
+      return this.messageHandler.sendWithPromise('GetPageIndex', {
+        ref: ref,
+      }).catch(function (reason) {
+        return Promise.reject(new Error(reason));
+      });
     },
 
     getAnnotations: function WorkerTransport_getAnnotations(pageIndex, intent) {
       return this.messageHandler.sendWithPromise('GetAnnotations', {
         pageIndex: pageIndex,
         intent: intent,
       });
     },
@@ -8787,16 +8844,23 @@ exports._UnsupportedManager = _Unsupport
   /**
     * Determines if we can eval strings as JS. Primarily used to improve
     * performance for font rendering.
     * @var {boolean}
     */
   PDFJS.isEvalSupported = (PDFJS.isEvalSupported === undefined ?
                            true : PDFJS.isEvalSupported);
 
+  /**
+   * Renders interactive form elements.
+   * @var {boolean}
+   */
+  PDFJS.renderInteractiveForms = (PDFJS.renderInteractiveForms === undefined ?
+                                  false : PDFJS.renderInteractiveForms);
+
 
   PDFJS.getDocument = displayAPI.getDocument;
   PDFJS.PDFDataRangeTransport = displayAPI.PDFDataRangeTransport;
   PDFJS.PDFWorker = displayAPI.PDFWorker;
 
   Object.defineProperty(PDFJS, 'hasCanvasTypedArrays', {
     configurable: true,
     get: function PDFJS_hasCanvasTypedArrays() {
--- a/browser/extensions/pdfjs/content/build/pdf.worker.js
+++ b/browser/extensions/pdfjs/content/build/pdf.worker.js
@@ -23,18 +23,18 @@ define('pdfjs-dist/build/pdf.worker', ['
     factory(exports);
   } else {
 factory((root.pdfjsDistBuildPdfWorker = {}));
   }
 }(this, function (exports) {
   // Use strict in our context only - users might not want it
   'use strict';
 
-var pdfjsVersion = '1.5.413';
-var pdfjsBuild = '6bb95e3';
+var pdfjsVersion = '1.5.437';
+var pdfjsBuild = 'ca61ccc';
 
   var pdfjsFilePath =
     typeof document !== 'undefined' && document.currentScript ?
       document.currentScript.src : null;
 
   var pdfjsLibs = {};
 
   (function pdfjsWrapper() {
@@ -1022,1051 +1022,16 @@ exports.ExpertSubsetCharset = ExpertSubs
   exports.MacRomanEncoding = MacRomanEncoding;
   exports.SymbolSetEncoding = SymbolSetEncoding;
   exports.ZapfDingbatsEncoding = ZapfDingbatsEncoding;
   exports.ExpertEncoding = ExpertEncoding;
   exports.getEncoding = getEncoding;
 }));
 
 
-
-(function (root, factory) {
-  {
-    factory((root.pdfjsCoreJpg = {}));
-  }
-}(this, function (exports) {
-
-/*
-This code was forked from https://github.com/notmasteryet/jpgjs. The original
-version was created by github user notmasteryet
-
-- The JPEG specification can be found in the ITU CCITT Recommendation T.81
- (www.w3.org/Graphics/JPEG/itu-t81.pdf)
-- The JFIF specification can be found in the JPEG File Interchange Format
- (www.w3.org/Graphics/JPEG/jfif3.pdf)
-- The Adobe Application-Specific JPEG markers in the Supporting the DCT Filters
- in PostScript Level 2, Technical Note #5116
- (partners.adobe.com/public/developer/en/ps/sdk/5116.DCT_Filter.pdf)
-*/
-
-var JpegImage = (function jpegImage() {
-  var dctZigZag = new Uint8Array([
-     0,
-     1,  8,
-    16,  9,  2,
-     3, 10, 17, 24,
-    32, 25, 18, 11, 4,
-     5, 12, 19, 26, 33, 40,
-    48, 41, 34, 27, 20, 13,  6,
-     7, 14, 21, 28, 35, 42, 49, 56,
-    57, 50, 43, 36, 29, 22, 15,
-    23, 30, 37, 44, 51, 58,
-    59, 52, 45, 38, 31,
-    39, 46, 53, 60,
-    61, 54, 47,
-    55, 62,
-    63
-  ]);
-
-  var dctCos1  =  4017;   // cos(pi/16)
-  var dctSin1  =   799;   // sin(pi/16)
-  var dctCos3  =  3406;   // cos(3*pi/16)
-  var dctSin3  =  2276;   // sin(3*pi/16)
-  var dctCos6  =  1567;   // cos(6*pi/16)
-  var dctSin6  =  3784;   // sin(6*pi/16)
-  var dctSqrt2 =  5793;   // sqrt(2)
-  var dctSqrt1d2 = 2896;  // sqrt(2) / 2
-
-  function constructor() {
-  }
-
-  function buildHuffmanTable(codeLengths, values) {
-    var k = 0, code = [], i, j, length = 16;
-    while (length > 0 && !codeLengths[length - 1]) {
-      length--;
-    }
-    code.push({children: [], index: 0});
-    var p = code[0], q;
-    for (i = 0; i < length; i++) {
-      for (j = 0; j < codeLengths[i]; j++) {
-        p = code.pop();
-        p.children[p.index] = values[k];
-        while (p.index > 0) {
-          p = code.pop();
-        }
-        p.index++;
-        code.push(p);
-        while (code.length <= i) {
-          code.push(q = {children: [], index: 0});
-          p.children[p.index] = q.children;
-          p = q;
-        }
-        k++;
-      }
-      if (i + 1 < length) {
-        // p here points to last code
-        code.push(q = {children: [], index: 0});
-        p.children[p.index] = q.children;
-        p = q;
-      }
-    }
-    return code[0].children;
-  }
-
-  function getBlockBufferOffset(component, row, col) {
-    return 64 * ((component.blocksPerLine + 1) * row + col);
-  }
-
-  function decodeScan(data, offset, frame, components, resetInterval,
-                      spectralStart, spectralEnd, successivePrev, successive) {
-    var mcusPerLine = frame.mcusPerLine;
-    var progressive = frame.progressive;
-
-    var startOffset = offset, bitsData = 0, bitsCount = 0;
-
-    function readBit() {
-      if (bitsCount > 0) {
-        bitsCount--;
-        return (bitsData >> bitsCount) & 1;
-      }
-      bitsData = data[offset++];
-      if (bitsData === 0xFF) {
-        var nextByte = data[offset++];
-        if (nextByte) {
-          throw 'unexpected marker: ' +
-            ((bitsData << 8) | nextByte).toString(16);
-        }
-        // unstuff 0
-      }
-      bitsCount = 7;
-      return bitsData >>> 7;
-    }
-
-    function decodeHuffman(tree) {
-      var node = tree;
-      while (true) {
-        node = node[readBit()];
-        if (typeof node === 'number') {
-          return node;
-        }
-        if (typeof node !== 'object') {
-          throw 'invalid huffman sequence';
-        }
-      }
-    }
-
-    function receive(length) {
-      var n = 0;
-      while (length > 0) {
-        n = (n << 1) | readBit();
-        length--;
-      }
-      return n;
-    }
-
-    function receiveAndExtend(length) {
-      if (length === 1) {
-        return readBit() === 1 ? 1 : -1;
-      }
-      var n = receive(length);
-      if (n >= 1 << (length - 1)) {
-        return n;
-      }
-      return n + (-1 << length) + 1;
-    }
-
-    function decodeBaseline(component, offset) {
-      var t = decodeHuffman(component.huffmanTableDC);
-      var diff = t === 0 ? 0 : receiveAndExtend(t);
-      component.blockData[offset] = (component.pred += diff);
-      var k = 1;
-      while (k < 64) {
-        var rs = decodeHuffman(component.huffmanTableAC);
-        var s = rs & 15, r = rs >> 4;
-        if (s === 0) {
-          if (r < 15) {
-            break;
-          }
-          k += 16;
-          continue;
-        }
-        k += r;
-        var z = dctZigZag[k];
-        component.blockData[offset + z] = receiveAndExtend(s);
-        k++;
-      }
-    }
-
-    function decodeDCFirst(component, offset) {
-      var t = decodeHuffman(component.huffmanTableDC);
-      var diff = t === 0 ? 0 : (receiveAndExtend(t) << successive);
-      component.blockData[offset] = (component.pred += diff);
-    }
-
-    function decodeDCSuccessive(component, offset) {
-      component.blockData[offset] |= readBit() << successive;
-    }
-
-    var eobrun = 0;
-    function decodeACFirst(component, offset) {
-      if (eobrun > 0) {
-        eobrun--;
-        return;
-      }
-      var k = spectralStart, e = spectralEnd;
-      while (k <= e) {
-        var rs = decodeHuffman(component.huffmanTableAC);
-        var s = rs & 15, r = rs >> 4;
-        if (s === 0) {
-          if (r < 15) {
-            eobrun = receive(r) + (1 << r) - 1;
-            break;
-          }
-          k += 16;
-          continue;
-        }
-        k += r;
-        var z = dctZigZag[k];
-        component.blockData[offset + z] =
-          receiveAndExtend(s) * (1 << successive);
-        k++;
-      }
-    }
-
-    var successiveACState = 0, successiveACNextValue;
-    function decodeACSuccessive(component, offset) {
-      var k = spectralStart;
-      var e = spectralEnd;
-      var r = 0;
-      var s;
-      var rs;
-      while (k <= e) {
-        var z = dctZigZag[k];
-        switch (successiveACState) {
-        case 0: // initial state
-          rs = decodeHuffman(component.huffmanTableAC);
-          s = rs & 15;
-          r = rs >> 4;
-          if (s === 0) {
-            if (r < 15) {
-              eobrun = receive(r) + (1 << r);
-              successiveACState = 4;
-            } else {
-              r = 16;
-              successiveACState = 1;
-            }
-          } else {
-            if (s !== 1) {
-              throw 'invalid ACn encoding';
-            }
-            successiveACNextValue = receiveAndExtend(s);
-            successiveACState = r ? 2 : 3;
-          }
-          continue;
-        case 1: // skipping r zero items
-        case 2:
-          if (component.blockData[offset + z]) {
-            component.blockData[offset + z] += (readBit() << successive);
-          } else {
-            r--;
-            if (r === 0) {
-              successiveACState = successiveACState === 2 ? 3 : 0;
-            }
-          }
-          break;
-        case 3: // set value for a zero item
-          if (component.blockData[offset + z]) {
-            component.blockData[offset + z] += (readBit() << successive);
-          } else {
-            component.blockData[offset + z] =
-              successiveACNextValue << successive;
-            successiveACState = 0;
-          }
-          break;
-        case 4: // eob
-          if (component.blockData[offset + z]) {
-            component.blockData[offset + z] += (readBit() << successive);
-          }
-          break;
-        }
-        k++;
-      }
-      if (successiveACState === 4) {
-        eobrun--;
-        if (eobrun === 0) {
-          successiveACState = 0;
-        }
-      }
-    }
-
-    function decodeMcu(component, decode, mcu, row, col) {
-      var mcuRow = (mcu / mcusPerLine) | 0;
-      var mcuCol = mcu % mcusPerLine;
-      var blockRow = mcuRow * component.v + row;
-      var blockCol = mcuCol * component.h + col;
-      var offset = getBlockBufferOffset(component, blockRow, blockCol);
-      decode(component, offset);
-    }
-
-    function decodeBlock(component, decode, mcu) {
-      var blockRow = (mcu / component.blocksPerLine) | 0;
-      var blockCol = mcu % component.blocksPerLine;
-      var offset = getBlockBufferOffset(component, blockRow, blockCol);
-      decode(component, offset);
-    }
-
-    var componentsLength = components.length;
-    var component, i, j, k, n;
-    var decodeFn;
-    if (progressive) {
-      if (spectralStart === 0) {
-        decodeFn = successivePrev === 0 ? decodeDCFirst : decodeDCSuccessive;
-      } else {
-        decodeFn = successivePrev === 0 ? decodeACFirst : decodeACSuccessive;
-      }
-    } else {
-      decodeFn = decodeBaseline;
-    }
-
-    var mcu = 0, marker;
-    var mcuExpected;
-    if (componentsLength === 1) {
-      mcuExpected = components[0].blocksPerLine * components[0].blocksPerColumn;
-    } else {
-      mcuExpected = mcusPerLine * frame.mcusPerColumn;
-    }
-    if (!resetInterval) {
-      resetInterval = mcuExpected;
-    }
-
-    var h, v;
-    while (mcu < mcuExpected) {
-      // reset interval stuff
-      for (i = 0; i < componentsLength; i++) {
-        components[i].pred = 0;
-      }
-      eobrun = 0;
-
-      if (componentsLength === 1) {
-        component = components[0];
-        for (n = 0; n < resetInterval; n++) {
-          decodeBlock(component, decodeFn, mcu);
-          mcu++;
-        }
-      } else {
-        for (n = 0; n < resetInterval; n++) {
-          for (i = 0; i < componentsLength; i++) {
-            component = components[i];
-            h = component.h;
-            v = component.v;
-            for (j = 0; j < v; j++) {
-              for (k = 0; k < h; k++) {
-                decodeMcu(component, decodeFn, mcu, j, k);
-              }
-            }
-          }
-          mcu++;
-        }
-      }
-
-      // find marker
-      bitsCount = 0;
-      marker = (data[offset] << 8) | data[offset + 1];
-      if (marker <= 0xFF00) {
-        throw 'marker was not found';
-      }
-
-      if (marker >= 0xFFD0 && marker <= 0xFFD7) { // RSTx
-        offset += 2;
-      } else {
-        break;
-      }
-    }
-
-    return offset - startOffset;
-  }
-
-  // A port of poppler's IDCT method which in turn is taken from:
-  //   Christoph Loeffler, Adriaan Ligtenberg, George S. Moschytz,
-  //   'Practical Fast 1-D DCT Algorithms with 11 Multiplications',
-  //   IEEE Intl. Conf. on Acoustics, Speech & Signal Processing, 1989,
-  //   988-991.
-  function quantizeAndInverse(component, blockBufferOffset, p) {
-    var qt = component.quantizationTable, blockData = component.blockData;
-    var v0, v1, v2, v3, v4, v5, v6, v7;
-    var p0, p1, p2, p3, p4, p5, p6, p7;
-    var t;
-
-    // inverse DCT on rows
-    for (var row = 0; row < 64; row += 8) {
-      // gather block data
-      p0 = blockData[blockBufferOffset + row];
-      p1 = blockData[blockBufferOffset + row + 1];
-      p2 = blockData[blockBufferOffset + row + 2];
-      p3 = blockData[blockBufferOffset + row + 3];
-      p4 = blockData[blockBufferOffset + row + 4];
-      p5 = blockData[blockBufferOffset + row + 5];
-      p6 = blockData[blockBufferOffset + row + 6];
-      p7 = blockData[blockBufferOffset + row + 7];
-
-      // dequant p0
-      p0 *= qt[row];
-
-      // check for all-zero AC coefficients
-      if ((p1 | p2 | p3 | p4 | p5 | p6 | p7) === 0) {
-        t = (dctSqrt2 * p0 + 512) >> 10;
-        p[row] = t;
-        p[row + 1] = t;
-        p[row + 2] = t;
-        p[row + 3] = t;
-        p[row + 4] = t;
-        p[row + 5] = t;
-        p[row + 6] = t;
-        p[row + 7] = t;
-        continue;
-      }
-      // dequant p1 ... p7
-      p1 *= qt[row + 1];
-      p2 *= qt[row + 2];
-      p3 *= qt[row + 3];
-      p4 *= qt[row + 4];
-      p5 *= qt[row + 5];
-      p6 *= qt[row + 6];
-      p7 *= qt[row + 7];
-
-      // stage 4
-      v0 = (dctSqrt2 * p0 + 128) >> 8;
-      v1 = (dctSqrt2 * p4 + 128) >> 8;
-      v2 = p2;
-      v3 = p6;
-      v4 = (dctSqrt1d2 * (p1 - p7) + 128) >> 8;
-      v7 = (dctSqrt1d2 * (p1 + p7) + 128) >> 8;
-      v5 = p3 << 4;
-      v6 = p5 << 4;
-
-      // stage 3
-      v0 = (v0 + v1 + 1) >> 1;
-      v1 = v0 - v1;
-      t  = (v2 * dctSin6 + v3 * dctCos6 + 128) >> 8;
-      v2 = (v2 * dctCos6 - v3 * dctSin6 + 128) >> 8;
-      v3 = t;
-      v4 = (v4 + v6 + 1) >> 1;
-      v6 = v4 - v6;
-      v7 = (v7 + v5 + 1) >> 1;
-      v5 = v7 - v5;
-
-      // stage 2
-      v0 = (v0 + v3 + 1) >> 1;
-      v3 = v0 - v3;
-      v1 = (v1 + v2 + 1) >> 1;
-      v2 = v1 - v2;
-      t  = (v4 * dctSin3 + v7 * dctCos3 + 2048) >> 12;
-      v4 = (v4 * dctCos3 - v7 * dctSin3 + 2048) >> 12;
-      v7 = t;
-      t  = (v5 * dctSin1 + v6 * dctCos1 + 2048) >> 12;
-      v5 = (v5 * dctCos1 - v6 * dctSin1 + 2048) >> 12;
-      v6 = t;
-
-      // stage 1
-      p[row] = v0 + v7;
-      p[row + 7] = v0 - v7;
-      p[row + 1] = v1 + v6;
-      p[row + 6] = v1 - v6;
-      p[row + 2] = v2 + v5;
-      p[row + 5] = v2 - v5;
-      p[row + 3] = v3 + v4;
-      p[row + 4] = v3 - v4;
-    }
-
-    // inverse DCT on columns
-    for (var col = 0; col < 8; ++col) {
-      p0 = p[col];
-      p1 = p[col +  8];
-      p2 = p[col + 16];
-      p3 = p[col + 24];
-      p4 = p[col + 32];
-      p5 = p[col + 40];
-      p6 = p[col + 48];
-      p7 = p[col + 56];
-
-      // check for all-zero AC coefficients
-      if ((p1 | p2 | p3 | p4 | p5 | p6 | p7) === 0) {
-        t = (dctSqrt2 * p0 + 8192) >> 14;
-        // convert to 8 bit
-        t = (t < -2040) ? 0 : (t >= 2024) ? 255 : (t + 2056) >> 4;
-        blockData[blockBufferOffset + col] = t;
-        blockData[blockBufferOffset + col +  8] = t;
-        blockData[blockBufferOffset + col + 16] = t;
-        blockData[blockBufferOffset + col + 24] = t;
-        blockData[blockBufferOffset + col + 32] = t;
-        blockData[blockBufferOffset + col + 40] = t;
-        blockData[blockBufferOffset + col + 48] = t;
-        blockData[blockBufferOffset + col + 56] = t;
-        continue;
-      }
-
-      // stage 4
-      v0 = (dctSqrt2 * p0 + 2048) >> 12;
-      v1 = (dctSqrt2 * p4 + 2048) >> 12;
-      v2 = p2;
-      v3 = p6;
-      v4 = (dctSqrt1d2 * (p1 - p7) + 2048) >> 12;
-      v7 = (dctSqrt1d2 * (p1 + p7) + 2048) >> 12;
-      v5 = p3;
-      v6 = p5;
-
-      // stage 3
-      // Shift v0 by 128.5 << 5 here, so we don't need to shift p0...p7 when
-      // converting to UInt8 range later.
-      v0 = ((v0 + v1 + 1) >> 1) + 4112;
-      v1 = v0 - v1;
-      t  = (v2 * dctSin6 + v3 * dctCos6 + 2048) >> 12;
-      v2 = (v2 * dctCos6 - v3 * dctSin6 + 2048) >> 12;
-      v3 = t;
-      v4 = (v4 + v6 + 1) >> 1;
-      v6 = v4 - v6;
-      v7 = (v7 + v5 + 1) >> 1;
-      v5 = v7 - v5;
-
-      // stage 2
-      v0 = (v0 + v3 + 1) >> 1;
-      v3 = v0 - v3;
-      v1 = (v1 + v2 + 1) >> 1;
-      v2 = v1 - v2;
-      t  = (v4 * dctSin3 + v7 * dctCos3 + 2048) >> 12;
-      v4 = (v4 * dctCos3 - v7 * dctSin3 + 2048) >> 12;
-      v7 = t;
-      t  = (v5 * dctSin1 + v6 * dctCos1 + 2048) >> 12;
-      v5 = (v5 * dctCos1 - v6 * dctSin1 + 2048) >> 12;
-      v6 = t;
-
-      // stage 1
-      p0 = v0 + v7;
-      p7 = v0 - v7;
-      p1 = v1 + v6;
-      p6 = v1 - v6;
-      p2 = v2 + v5;
-      p5 = v2 - v5;
-      p3 = v3 + v4;
-      p4 = v3 - v4;
-
-      // convert to 8-bit integers
-      p0 = (p0 < 16) ? 0 : (p0 >= 4080) ? 255 : p0 >> 4;
-      p1 = (p1 < 16) ? 0 : (p1 >= 4080) ? 255 : p1 >> 4;
-      p2 = (p2 < 16) ? 0 : (p2 >= 4080) ? 255 : p2 >> 4;
-      p3 = (p3 < 16) ? 0 : (p3 >= 4080) ? 255 : p3 >> 4;
-      p4 = (p4 < 16) ? 0 : (p4 >= 4080) ? 255 : p4 >> 4;
-      p5 = (p5 < 16) ? 0 : (p5 >= 4080) ? 255 : p5 >> 4;
-      p6 = (p6 < 16) ? 0 : (p6 >= 4080) ? 255 : p6 >> 4;
-      p7 = (p7 < 16) ? 0 : (p7 >= 4080) ? 255 : p7 >> 4;
-
-      // store block data
-      blockData[blockBufferOffset + col] = p0;
-      blockData[blockBufferOffset + col +  8] = p1;
-      blockData[blockBufferOffset + col + 16] = p2;
-      blockData[blockBufferOffset + col + 24] = p3;
-      blockData[blockBufferOffset + col + 32] = p4;
-      blockData[blockBufferOffset + col + 40] = p5;
-      blockData[blockBufferOffset + col + 48] = p6;
-      blockData[blockBufferOffset + col + 56] = p7;
-    }
-  }
-
-  function buildComponentData(frame, component) {
-    var blocksPerLine = component.blocksPerLine;
-    var blocksPerColumn = component.blocksPerColumn;
-    var computationBuffer = new Int16Array(64);
-
-    for (var blockRow = 0; blockRow < blocksPerColumn; blockRow++) {
-      for (var blockCol = 0; blockCol < blocksPerLine; blockCol++) {
-        var offset = getBlockBufferOffset(component, blockRow, blockCol);
-        quantizeAndInverse(component, offset, computationBuffer);
-      }
-    }
-    return component.blockData;
-  }
-
-  function clamp0to255(a) {
-    return a <= 0 ? 0 : a >= 255 ? 255 : a;
-  }
-
-  constructor.prototype = {
-    parse: function parse(data) {
-
-      function readUint16() {
-        var value = (data[offset] << 8) | data[offset + 1];
-        offset += 2;
-        return value;
-      }
-
-      function readDataBlock() {
-        var length = readUint16();
-        var array = data.subarray(offset, offset + length - 2);
-        offset += array.length;
-        return array;
-      }
-
-      function prepareComponents(frame) {
-        var mcusPerLine = Math.ceil(frame.samplesPerLine / 8 / frame.maxH);
-        var mcusPerColumn = Math.ceil(frame.scanLines / 8 / frame.maxV);
-        for (var i = 0; i < frame.components.length; i++) {
-          component = frame.components[i];
-          var blocksPerLine = Math.ceil(Math.ceil(frame.samplesPerLine / 8) *
-                                        component.h / frame.maxH);
-          var blocksPerColumn = Math.ceil(Math.ceil(frame.scanLines  / 8) *
-                                          component.v / frame.maxV);
-          var blocksPerLineForMcu = mcusPerLine * component.h;
-          var blocksPerColumnForMcu = mcusPerColumn * component.v;
-
-          var blocksBufferSize = 64 * blocksPerColumnForMcu *
-                                      (blocksPerLineForMcu + 1);
-          component.blockData = new Int16Array(blocksBufferSize);
-          component.blocksPerLine = blocksPerLine;
-          component.blocksPerColumn = blocksPerColumn;
-        }
-        frame.mcusPerLine = mcusPerLine;
-        frame.mcusPerColumn = mcusPerColumn;
-      }
-
-      var offset = 0;
-      var jfif = null;
-      var adobe = null;
-      var frame, resetInterval;
-      var quantizationTables = [];
-      var huffmanTablesAC = [], huffmanTablesDC = [];
-      var fileMarker = readUint16();
-      if (fileMarker !== 0xFFD8) { // SOI (Start of Image)
-        throw 'SOI not found';
-      }
-
-      fileMarker = readUint16();
-      while (fileMarker !== 0xFFD9) { // EOI (End of image)
-        var i, j, l;
-        switch(fileMarker) {
-          case 0xFFE0: // APP0 (Application Specific)
-          case 0xFFE1: // APP1
-          case 0xFFE2: // APP2
-          case 0xFFE3: // APP3
-          case 0xFFE4: // APP4
-          case 0xFFE5: // APP5
-          case 0xFFE6: // APP6
-          case 0xFFE7: // APP7
-          case 0xFFE8: // APP8
-          case 0xFFE9: // APP9
-          case 0xFFEA: // APP10
-          case 0xFFEB: // APP11
-          case 0xFFEC: // APP12
-          case 0xFFED: // APP13
-          case 0xFFEE: // APP14
-          case 0xFFEF: // APP15
-          case 0xFFFE: // COM (Comment)
-            var appData = readDataBlock();
-
-            if (fileMarker === 0xFFE0) {
-              if (appData[0] === 0x4A && appData[1] === 0x46 &&
-                  appData[2] === 0x49 && appData[3] === 0x46 &&
-                  appData[4] === 0) { // 'JFIF\x00'
-                jfif = {
-                  version: { major: appData[5], minor: appData[6] },
-                  densityUnits: appData[7],
-                  xDensity: (appData[8] << 8) | appData[9],
-                  yDensity: (appData[10] << 8) | appData[11],
-                  thumbWidth: appData[12],
-                  thumbHeight: appData[13],
-                  thumbData: appData.subarray(14, 14 +
-                                              3 * appData[12] * appData[13])
-                };
-              }
-            }
-            // TODO APP1 - Exif
-            if (fileMarker === 0xFFEE) {
-              if (appData[0] === 0x41 && appData[1] === 0x64 &&
-                  appData[2] === 0x6F && appData[3] === 0x62 &&
-                  appData[4] === 0x65) { // 'Adobe'
-                adobe = {
-                  version: (appData[5] << 8) | appData[6],
-                  flags0: (appData[7] << 8) | appData[8],
-                  flags1: (appData[9] << 8) | appData[10],
-                  transformCode: appData[11]
-                };
-              }
-            }
-            break;
-
-          case 0xFFDB: // DQT (Define Quantization Tables)
-            var quantizationTablesLength = readUint16();
-            var quantizationTablesEnd = quantizationTablesLength + offset - 2;
-            var z;
-            while (offset < quantizationTablesEnd) {
-              var quantizationTableSpec = data[offset++];
-              var tableData = new Uint16Array(64);
-              if ((quantizationTableSpec >> 4) === 0) { // 8 bit values
-                for (j = 0; j < 64; j++) {
-                  z = dctZigZag[j];
-                  tableData[z] = data[offset++];
-                }
-              } else if ((quantizationTableSpec >> 4) === 1) { //16 bit
-                for (j = 0; j < 64; j++) {
-                  z = dctZigZag[j];
-                  tableData[z] = readUint16();
-                }
-              } else {
-                throw 'DQT: invalid table spec';
-              }
-              quantizationTables[quantizationTableSpec & 15] = tableData;
-            }
-            break;
-
-          case 0xFFC0: // SOF0 (Start of Frame, Baseline DCT)
-          case 0xFFC1: // SOF1 (Start of Frame, Extended DCT)
-          case 0xFFC2: // SOF2 (Start of Frame, Progressive DCT)
-            if (frame) {
-              throw 'Only single frame JPEGs supported';
-            }
-            readUint16(); // skip data length
-            frame = {};
-            frame.extended = (fileMarker === 0xFFC1);
-            frame.progressive = (fileMarker === 0xFFC2);
-            frame.precision = data[offset++];
-            frame.scanLines = readUint16();
-            frame.samplesPerLine = readUint16();
-            frame.components = [];
-            frame.componentIds = {};
-            var componentsCount = data[offset++], componentId;
-            var maxH = 0, maxV = 0;
-            for (i = 0; i < componentsCount; i++) {
-              componentId = data[offset];
-              var h = data[offset + 1] >> 4;
-              var v = data[offset + 1] & 15;
-              if (maxH < h) {
-                maxH = h;
-              }
-              if (maxV < v) {
-                maxV = v;
-              }
-              var qId = data[offset + 2];
-              l = frame.components.push({
-                h: h,
-                v: v,
-                quantizationTable: quantizationTables[qId]
-              });
-              frame.componentIds[componentId] = l - 1;
-              offset += 3;
-            }
-            frame.maxH = maxH;
-            frame.maxV = maxV;
-            prepareComponents(frame);
-            break;
-
-          case 0xFFC4: // DHT (Define Huffman Tables)
-            var huffmanLength = readUint16();
-            for (i = 2; i < huffmanLength;) {
-              var huffmanTableSpec = data[offset++];
-              var codeLengths = new Uint8Array(16);
-              var codeLengthSum = 0;
-              for (j = 0; j < 16; j++, offset++) {
-                codeLengthSum += (codeLengths[j] = data[offset]);
-              }
-              var huffmanValues = new Uint8Array(codeLengthSum);
-              for (j = 0; j < codeLengthSum; j++, offset++) {
-                huffmanValues[j] = data[offset];
-              }
-              i += 17 + codeLengthSum;
-
-              ((huffmanTableSpec >> 4) === 0 ?
-                huffmanTablesDC : huffmanTablesAC)[huffmanTableSpec & 15] =
-                buildHuffmanTable(codeLengths, huffmanValues);
-            }
-            break;
-
-          case 0xFFDD: // DRI (Define Restart Interval)
-            readUint16(); // skip data length
-            resetInterval = readUint16();
-            break;
-
-          case 0xFFDA: // SOS (Start of Scan)
-            var scanLength = readUint16();
-            var selectorsCount = data[offset++];
-            var components = [], component;
-            for (i = 0; i < selectorsCount; i++) {
-              var componentIndex = frame.componentIds[data[offset++]];
-              component = frame.components[componentIndex];
-              var tableSpec = data[offset++];
-              component.huffmanTableDC = huffmanTablesDC[tableSpec >> 4];
-              component.huffmanTableAC = huffmanTablesAC[tableSpec & 15];
-              components.push(component);
-            }
-            var spectralStart = data[offset++];
-            var spectralEnd = data[offset++];
-            var successiveApproximation = data[offset++];
-            var processed = decodeScan(data, offset,
-              frame, components, resetInterval,
-              spectralStart, spectralEnd,
-              successiveApproximation >> 4, successiveApproximation & 15);
-            offset += processed;
-            break;
-
-          case 0xFFFF: // Fill bytes
-            if (data[offset] !== 0xFF) { // Avoid skipping a valid marker.
-              offset--;
-            }
-            break;
-
-          default:
-            if (data[offset - 3] === 0xFF &&
-                data[offset - 2] >= 0xC0 && data[offset - 2] <= 0xFE) {
-              // could be incorrect encoding -- last 0xFF byte of the previous
-              // block was eaten by the encoder
-              offset -= 3;
-              break;
-            }
-            throw 'unknown JPEG marker ' + fileMarker.toString(16);
-        }
-        fileMarker = readUint16();
-      }
-
-      this.width = frame.samplesPerLine;
-      this.height = frame.scanLines;
-      this.jfif = jfif;
-      this.adobe = adobe;
-      this.components = [];
-      for (i = 0; i < frame.components.length; i++) {
-        component = frame.components[i];
-        this.components.push({
-          output: buildComponentData(frame, component),
-          scaleX: component.h / frame.maxH,
-          scaleY: component.v / frame.maxV,
-          blocksPerLine: component.blocksPerLine,
-          blocksPerColumn: component.blocksPerColumn
-        });
-      }
-      this.numComponents = this.components.length;
-    },
-
-    _getLinearizedBlockData: function getLinearizedBlockData(width, height) {
-      var scaleX = this.width / width, scaleY = this.height / height;
-
-      var component, componentScaleX, componentScaleY, blocksPerScanline;
-      var x, y, i, j, k;
-      var index;
-      var offset = 0;
-      var output;
-      var numComponents = this.components.length;
-      var dataLength = width * height * numComponents;
-      var data = new Uint8Array(dataLength);
-      var xScaleBlockOffset = new Uint32Array(width);
-      var mask3LSB = 0xfffffff8; // used to clear the 3 LSBs
-
-      for (i = 0; i < numComponents; i++) {
-        component = this.components[i];
-        componentScaleX = component.scaleX * scaleX;
-        componentScaleY = component.scaleY * scaleY;
-        offset = i;
-        output = component.output;
-        blocksPerScanline = (component.blocksPerLine + 1) << 3;
-        // precalculate the xScaleBlockOffset
-        for (x = 0; x < width; x++) {
-          j = 0 | (x * componentScaleX);
-          xScaleBlockOffset[x] = ((j & mask3LSB) << 3) | (j & 7);
-        }
-        // linearize the blocks of the component
-        for (y = 0; y < height; y++) {
-          j = 0 | (y * componentScaleY);
-          index = blocksPerScanline * (j & mask3LSB) | ((j & 7) << 3);
-          for (x = 0; x < width; x++) {
-            data[offset] = output[index + xScaleBlockOffset[x]];
-            offset += numComponents;
-          }
-        }
-      }
-
-      // decodeTransform contains pairs of multiplier (-256..256) and additive
-      var transform = this.decodeTransform;
-      if (transform) {
-        for (i = 0; i < dataLength;) {
-          for (j = 0, k = 0; j < numComponents; j++, i++, k += 2) {
-            data[i] = ((data[i] * transform[k]) >> 8) + transform[k + 1];
-          }
-        }
-      }
-      return data;
-    },
-
-    _isColorConversionNeeded: function isColorConversionNeeded() {
-      if (this.adobe && this.adobe.transformCode) {
-        // The adobe transform marker overrides any previous setting
-        return true;
-      } else if (this.numComponents === 3) {
-        return true;
-      } else {
-        return false;
-      }
-    },
-
-    _convertYccToRgb: function convertYccToRgb(data) {
-      var Y, Cb, Cr;
-      for (var i = 0, length = data.length; i < length; i += 3) {
-        Y  = data[i    ];
-        Cb = data[i + 1];
-        Cr = data[i + 2];
-        data[i    ] = clamp0to255(Y - 179.456 + 1.402 * Cr);
-        data[i + 1] = clamp0to255(Y + 135.459 - 0.344 * Cb - 0.714 * Cr);
-        data[i + 2] = clamp0to255(Y - 226.816 + 1.772 * Cb);
-      }
-      return data;
-    },
-
-    _convertYcckToRgb: function convertYcckToRgb(data) {
-      var Y, Cb, Cr, k;
-      var offset = 0;
-      for (var i = 0, length = data.length; i < length; i += 4) {
-        Y  = data[i];
-        Cb = data[i + 1];
-        Cr = data[i + 2];
-        k = data[i + 3];
-
-        var r = -122.67195406894 +
-          Cb * (-6.60635669420364e-5 * Cb + 0.000437130475926232 * Cr -
-                5.4080610064599e-5 * Y + 0.00048449797120281 * k -
-                0.154362151871126) +
-          Cr * (-0.000957964378445773 * Cr + 0.000817076911346625 * Y -
-                0.00477271405408747 * k + 1.53380253221734) +
-          Y * (0.000961250184130688 * Y - 0.00266257332283933 * k +
-               0.48357088451265) +
-          k * (-0.000336197177618394 * k + 0.484791561490776);
-
-        var g = 107.268039397724 +
-          Cb * (2.19927104525741e-5 * Cb - 0.000640992018297945 * Cr +
-                0.000659397001245577 * Y + 0.000426105652938837 * k -
-                0.176491792462875) +
-          Cr * (-0.000778269941513683 * Cr + 0.00130872261408275 * Y +
-                0.000770482631801132 * k - 0.151051492775562) +
-          Y * (0.00126935368114843 * Y - 0.00265090189010898 * k +
-               0.25802910206845) +
-          k * (-0.000318913117588328 * k - 0.213742400323665);
-
-        var b = -20.810012546947 +
-          Cb * (-0.000570115196973677 * Cb - 2.63409051004589e-5 * Cr +
-                0.0020741088115012 * Y - 0.00288260236853442 * k +
-                0.814272968359295) +
-          Cr * (-1.53496057440975e-5 * Cr - 0.000132689043961446 * Y +
-                0.000560833691242812 * k - 0.195152027534049) +
-          Y * (0.00174418132927582 * Y - 0.00255243321439347 * k +
-               0.116935020465145) +
-          k * (-0.000343531996510555 * k + 0.24165260232407);
-
-        data[offset++] = clamp0to255(r);
-        data[offset++] = clamp0to255(g);
-        data[offset++] = clamp0to255(b);
-      }
-      return data;
-    },
-
-    _convertYcckToCmyk: function convertYcckToCmyk(data) {
-      var Y, Cb, Cr;
-      for (var i = 0, length = data.length; i < length; i += 4) {
-        Y  = data[i];
-        Cb = data[i + 1];
-        Cr = data[i + 2];
-        data[i    ] = clamp0to255(434.456 - Y - 1.402 * Cr);
-        data[i + 1] = clamp0to255(119.541 - Y + 0.344 * Cb + 0.714 * Cr);
-        data[i + 2] = clamp0to255(481.816 - Y - 1.772 * Cb);
-        // K in data[i + 3] is unchanged
-      }
-      return data;
-    },
-
-    _convertCmykToRgb: function convertCmykToRgb(data) {
-      var c, m, y, k;
-      var offset = 0;
-      var min = -255 * 255 * 255;
-      var scale = 1 / 255 / 255;
-      for (var i = 0, length = data.length; i < length; i += 4) {
-        c = data[i];
-        m = data[i + 1];
-        y = data[i + 2];
-        k = data[i + 3];
-
-        var r =
-          c * (-4.387332384609988 * c + 54.48615194189176 * m +
-               18.82290502165302 * y + 212.25662451639585 * k -
-               72734.4411664936) +
-          m * (1.7149763477362134 * m - 5.6096736904047315 * y -
-               17.873870861415444 * k - 1401.7366389350734) +
-          y * (-2.5217340131683033 * y - 21.248923337353073 * k +
-               4465.541406466231) -
-          k * (21.86122147463605 * k + 48317.86113160301);
-        var g =
-          c * (8.841041422036149 * c + 60.118027045597366 * m +
-               6.871425592049007 * y + 31.159100130055922 * k -
-               20220.756542821975) +
-          m * (-15.310361306967817 * m + 17.575251261109482 * y +
-               131.35250912493976 * k - 48691.05921601825) +
-          y * (4.444339102852739 * y + 9.8632861493405 * k -
-               6341.191035517494) -
-          k * (20.737325471181034 * k + 47890.15695978492);
-        var b =
-          c * (0.8842522430003296 * c + 8.078677503112928 * m +
-               30.89978309703729 * y - 0.23883238689178934 * k -
-               3616.812083916688) +
-          m * (10.49593273432072 * m + 63.02378494754052 * y +
-               50.606957656360734 * k - 28620.90484698408) +
-          y * (0.03296041114873217 * y + 115.60384449646641 * k -
-               49363.43385999684) -
-          k * (22.33816807309886 * k + 45932.16563550634);
-
-        data[offset++] = r >= 0 ? 255 : r <= min ? 0 : 255 + r * scale | 0;
-        data[offset++] = g >= 0 ? 255 : g <= min ? 0 : 255 + g * scale | 0;
-        data[offset++] = b >= 0 ? 255 : b <= min ? 0 : 255 + b * scale | 0;
-      }
-      return data;
-    },
-
-    getData: function getData(width, height, forceRGBoutput) {
-      if (this.numComponents > 4) {
-        throw 'Unsupported color mode';
-      }
-      // type of data: Uint8Array(width * height * numComponents)
-      var data = this._getLinearizedBlockData(width, height);
-
-      if (this.numComponents === 1 && forceRGBoutput) {
-        var dataLength = data.length;
-        var rgbData = new Uint8Array(dataLength * 3);
-        var offset = 0;
-        for (var i = 0; i < dataLength; i++) {
-          var grayColor = data[i];
-          rgbData[offset++] = grayColor;
-          rgbData[offset++] = grayColor;
-          rgbData[offset++] = grayColor;
-        }
-        return rgbData;
-      } else if (this.numComponents === 3) {
-        return this._convertYccToRgb(data);
-      } else if (this.numComponents === 4) {
-        if (this._isColorConversionNeeded()) {
-          if (forceRGBoutput) {
-            return this._convertYcckToRgb(data);
-          } else {
-            return this._convertYcckToCmyk(data);
-          }
-        } else if (forceRGBoutput) {
-          return this._convertCmykToRgb(data);
-        }
-      }
-      return data;
-    }
-  };
-
-  return constructor;
-})();
-
-exports.JpegImage = JpegImage;
-}));
-
-
 (function (root, factory) {
   {
     factory((root.pdfjsSharedUtil = {}));
   }
 }(this, function (exports) {
 
 var globalScope = (typeof window !== 'undefined') ? window :
                   (typeof global !== 'undefined') ? global :
@@ -3174,16 +2139,17 @@ function createPromiseCapability() {
         return globalScope.Promise.prototype.then(undefined, onReject);
       };
     }
     return;
   }
   throw new Error('DOM Promise is not present');
 })();
 
+
 var StatTimer = (function StatTimerClosure() {
   function rpad(str, pad, length) {
     while (str.length < length) {
       str += pad;
     }
     return str;
   }
   function StatTimer() {
@@ -11201,16 +10167,1066 @@ var Jbig2Image = (function Jbig2ImageClo
 })();
 
 exports.Jbig2Image = Jbig2Image;
 }));
 
 
 (function (root, factory) {
   {
+    factory((root.pdfjsCoreJpg = {}), root.pdfjsSharedUtil);
+  }
+}(this, function (exports, sharedUtil) {
+
+var error = sharedUtil.error;
+
+/**
+ * This code was forked from https://github.com/notmasteryet/jpgjs.
+ * The original version was created by GitHub user notmasteryet.
+ *
+ * - The JPEG specification can be found in the ITU CCITT Recommendation T.81
+ *   (www.w3.org/Graphics/JPEG/itu-t81.pdf)
+ * - The JFIF specification can be found in the JPEG File Interchange Format
+ *   (www.w3.org/Graphics/JPEG/jfif3.pdf)
+ * - The Adobe Application-Specific JPEG markers in the
+ *   Supporting the DCT Filters in PostScript Level 2, Technical Note #5116
+ *   (partners.adobe.com/public/developer/en/ps/sdk/5116.DCT_Filter.pdf)
+ */
+
+var JpegImage = (function jpegImage() {
+  var dctZigZag = new Uint8Array([
+     0,
+     1,  8,
+    16,  9,  2,
+     3, 10, 17, 24,
+    32, 25, 18, 11, 4,
+     5, 12, 19, 26, 33, 40,
+    48, 41, 34, 27, 20, 13,  6,
+     7, 14, 21, 28, 35, 42, 49, 56,
+    57, 50, 43, 36, 29, 22, 15,
+    23, 30, 37, 44, 51, 58,
+    59, 52, 45, 38, 31,
+    39, 46, 53, 60,
+    61, 54, 47,
+    55, 62,
+    63
+  ]);
+
+  var dctCos1  =  4017;   // cos(pi/16)
+  var dctSin1  =   799;   // sin(pi/16)
+  var dctCos3  =  3406;   // cos(3*pi/16)
+  var dctSin3  =  2276;   // sin(3*pi/16)
+  var dctCos6  =  1567;   // cos(6*pi/16)
+  var dctSin6  =  3784;   // sin(6*pi/16)
+  var dctSqrt2 =  5793;   // sqrt(2)
+  var dctSqrt1d2 = 2896;  // sqrt(2) / 2
+
+  function constructor() {
+  }
+
+  function buildHuffmanTable(codeLengths, values) {
+    var k = 0, code = [], i, j, length = 16;
+    while (length > 0 && !codeLengths[length - 1]) {
+      length--;
+    }
+    code.push({children: [], index: 0});
+    var p = code[0], q;
+    for (i = 0; i < length; i++) {
+      for (j = 0; j < codeLengths[i]; j++) {
+        p = code.pop();
+        p.children[p.index] = values[k];
+        while (p.index > 0) {
+          p = code.pop();
+        }
+        p.index++;
+        code.push(p);
+        while (code.length <= i) {
+          code.push(q = {children: [], index: 0});
+          p.children[p.index] = q.children;
+          p = q;
+        }
+        k++;
+      }
+      if (i + 1 < length) {
+        // p here points to last code
+        code.push(q = {children: [], index: 0});
+        p.children[p.index] = q.children;
+        p = q;
+      }
+    }
+    return code[0].children;
+  }
+
+  function getBlockBufferOffset(component, row, col) {
+    return 64 * ((component.blocksPerLine + 1) * row + col);
+  }
+
+  function decodeScan(data, offset, frame, components, resetInterval,
+                      spectralStart, spectralEnd, successivePrev, successive) {
+    var mcusPerLine = frame.mcusPerLine;
+    var progressive = frame.progressive;
+
+    var startOffset = offset, bitsData = 0, bitsCount = 0;
+
+    function readBit() {
+      if (bitsCount > 0) {
+        bitsCount--;
+        return (bitsData >> bitsCount) & 1;
+      }
+      bitsData = data[offset++];
+      if (bitsData === 0xFF) {
+        var nextByte = data[offset++];
+        if (nextByte) {
+          error('JPEG error: unexpected marker ' +
+                ((bitsData << 8) | nextByte).toString(16));
+        }
+        // unstuff 0
+      }
+      bitsCount = 7;
+      return bitsData >>> 7;
+    }
+
+    function decodeHuffman(tree) {
+      var node = tree;
+      while (true) {
+        node = node[readBit()];
+        if (typeof node === 'number') {
+          return node;
+        }
+        if (typeof node !== 'object') {
+          error('JPEG error: invalid huffman sequence');
+        }
+      }
+    }
+
+    function receive(length) {
+      var n = 0;
+      while (length > 0) {
+        n = (n << 1) | readBit();
+        length--;
+      }
+      return n;
+    }
+
+    function receiveAndExtend(length) {
+      if (length === 1) {
+        return readBit() === 1 ? 1 : -1;
+      }
+      var n = receive(length);
+      if (n >= 1 << (length - 1)) {
+        return n;
+      }
+      return n + (-1 << length) + 1;
+    }
+
+    function decodeBaseline(component, offset) {
+      var t = decodeHuffman(component.huffmanTableDC);
+      var diff = t === 0 ? 0 : receiveAndExtend(t);
+      component.blockData[offset] = (component.pred += diff);
+      var k = 1;
+      while (k < 64) {
+        var rs = decodeHuffman(component.huffmanTableAC);
+        var s = rs & 15, r = rs >> 4;
+        if (s === 0) {
+          if (r < 15) {
+            break;
+          }
+          k += 16;
+          continue;
+        }
+        k += r;
+        var z = dctZigZag[k];
+        component.blockData[offset + z] = receiveAndExtend(s);
+        k++;
+      }
+    }
+
+    function decodeDCFirst(component, offset) {
+      var t = decodeHuffman(component.huffmanTableDC);
+      var diff = t === 0 ? 0 : (receiveAndExtend(t) << successive);
+      component.blockData[offset] = (component.pred += diff);
+    }
+
+    function decodeDCSuccessive(component, offset) {
+      component.blockData[offset] |= readBit() << successive;
+    }
+
+    var eobrun = 0;
+    function decodeACFirst(component, offset) {
+      if (eobrun > 0) {
+        eobrun--;
+        return;
+      }
+      var k = spectralStart, e = spectralEnd;
+      while (k <= e) {
+        var rs = decodeHuffman(component.huffmanTableAC);
+        var s = rs & 15, r = rs >> 4;
+        if (s === 0) {
+          if (r < 15) {
+            eobrun = receive(r) + (1 << r) - 1;
+            break;
+          }
+          k += 16;
+          continue;
+        }
+        k += r;
+        var z = dctZigZag[k];
+        component.blockData[offset + z] =
+          receiveAndExtend(s) * (1 << successive);
+        k++;
+      }
+    }
+
+    var successiveACState = 0, successiveACNextValue;
+    function decodeACSuccessive(component, offset) {
+      var k = spectralStart;
+      var e = spectralEnd;
+      var r = 0;
+      var s;
+      var rs;
+      while (k <= e) {
+        var z = dctZigZag[k];
+        switch (successiveACState) {
+        case 0: // initial state
+          rs = decodeHuffman(component.huffmanTableAC);
+          s = rs & 15;
+          r = rs >> 4;
+          if (s === 0) {
+            if (r < 15) {
+              eobrun = receive(r) + (1 << r);
+              successiveACState = 4;
+            } else {
+              r = 16;
+              successiveACState = 1;
+            }
+          } else {
+            if (s !== 1) {
+              error('JPEG error: invalid ACn encoding');
+            }
+            successiveACNextValue = receiveAndExtend(s);
+            successiveACState = r ? 2 : 3;
+          }
+          continue;
+        case 1: // skipping r zero items
+        case 2:
+          if (component.blockData[offset + z]) {
+            component.blockData[offset + z] += (readBit() << successive);
+          } else {
+            r--;
+            if (r === 0) {
+              successiveACState = successiveACState === 2 ? 3 : 0;
+            }
+          }
+          break;
+        case 3: // set value for a zero item
+          if (component.blockData[offset + z]) {
+            component.blockData[offset + z] += (readBit() << successive);
+          } else {
+            component.blockData[offset + z] =
+              successiveACNextValue << successive;
+            successiveACState = 0;
+          }
+          break;
+        case 4: // eob
+          if (component.blockData[offset + z]) {
+            component.blockData[offset + z] += (readBit() << successive);
+          }
+          break;
+        }
+        k++;
+      }
+      if (successiveACState === 4) {
+        eobrun--;
+        if (eobrun === 0) {
+          successiveACState = 0;
+        }
+      }
+    }
+
+    function decodeMcu(component, decode, mcu, row, col) {
+      var mcuRow = (mcu / mcusPerLine) | 0;
+      var mcuCol = mcu % mcusPerLine;
+      var blockRow = mcuRow * component.v + row;
+      var blockCol = mcuCol * component.h + col;
+      var offset = getBlockBufferOffset(component, blockRow, blockCol);
+      decode(component, offset);
+    }
+
+    function decodeBlock(component, decode, mcu) {
+      var blockRow = (mcu / component.blocksPerLine) | 0;
+      var blockCol = mcu % component.blocksPerLine;
+      var offset = getBlockBufferOffset(component, blockRow, blockCol);
+      decode(component, offset);
+    }
+
+    var componentsLength = components.length;
+    var component, i, j, k, n;
+    var decodeFn;
+    if (progressive) {
+      if (spectralStart === 0) {
+        decodeFn = successivePrev === 0 ? decodeDCFirst : decodeDCSuccessive;
+      } else {
+        decodeFn = successivePrev === 0 ? decodeACFirst : decodeACSuccessive;
+      }
+    } else {
+      decodeFn = decodeBaseline;
+    }
+
+    var mcu = 0, marker;
+    var mcuExpected;
+    if (componentsLength === 1) {
+      mcuExpected = components[0].blocksPerLine * components[0].blocksPerColumn;
+    } else {
+      mcuExpected = mcusPerLine * frame.mcusPerColumn;
+    }
+    if (!resetInterval) {
+      resetInterval = mcuExpected;
+    }
+
+    var h, v;
+    while (mcu < mcuExpected) {
+      // reset interval stuff
+      for (i = 0; i < componentsLength; i++) {
+        components[i].pred = 0;
+      }
+      eobrun = 0;
+
+      if (componentsLength === 1) {
+        component = components[0];
+        for (n = 0; n < resetInterval; n++) {
+          decodeBlock(component, decodeFn, mcu);
+          mcu++;
+        }
+      } else {
+        for (n = 0; n < resetInterval; n++) {
+          for (i = 0; i < componentsLength; i++) {
+            component = components[i];
+            h = component.h;
+            v = component.v;
+            for (j = 0; j < v; j++) {
+              for (k = 0; k < h; k++) {
+                decodeMcu(component, decodeFn, mcu, j, k);
+              }
+            }
+          }
+          mcu++;
+        }
+      }
+
+      // find marker
+      bitsCount = 0;
+      marker = (data[offset] << 8) | data[offset + 1];
+      if (marker <= 0xFF00) {
+        error('JPEG error: marker was not found');
+      }
+
+      if (marker >= 0xFFD0 && marker <= 0xFFD7) { // RSTx
+        offset += 2;
+      } else {
+        break;
+      }
+    }
+
+    return offset - startOffset;
+  }
+
+  // A port of poppler's IDCT method which in turn is taken from:
+  //   Christoph Loeffler, Adriaan Ligtenberg, George S. Moschytz,
+  //   'Practical Fast 1-D DCT Algorithms with 11 Multiplications',
+  //   IEEE Intl. Conf. on Acoustics, Speech & Signal Processing, 1989,
+  //   988-991.
+  function quantizeAndInverse(component, blockBufferOffset, p) {
+    var qt = component.quantizationTable, blockData = component.blockData;
+    var v0, v1, v2, v3, v4, v5, v6, v7;
+    var p0, p1, p2, p3, p4, p5, p6, p7;
+    var t;
+
+    if (!qt) {
+      error('JPEG error: missing required Quantization Table.');
+    }
+
+    // inverse DCT on rows
+    for (var row = 0; row < 64; row += 8) {
+      // gather block data
+      p0 = blockData[blockBufferOffset + row];
+      p1 = blockData[blockBufferOffset + row + 1];
+      p2 = blockData[blockBufferOffset + row + 2];
+      p3 = blockData[blockBufferOffset + row + 3];
+      p4 = blockData[blockBufferOffset + row + 4];
+      p5 = blockData[blockBufferOffset + row + 5];
+      p6 = blockData[blockBufferOffset + row + 6];
+      p7 = blockData[blockBufferOffset + row + 7];
+
+      // dequant p0
+      p0 *= qt[row];
+
+      // check for all-zero AC coefficients
+      if ((p1 | p2 | p3 | p4 | p5 | p6 | p7) === 0) {
+        t = (dctSqrt2 * p0 + 512) >> 10;
+        p[row] = t;
+        p[row + 1] = t;
+        p[row + 2] = t;
+        p[row + 3] = t;
+        p[row + 4] = t;
+        p[row + 5] = t;
+        p[row + 6] = t;
+        p[row + 7] = t;
+        continue;
+      }
+      // dequant p1 ... p7
+      p1 *= qt[row + 1];
+      p2 *= qt[row + 2];
+      p3 *= qt[row + 3];
+      p4 *= qt[row + 4];
+      p5 *= qt[row + 5];
+      p6 *= qt[row + 6];
+      p7 *= qt[row + 7];
+
+      // stage 4
+      v0 = (dctSqrt2 * p0 + 128) >> 8;
+      v1 = (dctSqrt2 * p4 + 128) >> 8;
+      v2 = p2;
+      v3 = p6;
+      v4 = (dctSqrt1d2 * (p1 - p7) + 128) >> 8;
+      v7 = (dctSqrt1d2 * (p1 + p7) + 128) >> 8;
+      v5 = p3 << 4;
+      v6 = p5 << 4;
+
+      // stage 3
+      v0 = (v0 + v1 + 1) >> 1;
+      v1 = v0 - v1;
+      t  = (v2 * dctSin6 + v3 * dctCos6 + 128) >> 8;
+      v2 = (v2 * dctCos6 - v3 * dctSin6 + 128) >> 8;
+      v3 = t;
+      v4 = (v4 + v6 + 1) >> 1;
+      v6 = v4 - v6;
+      v7 = (v7 + v5 + 1) >> 1;
+      v5 = v7 - v5;
+
+      // stage 2
+      v0 = (v0 + v3 + 1) >> 1;
+      v3 = v0 - v3;
+      v1 = (v1 + v2 + 1) >> 1;
+      v2 = v1 - v2;
+      t  = (v4 * dctSin3 + v7 * dctCos3 + 2048) >> 12;
+      v4 = (v4 * dctCos3 - v7 * dctSin3 + 2048) >> 12;
+      v7 = t;
+      t  = (v5 * dctSin1 + v6 * dctCos1 + 2048) >> 12;
+      v5 = (v5 * dctCos1 - v6 * dctSin1 + 2048) >> 12;
+      v6 = t;
+
+      // stage 1
+      p[row] = v0 + v7;
+      p[row + 7] = v0 - v7;
+      p[row + 1] = v1 + v6;
+      p[row + 6] = v1 - v6;
+      p[row + 2] = v2 + v5;
+      p[row + 5] = v2 - v5;
+      p[row + 3] = v3 + v4;
+      p[row + 4] = v3 - v4;
+    }
+
+    // inverse DCT on columns
+    for (var col = 0; col < 8; ++col) {
+      p0 = p[col];
+      p1 = p[col +  8];
+      p2 = p[col + 16];
+      p3 = p[col + 24];
+      p4 = p[col + 32];
+      p5 = p[col + 40];
+      p6 = p[col + 48];
+      p7 = p[col + 56];
+
+      // check for all-zero AC coefficients
+      if ((p1 | p2 | p3 | p4 | p5 | p6 | p7) === 0) {
+        t = (dctSqrt2 * p0 + 8192) >> 14;
+        // convert to 8 bit
+        t = (t < -2040) ? 0 : (t >= 2024) ? 255 : (t + 2056) >> 4;
+        blockData[blockBufferOffset + col] = t;
+        blockData[blockBufferOffset + col +  8] = t;
+        blockData[blockBufferOffset + col + 16] = t;
+        blockData[blockBufferOffset + col + 24] = t;
+        blockData[blockBufferOffset + col + 32] = t;
+        blockData[blockBufferOffset + col + 40] = t;
+        blockData[blockBufferOffset + col + 48] = t;
+        blockData[blockBufferOffset + col + 56] = t;
+        continue;
+      }
+
+      // stage 4
+      v0 = (dctSqrt2 * p0 + 2048) >> 12;
+      v1 = (dctSqrt2 * p4 + 2048) >> 12;
+      v2 = p2;
+      v3 = p6;
+      v4 = (dctSqrt1d2 * (p1 - p7) + 2048) >> 12;
+      v7 = (dctSqrt1d2 * (p1 + p7) + 2048) >> 12;
+      v5 = p3;
+      v6 = p5;
+
+      // stage 3
+      // Shift v0 by 128.5 << 5 here, so we don't need to shift p0...p7 when
+      // converting to UInt8 range later.
+      v0 = ((v0 + v1 + 1) >> 1) + 4112;
+      v1 = v0 - v1;
+      t  = (v2 * dctSin6 + v3 * dctCos6 + 2048) >> 12;
+      v2 = (v2 * dctCos6 - v3 * dctSin6 + 2048) >> 12;
+      v3 = t;
+      v4 = (v4 + v6 + 1) >> 1;
+      v6 = v4 - v6;
+      v7 = (v7 + v5 + 1) >> 1;
+      v5 = v7 - v5;
+
+      // stage 2
+      v0 = (v0 + v3 + 1) >> 1;
+      v3 = v0 - v3;
+      v1 = (v1 + v2 + 1) >> 1;
+      v2 = v1 - v2;
+      t  = (v4 * dctSin3 + v7 * dctCos3 + 2048) >> 12;
+      v4 = (v4 * dctCos3 - v7 * dctSin3 + 2048) >> 12;
+      v7 = t;
+      t  = (v5 * dctSin1 + v6 * dctCos1 + 2048) >> 12;
+      v5 = (v5 * dctCos1 - v6 * dctSin1 + 2048) >> 12;
+      v6 = t;
+
+      // stage 1
+      p0 = v0 + v7;
+      p7 = v0 - v7;
+      p1 = v1 + v6;
+      p6 = v1 - v6;
+      p2 = v2 + v5;
+      p5 = v2 - v5;
+      p3 = v3 + v4;
+      p4 = v3 - v4;
+
+      // convert to 8-bit integers
+      p0 = (p0 < 16) ? 0 : (p0 >= 4080) ? 255 : p0 >> 4;
+      p1 = (p1 < 16) ? 0 : (p1 >= 4080) ? 255 : p1 >> 4;
+      p2 = (p2 < 16) ? 0 : (p2 >= 4080) ? 255 : p2 >> 4;
+      p3 = (p3 < 16) ? 0 : (p3 >= 4080) ? 255 : p3 >> 4;
+      p4 = (p4 < 16) ? 0 : (p4 >= 4080) ? 255 : p4 >> 4;
+      p5 = (p5 < 16) ? 0 : (p5 >= 4080) ? 255 : p5 >> 4;
+      p6 = (p6 < 16) ? 0 : (p6 >= 4080) ? 255 : p6 >> 4;
+      p7 = (p7 < 16) ? 0 : (p7 >= 4080) ? 255 : p7 >> 4;
+
+      // store block data
+      blockData[blockBufferOffset + col] = p0;
+      blockData[blockBufferOffset + col +  8] = p1;
+      blockData[blockBufferOffset + col + 16] = p2;
+      blockData[blockBufferOffset + col + 24] = p3;
+      blockData[blockBufferOffset + col + 32] = p4;
+      blockData[blockBufferOffset + col + 40] = p5;
+      blockData[blockBufferOffset + col + 48] = p6;
+      blockData[blockBufferOffset + col + 56] = p7;
+    }
+  }
+
+  function buildComponentData(frame, component) {
+    var blocksPerLine = component.blocksPerLine;
+    var blocksPerColumn = component.blocksPerColumn;
+    var computationBuffer = new Int16Array(64);
+
+    for (var blockRow = 0; blockRow < blocksPerColumn; blockRow++) {
+      for (var blockCol = 0; blockCol < blocksPerLine; blockCol++) {
+        var offset = getBlockBufferOffset(component, blockRow, blockCol);
+        quantizeAndInverse(component, offset, computationBuffer);
+      }
+    }
+    return component.blockData;
+  }
+
+  function clamp0to255(a) {
+    return a <= 0 ? 0 : a >= 255 ? 255 : a;
+  }
+
+  constructor.prototype = {
+    parse: function parse(data) {
+
+      function readUint16() {
+        var value = (data[offset] << 8) | data[offset + 1];
+        offset += 2;
+        return value;
+      }
+
+      function readDataBlock() {
+        var length = readUint16();
+        var array = data.subarray(offset, offset + length - 2);
+        offset += array.length;
+        return array;
+      }
+
+      function prepareComponents(frame) {
+        var mcusPerLine = Math.ceil(frame.samplesPerLine / 8 / frame.maxH);
+        var mcusPerColumn = Math.ceil(frame.scanLines / 8 / frame.maxV);
+        for (var i = 0; i < frame.components.length; i++) {
+          component = frame.components[i];
+          var blocksPerLine = Math.ceil(Math.ceil(frame.samplesPerLine / 8) *
+                                        component.h / frame.maxH);
+          var blocksPerColumn = Math.ceil(Math.ceil(frame.scanLines  / 8) *
+                                          component.v / frame.maxV);
+          var blocksPerLineForMcu = mcusPerLine * component.h;
+          var blocksPerColumnForMcu = mcusPerColumn * component.v;
+
+          var blocksBufferSize = 64 * blocksPerColumnForMcu *
+                                      (blocksPerLineForMcu + 1);
+          component.blockData = new Int16Array(blocksBufferSize);
+          component.blocksPerLine = blocksPerLine;
+          component.blocksPerColumn = blocksPerColumn;
+        }
+        frame.mcusPerLine = mcusPerLine;
+        frame.mcusPerColumn = mcusPerColumn;
+      }
+
+      var offset = 0;
+      var jfif = null;
+      var adobe = null;
+      var frame, resetInterval;
+      var quantizationTables = [];
+      var huffmanTablesAC = [], huffmanTablesDC = [];
+      var fileMarker = readUint16();
+      if (fileMarker !== 0xFFD8) { // SOI (Start of Image)
+        error('JPEG error: SOI not found');
+      }
+
+      fileMarker = readUint16();
+      while (fileMarker !== 0xFFD9) { // EOI (End of image)
+        var i, j, l;
+        switch(fileMarker) {
+          case 0xFFE0: // APP0 (Application Specific)
+          case 0xFFE1: // APP1
+          case 0xFFE2: // APP2
+          case 0xFFE3: // APP3
+          case 0xFFE4: // APP4
+          case 0xFFE5: // APP5
+          case 0xFFE6: // APP6
+          case 0xFFE7: // APP7
+          case 0xFFE8: // APP8
+          case 0xFFE9: // APP9
+          case 0xFFEA: // APP10
+          case 0xFFEB: // APP11
+          case 0xFFEC: // APP12
+          case 0xFFED: // APP13
+          case 0xFFEE: // APP14
+          case 0xFFEF: // APP15
+          case 0xFFFE: // COM (Comment)
+            var appData = readDataBlock();
+
+            if (fileMarker === 0xFFE0) {
+              if (appData[0] === 0x4A && appData[1] === 0x46 &&
+                  appData[2] === 0x49 && appData[3] === 0x46 &&
+                  appData[4] === 0) { // 'JFIF\x00'
+                jfif = {
+                  version: { major: appData[5], minor: appData[6] },
+                  densityUnits: appData[7],
+                  xDensity: (appData[8] << 8) | appData[9],
+                  yDensity: (appData[10] << 8) | appData[11],
+                  thumbWidth: appData[12],
+                  thumbHeight: appData[13],
+                  thumbData: appData.subarray(14, 14 +
+                                              3 * appData[12] * appData[13])
+                };
+              }
+            }
+            // TODO APP1 - Exif
+            if (fileMarker === 0xFFEE) {
+              if (appData[0] === 0x41 && appData[1] === 0x64 &&
+                  appData[2] === 0x6F && appData[3] === 0x62 &&
+                  appData[4] === 0x65) { // 'Adobe'
+                adobe = {
+                  version: (appData[5] << 8) | appData[6],
+                  flags0: (appData[7] << 8) | appData[8],
+                  flags1: (appData[9] << 8) | appData[10],
+                  transformCode: appData[11]
+                };
+              }
+            }
+            break;
+
+          case 0xFFDB: // DQT (Define Quantization Tables)
+            var quantizationTablesLength = readUint16();
+            var quantizationTablesEnd = quantizationTablesLength + offset - 2;
+            var z;
+            while (offset < quantizationTablesEnd) {
+              var quantizationTableSpec = data[offset++];
+              var tableData = new Uint16Array(64);
+              if ((quantizationTableSpec >> 4) === 0) { // 8 bit values
+                for (j = 0; j < 64; j++) {
+                  z = dctZigZag[j];
+                  tableData[z] = data[offset++];
+                }
+              } else if ((quantizationTableSpec >> 4) === 1) { //16 bit
+                for (j = 0; j < 64; j++) {
+                  z = dctZigZag[j];
+                  tableData[z] = readUint16();
+                }
+              } else {
+                error('JPEG error: DQT - invalid table spec');
+              }
+              quantizationTables[quantizationTableSpec & 15] = tableData;
+            }
+            break;
+
+          case 0xFFC0: // SOF0 (Start of Frame, Baseline DCT)
+          case 0xFFC1: // SOF1 (Start of Frame, Extended DCT)
+          case 0xFFC2: // SOF2 (Start of Frame, Progressive DCT)
+            if (frame) {
+              error('JPEG error: Only single frame JPEGs supported');
+            }
+            readUint16(); // skip data length
+            frame = {};
+            frame.extended = (fileMarker === 0xFFC1);
+            frame.progressive = (fileMarker === 0xFFC2);
+            frame.precision = data[offset++];
+            frame.scanLines = readUint16();
+            frame.samplesPerLine = readUint16();
+            frame.components = [];
+            frame.componentIds = {};
+            var componentsCount = data[offset++], componentId;
+            var maxH = 0, maxV = 0;
+            for (i = 0; i < componentsCount; i++) {
+              componentId = data[offset];
+              var h = data[offset + 1] >> 4;
+              var v = data[offset + 1] & 15;
+              if (maxH < h) {
+                maxH = h;
+              }
+              if (maxV < v) {
+                maxV = v;
+              }
+              var qId = data[offset + 2];
+              l = frame.components.push({
+                h: h,
+                v: v,
+                quantizationId: qId,
+                quantizationTable: null, // See comment below.
+              });
+              frame.componentIds[componentId] = l - 1;
+              offset += 3;
+            }
+            frame.maxH = maxH;
+            frame.maxV = maxV;
+            prepareComponents(frame);
+            break;
+
+          case 0xFFC4: // DHT (Define Huffman Tables)
+            var huffmanLength = readUint16();
+            for (i = 2; i < huffmanLength;) {
+              var huffmanTableSpec = data[offset++];
+              var codeLengths = new Uint8Array(16);
+              var codeLengthSum = 0;
+              for (j = 0; j < 16; j++, offset++) {
+                codeLengthSum += (codeLengths[j] = data[offset]);
+              }
+              var huffmanValues = new Uint8Array(codeLengthSum);
+              for (j = 0; j < codeLengthSum; j++, offset++) {
+                huffmanValues[j] = data[offset];
+              }
+              i += 17 + codeLengthSum;
+
+              ((huffmanTableSpec >> 4) === 0 ?
+                huffmanTablesDC : huffmanTablesAC)[huffmanTableSpec & 15] =
+                buildHuffmanTable(codeLengths, huffmanValues);
+            }
+            break;
+
+          case 0xFFDD: // DRI (Define Restart Interval)
+            readUint16(); // skip data length
+            resetInterval = readUint16();
+            break;
+
+          case 0xFFDA: // SOS (Start of Scan)
+            var scanLength = readUint16();
+            var selectorsCount = data[offset++];
+            var components = [], component;
+            for (i = 0; i < selectorsCount; i++) {
+              var componentIndex = frame.componentIds[data[offset++]];
+              component = frame.components[componentIndex];
+              var tableSpec = data[offset++];
+              component.huffmanTableDC = huffmanTablesDC[tableSpec >> 4];
+              component.huffmanTableAC = huffmanTablesAC[tableSpec & 15];
+              components.push(component);
+            }
+            var spectralStart = data[offset++];
+            var spectralEnd = data[offset++];
+            var successiveApproximation = data[offset++];
+            var processed = decodeScan(data, offset,
+              frame, components, resetInterval,
+              spectralStart, spectralEnd,
+              successiveApproximation >> 4, successiveApproximation & 15);
+            offset += processed;
+            break;
+
+          case 0xFFFF: // Fill bytes
+            if (data[offset] !== 0xFF) { // Avoid skipping a valid marker.
+              offset--;
+            }
+            break;
+
+          default:
+            if (data[offset - 3] === 0xFF &&
+                data[offset - 2] >= 0xC0 && data[offset - 2] <= 0xFE) {
+              // could be incorrect encoding -- last 0xFF byte of the previous
+              // block was eaten by the encoder
+              offset -= 3;
+              break;
+            }
+            error('JPEG error: unknown marker ' + fileMarker.toString(16));
+        }
+        fileMarker = readUint16();
+      }
+
+      this.width = frame.samplesPerLine;
+      this.height = frame.scanLines;
+      this.jfif = jfif;
+      this.adobe = adobe;
+      this.components = [];
+      for (i = 0; i < frame.components.length; i++) {
+        component = frame.components[i];
+
+        // Prevent errors when DQT markers are placed after SOF{n} markers,
+        // by assigning the `quantizationTable` entry after the entire image
+        // has been parsed (fixes issue7406.pdf).
+        var quantizationTable = quantizationTables[component.quantizationId];
+        if (quantizationTable) {
+          component.quantizationTable = quantizationTable;
+        }
+
+        this.components.push({
+          output: buildComponentData(frame, component),
+          scaleX: component.h / frame.maxH,
+          scaleY: component.v / frame.maxV,
+          blocksPerLine: component.blocksPerLine,
+          blocksPerColumn: component.blocksPerColumn
+        });
+      }
+      this.numComponents = this.components.length;
+    },
+
+    _getLinearizedBlockData: function getLinearizedBlockData(width, height) {
+      var scaleX = this.width / width, scaleY = this.height / height;
+
+      var component, componentScaleX, componentScaleY, blocksPerScanline;
+      var x, y, i, j, k;
+      var index;
+      var offset = 0;
+      var output;
+      var numComponents = this.components.length;
+      var dataLength = width * height * numComponents;
+      var data = new Uint8Array(dataLength);
+      var xScaleBlockOffset = new Uint32Array(width);
+      var mask3LSB = 0xfffffff8; // used to clear the 3 LSBs
+
+      for (i = 0; i < numComponents; i++) {
+        component = this.components[i];
+        componentScaleX = component.scaleX * scaleX;
+        componentScaleY = component.scaleY * scaleY;
+        offset = i;
+        output = component.output;
+        blocksPerScanline = (component.blocksPerLine + 1) << 3;
+        // precalculate the xScaleBlockOffset
+        for (x = 0; x < width; x++) {
+          j = 0 | (x * componentScaleX);
+          xScaleBlockOffset[x] = ((j & mask3LSB) << 3) | (j & 7);
+        }
+        // linearize the blocks of the component
+        for (y = 0; y < height; y++) {
+          j = 0 | (y * componentScaleY);
+          index = blocksPerScanline * (j & mask3LSB) | ((j & 7) << 3);
+          for (x = 0; x < width; x++) {
+            data[offset] = output[index + xScaleBlockOffset[x]];
+            offset += numComponents;
+          }
+        }
+      }
+
+      // decodeTransform contains pairs of multiplier (-256..256) and additive
+      var transform = this.decodeTransform;
+      if (transform) {
+        for (i = 0; i < dataLength;) {
+          for (j = 0, k = 0; j < numComponents; j++, i++, k += 2) {
+            data[i] = ((data[i] * transform[k]) >> 8) + transform[k + 1];
+          }
+        }
+      }
+      return data;
+    },
+
+    _isColorConversionNeeded: function isColorConversionNeeded() {
+      if (this.adobe && this.adobe.transformCode) {
+        // The adobe transform marker overrides any previous setting
+        return true;
+      } else if (this.numComponents === 3) {
+        return true;
+      } else {
+        return false;
+      }
+    },
+
+    _convertYccToRgb: function convertYccToRgb(data) {
+      var Y, Cb, Cr;
+      for (var i = 0, length = data.length; i < length; i += 3) {
+        Y  = data[i    ];
+        Cb = data[i + 1];
+        Cr = data[i + 2];
+        data[i    ] = clamp0to255(Y - 179.456 + 1.402 * Cr);
+        data[i + 1] = clamp0to255(Y + 135.459 - 0.344 * Cb - 0.714 * Cr);
+        data[i + 2] = clamp0to255(Y - 226.816 + 1.772 * Cb);
+      }
+      return data;
+    },
+
+    _convertYcckToRgb: function convertYcckToRgb(data) {
+      var Y, Cb, Cr, k;
+      var offset = 0;
+      for (var i = 0, length = data.length; i < length; i += 4) {
+        Y  = data[i];
+        Cb = data[i + 1];
+        Cr = data[i + 2];
+        k = data[i + 3];
+
+        var r = -122.67195406894 +
+          Cb * (-6.60635669420364e-5 * Cb + 0.000437130475926232 * Cr -
+                5.4080610064599e-5 * Y + 0.00048449797120281 * k -
+                0.154362151871126) +
+          Cr * (-0.000957964378445773 * Cr + 0.000817076911346625 * Y -
+                0.00477271405408747 * k + 1.53380253221734) +
+          Y * (0.000961250184130688 * Y - 0.00266257332283933 * k +
+               0.48357088451265) +
+          k * (-0.000336197177618394 * k + 0.484791561490776);
+
+        var g = 107.268039397724 +
+          Cb * (2.19927104525741e-5 * Cb - 0.000640992018297945 * Cr +
+                0.000659397001245577 * Y + 0.000426105652938837 * k -
+                0.176491792462875) +
+          Cr * (-0.000778269941513683 * Cr + 0.00130872261408275 * Y +
+                0.000770482631801132 * k - 0.151051492775562) +
+          Y * (0.00126935368114843 * Y - 0.00265090189010898 * k +
+               0.25802910206845) +
+          k * (-0.000318913117588328 * k - 0.213742400323665);
+
+        var b = -20.810012546947 +
+          Cb * (-0.000570115196973677 * Cb - 2.63409051004589e-5 * Cr +
+                0.0020741088115012 * Y - 0.00288260236853442 * k +
+                0.814272968359295) +
+          Cr * (-1.53496057440975e-5 * Cr - 0.000132689043961446 * Y +
+                0.000560833691242812 * k - 0.195152027534049) +
+          Y * (0.00174418132927582 * Y - 0.00255243321439347 * k +
+               0.116935020465145) +
+          k * (-0.000343531996510555 * k + 0.24165260232407);
+
+        data[offset++] = clamp0to255(r);
+        data[offset++] = clamp0to255(g);
+        data[offset++] = clamp0to255(b);
+      }
+      return data;
+    },
+
+    _convertYcckToCmyk: function convertYcckToCmyk(data) {
+      var Y, Cb, Cr;
+      for (var i = 0, length = data.length; i < length; i += 4) {
+        Y  = data[i];
+        Cb = data[i + 1];
+        Cr = data[i + 2];
+        data[i    ] = clamp0to255(434.456 - Y - 1.402 * Cr);
+        data[i + 1] = clamp0to255(119.541 - Y + 0.344 * Cb + 0.714 * Cr);
+        data[i + 2] = clamp0to255(481.816 - Y - 1.772 * Cb);
+        // K in data[i + 3] is unchanged
+      }
+      return data;
+    },
+
+    _convertCmykToRgb: function convertCmykToRgb(data) {
+      var c, m, y, k;
+      var offset = 0;
+      var min = -255 * 255 * 255;
+      var scale = 1 / 255 / 255;
+      for (var i = 0, length = data.length; i < length; i += 4) {
+        c = data[i];
+        m = data[i + 1];
+        y = data[i + 2];
+        k = data[i + 3];
+
+        var r =
+          c * (-4.387332384609988 * c + 54.48615194189176 * m +
+               18.82290502165302 * y + 212.25662451639585 * k -
+               72734.4411664936) +
+          m * (1.7149763477362134 * m - 5.6096736904047315 * y -
+               17.873870861415444 * k - 1401.7366389350734) +
+          y * (-2.5217340131683033 * y - 21.248923337353073 * k +
+               4465.541406466231) -
+          k * (21.86122147463605 * k + 48317.86113160301);
+        var g =
+          c * (8.841041422036149 * c + 60.118027045597366 * m +
+               6.871425592049007 * y + 31.159100130055922 * k -
+               20220.756542821975) +
+          m * (-15.310361306967817 * m + 17.575251261109482 * y +
+               131.35250912493976 * k - 48691.05921601825) +
+          y * (4.444339102852739 * y + 9.8632861493405 * k -
+               6341.191035517494) -
+          k * (20.737325471181034 * k + 47890.15695978492);
+        var b =
+          c * (0.8842522430003296 * c + 8.078677503112928 * m +
+               30.89978309703729 * y - 0.23883238689178934 * k -
+               3616.812083916688) +
+          m * (10.49593273432072 * m + 63.02378494754052 * y +
+               50.606957656360734 * k - 28620.90484698408) +
+          y * (0.03296041114873217 * y + 115.60384449646641 * k -
+               49363.43385999684) -
+          k * (22.33816807309886 * k + 45932.16563550634);
+
+        data[offset++] = r >= 0 ? 255 : r <= min ? 0 : 255 + r * scale | 0;
+        data[offset++] = g >= 0 ? 255 : g <= min ? 0 : 255 + g * scale | 0;
+        data[offset++] = b >= 0 ? 255 : b <= min ? 0 : 255 + b * scale | 0;
+      }
+      return data;
+    },
+
+    getData: function getData(width, height, forceRGBoutput) {
+      if (this.numComponents > 4) {
+        error('JPEG error: Unsupported color mode');
+      }
+      // type of data: Uint8Array(width * height * numComponents)
+      var data = this._getLinearizedBlockData(width, height);
+
+      if (this.numComponents === 1 && forceRGBoutput) {
+        var dataLength = data.length;
+        var rgbData = new Uint8Array(dataLength * 3);
+        var offset = 0;
+        for (var i = 0; i < dataLength; i++) {
+          var grayColor = data[i];
+          rgbData[offset++] = grayColor;
+          rgbData[offset++] = grayColor;
+          rgbData[offset++] = grayColor;
+        }
+        return rgbData;
+      } else if (this.numComponents === 3) {
+        return this._convertYccToRgb(data);
+      } else if (this.numComponents === 4) {
+        if (this._isColorConversionNeeded()) {
+          if (forceRGBoutput) {
+            return this._convertYcckToRgb(data);
+          } else {
+            return this._convertYcckToCmyk(data);
+          }
+        } else if (forceRGBoutput) {
+          return this._convertCmykToRgb(data);
+        }
+      }
+      return data;
+    }
+  };
+
+  return constructor;
+})();
+
+exports.JpegImage = JpegImage;
+}));
+
+
+(function (root, factory) {
+  {
     factory((root.pdfjsCoreJpx = {}), root.pdfjsSharedUtil,
       root.pdfjsCoreArithmeticDecoder);
   }
 }(this, function (exports, sharedUtil, coreArithmeticDecoder) {
 
 var info = sharedUtil.info;
 var log2 = sharedUtil.log2;
 var readUint16 = sharedUtil.readUint16;
@@ -19674,48 +19690,44 @@ var JpegStream = (function JpegStreamClo
     },
     configurable: true
   });
 
   JpegStream.prototype.ensureBuffer = function JpegStream_ensureBuffer(req) {
     if (this.bufferLength) {
       return;
     }
-    try {
-      var jpegImage = new JpegImage();
-
-      // checking if values needs to be transformed before conversion
-      if (this.forceRGB && this.dict && isArray(this.dict.get('Decode'))) {
-        var decodeArr = this.dict.getArray('Decode');
-        var bitsPerComponent = this.dict.get('BitsPerComponent') || 8;
-        var decodeArrLength = decodeArr.length;
-        var transform = new Int32Array(decodeArrLength);
-        var transformNeeded = false;
-        var maxValue = (1 << bitsPerComponent) - 1;
-        for (var i = 0; i < decodeArrLength; i += 2) {
-          transform[i] = ((decodeArr[i + 1] - decodeArr[i]) * 256) | 0;
-          transform[i + 1] = (decodeArr[i] * maxValue) | 0;
-          if (transform[i] !== 256 || transform[i + 1] !== 0) {
-            transformNeeded = true;
-          }
-        }
-        if (transformNeeded) {
-          jpegImage.decodeTransform = transform;
-        }
-      }
-
-      jpegImage.parse(this.bytes);
-      var data = jpegImage.getData(this.drawWidth, this.drawHeight,
-                                   this.forceRGB);
-      this.buffer = data;
-      this.bufferLength = data.length;
-      this.eof = true;
-    } catch (e) {
-      error('JPEG error: ' + e);
-    }
+    var jpegImage = new JpegImage();
+
+    // Checking if values need to be transformed before conversion.
+    if (this.forceRGB && this.dict && isArray(this.dict.get('Decode'))) {
+      var decodeArr = this.dict.getArray('Decode');
+      var bitsPerComponent = this.dict.get('BitsPerComponent') || 8;
+      var decodeArrLength = decodeArr.length;
+      var transform = new Int32Array(decodeArrLength);
+      var transformNeeded = false;
+      var maxValue = (1 << bitsPerComponent) - 1;
+      for (var i = 0; i < decodeArrLength; i += 2) {
+        transform[i] = ((decodeArr[i + 1] - decodeArr[i]) * 256) | 0;
+        transform[i + 1] = (decodeArr[i] * maxValue) | 0;
+        if (transform[i] !== 256 || transform[i + 1] !== 0) {
+          transformNeeded = true;
+        }
+      }
+      if (transformNeeded) {
+        jpegImage.decodeTransform = transform;
+      }
+    }
+
+    jpegImage.parse(this.bytes);
+    var data = jpegImage.getData(this.drawWidth, this.drawHeight,
+                                 this.forceRGB);
+    this.buffer = data;
+    this.bufferLength = data.length;
+    this.eof = true;
   };
 
   JpegStream.prototype.getBytes = function JpegStream_getBytes(length) {
     this.ensureBuffer();
     return this.buffer;
   };
 
   JpegStream.prototype.getIR = function JpegStream_getIR(forceDataSchema) {
@@ -39227,19 +39239,24 @@ AnnotationFactory.prototype = /** @lends
       case 'Link':
         return new LinkAnnotation(parameters);
 
       case 'Text':
         return new TextAnnotation(parameters);
 
       case 'Widget':
         var fieldType = Util.getInheritableProperty(dict, 'FT');
-        if (isName(fieldType, 'Tx')) {
-          return new TextWidgetAnnotation(parameters);
-        }
+        fieldType = isName(fieldType) ? fieldType.name : null;
+
+        switch (fieldType) {
+          case 'Tx':
+            return new TextWidgetAnnotation(parameters);
+        }
+        warn('Unimplemented widget field type "' + fieldType + '", ' +
+             'falling back to base field type.');
         return new WidgetAnnotation(parameters);
 
       case 'Popup':
         return new PopupAnnotation(parameters);
 
       case 'Highlight':
         return new HighlightAnnotation(parameters);
 
@@ -39744,23 +39761,22 @@ var WidgetAnnotation = (function WidgetA
     var data = this.data;
 
     data.annotationType = AnnotationType.WIDGET;
     data.fieldValue = stringToPDFString(
       Util.getInheritableProperty(dict, 'V') || '');
     data.alternativeText = stringToPDFString(dict.get('TU') || '');
     data.defaultAppearance = Util.getInheritableProperty(dict, 'DA') || '';
     var fieldType = Util.getInheritableProperty(dict, 'FT');
-    data.fieldType = isName(fieldType) ? fieldType.name : '';
+    data.fieldType = isName(fieldType) ? fieldType.name : null;
     data.fieldFlags = Util.getInheritableProperty(dict, 'Ff') || 0;
     this.fieldResources = Util.getInheritableProperty(dict, 'DR') || Dict.empty;
 
-    // Hide unsupported Widget signatures.
+    // Hide signatures because we cannot validate them.
     if (data.fieldType === 'Sig') {
-      warn('unimplemented annotation type: Widget signature');
       this.setFlags(AnnotationFlag.HIDDEN);
     }
 
     // Building the full field name by collecting the field and
     // its ancestors 'T' data and joining them using '.'.
     var fieldName = [];
     var namedItem = dict;
     var ref = params.ref;
--- a/browser/extensions/pdfjs/content/web/viewer.css
+++ b/browser/extensions/pdfjs/content/web/viewer.css
@@ -96,16 +96,36 @@
   box-shadow: 0px 2px 10px #ff0;
 }
 
 .annotationLayer .textAnnotation img {
   position: absolute;
   cursor: pointer;
 }
 
+.annotationLayer .textWidgetAnnotation input {
+  background-color: rgba(0, 54, 255, 0.13);
+  border: 1px solid transparent;
+  box-sizing: border-box;
+  font-size: 9px;
+  height: 100%;
+  padding: 0 3px;
+  vertical-align: top;
+  width: 100%;
+}
+
+.annotationLayer .textWidgetAnnotation input:hover {
+  border: 1px solid #000;
+}
+
+.annotationLayer .textWidgetAnnotation input:focus {
+  background: none;
+  border: 1px solid transparent;
+}
+
 .annotationLayer .popupWrapper {
   position: absolute;
   width: 20em;
 }
 
 .annotationLayer .popup {
   position: absolute;
   z-index: 200;
--- a/browser/extensions/pdfjs/content/web/viewer.js
+++ b/browser/extensions/pdfjs/content/web/viewer.js
@@ -946,17 +946,18 @@ exports.PDFRenderingQueue = PDFRendering
   "enableWebGL": false,
   "pdfBugEnabled": false,
   "disableRange": false,
   "disableStream": false,
   "disableAutoFetch": false,
   "disableFontFace": false,
   "disableTextLayer": false,
   "useOnlyCssZoom": false,
-  "externalLinkTarget": 0
+  "externalLinkTarget": 0,
+  "renderInteractiveForms": false
 }
 
   );
 
 function cloneObj(obj) {
   var result = {};
   for (var i in obj) {
     if (Object.prototype.hasOwnProperty.call(obj, i)) {
@@ -5032,17 +5033,17 @@ var TEXT_LAYER_RENDER_DELAY = 200; // ms
  * @property {EventBus} eventBus - The application event bus.
  * @property {number} id - The page unique ID (normally its number).
  * @property {number} scale - The page scale display.
  * @property {PageViewport} defaultViewport - The page viewport.
  * @property {PDFRenderingQueue} renderingQueue - The rendering queue object.
  * @property {IPDFTextLayerFactory} textLayerFactory
  * @property {IPDFAnnotationLayerFactory} annotationLayerFactory
  * @property {boolean} enhanceTextSelection - Turns on the text selection
- * enhancement. The default is `false`.
+ *   enhancement. The default is `false`.
  */
 
 /**
  * @class
  * @implements {IRenderableView}
  */
 var PDFPageView = (function PDFPageViewClosure() {
   /**
@@ -5788,17 +5789,17 @@ exports.PDFThumbnailViewer = PDFThumbnai
 /**
  * @typedef {Object} TextLayerBuilderOptions
  * @property {HTMLDivElement} textLayerDiv - The text layer container.
  * @property {EventBus} eventBus - The application event bus.
  * @property {number} pageIndex - The page index.
  * @property {PageViewport} viewport - The viewport of the text layer.
  * @property {PDFFindController} findController
  * @property {boolean} enhanceTextSelection - Option to turn on improved
- * text selection.
+ *   text selection.
  */
 
 /**
  * TextLayerBuilder provides text-selection functionality for the PDF.
  * It does this by creating overlay divs over the PDF text. These divs
  * contain text that matches the PDF text they are overlaying. This object
  * also provides a way to highlight text that is being searched for.
  * @class
@@ -6185,17 +6186,18 @@ var AnnotationLayerBuilder = (function A
       this.pdfPage.getAnnotations(parameters).then(function (annotations) {
         viewport = viewport.clone({ dontFlip: true });
         parameters = {
           viewport: viewport,
           div: self.div,
           annotations: annotations,
           page: self.pdfPage,
           linkService: self.linkService,
-          downloadManager: self.downloadManager
+          downloadManager: self.downloadManager,
+          renderInteractiveForms: pdfjsLib.PDFJS.renderInteractiveForms,
         };
 
         if (self.div) {
           // If an annotationLayer already exists, refresh its children's
           // transformation matrices.
           pdfjsLib.AnnotationLayer.update(parameters);
         } else {
           // Create an annotation layer div and render the annotations
@@ -7398,16 +7400,19 @@ var PDFViewerApplication = {
         PDFJS.useOnlyCssZoom = value;
       }),
       Preferences.get('externalLinkTarget').then(function resolved(value) {
         if (PDFJS.isExternalLinkTargetSet()) {
           return;
         }
         PDFJS.externalLinkTarget = value;
       }),
+      Preferences.get('renderInteractiveForms').then(function resolved(value) {
+        PDFJS.renderInteractiveForms = value;
+      }),
       // TODO move more preferences and other async stuff here
     ]).catch(function (reason) { });
 
     return initializedPromise.then(function () {
       if (self.isViewerEmbedded && !PDFJS.isExternalLinkTargetSet()) {
         // Prevent external links from "replacing" the viewer,
         // when it's embedded in e.g. an iframe or an object.
         PDFJS.externalLinkTarget = PDFJS.LinkTarget.TOP;
--- a/browser/locales/en-US/chrome/browser/browser.properties
+++ b/browser/locales/en-US/chrome/browser/browser.properties
@@ -373,16 +373,26 @@ geolocation.shareLocation=Share Location
 geolocation.shareLocation.accesskey=a
 geolocation.alwaysShareLocation=Always Share Location
 geolocation.alwaysShareLocation.accesskey=A
 geolocation.neverShareLocation=Never Share Location
 geolocation.neverShareLocation.accesskey=N
 geolocation.shareWithSite2=Would you like to share your location with this site?
 geolocation.shareWithFile2=Would you like to share your location with this file?
 
+# FlyWeb UI
+# LOCALIZATION NOTE (flyWebPublishServer.allowPublishServer): This is an experimental feature only shipping in Nightly, and doesn't need translation.
+flyWebPublishServer.allowPublishServer=Allow Server
+# LOCALIZATION NOTE (flyWebPublishServer.allowPublishServer.accessKey): This is an experimental feature only shipping in Nightly, and doesn't need translation.
+flyWebPublishServer.allowPublishServer.accesskey=A
+# LOCALIZATION NOTE (flyWebPublishServer.denyPublishServer): This is an experimental feature only shipping in Nightly, and doesn't need translation.
+flyWebPublishServer.denyPublishServer=Block Server
+# LOCALIZATION NOTE (flyWebPublishServer.denyPublishServer.accessKey): This is an experimental feature only shipping in Nightly, and doesn't need translation.
+flyWebPublishServer.denyPublishServer.accesskey=B
+
 webNotifications.receiveForSession=Receive for this session
 webNotifications.receiveForSession.accesskey=s
 webNotifications.alwaysReceive=Always Receive Notifications
 webNotifications.alwaysReceive.accesskey=A
 webNotifications.neverShow=Always Block Notifications
 webNotifications.neverShow.accesskey=N
 webNotifications.receiveFromSite=Would you like to receive notifications from this site?
 # LOCALIZATION NOTE (webNotifications.upgradeTitle): When using native notifications on OS X, the title may be truncated around 32 characters.
--- a/browser/themes/linux/browser.css
+++ b/browser/themes/linux/browser.css
@@ -972,18 +972,22 @@ toolbaritem[cui-areatype="menu-panel"] >
   border: 1px solid ThreeDLightShadow;
 }
 
 #urlbar-zoom-button[animate="true"] {
   animation-name: urlbar-zoom-reset-pulse;
   animation-duration: 250ms;
 }
 
+#urlbar-zoom-button:hover {
+  background-color: hsla(0,0%,0%,.1);
+}
+
 #urlbar-zoom-button:hover:active {
-  background-color: hsla(0,0%,0%,.1);
+  background-color: hsla(0,0%,0%,.15);
 }
 
 #urlbar-zoom-button > .toolbarbutton-text {
   display: -moz-box;
 }
 
 #urlbar-zoom-button > .toolbarbutton-icon {
   display: none;
--- a/browser/themes/osx/browser.css
+++ b/browser/themes/osx/browser.css
@@ -1684,18 +1684,23 @@ toolbar .toolbarbutton-1 > .toolbarbutto
   background-color: hsla(0,0%,0%,.05);
   border: 1px solid hsla(0,0%,0%,.1);
 }
 
 #urlbar-zoom-button[animate="true"] {
   animation-name: urlbar-zoom-reset-pulse;
   animation-duration: 250ms;
 }
+
+#urlbar-zoom-button:hover {
+  background-color: hsla(0,0%,0%,.1);
+}
+
 #urlbar-zoom-button:hover:active {
-  background-color: hsla(0,0%,0%,.1);
+  background-color: hsla(0,0%,0%,.15);
 }
 
 #urlbar-zoom-button > .toolbarbutton-text {
   display: -moz-box;
 }
 
 #urlbar-zoom-button > .toolbarbutton-icon {
   display: none;
--- a/browser/themes/windows/browser.css
+++ b/browser/themes/windows/browser.css
@@ -1417,18 +1417,22 @@ html|*.urlbar-input:-moz-lwtheme::placeh
   border: 1px solid ThreeDLightShadow;
 }
 
 #urlbar-zoom-button[animate="true"] {
   animation-name: urlbar-zoom-reset-pulse;
   animation-duration: 250ms;
 }
 
+#urlbar-zoom-button:hover {
+  background-color: hsla(0,0%,0%,.1);
+}
+
 #urlbar-zoom-button:hover:active {
-  background-color: hsla(0,0%,0%,.1);
+  background-color: hsla(0,0%,0%,.15);
 }
 
 #urlbar-zoom-button > .toolbarbutton-text {
   display: -moz-box;
 }
 
 #urlbar-zoom-button > .toolbarbutton-icon {
   display: none;
deleted file mode 100644
--- a/build/autoconf/rust.m4
+++ /dev/null
@@ -1,152 +0,0 @@
-dnl This Source Code Form is subject to the terms of the Mozilla Public
-dnl License, v. 2.0. If a copy of the MPL was not distributed with this
-dnl file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-AC_DEFUN([MOZ_RUST_SUPPORT], [
-  MOZ_PATH_PROG(RUSTC, rustc)
-  if test -n "$RUSTC"; then
-    AC_MSG_CHECKING([rustc version])
-    RUSTC_VERSION=`$RUSTC --version | cut -d ' ' -f 2`
-    # Parse out semversion elements.
-    _RUSTC_MAJOR_VERSION=`echo ${RUSTC_VERSION} | cut -d . -f 1`
-    _RUSTC_MINOR_VERSION=`echo ${RUSTC_VERSION} | cut -d . -f 2`
-    _RUSTC_EXTRA_VERSION=`echo ${RUSTC_VERSION} | cut -d . -f 3 | cut -d + -f 1`
-    _RUSTC_PATCH_VERSION=`echo ${_RUSTC_EXTRA_VERSION} | cut -d '-' -f 1`
-    AC_MSG_RESULT([${_RUSTC_MAJOR_VERSION}.${_RUSTC_MINOR_VERSION}.${_RUSTC_PATCH_VERSION} ($RUSTC_VERSION)])
-  fi
-  MOZ_ARG_ENABLE_BOOL([rust],
-                      [  --enable-rust           Include Rust language sources],
-                      [MOZ_RUST=1],
-                      [MOZ_RUST= ])
-  if test -z "$RUSTC" -a -n "$MOZ_RUST"; then
-    AC_MSG_ERROR([Rust compiler not found.
-      To compile rust language sources, you must have 'rustc' in your path.
-      See http://www.rust-lang.org/ for more information.])
-  fi
-  if test -n "$MOZ_RUST" && test -z "$_RUSTC_MAJOR_VERSION" -o \
-    "$_RUSTC_MAJOR_VERSION" -lt 1 -o \
-    \( "$_RUSTC_MAJOR_VERSION" -eq 1 -a "$_RUSTC_MINOR_VERSION" -lt 5 \); then
-    AC_MSG_ERROR([Rust compiler ${RUSTC_VERSION} is too old.
-      To compile Rust language sources please install at least
-      version 1.5 of the 'rustc' toolchain and make sure it is
-      first in your path.
-      You can verify this by typing 'rustc --version'.])
-  fi
-
-  if test -n "$RUSTC" -a -n "$MOZ_RUST"; then
-    # Rust's --target options are similar to, but not exactly the same
-    # as, the autoconf-derived targets we use.  An example would be that
-    # Rust uses distinct target triples for targetting the GNU C++ ABI
-    # and the MSVC C++ ABI on Win32, whereas autoconf has a single
-    # triple and relies on the user to ensure that everything is
-    # compiled for the appropriate ABI.  We need to perform appropriate
-    # munging to get the correct option to rustc.
-    #
-    # The canonical list of targets supported can be derived from:
-    #
-    # https://github.com/rust-lang/rust/tree/master/mk/cfg
-    rust_target=
-    case "$target" in
-      # Bitrig
-      x86_64-*-bitrig*)
-          rust_target=x86_64-unknown-bitrig
-          ;;
-
-      # DragonFly
-      x86_64-*-dragonfly*)
-          rust_target=x86_64-unknown-dragonfly
-          ;;
-
-      # FreeBSD, GNU/kFreeBSD
-      i*86-*-*freebsd*)
-          rust_target=i686-unknown-freebsd
-          ;;
-      x86_64-*-*freebsd*)
-          rust_target=x86_64-unknown-freebsd
-          ;;
-
-      # NetBSD
-      x86_64-*-netbsd*)
-          rust_target=x86_64-unknown-netbsd
-          ;;
-
-      # OpenBSD
-      x86_64-*-openbsd*)
-          rust_target=x86_64-unknown-openbsd
-          ;;
-
-      # Linux
-      i*86*linux-gnu)
-          rust_target=i686-unknown-linux-gnu
-          ;;
-      x86_64*linux-gnu)
-          rust_target=x86_64-unknown-linux-gnu
-          ;;
-
-      # OS X and iOS
-      i*86-apple-darwin*)
-          rust_target=i686-apple-darwin
-          ;;
-      i*86-apple-ios*)
-          rust_target=i386-apple-ios
-          ;;
-      x86_64-apple-darwin*)
-          rust_target=x86_64-apple-darwin
-          ;;
-
-      # Android
-      i*86*linux-android)
-          rust_target=i686-linux-android
-          ;;
-      arm*linux-android*)
-          rust_target=arm-linux-androideabi
-          ;;
-
-      # Windows
-      i*86-pc-mingw32)
-          # XXX better detection of CXX needed here, to figure out whether
-          # we need i686-pc-windows-gnu instead, since mingw32 builds work.
-          rust_target=i686-pc-windows-msvc
-          ;;
-      x86_64-pc-mingw32)
-          # XXX and here as well
-          rust_target=x86_64-pc-windows-msvc
-          ;;
-      *)
-          # Fall back to implicit (native) target when not cross-compiling
-          if test -n "$CROSS_COMPILE"; then
-            AC_ERROR([don't know how to translate $target for rustc])
-          fi
-          ;;
-    esac
-
-    if test -n "$rust_target"; then
-      # Check to see whether we need to pass --target to RUSTC.  This can
-      # happen when building Firefox on Windows: js's configure will receive
-      # a RUSTC from the toplevel configure that already has --target added to
-      # it.
-      rustc_target_arg=
-      case "$RUSTC" in
-        *--target=${rust_target}*)
-          ;;
-        *)
-          rustc_target_arg=--target=${rust_target}
-          ;;
-      esac
-    fi
-
-    # Check to see whether our rustc has a reasonably functional stdlib
-    # for our chosen target.
-    echo 'pub extern fn hello() { println!("Hello world"); }' > conftest.rs
-    if AC_TRY_COMMAND(${RUSTC} --crate-type staticlib ${rustc_target_arg} -o conftest.rlib conftest.rs > /dev/null) && test -s conftest.rlib; then
-      RUSTC="${RUSTC} ${rustc_target_arg}"
-    else
-      AC_ERROR([cannot compile for ${rust_target} with ${RUSTC}])
-    fi
-    rm -f conftest.rs conftest.rlib
-  fi
-
-  # TODO: separate HOST_RUSTC and RUSTC variables
-
-  AC_SUBST(MOZ_RUST)
-])
--- a/caps/nsJSPrincipals.cpp
+++ b/caps/nsJSPrincipals.cpp
@@ -83,18 +83,19 @@ nsJSPrincipals::Destroy(JSPrincipals *js
 #ifdef DEBUG
 
 // Defined here so one can do principals->dump() in the debugger
 JS_PUBLIC_API(void)
 JSPrincipals::dump()
 {
     if (debugToken == nsJSPrincipals::DEBUG_TOKEN) {
       nsAutoCString str;
-      static_cast<nsJSPrincipals *>(this)->GetScriptLocation(str);
-      fprintf(stderr, "nsIPrincipal (%p) = %s\n", static_cast<void*>(this), str.get());
+      nsresult rv = static_cast<nsJSPrincipals *>(this)->GetScriptLocation(str);
+      fprintf(stderr, "nsIPrincipal (%p) = %s\n", static_cast<void*>(this),
+              NS_SUCCEEDED(rv) ? str.get() : "(unknown)");
     } else if (debugToken == dom::workers::kJSPrincipalsDebugToken) {
         fprintf(stderr, "Web Worker principal singleton (%p)\n", this);
     } else {
         fprintf(stderr,
                 "!!! JSPrincipals (%p) is not nsJSPrincipals instance - bad token: "
                 "actual=0x%x expected=0x%x\n",
                 this, unsigned(debugToken), unsigned(nsJSPrincipals::DEBUG_TOKEN));
     }
--- a/caps/nsJSPrincipals.h
+++ b/caps/nsJSPrincipals.h
@@ -48,17 +48,17 @@ public:
   nsJSPrincipals() {
     refcount = 0;
     setDebugToken(DEBUG_TOKEN);
   }
 
   /**
    * Return a string that can be used as JS script filename in error reports.
    */
-  virtual void GetScriptLocation(nsACString &aStr) = 0;
+  virtual nsresult GetScriptLocation(nsACString &aStr) = 0;
   static const uint32_t DEBUG_TOKEN = 0x0bf41760;
 
 protected:
   virtual ~nsJSPrincipals() {
     setDebugToken(0);
   }
 
 };
--- a/caps/nsNullPrincipal.cpp
+++ b/caps/nsNullPrincipal.cpp
@@ -73,20 +73,20 @@ nsNullPrincipal::Init(const PrincipalOri
   mOriginAttributes = aOriginAttributes;
 
   mURI = nsNullPrincipalURI::Create();
   NS_ENSURE_TRUE(mURI, NS_ERROR_NOT_AVAILABLE);
 
   return NS_OK;
 }
 
-void
+nsresult
 nsNullPrincipal::GetScriptLocation(nsACString &aStr)
 {
-  mURI->GetSpec(aStr);
+  return mURI->GetSpec(aStr);
 }
 
 /**
  * nsIPrincipal implementation
  */
 
 NS_IMETHODIMP
 nsNullPrincipal::GetHashValue(uint32_t *aResult)
--- a/caps/nsNullPrincipal.h
+++ b/caps/nsNullPrincipal.h
@@ -52,17 +52,17 @@ public:
 
   static already_AddRefed<nsNullPrincipal> CreateWithInheritedAttributes(nsIDocShell* aDocShell);
 
   static already_AddRefed<nsNullPrincipal>
   Create(const mozilla::PrincipalOriginAttributes& aOriginAttributes = mozilla::PrincipalOriginAttributes());
 
   nsresult Init(const mozilla::PrincipalOriginAttributes& aOriginAttributes = mozilla::PrincipalOriginAttributes());
 
-  virtual void GetScriptLocation(nsACString &aStr) override;
+  virtual nsresult GetScriptLocation(nsACString &aStr) override;
 
   PrincipalKind Kind() override { return eNullPrincipal; }
 
  protected:
   virtual ~nsNullPrincipal() {}
 
   bool SubsumesInternal(nsIPrincipal* aOther, DocumentDomainConsideration aConsideration) override
   {
--- a/caps/nsNullPrincipalURI.cpp
+++ b/caps/nsNullPrincipalURI.cpp
@@ -91,17 +91,18 @@ nsNullPrincipalURI::GetAsciiHostPort(nsA
 {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP
 nsNullPrincipalURI::GetAsciiSpec(nsACString &_spec)
 {
   nsAutoCString buffer;
-  (void)GetSpec(buffer);
+  // Ignore the return value -- nsNullPrincipalURI::GetSpec() is infallible.
+  Unused << GetSpec(buffer);
   NS_EscapeURL(buffer, esc_OnlyNonASCII | esc_AlwaysCopy, _spec);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsNullPrincipalURI::GetHost(nsACString &_host)
 {
   _host.Truncate();
--- a/caps/nsPrincipal.cpp
+++ b/caps/nsPrincipal.cpp
@@ -94,20 +94,20 @@ nsPrincipal::Init(nsIURI *aCodebase, con
 
   mCodebase = NS_TryToMakeImmutable(aCodebase);
   mCodebaseImmutable = URIIsImmutable(mCodebase);
   mOriginAttributes = aOriginAttributes;
 
   return NS_OK;
 }
 
-void
+nsresult
 nsPrincipal::GetScriptLocation(nsACString &aStr)
 {
-  mCodebase->GetSpec(aStr);
+  return mCodebase->GetSpec(aStr);
 }
 
 /* static */ nsresult
 nsPrincipal::GetOriginForURI(nsIURI* aURI, nsACString& aOrigin)
 {
   if (!aURI) {
     return NS_ERROR_FAILURE;
   }
@@ -801,32 +801,34 @@ bool
 nsExpandedPrincipal::IsOnCSSUnprefixingWhitelist()
 {
   // CSS Unprefixing Whitelist is a per-origin thing; doesn't really make sense
   // for an expanded principal. (And probably shouldn't be needed.)
   return false;
 }
 
 
-void
+nsresult
 nsExpandedPrincipal::GetScriptLocation(nsACString& aStr)
 {
   aStr.Assign("[Expanded Principal [");
   for (size_t i = 0; i < mPrincipals.Length(); ++i) {
     if (i != 0) {
       aStr.AppendLiteral(", ");
     }
 
     nsAutoCString spec;
-    nsJSPrincipals::get(mPrincipals.ElementAt(i))->GetScriptLocation(spec);
+    nsresult rv =
+      nsJSPrincipals::get(mPrincipals.ElementAt(i))->GetScriptLocation(spec);
+    NS_ENSURE_SUCCESS(rv, rv);
 
     aStr.Append(spec);
-
   }
   aStr.Append("]]");
+  return NS_OK;
 }
 
 //////////////////////////////////////////
 // Methods implementing nsISerializable //
 //////////////////////////////////////////
 
 NS_IMETHODIMP
 nsExpandedPrincipal::Read(nsIObjectInputStream* aStream)
--- a/caps/nsPrincipal.h
+++ b/caps/nsPrincipal.h
@@ -29,17 +29,17 @@ public:
   bool IsCodebasePrincipal() const override { return true; }
   nsresult GetOriginInternal(nsACString& aOrigin) override;
 
   nsPrincipal();
 
   // Init() must be called before the principal is in a usable state.
   nsresult Init(nsIURI* aCodebase, const mozilla::PrincipalOriginAttributes& aOriginAttributes);
 
-  virtual void GetScriptLocation(nsACString& aStr) override;
+  virtual nsresult GetScriptLocation(nsACString& aStr) override;
   void SetURI(nsIURI* aURI);
 
   /**
    * Computes the puny-encoded origin of aURI.
    */
   static nsresult GetOriginForURI(nsIURI* aURI, nsACString& aOrigin);
 
   /**
@@ -76,17 +76,17 @@ public:
   NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr) override;
   NS_IMETHOD GetHashValue(uint32_t* aHashValue) override;
   NS_IMETHOD GetURI(nsIURI** aURI) override;
   NS_IMETHOD GetDomain(nsIURI** aDomain) override;
   NS_IMETHOD SetDomain(nsIURI* aDomain) override;
   NS_IMETHOD GetBaseDomain(nsACString& aBaseDomain) override;
   virtual bool AddonHasPermission(const nsAString& aPerm) override;
   virtual bool IsOnCSSUnprefixingWhitelist() override;
-  virtual void GetScriptLocation(nsACString &aStr) override;
+  virtual nsresult GetScriptLocation(nsACString &aStr) override;
   nsresult GetOriginInternal(nsACString& aOrigin) override;
 
   PrincipalKind Kind() override { return eExpandedPrincipal; }
 
 protected:
   virtual ~nsExpandedPrincipal();
 
   bool SubsumesInternal(nsIPrincipal* aOther, DocumentDomainConsideration aConsideration) override;
--- a/caps/nsSystemPrincipal.cpp
+++ b/caps/nsSystemPrincipal.cpp
@@ -26,20 +26,21 @@ NS_IMPL_QUERY_INTERFACE_CI(nsSystemPrinc
                            nsIPrincipal,
                            nsISerializable)
 NS_IMPL_CI_INTERFACE_GETTER(nsSystemPrincipal,
                             nsIPrincipal,
                             nsISerializable)
 
 #define SYSTEM_PRINCIPAL_SPEC "[System Principal]"
 
-void
+nsresult
 nsSystemPrincipal::GetScriptLocation(nsACString &aStr)
 {
     aStr.AssignLiteral(SYSTEM_PRINCIPAL_SPEC);
+    return NS_OK;
 }
 
 ///////////////////////////////////////
 // Methods implementing nsIPrincipal //
 ///////////////////////////////////////
 
 NS_IMETHODIMP
 nsSystemPrincipal::GetHashValue(uint32_t *result)
--- a/caps/nsSystemPrincipal.h
+++ b/caps/nsSystemPrincipal.h
@@ -33,17 +33,17 @@ public:
   NS_IMETHOD EnsureCSP(nsIDOMDocument* aDocument, nsIContentSecurityPolicy** aCSP) override;
   NS_IMETHOD GetPreloadCsp(nsIContentSecurityPolicy** aPreloadCSP) override;
   NS_IMETHOD EnsurePreloadCSP(nsIDOMDocument* aDocument, nsIContentSecurityPolicy** aCSP) override;
   NS_IMETHOD GetBaseDomain(nsACString& aBaseDomain) override;
   nsresult GetOriginInternal(nsACString& aOrigin) override;
 
   nsSystemPrincipal() {}
 
-  virtual void GetScriptLocation(nsACString &aStr) override;
+  virtual nsresult GetScriptLocation(nsACString &aStr) override;
 
 protected:
   virtual ~nsSystemPrincipal(void) {}
 
   bool SubsumesInternal(nsIPrincipal *aOther, DocumentDomainConsideration aConsideration) override
   {
     return true;
   }
--- a/chrome/nsChromeRegistryChrome.cpp
+++ b/chrome/nsChromeRegistryChrome.cpp
@@ -421,17 +421,18 @@ nsChromeRegistryChrome::SendRegisteredCh
     NS_ENSURE_TRUE_VOID(io);
 
     nsCOMPtr<nsIProtocolHandler> ph;
     nsresult rv = io->GetProtocolHandler("resource", getter_AddRefs(ph));
     NS_ENSURE_SUCCESS_VOID(rv);
 
     nsCOMPtr<nsIResProtocolHandler> irph (do_QueryInterface(ph));
     nsResProtocolHandler* rph = static_cast<nsResProtocolHandler*>(irph.get());
-    rph->CollectSubstitutions(resources);
+    rv = rph->CollectSubstitutions(resources);
+    NS_ENSURE_SUCCESS_VOID(rv);
   }
 
   for (auto iter = mOverrideTable.Iter(); !iter.Done(); iter.Next()) {
     SerializedURI chromeURI, overrideURI;
 
     SerializeURI(iter.Key(), chromeURI);
     SerializeURI(iter.UserData(), overrideURI);
 
--- a/devtools/client/debugger/new/index.html
+++ b/devtools/client/debugger/new/index.html
@@ -1,18 +1,29 @@
 <!-- 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/. -->
 <!DOCTYPE html>
 <html>
   <head>
     <link rel="stylesheet" type="text/css" href="resource://devtools/client/debugger/new/styles.css" />
+    <link rel="stylesheet"
+          type="text/css"
+          href="chrome://devtools/content/sourceeditor/codemirror/lib/codemirror.css" />
+    <link rel="stylesheet"
+          type="text/css"
+          href="chrome://devtools/content/sourceeditor/codemirror/addon/dialog/dialog.css" />
+    <link rel="stylesheet"
+          type="text/css"
+          href="chrome://devtools/content/sourceeditor/codemirror/mozilla.css" />
   </head>
   <body>
     <div id="mount"></div>
+    <script type="application/javascript;version=1.8"
+            src="chrome://devtools/content/shared/theme-switching.js"></script>
     <script type="text/javascript">
       const { BrowserLoader } = Components.utils.import("resource://devtools/client/shared/browser-loader.js", {});
       const { require: devtoolsRequire } = BrowserLoader({
         baseURI: "resource://devtools/client/debugger/new/",
         window,
       });
     </script>
     <script type="text/javascript" src="resource://devtools/client/debugger/new/bundle.js"></script>
--- a/devtools/client/webide/test/chrome.ini
+++ b/devtools/client/webide/test/chrome.ini
@@ -61,10 +61,11 @@ skip-if = true # Bug 1201392 - Update ad
 [test_telemetry.html]
 skip-if = true # Bug 1201392 - Update add-ons after migration
 [test_device_preferences.html]
 [test_device_settings.html]
 [test_fullscreenToolbox.html]
 [test_zoom.html]
 [test_build.html]
 [test_simulators.html]
+skip-if = true # Bug 1281138 - intermittent failures
 [test_toolbox.html]
 [test_app_validator.html]
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -12270,27 +12270,35 @@ nsDocShell::AddToSessionHistory(nsIURI* 
       nsCOMPtr<nsISHEntry> newEntry;
       CloneAndReplace(mOSHE, this, cloneID, entry, true,
                       getter_AddRefs(newEntry));
       NS_ASSERTION(entry == newEntry,
                    "The new session history should be in the new entry");
     }
 
     // This is the root docshell
-    if (LOAD_TYPE_HAS_FLAGS(mLoadType, LOAD_FLAGS_REPLACE_HISTORY)) {
+    bool addToSHistory = !LOAD_TYPE_HAS_FLAGS(mLoadType, LOAD_FLAGS_REPLACE_HISTORY);
+    if (!addToSHistory) {
       // Replace current entry in session history.
       int32_t index = 0;
       mSessionHistory->GetIndex(&index);
       nsCOMPtr<nsISHistoryInternal> shPrivate =
         do_QueryInterface(mSessionHistory);
       // Replace the current entry with the new entry
-      if (shPrivate) {
-        rv = shPrivate->ReplaceEntry(index, entry);
-      }
-    } else {
+      if (index >= 0) {
+        if (shPrivate) {
+          rv = shPrivate->ReplaceEntry(index, entry);
+        }
+      } else {
+        // If we're trying to replace an inexistant shistory entry, append.
+        addToSHistory = true;
+      }
+    }
+
+    if (addToSHistory) {
       // Add to session history
       nsCOMPtr<nsISHistoryInternal> shPrivate =
         do_QueryInterface(mSessionHistory);
       NS_ENSURE_TRUE(shPrivate, NS_ERROR_FAILURE);
       mSessionHistory->GetIndex(&mPreviousTransIndex);
       rv = shPrivate->AddEntry(entry, shouldPersist);
       mSessionHistory->GetIndex(&mLoadedTransIndex);
 #ifdef DEBUG_PAGE_CACHE
--- a/dom/animation/KeyframeEffect.cpp
+++ b/dom/animation/KeyframeEffect.cpp
@@ -1,17 +1,17 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/KeyframeEffect.h"
 
-#include "mozilla/dom/AnimatableBinding.h"
+#include "mozilla/dom/KeyframeAnimationOptionsBinding.h"
   // For UnrestrictedDoubleOrKeyframeAnimationOptions
 #include "mozilla/dom/AnimationEffectTiming.h"
 #include "mozilla/dom/KeyframeEffectBinding.h"
 #include "mozilla/KeyframeUtils.h"
 #include "nsDOMMutationObserver.h" // For nsAutoAnimationMutationBatch
 #include "nsIScriptError.h"
 
 namespace mozilla {
--- a/dom/animation/KeyframeEffectReadOnly.cpp
+++ b/dom/animation/KeyframeEffectReadOnly.cpp
@@ -1,17 +1,17 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/KeyframeEffectReadOnly.h"
 
-#include "mozilla/dom/AnimatableBinding.h"
+#include "mozilla/dom/KeyframeAnimationOptionsBinding.h"
   // For UnrestrictedDoubleOrKeyframeAnimationOptions;
 #include "mozilla/dom/CSSPseudoElement.h"
 #include "mozilla/dom/KeyframeEffectBinding.h"
 #include "mozilla/AnimationUtils.h"
 #include "mozilla/EffectSet.h"
 #include "mozilla/FloatingPoint.h" // For IsFinite
 #include "mozilla/LookAndFeel.h" // For LookAndFeel::GetInt
 #include "mozilla/KeyframeUtils.h"
--- a/dom/animation/TimingParams.cpp
+++ b/dom/animation/TimingParams.cpp
@@ -3,16 +3,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/TimingParams.h"
 
 #include "mozilla/AnimationUtils.h"
 #include "mozilla/dom/AnimatableBinding.h"
+#include "mozilla/dom/KeyframeAnimationOptionsBinding.h"
 #include "mozilla/dom/KeyframeEffectBinding.h"
 #include "nsCSSParser.h" // For nsCSSParser
 #include "nsIDocument.h"
 #include "nsRuleNode.h"
 
 namespace mozilla {
 
 template <class OptionsType>
--- a/dom/base/AnonymousContent.cpp
+++ b/dom/base/AnonymousContent.cpp
@@ -132,16 +132,33 @@ AnonymousContent::GetCanvasContext(const
   nsCOMPtr<nsISupports> context;
 
   HTMLCanvasElement* canvas = static_cast<HTMLCanvasElement*>(element);
   canvas->GetContext(aContextId, getter_AddRefs(context));
 
   return context.forget();
 }
 
+already_AddRefed<Animation>
+AnonymousContent::SetAnimationForElement(JSContext* aContext,
+                                         const nsAString& aElementId,
+                                         JS::Handle<JSObject*> aKeyframes,
+                                         const UnrestrictedDoubleOrKeyframeAnimationOptions& aOptions,
+                                         ErrorResult& aRv)
+{
+  Element* element = GetElementById(aElementId);
+
+  if (!element) {
+    aRv.Throw(NS_ERROR_NOT_AVAILABLE);
+    return nullptr;
+  }
+
+  return element->Animate(aContext, aKeyframes, aOptions, aRv);
+}
+
 Element*
 AnonymousContent::GetElementById(const nsAString& aElementId)
 {
   // This can be made faster in the future if needed.
   nsCOMPtr<nsIAtom> elementId = NS_Atomize(aElementId);
   for (nsIContent* kid = mContentNode->GetFirstChild(); kid;
        kid = kid->GetNextNode(mContentNode)) {
     if (!kid->IsElement()) {
--- a/dom/base/AnonymousContent.h
+++ b/dom/base/AnonymousContent.h
@@ -11,16 +11,17 @@
 #include "nsCycleCollectionParticipant.h"
 #include "nsICSSDeclaration.h"
 #include "nsIDocument.h"
 
 namespace mozilla {
 namespace dom {
 
 class Element;
+class UnrestrictedDoubleOrAnonymousKeyframeAnimationOptions;
 
 class AnonymousContent final
 {
 public:
   // Ref counting and cycle collection
   NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(AnonymousContent)
   NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(AnonymousContent)
 
@@ -52,16 +53,22 @@ public:
   void RemoveAttributeForElement(const nsAString& aElementId,
                                  const nsAString& aName,
                                  ErrorResult& aRv);
 
   already_AddRefed<nsISupports> GetCanvasContext(const nsAString& aElementId,
                                                  const nsAString& aContextId,
                                                  ErrorResult& aRv);
 
+  already_AddRefed<Animation> SetAnimationForElement(JSContext* aContext,
+                                                     const nsAString& aElementId,
+                                                     JS::Handle<JSObject*> aKeyframes,
+                                                     const UnrestrictedDoubleOrKeyframeAnimationOptions& aOptions,
+                                                     ErrorResult& aError);
+
 private:
   ~AnonymousContent();
   nsCOMPtr<Element> mContentNode;
 };
 
 } // namespace dom
 } // namespace mozilla
 
--- a/dom/base/DOMMatrix.cpp
+++ b/dom/base/DOMMatrix.cpp
@@ -202,43 +202,43 @@ DOMMatrixReadOnly::TransformPoint(const 
 
   if (mMatrix3D) {
     gfx::Point4D transformedPoint;
     transformedPoint.x = point.mX;
     transformedPoint.y = point.mY;
     transformedPoint.z = point.mZ;
     transformedPoint.w = point.mW;
 
-    transformedPoint = *mMatrix3D * transformedPoint;
+    transformedPoint = mMatrix3D->TransformPoint(transformedPoint);
 
     retval->SetX(transformedPoint.x);
     retval->SetY(transformedPoint.y);
     retval->SetZ(transformedPoint.z);
     retval->SetW(transformedPoint.w);
   } else if (point.mZ != 0 || point.mW != 1.0) {
     gfx::Matrix4x4 tempMatrix(gfx::Matrix4x4::From2D(*mMatrix2D));
 
     gfx::Point4D transformedPoint;
     transformedPoint.x = point.mX;
     transformedPoint.y = point.mY;
     transformedPoint.z = point.mZ;
     transformedPoint.w = point.mW;
 
-    transformedPoint = tempMatrix * transformedPoint;
+    transformedPoint = tempMatrix.TransformPoint(transformedPoint);
 
     retval->SetX(transformedPoint.x);
     retval->SetY(transformedPoint.y);
     retval->SetZ(transformedPoint.z);
     retval->SetW(transformedPoint.w);
   } else {
     gfx::Point transformedPoint;
     transformedPoint.x = point.mX;
     transformedPoint.y = point.mY;
 
-    transformedPoint = *mMatrix2D * transformedPoint;
+    transformedPoint = mMatrix2D->TransformPoint(transformedPoint);
 
     retval->SetX(transformedPoint.x);
     retval->SetY(transformedPoint.y);
     retval->SetZ(point.mZ);
     retval->SetW(point.mW);
   }
   return retval.forget();
 }
--- a/dom/base/Element.cpp
+++ b/dom/base/Element.cpp
@@ -48,16 +48,17 @@
 #include "nsVariant.h"
 #include "nsDOMTokenList.h"
 #include "nsXBLPrototypeBinding.h"
 #include "nsError.h"
 #include "nsDOMString.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsIDOMMutationEvent.h"
 #include "mozilla/dom/AnimatableBinding.h"
+#include "mozilla/dom/KeyframeAnimationOptionsBinding.h"
 #include "mozilla/AnimationComparator.h"
 #include "mozilla/AsyncEventDispatcher.h"
 #include "mozilla/ContentEvents.h"
 #include "mozilla/EffectSet.h"
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/EventListenerManager.h"
 #include "mozilla/EventStateManager.h"
 #include "mozilla/EventStates.h"
--- a/dom/base/FragmentOrElement.cpp
+++ b/dom/base/FragmentOrElement.cpp
@@ -1854,17 +1854,17 @@ static const char* kNSURIs[] = {
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(FragmentOrElement)
   if (MOZ_UNLIKELY(cb.WantDebugInfo())) {
     char name[512];
     uint32_t nsid = tmp->GetNameSpaceID();
     nsAtomCString localName(tmp->NodeInfo()->NameAtom());
     nsAutoCString uri;
     if (tmp->OwnerDoc()->GetDocumentURI()) {
-      tmp->OwnerDoc()->GetDocumentURI()->GetSpec(uri);
+      uri = tmp->OwnerDoc()->GetDocumentURI()->GetSpecOrDefault();
     }
 
     nsAutoString id;
     nsIAtom* idAtom = tmp->GetID();
     if (idAtom) {
       id.AppendLiteral(" id='");
       id.Append(nsDependentAtomString(idAtom));
       id.Append('\'');
--- a/dom/base/nsContentAreaDragDrop.cpp
+++ b/dom/base/nsContentAreaDragDrop.cpp
@@ -80,17 +80,18 @@ private:
                  nsIPrincipal* aPrincipal);
   nsresult AddStringsToDataTransfer(nsIContent* aDragNode,
                                     DataTransfer* aDataTransfer);
   static nsresult GetDraggableSelectionData(nsISelection* inSelection,
                                             nsIContent* inRealTargetNode,
                                             nsIContent **outImageOrLinkNode,
                                             bool* outDragSelectedText);
   static already_AddRefed<nsIContent> FindParentLinkNode(nsIContent* inNode);
-  static void GetAnchorURL(nsIContent* inNode, nsAString& outURL);
+  static MOZ_MUST_USE nsresult
+  GetAnchorURL(nsIContent* inNode, nsAString& outURL);
   static void GetNodeString(nsIContent* inNode, nsAString & outNodeString);
   static void CreateLinkText(const nsAString& inURL, const nsAString & inText,
                               nsAString& outLinkText);
 
   nsCOMPtr<nsPIDOMWindowOuter> mWindow;
   nsCOMPtr<nsIContent> mTarget;
   nsCOMPtr<nsIContent> mSelectionTargetNode;
   bool mIsAltKeyPressed;
@@ -290,29 +291,31 @@ DragDataProducer::FindParentLinkNode(nsI
 
   return nullptr;
 }
 
 
 //
 // GetAnchorURL
 //
-void
+nsresult
 DragDataProducer::GetAnchorURL(nsIContent* inNode, nsAString& outURL)
 {
   nsCOMPtr<nsIURI> linkURI;
   if (!inNode || !inNode->IsLink(getter_AddRefs(linkURI))) {
     // Not a link
     outURL.Truncate();
-    return;
+    return NS_OK;
   }
 
   nsAutoCString spec;
-  linkURI->GetSpec(spec);
+  nsresult rv = linkURI->GetSpec(spec);
+  NS_ENSURE_SUCCESS(rv, rv);
   CopyUTF8toUTF16(spec, outURL);
+  return NS_OK;
 }
 
 
 //
 // CreateLinkText
 //
 // Creates the html for an anchor in the form
 //  <a href="inURL">inText</a>
@@ -516,17 +519,18 @@ DragDataProducer::Produce(DataTransfer* 
           // this can be a relative link
           areaElem->GetAttribute(NS_LITERAL_STRING("href"), mTitleString);
         }
 
         // we'll generate HTML like <a href="absurl">alt text</a>
         mIsAnchor = true;
 
         // gives an absolute link
-        GetAnchorURL(draggedNode, mUrlString);
+        nsresult rv = GetAnchorURL(draggedNode, mUrlString);
+        NS_ENSURE_SUCCESS(rv, rv);
 
         mHtmlString.AssignLiteral("<a href=\"");
         mHtmlString.Append(mUrlString);
         mHtmlString.AppendLiteral("\">");
         mHtmlString.Append(mTitleString);
         mHtmlString.AppendLiteral("</a>");
 
         dragNode = draggedNode;
@@ -534,17 +538,18 @@ DragDataProducer::Produce(DataTransfer* 
         mIsAnchor = true;
         // grab the href as the url, use alt text as the title of the
         // area if it's there.  the drag data is the image tag and src
         // attribute.
         nsCOMPtr<nsIURI> imageURI;
         image->GetCurrentURI(getter_AddRefs(imageURI));
         if (imageURI) {
           nsAutoCString spec;
-          imageURI->GetSpec(spec);
+          rv = imageURI->GetSpec(spec);
+          NS_ENSURE_SUCCESS(rv, rv);
           CopyUTF8toUTF16(spec, mUrlString);
         }
 
         nsCOMPtr<nsIDOMElement> imageElement(do_QueryInterface(image));
         // XXXbz Shouldn't we use the "title" attr for title?  Using
         // "alt" seems very wrong....
         if (imageElement) {
           imageElement->GetAttribute(NS_LITERAL_STRING("alt"), mTitleString);
@@ -579,17 +584,18 @@ DragDataProducer::Produce(DataTransfer* 
             imgRequest->GetMimeType(getter_Copies(mimeType));
 
             nsCOMPtr<nsIMIMEInfo> mimeInfo;
             mimeService->GetFromTypeAndExtension(mimeType, EmptyCString(),
                                                  getter_AddRefs(mimeInfo));
 
             if (mimeInfo) {
               nsAutoCString spec;
-              imgUrl->GetSpec(spec);
+              rv = imgUrl->GetSpec(spec);
+              NS_ENSURE_SUCCESS(rv, rv);
 
               // pass out the image source string
               CopyUTF8toUTF16(spec, mImageSourceString);
 
               bool validExtension;
               if (extension.IsEmpty() || 
                   NS_FAILED(mimeInfo->ExtensionExists(extension,
                                                       &validExtension)) ||
@@ -642,17 +648,18 @@ DragDataProducer::Produce(DataTransfer* 
         nodeToSerialize = linkNode;
       } else if (!haveSelectedContent) {
         // nothing draggable
         return NS_OK;
       }
 
       if (linkNode) {
         mIsAnchor = true;
-        GetAnchorURL(linkNode, mUrlString);
+        rv = GetAnchorURL(linkNode, mUrlString);
+        NS_ENSURE_SUCCESS(rv, rv);
         dragNode = linkNode;
       }
     }
   }
 
   if (nodeToSerialize || *aSelection) {
     mHtmlString.Truncate();
     mContextString.Truncate();
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -3588,17 +3588,17 @@ nsContentUtils::ReportToConsoleNonLocali
   nsAutoCString spec;
   if (!aLineNumber && aLocationMode == eUSE_CALLING_LOCATION) {
     JSContext *cx = GetCurrentJSContext();
     if (cx) {
       nsJSUtils::GetCallingLocation(cx, spec, &aLineNumber, &aColumnNumber);
     }
   }
   if (spec.IsEmpty() && aURI) {
-    aURI->GetSpec(spec);
+    spec = aURI->GetSpecOrDefault();
   }
 
   nsCOMPtr<nsIScriptError> errorObject =
       do_CreateInstance(NS_SCRIPTERROR_CONTRACTID, &rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = errorObject->InitWithWindowID(aErrorText,
                                      NS_ConvertUTF8toUTF16(spec), // file name
@@ -3670,17 +3670,18 @@ nsContentUtils::IsPlainTextType(const ns
 }
 
 bool
 nsContentUtils::GetWrapperSafeScriptFilename(nsIDocument *aDocument,
                                              nsIURI *aURI,
                                              nsACString& aScriptURI)
 {
   bool scriptFileNameModified = false;
-  aURI->GetSpec(aScriptURI);
+  // XXX: should handle GetSpec() failure properly. See bug 1301251.
+  Unused << aURI->GetSpec(aScriptURI);
 
   if (IsChromeDoc(aDocument)) {
     nsCOMPtr<nsIChromeRegistry> chromeReg =
       mozilla::services::GetChromeRegistryService();
 
     if (!chromeReg) {
       // If we're running w/o a chrome registry we won't modify any
       // script file names.
@@ -3698,17 +3699,18 @@ nsContentUtils::GetWrapperSafeScriptFile
     if (docURI && docWrappersEnabled && !uriWrappersEnabled) {
       // aURI is a script from a URL that doesn't get wrapper
       // automation. aDocument is a chrome document that does get
       // wrapper automation. Prepend the chrome document's URI
       // followed by the string " -> " to the URI of the script we're
       // loading here so that script in that URI gets the same wrapper
       // automation that the chrome document expects.
       nsAutoCString spec;
-      docURI->GetSpec(spec);
+      // XXX: should handle GetSpec() failure properly. See bug 1301251.
+      Unused << docURI->GetSpec(spec);
       spec.AppendLiteral(" -> ");
       spec.Append(aScriptURI);
 
       aScriptURI = spec;
 
       scriptFileNameModified = true;
     }
   }
@@ -9232,17 +9234,16 @@ nsContentUtils::IsSpecificAboutPage(JSOb
   MOZ_ASSERT(strncmp(aUri, "about:", 6) == 0);
 
   // Make sure the global is a window
   nsGlobalWindow* win = xpc::WindowGlobalOrNull(aGlobal);
   if (!win) {
     return false;
   }
 
-  // Make sure that the principal is about:feeds.
   nsCOMPtr<nsIPrincipal> principal = win->GetPrincipal();
   NS_ENSURE_TRUE(principal, false);
   nsCOMPtr<nsIURI> uri;
   principal->GetURI(getter_AddRefs(uri));
   if (!uri) {
     return false;
   }
 
@@ -9250,17 +9251,17 @@ nsContentUtils::IsSpecificAboutPage(JSOb
   bool isAbout = false;
   uri->SchemeIs("about", &isAbout);
   if (!isAbout) {
     return false;
   }
 
   // Now check the spec itself
   nsAutoCString spec;
-  uri->GetSpec(spec);
+  uri->GetSpecIgnoringRef(spec);
   return spec.EqualsASCII(aUri);
 }
 
 /* static */ void
 nsContentUtils::SetScrollbarsVisibility(nsIDocShell* aDocShell, bool aVisible)
 {
   nsCOMPtr<nsIScrollable> scroller = do_QueryInterface(aDocShell);
 
--- a/dom/base/nsCopySupport.cpp
+++ b/dom/base/nsCopySupport.cpp
@@ -250,17 +250,18 @@ SelectionCopyHelper(nsISelection *aSel, 
           rv = AppendString(trans, textPlainBuf, kUnicodeMime);
           NS_ENSURE_SUCCESS(rv, rv);
         }
 
         // Try and get source URI of the items that are being dragged
         nsIURI *uri = aDoc->GetDocumentURI();
         if (uri) {
           nsAutoCString spec;
-          uri->GetSpec(spec);
+          nsresult rv = uri->GetSpec(spec);
+          NS_ENSURE_SUCCESS(rv, rv);
           if (!spec.IsEmpty()) {
             nsAutoString shortcut;
             AppendUTF8toUTF16(spec, shortcut);
 
             // Add the URL DataFlavor to the transferable. Don't use kURLMime, as it will
             // cause an unnecessary UniformResourceLocator to be added which confuses
             // some apps eg. Outlook 2000 - (See Bug 315370). Don't use
             // kURLDataMime, as it will cause a bogus 'url ' flavor to
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -7076,17 +7076,18 @@ nsDocument::GetDocumentURI(nsAString& aD
   return NS_OK;
 }
 
 void
 nsIDocument::GetDocumentURI(nsString& aDocumentURI) const
 {
   if (mDocumentURI) {
     nsAutoCString uri;
-    mDocumentURI->GetSpec(uri);
+    // XXX: should handle GetSpec() failure properly. See bug 1301249.
+    Unused << mDocumentURI->GetSpec(uri);
     CopyUTF8toUTF16(uri, aDocumentURI);
   } else {
     aDocumentURI.Truncate();
   }
 }
 
 // Alias of above
 NS_IMETHODIMP
@@ -7097,24 +7098,28 @@ nsDocument::GetURL(nsAString& aURL)
 
 void
 nsIDocument::GetURL(nsString& aURL) const
 {
   return GetDocumentURI(aURL);
 }
 
 void
-nsIDocument::GetDocumentURIFromJS(nsString& aDocumentURI) const
+nsIDocument::GetDocumentURIFromJS(nsString& aDocumentURI, ErrorResult& aRv) const
 {
   if (!mChromeXHRDocURI || !nsContentUtils::IsCallerChrome()) {
     return GetDocumentURI(aDocumentURI);
   }
 
   nsAutoCString uri;
-  mChromeXHRDocURI->GetSpec(uri);
+  nsresult res = mChromeXHRDocURI->GetSpec(uri);
+  if (NS_FAILED(res)) {
+    aRv.Throw(res);
+    return;
+  }
   CopyUTF8toUTF16(uri, aDocumentURI);
 }
 
 nsIURI*
 nsIDocument::GetDocumentURIObject() const
 {
   if (!mChromeXHRDocURI) {
     return GetDocumentURI();
@@ -9592,17 +9597,21 @@ nsDocument::SetScrollToRef(nsIURI *aDocu
 
   nsAutoCString ref;
 
   // Since all URI's that pass through here aren't URL's we can't
   // rely on the nsIURI implementation for providing a way for
   // finding the 'ref' part of the URI, we'll haveto revert to
   // string routines for finding the data past '#'
 
-  aDocumentURI->GetSpec(ref);
+  nsresult rv = aDocumentURI->GetSpec(ref);
+  if (NS_FAILED(rv)) {
+    Unused << aDocumentURI->GetRef(mScrollToRef);
+    return;
+  }
 
   nsReadingIterator<char> start, end;
 
   ref.BeginReading(start);
   ref.EndReading(end);
 
   if (FindCharInReadable('#', start, end)) {
     ++start; // Skip over the '#'
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -2157,16 +2157,17 @@ nsGlobalWindow::SetInitialPrincipalToSub
   MOZ_ASSERT(IsOuterWindow());
 
   // First, grab the subject principal.
   nsCOMPtr<nsIPrincipal> newWindowPrincipal = nsContentUtils::SubjectPrincipalOrSystemIfNativeCaller();
 
   // We should never create windows with an expanded principal.
   // If we have a system principal, make sure we're not using it for a content
   // docshell.
+  // NOTE: Please keep this logic in sync with nsWebShellWindow::Initialize().
   if (nsContentUtils::IsExpandedPrincipal(newWindowPrincipal) ||
       (nsContentUtils::IsSystemPrincipal(newWindowPrincipal) &&
        GetDocShell()->ItemType() != nsIDocShellTreeItem::typeChrome)) {
     newWindowPrincipal = nullptr;
   }
 
   // If there's an existing document, bail if it either:
   if (mDoc) {
@@ -10167,18 +10168,20 @@ nsGlobalWindow::DispatchAsyncHashchange(
   bool oldHasHash, newHasHash;
   NS_ENSURE_STATE(NS_SUCCEEDED(aOldURI->GetRef(oldHash)) &&
                   NS_SUCCEEDED(aNewURI->GetRef(newHash)) &&
                   NS_SUCCEEDED(aOldURI->GetHasRef(&oldHasHash)) &&
                   NS_SUCCEEDED(aNewURI->GetHasRef(&newHasHash)) &&
                   (oldHasHash != newHasHash || !oldHash.Equals(newHash)));
 
   nsAutoCString oldSpec, newSpec;
-  aOldURI->GetSpec(oldSpec);
-  aNewURI->GetSpec(newSpec);
+  nsresult rv = aOldURI->GetSpec(oldSpec);
+  NS_ENSURE_SUCCESS(rv, rv);
+  rv = aNewURI->GetSpec(newSpec);
+  NS_ENSURE_SUCCESS(rv, rv);
 
   NS_ConvertUTF8toUTF16 oldWideSpec(oldSpec);
   NS_ConvertUTF8toUTF16 newWideSpec(newSpec);
 
   nsCOMPtr<nsIRunnable> callback =
     new HashchangeCallback(oldWideSpec, newWideSpec, this);
   return NS_DispatchToMainThread(callback);
 }
--- a/dom/base/nsHostObjectProtocolHandler.cpp
+++ b/dom/base/nsHostObjectProtocolHandler.cpp
@@ -897,17 +897,18 @@ nsFontTableProtocolHandler::NewURI(const
 
     uri->SetRef(aSpec);
   } else {
     // Relative URIs (other than #ref) are not meaningful within the
     // fonttable: scheme.
     // If aSpec is a relative URI -other- than a bare #ref,
     // this will leave uri empty, and we'll return a failure code below.
     uri = new mozilla::net::nsSimpleURI();
-    uri->SetSpec(aSpec);
+    nsresult rv = uri->SetSpec(aSpec);
+    NS_ENSURE_SUCCESS(rv, rv);
   }
 
   bool schemeIs;
   if (NS_FAILED(uri->SchemeIs(FONTTABLEURI_SCHEME, &schemeIs)) || !schemeIs) {
     NS_WARNING("Non-fonttable spec in nsFontTableProtocolHander");
     return NS_ERROR_NOT_AVAILABLE;
   }
 
--- a/dom/base/nsIDocument.h
+++ b/dom/base/nsIDocument.h
@@ -2467,17 +2467,18 @@ public:
   virtual mozilla::dom::DOMImplementation*
     GetImplementation(mozilla::ErrorResult& rv) = 0;
   void GetURL(nsString& retval) const;
   void GetDocumentURI(nsString& retval) const;
   // Return the URI for the document.
   // The returned value may differ if the document is loaded via XHR, and
   // when accessed from chrome privileged script and
   // from content privileged script for compatibility.
-  void GetDocumentURIFromJS(nsString& aDocumentURI) const;
+  void GetDocumentURIFromJS(nsString& aDocumentURI,
+                            mozilla::ErrorResult& aRv) const;
   void GetCompatMode(nsString& retval) const;
   void GetCharacterSet(nsAString& retval) const;
   // Skip GetContentType, because our NS_IMETHOD version above works fine here.
   // GetDoctype defined above
   Element* GetDocumentElement() const
   {
     return GetRootElement();
   }
--- a/dom/base/nsINode.cpp
+++ b/dom/base/nsINode.cpp
@@ -689,29 +689,34 @@ nsINode::Normalize()
 
 void
 nsINode::GetBaseURI(nsAString &aURI) const
 {
   nsCOMPtr<nsIURI> baseURI = GetBaseURI();
 
   nsAutoCString spec;
   if (baseURI) {
-    baseURI->GetSpec(spec);
+    // XXX: should handle GetSpec() failure properly. See bug 1301254.
+    Unused << baseURI->GetSpec(spec);
   }
 
   CopyUTF8toUTF16(spec, aURI);
 }
 
 void
-nsINode::GetBaseURIFromJS(nsAString& aURI) const
+nsINode::GetBaseURIFromJS(nsAString& aURI, ErrorResult& aRv) const
 {
   nsCOMPtr<nsIURI> baseURI = GetBaseURI(nsContentUtils::IsCallerChrome());
   nsAutoCString spec;
   if (baseURI) {
-    baseURI->GetSpec(spec);
+    nsresult res = baseURI->GetSpec(spec);
+    if (NS_FAILED(res)) {
+      aRv.Throw(res);
+      return;
+    }
   }
   CopyUTF8toUTF16(spec, aURI);
 }
 
 already_AddRefed<nsIURI>
 nsINode::GetBaseURIObject() const
 {
   return GetBaseURI(true);
--- a/dom/base/nsINode.h
+++ b/dom/base/nsINode.h
@@ -1826,17 +1826,17 @@ public:
     aNodeName.SetStringBuffer(nsStringBuffer::FromString(nodeName),
                               nodeName.Length());
   }
   void GetBaseURI(nsAString& aBaseURI) const;
   // Return the base URI for the document.
   // The returned value may differ if the document is loaded via XHR, and
   // when accessed from chrome privileged script and
   // from content privileged script for compatibility.
-  void GetBaseURIFromJS(nsAString& aBaseURI) const;
+  void GetBaseURIFromJS(nsAString& aBaseURI, mozilla::ErrorResult& aRv) const;
   bool HasChildNodes() const
   {
     return HasChildren();
   }
   uint16_t CompareDocumentPosition(nsINode& aOther) const;
   void GetNodeValue(nsAString& aNodeValue)
   {
     GetNodeValueInternal(aNodeValue);
--- a/dom/base/nsInProcessTabChildGlobal.cpp
+++ b/dom/base/nsInProcessTabChildGlobal.cpp
@@ -293,17 +293,18 @@ nsInProcessTabChildGlobal::InitTabChildG
 {
   // If you change this, please change GetCompartmentName() in XPCJSRuntime.cpp
   // accordingly.
   nsAutoCString id;
   id.AssignLiteral("inProcessTabChildGlobal");
   nsIURI* uri = mOwner->OwnerDoc()->GetDocumentURI();
   if (uri) {
     nsAutoCString u;
-    uri->GetSpec(u);
+    nsresult rv = uri->GetSpec(u);
+    NS_ENSURE_SUCCESS(rv, rv);
     id.AppendLiteral("?ownedBy=");
     id.Append(u);
   }
   nsISupports* scopeSupports = NS_ISUPPORTS_CAST(EventTarget*, this);
   NS_ENSURE_STATE(InitChildGlobalInternal(scopeSupports, id));
   return NS_OK;
 }
 
--- a/dom/base/nsObjectLoadingContent.cpp
+++ b/dom/base/nsObjectLoadingContent.cpp
@@ -535,17 +535,23 @@ IsSupportedImage(const nsCString& aMimeT
 static void
 GetExtensionFromURI(nsIURI* uri, nsCString& ext)
 {
   nsCOMPtr<nsIURL> url(do_QueryInterface(uri));
   if (url) {
     url->GetFileExtension(ext);
   } else {
     nsCString spec;
-    uri->GetSpec(spec);
+    nsresult rv = uri->GetSpec(spec);
+    if (NS_FAILED(rv)) {
+      // This means we could incorrectly think a plugin is not enabled for
+      // the URI when it is, but that's not so bad.
+      ext.Truncate();
+      return;
+    }
 
     int32_t offset = spec.RFindChar('.');
     if (offset != kNotFound) {
       ext = Substring(spec, offset + 1, spec.Length());
     }
   }
 }
 
@@ -990,22 +996,22 @@ nsObjectLoadingContent::GetNestedParams(
         continue;
       }
 
       aParams.AppendElement(param);
     }
   }
 }
 
-void
+nsresult
 nsObjectLoadingContent::BuildParametersArray()
 {
   if (mCachedAttributes.Length() || mCachedParameters.Length()) {
     MOZ_ASSERT(false, "Parameters array should be empty.");
-    return;
+    return NS_OK;
   }
 
   nsCOMPtr<nsIContent> content =
     do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
 
   int32_t start = 0, end = content->GetAttrCount(), step = 1;
   // HTML attributes are stored in reverse order.
   if (content->IsHTMLElement() && content->IsInHTMLDocument()) {
@@ -1022,17 +1028,18 @@ nsObjectLoadingContent::BuildParametersA
     atom->ToString(param.mName);
     mCachedAttributes.AppendElement(param);
   }
 
   bool isJava = IsJavaMIME(mContentType);
 
   nsCString codebase;
   if (isJava) {
-      mBaseURI->GetSpec(codebase);
+      nsresult rv = mBaseURI->GetSpec(codebase);
+      NS_ENSURE_SUCCESS(rv, rv);
   }
 
   nsAdoptingCString wmodeOverride = Preferences::GetCString("plugins.force.wmode");
   for (uint32_t i = 0; i < mCachedAttributes.Length(); i++) {
     if (!wmodeOverride.IsEmpty() && mCachedAttributes[i].mName.EqualsIgnoreCase("wmode")) {
       CopyASCIItoUTF16(wmodeOverride, mCachedAttributes[i].mValue);
       wmodeOverride.Truncate();
     } else if (!codebase.IsEmpty() && mCachedAttributes[i].mName.EqualsIgnoreCase("codebase")) {
@@ -1066,16 +1073,18 @@ nsObjectLoadingContent::BuildParametersA
     content->GetAttr(kNameSpaceID_None, nsGkAtoms::data, param.mValue);
     if (!param.mValue.IsEmpty()) {
       param.mName = NS_LITERAL_STRING("SRC");
       mCachedAttributes.AppendElement(param);
     }
   }
 
   GetNestedParams(mCachedParameters, isJava);
+
+  return NS_OK;
 }
 
 void
 nsObjectLoadingContent::NotifyOwnerDocumentActivityChanged()
 {
   // XXX(johns): We cannot touch plugins or run arbitrary script from this call,
   //             as nsDocument is in a non-reentrant state.
 
@@ -1545,17 +1554,21 @@ nsObjectLoadingContent::MaybeRewriteYout
   nsAutoCString path;
   aURI->GetPath(path);
   if (!StringBeginsWith(path, NS_LITERAL_CSTRING("/v/"))) {
     return;
   }
 
   // See if requester is planning on using the JS API.
   nsAutoCString uri;
-  aURI->GetSpec(uri);
+  nsresult rv = aURI->GetSpec(uri);
+  if (NS_FAILED(rv)) {
+    return;
+  }
+
   if (uri.Find("enablejsapi=1", true, 0, -1) != kNotFound) {
     Telemetry::Accumulate(Telemetry::YOUTUBE_NONREWRITABLE_EMBED_SEEN, 1);
     return;
   }
 
   // Some YouTube urls have parameters in path components, e.g.
   // http://youtube.com/embed/7LcUOEP7Brc&start=35. These URLs work with flash,
   // but break iframe/object embedding. If this situation occurs with rewritten
@@ -1590,20 +1603,20 @@ nsObjectLoadingContent::MaybeRewriteYout
     // Replace the first ampersand with a question mark.
     uri.SetCharAt('?', ampIndex);
   }
   // Switch out video access url formats, which should possibly allow HTML5
   // video loading.
   uri.ReplaceSubstring(NS_LITERAL_CSTRING("/v/"),
                        NS_LITERAL_CSTRING("/embed/"));
   nsAutoString utf16URI = NS_ConvertUTF8toUTF16(uri);
-  nsresult rv = nsContentUtils::NewURIWithDocumentCharset(aOutURI,
-                                                          utf16URI,
-                                                          thisContent->OwnerDoc(),
-                                                          aBaseURI);
+  rv = nsContentUtils::NewURIWithDocumentCharset(aOutURI,
+                                                 utf16URI,
+                                                 thisContent->OwnerDoc(),
+                                                 aBaseURI);
   if (NS_FAILED(rv)) {
     return;
   }
   const char16_t* params[] = { utf16OldURI.get(), utf16URI.get() };
   const char* msgName;
   // If there's no query to rewrite, just notify in the developer console
   // that we're changing the embed.
   if (!replaceQuery) {
@@ -2392,17 +2405,18 @@ nsObjectLoadingContent::LoadObject(bool 
 
   ///
   /// Attempt to load new type
   ///
 
 
   // Cache the current attributes and parameters.
   if (mType == eType_Plugin || mType == eType_Null) {
-    BuildParametersArray();
+    rv = BuildParametersArray();
+    NS_ENSURE_SUCCESS(rv, rv);
   }
 
   // We don't set mFinalListener until OnStartRequest has been called, to
   // prevent re-entry ugliness with CloseChannel()
   nsCOMPtr<nsIStreamListener> finalListener;
   // If we decide to synchronously spawn a plugin, we do it after firing
   // notifications to avoid re-entry causing notifications to fire out of order.
   bool doSpawnPlugin = false;
--- a/dom/base/nsObjectLoadingContent.h
+++ b/dom/base/nsObjectLoadingContent.h
@@ -375,17 +375,17 @@ class nsObjectLoadingContent : public ns
      *                        from nested <param> objects.
      * @param aIgnoreCodebase Flag for ignoring the "codebase" param when
      *                        building the array. This is useful when loading
      *                        java.
      */
     void GetNestedParams(nsTArray<mozilla::dom::MozPluginParameter>& aParameters,
                          bool aIgnoreCodebase);
 
-    void BuildParametersArray();
+    MOZ_MUST_USE nsresult BuildParametersArray();
 
     /**
      * Loads fallback content with the specified FallbackType
      *
      * @param aType   FallbackType value for type of fallback we're loading
      * @param aNotify Send notifications and events. If false, caller is
      *                responsible for doing so
      */
--- a/dom/base/test/test_anonymousContent_api.html
+++ b/dom/base/test/test_anonymousContent_api.html
@@ -40,16 +40,17 @@ https://bugzilla.mozilla.org/show_bug.cg
   // Testing the API of the returned object
   let div = document.createElement("div");
   div.textContent = "this is a test element";
   let anonymousContent = chromeDocument.insertAnonymousContent(div);
   ok(anonymousContent, "AnonymousContent object returned");
 
   let members = ["getTextContentForElement", "setTextContentForElement",
                  "getAttributeForElement", "setAttributeForElement",
-                 "removeAttributeForElement", "getCanvasContext"];
+                 "removeAttributeForElement", "getCanvasContext",
+                 "setAnimationForElement"];
   for (let member of members) {
     ok(member in anonymousContent, "AnonymousContent object defines " + member);
   }
   chromeDocument.removeAnonymousContent(anonymousContent);
   </script>
 </body>
 </html>
--- a/dom/base/test/test_anonymousContent_manipulate_content.html
+++ b/dom/base/test/test_anonymousContent_manipulate_content.html
@@ -55,12 +55,20 @@ https://bugzilla.mozilla.org/show_bug.cg
     "Class attribute for the test element is correct after update");
   ok(testElement.getAttribute("class") !== "updated-test-class",
     "Class attribute change on the inserted node does not change the original DOM node");
 
   anonymousContent.removeAttributeForElement("test-element", "class");
   is(anonymousContent.getAttributeForElement("test-element", "class"), null,
     "Class attribute for the test element was removed");
 
+  let anim = anonymousContent.setAnimationForElement("test-element", [
+    { transform: 'translateY(0px)' },
+    { transform: 'translateY(-300px)' }
+  ], 2000);
+  is(anim.playState, "pending", "Animation should be running");
+  anim.cancel();
+  is(anim.playState, "idle", "Animation should have stopped immediately");
+
   chromeDocument.removeAnonymousContent(anonymousContent);
   </script>
 </body>
 </html>
--- a/dom/browser-element/BrowserElementChildPreload.js
+++ b/dom/browser-element/BrowserElementChildPreload.js
@@ -1500,65 +1500,62 @@ BrowserElementChild.prototype = {
         return;
       }
     }
     sendAsyncMsg('got-web-manifest', {
       id: data.json.id,
       successRv: manifest
     });
   }),
+
   _initFinder: function() {
     if (!this._finder) {
-      try {
-        this._findLimit = Services.prefs.getIntPref("accessibility.typeaheadfind.matchesCountLimit");
-      } catch (e) {
-        // Pref not available, assume 0, no match counting.
-        this._findLimit = 0;
-      }
-
       let {Finder} = Components.utils.import("resource://gre/modules/Finder.jsm", {});
       this._finder = new Finder(docShell);
-      this._finder.addResultListener({
-        onMatchesCountResult: (data) => {
-          sendAsyncMsg('findchange', {
-            active: true,
-            searchString: this._finder.searchString,
-            searchLimit: this._findLimit,
-            activeMatchOrdinal: data.current,
-            numberOfMatches: data.total
-          });
-        }
-      });
     }
+    let listener = {
+      onMatchesCountResult: (data) => {
+        sendAsyncMsg("findchange", {
+          active: true,
+          searchString: this._finder.searchString,
+          searchLimit: this._finder.matchesCountLimit,
+          activeMatchOrdinal: data.current,
+          numberOfMatches: data.total
+        });
+        this._finder.removeResultListener(listener);
+      }
+    };
+    this._finder.addResultListener(listener);
   },
 
   _recvFindAll: function(data) {
     this._initFinder();
     let searchString = data.json.searchString;
     this._finder.caseSensitive = data.json.caseSensitive;
     this._finder.fastFind(searchString, false, false);
-    this._finder.requestMatchesCount(searchString, this._findLimit, false);
+    this._finder.requestMatchesCount(searchString, this._finder.matchesCountLimit, false);
   },
 
   _recvFindNext: function(data) {
     if (!this._finder) {
       debug("findNext() called before findAll()");
       return;
     }
+    this._initFinder();
     this._finder.findAgain(data.json.backward, false, false);
-    this._finder.requestMatchesCount(this._finder.searchString, this._findLimit, false);
+    this._finder.requestMatchesCount(this._finder.searchString, this._finder.matchesCountLimit, false);
   },
 
   _recvClearMatch: function(data) {
     if (!this._finder) {
       debug("clearMach() called before findAll()");
       return;
     }
     this._finder.removeSelection();
-    sendAsyncMsg('findchange', {active: false});
+    sendAsyncMsg("findchange", {active: false});
   },
 
   _recvSetInputMethodActive: function(data) {
     let msgData = { id: data.json.id };
     if (!this._isContentWindowCreated) {
       if (data.json.args.isActive) {
         // To activate the input method, we should wait before the content
         // window is ready.
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -3305,17 +3305,17 @@ CanvasRenderingContext2D::ArcTo(double a
   if (mPathBuilder) {
     p0 = mPathBuilder->CurrentPoint();
   } else {
     Matrix invTransform = mTarget->GetTransform();
     if (!invTransform.Invert()) {
       return;
     }
 
-    p0 = invTransform * mDSPathBuilder->CurrentPoint();
+    p0 = invTransform.TransformPoint(mDSPathBuilder->CurrentPoint());
   }
 
   Point p1(aX1, aY1);
   Point p2(aX2, aY2);
 
   // Execute these calculations in double precision to avoid cumulative
   // rounding errors.
   double dir, a2, b2, c2, cosx, sinx, d, anx, any,
@@ -3388,20 +3388,20 @@ CanvasRenderingContext2D::Rect(double aX
 
   if (mPathBuilder) {
     mPathBuilder->MoveTo(Point(aX, aY));
     mPathBuilder->LineTo(Point(aX + aW, aY));
     mPathBuilder->LineTo(Point(aX + aW, aY + aH));
     mPathBuilder->LineTo(Point(aX, aY + aH));
     mPathBuilder->Close();
   } else {
-    mDSPathBuilder->MoveTo(mTarget->GetTransform() * Point(aX, aY));
-    mDSPathBuilder->LineTo(mTarget->GetTransform() * Point(aX + aW, aY));
-    mDSPathBuilder->LineTo(mTarget->GetTransform() * Point(aX + aW, aY + aH));
-    mDSPathBuilder->LineTo(mTarget->GetTransform() * Point(aX, aY + aH));
+    mDSPathBuilder->MoveTo(mTarget->GetTransform().TransformPoint(Point(aX, aY)));
+    mDSPathBuilder->LineTo(mTarget->GetTransform().TransformPoint(Point(aX + aW, aY)));
+    mDSPathBuilder->LineTo(mTarget->GetTransform().TransformPoint(Point(aX + aW, aY + aH)));
+    mDSPathBuilder->LineTo(mTarget->GetTransform().TransformPoint(Point(aX, aY + aH)));
     mDSPathBuilder->Close();
   }
 }
 
 void
 CanvasRenderingContext2D::Ellipse(double aX, double aY, double aRadiusX, double aRadiusY,
                                   double aRotation, double aStartAngle, double aEndAngle,
                                   bool aAnticlockwise, ErrorResult& aError)
--- a/dom/canvas/CanvasRenderingContext2D.h
+++ b/dom/canvas/CanvasRenderingContext2D.h
@@ -300,18 +300,18 @@ public:
 
   void MoveTo(double aX, double aY)
   {
     EnsureWritablePath();
 
     if (mPathBuilder) {
       mPathBuilder->MoveTo(mozilla::gfx::Point(ToFloat(aX), ToFloat(aY)));
     } else {
-      mDSPathBuilder->MoveTo(mTarget->GetTransform() *
-                             mozilla::gfx::Point(ToFloat(aX), ToFloat(aY)));
+      mDSPathBuilder->MoveTo(mTarget->GetTransform().TransformPoint(
+                             mozilla::gfx::Point(ToFloat(aX), ToFloat(aY))));
     }
   }
 
   void LineTo(double aX, double aY)
   {
     EnsureWritablePath();
 
     LineTo(mozilla::gfx::Point(ToFloat(aX), ToFloat(aY)));
@@ -321,20 +321,20 @@ public:
   {
     EnsureWritablePath();
 
     if (mPathBuilder) {
       mPathBuilder->QuadraticBezierTo(mozilla::gfx::Point(ToFloat(aCpx), ToFloat(aCpy)),
                                       mozilla::gfx::Point(ToFloat(aX), ToFloat(aY)));
     } else {
       mozilla::gfx::Matrix transform = mTarget->GetTransform();
-      mDSPathBuilder->QuadraticBezierTo(transform *
-                                        mozilla::gfx::Point(ToFloat(aCpx), ToFloat(aCpy)),
-                                        transform *
-                                        mozilla::gfx::Point(ToFloat(aX), ToFloat(aY)));
+      mDSPathBuilder->QuadraticBezierTo(transform.TransformPoint(
+                                          mozilla::gfx::Point(ToFloat(aCpx), ToFloat(aCpy))),
+                                        transform.TransformPoint(
+                                          mozilla::gfx::Point(ToFloat(aX), ToFloat(aY))));
     }
   }
 
   void BezierCurveTo(double aCp1x, double aCp1y, double aCp2x, double aCp2y, double aX, double aY)
   {
     EnsureWritablePath();
 
     BezierTo(mozilla::gfx::Point(ToFloat(aCp1x), ToFloat(aCp1y)),
@@ -512,31 +512,31 @@ public:
     return mCanvasElement;
   }
 
   void LineTo(const mozilla::gfx::Point& aPoint)
   {
     if (mPathBuilder) {
       mPathBuilder->LineTo(aPoint);
     } else {
-      mDSPathBuilder->LineTo(mTarget->GetTransform() * aPoint);
+      mDSPathBuilder->LineTo(mTarget->GetTransform().TransformPoint(aPoint));
     }
   }
 
   void BezierTo(const mozilla::gfx::Point& aCP1,
                 const mozilla::gfx::Point& aCP2,
                 const mozilla::gfx::Point& aCP3)
   {
     if (mPathBuilder) {
       mPathBuilder->BezierTo(aCP1, aCP2, aCP3);
     } else {
       mozilla::gfx::Matrix transform = mTarget->GetTransform();
-      mDSPathBuilder->BezierTo(transform * aCP1,
-                                transform * aCP2,
-                                transform * aCP3);
+      mDSPathBuilder->BezierTo(transform.TransformPoint(aCP1),
+                               transform.TransformPoint(aCP2),
+                               transform.TransformPoint(aCP3));
     }
   }
 
   friend class CanvasRenderingContext2DUserData;
 
   virtual UniquePtr<uint8_t[]> GetImageBuffer(int32_t* aFormat) override;
 
 
--- a/dom/canvas/WebGLExtensionDrawBuffers.cpp
+++ b/dom/canvas/WebGLExtensionDrawBuffers.cpp
@@ -43,18 +43,21 @@ WebGLExtensionDrawBuffers::DrawBuffersWE
     mContext->DrawBuffers(buffers);
 }
 
 bool
 WebGLExtensionDrawBuffers::IsSupported(const WebGLContext* webgl)
 {
     gl::GLContext* gl = webgl->GL();
 
-    if (!gl->IsSupported(gl::GLFeature::draw_buffers))
+    if (!gl->IsExtensionSupported(gl::GLContext::ARB_draw_buffers) &&
+        !gl->IsExtensionSupported(gl::GLContext::EXT_draw_buffers))
+    {
         return false;
+    }
 
     // WEBGL_draw_buffers requires at least 4 color attachments.
     if (webgl->mGLMaxDrawBuffers < webgl->kMinMaxDrawBuffers ||
         webgl->mGLMaxColorAttachments < webgl->kMinMaxColorAttachments)
     {
         return false;
     }
 
--- a/dom/flyweb/FlyWebPublishedServer.cpp
+++ b/dom/flyweb/FlyWebPublishedServer.cpp
@@ -166,16 +166,26 @@ NS_IMPL_ISUPPORTS_INHERITED0(FlyWebPubli
 
 FlyWebPublishedServerImpl::FlyWebPublishedServerImpl(nsPIDOMWindowInner* aOwner,
                                                      const nsAString& aName,
                                                      const FlyWebPublishOptions& aOptions)
   : FlyWebPublishedServer(aOwner, aName, aOptions)
   , mHttpServer(new HttpServer())
 {
   LOG_I("FlyWebPublishedServerImpl::FlyWebPublishedServerImpl(%p)", this);
+}
+
+void
+FlyWebPublishedServerImpl::PermissionGranted(bool aGranted)
+{
+  LOG_I("FlyWebPublishedServerImpl::PermissionGranted(%b)", aGranted);
+  if (!aGranted) {
+    PublishedServerStarted(NS_ERROR_FAILURE);
+    return;
+  }
 
   mHttpServer->Init(-1, Preferences::GetBool("flyweb.use-tls", false), this);
 }
 
 void
 FlyWebPublishedServerImpl::Close()
 {
   FlyWebPublishedServer::Close();
@@ -247,72 +257,84 @@ FlyWebPublishedServerImpl::OnWebSocketAc
 }
 
 /******** FlyWebPublishedServerChild ********/
 
 FlyWebPublishedServerChild::FlyWebPublishedServerChild(nsPIDOMWindowInner* aOwner,
                                                        const nsAString& aName,
                                                        const FlyWebPublishOptions& aOptions)
   : FlyWebPublishedServer(aOwner, aName, aOptions)
-  , mActorDestroyed(false)
+  , mActorExists(false)
 {
   LOG_I("FlyWebPublishedServerChild::FlyWebPublishedServerChild(%p)", this);
 
-  ContentChild::GetSingleton()->
-    SendPFlyWebPublishedServerConstructor(this,
-                                          PromiseFlatString(aName),
-                                          aOptions);
-
   // The matching release happens when the actor is destroyed, in
   // ContentChild::DeallocPFlyWebPublishedServerChild
   NS_ADDREF_THIS();
 }
 
+void
+FlyWebPublishedServerChild::PermissionGranted(bool aGranted)
+{
+  if (!aGranted) {
+    PublishedServerStarted(NS_ERROR_FAILURE);
+    return;
+  }
+
+  mActorExists = true;
+  FlyWebPublishOptions options;
+  options.mUiUrl = mUiUrl;
+
+  // Proceed with initialization.
+  ContentChild::GetSingleton()->
+    SendPFlyWebPublishedServerConstructor(this, mName, options);
+}
+
 bool
 FlyWebPublishedServerChild::RecvServerReady(const nsresult& aStatus)
 {
   LOG_I("FlyWebPublishedServerChild::RecvServerReady(%p)", this);
-  MOZ_ASSERT(!mActorDestroyed);
+  MOZ_ASSERT(mActorExists);
 
   PublishedServerStarted(aStatus);
   return true;
 }
 
 bool
 FlyWebPublishedServerChild::RecvServerClose()
 {
   LOG_I("FlyWebPublishedServerChild::RecvServerClose(%p)", this);
-  MOZ_ASSERT(!mActorDestroyed);
+  MOZ_ASSERT(mActorExists);
 
   Close();
 
   return true;
 }
 
 bool
 FlyWebPublishedServerChild::RecvFetchRequest(const IPCInternalRequest& aRequest,
                                              const uint64_t& aRequestId)
 {
   LOG_I("FlyWebPublishedServerChild::RecvFetchRequest(%p)", this);
-  MOZ_ASSERT(!mActorDestroyed);
+  MOZ_ASSERT(mActorExists);
 
   RefPtr<InternalRequest> request = new InternalRequest(aRequest);
   mPendingRequests.Put(request, aRequestId);
   FireFetchEvent(request);
 
   return true;
 }
 
 bool
 FlyWebPublishedServerChild::RecvWebSocketRequest(const IPCInternalRequest& aRequest,
                                                  const uint64_t& aRequestId,
                                                  PTransportProviderChild* aProvider)
 {
   LOG_I("FlyWebPublishedServerChild::RecvWebSocketRequest(%p)", this);
-  MOZ_ASSERT(!mActorDestroyed);
+  MOZ_ASSERT(mActorExists);
 
   RefPtr<InternalRequest> request = new InternalRequest(aRequest);
   mPendingRequests.Put(request, aRequestId);
 
   // Not addreffing here. The addref was already done when the
   // PTransportProvider child constructor original ran.
   mPendingTransportProviders.Put(aRequestId,
     dont_AddRef(static_cast<TransportProviderChild*>(aProvider)));
@@ -322,26 +344,26 @@ FlyWebPublishedServerChild::RecvWebSocke
   return true;
 }
 
 void
 FlyWebPublishedServerChild::ActorDestroy(ActorDestroyReason aWhy)
 {
   LOG_I("FlyWebPublishedServerChild::ActorDestroy(%p)", this);
 
-  mActorDestroyed = true;
+  mActorExists = false;
 }
 
 void
 FlyWebPublishedServerChild::OnFetchResponse(InternalRequest* aRequest,
                                             InternalResponse* aResponse)
 {
   LOG_I("FlyWebPublishedServerChild::OnFetchResponse(%p)", this);
 
-  if (mActorDestroyed) {
+  if (!mActorExists) {
     LOG_I("FlyWebPublishedServerChild::OnFetchResponse(%p) - No actor!", this);
     return;
   }
 
   uint64_t id = mPendingRequests.Get(aRequest);
   MOZ_ASSERT(id);
   mPendingRequests.Remove(aRequest);
 
@@ -356,17 +378,17 @@ FlyWebPublishedServerChild::OnFetchRespo
 
 already_AddRefed<nsITransportProvider>
 FlyWebPublishedServerChild::OnWebSocketAcceptInternal(InternalRequest* aRequest,
                                                       const Optional<nsAString>& aProtocol,
                                                       ErrorResult& aRv)
 {
   LOG_I("FlyWebPublishedServerChild::OnWebSocketAcceptInternal(%p)", this);
 
-  if (mActorDestroyed) {
+  if (!mActorExists) {
     LOG_I("FlyWebPublishedServerChild::OnWebSocketAcceptInternal(%p) - No actor!", this);
     return nullptr;
   }
 
   uint64_t id = mPendingRequests.Get(aRequest);
   MOZ_ASSERT(id);
   mPendingRequests.Remove(aRequest);
 
@@ -395,17 +417,17 @@ FlyWebPublishedServerChild::OnWebSocketA
 }
 
 void
 FlyWebPublishedServerChild::OnWebSocketResponse(InternalRequest* aRequest,
                                                 InternalResponse* aResponse)
 {
   LOG_I("FlyWebPublishedServerChild::OnFetchResponse(%p)", this);
 
-  if (mActorDestroyed) {
+  if (!mActorExists) {
     LOG_I("FlyWebPublishedServerChild::OnFetchResponse(%p) - No actor!", this);
     return;
   }
 
   uint64_t id = mPendingRequests.Get(aRequest);
   MOZ_ASSERT(id);
   mPendingRequests.Remove(aRequest);
 
@@ -423,17 +445,17 @@ FlyWebPublishedServerChild::OnWebSocketR
 
 void
 FlyWebPublishedServerChild::Close()
 {
   LOG_I("FlyWebPublishedServerChild::Close(%p)", this);
 
   FlyWebPublishedServer::Close();
 
-  if (!mActorDestroyed) {
+  if (mActorExists) {
     LOG_I("FlyWebPublishedServerChild::Close - sending __delete__ (%p)", this);
 
     Send__delete__(this);
   }
 }
 
 /******** FlyWebPublishedServerParent ********/
 
--- a/dom/flyweb/FlyWebPublishedServer.h
+++ b/dom/flyweb/FlyWebPublishedServer.h
@@ -52,16 +52,18 @@ public:
     return mName;
   }
 
   void GetUiUrl(nsAString& aUiUrl)
   {
     aUiUrl = mUiUrl;
   }
 
+  virtual void PermissionGranted(bool aGranted) = 0;
+
   virtual void OnFetchResponse(InternalRequest* aRequest,
                                InternalResponse* aResponse) = 0;
   already_AddRefed<WebSocket>
     OnWebSocketAccept(InternalRequest* aConnectRequest,
                       const Optional<nsAString>& aProtocol,
                       ErrorResult& aRv);
   virtual void OnWebSocketResponse(InternalRequest* aConnectRequest,
                                    InternalResponse* aResponse) = 0;
--- a/dom/flyweb/FlyWebPublishedServerIPC.h
+++ b/dom/flyweb/FlyWebPublishedServerIPC.h
@@ -45,16 +45,17 @@ public:
   void GetCertKey(nsACString& aKey) {
     if (mHttpServer) {
       mHttpServer->GetCertKey(aKey);
     } else {
       aKey.Truncate();
     }
   }
 
+  virtual void PermissionGranted(bool aGranted) override;
   virtual void OnFetchResponse(InternalRequest* aRequest,
                                InternalResponse* aResponse) override;
   virtual void OnWebSocketResponse(InternalRequest* aConnectRequest,
                                    InternalResponse* aResponse) override;
   virtual already_AddRefed<nsITransportProvider>
     OnWebSocketAcceptInternal(InternalRequest* aConnectRequest,
                               const Optional<nsAString>& aProtocol,
                               ErrorResult& aRv) override;
@@ -93,16 +94,17 @@ private:
 class FlyWebPublishedServerChild final : public FlyWebPublishedServer
                                        , public PFlyWebPublishedServerChild
 {
 public:
   FlyWebPublishedServerChild(nsPIDOMWindowInner* aOwner,
                              const nsAString& aName,
                              const FlyWebPublishOptions& aOptions);
 
+  virtual void PermissionGranted(bool aGranted) override;
   virtual bool RecvServerReady(const nsresult& aStatus) override;
   virtual bool RecvServerClose() override;
   virtual bool RecvFetchRequest(const IPCInternalRequest& aRequest,
                                 const uint64_t& aRequestId) override;
   virtual bool RecvWebSocketRequest(const IPCInternalRequest& aRequest,
                                     const uint64_t& aRequestId,
                                     PTransportProviderChild* aProvider) override;
 
@@ -120,17 +122,17 @@ public:
   virtual void ActorDestroy(ActorDestroyReason aWhy) override;
 
 private:
   ~FlyWebPublishedServerChild() {}
 
   nsDataHashtable<nsRefPtrHashKey<InternalRequest>, uint64_t> mPendingRequests;
   nsRefPtrHashtable<nsUint64HashKey, TransportProviderChild>
     mPendingTransportProviders;
-  bool mActorDestroyed;
+  bool mActorExists;
 };
 
 class FlyWebPublishedServerParent final : public PFlyWebPublishedServerParent
                                         , public nsIDOMEventListener
 {
 public:
   FlyWebPublishedServerParent(const nsAString& aName,
                               const FlyWebPublishOptions& aOptions);
--- a/dom/flyweb/FlyWebService.cpp
+++ b/dom/flyweb/FlyWebService.cpp
@@ -4,46 +4,160 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/FlyWebService.h"
 #include "mozilla/StaticPtr.h"
 #include "mozilla/ScopeExit.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/dom/FlyWebPublishedServerIPC.h"
+#include "mozilla/AddonPathService.h"
 #include "nsISocketTransportService.h"
 #include "mdns/libmdns/nsDNSServiceInfo.h"
 #include "nsIUUIDGenerator.h"
 #include "nsStandardURL.h"
 #include "mozilla/Services.h"
 #include "nsISupportsPrimitives.h"
 #include "mozilla/dom/FlyWebDiscoveryManagerBinding.h"
 #include "prnetdb.h"
 #include "DNS.h"
+#include "nsContentPermissionHelper.h"
 #include "nsSocketTransportService2.h"
 #include "nsSocketTransport2.h"
 #include "nsHashPropertyBag.h"
 #include "nsNetUtil.h"
 #include "nsISimpleEnumerator.h"
 #include "nsIProperty.h"
 #include "nsICertOverrideService.h"
 
 namespace mozilla {
 namespace dom {
 
 struct FlyWebPublishOptions;
 
 static LazyLogModule gFlyWebServiceLog("FlyWebService");
 #undef LOG_I
 #define LOG_I(...) MOZ_LOG(mozilla::dom::gFlyWebServiceLog, mozilla::LogLevel::Debug, (__VA_ARGS__))
+
 #undef LOG_E
 #define LOG_E(...) MOZ_LOG(mozilla::dom::gFlyWebServiceLog, mozilla::LogLevel::Error, (__VA_ARGS__))
+
 #undef LOG_TEST_I
 #define LOG_TEST_I(...) MOZ_LOG_TEST(mozilla::dom::gFlyWebServiceLog, mozilla::LogLevel::Debug)
 
+class FlyWebPublishServerPermissionCheck final
+  : public nsIContentPermissionRequest
+  , public nsIRunnable
+{
+public:
+  NS_DECL_ISUPPORTS
+
+  FlyWebPublishServerPermissionCheck(const nsCString& aServiceName, uint64_t aWindowID,
+                                     FlyWebPublishedServer* aServer)
+    : mServiceName(aServiceName)
+    , mWindowID(aWindowID)
+    , mServer(aServer)
+  {}
+
+  uint64_t WindowID() const
+  {
+    return mWindowID;
+  }
+
+  NS_IMETHOD Run() override
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+
+    nsGlobalWindow* globalWindow = nsGlobalWindow::GetInnerWindowWithId(mWindowID);
+    if (!globalWindow) {
+      return Cancel();
+    }
+    mWindow = globalWindow->AsInner();
+    if (NS_WARN_IF(!mWindow)) {
+      return Cancel();
+    }
+
+    nsCOMPtr<nsIDocument> doc = mWindow->GetDoc();
+    if (NS_WARN_IF(!doc)) {
+      return Cancel();
+    }
+
+    mPrincipal = doc->NodePrincipal();
+    MOZ_ASSERT(mPrincipal);
+
+    mRequester = new nsContentPermissionRequester(mWindow);
+    return nsContentPermissionUtils::AskPermission(this, mWindow);
+  }
+
+  NS_IMETHOD Cancel() override
+  {
+    Resolve(false);
+    return NS_OK;
+  }
+
+  NS_IMETHOD Allow(JS::HandleValue aChoices) override
+  {
+    MOZ_ASSERT(aChoices.isUndefined());
+    Resolve(true);
+    return NS_OK;
+  }
+
+  NS_IMETHOD GetTypes(nsIArray** aTypes) override
+  {
+    nsTArray<nsString> emptyOptions;
+    return nsContentPermissionUtils::CreatePermissionArray(NS_LITERAL_CSTRING("flyweb-publish-server"),
+                                                           NS_LITERAL_CSTRING("unused"), emptyOptions, aTypes);
+  }
+
+  NS_IMETHOD GetRequester(nsIContentPermissionRequester** aRequester) override
+  {
+    NS_ENSURE_ARG_POINTER(aRequester);
+    nsCOMPtr<nsIContentPermissionRequester> requester = mRequester;
+    requester.forget(aRequester);
+    return NS_OK;
+  }
+
+  NS_IMETHOD GetPrincipal(nsIPrincipal** aRequestingPrincipal) override
+  {
+    NS_IF_ADDREF(*aRequestingPrincipal = mPrincipal);
+    return NS_OK;
+  }
+
+  NS_IMETHOD GetWindow(mozIDOMWindow** aRequestingWindow) override
+  {
+    NS_IF_ADDREF(*aRequestingWindow = mWindow);
+    return NS_OK;
+  }
+
+  NS_IMETHOD GetElement(nsIDOMElement** aRequestingElement) override
+  {
+    *aRequestingElement = nullptr;
+    return NS_OK;
+  }
+
+private:
+  void Resolve(bool aResolve)
+  {
+    mServer->PermissionGranted(aResolve);
+  }
+
+  virtual ~FlyWebPublishServerPermissionCheck() = default;
+
+  nsCString mServiceName;
+  uint64_t mWindowID;
+  RefPtr<FlyWebPublishedServer> mServer;
+  nsCOMPtr<nsPIDOMWindowInner> mWindow;
+  nsCOMPtr<nsIPrincipal> mPrincipal;
+  nsCOMPtr<nsIContentPermissionRequester> mRequester;
+};
+
+NS_IMPL_ISUPPORTS(FlyWebPublishServerPermissionCheck,
+                  nsIContentPermissionRequest,
+                  nsIRunnable)
+
 class FlyWebMDNSService final
   : public nsIDNSServiceDiscoveryListener
   , public nsIDNSServiceResolveListener
   , public nsIDNSRegistrationListener
   , public nsITimerCallback
 {
   friend class FlyWebService;
 
@@ -836,39 +950,88 @@ FlyWebService::Init()
       mMDNSFlywebService = nullptr;
       rv.SuppressException();
     }
   }
 
   return ErrorResult(NS_OK);
 }
 
+static already_AddRefed<FlyWebPublishPromise>
+MakeRejectionPromise(const char* name)
+{
+    MozPromiseHolder<FlyWebPublishPromise> holder;
+    RefPtr<FlyWebPublishPromise> promise = holder.Ensure(name);
+    holder.Reject(NS_ERROR_FAILURE, name);
+    return promise.forget();
+}
+
 already_AddRefed<FlyWebPublishPromise>
 FlyWebService::PublishServer(const nsAString& aName,
                              const FlyWebPublishOptions& aOptions,
                              nsPIDOMWindowInner* aWindow)
 {
   // Scan uiUrl for illegal characters
 
   RefPtr<FlyWebPublishedServer> existingServer =
     FlyWebService::GetOrCreate()->FindPublishedServerByName(aName);
   if (existingServer) {
     LOG_I("PublishServer: Trying to publish server with already-existing name %s.",
           NS_ConvertUTF16toUTF8(aName).get());
-    MozPromiseHolder<FlyWebPublishPromise> holder;
-    RefPtr<FlyWebPublishPromise> promise = holder.Ensure(__func__);
-    holder.Reject(NS_ERROR_FAILURE, __func__);
-    return promise.forget();
+    return MakeRejectionPromise(__func__);
   }
 
   RefPtr<FlyWebPublishedServer> server;
   if (XRE_GetProcessType() == GeckoProcessType_Content) {
     server = new FlyWebPublishedServerChild(aWindow, aName, aOptions);
   } else {
     server = new FlyWebPublishedServerImpl(aWindow, aName, aOptions);
+
+    // Before proceeding, ensure that the FlyWeb system addon exists.
+    nsresult rv;
+    nsCOMPtr<nsIURI> uri;
+    rv = NS_NewURI(getter_AddRefs(uri), NS_LITERAL_CSTRING("chrome://flyweb/skin/icon-64.png"));
+    if (NS_FAILED(rv)) {
+      return MakeRejectionPromise(__func__);
+    }
+
+    JSAddonId *addonId = MapURIToAddonID(uri);
+    if (!addonId) {
+      LOG_E("PublishServer: Failed to find FlyWeb system addon.");
+      return MakeRejectionPromise(__func__);
+    }
+
+    JSFlatString* flat = JS_ASSERT_STRING_IS_FLAT(JS::StringOfAddonId(addonId));
+    nsAutoString addonIdString;
+    AssignJSFlatString(addonIdString, flat);
+    if (!addonIdString.EqualsLiteral("flyweb@mozilla.org")) {
+      nsCString addonIdCString = NS_ConvertUTF16toUTF8(addonIdString);
+      LOG_E("PublishServer: FlyWeb resource found on wrong system addon: %s.", addonIdCString.get());
+      return MakeRejectionPromise(__func__);
+    }
+  }
+
+  if (aWindow) {
+    nsresult rv;
+
+    MOZ_ASSERT(NS_IsMainThread());
+    rv = NS_DispatchToCurrentThread(
+      MakeAndAddRef<FlyWebPublishServerPermissionCheck>(
+        NS_ConvertUTF16toUTF8(aName), aWindow->WindowID(), server));
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      LOG_E("PublishServer: Failed to dispatch permission check runnable for %s",
+            NS_ConvertUTF16toUTF8(aName).get());
+      return MakeRejectionPromise(__func__);
+    }
+  } else {
+    // If aWindow is null, we're definitely in the e10s parent process.
+    // In this case, we know that permission has already been granted
+    // by the user because of content-process prompt.
+    MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
+    server->PermissionGranted(true);
   }
 
   mServers.AppendElement(server);
 
   return server->GetPublishPromise();
 }
 
 already_AddRefed<FlyWebPublishedServer>
--- a/dom/grid/test/chrome/test_grid_track_state.html
+++ b/dom/grid/test/chrome/test_grid_track_state.html
@@ -7,67 +7,143 @@
 <style>
 body {
 	margin: 40px;
 }
 .wrapper {
 	display: grid;
 	width: 600px;
 	grid-gap: 0px;
-	grid-template-columns: 50px repeat(auto-fit, 100px);
 	background-color: #f00;
 }
-.wrapper2 {
-	display: grid;
-	width: 600px;
-	grid-gap: 0px;
+.grid1 {
+	grid-template-columns: 50px 0 repeat(auto-fit, 100px);
+}
+.grid2 {
+	grid-template-columns: 50px 0 [real-before] repeat(auto-fit, [before] 100px [after]) [real-after];
+}
+.grid3 {
+	grid-template-columns: repeat(3, 66px) [real-before] repeat(auto-fit, [before] 100px [after]) [real-after];
+}
+.grid4 {
 	grid-template-columns: repeat(2, 100px) repeat(auto-fill, 50px);
-	background-color: #f00;
+}
+.grid5 {
+	grid-template-columns: [real-before] repeat(auto-fit, [before] 100px [after]) [real-after];
 }
 .box {
 	background-color: #444;
 	color: #fff;
 }
 .a {
-	grid-column: 3;
+	grid-column: auto;
+}
+.b {
+	grid-column: 4;
 }
+.c {
+	grid-column: 6;
+}
+.d {
+	grid-column: 7;
+}
+
 </style>
 
 <script>
 'use strict';
 
 SimpleTest.waitForExplicitFinish();
 
 function runTests() {
-	var wrapper = document.getElementById("wrapper");
-	var grid = wrapper.getGridFragments()[0];
+	let wrapper = document.getElementById("wrapper1");
+	let grid = wrapper.getGridFragments()[0];
 	
 	// test auto-fit count after removal
-	is(grid.cols.tracks.length, 2, "Grid column track array compensates for removed auto-fit columns.");
+	is(grid.cols.tracks.length, 3, "Grid column track array compensates for removed auto-fit columns.");
+	
+	// test resolved value of grid-template-columns
+	let templateColumnsText = getComputedStyle(wrapper).gridTemplateColumns;
+	is(templateColumnsText, "50px 0px 0px 100px 0px 0px 0px",
+		"Resolved value of grid-template-columns reports removed auto-fits as '0px'.");
+	
+	is(grid.cols.tracks[0].breadth, 50, "Column 1 is breadth 50.");
+	is(grid.cols.tracks[1].breadth, 0, "Column 2 is breadth 0.");
+	is(grid.cols.tracks[2].breadth, 100, "Column 3 is breadth 100.");
+
+	
+	wrapper = document.getElementById("wrapper2");
+	grid = wrapper.getGridFragments()[0];
 	
-	var wrapper2 = document.getElementById("wrapper2");
-	var grid2 = wrapper2.getGridFragments()[0];
+	// test resolved value of grid-template-columns
+	templateColumnsText = getComputedStyle(wrapper).gridTemplateColumns;
+	is(templateColumnsText, "50px 0px [real-before before] 0px [after before] 100px [after before] 0px [after before] 100px [after before] 0px [after real-after]",
+		"Resolved value of grid-template-columns reports lines for removed tracks.");
+	
+	
+	wrapper = document.getElementById("wrapper3");
+	grid = wrapper.getGridFragments()[0];
+	
+	// test resolved value of grid-template-columns
+	templateColumnsText = getComputedStyle(wrapper).gridTemplateColumns;
+	is(templateColumnsText, "66px 66px 66px [real-before before] 100px [after before] 0px [after before] 100px [after before] 100px [after real-after]",
+		"Resolved value of grid-template-columns reports lines for removed tracks.");
+	
+	
+	wrapper = document.getElementById("wrapper4");
+	grid = wrapper.getGridFragments()[0];
 	
 	// test auto-fill count of tracks
-	is(grid2.cols.tracks.length, 10, "Grid column track array respects auto-fill columns.");
+	is(grid.cols.tracks.length, 10, "Grid column track array respects auto-fill columns.");
 	
-	if (grid2.cols.tracks.length == 10) {
+	if (grid.cols.tracks.length == 10) {
 		// test for static and repeat
-		is(grid2.cols.tracks[1].state, "static", "Grid column track 2 is marked as static.");
-		is(grid2.cols.tracks[2].state, "repeat", "Grid column track 3 is marked as repeat.");
+		is(grid.cols.tracks[1].state, "static", "Grid column track 2 is marked as static.");
+		is(grid.cols.tracks[2].state, "repeat", "Grid column track 3 is marked as repeat.");
 	}
 	
+	
+	wrapper = document.getElementById("wrapper5");
+	grid = wrapper.getGridFragments()[0];
+	
+	// test resolved value of grid-template-columns
+	templateColumnsText = getComputedStyle(wrapper).gridTemplateColumns;
+	is(templateColumnsText, "[real-before before] 0px [after before] 0px [after before] 0px [after before] 0px [after before] 0px [after before] 0px [after real-after]",
+		"Resolved value of grid-template-columns no longer lists 'none' when all auto-fit tracks are empty.");
+	
 	SimpleTest.finish();
 }
 </script>
 </head>
 <body onLoad="runTests();">
 
-	<div id="wrapper" class="wrapper">
+	<div id="wrapper1" class="wrapper grid1">
+		<div id="boxB" class="box b">B</div>
+	</div>
+		
+	<br/>
+	
+	<div id="wrapper2" class="wrapper grid2">
+		<div id="boxB" class="box b">B</div>
+		<div id="boxC" class="box c">C</div>
+	</div>
+		
+	<br/>
+	
+	<div id="wrapper3" class="wrapper grid3">
+		<div id="boxB" class="box b">B</div>
+		<div id="boxC" class="box c">C</div>
+		<div id="boxD" class="box d">D</div>
+	</div>
+		
+	<br/>
+	
+	<div id="wrapper4" class="wrapper grid4">
 		<div id="boxA" class="box a">A</div>
 	</div>
 	
-	<div id="wrapper2" class="wrapper2">
-		<div id="boxB" class="box b">B</div>
+	<br/>
+	
+	<div id="wrapper5" class="wrapper grid5">
 	</div>
 	
 </body>
 </html>
--- a/dom/html/HTMLInputElement.cpp
+++ b/dom/html/HTMLInputElement.cpp
@@ -212,16 +212,17 @@ const Decimal HTMLInputElement::kStepSca
 const Decimal HTMLInputElement::kStepScaleFactorMonth = Decimal(1);
 const Decimal HTMLInputElement::kDefaultStepBase = Decimal(0);
 const Decimal HTMLInputElement::kDefaultStep = Decimal(1);
 const Decimal HTMLInputElement::kDefaultStepTime = Decimal(60);
 const Decimal HTMLInputElement::kStepAny = Decimal(0);
 
 const double HTMLInputElement::kMaximumYear = 275760;
 const double HTMLInputElement::kMinimumYear = 1;
+const double HTMLInputElement::kMaximumWeekInYear = 53;
 
 #define NS_INPUT_ELEMENT_STATE_IID                 \
 { /* dc3b3d14-23e2-4479-b513-7b369343e3a0 */       \
   0xdc3b3d14,                                      \
   0x23e2,                                          \
   0x4479,                                          \
   {0xb5, 0x13, 0x7b, 0x36, 0x93, 0x43, 0xe3, 0xa0} \
 }
@@ -5042,16 +5043,23 @@ HTMLInputElement::SanitizeValue(nsAStrin
       break;
     case NS_FORM_INPUT_MONTH:
       {
         if (!aValue.IsEmpty() && !IsValidMonth(aValue)) {
           aValue.Truncate();
         }
       }
       break;
+    case NS_FORM_INPUT_WEEK:
+      {
+        if (!aValue.IsEmpty() && !IsValidWeek(aValue)) {
+          aValue.Truncate();
+        }
+      }
+      break;
     case NS_FORM_INPUT_COLOR:
       {
         if (IsValidSimpleColor(aValue)) {
           ToLowerCase(aValue);
         } else {
           // Set default (black) color, if aValue wasn't parsed correctly.
           aValue.AssignLiteral("#000000");
         }
@@ -5072,16 +5080,53 @@ bool HTMLInputElement::IsValidSimpleColo
         !(aValue[i] >= 'A' && aValue[i] <= 'F')) {
       return false;
     }
   }
   return true;
 }
 
 bool
+HTMLInputElement::IsLeapYear(uint32_t aYear) const
+{
+  if ((aYear % 4 == 0 && aYear % 100 != 0) || ( aYear % 400 == 0)) {
+    return true;
+  }
+  return false;
+}
+
+uint32_t
+HTMLInputElement::DayOfWeek(uint32_t aYear, uint32_t aMonth, uint32_t aDay) const
+{
+  // Tomohiko Sakamoto algorithm.
+  int monthTable[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4};
+  aYear -= aMonth < 3;
+
+  return (aYear + aYear / 4 - aYear / 100 + aYear / 400 +
+          monthTable[aMonth - 1] + aDay) % 7;
+}
+
+uint32_t
+HTMLInputElement::MaximumWeekInYear(uint32_t aYear) const
+{
+  int day = DayOfWeek(aYear, 1, 1); // January 1.
+  // A year starting on Thursday or a leap year starting on Wednesday has 53
+  // weeks. All other years have 52 weeks.
+  return day == 4 || (day == 3 && IsLeapYear(aYear)) ? kMaximumWeekInYear
+                                                     : kMaximumWeekInYear - 1;
+}
+
+bool
+HTMLInputElement::IsValidWeek(const nsAString& aValue) const
+{
+  uint32_t year, week;
+  return ParseWeek(aValue, &year, &week);
+}
+
+bool
 HTMLInputElement::IsValidMonth(const nsAString& aValue) const
 {
   uint32_t year, month;
   return ParseMonth(aValue, &year, &month);
 }
 
 bool
 HTMLInputElement::IsValidDate(const nsAString& aValue) const
@@ -5118,16 +5163,44 @@ bool HTMLInputElement::ParseMonth(const 
   if (!ParseYear(yearStr, aYear)) {
     return false;
   }
 
   return DigitSubStringToNumber(aValue, endOfYearOffset + 1, 2, aMonth) &&
          *aMonth > 0 && *aMonth <= 12;
 }
 
+bool HTMLInputElement::ParseWeek(const nsAString& aValue,
+                                 uint32_t* aYear,
+                                 uint32_t* aWeek) const
+{
+  // Parse the year, month values out a string formatted as 'yyyy-Www'.
+  if (aValue.Length() < 8) {
+    return false;
+  }
+
+  uint32_t endOfYearOffset = aValue.Length() - 4;
+  if (aValue[endOfYearOffset] != '-') {
+    return false;
+  }
+
+  if (aValue[endOfYearOffset + 1] != 'W') {
+    return false;
+  }
+
+  const nsAString& yearStr = Substring(aValue, 0, endOfYearOffset);
+  if (!ParseYear(yearStr, aYear)) {
+    return false;
+  }
+
+  return DigitSubStringToNumber(aValue, endOfYearOffset + 2, 2, aWeek) &&
+         *aWeek > 0 && *aWeek <= MaximumWeekInYear(*aYear);
+
+}
+
 bool HTMLInputElement::ParseDate(const nsAString& aValue,
                                  uint32_t* aYear,
                                  uint32_t* aMonth,
                                  uint32_t* aDay) const
 {
 /*
  * Parse the year, month, day values out a date string formatted as 'yyyy-mm-dd'.
  * -The year must be 4 or more digits long, and year > 0
--- a/dom/html/HTMLInputElement.h
+++ b/dom/html/HTMLInputElement.h
@@ -1160,17 +1160,25 @@ protected:
    * Parse a color string of the form #XXXXXX where X should be hexa characters
    * @param the string to be parsed.
    * @return whether the string is a valid simple color.
    * Note : this function does not consider the empty string as valid.
    */
   bool IsValidSimpleColor(const nsAString& aValue) const;
 
   /**
-   * Parse a date string of the form yyyy-mm
+   * Parse a week string of the form yyyy-Www
+   * @param the string to be parsed.
+   * @return whether the string is a valid week.
+   * Note : this function does not consider the empty string as valid.
+   */
+  bool IsValidWeek(const nsAString& aValue) const;
+
+  /**
+   * Parse a month string of the form yyyy-mm
    * @param the string to be parsed.
    * @return whether the string is a valid month.
    * Note : this function does not consider the empty string as valid.
    */
   bool IsValidMonth(const nsAString& aValue) const;
 
   /**
    * Parse a date string of the form yyyy-mm-dd
@@ -1197,16 +1205,26 @@ protected:
    * @return the year and month in aYear and aMonth.
    * @return whether the parsing was successful.
    */
   bool ParseMonth(const nsAString& aValue,
                   uint32_t* aYear,
                   uint32_t* aMonth) const;
 
   /**
+   * Parse a week string of the form yyyy-Www
+   *
+   * @param the string to be parsed.
+   * @return the year and week in aYear and aWeek.
+   * @return whether the parsing was successful.
+   */
+  bool ParseWeek(const nsAString& aValue,
+                 uint32_t* aYear,
+                 uint32_t* aWeek) const;
+  /**
    * Parse a date string of the form yyyy-mm-dd
    *
    * @param the string to be parsed.
    * @return the date in aYear, aMonth, aDay.
    * @return whether the parsing was successful.
    */
   bool ParseDate(const nsAString& aValue,
                  uint32_t* aYear,
@@ -1220,16 +1238,32 @@ protected:
 
   /**
    * This methods returns the number of months between January 1970 and the
    * given year and month.
    */
   int32_t MonthsSinceJan1970(uint32_t aYear, uint32_t aMonth) const;
 
   /**
+   * This methods returns the day of the week given a date, note that 0 = Sunday.
+   */
+  uint32_t DayOfWeek(uint32_t aYear, uint32_t aMonth, uint32_t aDay) const;
+
+  /**
+   * This methods returns the maximum number of week in a given year, the
+   * result is either 52 or 53.
+   */
+  uint32_t MaximumWeekInYear(uint32_t aYear) const;
+
+  /**
+   * This methods returns true if it's a leap year.
+   */
+  bool IsLeapYear(uint32_t aYear) const;
+
+  /**
    * Returns whether aValue is a valid time as described by HTML specifications:
    * http://www.whatwg.org/specs/web-apps/current-work/multipage/common-microsyntaxes.html#valid-time-string
    *
    * @param aValue the string to be tested.
    * @return Whether the string is a valid time per HTML specifications.
    */
   bool IsValidTime(const nsAString& aValue) const;
 
@@ -1455,16 +1489,18 @@ protected:
 
   // Float value returned by GetStep() when the step attribute is set to 'any'.
   static const Decimal kStepAny;
 
   // Maximum year limited by ECMAScript date object range, year <= 275760.
   static const double kMaximumYear;
   // Minimum year limited by HTML standard, year >= 1.
   static const double kMinimumYear;
+  // Long years in a ISO calendar have 53 weeks in them.
+  static const double kMaximumWeekInYear;
 
   /**
    * The type of this input (<input type=...>) as an integer.
    * @see nsIFormControl.h (specifically NS_FORM_INPUT_*)
    */
   uint8_t                  mType;
   nsContentUtils::AutocompleteAttrState mAutocompleteAttrState;
   bool                     mDisabledChanged     : 1;
--- a/dom/html/test/forms/test_input_sanitization.html
+++ b/dom/html/test/forms/test_input_sanitization.html
@@ -69,17 +69,17 @@ function flushDelayedTests(description)
 }
 
 // We are excluding "file" because it's too different from the other types.
 // And it has no sanitizing algorithm.
 var inputTypes =
 [
   "text", "password", "search", "tel", "hidden", "checkbox", "radio",
   "submit", "image", "reset", "button", "email", "url", "number", "date",
-  "time", "range", "color", "month"
+  "time", "range", "color", "month", "week"
 ];
 
 var todoTypes =
 [
   "datetime", "datetime-local",
 ];
 
 var valueModeValue =
@@ -186,16 +186,46 @@ function sanitizeValue(aType, aValue)
         return "";
       }
       var month = Number(match[2]);
       if (month > 12 || month < 1) {
         return "";
       }
       return aValue;
     case "week":
+      // https://html.spec.whatwg.org/multipage/infrastructure.html#valid-week-string
+      function isLeapYear(aYear) {
+        return ((aYear % 4 == 0) && (aYear % 100 != 0)) || (aYear % 400 == 0);
+      }
+      function getDayofWeek(aYear, aMonth, aDay) { /* 0 = Sunday */
+        // Tomohiko Sakamoto algorithm.
+        var monthTable = [0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4];
+        aYear -= Number(aMonth < 3);
+
+        return (aYear + parseInt(aYear / 4) - parseInt(aYear / 100) +
+                parseInt(aYear / 400) + monthTable[aMonth - 1] + aDay) % 7;
+      }
+      function getMaximumWeekInYear(aYear) {
+        var day = getDayofWeek(aYear, 1, 1);
+        return day == 4 || (day == 3 && isLeapYear(aYear)) ? 53 : 52;
+      }
+
+      var match = /^([0-9]{4,})-W([0-9]{2})$/.exec(aValue);
+      if (!match) {
+        return "";
+      }
+      var year = Number(match[1]);
+      if (year === 0) {
+        return "";
+      }
+      var week = Number(match[2]);
+      if (week > 53 || month < 1) {
+        return "";
+      }
+      return 1 <= week && week <= getMaximumWeekInYear(year) ? aValue : "";
     case "datetime":
     case "datetime-local":
       // TODO: write the sanitize algorithm.
       ok(false);
       return "";
     case "color":
       return /^#[0-9A-Fa-f]{6}$/.exec(aValue) ? aValue.toLowerCase() : "#000000";
     default:
@@ -360,16 +390,37 @@ function checkSanitizing(element, inputT
     "2013-03-13",
     "december",
     "abcdef",
     "12",
     "  2013-03",
     "2013 - 03",
     "2013 03",
     "2013/03",
+    // For week
+    "1970-W01",
+    "1970-W53",
+    "1964-W53",
+    "1900-W10",
+    "2004-W53",
+    "2065-W53",
+    "2099-W53",
+    "2010-W53",
+    "2016-W30",
+    "1900-W3",
+    "2016-w30",
+    "2016-30",
+    "16-W30",
+    "2016-Week30",
+    "2000-100",
+    "0000-W01",
+    "00-W01",
+    "123456-W05",
+    "1985-W100",
+    "week",
   ];
 
   for (value of testData) {
     element.setAttribute('value', value);
     delayed_is(element.value, sanitizeValue(type, value),
        "The value has not been correctly sanitized for type=" + type);
     delayed_is(element.getAttribute('value'), value,
        "The content value should not have been sanitized");
--- a/dom/html/test/forms/test_input_typing_sanitization.html
+++ b/dom/html/test/forms/test_input_typing_sanitization.html
@@ -193,16 +193,34 @@ function runTest()
         '-',
         'december',
         '2012-dec',
         '2012/12',
         '2012-99',
         '2012-1',
       ]
     },
+    {
+      type: 'week',
+      validData: [
+        '0001-W01',
+        '1970-W53',
+        '100000-W52',
+        '2016-W30',
+      ],
+      invalidData: [
+        '1-W01',
+        'week',
+        '2016-30',
+        '2010-W80',
+        '2000/W30',
+        '1985-W00',
+        '1000-W'
+      ]
+    },
     { type: 'datetime', todo: true },
     { type: 'datetime-local', todo: true },
   ];
 
   for (test of data) {
     gCurrentTest = test;
 
     if (test.todo) {
--- a/dom/html/test/test_bug590363.html
+++ b/dom/html/test/test_bug590363.html
@@ -43,55 +43,58 @@ var testData = [
   [ 'week',     true ]
   // 'file' is treated separatly.
 ];
 
 var todoTypes = [
   "datetime", "datetime-local"
 ];
 
-var nonTrivialSanitizing = [ 'number', 'date', 'time', 'color', 'month' ];
+var nonTrivialSanitizing = [ 'number', 'date', 'time', 'color', 'month', 'week' ];
 
 var length = testData.length;
 for (var i=0; i<length; ++i) {
   for (var j=0; j<length; ++j) {
     var e = document.createElement('input');
     e.type = testData[i][0];
 
     var expectedValue;
 
     // range will sanitize its value to 50 (the default) if it isn't a valid
     // number. We need to handle that specially.
     if (testData[j][0] == 'range' || testData[i][0] == 'range') {
       if (testData[j][0] == 'date' || testData[j][0] == 'time' ||
-          testData[j][0] == 'month') {
+          testData[j][0] == 'month' || testData[j][0] == 'week') {
         expectedValue = '';
       } else if (testData[j][0] == 'color') {
         expectedValue = '#000000';
       } else {
         expectedValue = '50';
       }
     } else if (testData[i][0] == 'color' || testData[j][0] == 'color') {
         if (testData[j][0] == 'number' || testData[j][0] == 'date' ||
-            testData[j][0] == 'time' || testData[j][0] == 'month') {
+            testData[j][0] == 'time' || testData[j][0] == 'month' ||
+            testData[j][0] == 'week') {
           expectedValue = ''
         } else {
           expectedValue = '#000000';
         }
     } else if (nonTrivialSanitizing.indexOf(testData[i][0]) != -1 &&
                nonTrivialSanitizing.indexOf(testData[j][0]) != -1) {
       expectedValue = '';
     } else if (testData[i][0] == 'number' || testData[j][0] == 'number') {
       expectedValue = '42';
     } else if (testData[i][0] == 'date' || testData[j][0] == 'date') {
       expectedValue = '2012-12-21';
     } else if (testData[i][0] == 'time' || testData[j][0] == 'time') {
       expectedValue = '21:21';
     } else if (testData[i][0] == 'month' || testData[j][0] == 'month') {
       expectedValue = '2013-03';
+    } else if (testData[i][0] == 'week' || testData[j][0] == 'week') {
+      expectedValue = '2016-W35';
     } else {
       expectedValue = "foo";
     }
     e.value = expectedValue;
 
     e.type = testData[j][0];
     is(e.value, expectedValue, ".value should still return the same value after " +
        "changing type from " + testData[i][0] + " to " + testData[j][0]);
--- a/dom/media/MediaFormatReader.cpp
+++ b/dom/media/MediaFormatReader.cpp
@@ -903,28 +903,24 @@ MediaFormatReader::RequestDemuxSamples(T
   LOGV("Requesting extra demux %s", TrackTypeToStr(aTrack));
   if (aTrack == TrackInfo::kVideoTrack) {
     DoDemuxVideo();
   } else {
     DoDemuxAudio();
   }
 }
 
-bool
+void
 MediaFormatReader::DecodeDemuxedSamples(TrackType aTrack,
                                         MediaRawData* aSample)
 {
   MOZ_ASSERT(OnTaskQueue());
   auto& decoder = GetDecoderData(aTrack);
-  if (NS_FAILED(decoder.mDecoder->Input(aSample))) {
-      LOG("Unable to pass frame to decoder");
-      return false;
-  }
+  decoder.mDecoder->Input(aSample);
   decoder.mDecodePending = true;
-  return true;
 }
 
 void
 MediaFormatReader::HandleDemuxedSamples(TrackType aTrack,
                                         AbstractMediaDecoder::AutoNotifyDecoded& aA)
 {
   MOZ_ASSERT(OnTaskQueue());
 
@@ -1014,19 +1010,18 @@ MediaFormatReader::HandleDemuxedSamples(
     decoder.mNumSamplesInput++;
     decoder.mSizeOfQueue++;
     if (aTrack == TrackInfo::kVideoTrack) {
       aA.mStats.mParsedFrames++;
     }
 
     if (mDemuxOnly) {
       ReturnOutput(sample, aTrack);
-    } else if (!DecodeDemuxedSamples(aTrack, sample)) {
-      NotifyError(aTrack);
-      return;
+    } else {
+      DecodeDemuxedSamples(aTrack, sample);
     }
 
     decoder.mQueuedSamples.RemoveElementAt(0);
     if (mDemuxOnly) {
       // If demuxed-only case, ReturnOutput will resolve with one demuxed data.
       // Then we should stop doing the iteration.
       return;
     }
--- a/dom/media/MediaFormatReader.h
+++ b/dom/media/MediaFormatReader.h
@@ -128,17 +128,17 @@ private:
   // Returns true if no more action is required.
   bool UpdateReceivedNewData(TrackType aTrack);
   // Called when new samples need to be demuxed.
   void RequestDemuxSamples(TrackType aTrack);
   // Handle demuxed samples by the input behavior.
   void HandleDemuxedSamples(TrackType aTrack,
                             AbstractMediaDecoder::AutoNotifyDecoded& aA);
   // Decode any pending already demuxed samples.
-  bool DecodeDemuxedSamples(TrackType aTrack,
+  void DecodeDemuxedSamples(TrackType aTrack,
                             MediaRawData* aSample);
 
   struct InternalSeekTarget {
     InternalSeekTarget(const media::TimeInterval& aTime, bool aDropTarget)
       : mTime(aTime)
       , mDropTarget(aDropTarget)
       , mWaiting(false)
       , mHasSeeked(false)
--- a/dom/media/platforms/PlatformDecoderModule.h
+++ b/dom/media/platforms/PlatformDecoderModule.h
@@ -205,16 +205,20 @@ public:
 //
 // Don't block inside these functions, unless it's explicitly noted that you
 // should (like in Flush()).
 //
 // Decoding is done asynchronously. Any async work can be done on the
 // TaskQueue passed into the PlatformDecoderModules's Create*Decoder()
 // function. This may not be necessary for platforms with async APIs
 // for decoding.
+//
+// If an error occurs at any point after the Init promise has been
+// completed, then Error() must be called on the associated
+// MediaDataDecoderCallback.
 class MediaDataDecoder {
 protected:
   virtual ~MediaDataDecoder() {};
 
 public:
   enum class DecoderFailureReason : uint8_t {
     INIT_ERROR,
     CANCELED
@@ -230,62 +234,59 @@ public:
   // than in its constructor or PlatformDecoderModule::Create*Decoder(),
   // so that if the MediaFormatReader needs to shutdown during initialization,
   // it can call Shutdown() to cancel this operation. Any initialization
   // that requires blocking the calling thread in this function *must*
   // be done here so that it can be canceled by calling Shutdown()!
   virtual RefPtr<InitPromise> Init() = 0;
 
   // Inserts a sample into the decoder's decode pipeline.
-  virtual nsresult Input(MediaRawData* aSample) = 0;
+  virtual void Input(MediaRawData* aSample) = 0;
 
   // Causes all samples in the decoding pipeline to be discarded. When
   // this function returns, the decoder must be ready to accept new input
   // for decoding. This function is called when the demuxer seeks, before
   // decoding resumes after the seek.
   // While the reader calls Flush(), it ignores all output sent to it;
   // it is safe (but pointless) to send output while Flush is called.
   // The MediaFormatReader will not call Input() while it's calling Flush().
-  virtual nsresult Flush() = 0;
+  virtual void Flush() = 0;
 
   // Causes all complete samples in the pipeline that can be decoded to be
   // output. If the decoder can't produce samples from the current output,
   // it drops the input samples. The decoder may be holding onto samples
   // that are required to decode samples that it expects to get in future.
   // This is called when the demuxer reaches end of stream.
   // The MediaFormatReader will not call Input() while it's calling Drain().
   // This function is asynchronous. The MediaDataDecoder must call
   // MediaDataDecoderCallback::DrainComplete() once all remaining
   // samples have been output.
-  virtual nsresult Drain() = 0;
+  virtual void Drain() = 0;
 
   // Cancels all init/input/drain operations, and shuts down the
   // decoder. The platform decoder should clean up any resources it's using
   // and release memory etc. Shutdown() must block until the decoder has
   // completed shutdown. The reader calls Flush() before calling Shutdown().
   // The reader will delete the decoder once Shutdown() returns.
   // The MediaDataDecoderCallback *must* not be called after Shutdown() has
   // returned.
-  virtual nsresult Shutdown() = 0;
+  virtual void Shutdown() = 0;
 
   // Called from the state machine task queue or main thread.
   // Decoder needs to decide whether or not hardware accelearation is supported
   // after creating. It doesn't need to call Init() before calling this function.
   virtual bool IsHardwareAccelerated(nsACString& aFailureReason) const { return false; }
 
   // ConfigurationChanged will be called to inform the video or audio decoder
   // that the format of the next input sample is about to change.
   // If video decoder, aConfig will be a VideoInfo object.
   // If audio decoder, aConfig will be a AudioInfo object.
   // It is not safe to store a reference to this object and the decoder must
   // make a copy.
-  virtual nsresult ConfigurationChanged(const TrackInfo& aConfig)
-  {
-    return NS_OK;
-  }
+  virtual void ConfigurationChanged(const TrackInfo& aConfig) {}
 
   // Return the name of the MediaDataDecoder, only used for decoding.
   // Only return a static const string, as the information may be accessed
   // in a non thread-safe fashion.
   virtual const char* GetDescriptionName() const = 0;
 
   // Set a hint of seek target time to decoder. Decoder will drop any decoded
   // data which pts is smaller than this value. This threshold needs to be clear
--- a/dom/media/platforms/agnostic/BlankDecoderModule.cpp
+++ b/dom/media/platforms/agnostic/BlankDecoderModule.cpp
@@ -39,47 +39,40 @@ public:
     , mType(aParams.mConfig.GetType())
   {
   }
 
   RefPtr<InitPromise> Init() override {
     return InitPromise::CreateAndResolve(mType, __func__);
   }
 
-  nsresult Shutdown() override {
-    return NS_OK;
-  }
+  void Shutdown() override {}
 
-  nsresult Input(MediaRawData* aSample) override
+  void Input(MediaRawData* aSample) override
   {
     RefPtr<MediaData> data =
       mCreator->Create(media::TimeUnit::FromMicroseconds(aSample->mTime),
                        media::TimeUnit::FromMicroseconds(aSample->mDuration),
                        aSample->mOffset);
 
     OutputFrame(data);
-
-    return NS_OK;
   }
 
-  nsresult Flush() override
+  void Flush() override
   {
     mReorderQueue.Clear();
-
-    return NS_OK;
   }
 
-  nsresult Drain() override
+  void Drain() override
   {
     while (!mReorderQueue.IsEmpty()) {
       mCallback->Output(mReorderQueue.Pop().get());
     }
 
     mCallback->DrainComplete();
-    return NS_OK;
   }
 
   const char* GetDescriptionName() const override
   {
     return "blank media data decoder";
   }
 
 private:
--- a/dom/media/platforms/agnostic/OpusDecoder.cpp
+++ b/dom/media/platforms/agnostic/OpusDecoder.cpp
@@ -36,20 +36,19 @@ OpusDataDecoder::OpusDataDecoder(const C
 OpusDataDecoder::~OpusDataDecoder()
 {
   if (mOpusDecoder) {
     opus_multistream_decoder_destroy(mOpusDecoder);
     mOpusDecoder = nullptr;
   }
 }
 
-nsresult
+void
 OpusDataDecoder::Shutdown()
 {
-  return NS_OK;
 }
 
 void
 OpusDataDecoder::AppendCodecDelay(MediaByteBuffer* config, uint64_t codecDelayUS)
 {
   uint8_t buffer[sizeof(uint64_t)];
   BigEndian::writeUint64(buffer, codecDelayUS);
   config->AppendElements(buffer, sizeof(uint64_t));
@@ -133,23 +132,21 @@ OpusDataDecoder::DecodeHeader(const unsi
     // Should never get here as vorbis layout is always convertible to SMPTE
     // default layout.
     PodCopy(mMappingTable, mOpusParser->mMappingTable, MAX_AUDIO_CHANNELS);
   }
 
   return NS_OK;
 }
 
-nsresult
+void
 OpusDataDecoder::Input(MediaRawData* aSample)
 {
   mTaskQueue->Dispatch(NewRunnableMethod<RefPtr<MediaRawData>>(
                        this, &OpusDataDecoder::ProcessDecode, aSample));
-
-  return NS_OK;
 }
 
 void
 OpusDataDecoder::ProcessDecode(MediaRawData* aSample)
 {
   if (mIsFlushing) {
     return;
   }
@@ -318,41 +315,39 @@ OpusDataDecoder::DoDecode(MediaRawData* 
 }
 
 void
 OpusDataDecoder::ProcessDrain()
 {
   mCallback->DrainComplete();
 }
 
-nsresult
+void
 OpusDataDecoder::Drain()
 {
   mTaskQueue->Dispatch(NewRunnableMethod(this, &OpusDataDecoder::ProcessDrain));
-  return NS_OK;
 }
 
-nsresult
+void
 OpusDataDecoder::Flush()
 {
   if (!mOpusDecoder) {
-    return NS_OK;
+    return;
   }
   mIsFlushing = true;
   nsCOMPtr<nsIRunnable> runnable = NS_NewRunnableFunction([this] () {
     MOZ_ASSERT(mOpusDecoder);
     // Reset the decoder.
     opus_multistream_decoder_ctl(mOpusDecoder, OPUS_RESET_STATE);
     mSkip = mOpusParser->mPreSkip;
     mPaddingDiscarded = false;
     mLastFrameTime.reset();
   });
   SyncRunnable::DispatchToThread(mTaskQueue, runnable);
   mIsFlushing = false;
-  return NS_OK;
 }
 
 /* static */
 bool
 OpusDataDecoder::IsOpus(const nsACString& aMimeType)
 {
   return aMimeType.EqualsLiteral("audio/webm; codecs=opus") ||
          aMimeType.EqualsLiteral("audio/ogg; codecs=opus") ||
--- a/dom/media/platforms/agnostic/OpusDecoder.h
+++ b/dom/media/platforms/agnostic/OpusDecoder.h
@@ -16,20 +16,20 @@ namespace mozilla {
 
 class OpusDataDecoder : public MediaDataDecoder
 {
 public:
   explicit OpusDataDecoder(const CreateDecoderParams& aParams);
   ~OpusDataDecoder();
 
   RefPtr<InitPromise> Init() override;
-  nsresult Input(MediaRawData* aSample) override;
-  nsresult Flush() override;
-  nsresult Drain() override;
-  nsresult Shutdown() override;
+  void Input(MediaRawData* aSample) override;
+  void Flush() override;
+  void Drain() override;
+  void Shutdown() override;
   const char* GetDescriptionName() const override
   {
     return "opus audio decoder";
   }
 
   // Return true if mimetype is Opus
   static bool IsOpus(const nsACString& aMimeType);
 
--- a/dom/media/platforms/agnostic/TheoraDecoder.cpp
+++ b/dom/media/platforms/agnostic/TheoraDecoder.cpp
@@ -53,24 +53,23 @@ TheoraDecoder::TheoraDecoder(const Creat
 TheoraDecoder::~TheoraDecoder()
 {
   MOZ_COUNT_DTOR(TheoraDecoder);
   th_setup_free(mTheoraSetupInfo);
   th_comment_clear(&mTheoraComment);
   th_info_clear(&mTheoraInfo);
 }
 
-nsresult
+void
 TheoraDecoder::Shutdown()
 {
   if (mTheoraDecoderContext) {
     th_decode_free(mTheoraDecoderContext);
     mTheoraDecoderContext = nullptr;
   }
-  return NS_OK;
 }
 
 RefPtr<MediaDataDecoder::InitPromise>
 TheoraDecoder::Init()
 {
   th_comment_init(&mTheoraComment);
   th_info_init(&mTheoraInfo);
 
@@ -94,27 +93,26 @@ TheoraDecoder::Init()
   if (mTheoraDecoderContext) {
     return InitPromise::CreateAndResolve(TrackInfo::kVideoTrack, __func__);
   } else {
     return InitPromise::CreateAndReject(DecoderFailureReason::INIT_ERROR, __func__);
   }
 
 }
 
-nsresult
+void
 TheoraDecoder::Flush()
 {
   MOZ_ASSERT(mCallback->OnReaderTaskQueue());
   mIsFlushing = true;
   nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction([this] () {
     // nothing to do for now.
   });
   SyncRunnable::DispatchToThread(mTaskQueue, r);
   mIsFlushing = false;
-  return NS_OK;
 }
 
 nsresult
 TheoraDecoder::DoDecodeHeader(const unsigned char* aData, size_t aLength)
 {
   bool bos = mPacketCount == 0;
   ogg_packet pkt = InitTheoraPacket(aData, aLength, bos, false, 0, mPacketCount++);
 
@@ -202,40 +200,36 @@ TheoraDecoder::ProcessDecode(MediaRawDat
   }
   if (DoDecode(aSample) == -1) {
     mCallback->Error(MediaDataDecoderError::DECODE_ERROR);
   } else {
     mCallback->InputExhausted();
   }
 }
 
-nsresult
+void
 TheoraDecoder::Input(MediaRawData* aSample)
 {
   MOZ_ASSERT(mCallback->OnReaderTaskQueue());
   mTaskQueue->Dispatch(NewRunnableMethod<RefPtr<MediaRawData>>(
                        this, &TheoraDecoder::ProcessDecode, aSample));
-
-  return NS_OK;
 }
 
 void
 TheoraDecoder::ProcessDrain()
 {
   MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
   mCallback->DrainComplete();
 }
 
-nsresult
+void
 TheoraDecoder::Drain()
 {
   MOZ_ASSERT(mCallback->OnReaderTaskQueue());
   mTaskQueue->Dispatch(NewRunnableMethod(this, &TheoraDecoder::ProcessDrain));
-
-  return NS_OK;
 }
 
 /* static */
 bool
 TheoraDecoder::IsTheora(const nsACString& aMimeType)
 {
   return aMimeType.EqualsLiteral("video/ogg; codecs=theora");
 }
--- a/dom/media/platforms/agnostic/TheoraDecoder.h
+++ b/dom/media/platforms/agnostic/TheoraDecoder.h
@@ -19,20 +19,20 @@ namespace mozilla {
 class TheoraDecoder : public MediaDataDecoder
 {
 public:
   explicit TheoraDecoder(const CreateDecoderParams& aParams);
 
   ~TheoraDecoder();
 
   RefPtr<InitPromise> Init() override;
-  nsresult Input(MediaRawData* aSample) override;
-  nsresult Flush() override;
-  nsresult Drain() override;
-  nsresult Shutdown() override;
+  void Input(MediaRawData* aSample) override;
+  void Flush() override;
+  void Drain() override;
+  void Shutdown() override;
 
   // Return true if mimetype is a Theora codec
   static bool IsTheora(const nsACString& aMimeType);
 
   const char* GetDescriptionName() const override
   {
     return "theora video decoder";
   }
--- a/dom/media/platforms/agnostic/VPXDecoder.cpp
+++ b/dom/media/platforms/agnostic/VPXDecoder.cpp
@@ -46,21 +46,20 @@ VPXDecoder::VPXDecoder(const CreateDecod
   PodZero(&mVPX);
 }
 
 VPXDecoder::~VPXDecoder()
 {
   MOZ_COUNT_DTOR(VPXDecoder);
 }
 
-nsresult
+void
 VPXDecoder::Shutdown()
 {
   vpx_codec_destroy(&mVPX);
-  return NS_OK;
 }
 
 RefPtr<MediaDataDecoder::InitPromise>
 VPXDecoder::Init()
 {
   int decode_threads = 2;
 
   vpx_codec_iface_t* dx = nullptr;
@@ -81,27 +80,26 @@ VPXDecoder::Init()
   config.w = config.h = 0; // set after decode
 
   if (!dx || vpx_codec_dec_init(&mVPX, dx, &config, 0)) {
     return InitPromise::CreateAndReject(DecoderFailureReason::INIT_ERROR, __func__);
   }
   return InitPromise::CreateAndResolve(TrackInfo::kVideoTrack, __func__);
 }
 
-nsresult
+void
 VPXDecoder::Flush()
 {
   MOZ_ASSERT(mCallback->OnReaderTaskQueue());
   mIsFlushing = true;
   nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction([this] () {
     // nothing to do for now.
   });
   SyncRunnable::DispatchToThread(mTaskQueue, r);
   mIsFlushing = false;
-  return NS_OK;
 }
 
 int
 VPXDecoder::DoDecode(MediaRawData* aSample)
 {
   MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
 #if defined(DEBUG)
   vpx_codec_stream_info_t si;
@@ -194,40 +192,36 @@ VPXDecoder::ProcessDecode(MediaRawData* 
   }
   if (DoDecode(aSample) == -1) {
     mCallback->Error(MediaDataDecoderError::DECODE_ERROR);
   } else {
     mCallback->InputExhausted();
   }
 }
 
-nsresult
+void
 VPXDecoder::Input(MediaRawData* aSample)
 {
   MOZ_ASSERT(mCallback->OnReaderTaskQueue());
   mTaskQueue->Dispatch(NewRunnableMethod<RefPtr<MediaRawData>>(
                        this, &VPXDecoder::ProcessDecode, aSample));
-
-  return NS_OK;
 }
 
 void
 VPXDecoder::ProcessDrain()
 {
   MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
   mCallback->DrainComplete();
 }
 
-nsresult
+void
 VPXDecoder::Drain()
 {
   MOZ_ASSERT(mCallback->OnReaderTaskQueue());
   mTaskQueue->Dispatch(NewRunnableMethod(this, &VPXDecoder::ProcessDrain));
-
-  return NS_OK;
 }
 
 /* static */
 bool
 VPXDecoder::IsVPX(const nsACString& aMimeType, uint8_t aCodecMask)
 {
   return ((aCodecMask & VPXDecoder::VP8) &&
           aMimeType.EqualsLiteral("video/webm; codecs=vp8")) ||
--- a/dom/media/platforms/agnostic/VPXDecoder.h
+++ b/dom/media/platforms/agnostic/VPXDecoder.h
@@ -20,20 +20,20 @@ using namespace layers;
 
 class VPXDecoder : public MediaDataDecoder
 {
 public:
   explicit VPXDecoder(const CreateDecoderParams& aParams);
   ~VPXDecoder();
 
   RefPtr<InitPromise> Init() override;
-  nsresult Input(MediaRawData* aSample) override;
-  nsresult Flush() override;
-  nsresult Drain() override;
-  nsresult Shutdown() override;
+  void Input(MediaRawData* aSample) override;
+  void Flush() override;
+  void Drain() override;
+  void Shutdown() override;
   const char* GetDescriptionName() const override
   {
     return "libvpx video decoder";
   }
 
   enum Codec: uint8_t {
     VP8 = 1 << 0,
     VP9 = 1 << 1
--- a/dom/media/platforms/agnostic/VorbisDecoder.cpp
+++ b/dom/media/platforms/agnostic/VorbisDecoder.cpp
@@ -49,21 +49,19 @@ VorbisDataDecoder::VorbisDataDecoder(con
 VorbisDataDecoder::~VorbisDataDecoder()
 {
   vorbis_block_clear(&mVorbisBlock);
   vorbis_dsp_clear(&mVorbisDsp);
   vorbis_info_clear(&mVorbisInfo);
   vorbis_comment_clear(&mVorbisComment);
 }
 
-nsresult
+void
 VorbisDataDecoder::Shutdown()
 {
-  //mReader = nullptr;
-  return NS_OK;
 }
 
 RefPtr<MediaDataDecoder::InitPromise>
 VorbisDataDecoder::Init()
 {
   vorbis_info_init(&mVorbisInfo);
   vorbis_comment_init(&mVorbisComment);
   PodZero(&mVorbisDsp);
@@ -119,24 +117,22 @@ VorbisDataDecoder::DecodeHeader(const un
   MOZ_ASSERT(mPacketCount <= 3);
 
   int r = vorbis_synthesis_headerin(&mVorbisInfo,
                                     &mVorbisComment,
                                     &pkt);
   return r == 0 ? NS_OK : NS_ERROR_FAILURE;
 }
 
-nsresult
+void
 VorbisDataDecoder::Input(MediaRawData* aSample)
 {
   MOZ_ASSERT(mCallback->OnReaderTaskQueue());
   mTaskQueue->Dispatch(NewRunnableMethod<RefPtr<MediaRawData>>(
                        this, &VorbisDataDecoder::ProcessDecode, aSample));
-
-  return NS_OK;
 }
 
 void
 VorbisDataDecoder::ProcessDecode(MediaRawData* aSample)
 {
   MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
   if (mIsFlushing) {
     return;
@@ -250,39 +246,37 @@ VorbisDataDecoder::DoDecode(MediaRawData
 
 void
 VorbisDataDecoder::ProcessDrain()
 {
   MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
   mCallback->DrainComplete();
 }
 
-nsresult
+void
 VorbisDataDecoder::Drain()
 {
   MOZ_ASSERT(mCallback->OnReaderTaskQueue());
   mTaskQueue->Dispatch(NewRunnableMethod(this, &VorbisDataDecoder::ProcessDrain));
-  return NS_OK;
 }
 
-nsresult
+void
 VorbisDataDecoder::Flush()
 {
   MOZ_ASSERT(mCallback->OnReaderTaskQueue());
   mIsFlushing = true;
   nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction([this] () {
     // Ignore failed results from vorbis_synthesis_restart. They
     // aren't fatal and it fails when ResetDecode is called at a
     // time when no vorbis data has been read.
     vorbis_synthesis_restart(&mVorbisDsp);
     mLastFrameTime.reset();
   });
   SyncRunnable::DispatchToThread(mTaskQueue, r);
   mIsFlushing = false;
-  return NS_OK;
 }
 
 /* static */
 bool
 VorbisDataDecoder::IsVorbis(const nsACString& aMimeType)
 {
   return aMimeType.EqualsLiteral("audio/webm; codecs=vorbis") ||
          aMimeType.EqualsLiteral("audio/ogg; codecs=vorbis");
--- a/dom/media/platforms/agnostic/VorbisDecoder.h
+++ b/dom/media/platforms/agnostic/VorbisDecoder.h
@@ -20,20 +20,20 @@ namespace mozilla {
 
 class VorbisDataDecoder : public MediaDataDecoder
 {
 public:
   explicit VorbisDataDecoder(const CreateDecoderParams& aParams);
   ~VorbisDataDecoder();
 
   RefPtr<InitPromise> Init() override;
-  nsresult Input(MediaRawData* aSample) override;
-  nsresult Flush() override;
-  nsresult Drain() override;
-  nsresult Shutdown() override;
+  void Input(MediaRawData* aSample) override;
+  void Flush() override;
+  void Drain() override;
+  void Shutdown() override;
   const char* GetDescriptionName() const override
   {
     return "vorbis audio decoder";
   }
 
   // Return true if mimetype is Vorbis
   static bool IsVorbis(const nsACString& aMimeType);
   static const AudioConfig::Channel* VorbisLayout(uint32_t aChannels);
--- a/dom/media/platforms/agnostic/WAVDecoder.cpp
+++ b/dom/media/platforms/agnostic/WAVDecoder.cpp
@@ -46,37 +46,35 @@ DecodeULawSample(uint8_t aValue)
 }
 
 WaveDataDecoder::WaveDataDecoder(const CreateDecoderParams& aParams)
   : mInfo(aParams.AudioConfig())
   , mCallback(aParams.mCallback)
 {
 }
 
-nsresult
+void
 WaveDataDecoder::Shutdown()
 {
-  return NS_OK;
 }
 
 RefPtr<MediaDataDecoder::InitPromise>
 WaveDataDecoder::Init()
 {
   return InitPromise::CreateAndResolve(TrackInfo::kAudioTrack, __func__);
 }
 
-nsresult
+void
 WaveDataDecoder::Input(MediaRawData* aSample)
 {
   if (!DoDecode(aSample)) {
     mCallback->Error(MediaDataDecoderError::DECODE_ERROR);
   } else {
     mCallback->InputExhausted();
   }
-  return NS_OK;
 }
 
 bool
 WaveDataDecoder::DoDecode(MediaRawData* aSample)
 {
   size_t aLength = aSample->Size();
   ByteReader aReader(aSample->Data(), aLength);
   int64_t aOffset = aSample->mOffset;
@@ -126,27 +124,25 @@ WaveDataDecoder::DoDecode(MediaRawData* 
                                   frames,
                                   Move(buffer),
                                   mInfo.mChannels,
                                   mInfo.mRate));
 
   return true;
 }
 
-nsresult
+void
 WaveDataDecoder::Drain()
 {
   mCallback->DrainComplete();
-  return NS_OK;
 }
 
-nsresult
+void
 WaveDataDecoder::Flush()
 {
-  return NS_OK;
 }
 
 /* static */
 bool
 WaveDataDecoder::IsWave(const nsACString& aMimeType)
 {
   // Some WebAudio uses "audio/x-wav",
   // WAVdemuxer uses "audio/wave; codecs=aNum".
--- a/dom/media/platforms/agnostic/WAVDecoder.h
+++ b/dom/media/platforms/agnostic/WAVDecoder.h
@@ -16,20 +16,20 @@ class WaveDataDecoder : public MediaData
 {
 public:
   explicit WaveDataDecoder(const CreateDecoderParams& aParams);
 
   // Return true if mimetype is Wave
   static bool IsWave(const nsACString& aMimeType);
 
   RefPtr<InitPromise> Init() override;
-  nsresult Input(MediaRawData* aSample) override;
-  nsresult Flush() override;
-  nsresult Drain() override;
-  nsresult Shutdown() override;
+  void Input(MediaRawData* aSample) override;
+  void Flush() override;
+  void Drain() override;
+  void Shutdown() override;
   const char* GetDescriptionName() const override
   {
     return "wave audio decoder";
   }
 
 private:
   bool DoDecode(MediaRawData* aSample);
 
--- a/dom/media/platforms/agnostic/eme/EMEDecoderModule.cpp
+++ b/dom/media/platforms/agnostic/eme/EMEDecoderModule.cpp
@@ -40,36 +40,36 @@ public:
   {
   }
 
   RefPtr<InitPromise> Init() override {
     MOZ_ASSERT(!mIsShutdown);
     return mDecoder->Init();
   }
 
-  nsresult Input(MediaRawData* aSample) override {
+  void Input(MediaRawData* aSample) override {
     MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
     if (mIsShutdown) {
       NS_WARNING("EME encrypted sample arrived after shutdown");
-      return NS_OK;
+      return;
     }
     if (mSamplesWaitingForKey->WaitIfKeyNotUsable(aSample)) {
-      return NS_OK;
+      return;
     }
 
     nsAutoPtr<MediaRawDataWriter> writer(aSample->CreateWriter());
     mProxy->GetSessionIdsForKeyId(aSample->mCrypto.mKeyId,
                                   writer->mCrypto.mSessionIds);
 
     mDecrypts.Put(aSample, new DecryptPromiseRequestHolder());
     mDecrypts.Get(aSample)->Begin(mProxy->Decrypt(aSample)->Then(
       mTaskQueue, __func__, this,
       &EMEDecryptor::Decrypted,
       &EMEDecryptor::Decrypted));
-    return NS_OK;
+    return;
   }
 
   void Decrypted(const DecryptResult& aDecrypted) {
     MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
     MOZ_ASSERT(aDecrypted.mSample);
 
     nsAutoPtr<DecryptPromiseRequestHolder> holder;
     mDecrypts.RemoveAndForget(aDecrypted.mSample, holder);
@@ -99,60 +99,53 @@ public:
       MOZ_ASSERT(!mIsShutdown);
       // The Adobe GMP AAC decoder gets confused if we pass it non-encrypted
       // samples with valid crypto data. So clear the crypto data, since the
       // sample should be decrypted now anyway. If we don't do this and we're
       // using the Adobe GMP for unencrypted decoding of data that is decrypted
       // by gmp-clearkey, decoding will fail.
       UniquePtr<MediaRawDataWriter> writer(aDecrypted.mSample->CreateWriter());
       writer->mCrypto = CryptoSample();
-      nsresult rv = mDecoder->Input(aDecrypted.mSample);
-      Unused << NS_WARN_IF(NS_FAILED(rv));
+      mDecoder->Input(aDecrypted.mSample);
     }
   }
 
-  nsresult Flush() override {
+  void Flush() override {
     MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
     MOZ_ASSERT(!mIsShutdown);
     for (auto iter = mDecrypts.Iter(); !iter.Done(); iter.Next()) {
       nsAutoPtr<DecryptPromiseRequestHolder>& holder = iter.Data();
       holder->DisconnectIfExists();
       iter.Remove();
     }
-    nsresult rv = mDecoder->Flush();
-    Unused << NS_WARN_IF(NS_FAILED(rv));
+    mDecoder->Flush();
     mSamplesWaitingForKey->Flush();
-    return rv;
   }
 
-  nsresult Drain() override {
+  void Drain() override {
     MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
     MOZ_ASSERT(!mIsShutdown);
     for (auto iter = mDecrypts.Iter(); !iter.Done(); iter.Next()) {
       nsAutoPtr<DecryptPromiseRequestHolder>& holder = iter.Data();
       holder->DisconnectIfExists();
       iter.Remove();
     }
-    nsresult rv = mDecoder->Drain();
-    Unused << NS_WARN_IF(NS_FAILED(rv));
-    return rv;
+    mDecoder->Drain();
   }
 
-  nsresult Shutdown() override {
+  void Shutdown() override {
     MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
     MOZ_ASSERT(!mIsShutdown);
     mIsShutdown = true;
-    nsresult rv = mDecoder->Shutdown();
-    Unused << NS_WARN_IF(NS_FAILED(rv));
+    mDecoder->Shutdown();
     mSamplesWaitingForKey->BreakCycles();
     mSamplesWaitingForKey = nullptr;
     mDecoder = nullptr;
     mProxy = nullptr;
     mCallback = nullptr;
-    return rv;
   }
 
   const char* GetDescriptionName() const override {
     return mDecoder->GetDescriptionName();
   }
 
 private:
 
@@ -173,48 +166,46 @@ public:
                            TaskQueue* aTaskQueue)
    : MediaDataDecoderProxy(Move(aProxyThread), aCallback)
    , mSamplesWaitingForKey(new SamplesWaitingForKey(this, aCallback,
                                                     aTaskQueue, aProxy))
    , mProxy(aProxy)
   {
   }
 
-  nsresult Input(MediaRawData* aSample) override;
-  nsresult Shutdown() override;
+  void Input(MediaRawData* aSample) override;
+  void Shutdown() override;
 
 private:
   RefPtr<SamplesWaitingForKey> mSamplesWaitingForKey;
   RefPtr<CDMProxy> mProxy;
 };
 
-nsresult
+void
 EMEMediaDataDecoderProxy::Input(MediaRawData* aSample)
 {
   if (mSamplesWaitingForKey->WaitIfKeyNotUsable(aSample)) {
-    return NS_OK;
+    return;
   }
 
   nsAutoPtr<MediaRawDataWriter> writer(aSample->CreateWriter());
   mProxy->GetSessionIdsForKeyId(aSample->mCrypto.mKeyId,
                                 writer->mCrypto.mSessionIds);
 
-  return MediaDataDecoderProxy::Input(aSample);
+  MediaDataDecoderProxy::Input(aSample);
 }
 
-nsresult
+void
 EMEMediaDataDecoderProxy::Shutdown()
 {
-  nsresult rv = MediaDataDecoderProxy::Shutdown();
+  MediaDataDecoderProxy::Shutdown();
 
   mSamplesWaitingForKey->BreakCycles();
   mSamplesWaitingForKey = nullptr;
   mProxy = nullptr;
-
-  return rv;
 }
 
 EMEDecoderModule::EMEDecoderModule(CDMProxy* aProxy, PDMFactory* aPDM)
   : mProxy(aProxy)
   , mPDM(aPDM)
 {
 }
 
--- a/dom/media/platforms/agnostic/gmp/GMPAudioDecoder.cpp
+++ b/dom/media/platforms/agnostic/gmp/GMPAudioDecoder.cpp
@@ -234,71 +234,62 @@ GMPAudioDecoder::Init()
   UniquePtr<GetGMPAudioDecoderCallback> callback(new GMPInitDoneCallback(this));
   if (NS_FAILED(mMPS->GetGMPAudioDecoder(mCrashHelper, &tags, GetNodeId(), Move(callback)))) {
     mInitPromise.Reject(MediaDataDecoder::DecoderFailureReason::INIT_ERROR, __func__);
   }
 
   return promise;
 }
 
-nsresult
+void
 GMPAudioDecoder::Input(MediaRawData* aSample)
 {
   MOZ_ASSERT(IsOnGMPThread());
 
   RefPtr<MediaRawData> sample(aSample);
   if (!mGMP) {
     mCallback->Error(MediaDataDecoderError::FATAL_ERROR);
-    return NS_ERROR_FAILURE;
+    return;
   }
 
   mAdapter->SetLastStreamOffset(sample->mOffset);
 
   gmp::GMPAudioSamplesImpl samples(sample, mConfig.mChannels, mConfig.mRate);
   nsresult rv = mGMP->Decode(samples);
   if (NS_FAILED(rv)) {
     mCallback->Error(MediaDataDecoderError::DECODE_ERROR);
-    return rv;
   }
-
-  return NS_OK;
 }
 
-nsresult
+void
 GMPAudioDecoder::Flush()
 {
   MOZ_ASSERT(IsOnGMPThread());
 
   if (!mGMP || NS_FAILED(mGMP->Reset())) {
     // Abort the flush.
     mCallback->FlushComplete();
   }
-
-  return NS_OK;
 }
 
-nsresult
+void
 GMPAudioDecoder::Drain()
 {
   MOZ_ASSERT(IsOnGMPThread());
 
   if (!mGMP || NS_FAILED(mGMP->Drain())) {
     mCallback->DrainComplete();
   }
-
-  return NS_OK;
 }
 
-nsresult
+void
 GMPAudioDecoder::Shutdown()
 {
   mInitPromise.RejectIfExists(MediaDataDecoder::DecoderFailureReason::CANCELED, __func__);
   if (!mGMP) {
-    return NS_ERROR_FAILURE;
+    return;
   }
   // Note this unblocks flush and drain operations waiting for callbacks.
   mGMP->Close();
   mGMP = nullptr;
-
-  return NS_OK;
 }
 
 } // namespace mozilla
--- a/dom/media/platforms/agnostic/gmp/GMPAudioDecoder.h
+++ b/dom/media/platforms/agnostic/gmp/GMPAudioDecoder.h
@@ -60,20 +60,20 @@ struct GMPAudioDecoderParams {
   RefPtr<GMPCrashHelper> mCrashHelper;
 };
 
 class GMPAudioDecoder : public MediaDataDecoder {
 public:
   explicit GMPAudioDecoder(const GMPAudioDecoderParams& aParams);
 
   RefPtr<InitPromise> Init() override;
-  nsresult Input(MediaRawData* aSample) override;
-  nsresult Flush() override;
-  nsresult Drain() override;
-  nsresult Shutdown() override;
+  void Input(MediaRawData* aSample) override;
+  void Flush() override;
+  void Drain() override;
+  void Shutdown() override;
   const char* GetDescriptionName() const override
   {
     return "GMP audio decoder";
   }
 
 protected:
   virtual void InitTags(nsTArray<nsCString>& aTags);
   virtual nsCString GetNodeId();
--- a/dom/media/platforms/agnostic/gmp/GMPVideoDecoder.cpp
+++ b/dom/media/platforms/agnostic/gmp/GMPVideoDecoder.cpp
@@ -308,77 +308,68 @@ GMPVideoDecoder::Init()
   UniquePtr<GetGMPVideoDecoderCallback> callback(new GMPInitDoneCallback(this));
   if (NS_FAILED(mMPS->GetGMPVideoDecoder(mCrashHelper, &tags, GetNodeId(), Move(callback)))) {
     mInitPromise.Reject(MediaDataDecoder::DecoderFailureReason::INIT_ERROR, __func__);
   }
 
   return promise;
 }
 
-nsresult
+void
 GMPVideoDecoder::Input(MediaRawData* aSample)
 {
   MOZ_ASSERT(IsOnGMPThread());
 
   RefPtr<MediaRawData> sample(aSample);
   if (!mGMP) {
     mCallback->Error(MediaDataDecoderError::FATAL_ERROR);
-    return NS_ERROR_FAILURE;
+    return;
   }
 
   mAdapter->SetLastStreamOffset(sample->mOffset);
 
   GMPUniquePtr<GMPVideoEncodedFrame> frame = CreateFrame(sample);
   if (!frame) {
     mCallback->Error(MediaDataDecoderError::FATAL_ERROR);
-    return NS_ERROR_FAILURE;
+    return;
   }
   nsTArray<uint8_t> info; // No codec specific per-frame info to pass.
   nsresult rv = mGMP->Decode(Move(frame), false, info, 0);
   if (NS_FAILED(rv)) {
     mCallback->Error(MediaDataDecoderError::DECODE_ERROR);
-    return rv;
   }
-
-  return NS_OK;
 }
 
-nsresult
+void
 GMPVideoDecoder::Flush()
 {
   MOZ_ASSERT(IsOnGMPThread());
 
   if (!mGMP || NS_FAILED(mGMP->Reset())) {
     // Abort the flush.
     mCallback->FlushComplete();
   }
-
-  return NS_OK;
 }
 
-nsresult
+void
 GMPVideoDecoder::Drain()
 {
   MOZ_ASSERT(IsOnGMPThread());
 
   if (!mGMP || NS_FAILED(mGMP->Drain())) {
     mCallback->DrainComplete();
   }
-
-  return NS_OK;
 }
 
-nsresult
+void
 GMPVideoDecoder::Shutdown()
 {
   mInitPromise.RejectIfExists(MediaDataDecoder::DecoderFailureReason::CANCELED, __func__);
   // Note that this *may* be called from the proxy thread also.
   if (!mGMP) {
-    return NS_ERROR_FAILURE;
+    return;
   }
   // Note this unblocks flush and drain operations waiting for callbacks.
   mGMP->Close();
   mGMP = nullptr;
-
-  return NS_OK;
 }
 
 } // namespace mozilla
--- a/dom/media/platforms/agnostic/gmp/GMPVideoDecoder.h
+++ b/dom/media/platforms/agnostic/gmp/GMPVideoDecoder.h
@@ -65,20 +65,20 @@ struct GMPVideoDecoderParams {
   RefPtr<GMPCrashHelper> mCrashHelper;
 };
 
 class GMPVideoDecoder : public MediaDataDecoder {
 public:
   explicit GMPVideoDecoder(const GMPVideoDecoderParams& aParams);
 
   RefPtr<InitPromise> Init() override;
-  nsresult Input(MediaRawData* aSample) override;
-  nsresult Flush() override;
-  nsresult Drain() override;
-  nsresult Shutdown() override;
+  void Input(MediaRawData* aSample) override;
+  void Flush() override;
+  void Drain() override;
+  void Shutdown() override;
   const char* GetDescriptionName() const override
   {
     return "GMP video decoder";
   }
 
 protected:
   virtual void InitTags(nsTArray<nsCString>& aTags);
   virtual nsCString GetNodeId();
--- a/dom/media/platforms/agnostic/gmp/MediaDataDecoderProxy.cpp
+++ b/dom/media/platforms/agnostic/gmp/MediaDataDecoderProxy.cpp
@@ -33,66 +33,59 @@ RefPtr<MediaDataDecoder::InitPromise>
 MediaDataDecoderProxy::Init()
 {
   MOZ_ASSERT(!mIsShutdown);
 
   return InvokeAsync(mProxyThread, this, __func__,
                      &MediaDataDecoderProxy::InternalInit);
 }
 
-nsresult
+void
 MediaDataDecoderProxy::Input(MediaRawData* aSample)
 {
   MOZ_ASSERT(!IsOnProxyThread());
   MOZ_ASSERT(!mIsShutdown);
 
   nsCOMPtr<nsIRunnable> task(new InputTask(mProxyDecoder, aSample));
   mProxyThread->Dispatch(task.forget());
-
-  return NS_OK;
 }
 
-nsresult
+void
 MediaDataDecoderProxy::Flush()
 {
   MOZ_ASSERT(!IsOnProxyThread());
   MOZ_ASSERT(!mIsShutdown);
 
   mFlushComplete.Set(false);
 
   mProxyThread->Dispatch(NewRunnableMethod(mProxyDecoder, &MediaDataDecoder::Flush));
 
   mFlushComplete.WaitUntil(true);
-
-  return NS_OK;
 }
 
-nsresult
+void
 MediaDataDecoderProxy::Drain()
 {
   MOZ_ASSERT(!IsOnProxyThread());
   MOZ_ASSERT(!mIsShutdown);
 
   mProxyThread->Dispatch(NewRunnableMethod(mProxyDecoder, &MediaDataDecoder::Drain));
-  return NS_OK;
 }
 
-nsresult
+void
 MediaDataDecoderProxy::Shutdown()
 {
   // Note that this *may* be called from the proxy thread also.
   MOZ_ASSERT(!mIsShutdown);
 #if defined(DEBUG)
   mIsShutdown = true;
 #endif
-  nsresult rv = mProxyThread->AsXPCOMThread()->Dispatch(NewRunnableMethod(mProxyDecoder,
-                                                                          &MediaDataDecoder::Shutdown),
-                                                        NS_DISPATCH_SYNC);
-  NS_ENSURE_SUCCESS(rv, rv);
-  return NS_OK;
+  mProxyThread->AsXPCOMThread()->Dispatch(NewRunnableMethod(mProxyDecoder,
+                                                            &MediaDataDecoder::Shutdown),
+                                          NS_DISPATCH_SYNC);
 }
 
 void
 MediaDataDecoderProxy::FlushComplete()
 {
   mFlushComplete.Set(true);
 }
 
--- a/dom/media/platforms/agnostic/gmp/MediaDataDecoderProxy.h
+++ b/dom/media/platforms/agnostic/gmp/MediaDataDecoderProxy.h
@@ -135,20 +135,20 @@ public:
     mProxyDecoder = aProxyDecoder;
   }
 
   // These are called from the decoder thread pool.
   // Init and Shutdown run synchronously on the proxy thread, all others are
   // asynchronously and responded to via the MediaDataDecoderCallback.
   // Note: the nsresults returned by the proxied decoder are lost.
   RefPtr<InitPromise> Init() override;
-  nsresult Input(MediaRawData* aSample) override;
-  nsresult Flush() override;
-  nsresult Drain() override;
-  nsresult Shutdown() override;
+  void Input(MediaRawData* aSample) override;
+  void Flush() override;
+  void Drain() override;
+  void Shutdown() override;
 
   const char* GetDescriptionName() const override
   {
     return "GMP proxy data decoder";
   }
 
   // Called by MediaDataDecoderCallbackProxy.
   void FlushComplete();
--- a/dom/media/platforms/android/MediaCodecDataDecoder.cpp
+++ b/dom/media/platforms/android/MediaCodecDataDecoder.cpp
@@ -84,21 +84,16 @@ public:
 
     return InitPromise::CreateAndResolve(TrackInfo::kVideoTrack, __func__);
   }
 
   void Cleanup() override
   {
   }
 
-  nsresult Input(MediaRawData* aSample) override
-  {
-    return MediaCodecDataDecoder::Input(aSample);
-  }
-
   nsresult PostOutput(BufferInfo::Param aInfo, MediaFormat::Param aFormat,
                       const TimeUnit& aDuration) override
   {
     RefPtr<layers::Image> img =
       new SurfaceTextureImage(mSurfaceTexture.get(), mConfig.mDisplay,
                               gl::OriginPos::BottomLeft);
 
     nsresult rv;
@@ -613,71 +608,65 @@ void
 MediaCodecDataDecoder::ClearQueue()
 {
   mMonitor.AssertCurrentThreadOwns();
 
   mQueue.clear();
   mDurations.clear();
 }
 
-nsresult
+void
 MediaCodecDataDecoder::Input(MediaRawData* aSample)
 {
   MonitorAutoLock lock(mMonitor);
   mQueue.push_back(aSample);
   lock.NotifyAll();
-
-  return NS_OK;
 }
 
 nsresult
 MediaCodecDataDecoder::ResetInputBuffers()
 {
   return mDecoder->GetInputBuffers(ReturnTo(&mInputBuffers));
 }
 
 nsresult
 MediaCodecDataDecoder::ResetOutputBuffers()
 {
   return mDecoder->GetOutputBuffers(ReturnTo(&mOutputBuffers));
 }
 
-nsresult
+void
 MediaCodecDataDecoder::Flush()
 {
   MonitorAutoLock lock(mMonitor);
   if (!SetState(ModuleState::kFlushing)) {
-    return NS_OK;
+    return;
   }
   lock.Notify();
 
   while (mState == ModuleState::kFlushing) {
     lock.Wait();
   }
-
-  return NS_OK;
 }
 
-nsresult
+void
 MediaCodecDataDecoder::Drain()
 {
   MonitorAutoLock lock(mMonitor);
   if (mState == ModuleState::kDrainDecoder ||
       mState == ModuleState::kDrainQueue) {
-    return NS_OK;
+    return;
   }
 
   SetState(ModuleState::kDrainQueue);
   lock.Notify();
-
-  return NS_OK;
 }
 
 
-nsresult
+void
 MediaCodecDataDecoder::Shutdown()
 {
   MonitorAutoLock lock(mMonitor);
 
   SetState(ModuleState::kStopping);
   lock.Notify();
 
   while (mThread && mState != ModuleState::kShutdown) {
@@ -689,13 +678,11 @@ MediaCodecDataDecoder::Shutdown()
     mThread = nullptr;
   }
 
   if (mDecoder) {
     mDecoder->Stop();
     mDecoder->Release();
     mDecoder = nullptr;
   }
-
-  return NS_OK;
 }
 
 } // mozilla
--- a/dom/media/platforms/android/MediaCodecDataDecoder.h
+++ b/dom/media/platforms/android/MediaCodecDataDecoder.h
@@ -28,20 +28,20 @@ public:
   static MediaDataDecoder* CreateVideoDecoder(const VideoInfo& aConfig,
                                               java::sdk::MediaFormat::Param aFormat,
                                               MediaDataDecoderCallback* aCallback,
                                               layers::ImageContainer* aImageContainer);
 
   virtual ~MediaCodecDataDecoder();
 
   RefPtr<MediaDataDecoder::InitPromise> Init() override;
-  nsresult Flush() override;
-  nsresult Drain() override;
-  nsresult Shutdown() override;
-  nsresult Input(MediaRawData* aSample) override;
+  void Flush() override;
+  void Drain() override;
+  void Shutdown() override;
+  void Input(MediaRawData* aSample) override;
   const char* GetDescriptionName() const override
   {
     return "Android MediaCodec decoder";
   }
 
 protected:
   enum class ModuleState : uint8_t {
     kDecoding = 0,
--- a/dom/media/platforms/android/RemoteDataDecoder.cpp
+++ b/dom/media/platforms/android/RemoteDataDecoder.cpp
@@ -211,38 +211,32 @@ public:
       return InitPromise::CreateAndReject(DecoderFailureReason::INIT_ERROR, __func__);
     }
 
     mInputDurations.Clear();
 
     return InitPromise::CreateAndResolve(TrackInfo::kVideoTrack, __func__);
   }
 
-  nsresult Flush() override
+  void Flush() override
   {
     mInputDurations.Clear();
-    return RemoteDataDecoder::Flush();
+    RemoteDataDecoder::Flush();
   }
 
-  nsresult Drain() override
+  void Drain() override
   {
-    nsresult res = RemoteDataDecoder::Drain();
-    NS_ENSURE_SUCCESS(res, res);
-
+    RemoteDataDecoder::Drain();
     mInputDurations.Put(0);
-    return NS_OK;
   }
 
-  nsresult Input(MediaRawData* aSample) override
+  void Input(MediaRawData* aSample) override
   {
-    nsresult res = RemoteDataDecoder::Input(aSample);
-    NS_ENSURE_SUCCESS(res, res);
-
+    RemoteDataDecoder::Input(aSample);
     mInputDurations.Put(aSample->mDuration);
-    return NS_OK;
   }
 
 private:
   class DurationQueue {
   public:
 
     void Clear()
     {
@@ -427,70 +421,67 @@ RemoteDataDecoder::RemoteDataDecoder(Med
                                      MediaDataDecoderCallback* aCallback)
   : mType(aType)
   , mMimeType(aMimeType)
   , mFormat(aFormat)
   , mCallback(aCallback)
 {
 }
 
-nsresult
+void
 RemoteDataDecoder::Flush()
 {
   mJavaDecoder->Flush();
-  return NS_OK;
 }
 
-nsresult
+void
 RemoteDataDecoder::Drain()
 {
   BufferInfo::LocalRef bufferInfo;
   nsresult rv = BufferInfo::New(&bufferInfo);
-  NS_ENSURE_SUCCESS(rv, rv);
+  NS_ENSURE_SUCCESS_VOID(rv);
   bufferInfo->Set(0, 0, -1, MediaCodec::BUFFER_FLAG_END_OF_STREAM);
 
   mJavaDecoder->Input(nullptr, bufferInfo);
-  return NS_OK;
 }
 
-nsresult
+void
 RemoteDataDecoder::Shutdown()
 {
   LOG("");
   MOZ_ASSERT(mJavaDecoder && mJavaCallbacks);
 
   mJavaDecoder->Release();
   mJavaDecoder = nullptr;
 
   JavaCallbacksSupport::GetNative(mJavaCallbacks)->Cancel();
   mJavaCallbacks = nullptr;
 
   mFormat = nullptr;
-
-  return NS_OK;
 }
 
-nsresult
+void
 RemoteDataDecoder::Input(MediaRawData* aSample)
 {
   MOZ_ASSERT(aSample != nullptr);
 
   JNIEnv* const env = jni::GetEnvForThread();
 
   // Copy sample data into Java byte array.
   uint32_t length = aSample->Size();
   jbyteArray data = env->NewByteArray(length);
   env->SetByteArrayRegion(data, 0, length, reinterpret_cast<const jbyte*>(aSample->Data()));
 
   jni::ByteArray::LocalRef bytes(env);
   bytes = jni::Object::LocalRef::Adopt(env, data);
 
   BufferInfo::LocalRef bufferInfo;
   nsresult rv = BufferInfo::New(&bufferInfo);
-  NS_ENSURE_SUCCESS(rv, rv);
+  if (NS_FAILED(rv)) {
+    mCallback->Error(MediaDataDecoderError::FATAL_ERROR);
+    return;
+  }
   bufferInfo->Set(0, aSample->Size(), aSample->mTime, 0);
 
   mJavaDecoder->Input(bytes, bufferInfo);
-
-  return NS_OK;
 }
 
 } // mozilla
--- a/dom/media/platforms/android/RemoteDataDecoder.h
+++ b/dom/media/platforms/android/RemoteDataDecoder.h
@@ -26,20 +26,20 @@ public:
 
   static MediaDataDecoder* CreateVideoDecoder(const VideoInfo& aConfig,
                                               java::sdk::MediaFormat::Param aFormat,
                                               MediaDataDecoderCallback* aCallback,
                                               layers::ImageContainer* aImageContainer);
 
   virtual ~RemoteDataDecoder() {}
 
-  nsresult Flush() override;
-  nsresult Drain() override;
-  nsresult Shutdown() override;
-  nsresult Input(MediaRawData* aSample) override;
+  void Flush() override;
+  void Drain() override;
+  void Shutdown() override;
+  void Input(MediaRawData* aSample) override;
   const char* GetDescriptionName() const override
   {
     return "android remote decoder";
   }
 
 protected:
   RemoteDataDecoder(MediaData::Type aType,
                     const nsACString& aMimeType,
--- a/dom/media/platforms/apple/AppleATDecoder.cpp
+++ b/dom/media/platforms/apple/AppleATDecoder.cpp
@@ -58,17 +58,17 @@ AppleATDecoder::Init()
   if (!mFormatID) {
     NS_ERROR("Non recognised format");
     return InitPromise::CreateAndReject(DecoderFailureReason::INIT_ERROR, __func__);
   }
 
   return InitPromise::CreateAndResolve(TrackType::kAudioTrack, __func__);
 }
 
-nsresult
+void
 AppleATDecoder::Input(MediaRawData* aSample)
 {
   MOZ_ASSERT(mCallback->OnReaderTaskQueue());
   LOG("mp4 input sample %p %lld us %lld pts%s %llu bytes audio",
       aSample,
       aSample->mDuration,
       aSample->mTime,
       aSample->mKeyframe ? " keyframe" : "",
@@ -76,77 +76,73 @@ AppleATDecoder::Input(MediaRawData* aSam
 
   // Queue a task to perform the actual decoding on a separate thread.
   nsCOMPtr<nsIRunnable> runnable =
       NewRunnableMethod<RefPtr<MediaRawData>>(
         this,
         &AppleATDecoder::SubmitSample,
         RefPtr<MediaRawData>(aSample));
   mTaskQueue->Dispatch(runnable.forget());
-
-  return NS_OK;
 }
 
 void
 AppleATDecoder::ProcessFlush()
 {
   MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
   mQueuedSamples.Clear();
   OSStatus rv = AudioConverterReset(mConverter);
   if (rv) {
     LOG("Error %d resetting AudioConverter", rv);
   }
 }
 
-nsresult
+void
 AppleATDecoder::Flush()
 {
   MOZ_ASSERT(mCallback->OnReaderTaskQueue());
   LOG("Flushing AudioToolbox AAC decoder");
   mIsFlushing = true;
   nsCOMPtr<nsIRunnable> runnable =
     NewRunnableMethod(this, &AppleATDecoder::ProcessFlush);
   SyncRunnable::DispatchToThread(mTaskQueue, runnable);
   mIsFlushing = false;
-  return NS_OK;
 }
 
-nsresult
+void
 AppleATDecoder::Drain()
 {
   MOZ_ASSERT(mCallback->OnReaderTaskQueue());
   LOG("Draining AudioToolbox AAC decoder");
   mTaskQueue->AwaitIdle();
   mCallback->DrainComplete();
-  return Flush();
+  Flush();
 }
 
-nsresult
+void
 AppleATDecoder::Shutdown()
 {
   MOZ_ASSERT(mCallback->OnReaderTaskQueue());
 
   LOG("Shutdown: Apple AudioToolbox AAC decoder");
   mQueuedSamples.Clear();
   OSStatus rv = AudioConverterDispose(mConverter);
   if (rv) {
     LOG("error %d disposing of AudioConverter", rv);
-    return NS_ERROR_FAILURE;
+    return;
   }
   mConverter = nullptr;
 
   if (mStream) {
     rv = AudioFileStreamClose(mStream);
     if (rv) {
       LOG("error %d disposing of AudioFileStream", rv);
-      return NS_ERROR_FAILURE;
+      return;
     }
     mStream = nullptr;
   }
-  return NS_OK;
 }
 
 struct PassthroughUserData {
   UInt32 mChannels;
   UInt32 mDataSize;
   const void* mData;
   AudioStreamPacketDescription mPacket;
 };
--- a/dom/media/platforms/apple/AppleATDecoder.h
+++ b/dom/media/platforms/apple/AppleATDecoder.h
@@ -22,20 +22,20 @@ class MediaDataDecoderCallback;
 class AppleATDecoder : public MediaDataDecoder {
 public:
   AppleATDecoder(const AudioInfo& aConfig,
                  TaskQueue* aTaskQueue,
                  MediaDataDecoderCallback* aCallback);
   virtual ~AppleATDecoder();
 
   RefPtr<InitPromise> Init() override;
-  nsresult Input(MediaRawData* aSample) override;
-  nsresult Flush() override;
-  nsresult Drain() override;
-  nsresult Shutdown() override;
+  void Input(MediaRawData* aSample) override;
+  void Flush() override;
+  void Drain() override;
+  void Shutdown() override;
 
   const char* GetDescriptionName() const override
   {
     return "apple CoreMedia decoder";
   }
 
   // Callbacks also need access to the config.
   const AudioInfo& mConfig;
--- a/dom/media/platforms/apple/AppleVTDecoder.cpp
+++ b/dom/media/platforms/apple/AppleVTDecoder.cpp
@@ -69,71 +69,66 @@ AppleVTDecoder::Init()
 
   if (NS_SUCCEEDED(rv)) {
     return InitPromise::CreateAndResolve(TrackType::kVideoTrack, __func__);
   }
 
   return InitPromise::CreateAndReject(DecoderFailureReason::INIT_ERROR, __func__);
 }
 
-nsresult
+void
 AppleVTDecoder::Input(MediaRawData* aSample)
 {
   MOZ_ASSERT(mCallback->OnReaderTaskQueue());
 
   LOG("mp4 input sample %p pts %lld duration %lld us%s %d bytes",
       aSample,
       aSample->mTime,
       aSample->mDuration,
       aSample->mKeyframe ? " keyframe" : "",
       aSample->Size());
 
   mTaskQueue->Dispatch(NewRunnableMethod<RefPtr<MediaRawData>>(
     this, &AppleVTDecoder::ProcessDecode, aSample));
-  return NS_OK;
 }
 
-nsresult
+void
 AppleVTDecoder::Flush()
 {
   MOZ_ASSERT(mCallback->OnReaderTaskQueue());
   mIsFlushing = true;
   nsCOMPtr<nsIRunnable> runnable =
     NewRunnableMethod(this, &AppleVTDecoder::ProcessFlush);
   SyncRunnable::DispatchToThread(mTaskQueue, runnable);
   mIsFlushing = false;
 
   mSeekTargetThreshold.reset();
-
-  return NS_OK;
 }
 
-nsresult
+void
 AppleVTDecoder::Drain()
 {
   MOZ_ASSERT(mCallback->OnReaderTaskQueue());
   nsCOMPtr<nsIRunnable> runnable =
     NewRunnableMethod(this, &AppleVTDecoder::ProcessDrain);
   mTaskQueue->Dispatch(runnable.forget());
-  return NS_OK;
 }
 
-nsresult
+void
 AppleVTDecoder::Shutdown()
 {
   MOZ_DIAGNOSTIC_ASSERT(!mIsShutDown);
   mIsShutDown = true;
   if (mTaskQueue) {
     nsCOMPtr<nsIRunnable> runnable =
       NewRunnableMethod(this, &AppleVTDecoder::ProcessShutdown);
     mTaskQueue->Dispatch(runnable.forget());
   } else {
     ProcessShutdown();
   }
-  return NS_OK;
 }
 
 nsresult
 AppleVTDecoder::ProcessDecode(MediaRawData* aSample)
 {
   AssertOnTaskQueueThread();
 
   if (mIsFlushing) {
--- a/dom/media/platforms/apple/AppleVTDecoder.h
+++ b/dom/media/platforms/apple/AppleVTDecoder.h
@@ -38,20 +38,20 @@ public:
       , duration(media::TimeUnit::FromMicroseconds(aSample.mDuration))
       , byte_offset(aSample.mOffset)
       , is_sync_point(aSample.mKeyframe)
     {
     }
   };
 
   RefPtr<InitPromise> Init() override;
-  nsresult Input(MediaRawData* aSample) override;
-  nsresult Flush() override;
-  nsresult Drain() override;
-  nsresult Shutdown() override;
+  void Input(MediaRawData* aSample) override;
+  void Flush() override;
+  void Drain() override;
+  void Shutdown() override;
   void SetSeekThreshold(const media::TimeUnit& aTime) override;
 
   bool IsHardwareAccelerated(nsACString& aFailureReason) const override
   {
     return mIsHardwareAccelerated;
   }
 
   const char* GetDescriptionName() const override
--- a/dom/media/platforms/ffmpeg/FFmpegDataDecoder.cpp
+++ b/dom/media/platforms/ffmpeg/FFmpegDataDecoder.cpp
@@ -85,27 +85,26 @@ FFmpegDataDecoder<LIBAV_VER>::InitDecode
     mLib->av_freep(&mCodecContext);
     return NS_ERROR_FAILURE;
   }
 
   FFMPEG_LOG("FFmpeg init successful.");
   return NS_OK;
 }
 
-nsresult
+void
 FFmpegDataDecoder<LIBAV_VER>::Shutdown()
 {
   if (mTaskQueue) {
     nsCOMPtr<nsIRunnable> runnable =
       NewRunnableMethod(this, &FFmpegDataDecoder<LIBAV_VER>::ProcessShutdown);
     mTaskQueue->Dispatch(runnable.forget());
   } else {
     ProcessShutdown();
   }
-  return NS_OK;
 }
 
 void
 FFmpegDataDecoder<LIBAV_VER>::ProcessDecode(MediaRawData* aSample)
 {
   MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
   if (mIsFlushing) {
     return;
@@ -121,44 +120,41 @@ FFmpegDataDecoder<LIBAV_VER>::ProcessDec
     case DecodeResult::DECODE_FRAME:
       mCallback->InputExhausted();
       break;
     default:
       break;
   }
 }
 
-nsresult
+void
 FFmpegDataDecoder<LIBAV_VER>::Input(MediaRawData* aSample)
 {
   mTaskQueue->Dispatch(NewRunnableMethod<RefPtr<MediaRawData>>(
     this, &FFmpegDataDecoder::ProcessDecode, aSample));
-  return NS_OK;
 }
 
-nsresult
+void
 FFmpegDataDecoder<LIBAV_VER>::Flush()
 {
   MOZ_ASSERT(mCallback->OnReaderTaskQueue());
   mIsFlushing = true;
   nsCOMPtr<nsIRunnable> runnable =
     NewRunnableMethod(this, &FFmpegDataDecoder<LIBAV_VER>::ProcessFlush);
   SyncRunnable::DispatchToThread(mTaskQueue, runnable);
   mIsFlushing = false;
-  return NS_OK;
 }
 
-nsresult
+void
 FFmpegDataDecoder<LIBAV_VER>::Drain()
 {
   MOZ_ASSERT(mCallback->OnReaderTaskQueue());
   nsCOMPtr<nsIRunnable> runnable =
     NewRunnableMethod(this, &FFmpegDataDecoder<LIBAV_VER>::ProcessDrain);
   mTaskQueue->Dispatch(runnable.forget());
-  return NS_OK;
 }
 
 void
 FFmpegDataDecoder<LIBAV_VER>::ProcessFlush()
 {
   MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
   if (mCodecContext) {
     mLib->avcodec_flush_buffers(mCodecContext);
--- a/dom/media/platforms/ffmpeg/FFmpegDataDecoder.h
+++ b/dom/media/platforms/ffmpeg/FFmpegDataDecoder.h
@@ -27,20 +27,20 @@ public:
   FFmpegDataDecoder(FFmpegLibWrapper* aLib, TaskQueue* aTaskQueue,
                     MediaDataDecoderCallback* aCallback,
                     AVCodecID aCodecID);
   virtual ~FFmpegDataDecoder();
 
   static bool Link();
 
   RefPtr<InitPromise> Init() override = 0;
-  nsresult Input(MediaRawData* aSample) override;
-  nsresult Flush() override;
-  nsresult Drain() override;
-  nsresult Shutdown() override;
+  void Input(MediaRawData* aSample) override;
+  void Flush() override;
+  void Drain() override;
+  void Shutdown() override;
 
   static AVCodec* FindAVCodec(FFmpegLibWrapper* aLib, AVCodecID aCodec);
 
 protected:
   enum DecodeResult {
     DECODE_FRAME,
     DECODE_NO_FRAME,
     DECODE_ERROR,
--- a/dom/media/platforms/gonk/GonkMediaDataDecoder.cpp
+++ b/dom/media/platforms/gonk/GonkMediaDataDecoder.cpp
@@ -343,41 +343,38 @@ GonkMediaDataDecoder::~GonkMediaDataDeco
 }
 
 RefPtr<MediaDataDecoder::InitPromise>
 GonkMediaDataDecoder::Init()
 {
   return mManager->Init();
 }
 
-nsresult
+void
 GonkMediaDataDecoder::Shutdown()
 {
-  nsresult rv = mManager->Shutdown();
+  mManager->Shutdown();
 
   // Because codec allocated runnable and init promise is at reader TaskQueue,
   // so manager needs to be destroyed at reader TaskQueue to prevent racing.
   mManager = nullptr;
-  return rv;
 }
 
 // Inserts data into the decoder's pipeline.
-nsresult
+void
 GonkMediaDataDecoder::Input(MediaRawData* aSample)
 {
   mManager->Input(aSample);
-  return NS_OK;
 }
 
-nsresult
+void
 GonkMediaDataDecoder::Flush()
 {
-  return mManager->Flush();
+  mManager->Flush();
 }
 
-nsresult
+void
 GonkMediaDataDecoder::Drain()
 {
   mManager->Input(nullptr);
-  return NS_OK;
 }
 
 } // namespace mozilla
--- a/dom/media/platforms/gonk/GonkMediaDataDecoder.h
+++ b/dom/media/platforms/gonk/GonkMediaDataDecoder.h
@@ -187,23 +187,23 @@ class GonkMediaDataDecoder : public Medi
 public:
   GonkMediaDataDecoder(GonkDecoderManager* aDecoderManager,
                        MediaDataDecoderCallback* aCallback);
 
   ~GonkMediaDataDecoder();
 
   RefPtr<InitPromise> Init() override;
 
-  nsresult Input(MediaRawData* aSample) override;
+  void Input(MediaRawData* aSample) override;
 
-  nsresult Flush() override;
+  void Flush() override;
 
-  nsresult Drain() override;
+  void Drain() override;
 
-  nsresult Shutdown() override;
+  void Shutdown() override;
 
   const char* GetDescriptionName() const override
   {
     return "gonk decoder";
   }
 
 private:
 
--- a/dom/media/platforms/omx/OmxDataDecoder.cpp
+++ b/dom/media/platforms/omx/OmxDataDecoder.cpp
@@ -170,17 +170,17 @@ OmxDataDecoder::Init()
       },
       [self] () {
         self->RejectInitPromise(DecoderFailureReason::INIT_ERROR, __func__);
       });
 
   return p;
 }
 
-nsresult
+void
 OmxDataDecoder::Input(MediaRawData* aSample)
 {
   LOG("sample %p", aSample);
   MOZ_ASSERT(mInitPromise.IsEmpty());
 
   RefPtr<OmxDataDecoder> self = this;
   RefPtr<MediaRawData> sample = aSample;
 
@@ -190,51 +190,45 @@ OmxDataDecoder::Input(MediaRawData* aSam
 
       // Start to fill/empty buffers.
       if (self->mOmxState == OMX_StateIdle ||
           self->mOmxState == OMX_StateExecuting) {
         self->FillAndEmptyBuffers();
       }
     });
   mOmxTaskQueue->Dispatch(r.forget());
-
-  return NS_OK;
 }
 
-nsresult
+void
 OmxDataDecoder::Flush()
 {
   LOG("");
 
   mFlushing = true;
 
   mOmxTaskQueue->Dispatch(NewRunnableMethod(this, &OmxDataDecoder::DoFlush));
 
   // According to the definition of Flush() in PDM:
   // "the decoder must be ready to accept new input for decoding".
   // So it needs to wait for the Omx to complete the flush command.
   MonitorAutoLock lock(mMonitor);
   while (mFlushing) {
     lock.Wait();
   }
-
-  return NS_OK;
 }
 
-nsresult
+void
 OmxDataDecoder::Drain()
 {
   LOG("");
 
   mOmxTaskQueue->Dispatch(NewRunnableMethod(this, &OmxDataDecoder::SendEosBuffer));
-
-  return NS_OK;
 }
 
-nsresult
+void
 OmxDataDecoder::Shutdown()
 {
   LOG("");
 
   mShuttingDown = true;
 
   mOmxTaskQueue->Dispatch(NewRunnableMethod(this, &OmxDataDecoder::DoAsyncShutdown));
 
@@ -245,18 +239,16 @@ OmxDataDecoder::Shutdown()
     MonitorAutoLock lock(mMonitor);
     while (mShuttingDown) {
       lock.Wait();
     }
   }
 
   mOmxTaskQueue->BeginShutdown();
   mOmxTaskQueue->AwaitShutdownAndIdle();
-
-  return NS_OK;
 }
 
 void
 OmxDataDecoder::DoAsyncShutdown()
 {
   LOG("");
   MOZ_ASSERT(mOmxTaskQueue->IsCurrentThreadIn());
   MOZ_ASSERT(!mFlushing);
--- a/dom/media/platforms/omx/OmxDataDecoder.h
+++ b/dom/media/platforms/omx/OmxDataDecoder.h
@@ -61,23 +61,23 @@ protected:
 
 public:
   OmxDataDecoder(const TrackInfo& aTrackInfo,
                  MediaDataDecoderCallback* aCallback,
                  layers::ImageContainer* aImageContainer);
 
   RefPtr<InitPromise> Init() override;
 
-  nsresult Input(MediaRawData* aSample) override;
+  void Input(MediaRawData* aSample) override;
 
-  nsresult Flush() override;
+  void Flush() override;
 
-  nsresult Drain() override;
+  void Drain() override;
 
-  nsresult Shutdown() override;
+  void Shutdown() override;
 
   const char* GetDescriptionName() const override
   {
     return "omx decoder";
   }
 
   // Return true if event is handled.
   bool Event(OMX_EVENTTYPE aEvent, OMX_U32 aData1, OMX_U32 aData2);
--- a/dom/media/platforms/wmf/WMFMediaDataDecoder.cpp
+++ b/dom/media/platforms/wmf/WMFMediaDataDecoder.cpp
@@ -67,56 +67,54 @@ SendTelemetry(unsigned long hr)
 
   nsCOMPtr<nsIRunnable> runnable = NS_NewRunnableFunction(
     [sample] {
       Telemetry::Accumulate(Telemetry::MEDIA_WMF_DECODE_ERROR, sample);
     });
   NS_DispatchToMainThread(runnable);
 }
 
-nsresult
+void
 WMFMediaDataDecoder::Shutdown()
 {
   MOZ_DIAGNOSTIC_ASSERT(!mIsShutDown);
 
   if (mTaskQueue) {
     mTaskQueue->Dispatch(NewRunnableMethod(this, &WMFMediaDataDecoder::ProcessShutdown));
   } else {
     ProcessShutdown();
   }
   mIsShutDown = true;
-  return NS_OK;
 }
 
 void
 WMFMediaDataDecoder::ProcessShutdown()
 {
   if (mMFTManager) {
     mMFTManager->Shutdown();
     mMFTManager = nullptr;
     if (!mRecordedError && mHasSuccessfulOutput) {
       SendTelemetry(S_OK);
     }
   }
 }
 
 // Inserts data into the decoder's pipeline.
-nsresult
+void
 WMFMediaDataDecoder::Input(MediaRawData* aSample)
 {
   MOZ_ASSERT(mCallback->OnReaderTaskQueue());
   MOZ_DIAGNOSTIC_ASSERT(!mIsShutDown);
 
   nsCOMPtr<nsIRunnable> runnable =
     NewRunnableMethod<RefPtr<MediaRawData>>(
       this,
       &WMFMediaDataDecoder::ProcessDecode,
       RefPtr<MediaRawData>(aSample));
   mTaskQueue->Dispatch(runnable.forget());
-  return NS_OK;
 }
 
 void
 WMFMediaDataDecoder::ProcessDecode(MediaRawData* aSample)
 {
   if (mIsFlushing) {
     // Skip sample, to be released by runnable.
     return;
@@ -163,72 +161,68 @@ WMFMediaDataDecoder::ProcessOutput()
 void
 WMFMediaDataDecoder::ProcessFlush()
 {
   if (mMFTManager) {
     mMFTManager->Flush();
   }
 }
 
-nsresult
+void
 WMFMediaDataDecoder::Flush()
 {
   MOZ_ASSERT(mCallback->OnReaderTaskQueue());
   MOZ_DIAGNOSTIC_ASSERT(!mIsShutDown);
 
   mIsFlushing = true;
   nsCOMPtr<nsIRunnable> runnable =
     NewRunnableMethod(this, &WMFMediaDataDecoder::ProcessFlush);
   SyncRunnable::DispatchToThread(mTaskQueue, runnable);
   mIsFlushing = false;
-  return NS_OK;
 }
 
 void
 WMFMediaDataDecoder::ProcessDrain()
 {
   if (!mIsFlushing && mMFTManager) {
     // Order the decoder to drain...
     mMFTManager->Drain();
     // Then extract all available output.
     ProcessOutput();
   }
   mCallback->DrainComplete();
 }
 
-nsresult
+void
 WMFMediaDataDecoder::Drain()
 {
   MOZ_ASSERT(mCallback->OnReaderTaskQueue());
   MOZ_DIAGNOSTIC_ASSERT(!mIsShutDown);
 
   mTaskQueue->Dispatch(NewRunnableMethod(this, &WMFMediaDataDecoder::ProcessDrain));
-  return NS_OK;
 }
 
 bool
 WMFMediaDataDecoder::IsHardwareAccelerated(nsACString& aFailureReason) const {
   MOZ_ASSERT(!mIsShutDown);
 
   return mMFTManager && mMFTManager->IsHardwareAccelerated(aFailureReason);
 }
 
-nsresult
+void
 WMFMediaDataDecoder::ConfigurationChanged(const TrackInfo& aConfig)
 {
   MOZ_ASSERT(mCallback->OnReaderTaskQueue());
 
   nsCOMPtr<nsIRunnable> runnable =
     NewRunnableMethod<UniquePtr<TrackInfo>&&>(
     this,
     &WMFMediaDataDecoder::ProcessConfigurationChanged,
     aConfig.Clone());
   mTaskQueue->Dispatch(runnable.forget());
-  return NS_OK;
-
 }
 
 void
 WMFMediaDataDecoder::ProcessConfigurationChanged(UniquePtr<TrackInfo>&& aConfig)
 {
   if (mMFTManager) {
     mMFTManager->ConfigurationChanged(*aConfig);
   }
--- a/dom/media/platforms/wmf/WMFMediaDataDecoder.h
+++ b/dom/media/platforms/wmf/WMFMediaDataDecoder.h
@@ -81,27 +81,27 @@ class WMFMediaDataDecoder : public Media
 public:
   WMFMediaDataDecoder(MFTManager* aOutputSource,
                       TaskQueue* aTaskQueue,
                       MediaDataDecoderCallback* aCallback);
   ~WMFMediaDataDecoder();
 
   RefPtr<MediaDataDecoder::InitPromise> Init() override;
 
-  nsresult Input(MediaRawData* aSample);
+  void Input(MediaRawData* aSample);
 
-  nsresult Flush() override;
+  void Flush() override;
 
-  nsresult Drain() override;
+  void Drain() override;
 
-  nsresult Shutdown() override;
+  void Shutdown() override;
 
   bool IsHardwareAccelerated(nsACString& aFailureReason) const override;
 
-  nsresult ConfigurationChanged(const TrackInfo& aConfig) override;
+  void ConfigurationChanged(const TrackInfo& aConfig) override;
 
   const char* GetDescriptionName() const override
   {
     return mMFTManager ? mMFTManager->GetDescriptionName() : "";
   }
 
   virtual void SetSeekThreshold(const media::TimeUnit& aTime) override;
 
--- a/dom/media/platforms/wrappers/FuzzingWrapper.cpp
+++ b/dom/media/platforms/wrappers/FuzzingWrapper.cpp
@@ -34,73 +34,71 @@ DecoderFuzzingWrapper::~DecoderFuzzingWr
 RefPtr<MediaDataDecoder::InitPromise>
 DecoderFuzzingWrapper::Init()
 {
   DFW_LOGV("");
   MOZ_ASSERT(mDecoder);
   return mDecoder->Init();
 }
 
-nsresult
+void
 DecoderFuzzingWrapper::Input(MediaRawData* aData)
 {
   DFW_LOGV("aData.mTime=%lld", aData->mTime);
   MOZ_ASSERT(mDecoder);
-  return mDecoder->Input(aData);
+  mDecoder->Input(aData);
 }
 
-nsresult
+void
 DecoderFuzzingWrapper::Flush()
 {
   DFW_LOGV("Calling mDecoder[%p]->Flush()", mDecoder.get());
   MOZ_ASSERT(mDecoder);
   // Flush may output some frames (though unlikely).
   // Flush may block a bit, it's ok if we output some frames in the meantime.
-  nsresult result = mDecoder->Flush();
-  DFW_LOGV("mDecoder[%p]->Flush() -> result=%u", mDecoder.get(), uint32_t(result));
+  mDecoder->Flush();
+  DFW_LOGV("mDecoder[%p]->Flush()", mDecoder.get());
   // Clear any delayed output we may have.
   mCallbackWrapper->ClearDelayedOutput();
-  return result;
 }
 
-nsresult
+void
 DecoderFuzzingWrapper::Drain()
 {
   DFW_LOGV("");
   MOZ_ASSERT(mDecoder);
   // Note: The decoder should callback DrainComplete(), we'll drain the
   // delayed output (if any) then.
-  return mDecoder->Drain();
+  mDecoder->Drain();
 }
 
-nsresult
+void
 DecoderFuzzingWrapper::Shutdown()
 {
   DFW_LOGV("");
   MOZ_ASSERT(mDecoder);
   // Both shutdowns below may block a bit.
-  nsresult result = mDecoder->Shutdown();
+  mDecoder->Shutdown();
   mCallbackWrapper->Shutdown();
-  return result;
 }
 
 bool
 DecoderFuzzingWrapper::IsHardwareAccelerated(nsACString& aFailureReason) const
 {
   DFW_LOGV("");
   MOZ_ASSERT(mDecoder);
   return mDecoder->IsHardwareAccelerated(aFailureReason);
 }
 
-nsresult
+void
 DecoderFuzzingWrapper::ConfigurationChanged(const TrackInfo& aConfig)
 {
   DFW_LOGV("");
   MOZ_ASSERT(mDecoder);
-  return mDecoder->ConfigurationChanged(aConfig);
+  mDecoder->ConfigurationChanged(aConfig);
 }
 
 
 DecoderCallbackFuzzingWrapper::DecoderCallbackFuzzingWrapper(MediaDataDecoderCallback* aCallback)
   : mCallback(aCallback)
   , mDontDelayInputExhausted(false)
   , mDraining(false)
   , mTaskQueue(new TaskQueue(SharedThreadPool::Get(NS_LITERAL_CSTRING("MediaFuzzingWrapper"), 1)))
--- a/dom/media/platforms/wrappers/FuzzingWrapper.h
+++ b/dom/media/platforms/wrappers/FuzzingWrapper.h
@@ -98,22 +98,22 @@ public: // public for the benefit of Dec
 class DecoderFuzzingWrapper : public MediaDataDecoder
 {
 public:
   DecoderFuzzingWrapper(already_AddRefed<MediaDataDecoder> aDecoder,
                         already_AddRefed<DecoderCallbackFuzzingWrapper> aCallbackWrapper);
 
   // MediaDataDecoder implementation.
   RefPtr<InitPromise> Init() override;
-  nsresult Input(MediaRawData* aSample) override;
-  nsresult Flush() override;
-  nsresult Drain() override;
-  nsresult Shutdown() override;
+  void Input(MediaRawData* aSample) override;
+  void Flush() override;
+  void Drain() override;
+  void Shutdown() override;
   bool IsHardwareAccelerated(nsACString& aFailureReason) const override;
-  nsresult ConfigurationChanged(const TrackInfo& aConfig) override;
+  void ConfigurationChanged(const TrackInfo& aConfig) override;
   const char* GetDescriptionName() const override
   {
     return mDecoder->GetDescriptionName();
   }
 
 private:
   virtual ~DecoderFuzzingWrapper();
   RefPtr<MediaDataDecoder> mDecoder;
--- a/dom/media/platforms/wrappers/H264Converter.cpp
+++ b/dom/media/platforms/wrappers/H264Converter.cpp
@@ -44,103 +44,105 @@ H264Converter::Init()
     return mDecoder->Init();
   }
 
   // We haven't been able to initialize a decoder due to a missing SPS/PPS.
   return MediaDataDecoder::InitPromise::CreateAndResolve(
            TrackType::kVideoTrack, __func__);
 }
 
-nsresult
+void
 H264Converter::Input(MediaRawData* aSample)
 {
   if (!mp4_demuxer::AnnexB::ConvertSampleToAVCC(aSample)) {
     // We need AVCC content to be able to later parse the SPS.
     // This is a no-op if the data is already AVCC.
-    return NS_ERROR_FAILURE;
+    mCallback->Error(MediaDataDecoderError::DECODE_ERROR);
+    return;
   }
 
   if (mInitPromiseRequest.Exists()) {
     if (mNeedKeyframe) {
       if (!aSample->mKeyframe) {
         // Frames dropped, we need a new one.
         mCallback->InputExhausted();
-        return NS_OK;
+        return;
       }
       mNeedKeyframe = false;
     }
     mMediaRawSamples.AppendElement(aSample);
-    return NS_OK;
+    return;
   }
 
   nsresult rv;
   if (!mDecoder) {
     // It is not possible to create an AVCC H264 decoder without SPS.
     // As such, creation will fail if the extra_data just extracted doesn't
     // contain a SPS.
     rv = CreateDecoderAndInit(aSample);
     if (rv == NS_ERROR_NOT_INITIALIZED) {
       // We are missing the required SPS to create the decoder.
       // Ignore for the time being, the MediaRawData will be dropped.
       mCallback->InputExhausted();
-      return NS_OK;
+      return;
     }
   } else {
     rv = CheckForSPSChange(aSample);
   }
-  NS_ENSURE_SUCCESS(rv, rv);
+  if (NS_FAILED(rv)) {
+    mCallback->Error(MediaDataDecoderError::DECODE_ERROR);
+    return;
+  }
 
   if (mNeedKeyframe && !aSample->mKeyframe) {
     mCallback->InputExhausted();
-    return NS_OK;
+    return;
   }
 
   if (!mNeedAVCC &&
       !mp4_demuxer::AnnexB::ConvertSampleToAnnexB(aSample)) {
-    return NS_ERROR_FAILURE;
+    mCallback->Error(MediaDataDecoderError::FATAL_ERROR);
+    return;
   }
 
   mNeedKeyframe = false;
 
   aSample->mExtraData = mCurrentConfig.mExtraData;
 
-  return mDecoder->Input(aSample);
+  mDecoder->Input(aSample);
 }
 
-nsresult
+void
 H264Converter::Flush()
 {
   mNeedKeyframe = true;
   if (mDecoder) {
-    return mDecoder->Flush();
+    mDecoder->Flush();
   }
-  return mLastError;
 }
 
-nsresult
+void
 H264Converter::Drain()
 {
   mNeedKeyframe = true;
   if (mDecoder) {
-    return mDecoder->Drain();
+    mDecoder->Drain();
+    return;
   }
   mCallback->DrainComplete();
-  return mLastError;
 }
 
-nsresult
+void
 H264Converter::Shutdown()
 {
   if (mDecoder) {
-    nsresult rv = mDecoder->Shutdown();
+    mDecoder->Shutdown();
     mInitPromiseRequest.DisconnectIfExists();
     mDecoder = nullptr;
-    return rv;
   }
-  return NS_OK;
 }
 
 bool
 H264Converter::IsHardwareAccelerated(nsACString& aFailureReason) const
 {
   if (mDecoder) {
     return mDecoder->IsHardwareAccelerated(aFailureReason);
   }
@@ -233,19 +235,17 @@ H264Converter::OnDecoderInitDone(const T
   for (uint32_t i = 0 ; i < mMediaRawSamples.Length(); i++) {
     const RefPtr<MediaRawData>& sample = mMediaRawSamples[i];
     if (mNeedKeyframe) {
       if (!sample->mKeyframe) {
         continue;
       }
       mNeedKeyframe = false;
     }
-    if (NS_FAILED(mDecoder->Input(sample))) {
-      mCallback->Error(MediaDataDecoderError::FATAL_ERROR);
-    }
+    mDecoder->Input(sample);
   }
   if (!gotInput) {
     mCallback->InputExhausted();
   }
   mMediaRawSamples.Clear();
 }
 
 void
--- a/dom/media/platforms/wrappers/H264Converter.h
+++ b/dom/media/platforms/wrappers/H264Converter.h
@@ -21,20 +21,20 @@ namespace mozilla {
 class H264Converter : public MediaDataDecoder {
 public:
 
   H264Converter(PlatformDecoderModule* aPDM,
                 const CreateDecoderParams& aParams);
   virtual ~H264Converter();
 
   RefPtr<InitPromise> Init() override;
-  nsresult Input(MediaRawData* aSample) override;
-  nsresult Flush() override;
-  nsresult Drain() override;
-  nsresult Shutdown() override;
+  void Input(MediaRawData* aSample) override;
+  void Flush() override;
+  void Drain() override;
+  void Shutdown() override;
   bool IsHardwareAccelerated(nsACString& aFailureReason) const override;
   const char* GetDescriptionName() const override
   {
     if (mDecoder) {
       return mDecoder->GetDescriptionName();
     }
     return "H264Converter decoder (pending)";
   }
--- a/dom/svg/DOMSVGPoint.cpp
+++ b/dom/svg/DOMSVGPoint.cpp
@@ -110,12 +110,12 @@ DOMSVGPoint::SetY(float aY, ErrorResult&
 }
 
 already_AddRefed<nsISVGPoint>
 DOMSVGPoint::MatrixTransform(dom::SVGMatrix& matrix)
 {
   float x = HasOwner() ? InternalItem().mX : mPt.mX;
   float y = HasOwner() ? InternalItem().mY : mPt.mY;
 
-  Point pt = ToMatrix(matrix.GetMatrix()) * Point(x, y);
+  Point pt = ToMatrix(matrix.GetMatrix()).TransformPoint(Point(x, y));
   nsCOMPtr<nsISVGPoint> newPoint = new DOMSVGPoint(pt);
   return newPoint.forget();
 }
--- a/dom/svg/SVGCircleElement.cpp
+++ b/dom/svg/SVGCircleElement.cpp
@@ -88,17 +88,17 @@ SVGCircleElement::GetGeometryBounds(Rect
                                     const Matrix& aToBoundsSpace,
                                     const Matrix* aToNonScalingStrokeSpace)
 {
   float x, y, r;
   GetAnimatedLengthValues(&x, &y, &r, nullptr);
 
   if (r <= 0.f) {
     // Rendering of the element is disabled
-    *aBounds = Rect(aToBoundsSpace * Point(x, y), Size());
+    *aBounds = Rect(aToBoundsSpace.TransformPoint(Point(x, y)), Size());
     return true;
   }
 
   if (aToBoundsSpace.IsRectilinear()) {
     // Optimize the case where we can treat the circle as a rectangle and
     // still get tight bounds.
     if (aStrokeOptions.mLineWidth > 0.f) {
       if (aToNonScalingStrokeSpace) {
--- a/dom/svg/SVGEllipseElement.cpp
+++ b/dom/svg/SVGEllipseElement.cpp
@@ -99,17 +99,17 @@ SVGEllipseElement::GetGeometryBounds(Rec
                                      const Matrix& aToBoundsSpace,
                                      const Matrix* aToNonScalingStrokeSpace)
 {
   float x, y, rx, ry;
   GetAnimatedLengthValues(&x, &y, &rx, &ry, nullptr);
 
   if (rx <= 0.f || ry <= 0.f) {
     // Rendering of the element is disabled
-    *aBounds = Rect(aToBoundsSpace * Point(x, y), Size());
+    *aBounds = Rect(aToBoundsSpace.TransformPoint(Point(x, y)), Size());
     return true;
   }
 
   if (aToBoundsSpace.IsRectilinear()) {
     // Optimize the case where we can treat the ellipse as a rectangle and
     // still get tight bounds.
     if (aStrokeOptions.mLineWidth > 0.f) {
       if (aToNonScalingStrokeSpace) {
--- a/dom/svg/SVGLineElement.cpp
+++ b/dom/svg/SVGLineElement.cpp
@@ -152,18 +152,18 @@ SVGLineElement::GetGeometryBounds(Rect* 
                                   const StrokeOptions& aStrokeOptions,
                                   const Matrix& aToBoundsSpace,
                                   const Matrix* aToNonScalingStrokeSpace)
 {
   float x1, y1, x2, y2;
   GetAnimatedLengthValues(&x1, &y1, &x2, &y2, nullptr);
 
   if (aStrokeOptions.mLineWidth <= 0) {
-    *aBounds = Rect(aToBoundsSpace * Point(x1, y1), Size());
-    aBounds->ExpandToEnclose(aToBoundsSpace * Point(x2, y2));
+    *aBounds = Rect(aToBoundsSpace.TransformPoint(Point(x1, y1)), Size());
+    aBounds->ExpandToEnclose(aToBoundsSpace.TransformPoint(Point(x2, y2)));
     return true;
   }
 
   // transform from non-scaling-stroke space to the space in which we compute
   // bounds
   Matrix nonScalingToBounds;
   if (aToNonScalingStrokeSpace) {
     MOZ_ASSERT(!aToNonScalingStrokeSpace->IsSingular());
@@ -193,18 +193,18 @@ SVGLineElement::GetGeometryBounds(Rect* 
 
   // Handle butt and square linecap, normal and non-scaling stroke cases
   // together: start with endpoints (x1, y1), (x2, y2) in the stroke space,
   // compute the four corners of the stroked line, transform the corners to
   // bounds space, and compute bounds there.
 
   if (aToNonScalingStrokeSpace) {
     Point nonScalingSpaceP1, nonScalingSpaceP2;
-    nonScalingSpaceP1 = *aToNonScalingStrokeSpace * Point(x1, y1);
-    nonScalingSpaceP2 = *aToNonScalingStrokeSpace * Point(x2, y2);
+    nonScalingSpaceP1 = aToNonScalingStrokeSpace->TransformPoint(Point(x1, y1));
+    nonScalingSpaceP2 = aToNonScalingStrokeSpace->TransformPoint(Point(x2, y2));
     x1 = nonScalingSpaceP1.x;
     y1 = nonScalingSpaceP1.y;
     x2 = nonScalingSpaceP2.x;
     y2 = nonScalingSpaceP2.y;
   }
 
   Float length = Float(NS_hypot(x2 - x1, y2 - y1));
   Float xDelta;
@@ -240,18 +240,18 @@ SVGLineElement::GetGeometryBounds(Rect* 
       points[2] = Point(x2 + yDelta + xDelta, y2 + xDelta - yDelta);
       points[3] = Point(x2 + yDelta - xDelta, y2 + xDelta + yDelta);
     }
   }
 
   const Matrix& toBoundsSpace = aToNonScalingStrokeSpace ?
     nonScalingToBounds : aToBoundsSpace;
 
-  *aBounds = Rect(toBoundsSpace * points[0], Size());
+  *aBounds = Rect(toBoundsSpace.TransformPoint(points[0]), Size());
   for (uint32_t i = 1; i < 4; ++i) {
-    aBounds->ExpandToEnclose(toBoundsSpace * points[i]);
+    aBounds->ExpandToEnclose(toBoundsSpace.TransformPoint(points[i]));
   }
 
   return true;
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/svg/SVGMarkerElement.cpp
+++ b/dom/svg/SVGMarkerElement.cpp
@@ -357,17 +357,17 @@ SVGMarkerElement::GetViewBoxTransform()
       SVGContentUtils::GetViewBoxTransform(viewportWidth, viewportHeight,
                                            viewbox.x, viewbox.y,
                                            viewbox.width, viewbox.height,
                                            mPreserveAspectRatio);
 
     float refX = mLengthAttributes[REFX].GetAnimValue(mCoordCtx);
     float refY = mLengthAttributes[REFY].GetAnimValue(mCoordCtx);
 
-    gfx::Point ref = viewBoxTM * gfx::Point(refX, refY);
+    gfx::Point ref = viewBoxTM.TransformPoint(gfx::Point(refX, refY));
 
     Matrix TM = viewBoxTM;
     TM.PostTranslate(-ref.x, -ref.y);
 
     mViewBoxToViewportTransform = new gfx::Matrix(TM);
   }
 
   return *mViewBoxToViewportTransform;
--- a/dom/svg/nsSVGPolyElement.cpp
+++ b/dom/svg/nsSVGPolyElement.cpp
@@ -144,16 +144,16 @@ nsSVGPolyElement::GetGeometryBounds(Rect
     // We can avoid transforming each point and just transform the result.
     // Important for large point lists.
     Rect bounds(points[0], Size());
     for (uint32_t i = 1; i < points.Length(); ++i) {
       bounds.ExpandToEnclose(points[i]);
     }
     *aBounds = aToBoundsSpace.TransformBounds(bounds);
   } else {
-    *aBounds = Rect(aToBoundsSpace * points[0], Size());
+    *aBounds = Rect(aToBoundsSpace.TransformPoint(points[0]), Size());
     for (uint32_t i = 1; i < points.Length(); ++i) {
-      aBounds->ExpandToEnclose(aToBoundsSpace * points[i]);
+      aBounds->ExpandToEnclose(aToBoundsSpace.TransformPoint(points[i]));
     }
   }
   return true;
 }
 
--- a/dom/system/nsDeviceSensors.cpp
+++ b/dom/system/nsDeviceSensors.cpp
@@ -373,17 +373,17 @@ nsDeviceSensors::Notify(const mozilla::h
 
 void
 nsDeviceSensors::FireDOMLightEvent(mozilla::dom::EventTarget* aTarget,
                                    double aValue)
 {
   DeviceLightEventInit init;
   init.mBubbles = true;
   init.mCancelable = false;
-  init.mValue = aValue;
+  init.mValue = round(aValue);
   RefPtr<DeviceLightEvent> event =
     DeviceLightEvent::Constructor(aTarget, NS_LITERAL_STRING("devicelight"), init);
 
   event->SetTrusted(true);
 
   bool defaultActionEnabled;
   aTarget->DispatchEvent(event, &defaultActionEnabled);
 }
--- a/dom/webidl/Animatable.webidl
+++ b/dom/webidl/Animatable.webidl
@@ -17,13 +17,12 @@ dictionary KeyframeAnimationOptions : Ke
 dictionary AnimationFilter {
   boolean subtree = false;
 };
 
 [NoInterfaceObject]
 interface Animatable {
   [Func="nsDocument::IsElementAnimateEnabled", Throws]
   Animation animate(object? keyframes,
-                    optional (unrestricted double or KeyframeAnimationOptions)
-                      options);
+                    optional UnrestrictedDoubleOrKeyframeAnimationOptions options);
   [Func="nsDocument::IsWebAnimationsEnabled"]
   sequence<Animation> getAnimations(optional AnimationFilter filter);
 };
--- a/dom/webidl/AnonymousContent.webidl
+++ b/dom/webidl/AnonymousContent.webidl
@@ -56,9 +56,15 @@ interface AnonymousContent {
 
   /**
    * Get the canvas' context for the element specified if it's a <canvas>
    * node, `null` otherwise.
    */
   [Throws]
   nsISupports? getCanvasContext(DOMString elementId,
                                 DOMString contextId);
+
+  [Func="nsDocument::IsElementAnimateEnabled", Throws]
+  Animation setAnimationForElement(DOMString elementId,
+                                   object? keyframes,
+                                   optional UnrestrictedDoubleOrKeyframeAnimationOptions
+                                     options);
 };
--- a/dom/webidl/Document.webidl
+++ b/dom/webidl/Document.webidl
@@ -19,19 +19,19 @@ dictionary ElementCreationOptions {
   DOMString is;
 };
 
 /* http://dom.spec.whatwg.org/#interface-document */
 [Constructor]
 interface Document : Node {
   [Throws]
   readonly attribute DOMImplementation implementation;
-  [Pure]
+  [Pure, Throws]
   readonly attribute DOMString URL;
-  [Pure]
+  [Pure, Throws]
   readonly attribute DOMString documentURI;
   [Pure]
   readonly attribute DOMString compatMode;
   [Pure]
   readonly attribute DOMString characterSet;
   [Pure,BinaryName="characterSet"]
   readonly attribute DOMString charset; // legacy alias of .characterSet
   [Pure,BinaryName="characterSet"]
new file mode 100644
--- /dev/null
+++ b/dom/webidl/KeyframeAnimationOptions.webidl
@@ -0,0 +1,14 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/.
+ *
+ * The origin of this IDL file is
+ * http://dev.w3.org/fxtf/web-animations/#the-animatable-interface
+ *
+ * Copyright © 2014 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
+ * liability, trademark and document use rules apply.
+ */
+
+// This typedef is off in its own file, because of bug 995352.
+typedef (unrestricted double or KeyframeAnimationOptions) UnrestrictedDoubleOrKeyframeAnimationOptions;
--- a/dom/webidl/Node.webidl
+++ b/dom/webidl/Node.webidl
@@ -26,17 +26,17 @@ interface Node : EventTarget {
   const unsigned short DOCUMENT_TYPE_NODE = 10;
   const unsigned short DOCUMENT_FRAGMENT_NODE = 11;
   const unsigned short NOTATION_NODE = 12; // historical
   [Constant]
   readonly attribute unsigned short nodeType;
   [Pure]
   readonly attribute DOMString nodeName;
 
-  [Pure]
+  [Pure, Throws]
   readonly attribute DOMString? baseURI;
 
   [Pure, BinaryName=getComposedDoc]
   readonly attribute boolean isConnected;
   [Pure]
   readonly attribute Document? ownerDocument;
   [Pure, Pref="dom.node.rootNode.enabled"]
   readonly attribute Node rootNode;
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -286,16 +286,17 @@ WEBIDL_FILES = [
     'InputMethod.webidl',
     'InputPort.webidl',
     'InputPortManager.webidl',
     'InspectorUtils.webidl',
     'IterableIterator.webidl',
     'KeyAlgorithm.webidl',
     'KeyboardEvent.webidl',
     'KeyEvent.webidl',
+    'KeyframeAnimationOptions.webidl',
     'KeyframeEffect.webidl',
     'LegacyQueryInterface.webidl',
     'LinkStyle.webidl',
     'ListBoxObject.webidl',
     'LocalMediaStream.webidl',
     'Location.webidl',
     'MediaDeviceInfo.webidl',
     'MediaDevices.webidl',
--- a/dom/xbl/nsXBLProtoImpl.cpp
+++ b/dom/xbl/nsXBLProtoImpl.cpp
@@ -508,28 +508,28 @@ nsXBLProtoImpl::Write(nsIObjectOutputStr
       rv = curr->Write(aStream);
     }
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   return aStream->Write8(XBLBinding_Serialize_NoMoreItems);
 }
 
-nsresult
+void
 NS_NewXBLProtoImpl(nsXBLPrototypeBinding* aBinding, 
                    const char16_t* aClassName, 
                    nsXBLProtoImpl** aResult)
 {
   nsXBLProtoImpl* impl = new nsXBLProtoImpl();
   if (aClassName) {
     impl->mClassName = aClassName;
   } else {
     nsCString spec;
-    aBinding->BindingURI()->GetSpec(spec);
+    nsresult rv = aBinding->BindingURI()->GetSpec(spec);
+    // XXX: should handle this better
+    MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
     impl->mClassName = NS_ConvertUTF8toUTF16(spec);
   }
 
   aBinding->SetImplementation(impl);
   *aResult = impl;
-
-  return NS_OK;
 }
 
--- a/dom/xbl/nsXBLProtoImpl.h
+++ b/dom/xbl/nsXBLProtoImpl.h
@@ -112,14 +112,14 @@ protected:
 
   nsXBLProtoImplField* mFields; // Our fields
 
 public:
   nsXBLProtoImplAnonymousMethod* mConstructor; // Our class constructor.
   nsXBLProtoImplAnonymousMethod* mDestructor;  // Our class destructor.
 };
 
-nsresult
+void
 NS_NewXBLProtoImpl(nsXBLPrototypeBinding* aBinding,
                    const char16_t* aClassName,
                    nsXBLProtoImpl** aResult);
 
 #endif // nsXBLProtoImpl_h__
--- a/dom/xbl/nsXBLProtoImplField.cpp
+++ b/dom/xbl/nsXBLProtoImplField.cpp
@@ -386,17 +386,20 @@ nsXBLProtoImplField::InstallField(JS::Ha
   // Empty fields are treated as not actually present.
   if (IsEmpty()) {
     return NS_OK;
   }
 
   nsAutoMicroTask mt;
 
   nsAutoCString uriSpec;
-  aBindingDocURI->GetSpec(uriSpec);
+  nsresult rv = aBindingDocURI->GetSpec(uriSpec);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
 
   nsIGlobalObject* globalObject = xpc::WindowGlobalOrNull(aBoundNode);
   if (!globalObject) {
     return NS_OK;
   }
 
   // We are going to run script via EvaluateString, so we need a script entry
   // point, but as this is XBL related it does not appear in the HTML spec.
@@ -404,17 +407,17 @@ nsXBLProtoImplField::InstallField(JS::Ha
   JSContext* cx = aes.cx();
 
   NS_ASSERTION(!::JS_IsExceptionPending(cx),
                "Shouldn't get here when an exception is pending!");
 
   JSAddonId* addonId = MapURIToAddonID(aBindingDocURI);
 
   Element* boundElement = nullptr;
-  nsresult rv = UNWRAP_OBJECT(Element, aBoundNode, boundElement);
+  rv = UNWRAP_OBJECT(Element, aBoundNode, boundElement);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   // First, enter the xbl scope, build the element's scope chain, and use
   // that as the scope chain for the evaluation.
   JS::Rooted<JSObject*> scopeObject(cx, xpc::GetScopeForXBLExecution(cx, aBoundNode, addonId));
   NS_ENSURE_TRUE(scopeObject, NS_ERROR_OUT_OF_MEMORY);
--- a/dom/xbl/nsXBLPrototypeBinding.cpp
+++ b/dom/xbl/nsXBLPrototypeBinding.cpp
@@ -1055,18 +1055,20 @@ nsXBLPrototypeBinding::Write(nsIObjectOu
   nsAutoCString id;
   mBindingURI->GetRef(id);
   rv = aStream->WriteStringZ(id.get());
   NS_ENSURE_SUCCESS(rv, rv);
 
   // write out the extends and display attribute values
   nsAutoCString extends;
   ResolveBaseBinding();
-  if (mBaseBindingURI)
-    mBaseBindingURI->GetSpec(extends);
+  if (mBaseBindingURI) {
+    rv = mBaseBindingURI->GetSpec(extends);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
 
   rv = aStream->WriteStringZ(extends.get());
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = WriteNamespace(aStream, mBaseNameSpaceID);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsAutoString baseTag;
--- a/dom/xbl/nsXBLPrototypeHandler.cpp
+++ b/dom/xbl/nsXBLPrototypeHandler.cpp
@@ -351,35 +351,36 @@ nsXBLPrototypeHandler::EnsureEventHandle
   NS_ENSURE_TRUE(!handlerText.IsEmpty(), NS_ERROR_FAILURE);
 
   JSAddonId* addonId = MapURIToAddonID(mPrototypeBinding->DocURI());
 
   JS::Rooted<JSObject*> scopeObject(cx, xpc::GetScopeForXBLExecution(cx, globalObject, addonId));
   NS_ENSURE_TRUE(scopeObject, NS_ERROR_OUT_OF_MEMORY);
 
   nsAutoCString bindingURI;
-  mPrototypeBinding->DocURI()->GetSpec(bindingURI);
+  nsresult rv = mPrototypeBinding->DocURI()->GetSpec(bindingURI);
+  NS_ENSURE_SUCCESS(rv, rv);
 
   uint32_t argCount;
   const char **argNames;
   nsContentUtils::GetEventArgNames(kNameSpaceID_XBL, aName, false, &argCount,
                                    &argNames);
 
   // Compile the event handler in the xbl scope.
   JSAutoCompartment ac(cx, scopeObject);
   JS::CompileOptions options(cx);
   options.setFileAndLine(bindingURI.get(), mLineNumber)
          .setVersion(JSVERSION_LATEST);
 
   JS::Rooted<JSObject*> handlerFun(cx);
   JS::AutoObjectVector emptyVector(cx);
-  nsresult rv = nsJSUtils::CompileFunction(jsapi, emptyVector, options,
-                                           nsAtomCString(aName), argCount,
-                                           argNames, handlerText,
-                                           handlerFun.address());
+  rv = nsJSUtils::CompileFunction(jsapi, emptyVector, options,
+                                  nsAtomCString(aName), argCount,
+                                  argNames, handlerText,
+                                  handlerFun.address());
   NS_ENSURE_SUCCESS(rv, rv);
   NS_ENSURE_TRUE(handlerFun, NS_ERROR_FAILURE);
 
   // Wrap the handler into the content scope, since we're about to stash it
   // on the DOM window and such.
   JSAutoCompartment ac2(cx, globalObject);
   bool ok = JS_WrapObject(cx, &handlerFun);
   NS_ENSURE_TRUE(ok, NS_ERROR_OUT_OF_MEMORY);
--- a/dom/xhr/XMLHttpRequestMainThread.cpp
+++ b/dom/xhr/XMLHttpRequestMainThread.cpp
@@ -2224,17 +2224,21 @@ XMLHttpRequestMainThread::RequestBody<ns
 
   if (mBody->IsHTMLDocument()) {
     aContentType.AssignLiteral("text/html");
 
     nsString serialized;
     if (!nsContentUtils::SerializeNodeToMarkup(mBody, true, serialized)) {
       return NS_ERROR_OUT_OF_MEMORY;
     }
-    NS_ConvertUTF16toUTF8 utf8Serialized(serialized);
+
+    nsAutoCString utf8Serialized;
+    if (!AppendUTF16toUTF8(serialized, utf8Serialized, fallible)) {
+      return NS_ERROR_OUT_OF_MEMORY;
+    }
 
     uint32_t written;
     rv = output->Write(utf8Serialized.get(), utf8Serialized.Length(), &written);
     NS_ENSURE_SUCCESS(rv, rv);
 
     MOZ_ASSERT(written == utf8Serialized.Length());
   } else {
     aContentType.AssignLiteral("application/xml");
@@ -2263,17 +2267,21 @@ XMLHttpRequestMainThread::RequestBody<ns
 template<> nsresult
 XMLHttpRequestMainThread::RequestBody<const nsAString>::GetAsStream(
    nsIInputStream** aResult, uint64_t* aContentLength,
    nsACString& aContentType, nsACString& aCharset) const
 {
   aContentType.AssignLiteral("text/plain");
   aCharset.AssignLiteral("UTF-8");
 
-  nsCString converted = NS_ConvertUTF16toUTF8(*mBody);
+  nsAutoCString converted;
+  if (!AppendUTF16toUTF8(*mBody, converted, fallible)) {
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
+
   *aContentLength = converted.Length();
   nsresult rv = NS_NewCStringInputStream(aResult, converted);
   NS_ENSURE_SUCCESS(rv, rv);
   return NS_OK;
 }
 
 template<> nsresult
 XMLHttpRequestMainThread::RequestBody<nsIInputStream>::GetAsStream(
--- a/embedding/components/webbrowserpersist/WebBrowserPersistLocalDocument.cpp
+++ b/embedding/components/webbrowserpersist/WebBrowserPersistLocalDocument.cpp
@@ -820,21 +820,21 @@ PersistNodeFixup::FixupAnchor(nsIDOMNode
 
         nsCOMPtr<nsIURI> relativeURI;
         relativeURI = IsFlagSet(IWBP::PERSIST_FLAGS_FIXUP_LINKS_TO_DESTINATION)
                       ? mTargetBaseURI : mCurrentBaseURI;
         // Make a new URI to replace the current one
         nsCOMPtr<nsIURI> newURI;
         rv = NS_NewURI(getter_AddRefs(newURI), oldCValue,
                        mParent->GetCharacterSet().get(), relativeURI);
-        if (NS_SUCCEEDED(rv) && newURI)
-        {
+        if (NS_SUCCEEDED(rv) && newURI) {
             newURI->SetUserPass(EmptyCString());
             nsAutoCString uriSpec;
-            newURI->GetSpec(uriSpec);
+            rv = newURI->GetSpec(uriSpec);
+            NS_ENSURE_SUCCESS(rv, rv);
             attr->SetValue(NS_ConvertUTF8toUTF16(uriSpec));
         }
     }
 
     return NS_OK;
 }
 
 static void
--- a/embedding/components/webbrowserpersist/nsWebBrowserPersist.cpp
+++ b/embedding/components/webbrowserpersist/nsWebBrowserPersist.cpp
@@ -1161,24 +1161,26 @@ nsresult nsWebBrowserPersist::SendErrorS
         // Do nothing
         return NS_OK;
     }
 
     // Get the file path or spec from the supplied URI
     nsCOMPtr<nsIFile> file;
     GetLocalFileFromURI(aURI, getter_AddRefs(file));
     nsAutoString path;
+    nsresult rv;
     if (file)
     {
         file->GetPath(path);
     }
     else
     {
         nsAutoCString fileurl;
-        aURI->GetSpec(fileurl);
+        rv = aURI->GetSpec(fileurl);
+        NS_ENSURE_SUCCESS(rv, rv);
         AppendUTF8toUTF16(fileurl, path);
     }
 
     nsAutoString msgId;
     switch(aResult)
     {
     case NS_ERROR_FILE_NAME_TOO_LONG:
         // File name too long.
@@ -1208,17 +1210,16 @@ nsresult nsWebBrowserPersist::SendErrorS
         // Generic read/write error message.
         if (aIsReadError)
             msgId.AssignLiteral("readError");
         else
             msgId.AssignLiteral("writeError");
         break;
     }
     // Get properties file bundle and extract status string.
-    nsresult rv;
     nsCOMPtr<nsIStringBundleService> s = do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv);
     NS_ENSURE_TRUE(NS_SUCCEEDED(rv) && s, NS_ERROR_FAILURE);
 
     nsCOMPtr<nsIStringBundle> bundle;
     rv = s->CreateBundle(kWebBrowserPersistStringBundle, getter_AddRefs(bundle));
     NS_ENSURE_TRUE(NS_SUCCEEDED(rv) && bundle, NS_ERROR_FAILURE);
 
     nsXPIDLString msgText;
--- a/embedding/components/windowwatcher/nsWindowWatcher.cpp
+++ b/embedding/components/windowwatcher/nsWindowWatcher.cpp
@@ -1048,26 +1048,29 @@ nsWindowWatcher::OpenWindowInternal(mozI
   // better have a window to use by this point
   if (!newDocShellItem) {
     return rv;
   }
 
   nsCOMPtr<nsIDocShell> newDocShell(do_QueryInterface(newDocShellItem));
   NS_ENSURE_TRUE(newDocShell, NS_ERROR_UNEXPECTED);
 
+  // If our parent is sandboxed, set it as the one permitted sandboxed navigator
+  // on the new window we're opening.
+  if (activeDocsSandboxFlags && parentWindow) {
+    newDocShell->SetOnePermittedSandboxedNavigator(
+      parentWindow->GetDocShell());
+  }
+
   // Copy sandbox flags to the new window if activeDocsSandboxFlags says to do
   // so.  Note that it's only nonzero if the window is new, so clobbering
   // sandbox flags on the window makes sense in that case.
   if (activeDocsSandboxFlags &
         SANDBOX_PROPAGATES_TO_AUXILIARY_BROWSING_CONTEXTS) {
     newDocShell->SetSandboxFlags(activeDocsSandboxFlags);
-    if (parentWindow) {
-      newDocShell->SetOnePermittedSandboxedNavigator(
-        parentWindow->GetDocShell());
-    }
   }
 
   rv = ReadyOpenedDocShellItem(newDocShellItem, parentWindow, windowIsNew, aResult);
   if (NS_FAILED(rv)) {
     return rv;
   }
 
   if (isNewToplevelWindow) {
@@ -1106,19 +1109,19 @@ nsWindowWatcher::OpenWindowInternal(mozI
   nsCOMPtr<nsIPrincipal> subjectPrincipal =
     nsContentUtils::GetCurrentJSContext() ? nsContentUtils::SubjectPrincipal() :
                                             nullptr;
 
   if (windowIsNew) {
     auto* docShell = static_cast<nsDocShell*>(newDocShell.get());
 
     // If this is not a chrome docShell, we apply originAttributes from the
-    // subjectPrincipal unless if it's an expanded principal.
+    // subjectPrincipal unless if it's an expanded or system principal.
     if (subjectPrincipal &&
-        !subjectPrincipal->GetIsExpandedPrincipal() &&
+        !nsContentUtils::IsSystemOrExpandedPrincipal(subjectPrincipal) &&
         docShell->ItemType() != nsIDocShellTreeItem::typeChrome) {
       DocShellOriginAttributes attrs;
       attrs.InheritFromDocToChildDocShell(BasePrincipal::Cast(subjectPrincipal)->OriginAttributesRef());
 
       docShell->SetOriginAttributes(attrs);
     }
 
     // Now set the opener principal on the new window.  Note that we need to do
@@ -1277,25 +1280,28 @@ nsWindowWatcher::OpenWindowInternal(mozI
 
     if (!windowStateHelper.DefaultEnabled()) {
       // Default to cancel not opening the modal window.
       NS_RELEASE(*aResult);
 
       return NS_OK;
     }
 
-    if (!newWindowShouldBeModal && parentIsModal) {
-      nsCOMPtr<nsIBaseWindow> parentWindow(do_GetInterface(newTreeOwner));
-      if (parentWindow) {
-        nsCOMPtr<nsIWidget> parentWidget;
-        parentWindow->GetMainWidget(getter_AddRefs(parentWidget));
-        if (parentWidget) {
-          parentWidget->SetFakeModal(true);
-        }
+    bool isAppModal = false;
+    nsCOMPtr<nsIBaseWindow> parentWindow(do_GetInterface(newTreeOwner));
+    nsCOMPtr<nsIWidget> parentWidget;
+    if (parentWindow) {
+      parentWindow->GetMainWidget(getter_AddRefs(parentWidget));
+      if (parentWidget) {
+        isAppModal = parentWidget->IsRunningAppModal();
       }
+    }
+    if (parentWidget &&
+        ((!newWindowShouldBeModal && parentIsModal) || isAppModal)) {
+      parentWidget->SetFakeModal(true);
     } else {
       // Reset popup state while opening a modal dialog, and firing
       // events about the dialog, to prevent the current state from
       // being active the whole time a modal dialog is open.
       nsAutoPopupStatePusher popupStatePusher(openAbused);
 
       newChrome->ShowAsModal();
     }
--- a/gfx/2d/2D.h
+++ b/gfx/2d/2D.h
@@ -1476,17 +1476,18 @@ public:
   static uint64_t GetD2DVRAMUsageDrawTarget();
   static uint64_t GetD2DVRAMUsageSourceSurface();
   static void D2DCleanup();
 
   static already_AddRefed<ScaledFont>
     CreateScaledFontForDWriteFont(IDWriteFont* aFont,
                                   IDWriteFontFamily* aFontFamily,
                                   IDWriteFontFace* aFontFace,
-                                  Float aSize);
+                                  Float aSize,
+                                  bool aUseEmbeddedBitmap);
 
 private:
   static ID2D1Device *mD2D1Device;
   static ID3D11Device *mD3D11Device;
 #endif
 
   static DrawEventRecorder *mRecorder;
 };
--- a/gfx/2d/DrawCommand.h
+++ b/gfx/2d/DrawCommand.h
@@ -203,17 +203,17 @@ public:
   {
   }
 
   virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix* aTransform) const
   {
     MOZ_ASSERT(!aTransform || !aTransform->HasNonIntegerTranslation());
     Point dest(Float(mDestination.x), Float(mDestination.y));
     if (aTransform) {
-      dest = (*aTransform) * dest;
+      dest = aTransform->TransformPoint(dest);
     }
     aDT->CopySurface(mSurface, mSourceRect, IntPoint(uint32_t(dest.x), uint32_t(dest.y)));
   }
 
 private:
   RefPtr<SourceSurface> mSurface;
   IntRect mSourceRect;
   IntPoint mDestination;
--- a/gfx/2d/DrawTargetSkia.cpp
+++ b/gfx/2d/DrawTargetSkia.cpp
@@ -36,16 +36,20 @@
 #include "BorrowedContext.h"
 #include <ApplicationServices/ApplicationServices.h>
 #include "mozilla/Vector.h"
 #include "ScaledFontMac.h"
 #include "DrawTargetCG.h"
 #include "CGTextDrawing.h"
 #endif
 
+#ifdef XP_WIN
+#include "ScaledFontDWrite.h"
+#endif
+
 namespace mozilla {
 namespace gfx {
 
 class GradientStopsSkia : public GradientStops
 {
 public:
   MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(GradientStopsSkia)
   GradientStopsSkia(const std::vector<GradientStop>& aStops, uint32_t aNumStops, ExtendMode aExtendMode)
@@ -1286,16 +1290,24 @@ DrawTargetSkia::FillGlyphs(ScaledFont *a
     if (!shouldLCDRenderText) {
       // If we have non LCD GDI text, render the fonts as cleartype and convert them
       // to grayscale. This seems to be what Chrome and IE are doing on Windows 7.
       // This also applies if cleartype is disabled system wide.
       paint.mPaint.setFlags(paint.mPaint.getFlags() | SkPaint::kGenA8FromLCD_Flag);
     }
     break;
   }
+#ifdef XP_WIN
+  case FontType::DWRITE:
+  {
+    ScaledFontDWrite* dwriteFont = static_cast<ScaledFontDWrite*>(aFont);
+    paint.mPaint.setEmbeddedBitmapText(dwriteFont->UseEmbeddedBitmaps());
+    break;
+  }
+#endif
   default:
     break;
   }
 
   paint.mPaint.setSubpixelText(useSubpixelText);
 
   std::vector<uint16_t> indices;
   std::vector<SkPoint> offsets;
--- a/gfx/2d/Factory.cpp
+++ b/gfx/2d/Factory.cpp
@@ -700,19 +700,20 @@ Factory::D2DCleanup()
   }
   DrawTargetD2D1::CleanupD2D();
 }
 
 already_AddRefed<ScaledFont>
 Factory::CreateScaledFontForDWriteFont(IDWriteFont* aFont,
                                        IDWriteFontFamily* aFontFamily,
                                        IDWriteFontFace* aFontFace,
-                                       float aSize)
+                                       float aSize,
+                                       bool aUseEmbeddedBitmap)
 {
-  return MakeAndAddRef<ScaledFontDWrite>(aFont, aFontFamily, aFontFace, aSize);
+  return MakeAndAddRef<ScaledFontDWrite>(aFont, aFontFamily, aFontFace, aSize, aUseEmbeddedBitmap);
 }
 
 #endif // XP_WIN
 
 #ifdef USE_SKIA_GPU
 already_AddRefed<DrawTarget>
 Factory::CreateDrawTargetSkiaWithGrContext(GrContext* aGrContext,
                                            const IntSize &aSize,
--- a/gfx/2d/HelpersD2D.h
+++ b/gfx/2d/HelpersD2D.h
@@ -648,20 +648,20 @@ CreatePartialBitmapForSurface(DataSource
       // Scope to auto-Unmap() |mapping|.
       DataSourceSurface::ScopedMap mapping(aSurface, DataSourceSurface::READ);
       if (MOZ2D_WARN_IF(!mapping.IsMapped())) {
         return nullptr;
       }
       ImageHalfScaler scaler(mapping.GetData(), mapping.GetStride(), size);
 
       // Calculate the maximum width/height of the image post transform.
-      Point topRight = transform * Point(Float(size.width), 0);
-      Point topLeft = transform * Point(0, 0);
-      Point bottomRight = transform * Point(Float(size.width), Float(size.height));
-      Point bottomLeft = transform * Point(0, Float(size.height));
+      Point topRight = transform.TransformPoint(Point(Float(size.width), 0));
+      Point topLeft = transform.TransformPoint(Point(0, 0));
+      Point bottomRight = transform.TransformPoint(Point(Float(size.width), Float(size.height)));
+      Point bottomLeft = transform.TransformPoint(Point(0, Float(size.height)));
 
       IntSize scaleSize;
 
       scaleSize.width = int32_t(std::max(Distance(topRight, topLeft),
                                          Distance(bottomRight, bottomLeft)));
       scaleSize.height = int32_t(std::max(Distance(topRight, bottomRight),
                                           Distance(topLeft, bottomLeft)));
 
--- a/gfx/2d/Matrix.cpp
+++ b/gfx/2d/Matrix.cpp
@@ -90,20 +90,20 @@ Matrix::Rotation(Float aAngle)
 Rect
 Matrix::TransformBounds(const Rect &aRect) const
 {
   int i;
   Point quad[4];
   Float min_x, max_x;
   Float min_y, max_y;
 
-  quad[0] = *this * aRect.TopLeft();
-  quad[1] = *this * aRect.TopRight();
-  quad[2] = *this * aRect.BottomLeft();
-  quad[3] = *this * aRect.BottomRight();
+  quad[0] = TransformPoint(aRect.TopLeft());
+  quad[1] = TransformPoint(aRect.TopRight());
+  quad[2] = TransformPoint(aRect.BottomLeft());
+  quad[3] = TransformPoint(aRect.BottomRight());
 
   min_x = max_x = quad[0].x;
   min_y = max_y = quad[0].y;
 
   for (i = 1; i < 4; i++) {
     if (quad[i].x < min_x)
       min_x = quad[i].x;
     if (quad[i].x > max_x)
--- a/gfx/2d/Matrix.h
+++ b/gfx/2d/Matrix.h
@@ -48,27 +48,27 @@ public:
 
   MOZ_ALWAYS_INLINE Matrix Copy() const
   {
     return Matrix(*this);
   }
 
   friend std::ostream& operator<<(std::ostream& aStream, const Matrix& aMatrix);
 
-  Point operator *(const Point &aPoint) const
+  Point TransformPoint(const Point &aPoint) const
   {
     Point retPoint;
 
     retPoint.x = aPoint.x * _11 + aPoint.y * _21 + _31;
     retPoint.y = aPoint.x * _12 + aPoint.y * _22 + _32;
 
     return retPoint;
   }
 
-  Size operator *(const Size &aSize) const
+  Size TransformSize(const Size &aSize) const
   {
     Size retSize;
 
     retSize.width = aSize.width * _11 + aSize.height * _21;
     retSize.height = aSize.width * _12 + aSize.height * _22;
 
     return retSize;
   }
@@ -587,17 +587,17 @@ public:
 
     // The transformed value of z is computed as:
     // z' = aPoint.x * _13 + aPoint.y * _23 + z * _33 + _43;
 
     // Solving for z when z' = 0 gives us:
     F z = -(aPoint.x * _13 + aPoint.y * _23 + _43) / _33;
 
     // Compute the transformed point
-    return *this * Point4DTyped<SourceUnits, F>(aPoint.x, aPoint.y, z, 1);
+    return this->TransformPoint(Point4DTyped<SourceUnits, F>(aPoint.x, aPoint.y, z, 1));
   }
 
   template<class F>
   RectTyped<TargetUnits, F>
   ProjectRectBounds(const RectTyped<SourceUnits, F>& aRect, const RectTyped<TargetUnits, F>& aClip) const
   {
     // This function must never return std::numeric_limits<Float>::max() or any
     // other arbitrary large value in place of inifinity.  This often occurs when
@@ -718,20 +718,20 @@ public:
                               const RectTyped<TargetUnits, F>& aClip,
                               PointTyped<TargetUnits, F>* aVerts) const
   {
     // Initialize a double-buffered array of points in homogenous space with
     // the input rectangle, aRect.
     Point4DTyped<UnknownUnits, F> points[2][kTransformAndClipRectMaxVerts];
     Point4DTyped<UnknownUnits, F>* dstPoint = points[0];
 
-    *dstPoint++ = *this * Point4DTyped<UnknownUnits, F>(aRect.x, aRect.y, 0, 1);
-    *dstPoint++ = *this * Point4DTyped<UnknownUnits, F>(aRect.XMost(), aRect.y, 0, 1);
-    *dstPoint++ = *this * Point4DTyped<UnknownUnits, F>(aRect.XMost(), aRect.YMost(), 0, 1);
-    *dstPoint++ = *this * Point4DTyped<UnknownUnits, F>(aRect.x, aRect.YMost(), 0, 1);
+    *dstPoint++ = TransformPoint(Point4DTyped<UnknownUnits, F>(aRect.x, aRect.y, 0, 1));
+    *dstPoint++ = TransformPoint(Point4DTyped<UnknownUnits, F>(aRect.XMost(), aRect.y, 0, 1));
+    *dstPoint++ = TransformPoint(Point4DTyped<UnknownUnits, F>(aRect.XMost(), aRect.YMost(), 0, 1));
+    *dstPoint++ = TransformPoint(Point4DTyped<UnknownUnits, F>(aRect.x, aRect.YMost(), 0, 1));
 
     // View frustum clipping planes are described as normals originating from
     // the 0,0,0,0 origin.
     Point4DTyped<UnknownUnits, F> planeNormals[4];
     planeNormals[0] = Point4DTyped<UnknownUnits, F>(1.0, 0.0, 0.0, -aClip.x);
     planeNormals[1] = Point4DTyped<UnknownUnits, F>(-1.0, 0.0, 0.0, aClip.XMost());
     planeNormals[2] = Point4DTyped<UnknownUnits, F>(0.0, 1.0, 0.0, -aClip.y);
     planeNormals[3] = Point4DTyped<UnknownUnits, F>(0.0, -1.0, 0.0, aClip.YMost());
@@ -819,66 +819,65 @@ public:
       Float y = aPoint.x * _21 + aPoint.y * _22 + aPoint.z * _23 + aPoint.w * _24;
       Float z = aPoint.x * _31 + aPoint.y * _32 + aPoint.z * _33 + aPoint.w * _34;
       Float w = aPoint.x * _41 + aPoint.y * _42 + aPoint.z * _43 + aPoint.w * _44;
 
       return TargetPoint4D(x, y, z, w);
   }
 
   template<class F>
-  Point4DTyped<TargetUnits, F> operator *(const Point4DTyped<SourceUnits, F>& aPoint) const
+  Point4DTyped<TargetUnits, F> TransformPoint(const Point4DTyped<SourceUnits, F>& aPoint) const
   {
     Point4DTyped<TargetUnits, F> retPoint;
 
     retPoint.x = aPoint.x * _11 + aPoint.y * _21 + aPoint.z * _31 + aPoint.w * _41;
     retPoint.y = aPoint.x * _12 + aPoint.y * _22 + aPoint.z * _32 + aPoint.w * _42;
     retPoint.z = aPoint.x * _13 + aPoint.y * _23 + aPoint.z * _33 + aPoint.w * _43;
     retPoint.w = aPoint.x * _14 + aPoint.y * _24 + aPoint.z * _34 + aPoint.w * _44;
 
     return retPoint;
   }
 
   template<class F>
-  Point3DTyped<TargetUnits, F> operator *(const Point3DTyped<SourceUnits, F>& aPoint) const
+  Point3DTyped<TargetUnits, F> TransformPoint(const Point3DTyped<SourceUnits, F>& aPoint) const
   {
     Point3DTyped<TargetUnits, F> result;
     result.x = aPoint.x * _11 + aPoint.y * _21 + aPoint.z * _31 + _41;
     result.y = aPoint.x * _12 + aPoint.y * _22 + aPoint.z * _32 + _42;
     result.z = aPoint.x * _13 + aPoint.y * _23 + aPoint.z * _33 + _43;
 
     result /= (aPoint.x * _14 + aPoint.y * _24 + aPoint.z * _34 + _44);
 
     return result;
   }
 
   template<class F>
-  PointTyped<TargetUnits, F> operator *(const PointTyped<SourceUnits, F> &aPoint) const
+  PointTyped<TargetUnits, F> TransformPoint(const PointTyped<SourceUnits, F> &aPoint) const
   {
     Point4DTyped<SourceUnits, F> temp(aPoint.x, aPoint.y, 0, 1);
-    Point4DTyped<TargetUnits, F> result = *this * temp;
-    return result.As2DPoint();
+    return TransformPoint(temp).As2DPoint();
   }
 
   template<class F>
   GFX2D_API RectTyped<TargetUnits, F> TransformBounds(const RectTyped<SourceUnits, F>& aRect) const
   {
     Point4DTyped<TargetUnits, F> verts[4];
-    verts[0] = *this * Point4DTyped<SourceUnits, F>(aRect.x, aRect.y, 0.0, 1.0);
-    verts[1] = *this * Point4DTyped<SourceUnits, F>(aRect.XMost(), aRect.y, 0.0, 1.0);
-    verts[2] = *this * Point4DTyped<SourceUnits, F>(aRect.XMost(), aRect.YMost(), 0.0, 1.0);
-    verts[3] = *this * Point4DTyped<SourceUnits, F>(aRect.x, aRect.YMost(), 0.0, 1.0);
+    verts[0] = TransformPoint(Point4DTyped<SourceUnits, F>(aRect.x, aRect.y, 0.0, 1.0));
+    verts[1] = TransformPoint(Point4DTyped<SourceUnits, F>(aRect.XMost(), aRect.y, 0.0, 1.0));
+    verts[2] = TransformPoint(Point4DTyped<SourceUnits, F>(aRect.XMost(), aRect.YMost(), 0.0, 1.0));
+    verts[3] = TransformPoint(Point4DTyped<SourceUnits, F>(aRect.x, aRect.YMost(), 0.0, 1.0));
 
     PointTyped<TargetUnits, F> quad[4];
     F min_x, max_x;
     F min_y, max_y;
 
-    quad[0] = *this * aRect.TopLeft();
-    quad[1] = *this * aRect.TopRight();
-    quad[2] = *this * aRect.BottomLeft();
-    quad[3] = *this * aRect.BottomRight();
+    quad[0] = TransformPoint(aRect.TopLeft());
+    quad[1] = TransformPoint(aRect.TopRight());
+    quad[2] = TransformPoint(aRect.BottomLeft());
+    quad[3] = TransformPoint(aRect.BottomRight());
 
     min_x = max_x = quad[0].x;
     min_y = max_y = quad[0].y;
 
     for (int i = 1; i < 4; i++) {
       if (quad[i].x < min_x) {
         min_x = quad[i].x;
       }
@@ -1502,19 +1501,19 @@ public:
     _33 += -1.0/aDepth * _43;
     _34 += -1.0/aDepth * _44;
   }
 
   Point3D GetNormalVector() const
   {
     // Define a plane in transformed space as the transformations
     // of 3 points on the z=0 screen plane.
-    Point3D a = *this * Point3D(0, 0, 0);
-    Point3D b = *this * Point3D(0, 1, 0);
-    Point3D c = *this * Point3D(1, 0, 0);
+    Point3D a = TransformPoint(Point3D(0, 0, 0));
+    Point3D b = TransformPoint(Point3D(0, 1, 0));
+    Point3D c = TransformPoint(Point3D(1, 0, 0));
 
     // Convert to two vectors on the surface of the plane.
     Point3D ab = b - a;
     Point3D ac = c - a;
 
     return ac.CrossProduct(ab);
   }
 
--- a/gfx/2d/PathCG.cpp
+++ b/gfx/2d/PathCG.cpp
@@ -249,17 +249,17 @@ PathCG::StreamToSink(PathSink *aSink) co
   CGPathApply(mPath, aSink, StreamPathToSinkApplierFunc);
 }
 
 bool
 PathCG::ContainsPoint(const Point &aPoint, const Matrix &aTransform) const
 {
   Matrix inverse = aTransform;
   inverse.Invert();
-  Point transformedPoint = inverse*aPoint;
+  Point transformedPoint = inverse.TransformPoint(aPoint);
   // We could probably drop the input transform and just transform the point at the caller?
   CGPoint point = {transformedPoint.x, transformedPoint.y};
 
   // The transform parameter of CGPathContainsPoint doesn't seem to work properly on OS X 10.5
   // so we transform aPoint ourselves.
   return CGPathContainsPoint(mPath, nullptr, point, mFillRule == FillRule::FILL_EVEN_ODD);
 }
 
@@ -289,17 +289,17 @@ ScratchContext()
 
 bool
 PathCG::StrokeContainsPoint(const StrokeOptions &aStrokeOptions,
                             const Point &aPoint,
                             const Matrix &aTransform) const
 {
   Matrix inverse = aTransform;
   inverse.Invert();
-  Point transformedPoint = inverse*aPoint;
+  Point transformedPoint = inverse.TransformPoint(aPoint);
   // We could probably drop the input transform and just transform the point at the caller?
   CGPoint point = {transformedPoint.x, transformedPoint.y};
 
   CGContextRef cg = ScratchContext();
 
   CGContextSaveGState(cg);
 
   CGContextBeginPath(cg);
--- a/gfx/2d/PathCairo.cpp
+++ b/gfx/2d/PathCairo.cpp
@@ -171,41 +171,41 @@ PathCairo::CopyToBuilder(FillRule aFillR
 }
 
 already_AddRefed<PathBuilder>
 PathCairo::TransformedCopyToBuilder(const Matrix &aTransform, FillRule aFillRule) const
 {
   RefPtr<PathBuilderCairo> builder = new PathBuilderCairo(aFillRule);
 
   AppendPathToBuilder(builder, &aTransform);
-  builder->mCurrentPoint = aTransform * mCurrentPoint;
+  builder->mCurrentPoint = aTransform.TransformPoint(mCurrentPoint);
 
   return builder.forget();
 }
 
 bool
 PathCairo::ContainsPoint(const Point &aPoint, const Matrix &aTransform) const
 {
   Matrix inverse = aTransform;
   inverse.Invert();
-  Point transformed = inverse * aPoint;
+  Point transformed = inverse.TransformPoint(aPoint);
 
   EnsureContainingContext(aTransform);
 
   return cairo_in_fill(mContainingContext, transformed.x, transformed.y);
 }
 
 bool
 PathCairo::StrokeContainsPoint(const StrokeOptions &aStrokeOptions,
                                const Point &aPoint,
                                const Matrix &aTransform) const
 {
   Matrix inverse = aTransform;
   inverse.Invert();
-  Point transformed = inverse * aPoint;
+  Point transformed = inverse.TransformPoint(aPoint);
 
   EnsureContainingContext(aTransform);
 
   SetCairoStrokeOptions(mContainingContext, aStrokeOptions);
 
   return cairo_in_stroke(mContainingContext, transformed.x, transformed.y);
 }
 
@@ -308,17 +308,17 @@ PathCairo::AppendPathToBuilder(PathBuild
   if (aTransform) {
     size_t i = 0;
     while (i < mPathData.size()) {
       uint32_t pointCount = mPathData[i].header.length - 1;
       aBuilder->mPathData.push_back(mPathData[i]);
       i++;
       for (uint32_t c = 0; c < pointCount; c++) {
         cairo_path_data_t data;
-        Point newPoint = *aTransform * Point(mPathData[i].point.x, mPathData[i].point.y);
+        Point newPoint = aTransform->TransformPoint(Point(mPathData[i].point.x, mPathData[i].point.y));
         data.point.x = newPoint.x;
         data.point.y = newPoint.y;
         aBuilder->mPathData.push_back(data);
         i++;
       }
     }
   } else {
     for (size_t i = 0; i < mPathData.size(); i++) {
--- a/gfx/2d/PathD2D.cpp
+++ b/gfx/2d/PathD2D.cpp
@@ -416,17 +416,17 @@ PathD2D::TransformedCopyToBuilder(const 
   }
   if (FAILED(hr)) {
     gfxWarning() << "Failed to simplify PathGeometry to tranformed copy. Code: " << hexa(hr) << " Active: " << mEndedActive;
     return nullptr;
   }
 
   RefPtr<PathBuilderD2D> pathBuilder = new PathBuilderD2D(sink, path, aFillRule, mBackendType);
   
-  pathBuilder->mCurrentPoint = aTransform * mEndPoint;
+  pathBuilder->mCurrentPoint = aTransform.TransformPoint(mEndPoint);
   
   if (mEndedActive) {
     pathBuilder->mFigureActive = true;
   }
 
   return pathBuilder.forget();
 }
 
--- a/gfx/2d/PathHelpers.h
+++ b/gfx/2d/PathHelpers.h
@@ -36,17 +36,19 @@ inline void PartialArcToBezier(T* aSink,
                                Float aKappaFactor = kKappaFactor)
 {
   Point cp1 =
     aStartOffset + Point(-aStartOffset.y, aStartOffset.x) * aKappaFactor;
 
   Point cp2 =
     aEndOffset + Point(aEndOffset.y, -aEndOffset.x) * aKappaFactor;
 
-  aSink->BezierTo(aTransform * cp1, aTransform * cp2, aTransform * aEndOffset);
+  aSink->BezierTo(aTransform.TransformPoint(cp1),
+                  aTransform.TransformPoint(cp2),
+                  aTransform.TransformPoint(aEndOffset));
 }
 
 /**
  * Draws an acute arc (<= 90 degrees) given exact start and end points.
  * Specialized version avoiding kappa calculation.
  */
 template <typename T>
 inline void AcuteArcToBezier(T* aSink,
@@ -105,17 +107,17 @@ void ArcToBezier(T* aSink, const Point &
 
   Float currentStartAngle = aStartAngle;
   Point currentStartOffset(cosf(aStartAngle), sinf(aStartAngle));
   Matrix transform = Matrix::Scaling(aRadius.width, aRadius.height);
   if (aRotation != 0.0f) {
     transform *= Matrix::Rotation(aRotation);
   }
   transform.PostTranslate(aOrigin);
-  aSink->LineTo(transform * currentStartOffset);
+  aSink->LineTo(transform.TransformPoint(currentStartOffset));
 
   while (arcSweepLeft > 0) {
     Float currentEndAngle =
       currentStartAngle + std::min(arcSweepLeft, Float(M_PI / 2.0f)) * sweepDirection;
     Point currentEndOffset(cosf(currentEndAngle), sinf(currentEndAngle));
 
     PartialArcToBezier(aSink, currentStartOffset, currentEndOffset, transform,
                        ComputeKappaFactor(currentEndAngle - currentStartAngle));
@@ -132,17 +134,17 @@ void ArcToBezier(T* aSink, const Point &
  * inlined which vastly simplifies it and avoids a bunch of transcedental function
  * calls which should make it faster. */
 template <typename T>
 void EllipseToBezier(T* aSink, const Point &aOrigin, const Size &aRadius)
 {
   Matrix transform(aRadius.width, 0, 0, aRadius.height, aOrigin.x, aOrigin.y);
   Point currentStartOffset(1, 0);
 
-  aSink->LineTo(transform * currentStartOffset);
+  aSink->LineTo(transform.TransformPoint(currentStartOffset));
 
   for (int i = 0; i < 4; i++) {
     // cos(x+pi/2) == -sin(x)
     // sin(x+pi/2) == cos(x)
     Point currentEndOffset(-currentStartOffset.y, currentStartOffset.x);
 
     PartialArcToBezier(aSink, currentStartOffset, currentEndOffset, transform);
 
@@ -358,19 +360,19 @@ inline bool UserToDevicePixelSnapped(Rec
   if (!aAllowScaleOr90DegreeRotate &&
       (!WITHIN_E(mat._11, 1.f) || !WITHIN_E(mat._22, 1.f) ||
        !WITHIN_E(mat._12, 0.f) || !WITHIN_E(mat._21, 0.f))) {
     // We have non-translation, but only translation is allowed.
     return false;
   }
 #undef WITHIN_E
 
-  Point p1 = mat * aRect.TopLeft();
-  Point p2 = mat * aRect.TopRight();
-  Point p3 = mat * aRect.BottomRight();
+  Point p1 = mat.TransformPoint(aRect.TopLeft());
+  Point p2 = mat.TransformPoint(aRect.TopRight());
+  Point p3 = mat.TransformPoint(aRect.BottomRight());
 
   // Check that the rectangle is axis-aligned. For an axis-aligned rectangle,
   // two opposite corners define the entire rectangle. So check if
   // the axis-aligned rectangle with opposite corners p1 and p3
   // define an axis-aligned rectangle whose other corners are p2 and p4.
   // We actually only need to check one of p2 and p4, since an affine
   // transform maps parallelograms to parallelograms.
   if (p2 == Point(p1.x, p3.y) || p2 == Point(p3.x, p1.y)) {
--- a/gfx/2d/PathRecording.cpp
+++ b/gfx/2d/PathRecording.cpp
@@ -98,23 +98,23 @@ PathRecording::TransformedCopyToBuilder(
 {
   RefPtr<PathBuilder> pathBuilder = mPath->TransformedCopyToBuilder(aTransform, aFillRule);
   RefPtr<PathBuilderRecording> recording = new PathBuilderRecording(pathBuilder, aFillRule);
   typedef std::vector<PathOp> pathOpVec;
   for (pathOpVec::const_iterator iter = mPathOps.begin(); iter != mPathOps.end(); iter++) {
     PathOp newPathOp;
     newPathOp.mType = iter->mType;
     if (sPointCount[newPathOp.mType] >= 1) {
-      newPathOp.mP1 = aTransform * iter->mP1;
+      newPathOp.mP1 = aTransform.TransformPoint(iter->mP1);
     }
     if (sPointCount[newPathOp.mType] >= 2) {
-      newPathOp.mP2 = aTransform * iter->mP2;
+      newPathOp.mP2 = aTransform.TransformPoint(iter->mP2);
     }
     if (sPointCount[newPathOp.mType] >= 3) {
-      newPathOp.mP3 = aTransform * iter->mP3;
+      newPathOp.mP3 = aTransform.TransformPoint(iter->mP3);
     }
     recording->mPathOps.push_back(newPathOp);
   }
   return recording.forget();
 }
 
 } // namespace gfx
 } // namespace mozilla
--- a/gfx/2d/PathSkia.cpp
+++ b/gfx/2d/PathSkia.cpp
@@ -129,17 +129,17 @@ PathSkia::TransformedCopyToBuilder(const
 static bool
 SkPathContainsPoint(const SkPath& aPath, const Point& aPoint, const Matrix& aTransform)
 {
   Matrix inverse = aTransform;
   if (!inverse.Invert()) {
     return false;
   }
 
-  SkPoint point = PointToSkPoint(inverse * aPoint);
+  SkPoint point = PointToSkPoint(inverse.TransformPoint(aPoint));
   return aPath.contains(point.fX, point.fY);
 }
 
 bool
 PathSkia::ContainsPoint(const Point &aPoint, const Matrix &aTransform) const
 {
   if (!mPath.isFinite()) {
     return false;
--- a/gfx/2d/ScaledFontDWrite.h
+++ b/gfx/2d/ScaledFontDWrite.h
@@ -18,49 +18,54 @@ class ScaledFontDWrite final : public Sc
 {
 public:
   MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(ScaledFontDwrite)
   ScaledFontDWrite(IDWriteFontFace *aFont, Float aSize)
     : ScaledFontBase(aSize)
     , mFont(nullptr)
     , mFontFamily(nullptr)
     , mFontFace(aFont)
+    , mUseEmbeddedBitmap(false)
   {}
 
   ScaledFontDWrite(IDWriteFont* aFont, IDWriteFontFamily* aFontFamily,
-                   IDWriteFontFace *aFontFace, Float aSize)
+                   IDWriteFontFace *aFontFace, Float aSize, bool aUseEmbeddedBitmap)
     : ScaledFontBase(aSize)
     , mFont(aFont)
     , mFontFamily(aFontFamily)
     , mFontFace(aFontFace)
+    , mUseEmbeddedBitmap(aUseEmbeddedBitmap)
   {}
 
   virtual FontType GetType() const { return FontType::DWRITE; }
 
   virtual already_AddRefed<Path> GetPathForGlyphs(const GlyphBuffer &aBuffer, const DrawTarget *aTarget);
   virtual void CopyGlyphsToBuilder(const GlyphBuffer &aBuffer, PathBuilder *aBuilder, BackendType aBackendType, const Matrix *aTransformHint);
 
   void CopyGlyphsToSink(const GlyphBuffer &aBuffer, ID2D1GeometrySink *aSink);
 
   virtual void GetGlyphDesignMetrics(const uint16_t* aGlyphIndices, uint32_t aNumGlyphs, GlyphMetrics* aGlyphMetrics);
 
   virtual bool GetFontFileData(FontFileDataOutput aDataCallback, void *aBaton);
 
   virtual AntialiasMode GetDefaultAAMode() override;
 
+  bool UseEmbeddedBitmaps() { return mUseEmbeddedBitmap; }
+
 #ifdef USE_SKIA
   virtual SkTypeface* GetSkTypeface();
   bool GetFontDataFromSystemFonts(IDWriteFactory* aFactory);
   bool DefaultToArialFont(IDWriteFontCollection* aSystemFonts);
 #endif
 
   // The font and font family are only used with Skia
   RefPtr<IDWriteFont> mFont;
   RefPtr<IDWriteFontFamily> mFontFamily;
   RefPtr<IDWriteFontFace> mFontFace;
+  bool mUseEmbeddedBitmap;
 
 protected:
 #ifdef USE_CAIRO_SCALED_FONT
   cairo_font_face_t* GetCairoFontFace() override;
 #endif
 };
 
 class GlyphRenderingOptionsDWrite : public GlyphRenderingOptions
--- a/gfx/gl/GLContextFeatures.cpp
+++ b/gfx/gl/GLContextFeatures.cpp
@@ -119,17 +119,17 @@ static const FeatureInfo sFeatureInfoArr
             // Intentionally avoid putting ANGLE_depth_texture here,
             // it does not offer quite the same functionality.
             GLContext::Extensions_End
         }
     },
     {
         "draw_buffers",
         GLVersion::GL2,
-        GLESVersion::NONE,
+        GLESVersion::ES3,
         GLContext::Extension_None,
         {
             GLContext::ARB_draw_buffers,
             GLContext::EXT_draw_buffers,
             GLContext::Extensions_End
         }
     },
     {
--- a/gfx/layers/LayerSorter.cpp
+++ b/gfx/layers/LayerSorter.cpp
@@ -41,17 +41,17 @@ enum LayerSortOrder {
  * We want to solve:
  *
  * point = normal . (p0 - l0) / normal . l
  */
 static gfxFloat RecoverZDepth(const Matrix4x4& aTransform, const gfxPoint& aPoint)
 {
     const Point3D l(0, 0, 1);
     Point3D l0 = Point3D(aPoint.x, aPoint.y, 0);
-    Point3D p0 = aTransform * Point3D(0, 0, 0);
+    Point3D p0 = aTransform.TransformPoint(Point3D(0, 0, 0));
     Point3D normal = aTransform.GetNormalVector();
 
     gfxFloat n = normal.DotProduct(p0 - l0); 
     gfxFloat d = normal.DotProduct(l);
 
     if (!d) {
         return 0;
     }
--- a/gfx/layers/Layers.cpp
+++ b/gfx/layers/Layers.cpp
@@ -682,17 +682,17 @@ Layer::SnapTransformTranslation(const Ma
     // don't snap it.
     // For a perspective transform, the content is transformed in
     // non-linear, so we don't snap it too.
     return aTransform;
   }
 
   // Snap for 3D Transforms
 
-  Point3D transformedOrigin = aTransform * Point3D();
+  Point3D transformedOrigin = aTransform.TransformPoint(Point3D());
 
   // Compute the transformed snap by rounding the values of
   // transformed origin.
   auto transformedSnapXY = IntPoint::Round(transformedOrigin.x, transformedOrigin.y);
   Matrix4x4 inverse = aTransform;
   inverse.Invert();
   // see Matrix4x4::ProjectPoint()
   Float transformedSnapZ =
@@ -701,17 +701,17 @@ Layer::SnapTransformTranslation(const Ma
                               inverse._43) / inverse._33);
   Point3D transformedSnap =
     Point3D(transformedSnapXY.x, transformedSnapXY.y, transformedSnapZ);
   if (transformedOrigin == transformedSnap) {
     return aTransform;
   }
 
   // Compute the snap from the transformed snap.
-  Point3D snap = inverse * transformedSnap;
+  Point3D snap = inverse.TransformPoint(transformedSnap);
   if (snap.z > 0.001 || snap.z < -0.001) {
     // Allow some level of accumulated computation error.
     MOZ_ASSERT(inverse._33 == 0.0);
     return aTransform;
   }
 
   // The difference between the origin and snap is the residual transform.
   if (aResidualTransform) {
@@ -744,19 +744,19 @@ Layer::SnapTransform(const Matrix4x4& aT
   }
 
   Matrix matrix2D;
   Matrix4x4 result;
   if (mManager->IsSnappingEffectiveTransforms() &&
       aTransform.Is2D(&matrix2D) &&
       gfxSize(1.0, 1.0) <= aSnapRect.Size() &&
       matrix2D.PreservesAxisAlignedRectangles()) {
-    auto transformedTopLeft = IntPoint::Round(matrix2D * ToPoint(aSnapRect.TopLeft()));
-    auto transformedTopRight = IntPoint::Round(matrix2D * ToPoint(aSnapRect.TopRight()));
-    auto transformedBottomRight = IntPoint::Round(matrix2D * ToPoint(aSnapRect.BottomRight()));
+    auto transformedTopLeft = IntPoint::Round(matrix2D.TransformPoint(ToPoint(aSnapRect.TopLeft())));
+    auto transformedTopRight = IntPoint::Round(matrix2D.TransformPoint(ToPoint(aSnapRect.TopRight())));
+    auto transformedBottomRight = IntPoint::Round(matrix2D.TransformPoint(ToPoint(aSnapRect.BottomRight())));
 
     Matrix snappedMatrix = gfxUtils::TransformRectToRect(aSnapRect,
       transformedTopLeft, transformedTopRight, transformedBottomRight);
 
     result = Matrix4x4::From2D(snappedMatrix);
     if (aResidualTransform && !snappedMatrix.IsSingular()) {
       // set aResidualTransform so that aResidual * snappedMatrix == matrix2D.
       // (i.e., appying snappedMatrix after aResidualTransform gives the
--- a/gfx/layers/Layers.h
+++ b/gfx/layers/Layers.h
@@ -1973,22 +1973,21 @@ public:
         mAllowResidualTranslation ? &residual : nullptr);
     // The residual can only be a translation because SnapTransformTranslation
     // only changes the transform if it's a translation
     NS_ASSERTION(residual.IsTranslation(),
                  "Residual transform can only be a translation");
     if (!gfx::ThebesPoint(residual.GetTranslation()).WithinEpsilonOf(mResidualTranslation, 1e-3f)) {
       mResidualTranslation = gfx::ThebesPoint(residual.GetTranslation());
       DebugOnly<mozilla::gfx::Point> transformedOrig =
-        idealTransform * mozilla::gfx::Point();
+        idealTransform.TransformPoint(mozilla::gfx::Point());
 #ifdef DEBUG
-      DebugOnly<mozilla::gfx::Point> transformed =
-        idealTransform * mozilla::gfx::Point(mResidualTranslation.x,
-                                             mResidualTranslation.y) -
-        *&transformedOrig;
+      DebugOnly<mozilla::gfx::Point> transformed = idealTransform.TransformPoint(
+        mozilla::gfx::Point(mResidualTranslation.x, mResidualTranslation.y)
+      ) - *&transformedOrig;
 #endif
       NS_ASSERTION(-0.5 <= (&transformed)->x && (&transformed)->x < 0.5 &&
                    -0.5 <= (&transformed)->y && (&transformed)->y < 0.5,
                    "Residual translation out of range");
       mValidRegion.SetEmpty();
     }
     ComputeEffectiveTransformForMaskLayers(aTransformToSurface);
   }
--- a/gfx/layers/apz/test/gtest/TestHitTesting.cpp
+++ b/gfx/layers/apz/test/gtest/TestHitTesting.cpp
@@ -116,49 +116,49 @@ TEST_F(APZHitTestingTester, HitTesting1)
   uint32_t paintSequenceNumber = 0;
 
   // Now we have a root APZC that will match the page
   SetScrollableFrameMetrics(root, FrameMetrics::START_SCROLL_ID);
   manager->UpdateHitTestingTree(nullptr, root, false, 0, paintSequenceNumber++);
   hit = GetTargetAPZC(ScreenPoint(15, 15));
   EXPECT_EQ(ApzcOf(root), hit.get());
   // expect hit point at LayerIntPoint(15, 15)
-  EXPECT_EQ(ParentLayerPoint(15, 15), transformToApzc * ScreenPoint(15, 15));
-  EXPECT_EQ(ScreenPoint(15, 15), transformToGecko * ParentLayerPoint(15, 15));
+  EXPECT_EQ(ParentLayerPoint(15, 15), transformToApzc.TransformPoint(ScreenPoint(15, 15)));
+  EXPECT_EQ(ScreenPoint(15, 15), transformToGecko.TransformPoint(ParentLayerPoint(15, 15)));
 
   // Now we have a sub APZC with a better fit
   SetScrollableFrameMetrics(layers[3], FrameMetrics::START_SCROLL_ID + 1);
   manager->UpdateHitTestingTree(nullptr, root, false, 0, paintSequenceNumber++);
   EXPECT_NE(ApzcOf(root), ApzcOf(layers[3]));
   hit = GetTargetAPZC(ScreenPoint(25, 25));
   EXPECT_EQ(ApzcOf(layers[3]), hit.get());
   // expect hit point at LayerIntPoint(25, 25)
-  EXPECT_EQ(ParentLayerPoint(25, 25), transformToApzc * ScreenPoint(25, 25));
-  EXPECT_EQ(ScreenPoint(25, 25), transformToGecko * ParentLayerPoint(25, 25));
+  EXPECT_EQ(ParentLayerPoint(25, 25), transformToApzc.TransformPoint(ScreenPoint(25, 25)));
+  EXPECT_EQ(ScreenPoint(25, 25), transformToGecko.TransformPoint(ParentLayerPoint(25, 25)));
 
   // At this point, layers[4] obscures layers[3] at the point (15, 15) so
   // hitting there should hit the root APZC
   hit = GetTargetAPZC(ScreenPoint(15, 15));
   EXPECT_EQ(ApzcOf(root), hit.get());
 
   // Now test hit testing when we have two scrollable layers
   SetScrollableFrameMetrics(layers[4], FrameMetrics::START_SCROLL_ID + 2);
   manager->UpdateHitTestingTree(nullptr, root, false, 0, paintSequenceNumber++);
   hit = GetTargetAPZC(ScreenPoint(15, 15));
   EXPECT_EQ(ApzcOf(layers[4]), hit.get());
   // expect hit point at LayerIntPoint(15, 15)
-  EXPECT_EQ(ParentLayerPoint(15, 15), transformToApzc * ScreenPoint(15, 15));
-  EXPECT_EQ(ScreenPoint(15, 15), transformToGecko * ParentLayerPoint(15, 15));
+  EXPECT_EQ(ParentLayerPoint(15, 15), transformToApzc.TransformPoint(ScreenPoint(15, 15)));
+  EXPECT_EQ(ScreenPoint(15, 15), transformToGecko.TransformPoint(ParentLayerPoint(15, 15)));
 
   // Hit test ouside the reach of layer[3,4] but inside root
   hit = GetTargetAPZC(ScreenPoint(90, 90));
   EXPECT_EQ(ApzcOf(root), hit.get());
   // expect hit point at LayerIntPoint(90, 90)
-  EXPECT_EQ(ParentLayerPoint(90, 90), transformToApzc * ScreenPoint(90, 90));
-  EXPECT_EQ(ScreenPoint(90, 90), transformToGecko * ParentLayerPoint(90, 90));
+  EXPECT_EQ(ParentLayerPoint(90, 90), transformToApzc.TransformPoint(ScreenPoint(90, 90)));
+  EXPECT_EQ(ScreenPoint(90, 90), transformToGecko.TransformPoint(ParentLayerPoint(90, 90)));
 
   // Hit test ouside the reach of any layer
   hit = GetTargetAPZC(ScreenPoint(1000, 10));
   EXPECT_EQ(nullAPZC, hit.get());
   EXPECT_EQ(ScreenToParentLayerMatrix4x4(), transformToApzc);
   EXPECT_EQ(ParentLayerToScreenMatrix4x4(), transformToGecko);
   hit = GetTargetAPZC(ScreenPoint(-1000, 10));
   EXPECT_EQ(nullAPZC, hit.get());
@@ -183,103 +183,103 @@ TEST_F(APZHitTestingTester, HitTesting2)
 
   TestAsyncPanZoomController* apzcroot = ApzcOf(root);
   TestAsyncPanZoomController* apzc1 = ApzcOf(layers[1]);
   TestAsyncPanZoomController* apzc3 = ApzcOf(layers[3]);
 
   // Hit an area that's clearly on the root layer but not any of the child layers.
   RefPtr<AsyncPanZoomController> hit = GetTargetAPZC(ScreenPoint(75, 25));
   EXPECT_EQ(apzcroot, hit.get());
-  EXPECT_EQ(ParentLayerPoint(75, 25), transformToApzc * ScreenPoint(75, 25));
-  EXPECT_EQ(ScreenPoint(75, 25), transformToGecko * ParentLayerPoint(75, 25));
+  EXPECT_EQ(ParentLayerPoint(75, 25), transformToApzc.TransformPoint(ScreenPoint(75, 25)));
+  EXPECT_EQ(ScreenPoint(75, 25), transformToGecko.TransformPoint(ParentLayerPoint(75, 25)));
 
   // Hit an area on the root that would be on layers[3] if layers[2]
   // weren't transformed.
   // Note that if layers[2] were scrollable, then this would hit layers[2]
   // because its composition bounds would be at (10,60)-(50,100) (and the
   // scale-only transform that we set on layers[2] would be invalid because
   // it would place the layer into overscroll, as its composition bounds
   // start at x=10 but its content at x=20).
   hit = GetTargetAPZC(ScreenPoint(15, 75));
   EXPECT_EQ(apzcroot, hit.get());
-  EXPECT_EQ(ParentLayerPoint(15, 75), transformToApzc * ScreenPoint(15, 75));
-  EXPECT_EQ(ScreenPoint(15, 75), transformToGecko * ParentLayerPoint(15, 75));
+  EXPECT_EQ(ParentLayerPoint(15, 75), transformToApzc.TransformPoint(ScreenPoint(15, 75)));
+  EXPECT_EQ(ScreenPoint(15, 75), transformToGecko.TransformPoint(ParentLayerPoint(15, 75)));
 
   // Hit an area on layers[1].
   hit = GetTargetAPZC(ScreenPoint(25, 25));
   EXPECT_EQ(apzc1, hit.get());
-  EXPECT_EQ(ParentLayerPoint(25, 25), transformToApzc * ScreenPoint(25, 25));
-  EXPECT_EQ(ScreenPoint(25, 25), transformToGecko * ParentLayerPoint(25, 25));
+  EXPECT_EQ(ParentLayerPoint(25, 25), transformToApzc.TransformPoint(ScreenPoint(25, 25)));
+  EXPECT_EQ(ScreenPoint(25, 25), transformToGecko.TransformPoint(ParentLayerPoint(25, 25)));
 
   // Hit an area on layers[3].
   hit = GetTargetAPZC(ScreenPoint(25, 75));
   EXPECT_EQ(apzc3, hit.get());
   // transformToApzc should unapply layers[2]'s transform
-  EXPECT_EQ(ParentLayerPoint(12.5, 75), transformToApzc * ScreenPoint(25, 75));
+  EXPECT_EQ(ParentLayerPoint(12.5, 75), transformToApzc.TransformPoint(ScreenPoint(25, 75)));
   // and transformToGecko should reapply it
-  EXPECT_EQ(ScreenPoint(25, 75), transformToGecko * ParentLayerPoint(12.5, 75));
+  EXPECT_EQ(ScreenPoint(25, 75), transformToGecko.TransformPoint(ParentLayerPoint(12.5, 75)));
 
   // Hit an area on layers[3] that would be on the root if layers[2]
   // weren't transformed.
   hit = GetTargetAPZC(ScreenPoint(75, 75));
   EXPECT_EQ(apzc3, hit.get());
   // transformToApzc should unapply layers[2]'s transform
-  EXPECT_EQ(ParentLayerPoint(37.5, 75), transformToApzc * ScreenPoint(75, 75));
+  EXPECT_EQ(ParentLayerPoint(37.5, 75), transformToApzc.TransformPoint(ScreenPoint(75, 75)));
   // and transformToGecko should reapply it
-  EXPECT_EQ(ScreenPoint(75, 75), transformToGecko * ParentLayerPoint(37.5, 75));
+  EXPECT_EQ(ScreenPoint(75, 75), transformToGecko.TransformPoint(ParentLayerPoint(37.5, 75)));
 
   // Pan the root layer upward by 50 pixels.
   // This causes layers[1] to scroll out of view, and an async transform
   // of -50 to be set on the root layer.
   EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(1);
 
   // This first pan will move the APZC by 50 pixels, and dispatch a paint request.
   // Since this paint request is in the queue to Gecko, transformToGecko will
   // take it into account.
   ApzcPanNoFling(apzcroot, 100, 50);
 
   // Hit where layers[3] used to be. It should now hit the root.
   hit = GetTargetAPZC(ScreenPoint(75, 75));
   EXPECT_EQ(apzcroot, hit.get());
   // transformToApzc doesn't unapply the root's own async transform
-  EXPECT_EQ(ParentLayerPoint(75, 75), transformToApzc * ScreenPoint(75, 75));
+  EXPECT_EQ(ParentLayerPoint(75, 75), transformToApzc.TransformPoint(ScreenPoint(75, 75)));
   // and transformToGecko unapplies it and then reapplies it, because by the
   // time the event being transformed reaches Gecko the new paint request will
   // have been handled.
-  EXPECT_EQ(ScreenPoint(75, 75), transformToGecko * ParentLayerPoint(75, 75));
+  EXPECT_EQ(ScreenPoint(75, 75), transformToGecko.TransformPoint(ParentLayerPoint(75, 75)));
 
   // Hit where layers[1] used to be and where layers[3] should now be.
   hit = GetTargetAPZC(ScreenPoint(25, 25));
   EXPECT_EQ(apzc3, hit.get());
   // transformToApzc unapplies both layers[2]'s css transform and the root's
   // async transform
-  EXPECT_EQ(ParentLayerPoint(12.5, 75), transformToApzc * ScreenPoint(25, 25));
+  EXPECT_EQ(ParentLayerPoint(12.5, 75), transformToApzc.TransformPoint(ScreenPoint(25, 25)));
   // transformToGecko reapplies both the css transform and the async transform
   // because we have already issued a paint request with it.
-  EXPECT_EQ(ScreenPoint(25, 25), transformToGecko * ParentLayerPoint(12.5, 75));
+  EXPECT_EQ(ScreenPoint(25, 25), transformToGecko.TransformPoint(ParentLayerPoint(12.5, 75)));
 
   // This second pan will move the APZC by another 50 pixels.
   EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(1);
   ApzcPanNoFling(apzcroot, 100, 50);
 
   // Hit where layers[3] used to be. It should now hit the root.
   hit = GetTargetAPZC(ScreenPoint(75, 75));
   EXPECT_EQ(apzcroot, hit.get());
   // transformToApzc doesn't unapply the root's own async transform
-  EXPECT_EQ(ParentLayerPoint(75, 75), transformToApzc * ScreenPoint(75, 75));
+  EXPECT_EQ(ParentLayerPoint(75, 75), transformToApzc.TransformPoint(ScreenPoint(75, 75)));
   // transformToGecko unapplies the full async transform of -100 pixels
-  EXPECT_EQ(ScreenPoint(75, 75), transformToGecko * ParentLayerPoint(75, 75));
+  EXPECT_EQ(ScreenPoint(75, 75), transformToGecko.TransformPoint(ParentLayerPoint(75, 75)));
 
   // Hit where layers[1] used to be. It should now hit the root.
   hit = GetTargetAPZC(ScreenPoint(25, 25));
   EXPECT_EQ(apzcroot, hit.get());
   // transformToApzc doesn't unapply the root's own async transform
-  EXPECT_EQ(ParentLayerPoint(25, 25), transformToApzc * ScreenPoint(25, 25));
+  EXPECT_EQ(ParentLayerPoint(25, 25), transformToApzc.TransformPoint(ScreenPoint(25, 25)));
   // transformToGecko unapplies the full async transform of -100 pixels
-  EXPECT_EQ(ScreenPoint(25, 25), transformToGecko * ParentLayerPoint(25, 25));
+  EXPECT_EQ(ScreenPoint(25, 25), transformToGecko.TransformPoint(ParentLayerPoint(25, 25)));
 }
 
 TEST_F(APZHitTestingTester, ComplexMultiLayerTree) {
   CreateComplexMultiLayerTree();
   ScopedLayerTreeRegistration registration(manager, 0, root, mcc);
   manager->UpdateHitTestingTree(nullptr, root, false, 0, 0);
 
   /* The layer tree looks like this:
--- a/gfx/layers/composite/AsyncCompositionManager.cpp
+++ b/gfx/layers/composite/AsyncCompositionManager.cpp
@@ -490,18 +490,18 @@ AsyncCompositionManager::AlignFixedAndSt
         LayerPoint offsetAnchor = anchor + GetLayerFixedMarginsOffset(layer, aFixedLayerMargins);
 
         // Additionally transform the anchor to compensate for the change
         // from the old cumulative transform to the new cumulative transform. We do
         // this by using the old transform to take the offset anchor back into
         // subtree root space, and then the inverse of the new cumulative transform
         // to bring it back to layer space.
         LayerPoint transformedAnchor = ViewAs<LayerPixel>(
-            newCumulativeTransform.Inverse() *
-            (oldCumulativeTransform * offsetAnchor.ToUnknownPoint()));
+            newCumulativeTransform.Inverse().TransformPoint(
+              (oldCumulativeTransform.TransformPoint(offsetAnchor.ToUnknownPoint()))));
 
         // We want to translate the layer by the difference between |transformedAnchor|
         // and |anchor|. To achieve this, we will add a translation to the layer's
         // transform. This translation will apply on top of the layer's local
         // transform, but |anchor| and |transformedAnchor| are in a coordinate space
         // where the local transform isn't applied yet, so apply it and then subtract
         // to get the desired translation.
         auto localTransformTyped = ViewAs<LayerToParentLayerMatrix4x4>(localTransform);
--- a/gfx/thebes/gfxAndroidPlatform.cpp
+++ b/gfx/thebes/gfxAndroidPlatform.cpp
@@ -309,25 +309,25 @@ gfxAndroidPlatform::GetScaledFontForFont
 }
 
 bool
 gfxAndroidPlatform::FontHintingEnabled()
 {
     // In "mobile" builds, we sometimes use non-reflow-zoom, so we
     // might not want hinting.  Let's see.
 
-#ifdef MOZ_USING_ANDROID_JAVA_WIDGETS
-    // On android-java, we currently only use gecko to render web
+#ifdef MOZ_WIDGET_ANDROID
+    // On Android, we currently only use gecko to render web
     // content that can always be be non-reflow-zoomed.  So turn off
     // hinting.
     // 
     // XXX when gecko-android-java is used as an "app runtime", we may
     // want to re-enable hinting for non-browser processes there.