Merge inbound to central, a=merge
authorWes Kocher <wkocher@mozilla.com>
Tue, 16 Aug 2016 17:05:30 -0700
changeset 309660 1a0e253638feaf6c149f01e65423f664087c5da7
parent 309659 52be5024e34261bcd08d68fda65379ed0ffd363d (current diff)
parent 309658 1eaa34d5dba1e3698785c7ffab4e5bd0f9529a0f (diff)
child 309661 ad3c62c42039ebc7997b4e92250b14c8689b1bf2
push id20328
push userkwierso@gmail.com
push dateWed, 17 Aug 2016 05:10:33 +0000
treeherderfx-team@72f11467d2cf [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone51.0a1
Merge inbound to central, a=merge a=release to get around the webidl hook for a comment-only change
accessible/ipc/DocAccessibleChild.cpp
accessible/ipc/DocAccessibleChild.h
accessible/ipc/PDocAccessible.ipdl
accessible/ipc/ProxyAccessible.cpp
accessible/ipc/ProxyAccessible.h
build/moz.configure/old.configure
dom/animation/AnimValuesStyleRule.h
dom/animation/KeyframeEffectParams.cpp
dom/ipc/ContentParent.cpp
js/src/jsobj.cpp
layout/style/Declaration.cpp
layout/style/Declaration.h
layout/style/StyleAnimationValue.cpp
layout/style/StyleAnimationValue.h
layout/style/nsCSSPropList.h
layout/style/nsCSSProperty.h
layout/style/nsCSSPropertySet.h
layout/style/nsCSSProps.cpp
layout/style/nsCSSProps.h
layout/style/nsComputedDOMStyle.cpp
layout/style/nsHTMLStyleSheet.cpp
layout/style/nsRuleNode.cpp
layout/style/nsRuleNode.h
layout/style/nsStyleContext.cpp
layout/style/nsStyleStruct.cpp
layout/style/nsStyleStruct.h
layout/style/nsTransitionManager.cpp
testing/web-platform/meta/MANIFEST.json
testing/web-platform/meta/dom/ranges/Range-insertNode.html.ini
testing/web-platform/meta/dom/ranges/Range-surroundContents.html.ini
testing/web-platform/meta/mixed-content/optionally-blockable/http-csp/cross-origin-http/link-prefetch-tag/top-level/keep-scheme-redirect/opt-in-blocks.https.html.ini
testing/web-platform/meta/mixed-content/optionally-blockable/http-csp/cross-origin-http/link-prefetch-tag/top-level/no-redirect/opt-in-blocks.https.html.ini
testing/web-platform/meta/mixed-content/optionally-blockable/http-csp/cross-origin-http/link-prefetch-tag/top-level/swap-scheme-redirect/opt-in-blocks.https.html.ini
testing/web-platform/meta/mixed-content/optionally-blockable/http-csp/same-host-http/link-prefetch-tag/top-level/keep-scheme-redirect/opt-in-blocks.https.html.ini
testing/web-platform/meta/mixed-content/optionally-blockable/http-csp/same-host-http/link-prefetch-tag/top-level/no-redirect/opt-in-blocks.https.html.ini
testing/web-platform/meta/mixed-content/optionally-blockable/http-csp/same-host-http/link-prefetch-tag/top-level/swap-scheme-redirect/opt-in-blocks.https.html.ini
testing/web-platform/meta/mixed-content/optionally-blockable/meta-csp/cross-origin-http/link-prefetch-tag/top-level/no-redirect/opt-in-blocks.https.html.ini
testing/web-platform/meta/mixed-content/optionally-blockable/meta-csp/same-host-http/link-prefetch-tag/top-level/no-redirect/opt-in-blocks.https.html.ini
toolkit/components/extensions/ExtensionUtils.jsm
xpcom/tests/TestPipe.cpp
--- a/CLOBBER
+++ b/CLOBBER
@@ -17,9 +17,9 @@
 #
 # Modifying this file will now automatically clobber the buildbot machines \o/
 #
 
 # Are you updating CLOBBER because you think it's needed for your WebIDL
 # changes to stick? As of bug 928195, this shouldn't be necessary! Please
 # don't change CLOBBER for WebIDL changes any more.
 
-Bug 1291229 - clobber due to changes in generated code (bug 1182840)
+Bug 1292323 - clobber due to changes in generated code (bug 1182840)
--- a/accessible/tests/mochitest/events/test_coalescence.html
+++ b/accessible/tests/mochitest/events/test_coalescence.html
@@ -315,17 +315,20 @@
     function removeGrandChildrenNHideParent(aChild1Id, aChild2Id, aParentId)
     {
       this.child1 = getNode(aChild1Id);
       this.child2 = getNode(aChild2Id);
       this.parent = getNode(aParentId);
 
       this.eventSeq = [
         new invokerChecker(EVENT_HIDE, getAccessible(aParentId)),
-        new invokerChecker(EVENT_REORDER, getNode(aParentId).parentNode)
+        new invokerChecker(EVENT_REORDER, getNode(aParentId).parentNode),
+        new unexpectedInvokerChecker(EVENT_HIDE, getAccessible(aChild1Id)),
+        new unexpectedInvokerChecker(EVENT_HIDE, getAccessible(aChild2Id)),
+        new unexpectedInvokerChecker(EVENT_REORDER, getAccessible(aParentId))
       ];
 
       this.invoke = function removeGrandChildrenNHideParent_invoke()
       {
         this.child1.parentNode.removeChild(this.child1);
         this.child2.parentNode.removeChild(this.child2);
         this.parent.hidden = true;
       }
--- a/addon-sdk/Makefile.in
+++ b/addon-sdk/Makefile.in
@@ -1,20 +1,20 @@
 # 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/.
 
 TESTADDONS = source/test/addons
 ADDONSRC = $(srcdir)/$(TESTADDONS)
 
-sinclude $(topsrcdir)/config/rules.mk
+include $(topsrcdir)/config/rules.mk
 
 # This can switch to just zipping the files when native jetpacks land
-$(TESTADDONS)/%.xpi: FORCE $(call mkdir_deps,$(CURDIR)/$(TESTADDONS)) $(ADDONSRC)/%
-	$(PYTHON) $(srcdir)/source/bin/cfx xpi --no-strip-xpi --pkgdir=$(lastword $^) --output-file=$@
+%.xpi: FORCE
+	$(PYTHON) $(srcdir)/source/bin/cfx xpi --no-strip-xpi --pkgdir=$(ADDONSRC)/$* --output-file=$@
 
 TEST_FILES = \
   $(srcdir)/source/app-extension \
   $(srcdir)/source/bin \
   $(srcdir)/source/python-lib \
   $(srcdir)/source/test \
   $(srcdir)/source/package.json \
   $(srcdir)/source/mapping.json \
--- a/addon-sdk/moz.build
+++ b/addon-sdk/moz.build
@@ -55,17 +55,17 @@ addons = [
     'simple-prefs',
     'standard-id',
     'tab-close-on-startup',
     'toolkit-require-reload',
     'translators',
     'unsafe-content-script',
 ]
 
-addons = ['source/test/addons/%s.xpi' % f for f in addons]
+addons = ['%s.xpi' % f for f in addons]
 GENERATED_FILES += addons
 
 TEST_HARNESS_FILES.testing.mochitest['jetpack-addon']['addon-sdk'].source.test.addons += [
     '!%s' % f for f in addons
 ]
 
 EXTRA_JS_MODULES.sdk += [
     'source/app-extension/bootstrap.js',
--- a/addon-sdk/source/app-extension/bootstrap.js
+++ b/addon-sdk/source/app-extension/bootstrap.js
@@ -1,13 +1,13 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-// @see http://mxr.mozilla.org/mozilla-central/source/js/src/xpconnect/loader/mozJSComponentLoader.cpp
+// @see http://dxr.mozilla.org/mozilla-central/source/js/src/xpconnect/loader/mozJSComponentLoader.cpp
 
 'use strict';
 
 // IMPORTANT: Avoid adding any initialization tasks here, if you need to do
 // something before add-on is loaded consider addon/runner module instead!
 
 const { classes: Cc, Constructor: CC, interfaces: Ci, utils: Cu,
         results: Cr, manager: Cm } = Components;
--- a/addon-sdk/source/lib/sdk/keyboard/hotkeys.js
+++ b/addon-sdk/source/lib/sdk/keyboard/hotkeys.js
@@ -79,17 +79,17 @@ keyboardObserver.on("keydown", function 
     modifiers.push("alt");
   if ("ctrlKey" in event && event.ctrlKey)
     modifiers.push("control");
   if ("metaKey" in event && event.metaKey)
     modifiers.push("meta");
 
   // If it's not a printable character then we fall back to a human readable
   // equivalent of one of the following constants.
-  // http://mxr.mozilla.org/mozilla-central/source/dom/interfaces/events/nsIDOMKeyEvent.idl
+  // http://dxr.mozilla.org/mozilla-central/source/dom/interfaces/events/nsIDOMKeyEvent.idl
   key = getKeyForCode(keyCode);
 
   // If only non-function (f1 - f24) key or only modifiers are pressed we don't
   // have a valid combination so we return immediately (Also, sometimes
   // `keyCode` may be one for the modifier which means we do not have a
   // modifier).
   if (!key || (!isFunctionKey(key) && !modifiers.length) || key in MODIFIERS)
     return;
--- a/addon-sdk/source/lib/sdk/keyboard/utils.js
+++ b/addon-sdk/source/lib/sdk/keyboard/utils.js
@@ -28,17 +28,17 @@ const MODIFIERS = exports.MODIFIERS = {
   'option': 'alt',
   'command': 'meta',
   'alt': 'alt',
   'shift': 'shift'
 };
 
 // Hash of key:code pairs for all the chars supported by `nsIDOMKeyEvent`.
 // This is just a copy of the `nsIDOMKeyEvent` hash with normalized names.
-// @See: http://mxr.mozilla.org/mozilla-central/source/dom/interfaces/events/nsIDOMKeyEvent.idl
+// @See: http://dxr.mozilla.org/mozilla-central/source/dom/interfaces/events/nsIDOMKeyEvent.idl
 const CODES = exports.CODES = new function Codes() {
   let nsIDOMKeyEvent = Ci.nsIDOMKeyEvent;
   // Names that will be substituted with a shorter analogs.
   let aliases = {
     'subtract':     '-',
     'add':          '+',
     'equals':       '=',
     'slash':        '/',
--- a/addon-sdk/source/lib/sdk/l10n/locale.js
+++ b/addon-sdk/source/lib/sdk/l10n/locale.js
@@ -72,17 +72,17 @@ exports.getPreferedLocales = getPrefered
  * @param  aLocales
  *         An array of available locales
  * @param  aMatchLocales
  *         An array of prefered locales, ordered by priority. Most wanted first.
  *         Locales have to be in lowercase.
  *         If null, uses getPreferedLocales() results
  * @return the best match for the currently selected locale
  *
- * Stolen from http://mxr.mozilla.org/mozilla-central/source/toolkit/mozapps/extensions/internal/XPIProvider.jsm
+ * Stolen from http://dxr.mozilla.org/mozilla-central/source/toolkit/mozapps/extensions/internal/XPIProvider.jsm
  */
 exports.findClosestLocale = function findClosestLocale(aLocales, aMatchLocales) {
   aMatchLocales = aMatchLocales || getPreferedLocales();
 
   // Holds the best matching localized resource
   let bestmatch = null;
   // The number of locale parts it matched with
   let bestmatchcount = 0;
--- a/addon-sdk/source/lib/sdk/system.js
+++ b/addon-sdk/source/lib/sdk/system.js
@@ -94,17 +94,17 @@ exports.exit = function exit(code) {
 var stdout = Object.freeze({ write: dump, end: dump });
 exports.stdout = stdout;
 exports.stderr = stdout;
 
 /**
  * Returns a path of the system's or application's special directory / file
  * associated with a given `id`. For list of possible `id`s please see:
  * https://developer.mozilla.org/en-US/docs/Code_snippets/File_I_O#Getting_files_in_special_directories
- * http://mxr.mozilla.org/mozilla-central/source/xpcom/io/nsAppDirectoryServiceDefs.h
+ * http://dxr.mozilla.org/mozilla-central/source/xpcom/io/nsAppDirectoryServiceDefs.h
  * @example
  *
  *    // get firefox profile path
  *    let profilePath = require('system').pathFor('ProfD');
  *    // get OS temp files directory (/tmp)
  *    let temps = require('system').pathFor('TmpD');
  *    // get OS desktop path for an active user (~/Desktop on linux
  *    // or C:\Documents and Settings\username\Desktop on windows).
--- a/addon-sdk/source/python-lib/cuddlefish/prefs.py
+++ b/addon-sdk/source/python-lib/cuddlefish/prefs.py
@@ -119,17 +119,17 @@ DEFAULT_FIREFOX_PREFS = {
     'browser.safebrowsing.provider.google.gethashURL' : 'http://localhost/safebrowsing-dummy/gethash',
     'browser.safebrowsing.provider.google.updateURL' : 'http://localhost/safebrowsing-dummy/update',
     'browser.safebrowsing.provider.mozilla.gethashURL': 'http://localhost/safebrowsing-dummy/gethash',
     'browser.safebrowsing.provider.mozilla.updateURL': 'http://localhost/safebrowsing-dummy/update',
 }
 
 # When launching a temporary new Thunderbird profile, use these preferences.
 # Note that these were taken from:
-# http://mxr.mozilla.org/comm-central/source/mail/test/mozmill/runtest.py
+# http://dxr.mozilla.org/comm-central/source/mail/test/mozmill/runtest.py
 DEFAULT_THUNDERBIRD_PREFS = {
     # say no to slow script warnings
     'dom.max_chrome_script_run_time': 200,
     'dom.max_script_run_time': 0,
     # do not ask about being the default mail client
     'mail.shell.checkDefaultClient': False,
     # disable non-gloda indexing daemons
     'mail.winsearch.enable': False,
--- a/addon-sdk/source/python-lib/cuddlefish/version_comparator.py
+++ b/addon-sdk/source/python-lib/cuddlefish/version_comparator.py
@@ -5,17 +5,17 @@
 '''
     This is a really crummy, slow Python implementation of the Mozilla
     platform's nsIVersionComparator interface:
 
       https://developer.mozilla.org/En/NsIVersionComparator
 
     For more information, also see:
 
-      http://mxr.mozilla.org/mozilla/source/xpcom/glue/nsVersionComparator.cpp
+      http://dxr.mozilla.org/mozilla-central/source/xpcom/glue/nsVersionComparator.cpp
 '''
 
 import re
 import sys
 
 class VersionPart(object):
     '''
     Examples:
--- a/addon-sdk/source/test/addons/l10n-properties/app-extension/bootstrap.js
+++ b/addon-sdk/source/test/addons/l10n-properties/app-extension/bootstrap.js
@@ -1,13 +1,13 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-// @see http://mxr.mozilla.org/mozilla-central/source/js/src/xpconnect/loader/mozJSComponentLoader.cpp
+// @see http://dxr.mozilla.org/mozilla-central/source/js/src/xpconnect/loader/mozJSComponentLoader.cpp
 
 'use strict';
 
 // IMPORTANT: Avoid adding any initialization tasks here, if you need to do
 // something before add-on is loaded consider addon/runner module instead!
 
 const { classes: Cc, Constructor: CC, interfaces: Ci, utils: Cu,
         results: Cr, manager: Cm } = Components;
--- a/addon-sdk/source/test/addons/simple-prefs-regression/app-extension/bootstrap.js
+++ b/addon-sdk/source/test/addons/simple-prefs-regression/app-extension/bootstrap.js
@@ -1,13 +1,13 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-// @see http://mxr.mozilla.org/mozilla-central/source/js/src/xpconnect/loader/mozJSComponentLoader.cpp
+// @see http://dxr.mozilla.org/mozilla-central/source/js/src/xpconnect/loader/mozJSComponentLoader.cpp
 
 'use strict';
 
 // IMPORTANT: Avoid adding any initialization tasks here, if you need to do
 // something before add-on is loaded consider addon/runner module instead!
 
 const { classes: Cc, Constructor: CC, interfaces: Ci, utils: Cu,
         results: Cr, manager: Cm } = Components;
--- a/b2g/graphene/config/horizon-mozconfigs/win64/debug
+++ b/b2g/graphene/config/horizon-mozconfigs/win64/debug
@@ -5,23 +5,16 @@ MOZ_AUTOMATION_L10N_CHECK=0
 ac_add_options --target=x86_64-pc-mingw32
 ac_add_options --host=x86_64-pc-mingw32
 
 ac_add_options --enable-debug
 ac_add_options --enable-dmd
 ac_add_options --enable-profiling  # needed for --enable-dmd to work on Windows
 ac_add_options --enable-signmar
 
-if [ -f /c/builds/google-oauth-api.key ]; then
-  _google_oauth_api_keyfile=/c/builds/google-oauth-api.key
-else
-  _google_oauth_api_keyfile=/e/builds/google-oauth-api.key
-fi
-ac_add_options --with-google-oauth-api-keyfile=${_google_oauth_api_keyfile}
-
 # Needed to enable breakpad in application.ini
 export MOZILLA_OFFICIAL=1
 
 # Package js shell.
 export MOZ_PACKAGE_JSSHELL=1
 
 . $topsrcdir/build/win64/mozconfig.vs-latest
 
--- a/b2g/graphene/config/mozconfigs/win64/debug
+++ b/b2g/graphene/config/mozconfigs/win64/debug
@@ -5,23 +5,16 @@ MOZ_AUTOMATION_L10N_CHECK=0
 ac_add_options --target=x86_64-pc-mingw32
 ac_add_options --host=x86_64-pc-mingw32
 
 ac_add_options --enable-debug
 ac_add_options --enable-dmd
 ac_add_options --enable-profiling  # needed for --enable-dmd to work on Windows
 ac_add_options --enable-signmar
 
-if [ -f /c/builds/google-oauth-api.key ]; then
-  _google_oauth_api_keyfile=/c/builds/google-oauth-api.key
-else
-  _google_oauth_api_keyfile=/e/builds/google-oauth-api.key
-fi
-ac_add_options --with-google-oauth-api-keyfile=${_google_oauth_api_keyfile}
-
 # Needed to enable breakpad in application.ini
 export MOZILLA_OFFICIAL=1
 
 # Package js shell.
 export MOZ_PACKAGE_JSSHELL=1
 
 . $topsrcdir/build/win64/mozconfig.vs-latest
 
--- a/b2g/graphene/graphene.js
+++ b/b2g/graphene/graphene.js
@@ -1,9 +1,9 @@
-// See http://mxr.mozilla.org/mozilla-central/source/dom/webidl/KeyEvent.webidl
+// See http://dxr.mozilla.org/mozilla-central/source/dom/webidl/KeyEvent.webidl
 // for keyCode values.
 // Default value is F5
 pref("b2g.reload_key", '{ "key": 116, "shift": false, "ctrl": false, "alt": false, "meta": false }');
 
 #ifdef MOZ_HORIZON
 pref("b2g.default.start_manifest_url", "https://mozvr.github.io/horizon/web/manifest.webapp");
 pref("dom.vr.enabled", true);
 pref("dom.ipc.tabs.disabled", true);
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -3219,19 +3219,20 @@
             else
               this.moveTabBackward();
           ]]>
         </body>
       </method>
 
       <method name="duplicateTab">
         <parameter name="aTab"/><!-- can be from a different window as well -->
+        <parameter name="aRestoreTabImmediately"/><!-- can defer loading of the tab contents -->
         <body>
           <![CDATA[
-            return SessionStore.duplicateTab(window, aTab);
+            return SessionStore.duplicateTab(window, aTab, 0, aRestoreTabImmediately);
           ]]>
         </body>
       </method>
 
       <!--
         The tab switcher is responsible for asynchronously switching
         tabs in e10s. It waits until the new tab is ready (i.e., the
         layer tree is available) before switching to it. Then it
--- a/browser/base/content/test/general/browser.ini
+++ b/browser/base/content/test/general/browser.ini
@@ -273,16 +273,17 @@ tags = mcb
 [browser_bug970746.js]
 [browser_bug1015721.js]
 skip-if = os == 'win'
 [browser_bug1064280_changeUrlInPinnedTab.js]
 [browser_accesskeys.js]
 [browser_clipboard.js]
 subsuite = clipboard
 [browser_clipboard_pastefile.js]
+skip-if = true # Disabled due to the clipboard not supporting real file types yet (bug 1288773)
 [browser_contentAreaClick.js]
 skip-if = e10s # Clicks in content don't go through contentAreaClick with e10s.
 [browser_contextmenu.js]
 subsuite = clipboard
 tags = fullscreen
 skip-if = toolkit == "gtk2" || toolkit == "gtk3" # disabled on Linux due to bug 513558
 [browser_contextmenu_input.js]
 skip-if = toolkit == "gtk2" || toolkit == "gtk3" # disabled on Linux due to bug 513558
--- a/browser/base/content/test/general/browser_contextmenu_input.js
+++ b/browser/base/content/test/general/browser_contextmenu_input.js
@@ -174,18 +174,19 @@ add_task(function* test_tel_email_url_nu
        "context-delete",      false,
        "---",                 null,
        "context-selectall",   null],
       {skipFocusChange: true}
     );
   }
 });
 
-add_task(function* test_date_time_color_range_input() {
-  for (let selector of ["#input_date", "#input_time", "#input_color", "#input_range"]) {
+add_task(function* test_date_time_color_range_month_week_input() {
+  for (let selector of ["#input_date", "#input_time", "#input_color",
+                        "#input_range", "#input_month"]) {
     yield test_contextmenu(selector,
       ["context-navigation", null,
            ["context-back",         false,
             "context-forward",      false,
             "context-reload",       true,
             "context-bookmarkpage", true], null,
        "---",                  null,
        "context-savepage",     true,
@@ -214,18 +215,18 @@ add_task(function* test_search_input() {
      "---",                 null,
      "context-selectall",   null,
      "---",                 null,
      "spell-check-enabled", true],
     {skipFocusChange: true}
   );
 });
 
-add_task(function* test_datetime_month_week_datetimelocal_input_todos() {
-  for (let type of ["datetime", "week", "datetime-local"]) {
+add_task(function* test_datetime_datetimelocal_input_todos() {
+  for (let type of ["datetime", "datetime-local"]) {
     let returnedType = yield ContentTask.spawn(gBrowser.selectedBrowser, type, function*(type) {
       let doc = content.document;
       let input = doc.getElementById("input_" + type);
       return input.type;
     });
     todo_is(returnedType, type, `TODO: add test for ${type} input fields`);
   }
 });
--- a/browser/components/extensions/ext-utils.js
+++ b/browser/components/extensions/ext-utils.js
@@ -582,30 +582,33 @@ ExtensionTabManager.prototype = {
       width: browser.frameLoader.lazyWidth || browser.clientWidth,
       height: browser.frameLoader.lazyHeight || browser.clientHeight,
       audible: tab.soundPlaying,
       mutedInfo,
     };
 
     if (this.hasTabPermission(tab)) {
       result.url = browser.currentURI.spec;
-      if (browser.contentTitle) {
-        result.title = browser.contentTitle;
+      let title = browser.contentTitle || tab.label;
+      if (title) {
+        result.title = title;
       }
       let icon = window.gBrowser.getIcon(tab);
       if (icon) {
         result.favIconUrl = icon;
       }
     }
 
     return result;
   },
 
   getTabs(window) {
-    return Array.from(window.gBrowser.tabs, tab => this.convert(tab));
+    return Array.from(window.gBrowser.tabs)
+                .filter(tab => !tab.closing)
+                .map(tab => this.convert(tab));
   },
 };
 
 
 // Manages global mappings between XUL tabs and extension tab IDs.
 global.TabManager = {
   _tabs: new WeakMap(),
   _nextId: 1,
--- a/browser/components/extensions/test/browser/browser_ext_tabs_duplicate.js
+++ b/browser/components/extensions/test/browser/browser_ext_tabs_duplicate.js
@@ -35,16 +35,90 @@ add_task(function* testDuplicateTab() {
   yield extension.awaitFinish("tabs.duplicate");
   yield extension.unload();
 
   while (gBrowser.tabs[0].linkedBrowser.currentURI.spec === "http://example.net/") {
     yield BrowserTestUtils.removeTab(gBrowser.tabs[0]);
   }
 });
 
+add_task(function* testDuplicateTabLazily() {
+  function background() {
+    let tabLoadComplete = new Promise(resolve => {
+      browser.test.onMessage.addListener((message, tabId, result) => {
+        if (message == "duplicate-tab-done") {
+          resolve(tabId);
+        }
+      });
+    });
+
+    function awaitLoad(tabId) {
+      return new Promise(resolve => {
+        browser.tabs.onUpdated.addListener(function listener(tabId_, changed, tab) {
+          if (tabId == tabId_ && changed.status == "complete") {
+            browser.tabs.onUpdated.removeListener(listener);
+            resolve();
+          }
+        });
+      });
+    }
+
+    let startTabId;
+    let url = "http://example.com/browser/browser/components/extensions/test/browser/file_dummy.html";
+    browser.tabs.create({url}, tab => {
+      startTabId = tab.id;
+
+      awaitLoad(startTabId).then(() => {
+        browser.test.sendMessage("duplicate-tab", startTabId);
+
+        tabLoadComplete.then(unloadedTabId => {
+          browser.tabs.get(startTabId, loadedtab => {
+            browser.test.assertEq("Dummy test page", loadedtab.title, "Title should be returned for loaded pages");
+            browser.test.assertEq("complete", loadedtab.status, "Tab status should be complete for loaded pages");
+          });
+
+          browser.tabs.get(unloadedTabId, unloadedtab => {
+            browser.test.assertEq("Dummy test page", unloadedtab.title, "Title should be returned after page has been unloaded");
+          });
+
+          browser.tabs.remove([tab.id, unloadedTabId]);
+          browser.test.notifyPass("tabs.hasCorrectTabTitle");
+        });
+      }).catch(e => {
+        browser.test.fail(`${e} :: ${e.stack}`);
+        browser.test.notifyFail("tabs.hasCorrectTabTitle");
+      });
+    });
+  }
+
+  let extension = ExtensionTestUtils.loadExtension({
+    manifest: {
+      "permissions": ["tabs"],
+    },
+
+    background,
+  });
+
+  extension.onMessage("duplicate-tab", tabId => {
+    let {TabManager} = Cu.import("resource://gre/modules/Extension.jsm", {});
+
+    let tab = TabManager.getTab(tabId);
+    // This is a bit of a hack to load a tab in the background.
+    let newTab = gBrowser.duplicateTab(tab, false);
+
+    BrowserTestUtils.waitForEvent(newTab, "SSTabRestored", () => true).then(() => {
+      extension.sendMessage("duplicate-tab-done", TabManager.getId(newTab));
+    });
+  });
+
+  yield extension.startup();
+  yield extension.awaitFinish("tabs.hasCorrectTabTitle");
+  yield extension.unload();
+});
+
 add_task(function* testDuplicatePinnedTab() {
   let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "http://example.net/");
   gBrowser.pinTab(tab);
 
   let extension = ExtensionTestUtils.loadExtension({
     manifest: {
       "permissions": ["tabs"],
     },
--- a/browser/components/extensions/test/browser/browser_ext_tabs_events.js
+++ b/browser/components/extensions/test/browser/browser_ext_tabs_events.js
@@ -231,8 +231,59 @@ add_task(function* testTabEventsSize() {
 
     extension.sendMessage("remove-tab", tabId);
     yield extension.awaitMessage("tab-removed");
   }
 
   yield extension.unload();
   SpecialPowers.clearUserPref(RESOLUTION_PREF);
 });
+
+add_task(function* testTabRemovalEvent() {
+  function background() {
+    let removalTabId;
+
+    function awaitLoad(tabId) {
+      return new Promise(resolve => {
+        browser.tabs.onUpdated.addListener(function listener(tabId_, changed, tab) {
+          if (tabId == tabId_ && changed.status == "complete") {
+            browser.tabs.onUpdated.removeListener(listener);
+            resolve();
+          }
+        });
+      });
+    }
+
+    chrome.tabs.onRemoved.addListener((tabId, info) => {
+      browser.test.log("Make sure the removed tab is not available in the tabs.query callback.");
+      chrome.tabs.query({}, tabs => {
+        for (let tab of tabs) {
+          browser.test.assertTrue(tab.id != tabId, "Tab query should not include removed tabId");
+        }
+        browser.test.notifyPass("tabs-events");
+      });
+    });
+
+    let url = "http://example.com/browser/browser/components/extensions/test/browser/context.html";
+    browser.tabs.create({url: url})
+    .then(tab => {
+      removalTabId = tab.id;
+      return awaitLoad(tab.id);
+    }).then(() => {
+      return browser.tabs.remove(removalTabId);
+    }).catch(e => {
+      browser.test.fail(`${e} :: ${e.stack}`);
+      browser.test.notifyFail("tabs-events");
+    });
+  }
+
+  let extension = ExtensionTestUtils.loadExtension({
+    manifest: {
+      "permissions": ["tabs"],
+    },
+
+    background,
+  });
+
+  yield extension.startup();
+  yield extension.awaitFinish("tabs-events");
+  yield extension.unload();
+});
--- a/browser/components/sessionstore/SessionStore.jsm
+++ b/browser/components/sessionstore/SessionStore.jsm
@@ -2083,17 +2083,17 @@ var SessionStoreInternal = {
 
     if (aTab.linkedBrowser.__SS_restoreState) {
       this._resetTabRestoringState(aTab);
     }
 
     this.restoreTab(aTab, tabState);
   },
 
-  duplicateTab: function ssi_duplicateTab(aWindow, aTab, aDelta = 0) {
+  duplicateTab: function ssi_duplicateTab(aWindow, aTab, aDelta = 0, aRestoreImmediately = true) {
     if (!aTab.ownerGlobal.__SSi) {
       throw Components.Exception("Default view is not tracked", Cr.NS_ERROR_INVALID_ARG);
     }
     if (!aWindow.gBrowser) {
       throw Components.Exception("Invalid window object: no gBrowser", Cr.NS_ERROR_INVALID_ARG);
     }
 
     // Create a new tab.
@@ -2132,17 +2132,17 @@ var SessionStoreInternal = {
       TabState.copyFromCache(browser, tabState, options);
 
       tabState.index += aDelta;
       tabState.index = Math.max(1, Math.min(tabState.index, tabState.entries.length));
       tabState.pinned = false;
 
       // Restore the state into the new tab.
       this.restoreTab(newTab, tabState, {
-        restoreImmediately: true /* Load this tab right away. */
+        restoreImmediately: aRestoreImmediately
       });
     });
 
     return newTab;
   },
 
   getClosedTabCount: function ssi_getClosedTabCount(aWindow) {
     if ("__SSi" in aWindow) {
--- a/browser/config/mozconfigs/linux32/common-opt
+++ b/browser/config/mozconfigs/linux32/common-opt
@@ -1,13 +1,12 @@
 # This file is sourced by nightly, beta, and release mozconfigs.
 
 ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
 ac_add_options --with-google-api-keyfile=/builds/gapi.data
-ac_add_options --with-google-oauth-api-keyfile=/builds/google-oauth-api.key
 ac_add_options --with-mozilla-api-keyfile=/builds/mozilla-desktop-geoloc-api.key
 
 . $topsrcdir/build/unix/mozconfig.linux32
 
 # Needed to enable breakpad in application.ini
 export MOZILLA_OFFICIAL=1
 
 export MOZ_TELEMETRY_REPORTING=1
--- a/browser/config/mozconfigs/linux32/debug
+++ b/browser/config/mozconfigs/linux32/debug
@@ -1,12 +1,11 @@
 ac_add_options --enable-debug
 ac_add_options --enable-dmd
 ac_add_options --enable-verify-mar
-ac_add_options --with-google-oauth-api-keyfile=/builds/google-oauth-api.key
 
 MOZ_AUTOMATION_L10N_CHECK=0
 
 . $topsrcdir/build/unix/mozconfig.linux32
 
 # Needed to enable breakpad in application.ini
 export MOZILLA_OFFICIAL=1
 
--- a/browser/config/mozconfigs/linux32/debug-asan
+++ b/browser/config/mozconfigs/linux32/debug-asan
@@ -1,10 +1,8 @@
-ac_add_options --with-google-oauth-api-keyfile=/builds/google-oauth-api.key
-
 # Use at least -O1 for optimization to avoid stack space
 # exhaustions caused by Clang function inlining.
 ac_add_options --enable-debug
 ac_add_options --enable-optimize="-O1"
 
 # ASan specific options on Linux
 ac_add_options --enable-valgrind
 
--- a/browser/config/mozconfigs/linux32/nightly-asan
+++ b/browser/config/mozconfigs/linux32/nightly-asan
@@ -1,10 +1,8 @@
-ac_add_options --with-google-oauth-api-keyfile=/builds/google-oauth-api.key
-
 # We still need to build with debug symbols
 ac_add_options --disable-debug
 ac_add_options --enable-optimize="-O2 -g"
 
 # ASan specific options on Linux
 ac_add_options --enable-valgrind
 
 . $topsrcdir/build/unix/mozconfig.asan
--- a/browser/config/mozconfigs/linux64/common-opt
+++ b/browser/config/mozconfigs/linux64/common-opt
@@ -1,13 +1,12 @@
 # This file is sourced by the nightly, beta, and release mozconfigs.
 
 ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
 ac_add_options --with-google-api-keyfile=/builds/gapi.data
-ac_add_options --with-google-oauth-api-keyfile=/builds/google-oauth-api.key
 ac_add_options --with-mozilla-api-keyfile=/builds/mozilla-desktop-geoloc-api.key
 
 . $topsrcdir/build/unix/mozconfig.linux
 
 # Needed to enable breakpad in application.ini
 export MOZILLA_OFFICIAL=1
 
 export MOZ_TELEMETRY_REPORTING=1
--- a/browser/config/mozconfigs/linux64/debug
+++ b/browser/config/mozconfigs/linux64/debug
@@ -1,12 +1,11 @@
 ac_add_options --enable-debug
 ac_add_options --enable-dmd
 ac_add_options --enable-verify-mar
-ac_add_options --with-google-oauth-api-keyfile=/builds/google-oauth-api.key
 
 MOZ_AUTOMATION_L10N_CHECK=0
 
 . $topsrcdir/build/unix/mozconfig.linux
 
 # Needed to enable breakpad in application.ini
 export MOZILLA_OFFICIAL=1
 
--- a/browser/config/mozconfigs/linux64/debug-asan
+++ b/browser/config/mozconfigs/linux64/debug-asan
@@ -1,10 +1,8 @@
-ac_add_options --with-google-oauth-api-keyfile=/builds/google-oauth-api.key
-
 # Use at least -O1 for optimization to avoid stack space
 # exhaustions caused by Clang function inlining.
 ac_add_options --enable-debug
 ac_add_options --enable-optimize="-O1"
 
 # ASan specific options on Linux
 ac_add_options --enable-valgrind
 
--- a/browser/config/mozconfigs/linux64/nightly-asan
+++ b/browser/config/mozconfigs/linux64/nightly-asan
@@ -1,10 +1,8 @@
-ac_add_options --with-google-oauth-api-keyfile=/builds/google-oauth-api.key
-
 # We still need to build with debug symbols
 ac_add_options --disable-debug
 ac_add_options --enable-optimize="-O2 -gline-tables-only"
 
 # ASan specific options on Linux
 ac_add_options --enable-valgrind
 
 . $topsrcdir/build/unix/mozconfig.asan
--- a/browser/config/mozconfigs/linux64/opt-tsan
+++ b/browser/config/mozconfigs/linux64/opt-tsan
@@ -1,10 +1,8 @@
-ac_add_options --with-google-oauth-api-keyfile=/builds/google-oauth-api.key
-
 . $topsrcdir/build/unix/mozconfig.tsan
 
 export PKG_CONFIG_LIBDIR=/usr/lib64/pkgconfig:/usr/share/pkgconfig
 . $topsrcdir/build/unix/mozconfig.gtk
 
 # Need this to prevent name conflicts with the normal nightly build packages
 export MOZ_PKG_SPECIAL=tsan
 
--- a/browser/config/mozconfigs/macosx-universal/common-opt
+++ b/browser/config/mozconfigs/macosx-universal/common-opt
@@ -2,17 +2,16 @@
 
 . $topsrcdir/build/macosx/universal/mozconfig
 
 # Universal builds override the default of browser (bug 575283 comment 29)
 ac_add_options --enable-application=browser
 
 ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
 ac_add_options --with-google-api-keyfile=/builds/gapi.data
-ac_add_options --with-google-oauth-api-keyfile=/builds/google-oauth-api.key
 ac_add_options --with-mozilla-api-keyfile=/builds/mozilla-desktop-geoloc-api.key
 
 # Needed to enable breakpad in application.ini
 export MOZILLA_OFFICIAL=1
 
 export MOZ_TELEMETRY_REPORTING=1
 
 # Package js shell.
--- a/browser/config/mozconfigs/macosx64/debug
+++ b/browser/config/mozconfigs/macosx64/debug
@@ -1,14 +1,13 @@
 . $topsrcdir/build/macosx/mozconfig.common
 
 ac_add_options --enable-debug
 ac_add_options --enable-dmd
 ac_add_options --enable-verify-mar
-ac_add_options --with-google-oauth-api-keyfile=/builds/google-oauth-api.key
 
 # Needed to enable breakpad in application.ini
 export MOZILLA_OFFICIAL=1
 
 # Enable Telemetry
 export MOZ_TELEMETRY_REPORTING=1
 
 if test "${MOZ_UPDATE_CHANNEL}" = "nightly"; then
--- a/browser/config/mozconfigs/macosx64/debug-asan
+++ b/browser/config/mozconfigs/macosx64/debug-asan
@@ -1,14 +1,13 @@
 . $topsrcdir/build/unix/mozconfig.asan
 
 ac_add_options --enable-application=browser
 ac_add_options --enable-debug
 ac_add_options --enable-optimize="-O1"
-ac_add_options --with-google-oauth-api-keyfile=/builds/google-oauth-api.key
 
 # Enable Telemetry
 export MOZ_TELEMETRY_REPORTING=1
 
 # Package js shell.
 export MOZ_PACKAGE_JSSHELL=1
 
 if test "${MOZ_UPDATE_CHANNEL}" = "nightly"; then
--- a/browser/config/mozconfigs/macosx64/nightly
+++ b/browser/config/mozconfigs/macosx64/nightly
@@ -1,12 +1,11 @@
 . $topsrcdir/build/macosx/mozconfig.common
 
 ac_add_options --enable-verify-mar
-ac_add_options --with-google-oauth-api-keyfile=/builds/google-oauth-api.key
 
 # Needed to enable breakpad in application.ini
 export MOZILLA_OFFICIAL=1
 
 # Enable Telemetry
 export MOZ_TELEMETRY_REPORTING=1
 
 if test "${MOZ_UPDATE_CHANNEL}" = "nightly"; then
--- a/browser/config/mozconfigs/win32/common-opt
+++ b/browser/config/mozconfigs/win32/common-opt
@@ -8,22 +8,16 @@ ac_add_options --enable-require-all-d3dc
 
 if [ -f /c/builds/gapi.data ]; then
   _gapi_keyfile=/c/builds/gapi.data
 else
   _gapi_keyfile=/e/builds/gapi.data
 fi
 ac_add_options --with-google-api-keyfile=${_gapi_keyfile}
 
-if [ -f /c/builds/google-oauth-api.key ]; then
-  _google_oauth_api_keyfile=/c/builds/google-oauth-api.key
-else
-  _google_oauth_api_keyfile=/e/builds/google-oauth-api.key
-fi
-ac_add_options --with-google-oauth-api-keyfile=${_google_oauth_api_keyfile}
 ac_add_options --with-mozilla-api-keyfile=/c/builds/mozilla-desktop-geoloc-api.key
 
 # Needed to enable breakpad in application.ini
 export MOZILLA_OFFICIAL=1
 
 export MOZ_TELEMETRY_REPORTING=1
 
 . $topsrcdir/build/win32/mozconfig.vs-latest
--- a/browser/config/mozconfigs/win32/debug
+++ b/browser/config/mozconfigs/win32/debug
@@ -3,23 +3,16 @@ MOZ_AUTOMATION_L10N_CHECK=0
 . "$topsrcdir/browser/config/mozconfigs/common"
 
 ac_add_options --enable-debug
 ac_add_options --enable-dmd
 ac_add_options --enable-profiling  # needed for --enable-dmd to work on Windows
 ac_add_options --enable-verify-mar
 ac_add_options --enable-require-all-d3dc-versions
 
-if [ -f /c/builds/google-oauth-api.key ]; then
-  _google_oauth_api_keyfile=/c/builds/google-oauth-api.key
-else
-  _google_oauth_api_keyfile=/e/builds/google-oauth-api.key
-fi
-ac_add_options --with-google-oauth-api-keyfile=${_google_oauth_api_keyfile}
-
 # Needed to enable breakpad in application.ini
 export MOZILLA_OFFICIAL=1
 
 # Enable Telemetry
 export MOZ_TELEMETRY_REPORTING=1
 
 . $topsrcdir/build/win32/mozconfig.vs-latest
 
--- a/browser/config/mozconfigs/win64/common-opt
+++ b/browser/config/mozconfigs/win64/common-opt
@@ -6,22 +6,16 @@ ac_add_options --enable-update-channel=$
 ac_add_options --enable-jemalloc
 if [ -f /c/builds/gapi.data ]; then
   _gapi_keyfile=/c/builds/gapi.data
 else
   _gapi_keyfile=/e/builds/gapi.data
 fi
 ac_add_options --with-google-api-keyfile=${_gapi_keyfile}
 
-if [ -f /c/builds/google-oauth-api.key ]; then
-  _google_oauth_api_keyfile=/c/builds/google-oauth-api.key
-else
-  _google_oauth_api_keyfile=/e/builds/google-oauth-api.key
-fi
-ac_add_options --with-google-oauth-api-keyfile=${_google_oauth_api_keyfile}
 ac_add_options --with-mozilla-api-keyfile=/c/builds/mozilla-desktop-geoloc-api.key
 
 # Needed to enable breakpad in application.ini
 export MOZILLA_OFFICIAL=1
 
 export MOZ_TELEMETRY_REPORTING=1
 
 . $topsrcdir/build/win64/mozconfig.vs-latest
--- a/browser/config/mozconfigs/win64/debug
+++ b/browser/config/mozconfigs/win64/debug
@@ -5,23 +5,16 @@ MOZ_AUTOMATION_L10N_CHECK=0
 ac_add_options --target=x86_64-pc-mingw32
 ac_add_options --host=x86_64-pc-mingw32
 
 ac_add_options --enable-debug
 ac_add_options --enable-dmd
 ac_add_options --enable-profiling  # needed for --enable-dmd to work on Windows
 ac_add_options --enable-verify-mar
 
-if [ -f /c/builds/google-oauth-api.key ]; then
-  _google_oauth_api_keyfile=/c/builds/google-oauth-api.key
-else
-  _google_oauth_api_keyfile=/e/builds/google-oauth-api.key
-fi
-ac_add_options --with-google-oauth-api-keyfile=${_google_oauth_api_keyfile}
-
 # Needed to enable breakpad in application.ini
 export MOZILLA_OFFICIAL=1
 
 # Enable Telemetry
 export MOZ_TELEMETRY_REPORTING=1
 
 # Package js shell.
 export MOZ_PACKAGE_JSSHELL=1
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -348,16 +348,21 @@
 @RESPATH@/components/BrowserElementParent.manifest
 @RESPATH@/components/BrowserElementParent.js
 @RESPATH@/components/BrowserElementProxy.manifest
 @RESPATH@/components/BrowserElementProxy.js
 @RESPATH@/components/FeedProcessor.manifest
 @RESPATH@/components/FeedProcessor.js
 @RESPATH@/components/PackagedAppUtils.js
 @RESPATH@/components/PackagedAppUtils.manifest
+#if defined(XP_LINUX) || defined(XP_WIN)
+; OSX uses native platform impl.  Windows, Linux, and Android uses fallback JS impl.
+@BINPATH@/components/nsDNSServiceDiscovery.manifest
+@BINPATH@/components/nsDNSServiceDiscovery.js
+#endif
 @RESPATH@/browser/components/BrowserFeeds.manifest
 @RESPATH@/browser/components/FeedConverter.js
 @RESPATH@/browser/components/FeedWriter.js
 @RESPATH@/browser/components/WebContentConverter.js
 @RESPATH@/browser/components/BrowserComponents.manifest
 @RESPATH@/browser/components/nsBrowserContentHandler.js
 @RESPATH@/browser/components/nsBrowserGlue.js
 @RESPATH@/browser/components/nsSetDefaultBrowser.manifest
--- a/browser/installer/windows/nsis/installer.nsi
+++ b/browser/installer/windows/nsis/installer.nsi
@@ -1,16 +1,16 @@
 # 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/.
 
 # Required Plugins:
 # AppAssocReg    http://nsis.sourceforge.net/Application_Association_Registration_plug-in
 # ApplicationID  http://nsis.sourceforge.net/ApplicationID_plug-in
-# CityHash       http://mxr.mozilla.org/mozilla-central/source/other-licenses/nsis/Contrib/CityHash
+# CityHash       http://dxr.mozilla.org/mozilla-central/source/other-licenses/nsis/Contrib/CityHash
 # ShellLink      http://nsis.sourceforge.net/ShellLink_plug-in
 # UAC            http://nsis.sourceforge.net/UAC_plug-in
 # ServicesHelper Mozilla specific plugin that is located in /other-licenses/nsis
 
 ; Set verbosity to 3 (e.g. no script) to lessen the noise in the build logs
 !verbose 3
 
 ; 7-Zip provides better compression than the lzma from NSIS so we add the files
--- a/browser/installer/windows/nsis/uninstaller.nsi
+++ b/browser/installer/windows/nsis/uninstaller.nsi
@@ -1,15 +1,15 @@
 # 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/.
 
 # Required Plugins:
 # AppAssocReg http://nsis.sourceforge.net/Application_Association_Registration_plug-in
-# CityHash    http://mxr.mozilla.org/mozilla-central/source/other-licenses/nsis/Contrib/CityHash
+# CityHash    http://dxr.mozilla.org/mozilla-central/source/other-licenses/nsis/Contrib/CityHash
 # ShellLink   http://nsis.sourceforge.net/ShellLink_plug-in
 # UAC         http://nsis.sourceforge.net/UAC_plug-in
 
 ; Set verbosity to 3 (e.g. no script) to lessen the noise in the build logs
 !verbose 3
 
 ; 7-Zip provides better compression than the lzma from NSIS so we add the files
 ; uncompressed and use 7-Zip to create a SFX archive of it
--- a/browser/themes/windows/browser.css
+++ b/browser/themes/windows/browser.css
@@ -187,31 +187,33 @@
   #main-window[tabsintitlebar]:not([inFullscreen]) #TabsToolbar:not(:-moz-lwtheme) {
     color: CaptionText;
   }
 
   #main-window[tabsintitlebar]:not([inFullscreen]) #toolbar-menubar:not(:-moz-lwtheme):-moz-window-inactive,
   #main-window[tabsintitlebar]:not([inFullscreen]) #TabsToolbar:not(:-moz-lwtheme):-moz-window-inactive {
     color: InactiveCaptionText;
   }
-
-  #main-window[tabsintitlebar] #main-menubar > menu:not(:-moz-lwtheme) {
-    color: inherit;
-  }
 }
 
 @media not all and (-moz-windows-compositor) {
   #main-window[tabsintitlebar] #titlebar:-moz-lwtheme {
     visibility: hidden;
   }
 
   #main-window[tabsintitlebar] #titlebar-content:-moz-lwtheme {
     -moz-binding: url("chrome://global/content/bindings/general.xml#windowdragbox");
     visibility: visible;
   }
+
+  /* Top-level menu appearance has transparent background, so the text color
+     needs to be inherited from our custom menubar too. */
+  #main-window[tabsintitlebar] #main-menubar > menu:not(:-moz-lwtheme) {
+    color: inherit;
+  }
 }
 
 /**
  * In the classic themes, the titlebar has a horizontal gradient, which is
  * problematic for reading the text of background tabs when they're in the
  * titlebar. We side-step this issue by layering our own background underneath
  * the tabs. Unfortunately, this requires a bunch of positioning in order to get
  * text and icons to not appear fuzzy.
new file mode 100644
--- /dev/null
+++ b/build/moz.configure/keyfiles.configure
@@ -0,0 +1,65 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# 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/.
+
+
+@template
+def keyfile(desc, help=None, callback=lambda x: x):
+    help = help or ('Use the secret key contained in the given keyfile '
+                    'for %s requests' % desc)
+    name = desc.lower().replace(' ', '-')
+    no_key = callback('no-%s-key' % name)
+
+    option('--with-%s-keyfile' % name, nargs=1, help=help)
+
+    @depends('--with-%s-keyfile' % name)
+    @checking('for the %s key' % desc, lambda x: x and x is not no_key)
+    @imports(_from='__builtin__', _import='open')
+    @imports(_from='__builtin__', _import='IOError')
+    def keyfile(value):
+        if value:
+            try:
+                with open(value[0]) as fh:
+                    result = fh.read().strip()
+                    if result:
+                        return callback(result)
+            except FatalCheckError:
+                raise
+            except IOError:
+                pass
+        return no_key
+
+    return keyfile
+
+
+@template
+def simple_keyfile(desc):
+    set_config('MOZ_%s_KEY' % desc.upper().replace(' ', '_'),
+               keyfile(desc))
+
+
+@template
+def id_and_secret_keyfile(desc):
+    def id_and_secret(value):
+        if value.startswith('no-') and value.endswith('-key'):
+            id = value[:-3] + 'clientid'
+            secret = value
+        elif ' ' in value:
+            id, secret = value.split(' ', 1)
+        else:
+            raise FatalCheckError('%s key file has an invalid format.' % desc)
+        return namespace(
+            id=id,
+            secret=secret,
+        )
+
+    content = keyfile(desc, help='Use the client id and secret key contained '
+                                 'in the given keyfile for %s requests' % desc,
+                      callback=id_and_secret)
+
+
+    name = desc.upper().replace(' ', '_')
+    set_config('MOZ_%s_CLIENTID' % name, delayed_getattr(content, 'id'))
+    set_config('MOZ_%s_KEY' % name, delayed_getattr(content, 'secret'))
--- a/build/moz.configure/old.configure
+++ b/build/moz.configure/old.configure
@@ -155,17 +155,16 @@ def old_configure_options(*options):
 
 @old_configure_options(
     '--cache-file',
     '--datadir',
     '--enable-accessibility',
     '--enable-address-sanitizer',
     '--enable-alsa',
     '--enable-android-omx',
-    '--enable-approximate-location',
     '--enable-b2g-bt',
     '--enable-b2g-camera',
     '--enable-b2g-ril',
     '--enable-bundled-fonts',
     '--enable-clang-plugin',
     '--enable-content-sandbox',
     '--enable-cookies',
     '--enable-cpp-rtti',
@@ -182,30 +181,28 @@ def old_configure_options(*options):
     '--enable-faststripe',
     '--enable-feeds',
     '--enable-gamepad',
     '--enable-gconf',
     '--enable-gczeal',
     '--enable-gio',
     '--enable-gnomeui',
     '--enable-gold',
-    '--enable-gps-debug',
     '--enable-hardware-aec-ns',
     '--enable-icf',
     '--enable-install-strip',
     '--enable-ion',
     '--enable-ios-target',
     '--enable-ipdl-tests',
     '--enable-jitspew',
     '--enable-libjpeg-turbo',
     '--enable-libproxy',
     '--enable-llvm-hacks',
     '--enable-logrefcnt',
     '--enable-maintenance-service',
-    '--enable-media-navigator',
     '--enable-memory-sanitizer',
     '--enable-mobile-optimize',
     '--enable-mozril-geoloc',
     '--enable-necko-protocols',
     '--enable-necko-wifi',
     '--enable-negotiateauth',
     '--enable-nfc',
     '--enable-nspr-build',
@@ -249,67 +246,60 @@ def old_configure_options(*options):
     '--enable-trace-logging',
     '--enable-tree-freetype',
     '--enable-ui-locale',
     '--enable-universalchardet',
     '--enable-updater',
     '--enable-url-classifier',
     '--enable-valgrind',
     '--enable-verify-mar',
-    '--enable-webapp-runtime',
     '--enable-webrtc',
     '--enable-websms-backend',
     '--enable-webspeech',
     '--enable-webspeechtestbackend',
     '--enable-xul',
     '--enable-zipwriter',
     '--includedir',
     '--libdir',
     '--no-create',
     '--prefix',
-    '--with-adjust-sdk-keyfile',
     '--with-android-cxx-stl',
     '--with-android-distribution-directory',
     '--with-android-max-sdk',
     '--with-android-min-sdk',
     '--with-android-sdk',
     '--with-app-basename',
     '--with-app-name',
     '--with-arch',
-    '--with-bing-api-keyfile',
     '--with-branding',
     '--with-crashreporter-enable-percent',
     '--with-cross-lib',
     '--with-debug-label',
     '--with-default-mozilla-five-home',
     '--with-distribution-id',
     '--with-doc-include-dirs',
     '--with-doc-input-dirs',
     '--with-doc-output-dir',
     '--with-float-abi',
     '--with-fpu',
-    '--with-google-api-keyfile',
-    '--with-google-oauth-api-keyfile',
     '--with-intl-api',
     '--with-ios-sdk',
     '--with-jitreport-granularity',
     '--with-linux-headers',
     '--with-macbundlename-prefix',
     '--with-macos-private-frameworks',
     '--with-macos-sdk',
-    '--with-mozilla-api-keyfile',
     '--with-nspr-cflags',
     '--with-nspr-exec-prefix',
     '--with-nspr-libs',
     '--with-nspr-prefix',
     '--with-nss-exec-prefix',
     '--with-nss-prefix',
     '--with-pthreads',
     '--with-qemu-exe',
-    '--with-servo',
     '--with-sixgill',
     '--with-soft-float',
     '--with-system-bz2',
     '--with-system-icu',
     '--with-system-jpeg',
     '--with-system-libevent',
     '--with-system-libvpx',
     '--with-system-nspr',
--- a/devtools/client/shared/widgets/MdnDocsWidget.js
+++ b/devtools/client/shared/widgets/MdnDocsWidget.js
@@ -51,17 +51,17 @@ const PROPERTY_VALUE_COLOR = "theme-fg-c
 const COMMENT_COLOR = "theme-comment";
 
 /**
  * Turns a string containing a series of CSS declarations into
  * a series of DOM nodes, with classes applied to provide syntax
  * highlighting.
  *
  * It uses the CSS tokenizer to generate a stream of CSS tokens.
- * https://mxr.mozilla.org/mozilla-central/source/dom/webidl/CSSLexer.webidl
+ * https://dxr.mozilla.org/mozilla-central/source/dom/webidl/CSSLexer.webidl
  * lists all the token types.
  *
  * - "whitespace", "comment", and "symbol" tokens are appended as TEXT nodes,
  * and will inherit the default style for text.
  *
  * - "ident" tokens that we think are property names are considered to be
  * a property name, and are appended as SPAN nodes with a distinct color class.
  *
--- a/devtools/client/webconsole/test/test-bug_923281_test2.js
+++ b/devtools/client/webconsole/test/test-bug_923281_test2.js
@@ -1,6 +1,8 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
+"use strict";
+
 console.log("This is a random text.");
--- a/devtools/shared/jsbeautify/src/beautify-js.js
+++ b/devtools/shared/jsbeautify/src/beautify-js.js
@@ -967,17 +967,17 @@ function Beautifier(js_source_text, opti
                 }
                 return [trim(resulting_string) + '\n', 'TK_UNKNOWN'];
             }
 
 
 
             // Spidermonkey-specific sharp variables for circular references
             // https://developer.mozilla.org/En/Sharp_variables_in_JavaScript
-            // http://mxr.mozilla.org/mozilla-central/source/js/src/jsscan.cpp around line 1935
+            // http://dxr.mozilla.org/mozilla-central/source/js/src/jsscan.cpp around line 1935
             var sharp = '#';
             if (parser_pos < input_length && in_array(input.charAt(parser_pos), digits)) {
                 do {
                     c = input.charAt(parser_pos);
                     sharp += c;
                     parser_pos += 1;
                 } while (parser_pos < input_length && c !== '#' && c !== '=');
                 if (c === '#') {
--- a/devtools/shared/protocol.js
+++ b/devtools/shared/protocol.js
@@ -1249,17 +1249,17 @@ var Front = Class({
       console.error(err);
       throw err;
     }
 
     let { deferred, stack } = this._requests.shift();
     callFunctionWithAsyncStack(() => {
       if (packet.error) {
         // "Protocol error" is here to avoid TBPL heuristics. See also
-        // https://mxr.mozilla.org/webtools-central/source/tbpl/php/inc/GeneralErrorFilter.php
+        // https://dxr.mozilla.org/webtools-central/source/tbpl/php/inc/GeneralErrorFilter.php
         let message;
         if (packet.error && packet.message) {
           message = "Protocol error (" + packet.error + "): " + packet.message;
         } else {
           message = packet.error;
         }
         deferred.reject(message);
       } else {
--- a/docshell/base/timeline/TimelineConsumers.cpp
+++ b/docshell/base/timeline/TimelineConsumers.cpp
@@ -153,22 +153,19 @@ TimelineConsumers::RemoveConsumer(nsDocS
   // Prepare for becoming a consumer later.
   observed.reset(nullptr);
 }
 
 bool
 TimelineConsumers::HasConsumer(nsIDocShell* aDocShell)
 {
   MOZ_ASSERT(NS_IsMainThread());
-  if (!aDocShell) {
-    return false;
-  }
-  bool isTimelineRecording = false;
-  aDocShell->GetRecordProfileTimelineMarkers(&isTimelineRecording);
-  return isTimelineRecording;
+  return aDocShell
+       ? aDocShell->GetRecordProfileTimelineMarkers()
+       : false;
 }
 
 bool
 TimelineConsumers::IsEmpty()
 {
   StaticMutexAutoLock lock(sMutex); // for `mActiveConsumers`.
   return mActiveConsumers == 0;
 }
--- a/docshell/test/browser/browser_tab_touch_events.js
+++ b/docshell/test/browser/browser_tab_touch_events.js
@@ -32,16 +32,19 @@ add_task(function*() {
                         .getInterface(Ci.nsIWebNavigation)
                         .QueryInterface(Ci.nsIDocShell);
   is(docshell.touchEventsOverride, Ci.nsIDocShell.TOUCHEVENTS_OVERRIDE_DISABLED,
     "Newly created frames should use the new touchEventsOverride flag");
 
   newFrameWin.location.reload();
   yield waitForEvent(newFrameWin, "load");
 
+  docshell = newFrameWin.QueryInterface(Ci.nsIInterfaceRequestor)
+                        .getInterface(Ci.nsIWebNavigation)
+                        .QueryInterface(Ci.nsIDocShell);
   is(docshell.touchEventsOverride, Ci.nsIDocShell.TOUCHEVENTS_OVERRIDE_DISABLED,
     "New touchEventsOverride flag should persist across reloads");
 
   gBrowser.removeCurrentTab();
 });
 
 function waitForEvent(target, event) {
   return new Promise(function(resolve) {
--- a/dom/animation/AnimValuesStyleRule.h
+++ b/dom/animation/AnimValuesStyleRule.h
@@ -3,18 +3,18 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_AnimValuesStyleRule_h
 #define mozilla_AnimValuesStyleRule_h
 
 #include "mozilla/StyleAnimationValue.h"
-#include "nsCSSProperty.h"
-#include "nsCSSPropertySet.h"
+#include "nsCSSPropertyID.h"
+#include "nsCSSPropertyIDSet.h"
 #include "nsIStyleRule.h"
 #include "nsISupportsImpl.h" // For NS_DECL_ISUPPORTS
 #include "nsRuleNode.h" // For nsCachedStyleData
 #include "nsTArray.h" // For nsTArray
 
 namespace mozilla {
 
 /**
@@ -33,25 +33,25 @@ public:
   void MapRuleInfoInto(nsRuleData* aRuleData) override;
   bool MightMapInheritedStyleData() override;
   bool GetDiscretelyAnimatedCSSValue(nsCSSProperty aProperty,
                                      nsCSSValue* aValue) override;
 #ifdef DEBUG
   void List(FILE* out = stdout, int32_t aIndent = 0) const override;
 #endif
 
-  void AddValue(nsCSSProperty aProperty, const StyleAnimationValue &aStartValue)
+  void AddValue(nsCSSPropertyID aProperty, const StyleAnimationValue &aStartValue)
   {
     PropertyStyleAnimationValuePair pair = { aProperty, aStartValue };
     mPropertyValuePairs.AppendElement(pair);
     mStyleBits |=
       nsCachedStyleData::GetBitForSID(nsCSSProps::kSIDTable[aProperty]);
   }
 
-  void AddValue(nsCSSProperty aProperty, StyleAnimationValue&& aStartValue)
+  void AddValue(nsCSSPropertyID aProperty, StyleAnimationValue&& aStartValue)
   {
     PropertyStyleAnimationValuePair* pair = mPropertyValuePairs.AppendElement();
     pair->mProperty = aProperty;
     pair->mValue = Move(aStartValue);
     mStyleBits |=
       nsCachedStyleData::GetBitForSID(nsCSSProps::kSIDTable[aProperty]);
   }
 
--- a/dom/animation/Animation.cpp
+++ b/dom/animation/Animation.cpp
@@ -764,17 +764,17 @@ Animation::HasLowerCompositeOrderThan(co
 
   // 3. Finally, generic animations sort by their position in the global
   // animation array.
   return mAnimationIndex < aOther.mAnimationIndex;
 }
 
 void
 Animation::ComposeStyle(RefPtr<AnimValuesStyleRule>& aStyleRule,
-                        nsCSSPropertySet& aSetProperties)
+                        nsCSSPropertyIDSet& aSetProperties)
 {
   if (!mEffect) {
     return;
   }
 
   if (!IsInEffect()) {
     return;
   }
--- a/dom/animation/Animation.h
+++ b/dom/animation/Animation.h
@@ -13,32 +13,32 @@
 #include "mozilla/EffectCompositor.h" // For EffectCompositor::CascadeLevel
 #include "mozilla/LinkedList.h"
 #include "mozilla/TimeStamp.h" // for TimeStamp, TimeDuration
 #include "mozilla/dom/AnimationBinding.h" // for AnimationPlayState
 #include "mozilla/dom/AnimationTimeline.h" // for AnimationTimeline
 #include "mozilla/DOMEventTargetHelper.h" // for DOMEventTargetHelper
 #include "mozilla/dom/KeyframeEffect.h" // for KeyframeEffectReadOnly
 #include "mozilla/dom/Promise.h" // for Promise
-#include "nsCSSProperty.h" // for nsCSSProperty
+#include "nsCSSPropertyID.h" // for nsCSSPropertyID
 #include "nsIGlobalObject.h"
 
 // X11 has a #define for CurrentTime.
 #ifdef CurrentTime
 #undef CurrentTime
 #endif
 
 // GetCurrentTime is defined in winbase.h as zero argument macro forwarding to
 // GetTickCount().
 #ifdef GetCurrentTime
 #undef GetCurrentTime
 #endif
 
 struct JSContext;
-class nsCSSPropertySet;
+class nsCSSPropertyIDSet;
 class nsIDocument;
 class nsPresContext;
 
 namespace mozilla {
 
 class AnimValuesStyleRule;
 
 namespace dom {
@@ -308,17 +308,17 @@ public:
   bool CanThrottle() const;
   /**
    * Updates |aStyleRule| with the animation values of this animation's effect,
    * if any.
    * Any properties already contained in |aSetProperties| are not changed. Any
    * properties that are changed are added to |aSetProperties|.
    */
   void ComposeStyle(RefPtr<AnimValuesStyleRule>& aStyleRule,
-                    nsCSSPropertySet& aSetProperties);
+                    nsCSSPropertyIDSet& aSetProperties);
 
   void NotifyEffectTimingUpdated();
 
 protected:
   void SilentlySetCurrentTime(const TimeDuration& aNewCurrentTime);
   void SilentlySetPlaybackRate(double aPlaybackRate);
   void CancelNoUpdate();
   void PlayNoUpdate(ErrorResult& aRv, LimitBehavior aLimitBehavior);
--- a/dom/animation/EffectCompositor.cpp
+++ b/dom/animation/EffectCompositor.cpp
@@ -13,17 +13,17 @@
 #include "mozilla/AnimationTarget.h"
 #include "mozilla/AnimationUtils.h"
 #include "mozilla/EffectSet.h"
 #include "mozilla/InitializerList.h"
 #include "mozilla/LayerAnimationInfo.h"
 #include "mozilla/RestyleManagerHandle.h"
 #include "mozilla/RestyleManagerHandleInlines.h"
 #include "nsComputedDOMStyle.h" // nsComputedDOMStyle::GetPresShellForContent
-#include "nsCSSPropertySet.h"
+#include "nsCSSPropertyIDSet.h"
 #include "nsCSSProps.h"
 #include "nsIPresShell.h"
 #include "nsLayoutUtils.h"
 #include "nsRuleNode.h" // For nsRuleNode::ComputePropertiesOverridingAnimation
 #include "nsRuleProcessorData.h" // For ElementRuleProcessorData etc.
 #include "nsTArray.h"
 
 using mozilla::dom::Animation;
@@ -56,17 +56,17 @@ NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(E
 // Helper function to factor out the common logic from
 // GetAnimationsForCompositor and HasAnimationsForCompositor.
 //
 // Takes an optional array to fill with eligible animations.
 //
 // Returns true if there are eligible animations, false otherwise.
 bool
 FindAnimationsForCompositor(const nsIFrame* aFrame,
-                            nsCSSProperty aProperty,
+                            nsCSSPropertyID aProperty,
                             nsTArray<RefPtr<dom::Animation>>* aMatches /*out*/)
 {
   MOZ_ASSERT(!aMatches || aMatches->IsEmpty(),
              "Matches array, if provided, should be empty");
 
   EffectSet* effects = EffectSet::GetEffectSet(aFrame);
   if (!effects || effects->IsEmpty()) {
     return false;
@@ -428,40 +428,40 @@ EffectCompositor::AddStyleUpdatesTo(Rest
 
     elementSet.Clear();
     // Note: mElement pointers in elementsToRestyle might now dangle
   }
 }
 
 /* static */ bool
 EffectCompositor::HasAnimationsForCompositor(const nsIFrame* aFrame,
-                                             nsCSSProperty aProperty)
+                                             nsCSSPropertyID aProperty)
 {
   return FindAnimationsForCompositor(aFrame, aProperty, nullptr);
 }
 
 /* static */ nsTArray<RefPtr<dom::Animation>>
 EffectCompositor::GetAnimationsForCompositor(const nsIFrame* aFrame,
-                                             nsCSSProperty aProperty)
+                                             nsCSSPropertyID aProperty)
 {
   nsTArray<RefPtr<dom::Animation>> result;
 
 #ifdef DEBUG
   bool foundSome =
 #endif
     FindAnimationsForCompositor(aFrame, aProperty, &result);
   MOZ_ASSERT(!foundSome || !result.IsEmpty(),
              "If return value is true, matches array should be non-empty");
 
   return result;
 }
 
 /* static */ void
 EffectCompositor::ClearIsRunningOnCompositor(const nsIFrame *aFrame,
-                                             nsCSSProperty aProperty)
+                                             nsCSSPropertyID aProperty)
 {
   EffectSet* effects = EffectSet::GetEffectSet(aFrame);
   if (!effects) {
     return;
   }
 
   for (KeyframeEffectReadOnly* effect : *effects) {
     effect->SetIsRunningOnCompositor(aProperty, false);
@@ -593,37 +593,37 @@ EffectCompositor::ComposeAnimationRule(d
   RefPtr<AnimValuesStyleRule>& animationRule =
     effects->AnimationRule(aCascadeLevel);
   animationRule = nullptr;
 
   // If multiple animations specify behavior for the same property the
   // animation with the *highest* composite order wins.
   // As a result, we iterate from last animation to first and, if a
   // property has already been set, we don't change it.
-  nsCSSPropertySet properties;
+  nsCSSPropertyIDSet properties;
 
   for (KeyframeEffectReadOnly* effect : Reversed(sortedEffectList)) {
     effect->GetAnimation()->ComposeStyle(animationRule, properties);
   }
 
   MOZ_ASSERT(effects == EffectSet::GetEffectSet(aElement, aPseudoType),
              "EffectSet should not change while composing style");
 
   effects->UpdateAnimationRuleRefreshTime(aCascadeLevel, aRefreshTime);
 }
 
 /* static */ void
 EffectCompositor::GetOverriddenProperties(nsStyleContext* aStyleContext,
                                           EffectSet& aEffectSet,
-                                          nsCSSPropertySet&
+                                          nsCSSPropertyIDSet&
                                             aPropertiesOverridden)
 {
-  AutoTArray<nsCSSProperty, LayerAnimationInfo::kRecords> propertiesToTrack;
+  AutoTArray<nsCSSPropertyID, LayerAnimationInfo::kRecords> propertiesToTrack;
   {
-    nsCSSPropertySet propertiesToTrackAsSet;
+    nsCSSPropertyIDSet propertiesToTrackAsSet;
     for (KeyframeEffectReadOnly* effect : aEffectSet) {
       for (const AnimationProperty& property : effect->Properties()) {
         if (nsCSSProps::PropHasFlags(property.mProperty,
                                      CSS_PROPERTY_CAN_ANIMATE_ON_COMPOSITOR) &&
             !propertiesToTrackAsSet.HasProperty(property.mProperty)) {
           propertiesToTrackAsSet.AddProperty(property.mProperty);
           propertiesToTrack.AppendElement(property.mProperty);
         }
@@ -665,23 +665,23 @@ EffectCompositor::UpdateCascadeResults(E
   }
   sortedEffectList.Sort(EffectCompositeOrderComparator());
 
   // Get properties that override the *animations* level of the cascade.
   //
   // We only do this for properties that we can animate on the compositor
   // since we will apply other properties on the main thread where the usual
   // cascade applies.
-  nsCSSPropertySet overriddenProperties;
+  nsCSSPropertyIDSet overriddenProperties;
   if (aStyleContext) {
     GetOverriddenProperties(aStyleContext, aEffectSet, overriddenProperties);
   }
 
   bool changed = false;
-  nsCSSPropertySet animatedProperties;
+  nsCSSPropertyIDSet animatedProperties;
 
   // Iterate from highest to lowest composite order.
   for (KeyframeEffectReadOnly* effect : Reversed(sortedEffectList)) {
     MOZ_ASSERT(effect->GetAnimation(),
                "Effects on a target element should have an Animation");
     bool inEffect = effect->IsInEffect();
     for (AnimationProperty& prop : effect->Properties()) {
 
@@ -743,17 +743,17 @@ EffectCompositor::GetPresContext(Element
     return nullptr;
   }
   return shell->GetPresContext();
 }
 
 /* static */ void
 EffectCompositor::SetPerformanceWarning(
   const nsIFrame *aFrame,
-  nsCSSProperty aProperty,
+  nsCSSPropertyID aProperty,
   const AnimationPerformanceWarning& aWarning)
 {
   EffectSet* effects = EffectSet::GetEffectSet(aFrame);
   if (!effects) {
     return;
   }
 
   for (KeyframeEffectReadOnly* effect : *effects) {
--- a/dom/animation/EffectCompositor.h
+++ b/dom/animation/EffectCompositor.h
@@ -7,23 +7,23 @@
 #ifndef mozilla_EffectCompositor_h
 #define mozilla_EffectCompositor_h
 
 #include "mozilla/EnumeratedArray.h"
 #include "mozilla/Maybe.h"
 #include "mozilla/OwningNonNull.h"
 #include "mozilla/PseudoElementHashEntry.h"
 #include "mozilla/RefPtr.h"
-#include "nsCSSProperty.h"
+#include "nsCSSPropertyID.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsDataHashtable.h"
 #include "nsIStyleRuleProcessor.h"
 #include "nsTArray.h"
 
-class nsCSSPropertySet;
+class nsCSSPropertyIDSet;
 class nsIFrame;
 class nsIStyleRule;
 class nsPresContext;
 class nsStyleContext;
 
 namespace mozilla {
 
 class EffectSet;
@@ -157,24 +157,24 @@ public:
   void AddStyleUpdatesTo(RestyleTracker& aTracker);
 
   nsIStyleRuleProcessor* RuleProcessor(CascadeLevel aCascadeLevel) const
   {
     return mRuleProcessors[aCascadeLevel];
   }
 
   static bool HasAnimationsForCompositor(const nsIFrame* aFrame,
-                                         nsCSSProperty aProperty);
+                                         nsCSSPropertyID aProperty);
 
   static nsTArray<RefPtr<dom::Animation>>
   GetAnimationsForCompositor(const nsIFrame* aFrame,
-                             nsCSSProperty aProperty);
+                             nsCSSPropertyID aProperty);
 
   static void ClearIsRunningOnCompositor(const nsIFrame* aFrame,
-                                         nsCSSProperty aProperty);
+                                         nsCSSPropertyID aProperty);
 
   // Update animation cascade results for the specified (pseudo-)element
   // but only if we have marked the cascade as needing an update due a
   // the change in the set of effects or a change in one of the effects'
   // "in effect" state.
   // |aStyleContext| may be nullptr in which case we will use the
   // nsStyleContext of the primary frame of the specified (pseudo-)element.
   //
@@ -207,17 +207,17 @@ public:
   // animations.
   static Maybe<NonOwningAnimationTarget>
   GetAnimationElementAndPseudoForFrame(const nsIFrame* aFrame);
 
   // Associates a performance warning with effects on |aFrame| that animates
   // |aProperty|.
   static void SetPerformanceWarning(
     const nsIFrame* aFrame,
-    nsCSSProperty aProperty,
+    nsCSSPropertyID aProperty,
     const AnimationPerformanceWarning& aWarning);
 
 private:
   ~EffectCompositor() = default;
 
   // Rebuilds the animation rule corresponding to |aCascadeLevel| on the
   // EffectSet associated with the specified (pseudo-)element.
   static void ComposeAnimationRule(dom::Element* aElement,
@@ -230,17 +230,17 @@ private:
                                              aPseudoType);
 
   // Get the properties in |aEffectSet| that we are able to animate on the
   // compositor but which are also specified at a higher level in the cascade
   // than the animations level in |aStyleContext|.
   static void
   GetOverriddenProperties(nsStyleContext* aStyleContext,
                           EffectSet& aEffectSet,
-                          nsCSSPropertySet& aPropertiesOverridden);
+                          nsCSSPropertyIDSet& aPropertiesOverridden);
 
   static void
   UpdateCascadeResults(EffectSet& aEffectSet,
                        dom::Element* aElement,
                        CSSPseudoElementType aPseudoType,
                        nsStyleContext* aStyleContext);
 
   static nsPresContext* GetPresContext(dom::Element* aElement);
--- a/dom/animation/KeyframeEffect.cpp
+++ b/dom/animation/KeyframeEffect.cpp
@@ -11,17 +11,17 @@
 #include "mozilla/AnimationUtils.h"
 #include "mozilla/FloatingPoint.h"
 #include "mozilla/LookAndFeel.h" // For LookAndFeel::GetInt
 #include "mozilla/KeyframeUtils.h"
 #include "mozilla/StyleAnimationValue.h"
 #include "Layers.h" // For Layer
 #include "nsComputedDOMStyle.h" // nsComputedDOMStyle::GetStyleContextForElement
 #include "nsContentUtils.h"  // nsContentUtils::ReportToConsole
-#include "nsCSSPropertySet.h"
+#include "nsCSSPropertyIDSet.h"
 #include "nsCSSProps.h" // For nsCSSProps::PropHasFlags
 #include "nsCSSPseudoElements.h" // For CSSPseudoElementType
 #include "nsDOMMutationObserver.h" // For nsAutoAnimationMutationBatch
 #include "nsIPresShell.h" // For nsIPresShell
 #include "nsIScriptError.h"
 
 namespace mozilla {
 
@@ -487,17 +487,17 @@ KeyframeEffectReadOnly::SetKeyframes(nsT
 
   if (aStyleContext) {
     UpdateProperties(aStyleContext);
     MaybeUpdateFrameForCompositor();
   }
 }
 
 const AnimationProperty*
-KeyframeEffectReadOnly::GetAnimationOfProperty(nsCSSProperty aProperty) const
+KeyframeEffectReadOnly::GetAnimationOfProperty(nsCSSPropertyID aProperty) const
 {
   for (size_t propIdx = 0, propEnd = mProperties.Length();
        propIdx != propEnd; ++propIdx) {
     if (aProperty == mProperties[propIdx].mProperty) {
       const AnimationProperty* result = &mProperties[propIdx];
       if (!result->mWinsInCascade) {
         result = nullptr;
       }
@@ -570,18 +570,18 @@ KeyframeEffectReadOnly::UpdateProperties
     mKeyframes.SwapElements(keyframesCopy);
   }
 
   if (mProperties == properties) {
     return;
   }
 
   // Preserve the state of mWinsInCascade and mIsRunningOnCompositor flags.
-  nsCSSPropertySet winningInCascadeProperties;
-  nsCSSPropertySet runningOnCompositorProperties;
+  nsCSSPropertyIDSet winningInCascadeProperties;
+  nsCSSPropertyIDSet runningOnCompositorProperties;
 
   for (const AnimationProperty& property : mProperties) {
     if (property.mWinsInCascade) {
       winningInCascadeProperties.AddProperty(property.mProperty);
     }
     if (property.mIsRunningOnCompositor) {
       runningOnCompositorProperties.AddProperty(property.mProperty);
     }
@@ -606,17 +606,17 @@ KeyframeEffectReadOnly::UpdateProperties
     }
 
     RequestRestyle(EffectCompositor::RestyleType::Layer);
   }
 }
 
 void
 KeyframeEffectReadOnly::ComposeStyle(RefPtr<AnimValuesStyleRule>& aStyleRule,
-                                     nsCSSPropertySet& aSetProperties)
+                                     nsCSSPropertyIDSet& aSetProperties)
 {
   ComputedTiming computedTiming = GetComputedTiming();
   mProgressOnLastCompose = computedTiming.mProgress;
 
   // If the progress is null, we don't have fill data for the current
   // time so we shouldn't animate.
   if (computedTiming.mProgress.IsNull()) {
     return;
@@ -720,17 +720,17 @@ KeyframeEffectReadOnly::IsRunningOnCompo
     if (property.mIsRunningOnCompositor) {
       return true;
     }
   }
   return false;
 }
 
 void
-KeyframeEffectReadOnly::SetIsRunningOnCompositor(nsCSSProperty aProperty,
+KeyframeEffectReadOnly::SetIsRunningOnCompositor(nsCSSPropertyID aProperty,
                                                  bool aIsRunning)
 {
   MOZ_ASSERT(nsCSSProps::PropHasFlags(aProperty,
                                       CSS_PROPERTY_CAN_ANIMATE_ON_COMPOSITOR),
              "Property being animated on compositor is a recognized "
              "compositor-animatable property");
   for (AnimationProperty& property : mProperties) {
     if (property.mProperty == aProperty) {
@@ -1000,17 +1000,17 @@ KeyframeEffectReadOnly::GetTarget(
 
     default:
       NS_NOTREACHED("Animation of unsupported pseudo-type");
       aRv.SetNull();
   }
 }
 
 static void
-CreatePropertyValue(nsCSSProperty aProperty,
+CreatePropertyValue(nsCSSPropertyID aProperty,
                     float aOffset,
                     const Maybe<ComputedTimingFunction>& aTimingFunction,
                     const StyleAnimationValue& aValue,
                     AnimationPropertyValueDetails& aResult)
 {
   aResult.mOffset = aOffset;
 
   nsString stringValue;
@@ -1127,17 +1127,17 @@ KeyframeEffectReadOnly::GetKeyframes(JSC
     JS::Rooted<JSObject*> keyframeObject(aCx, &keyframeJSValue.toObject());
     for (const PropertyValuePair& propertyValue : keyframe.mPropertyValues) {
 
       const char* name = nsCSSProps::PropertyIDLName(propertyValue.mProperty);
 
       // nsCSSValue::AppendToString does not accept shorthands properties but
       // works with token stream values if we pass eCSSProperty_UNKNOWN as
       // the property.
-      nsCSSProperty propertyForSerializing =
+      nsCSSPropertyID propertyForSerializing =
         nsCSSProps::IsShorthand(propertyValue.mProperty)
         ? eCSSProperty_UNKNOWN
         : propertyValue.mProperty;
 
       nsAutoString stringValue;
       propertyValue.mValue.AppendToString(
         propertyForSerializing, stringValue, nsCSSValue::eNormalized);
 
@@ -1347,17 +1347,17 @@ KeyframeEffectReadOnly::GetPresContext()
   if (!shell) {
     return nullptr;
   }
   return shell->GetPresContext();
 }
 
 /* static */ bool
 KeyframeEffectReadOnly::IsGeometricProperty(
-  const nsCSSProperty aProperty)
+  const nsCSSPropertyID aProperty)
 {
   switch (aProperty) {
     case eCSSProperty_bottom:
     case eCSSProperty_height:
     case eCSSProperty_left:
     case eCSSProperty_right:
     case eCSSProperty_top:
     case eCSSProperty_width:
@@ -1433,17 +1433,17 @@ KeyframeEffectReadOnly::ShouldBlockAsync
     }
   }
 
   return false;
 }
 
 void
 KeyframeEffectReadOnly::SetPerformanceWarning(
-  nsCSSProperty aProperty,
+  nsCSSPropertyID aProperty,
   const AnimationPerformanceWarning& aWarning)
 {
   for (AnimationProperty& property : mProperties) {
     if (property.mProperty == aProperty &&
         (!property.mPerformanceWarning ||
          *property.mPerformanceWarning != aWarning)) {
       property.mPerformanceWarning = Some(aWarning);
 
@@ -1454,17 +1454,17 @@ KeyframeEffectReadOnly::SetPerformanceWa
         AnimationUtils::LogAsyncAnimationFailure(logMessage, mTarget->mElement);
       }
       return;
     }
   }
 }
 
 static already_AddRefed<nsStyleContext>
-CreateStyleContextForAnimationValue(nsCSSProperty aProperty,
+CreateStyleContextForAnimationValue(nsCSSPropertyID aProperty,
                                     StyleAnimationValue aValue,
                                     nsStyleContext* aBaseStyleContext)
 {
   MOZ_ASSERT(aBaseStyleContext,
              "CreateStyleContextForAnimationValue needs to be called "
              "with a valid nsStyleContext");
 
   RefPtr<AnimValuesStyleRule> styleRule = new AnimValuesStyleRule();
--- a/dom/animation/KeyframeEffect.h
+++ b/dom/animation/KeyframeEffect.h
@@ -3,17 +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/. */
 
 #ifndef mozilla_dom_KeyframeEffect_h
 #define mozilla_dom_KeyframeEffect_h
 
 #include "nsChangeHint.h"
-#include "nsCSSProperty.h"
+#include "nsCSSPropertyID.h"
 #include "nsCSSValue.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsTArray.h"
 #include "nsWrapperCache.h"
 #include "mozilla/AnimationPerformanceWarning.h"
 #include "mozilla/AnimationTarget.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/ComputedTiming.h"
@@ -27,17 +27,17 @@
 #include "mozilla/TimeStamp.h"
 #include "mozilla/TimingParams.h"
 #include "mozilla/dom/AnimationEffectReadOnly.h"
 #include "mozilla/dom/AnimationEffectTimingReadOnly.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/Nullable.h"
 
 struct JSContext;
-class nsCSSPropertySet;
+class nsCSSPropertyIDSet;
 class nsIContent;
 class nsIDocument;
 class nsIFrame;
 class nsIPresShell;
 class nsPresContext;
 
 namespace mozilla {
 
@@ -54,17 +54,17 @@ enum class CompositeOperation : uint32_t
 struct AnimationPropertyDetails;
 }
 
 /**
  * A property-value pair specified on a keyframe.
  */
 struct PropertyValuePair
 {
-  nsCSSProperty mProperty;
+  nsCSSPropertyID mProperty;
   // The specified value for the property. For shorthand properties or invalid
   // property values, we store the specified property value as a token stream
   // (string).
   nsCSSValue    mValue;
 
   bool operator==(const PropertyValuePair& aOther) const {
     return mProperty == aOther.mProperty &&
            mValue == aOther.mValue;
@@ -129,17 +129,17 @@ struct AnimationPropertySegment
   }
   bool operator!=(const AnimationPropertySegment& aOther) const {
     return !(*this == aOther);
   }
 };
 
 struct AnimationProperty
 {
-  nsCSSProperty mProperty = eCSSProperty_UNKNOWN;
+  nsCSSPropertyID mProperty = eCSSProperty_UNKNOWN;
 
   // Does this property win in the CSS Cascade?
   //
   // For CSS transitions, this is true as long as a CSS animation on the
   // same property and element is not running, in which case we set this
   // to false so that the animation (lower in the cascade) can win.  We
   // then use this to decide whether to apply the style both in the CSS
   // cascade and for OMTA.
@@ -285,18 +285,18 @@ public:
   void SetAnimation(Animation* aAnimation);
   Animation* GetAnimation() const { return mAnimation; }
 
   void SetKeyframes(JSContext* aContext, JS::Handle<JSObject*> aKeyframes,
                     ErrorResult& aRv);
   void SetKeyframes(nsTArray<Keyframe>&& aKeyframes,
                     nsStyleContext* aStyleContext);
   const AnimationProperty*
-  GetAnimationOfProperty(nsCSSProperty aProperty) const;
-  bool HasAnimationOfProperty(nsCSSProperty aProperty) const {
+  GetAnimationOfProperty(nsCSSPropertyID aProperty) const;
+  bool HasAnimationOfProperty(nsCSSPropertyID aProperty) const {
     return GetAnimationOfProperty(aProperty) != nullptr;
   }
   const InfallibleTArray<AnimationProperty>& Properties() const {
     return mProperties;
   }
   InfallibleTArray<AnimationProperty>& Properties() {
     return mProperties;
   }
@@ -305,20 +305,20 @@ public:
   // |aStyleContext| to resolve specified values.
   void UpdateProperties(nsStyleContext* aStyleContext);
 
   // Updates |aStyleRule| with the animation values produced by this
   // AnimationEffect for the current time except any properties already
   // contained in |aSetProperties|.
   // Any updated properties are added to |aSetProperties|.
   void ComposeStyle(RefPtr<AnimValuesStyleRule>& aStyleRule,
-                    nsCSSPropertySet& aSetProperties);
+                    nsCSSPropertyIDSet& aSetProperties);
   // Returns true if at least one property is being animated on compositor.
   bool IsRunningOnCompositor() const;
-  void SetIsRunningOnCompositor(nsCSSProperty aProperty, bool aIsRunning);
+  void SetIsRunningOnCompositor(nsCSSPropertyID aProperty, bool aIsRunning);
   void ResetIsRunningOnCompositor();
 
   // Returns true if this effect, applied to |aFrame|, contains properties
   // that mean we shouldn't run transform compositor animations on this element.
   //
   // For example, if we have an animation of geometric properties like 'left'
   // and 'top' on an element, we force all 'transform' animations running at
   // the same time on the same element to run on the main thread.
@@ -333,17 +333,17 @@ public:
   nsPresContext* GetPresContext() const;
   nsIPresShell* GetPresShell() const;
 
   // Associates a warning with the animated property on the specified frame
   // indicating why, for example, the property could not be animated on the
   // compositor. |aParams| and |aParamsLength| are optional parameters which
   // will be used to generate a localized message for devtools.
   void SetPerformanceWarning(
-    nsCSSProperty aProperty,
+    nsCSSPropertyID aProperty,
     const AnimationPerformanceWarning& aWarning);
 
   // Cumulative change hint on each segment for each property.
   // This is used for deciding the animation is paint-only.
   void CalculateCumulativeChangeHint(nsStyleContext* aStyleContext);
 
   // Returns true if all of animation properties' change hints
   // can ignore painting if the animation is not visible.
@@ -429,17 +429,17 @@ private:
   bool CanThrottleTransformChanges(nsIFrame& aFrame) const;
 
   // Returns true unless Gecko limitations prevent performing transform
   // animations for |aFrame|. When returning true, the reason for the
   // limitation is stored in |aOutPerformanceWarning|.
   static bool CanAnimateTransformOnCompositor(
     const nsIFrame* aFrame,
     AnimationPerformanceWarning::Type& aPerformanceWarning);
-  static bool IsGeometricProperty(const nsCSSProperty aProperty);
+  static bool IsGeometricProperty(const nsCSSPropertyID aProperty);
 
   static const TimeDuration OverflowRegionRefreshInterval();
 };
 
 class KeyframeEffect : public KeyframeEffectReadOnly
 {
 public:
   KeyframeEffect(nsIDocument* aDocument,
--- a/dom/animation/KeyframeEffectParams.cpp
+++ b/dom/animation/KeyframeEffectParams.cpp
@@ -101,17 +101,17 @@ ConsumeIdentToken(RangedPtr<const char16
     }
     ++aIter;
   }
 }
 
 /* static */ void
 KeyframeEffectParams::ParseSpacing(const nsAString& aSpacing,
                                    SpacingMode& aSpacingMode,
-                                   nsCSSProperty& aPacedProperty,
+                                   nsCSSPropertyID& aPacedProperty,
                                    nsAString& aInvalidPacedProperty,
                                    ErrorResult& aRv)
 {
   aInvalidPacedProperty.Truncate();
 
   // Ignore spacing if the core API is not enabled since it is not yet ready to
   // ship.
   if (!AnimationUtils::IsCoreAPIEnabled()) {
--- a/dom/animation/KeyframeEffectParams.h
+++ b/dom/animation/KeyframeEffectParams.h
@@ -40,21 +40,21 @@ struct KeyframeEffectParams
    * @param [out] aInvalidPacedProperty A string that, if we parsed a string of
    *                                    the form 'paced(<ident>)' where <ident>
    *                                    is not a recognized animatable property,
    *                                    will be set to <ident>.
    * @param [out] aRv The error result.
    */
   static void ParseSpacing(const nsAString& aSpacing,
                            SpacingMode& aSpacingMode,
-                           nsCSSProperty& aPacedProperty,
+                           nsCSSPropertyID& aPacedProperty,
                            nsAString& aInvalidPacedProperty,
                            ErrorResult& aRv);
 
   // FIXME: Bug 1216843: Add IterationCompositeOperations and
   //        Bug 1216844: Add CompositeOperation
   SpacingMode mSpacingMode = SpacingMode::distribute;
-  nsCSSProperty mPacedProperty = eCSSProperty_UNKNOWN;
+  nsCSSPropertyID mPacedProperty = eCSSProperty_UNKNOWN;
 };
 
 } // namespace mozilla
 
 #endif // mozilla_KeyframeEffectParams_h
--- a/dom/animation/KeyframeUtils.cpp
+++ b/dom/animation/KeyframeUtils.cpp
@@ -34,17 +34,17 @@ namespace mozilla {
 // we set its cumulative distance to kNotPaceable, so we can use this to check.
 const double kNotPaceable = -1.0;
 
 // For the aAllowList parameter of AppendStringOrStringSequence and
 // GetPropertyValuesPairs.
 enum class ListAllowance { eDisallow, eAllow };
 
 /**
- * A comparator to sort nsCSSProperty values such that longhands are sorted
+ * A comparator to sort nsCSSPropertyID values such that longhands are sorted
  * before shorthands, and shorthands with fewer components are sorted before
  * shorthands with more components.
  *
  * Using this allows us to prioritize values specified by longhands (or smaller
  * shorthand subsets) when longhands and shorthands are both specified
  * on the one keyframe.
  *
  * Example orderings that result from this:
@@ -56,23 +56,23 @@ enum class ListAllowance { eDisallow, eA
  *   border-top-color, border-color, border-top, border
  */
 class PropertyPriorityComparator
 {
 public:
   PropertyPriorityComparator()
     : mSubpropertyCountInitialized(false) {}
 
-  bool Equals(nsCSSProperty aLhs, nsCSSProperty aRhs) const
+  bool Equals(nsCSSPropertyID aLhs, nsCSSPropertyID aRhs) const
   {
     return aLhs == aRhs;
   }
 
-  bool LessThan(nsCSSProperty aLhs,
-                nsCSSProperty aRhs) const
+  bool LessThan(nsCSSPropertyID aLhs,
+                nsCSSPropertyID aRhs) const
   {
     bool isShorthandLhs = nsCSSProps::IsShorthand(aLhs);
     bool isShorthandRhs = nsCSSProps::IsShorthand(aRhs);
 
     if (isShorthandLhs) {
       if (isShorthandRhs) {
         // First, sort shorthands by the number of longhands they have.
         uint32_t subpropCountLhs = SubpropertyCount(aLhs);
@@ -92,17 +92,17 @@ public:
       }
     }
     // For two longhand properties, or two shorthand with the same number
     // of longhand components, sort by IDL name.
     return nsCSSProps::PropertyIDLNameSortPosition(aLhs) <
            nsCSSProps::PropertyIDLNameSortPosition(aRhs);
   }
 
-  uint32_t SubpropertyCount(nsCSSProperty aProperty) const
+  uint32_t SubpropertyCount(nsCSSPropertyID aProperty) const
   {
     if (!mSubpropertyCountInitialized) {
       PodZero(&mSubpropertyCount);
       mSubpropertyCountInitialized = true;
     }
     if (mSubpropertyCount[aProperty] == 0) {
       uint32_t count = 0;
       CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(
@@ -200,17 +200,17 @@ public:
   };
 
   Iter begin() { return Iter(*this); }
   Iter end()   { return Iter::EndIter(*this); }
 
 private:
   struct PropertyAndIndex
   {
-    nsCSSProperty mProperty;
+    nsCSSPropertyID mProperty;
     size_t mIndex; // Index of mProperty within mProperties
 
     typedef TPropertyPriorityComparator<PropertyAndIndex> Comparator;
   };
 
   const nsTArray<PropertyValuePair>& mProperties;
   nsTArray<PropertyAndIndex> mSortedPropertyIndices;
 };
@@ -220,29 +220,29 @@ private:
  * discovered on a regular keyframe or property-indexed keyframe object.
  *
  * Single values (as required by a regular keyframe, and as also supported
  * on property-indexed keyframes) are stored as the only element in
  * mValues.
  */
 struct PropertyValuesPair
 {
-  nsCSSProperty mProperty;
+  nsCSSPropertyID mProperty;
   nsTArray<nsString> mValues;
 
   typedef TPropertyPriorityComparator<PropertyValuesPair> Comparator;
 };
 
 /**
  * An additional property (for a property-values pair) found on a
  * BaseKeyframe or BasePropertyIndexedKeyframe object.
  */
 struct AdditionalProperty
 {
-  nsCSSProperty mProperty;
+  nsCSSPropertyID mProperty;
   size_t mJsidIndex;        // Index into |ids| in GetPropertyValuesPairs.
 
   struct PropertyComparator
   {
     bool Equals(const AdditionalProperty& aLhs,
                 const AdditionalProperty& aRhs) const
     {
       return aLhs.mProperty == aRhs.mProperty;
@@ -260,17 +260,17 @@ struct AdditionalProperty
  * Data for a segment in a keyframe animation of a given property
  * whose value is a StyleAnimationValue.
  *
  * KeyframeValueEntry is used in GetAnimationPropertiesFromKeyframes
  * to gather data for each individual segment.
  */
 struct KeyframeValueEntry
 {
-  nsCSSProperty mProperty;
+  nsCSSPropertyID mProperty;
   StyleAnimationValue mValue;
   float mOffset;
   Maybe<ComputedTimingFunction> mTimingFunction;
 
   struct PropertyOffsetComparator
   {
     static bool Equals(const KeyframeValueEntry& aLhs,
                        const KeyframeValueEntry& aRhs)
@@ -365,17 +365,17 @@ AppendStringOrStringSequenceToArray(JSCo
                                     nsTArray<nsString>& aValues);
 
 static bool
 AppendValueAsString(JSContext* aCx,
                     nsTArray<nsString>& aValues,
                     JS::Handle<JS::Value> aValue);
 
 static PropertyValuePair
-MakePropertyValuePair(nsCSSProperty aProperty, const nsAString& aStringValue,
+MakePropertyValuePair(nsCSSPropertyID aProperty, const nsAString& aStringValue,
                       nsCSSParser& aParser, nsIDocument* aDocument);
 
 static bool
 HasValidOffsets(const nsTArray<Keyframe>& aKeyframes);
 
 static void
 MarkAsComputeValuesFailureKey(PropertyValuePair& aPair);
 
@@ -406,17 +406,17 @@ static void
 DistributeRange(const Range<Keyframe>& aSpacingRange);
 
 static void
 PaceRange(const Range<Keyframe>& aKeyframes,
           const Range<double>& aCumulativeDistances);
 
 static nsTArray<double>
 GetCumulativeDistances(const nsTArray<ComputedKeyframeValues>& aValues,
-                       nsCSSProperty aProperty);
+                       nsCSSPropertyID aProperty);
 
 // ------------------------------------------------------------------
 //
 // Public API
 //
 // ------------------------------------------------------------------
 
 /* static */ nsTArray<Keyframe>
@@ -469,17 +469,17 @@ KeyframeUtils::GetKeyframesFromObject(JS
   }
 
   return keyframes;
 }
 
 /* static */ void
 KeyframeUtils::ApplySpacing(nsTArray<Keyframe>& aKeyframes,
                             SpacingMode aSpacingMode,
-                            nsCSSProperty aProperty,
+                            nsCSSPropertyID aProperty,
                             nsTArray<ComputedKeyframeValues>& aComputedValues)
 {
   if (aKeyframes.IsEmpty()) {
     return;
   }
 
   nsTArray<double> cumulativeDistances;
   if (aSpacingMode == SpacingMode::paced) {
@@ -587,17 +587,17 @@ KeyframeUtils::GetComputedKeyframeValues
 {
   MOZ_ASSERT(aStyleContext);
   MOZ_ASSERT(aElement);
 
   const size_t len = aKeyframes.Length();
   nsTArray<ComputedKeyframeValues> result(len);
 
   for (const Keyframe& frame : aKeyframes) {
-    nsCSSPropertySet propertiesOnThisKeyframe;
+    nsCSSPropertyIDSet propertiesOnThisKeyframe;
     ComputedKeyframeValues* computedValues = result.AppendElement();
     for (const PropertyValuePair& pair :
            PropertyPriorityIterator(frame.mPropertyValues)) {
       if (IsInvalidValuePair(pair)) {
         continue;
       }
 
       // Expand each value into the set of longhands and produce
@@ -667,17 +667,17 @@ KeyframeUtils::GetAnimationPropertiesFro
   }
 
   nsTArray<AnimationProperty> result;
   BuildSegmentsFromValueEntries(aStyleContext, entries, result);
   return result;
 }
 
 /* static */ bool
-KeyframeUtils::IsAnimatableProperty(nsCSSProperty aProperty)
+KeyframeUtils::IsAnimatableProperty(nsCSSPropertyID aProperty)
 {
   if (aProperty == eCSSProperty_UNKNOWN) {
     return false;
   }
 
   if (!nsCSSProps::IsShorthand(aProperty)) {
     return nsCSSProps::kAnimTypeTable[aProperty] != eStyleAnimType_None;
   }
@@ -858,17 +858,17 @@ GetPropertyValuesPairs(JSContext* aCx,
   if (!JS_Enumerate(aCx, aObject, &ids)) {
     return false;
   }
   for (size_t i = 0, n = ids.length(); i < n; i++) {
     nsAutoJSString propName;
     if (!propName.init(aCx, ids[i])) {
       return false;
     }
-    nsCSSProperty property =
+    nsCSSPropertyID property =
       nsCSSProps::LookupPropertyByIDLName(propName,
                                           CSSEnabledState::eForAllContent);
     if (KeyframeUtils::IsAnimatableProperty(property)) {
       AdditionalProperty* p = properties.AppendElement();
       p->mProperty = property;
       p->mJsidIndex = i;
     }
   }
@@ -959,17 +959,17 @@ AppendValueAsString(JSContext* aCx,
  *
  * @param aProperty The CSS property.
  * @param aStringValue The property value to parse.
  * @param aParser The CSS parser object to use.
  * @param aDocument The document to use when parsing.
  * @return The constructed PropertyValuePair object.
  */
 static PropertyValuePair
-MakePropertyValuePair(nsCSSProperty aProperty, const nsAString& aStringValue,
+MakePropertyValuePair(nsCSSPropertyID aProperty, const nsAString& aStringValue,
                       nsCSSParser& aParser, nsIDocument* aDocument)
 {
   MOZ_ASSERT(aDocument);
 
   nsCSSValue value;
   if (!nsCSSProps::IsShorthand(aProperty)) {
     aParser.ParseLonghandProperty(aProperty,
                                   aStringValue,
@@ -1111,17 +1111,17 @@ BuildSegmentsFromValueEntries(nsStyleCon
   // one KeyframeValueEntry with offset 0.0, and at least one with offset 1.0.
   // However, since it is possible that when building |aEntries|, the call to
   // StyleAnimationValue::ComputeValues might fail, this can't be guaranteed.
   // Furthermore, since we don't yet implement additive animation and hence
   // don't have sensible fallback behavior when these values are missing, the
   // following loop takes care to identify properties that lack a value at
   // offset 0.0/1.0 and drops those properties from |aResult|.
 
-  nsCSSProperty lastProperty = eCSSProperty_UNKNOWN;
+  nsCSSPropertyID lastProperty = eCSSProperty_UNKNOWN;
   AnimationProperty* animationProperty = nullptr;
 
   size_t i = 0, n = aEntries.Length();
 
   while (i < n) {
     // Check that the last property ends with an entry at offset 1.
     if (i + 1 == n) {
       if (aEntries[i].mOffset != 1.0f && animationProperty) {
@@ -1326,21 +1326,21 @@ RequiresAdditiveAnimation(const nsTArray
   // StyleAnimationValue since doing that requires a target element bound to
   // a document which we might not always have at the point where we want to
   // perform this check.
   //
   // This is only a temporary measure until we implement additive animation.
   // So as long as this check catches most cases, and we don't do anything
   // horrible in one of the cases we can't detect, it should be sufficient.
 
-  nsCSSPropertySet properties;              // All properties encountered.
-  nsCSSPropertySet propertiesWithFromValue; // Those with a defined 0% value.
-  nsCSSPropertySet propertiesWithToValue;   // Those with a defined 100% value.
+  nsCSSPropertyIDSet properties;              // All properties encountered.
+  nsCSSPropertyIDSet propertiesWithFromValue; // Those with a defined 0% value.
+  nsCSSPropertyIDSet propertiesWithToValue;   // Those with a defined 100% value.
 
-  auto addToPropertySets = [&](nsCSSProperty aProperty, double aOffset) {
+  auto addToPropertySets = [&](nsCSSPropertyID aProperty, double aOffset) {
     properties.AddProperty(aProperty);
     if (aOffset == 0.0) {
       propertiesWithFromValue.AddProperty(aProperty);
     } else if (aOffset == 1.0) {
       propertiesWithToValue.AddProperty(aProperty);
     }
   };
 
@@ -1495,22 +1495,22 @@ PaceRange(const Range<Keyframe>& aKeyfra
  *
  * @param aValues The computed values returned by GetComputedKeyframeValues.
  * @param aPacedProperty The paced property.
  * @return The cumulative distances for the paced property. The length will be
  *   the same as aValues.
  */
 static nsTArray<double>
 GetCumulativeDistances(const nsTArray<ComputedKeyframeValues>& aValues,
-                       nsCSSProperty aPacedProperty)
+                       nsCSSPropertyID aPacedProperty)
 {
   // a) If aPacedProperty is a shorthand property, get its components.
   //    Otherwise, just add the longhand property into the set.
   size_t pacedPropertyCount = 0;
-  nsCSSPropertySet pacedPropertySet;
+  nsCSSPropertyIDSet pacedPropertySet;
   bool isShorthand = nsCSSProps::IsShorthand(aPacedProperty);
   if (isShorthand) {
     CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(p, aPacedProperty,
                                          CSSEnabledState::eForAllContent) {
       pacedPropertySet.AddProperty(*p);
       ++pacedPropertyCount;
     }
   } else {
@@ -1547,17 +1547,17 @@ GetCumulativeDistances(const nsTArray<Co
       // This is the first paceable keyframe so its cumulative distance is 0.0.
       cumulativeDistances[i] = 0.0;
     } else {
       double dist = 0.0;
       if (isShorthand) {
         // Apply the distance by the square root of the sum of squares of
         // longhand component distances.
         for (size_t propIdx = 0; propIdx < pacedPropertyCount; ++propIdx) {
-          nsCSSProperty prop = prevPacedValues[propIdx].mProperty;
+          nsCSSPropertyID prop = prevPacedValues[propIdx].mProperty;
           MOZ_ASSERT(pacedValues[propIdx].mProperty == prop,
                      "Property mismatch");
 
           double componentDistance = 0.0;
           if (StyleAnimationValue::ComputeDistance(
                 prop,
                 prevPacedValues[propIdx].mValue,
                 pacedValues[propIdx].mValue,
--- a/dom/animation/KeyframeUtils.h
+++ b/dom/animation/KeyframeUtils.h
@@ -93,17 +93,17 @@ public:
    *   any value, e.g. eCSSProperty_UNKNOWN.
    * @param aComputedValues The set of computed keyframe values as returned by
    *   GetComputedKeyframeValues. Only used when |aSpacingMode| is
    *   SpacingMode::paced. In all other cases this parameter is unused and may
    *   be any value including an empty array.
    */
   static void ApplySpacing(nsTArray<Keyframe>& aKeyframes,
                            SpacingMode aSpacingMode,
-                           nsCSSProperty aProperty,
+                           nsCSSPropertyID aProperty,
                            nsTArray<ComputedKeyframeValues>& aComputedValues);
 
   /**
    * Wrapper for ApplySpacing to simplify using distribute spacing.
    *
    * @param aKeyframes The set of keyframes to adjust.
    */
   static void ApplyDistributeSpacing(nsTArray<Keyframe>& aKeyframes);
@@ -132,14 +132,14 @@ public:
 
   /**
    * Check if the property or, for shorthands, one or more of
    * its subproperties, is animatable.
    *
    * @param aProperty The property to check.
    * @return true if |aProperty| is animatable.
    */
-  static bool IsAnimatableProperty(nsCSSProperty aProperty);
+  static bool IsAnimatableProperty(nsCSSPropertyID aProperty);
 };
 
 } // namespace mozilla
 
 #endif // mozilla_KeyframeUtils_h
--- a/dom/asmjscache/AsmJSCache.cpp
+++ b/dom/asmjscache/AsmJSCache.cpp
@@ -1406,31 +1406,24 @@ private:
 
 NS_IMETHODIMP
 ChildRunnable::Run()
 {
   switch (mState) {
     case eInitial: {
       MOZ_ASSERT(NS_IsMainThread());
 
-      bool nullPrincipal;
-      nsresult rv = mPrincipal->GetIsNullPrincipal(&nullPrincipal);
-      if (NS_WARN_IF(NS_FAILED(rv))) {
-        Fail(JS::AsmJSCache_InternalError);
-        return NS_OK;
-      }
-
-      if (nullPrincipal) {
+      if (mPrincipal->GetIsNullPrincipal()) {
         NS_WARNING("AsmsJSCache not supported on null principal.");
         Fail(JS::AsmJSCache_InternalError);
         return NS_OK;
       }
 
       nsAutoPtr<PrincipalInfo> principalInfo(new PrincipalInfo());
-      rv = PrincipalToPrincipalInfo(mPrincipal, principalInfo);
+      nsresult rv = PrincipalToPrincipalInfo(mPrincipal, principalInfo);
       if (NS_WARN_IF(NS_FAILED(rv))) {
         Fail(JS::AsmJSCache_InternalError);
         return NS_OK;
       }
 
       mPrincipalInfo = Move(principalInfo);
 
       PBackgroundChild* actor = BackgroundChild::GetForCurrentThread();
--- a/dom/base/Element.h
+++ b/dom/base/Element.h
@@ -752,16 +752,31 @@ public:
       // or on element that have status pending pointer capture)
       if (pointerCaptureInfo->mOverrideContent == this) {
         nsIPresShell::ReleasePointerCapturingContent(aPointerId);
       } else if (pointerCaptureInfo->mPendingContent == this) {
         nsIPresShell::ReleasePointerCapturingContent(aPointerId);
       }
     }
   }
+  bool HasPointerCapture(long aPointerId)
+  {
+    bool activeState = false;
+    if (!nsIPresShell::GetPointerInfo(aPointerId, activeState)) {
+      return false;
+    }
+    nsIPresShell::PointerCaptureInfo* pointerCaptureInfo = nullptr;
+    if (nsIPresShell::gPointerCaptureList->Get(aPointerId, &pointerCaptureInfo) &&
+        pointerCaptureInfo && !pointerCaptureInfo->mReleaseContent &&
+        (pointerCaptureInfo->mOverrideContent == this ||
+         pointerCaptureInfo->mPendingContent == this)) {
+      return true;
+    }
+    return false;
+  }
   void SetCapture(bool aRetargetToElement)
   {
     // If there is already an active capture, ignore this request. This would
     // occur if a splitter, frame resizer, etc had already captured and we don't
     // want to override those.
     if (!nsIPresShell::GetCapturingContent()) {
       nsIPresShell::SetCapturingContent(this, CAPTURE_PREVENTDRAG |
         (aRetargetToElement ? CAPTURE_RETARGETTOELEMENT : 0));
--- a/dom/base/WebSocket.cpp
+++ b/dom/base/WebSocket.cpp
@@ -1640,21 +1640,17 @@ WebSocketImpl::Init(JSContext* aCx,
         principal = globalObject->PrincipalOrNull();
       }
 
       nsCOMPtr<nsPIDOMWindowInner> innerWindow;
 
       while (true) {
         bool isNullPrincipal = true;
         if (principal) {
-          nsresult rv = principal->GetIsNullPrincipal(&isNullPrincipal);
-          if (NS_WARN_IF(NS_FAILED(rv))) {
-            aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
-            return;
-          }
+          isNullPrincipal = principal->GetIsNullPrincipal();
         }
 
         if (!isNullPrincipal) {
           break;
         }
 
         if (!innerWindow) {
           innerWindow = do_QueryInterface(globalObject);
--- a/dom/base/nsAttrAndChildArray.cpp
+++ b/dom/base/nsAttrAndChildArray.cpp
@@ -795,17 +795,22 @@ nsAttrAndChildArray::GrowBy(uint32_t aGr
     do {
       size += ATTRCHILD_ARRAY_GROWSIZE;
       if (!size.isValid()) {
         return false;
       }
     } while (size.value() < minSize.value());
   }
   else {
-    size = 1u << mozilla::CeilingLog2(minSize.value());
+    uint32_t shift = mozilla::CeilingLog2(minSize.value());
+    if (shift >= 32) {
+      return false;
+    }
+
+    size = 1u << shift;
   }
 
   bool needToInitialize = !mImpl;
   CheckedUint32 neededSize = size;
   neededSize *= sizeof(void*);
   if (!neededSize.isValid()) {
     return false;
   }
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -8454,19 +8454,17 @@ nsContentUtils::InternalStorageAllowedFo
 {
   MOZ_ASSERT(aPrincipal);
   MOZ_ASSERT(!aWindow || aWindow->IsInnerWindow());
 
   StorageAccess access = StorageAccess::eAllow;
 
   // We don't allow storage on the null principal, in general. Even if the
   // calling context is chrome.
-  bool isNullPrincipal;
-  if (NS_WARN_IF(NS_FAILED(aPrincipal->GetIsNullPrincipal(&isNullPrincipal))) ||
-      isNullPrincipal) {
+  if (aPrincipal->GetIsNullPrincipal()) {
     return StorageAccess::eDeny;
   }
 
   if (aWindow) {
     // If the document is sandboxed, then it is not permitted to use storage
     nsIDocument* document = aWindow->GetExtantDoc();
     if (document->GetSandboxFlags() & SANDBOXED_ORIGIN) {
       return StorageAccess::eDeny;
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -2410,17 +2410,17 @@ nsDOMWindowUtils::BeginTabSwitch()
     return NS_ERROR_FAILURE;
 
   mgr->BeginTabSwitch();
 
   return NS_OK;
 }
 
 static bool
-ComputeAnimationValue(nsCSSProperty aProperty,
+ComputeAnimationValue(nsCSSPropertyID aProperty,
                       Element* aElement,
                       const nsAString& aInput,
                       StyleAnimationValue& aOutput)
 {
   nsIDocument* doc = aElement->GetUncomposedDoc();
   nsIPresShell* shell = doc->GetShell();
   if (!shell) {
     return false;
@@ -2670,17 +2670,17 @@ nsDOMWindowUtils::ComputeAnimationDistan
                                            const nsAString& aValue1,
                                            const nsAString& aValue2,
                                            double* aResult)
 {
   nsresult rv;
   nsCOMPtr<nsIContent> content = do_QueryInterface(aElement, &rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  nsCSSProperty property =
+  nsCSSPropertyID property =
     nsCSSProps::LookupProperty(aProperty, CSSEnabledState::eIgnoreEnabledState);
   if (property != eCSSProperty_UNKNOWN && nsCSSProps::IsShorthand(property)) {
     property = eCSSProperty_UNKNOWN;
   }
 
   MOZ_ASSERT(property == eCSSProperty_UNKNOWN ||
              !nsCSSProps::IsShorthand(property),
              "should not have shorthand");
--- a/dom/base/nsFrameLoader.cpp
+++ b/dom/base/nsFrameLoader.cpp
@@ -2161,19 +2161,17 @@ nsFrameLoader::MaybeCreateDocShell()
     if (mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::name, name)) {
       docShell->SetName(name);
     }
     mDocShell->SetFullscreenAllowed(
       mOwnerContent->HasAttr(kNameSpaceID_None, nsGkAtoms::allowfullscreen) ||
       mOwnerContent->HasAttr(kNameSpaceID_None, nsGkAtoms::mozallowfullscreen));
     bool isPrivate = mOwnerContent->HasAttr(kNameSpaceID_None, nsGkAtoms::mozprivatebrowsing);
     if (isPrivate) {
-      bool nonBlank;
-      mDocShell->GetHasLoadedNonBlankURI(&nonBlank);
-      if (nonBlank) {
+      if (mDocShell->GetHasLoadedNonBlankURI()) {
         nsContentUtils::ReportToConsoleNonLocalized(
           NS_LITERAL_STRING("We should not switch to Private Browsing after loading a document."),
           nsIScriptError::warningFlag,
           NS_LITERAL_CSTRING("mozprivatebrowsing"),
           nullptr);
       } else {
         // This handles the case where a frames private browsing is set by chrome flags
         // and not inherited by its parent.
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -1729,16 +1729,18 @@ nsGlobalWindow::FreeInnerObjects()
 
   if (mApplicationCache) {
     static_cast<nsDOMOfflineResourceList*>(mApplicationCache.get())->Disconnect();
     mApplicationCache = nullptr;
   }
 
   mIndexedDB = nullptr;
 
+  UnlinkHostObjectURIs();
+
   NotifyWindowIDDestroyed("inner-window-destroyed");
 
   CleanupCachedXBLHandlers(this);
 
   for (uint32_t i = 0; i < mAudioContexts.Length(); ++i) {
     mAudioContexts[i]->Shutdown();
   }
   mAudioContexts.Clear();
@@ -12206,34 +12208,32 @@ nsGlobalWindow::RunTimeoutHandler(nsTime
     reason = "setTimeout handler";
   }
 
   bool abortIntervalHandler = false;
   nsCOMPtr<nsIScriptTimeoutHandler> handler(timeout->mScriptHandler);
   RefPtr<Function> callback = handler->GetCallback();
   if (!callback) {
     // Evaluate the timeout expression.
-    const char16_t* script = handler->GetHandlerText();
-    NS_ASSERTION(script, "timeout has no script nor handler text!");
+    nsAutoString script;
+    handler->GetHandlerText(script);
 
     const char* filename = nullptr;
     uint32_t lineNo = 0, dummyColumn = 0;
     handler->GetLocation(&filename, &lineNo, &dummyColumn);
 
     // New script entry point required, due to the "Create a script" sub-step of
     // http://www.whatwg.org/specs/web-apps/current-work/#timer-initialisation-steps
     nsAutoMicroTask mt;
     AutoEntryScript aes(this, reason, true);
     JS::CompileOptions options(aes.cx());
     options.setFileAndLine(filename, lineNo)
            .setVersion(JSVERSION_DEFAULT);
     JS::Rooted<JSObject*> global(aes.cx(), FastGetGlobalJSObject());
-    nsresult rv =
-      nsJSUtils::EvaluateString(aes.cx(), nsDependentString(script),
-                                global, options);
+    nsresult rv = nsJSUtils::EvaluateString(aes.cx(), script, global, options);
     if (rv == NS_SUCCESS_DOM_SCRIPT_EVALUATION_THREW_UNCATCHABLE) {
       abortIntervalHandler = true;
     }
   } else {
     // Hold strong ref to ourselves while we call the callback.
     nsCOMPtr<nsISupports> me(static_cast<nsIDOMWindow *>(this));
     ErrorResult rv;
     JS::Rooted<JS::Value> ignoredVal(RootingCx());
--- a/dom/base/nsIScriptTimeoutHandler.h
+++ b/dom/base/nsIScriptTimeoutHandler.h
@@ -29,17 +29,17 @@ class nsIScriptTimeoutHandler : public n
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_ISCRIPTTIMEOUTHANDLER_IID)
 
   // Get the Function to call.  If this returns nullptr, GetHandlerText() will
   // be called to get the string.
   virtual mozilla::dom::Function *GetCallback() = 0;
 
   // Get the handler text of not a compiled object.
-  virtual const char16_t *GetHandlerText() = 0;
+  virtual void GetHandlerText(nsAString& aString) = 0;
 
   // Get the location of the script.
   // Note: The memory pointed to by aFileName is owned by the
   // nsIScriptTimeoutHandler and should not be freed by the caller.
   virtual void GetLocation(const char **aFileName, uint32_t *aLineNo,
                            uint32_t *aColumn) = 0;
 
   // If we have a Function, get the arguments for passing to it.
--- a/dom/base/nsJSTimeoutHandler.cpp
+++ b/dom/base/nsJSTimeoutHandler.cpp
@@ -12,23 +12,25 @@
 #include "nsContentUtils.h"
 #include "nsError.h"
 #include "nsGlobalWindow.h"
 #include "nsIContentSecurityPolicy.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/Likely.h"
 #include <algorithm>
 #include "mozilla/dom/FunctionBinding.h"
+#include "WorkerPrivate.h"
 #include "nsAXPCNativeCallContext.h"
 
 static const char kSetIntervalStr[] = "setInterval";
 static const char kSetTimeoutStr[] = "setTimeout";
 
 using namespace mozilla;
 using namespace mozilla::dom;
+using namespace mozilla::dom::workers;
 
 // Our JS nsIScriptTimeoutHandler implementation.
 class nsJSScriptTimeoutHandler final : public nsIScriptTimeoutHandler
 {
 public:
   // nsISupports
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsJSScriptTimeoutHandler)
@@ -37,18 +39,23 @@ public:
   // This will call SwapElements on aArguments with an empty array.
   nsJSScriptTimeoutHandler(JSContext* aCx, nsGlobalWindow *aWindow,
                            Function& aFunction,
                            FallibleTArray<JS::Heap<JS::Value> >& aArguments,
                            ErrorResult& aError);
   nsJSScriptTimeoutHandler(JSContext* aCx, nsGlobalWindow *aWindow,
                            const nsAString& aExpression, bool* aAllowEval,
                            ErrorResult& aError);
+  nsJSScriptTimeoutHandler(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
+                           Function& aFunction,
+                           FallibleTArray<JS::Heap<JS::Value> >& aArguments);
+  nsJSScriptTimeoutHandler(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
+                           const nsAString& aExpression);
 
-  virtual const char16_t* GetHandlerText() override;
+  virtual void GetHandlerText(nsAString& aString) override;
   virtual Function* GetCallback() override
   {
     return mFunction;
   }
   virtual void GetLocation(const char** aFileName, uint32_t* aLineNo,
                            uint32_t* aColumn) override
   {
     *aFileName = mFileName.get();
@@ -61,16 +68,20 @@ public:
     return mArgs;
   }
 
   void ReleaseJSObjects();
 
 private:
   ~nsJSScriptTimeoutHandler();
 
+  void Init(JSContext* aCx,
+            FallibleTArray<JS::Heap<JS::Value>>& aArguments);
+  void Init(JSContext* aCx);
+
   // filename, line number and JS language version string of the
   // caller of setTimeout()
   nsCString mFileName;
   uint32_t mLineNo;
   uint32_t mColumn;
   nsTArray<JS::Heap<JS::Value> > mArgs;
 
   // The expression to evaluate or function to call. If mFunction is non-null
@@ -193,34 +204,30 @@ nsJSScriptTimeoutHandler::nsJSScriptTime
   : mLineNo(0)
   , mColumn(0)
 {
 }
 
 nsJSScriptTimeoutHandler::nsJSScriptTimeoutHandler(JSContext* aCx,
                                                    nsGlobalWindow *aWindow,
                                                    Function& aFunction,
-                                                   FallibleTArray<JS::Heap<JS::Value> >& aArguments,
+                                                   FallibleTArray<JS::Heap<JS::Value>>& aArguments,
                                                    ErrorResult& aError)
   : mLineNo(0)
   , mColumn(0)
   , mFunction(&aFunction)
 {
   if (!aWindow->GetContextInternal() || !aWindow->FastGetGlobalJSObject()) {
     // This window was already closed, or never properly initialized,
     // don't let a timer be scheduled on such a window.
     aError.Throw(NS_ERROR_NOT_INITIALIZED);
     return;
   }
 
-  mozilla::HoldJSObjects(this);
-  mArgs.SwapElements(aArguments);
-
-  // Get the calling location.
-  nsJSUtils::GetCallingLocation(aCx, mFileName, &mLineNo, &mColumn);
+  Init(aCx, aArguments);
 }
 
 nsJSScriptTimeoutHandler::nsJSScriptTimeoutHandler(JSContext* aCx,
                                                    nsGlobalWindow *aWindow,
                                                    const nsAString& aExpression,
                                                    bool* aAllowEval,
                                                    ErrorResult& aError)
   : mLineNo(0)
@@ -234,40 +241,83 @@ nsJSScriptTimeoutHandler::nsJSScriptTime
     return;
   }
 
   *aAllowEval = CheckCSPForEval(aCx, aWindow, aError);
   if (aError.Failed() || !*aAllowEval) {
     return;
   }
 
-  // Get the calling location.
-  nsJSUtils::GetCallingLocation(aCx, mFileName, &mLineNo, &mColumn);
+  Init(aCx);
+}
+
+nsJSScriptTimeoutHandler::nsJSScriptTimeoutHandler(JSContext* aCx,
+                                                   WorkerPrivate* aWorkerPrivate,
+                                                   Function& aFunction,
+                                                   FallibleTArray<JS::Heap<JS::Value>>& aArguments)
+  : mLineNo(0)
+  , mColumn(0)
+  , mFunction(&aFunction)
+{
+  MOZ_ASSERT(aWorkerPrivate);
+  aWorkerPrivate->AssertIsOnWorkerThread();
+
+  Init(aCx, aArguments);
+}
+
+nsJSScriptTimeoutHandler::nsJSScriptTimeoutHandler(JSContext* aCx,
+                                                   WorkerPrivate* aWorkerPrivate,
+                                                   const nsAString& aExpression)
+  : mLineNo(0)
+  , mColumn(0)
+  , mExpr(aExpression)
+{
+  MOZ_ASSERT(aWorkerPrivate);
+  aWorkerPrivate->AssertIsOnWorkerThread();
+
+  Init(aCx);
 }
 
 nsJSScriptTimeoutHandler::~nsJSScriptTimeoutHandler()
 {
   ReleaseJSObjects();
 }
 
 void
+nsJSScriptTimeoutHandler::Init(JSContext* aCx,
+                               FallibleTArray<JS::Heap<JS::Value>>& aArguments)
+{
+  mozilla::HoldJSObjects(this);
+  mArgs.SwapElements(aArguments);
+
+  Init(aCx);
+}
+
+void
+nsJSScriptTimeoutHandler::Init(JSContext* aCx)
+{
+  // Get the calling location.
+  nsJSUtils::GetCallingLocation(aCx, mFileName, &mLineNo, &mColumn);
+}
+
+void
 nsJSScriptTimeoutHandler::ReleaseJSObjects()
 {
   if (mFunction) {
     mFunction = nullptr;
     mArgs.Clear();
     mozilla::DropJSObjects(this);
   }
 }
 
-const char16_t *
-nsJSScriptTimeoutHandler::GetHandlerText()
+void
+nsJSScriptTimeoutHandler::GetHandlerText(nsAString& aString)
 {
   NS_ASSERTION(!mFunction, "No expression, so no handler text!");
-  return mExpr.get();
+  aString = mExpr;
 }
 
 already_AddRefed<nsIScriptTimeoutHandler>
 NS_CreateJSTimeoutHandler(JSContext *aCx, nsGlobalWindow *aWindow,
                           Function& aFunction,
                           const Sequence<JS::Value>& aArguments,
                           ErrorResult& aError)
 {
@@ -290,8 +340,34 @@ NS_CreateJSTimeoutHandler(JSContext* aCx
   RefPtr<nsJSScriptTimeoutHandler> handler =
     new nsJSScriptTimeoutHandler(aCx, aWindow, aExpression, &allowEval, aError);
   if (aError.Failed() || !allowEval) {
     return nullptr;
   }
 
   return handler.forget();
 }
+
+already_AddRefed<nsIScriptTimeoutHandler>
+NS_CreateJSTimeoutHandler(JSContext *aCx, WorkerPrivate* aWorkerPrivate,
+                          Function& aFunction,
+                          const Sequence<JS::Value>& aArguments,
+                          ErrorResult& aError)
+{
+  FallibleTArray<JS::Heap<JS::Value>> args;
+  if (!args.AppendElements(aArguments, fallible)) {
+    aError.Throw(NS_ERROR_OUT_OF_MEMORY);
+    return nullptr;
+  }
+
+  RefPtr<nsJSScriptTimeoutHandler> handler =
+    new nsJSScriptTimeoutHandler(aCx, aWorkerPrivate, aFunction, args);
+  return handler.forget();
+}
+
+already_AddRefed<nsIScriptTimeoutHandler>
+NS_CreateJSTimeoutHandler(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
+                          const nsAString& aExpression)
+{
+  RefPtr<nsJSScriptTimeoutHandler> handler =
+    new nsJSScriptTimeoutHandler(aCx, aWorkerPrivate, aExpression);
+  return handler.forget();
+}
--- a/dom/base/nsRange.cpp
+++ b/dom/base/nsRange.cpp
@@ -2530,16 +2530,21 @@ nsRange::InsertNode(nsINode& aNode, Erro
 
   int32_t tStartOffset = StartOffset();
 
   nsCOMPtr<nsINode> tStartContainer = GetStartContainer(aRv);
   if (aRv.Failed()) {
     return;
   }
 
+  if (&aNode == tStartContainer) {
+    aRv.Throw(NS_ERROR_DOM_HIERARCHY_REQUEST_ERR);
+    return;
+  }
+
   // This is the node we'll be inserting before, and its parent
   nsCOMPtr<nsINode> referenceNode;
   nsCOMPtr<nsINode> referenceParentNode = tStartContainer;
 
   nsCOMPtr<nsIDOMText> startTextNode(do_QueryInterface(tStartContainer));
   nsCOMPtr<nsIDOMNodeList> tChildList;
   if (startTextNode) {
     referenceParentNode = tStartContainer->GetParentNode();
--- a/dom/base/nsScriptLoader.cpp
+++ b/dom/base/nsScriptLoader.cpp
@@ -2331,19 +2331,17 @@ nsScriptLoader::OnStreamComplete(nsIIncr
     MOZ_ASSERT(aSRIDataVerifier);
     if (NS_FAILED(aSRIDataVerifier->Verify(request->mIntegrity, channel,
                                            request->mCORSMode, mDocument))) {
       rv = NS_ERROR_SRI_CORRUPT;
     }
   } else {
     nsCOMPtr<nsILoadInfo> loadInfo = channel->GetLoadInfo();
 
-    bool enforceSRI = false;
-    loadInfo->GetEnforceSRI(&enforceSRI);
-    if (enforceSRI) {
+    if (loadInfo->GetEnforceSRI()) {
       MOZ_LOG(SRILogHelper::GetSriLog(), mozilla::LogLevel::Debug,
              ("nsScriptLoader::OnStreamComplete, required SRI not found"));
       nsCOMPtr<nsIContentSecurityPolicy> csp;
       loadInfo->LoadingPrincipal()->GetCsp(getter_AddRefs(csp));
       nsAutoCString violationURISpec;
       mDocument->GetDocumentURI()->GetAsciiSpec(violationURISpec);
       uint32_t lineNo = request->mElement ? request->mElement->GetScriptLineNumber() : 0;
       csp->LogViolationDetails(
--- a/dom/base/nsTreeSanitizer.cpp
+++ b/dom/base/nsTreeSanitizer.cpp
@@ -7,17 +7,17 @@
 #include "nsTreeSanitizer.h"
 
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/CSSStyleSheet.h"
 #include "mozilla/css/Declaration.h"
 #include "mozilla/css/StyleRule.h"
 #include "mozilla/css/Rule.h"
 #include "nsCSSParser.h"
-#include "nsCSSProperty.h"
+#include "nsCSSPropertyID.h"
 #include "nsUnicharInputStream.h"
 #include "nsIDOMCSSRule.h"
 #include "nsAttrName.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsNetUtil.h"
 #include "nsComponentManagerUtils.h"
 #include "nsNullPrincipal.h"
 #include "nsContentUtils.h"
new file mode 100644
--- /dev/null
+++ b/dom/base/test/file_blobURL_expiring.html
@@ -0,0 +1,4 @@
+<script>
+var blob = new Blob([123]);
+parent.postMessage(URL.createObjectURL(blob), "*");
+</script>
new file mode 100644
--- /dev/null
+++ b/dom/base/test/file_bug1268962.sjs
@@ -0,0 +1,90 @@
+// Test server for bug 1268962
+'use strict';
+Components.utils.importGlobalProperties(["URLSearchParams"]);
+const HTTPStatus = new Map([
+  [100, 'Continue'],
+  [101, 'Switching Protocol'],
+  [200, 'OK'],
+  [201, 'Created'],
+  [202, 'Accepted'],
+  [203, 'Non-Authoritative Information'],
+  [204, 'No Content'],
+  [205, 'Reset Content'],
+  [206, 'Partial Content'],
+  [300, 'Multiple Choice'],
+  [301, 'Moved Permanently'],
+  [302, 'Found'],
+  [303, 'See Other'],
+  [304, 'Not Modified'],
+  [305, 'Use Proxy'],
+  [306, 'unused'],
+  [307, 'Temporary Redirect'],
+  [308, 'Permanent Redirect'],
+  [400, 'Bad Request'],
+  [401, 'Unauthorized'],
+  [402, 'Payment Required'],
+  [403, 'Forbidden'],
+  [404, 'Not Found'],
+  [405, 'Method Not Allowed'],
+  [406, 'Not Acceptable'],
+  [407, 'Proxy Authentication Required'],
+  [408, 'Request Timeout'],
+  [409, 'Conflict'],
+  [410, 'Gone'],
+  [411, 'Length Required'],
+  [412, 'Precondition Failed'],
+  [413, 'Request Entity Too Large'],
+  [414, 'Request-URI Too Long'],
+  [415, 'Unsupported Media Type'],
+  [416, 'Requested Range Not Satisfiable'],
+  [417, 'Expectation Failed'],
+  [500, 'Internal Server Error'],
+  [501, 'Not Implemented'],
+  [502, 'Bad Gateway'],
+  [503, 'Service Unavailable'],
+  [504, 'Gateway Timeout'],
+  [505, 'HTTP Version Not Supported']
+]);
+
+const SAME_ORIGIN = 'http://mochi.test:8888/tests/dom/base/test/file_bug1268962.sjs';
+const CROSS_ORIGIN = 'http://example.com/tests/dom/base/test/file_bug1268962.sjs';
+
+function handleRequest(request, response) {
+  const queryMap = new URLSearchParams(request.queryString);
+
+  // Check redirection before everything else.
+  if (queryMap.has('redirect')) {
+    let redirect = queryMap.get('redirect');
+    let location;
+    if (redirect == 'sameorigin') {
+      location = SAME_ORIGIN;
+    } else if (redirect == 'crossorigin') {
+      location = CROSS_ORIGIN;
+    }
+
+    if (location) {
+      // Use HTTP 302 redirection.
+      response.setStatusLine('1.1', 302, HTTPStatus.get(302));
+
+      // Forward query strings except the redirect option.
+      queryMap.delete('redirect');
+      response.setHeader('Location', location + '?' + queryMap.toString());
+
+      return;
+    }
+  }
+
+  if (queryMap.has('statusCode')) {
+    let statusCode = parseInt(queryMap.get('statusCode'));
+    let statusText = HTTPStatus.get(statusCode);
+    response.setStatusLine('1.1', statusCode, statusText);
+  }
+  if (queryMap.has('cacheControl')) {
+    let cacheControl = queryMap.get('cacheControl');
+    response.setHeader('Cache-Control', cacheControl);
+  }
+  if (queryMap.has('allowOrigin')) {
+    let allowOrigin = queryMap.get('allowOrigin');
+    response.setHeader('Access-Control-Allow-Origin', allowOrigin);
+  }
+}
--- a/dom/base/test/mochitest.ini
+++ b/dom/base/test/mochitest.ini
@@ -221,24 +221,26 @@ support-files =
   script_postmessages_fileList.js
   iframe_postMessages.html
   test_anonymousContent_style_csp.html^headers^
   file_explicit_user_agent.sjs
   referrer_change_server.sjs
   file_change_policy_redirect.html
   file_bug1198095.js
   file_bug1250148.sjs
+  file_bug1268962.sjs
   mozbrowser_api_utils.js
   websocket_helpers.js
   websocket_tests.js
   !/dom/html/test/form_submit_server.sjs
   !/dom/security/test/cors/file_CrossSiteXHR_server.sjs
   !/image/test/mochitest/blue.png
   !/dom/xhr/tests/file_XHRSendData.sjs
   script_bug1238440.js
+  file_blobURL_expiring.html
 
 [test_anchor_area_referrer.html]
 [test_anchor_area_referrer_changing.html]
 [test_anchor_area_referrer_invalid.html]
 [test_anchor_area_referrer_rel.html]
 [test_anonymousContent_api.html]
 [test_anonymousContent_append_after_reflow.html]
 [test_anonymousContent_canvas.html]
@@ -264,16 +266,17 @@ skip-if = buildapp == 'mulet'
 tags = audiochannel
 skip-if = buildapp == 'mulet'
 [test_audioNotificationWithEarlyPlay.html]
 tags = audiochannel
 skip-if = buildapp == 'mulet'
 [test_base.xhtml]
 [test_blob_fragment_and_query.html]
 [test_blobconstructor.html]
+[test_blobURL_expiring.html]
 [test_bug5141.html]
 [test_bug28293.html]
 [test_bug28293.xhtml]
 [test_bug51034.html]
 [test_bug116083.html]
 subsuite = clipboard
 [test_bug166235.html]
 subsuite = clipboard
@@ -622,16 +625,17 @@ skip-if = buildapp == 'b2g'
 [test_bug1163743.html]
 [test_bug1165501.html]
 [test_bug1187157.html]
 [test_bug1198095.html]
 [test_bug1238440.html]
 [test_bug1250148.html]
 [test_bug1259588.html]
 [test_bug1263696.html]
+[test_bug1268962.html]
 [test_bug1274806.html]
 [test_bug1281963.html]
 [test_caretPositionFromPoint.html]
 [test_change_policy.html]
 skip-if = buildapp == 'b2g' #no ssl support
 [test_classList.html]
 [test_clearTimeoutIntervalNoArg.html]
 [test_constructor-assignment.html]
@@ -775,16 +779,17 @@ skip-if = toolkit == 'android'
 [test_referrer_redirect.html]
 [test_root_iframe.html]
 [test_screen_orientation.html]
 [test_script_loader_crossorigin_data_url.html]
 [test_setInterval_uncatchable_exception.html]
 skip-if = debug == false
 [test_settimeout_extra_arguments.html]
 [test_settimeout_inner.html]
+[test_setTimeoutWith0.html]
 [test_setting_opener.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
 [test_simplecontentpolicy.html]
 skip-if = e10s || buildapp == 'b2g' # Bug 1156489.
 [test_text_wholeText.html]
 [test_textnode_normalize_in_selection.html]
 [test_textnode_split_in_selection.html]
 [test_title.html]
new file mode 100644
--- /dev/null
+++ b/dom/base/test/test_blobURL_expiring.html
@@ -0,0 +1,47 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>Test for Blob URI expiration</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+  <script>
+
+onmessage = function(e) {
+  var blobURL = e.data;
+
+  (new Promise(function(resolve, reject) {
+    var xhr = new XMLHttpRequest();
+    xhr.open("GET", blobURL);
+    xhr.send();
+    xhr.onload = function() {
+      is(xhr.response, "123", "Response matches!");
+      resolve();
+    }
+  })).then(function() {
+    document.body.removeChild(iframe);
+  }).then(function() {
+    var xhr = new XMLHttpRequest();
+
+    try {
+      xhr.open("GET", blobURL);
+      ok(false, "The URL should be done!");
+    } catch(e) {
+      ok(true, "The URL should be done!");
+    }
+
+    SimpleTest.finish();
+  });
+}
+
+var iframe = document.createElement('iframe');
+iframe.src = 'file_blobURL_expiring.html';
+document.body.appendChild(iframe);
+
+SimpleTest.waitForExplicitFinish();
+
+  </script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/base/test/test_bug1268962.html
@@ -0,0 +1,105 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1268962
+-->
+<head>
+  <title>Test for Bug 1268962</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1268962">Mozilla Bug 1268962</a>
+<p id="display"></p>
+<div id="content" style="display: none"></div>
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 1268962 **/
+
+function testPrefetchEvent(url, crossorigin, expectLoad) {
+  return new Promise((resolve) => {
+    var link = document.createElement("LINK");
+    link.setAttribute("rel", "prefetch");
+    link.setAttribute("href", url);
+    if (crossorigin) {
+      link.setAttribute("crossorigin", "");
+    }
+
+    link.addEventListener("load", () => {
+      ok(expectLoad, "not expecting load event for " + url);
+      link.remove();
+      resolve();
+    });
+    link.addEventListener("error", () => {
+      ok(!expectLoad, "not expecting error event for " + url);
+      link.remove();
+      resolve();
+    });
+    document.head.appendChild(link);
+  });
+}
+
+function testCancelPrefetchNotCrash(url) {
+  var ios = SpecialPowers.Cc["@mozilla.org/network/io-service;1"].
+            getService(SpecialPowers.Ci.nsIIOService);
+  var prefetch = SpecialPowers.Cc["@mozilla.org/prefetch-service;1"].
+                   getService(SpecialPowers.Ci.nsIPrefetchService);
+
+  var link = document.createElement("LINK");
+  link.setAttribute("rel", "prefetch");
+  link.setAttribute("href", url);
+  document.head.appendChild(link);
+
+  // Not actually verifying any value, just to ensure cancelPrefetch
+  // won't cause crash.
+  prefetch.cancelPrefetchURI(ios.newURI(url, null, null), link);
+}
+
+const SJS_PATH = window.location.pathname.replace(/[^/]+$/, "file_bug1268962.sjs");
+const SAME_ORIGIN = "http://mochi.test:8888" + SJS_PATH;
+const CROSS_ORIGIN = "http://example.com" + SJS_PATH;
+
+SimpleTest.waitForExplicitFinish();
+
+new Promise(resolve =>
+  SpecialPowers.pushPrefEnv({"set": [["network.prefetch-next.aggressive", true]]}, resolve))
+
+// test same origin
+.then(() => testPrefetchEvent(SAME_ORIGIN + "?statusCode=200&cacheControl=no-cache", false, false))
+.then(() => testPrefetchEvent(SAME_ORIGIN + "?statusCode=404&cacheControl=no-cache", false, false))
+.then(() => testPrefetchEvent(SAME_ORIGIN + "?statusCode=200&cacheControl=max-age%3D120", false, true))
+.then(() => testPrefetchEvent(SAME_ORIGIN + "?statusCode=404&cacheControl=max-age%3D120", false, false))
+
+// test cross origin without CORS
+.then(() => testPrefetchEvent(CROSS_ORIGIN + "?statusCode=200&cacheControl=no-cache", false, true))
+.then(() => testPrefetchEvent(CROSS_ORIGIN + "?statusCode=404&cacheControl=no-cache", false, true))
+.then(() => testPrefetchEvent(CROSS_ORIGIN + "?statusCode=200&cacheControl=max-age%3D120", false, true))
+.then(() => testPrefetchEvent(CROSS_ORIGIN + "?statusCode=404&cacheControl=max-age%3D120", false, true))
+
+// test cross origin by redirection without CORS
+.then(() => testPrefetchEvent(SAME_ORIGIN + "?redirect=crossorigin&statusCode=200&cacheControl=no-cache", false, true))
+.then(() => testPrefetchEvent(SAME_ORIGIN + "?redirect=crossorigin&statusCode=404&cacheControl=no-cache", false, true))
+.then(() => testPrefetchEvent(SAME_ORIGIN + "?redirect=crossorigin&statusCode=200&cacheControl=max-age%3D120", false, true))
+.then(() => testPrefetchEvent(SAME_ORIGIN + "?redirect=crossorigin&statusCode=404&cacheControl=max-age%3D120", false, true))
+
+// test cross origin with CORS request but no CORS response
+.then(() => testPrefetchEvent(CROSS_ORIGIN + "?statusCode=200&cacheControl=no-cache", true, true))
+.then(() => testPrefetchEvent(CROSS_ORIGIN + "?statusCode=404&cacheControl=no-cache", true, true))
+.then(() => testPrefetchEvent(CROSS_ORIGIN + "?statusCode=200&cacheControl=max-age%3D120", true, true))
+.then(() => testPrefetchEvent(CROSS_ORIGIN + "?statusCode=404&cacheControl=max-age%3D120", true, true))
+
+// test cross origin with CORS request and CORS response
+.then(() => testPrefetchEvent(CROSS_ORIGIN + "?statusCode=200&cacheControl=no-cache&allowOrigin=*", true, false))
+.then(() => testPrefetchEvent(CROSS_ORIGIN + "?statusCode=404&cacheControl=no-cache&allowOrigin=*", true, false))
+.then(() => testPrefetchEvent(CROSS_ORIGIN + "?statusCode=200&cacheControl=max-age%3D120&allowOrigin=*", true, true))
+.then(() => testPrefetchEvent(CROSS_ORIGIN + "?statusCode=404&cacheControl=max-age%3D120&allowOrigin=*", true, false))
+
+// test the crash issue: https://bugzilla.mozilla.org/show_bug.cgi?id=1294159
+.then(() => testCancelPrefetchNotCrash(SAME_ORIGIN + "?statusCode=200&cacheControl=max-age%3D120"))
+
+.catch((err) => ok(false, "promise rejected: " + err))
+.then(() => SimpleTest.finish());
+
+</script>
+</body>
+</html>
--- a/dom/base/test/test_link_prefetch.html
+++ b/dom/base/test/test_link_prefetch.html
@@ -155,22 +155,11 @@
          RESULT: 'full'},
       ]},
   ];
 
   </script>
   <script type="application/javascript;version=1.7" src="/tests/dom/base/test/referrer_helper.js"></script>
 </head>
 <body onload="tests.next();">
-  <script type="application/javascript;version=1.7">
-    /**
-     * Listen for notifications that pretching finishes.
-     * XXX Bug 1268962 - Fire load/error events on <link rel="prefetch">
-     * Because there's no onload/onerror event fired, we catch prefetch-load-completed
-     * to test
-     * Simply remove this after bug 1268962 is fixed
-     */
-    netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-    SpecialPowers.Services.obs.addObserver(function() { tests.next(); }, "prefetch-load-completed", false);
-  </script>
   <iframe id="testframe"></iframe>
 </body>
 </html>
new file mode 100644
--- /dev/null
+++ b/dom/base/test/test_setTimeoutWith0.html
@@ -0,0 +1,22 @@
+<html>
+<head>
+  <title>Test for setTimeout and strings containing 0</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<script>
+
+var x = 0;
+setTimeout("x++; '\x00'; x++;");
+setTimeout(function() {
+  is(x, 2, "We want to see 2 here");
+  SimpleTest.finish();
+});
+
+SimpleTest.waitForExplicitFinish();
+</script>
+</body>
+</html>
+
+
--- a/dom/battery/BatteryManager.cpp
+++ b/dom/battery/BatteryManager.cpp
@@ -132,17 +132,17 @@ void
 BatteryManager::UpdateFromBatteryInfo(const hal::BatteryInformation& aBatteryInfo)
 {
   mLevel = aBatteryInfo.level();
 
   // Round to the nearest ten percent for non-chrome and non-certified apps
   nsIDocument* doc = GetOwner() ? GetOwner()->GetDoc() : nullptr;
   uint16_t status = nsIPrincipal::APP_STATUS_NOT_INSTALLED;
   if (doc) {
-    doc->NodePrincipal()->GetAppStatus(&status);
+    status = doc->NodePrincipal()->GetAppStatus();
   }
 
   mCharging = aBatteryInfo.charging();
   mRemainingTime = aBatteryInfo.remainingTime();
 
   if (!nsContentUtils::IsChromeDoc(doc) &&
       status != nsIPrincipal::APP_STATUS_CERTIFIED)
   {
--- a/dom/broadcastchannel/BroadcastChannel.cpp
+++ b/dom/broadcastchannel/BroadcastChannel.cpp
@@ -87,23 +87,17 @@ public:
     MOZ_ASSERT(NS_IsMainThread());
 
     nsIPrincipal* principal = GetPrincipalFromWorkerPrivate(mWorkerPrivate);
     if (!principal) {
       mRv.Throw(NS_ERROR_FAILURE);
       return true;
     }
 
-    bool isNullPrincipal;
-    mRv = principal->GetIsNullPrincipal(&isNullPrincipal);
-    if (NS_WARN_IF(mRv.Failed())) {
-      return true;
-    }
-
-    if (NS_WARN_IF(isNullPrincipal)) {
+    if (NS_WARN_IF(principal->GetIsNullPrincipal())) {
       mRv.Throw(NS_ERROR_FAILURE);
       return true;
     }
 
     mRv = PrincipalToPrincipalInfo(principal, &mPrincipalInfo);
     if (NS_WARN_IF(mRv.Failed())) {
       return true;
     }
@@ -345,23 +339,17 @@ BroadcastChannel::Constructor(const Glob
     }
 
     nsIPrincipal* principal = incumbent->PrincipalOrNull();
     if (!principal) {
       aRv.Throw(NS_ERROR_UNEXPECTED);
       return nullptr;
     }
 
-    bool isNullPrincipal;
-    aRv = principal->GetIsNullPrincipal(&isNullPrincipal);
-    if (NS_WARN_IF(aRv.Failed())) {
-      return nullptr;
-    }
-
-    if (NS_WARN_IF(isNullPrincipal)) {
+    if (NS_WARN_IF(principal->GetIsNullPrincipal())) {
       aRv.Throw(NS_ERROR_FAILURE);
       return nullptr;
     }
 
     aRv = principal->GetOrigin(origin);
     if (NS_WARN_IF(aRv.Failed())) {
       return nullptr;
     }
--- a/dom/camera/DOMCameraManager.cpp
+++ b/dom/camera/DOMCameraManager.cpp
@@ -302,23 +302,22 @@ nsDOMCameraManager::GetCamera(const nsAS
   if (!sop) {
     aRv.Throw(NS_ERROR_UNEXPECTED);
     return nullptr;
   }
 
   nsCOMPtr<nsIPrincipal> principal = sop->GetPrincipal();
   // If we are a CERTIFIED app, we can short-circuit the permission check,
   // which gets us a performance win.
-  uint16_t status = nsIPrincipal::APP_STATUS_NOT_INSTALLED;
-  principal->GetAppStatus(&status);
   // Unprivileged mochitests always fail the dispatched permission check,
   // even if permission to the camera has been granted.
   bool immediateCheck = false;
   CameraPreferences::GetPref("camera.control.test.permission", immediateCheck);
-  if ((status == nsIPrincipal::APP_STATUS_CERTIFIED || immediateCheck) && CheckPermission(mWindow)) {
+  if ((principal->GetAppStatus() == nsIPrincipal::APP_STATUS_CERTIFIED || immediateCheck) &&
+      CheckPermission(mWindow)) {
     PermissionAllowed(cameraId, aInitialConfig, promise);
     return promise.forget();
   }
 
   nsCOMPtr<nsIRunnable> permissionRequest =
     new CameraPermissionRequest(principal, mWindow, this, cameraId,
                                 aInitialConfig, promise);
 
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -1875,31 +1875,43 @@ CanvasRenderingContext2D::SetContextOpti
   }
 
   return NS_OK;
 }
 
 UniquePtr<uint8_t[]>
 CanvasRenderingContext2D::GetImageBuffer(int32_t* aFormat)
 {
+  UniquePtr<uint8_t[]> ret;
+
   *aFormat = 0;
 
-  EnsureTarget();
-  RefPtr<SourceSurface> snapshot = mTarget->Snapshot();
-  if (!snapshot) {
-    return nullptr;
-  }
-
-  RefPtr<DataSourceSurface> data = snapshot->GetDataSurface();
-  if (!data || data->GetSize() != IntSize(mWidth, mHeight)) {
-    return nullptr;
-  }
-
-  *aFormat = imgIEncoder::INPUT_FORMAT_HOSTARGB;
-  return SurfaceToPackedBGRA(data);
+  RefPtr<SourceSurface> snapshot;
+  if (mTarget) {
+    snapshot = mTarget->Snapshot();
+  } else if (mBufferProvider) {
+    snapshot = mBufferProvider->BorrowSnapshot();
+  } else {
+    EnsureTarget();
+    snapshot = mTarget->Snapshot();
+  }
+
+  if (snapshot) {
+    RefPtr<DataSourceSurface> data = snapshot->GetDataSurface();
+    if (data && data->GetSize() == IntSize(mWidth, mHeight)) {
+      *aFormat = imgIEncoder::INPUT_FORMAT_HOSTARGB;
+      ret = SurfaceToPackedBGRA(data);
+    }
+  }
+
+  if (!mTarget && mBufferProvider) {
+    mBufferProvider->ReturnSnapshot(snapshot.forget());
+  }
+
+  return ret;
 }
 
 nsString CanvasRenderingContext2D::GetHitRegion(const mozilla::gfx::Point& aPoint)
 {
   for (size_t x = 0 ; x < mHitRegionsOptions.Length(); x++) {
     RegionInfo& info = mHitRegionsOptions[x];
     if (info.mPath->ContainsPoint(aPoint, Matrix())) {
       return info.mId;
@@ -2386,18 +2398,18 @@ CanvasRenderingContext2D::SetShadowColor
 }
 
 //
 // filters
 //
 
 static already_AddRefed<Declaration>
 CreateDeclaration(nsINode* aNode,
-  const nsCSSProperty aProp1, const nsAString& aValue1, bool* aChanged1,
-  const nsCSSProperty aProp2, const nsAString& aValue2, bool* aChanged2)
+  const nsCSSPropertyID aProp1, const nsAString& aValue1, bool* aChanged1,
+  const nsCSSPropertyID aProp2, const nsAString& aValue2, bool* aChanged2)
 {
   nsIPrincipal* principal = aNode->NodePrincipal();
   nsIDocument* document = aNode->OwnerDoc();
 
   nsIURI* docURL = document->GetDocumentURI();
   nsIURI* baseURL = document->GetDocBaseURI();
 
   // Pass the CSS Loader object to the parser, to allow parser error reports
@@ -2472,17 +2484,17 @@ GetFontParentStyleContext(Element* aElem
   if (!result) {
     aError.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
   return result.forget();
 }
 
 static bool
-PropertyIsInheritOrInitial(Declaration* aDeclaration, const nsCSSProperty aProperty)
+PropertyIsInheritOrInitial(Declaration* aDeclaration, const nsCSSPropertyID aProperty)
 {
   // We know the declaration is not !important, so we can use
   // GetNormalBlock().
   const nsCSSValue* filterVal =
     aDeclaration->GetNormalBlock()->ValueFor(aProperty);
   return (!filterVal || (filterVal->GetUnit() == eCSSUnit_Unset ||
                          filterVal->GetUnit() == eCSSUnit_Inherit ||
                          filterVal->GetUnit() == eCSSUnit_Initial));
@@ -5112,20 +5124,22 @@ CanvasRenderingContext2D::DrawWindow(nsG
     }
 
     thebes = gfxContext::CreateOrNull(drawDT);
     MOZ_ASSERT(thebes); // alrady checked the draw target above
     thebes->SetMatrix(gfxMatrix::Scaling(matrix._11, matrix._22));
   }
 
   nsCOMPtr<nsIPresShell> shell = presContext->PresShell();
+
   Unused << shell->RenderDocument(r, renderDocFlags, backgroundColor, thebes);
   // If this canvas was contained in the drawn window, the pre-transaction callback
   // may have returned its DT. If so, we must reacquire it here.
   EnsureTarget();
+
   if (drawDT) {
     RefPtr<SourceSurface> snapshot = drawDT->Snapshot();
     if (NS_WARN_IF(!snapshot)) {
       aError.Throw(NS_ERROR_FAILURE);
       return;
     }
     RefPtr<DataSourceSurface> data = snapshot->GetDataSurface();
 
@@ -5631,17 +5645,16 @@ CanvasRenderingContext2D::PutImageData_e
       *dst++ = gfxUtils::sPremultiplyTable[a * 256 + r];
       *dst++ = gfxUtils::sPremultiplyTable[a * 256 + g];
       *dst++ = gfxUtils::sPremultiplyTable[a * 256 + b];
 #endif
     }
     srcLine += aW * 4;
   }
 
-  EnsureTarget();
   if (!IsTargetValid()) {
     return NS_ERROR_FAILURE;
   }
 
   RefPtr<SourceSurface> sourceSurface =
     mTarget->CreateSourceSurfaceFromData(imgsurf->Data(), IntSize(copyWidth, copyHeight), imgsurf->Stride(), SurfaceFormat::B8G8R8A8);
 
   // In certain scenarios, requesting larger than 8k image fails.  Bug 803568
--- a/dom/canvas/WebGL2Context.h
+++ b/dom/canvas/WebGL2Context.h
@@ -47,25 +47,22 @@ public:
                            GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size);
 
 private:
     template<typename BufferT>
     void GetBufferSubDataT(GLenum target, GLintptr offset, const BufferT& data);
 
 public:
     void GetBufferSubData(GLenum target, GLintptr offset,
-                          const dom::Nullable<dom::ArrayBuffer>& maybeData);
-    void GetBufferSubData(GLenum target, GLintptr offset,
-                          const dom::SharedArrayBuffer& data);
+                          const dom::ArrayBufferView& dstData);
     void ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format,
                     GLenum type, WebGLsizeiptr offset, ErrorResult& out_error);
 
-    void ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height,
-                    GLenum format, GLenum type,
-                    const dom::Nullable<dom::ArrayBufferView>& pixels,
+    void ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format,
+                    GLenum type, const dom::ArrayBufferView& pixels,
                     ErrorResult& out_error)
     {
         WebGLContext::ReadPixels(x, y, width, height, format, type, pixels, out_error);
     }
 
     // -------------------------------------------------------------------------
     // Framebuffer objects - WebGL2ContextFramebuffers.cpp
 
@@ -97,49 +94,38 @@ public:
 
     // -------------------------------------------------------------------------
     // Texture objects - WebGL2ContextTextures.cpp
 
     void TexStorage2D(GLenum target, GLsizei levels, GLenum internalFormat, GLsizei width,
                       GLsizei height);
     void TexStorage3D(GLenum target, GLsizei levels, GLenum internalFormat, GLsizei width,
                       GLsizei height, GLsizei depth);
+
     void TexImage3D(GLenum target, GLint level, GLenum internalFormat, GLsizei width,
                     GLsizei height, GLsizei depth, GLint border, GLenum unpackFormat,
-                    GLenum unpackType,
-                    const dom::Nullable<dom::ArrayBufferView>& pixels);
+                    GLenum unpackType, const dom::Nullable<dom::ArrayBufferView>& data);
+
     void TexSubImage3D(GLenum target, GLint level, GLint xOffset, GLint yOffset,
                        GLint zOffset, GLsizei width, GLsizei height, GLsizei depth,
                        GLenum unpackFormat, GLenum unpackType,
-                       const dom::Nullable<dom::ArrayBufferView>& pixels,
-                       ErrorResult& out_rv);
-    void TexSubImage3D(GLenum target, GLint level, GLint xOffset, GLint yOffset,
-                       GLint zOffset, GLenum unpackFormat, GLenum unpackType,
-                       dom::ImageData* data, ErrorResult& out_rv);
-protected:
+                       const dom::ArrayBufferView& data, ErrorResult&);
     void TexSubImage3D(GLenum target, GLint level, GLint xOffset, GLint yOffset,
                        GLint zOffset, GLenum unpackFormat, GLenum unpackType,
-                       dom::Element* elem, ErrorResult* const out_rv);
-public:
-    template<class T>
-    inline void
-    TexSubImage3D(GLenum target, GLint level, GLint xOffset, GLint yOffset, GLint zOffset,
-                  GLenum unpackFormat, GLenum unpackType, T& any, ErrorResult& out_rv)
-    {
-        TexSubImage3D(target, level, xOffset, yOffset, zOffset, unpackFormat, unpackType,
-                      &any, &out_rv);
-    }
+                       const dom::ImageData& data, ErrorResult&);
+    void TexSubImage3D(GLenum target, GLint level, GLint xOffset, GLint yOffset,
+                       GLint zOffset, GLenum unpackFormat, GLenum unpackType,
+                       const dom::Element& elem, ErrorResult& out_error);
 
     void CopyTexSubImage3D(GLenum target, GLint level, GLint xOffset, GLint yOffset,
                            GLint zOffset, GLint x, GLint y, GLsizei width,
                            GLsizei height);
     void CompressedTexImage3D(GLenum target, GLint level, GLenum internalFormat,
                               GLsizei width, GLsizei height, GLsizei depth,
-                              GLint border,
-                              const dom::ArrayBufferView& data);
+                              GLint border, const dom::ArrayBufferView& data);
     void CompressedTexSubImage3D(GLenum target, GLint level, GLint xOffset, GLint yOffset,
                                  GLint zOffset, GLsizei width, GLsizei height,
                                  GLsizei depth, GLenum sizedUnpackFormat,
                                  const dom::ArrayBufferView& data);
 
     ////////////////
     // Texture PBOs
 
@@ -170,35 +156,36 @@ public:
     {
         WebGLContext::TexImage2D(texImageTarget, level, internalFormat, width, height,
                                  border, unpackFormat, unpackType, pixels, out_rv);
     }
 
     template<typename T>
     void
     TexImage2D(GLenum texImageTarget, GLint level, GLenum internalFormat,
-               GLenum unpackFormat, GLenum unpackType, T& any, ErrorResult& out_rv)
+               GLenum unpackFormat, GLenum unpackType, const T& any, ErrorResult& out_rv)
     {
         WebGLContext::TexImage2D(texImageTarget, level, internalFormat, unpackFormat,
                                  unpackType, any, out_rv);
     }
 
     void
     TexSubImage2D(GLenum texImageTarget, GLint level, GLint xOffset, GLint yOffset,
                   GLsizei width, GLsizei height, GLenum unpackFormat, GLenum unpackType,
-                  const dom::Nullable<dom::ArrayBufferView>& pixels, ErrorResult& out_rv)
+                  const dom::ArrayBufferView& view, ErrorResult&)
     {
         WebGLContext::TexSubImage2D(texImageTarget, level, xOffset, yOffset, width,
-                                    height, unpackFormat, unpackType, pixels, out_rv);
+                                    height, unpackFormat, unpackType, view);
     }
 
     template<typename T>
     inline void
     TexSubImage2D(GLenum texImageTarget, GLint level, GLint xOffset, GLint yOffset,
-                  GLenum unpackFormat, GLenum unpackType, T& any, ErrorResult& out_rv)
+                  GLenum unpackFormat, GLenum unpackType, const T& any,
+                  ErrorResult& out_rv)
     {
         WebGLContext::TexSubImage2D(texImageTarget, level, xOffset, yOffset, unpackFormat,
                                     unpackType, any, out_rv);
     }
 
     // -------------------------------------------------------------------------
     // Programs and shaders - WebGL2ContextPrograms.cpp
     GLint GetFragDataLocation(WebGLProgram* program, const nsAString& name);
--- a/dom/canvas/WebGL2ContextBuffers.cpp
+++ b/dom/canvas/WebGL2ContextBuffers.cpp
@@ -135,22 +135,19 @@ WebGL2Context::CopyBufferSubData(GLenum 
 
     if (writeType == WebGLBuffer::Kind::Undefined) {
         writeBuffer->BindTo(
             (readType == WebGLBuffer::Kind::OtherData) ? LOCAL_GL_ARRAY_BUFFER
                                                        : LOCAL_GL_ELEMENT_ARRAY_BUFFER);
     }
 }
 
-// BufferT may be one of
-// const dom::ArrayBuffer&
-// const dom::SharedArrayBuffer&
-template<typename BufferT>
 void
-WebGL2Context::GetBufferSubDataT(GLenum target, GLintptr offset, const BufferT& data)
+WebGL2Context::GetBufferSubData(GLenum target, GLintptr offset,
+                                const dom::ArrayBufferView& data)
 {
     const char funcName[] = "getBufferSubData";
     if (IsContextLost())
         return;
 
     // For the WebGLBuffer bound to the passed target, read
     // returnedData.byteLength bytes from the buffer starting at byte
     // offset offset and write them to returnedData.
@@ -230,31 +227,9 @@ WebGL2Context::GetBufferSubDataT(GLenum 
 
     ////
 
     if (target == LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER && currentTF) {
         BindTransformFeedback(LOCAL_GL_TRANSFORM_FEEDBACK, currentTF);
     }
 }
 
-void
-WebGL2Context::GetBufferSubData(GLenum target, GLintptr offset,
-                                const dom::Nullable<dom::ArrayBuffer>& maybeData)
-{
-    // If returnedData is null then an INVALID_VALUE error is
-    // generated.
-    if (maybeData.IsNull()) {
-        ErrorInvalidValue("getBufferSubData: returnedData is null");
-        return;
-    }
-
-    const dom::ArrayBuffer& data = maybeData.Value();
-    GetBufferSubDataT(target, offset, data);
-}
-
-void
-WebGL2Context::GetBufferSubData(GLenum target, GLintptr offset,
-                                const dom::SharedArrayBuffer& data)
-{
-    GetBufferSubDataT(target, offset, data);
-}
-
 } // namespace mozilla
--- a/dom/canvas/WebGL2ContextTextures.cpp
+++ b/dom/canvas/WebGL2ContextTextures.cpp
@@ -53,31 +53,35 @@ WebGL2Context::TexImage3D(GLenum rawTexI
     TexImageTarget target;
     WebGLTexture* tex;
     if (!ValidateTexImageTarget(this, funcName, funcDims, rawTexImageTarget, &target,
                                 &tex))
     {
         return;
     }
 
+    const dom::ArrayBufferView* view = nullptr;
+    if (!maybeView.IsNull()) {
+        view = &maybeView.Value();
+    }
+
     const bool isSubImage = false;
     const GLint xOffset = 0;
     const GLint yOffset = 0;
     const GLint zOffset = 0;
     tex->TexOrSubImage(isSubImage, funcName, target, level, internalFormat, xOffset,
                        yOffset, zOffset, width, height, depth, border, unpackFormat,
-                       unpackType, maybeView);
+                       unpackType, view);
 }
 
 void
 WebGL2Context::TexSubImage3D(GLenum rawTexImageTarget, GLint level, GLint xOffset,
                              GLint yOffset, GLint zOffset, GLsizei width, GLsizei height,
                              GLsizei depth, GLenum unpackFormat, GLenum unpackType,
-                             const dom::Nullable<dom::ArrayBufferView>& maybeView,
-                             ErrorResult& /*out_rv*/)
+                             const dom::ArrayBufferView& view, ErrorResult&)
 {
     const char funcName[] = "texSubImage3D";
     const uint8_t funcDims = 3;
 
     TexImageTarget target;
     WebGLTexture* tex;
     if (!ValidateTexImageTarget(this, funcName, funcDims, rawTexImageTarget, &target,
                                 &tex))
@@ -85,24 +89,24 @@ WebGL2Context::TexSubImage3D(GLenum rawT
         return;
     }
 
     const bool isSubImage = true;
     const GLenum internalFormat = 0;
     const GLint border = 0;
     tex->TexOrSubImage(isSubImage, funcName, target, level, internalFormat, xOffset,
                        yOffset, zOffset, width, height, depth, border, unpackFormat,
-                       unpackType, maybeView);
+                       unpackType, &view);
 }
 
 void
 WebGL2Context::TexSubImage3D(GLenum rawTexImageTarget, GLint level, GLint xOffset,
                              GLint yOffset, GLint zOffset, GLenum unpackFormat,
-                             GLenum unpackType, dom::ImageData* imageData,
-                             ErrorResult& /*out_rv*/)
+                             GLenum unpackType, const dom::ImageData& imageData,
+                             ErrorResult&)
 {
     const char funcName[] = "texSubImage3D";
     const uint8_t funcDims = 3;
 
     TexImageTarget target;
     WebGLTexture* tex;
     if (!ValidateTexImageTarget(this, funcName, funcDims, rawTexImageTarget, &target,
                                 &tex))
@@ -114,34 +118,34 @@ WebGL2Context::TexSubImage3D(GLenum rawT
     const GLenum internalFormat = 0;
     tex->TexOrSubImage(isSubImage, funcName, target, level, internalFormat, xOffset,
                        yOffset, zOffset, unpackFormat, unpackType, imageData);
 }
 
 void
 WebGL2Context::TexSubImage3D(GLenum rawTexImageTarget, GLint level, GLint xOffset,
                              GLint yOffset, GLint zOffset, GLenum unpackFormat,
-                             GLenum unpackType, dom::Element* elem,
-                             ErrorResult* const out_rv)
+                             GLenum unpackType, const dom::Element& elem,
+                             ErrorResult& out_rv)
 {
     const char funcName[] = "texSubImage3D";
     const uint8_t funcDims = 3;
 
     TexImageTarget target;
     WebGLTexture* tex;
     if (!ValidateTexImageTarget(this, funcName, funcDims, rawTexImageTarget, &target,
                                 &tex))
     {
         return;
     }
 
     const bool isSubImage = true;
     const GLenum internalFormat = 0;
     tex->TexOrSubImage(isSubImage, funcName, target, level, internalFormat, xOffset,
-                       yOffset, zOffset, unpackFormat, unpackType, elem, out_rv);
+                       yOffset, zOffset, unpackFormat, unpackType, elem, &out_rv);
 }
 
 void
 WebGL2Context::CompressedTexImage3D(GLenum rawTexImageTarget, GLint level,
                                     GLenum internalFormat, GLsizei width, GLsizei height,
                                     GLsizei depth, GLint border,
                                     const dom::ArrayBufferView& view)
 {
--- a/dom/canvas/WebGLContext.h
+++ b/dom/canvas/WebGLContext.h
@@ -547,20 +547,30 @@ protected:
     bool ReadPixels_SharedPrecheck(ErrorResult* const out_error);
     void ReadPixelsImpl(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format,
                         GLenum type, void* data, uint32_t dataLen);
     bool DoReadPixelsAndConvert(const webgl::FormatInfo* srcFormat, GLint x, GLint y,
                                 GLsizei width, GLsizei height, GLenum format,
                                 GLenum destType, void* dest, uint32_t dataLen,
                                 uint32_t rowStride);
 public:
-    void ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height,
-                    GLenum format, GLenum type,
-                    const dom::Nullable<dom::ArrayBufferView>& pixels,
-                    ErrorResult& rv);
+    void ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format,
+                    GLenum type, const dom::Nullable<dom::ArrayBufferView>& maybeView,
+                    ErrorResult& rv)
+    {
+        const char funcName[] = "readPixels";
+        if (maybeView.IsNull()) {
+            ErrorInvalidValue("%s: `pixels` must not be null.", funcName);
+            return;
+        }
+        ReadPixels(x, y, width, height, format, type, maybeView.Value(), rv);
+    }
+
+    void ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format,
+                    GLenum type, const dom::ArrayBufferView& pixels, ErrorResult& rv);
     void RenderbufferStorage(GLenum target, GLenum internalFormat,
                              GLsizei width, GLsizei height);
 protected:
     void RenderbufferStorage_base(const char* funcName, GLenum target,
                                   GLsizei samples, GLenum internalformat,
                                   GLsizei width, GLsizei height);
 public:
     void SampleCoverage(GLclampf value, WebGLboolean invert);
@@ -847,58 +857,87 @@ public:
                                  GLenum unpackFormat, const dom::ArrayBufferView& view);
 
     void CopyTexImage2D(GLenum texImageTarget, GLint level, GLenum internalFormat,
                         GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
     void CopyTexSubImage2D(GLenum texImageTarget, GLint level, GLint xOffset,
                            GLint yOffset, GLint x, GLint y, GLsizei width,
                            GLsizei height);
 
+    ////
+
     void TexImage2D(GLenum texImageTarget, GLint level, GLenum internalFormat,
                     GLsizei width, GLsizei height, GLint border, GLenum unpackFormat,
                     GLenum unpackType,
                     const dom::Nullable<dom::ArrayBufferView>& maybeView,
                     ErrorResult&);
+protected:
     void TexImage2D(GLenum texImageTarget, GLint level, GLenum internalFormat,
-                    GLenum unpackFormat, GLenum unpackType, dom::ImageData* imageData,
-                    ErrorResult&);
+                    GLenum unpackFormat, GLenum unpackType,
+                    const dom::ImageData& imageData, ErrorResult& out_error);
+public:
     void TexImage2D(GLenum texImageTarget, GLint level, GLenum internalFormat,
-                    GLenum unpackFormat, GLenum unpackType, dom::Element* elem,
-                    ErrorResult* const out_error);
+                    GLenum unpackFormat, GLenum unpackType, const dom::Element& elem,
+                    ErrorResult& out_error);
+
+    ////
+
+protected:
+    void TexSubImage2D(GLenum texImageTarget, GLint level, GLint xOffset, GLint yOffset,
+                       GLsizei width, GLsizei height, GLenum unpackFormat,
+                       GLenum unpackType, const dom::ArrayBufferView& view);
+    void TexSubImage2D(GLenum texImageTarget, GLint level, GLint xOffset, GLint yOffset,
+                       GLenum unpackFormat, GLenum unpackType,
+                       const dom::ImageData& imageData, ErrorResult& out_error);
+public:
+    void TexSubImage2D(GLenum texImageTarget, GLint level, GLint xOffset, GLint yOffset,
+                       GLenum unpackFormat, GLenum unpackType, const dom::Element& elem,
+                       ErrorResult& out_error);
+
+    ////////////////
+    // Pseudo-nullable WebGL1 entrypoints
+
+    void TexImage2D(GLenum texImageTarget, GLint level, GLenum internalFormat,
+                    GLenum unpackFormat, GLenum unpackType,
+                    const dom::ImageData* imageData, ErrorResult& out_error)
+    {
+        const char funcName[] = "texImage2D";
+        if (!imageData) {
+            ErrorInvalidValue("%s: `data` must not be null.", funcName);
+            return;
+        }
+        TexImage2D(texImageTarget, level, internalFormat, unpackFormat, unpackType,
+                   *imageData, out_error);
+    }
 
     void TexSubImage2D(GLenum texImageTarget, GLint level, GLint xOffset, GLint yOffset,
                        GLsizei width, GLsizei height, GLenum unpackFormat,
                        GLenum unpackType,
-                       const dom::Nullable<dom::ArrayBufferView>& maybeView,
-                       ErrorResult&);
-    void TexSubImage2D(GLenum texImageTarget, GLint level, GLint xOffset, GLint yOffset,
-                       GLenum unpackFormat, GLenum unpackType, dom::ImageData* imageData,
-                       ErrorResult&);
-    void TexSubImage2D(GLenum texImageTarget, GLint level, GLint xOffset, GLint yOffset,
-                       GLenum unpackFormat, GLenum unpackType, dom::Element* elem,
-                       ErrorResult* const out_error);
-
-    // Allow whatever element unpackTypes the bindings are willing to pass
-    // us in Tex(Sub)Image2D
-    template<typename T>
-    inline void
-    TexImage2D(GLenum texImageTarget, GLint level, GLenum internalFormat,
-               GLenum unpackFormat, GLenum unpackType, T& elem, ErrorResult& out_error)
+                       const dom::Nullable<dom::ArrayBufferView>& maybeView, ErrorResult&)
     {
-        TexImage2D(texImageTarget, level, internalFormat, unpackFormat, unpackType, &elem,
-                   &out_error);
+        const char funcName[] = "texSubImage2D";
+        if (maybeView.IsNull()) {
+            ErrorInvalidValue("%s: `data` must not be null.", funcName);
+            return;
+        }
+        TexSubImage2D(texImageTarget, level, xOffset, yOffset, width, height,
+                      unpackFormat, unpackType, maybeView.Value());
     }
 
-    template<typename T>
-    inline void
-    TexSubImage2D(GLenum texImageTarget, GLint level, GLint xOffset, GLint yOffset,
-                  GLenum unpackFormat, GLenum unpackType, T& elem, ErrorResult& out_error)
+    void TexSubImage2D(GLenum texImageTarget, GLint level, GLint xOffset, GLint yOffset,
+                       GLenum unpackFormat, GLenum unpackType,
+                       const dom::ImageData* imageData, ErrorResult& out_error)
     {
+        const char funcName[] = "texSubImage2D";
+        if (!imageData) {
+            ErrorInvalidValue("%s: `data` must not be null.", funcName);
+            return;
+        }
         TexSubImage2D(texImageTarget, level, xOffset, yOffset, unpackFormat, unpackType,
-                      &elem, &out_error);
+                      *imageData, out_error);
     }
 
     //////
     // WebGLTextureUpload.cpp
 public:
     bool ValidateUnpackPixels(const char* funcName, uint32_t fullRows,
                               uint32_t tailPixels, webgl::TexUnpackBlob* blob);
 
--- a/dom/canvas/WebGLContextGL.cpp
+++ b/dom/canvas/WebGLContextGL.cpp
@@ -1498,39 +1498,29 @@ WebGLContext::ValidatePackSize(const cha
 
     *out_rowStride = rowStride.value();
     *out_endOffset = usedBytesPerImage.value();
     return true;
 }
 
 void
 WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format,
-                         GLenum type,
-                         const dom::Nullable<dom::ArrayBufferView>& pixels,
+                         GLenum type, const dom::ArrayBufferView& view,
                          ErrorResult& out_error)
 {
     if (!ReadPixels_SharedPrecheck(&out_error))
         return;
 
     if (mBoundPixelPackBuffer) {
         ErrorInvalidOperation("readPixels: PIXEL_PACK_BUFFER must be null.");
         return;
     }
 
     //////
 
-    if (pixels.IsNull()) {
-        ErrorInvalidValue("readPixels: null destination buffer");
-        return;
-    }
-
-    const auto& view = pixels.Value();
-
-    //////
-
     js::Scalar::Type reqScalarType;
     if (!GetJSScalarFromGLType(type, &reqScalarType)) {
         ErrorInvalidEnum("readPixels: Bad `type`.");
         return;
     }
 
     const js::Scalar::Type dataScalarType = JS_GetArrayBufferViewType(view.Obj());
     if (dataScalarType != reqScalarType) {
--- a/dom/canvas/WebGLContextTextures.cpp
+++ b/dom/canvas/WebGLContextTextures.cpp
@@ -337,30 +337,35 @@ WebGLContext::TexImage2D(GLenum rawTexIm
     TexImageTarget target;
     WebGLTexture* tex;
     if (!ValidateTexImageTarget(this, funcName, funcDims, rawTexImageTarget, &target,
                                 &tex))
     {
         return;
     }
 
+    const dom::ArrayBufferView* view = nullptr;
+    if (!maybeView.IsNull()) {
+        view = &maybeView.Value();
+    }
+
     const bool isSubImage = false;
     const GLint xOffset = 0;
     const GLint yOffset = 0;
     const GLint zOffset = 0;
     const GLsizei depth = 1;
     tex->TexOrSubImage(isSubImage, funcName, target, level, internalFormat, xOffset,
                        yOffset, zOffset, width, height, depth, border, unpackFormat,
-                       unpackType, maybeView);
+                       unpackType, view);
 }
 
 void
 WebGLContext::TexImage2D(GLenum rawTexImageTarget, GLint level, GLenum internalFormat,
                          GLenum unpackFormat, GLenum unpackType,
-                         dom::ImageData* imageData, ErrorResult&)
+                         const dom::ImageData& imageData, ErrorResult&)
 {
     const char funcName[] = "texImage2D";
     const uint8_t funcDims = 2;
 
     TexImageTarget target;
     WebGLTexture* tex;
     if (!ValidateTexImageTarget(this, funcName, funcDims, rawTexImageTarget, &target,
                                 &tex))
@@ -373,18 +378,18 @@ WebGLContext::TexImage2D(GLenum rawTexIm
     const GLint yOffset = 0;
     const GLint zOffset = 0;
     tex->TexOrSubImage(isSubImage, funcName, target, level, internalFormat, xOffset,
                        yOffset, zOffset, unpackFormat, unpackType, imageData);
 }
 
 void
 WebGLContext::TexImage2D(GLenum rawTexImageTarget, GLint level, GLenum internalFormat,
-                         GLenum unpackFormat, GLenum unpackType, dom::Element* elem,
-                         ErrorResult* const out_error)
+                         GLenum unpackFormat, GLenum unpackType, const dom::Element& elem,
+                         ErrorResult& out_error)
 {
     const char funcName[] = "texImage2D";
     const uint8_t funcDims = 2;
 
     TexImageTarget target;
     WebGLTexture* tex;
     if (!ValidateTexImageTarget(this, funcName, funcDims, rawTexImageTarget, &target,
                                 &tex))
@@ -392,28 +397,27 @@ WebGLContext::TexImage2D(GLenum rawTexIm
         return;
     }
 
     const bool isSubImage = false;
     const GLint xOffset = 0;
     const GLint yOffset = 0;
     const GLint zOffset = 0;
     tex->TexOrSubImage(isSubImage, funcName, target, level, internalFormat, xOffset,
-                       yOffset, zOffset, unpackFormat, unpackType, elem, out_error);
+                       yOffset, zOffset, unpackFormat, unpackType, elem, &out_error);
 }
 
 ////////////////////////////////////////
 // TexSubImage
 
 void
 WebGLContext::TexSubImage2D(GLenum rawTexImageTarget, GLint level, GLint xOffset,
                             GLint yOffset, GLsizei width, GLsizei height,
                             GLenum unpackFormat, GLenum unpackType,
-                            const dom::Nullable<dom::ArrayBufferView>& maybeView,
-                            ErrorResult&)
+                            const dom::ArrayBufferView& view)
 {
     const char funcName[] = "texSubImage2D";
     const uint8_t funcDims = 2;
 
     TexImageTarget target;
     WebGLTexture* tex;
     if (!ValidateTexImageTarget(this, funcName, funcDims, rawTexImageTarget, &target,
                                 &tex))
@@ -423,23 +427,23 @@ WebGLContext::TexSubImage2D(GLenum rawTe
 
     const bool isSubImage = true;
     const GLenum internalFormat = 0;
     const GLint zOffset = 0;
     const GLsizei depth = 1;
     const GLint border = 0;
     tex->TexOrSubImage(isSubImage, funcName, target, level, internalFormat, xOffset,
                        yOffset, zOffset, width, height, depth, border, unpackFormat,
-                       unpackType, maybeView);
+                       unpackType, &view);
 }
 
 void
 WebGLContext::TexSubImage2D(GLenum rawTexImageTarget, GLint level, GLint xOffset,
                             GLint yOffset, GLenum unpackFormat, GLenum unpackType,
-                            dom::ImageData* imageData, ErrorResult&)
+                            const dom::ImageData& imageData, ErrorResult&)
 {
     const char funcName[] = "texSubImage2D";
     const uint8_t funcDims = 2;
 
     TexImageTarget target;
     WebGLTexture* tex;
     if (!ValidateTexImageTarget(this, funcName, funcDims, rawTexImageTarget, &target,
                                 &tex))
@@ -452,34 +456,34 @@ WebGLContext::TexSubImage2D(GLenum rawTe
     const GLint zOffset = 0;
     tex->TexOrSubImage(isSubImage, funcName, target, level, internalFormat, xOffset,
                        yOffset, zOffset, unpackFormat, unpackType, imageData);
 }
 
 void
 WebGLContext::TexSubImage2D(GLenum rawTexImageTarget, GLint level, GLint xOffset,
                             GLint yOffset, GLenum unpackFormat, GLenum unpackType,
-                            dom::Element* elem, ErrorResult* const out_error)
+                            const dom::Element& elem, ErrorResult& out_error)
 {
     const char funcName[] = "texSubImage2D";
     const uint8_t funcDims = 2;
 
     TexImageTarget target;
     WebGLTexture* tex;
     if (!ValidateTexImageTarget(this, funcName, funcDims, rawTexImageTarget, &target,
                                 &tex))
     {
         return;
     }
 
     const bool isSubImage = true;
     const GLenum internalFormat = 0;
     const GLint zOffset = 0;
     tex->TexOrSubImage(isSubImage, funcName, target, level, internalFormat, xOffset,
-                       yOffset, zOffset, unpackFormat, unpackType, elem, out_error);
+                       yOffset, zOffset, unpackFormat, unpackType, elem, &out_error);
 }
 
 ////////////////////////////////////////
 // CompressedTex(Sub)Image
 
 void
 WebGLContext::CompressedTexImage2D(GLenum rawTexImageTarget, GLint level,
                                    GLenum internalFormat, GLsizei width, GLsizei height,
--- a/dom/canvas/WebGLTexture.h
+++ b/dom/canvas/WebGLTexture.h
@@ -231,27 +231,27 @@ public:
 
     ////////////////////////////////////
     // WebGLTextureUpload.cpp
 
     void TexOrSubImage(bool isSubImage, const char* funcName, TexImageTarget target,
                        GLint level, GLenum internalFormat, GLint xOffset, GLint yOffset,
                        GLint zOffset, GLsizei width, GLsizei height, GLsizei depth,
                        GLint border, GLenum unpackFormat, GLenum unpackType,
-                       const dom::Nullable<dom::ArrayBufferView>& maybeView);
+                       const dom::ArrayBufferView* view);
 
     void TexOrSubImage(bool isSubImage, const char* funcName, TexImageTarget target,
                        GLint level, GLenum internalFormat, GLint xOffset, GLint yOffset,
                        GLint zOffset, GLenum unpackFormat, GLenum unpackType,
-                       dom::ImageData* imageData);
+                       const dom::ImageData& imageData);
 
     void TexOrSubImage(bool isSubImage, const char* funcName, TexImageTarget target,
                        GLint level, GLenum internalFormat, GLint xOffset, GLint yOffset,
                        GLint zOffset, GLenum unpackFormat, GLenum unpackType,
-                       dom::Element* elem, ErrorResult* const out_error);
+                       const dom::Element& elem, ErrorResult* const out_error);
 
     void TexOrSubImage(bool isSubImage, const char* funcName, TexImageTarget target,
                        GLint level, GLenum internalFormat, GLint xOffset, GLint yOffset,
                        GLint zOffset, GLsizei width, GLsizei height, GLsizei depth,
                        GLint border, GLenum unpackFormat, GLenum unpackType,
                        WebGLsizeiptr offset);
 
 protected:
--- a/dom/canvas/WebGLTextureUpload.cpp
+++ b/dom/canvas/WebGLTextureUpload.cpp
@@ -179,16 +179,19 @@ WebGLContext::ValidateUnpackPixels(const
     return false;
 }
 
 static bool
 ValidateUnpackBytes(WebGLContext* webgl, const char* funcName, uint32_t width,
                     uint32_t height, uint32_t depth, const webgl::PackingInfo& pi,
                     uint32_t byteCount, webgl::TexUnpackBlob* blob)
 {
+    if (!width || !height || !depth)
+        return true;
+
     const auto bytesPerPixel = webgl::BytesPerPixel(pi);
     const auto bytesPerRow = CheckedUint32(blob->mRowLength) * bytesPerPixel;
     const auto rowStride = RoundUpToMultipleOf(bytesPerRow, blob->mAlignment);
 
     const auto fullRows = byteCount / rowStride;
     if (!fullRows.isValid()) {
         webgl->ErrorOutOfMemory("%s: Unacceptable upload size calculated.");
         return false;
@@ -222,17 +225,17 @@ WebGLContext::ValidateUnpackInfo(const c
 }
 
 void
 WebGLTexture::TexOrSubImage(bool isSubImage, const char* funcName, TexImageTarget target,
                             GLint level, GLenum internalFormat, GLint xOffset,
                             GLint yOffset, GLint zOffset, GLsizei rawWidth,
                             GLsizei rawHeight, GLsizei rawDepth, GLint border,
                             GLenum unpackFormat, GLenum unpackType,
-                            const dom::Nullable<dom::ArrayBufferView>& maybeView)
+                            const dom::ArrayBufferView* view)
 {
     uint32_t width, height, depth;
     if (!ValidateExtents(mContext, funcName, rawWidth, rawHeight, rawDepth, border,
                          &width, &height, &depth))
     {
         return;
     }
 
@@ -241,32 +244,27 @@ WebGLTexture::TexOrSubImage(bool isSubIm
     if (!mContext->ValidateUnpackInfo(funcName, usePBOs, unpackFormat, unpackType, &pi))
         return;
 
     ////
 
     const uint8_t* bytes = nullptr;
     uint32_t byteCount = 0;
 
-    if (!maybeView.IsNull()) {
-        const auto& view = maybeView.Value();
+    if (view) {
+        view->ComputeLengthAndData();
+        bytes = view->DataAllowShared();
+        byteCount = view->LengthAllowShared();
 
-        const auto jsType = JS_GetArrayBufferViewType(view.Obj());
+        const auto& jsType = view->Type();
         if (!DoesJSTypeMatchUnpackType(pi.type, jsType)) {
             mContext->ErrorInvalidOperation("%s: `pixels` not compatible with `type`.",
                                             funcName);
             return;
         }
-
-        if (width && height && depth) {
-            view.ComputeLengthAndData();
-
-            bytes = view.DataAllowShared();
-            byteCount = view.LengthAllowShared();
-        }
     } else if (isSubImage) {
         mContext->ErrorInvalidValue("%s: `pixels` must not be null.", funcName);
         return;
     }
 
     const bool isClientData = true;
     webgl::TexUnpackBytes blob(mContext, target, width, height, depth, isClientData,
                                bytes);
@@ -331,26 +329,26 @@ WebGLTexture::TexOrSubImage(bool isSubIm
                       yOffset, zOffset, pi, &blob);
 }
 
 ////////////////////////////////////////
 // ImageData
 
 static already_AddRefed<gfx::DataSourceSurface>
 FromImageData(WebGLContext* webgl, const char* funcName, GLenum unpackType,
-              dom::ImageData* imageData, dom::Uint8ClampedArray* scopedArr)
+              const dom::ImageData& imageData, dom::Uint8ClampedArray* scopedArr)
 {
-    DebugOnly<bool> inited = scopedArr->Init(imageData->GetDataObject());
+    DebugOnly<bool> inited = scopedArr->Init(imageData.GetDataObject());
     MOZ_ASSERT(inited);
 
     scopedArr->ComputeLengthAndData();
     const DebugOnly<size_t> dataSize = scopedArr->Length();
     const void* const data = scopedArr->Data();
 
-    const gfx::IntSize size(imageData->Width(), imageData->Height());
+    const gfx::IntSize size(imageData.Width(), imageData.Height());
     const size_t stride = size.width * 4;
     const gfx::SurfaceFormat surfFormat = gfx::SurfaceFormat::R8G8B8A8;
 
     MOZ_ASSERT(dataSize == stride * size.height);
 
     uint8_t* wrappableData = (uint8_t*)data;
 
     RefPtr<gfx::DataSourceSurface> surf =
@@ -365,32 +363,26 @@ FromImageData(WebGLContext* webgl, const
 
     return surf.forget();
 }
 
 void
 WebGLTexture::TexOrSubImage(bool isSubImage, const char* funcName, TexImageTarget target,
                             GLint level, GLenum internalFormat, GLint xOffset,
                             GLint yOffset, GLint zOffset, GLenum unpackFormat,
-                            GLenum unpackType, dom::ImageData* imageData)
+                            GLenum unpackType, const dom::ImageData& imageData)
 {
     const bool usePBOs = false;
     webgl::PackingInfo pi;
     if (!mContext->ValidateUnpackInfo(funcName, usePBOs, unpackFormat, unpackType, &pi))
         return;
 
-    if (!imageData) {
-        // Spec says to generate an INVALID_VALUE error
-        mContext->ErrorInvalidValue("%s: Null ImageData.", funcName);
-        return;
-    }
-
     // Eventually, these will be args.
-    const uint32_t width = imageData->Width();
-    const uint32_t height = imageData->Height();
+    const uint32_t width = imageData.Width();
+    const uint32_t height = imageData.Height();
     const uint32_t depth = 1;
 
     dom::RootedTypedArray<dom::Uint8ClampedArray> scopedArr(dom::RootingCx());
     const RefPtr<gfx::DataSourceSurface> surf = FromImageData(mContext, funcName,
                                                               unpackType, imageData,
                                                               &scopedArr);
     if (!surf)
         return;
@@ -398,33 +390,33 @@ WebGLTexture::TexOrSubImage(bool isSubIm
     // WhatWG "HTML Living Standard" (30 October 2015):
     // "The getImageData(sx, sy, sw, sh) method [...] Pixels must be returned as
     //  non-premultiplied alpha values."
     const bool isAlphaPremult = false;
 
     webgl::TexUnpackSurface blob(mContext, target, width, height, depth, surf,
                                  isAlphaPremult);
 
-    const uint32_t fullRows = imageData->Height();
+    const uint32_t fullRows = imageData.Height();
     const uint32_t tailPixels = 0;
     if (!mContext->ValidateUnpackPixels(funcName, fullRows, tailPixels, &blob))
         return;
 
     TexOrSubImageBlob(isSubImage, funcName, target, level, internalFormat, xOffset,
                       yOffset, zOffset, pi, &blob);
 }
 
 ////////////////////////////////////////
 // dom::Element
 
 void
 WebGLTexture::TexOrSubImage(bool isSubImage, const char* funcName, TexImageTarget target,
                             GLint level, GLenum internalFormat, GLint xOffset,
                             GLint yOffset, GLint zOffset, GLenum unpackFormat,
-                            GLenum unpackType, dom::Element* elem,
+                            GLenum unpackType, const dom::Element& elem,
                             ErrorResult* const out_error)
 {
     const bool usePBOs = false;
     webgl::PackingInfo pi;
     if (!mContext->ValidateUnpackInfo(funcName, usePBOs, unpackFormat, unpackType, &pi))
         return;
 
     //////
@@ -434,17 +426,18 @@ WebGLTexture::TexOrSubImage(bool isSubIm
 
     if (mContext->mPixelStore_ColorspaceConversion == LOCAL_GL_NONE)
         flags |= nsLayoutUtils::SFE_NO_COLORSPACE_CONVERSION;
 
     if (!mContext->mPixelStore_PremultiplyAlpha)
         flags |= nsLayoutUtils::SFE_PREFER_NO_PREMULTIPLY_ALPHA;
 
     RefPtr<gfx::DrawTarget> idealDrawTarget = nullptr; // Don't care for now.
-    auto sfer = nsLayoutUtils::SurfaceFromElement(elem, flags, idealDrawTarget);
+    auto sfer = nsLayoutUtils::SurfaceFromElement(const_cast<dom::Element*>(&elem), flags,
+                                                  idealDrawTarget);
 
     //////
 
     uint32_t elemWidth = 0;
     uint32_t elemHeight = 0;
     layers::Image* layersImage = nullptr;
     if (!gfxPrefs::WebGLDisableDOMBlitUploads() && sfer.mLayersImage) {
         layersImage = sfer.mLayersImage;
--- a/dom/canvas/test/webgl-conf/checkout/conformance/more/README.md
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/more/README.md
@@ -17,17 +17,17 @@ Running the tests
   4. Open all_tests.html in your browser.
 
 
 Want to contribute?
 -------------------
 
   1. Fork this repo
   2. Run <code>gen_tests.rb</code>
-  3. Look into templates/ to see which functions lack tests (also see <a href="../raw/master/methods.txt">methods.txt</a> and <a href="http://mxr.mozilla.org/mozilla-central/source/dom/interfaces/canvas/nsICanvasRenderingContextWebGL.idl">nsICanvasRenderingContextWebGL.idl</a>):
+  3. Look into templates/ to see which functions lack tests (also see <a href="../raw/master/methods.txt">methods.txt</a> and <a href="http://dxr.mozilla.org/mozilla-central/source/dom/interfaces/canvas/nsICanvasRenderingContextWebGL.idl">nsICanvasRenderingContextWebGL.idl</a>):
     1. copy methodName.html to functions/methodName.html and write tests that test the results of valid inputs.
     2. copy methodNameBadArgs.html to functions/methodNameBadArgs.html and write tests to assert that invalid inputs throw exceptions.
     3. If your test causes a segfault, add the following to the top of the script tag: <code>Tests.autorun = false; Tests.message = "Caution: this may crash your browser";</code>
   4. For each performance test:
     1. Write a performance/myTestName.html and set <code>Tests.autorun = false;</code>
   5. If you have a test that you would like to run over the whole API or want to generate tests programmatically, add them to gen_tests.rb or write your own script.
   6. Create a commit for each file. (E.g. <code>for f in $(git status | grep -e "^#\\s*functions/\\S*$" | sed "s/^#\s*//"); do git add $f; git commit -m $f; done</code>)
   7. Send me a pull request.
--- a/dom/canvas/test/webgl-conf/checkout/conformance/textures/misc/tex-sub-image-2d-bad-args.html
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/textures/misc/tex-sub-image-2d-bad-args.html
@@ -61,20 +61,36 @@ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE
 gl.texSubImage2D(gl.TEXTURE_2D, 0, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, c);
 wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "x + width > texture width");
 gl.texSubImage2D(gl.TEXTURE_2D, 0, -1, 0, gl.RGBA, gl.UNSIGNED_BYTE, c);
 wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "negative x");
 gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, -1, gl.RGBA, gl.UNSIGNED_BYTE, c);
 wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "negative y");
 gl.texSubImage2D(gl.TEXTURE_2D, -1, 0, 0, gl.RGBA, gl.UNSIGNED_BYTE, c);
 wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "negative level");
-gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
-wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "no image data");
-gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, 0, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
-wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "null pixels");
+
+if (contextVersion >= 2) {
+    var text = "Should throw with no image data.";
+    try {
+        gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
+        testFailed(text);
+    } catch(e) {
+        testPassed(text);
+    }
+    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "no image data");
+} else {
+    gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
+    wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "no image data");
+}
+
+if (contextVersion < 2) {
+    // In WebGL2, null coerces to 0 for the PBO entrypoint.
+    gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, 0, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
+    wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "null pixels");
+}
 
 // GL_INVALID_VALUE may be generated if level is greater than log 2 max, where max is the returned value of GL_MAX_TEXTURE_SIZE.
 // GL_INVALID_OPERATION is generated if the texture array has not been defined by a previous  glTexImage2D or glCopyTexImage2D operation whose internalformat matches the format of glTexSubImage2D.
 gl.texSubImage2D(gl.TEXTURE_2D, maxTextureLevel + 1, 0, 0, gl.RGBA, gl.UNSIGNED_BYTE, c);
 wtu.glErrorShouldBe(gl, [gl.INVALID_VALUE, gl.INVALID_OPERATION], "too high level");
 
 gl.texSubImage2D(gl.FLOAT, 0, 0, 0, gl.RGBA, gl.UNSIGNED_BYTE, c);
 wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "bad target");
--- a/dom/canvas/test/webgl-conf/checkout/conformance2/buffers/buffer-copying-contents.html
+++ b/dom/canvas/test/webgl-conf/checkout/conformance2/buffers/buffer-copying-contents.html
@@ -103,24 +103,24 @@ function testCopyBuffers(srcTarget, dstT
   }
 
   gl.copyBufferSubData(copyRead ? gl.COPY_READ_BUFFER : srcTarget,
                        copyWrite ? gl.COPY_WRITE_BUFFER : dstTarget,
                        0, 0, length);
   if (expectedGLError == gl.NO_ERROR) {
     wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Copying should work");
 
-    var retBuffer = new ArrayBuffer(length);
+    var retBuffer = new Uint8Array(length);
     gl.getBufferSubData(dstTarget, 0, retBuffer);
     wtu.glErrorShouldBe(gl, gl.NO_ERROR,
         "gl.getBufferSubData(" + targetToString(gl, dstTarget) +
         ", 0, retBuffer) should work");
 
     var failed = false;
-    var retArray = new Float32Array(retBuffer);
+    var retArray = new Float32Array(retBuffer.buffer);
     for (var i = 0; i < vertices.length; i++) {
       if (originalData[i] != retArray[i]) {
         failed = true;
         break;
       }
     }
     if (failed)
       testFailed("The returned array buffer fails to match original data");
--- a/dom/canvas/test/webgl-conf/checkout/conformance2/buffers/getBufferSubData.html
+++ b/dom/canvas/test/webgl-conf/checkout/conformance2/buffers/getBufferSubData.html
@@ -55,56 +55,51 @@ var floatArray = new Float32Array(vertic
 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Should be no errors from setup.");
 
 var buffer = gl.createBuffer();
 gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
 gl.bufferData(gl.ARRAY_BUFFER, floatArray, gl.STATIC_DRAW);
 
 debug("");
 debug("Test that getBufferSubData successfully works reading buffer data from gl.ARRAY_BUFFER");
-var arrBuffer = new ArrayBuffer(vertices.length * Float32Array.BYTES_PER_ELEMENT);
-gl.getBufferSubData(gl.ARRAY_BUFFER, 0, arrBuffer);
+var retArray = new Float32Array(vertices.length);
+gl.getBufferSubData(gl.ARRAY_BUFFER, 0, retArray);
 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "gl.getBufferSubData(gl.ARRAY_BUFFER, 0, arrBuffer) should WORK");
 
 debug("Check array data to match original data set by the buffer");
 var failed = false;
-var retArray = new Float32Array(arrBuffer);
 for (var i = 0; i < vertices.length; i++) {
   if (floatArray[i] != retArray[i]) {
     failed = true;
     break;
   }
 }
 if (failed)
   testFailed("The returned array buffer fails to match original data");
 else
   testPassed("The returned array buffer matches original data");
 
 debug("Test that getBufferSubData fails when given a buffer with its size larger than the original data");
-var extraLargeBuffer = new ArrayBuffer(vertices.length * Float32Array.BYTES_PER_ELEMENT + 1);
+var extraLargeBuffer = new Uint8Array(vertices.length * Float32Array.BYTES_PER_ELEMENT + 1);
 gl.getBufferSubData(gl.ARRAY_BUFFER, 0, extraLargeBuffer);
 wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "gl.getBufferSubData(gl.ARRAY_BUFFER, 0, extraLargeBuffer) with extra length should generate INVALID_VALUE");
 
 debug("Test that getBufferSubData fails when offset summed with buffer length is larger than the size of the original data size");
-gl.getBufferSubData(gl.ARRAY_BUFFER, vertices.length * Float32Array.BYTES_PER_ELEMENT + 1, arrBuffer);
+gl.getBufferSubData(gl.ARRAY_BUFFER, vertices.length * Float32Array.BYTES_PER_ELEMENT + 1, retArray);
 wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "gl.getBufferSubData(gl.ARRAY_BUFFER, vertices.length * Float32Array.BYTES_PER_ELEMENT + 1, arrBuffer) with offset larger than original data size should generate INVALID_VALUE");
-gl.getBufferSubData(gl.ARRAY_BUFFER, 1, arrBuffer);
+gl.getBufferSubData(gl.ARRAY_BUFFER, 1, retArray);
 wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "gl.getBufferSubData(gl.ARRAY_BUFFER, 1, arrBuffer) with offset and length larger than buffer size should generate INVALID_VALUE");
 
 debug("Test that getBufferSubData fails when 0 is bound to the target");
 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
-gl.getBufferSubData(gl.ELEMENT_ARRAY_BUFFER, 0, arrBuffer);
+gl.getBufferSubData(gl.ELEMENT_ARRAY_BUFFER, 0, retArray);
 wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "gl.getBufferSubData(gl.ELEMENT_ARRAY_BUFFER, 0, arrBuffer) should generate INVALID_OPERATION");
 
 debug("Test that getBufferSubData fails when offset is less than 0");
-gl.getBufferSubData(gl.ARRAY_BUFFER, -1, arrBuffer);
+gl.getBufferSubData(gl.ARRAY_BUFFER, -1, retArray);
 wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "gl.getBufferSubData(gl.ARRAY_BUFFER, -1, arrBuffer) should generate INVALID_VALUE");
 
-debug("Test that getBufferSubData fails when given a null buffer");
-gl.getBufferSubData(gl.ARRAY_BUFFER, 0, null);
-wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "gl.getBufferSubData(gl.ARRAY_BUFFER, 0, null) should generate INVALID_VALUE");
-
 finishTest();
 
 var successfullyParsed = true;
 </script>
 </body>
 </html>
--- a/dom/canvas/test/webgl-conf/checkout/js/webgl-test-utils.js
+++ b/dom/canvas/test/webgl-conf/checkout/js/webgl-test-utils.js
@@ -1234,20 +1234,19 @@ var checkAreaInAndOut = function(gl, x, 
  */
 var checkFloatBuffer = function(gl, target, expected, opt_msg, opt_errorRange) {
   if (opt_msg === undefined)
     opt_msg = "buffer should match expected values";
 
   if (opt_errorRange === undefined)
     opt_errorRange = 0.001;
 
-  var outData = new ArrayBuffer(Float32Array.BYTES_PER_ELEMENT * expected.length);
-  gl.getBufferSubData(target, 0, outData);
+  var floatArray = new Float32Array(expected.length);
+  gl.getBufferSubData(target, 0, floatArray);
 
-  var floatArray = new Float32Array(outData);
   for (var i = 0; i < expected.length; i++) {
     if (Math.abs(floatArray[i] - expected[i]) > opt_errorRange) {
       testFailed(opt_msg);
       debug('at [' + i + '] expected: ' + expected[i] + ' was ' + floatArray[i]);
       return;
     }
   }
   testPassed(opt_msg);
--- a/dom/canvas/test/webgl-mochitest/test_pixel_pack_buffer.html
+++ b/dom/canvas/test/webgl-mochitest/test_pixel_pack_buffer.html
@@ -182,65 +182,65 @@ function Test() {
   ////////
 
   // Basic
   section('Basic readback');
   data = ClearBufferPair(gl, 16);
   EnsureNoError(gl);
   gl.readPixels(0, 0, 2, 2, gl.RGBA, gl.UNSIGNED_BYTE, 0);
   EnsureNoError(gl);
-  gl.getBufferSubData(gl.PIXEL_PACK_BUFFER, 0, data.buffer);
+  gl.getBufferSubData(gl.PIXEL_PACK_BUFFER, 0, data);
   EnsureNoError(gl);
   TestIsUNormColor(RED, data, 0);
   TestIsUNormColor(BLUE, data, 4);
   TestIsUNormColor(GREEN, data, 8);
   TestIsUNormColor(WHITE, data, 12);
 
   section('Subrect readback');
   data = ClearBufferPair(gl, 8);
   gl.readPixels(1, 1, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, 0);
-  gl.getBufferSubData(gl.PIXEL_PACK_BUFFER, 0, data.buffer);
+  gl.getBufferSubData(gl.PIXEL_PACK_BUFFER, 0, data);
   EnsureNoError(gl);
   TestIsUNormColor(WHITE, data, 0);
   TestIsUNormColor(ZERO, data, 4);
 
   section('ReadPixels offset:4');
   data = ClearBufferPair(gl, 16);
   gl.readPixels(1, 1, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, 4);
-  gl.getBufferSubData(gl.PIXEL_PACK_BUFFER, 0, data.buffer);
+  gl.getBufferSubData(gl.PIXEL_PACK_BUFFER, 0, data);
   EnsureNoError(gl);
   TestIsUNormColor(ZERO, data, 0);
   TestIsUNormColor(WHITE, data, 4);
   TestIsUNormColor(ZERO, data, 8);
   TestIsUNormColor(ZERO, data, 12);
 
   section('ReadPixels offset:5');
   gl.readPixels(1, 1, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, 5);
-  gl.getBufferSubData(gl.PIXEL_PACK_BUFFER, 0, data.buffer);
+  gl.getBufferSubData(gl.PIXEL_PACK_BUFFER, 0, data);
   EnsureNoError(gl);
   TestIsUNormColor(ZERO, data, 0);
   TestIsUNormColor(WHITE, data, 4); // Should remain from previous read.
   TestIsUNormColor(WHITE, data, 5);
   TestIsUNormColor(ZERO, data, 9);
   TestIsUNormColor(ZERO, data, 12);
 
   section('GetBufferSubData src too small');
   data = ClearBufferPair(gl, 16);
   EnsureNoError(gl);
-  gl.getBufferSubData(gl.PIXEL_PACK_BUFFER, 1, data.buffer);
+  gl.getBufferSubData(gl.PIXEL_PACK_BUFFER, 1, data);
   TestError(gl, gl.INVALID_VALUE);
   TestIsUNormColor(ZERO, data, 0);
   TestIsUNormColor(ZERO, data, 4);
   TestIsUNormColor(ZERO, data, 8);
   TestIsUNormColor(ZERO, data, 12);
 
   section('GetBufferSubData offset:1');
   data = new Uint8Array(15);
   gl.readPixels(1, 1, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, 8);
-  gl.getBufferSubData(gl.PIXEL_PACK_BUFFER, 1, data.buffer);
+  gl.getBufferSubData(gl.PIXEL_PACK_BUFFER, 1, data);
   EnsureNoError(gl);
   TestIsUNormColor(ZERO, data, 0);
   TestIsUNormColor(ZERO, data, 3);
   TestIsUNormColor(WHITE, data, 7);
   TestIsUNormColor(ZERO, data, 11);
 
   //////////////////////////////////////
 
--- a/dom/canvas/test/webgl-mochitest/test_sab_with_webgl.html
+++ b/dom/canvas/test/webgl-mochitest/test_sab_with_webgl.html
@@ -151,18 +151,18 @@ function TestScreenColor(gl, r, g, b, a)
   var arr = new SharedArrayBuffer(8*4);
   var view = new Float32Array(arr);
   view.set(new Float32Array([-1, -1, 1, -1, -1,  1, 1,  1]));
   var vb = gl.createBuffer();
   gl.bindBuffer(gl.ARRAY_BUFFER, vb);
   gl.bufferData(gl.ARRAY_BUFFER, arr, gl.STATIC_DRAW);
 
   var arr2 = new SharedArrayBuffer(8*4);
-  gl.getBufferSubData(gl.ARRAY_BUFFER, 0, arr2);
   var view2 = new Float32Array(arr2);
+  gl.getBufferSubData(gl.ARRAY_BUFFER, 0, view2);
   var equal = true;
   for(var i = 0; i < 8; ++i) {
     if (view[i] != view2[i]) equal = false;
   }
   ok(equal, 'getBufferSubData with SAB as input parameter works ok.');
 
   // Test gl.texImage3D() and gl.texSubImage3D() APIs with SAB as input.
   var tex = gl.createTexture();
--- a/dom/console/Console.cpp
+++ b/dom/console/Console.cpp
@@ -335,17 +335,18 @@ public:
     mWorkerPrivate->AssertIsOnWorkerThread();
 
     if (NS_WARN_IF(!PreDispatch(aCx))) {
       RunBackOnWorkerThread();
       return false;
     }
 
     if (NS_WARN_IF(!WorkerProxyToMainThreadRunnable::Dispatch())) {
-      RunBackOnWorkerThread();
+      // RunBackOnWorkerThread() will be called by
+      // WorkerProxyToMainThreadRunnable::Dispatch().
       return false;
     }
 
     return true;
   }
 
 protected:
   void
--- a/dom/events/DataTransfer.cpp
+++ b/dom/events/DataTransfer.cpp
@@ -307,43 +307,42 @@ DataTransfer::GetFiles(nsIDOMFileList** 
 }
 
 already_AddRefed<DOMStringList>
 DataTransfer::GetTypes(ErrorResult& aRv) const
 {
   RefPtr<DOMStringList> types = new DOMStringList();
 
   const nsTArray<RefPtr<DataTransferItem>>* items = mItems->MozItemsAt(0);
-  if (!items || items->IsEmpty()) {
+  if (NS_WARN_IF(!items)) {
     return types.forget();
   }
 
-  bool addFile = false;
   for (uint32_t i = 0; i < items->Length(); i++) {
     DataTransferItem* item = items->ElementAt(i);
     MOZ_ASSERT(item);
 
     if (item->ChromeOnly() && !nsContentUtils::LegacyIsCallerChromeOrNativeCode()) {
       continue;
     }
 
     nsAutoString type;
     item->GetType(type);
-    if (NS_WARN_IF(!types->Add(type))) {
-      aRv.Throw(NS_ERROR_FAILURE);
-      return nullptr;
-    }
-
-    if (!addFile) {
-      addFile = item->Kind() == DataTransferItem::KIND_FILE;
+    if (item->Kind() == DataTransferItem::KIND_STRING || type.EqualsASCII(kFileMime)) {
+      // If the entry has kind KIND_STRING, we want to add it to the list.
+      if (NS_WARN_IF(!types->Add(type))) {
+        aRv.Throw(NS_ERROR_FAILURE);
+        return nullptr;
+      }
     }
   }
 
-  // If we have any files, we need to also add the "Files" type!
-  if (addFile && NS_WARN_IF(!types->Add(NS_LITERAL_STRING("Files")))) {
+  // If we have any files, add the "Files" string to the list
+  if (mItems->Files()->Length() > 0 &&
+      NS_WARN_IF(!types->Add(NS_LITERAL_STRING("Files")))) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   return types.forget();
 }
 
 NS_IMETHODIMP
--- a/dom/events/DataTransferItem.cpp
+++ b/dom/events/DataTransferItem.cpp
@@ -26,18 +26,16 @@ namespace {
 struct FileMimeNameData
 {
   const char* mMimeName;
   const char* mFileName;
 };
 
 FileMimeNameData kFileMimeNameMap[] = {
   { kFileMime, "GenericFileName" },
-  { kJPEGImageMime, "GenericImageNameJPEG" },
-  { kGIFImageMime, "GenericImageNameGIF" },
   { kPNGImageMime, "GenericImageNamePNG" },
 };
 
 } // anonymous namespace
 
 namespace mozilla {
 namespace dom {
 
--- a/dom/events/test/pointerevents/mochitest.ini
+++ b/dom/events/test/pointerevents/mochitest.ini
@@ -12,16 +12,18 @@ support-files =
   support-files = pointerevent_capture_mouse-manual.html
 [test_pointerevent_capture_suppressing_mouse-manual.html]
   support-files = pointerevent_capture_suppressing_mouse-manual.html
 [test_pointerevent_change-touch-action-onpointerdown_touch-manual.html]
   support-files = pointerevent_change-touch-action-onpointerdown_touch-manual.html
   disabled = disabled
 [test_pointerevent_constructor.html]
   support-files = pointerevent_constructor.html
+[test_pointerevent_element_haspointercapture.html]
+  support-files = pointerevent_element_haspointercapture.html
 [test_pointerevent_gotpointercapture_before_first_pointerevent-manual.html]
   support-files = pointerevent_gotpointercapture_before_first_pointerevent-manual.html
   disabled = should be investigated
 [test_pointerevent_lostpointercapture_for_disconnected_node-manual.html]
   support-files = pointerevent_lostpointercapture_for_disconnected_node-manual.html
 [test_pointerevent_lostpointercapture_is_first-manual.html]
   support-files = pointerevent_lostpointercapture_is_first-manual.html
 [test_pointerevent_pointercancel_touch-manual.html]
new file mode 100644
--- /dev/null
+++ b/dom/events/test/pointerevents/pointerevent_element_haspointercapture.html
@@ -0,0 +1,111 @@
+<!doctype html>
+<html>
+    <head>
+        <title>Element.hasPointerCapture test</title>
+        <meta name="viewport" content="width=device-width">
+        <link rel="stylesheet" type="text/css" href="pointerevent_styles.css">
+        <script src="/resources/testharness.js"></script>
+        <!--script src="/resources/testharnessreport.js"></script-->
+        <script type="text/javascript" src="pointerevent_support.js"></script>
+        <script type="text/javascript" src="mochitest_support_internal.js"></script>
+        <script>
+            var detected_pointertypes = {};
+            add_completion_callback(showPointerTypes);
+            var test_pointerEvent = async_test("hasPointerCapture");
+            var listening_events = [
+                "pointerover",
+                "pointerenter",
+                "pointerout",
+                "pointerleave",
+                "pointermove",
+                "gotpointercapture"
+            ];
+            var set_capture_to_target0 = false;
+
+            function run() {
+                var target0 = document.getElementById("target0");
+                var target1 = document.getElementById("target1");
+
+                on_event(target0, "pointerdown", function (e) {
+                    detected_pointertypes[e.pointerType] = true;
+                    test_pointerEvent.step(function () {
+                        assert_equals(target0.hasPointerCapture(e.pointerId), false,
+                                      "before target0.setPointerCapture, target0.hasPointerCapture should be false");
+                    });
+                    target1.setPointerCapture(e.pointerId);
+                    test_pointerEvent.step(function () {
+                        assert_equals(target0.hasPointerCapture(e.pointerId), false,
+                                      "target1.setPointerCapture, target0.hasPointerCapture should be false");
+                    });
+                    target0.setPointerCapture(e.pointerId);
+                    set_capture_to_target0 = true;
+                    // hasPointerCapture will return true immediately after a call to setPointerCapture
+                    test_pointerEvent.step(function () {
+                        assert_equals(target0.hasPointerCapture(e.pointerId), true,
+                                      "after target0.setPointerCapture, target0.hasPointerCapture should be true");
+                    });
+                    // hasPointerCapture will return false immediately after a call to releasePointerCapture
+                    target0.releasePointerCapture(e.pointerId);
+                    set_capture_to_target0 = false;
+                    test_pointerEvent.step(function () {
+                        assert_equals(target0.hasPointerCapture(e.pointerId), false,
+                                      "after target0.releasePointerCapture, target0.hasPointerCapture should be false");
+                    });
+                    target0.setPointerCapture(e.pointerId);
+                    set_capture_to_target0 = true;
+                    test_pointerEvent.step(function () {
+                        assert_equals(target0.hasPointerCapture(e.pointerId), true,
+                                      "after target0.setPointerCapture, target0.hasPointerCapture should be true");
+                    });
+                });
+
+                for (var i = 0; i < listening_events.length; i++) {
+                    on_event(target0, listening_events[i], function (e) {
+                        test_pointerEvent.step(function () {
+                            assert_equals(target0.hasPointerCapture(e.pointerId), set_capture_to_target0,
+                                          "Received " + e.type + " target0.hasPointerCapture should be " + set_capture_to_target0);
+                        });
+                    });
+                }
+
+                on_event(target0, "pointerup", function (e) {
+                    // Immediately after firing the pointerup or pointercancel events, a user agent must run the steps
+                    // as if the releasePointerCapture() method has been called
+                    test_pointerEvent.step(function () {
+                        assert_equals(target0.hasPointerCapture(e.pointerId), true,
+                                      "pointerup target0.hasPointerCapture should be true");
+                    });
+                    set_capture_to_target0 = false;
+                });
+
+                on_event(target0, "lostpointercapture", function (e) {
+                    test_pointerEvent.step(function () {
+                        assert_equals(target0.hasPointerCapture(e.pointerId), false,
+                                      "pointerup target0.hasPointerCapture should be false");
+                    });
+                    test_pointerEvent.done();
+                });
+            }
+        </script>
+    </head>
+    <body onload="run()">
+        <h1>Element.hasPointerCapture test</h1>
+        <!--
+        <h4>
+            Test Description: This test checks if Element.hasPointerCapture returns value correctly
+            <ol>
+                <li> Press black rectangle and do not release
+                <li> Move your pointer to yellow rectangle
+                <li> Release the pointer
+            </ol>
+        </h4>
+        <p>
+        -->
+        <div id="target0" style="background:black"></div>
+        <div id="target1" style="background:yellow"></div>
+        <div id="complete-notice">
+            <p>The following pointer types were detected: <span id="pointertype-log"></span>.</p>
+        </div>
+        <div id="log"></div>
+    </body>
+</html>
\ No newline at end of file
--- a/dom/events/test/pointerevents/pointerevent_lostpointercapture_is_first-manual.html
+++ b/dom/events/test/pointerevents/pointerevent_lostpointercapture_is_first-manual.html
@@ -1,30 +1,30 @@
 <!doctype html>
 <html>
     <head>
         <title>Lostpointercapture triggers first and asynchronously</title>
-        <meta name="assert" content="TA11.1: After pointer capture is released for a pointer, and prior to any subsequent events for the pointer, the lostpointercapture event must be dispatched to the element from which pointer capture was removed; TA11.2: lostpointercapture must be dispatched asynchronously.">
+        <meta name="assert" content="TA5.2.10: A user agent must fire a pointer event named lostpointercapture after pointer capture is released for a pointer. This event must be fired prior to any subsequent events for the pointer after capture was released. This event is fired at the element from which pointer capture was removed;">
         <meta name="viewport" content="width=device-width">
         <link rel="stylesheet" type="text/css" href="pointerevent_styles.css">
         <script src="/resources/testharness.js"></script>
         <!--script src="/resources/testharnessreport.js"></script-->
         <script src="pointerevent_support.js"></script>
         <script src="mochitest_support_internal.js"></script>
     </head>
     <body onload="run()">
         <h1>Pointer Events capture test - lostpointercapture order</h1>
         <!--
         <h4>
             Test Description:
             This test checks if lostpointercapture is handled asynchronously and prior to all subsequent events.
             Complete the following actions:
             <ol>
                 <li>Press and hold left mouse button over "Set Capture" button. "gotpointercapture" should be logged inside of the black rectangle
-                <li>"lostpointercapture" should be logged inside of the black rectangle after a short delay
+                <li>"lostpointercapture" should be logged inside of the black rectangle after pointerup
             </ol>
         </h4>
         Test passes if lostpointercapture is dispatched after releasing the mouse button and before any additional pointer events.
         -->
         <div id="target0" style="background:black; color:white"></div>
         <br>
         <input type="button" id="btnCapture" value="Set Capture">
         <script type='text/javascript'>
@@ -52,19 +52,23 @@
                     pointerdown_event = event;
                     if(isPointerCapture == false) {
                         isPointerCapture = true;
                         captureButton.value = 'Release Capture';
                         sPointerCapture(event);
                     }
                 });
 
+                // TA5.1.3.1: Process Pending Pointer Capture
+                // Whenever a user agent is to fire a Pointer Event that is not gotpointercapture or lostpointercapture,
+                // it must first run the steps of processing pending pointer capture
+                //
+                // TA5.2.12: The lostpointercapture event
                 // After pointer capture is released for a pointer, and prior to any subsequent events for the pointer,
                 // the lostpointercapture event must be dispatched to the element from which pointer capture was removed.
-                // TA: 11.1
                 // listen to all events
                 for (var i = 0; i < All_Pointer_Events.length; i++) {
                     on_event(target0, All_Pointer_Events[i], function (event) {
                         // if the event was gotpointercapture, just log it and return
                         if (event.type == "gotpointercapture") {
                             testStarted = true;
                             rPointerCapture(event);
                             isAsync = true;
@@ -76,32 +80,32 @@
                             captureButton.value = 'Set Capture';
                             isPointerCapture = false;
 
                             // TA: 11.2
                             test_pointerEvent.step(function () {
                                 assert_true(isAsync, "lostpointercapture must be fired asynchronously");
                              });
 
-                            // if any events have been received with same pointerId before lostpointercapture, then fail
+                            // if any events except pointerup have been received with same pointerId before lostpointercapture, then fail
                             var eventsRcvd_str = "";
                             if (eventRcvd) {
                                 eventsRcvd_str = "Events received before lostpointercapture: ";
                                 for (var i = 0; i < detected_pointerEvents.length; i++) {
                                     eventsRcvd_str += detected_pointerEvents[i] + ", ";
                                 }
                             }
                             test_pointerEvent.step(function () {
                                 assert_false(eventRcvd, "no other events should be received before lostpointercapture." + eventsRcvd_str);
                                 assert_equals(event.pointerId, pointerdown_event.pointerId, "pointerID is same for pointerdown and lostpointercapture");
                             });
                             test_pointerEvent.done(); // complete test
                         }
                         else {
-                            if (testStarted && pointerdown_event != null && pointerdown_event.pointerId === event.pointerId) {
+                            if (testStarted && pointerdown_event != null && pointerdown_event.pointerId === event.pointerId && event.type != "pointerup") {
                                 detected_pointerEvents.push(event.type);
                                 eventRcvd = true;
                             }
                         }
                     });
                 }
             }
         </script>
new file mode 100644
--- /dev/null
+++ b/dom/events/test/pointerevents/test_pointerevent_element_haspointercapture.html
@@ -0,0 +1,32 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1000870
+-->
+  <head>
+    <meta charset="utf-8">
+    <title>Test for Bug 1000870</title>
+    <meta name="author" content="Maksim Lebedev" />
+    <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+    <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+    <script type="text/javascript" src="mochitest_support_external.js"></script>
+    <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+    <script type="text/javascript">
+      SimpleTest.waitForExplicitFinish();
+      function startTest() {
+        var iframe = document.getElementById("testFrame");
+        iframe.src = "pointerevent_element_haspointercapture.html";
+      }
+      function executeTest(int_win) {
+        sendMouseEvent(int_win, "target0", "mousemove");
+        sendMouseEvent(int_win, "target0", "mousedown", {button:0});
+        sendMouseEvent(int_win, "target0", "mousemove", {button:0});
+        sendMouseEvent(int_win, "target1", "mousemove", {button:0});
+        sendMouseEvent(int_win, "target1", "mouseup", {button:0});
+      }
+    </script>
+  </head>
+  <body>
+    <iframe id="testFrame" height="800" width="1000"></iframe>
+  </body>
+</html>
--- a/dom/fetch/InternalRequest.cpp
+++ b/dom/fetch/InternalRequest.cpp
@@ -332,18 +332,17 @@ InternalRequest::MapChannelToRequestMode
     return RequestMode::Navigate;
   }
 
   // TODO: remove the worker override once securityMode is fully implemented (bug 1189945)
   if (IsWorkerContentPolicy(contentPolicy)) {
     return RequestMode::Same_origin;
   }
 
-  uint32_t securityMode;
-  MOZ_ALWAYS_SUCCEEDS(loadInfo->GetSecurityMode(&securityMode));
+  uint32_t securityMode = loadInfo->GetSecurityMode();
 
   switch(securityMode) {
     case nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_INHERITS:
     case nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_IS_BLOCKED:
       return RequestMode::Same_origin;
     case nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_INHERITS:
     case nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL:
       return RequestMode::No_cors;
@@ -372,21 +371,19 @@ InternalRequest::MapChannelToRequestMode
 RequestCredentials
 InternalRequest::MapChannelToRequestCredentials(nsIChannel* aChannel)
 {
   MOZ_ASSERT(aChannel);
 
   nsCOMPtr<nsILoadInfo> loadInfo;
   MOZ_ALWAYS_SUCCEEDS(aChannel->GetLoadInfo(getter_AddRefs(loadInfo)));
 
-  uint32_t securityMode;
-  MOZ_ALWAYS_SUCCEEDS(loadInfo->GetSecurityMode(&securityMode));
 
   // TODO: Remove following code after stylesheet and image support cookie policy
-  if (securityMode == nsILoadInfo::SEC_NORMAL) {
+  if (loadInfo->GetSecurityMode() == nsILoadInfo::SEC_NORMAL) {
     uint32_t loadFlags;
     aChannel->GetLoadFlags(&loadFlags);
 
     if (loadFlags & nsIRequest::LOAD_ANONYMOUS) {
       return RequestCredentials::Omit;
     } else {
       bool includeCrossOrigin;
       nsCOMPtr<nsIHttpChannelInternal> internalChannel = do_QueryInterface(aChannel);
--- a/dom/html/HTMLFormControlsCollection.cpp
+++ b/dom/html/HTMLFormControlsCollection.cpp
@@ -42,21 +42,22 @@ HTMLFormControlsCollection::ShouldBeInEl
   case NS_FORM_INPUT_RESET :
   case NS_FORM_INPUT_PASSWORD :
   case NS_FORM_INPUT_RADIO :
   case NS_FORM_INPUT_SEARCH :
   case NS_FORM_INPUT_SUBMIT :
   case NS_FORM_INPUT_TEXT :
   case NS_FORM_INPUT_TEL :
   case NS_FORM_INPUT_URL :
-  case NS_FORM_INPUT_MONTH :
   case NS_FORM_INPUT_NUMBER :
   case NS_FORM_INPUT_RANGE :
   case NS_FORM_INPUT_DATE :
   case NS_FORM_INPUT_TIME :
+  case NS_FORM_INPUT_MONTH :
+  case NS_FORM_INPUT_WEEK :
   case NS_FORM_SELECT :
   case NS_FORM_TEXTAREA :
   case NS_FORM_FIELDSET :
   case NS_FORM_OBJECT :
   case NS_FORM_OUTPUT :
     return true;
   }
 
--- a/dom/html/HTMLHRElement.cpp
+++ b/dom/html/HTMLHRElement.cpp
@@ -201,17 +201,17 @@ HTMLHRElement::MapAttributesIntoRule(con
         borderLeftStyle->SetIntValue(NS_STYLE_BORDER_STYLE_SOLID,
                                      eCSSUnit_Enumerated);
       }
 
       // If it would be noticeable, set the border radius to
       // 10000px on all corners; this triggers the clamping to make
       // circular ends.  This assumes the <hr> isn't larger than
       // that in *both* dimensions.
-      for (const nsCSSProperty* props =
+      for (const nsCSSPropertyID* props =
             nsCSSProps::SubpropertyEntryFor(eCSSProperty_border_radius);
            *props != eCSSProperty_UNKNOWN; ++props) {
         nsCSSValue* dimen = aData->ValueFor(*props);
         if (dimen->GetUnit() == eCSSUnit_Null) {
           dimen->SetFloatValue(10000.0f, eCSSUnit_Pixel);
         }
       }
     }
--- a/dom/html/HTMLInputElement.cpp
+++ b/dom/html/HTMLInputElement.cpp
@@ -172,16 +172,17 @@ static const nsAttrValue::EnumTable kInp
   { "radio", NS_FORM_INPUT_RADIO },
   { "range", NS_FORM_INPUT_RANGE },
   { "search", NS_FORM_INPUT_SEARCH },
   { "submit", NS_FORM_INPUT_SUBMIT },
   { "tel", NS_FORM_INPUT_TEL },
   { "text", NS_FORM_INPUT_TEXT },
   { "time", NS_FORM_INPUT_TIME },
   { "url", NS_FORM_INPUT_URL },
+  { "week", NS_FORM_INPUT_WEEK },
   { 0 }
 };
 
 // Default type is 'text'.
 static const nsAttrValue::EnumTable* kInputDefaultType = &kInputTypeTable[17];
 
 static const uint8_t NS_INPUT_INPUTMODE_AUTO              = 0;
 static const uint8_t NS_INPUT_INPUTMODE_NUMERIC           = 1;
@@ -2117,17 +2118,18 @@ HTMLInputElement::ConvertNumberToString(
       return false;
   }
 }
 
 
 Nullable<Date>
 HTMLInputElement::GetValueAsDate(ErrorResult& aRv)
 {
-  if (!IsDateTimeInputType(mType)) {
+  // TODO: this is temporary until bug 888316 is fixed.
+  if (!IsDateTimeInputType(mType) || mType == NS_FORM_INPUT_WEEK) {
     return Nullable<Date>();
   }
 
   switch (mType) {
     case NS_FORM_INPUT_DATE:
     {
       uint32_t year, month, day;
       nsAutoString value;
@@ -2171,17 +2173,18 @@ HTMLInputElement::GetValueAsDate(ErrorRe
   MOZ_ASSERT(false, "Unrecognized input type");
   aRv.Throw(NS_ERROR_UNEXPECTED);
   return Nullable<Date>();
 }
 
 void
 HTMLInputElement::SetValueAsDate(Nullable<Date> aDate, ErrorResult& aRv)
 {
-  if (!IsDateTimeInputType(mType)) {
+  // TODO: this is temporary until bug 888316 is fixed.
+  if (!IsDateTimeInputType(mType) || mType == NS_FORM_INPUT_WEEK) {
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return;
   }
 
   if (aDate.IsNull() || aDate.Value().IsUndefined()) {
     aRv = SetValue(EmptyString());
     return;
   }
@@ -2419,19 +2422,20 @@ HTMLInputElement::IsExperimentalMobileTy
     !Preferences::GetBool("dom.forms.datepicker", false)) ||
     (aType == NS_FORM_INPUT_TIME &&
      !Preferences::GetBool("dom.forms.datetime", false));
 }
 
 bool
 HTMLInputElement::IsDateTimeInputType(uint8_t aType)
 {
-  return aType == NS_FORM_INPUT_DATE || aType == NS_FORM_INPUT_TIME ||
-    aType == NS_FORM_INPUT_MONTH;
-
+  return aType == NS_FORM_INPUT_DATE ||
+         aType == NS_FORM_INPUT_TIME ||
+         aType == NS_FORM_INPUT_MONTH ||
+         aType == NS_FORM_INPUT_WEEK;
 }
 
 NS_IMETHODIMP
 HTMLInputElement::StepDown(int32_t n, uint8_t optional_argc)
 {
   return ApplyStep(optional_argc ? -n : -1);
 }
 
@@ -5253,17 +5257,18 @@ IsDateTimeEnabled(int32_t aNewType)
 {
   return (aNewType == NS_FORM_INPUT_DATE &&
           (Preferences::GetBool("dom.forms.datetime", false) ||
            Preferences::GetBool("dom.experimental_forms", false) ||
            Preferences::GetBool("dom.forms.datepicker", false))) ||
          (aNewType == NS_FORM_INPUT_TIME &&
           (Preferences::GetBool("dom.forms.datetime", false) ||
            Preferences::GetBool("dom.experimental_forms", false))) ||
-         (aNewType == NS_FORM_INPUT_MONTH &&
+         ((aNewType == NS_FORM_INPUT_MONTH ||
+           aNewType == NS_FORM_INPUT_WEEK) &&
           Preferences::GetBool("dom.forms.datetime", false));
 }
 
 bool
 HTMLInputElement::ParseAttribute(int32_t aNamespaceID,
                                  nsIAtom* aAttribute,
                                  const nsAString& aValue,
                                  nsAttrValue& aResult)
@@ -6739,16 +6744,17 @@ HTMLInputElement::GetValueMode() const
     case NS_FORM_INPUT_EMAIL:
     case NS_FORM_INPUT_URL:
     case NS_FORM_INPUT_NUMBER:
     case NS_FORM_INPUT_RANGE:
     case NS_FORM_INPUT_DATE:
     case NS_FORM_INPUT_TIME:
     case NS_FORM_INPUT_COLOR:
     case NS_FORM_INPUT_MONTH:
+    case NS_FORM_INPUT_WEEK:
       return VALUE_MODE_VALUE;
     default:
       NS_NOTYETIMPLEMENTED("Unexpected input type in GetValueMode()");
       return VALUE_MODE_VALUE;
 #else // DEBUG
     default:
       return VALUE_MODE_VALUE;
 #endif // DEBUG
@@ -6785,16 +6791,17 @@ HTMLInputElement::DoesReadOnlyApply() co
     case NS_FORM_INPUT_SEARCH:
     case NS_FORM_INPUT_TEL:
     case NS_FORM_INPUT_EMAIL:
     case NS_FORM_INPUT_URL:
     case NS_FORM_INPUT_NUMBER:
     case NS_FORM_INPUT_DATE:
     case NS_FORM_INPUT_TIME:
     case NS_FORM_INPUT_MONTH:
+    case NS_FORM_INPUT_WEEK:
       return true;
     default:
       NS_NOTYETIMPLEMENTED("Unexpected input type in DoesReadOnlyApply()");
       return true;
 #else // DEBUG
     default:
       return true;
 #endif // DEBUG
@@ -6823,16 +6830,17 @@ HTMLInputElement::DoesRequiredApply() co
     case NS_FORM_INPUT_SEARCH:
     case NS_FORM_INPUT_TEL:
     case NS_FORM_INPUT_EMAIL:
     case NS_FORM_INPUT_URL:
     case NS_FORM_INPUT_NUMBER:
     case NS_FORM_INPUT_DATE:
     case NS_FORM_INPUT_TIME:
     case NS_FORM_INPUT_MONTH:
+    case NS_FORM_INPUT_WEEK:
       return true;
     default:
       NS_NOTYETIMPLEMENTED("Unexpected input type in DoesRequiredApply()");
       return true;
 #else // DEBUG
     default:
       return true;
 #endif // DEBUG
@@ -6865,16 +6873,17 @@ HTMLInputElement::DoesMinMaxApply() cons
 {
   switch (mType)
   {
     case NS_FORM_INPUT_NUMBER:
     case NS_FORM_INPUT_DATE:
     case NS_FORM_INPUT_TIME:
     case NS_FORM_INPUT_RANGE:
     case NS_FORM_INPUT_MONTH:
+    case NS_FORM_INPUT_WEEK:
     // TODO:
     // All date/time types.
       return true;
 #ifdef DEBUG
     case NS_FORM_INPUT_RESET:
     case NS_FORM_INPUT_SUBMIT:
     case NS_FORM_INPUT_IMAGE:
     case NS_FORM_INPUT_BUTTON:
@@ -6913,16 +6922,17 @@ HTMLInputElement::DoesAutocompleteApply(
     case NS_FORM_INPUT_EMAIL:
     case NS_FORM_INPUT_PASSWORD:
     case NS_FORM_INPUT_DATE:
     case NS_FORM_INPUT_TIME:
     case NS_FORM_INPUT_NUMBER:
     case NS_FORM_INPUT_RANGE:
     case NS_FORM_INPUT_COLOR:
     case NS_FORM_INPUT_MONTH:
+    case NS_FORM_INPUT_WEEK:
       return true;
 #ifdef DEBUG
     case NS_FORM_INPUT_RESET:
     case NS_FORM_INPUT_SUBMIT:
     case NS_FORM_INPUT_IMAGE:
     case NS_FORM_INPUT_BUTTON:
     case NS_FORM_INPUT_RADIO:
     case NS_FORM_INPUT_CHECKBOX:
@@ -7096,17 +7106,18 @@ HTMLInputElement::HasPatternMismatch() c
   nsIDocument* doc = OwnerDoc();
 
   return !nsContentUtils::IsPatternMatching(value, pattern, doc);
 }
 
 bool
 HTMLInputElement::IsRangeOverflow() const
 {
-  if (!DoesMinMaxApply()) {
+  // TODO: this is temporary until bug 888316 is fixed.
+  if (!DoesMinMaxApply() || mType == NS_FORM_INPUT_WEEK) {
     return false;
   }
 
   Decimal maximum = GetMaximum();
   if (maximum.isNaN()) {
     return false;
   }
 
@@ -7116,17 +7127,18 @@ HTMLInputElement::IsRangeOverflow() cons
   }
 
   return value > maximum;
 }
 
 bool
 HTMLInputElement::IsRangeUnderflow() const
 {
-  if (!DoesMinMaxApply()) {
+  // TODO: this is temporary until bug 888316 is fixed.
+  if (!DoesMinMaxApply() || mType == NS_FORM_INPUT_WEEK) {
     return false;
   }
 
   Decimal minimum = GetMinimum();
   if (minimum.isNaN()) {
     return false;
   }
 
@@ -8087,17 +8099,18 @@ HTMLInputElement::UpdateHasRange()
 {
   /*
    * There is a range if min/max applies for the type and if the element
    * currently have a valid min or max.
    */
 
   mHasRange = false;
 
-  if (!DoesMinMaxApply()) {
+  // TODO: this is temporary until bug 888316 is fixed.
+  if (!DoesMinMaxApply() || mType == NS_FORM_INPUT_WEEK) {
     return;
   }
 
   Decimal minimum = GetMinimum();
   if (!minimum.isNaN()) {
     mHasRange = true;
     return;
   }
--- a/dom/html/HTMLInputElement.h
+++ b/dom/html/HTMLInputElement.h
@@ -1018,27 +1018,35 @@ protected:
   /**
    * Returns if the min and max attributes apply for the current type.
    */
   bool DoesMinMaxApply() const;
 
   /**
    * Returns if the step attribute apply for the current type.
    */
-  bool DoesStepApply() const { return DoesMinMaxApply(); }
+  bool DoesStepApply() const
+  {
+    // TODO: this is temporary until bug 888316 is fixed.
+    return DoesMinMaxApply() && mType != NS_FORM_INPUT_WEEK;
+  }
 
   /**
    * Returns if stepDown and stepUp methods apply for the current type.
    */
   bool DoStepDownStepUpApply() const { return DoesStepApply(); }
 
   /**
    * Returns if valueAsNumber attribute applies for the current type.
    */
-  bool DoesValueAsNumberApply() const { return DoesMinMaxApply(); }
+  bool DoesValueAsNumberApply() const
+  {
+    // TODO: this is temporary until bug 888316 is fixed.
+    return DoesMinMaxApply() && mType != NS_FORM_INPUT_WEEK;
+  }
 
   /**
    * Returns if autocomplete attribute applies for the current type.
    */
   bool DoesAutocompleteApply() const;
 
   /**
    * Returns if the maxlength attribute applies for the current type.
--- a/dom/html/nsGenericHTMLFrameElement.cpp
+++ b/dom/html/nsGenericHTMLFrameElement.cpp
@@ -191,29 +191,25 @@ NS_IMETHODIMP
 nsGenericHTMLFrameElement::GetParentApplication(mozIApplication** aApplication)
 {
   if (!aApplication) {
     return NS_ERROR_FAILURE;
   }
 
   *aApplication = nullptr;
 
-  uint32_t appId;
   nsIPrincipal *principal = NodePrincipal();
-  nsresult rv = principal->GetAppId(&appId);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
+  uint32_t appId = principal->GetAppId();
 
   nsCOMPtr<nsIAppsService> appsService = do_GetService(APPS_SERVICE_CONTRACTID);
   if (NS_WARN_IF(!appsService)) {
     return NS_ERROR_FAILURE;
   }
 
-  rv = appsService->GetAppByLocalId(appId, aApplication);
+  nsresult rv = appsService->GetAppByLocalId(appId, aApplication);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   return NS_OK;
 }
 
 void
--- a/dom/html/nsIFormControl.h
+++ b/dom/html/nsIFormControl.h
@@ -61,16 +61,17 @@ enum InputElementTypes {
   NS_FORM_INPUT_RADIO,
   NS_FORM_INPUT_SEARCH,
   NS_FORM_INPUT_SUBMIT,
   NS_FORM_INPUT_TEL,
   NS_FORM_INPUT_TEXT,
   NS_FORM_INPUT_TIME,
   NS_FORM_INPUT_URL,
   NS_FORM_INPUT_RANGE,
+  NS_FORM_INPUT_WEEK,
   eInputElementTypesMax
 };
 
 static_assert(static_cast<uint32_t>(eFormControlsWithoutSubTypesMax) <
               static_cast<uint32_t>(NS_FORM_BUTTON_ELEMENT),
               "Too many FormControlsTypes without sub-types");
 static_assert(static_cast<uint32_t>(eButtonElementTypesMax) <
               static_cast<uint32_t>(NS_FORM_INPUT_ELEMENT),
@@ -263,16 +264,17 @@ nsIFormControl::IsSingleLineTextControl(
          aType == NS_FORM_INPUT_EMAIL ||
          aType == NS_FORM_INPUT_SEARCH ||
          aType == NS_FORM_INPUT_TEL ||
          aType == NS_FORM_INPUT_URL ||
          // TODO: those are temporary until bug 773205 is fixed.
          aType == NS_FORM_INPUT_DATE ||
          aType == NS_FORM_INPUT_TIME ||
          aType == NS_FORM_INPUT_MONTH ||
+         aType == NS_FORM_INPUT_WEEK ||
          (!aExcludePassword && aType == NS_FORM_INPUT_PASSWORD);
 }
 
 bool
 nsIFormControl::IsSubmittableControl() const
 {
   // TODO: keygen should be in that list, see bug 101019.
   uint32_t type = GetType();
--- a/dom/html/test/forms/test_input_attributes_reflection.html
+++ b/dom/html/test/forms/test_input_attributes_reflection.html
@@ -229,20 +229,21 @@ reflectString({
 });
 
 // .type
 reflectLimitedEnumerated({
   element: document.createElement("input"),
   attribute: "type",
   validValues: [ "hidden", "text", "search", "tel", "url", "email", "password",
                  "checkbox", "radio", "file", "submit", "image", "reset",
-                 "button", "date", "time", "number", "range", "color", "month" ],
+                 "button", "date", "time", "number", "range", "color", "month",
+                 "week" ],
   invalidValues: [ "this-is-probably-a-wrong-type", "", "tulip" ],
   defaultValue: "text",
-  unsupportedValues: [ "datetime", "week", "datetime-local" ]
+  unsupportedValues: [ "datetime", "datetime-local" ]
 });
 
 // .defaultValue
 reflectString({
   element: document.createElement("input"),
   attribute: { idl: "defaultValue", content: "value" },
   otherValues: [ "foo\nbar", "foo\rbar", "foo\r\nbar" ],
 });
--- a/dom/html/test/forms/test_input_sanitization.html
+++ b/dom/html/test/forms/test_input_sanitization.html
@@ -74,17 +74,17 @@ var inputTypes =
 [
   "text", "password", "search", "tel", "hidden", "checkbox", "radio",
   "submit", "image", "reset", "button", "email", "url", "number", "date",
   "time", "range", "color", "month"
 ];
 
 var todoTypes =
 [
-  "week", "datetime", "datetime-local",
+  "datetime", "datetime-local",
 ];
 
 var valueModeValue =
 [
   "text", "search", "url", "tel", "email", "password", "date", "datetime",
   "month", "week", "time", "datetime-local", "number", "range", "color",
 ];
 
--- a/dom/html/test/forms/test_input_types_pref.html
+++ b/dom/html/test/forms/test_input_types_pref.html
@@ -59,16 +59,24 @@ https://bugzilla.mozilla.org/show_bug.cg
     }, {
       prefs: [["dom.forms.datetime", false]],
       inputType: "month",
       expectedType: "text"
     }, {
       prefs: [["dom.forms.datetime", true]],
       inputType: "month",
       expectedType: "month"
+    }, {
+      prefs: [["dom.forms.datetime", false]],
+      inputType: "week",
+      expectedType: "text"
+    }, {
+      prefs: [["dom.forms.datetime", true]],
+      inputType: "week",
+      expectedType: "week"
     }
   ];
 
   function testInputTypePreference(aData) {
     return SpecialPowers.pushPrefEnv({'set': aData.prefs})
       .then(() => {
         // Change the type of input to text and then back to the tested input type,
         // so that HTMLInputElement::ParseAttribute gets called with the pref enabled.
--- a/dom/html/test/forms/test_input_typing_sanitization.html
+++ b/dom/html/test/forms/test_input_typing_sanitization.html
@@ -193,17 +193,16 @@ function runTest()
         '-',
         'december',
         '2012-dec',
         '2012/12',
         '2012-99',
         '2012-1',
       ]
     },
-    { type: 'week', todo: true },
     { type: 'datetime', todo: true },
     { type: 'datetime-local', todo: true },
   ];
 
   for (test of data) {
     gCurrentTest = test;
 
     if (test.todo) {
--- a/dom/html/test/forms/test_max_attribute.html
+++ b/dom/html/test/forms/test_max_attribute.html
@@ -25,17 +25,18 @@ var data = [
   { type: 'search', apply: false },
   { type: 'tel', apply: false },
   { type: 'url', apply: false },
   { type: 'email', apply: false },
   { type: 'password', apply: false },
   { type: 'datetime', apply: true, todo: true },
   { type: 'date', apply: true },
   { type: 'month', apply: true },
-  { type: 'week', apply: true, todo: true },
+  // TODO: temporary set to false until bug 888316 is fixed.
+  { type: 'week', apply: false },
   { type: 'time', apply: true },
   { type: 'datetime-local', apply: true, todo: true },
   { type: 'number', apply: true },
   { type: 'range', apply: true },
   { type: 'color', apply: false },
   { type: 'checkbox', apply: false },
   { type: 'radio', apply: false },
   { type: 'file', apply: false },
@@ -144,16 +145,19 @@ for (var test of data) {
       input.max = '-1';
       checkValidity(input, false, apply, apply);
       // Now make it something that won't cause an error below:
       input.max = '10';
       break;
     case 'month':
       input.max = '2016-12';
       break;
+    case 'week':
+      // TODO: this is temporary until bug 888316 is fixed.
+      break;
     default:
       ok(false, 'please, add a case for this new type (' + input.type + ')');
   }
 
   checkValidity(input, true, apply, apply);
 
   switch (input.type) {
     case 'text':
@@ -374,17 +378,18 @@ for (var test of data) {
       input.value = '0049-12';
       checkValidity(input, true, apply, apply);
 
       input.max = '';
       checkValidity(input, true, apply, false);
 
       input.max = 'foo';
       checkValidity(input, true, apply, false);
-
+    case 'week':
+      // TODO: this is temporary until bug 888316 is fixed.
       break;
   }
 
   // Cleaning up,
   input.removeAttribute('max');
   input.value = '';
 }
 
--- a/dom/html/test/forms/test_min_attribute.html
+++ b/dom/html/test/forms/test_min_attribute.html
@@ -25,17 +25,18 @@ var data = [
   { type: 'search', apply: false },
   { type: 'tel', apply: false },
   { type: 'url', apply: false },
   { type: 'email', apply: false },
   { type: 'password', apply: false },
   { type: 'datetime', apply: true, todo: true },
   { type: 'date', apply: true },
   { type: 'month', apply: true },
-  { type: 'week', apply: true, todo: true },
+  // TODO: temporary set to false until bug 888316 is fixed.
+  { type: 'week', apply: false },
   { type: 'time', apply: true },
   { type: 'datetime-local', apply: true, todo: true },
   { type: 'number', apply: true },
   { type: 'range', apply: true },
   { type: 'color', apply: false },
   { type: 'checkbox', apply: false },
   { type: 'radio', apply: false },
   { type: 'file', apply: false },
@@ -140,16 +141,19 @@ for (var test of data) {
     case 'range':
       // range is special, since setting min to 999 will make it invalid since
       // it's default maximum is 100, its value would be 999, and it would
       // suffer from overflow.
       break;
     case 'month':
       input.min = '2016-06';
       break;
+    case 'week':
+      // TODO: this is temporary until bug 888316 is fixed.
+      break;
     default:
       ok(false, 'please, add a case for this new type (' + input.type + ')');
   }
 
   // The element should still be valid and range should apply if it can.
   checkValidity(input, true, apply, apply);
 
   switch (input.type) {
@@ -371,16 +375,19 @@ for (var test of data) {
       checkValidity(input, false, apply, apply);
 
       input.min = '';
       checkValidity(input, true, apply, false);
 
       input.min = 'foo';
       checkValidity(input, true, apply, false);
       break;
+    case 'week':
+      // TODO: this is temporary until bug 888316 is fixed.
+      break;
     default:
       ok(false, 'write tests for ' + input.type);
   }
 
   // Cleaning up,
   input.removeAttribute('min');
   input.value = '';
 }
--- a/dom/html/test/forms/test_mozistextfield.html
+++ b/dom/html/test/forms/test_mozistextfield.html
@@ -48,26 +48,26 @@ var gInputTestData = [
   ['email',    true],
   ['url',      true],
   ['number',   false],
   ['range',    false],
   ['date',     false],
   ['time',     false],
   ['color',    false],
   ['month',    false],
+  ['week',     false],
 ];
 
 /**
  * TODO: the next types are not yet in the tree.
  * The value is only a suggestion.
  */
 var gInputTodoData = [
 /* type        expected result */
   ['datetime', false],
-  ['week',     false],
   ['datetime-local', false],
 ];
 
 function checkMozIsTextFieldDefined(aElement, aResult)
 {
   var element = document.createElement(aElement);
 
   var msg = "mozIsTextField should be "
--- a/dom/html/test/forms/test_pattern_attribute.html
+++ b/dom/html/test/forms/test_pattern_attribute.html
@@ -293,18 +293,19 @@ function checkPatternValidity(element)
 }
 
 var input = document.getElementById('i');
 
 // |validTypes| are the types which accept @pattern
 // and |invalidTypes| are the ones which do not accept it.
 var validTypes = Array('text', 'password', 'search', 'tel', 'email', 'url');
 var barredTypes = Array('hidden', 'reset', 'button');
-var invalidTypes = Array('checkbox', 'radio', 'file', 'number', 'range', 'date', 'time', 'color', 'submit', 'image', 'month');
-// TODO: 'datetime', 'week', and 'datetime-local'
+var invalidTypes = Array('checkbox', 'radio', 'file', 'number', 'range', 'date',
+                         'time', 'color', 'submit', 'image', 'month', 'week');
+// TODO: 'datetime' and 'datetime-local'
 //       do not accept the @pattern too but are not implemented yet.
 
 for (type of validTypes) {
   input.type = type;
   completeValidityCheck(input, false);
   checkPatternValidity(input);
 }
 
--- a/dom/html/test/forms/test_required_attribute.html
+++ b/dom/html/test/forms/test_required_attribute.html
@@ -359,20 +359,20 @@ for (type of typeBarredFromConstraintVal
 
 // Then, checks for the types which do not use the required attribute.
 var typeRequireNotApply = ['range', 'color', 'submit', 'image'];
 for (type of typeRequireNotApply) {
   checkInputRequiredNotApply(type, false);
 }
 
 // Now, checking for all types which accept the required attribute.
-// TODO: check 'datetime', 'week' and 'datetime-local'
+// TODO: check 'datetime' and 'datetime-local'
 //       when they will be implemented.
 var typeRequireApply = ["text", "password", "search", "tel", "email", "url",
-                        "number", "date", "time", "month"];
+                        "number", "date", "time", "month", "week"];
 
 for (type of typeRequireApply) {
   checkInputRequiredValidity(type);
 }
 
 checkInputRequiredValidityForCheckbox();
 checkInputRequiredValidityForRadio();
 checkInputRequiredValidityForFile();
--- a/dom/html/test/forms/test_step_attribute.html
+++ b/dom/html/test/forms/test_step_attribute.html
@@ -25,17 +25,18 @@ var data = [
   { type: 'search', apply: false },
   { type: 'tel', apply: false },
   { type: 'url', apply: false },
   { type: 'email', apply: false },
   { type: 'password', apply: false },
   { type: 'datetime', apply: true, todo: true },
   { type: 'date', apply: true },
   { type: 'month', apply: true },
-  { type: 'week', apply: true, todo: true },
+  // TODO: temporary set to false until bug 888316 is fixed.
+  { type: 'week', apply: false },
   { type: 'time', apply: true },
   { type: 'datetime-local', apply: true, todo: true },
   { type: 'number', apply: true },
   { type: 'range', apply: true },
   { type: 'color', apply: false },
   { type: 'checkbox', apply: false },
   { type: 'radio', apply: false },
   { type: 'file', apply: false },
@@ -833,16 +834,19 @@ for (var test of data) {
 
       input.value = '1970-01';
       checkValidity(input, false, apply, { low: "1969-12", high: "1970-02" });
 
       input.value = '1970-02';
       checkValidity(input, true, apply);
 
       break;
+    case 'week':
+      // TODO: this is temporary until bug 888316 is fixed.
+      break;
     default:
       ok(false, "Implement the tests for <input type='" + test.type + " >");
       break;
   }
 }
 
 </script>
 </pre>
--- a/dom/html/test/forms/test_valueasdate_attribute.html
+++ b/dom/html/test/forms/test_valueasdate_attribute.html
@@ -41,22 +41,23 @@ var validTypes =
   ["reset", false],
   ["button", false],
   ["number", false],
   ["range", false],
   ["date", true],
   ["time", true],
   ["color", false],
   ["month", true],
+  // TODO: temporary set to false until bug 888316 is fixed.
+  ["week", false],
 ];
 
 var todoTypes =
 [
   ["datetime", true],
-  ["week", true],
   ["datetime-local", true],
 ];
 
 function checkAvailability()
 {
 
   for (data of validTypes) {
     var exceptionCatched = false;
--- a/dom/html/test/forms/test_valueasnumber_attribute.html
+++ b/dom/html/test/forms/test_valueasnumber_attribute.html
@@ -40,22 +40,23 @@ function checkAvailability()
     ["reset", false],
     ["button", false],
     ["number", true],
     ["range", true],
     ["date", true],
     ["time", true],
     ["color", false],
     ["month", true],
+    // TODO: temporary set to false until bug 888316 is fixed.
+    ["week", false],
   ];
 
   var todoList =
   [
     ["datetime", true],
-    ["week", true],
     ["datetime-local", true],
   ];
 
   var element = document.createElement('input');
 
   for (data of testData) {
     var exceptionCatched = false;
     element.type = data[0];
--- a/dom/html/test/test_bug590363.html
+++ b/dom/html/test/test_bug590363.html
@@ -34,22 +34,23 @@ var testData = [
   [ "email",    true ],
   [ "search",   true ],
   [ "password", true ],
   [ "number",   true ],
   [ "date",     true ],
   [ "time",     true ],
   [ "range",    true ],
   [ "color",    true ],
-  [ 'month',    true ]
+  [ 'month',    true ],
+  [ 'week',     true ]
   // 'file' is treated separatly.
 ];
 
 var todoTypes = [
-  "datetime", "week", "datetime-local"
+  "datetime", "datetime-local"
 ];
 
 var nonTrivialSanitizing = [ 'number', 'date', 'time', 'color', 'month' ];
 
 var length = testData.length;
 for (var i=0; i<length; ++i) {
   for (var j=0; j<length; ++j) {
     var e = document.createElement('input');
--- a/dom/html/test/test_bug598643.html
+++ b/dom/html/test/test_bug598643.html
@@ -33,19 +33,19 @@ function testFileControl(aElement)
      "the file control shouldn't suffer from being too long");
 }
 
 var types = [
   // These types can be too long.
   [ "text", "email", "password", "url", "search", "tel" ],
   // These types can't be too long.
   [ "radio", "checkbox", "submit", "button", "reset", "image", "hidden",
-    'number', 'range', 'date', 'time', 'color', 'month' ],
+    'number', 'range', 'date', 'time', 'color', 'month', 'week' ],
   // These types can't be too long but are not implemented yet.
-  [ "datetime", "week", 'datetime-local' ]
+  [ "datetime", 'datetime-local' ]
 ];
 
 var input = document.createElement("input");
 input.maxLength = 1;
 input.value = "foo";
 
 // Too long types.
 for (type of types[0]) {
--- a/dom/indexedDB/IDBFactory.cpp
+++ b/dom/indexedDB/IDBFactory.cpp
@@ -402,19 +402,17 @@ IDBFactory::AllowedForPrincipal(nsIPrinc
     if (aIsSystemPrincipal) {
       *aIsSystemPrincipal = true;
     }
     return true;
   } else if (aIsSystemPrincipal) {
     *aIsSystemPrincipal = false;
   }
 
-  bool isNullPrincipal;
-  if (NS_WARN_IF(NS_FAILED(aPrincipal->GetIsNullPrincipal(&isNullPrincipal))) ||
-      isNullPrincipal) {
+  if (aPrincipal->GetIsNullPrincipal()) {
     return false;
   }
 
   return true;
 }
 
 #ifdef DEBUG
 
--- a/dom/indexedDB/Key.cpp
+++ b/dom/indexedDB/Key.cpp
@@ -29,20 +29,21 @@ namespace mozilla {
 namespace dom {
 namespace indexedDB {
 
 /*
  Here's how we encode keys:
 
  Basic strategy is the following
 
- Numbers: 0x10 n n n n n n n n    ("n"s are encoded 64bit float)
- Dates:   0x20 n n n n n n n n    ("n"s are encoded 64bit float)
- Strings: 0x30 s s s ... 0        ("s"s are encoded unicode bytes)
- Arrays:  0x50 i i i ... 0        ("i"s are encoded array items)
+ Numbers:  0x10 n n n n n n n n    ("n"s are encoded 64bit float)
+ Dates:    0x20 n n n n n n n n    ("n"s are encoded 64bit float)
+ Strings:  0x30 s s s ... 0        ("s"s are encoded unicode bytes)
+ Binaries: 0x40 s s s ... 0        ("s"s are encoded unicode bytes)
+ Arrays:   0x50 i i i ... 0        ("i"s are encoded array items)
 
 
  When encoding floats, 64bit IEEE 754 are almost sortable, except that
  positive sort lower than negative, and negative sort descending. So we use
  the following encoding:
  
  value < 0 ?
    (-to64bitInt(value)) :
@@ -55,16 +56,19 @@ namespace indexedDB {
  Chars 7F        - (3FFF+7F)    are encoded as 10xxxxxx xxxxxxxx with 7F subtracted
  Chars (3FFF+80) - FFFF         are encoded as 11xxxxxx xxxxxxxx xx000000
 
  This ensures that the first byte is never encoded as 0, which means that the
  string terminator (per basic-stategy table) sorts before any character.
  The reason that (3FFF+80) - FFFF is encoded "shifted up" 6 bits is to maximize
  the chance that the last character is 0. See below for why.
 
+ When encoding binaries, the algorithm is the same to how strings are encoded.
+ Since each octet in binary is in the range of [0-255], it'll take 1 to 2 encoded
+ unicode bytes.
 
  When encoding Arrays, we use an additional trick. Rather than adding a byte
  containing the value 0x50 to indicate type, we instead add 0x50 to the next byte.
  This is usually the byte containing the type of the first item in the array.
  So simple examples are
 
  ["foo"]      0x80 s s s 0 0                              // 0x80 is 0x30 + 0x50
  [1, 2]       0x60 n n n n n n n n 1 n n n n n n n n 0    // 0x60 is 0x10 + 0x50
@@ -107,17 +111,17 @@ namespace indexedDB {
 nsresult
 Key::ToLocaleBasedKey(Key& aTarget, const nsCString& aLocale) const
 {
   if (IsUnset()) {
     aTarget.Unset();
     return NS_OK;
   }
 
-  if (IsFloat() || IsDate()) {
+  if (IsFloat() || IsDate() || IsBinary()) {
     aTarget.mBuffer = mBuffer;
     return NS_OK;
   }
 
   aTarget.mBuffer.Truncate();
   aTarget.mBuffer.SetCapacity(mBuffer.Length());
 
   auto* it = reinterpret_cast<const unsigned char*>(mBuffer.BeginReading());
@@ -287,16 +291,26 @@ Key::EncodeJSValInternal(JSContext* aCx,
       double t;
       if (!js::DateGetMsecSinceEpoch(aCx, obj, &t)) {
         IDB_REPORT_INTERNAL_ERR();
         return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
       }
       EncodeNumber(t, eDate + aTypeOffset);
       return NS_OK;
     }
+
+    if (JS_IsArrayBufferObject(obj)) {
+      EncodeBinary(obj, /* aIsViewObject */ false, aTypeOffset);
+      return NS_OK;
+    }
+
+    if (JS_IsArrayBufferViewObject(obj)) {
+      EncodeBinary(obj, /* aIsViewObject */ true, aTypeOffset);
+      return NS_OK;
+    }
   }
 
   return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
 }
 
 // static
 nsresult
 Key::DecodeJSValInternal(const unsigned char*& aPos, const unsigned char* aEnd,
@@ -364,16 +378,25 @@ Key::DecodeJSValInternal(const unsigned 
       return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
     }
 
     aVal.setObject(*date);
   }
   else if (*aPos - aTypeOffset == eFloat) {
     aVal.setDouble(DecodeNumber(aPos, aEnd));
   }
+  else if (*aPos - aTypeOffset == eBinary) {
+    JSObject* binary = DecodeBinary(aPos, aEnd, aCx);
+    if (!binary) {
+      IDB_REPORT_INTERNAL_ERR();
+      return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
+    }
+
+    aVal.setObject(*binary);
+  }
   else {
     NS_NOTREACHED("Unknown key type!");
   }
 
   return NS_OK;
 }
 
 #define ONE_BYTE_LIMIT 0x7E
@@ -398,16 +421,23 @@ Key::EncodeString(const nsAString& aStri
   const char16_t* end = aString.EndReading();
   EncodeString(start, end, aTypeOffset);
 }
 
 template <typename T>
 void
 Key::EncodeString(const T* aStart, const T* aEnd, uint8_t aTypeOffset)
 {
+  EncodeAsString(aStart, aEnd, eString + aTypeOffset);
+}
+
+template <typename T>
+void
+Key::EncodeAsString(const T* aStart, const T* aEnd, uint8_t aType)
+{
   // First measure how long the encoded string will be.
 
   // The +2 is for initial 3 and trailing 0. We'll compensate for multi-byte
   // chars below.
   uint32_t size = (aEnd - aStart) + 2;
   
   const T* start = aStart;
   const T* end = aEnd;
@@ -421,17 +451,17 @@ Key::EncodeString(const T* aStart, const
   uint32_t oldLen = mBuffer.Length();
   char* buffer;
   if (!mBuffer.GetMutableData(&buffer, oldLen + size)) {
     return;
   }
   buffer += oldLen;
 
   // Write type marker
-  *(buffer++) = eString + aTypeOffset;
+  *(buffer++) = aType;
 
   // Encode string
   for (const T* iter = start; iter < end; ++iter) {
     if (*iter <= ONE_BYTE_LIMIT) {
       *(buffer++) = *iter + ONE_BYTE_ADJUST;
     }
     else if (char16_t(*iter) <= TWO_BYTE_LIMIT) {
       char16_t c = char16_t(*iter) + TWO_BYTE_ADJUST + 0x8000;
@@ -613,16 +643,92 @@ Key::DecodeNumber(const unsigned char*& 
   // MSVC build warning C4146 (negating an unsigned value).
   pun.u = number & PR_UINT64(0x8000000000000000) ?
           (number & ~PR_UINT64(0x8000000000000000)) :
           (0 - number);
 
   return pun.d;
 }
 
+void
+Key::EncodeBinary(JSObject* aObject, bool aIsViewObject, uint8_t aTypeOffset)
+{
+  uint8_t* bufferData;
+  uint32_t bufferLength;
+  bool unused;
+
+  if (aIsViewObject) {
+    js::GetArrayBufferViewLengthAndData(aObject, &bufferLength, &unused, &bufferData);
+  } else {
+    js::GetArrayBufferLengthAndData(aObject, &bufferLength, &unused, &bufferData);
+  }
+
+  EncodeAsString(bufferData, bufferData + bufferLength, eBinary + aTypeOffset);
+}
+
+// static
+JSObject*
+Key::DecodeBinary(const unsigned char*& aPos,
+                  const unsigned char* aEnd,
+                  JSContext* aCx)
+{
+  MOZ_ASSERT(*aPos % eMaxType == eBinary, "Don't call me!");
+
+  const unsigned char* buffer = ++aPos;
+
+  // First measure how big the decoded array buffer will be.
+  size_t size = 0;
+  const unsigned char* iter;
+  for (iter = buffer; iter < aEnd && *iter != eTerminator; ++iter) {
+    if (*iter & 0x80) {
+      iter++;
+    }
+    ++size;
+  }
+
+  if (!size) {
+    return JS_NewArrayBuffer(aCx, 0);
+  }
+
+  uint8_t* out = static_cast<uint8_t*>(JS_malloc(aCx, size));
+  if (NS_WARN_IF(!out)) {
+    return nullptr;
+  }
+
+  uint8_t* pos = out;
+
+  // Set end so that we don't have to check for null termination in the loop
+  // below
+  if (iter < aEnd) {
+    aEnd = iter;
+  }
+
+  for (iter = buffer; iter < aEnd;) {
+    if (!(*iter & 0x80)) {
+      *pos = *(iter++) - ONE_BYTE_ADJUST;
+    }
+    else {
+      uint16_t c = (uint16_t(*(iter++)) << 8);
+      if (iter < aEnd) {
+        c |= *(iter++);
+      }
+      *pos = static_cast<uint8_t>(c - TWO_BYTE_ADJUST - 0x8000);
+    }
+
+    ++pos;
+  }
+
+  aPos = iter + 1;
+
+  MOZ_ASSERT(static_cast<size_t>(pos - out) == size,
+             "Should have written the whole buffer");
+
+  return JS_NewArrayBufferWithContents(aCx, size, out);
+}
+
 nsresult
 Key::BindToStatement(mozIStorageStatement* aStatement,
                      const nsACString& aParamName) const
 {
   nsresult rv;
   if (IsUnset()) {
     rv = aStatement->BindNullByName(aParamName);
   } else {
--- a/dom/indexedDB/Key.h
+++ b/dom/indexedDB/Key.h
@@ -30,16 +30,17 @@ class Key
   nsCString mBuffer;
 
 public:
   enum {
     eTerminator = 0,
     eFloat = 0x10,
     eDate = 0x20,
     eString = 0x30,
+    eBinary = 0x40,
     eArray = 0x50,
     eMaxType = eArray
   };
 
   static const uint8_t kMaxArrayCollapse = uint8_t(3);
   static const uint8_t kMaxRecursionDepth = uint8_t(64);
 
   Key()
@@ -140,16 +141,22 @@ public:
 
   bool
   IsString() const
   {
     return !IsUnset() && *BufferStart() == eString;
   }
 
   bool
+  IsBinary() const
+  {
+    return !IsUnset() && *BufferStart() == eBinary;
+  }
+
+  bool
   IsArray() const
   {
     return !IsUnset() && *BufferStart() >= eArray;
   }
 
   double
   ToFloat() const
   {
@@ -282,41 +289,53 @@ private:
 
   void
   EncodeString(const nsAString& aString, uint8_t aTypeOffset);
 
   template <typename T>
   void
   EncodeString(const T* aStart, const T* aEnd, uint8_t aTypeOffset);
 
+  template <typename T>
+  void
+  EncodeAsString(const T* aStart, const T* aEnd, uint8_t aType);
+
 #ifdef ENABLE_INTL_API
   nsresult
   EncodeLocaleString(const nsDependentString& aString, uint8_t aTypeOffset,
                      const nsCString& aLocale);
 #endif
 
   void
   EncodeNumber(double aFloat, uint8_t aType);
 
+  void
+  EncodeBinary(JSObject* aObject, bool aIsViewObject, uint8_t aTypeOffset);
+
   // Decoding functions. aPos points into mBuffer and is adjusted to point
   // past the consumed value.
   static nsresult
   DecodeJSVal(const unsigned char*& aPos,
               const unsigned char* aEnd,
               JSContext* aCx,
               JS::MutableHandle<JS::Value> aVal);
 
   static void
   DecodeString(const unsigned char*& aPos,
                const unsigned char* aEnd,
                nsString& aString);
 
   static double
   DecodeNumber(const unsigned char*& aPos, const unsigned char* aEnd);
 
+  static JSObject*
+  DecodeBinary(const unsigned char*& aPos,
+               const unsigned char* aEnd,
+               JSContext* aCx);
+
   nsresult
   EncodeJSValInternal(JSContext* aCx,
                       JS::Handle<JS::Value> aVal,
                       uint8_t aTypeOffset,
                       uint16_t aRecursionDepth);
 
   static nsresult
   DecodeJSValInternal(const unsigned char*& aPos,
--- a/dom/indexedDB/ProfilerHelpers.h
+++ b/dom/indexedDB/ProfilerHelpers.h
@@ -196,16 +196,18 @@ public:
     } else if (aKey.IsFloat()) {
       AppendPrintf("%g", aKey.ToFloat());
     } else if (aKey.IsDate()) {
       AppendPrintf("<Date %g>", aKey.ToDateMsec());
     } else if (aKey.IsString()) {
       nsAutoString str;
       aKey.ToString(str);
       AppendPrintf("\"%s\"", NS_ConvertUTF16toUTF8(str).get());
+    } else if (aKey.IsBinary()) {
+      AssignLiteral("[object ArrayBuffer]");
     } else {
       MOZ_ASSERT(aKey.IsArray());
       AssignLiteral("[...]");
     }
   }
 
   explicit
   LoggingString(const IDBCursor::Direction aDirection)
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -1126,19 +1126,17 @@ ContentParent::CreateBrowserOrApp(const 
       }
       uint32_t chromeFlags = 0;
       wbc->GetChromeFlags(&chromeFlags);
 
       nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(docShell);
       if (loadContext && loadContext->UsePrivateBrowsing()) {
         chromeFlags |= nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW;
       }
-      bool affectLifetime;
-      docShell->GetAffectPrivateSessionLifetime(&affectLifetime);
-      if (affectLifetime) {
+      if (docShell->GetAffectPrivateSessionLifetime()) {
         chromeFlags |= nsIWebBrowserChrome::CHROME_PRIVATE_LIFETIME;
       }
 
       if (tabId == 0) {
         return nullptr;
       }
       RefPtr<TabParent> tp(new TabParent(constructorSender, tabId,
                                          aContext, chromeFlags));
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -1483,19 +1483,17 @@ TabChild::ApplyShowInfo(const ShowInfo& 
       // shouldn't trust it for <xul:browser> elements.
       item->SetName(aInfo.name());
     }
     docShell->SetFullscreenAllowed(aInfo.fullscreenAllowed());
     if (aInfo.isPrivate()) {
       nsCOMPtr<nsILoadContext> context = do_GetInterface(docShell);
       // No need to re-set private browsing mode.
       if (!context->UsePrivateBrowsing()) {
-        bool nonBlank;
-        docShell->GetHasLoadedNonBlankURI(&nonBlank);
-        if (nonBlank) {
+        if (docShell->GetHasLoadedNonBlankURI()) {
           nsContentUtils::ReportToConsoleNonLocalized(
             NS_LITERAL_STRING("We should not switch to Private Browsing after loading a document."),
             nsIScriptError::warningFlag,
             NS_LITERAL_CSTRING("mozprivatebrowsing"),
             nullptr);
         } else {
           DocShellOriginAttributes attrs(nsDocShell::Cast(docShell)->GetOriginAttributes());
           attrs.SyncAttributesWithPrivateBrowsing(true);
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -470,19 +470,17 @@ TabParent::GetAppType(nsAString& aOut)
 bool
 TabParent::IsVisible() const
 {
   RefPtr<nsFrameLoader> frameLoader = GetFrameLoader();
   if (!frameLoader) {
     return false;
   }
 
-  bool visible = false;
-  frameLoader->GetVisible(&visible);
-  return visible;
+  return frameLoader->GetVisible();
 }
 
 void
 TabParent::DestroyInternal()
 {
   IMEStateManager::OnTabParentDestroying(this);
 
   RemoveWindowListeners();
--- a/dom/media/MediaManager.cpp
+++ b/dom/media/MediaManager.cpp
@@ -1920,21 +1920,19 @@ MediaManager::NotifyRecordingStatusChang
   RefPtr<nsHashPropertyBag> props = new nsHashPropertyBag();
   props->SetPropertyAsBool(NS_LITERAL_STRING("isAudio"), aIsAudio);
   props->SetPropertyAsBool(NS_LITERAL_STRING("isVideo"), aIsVideo);
 
   bool isApp = false;
   nsString requestURL;
 
   if (nsCOMPtr<nsIDocShell> docShell = aWindow->GetDocShell()) {
-    nsresult rv = docShell->GetIsApp(&isApp);
-    NS_ENSURE_SUCCESS(rv, rv);
-
+    isApp = docShell->GetIsApp();
     if (isApp) {
-      rv = docShell->GetAppManifestURL(requestURL);
+      nsresult rv = docShell->GetAppManifestURL(requestURL);
       NS_ENSURE_SUCCESS(rv, rv);
     }
   }
 
   if (!isApp) {
     nsCString pageURL;
     nsCOMPtr<nsIURI> docURI = aWindow->GetDocumentURI();
     NS_ENSURE_TRUE(docURI, NS_ERROR_FAILURE);
--- a/dom/media/MediaRecorder.cpp
+++ b/dom/media/MediaRecorder.cpp
@@ -714,21 +714,19 @@ private:
       return false;
     }
 
     nsCOMPtr<nsIDocument> doc = mRecorder->GetOwner()->GetExtantDoc();
     if (!doc) {
       return false;
     }
 
-    uint16_t appStatus = nsIPrincipal::APP_STATUS_NOT_INSTALLED;
-    doc->NodePrincipal()->GetAppStatus(&appStatus);
-
     // Certified applications can always assign AUDIO_3GPP
-    if (appStatus == nsIPrincipal::APP_STATUS_CERTIFIED) {
+    if (doc->NodePrincipal()->GetAppStatus() ==
+        nsIPrincipal::APP_STATUS_CERTIFIED) {
       return true;
     }
 
     nsCOMPtr<nsIPermissionManager> pm =
        do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
 
     if (!pm) {
       return false;
--- a/dom/media/test/test_streams_element_capture_createObjectURL.html
+++ b/dom/media/test/test_streams_element_capture_createObjectURL.html
@@ -29,39 +29,43 @@ function isGreaterThanOrEqualEps(a, b, m
 function startTest(test, token) {
   manager.started(token);
 
   var v = document.createElement('video');
   var vout = document.createElement('video');
   vout.token = token;
 
   v.src = test.name;
-  var stream = v.mozCaptureStreamUntilEnded();
-  is(stream.currentTime, 0, test.name + " stream initial currentTime");
-  vout.src = URL.createObjectURL(stream);
+  v.preload = "metadata"
+  var stream;
 
-  var checkEnded = function(test, vout, stream) { return function() {
+  var checkEnded = function() {
     is(stream.currentTime, vout.currentTime, test.name + " stream final currentTime");
     if (test.duration) {
       isGreaterThanOrEqualEps(vout.currentTime, test.duration,
          test.name + " current time at end");
     }
     is(vout.readyState, vout.HAVE_CURRENT_DATA, test.name + " checking readyState");
     ok(vout.ended, test.name + " checking playback has ended");
     if (test.type.match(/^video/)) {
       checkDrawImage(vout);
     }
     vout.parentNode.removeChild(vout);
     URL.revokeObjectURL(vout.src);
     manager.finished(vout.token);
-  }}(test, vout, stream);
+  };
   vout.addEventListener("ended", checkEnded, false);
 
   document.body.appendChild(vout);
-  v.play();
-  vout.play();
+  v.onloadedmetadata = function () {
+    stream = v.mozCaptureStreamUntilEnded();
+    is(stream.currentTime, 0, test.name + " stream initial currentTime");
+    vout.src = URL.createObjectURL(stream);
+    v.play();
+    vout.play();
+  };
 }
 
 manager.runTests([getPlayableVideo(gSmallTests)], startTest);
 </script>
 </pre>
 </body>
 </html>
--- a/dom/media/wave/WaveDemuxer.cpp
+++ b/dom/media/wave/WaveDemuxer.cpp
@@ -108,18 +108,16 @@ WAVTrackDemuxer::Init()
   while (true) {
     if (!HeaderParserInit()) {
       return false;
     }
 
     uint32_t aChunkName = mHeaderParser.GiveHeader().ChunkName();
     uint32_t aChunkSize = mHeaderParser.GiveHeader().ChunkSize();
 
-    aChunkSize += aChunkSize % 2;
-
     if (aChunkName == FRMT_CODE) {
       if (!FmtChunkParserInit()) {
         return false;
       }
     } else if (aChunkName == LIST_CODE) {
       mHeaderParser.Reset();
       uint64_t endOfListChunk = static_cast<uint64_t>(mOffset) + aChunkSize;
       if (endOfListChunk > UINT32_MAX) {
@@ -130,17 +128,18 @@ WAVTrackDemuxer::Init()
       }
     } else if (aChunkName == DATA_CODE) {
       mDataLength = aChunkSize;
       if (mFirstChunkOffset != mOffset) {
         mFirstChunkOffset = mOffset;
       }
       break;
     } else {
-      mOffset += aChunkSize; // Skip other irrelevant chunks.
+      // Wave files are 2-byte aligned so we need to round up
+      mOffset += (aChunkSize + 1) & ~1; // Skip other irrelevant chunks.
     }
     mHeaderParser.Reset();
   }
 
   if (mDataLength > StreamLength() - mFirstChunkOffset) {
     mDataLength = StreamLength() - mFirstChunkOffset;
   }
 
--- a/dom/network/UDPSocketParent.cpp
+++ b/dom/network/UDPSocketParent.cpp
@@ -74,21 +74,18 @@ UDPSocketParent::OfflineNotification(nsI
   }
 
   return NS_OK;
 }
 
 uint32_t
 UDPSocketParent::GetAppId()
 {
-  uint32_t appId;
-  if (!mPrincipal || NS_FAILED(mPrincipal->GetAppId(&appId))) {
-    return nsIScriptSecurityManager::UNKNOWN_APP_ID;
-  }
-  return appId;
+  return mPrincipal ? mPrincipal->GetAppId()
+                    : nsIScriptSecurityManager::UNKNOWN_APP_ID;
 }
 
 bool
 UDPSocketParent::Init(const IPC::Principal& aPrincipal,
                       const nsACString& aFilter)
 {
   MOZ_ASSERT_IF(mBackgroundManager, !aPrincipal);
   // will be used once we move all UDPSocket to PBackground, or
--- a/dom/permission/tests/file_framework.js
+++ b/dom/permission/tests/file_framework.js
@@ -2,17 +2,17 @@
 /*
  * gData is an array of object that tests using this framework must pass in
  * The current tests only pass in a single element array. Each test in
  * gData is executed by the framework for a given file
  *
  * Fields in gData object
  * perms   (required) Array of Strings
  *         list of permissions that this test will need. See
- *         http://mxr.mozilla.org/mozilla-central/source/dom/apps/src/PermissionsTable.jsm
+ *         http://dxr.mozilla.org/mozilla-central/source/dom/apps/src/PermissionsTable.jsm
  *         These permissions are added after a sanity check and removed at
  *         test conclusion
  *
  * obj     (required for default verifier) String
  *         The name of the window.navigator object used for accessing the
  *         WebAPI during the tests
  *
  * webidl  (required for default verifier) String
--- a/dom/push/Push.js
+++ b/dom/push/Push.js
@@ -237,22 +237,24 @@ PushSubscriptionCallback.prototype = {
       options.appServerKey = appServerKey;
     }
     let sub = new pushManager._window.PushSubscription(options);
     this.resolve(sub);
   },
 
   _getKey: function(subscription, name) {
     let outKeyLen = {};
-    let rawKey = subscription.getKey(name, outKeyLen);
+    let rawKey = Cu.cloneInto(subscription.getKey(name, outKeyLen),
+                              this.pushManager._window);
     if (!outKeyLen.value) {
       return null;
     }
-    let key = new ArrayBuffer(outKeyLen.value);
-    let keyView = new Uint8Array(key);
+
+    let key = new this.pushManager._window.ArrayBuffer(outKeyLen.value);
+    let keyView = new this.pushManager._window.Uint8Array(key);
     keyView.set(rawKey);
     return key;
   },
 
   _rejectWithError: function(result) {
     let error;
     switch (result) {
       case Cr.NS_ERROR_DOM_PUSH_INVALID_KEY_ERR:
--- a/dom/quota/ActorsParent.cpp
+++ b/dom/quota/ActorsParent.cpp
@@ -4650,27 +4650,24 @@ QuotaManager::GetInfoFromPrincipal(nsIPr
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aPrincipal);
 
   if (nsContentUtils::IsSystemPrincipal(aPrincipal)) {
     GetInfoForChrome(aSuffix, aGroup, aOrigin, aIsApp);
     return NS_OK;
   }
 
-  bool isNullPrincipal;
-  nsresult rv = aPrincipal->GetIsNullPrincipal(&isNullPrincipal);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  if (isNullPrincipal) {
+
+  if (aPrincipal->GetIsNullPrincipal()) {
     NS_WARNING("IndexedDB not supported from this principal!");
     return NS_ERROR_FAILURE;
   }
 
   nsCString origin;
-  rv = aPrincipal->GetOrigin(origin);
+  nsresult rv = aPrincipal->GetOrigin(origin);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (origin.EqualsLiteral(kChromeOrigin)) {
     NS_WARNING("Non-chrome principal can't use chrome origin!");
     return NS_ERROR_FAILURE;
   }
 
   nsCString suffix;
--- a/dom/security/nsContentSecurityManager.cpp
+++ b/dom/security/nsContentSecurityManager.cpp
@@ -425,34 +425,32 @@ nsContentSecurityManager::doContentSecur
   nsresult rv = ValidateSecurityFlags(loadInfo);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // since aChannel was openend using asyncOpen2() we have to make sure
   // that redirects of that channel also get openend using asyncOpen2()
   // please note that some implementations of ::AsyncOpen2 might already
   // have set that flag to true (e.g. nsViewSourceChannel) in which case
   // we just set the flag again.
-  rv = loadInfo->SetEnforceSecurity(true);
-  NS_ENSURE_SUCCESS(rv, rv);
+  loadInfo->SetEnforceSecurity(true);
 
   if (loadInfo->GetSecurityMode() == nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS) {
     rv = DoCORSChecks(aChannel, loadInfo, aInAndOutListener);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   rv = CheckChannel(aChannel);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Perform all ContentPolicy checks (MixedContent, CSP, ...)
   rv = DoContentSecurityChecks(aChannel, loadInfo);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // now lets set the initalSecurityFlag for subsequent calls
-  rv = loadInfo->SetInitialSecurityCheckDone(true);
-  NS_ENSURE_SUCCESS(rv, rv);
+  loadInfo->SetInitialSecurityCheckDone(true);
 
   // all security checks passed - lets allow the load
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsContentSecurityManager::AsyncOnChannelRedirect(nsIChannel* aOldChannel,
                                                  nsIChannel* aNewChannel,
--- a/dom/smil/nsSMILAnimationController.cpp
+++ b/dom/smil/nsSMILAnimationController.cpp
@@ -688,17 +688,17 @@ nsSMILAnimationController::GetTargetIden
   if (attributeType == eSMILTargetAttrType_auto) {
     if (attributeNamespaceID == kNameSpaceID_None) {
       // width/height are special as they may be attributes or for
       // outer-<svg> elements, mapped into style.
       if (attributeName == nsGkAtoms::width ||
           attributeName == nsGkAtoms::height) {
         isCSS = targetElem->GetNameSpaceID() != kNameSpaceID_SVG;
       } else {
-        nsCSSProperty prop =
+        nsCSSPropertyID prop =
           nsCSSProps::LookupProperty(nsDependentAtomString(attributeName),
                                      CSSEnabledState::eForAllContent);
         isCSS = nsSMILCSSProperty::IsPropertyAnimatable(prop);
       }
     }
   } else {
     isCSS = (attributeType == eSMILTargetAttrType_CSS);
   }
--- a/dom/smil/nsSMILCSSProperty.cpp
+++ b/dom/smil/nsSMILCSSProperty.cpp
@@ -17,17 +17,17 @@
 #include "nsIDOMElement.h"
 #include "nsIDocument.h"
 
 using namespace mozilla::dom;
 
 // Helper function
 static bool
 GetCSSComputedValue(Element* aElem,
-                    nsCSSProperty aPropID,
+                    nsCSSPropertyID aPropID,
                     nsAString& aResult)
 {
   MOZ_ASSERT(!nsCSSProps::IsShorthand(aPropID),
              "Can't look up computed value of shorthand property");
   MOZ_ASSERT(nsSMILCSSProperty::IsPropertyAnimatable(aPropID),
              "Shouldn't get here for non-animatable properties");
 
   nsIDocument* doc = aElem->GetUncomposedDoc();
@@ -47,17 +47,17 @@ GetCSSComputedValue(Element* aElem,
   RefPtr<nsComputedDOMStyle> computedStyle =
     NS_NewComputedDOMStyle(aElem, EmptyString(), shell);
 
   computedStyle->GetPropertyValue(aPropID, aResult);
   return true;
 }
 
 // Class Methods
-nsSMILCSSProperty::nsSMILCSSProperty(nsCSSProperty aPropID,
+nsSMILCSSProperty::nsSMILCSSProperty(nsCSSPropertyID aPropID,
                                      Element* aElement)
   : mPropID(aPropID), mElement(aElement)
 {
   MOZ_ASSERT(IsPropertyAnimatable(mPropID),
              "Creating a nsSMILCSSProperty for a property "
              "that's not supported for animation");
 }
 
@@ -181,17 +181,17 @@ nsSMILCSSProperty::ClearAnimValue()
   if (overrideDecl) {
     overrideDecl->SetPropertyValue(mPropID, EmptyString());
   }
 }
 
 // Based on http://www.w3.org/TR/SVG/propidx.html
 // static
 bool
-nsSMILCSSProperty::IsPropertyAnimatable(nsCSSProperty aPropID)
+nsSMILCSSProperty::IsPropertyAnimatable(nsCSSPropertyID aPropID)
 {
   // NOTE: Right now, Gecko doesn't recognize the following properties from
   // the SVG Property Index:
   //   alignment-baseline
   //   baseline-shift
   //   color-profile
   //   color-rendering
   //   glyph-orientation-horizontal
--- a/dom/smil/nsSMILCSSProperty.h
+++ b/dom/smil/nsSMILCSSProperty.h
@@ -7,17 +7,17 @@
 /* representation of a SMIL-animatable CSS property on an element */
 
 #ifndef NS_SMILCSSPROPERTY_H_
 #define NS_SMILCSSPROPERTY_H_
 
 #include "mozilla/Attributes.h"
 #include "nsISMILAttr.h"
 #include "nsIAtom.h"
-#include "nsCSSProperty.h"
+#include "nsCSSPropertyID.h"
 #include "nsCSSValue.h"
 
 namespace mozilla {
 namespace dom {
 class Element;
 } // namespace dom
 } // namespace mozilla
 
@@ -29,17 +29,17 @@ class Element;
 class nsSMILCSSProperty : public nsISMILAttr
 {
 public:
   /**
    * Constructs a new nsSMILCSSProperty.
    * @param  aPropID   The CSS property we're interested in animating.
    * @param  aElement  The element whose CSS property is being animated.
    */
-  nsSMILCSSProperty(nsCSSProperty aPropID, mozilla::dom::Element* aElement);
+  nsSMILCSSProperty(nsCSSPropertyID aPropID, mozilla::dom::Element* aElement);
 
   // nsISMILAttr methods
   virtual nsresult ValueFromString(const nsAString& aStr,
                                    const mozilla::dom::SVGAnimationElement* aSrcElement,
                                    nsSMILValue& aValue,
                                    bool& aPreventCachingOfSandwich) const override;
   virtual nsSMILValue GetBaseValue() const override;
   virtual nsresult    SetAnimValue(const nsSMILValue& aValue) override;
@@ -48,20 +48,20 @@ public:
   /**
    * Utility method - returns true if the given property is supported for
    * SMIL animation.
    *
    * @param   aProperty  The property to check for animation support.
    * @return  true if the given property is supported for SMIL animation, or
    *          false otherwise
    */
-  static bool IsPropertyAnimatable(nsCSSProperty aPropID);
+  static bool IsPropertyAnimatable(nsCSSPropertyID aPropID);
 
 protected:
-  nsCSSProperty mPropID;
+  nsCSSPropertyID mPropID;
   // Using non-refcounted pointer for mElement -- we know mElement will stay
   // alive for my lifetime because a nsISMILAttr (like me) only lives as long
   // as the Compositing step, and DOM elements don't get a chance to die during
   // that time.
   mozilla::dom::Element*   mElement;
 };
 
 #endif // NS_SMILCSSPROPERTY_H_
--- a/dom/smil/nsSMILCSSValueType.cpp
+++ b/dom/smil/nsSMILCSSValueType.cpp
@@ -20,20 +20,20 @@
 #include "nsIDocument.h"
 
 using namespace mozilla::dom;
 using mozilla::StyleAnimationValue;
 
 /*static*/ nsSMILCSSValueType nsSMILCSSValueType::sSingleton;
 
 struct ValueWrapper {
-  ValueWrapper(nsCSSProperty aPropID, const StyleAnimationValue& aValue) :
+  ValueWrapper(nsCSSPropertyID aPropID, const StyleAnimationValue& aValue) :
     mPropID(aPropID), mCSSValue(aValue) {}
 
-  nsCSSProperty mPropID;
+  nsCSSPropertyID mPropID;
   StyleAnimationValue mCSSValue;
 };
 
 // Helper Methods
 // --------------
 static const StyleAnimationValue*
 GetZeroValueForUnit(StyleAnimationValue::Unit aUnit)
 {
@@ -218,17 +218,17 @@ nsSMILCSSValueType::Add(nsSMILValue& aDe
              "Trying to add invalid types");
   MOZ_ASSERT(aValueToAdd.mType == this, "Unexpected source type");
 
   ValueWrapper* destWrapper = ExtractValueWrapper(aDest);
   const ValueWrapper* valueToAddWrapper = ExtractValueWrapper(aValueToAdd);
   MOZ_ASSERT(destWrapper || valueToAddWrapper,
              "need at least one fully-initialized value");
 
-  nsCSSProperty property = (valueToAddWrapper ? valueToAddWrapper->mPropID :
+  nsCSSPropertyID property = (valueToAddWrapper ? valueToAddWrapper->mPropID :
                             destWrapper->mPropID);
   // Special case: font-size-adjust and stroke-dasharray are explicitly
   // non-additive (even though StyleAnimationValue *could* support adding them)
   if (property == eCSSProperty_font_size_adjust ||
       property == eCSSProperty_stroke_dasharray) {
     return NS_ERROR_FAILURE;
   }
 
@@ -330,17 +330,17 @@ GetPresContextForElement(Element* aElem)
     return nullptr;
   }
   nsIPresShell* shell = doc->GetShell();
   return shell ? shell->GetPresContext() : nullptr;
 }
 
 // Helper function to parse a string into a StyleAnimationValue
 static bool
-ValueFromStringHelper(nsCSSProperty aPropID,
+ValueFromStringHelper(nsCSSPropertyID aPropID,
                       Element* aTargetElement,
                       nsPresContext* aPresContext,
                       const nsAString& aString,
                       StyleAnimationValue& aStyleAnimValue,
                       bool* aIsContextSensitive)
 {
   // If value is negative, we'll strip off the "-" so the CSS parser won't
   // barf, and then manually make the parsed value negative.
@@ -382,17 +382,17 @@ ValueFromStringHelper(nsCSSProperty aPro
     aStyleAnimValue.SetCoordValue(aStyleAnimValue.GetCoordValue() /
                                   aPresContext->TextZoom());
   }
   return true;
 }
 
 // static
 void
-nsSMILCSSValueType::ValueFromString(nsCSSProperty aPropID,
+nsSMILCSSValueType::ValueFromString(nsCSSPropertyID aPropID,
                                     Element* aTargetElement,
                                     const nsAString& aString,
                                     nsSMILValue& aValue,
                                     bool* aIsContextSensitive)
 {
   MOZ_ASSERT(aValue.IsNull(), "Outparam should be null-typed");
   nsPresContext* presContext = GetPresContextForElement(aTargetElement);
   if (!presContext) {
@@ -425,17 +425,17 @@ nsSMILCSSValueType::ValueToString(const 
              "Unexpected SMIL value type");
   const ValueWrapper* wrapper = ExtractValueWrapper(aValue);
   return !wrapper ||
     StyleAnimationValue::UncomputeValue(wrapper->mPropID,
                                         wrapper->mCSSValue, aString);
 }
 
 // static
-nsCSSProperty
+nsCSSPropertyID
 nsSMILCSSValueType::PropertyFromValue(const nsSMILValue& aValue)
 {
   if (aValue.mType != &nsSMILCSSValueType::sSingleton) {
     return eCSSProperty_UNKNOWN;
   }
 
   const ValueWrapper* wrapper = ExtractValueWrapper(aValue);
   if (!wrapper) {
--- a/dom/smil/nsSMILCSSValueType.h
+++ b/dom/smil/nsSMILCSSValueType.h
@@ -5,17 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /* representation of a value for a SMIL-animated CSS property */
 
 #ifndef NS_SMILCSSVALUETYPE_H_
 #define NS_SMILCSSVALUETYPE_H_
 
 #include "nsISMILType.h"
-#include "nsCSSProperty.h"
+#include "nsCSSPropertyID.h"
 #include "mozilla/Attributes.h"
 
 class nsAString;
 
 namespace mozilla {
 namespace dom {
 class Element;
 } // namespace dom
@@ -73,17 +73,17 @@ public:
    *                                  a different |aValue| depending on other
    *                                  CSS properties on |aTargetElement|
    *                                  or its ancestors (e.g. 'inherit).
    *                                  false otherwise. May be nullptr.
    *                                  Not set if the method fails.
    * @pre  aValue.IsNull()
    * @post aValue.IsNull() || aValue.mType == nsSMILCSSValueType::sSingleton
    */
-  static void ValueFromString(nsCSSProperty aPropID,
+  static void ValueFromString(nsCSSPropertyID aPropID,
                               Element* aTargetElement,
                               const nsAString& aString,
                               nsSMILValue& aValue,
                               bool* aIsContextSensitive);
 
   /**
    * Creates a string representation of the given nsSMILValue.
    *
@@ -97,20 +97,20 @@ public:
    * @return               true on success, false on failure.
    */
   static bool ValueToString(const nsSMILValue& aValue, nsAString& aString);
 
   /**
    * Return the CSS property animated by the specified value.
    *
    * @param   aValue   The nsSMILValue to examine.
-   * @return           The nsCSSProperty enum value of the property animated
+   * @return           The nsCSSPropertyID enum value of the property animated
    *                   by |aValue|, or eCSSProperty_UNKNOWN if the type of
    *                   |aValue| is not nsSMILCSSValueType.
    */
-  static nsCSSProperty PropertyFromValue(const nsSMILValue& aValue);
+  static nsCSSPropertyID PropertyFromValue(const nsSMILValue& aValue);
 
 private:
   // Private constructor: prevent instances beyond my singleton.
   constexpr nsSMILCSSValueType() {}
 };
 
 #endif // NS_SMILCSSVALUETYPE_H_
--- a/dom/smil/nsSMILCompositor.cpp
+++ b/dom/smil/nsSMILCompositor.cpp
@@ -122,17 +122,17 @@ nsSMILCompositor::ClearAnimationEffects(
 }
 
 // Protected Helper Functions
 // --------------------------
 nsISMILAttr*
 nsSMILCompositor::CreateSMILAttr()
 {
   if (mKey.mIsCSS) {
-    nsCSSProperty propId =
+    nsCSSPropertyID propId =
       nsCSSProps::LookupProperty(nsDependentAtomString(mKey.mAttributeName),
                                  CSSEnabledState::eForAllContent);
     if (nsSMILCSSProperty::IsPropertyAnimatable(propId)) {
       return new nsSMILCSSProperty(propId, mKey.mElement.get());
     }
   } else {
     return mKey.mElement->GetAnimatedAttr(mKey.mAttributeNamespaceID,
                                           mKey.mAttributeName);
--- a/dom/smil/nsSMILMappedAttribute.h
+++ b/dom/smil/nsSMILMappedAttribute.h
@@ -31,17 +31,17 @@ class nsSMILMappedAttribute : public nsS
 public:
   /**
    * Constructs a new nsSMILMappedAttribute.
    *
    * @param  aPropID   The CSS property for the mapped attribute we're
    *                   interested in animating.
    * @param  aElement  The element whose attribute is being animated.
    */
-  nsSMILMappedAttribute(nsCSSProperty aPropID, mozilla::dom::Element* aElement) :
+  nsSMILMappedAttribute(nsCSSPropertyID aPropID, mozilla::dom::Element* aElement) :
     nsSMILCSSProperty(aPropID, aElement) {}
 
   // nsISMILAttr methods
   virtual nsresult ValueFromString(const nsAString& aStr,
                                    const mozilla::dom::SVGAnimationElement* aSrcElement,
                                    nsSMILValue& aValue,
                                    bool& aPreventCachingOfSandwich) const override;
   virtual nsSMILValue GetBaseValue() const override;
--- a/dom/svg/nsSVGElement.cpp
+++ b/dom/svg/nsSVGElement.cpp
@@ -1194,18 +1194,18 @@ void
 MappedAttrParser::ParseMappedAttrValue(nsIAtom* aMappedAttrName,
                                        const nsAString& aMappedAttrValue)
 {
   if (!mDecl) {
     mDecl = new css::Declaration();
     mDecl->InitializeEmpty();
   }
 
-  // Get the nsCSSProperty ID for our mapped attribute.
-  nsCSSProperty propertyID =
+  // Get the nsCSSPropertyID ID for our mapped attribute.
+  nsCSSPropertyID propertyID =
     nsCSSProps::LookupProperty(nsDependentAtomString(aMappedAttrName),
                                CSSEnabledState::eForAllContent);
   if (propertyID != eCSSProperty_UNKNOWN) {
     bool changed = false; // outparam for ParseProperty.
     mParser.ParseProperty(propertyID, aMappedAttrValue, mDocURI, mBaseURI,
                           mElement->NodePrincipal(), mDecl, &changed, false, true);
     if (changed) {
       // The normal reporting of use counters by the nsCSSParser won't happen
@@ -2553,17 +2553,17 @@ nsSVGElement::GetAnimatedAttr(int32_t aN
   if (aNamespaceID == kNameSpaceID_None) {
     // We check mapped-into-style attributes first so that animations
     // targeting width/height on outer-<svg> don't appear to be ignored
     // because we returned a nsISMILAttr for the corresponding
     // SVGAnimatedLength.
 
     // Mapped attributes:
     if (IsAttributeMapped(aName)) {
-      nsCSSProperty prop =
+      nsCSSPropertyID prop =
         nsCSSProps::LookupProperty(nsDependentAtomString(aName),
                                    CSSEnabledState::eForAllContent);
       // Check IsPropertyAnimatable to avoid attributes that...
       //  - map to explicitly unanimatable properties (e.g. 'direction')
       //  - map to unsupported attributes (e.g. 'glyph-orientation-horizontal')
       if (nsSMILCSSProperty::IsPropertyAnimatable(prop)) {
         return new nsSMILMappedAttribute(prop, this);
       }
--- a/dom/tests/mochitest/general/test_picture_apng.html
+++ b/dom/tests/mochitest/general/test_picture_apng.html
@@ -47,17 +47,17 @@ window.onload = function() {
     SimpleTest.finish();
   }
 };
 SimpleTest.waitForExplicitFinish();
 </script>
 
 <body>
   <picture id="test0">
-    <srouce>
+    <source>
     <img src="pass.apng">
   </picture>
   <picture id="test1">
     <source type="bogus/type" srcset="fail.png">
     <source type="image/apng" srcset="pass.apng">
     <source type="image/jpeg" srcset="fail.png">
     <img src="fail-fallback">
   </picture>
--- a/dom/tv/TVChannel.cpp
+++ b/dom/tv/TVChannel.cpp
@@ -59,18 +59,18 @@ TVChannel::Init(nsITVChannelData* aData)
     return false;
   }
 
   aData->GetNetworkId(mNetworkId);
   aData->GetTransportStreamId(mTransportStreamId);
   aData->GetServiceId(mServiceId);
   aData->GetName(mName);
   aData->GetNumber(mNumber);
-  aData->GetIsEmergency(&mIsEmergency);
-  aData->GetIsFree(&mIsFree);
+  mIsEmergency = aData->GetIsEmergency();
+  mIsFree = aData->GetIsFree();
 
   mTVService = TVServiceFactory::AutoCreateTVService();
   NS_ENSURE_TRUE(mTVService, false);
 
   return true;
 }
 
 /* virtual */ JSObject*
--- a/dom/tv/TVProgram.cpp
+++ b/dom/tv/TVProgram.cpp
@@ -28,18 +28,18 @@ TVProgram::TVProgram(nsISupports* aOwner
   : mOwner(aOwner)
   , mChannel(aChannel)
 {
   MOZ_ASSERT(mChannel);
   MOZ_ASSERT(aData);
 
   aData->GetEventId(mEventId);
   aData->GetTitle(mTitle);
-  aData->GetStartTime(&mStartTime);
-  aData->GetDuration(&mDuration);
+  mStartTime = aData->GetStartTime();
+  mDuration = aData->GetDuration();
   aData->GetDescription(mDescription);
   aData->GetRating(mRating);
 
   uint32_t count;
   char** languages;
   aData->GetAudioLanguages(&count, &languages);
   SetLanguages(count, languages, mAudioLanguages);
   aData->GetSubtitleLanguages(&count, &languages);
--- a/dom/url/URL.cpp
+++ b/dom/url/URL.cpp
@@ -238,17 +238,19 @@ URLMainThread::Constructor(nsISupports* 
 URLMainThread::Constructor(nsISupports* aParent, const nsAString& aURL,
                            nsIURI* aBase, ErrorResult& aRv)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   nsCOMPtr<nsIURI> uri;
   nsresult rv = NS_NewURI(getter_AddRefs(uri), aURL, nullptr, aBase,
                           nsContentUtils::GetIOService());
-  if (NS_WARN_IF(NS_FAILED(rv))) {
+  if (NS_FAILED(rv)) {
+    // No need to warn in this case. It's common to use the URL constructor
+    // to determine if a URL is valid and an exception will be propagated.
     aRv.ThrowTypeError<MSG_INVALID_URL>(aURL);
     return nullptr;
   }
 
   RefPtr<URLMainThread> url = new URLMainThread(aParent, uri.forget());
   return url.forget();
 }
 
--- a/dom/webidl/Document.webidl
+++ b/dom/webidl/Document.webidl
@@ -1,14 +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/.
  *
- * http://mxr.mozilla.org/mozilla-central/source/dom/interfaces/core/nsIDOMDocument.idl
+ * http://dxr.mozilla.org/mozilla-central/source/dom/interfaces/core/nsIDOMDocument.idl
  */
 
 interface WindowProxy;
 interface nsISupports;
 interface URI;
 interface nsIDocShell;
 interface nsILoadGroup;
 
--- a/dom/webidl/Element.webidl
+++ b/dom/webidl/Element.webidl
@@ -106,16 +106,19 @@ interface Element : Node {
 
   // Pointer events methods.
   [Throws, Pref="dom.w3c_pointer_events.enabled", UnsafeInPrerendering]
   void setPointerCapture(long pointerId);
 
   [Throws, Pref="dom.w3c_pointer_events.enabled"]
   void releasePointerCapture(long pointerId);
 
+  [Pref="dom.w3c_pointer_events.enabled"]
+  boolean hasPointerCapture(long pointerId);
+
   // Proprietary extensions
   /**
    * Set this during a mousedown event to grab and retarget all mouse events
    * to this element until the mouse button is released or releaseCapture is
    * called. If retargetToElement is true, then all events are targetted at
    * this element. If false, events can also fire at descendants of this
    * element.
    * 
--- a/dom/webidl/WebGL2RenderingContext.webidl
+++ b/dom/webidl/WebGL2RenderingContext.webidl
@@ -313,38 +313,37 @@ interface WebGL2RenderingContext : WebGL
     const GLint64 TIMEOUT_IGNORED                              = -1;
 
     /* WebGL-specific enums */
     const GLenum MAX_CLIENT_WAIT_TIMEOUT_WEBGL                 = 0x9247;
 
     /* Buffer objects */
     void copyBufferSubData(GLenum readTarget, GLenum writeTarget, GLintptr readOffset,
                            GLintptr writeOffset, GLsizeiptr size);
-    void getBufferSubData(GLenum target, GLintptr offset, ArrayBuffer? returnedData);
-    void getBufferSubData(GLenum target, GLintptr offset, SharedArrayBuffer returnedData);
+    void getBufferSubData(GLenum target, GLintptr offset, ArrayBufferView dstData);
 
     [Throws] /* Throws on readback in a write-only context. */
     void readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format,
                     GLenum type, GLintptr offset);
     /* Include our WebGL 1 function override(s) */
     [Throws]
     void readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format,
-                    GLenum type, ArrayBufferView? pixels);
+                    GLenum type, ArrayBufferView pixels);
 
     /* Framebuffer objects */
     void blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0,
                          GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
     void framebufferTextureLayer(GLenum target, GLenum attachment, WebGLTexture? texture, GLint level, GLint layer);
 
     [Throws]
     void invalidateFramebuffer(GLenum target, sequence<GLenum> attachments);
 
     [Throws]
-    void invalidateSubFramebuffer (GLenum target, sequence<GLenum> attachments,
-                                   GLint x, GLint y, GLsizei width, GLsizei height);
+    void invalidateSubFramebuffer(GLenum target, sequence<GLenum> attachments, GLint x,
+                                  GLint y, GLsizei width, GLsizei height);
 
     void readBuffer(GLenum src);
 
     /* Renderbuffer objects */
     [Throws]
     any getInternalformatParameter(GLenum target, GLenum internalformat, GLenum pname);
     void renderbufferStorageMultisample(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
 
@@ -361,20 +360,20 @@ interface WebGL2RenderingContext : WebGL
                     GLsizei height, GLsizei depth, GLint border, GLenum format,
                     GLenum type, ArrayBufferView? pixels);
 
     //////
 
     [Throws] // Can't actually throw.
     void texSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
                        GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
-                       GLenum format, GLenum type, ArrayBufferView? pixels);
+                       GLenum format, GLenum type, ArrayBufferView pixels);
     [Throws] // Can't actually throw.
     void texSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
-                       GLint zoffset, GLenum format, GLenum type, ImageData? data);
+                       GLint zoffset, GLenum format, GLenum type, ImageData data);
     [Throws]
     void texSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
                        GLint zoffset, GLenum format, GLenum type, HTMLImageElement image);
     [Throws]
     void texSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
                        GLint zoffset, GLenum format, GLenum type,
                        HTMLCanvasElement canvas);
     [Throws]
@@ -422,36 +421,36 @@ interface WebGL2RenderingContext : WebGL
 
     // Overloads must share [Throws].
     [Throws] // Can't throw.
     void texImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width,
                     GLsizei height, GLint border, GLenum format, GLenum type,
                     ArrayBufferView? pixels);
     [Throws] // Can't throw.
     void texImage2D(GLenum target, GLint level, GLenum internalformat, GLenum format,
-                    GLenum type, ImageData? pixels);
+                    GLenum type, ImageData pixels);
     [Throws] // May throw DOMException
     void texImage2D(GLenum target, GLint level, GLenum internalformat, GLenum format,
                     GLenum type, HTMLImageElement image);
     [Throws] // May throw DOMException
     void texImage2D(GLenum target, GLint level, GLenum internalformat, GLenum format,
                     GLenum type, HTMLCanvasElement canvas);
     [Throws] // May throw DOMException
     void texImage2D(GLenum target, GLint level, GLenum internalformat, GLenum format,
                     GLenum type, HTMLVideoElement video);
 
     //////
 
     [Throws] // Can't throw.
     void texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
                        GLsizei width, GLsizei height, GLenum format, GLenum type,
-                       ArrayBufferView? pixels);
+                       ArrayBufferView pixels);
     [Throws] // Can't throw.
     void texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
-                       GLenum format, GLenum type, ImageData? pixels);
+                       GLenum format, GLenum type, ImageData pixels);
     [Throws]  // May throw DOMException
     void texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
                        GLenum format, GLenum type, HTMLImageElement image);
     [Throws] // May throw DOMException
     void texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
                        GLenum format, GLenum type, HTMLCanvasElement canvas);
     [Throws] // May throw DOMException
     void texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
--- a/dom/workers/RuntimeService.cpp
+++ b/dom/workers/RuntimeService.cpp
@@ -747,16 +747,28 @@ bool
 InitJSContextForWorker(WorkerPrivate* aWorkerPrivate, JSContext* aWorkerCx)
 {
   aWorkerPrivate->AssertIsOnWorkerThread();
   NS_ASSERTION(!aWorkerPrivate->GetJSContext(), "Already has a context!");
 
   JSSettings settings;
   aWorkerPrivate->CopyJSSettings(settings);
 
+  {
+    JS::UniqueChars defaultLocale = aWorkerPrivate->AdoptDefaultLocale();
+    MOZ_ASSERT(defaultLocale,
+               "failure of a WorkerPrivate to have a default locale should "
+               "have made the worker fail to spawn");
+
+    if (!JS_SetDefaultLocale(aWorkerCx, defaultLocale.get())) {
+      NS_WARNING("failed to set workerCx's default locale");
+      return false;
+    }
+  }
+
   JS::ContextOptionsRef(aWorkerCx) = settings.contextOptions;
 
   JSSettings::JSGCSettingsArray& gcSettings = settings.gcSettings;
 
   // This is the real place where we set the max memory for the runtime.
   for (uint32_t index = 0; index < ArrayLength(gcSettings); index++) {
     const JSSettings::JSGCSetting& setting = gcSettings[index];
     if (setting.IsSet()) {
--- a/dom/workers/ServiceWorkerClient.cpp
+++ b/dom/workers/ServiceWorkerClient.cpp
@@ -142,19 +142,19 @@ private:
     RootedDictionary<ServiceWorkerMessageEventInit> init(aCx);
 
     nsCOMPtr<nsIPrincipal> principal = aTargetContainer->GetParentObject()->PrincipalOrNull();
     NS_WARN_IF_FALSE(principal, "Why is the principal null here?");
 
     bool isNullPrincipal = false;
     bool isSystemPrincipal = false;
     if (principal) {
-      principal->GetIsNullPrincipal(&isNullPrincipal);
+      isNullPrincipal = principal->GetIsNullPrincipal();
       MOZ_ASSERT(!isNullPrincipal);
-      principal->GetIsSystemPrincipal(&isSystemPrincipal);
+      isSystemPrincipal = principal->GetIsSystemPrincipal();
       MOZ_ASSERT(!isSystemPrincipal);
     }
 
     init.mData = messageData;
     nsAutoCString origin;
     if (principal && !isNullPrincipal && !isSystemPrincipal) {
       principal->GetOrigin(origin);
     }
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -16,16 +16,17 @@
 #include "nsIDocShell.h"
 #include "nsIInterfaceRequestor.h"
 #include "nsIMemoryReporter.h"
 #include "nsINetworkInterceptController.h"
 #include "nsIPermissionManager.h"
 #include "nsIScriptError.h"
 #include "nsIScriptGlobalObject.h"
 #include "nsIScriptSecurityManager.h"
+#include "nsIScriptTimeoutHandler.h"
 #include "nsITabChild.h"
 #include "nsITextToSubURI.h"
 #include "nsIThreadInternal.h"
 #include "nsITimer.h"
 #include "nsIURI.h"
 #include "nsIURL.h"
 #include "nsIWeakReferenceUtils.h"
 #include "nsIWorkerDebugger.h"
@@ -37,16 +38,17 @@
 #include "jsfriendapi.h"
 #include "js/MemoryMetrics.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/ContentEvents.h"
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/Likely.h"
 #include "mozilla/LoadContext.h"
+#include "mozilla/Move.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/Console.h"
 #include "mozilla/dom/ErrorEvent.h"
 #include "mozilla/dom/ErrorEventBinding.h"
 #include "mozilla/dom/Exceptions.h"
 #include "mozilla/dom/ExtendableMessageEventBinding.h"
 #include "mozilla/dom/FunctionBinding.h"
 #include "mozilla/dom/IndexedDatabaseManager.h"
@@ -2123,18 +2125,17 @@ InterfaceRequestor::GetAnyLiveTabChild()
 
 NS_IMPL_ADDREF(WorkerLoadInfo::InterfaceRequestor)
 NS_IMPL_RELEASE(WorkerLoadInfo::InterfaceRequestor)
 NS_IMPL_QUERY_INTERFACE(WorkerLoadInfo::InterfaceRequestor, nsIInterfaceRequestor)
 
 struct WorkerPrivate::TimeoutInfo
 {
   TimeoutInfo()
-  : mTimeoutCallable(JS::UndefinedValue()), mLineNumber(0), mId(0),
-    mIsInterval(false), mCanceled(false)
+  : mId(0), mIsInterval(false), mCanceled(false)
   {
     MOZ_COUNT_CTOR(mozilla::dom::workers::WorkerPrivate::TimeoutInfo);
   }
 
   ~TimeoutInfo()
   {
     MOZ_COUNT_DTOR(mozilla::dom::workers::WorkerPrivate::TimeoutInfo);
   }
@@ -2144,23 +2145,19 @@ struct WorkerPrivate::TimeoutInfo
     return mTargetTime == aOther.mTargetTime;
   }
 
   bool operator<(const TimeoutInfo& aOther)
   {
     return mTargetTime < aOther.mTargetTime;
   }
 
-  JS::Heap<JS::Value> mTimeoutCallable;
-  nsString mTimeoutString;
-  nsTArray<JS::Heap<JS::Value> > mExtraArgVals;
+  nsCOMPtr<nsIScriptTimeoutHandler> mHandler;
   mozilla::TimeStamp mTargetTime;
   mozilla::TimeDuration mInterval;
-  nsCString mFilename;
-  uint32_t mLineNumber;
   int32_t mId;
   bool mIsInterval;
   bool mCanceled;
 };
 
 class WorkerPrivate::MemoryReporter final : public nsIMemoryReporter
 {
   NS_DECL_THREADSAFE_ISUPPORTS
@@ -4191,16 +4188,28 @@ WorkerPrivate::Constructor(JSContext* aC
   }
 
   MOZ_ASSERT(runtimeService);
 
   RefPtr<WorkerPrivate> worker =
     new WorkerPrivate(parent, aScriptURL, aIsChromeWorker,
                       aWorkerType, aWorkerName, *aLoadInfo);
 
+  // Gecko contexts always have an explicitly-set default locale (set by
+  // XPJSRuntime::Initialize for the main thread, set by
+  // WorkerThreadPrimaryRunnable::Run for workers just before running worker
+  // code), so this is never SpiderMonkey's builtin default locale.
+  JS::UniqueChars defaultLocale = JS_GetDefaultLocale(aCx);
+  if (NS_WARN_IF(!defaultLocale)) {
+    aRv.Throw(NS_ERROR_UNEXPECTED);
+    return nullptr;
+  }
+
+  worker->mDefaultLocale = Move(defaultLocale);
+
   if (!runtimeService->RegisterWorker(worker)) {
     aRv.Throw(NS_ERROR_UNEXPECTED);
     return nullptr;
   }
 
   worker->EnableDebugger();
 
   RefPtr<CompileScriptRunnable> compiler =
@@ -5171,33 +5180,28 @@ WorkerPrivate::ThawInternal()
 
   NS_ASSERTION(mFrozen, "Not yet frozen!");
 
   mFrozen = false;
   return true;
 }
 
 void
-WorkerPrivate::TraceTimeouts(const TraceCallbacks& aCallbacks,
-                             void* aClosure) const
-{
-  AssertIsOnWorkerThread();
-
-  for (uint32_t index = 0; index < mTimeouts.Length(); index++) {
-    TimeoutInfo* info = mTimeouts[index];
-
-    if (info->mTimeoutCallable.isUndefined()) {
-      continue;
-    }
-
-    aCallbacks.Trace(&info->mTimeoutCallable, "mTimeoutCallable", aClosure);
-    for (uint32_t index2 = 0; index2 < info->mExtraArgVals.Length(); index2++) {
-      aCallbacks.Trace(&info->mExtraArgVals[index2], "mExtraArgVals[i]", aClosure);
-    }
-  }
+WorkerPrivate::TraverseTimeouts(nsCycleCollectionTraversalCallback& cb)
+{
+  for (uint32_t i = 0; i < mTimeouts.Length(); ++i) {
+    TimeoutInfo* tmp = mTimeouts[i];
+    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mHandler)
+  }
+}
+
+void
+WorkerPrivate::UnlinkTimeouts()
+{
+  mTimeouts.Clear();
 }
 
 bool
 WorkerPrivate::ModifyBusyCountFromWorker(bool aIncrease)
 {
   AssertIsOnWorkerThread();
 
   {
@@ -5976,24 +5980,22 @@ WorkerPrivate::ReportErrorToConsole(cons
     wp = GetCurrentThreadWorkerPrivate();
   }
 
   ReportErrorToConsoleRunnable::Report(wp, aMessage);
 }
 
 int32_t
 WorkerPrivate::SetTimeout(JSContext* aCx,
-                          dom::Function* aHandler,
-                          const nsAString& aStringHandler,
-                          int32_t aTimeout,
-                          const Sequence<JS::Value>& aArguments,
-                          bool aIsInterval,
+                          nsIScriptTimeoutHandler* aHandler,
+                          int32_t aTimeout, bool aIsInterval,
                           ErrorResult& aRv)
 {
   AssertIsOnWorkerThread();
+  MOZ_ASSERT(aHandler);
 
   const int32_t timerId = mNextTimeoutId++;
 
   Status currentStatus;
   {
     MutexAutoLock lock(mMutex);
     currentStatus = mStatus;
   }
@@ -6016,52 +6018,24 @@ WorkerPrivate::SetTimeout(JSContext* aCx
   newInfo->mIsInterval = aIsInterval;
   newInfo->mId = timerId;
 
   if (MOZ_UNLIKELY(timerId == INT32_MAX)) {
     NS_WARNING("Timeout ids overflowed!");
     mNextTimeoutId = 1;
   }
 
-  // Take care of the main argument.
-  if (aHandler) {
-    newInfo->mTimeoutCallable = JS::ObjectValue(*aHandler->Callable());
-  }
-  else if (!aStringHandler.IsEmpty()) {
-    newInfo->mTimeoutString = aStringHandler;
-  }
-  else {
-    NS_NAMED_LITERAL_STRING(kSetInterval, "setInterval");
-    NS_NAMED_LITERAL_STRING(kSetTimeout, "setTimeout");
-    aRv.ThrowTypeError<MSG_USELESS_SETTIMEOUT>(aIsInterval ? kSetInterval
-                                                           : kSetTimeout);
-    return 0;
-  }
+  newInfo->mHandler = aHandler;
 
   // See if any of the optional arguments were passed.
   aTimeout = std::max(0, aTimeout);
   newInfo->mInterval = TimeDuration::FromMilliseconds(aTimeout);
 
-  uint32_t argc = aArguments.Length();
-  if (argc && !newInfo->mTimeoutCallable.isUndefined()) {
-    nsTArray<JS::Heap<JS::Value>> extraArgVals(argc);
-    for (uint32_t index = 0; index < argc; index++) {
-      extraArgVals.AppendElement(aArguments[index]);
-    }
-    newInfo->mExtraArgVals.SwapElements(extraArgVals);
-  }
-
   newInfo->mTargetTime = TimeStamp::Now() + newInfo->mInterval;
 
-  if (!newInfo->mTimeoutString.IsEmpty()) {
-    if (!nsJSUtils::GetCallingLocation(aCx, newInfo->mFilename, &newInfo->mLineNumber)) {
-      NS_WARNING("Failed to get calling location!");
-    }
-  }
-
   nsAutoPtr<TimeoutInfo>* insertedInfo =
     mTimeouts.InsertElementSorted(newInfo.forget(), GetAutoPtrComparator(mTimeouts));
 
   LOG(TimeoutsLog(), ("Worker %p has new timeout: delay=%d interval=%s\n",
                       this, aTimeout, aIsInterval ? "yes" : "no"));
 
   // If the timeout we just made is set to fire next then we need to update the
   // timer, unless we're currently running timeouts.
@@ -6171,51 +6145,53 @@ WorkerPrivate::RunExpiredTimeouts(JSCont
     // break out of the loop.
     const char *reason;
     if (info->mIsInterval) {
       reason = "setInterval handler";
     } else {
       reason = "setTimeout handler";
     }
 
-    { // scope for the AutoEntryScript, so it comes off the stack before we do
+    RefPtr<Function> callback = info->mHandler->GetCallback();
+    if (!callback) {
+      // scope for the AutoEntryScript, so it comes off the stack before we do
       // Promise::PerformMicroTaskCheckpoint.
       AutoEntryScript aes(global, reason, false);
-      if (!info->mTimeoutCallable.isUndefined()) {
-        JS::ExposeValueToActiveJS(info->mTimeoutCallable);
-        for (uint32_t i = 0; i < info->mExtraArgVals.Length(); ++i) {
-          JS::ExposeValueToActiveJS(info->mExtraArgVals[i]);
-        }
-        JS::Rooted<JS::Value> rval(aCx);
-        JS::HandleValueArray args =
-          JS::HandleValueArray::fromMarkedLocation(info->mExtraArgVals.Length(),
-                                                   info->mExtraArgVals.Elements()->address());
-        JS::Rooted<JS::Value> callable(aCx, info->mTimeoutCallable);
-        if (!JS_CallFunctionValue(aCx, global, callable, args, &rval) &&
-            !JS_IsExceptionPending(aCx)) {
-          retval = false;
-          break;
-        }
+
+      // Evaluate the timeout expression.
+      nsAutoString script;
+      info->mHandler->GetHandlerText(script);
+
+      const char* filename = nullptr;
+      uint32_t lineNo = 0, dummyColumn = 0;
+      info->mHandler->GetLocation(&filename, &lineNo, &dummyColumn);
+
+      JS::CompileOptions options(aes.cx());
+      options.setFileAndLine(filename, lineNo).setNoScriptRval(true);
+
+      JS::Rooted<JS::Value> unused(aes.cx());
+
+      if (!JS::Evaluate(aes.cx(), options, script.get(),
+                        script.Length(), &unused) &&
+          !JS_IsExceptionPending(aCx)) {
+        retval = false;
+        break;
       }
-      else {
-        nsString expression = info->mTimeoutString;
-
-        JS::CompileOptions options(aCx);
-        options.setFileAndLine(info->mFilename.get(), info->mLineNumber)
-               .setNoScriptRval(true);
-
-        JS::Rooted<JS::Value> unused(aCx);
-        if (!expression.IsEmpty() &&
-            !JS::Evaluate(aCx, options,
-                          expression.get(), expression.Length(), &unused) &&
-            !JS_IsExceptionPending(aCx)) {
-          retval = false;
-          break;
-        }
+    } else {
+      ErrorResult rv;
+      JS::Rooted<JS::Value> ignoredVal(aCx);
+      callback->Call(GlobalScope(), info->mHandler->GetArgs(), &ignoredVal, rv,
+                     reason);
+      if (rv.IsUncatchableException()) {
+        rv.SuppressException();
+        retval = false;
+        break;
       }
+
+      rv.SuppressException();
     }
 
     // Since we might be processing more timeouts, go ahead and flush
     // the promise queue now before we do that.
     Promise::PerformWorkerMicroTaskCheckpoint();
 
     NS_ASSERTION(mRunningExpiredTimeouts, "Someone changed this!");
   }
--- a/dom/workers/WorkerPrivate.h
+++ b/dom/workers/WorkerPrivate.h
@@ -10,18 +10,21 @@
 #include "Workers.h"
 
 #include "nsIContentPolicy.h"
 #include "nsIContentSecurityPolicy.h"
 #include "nsILoadGroup.h"
 #include "nsIWorkerDebugger.h"
 #include "nsPIDOMWindow.h"
 
+#include "mozilla/Assertions.h"
+#include "mozilla/Attributes.h"
 #include "mozilla/CondVar.h"
 #include "mozilla/DOMEventTargetHelper.h"
+#include "mozilla/Move.h"
 #include "mozilla/TimeStamp.h"
 #include "mozilla/dom/BindingDeclarations.h"
 #include "nsAutoPtr.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsDataHashtable.h"
 #include "nsHashKeys.h"
 #include "nsRefPtrHashtable.h"
 #include "nsString.h"
@@ -36,16 +39,17 @@
 #undef PostMessage
 #endif
 
 class nsIChannel;
 class nsIDocument;
 class nsIEventTarget;
 class nsIPrincipal;
 class nsIScriptContext;
+class nsIScriptTimeoutHandler;
 class nsISerializable;
 class nsIThread;
 class nsIThreadInternal;
 class nsITimer;
 class nsIURI;
 template<class T> class nsMainThreadPtrHandle;
 
 namespace JS {
@@ -933,16 +937,17 @@ class WorkerPrivate : public WorkerPriva
   nsCOMPtr<nsIEventTarget> mPeriodicGCTimerTarget;
   nsCOMPtr<nsIEventTarget> mIdleGCTimerTarget;
 
   RefPtr<MemoryReporter> mMemoryReporter;
 
   // fired on the main thread if the worker script fails to load
   nsCOMPtr<nsIRunnable> mLoadFailedRunnable;
 
+  JS::UniqueChars mDefaultLocale; // nulled during worker JSContext init
   TimeStamp mKillTime;
   uint32_t mErrorHandlerRecursionCount;
   uint32_t mNextTimeoutId;
   Status mStatus;
   bool mFrozen;
   bool mTimerRunning;
   bool mRunningExpiredTimeouts;
   bool mCloseHandlerStarted;
@@ -1044,16 +1049,25 @@ public:
   SetDebugger(WorkerDebugger* aDebugger)
   {
     AssertIsOnMainThread();
 
     MOZ_ASSERT(mDebugger != aDebugger);
     mDebugger = aDebugger;
   }
 
+  JS::UniqueChars
+  AdoptDefaultLocale()
+  {
+    MOZ_ASSERT(mDefaultLocale,
+               "the default locale must have been successfully set for anyone "
+               "to be trying to adopt it");
+    return Move(mDefaultLocale);
+  }
+
   void
   DoRunLoop(JSContext* aCx);
 
   bool
   InterruptCallback(JSContext* aCx);
 
   nsresult
   IsOnCurrentThread(bool* aIsOnCurrentThread);
@@ -1067,17 +1081,20 @@ public:
 
   bool
   FreezeInternal();
 
   bool
   ThawInternal();
 
   void
-  TraceTimeouts(const TraceCallbacks& aCallbacks, void* aClosure) const;
+  TraverseTimeouts(nsCycleCollectionTraversalCallback& aCallback);
+
+  void
+  UnlinkTimeouts();
 
   bool
   ModifyBusyCountFromWorker(bool aIncrease);
 
   bool
   AddChildWorker(ParentType* aChildWorker);
 
   void
@@ -1120,22 +1137,18 @@ public:
 
   void
   ReportError(JSContext* aCx, const char* aMessage, JSErrorReport* aReport);
 
   static void
   ReportErrorToConsole(const char* aMessage);
 
   int32_t
-  SetTimeout(JSContext* aCx,
-             Function* aHandler,
-             const nsAString& aStringHandler,
-             int32_t aTimeout,
-             const Sequence<JS::Value>& aArguments,
-             bool aIsInterval,
+  SetTimeout(JSContext* aCx, nsIScriptTimeoutHandler* aHandler,
+             int32_t aTimeout, bool aIsInterval,
              ErrorResult& aRv);
 
   void
   ClearTimeout(int32_t aId);
 
   bool
   RunExpiredTimeouts(JSContext* aCx);
 
--- a/dom/workers/WorkerRunnable.cpp
+++ b/dom/workers/WorkerRunnable.cpp
@@ -672,23 +672,23 @@ WorkerProxyToMainThreadRunnable::WorkerP
 WorkerProxyToMainThreadRunnable::~WorkerProxyToMainThreadRunnable()
 {}
 
 bool
 WorkerProxyToMainThreadRunnable::Dispatch()
 {
   mWorkerPrivate->AssertIsOnWorkerThread();
 
-  if (NS_WARN_IF(!mWorkerPrivate->ModifyBusyCountFromWorker(true))) {
+  if (NS_WARN_IF(!HoldWorker())) {
     RunBackOnWorkerThread();
     return false;
   }
 
   if (NS_WARN_IF(NS_FAILED(NS_DispatchToMainThread(this)))) {
-    mWorkerPrivate->ModifyBusyCountFromWorker(false);
+    ReleaseWorker();
     RunBackOnWorkerThread();
     return false;
   }
 
   return true;
 }
 
 NS_IMETHODIMP
@@ -728,21 +728,55 @@ WorkerProxyToMainThreadRunnable::PostDis
     WorkerRun(JSContext* aCx, workers::WorkerPrivate* aWorkerPrivate) override
     {
       MOZ_ASSERT(aWorkerPrivate);
       aWorkerPrivate->AssertIsOnWorkerThread();
 
       mRunnable->RunBackOnWorkerThread();
 
       // Let's release the worker thread.
-      aWorkerPrivate->ModifyBusyCountFromWorker(false);
+      mRunnable->ReleaseWorker();
       return true;
     }
 
   private:
     ~ReleaseRunnable()
     {}
   };
 
   RefPtr<WorkerControlRunnable> runnable =
     new ReleaseRunnable(mWorkerPrivate, this);
   NS_WARN_IF(!runnable->Dispatch());
 }
+
+bool
+WorkerProxyToMainThreadRunnable::HoldWorker()
+{
+  mWorkerPrivate->AssertIsOnWorkerThread();
+  MOZ_ASSERT(!mWorkerHolder);
+
+  class SimpleWorkerHolder final : public WorkerHolder
+  {
+  public:
+    bool Notify(Status aStatus) override
+    {
+      // We don't care about the notification. We just want to keep the
+      // mWorkerPrivate alive.
+      return true;
+    }
+  };
+
+  UniquePtr<WorkerHolder> workerHolder(new SimpleWorkerHolder());
+  if (NS_WARN_IF(!workerHolder->HoldWorker(mWorkerPrivate))) {
+    return false;
+  }
+
+  mWorkerHolder = Move(workerHolder);
+  return true;
+}
+
+void
+WorkerProxyToMainThreadRunnable::ReleaseWorker()
+{
+  mWorkerPrivate->AssertIsOnWorkerThread();
+  MOZ_ASSERT(mWorkerHolder);
+  mWorkerHolder = nullptr;
+}
--- a/dom/workers/WorkerRunnable.h
+++ b/dom/workers/WorkerRunnable.h
@@ -428,18 +428,22 @@ protected:
 public:
   bool Dispatch();
 
 private:
   NS_IMETHOD Run() override;
 
   void PostDispatchOnMainThread();
 
+  bool HoldWorker();
+  void ReleaseWorker();
+
 protected:
   WorkerPrivate* mWorkerPrivate;
+  UniquePtr<WorkerHolder> mWorkerHolder;
 };
 
 // Class for checking API exposure.  This totally violates the "MUST" in the
 // comments on WorkerMainThreadRunnable::Dispatch, because API exposure checks
 // can't throw.  Maybe we should change it so they _could_ throw.  But for now
 // we are bad people and should be ashamed of ourselves.  Let's hope none of
 // them happen while a worker is shutting down.
 //
--- a/dom/workers/WorkerScope.cpp
+++ b/dom/workers/WorkerScope.cpp
@@ -27,16 +27,17 @@
 #include "mozilla/dom/WorkerLocation.h"
 #include "mozilla/dom/WorkerNavigator.h"
 #include "mozilla/dom/cache/CacheStorage.h"
 #include "mozilla/Services.h"
 #include "nsServiceManagerUtils.h"
 
 #include "nsIDocument.h"
 #include "nsIServiceWorkerManager.h"
+#include "nsIScriptTimeoutHandler.h"
 
 #ifdef ANDROID
 #include <android/log.h>
 #endif
 
 #include "Crypto.h"
 #include "Principal.h"
 #include "RuntimeService.h"
@@ -46,16 +47,28 @@
 #include "ServiceWorkerClients.h"
 #include "ServiceWorkerManager.h"
 #include "ServiceWorkerRegistration.h"
 
 #ifdef XP_WIN
 #undef PostMessage
 #endif
 
+extern already_AddRefed<nsIScriptTimeoutHandler>
+NS_CreateJSTimeoutHandler(JSContext* aCx,
+                          mozilla::dom::workers::WorkerPrivate* aWorkerPrivate,
+                          mozilla::dom::Function& aFunction,
+                          const mozilla::dom::Sequence<JS::Value>& aArguments,
+                          mozilla::ErrorResult& aError);
+
+extern already_AddRefed<nsIScriptTimeoutHandler>
+NS_CreateJSTimeoutHandler(JSContext* aCx,
+                          mozilla::dom::workers::WorkerPrivate* aWorkerPrivate,
+                          const nsAString& aExpression);
+
 using namespace mozilla;
 using namespace mozilla::dom;
 USING_WORKERS_NAMESPACE
 
 using mozilla::dom::cache::CacheStorage;
 using mozilla::ipc::PrincipalInfo;
 
 WorkerGlobalScope::WorkerGlobalScope(WorkerPrivate* aWorkerPrivate)
@@ -78,36 +91,36 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mConsole)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCrypto)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPerformance)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocation)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNavigator)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIndexedDB)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCacheStorage)
   tmp->TraverseHostObjectURIs(cb);
+  tmp->mWorkerPrivate->TraverseTimeouts(cb);
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(WorkerGlobalScope,
                                                 DOMEventTargetHelper)
   tmp->mWorkerPrivate->AssertIsOnWorkerThread();
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mConsole)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mCrypto)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mPerformance)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mLocation)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mNavigator)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mIndexedDB)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mCacheStorage)
   tmp->UnlinkHostObjectURIs();
+  tmp->mWorkerPrivate->UnlinkTimeouts();
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(WorkerGlobalScope,
                                                DOMEventTargetHelper)
   tmp->mWorkerPrivate->AssertIsOnWorkerThread();
-
-  tmp->mWorkerPrivate->TraceTimeouts(aCallbacks, aClosure);
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
 NS_IMPL_ADDREF_INHERITED(WorkerGlobalScope, DOMEventTargetHelper)
 NS_IMPL_RELEASE_INHERITED(WorkerGlobalScope, DOMEventTargetHelper)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WorkerGlobalScope)
   NS_INTERFACE_MAP_ENTRY(nsIGlobalObject)
   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
@@ -242,31 +255,38 @@ WorkerGlobalScope::ImportScripts(const S
 int32_t
 WorkerGlobalScope::SetTimeout(JSContext* aCx,
                               Function& aHandler,
                               const int32_t aTimeout,
                               const Sequence<JS::Value>& aArguments,
                               ErrorResult& aRv)
 {
   mWorkerPrivate->AssertIsOnWorkerThread();
-  return mWorkerPrivate->SetTimeout(aCx, &aHandler, EmptyString(), aTimeout,
-                                    aArguments, false, aRv);
+
+  nsCOMPtr<nsIScriptTimeoutHandler> handler =
+    NS_CreateJSTimeoutHandler(aCx, mWorkerPrivate, aHandler, aArguments, aRv);
+  if (NS_WARN_IF(aRv.Failed())) {
+    return 0;
+  }
+
+  return mWorkerPrivate->SetTimeout(aCx, handler, aTimeout, false, aRv);
 }
 
 int32_t
 WorkerGlobalScope::SetTimeout(JSContext* aCx,
                               const nsAString& aHandler,
                               const int32_t aTimeout,
                               const Sequence<JS::Value>& /* unused */,
                               ErrorResult& aRv)
 {
   mWorkerPrivate->AssertIsOnWorkerThread();
-  Sequence<JS::Value> dummy;
-  return mWorkerPrivate->SetTimeout(aCx, nullptr, aHandler, aTimeout, dummy,
-                                    false, aRv);
+
+  nsCOMPtr<nsIScriptTimeoutHandler> handler =
+    NS_CreateJSTimeoutHandler(aCx, mWorkerPrivate, aHandler);
+  return mWorkerPrivate->SetTimeout(aCx, handler, aTimeout, false, aRv);
 }
 
 void
 WorkerGlobalScope::ClearTimeout(int32_t aHandle)
 {
   mWorkerPrivate->AssertIsOnWorkerThread();
   mWorkerPrivate->ClearTimeout(aHandle);
 }
@@ -278,36 +298,42 @@ WorkerGlobalScope::SetInterval(JSContext
                                const Sequence<JS::Value>& aArguments,
                                ErrorResult& aRv)
 {
   mWorkerPrivate->AssertIsOnWorkerThread();
 
   bool isInterval = aTimeout.WasPassed();
   int32_t timeout = aTimeout.WasPassed() ? aTimeout.Value() : 0;
 
-  return mWorkerPrivate->SetTimeout(aCx, &aHandler, EmptyString(), timeout,
-                                    aArguments, isInterval, aRv);
+  nsCOMPtr<nsIScriptTimeoutHandler> handler =
+    NS_CreateJSTimeoutHandler(aCx, mWorkerPrivate, aHandler, aArguments, aRv);
+  if (NS_WARN_IF(aRv.Failed())) {
+    return 0;
+  }
+
+  return mWorkerPrivate->SetTimeout(aCx, handler,  timeout, isInterval, aRv);
 }
 
 int32_t
 WorkerGlobalScope::SetInterval(JSContext* aCx,
                                const nsAString& aHandler,
                                const Optional<int32_t>& aTimeout,
                                const Sequence<JS::Value>& /* unused */,
                                ErrorResult& aRv)
 {
   mWorkerPrivate->AssertIsOnWorkerThread();
 
   Sequence<JS::Value> dummy;
 
   bool isInterval = aTimeout.WasPassed();
   int32_t timeout = aTimeout.WasPassed() ? aTimeout.Value() : 0;
 
-  return mWorkerPrivate->SetTimeout(aCx, nullptr, aHandler, timeout, dummy,
-                                    isInterval, aRv);
+  nsCOMPtr<nsIScriptTimeoutHandler> handler =
+    NS_CreateJSTimeoutHandler(aCx, mWorkerPrivate, aHandler);
+  return mWorkerPrivate->SetTimeout(aCx, handler, timeout, isInterval, aRv);
 }
 
 void
 WorkerGlobalScope::ClearInterval(int32_t aHandle)
 {
   mWorkerPrivate->AssertIsOnWorkerThread();
   mWorkerPrivate->ClearTimeout(aHandle);
 }
--- a/dom/workers/test/mochitest.ini
+++ b/dom/workers/test/mochitest.ini
@@ -100,16 +100,17 @@ support-files =
   sharedWorker_lifetime.js
   worker_referrer.js
   websocket_https.html
   websocket_https_worker.js
   worker_fileReader.js
   fileapi_chromeScript.js
   importScripts_3rdParty_worker.js
   worker_bug1278777.js
+  worker_setTimeoutWith0.js
   !/dom/base/test/file_websocket_basic_wsh.py
   !/dom/base/test/file_websocket_hello_wsh.py
   !/dom/base/test/file_websocket_http_resource.txt
   !/dom/base/test/file_websocket_permessage_deflate_disabled_wsh.py
   !/dom/base/test/file_websocket_permessage_deflate_params_wsh.py
   !/dom/base/test/file_websocket_permessage_deflate_rejected_wsh.py
   !/dom/base/test/file_websocket_permessage_deflate_wsh.py
   !/dom/base/test/file_websocket_wsh.py
@@ -225,8 +226,9 @@ skip-if = buildapp == 'b2g' || toolkit =
 [test_referrer.html]
 [test_referrer_header_worker.html]
 [test_importScripts_3rdparty.html]
 [test_sharedWorker_ports.html]
 [test_sharedWorker_lifetime.html]
 [test_fileReader.html]
 [test_navigator_workers_hardwareConcurrency.html]
 [test_bug1278777.html]
+[test_setTimeoutWith0.html]
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/test_setTimeoutWith0.html
@@ -0,0 +1,20 @@
+<html>
+<head>
+  <title>Test for DOM Worker setTimeout and strings containing 0</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<script>
+
+var a = new Worker('worker_setTimeoutWith0.js');
+a.onmessage = function(e) {
+  is(e.data, 2, "We want to see 2 here");
+  SimpleTest.finish();
+}
+
+SimpleTest.waitForExplicitFinish();
+</script>
+</body>
+</html>
+
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/worker_setTimeoutWith0.js
@@ -0,0 +1,3 @@
+var x = 0;
+setTimeout("x++; '\x00'; x++;");
+setTimeout("postMessage(x);");
--- a/dom/xul/nsXULElement.cpp
+++ b/dom/xul/nsXULElement.cpp
@@ -1748,16 +1748,22 @@ nsXULElement::ClickWithInputSource(uint1
             status = nsEventStatus_eIgnore;  // reset status
             EventDispatcher::Dispatch(static_cast<nsIContent*>(this),
                                       context, &eventUp, nullptr, &status);
 
             // send mouse click
             status = nsEventStatus_eIgnore;  // reset status
             EventDispatcher::Dispatch(static_cast<nsIContent*>(this),
                                       context, &eventClick, nullptr, &status);
+
+            // If the click has been prevented, lets skip the command call
+            // this is how a physical click works
+            if (status == nsEventStatus_eConsumeNoDefault) {
+                return NS_OK;
+            }
         }
     }
 
     // oncommand is fired when an element is clicked...
     return DoCommand();
 }
 
 NS_IMETHODIMP
--- a/dom/xul/test/chrome.ini
+++ b/dom/xul/test/chrome.ini
@@ -33,8 +33,9 @@ support-files =
 [test_bug1061864_1.xul]
 [test_bug1061864_2.xul]
 [test_bug1070049_throw_from_script.xul]
 [test_import_xul_to_content.xul]
 [test_bug1271240.xul]
 skip-if = os == "android"
 [test_bug1069772.xul]
 skip-if = os == "android"
+[test_bug1290965.xul]
new file mode 100644
--- /dev/null
+++ b/dom/xul/test/test_bug1290965.xul
@@ -0,0 +1,39 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
+<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" xmlns:html="http://www.w3.org/1999/xhtml" xmlns:h="http://www.w3.org/1999/xhtml">
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
+  <toolbarbutton oncommand="++countera;" id="a">A</toolbarbutton>
+  <toolbarbutton oncommand="++counterb;" id="b">B</toolbarbutton>
+  <script type="text/javascript">
+  <![CDATA[
+    let aEl = document.getElementById('a');
+    let bEl = document.getElementById('b');
+    let countera = 0;
+    let counterb = 0;
+
+    aEl.addEventListener('click', function (aEvent) {
+      aEvent.preventDefault();
+      let cmdEvent = document.createEvent("xulcommandevent");
+      cmdEvent.initCommandEvent("command", true, true, window, 0,
+                                aEvent.ctrlKey, aEvent.altKey, aEvent.shiftKey,
+                                aEvent.metaKey, null);
+      aEvent.currentTarget.dispatchEvent(cmdEvent);
+    });
+
+    bEl.addEventListener('click', function (aEvent) {
+      let cmdEvent = document.createEvent("xulcommandevent");
+      cmdEvent.initCommandEvent("command", true, true, window, 0,
+                                aEvent.ctrlKey, aEvent.altKey, aEvent.shiftKey,
+                                aEvent.metaKey, null);
+      aEvent.currentTarget.dispatchEvent(cmdEvent);
+    });
+
+    bEl.click();
+    aEl.click();
+
+    is(countera, 1, "Counter should be one as event fires once");
+    is(counterb, 2, "Counter should be two as event fires twice");
+  ]]>
+  </script>
+</window>
--- a/editor/libeditor/CSSEditUtils.cpp
+++ b/editor/libeditor/CSSEditUtils.cpp
@@ -543,17 +543,17 @@ CSSEditUtils::GetCSSInlinePropertyBase(n
     return NS_OK;
   }
 
   MOZ_ASSERT(aStyleType == eSpecified);
   RefPtr<css::Declaration> decl = element->GetInlineStyleDeclaration();
   if (!decl) {
     return NS_OK;
   }
-  nsCSSProperty prop =
+  nsCSSPropertyID prop =
     nsCSSProps::LookupProperty(nsDependentAtomString(aProperty),
                                CSSEnabledState::eForAllContent);
   MOZ_ASSERT(prop != eCSSProperty_UNKNOWN);
   decl->GetValue(prop, aValue);
 
   return NS_OK;
 }
 
--- a/embedding/components/windowwatcher/nsWindowWatcher.cpp
+++ b/embedding/components/windowwatcher/nsWindowWatcher.cpp
@@ -482,21 +482,17 @@ CheckUserContextCompatibility(nsIDocShel
   }
 
   // DocShell can have UsercontextID set but loading a document with system
   // principal. In this case, we consider everything ok.
   if (nsContentUtils::IsSystemPrincipal(subjectPrincipal)) {
     return true;
   }
 
-  uint32_t principalUserContextId;
-  nsresult rv = subjectPrincipal->GetUserContextId(&principalUserContextId);
-  NS_ENSURE_SUCCESS(rv, false);
-
-  return principalUserContextId == userContextId;
+  return subjectPrincipal->GetUserContextId() == userContextId;
 }
 
 NS_IMETHODIMP
 nsWindowWatcher::OpenWindowWithoutParent(nsITabParent** aResult)
 {
   return OpenWindowWithTabParent(nullptr, EmptyCString(), true, 1.0f, aResult);
 }
 
--- a/extensions/cookie/nsPermissionManager.cpp
+++ b/extensions/cookie/nsPermissionManager.cpp
@@ -1532,20 +1532,17 @@ nsPermissionManager::AddFromPrincipal(ns
   // We don't add the system principal because it actually has no URI and we
   // always allow action for them.
   if (nsContentUtils::IsSystemPrincipal(aPrincipal)) {
     return NS_OK;
   }
 
   // Null principals can't meaningfully have persisted permissions attached to
   // them, so we don't allow adding permissions for them.
-  bool isNullPrincipal;
-  nsresult rv = aPrincipal->GetIsNullPrincipal(&isNullPrincipal);
-  NS_ENSURE_SUCCESS(rv, rv);
-  if (isNullPrincipal) {
+  if (aPrincipal->GetIsNullPrincipal()) {
     return NS_OK;
   }
 
   // Permissions may not be added to expanded principals.
   if (IsExpandedPrincipal(aPrincipal)) {
     return NS_ERROR_INVALID_ARG;
   }
 
@@ -2426,20 +2423,17 @@ nsPermissionManager::RemoveExpiredPermis
     return NS_OK;
   }
 
   for (auto iter = mPermissionTable.Iter(); !iter.Done(); iter.Next()) {
     PermissionHashKey* entry = iter.Get();
     nsCOMPtr<nsIPrincipal> principal;
     GetPrincipalFromOrigin(entry->GetKey()->mOrigin, getter_AddRefs(principal));
 
-    uint32_t appId;
-    principal->GetAppId(&appId);
-
-    if (appId != aAppId) {
+    if (principal->GetAppId() != aAppId) {
       continue;
     }
 
     for (uint32_t i = 0; i < entry->GetPermissions().Length(); ++i) {
       PermissionEntry& permEntry = entry->GetPermissions()[i];
       if (permEntry.mExpireType != nsIPermissionManager::EXPIRE_SESSION) {
         continue;
       }
--- a/gfx/2d/Path.cpp
+++ b/gfx/2d/Path.cpp
@@ -452,17 +452,17 @@ FlattenBezier(const BezierControlPoints 
 {
   double t1;
   double t2;
   uint32_t count;
 
   FindInflectionPoints(aControlPoints, &t1, &t2, &count);
 
   // Check that at least one of the inflection points is inside [0..1]
-  if (count == 0 || ((t1 <= 0.0 || t1 >= 1.0) && (count == 1 || (t2 <= 0.0 || t2 >= 1.0))) ) {
+  if (count == 0 || ((t1 < 0.0 || t1 >= 1.0) && (count == 1 || (t2 < 0.0 || t2 >= 1.0))) ) {
     FlattenBezierCurveSegment(aControlPoints, aSink, aTolerance);
     return;
   }
 
   double t1min = t1, t1max = t1, t2min = t2, t2max = t2;
 
   BezierControlPoints remainingCP = aControlPoints;
 
new file mode 100644
--- /dev/null
+++ b/gfx/2d/Polygon.h
@@ -0,0 +1,91 @@
+/* -*- Mode: C++; 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/. */
+
+
+#ifndef MOZILLA_GFX_POLYGON_H
+#define MOZILLA_GFX_POLYGON_H
+
+#include "mozilla/InitializerList.h"
+#include "nsTArray.h"
+#include "Point.h"
+
+namespace mozilla {
+namespace gfx {
+
+
+// BasePolygon3D stores the points of a convex planar polygon.
+template<class Units>
+class BasePolygon3D {
+public:
+  explicit BasePolygon3D(const std::initializer_list<Point3DTyped<Units>>& aPoints)
+    : mPoints(aPoints)
+  {
+    CalculateNormal();
+  }
+
+  explicit BasePolygon3D(nsTArray<Point3DTyped<Units>> && aPoints)
+    : mPoints(aPoints)
+  {
+    CalculateNormal();
+  }
+
+  const Point3DTyped<Units>& GetNormal() const
+  {
+    return mNormal;
+  }
+
+  const nsTArray<Point3D>& GetPoints() const
+  {
+    return mPoints;
+  }
+
+  const Point3DTyped<Units>& operator[](size_t aIndex) const
+  {
+    MOZ_ASSERT(mPoints.Length() > aIndex);
+    return mPoints[aIndex];
+  }
+
+private:
+  // Calculates the polygon surface normal.
+  // The resulting normal vector will point towards the viewer when the polygon
+  // has a counter-clockwise winding order from the perspective of the viewer.
+  void CalculateNormal()
+  {
+    MOZ_ASSERT(mPoints.Length() >= 3);
+
+    // This normal calculation method works only for planar polygons.
+    mNormal = (mPoints[1] - mPoints[0]).CrossProduct(mPoints[2] - mPoints[0]);
+
+    const float epsilon = 0.001f;
+    if (mNormal.Length() < epsilon) {
+      // The first three points were too close.
+      // Use more points for better accuracy.
+      for (size_t i = 2; i < mPoints.Length() - 1; ++i) {
+        mNormal += (mPoints[i] - mPoints[0]).CrossProduct(mPoints[i + 1] - mPoints[0]);
+      }
+    }
+
+    mNormal.Normalize();
+
+    #ifdef DEBUG
+    // Ensure that the polygon is planar.
+    // http://mathworld.wolfram.com/Point-PlaneDistance.html
+    for (const gfx::Point3DTyped<Units>& point : mPoints) {
+      float d = mNormal.DotProduct(point - mPoints[0]);
+      MOZ_ASSERT(std::abs(d) < epsilon);
+    }
+    #endif
+  }
+
+  nsTArray<Point3DTyped<Units>> mPoints;
+  Point3DTyped<Units> mNormal;
+};
+
+typedef BasePolygon3D<UnknownUnits> Polygon3D;
+
+} // namespace gfx
+} // namespace mozilla
+
+#endif /* MOZILLA_GFX_POLYGON_H */
\ No newline at end of file
--- a/gfx/2d/moz.build
+++ b/gfx/2d/moz.build
@@ -35,16 +35,17 @@ EXPORTS.mozilla.gfx += [
     'Logging.h',
     'LoggingConstants.h',
     'Matrix.h',
     'MatrixFwd.h',
     'NumericTools.h',
     'PathHelpers.h',
     'PatternHelpers.h',
     'Point.h',
+    'Polygon.h',
     'Quaternion.h',
     'RecordedEvent.h',
     'RecordingTypes.h',
     'Rect.h',
     'Scale.h',
     'ScaleFactor.h',
     'ScaleFactors2D.h',
     'SourceSurfaceCairo.h',
new file mode 100644
--- /dev/null
+++ b/gfx/layers/BSPTree.cpp
@@ -0,0 +1,187 @@
+/* -*- Mode: C++; 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/. */
+
+#include "BSPTree.h"
+#include "mozilla/gfx/Polygon.h"
+
+namespace mozilla {
+namespace layers {
+
+gfx::Polygon3D PopFront(std::deque<gfx::Polygon3D>& aPolygons)
+{
+  gfx::Polygon3D polygon = std::move(aPolygons.front());
+  aPolygons.pop_front();
+  return polygon;
+}
+
+namespace {
+
+static int sign(float d) {
+  if (d > 0) return 1;
+  if (d < 0) return -1;
+
+  return 0;
+}
+
+}
+
+void
+BSPTree::BuildDrawOrder(const UniquePtr<BSPTreeNode>& aNode,
+                        nsTArray<gfx::Polygon3D>& aPolygons) const
+{
+  const gfx::Point3D& normal = aNode->First().GetNormal();
+
+  UniquePtr<BSPTreeNode> *front = &aNode->front;
+  UniquePtr<BSPTreeNode> *back = &aNode->back;
+
+  // Since the goal is to return the draw order from back to front, we reverse
+  // the traversal order if the current polygon is facing towards the camera.
+  const bool reverseOrder = normal.z > 0.0f;
+
+  if (reverseOrder) {
+    std::swap(front, back);
+  }
+
+  if (*front) {
+    BuildDrawOrder(*front, aPolygons);
+  }
+
+  for (gfx::Polygon3D& polygon : aNode->polygons) {
+    aPolygons.AppendElement(std::move(polygon));
+  }
+
+  if (*back) {
+    BuildDrawOrder(*back, aPolygons);
+  }
+}
+
+nsTArray<float>
+BSPTree::CalculateDotProduct(const gfx::Polygon3D& aFirst,
+                             const gfx::Polygon3D& aSecond,
+                             size_t& aPos, size_t& aNeg) const
+{
+  // Point classification might produce incorrect results due to numerical
+  // inaccuracies. Using an epsilon value makes the splitting plane "thicker".
+  const float epsilon = 0.05f;
+
+  const gfx::Point3D& normal = aFirst.GetNormal();
+  const gfx::Point3D& planePoint = aFirst[0];
+
+  nsTArray<float> dotProducts;
+
+  for (const gfx::Point3D& point : aSecond.GetPoints()) {
+    float dot = (point - planePoint).DotProduct(normal);
+
+    if (dot > epsilon) {
+      aPos++;
+    } else if (dot < -epsilon) {
+      aNeg++;
+    } else {
+      // The point is within the thick plane.
+      dot = 0.0f;
+    }
+
+    dotProducts.AppendElement(dot);
+  }
+
+  return dotProducts;
+}
+
+void
+BSPTree::BuildTree(UniquePtr<BSPTreeNode>& aRoot,
+                   std::deque<gfx::Polygon3D>& aPolygons)
+{
+  if (aPolygons.empty()) {
+    return;
+  }
+
+  const gfx::Polygon3D& splittingPlane = aRoot->First();
+  std::deque<gfx::Polygon3D> backPolygons, frontPolygons;
+
+  for (gfx::Polygon3D& polygon : aPolygons) {
+    size_t pos = 0, neg = 0;
+    nsTArray<float> dots = CalculateDotProduct(splittingPlane, polygon,
+                                               pos, neg);
+
+    // Back polygon
+    if (pos == 0 && neg > 0) {
+      backPolygons.push_back(std::move(polygon));
+    }
+    // Front polygon
+    else if (pos > 0 && neg == 0) {
+     frontPolygons.push_back(std::move(polygon));
+    }
+    // Coplanar polygon
+    else if (pos == 0 && neg == 0) {
+      aRoot->polygons.push_back(std::move(polygon));
+    }
+    // Polygon intersects with the splitting plane.
+    else if (pos > 0 && neg > 0) {
+      nsTArray<gfx::Point3D> backPoints, frontPoints;
+      SplitPolygon(splittingPlane, polygon, dots, backPoints, frontPoints);
+
+      backPolygons.push_back(gfx::Polygon3D(std::move(backPoints)));
+      frontPolygons.push_back(gfx::Polygon3D(std::move(frontPoints)));
+    }
+  }
+
+  if (!backPolygons.empty()) {
+    aRoot->back.reset(new BSPTreeNode(PopFront(backPolygons)));
+    BuildTree(aRoot->back, backPolygons);
+  }
+
+  if (!frontPolygons.empty()) {
+    aRoot->front.reset(new BSPTreeNode(PopFront(frontPolygons)));
+    BuildTree(aRoot->front, frontPolygons);
+  }
+}
+
+void
+BSPTree::SplitPolygon(const gfx::Polygon3D& aSplittingPlane,
+                      const gfx::Polygon3D& aPolygon,
+                      const nsTArray<float>& dots,
+                      nsTArray<gfx::Point3D>& backPoints,
+                      nsTArray<gfx::Point3D>& frontPoints)
+{
+  const gfx::Point3D& normal = aSplittingPlane.GetNormal();
+  const size_t pointCount = aPolygon.GetPoints().Length();
+
+  for (size_t i = 0; i < pointCount; ++i) {
+    size_t j = (i + 1) % pointCount;
+
+    const gfx::Point3D& a = aPolygon[i];
+    const gfx::Point3D& b = aPolygon[j];
+    const float dotA = dots[i];
+    const float dotB = dots[j];
+
+    // The point is in front of the plane.
+    if (dotA >= 0) {
+      frontPoints.AppendElement(a);
+    }
+
+    // The point is behind the plane.
+    if (dotA <= 0) {
+      backPoints.AppendElement(a);
+    }
+
+    // If the sign of the dot product changes between two consecutive vertices,
+    // the splitting plane intersects the corresponding polygon edge.
+    if (sign(dotA) != sign(dotB)) {
+
+      // Calculate the line segment and plane intersection point.
+      const gfx::Point3D ab = b - a;
+      const float dotAB = ab.DotProduct(normal);
+      const float t = -dotA / dotAB;
+      const gfx::Point3D p = a + (ab * t);
+
+      // Add the intersection point to both polygons.
+      backPoints.AppendElement(p);
+      frontPoints.AppendElement(p);
+    }
+  }
+}
+
+} // namespace layers
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/gfx/layers/BSPTree.h
@@ -0,0 +1,92 @@
+/* -*- Mode: C++; 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/. */
+
+#ifndef MOZILLA_LAYERS_BSPTREE_H
+#define MOZILLA_LAYERS_BSPTREE_H
+
+#include "mozilla/gfx/Polygon.h"
+#include "mozilla/UniquePtr.h"
+#include "nsTArray.h"
+
+#include <deque>
+
+namespace mozilla {
+namespace layers {
+
+gfx::Polygon3D PopFront(std::deque<gfx::Polygon3D>& aPolygons);
+
+// Represents a node in a BSP tree. The node contains at least one polygon that
+// is used as a splitting plane, and at most two child nodes that represent the
+// splitting planes that further subdivide the space.
+struct BSPTreeNode {
+  explicit BSPTreeNode(gfx::Polygon3D && aPolygon)
+  {
+    polygons.push_back(std::move(aPolygon));
+  }
+
+  const gfx::Polygon3D& First() const
+  {
+    return polygons[0];
+  }
+
+  UniquePtr<BSPTreeNode> front;
+  UniquePtr<BSPTreeNode> back;
+  std::deque<gfx::Polygon3D> polygons;
+};
+
+// BSPTree class takes a list of polygons as an input and uses binary space
+// partitioning algorithm to create a tree structure that can be used for
+// depth sorting.
+//
+// Sources for more information:
+// https://en.wikipedia.org/wiki/Binary_space_partitioning
+// ftp://ftp.sgi.com/other/bspfaq/faq/bspfaq.html
+class BSPTree {
+public:
+  // This constructor takes the ownership of polygons in the given list.
+  explicit BSPTree(std::deque<gfx::Polygon3D>& aPolygons)
+    : mRoot(new BSPTreeNode(PopFront(aPolygons)))
+  {
+    BuildTree(mRoot, aPolygons);
+  }
+
+  // Returns the root node of the BSP tree.
+  const UniquePtr<BSPTreeNode>& GetRoot() const
+  {
+    return mRoot;
+  }
+
+  // Builds and returns the back-to-front draw order for the created BSP tree.
+  nsTArray<gfx::Polygon3D> GetDrawOrder() const
+  {
+    nsTArray<gfx::Polygon3D> polygons;
+    BuildDrawOrder(mRoot, polygons);
+    return polygons;
+  }
+
+private:
+  UniquePtr<BSPTreeNode> mRoot;
+
+  void BuildDrawOrder(const UniquePtr<BSPTreeNode>& aNode,
+                      nsTArray<gfx::Polygon3D>& aPolygons) const;
+
+  void BuildTree(UniquePtr<BSPTreeNode>& aRoot,
+                 std::deque<gfx::Polygon3D>& aPolygons);
+
+  nsTArray<float> CalculateDotProduct(const gfx::Polygon3D& aFirst,
+                                      const gfx::Polygon3D& aSecond,
+                                      size_t& aPos, size_t& aNeg) const;
+
+  void SplitPolygon(const gfx::Polygon3D& aSplittingPlane,
+                    const gfx::Polygon3D& aPolygon,
+                    const nsTArray<float>& dots,
+                    nsTArray<gfx::Point3D>& backPoints,
+                    nsTArray<gfx::Point3D>& frontPoints);
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif /* MOZILLA_LAYERS_BSPTREE_H */
\ No newline at end of file
--- a/gfx/layers/ImageDataSerializer.cpp
+++ b/gfx/layers/ImageDataSerializer.cpp
@@ -213,12 +213,38 @@ DataSourceSurfaceFromYCbCrDescriptor(uin
                          ySize,
                          map.mData,
                          map.mStride);
 
   result->Unmap();
   return result.forget();
 }
 
+void
+ConvertAndScaleFromYCbCrDescriptor(uint8_t* aBuffer,
+                                   const YCbCrDescriptor& aDescriptor,
+                                   const gfx::SurfaceFormat& aDestFormat,
+                                   const gfx::IntSize& aDestSize,
+                                   unsigned char* aDestBuffer,
+                                   int32_t aStride)
+{
+  MOZ_ASSERT(aBuffer);
+  gfx::IntSize ySize = aDescriptor.ySize();
+  gfx::IntSize cbCrSize = aDescriptor.cbCrSize();
+  int32_t yStride = ySize.width;
+  int32_t cbCrStride = cbCrSize.width;
+
+  layers::PlanarYCbCrData ycbcrData;
+  ycbcrData.mYChannel     = GetYChannel(aBuffer, aDescriptor);
+  ycbcrData.mYStride      = yStride;
+  ycbcrData.mYSize        = ySize;
+  ycbcrData.mCbChannel    = GetCbChannel(aBuffer, aDescriptor);
+  ycbcrData.mCrChannel    = GetCrChannel(aBuffer, aDescriptor);
+  ycbcrData.mCbCrStride   = cbCrStride;
+  ycbcrData.mCbCrSize     = cbCrSize;
+  ycbcrData.mPicSize      = ySize;
+
+  gfx::ConvertYCbCrToRGB(ycbcrData, aDestFormat, aDestSize, aDestBuffer, aStride);
+}
 
 } // namespace ImageDataSerializer
 } // namespace layers
 } // namespace mozilla
--- a/gfx/layers/ImageDataSerializer.h
+++ b/gfx/layers/ImageDataSerializer.h
@@ -66,14 +66,21 @@ uint8_t* GetYChannel(uint8_t* aBuffer, c
 
 uint8_t* GetCbChannel(uint8_t* aBuffer, const YCbCrDescriptor& aDescriptor);
 
 uint8_t* GetCrChannel(uint8_t* aBuffer, const YCbCrDescriptor& aDescriptor);
 
 already_AddRefed<gfx::DataSourceSurface>
 DataSourceSurfaceFromYCbCrDescriptor(uint8_t* aBuffer, const YCbCrDescriptor& aDescriptor, gfx::DataSourceSurface* aSurface = nullptr);
 
+void ConvertAndScaleFromYCbCrDescriptor(uint8_t* aBuffer,
+                                        const YCbCrDescriptor& aDescriptor,
+                                        const gfx::SurfaceFormat& aDestFormat,
+                                        const gfx::IntSize& aDestSize,
+                                        unsigned char* aDestBuffer,
+                                        int32_t aStride);
+
 } // ImageDataSerializer
 
 } // namespace layers
 } // namespace mozilla
 
 #endif
--- a/gfx/layers/Layers.h
+++ b/gfx/layers/Layers.h
@@ -31,17 +31,17 @@
 #include "mozilla/gfx/Point.h"          // for IntSize
 #include "mozilla/gfx/TiledRegion.h"    // for TiledIntRegion
 #include "mozilla/gfx/Types.h"          // for SurfaceFormat
 #include "mozilla/gfx/UserData.h"       // for UserData, etc
 #include "mozilla/layers/LayersTypes.h"
 #include "mozilla/mozalloc.h"           // for operator delete, etc
 #include "nsAutoPtr.h"                  // for nsAutoPtr, nsRefPtr, etc
 #include "nsCOMPtr.h"                   // for already_AddRefed
-#include "nsCSSProperty.h"              // for nsCSSProperty
+#include "nsCSSPropertyID.h"              // for nsCSSPropertyID
 #include "nsDebug.h"                    // for NS_ASSERTION
 #include "nsISupportsImpl.h"            // for Layer::Release, etc
 #include "nsRect.h"                     // for mozilla::gfx::IntRect
 #include "nsRegion.h"                   // for nsIntRegion
 #include "nsString.h"                   // for nsCString
 #include "nsTArray.h"                   // for nsTArray
 #include "nsTArrayForwardDeclare.h"     // for InfallibleTArray
 #include "nscore.h"                     // for nsACString, nsAString
--- a/gfx/layers/TiledLayerBuffer.h
+++ b/gfx/layers/TiledLayerBuffer.h
@@ -137,17 +137,17 @@ inline int RoundDownToTileEdge(int aX, i
 
 template<typename Derived, typename Tile>
 class TiledLayerBuffer
 {
 public:
   TiledLayerBuffer()
     : mTiles(0, 0, 0, 0)
     , mResolution(1)
-    , mTileSize(gfxVars::TileSize())
+    , mTileSize(mozilla::gfx::gfxVars::TileSize())
   {}
 
   ~TiledLayerBuffer() {}
 
   gfx::IntPoint GetTileOffset(TileIntPoint aPosition) const {
     gfx::IntSize scaledTileSize = GetScaledTileSize();
     return gfx::IntPoint(aPosition.x * scaledTileSize.width,
                          aPosition.y * scaledTileSize.height) + mTileOrigin;
--- a/gfx/layers/apz/test/reftest/reftest.list
+++ b/gfx/layers/apz/test/reftest/reftest.list
@@ -1,16 +1,16 @@
 # The following tests test the async positioning of the scrollbars.
 # Basic root-frame scrollbar with async scrolling
 skip-if(!asyncPan) fuzzy-if(Android,6,8) == async-scrollbar-1-v.html async-scrollbar-1-v-ref.html
 skip-if(!asyncPan) fuzzy-if(Android,6,8) == async-scrollbar-1-h.html async-scrollbar-1-h-ref.html
 skip-if(!asyncPan) fuzzy-if(Android,6,8) == async-scrollbar-1-vh.html async-scrollbar-1-vh-ref.html
 skip-if(!asyncPan) fuzzy-if(Android,6,8) == async-scrollbar-1-v-rtl.html async-scrollbar-1-v-rtl-ref.html
 skip-if(!asyncPan) fuzzy-if(Android,13,8) == async-scrollbar-1-h-rtl.html async-scrollbar-1-h-rtl-ref.html
-skip-if(!asyncPan) fuzzy-if(Android,8,11) == async-scrollbar-1-vh-rtl.html async-scrollbar-1-vh-rtl-ref.html
+skip-if(!asyncPan) fuzzy-if(Android,8,10) == async-scrollbar-1-vh-rtl.html async-scrollbar-1-vh-rtl-ref.html
 
 # Different async zoom levels. Since the scrollthumb gets async-scaled in the
 # compositor, the border-radius ends of the scrollthumb are going to be a little
 # off, hence the fuzzy-if clauses.
 skip-if(!asyncZoom) fuzzy-if(B2G,98,82) == async-scrollbar-zoom-1.html async-scrollbar-zoom-1-ref.html
 skip-if(!asyncZoom) fuzzy-if(B2G,94,146) == async-scrollbar-zoom-2.html async-scrollbar-zoom-2-ref.html
 
 # Meta-viewport tag support
--- a/gfx/layers/basic/BasicCompositor.cpp
+++ b/gfx/layers/basic/BasicCompositor.cpp
@@ -167,16 +167,35 @@ public:
   }
 
   void SetBufferTextureHost(BufferTextureHost* aTexture) override
   {
     mTexture = aTexture;
     mNeedsUpdate = true;
   }
 
+  void ConvertAndScale(const SurfaceFormat& aDestFormat,
+                       const IntSize& aDestSize,
+                       unsigned char* aDestBuffer,
+                       int32_t aStride)
+  {
+    MOZ_ASSERT(mTexture);
+    if (!mTexture) {
+      return;
+    }
+    MOZ_ASSERT(mTexture->GetBufferDescriptor().type() == BufferDescriptor::TYCbCrDescriptor);
+    MOZ_ASSERT(mTexture->GetSize() == mSize);
+    ImageDataSerializer::ConvertAndScaleFromYCbCrDescriptor(
+      mTexture->GetBuffer(),
+      mTexture->GetBufferDescriptor().get_YCbCrDescriptor(),
+      aDestFormat,
+      aDestSize,
+      aDestBuffer,
+      aStride);
+  }
 public:
   BufferTextureHost* mTexture;
   const gfx::IntSize mSize;
   RefPtr<gfx::DataSourceSurface> mSurface;
   bool mNeedsUpdate;
 };
 
 BasicCompositor::BasicCompositor(CompositorBridgeParent* aParent, widget::CompositorWidget* aWidget)
@@ -454,16 +473,73 @@ AttemptVideoScale(TextureSourceBasic* aS
 
     aDest->ReleaseBits(dstData);
     return true;
   } else
 #endif // MOZILLA_SSE_HAVE_CPUID_DETECTION
     return false;
 }
 
+static bool
+AttemptVideoConvertAndScale(TextureSource* aSource, const SourceSurface* aSourceMask,
+                            gfx::Float aOpacity, CompositionOp aBlendMode,
+                            const TexturedEffect* aTexturedEffect,
+                            const Matrix& aNewTransform, const gfx::Rect& aRect,
+                            const gfx::Rect& aClipRect,
+                            DrawTarget* aDest, const DrawTarget* aBuffer)
+{
+  WrappingTextureSourceYCbCrBasic* wrappingSource = aSource->AsWrappingTextureSourceYCbCrBasic();
+  if (!wrappingSource)
+    return false;
+#ifdef MOZILLA_SSE_HAVE_CPUID_DETECTION
+  if (!mozilla::supports_ssse3()) // libyuv requests SSSE3 for fast YUV conversion.
+    return false;
+  if (aNewTransform.HasNonAxisAlignedTransform() || aNewTransform.HasNegativeScaling())
+      return false;
+  if (aSourceMask || aOpacity != 1.0f)
+    return false;
+  if (aBlendMode != CompositionOp::OP_OVER && aBlendMode != CompositionOp::OP_SOURCE)
+    return false;
+
+  IntRect dstRect;
+  // the compiler should know a lot about aNewTransform at this point
+  // maybe it can do some sophisticated optimization of the following
+  if (!aNewTransform.TransformBounds(aRect).ToIntRect(&dstRect))
+    return false;
+
+  IntRect clipRect;
+  if (!aClipRect.ToIntRect(&clipRect))
+    return false;
+
+  if (!(aTexturedEffect->mTextureCoords == Rect(0.0f, 0.0f, 1.0f, 1.0f)))
+    return false;
+  if (aDest->GetFormat() == SurfaceFormat::R5G6B5_UINT16)
+    return false;
+
+  if (aDest == aBuffer && !clipRect.Contains(dstRect))
+    return false;
+  if (!IntRect(IntPoint(0, 0), aDest->GetSize()).Contains(dstRect))
+    return false;
+
+  uint8_t* dstData;
+  IntSize dstSize;
+  int32_t dstStride;
+  SurfaceFormat dstFormat;
+  if (aDest->LockBits(&dstData, &dstSize, &dstStride, &dstFormat)) {
+    wrappingSource->ConvertAndScale(dstFormat,
+                                    dstRect.Size(),
+                                    dstData + ptrdiff_t(dstRect.x) * BytesPerPixel(dstFormat) + ptrdiff_t(dstRect.y) * dstStride,
+                                    dstStride);
+    aDest->ReleaseBits(dstData);
+    return true;
+  } else
+#endif // MOZILLA_SSE_HAVE_CPUID_DETECTION
+    return false;
+}
+
 void
 BasicCompositor::DrawQuad(const gfx::Rect& aRect,
                           const gfx::IntRect& aClipRect,
                           const EffectChain &aEffectChain,
                           gfx::Float aOpacity,
                           const gfx::Matrix4x4& aTransform,
                           const gfx::Rect& aVisibleRect)
 {
@@ -548,16 +624,22 @@ BasicCompositor::DrawQuad(const gfx::Rec
     case EffectTypes::RGB: {
       TexturedEffect* texturedEffect =
           static_cast<TexturedEffect*>(aEffectChain.mPrimaryEffect.get());
       TextureSourceBasic* source = texturedEffect->mTexture->AsSourceBasic();
 
       if (source && texturedEffect->mPremultiplied) {
         // we have a fast path for video here
         if (source->mFromYCBCR &&
+            AttemptVideoConvertAndScale(texturedEffect->mTexture, sourceMask, aOpacity, blendMode,
+                                        texturedEffect,
+                                        newTransform, aRect, transformedClipRect,
+                                        dest, buffer)) {
+          // we succeeded in convert and scaling
+        } else if (source->mFromYCBCR &&
             AttemptVideoScale(source, sourceMask, aOpacity, blendMode,
                               texturedEffect,
                               newTransform, aRect, transformedClipRect,
                               dest, buffer)) {
           // we succeeded in scaling
         } else {
           DrawSurfaceWithTextureCoords(dest, aRect,
                                        source->GetSurface(dest),
--- a/gfx/layers/d3d11/CompositorD3D11.cpp
+++ b/gfx/layers/d3d11/CompositorD3D11.cpp
@@ -1515,17 +1515,17 @@ CompositorD3D11::HandleError(HRESULT hr,
     return;
   }
 
   if (aSeverity == Critical) {
     MOZ_CRASH("GFX: Unrecoverable D3D11 error");
   }
 
   if (mDevice && DeviceManagerD3D11::Get()->GetCompositorDevice() != mDevice) {
-    gfxCriticalError() << "Out of sync D3D11 devices in HandleError, " << (int)mVerifyBuffersFailed;
+    gfxCriticalNote << "Out of sync D3D11 devices in HandleError, " << (int)mVerifyBuffersFailed;
   }
 
   HRESULT hrOnReset = S_OK;
   bool deviceRemoved = hr == DXGI_ERROR_DEVICE_REMOVED;
 
   if (deviceRemoved && mDevice) {
     hrOnReset = mDevice->GetDeviceRemovedReason();
   } else if (hr == DXGI_ERROR_INVALID_CALL && mDevice) {
--- a/gfx/layers/ipc/LayersMessages.ipdlh
+++ b/gfx/layers/ipc/LayersMessages.ipdlh
@@ -23,17 +23,17 @@ using struct mozilla::gfx::Point3D from 
 using mozilla::gfx::IntPoint from "mozilla/gfx/Point.h";
 using class mozilla::gfx::Matrix4x4 from "mozilla/gfx/Matrix.h";
 using nscoord from "nsCoord.h";
 using struct nsRect from "nsRect.h";
 using struct nsPoint from "nsPoint.h";
 using class mozilla::TimeDuration from "mozilla/TimeStamp.h";
 using class mozilla::TimeStamp from "mozilla/TimeStamp.h";
 using mozilla::ScreenRotation from "mozilla/WidgetUtils.h";
-using nsCSSProperty from "nsCSSProperty.h";
+using nsCSSPropertyID from "nsCSSPropertyID.h";
 using mozilla::dom::ScreenOrientationInternal from "mozilla/dom/ScreenOrientation.h";
 using struct mozilla::layers::TextureInfo from "mozilla/layers/CompositorTypes.h";
 using mozilla::LayerMargin from "Units.h";
 using mozilla::LayerPoint from "Units.h";
 using mozilla::LayerRect from "Units.h";
 using mozilla::LayerIntRegion from "Units.h";
 using mozilla::ParentLayerIntRect from "Units.h";
 using mozilla::LayoutDeviceIntRect from "Units.h";
@@ -194,17 +194,17 @@ struct Animation {
   AnimationSegment[] segments;
   // Number of times to repeat the animation, including positive infinity.
   // Values <= 0 mean the animation will not play (although events are still
   // dispatched on the main thread).
   float iterations;
   float iterationStart;
   // This uses the NS_STYLE_ANIMATION_DIRECTION_* constants.
   int32_t direction;
-  nsCSSProperty property;
+  nsCSSPropertyID property;
   AnimationData data;
   float playbackRate;
   // This is used in the transformed progress calculation.
   TimingFunction easingFunction;
 };
 
 // Change a layer's attributes
 struct CommonLayerAttributes {
--- a/gfx/layers/moz.build
+++ b/gfx/layers/moz.build
@@ -119,16 +119,17 @@ EXPORTS.mozilla.layers += [
     'apz/util/TouchActionHelper.h',
     'AsyncCanvasRenderer.h',
     'AtomicRefCountedWithFinalize.h',
     'AxisPhysicsModel.h',
     'AxisPhysicsMSDModel.h',
     'basic/BasicCompositor.h',
     'basic/MacIOSurfaceTextureHostBasic.h',
     'basic/TextureHostBasic.h',
+    'BSPTree.h',
     'BufferTexture.h',
     'client/CanvasClient.h',
     'client/CompositableClient.h',
     'client/ContentClient.h',
     'client/ImageClient.h',
     'client/SingleTiledContentClient.h',
     'client/TextureClient.h',
     'client/TextureClientPool.h',
@@ -297,16 +298,17 @@ UNIFIED_SOURCES += [
     'basic/BasicColorLayer.cpp',
     'basic/BasicCompositor.cpp',
     'basic/BasicContainerLayer.cpp',
     'basic/BasicImages.cpp',
     'basic/BasicLayerManager.cpp',
     'basic/BasicLayersImpl.cpp',
     'basic/BasicPaintedLayer.cpp',
     'basic/TextureHostBasic.cpp',
+    'BSPTree.cpp',
     'BufferTexture.cpp',
     'BufferUnrotate.cpp',
     'client/CanvasClient.cpp',
     'client/ClientCanvasLayer.cpp',
     'client/ClientColorLayer.cpp',
     'client/ClientContainerLayer.cpp',
     'client/ClientImageLayer.cpp',
     'client/ClientLayerManager.cpp',
--- a/gfx/ots/README.mozilla
+++ b/gfx/ots/README.mozilla
@@ -1,11 +1,11 @@
 This is the Sanitiser for OpenType project, from http://code.google.com/p/ots/.
 
 Our reference repository is https://github.com/khaledhosny/ots/.
 
-Current revision: 99a3b7ff8fb241e0f68a25a41726cc3421d1f9bf
+Current revision: 8d70cffebbfa58f67a5c3ed0e9bc84dccdbc5bc0
 
 Upstream files included: LICENSE, src/, include/
 
 Additional files: README.mozilla, src/moz.build
 
 Additional patch: ots-visibility.patch (bug 711079).
--- a/gfx/ots/src/cmap.cc
+++ b/gfx/ots/src/cmap.cc
@@ -277,17 +277,17 @@ bool Parse31012(ots::Font *font,
   if (language) {
     return OTS_FAILURE_MSG("format 12 subtable language should be zero (%d)", language);
   }
 
   uint32_t num_groups = 0;
   if (!subtable.ReadU32(&num_groups)) {
     return OTS_FAILURE_MSG("can't read number of format 12 subtable groups");
   }
-  if (num_groups == 0 || subtable.remaining() < num_groups * 12) {
+  if (num_groups == 0 || subtable.remaining() / 12 < num_groups) {
     return OTS_FAILURE_MSG("Bad format 12 subtable group count %d", num_groups);
   }
 
   std::vector<ots::OpenTypeCMAPSubtableRange> &groups
       = font->cmap->subtable_3_10_12;
   groups.resize(num_groups);
 
   for (unsigned i = 0; i < num_groups; ++i) {
@@ -351,17 +351,17 @@ bool Parse31013(ots::Font *font,
 
   uint32_t num_groups = 0;
   if (!subtable.ReadU32(&num_groups)) {
     return OTS_FAILURE_MSG("Can't read number of groups in a cmap subtable");
   }
 
   // We limit the number of groups in the same way as in 3.10.12 tables. See
   // the comment there in
-  if (num_groups == 0 || subtable.remaining() < num_groups * 12) {
+  if (num_groups == 0 || subtable.remaining() / 12 < num_groups) {
     return OTS_FAILURE_MSG("Bad format 13 subtable group count %d", num_groups);
   }
 
   std::vector<ots::OpenTypeCMAPSubtableRange> &groups
       = font->cmap->subtable_3_10_13;
   groups.resize(num_groups);
 
   for (unsigned i = 0; i < num_groups; ++i) {
@@ -459,17 +459,17 @@ bool Parse0514(ots::Font *font,
   for (unsigned i = 0; i < num_records; ++i) {
     // Checks default UVS table
     if (records[i].default_offset) {
       subtable.set_offset(records[i].default_offset);
       uint32_t num_ranges = 0;
       if (!subtable.ReadU32(&num_ranges)) {
         return OTS_FAILURE_MSG("Can't read number of ranges in record %d", i);
       }
-      if (num_ranges == 0 || subtable.remaining() < num_ranges * 4) {
+      if (num_ranges == 0 || subtable.remaining() / 4 < num_ranges) {
         return OTS_FAILURE_MSG("Bad number of ranges (%d) in record %d", num_ranges, i);
       }
 
       uint32_t last_unicode_value = 0;
       std::vector<ots::OpenTypeCMAPSubtableVSRange>& ranges
           = records[i].ranges;
       ranges.resize(num_ranges);
 
@@ -493,17 +493,17 @@ bool Parse0514(ots::Font *font,
 
     // Checks non default UVS table
     if (records[i].non_default_offset) {
       subtable.set_offset(records[i].non_default_offset);
       uint32_t num_mappings = 0;
       if (!subtable.ReadU32(&num_mappings)) {
         return OTS_FAILURE_MSG("Can't read number of mappings in variation selector record %d", i);
       }
-      if (num_mappings == 0 || subtable.remaining() < num_mappings * 5) {
+      if (num_mappings == 0 || subtable.remaining() / 5 < num_mappings) {
         return OTS_FAILURE_MSG("Bad number of mappings (%d) in variation selector record %d", num_mappings, i);
       }
 
       uint32_t last_unicode_value = 0;
       std::vector<ots::OpenTypeCMAPSubtableVSMapping>& mappings
           = records[i].mappings;
       mappings.resize(num_mappings);
 
@@ -653,30 +653,31 @@ bool ots_cmap_parse(Font *font, const ui
       default:
         subtable_headers[i].length = 0;
         subtable_headers[i].language = 0;
         break;
     }
   }
 
   // check if the table is sorted first by platform ID, then by encoding ID.
-  uint32_t last_id = 0;
-  for (unsigned i = 0; i < num_tables; ++i) {
-    uint32_t current_id
-        = (subtable_headers[i].platform << 24)
-        + (subtable_headers[i].encoding << 16)
-        + subtable_headers[i].language;
-    if ((i != 0) && (last_id >= current_id)) {
+  for (unsigned i = 1; i < num_tables; ++i) {
+    if (subtable_headers[i - 1].platform > subtable_headers[i].platform ||
+        (subtable_headers[i - 1].platform == subtable_headers[i].platform &&
+         (subtable_headers[i - 1].encoding > subtable_headers[i].encoding ||
+          (subtable_headers[i - 1].encoding == subtable_headers[i].encoding &&
+           subtable_headers[i - 1].language > subtable_headers[i].language))))
       OTS_WARNING("subtable %d with platform ID %d, encoding ID %d, language ID %d "
                   "following subtable with platform ID %d, encoding ID %d, language ID %d",
                   i,
-                  (uint8_t)(current_id >> 24), (uint8_t)(current_id >> 16), (uint8_t)(current_id),
-                  (uint8_t)(last_id >> 24), (uint8_t)(last_id >> 16), (uint8_t)(last_id));
-    }
-    last_id = current_id;
+                  subtable_headers[i].platform,
+                  subtable_headers[i].encoding,
+                  subtable_headers[i].language,
+                  subtable_headers[i - 1].platform,
+                  subtable_headers[i - 1].encoding,
+                  subtable_headers[i - 1].language);
   }
 
   // Now, verify that all the lengths are sane
   for (unsigned i = 0; i < num_tables; ++i) {
     if (!subtable_headers[i].length) continue;
     if (subtable_headers[i].length > 1024 * 1024 * 1024) {
       return OTS_FAILURE_MSG("Bad cmap subtable %d length", i);
     }
--- a/gfx/ots/src/layout.cc
+++ b/gfx/ots/src/layout.cc
@@ -90,19 +90,24 @@ bool ParseScriptTable(const ots::Font *f
   uint16_t lang_sys_count = 0;
   if (!subtable.ReadU16(&offset_default_lang_sys) ||
       !subtable.ReadU16(&lang_sys_count)) {
     return OTS_FAILURE_MSG("Failed to read script header for script tag %c%c%c%c", OTS_UNTAG(tag));
   }
 
   // The spec requires a script table for 'DFLT' tag must contain non-NULL
   // |offset_default_lang_sys| and |lang_sys_count| == 0
-  if (tag == kScriptTableTagDflt &&
-      (offset_default_lang_sys == 0 || lang_sys_count != 0)) {
-    return OTS_FAILURE_MSG("DFLT table doesn't satisfy the spec. for script tag %c%c%c%c", OTS_UNTAG(tag));
+  // https://www.microsoft.com/typography/otspec/chapter2.htm
+  if (tag == kScriptTableTagDflt) {
+    if (offset_default_lang_sys == 0) {
+      return OTS_FAILURE_MSG("DFLT script doesn't satisfy the spec. DefaultLangSys is NULL");
+    }
+    if (lang_sys_count != 0) {
+      return OTS_FAILURE_MSG("DFLT script doesn't satisfy the spec. LangSysCount is not zero: %d", lang_sys_count);
+    }
   }
 
   const unsigned lang_sys_record_end =
       6 * static_cast<unsigned>(lang_sys_count) + 4;
   if (lang_sys_record_end > std::numeric_limits<uint16_t>::max()) {
     return OTS_FAILURE_MSG("Bad end of langsys record %d for script tag %c%c%c%c", lang_sys_record_end, OTS_UNTAG(tag));
   }
 
--- a/gfx/ots/src/math.cc
+++ b/gfx/ots/src/math.cc
@@ -443,16 +443,21 @@ bool ParseMathGlyphConstructionTable(con
 bool ParseMathGlyphConstructionSequence(const ots::Font *font,
                                         ots::Buffer* subtable,
                                         const uint8_t *data,
                                         size_t length,
                                         const uint16_t num_glyphs,
                                         uint16_t offset_coverage,
                                         uint16_t glyph_count,
                                         const unsigned sequence_end) {
+  // Zero glyph count, nothing to parse.
+  if (!glyph_count) {
+    return true;
+  }
+
   // Check coverage table.
   if (offset_coverage < sequence_end || offset_coverage >= length) {
     return OTS_FAILURE();
   }
   if (!ots::ParseCoverageTable(font, data + offset_coverage,
                                length - offset_coverage,
                                num_glyphs, glyph_count)) {
     return OTS_FAILURE();
new file mode 100644
--- /dev/null
+++ b/gfx/tests/gtest/TestBSPTree.cpp
@@ -0,0 +1,1124 @@
+/* -*- Mode: C++; 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/. */
+
+#include "BSPTree.h"
+#include "Polygon.h"
+
+#include "gtest/gtest.h"
+
+#include <deque>
+
+using mozilla::layers::BSPTree;
+using mozilla::gfx::Point3D;
+using mozilla::gfx::Polygon3D;
+
+namespace
+{
+
+// Compares two points while allowing some numerical inaccuracy.
+static bool FuzzyCompare(const Point3D& lhs, const Point3D& rhs)
+{
+  const float epsilon = 0.001f;
+  const Point3D d = lhs - rhs;
+
+  return (abs(d.x) > epsilon || abs(d.y) > epsilon || abs(d.z) > epsilon);
+}
+
+// Compares the points of two polygons and ensures
+// that the points are in the same winding order.
+static bool operator==(const Polygon3D& lhs, const Polygon3D& rhs)
+{
+  const nsTArray<Point3D>& left = lhs.GetPoints();
+  const nsTArray<Point3D>& right = rhs.GetPoints();
+
+  // Polygons do not have the same amount of points.
+  if (left.Length() != right.Length()) {
+    return false;
+  }
+
+  const size_t pointCount = left.Length();
+
+  // Find the first vertex of the first polygon from the second polygon.
+  // This assumes that the polygons do not contain duplicate vertices.
+  int start = -1;
+  for (size_t i = 0; i < pointCount; ++i) {
+    if (FuzzyCompare(left[0], right[i])) {
+      start = i;
+      break;
+    }
+  }
+
+  // Found at least one different vertex.
+  if (start == -1) {
+    return false;
+  }
+
+  // Verify that the polygons have the same points.
+  for (size_t i = 0; i < pointCount; ++i) {
+    size_t j = (start + i) % pointCount;
+
+    if (!FuzzyCompare(left[i], right[j])) {
+      return false;
+    }
+  }
+
+  return true;
+}
+
+static void RunTest(std::deque<Polygon3D> aPolygons,
+                    std::deque<Polygon3D> aExpected)
+{
+  const BSPTree tree(aPolygons);
+  const nsTArray<Polygon3D> order = tree.GetDrawOrder();
+
+  EXPECT_EQ(order.Length(), aExpected.size());
+
+  for (size_t i = 0; i < order.Length(); ++i) {
+    EXPECT_TRUE(order[i] == aExpected[i]);
+  }
+}
+
+}
+
+TEST(BSPTree, SameNode)
+{
+  const std::deque<Polygon3D> polygons {
+    Polygon3D {
+      Point3D(0.0f, 0.0f, 0.0f),
+      Point3D(1.0f, 0.0f, 0.0f),
+      Point3D(1.0f, 1.0f, 0.0f),
+      Point3D(0.0f, 1.0f, 0.0f)
+    },
+    Polygon3D {
+      Point3D(0.0f, 0.0f, 0.0f),
+      Point3D(1.0f, 0.0f, 0.0f),
+      Point3D(1.0f, 1.0f, 0.0f),
+      Point3D(0.0f, 1.0f, 0.0f)
+    }
+  };
+
+  ::RunTest(polygons, polygons);
+}
+
+TEST(BSPTree, OneChild)
+{
+  const Polygon3D p1 {
+    Point3D(0.0f, 0.0f, 0.0f),
+    Point3D(1.0f, 0.0f, 0.0f),
+    Point3D(1.0f, 1.0f, 0.0f),
+    Point3D(0.0f, 1.0f, 0.0f)
+  };
+
+  const Polygon3D p2 {
+    Point3D(0.0f, 0.0f, 1.0f),
+    Point3D(1.0f, 0.0f, 1.0f),
+    Point3D(1.0f, 1.0f, 1.0f),
+    Point3D(0.0f, 1.0f, 1.0f)
+  };
+
+  ::RunTest(std::deque<Polygon3D> {p1, p2}, {p1, p2});
+  ::RunTest(std::deque<Polygon3D> {p2, p1}, {p1, p2});
+}
+
+TEST(BSPTree, SplitSimple1)
+{
+  Polygon3D p1 {
+    Point3D(0.0f, 0.0f, 1.0f),
+    Point3D(1.0f, 0.0f, 1.0f),
+    Point3D(1.0f, 1.0f, 1.0f),
+    Point3D(0.0f, 1.0f, 1.0f)
+  };
+
+  Polygon3D p2 {
+    Point3D(0.0f, 0.0f, 2.0f),
+    Point3D(1.0f, 0.0f, 2.0f),
+    Point3D(1.0f, 1.0f, 0.0f),
+    Point3D(0.0f, 1.0f, 0.0f)
+  };
+
+  const std::deque<Polygon3D> expected {
+    Polygon3D {
+      Point3D(0.0f, 1.0f, 0.0f),
+      Point3D(0.0f, 0.5f, 1.0f),
+      Point3D(1.0f, 0.5f, 1.0f),
+      Point3D(1.0f, 1.0f, 0.0f)
+    },
+    p1,
+    Polygon3D {
+      Point3D(0.0f, 0.0f, 2.0f),
+      Point3D(1.0f, 0.0f, 2.0f),
+      Point3D(1.0f, 0.5f, 1.0f),
+      Point3D(0.0f, 0.5f, 1.0f)
+    }
+  };
+
+  ::RunTest({p1, p2}, expected);
+}
+
+TEST(BSPTree, SplitSimple2) {
+  const std::deque<Polygon3D> polygons {
+    Polygon3D {
+      Point3D(-5.00000f, -5.00000f, 0.00000f),
+      Point3D(-5.00000f, 5.00000f, 0.00000f),
+      Point3D(5.00000f, 5.00000f, 0.00000f),
+      Point3D(5.00000f, -5.00000f, 0.00000f)
+    },
+    Polygon3D {
+      Point3D(0.00000f, -5.00000f, -5.00000f),
+      Point3D(0.00000f, 5.00000f, -5.00000f),
+      Point3D(0.00000f, 5.00000f, 5.00000f),
+      Point3D(0.00000f, -5.00000f, 5.00000f)
+    }
+  };
+
+  const std::deque<Polygon3D> expected {
+    Polygon3D {
+      Point3D(0.00000f, -5.00000f, 0.00000f),
+      Point3D(0.00000f, -5.00000f, -5.00000f),
+      Point3D(0.00000f, 5.00000f, -5.00000f),
+      Point3D(0.00000f, 5.00000f, 0.00000f)
+    },
+    Polygon3D {
+      Point3D(-5.00000f, -5.00000f, 0.00000f),
+      Point3D(-5.00000f, 5.00000f, 0.00000f),
+      Point3D(5.00000f, 5.00000f, 0.00000f),
+      Point3D(5.00000f, -5.00000f, 0.00000f)
+    },
+    Polygon3D {
+      Point3D(0.00000f, 5.00000f, 0.00000f),
+      Point3D(0.00000f, 5.00000f, 5.00000f),
+      Point3D(0.00000f, -5.00000f, 5.00000f),
+      Point3D(0.00000f, -5.00000f, 0.00000f)
+    }
+  };
+  ::RunTest(polygons, expected);
+}
+
+TEST(BSPTree, NoSplit1) {
+  const std::deque<Polygon3D> polygons {
+    Polygon3D {
+      Point3D(0.00000f, 10.00000f, 0.00000f),
+      Point3D(0.00000f, 0.00000f, 0.00000f),
+      Point3D(10.00000f, 0.00000f, 0.00000f),
+      Point3D(10.00000f, 10.00000f, 0.00000f)
+    },
+    Polygon3D {
+      Point3D(0.00000f, 10.00000f, -5.00000f),
+      Point3D(0.00000f, 0.00000f, -5.00000f),
+      Point3D(10.00000f, 0.00000f, -5.00000f),
+      Point3D(10.00000f, 10.00000f, -5.00000f)
+    },
+    Polygon3D {
+      Point3D(0.00000f, 10.00000f, 5.00000f),
+      Point3D(0.00000f, 0.00000f, 5.00000f),
+      Point3D(10.00000f, 0.00000f, 5.00000f),
+      Point3D(10.00000f, 10.00000f, 5.00000f)
+    }
+  };
+
+  const std::deque<Polygon3D> expected {
+    Polygon3D {
+      Point3D(0.00000f, 10.00000f, -5.00000f),
+      Point3D(0.00000f, 0.00000f, -5.00000f),
+      Point3D(10.00000f, 0.00000f, -5.00000f),
+      Point3D(10.00000f, 10.00000f, -5.00000f)
+    },
+    Polygon3D {
+      Point3D(0.00000f, 10.00000f, 0.00000f),
+      Point3D(0.00000f, 0.00000f, 0.00000f),
+      Point3D(10.00000f, 0.00000f, 0.00000f),
+      Point3D(10.00000f, 10.00000f, 0.00000f)
+    },
+    Polygon3D {
+      Point3D(0.00000f, 10.00000f, 5.00000f),
+      Point3D(0.00000f, 0.00000f, 5.00000f),
+      Point3D(10.00000f, 0.00000f, 5.00000f),
+      Point3D(10.00000f, 10.00000f, 5.00000f)
+    }
+  };
+  ::RunTest(polygons, expected);
+}
+
+TEST(BSPTree, NoSplit2) {
+  const std::deque<Polygon3D> polygons {
+    Polygon3D {
+      Point3D(-5.00000f, -5.00000f, 0.00000f),
+      Point3D(-5.00000f, 5.00000f, 0.00000f),
+      Point3D(5.00000f, 5.00000f, 0.00000f),
+      Point3D(5.00000f, -5.00000f, 0.00000f)
+    },
+    Polygon3D {
+      Point3D(0.00000f, 5.00000f, -15.00000f),
+      Point3D(0.00000f, -5.00000f, -15.00000f),
+      Point3D(0.00000f, -5.00000f, -10.00000f),
+      Point3D(0.00000f, 5.00000f, -10.00000f)
+    }
+  };
+
+  const std::deque<Polygon3D> expected {
+    Polygon3D {
+      Point3D(0.00000f, 5.00000f, -15.00000f),
+      Point3D(0.00000f, -5.00000f, -15.00000f),
+      Point3D(0.00000f, -5.00000f, -10.00000f),
+      Point3D(0.00000f, 5.00000f, -10.00000f)
+    },
+    Polygon3D {
+      Point3D(-5.00000f, -5.00000f, 0.00000f),
+      Point3D(-5.00000f, 5.00000f, 0.00000f),
+      Point3D(5.00000f, 5.00000f, 0.00000f),
+      Point3D(5.00000f, -5.00000f, 0.00000f)
+    }
+  };
+  ::RunTest(polygons, expected);
+}
+
+TEST(BSPTree, SplitComplex1) {
+  const std::deque<Polygon3D> polygons {
+    Polygon3D {
+      Point3D(0.00000f, -5.00000f, -15.00000f),
+      Point3D(0.00000f, 5.00000f, -15.00000f),
+      Point3D(0.00000f, 5.00000f, -10.00000f),
+      Point3D(0.00000f, -5.00000f, -10.00000f)
+    },
+    Polygon3D {
+      Point3D(-5.00000f, -5.00000f, 0.00000f),
+      Point3D(-5.00000f, 5.00000f, 0.00000f),
+      Point3D(5.00000f, 5.00000f, 0.00000f),
+      Point3D(5.00000f, -5.00000f, 0.00000f)
+    }
+  };
+
+  const std::deque<Polygon3D> expected {
+    Polygon3D {
+      Point3D(0.00000f, 5.00000f, 0.00000f),
+      Point3D(5.00000f, 5.00000f, 0.00000f),
+      Point3D(5.00000f, -5.00000f, 0.00000f),
+      Point3D(0.00000f, -5.00000f, 0.00000f)
+    },
+    Polygon3D {
+      Point3D(0.00000f, -5.00000f, -15.00000f),
+      Point3D(0.00000f, 5.00000f, -15.00000f),
+      Point3D(0.00000f, 5.00000f, -10.00000f),
+      Point3D(0.00000f, -5.00000f, -10.00000f)
+    },
+    Polygon3D {
+      Point3D(0.00000f, -5.00000f, 0.00000f),
+      Point3D(-5.00000f, -5.00000f, 0.00000f),
+      Point3D(-5.00000f, 5.00000f, 0.00000f),
+      Point3D(0.00000f, 5.00000f, 0.00000f)
+    }
+  };
+  ::RunTest(polygons, expected);
+}
+
+TEST(BSPTree, SplitComplex2) {
+  const std::deque<Polygon3D> polygons {
+    Polygon3D {
+      Point3D(-5.00000f, -5.00000f, 0.00000f),
+      Point3D(-5.00000f, 5.00000f, 0.00000f),
+      Point3D(5.00000f, 5.00000f, 0.00000f),
+      Point3D(5.00000f, -5.00000f, 0.00000f)
+    },
+    Polygon3D {
+      Point3D(0.00000f, -5.00000f, -5.00000f),
+      Point3D(0.00000f, 5.00000f, -5.00000f),
+      Point3D(0.00000f, 5.00000f, 5.00000f),
+      Point3D(0.00000f, -5.00000f, 5.00000f)
+    },
+    Polygon3D {
+      Point3D(-5.00000f, 0.00000f, -5.00000f),
+      Point3D(-5.00000f, 0.00000f, 5.00000f),
+      Point3D(5.00000f, 0.00000f, 5.00000f),
+      Point3D(5.00000f, 0.00000f, -5.00000f)
+    }
+  };
+
+  const std::deque<Polygon3D> expected {
+    Polygon3D {
+      Point3D(0.00000f, 0.00000f, 0.00000f),
+      Point3D(5.00000f, 0.00000f, 0.00000f),
+      Point3D(5.00000f, 0.00000f, -5.00000f),
+      Point3D(0.00000f, 0.00000f, -5.00000f)
+    },
+    Polygon3D {
+      Point3D(0.00000f, -5.00000f, 0.00000f),
+      Point3D(0.00000f, -5.00000f, -5.00000f),
+      Point3D(0.00000f, 5.00000f, -5.00000f),
+      Point3D(0.00000f, 5.00000f, 0.00000f)
+    },
+    Polygon3D {
+      Point3D(0.00000f, 0.00000f, -5.00000f),
+      Point3D(-5.00000f, 0.00000f, -5.00000f),
+      Point3D(-5.00000f, 0.00000f, 0.00000f),
+      Point3D(0.00000f, 0.00000f, 0.00000f)
+    },
+    Polygon3D {
+      Point3D(-5.00000f, -5.00000f, 0.00000f),
+      Point3D(-5.00000f, 5.00000f, 0.00000f),
+      Point3D(5.00000f, 5.00000f, 0.00000f),
+      Point3D(5.00000f, -5.00000f, 0.00000f)
+    },
+    Polygon3D {
+      Point3D(0.00000f, 0.00000f, 5.00000f),
+      Point3D(5.00000f, 0.00000f, 5.00000f),
+      Point3D(5.00000f, 0.00000f, 0.00000f),
+      Point3D(0.00000f, 0.00000f, 0.00000f)
+    },
+    Polygon3D {
+      Point3D(0.00000f, 5.00000f, 0.00000f),
+      Point3D(0.00000f, 5.00000f, 5.00000f),
+      Point3D(0.00000f, -5.00000f, 5.00000f),
+      Point3D(0.00000f, -5.00000f, 0.00000f)
+    },
+    Polygon3D {
+      Point3D(0.00000f, 0.00000f, 0.00000f),
+      Point3D(-5.00000f, 0.00000f, 0.00000f),
+      Point3D(-5.00000f, 0.00000f, 5.00000f),
+      Point3D(0.00000f, 0.00000f, 5.00000f)
+    }
+  };
+  ::RunTest(polygons, expected);
+}
+
+TEST(BSPTree, TwoPlaneIntersectRotate0degrees) {
+  const std::deque<Polygon3D> polygons {
+    Polygon3D {
+      Point3D(-0.00000f, 2.00000f, 2.00000f),
+      Point3D(-0.00000f, -2.00000f, 2.00000f),
+      Point3D(0.00010f, -2.00000f, -2.00000f),
+      Point3D(0.00010f, 2.00000f, -2.00000f)
+    },
+    Polygon3D {
+      Point3D(2.00000f, 0.00000f, 2.00000f),
+      Point3D(2.00000f, -0.00000f, -2.00000f),
+      Point3D(-2.00000f, 0.00000f, -2.00000f),
+      Point3D(-2.00000f, 0.00010f, 2.00000f)
+    }
+  };
+
+  const std::deque<Polygon3D> expected {
+    Polygon3D {
+      Point3D(0.00010f, 0.00000f, -2.00000f),
+      Point3D(-2.00000f, 0.00000f, -2.00000f),
+      Point3D(-2.00000f, 0.00010f, 2.00000f),
+      Point3D(0.00000f, 0.00005f, 2.00000f)
+    },
+    Polygon3D {
+      Point3D(-0.00000f, 2.00000f, 2.00000f),
+      Point3D(-0.00000f, -2.00000f, 2.00000f),
+      Point3D(0.00010f, -2.00000f, -2.00000f),
+      Point3D(0.00010f, 2.00000f, -2.00000f)
+    },
+    Polygon3D {
+      Point3D(0.00000f, 0.00005f, 2.00000f),
+      Point3D(2.00000f, 0.00000f, 2.00000f),
+      Point3D(2.00000f, -0.00000f, -2.00000f),
+      Point3D(0.00010f, 0.00000f, -2.00000f)
+    }
+  };
+  ::RunTest(polygons, expected);
+}
+
+TEST(BSPTree, TwoPlaneIntersectRotate20degrees) {
+  const std::deque<Polygon3D> polygons {
+    Polygon3D {
+      Point3D(-0.00000f, 1.19540f, 2.56350f),
+      Point3D(-0.00000f, -2.56340f, 1.19540f),
+      Point3D(0.00010f, -1.19530f, -2.56340f),
+      Point3D(0.00010f, 2.56350f, -1.19530f)
+    },
+    Polygon3D {
+      Point3D(2.00000f, -0.68400f, 1.87940f),
+      Point3D(2.00000f, 0.68410f, -1.87930f),
+      Point3D(-2.00000f, 0.68410f, -1.87930f),
+      Point3D(-2.00000f, -0.68400f, 1.87940f)
+    }
+  };
+
+  const std::deque<Polygon3D> expected {
+    Polygon3D {
+      Point3D(0.00010f, 0.68410f, -1.87930f),
+      Point3D(-2.00000f, 0.68410f, -1.87930f),
+      Point3D(-2.00000f, -0.68400f, 1.87940f),
+      Point3D(0.00000f, -0.68400f, 1.87940f)
+    },
+    Polygon3D {
+      Point3D(-0.00000f, 1.19540f, 2.56350f),
+      Point3D(-0.00000f, -2.56340f, 1.19540f),
+      Point3D(0.00010f, -1.19530f, -2.56340f),
+      Point3D(0.00010f, 2.56350f, -1.19530f)
+    },
+    Polygon3D {
+      Point3D(0.00000f, -0.68400f, 1.87940f),
+      Point3D(2.00000f, -0.68400f, 1.87940f),
+      Point3D(2.00000f, 0.68410f, -1.87930f),
+      Point3D(0.00010f, 0.68410f, -1.87930f)
+    }
+  };
+  ::RunTest(polygons, expected);
+}
+
+TEST(BSPTree, TwoPlaneIntersectRotate40degrees) {
+  const std::deque<Polygon3D> polygons {
+    Polygon3D {
+      Point3D(-0.00000f, -0.73200f, 2.73210f),
+      Point3D(-0.00000f, -2.73200f, -0.73200f),
+      Point3D(0.00010f, 0.73210f, -2.73200f),
+      Point3D(0.00010f, 2.73210f, 0.73210f)
+    },
+    Polygon3D {
+      Point3D(2.00000f, -1.73200f, 1.00000f),
+      Point3D(2.00000f, 1.73210f, -0.99990f),
+      Point3D(-2.00000f, 1.73210f, -0.99990f),
+      Point3D(-2.00000f, -1.73200f, 1.00000f)
+    }
+  };
+
+  const std::deque<Polygon3D> expected {
+    Polygon3D {
+      Point3D(0.00010f, 1.73210f, -0.99990f),
+      Point3D(-2.00000f, 1.73210f, -0.99990f),
+      Point3D(-2.00000f, -1.73200f, 1.00000f),
+      Point3D(0.00000f, -1.73200f, 1.00000f)
+    },
+    Polygon3D {
+      Point3D(-0.00000f, -0.73200f, 2.73210f),
+      Point3D(-0.00000f, -2.73200f, -0.73200f),
+      Point3D(0.00010f, 0.73210f, -2.73200f),
+      Point3D(0.00010f, 2.73210f, 0.73210f)
+    },
+    Polygon3D {
+      Point3D(0.00000f, -1.73200f, 1.00000f),
+      Point3D(2.00000f, -1.73200f, 1.00000f),
+      Point3D(2.00000f, 1.73210f, -0.99990f),
+      Point3D(0.00010f, 1.73210f, -0.99990f)
+    }
+  };
+  ::RunTest(polygons, expected);
+}
+
+TEST(BSPTree, TwoPlaneIntersectRotate60degrees) {
+  const std::deque<Polygon3D> polygons {
+    Polygon3D {
+      Point3D(-0.00000f, -2.73200f, 0.73210f),
+      Point3D(-0.00000f, -0.73200f, -2.73200f),
+      Point3D(0.00010f, 2.73210f, -0.73200f),
+      Point3D(0.00010f, 0.73210f, 2.73210f)
+    },
+    Polygon3D {
+      Point3D(2.00000f, -1.73200f, -1.00000f),
+      Point3D(2.00000f, 1.73210f, 1.00010f),
+      Point3D(-2.00000f, 1.73210f, 1.00010f),
+      Point3D(-2.00000f, -1.73200f, -1.00000f)
+    }
+  };
+
+  const std::deque<Polygon3D> expected {
+    Polygon3D {
+      Point3D(0.00000f, -1.73200f, -1.00000f),
+      Point3D(2.00000f, -1.73200f, -1.00000f),
+      Point3D(2.00000f, 1.73210f, 1.00010f),
+      Point3D(0.00010f, 1.73210f, 1.00010f)
+    },
+    Polygon3D {
+      Point3D(-0.00000f, -2.73200f, 0.73210f),
+      Point3D(-0.00000f, -0.73200f, -2.73200f),
+      Point3D(0.00010f, 2.73210f, -0.73200f),
+      Point3D(0.00010f, 0.73210f, 2.73210f)
+    },
+    Polygon3D {
+      Point3D(0.00010f, 1.73210f, 1.00010f),
+      Point3D(-2.00000f, 1.73210f, 1.00010f),
+      Point3D(-2.00000f, -1.73200f, -1.00000f),
+      Point3D(0.00000f, -1.73200f, -1.00000f)
+    }
+  };
+  ::RunTest(polygons, expected);
+}
+
+TEST(BSPTree, TwoPlaneIntersectRotate80degrees) {
+  const std::deque<Polygon3D> polygons {
+    Polygon3D {
+      Point3D(-0.00000f, -1.19530f, -2.56340f),
+      Point3D(-0.00000f, 2.56350f, -1.19530f),
+      Point3D(0.00010f, 1.19540f, 2.56350f),
+      Point3D(0.00010f, -2.56340f, 1.19540f)
+    },
+    Polygon3D {
+      Point3D(2.00000f, 0.68410f, -1.87930f),
+      Point3D(2.00000f, -0.68400f, 1.87940f),
+      Point3D(-2.00000f, -0.68400f, 1.87940f),
+      Point3D(-2.00000f, 0.68410f, -1.87930f)
+    }
+  };
+
+  const std::deque<Polygon3D> expected {
+    Polygon3D {
+      Point3D(0.00000f, 0.68410f, -1.87930f),
+      Point3D(2.00000f, 0.68410f, -1.87930f),
+      Point3D(2.00000f, -0.68400f, 1.87940f),
+      Point3D(0.00010f, -0.68400f, 1.87940f)
+    },
+    Polygon3D {
+      Point3D(-0.00000f, -1.19530f, -2.56340f),
+      Point3D(-0.00000f, 2.56350f, -1.19530f),
+      Point3D(0.00010f, 1.19540f, 2.56350f),
+      Point3D(0.00010f, -2.56340f, 1.19540f)
+    },
+    Polygon3D {
+      Point3D(0.00010f, -0.68400f, 1.87940f),
+      Point3D(-2.00000f, -0.68400f, 1.87940f),
+      Point3D(-2.00000f, 0.68410f, -1.87930f),
+      Point3D(0.00000f, 0.68410f, -1.87930f)
+    }
+  };
+  ::RunTest(polygons, expected);
+}
+
+TEST(BSPTree, TwoPlaneIntersectRotate100degrees) {
+  const std::deque<Polygon3D> polygons {
+    Polygon3D {
+      Point3D(-0.00000f, 2.73210f, -0.73200f),
+      Point3D(-0.00000f, 0.73210f, 2.73210f),
+      Point3D(0.00010f, -2.73200f, 0.73210f),
+      Point3D(0.00010f, -0.73200f, -2.73200f)
+    },
+    Polygon3D {
+      Point3D(2.00000f, 1.73210f, 1.00010f),
+      Point3D(2.00000f, -1.73200f, -1.00000f),
+      Point3D(-2.00000f, -1.73200f, -1.00000f),
+      Point3D(-2.00000f, 1.73210f, 1.00010f)
+    }
+  };
+
+  const std::deque<Polygon3D> expected {
+    Polygon3D {
+      Point3D(0.00010f, -1.73200f, -1.00000f),
+      Point3D(-2.00000f, -1.73200f, -1.00000f),
+      Point3D(-2.00000f, 1.73210f, 1.00010f),
+      Point3D(0.00000f, 1.73210f, 1.00010f)
+    },
+    Polygon3D {
+      Point3D(-0.00000f, 2.73210f, -0.73200f),
+      Point3D(-0.00000f, 0.73210f, 2.73210f),
+      Point3D(0.00010f, -2.73200f, 0.73210f),
+      Point3D(0.00010f, -0.73200f, -2.73200f)
+    },
+    Polygon3D {
+      Point3D(0.00000f, 1.73210f, 1.00010f),
+      Point3D(2.00000f, 1.73210f, 1.00010f),
+      Point3D(2.00000f, -1.73200f, -1.00000f),
+      Point3D(0.00010f, -1.73200f, -1.00000f)
+    }
+  };
+  ::RunTest(polygons, expected);
+}
+
+TEST(BSPTree, TwoPlaneIntersectRotate120degrees) {
+  const std::deque<Polygon3D> polygons {
+    Polygon3D {
+      Point3D(-0.00000f, -0.73200f, 2.73210f),
+      Point3D(-0.00000f, -2.73200f, -0.73200f),
+      Point3D(0.00010f, 0.73210f, -2.73200f),
+      Point3D(0.00010f, 2.73210f, 0.73210f)
+    },
+    Polygon3D {
+      Point3D(2.00000f, -1.73200f, 1.00000f),
+      Point3D(2.00000f, 1.73210f, -0.99990f),
+      Point3D(-2.00000f, 1.73210f, -0.99990f),
+      Point3D(-2.00000f, -1.73200f, 1.00000f)
+    }
+  };
+
+  const std::deque<Polygon3D> expected {
+    Polygon3D {
+      Point3D(0.00010f, 1.73210f, -0.99990f),
+      Point3D(-2.00000f, 1.73210f, -0.99990f),
+      Point3D(-2.00000f, -1.73200f, 1.00000f),
+      Point3D(0.00000f, -1.73200f, 1.00000f)
+    },
+    Polygon3D {
+      Point3D(-0.00000f, -0.73200f, 2.73210f),
+      Point3D(-0.00000f, -2.73200f, -0.73200f),
+      Point3D(0.00010f, 0.73210f, -2.73200f),
+      Point3D(0.00010f, 2.73210f, 0.73210f)
+    },
+    Polygon3D {
+      Point3D(0.00000f, -1.73200f, 1.00000f),
+      Point3D(2.00000f, -1.73200f, 1.00000f),
+      Point3D(2.00000f, 1.73210f, -0.99990f),
+      Point3D(0.00010f, 1.73210f, -0.99990f)
+    }
+  };
+  ::RunTest(polygons, expected);
+}
+
+TEST(BSPTree, TwoPlaneIntersectRotate140degrees) {
+  const std::deque<Polygon3D> polygons {
+    Polygon3D {
+      Point3D(-0.00000f, -1.19530f, -2.56340f),
+      Point3D(-0.00000f, 2.56350f, -1.19530f),
+      Point3D(0.00010f, 1.19540f, 2.56350f),
+      Point3D(0.00010f, -2.56340f, 1.19540f)
+    },
+    Polygon3D {
+      Point3D(2.00000f, 0.68410f, -1.87930f),
+      Point3D(2.00000f, -0.68400f, 1.87940f),
+      Point3D(-2.00000f, -0.68400f, 1.87940f),
+      Point3D(-2.00000f, 0.68410f, -1.87930f)
+    }
+  };
+
+  const std::deque<Polygon3D> expected {
+    Polygon3D {
+      Point3D(0.00000f, 0.68410f, -1.87930f),
+      Point3D(2.00000f, 0.68410f, -1.87930f),
+      Point3D(2.00000f, -0.68400f, 1.87940f),
+      Point3D(0.00010f, -0.68400f, 1.87940f)
+    },
+    Polygon3D {
+      Point3D(-0.00000f, -1.19530f, -2.56340f),
+      Point3D(-0.00000f, 2.56350f, -1.19530f),
+      Point3D(0.00010f, 1.19540f, 2.56350f),
+      Point3D(0.00010f, -2.56340f, 1.19540f)
+    },
+    Polygon3D {
+      Point3D(0.00010f, -0.68400f, 1.87940f),
+      Point3D(-2.00000f, -0.68400f, 1.87940f),
+      Point3D(-2.00000f, 0.68410f, -1.87930f),
+      Point3D(0.00000f, 0.68410f, -1.87930f)
+    }
+  };
+  ::RunTest(polygons, expected);
+}
+
+TEST(BSPTree, TwoPlaneIntersectRotate160degrees) {
+  const std::deque<Polygon3D> polygons {
+    Polygon3D {
+      Point3D(-0.00000f, 2.00000f, 2.00000f),
+      Point3D(-0.00000f, -2.00000f, 2.00000f),
+      Point3D(0.00010f, -2.00000f, -2.00000f),
+      Point3D(0.00010f, 2.00000f, -2.00000f)
+    },
+    Polygon3D {
+      Point3D(2.00000f, -0.00000f, 2.00000f),
+      Point3D(2.00000f, 0.00010f, -2.00000f),
+      Point3D(-2.00000f, 0.00010f, -2.00000f),
+      Point3D(-2.00000f, -0.00000f, 2.00000f)
+    }
+  };
+
+  const std::deque<Polygon3D> expected {
+    Polygon3D {
+      Point3D(0.00010f, 0.00010f, -2.00000f),
+      Point3D(-2.00000f, 0.00010f, -2.00000f),
+      Point3D(-2.00000f, -0.00000f, 2.00000f),
+      Point3D(0.00000f, 0.00000f, 2.00000f)
+    },
+    Polygon3D {
+      Point3D(-0.00000f, 2.00000f, 2.00000f),
+      Point3D(-0.00000f, -2.00000f, 2.00000f),
+      Point3D(0.00010f, -2.00000f, -2.00000f),
+      Point3D(0.00010f, 2.00000f, -2.00000f)
+    },
+    Polygon3D {
+      Point3D(0.00000f, 0.00000f, 2.00000f),
+      Point3D(2.00000f, -0.00000f, 2.00000f),
+      Point3D(2.00000f, 0.00010f, -2.00000f),
+      Point3D(0.00010f, 0.00010f, -2.00000f)
+    }
+  };
+  ::RunTest(polygons, expected);
+}
+
+TEST(BSPTree, TwoPlaneIntersectRotate180degrees) {
+  const std::deque<Polygon3D> polygons {
+    Polygon3D {
+      Point3D(-0.00000f, -2.00000f, -2.00000f),
+      Point3D(-0.00000f, 2.00000f, -2.00000f),
+      Point3D(0.00010f, 2.00000f, 2.00000f),
+      Point3D(0.00010f, -2.00000f, 2.00000f)
+    },
+    Polygon3D {
+      Point3D(2.00000f, 0.00010f, -2.00000f),
+      Point3D(2.00000f, -0.00000f, 2.00000f),
+      Point3D(-2.00000f, -0.00000f, 2.00000f),
+      Point3D(-2.00000f, 0.00010f, -2.00000f)
+    }
+  };
+
+  const std::deque<Polygon3D> expected {
+    Polygon3D {
+      Point3D(0.00000f, 0.00010f, -2.00000f),
+      Point3D(2.00000f, 0.00010f, -2.00000f),
+      Point3D(2.00000f, -0.00000f, 2.00000f),
+      Point3D(0.00010f, 0.00000f, 2.00000f)
+    },
+    Polygon3D {
+      Point3D(-0.00000f, -2.00000f, -2.00000f),
+      Point3D(-0.00000f, 2.00000f, -2.00000f),
+      Point3D(0.00010f, 2.00000f, 2.00000f),
+      Point3D(0.00010f, -2.00000f, 2.00000f)
+    },
+    Polygon3D {
+      Point3D(0.00010f, 0.00000f, 2.00000f),
+      Point3D(-2.00000f, -0.00000f, 2.00000f),
+      Point3D(-2.00000f, 0.00010f, -2.00000f),
+      Point3D(0.00000f, 0.00010f, -2.00000f)
+    }
+  };
+  ::RunTest(polygons, expected);
+}
+
+TEST(BSPTree, TwoPlaneIntersectRotate200degrees) {
+  const std::deque<Polygon3D> polygons {
+    Polygon3D {
+      Point3D(-0.00000f, 1.19540f, 2.56350f),
+      Point3D(-0.00000f, -2.56340f, 1.19540f),
+      Point3D(0.00010f, -1.19530f, -2.56340f),