merge mozilla-inbound to mozilla-central a=merge
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Mon, 20 Oct 2014 14:34:56 +0200
changeset 235523 cc2d8bdbccb86454ee315f42eb0d998f87d789ca
parent 235304 ca6b46cbca3b356900f7ad9713ecaaf0035a12f0 (current diff)
parent 235522 62ac7c28ddae3742c32daafe3198a9c6965ead83 (diff)
child 235555 f2d7d694aae5bda8957b0d20c6922f40f487d231
push id4311
push userraliiev@mozilla.com
push dateMon, 12 Jan 2015 19:37:41 +0000
treeherdermozilla-beta@150c9fed433b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone36.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
merge mozilla-inbound to mozilla-central a=merge
dom/plugins/test/reftest/plugin-async-update-ref.html
dom/plugins/test/reftest/plugin-asyncbitmap-sanity.html
dom/plugins/test/reftest/plugin-asyncbitmap-update.html
dom/plugins/test/reftest/plugin-asyncdxgi-sanity.html
dom/plugins/test/reftest/plugin-asyncdxgi-update.html
gfx/graphite2/src/Makefile.in
gfx/thebes/nsSurfaceTexture.cpp
gfx/thebes/nsSurfaceTexture.h
js/src/tests/ecma_6/TypedObject/simd/float32x4shuffle.js
js/src/tests/ecma_6/TypedObject/simd/float32x4shufflemix.js
js/src/tests/ecma_6/TypedObject/simd/int32x4shuffle.js
js/src/tests/ecma_6/TypedObject/simd/int32x4shufflemix.js
js/src/tests/ecma_6/TypedObject/simd/shufflemaskconstants.js
layout/build/nsLayoutModule.cpp
media/libvpx/mingw.patch
media/libvpx/unified.patch
media/libvpx/vp8/common/arm/neon/bilinearpredict16x16_neon.asm
media/libvpx/vp8/common/arm/neon/bilinearpredict4x4_neon.asm
media/libvpx/vp8/common/arm/neon/bilinearpredict8x4_neon.asm
media/libvpx/vp8/common/arm/neon/bilinearpredict8x8_neon.asm
media/libvpx/vp8/common/arm/neon/buildintrapredictorsmby_neon.asm
media/libvpx/vp8/common/arm/neon/copymem16x16_neon.asm
media/libvpx/vp8/common/arm/neon/copymem8x4_neon.asm
media/libvpx/vp8/common/arm/neon/copymem8x8_neon.asm
media/libvpx/vp8/common/arm/neon/dc_only_idct_add_neon.asm
media/libvpx/vp8/common/arm/neon/dequant_idct_neon.asm
media/libvpx/vp8/common/arm/neon/dequantizeb_neon.asm
media/libvpx/vp8/common/arm/neon/idct_dequant_0_2x_neon.asm
media/libvpx/vp8/common/arm/neon/idct_dequant_full_2x_neon.asm
media/libvpx/vp8/common/arm/neon/iwalsh_neon.asm
media/libvpx/vp8/common/arm/neon/loopfilter_neon.asm
media/libvpx/vp8/common/arm/neon/loopfiltersimplehorizontaledge_neon.asm
media/libvpx/vp8/common/arm/neon/loopfiltersimpleverticaledge_neon.asm
media/libvpx/vp8/common/arm/neon/mbloopfilter_neon.asm
media/libvpx/vp8/common/arm/neon/sad16_neon.asm
media/libvpx/vp8/common/arm/neon/sad8_neon.asm
media/libvpx/vp8/common/arm/neon/save_reg_neon.asm
media/libvpx/vp8/common/arm/neon/shortidct4x4llm_neon.asm
media/libvpx/vp8/common/arm/neon/sixtappredict16x16_neon.asm
media/libvpx/vp8/common/arm/neon/sixtappredict4x4_neon.asm
media/libvpx/vp8/common/arm/neon/sixtappredict8x4_neon.asm
media/libvpx/vp8/common/arm/neon/sixtappredict8x8_neon.asm
media/libvpx/vp8/common/arm/neon/variance_neon.asm
media/libvpx/vp8/common/arm/neon/vp8_subpixelvariance16x16_neon.asm
media/libvpx/vp8/common/arm/neon/vp8_subpixelvariance16x16s_neon.asm
media/libvpx/vp8/common/arm/neon/vp8_subpixelvariance8x8_neon.asm
media/libvpx/vp8/common/arm/reconintra_arm.c
media/libvpx/vp8/common/pragmas.h
media/libvpx/vp8/common/x86/loopfilter_block_sse2.asm
media/libvpx/vp8/common/x86/postproc_x86.c
media/libvpx/vp8/decoder/decodframe.c
media/libvpx/vp8/encoder/arm/neon/picklpf_arm.c
media/libvpx/vp8/encoder/arm/neon/shortfdct_neon.asm
media/libvpx/vp8/encoder/arm/neon/subtract_neon.asm
media/libvpx/vp8/encoder/arm/neon/vp8_memcpy_neon.asm
media/libvpx/vp8/encoder/arm/neon/vp8_shortwalsh4x4_neon.asm
media/libvpx/vp8/encoder/psnr.c
media/libvpx/vp8/encoder/psnr.h
media/libvpx/vp8/encoder/x86/quantize_sse4.asm
media/libvpx/vp8/encoder/x86/quantize_ssse3.asm
media/libvpx/vp9/common/arm/neon/vp9_short_idct16x16_1_add_neon.asm
media/libvpx/vp9/common/arm/neon/vp9_short_idct16x16_add_neon.asm
media/libvpx/vp9/common/arm/neon/vp9_short_idct32x32_1_add_neon.asm
media/libvpx/vp9/common/arm/neon/vp9_short_idct32x32_add_neon.asm
media/libvpx/vp9/common/arm/neon/vp9_short_idct4x4_1_add_neon.asm
media/libvpx/vp9/common/arm/neon/vp9_short_idct4x4_add_neon.asm
media/libvpx/vp9/common/arm/neon/vp9_short_idct8x8_1_add_neon.asm
media/libvpx/vp9/common/arm/neon/vp9_short_idct8x8_add_neon.asm
media/libvpx/vp9/common/arm/neon/vp9_short_iht4x4_add_neon.asm
media/libvpx/vp9/common/arm/neon/vp9_short_iht8x8_add_neon.asm
media/libvpx/vp9/common/generic/vp9_systemdependent.c
media/libvpx/vp9/common/vp9_default_coef_probs.h
media/libvpx/vp9/common/vp9_extend.c
media/libvpx/vp9/common/vp9_extend.h
media/libvpx/vp9/common/vp9_findnearmv.c
media/libvpx/vp9/common/vp9_findnearmv.h
media/libvpx/vp9/common/vp9_onyx.h
media/libvpx/vp9/common/vp9_pragmas.h
media/libvpx/vp9/common/vp9_sadmxn.h
media/libvpx/vp9/common/vp9_treecoder.c
media/libvpx/vp9/common/vp9_treecoder.h
media/libvpx/vp9/common/x86/vp9_postproc_mmx.asm
media/libvpx/vp9/common/x86/vp9_postproc_x86.h
media/libvpx/vp9/decoder/vp9_dboolhuff.c
media/libvpx/vp9/decoder/vp9_dboolhuff.h
media/libvpx/vp9/decoder/vp9_decodframe.c
media/libvpx/vp9/decoder/vp9_decodframe.h
media/libvpx/vp9/decoder/vp9_onyxd.h
media/libvpx/vp9/decoder/vp9_onyxd_if.c
media/libvpx/vp9/decoder/vp9_onyxd_int.h
media/libvpx/vp9/decoder/vp9_thread.c
media/libvpx/vp9/decoder/vp9_thread.h
media/libvpx/vp9/decoder/vp9_treereader.h
media/libvpx/vp9/encoder/vp9_boolhuff.c
media/libvpx/vp9/encoder/vp9_boolhuff.h
media/libvpx/vp9/encoder/vp9_dct.h
media/libvpx/vp9/encoder/vp9_encodeintra.c
media/libvpx/vp9/encoder/vp9_encodeintra.h
media/libvpx/vp9/encoder/vp9_modecosts.c
media/libvpx/vp9/encoder/vp9_modecosts.h
media/libvpx/vp9/encoder/vp9_onyx_if.c
media/libvpx/vp9/encoder/vp9_onyx_int.h
media/libvpx/vp9/encoder/vp9_psnr.c
media/libvpx/vp9/encoder/vp9_psnr.h
media/libvpx/vp9/encoder/vp9_sad_c.c
media/libvpx/vp9/encoder/vp9_vaq.c
media/libvpx/vp9/encoder/vp9_vaq.h
media/libvpx/vp9/encoder/vp9_variance_c.c
media/libvpx/vp9/encoder/x86/vp9_mcomp_x86.h
media/libvpx/vp9/encoder/x86/vp9_quantize_ssse3.asm
media/libvpx/vp9/encoder/x86/vp9_sad_mmx.asm
media/libvpx/vp9/encoder/x86/vp9_subpel_variance_impl_sse2.asm
media/libvpx/vp9/encoder/x86/vp9_variance_impl_mmx.asm
media/libvpx/vp9/encoder/x86/vp9_variance_impl_sse2.asm
media/libvpx/vp9/encoder/x86/vp9_variance_mmx.c
media/libvpx/vpx_ports/x86_cpuid.c
media/libvpx/vpx_scale/arm/neon/vp8_vpxyv12_copy_y_neon.asm
media/libvpx/vpx_scale/arm/neon/vp8_vpxyv12_copyframe_func_neon.asm
media/libvpx/vpx_scale/arm/neon/vp8_vpxyv12_copysrcframe_func_neon.asm
media/libvpx/vpx_scale/arm/neon/vp8_vpxyv12_extendframeborders_neon.asm
media/libvpx/vpx_scale/arm/neon/yv12extend_arm.c
testing/mochitest/tests/browser/moz.build
testing/web-platform/meta/shadow-dom/elements-and-dom-objects/shadowroot-object/shadowroot-attributes/test-014.html.ini
--- 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 609976 - CLOBBER 
+Bug 609976 needs a CLOBBER on Windows again.
--- a/addon-sdk/source/lib/sdk/content/sandbox.js
+++ b/addon-sdk/source/lib/sdk/content/sandbox.js
@@ -171,17 +171,17 @@ const WorkerSandbox = Class({
     let options = 'contentScriptOptions' in worker ?
       JSON.stringify(worker.contentScriptOptions) :
       undefined;
 
     // Then call `inject` method and communicate with this script
     // by trading two methods that allow to send events to the other side:
     //   - `onEvent` called by content script
     //   - `result.emitToContent` called by addon script
-    let onEvent = onContentEvent.bind(null, this);
+    let onEvent = Cu.exportFunction(onContentEvent.bind(null, this), ContentWorker);
     let chromeAPI = createChromeAPI(ContentWorker);
     let result = Cu.waiveXrays(ContentWorker).inject(content, chromeAPI, onEvent, options);
 
     // Merge `emitToContent` into our private model of the
     // WorkerSandbox so we can communicate with content script
     model.emitToContent = result;
 
     let console = new PlainTextConsole(null, getInnerId(window));
--- a/addon-sdk/source/lib/sdk/deprecated/traits-worker.js
+++ b/addon-sdk/source/lib/sdk/deprecated/traits-worker.js
@@ -78,17 +78,17 @@ const WorkerSandbox = EventEmitter.compo
   /**
    * Synchronous version of `emit`.
    * /!\ Should only be used when it is strictly mandatory /!\
    *     Doesn't ensure passing only JSON values.
    *     Mainly used by context-menu in order to avoid breaking it.
    */
   emitSync: function emitSync() {
     let args = Array.slice(arguments);
-    return this._emitToContent(args);
+    return this._emitToContent(Cu.cloneInto(args, this._addonWorker._window));
   },
 
   /**
    * Method called by the worker sandbox when it needs to send a message
    */
   _onContentEvent: function onContentEvent(args) {
     // As `emit`, we ensure having an asynchronous behavior
     let self = this;
@@ -190,17 +190,17 @@ const WorkerSandbox = EventEmitter.compo
         setInterval: timer.setInterval.bind(timer),
         clearTimeout: timer.clearTimeout.bind(timer),
         clearInterval: timer.clearInterval.bind(timer),
       },
       sandbox: {
         evaluate: evaluate,
       },
     }, ContentWorker, {cloneFunctions: true});
-    let onEvent = this._onContentEvent.bind(this);
+    let onEvent = Cu.exportFunction(this._onContentEvent.bind(this), ContentWorker);
     let result = Cu.waiveXrays(ContentWorker).inject(content, chromeAPI, onEvent, options);
     this._emitToContent = result;
 
     // Handle messages send by this script:
     let self = this;
     // console.xxx calls
     this.on("console", function consoleListener(kind) {
       console[kind].apply(console, Array.slice(arguments, 1));
--- a/browser/base/content/test/general/browser.ini
+++ b/browser/base/content/test/general/browser.ini
@@ -84,16 +84,19 @@ support-files =
   video.ogg
   zoom_test.html
   test_no_mcb_on_http_site_img.html
   test_no_mcb_on_http_site_img.css
   test_no_mcb_on_http_site_font.html
   test_no_mcb_on_http_site_font.css
   test_no_mcb_on_http_site_font2.html
   test_no_mcb_on_http_site_font2.css
+  test_mcb_redirect.html
+  test_mcb_redirect.js
+  test_mcb_redirect.sjs
   xul_tooltiptext.xhtml
   file_bug1045809_1.html
   file_bug1045809_2.html
 
 [browser_URLBarSetURI.js]
 skip-if = (os == "linux" || os == "mac") && debug # bug 970052, bug 970053
 [browser_aboutAccounts.js]
 skip-if = os == "linux" # Bug 958026
@@ -498,8 +501,10 @@ skip-if = e10s
 [browser_bug1025195_switchToTabHavingURI_ignoreFragment.js]
 [browser_addCertException.js]
 skip-if = e10s # Bug ?????? - test directly manipulates content (content.document.getElementById)
 [browser_bug1045809.js]
 skip-if = e10s # Bug 1068360 - [e10s] Mixed content blocker doorhanger doesn't work
 [browser_e10s_switchbrowser.js]
 [browser_blockHPKP.js]
 skip-if = e10s # bug ?????? - test directly manipulates content (content.document.getElementById)
+[browser_mcb_redirect.js]
+skip-if = e10s # bug 1084504 - [e10s] Mixed content detection does not take redirection into account
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/general/browser_mcb_redirect.js
@@ -0,0 +1,110 @@
+/*
+ * Description of the Tests for
+ *  - Bug 418354 - Call Mixed content blocking on redirects
+ *
+ * 1. Load a script over https inside an https page
+ *    - the server responds with a 302 redirect to a >> HTTP << script
+ *    - the doorhanger should appear!
+ *
+ * 2. Load a script over https inside an http page
+ *    - the server responds with a 302 redirect to a >> HTTP << script
+ *    - the doorhanger should not appear!
+ */
+
+const PREF_ACTIVE = "security.mixed_content.block_active_content";
+const gHttpsTestRoot = "https://example.com/browser/browser/base/content/test/general/";
+const gHttpTestRoot = "http://example.com/browser/browser/base/content/test/general/";
+
+let origBlockActive;
+var gTestBrowser = null;
+
+//------------------------ Helper Functions ---------------------
+
+registerCleanupFunction(function() {
+  // Set preferences back to their original values
+  Services.prefs.setBoolPref(PREF_ACTIVE, origBlockActive);
+});
+
+function cleanUpAfterTests() {
+  gBrowser.removeCurrentTab();
+  window.focus();
+  finish();
+}
+
+function waitForCondition(condition, nextTest, errorMsg, okMsg) {
+  var tries = 0;
+  var interval = setInterval(function() {
+    if (tries >= 30) {
+      ok(false, errorMsg);
+      moveOn();
+    }
+    if (condition()) {
+      ok(true, okMsg)
+      moveOn();
+    }
+    tries++;
+  }, 100);
+  var moveOn = function() {
+    clearInterval(interval); nextTest();
+  };
+}
+
+//------------------------ Test 1 ------------------------------
+
+function test1() {
+  gTestBrowser.addEventListener("load", checkPopUpNotificationsForTest1, true);
+  var url = gHttpsTestRoot + "test_mcb_redirect.html"
+  gTestBrowser.contentWindow.location = url;
+}
+
+function checkPopUpNotificationsForTest1() {
+  gTestBrowser.removeEventListener("load", checkPopUpNotificationsForTest1, true);
+
+  var notification = PopupNotifications.getNotification("bad-content", gTestBrowser.selectedBrowser);
+  ok(notification, "OK: Mixed Content Doorhanger appeared in Test1!");
+
+  var expected = "script blocked";
+  waitForCondition(
+    function() content.document.getElementById('mctestdiv').innerHTML == expected,
+    test2, "Error: Waited too long for status in Test 1!",
+    "OK: Expected result in innerHTML for Test1!");
+}
+
+//------------------------ Test 2 ------------------------------
+
+function test2() {
+  gTestBrowser.addEventListener("load", checkPopUpNotificationsForTest2, true);
+  var url = gHttpTestRoot + "test_mcb_redirect.html"
+  gTestBrowser.contentWindow.location = url;
+}
+
+function checkPopUpNotificationsForTest2() {
+  gTestBrowser.removeEventListener("load", checkPopUpNotificationsForTest2, true);
+
+  var notification = PopupNotifications.getNotification("bad-content", gTestBrowser.selectedBrowser);
+  ok(!notification, "OK: Mixed Content Doorhanger did not appear in 2!");
+
+  var expected = "script executed";
+  waitForCondition(
+    function() content.document.getElementById('mctestdiv').innerHTML == expected,
+    cleanUpAfterTests, "Error: Waited too long for status in Test 2!",
+    "OK: Expected result in innerHTML for Test2!");
+}
+
+//------------------------ SETUP ------------------------------
+
+function test() {
+  // Performing async calls, e.g. 'onload', we have to wait till all of them finished
+  waitForExplicitFinish();
+
+  // Store original preferences so we can restore settings after testing
+  origBlockActive = Services.prefs.getBoolPref(PREF_ACTIVE);
+  Services.prefs.setBoolPref(PREF_ACTIVE, true);
+
+  var newTab = gBrowser.addTab();
+  gBrowser.selectedTab = newTab;
+  gTestBrowser = gBrowser.selectedBrowser;
+  newTab.linkedBrowser.stop();
+
+  executeSoon(test1);
+}
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/general/test_mcb_redirect.html
@@ -0,0 +1,15 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+  Test 1 for Bug 418354 - See file browser_mcb_redirect.js for description.
+  https://bugzilla.mozilla.org/show_bug.cgi?id=418354
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Bug 418354</title>
+</head>
+<body>
+  <div id="mctestdiv">script blocked</div>
+  <script src="https://example.com/browser/browser/base/content/test/general/test_mcb_redirect.sjs" ></script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/general/test_mcb_redirect.js
@@ -0,0 +1,5 @@
+/*
+ * Once the mixed content blocker is disabled for the page, this scripts loads
+ * and updates the text inside the div container.
+ */
+document.getElementById("mctestdiv").innerHTML = "script executed";
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/general/test_mcb_redirect.sjs
@@ -0,0 +1,11 @@
+function handleRequest(request, response) {
+  var page = "<!DOCTYPE html><html><body>bug 418354</body></html>";
+
+  var redirect = "http://example.com/browser/browser/base/content/test/general/test_mcb_redirect.js";
+
+  response.setHeader("Cache-Control", "no-cache", false);
+  response.setHeader("Content-Type", "text/html", false);
+  response.setStatusLine(request.httpVersion, "302", "Found");
+  response.setHeader("Location", redirect, false);
+  response.write(page);
+}
--- a/browser/devtools/styleinspector/test/browser_ruleview_edit-selector_02.js
+++ b/browser/devtools/styleinspector/test/browser_ruleview_edit-selector_02.js
@@ -36,21 +36,21 @@ let test = asyncTest(function*() {
   yield testEditSelector(view, "div:nth-child(2)");
 
   info("Selecting the modified element");
   yield selectNode("#testid", inspector);
   yield checkModifiedElement(view, "div:nth-child(2)");
 
   info("Selecting the test element");
   yield selectNode("#testid3", inspector);
-  yield testEditSelector(view, ".testclass2:first-letter");
+  yield testEditSelector(view, ".testclass2::first-letter");
 
   info("Selecting the modified element");
   yield selectNode(".testclass2", inspector);
-  yield checkModifiedElement(view, ".testclass2:first-letter");
+  yield checkModifiedElement(view, ".testclass2::first-letter");
 });
 
 function* testEditSelector(view, name) {
   info("Test editing existing selector fields");
 
   let idRuleEditor = getRuleViewRuleEditor(view, 1) ||
     getRuleViewRuleEditor(view, 1, 0);
 
--- a/browser/installer/windows/nsis/shared.nsh
+++ b/browser/installer/windows/nsis/shared.nsh
@@ -177,31 +177,31 @@ FunctionEnd
 !ifdef MOZ_MAINTENANCE_SERVICE
   Call IsUserAdmin
   Pop $R0
   ${If} $R0 == "true"
   ; Only proceed if we have HKLM write access
   ${AndIf} $TmpVal == "HKLM"
   ; On Windows 2000 we do not install the maintenance service.
   ${AndIf} ${AtLeastWinXP}
-    ; Add the registry keys for allowed certificates.
-    ${AddMaintCertKeys}
-
     ; We check to see if the maintenance service install was already attempted.
     ; Since the Maintenance service can be installed either x86 or x64,
     ; always use the 64-bit registry for checking if an attempt was made.
     ${If} ${RunningX64}
       SetRegView 64
     ${EndIf}
     ReadRegDWORD $5 HKLM "Software\Mozilla\MaintenanceService" "Attempted"
     ClearErrors
     ${If} ${RunningX64}
       SetRegView lastused
     ${EndIf}
 
+    ; Add the registry keys for allowed certificates.
+    ${AddMaintCertKeys}
+
     ; If the maintenance service is already installed, do nothing.
     ; The maintenance service will launch:
     ; maintenanceservice_installer.exe /Upgrade to upgrade the maintenance
     ; service if necessary.   If the update was done from updater.exe without
     ; the service (i.e. service is failing), updater.exe will do the update of
     ; the service.  The reasons we do not do it here is because we don't want
     ; to have to prompt for limited user accounts when the service isn't used
     ; and we currently call the PostUpdate twice, once for the user and once
@@ -807,18 +807,28 @@ FunctionEnd
     ; More than one certificate can be specified in a different subfolder
     ; for example: $R0\1, but each individual binary can be signed
     ; with at most one certificate.  A fallback certificate can only be used
     ; if the binary is replaced with a different certificate.
     ; We always use the 64bit registry for certs.
     ${If} ${RunningX64}
       SetRegView 64
     ${EndIf}
-    DeleteRegKey HKLM "$R0"
-    WriteRegStr HKLM "$R0" "prefetchProcessName" "FIREFOX"
+
+    ; PrefetchProcessName was originally used to experiment with deleting
+    ; Windows prefetch as a speed optimization.  It is no longer used though.
+    DeleteRegValue HKLM "$R0" "prefetchProcessName"
+
+    ; Setting the Attempted value will ensure that a new Maintenance Service
+    ; install will never be attempted again after this from updates.  The value
+    ; is used only to see if updates should attempt new service installs.
+    WriteRegDWORD HKLM "Software\Mozilla\MaintenanceService" "Attempted" 1
+
+    ; These values associate the allowed certificates for the current
+    ; installation.
     WriteRegStr HKLM "$R0\0" "name" "${CERTIFICATE_NAME}"
     WriteRegStr HKLM "$R0\0" "issuer" "${CERTIFICATE_ISSUER}"
     ${If} ${RunningX64}
       SetRegView lastused
     ${EndIf}
     ClearErrors
   ${EndIf}
   ; Restore the previously used value back
--- a/config/external/icu/Makefile.in
+++ b/config/external/icu/Makefile.in
@@ -4,28 +4,22 @@
 
 # Ensure that this happens before including rules.mk
 ifdef USE_ICU
   ifndef MOZ_NATIVE_ICU
   # Library names: On Windows, ICU uses modified library names for static
   # and debug libraries.
     ifdef MOZ_SHARED_ICU
       ifeq ($(OS_ARCH),WINNT)
-        ifdef JS_SHARED_LIBRARY
-          ICU_FILES := $(foreach libname,$(ICU_LIB_NAMES),$(DEPTH)/intl/icu/target/lib/$(libname)$(MOZ_ICU_DBG_SUFFIX)$(MOZ_ICU_VERSION).dll)
-        endif
+        ICU_FILES := $(foreach libname,$(ICU_LIB_NAMES),$(DEPTH)/intl/icu/target/lib/$(libname)$(MOZ_ICU_DBG_SUFFIX)$(MOZ_ICU_VERSION).dll)
       else # ! WINNT
         ifeq ($(OS_ARCH),Darwin)
-          ifdef JS_SHARED_LIBRARY
-            ICU_FILES := $(foreach libname,$(ICU_LIB_NAMES),$(DEPTH)/intl/icu/target/lib/$(DLL_PREFIX)$(libname).$(MOZ_ICU_VERSION)$(DLL_SUFFIX))
-          endif
+          ICU_FILES := $(foreach libname,$(ICU_LIB_NAMES),$(DEPTH)/intl/icu/target/lib/$(DLL_PREFIX)$(libname).$(MOZ_ICU_VERSION)$(DLL_SUFFIX))
         else # ! Darwin
-          ifdef JS_SHARED_LIBRARY
-            ICU_FILES := $(foreach libname,$(ICU_LIB_NAMES),$(DEPTH)/intl/icu/target/lib/$(DLL_PREFIX)$(libname)$(DLL_SUFFIX).$(MOZ_ICU_VERSION))
-          endif
+          ICU_FILES := $(foreach libname,$(ICU_LIB_NAMES),$(DEPTH)/intl/icu/target/lib/$(DLL_PREFIX)$(libname)$(DLL_SUFFIX).$(MOZ_ICU_VERSION))
         endif
       endif # WINNT
       ifdef ICU_FILES
         ICU_DEST := $(DIST)/bin
         INSTALL_TARGETS += ICU
         $(ICU_FILES): buildicu
         ICU_TARGET := target
       endif
--- a/configure.in
+++ b/configure.in
@@ -9051,16 +9051,20 @@ if test "$MOZ_WIDGET_TOOLKIT" = "android
 else
     _INTL_API=yes
 fi
 
 if test "$MOZ_WIDGET_TOOLKIT" = "cocoa"; then
     USE_ICU=1
 fi
 
+if test "$OS_TARGET" = WINNT; then
+    MOZ_SHARED_ICU=1
+fi
+
 MOZ_CONFIG_ICU()
 
 if test -z "$JS_SHARED_LIBRARY"; then
   AC_DEFINE(MOZ_STATIC_JS)
 fi
 AC_SUBST(JS_SHARED_LIBRARY)
 
 MOZ_CREATE_CONFIG_STATUS()
--- a/content/base/public/File.h
+++ b/content/base/public/File.h
@@ -11,17 +11,16 @@
 #include "mozilla/GuardObjects.h"
 #include "mozilla/LinkedList.h"
 #include "mozilla/StaticMutex.h"
 #include "mozilla/StaticPtr.h"
 #include "mozilla/dom/Date.h"
 #include "mozilla/dom/indexedDB/FileInfo.h"
 #include "mozilla/dom/indexedDB/FileManager.h"
 #include "mozilla/dom/indexedDB/IndexedDatabaseManager.h"
-#include "mozilla/dom/UnionTypes.h"
 #include "nsAutoPtr.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsCOMPtr.h"
 #include "nsIDOMFile.h"
 #include "nsIDOMFileList.h"
 #include "nsIFile.h"
 #include "nsIMutable.h"
 #include "nsIXMLHttpRequest.h"
@@ -53,16 +52,17 @@ namespace dom {
 namespace indexedDB {
 class FileInfo;
 };
 
 struct BlobPropertyBag;
 struct ChromeFilePropertyBag;
 struct FilePropertyBag;
 class FileImpl;
+class OwningArrayBufferOrArrayBufferViewOrBlobOrString;
 
 class File MOZ_FINAL : public nsIDOMFile
                      , public nsIXHRSendable
                      , public nsIMutable
                      , public nsSupportsWeakReference
                      , public nsWrapperCache
 {
 public:
--- a/content/base/src/FragmentOrElement.cpp
+++ b/content/base/src/FragmentOrElement.cpp
@@ -2949,11 +2949,11 @@ FragmentOrElement::SetIsElementInStyleSc
 void
 FragmentOrElement::SetIsElementInStyleScopeFlagOnShadowTree(bool aInStyleScope)
 {
   NS_ASSERTION(IsElement(), "calling SetIsElementInStyleScopeFlagOnShadowTree "
                             "on a non-Element is useless");
   ShadowRoot* shadowRoot = GetShadowRoot();
   while (shadowRoot) {
     shadowRoot->SetIsElementInStyleScopeFlagOnSubtree(aInStyleScope);
-    shadowRoot = shadowRoot->GetOlderShadow();
+    shadowRoot = shadowRoot->GetOlderShadowRoot();
   }
 }
--- a/content/base/src/MultipartFileImpl.cpp
+++ b/content/base/src/MultipartFileImpl.cpp
@@ -2,16 +2,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "MultipartFileImpl.h"
 #include "jsfriendapi.h"
 #include "mozilla/dom/BlobSet.h"
 #include "mozilla/dom/FileBinding.h"
+#include "mozilla/dom/UnionTypes.h"
 #include "nsAutoPtr.h"
 #include "nsDOMClassInfoID.h"
 #include "nsIMultiplexInputStream.h"
 #include "nsStringStream.h"
 #include "nsTArray.h"
 #include "nsJSUtils.h"
 #include "nsContentUtils.h"
 #include "nsIScriptError.h"
--- a/content/base/src/ShadowRoot.cpp
+++ b/content/base/src/ShadowRoot.cpp
@@ -476,16 +476,26 @@ ShadowRoot::GetInnerHTML(nsAString& aInn
 }
 
 void
 ShadowRoot::SetInnerHTML(const nsAString& aInnerHTML, ErrorResult& aError)
 {
   SetInnerHTMLInternal(aInnerHTML, aError);
 }
 
+Element*
+ShadowRoot::Host()
+{
+  nsIContent* host = GetHost();
+  MOZ_ASSERT(host && host->IsElement(),
+             "ShadowRoot host should always be an element, "
+             "how else did we create this ShadowRoot?");
+  return host->AsElement();
+}
+
 bool
 ShadowRoot::ApplyAuthorStyles()
 {
   return mProtoBinding->InheritsStyle();
 }
 
 void
 ShadowRoot::SetApplyAuthorStyles(bool aApplyAuthorStyles)
--- a/content/base/src/ShadowRoot.h
+++ b/content/base/src/ShadowRoot.h
@@ -88,18 +88,17 @@ public:
    * insertion points in this ShadowRoot.
    */
   void DistributeAllNodes();
 
   void AddInsertionPoint(HTMLContentElement* aInsertionPoint);
   void RemoveInsertionPoint(HTMLContentElement* aInsertionPoint);
 
   void SetYoungerShadow(ShadowRoot* aYoungerShadow);
-  ShadowRoot* GetOlderShadow() { return mOlderShadow; }
-  ShadowRoot* GetYoungerShadow() { return mYoungerShadow; }
+  ShadowRoot* GetYoungerShadowRoot() { return mYoungerShadow; }
   void SetInsertionPointChanged() { mInsertionPointChanged = true; }
 
   void SetAssociatedBinding(nsXBLBinding* aBinding) { mAssociatedBinding = aBinding; }
 
   nsISupports* GetParentObject() const { return mPoolHost; }
 
   nsIContent* GetPoolHost() { return mPoolHost; }
   nsTArray<HTMLShadowElement*>& ShadowDescendants() { return mShadowDescendants; }
@@ -120,16 +119,18 @@ public:
     GetElementsByTagName(const nsAString& aNamespaceURI);
   already_AddRefed<nsContentList>
     GetElementsByTagNameNS(const nsAString& aNamespaceURI,
                            const nsAString& aLocalName);
   already_AddRefed<nsContentList>
     GetElementsByClassName(const nsAString& aClasses);
   void GetInnerHTML(nsAString& aInnerHTML);
   void SetInnerHTML(const nsAString& aInnerHTML, ErrorResult& aError);
+  Element* Host();
+  ShadowRoot* GetOlderShadowRoot() { return mOlderShadow; }
   void StyleSheetChanged();
 protected:
   virtual ~ShadowRoot();
 
   // The pool host is the parent of the nodes that will be distributed
   // into the insertion points in this ShadowRoot. See |ChangeShadowRoot|.
   nsCOMPtr<nsIContent> mPoolHost;
 
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -6811,24 +6811,24 @@ nsContentUtils::HasDistributedChildren(n
     // to content insertion points in the shadow root.
     return true;
   }
 
   ShadowRoot* shadow = ShadowRoot::FromNode(aContent);
   if (shadow) {
     // Children of a shadow root are distributed to
     // the shadow insertion point of the younger shadow root.
-    return shadow->GetYoungerShadow();
+    return shadow->GetYoungerShadowRoot();
   }
 
   HTMLShadowElement* shadowEl = HTMLShadowElement::FromContent(aContent);
   if (shadowEl && shadowEl->IsInsertionPoint()) {
     // Children of a shadow insertion points are distributed
     // to the insertion points in the older shadow root.
-    return shadow->GetOlderShadow();
+    return shadowEl->GetOlderShadowRoot();
   }
 
   HTMLContentElement* contentEl = HTMLContentElement::FromContent(aContent);
   if (contentEl && contentEl->IsInsertionPoint()) {
     // Children of a content insertion point are distributed to the
     // content insertion point if the content insertion point does
     // not match any nodes (fallback content).
     return contentEl->MatchedNodes().IsEmpty();
--- a/content/base/src/nsMixedContentBlocker.cpp
+++ b/content/base/src/nsMixedContentBlocker.cpp
@@ -21,16 +21,20 @@
 #include "nsIHttpChannel.h"
 #include "mozilla/Preferences.h"
 #include "nsIScriptObjectPrincipal.h"
 #include "nsISecureBrowserUI.h"
 #include "nsIDocumentLoader.h"
 #include "nsIWebNavigation.h"
 #include "nsLoadGroup.h"
 #include "nsIScriptError.h"
+#include "nsIURI.h"
+#include "nsIChannelEventSink.h"
+#include "nsAsyncRedirectVerifyHelper.h"
+#include "mozilla/LoadInfo.h"
 
 #include "prlog.h"
 
 using namespace mozilla;
 
 enum nsMixedContentBlockerMessageType {
   eBlocked = 0x00,
   eUserOverride = 0x01
@@ -145,17 +149,17 @@ nsMixedContentBlocker::nsMixedContentBlo
   Preferences::AddBoolVarCache(&sBlockMixedDisplay,
                                "security.mixed_content.block_display_content");
 }
 
 nsMixedContentBlocker::~nsMixedContentBlocker()
 {
 }
 
-NS_IMPL_ISUPPORTS(nsMixedContentBlocker, nsIContentPolicy)
+NS_IMPL_ISUPPORTS(nsMixedContentBlocker, nsIContentPolicy, nsIChannelEventSink)
 
 static void
 LogMixedContentMessage(MixedContentTypes aClassification,
                        nsIURI* aContentLocation,
                        nsIDocument* aRootDoc,
                        nsMixedContentBlockerMessageType aMessageType)
 {
   nsAutoCString messageCategory;
@@ -185,16 +189,97 @@ LogMixedContentMessage(MixedContentTypes
   NS_ConvertUTF8toUTF16 locationSpecUTF16(locationSpec);
 
   const char16_t* strings[] = { locationSpecUTF16.get() };
   nsContentUtils::ReportToConsole(severityFlag, messageCategory, aRootDoc,
                                   nsContentUtils::eSECURITY_PROPERTIES,
                                   messageLookupKey.get(), strings, ArrayLength(strings));
 }
 
+
+
+/* nsIChannelEventSink implementation
+ * This code is called when a request is redirected.
+ * We check the channel associated with the new uri is allowed to load
+ * in the current context
+ */
+NS_IMETHODIMP
+nsMixedContentBlocker::AsyncOnChannelRedirect(nsIChannel* aOldChannel,
+                                              nsIChannel* aNewChannel,
+                                              uint32_t aFlags,
+                                              nsIAsyncVerifyRedirectCallback* aCallback)
+{
+  nsAsyncRedirectAutoCallback autoCallback(aCallback);
+
+  if (!aOldChannel) {
+    NS_ERROR("No channel when evaluating mixed content!");
+    return NS_ERROR_FAILURE;
+  }
+
+  nsresult rv;
+  nsCOMPtr<nsIURI> oldUri;
+  rv = aOldChannel->GetURI(getter_AddRefs(oldUri));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsCOMPtr<nsIURI> newUri;
+  rv = aNewChannel->GetURI(getter_AddRefs(newUri));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  // Get the loading Info from the old channel
+  nsCOMPtr<nsILoadInfo> loadInfo;
+  rv = aOldChannel->GetLoadInfo(getter_AddRefs(loadInfo));
+  NS_ENSURE_SUCCESS(rv, rv);
+  if (!loadInfo) {
+    // XXX: We want to have a loadInfo on all channels, but we don't yet.
+    // If an addon creates a channel, they may not set loadinfo. If that
+    // channel redirects from one page to another page, we would get caught
+    // in this code path. Hence, we have to return NS_OK. Once we have more
+    // confidence that all channels have loadinfo, we can change this to
+    // a failure. See bug 1077201.
+    return NS_OK;
+  }
+
+  uint32_t contentPolicyType = loadInfo->GetContentPolicyType();
+  nsCOMPtr<nsIPrincipal> requestingPrincipal = loadInfo->LoadingPrincipal();
+
+  // Since we are calling shouldLoad() directly on redirects, we don't go through the code
+  // in nsContentPolicyUtils::NS_CheckContentLoadPolicy(). Hence, we have to
+  // duplicate parts of it here.
+  nsCOMPtr<nsIURI> requestingLocation;
+  if (requestingPrincipal) {
+    // We check to see if the loadingPrincipal is systemPrincipal and return
+    // early if it is
+    if (nsContentUtils::IsSystemPrincipal(requestingPrincipal)) {
+      return NS_OK;
+    }
+    // We set the requestingLocation from the RequestingPrincipal.
+    rv = requestingPrincipal->GetURI(getter_AddRefs(requestingLocation));
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+  int16_t decision = REJECT_REQUEST;
+  rv = ShouldLoad(contentPolicyType,
+                  newUri,
+                  requestingLocation,
+                  loadInfo->LoadingNode(),
+                  EmptyCString(),       // aMimeGuess
+                  nullptr,              // aExtra
+                  requestingPrincipal,
+                  &decision);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  // If the channel is about to load mixed content, abort the channel
+  if (!NS_CP_ACCEPTED(decision)) {
+    autoCallback.DontCallback();
+    return NS_BINDING_FAILED;
+  }
+
+  return NS_OK;
+}
+
 NS_IMETHODIMP
 nsMixedContentBlocker::ShouldLoad(uint32_t aContentType,
                                   nsIURI* aContentLocation,
                                   nsIURI* aRequestingLocation,
                                   nsISupports* aRequestingContext,
                                   const nsACString& aMimeGuess,
                                   nsISupports* aExtra,
                                   nsIPrincipal* aRequestPrincipal,
--- a/content/base/src/nsMixedContentBlocker.h
+++ b/content/base/src/nsMixedContentBlocker.h
@@ -18,23 +18,27 @@ enum MixedContentTypes {
   // "Active" content, such as fonts, plugin content, JavaScript, stylesheets,
   // iframes, WebSockets, and XHR
   eMixedScript,
   // "Display" content, such as images, audio, video, and <a ping>
   eMixedDisplay
 };
 
 #include "nsIContentPolicy.h"
+#include "nsIChannel.h"
+#include "nsIChannelEventSink.h"
 
-class nsMixedContentBlocker : public nsIContentPolicy
+class nsMixedContentBlocker : public nsIContentPolicy,
+                              public nsIChannelEventSink
 {
   virtual ~nsMixedContentBlocker();
 
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSICONTENTPOLICY
+  NS_DECL_NSICHANNELEVENTSINK
 
   nsMixedContentBlocker();
   static bool sBlockMixedScript;
   static bool sBlockMixedDisplay;
 };
 
 #endif /* nsMixedContentBlocker_h___ */
--- a/content/base/test/chrome/cpows_child.js
+++ b/content/base/test/chrome/cpows_child.js
@@ -147,17 +147,22 @@ function compartment_test()
     let results = [];
     function is(a, b, msg) { results.push({ result: a === b ? "PASS" : "FAIL", message: msg }) };
     function ok(x, msg) { results.push({ result: x ? "PASS" : "FAIL", message: msg }) };
 
     let cpowLocation = Cu.getCompartmentLocation(obj);
     ok(/Privileged Junk/.test(cpowLocation),
        "child->parent CPOWs should live in the privileged junk scope: " + cpowLocation);
     is(obj(), 42, "child->parent CPOW is invokable");
-    is(obj.expando, undefined, "child->parent CPOW cannot access properties");
+    try {
+      obj.expando;
+      ok(false, "child->parent CPOW cannot access properties");
+    } catch (e) {
+      ok(true, "child->parent CPOW cannot access properties");
+    }
 
     return results;
   }
   sendSyncMessage("cpows:compartment_test", {}, { getUnprivilegedObject: sb.getUnprivilegedObject,
                                                   testParentObject: testParentObject });
 }
 
 function regexp_test()
--- a/content/html/content/public/HTMLMediaElement.h
+++ b/content/html/content/public/HTMLMediaElement.h
@@ -12,23 +12,23 @@
 #include "nsCycleCollectionParticipant.h"
 #include "nsIObserver.h"
 #include "mozilla/CORSMode.h"
 #include "DOMMediaStream.h"
 #include "AudioChannelCommon.h"
 #include "DecoderTraits.h"
 #include "nsIAudioChannelAgent.h"
 #include "mozilla/Attributes.h"
-#include "mozilla/dom/AudioChannelBinding.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/dom/TextTrackManager.h"
 #include "MediaDecoder.h"
 #ifdef MOZ_EME
 #include "mozilla/dom/MediaKeys.h"
 #endif
+#include "nsGkAtoms.h"
 
 // Something on Linux #defines None, which is an entry in the
 // MediaWaitingFor enum, so undef it here before including the binfing,
 // so that the build doesn't fail...
 #ifdef None
 #undef None
 #endif
 
--- a/content/html/content/src/HTMLCanvasElement.cpp
+++ b/content/html/content/src/HTMLCanvasElement.cpp
@@ -9,17 +9,16 @@
 #include "jsapi.h"
 #include "jsfriendapi.h"
 #include "Layers.h"
 #include "mozilla/Base64.h"
 #include "mozilla/CheckedInt.h"
 #include "mozilla/dom/CanvasRenderingContext2D.h"
 #include "mozilla/dom/File.h"
 #include "mozilla/dom/HTMLCanvasElementBinding.h"
-#include "mozilla/dom/UnionTypes.h"
 #include "mozilla/dom/MouseEvent.h"
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/gfx/Rect.h"
 #include "mozilla/MouseEvents.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Telemetry.h"
 #include "nsAttrValueInlines.h"
 #include "nsContentUtils.h"
--- a/content/html/content/src/HTMLFormControlsCollection.cpp
+++ b/content/html/content/src/HTMLFormControlsCollection.cpp
@@ -6,17 +6,16 @@
 
 #include "mozilla/dom/HTMLFormControlsCollection.h"
 
 #include "mozFlushType.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/HTMLFormControlsCollectionBinding.h"
 #include "mozilla/dom/HTMLFormElement.h"
-#include "mozilla/dom/UnionTypes.h"
 #include "nsGenericHTMLElement.h" // nsGenericHTMLFormElement
 #include "nsIDocument.h"
 #include "nsIDOMNode.h"
 #include "nsIDOMNodeList.h"
 #include "nsIFormControl.h"
 #include "RadioNodeList.h"
 #include "jsfriendapi.h"
 
--- a/content/html/content/src/HTMLOptionsCollection.h
+++ b/content/html/content/src/HTMLOptionsCollection.h
@@ -6,28 +6,29 @@
 #define mozilla_dom_HTMLOptionsCollection_h
 
 #include "mozilla/Attributes.h"
 #include "nsIHTMLCollection.h"
 #include "nsIDOMHTMLOptionsCollection.h"
 #include "nsWrapperCache.h"
 
 #include "mozilla/dom/HTMLOptionElement.h"
-#include "mozilla/dom/UnionTypes.h"
 #include "mozilla/ErrorResult.h"
 #include "nsCOMPtr.h"
 #include "nsError.h"
 #include "nsGenericHTMLElement.h"
 #include "nsTArray.h"
 
 class nsIDOMHTMLOptionElement;
 
 namespace mozilla {
 namespace dom {
 
+class HTMLElementOrLong;
+class HTMLOptionElementOrHTMLOptGroupElement;
 class HTMLSelectElement;
 
 /**
  * The collection of options in the select (what you get back when you do
  * select.options in DOM)
  */
 class HTMLOptionsCollection MOZ_FINAL : public nsIHTMLCollection
                                       , public nsIDOMHTMLOptionsCollection
--- a/content/html/content/src/HTMLSelectElement.cpp
+++ b/content/html/content/src/HTMLSelectElement.cpp
@@ -9,16 +9,17 @@
 #include "mozilla/Attributes.h"
 #include "mozilla/BasicEvents.h"
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/EventStates.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/HTMLOptGroupElement.h"
 #include "mozilla/dom/HTMLOptionElement.h"
 #include "mozilla/dom/HTMLSelectElementBinding.h"
+#include "mozilla/dom/UnionTypes.h"
 #include "nsContentCreatorFunctions.h"
 #include "nsContentList.h"
 #include "nsError.h"
 #include "nsFormSubmission.h"
 #include "nsGkAtoms.h"
 #include "nsIComboboxControlFrame.h"
 #include "nsIDocument.h"
 #include "nsIFormControlFrame.h"
--- a/content/html/content/src/HTMLShadowElement.cpp
+++ b/content/html/content/src/HTMLShadowElement.cpp
@@ -139,17 +139,17 @@ HTMLShadowElement::BindToTree(nsIDocumen
       containingShadow->SetShadowElement(this);
     }
 
     containingShadow->SetInsertionPointChanged();
   }
 
   if (mIsInsertionPoint && containingShadow) {
     // Propagate BindToTree calls to projected shadow root children.
-    ShadowRoot* projectedShadow = containingShadow->GetOlderShadow();
+    ShadowRoot* projectedShadow = containingShadow->GetOlderShadowRoot();
     if (projectedShadow) {
       for (nsIContent* child = projectedShadow->GetFirstChild(); child;
            child = child->GetNextSibling()) {
         rv = child->BindToTree(nullptr, projectedShadow,
                                projectedShadow->GetBindingParent(),
                                aCompileEventHandlers);
         NS_ENSURE_SUCCESS(rv, rv);
       }
@@ -162,17 +162,17 @@ HTMLShadowElement::BindToTree(nsIDocumen
 void
 HTMLShadowElement::UnbindFromTree(bool aDeep, bool aNullParent)
 {
   nsRefPtr<ShadowRoot> oldContainingShadow = GetContainingShadow();
 
   if (mIsInsertionPoint && oldContainingShadow) {
     // Propagate UnbindFromTree call to previous projected shadow
     // root children.
-    ShadowRoot* projectedShadow = oldContainingShadow->GetOlderShadow();
+    ShadowRoot* projectedShadow = oldContainingShadow->GetOlderShadowRoot();
     if (projectedShadow) {
       for (nsIContent* child = projectedShadow->GetFirstChild(); child;
            child = child->GetNextSibling()) {
         child->UnbindFromTree(true, false);
       }
     }
   }
 
@@ -215,17 +215,17 @@ HTMLShadowElement::DistributeSingleNode(
   if (parentShadowRoot) {
     parentShadowRoot->DistributeSingleNode(aContent);
     return;
   }
 
   // Handle the case where the parent of this shadow element is a ShadowRoot
   // that is projected into a shadow insertion point in the younger ShadowRoot.
   ShadowRoot* containingShadow = GetContainingShadow();
-  ShadowRoot* youngerShadow = containingShadow->GetYoungerShadow();
+  ShadowRoot* youngerShadow = containingShadow->GetYoungerShadowRoot();
   if (youngerShadow && GetParent() == containingShadow) {
     HTMLShadowElement* youngerShadowElement = youngerShadow->GetShadowElement();
     if (youngerShadowElement) {
       youngerShadowElement->DistributeSingleNode(aContent);
     }
   }
 }
 
@@ -242,33 +242,33 @@ HTMLShadowElement::RemoveDistributedNode
   if (parentShadowRoot) {
     parentShadowRoot->RemoveDistributedNode(aContent);
     return;
   }
 
   // Handle the case where the parent of this shadow element is a ShadowRoot
   // that is projected into a shadow insertion point in the younger ShadowRoot.
   ShadowRoot* containingShadow = GetContainingShadow();
-  ShadowRoot* youngerShadow = containingShadow->GetYoungerShadow();
+  ShadowRoot* youngerShadow = containingShadow->GetYoungerShadowRoot();
   if (youngerShadow && GetParent() == containingShadow) {
     HTMLShadowElement* youngerShadowElement = youngerShadow->GetShadowElement();
     if (youngerShadowElement) {
       youngerShadowElement->RemoveDistributedNode(aContent);
     }
   }
 }
 
 void
 HTMLShadowElement::DistributeAllNodes()
 {
   // All the explicit children of the projected ShadowRoot are distributed
   // into this shadow insertion point so update the destination insertion
   // points.
   ShadowRoot* containingShadow = GetContainingShadow();
-  ShadowRoot* olderShadow = containingShadow->GetOlderShadow();
+  ShadowRoot* olderShadow = containingShadow->GetOlderShadowRoot();
   if (olderShadow) {
     ExplicitChildIterator childIterator(olderShadow);
     for (nsIContent* content = childIterator.GetNextChild();
          content;
          content = childIterator.GetNextChild()) {
       ShadowRoot::RemoveDestInsertionPoint(this, content->DestInsertionPoints());
       content->DestInsertionPoints().AppendElement(this);
     }
@@ -281,17 +281,17 @@ HTMLShadowElement::DistributeAllNodes()
   ShadowRoot* parentShadowRoot = GetParent()->GetShadowRoot();
   if (parentShadowRoot) {
     parentShadowRoot->DistributeAllNodes();
     return;
   }
 
   // Handle the case where the parent of this shadow element is a ShadowRoot
   // that is projected into a shadow insertion point in the younger ShadowRoot.
-  ShadowRoot* youngerShadow = containingShadow->GetYoungerShadow();
+  ShadowRoot* youngerShadow = containingShadow->GetYoungerShadowRoot();
   if (youngerShadow && GetParent() == containingShadow) {
     HTMLShadowElement* youngerShadowElement = youngerShadow->GetShadowElement();
     if (youngerShadowElement) {
       youngerShadowElement->DistributeAllNodes();
     }
   }
 }
 
--- a/content/html/content/src/HTMLTableElement.cpp
+++ b/content/html/content/src/HTMLTableElement.cpp
@@ -3,17 +3,16 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/HTMLTableElement.h"
 #include "nsAttrValueInlines.h"
 #include "nsRuleData.h"
 #include "nsHTMLStyleSheet.h"
 #include "nsMappedAttributes.h"
-#include "mozilla/dom/UnionTypes.h"
 #include "mozilla/dom/HTMLCollectionBinding.h"
 #include "mozilla/dom/HTMLTableElementBinding.h"
 #include "nsContentUtils.h"
 #include "jsfriendapi.h"
 
 NS_IMPL_NS_NEW_HTML_ELEMENT(Table)
 
 namespace mozilla {
--- a/content/html/document/src/HTMLAllCollection.cpp
+++ b/content/html/document/src/HTMLAllCollection.cpp
@@ -3,17 +3,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/. */
 
 #include "mozilla/dom/HTMLAllCollection.h"
 
 #include "mozilla/dom/HTMLAllCollectionBinding.h"
 #include "mozilla/dom/Nullable.h"
-#include "mozilla/dom/UnionTypes.h"
 #include "nsHTMLDocument.h"
 
 namespace mozilla {
 namespace dom {
 
 HTMLAllCollection::HTMLAllCollection(nsHTMLDocument* aDocument)
   : mDocument(aDocument)
 {
--- a/content/html/document/test/browser.ini
+++ b/content/html/document/test/browser.ini
@@ -1,4 +1,5 @@
 [DEFAULT]
 support-files = bug592641_img.jpg
 
 [browser_bug592641.js]
+[browser_bug1081537.js]
new file mode 100644
--- /dev/null
+++ b/content/html/document/test/browser_bug1081537.js
@@ -0,0 +1,11 @@
+// This test is useful because mochitest-browser runs as an addon, so we test
+// addon-scope paths here.
+let ifr;
+function test() {
+  ifr = document.createElement('iframe');
+  document.getElementById('main-window').appendChild(ifr);
+  is(ifr.contentDocument.nodePrincipal.origin, "[System Principal]");
+  ifr.contentDocument.open();
+  ok(true, "Didn't throw");
+}
+registerCleanupFunction(() => ifr.remove());
--- a/content/media/TextTrackCue.h
+++ b/content/media/TextTrackCue.h
@@ -10,17 +10,16 @@
 #include "mozilla/DOMEventTargetHelper.h"
 #include "mozilla/dom/DocumentFragment.h"
 #include "mozilla/dom/VTTCueBinding.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsIWebVTTParserWrapper.h"
 #include "mozilla/StaticPtr.h"
 #include "nsIDocument.h"
 #include "mozilla/dom/HTMLDivElement.h"
-#include "mozilla/dom/UnionTypes.h"
 #include "mozilla/dom/TextTrack.h"
 
 namespace mozilla {
 namespace dom {
 
 class HTMLTrackElement;
 class TextTrackRegion;
 
--- a/content/media/android/AndroidMediaResourceServer.cpp
+++ b/content/media/android/AndroidMediaResourceServer.cpp
@@ -445,17 +445,17 @@ AndroidMediaResourceServer::AppendRandom
   aUrl += salt;
   return NS_OK;
 }
 
 nsresult
 AndroidMediaResourceServer::AddResource(mozilla::MediaResource* aResource, nsCString& aUrl)
 {
   nsCString url = GetURLPrefix();
-  nsresult rv = GenerateRandomPathName(url, 16);
+  nsresult rv = AppendRandomPath(url);
   if (NS_FAILED (rv)) return rv;
 
   {
     MutexAutoLock lock(mMutex);
 
     // Adding a resource URL that already exists is considered an error.
     if (mResources.find(aUrl) != mResources.end()) return NS_ERROR_FAILURE;
     mResources[url] = aResource;
--- a/content/media/eme/MediaEncryptedEvent.cpp
+++ b/content/media/eme/MediaEncryptedEvent.cpp
@@ -41,17 +41,17 @@ MediaEncryptedEvent::MediaEncryptedEvent
 
 MediaEncryptedEvent::~MediaEncryptedEvent()
 {
   mInitData = nullptr;
   mozilla::DropJSObjects(this);
 }
 
 JSObject*
-MediaEncryptedEvent::WrapObject(JSContext* aCx)
+MediaEncryptedEvent::WrapObjectInternal(JSContext* aCx)
 {
   return MediaEncryptedEventBinding::Wrap(aCx, this);
 }
 
 already_AddRefed<MediaEncryptedEvent>
 MediaEncryptedEvent::Constructor(EventTarget* aOwner,
                                  const nsAString& aInitDataType,
                                  const nsTArray<uint8_t>& aInitData)
--- a/content/media/eme/MediaEncryptedEvent.h
+++ b/content/media/eme/MediaEncryptedEvent.h
@@ -31,17 +31,17 @@ protected:
   virtual ~MediaEncryptedEvent();
   explicit MediaEncryptedEvent(EventTarget* aOwner);
 
   nsString mInitDataType;
   JS::Heap<JSObject*> mInitData;
 
 public:
 
-  virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE;
+  virtual JSObject* WrapObjectInternal(JSContext* aCx) MOZ_OVERRIDE;
 
   static already_AddRefed<MediaEncryptedEvent>
   Constructor(EventTarget* aOwner,
               const nsAString& aInitDataType,
               const nsTArray<uint8_t>& aInitData);
 
   static already_AddRefed<MediaEncryptedEvent>
   Constructor(const GlobalObject& aGlobal,
--- a/content/media/eme/MediaKeyError.cpp
+++ b/content/media/eme/MediaKeyError.cpp
@@ -24,16 +24,16 @@ MediaKeyError::~MediaKeyError()
 
 uint32_t
 MediaKeyError::SystemCode() const
 {
   return mSystemCode;
 }
 
 JSObject*
-MediaKeyError::WrapObject(JSContext* aCx)
+MediaKeyError::WrapObjectInternal(JSContext* aCx)
 {
   return MediaKeyErrorBinding::Wrap(aCx, this);
 }
 
 
 } // namespace dom
 } // namespace mozilla
--- a/content/media/eme/MediaKeyError.h
+++ b/content/media/eme/MediaKeyError.h
@@ -19,17 +19,17 @@ namespace dom {
 class MediaKeyError MOZ_FINAL : public Event
 {
 public:
   NS_FORWARD_TO_EVENT
 
   MediaKeyError(EventTarget* aOwner, uint32_t aSystemCode);
   ~MediaKeyError();
 
-  virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE;
+  virtual JSObject* WrapObjectInternal(JSContext* aCx) MOZ_OVERRIDE;
 
   uint32_t SystemCode() const;
 
 private:
   uint32_t mSystemCode;
 };
 
 } // namespace dom
--- a/content/media/eme/MediaKeyMessageEvent.cpp
+++ b/content/media/eme/MediaKeyMessageEvent.cpp
@@ -51,17 +51,17 @@ MediaKeyMessageEvent::~MediaKeyMessageEv
 
 MediaKeyMessageEvent*
 MediaKeyMessageEvent::AsMediaKeyMessageEvent()
 {
   return this;
 }
 
 JSObject*
-MediaKeyMessageEvent::WrapObject(JSContext* aCx)
+MediaKeyMessageEvent::WrapObjectInternal(JSContext* aCx)
 {
   return MediaKeyMessageEventBinding::Wrap(aCx, this);
 }
 
 already_AddRefed<MediaKeyMessageEvent>
 MediaKeyMessageEvent::Constructor(EventTarget* aOwner,
                                   const nsAString& aURL,
                                   const nsTArray<uint8_t>& aMessage)
--- a/content/media/eme/MediaKeyMessageEvent.h
+++ b/content/media/eme/MediaKeyMessageEvent.h
@@ -32,17 +32,17 @@ protected:
   explicit MediaKeyMessageEvent(EventTarget* aOwner);
 
   JS::Heap<JSObject*> mMessage;
   nsString mDestinationURL;
 
 public:
   virtual MediaKeyMessageEvent* AsMediaKeyMessageEvent();
 
-  virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE;
+  virtual JSObject* WrapObjectInternal(JSContext* aCx) MOZ_OVERRIDE;
 
   static already_AddRefed<MediaKeyMessageEvent>
     Constructor(EventTarget* aOwner,
                 const nsAString& aURL,
                 const nsTArray<uint8_t>& aMessage);
 
   static already_AddRefed<MediaKeyMessageEvent>
   Constructor(const GlobalObject& aGlobal,
--- a/content/media/eme/MediaKeySession.h
+++ b/content/media/eme/MediaKeySession.h
@@ -13,26 +13,26 @@
 #include "mozilla/DOMEventTargetHelper.h"
 #include "nsCOMPtr.h"
 #include "mozilla/dom/TypedArray.h"
 #include "mozilla/Mutex.h"
 #include "mozilla/dom/Date.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/dom/MediaKeySessionBinding.h"
 #include "mozilla/dom/MediaKeysBinding.h"
-#include "mozilla/dom/UnionTypes.h"
 
 struct JSContext;
 
 namespace mozilla {
 
 class CDMProxy;
 
 namespace dom {
 
+class ArrayBufferViewOrArrayBuffer;
 class MediaKeyError;
 
 class MediaKeySession MOZ_FINAL : public DOMEventTargetHelper
 {
 public:
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(MediaKeySession,
                                            DOMEventTargetHelper)
--- a/content/media/eme/MediaKeys.cpp
+++ b/content/media/eme/MediaKeys.cpp
@@ -6,16 +6,17 @@
 
 #include "mozilla/dom/HTMLMediaElement.h"
 #include "mozilla/dom/MediaKeys.h"
 #include "mozilla/dom/MediaKeysBinding.h"
 #include "mozilla/dom/MediaKeyMessageEvent.h"
 #include "mozilla/dom/MediaKeyError.h"
 #include "mozilla/dom/MediaKeySession.h"
 #include "mozilla/dom/DOMException.h"
+#include "mozilla/dom/UnionTypes.h"
 #include "mozilla/CDMProxy.h"
 #include "mozilla/EMELog.h"
 #include "nsContentUtils.h"
 #include "nsIScriptObjectPrincipal.h"
 #include "mozilla/Preferences.h"
 #include "nsContentTypeParser.h"
 #ifdef MOZ_FMP4
 #include "MP4Decoder.h"
--- a/content/media/eme/MediaKeys.h
+++ b/content/media/eme/MediaKeys.h
@@ -12,25 +12,25 @@
 #include "nsISupports.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/RefPtr.h"
 #include "nsCOMPtr.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsRefPtrHashtable.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/dom/MediaKeysBinding.h"
-#include "mozilla/dom/UnionTypes.h"
 #include "mozIGeckoMediaPluginService.h"
 
 namespace mozilla {
 
 class CDMProxy;
 
 namespace dom {
 
+class ArrayBufferViewOrArrayBuffer;
 class MediaKeySession;
 class HTMLMediaElement;
 
 typedef nsRefPtrHashtable<nsStringHashKey, MediaKeySession> KeySessionHashMap;
 typedef nsRefPtrHashtable<nsUint32HashKey, dom::Promise> PromiseHashMap;
 typedef nsRefPtrHashtable<nsUint32HashKey, MediaKeySession> PendingKeySessionsHashMap;
 typedef uint32_t PromiseId;
 
--- a/content/media/gtest/TestWebMBuffered.cpp
+++ b/content/media/gtest/TestWebMBuffered.cpp
@@ -1,13 +1,14 @@
 /* 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 "gtest/gtest.h"
+#include "mozilla/ArrayUtils.h"
 #include <stdio.h>
 #include "nsTArray.h"
 #include "WebMBufferedParser.h"
 
 using namespace mozilla;
 
 // "test.webm" contains 8 SimpleBlocks in a single Cluster with the following attributes
 static const uint64_t gTimecodes[] = { 66000000, 160000000, 100000000, 133000000,
--- a/content/media/webaudio/AudioDestinationNode.cpp
+++ b/content/media/webaudio/AudioDestinationNode.cpp
@@ -203,17 +203,17 @@ private:
 };
 
 class DestinationNodeEngine : public AudioNodeEngine
 {
 public:
   explicit DestinationNodeEngine(AudioDestinationNode* aNode)
     : AudioNodeEngine(aNode)
     , mVolume(1.0f)
-    , mLastInputMuted(true)
+    , mLastInputMuted(false)
   {
     MOZ_ASSERT(aNode);
   }
 
   virtual void ProcessBlock(AudioNodeStream* aStream,
                             const AudioChunk& aInput,
                             AudioChunk* aOutput,
                             bool* aFinished) MOZ_OVERRIDE
@@ -617,16 +617,20 @@ AudioDestinationNode::CreateAudioChannel
                                            static_cast<int32_t>(mAudioChannel),
                                            this);
 
   nsCOMPtr<nsIDocShell> docshell = do_GetInterface(GetOwner());
   if (docshell) {
     bool isActive = false;
     docshell->GetIsActive(&isActive);
     mAudioChannelAgent->SetVisibilityState(isActive);
+
+    // The AudioChannelAgent must start playing immediately in order to avoid
+    // race conditions with mozinterruptbegin/end events.
+    InputMuted(false);
   }
 }
 
 void
 AudioDestinationNode::NotifyStableState()
 {
   mExtraCurrentTimeUpdatedSinceLastStableState = false;
 }
@@ -704,16 +708,18 @@ AudioDestinationNode::InputMuted(bool aM
   }
 
   if (aMuted) {
     mAudioChannelAgent->StopPlaying();
     return;
   }
 
   int32_t state = 0;
-  mAudioChannelAgent->StartPlaying(&state);
-  mAudioChannelAgentPlaying =
-    state == AudioChannelState::AUDIO_CHANNEL_STATE_NORMAL;
-  SetCanPlay(mAudioChannelAgentPlaying);
+  nsresult rv = mAudioChannelAgent->StartPlaying(&state);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return;
+  }
+
+  CanPlayChanged(state);
 }
 
 } // dom namespace
 } // mozilla namespace
--- a/content/media/webaudio/AudioProcessingEvent.cpp
+++ b/content/media/webaudio/AudioProcessingEvent.cpp
@@ -30,17 +30,17 @@ AudioProcessingEvent::AudioProcessingEve
 {
 }
 
 AudioProcessingEvent::~AudioProcessingEvent()
 {
 }
 
 JSObject*
-AudioProcessingEvent::WrapObject(JSContext* aCx)
+AudioProcessingEvent::WrapObjectInternal(JSContext* aCx)
 {
   return AudioProcessingEventBinding::Wrap(aCx, this);
 }
 
 already_AddRefed<AudioBuffer>
 AudioProcessingEvent::LazilyCreateBuffer(uint32_t aNumberOfChannels,
                                          ErrorResult& aRv)
 {
--- a/content/media/webaudio/AudioProcessingEvent.h
+++ b/content/media/webaudio/AudioProcessingEvent.h
@@ -20,17 +20,17 @@ public:
   AudioProcessingEvent(ScriptProcessorNode* aOwner,
                        nsPresContext* aPresContext,
                        WidgetEvent* aEvent);
 
   NS_DECL_ISUPPORTS_INHERITED
   NS_FORWARD_TO_EVENT
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(AudioProcessingEvent, Event)
 
-  virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE;
+  virtual JSObject* WrapObjectInternal(JSContext* aCx) MOZ_OVERRIDE;
 
   void InitEvent(AudioBuffer* aInputBuffer,
                  uint32_t aNumberOfInputChannels,
                  double aPlaybackTime)
   {
     InitEvent(NS_LITERAL_STRING("audioprocess"), false, false);
     mInputBuffer = aInputBuffer;
     mNumberOfInputChannels = aNumberOfInputChannels;
--- a/content/media/webaudio/OfflineAudioCompletionEvent.cpp
+++ b/content/media/webaudio/OfflineAudioCompletionEvent.cpp
@@ -27,16 +27,16 @@ OfflineAudioCompletionEvent::OfflineAudi
 {
 }
 
 OfflineAudioCompletionEvent::~OfflineAudioCompletionEvent()
 {
 }
 
 JSObject*
-OfflineAudioCompletionEvent::WrapObject(JSContext* aCx)
+OfflineAudioCompletionEvent::WrapObjectInternal(JSContext* aCx)
 {
   return OfflineAudioCompletionEventBinding::Wrap(aCx, this);
 }
 
 }
 }
 
--- a/content/media/webaudio/OfflineAudioCompletionEvent.h
+++ b/content/media/webaudio/OfflineAudioCompletionEvent.h
@@ -21,17 +21,17 @@ public:
   OfflineAudioCompletionEvent(AudioContext* aOwner,
                               nsPresContext* aPresContext,
                               WidgetEvent* aEvent);
 
   NS_DECL_ISUPPORTS_INHERITED
   NS_FORWARD_TO_EVENT
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(OfflineAudioCompletionEvent, Event)
 
-  virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE;
+  virtual JSObject* WrapObjectInternal(JSContext* aCx) MOZ_OVERRIDE;
 
   void InitEvent(AudioBuffer* aRenderedBuffer)
   {
     InitEvent(NS_LITERAL_STRING("complete"), false, false);
     mRenderedBuffer = aRenderedBuffer;
   }
 
   AudioBuffer* RenderedBuffer() const
--- a/content/media/webaudio/test/browser_mozAudioChannel.js
+++ b/content/media/webaudio/test/browser_mozAudioChannel.js
@@ -6,25 +6,16 @@ function whenBrowserLoaded(aBrowser, aCa
   aBrowser.addEventListener("load", function onLoad(event) {
     if (event.target == aBrowser.contentDocument) {
       aBrowser.removeEventListener("load", onLoad, true);
       executeSoon(aCallback);
     }
   }, true);
 }
 
-function whenTabRestored(aTab, aCallback) {
-  aTab.addEventListener("SSTabRestored", function onRestored(aEvent) {
-    aTab.removeEventListener("SSTabRestored", onRestored, true);
-    executeSoon(function executeWhenTabRestored() {
-      aCallback();
-    });
-  }, true);
-}
-
 function whenBrowserUnloaded(aBrowser, aCallback) {
   aBrowser.addEventListener("unload", function onUnload() {
     aBrowser.removeEventListener("unload", onUnload, true);
     executeSoon(aCallback);
   }, true);
 }
 
 var event;
@@ -68,19 +59,19 @@ function test() {
 
               info("Unloading a tab...");
               whenBrowserUnloaded(tab2.linkedBrowser, function() { info("Tab unloaded."); });
 
               gBrowser.removeTab(tab2);
               gBrowser.selectedTab = tab1;
             }
 
-            let tab2 = gBrowser.duplicateTab(tab1);
+            let tab2 = gBrowser.addTab(testURL);
             gBrowser.selectedTab = tab2;
 
-            info("Restoring the tab...");
-            whenTabRestored(tab2, function() { info("Tab restored."); });
+            info("Loading the tab...");
+            whenBrowserLoaded(tab2.linkedBrowser, function() { info("Tab restored."); });
           }
         );
       });
     }
   );
 }
--- a/content/media/webaudio/test/browser_mozAudioChannel_muted.js
+++ b/content/media/webaudio/test/browser_mozAudioChannel_muted.js
@@ -45,22 +45,22 @@ function test() {
         is(doc.getElementById("mozAudioChannelTest").textContent, "READY",
            "Test is ready to run");
 
         SpecialPowers.pushPrefEnv({"set": [["media.defaultAudioChannel", "telephony" ]]},
           function() {
             let tab2 = gBrowser.duplicateTab(tab1);
             gBrowser.selectedTab = tab2;
             whenTabRestored(tab2, function() {
-              is(doc.getElementById("mozAudioChannelTest").textContent, "READY",
-                 "AudioContext should not be muted by the second tab.");
+              is(doc.getElementById("mozAudioChannelTest").textContent, "mozinterruptbegin",
+                 "AudioContext should be muted by the second tab.");
 
               whenBrowserUnloaded(tab2.linkedBrowser, function() {
-                is(doc.getElementById("mozAudioChannelTest").textContent, "READY",
-                   "AudioContext should not be muted by the second tab.");
+                is(doc.getElementById("mozAudioChannelTest").textContent, "mozinterruptend",
+                   "AudioContext should be muted by the second tab.");
                 gBrowser.removeTab(tab1);
                 finish();
               });
 
               gBrowser.removeTab(tab2);
               gBrowser.selectedTab = tab1;
             });
           }
--- a/content/media/webspeech/synth/ipc/test/file_ipc.html
+++ b/content/media/webspeech/synth/ipc/test/file_ipc.html
@@ -8,16 +8,17 @@
   <body>
 
   <script type="application/javascript;version=1.7">
     "use strict";
 
     window.SimpleTest = parent.SimpleTest;
     window.ok = parent.ok;
     window.is = parent.is;
+    window.info = parent.info;
 
     function iframeScriptFirst() {
       content.wrappedJSObject.RunSet.reloadAndRunAll({
           preventDefault: function() { },
           __exposedProps__: { preventDefault: 'r' }
       });
     }
 
--- a/content/svg/content/src/SVGFEDropShadowElement.cpp
+++ b/content/svg/content/src/SVGFEDropShadowElement.cpp
@@ -104,22 +104,18 @@ SVGFEDropShadowElement::GetPrimitiveDesc
 
   FilterPrimitiveDescription descr(PrimitiveType::DropShadow);
   descr.Attributes().Set(eDropShadowStdDeviation, Size(stdX, stdY));
   descr.Attributes().Set(eDropShadowOffset, offset);
 
   nsIFrame* frame = GetPrimaryFrame();
   if (frame) {
     nsStyleContext* style = frame->StyleContext();
-    nscolor floodColor = style->StyleSVGReset()->mFloodColor;
-    float floodOpacity = style->StyleSVGReset()->mFloodOpacity;
-    Color color(NS_GET_R(floodColor) / 255.0,
-                NS_GET_G(floodColor) / 255.0,
-                NS_GET_B(floodColor) / 255.0,
-                NS_GET_A(floodColor) / 255.0 * floodOpacity);
+    Color color(Color::FromABGR(style->StyleSVGReset()->mFloodColor));
+    color.a *= style->StyleSVGReset()->mFloodOpacity;
     descr.Attributes().Set(eDropShadowColor, color);
   } else {
     descr.Attributes().Set(eDropShadowColor, Color());
   }
   return descr;
 }
 
 bool
--- a/content/svg/content/src/SVGFEFloodElement.cpp
+++ b/content/svg/content/src/SVGFEFloodElement.cpp
@@ -38,22 +38,18 @@ SVGFEFloodElement::GetPrimitiveDescripti
                                            const IntRect& aFilterSubregion,
                                            const nsTArray<bool>& aInputsAreTainted,
                                            nsTArray<RefPtr<SourceSurface>>& aInputImages)
 {
   FilterPrimitiveDescription descr(PrimitiveType::Flood);
   nsIFrame* frame = GetPrimaryFrame();
   if (frame) {
     nsStyleContext* style = frame->StyleContext();
-    nscolor floodColor = style->StyleSVGReset()->mFloodColor;
-    float floodOpacity = style->StyleSVGReset()->mFloodOpacity;
-    Color color(NS_GET_R(floodColor) / 255.0,
-                NS_GET_G(floodColor) / 255.0,
-                NS_GET_B(floodColor) / 255.0,
-                NS_GET_A(floodColor) / 255.0 * floodOpacity);
+    Color color(Color::FromABGR(style->StyleSVGReset()->mFloodColor));
+    color.a *= style->StyleSVGReset()->mFloodOpacity;
     descr.Attributes().Set(eFloodColor, color);
   } else {
     descr.Attributes().Set(eFloodColor, Color());
   }
   return descr;
 }
 
 //----------------------------------------------------------------------
--- a/content/svg/content/src/SVGZoomEvent.h
+++ b/content/svg/content/src/SVGZoomEvent.h
@@ -28,17 +28,17 @@ public:
   NS_DECL_ISUPPORTS_INHERITED
 
   SVGZoomEvent(EventTarget* aOwner, nsPresContext* aPresContext,
                InternalSVGZoomEvent* aEvent);
 
   // Forward to base class
   NS_FORWARD_TO_UIEVENT
 
-  virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE
+  virtual JSObject* WrapObjectInternal(JSContext* aCx) MOZ_OVERRIDE
   {
     return SVGZoomEventBinding::Wrap(aCx, this);
   }
 
   float PreviousScale() const
   {
     return mPreviousScale;
   }
--- a/content/svg/content/src/nsSVGFilters.cpp
+++ b/content/svg/content/src/nsSVGFilters.cpp
@@ -506,21 +506,18 @@ nsSVGFELightingElement::AddLightingAttri
                                               nsSVGFilterInstance* aInstance)
 {
   nsIFrame* frame = GetPrimaryFrame();
   if (!frame) {
     return FilterPrimitiveDescription(PrimitiveType::Empty);
   }
 
   nsStyleContext* style = frame->StyleContext();
-  nscolor lightColor = style->StyleSVGReset()->mLightingColor;
-  Color color(NS_GET_R(lightColor) / 255.0f,
-                   NS_GET_G(lightColor) / 255.0f,
-                   NS_GET_B(lightColor) / 255.0f,
-                   1.0f);
+  Color color(Color::FromABGR(style->StyleSVGReset()->mLightingColor));
+  color.a = 1.f;
   float surfaceScale = mNumberAttributes[SURFACE_SCALE].GetAnimValue();
   Size kernelUnitLength =
     GetKernelUnitLength(aInstance, &mNumberPairAttributes[KERNEL_UNIT_LENGTH]);
 
   FilterPrimitiveDescription& descr = aDescription;
   descr.Attributes().Set(eLightingLight, ComputeLightAttributes(aInstance));
   descr.Attributes().Set(eLightingSurfaceScale, surfaceScale);
   descr.Attributes().Set(eLightingKernelUnitLength, kernelUnitLength);
--- a/dom/animation/Animation.cpp
+++ b/dom/animation/Animation.cpp
@@ -2,16 +2,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/. */
 
 #include "mozilla/dom/Animation.h"
 #include "mozilla/dom/AnimationBinding.h"
 #include "mozilla/dom/AnimationEffect.h"
 #include "mozilla/FloatingPoint.h"
+#include "AnimationCommon.h"
+#include "nsCSSPropertySet.h"
 
 namespace mozilla {
 
 void
 ComputedTimingFunction::Init(const nsTimingFunction &aFunction)
 {
   mType = aFunction.mType;
   if (mType == nsTimingFunction::Function) {
@@ -257,10 +259,93 @@ Animation::HasAnimationOfProperty(nsCSSP
        propIdx != propEnd; ++propIdx) {
     if (aProperty == mProperties[propIdx].mProperty) {
       return true;
     }
   }
   return false;
 }
 
+void
+Animation::ComposeStyle(nsRefPtr<css::AnimValuesStyleRule>& aStyleRule,
+                        nsCSSPropertySet& aSetProperties)
+{
+  ComputedTiming computedTiming = GetComputedTiming();
+
+  // If the time fraction is null, we don't have fill data for the current
+  // time so we shouldn't animate.
+  if (computedTiming.mTimeFraction == ComputedTiming::kNullTimeFraction) {
+    return;
+  }
+
+  MOZ_ASSERT(0.0 <= computedTiming.mTimeFraction &&
+             computedTiming.mTimeFraction <= 1.0,
+             "timing fraction should be in [0-1]");
+
+  for (size_t propIdx = 0, propEnd = mProperties.Length();
+       propIdx != propEnd; ++propIdx)
+  {
+    const AnimationProperty& prop = mProperties[propIdx];
+
+    MOZ_ASSERT(prop.mSegments[0].mFromKey == 0.0, "incorrect first from key");
+    MOZ_ASSERT(prop.mSegments[prop.mSegments.Length() - 1].mToKey == 1.0,
+               "incorrect last to key");
+
+    if (aSetProperties.HasProperty(prop.mProperty)) {
+      // Animations are composed by AnimationPlayerCollection by iterating
+      // from the last animation to first. For animations targetting the
+      // same property, the later one wins. So if this property is already set,
+      // we should not override it.
+      return;
+    }
+
+    aSetProperties.AddProperty(prop.mProperty);
+
+    MOZ_ASSERT(prop.mSegments.Length() > 0,
+               "property should not be in animations if it has no segments");
+
+    // FIXME: Maybe cache the current segment?
+    const AnimationPropertySegment *segment = prop.mSegments.Elements(),
+                                *segmentEnd = segment + prop.mSegments.Length();
+    while (segment->mToKey < computedTiming.mTimeFraction) {
+      MOZ_ASSERT(segment->mFromKey < segment->mToKey, "incorrect keys");
+      ++segment;
+      if (segment == segmentEnd) {
+        MOZ_ASSERT_UNREACHABLE("incorrect time fraction");
+        break; // in order to continue in outer loop (just below)
+      }
+      MOZ_ASSERT(segment->mFromKey == (segment-1)->mToKey, "incorrect keys");
+    }
+    if (segment == segmentEnd) {
+      continue;
+    }
+    MOZ_ASSERT(segment->mFromKey < segment->mToKey, "incorrect keys");
+    MOZ_ASSERT(segment >= prop.mSegments.Elements() &&
+               size_t(segment - prop.mSegments.Elements()) <
+                 prop.mSegments.Length(),
+               "out of array bounds");
+
+    if (!aStyleRule) {
+      // Allocate the style rule now that we know we have animation data.
+      aStyleRule = new css::AnimValuesStyleRule();
+    }
+
+    double positionInSegment =
+      (computedTiming.mTimeFraction - segment->mFromKey) /
+      (segment->mToKey - segment->mFromKey);
+    double valuePosition =
+      segment->mTimingFunction.GetValue(positionInSegment);
+
+    StyleAnimationValue *val = aStyleRule->AddEmptyValue(prop.mProperty);
+
+#ifdef DEBUG
+    bool result =
+#endif
+      StyleAnimationValue::Interpolate(prop.mProperty,
+                                       segment->mFromValue,
+                                       segment->mToValue,
+                                       valuePosition, *val);
+    MOZ_ASSERT(result, "interpolate must succeed now");
+  }
+}
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/animation/Animation.h
+++ b/dom/animation/Animation.h
@@ -16,18 +16,22 @@
 #include "mozilla/StyleAnimationValue.h"
 #include "mozilla/TimeStamp.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/Nullable.h"
 #include "nsSMILKeySpline.h"
 #include "nsStyleStruct.h" // for nsTimingFunction
 
 struct JSContext;
+class nsCSSPropertySet;
 
 namespace mozilla {
+namespace css {
+class AnimValuesStyleRule;
+} // namespace css
 
 /**
  * Input timing parameters.
  *
  * Eventually this will represent all the input timing parameters specified
  * by content but for now it encapsulates just the subset of those
  * parameters passed to GetPositionInIteration.
  */
@@ -134,17 +138,16 @@ public:
             nsCSSPseudoElements::Type aPseudoType,
             const AnimationTiming &aTiming,
             const nsSubstring& aName)
     : mDocument(aDocument)
     , mTarget(aTarget)
     , mTiming(aTiming)
     , mName(aName)
     , mIsFinishedTransition(false)
-    , mLastNotification(LAST_NOTIFICATION_NONE)
     , mPseudoType(aPseudoType)
   {
     MOZ_ASSERT(aTarget, "null animation target is not yet supported");
   }
 
   NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(Animation)
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(Animation)
 
@@ -160,24 +163,32 @@ public:
   }
 
   // Animation interface
   // This currently returns a new object each time when used from C++ but is
   // cached when used from JS.
   already_AddRefed<AnimationEffect> GetEffect();
   Element* GetTarget() const {
     // Currently we only implement Element.getAnimationPlayers() which only
-    // returns animations targetting Elements so we should this should never
+    // returns animations targetting Elements so this should never
     // be called for an animation that targets a pseudo-element.
     MOZ_ASSERT(mPseudoType == nsCSSPseudoElements::ePseudo_NotPseudoElement,
                "Requesting the target of an Animation that targets a"
                " pseudo-element is not yet supported.");
     return mTarget;
   }
 
+  // Temporary workaround to return both the target element and pseudo-type
+  // until we implement PseudoElement.
+  void GetTarget(Element*& aTarget,
+                 nsCSSPseudoElements::Type& aPseudoType) const {
+    aTarget = mTarget;
+    aPseudoType = mPseudoType;
+  }
+
   void SetParentTime(Nullable<TimeDuration> aParentTime);
 
   const AnimationTiming& Timing() const {
     return mTiming;
   }
   AnimationTiming& Timing() {
     return mTiming;
   }
@@ -237,50 +248,45 @@ public:
     MOZ_ASSERT(AsTransition(),
                "Calling SetIsFinishedTransition but it's not a transition");
     mIsFinishedTransition = true;
   }
 
   bool IsCurrent() const;
   bool IsInEffect() const;
 
-  enum {
-    LAST_NOTIFICATION_NONE = uint64_t(-1),
-    LAST_NOTIFICATION_END = uint64_t(-2)
-  };
-  uint64_t LastNotification() const { return mLastNotification; }
-  void SetLastNotification(uint64_t aLastNotification) {
-    mLastNotification = aLastNotification;
-  }
-
   bool HasAnimationOfProperty(nsCSSProperty aProperty) const;
   const InfallibleTArray<AnimationProperty>& Properties() const {
     return mProperties;
   }
   InfallibleTArray<AnimationProperty>& Properties() {
     return mProperties;
   }
 
+  // Updates |aStyleRule| with the animation values produced by this
+  // Animation for the current time except any properties already contained
+  // in |aSetProperties|.
+  // Any updated properties are added to |aSetProperties|.
+  void ComposeStyle(nsRefPtr<css::AnimValuesStyleRule>& aStyleRule,
+                    nsCSSPropertySet& aSetProperties);
+
 protected:
   virtual ~Animation() { }
 
   // We use a document for a parent object since the other likely candidate,
   // the target element, can be empty.
   nsCOMPtr<nsIDocument> mDocument;
   nsCOMPtr<Element> mTarget;
   Nullable<TimeDuration> mParentTime;
 
   AnimationTiming mTiming;
   nsString mName;
   // A flag to mark transitions that have finished and are due to
   // be removed on the next throttle-able cycle.
   bool mIsFinishedTransition;
-  // One of the LAST_NOTIFICATION_* constants, or an integer for the iteration
-  // whose start we last notified on.
-  uint64_t mLastNotification;
   nsCSSPseudoElements::Type mPseudoType;
 
   InfallibleTArray<AnimationProperty> mProperties;
 };
 
 } // namespace dom
 } // namespace mozilla
 
--- a/dom/animation/AnimationPlayer.cpp
+++ b/dom/animation/AnimationPlayer.cpp
@@ -1,16 +1,17 @@
 /* vim: set shiftwidth=2 tabstop=8 autoindent cindent expandtab: */
 /* 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 "AnimationPlayer.h"
 #include "AnimationUtils.h"
 #include "mozilla/dom/AnimationPlayerBinding.h"
+#include "nsLayoutUtils.h" // For PostRestyleEvent (remove after bug 1073336)
 
 namespace mozilla {
 namespace dom {
 
 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(AnimationPlayer, mTimeline, mSource)
 
 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(AnimationPlayer, AddRef)
 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(AnimationPlayer, Release)
@@ -22,62 +23,258 @@ AnimationPlayer::WrapObject(JSContext* a
 }
 
 Nullable<double>
 AnimationPlayer::GetStartTime() const
 {
   return AnimationUtils::TimeDurationToDouble(mStartTime);
 }
 
-Nullable<double>
+Nullable<TimeDuration>
 AnimationPlayer::GetCurrentTime() const
 {
-  return AnimationUtils::TimeDurationToDouble(GetCurrentTimeDuration());
+  Nullable<TimeDuration> result;
+  if (!mHoldTime.IsNull()) {
+    result = mHoldTime;
+  } else {
+    Nullable<TimeDuration> timelineTime = mTimeline->GetCurrentTime();
+    if (!timelineTime.IsNull() && !mStartTime.IsNull()) {
+      result.SetValue(timelineTime.Value() - mStartTime.Value());
+    }
+  }
+  return result;
+}
+
+AnimationPlayState
+AnimationPlayer::PlayState() const
+{
+  Nullable<TimeDuration> currentTime = GetCurrentTime();
+  if (currentTime.IsNull()) {
+    return AnimationPlayState::Idle;
+  }
+
+  if (mIsPaused) {
+    return AnimationPlayState::Paused;
+  }
+
+  if (currentTime.Value() >= SourceContentEnd()) {
+    return AnimationPlayState::Finished;
+  }
+
+  return AnimationPlayState::Running;
+}
+
+void
+AnimationPlayer::Play(UpdateFlags aFlags)
+{
+  // FIXME: When we implement finishing behavior (bug 1074630) we should
+  // not return early if mIsPaused is false since we may still need to seek.
+  // (However, we will need to pass a flag so that when we start playing due to
+  //  a change in animation-play-state we *don't* trigger finishing behavior.)
+  if (!mIsPaused) {
+    return;
+  }
+  mIsPaused = false;
+
+  Nullable<TimeDuration> timelineTime = mTimeline->GetCurrentTime();
+  if (timelineTime.IsNull()) {
+    // FIXME: We should just sit in the pending state in this case.
+    // We will introduce the pending state in Bug 927349.
+    return;
+  }
+
+  // Update start time to an appropriate offset from the current timeline time
+  MOZ_ASSERT(!mHoldTime.IsNull(), "Hold time should not be null when paused");
+  mStartTime.SetValue(timelineTime.Value() - mHoldTime.Value());
+  mHoldTime.SetNull();
+
+  if (aFlags == eUpdateStyle) {
+    MaybePostRestyle();
+  }
+}
+
+void
+AnimationPlayer::Pause(UpdateFlags aFlags)
+{
+  if (mIsPaused) {
+    return;
+  }
+  mIsPaused = true;
+  mIsRunningOnCompositor = false;
+
+  // Bug 927349 - check for null result here and go to pending state
+  mHoldTime = GetCurrentTime();
+  mStartTime.SetNull();
+
+  if (aFlags == eUpdateStyle) {
+    MaybePostRestyle();
+  }
+}
+
+Nullable<double>
+AnimationPlayer::GetCurrentTimeAsDouble() const
+{
+  return AnimationUtils::TimeDurationToDouble(GetCurrentTime());
+}
+
+AnimationPlayState
+AnimationPlayer::PlayStateFromJS() const
+{
+  // FIXME: Once we introduce CSSTransitionPlayer, this should move to an
+  // override of PlayStateFromJS in CSSAnimationPlayer and CSSTransitionPlayer
+  // and we should skip it in the general case.
+  FlushStyle();
+
+  return PlayState();
+}
+
+void
+AnimationPlayer::PlayFromJS()
+{
+  // Flush style to ensure that any properties controlling animation state
+  // (e.g. animation-play-state) are fully updated before we proceed.
+  //
+  // Note that this might trigger PlayFromStyle()/PauseFromStyle() on this
+  // object.
+  //
+  // FIXME: Once we introduce CSSTransitionPlayer, this should move to an
+  // override of PlayFromJS in CSSAnimationPlayer and CSSTransitionPlayer and
+  // we should skip it in the general case.
+  FlushStyle();
+
+  Play(eUpdateStyle);
+}
+
+void
+AnimationPlayer::PauseFromJS()
+{
+  Pause(eUpdateStyle);
 }
 
 void
 AnimationPlayer::SetSource(Animation* aSource)
 {
   if (mSource) {
     mSource->SetParentTime(Nullable<TimeDuration>());
   }
   mSource = aSource;
   if (mSource) {
-    mSource->SetParentTime(GetCurrentTimeDuration());
+    mSource->SetParentTime(GetCurrentTime());
   }
 }
 
 void
 AnimationPlayer::Tick()
 {
   if (mSource) {
-    mSource->SetParentTime(GetCurrentTimeDuration());
+    mSource->SetParentTime(GetCurrentTime());
   }
 }
 
 bool
 AnimationPlayer::IsRunning() const
 {
   if (IsPaused() || !GetSource() || GetSource()->IsFinishedTransition()) {
     return false;
   }
 
   ComputedTiming computedTiming = GetSource()->GetComputedTiming();
   return computedTiming.mPhase == ComputedTiming::AnimationPhase_Active;
 }
 
-Nullable<TimeDuration>
-AnimationPlayer::GetCurrentTimeDuration() const
+bool
+AnimationPlayer::CanThrottle() const
+{
+  if (!mSource ||
+      mSource->IsFinishedTransition() ||
+      mSource->Properties().IsEmpty()) {
+    return true;
+  }
+
+  if (!mIsRunningOnCompositor) {
+    return false;
+  }
+
+  if (PlayState() != AnimationPlayState::Finished) {
+    // Unfinished animations can be throttled.
+    return true;
+  }
+
+  // The animation has finished but, if this is the first sample since
+  // finishing, we need an unthrottled sample so we can apply the correct
+  // end-of-animation behavior on the main thread (either removing the
+  // animation style or applying the fill mode).
+  return mIsPreviousStateFinished;
+}
+
+void
+AnimationPlayer::ComposeStyle(nsRefPtr<css::AnimValuesStyleRule>& aStyleRule,
+                              nsCSSPropertySet& aSetProperties,
+                              bool& aNeedsRefreshes)
+{
+  if (!mSource || mSource->IsFinishedTransition()) {
+    return;
+  }
+
+  AnimationPlayState playState = PlayState();
+  if (playState == AnimationPlayState::Running) {
+    aNeedsRefreshes = true;
+  }
+
+  mSource->ComposeStyle(aStyleRule, aSetProperties);
+
+  mIsPreviousStateFinished = (playState == AnimationPlayState::Finished);
+}
+
+void
+AnimationPlayer::FlushStyle() const
 {
-  Nullable<TimeDuration> result;
-  if (!mHoldTime.IsNull()) {
-    result = mHoldTime;
-  } else {
-    Nullable<TimeDuration> timelineTime = mTimeline->GetCurrentTimeDuration();
-    if (!timelineTime.IsNull() && !mStartTime.IsNull()) {
-      result.SetValue(timelineTime.Value() - mStartTime.Value());
-    }
+  if (!mSource) {
+    return;
+  }
+
+  Element* targetElement;
+  nsCSSPseudoElements::Type pseudoType;
+  mSource->GetTarget(targetElement, pseudoType);
+  if (!targetElement) {
+    return;
+  }
+
+  nsIDocument* doc = targetElement->GetComposedDoc();
+  if (doc) {
+    doc->FlushPendingNotifications(Flush_Style);
+  }
+}
+
+void
+AnimationPlayer::MaybePostRestyle() const
+{
+  if (!mSource) {
+    return;
   }
-  return result;
+
+  Element* targetElement;
+  nsCSSPseudoElements::Type pseudoType;
+  mSource->GetTarget(targetElement, pseudoType);
+  if (!targetElement) {
+    return;
+  }
+
+  // FIXME: This is a bit heavy-handed but in bug 1073336 we hope to
+  // introduce a better means for players to update style.
+  nsLayoutUtils::PostRestyleEvent(targetElement,
+                                  eRestyle_Self,
+                                  nsChangeHint_AllReflowHints);
+}
+
+StickyTimeDuration
+AnimationPlayer::SourceContentEnd() const
+{
+  if (!mSource) {
+    return StickyTimeDuration(0);
+  }
+
+  return mSource->Timing().mDelay
+         + mSource->GetComputedTiming().mActiveDuration;
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/animation/AnimationPlayer.h
+++ b/dom/animation/AnimationPlayer.h
@@ -1,91 +1,143 @@
 /* vim: set shiftwidth=2 tabstop=8 autoindent cindent expandtab: */
 /* 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_AnimationPlayer_h
 #define mozilla_dom_AnimationPlayer_h
 
-#include <algorithm> // for std::max
 #include "nsWrapperCache.h"
 #include "nsCycleCollectionParticipant.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/TimeStamp.h" // for TimeStamp, TimeDuration
 #include "mozilla/dom/Animation.h" // for Animation
+#include "mozilla/dom/AnimationPlayerBinding.h" // for AnimationPlayState
 #include "mozilla/dom/AnimationTimeline.h" // for AnimationTimeline
 #include "nsCSSProperty.h" // for nsCSSProperty
 
 // X11 has a #define for CurrentTime.
 #ifdef CurrentTime
 #undef CurrentTime
 #endif
 
 struct JSContext;
+class nsCSSPropertySet;
 
 namespace mozilla {
+namespace css {
+class AnimValuesStyleRule;
+} // namespace css
+
+class CSSAnimationPlayer;
+
 namespace dom {
 
-class AnimationPlayer MOZ_FINAL : public nsWrapperCache
+class AnimationPlayer : public nsWrapperCache
 {
 protected:
   virtual ~AnimationPlayer() { }
 
 public:
   explicit AnimationPlayer(AnimationTimeline* aTimeline)
-    : mPlayState(NS_STYLE_ANIMATION_PLAY_STATE_RUNNING)
+    : mTimeline(aTimeline)
+    , mIsPaused(false)
     , mIsRunningOnCompositor(false)
-    , mTimeline(aTimeline)
+    , mIsPreviousStateFinished(false)
   {
   }
 
   NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(AnimationPlayer)
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(AnimationPlayer)
 
   AnimationTimeline* GetParentObject() const { return mTimeline; }
   virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE;
 
+  virtual CSSAnimationPlayer* AsCSSAnimationPlayer() { return nullptr; }
+
+  // Temporary flags to control restyle behavior until bug 1073336
+  // provides a better solution.
+  enum UpdateFlags {
+    eNoUpdate,
+    eUpdateStyle
+  };
+
   // AnimationPlayer methods
   Animation* GetSource() const { return mSource; }
   AnimationTimeline* Timeline() const { return mTimeline; }
   Nullable<double> GetStartTime() const;
-  Nullable<double> GetCurrentTime() const;
+  Nullable<TimeDuration> GetCurrentTime() const;
+  AnimationPlayState PlayState() const;
+  virtual void Play(UpdateFlags aUpdateFlags);
+  virtual void Pause(UpdateFlags aUpdateFlags);
   bool IsRunningOnCompositor() const { return mIsRunningOnCompositor; }
 
+  // Wrapper functions for AnimationPlayer DOM methods when called
+  // from script. We often use the same methods internally and from
+  // script but when called from script we perform extra steps such
+  // as flushing style or converting the return type.
+  Nullable<double> GetCurrentTimeAsDouble() const;
+  AnimationPlayState PlayStateFromJS() const;
+  void PlayFromJS();
+  void PauseFromJS();
+
   void SetSource(Animation* aSource);
   void Tick();
 
   const nsString& Name() const {
     return mSource ? mSource->Name() : EmptyString();
   }
 
-  bool IsPaused() const {
-    return mPlayState == NS_STYLE_ANIMATION_PLAY_STATE_PAUSED;
-  }
-
+  bool IsPaused() const { return mIsPaused; }
   bool IsRunning() const;
 
   bool HasCurrentSource() const {
     return GetSource() && GetSource()->IsCurrent();
   }
   bool HasInEffectSource() const {
     return GetSource() && GetSource()->IsInEffect();
   }
 
-  // Return the duration since the start time of the player, taking into
-  // account the pause state.  May be negative or null.
-  Nullable<TimeDuration> GetCurrentTimeDuration() const;
+  void SetIsRunningOnCompositor() { mIsRunningOnCompositor = true; }
+  void ClearIsRunningOnCompositor() { mIsRunningOnCompositor = false; }
+
+  // Returns true if this animation does not currently need to update
+  // style on the main thread (e.g. because it is empty, or is
+  // running on the compositor).
+  bool CanThrottle() const;
+
+  // Updates |aStyleRule| with the animation values of this player's source
+  // content, if any.
+  // Any properties already contained in |aSetProperties| are not changed. Any
+  // properties that are changed are added to |aSetProperties|.
+  // |aNeedsRefreshes| will be set to true if this player expects to update
+  // the style rule on the next refresh driver tick as well (because it
+  // is running and has source content to sample).
+  void ComposeStyle(nsRefPtr<css::AnimValuesStyleRule>& aStyleRule,
+                    nsCSSPropertySet& aSetProperties,
+                    bool& aNeedsRefreshes);
 
   // The beginning of the delay period.
-  Nullable<TimeDuration> mStartTime;
-  Nullable<TimeDuration> mHoldTime;
-  uint8_t mPlayState;
-  bool mIsRunningOnCompositor;
+  Nullable<TimeDuration> mStartTime; // Timeline timescale
+
+protected:
+  void FlushStyle() const;
+  void MaybePostRestyle() const;
+  StickyTimeDuration SourceContentEnd() const;
 
   nsRefPtr<AnimationTimeline> mTimeline;
   nsRefPtr<Animation> mSource;
+  Nullable<TimeDuration> mHoldTime;  // Player timescale
+  bool mIsPaused;
+  bool mIsRunningOnCompositor;
+  // Indicates whether we were in the finished state during our
+  // most recent unthrottled sample (our last ComposeStyle call).
+  // FIXME: When we implement the finished promise (bug 1074630) we can
+  // probably remove this and check if the promise has been settled yet
+  // or not instead.
+  bool mIsPreviousStateFinished; // Spec calls this "previous finished state"
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_AnimationPlayer_h
--- a/dom/animation/AnimationTimeline.cpp
+++ b/dom/animation/AnimationTimeline.cpp
@@ -21,20 +21,26 @@ NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(Ani
 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(AnimationTimeline, Release)
 
 JSObject*
 AnimationTimeline::WrapObject(JSContext* aCx)
 {
   return AnimationTimelineBinding::Wrap(aCx, this);
 }
 
-Nullable<double>
+Nullable<TimeDuration>
 AnimationTimeline::GetCurrentTime() const
 {
-  return AnimationUtils::TimeDurationToDouble(GetCurrentTimeDuration());
+  return ToTimelineTime(GetCurrentTimeStamp());
+}
+
+Nullable<double>
+AnimationTimeline::GetCurrentTimeAsDouble() const
+{
+  return AnimationUtils::TimeDurationToDouble(GetCurrentTime());
 }
 
 TimeStamp
 AnimationTimeline::GetCurrentTimeStamp() const
 {
   // Always return the same object to benefit from return-value optimization.
   TimeStamp result = mLastCurrentTime;
 
@@ -64,22 +70,16 @@ AnimationTimeline::GetCurrentTimeStamp()
   //   mLastCurrentTime.IsNull() || result >= mLastCurrentTime
   // but due to bug 1043078 this will not be the case when the refresh driver
   // is restored from test control.
   mLastCurrentTime = result;
   return result;
 }
 
 Nullable<TimeDuration>
-AnimationTimeline::GetCurrentTimeDuration() const
-{
-  return ToTimelineTime(GetCurrentTimeStamp());
-}
-
-Nullable<TimeDuration>
 AnimationTimeline::ToTimelineTime(const TimeStamp& aTimeStamp) const
 {
   Nullable<TimeDuration> result; // Initializes to null
   if (aTimeStamp.IsNull()) {
     return result;
   }
 
   nsRefPtr<nsDOMNavigationTiming> timing = mDocument->GetNavigationTiming();
--- a/dom/animation/AnimationTimeline.h
+++ b/dom/animation/AnimationTimeline.h
@@ -27,20 +27,22 @@ public:
   }
 
   NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(AnimationTimeline)
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(AnimationTimeline)
 
   nsISupports* GetParentObject() const { return mDocument; }
   virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE;
 
-  // WebIDL API
-  Nullable<double> GetCurrentTime() const;
+  // AnimationTimeline methods
+  Nullable<TimeDuration> GetCurrentTime() const;
 
-  Nullable<TimeDuration> GetCurrentTimeDuration() const;
+  // Wrapper functions for AnimationTimeline DOM methods when called from
+  // script.
+  Nullable<double> GetCurrentTimeAsDouble() const;
 
   Nullable<TimeDuration> ToTimelineTime(const TimeStamp& aTimeStamp) const;
   TimeStamp ToTimeStamp(const TimeDuration& aTimelineTime) const;
 
 protected:
   TimeStamp GetCurrentTimeStamp() const;
 
   virtual ~AnimationTimeline() { }
new file mode 100644
--- /dev/null
+++ b/dom/animation/test/css-integration/test_animation-pausing.html
@@ -0,0 +1,253 @@
+<!doctype html>
+<meta charset=utf-8>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<style>
+@keyframes anim { 
+  0% { margin-left: 0px }
+  100% { margin-left: 10000px }
+}
+</style>
+<script>
+'use strict';
+
+function addDiv() {
+  var div = document.createElement('div');
+  document.body.appendChild(div);
+  return div;
+}
+
+function waitForFrame() {
+  return new Promise(function(resolve, reject) {
+    window.requestAnimationFrame(resolve);
+  });
+}
+
+function getMarginLeft(cs) {
+  return parseFloat(cs.marginLeft);
+}
+
+async_test(function(t) {
+  var div = addDiv();
+  var cs = window.getComputedStyle(div);
+  div.style.animation = 'anim 1000s';
+
+  var player = div.getAnimationPlayers()[0];
+
+  assert_equals(getMarginLeft(cs), 0,
+                'Initial value of margin-left is zero');
+  var previousAnimVal = getMarginLeft(cs);
+
+  waitForFrame().then(function() {
+    t.step(function() {
+      assert_true(getMarginLeft(cs) > previousAnimVal,
+                  'margin-left is initially increasing');
+      previousAnimVal = getMarginLeft(cs);
+
+      player.pause();
+    });
+    return waitForFrame();
+  }).then(function() {
+    t.step(function() {
+      assert_equals(getMarginLeft(cs), previousAnimVal,
+                    'margin-left does not increase after calling pause()');
+    });
+    div.remove();
+    t.done();
+  });
+}, 'pause() a running animation');
+
+async_test(function(t) {
+  var div = addDiv();
+  var cs = window.getComputedStyle(div);
+  div.style.animation = 'anim 1000s paused';
+
+  var player = div.getAnimationPlayers()[0];
+  assert_equals(getMarginLeft(cs), 0,
+                'Initial value of margin-left is zero');
+
+  player.pause();
+  div.style.animationPlayState = 'running';
+  cs.animationPlayState; // Trigger style resolution
+
+  waitForFrame().then(function() {
+    t.step(function() {
+      assert_equals(cs.animationPlayState, 'running',
+                    'animation-play-state is running');
+      assert_equals(getMarginLeft(cs), 0,
+                    'Paused value of margin-left is zero');
+    });
+    div.remove();
+    t.done();
+  });
+}, 'pause() overrides animation-play-state');
+
+async_test(function(t) {
+  var div = addDiv();
+  var cs = window.getComputedStyle(div);
+  div.style.animation = 'anim 1000s paused';
+
+  var player = div.getAnimationPlayers()[0];
+
+  assert_equals(getMarginLeft(cs), 0,
+                'Initial value of margin-left is zero');
+
+  player.play();
+
+  waitForFrame().then(function() {
+    t.step(function() {
+      assert_true(getMarginLeft(cs) > 0,
+                  'Playing value of margin-left is greater than zero');
+    });
+    div.remove();
+    t.done();
+  });
+}, 'play() overrides animation-play-state');
+
+async_test(function(t) {
+  var div = addDiv();
+  var cs = window.getComputedStyle(div);
+  div.style.animation = 'anim 1000s paused';
+
+  var player = div.getAnimationPlayers()[0];
+  assert_equals(getMarginLeft(cs), 0,
+                'Initial value of margin-left is zero');
+
+  player.play();
+  div.style.animationPlayState = 'running';
+  cs.animationPlayState; // Trigger style resolution
+
+  var previousAnimVal;
+
+  waitForFrame().then(function() {
+    t.step(function() {
+      assert_equals(cs.animationPlayState, 'running',
+                    'animation-play-state is running');
+      previousAnimVal = getMarginLeft(cs);
+      div.style.animationPlayState = 'paused';
+      cs.animationPlayState; // Trigger style resolution
+    });
+    return waitForFrame();
+  }).then(function() {
+    t.step(function() {
+      assert_equals(cs.animationPlayState, 'paused',
+                    'animation-play-state is paused');
+      assert_equals(getMarginLeft(cs), previousAnimVal,
+                    'Animated value of margin-left does not change when'
+                    + ' paused by style');
+    });
+    div.remove();
+    t.done();
+  });
+}, 'play() is overridden by later setting "animation-play-state: paused"');
+
+async_test(function(t) {
+  var div = addDiv();
+  var cs = window.getComputedStyle(div);
+  div.style.animation = 'anim 1000s';
+
+  var player = div.getAnimationPlayers()[0];
+  assert_equals(getMarginLeft(cs), 0,
+                'Initial value of margin-left is zero');
+
+  // Set the specified style first. If implementations fail to
+  // apply the style changes first, they will ignore the redundant
+  // call to play() and fail to correctly override the pause style.
+  div.style.animationPlayState = 'paused';
+  player.play();
+  var previousAnimVal = getMarginLeft(cs);
+
+  waitForFrame().then(function() {
+    t.step(function() {
+      assert_equals(cs.animationPlayState, 'paused',
+                    'animation-play-state is paused');
+      assert_true(getMarginLeft(cs) > previousAnimVal,
+                  'Playing value of margin-left is increasing');
+    });
+    div.remove();
+    t.done();
+  });
+}, 'play() flushes pending changes to animation-play-state first');
+
+async_test(function(t) {
+  var div = addDiv();
+  var cs = window.getComputedStyle(div);
+  div.style.animation = 'anim 1000s paused';
+
+  var player = div.getAnimationPlayers()[0];
+  assert_equals(getMarginLeft(cs), 0,
+                'Initial value of margin-left is zero');
+
+  // Unlike the previous test for play(), since calling pause() is sticky,
+  // we'll apply it even if the underlying style also says we're paused.
+  // 
+  // We would like to test that implementations flush styles before running
+  // pause() but actually there's no style we can currently set that will
+  // change the behavior of pause(). That may change in the future
+  // (e.g. if we introduce animation-timeline or animation-playback-rate etc.).
+  //
+  // For now this just serves as a sanity check that we do the same thing
+  // even if we set style before calling the API.
+  div.style.animationPlayState = 'running';
+  player.pause();
+  var previousAnimVal = getMarginLeft(cs);
+
+  waitForFrame().then(function() {
+    t.step(function() {
+      assert_equals(cs.animationPlayState, 'running',
+                    'animation-play-state is paused');
+      assert_equals(getMarginLeft(cs), previousAnimVal,
+                    'Paused value of margin-left does not change');
+    });
+    div.remove();
+    t.done();
+  });
+}, 'pause() applies pending changes to animation-play-state first');
+// (Note that we can't actually test for this; see comment above, in test-body.)
+
+/* Disabled until bug 1073336 lands */
+if (false) {
+async_test(function(t) {
+  var div = addDiv();
+  var cs = window.getComputedStyle(div);
+
+  div.style.marginLeft = '0px';
+  cs.marginLeft; // Flush style to set up transition start point
+  div.style.transition = 'margin-left 100s';
+  div.style.marginLeft = '10000px';
+  cs.marginLeft;
+
+  var player = div.getAnimationPlayers()[0];
+  assert_equals(getMarginLeft(cs), 0,
+                'Initial value of margin-left is zero');
+  var previousAnimVal = getMarginLeft(cs);
+
+  waitForFrame().then(function() {
+    t.step(function() {
+      assert_true(getMarginLeft(cs) > previousAnimVal,
+                  'margin-left is initially increasing');
+      previousAnimVal = getMarginLeft(cs);
+      player.pause();
+    });
+    return waitForFrame();
+  }).then(function() {
+    t.step(function() {
+      assert_equals(getMarginLeft(cs), previousAnimVal,
+                    'margin-left does not increase after calling pause()');
+      previousAnimVal = getMarginLeft(cs);
+      player.play();
+    });
+    return waitForFrame();
+  }).then(function() {
+    t.step(function() {
+      assert_true(getMarginLeft(cs) > previousAnimVal,
+                  'margin-left increases after calling play()');
+    });
+    div.remove();
+    t.done();
+  });
+}, 'pause() and play() a transition');
+}
+
+</script>
new file mode 100644
--- /dev/null
+++ b/dom/animation/test/css-integration/test_animation-player-playstate.html
@@ -0,0 +1,57 @@
+<!doctype html>
+<meta charset=utf-8>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<style>
+@keyframes anim { }
+</style>
+<script>
+'use strict';
+
+function addDiv() {
+  var div = document.createElement('div');
+  document.body.appendChild(div);
+  return div;
+}
+
+test(function() {
+  var div = addDiv();
+  var cs = window.getComputedStyle(div);
+  div.style.animation = 'anim 1000s';
+
+  var player = div.getAnimationPlayers()[0];
+  assert_equals(player.playState, 'running');
+}, 'Player returns correct playState when running');
+
+test(function() {
+  var div = addDiv();
+  var cs = window.getComputedStyle(div);
+  div.style.animation = 'anim 1000s paused';
+
+  var player = div.getAnimationPlayers()[0];
+  assert_equals(player.playState, 'paused');
+}, 'Player returns correct playState when paused');
+
+test(function() {
+  var div = addDiv();
+  var cs = window.getComputedStyle(div);
+  div.style.animation = 'anim 1000s';
+
+  var player = div.getAnimationPlayers()[0];
+  player.pause();
+  assert_equals(player.playState, 'paused');
+}, 'Player.playState updates when paused by script');
+
+test(function() {
+  var div = addDiv();
+  var cs = window.getComputedStyle(div);
+  div.style.animation = 'anim 1000s paused';
+
+  var player = div.getAnimationPlayers()[0];
+  div.style.animationPlayState = 'running';
+  // This test also checks that calling playState flushes style
+  assert_equals(player.playState, 'running');
+}, 'Player.playState updates when resumed by setting style');
+
+</script>
--- a/dom/animation/test/css-integration/test_element-get-animation-players.html
+++ b/dom/animation/test/css-integration/test_element-get-animation-players.html
@@ -318,18 +318,18 @@ test(function() {
 test(function() {
   var div = addDiv();
   div.style.animation = 'anim1 100s';
   var originalPlayer = div.getAnimationPlayers()[0];
 
   // Update pause state (an AnimationPlayer change)
   div.style.animationPlayState = 'paused';
   var pausedPlayer = div.getAnimationPlayers()[0];
-  // FIXME: Check pausedPlayer.playState has changed once the API is available
-  // (bug 1037321)
+  assert_equals(pausedPlayer.playState, 'paused',
+                'player\'s paused state is updated');
   assert_equals(originalPlayer, pausedPlayer,
                 'getAnimationPlayers returns the same objects even when their'
                 + ' play state changes');
 
   // Update duration (an Animation change)
   div.style.animationDuration = '200s';
   var extendedPlayer = div.getAnimationPlayers()[0];
   // FIXME: Check extendedPlayer.source.timing.duration has changed once the
--- a/dom/animation/test/mochitest.ini
+++ b/dom/animation/test/mochitest.ini
@@ -1,7 +1,9 @@
 [animation-timeline/test_animation-timeline.html]
 skip-if = buildapp == 'mulet'
 [css-integration/test_element-get-animation-players.html]
 skip-if = buildapp == 'mulet'
 [css-integration/test_animations-dynamic-changes.html]
 [css-integration/test_animation-effect-name.html]
+[css-integration/test_animation-pausing.html]
+[css-integration/test_animation-player-playstate.html]
 [css-integration/test_animation-target.html]
--- a/dom/audiochannel/AudioChannelService.cpp
+++ b/dom/audiochannel/AudioChannelService.cpp
@@ -10,16 +10,17 @@
 #include "base/basictypes.h"
 
 #include "mozilla/Services.h"
 #include "mozilla/StaticPtr.h"
 #include "mozilla/unused.h"
 
 #include "mozilla/dom/ContentParent.h"
 
+#include "nsISupportsPrimitives.h"
 #include "nsThreadUtils.h"
 #include "nsHashPropertyBag.h"
 #include "nsComponentManagerUtils.h"
 #include "nsPIDOMWindow.h"
 #include "nsServiceManagerUtils.h"
 #include "mozilla/dom/SettingChangeNotificationBinding.h"
 
 #ifdef MOZ_WIDGET_GONK
@@ -107,16 +108,17 @@ AudioChannelService::AudioChannelService
 , mDisabled(false)
 , mDefChannelChildID(CONTENT_PROCESS_ID_UNKNOWN)
 {
   if (XRE_GetProcessType() == GeckoProcessType_Default) {
     nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
     if (obs) {
       obs->AddObserver(this, "ipc:content-shutdown", false);
       obs->AddObserver(this, "xpcom-shutdown", false);
+      obs->AddObserver(this, "inner-window-destroyed", false);
 #ifdef MOZ_WIDGET_GONK
       // To monitor the volume settings based on audio channel.
       obs->AddObserver(this, "mozsettings-changed", false);
 #endif
     }
   }
 }
 
@@ -217,16 +219,17 @@ AudioChannelService::UnregisterAudioChan
 
   nsAutoPtr<AudioChannelAgentData> data;
   mAgents.RemoveAndForget(aAgent, data);
 
   if (data) {
     UnregisterType(data->mChannel, data->mElementHidden,
                    CONTENT_PROCESS_ID_MAIN, data->mWithVideo);
   }
+
 #ifdef MOZ_WIDGET_GONK
   bool active = AnyAudioChannelIsActive();
   for (uint32_t i = 0; i < mSpeakerManager.Length(); i++) {
     mSpeakerManager[i]->SetAudioChannelActive(active);
   }
 #endif
 
   // If this is the last agent for this window, we must notify the observers.
@@ -741,16 +744,38 @@ AudioChannelService::ChannelsActiveWithH
     if (!mChannelCounters[i].IsEmpty()) {
       return true;
     }
   }
 
   return false;
 }
 
+PLDHashOperator
+AudioChannelService::WindowDestroyedEnumerator(AudioChannelAgent* aAgent,
+                                               nsAutoPtr<AudioChannelAgentData>& aData,
+                                               void* aPtr)
+{
+  uint64_t* innerID = static_cast<uint64_t*>(aPtr);
+  MOZ_ASSERT(innerID);
+
+  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aAgent->Window());
+  if (!window || window->WindowID() != *innerID) {
+    return PL_DHASH_NEXT;
+  }
+
+  AudioChannelService* service = AudioChannelService::GetAudioChannelService();
+  MOZ_ASSERT(service);
+
+  service->UnregisterType(aData->mChannel, aData->mElementHidden,
+                          CONTENT_PROCESS_ID_MAIN, aData->mWithVideo);
+
+  return PL_DHASH_REMOVE;
+}
+
 NS_IMETHODIMP
 AudioChannelService::Observe(nsISupports* aSubject, const char* aTopic, const char16_t* aData)
 {
   if (!strcmp(aTopic, "xpcom-shutdown")) {
     mDisabled = true;
   }
 
   if (!strcmp(aTopic, "ipc:content-shutdown")) {
@@ -793,16 +818,17 @@ AudioChannelService::Observe(nsISupports
       if (mDefChannelChildID == childID) {
         SetDefaultVolumeControlChannelInternal(-1, false, childID);
         mDefChannelChildID = CONTENT_PROCESS_ID_UNKNOWN;
       }
     } else {
       NS_WARNING("ipc:content-shutdown message without childID property");
     }
   }
+
 #ifdef MOZ_WIDGET_GONK
   // To process the volume control on each audio channel according to
   // change of settings
   else if (!strcmp(aTopic, "mozsettings-changed")) {
     AutoJSAPI jsapi;
     jsapi.Init();
     JSContext* cx = jsapi.cx();
     RootedDictionary<SettingChangeNotification> setting(cx);
@@ -834,16 +860,36 @@ AudioChannelService::Observe(nsISupports
       // We didn't use MOZ_CRASH or MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE here
       // because any web content who has permission of mozSettings can set any
       // names then it can be easy to crash the B2G.
       NS_WARNING("unexpected audio channel for volume control");
     }
   }
 #endif
 
+  else if (!strcmp(aTopic, "inner-window-destroyed")) {
+    nsCOMPtr<nsISupportsPRUint64> wrapper = do_QueryInterface(aSubject);
+    NS_ENSURE_TRUE(wrapper, NS_ERROR_FAILURE);
+
+    uint64_t innerID;
+    nsresult rv = wrapper->GetData(&innerID);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+
+    mAgents.Enumerate(WindowDestroyedEnumerator, &innerID);
+
+#ifdef MOZ_WIDGET_GONK
+    bool active = AnyAudioChannelIsActive();
+    for (uint32_t i = 0; i < mSpeakerManager.Length(); i++) {
+      mSpeakerManager[i]->SetAudioChannelActive(active);
+    }
+#endif
+  }
+
   return NS_OK;
 }
 
 AudioChannelService::AudioChannelInternalType
 AudioChannelService::GetInternalType(AudioChannel aChannel,
                                      bool aElementHidden)
 {
   switch (aChannel) {
--- a/dom/audiochannel/AudioChannelService.h
+++ b/dom/audiochannel/AudioChannelService.h
@@ -216,16 +216,21 @@ protected:
                                 AudioChannelAgentData* aUnused,
                                 void *aPtr);
 
   static PLDHashOperator
   CountWindowEnumerator(AudioChannelAgent* aAgent,
                         AudioChannelAgentData* aUnused,
                         void *aPtr);
 
+  static PLDHashOperator
+  WindowDestroyedEnumerator(AudioChannelAgent* aAgent,
+                            nsAutoPtr<AudioChannelAgentData>& aData,
+                            void *aPtr);
+
   // This returns the number of agents from this aWindow.
   uint32_t CountWindow(nsIDOMWindow* aWindow);
 
   nsClassHashtable< nsPtrHashKey<AudioChannelAgent>, AudioChannelAgentData > mAgents;
 #ifdef MOZ_WIDGET_GONK
   nsTArray<SpeakerManagerService*>  mSpeakerManager;
 #endif
   nsTArray<uint64_t> mChannelCounters[AUDIO_CHANNEL_INT_LAST];
--- a/dom/base/Console.h
+++ b/dom/base/Console.h
@@ -2,24 +2,25 @@
 /* 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_Console_h
 #define mozilla_dom_Console_h
 
 #include "mozilla/dom/BindingDeclarations.h"
-#include "mozilla/dom/UnionConversions.h"
 #include "mozilla/ErrorResult.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsDataHashtable.h"
 #include "nsHashKeys.h"
 #include "nsIObserver.h"
 #include "nsITimer.h"
 #include "nsWrapperCache.h"
+#include "nsDOMNavigationTiming.h"
+#include "nsPIDOMWindow.h"
 
 class nsIConsoleAPIStorage;
 
 namespace mozilla {
 namespace dom {
 
 class ConsoleCallData;
 struct ConsoleStackEntry;
--- a/dom/base/ScriptSettings.cpp
+++ b/dom/base/ScriptSettings.cpp
@@ -126,17 +126,26 @@ nsIGlobalObject*
 GetEntryGlobal()
 {
   return ScriptSettingsStack::EntryGlobal();
 }
 
 nsIDocument*
 GetEntryDocument()
 {
-  nsCOMPtr<nsPIDOMWindow> entryWin = do_QueryInterface(GetEntryGlobal());
+  nsIGlobalObject* global = GetEntryGlobal();
+  nsCOMPtr<nsPIDOMWindow> entryWin = do_QueryInterface(global);
+
+  // If our entry global isn't a window, see if it's an addon scope associated
+  // with a window. If it is, the caller almost certainly wants that rather
+  // than null.
+  if (!entryWin && global) {
+    entryWin = xpc::AddonWindowOrNull(global->GetGlobalJSObject());
+  }
+
   return entryWin ? entryWin->GetExtantDoc() : nullptr;
 }
 
 nsIGlobalObject*
 GetIncumbentGlobal()
 {
   // We need the current JSContext in order to check the JS for
   // scripted frames that may have appeared since anyone last
--- a/dom/base/SubtleCrypto.h
+++ b/dom/base/SubtleCrypto.h
@@ -5,23 +5,23 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_SubtleCrypto_h
 #define mozilla_dom_SubtleCrypto_h
 
 #include "nsCycleCollectionParticipant.h"
 #include "nsWrapperCache.h"
 #include "nsPIDOMWindow.h"
-#include "mozilla/dom/UnionTypes.h"
 #include "mozilla/dom/CryptoKey.h"
 #include "js/TypeDecls.h"
 
 namespace mozilla {
 namespace dom {
 
+class ObjectOrString;
 class Promise;
 
 typedef ArrayBufferViewOrArrayBuffer CryptoOperationData;
 
 class SubtleCrypto MOZ_FINAL : public nsISupports,
                                public nsWrapperCache
 {
   ~SubtleCrypto() {}
--- a/dom/base/WindowNamedPropertiesHandler.cpp
+++ b/dom/base/WindowNamedPropertiesHandler.cpp
@@ -244,17 +244,16 @@ const NativePropertyHooks sWindowNamedPr
   { nullptr, nullptr },
   prototypes::id::_ID_Count,
   constructors::id::_ID_Count,
   nullptr
 } };
 
 static const DOMIfaceAndProtoJSClass WindowNamedPropertiesClass = {
   PROXY_CLASS_DEF("WindowProperties",
-                  DOM_INTERFACE_PROTO_SLOTS_BASE, /* extra slots */
                   JSCLASS_IS_DOMIFACEANDPROTOJSCLASS),
   eNamedPropertiesObject,
   sWindowNamedPropertiesNativePropertyHooks,
   "[object WindowProperties]",
   prototypes::id::_ID_Count,
   0,
   EventTargetBinding::GetProtoObject
 };
new file mode 100644
--- /dev/null
+++ b/dom/base/crashtests/476526.html
@@ -0,0 +1,10 @@
+<!DOCTYPE HTML>
+<html>
+<body>
+<iframe src="data:text/xml,
+  <html xmlns='http://www.w3.org/1999/xhtml'
+   onDOMAttrModified='window.frameElement.parentNode.removeChild(window.frameElement)'>
+  </html>"
+ onload="event.target.contentDocument.documentElement.setAttribute('x', 'y');"></iframe>
+</body>
+</html>
--- a/dom/base/crashtests/crashtests.list
+++ b/dom/base/crashtests/crashtests.list
@@ -13,16 +13,17 @@ load 371124-1.html
 load 371124-2.html
 load 372554-1.html
 load 375399-1.html
 load 404869-1.xul
 load 417852-1.html
 load 462947.html
 load 439206-1.html
 load 473284.xul
+load 476526.html
 load 499006-1.html
 load 499006-2.html
 load 502617.html
 load 504224.html
 load 603531.html
 load 601247.html
 load 609560-1.xhtml
 load 612018-1.html
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -86,17 +86,16 @@
 #include "nsIDOMCSSStyleRule.h"
 #include "nsIDOMXULCommandDispatcher.h"
 #include "nsIControllers.h"
 #ifdef MOZ_XUL
 #include "nsITreeSelection.h"
 #include "nsITreeContentView.h"
 #include "nsITreeView.h"
 #include "nsIXULTemplateBuilder.h"
-#include "nsITreeColumns.h"
 #endif
 #include "nsIDOMXPathNSResolver.h"
 
 #include "nsIEventListenerService.h"
 #include "nsIMessageManager.h"
 
 #include "mozilla/dom/TouchEvent.h"
 
@@ -260,21 +259,16 @@ static nsDOMClassInfoData sClassInfoData
 #ifdef MOZ_XUL
   NS_DEFINE_CHROME_XBL_CLASSINFO_DATA(XULTemplateBuilder, nsDOMGenericSH,
                                       DEFAULT_SCRIPTABLE_FLAGS)
 
   NS_DEFINE_CHROME_XBL_CLASSINFO_DATA(XULTreeBuilder, nsDOMGenericSH,
                                       DEFAULT_SCRIPTABLE_FLAGS)
 #endif
 
-#ifdef MOZ_XUL
-  NS_DEFINE_CHROME_XBL_CLASSINFO_DATA(TreeColumn, nsDOMGenericSH,
-                                      DEFAULT_SCRIPTABLE_FLAGS)
-#endif
-
   NS_DEFINE_CLASSINFO_DATA(CSSMozDocumentRule, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
   NS_DEFINE_CLASSINFO_DATA(CSSSupportsRule, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
   NS_DEFINE_CLASSINFO_DATA(XPathNSResolver, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
@@ -711,22 +705,16 @@ nsDOMClassInfo::Init()
 
   DOM_CLASSINFO_MAP_BEGIN(XULTreeBuilder, nsIXULTreeBuilder)
     DOM_CLASSINFO_MAP_ENTRY(nsIXULTreeBuilder)
     DOM_CLASSINFO_MAP_ENTRY(nsIXULTemplateBuilder)
     DOM_CLASSINFO_MAP_ENTRY(nsITreeView)
   DOM_CLASSINFO_MAP_END
 #endif
 
-#ifdef MOZ_XUL
-  DOM_CLASSINFO_MAP_BEGIN(TreeColumn, nsITreeColumn)
-    DOM_CLASSINFO_MAP_ENTRY(nsITreeColumn)
-  DOM_CLASSINFO_MAP_END
-#endif
-
   DOM_CLASSINFO_MAP_BEGIN(CSSMozDocumentRule, nsIDOMCSSMozDocumentRule)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMCSSMozDocumentRule)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(CSSSupportsRule, nsIDOMCSSSupportsRule)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMCSSSupportsRule)
   DOM_CLASSINFO_MAP_END
 
--- a/dom/base/nsDOMClassInfoClasses.h
+++ b/dom/base/nsDOMClassInfoClasses.h
@@ -24,20 +24,16 @@ DOMCI_CLASS(TreeSelection)
 DOMCI_CLASS(TreeContentView)
 #endif
 
 #ifdef MOZ_XUL
 DOMCI_CLASS(XULTemplateBuilder)
 DOMCI_CLASS(XULTreeBuilder)
 #endif
 
-#ifdef MOZ_XUL
-DOMCI_CLASS(TreeColumn)
-#endif
-
 DOMCI_CLASS(CSSMozDocumentRule)
 DOMCI_CLASS(CSSSupportsRule)
 
 // DOM Level 3 XPath objects
 DOMCI_CLASS(XPathNSResolver)
 
 DOMCI_CLASS(MozSmsMessage)
 DOMCI_CLASS(MozMmsMessage)
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -198,16 +198,17 @@
 #include "nsLocation.h"
 #include "nsHTMLDocument.h"
 #include "nsWrapperCacheInlines.h"
 #include "mozilla/DOMEventTargetHelper.h"
 #include "prrng.h"
 #include "nsSandboxFlags.h"
 #include "TimeChangeObserver.h"
 #include "mozilla/dom/AudioContext.h"
+#include "mozilla/dom/BlobBinding.h"
 #include "mozilla/dom/BrowserElementDictionariesBinding.h"
 #include "mozilla/dom/Console.h"
 #include "mozilla/dom/FunctionBinding.h"
 #include "mozilla/dom/HashChangeEvent.h"
 #include "mozilla/dom/MozSelfSupportBinding.h"
 #include "mozilla/dom/PopStateEvent.h"
 #include "mozilla/dom/PopupBlockedEvent.h"
 #include "mozilla/dom/WindowBinding.h"
@@ -690,17 +691,16 @@ protected:
 
   bool AppendIndexedPropertyNames(JSContext *cx, JSObject *proxy,
                                   JS::AutoIdVector &props) const;
 };
 
 const js::Class OuterWindowProxyClass =
     PROXY_CLASS_WITH_EXT(
         "Proxy",
-        0, /* additional slots */
         0, /* additional class flags */
         PROXY_MAKE_EXT(
             nullptr, /* outerObject */
             js::proxy_innerObject,
             nullptr, /* iteratorObject */
             false,   /* isWrappedNative */
             nsOuterWindowProxy::ObjectMoved
         ));
--- a/dom/base/nsGlobalWindow.h
+++ b/dom/base/nsGlobalWindow.h
@@ -33,17 +33,16 @@
 #include "nsIScriptObjectPrincipal.h"
 #include "nsITimer.h"
 #include "nsIDOMModalContentWindow.h"
 #include "mozilla/EventListenerManager.h"
 #include "nsIPrincipal.h"
 #include "nsSize.h"
 #include "mozFlushType.h"
 #include "prclist.h"
-#include "mozilla/dom/RequestBinding.h"
 #include "mozilla/dom/StorageEvent.h"
 #include "mozilla/dom/StorageEventBinding.h"
 #include "mozilla/dom/UnionTypes.h"
 #include "nsFrameMessageManager.h"
 #include "mozilla/LinkedList.h"
 #include "mozilla/TimeStamp.h"
 #include "nsWrapperCacheInlines.h"
 #include "nsIIdleObserver.h"
@@ -105,16 +104,18 @@ class Console;
 class External;
 class Function;
 class Gamepad;
 class MediaQueryList;
 class MozSelfSupport;
 class Navigator;
 class OwningExternalOrWindowProxy;
 class Promise;
+struct RequestInit;
+class RequestOrScalarValueString;
 class Selection;
 class SpeechSynthesis;
 class WakeLock;
 namespace indexedDB {
 class IDBFactory;
 } // namespace indexedDB
 } // namespace dom
 } // namespace mozilla
--- a/dom/base/nsWindowRoot.cpp
+++ b/dom/base/nsWindowRoot.cpp
@@ -1,44 +1,44 @@
 /* -*- 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 "mozilla/BasicEvents.h"
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/EventListenerManager.h"
+#include "mozilla/dom/WindowRootBinding.h"
 #include "nsCOMPtr.h"
 #include "nsWindowRoot.h"
 #include "nsPIDOMWindow.h"
 #include "nsPresContext.h"
 #include "nsLayoutCID.h"
 #include "nsContentCID.h"
 #include "nsString.h"
 #include "nsGlobalWindow.h"
 #include "nsFocusManager.h"
 #include "nsIContent.h"
 #include "nsIDOMHTMLInputElement.h"
 #include "nsIDOMHTMLTextAreaElement.h"
 #include "nsIControllers.h"
 #include "nsIController.h"
-
+#include "xpcpublic.h"
 #include "nsCycleCollectionParticipant.h"
 
 #ifdef MOZ_XUL
 #include "nsIDOMXULElement.h"
 #endif
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 nsWindowRoot::nsWindowRoot(nsPIDOMWindow* aWindow)
 {
   mWindow = aWindow;
-  SetIsNotDOMBinding();
 }
 
 nsWindowRoot::~nsWindowRoot()
 {
   if (mListenerManager) {
     mListenerManager->Disconnect();
   }
 }
@@ -288,16 +288,28 @@ nsWindowRoot::GetPopupNode()
 }
 
 void
 nsWindowRoot::SetPopupNode(nsIDOMNode* aNode)
 {
   mPopupNode = aNode;
 }
 
+nsIGlobalObject*
+nsWindowRoot::GetParentObject()
+{
+  return xpc::NativeGlobal(xpc::PrivilegedJunkScope());
+}
+
+JSObject*
+nsWindowRoot::WrapObject(JSContext* aCx)
+{
+  return mozilla::dom::WindowRootBinding::Wrap(aCx, this);
+}
+
 ///////////////////////////////////////////////////////////////////////////////////
 
 already_AddRefed<EventTarget>
 NS_NewWindowRoot(nsPIDOMWindow* aWindow)
 {
   nsCOMPtr<EventTarget> result = new nsWindowRoot(aWindow);
   return result.forget();
 }
--- a/dom/base/nsWindowRoot.h
+++ b/dom/base/nsWindowRoot.h
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsWindowRoot_h__
 #define nsWindowRoot_h__
 
 class nsPIDOMWindow;
 class nsIDOMEventListener;
 class nsIDOMEvent;
+class nsIGlobalObject;
 
 namespace mozilla {
 class EventChainPostVisitor;
 class EventChainPreVisitor;
 } // namespace mozilla
 
 #include "mozilla/Attributes.h"
 #include "mozilla/EventListenerManager.h"
@@ -56,20 +57,19 @@ public:
 
   virtual void SetParentTarget(mozilla::dom::EventTarget* aTarget) MOZ_OVERRIDE
   {
     mParent = aTarget;
   }
   virtual mozilla::dom::EventTarget* GetParentTarget() MOZ_OVERRIDE { return mParent; }
   virtual nsIDOMWindow* GetOwnerGlobal() MOZ_OVERRIDE;
 
-  virtual JSObject* WrapObject(JSContext* cx) MOZ_OVERRIDE
-  {
-    MOZ_CRASH("nsWindowRoot doesn't use DOM bindings!");
-  }
+  nsIGlobalObject* GetParentObject();
+
+  virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE;
 
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(nsWindowRoot,
                                                          nsIDOMEventTarget)
 
 protected:
   virtual ~nsWindowRoot();
 
   // Members
--- a/dom/base/nsWrapperCache.h
+++ b/dom/base/nsWrapperCache.h
@@ -101,17 +101,17 @@ public:
   {
     return GetWrapperJSObject();
   }
 
   void SetWrapper(JSObject* aWrapper)
   {
     MOZ_ASSERT(!PreservingWrapper(), "Clearing a preserved wrapper!");
     MOZ_ASSERT(aWrapper, "Use ClearWrapper!");
-    MOZ_ASSERT(js::HasObjectMovedOpIfRequired(aWrapper),
+    MOZ_ASSERT(js::HasObjectMovedOp(aWrapper),
                "Object has not provided the hook to update the wrapper if it is moved");
 
     SetWrapperJSObject(aWrapper);
   }
 
   /**
    * Clear the wrapper. This should be called from the finalizer for the
    * wrapper.
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -1663,25 +1663,25 @@ DictionaryBase::AppendJSONToString(const
 
 // Dynamically ensure that two objects don't end up with the same reserved slot.
 class MOZ_STACK_CLASS AutoCloneDOMObjectSlotGuard
 {
 public:
   AutoCloneDOMObjectSlotGuard(JSContext* aCx, JSObject* aOld, JSObject* aNew)
     : mOldReflector(aCx, aOld), mNewReflector(aCx, aNew)
   {
-    MOZ_ASSERT(js::GetReservedSlot(aOld, DOM_OBJECT_SLOT) ==
-                 js::GetReservedSlot(aNew, DOM_OBJECT_SLOT));
+    MOZ_ASSERT(js::GetReservedOrProxyPrivateSlot(aOld, DOM_OBJECT_SLOT) ==
+               js::GetReservedOrProxyPrivateSlot(aNew, DOM_OBJECT_SLOT));
   }
 
   ~AutoCloneDOMObjectSlotGuard()
   {
-    if (js::GetReservedSlot(mOldReflector, DOM_OBJECT_SLOT).toPrivate()) {
-      js::SetReservedSlot(mNewReflector, DOM_OBJECT_SLOT,
-                          JS::PrivateValue(nullptr));
+    if (js::GetReservedOrProxyPrivateSlot(mOldReflector, DOM_OBJECT_SLOT).toPrivate()) {
+      js::SetReservedOrProxyPrivateSlot(mNewReflector, DOM_OBJECT_SLOT,
+                                        JS::PrivateValue(nullptr));
     }
   }
 
 private:
   JS::Rooted<JSObject*> mOldReflector;
   JS::Rooted<JSObject*> mNewReflector;
 };
 
@@ -1737,18 +1737,18 @@ ReparentWrapper(JSContext* aCx, JS::Hand
     return NS_ERROR_FAILURE;
   }
 
   JS::Rooted<JSObject*> newobj(aCx, JS_CloneObject(aCx, aObj, proto, newParent));
   if (!newobj) {
     return NS_ERROR_FAILURE;
   }
 
-  js::SetReservedSlot(newobj, DOM_OBJECT_SLOT,
-                      js::GetReservedSlot(aObj, DOM_OBJECT_SLOT));
+  js::SetReservedOrProxyPrivateSlot(newobj, DOM_OBJECT_SLOT,
+                                    js::GetReservedOrProxyPrivateSlot(aObj, DOM_OBJECT_SLOT));
 
   // At this point, both |aObj| and |newobj| point to the same native
   // which is bad, because one of them will end up being finalized with a
   // native it does not own. |cloneGuard| ensures that if we exit before
   // clearing |aObj|'s reserved slot the reserved slot of |newobj| will be
   // set to null. |aObj| will go away soon, because we swap it with
   // another object during the transplant and let that object die.
   JS::Rooted<JSObject*> propertyHolder(aCx);
@@ -1777,17 +1777,17 @@ ReparentWrapper(JSContext* aCx, JS::Hand
     }
 
     // We've set up |newobj|, so we make it own the native by nulling
     // out the reserved slot of |obj|.
     //
     // NB: It's important to do this _after_ copying the properties to
     // propertyHolder. Otherwise, an object with |foo.x === foo| will
     // crash when JS_CopyPropertiesFrom tries to call wrap() on foo.x.
-    js::SetReservedSlot(aObj, DOM_OBJECT_SLOT, JS::PrivateValue(nullptr));
+    js::SetReservedOrProxyPrivateSlot(aObj, DOM_OBJECT_SLOT, JS::PrivateValue(nullptr));
   }
 
   aObj = xpc::TransplantObject(aCx, aObj, newobj);
   if (!aObj) {
     MOZ_CRASH();
   }
 
   nsWrapperCache* cache = nullptr;
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -161,27 +161,27 @@ IsDOMIfaceAndProtoClass(const JSClass* c
 }
 
 inline bool
 IsDOMIfaceAndProtoClass(const js::Class* clasp)
 {
   return IsDOMIfaceAndProtoClass(Jsvalify(clasp));
 }
 
-static_assert(DOM_OBJECT_SLOT == js::PROXY_PRIVATE_SLOT,
-              "js::PROXY_PRIVATE_SLOT doesn't match DOM_OBJECT_SLOT.  "
+static_assert(DOM_OBJECT_SLOT == 0,
+              "DOM_OBJECT_SLOT doesn't match the proxy private slot.  "
               "Expect bad things");
 template <class T>
 inline T*
 UnwrapDOMObject(JSObject* obj)
 {
   MOZ_ASSERT(IsDOMClass(js::GetObjectClass(obj)),
              "Don't pass non-DOM objects to this function");
 
-  JS::Value val = js::GetReservedSlot(obj, DOM_OBJECT_SLOT);
+  JS::Value val = js::GetReservedOrProxyPrivateSlot(obj, DOM_OBJECT_SLOT);
   return static_cast<T*>(val.toPrivate());
 }
 
 inline const DOMJSClass*
 GetDOMClass(const js::Class* clasp)
 {
   return IsDOMClass(clasp) ? DOMJSClass::FromJSClass(clasp) : nullptr;
 }
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -1,8 +1,10 @@
+# -*- Mode:Python; tab-width:8; indent-tabs-mode:nil; c-basic-offset:8 -*- */
+# vim: set ts=8 sts=4 et sw=4 tw=80: */
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 # DOM Bindings Configuration.
 #
 # The WebIDL interfaces are defined in dom/webidl. For each such interface, there
 # is a corresponding entry in the configuration table below. The configuration
@@ -1207,16 +1209,21 @@ DOMInterfaces = {
 'TimeRanges': {
     'wrapperCache': False
 },
 
 'TouchList': {
     'headerFile': 'mozilla/dom/TouchEvent.h',
 },
 
+'TreeColumn': {
+    'nativeType': 'nsTreeColumn',
+    'headerFile': 'nsTreeColumns.h',
+},
+
 'TreeColumns': {
     'nativeType': 'nsTreeColumns',
 },
 
 'TreeWalker': {
     'wrapperCache': False,
 },
 
@@ -1465,16 +1472,20 @@ DOMInterfaces = {
     'concrete': False
 },
 {
     # We need a worker descriptor for WindowProxy because EventTarget exists in
     # workers.  But it's an external interface, so it'll just map to JSObject*.
     'workers': True
 }],
 
+'WindowRoot': {
+    'nativeType': 'nsWindowRoot'
+},
+
 'Worker': {
     'headerFile': 'mozilla/dom/WorkerPrivate.h',
     'nativeType': 'mozilla::dom::workers::WorkerPrivate',
     'implicitJSContext': [
         'terminate',
     ],
 },
 
@@ -1815,18 +1826,16 @@ addExternalIface('MozFrameLoader', nativ
 addExternalIface('MozFrameRequestCallback', nativeType='nsIFrameRequestCallback',
                  notflattened=True)
 addExternalIface('MozMmsMessage')
 addExternalIface('MozObserver', nativeType='nsIObserver', notflattened=True)
 addExternalIface('MozRDFCompositeDataSource', nativeType='nsIRDFCompositeDataSource',
                  notflattened=True)
 addExternalIface('MozRDFResource', nativeType='nsIRDFResource', notflattened=True)
 addExternalIface('MozSmsMessage')
-addExternalIface('MozTreeColumn', nativeType='nsITreeColumn',
-                 headerFile='nsITreeColumns.h')
 addExternalIface('MozTreeView', nativeType='nsITreeView',
                   headerFile='nsITreeView.h')
 addExternalIface('MozWakeLockListener', headerFile='nsIDOMWakeLockListener.h')
 addExternalIface('MozXULTemplateBuilder', nativeType='nsIXULTemplateBuilder')
 addExternalIface('nsIBrowserDOMWindow', nativeType='nsIBrowserDOMWindow',
                  notflattened=True)
 addExternalIface('nsIControllers', nativeType='nsIControllers')
 addExternalIface('nsIDOMCrypto', nativeType='nsIDOMCrypto',
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -5,18 +5,18 @@
 # Common codegen classes.
 
 import os
 import re
 import string
 import math
 import textwrap
 
-from WebIDL import BuiltinTypes, IDLBuiltinType, IDLNullValue, IDLSequenceType, IDLType, IDLAttribute, IDLUndefinedValue, IDLEmptySequenceValue
-from Configuration import NoSuchDescriptorError, getTypesFromDescriptor, getTypesFromDictionary, getTypesFromCallback, Descriptor
+from WebIDL import BuiltinTypes, IDLBuiltinType, IDLNullValue, IDLSequenceType, IDLType, IDLAttribute, IDLUndefinedValue, IDLEmptySequenceValue, IDLDictionary
+from Configuration import NoSuchDescriptorError, getTypesFromDescriptor, getTypesFromDictionary, getTypesFromCallback, getAllTypes, Descriptor
 
 AUTOGENERATED_WARNING_COMMENT = \
     "/* THIS FILE IS AUTOGENERATED - DO NOT EDIT */\n\n"
 ADDPROPERTY_HOOK_NAME = '_addProperty'
 FINALIZE_HOOK_NAME = '_finalize'
 OBJECT_MOVED_HOOK_NAME = '_objectMoved'
 CONSTRUCT_HOOK_NAME = '_constructor'
 LEGACYCALLER_HOOK_NAME = '_legacycaller'
@@ -492,17 +492,16 @@ class CGDOMProxyJSClass(CGThing):
         # HTMLAllCollection.  So just hardcode it here.
         if self.descriptor.interface.identifier.name == "HTMLAllCollection":
             flags.append("JSCLASS_EMULATES_UNDEFINED")
         objectMovedHook = OBJECT_MOVED_HOOK_NAME if self.descriptor.wrapperCache else 'nullptr'
         return fill(
             """
             static const DOMJSClass Class = {
               PROXY_CLASS_WITH_EXT("${name}",
-                                   0, /* extra slots */
                                    ${flags},
                                    PROXY_MAKE_EXT(nullptr, /* outerObject */
                                                   nullptr, /* innerObject */
                                                   nullptr, /* iteratorObject */
                                                   false,   /* isWrappedNative */
                                                   ${objectMoved})),
               $*{descriptor}
             };
@@ -1004,36 +1003,16 @@ def getRelevantProviders(descriptor, con
         return [descriptor]
     # Do both the non-worker and worker versions
     return [
         config.getDescriptorProvider(False),
         config.getDescriptorProvider(True)
     ]
 
 
-def getAllTypes(descriptors, dictionaries, callbacks):
-    """
-    Generate all the types we're dealing with.  For each type, a tuple
-    containing type, descriptor, dictionary is yielded.  The
-    descriptor and dictionary can be None if the type does not come
-    from a descriptor or dictionary; they will never both be non-None.
-    """
-    for d in descriptors:
-        if d.interface.isExternal():
-            continue
-        for t in getTypesFromDescriptor(d):
-            yield (t, d, None)
-    for dictionary in dictionaries:
-        for t in getTypesFromDictionary(dictionary):
-            yield (t, None, dictionary)
-    for callback in callbacks:
-        for t in getTypesFromCallback(callback):
-            yield (t, None, None)
-
-
 class CGHeaders(CGWrapper):
     """
     Generates the appropriate include statements.
     """
     def __init__(self, descriptors, dictionaries, callbacks,
                  callbackDescriptors,
                  declareIncludes, defineIncludes, prefix, child,
                  config=None, jsImplementedDescriptors=[]):
@@ -1101,22 +1080,21 @@ class CGHeaders(CGWrapper):
             else:
                 headerSet = bindingHeaders
             if t.nullable():
                 # Need to make sure that Nullable as a dictionary
                 # member works.
                 headerSet.add("mozilla/dom/Nullable.h")
             unrolled = t.unroll()
             if unrolled.isUnion():
-                # UnionConversions.h includes UnionTypes.h
+                if len(config.filenamesPerUnion[unrolled.name]) > 1:
+                    headerSet.add("mozilla/dom/UnionTypes.h")
+                else:
+                    headerSet.add(self.getDeclarationFilename(unrolled))
                 bindingHeaders.add("mozilla/dom/UnionConversions.h")
-                if dictionary:
-                    # Our dictionary definition is in the header and
-                    # needs the union type.
-                    declareIncludes.add("mozilla/dom/UnionTypes.h")
             elif unrolled.isDate():
                 if dictionary or jsImplementedDescriptors:
                     declareIncludes.add("mozilla/dom/Date.h")
                 else:
                     bindingHeaders.add("mozilla/dom/Date.h")
             elif unrolled.isInterface():
                 if unrolled.isSpiderMonkeyInterface():
                     bindingHeaders.add("jsfriendapi.h")
@@ -1252,53 +1230,52 @@ class CGHeaders(CGWrapper):
 
 
 def SortedDictValues(d):
     """
     Returns a list of values from the dict sorted by key.
     """
     return [v for k, v in sorted(d.items())]
 
-
-def UnionTypes(descriptors, dictionaries, callbacks, config):
-    """
+def UnionsForFile(config, webIDLFile):
+    """
+    Returns a list of tuples each containing two elements (type and descriptor)
+    for all union types that are only used in webIDLFile. If webIDLFile is None
+    this will return the list of tuples for union types that are used in more
+    than one WebIDL file.
+    """
+    return config.unionsPerFilename.get(webIDLFile, [])
+
+def UnionTypes(unionTypes, config):
+    """
+    The unionTypes argument should be a list of tuples, each containing two
+    elements: a union type and a descriptor. This is typically the list
+    generated by UnionsForFile.
+
     Returns a tuple containing a set of header filenames to include in
-    UnionTypes.h, a set of header filenames to include in UnionTypes.cpp, a set
+    the header for the types in unionTypes, a set of header filenames to
+    include in the implementation file for the types in unionTypes, a set
     of tuples containing a type declaration and a boolean if the type is a
-    struct for member types of the unions and a CGList containing CGUnionStructs
-    for every union.
-    """
-
-    # Now find all the things we'll need as arguments and return values because
-    # we need to wrap or unwrap them.
+    struct for member types of the union, a list of traverse methods,
+    unlink methods and a list of union types. These last three lists only
+    contain unique union types.
+    """
+
     headers = set()
-    implheaders = set(["UnionTypes.h"])
+    implheaders = set()
     declarations = set()
     unionStructs = dict()
-    owningUnionStructs = dict()
     traverseMethods = dict()
     unlinkMethods = dict()
 
-    for t, descriptor, dictionary in getAllTypes(descriptors, dictionaries, callbacks):
-        # Add info for the given type.  descriptor and dictionary, if present, are
-        # used to figure out what to do with interface types.
-        assert not descriptor or not dictionary
-
-        t = t.unroll()
-        while t.isMozMap():
-            t = t.inner.unroll()
-        if not t.isUnion():
-            continue
+    for (t, descriptor) in unionTypes:
         name = str(t)
         if name not in unionStructs:
             providers = getRelevantProviders(descriptor, config)
-            # FIXME: Unions are broken in workers.  See bug 809899.
-            unionStructs[name] = CGUnionStruct(t, providers[0])
-            owningUnionStructs[name] = CGUnionStruct(t, providers[0],
-                                                     ownsMembers=True)
+            unionStructs[name] = t
 
             def addHeadersForType(f):
                 if f.nullable():
                     headers.add("mozilla/dom/Nullable.h")
                 isSequence = f.isSequence()
                 f = f.unroll()
                 if f.isInterface():
                     if f.isSpiderMonkeyInterface():
@@ -1339,55 +1316,51 @@ def UnionTypes(descriptors, dictionaries
                     # the right header to be able to Release() in our inlined
                     # code.
                     headers.add(CGHeaders.getDeclarationFilename(f))
                 elif f.isMozMap():
                     headers.add("mozilla/dom/MozMap.h")
                     # And add headers for the type we're parametrized over
                     addHeadersForType(f.inner)
 
+            if len(config.filenamesPerUnion[t.name]) > 1:
+                implheaders.add("mozilla/dom/UnionTypes.h")
+            else:
+                implheaders.add(CGHeaders.getDeclarationFilename(t))
             for f in t.flatMemberTypes:
                 assert not f.nullable()
                 addHeadersForType(f)
 
             if idlTypeNeedsCycleCollection(t):
                 declarations.add(("mozilla::dom::%s" % CGUnionStruct.unionTypeName(t, True), False))
                 traverseMethods[name] = CGCycleCollectionTraverseForOwningUnionMethod(t)
                 unlinkMethods[name] = CGCycleCollectionUnlinkForOwningUnionMethod(t)
 
     # The order of items in CGList is important.
     # Since the union structs friend the unlinkMethods, the forward-declaration
     # for these methods should come before the class declaration. Otherwise
     # some compilers treat the friend declaration as a forward-declaration in
     # the class scope.
     return (headers, implheaders, declarations,
-            CGList(SortedDictValues(traverseMethods) +
-                   SortedDictValues(unlinkMethods) +
-                   SortedDictValues(unionStructs) +
-                   SortedDictValues(owningUnionStructs),
-                   "\n"))
-
-
-def UnionConversions(descriptors, dictionaries, callbacks, config):
-    """
-    Returns a CGThing to declare all union argument conversion helper structs.
-    """
-    # Now find all the things we'll need as arguments because we
-    # need to unwrap them.
+            SortedDictValues(traverseMethods), SortedDictValues(unlinkMethods),
+            SortedDictValues(unionStructs))
+
+def UnionConversions(unionTypes, config):
+    """
+    The unionTypes argument should be a list of tuples, each containing two
+    elements: a union type and a descriptor. This is typically the list
+    generated by UnionsForFile.
+
+    Returns a tuple containing a list of headers and a CGThing to declare all
+    union argument conversion helper structs.
+    """
     headers = set()
     unionConversions = dict()
 
-    for t, descriptor, dictionary in getAllTypes(descriptors, dictionaries, callbacks):
-        # Add info for the given type.  descriptor and dictionary, if passed, are
-        # used to figure out what to do with interface types.
-        assert not descriptor or not dictionary
-
-        t = t.unroll()
-        if not t.isUnion():
-            continue
+    for (t, descriptor) in unionTypes:
         name = str(t)
         if name not in unionConversions:
             providers = getRelevantProviders(descriptor, config)
             unionConversions[name] = CGUnionConversionStruct(t, providers[0])
             def addHeadersForType(f, providers):
                 f = f.unroll()
                 if f.isInterface():
                     if f.isSpiderMonkeyInterface():
@@ -1414,16 +1387,19 @@ def UnionConversions(descriptors, dictio
                     headers.add(CGHeaders.getDeclarationFilename(f.inner))
                 elif f.isPrimitive():
                     headers.add("mozilla/dom/PrimitiveConversions.h")
                 elif f.isMozMap():
                     headers.add("mozilla/dom/MozMap.h")
                     # And the internal type of the MozMap
                     addHeadersForType(f.inner, providers)
 
+            if len(config.filenamesPerUnion[t.name]) == 1:
+                headers.add(CGHeaders.getDeclarationFilename(t))
+
             for f in t.flatMemberTypes:
                 addHeadersForType(f, providers)
 
     return (headers,
             CGWrapper(CGList(SortedDictValues(unionConversions), "\n"),
                       post="\n\n"))
 
 
@@ -3460,18 +3436,16 @@ class CGUpdateMemberSlotsMethod(CGAbstra
     def definition_body(self):
         body = ("JS::Rooted<JS::Value> temp(aCx);\n"
                 "JSJitGetterCallArgs args(&temp);\n")
         for m in self.descriptor.interface.members:
             if m.isAttr() and m.getExtendedAttribute("StoreInSlot"):
                 body += fill(
                     """
 
-                    static_assert(${slot} < js::shadow::Object::MAX_FIXED_SLOTS,
-                                  "Not enough fixed slots to fit '${interface}.${member}'");
                     if (!get_${member}(aCx, aWrapper, aObject, args)) {
                       return false;
                     }
                     // Getter handled setting our reserved slots
                     """,
                     slot=memberReservedSlot(m),
                     interface=self.descriptor.interface.identifier.name,
                     member=m.identifier.name)
@@ -3591,16 +3565,19 @@ class CGCycleCollectionTraverseForOwning
     def __init__(self, type):
         self.type = type
         args = [Argument("nsCycleCollectionTraversalCallback&", "aCallback"),
                 Argument("%s&" % CGUnionStruct.unionTypeName(type, True), "aUnion"),
                 Argument("const char*", "aName"),
                 Argument("uint32_t", "aFlags", "0")]
         CGAbstractMethod.__init__(self, None, "ImplCycleCollectionTraverse", "void", args)
 
+    def deps(self):
+        return self.type.getDeps()
+
     def definition_body(self):
         memberNames = [getUnionMemberName(t)
                        for t in self.type.flatMemberTypes
                        if idlTypeNeedsCycleCollection(t)]
         assert memberNames
 
         conditionTemplate = 'aUnion.Is%s()'
         functionCallTemplate = 'ImplCycleCollectionTraverse(aCallback, aUnion.GetAs%s(), "m%s", aFlags);\n'
@@ -3612,19 +3589,23 @@ class CGCycleCollectionTraverseForOwning
         return CGElseChain(ifStaments).define()
 
 
 class CGCycleCollectionUnlinkForOwningUnionMethod(CGAbstractMethod):
     """
     ImplCycleCollectionUnlink for owning union type.
     """
     def __init__(self, type):
+        self.type = type
         args = [Argument("%s&" % CGUnionStruct.unionTypeName(type, True), "aUnion")]
         CGAbstractMethod.__init__(self, None, "ImplCycleCollectionUnlink", "void", args)
 
+    def deps(self):
+        return self.type.getDeps()
+
     def definition_body(self):
         return "aUnion.Uninit();\n"
 
 
 builtinNames = {
     IDLType.Tags.bool: 'bool',
     IDLType.Tags.int8: 'int8_t',
     IDLType.Tags.int16: 'int16_t',
@@ -3902,17 +3883,18 @@ def getJSToNativeConversionInfo(type, de
                                 treatNullAs="Default",
                                 isEnforceRange=False,
                                 isClamp=False,
                                 isNullOrUndefined=False,
                                 exceptionCode=None,
                                 lenientFloatCode=None,
                                 allowTreatNonCallableAsNull=False,
                                 isCallbackReturnValue=False,
-                                sourceDescription="value"):
+                                sourceDescription="value",
+                                nestingLevel=""):
     """
     Get a template for converting a JS value to a native object based on the
     given type and descriptor.  If failureCode is given, then we're actually
     testing whether we can convert the argument to the desired type.  That
     means that failures to convert due to the JS value being the wrong type of
     value need to use failureCode instead of throwing exceptions.  Failures to
     convert that are due to JS exceptions (from toString or valueOf methods) or
     out of memory conditions need to throw exceptions no matter what
@@ -4105,16 +4087,19 @@ def getJSToNativeConversionInfo(type, de
 
         setToNullCode = "${declName} = nullptr;\n"
         template = wrapObjectTemplate(templateBody, type, setToNullCode,
                                       failureCode)
         return JSToNativeConversionInfo(template, declType=declType,
                                         dealWithOptional=isOptional,
                                         declArgs=declArgs)
 
+    def incrementNestingLevel():
+        return 1 if nestingLevel is "" else ++nestingLevel
+
     assert not (isEnforceRange and isClamp)  # These are mutually exclusive
 
     if type.isArray():
         raise TypeError("Can't handle array arguments yet")
 
     if type.isSequence():
         assert not isEnforceRange and not isClamp
 
@@ -4152,75 +4137,77 @@ def getJSToNativeConversionInfo(type, de
             sequenceClass = "binding_detail::AutoSequence"
 
         # XXXbz we can't include the index in the sourceDescription, because
         # we don't really have a way to pass one in dynamically at runtime...
         elementInfo = getJSToNativeConversionInfo(
             elementType, descriptorProvider, isMember="Sequence",
             exceptionCode=exceptionCode, lenientFloatCode=lenientFloatCode,
             isCallbackReturnValue=isCallbackReturnValue,
-            sourceDescription="element of %s" % sourceDescription)
+            sourceDescription="element of %s" % sourceDescription,
+            nestingLevel=incrementNestingLevel())
         if elementInfo.dealWithOptional:
             raise TypeError("Shouldn't have optional things in sequences")
         if elementInfo.holderType is not None:
             raise TypeError("Shouldn't need holders for sequences")
 
         typeName = CGTemplatedType(sequenceClass, elementInfo.declType)
         sequenceType = typeName.define()
         if nullable:
             typeName = CGTemplatedType("Nullable", typeName)
             arrayRef = "${declName}.SetValue()"
         else:
             arrayRef = "${declName}"
 
         elementConversion = string.Template(elementInfo.template).substitute({
-                "val": "temp",
-                "declName": "slot",
+                "val": "temp" + str(nestingLevel),
+                "declName": "slot" + str(nestingLevel),
                 # We only need holderName here to handle isExternal()
                 # interfaces, which use an internal holder for the
                 # conversion even when forceOwningType ends up true.
-                "holderName": "tempHolder",
+                "holderName": "tempHolder" + str(nestingLevel),
                 "passedToJSImpl": "${passedToJSImpl}"
             })
 
         # NOTE: Keep this in sync with variadic conversions as needed
         templateBody = fill(
             """
-            JS::ForOfIterator iter(cx);
-            if (!iter.init($${val}, JS::ForOfIterator::AllowNonIterable)) {
+            JS::ForOfIterator iter${nestingLevel}(cx);
+            if (!iter${nestingLevel}.init($${val}, JS::ForOfIterator::AllowNonIterable)) {
               $*{exceptionCode}
             }
-            if (!iter.valueIsIterable()) {
+            if (!iter${nestingLevel}.valueIsIterable()) {
               $*{notSequence}
             }
-            ${sequenceType} &arr = ${arrayRef};
-            JS::Rooted<JS::Value> temp(cx);
+            ${sequenceType} &arr${nestingLevel} = ${arrayRef};
+            JS::Rooted<JS::Value> temp${nestingLevel}(cx);
             while (true) {
-              bool done;
-              if (!iter.next(&temp, &done)) {
+              bool done${nestingLevel};
+              if (!iter${nestingLevel}.next(&temp${nestingLevel}, &done${nestingLevel})) {
                 $*{exceptionCode}
               }
-              if (done) {
+              if (done${nestingLevel}) {
                 break;
               }
-              ${elementType}* slotPtr = arr.AppendElement();
-              if (!slotPtr) {
+              ${elementType}* slotPtr${nestingLevel} = arr${nestingLevel}.AppendElement();
+              if (!slotPtr${nestingLevel}) {
                 JS_ReportOutOfMemory(cx);
                 $*{exceptionCode}
               }
-              ${elementType}& slot = *slotPtr;
+              ${elementType}& slot${nestingLevel} = *slotPtr${nestingLevel};
               $*{elementConversion}
             }
             """,
             exceptionCode=exceptionCode,
             notSequence=notSequence,
             sequenceType=sequenceType,
             arrayRef=arrayRef,
             elementType=elementInfo.declType.define(),
-            elementConversion=elementConversion)
+            elementConversion=elementConversion,
+            nestingLevel=str(nestingLevel))
 
         templateBody = wrapObjectTemplate(templateBody, type,
                                           "${declName}.SetNull();\n", notSequence)
         if isinstance(defaultValue, IDLEmptySequenceValue):
             if type.nullable():
                 codeToSetEmpty = "${declName}.SetValue();\n"
             else:
                 codeToSetEmpty = "/* Array is already empty; nothing to do */\n"
@@ -4257,17 +4244,18 @@ def getJSToNativeConversionInfo(type, de
             valueType = type.inner.inner
         else:
             valueType = type.inner
 
         valueInfo = getJSToNativeConversionInfo(
             valueType, descriptorProvider, isMember="MozMap",
             exceptionCode=exceptionCode, lenientFloatCode=lenientFloatCode,
             isCallbackReturnValue=isCallbackReturnValue,
-            sourceDescription="value in %s" % sourceDescription)
+            sourceDescription="value in %s" % sourceDescription,
+            nestingLevel=incrementNestingLevel())
         if valueInfo.dealWithOptional:
             raise TypeError("Shouldn't have optional things in MozMap")
         if valueInfo.holderType is not None:
             raise TypeError("Shouldn't need holders for MozMap")
 
         typeName = CGTemplatedType("MozMap", valueInfo.declType)
         mozMapType = typeName.define()
         if nullable:
@@ -8680,16 +8668,19 @@ class CGUnionStruct(CGThing):
         self.struct = self.getStruct()
 
     def declare(self):
         return self.struct.declare()
 
     def define(self):
         return self.struct.define()
 
+    def deps(self):
+        return self.type.getDeps()
+
     def getStruct(self):
 
         members = [ClassMember("mType", "Type", body="eUninitialized"),
                    ClassMember("mValue", "Value")]
         ctor = ClassConstructor([], bodyInHeader=True, visibility="public",
                                 explicit=True)
 
         methods = []
@@ -9037,17 +9028,19 @@ class CGUnionConversionStruct(CGThing):
 
         return CGClass(structName + "Argument",
                        members=members,
                        constructors=[ctor],
                        methods=methods,
                        disallowCopyConstruction=True).declare()
 
     def define(self):
-        return "\n"
+        return ""
+    def deps(self):
+        return set()
 
 
 class ClassItem:
     """ Use with CGClass """
     def __init__(self, name, visibility):
         self.name = name
         self.visibility = visibility
 
@@ -11848,33 +11841,16 @@ class CGDictionary(CGThing):
         return ("'%s' member of %s" %
                 (member.identifier.name, self.dictionary.identifier.name))
 
     @staticmethod
     def makeIdName(name):
         return IDLToCIdentifier(name) + "_id"
 
     @staticmethod
-    def getDictionaryDependenciesFromType(type):
-        if type.isDictionary():
-            return set([type.unroll().inner])
-        if type.isSequence() or type.isArray():
-            return CGDictionary.getDictionaryDependenciesFromType(type.unroll())
-        return set()
-
-    @staticmethod
-    def getDictionaryDependencies(dictionary):
-        deps = set()
-        if dictionary.parent:
-            deps.add(dictionary.parent)
-        for member in dictionary.members:
-            deps |= CGDictionary.getDictionaryDependenciesFromType(member.type)
-        return deps
-
-    @staticmethod
     def isDictionaryCopyConstructible(dictionary):
         if (dictionary.parent and
             not CGDictionary.isDictionaryCopyConstructible(dictionary.parent)):
             return False
         return all(isTypeCopyConstructible(m.type) for m in dictionary.members)
 
 
 class CGRegisterWorkerBindings(CGAbstractMethod):
@@ -11914,16 +11890,72 @@ class CGRegisterWorkerBindings(CGAbstrac
                     + condition)
             conditions.append(condition)
         lines = [CGIfWrapper(CGGeneric("return false;\n"), condition) for
                  condition in conditions]
         lines.append(CGGeneric("return true;\n"))
         return CGList(lines, "\n").define()
 
 
+class CGResolveSystemBinding(CGAbstractMethod):
+    def __init__(self, config):
+        CGAbstractMethod.__init__(self, None, 'ResolveSystemBinding', 'bool',
+                                  [Argument('JSContext*', 'aCx'),
+                                   Argument('JS::Handle<JSObject*>', 'aObj'),
+                                   Argument('JS::Handle<jsid>', 'aId'),
+                                   Argument('JS::MutableHandle<JSObject*>',
+                                            'aObjp')])
+        self.config = config
+
+    def definition_body(self):
+        descriptors = self.config.getDescriptors(hasInterfaceObject=True,
+                                                 isExposedInSystemGlobals=True,
+                                                 register=True,
+                                                 skipGen=False)
+
+        def descNameToId(name):
+            return "s%s_id" % name
+        jsidNames = [descNameToId(desc.name) for desc in descriptors]
+        jsidDecls = CGList(CGGeneric("static jsid %s;\n" % name)
+                           for name in jsidNames)
+
+        jsidInits = CGList(
+            (CGIfWrapper(
+                CGGeneric("return false;\n"),
+                '!InternJSString(aCx, %s, "%s")' %
+                (descNameToId(desc.name), desc.interface.identifier.name))
+             for desc in descriptors),
+            "\n")
+        jsidInits.append(CGGeneric("idsInited = true;\n"))
+        jsidInits = CGIfWrapper(jsidInits, "!idsInited")
+        jsidInits = CGList([CGGeneric("static bool idsInited = false;\n"),
+                            jsidInits])
+
+        definitions = CGList([], "\n")
+        for desc in descriptors:
+            bindingNS = toBindingNamespace(desc.name)
+            defineCode = "!%s::GetConstructorObject(aCx, aObj)" % bindingNS
+            defineCode = CGIfWrapper(CGGeneric("return false;\n"), defineCode)
+            defineCode = CGList([defineCode,
+                                 CGGeneric("aObjp.set(aObj);\n")])
+
+            condition = "JSID_IS_VOID(aId) || aId == %s" % descNameToId(desc.name)
+            if desc.isExposedConditionally():
+                condition = "(%s) && %s::ConstructorEnabled(aCx, aObj)" % (condition, bindingNS)
+
+            definitions.append(CGIfWrapper(defineCode, condition))
+
+        return CGList([CGGeneric("MOZ_ASSERT(NS_IsMainThread());\n"),
+                       jsidDecls,
+                       jsidInits,
+                       definitions,
+                       CGGeneric("return true;\n")],
+                      "\n").define()
+
+
 class CGRegisterProtos(CGAbstractMethod):
     def __init__(self, config):
         CGAbstractMethod.__init__(self, None, 'Register', 'void',
                                   [Argument('nsScriptNameSpaceManager*', 'aNameSpaceManager')])
         self.config = config
 
     def _defineMacro(self):
         return dedent("""
@@ -12062,19 +12094,22 @@ class ForwardDeclarationBuilder:
 
     def build(self):
         return self._build(atTopLevel=True)
 
 
 class CGForwardDeclarations(CGWrapper):
     """
     Code generate the forward declarations for a header file.
+    additionalDeclarations is a list of tuples containing a classname and a
+    boolean. If the boolean is true we will declare a struct, otherwise we'll
+    declare a class.
     """
     def __init__(self, config, descriptors, mainCallbacks, workerCallbacks,
-                 dictionaries, callbackInterfaces):
+                 dictionaries, callbackInterfaces, additionalDeclarations=[]):
         builder = ForwardDeclarationBuilder()
 
         def forwardDeclareForType(t, workerness='both'):
             t = t.unroll()
             if t.isGeckoInterface():
                 name = t.inner.identifier.name
                 # Find and add the non-worker implementation, if any.
                 if workerness != 'workeronly':
@@ -12136,16 +12171,19 @@ class CGForwardDeclarations(CGWrapper):
                 forwardDeclareForType(t)
 
         for d in dictionaries:
             if len(d.members) > 0:
                 builder.addInMozillaDom(d.identifier.name + "Atoms", isStruct=True)
             for t in getTypesFromDictionary(d):
                 forwardDeclareForType(t)
 
+        for className, isStruct in additionalDeclarations:
+            builder.add(className, isStruct=isStruct)
+
         CGWrapper.__init__(self, builder.build())
 
 
 class CGBindingRoot(CGThing):
     """
     Root codegen class for binding generation. Instantiate the class, and call
     declare or define to generate header or cpp code (respectively).
     """
@@ -12157,16 +12195,27 @@ class CGBindingRoot(CGThing):
             'mozilla/ErrorResult.h',
             ),
             True)
 
         descriptors = config.getDescriptors(webIDLFile=webIDLFile,
                                             hasInterfaceOrInterfacePrototypeObject=True,
                                             skipGen=False)
 
+        unionTypes = UnionsForFile(config, webIDLFile)
+
+        (unionHeaders, unionImplheaders, unionDeclarations, traverseMethods,
+         unlinkMethods, unionStructs) = UnionTypes(unionTypes, config)
+
+        bindingDeclareHeaders.update(dict.fromkeys(unionHeaders, True))
+        bindingHeaders.update(dict.fromkeys(unionImplheaders, True))
+
+        bindingDeclareHeaders["mozilla/dom/UnionMember.h"] = len(unionStructs) > 0
+        bindingDeclareHeaders["mozilla/dom/BindingUtils.h"] = len(unionStructs) > 0
+
         def descriptorHasCrossOriginProperties(desc):
             def hasCrossOriginProperty(m):
                 props = memberProperties(m, desc)
                 return (props.isCrossOriginMethod or
                         props.isCrossOriginGetter or
                         props.isCrossOriginSetter)
 
             return any(hasCrossOriginProperty(m) for m in desc.interface.members)
@@ -12268,25 +12317,63 @@ class CGBindingRoot(CGThing):
         bindingHeaders["mozilla/dom/BindingDeclarations.h"] = (
             not hasCode and enums)
 
         bindingHeaders["WrapperFactory.h"] = descriptors
         bindingHeaders["mozilla/dom/DOMJSClass.h"] = descriptors
         bindingHeaders["mozilla/dom/ScriptSettings.h"] = dictionaries # AutoJSAPI
         bindingHeaders["xpcpublic.h"] = dictionaries ## xpc::UnprivilegedJunkScope
 
+        cgthings.extend(traverseMethods)
+        cgthings.extend(unlinkMethods)
+
         # Do codegen for all the dictionaries.  We have to be a bit careful
         # here, because we have to generate these in order from least derived
         # to most derived so that class inheritance works out.  We also have to
         # generate members before the dictionary that contains them.
-        cgthings.extend([CGDictionary(d, config.getDescriptorProvider(False))
-                         for d in
-                         dependencySortObjects(dictionaries,
-                                               CGDictionary.getDictionaryDependencies,
-                                               lambda d: d.identifier.name)])
+
+        def getDependenciesFromType(type):
+            if type.isDictionary():
+                return set([type.unroll().inner])
+            if type.isSequence() or type.isArray():
+                return getDependenciesFromType(type.unroll())
+            if type.isUnion():
+                return set([type.unroll()])
+            return set()
+
+        def getDependencies(unionTypeOrDictionary):
+            if isinstance(unionTypeOrDictionary, IDLDictionary):
+                deps = set()
+                if unionTypeOrDictionary.parent:
+                    deps.add(unionTypeOrDictionary.parent)
+                for member in unionTypeOrDictionary.members:
+                    deps |= getDependenciesFromType(member.type)
+                return deps
+
+            assert unionTypeOrDictionary.isType() and unionTypeOrDictionary.isUnion()
+            deps = set()
+            for member in unionTypeOrDictionary.flatMemberTypes:
+                deps |= getDependenciesFromType(member)
+            return deps
+
+        def getName(unionTypeOrDictionary):
+            if isinstance(unionTypeOrDictionary, IDLDictionary):
+                return unionTypeOrDictionary.identifier.name
+
+            assert unionTypeOrDictionary.isType() and unionTypeOrDictionary.isUnion()
+            return unionTypeOrDictionary.name
+
+        for t in dependencySortObjects(dictionaries + unionStructs, getDependencies, getName):
+            if t.isDictionary():
+                cgthings.append(CGDictionary(t, config.getDescriptorProvider(False)))
+            else:
+                assert t.isUnion()
+                # FIXME: Unions are broken in workers.  See bug 809899.
+                cgthings.append(CGUnionStruct(t, config.getDescriptorProvider(False)))
+                cgthings.append(CGUnionStruct(t, config.getDescriptorProvider(False), True))
 
         # Do codegen for all the callbacks.
         cgthings.extend(CGCallbackFunction(c, config.getDescriptorProvider(False))
                         for c in mainCallbacks)
 
         cgthings.extend(CGCallbackFunction(c, config.getDescriptorProvider(True))
                         for c in workerCallbacks if c not in mainCallbacks)
 
@@ -12312,17 +12399,18 @@ class CGBindingRoot(CGThing):
 
         # Wrap all of that in our namespaces.
         curr = CGNamespace.build(['mozilla', 'dom'],
                                  CGWrapper(curr, pre="\n"))
 
         curr = CGList([CGForwardDeclarations(config, descriptors,
                                              mainCallbacks, workerCallbacks,
                                              dictionaries,
-                                             callbackDescriptors + jsImplemented),
+                                             callbackDescriptors + jsImplemented,
+                                             additionalDeclarations=unionDeclarations),
                        curr],
                       "\n")
 
         # Add header includes.
         bindingHeaders = [header
                           for header, include in bindingHeaders.iteritems()
                           if include]
         bindingDeclareHeaders = [header
@@ -12806,17 +12894,17 @@ class CGExampleSetter(CGNativeMember):
     def define(self, cgClass):
         return ''
 
 
 class CGBindingImplClass(CGClass):
     """
     Common codegen for generating a C++ implementation of a WebIDL interface
     """
-    def __init__(self, descriptor, cgMethod, cgGetter, cgSetter, wantGetParent=True):
+    def __init__(self, descriptor, cgMethod, cgGetter, cgSetter, wantGetParent=True, wrapMethodName="WrapObject"):
         """
         cgMethod, cgGetter and cgSetter are classes used to codegen methods,
         getters and setters.
         """
         self.descriptor = descriptor
         self._deps = descriptor.interface.getDeps()
 
         iface = descriptor.interface
@@ -12929,17 +13017,17 @@ class CGBindingImplClass(CGClass):
                     (BuiltinTypes[IDLBuiltinType.Types.boolean],
                      [FakeArgument(BuiltinTypes[IDLBuiltinType.Types.domstring],
                                    FakeMember(),
                                    name="aName")]),
                     { "infallible": True }))
 
         wrapArgs = [Argument('JSContext*', 'aCx')]
         self.methodDecls.insert(0,
-                                ClassMethod("WrapObject", "JSObject*",
+                                ClassMethod(wrapMethodName, "JSObject*",
                                             wrapArgs, virtual=descriptor.wrapperCache,
                                             breakAfterReturnDecl=" ",
                                             override=descriptor.wrapperCache,
                                             body=self.getWrapObjectBody()))
         if wantGetParent:
             self.methodDecls.insert(0,
                                     ClassMethod("GetParentObject",
                                                 self.getGetParentObjectReturnType(),
@@ -14336,17 +14424,16 @@ class GlobalGenRoots():
         curr = CGWrapper(curr, pre=AUTOGENERATED_WARNING_COMMENT)
 
         # Done.
         return curr
 
     @staticmethod
     def RegisterBindings(config):
 
-        # TODO - Generate the methods we want
         curr = CGRegisterProtos(config)
 
         # Wrap all of that in our namespaces.
         curr = CGNamespace.build(['mozilla', 'dom'],
                                  CGWrapper(curr, post='\n'))
         curr = CGWrapper(curr, post='\n')
 
         # Add the includes
@@ -14366,17 +14453,16 @@ class GlobalGenRoots():
         curr = CGIncludeGuard('RegisterBindings', curr)
 
         # Done.
         return curr
 
     @staticmethod
     def RegisterWorkerBindings(config):
 
-        # TODO - Generate the methods we want
         curr = CGRegisterWorkerBindings(config)
 
         # Wrap all of that in our namespaces.
         curr = CGNamespace.build(['mozilla', 'dom'],
                                  CGWrapper(curr, post='\n'))
         curr = CGWrapper(curr, post='\n')
 
         # Add the includes
@@ -14391,79 +14477,91 @@ class GlobalGenRoots():
 
         # Add include guards.
         curr = CGIncludeGuard('RegisterWorkerBindings', curr)
 
         # Done.
         return curr
 
     @staticmethod
+    def ResolveSystemBinding(config):
+
+        curr = CGResolveSystemBinding(config)
+
+        # Wrap all of that in our namespaces.
+        curr = CGNamespace.build(['mozilla', 'dom'],
+                                 CGWrapper(curr, post='\n'))
+        curr = CGWrapper(curr, post='\n')
+
+        # Add the includes
+        defineIncludes = [CGHeaders.getDeclarationFilename(desc.interface)
+                          for desc in config.getDescriptors(hasInterfaceObject=True,
+                                                            register=True,
+                                                            isExposedInSystemGlobals=True,
+                                                            skipGen=False)]
+        defineIncludes.append("nsThreadUtils.h") # For NS_IsMainThread
+        defineIncludes.append("js/Id.h") # For jsid
+        defineIncludes.append("mozilla/dom/BindingUtils.h") # InternJSString
+
+        curr = CGHeaders([], [], [], [], [], defineIncludes,
+                         'ResolveSystemBinding', curr)
+
+        # Add include guards.
+        curr = CGIncludeGuard('ResolveSystemBinding', curr)
+
+        # Done.
+        return curr
+
+    @staticmethod
     def UnionTypes(config):
-
-        (includes, implincludes,
-         declarations, unions) = UnionTypes(config.getDescriptors(),
-                                            config.getDictionaries(),
-                                            config.getCallbacks(),
-                                            config)
+        unionTypes = UnionsForFile(config, None)
+        (includes, implincludes, declarations,
+         traverseMethods, unlinkMethods,
+         unionStructs) = UnionTypes(unionTypes, config)
+
+        unions = CGList(traverseMethods +
+                        unlinkMethods +
+                        [CGUnionStruct(t, config.getDescriptorProvider(False)) for t in unionStructs] +
+                        [CGUnionStruct(t, config.getDescriptorProvider(False), True) for t in unionStructs],
+                        "\n")
+
         includes.add("mozilla/dom/OwningNonNull.h")
         includes.add("mozilla/dom/UnionMember.h")
         includes.add("mozilla/dom/BindingDeclarations.h")
         # Need BindingUtils.h for FakeString
         includes.add("mozilla/dom/BindingUtils.h")
         implincludes.add("mozilla/dom/PrimitiveConversions.h")
 
         # Wrap all of that in our namespaces.
         curr = CGNamespace.build(['mozilla', 'dom'], unions)
 
         curr = CGWrapper(curr, post='\n')
 
-        namespaces = []
-        stack = [CGList([])]
-        for clazz, isStruct in sorted(declarations):
-            elements = clazz.split("::")
-            clazz = CGClassForwardDeclare(elements.pop(), isStruct=isStruct)
-            i = 0
-            if len(elements) > 0:
-                common = min(len(namespaces), len(elements))
-                while i < common and namespaces[i] == elements[i]:
-                    i += 1
-
-            # pop all the namespaces that should be closed
-            namespaces = namespaces[:i]
-
-            # add all the namespaces that should be opened
-            for j, namespace in enumerate(elements[i:]):
-                namespaces.append(namespace)
-                # every CGNamespace that we add holds a CGList
-                list = CGList([])
-                # add the new namespace to the list on top of the stack
-                stack[i + j].append(CGNamespace(namespace, list))
-                # set the top of the namespace stack to the list of the new
-                # namespace
-                stack[i + j + 1:] = [list]
-
-            stack[len(elements)].append(clazz)
-
-        curr = CGList([stack[0], curr], "\n")
+        builder = ForwardDeclarationBuilder()
+        for className, isStruct in declarations:
+            builder.add(className, isStruct=isStruct)
+
+        curr = CGList([builder.build(), curr], "\n")
 
         curr = CGHeaders([], [], [], [], includes, implincludes, 'UnionTypes',
                          curr)
 
         # Add include guards.
         curr = CGIncludeGuard('UnionTypes', curr)
 
         # Done.
         return curr
 
     @staticmethod
     def UnionConversions(config):
-
-        headers, unions = UnionConversions(config.getDescriptors(),
-                                           config.getDictionaries(),
-                                           config.getCallbacks(),
+        unionTypes = []
+        for l in config.unionsPerFilename.itervalues():
+            unionTypes.extend(l)
+        unionTypes.sort(key=lambda u: u[0].name)
+        headers, unions = UnionConversions(unionTypes,
                                            config)
 
         # Wrap all of that in our namespaces.
         curr = CGNamespace.build(['mozilla', 'dom'], unions)
 
         curr = CGWrapper(curr, post='\n')
 
         headers.update(["nsDebug.h", "mozilla/dom/UnionTypes.h"])
@@ -14749,17 +14847,17 @@ class CGEventMethod(CGNativeMember):
         return constructorForNativeCaller + CGNativeMember.define(self, cgClass)
 
 
 class CGEventClass(CGBindingImplClass):
     """
     Codegen for the actual Event class implementation for this descriptor
     """
     def __init__(self, descriptor):
-        CGBindingImplClass.__init__(self, descriptor, CGEventMethod, CGEventGetter, CGEventSetter, False)
+        CGBindingImplClass.__init__(self, descriptor, CGEventMethod, CGEventGetter, CGEventSetter, False, "WrapObjectInternal")
         members = []
         for m in descriptor.interface.members:
             if m.isAttr():
                 if getattr(m, "originatingInterface",
                            descriptor.interface) != descriptor.interface:
                     continue
                 nativeType = self.getNativeTypeForIDLType(m.type).define()
                 members.append(ClassMember(CGDictionary.makeMemberName(m.identifier.name),
@@ -14974,17 +15072,17 @@ class CGEventRoot(CGThing):
                                   'mozilla/dom/BindingUtils.h',
                               ],
                               [
                                   "%s.h" % interfaceName,
                                   "js/GCAPI.h",
                                   'mozilla/dom/Nullable.h',
                                   'nsDOMQS.h'
                               ],
-                              "", self.root)
+                              "", self.root, config)
 
         # And now some include guards
         self.root = CGIncludeGuard(interfaceName, self.root)
 
         self.root = CGWrapper(self.root, pre=AUTOGENERATED_WARNING_COMMENT)
 
         self.root = CGWrapper(self.root, pre=dedent("""
             /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
--- a/dom/bindings/Configuration.py
+++ b/dom/bindings/Configuration.py
@@ -1,14 +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/.
 
 from WebIDL import IDLInterface, IDLExternalInterface, IDLImplementsStatement
 import os
+from collections import defaultdict
 
 autogenerated_comment = "/* THIS FILE IS AUTOGENERATED - DO NOT EDIT */\n"
 
 class Configuration:
     """
     Represents global configuration state based on IDL parse data and
     the configuration file.
     """
@@ -112,16 +113,62 @@ class Configuration:
                            self.getDescriptors(workers=True, isExternal=False, skipGen=False)):
             workerTypes |= set(getFlatTypes(getTypesFromDescriptor(descriptor)))
         (workerCallbacks, workerDictionaries) = findCallbacksAndDictionaries(workerTypes)
 
         self.dictionaries = [d for d in parseData if d.isDictionary()]
         self.callbacks = [c for c in parseData if
                           c.isCallback() and not c.isInterface()]
 
+        # Dictionary mapping from a union type name to a set of filenames where
+        # union types with that name are used.
+        self.filenamesPerUnion = defaultdict(set)
+
+        # Dictionary mapping from a filename to a list of tuples containing a
+        # type and descriptor for the union types used in that file. If a union
+        # type is used in multiple files then it will be added to the list
+        # for the None key. Note that the list contains a tuple for every use of
+        # a union type, so there can be multiple tuples with union types that
+        # have the same name.
+        self.unionsPerFilename = defaultdict(list)
+
+        for (t, descriptor, _) in getAllTypes(self.descriptors, self.dictionaries, self.callbacks):
+            if t.isMozMap():
+                t = t.inner
+            t = t.unroll()
+            if t.isUnion():
+                filenamesForUnion = self.filenamesPerUnion[t.name]
+                if t.filename() not in filenamesForUnion:
+                    if len(filenamesForUnion) == 0:
+                        # This is the first file that we found a union with this
+                        # name in, record the union as part of the file.
+                        uniqueFilenameForUnion = t.filename()
+                    else:
+                        # We already found a file that contains a union with
+                        # this name.
+                        if len(filenamesForUnion) == 1:
+                            # This is the first time we found a union with this
+                            # name in another file.
+                            for f in filenamesForUnion:
+                                # Filter out unions with this name from the
+                                # unions for the file where we previously found
+                                # them.
+                                unionsForFilename = self.unionsPerFilename[f]
+                                unionsForFilename = filter(lambda u: u[0].name != t.name,
+                                                           unionsForFilename)
+                                if len(unionsForFilename) == 0:
+                                    del self.unionsPerFilename[f]
+                                else:
+                                    self.unionsPerFilename[f] = unionsForFilename
+                        # Unions with this name appear in multiple files, record
+                        # the filename as None, so that we can detect that.
+                        uniqueFilenameForUnion = None
+                    self.unionsPerFilename[uniqueFilenameForUnion].append((t, descriptor))
+                    filenamesForUnion.add(t.filename())
+
         def flagWorkerOrMainThread(items, main, worker):
             for item in items:
                 if item in main:
                     item.setUserData("mainThread", True)
                 if item in worker:
                     item.setUserData("workers", True)
         flagWorkerOrMainThread(self.callbacks, mainCallbacks, workerCallbacks)
 
@@ -155,16 +202,19 @@ class Configuration:
                 getter = lambda x: x.interface.isExternal()
             elif key == 'isJSImplemented':
                 getter = lambda x: x.interface.isJSImplemented()
             elif key == 'isNavigatorProperty':
                 getter = lambda x: x.interface.getNavigatorProperty() != None
             elif key == 'isExposedInAnyWorker':
                 getter = lambda x: (not x.interface.isExternal() and
                                     x.interface.isExposedInAnyWorker())
+            elif key == 'isExposedInSystemGlobals':
+                getter = lambda x: (not x.interface.isExternal() and
+                                    x.interface.isExposedInSystemGlobals())
             else:
                 # Have to watch out: just closing over "key" is not enough,
                 # since we're about to mutate its value
                 getter = (lambda attrName: lambda x: getattr(x, attrName))(key)
             tofilter.append((getter, val))
         for f in tofilter:
             curr = filter(lambda x: f[0](x) == f[1], curr)
         return curr
@@ -311,29 +361,39 @@ class Descriptor(DescriptorProvider):
             'NamedGetter': None,
             'NamedSetter': None,
             'NamedCreator': None,
             'NamedDeleter': None,
             'Stringifier': None,
             'LegacyCaller': None,
             'Jsonifier': None
             }
-        if self.concrete:
-            self.proxy = False
-            iface = self.interface
-            def addOperation(operation, m):
-                if not self.operations[operation]:
-                    self.operations[operation] = m
-            # Since stringifiers go on the prototype, we only need to worry
-            # about our own stringifier, not those of our ancestor interfaces.
-            for m in iface.members:
+        # Stringifiers and jsonifiers need to be set up whether an interface is
+        # concrete or not, because they're actually prototype methods and hence
+        # can apply to instances of descendant interfaces.  Legacy callers and
+        # named/indexed operations only need to be set up on concrete
+        # interfaces, since they affect the JSClass we end up using, not the
+        # prototype object.
+        def addOperation(operation, m):
+            if not self.operations[operation]:
+                self.operations[operation] = m
+
+        # Since stringifiers go on the prototype, we only need to worry
+        # about our own stringifier, not those of our ancestor interfaces.
+        if not self.interface.isExternal():
+            for m in self.interface.members:
                 if m.isMethod() and m.isStringifier():
                     addOperation('Stringifier', m)
                 if m.isMethod() and m.isJsonifier():
                     addOperation('Jsonifier', m)
+
+        if self.concrete:
+            self.proxy = False
+            iface = self.interface
+            for m in iface.members:
                 # Don't worry about inheriting legacycallers either: in
                 # practice these are on most-derived prototypes.
                 if m.isMethod() and m.isLegacycaller():
                     if not m.isIdentifierLess():
                         raise TypeError("We don't support legacycaller with "
                                         "identifier.\n%s" % m.location);
                     if len(m.signatures()) != 1:
                         raise TypeError("We don't support overloaded "
@@ -707,8 +767,27 @@ def findCallbacksAndDictionaries(inputTy
                     d = d.parent
         if len(unhandledTypes) != 0:
             doFindCallbacksAndDictionaries(unhandledTypes, callbacks, dictionaries)
 
     retCallbacks = set()
     retDictionaries = set()
     doFindCallbacksAndDictionaries(inputTypes, retCallbacks, retDictionaries)
     return (retCallbacks, retDictionaries)
+
+def getAllTypes(descriptors, dictionaries, callbacks):
+    """
+    Generate all the types we're dealing with.  For each type, a tuple
+    containing type, descriptor, dictionary is yielded.  The
+    descriptor and dictionary can be None if the type does not come
+    from a descriptor or dictionary; they will never both be non-None.
+    """
+    for d in descriptors:
+        if d.interface.isExternal():
+            continue
+        for t in getTypesFromDescriptor(d):
+            yield (t, d, None)
+    for dictionary in dictionaries:
+        for t in getTypesFromDictionary(dictionary):
+            yield (t, None, dictionary)
+    for callback in callbacks:
+        for t in getTypesFromCallback(callback):
+            yield (t, None, None)
--- a/dom/bindings/DOMJSProxyHandler.cpp
+++ b/dom/bindings/DOMJSProxyHandler.cpp
@@ -55,17 +55,17 @@ DOMProxyShadows(JSContext* cx, JS::Handl
   return hasOwn ? js::Shadows : js::DoesntShadowUnique;
 }
 
 // Store the information for the specialized ICs.
 struct SetDOMProxyInformation
 {
   SetDOMProxyInformation() {
     js::SetDOMProxyInformation((const void*) &DOMProxyHandler::family,
-                               js::PROXY_EXTRA_SLOT + JSPROXYSLOT_EXPANDO, DOMProxyShadows);
+                               JSPROXYSLOT_EXPANDO, DOMProxyShadows);
   }
 };
 
 SetDOMProxyInformation gSetDOMProxyInformation;
 
 // static
 JSObject*
 DOMProxyHandler::GetAndClearExpandoObject(JSObject* obj)
--- a/dom/bindings/mozwebidlcodegen/__init__.py
+++ b/dom/bindings/mozwebidlcodegen/__init__.py
@@ -127,24 +127,26 @@ class WebIDLCodegenManager(LoggingMixin)
 
     # Global parser derived declaration files.
     GLOBAL_DECLARE_FILES = {
         'FeatureList.h',
         'GeneratedAtomList.h',
         'PrototypeList.h',
         'RegisterBindings.h',
         'RegisterWorkerBindings.h',
+        'ResolveSystemBinding.h',
         'UnionConversions.h',
         'UnionTypes.h',
     }
 
     # Global parser derived definition files.
     GLOBAL_DEFINE_FILES = {
         'RegisterBindings.cpp',
         'RegisterWorkerBindings.cpp',
+        'ResolveSystemBinding.cpp',
         'UnionTypes.cpp',
         'PrototypeList.cpp',
     }
 
     def __init__(self, config_path, inputs, exported_header_dir,
         codegen_dir, state_path, cache_dir=None, make_deps_path=None,
         make_deps_target=None):
         """Create an instance that manages WebIDLs in the build system.
--- a/dom/bindings/parser/WebIDL.py
+++ b/dom/bindings/parser/WebIDL.py
@@ -1064,16 +1064,19 @@ class IDLInterface(IDLObjectWithScope):
                     m.isMethod() and not m.isStatic())) == 1)
 
     def isExposedInWindow(self):
         return 'Window' in self.exposureSet
 
     def isExposedInAnyWorker(self):
         return len(self.getWorkerExposureSet()) > 0
 
+    def isExposedInSystemGlobals(self):
+        return 'BackstagePass' in self.exposureSet
+
     def isExposedOnlyInSomeWorkers(self):
         assert self.isExposedInAnyWorker()
         workerScopes = self.parentScope.globalNameMapping["Worker"]
         return len(workerScopes.difference(self.exposureSet)) > 0
 
     def getWorkerExposureSet(self):
         workerScopes = self.parentScope.globalNameMapping["Worker"]
         return workerScopes.intersection(self.exposureSet)
@@ -2053,16 +2056,20 @@ class IDLUnionType(IDLType):
         self.hasNullableType = False
         self.hasDictionaryType = False
         self.flatMemberTypes = None
         self.builtin = False
 
     def __eq__(self, other):
         return isinstance(other, IDLUnionType) and self.memberTypes == other.memberTypes
 
+    def __hash__(self):
+        assert self.isComplete()
+        return self.name.__hash__()
+
     def isVoid(self):
         return False
 
     def isUnion(self):
         return True
 
     def isSerializable(self):
         return all(m.isSerializable() for m in self.memberTypes)
@@ -5604,16 +5611,20 @@ class Parser(Tokenizer):
                             )
         logger.reportGrammarErrors()
 
         self._globalScope = IDLScope(BuiltinLocation("<Global Scope>"), None, None)
         # To make our test harness work, pretend like we have a primary global already.  Note that we _don't_ set _globalScope.primaryGlobalAttr, so we'll still be able to detect multiple PrimaryGlobal extended attributes.
         self._globalScope.primaryGlobalName = "FakeTestPrimaryGlobal"
         self._globalScope.globalNames.add("FakeTestPrimaryGlobal")
         self._globalScope.globalNameMapping["FakeTestPrimaryGlobal"].add("FakeTestPrimaryGlobal")
+        # And we add the special-cased "System" global name, which
+        # doesn't have any corresponding interfaces.
+        self._globalScope.globalNames.add("System")
+        self._globalScope.globalNameMapping["System"].add("BackstagePass")
         self._installBuiltins(self._globalScope)
         self._productions = []
 
         self._filename = "<builtin>"
         self.lexer.input(Parser._builtins)
         self._filename = None
 
         self.parser.parse(lexer=self.lexer,tracking=True)
--- a/dom/bindings/test/TestBindingHeader.h
+++ b/dom/bindings/test/TestBindingHeader.h
@@ -6,17 +6,16 @@
 
 #ifndef TestBindingHeader_h
 #define TestBindingHeader_h
 
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/Date.h"
 #include "mozilla/dom/MozMap.h"
 #include "mozilla/dom/TypedArray.h"
-#include "mozilla/dom/UnionTypes.h"
 #include "mozilla/ErrorResult.h"
 #include "nsCOMPtr.h"
 #include "nsGenericHTMLElement.h"
 #include "nsWrapperCache.h"
 
 // Forward declare this before we include TestCodeGenBinding.h, because that header relies on including
 // this one for it, for ParentDict. Hopefully it won't begin to rely on it in more fundamental ways.
 namespace mozilla {
--- a/dom/bindings/test/TestCodeGen.webidl
+++ b/dom/bindings/test/TestCodeGen.webidl
@@ -941,17 +941,17 @@ dictionary Dict : ParentDict {
   unrestricted double  negativeInfUrDouble = -Infinity;
   unrestricted double  nanUrDouble = NaN;
 
   (float or DOMString) floatOrString = "str";
   (object or long) objectOrLong;
 #ifdef DEBUG
   (EventInit or long) eventInitOrLong;
   (EventInit or long)? nullableEventInitOrLong;
-  (Node or long)? nullableNodeOrLong;
+  (HTMLElement or long)? nullableHTMLElementOrLong;
   // CustomEventInit is useful to test because it needs rooting.
   (CustomEventInit or long) eventInitOrLong2;
   (CustomEventInit or long)? nullableEventInitOrLong2;
   (EventInit or long) eventInitOrLongWithDefaultValue = null;
   (CustomEventInit or long) eventInitOrLongWithDefaultValue2 = null;
   (EventInit or long) eventInitOrLongWithDefaultValue3 = 5;
   (CustomEventInit or long) eventInitOrLongWithDefaultValue4 = 5;
   (sequence<object> or long) objectSequenceOrLong;
--- a/dom/bindings/test/TestExampleGen.webidl
+++ b/dom/bindings/test/TestExampleGen.webidl
@@ -8,17 +8,18 @@
  Constructor(unsigned long num, boolean? boolArg),
  Constructor(TestInterface? iface),
  Constructor(long arg1, IndirectlyImplementedInterface iface),
  // Constructor(long arg1, long arg2, (TestInterface or OnlyForUseInConstructor) arg3),
  NamedConstructor=Example,
  NamedConstructor=Example(DOMString str),
  NamedConstructor=Example2(DictForConstructor dict, any any1, object obj1,
                            object? obj2, sequence<Dict> seq, optional any any2,
-                           optional object obj3, optional object? obj4)
+                           optional object obj3, optional object? obj4),
+ NamedConstructor=Example2((long or MozMap<any>) arg1)
  ]
 interface TestExampleInterface {
   // Integer types
   // XXXbz add tests for throwing versions of all the integer stuff
   readonly attribute byte readonlyByte;
   attribute byte writableByte;
   void passByte(byte arg);
   byte receiveByte();
--- a/dom/browser-element/BrowserElementParent.jsm
+++ b/dom/browser-element/BrowserElementParent.jsm
@@ -83,42 +83,42 @@ function BrowserElementParent(frameLoade
     return;
   }
 
   Services.obs.addObserver(this, 'ask-children-to-exit-fullscreen', /* ownsWeak = */ true);
   Services.obs.addObserver(this, 'oop-frameloader-crashed', /* ownsWeak = */ true);
   Services.obs.addObserver(this, 'copypaste-docommand', /* ownsWeak = */ true);
 
   let defineMethod = function(name, fn) {
-    XPCNativeWrapper.unwrap(self._frameElement)[name] = function() {
+    XPCNativeWrapper.unwrap(self._frameElement)[name] = Cu.exportFunction(function() {
       if (self._isAlive()) {
         return fn.apply(self, arguments);
       }
-    };
+    }, self._frameElement);
   }
 
   let defineNoReturnMethod = function(name, fn) {
-    XPCNativeWrapper.unwrap(self._frameElement)[name] = function method() {
+    XPCNativeWrapper.unwrap(self._frameElement)[name] = Cu.exportFunction(function method() {
       if (!self._domRequestReady) {
         // Remote browser haven't been created, we just queue the API call.
         let args = Array.slice(arguments);
         args.unshift(self);
         self._pendingAPICalls.push(method.bind.apply(fn, args));
         return;
       }
       if (self._isAlive()) {
         fn.apply(self, arguments);
       }
-    };
+    }, self._frameElement);
   };
 
   let defineDOMRequestMethod = function(domName, msgName) {
-    XPCNativeWrapper.unwrap(self._frameElement)[domName] = function() {
+    XPCNativeWrapper.unwrap(self._frameElement)[domName] = Cu.exportFunction(function() {
       return self._sendDOMRequest(msgName);
-    };
+    }, self._frameElement);
   }
 
   // Define methods on the frame element.
   defineNoReturnMethod('setVisible', this._setVisible);
   defineDOMRequestMethod('getVisible', 'get-visible');
 
   // Not expose security sensitive browser API for widgets
   if (!this._frameLoader.QueryInterface(Ci.nsIFrameLoader).ownerIsWidget) {
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -93,17 +93,16 @@
 #include "mozilla/unused.h"
 #include "nsCCUncollectableMarker.h"
 #include "nsWrapperCacheInlines.h"
 #include "mozilla/dom/CanvasRenderingContext2DBinding.h"
 #include "mozilla/dom/HTMLImageElement.h"
 #include "mozilla/dom/HTMLVideoElement.h"
 #include "mozilla/dom/SVGMatrix.h"
 #include "mozilla/dom/TextMetrics.h"
-#include "mozilla/dom/UnionTypes.h"
 #include "mozilla/dom/SVGMatrix.h"
 #include "mozilla/FloatingPoint.h"
 #include "nsGlobalWindow.h"
 #include "GLContext.h"
 #include "GLContextProvider.h"
 #include "SVGContentUtils.h"
 #include "SVGImageContext.h"
 #include "nsIScreenManager.h"
@@ -231,17 +230,17 @@ public:
   {
     // This should only be called once or the mPattern destructor will
     // not be executed.
     NS_ASSERTION(!mPattern.GetPattern(), "ForStyle() should only be called once on CanvasGeneralPattern!");
 
     const ContextState &state = aCtx->CurrentState();
 
     if (state.StyleIsColor(aStyle)) {
-      mPattern.InitColorPattern(Color::FromABGR(state.colorStyles[aStyle]));
+      mPattern.InitColorPattern(ToDeviceColor(state.colorStyles[aStyle]));
     } else if (state.gradientStyles[aStyle] &&
                state.gradientStyles[aStyle]->GetType() == CanvasGradient::Type::LINEAR) {
       CanvasLinearGradient *gradient =
         static_cast<CanvasLinearGradient*>(state.gradientStyles[aStyle].get());
 
       mPattern.InitLinearGradientPattern(gradient->mBegin, gradient->mEnd,
                                          gradient->GetGradientStopsForTarget(aRT));
     } else if (state.gradientStyles[aStyle] &&
--- a/dom/canvas/WebGLContextBuffers.cpp
+++ b/dom/canvas/WebGLContextBuffers.cpp
@@ -155,25 +155,24 @@ WebGLContext::BufferData(GLenum target, 
     if (!CheckedInt<GLsizeiptr>(size).isValid())
         return ErrorOutOfMemory("bufferData: bad size");
 
     WebGLBuffer* boundBuffer = bufferSlot->get();
 
     if (!boundBuffer)
         return ErrorInvalidOperation("bufferData: no buffer bound!");
 
-    void* zeroBuffer = calloc(size, 1);
+    UniquePtr<uint8_t> zeroBuffer((uint8_t*)moz_calloc(size, 1));
     if (!zeroBuffer)
         return ErrorOutOfMemory("bufferData: out of memory");
 
     MakeContextCurrent();
     InvalidateBufferFetching();
 
-    GLenum error = CheckedBufferData(target, size, zeroBuffer, usage);
-    free(zeroBuffer);
+    GLenum error = CheckedBufferData(target, size, zeroBuffer.get(), usage);
 
     if (error) {
         GenerateWarning("bufferData generated error %s", ErrorName(error));
         return;
     }
 
     boundBuffer->SetByteLength(size);
     if (!boundBuffer->ElementArrayCacheBufferData(nullptr, size)) {
--- a/dom/canvas/WebGLContextDraw.cpp
+++ b/dom/canvas/WebGLContextDraw.cpp
@@ -573,24 +573,28 @@ WebGLContext::DoFakeVertexAttrib0(GLuint
         mFakeVertexAttrib0BufferObjectVector[2] = mVertexAttrib0Vector[2];
         mFakeVertexAttrib0BufferObjectVector[3] = mVertexAttrib0Vector[3];
 
         gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mFakeVertexAttrib0BufferObject);
 
         GetAndFlushUnderlyingGLErrors();
 
         if (mFakeVertexAttrib0BufferStatus == WebGLVertexAttrib0Status::EmulatedInitializedArray) {
-            nsAutoArrayPtr<GLfloat> array(new GLfloat[4 * vertexCount]);
+            UniquePtr<GLfloat[]> array(new ((fallible_t())) GLfloat[4 * vertexCount]);
+            if (!array) {
+                ErrorOutOfMemory("Fake attrib0 array.");
+                return false;
+            }
             for(size_t i = 0; i < vertexCount; ++i) {
                 array[4 * i + 0] = mVertexAttrib0Vector[0];
                 array[4 * i + 1] = mVertexAttrib0Vector[1];
                 array[4 * i + 2] = mVertexAttrib0Vector[2];
                 array[4 * i + 3] = mVertexAttrib0Vector[3];
             }
-            gl->fBufferData(LOCAL_GL_ARRAY_BUFFER, dataSize, array, LOCAL_GL_DYNAMIC_DRAW);
+            gl->fBufferData(LOCAL_GL_ARRAY_BUFFER, dataSize, array.get(), LOCAL_GL_DYNAMIC_DRAW);
         } else {
             gl->fBufferData(LOCAL_GL_ARRAY_BUFFER, dataSize, nullptr, LOCAL_GL_DYNAMIC_DRAW);
         }
         GLenum error = GetAndFlushUnderlyingGLErrors();
 
         gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mBoundArrayBuffer ? mBoundArrayBuffer->GLName() : 0);
 
         // note that we do this error checking and early return AFTER having restored the buffer binding above
@@ -745,27 +749,26 @@ WebGLContext::FakeBlackTexture::FakeBlac
                    &formerBinding);
   gl->fGenTextures(1, &mGLName);
   gl->fBindTexture(target.get(), mGLName);
 
   // we allocate our zeros on the heap, and we overallocate (16 bytes instead of 4)
   // to minimize the risk of running into a driver bug in texImage2D, as it is
   // a bit unusual maybe to create 1x1 textures, and the stack may not have the alignment
   // that texImage2D expects.
-  void* zeros = calloc(1, 16);
+  UniquePtr<uint8_t> zeros((uint8_t*)moz_xcalloc(1, 16));
   if (target == LOCAL_GL_TEXTURE_2D) {
       gl->fTexImage2D(target.get(), 0, format, 1, 1,
-                      0, format, LOCAL_GL_UNSIGNED_BYTE, zeros);
+                      0, format, LOCAL_GL_UNSIGNED_BYTE, zeros.get());
   } else {
       for (GLuint i = 0; i < 6; ++i) {
           gl->fTexImage2D(LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, format, 1, 1,
-                          0, format, LOCAL_GL_UNSIGNED_BYTE, zeros);
+                          0, format, LOCAL_GL_UNSIGNED_BYTE, zeros.get());
       }
   }
-  free(zeros);
 
   gl->fBindTexture(target.get(), formerBinding);
 }
 
 WebGLContext::FakeBlackTexture::~FakeBlackTexture()
 {
   if (mGL) {
       mGL->MakeCurrent();
--- a/dom/canvas/WebGLContextGL.cpp
+++ b/dom/canvas/WebGLContextGL.cpp
@@ -2321,30 +2321,33 @@ WebGLContext::ReadPixels(GLint x, GLint 
         // no need to check again for integer overflow here, since we already know the sizes aren't greater than before
         uint32_t subrect_plainRowSize = subrect_width * bytesPerPixel;
     // There are checks above to ensure that this doesn't overflow.
         uint32_t subrect_alignedRowSize =
             RoundedToNextMultipleOf(subrect_plainRowSize, mPixelStorePackAlignment).value();
         uint32_t subrect_byteLength = (subrect_height-1)*subrect_alignedRowSize + subrect_plainRowSize;
 
         // create subrect buffer, call glReadPixels, copy pixels into destination buffer, delete subrect buffer
-        GLubyte *subrect_data = new GLubyte[subrect_byteLength];
-        gl->fReadPixels(subrect_x, subrect_y, subrect_width, subrect_height, format, type, subrect_data);
+        UniquePtr<GLubyte> subrect_data(new ((fallible_t())) GLubyte[subrect_byteLength]);
+        if (!subrect_data)
+            return ErrorOutOfMemory("readPixels: subrect_data");
+
+        gl->fReadPixels(subrect_x, subrect_y, subrect_width, subrect_height,
+                        format, type, subrect_data.get());
 
         // notice that this for loop terminates because we already checked that subrect_height is at most height
         for (GLint y_inside_subrect = 0; y_inside_subrect < subrect_height; ++y_inside_subrect) {
             GLint subrect_x_in_dest_buffer = subrect_x - x;
             GLint subrect_y_in_dest_buffer = subrect_y - y;
             memcpy(static_cast<GLubyte*>(data)
                      + checked_alignedRowSize.value() * (subrect_y_in_dest_buffer + y_inside_subrect)
                      + bytesPerPixel * subrect_x_in_dest_buffer, // destination
-                   subrect_data + subrect_alignedRowSize * y_inside_subrect, // source
+                   subrect_data.get() + subrect_alignedRowSize * y_inside_subrect, // source
                    subrect_plainRowSize); // size
         }
-        delete [] subrect_data;
     }
 
     // if we're reading alpha, we may need to do fixup.  Note that we don't allow
     // GL_ALPHA to readpixels currently, but we had the code written for it already.
     if (format == LOCAL_GL_ALPHA ||
         format == LOCAL_GL_RGBA)
     {
         bool needAlphaFixup;
@@ -3805,17 +3808,17 @@ WebGLContext::TexImage2D_base(TexImageTa
             !mPixelStoreFlipY)
         {
             // no conversion, no flipping, so we avoid copying anything and just pass the source pointer
             pixels = data;
         }
         else
         {
             size_t convertedDataSize = height * dstStride;
-            convertedData = (uint8_t*)moz_malloc(convertedDataSize);
+            convertedData = new ((fallible_t())) uint8_t[convertedDataSize];
             if (!convertedData) {
                 ErrorOutOfMemory("texImage2D: Ran out of memory when allocating"
                                  " a buffer for doing format conversion.");
                 return;
             }
             if (!ConvertImage(width, height, srcStride, dstStride,
                               static_cast<uint8_t*>(data), convertedData,
                               actualSrcFormat, srcPremultiplied,
@@ -4009,17 +4012,17 @@ WebGLContext::TexSubImage2D_base(TexImag
     // no conversion, no flipping, so we avoid copying anything and just pass the source pointer
     bool noConversion = (actualSrcFormat == dstFormat &&
                          srcPremultiplied == mPixelStorePremultiplyAlpha &&
                          srcStride == dstStride &&
                          !mPixelStoreFlipY);
 
     if (!noConversion) {
         size_t convertedDataSize = height * dstStride;
-        convertedData = (uint8_t*)moz_malloc(convertedDataSize);
+        convertedData = new ((fallible_t())) uint8_t[convertedDataSize];
         if (!convertedData) {
             ErrorOutOfMemory("texImage2D: Ran out of memory when allocating"
                              " a buffer for doing format conversion.");
             return;
         }
         if (!ConvertImage(width, height, srcStride, dstStride,
                           static_cast<const uint8_t*>(data), convertedData,
                           actualSrcFormat, srcPremultiplied,
--- a/dom/canvas/WebGLTexture.cpp
+++ b/dom/canvas/WebGLTexture.cpp
@@ -590,44 +590,44 @@ WebGLTexture::EnsureNoUninitializedImage
     CheckedUint32 checked_byteLength
         = WebGLContext::GetImageSize(
                         imageInfo.mHeight,
                         imageInfo.mWidth,
                         imageInfo.mDepth,
                         bytespertexel,
                         mContext->mPixelStoreUnpackAlignment);
     MOZ_ASSERT(checked_byteLength.isValid()); // should have been checked earlier
-    ScopedFreePtr<void> zeros;
-    zeros = calloc(1, checked_byteLength.value());
+
+    UniquePtr<uint8_t> zeros((uint8_t*)moz_xcalloc(1, checked_byteLength.value())); // Infallible for now.
 
     gl::GLContext* gl = mContext->gl;
     GLenum driverInternalFormat = LOCAL_GL_NONE;
     GLenum driverFormat = LOCAL_GL_NONE;
     GLenum driverType = LOCAL_GL_NONE;
     DriverFormatsFromEffectiveInternalFormat(gl, imageInfo.mEffectiveInternalFormat,
                                              &driverInternalFormat, &driverFormat, &driverType);
 
     mContext->GetAndFlushUnderlyingGLErrors();
     if (imageTarget == LOCAL_GL_TEXTURE_3D) {
         MOZ_ASSERT(mImmutable, "Shouldn't be possible to have non-immutable-format 3D textures in WebGL");
         gl->fTexSubImage3D(imageTarget.get(), level, 0, 0, 0,
                         imageInfo.mWidth, imageInfo.mHeight, imageInfo.mDepth,
                         driverFormat, driverType,
-                        zeros);
+                        zeros.get());
     } else {
         if (mImmutable) {
             gl->fTexSubImage2D(imageTarget.get(), level, 0, 0,
                             imageInfo.mWidth, imageInfo.mHeight,
                             driverFormat, driverType,
-                            zeros);
+                            zeros.get());
         } else {
             gl->fTexImage2D(imageTarget.get(), level, driverInternalFormat,
                             imageInfo.mWidth, imageInfo.mHeight,
                             0, driverFormat, driverType,
-                            zeros);
+                            zeros.get());
         }
     }
     GLenum error = mContext->GetAndFlushUnderlyingGLErrors();
     if (error) {
         // Should only be OUT_OF_MEMORY. Anyway, there's no good way to recover from this here.
         printf_stderr("Error: 0x%4x\n", error);
         MOZ_CRASH(); // errors on texture upload have been related to video memory exposure in the past.
     }
--- a/dom/crypto/CryptoBuffer.cpp
+++ b/dom/crypto/CryptoBuffer.cpp
@@ -138,32 +138,28 @@ CryptoBuffer::ToJwkBase64(nsString& aBas
   if (base64.FindCharInSet("+/", 0) != kNotFound) {
     return NS_ERROR_FAILURE;
   }
 
   CopyASCIItoUTF16(base64, aBase64);
   return NS_OK;
 }
 
-SECItem*
-CryptoBuffer::ToSECItem() const
+bool
+CryptoBuffer::ToSECItem(PLArenaPool *aArena, SECItem* aItem) const
 {
-  uint8_t* data = (uint8_t*) moz_malloc(Length());
-  if (!data) {
-    return nullptr;
+  aItem->type = siBuffer;
+  aItem->data = nullptr;
+
+  if (!::SECITEM_AllocItem(aArena, aItem, Length())) {
+    return false;
   }
 
-  SECItem* item = ::SECITEM_AllocItem(nullptr, nullptr, 0);
-  item->type = siBuffer;
-  item->data = data;
-  item->len = Length();
-
-  memcpy(item->data, Elements(), Length());
-
-  return item;
+  memcpy(aItem->data, Elements(), Length());
+  return true;
 }
 
 JSObject*
 CryptoBuffer::ToUint8Array(JSContext* aCx) const
 {
   return Uint8Array::Create(aCx, Length(), Elements());
 }
 
--- a/dom/crypto/CryptoBuffer.h
+++ b/dom/crypto/CryptoBuffer.h
@@ -34,17 +34,17 @@ public:
   uint8_t* Assign(const TypedArray_base<T, UnwrapArray, GetLengthAndData>& aArray)
   {
     aArray.ComputeLengthAndData();
     return Assign(aArray.Data(), aArray.Length());
   }
 
   nsresult FromJwkBase64(const nsString& aBase64);
   nsresult ToJwkBase64(nsString& aBase64);
-  SECItem* ToSECItem() const;
+  bool ToSECItem(PLArenaPool* aArena, SECItem* aItem) const;
   JSObject* ToUint8Array(JSContext* aCx) const;
 
   bool GetBigIntValue(unsigned long& aRetVal);
 };
 
 } // namespace dom
 } // namespace mozilla
 
--- a/dom/crypto/CryptoKey.cpp
+++ b/dom/crypto/CryptoKey.cpp
@@ -7,16 +7,31 @@
 #include "pk11pub.h"
 #include "cryptohi.h"
 #include "ScopedNSSTypes.h"
 #include "mozilla/dom/CryptoKey.h"
 #include "mozilla/dom/WebCryptoCommon.h"
 #include "mozilla/dom/SubtleCryptoBinding.h"
 #include "mozilla/dom/ToJSValue.h"
 
+// Templates taken from security/nss/lib/cryptohi/seckey.c
+// These would ideally be exported by NSS and until that
+// happens we have to keep our own copies.
+const SEC_ASN1Template SECKEY_DHPublicKeyTemplate[] = {
+    { SEC_ASN1_INTEGER, offsetof(SECKEYPublicKey,u.dh.publicValue), },
+    { 0, }
+};
+const SEC_ASN1Template SECKEY_DHParamKeyTemplate[] = {
+    { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SECKEYPublicKey) },
+    { SEC_ASN1_INTEGER, offsetof(SECKEYPublicKey,u.dh.prime), },
+    { SEC_ASN1_INTEGER, offsetof(SECKEYPublicKey,u.dh.base), },
+    { SEC_ASN1_SKIP_REST },
+    { 0, }
+};
+
 namespace mozilla {
 namespace dom {
 
 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(CryptoKey, mGlobal)
 NS_IMPL_CYCLE_COLLECTING_ADDREF(CryptoKey)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(CryptoKey)
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CryptoKey)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
@@ -107,16 +122,22 @@ CryptoKey::GetAlgorithm(JSContext* cx, J
       RootedDictionary<RsaHashedKeyAlgorithm> rsa(cx);
       mAlgorithm.mRsa.ToKeyAlgorithm(cx, rsa);
       converted = ToJSValue(cx, rsa, &val);
       break;
     }
     case KeyAlgorithmProxy::EC:
       converted = ToJSValue(cx, mAlgorithm.mEc, &val);
       break;
+    case KeyAlgorithmProxy::DH: {
+      RootedDictionary<DhKeyAlgorithm> dh(cx);
+      mAlgorithm.mDh.ToKeyAlgorithm(cx, dh);
+      converted = ToJSValue(cx, dh, &val);
+      break;
+    }
   }
   if (!converted) {
     aRv.Throw(NS_ERROR_DOM_OPERATION_ERR);
     return;
   }
 
   aRetVal.set(&val.toObject());
 }
@@ -341,54 +362,78 @@ void CryptoKey::destructorSafeDestroyNSS
 // Serialization and deserialization convenience methods
 
 SECKEYPrivateKey*
 CryptoKey::PrivateKeyFromPkcs8(CryptoBuffer& aKeyData,
                          const nsNSSShutDownPreventionLock& /*proofOfLock*/)
 {
   SECKEYPrivateKey* privKey;
   ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
-  ScopedSECItem pkcs8Item(aKeyData.ToSECItem());
-  if (!pkcs8Item) {
+
+  ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
+  if (!arena) {
+    return nullptr;
+  }
+
+  SECItem pkcs8Item = { siBuffer, nullptr, 0 };
+  if (!aKeyData.ToSECItem(arena, &pkcs8Item)) {
     return nullptr;
   }
 
   // Allow everything, we enforce usage ourselves
   unsigned int usage = KU_ALL;
 
   SECStatus rv = PK11_ImportDERPrivateKeyInfoAndReturnKey(
-                 slot.get(), pkcs8Item.get(), nullptr, nullptr, false, false,
+                 slot.get(), &pkcs8Item, nullptr, nullptr, false, false,
                  usage, &privKey, nullptr);
 
   if (rv == SECFailure) {
     return nullptr;
   }
   return privKey;
 }
 
 SECKEYPublicKey*
 CryptoKey::PublicKeyFromSpki(CryptoBuffer& aKeyData,
                        const nsNSSShutDownPreventionLock& /*proofOfLock*/)
 {
-  ScopedSECItem spkiItem(aKeyData.ToSECItem());
-  if (!spkiItem) {
+  ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
+  if (!arena) {
     return nullptr;
   }
 
-  ScopedCERTSubjectPublicKeyInfo spki(SECKEY_DecodeDERSubjectPublicKeyInfo(spkiItem.get()));
+  SECItem spkiItem = { siBuffer, nullptr, 0 };
+  if (!aKeyData.ToSECItem(arena, &spkiItem)) {
+    return nullptr;
+  }
+
+  ScopedCERTSubjectPublicKeyInfo spki(SECKEY_DecodeDERSubjectPublicKeyInfo(&spkiItem));
   if (!spki) {
     return nullptr;
   }
 
-  // Check for id-ecDH. Per the WebCrypto spec we must support it but NSS
-  // does unfortunately not know about it. Let's change the algorithm to
-  // id-ecPublicKey to make NSS happy.
-  if (SECITEM_ItemsAreEqual(&SEC_OID_DATA_EC_DH, &spki->algorithm.algorithm)) {
-    // Retrieve OID data for id-ecPublicKey (1.2.840.10045.2.1).
-    SECOidData* oidData = SECOID_FindOIDByTag(SEC_OID_ANSIX962_EC_PUBLIC_KEY);
+  bool isECDHAlgorithm = SECITEM_ItemsAreEqual(&SEC_OID_DATA_EC_DH,
+                                               &spki->algorithm.algorithm);
+  bool isDHAlgorithm = SECITEM_ItemsAreEqual(&SEC_OID_DATA_DH_KEY_AGREEMENT,
+                                             &spki->algorithm.algorithm);
+
+  // Check for |id-ecDH| and |dhKeyAgreement|. Per the WebCrypto spec we must
+  // support these OIDs but NSS does unfortunately not know about them. Let's
+  // change the algorithm to |id-ecPublicKey| or |dhPublicKey| to make NSS happy.
+  if (isECDHAlgorithm || isDHAlgorithm) {
+    SECOidTag oid = SEC_OID_UNKNOWN;
+    if (isECDHAlgorithm) {
+      oid = SEC_OID_ANSIX962_EC_PUBLIC_KEY;
+    } else if (isDHAlgorithm) {
+      oid = SEC_OID_X942_DIFFIE_HELMAN_KEY;
+    } else {
+      MOZ_ASSERT(false);
+    }
+
+    SECOidData* oidData = SECOID_FindOIDByTag(oid);
     if (!oidData) {
       return nullptr;
     }
 
     SECStatus rv = SECITEM_CopyItem(spki->arena, &spki->algorithm.algorithm,
                                     &oidData->oid);
     if (rv != SECSuccess) {
       return nullptr;
@@ -412,31 +457,100 @@ CryptoKey::PrivateKeyToPkcs8(SECKEYPriva
   if (!pkcs8Item.get()) {
     return NS_ERROR_DOM_INVALID_ACCESS_ERR;
   }
   aRetVal.Assign(pkcs8Item.get());
   return NS_OK;
 }
 
 nsresult
-CryptoKey::PublicKeyToSpki(SECKEYPublicKey* aPubKey,
-                     CryptoBuffer& aRetVal,
-                     const nsNSSShutDownPreventionLock& /*proofOfLock*/)
+PublicDhKeyToSpki(SECKEYPublicKey* aPubKey,
+                  CERTSubjectPublicKeyInfo* aSpki)
 {
-  ScopedCERTSubjectPublicKeyInfo spki(SECKEY_CreateSubjectPublicKeyInfo(aPubKey));
-  if (!spki) {
+  SECItem* params = ::SECITEM_AllocItem(aSpki->arena, nullptr, 0);
+  if (!params) {
+    return NS_ERROR_DOM_OPERATION_ERR;
+  }
+
+  SECItem* rvItem = SEC_ASN1EncodeItem(aSpki->arena, params, aPubKey,
+                                       SECKEY_DHParamKeyTemplate);
+  if (!rvItem) {
+    return NS_ERROR_DOM_OPERATION_ERR;
+  }
+
+  SECStatus rv = SECOID_SetAlgorithmID(aSpki->arena, &aSpki->algorithm,
+                                       SEC_OID_X942_DIFFIE_HELMAN_KEY, params);
+  if (rv != SECSuccess) {
+    return NS_ERROR_DOM_OPERATION_ERR;
+  }
+
+  rvItem = SEC_ASN1EncodeItem(aSpki->arena, &aSpki->subjectPublicKey, aPubKey,
+                              SECKEY_DHPublicKeyTemplate);
+  if (!rvItem) {
     return NS_ERROR_DOM_OPERATION_ERR;
   }
 
+  // The public value is a BIT_STRING encoded as an INTEGER. After encoding
+  // an INT we need to adjust the length to reflect the number of bits.
+  aSpki->subjectPublicKey.len <<= 3;
+
+  return NS_OK;
+}
+
+nsresult
+CryptoKey::PublicKeyToSpki(SECKEYPublicKey* aPubKey,
+                           CryptoBuffer& aRetVal,
+                           const nsNSSShutDownPreventionLock& /*proofOfLock*/)
+{
+  ScopedCERTSubjectPublicKeyInfo spki;
+
+  // NSS doesn't support exporting DH public keys.
+  if (aPubKey->keyType == dhKey) {
+    // Mimic the behavior of SECKEY_CreateSubjectPublicKeyInfo() and create
+    // a new arena for the SPKI object.
+    ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
+    if (!arena) {
+      return NS_ERROR_DOM_OPERATION_ERR;
+    }
+
+    spki = PORT_ArenaZNew(arena, CERTSubjectPublicKeyInfo);
+    if (!spki) {
+      return NS_ERROR_DOM_OPERATION_ERR;
+    }
+
+    // Assign |arena| to |spki| and null the variable afterwards so that the
+    // arena created above that holds the SPKI object is free'd when |spki|
+    // goes out of scope, not when |arena| does.
+    spki->arena = arena.forget();
+
+    nsresult rv = PublicDhKeyToSpki(aPubKey, spki);
+    NS_ENSURE_SUCCESS(rv, rv);
+  } else {
+    spki = SECKEY_CreateSubjectPublicKeyInfo(aPubKey);
+    if (!spki) {
+      return NS_ERROR_DOM_OPERATION_ERR;
+    }
+  }
+
   // Per WebCrypto spec we must export ECDH SPKIs with the algorithm OID
-  // id-ecDH (1.3.132.112). NSS doesn't know about that OID and there is
+  // id-ecDH (1.3.132.112) and DH SPKIs with OID dhKeyAgreement
+  // (1.2.840.113549.1.3.1). NSS doesn't know about these OIDs and there is
   // no way to specify the algorithm to use when exporting a public key.
-  if (aPubKey->keyType == ecKey) {
+  if (aPubKey->keyType == ecKey || aPubKey->keyType == dhKey) {
+    const SECItem* oidData = nullptr;
+    if (aPubKey->keyType == ecKey) {
+      oidData = &SEC_OID_DATA_EC_DH;
+    } else if (aPubKey->keyType == dhKey) {
+      oidData = &SEC_OID_DATA_DH_KEY_AGREEMENT;
+    } else {
+      MOZ_ASSERT(false);
+    }
+
     SECStatus rv = SECITEM_CopyItem(spki->arena, &spki->algorithm.algorithm,
-                                    &SEC_OID_DATA_EC_DH);
+                                    oidData);
     if (rv != SECSuccess) {
       return NS_ERROR_DOM_OPERATION_ERR;
     }
   }
 
   const SEC_ASN1Template* tpl = SEC_ASN1_GET(CERT_SubjectPublicKeyInfoTemplate);
   ScopedSECItem spkiItem(SEC_ASN1EncodeItem(nullptr, nullptr, spki, tpl));
 
@@ -570,24 +684,29 @@ CryptoKey::PrivateKeyFromJwk(const JsonW
         !aJwk.mP.WasPassed() || NS_FAILED(p.FromJwkBase64(aJwk.mP.Value())) ||
         !aJwk.mQ.WasPassed() || NS_FAILED(q.FromJwkBase64(aJwk.mQ.Value())) ||
         !aJwk.mDp.WasPassed() || NS_FAILED(dp.FromJwkBase64(aJwk.mDp.Value())) ||
         !aJwk.mDq.WasPassed() || NS_FAILED(dq.FromJwkBase64(aJwk.mDq.Value())) ||
         !aJwk.mQi.WasPassed() || NS_FAILED(qi.FromJwkBase64(aJwk.mQi.Value()))) {
       return nullptr;
     }
 
-    // Compute the ID for this key
-    // This is generated with a SHA-1 hash, so unlikely to collide
-    ScopedSECItem nItem(n.ToSECItem());
-    if (!nItem.get()) {
+    ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
+    if (!arena) {
       return nullptr;
     }
 
-    ScopedSECItem objID(PK11_MakeIDFromPubKey(nItem.get()));
+    // Compute the ID for this key
+    // This is generated with a SHA-1 hash, so unlikely to collide
+    SECItem nItem = { siBuffer, nullptr, 0 };
+    if (!n.ToSECItem(arena, &nItem)) {
+      return nullptr;
+    }
+
+    ScopedSECItem objID(PK11_MakeIDFromPubKey(&nItem));
     if (!objID.get()) {
       return nullptr;
     }
 
     // Populate template from parameters
     CK_KEY_TYPE rsaValue = CKK_RSA;
     CK_ATTRIBUTE keyTemplate[14] = {
       { CKA_CLASS,            &privateKeyValue,      sizeof(privateKeyValue) },
@@ -885,16 +1004,59 @@ CryptoKey::PublicKeyToJwk(SECKEYPublicKe
         return NS_ERROR_DOM_OPERATION_ERR;
       }
       return NS_OK;
     default:
       return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
   }
 }
 
+SECKEYPublicKey*
+CryptoKey::PublicDhKeyFromRaw(CryptoBuffer& aKeyData,
+                              const CryptoBuffer& aPrime,
+                              const CryptoBuffer& aGenerator,
+                              const nsNSSShutDownPreventionLock& /*proofOfLock*/)
+{
+  ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
+  if (!arena) {
+    return nullptr;
+  }
+
+  SECKEYPublicKey* key = PORT_ArenaZNew(arena, SECKEYPublicKey);
+  if (!key) {
+    return nullptr;
+  }
+
+  key->keyType = dhKey;
+  key->pkcs11Slot = nullptr;
+  key->pkcs11ID = CK_INVALID_HANDLE;
+
+  // Set DH public key params.
+  if (!aPrime.ToSECItem(arena, &key->u.dh.prime) ||
+      !aGenerator.ToSECItem(arena, &key->u.dh.base) ||
+      !aKeyData.ToSECItem(arena, &key->u.dh.publicValue)) {
+    return nullptr;
+  }
+
+  key->u.dh.prime.type = siUnsignedInteger;
+  key->u.dh.base.type = siUnsignedInteger;
+  key->u.dh.publicValue.type = siUnsignedInteger;
+
+  return SECKEY_CopyPublicKey(key);
+}
+
+nsresult
+CryptoKey::PublicDhKeyToRaw(SECKEYPublicKey* aPubKey,
+                            CryptoBuffer& aRetVal,
+                            const nsNSSShutDownPreventionLock& /*proofOfLock*/)
+{
+  aRetVal.Assign(&aPubKey->u.dh.publicValue);
+  return NS_OK;
+}
+
 bool
 CryptoKey::PublicKeyValid(SECKEYPublicKey* aPubKey)
 {
   ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
   if (!slot.get()) {
     return false;
   }
 
--- a/dom/crypto/CryptoKey.h
+++ b/dom/crypto/CryptoKey.h
@@ -166,16 +166,24 @@ public:
                                   const nsNSSShutDownPreventionLock& /*proofOfLock*/);
 
   static SECKEYPublicKey* PublicKeyFromJwk(const JsonWebKey& aKeyData,
                                            const nsNSSShutDownPreventionLock& /*proofOfLock*/);
   static nsresult PublicKeyToJwk(SECKEYPublicKey* aPrivKey,
                                  JsonWebKey& aRetVal,
                                  const nsNSSShutDownPreventionLock& /*proofOfLock*/);
 
+  static SECKEYPublicKey* PublicDhKeyFromRaw(CryptoBuffer& aKeyData,
+                                             const CryptoBuffer& aPrime,
+                                             const CryptoBuffer& aGenerator,
+                                             const nsNSSShutDownPreventionLock& /*proofOfLock*/);
+  static nsresult PublicDhKeyToRaw(SECKEYPublicKey* aPubKey,
+                                   CryptoBuffer& aRetVal,
+                                   const nsNSSShutDownPreventionLock& /*proofOfLock*/);
+
   static bool PublicKeyValid(SECKEYPublicKey* aPubKey);
 
   // Structured clone methods use these to clone keys
   bool WriteStructuredClone(JSStructuredCloneWriter* aWriter) const;
   bool ReadStructuredClone(JSStructuredCloneReader* aReader);
 
 private:
   ~CryptoKey();
--- a/dom/crypto/KeyAlgorithmProxy.cpp
+++ b/dom/crypto/KeyAlgorithmProxy.cpp
@@ -26,16 +26,20 @@ KeyAlgorithmProxy::WriteStructuredClone(
              WriteString(aWriter, mHmac.mHash.mName);
     case RSA: {
       return JS_WriteUint32Pair(aWriter, mRsa.mModulusLength, 0) &&
              WriteBuffer(aWriter, mRsa.mPublicExponent) &&
              WriteString(aWriter, mRsa.mHash.mName);
     }
     case EC:
       return WriteString(aWriter, mEc.mNamedCurve);
+    case DH: {
+      return WriteBuffer(aWriter, mDh.mPrime) &&
+             WriteBuffer(aWriter, mDh.mGenerator);
+    }
   }
 
   return false;
 }
 
 bool
 KeyAlgorithmProxy::ReadStructuredClone(JSStructuredCloneReader* aReader)
 {
@@ -87,16 +91,25 @@ KeyAlgorithmProxy::ReadStructuredClone(J
       nsString namedCurve;
       if (!ReadString(aReader, mEc.mNamedCurve)) {
         return false;
       }
 
       mEc.mName = mName;
       return true;
     }
+    case DH: {
+      if (!ReadBuffer(aReader, mDh.mPrime) ||
+          !ReadBuffer(aReader, mDh.mGenerator)) {
+        return false;
+      }
+
+      mDh.mName = mName;
+      return true;
+    }
   }
 
   return false;
 }
 
 CK_MECHANISM_TYPE
 KeyAlgorithmProxy::Mechanism() const
 {
--- a/dom/crypto/KeyAlgorithmProxy.h
+++ b/dom/crypto/KeyAlgorithmProxy.h
@@ -31,35 +31,55 @@ struct RsaHashedKeyAlgorithmStorage {
     aRsa.mName = mName;
     aRsa.mModulusLength = mModulusLength;
     aRsa.mHash.mName = mHash.mName;
     aRsa.mPublicExponent.Init(mPublicExponent.ToUint8Array(aCx));
     aRsa.mPublicExponent.ComputeLengthAndData();
   }
 };
 
+// A heap-safe variant of DhKeyAlgorithm
+// The only difference is that it uses CryptoBuffers instead of Uint8Arrays
+struct DhKeyAlgorithmStorage {
+  nsString mName;
+  CryptoBuffer mPrime;
+  CryptoBuffer mGenerator;
+
+  void
+  ToKeyAlgorithm(JSContext* aCx, DhKeyAlgorithm& aDh) const
+  {
+    aDh.mName = mName;
+    aDh.mPrime.Init(mPrime.ToUint8Array(aCx));
+    aDh.mPrime.ComputeLengthAndData();
+    aDh.mGenerator.Init(mGenerator.ToUint8Array(aCx));
+    aDh.mGenerator.ComputeLengthAndData();
+  }
+};
+
 // This class encapuslates a KeyAlgorithm object, and adds several
 // methods that make WebCrypto operations simpler.
 struct KeyAlgorithmProxy
 {
   enum KeyAlgorithmType {
     AES,
     HMAC,
     RSA,
-    EC
+    EC,
+    DH,
   };
   KeyAlgorithmType mType;
 
   // Plain is always populated with the algorithm name
   // Others are only populated for the corresponding key type
   nsString mName;
   AesKeyAlgorithm mAes;
   HmacKeyAlgorithm mHmac;
   RsaHashedKeyAlgorithmStorage mRsa;
   EcKeyAlgorithm mEc;
+  DhKeyAlgorithmStorage mDh;
 
   // Structured clone
   bool WriteStructuredClone(JSStructuredCloneWriter* aWriter) const;
   bool ReadStructuredClone(JSStructuredCloneReader* aReader);
 
   // Extract various forms of derived information
   CK_MECHANISM_TYPE Mechanism() const;
   nsString JwkAlg() const;
@@ -104,14 +124,25 @@ struct KeyAlgorithmProxy
   void
   MakeEc(const nsString& aName, const nsString& aNamedCurve)
   {
     mType = EC;
     mName = aName;
     mEc.mName = aName;
     mEc.mNamedCurve = aNamedCurve;
   }
+
+  void
+  MakeDh(const nsString& aName, const CryptoBuffer& aPrime,
+         const CryptoBuffer& aGenerator)
+  {
+    mType = DH;
+    mName = aName;
+    mDh.mName = aName;
+    mDh.mPrime.Assign(aPrime);
+    mDh.mGenerator.Assign(aGenerator);
+  }
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_KeyAlgorithmProxy_h
--- a/dom/crypto/WebCryptoCommon.h
+++ b/dom/crypto/WebCryptoCommon.h
@@ -23,16 +23,17 @@
 #define WEBCRYPTO_ALG_SHA384        "SHA-384"
 #define WEBCRYPTO_ALG_SHA512        "SHA-512"
 #define WEBCRYPTO_ALG_HMAC          "HMAC"
 #define WEBCRYPTO_ALG_PBKDF2        "PBKDF2"
 #define WEBCRYPTO_ALG_RSASSA_PKCS1  "RSASSA-PKCS1-v1_5"
 #define WEBCRYPTO_ALG_RSA_OAEP      "RSA-OAEP"
 #define WEBCRYPTO_ALG_ECDH          "ECDH"
 #define WEBCRYPTO_ALG_ECDSA         "ECDSA"
+#define WEBCRYPTO_ALG_DH            "DH"
 
 // WebCrypto key formats
 #define WEBCRYPTO_KEY_FORMAT_RAW    "raw"
 #define WEBCRYPTO_KEY_FORMAT_PKCS8  "pkcs8"
 #define WEBCRYPTO_KEY_FORMAT_SPKI   "spki"
 #define WEBCRYPTO_KEY_FORMAT_JWK    "jwk"
 
 // WebCrypto key types
@@ -96,16 +97,24 @@
 // Define an unknown mechanism type
 #define UNKNOWN_CK_MECHANISM        CKM_VENDOR_DEFINED+1
 
 // python security/pkix/tools/DottedOIDToCode.py id-ecDH 1.3.132.112
 static const uint8_t id_ecDH[] = { 0x2b, 0x81, 0x04, 0x70 };
 const SECItem SEC_OID_DATA_EC_DH = { siBuffer, (unsigned char*)id_ecDH,
                                      PR_ARRAY_SIZE(id_ecDH) };
 
+// python security/pkix/tools/DottedOIDToCode.py dhKeyAgreement 1.2.840.113549.1.3.1
+static const uint8_t dhKeyAgreement[] = {
+  0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x03, 0x01
+};
+const SECItem SEC_OID_DATA_DH_KEY_AGREEMENT = { siBuffer,
+                                                (unsigned char*)dhKeyAgreement,
+                                                PR_ARRAY_SIZE(dhKeyAgreement) };
+
 namespace mozilla {
 namespace dom {
 
 // Helper functions for structured cloning
 inline bool
 ReadString(JSStructuredCloneReader* aReader, nsString& aString)
 {
   bool read;
@@ -186,16 +195,18 @@ MapAlgorithmNameToMechanism(const nsStri
   } else if (aName.EqualsLiteral(WEBCRYPTO_ALG_PBKDF2)) {
     mechanism = CKM_PKCS5_PBKD2;
   } else if (aName.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1)) {
     mechanism = CKM_RSA_PKCS;
   } else if (aName.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP)) {
     mechanism = CKM_RSA_PKCS_OAEP;
   } else if (aName.EqualsLiteral(WEBCRYPTO_ALG_ECDH)) {
     mechanism = CKM_ECDH1_DERIVE;
+  } else if (aName.EqualsLiteral(WEBCRYPTO_ALG_DH)) {
+    mechanism = CKM_DH_PKCS_DERIVE;
   }
 
   return mechanism;
 }
 
 #define NORMALIZED_EQUALS(aTest, aConst) \
         nsContentUtils::EqualsIgnoreASCIICase(aTest, NS_LITERAL_STRING(aConst))
 
@@ -226,16 +237,18 @@ NormalizeToken(const nsString& aName, ns
   } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_RSASSA_PKCS1)) {
     aDest.AssignLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1);
   } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_RSA_OAEP)) {
     aDest.AssignLiteral(WEBCRYPTO_ALG_RSA_OAEP);
   } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_ECDH)) {
     aDest.AssignLiteral(WEBCRYPTO_ALG_ECDH);
   } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_ECDSA)) {
     aDest.AssignLiteral(WEBCRYPTO_ALG_ECDSA);
+  } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_DH)) {
+    aDest.AssignLiteral(WEBCRYPTO_ALG_DH);
   // Named curve values
   } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_NAMED_CURVE_P256)) {
     aDest.AssignLiteral(WEBCRYPTO_NAMED_CURVE_P256);
   } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_NAMED_CURVE_P384)) {
     aDest.AssignLiteral(WEBCRYPTO_NAMED_CURVE_P384);
   } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_NAMED_CURVE_P521)) {
     aDest.AssignLiteral(WEBCRYPTO_NAMED_CURVE_P521);
   } else {
--- a/dom/crypto/WebCryptoTask.cpp
+++ b/dom/crypto/WebCryptoTask.cpp
@@ -75,19 +75,18 @@ enum TelemetryAlgorithm {
 // OOM-safe CryptoBuffer initialization, suitable for constructors
 #define ATTEMPT_BUFFER_INIT(dst, src) \
   if (!dst.Assign(src)) { \
     mEarlyRv = NS_ERROR_DOM_UNKNOWN_ERR; \
     return; \
   }
 
 // OOM-safe CryptoBuffer-to-SECItem copy, suitable for DoCrypto
-#define ATTEMPT_BUFFER_TO_SECITEM(dst, src) \
-  dst = src.ToSECItem(); \
-  if (!dst) { \
+#define ATTEMPT_BUFFER_TO_SECITEM(arena, dst, src) \
+  if (!src.ToSECItem(arena, dst)) { \
     return NS_ERROR_DOM_UNKNOWN_ERR; \
   }
 
 // OOM-safe CryptoBuffer copy, suitable for DoCrypto
 #define ATTEMPT_BUFFER_ASSIGN(dst, src) \
   if (!dst.Assign(src)) { \
     return NS_ERROR_DOM_UNKNOWN_ERR; \
   }
@@ -506,25 +505,28 @@ private:
   virtual nsresult DoCrypto() MOZ_OVERRIDE
   {
     nsresult rv;
 
     if (!mDataIsSet) {
       return NS_ERROR_DOM_OPERATION_ERR;
     }
 
+    ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
+    if (!arena) {
+      return NS_ERROR_DOM_OPERATION_ERR;
+    }
+
     // Construct the parameters object depending on algorithm
-    SECItem param;
-    ScopedSECItem cbcParam;
+    SECItem param = { siBuffer, nullptr, 0 };
     CK_AES_CTR_PARAMS ctrParams;
     CK_GCM_PARAMS gcmParams;
     switch (mMechanism) {
       case CKM_AES_CBC_PAD:
-        ATTEMPT_BUFFER_TO_SECITEM(cbcParam, mIv);
-        param = *cbcParam;
+        ATTEMPT_BUFFER_TO_SECITEM(arena, &param, mIv);
         break;
       case CKM_AES_CTR:
         ctrParams.ulCounterBits = mCounterLength;
         MOZ_ASSERT(mIv.Length() == 16);
         memcpy(&ctrParams.cb, mIv.Elements(), 16);
         param.type = siBuffer;
         param.data = (unsigned char*) &ctrParams;
         param.len  = sizeof(ctrParams);
@@ -539,22 +541,22 @@ private:
         param.data = (unsigned char*) &gcmParams;
         param.len  = sizeof(gcmParams);
         break;
       default:
         return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
     }
 
     // Import the key
-    ScopedSECItem keyItem;
-    ATTEMPT_BUFFER_TO_SECITEM(keyItem, mSymKey);
+    SECItem keyItem = { siBuffer, nullptr, 0 };
+    ATTEMPT_BUFFER_TO_SECITEM(arena, &keyItem, mSymKey);
     ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
     MOZ_ASSERT(slot.get());
     ScopedPK11SymKey symKey(PK11_ImportSymKey(slot, mMechanism, PK11_OriginUnwrap,
-                                              CKA_ENCRYPT, keyItem.get(), nullptr));
+                                              CKA_ENCRYPT, &keyItem, nullptr));
     if (!symKey) {
       return NS_ERROR_DOM_INVALID_ACCESS_ERR;
     }
 
     // Initialize the output buffer (enough space for padding / a full tag)
     uint32_t dataLen = mData.Length();
     uint32_t maxLen = dataLen + 16;
     if (!mResult.SetLength(maxLen)) {
@@ -641,40 +643,45 @@ private:
       return NS_ERROR_DOM_OPERATION_ERR;
     }
 
     // Check that the input is a multiple of 64 bits long
     if (mData.Length() == 0 || mData.Length() % 8 != 0) {
       return NS_ERROR_DOM_DATA_ERR;
     }
 
+    ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
+    if (!arena) {
+      return NS_ERROR_DOM_OPERATION_ERR;
+    }
+
     // Import the key
-    ScopedSECItem keyItem;
-    ATTEMPT_BUFFER_TO_SECITEM(keyItem, mSymKey);
+    SECItem keyItem = { siBuffer, nullptr, 0 };
+    ATTEMPT_BUFFER_TO_SECITEM(arena, &keyItem, mSymKey);
     ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
     MOZ_ASSERT(slot.get());
     ScopedPK11SymKey symKey(PK11_ImportSymKey(slot, mMechanism, PK11_OriginUnwrap,
-                                              CKA_WRAP, keyItem.get(), nullptr));
+                                              CKA_WRAP, &keyItem, nullptr));
     if (!symKey) {
       return NS_ERROR_DOM_INVALID_ACCESS_ERR;
     }
 
     // Import the data to a SECItem
-    ScopedSECItem dataItem;
-    ATTEMPT_BUFFER_TO_SECITEM(dataItem, mData);
+    SECItem dataItem = { siBuffer, nullptr, 0 };
+    ATTEMPT_BUFFER_TO_SECITEM(arena, &dataItem, mData);
 
     // Parameters for the fake keys
     CK_MECHANISM_TYPE fakeMechanism = CKM_SHA_1_HMAC;
     CK_ATTRIBUTE_TYPE fakeOperation = CKA_SIGN;
 
     if (mEncrypt) {
       // Import the data into a fake PK11SymKey structure
       ScopedPK11SymKey keyToWrap(PK11_ImportSymKey(slot, fakeMechanism,
                                                    PK11_OriginUnwrap, fakeOperation,
-                                                   dataItem.get(), nullptr));
+                                                   &dataItem, nullptr));
       if (!keyToWrap) {
         return NS_ERROR_DOM_OPERATION_ERR;
       }
 
       // Encrypt and return the wrapped key
       // AES-KW encryption results in a wrapped key 64 bits longer
       if (!mResult.SetLength(mData.Length() + 8)) {
         return NS_ERROR_DOM_OPERATION_ERR;
@@ -684,17 +691,17 @@ private:
       rv = MapSECStatus(PK11_WrapSymKey(mMechanism, nullptr, symKey.get(),
                                         keyToWrap.get(), &resultItem));
       NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_OPERATION_ERR);
     } else {
       // Decrypt the ciphertext into a temporary PK11SymKey
       // Unwrapped key should be 64 bits shorter
       int keySize = mData.Length() - 8;
       ScopedPK11SymKey unwrappedKey(PK11_UnwrapSymKey(symKey, mMechanism, nullptr,
-                                                 dataItem.get(), fakeMechanism,
+                                                 &dataItem, fakeMechanism,
                                                  fakeOperation, keySize));
       if (!unwrappedKey) {
         return NS_ERROR_DOM_OPERATION_ERR;
       }
 
       // Export the key to get the cleartext
       rv = MapSECStatus(PK11_ExtractKeyValue(unwrappedKey));
       if (NS_FAILED(rv)) {
@@ -896,25 +903,30 @@ private:
   bool mSign;
 
   virtual nsresult DoCrypto() MOZ_OVERRIDE
   {
     // Initialize the output buffer
     if (!mResult.SetLength(HASH_LENGTH_MAX)) {
       return NS_ERROR_DOM_UNKNOWN_ERR;
     }
-    uint32_t outLen;
+
+    ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
+    if (!arena) {
+      return NS_ERROR_DOM_OPERATION_ERR;
+    }
 
     // Import the key
-    ScopedSECItem keyItem;
-    ATTEMPT_BUFFER_TO_SECITEM(keyItem, mSymKey);
+    uint32_t outLen;
+    SECItem keyItem = { siBuffer, nullptr, 0 };
+    ATTEMPT_BUFFER_TO_SECITEM(arena, &keyItem, mSymKey);
     ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
     MOZ_ASSERT(slot.get());
     ScopedPK11SymKey symKey(PK11_ImportSymKey(slot, mMechanism, PK11_OriginUnwrap,
-                                              CKA_SIGN, keyItem.get(), nullptr));
+                                              CKA_SIGN, &keyItem, nullptr));
     if (!symKey) {
       return NS_ERROR_DOM_INVALID_ACCESS_ERR;
     }
 
     // Compute the MAC
     SECItem param = { siBuffer, nullptr, 0 };
     ScopedPK11Context ctx(PK11_CreateContextBySymKey(mMechanism, CKA_SIGN,
                                                      symKey.get(), &param));
@@ -1064,17 +1076,17 @@ private:
   bool mSign;
   bool mVerified;
   bool mEcdsa;
 
   virtual nsresult DoCrypto() MOZ_OVERRIDE
   {
     nsresult rv;
     if (mSign) {
-      ScopedSECItem signature((SECItem*) PORT_Alloc(sizeof(SECItem)));
+      ScopedSECItem signature(::SECITEM_AllocItem(nullptr, nullptr, 0));
       ScopedSGNContext ctx(SGN_NewContext(mOidTag, mPrivKey));
       if (!signature.get() || !ctx.get()) {
         return NS_ERROR_DOM_OPERATION_ERR;
       }
 
       rv = MapSECStatus(SEC_SignData(signature, mData.Elements(),
                                      mData.Length(), mPrivKey, mOidTag));
 
@@ -1088,37 +1100,33 @@ private:
         }
 
         ATTEMPT_BUFFER_ASSIGN(mSignature, rawSignature);
       } else {
         ATTEMPT_BUFFER_ASSIGN(mSignature, signature);
       }
 
     } else {
-      ScopedSECItem signature;
+      ScopedSECItem signature(::SECITEM_AllocItem(nullptr, nullptr, 0));
+      if (!signature.get()) {
+        return NS_ERROR_DOM_UNKNOWN_ERR;
+      }
 
       if (mEcdsa) {
         // DER-encode the signature
-        ScopedSECItem rawSignature(mSignature.ToSECItem());
-        if (!rawSignature.get()) {
+        ScopedSECItem rawSignature(::SECITEM_AllocItem(nullptr, nullptr, 0));
+        if (!rawSignature || !mSignature.ToSECItem(nullptr, rawSignature)) {
           return NS_ERROR_DOM_UNKNOWN_ERR;
         }
 
-        signature = (SECItem*) PORT_Alloc(sizeof(SECItem));
-        if (!signature.get()) {
-          return NS_ERROR_DOM_UNKNOWN_ERR;
-        }
         rv = MapSECStatus(DSAU_EncodeDerSigWithLen(signature, rawSignature,
                                                    rawSignature->len));
         NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_OPERATION_ERR);
-      } else {
-        signature = mSignature.ToSECItem();
-        if (!signature) {
-          return NS_ERROR_DOM_UNKNOWN_ERR;
-        }
+      } else if (!mSignature.ToSECItem(nullptr, signature)) {
+        return NS_ERROR_DOM_UNKNOWN_ERR;
       }
 
       rv = MapSECStatus(VFY_VerifyData(mData.Elements(), mData.Length(),
                                        mPubKey, signature, mOidTag, nullptr));
       mVerified = NS_SUCCEEDED(rv);
     }
 
     return NS_OK;
@@ -1741,16 +1749,113 @@ private:
     if (mDataIsJwk && !JwkCompatible(mJwk, mKey)) {
       return NS_ERROR_DOM_DATA_ERR;
     }
 
     return NS_OK;
   }
 };
 
+class ImportDhKeyTask : public ImportKeyTask
+{
+public:
+  ImportDhKeyTask(JSContext* aCx, const nsAString& aFormat,
+                  const ObjectOrString& aAlgorithm, bool aExtractable,
+                  const Sequence<nsString>& aKeyUsages)
+  {
+    Init(aCx, aFormat, aAlgorithm, aExtractable, aKeyUsages);
+  }
+
+  ImportDhKeyTask(JSContext* aCx, const nsAString& aFormat,
+                  JS::Handle<JSObject*> aKeyData,
+                  const ObjectOrString& aAlgorithm, bool aExtractable,
+                  const Sequence<nsString>& aKeyUsages)
+  {
+    Init(aCx, aFormat, aAlgorithm, aExtractable, aKeyUsages);
+    if (NS_SUCCEEDED(mEarlyRv)) {
+      SetKeyData(aCx, aKeyData);
+    }
+  }
+
+  void Init(JSContext* aCx, const nsAString& aFormat,
+            const ObjectOrString& aAlgorithm, bool aExtractable,
+            const Sequence<nsString>& aKeyUsages)
+  {
+    ImportKeyTask::Init(aCx, aFormat, aAlgorithm, aExtractable, aKeyUsages);
+    if (NS_FAILED(mEarlyRv)) {
+      return;
+    }
+
+    if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_RAW)) {
+      RootedDictionary<DhImportKeyParams> params(aCx);
+      mEarlyRv = Coerce(aCx, params, aAlgorithm);
+      if (NS_FAILED(mEarlyRv)) {
+        mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
+        return;
+      }
+
+      CryptoBuffer prime;
+      ATTEMPT_BUFFER_INIT(mPrime, params.mPrime);
+
+      CryptoBuffer generator;
+      ATTEMPT_BUFFER_INIT(mGenerator, params.mGenerator);
+    }
+  }
+
+private:
+  CryptoBuffer mPrime;
+  CryptoBuffer mGenerator;
+
+  virtual nsresult DoCrypto() MOZ_OVERRIDE
+  {
+    // Import the key data itself
+    ScopedSECKEYPublicKey pubKey;
+
+    nsNSSShutDownPreventionLock locker;
+    if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_RAW) ||
+        mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_SPKI)) {
+      // Public key import
+      if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_RAW)) {
+        pubKey = CryptoKey::PublicDhKeyFromRaw(mKeyData, mPrime, mGenerator, locker);
+      } else if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_SPKI)) {
+        pubKey = CryptoKey::PublicKeyFromSpki(mKeyData, locker);
+      } else {
+        MOZ_ASSERT(false);
+      }
+
+      if (!pubKey) {
+        return NS_ERROR_DOM_DATA_ERR;
+      }
+
+      if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_SPKI)) {
+        ATTEMPT_BUFFER_ASSIGN(mPrime, &pubKey->u.dh.prime);
+        ATTEMPT_BUFFER_ASSIGN(mGenerator, &pubKey->u.dh.base);
+      }
+
+      mKey->SetPublicKey(pubKey.get());
+      mKey->SetType(CryptoKey::PUBLIC);
+    } else {
+      return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
+    }
+
+    return NS_OK;
+  }
+
+  virtual nsresult AfterCrypto() MOZ_OVERRIDE
+  {
+    // Check permissions for the requested operation
+    if (mKey->HasUsageOtherThan(CryptoKey::DERIVEBITS | CryptoKey::DERIVEKEY)) {
+      return NS_ERROR_DOM_DATA_ERR;
+    }
+
+    mKey->Algorithm().MakeDh(mAlgName, mPrime, mGenerator);
+    return NS_OK;
+  }
+};
+
 class ExportKeyTask : public WebCryptoTask
 {
 public:
   ExportKeyTask(const nsAString& aFormat, CryptoKey& aKey)
     : mFormat(aFormat)
     , mSymKey(aKey.GetSymKey())
     , mPrivateKey(aKey.GetPrivateKey())
     , mPublicKey(aKey.GetPublicKey())
@@ -1781,16 +1886,24 @@ private:
     mPublicKey.dispose();
   }
 
   virtual nsresult DoCrypto() MOZ_OVERRIDE
   {
     nsNSSShutDownPreventionLock locker;
 
     if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_RAW)) {
+      if (mPublicKey && mPublicKey->keyType == dhKey) {
+        nsresult rv = CryptoKey::PublicDhKeyToRaw(mPublicKey, mResult, locker);
+        if (NS_FAILED(rv)) {
+          return NS_ERROR_DOM_OPERATION_ERR;
+        }
+        return NS_OK;
+      }
+
       mResult = mSymKey;
       if (mResult.Length() == 0) {
         return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
       }
 
       return NS_OK;
     } else if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_PKCS8)) {
       if (!mPrivateKey) {
@@ -2003,16 +2116,22 @@ public:
       const Sequence<nsString>& aKeyUsages)
   {
     nsIGlobalObject* global = xpc::NativeGlobal(JS::CurrentGlobalOrNull(aCx));
     if (!global) {
       mEarlyRv = NS_ERROR_DOM_UNKNOWN_ERR;
       return;
     }
 
+    mArena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+    if (!mArena) {
+      mEarlyRv = NS_ERROR_DOM_UNKNOWN_ERR;
+      return;
+    }
+
     // Create an empty key and set easy attributes
     mKeyPair.mPrivateKey = new CryptoKey(global);
     mKeyPair.mPublicKey  = new CryptoKey(global);
 
     // Extract algorithm name
     nsString algName;
     mEarlyRv = GetAlgorithmName(aCx, aAlgorithm, algName);
     if (NS_FAILED(mEarlyRv)) {
@@ -2073,30 +2192,56 @@ public:
         mEarlyRv = NS_ERROR_DOM_NOT_SUPPORTED_ERR;
         return;
       }
 
       // Create algorithm.
       mKeyPair.mPublicKey.get()->Algorithm().MakeEc(algName, mNamedCurve);
       mKeyPair.mPrivateKey.get()->Algorithm().MakeEc(algName, mNamedCurve);
       mMechanism = CKM_EC_KEY_PAIR_GEN;
+    } else if (algName.EqualsLiteral(WEBCRYPTO_ALG_DH)) {
+      RootedDictionary<DhKeyGenParams> params(aCx);
+      mEarlyRv = Coerce(aCx, params, aAlgorithm);
+      if (NS_FAILED(mEarlyRv)) {
+        mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
+        return;
+      }
+
+      CryptoBuffer prime;
+      ATTEMPT_BUFFER_INIT(prime, params.mPrime);
+
+      CryptoBuffer generator;
+      ATTEMPT_BUFFER_INIT(generator, params.mGenerator);
+
+      // Set up params.
+      if (!prime.ToSECItem(mArena, &mDhParams.prime) ||
+          !generator.ToSECItem(mArena, &mDhParams.base)) {
+        mEarlyRv = NS_ERROR_DOM_UNKNOWN_ERR;
+        return;
+      }
+
+      // Create algorithm.
+      mKeyPair.mPublicKey.get()->Algorithm().MakeDh(algName, prime, generator);
+      mKeyPair.mPrivateKey.get()->Algorithm().MakeDh(algName, prime, generator);
+      mMechanism = CKM_DH_PKCS_KEY_PAIR_GEN;
     } else {
       mEarlyRv = NS_ERROR_DOM_NOT_SUPPORTED_ERR;
       return;
     }
 
     // Set key usages.
     if (algName.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1) ||
         algName.EqualsLiteral(WEBCRYPTO_ALG_ECDSA)) {
       privateAllowedUsages = CryptoKey::SIGN;
       publicAllowedUsages = CryptoKey::VERIFY;
     } else if (algName.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP)) {
       privateAllowedUsages = CryptoKey::DECRYPT | CryptoKey::UNWRAPKEY;
       publicAllowedUsages = CryptoKey::ENCRYPT | CryptoKey::WRAPKEY;
-    } else if (algName.EqualsLiteral(WEBCRYPTO_ALG_ECDH)) {
+    } else if (algName.EqualsLiteral(WEBCRYPTO_ALG_ECDH) ||
+               algName.EqualsLiteral(WEBCRYPTO_ALG_DH)) {
       privateAllowedUsages = CryptoKey::DERIVEKEY | CryptoKey::DERIVEBITS;
       publicAllowedUsages = 0;
     }
 
     mKeyPair.mPrivateKey.get()->SetExtractable(aExtractable);
     mKeyPair.mPrivateKey.get()->SetType(CryptoKey::PRIVATE);
 
     mKeyPair.mPublicKey.get()->SetExtractable(true);
@@ -2122,48 +2267,46 @@ public:
     if (!mKeyPair.mPublicKey.get()->HasAnyUsage() &&
         !mKeyPair.mPrivateKey.get()->HasAnyUsage()) {
       mEarlyRv = NS_ERROR_DOM_DATA_ERR;
       return;
     }
   }
 
 private:
+  ScopedPLArenaPool mArena;
   CryptoKeyPair mKeyPair;
   CK_MECHANISM_TYPE mMechanism;
   PK11RSAGenParams mRsaParams;
+  SECKEYDHParams mDhParams;
   ScopedSECKEYPublicKey mPublicKey;
   ScopedSECKEYPrivateKey mPrivateKey;
   nsString mNamedCurve;
 
   virtual void ReleaseNSSResources() MOZ_OVERRIDE
   {
     mPublicKey.dispose();
     mPrivateKey.dispose();
   }
 
   virtual nsresult DoCrypto() MOZ_OVERRIDE
   {
     ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
     MOZ_ASSERT(slot.get());
 
     void* param;
-    ScopedPLArenaPool arena;
-
     switch (mMechanism) {
       case CKM_RSA_PKCS_KEY_PAIR_GEN:
         param = &mRsaParams;
         break;
+      case CKM_DH_PKCS_KEY_PAIR_GEN:
+        param = &mDhParams;
+        break;
       case CKM_EC_KEY_PAIR_GEN: {
-        arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
-        if (!arena) {
-          return NS_ERROR_DOM_UNKNOWN_ERR;
-        }
-
-        param = CreateECParamsForCurve(mNamedCurve, arena.get());
+        param = CreateECParamsForCurve(mNamedCurve, mArena);
         if (!param) {
           return NS_ERROR_DOM_UNKNOWN_ERR;
         }
         break;
       }
       default:
         return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
     }
@@ -2261,40 +2404,45 @@ private:
   size_t mLength;
   size_t mIterations;
   CryptoBuffer mSalt;
   CryptoBuffer mSymKey;
   SECOidTag mHashOidTag;
 
   virtual nsresult DoCrypto() MOZ_OVERRIDE
   {
-    ScopedSECItem salt;
-    ATTEMPT_BUFFER_TO_SECITEM(salt, mSalt);
+    ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
+    if (!arena) {
+      return NS_ERROR_DOM_OPERATION_ERR;
+    }
+
+    SECItem salt = { siBuffer, nullptr, 0 };
+    ATTEMPT_BUFFER_TO_SECITEM(arena, &salt, mSalt);
 
     // Always pass in cipherAlg=SEC_OID_HMAC_SHA1 (i.e. PBMAC1) as this
     // parameter is unused for key generation. It is currently only used
     // for PBKDF2 authentication or key (un)wrapping when specifying an
     // encryption algorithm (PBES2).
     ScopedSECAlgorithmID alg_id(PK11_CreatePBEV2AlgorithmID(
       SEC_OID_PKCS5_PBKDF2, SEC_OID_HMAC_SHA1, mHashOidTag,
-      mLength, mIterations, salt));
+      mLength, mIterations, &salt));
 
     if (!alg_id.get()) {
       return NS_ERROR_DOM_OPERATION_ERR;
     }
 
     ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
     if (!slot.get()) {
       return NS_ERROR_DOM_OPERATION_ERR;
     }
 
-    ScopedSECItem keyItem;
-    ATTEMPT_BUFFER_TO_SECITEM(keyItem, mSymKey);
-
-    ScopedPK11SymKey symKey(PK11_PBEKeyGen(slot, alg_id, keyItem, false, nullptr));
+    SECItem keyItem = { siBuffer, nullptr, 0 };
+    ATTEMPT_BUFFER_TO_SECITEM(arena, &keyItem, mSymKey);
+
+    ScopedPK11SymKey symKey(PK11_PBEKeyGen(slot, alg_id, &keyItem, false, nullptr));
     if (!symKey.get()) {
       return NS_ERROR_DOM_OPERATION_ERR;
     }
 
     nsresult rv = MapSECStatus(PK11_ExtractKeyValue(symKey));
     if (NS_FAILED(rv)) {
       return NS_ERROR_DOM_OPERATION_ERR;
     }
@@ -2416,19 +2564,120 @@ public:
 
 private:
   size_t mLength;
   ScopedSECKEYPrivateKey mPrivKey;
   ScopedSECKEYPublicKey mPubKey;
 
   virtual nsresult DoCrypto() MOZ_OVERRIDE
   {
+    // CKM_SHA512_HMAC and CKA_SIGN are key type and usage attributes of the
+    // derived symmetric key and don't matter because we ignore them anyway.
     ScopedPK11SymKey symKey(PK11_PubDeriveWithKDF(
       mPrivKey, mPubKey, PR_FALSE, nullptr, nullptr, CKM_ECDH1_DERIVE,
-      CKM_CONCATENATE_DATA_AND_BASE, CKA_DERIVE, 0, CKD_NULL, nullptr, nullptr));
+      CKM_SHA512_HMAC, CKA_SIGN, 0, CKD_NULL, nullptr, nullptr));
+
+    if (!symKey.get()) {
+      return NS_ERROR_DOM_OPERATION_ERR;
+    }
+
+    nsresult rv = MapSECStatus(PK11_ExtractKeyValue(symKey));
+    if (NS_FAILED(rv)) {
+      return NS_ERROR_DOM_OPERATION_ERR;
+    }
+
+    // This doesn't leak, because the SECItem* returned by PK11_GetKeyData
+    // just refers to a buffer managed by symKey. The assignment copies the
+    // data, so mResult manages one copy, while symKey manages another.
+    ATTEMPT_BUFFER_ASSIGN(mResult, PK11_GetKeyData(symKey));
+
+    if (mLength > mResult.Length()) {
+      return NS_ERROR_DOM_DATA_ERR;
+    }
+
+    if (!mResult.SetLength(mLength)) {
+      return NS_ERROR_DOM_UNKNOWN_ERR;
+    }
+
+    return NS_OK;
+  }
+};
+
+class DeriveDhBitsTask : public ReturnArrayBufferViewTask
+{
+public:
+  DeriveDhBitsTask(JSContext* aCx,
+      const ObjectOrString& aAlgorithm, CryptoKey& aKey, uint32_t aLength)
+    : mLength(aLength),
+      mPrivKey(aKey.GetPrivateKey())
+  {
+    Init(aCx, aAlgorithm, aKey);
+  }
+
+  DeriveDhBitsTask(JSContext* aCx, const ObjectOrString& aAlgorithm,
+                   CryptoKey& aKey, const ObjectOrString& aTargetAlgorithm)
+    : mPrivKey(aKey.GetPrivateKey())
+  {
+    mEarlyRv = GetKeyLengthForAlgorithm(aCx, aTargetAlgorithm, mLength);
+    if (NS_SUCCEEDED(mEarlyRv)) {
+      Init(aCx, aAlgorithm, aKey);
+    }
+  }
+
+  void Init(JSContext* aCx, const ObjectOrString& aAlgorithm, CryptoKey& aKey)
+  {
+    CHECK_KEY_ALGORITHM(aKey.Algorithm(), WEBCRYPTO_ALG_DH);
+
+    // Check that we have a private key.
+    if (!mPrivKey) {
+      mEarlyRv = NS_ERROR_DOM_INVALID_ACCESS_ERR;
+      return;
+    }
+
+    mLength = mLength >> 3; // bits to bytes
+
+    // Retrieve the peer's public key.
+    RootedDictionary<DhKeyDeriveParams> params(aCx);
+    mEarlyRv = Coerce(aCx, params, aAlgorithm);
+    if (NS_FAILED(mEarlyRv)) {
+      mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
+      return;
+    }
+
+    CryptoKey* publicKey = params.mPublic;
+    mPubKey = publicKey->GetPublicKey();
+    if (!mPubKey) {
+      mEarlyRv = NS_ERROR_DOM_INVALID_ACCESS_ERR;
+      return;
+    }
+
+    KeyAlgorithmProxy alg1 = publicKey->Algorithm();
+    CHECK_KEY_ALGORITHM(alg1, WEBCRYPTO_ALG_DH);
+
+    // Both keys must use the same prime and generator.
+    KeyAlgorithmProxy alg2 = aKey.Algorithm();
+    if (alg1.mDh.mPrime != alg2.mDh.mPrime ||
+        alg1.mDh.mGenerator != alg2.mDh.mGenerator) {
+      mEarlyRv = NS_ERROR_DOM_DATA_ERR;
+      return;
+    }
+  }
+
+private:
+  size_t mLength;
+  ScopedSECKEYPrivateKey mPrivKey;
+  ScopedSECKEYPublicKey mPubKey;
+
+  virtual nsresult DoCrypto() MOZ_OVERRIDE
+  {
+    // CKM_SHA512_HMAC and CKA_SIGN are key type and usage attributes of the
+    // derived symmetric key and don't matter because we ignore them anyway.
+    ScopedPK11SymKey symKey(PK11_PubDeriveWithKDF(
+      mPrivKey, mPubKey, PR_FALSE, nullptr, nullptr, CKM_DH_PKCS_DERIVE,
+      CKM_SHA512_HMAC, CKA_SIGN, 0, CKD_NULL, nullptr, nullptr));
 
     if (!symKey.get()) {
       return NS_ERROR_DOM_OPERATION_ERR;
     }
 
     nsresult rv = MapSECStatus(PK11_ExtractKeyValue(symKey));
     if (NS_FAILED(rv)) {
       return NS_ERROR_DOM_OPERATION_ERR;
@@ -2689,16 +2938,19 @@ WebCryptoTask::CreateImportKeyTask(JSCon
   } else if (algName.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1) ||
              algName.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP)) {
     return new ImportRsaKeyTask(aCx, aFormat, aKeyData, aAlgorithm,
                                 aExtractable, aKeyUsages);
   } else if (algName.EqualsLiteral(WEBCRYPTO_ALG_ECDH) ||
              algName.EqualsLiteral(WEBCRYPTO_ALG_ECDSA)) {
     return new ImportEcKeyTask(aCx, aFormat, aKeyData, aAlgorithm,
                                aExtractable, aKeyUsages);
+  } else if (algName.EqualsLiteral(WEBCRYPTO_ALG_DH)) {
+    return new ImportDhKeyTask(aCx, aFormat, aKeyData, aAlgorithm,
+                               aExtractable, aKeyUsages);
   } else {
     return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
   }
 }
 
 WebCryptoTask*
 WebCryptoTask::CreateExportKeyTask(const nsAString& aFormat,
                                    CryptoKey& aKey)
@@ -2725,17 +2977,18 @@ WebCryptoTask::CreateExportKeyTask(const
   if (algName.EqualsLiteral(WEBCRYPTO_ALG_AES_CBC) ||
       algName.EqualsLiteral(WEBCRYPTO_ALG_AES_CTR) ||
       algName.EqualsLiteral(WEBCRYPTO_ALG_AES_GCM) ||
       algName.EqualsLiteral(WEBCRYPTO_ALG_AES_KW) ||
       algName.EqualsLiteral(WEBCRYPTO_ALG_PBKDF2) ||
       algName.EqualsLiteral(WEBCRYPTO_ALG_HMAC) ||
       algName.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1) ||
       algName.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP) ||
-      algName.EqualsLiteral(WEBCRYPTO_ALG_ECDH)) {
+      algName.EqualsLiteral(WEBCRYPTO_ALG_ECDH) ||
+      algName.EqualsLiteral(WEBCRYPTO_ALG_DH)) {
     return new ExportKeyTask(aFormat, aKey);
   }
 
   return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
 }
 
 WebCryptoTask*
 WebCryptoTask::CreateGenerateKeyTask(JSContext* aCx,
@@ -2763,17 +3016,18 @@ WebCryptoTask::CreateGenerateKeyTask(JSC
       algName.EqualsASCII(WEBCRYPTO_ALG_AES_CTR) ||
       algName.EqualsASCII(WEBCRYPTO_ALG_AES_GCM) ||
       algName.EqualsASCII(WEBCRYPTO_ALG_AES_KW) ||
       algName.EqualsASCII(WEBCRYPTO_ALG_HMAC)) {
     return new GenerateSymmetricKeyTask(aCx, aAlgorithm, aExtractable, aKeyUsages);
   } else if (algName.EqualsASCII(WEBCRYPTO_ALG_RSASSA_PKCS1) ||
              algName.EqualsASCII(WEBCRYPTO_ALG_RSA_OAEP) ||
              algName.EqualsASCII(WEBCRYPTO_ALG_ECDH) ||
-             algName.EqualsASCII(WEBCRYPTO_ALG_ECDSA)) {
+             algName.EqualsASCII(WEBCRYPTO_ALG_ECDSA) ||
+             algName.EqualsASCII(WEBCRYPTO_ALG_DH)) {
     return new GenerateAsymmetricKeyTask(aCx, aAlgorithm, aExtractable, aKeyUsages);
   } else {
     return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
   }
 }
 
 WebCryptoTask*
 WebCryptoTask::CreateDeriveKeyTask(JSContext* aCx,
@@ -2838,16 +3092,20 @@ WebCryptoTask::CreateDeriveBitsTask(JSCo
   if (algName.EqualsASCII(WEBCRYPTO_ALG_PBKDF2)) {
     return new DerivePbkdfBitsTask(aCx, aAlgorithm, aKey, aLength);
   }
 
   if (algName.EqualsASCII(WEBCRYPTO_ALG_ECDH)) {
     return new DeriveEcdhBitsTask(aCx, aAlgorithm, aKey, aLength);
   }
 
+  if (algName.EqualsASCII(WEBCRYPTO_ALG_DH)) {
+    return new DeriveDhBitsTask(aCx, aAlgorithm, aKey, aLength);
+  }
+
   return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
 }
 
 WebCryptoTask*
 WebCryptoTask::CreateWrapKeyTask(JSContext* aCx,
                                  const nsAString& aFormat,
                                  CryptoKey& aKey,
                                  CryptoKey& aWrappingKey,
--- a/dom/crypto/test/mochitest.ini
+++ b/dom/crypto/test/mochitest.ini
@@ -3,12 +3,13 @@
 skip-if = (buildapp == 'b2g')
 support-files =
   test-array.js
   test-vectors.js
   test_WebCrypto.css
   util.js
 
 [test_WebCrypto.html]
+[test_WebCrypto_DH.html]
 [test_WebCrypto_ECDH.html]
 [test_WebCrypto_JWK.html]
 [test_WebCrypto_PBKDF2.html]
 [test_WebCrypto_RSA_OAEP.html]
--- a/dom/crypto/test/test-vectors.js
+++ b/dom/crypto/test/test-vectors.js
@@ -652,10 +652,68 @@ tv = {
     pub_jwk: {
       "kty": "EC",
       "crv": "P-521",
       "x": "BhOH_WuVkU6IX5Eu37tfsnRlUCfyFsQJHKg-GTNnQP2B" +
            "rt_gR_UbQr32gWESEBPg1VsRehTkMD-SbI3rt3p_2q0B",
       "y": "AUNouOdGgHsraPNhXNeNdhpGTd15GPyN9R0iWWL98ePc" +
            "JD4mUQD/DsEzNZ4zLkTdSa/Y5fOP6GEzVzQy0zwC+goD"
     }
-  }
+  },
+
+  // RFC 2409 <http://tools.ietf.org/html/rfc2409#section-6.1>
+  dh: {
+    prime: util.hex2abv(
+      "ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74" +
+      "020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f1437" +
+      "4fe1356d6d51c245e485b576625e7ec6f44c42e9a63a3620ffffffffffffffff"
+    ),
+
+    prime2: util.hex2abv(
+      "ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74" +
+      "020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f1437" +
+      "4fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7ed" +
+      "ee386bfb5a899fa5ae9f24117c4b1fe649286651ece65381ffffffffffffffff"
+    ),
+  },
+
+  // KASValidityTest_FFCStatic_NOKC_ZZOnly_resp.fax [FA]
+  // <http://csrc.nist.gov/groups/STM/cavp/documents/keymgmt/kastestvectors.zip>
+  dh_nist: {
+    prime: util.hex2abv(
+      "8b79f180cbd3f282de92e8b8f2d092674ffda61f01ed961f8ef04a1b7a3709ff" +
+      "748c2abf6226cf0c4538e48838193da456e92ee530ef7aa703e741585e475b26" +
+      "cd64fa97819181cef27de2449cd385c49c9b030f89873b5b7eaf063a788f00db" +
+      "3cb670c73846bc4f76af062d672bde8f29806b81548411ab48b99aebfd9c2d09"
+    ),
+
+    gen: util.hex2abv(
+      "029843c81d0ea285c41a49b1a2f8e11a56a4b39040dfbc5ec040150c16f72f87" +
+      "4152f9c44c659d86f7717b2425b62597e9a453b13da327a31cde2cced6009152" +
+      "52d30262d1e54f4f864ace0e484f98abdbb37ebb0ba4106af5f0935b744677fa" +
+      "2f7f3826dcef3a1586956105ebea805d871f34c46c25bc30fc66b2db26cb0a93"
+    ),
+
+    raw: util.hex2abv(
+      "4fc9904887ac7fabff87f054003547c2d9458c1f6f584c140d7271f8b266bb39" +
+      "0af7e3f625a629bec9c6a057a4cbe1a556d5e3eb2ff1c6ff677a08b0c7c50911" +
+      "0b9e7c6dbc961ca4360362d3dbcffc5bf2bb7207e0a5922f77cf5464b316aa49" +
+      "fb62b338ebcdb30bf573d07b663bb7777b69d6317df0a4f636ba3d9acbf9e8ac"
+    ),
+
+    spki: util.hex2abv(
+      "308201a33082011806092a864886f70d01030130820109028181008b79f180cb" +
+      "d3f282de92e8b8f2d092674ffda61f01ed961f8ef04a1b7a3709ff748c2abf62" +
+      "26cf0c4538e48838193da456e92ee530ef7aa703e741585e475b26cd64fa9781" +
+      "9181cef27de2449cd385c49c9b030f89873b5b7eaf063a788f00db3cb670c738" +
+      "46bc4f76af062d672bde8f29806b81548411ab48b99aebfd9c2d090281800298" +
+      "43c81d0ea285c41a49b1a2f8e11a56a4b39040dfbc5ec040150c16f72f874152" +
+      "f9c44c659d86f7717b2425b62597e9a453b13da327a31cde2cced600915252d3" +
+      "0262d1e54f4f864ace0e484f98abdbb37ebb0ba4106af5f0935b744677fa2f7f" +
+      "3826dcef3a1586956105ebea805d871f34c46c25bc30fc66b2db26cb0a930000" +
+      "038184000281804fc9904887ac7fabff87f054003547c2d9458c1f6f584c140d" +
+      "7271f8b266bb390af7e3f625a629bec9c6a057a4cbe1a556d5e3eb2ff1c6ff67" +
+      "7a08b0c7c509110b9e7c6dbc961ca4360362d3dbcffc5bf2bb7207e0a5922f77" +
+      "cf5464b316aa49fb62b338ebcdb30bf573d07b663bb7777b69d6317df0a4f636" +
+      "ba3d9acbf9e8ac"
+    )
+  },
 }
new file mode 100644
--- /dev/null
+++ b/dom/crypto/test/test_WebCrypto_DH.html
@@ -0,0 +1,284 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+<title>WebCrypto Test Suite</title>
+<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
+<link rel="stylesheet" href="./test_WebCrypto.css"/>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+
+<!-- Utilities for manipulating ABVs -->
+<script src="util.js"></script>
+
+<!-- A simple wrapper around IndexedDB -->
+<script src="simpledb.js"></script>
+
+<!-- Test vectors drawn from the literature -->
+<script src="./test-vectors.js"></script>
+
+<!-- General testing framework -->
+<script src="./test-array.js"></script>
+
+<script>/*<![CDATA[*/
+"use strict";
+
+// -----------------------------------------------------------------------------
+TestArray.addTest(
+  "Generate a DH key",
+  function() {
+    var that = this;
+    var alg = {
+      name: "DH",
+      prime: tv.dh.prime,
+      generator: new Uint8Array([0x02])
+    };
+    crypto.subtle.generateKey(alg, false, ["deriveKey", "deriveBits"]).then(
+      complete(that, function(x) {
+        return exists(x.publicKey) &&
+               (x.publicKey.algorithm.name == alg.name) &&
+               util.memcmp(x.publicKey.algorithm.prime, alg.prime) &&
+               util.memcmp(x.publicKey.algorithm.generator, alg.generator) &&
+               (x.publicKey.type == "public") &&
+               x.publicKey.extractable &&
+               (x.publicKey.usages.length == 0) &&
+               exists(x.privateKey) &&
+               (x.privateKey.algorithm.name == alg.name) &&
+               util.memcmp(x.privateKey.algorithm.prime, alg.prime) &&
+               util.memcmp(x.privateKey.algorithm.generator, alg.generator) &&
+               (x.privateKey.type == "private") &&
+               !x.privateKey.extractable &&
+               (x.privateKey.usages.length == 2) &&
+               (x.privateKey.usages[0] == "deriveKey") &&
+               (x.privateKey.usages[1] == "deriveBits");
+      }),
+      error(that)
+    );
+  }
+);
+
+// -----------------------------------------------------------------------------
+TestArray.addTest(
+  "Derive bits from a DH key",
+  function() {
+    var that = this;
+    var alg = {
+      name: "DH",
+      prime: tv.dh.prime,
+      generator: new Uint8Array([0x02])
+    };
+
+    function doDerive(x) {
+      var alg = {
+        name: "DH",
+        public: x.publicKey
+      };
+      return crypto.subtle.deriveBits(alg, x.privateKey, 128);
+    }
+
+    crypto.subtle.generateKey(alg, false, ["deriveBits"])
+      .then(doDerive, error(that))
+      .then(complete(that, function (x) {
+        return x.byteLength == 16;
+      }), error(that));
+  }
+);
+
+// -----------------------------------------------------------------------------
+TestArray.addTest(
+  "Test that DH deriveBits() fails when the public key is not a DH key",
+  function() {
+    var that = this;
+    var pubKey, privKey;
+    function setPub(x) { pubKey = x.publicKey; }
+    function setPriv(x) { privKey = x.privateKey; }
+
+    function doGenerateDH() {
+      var alg = {
+        name: "DH",
+        prime: tv.dh.prime,
+        generator: new Uint8Array([0x02])
+      };
+      return crypto.subtle.generateKey(alg, false, ["deriveBits"]);
+    }
+
+    function doGenerateRSA() {
+      var alg = {
+        name: "RSA-OAEP",
+        hash: "SHA-256",
+        modulusLength: 2048,
+        publicExponent: new Uint8Array([0x01, 0x00, 0x01])
+      };
+      return crypto.subtle.generateKey(alg, false, ["encrypt"])
+    }
+
+    function doDerive() {
+      var alg = {name: "DH", public: pubKey};
+      return crypto.subtle.deriveBits(alg, privKey, 128);
+    }
+
+    doGenerateDH()
+      .then(setPriv, error(that))
+      .then(doGenerateRSA, error(that))
+      .then(setPub, error(that))
+      .then(doDerive, error(that))
+      .then(error(that), complete(that));
+  }
+);
+
+// -----------------------------------------------------------------------------
+TestArray.addTest(
+  "Test that DH deriveBits() fails when the given keys' primes or bases don't match",
+  function() {
+    var that = this;
+    var pubKey, privKey;
+    function setPub(x) { pubKey = x.publicKey; }
+    function setPriv(x) { privKey = x.privateKey; }
+
+    function doGenerateDH() {
+      var alg = {
+        name: "DH",
+        prime: tv.dh.prime,
+        generator: new Uint8Array([0x02])
+      };
+      return crypto.subtle.generateKey(alg, false, ["deriveBits"]);
+    }
+
+    function doGenerateDH2() {
+      var alg = {
+        name: "DH",
+        prime: tv.dh.prime2,
+        generator: new Uint8Array([0x02])
+      };
+      return crypto.subtle.generateKey(alg, false, ["deriveBits"]);
+    }
+
+    function doGenerateDH3() {
+      var alg = {
+        name: "DH",
+        prime: tv.dh.prime,
+        generator: new Uint8Array([0x03])
+      };
+      return crypto.subtle.generateKey(alg, false, ["deriveBits"]);
+    }
+
+    function doDerive() {
+      var alg = {name: "DH", public: pubKey};
+      return crypto.subtle.deriveBits(alg, privKey, 128);
+    }
+
+    doGenerateDH()
+      .then(setPriv, error(that))
+      .then(doGenerateDH2, error(that))
+      .then(setPub, error(that))
+      .then(doDerive, error(that))
+      .then(error(that), doGenerateDH3)
+      .then(setPub, error(that))
+      .then(doDerive, error(that))
+      .then(error(that), complete(that));
+  }
+);
+
+// -----------------------------------------------------------------------------
+TestArray.addTest(
+  "Raw import/export of a public DH key",
+  function () {
+    var that = this;
+    var alg = {
+      name: "DH",
+      prime: tv.dh_nist.prime,
+      generator: tv.dh_nist.gen
+    };
+
+    function doExport(x) {
+      return crypto.subtle.exportKey("raw", x);
+    }
+
+    crypto.subtle.importKey("raw", tv.dh_nist.raw, alg, true, ["deriveBits"])
+      .then(doExport)
+      .then(memcmp_complete(that, tv.dh_nist.raw), error(that));
+  }
+);
+
+// -----------------------------------------------------------------------------
+TestArray.addTest(
+  "Derive bits from an imported public and a generated private DH key",
+  function() {
+    var that = this;
+    var alg = {
+      name: "DH",
+      prime: tv.dh_nist.prime,
+      generator: tv.dh_nist.gen
+    };
+
+    var privKey;
+    function setPriv(x) { privKey = x.privateKey; }
+
+    function doImport() {
+      return crypto.subtle.importKey("raw", tv.dh_nist.raw, alg, true, ["deriveBits"]);
+    }
+
+    function doDerive(pubKey) {
+      var alg = {name: "DH", public: pubKey};
+      return crypto.subtle.deriveBits(alg, privKey, 128);
+    }
+
+    crypto.subtle.generateKey(alg, false, ["deriveBits"])
+      .then(setPriv, error(that))
+      .then(doImport, error(that))
+      .then(doDerive, error(that))
+      .then(complete(that, function (x) {
+        return x.byteLength == 16;
+      }), error(that));
+  }
+);
+
+// -----------------------------------------------------------------------------
+TestArray.addTest(
+  "SPKI import/export of a public DH key",
+  function() {
+    var that = this;
+
+    function doExport(x) {
+      return crypto.subtle.exportKey("spki", x);
+    }
+
+    crypto.subtle.importKey("spki", tv.dh_nist.spki, "DH", true, ["deriveBits"])
+      .then(doExport, error(that))
+      .then(memcmp_complete(that, tv.dh_nist.spki), error(that));
+  }
+);
+/*]]>*/</script>
+</head>
+
+<body>
+
+<div id="content">
+	<div id="head">
+		<b>Web</b>Crypto<br>
+	</div>
+
+    <div id="start" onclick="start();">RUN ALL</div>
+
+    <div id="resultDiv" class="content">
+    Summary:
+    <span class="pass"><span id="passN">0</span> passed, </span>
+    <span class="fail"><span id="failN">0</span> failed, </span>
+    <span class="pending"><span id="pendingN">0</span> pending.</span>
+    <br/>
+    <br/>
+
+    <table id="results">
+        <tr>
+            <th>Test</th>
+            <th>Result</th>
+            <th>Time</th>
+        </tr>
+    </table>
+
+    </div>
+
+    <div id="foot"></div>
+</div>
+
+</body>
+</html>
--- a/dom/events/AnimationEvent.h
+++ b/dom/events/AnimationEvent.h
@@ -28,17 +28,17 @@ public:
   NS_DECL_NSIDOMANIMATIONEVENT
 
   static already_AddRefed<AnimationEvent>
   Constructor(const GlobalObject& aGlobal,
               const nsAString& aType,
               const AnimationEventInit& aParam,
               ErrorResult& aRv);
 
-  virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE
+  virtual JSObject* WrapObjectInternal(JSContext* aCx) MOZ_OVERRIDE
   {
     return AnimationEventBinding::Wrap(aCx, this);
   }
 
   // xpidl implementation
   // GetAnimationName(nsAString& aAnimationName);
   // GetPseudoElement(nsAString& aPseudoElement);
 
--- a/dom/events/BeforeUnloadEvent.h
+++ b/dom/events/BeforeUnloadEvent.h
@@ -19,17 +19,17 @@ class BeforeUnloadEvent : public Event,
 public:
   BeforeUnloadEvent(EventTarget* aOwner,
                     nsPresContext* aPresContext,
                     WidgetEvent* aEvent)
     : Event(aOwner, aPresContext, aEvent)
   {
   }
 
-  virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE
+  virtual JSObject* WrapObjectInternal(JSContext* aCx) MOZ_OVERRIDE
   {
     return BeforeUnloadEventBinding::Wrap(aCx, this);
   }
 
   NS_DECL_ISUPPORTS_INHERITED
 
   // Forward to Event
   NS_FORWARD_TO_EVENT
--- a/dom/events/ClipboardEvent.h
+++ b/dom/events/ClipboardEvent.h
@@ -25,17 +25,17 @@ public:
 
   NS_DECL_ISUPPORTS_INHERITED
 
   NS_DECL_NSIDOMCLIPBOARDEVENT
 
   // Forward to base class
   NS_FORWARD_TO_EVENT
 
-  virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE
+  virtual JSObject* WrapObjectInternal(JSContext* aCx) MOZ_OVERRIDE
   {
     return ClipboardEventBinding::Wrap(aCx, this);
   }
 
   static already_AddRefed<ClipboardEvent>
   Constructor(const GlobalObject& aGlobal,
               const nsAString& aType,
               const ClipboardEventInit& aParam,
--- a/dom/events/CommandEvent.h
+++ b/dom/events/CommandEvent.h
@@ -24,17 +24,17 @@ public:
 
   NS_DECL_ISUPPORTS_INHERITED
 
   NS_DECL_NSIDOMCOMMANDEVENT
 
   // Forward to base class
   NS_FORWARD_TO_EVENT
 
-  virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE
+  virtual JSObject* WrapObjectInternal(JSContext* aCx) MOZ_OVERRIDE
   {
     return CommandEventBinding::Wrap(aCx, this);
   }
 
   void InitCommandEvent(const nsAString& aType,
                         bool aCanBubble,
                         bool aCancelable,
                         const nsAString& aCommand,
--- a/dom/events/CompositionEvent.h
+++ b/dom/events/CompositionEvent.h
@@ -22,17 +22,17 @@ public:
   CompositionEvent(EventTarget* aOwner,
                    nsPresContext* aPresContext,
                    WidgetCompositionEvent* aEvent);
 
   NS_DECL_ISUPPORTS_INHERITED
   NS_FORWARD_TO_UIEVENT
   NS_DECL_NSIDOMCOMPOSITIONEVENT
 
-  virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE
+  virtual JSObject* WrapObjectInternal(JSContext* aCx) MOZ_OVERRIDE
   {
     return CompositionEventBinding::Wrap(aCx, this);
   }
 
   void InitCompositionEvent(const nsAString& aType,
                             bool aCanBubble,
                             bool aCancelable,
                             nsIDOMWindow* aView,
--- a/dom/events/CustomEvent.cpp
+++ b/dom/events/CustomEvent.cpp
@@ -48,17 +48,17 @@ CustomEvent::Constructor(const GlobalObj
   bool trusted = e->Init(t);
   JS::Rooted<JS::Value> detail(aGlobal.Context(), aParam.mDetail);
   e->InitCustomEvent(aGlobal.Context(), aType, aParam.mBubbles, aParam.mCancelable, detail, aRv);
   e->SetTrusted(trusted);
   return e.forget();
 }
 
 JSObject*
-CustomEvent::WrapObject(JSContext* aCx)
+CustomEvent::WrapObjectInternal(JSContext* aCx)
 {
   return mozilla::dom::CustomEventBinding::Wrap(aCx, this);
 }
 
 NS_IMETHODIMP
 CustomEvent::InitCustomEvent(const nsAString& aType,
                              bool aCanBubble,
                              bool aCancelable,
--- a/dom/events/CustomEvent.h
+++ b/dom/events/CustomEvent.h
@@ -33,17 +33,17 @@ public:
 
   static already_AddRefed<CustomEvent>
   Constructor(const GlobalObject& aGlobal,
               const nsAString& aType,
               const CustomEventInit& aParam,
               ErrorResult& aRv);
 
   virtual JSObject*
-  WrapObject(JSContext* aCx) MOZ_OVERRIDE;
+  WrapObjectInternal(JSContext* aCx) MOZ_OVERRIDE;
 
   void
   GetDetail(JSContext* aCx,
             JS::MutableHandle<JS::Value> aRetval);
 
   void
   InitCustomEvent(JSContext* aCx,
                   const nsAString& aType,
--- a/dom/events/DataContainerEvent.h
+++ b/dom/events/DataContainerEvent.h
@@ -26,17 +26,17 @@ public:
 
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(DataContainerEvent, Event)
 
   NS_FORWARD_TO_EVENT
 
   NS_DECL_NSIDOMDATACONTAINEREVENT
 
   virtual JSObject*
-  WrapObject(JSContext* aCx) MOZ_OVERRIDE
+  WrapObjectInternal(JSContext* aCx) MOZ_OVERRIDE
   {
     return DataContainerEventBinding::Wrap(aCx, this);
   }
 
   already_AddRefed<nsIVariant> GetData(const nsAString& aKey)
   {
     nsCOMPtr<nsIVariant> val;
     GetData(aKey, getter_AddRefs(val));
--- a/dom/events/DeviceMotionEvent.h
+++ b/dom/events/DeviceMotionEvent.h
@@ -89,17 +89,17 @@ public:
 
   NS_DECL_ISUPPORTS_INHERITED
 
   // Forward to Event
   NS_FORWARD_TO_EVENT
 
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(DeviceMotionEvent, Event)
 
-  virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE
+  virtual JSObject* WrapObjectInternal(JSContext* aCx) MOZ_OVERRIDE
   {
     return DeviceMotionEventBinding::Wrap(aCx, this);
   }
 
   DeviceAcceleration* GetAcceleration() const
   {
     return mAcceleration;
   }
--- a/dom/events/DragEvent.h
+++ b/dom/events/DragEvent.h
@@ -25,17 +25,17 @@ public:
             WidgetDragEvent* aEvent);
 
   NS_DECL_ISUPPORTS_INHERITED
 
   NS_DECL_NSIDOMDRAGEVENT
 
   NS_FORWARD_TO_MOUSEEVENT
 
-  virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE
+  virtual JSObject* WrapObjectInternal(JSContext* aCx) MOZ_OVERRIDE
   {
     return DragEventBinding::Wrap(aCx, this);
   }
 
   DataTransfer* GetDataTransfer();
 
   void InitDragEvent(const nsAString& aType,
                      bool aCanBubble, bool aCancelable,
--- a/dom/events/Event.cpp
+++ b/dom/events/Event.cpp
@@ -59,19 +59,16 @@ Event::Event(nsPIDOMWindow* aParent)
 
 void
 Event::ConstructorInit(EventTarget* aOwner,
                        nsPresContext* aPresContext,
                        WidgetEvent* aEvent)
 {
   SetOwner(aOwner);
   mIsMainThreadEvent = mOwner || NS_IsMainThread();
-  if (mIsMainThreadEvent) {
-    nsJSContext::LikelyShortLivingObjectCreated();
-  }
 
   if (mIsMainThreadEvent && !sReturnHighResTimeStampIsSet) {
     Preferences::AddBoolVarCache(&sReturnHighResTimeStamp,
                                  "dom.event.highrestimestamp.enabled",
                                  sReturnHighResTimeStamp);
     sReturnHighResTimeStampIsSet = true;
   }
 
@@ -230,16 +227,32 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(
     }
   }
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPresContext)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mExplicitOriginalTarget)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOwner)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
+
+JSObject*
+Event::WrapObject(JSContext* aCx)
+{
+  if (mIsMainThreadEvent && !GetWrapperPreserveColor()) {
+    nsJSContext::LikelyShortLivingObjectCreated();
+  }
+  return WrapObjectInternal(aCx);
+}
+
+JSObject*
+Event::WrapObjectInternal(JSContext* aCx)
+{
+  return EventBinding::Wrap(aCx, this);
+}
+
 bool
 Event::IsChrome(JSContext* aCx) const
 {
   return mIsMainThreadEvent ?
     xpc::AccessCheck::isChrome(js::GetContextCompartment(aCx)) :
     mozilla::dom::workers::IsCurrentThreadRunningChromeWorker();
 }
 
--- a/dom/events/Event.h
+++ b/dom/events/Event.h
@@ -86,20 +86,19 @@ public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(Event)
 
   nsISupports* GetParentObject()
   {
     return mOwner;
   }
 
-  virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE
-  {
-    return EventBinding::Wrap(aCx, this);
-  }
+  virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE MOZ_FINAL;
+
+  virtual JSObject* WrapObjectInternal(JSContext* aCx);
 
   virtual ErrorEvent* AsErrorEvent()
   {
     return nullptr;
   }
 
   virtual ProgressEvent* AsProgressEvent()
   {
--- a/dom/events/FocusEvent.h
+++ b/dom/events/FocusEvent.h
@@ -18,17 +18,17 @@ class FocusEvent : public UIEvent,
 {
 public:
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_NSIDOMFOCUSEVENT
 
   // Forward to base class
   NS_FORWARD_TO_UIEVENT
 
-  virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE
+  virtual JSObject* WrapObjectInternal(JSContext* aCx) MOZ_OVERRIDE
   {
     return FocusEventBinding::Wrap(aCx, this);
   }
 
   FocusEvent(EventTarget* aOwner,
              nsPresContext* aPresContext,
              InternalFocusEvent* aEvent);
 
--- a/dom/events/InputEvent.h
+++ b/dom/events/InputEvent.h
@@ -26,17 +26,17 @@ public:
   NS_FORWARD_TO_UIEVENT
 
 
   static already_AddRefed<InputEvent> Constructor(const GlobalObject& aGlobal,
                                                   const nsAString& aType,
                                                   const InputEventInit& aParam,
                                                   ErrorResult& aRv);
 
-  virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE
+  virtual JSObject* WrapObjectInternal(JSContext* aCx) MOZ_OVERRIDE
   {
     return InputEventBinding::Wrap(aCx, this);
   }
 
   bool IsComposing();
 
 protected:
   ~InputEvent() {}
--- a/dom/events/JSEventHandler.cpp
+++ b/dom/events/JSEventHandler.cpp
@@ -18,17 +18,16 @@
 #include "nsDOMJSUtils.h"
 #include "WorkerPrivate.h"
 #include "mozilla/ContentEvents.h"
 #include "mozilla/CycleCollectedJSRuntime.h"
 #include "mozilla/HoldDropJSObjects.h"
 #include "mozilla/JSEventHandler.h"
 #include "mozilla/Likely.h"
 #include "mozilla/dom/ErrorEvent.h"
-#include "mozilla/dom/UnionTypes.h"
 
 namespace mozilla {
 
 using namespace dom;
 
 JSEventHandler::JSEventHandler(nsISupports* aTarget,
                                nsIAtom* aType,
                                const TypedEventHandler& aTypedHandler)
--- a/dom/events/KeyboardEvent.h
+++ b/dom/events/KeyboardEvent.h
@@ -31,17 +31,17 @@ public:
   NS_FORWARD_TO_UIEVENT
 
   static already_AddRefed<KeyboardEvent> Constructor(
                                            const GlobalObject& aGlobal,
                                            const nsAString& aType,
                                            const KeyboardEventInit& aParam,
                                            ErrorResult& aRv);
 
-  virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE
+  virtual JSObject* WrapObjectInternal(JSContext* aCx) MOZ_OVERRIDE
   {
     return KeyboardEventBinding::Wrap(aCx, this);
   }
 
   bool AltKey();
   bool CtrlKey();
   bool ShiftKey();
   bool MetaKey();
--- a/dom/events/MessageEvent.cpp
+++ b/dom/events/MessageEvent.cpp
@@ -3,17 +3,16 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/MessageEvent.h"
 #include "mozilla/dom/MessageEventBinding.h"
 #include "mozilla/dom/MessagePort.h"
 #include "mozilla/dom/MessagePortBinding.h"
 #include "mozilla/dom/MessagePortList.h"
-#include "mozilla/dom/UnionTypes.h"
 
 #include "mozilla/HoldDropJSObjects.h"
 #include "jsapi.h"
 
 namespace mozilla {
 namespace dom {
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(MessageEvent)
@@ -52,17 +51,17 @@ MessageEvent::MessageEvent(EventTarget* 
 
 MessageEvent::~MessageEvent()
 {
   mData = JSVAL_VOID;
   DropJSObjects(this);
 }
 
 JSObject*
-MessageEvent::WrapObject(JSContext* aCx)
+MessageEvent::WrapObjectInternal(JSContext* aCx)
 {
   return mozilla::dom::MessageEventBinding::Wrap(aCx, this);
 }
 
 NS_IMETHODIMP
 MessageEvent::GetData(JSContext* aCx, JS::MutableHandle<JS::Value> aData)
 {
   ErrorResult rv;
--- a/dom/events/MessageEvent.h
+++ b/dom/events/MessageEvent.h
@@ -38,17 +38,17 @@ public:
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(MessageEvent, Event)
 
   NS_DECL_NSIDOMMESSAGEEVENT
 
   // Forward to base class
   NS_FORWARD_TO_EVENT
 
-  virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE;
+  virtual JSObject* WrapObjectInternal(JSContext* aCx) MOZ_OVERRIDE;
 
   void GetData(JSContext* aCx, JS::MutableHandle<JS::Value> aData,
                ErrorResult& aRv);
 
   void GetSource(Nullable<OwningWindowProxyOrMessagePort>& aValue) const;
 
   MessagePortList* GetPorts()
   {
--- a/dom/events/MouseEvent.h
+++ b/dom/events/MouseEvent.h
@@ -25,17 +25,17 @@ public:
   NS_DECL_ISUPPORTS_INHERITED
 
   // nsIDOMMouseEvent Interface
   NS_DECL_NSIDOMMOUSEEVENT
 
   // Forward to base class
   NS_FORWARD_TO_UIEVENT
 
-  virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE
+  virtual JSObject* WrapObjectInternal(JSContext* aCx) MOZ_OVERRIDE
   {
     return MouseEventBinding::Wrap(aCx, this);
   }
 
   // Web IDL binding methods
   virtual uint32_t Which() MOZ_OVERRIDE
   {
     return Button() + 1;
--- a/dom/events/MouseScrollEvent.h
+++ b/dom/events/MouseScrollEvent.h
@@ -24,17 +24,17 @@ public:
   NS_DECL_ISUPPORTS_INHERITED
 
   // nsIDOMMouseScrollEvent Interface
   NS_DECL_NSIDOMMOUSESCROLLEVENT
 
   // Forward to base class
   NS_FORWARD_TO_MOUSEEVENT
 
-  virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE
+  virtual JSObject* WrapObjectInternal(JSContext* aCx) MOZ_OVERRIDE
   {
     return MouseScrollEventBinding::Wrap(aCx, this);
   }
 
   int32_t Axis();
 
   void InitMouseScrollEvent(const nsAString& aType, bool aCanBubble,
                             bool aCancelable, nsIDOMWindow* aView,
--- a/dom/events/MutationEvent.h
+++ b/dom/events/MutationEvent.h
@@ -25,17 +25,17 @@ public:
 
   NS_DECL_ISUPPORTS_INHERITED
 
   NS_DECL_NSIDOMMUTATIONEVENT
 
   // Forward to base class
   NS_FORWARD_TO_EVENT
 
-  virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE
+  virtual JSObject* WrapObjectInternal(JSContext* aCx) MOZ_OVERRIDE
   {
     return MutationEventBinding::Wrap(aCx, this);
   }
 
   // xpidl implementation
   // GetPrevValue(nsAString& aPrevValue);
   // GetNewValue(nsAString& aNewValue);
   // GetAttrName(nsAString& aAttrName);
--- a/dom/events/NotifyPaintEvent.h
+++ b/dom/events/NotifyPaintEvent.h
@@ -38,17 +38,17 @@ public:
   NS_FORWARD_TO_EVENT_NO_SERIALIZATION_NO_DUPLICATION
   NS_IMETHOD DuplicatePrivateData() MOZ_OVERRIDE
   {
     return Event::DuplicatePrivateData();
   }
   NS_IMETHOD_(void) Serialize(IPC::Message* aMsg, bool aSerializeInterfaceType) MOZ_OVERRIDE;
   NS_IMETHOD_(bool) Deserialize(const IPC::Message* aMsg, void** aIter) MOZ_OVERRIDE;
 
-  virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE
+  virtual JSObject* WrapObjectInternal(JSContext* aCx) MOZ_OVERRIDE
   {
     return NotifyPaintEventBinding::Wrap(aCx, this);
   }
 
   already_AddRefed<DOMRectList> ClientRects();
 
   already_AddRefed<DOMRect> BoundingClientRect();
 
--- a/dom/events/PointerEvent.h
+++ b/dom/events/PointerEvent.h
@@ -17,17 +17,17 @@ namespace dom {
 
 class PointerEvent : public MouseEvent
 {
 public:
   PointerEvent(EventTarget* aOwner,
                nsPresContext* aPresContext,
                WidgetPointerEvent* aEvent);
 
-  virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE
+  virtual JSObject* WrapObjectInternal(JSContext* aCx) MOZ_OVERRIDE
   {
     return PointerEventBinding::Wrap(aCx, this);
   }
 
   static already_AddRefed<PointerEvent>
   Constructor(const GlobalObject& aGlobal,
               const nsAString& aType,
               const PointerEventInit& aParam,
--- a/dom/events/ScrollAreaEvent.h
+++ b/dom/events/ScrollAreaEvent.h
@@ -33,17 +33,17 @@ public:
   NS_FORWARD_TO_EVENT_NO_SERIALIZATION_NO_DUPLICATION
   NS_IMETHOD DuplicatePrivateData()
   {
     return Event::DuplicatePrivateData();
   }
   NS_IMETHOD_(void) Serialize(IPC::Message* aMsg, bool aSerializeInterfaceType) MOZ_OVERRIDE;
   NS_IMETHOD_(bool) Deserialize(const IPC::Message* aMsg, void** aIter) MOZ_OVERRIDE;
 
-  virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE
+  virtual JSObject* WrapObjectInternal(JSContext* aCx) MOZ_OVERRIDE
   {
     return ScrollAreaEventBinding::Wrap(aCx, this);
   }
 
   float X() const
   {
     return mClientArea->Left();
   }
--- a/dom/events/SimpleGestureEvent.h
+++ b/dom/events/SimpleGestureEvent.h
@@ -25,17 +25,17 @@ public:
 
   NS_DECL_ISUPPORTS_INHERITED
 
   NS_DECL_NSIDOMSIMPLEGESTUREEVENT
 
   // Forward to base class
   NS_FORWARD_TO_MOUSEEVENT
 
-  virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE
+  virtual JSObject* WrapObjectInternal(JSContext* aCx) MOZ_OVERRIDE
   {
     return SimpleGestureEventBinding::Wrap(aCx, this);
   }
 
   uint32_t AllowedDirections();
   uint32_t Direction();
   double Delta();
   uint32_t ClickCount();
--- a/dom/events/SpeechRecognitionError.h
+++ b/dom/events/SpeechRecognitionError.h
@@ -21,17 +21,17 @@ public:
   virtual ~SpeechRecognitionError();
 
   static already_AddRefed<SpeechRecognitionError>
   Constructor(const GlobalObject& aGlobal,
               const nsAString& aType,
               const SpeechRecognitionErrorInit& aParam,
               ErrorResult& aRv);
 
-  virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE
+  virtual JSObject* WrapObjectInternal(JSContext* aCx) MOZ_OVERRIDE
   {
     return mozilla::dom::SpeechRecognitionErrorBinding::Wrap(aCx, this);
   }
 
   void
   GetMessage(nsAString& aString)
   {
     aString = mMessage;
--- a/dom/events/StorageEvent.cpp
+++ b/dom/events/StorageEvent.cpp
@@ -40,17 +40,17 @@ StorageEvent::~StorageEvent()
 
 StorageEvent*
 StorageEvent::AsStorageEvent()
 {
   return this;
 }
 
 JSObject*
-StorageEvent::WrapObject(JSContext* aCx)
+StorageEvent::WrapObjectInternal(JSContext* aCx)
 {
   return StorageEventBinding::Wrap(aCx, this);
 }
 
 already_AddRefed<StorageEvent>
 StorageEvent::Constructor(EventTarget* aOwner,
                           const nsAString& aType,
                           const StorageEventInit& aEventInitDict)
--- a/dom/events/StorageEvent.h
+++ b/dom/events/StorageEvent.h
@@ -37,17 +37,17 @@ protected:
   nsString mOldValue;
   nsString mNewValue;
   nsString mUrl;
   nsRefPtr<DOMStorage> mStorageArea;
 
 public:
   virtual StorageEvent* AsStorageEvent();
 
-  virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE;
+  virtual JSObject* WrapObjectInternal(JSContext* aCx) MOZ_OVERRIDE;
 
   static already_AddRefed<StorageEvent>
   Constructor(EventTarget* aOwner, const nsAString& aType,
               const StorageEventInit& aEventInitDict);
 
   static already_AddRefed<StorageEvent>
   Constructor(const GlobalObject& aGlobal, const nsAString& aType,
               const StorageEventInit& aEventInitDict, ErrorResult& aRv);
--- a/dom/events/TouchEvent.h
+++ b/dom/events/TouchEvent.h
@@ -84,17 +84,17 @@ class TouchEvent : public UIEvent
 public:
   TouchEvent(EventTarget* aOwner,
              nsPresContext* aPresContext,
              WidgetTouchEvent* aEvent);
 
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(TouchEvent, UIEvent)
 
-  virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE
+  virtual JSObject* WrapObjectInternal(JSContext* aCx) MOZ_OVERRIDE
   {
     return TouchEventBinding::Wrap(aCx, this);
   }
 
   TouchList* Touches();
   TouchList* TargetTouches();
   TouchList* ChangedTouches();
 
--- a/dom/events/TransitionEvent.h
+++ b/dom/events/TransitionEvent.h
@@ -28,17 +28,17 @@ public:
   NS_DECL_NSIDOMTRANSITIONEVENT
 
   static already_AddRefed<TransitionEvent>
   Constructor(const GlobalObject& aGlobal,
               const nsAString& aType,
               const TransitionEventInit& aParam,
               ErrorResult& aRv);
 
-  virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE
+  virtual JSObject* WrapObjectInternal(JSContext* aCx) MOZ_OVERRIDE
   {
     return TransitionEventBinding::Wrap(aCx, this);
   }
 
   // xpidl implementation
   // GetPropertyName(nsAString& aPropertyName)
   // GetPseudoElement(nsAString& aPreudoElement)
 
--- a/dom/events/UIEvent.h
+++ b/dom/events/UIEvent.h
@@ -97,17 +97,17 @@ public:
     return CSSIntPoint::FromAppUnitsRounded(pt);
   }
 
   static already_AddRefed<UIEvent> Constructor(const GlobalObject& aGlobal,
                                                const nsAString& aType,
                                                const UIEventInit& aParam,
                                                ErrorResult& aRv);
 
-  virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE
+  virtual JSObject* WrapObjectInternal(JSContext* aCx) MOZ_OVERRIDE
   {
     return UIEventBinding::Wrap(aCx, this);
   }
 
   nsIDOMWindow* GetView() const
   {
     return mView;
   }
--- a/dom/events/WheelEvent.h
+++ b/dom/events/WheelEvent.h
@@ -32,17 +32,17 @@ public:
   NS_FORWARD_TO_MOUSEEVENT
 
   static
   already_AddRefed<WheelEvent> Constructor(const GlobalObject& aGlobal,
                                            const nsAString& aType,
                                            const WheelEventInit& aParam,
                                            ErrorResult& aRv);
 
-  virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE
+  virtual JSObject* WrapObjectInternal(JSContext* aCx) MOZ_OVERRIDE
   {
     return WheelEventBinding::Wrap(aCx, this);
   }
 
   // NOTE: DeltaX(), DeltaY() and DeltaZ() return CSS pixels when deltaMode is
   //       DOM_DELTA_PIXEL. (The internal event's delta values are device pixels
   //       if it's dispatched by widget)
   double DeltaX();
--- a/dom/events/XULCommandEvent.h
+++ b/dom/events/XULCommandEvent.h
@@ -26,17 +26,17 @@ public:
 
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(XULCommandEvent, UIEvent)
   NS_DECL_NSIDOMXULCOMMANDEVENT
 
   // Forward our inherited virtual methods to the base class
   NS_FORWARD_TO_UIEVENT
 
-  virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE
+  virtual JSObject* WrapObjectInternal(JSContext* aCx) MOZ_OVERRIDE
   {
     return XULCommandEventBinding::Wrap(aCx, this);
   }
 
   bool AltKey();
   bool CtrlKey();
   bool ShiftKey();
   bool MetaKey();
--- a/dom/fetch/Fetch.h
+++ b/dom/fetch/Fetch.h
@@ -1,23 +1,28 @@
 /* -*- 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_dom_Fetch_h
 #define mozilla_dom_Fetch_h
 
-#include "mozilla/dom/UnionTypes.h"
+#include "nsCOMPtr.h"
+#include "nsError.h"
+#include "nsString.h"
+#include "mozilla/ErrorResult.h"
 
 class nsIInputStream;
 
 namespace mozilla {
 namespace dom {
 
+class ArrayBufferOrArrayBufferViewOrBlobOrScalarValueStringOrURLSearchParams;
+class OwningArrayBufferOrArrayBufferViewOrBlobOrScalarValueStringOrURLSearchParams;
 class Promise;
 
 /*
  * Creates an nsIInputStream based on the fetch specifications 'extract a byte
  * stream algorithm' - http://fetch.spec.whatwg.org/#concept-bodyinit-extract.
  * Stores content type in out param aContentType.
  */
 nsresult
--- a/dom/fetch/Headers.h
+++ b/dom/fetch/Headers.h
@@ -3,33 +3,33 @@
 /* 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_Headers_h
 #define mozilla_dom_Headers_h
 
 #include "mozilla/dom/HeadersBinding.h"
-#include "mozilla/dom/UnionTypes.h"
 
 #include "nsClassHashtable.h"
 #include "nsWrapperCache.h"
 
 #include "InternalHeaders.h"
 
 class nsPIDOMWindow;
 
 namespace mozilla {
 
 class ErrorResult;
 
 namespace dom {
 
 template<typename T> class MozMap;
 class HeadersOrByteStringSequenceSequenceOrByteStringMozMap;
+class OwningHeadersOrByteStringSequenceSequenceOrByteStringMozMap;
 
 /**
  * This Headers class is only used to represent the content facing Headers
  * object. It is actually backed by an InternalHeaders implementation. Gecko
  * code should NEVER use this, except in the Request and Response
  * implementations, where they must always be created from the backing
  * InternalHeaders object.
  */
--- a/dom/fetch/InternalRequest.h
+++ b/dom/fetch/InternalRequest.h
@@ -4,17 +4,16 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_InternalRequest_h
 #define mozilla_dom_InternalRequest_h
 
 #include "mozilla/dom/HeadersBinding.h"
 #include "mozilla/dom/InternalHeaders.h"
 #include "mozilla/dom/RequestBinding.h"
-#include "mozilla/dom/UnionTypes.h"
 
 #include "nsIContentPolicy.h"
 #include "nsIInputStream.h"
 #include "nsISupportsImpl.h"
 
 class nsIDocument;
 class nsPIDOMWindow;
 
--- a/dom/fetch/Request.h
+++ b/dom/fetch/Request.h
@@ -9,26 +9,26 @@
 #include "nsISupportsImpl.h"
 #include "nsWrapperCache.h"
 
 #include "mozilla/dom/Fetch.h"
 #include "mozilla/dom/InternalRequest.h"
 // Required here due to certain WebIDL enums/classes being declared in both
 // files.
 #include "mozilla/dom/RequestBinding.h"
-#include "mozilla/dom/UnionTypes.h"
 
 class nsPIDOMWindow;
 
 namespace mozilla {
 namespace dom {
 
 class Headers;
 class InternalHeaders;
 class Promise;
+class RequestOrScalarValueString;
 
 class Request MOZ_FINAL : public nsISupports
                         , public nsWrapperCache
                         , public FetchBody<Request>
 {
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(Request)
 
--- a/dom/fetch/Response.cpp
+++ b/dom/fetch/Response.cpp
@@ -5,16 +5,17 @@
 
 #include "Response.h"
 
 #include "nsISupportsImpl.h"
 #include "nsIURI.h"
 #include "nsPIDOMWindow.h"
 
 #include "mozilla/ErrorResult.h"
+#include "mozilla/dom/FetchBinding.h"
 #include "mozilla/dom/Headers.h"
 #include "mozilla/dom/Promise.h"
 
 #include "nsDOMString.h"
 
 #include "InternalResponse.h"
 
 namespace mozilla {
--- a/dom/fetch/Response.h
+++ b/dom/fetch/Response.h
@@ -6,25 +6,25 @@
 #ifndef mozilla_dom_Response_h
 #define mozilla_dom_Response_h
 
 #include "nsWrapperCache.h"
 #include "nsISupportsImpl.h"
 
 #include "mozilla/dom/Fetch.h"
 #include "mozilla/dom/ResponseBinding.h"
-#include "mozilla/dom/UnionTypes.h"
 
 #include "InternalResponse.h"
 
 class nsPIDOMWindow;
 
 namespace mozilla {
 namespace dom {
 
+class ArrayBufferOrArrayBufferViewOrScalarValueStringOrURLSearchParams;
 class Headers;
 class InternalHeaders;
 class Promise;
 
 class Response MOZ_FINAL : public nsISupports
                          , public nsWrapperCache
                          , public FetchBody<Response>
 {
--- a/dom/filesystem/Directory.cpp
+++ b/dom/filesystem/Directory.cpp
@@ -12,17 +12,16 @@
 #include "GetFileOrDirectoryTask.h"
 #include "RemoveTask.h"
 
 #include "nsCharSeparatedTokenizer.h"
 #include "nsString.h"
 #include "mozilla/dom/DirectoryBinding.h"
 #include "mozilla/dom/FileSystemBase.h"
 #include "mozilla/dom/FileSystemUtils.h"
-#include "mozilla/dom/UnionTypes.h"
 
 // Resolve the name collision of Microsoft's API name with macros defined in
 // Windows header files. Undefine the macro of CreateDirectory to avoid
 // Directory#CreateDirectory being replaced by Directory#CreateDirectoryW.
 #ifdef CreateDirectory
 #undef CreateDirectory
 #endif
 // Undefine the macro of CreateFile to avoid Directory#CreateFile being replaced
--- a/dom/icc/Icc.h
+++ b/dom/icc/Icc.h
@@ -1,26 +1,26 @@
 /* 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_Icc_h
 #define mozilla_dom_Icc_h
 
 #include "mozilla/dom/MozIccBinding.h" // For IccCardState
-#include "mozilla/dom/UnionTypes.h"
 #include "mozilla/DOMEventTargetHelper.h"
 
 class nsIIccInfo;
 class nsIIccProvider;
 
 namespace mozilla {
 namespace dom {
 
 class DOMRequest;
+class OwningMozIccInfoOrMozGsmIccInfoOrMozCdmaIccInfo;
 
 class Icc MOZ_FINAL : public DOMEventTargetHelper
 {
 public:
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(Icc, DOMEventTargetHelper)
   NS_REALLY_FORWARD_NSIDOMEVENTTARGET(DOMEventTargetHelper)
 
--- a/dom/indexedDB/IDBEvents.cpp
+++ b/dom/indexedDB/IDBEvents.cpp
@@ -91,16 +91,16 @@ IDBVersionChangeEvent::Constructor(const
 NS_IMPL_ADDREF_INHERITED(IDBVersionChangeEvent, Event)
 NS_IMPL_RELEASE_INHERITED(IDBVersionChangeEvent, Event)
 
 NS_INTERFACE_MAP_BEGIN(IDBVersionChangeEvent)
   NS_INTERFACE_MAP_ENTRY(IDBVersionChangeEvent)
 NS_INTERFACE_MAP_END_INHERITING(Event)
 
 JSObject*
-IDBVersionChangeEvent::WrapObject(JSContext* aCx)
+IDBVersionChangeEvent::WrapObjectInternal(JSContext* aCx)
 {
   return IDBVersionChangeEventBinding::Wrap(aCx, this);
 }
 
 } // namespace indexedDB
 } // namespace dom
 } // namespace mozilla
--- a/dom/indexedDB/IDBEvents.h
+++ b/dom/indexedDB/IDBEvents.h
@@ -99,17 +99,17 @@ public:
   }
 
   NS_DECLARE_STATIC_IID_ACCESSOR(IDBVERSIONCHANGEEVENT_IID)
 
   NS_DECL_ISUPPORTS_INHERITED
   NS_FORWARD_TO_EVENT
 
   virtual JSObject*
-  WrapObject(JSContext* aCx) MOZ_OVERRIDE;
+  WrapObjectInternal(JSContext* aCx) MOZ_OVERRIDE;
 
 private:
   IDBVersionChangeEvent(EventTarget* aOwner, uint64_t aOldVersion)
     : Event(aOwner, nullptr, nullptr)
     , mOldVersion(aOldVersion)
   {
   }
 
--- a/dom/indexedDB/IDBRequest.cpp
+++ b/dom/indexedDB/IDBRequest.cpp
@@ -16,17 +16,16 @@
 #include "IDBTransaction.h"
 #include "mozilla/ContentEvents.h"
 #include "mozilla/ErrorResult.h"
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/dom/DOMError.h"
 #include "mozilla/dom/ErrorEventBinding.h"
 #include "mozilla/dom/IDBOpenDBRequestBinding.h"
 #include "mozilla/dom/ScriptSettings.h"
-#include "mozilla/dom/UnionTypes.h"
 #include "nsCOMPtr.h"
 #include "nsContentUtils.h"
 #include "nsIScriptContext.h"
 #include "nsJSUtils.h"
 #include "nsPIDOMWindow.h"
 #include "nsString.h"
 #include "ReportInternalError.h"
 
--- a/dom/ipc/StructuredCloneUtils.cpp
+++ b/dom/ipc/StructuredCloneUtils.cpp
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "StructuredCloneUtils.h"
 
 #include "nsIDOMDOMException.h"
 #include "nsIMutable.h"
 #include "nsIXPConnect.h"
 
+#include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/BlobBinding.h"
 #include "mozilla/dom/File.h"
 #include "nsContentUtils.h"
 #include "nsJSEnvironment.h"
 #include "MainThreadUtils.h"
 #include "StructuredCloneTags.h"
 #include "jsapi.h"
 
--- a/dom/mobilemessage/DOMMobileMessageError.cpp
+++ b/dom/mobilemessage/DOMMobileMessageError.cpp
@@ -1,17 +1,16 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "DOMMobileMessageError.h"
 #include "mozilla/dom/DOMMobileMessageErrorBinding.h"
-#include "mozilla/dom/UnionTypes.h"
 #include "nsIDOMMozMmsMessage.h"
 #include "nsIDOMMozSmsMessage.h"
 
 using namespace mozilla::dom;
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(DOMMobileMessageError)
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(DOMMobileMessageError, DOMError)
--- a/dom/mobilemessage/MobileMessageManager.h
+++ b/dom/mobilemessage/MobileMessageManager.h
@@ -2,32 +2,32 @@
 /* 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_mobilemessage_MobileMessageManager_h
 #define mozilla_dom_mobilemessage_MobileMessageManager_h
 
 #include "mozilla/Attributes.h"
-#include "mozilla/dom/UnionTypes.h"
 #include "mozilla/DOMEventTargetHelper.h"
 #include "nsIObserver.h"
 
 class nsISmsService;
 class nsIDOMMozSmsMessage;
 class nsIDOMMozMmsMessage;
 
 namespace mozilla {
 namespace dom {
 
 class DOMRequest;
 class DOMCursor;
 struct MmsParameters;
 struct MmsSendParameters;
 struct MobileMessageFilter;
+class OwningLongOrMozSmsMessageOrMozMmsMessage;
 struct SmsSendParameters;
 
 class MobileMessageManager MOZ_FINAL : public DOMEventTargetHelper
                                      , public nsIObserver
 {
 public:
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_NSIOBSERVER
--- a/dom/network/TCPServerSocket.js
+++ b/dom/network/TCPServerSocket.js
@@ -40,16 +40,20 @@ function TCPServerSocket() {
   this._onerror = null;
 
   this._inChild = false;
   this._neckoTCPServerSocket = null;
   this._serverBridge = null;
   this.useWin = null;
 }
 
+// When this API moves to WebIDL and these __exposedProps__ go away, remove
+// this call here and remove the API from XPConnect.
+Cu.skipCOWCallableChecks();
+
 TCPServerSocket.prototype = {
   __exposedProps__: {
     port: 'r',
     onconnect: 'rw',
     onerror: 'rw'
   },
   get localPort() {
     return this._localPort;
--- a/dom/network/TCPSocket.js
+++ b/dom/network/TCPSocket.js
@@ -64,16 +64,20 @@ function LOG(msg) {
  */
 
 function TCPSocketEvent(type, sock, data) {
   this._type = type;
   this._target = sock;
   this._data = data;
 }
 
+// When this API moves to WebIDL and these __exposedProps__ go away, remove
+// this call here and remove the API from XPConnect.
+Cu.skipCOWCallableChecks();
+
 TCPSocketEvent.prototype = {
   __exposedProps__: {
     type: 'r',
     target: 'r',
     data: 'r'
   },
   get type() {
     return this._type;
--- a/dom/payment/Payment.js
+++ b/dom/payment/Payment.js
@@ -93,17 +93,17 @@ PaymentContentHelper.prototype = {
     try {
       this._debug =
         Services.prefs.getPrefType(PREF_DEBUG) == Ci.nsIPrefBranch.PREF_BOOL
         && Services.prefs.getBoolPref(PREF_DEBUG);
     } catch(e) {
       this._debug = false;
     }
 
-    return this.pay.bind(this);
+    return Cu.exportFunction(this.pay.bind(this), aWindow);
   },
 
   // nsIFrameMessageListener
 
   receiveMessage: function receiveMessage(aMessage) {
     let name = aMessage.name;
     let msg = aMessage.json;
     if (this._debug) {
--- a/dom/plugins/base/npapi.h
+++ b/dom/plugins/base/npapi.h
@@ -54,17 +54,17 @@
 #include <QRegion>
 #endif
 
 /*----------------------------------------------------------------------*/
 /*                        Plugin Version Constants                      */
 /*----------------------------------------------------------------------*/
 
 #define NP_VERSION_MAJOR 0
-#define NP_VERSION_MINOR 27
+#define NP_VERSION_MINOR 28
 
 
 /* The OS/2 version of Netscape uses RC_DATA to define the
    mime types, file extensions, etc that are required.
    Use a vertical bar to separate types, end types with \0.
    FileVersion and ProductVersion are 32bit ints, all other
    entries are strings that MUST be terminated with a \0.
 
@@ -181,43 +181,16 @@ typedef struct _NPSize
   int32_t height;
 } NPSize;
 
 typedef enum {
   NPFocusNext = 0,
   NPFocusPrevious = 1
 } NPFocusDirection;
 
-/* These formats describe the format in the memory byte-order. This means if
- * a 32-bit value of a pixel is viewed on a little-endian system the layout will
- * be 0xAARRGGBB. The Alpha channel will be stored in the most significant
- * bits. */
-typedef enum {
-  /* 32-bit per pixel 8-bit per channel - premultiplied alpha */
-  NPImageFormatBGRA32     = 0x1,
-  /* 32-bit per pixel 8-bit per channel - 1 unused channel */
-  NPImageFormatBGRX32     = 0x2 
-} NPImageFormat;
-
-typedef struct _NPAsyncSurface
-{
-  uint32_t version;
-  NPSize size;
-  NPImageFormat format;
-  union {
-    struct {
-      uint32_t stride;
-      void *data;
-    } bitmap;
-#if defined(XP_WIN)
-    HANDLE sharedHandle;
-#endif
-  };
-} NPAsyncSurface;
-
 /* Return values for NPP_HandleEvent */
 #define kNPEventNotHandled 0
 #define kNPEventHandled 1
 /* Exact meaning must be spec'd in event model. */
 #define kNPEventStartIME 2
 
 #if defined(XP_UNIX)
 /*
@@ -254,34 +227,37 @@ typedef struct
 {
   int32_t type;
   FILE* fp;
 } NPPrintCallbackStruct;
 
 #endif /* XP_UNIX */
 
 typedef enum {
+  NPDrawingModelDUMMY
 #if defined(XP_MACOSX)
 #ifndef NP_NO_QUICKDRAW
-  NPDrawingModelQuickDraw = 0,
+  , NPDrawingModelQuickDraw = 0
 #endif
-  NPDrawingModelCoreGraphics = 1,
-  NPDrawingModelOpenGL = 2,
-  NPDrawingModelCoreAnimation = 3,
-  NPDrawingModelInvalidatingCoreAnimation = 4,
+  , NPDrawingModelCoreGraphics = 1
+  , NPDrawingModelOpenGL = 2
+  , NPDrawingModelCoreAnimation = 3
+  , NPDrawingModelInvalidatingCoreAnimation = 4
 #endif
 #if defined(XP_WIN)
-  NPDrawingModelSyncWin = 5,
+  , NPDrawingModelSyncWin = 5
 #endif
 #if defined(MOZ_X11)
-  NPDrawingModelSyncX = 6,
+  , NPDrawingModelSyncX = 6
 #endif
-  NPDrawingModelAsyncBitmapSurface = 7
+#if 0 /* OBSOLETE */
+  , NPDrawingModelAsyncBitmapSurfaceOBSOLETE = 7
 #if defined(XP_WIN)
-  , NPDrawingModelAsyncWindowsDXGISurface = 8
+  , NPDrawingModelAsyncWindowsDXGISurfaceOBSOLETE = 8
+#endif
 #endif
 } NPDrawingModel;
 
 #ifdef XP_MACOSX
 typedef enum {
 #ifndef NP_NO_CARBON
   NPEventModelCarbon = 0,
 #endif
@@ -415,19 +391,21 @@ typedef enum {
 #ifndef NP_NO_QUICKDRAW
   , NPNVsupportsQuickDrawBool = 2000
 #endif
   , NPNVsupportsCoreGraphicsBool = 2001
   , NPNVsupportsOpenGLBool = 2002
   , NPNVsupportsCoreAnimationBool = 2003
   , NPNVsupportsInvalidatingCoreAnimationBool = 2004
 #endif
-  , NPNVsupportsAsyncBitmapSurfaceBool = 2007
+#if 0 /* OBSOLETE */
+  , NPNVsupportsAsyncBitmapSurfaceBoolOBSOLETE = 2007
 #if defined(XP_WIN)
-  , NPNVsupportsAsyncWindowsDXGISurfaceBool = 2008
+  , NPNVsupportsAsyncWindowsDXGISurfaceBoolOBSOLETE = 2008
+#endif
 #endif
 #if defined(XP_MACOSX)
 #ifndef NP_NO_CARBON
   , NPNVsupportsCarbonBool = 3000 /* TRUE if the browser supports the Carbon event model */
 #endif
   , NPNVsupportsCocoaBool = 3001 /* TRUE if the browser supports the Cocoa event model */
   , NPNVsupportsUpdatedCocoaTextInputBool = 3002 /* TRUE if the browser supports the updated
                                                     Cocoa text input specification. */
@@ -862,21 +840,16 @@ NPError     NPN_GetAuthenticationInfo(NP
                                       uint32_t *plen);
 uint32_t    NPN_ScheduleTimer(NPP instance, uint32_t interval, NPBool repeat, void (*timerFunc)(NPP npp, uint32_t timerID));
 void        NPN_UnscheduleTimer(NPP instance, uint32_t timerID);
 NPError     NPN_PopUpContextMenu(NPP instance, NPMenu* menu);
 NPBool      NPN_ConvertPoint(NPP instance, double sourceX, double sourceY, NPCoordinateSpace sourceSpace, double *destX, double *destY, NPCoordinateSpace destSpace);
 NPBool      NPN_HandleEvent(NPP instance, void *event, NPBool handled);
 NPBool      NPN_UnfocusInstance(NPP instance, NPFocusDirection direction);
 void        NPN_URLRedirectResponse(NPP instance, void* notifyData, NPBool allow);
-NPError     NPN_InitAsyncSurface(NPP instance, NPSize *size,
-                                 NPImageFormat format, void *initData,
-                                 NPAsyncSurface *surface);
-NPError     NPN_FinalizeAsyncSurface(NPP instance, NPAsyncSurface *surface);
-void        NPN_SetCurrentAsyncSurface(NPP instance, NPAsyncSurface *surface, NPRect *changed);
 
 #ifdef __cplusplus
 }  /* end extern "C" */
 #endif
 
 #endif /* RC_INVOKED */
 
 #endif /* npapi_h_ */
--- a/dom/plugins/base/npfunctions.h
+++ b/dom/plugins/base/npfunctions.h
@@ -87,19 +87,18 @@ typedef NPError      (*NPN_SetValueForUR
 typedef NPError      (*NPN_GetAuthenticationInfoPtr)(NPP npp, const char *protocol, const char *host, int32_t port, const char *scheme, const char *realm, char **username, uint32_t *ulen, char **password, uint32_t *plen);
 typedef uint32_t     (*NPN_ScheduleTimerPtr)(NPP instance, uint32_t interval, NPBool repeat, void (*timerFunc)(NPP npp, uint32_t timerID));
 typedef void         (*NPN_UnscheduleTimerPtr)(NPP instance, uint32_t timerID);
 typedef NPError      (*NPN_PopUpContextMenuPtr)(NPP instance, NPMenu* menu);
 typedef NPBool       (*NPN_ConvertPointPtr)(NPP instance, double sourceX, double sourceY, NPCoordinateSpace sourceSpace, double *destX, double *destY, NPCoordinateSpace destSpace);
 typedef NPBool       (*NPN_HandleEventPtr)(NPP instance, void *event, NPBool handled);
 typedef NPBool       (*NPN_UnfocusInstancePtr)(NPP instance, NPFocusDirection direction);
 typedef void         (*NPN_URLRedirectResponsePtr)(NPP instance, void* notifyData, NPBool allow);
-typedef NPError      (*NPN_InitAsyncSurfacePtr)(NPP instance, NPSize *size, NPImageFormat format, void *initData, NPAsyncSurface *surface);
-typedef NPError      (*NPN_FinalizeAsyncSurfacePtr)(NPP instance, NPAsyncSurface *surface);
-typedef void         (*NPN_SetCurrentAsyncSurfacePtr)(NPP instance, NPAsyncSurface *surface, NPRect *changed);
+
+typedef void         (*NPN_DummyPtr)(void);
 
 typedef struct _NPPluginFuncs {
   uint16_t size;
   uint16_t version;
   NPP_NewProcPtr newp;
   NPP_DestroyProcPtr destroy;
   NPP_SetWindowProcPtr setwindow;
   NPP_NewStreamProcPtr newstream;
@@ -174,19 +173,19 @@ typedef struct _NPNetscapeFuncs {
   NPN_GetAuthenticationInfoPtr getauthenticationinfo;
   NPN_ScheduleTimerPtr scheduletimer;
   NPN_UnscheduleTimerPtr unscheduletimer;
   NPN_PopUpContextMenuPtr popupcontextmenu;
   NPN_ConvertPointPtr convertpoint;
   NPN_HandleEventPtr handleevent;
   NPN_UnfocusInstancePtr unfocusinstance;
   NPN_URLRedirectResponsePtr urlredirectresponse;
-  NPN_InitAsyncSurfacePtr initasyncsurface;
-  NPN_FinalizeAsyncSurfacePtr finalizeasyncsurface;
-  NPN_SetCurrentAsyncSurfacePtr setcurrentasyncsurface;
+  NPN_DummyPtr initasyncsurfaceOBSOLETE;
+  NPN_DummyPtr finalizeasyncsurfaceOBSOLETE;
+  NPN_DummyPtr setcurrentasyncsurfaceOBSOLETE;
 } NPNetscapeFuncs;
 
 #ifdef XP_MACOSX
 /*
  * Mac OS X version(s) of NP_GetMIMEDescription(const char *)
  * These can be called to retreive MIME information from the plugin dynamically
  *
  * Note: For compatibility with Quicktime, BPSupportedMIMEtypes is another way
--- a/dom/plugins/base/nsIPluginInstanceOwner.idl
+++ b/dom/plugins/base/nsIPluginInstanceOwner.idl
@@ -21,17 +21,17 @@ enum nsPluginTagType {
   nsPluginTagType_Applet
 };
 %}
 
 [ptr] native nsNPAPIPluginInstancePtr(nsNPAPIPluginInstance);
 
 // Do not make this interface scriptable, because the virtual functions in C++
 // blocks will make script call the wrong functions.
-[uuid(59BE4CA5-3CB0-40E6-A111-9A88C8477610)]
+[uuid(c4e26e5d-7a9b-4900-b567-e128c4be6e31)]
 interface nsIPluginInstanceOwner : nsISupports
 {
   /**
    * Let the owner know what its instance is
    */
   void setInstance(in nsNPAPIPluginInstancePtr aInstance);
 
   /**
@@ -105,20 +105,16 @@ interface nsIPluginInstanceOwner : nsISu
 
   /**
    * Show native context menu
    */
 %{C++
   virtual NPError ShowNativeContextMenu(NPMenu* menu, void* event) = 0;
   virtual NPBool  ConvertPoint(double sourceX, double sourceY, NPCoordinateSpace sourceSpace,
                                double *destX, double *destY, NPCoordinateSpace destSpace) = 0;
-  virtual NPError InitAsyncSurface(NPSize *size, NPImageFormat format,
-                                   void *initData, NPAsyncSurface *surface) = 0;
-  virtual NPError FinalizeAsyncSurface(NPAsyncSurface *surface) = 0;
-  virtual void SetCurrentAsyncSurface(NPAsyncSurface *surface, NPRect *changed) = 0;
 %}
 
   void setEventModel(in int32_t eventModel);
 
   /**
    * Call NPP_SetWindow on the plugin.
    */
   void callSetWindow();
--- a/dom/plugins/base/nsNPAPIPlugin.cpp
+++ b/dom/plugins/base/nsNPAPIPlugin.cpp
@@ -159,20 +159,17 @@ static NPNetscapeFuncs sBrowserFuncs = {
   _setvalueforurl,
   _getauthenticationinfo,
   _scheduletimer,
   _unscheduletimer,
   _popupcontextmenu,
   _convertpoint,
   nullptr, // handleevent, unimplemented
   nullptr, // unfocusinstance, unimplemented
-  _urlredirectresponse,
-  _initasyncsurface,
-  _finalizeasyncsurface,
-  _setcurrentasyncsurface
+  _urlredirectresponse
 };
 
 static Mutex *sPluginThreadAsyncCallLock = nullptr;
 static PRCList sPendingAsyncCalls = PR_INIT_STATIC_CLIST(&sPendingAsyncCalls);
 
 // POST/GET stream type
 enum eNPPStreamTypeInternal {
   eNPPStreamTypeInternal_Get,
@@ -2772,46 +2769,16 @@ NPError
 {
   nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance *)instance->ndata;
   if (!inst)
     return NPERR_GENERIC_ERROR;
 
   return inst->PopUpContextMenu(menu);
 }
 
-NPError
-_initasyncsurface(NPP instance, NPSize *size, NPImageFormat format, void *initData, NPAsyncSurface *surface)
-{
-  nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance *)instance->ndata;
-  if (!inst)
-    return NPERR_GENERIC_ERROR;
-
-  return inst->InitAsyncSurface(size, format, initData, surface);
-}
-
-NPError
-_finalizeasyncsurface(NPP instance, NPAsyncSurface *surface)
-{
-  nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance *)instance->ndata;
-  if (!inst)
-    return NPERR_GENERIC_ERROR;
-
-  return inst->FinalizeAsyncSurface(surface);
-}
-
-void
-_setcurrentasyncsurface(NPP instance, NPAsyncSurface *surface, NPRect *changed)
-{
-  nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance *)instance->ndata;
-  if (!inst)
-    return;
-
-  inst->SetCurrentAsyncSurface(surface, changed);
-}
-
 NPBool
 _convertpoint(NPP instance, double sourceX, double sourceY, NPCoordinateSpace sourceSpace, double *destX, double *destY, NPCoordinateSpace destSpace)
 {
   nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance *)instance->ndata;
   if (!inst)
     return false;
 
   return inst->ConvertPoint(sourceX, sourceY, sourceSpace, destX, destY, destSpace);
--- a/dom/plugins/base/nsNPAPIPlugin.h
+++ b/dom/plugins/base/nsNPAPIPlugin.h
@@ -242,25 +242,16 @@ uint32_t
 _scheduletimer(NPP instance, uint32_t interval, NPBool repeat, PluginTimerFunc timerFunc);
 
 void
 _unscheduletimer(NPP instance, uint32_t timerID);
 
 NPError
 _popupcontextmenu(NPP instance, NPMenu* menu);
 
-NPError
-_initasyncsurface(NPP instance, NPSize *size, NPImageFormat format, void *initData, NPAsyncSurface *surface);
-
-NPError
-_finalizeasyncsurface(NPP instance, NPAsyncSurface *surface);
-
-void
-_setcurrentasyncsurface(NPP instance, NPAsyncSurface *surface, NPRect *changed);
-
 NPBool
 _convertpoint(NPP instance, double sourceX, double sourceY, NPCoordinateSpace sourceSpace, double *destX, double *destY, NPCoordinateSpace destSpace);
 
 NPError
 _requestread(NPStream *pstream, NPByteRange *rangeList);
 
 NPError
 _geturlnotify(NPP npp, const char* relativeURL, const char* target,
--- a/dom/plugins/base/nsNPAPIPluginInstance.cpp
+++ b/dom/plugins/base/nsNPAPIPluginInstance.cpp
@@ -1642,42 +1642,16 @@ nsNPAPIPluginInstance::URLRedirectRespon
   for (uint32_t i = 0; i < listenerCount; i++) {
     nsNPAPIPluginStreamListener* currentListener = mStreamListeners[i];
     if (currentListener->GetNotifyData() == notifyData) {
       currentListener->URLRedirectResponse(allow);
     }
   }
 }
 
-NPError
-nsNPAPIPluginInstance::InitAsyncSurface(NPSize *size, NPImageFormat format,
-                                        void *initData, NPAsyncSurface *surface)
-{
-  if (mOwner)
-    return mOwner->InitAsyncSurface(size, format, initData, surface);
-
-  return NPERR_GENERIC_ERROR;
-}
-
-NPError
-nsNPAPIPluginInstance::FinalizeAsyncSurface(NPAsyncSurface *surface)
-{
-  if (mOwner)
-    return mOwner->FinalizeAsyncSurface(surface);
-
-  return NPERR_GENERIC_ERROR;
-}
-
-void
-nsNPAPIPluginInstance::SetCurrentAsyncSurface(NPAsyncSurface *surface, NPRect *changed)
-{
-  if (mOwner)
-    mOwner->SetCurrentAsyncSurface(surface, changed);
-}
-
 class CarbonEventModelFailureEvent : public nsRunnable {
 public:
   nsCOMPtr<nsIContent> mContent;
 
   explicit CarbonEventModelFailureEvent(nsIContent* aContent)
     : mContent(aContent)
   {}
 
--- a/dom/plugins/base/nsNPAPIPluginInstance.h
+++ b/dom/plugins/base/nsNPAPIPluginInstance.h
@@ -269,21 +269,16 @@ public:
   nsTArray<nsNPAPIPluginStreamListener*> *StreamListeners();
 
   nsTArray<nsPluginStreamListenerPeer*> *FileCachedStreamListeners();
 
   nsresult AsyncSetWindow(NPWindow& window);
 
   void URLRedirectResponse(void* notifyData, NPBool allow);
 
-  NPError InitAsyncSurface(NPSize *size, NPImageFormat format,
-                           void *initData, NPAsyncSurface *surface);
-  NPError FinalizeAsyncSurface(NPAsyncSurface *surface);
-  void SetCurrentAsyncSurface(NPAsyncSurface *surface, NPRect *changed);
-
   // Called when the instance fails to instantiate beceause the Carbon
   // event model is not supported.
   void CarbonNPAPIFailure();
 
   // Returns the contents scale factor of the screen the plugin is drawn on.
   double GetContentsScaleFactor();
 
   static bool InPluginCallUnsafeForReentry() { return gInUnsafePluginCalls > 0; }
--- a/dom/plugins/base/nsPluginInstanceOwner.cpp
+++ b/dom/plugins/base/nsPluginInstanceOwner.cpp
@@ -754,31 +754,16 @@ NPBool nsPluginInstanceOwner::ConvertPoi
   return NS_NPAPI_ConvertPointCocoa(mWidget->GetNativeData(NS_NATIVE_WIDGET),
                                     sourceX, sourceY, sourceSpace, destX, destY, destSpace);
 #else
   // we should implement this for all platforms
   return false;
 #endif
 }
 
-NPError nsPluginInstanceOwner::InitAsyncSurface(NPSize *size, NPImageFormat format,
-                                                void *initData, NPAsyncSurface *surface)
-{
-  return NPERR_INCOMPATIBLE_VERSION_ERROR;
-}
-
-NPError nsPluginInstanceOwner::FinalizeAsyncSurface(NPAsyncSurface *)
-{
-  return NPERR_INCOMPATIBLE_VERSION_ERROR;
-}
-
-void nsPluginInstanceOwner::SetCurrentAsyncSurface(NPAsyncSurface *, NPRect*)
-{
-}
-
 NS_IMETHODIMP nsPluginInstanceOwner::GetTagType(nsPluginTagType *result)
 {
   NS_ENSURE_ARG_POINTER(result);
 
   *result = nsPluginTagType_Unknown;
 
   nsIAtom *atom = mContent->Tag();
 
--- a/dom/plugins/base/nsPluginInstanceOwner.h
+++ b/dom/plugins/base/nsPluginInstanceOwner.h
@@ -62,21 +62,16 @@ public:
   
   NS_IMETHOD ShowStatus(const char16_t *aStatusMsg) MOZ_OVERRIDE;
   
   NPError    ShowNativeContextMenu(NPMenu* menu, void* event) MOZ_OVERRIDE;
   
   NPBool     ConvertPoint(double sourceX, double sourceY, NPCoordinateSpace sourceSpace,
                           double *destX, double *destY, NPCoordinateSpace destSpace) MOZ_OVERRIDE;
   
-  virtual NPError InitAsyncSurface(NPSize *size, NPImageFormat format,
-                                   void *initData, NPAsyncSurface *surface) MOZ_OVERRIDE;
-  virtual NPError FinalizeAsyncSurface(NPAsyncSurface *surface) MOZ_OVERRIDE;
-  virtual void SetCurrentAsyncSurface(NPAsyncSurface *surface, NPRect *changed) MOZ_OVERRIDE;
-
   /**
    * Get the type of the HTML tag that was used ot instantiate this
    * plugin.  Currently supported tags are EMBED, OBJECT and APPLET.
    */
   NS_IMETHOD GetTagType(nsPluginTagType *aResult);
 
   void GetParameters(nsTArray<mozilla::dom::MozPluginParameter>& parameters);
   void GetAttributes(nsTArray<mozilla::dom::MozPluginParameter>& attributes);
--- a/dom/plugins/ipc/PPluginInstance.ipdl
+++ b/dom/plugins/ipc/PPluginInstance.ipdl
@@ -12,28 +12,25 @@ include protocol PStreamNotify;
 include protocol PPluginSurface;
 
 include "mozilla/GfxMessageUtils.h";
 
 using NPError from "npapi.h";
 using struct mozilla::plugins::NPRemoteWindow from "mozilla/plugins/PluginMessageUtils.h";
 using struct mozilla::plugins::NPRemoteEvent from "mozilla/plugins/PluginMessageUtils.h";
 using NPRect from "npapi.h";
-using NPImageFormat from "npapi.h";
 using NPNURLVariable from "npapi.h";
 using NPCoordinateSpace from "npapi.h";
 using NPNVariable from "npapi.h";
 using mozilla::plugins::NativeWindowHandle from "mozilla/plugins/PluginMessageUtils.h";
 using gfxSurfaceType from "gfxTypes.h";
 using gfxIntSize from "nsSize.h";
 using struct mozilla::null_t from "ipc/IPCMessageUtils.h";
 using mozilla::plugins::WindowsSharedMemoryHandle from "mozilla/plugins/PluginMessageUtils.h";
-using mozilla::plugins::DXGISharedSurfaceHandle from "mozilla/plugins/PluginMessageUtils.h";
-using mozilla::CrossProcessMutexHandle from "mozilla/ipc/CrossProcessMutex.h";
-using struct SurfaceDescriptorX11 from "gfxipc/ShadowLayerUtils.h";
+using mozilla::layers::SurfaceDescriptorX11 from "gfxipc/ShadowLayerUtils.h";
 using struct nsIntRect from "nsRect.h";
 
 namespace mozilla {
 namespace plugins {
 
 struct IOSurfaceDescriptor {
   uint32_t surfaceId;
   double contentsScaleFactor;
@@ -52,31 +49,16 @@ union SurfaceDescriptor {
   null_t;
 };
 
 union OptionalShmem {
   Shmem;
   null_t;
 };
 
-union AsyncSurfaceDescriptor {
-  Shmem;
-  DXGISharedSurfaceHandle;
-};
-
-struct NPRemoteAsyncSurface
-{
-  uint32_t version;
-  gfxIntSize size;
-  NPImageFormat format;
-  uint32_t      stride;
-  AsyncSurfaceDescriptor data;
-  uintptr_t hostPtr;
-};
-
 intr protocol PPluginInstance
 {
   manager PPluginModule;
 
   manages PPluginBackgroundDestroyer;
   manages PPluginScriptableObject;
   manages PBrowserStream;
   manages PPluginStream;
@@ -157,17 +139,17 @@ parent:
 
   intr NPN_SetValue_NPPVpluginWindow(bool windowed)
     returns (NPError result);
   intr NPN_SetValue_NPPVpluginTransparent(bool transparent)
     returns (NPError result);
   intr NPN_SetValue_NPPVpluginUsesDOMForCursor(bool useDOMForCursor)
     returns (NPError result);
   intr NPN_SetValue_NPPVpluginDrawingModel(int drawingModel)
-    returns (OptionalShmem remoteImageData, CrossProcessMutexHandle mutex, NPError result);
+    returns (NPError result);
   intr NPN_SetValue_NPPVpluginEventModel(int eventModel)
     returns (NPError result);
 
   intr NPN_GetURL(nsCString url, nsCString target)
     returns (NPError result);
   intr NPN_PostURL(nsCString url, nsCString target, nsCString buffer, bool file)
     returns (NPError result);
 
@@ -215,27 +197,21 @@ parent:
     returns (nsCString username, nsCString password, NPError result);
 
   intr NPN_ConvertPoint(double sourceX, bool ignoreDestX, double sourceY, bool ignoreDestY, NPCoordinateSpace sourceSpace,
                        NPCoordinateSpace destSpace)
     returns (double destX, double destY, bool result);
 
   async RedrawPlugin();
 
-  intr NPN_InitAsyncSurface(gfxIntSize size, NPImageFormat format)
-    returns (NPRemoteAsyncSurface surfData, bool result);
-
   // Send notification that a plugin tried to negotiate Carbon NPAPI so that
   // users can be notified that restarting the browser in i386 mode may allow
   // them to use the plugin.
   sync NegotiatedCarbon();
 
-  // Notifies us we can release a Async Surface DXGI texture.
-  async ReleaseDXGISharedSurface(DXGISharedSurfaceHandle handle);
-
 both:
   async PPluginScriptableObject();
 
 child:
   /* NPP_NewStream */
   intr PBrowserStream(nsCString url,
                      uint32_t length,
                      uint32_t lastmodified,
--- a/dom/plugins/ipc/PPluginModule.ipdl
+++ b/dom/plugins/ipc/PPluginModule.ipdl
@@ -44,17 +44,17 @@ both:
   // a nested event loop for the current interrupt call.
   async ProcessNativeEventsInInterruptCall();
 
 child:
   // Forces the child process to update its plugin function table.
   intr NP_GetEntryPoints()
     returns (NPError rv);
 
-  intr NP_Initialize(uint32_t aFlags)
+  intr NP_Initialize()
     returns (NPError rv);
 
   intr PPluginInstance(nsCString aMimeType,
                       uint16_t aMode,
                       nsCString[] aNames,
                       nsCString[] aValues)
     returns (NPError rv);
 
--- a/dom/plugins/ipc/PluginInstanceChild.cpp
+++ b/dom/plugins/ipc/PluginInstanceChild.cpp
@@ -120,17 +120,16 @@ CreateDrawTargetForSurface(gfxASurface *
 }
 
 PluginInstanceChild::PluginInstanceChild(const NPPluginFuncs* aPluginIface)
     : mPluginIface(aPluginIface)
 #if defined(XP_MACOSX)
     , mContentsScaleFactor(1.0)
 #endif
     , mDrawingModel(kDefaultDrawingModel)
-    , mCurrentAsyncSurface(0)
     , mAsyncInvalidateMutex("PluginInstanceChild::mAsyncInvalidateMutex")
     , mAsyncInvalidateTask(0)
     , mCachedWindowActor(nullptr)
     , mCachedElementActor(nullptr)
 #ifdef MOZ_WIDGET_GTK
     , mXEmbed(false)
 #endif // MOZ_WIDGET_GTK
 #if defined(OS_WIN)
@@ -376,35 +375,16 @@ PluginInstanceChild::NPN_GetValue(NPNVar
         NPError result;
         CallNPN_GetValue_NPNVnetscapeWindow(static_cast<XID*>(aValue), &result);
         return result;
 #else
         return NPERR_GENERIC_ERROR;
 #endif
     }
 
-    case NPNVsupportsAsyncBitmapSurfaceBool: {
-#ifdef XP_WIN
-        *((NPBool*)aValue) = PluginModuleChild::current()->AsyncDrawingAllowed();
-#else
-        // We do not support non-windows yet.
-        *((NPBool*)aValue) = false;
-#endif
-        return NPERR_NO_ERROR;
-    }
-
-#ifdef XP_WIN
-    case NPNVsupportsAsyncWindowsDXGISurfaceBool: {
-        bool val;
-        CallNPN_GetValue_DrawingModelSupport(NPNVsupportsAsyncWindowsDXGISurfaceBool, &val);
-        *((NPBool*)aValue) = val;
-        return NPERR_NO_ERROR;
-    }
-#endif
-
 #ifdef XP_MACOSX
    case NPNVsupportsCoreGraphicsBool: {
         *((NPBool*)aValue) = true;
         return NPERR_NO_ERROR;
     }
 
     case NPNVsupportsCoreAnimationBool: {
         *((NPBool*)aValue) = nsCocoaFeatures::SupportCoreAnimationPlugins();
@@ -538,34 +518,19 @@ PluginInstanceChild::NPN_SetValue(NPPVar
         }
         return rv;
     }
 
     case NPPVpluginDrawingModel: {
         NPError rv;
         int drawingModel = (int16_t) (intptr_t) aValue;
 
-        if (!PluginModuleChild::current()->AsyncDrawingAllowed() &&
-            IsDrawingModelAsync(drawingModel)) {
-            return NPERR_GENERIC_ERROR;
-        }              
-
-        CrossProcessMutexHandle handle;
-        OptionalShmem optionalShmem;
-        if (!CallNPN_SetValue_NPPVpluginDrawingModel(drawingModel, &optionalShmem, &handle, &rv))
+        if (!CallNPN_SetValue_NPPVpluginDrawingModel(drawingModel, &rv))
             return NPERR_GENERIC_ERROR;
 
-        if (IsDrawingModelAsync(drawingModel)) {
-            if (optionalShmem.type() != OptionalShmem::TShmem) {
-                return NPERR_GENERIC_ERROR;
-            }
-            mRemoteImageDataShmem = optionalShmem.get_Shmem();
-            mRemoteImageData = mRemoteImageDataShmem.get<RemoteImageData>();
-            mRemoteImageDataMutex = new CrossProcessMutex(handle);
-        }
         mDrawingModel = drawingModel;
 
 #ifdef XP_MACOSX
         if (drawingModel == NPDrawingModelCoreAnimation) {
             mCARefreshTimer = ScheduleTimer(DEFAULT_REFRESH_MS, true, CAUpdate);
         }
 #endif
 
@@ -2480,222 +2445,16 @@ PluginInstanceChild::NPN_URLRedirectResp
         if (sn->mClosure == notifyData) {
             sn->SendRedirectNotifyResponse(static_cast<bool>(allow));
             return;
         }
     }
     NS_ASSERTION(false, "Couldn't find stream for redirect response!");
 }
 
-NPError
-PluginInstanceChild::DeallocateAsyncBitmapSurface(NPAsyncSurface *aSurface)
-{
-    AsyncBitmapData* data;
-    
-    if (!mAsyncBitmaps.Get(aSurface, &data)) {
-        return NPERR_INVALID_PARAM;
-    }
-
-    DeallocShmem(data->mShmem);
-    aSurface->bitmap.data = nullptr;
-
-    mAsyncBitmaps.Remove(aSurface);
-    return NPERR_NO_ERROR;
-}
-
-bool
-PluginInstanceChild::IsAsyncDrawing()
-{
-    return IsDrawingModelAsync(mDrawingModel);
-}
-
-NPError
-PluginInstanceChild::NPN_InitAsyncSurface(NPSize *size, NPImageFormat format,
-                                          void *initData, NPAsyncSurface *surface)
-{
-    AssertPluginThread();
-
-    surface->bitmap.data = nullptr;
-
-    if (!IsAsyncDrawing()) {
-        return NPERR_GENERIC_ERROR;
-    }
-
-    switch (mDrawingModel) {
-    case NPDrawingModelAsyncBitmapSurface: {
-            if (mAsyncBitmaps.Get(surface, nullptr)) {
-                return NPERR_INVALID_PARAM;
-            }
-
-            if (size->width < 0 || size->height < 0) {
-                return NPERR_INVALID_PARAM;
-            }
-
-
-            bool result;
-            NPRemoteAsyncSurface remote;
-
-            if (!CallNPN_InitAsyncSurface(gfxIntSize(size->width, size->height), format, &remote, &result) || !result) {
-                return NPERR_OUT_OF_MEMORY_ERROR;
-            }
-
-            NS_ABORT_IF_FALSE(remote.data().get_Shmem().IsWritable(),
-                "Failed to create writable shared memory.");
-            
-            AsyncBitmapData *data = new AsyncBitmapData;
-            mAsyncBitmaps.Put(surface, data);
-
-            data->mRemotePtr = (void*)remote.hostPtr();
-            data->mShmem = remote.data().get_Shmem();
-
-            surface->bitmap.data = data->mShmem.get<unsigned char>();
-            surface->bitmap.stride = remote.stride();
-            surface->format = remote.format();
-            surface->size.width = remote.size().width;
-            surface->size.height = remote.size().height;
-
-            return NPERR_NO_ERROR;
-        }
-#ifdef XP_WIN
-    case NPDrawingModelAsyncWindowsDXGISurface: {
-            if (size->width < 0 || size->height < 0) {
-                return NPERR_INVALID_PARAM;
-            }
-            bool result;
-            NPRemoteAsyncSurface remote;
-
-            if (!CallNPN_InitAsyncSurface(gfxIntSize(size->width, size->height), format, &remote, &result) || !result) {
-                return NPERR_OUT_OF_MEMORY_ERROR;
-            }
-
-            surface->format = remote.format();
-            surface->size.width = remote.size().width;
-            surface->size.height = remote.size().height;
-            surface->sharedHandle = remote.data().get_DXGISharedSurfaceHandle();
-
-            return NPERR_NO_ERROR;
-        }
-#endif
-    }
-
-    return NPERR_GENERIC_ERROR;
-}
-
-NPError
-PluginInstanceChild::NPN_FinalizeAsyncSurface(NPAsyncSurface *surface)
-{
-    AssertPluginThread();
-
-    if (!IsAsyncDrawing()) {
-        return NPERR_GENERIC_ERROR;
-    }
-
-    switch (mDrawingModel) {
-    case NPDrawingModelAsyncBitmapSurface: {
-            AsyncBitmapData *bitmapData;
-
-            if (!mAsyncBitmaps.Get(surface, &bitmapData)) {
-                return NPERR_GENERIC_ERROR;
-            }
-
-            {
-                CrossProcessMutexAutoLock autoLock(*mRemoteImageDataMutex);
-                RemoteImageData *data = mRemoteImageData;
-                if (data->mBitmap.mData == bitmapData->mRemotePtr) {
-                    data->mBitmap.mData = nullptr;
-                    data->mSize = IntSize(0, 0);
-                    data->mWasUpdated = true;
-                }
-            }
-
-            return DeallocateAsyncBitmapSurface(surface);
-        }
-#ifdef XP_WIN
-    case NPDrawingModelAsyncWindowsDXGISurface: {
-            
-            {
-                CrossProcessMutexAutoLock autoLock(*mRemoteImageDataMutex);
-                RemoteImageData *data = mRemoteImageData;
-                if (data->mTextureHandle == surface->sharedHandle) {
-                    data->mTextureHandle = nullptr;
-                    data->mSize = IntSize(0, 0);
-                    data->mWasUpdated = true;
-                }
-            }
-
-            SendReleaseDXGISharedSurface(surface->sharedHandle);
-            return NPERR_NO_ERROR;
-        }
-#endif
-    }
-
-    return NPERR_GENERIC_ERROR;
-}
-
-void
-PluginInstanceChild::NPN_SetCurrentAsyncSurface(NPAsyncSurface *surface, NPRect *changed)
-{
-    if (!IsAsyncDrawing()) {
-        return;
-    }
-
-    RemoteImageData *data = mRemoteImageData;
-
-    if (!surface) {
-        CrossProcessMutexAutoLock autoLock(*mRemoteImageDataMutex);
-        data->mBitmap.mData = nullptr;
-        data->mSize = IntSize(0, 0);
-        data->mWasUpdated = true;
-    } else {
-        switch (mDrawingModel) {
-        case NPDrawingModelAsyncBitmapSurface:
-            {
-                AsyncBitmapData *bitmapData;
-        
-                if (!mAsyncBitmaps.Get(surface, &bitmapData)) {
-                    return;
-                }
-              
-                CrossProcessMutexAutoLock autoLock(*mRemoteImageDataMutex);
-                data->mBitmap.mData = (unsigned char*)bitmapData->mRemotePtr;
-                data->mSize = IntSize(surface->size.width, surface->size.height);
-                data->mFormat = surface->format == NPImageFormatBGRX32 ?
-                                RemoteImageData::BGRX32 : RemoteImageData::BGRA32;
-                data->mBitmap.mStride = surface->bitmap.stride;
-                data->mWasUpdated = true;
-                break;
-            }
-#ifdef XP_WIN
-        case NPDrawingModelAsyncWindowsDXGISurface:
-            {
-                CrossProcessMutexAutoLock autoLock(*mRemoteImageDataMutex);
-                data->mType = RemoteImageData::DXGI_TEXTURE_HANDLE;
-                data->mSize = IntSize(surface->size.width, surface->size.height);
-                data->mFormat = surface->format == NPImageFormatBGRX32 ?
-                                RemoteImageData::BGRX32 : RemoteImageData::BGRA32;
-                data->mTextureHandle = surface->sharedHandle;
-
-                data->mWasUpdated = true;
-                break;
-            }
-#endif
-        }
-    }
-
-    {
-        MutexAutoLock autoLock(mAsyncInvalidateMutex);
-        if (!mAsyncInvalidateTask) {
-            mAsyncInvalidateTask = 
-                NewRunnableMethod<PluginInstanceChild, void (PluginInstanceChild::*)()>
-                    (this, &PluginInstanceChild::DoAsyncRedraw);
-            ProcessChild::message_loop()->PostTask(FROM_HERE, mAsyncInvalidateTask);
-        }
-    }
-}
-
 void
 PluginInstanceChild::DoAsyncRedraw()
 {
     {
         MutexAutoLock autoLock(mAsyncInvalidateMutex);
         mAsyncInvalidateTask = nullptr;
     }
 
@@ -3193,17 +2952,17 @@ PluginInstanceChild::PaintRectToSurface(
 
     if (mIsTransparent && !CanPaintOnBackground()) {
         RefPtr<DrawTarget> dt = CreateDrawTargetForSurface(renderSurface);
         gfx::Rect rect(plPaintRect.x, plPaintRect.y,
                        plPaintRect.width, plPaintRect.height);
         // Moz2D treats OP_SOURCE operations as unbounded, so we need to
         // clip to the rect that we want to fill:
         dt->PushClipRect(rect);
-        dt->FillRect(rect, ColorPattern(ToColor(aColor)),
+        dt->FillRect(rect, ColorPattern(ToColor(aColor)), // aColor is already a device color
                      DrawOptions(1.f, CompositionOp::OP_SOURCE));
         dt->PopClip();
         dt->Flush();
     }
 
     PaintRectToPlatformSurface(plPaintRect, renderSurface);
 
     if (renderSurface != aSurface) {
@@ -3914,26 +3673,16 @@ PluginInstanceChild::ClearAllSurfaces()
         mCGLayer = nullptr;
     }
 
     mDoubleBufferCARenderer.ClearFrontSurface();
     mDoubleBufferCARenderer.ClearBackSurface();
 #endif
 }
 
-PLDHashOperator
-PluginInstanceChild::DeleteSurface(NPAsyncSurface* surf, nsAutoPtr<AsyncBitmapData> &data, void* userArg)
-{
-    PluginInstanceChild *inst = static_cast<PluginInstanceChild*>(userArg);
-
-    inst->DeallocShmem(data->mShmem);
-
-    return PL_DHASH_REMOVE;
-}
-
 bool
 PluginInstanceChild::AnswerNPP_Destroy(NPError* aResult)
 {
     PLUGIN_LOG_DEBUG_METHOD;
     AssertPluginThread();
     *aResult = NPERR_NO_ERROR;
 
 #if defined(OS_WIN)
@@ -3999,21 +3748,16 @@ PluginInstanceChild::AnswerNPP_Destroy(N
 
     // Pending async calls are discarded, not delivered. This matches the
     // in-process behavior.
     for (uint32_t i = 0; i < mPendingAsyncCalls.Length(); ++i)
         mPendingAsyncCalls[i]->Cancel();
 
     mPendingAsyncCalls.Clear();
     
-    if (mAsyncBitmaps.Count()) {
-        NS_ERROR("Not all AsyncBitmaps were finalized by a plugin!");
-        mAsyncBitmaps.Enumerate(DeleteSurface, this);
-    }
-
 #ifdef MOZ_WIDGET_GTK
     if (mWindow.type == NPWindowTypeWindow && !mXEmbed) {
       xt_client_xloop_destroy();
     }
 #endif
 #if defined(MOZ_X11) && defined(XP_UNIX) && !defined(XP_MACOSX)
     DeleteWindow();
 #endif
--- a/dom/plugins/ipc/PluginInstanceChild.h
+++ b/dom/plugins/ipc/PluginInstanceChild.h
@@ -235,34 +235,26 @@ public:
     void UnscheduleTimer(uint32_t id);
 
     void AsyncCall(PluginThreadCallback aFunc, void* aUserData);
 
     int GetQuirks();
 
     void NPN_URLRedirectResponse(void* notifyData, NPBool allow);
 
-    NPError NPN_InitAsyncSurface(NPSize *size, NPImageFormat format,
-                                 void *initData, NPAsyncSurface *surface);
-    NPError NPN_FinalizeAsyncSurface(NPAsyncSurface *surface);
-
-    void NPN_SetCurrentAsyncSurface(NPAsyncSurface *surface, NPRect *changed);
-
     void DoAsyncRedraw();
 private:
     friend class PluginModuleChild;
 
     NPError
     InternalGetNPObjectForValue(NPNVariable aValue,
                                 NPObject** aObject);
 
     bool IsAsyncDrawing();
 
-    NPError DeallocateAsyncBitmapSurface(NPAsyncSurface *aSurface);
-
     virtual bool RecvUpdateBackground(const SurfaceDescriptor& aBackground,
                                       const nsIntRect& aRect) MOZ_OVERRIDE;
 
     virtual PPluginBackgroundDestroyerChild*
     AllocPPluginBackgroundDestroyerChild() MOZ_OVERRIDE;
 
     virtual bool
     RecvPPluginBackgroundDestroyerConstructor(PPluginBackgroundDestroyerChild* aActor) MOZ_OVERRIDE;
@@ -360,27 +352,17 @@ private:
 #endif
     const NPPluginFuncs* mPluginIface;
     NPP_t mData;
     NPWindow mWindow;
 #if defined(XP_MACOSX)
     double mContentsScaleFactor;
 #endif
     int16_t               mDrawingModel;
-    NPAsyncSurface* mCurrentAsyncSurface;
-    struct AsyncBitmapData {
-      void *mRemotePtr;
-      Shmem mShmem;
-    };
 
-    static PLDHashOperator DeleteSurface(NPAsyncSurface* surf, nsAutoPtr<AsyncBitmapData> &data, void* userArg);
-    nsClassHashtable<nsPtrHashKey<NPAsyncSurface>, AsyncBitmapData> mAsyncBitmaps;
-    Shmem mRemoteImageDataShmem;
-    mozilla::layers::RemoteImageData *mRemoteImageData;
-    nsAutoPtr<CrossProcessMutex> mRemoteImageDataMutex;
     mozilla::Mutex mAsyncInvalidateMutex;
     CancelableTask *mAsyncInvalidateTask;
 
     // Cached scriptable actors to avoid IPC churn
     PluginScriptableObjectChild* mCachedWindowActor;
     PluginScriptableObjectChild* mCachedElementActor;
 
 #if defined(MOZ_X11) && defined(XP_UNIX) && !defined(XP_MACOSX)
--- a/dom/plugins/ipc/PluginInstanceParent.cpp
+++ b/dom/plugins/ipc/PluginInstanceParent.cpp
@@ -103,23 +103,16 @@ PluginInstanceParent::~PluginInstancePar
 #endif
 #if defined(MOZ_WIDGET_COCOA)
     if (mShWidth != 0 && mShHeight != 0) {
         DeallocShmem(mShSurface);
     }
     if (mShColorSpace)
         ::CGColorSpaceRelease(mShColorSpace);
 #endif
-    if (mRemoteImageDataShmem.IsWritable()) {
-        if (mImageContainer) {
-            mImageContainer->SetRemoteImageData(nullptr, nullptr);
-            mImageContainer->SetCompositionNotifySink(nullptr);
-        }
-        DeallocShmem(mRemoteImageDataShmem);
-    }
 }
 
 bool
 PluginInstanceParent::Init()
 {
     return true;
 }
 
@@ -249,22 +242,16 @@ PluginInstanceParent::InternalGetValueFo
     }
 
     *aValue = nullptr;
     *aResult = result;
     return true;
 }
 
 bool
-PluginInstanceParent::IsAsyncDrawing()
-{
-  return IsDrawingModelAsync(mDrawingModel);
-}
-
-bool
 PluginInstanceParent::AnswerNPN_GetValue_NPNVWindowNPObject(
                                          PPluginScriptableObjectParent** aValue,
                                          NPError* aResult)
 {
     return InternalGetValueForNPObject(NPNVWindowNPObject, aValue, aResult);
 }
 
 bool
@@ -285,27 +272,16 @@ PluginInstanceParent::AnswerNPN_GetValue
     *value = v;
     return true;
 }
 
 bool
 PluginInstanceParent::AnswerNPN_GetValue_DrawingModelSupport(const NPNVariable& model, bool* value)
 {
     *value = false;
-
-#ifdef XP_WIN
-    switch (model) {
-        case NPNVsupportsAsyncWindowsDXGISurfaceBool: {
-            if (gfxWindowsPlatform::GetPlatform()->GetRenderMode() == gfxWindowsPlatform::RENDER_DIRECT2D) {
-                *value = true;
-            }
-        }
-    }
-#endif
-
     return true;
 }
 
 bool
 PluginInstanceParent::AnswerNPN_GetValue_NPNVdocumentOrigin(nsCString* value,
                                                             NPError* result)
 {
     void *v = nullptr;
@@ -354,97 +330,44 @@ public:
 
   virtual void DidComposite() { mInstance->DidComposite(); }
 private:
   PluginInstanceParent *mInstance;
 };
 
 bool
 PluginInstanceParent::AnswerNPN_SetValue_NPPVpluginDrawingModel(
-    const int& drawingModel, OptionalShmem *shmem, CrossProcessMutexHandle *mutex, NPError* result)
+    const int& drawingModel, NPError* result)
 {
-    *shmem = null_t();
-
 #ifdef XP_MACOSX
     if (drawingModel == NPDrawingModelCoreAnimation ||
         drawingModel == NPDrawingModelInvalidatingCoreAnimation) {
         // We need to request CoreGraphics otherwise
         // the nsPluginFrame will try to draw a CALayer
         // that can not be shared across process.
         mDrawingModel = drawingModel;
         *result = mNPNIface->setvalue(mNPP, NPPVpluginDrawingModel,
                                   (void*)NPDrawingModelCoreGraphics);
     } else
 #endif
-    if (drawingModel == NPDrawingModelAsyncBitmapSurface
-#ifdef XP_WIN
-        || drawingModel == NPDrawingModelAsyncWindowsDXGISurface
-#endif
-        ) {
-        ImageContainer *container = GetImageContainer();
-        if (!container) {
-            *result = NPERR_GENERIC_ERROR;
-            return true;
-        }
-
-#ifdef XP_WIN
-        if (drawingModel == NPDrawingModelAsyncWindowsDXGISurface &&
-            gfxWindowsPlatform::GetPlatform()->GetRenderMode() != gfxWindowsPlatform::RENDER_DIRECT2D) {
-            *result = NPERR_GENERIC_ERROR;
-            return true;
-        }
-#endif
-
-        mDrawingModel = drawingModel;
-        *result = mNPNIface->setvalue(mNPP, NPPVpluginDrawingModel,
-                                      reinterpret_cast<void*>(static_cast<uintptr_t>(drawingModel)));
-
-
-        if (*result != NPERR_NO_ERROR) {
-            return true;
-        }
-
-        AllocUnsafeShmem(sizeof(RemoteImageData), SharedMemory::TYPE_BASIC, &mRemoteImageDataShmem);
-
-        *shmem = mRemoteImageDataShmem;
-
-        mRemoteImageDataMutex = new CrossProcessMutex("PluginInstanceParent.mRemoteImageDataMutex");
-
-        *mutex = mRemoteImageDataMutex->ShareToProcess(OtherProcess());
-        container->SetRemoteImageData(mRemoteImageDataShmem.get<RemoteImageData>(), mRemoteImageDataMutex);
-
-        mNotifySink = new NotificationSink(this);
-
-        container->SetCompositionNotifySink(mNotifySink);
-    } else if (
+    if (
 #if defined(XP_WIN)
                drawingModel == NPDrawingModelSyncWin
 #elif defined(XP_MACOSX)
                drawingModel == NPDrawingModelOpenGL ||
                drawingModel == NPDrawingModelCoreGraphics
 #elif defined(MOZ_X11)
                drawingModel == NPDrawingModelSyncX
 #else
                false
 #endif
                ) {
-        *shmem = null_t();
-
         mDrawingModel = drawingModel;
         *result = mNPNIface->setvalue(mNPP, NPPVpluginDrawingModel,
                                       (void*)(intptr_t)drawingModel);
-
-        if (mRemoteImageDataShmem.IsWritable()) {
-            if (mImageContainer) {
-                mImageContainer->SetRemoteImageData(nullptr, nullptr);
-                mImageContainer->SetCompositionNotifySink(nullptr);
-            }
-            DeallocShmem(mRemoteImageDataShmem);
-            mRemoteImageDataMutex = nullptr;
-        }
     } else {
         *result = NPERR_GENERIC_ERROR;
     }
     return true;
 }
 
 bool
 PluginInstanceParent::AnswerNPN_SetValue_NPPVpluginEventModel(
@@ -711,22 +634,16 @@ PluginInstanceParent::GetImageContainer(
         return NS_ERROR_NOT_AVAILABLE;
 
     ImageContainer *container = GetImageContainer();
 
     if (!container) {
         return NS_ERROR_FAILURE;
     }
 
-    if (IsAsyncDrawing()) {
-      NS_IF_ADDREF(container);
-      *aContainer = container;
-      return NS_OK;
-    }
-
 #ifdef XP_MACOSX
     if (ioSurface) {
         nsRefPtr<Image> image = container->CreateImage(ImageFormat::MAC_IOSURFACE);
         if (!image) {
             return NS_ERROR_FAILURE;
         }
 
         NS_ASSERTION(image->GetFormat() == ImageFormat::MAC_IOSURFACE, "Wrong format?");
@@ -1182,22 +1099,16 @@ PluginInstanceParent::NPP_HandleEvent(vo
     double scaleFactor = 1.0;
     mNPNIface->getvalue(mNPP, NPNVcontentsScaleFactor, &scaleFactor);
     npremoteevent.contentsScaleFactor = scaleFactor;
 #endif
     int16_t handled = 0;
 
 #if defined(OS_WIN)
     if (mWindowType == NPWindowTypeDrawable) {
-        if (IsAsyncDrawing()) {
-            if (npevent->event == WM_PAINT || npevent->event == DoublePassRenderingEvent()) {
-                // This plugin maintains its own async drawing.
-                return handled;
-            }
-        }
         if (DoublePassRenderingEvent() == npevent->event) {
             return CallPaint(npremoteevent, &handled) && handled;
         }
 
         switch (npevent->event) {
             case WM_PAINT:
             {
                 RECT rect;
@@ -1687,83 +1598,16 @@ PluginInstanceParent::AnswerNPN_ConvertP
                                       ignoreDestX ? nullptr : destX,
                                       ignoreDestY ? nullptr : destY,
                                       destSpace);
 
     return true;
 }
 
 bool
-PluginInstanceParent::AnswerNPN_InitAsyncSurface(const gfxIntSize& size,
-                                                 const NPImageFormat& format,
-                                                 NPRemoteAsyncSurface* surfData,
-                                                 bool* result)
-{
-    if (!IsAsyncDrawing()) {
-        *result = false;
-        return true;
-    }
-
-    switch (mDrawingModel) {
-    case NPDrawingModelAsyncBitmapSurface: {
-            Shmem sharedMem;
-            if (!AllocUnsafeShmem(size.width * size.height * 4, SharedMemory::TYPE_BASIC, &sharedMem)) {
-                *result = false;
-                return true;
-            }
-
-            surfData->size() = size;
-            surfData->hostPtr() = (uintptr_t)sharedMem.get<unsigned char>();
-            surfData->stride() = size.width * 4;
-            surfData->format() = format;
-            surfData->data() = sharedMem;
-            *result = true;
-            return true;
-        }
-#ifdef XP_WIN
-    case NPDrawingModelAsyncWindowsDXGISurface: {
-            ID3D10Device1 *device = gfxWindowsPlatform::GetPlatform()->GetD3D10Device();
-
-            nsRefPtr<ID3D10Texture2D> texture;
-
-            CD3D10_TEXTURE2D_DESC desc(DXGI_FORMAT_B8G8R8A8_UNORM, size.width, size.height, 1, 1);
-            desc.MiscFlags = D3D10_RESOURCE_MISC_SHARED_KEYEDMUTEX;
-            desc.BindFlags = D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE;
-            if (FAILED(device->CreateTexture2D(&desc, nullptr, getter_AddRefs(texture)))) {
-                *result = false;
-                return true;
-            }
-
-            nsRefPtr<IDXGIResource> resource;
-            if (FAILED(texture->QueryInterface(IID_IDXGIResource, getter_AddRefs(resource)))) {
-                *result = false;
-                return true;
-            }
-
-            HANDLE sharedHandle;
-
-            if (FAILED(resource->GetSharedHandle(&sharedHandle))) {
-                *result = false;
-                return true;
-            }
-
-            surfData->size() = size;
-            surfData->data() = sharedHandle;
-            surfData->format() = format;
-
-            mTextureMap.Put(sharedHandle, texture);
-            *result = true;
-        }
-#endif
-    }
-
-    return true;
-}
-
-bool
 PluginInstanceParent::RecvRedrawPlugin()
 {
     nsNPAPIPluginInstance *inst = static_cast<nsNPAPIPluginInstance*>(mNPP->ndata);
     if (!inst) {
         return false;
     }
 
     inst->RedrawPlugin();
@@ -1776,25 +1620,16 @@ PluginInstanceParent::RecvNegotiatedCarb
     nsNPAPIPluginInstance *inst = static_cast<nsNPAPIPluginInstance*>(mNPP->ndata);
     if (!inst) {
         return false;
     }
     inst->CarbonNPAPIFailure();
     return true;
 }
 
-bool
-PluginInstanceParent::RecvReleaseDXGISharedSurface(const DXGISharedSurfaceHandle &aHandle)
-{
-#ifdef XP_WIN
-    mTextureMap.Remove(aHandle);
-#endif
-    return true;
-}
-
 #if defined(OS_WIN)
 
 /*
   plugin focus changes between processes
 
   focus from dom -> child:
     Focus manager calls on widget to set the focus on the window.
     We pick up the resulting wm_setfocus event here, and forward
--- a/dom/plugins/ipc/PluginInstanceParent.h
+++ b/dom/plugins/ipc/PluginInstanceParent.h
@@ -114,18 +114,16 @@ public:
     virtual bool
     AnswerNPN_SetValue_NPPVpluginTransparent(const bool& transparent,
                                              NPError* result) MOZ_OVERRIDE;
     virtual bool
     AnswerNPN_SetValue_NPPVpluginUsesDOMForCursor(const bool& useDOMForCursor,
                                                   NPError* result) MOZ_OVERRIDE;
     virtual bool
     AnswerNPN_SetValue_NPPVpluginDrawingModel(const int& drawingModel,
-                                              OptionalShmem *remoteImageData,
-                                              CrossProcessMutexHandle *mutex,
                                               NPError* result) MOZ_OVERRIDE;
     virtual bool
     AnswerNPN_SetValue_NPPVpluginEventModel(const int& eventModel,
                                              NPError* result) MOZ_OVERRIDE;
 
     virtual bool
     AnswerNPN_GetURL(const nsCString& url, const nsCString& target,
                      NPError *result) MOZ_OVERRIDE;
@@ -202,29 +200,21 @@ public:
                            const bool&   ignoreDestY,
                            const NPCoordinateSpace& sourceSpace,
                            const NPCoordinateSpace& destSpace,
                            double *destX,
                            double *destY,
                            bool *result) MOZ_OVERRIDE;
 
     virtual bool
-    AnswerNPN_InitAsyncSurface(const gfxIntSize& size,
-                               const NPImageFormat& format,
-                               NPRemoteAsyncSurface* surfData,
-                               bool* result) MOZ_OVERRIDE;
-
-    virtual bool
     RecvRedrawPlugin() MOZ_OVERRIDE;
 
     virtual bool
     RecvNegotiatedCarbon() MOZ_OVERRIDE;
 
-    virtual bool RecvReleaseDXGISharedSurface(const DXGISharedSurfaceHandle &aHandle) MOZ_OVERRIDE;
-
     NPError NPP_SetWindow(const NPWindow* aWindow);
 
     NPError NPP_GetValue(NPPVariable variable, void* retval);
     NPError NPP_SetValue(NPNVariable variable, void* value);
 
     void NPP_URLRedirectNotify(const char* url, int32_t status,
                                void* notifyData);
 
@@ -296,25 +286,21 @@ private:
 
     virtual bool
     DeallocPPluginBackgroundDestroyerParent(PPluginBackgroundDestroyerParent* aActor) MOZ_OVERRIDE;
 
     bool InternalGetValueForNPObject(NPNVariable aVariable,
                                      PPluginScriptableObjectParent** aValue,
                                      NPError* aResult);
 
-    bool IsAsyncDrawing();
-
 private:
     PluginModuleParent* mParent;
     NPP mNPP;
     const NPNetscapeFuncs* mNPNIface;
     NPWindowType mWindowType;
-    Shmem mRemoteImageDataShmem;
-    nsAutoPtr<CrossProcessMutex> mRemoteImageDataMutex;
     int16_t            mDrawingModel;
     nsAutoPtr<mozilla::layers::CompositionNotifySink> mNotifySink;
 
     nsDataHashtable<nsPtrHashKey<NPObject>, PluginScriptableObjectParent*> mScriptableObjects;
 
 #if defined(OS_WIN)
 private:
     // Used in rendering windowless plugins in other processes.
--- a/dom/plugins/ipc/PluginMessageUtils.h
+++ b/dom/plugins/ipc/PluginMessageUtils.h
@@ -49,26 +49,16 @@ MediateRace(const mozilla::ipc::MessageC
 
 std::string
 MungePluginDsoPath(const std::string& path);
 std::string
 UnmungePluginDsoPath(const std::string& munged);
 
 extern PRLogModuleInfo* GetPluginLog();
 
-const uint32_t kAllowAsyncDrawing = 0x1;
-
-inline bool IsDrawingModelAsync(int16_t aModel) {
-  return aModel == NPDrawingModelAsyncBitmapSurface
-#ifdef XP_WIN
-         || aModel == NPDrawingModelAsyncWindowsDXGISurface
-#endif
-         ;
-}
-
 #if defined(_MSC_VER)
 #define FULLFUNCTION __FUNCSIG__
 #elif defined(__GNUC__)
 #define FULLFUNCTION __PRETTY_FUNCTION__
 #else
 #define FULLFUNCTION __FUNCTION__
 #endif
 
@@ -333,42 +323,16 @@ struct ParamTraits<NPWindowType>
 
   static void Log(const paramType& aParam, std::wstring* aLog)
   {
     aLog->append(StringPrintf(L"%d", int16_t(aParam)));
   }
 };
 
 template <>
-struct ParamTraits<NPImageFormat>
-{
-  typedef NPImageFormat paramType;
-
-  static void Write(Message* aMsg, const paramType& aParam)
-  {
-    aMsg->WriteInt16(int16_t(aParam));
-  }
-
-  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
-  {
-    int16_t result;
-    if (aMsg->ReadInt16(aIter, &result)) {
-      *aResult = paramType(result);
-      return true;
-    }
-    return false;
-  }
-
-  static void Log(const paramType& aParam, std::wstring* aLog)
-  {
-    aLog->append(StringPrintf(L"%d", int16_t(aParam)));
-  }
-};
-
-template <>
 struct ParamTraits<mozilla::plugins::NPRemoteWindow>
 {
   typedef mozilla::plugins::NPRemoteWindow paramType;
 
   static void Write(Message* aMsg, const paramType& aParam)
   {
     aMsg->WriteUInt64(aParam.window);
     WriteParam(aMsg, aParam.x);
--- a/dom/plugins/ipc/PluginModuleChild.cpp
+++ b/dom/plugins/ipc/PluginModuleChild.cpp
@@ -940,27 +940,16 @@ static NPError
 static NPBool
 _convertpoint(NPP instance, 
               double sourceX, double sourceY, NPCoordinateSpace sourceSpace,
               double *destX, double *destY, NPCoordinateSpace destSpace);
 
 static void
 _urlredirectresponse(NPP instance, void* notifyData, NPBool allow);
 
-static NPError
-_initasyncsurface(NPP instance, NPSize *size,
-                  NPImageFormat format, void *initData,
-                  NPAsyncSurface *surface);
-
-static NPError
-_finalizeasyncsurface(NPP instance, NPAsyncSurface *surface);
-
-static void
-_setcurrentasyncsurface(NPP instance, NPAsyncSurface *surface, NPRect *changed);
-
 } /* namespace child */
 } /* namespace plugins */
 } /* namespace mozilla */
 
 const NPNetscapeFuncs PluginModuleChild::sBrowserFuncs = {
     sizeof(sBrowserFuncs),
     (NP_VERSION_MAJOR << 8) + NP_VERSION_MINOR,
     mozilla::plugins::child::_geturl,
@@ -1012,20 +1001,17 @@ const NPNetscapeFuncs PluginModuleChild:
     mozilla::plugins::child::_setvalueforurl,
     mozilla::plugins::child::_getauthenticationinfo,
     mozilla::plugins::child::_scheduletimer,
     mozilla::plugins::child::_unscheduletimer,
     mozilla::plugins::child::_popupcontextmenu,
     mozilla::plugins::child::_convertpoint,
     nullptr, // handleevent, unimplemented
     nullptr, // unfocusinstance, unimplemented
-    mozilla::plugins::child::_urlredirectresponse,
-    mozilla::plugins::child::_initasyncsurface,
-    mozilla::plugins::child::_finalizeasyncsurface,
-    mozilla::plugins::child::_setcurrentasyncsurface
+    mozilla::plugins::child::_urlredirectresponse
 };
 
 PluginInstanceChild*
 InstCast(NPP aNPP)
 {
     NS_ABORT_IF_FALSE(!!(aNPP->ndata), "nil instance");
     return static_cast<PluginInstanceChild*>(aNPP->ndata);
 }
@@ -1803,36 +1789,16 @@ NPBool
 }
 
 void
 _urlredirectresponse(NPP instance, void* notifyData, NPBool allow)
 {
     InstCast(instance)->NPN_URLRedirectResponse(notifyData, allow);
 }
 
-NPError
-_initasyncsurface(NPP instance, NPSize *size,
-                  NPImageFormat format, void *initData,
-                  NPAsyncSurface *surface)
-{
-    return InstCast(instance)->NPN_InitAsyncSurface(size, format, initData, surface);
-}
-
-NPError
-_finalizeasyncsurface(NPP instance, NPAsyncSurface *surface)
-{
-    return InstCast(instance)->NPN_FinalizeAsyncSurface(surface);
-}
-
-void
-_setcurrentasyncsurface(NPP instance, NPAsyncSurface *surface, NPRect *changed)
-{
-    InstCast(instance)->NPN_SetCurrentAsyncSurface(surface, changed);
-}
-
 } /* namespace child */
 } /* namespace plugins */
 } /* namespace mozilla */
 
 //-----