Merge m-c to fx-team. a=merge
authorRyan VanderMeulen <ryanvm@gmail.com>
Sun, 30 Aug 2015 15:57:17 -0400
changeset 260035 5eda6b9070bc4ef245009926fb0e8b4dfdfb02dc
parent 260034 a877d212f6b091ade73854ba65bf4977cdf809e2 (current diff)
parent 259991 2ad5077d86ba81b667de45ccc986dbd2ce633cc4 (diff)
child 260036 b2b0c1f6e8f8e51e462d21c18ce1e3d606017334
push id29298
push userryanvm@gmail.com
push dateMon, 31 Aug 2015 02:09:10 +0000
treeherdermozilla-central@f2518b8a7b97 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone43.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 m-c to fx-team. a=merge
testing/web-platform/mozilla/meta/service-workers/service-worker/invalid-header.https.html.ini
--- a/README.txt
+++ b/README.txt
@@ -17,11 +17,11 @@ If you have a question about developing 
 on http://developer.mozilla.org, you can try asking your question in a
 mozilla.* Usenet group, or on IRC at irc.mozilla.org. [The Mozilla news groups
 are accessible on Google Groups, or news.mozilla.org with a NNTP reader.]
 
 You can download nightly development builds from the Mozilla FTP server.
 Keep in mind that nightly builds, which are used by Mozilla developers for
 testing, may be buggy. Firefox nightlies, for example, can be found at:
 
-    ftp://ftp.mozilla.org/pub/firefox/nightly/latest-trunk/
+    https://archive.mozilla.org/pub/firefox/nightly/latest-mozilla-central/
             - or -
     http://nightly.mozilla.org/
--- a/accessible/base/nsCoreUtils.cpp
+++ b/accessible/base/nsCoreUtils.cpp
@@ -105,20 +105,20 @@ nsCoreUtils::DispatchClickEvent(nsITreeB
   nsRefPtr<nsPresContext> presContext = presShell->GetPresContext();
 
   int32_t cnvdX = presContext->CSSPixelsToDevPixels(tcX + x + 1) +
     presContext->AppUnitsToDevPixels(offset.x);
   int32_t cnvdY = presContext->CSSPixelsToDevPixels(tcY + y + 1) +
     presContext->AppUnitsToDevPixels(offset.y);
 
   // XUL is just desktop, so there is no real reason for senfing touch events.
-  DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN, cnvdX, cnvdY,
+  DispatchMouseEvent(eMouseDown, cnvdX, cnvdY,
                      tcContent, tcFrame, presShell, rootWidget);
 
-  DispatchMouseEvent(NS_MOUSE_BUTTON_UP, cnvdX, cnvdY,
+  DispatchMouseEvent(eMouseUp, cnvdX, cnvdY,
                      tcContent, tcFrame, presShell, rootWidget);
 }
 
 void
 nsCoreUtils::DispatchMouseEvent(EventMessage aMessage, int32_t aX, int32_t aY,
                                 nsIContent *aContent, nsIFrame *aFrame,
                                 nsIPresShell *aPresShell, nsIWidget *aRootWidget)
 {
--- a/accessible/generic/Accessible.cpp
+++ b/accessible/generic/Accessible.cpp
@@ -532,17 +532,17 @@ Accessible::ChildAtPoint(int32_t aX, int
 
   // Check whether the point is at popup content.
   nsIWidget* rootWidget = rootFrame->GetView()->GetNearestWidget(nullptr);
   NS_ENSURE_TRUE(rootWidget, nullptr);
 
   nsIntRect rootRect;
   rootWidget->GetScreenBounds(rootRect);
 
-  WidgetMouseEvent dummyEvent(true, NS_MOUSE_MOVE, rootWidget,
+  WidgetMouseEvent dummyEvent(true, eMouseMove, rootWidget,
                               WidgetMouseEvent::eSynthesized);
   dummyEvent.refPoint = LayoutDeviceIntPoint(aX - rootRect.x, aY - rootRect.y);
 
   nsIFrame* popupFrame = nsLayoutUtils::
     GetPopupFrameForEventCoordinates(accDocument->PresContext()->GetRootPresContext(),
                                      &dummyEvent);
   if (popupFrame) {
     // If 'this' accessible is not inside the popup then ignore the popup when
@@ -1830,19 +1830,21 @@ Accessible::DispatchClickEvent(nsIConten
   nsSize size = frame->GetSize();
 
   nsRefPtr<nsPresContext> presContext = presShell->GetPresContext();
   int32_t x = presContext->AppUnitsToDevPixels(point.x + size.width / 2);
   int32_t y = presContext->AppUnitsToDevPixels(point.y + size.height / 2);
 
   // Simulate a touch interaction by dispatching touch events with mouse events.
   nsCoreUtils::DispatchTouchEvent(NS_TOUCH_START, x, y, aContent, frame, presShell, widget);
-  nsCoreUtils::DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN, x, y, aContent, frame, presShell, widget);
+  nsCoreUtils::DispatchMouseEvent(eMouseDown, x, y, aContent, frame,
+                                  presShell, widget);
   nsCoreUtils::DispatchTouchEvent(NS_TOUCH_END, x, y, aContent, frame, presShell, widget);
-  nsCoreUtils::DispatchMouseEvent(NS_MOUSE_BUTTON_UP, x, y, aContent, frame, presShell, widget);
+  nsCoreUtils::DispatchMouseEvent(eMouseUp, x, y, aContent, frame,
+                                  presShell, widget);
 }
 
 void
 Accessible::ScrollToPoint(uint32_t aCoordinateType, int32_t aX, int32_t aY)
 {
   nsIFrame* frame = GetFrame();
   if (!frame)
     return;
--- a/b2g/config/aries/sources.xml
+++ b/b2g/config/aries/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="e935894ef5f27e2f04b9e929a45a958e6288a223">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="7a77326ef8b14ddef4d101efc336d7b26670ef94"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="31e595f86f6bf159b3a9a46816a6ac00a55ca9f9"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="62cfa11ae7d77f6330de019a5aa79607e35be7d1"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="51ebaf824cc634665c5efcae95b8301ad1758c5e"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="b4f6fd4afd03161f53c7d2a663750f94762bd238"/>
@@ -121,17 +121,17 @@
   <project name="platform/hardware/libhardware_legacy" path="hardware/libhardware_legacy" revision="76c4bf4bc430a1b8317f2f21ef735867733e50cc"/>
   <project name="platform/system/media" path="system/media" revision="c1332c21c608f4932a6d7e83450411cde53315ef"/>
   <default remote="caf" revision="LNX.LA.3.5.2.1.1" sync-j="4"/>
   <!-- Platform common things -->
   <project name="device-shinano-common" path="device/sony/shinano-common" remote="b2g" revision="df3d2ae4345ca5d32bce717bb7b3dac18a3afa18"/>
   <project name="device/generic/armv7-a-neon" path="device/generic/armv7-a-neon" revision="1bb28abbc215f45220620af5cd60a8ac1be93722"/>
   <project name="device/qcom/common" path="device/qcom/common" revision="2501e5940ba69ece7654ff85611c76ae5bda299c"/>
   <project name="codeaurora_kernel_msm" path="kernel" remote="b2g" revision="d620691cad7aee780018e98159ff03bf99840317"/>
-  <project name="init_sh" path="external/init_sh" remote="b2g" revision="3bdd26e092db9c47c5beb04b4809a35f8f767b8a"/>
+  <project name="init_sh" path="external/init_sh" remote="b2g" revision="0634405632190765881347500a982221b86a1766"/>
   <project name="platform_external_bluetooth_bluedroid" path="external/bluetooth/bluedroid" remote="b2g" revision="70f536bd97d901b96b94669ae1aa2fd0fb54b258"/>
   <project name="platform/external/libnfc-nci" path="external/libnfc-nci" revision="0a01977f34d6e86fe23d6c0ec75e96ba988bbebb"/>
   <project name="platform_external_libnfc-pn547" path="external/libnfc-pn547" remote="b2g" revision="5bb999b84b8adc14f6bea004d523ba258dea8188"/>
   <project name="platform/external/wpa_supplicant_8" path="external/wpa_supplicant_8" revision="5b71e40213f650459e95d35b6f14af7e88d8ab62"/>
   <project name="platform_frameworks_av" path="frameworks/av" remote="b2g" revision="a920312eb6299b6cc11f7136254c4b0ba7a663be"/>
   <project name="platform/frameworks/base" path="frameworks/base" revision="da8e6bc53c8bc669da0bb627904d08aa293f2497"/>
   <project name="platform/frameworks/native" path="frameworks/native" revision="a46a9f1ac0ed5662d614c277cbb14eb3f332f365"/>
   <project name="platform/hardware/libhardware" path="hardware/libhardware" revision="7196881a0e9dd7bfbbcf0af64c8064e70f0fa094"/>
--- a/b2g/config/dolphin/sources.xml
+++ b/b2g/config/dolphin/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="e935894ef5f27e2f04b9e929a45a958e6288a223">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="7a77326ef8b14ddef4d101efc336d7b26670ef94"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="31e595f86f6bf159b3a9a46816a6ac00a55ca9f9"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="62cfa11ae7d77f6330de019a5aa79607e35be7d1"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="51ebaf824cc634665c5efcae95b8301ad1758c5e"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="b4f6fd4afd03161f53c7d2a663750f94762bd238"/>
--- a/b2g/config/emulator-ics/sources.xml
+++ b/b2g/config/emulator-ics/sources.xml
@@ -14,17 +14,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="1b0db93fb6b870b03467aff50d6419771ba0d88c">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="7a77326ef8b14ddef4d101efc336d7b26670ef94"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="31e595f86f6bf159b3a9a46816a6ac00a55ca9f9"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="62cfa11ae7d77f6330de019a5aa79607e35be7d1"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="2d58f4b9206b50b8fda0d5036da6f0c62608db7c"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="d70e4bfdcb65e7514de0f9315b74aea1c811678d"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="51ebaf824cc634665c5efcae95b8301ad1758c5e"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="34ea6163f9f0e0122fb0bb03607eccdca31ced7a"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- a/b2g/config/emulator-jb/sources.xml
+++ b/b2g/config/emulator-jb/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="660169a3d7e034a892359e39135e8c2785a6ad6f">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="7a77326ef8b14ddef4d101efc336d7b26670ef94"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="31e595f86f6bf159b3a9a46816a6ac00a55ca9f9"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="62cfa11ae7d77f6330de019a5aa79607e35be7d1"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="51ebaf824cc634665c5efcae95b8301ad1758c5e"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="b4f6fd4afd03161f53c7d2a663750f94762bd238"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
--- a/b2g/config/emulator-kk/sources.xml
+++ b/b2g/config/emulator-kk/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="e935894ef5f27e2f04b9e929a45a958e6288a223">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="7a77326ef8b14ddef4d101efc336d7b26670ef94"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="31e595f86f6bf159b3a9a46816a6ac00a55ca9f9"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="62cfa11ae7d77f6330de019a5aa79607e35be7d1"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="51ebaf824cc634665c5efcae95b8301ad1758c5e"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="b4f6fd4afd03161f53c7d2a663750f94762bd238"/>
--- a/b2g/config/emulator-l/sources.xml
+++ b/b2g/config/emulator-l/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="05a36844c1046a1eb07d5b1325f85ed741f961ea">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="7a77326ef8b14ddef4d101efc336d7b26670ef94"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="31e595f86f6bf159b3a9a46816a6ac00a55ca9f9"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="62cfa11ae7d77f6330de019a5aa79607e35be7d1"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="51ebaf824cc634665c5efcae95b8301ad1758c5e"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="b4f6fd4afd03161f53c7d2a663750f94762bd238"/>
--- a/b2g/config/emulator/sources.xml
+++ b/b2g/config/emulator/sources.xml
@@ -14,17 +14,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="1b0db93fb6b870b03467aff50d6419771ba0d88c">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="7a77326ef8b14ddef4d101efc336d7b26670ef94"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="31e595f86f6bf159b3a9a46816a6ac00a55ca9f9"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="62cfa11ae7d77f6330de019a5aa79607e35be7d1"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="2d58f4b9206b50b8fda0d5036da6f0c62608db7c"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="d70e4bfdcb65e7514de0f9315b74aea1c811678d"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="51ebaf824cc634665c5efcae95b8301ad1758c5e"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="34ea6163f9f0e0122fb0bb03607eccdca31ced7a"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- a/b2g/config/flame-kk/sources.xml
+++ b/b2g/config/flame-kk/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="e935894ef5f27e2f04b9e929a45a958e6288a223">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="7a77326ef8b14ddef4d101efc336d7b26670ef94"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="31e595f86f6bf159b3a9a46816a6ac00a55ca9f9"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="62cfa11ae7d77f6330de019a5aa79607e35be7d1"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="51ebaf824cc634665c5efcae95b8301ad1758c5e"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="b4f6fd4afd03161f53c7d2a663750f94762bd238"/>
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,9 +1,9 @@
 {
     "git": {
-        "git_revision": "7a77326ef8b14ddef4d101efc336d7b26670ef94", 
+        "git_revision": "31e595f86f6bf159b3a9a46816a6ac00a55ca9f9", 
         "remote": "https://git.mozilla.org/releases/gaia.git", 
         "branch": ""
     }, 
-    "revision": "6eaf499cb32bdf152ff5bf9f607e896a08b14f9c", 
+    "revision": "15ba43fc66bdea9bfe6397bb992c0918d9d3d77c", 
     "repo_path": "integration/gaia-central"
 }
--- a/b2g/config/nexus-4/sources.xml
+++ b/b2g/config/nexus-4/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="660169a3d7e034a892359e39135e8c2785a6ad6f">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="7a77326ef8b14ddef4d101efc336d7b26670ef94"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="31e595f86f6bf159b3a9a46816a6ac00a55ca9f9"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="62cfa11ae7d77f6330de019a5aa79607e35be7d1"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="51ebaf824cc634665c5efcae95b8301ad1758c5e"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="b4f6fd4afd03161f53c7d2a663750f94762bd238"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
--- a/b2g/config/nexus-5-l/sources.xml
+++ b/b2g/config/nexus-5-l/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="05a36844c1046a1eb07d5b1325f85ed741f961ea">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="7a77326ef8b14ddef4d101efc336d7b26670ef94"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="31e595f86f6bf159b3a9a46816a6ac00a55ca9f9"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="62cfa11ae7d77f6330de019a5aa79607e35be7d1"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="51ebaf824cc634665c5efcae95b8301ad1758c5e"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="b4f6fd4afd03161f53c7d2a663750f94762bd238"/>
--- a/b2g/gaia/Makefile.in
+++ b/b2g/gaia/Makefile.in
@@ -1,15 +1,19 @@
 # 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/.
 
 # For b2gdroid, gaia ends up in the assets/gaia folder in the APK.
 GAIA_PATH := $(if MOZ_B2GDROID,gaia/assets/gaia,gaia/profile)
 
+# For b2gdroid, we disable the screen timeout since this is managed by android.
+# We also limit the app set to the production ones.
+GAIA_OPTIONS := $(if MOZ_B2GDROID,SCREEN_TIMEOUT=0 PRODUCTION=1,)
+
 GENERATED_DIRS += $(DIST)/bin/$(GAIA_PATH)
 
 include $(topsrcdir)/config/rules.mk
 
 libs::
 	+$(MAKE) -j1 -C $(GAIADIR) clean
-	+$(MAKE) -j1 -C $(GAIADIR) profile
+	+$(GAIA_OPTIONS) $(MAKE) -j1 -C $(GAIADIR) profile
 	(cd $(GAIADIR)/profile && tar $(TAR_CREATE_FLAGS) - .) | (cd $(abspath $(DIST))/bin/$(GAIA_PATH) && tar -xf -)
--- a/b2g/moz.build
+++ b/b2g/moz.build
@@ -10,9 +10,8 @@ DIRS += ['chrome', 'components', 'locale
 
 if CONFIG['OS_ARCH'] == 'WINNT':
     DIRS += ['../xulrunner/tools/redit']
 
 if CONFIG['GAIADIR']:
     DIRS += ['gaia']
 
 DIRS += ['app']
-
--- a/browser/base/content/browser-gestureSupport.js
+++ b/browser/base/content/browser-gestureSupport.js
@@ -20,17 +20,17 @@ let gGestureSupport = {
 
   /**
    * Add or remove mouse gesture event listeners
    *
    * @param aAddListener
    *        True to add/init listeners and false to remove/uninit
    */
   init: function GS_init(aAddListener) {
-    const gestureEvents = ["SwipeGestureStart",
+    const gestureEvents = ["SwipeGestureMayStart", "SwipeGestureStart",
       "SwipeGestureUpdate", "SwipeGestureEnd", "SwipeGesture",
       "MagnifyGestureStart", "MagnifyGestureUpdate", "MagnifyGesture",
       "RotateGestureStart", "RotateGestureUpdate", "RotateGesture",
       "TapGesture", "PressTapGesture"];
 
     let addRemove = aAddListener ? window.addEventListener :
       window.removeEventListener;
 
@@ -53,21 +53,25 @@ let gGestureSupport = {
       aEvent.stopPropagation();
     }
 
     // Create a preference object with some defaults
     let def = function(aThreshold, aLatched)
       ({ threshold: aThreshold, latched: !!aLatched });
 
     switch (aEvent.type) {
-      case "MozSwipeGestureStart":
-        if (this._setupSwipeGesture(aEvent)) {
+      case "MozSwipeGestureMayStart":
+        if (this._shouldDoSwipeGesture(aEvent)) {
           aEvent.preventDefault();
         }
         break;
+      case "MozSwipeGestureStart":
+        aEvent.preventDefault();
+        this._setupSwipeGesture();
+        break;
       case "MozSwipeGestureUpdate":
         aEvent.preventDefault();
         this._doUpdate(aEvent);
         break;
       case "MozSwipeGestureEnd":
         aEvent.preventDefault();
         this._doEnd(aEvent);
         break;
@@ -168,25 +172,25 @@ let gGestureSupport = {
   _swipeNavigatesHistory: function GS__swipeNavigatesHistory(aEvent) {
     return this._getCommand(aEvent, ["swipe", "left"])
               == "Browser:BackOrBackDuplicate" &&
            this._getCommand(aEvent, ["swipe", "right"])
               == "Browser:ForwardOrForwardDuplicate";
   },
 
   /**
-   * Sets up swipe gestures. This includes setting up swipe animations for the
-   * gesture, if enabled.
+   * Checks whether we want to start a swipe for aEvent and sets
+   * aEvent.allowedDirections to the right values.
    *
    * @param aEvent
-   *        The swipe gesture start event.
-   * @return true if swipe gestures could successfully be set up, false
-   *         othwerwise.
+   *        The swipe gesture "MayStart" event.
+   * @return true if we're willing to start a swipe for this event, false
+   *         otherwise.
    */
-  _setupSwipeGesture: function GS__setupSwipeGesture(aEvent) {
+  _shouldDoSwipeGesture: function GS__shouldDoSwipeGesture(aEvent) {
     if (!this._swipeNavigatesHistory(aEvent)) {
       return false;
     }
 
     let isVerticalSwipe = false;
     if (aEvent.direction == aEvent.DIRECTION_UP) {
       if (gMultiProcessBrowser || content.pageYOffset > 0) {
         return false;
@@ -212,30 +216,41 @@ let gGestureSupport = {
       aEvent.allowedDirections |= isLTR ? aEvent.DIRECTION_LEFT :
                                           aEvent.DIRECTION_RIGHT;
     }
     if (canGoForward) {
       aEvent.allowedDirections |= isLTR ? aEvent.DIRECTION_RIGHT :
                                           aEvent.DIRECTION_LEFT;
     }
 
-    gHistorySwipeAnimation.startAnimation(isVerticalSwipe);
+    return true;
+  },
+
+  /**
+   * Sets up swipe gestures. This includes setting up swipe animations for the
+   * gesture, if enabled.
+   *
+   * @param aEvent
+   *        The swipe gesture start event.
+   * @return true if swipe gestures could successfully be set up, false
+   *         othwerwise.
+   */
+  _setupSwipeGesture: function GS__setupSwipeGesture() {
+    gHistorySwipeAnimation.startAnimation(false);
 
     this._doUpdate = function GS__doUpdate(aEvent) {
       gHistorySwipeAnimation.updateAnimation(aEvent.delta);
     };
 
     this._doEnd = function GS__doEnd(aEvent) {
       gHistorySwipeAnimation.swipeEndEventReceived();
 
       this._doUpdate = function (aEvent) {};
       this._doEnd = function (aEvent) {};
     }
-
-    return true;
   },
 
   /**
    * Generator producing the powerset of the input array where the first result
    * is the complete set and the last result (before StopIteration) is empty.
    *
    * @param aArray
    *        Source array containing any number of elements
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -4876,17 +4876,19 @@ nsBrowserAccess.prototype = {
         aWhere = gPrefService.getIntPref("browser.link.open_newwindow");
     }
 
     let referrer = aOpener ? makeURI(aOpener.location.href) : null;
     let referrerPolicy = Ci.nsIHttpChannel.REFERRER_POLICY_DEFAULT;
     if (aOpener && aOpener.document) {
       referrerPolicy = aOpener.document.referrerPolicy;
     }
-    let isPrivate = PrivateBrowsingUtils.isWindowPrivate(aOpener || window);
+    let isPrivate = aOpener
+                  ? PrivateBrowsingUtils.isContentWindowPrivate(aOpener)
+                  : PrivateBrowsingUtils.isWindowPrivate(window);
 
     switch (aWhere) {
       case Ci.nsIBrowserDOMWindow.OPEN_NEWWINDOW :
         // FIXME: Bug 408379. So how come this doesn't send the
         // referrer like the other loads do?
         var url = aURI ? aURI.spec : "about:blank";
         let features = "all,dialog=no";
         if (isPrivate) {
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -9984,36 +9984,41 @@ nsDocShell::InternalLoad(nsIURI* aURI,
       // ScrollToAnchor performs other important tasks, such as informing
       // the presShell that we have a new hash.  See bug 680257.
       rv = ScrollToAnchor(curHash, newHash, aLoadType);
       NS_ENSURE_SUCCESS(rv, rv);
 
       /* restore previous position of scroller(s), if we're moving
        * back in history (bug 59774)
        */
+      nscoord bx, by;
+      bool needsScrollPosUpdate = false;
       if (mOSHE && (aLoadType == LOAD_HISTORY ||
                     aLoadType == LOAD_RELOAD_NORMAL)) {
-        nscoord bx, by;
+        needsScrollPosUpdate = true;
         mOSHE->GetScrollPosition(&bx, &by);
-        SetCurScrollPosEx(bx, by);
       }
 
       // Dispatch the popstate and hashchange events, as appropriate.
       //
       // The event dispatch below can cause us to re-enter script and
       // destroy the docshell, nulling out mScriptGlobal. Hold a stack
       // reference to avoid null derefs. See bug 914521.
       if (win) {
         // Fire a hashchange event URIs differ, and only in their hashes.
         bool doHashchange = sameExceptHashes && !curHash.Equals(newHash);
 
         if (historyNavBetweenSameDoc || doHashchange) {
           win->DispatchSyncPopState();
         }
 
+        if (needsScrollPosUpdate && win->HasActiveDocument()) {
+          SetCurScrollPosEx(bx, by);
+        }
+
         if (doHashchange) {
           // Note that currentURI hasn't changed because it's on the
           // stack, so we can just use it directly as the old URI.
           win->DispatchAsyncHashchange(currentURI, aURI);
         }
       }
 
       return NS_OK;
--- a/docshell/test/mochitest.ini
+++ b/docshell/test/mochitest.ini
@@ -94,16 +94,17 @@ skip-if = (buildapp == 'b2g' && toolkit 
 [test_bug691547.html]
 [test_bug694612.html]
 [test_bug703855.html]
 [test_bug713825.html]
 [test_bug728939.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
 [test_bug797909.html]
 [test_bug1045096.html]
+[test_bug1186774.html]
 [test_framedhistoryframes.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') || toolkit == 'android' #Bug 931116, b2g desktop specific, initial triage, and also bug 784321
 support-files = file_framedhistoryframes.html
 [test_pushState_after_document_open.html]
 [test_windowedhistoryframes.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
 [test_bug1121701.html]
 skip-if = (buildapp == 'b2g' || buildapp == 'mulet')
new file mode 100644
--- /dev/null
+++ b/docshell/test/test_bug1186774.html
@@ -0,0 +1,51 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1186774
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 1186774</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+  <script type="application/javascript">
+
+  /** Test for Bug 1186774 **/
+
+var child;
+
+function runTest() {
+  child = window.open("data:text/html,<div style='height: 9000px;'></div>", "", "width=100,height=100");
+  child.onload = function() {
+    setTimeout(function() {
+      child.scrollTo(0, 0);
+      child.history.pushState({}, "initial");
+      child.scrollTo(0, 3000);
+      child.history.pushState({}, "scrolled");
+      child.scrollTo(0, 6000);
+      child.history.back();
+    });
+  }
+
+  child.onpopstate = function() {
+    is(child.scrollY,  6000, "Shouldn't have scrolled before popstate");
+    child.close();
+    SimpleTest.finish();
+  }
+}
+
+SimpleTest.waitForExplicitFinish();
+addLoadEvent(runTest);
+
+  </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1186774">Mozilla Bug 1186774</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
--- a/dom/asmjscache/AsmJSCache.cpp
+++ b/dom/asmjscache/AsmJSCache.cpp
@@ -16,19 +16,24 @@
 #include "mozilla/dom/asmjscache/PAsmJSCacheEntryParent.h"
 #include "mozilla/dom/ContentChild.h"
 #include "mozilla/dom/PermissionMessageUtils.h"
 #include "mozilla/dom/quota/Client.h"
 #include "mozilla/dom/quota/QuotaManager.h"
 #include "mozilla/dom/quota/QuotaObject.h"
 #include "mozilla/dom/quota/UsageInfo.h"
 #include "mozilla/HashFunctions.h"
+#include "mozilla/ipc/BackgroundChild.h"
+#include "mozilla/ipc/BackgroundParent.h"
+#include "mozilla/ipc/BackgroundUtils.h"
+#include "mozilla/ipc/PBackgroundChild.h"
 #include "mozilla/unused.h"
 #include "nsIAtom.h"
 #include "nsIFile.h"
+#include "nsIIPCBackgroundChildCreateCallback.h"
 #include "nsIPermissionManager.h"
 #include "nsIPrincipal.h"
 #include "nsIRunnable.h"
 #include "nsISimpleEnumerator.h"
 #include "nsIThread.h"
 #include "nsIXULAppInfo.h"
 #include "nsJSPrincipals.h"
 #include "nsThreadUtils.h"
@@ -36,20 +41,26 @@
 #include "prio.h"
 #include "private/pprio.h"
 #include "mozilla/Services.h"
 
 #define ASMJSCACHE_METADATA_FILE_NAME "metadata"
 #define ASMJSCACHE_ENTRY_FILE_NAME_BASE "module"
 
 using mozilla::dom::quota::AssertIsOnIOThread;
+using mozilla::dom::quota::DirectoryLock;
 using mozilla::dom::quota::PersistenceType;
 using mozilla::dom::quota::QuotaManager;
 using mozilla::dom::quota::QuotaObject;
 using mozilla::dom::quota::UsageInfo;
+using mozilla::ipc::AssertIsOnBackgroundThread;
+using mozilla::ipc::BackgroundChild;
+using mozilla::ipc::IsOnBackgroundThread;
+using mozilla::ipc::PBackgroundChild;
+using mozilla::ipc::PrincipalInfo;
 using mozilla::unused;
 using mozilla::HashString;
 
 namespace mozilla {
 
 MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedPRFileDesc, PRFileDesc, PR_Close);
 
 namespace dom {
@@ -220,22 +231,18 @@ EvictEntries(nsIFile* aDirectory, const 
       usage.mFreed += fileSize;
     }
 
     entry.clear();
   }
 }
 
 // FileDescriptorHolder owns a file descriptor and its memory mapping.
-// FileDescriptorHolder is derived by all three runnable classes (that is,
-// (Single|Parent|Child)ProcessRunnable. To avoid awkward workarouds,
-// FileDescriptorHolder is derived virtually by File and MainProcessRunnable for
-// the benefit of SingleProcessRunnable, which derives both. Since File and
-// MainProcessRunnable both need to be runnables, FileDescriptorHolder also
-// derives nsRunnable.
+// FileDescriptorHolder is derived by two runnable classes (that is,
+// (Parent|Child)Runnable.
 class FileDescriptorHolder : public nsRunnable
 {
 public:
   FileDescriptorHolder()
   : mQuotaObject(nullptr),
     mFileSize(INT64_MIN),
     mFileDesc(nullptr),
     mFileMap(nullptr),
@@ -317,334 +324,298 @@ protected:
 
   nsRefPtr<QuotaObject> mQuotaObject;
   int64_t mFileSize;
   PRFileDesc* mFileDesc;
   PRFileMap* mFileMap;
   void* mMappedMemory;
 };
 
-// File is a base class shared by (Single|Client)ProcessEntryRunnable that
-// presents a single interface to the AsmJSCache ops which need to wait until
-// the file is open, regardless of whether we are executing in the main process
-// or not.
-class File : public virtual FileDescriptorHolder
+class UnlockDirectoryRunnable final
+  : public nsRunnable
 {
-public:
-  class AutoClose
-  {
-    File* mFile;
-
-  public:
-    explicit AutoClose(File* aFile = nullptr)
-    : mFile(aFile)
-    { }
-
-    void
-    Init(File* aFile)
-    {
-      MOZ_ASSERT(!mFile);
-      mFile = aFile;
-    }
-
-    File*
-    operator->() const MOZ_NO_ADDREF_RELEASE_ON_RETURN
-    {
-      MOZ_ASSERT(mFile);
-      return mFile;
-    }
-
-    void
-    Forget(File** aFile)
-    {
-      *aFile = mFile;
-      mFile = nullptr;
-    }
+  nsRefPtr<DirectoryLock> mDirectoryLock;
 
-    ~AutoClose()
-    {
-      if (mFile) {
-        mFile->Close();
-      }
-    }
-  };
-
-  JS::AsmJSCacheResult
-  BlockUntilOpen(AutoClose* aCloser)
-  {
-    MOZ_ASSERT(!mWaiting, "Can only call BlockUntilOpen once");
-    MOZ_ASSERT(!mOpened, "Can only call BlockUntilOpen once");
-
-    mWaiting = true;
+public:
+  explicit
+  UnlockDirectoryRunnable(already_AddRefed<DirectoryLock> aDirectoryLock)
+    : mDirectoryLock(Move(aDirectoryLock))
+  { }
 
-    nsresult rv = NS_DispatchToMainThread(this);
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return JS::AsmJSCache_InternalError;
-    }
-
-    {
-      MutexAutoLock lock(mMutex);
-      while (mWaiting) {
-        mCondVar.Wait();
-      }
-    }
-
-    if (!mOpened) {
-      return mResult;
-    }
-
-    // Now that we're open, we're guarnateed a Close() call. However, we are
-    // not guarnateed someone is holding an outstanding reference until the File
-    // is closed, so we do that ourselves and Release() in OnClose().
-    aCloser->Init(this);
-    AddRef();
-    return JS::AsmJSCache_Success;
+private:
+  ~UnlockDirectoryRunnable()
+  {
+    MOZ_ASSERT(!mDirectoryLock);
   }
 
-  // This method must be called if BlockUntilOpen returns 'true'. AutoClose
-  // mostly takes care of this. A derived class that implements Close() must
-  // guarnatee that OnClose() is called (eventually).
-  virtual void
-  Close() = 0;
-
-protected:
-  File()
-  : mMutex("File::mMutex"),
-    mCondVar(mMutex, "File::mCondVar"),
-    mWaiting(false),
-    mOpened(false),
-    mResult(JS::AsmJSCache_InternalError)
-  { }
-
-  ~File()
-  {
-    MOZ_ASSERT(!mWaiting, "Shouldn't be destroyed while thread is waiting");
-    MOZ_ASSERT(!mOpened, "OnClose() should have been called");
-  }
-
-  void
-  OnOpen()
-  {
-    Notify(JS::AsmJSCache_Success);
-  }
-
-  void
-  OnFailure(JS::AsmJSCacheResult aResult)
-  {
-    MOZ_ASSERT(aResult != JS::AsmJSCache_Success);
-
-    FileDescriptorHolder::Finish();
-    Notify(aResult);
-  }
-
-  void
-  OnClose()
-  {
-    FileDescriptorHolder::Finish();
-
-    MOZ_ASSERT(mOpened);
-    mOpened = false;
-
-    // Match the AddRef in BlockUntilOpen(). The main thread event loop still
-    // holds an outstanding ref which will keep 'this' alive until returning to
-    // the event loop.
-    Release();
-  }
-
-private:
-  void
-  Notify(JS::AsmJSCacheResult aResult)
+  NS_IMETHOD
+  Run() override
   {
     MOZ_ASSERT(NS_IsMainThread());
-
-    MutexAutoLock lock(mMutex);
-    MOZ_ASSERT(mWaiting);
+    MOZ_ASSERT(mDirectoryLock);
 
-    mWaiting = false;
-    mOpened = aResult == JS::AsmJSCache_Success;
-    mResult = aResult;
-    mCondVar.Notify();
-  }
+    mDirectoryLock = nullptr;
 
-  Mutex mMutex;
-  CondVar mCondVar;
-  bool mWaiting;
-  bool mOpened;
-  JS::AsmJSCacheResult mResult;
+    return NS_OK;
+  }
 };
 
-// MainProcessRunnable is a base class shared by (Single|Parent)ProcessRunnable
-// that factors out the runnable state machine required to open a cache entry
-// that runs in the main process.
-class MainProcessRunnable
-  : public virtual FileDescriptorHolder
+// A runnable that implements a state machine required to open a cache entry.
+// It executes in the parent for a cache access originating in the child.
+// This runnable gets registered as an IPDL subprotocol actor so that it
+// can communicate with the corresponding ChildRunnable.
+class ParentRunnable final
+  : public FileDescriptorHolder
   , public quota::OpenDirectoryListener
+  , public PAsmJSCacheEntryParent
 {
-  typedef mozilla::dom::quota::DirectoryLock DirectoryLock;
-
 public:
+  NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_NSIRUNNABLE
 
-  // MainProcessRunnable runnable assumes that the derived class ensures
-  // (through ref-counting or preconditions) that aPrincipal is kept alive for
-  // the lifetime of the MainProcessRunnable.
-  MainProcessRunnable(nsIPrincipal* aPrincipal,
-                      OpenMode aOpenMode,
-                      WriteParams aWriteParams)
-  : mPrincipal(aPrincipal),
+  ParentRunnable(const PrincipalInfo& aPrincipalInfo,
+                 OpenMode aOpenMode,
+                 WriteParams aWriteParams)
+  : mOwningThread(NS_GetCurrentThread()),
+    mPrincipalInfo(aPrincipalInfo),
     mOpenMode(aOpenMode),
     mWriteParams(aWriteParams),
     mPersistence(quota::PERSISTENCE_TYPE_INVALID),
     mState(eInitial),
     mResult(JS::AsmJSCache_InternalError),
     mIsApp(false),
-    mEnforcingQuota(true)
+    mEnforcingQuota(true),
+    mActorDestroyed(false),
+    mOpened(false)
   {
     MOZ_ASSERT(XRE_IsParentProcess());
+    AssertIsOnOwningThread();
+    MOZ_COUNT_CTOR(ParentRunnable);
   }
 
-  virtual ~MainProcessRunnable()
+private:
+  ~ParentRunnable()
   {
     MOZ_ASSERT(mState == eFinished);
     MOZ_ASSERT(!mDirectoryLock);
+    MOZ_ASSERT(mActorDestroyed);
+    MOZ_COUNT_DTOR(ParentRunnable);
+  }
+
+  bool
+  IsOnOwningThread() const
+  {
+    MOZ_ASSERT(mOwningThread);
+
+    bool current;
+    return NS_SUCCEEDED(mOwningThread->IsOnCurrentThread(&current)) && current;
   }
 
-protected:
-  // This method is called by the derived class on the main thread when a
-  // cache entry has been selected to open.
   void
-  OpenForRead(unsigned aModuleIndex)
+  AssertIsOnOwningThread() const
   {
-    MOZ_ASSERT(NS_IsMainThread());
-    MOZ_ASSERT(mState == eWaitingToOpenCacheFileForRead);
-    MOZ_ASSERT(mOpenMode == eOpenForRead);
-
-    mModuleIndex = aModuleIndex;
-    mState = eReadyToOpenCacheFileForRead;
-    DispatchToIOThread();
+    MOZ_ASSERT(IsOnBackgroundThread());
+    MOZ_ASSERT(IsOnOwningThread());
   }
 
-  // This method is called by the derived class on the main thread when no cache
-  // entry was found to open. If we just tried a lookup in persistent storage
-  // then we might still get a hit in temporary storage (for an asm.js module
-  // that wasn't compiled at install-time).
+  void
+  AssertIsOnNonOwningThread() const
+  {
+    MOZ_ASSERT(!IsOnBackgroundThread());
+    MOZ_ASSERT(!IsOnOwningThread());
+  }
+
+  // This method is called on the owning thread when no cache entry was found
+  // to open. If we just tried a lookup in persistent storage then we might
+  // still get a hit in temporary storage (for an asm.js module that wasn't
+  // compiled at install-time).
   void
   CacheMiss()
   {
-    MOZ_ASSERT(NS_IsMainThread());
+    AssertIsOnOwningThread();
     MOZ_ASSERT(mState == eFailedToReadMetadata ||
                mState == eWaitingToOpenCacheFileForRead);
     MOZ_ASSERT(mOpenMode == eOpenForRead);
 
     if (mPersistence == quota::PERSISTENCE_TYPE_TEMPORARY) {
       Fail();
       return;
     }
 
     // Try again with a clean slate. InitOnMainThread will see that mPersistence
     // is initialized and switch to temporary storage.
     MOZ_ASSERT(mPersistence == quota::PERSISTENCE_TYPE_PERSISTENT);
-    FinishOnMainThread();
+    FinishOnOwningThread();
     mState = eInitial;
     NS_DispatchToMainThread(this);
   }
 
-  // This method is called by the derived class (either on the JS compilation
-  // thread or the main thread) when the JS engine is finished reading/writing
-  // the cache entry.
+  // This method is called on the owning thread when the JS engine is finished
+  // reading/writing the cache entry.
   void
   Close()
   {
+    AssertIsOnOwningThread();
     MOZ_ASSERT(mState == eOpened);
-    mState = eClosing;
-    NS_DispatchToMainThread(this);
+
+    mState = eFinished;
+
+    MOZ_ASSERT(mOpened);
+
+    FinishOnOwningThread();
   }
 
-  // This method is called both internally and by derived classes upon any
-  // failure that prevents the eventual opening of the cache entry.
+  // This method is called upon any failure that prevents the eventual opening
+  // of the cache entry.
   void
   Fail()
   {
+    AssertIsOnOwningThread();
+    MOZ_ASSERT(mState != eFinished);
+
+    mState = eFinished;
+
+    MOZ_ASSERT(!mOpened);
+
+    FinishOnOwningThread();
+
+    if (!mActorDestroyed) {
+      unused << Send__delete__(this, mResult);
+    }
+  }
+
+  // The same as method above but is intended to be called off the owning
+  // thread.
+  void
+  FailOnNonOwningThread()
+  {
+    AssertIsOnNonOwningThread();
     MOZ_ASSERT(mState != eOpened &&
-               mState != eClosing &&
                mState != eFailing &&
                mState != eFinished);
 
     mState = eFailing;
-    NS_DispatchToMainThread(this);
+    MOZ_ALWAYS_TRUE(NS_SUCCEEDED(mOwningThread->Dispatch(this,
+                                                         NS_DISPATCH_NORMAL)));
   }
 
-  // Called by MainProcessRunnable on the main thread after metadata is open:
-  virtual void
-  OnOpenMetadataForRead(const Metadata& aMetadata) = 0;
-
-  // Called by MainProcessRunnable on the main thread after the entry is open:
-  virtual void
-  OnOpenCacheFile() = 0;
-
-  // This method may be overridden, but it must be called from the overrider.
-  // Called by MainProcessRunnable on the main thread after a call to Fail():
-  virtual void
-  OnFailure(JS::AsmJSCacheResult aResult)
-  {
-    FinishOnMainThread();
-  }
-
-  // This method may be overridden, but it must be called from the overrider.
-  // Called by MainProcessRunnable on the main thread after a call to Close():
-  virtual void
-  OnClose()
-  {
-    FinishOnMainThread();
-  }
-
-private:
   void
   InitPersistenceType();
 
   nsresult
   InitOnMainThread();
 
   nsresult
   ReadMetadata();
 
   nsresult
   OpenCacheFileForWrite();
 
   nsresult
   OpenCacheFileForRead();
 
   void
-  FinishOnMainThread();
+  FinishOnOwningThread();
 
   void
   DispatchToIOThread()
   {
+    MOZ_ASSERT(NS_IsMainThread());
+
     // If shutdown just started, the QuotaManager may have been deleted.
     QuotaManager* qm = QuotaManager::Get();
     if (!qm) {
-      Fail();
+      FailOnNonOwningThread();
       return;
     }
 
     nsresult rv = qm->IOThread()->Dispatch(this, NS_DISPATCH_NORMAL);
     if (NS_FAILED(rv)) {
-      Fail();
+      FailOnNonOwningThread();
       return;
     }
   }
 
   // OpenDirectoryListener overrides.
   virtual void
   DirectoryLockAcquired(DirectoryLock* aLock) override;
 
   virtual void
   DirectoryLockFailed() override;
 
-  nsIPrincipal* const mPrincipal;
+  // IPDL methods.
+  bool
+  Recv__delete__(const JS::AsmJSCacheResult& aResult) override
+  {
+    AssertIsOnOwningThread();
+    MOZ_ASSERT(mState != eFinished);
+
+    if (mOpened) {
+      Close();
+    } else {
+      Fail();
+    }
+
+    MOZ_ASSERT(mState == eFinished);
+
+    return true;
+  }
+
+  void
+  ActorDestroy(ActorDestroyReason why) override
+  {
+    AssertIsOnOwningThread();
+    MOZ_ASSERT(!mActorDestroyed);
+
+    mActorDestroyed = true;
+
+    // Assume ActorDestroy can happen at any time, so probe the current state to
+    // determine what needs to happen.
+
+    if (mState == eFinished) {
+      return;
+    }
+
+    if (mOpened) {
+      Close();
+    } else {
+      Fail();
+    }
+
+    MOZ_ASSERT(mState == eFinished);
+  }
+
+  bool
+  RecvSelectCacheFileToRead(const uint32_t& aModuleIndex) override
+  {
+    AssertIsOnOwningThread();
+    MOZ_ASSERT(mState == eWaitingToOpenCacheFileForRead);
+    MOZ_ASSERT(mOpenMode == eOpenForRead);
+
+    // A cache entry has been selected to open.
+
+    mModuleIndex = aModuleIndex;
+    mState = eDispatchToMainThread;
+    NS_DispatchToMainThread(this);
+
+    return true;
+  }
+
+  bool
+  RecvCacheMiss() override
+  {
+    AssertIsOnOwningThread();
+
+    CacheMiss();
+
+    return true;
+  }
+
+  nsCOMPtr<nsIEventTarget> mOwningThread;
+  const PrincipalInfo mPrincipalInfo;
   const OpenMode mOpenMode;
   const WriteParams mWriteParams;
 
   // State initialized during eInitial:
   quota::PersistenceType mPersistence;
   nsCString mGroup;
   nsCString mOrigin;
   nsRefPtr<DirectoryLock> mDirectoryLock;
@@ -654,37 +625,39 @@ private:
   nsCOMPtr<nsIFile> mMetadataFile;
   Metadata mMetadata;
 
   // State initialized during eWaitingToOpenCacheFileForRead
   unsigned mModuleIndex;
 
   enum State {
     eInitial, // Just created, waiting to be dispatched to main thread
-    eWaitingToOpenMetadata, // Waiting to be called back from WaitForOpenAllowed
+    eWaitingToOpenMetadata, // Waiting to be called back from OpenDirectory
     eReadyToReadMetadata, // Waiting to read the metadata file on the IO thread
-    eFailedToReadMetadata, // Waiting to be dispatched to main thread after fail
+    eFailedToReadMetadata, // Waiting to be dispatched to owning thread after fail
     eSendingMetadataForRead, // Waiting to send OnOpenMetadataForRead
     eWaitingToOpenCacheFileForRead, // Waiting to hear back from child
+    eDispatchToMainThread, // IO thread dispatch allowed from main thread only
     eReadyToOpenCacheFileForRead, // Waiting to open cache file for read
-    eSendingCacheFile, // Waiting to send OnOpenCacheFile on the main thread
-    eOpened, // Finished calling OnOpen, waiting to be closed
-    eClosing, // Waiting to be dispatched to main thread again
-    eFailing, // Just failed, waiting to be dispatched to the main thread
+    eSendingCacheFile, // Waiting to send OnOpenCacheFile on the owning thread
+    eOpened, // Finished calling OnOpenCacheFile, waiting to be closed
+    eFailing, // Just failed, waiting to be dispatched to the owning thread
     eFinished, // Terminal state
   };
   State mState;
   JS::AsmJSCacheResult mResult;
 
   bool mIsApp;
   bool mEnforcingQuota;
+  bool mActorDestroyed;
+  bool mOpened;
 };
 
 void
-MainProcessRunnable::InitPersistenceType()
+ParentRunnable::InitPersistenceType()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(mState == eInitial);
 
   if (mOpenMode == eOpenForWrite) {
     MOZ_ASSERT(mPersistence == quota::PERSISTENCE_TYPE_INVALID);
 
     // If we are performing install-time caching of an app, we'd like to store
@@ -720,38 +693,46 @@ MainProcessRunnable::InitPersistenceType
   if (mPersistence == quota::PERSISTENCE_TYPE_INVALID && mIsApp) {
     mPersistence = quota::PERSISTENCE_TYPE_PERSISTENT;
   } else {
     mPersistence = quota::PERSISTENCE_TYPE_TEMPORARY;
   }
 }
 
 nsresult
-MainProcessRunnable::InitOnMainThread()
+ParentRunnable::InitOnMainThread()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(mState == eInitial);
+  MOZ_ASSERT(mPrincipalInfo.type() != PrincipalInfo::TNullPrincipalInfo);
+
+  nsresult rv;
+  nsCOMPtr<nsIPrincipal> principal =
+    PrincipalInfoToPrincipal(mPrincipalInfo, &rv);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
 
   QuotaManager* qm = QuotaManager::GetOrCreate();
   NS_ENSURE_STATE(qm);
 
-  nsresult rv =
-    QuotaManager::GetInfoFromPrincipal(mPrincipal, &mGroup, &mOrigin, &mIsApp);
+  rv = QuotaManager::GetInfoFromPrincipal(principal, &mGroup, &mOrigin,
+                                          &mIsApp);
   NS_ENSURE_SUCCESS(rv, rv);
 
   InitPersistenceType();
 
   mEnforcingQuota =
     QuotaManager::IsQuotaEnforced(mPersistence, mOrigin, mIsApp);
 
   return NS_OK;
 }
 
 nsresult
-MainProcessRunnable::ReadMetadata()
+ParentRunnable::ReadMetadata()
 {
   AssertIsOnIOThread();
   MOZ_ASSERT(mState == eReadyToReadMetadata);
 
   QuotaManager* qm = QuotaManager::Get();
   MOZ_ASSERT(qm, "We are on the QuotaManager's IO thread");
 
   nsresult rv =
@@ -804,17 +785,17 @@ MainProcessRunnable::ReadMetadata()
       entry.clear();
     }
   }
 
   return NS_OK;
 }
 
 nsresult
-MainProcessRunnable::OpenCacheFileForWrite()
+ParentRunnable::OpenCacheFileForWrite()
 {
   AssertIsOnIOThread();
   MOZ_ASSERT(mState == eReadyToReadMetadata);
   MOZ_ASSERT(mOpenMode == eOpenForWrite);
 
   mFileSize = mWriteParams.mSize;
 
   // Kick out the oldest entry in the LRU queue in the metadata.
@@ -863,17 +844,17 @@ MainProcessRunnable::OpenCacheFileForWri
 
   rv = WriteMetadataFile(mMetadataFile, mMetadata);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
 nsresult
-MainProcessRunnable::OpenCacheFileForRead()
+ParentRunnable::OpenCacheFileForRead()
 {
   AssertIsOnIOThread();
   MOZ_ASSERT(mState == eReadyToOpenCacheFileForRead);
   MOZ_ASSERT(mOpenMode == eOpenForRead);
 
   nsCOMPtr<nsIFile> file;
   nsresult rv = GetCacheFile(mDirectory, mModuleIndex, getter_AddRefs(file));
   NS_ENSURE_SUCCESS(rv, rv);
@@ -909,41 +890,46 @@ MainProcessRunnable::OpenCacheFileForRea
 
   rv = WriteMetadataFile(mMetadataFile, mMetadata);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
 void
-MainProcessRunnable::FinishOnMainThread()
+ParentRunnable::FinishOnOwningThread()
 {
-  MOZ_ASSERT(NS_IsMainThread());
+  AssertIsOnOwningThread();
 
   // Per FileDescriptorHolder::Finish()'s comment, call before
   // releasing the directory lock.
   FileDescriptorHolder::Finish();
 
-  mDirectoryLock = nullptr;
+  if (mDirectoryLock) {
+    nsRefPtr<UnlockDirectoryRunnable> runnable =
+      new UnlockDirectoryRunnable(mDirectoryLock.forget());
+
+    NS_DispatchToMainThread(runnable);
+  }
 }
 
 NS_IMETHODIMP
-MainProcessRunnable::Run()
+ParentRunnable::Run()
 {
   nsresult rv;
 
   // All success/failure paths must eventually call Finish() to avoid leaving
   // the parser hanging.
   switch (mState) {
     case eInitial: {
       MOZ_ASSERT(NS_IsMainThread());
 
       rv = InitOnMainThread();
       if (NS_FAILED(rv)) {
-        Fail();
+        FailOnNonOwningThread();
         return NS_OK;
       }
 
       mState = eWaitingToOpenMetadata;
 
       // XXX The exclusive lock shouldn't be needed for read operations.
       QuotaManager::Get()->OpenDirectory(mPersistence,
                                          mGroup,
@@ -957,132 +943,154 @@ MainProcessRunnable::Run()
     }
 
     case eReadyToReadMetadata: {
       AssertIsOnIOThread();
 
       rv = ReadMetadata();
       if (NS_FAILED(rv)) {
         mState = eFailedToReadMetadata;
-        NS_DispatchToMainThread(this);
+        MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
+          mOwningThread->Dispatch(this, NS_DISPATCH_NORMAL)));
         return NS_OK;
       }
 
       if (mOpenMode == eOpenForRead) {
         mState = eSendingMetadataForRead;
-        NS_DispatchToMainThread(this);
+        MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
+          mOwningThread->Dispatch(this, NS_DISPATCH_NORMAL)));
+
         return NS_OK;
       }
 
       rv = OpenCacheFileForWrite();
       if (NS_FAILED(rv)) {
-        Fail();
+        FailOnNonOwningThread();
         return NS_OK;
       }
 
       mState = eSendingCacheFile;
-      NS_DispatchToMainThread(this);
+      MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
+        mOwningThread->Dispatch(this, NS_DISPATCH_NORMAL)));
       return NS_OK;
     }
 
     case eFailedToReadMetadata: {
-      MOZ_ASSERT(NS_IsMainThread());
+      AssertIsOnOwningThread();
 
       if (mOpenMode == eOpenForRead) {
         CacheMiss();
         return NS_OK;
       }
 
       Fail();
       return NS_OK;
     }
 
     case eSendingMetadataForRead: {
-      MOZ_ASSERT(NS_IsMainThread());
+      AssertIsOnOwningThread();
       MOZ_ASSERT(mOpenMode == eOpenForRead);
 
       mState = eWaitingToOpenCacheFileForRead;
-      OnOpenMetadataForRead(mMetadata);
+
+      // Metadata is now open.
+      if (!SendOnOpenMetadataForRead(mMetadata)) {
+        unused << Send__delete__(this, JS::AsmJSCache_InternalError);
+      }
+
+      return NS_OK;
+    }
+
+    case eDispatchToMainThread: {
+      MOZ_ASSERT(NS_IsMainThread());
+
+      mState = eReadyToOpenCacheFileForRead;
+      DispatchToIOThread();
       return NS_OK;
     }
 
     case eReadyToOpenCacheFileForRead: {
       AssertIsOnIOThread();
       MOZ_ASSERT(mOpenMode == eOpenForRead);
 
       rv = OpenCacheFileForRead();
       if (NS_FAILED(rv)) {
-        Fail();
+        FailOnNonOwningThread();
         return NS_OK;
       }
 
       mState = eSendingCacheFile;
-      NS_DispatchToMainThread(this);
+      MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
+        mOwningThread->Dispatch(this, NS_DISPATCH_NORMAL)));
       return NS_OK;
     }
 
     case eSendingCacheFile: {
-      MOZ_ASSERT(NS_IsMainThread());
+      AssertIsOnOwningThread();
 
       mState = eOpened;
-      OnOpenCacheFile();
+
+      // The entry is now open.
+      MOZ_ASSERT(!mOpened);
+      mOpened = true;
+
+      FileDescriptor::PlatformHandleType handle =
+        FileDescriptor::PlatformHandleType(PR_FileDesc2NativeHandle(mFileDesc));
+      if (!SendOnOpenCacheFile(mFileSize, FileDescriptor(handle))) {
+        unused << Send__delete__(this, JS::AsmJSCache_InternalError);
+      }
+
       return NS_OK;
     }
 
     case eFailing: {
-      MOZ_ASSERT(NS_IsMainThread());
+      AssertIsOnOwningThread();
 
-      mState = eFinished;
-      OnFailure(mResult);
-      return NS_OK;
-    }
+      Fail();
 
-    case eClosing: {
-      MOZ_ASSERT(NS_IsMainThread());
-
-      mState = eFinished;
-      OnClose();
       return NS_OK;
     }
 
     case eWaitingToOpenMetadata:
     case eWaitingToOpenCacheFileForRead:
     case eOpened:
     case eFinished: {
       MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("Shouldn't Run() in this state");
     }
   }
 
   MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("Corrupt state");
   return NS_OK;
 }
 
 void
-MainProcessRunnable::DirectoryLockAcquired(DirectoryLock* aLock)
+ParentRunnable::DirectoryLockAcquired(DirectoryLock* aLock)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(mState == eWaitingToOpenMetadata);
   MOZ_ASSERT(!mDirectoryLock);
 
   mDirectoryLock = aLock;
 
   mState = eReadyToReadMetadata;
   DispatchToIOThread();
 }
 
 void
-MainProcessRunnable::DirectoryLockFailed()
+ParentRunnable::DirectoryLockFailed()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(mState == eWaitingToOpenMetadata);
   MOZ_ASSERT(!mDirectoryLock);
 
-  Fail();
+  FailOnNonOwningThread();
 }
 
+NS_IMPL_ISUPPORTS_INHERITED0(ParentRunnable, FileDescriptorHolder)
+
 bool
 FindHashMatch(const Metadata& aMetadata, const ReadParams& aReadParams,
               unsigned* aModuleIndex)
 {
   // Perform a fast hash of the first sNumFastHashChars chars. Each cache entry
   // also stores an mFastHash of its first sNumFastHashChars so this gives us a
   // fast way to probabilistically determine whether we have a cache hit. We
   // still do a full hash of all the chars before returning the cache file to
@@ -1117,310 +1125,165 @@ FindHashMatch(const Metadata& aMetadata,
 
     *aModuleIndex = entry.mModuleIndex;
     return true;
   }
 
   return false;
 }
 
-// A runnable that executes for a cache access originating in the main process.
-class SingleProcessRunnable final : public File,
-                                    private MainProcessRunnable
-{
-public:
-  NS_DECL_ISUPPORTS_INHERITED
-
-  // In the single-process case, the calling JS compilation thread holds the
-  // nsIPrincipal alive indirectly (via the global object -> compartment ->
-  // principal) so we don't have to ref-count it here. This is fortunate since
-  // we are off the main thread and nsIPrincipals can only be ref-counted on
-  // the main thread.
-  SingleProcessRunnable(nsIPrincipal* aPrincipal,
-                        OpenMode aOpenMode,
-                        WriteParams aWriteParams,
-                        ReadParams aReadParams)
-  : MainProcessRunnable(aPrincipal, aOpenMode, aWriteParams),
-    mReadParams(aReadParams)
-  {
-    MOZ_ASSERT(XRE_IsParentProcess());
-    MOZ_ASSERT(!NS_IsMainThread());
-    MOZ_COUNT_CTOR(SingleProcessRunnable);
-  }
-
-protected:
-  ~SingleProcessRunnable()
-  {
-    MOZ_COUNT_DTOR(SingleProcessRunnable);
-  }
-
-private:
-  void
-  OnOpenMetadataForRead(const Metadata& aMetadata) override
-  {
-    uint32_t moduleIndex;
-    if (FindHashMatch(aMetadata, mReadParams, &moduleIndex)) {
-      MainProcessRunnable::OpenForRead(moduleIndex);
-    } else {
-      MainProcessRunnable::CacheMiss();
-    }
-  }
-
-  void
-  OnOpenCacheFile() override
-  {
-    File::OnOpen();
-  }
-
-  void
-  Close() override final
-  {
-    MainProcessRunnable::Close();
-  }
-
-  void
-  OnFailure(JS::AsmJSCacheResult aResult) override
-  {
-    MainProcessRunnable::OnFailure(aResult);
-    File::OnFailure(aResult);
-  }
-
-  void
-  OnClose() override final
-  {
-    MainProcessRunnable::OnClose();
-    File::OnClose();
-  }
-
-  // Avoid MSVC 'dominance' warning by having clear Run() override.
-  NS_IMETHODIMP
-  Run() override
-  {
-    return MainProcessRunnable::Run();
-  }
-
-  ReadParams mReadParams;
-};
-
-NS_IMPL_ISUPPORTS_INHERITED0(SingleProcessRunnable, File)
-
-// A runnable that executes in a parent process for a cache access originating
-// in the content process. This runnable gets registered as an IPDL subprotocol
-// actor so that it can communicate with the corresponding ChildProcessRunnable.
-class ParentProcessRunnable final : public PAsmJSCacheEntryParent,
-                                    public MainProcessRunnable
-{
-public:
-  NS_DECL_ISUPPORTS_INHERITED
-
-  // The given principal comes from an IPC::Principal which will be dec-refed
-  // at the end of the message, so we must ref-count it here. Fortunately, we
-  // are on the main thread (where PContent messages are delivered).
-  ParentProcessRunnable(nsIPrincipal* aPrincipal,
-                        OpenMode aOpenMode,
-                        WriteParams aWriteParams)
-  : MainProcessRunnable(aPrincipal, aOpenMode, aWriteParams),
-    mPrincipalHolder(aPrincipal),
-    mActorDestroyed(false),
-    mOpened(false),
-    mFinished(false)
-  {
-    MOZ_ASSERT(XRE_IsParentProcess());
-    MOZ_ASSERT(NS_IsMainThread());
-    MOZ_COUNT_CTOR(ParentProcessRunnable);
-  }
-
-private:
-  ~ParentProcessRunnable()
-  {
-    MOZ_ASSERT(!mPrincipalHolder, "Should have already been released");
-    MOZ_ASSERT(mActorDestroyed);
-    MOZ_ASSERT(mFinished);
-    MOZ_COUNT_DTOR(ParentProcessRunnable);
-  }
-
-  bool
-  Recv__delete__(const JS::AsmJSCacheResult& aResult) override
-  {
-    MOZ_ASSERT(!mFinished);
-    mFinished = true;
-
-    if (mOpened) {
-      MainProcessRunnable::Close();
-    } else {
-      MainProcessRunnable::Fail();
-    }
-
-    return true;
-  }
-
-  void
-  ActorDestroy(ActorDestroyReason why) override
-  {
-    MOZ_ASSERT(!mActorDestroyed);
-    mActorDestroyed = true;
-
-    // Assume ActorDestroy can happen at any time, so probe the current state to
-    // determine what needs to happen.
-
-    if (mFinished) {
-      return;
-    }
-
-    mFinished = true;
-
-    if (mOpened) {
-      MainProcessRunnable::Close();
-    } else {
-      MainProcessRunnable::Fail();
-    }
-  }
-
-  void
-  OnOpenMetadataForRead(const Metadata& aMetadata) override
-  {
-    MOZ_ASSERT(NS_IsMainThread());
-
-    if (!SendOnOpenMetadataForRead(aMetadata)) {
-      unused << Send__delete__(this, JS::AsmJSCache_InternalError);
-    }
-  }
-
-  bool
-  RecvSelectCacheFileToRead(const uint32_t& aModuleIndex) override
-  {
-    MainProcessRunnable::OpenForRead(aModuleIndex);
-    return true;
-  }
-
-  bool
-  RecvCacheMiss() override
-  {
-    MainProcessRunnable::CacheMiss();
-    return true;
-  }
-
-  void
-  OnOpenCacheFile() override
-  {
-    MOZ_ASSERT(NS_IsMainThread());
-
-    MOZ_ASSERT(!mOpened);
-    mOpened = true;
-
-    FileDescriptor::PlatformHandleType handle =
-      FileDescriptor::PlatformHandleType(PR_FileDesc2NativeHandle(mFileDesc));
-    if (!SendOnOpenCacheFile(mFileSize, FileDescriptor(handle))) {
-      unused << Send__delete__(this, JS::AsmJSCache_InternalError);
-    }
-  }
-
-  void
-  OnClose() override final
-  {
-    MOZ_ASSERT(NS_IsMainThread());
-    MOZ_ASSERT(mOpened);
-
-    mFinished = true;
-
-    MainProcessRunnable::OnClose();
-
-    MOZ_ASSERT(mActorDestroyed);
-
-    mPrincipalHolder = nullptr;
-  }
-
-  void
-  OnFailure(JS::AsmJSCacheResult aResult) override
-  {
-    MOZ_ASSERT(NS_IsMainThread());
-    MOZ_ASSERT(!mOpened);
-
-    mFinished = true;
-
-    MainProcessRunnable::OnFailure(aResult);
-
-    if (!mActorDestroyed) {
-      unused << Send__delete__(this, aResult);
-    }
-
-    mPrincipalHolder = nullptr;
-  }
-
-  nsCOMPtr<nsIPrincipal> mPrincipalHolder;
-  bool mActorDestroyed;
-  bool mOpened;
-  bool mFinished;
-};
-
-NS_IMPL_ISUPPORTS_INHERITED0(ParentProcessRunnable, FileDescriptorHolder)
-
 } // unnamed namespace
 
 PAsmJSCacheEntryParent*
 AllocEntryParent(OpenMode aOpenMode,
                  WriteParams aWriteParams,
-                 nsIPrincipal* aPrincipal)
+                 const PrincipalInfo& aPrincipalInfo)
 {
-  nsRefPtr<ParentProcessRunnable> runnable =
-    new ParentProcessRunnable(aPrincipal, aOpenMode, aWriteParams);
+  AssertIsOnBackgroundThread();
+
+  if (NS_WARN_IF(aPrincipalInfo.type() == PrincipalInfo::TNullPrincipalInfo)) {
+    MOZ_ASSERT(false);
+    return nullptr;
+  }
+
+  nsRefPtr<ParentRunnable> runnable =
+    new ParentRunnable(aPrincipalInfo, aOpenMode, aWriteParams);
 
   nsresult rv = NS_DispatchToMainThread(runnable);
   NS_ENSURE_SUCCESS(rv, nullptr);
 
   // Transfer ownership to IPDL.
   return runnable.forget().take();
 }
 
 void
 DeallocEntryParent(PAsmJSCacheEntryParent* aActor)
 {
   // Transfer ownership back from IPDL.
-  nsRefPtr<ParentProcessRunnable> op =
-    dont_AddRef(static_cast<ParentProcessRunnable*>(aActor));
+  nsRefPtr<ParentRunnable> op =
+    dont_AddRef(static_cast<ParentRunnable*>(aActor));
 }
 
 namespace {
 
-class ChildProcessRunnable final : public File,
-                                   public PAsmJSCacheEntryChild
+// A runnable that presents a single interface to the AsmJSCache ops which need
+// to wait until the file is open.
+class ChildRunnable final
+  : public FileDescriptorHolder
+  , public PAsmJSCacheEntryChild
+  , public nsIIPCBackgroundChildCreateCallback
 {
+  typedef mozilla::ipc::PBackgroundChild PBackgroundChild;
+
 public:
-  NS_DECL_NSIRUNNABLE
+  class AutoClose
+  {
+    ChildRunnable* mChildRunnable;
+
+  public:
+    explicit AutoClose(ChildRunnable* aChildRunnable = nullptr)
+    : mChildRunnable(aChildRunnable)
+    { }
+
+    void
+    Init(ChildRunnable* aChildRunnable)
+    {
+      MOZ_ASSERT(!mChildRunnable);
+      mChildRunnable = aChildRunnable;
+    }
 
-  // In the single-process case, the calling JS compilation thread holds the
-  // nsIPrincipal alive indirectly (via the global object -> compartment ->
-  // principal) so we don't have to ref-count it here. This is fortunate since
-  // we are off the main thread and nsIPrincipals can only be ref-counted on
-  // the main thread.
-  ChildProcessRunnable(nsIPrincipal* aPrincipal,
-                       OpenMode aOpenMode,
-                       WriteParams aWriteParams,
-                       ReadParams aReadParams)
+    ChildRunnable*
+    operator->() const MOZ_NO_ADDREF_RELEASE_ON_RETURN
+    {
+      MOZ_ASSERT(mChildRunnable);
+      return mChildRunnable;
+    }
+
+    void
+    Forget(ChildRunnable** aChildRunnable)
+    {
+      *aChildRunnable = mChildRunnable;
+      mChildRunnable = nullptr;
+    }
+
+    ~AutoClose()
+    {
+      if (mChildRunnable) {
+        mChildRunnable->Close();
+      }
+    }
+  };
+
+  NS_DECL_ISUPPORTS_INHERITED
+  NS_DECL_NSIRUNNABLE
+  NS_DECL_NSIIPCBACKGROUNDCHILDCREATECALLBACK
+
+  ChildRunnable(nsIPrincipal* aPrincipal,
+                OpenMode aOpenMode,
+                WriteParams aWriteParams,
+                ReadParams aReadParams)
   : mPrincipal(aPrincipal),
-    mOpenMode(aOpenMode),
     mWriteParams(aWriteParams),
     mReadParams(aReadParams),
+    mMutex("ChildRunnable::mMutex"),
+    mCondVar(mMutex, "ChildRunnable::mCondVar"),
+    mOpenMode(aOpenMode),
+    mState(eInitial),
+    mResult(JS::AsmJSCache_InternalError),
     mActorDestroyed(false),
-    mState(eInitial)
+    mWaiting(false),
+    mOpened(false)
   {
-    MOZ_ASSERT(!XRE_IsParentProcess());
     MOZ_ASSERT(!NS_IsMainThread());
-    MOZ_COUNT_CTOR(ChildProcessRunnable);
+    MOZ_COUNT_CTOR(ChildRunnable);
   }
 
-protected:
-  ~ChildProcessRunnable()
+  JS::AsmJSCacheResult
+  BlockUntilOpen(AutoClose* aCloser)
   {
-    MOZ_ASSERT(mState == eFinished);
-    MOZ_ASSERT(mActorDestroyed);
-    MOZ_COUNT_DTOR(ChildProcessRunnable);
+    MOZ_ASSERT(!mWaiting, "Can only call BlockUntilOpen once");
+    MOZ_ASSERT(!mOpened, "Can only call BlockUntilOpen once");
+
+    mWaiting = true;
+
+    nsresult rv = NS_DispatchToMainThread(this);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return JS::AsmJSCache_InternalError;
+    }
+
+    {
+      MutexAutoLock lock(mMutex);
+      while (mWaiting) {
+        mCondVar.Wait();
+      }
+    }
+
+    if (!mOpened) {
+      return mResult;
+    }
+
+    // Now that we're open, we're guaranteed a Close() call. However, we are
+    // not guaranteed someone is holding an outstanding reference until the File
+    // is closed, so we do that ourselves and Release() in OnClose().
+    aCloser->Init(this);
+    AddRef();
+    return JS::AsmJSCache_Success;
   }
 
 private:
+  ~ChildRunnable()
+  {
+    MOZ_ASSERT(!mWaiting, "Shouldn't be destroyed while thread is waiting");
+    MOZ_ASSERT(!mOpened);
+    MOZ_ASSERT(mState == eFinished);
+    MOZ_ASSERT(mActorDestroyed);
+    MOZ_COUNT_DTOR(ChildRunnable);
+  }
+
+  // IPDL methods.
   bool
   RecvOnOpenMetadataForRead(const Metadata& aMetadata) override
   {
     MOZ_ASSERT(NS_IsMainThread());
     MOZ_ASSERT(mState == eOpening);
 
     uint32_t moduleIndex;
     if (FindHashMatch(aMetadata, mReadParams, &moduleIndex)) {
@@ -1440,17 +1303,17 @@ private:
     mFileSize = aFileSize;
 
     mFileDesc = PR_ImportFile(PROsfd(aFileDesc.PlatformHandle()));
     if (!mFileDesc) {
       return false;
     }
 
     mState = eOpened;
-    File::OnOpen();
+    Notify(JS::AsmJSCache_Success);
     return true;
   }
 
   bool
   Recv__delete__(const JS::AsmJSCacheResult& aResult) override
   {
     MOZ_ASSERT(NS_IsMainThread());
     MOZ_ASSERT(mState == eOpening);
@@ -1462,123 +1325,207 @@ private:
   void
   ActorDestroy(ActorDestroyReason why) override
   {
     MOZ_ASSERT(NS_IsMainThread());
     mActorDestroyed = true;
   }
 
   void
-  Close() override final
+  Close()
   {
     MOZ_ASSERT(mState == eOpened);
 
     mState = eClosing;
     NS_DispatchToMainThread(this);
   }
 
-private:
   void
   Fail(JS::AsmJSCacheResult aResult)
   {
     MOZ_ASSERT(NS_IsMainThread());
     MOZ_ASSERT(mState == eInitial || mState == eOpening);
+    MOZ_ASSERT(aResult != JS::AsmJSCache_Success);
 
     mState = eFinished;
-    File::OnFailure(aResult);
+
+    FileDescriptorHolder::Finish();
+    Notify(aResult);
+  }
+
+  void
+  Notify(JS::AsmJSCacheResult aResult)
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+
+    MutexAutoLock lock(mMutex);
+    MOZ_ASSERT(mWaiting);
+
+    mWaiting = false;
+    mOpened = aResult == JS::AsmJSCache_Success;
+    mResult = aResult;
+    mCondVar.Notify();
   }
 
   nsIPrincipal* const mPrincipal;
-  const OpenMode mOpenMode;
+  nsAutoPtr<PrincipalInfo> mPrincipalInfo;
   WriteParams mWriteParams;
   ReadParams mReadParams;
-  bool mActorDestroyed;
+  Mutex mMutex;
+  CondVar mCondVar;
 
+  // Couple enums and bools together
+  const OpenMode mOpenMode;
   enum State {
-    eInitial, // Just created, waiting to dispatched to the main thread
+    eInitial, // Just created, waiting to be dispatched to the main thread
+    eBackgroundChildPending, // Waiting for the background child to be created
     eOpening, // Waiting for the parent process to respond
     eOpened, // Parent process opened the entry and sent it back
     eClosing, // Waiting to be dispatched to the main thread to Send__delete__
     eFinished // Terminal state
   };
   State mState;
+  JS::AsmJSCacheResult mResult;
+
+  bool mActorDestroyed;
+  bool mWaiting;
+  bool mOpened;
 };
 
 NS_IMETHODIMP
-ChildProcessRunnable::Run()
+ChildRunnable::Run()
 {
   switch (mState) {
     case eInitial: {
       MOZ_ASSERT(NS_IsMainThread());
 
-      // AddRef to keep this runnable alive until IPDL deallocates the
-      // subprotocol (DeallocEntryChild).
-      AddRef();
+      bool nullPrincipal;
+      nsresult rv = mPrincipal->GetIsNullPrincipal(&nullPrincipal);
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        Fail(JS::AsmJSCache_InternalError);
+        return NS_OK;
+      }
 
-      if (!ContentChild::GetSingleton()->SendPAsmJSCacheEntryConstructor(
-        this, mOpenMode, mWriteParams, IPC::Principal(mPrincipal)))
-      {
-        // On failure, undo the AddRef (since DeallocEntryChild will not be
-        // called) and unblock the parsing thread with a failure. The main
-        // thread event loop still holds an outstanding ref which will keep
-        // 'this' alive until returning to the event loop.
-        Release();
-
+      if (nullPrincipal) {
+        NS_WARNING("AsmsJSCache not supported on null principal.");
         Fail(JS::AsmJSCache_InternalError);
         return NS_OK;
       }
 
-      mState = eOpening;
+      nsAutoPtr<PrincipalInfo> principalInfo(new PrincipalInfo());
+      rv = PrincipalToPrincipalInfo(mPrincipal, principalInfo);
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        Fail(JS::AsmJSCache_InternalError);
+        return NS_OK;
+      }
+
+      mPrincipalInfo = Move(principalInfo);
+
+      PBackgroundChild* actor = BackgroundChild::GetForCurrentThread();
+      if (actor) {
+        ActorCreated(actor);
+        return NS_OK;
+      }
+
+      if (NS_WARN_IF(!BackgroundChild::GetOrCreateForCurrentThread(this))) {
+        Fail(JS::AsmJSCache_InternalError);
+        return NS_OK;
+      }
+
+      mState = eBackgroundChildPending;
       return NS_OK;
     }
 
     case eClosing: {
       MOZ_ASSERT(NS_IsMainThread());
 
       // Per FileDescriptorHolder::Finish()'s comment, call before
       // releasing the directory lock (which happens in the parent upon receipt
       // of the Send__delete__ message).
-      File::OnClose();
+      FileDescriptorHolder::Finish();
+
+      MOZ_ASSERT(mOpened);
+      mOpened = false;
+
+      // Match the AddRef in BlockUntilOpen(). The main thread event loop still
+      // holds an outstanding ref which will keep 'this' alive until returning to
+      // the event loop.
+      Release();
 
       if (!mActorDestroyed) {
         unused << Send__delete__(this, JS::AsmJSCache_Success);
       }
 
       mState = eFinished;
       return NS_OK;
     }
 
+    case eBackgroundChildPending:
     case eOpening:
     case eOpened:
     case eFinished: {
       MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("Shouldn't Run() in this state");
     }
   }
 
   MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("Corrupt state");
   return NS_OK;
 }
 
+void
+ChildRunnable::ActorCreated(PBackgroundChild* aActor)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  if (!aActor->SendPAsmJSCacheEntryConstructor(this, mOpenMode, mWriteParams,
+                                               *mPrincipalInfo)) {
+    // Unblock the parsing thread with a failure.
+
+    Fail(JS::AsmJSCache_InternalError);
+
+    return;
+  }
+
+  // AddRef to keep this runnable alive until IPDL deallocates the
+  // subprotocol (DeallocEntryChild).
+  AddRef();
+
+  mState = eOpening;
+}
+
+void
+ChildRunnable::ActorFailed()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(mState == eBackgroundChildPending);
+
+  Fail(JS::AsmJSCache_InternalError);
+}
+
+NS_IMPL_ISUPPORTS_INHERITED(ChildRunnable,
+                            FileDescriptorHolder,
+                            nsIIPCBackgroundChildCreateCallback)
+
 } // unnamed namespace
 
 void
 DeallocEntryChild(PAsmJSCacheEntryChild* aActor)
 {
   // Match the AddRef before SendPAsmJSCacheEntryConstructor.
-  static_cast<ChildProcessRunnable*>(aActor)->Release();
+  static_cast<ChildRunnable*>(aActor)->Release();
 }
 
 namespace {
 
 JS::AsmJSCacheResult
 OpenFile(nsIPrincipal* aPrincipal,
          OpenMode aOpenMode,
          WriteParams aWriteParams,
          ReadParams aReadParams,
-         File::AutoClose* aFile)
+         ChildRunnable::AutoClose* aChildRunnable)
 {
   MOZ_ASSERT_IF(aOpenMode == eOpenForRead, aWriteParams.mSize == 0);
   MOZ_ASSERT_IF(aOpenMode == eOpenForWrite, aReadParams.mBegin == nullptr);
 
   // There are three reasons we don't attempt caching from the main thread:
   //  1. In the parent process: QuotaManager::WaitForOpenAllowed prevents
   //     synchronous waiting on the main thread requiring a runnable to be
   //     dispatched to the main thread.
@@ -1589,34 +1536,29 @@ OpenFile(nsIPrincipal* aPrincipal,
   //     occasional janks on the main thread.
   // We could use a nested event loop to address 1 and 2, but we're potentially
   // in the middle of running JS (eval()) and nested event loops can be
   // semantically observable.
   if (NS_IsMainThread()) {
     return JS::AsmJSCache_SynchronousScript;
   }
 
-  // If we are in a child process, we need to synchronously call into the
-  // parent process to open the file and interact with the QuotaManager. The
-  // child can then map the file into its address space to perform I/O.
-  nsRefPtr<File> file;
-  if (XRE_IsParentProcess()) {
-    file = new SingleProcessRunnable(aPrincipal, aOpenMode, aWriteParams,
-                                     aReadParams);
-  } else {
-    file = new ChildProcessRunnable(aPrincipal, aOpenMode, aWriteParams,
-                                    aReadParams);
-  }
+  // We need to synchronously call into the parent to open the file and
+  // interact with the QuotaManager. The child can then map the file into its
+  // address space to perform I/O.
+  nsRefPtr<ChildRunnable> childRunnable =
+    new ChildRunnable(aPrincipal, aOpenMode, aWriteParams, aReadParams);
 
-  JS::AsmJSCacheResult openResult = file->BlockUntilOpen(aFile);
+  JS::AsmJSCacheResult openResult =
+    childRunnable->BlockUntilOpen(aChildRunnable);
   if (openResult != JS::AsmJSCache_Success) {
     return openResult;
   }
 
-  if (!file->MapMemory(aOpenMode)) {
+  if (!childRunnable->MapMemory(aOpenMode)) {
     return JS::AsmJSCache_InternalError;
   }
 
   return JS::AsmJSCache_Success;
 }
 
 } // namespace
 
@@ -1624,78 +1566,80 @@ typedef uint32_t AsmJSCookieType;
 static const uint32_t sAsmJSCookie = 0x600d600d;
 
 bool
 OpenEntryForRead(nsIPrincipal* aPrincipal,
                  const char16_t* aBegin,
                  const char16_t* aLimit,
                  size_t* aSize,
                  const uint8_t** aMemory,
-                 intptr_t* aFile)
+                 intptr_t* aHandle)
 {
   if (size_t(aLimit - aBegin) < sMinCachedModuleLength) {
     return false;
   }
 
   ReadParams readParams;
   readParams.mBegin = aBegin;
   readParams.mLimit = aLimit;
 
-  File::AutoClose file;
+  ChildRunnable::AutoClose childRunnable;
   WriteParams notAWrite;
   JS::AsmJSCacheResult openResult =
-    OpenFile(aPrincipal, eOpenForRead, notAWrite, readParams, &file);
+    OpenFile(aPrincipal, eOpenForRead, notAWrite, readParams, &childRunnable);
   if (openResult != JS::AsmJSCache_Success) {
     return false;
   }
 
   // Although we trust that the stored cache files have not been arbitrarily
   // corrupted, it is possible that a previous execution aborted in the middle
   // of writing a cache file (crash, OOM-killer, etc). To protect against
   // partially-written cache files, we use the following scheme:
   //  - Allocate an extra word at the beginning of every cache file which
   //    starts out 0 (OpenFile opens with PR_TRUNCATE).
   //  - After the asm.js serialization is complete, PR_SyncMemMap to write
   //    everything to disk and then store a non-zero value (sAsmJSCookie)
   //    in the first word.
   //  - When attempting to read a cache file, check whether the first word is
   //    sAsmJSCookie.
-  if (file->FileSize() < sizeof(AsmJSCookieType) ||
-      *(AsmJSCookieType*)file->MappedMemory() != sAsmJSCookie) {
+  if (childRunnable->FileSize() < sizeof(AsmJSCookieType) ||
+      *(AsmJSCookieType*)childRunnable->MappedMemory() != sAsmJSCookie) {
     return false;
   }
 
-  *aSize = file->FileSize() - sizeof(AsmJSCookieType);
-  *aMemory = (uint8_t*) file->MappedMemory() + sizeof(AsmJSCookieType);
+  *aSize = childRunnable->FileSize() - sizeof(AsmJSCookieType);
+  *aMemory = (uint8_t*) childRunnable->MappedMemory() + sizeof(AsmJSCookieType);
 
   // The caller guarnatees a call to CloseEntryForRead (on success or
   // failure) at which point the file will be closed.
-  file.Forget(reinterpret_cast<File**>(aFile));
+  childRunnable.Forget(reinterpret_cast<ChildRunnable**>(aHandle));
   return true;
 }
 
 void
 CloseEntryForRead(size_t aSize,
                   const uint8_t* aMemory,
-                  intptr_t aFile)
+                  intptr_t aHandle)
 {
-  File::AutoClose file(reinterpret_cast<File*>(aFile));
+  ChildRunnable::AutoClose childRunnable(
+    reinterpret_cast<ChildRunnable*>(aHandle));
 
-  MOZ_ASSERT(aSize + sizeof(AsmJSCookieType) == file->FileSize());
-  MOZ_ASSERT(aMemory - sizeof(AsmJSCookieType) == file->MappedMemory());
+  MOZ_ASSERT(aSize + sizeof(AsmJSCookieType) == childRunnable->FileSize());
+  MOZ_ASSERT(aMemory - sizeof(AsmJSCookieType) ==
+               childRunnable->MappedMemory());
 }
 
 JS::AsmJSCacheResult
 OpenEntryForWrite(nsIPrincipal* aPrincipal,
                   bool aInstalled,
                   const char16_t* aBegin,
                   const char16_t* aEnd,
                   size_t aSize,
                   uint8_t** aMemory,
-                  intptr_t* aFile)
+                  intptr_t* aHandle)
 {
   if (size_t(aEnd - aBegin) < sMinCachedModuleLength) {
     return JS::AsmJSCache_ModuleTooSmall;
   }
 
   // Add extra space for the AsmJSCookieType (see OpenEntryForRead).
   aSize += sizeof(AsmJSCookieType);
 
@@ -1703,50 +1647,52 @@ OpenEntryForWrite(nsIPrincipal* aPrincip
 
   WriteParams writeParams;
   writeParams.mInstalled = aInstalled;
   writeParams.mSize = aSize;
   writeParams.mFastHash = HashString(aBegin, sNumFastHashChars);
   writeParams.mNumChars = aEnd - aBegin;
   writeParams.mFullHash = HashString(aBegin, writeParams.mNumChars);
 
-  File::AutoClose file;
+  ChildRunnable::AutoClose childRunnable;
   ReadParams notARead;
   JS::AsmJSCacheResult openResult =
-    OpenFile(aPrincipal, eOpenForWrite, writeParams, notARead, &file);
+    OpenFile(aPrincipal, eOpenForWrite, writeParams, notARead, &childRunnable);
   if (openResult != JS::AsmJSCache_Success) {
     return openResult;
   }
 
   // Strip off the AsmJSCookieType from the buffer returned to the caller,
   // which expects a buffer of aSize, not a buffer of sizeWithCookie starting
   // with a cookie.
-  *aMemory = (uint8_t*) file->MappedMemory() + sizeof(AsmJSCookieType);
+  *aMemory = (uint8_t*) childRunnable->MappedMemory() + sizeof(AsmJSCookieType);
 
   // The caller guarnatees a call to CloseEntryForWrite (on success or
   // failure) at which point the file will be closed
-  file.Forget(reinterpret_cast<File**>(aFile));
+  childRunnable.Forget(reinterpret_cast<ChildRunnable**>(aHandle));
   return JS::AsmJSCache_Success;
 }
 
 void
 CloseEntryForWrite(size_t aSize,
                    uint8_t* aMemory,
-                   intptr_t aFile)
+                   intptr_t aHandle)
 {
-  File::AutoClose file(reinterpret_cast<File*>(aFile));
+  ChildRunnable::AutoClose childRunnable(
+    reinterpret_cast<ChildRunnable*>(aHandle));
 
-  MOZ_ASSERT(aSize + sizeof(AsmJSCookieType) == file->FileSize());
-  MOZ_ASSERT(aMemory - sizeof(AsmJSCookieType) == file->MappedMemory());
+  MOZ_ASSERT(aSize + sizeof(AsmJSCookieType) == childRunnable->FileSize());
+  MOZ_ASSERT(aMemory - sizeof(AsmJSCookieType) ==
+               childRunnable->MappedMemory());
 
   // Flush to disk before writing the cookie (see OpenEntryForRead).
-  if (PR_SyncMemMap(file->FileDesc(),
-                    file->MappedMemory(),
-                    file->FileSize()) == PR_SUCCESS) {
-    *(AsmJSCookieType*)file->MappedMemory() = sAsmJSCookie;
+  if (PR_SyncMemMap(childRunnable->FileDesc(),
+                    childRunnable->MappedMemory(),
+                    childRunnable->FileSize()) == PR_SUCCESS) {
+    *(AsmJSCookieType*)childRunnable->MappedMemory() = sAsmJSCookie;
   }
 }
 
 bool
 GetBuildId(JS::BuildIdCharVector* aBuildID)
 {
   nsCOMPtr<nsIXULAppInfo> info = do_GetService("@mozilla.org/xre/app-info;1");
   if (!info) {
--- a/dom/asmjscache/AsmJSCache.h
+++ b/dom/asmjscache/AsmJSCache.h
@@ -10,16 +10,23 @@
 #include "ipc/IPCMessageUtils.h"
 #include "js/TypeDecls.h"
 #include "js/Vector.h"
 #include "jsapi.h"
 
 class nsIPrincipal;
 
 namespace mozilla {
+
+namespace ipc {
+
+class PrincipalInfo;
+
+} // namespace ipc
+
 namespace dom {
 
 namespace quota {
 class Client;
 } // namespace quota
 
 namespace asmjscache {
 
@@ -132,17 +139,17 @@ GetBuildId(JS::BuildIdCharVector* aBuild
 
 quota::Client*
 CreateClient();
 
 // Called from ipc/ContentParent.cpp:
 
 PAsmJSCacheEntryParent*
 AllocEntryParent(OpenMode aOpenMode, WriteParams aWriteParams,
-                 nsIPrincipal* aPrincipal);
+                 const mozilla::ipc::PrincipalInfo& aPrincipalInfo);
 
 void
 DeallocEntryParent(PAsmJSCacheEntryParent* aActor);
 
 // Called from ipc/ContentChild.cpp:
 
 void
 DeallocEntryChild(PAsmJSCacheEntryChild* aActor);
--- a/dom/asmjscache/PAsmJSCacheEntry.ipdl
+++ b/dom/asmjscache/PAsmJSCacheEntry.ipdl
@@ -1,24 +1,24 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-include protocol PContent;
+include protocol PBackground;
 
 using mozilla::dom::asmjscache::Metadata from "mozilla/dom/asmjscache/AsmJSCache.h";
 using JS::AsmJSCacheResult from "mozilla/dom/asmjscache/AsmJSCache.h";
 
 namespace mozilla {
 namespace dom {
 namespace asmjscache {
 
 protocol PAsmJSCacheEntry
 {
-  manager PContent;
+  manager PBackground;
 
   // When the cache is opened to read, the parent process sends over the
   // origin's Metadata so the child process can select the cache entry to open
   // (based on hash) and notify the parent (via SelectCacheFileToRead).
 child:
   OnOpenMetadataForRead(Metadata metadata);
 parent:
   SelectCacheFileToRead(uint32_t moduleIndex);
--- a/dom/base/Element.cpp
+++ b/dom/base/Element.cpp
@@ -2049,17 +2049,17 @@ Element::DispatchClickEvent(nsPresContex
                             bool aFullDispatch,
                             const EventFlags* aExtraEventFlags,
                             nsEventStatus* aStatus)
 {
   NS_PRECONDITION(aTarget, "Must have target");
   NS_PRECONDITION(aSourceEvent, "Must have source event");
   NS_PRECONDITION(aStatus, "Null out param?");
 
-  WidgetMouseEvent event(aSourceEvent->mFlags.mIsTrusted, NS_MOUSE_CLICK,
+  WidgetMouseEvent event(aSourceEvent->mFlags.mIsTrusted, eMouseClick,
                          aSourceEvent->widget, WidgetMouseEvent::eReal);
   event.refPoint = aSourceEvent->refPoint;
   uint32_t clickCount = 1;
   float pressure = 0;
   uint16_t inputSource = 0;
   WidgetMouseEvent* sourceMouseEvent = aSourceEvent->AsMouseEvent();
   if (sourceMouseEvent) {
     clickCount = sourceMouseEvent->clickCount;
@@ -2845,37 +2845,37 @@ Element::Describe(nsAString& aOutDescrip
 }
 
 bool
 Element::CheckHandleEventForLinksPrecondition(EventChainVisitor& aVisitor,
                                               nsIURI** aURI) const
 {
   if (aVisitor.mEventStatus == nsEventStatus_eConsumeNoDefault ||
       (!aVisitor.mEvent->mFlags.mIsTrusted &&
-       (aVisitor.mEvent->mMessage != NS_MOUSE_CLICK) &&
-       (aVisitor.mEvent->mMessage != NS_KEY_PRESS) &&
+       (aVisitor.mEvent->mMessage != eMouseClick) &&
+       (aVisitor.mEvent->mMessage != eKeyPress) &&
        (aVisitor.mEvent->mMessage != NS_UI_ACTIVATE)) ||
       !aVisitor.mPresContext ||
       aVisitor.mEvent->mFlags.mMultipleActionsPrevented) {
     return false;
   }
 
   // Make sure we actually are a link
   return IsLink(aURI);
 }
 
 nsresult
 Element::PreHandleEventForLinks(EventChainPreVisitor& aVisitor)
 {
   // Optimisation: return early if this event doesn't interest us.
   // IMPORTANT: this switch and the switch below it must be kept in sync!
   switch (aVisitor.mEvent->mMessage) {
-  case NS_MOUSE_OVER:
+  case eMouseOver:
   case NS_FOCUS_CONTENT:
-  case NS_MOUSE_OUT:
+  case eMouseOut:
   case NS_BLUR_CONTENT:
     break;
   default:
     return NS_OK;
   }
 
   // Make sure we meet the preconditions before continuing
   nsCOMPtr<nsIURI> absURI;
@@ -2884,32 +2884,32 @@ Element::PreHandleEventForLinks(EventCha
   }
 
   nsresult rv = NS_OK;
 
   // We do the status bar updates in PreHandleEvent so that the status bar gets
   // updated even if the event is consumed before we have a chance to set it.
   switch (aVisitor.mEvent->mMessage) {
   // Set the status bar similarly for mouseover and focus
-  case NS_MOUSE_OVER:
+  case eMouseOver:
     aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
     // FALL THROUGH
   case NS_FOCUS_CONTENT: {
     InternalFocusEvent* focusEvent = aVisitor.mEvent->AsFocusEvent();
     if (!focusEvent || !focusEvent->isRefocus) {
       nsAutoString target;
       GetLinkTarget(target);
       nsContentUtils::TriggerLink(this, aVisitor.mPresContext, absURI, target,
                                   false, true, true);
       // Make sure any ancestor links don't also TriggerLink
       aVisitor.mEvent->mFlags.mMultipleActionsPrevented = true;
     }
     break;
   }
-  case NS_MOUSE_OUT:
+  case eMouseOut:
     aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
     // FALL THROUGH
   case NS_BLUR_CONTENT:
     rv = LeaveLink(aVisitor.mPresContext);
     if (NS_SUCCEEDED(rv)) {
       aVisitor.mEvent->mFlags.mMultipleActionsPrevented = true;
     }
     break;
@@ -2924,35 +2924,35 @@ Element::PreHandleEventForLinks(EventCha
 }
 
 nsresult
 Element::PostHandleEventForLinks(EventChainPostVisitor& aVisitor)
 {
   // Optimisation: return early if this event doesn't interest us.
   // IMPORTANT: this switch and the switch below it must be kept in sync!
   switch (aVisitor.mEvent->mMessage) {
-  case NS_MOUSE_BUTTON_DOWN:
-  case NS_MOUSE_CLICK:
+  case eMouseDown:
+  case eMouseClick:
   case NS_UI_ACTIVATE:
-  case NS_KEY_PRESS:
+  case eKeyPress:
     break;
   default:
     return NS_OK;
   }
 
   // Make sure we meet the preconditions before continuing
   nsCOMPtr<nsIURI> absURI;
   if (!CheckHandleEventForLinksPrecondition(aVisitor, getter_AddRefs(absURI))) {
     return NS_OK;
   }
 
   nsresult rv = NS_OK;
 
   switch (aVisitor.mEvent->mMessage) {
-  case NS_MOUSE_BUTTON_DOWN:
+  case eMouseDown:
     {
       if (aVisitor.mEvent->AsMouseEvent()->button ==
             WidgetMouseEvent::eLeftButton) {
         // don't make the link grab the focus if there is no link handler
         nsILinkHandler *handler = aVisitor.mPresContext->GetLinkHandler();
         nsIDocument *document = GetComposedDoc();
         if (handler && document) {
           nsIFocusManager* fm = nsFocusManager::GetFocusManager();
@@ -2965,17 +2965,17 @@ Element::PostHandleEventForLinks(EventCh
 
           EventStateManager::SetActiveManager(
             aVisitor.mPresContext->EventStateManager(), this);
         }
       }
     }
     break;
 
-  case NS_MOUSE_CLICK: {
+  case eMouseClick: {
     WidgetMouseEvent* mouseEvent = aVisitor.mEvent->AsMouseEvent();
     if (mouseEvent->IsLeftClickEvent()) {
       if (mouseEvent->IsControl() || mouseEvent->IsMeta() ||
           mouseEvent->IsAlt() ||mouseEvent->IsShift()) {
         break;
       }
 
       // The default action is simply to dispatch DOMActivate
@@ -3005,17 +3005,17 @@ Element::PostHandleEventForLinks(EventCh
         MOZ_ASSERT(activeEvent);
         nsContentUtils::TriggerLink(this, aVisitor.mPresContext, absURI, target,
                                     true, true, activeEvent->IsTrustable());
         aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
       }
     }
     break;
 
-  case NS_KEY_PRESS:
+  case eKeyPress:
     {
       WidgetKeyboardEvent* keyEvent = aVisitor.mEvent->AsKeyboardEvent();
       if (keyEvent && keyEvent->keyCode == NS_VK_RETURN) {
         nsEventStatus status = nsEventStatus_eIgnore;
         rv = DispatchClickEvent(aVisitor.mPresContext, keyEvent, this,
                                 false, nullptr, &status);
         if (NS_SUCCEEDED(rv)) {
           aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
--- a/dom/base/FragmentOrElement.cpp
+++ b/dom/base/FragmentOrElement.cpp
@@ -672,18 +672,18 @@ nsIContent::PreHandleEvent(EventChainPre
 {
   //FIXME! Document how this event retargeting works, Bug 329124.
   aVisitor.mCanHandle = true;
   aVisitor.mMayHaveListenerManager = HasListenerManager();
 
   // Don't propagate mouseover and mouseout events when mouse is moving
   // inside chrome access only content.
   bool isAnonForEvents = IsRootOfChromeAccessOnlySubtree();
-  if ((aVisitor.mEvent->mMessage == NS_MOUSE_OVER ||
-       aVisitor.mEvent->mMessage == NS_MOUSE_OUT ||
+  if ((aVisitor.mEvent->mMessage == eMouseOver ||
+       aVisitor.mEvent->mMessage == eMouseOut ||
        aVisitor.mEvent->mMessage == NS_POINTER_OVER ||
        aVisitor.mEvent->mMessage == NS_POINTER_OUT) &&
       // Check if we should stop event propagation when event has just been
       // dispatched or when we're about to propagate from
       // chrome access only subtree or if we are about to propagate out of
       // a shadow root to a shadow root host.
       ((this == aVisitor.mEvent->originalTarget &&
         !ChromeOnlyAccess()) || isAnonForEvents || GetShadowRoot())) {
@@ -734,17 +734,17 @@ nsIContent::PreHandleEvent(EventChainPre
               if (originalTarget) {
                 originalTarget->NodeInfo()->NameAtom()->ToString(ot);
               }
               NodeInfo()->NameAtom()->ToString(ct);
               relatedTarget->NodeInfo()->NameAtom()->ToString(rt);
               printf("Stopping %s propagation:"
                      "\n\toriginalTarget=%s \n\tcurrentTarget=%s %s"
                      "\n\trelatedTarget=%s %s \n%s",
-                     (aVisitor.mEvent->mMessage == NS_MOUSE_OVER)
+                     (aVisitor.mEvent->mMessage == eMouseOver)
                        ? "mouseover" : "mouseout",
                      NS_ConvertUTF16toUTF8(ot).get(),
                      NS_ConvertUTF16toUTF8(ct).get(),
                      isAnonForEvents
                        ? "(is native anonymous)"
                        : (ChromeOnlyAccess()
                            ? "(is in native anonymous subtree)" : ""),
                      NS_ConvertUTF16toUTF8(rt).get(),
@@ -807,18 +807,18 @@ nsIContent::PreHandleEvent(EventChainPre
     bool stopEvent = false;
     switch (aVisitor.mEvent->mMessage) {
       case NS_IMAGE_ABORT:
       case NS_LOAD_ERROR:
       case NS_FORM_SELECTED:
       case NS_FORM_CHANGE:
       case NS_LOAD:
       case NS_FORM_RESET:
-      case NS_RESIZE_EVENT:
-      case NS_SCROLL_EVENT:
+      case eResize:
+      case eScroll:
         stopEvent = true;
         break;
       case NS_USER_DEFINED_EVENT:
         if (aVisitor.mDOMEvent) {
           nsAutoString eventType;
           aVisitor.mDOMEvent->GetType(eventType);
           if (eventType.EqualsLiteral("abort") ||
               eventType.EqualsLiteral("error") ||
--- a/dom/base/StructuredCloneHelper.cpp
+++ b/dom/base/StructuredCloneHelper.cpp
@@ -272,16 +272,17 @@ StructuredCloneHelper::Read(nsISupports*
   if (!StructuredCloneHelperInternal::Read(aCx, aValue)) {
     JS_ClearPendingException(aCx);
     aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
   }
 
   // If we are tranferring something, we cannot call 'Read()' more than once.
   if (mSupportsTransferring) {
     mBlobImplArray.Clear();
+    mClonedImages.Clear();
     Shutdown();
   }
 }
 
 void
 StructuredCloneHelper::ReadFromBuffer(nsISupports* aParent,
                                       JSContext* aCx,
                                       uint64_t* aBuffer,
@@ -428,17 +429,17 @@ EnsureBlobForBackgroundManager(BlobImpl*
 
 JSObject*
 ReadBlob(JSContext* aCx,
          uint32_t aIndex,
          StructuredCloneHelper* aHelper)
 {
   MOZ_ASSERT(aHelper);
   MOZ_ASSERT(aIndex < aHelper->BlobImpls().Length());
-  nsRefPtr<BlobImpl> blobImpl =  aHelper->BlobImpls()[aIndex];
+  nsRefPtr<BlobImpl> blobImpl = aHelper->BlobImpls()[aIndex];
 
   blobImpl = EnsureBlobForBackgroundManager(blobImpl);
   MOZ_ASSERT(blobImpl);
 
   // nsRefPtr<File> needs to go out of scope before toObjectOrNull() is
   // called because the static analysis thinks dereferencing XPCOM objects
   // can GC (because in some cases it can!), and a return statement with a
   // JSObject* type means that JSObject* is on the stack as a raw pointer
@@ -502,16 +503,19 @@ ReadFileList(JSContext* aCx,
     // |aCount| is the number of BlobImpls to use from the |offset|.
     for (uint32_t i = 0; i < aCount; ++i) {
       uint32_t index = offset + i;
       MOZ_ASSERT(index < aHelper->BlobImpls().Length());
 
       nsRefPtr<BlobImpl> blobImpl = aHelper->BlobImpls()[index];
       MOZ_ASSERT(blobImpl->IsFile());
 
+      blobImpl = EnsureBlobForBackgroundManager(blobImpl);
+      MOZ_ASSERT(blobImpl);
+
       nsRefPtr<File> file = File::Create(aHelper->ParentDuringRead(), blobImpl);
       if (!fileList->Append(file)) {
         return nullptr;
       }
     }
 
     if (!ToJSValue(aCx, fileList, &val)) {
       return nullptr;
@@ -539,17 +543,21 @@ WriteFileList(JSStructuredCloneWriter* a
   if (!JS_WriteUint32Pair(aWriter, SCTAG_DOM_FILELIST,
                           aFileList->Length()) ||
       !JS_WriteUint32Pair(aWriter, 0,
                           aHelper->BlobImpls().Length())) {
     return false;
   }
 
   for (uint32_t i = 0; i < aFileList->Length(); ++i) {
-    aHelper->BlobImpls().AppendElement(aFileList->Item(i)->Impl());
+    nsRefPtr<BlobImpl> blobImpl =
+      EnsureBlobForBackgroundManager(aFileList->Item(i)->Impl());
+    MOZ_ASSERT(blobImpl);
+
+    aHelper->BlobImpls().AppendElement(blobImpl);
   }
 
   return true;
 }
 
 // Read the WriteFormData for the format.
 JSObject*
 ReadFormData(JSContext* aCx,
--- a/dom/base/TextInputProcessor.cpp
+++ b/dom/base/TextInputProcessor.cpp
@@ -244,17 +244,17 @@ TextInputProcessor::IsValidStateForCompo
   return NS_OK;
 }
 
 bool
 TextInputProcessor::IsValidEventTypeForComposition(
                       const WidgetKeyboardEvent& aKeyboardEvent) const
 {
   // The key event type of composition methods must be "" or "keydown".
-  if (aKeyboardEvent.mMessage == NS_KEY_DOWN) {
+  if (aKeyboardEvent.mMessage == eKeyDown) {
     return true;
   }
   if (aKeyboardEvent.mMessage == NS_USER_DEFINED_EVENT &&
       aKeyboardEvent.userType &&
       nsDependentAtomString(aKeyboardEvent.userType).EqualsLiteral("on")) {
     return true;
   }
   return false;
@@ -305,19 +305,19 @@ TextInputProcessor::MaybeDispatchKeyupFo
                       uint32_t aKeyFlags)
 {
   EventDispatcherResult result;
 
   if (!aKeyboardEvent) {
     return result;
   }
 
-  // If the mMessage is NS_KEY_DOWN, the caller doesn't want TIP to dispatch
+  // If the mMessage is eKeyDown, the caller doesn't want TIP to dispatch
   // keyup event.
-  if (aKeyboardEvent->mMessage == NS_KEY_DOWN) {
+  if (aKeyboardEvent->mMessage == eKeyDown) {
     return result;
   }
 
   // If the widget has been destroyed, we can do nothing here.
   result.mResult = IsValidStateForComposition();
   if (NS_FAILED(result.mResult)) {
     result.mCanContinue = false;
     return result;
@@ -833,17 +833,17 @@ TextInputProcessor::KeydownInternal(cons
   nsRefPtr<TextEventDispatcher> kungfuDeathGrip(mDispatcher);
   rv = IsValidStateForComposition();
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   nsEventStatus status = aConsumedFlags ? nsEventStatus_eConsumeNoDefault :
                                           nsEventStatus_eIgnore;
-  if (!mDispatcher->DispatchKeyboardEvent(NS_KEY_DOWN, keyEvent, status,
+  if (!mDispatcher->DispatchKeyboardEvent(eKeyDown, keyEvent, status,
                                           GetDispatchTo())) {
     // If keydown event isn't dispatched, we don't need to dispatch keypress
     // events.
     return NS_OK;
   }
 
   aConsumedFlags |=
     (status == nsEventStatus_eConsumeNoDefault) ? KEYDOWN_IS_CONSUMED :
@@ -915,18 +915,17 @@ TextInputProcessor::KeyupInternal(const 
   nsRefPtr<TextEventDispatcher> kungfuDeathGrip(mDispatcher);
   rv = IsValidStateForComposition();
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   nsEventStatus status = aDoDefault ? nsEventStatus_eIgnore :
                                       nsEventStatus_eConsumeNoDefault;
-  mDispatcher->DispatchKeyboardEvent(NS_KEY_UP, keyEvent, status,
-                                     GetDispatchTo());
+  mDispatcher->DispatchKeyboardEvent(eKeyUp, keyEvent, status, GetDispatchTo());
   aDoDefault = (status != nsEventStatus_eConsumeNoDefault);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 TextInputProcessor::GetModifierState(const nsAString& aModifierKeyName,
                                      bool* aActive)
 {
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -7719,28 +7719,28 @@ nsContentUtils::SendKeyEvent(nsIWidget* 
                              bool* aDefaultActionTaken)
 {
   // get the widget to send the event to
   if (!aWidget)
     return NS_ERROR_FAILURE;
 
   EventMessage msg;
   if (aType.EqualsLiteral("keydown"))
-    msg = NS_KEY_DOWN;
+    msg = eKeyDown;
   else if (aType.EqualsLiteral("keyup"))
-    msg = NS_KEY_UP;
+    msg = eKeyUp;
   else if (aType.EqualsLiteral("keypress"))
-    msg = NS_KEY_PRESS;
+    msg = eKeyPress;
   else
     return NS_ERROR_FAILURE;
 
   WidgetKeyboardEvent event(true, msg, aWidget);
   event.modifiers = GetWidgetModifiers(aModifiers);
 
-  if (msg == NS_KEY_PRESS) {
+  if (msg == eKeyPress) {
     event.keyCode = aCharCode ? 0 : aKeyCode;
     event.charCode = aCharCode;
   } else {
     event.keyCode = aKeyCode;
     event.charCode = 0;
   }
 
   uint32_t locationFlag = (aAdditionalFlags &
@@ -7833,30 +7833,30 @@ nsContentUtils::SendMouseEvent(nsCOMPtr<
   nsPoint offset;
   nsCOMPtr<nsIWidget> widget = GetWidget(aPresShell, &offset);
   if (!widget)
     return NS_ERROR_FAILURE;
 
   EventMessage msg;
   bool contextMenuKey = false;
   if (aType.EqualsLiteral("mousedown"))
-    msg = NS_MOUSE_BUTTON_DOWN;
+    msg = eMouseDown;
   else if (aType.EqualsLiteral("mouseup"))
-    msg = NS_MOUSE_BUTTON_UP;
+    msg = eMouseUp;
   else if (aType.EqualsLiteral("mousemove"))
-    msg = NS_MOUSE_MOVE;
+    msg = eMouseMove;
   else if (aType.EqualsLiteral("mouseover"))
-    msg = NS_MOUSE_ENTER_WIDGET;
+    msg = eMouseEnterIntoWidget;
   else if (aType.EqualsLiteral("mouseout"))
-    msg = NS_MOUSE_EXIT_WIDGET;
+    msg = eMouseExitFromWidget;
   else if (aType.EqualsLiteral("contextmenu")) {
     msg = NS_CONTEXTMENU;
     contextMenuKey = (aButton == 0);
   } else if (aType.EqualsLiteral("MozMouseHittest"))
-    msg = NS_MOUSE_MOZHITTEST;
+    msg = eMouseHitTest;
   else
     return NS_ERROR_FAILURE;
 
   if (aInputSourceArg == nsIDOMMouseEvent::MOZ_SOURCE_UNKNOWN) {
     aInputSourceArg = nsIDOMMouseEvent::MOZ_SOURCE_MOUSE;
   }
 
   WidgetMouseEvent event(true, msg, widget, WidgetMouseEvent::eReal,
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -1310,17 +1310,19 @@ nsDOMWindowUtils::SendSimpleGestureEvent
 
   // get the widget to send the event to
   nsPoint offset;
   nsCOMPtr<nsIWidget> widget = GetWidget(&offset);
   if (!widget)
     return NS_ERROR_FAILURE;
 
   EventMessage msg;
-  if (aType.EqualsLiteral("MozSwipeGestureStart"))
+  if (aType.EqualsLiteral("MozSwipeGestureMayStart"))
+    msg = NS_SIMPLE_GESTURE_SWIPE_MAY_START;
+  else if (aType.EqualsLiteral("MozSwipeGestureStart"))
     msg = NS_SIMPLE_GESTURE_SWIPE_START;
   else if (aType.EqualsLiteral("MozSwipeGestureUpdate"))
     msg = NS_SIMPLE_GESTURE_SWIPE_UPDATE;
   else if (aType.EqualsLiteral("MozSwipeGestureEnd"))
     msg = NS_SIMPLE_GESTURE_SWIPE_END;
   else if (aType.EqualsLiteral("MozSwipeGesture"))
     msg = NS_SIMPLE_GESTURE_SWIPE;
   else if (aType.EqualsLiteral("MozMagnifyGestureStart"))
@@ -3572,17 +3574,17 @@ nsDOMWindowUtils::IsNodeDisabledForEvent
 {
   *aRetVal = false;
   MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
   nsCOMPtr<nsINode> n = do_QueryInterface(aNode);
   nsINode* node = n;
   while (node) {
     if (node->IsNodeOfType(nsINode::eHTML_FORM_CONTROL)) {
       nsCOMPtr<nsIFormControl> fc = do_QueryInterface(node);
-      if (fc && fc->IsDisabledForEvents(NS_EVENT_NULL)) {
+      if (fc && fc->IsDisabledForEvents(eVoidEvent)) {
         *aRetVal = true;
         break;
       }
     }
     node = node->GetParentNode();
   }
 
   return NS_OK;
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -11381,47 +11381,42 @@ LogFullScreenDenied(bool aLogFailure, co
                                   NS_LITERAL_CSTRING("DOM"), aDoc,
                                   nsContentUtils::eDOM_PROPERTIES,
                                   aMessage);
 }
 
 void
 nsDocument::CleanupFullscreenState()
 {
-  if (!mFullScreenStack.IsEmpty()) {
-    // The top element in the full-screen stack will have full-screen
-    // style bits set on it and its ancestors. Remove the style bits.
-    // Note the non-top elements won't have the style bits set.
-    Element* top = FullScreenStackTop();
-    NS_ASSERTION(top, "Should have a top when full-screen stack isn't empty");
-    if (top) {
+  // Iterate the fullscreen stack and clear the fullscreen states.
+  // Since we also need to clear the fullscreen-ancestor state, and
+  // currently fullscreen elements can only be placed in hierarchy
+  // order in the stack, reversely iterating the stack could be more
+  // efficient. NOTE that fullscreen-ancestor state would be removed
+  // in bug 1199529, and the elements may not in hierarchy order
+  // after bug 1195213.
+  for (nsWeakPtr& weakPtr : Reversed(mFullScreenStack)) {
+    if (nsCOMPtr<Element> element = do_QueryReferent(weakPtr)) {
       // Remove any VR state properties
-      top->DeleteProperty(nsGkAtoms::vr_state);
-
-      EventStateManager::SetFullScreenState(top, false);
-    }
-    mFullScreenStack.Clear();
-  }
+      element->DeleteProperty(nsGkAtoms::vr_state);
+      EventStateManager::SetFullScreenState(element, false);
+    }
+  }
+  mFullScreenStack.Clear();
   mFullscreenRoot = nullptr;
 }
 
 bool
 nsDocument::FullScreenStackPush(Element* aElement)
 {
   NS_ASSERTION(aElement, "Must pass non-null to FullScreenStackPush()");
   Element* top = FullScreenStackTop();
   if (top == aElement || !aElement) {
     return false;
   }
-  if (top) {
-    // We're pushing a new element onto the full-screen stack, so we must
-    // remove the ancestor and full-screen styles from the former top of the
-    // stack.
-    EventStateManager::SetFullScreenState(top, false);
-  }
   EventStateManager::SetFullScreenState(aElement, true);
   mFullScreenStack.AppendElement(do_GetWeakReference(aElement));
   NS_ASSERTION(GetFullScreenElement() == aElement, "Should match");
   return true;
 }
 
 void
 nsDocument::FullScreenStackPop()
@@ -11450,19 +11445,17 @@ nsDocument::FullScreenStackPop()
   while (!mFullScreenStack.IsEmpty()) {
     Element* element = FullScreenStackTop();
     if (!element || !element->IsInDoc() || element->OwnerDoc() != this) {
       NS_ASSERTION(!element->IsFullScreenAncestor(),
                    "Should have already removed full-screen styles");
       uint32_t last = mFullScreenStack.Length() - 1;
       mFullScreenStack.RemoveElementAt(last);
     } else {
-      // The top element of the stack is now an in-doc element. Apply the
-      // full-screen styles and return.
-      EventStateManager::SetFullScreenState(element, true);
+      // The top element of the stack is now an in-doc element. Return here.
       break;
     }
   }
 }
 
 Element*
 nsDocument::FullScreenStackTop()
 {
--- a/dom/base/nsGkAtomList.h
+++ b/dom/base/nsGkAtomList.h
@@ -1858,16 +1858,17 @@ GK_ATOM(daysFromDate, "days-from-date")
 GK_ATOM(init, "init")
 GK_ATOM(instance, "instance")
 GK_ATOM(months, "months")
 GK_ATOM(now, "now")
 GK_ATOM(seconds, "seconds")
 GK_ATOM(secondsFromDateTime, "seconds-from-dateTime")
 
 // Simple gestures support
+GK_ATOM(onMozSwipeGestureMayStart, "onMozSwipeGestureMayStart")
 GK_ATOM(onMozSwipeGestureStart, "onMozSwipeGestureStart")
 GK_ATOM(onMozSwipeGestureUpdate, "onMozSwipeGestureUpdate")
 GK_ATOM(onMozSwipeGestureEnd, "onMozSwipeGestureEnd")
 GK_ATOM(onMozSwipeGesture, "onMozSwipeGesture")
 GK_ATOM(onMozMagnifyGestureStart, "onMozMagnifyGestureStart")
 GK_ATOM(onMozMagnifyGestureUpdate, "onMozMagnifyGestureUpdate")
 GK_ATOM(onMozMagnifyGesture, "onMozMagnifyGesture")
 GK_ATOM(onMozRotateGestureStart, "onMozRotateGestureStart")
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -3056,44 +3056,42 @@ nsresult
 nsGlobalWindow::PreHandleEvent(EventChainPreVisitor& aVisitor)
 {
   NS_PRECONDITION(IsInnerWindow(), "PreHandleEvent is used on outer window!?");
   static uint32_t count = 0;
   EventMessage msg = aVisitor.mEvent->mMessage;
 
   aVisitor.mCanHandle = true;
   aVisitor.mForceContentDispatch = true; //FIXME! Bug 329119
-  if ((msg == NS_MOUSE_MOVE) && gEntropyCollector) {
+  if (msg == eMouseMove && gEntropyCollector) {
     //Chances are this counter will overflow during the life of the
     //process, but that's OK for our case. Means we get a little
     //more entropy.
     if (count++ % 100 == 0) {
       //Since the high bits seem to be zero's most of the time,
       //let's only take the lowest half of the point structure.
       int16_t myCoord[2];
 
       myCoord[0] = aVisitor.mEvent->refPoint.x;
       myCoord[1] = aVisitor.mEvent->refPoint.y;
       gEntropyCollector->RandomUpdate((void*)myCoord, sizeof(myCoord));
       gEntropyCollector->RandomUpdate((void*)&(aVisitor.mEvent->time),
                                       sizeof(uint32_t));
     }
-  } else if (msg == NS_RESIZE_EVENT && aVisitor.mEvent->mFlags.mIsTrusted) {
+  } else if (msg == eResize && aVisitor.mEvent->mFlags.mIsTrusted) {
     // QIing to window so that we can keep the old behavior also in case
     // a child window is handling resize.
     nsCOMPtr<nsPIDOMWindow> window =
       do_QueryInterface(aVisitor.mEvent->originalTarget);
     if (window) {
       mIsHandlingResizeEvent = true;
     }
-  } else if (msg == NS_MOUSE_BUTTON_DOWN &&
-             aVisitor.mEvent->mFlags.mIsTrusted) {
+  } else if (msg == eMouseDown && aVisitor.mEvent->mFlags.mIsTrusted) {
     gMouseDown = true;
-  } else if ((msg == NS_MOUSE_BUTTON_UP ||
-              msg == NS_DRAGDROP_END) &&
+  } else if ((msg == eMouseUp || msg == NS_DRAGDROP_END) &&
              aVisitor.mEvent->mFlags.mIsTrusted) {
     gMouseDown = false;
     if (gDragServiceDisabled) {
       nsCOMPtr<nsIDragService> ds =
         do_GetService("@mozilla.org/widget/dragservice;1");
       if (ds) {
         gDragServiceDisabled = false;
         ds->Unsuppress();
@@ -3261,31 +3259,31 @@ nsGlobalWindow::EnableDialogs()
 
 nsresult
 nsGlobalWindow::PostHandleEvent(EventChainPostVisitor& aVisitor)
 {
   NS_PRECONDITION(IsInnerWindow(), "PostHandleEvent is used on outer window!?");
 
   // Return early if there is nothing to do.
   switch (aVisitor.mEvent->mMessage) {
-    case NS_RESIZE_EVENT:
+    case eResize:
     case NS_PAGE_UNLOAD:
     case NS_LOAD:
       break;
     default:
       return NS_OK;
   }
 
   /* mChromeEventHandler and mContext go dangling in the middle of this
    function under some circumstances (events that destroy the window)
    without this addref. */
   nsCOMPtr<nsIDOMEventTarget> kungFuDeathGrip1(mChromeEventHandler);
   nsCOMPtr<nsIScriptContext> kungFuDeathGrip2(GetContextInternal());
 
-  if (aVisitor.mEvent->mMessage == NS_RESIZE_EVENT) {
+  if (aVisitor.mEvent->mMessage == eResize) {
     mIsHandlingResizeEvent = false;
   } else if (aVisitor.mEvent->mMessage == NS_PAGE_UNLOAD &&
              aVisitor.mEvent->mFlags.mIsTrusted) {
     // Execute bindingdetached handlers before we tear ourselves
     // down.
     if (mDoc) {
       mDoc->BindingManager()->ExecuteDetachedHandlers();
     }
@@ -6222,17 +6220,17 @@ nsGlobalWindow::GetMainWidget()
   if (treeOwnerAsWin) {
     treeOwnerAsWin->GetMainWidget(getter_AddRefs(widget));
   }
 
   return widget.forget();
 }
 
 nsIWidget*
-nsGlobalWindow::GetNearestWidget()
+nsGlobalWindow::GetNearestWidget() const
 {
   nsIDocShell* docShell = GetDocShell();
   NS_ENSURE_TRUE(docShell, nullptr);
   nsCOMPtr<nsIPresShell> presShell = docShell->GetPresShell();
   NS_ENSURE_TRUE(presShell, nullptr);
   nsIFrame* rootFrame = presShell->GetRootFrame();
   NS_ENSURE_TRUE(rootFrame, nullptr);
   return rootFrame->GetView()->GetNearestWidget(nullptr);
@@ -6663,18 +6661,26 @@ nsGlobalWindow::FullScreen() const
 
   NS_ENSURE_TRUE(mDocShell, mFullScreen);
 
   // Get the fullscreen value of the root window, to always have the value
   // accurate, even when called from content.
   nsCOMPtr<nsIDocShellTreeItem> rootItem;
   mDocShell->GetRootTreeItem(getter_AddRefs(rootItem));
   if (rootItem == mDocShell) {
-    // We are the root window. Return our internal value.
-    return mFullScreen;
+    if (!XRE_IsContentProcess()) {
+      // We are the root window. Return our internal value.
+      return mFullScreen;
+    }
+    if (nsCOMPtr<nsIWidget> widget = GetNearestWidget()) {
+      // We are in content process, figure out the value from
+      // the sizemode of the puppet widget.
+      return widget->SizeMode() == nsSizeMode_Fullscreen;
+    }
+    return false;
   }
 
   nsCOMPtr<nsIDOMWindow> window = rootItem->GetWindow();
   NS_ENSURE_TRUE(window, mFullScreen);
 
   return static_cast<nsGlobalWindow*>(window.get())->FullScreen();
 }
 
--- a/dom/base/nsGlobalWindow.h
+++ b/dom/base/nsGlobalWindow.h
@@ -1504,17 +1504,17 @@ public:
 
   // Outer windows only.
   // If aLookForCallerOnJSStack is true, this method will look at the JS stack
   // to determine who the caller is.  If it's false, it'll use |this| as the
   // caller.
   bool WindowExists(const nsAString& aName, bool aLookForCallerOnJSStack);
 
   already_AddRefed<nsIWidget> GetMainWidget();
-  nsIWidget* GetNearestWidget();
+  nsIWidget* GetNearestWidget() const;
 
   void Freeze()
   {
     NS_ASSERTION(!IsFrozen(), "Double-freezing?");
     mIsFrozen = true;
     NotifyDOMWindowFrozen(this);
   }
 
--- a/dom/base/nsPIDOMWindow.h
+++ b/dom/base/nsPIDOMWindow.h
@@ -363,17 +363,17 @@ public:
   }
 
   // Outer windows only.
   virtual bool WouldReuseInnerWindow(nsIDocument* aNewDocument) = 0;
 
   /**
    * Get the docshell in this window.
    */
-  nsIDocShell *GetDocShell()
+  nsIDocShell *GetDocShell() const
   {
     if (mOuterWindow) {
       return mOuterWindow->mDocShell;
     }
 
     return mDocShell;
   }
 
--- a/dom/broadcastchannel/BroadcastChannelParent.cpp
+++ b/dom/broadcastchannel/BroadcastChannelParent.cpp
@@ -83,24 +83,16 @@ BroadcastChannelParent::CheckAndDeliver(
                                         const nsString& aChannel,
                                         bool aPrivateBrowsing)
 {
   AssertIsOnBackgroundThread();
 
   if (aOrigin == mOrigin &&
       aChannel == mChannel &&
       aPrivateBrowsing == mPrivateBrowsing) {
-    // We need to duplicate data only if we have blobs or if the manager of
-    // them is different than the manager of this parent actor.
-    if (aData.blobsParent().IsEmpty() ||
-        static_cast<BlobParent*>(aData.blobsParent()[0])->GetBackgroundManager() == Manager()) {
-      unused << SendNotify(aData);
-      return;
-    }
-
     // Duplicate the data for this parent.
     ClonedMessageData newData(aData);
 
     // Ricreate the BlobParent for this new message.
     for (uint32_t i = 0, len = newData.blobsParent().Length(); i < len; ++i) {
       nsRefPtr<BlobImpl> impl =
         static_cast<BlobParent*>(newData.blobsParent()[i])->GetBlobImpl();
 
--- a/dom/events/AnimationEvent.cpp
+++ b/dom/events/AnimationEvent.cpp
@@ -10,17 +10,17 @@
 
 namespace mozilla {
 namespace dom {
 
 AnimationEvent::AnimationEvent(EventTarget* aOwner,
                                nsPresContext* aPresContext,
                                InternalAnimationEvent* aEvent)
   : Event(aOwner, aPresContext,
-          aEvent ? aEvent : new InternalAnimationEvent(false, NS_EVENT_NULL))
+          aEvent ? aEvent : new InternalAnimationEvent(false, eVoidEvent))
 {
   if (aEvent) {
     mEventIsInternal = false;
   }
   else {
     mEventIsInternal = true;
     mEvent->time = PR_Now();
   }
--- a/dom/events/BeforeAfterKeyboardEvent.cpp
+++ b/dom/events/BeforeAfterKeyboardEvent.cpp
@@ -13,17 +13,17 @@ namespace dom {
 
 BeforeAfterKeyboardEvent::BeforeAfterKeyboardEvent(
                                        EventTarget* aOwner,
                                        nsPresContext* aPresContext,
                                        InternalBeforeAfterKeyboardEvent* aEvent)
   : KeyboardEvent(aOwner, aPresContext,
                   aEvent ? aEvent :
                            new InternalBeforeAfterKeyboardEvent(false,
-                                                                NS_EVENT_NULL,
+                                                                eVoidEvent,
                                                                 nullptr))
 {
   MOZ_ASSERT(mEvent->mClass == eBeforeAfterKeyboardEventClass,
              "event type mismatch eBeforeAfterKeyboardEventClass");
 
   if (!aEvent) {
     mEventIsInternal = true;
     mEvent->time = PR_Now();
--- a/dom/events/ClipboardEvent.cpp
+++ b/dom/events/ClipboardEvent.cpp
@@ -11,17 +11,17 @@
 
 namespace mozilla {
 namespace dom {
 
 ClipboardEvent::ClipboardEvent(EventTarget* aOwner,
                                nsPresContext* aPresContext,
                                InternalClipboardEvent* aEvent)
   : Event(aOwner, aPresContext,
-          aEvent ? aEvent : new InternalClipboardEvent(false, NS_EVENT_NULL))
+          aEvent ? aEvent : new InternalClipboardEvent(false, eVoidEvent))
 {
   if (aEvent) {
     mEventIsInternal = false;
   } else {
     mEventIsInternal = true;
     mEvent->time = PR_Now();
   }
 }
--- a/dom/events/CompositionEvent.cpp
+++ b/dom/events/CompositionEvent.cpp
@@ -11,17 +11,17 @@
 namespace mozilla {
 namespace dom {
 
 CompositionEvent::CompositionEvent(EventTarget* aOwner,
                                    nsPresContext* aPresContext,
                                    WidgetCompositionEvent* aEvent)
   : UIEvent(aOwner, aPresContext,
             aEvent ? aEvent :
-                     new WidgetCompositionEvent(false, NS_EVENT_NULL, nullptr))
+                     new WidgetCompositionEvent(false, eVoidEvent, nullptr))
 {
   NS_ASSERTION(mEvent->mClass == eCompositionEventClass,
                "event type mismatch");
 
   if (aEvent) {
     mEventIsInternal = false;
   } else {
     mEventIsInternal = true;
--- a/dom/events/DragEvent.cpp
+++ b/dom/events/DragEvent.cpp
@@ -12,17 +12,17 @@
 namespace mozilla {
 namespace dom {
 
 DragEvent::DragEvent(EventTarget* aOwner,
                      nsPresContext* aPresContext,
                      WidgetDragEvent* aEvent)
   : MouseEvent(aOwner, aPresContext,
                aEvent ? aEvent :
-                        new WidgetDragEvent(false, NS_EVENT_NULL, nullptr))
+                        new WidgetDragEvent(false, eVoidEvent, nullptr))
 {
   if (aEvent) {
     mEventIsInternal = false;
   }
   else {
     mEventIsInternal = true;
     mEvent->time = PR_Now();
     mEvent->refPoint.x = mEvent->refPoint.y = 0;
--- a/dom/events/Event.cpp
+++ b/dom/events/Event.cpp
@@ -101,17 +101,17 @@ Event::ConstructorInit(EventTarget* aOwn
             mEventIsInternal = false;
           }
           else {
             mEventIsInternal = true;
           }
           ...
         }
      */
-    mEvent = new WidgetEvent(false, NS_EVENT_NULL);
+    mEvent = new WidgetEvent(false, eVoidEvent);
     mEvent->time = PR_Now();
   }
 
   InitPresContextData(aPresContext);
 }
 
 void
 Event::InitPresContextData(nsPresContext* aPresContext)
@@ -765,33 +765,33 @@ Event::GetEventPopupControlState(WidgetE
         break;
       }
     }
     break;
   case eKeyboardEventClass:
     if (aEvent->mFlags.mIsTrusted) {
       uint32_t key = aEvent->AsKeyboardEvent()->keyCode;
       switch(aEvent->mMessage) {
-      case NS_KEY_PRESS :
-        // return key on focused button. see note at NS_MOUSE_CLICK.
+      case eKeyPress:
+        // return key on focused button. see note at eMouseClick.
         if (key == nsIDOMKeyEvent::DOM_VK_RETURN) {
           abuse = openAllowed;
         } else if (PopupAllowedForEvent("keypress")) {
           abuse = openControlled;
         }
         break;
-      case NS_KEY_UP :
-        // space key on focused button. see note at NS_MOUSE_CLICK.
+      case eKeyUp:
+        // space key on focused button. see note at eMouseClick.
         if (key == nsIDOMKeyEvent::DOM_VK_SPACE) {
           abuse = openAllowed;
         } else if (PopupAllowedForEvent("keyup")) {
           abuse = openControlled;
         }
         break;
-      case NS_KEY_DOWN :
+      case eKeyDown:
         if (PopupAllowedForEvent("keydown")) {
           abuse = openControlled;
         }
         break;
       default:
         break;
       }
     }
@@ -813,36 +813,36 @@ Event::GetEventPopupControlState(WidgetE
         break;
       }
     }
     break;
   case eMouseEventClass:
     if (aEvent->mFlags.mIsTrusted &&
         aEvent->AsMouseEvent()->button == WidgetMouseEvent::eLeftButton) {
       switch(aEvent->mMessage) {
-      case NS_MOUSE_BUTTON_UP :
+      case eMouseUp:
         if (PopupAllowedForEvent("mouseup")) {
           abuse = openControlled;
         }
         break;
-      case NS_MOUSE_BUTTON_DOWN :
+      case eMouseDown:
         if (PopupAllowedForEvent("mousedown")) {
           abuse = openControlled;
         }
         break;
-      case NS_MOUSE_CLICK :
+      case eMouseClick:
         /* Click events get special treatment because of their
            historical status as a more legitimate event handler. If
            click popups are enabled in the prefs, clear the popup
            status completely. */
         if (PopupAllowedForEvent("click")) {
           abuse = openAllowed;
         }
         break;
-      case NS_MOUSE_DOUBLECLICK :
+      case eMouseDoubleClick:
         if (PopupAllowedForEvent("dblclick")) {
           abuse = openControlled;
         }
         break;
       default:
         break;
       }
     }
--- a/dom/events/EventDispatcher.cpp
+++ b/dom/events/EventDispatcher.cpp
@@ -488,17 +488,17 @@ EventDispatcher::Dispatch(nsISupports* a
       // Set the target to be the original dispatch target,
       aEvent->target = target;
       // but use chrome event handler or TabChildGlobal for event target chain.
       target = piTarget;
     }
   }
 
 #ifdef DEBUG
-  if (aEvent->mMessage != NS_EVENT_NULL &&
+  if (aEvent->mMessage != eVoidEvent &&
       !nsContentUtils::IsSafeToRunScript()) {
     nsresult rv = NS_ERROR_FAILURE;
     if (target->GetContextForEventHandlers(&rv) ||
         NS_FAILED(rv)) {
       nsCOMPtr<nsINode> node = do_QueryInterface(target);
       if (node && nsContentUtils::IsChromeDoc(node->OwnerDoc())) {
         NS_WARNING("Fix the caller!");
       } else {
--- a/dom/events/EventDispatcher.h
+++ b/dom/events/EventDispatcher.h
@@ -242,17 +242,17 @@ public:
    * aTarget is always used as the starting point for constructing the event
    * target chain, no matter what the value of aEvent->target is.
    * In other words, aEvent->target is only a property of the event and it has
    * nothing to do with the construction of the event target chain.
    * Neither aTarget nor aEvent is allowed to be nullptr.
    *
    * If aTargets is non-null, event target chain will be created, but
    * event won't be handled. In this case aEvent->mMessage should be
-   * NS_EVENT_NULL.
+   * eVoidEvent.
    * @note Use this method when dispatching a WidgetEvent.
    */
   static nsresult Dispatch(nsISupports* aTarget,
                            nsPresContext* aPresContext,
                            WidgetEvent* aEvent,
                            nsIDOMEvent* aDOMEvent = nullptr,
                            nsEventStatus* aEventStatus = nullptr,
                            EventDispatchingCallback* aCallback = nullptr,
--- a/dom/events/EventListenerManager.cpp
+++ b/dom/events/EventListenerManager.cpp
@@ -90,17 +90,17 @@ MutationBitForEventType(EventMessage aEv
       break;
   }
   return 0;
 }
 
 uint32_t EventListenerManager::sMainThreadCreatedCount = 0;
 
 EventListenerManagerBase::EventListenerManagerBase()
-  : mNoListenerForEvent(NS_EVENT_NULL)
+  : mNoListenerForEvent(eVoidEvent)
   , mMayHavePaintEventListener(false)
   , mMayHaveMutationListeners(false)
   , mMayHaveCapturingListeners(false)
   , mMayHaveSystemGroupListeners(false)
   , mMayHaveTouchEventListener(false)
   , mMayHaveMouseEnterLeaveEventListener(false)
   , mMayHavePointerEnterLeaveEventListener(false)
   , mMayHaveKeyEventListener(false)
@@ -252,17 +252,17 @@ EventListenerManager::AddEventListenerIn
         listener->mFlags == aFlags &&
         EVENT_TYPE_EQUALS(listener, aEventMessage, aTypeAtom, aTypeString,
                           aAllEvents) &&
         listener->mListener == aListenerHolder) {
       return;
     }
   }
 
-  mNoListenerForEvent = NS_EVENT_NULL;
+  mNoListenerForEvent = eVoidEvent;
   mNoListenerForEventAtom = nullptr;
 
   listener = aAllEvents ? mListeners.InsertElementAt(0) :
                           mListeners.AppendElement();
   listener->mListener = aListenerHolder;
   listener->mEventMessage = aEventMessage;
   listener->mTypeString = aTypeString;
   listener->mTypeAtom = aTypeAtom;
@@ -519,17 +519,17 @@ EventListenerManager::RemoveEventListene
     if (EVENT_TYPE_EQUALS(listener, aEventMessage, aUserType, aTypeString,
                           aAllEvents)) {
       ++typeCount;
       if (listener->mListener == aListenerHolder &&
           listener->mFlags.EqualsIgnoringTrustness(aFlags)) {
         nsRefPtr<EventListenerManager> kungFuDeathGrip(this);
         mListeners.RemoveElementAt(i);
         --count;
-        mNoListenerForEvent = NS_EVENT_NULL;
+        mNoListenerForEvent = eVoidEvent;
         mNoListenerForEventAtom = nullptr;
         if (mTarget && aUserType) {
           mTarget->EventListenerRemoved(aUserType);
         }
         if (mIsMainThreadELM && mTarget) {
           EventListenerService::NotifyAboutMainThreadListenerChange(mTarget,
                                                                     aUserType);
         }
@@ -786,17 +786,17 @@ EventListenerManager::RemoveEventHandler
     return;
   }
 
   EventMessage eventMessage = nsContentUtils::GetEventMessage(aName);
   Listener* listener = FindEventHandler(eventMessage, aName, aTypeString);
 
   if (listener) {
     mListeners.RemoveElementAt(uint32_t(listener - &mListeners.ElementAt(0)));
-    mNoListenerForEvent = NS_EVENT_NULL;
+    mNoListenerForEvent = eVoidEvent;
     mNoListenerForEventAtom = nullptr;
     if (mTarget && aName) {
       mTarget->EventListenerRemoved(aName);
     }
     if (mIsMainThreadELM && mTarget) {
       EventListenerService::NotifyAboutMainThreadListenerChange(mTarget, aName);
     }
   }
@@ -1219,31 +1219,31 @@ EventListenerManager::AddListenerForAllE
                                               bool aWantsUntrusted,
                                               bool aSystemEventGroup)
 {
   EventListenerFlags flags;
   flags.mCapture = aUseCapture;
   flags.mAllowUntrustedEvents = aWantsUntrusted;
   flags.mInSystemGroup = aSystemEventGroup;
   EventListenerHolder listenerHolder(aDOMListener);
-  AddEventListenerInternal(listenerHolder, NS_EVENT_ALL, nullptr, EmptyString(),
+  AddEventListenerInternal(listenerHolder, eAllEvents, nullptr, EmptyString(),
                            flags, false, true);
 }
 
 void
 EventListenerManager::RemoveListenerForAllEvents(
                         nsIDOMEventListener* aDOMListener,
                         bool aUseCapture,
                         bool aSystemEventGroup)
 {
   EventListenerFlags flags;
   flags.mCapture = aUseCapture;
   flags.mInSystemGroup = aSystemEventGroup;
   EventListenerHolder listenerHolder(aDOMListener);
-  RemoveEventListenerInternal(listenerHolder, NS_EVENT_ALL, nullptr,
+  RemoveEventListenerInternal(listenerHolder, eAllEvents, nullptr,
                               EmptyString(), flags, true);
 }
 
 bool
 EventListenerManager::HasMutationListeners()
 {
   if (mMayHaveMutationListeners) {
     uint32_t count = mListeners.Length();
--- a/dom/events/EventListenerService.cpp
+++ b/dom/events/EventListenerService.cpp
@@ -221,17 +221,17 @@ EventListenerService::GetListenerInfoFor
 NS_IMETHODIMP
 EventListenerService::GetEventTargetChainFor(nsIDOMEventTarget* aEventTarget,
                                              uint32_t* aCount,
                                              nsIDOMEventTarget*** aOutArray)
 {
   *aCount = 0;
   *aOutArray = nullptr;
   NS_ENSURE_ARG(aEventTarget);
-  WidgetEvent event(true, NS_EVENT_NULL);
+  WidgetEvent event(true, eVoidEvent);
   nsTArray<EventTarget*> targets;
   nsresult rv = EventDispatcher::Dispatch(aEventTarget, nullptr, &event,
                                           nullptr, nullptr, nullptr, &targets);
   NS_ENSURE_SUCCESS(rv, rv);
   int32_t count = targets.Length();
   if (count == 0) {
     return NS_OK;
   }
--- a/dom/events/EventNameList.h
+++ b/dom/events/EventNameList.h
@@ -160,27 +160,27 @@ EVENT(canplaythrough,
       NS_CANPLAYTHROUGH,
       EventNameType_HTML,
       eBasicEventClass)
 EVENT(change,
       NS_FORM_CHANGE,
       EventNameType_HTMLXUL,
       eBasicEventClass)
 EVENT(click,
-      NS_MOUSE_CLICK,
+      eMouseClick,
       EventNameType_All,
       eMouseEventClass)
 EVENT(contextmenu,
       NS_CONTEXTMENU,
       EventNameType_HTMLXUL,
       eMouseEventClass)
 // Not supported yet
 // EVENT(cuechange)
 EVENT(dblclick,
-      NS_MOUSE_DOUBLECLICK,
+      eMouseDoubleClick,
       EventNameType_HTMLXUL,
       eMouseEventClass)
 EVENT(drag,
       NS_DRAGDROP_DRAG,
       EventNameType_HTMLXUL,
       eDragEventClass)
 EVENT(dragend,
       NS_DRAGDROP_END,
@@ -222,81 +222,81 @@ EVENT(input,
       NS_EDITOR_INPUT,
       EventNameType_HTMLXUL,
       eEditorInputEventClass)
 EVENT(invalid,
       NS_FORM_INVALID,
       EventNameType_HTMLXUL,
       eBasicEventClass)
 EVENT(keydown,
-      NS_KEY_DOWN,
+      eKeyDown,
       EventNameType_HTMLXUL,
       eKeyboardEventClass)
 EVENT(keypress,
-      NS_KEY_PRESS,
+      eKeyPress,
       EventNameType_HTMLXUL,
       eKeyboardEventClass)
 EVENT(keyup,
-      NS_KEY_UP,
+      eKeyUp,
       EventNameType_HTMLXUL,
       eKeyboardEventClass)
 NON_IDL_EVENT(mozbrowserbeforekeydown,
-              NS_KEY_BEFORE_DOWN,
+              eBeforeKeyDown,
               EventNameType_None,
               eBeforeAfterKeyboardEventClass)
 NON_IDL_EVENT(mozbrowserafterkeydown,
-              NS_KEY_AFTER_DOWN,
+              eAfterKeyDown,
               EventNameType_None,
               eBeforeAfterKeyboardEventClass)
 NON_IDL_EVENT(mozbrowserbeforekeyup,
-              NS_KEY_BEFORE_UP,
+              eBeforeKeyUp,
               EventNameType_None,
               eBeforeAfterKeyboardEventClass)
 NON_IDL_EVENT(mozbrowserafterkeyup,
-              NS_KEY_AFTER_UP,
+              eAfterKeyUp,
               EventNameType_None,
               eBeforeAfterKeyboardEventClass)
 EVENT(loadeddata,
       NS_LOADEDDATA,
       EventNameType_HTML,
       eBasicEventClass)
 EVENT(loadedmetadata,
       NS_LOADEDMETADATA,
       EventNameType_HTML,
       eBasicEventClass)
 EVENT(loadstart,
       NS_LOADSTART,
       EventNameType_HTML,
       eBasicEventClass)
 EVENT(mousedown,
-      NS_MOUSE_BUTTON_DOWN,
+      eMouseDown,
       EventNameType_All,
       eMouseEventClass)
 EVENT(mouseenter,
-      NS_MOUSEENTER,
+      eMouseEnter,
       EventNameType_All,
       eMouseEventClass)
 EVENT(mouseleave,
-      NS_MOUSELEAVE,
+      eMouseLeave,
       EventNameType_All,
       eMouseEventClass)
 EVENT(mousemove,
-      NS_MOUSE_MOVE,
+      eMouseMove,
       EventNameType_All,
       eMouseEventClass)
 EVENT(mouseout,
-      NS_MOUSE_OUT,
+      eMouseOut,
       EventNameType_All,
       eMouseEventClass)
 EVENT(mouseover,
-      NS_MOUSE_OVER,
+      eMouseOver,
       EventNameType_All,
       eMouseEventClass)
 EVENT(mouseup,
-      NS_MOUSE_BUTTON_UP,
+      eMouseUp,
       EventNameType_All,
       eMouseEventClass)
 EVENT(mozfullscreenchange,
       NS_FULLSCREENCHANGE,
       EventNameType_HTML,
       eBasicEventClass)
 EVENT(mozfullscreenerror,
       NS_FULLSCREENERROR,
@@ -455,21 +455,21 @@ FORWARDED_EVENT(focus,
                 NS_FOCUS_CONTENT,
                 EventNameType_HTMLXUL,
                 eFocusEventClass)
 FORWARDED_EVENT(load,
                 NS_LOAD,
                 EventNameType_All,
                 eBasicEventClass)
 FORWARDED_EVENT(resize,
-                NS_RESIZE_EVENT,
+                eResize,
                 EventNameType_All,
                 eBasicEventClass)
 FORWARDED_EVENT(scroll,
-                NS_SCROLL_EVENT,
+                eScroll,
                 (EventNameType_HTMLXUL | EventNameType_SVGSVG),
                 eBasicEventClass)
 
 WINDOW_EVENT(afterprint,
              NS_AFTERPRINT,
              EventNameType_XUL | EventNameType_HTMLBodyOrFramesetOnly,
              eBasicEventClass)
 WINDOW_EVENT(beforeprint,
@@ -480,32 +480,32 @@ BEFOREUNLOAD_EVENT(beforeunload,
                    NS_BEFORE_PAGE_UNLOAD,
                    EventNameType_XUL | EventNameType_HTMLBodyOrFramesetOnly,
                    eBasicEventClass)
 WINDOW_EVENT(hashchange,
              NS_HASHCHANGE,
              EventNameType_XUL | EventNameType_HTMLBodyOrFramesetOnly,
              eBasicEventClass)
 WINDOW_EVENT(languagechange,
-             NS_LANGUAGECHANGE,
+             eLanguageChange,
              EventNameType_HTMLBodyOrFramesetOnly,
              eBasicEventClass)
 // XXXbz Should the onmessage attribute on <body> really not work?  If so, do we
 // need a different macro to flag things like that (IDL, but not content
 // attributes on body/frameset), or is just using EventNameType_None enough?
 WINDOW_EVENT(message,
              NS_MESSAGE,
              EventNameType_None,
              eBasicEventClass)
 WINDOW_EVENT(offline,
-             NS_OFFLINE,
+             eOffline,
              EventNameType_XUL | EventNameType_HTMLBodyOrFramesetOnly,
              eBasicEventClass)
 WINDOW_EVENT(online,
-             NS_ONLINE,
+             eOnline,
              EventNameType_XUL | EventNameType_HTMLBodyOrFramesetOnly,
              eBasicEventClass)
 WINDOW_EVENT(pagehide,
              NS_PAGE_HIDE,
              EventNameType_HTMLBodyOrFramesetOnly,
              eBasicEventClass)
 WINDOW_EVENT(pageshow,
              NS_PAGE_SHOW,
@@ -581,17 +581,17 @@ TOUCH_EVENT(touchcancel,
             eTouchEventClass)
 
 DOCUMENT_ONLY_EVENT(readystatechange,
                     NS_READYSTATECHANGE,
                     EventNameType_HTMLXUL,
                     eBasicEventClass)
 
 NON_IDL_EVENT(MozMouseHittest,
-              NS_MOUSE_MOZHITTEST,
+              eMouseHitTest,
               EventNameType_None,
               eMouseEventClass)
 
 NON_IDL_EVENT(DOMAttrModified,
               NS_MUTATION_ATTRMODIFIED,
               EventNameType_HTMLXUL,
               eMutationEventClass)
 NON_IDL_EVENT(DOMCharacterDataModified,
@@ -687,17 +687,17 @@ NON_IDL_EVENT(compositionend,
               NS_COMPOSITION_END,
               EventNameType_XUL,
               eCompositionEventClass)
 NON_IDL_EVENT(command,
               NS_XUL_COMMAND,
               EventNameType_XUL,
               eInputEventClass)
 NON_IDL_EVENT(close,
-              NS_XUL_CLOSE,
+              eWindowClose,
               EventNameType_XUL,
               eBasicEventClass)
 NON_IDL_EVENT(popupshowing,
               NS_XUL_POPUP_SHOWING,
               EventNameType_XUL,
               eBasicEventClass)
 NON_IDL_EVENT(popupshown,
               NS_XUL_POPUP_SHOWN,
@@ -834,16 +834,20 @@ NON_IDL_EVENT(gamepadconnected,
               eBasicEventClass)
 NON_IDL_EVENT(gamepaddisconnected,
               NS_GAMEPAD_DISCONNECTED,
               EventNameType_None,
               eBasicEventClass)
 #endif
 
 // Simple gesture events
+NON_IDL_EVENT(MozSwipeGestureMayStart,
+              NS_SIMPLE_GESTURE_SWIPE_MAY_START,
+              EventNameType_None,
+              eSimpleGestureEventClass)
 NON_IDL_EVENT(MozSwipeGestureStart,
               NS_SIMPLE_GESTURE_SWIPE_START,
               EventNameType_None,
               eSimpleGestureEventClass)
 NON_IDL_EVENT(MozSwipeGestureUpdate,
               NS_SIMPLE_GESTURE_SWIPE_UPDATE,
               EventNameType_None,
               eSimpleGestureEventClass)
--- a/dom/events/EventStateManager.cpp
+++ b/dom/events/EventStateManager.cpp
@@ -489,23 +489,23 @@ EventStateManager::PreHandleEvent(nsPres
                    !aTargetFrame->GetContent() ||
                    aTargetFrame->GetContent() == aTargetContent ||
                    aTargetFrame->GetContent()->GetFlattenedTreeParent() == aTargetContent,
                    "aTargetFrame should be related with aTargetContent");
 
   mCurrentTarget = aTargetFrame;
   mCurrentTargetContent = nullptr;
 
-  // Do not take account NS_MOUSE_ENTER_WIDGET/EXIT_WIDGET so that loading a page
-  // when user is not active doesn't change the state to active.
+  // Do not take account eMouseEnterIntoWidget/ExitFromWidget so that loading
+  // a page when user is not active doesn't change the state to active.
   WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
   if (aEvent->mFlags.mIsTrusted &&
       ((mouseEvent && mouseEvent->IsReal() &&
-        mouseEvent->mMessage != NS_MOUSE_ENTER_WIDGET &&
-        mouseEvent->mMessage != NS_MOUSE_EXIT_WIDGET) ||
+        mouseEvent->mMessage != eMouseEnterIntoWidget &&
+        mouseEvent->mMessage != eMouseExitFromWidget) ||
        aEvent->mClass == eWheelEventClass ||
        aEvent->mClass == eKeyboardEventClass)) {
     if (gMouseOrKeyboardEventCounter == 0) {
       nsCOMPtr<nsIObserverService> obs =
         mozilla::services::GetObserverService();
       if (obs) {
         obs->NotifyObservers(nullptr, "user-interaction-active", nullptr);
         UpdateUserActivityTimer();
@@ -543,17 +543,17 @@ EventStateManager::PreHandleEvent(nsPres
   *aStatus = nsEventStatus_eIgnore;
 
   switch (aEvent->mMessage) {
   case NS_CONTEXTMENU:
     if (sIsPointerLocked) {
       return NS_ERROR_DOM_INVALID_STATE_ERR;
     }
     break;
-  case NS_MOUSE_BUTTON_DOWN: {
+  case eMouseDown: {
     switch (mouseEvent->button) {
     case WidgetMouseEvent::eLeftButton:
       BeginTrackingDragGesture(aPresContext, mouseEvent, aTargetFrame);
       mLClickCount = mouseEvent->clickCount;
       SetClickCount(aPresContext, mouseEvent, aStatus);
       sNormalLMouseEventInProcess = true;
       break;
     case WidgetMouseEvent::eMiddleButton:
@@ -562,78 +562,79 @@ EventStateManager::PreHandleEvent(nsPres
       break;
     case WidgetMouseEvent::eRightButton:
       mRClickCount = mouseEvent->clickCount;
       SetClickCount(aPresContext, mouseEvent, aStatus);
       break;
     }
     break;
   }
-  case NS_MOUSE_BUTTON_UP: {
+  case eMouseUp: {
     switch (mouseEvent->button) {
       case WidgetMouseEvent::eLeftButton:
         if (Prefs::ClickHoldContextMenu()) {
           KillClickHoldTimer();
         }
         StopTrackingDragGesture();
         sNormalLMouseEventInProcess = false;
         // then fall through...
       case WidgetMouseEvent::eRightButton:
       case WidgetMouseEvent::eMiddleButton:
         SetClickCount(aPresContext, mouseEvent, aStatus);
         break;
     }
     break;
   }
-  case NS_MOUSE_ENTER_WIDGET:
-    // In some cases on e10s NS_MOUSE_ENTER_WIDGET
+  case eMouseEnterIntoWidget:
+    // In some cases on e10s eMouseEnterIntoWidget
     // event was sent twice into child process of content.
     // (From specific widget code (sending is not permanent) and
     // from ESM::DispatchMouseOrPointerEvent (sending is permanent)).
     // Flag mNoCrossProcessBoundaryForwarding helps to
     // suppress sending accidental event from widget code.
     aEvent->mFlags.mNoCrossProcessBoundaryForwarding = true;
     break;
-  case NS_MOUSE_EXIT_WIDGET:
-    // If this is a remote frame, we receive NS_MOUSE_EXIT_WIDGET from the parent
-    // the mouse exits our content. Since the parent may update the cursor
-    // while the mouse is outside our frame, and since PuppetWidget caches the
-    // current cursor internally, re-entering our content (say from over a
-    // window edge) wont update the cursor if the cached value and the current
-    // cursor match. So when the mouse exits a remote frame, clear the cached
-    // widget cursor so a proper update will occur when the mouse re-enters.
+  case eMouseExitFromWidget:
+    // If this is a remote frame, we receive eMouseExitFromWidget from the
+    // parent the mouse exits our content. Since the parent may update the
+    // cursor while the mouse is outside our frame, and since PuppetWidget
+    // caches the current cursor internally, re-entering our content (say from
+    // over a window edge) wont update the cursor if the cached value and the
+    // current cursor match. So when the mouse exits a remote frame, clear the
+    // cached widget cursor so a proper update will occur when the mouse
+    // re-enters.
     if (XRE_IsContentProcess()) {
       ClearCachedWidgetCursor(mCurrentTarget);
     }
 
     // Flag helps to suppress double event sending into process of content.
-    // For more information see comment above, at NS_MOUSE_ENTER_WIDGET case.
+    // For more information see comment above, at eMouseEnterIntoWidget case.
     aEvent->mFlags.mNoCrossProcessBoundaryForwarding = true;
 
     // If the event is not a top-level window exit, then it's not
     // really an exit --- we may have traversed widget boundaries but
     // we're still in our toplevel window.
     if (mouseEvent->exit != WidgetMouseEvent::eTopLevel) {
       // Treat it as a synthetic move so we don't generate spurious
       // "exit" or "move" events.  Any necessary "out" or "over" events
       // will be generated by GenerateMouseEnterExit
-      mouseEvent->mMessage = NS_MOUSE_MOVE;
+      mouseEvent->mMessage = eMouseMove;
       mouseEvent->reason = WidgetMouseEvent::eSynthesized;
       // then fall through...
     } else {
       if (sPointerEventEnabled) {
         // We should synthetize corresponding pointer events
         GeneratePointerEnterExit(NS_POINTER_LEAVE, mouseEvent);
       }
       GenerateMouseEnterExit(mouseEvent);
       //This is a window level mouse exit event and should stop here
-      aEvent->mMessage = NS_EVENT_NULL;
+      aEvent->mMessage = eVoidEvent;
       break;
     }
-  case NS_MOUSE_MOVE:
+  case eMouseMove:
   case NS_POINTER_DOWN:
   case NS_POINTER_MOVE: {
     // on the Mac, GenerateDragGesture() may not return until the drag
     // has completed and so |aTargetFrame| may have been deleted (moving
     // a bookmark, for example).  If this is the case, however, we know
     // that ClearFrameRefs() has been called and it cleared out
     // |mCurrentTarget|. As a result, we should pass |mCurrentTarget|
     // into UpdateCursor().
@@ -653,17 +654,17 @@ EventStateManager::PreHandleEvent(nsPres
     }
     break;
   case NS_DRAGDROP_OVER:
     // NS_DRAGDROP_DROP is fired before NS_DRAGDROP_DRAGDROP so send
     // the enter/exit events before NS_DRAGDROP_DROP.
     GenerateDragDropEnterExit(aPresContext, aEvent->AsDragEvent());
     break;
 
-  case NS_KEY_PRESS:
+  case eKeyPress:
     {
       WidgetKeyboardEvent* keyEvent = aEvent->AsKeyboardEvent();
 
       int32_t modifierMask = 0;
       if (keyEvent->IsShift())
         modifierMask |= NS_MODIFIER_SHIFT;
       if (keyEvent->IsControl())
         modifierMask |= NS_MODIFIER_CONTROL;
@@ -678,22 +679,22 @@ EventStateManager::PreHandleEvent(nsPres
       if (modifierMask &&
           (modifierMask == Prefs::ChromeAccessModifierMask() ||
            modifierMask == Prefs::ContentAccessModifierMask())) {
         HandleAccessKey(aPresContext, keyEvent, aStatus, nullptr,
                         eAccessKeyProcessingNormal, modifierMask);
       }
     }
     // then fall through...
-  case NS_KEY_BEFORE_DOWN:
-  case NS_KEY_DOWN:
-  case NS_KEY_AFTER_DOWN:
-  case NS_KEY_BEFORE_UP:
-  case NS_KEY_UP:
-  case NS_KEY_AFTER_UP:
+  case eBeforeKeyDown:
+  case eKeyDown:
+  case eAfterKeyDown:
+  case eBeforeKeyUp:
+  case eKeyUp:
+  case eAfterKeyUp:
     {
       nsIContent* content = GetFocusedContent();
       if (content)
         mCurrentTargetContent = content;
 
       // NOTE: Don't refer TextComposition::IsComposing() since DOM Level 3
       //       Events defines that KeyboardEvent.isComposing is true when it's
       //       dispatched after compositionstart and compositionend.
@@ -1165,22 +1166,22 @@ bool
 CrossProcessSafeEvent(const WidgetEvent& aEvent)
 {
   switch (aEvent.mClass) {
   case eKeyboardEventClass:
   case eWheelEventClass:
     return true;
   case eMouseEventClass:
     switch (aEvent.mMessage) {
-    case NS_MOUSE_BUTTON_DOWN:
-    case NS_MOUSE_BUTTON_UP:
-    case NS_MOUSE_MOVE:
+    case eMouseDown:
+    case eMouseUp:
+    case eMouseMove:
     case NS_CONTEXTMENU:
-    case NS_MOUSE_ENTER_WIDGET:
-    case NS_MOUSE_EXIT_WIDGET:
+    case eMouseEnterIntoWidget:
+    case eMouseExitFromWidget:
       return true;
     default:
       return false;
     }
   case eTouchEventClass:
     switch (aEvent.mMessage) {
     case NS_TOUCH_START:
     case NS_TOUCH_MOVE:
@@ -2790,27 +2791,27 @@ EventStateManager::PostHandleEvent(nsPre
   bool dispatchedToContentProcess = HandleCrossProcessEvent(aEvent,
                                                             aStatus);
 
   mCurrentTarget = aTargetFrame;
   mCurrentTargetContent = nullptr;
 
   // Most of the events we handle below require a frame.
   // Add special cases here.
-  if (!mCurrentTarget && aEvent->mMessage != NS_MOUSE_BUTTON_UP &&
-      aEvent->mMessage != NS_MOUSE_BUTTON_DOWN) {
+  if (!mCurrentTarget && aEvent->mMessage != eMouseUp &&
+      aEvent->mMessage != eMouseDown) {
     return NS_OK;
   }
 
   //Keep the prescontext alive, we might need it after event dispatch
   nsRefPtr<nsPresContext> presContext = aPresContext;
   nsresult ret = NS_OK;
 
   switch (aEvent->mMessage) {
-  case NS_MOUSE_BUTTON_DOWN:
+  case eMouseDown:
     {
       WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
       if (mouseEvent->button == WidgetMouseEvent::eLeftButton &&
           !sNormalLMouseEventInProcess) {
         // We got a mouseup event while a mousedown event was being processed.
         // Make sure that the capturing content is cleared.
         nsIPresShell::SetCapturingContent(nullptr, 0);
         break;
@@ -3012,17 +3013,17 @@ EventStateManager::PostHandleEvent(nsPre
     // After UP/Cancel Touch pointers become invalid so we can remove relevant helper from Table
     // Mouse/Pen pointers are valid all the time (not only between down/up)
     if (pointerEvent->inputSource == nsIDOMMouseEvent::MOZ_SOURCE_TOUCH) {
       mPointersEnterLeaveHelper.Remove(pointerEvent->pointerId);
       GenerateMouseEnterExit(pointerEvent);
     }
     break;
   }
-  case NS_MOUSE_BUTTON_UP:
+  case eMouseUp:
     {
       ClearGlobalActiveContent(this);
       WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
       if (mouseEvent && mouseEvent->IsReal()) {
         if (!mCurrentTarget) {
           GetEventTarget();
         }
         // Make sure to dispatch the click even if there is no frame for
@@ -3126,22 +3127,41 @@ EventStateManager::PostHandleEvent(nsPre
           if (!intDelta) {
             break;
           }
           DoScrollZoom(aTargetFrame, intDelta);
           break;
         }
         case WheelPrefs::ACTION_NONE:
         default:
-          // If we don't handle the wheel event, all of the delta values must
-          // be overflown delta values.
+          bool allDeltaOverflown = false;
+          if (wheelEvent->mFlags.mHandledByAPZ) {
+            if (wheelEvent->mCanTriggerSwipe) {
+              // For events that can trigger swipes, APZ needs to know whether
+              // scrolling is possible in the requested direction. It does this
+              // by looking at the scroll overflow values on mCanTriggerSwipe
+              // events after they have been processed.
+              allDeltaOverflown =
+                !ComputeScrollTarget(aTargetFrame, wheelEvent,
+                                     COMPUTE_DEFAULT_ACTION_TARGET);
+            }
+          } else {
+            // The event was processed neither by APZ nor by us, so all of the
+            // delta values must be overflown delta values.
+            allDeltaOverflown = true;
+          }
+
+          if (!allDeltaOverflown) {
+            break;
+          }
           wheelEvent->overflowDeltaX = wheelEvent->deltaX;
           wheelEvent->overflowDeltaY = wheelEvent->deltaY;
           WheelPrefs::GetInstance()->
             CancelApplyingUserPrefsFromOverflowDelta(wheelEvent);
+          wheelEvent->mViewPortIsOverscrolled = true;
           break;
       }
       *aStatus = nsEventStatus_eConsumeNoDefault;
     }
     break;
 
   case NS_GESTURENOTIFY_EVENT_START:
     {
@@ -3300,38 +3320,38 @@ EventStateManager::PostHandleEvent(nsPre
       break;
     }
   case NS_DRAGDROP_EXIT:
      // make sure to fire the enter and exit_synth events after the
      // NS_DRAGDROP_EXIT event, otherwise we'll clean up too early
     GenerateDragDropEnterExit(presContext, aEvent->AsDragEvent());
     break;
 
-  case NS_KEY_BEFORE_UP:
-  case NS_KEY_UP:
-  case NS_KEY_AFTER_UP:
+  case eBeforeKeyUp:
+  case eKeyUp:
+  case eAfterKeyUp:
     break;
 
-  case NS_KEY_PRESS:
+  case eKeyPress:
     {
       WidgetKeyboardEvent* keyEvent = aEvent->AsKeyboardEvent();
       PostHandleKeyboardEvent(keyEvent, *aStatus, dispatchedToContentProcess);
     }
     break;
 
-  case NS_MOUSE_ENTER_WIDGET:
+  case eMouseEnterIntoWidget:
     if (mCurrentTarget) {
       nsCOMPtr<nsIContent> targetContent;
       mCurrentTarget->GetContentForEvent(aEvent, getter_AddRefs(targetContent));
       SetContentState(targetContent, NS_EVENT_STATE_HOVER);
     }
     break;
 
 #ifdef XP_MACOSX
-  case NS_MOUSE_ACTIVATE:
+  case eMouseActivate:
     if (mCurrentTarget) {
       nsCOMPtr<nsIContent> targetContent;
       mCurrentTarget->GetContentForEvent(aEvent, getter_AddRefs(targetContent));
       if (!NodeAllowsClickThrough(targetContent)) {
         *aStatus = nsEventStatus_eConsumeNoDefault;
       }
     }
     break;
@@ -3735,20 +3755,20 @@ EventStateManager::DispatchMouseOrPointe
                                                EventMessage aMessage,
                                                nsIContent* aTargetContent,
                                                nsIContent* aRelatedContent)
 {
   // http://dvcs.w3.org/hg/webevents/raw-file/default/mouse-lock.html#methods
   // "[When the mouse is locked on an element...e]vents that require the concept
   // of a mouse cursor must not be dispatched (for example: mouseover, mouseout).
   if (sIsPointerLocked &&
-      (aMessage == NS_MOUSELEAVE ||
-       aMessage == NS_MOUSEENTER ||
-       aMessage == NS_MOUSE_OVER ||
-       aMessage == NS_MOUSE_OUT)) {
+      (aMessage == eMouseLeave ||
+       aMessage == eMouseEnter ||
+       aMessage == eMouseOver ||
+       aMessage == eMouseOut)) {
     mCurrentTargetContent = nullptr;
     nsCOMPtr<Element> pointerLockedElement =
       do_QueryReferent(EventStateManager::sPointerLockedElement);
     if (!pointerLockedElement) {
       NS_WARNING("Should have pointer locked element, but didn't.");
       return nullptr;
     }
     nsCOMPtr<nsIContent> content = do_QueryInterface(pointerLockedElement);
@@ -3783,32 +3803,32 @@ EventStateManager::DispatchMouseOrPointe
   if (mPresContext) {
     // Although the primary frame was checked in event callback, it may not be
     // the same object after event dispatch and handling, so refetch it.
     targetFrame = mPresContext->GetPrimaryFrameFor(aTargetContent);
 
     // If we are entering/leaving remote content, dispatch a mouse enter/exit
     // event to the remote frame.
     if (IsRemoteTarget(aTargetContent)) {
-      if (aMessage == NS_MOUSE_OUT) {
+      if (aMessage == eMouseOut) {
         // For remote content, send a "top-level" widget mouse exit event.
         nsAutoPtr<WidgetMouseEvent> remoteEvent;
-        CreateMouseOrPointerWidgetEvent(aMouseEvent, NS_MOUSE_EXIT_WIDGET,
+        CreateMouseOrPointerWidgetEvent(aMouseEvent, eMouseExitFromWidget,
                                         aRelatedContent, remoteEvent);
         remoteEvent->exit = WidgetMouseEvent::eTopLevel;
 
         // mCurrentTarget is set to the new target, so we must reset it to the
         // old target and then dispatch a cross-process event. (mCurrentTarget
         // will be set back below.) HandleCrossProcessEvent will query for the
         // proper target via GetEventTarget which will return mCurrentTarget.
         mCurrentTarget = targetFrame;
         HandleCrossProcessEvent(remoteEvent, &status);
-      } else if (aMessage == NS_MOUSE_OVER) {
+      } else if (aMessage == eMouseOver) {
         nsAutoPtr<WidgetMouseEvent> remoteEvent;
-        CreateMouseOrPointerWidgetEvent(aMouseEvent, NS_MOUSE_ENTER_WIDGET,
+        CreateMouseOrPointerWidgetEvent(aMouseEvent, eMouseEnterIntoWidget,
                                         aRelatedContent, remoteEvent);
         HandleCrossProcessEvent(remoteEvent, &status);
       }
     }
   }
 
   mCurrentTargetContent = nullptr;
   mCurrentTarget = previousTarget;
@@ -3847,17 +3867,17 @@ public:
         // mouseenter/leave is fired only on elements.
         current = current->GetParent();
       }
     }
   }
 
   ~EnterLeaveDispatcher()
   {
-    if (mEventMessage == NS_MOUSEENTER ||
+    if (mEventMessage == eMouseEnter ||
         mEventMessage == NS_POINTER_ENTER) {
       for (int32_t i = mTargets.Count() - 1; i >= 0; --i) {
         mESM->DispatchMouseOrPointerEvent(mMouseEvent, mEventMessage,
                                           mTargets[i], mRelatedTarget);
       }
     } else {
       for (int32_t i = 0; i < mTargets.Count(); ++i) {
         mESM->DispatchMouseOrPointerEvent(mMouseEvent, mEventMessage,
@@ -3926,20 +3946,20 @@ EventStateManager::NotifyMouseOut(Widget
   // In case we go out from capturing element (retargetedByPointerCapture is true)
   // we should dispatch NS_POINTER_LEAVE event and only for capturing element.
   nsRefPtr<nsIContent> movingInto = aMouseEvent->retargetedByPointerCapture
                                     ? wrapper->mLastOverElement->GetParent()
                                     : aMovingInto;
 
   EnterLeaveDispatcher leaveDispatcher(this, wrapper->mLastOverElement,
                                        movingInto, aMouseEvent,
-                                       isPointer ? NS_POINTER_LEAVE : NS_MOUSELEAVE);
+                                       isPointer ? NS_POINTER_LEAVE : eMouseLeave);
 
   // Fire mouseout
-  DispatchMouseOrPointerEvent(aMouseEvent, isPointer ? NS_POINTER_OUT : NS_MOUSE_OUT,
+  DispatchMouseOrPointerEvent(aMouseEvent, isPointer ? NS_POINTER_OUT : eMouseOut,
                               wrapper->mLastOverElement, aMovingInto);
 
   wrapper->mLastOverFrame = nullptr;
   wrapper->mLastOverElement = nullptr;
 
   // Turn recursion protection back off
   wrapper->mFirstOutEventElement = nullptr;
 }
@@ -3985,34 +4005,34 @@ EventStateManager::NotifyMouseOver(Widge
   // DispatchMouseOrPointerEvent() call below, since NotifyMouseOut() resets it, bug 298477.
   nsCOMPtr<nsIContent> lastOverElement = wrapper->mLastOverElement;
 
   bool isPointer = aMouseEvent->mClass == ePointerEventClass;
   
   Maybe<EnterLeaveDispatcher> enterDispatcher;
   if (dispatch) {
     enterDispatcher.emplace(this, aContent, lastOverElement, aMouseEvent,
-                            isPointer ? NS_POINTER_ENTER : NS_MOUSEENTER);
+                            isPointer ? NS_POINTER_ENTER : eMouseEnter);
   }
 
   NotifyMouseOut(aMouseEvent, aContent);
 
   // Store the first mouseOver event we fire and don't refire mouseOver
   // to that element while the first mouseOver is still ongoing.
   wrapper->mFirstOverEventElement = aContent;
 
   if (!isPointer) {
     SetContentState(aContent, NS_EVENT_STATE_HOVER);
   }
 
   if (dispatch) {
     // Fire mouseover
     wrapper->mLastOverFrame = 
       DispatchMouseOrPointerEvent(aMouseEvent,
-                                  isPointer ? NS_POINTER_OVER : NS_MOUSE_OVER,
+                                  isPointer ? NS_POINTER_OVER : eMouseOver,
                                   aContent, lastOverElement);
     wrapper->mLastOverElement = aContent;
   } else {
     wrapper->mLastOverFrame = nullptr;
     wrapper->mLastOverElement = nullptr;
   }
 
   // Turn recursion protection back off
@@ -4077,17 +4097,17 @@ EventStateManager::GenerateMouseEnterExi
   EnsureDocument(mPresContext);
   if (!mDocument)
     return;
 
   // Hold onto old target content through the event and reset after.
   nsCOMPtr<nsIContent> targetBeforeEvent = mCurrentTargetContent;
 
   switch(aMouseEvent->mMessage) {
-  case NS_MOUSE_MOVE:
+  case eMouseMove:
     {
       // Mouse movement is reported on the MouseEvent.movement{X,Y} fields.
       // Movement is calculated in UIEvent::GetMovementPoint() as:
       //   previous_mousemove_refPoint - current_mousemove_refPoint.
       if (sIsPointerLocked && aMouseEvent->widget) {
         // The pointer is locked. If the pointer is not located at the center of
         // the window, dispatch a synthetic mousemove to return the pointer there.
         // Doing this between "real" pointer moves gives the impression that the
@@ -4161,17 +4181,17 @@ EventStateManager::GenerateMouseEnterExi
           helper->mLastOverElement = targetElement;
         }
         NotifyMouseOut(aMouseEvent, nullptr);
       }
     }
     break;
   case NS_POINTER_LEAVE:
   case NS_POINTER_CANCEL:
-  case NS_MOUSE_EXIT_WIDGET:
+  case eMouseExitFromWidget:
     {
       // This is actually the window mouse exit or pointer leave event. We're not moving
       // into any new element.
 
       OverOutElementsWrapper* helper = GetWrapperByEventID(aMouseEvent);
       if (helper->mLastOverFrame &&
           nsContentUtils::GetTopLevelWidget(aMouseEvent->widget) !=
           nsContentUtils::GetTopLevelWidget(helper->mLastOverFrame->GetNearestWidget())) {
@@ -4433,56 +4453,56 @@ EventStateManager::SetClickCount(nsPresC
     }
     if (mouseContent && mouseContent->IsRootOfNativeAnonymousSubtree()) {
       mouseContentParent = mouseContent->GetParent();
     }
   }
 
   switch (aEvent->button) {
   case WidgetMouseEvent::eLeftButton:
-    if (aEvent->mMessage == NS_MOUSE_BUTTON_DOWN) {
+    if (aEvent->mMessage == eMouseDown) {
       mLastLeftMouseDownContent = mouseContent;
       mLastLeftMouseDownContentParent = mouseContentParent;
-    } else if (aEvent->mMessage == NS_MOUSE_BUTTON_UP) {
+    } else if (aEvent->mMessage == eMouseUp) {
       if (mLastLeftMouseDownContent == mouseContent ||
           mLastLeftMouseDownContentParent == mouseContent ||
           mLastLeftMouseDownContent == mouseContentParent) {
         aEvent->clickCount = mLClickCount;
         mLClickCount = 0;
       } else {
         aEvent->clickCount = 0;
       }
       mLastLeftMouseDownContent = nullptr;
       mLastLeftMouseDownContentParent = nullptr;
     }
     break;
 
   case WidgetMouseEvent::eMiddleButton:
-    if (aEvent->mMessage == NS_MOUSE_BUTTON_DOWN) {
+    if (aEvent->mMessage == eMouseDown) {
       mLastMiddleMouseDownContent = mouseContent;
       mLastMiddleMouseDownContentParent = mouseContentParent;
-    } else if (aEvent->mMessage == NS_MOUSE_BUTTON_UP) {
+    } else if (aEvent->mMessage == eMouseUp) {
       if (mLastMiddleMouseDownContent == mouseContent ||
           mLastMiddleMouseDownContentParent == mouseContent ||
           mLastMiddleMouseDownContent == mouseContentParent) {
         aEvent->clickCount = mMClickCount;
         mMClickCount = 0;
       } else {
         aEvent->clickCount = 0;
       }
       mLastMiddleMouseDownContent = nullptr;
       mLastMiddleMouseDownContentParent = nullptr;
     }
     break;
 
   case WidgetMouseEvent::eRightButton:
-    if (aEvent->mMessage == NS_MOUSE_BUTTON_DOWN) {
+    if (aEvent->mMessage == eMouseDown) {
       mLastRightMouseDownContent = mouseContent;
       mLastRightMouseDownContentParent = mouseContentParent;
-    } else if (aEvent->mMessage == NS_MOUSE_BUTTON_UP) {
+    } else if (aEvent->mMessage == eMouseUp) {
       if (mLastRightMouseDownContent == mouseContent ||
           mLastRightMouseDownContentParent == mouseContent ||
           mLastRightMouseDownContent == mouseContentParent) {
         aEvent->clickCount = mRClickCount;
         mRClickCount = 0;
       } else {
         aEvent->clickCount = 0;
       }
@@ -4510,17 +4530,17 @@ EventStateManager::CheckForAndDispatchCl
     if (aEvent->widget && !aEvent->widget->IsEnabled()) {
       return ret;
     }
     //fire click
     bool notDispatchToContents =
      (aEvent->button == WidgetMouseEvent::eMiddleButton ||
       aEvent->button == WidgetMouseEvent::eRightButton);
 
-    WidgetMouseEvent event(aEvent->mFlags.mIsTrusted, NS_MOUSE_CLICK,
+    WidgetMouseEvent event(aEvent->mFlags.mIsTrusted, eMouseClick,
                            aEvent->widget, WidgetMouseEvent::eReal);
     event.refPoint = aEvent->refPoint;
     event.clickCount = aEvent->clickCount;
     event.modifiers = aEvent->modifiers;
     event.buttons = aEvent->buttons;
     event.time = aEvent->time;
     event.timeStamp = aEvent->timeStamp;
     event.mFlags.mNoContentDispatch = notDispatchToContents;
@@ -4543,17 +4563,17 @@ EventStateManager::CheckForAndDispatchCl
       }
 
       // HandleEvent clears out mCurrentTarget which we might need again
       nsWeakFrame currentTarget = mCurrentTarget;
       ret = presShell->HandleEventWithTarget(&event, currentTarget,
                                              mouseContent, aStatus);
       if (NS_SUCCEEDED(ret) && aEvent->clickCount == 2) {
         //fire double click
-        WidgetMouseEvent event2(aEvent->mFlags.mIsTrusted, NS_MOUSE_DOUBLECLICK,
+        WidgetMouseEvent event2(aEvent->mFlags.mIsTrusted, eMouseDoubleClick,
                                 aEvent->widget, WidgetMouseEvent::eReal);
         event2.refPoint = aEvent->refPoint;
         event2.clickCount = aEvent->clickCount;
         event2.modifiers = aEvent->modifiers;
         event2.buttons = aEvent->buttons;
         event2.mFlags.mNoContentDispatch = notDispatchToContents;
         event2.button = aEvent->button;
         event2.inputSource = aEvent->inputSource;
@@ -4683,16 +4703,20 @@ GetParentElement(Element* aElement)
 /* static */
 void
 EventStateManager::SetFullScreenState(Element* aElement, bool aIsFullScreen)
 {
   DoStateChange(aElement, NS_EVENT_STATE_FULL_SCREEN, aIsFullScreen);
   Element* ancestor = aElement;
   while ((ancestor = GetParentElement(ancestor))) {
     DoStateChange(ancestor, NS_EVENT_STATE_FULL_SCREEN_ANCESTOR, aIsFullScreen);
+    if (ancestor->State().HasState(NS_EVENT_STATE_FULL_SCREEN)) {
+      // If we meet another fullscreen element, stop here.
+      break;
+    }
   }
 }
 
 /* static */
 inline void
 EventStateManager::DoStateChange(Element* aElement, EventStates aState,
                                  bool aAddState)
 {
@@ -4955,17 +4979,17 @@ EventStateManager::ContentRemoved(nsIDoc
   ResetLastOverForContent(0, mMouseEnterLeaveHelper, aContent);
   mPointersEnterLeaveHelper.Enumerate(
     &EventStateManager::ResetLastOverForContent, aContent);
 }
 
 bool
 EventStateManager::EventStatusOK(WidgetGUIEvent* aEvent)
 {
-  return !(aEvent->mMessage == NS_MOUSE_BUTTON_DOWN &&
+  return !(aEvent->mMessage == eMouseDown &&
            aEvent->AsMouseEvent()->button == WidgetMouseEvent::eLeftButton &&
            !sNormalLMouseEventInProcess);
 }
 
 //-------------------------------------------
 // Access Key Registration
 //-------------------------------------------
 void
@@ -5744,33 +5768,32 @@ EventStateManager::Prefs::GetAccessModif
 /* mozilla::AutoHandlingUserInputStatePusher                      */
 /******************************************************************/
 
 AutoHandlingUserInputStatePusher::AutoHandlingUserInputStatePusher(
                                     bool aIsHandlingUserInput,
                                     WidgetEvent* aEvent,
                                     nsIDocument* aDocument) :
   mIsHandlingUserInput(aIsHandlingUserInput),
-  mIsMouseDown(aEvent && aEvent->mMessage == NS_MOUSE_BUTTON_DOWN),
+  mIsMouseDown(aEvent && aEvent->mMessage == eMouseDown),
   mResetFMMouseButtonHandlingState(false)
 {
   if (!aIsHandlingUserInput) {
     return;
   }
   EventStateManager::StartHandlingUserInput();
   if (mIsMouseDown) {
     nsIPresShell::SetCapturingContent(nullptr, 0);
     nsIPresShell::AllowMouseCapture(true);
   }
   if (!aDocument || !aEvent || !aEvent->mFlags.mIsTrusted) {
     return;
   }
   mResetFMMouseButtonHandlingState =
-    (aEvent->mMessage == NS_MOUSE_BUTTON_DOWN ||
-     aEvent->mMessage == NS_MOUSE_BUTTON_UP);
+    (aEvent->mMessage == eMouseDown || aEvent->mMessage == eMouseUp);
   if (mResetFMMouseButtonHandlingState) {
     nsFocusManager* fm = nsFocusManager::GetFocusManager();
     NS_ENSURE_TRUE_VOID(fm);
     // If it's in modal state, mouse button event handling may be nested.
     // E.g., a modal dialog is opened at mousedown or mouseup event handler
     // and the dialog is clicked.  Therefore, we should store current
     // mouse button event handling document if nsFocusManager already has it.
     mMouseButtonEventHandlingDocument =
--- a/dom/events/EventStateManager.h
+++ b/dom/events/EventStateManager.h
@@ -953,12 +953,12 @@ private:
 };
 
 } // namespace mozilla
 
 // Click and double-click events need to be handled even for content that
 // has no frame. This is required for Web compatibility.
 #define NS_EVENT_NEEDS_FRAME(event) \
     (!(event)->HasPluginActivationEventMessage() && \
-     (event)->mMessage != NS_MOUSE_CLICK && \
-     (event)->mMessage != NS_MOUSE_DOUBLECLICK)
+     (event)->mMessage != eMouseClick && \
+     (event)->mMessage != eMouseDoubleClick)
 
 #endif // mozilla_EventStateManager_h_
--- a/dom/events/IMEContentObserver.cpp
+++ b/dom/events/IMEContentObserver.cpp
@@ -452,18 +452,18 @@ IMEContentObserver::OnMouseButtonEvent(n
   }
   if (!aMouseEvent->mFlags.mIsTrusted ||
       aMouseEvent->mFlags.mDefaultPrevented ||
       !aMouseEvent->widget) {
     return false;
   }
   // Now, we need to notify only mouse down and mouse up event.
   switch (aMouseEvent->mMessage) {
-    case NS_MOUSE_BUTTON_UP:
-    case NS_MOUSE_BUTTON_DOWN:
+    case eMouseUp:
+    case eMouseDown:
       break;
     default:
       return false;
   }
   if (NS_WARN_IF(!mWidget) || NS_WARN_IF(mWidget->Destroyed())) {
     return false;
   }
 
--- a/dom/events/InputEvent.cpp
+++ b/dom/events/InputEvent.cpp
@@ -11,18 +11,17 @@
 namespace mozilla {
 namespace dom {
 
 InputEvent::InputEvent(EventTarget* aOwner,
                        nsPresContext* aPresContext,
                        InternalEditorInputEvent* aEvent)
   : UIEvent(aOwner, aPresContext,
             aEvent ? aEvent :
-                     new InternalEditorInputEvent(false, NS_EVENT_NULL,
-                                                  nullptr))
+                     new InternalEditorInputEvent(false, eVoidEvent, nullptr))
 {
   NS_ASSERTION(mEvent->mClass == eEditorInputEventClass,
                "event type mismatch");
 
   if (aEvent) {
     mEventIsInternal = false;
   } else {
     mEventIsInternal = true;
--- a/dom/events/KeyboardEvent.cpp
+++ b/dom/events/KeyboardEvent.cpp
@@ -11,17 +11,17 @@
 namespace mozilla {
 namespace dom {
 
 KeyboardEvent::KeyboardEvent(EventTarget* aOwner,
                              nsPresContext* aPresContext,
                              WidgetKeyboardEvent* aEvent)
   : UIEvent(aOwner, aPresContext,
             aEvent ? aEvent :
-                     new WidgetKeyboardEvent(false, NS_EVENT_NULL, nullptr))
+                     new WidgetKeyboardEvent(false, eVoidEvent, nullptr))
   , mInitializedByCtor(false)
   , mInitializedWhichValue(0)
 {
   if (aEvent) {
     mEventIsInternal = false;
   }
   else {
     mEventIsInternal = true;
@@ -148,24 +148,24 @@ uint32_t
 KeyboardEvent::CharCode()
 {
   // If this event is initialized with ctor, we shouldn't check event type.
   if (mInitializedByCtor) {
     return mEvent->AsKeyboardEvent()->charCode;
   }
 
   switch (mEvent->mMessage) {
-  case NS_KEY_BEFORE_DOWN:
-  case NS_KEY_DOWN:
-  case NS_KEY_AFTER_DOWN:
-  case NS_KEY_BEFORE_UP:
-  case NS_KEY_UP:
-  case NS_KEY_AFTER_UP:
+  case eBeforeKeyDown:
+  case eKeyDown:
+  case eAfterKeyDown:
+  case eBeforeKeyUp:
+  case eKeyUp:
+  case eAfterKeyUp:
     return 0;
-  case NS_KEY_PRESS:
+  case eKeyPress:
     return mEvent->AsKeyboardEvent()->charCode;
   default:
     break;
   }
   return 0;
 }
 
 NS_IMETHODIMP
@@ -194,24 +194,24 @@ uint32_t
 KeyboardEvent::Which()
 {
   // If this event is initialized with ctor, which can have independent value.
   if (mInitializedByCtor) {
     return mInitializedWhichValue;
   }
 
   switch (mEvent->mMessage) {
-    case NS_KEY_BEFORE_DOWN:
-    case NS_KEY_DOWN:
-    case NS_KEY_AFTER_DOWN:
-    case NS_KEY_BEFORE_UP:
-    case NS_KEY_UP:
-    case NS_KEY_AFTER_UP:
+    case eBeforeKeyDown:
+    case eKeyDown:
+    case eAfterKeyDown:
+    case eBeforeKeyUp:
+    case eKeyUp:
+    case eAfterKeyUp:
       return KeyCode();
-    case NS_KEY_PRESS:
+    case eKeyPress:
       //Special case for 4xp bug 62878.  Try to make value of which
       //more closely mirror the values that 4.x gave for RETURN and BACKSPACE
       {
         uint32_t keyCode = mEvent->AsKeyboardEvent()->keyCode;
         if (keyCode == NS_VK_RETURN || keyCode == NS_VK_BACK) {
           return keyCode;
         }
         return CharCode();
--- a/dom/events/MouseEvent.cpp
+++ b/dom/events/MouseEvent.cpp
@@ -13,17 +13,17 @@
 namespace mozilla {
 namespace dom {
 
 MouseEvent::MouseEvent(EventTarget* aOwner,
                        nsPresContext* aPresContext,
                        WidgetMouseEventBase* aEvent)
   : UIEvent(aOwner, aPresContext,
             aEvent ? aEvent :
-                     new WidgetMouseEvent(false, NS_EVENT_NULL, nullptr,
+                     new WidgetMouseEvent(false, eVoidEvent, nullptr,
                                           WidgetMouseEvent::eReal))
 {
   // There's no way to make this class' ctor allocate an WidgetMouseScrollEvent.
   // It's not that important, though, since a scroll event is not a real
   // DOM event.
 
   WidgetMouseEvent* mouseEvent = mEvent->AsMouseEvent();
   if (aEvent) {
--- a/dom/events/MouseScrollEvent.cpp
+++ b/dom/events/MouseScrollEvent.cpp
@@ -11,18 +11,17 @@
 namespace mozilla {
 namespace dom {
 
 MouseScrollEvent::MouseScrollEvent(EventTarget* aOwner,
                                    nsPresContext* aPresContext,
                                    WidgetMouseScrollEvent* aEvent)
   : MouseEvent(aOwner, aPresContext,
                aEvent ? aEvent :
-                        new WidgetMouseScrollEvent(false, NS_EVENT_NULL,
-                                                   nullptr))
+                        new WidgetMouseScrollEvent(false, eVoidEvent, nullptr))
 {
   if (aEvent) {
     mEventIsInternal = false;
   } else {
     mEventIsInternal = true;
     mEvent->time = PR_Now();
     mEvent->refPoint.x = mEvent->refPoint.y = 0;
     static_cast<WidgetMouseEventBase*>(mEvent)->inputSource =
--- a/dom/events/MutationEvent.cpp
+++ b/dom/events/MutationEvent.cpp
@@ -12,17 +12,17 @@ class nsPresContext;
 
 namespace mozilla {
 namespace dom {
 
 MutationEvent::MutationEvent(EventTarget* aOwner,
                              nsPresContext* aPresContext,
                              InternalMutationEvent* aEvent)
   : Event(aOwner, aPresContext,
-          aEvent ? aEvent : new InternalMutationEvent(false, NS_EVENT_NULL))
+          aEvent ? aEvent : new InternalMutationEvent(false, eVoidEvent))
 {
   mEventIsInternal = (aEvent == nullptr);
 }
 
 NS_INTERFACE_MAP_BEGIN(MutationEvent)
   NS_INTERFACE_MAP_ENTRY(nsIDOMMutationEvent)
 NS_INTERFACE_MAP_END_INHERITING(Event)
 
--- a/dom/events/NotifyPaintEvent.h
+++ b/dom/events/NotifyPaintEvent.h
@@ -68,13 +68,13 @@ private:
 } // namespace mozilla
 
 // This empties aInvalidateRequests.
 already_AddRefed<mozilla::dom::NotifyPaintEvent>
 NS_NewDOMNotifyPaintEvent(mozilla::dom::EventTarget* aOwner,
                           nsPresContext* aPresContext,
                           mozilla::WidgetEvent* aEvent,
                           mozilla::EventMessage aEventMessage =
-                            mozilla::NS_EVENT_NULL,
+                            mozilla::eVoidEvent,
                           nsInvalidateRequestList* aInvalidateRequests =
                             nullptr);
 
 #endif // mozilla_dom_NotifyPaintEvent_h_
--- a/dom/events/PointerEvent.cpp
+++ b/dom/events/PointerEvent.cpp
@@ -13,17 +13,17 @@
 namespace mozilla {
 namespace dom {
 
 PointerEvent::PointerEvent(EventTarget* aOwner,
                            nsPresContext* aPresContext,
                            WidgetPointerEvent* aEvent)
   : MouseEvent(aOwner, aPresContext,
                aEvent ? aEvent :
-                        new WidgetPointerEvent(false, NS_EVENT_NULL, nullptr))
+                        new WidgetPointerEvent(false, eVoidEvent, nullptr))
 {
   NS_ASSERTION(mEvent->mClass == ePointerEventClass,
                "event type mismatch ePointerEventClass");
 
   WidgetMouseEvent* mouseEvent = mEvent->AsMouseEvent();
   if (aEvent) {
     mEventIsInternal = false;
   } else {
--- a/dom/events/SimpleGestureEvent.cpp
+++ b/dom/events/SimpleGestureEvent.cpp
@@ -11,17 +11,17 @@
 namespace mozilla {
 namespace dom {
 
 SimpleGestureEvent::SimpleGestureEvent(EventTarget* aOwner,
                                        nsPresContext* aPresContext,
                                        WidgetSimpleGestureEvent* aEvent)
   : MouseEvent(aOwner, aPresContext,
                aEvent ? aEvent :
-                        new WidgetSimpleGestureEvent(false, NS_EVENT_NULL,
+                        new WidgetSimpleGestureEvent(false, eVoidEvent,
                                                      nullptr))
 {
   NS_ASSERTION(mEvent->mClass == eSimpleGestureEventClass,
                "event type mismatch");
 
   if (aEvent) {
     mEventIsInternal = false;
   } else {
--- a/dom/events/TouchEvent.cpp
+++ b/dom/events/TouchEvent.cpp
@@ -59,17 +59,17 @@ TouchList::IdentifiedTouch(int32_t aIden
  * TouchEvent
  *****************************************************************************/
 
 TouchEvent::TouchEvent(EventTarget* aOwner,
                        nsPresContext* aPresContext,
                        WidgetTouchEvent* aEvent)
   : UIEvent(aOwner, aPresContext,
             aEvent ? aEvent :
-                     new WidgetTouchEvent(false, NS_EVENT_NULL, nullptr))
+                     new WidgetTouchEvent(false, eVoidEvent, nullptr))
 {
   if (aEvent) {
     mEventIsInternal = false;
 
     for (uint32_t i = 0; i < aEvent->touches.Length(); ++i) {
       Touch* touch = aEvent->touches[i];
       touch->InitializePoints(mPresContext, aEvent);
     }
--- a/dom/events/TransitionEvent.cpp
+++ b/dom/events/TransitionEvent.cpp
@@ -10,17 +10,17 @@
 
 namespace mozilla {
 namespace dom {
 
 TransitionEvent::TransitionEvent(EventTarget* aOwner,
                                  nsPresContext* aPresContext,
                                  InternalTransitionEvent* aEvent)
   : Event(aOwner, aPresContext,
-          aEvent ? aEvent : new InternalTransitionEvent(false, NS_EVENT_NULL))
+          aEvent ? aEvent : new InternalTransitionEvent(false, eVoidEvent))
 {
   if (aEvent) {
     mEventIsInternal = false;
   }
   else {
     mEventIsInternal = true;
     mEvent->time = PR_Now();
   }
--- a/dom/events/UIEvent.cpp
+++ b/dom/events/UIEvent.cpp
@@ -24,17 +24,17 @@
 
 namespace mozilla {
 namespace dom {
 
 UIEvent::UIEvent(EventTarget* aOwner,
                  nsPresContext* aPresContext,
                  WidgetGUIEvent* aEvent)
   : Event(aOwner, aPresContext,
-          aEvent ? aEvent : new InternalUIEvent(false, NS_EVENT_NULL, nullptr))
+          aEvent ? aEvent : new InternalUIEvent(false, eVoidEvent, nullptr))
   , mClientPoint(0, 0)
   , mLayerPoint(0, 0)
   , mPagePoint(0, 0)
   , mMovementPoint(0, 0)
   , mIsPointerLocked(EventStateManager::sIsPointerLocked)
   , mLastClientPoint(EventStateManager::sLastClientPoint)
 {
   if (aEvent) {
--- a/dom/events/WheelEvent.cpp
+++ b/dom/events/WheelEvent.cpp
@@ -11,18 +11,17 @@
 namespace mozilla {
 namespace dom {
 
 WheelEvent::WheelEvent(EventTarget* aOwner,
                        nsPresContext* aPresContext,
                        WidgetWheelEvent* aWheelEvent)
   : MouseEvent(aOwner, aPresContext,
                aWheelEvent ? aWheelEvent :
-                             new WidgetWheelEvent(false, NS_EVENT_NULL,
-                                                  nullptr))
+                             new WidgetWheelEvent(false, eVoidEvent, nullptr))
   , mAppUnitsPerDevPixel(0)
 {
   if (aWheelEvent) {
     mEventIsInternal = false;
     // If the delta mode is pixel, the WidgetWheelEvent's delta values are in
     // device pixels.  However, JS contents need the delta values in CSS pixels.
     // We should store the value of mAppUnitsPerDevPixel here because
     // it might be changed by changing zoom or something.
--- a/dom/events/WheelHandlingHelper.cpp
+++ b/dom/events/WheelHandlingHelper.cpp
@@ -179,17 +179,17 @@ WheelTransaction::OnEvent(WidgetEvent* a
     case NS_WHEEL_WHEEL:
       if (sMouseMoved != 0 &&
           OutOfTime(sMouseMoved, GetIgnoreMoveDelayTime())) {
         // Terminate the current mousewheel transaction if the mouse moved more
         // than ignoremovedelay milliseconds ago
         EndTransaction();
       }
       return;
-    case NS_MOUSE_MOVE:
+    case eMouseMove:
     case NS_DRAGDROP_OVER: {
       WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
       if (mouseEvent->IsReal()) {
         // If the cursor is moving to be outside the frame,
         // terminate the scrollwheel transaction.
         nsIntPoint pt = GetScreenPoint(mouseEvent);
         nsIntRect r = sTargetFrame->GetScreenRectExternal();
         if (!r.Contains(pt)) {
@@ -202,23 +202,23 @@ WheelTransaction::OnEvent(WidgetEvent* a
         // the mouse move; otherwise, record the current mouse move time to be
         // checked later
         if (!sMouseMoved && OutOfTime(sTime, GetIgnoreMoveDelayTime())) {
           sMouseMoved = PR_IntervalToMilliseconds(PR_IntervalNow());
         }
       }
       return;
     }
-    case NS_KEY_PRESS:
-    case NS_KEY_UP:
-    case NS_KEY_DOWN:
-    case NS_MOUSE_BUTTON_UP:
-    case NS_MOUSE_BUTTON_DOWN:
-    case NS_MOUSE_DOUBLECLICK:
-    case NS_MOUSE_CLICK:
+    case eKeyPress:
+    case eKeyUp:
+    case eKeyDown:
+    case eMouseUp:
+    case eMouseDown:
+    case eMouseDoubleClick:
+    case eMouseClick:
     case NS_CONTEXTMENU:
     case NS_DRAGDROP_DROP:
       EndTransaction();
       return;
     default:
       break;
   }
 }
--- a/dom/events/XULCommandEvent.cpp
+++ b/dom/events/XULCommandEvent.cpp
@@ -10,17 +10,17 @@
 namespace mozilla {
 namespace dom {
 
 XULCommandEvent::XULCommandEvent(EventTarget* aOwner,
                                  nsPresContext* aPresContext,
                                  WidgetInputEvent* aEvent)
   : UIEvent(aOwner, aPresContext,
             aEvent ? aEvent :
-                     new WidgetInputEvent(false, NS_EVENT_NULL, nullptr))
+                     new WidgetInputEvent(false, eVoidEvent, nullptr))
 {
   if (aEvent) {
     mEventIsInternal = false;
   }
   else {
     mEventIsInternal = true;
     mEvent->time = PR_Now();
   }
--- a/dom/fetch/FetchDriver.cpp
+++ b/dom/fetch/FetchDriver.cpp
@@ -36,17 +36,17 @@
 #include "InternalRequest.h"
 #include "InternalResponse.h"
 
 namespace mozilla {
 namespace dom {
 
 NS_IMPL_ISUPPORTS(FetchDriver,
                   nsIStreamListener, nsIChannelEventSink, nsIInterfaceRequestor,
-                  nsIAsyncVerifyRedirectCallback)
+                  nsIAsyncVerifyRedirectCallback, nsIThreadRetargetableStreamListener)
 
 FetchDriver::FetchDriver(InternalRequest* aRequest, nsIPrincipal* aPrincipal,
                          nsILoadGroup* aLoadGroup)
   : mPrincipal(aPrincipal)
   , mLoadGroup(aLoadGroup)
   , mRequest(aRequest)
   , mFetchRecursionCount(0)
   , mResponseAvailableCalled(false)
@@ -777,30 +777,33 @@ FetchDriver::OnStartRequest(nsIRequest* 
   nsCOMPtr<nsIEventTarget> sts = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID, &rv);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     FailWithNetworkError();
     // Cancel request.
     return rv;
   }
 
   // Try to retarget off main thread.
-  nsCOMPtr<nsIThreadRetargetableRequest> rr = do_QueryInterface(aRequest);
-  if (rr) {
-    rr->RetargetDeliveryTo(sts);
+  if (nsCOMPtr<nsIThreadRetargetableRequest> rr = do_QueryInterface(aRequest)) {
+    NS_WARN_IF(NS_FAILED(rr->RetargetDeliveryTo(sts)));
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 FetchDriver::OnDataAvailable(nsIRequest* aRequest,
                              nsISupports* aContext,
                              nsIInputStream* aInputStream,
                              uint64_t aOffset,
                              uint32_t aCount)
 {
+  // NB: This can be called on any thread!  But we're guaranteed that it is
+  // called between OnStartRequest and OnStopRequest, so we don't need to worry
+  // about races.
+
   uint32_t aRead;
   MOZ_ASSERT(mResponse);
   MOZ_ASSERT(mPipeOutputStream);
 
   nsresult rv = aInputStream->ReadSegments(NS_CopySegmentToStream,
                                            mPipeOutputStream,
                                            aCount, &aRead);
   return rv;
@@ -882,16 +885,22 @@ FetchDriver::AsyncOnChannelRedirect(nsIC
     }
     return rv;
   }
 
   (void) OnRedirectVerifyCallback(NS_OK);
   return NS_OK;
 }
 
+NS_IMETHODIMP
+FetchDriver::CheckListenerChain()
+{
+  return NS_OK;
+}
+
 // Returns NS_OK if no preflight is required, error otherwise.
 nsresult
 FetchDriver::DoesNotRequirePreflight(nsIChannel* aChannel)
 {
   // If this is a same-origin request or the channel's URI inherits
   // its principal, it's allowed.
   if (nsContentUtils::CheckMayLoad(mPrincipal, aChannel, true)) {
     return NS_OK;
--- a/dom/fetch/FetchDriver.h
+++ b/dom/fetch/FetchDriver.h
@@ -7,16 +7,17 @@
 #ifndef mozilla_dom_FetchDriver_h
 #define mozilla_dom_FetchDriver_h
 
 #include "nsAutoPtr.h"
 #include "nsIAsyncVerifyRedirectCallback.h"
 #include "nsIChannelEventSink.h"
 #include "nsIInterfaceRequestor.h"
 #include "nsIStreamListener.h"
+#include "nsIThreadRetargetableStreamListener.h"
 #include "mozilla/nsRefPtr.h"
 
 #include "mozilla/DebugOnly.h"
 #include "mozilla/net/ReferrerPolicy.h"
 
 class nsIDocument;
 class nsIOutputStream;
 class nsILoadGroup;
@@ -39,25 +40,27 @@ public:
 protected:
   virtual ~FetchDriverObserver()
   { };
 };
 
 class FetchDriver final : public nsIStreamListener,
                           public nsIChannelEventSink,
                           public nsIInterfaceRequestor,
-                          public nsIAsyncVerifyRedirectCallback
+                          public nsIAsyncVerifyRedirectCallback,
+                          public nsIThreadRetargetableStreamListener
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIREQUESTOBSERVER
   NS_DECL_NSISTREAMLISTENER
   NS_DECL_NSICHANNELEVENTSINK
   NS_DECL_NSIINTERFACEREQUESTOR
   NS_DECL_NSIASYNCVERIFYREDIRECTCALLBACK
+  NS_DECL_NSITHREADRETARGETABLESTREAMLISTENER
 
   explicit FetchDriver(InternalRequest* aRequest, nsIPrincipal* aPrincipal,
                        nsILoadGroup* aLoadGroup);
   NS_IMETHOD Fetch(FetchDriverObserver* aObserver);
 
   void
   SetDocument(nsIDocument* aDocument);
 
--- a/dom/html/HTMLButtonElement.cpp
+++ b/dom/html/HTMLButtonElement.cpp
@@ -277,41 +277,41 @@ HTMLButtonElement::PostHandleEvent(Event
     // so the form knows not to defer subsequent submissions
     // the pending ones that were created during the handler
     // will be flushed or forgoten.
     mForm->OnSubmitClickEnd();
   }
 
   if (nsEventStatus_eIgnore == aVisitor.mEventStatus) {
     switch (aVisitor.mEvent->mMessage) {
-      case NS_KEY_PRESS:
-      case NS_KEY_UP:
+      case eKeyPress:
+      case eKeyUp:
         {
           // For backwards compat, trigger buttons with space or enter
           // (bug 25300)
           WidgetKeyboardEvent* keyEvent = aVisitor.mEvent->AsKeyboardEvent();
           if ((keyEvent->keyCode == NS_VK_RETURN &&
-               NS_KEY_PRESS == aVisitor.mEvent->mMessage) ||
+               eKeyPress == aVisitor.mEvent->mMessage) ||
               (keyEvent->keyCode == NS_VK_SPACE &&
-               NS_KEY_UP == aVisitor.mEvent->mMessage)) {
+               eKeyUp == aVisitor.mEvent->mMessage)) {
             nsEventStatus status = nsEventStatus_eIgnore;
 
             WidgetMouseEvent event(aVisitor.mEvent->mFlags.mIsTrusted,
-                                   NS_MOUSE_CLICK, nullptr,
+                                   eMouseClick, nullptr,
                                    WidgetMouseEvent::eReal);
             event.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_KEYBOARD;
             EventDispatcher::Dispatch(static_cast<nsIContent*>(this),
                                       aVisitor.mPresContext, &event, nullptr,
                                       &status);
             aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
           }
         }
-        break;// NS_KEY_PRESS
+        break;
 
-      case NS_MOUSE_BUTTON_DOWN:
+      case eMouseDown:
         {
           WidgetMouseEvent* mouseEvent = aVisitor.mEvent->AsMouseEvent();
           if (mouseEvent->button == WidgetMouseEvent::eLeftButton) {
             if (mouseEvent->mFlags.mIsTrusted) {
               EventStateManager* esm =
                 aVisitor.mPresContext->EventStateManager();
               EventStateManager::SetActiveManager(
                 static_cast<EventStateManager*>(esm), this);
@@ -329,38 +329,38 @@ HTMLButtonElement::PostHandleEvent(Event
               aVisitor.mDOMEvent->StopPropagation();
             }
           }
         }
         break;
 
       // cancel all of these events for buttons
       //XXXsmaug What to do with these events? Why these should be cancelled?
-      case NS_MOUSE_BUTTON_UP:
-      case NS_MOUSE_DOUBLECLICK:
+      case eMouseUp:
+      case eMouseDoubleClick:
         {
           WidgetMouseEvent* mouseEvent = aVisitor.mEvent->AsMouseEvent();
           if (aVisitor.mDOMEvent &&
               (mouseEvent->button == WidgetMouseEvent::eMiddleButton ||
                mouseEvent->button == WidgetMouseEvent::eRightButton)) {
             aVisitor.mDOMEvent->StopPropagation();
           }
         }
         break;
 
-      case NS_MOUSE_OVER:
+      case eMouseOver:
         {
           aVisitor.mPresContext->EventStateManager()->
             SetContentState(this, NS_EVENT_STATE_HOVER);
           aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
         }
         break;
 
         // XXX this doesn't seem to do anything yet
-      case NS_MOUSE_OUT:
+      case eMouseOut:
         {
           aVisitor.mPresContext->EventStateManager()->
             SetContentState(nullptr, NS_EVENT_STATE_HOVER);
           aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
         }
         break;
 
       default:
--- a/dom/html/HTMLInputElement.cpp
+++ b/dom/html/HTMLInputElement.cpp
@@ -2801,18 +2801,17 @@ HTMLInputElement::MaybeSubmitForm(nsPres
 
   // Get the default submit element
   nsIFormControl* submitControl = mForm->GetDefaultSubmitElement();
   if (submitControl) {
     nsCOMPtr<nsIContent> submitContent = do_QueryInterface(submitControl);
     NS_ASSERTION(submitContent, "Form control not implementing nsIContent?!");
     // Fire the button's onclick handler and let the button handle
     // submitting the form.
-    WidgetMouseEvent event(true, NS_MOUSE_CLICK, nullptr,
-                           WidgetMouseEvent::eReal);
+    WidgetMouseEvent event(true, eMouseClick, nullptr, WidgetMouseEvent::eReal);
     nsEventStatus status = nsEventStatus_eIgnore;
     shell->HandleDOMEventWithTarget(submitContent, &event, &status);
   } else if (!mForm->ImplicitSubmissionIsDisabled() &&
              (mForm->HasAttr(kNameSpaceID_None, nsGkAtoms::novalidate) ||
               mForm->CheckValidFormSubmission())) {
     // TODO: removing this code and have the submit event sent by the form,
     // bug 592124.
     // If there's only one text control, just submit the form
@@ -3021,21 +3020,21 @@ HTMLInputElement::NeedToInitializeEditor
   // handled without the editor being initialized.  These events include:
   // mousein/move/out, overflow/underflow, and DOM mutation events.
   if (!IsSingleLineTextControl(false) ||
       aVisitor.mEvent->mClass == eMutationEventClass) {
     return false;
   }
 
   switch (aVisitor.mEvent->mMessage) {
-  case NS_MOUSE_MOVE:
-  case NS_MOUSE_ENTER_WIDGET:
-  case NS_MOUSE_EXIT_WIDGET:
-  case NS_MOUSE_OVER:
-  case NS_MOUSE_OUT:
+  case eMouseMove:
+  case eMouseEnterIntoWidget:
+  case eMouseExitFromWidget:
+  case eMouseOver:
+  case eMouseOut:
   case NS_SCROLLPORT_UNDERFLOW:
   case NS_SCROLLPORT_OVERFLOW:
     return false;
   default:
     return true;
   }
 }
 
@@ -3148,17 +3147,17 @@ HTMLInputElement::PreHandleEvent(EventCh
 
   // If mNoContentDispatch is true we will not allow content to handle
   // this event.  But to allow middle mouse button paste to work we must allow
   // middle clicks to go to text fields anyway.
   if (aVisitor.mEvent->mFlags.mNoContentDispatch) {
     aVisitor.mItemFlags |= NS_NO_CONTENT_DISPATCH;
   }
   if (IsSingleLineTextControl(false) &&
-      aVisitor.mEvent->mMessage == NS_MOUSE_CLICK &&
+      aVisitor.mEvent->mMessage == eMouseClick &&
       aVisitor.mEvent->AsMouseEvent()->button ==
         WidgetMouseEvent::eMiddleButton) {
     aVisitor.mEvent->mFlags.mNoContentDispatch = false;
   }
 
   // We must cache type because mType may change during JS event (bug 2369)
   aVisitor.mItemFlags |= mType;
 
@@ -3192,17 +3191,17 @@ HTMLInputElement::PreHandleEvent(EventCh
       aVisitor.mEvent->mFlags.mIsTrusted) {
     if (mNumberControlSpinnerIsSpinning) {
       // If the timer is running the user has depressed the mouse on one of the
       // spin buttons. If the mouse exits the button we either want to reverse
       // the direction of spin if it has moved over the other button, or else
       // we want to end the spin. We do this here (rather than in
       // PostHandleEvent) because we don't want to let content preventDefault()
       // the end of the spin.
-      if (aVisitor.mEvent->mMessage == NS_MOUSE_MOVE) {
+      if (aVisitor.mEvent->mMessage == eMouseMove) {
         // Be aggressive about stopping the spin:
         bool stopSpin = true;
         nsNumberControlFrame* numberControlFrame =
           do_QueryFrame(GetPrimaryFrame());
         if (numberControlFrame) {
           bool oldNumberControlSpinTimerSpinsUpValue =
                  mNumberControlSpinnerSpinsUp;
           switch (numberControlFrame->GetSpinButtonForPointerEvent(
@@ -3223,17 +3222,17 @@ HTMLInputElement::PreHandleEvent(EventCh
             if (numberControlFrame) {
               numberControlFrame->SpinnerStateChanged();
             }
           }
         }
         if (stopSpin) {
           StopNumberControlSpinnerSpin();
         }
-      } else if (aVisitor.mEvent->mMessage == NS_MOUSE_BUTTON_UP) {
+      } else if (aVisitor.mEvent->mMessage == eMouseUp) {
         StopNumberControlSpinnerSpin();
       }
     }
     if (aVisitor.mEvent->mMessage == NS_FOCUS_CONTENT ||
         aVisitor.mEvent->mMessage == NS_BLUR_CONTENT) {
       if (aVisitor.mEvent->mMessage == NS_FOCUS_CONTENT) {
         // Tell our frame it's getting focus so that it can make sure focus
         // is moved to our anonymous text control.
@@ -3249,17 +3248,17 @@ HTMLInputElement::PreHandleEvent(EventCh
         // Our frame's nested <input type=text> will be invalidated when it
         // loses focus, but since we are also native themed we need to make
         // sure that our entire area is repainted since any focus highlight
         // from the theme should be removed from us (the repainting of the
         // sub-area occupied by the anon text control is not enough to do
         // that).
         frame->InvalidateFrame();
       }
-    } else if (aVisitor.mEvent->mMessage == NS_KEY_UP) {
+    } else if (aVisitor.mEvent->mMessage == eKeyUp) {
       WidgetKeyboardEvent* keyEvent = aVisitor.mEvent->AsKeyboardEvent();
       if ((keyEvent->keyCode == NS_VK_UP || keyEvent->keyCode == NS_VK_DOWN) &&
           !(keyEvent->IsShift() || keyEvent->IsControl() ||
             keyEvent->IsAlt() || keyEvent->IsMeta() ||
             keyEvent->IsAltGraph() || keyEvent->IsFn() ||
             keyEvent->IsOS())) {
         // The up/down arrow key events fire 'change' events when released
         // so that at the end of a series of up/down arrow key repeat events
@@ -3717,17 +3716,17 @@ HTMLInputElement::PostHandleEvent(EventC
       }
 #endif
     }
   }
 
   if (NS_SUCCEEDED(rv)) {
     WidgetKeyboardEvent* keyEvent = aVisitor.mEvent->AsKeyboardEvent();
     if (mType ==  NS_FORM_INPUT_NUMBER &&
-        keyEvent && keyEvent->mMessage == NS_KEY_PRESS &&
+        keyEvent && keyEvent->mMessage == eKeyPress &&
         aVisitor.mEvent->mFlags.mIsTrusted &&
         (keyEvent->keyCode == NS_VK_UP || keyEvent->keyCode == NS_VK_DOWN) &&
         !(keyEvent->IsShift() || keyEvent->IsControl() ||
           keyEvent->IsAlt() || keyEvent->IsMeta() ||
           keyEvent->IsAltGraph() || keyEvent->IsFn() ||
           keyEvent->IsOS())) {
       // We handle the up/down arrow keys specially for <input type=number>.
       // On some platforms the editor for the nested text control will
@@ -3769,25 +3768,25 @@ HTMLInputElement::PostHandleEvent(EventC
                   SelectAll(presContext);
                 }
               }
             }
           }
           break;
         }
 
-        case NS_KEY_PRESS:
-        case NS_KEY_UP:
+        case eKeyPress:
+        case eKeyUp:
         {
           // For backwards compat, trigger checks/radios/buttons with
           // space or enter (bug 25300)
           WidgetKeyboardEvent* keyEvent = aVisitor.mEvent->AsKeyboardEvent();
-          if ((aVisitor.mEvent->mMessage == NS_KEY_PRESS &&
+          if ((aVisitor.mEvent->mMessage == eKeyPress &&
                keyEvent->keyCode == NS_VK_RETURN) ||
-              (aVisitor.mEvent->mMessage == NS_KEY_UP &&
+              (aVisitor.mEvent->mMessage == eKeyUp &&
                keyEvent->keyCode == NS_VK_SPACE)) {
             switch(mType) {
               case NS_FORM_INPUT_CHECKBOX:
               case NS_FORM_INPUT_RADIO:
               {
                 // Checkbox and Radio try to submit on Enter press
                 if (keyEvent->keyCode != NS_VK_SPACE) {
                   MaybeSubmitForm(aVisitor.mPresContext);
@@ -3798,29 +3797,29 @@ HTMLInputElement::PostHandleEvent(EventC
               }
               case NS_FORM_INPUT_BUTTON:
               case NS_FORM_INPUT_RESET:
               case NS_FORM_INPUT_SUBMIT:
               case NS_FORM_INPUT_IMAGE: // Bug 34418
               case NS_FORM_INPUT_COLOR:
               {
                 WidgetMouseEvent event(aVisitor.mEvent->mFlags.mIsTrusted,
-                                       NS_MOUSE_CLICK, nullptr,
+                                       eMouseClick, nullptr,
                                        WidgetMouseEvent::eReal);
                 event.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_KEYBOARD;
                 nsEventStatus status = nsEventStatus_eIgnore;
 
                 EventDispatcher::Dispatch(static_cast<nsIContent*>(this),
                                           aVisitor.mPresContext, &event,
                                           nullptr, &status);
                 aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
               } // case
             } // switch
           }
-          if (aVisitor.mEvent->mMessage == NS_KEY_PRESS &&
+          if (aVisitor.mEvent->mMessage == eKeyPress &&
               mType == NS_FORM_INPUT_RADIO && !keyEvent->IsAlt() &&
               !keyEvent->IsControl() && !keyEvent->IsMeta()) {
             bool isMovingBack = false;
             switch (keyEvent->keyCode) {
               case NS_VK_UP:
               case NS_VK_LEFT:
                 isMovingBack = true;
                 // FALLTHROUGH
@@ -3834,17 +3833,17 @@ HTMLInputElement::PostHandleEvent(EventC
                 nsRefPtr<HTMLInputElement> selectedRadioButton;
                 container->GetNextRadioButton(name, isMovingBack, this,
                                               getter_AddRefs(selectedRadioButton));
                 if (selectedRadioButton) {
                   rv = selectedRadioButton->Focus();
                   if (NS_SUCCEEDED(rv)) {
                     nsEventStatus status = nsEventStatus_eIgnore;
                     WidgetMouseEvent event(aVisitor.mEvent->mFlags.mIsTrusted,
-                                           NS_MOUSE_CLICK, nullptr,
+                                           eMouseClick, nullptr,
                                            WidgetMouseEvent::eReal);
                     event.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_KEYBOARD;
                     rv =
                       EventDispatcher::Dispatch(ToSupports(selectedRadioButton),
                                                 aVisitor.mPresContext,
                                                 &event, nullptr, &status);
                     if (NS_SUCCEEDED(rv)) {
                       aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
@@ -3862,27 +3861,27 @@ HTMLInputElement::PostHandleEvent(EventC
            * (a) if there is a submit control in the form, click the first
            *     submit control in the form.
            * (b) if there is just one text control in the form, submit by
            *     sending a submit event directly to the form
            * (c) if there is more than one text input and no submit buttons, do
            *     not submit, period.
            */
 
-          if (aVisitor.mEvent->mMessage == NS_KEY_PRESS &&
+          if (aVisitor.mEvent->mMessage == eKeyPress &&
               keyEvent->keyCode == NS_VK_RETURN &&
                (IsSingleLineTextControl(false, mType) ||
                 mType == NS_FORM_INPUT_NUMBER ||
                 IsExperimentalMobileType(mType))) {
             FireChangeEventIfNeeded();
             rv = MaybeSubmitForm(aVisitor.mPresContext);
             NS_ENSURE_SUCCESS(rv, rv);
           }
 
-          if (aVisitor.mEvent->mMessage == NS_KEY_PRESS &&
+          if (aVisitor.mEvent->mMessage == eKeyPress &&
               mType == NS_FORM_INPUT_RANGE && !keyEvent->IsAlt() &&
               !keyEvent->IsControl() && !keyEvent->IsMeta() &&
               (keyEvent->keyCode == NS_VK_LEFT ||
                keyEvent->keyCode == NS_VK_RIGHT ||
                keyEvent->keyCode == NS_VK_UP ||
                keyEvent->keyCode == NS_VK_DOWN ||
                keyEvent->keyCode == NS_VK_PAGE_UP ||
                keyEvent->keyCode == NS_VK_PAGE_DOWN ||
@@ -3931,22 +3930,21 @@ HTMLInputElement::PostHandleEvent(EventC
                   newValue = value - std::max(step, (maximum - minimum) / Decimal(10));
                   break;
               }
               SetValueOfRangeForUserEvent(newValue);
               aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
             }
           }
 
-        } break; // NS_KEY_PRESS || NS_KEY_UP
-
-        case NS_MOUSE_BUTTON_DOWN:
-        case NS_MOUSE_BUTTON_UP:
-        case NS_MOUSE_DOUBLECLICK:
-        {
+        } break; // eKeyPress || eKeyUp
+
+        case eMouseDown:
+        case eMouseUp:
+        case eMouseDoubleClick: {
           // cancel all of these events for buttons
           //XXXsmaug Why?
           WidgetMouseEvent* mouseEvent = aVisitor.mEvent->AsMouseEvent();
           if (mouseEvent->button == WidgetMouseEvent::eMiddleButton ||
               mouseEvent->button == WidgetMouseEvent::eRightButton) {
             if (mType == NS_FORM_INPUT_BUTTON ||
                 mType == NS_FORM_INPUT_RESET ||
                 mType == NS_FORM_INPUT_SUBMIT) {
@@ -3962,17 +3960,17 @@ HTMLInputElement::PostHandleEvent(EventC
             if (mouseEvent->button == WidgetMouseEvent::eLeftButton &&
                 !(mouseEvent->IsShift() || mouseEvent->IsControl() ||
                   mouseEvent->IsAlt() || mouseEvent->IsMeta() ||
                   mouseEvent->IsAltGraph() || mouseEvent->IsFn() ||
                   mouseEvent->IsOS())) {
               nsNumberControlFrame* numberControlFrame =
                 do_QueryFrame(GetPrimaryFrame());
               if (numberControlFrame) {
-                if (aVisitor.mEvent->mMessage == NS_MOUSE_BUTTON_DOWN && 
+                if (aVisitor.mEvent->mMessage == eMouseDown && 
                     IsMutable()) {
                   switch (numberControlFrame->GetSpinButtonForPointerEvent(
                             aVisitor.mEvent->AsMouseEvent())) {
                   case nsNumberControlFrame::eSpinButtonUp:
                     StepNumberControlForUserEvent(1);
                     mNumberControlSpinnerSpinsUp = true;
                     StartNumberControlSpinnerSpin();
                     aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
@@ -4081,77 +4079,77 @@ HTMLInputElement::PostHandleEventForRang
   nsRangeFrame* rangeFrame = do_QueryFrame(GetPrimaryFrame());
   if (!rangeFrame && mIsDraggingRange) {
     CancelRangeThumbDrag();
     return;
   }
 
   switch (aVisitor.mEvent->mMessage)
   {
-    case NS_MOUSE_BUTTON_DOWN:
+    case eMouseDown:
     case NS_TOUCH_START: {
       if (mIsDraggingRange) {
         break;
       }
       if (nsIPresShell::GetCapturingContent()) {
         break; // don't start drag if someone else is already capturing
       }
       WidgetInputEvent* inputEvent = aVisitor.mEvent->AsInputEvent();
       if (inputEvent->IsShift() || inputEvent->IsControl() ||
           inputEvent->IsAlt() || inputEvent->IsMeta() ||
           inputEvent->IsAltGraph() || inputEvent->IsFn() ||
           inputEvent->IsOS()) {
         break; // ignore
       }
-      if (aVisitor.mEvent->mMessage == NS_MOUSE_BUTTON_DOWN) {
+      if (aVisitor.mEvent->mMessage == eMouseDown) {
         if (aVisitor.mEvent->AsMouseEvent()->buttons ==
               WidgetMouseEvent::eLeftButtonFlag) {
           StartRangeThumbDrag(inputEvent);
         } else if (mIsDraggingRange) {
           CancelRangeThumbDrag();
         }
       } else {
         if (aVisitor.mEvent->AsTouchEvent()->touches.Length() == 1) {
           StartRangeThumbDrag(inputEvent);
         } else if (mIsDraggingRange) {
           CancelRangeThumbDrag();
         }
       }
       aVisitor.mEvent->mFlags.mMultipleActionsPrevented = true;
     } break;
 
-    case NS_MOUSE_MOVE:
+    case eMouseMove:
     case NS_TOUCH_MOVE:
       if (!mIsDraggingRange) {
         break;
       }
       if (nsIPresShell::GetCapturingContent() != this) {
         // Someone else grabbed capture.
         CancelRangeThumbDrag();
         break;
       }
       SetValueOfRangeForUserEvent(
         rangeFrame->GetValueAtEventPoint(aVisitor.mEvent->AsInputEvent()));
       aVisitor.mEvent->mFlags.mMultipleActionsPrevented = true;
       break;
 
-    case NS_MOUSE_BUTTON_UP:
+    case eMouseUp:
     case NS_TOUCH_END:
       if (!mIsDraggingRange) {
         break;
       }
       // We don't check to see whether we are the capturing content here and
       // call CancelRangeThumbDrag() if that is the case. We just finish off
       // the drag and set our final value (unless someone has called
       // preventDefault() and prevents us getting here).
       FinishRangeThumbDrag(aVisitor.mEvent->AsInputEvent());
       aVisitor.mEvent->mFlags.mMultipleActionsPrevented = true;
       break;
 
-    case NS_KEY_PRESS:
+    case eKeyPress:
       if (mIsDraggingRange &&
           aVisitor.mEvent->AsKeyboardEvent()->keyCode == NS_VK_ESCAPE) {
         CancelRangeThumbDrag();
       }
       break;
 
     case NS_TOUCH_CANCEL:
       if (mIsDraggingRange) {
--- a/dom/html/HTMLLabelElement.cpp
+++ b/dom/html/HTMLLabelElement.cpp
@@ -99,17 +99,17 @@ InInteractiveHTMLContent(nsIContent* aCo
 }
 
 nsresult
 HTMLLabelElement::PostHandleEvent(EventChainPostVisitor& aVisitor)
 {
   WidgetMouseEvent* mouseEvent = aVisitor.mEvent->AsMouseEvent();
   if (mHandlingEvent ||
       (!(mouseEvent && mouseEvent->IsLeftClickEvent()) &&
-       aVisitor.mEvent->mMessage != NS_MOUSE_BUTTON_DOWN) ||
+       aVisitor.mEvent->mMessage != eMouseDown) ||
       aVisitor.mEventStatus == nsEventStatus_eConsumeNoDefault ||
       !aVisitor.mPresContext ||
       // Don't handle the event if it's already been handled by another label
       aVisitor.mEvent->mFlags.mMultipleActionsPrevented) {
     return NS_OK;
   }
 
   nsCOMPtr<nsIContent> target = do_QueryInterface(aVisitor.mEvent->target);
@@ -118,29 +118,29 @@ HTMLLabelElement::PostHandleEvent(EventC
   }
 
   // Strong ref because event dispatch is going to happen.
   nsRefPtr<Element> content = GetLabeledElement();
 
   if (content) {
     mHandlingEvent = true;
     switch (aVisitor.mEvent->mMessage) {
-      case NS_MOUSE_BUTTON_DOWN:
+      case eMouseDown:
         if (mouseEvent->button == WidgetMouseEvent::eLeftButton) {
           // We reset the mouse-down point on every event because there is
-          // no guarantee we will reach the NS_MOUSE_CLICK code below.
+          // no guarantee we will reach the eMouseClick code below.
           LayoutDeviceIntPoint* curPoint =
             new LayoutDeviceIntPoint(mouseEvent->refPoint);
           SetProperty(nsGkAtoms::labelMouseDownPtProperty,
                       static_cast<void*>(curPoint),
                       nsINode::DeleteProperty<LayoutDeviceIntPoint>);
         }
         break;
 
-      case NS_MOUSE_CLICK:
+      case eMouseClick:
         if (mouseEvent->IsLeftClickEvent()) {
           LayoutDeviceIntPoint* mouseDownPoint =
             static_cast<LayoutDeviceIntPoint*>(
               GetProperty(nsGkAtoms::labelMouseDownPtProperty));
 
           bool dragSelect = false;
           if (mouseDownPoint) {
             LayoutDeviceIntPoint dragDistance = *mouseDownPoint;
@@ -227,17 +227,17 @@ HTMLLabelElement::PerformAccesskey(bool 
     if (element)
       element->PerformAccesskey(aKeyCausesActivation, aIsTrustedEvent);
   } else {
     nsPresContext *presContext = GetPresContext(eForUncomposedDoc);
     if (!presContext)
       return;
 
     // Click on it if the users prefs indicate to do so.
-    WidgetMouseEvent event(aIsTrustedEvent, NS_MOUSE_CLICK,
+    WidgetMouseEvent event(aIsTrustedEvent, eMouseClick,
                            nullptr, WidgetMouseEvent::eReal);
     event.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_KEYBOARD;
 
     nsAutoPopupStatePusher popupStatePusher(aIsTrustedEvent ?
                                             openAllowed : openAbused);
 
     EventDispatcher::Dispatch(static_cast<nsIContent*>(this), presContext,
                               &event);
--- a/dom/html/HTMLMenuItemElement.cpp
+++ b/dom/html/HTMLMenuItemElement.cpp
@@ -249,17 +249,17 @@ HTMLMenuItemElement::SetChecked(bool aCh
   }
 
   return NS_OK;
 }
 
 nsresult
 HTMLMenuItemElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
 {
-  if (aVisitor.mEvent->mMessage == NS_MOUSE_CLICK) {
+  if (aVisitor.mEvent->mMessage == eMouseClick) {
 
     bool originalCheckedValue = false;
     switch (mType) {
       case CMD_TYPE_CHECKBOX:
         originalCheckedValue = mChecked;
         SetChecked(!originalCheckedValue);
         aVisitor.mItemFlags |= NS_CHECKED_IS_TOGGLED;
         break;
@@ -285,17 +285,17 @@ HTMLMenuItemElement::PreHandleEvent(Even
 
   return nsGenericHTMLElement::PreHandleEvent(aVisitor);
 }
 
 nsresult
 HTMLMenuItemElement::PostHandleEvent(EventChainPostVisitor& aVisitor)
 {
   // Check to see if the event was cancelled.
-  if (aVisitor.mEvent->mMessage == NS_MOUSE_CLICK &&
+  if (aVisitor.mEvent->mMessage == eMouseClick &&
       aVisitor.mItemFlags & NS_CHECKED_IS_TOGGLED &&
       aVisitor.mEventStatus == nsEventStatus_eConsumeNoDefault) {
     bool originalCheckedValue =
       !!(aVisitor.mItemFlags & NS_ORIGINAL_CHECKED_VALUE);
     uint8_t oldType = NS_MENUITEM_TYPE(aVisitor.mItemFlags);
 
     nsCOMPtr<nsIDOMHTMLMenuItemElement> selectedRadio =
       do_QueryInterface(aVisitor.mItemData);
--- a/dom/html/HTMLTextAreaElement.cpp
+++ b/dom/html/HTMLTextAreaElement.cpp
@@ -494,17 +494,17 @@ HTMLTextAreaElement::PreHandleEvent(Even
   }
 
   // If noContentDispatch is true we will not allow content to handle
   // this event.  But to allow middle mouse button paste to work we must allow 
   // middle clicks to go to text fields anyway.
   if (aVisitor.mEvent->mFlags.mNoContentDispatch) {
     aVisitor.mItemFlags |= NS_NO_CONTENT_DISPATCH;
   }
-  if (aVisitor.mEvent->mMessage == NS_MOUSE_CLICK &&
+  if (aVisitor.mEvent->mMessage == eMouseClick &&
       aVisitor.mEvent->AsMouseEvent()->button ==
         WidgetMouseEvent::eMiddleButton) {
     aVisitor.mEvent->mFlags.mNoContentDispatch = false;
   }
 
   // Fire onchange (if necessary), before we do the blur, bug 370521.
   if (aVisitor.mEvent->mMessage == NS_BLUR_CONTENT) {
     FireChangeEventIfNeeded();
--- a/dom/html/nsGenericHTMLElement.cpp
+++ b/dom/html/nsGenericHTMLElement.cpp
@@ -2461,17 +2461,17 @@ nsGenericHTMLFormElement::IsElementDisab
 {
   bool disabled = IsDisabled();
   if (!disabled && aFrame) {
     const nsStyleUserInterface* uiStyle = aFrame->StyleUserInterface();
     disabled = uiStyle->mUserInput == NS_STYLE_USER_INPUT_NONE ||
       uiStyle->mUserInput == NS_STYLE_USER_INPUT_DISABLED;
 
   }
-  return disabled && aMessage != NS_MOUSE_MOVE;
+  return disabled && aMessage != eMouseMove;
 }
 
 void
 nsGenericHTMLFormElement::UpdateFormOwner(bool aBindToTree,
                                           Element* aFormIdElement)
 {
   NS_PRECONDITION(!aBindToTree || !aFormIdElement,
                   "aFormIdElement shouldn't be set if aBindToTree is true!");
@@ -2650,17 +2650,17 @@ nsGenericHTMLElement::Click()
   }
 
   SetHandlingClick();
 
   // Click() is never called from native code, but it may be
   // called from chrome JS. Mark this event trusted if Click()
   // is called from chrome code.
   WidgetMouseEvent event(nsContentUtils::IsCallerChrome(),
-                         NS_MOUSE_CLICK, nullptr, WidgetMouseEvent::eReal);
+                         eMouseClick, nullptr, WidgetMouseEvent::eReal);
   event.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_UNKNOWN;
 
   EventDispatcher::Dispatch(static_cast<nsIContent*>(this), context, &event);
 
   ClearHandlingClick();
 }
 
 bool
@@ -2752,17 +2752,17 @@ nsGenericHTMLElement::PerformAccesskey(b
   // It's hard to say what HTML4 wants us to do in all cases.
   nsIFocusManager* fm = nsFocusManager::GetFocusManager();
   if (fm) {
     fm->SetFocus(this, nsIFocusManager::FLAG_BYKEY);
   }
 
   if (aKeyCausesActivation) {
     // Click on it if the users prefs indicate to do so.
-    WidgetMouseEvent event(aIsTrustedEvent, NS_MOUSE_CLICK, nullptr,
+    WidgetMouseEvent event(aIsTrustedEvent, eMouseClick, nullptr,
                            WidgetMouseEvent::eReal);
     event.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_KEYBOARD;
 
     nsAutoPopupStatePusher popupStatePusher(aIsTrustedEvent ?
                                             openAllowed : openAbused);
 
     EventDispatcher::Dispatch(static_cast<nsIContent*>(this),
                               presContext, &event);
--- a/dom/html/nsTextEditorState.cpp
+++ b/dom/html/nsTextEditorState.cpp
@@ -899,17 +899,17 @@ nsTextInputListener::HandleEvent(nsIDOME
   }
 
   WidgetKeyboardEvent* keyEvent =
     aEvent->GetInternalNSEvent()->AsKeyboardEvent();
   if (!keyEvent) {
     return NS_ERROR_UNEXPECTED;
   }
 
-  if (keyEvent->mMessage != NS_KEY_PRESS) {
+  if (keyEvent->mMessage != eKeyPress) {
     return NS_OK;
   }
 
   nsIWidget::NativeKeyBindingsType nativeKeyBindingsType =
     mTxtCtrlElement->IsTextArea() ?
       nsIWidget::NativeKeyBindingsForMultiLineEditor :
       nsIWidget::NativeKeyBindingsForSingleLineEditor;
   nsIWidget* widget = keyEvent->widget;
new file mode 100644
--- /dev/null
+++ b/dom/html/test/file_fullscreen-selector.html
@@ -0,0 +1,178 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test for Bug 1199522</title>
+  <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="file_fullscreen-utils.js"></script>
+  <style>
+    div {
+      position: fixed;
+      top: 20px; height: 50px;
+      opacity: 0.3;
+      border: 5px solid black;
+      box-sizing: border-box;
+    }
+    #fullscreen0 {
+      left: 50px; width: 50px;
+      background: #ff0000;
+      border-color: #800000;
+    }
+    #fullscreen1 {
+      left: 100px; width: 50px;
+      background: #00ff00;
+      border-color: #008000;
+    }
+    #fullscreen2 {
+      left: 150px; width: 50px;
+      background: #0000ff;
+      border-color: #000080;
+    }
+  </style>
+</head>
+<body>
+<script type="application/javascript">
+
+/** Test for Bug 1199522 **/
+
+function info(msg) {
+  opener.info("[selector] " + msg);
+}
+
+function ok(condition, msg) {
+  opener.ok(condition, "[selector] " + msg);
+}
+
+function is(a, b, msg) {
+  opener.is(a, b, "[selector] " + msg);
+}
+
+function rectEquals(rect1, rect2) {
+  return rect1.x == rect2.x && rect1.y == rect2.y &&
+    rect1.width == rect2.width && rect1.height == rect2.height;
+}
+
+function getViewportRect() {
+  return new DOMRect(0, 0, window.innerWidth, window.innerHeight);
+}
+
+var fullscreenElems = [];
+
+function checkFullscreenState(elem, hasState, viewportRect) {
+  var id = elem.id;
+  var rect = elem.getBoundingClientRect();
+  if (hasState) {
+    ok(elem.matches(":-moz-full-screen"),
+       `${id} should match selector ":fullscreen"`);
+    ok(rectEquals(rect, viewportRect),
+       `The bounding rect of ${id} should match the viewport`);
+  } else {
+    ok(!elem.matches(":-moz-full-screen"),
+       `${id} should not match selector ":fullscreen"`);
+    ok(rectEquals(rect, elem.initialRect),
+       `The bounding rect of ${id} should match its initial state`);
+  }
+}
+
+function checkFullscreenStates(states) {
+  var viewportRect = getViewportRect();
+  fullscreenElems.forEach((elem, index) => {
+    checkFullscreenState(elem, states[index], viewportRect);
+  });
+}
+
+function begin() {
+  fullscreenElems.push(document.getElementById('fullscreen0'));
+  fullscreenElems.push(document.getElementById('fullscreen1'));
+  fullscreenElems.push(document.getElementById('fullscreen2'));
+
+  var viewportRect = getViewportRect();
+  for (var elem of fullscreenElems) {
+    var rect = elem.getBoundingClientRect();
+    var id = elem.id;
+    elem.initialRect = rect;
+    ok(!elem.matches(":-moz-full-screen"),
+       `${id} should not match selector ":fullscreen"`);
+    ok(!rectEquals(elem.initialRect, viewportRect),
+       `The initial bounding rect of ${id} should not match the viewport`);
+  }
+
+  info("Entering fullscreen on fullscreen0");
+  addFullscreenChangeContinuation("enter", enter0);
+  fullscreenElems[0].mozRequestFullScreen();
+}
+
+function enter0() {
+  checkFullscreenStates([true, false, false]);
+  info("Entering fullscreen on fullscreen1");
+  addFullscreenChangeContinuation("enter", enter1);
+  fullscreenElems[1].mozRequestFullScreen();
+}
+
+function enter1() {
+  checkFullscreenStates([true, true, false]);
+  info("Entering fullscreen on fullscreen2");
+  addFullscreenChangeContinuation("enter", enter2);
+  fullscreenElems[2].mozRequestFullScreen();
+}
+
+function enter2() {
+  checkFullscreenStates([true, true, true]);
+  info("Leaving fullscreen on fullscreen2");
+  addFullscreenChangeContinuation("exit", exit2);
+  document.mozCancelFullScreen();
+}
+
+function exit2() {
+  checkFullscreenStates([true, true, false]);
+  info("Leaving fullscreen on fullscreen1");
+  addFullscreenChangeContinuation("exit", exit1);
+  document.mozCancelFullScreen();
+}
+
+function exit1() {
+  checkFullscreenStates([true, false, false]);
+  info("Leaving fullscreen on fullscreen0");
+  addFullscreenChangeContinuation("exit", exit0);
+  document.mozCancelFullScreen();
+}
+
+function exit0() {
+  checkFullscreenStates([false, false, false]);
+
+  info("Entering fullscreen on all elements");
+  var count = 0;
+  function listener() {
+    if (++count == 3) {
+      document.removeEventListener("mozfullscreenchange", listener);
+      enterAll();
+    }
+  }
+  document.addEventListener("mozfullscreenchange", listener);
+  fullscreenElems[0].mozRequestFullScreen();
+  fullscreenElems[1].mozRequestFullScreen();
+  fullscreenElems[2].mozRequestFullScreen();
+}
+
+function enterAll() {
+  checkFullscreenStates([true, true, true]);
+  info("Fully-exiting fullscreen");
+  addFullscreenChangeContinuation("exit", exitAll);
+  synthesizeKey("VK_ESCAPE", {});
+}
+
+function exitAll() {
+  checkFullscreenStates([false, false, false]);
+  opener.nextTest();
+}
+
+</script>
+</pre>
+<div id="fullscreen0">
+  <div id="fullscreen1">
+    <div id="fullscreen2">
+    </div>
+  </div>
+</div>
+</body>
+</html>
--- a/dom/html/test/mochitest.ini
+++ b/dom/html/test/mochitest.ini
@@ -55,16 +55,17 @@ support-files =
   file_fullscreen-esc-exit-inner.html
   file_fullscreen-esc-exit.html
   file_fullscreen-hidden.html
   file_fullscreen-multiple-inner.html
   file_fullscreen-multiple.html
   file_fullscreen-navigation.html
   file_fullscreen-plugins.html
   file_fullscreen-rollback.html
+  file_fullscreen-selector.html
   file_fullscreen-svg-element.html
   file_fullscreen-utils.js
   file_iframe_sandbox_a_if1.html
   file_iframe_sandbox_a_if10.html
   file_iframe_sandbox_a_if11.html
   file_iframe_sandbox_a_if12.html
   file_iframe_sandbox_a_if13.html
   file_iframe_sandbox_a_if14.html
--- a/dom/html/test/test_fullscreen-api.html
+++ b/dom/html/test/test_fullscreen-api.html
@@ -34,31 +34,32 @@ var gTestWindows = [
   "file_fullscreen-esc-context-menu.html",
   "file_fullscreen-esc-exit.html",
   "file_fullscreen-denied.html",
   "file_fullscreen-api.html",
   "file_fullscreen-api-keys.html",
   "file_fullscreen-plugins.html",
   "file_fullscreen-hidden.html",
   "file_fullscreen-svg-element.html",
-  "file_fullscreen-navigation.html"
+  "file_fullscreen-navigation.html",
+  "file_fullscreen-selector.html"
 ];
 
 var testWindow = null;
 var gTestIndex = 0;
 
 function finish() {
   SimpleTest.finish();
 }
 
 function nextTest() {
   if (testWindow) {
     testWindow.close();
   }
-  runNextTest();
+  SimpleTest.executeSoon(runNextTest);
 }
 
 function runNextTest() {
   if (gTestIndex < gTestWindows.length) {
     info("Run test " + gTestWindows[gTestIndex]);
     testWindow = window.open(gTestWindows[gTestIndex], "", "width=500,height=500");
     // We'll wait for the window to load, then make sure our window is refocused
     // before starting the test, which will get kicked off on "focus".
--- a/dom/interfaces/base/nsIDOMWindowUtils.idl
+++ b/dom/interfaces/base/nsIDOMWindowUtils.idl
@@ -814,21 +814,21 @@ interface nsIDOMWindowUtils : nsISupport
 
   /**
    * Trigger whichever GC or CC timer is currently active and waiting to fire.
    * Don't do this too much for initiating heavy actions, like the start of a IGC.
    */
   void runNextCollectorTimer();
 
   /** Synthesize a simple gesture event for a window. The event types
-   *  supported are: MozSwipeGestureStart, MozSwipeGestureUpdate,
-   *  MozSwipeGestureEnd, MozSwipeGesture, MozMagnifyGestureStart,
-   *  MozMagnifyGestureUpdate, MozMagnifyGesture, MozRotateGestureStart,
-   *  MozRotateGestureUpdate, MozRotateGesture, MozPressTapGesture,
-   *  MozTapGesture, and MozEdgeUIGesture.
+   *  supported are: MozSwipeGestureMayStart, MozSwipeGestureStart,
+   *  MozSwipeGestureUpdate, MozSwipeGestureEnd, MozSwipeGesture,
+   *  MozMagnifyGestureStart, MozMagnifyGestureUpdate, MozMagnifyGesture,
+   *  MozRotateGestureStart, MozRotateGestureUpdate, MozRotateGesture,
+   *  MozPressTapGesture, MozTapGesture, and MozEdgeUIGesture.
    *
    * Cannot be accessed from unprivileged context (not
    * content-accessible) Will throw a DOM security error if called
    * without chrome privileges.
    *
    * @param aType event type
    * @param aX x offset in CSS pixels
    * @param aY y offset in CSS pixels
--- a/dom/interfaces/events/nsIDOMSimpleGestureEvent.idl
+++ b/dom/interfaces/events/nsIDOMSimpleGestureEvent.idl
@@ -7,30 +7,35 @@
 #include "nsIDOMMouseEvent.idl"
 
 /**
  * The nsIDOMSimpleGestureEvent interface is the datatype for all
  * Mozilla-specific simple gesture events in the Document Object Model.
  *
  * The following events are generated:
  *
- * MozSwipeGestureStart - Generated when the user starts a horizontal
- * swipe across the input device.  This event not only acts as a signal,
- * but also asks two questions:  Should a swipe really be started, and
+ * MozSwipeGestureMayStart - Generated when the user starts a horizontal
+ * swipe across the input device, but before we know whether the user
+ * is actually scrolling past a scroll edge.
+ * This event asks two questions:  Should a swipe really be started, and
  * in which directions should the user be able to swipe?  The first
  * question is answered by event listeners by calling or not calling
  * preventDefault() on the event.  Since a swipe swallows all scroll
  * events, the default action of the swipe start event is *not* to
  * start a swipe. Call preventDefault() if you want a swipe to be
- * started.
+ * started. Doing so won't necessarily result in a swipe being started,
+ * it only communicates an intention. Once Gecko determines whether a
+ * swipe should actually be started, it will send a MozSwipeGestureStart
+ * event.
  * The second question (swipe-able directions) is answered in the
  * allowedDirections field.
- * If this event has preventDefault() called on it (and thus starts
- * a swipe), it guarantees a future MozSwipeGestureEnd event that
- * will signal the end of a swipe animation.
+ *
+ * MozSwipeGestureStart - This event signals the start of a swipe.
+ * It guarantees a future MozSwipeGestureEnd event that will signal
+ * the end of a swipe animation.
  *
  * MozSwipeGestureUpdate - Generated periodically while the user is
  * continuing a horizontal swipe gesture.  The "delta" value represents
  * the current absolute gesture amount.  This event may even be sent
  * after a MozSwipeGesture event fired in order to allow for fluid
  * completion of a swipe animation.  The direction value is meaningless
  * on swipe update events.
  *
@@ -112,24 +117,24 @@ interface nsIDOMSimpleGestureEvent : nsI
   const unsigned long ROTATION_COUNTERCLOCKWISE = 1;
   const unsigned long ROTATION_CLOCKWISE = 2;
 
   /* Read-write value for swipe events.
    *
    * Reports the directions that can be swiped to; multiple directions
    * should be OR'ed together.
    *
-   * The allowedDirections field is designed to be set on SwipeGestureStart
+   * The allowedDirections field is designed to be set on SwipeGestureMayStart
    * events by event listeners.  Its value after event dispatch determines
-   * the behavior of the swipe animation that is about to begin.
+   * the behavior of the swipe animation that might be about to begin.
    * Specifically, if the user swipes in a direction that can't be swiped
    * to, the animation will have a bounce effect.
    * Future SwipeGestureUpdate, SwipeGesture and SwipeGestureEnd events
-   * will carry the allowDirections value that was set on the SwipeStart
-   * event.  Changing this field on non-SwipeGestureStart events doesn't
+   * will carry the allowDirections value that was set on the SwipeMayStart
+   * event.  Changing this field on non-SwipeGestureMayStart events doesn't
    * have any effect.
    */
   attribute unsigned long allowedDirections;
 
   /* Direction of a gesture. Diagonals are indicated by OR'ing the
    * applicable constants together.
    *
    * Swipes gestures may occur in any direction.
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -28,18 +28,16 @@
 #include "mozilla/dom/ContentBridgeParent.h"
 #include "mozilla/dom/ContentParent.h"
 #include "mozilla/dom/DataTransfer.h"
 #include "mozilla/dom/DOMStorageIPC.h"
 #include "mozilla/dom/ExternalHelperAppChild.h"
 #include "mozilla/dom/PCrashReporterChild.h"
 #include "mozilla/dom/ProcessGlobal.h"
 #include "mozilla/dom/Promise.h"
-#include "mozilla/dom/asmjscache/AsmJSCache.h"
-#include "mozilla/dom/asmjscache/PAsmJSCacheEntryChild.h"
 #include "mozilla/dom/nsIContentChild.h"
 #include "mozilla/psm/PSMContentListener.h"
 #include "mozilla/hal_sandbox/PHalChild.h"
 #include "mozilla/ipc/BackgroundChild.h"
 #include "mozilla/ipc/FileDescriptorSetChild.h"
 #include "mozilla/ipc/FileDescriptorUtils.h"
 #include "mozilla/ipc/GeckoChildProcessHost.h"
 #include "mozilla/ipc/TestShellChild.h"
@@ -1462,33 +1460,16 @@ ContentChild::AllocPIccChild(const uint3
 bool
 ContentChild::DeallocPIccChild(PIccChild* aActor)
 {
     // IccChild is refcounted, must not be freed manually.
     static_cast<IccChild*>(aActor)->Release();
     return true;
 }
 
-asmjscache::PAsmJSCacheEntryChild*
-ContentChild::AllocPAsmJSCacheEntryChild(
-                                    const asmjscache::OpenMode& aOpenMode,
-                                    const asmjscache::WriteParams& aWriteParams,
-                                    const IPC::Principal& aPrincipal)
-{
-    NS_NOTREACHED("Should never get here!");
-    return nullptr;
-}
-
-bool
-ContentChild::DeallocPAsmJSCacheEntryChild(PAsmJSCacheEntryChild* aActor)
-{
-    asmjscache::DeallocEntryChild(aActor);
-    return true;
-}
-
 PTestShellChild*
 ContentChild::AllocPTestShellChild()
 {
     return new TestShellChild();
 }
 
 bool
 ContentChild::DeallocPTestShellChild(PTestShellChild* shell)
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -272,23 +272,16 @@ public:
     virtual PFMRadioChild* AllocPFMRadioChild() override;
     virtual bool DeallocPFMRadioChild(PFMRadioChild* aActor) override;
 
     virtual PPresentationChild* AllocPPresentationChild() override;
     virtual bool DeallocPPresentationChild(PPresentationChild* aActor) override;
     virtual bool RecvNotifyPresentationReceiverLaunched(PBrowserChild* aIframe,
                                                         const nsString& aSessionId) override;
 
-    virtual PAsmJSCacheEntryChild* AllocPAsmJSCacheEntryChild(
-                                 const asmjscache::OpenMode& aOpenMode,
-                                 const asmjscache::WriteParams& aWriteParams,
-                                 const IPC::Principal& aPrincipal) override;
-    virtual bool DeallocPAsmJSCacheEntryChild(
-                                    PAsmJSCacheEntryChild* aActor) override;
-
     virtual PSpeechSynthesisChild* AllocPSpeechSynthesisChild() override;
     virtual bool DeallocPSpeechSynthesisChild(PSpeechSynthesisChild* aActor) override;
 
     virtual bool RecvRegisterChrome(InfallibleTArray<ChromePackage>&& packages,
                                     InfallibleTArray<SubstitutionMapping>&& resources,
                                     InfallibleTArray<OverrideMapping>&& overrides,
                                     const nsCString& locale,
                                     const bool& reset) override;
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -44,17 +44,16 @@
 #include "mozilla/dom/GeolocationBinding.h"
 #include "mozilla/dom/NuwaParent.h"
 #include "mozilla/dom/PContentBridgeParent.h"
 #include "mozilla/dom/PContentPermissionRequestParent.h"
 #include "mozilla/dom/PCycleCollectWithLogsParent.h"
 #include "mozilla/dom/PFMRadioParent.h"
 #include "mozilla/dom/PMemoryReportRequestParent.h"
 #include "mozilla/dom/ServiceWorkerRegistrar.h"
-#include "mozilla/dom/asmjscache/AsmJSCache.h"
 #include "mozilla/dom/bluetooth/PBluetoothParent.h"
 #include "mozilla/dom/cellbroadcast/CellBroadcastParent.h"
 #include "mozilla/dom/devicestorage/DeviceStorageRequestParent.h"
 #include "mozilla/dom/icc/IccParent.h"
 #include "mozilla/dom/mobileconnection/MobileConnectionParent.h"
 #include "mozilla/dom/mobilemessage/SmsParent.h"
 #include "mozilla/dom/power/PowerManagerService.h"
 #include "mozilla/dom/PresentationParent.h"
@@ -3909,32 +3908,16 @@ ContentParent::DeallocPPresentationParen
 }
 
 bool
 ContentParent::RecvPPresentationConstructor(PPresentationParent* aActor)
 {
   return static_cast<PresentationParent*>(aActor)->Init();
 }
 
-asmjscache::PAsmJSCacheEntryParent*
-ContentParent::AllocPAsmJSCacheEntryParent(
-                                    const asmjscache::OpenMode& aOpenMode,
-                                    const asmjscache::WriteParams& aWriteParams,
-                                    const IPC::Principal& aPrincipal)
-{
-    return asmjscache::AllocEntryParent(aOpenMode, aWriteParams, aPrincipal);
-}
-
-bool
-ContentParent::DeallocPAsmJSCacheEntryParent(PAsmJSCacheEntryParent* aActor)
-{
-    asmjscache::DeallocEntryParent(aActor);
-    return true;
-}
-
 PSpeechSynthesisParent*
 ContentParent::AllocPSpeechSynthesisParent()
 {
 #ifdef MOZ_WEBSPEECH
     return new mozilla::dom::SpeechSynthesisParent();
 #else
     return nullptr;
 #endif
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -662,23 +662,16 @@ private:
 
     virtual PFMRadioParent* AllocPFMRadioParent() override;
     virtual bool DeallocPFMRadioParent(PFMRadioParent* aActor) override;
 
     virtual PPresentationParent* AllocPPresentationParent() override;
     virtual bool DeallocPPresentationParent(PPresentationParent* aActor) override;
     virtual bool RecvPPresentationConstructor(PPresentationParent* aActor) override;
 
-    virtual PAsmJSCacheEntryParent* AllocPAsmJSCacheEntryParent(
-                                 const asmjscache::OpenMode& aOpenMode,
-                                 const asmjscache::WriteParams& aWriteParams,
-                                 const IPC::Principal& aPrincipal) override;
-    virtual bool DeallocPAsmJSCacheEntryParent(
-                                   PAsmJSCacheEntryParent* aActor) override;
-
     virtual PSpeechSynthesisParent* AllocPSpeechSynthesisParent() override;
     virtual bool DeallocPSpeechSynthesisParent(PSpeechSynthesisParent* aActor) override;
     virtual bool RecvPSpeechSynthesisConstructor(PSpeechSynthesisParent* aActor) override;
 
     virtual bool RecvReadPrefsArray(InfallibleTArray<PrefSetting>* aPrefs) override;
     virtual bool RecvReadFontList(InfallibleTArray<FontListEntry>* retValue) override;
 
     virtual bool RecvReadPermissions(InfallibleTArray<IPC::Permission>* aPermissions) override;
--- a/dom/ipc/PBrowser.ipdl
+++ b/dom/ipc/PBrowser.ipdl
@@ -62,16 +62,17 @@ using mozilla::Modifiers from "mozilla/E
 using mozilla::layers::GeckoContentController::APZStateChange from "mozilla/layers/GeckoContentController.h";
 using mozilla::WritingMode from "mozilla/WritingModes.h";
 using mozilla::layers::TouchBehaviorFlags from "mozilla/layers/APZUtils.h";
 using nsIWidget::TouchPointerState from "nsIWidget.h";
 using struct LookAndFeelInt from "mozilla/widget/WidgetMessageUtils.h";
 using struct mozilla::OwningSerializedStructuredCloneBuffer from "ipc/IPCMessageUtils.h";
 using mozilla::EventMessage from "mozilla/EventForwards.h";
 using nsEventStatus from "mozilla/EventForwards.h";
+using nsSizeMode from "nsIWidgetListener.h";
 
 namespace mozilla {
 namespace dom {
 
 struct NativeKeyBinding
 {
   CommandInt[] singleLineCommands;
   CommandInt[] multiLineCommands;
@@ -470,16 +471,23 @@ parent:
      * Updates the zoom constraints for a scrollable frame in this tab.
      * The zoom controller code lives on the parent side and so this allows it to
      * have up-to-date zoom constraints.
      */
     UpdateZoomConstraints(uint32_t aPresShellId, ViewID aViewId,
                           MaybeZoomConstraints aConstraints);
 
     /**
+     * Tells the containing widget whether the given input block results in a
+     * swipe. Should be called in response to a WidgetWheelEvent that has
+     * mFlags.mCanTriggerSwipe set on it.
+     */
+    RespondStartSwipeEvent(uint64_t aInputBlockId, bool aStartSwipe);
+
+    /**
      * Brings up the auth prompt dialog.
      * Called when this is the PBrowserParent for a nested remote iframe.
      * aCallbackId corresponds to an nsIAuthPromptCallback that lives in the
      * root process.  It will be passed back to the root process with either the
      * OnAuthAvailable or OnAuthCancelled message.
      */
     AsyncAuthPrompt(nsCString uri, nsString realm, uint64_t aCallbackId);
 
@@ -574,17 +582,17 @@ child:
          uint64_t layersId,
          nullable PRenderFrame renderFrame,
          bool parentIsActive);
 
     LoadURL(nsCString uri, BrowserConfiguration config);
 
     CacheFileDescriptor(nsString path, FileDescriptor fd);
 
-    UpdateDimensions(CSSRect rect, CSSSize size,
+    UpdateDimensions(CSSRect rect, CSSSize size, nsSizeMode sizeMode,
                      ScreenOrientationInternal orientation,
                      LayoutDeviceIntPoint chromeDisp) compressall;
 
     UpdateFrame(FrameMetrics frame);
 
     // The following methods correspond to functions on the GeckoContentController
     // interface in gfx/layers/apz/public/GeckoContentController.h. Refer to documentation
     // in that file for these functions.
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -1,15 +1,14 @@
 /* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 8 -*- */
 /* vim: set sw=4 ts=8 et tw=80 ft=cpp : */
 /* 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 protocol PAsmJSCacheEntry;
 include protocol PBackground;
 include protocol PBlob;
 include protocol PBluetooth;
 include protocol PBrowser;
 include protocol PCellBroadcast;
 include protocol PCompositor;
 include protocol PContentBridge;
 include protocol PContentPermissionRequest;
@@ -76,18 +75,16 @@ using struct ChromePackage from "mozilla
 using struct SubstitutionMapping from "mozilla/chrome/RegistryMessageUtils.h";
 using struct OverrideMapping from "mozilla/chrome/RegistryMessageUtils.h";
 using base::ChildPrivileges from "base/process_util.h";
 using base::ProcessId from "base/process.h";
 using struct IPC::Permission from "mozilla/net/NeckoMessageUtils.h";
 using class IPC::Principal from "mozilla/dom/PermissionMessageUtils.h";
 using struct mozilla::null_t from "ipc/IPCMessageUtils.h";
 using struct mozilla::void_t from "ipc/IPCMessageUtils.h";
-using mozilla::dom::asmjscache::OpenMode from "mozilla/dom/asmjscache/AsmJSCache.h";
-using mozilla::dom::asmjscache::WriteParams from "mozilla/dom/asmjscache/AsmJSCache.h";
 using mozilla::dom::NativeThreadId from "mozilla/dom/TabMessageUtils.h";
 using mozilla::dom::quota::PersistenceType from "mozilla/dom/quota/PersistenceType.h";
 using mozilla::hal::ProcessPriority from "mozilla/HalTypes.h";
 using gfxIntSize from "nsSize.h";
 using mozilla::dom::TabId from "mozilla/dom/ipc/IdType.h";
 using mozilla::dom::ContentParentId from "mozilla/dom/ipc/IdType.h";
 using struct LookAndFeelInt from "mozilla/widget/WidgetMessageUtils.h";
 using struct mozilla::OwningSerializedStructuredCloneBuffer from "ipc/IPCMessageUtils.h";
@@ -416,17 +413,16 @@ prio(normal upto urgent) sync protocol P
 
     parent opens PCompositor;
     parent opens PProcessHangMonitor;
     parent opens PSharedBufferManager;
     parent opens PImageBridge;
     parent opens PGMPService;
     child opens PBackground;
 
-    manages PAsmJSCacheEntry;
     manages PBlob;
     manages PBluetooth;
     manages PBrowser;
     manages PCellBroadcast;
     manages PContentPermissionRequest;
     manages PCrashReporter;
     manages PCycleCollectWithLogs;
     manages PDeviceStorageRequest;
@@ -778,18 +774,16 @@ parent:
     PVoicemail();
 
     PMedia();
 
     PBluetooth();
 
     PFMRadio();
 
-    PAsmJSCacheEntry(OpenMode openMode, WriteParams write, Principal principal);
-
     PWebrtcGlobal();
     
     PPresentation();
 
     // Services remoting
 
     async StartVisitedQuery(URIParams uri);
     async VisitURI(URIParams uri, OptionalURIParams referrer, uint32_t flags);
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -1719,16 +1719,17 @@ TabChild::RecvShow(const ScreenIntSize& 
     ApplyShowInfo(aInfo);
     RecvParentActivated(aParentIsActive);
 
     return res;
 }
 
 bool
 TabChild::RecvUpdateDimensions(const CSSRect& rect, const CSSSize& size,
+                               const nsSizeMode& sizeMode,
                                const ScreenOrientationInternal& orientation,
                                const LayoutDeviceIntPoint& chromeDisp)
 {
     if (!mRemoteFrame) {
         return true;
     }
 
     mUnscaledOuterRect = rect;
@@ -1745,16 +1746,17 @@ TabChild::RecvUpdateDimensions(const CSS
 
     // Set the size on the document viewer before we update the widget and
     // trigger a reflow. Otherwise the MobileViewportManager reads the stale
     // size from the content viewer when it computes a new CSS viewport.
     nsCOMPtr<nsIBaseWindow> baseWin = do_QueryInterface(WebNavigation());
     baseWin->SetPositionAndSize(0, 0, screenSize.width, screenSize.height,
                                 true);
 
+    mPuppetWidget->SetSizeMode(sizeMode);
     mPuppetWidget->Resize(screenRect.x + chromeDisp.x,
                           screenRect.y + chromeDisp.y,
                           screenSize.width, screenSize.height, true);
 
     return true;
 }
 
 bool
@@ -1951,16 +1953,19 @@ TabChild::RecvMouseWheelEvent(const Widg
       mPuppetWidget, document, aEvent, aGuid, aInputBlockId);
   }
 
   WidgetWheelEvent event(aEvent);
   event.widget = mPuppetWidget;
   APZCCallbackHelper::DispatchWidgetEvent(event);
 
   if (aEvent.mFlags.mHandledByAPZ) {
+    if (event.mCanTriggerSwipe) {
+      SendRespondStartSwipeEvent(aInputBlockId, event.TriggersSwipe());
+    }
     mAPZEventState->ProcessWheelEvent(event, aGuid, aInputBlockId);
   }
   return true;
 }
 
 bool
 TabChild::RecvMouseScrollTestEvent(const FrameMetrics::ViewID& aScrollId, const nsString& aEvent)
 {
@@ -2050,21 +2055,21 @@ TabChild::UpdateTapState(const WidgetTou
         std::abs(currentPoint.y - mGestureDownPoint.y) > sDragThreshold.height) {
       CancelTapTracking();
     }
     return;
 
   case NS_TOUCH_END:
     if (!TouchManager::gPreventMouseEvents) {
       APZCCallbackHelper::DispatchSynthesizedMouseEvent(
-        NS_MOUSE_MOVE, time, currentPoint, 0, mPuppetWidget);
+        eMouseMove, time, currentPoint, 0, mPuppetWidget);
       APZCCallbackHelper::DispatchSynthesizedMouseEvent(
-        NS_MOUSE_BUTTON_DOWN, time, currentPoint, 0, mPuppetWidget);
+        eMouseDown, time, currentPoint, 0, mPuppetWidget);
       APZCCallbackHelper::DispatchSynthesizedMouseEvent(
-        NS_MOUSE_BUTTON_UP, time, currentPoint, 0, mPuppetWidget);
+        eMouseUp, time, currentPoint, 0, mPuppetWidget);
     }
     // fall through
   case NS_TOUCH_CANCEL:
     CancelTapTracking();
     return;
 
   default:
     NS_WARNING("Unknown touch event type");
@@ -2226,17 +2231,17 @@ TabChild::RecvNativeSynthesisResponse(co
 }
 
 bool
 TabChild::RecvRealKeyEvent(const WidgetKeyboardEvent& event,
                            const MaybeNativeKeyBinding& aBindings)
 {
   AutoCacheNativeKeyCommands autoCache(mPuppetWidget);
 
-  if (event.mMessage == NS_KEY_PRESS) {
+  if (event.mMessage == eKeyPress) {
     // If content code called preventDefault() on a keydown event, then we don't
     // want to process any following keypress events.
     if (mIgnoreKeyPressEvent) {
       return true;
     }
     if (aBindings.type() == MaybeNativeKeyBinding::TNativeKeyBinding) {
       const NativeKeyBinding& bindings = aBindings;
       autoCache.Cache(bindings.singleLineCommands(),
@@ -2246,17 +2251,17 @@ TabChild::RecvRealKeyEvent(const WidgetK
       autoCache.CacheNoCommands();
     }
   }
 
   WidgetKeyboardEvent localEvent(event);
   localEvent.widget = mPuppetWidget;
   nsEventStatus status = APZCCallbackHelper::DispatchWidgetEvent(localEvent);
 
-  if (event.mMessage == NS_KEY_DOWN) {
+  if (event.mMessage == eKeyDown) {
     mIgnoreKeyPressEvent = status == nsEventStatus_eConsumeNoDefault;
   }
 
   if (localEvent.mFlags.mWantReplyFromContentProcess) {
     SendReplyKeyEvent(localEvent);
   }
 
   if (PresShell::BeforeAfterKeyboardEventEnabled()) {
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -298,16 +298,17 @@ public:
     virtual bool RecvShow(const ScreenIntSize& aSize,
                           const ShowInfo& aInfo,
                           const TextureFactoryIdentifier& aTextureFactoryIdentifier,
                           const uint64_t& aLayersId,
                           PRenderFrameChild* aRenderFrame,
                           const bool& aParentIsActive) override;
     virtual bool RecvUpdateDimensions(const CSSRect& rect,
                                       const CSSSize& size,
+                                      const nsSizeMode& sizeMode,
                                       const ScreenOrientationInternal& orientation,
                                       const LayoutDeviceIntPoint& chromeDisp) override;
     virtual bool RecvUpdateFrame(const layers::FrameMetrics& aFrameMetrics) override;
     virtual bool RecvRequestFlingSnap(const ViewID& aScrollId,
                                       const CSSPoint& aDestination) override;
     virtual bool RecvAcknowledgeScrollUpdate(const ViewID& aScrollId,
                                              const uint32_t& aScrollGeneration) override;
     virtual bool RecvHandleDoubleTap(const CSSPoint& aPoint,
--- a/dom/ipc/TabMessageUtils.h
+++ b/dom/ipc/TabMessageUtils.h
@@ -90,11 +90,18 @@ struct ParamTraits<mozilla::dom::AudioCh
 
 template <>
 struct ParamTraits<nsEventStatus>
   : public ContiguousEnumSerializer<nsEventStatus,
                                     nsEventStatus_eIgnore,
                                     nsEventStatus_eSentinel>
 { };
 
+template<>
+struct ParamTraits<nsSizeMode>
+  : public ContiguousEnumSerializer<nsSizeMode,
+                                    nsSizeMode_Normal,
+                                    nsSizeMode_Invalid>
+{ };
+
 } // namespace IPC
 
 #endif
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -1054,17 +1054,19 @@ TabParent::UpdateDimensions(const nsIntR
       ViewAs<LayoutDevicePixel>(mRect,
                                 PixelCastJustification::LayoutDeviceIsScreenForTabDims);
     LayoutDeviceIntSize devicePixelSize =
       ViewAs<LayoutDevicePixel>(mDimensions.ToUnknownSize(),
                                 PixelCastJustification::LayoutDeviceIsScreenForTabDims);
 
     CSSRect unscaledRect = devicePixelRect / widgetScale;
     CSSSize unscaledSize = devicePixelSize / widgetScale;
-    unused << SendUpdateDimensions(unscaledRect, unscaledSize, orientation, chromeOffset);
+    unused << SendUpdateDimensions(unscaledRect, unscaledSize,
+                                   widget->SizeMode(),
+                                   orientation, chromeOffset);
   }
 }
 
 void
 TabParent::UpdateFrame(const FrameMetrics& aFrameMetrics)
 {
   if (!mIsDestroyed) {
     unused << SendUpdateFrame(aFrameMetrics);
@@ -1378,29 +1380,29 @@ bool TabParent::SendRealMouseEvent(Widge
     return false;
   }
   event.refPoint += GetChildProcessOffset();
 
   nsCOMPtr<nsIWidget> widget = GetWidget();
   if (widget) {
     // When we mouseenter the tab, the tab's cursor should
     // become the current cursor.  When we mouseexit, we stop.
-    if (NS_MOUSE_ENTER_WIDGET == event.mMessage) {
+    if (eMouseEnterIntoWidget == event.mMessage) {
       mTabSetsCursor = true;
       if (mCustomCursor) {
         widget->SetCursor(mCustomCursor, mCustomCursorHotspotX, mCustomCursorHotspotY);
       } else if (mCursor != nsCursor(-1)) {
         widget->SetCursor(mCursor);
       }
-    } else if (NS_MOUSE_EXIT_WIDGET == event.mMessage) {
+    } else if (eMouseExitFromWidget == event.mMessage) {
       mTabSetsCursor = false;
     }
   }
 
-  if (NS_MOUSE_MOVE == event.mMessage) {
+  if (eMouseMove == event.mMessage) {
     if (event.reason == WidgetMouseEvent::eSynthesized) {
       return SendSynthMouseMoveEvent(event);
     } else {
       return SendRealMouseMoveEvent(event);
     }
   }
   return SendRealMouseButtonEvent(event);
 }
@@ -1736,17 +1738,17 @@ bool TabParent::SendRealKeyEvent(WidgetK
 {
   if (mIsDestroyed) {
     return false;
   }
   event.refPoint += GetChildProcessOffset();
 
   MaybeNativeKeyBinding bindings;
   bindings = void_t();
-  if (event.mMessage == NS_KEY_PRESS) {
+  if (event.mMessage == eKeyPress) {
     nsCOMPtr<nsIWidget> widget = GetWidget();
 
     AutoInfallibleTArray<mozilla::CommandInt, 4> singleLine;
     AutoInfallibleTArray<mozilla::CommandInt, 4> multiLine;
     AutoInfallibleTArray<mozilla::CommandInt, 4> richText;
 
     widget->ExecuteNativeKeyBinding(nsIWidget::NativeKeyBindingsForSingleLineEditor,
                                     event, DoCommandCallback, &singleLine);
@@ -2277,17 +2279,17 @@ TabParent::RecvDispatchAfterKeyboardEven
   localEvent.widget = GetWidget();
 
   nsIDocument* doc = mFrameElement->OwnerDoc();
   nsCOMPtr<nsIPresShell> presShell = doc->GetShell();
   NS_ENSURE_TRUE(presShell, true);
 
   if (mFrameElement &&
       PresShell::BeforeAfterKeyboardEventEnabled() &&
-      localEvent.mMessage != NS_KEY_PRESS) {
+      localEvent.mMessage != eKeyPress) {
     presShell->DispatchAfterKeyboardEvent(mFrameElement, localEvent,
                                           aEvent.mFlags.mDefaultPrevented);
   }
 
   return true;
 }
 
 bool
@@ -2845,16 +2847,26 @@ TabParent::RecvUpdateZoomConstraints(con
 {
   if (RenderFrameParent* rfp = GetRenderFrame()) {
     rfp->UpdateZoomConstraints(aPresShellId, aViewId, aConstraints);
   }
   return true;
 }
 
 bool
+TabParent::RecvRespondStartSwipeEvent(const uint64_t& aInputBlockId,
+                                      const bool& aStartSwipe)
+{
+  if (nsCOMPtr<nsIWidget> widget = GetWidget()) {
+    widget->ReportSwipeStarted(aInputBlockId, aStartSwipe);
+  }
+  return true;
+}
+
+bool
 TabParent::RecvContentReceivedInputBlock(const ScrollableLayerGuid& aGuid,
                                          const uint64_t& aInputBlockId,
                                          const bool& aPreventDefault)
 {
   if (RenderFrameParent* rfp = GetRenderFrame()) {
     rfp->ContentReceivedInputBlock(aGuid, aInputBlockId, aPreventDefault);
   }
   return true;
--- a/dom/ipc/TabParent.h
+++ b/dom/ipc/TabParent.h
@@ -224,16 +224,18 @@ public:
     virtual bool RecvSetNativeChildOfShareableWindow(const uintptr_t& childWindow) override;
     virtual bool RecvDispatchFocusToTopLevelWindow() override;
     virtual bool RecvZoomToRect(const uint32_t& aPresShellId,
                                 const ViewID& aViewId,
                                 const CSSRect& aRect) override;
     virtual bool RecvUpdateZoomConstraints(const uint32_t& aPresShellId,
                                            const ViewID& aViewId,
                                            const MaybeZoomConstraints& aConstraints) override;
+    virtual bool RecvRespondStartSwipeEvent(const uint64_t& aInputBlockId,
+                                            const bool& aStartSwipe) override;
     virtual bool RecvContentReceivedInputBlock(const ScrollableLayerGuid& aGuid,
                                                const uint64_t& aInputBlockId,
                                                const bool& aPreventDefault) override;
     virtual bool RecvSetTargetAPZC(const uint64_t& aInputBlockId,
                                    nsTArray<ScrollableLayerGuid>&& aTargets) override;
     virtual bool RecvSetAllowedTouchBehavior(const uint64_t& aInputBlockId,
                                              nsTArray<TouchBehaviorFlags>&& aTargets) override;
     virtual bool RecvDispatchWheelEvent(const mozilla::WidgetWheelEvent& aEvent) override;
--- a/dom/media/MediaFormatReader.cpp
+++ b/dom/media/MediaFormatReader.cpp
@@ -660,17 +660,16 @@ MediaFormatReader::RequestVideoData(bool
 
   if (mShutdown) {
     NS_WARNING("RequestVideoData on shutdown MediaFormatReader!");
     return VideoDataPromise::CreateAndReject(CANCELED, __func__);
   }
 
   media::TimeUnit timeThreshold{media::TimeUnit::FromMicroseconds(aTimeThreshold)};
   if (ShouldSkip(aSkipToNextKeyframe, timeThreshold)) {
-    mVideo.mDecodingRequested = false;
     Flush(TrackInfo::kVideoTrack);
     nsRefPtr<VideoDataPromise> p = mVideo.mPromise.Ensure(__func__);
     SkipVideoDemuxToNextKeyFrame(timeThreshold);
     return p;
   }
 
   nsRefPtr<VideoDataPromise> p = mVideo.mPromise.Ensure(__func__);
   NotifyDecodingRequested(TrackInfo::kVideoTrack);
@@ -1021,29 +1020,29 @@ MediaFormatReader::DecodeDemuxedSamples(
       decoder.mLastStreamSourceID = info->GetID();
       // Flush will clear our array of queued samples. So make a copy now.
       nsTArray<nsRefPtr<MediaRawData>> samples{decoder.mQueuedSamples};
       Flush(aTrack);
       decoder.mDecoder->Shutdown();
       decoder.mDecoder = nullptr;
       if (sample->mKeyframe) {
         decoder.mQueuedSamples.AppendElements(Move(samples));
-        ScheduleUpdate(aTrack);
+        NotifyDecodingRequested(aTrack);
       } else {
         MOZ_ASSERT(decoder.mTimeThreshold.isNothing());
         LOG("Stream change occurred on a non-keyframe. Seeking to:%lld",
             sample->mTime);
         decoder.mTimeThreshold = Some(TimeUnit::FromMicroseconds(sample->mTime));
         nsRefPtr<MediaFormatReader> self = this;
         decoder.mSeekRequest.Begin(decoder.mTrackDemuxer->Seek(decoder.mTimeThreshold.ref())
                    ->Then(OwnerThread(), __func__,
                           [self, aTrack] (media::TimeUnit aTime) {
                             auto& decoder = self->GetDecoderData(aTrack);
                             decoder.mSeekRequest.Complete();
-                            self->ScheduleUpdate(aTrack);
+                            self->NotifyDecodingRequested(aTrack);
                           },
                           [self, aTrack] (DemuxerFailureReason aResult) {
                             auto& decoder = self->GetDecoderData(aTrack);
                             decoder.mSeekRequest.Complete();
                             switch (aResult) {
                               case DemuxerFailureReason::WAITING_FOR_DATA:
                                 self->NotifyWaitingForData(aTrack);
                                 break;
--- a/dom/media/MediaFormatReader.h
+++ b/dom/media/MediaFormatReader.h
@@ -284,16 +284,17 @@ private:
     void ResetState()
     {
       MOZ_ASSERT(mOwner->OnTaskQueue());
       mDemuxEOS = false;
       mWaitingForData = false;
       mReceivedNewData = false;
       mDiscontinuity = true;
       mQueuedSamples.Clear();
+      mDecodingRequested = false;
       mOutputRequested = false;
       mInputExhausted = false;
       mNeedDraining = false;
       mDraining = false;
       mDrainComplete = false;
       mTimeThreshold.reset();
       mOutput.Clear();
       mNumSamplesInput = 0;
--- a/dom/media/MediaResource.h
+++ b/dom/media/MediaResource.h
@@ -20,17 +20,21 @@
 #include "mozilla/Attributes.h"
 #include "mozilla/TimeStamp.h"
 #include "nsThreadUtils.h"
 #include <algorithm>
 
 // For HTTP seeking, if number of bytes needing to be
 // seeked forward is less than this value then a read is
 // done rather than a byte range request.
-static const int64_t SEEK_VS_READ_THRESHOLD = 32*1024;
+//
+// If we assume a 100Mbit connection, and assume reissuing an HTTP seek causes
+// a delay of 200ms, then in that 200ms we could have simply read ahead 2MB. So
+// setting SEEK_VS_READ_THRESHOLD to 1MB sounds reasonable.
+static const int64_t SEEK_VS_READ_THRESHOLD = 1 * 1024 * 1024;
 
 static const uint32_t HTTP_REQUESTED_RANGE_NOT_SATISFIABLE_CODE = 416;
 
 // Number of bytes we have accumulated before we assume the connection download
 // rate can be reliably calculated. 57 Segments at IW=3 allows slow start to
 // reach a CWND of 30 (See bug 831998)
 static const int64_t RELIABLE_DATA_THRESHOLD = 57 * 1460;
 
--- a/dom/media/mediasource/TrackBuffersManager.cpp
+++ b/dom/media/mediasource/TrackBuffersManager.cpp
@@ -92,17 +92,17 @@ private:
 
 TrackBuffersManager::TrackBuffersManager(dom::SourceBufferAttributes* aAttributes,
                                          MediaSourceDecoder* aParentDecoder,
                                          const nsACString& aType)
   : mInputBuffer(new MediaByteBuffer)
   , mAppendState(AppendState::WAITING_FOR_SEGMENT)
   , mBufferFull(false)
   , mFirstInitializationSegmentReceived(false)
-  , mNewSegmentStarted(false)
+  , mNewMediaSegmentStarted(false)
   , mActiveTrack(false)
   , mType(aType)
   , mParser(ContainerParser::CreateForMIMEType(aType))
   , mProcessedInput(0)
   , mAppendRunning(false)
   , mTaskQueue(aParentDecoder->GetDemuxer()->GetTaskQueue())
   , mSourceBufferAttributes(aAttributes)
   , mParentDecoder(new nsMainThreadPtrHolder<MediaSourceDecoder>(aParentDecoder, false /* strict */))
@@ -651,22 +651,21 @@ TrackBuffersManager::SegmentParserLoop()
     // steps:
     if (mAppendState == AppendState::WAITING_FOR_SEGMENT) {
       if (mParser->IsInitSegmentPresent(mInputBuffer)) {
         SetAppendState(AppendState::PARSING_INIT_SEGMENT);
         if (mFirstInitializationSegmentReceived) {
           // This is a new initialization segment. Obsolete the old one.
           RecreateParser(false);
         }
-        mNewSegmentStarted = true;
         continue;
       }
       if (mParser->IsMediaSegmentPresent(mInputBuffer)) {
         SetAppendState(AppendState::PARSING_MEDIA_SEGMENT);
-        mNewSegmentStarted = true;
+        mNewMediaSegmentStarted = true;
         continue;
       }
       // We have neither an init segment nor a media segment, this is either
       // invalid data or not enough data to detect a segment type.
       MSE_DEBUG("Found invalid or incomplete data.");
       NeedMoreData();
       return;
     }
@@ -687,37 +686,50 @@ TrackBuffersManager::SegmentParserLoop()
       return;
     }
     if (mAppendState == AppendState::PARSING_MEDIA_SEGMENT) {
       // 1. If the first initialization segment received flag is false, then run the append error algorithm with the decode error parameter set to true and abort this algorithm.
       if (!mFirstInitializationSegmentReceived) {
         RejectAppend(NS_ERROR_FAILURE, __func__);
         return;
       }
-      // 2. If the input buffer does not contain a complete media segment header yet, then jump to the need more data step below.
-      if (mParser->MediaHeaderRange().IsNull()) {
-        AppendDataToCurrentInputBuffer(mInputBuffer);
-        mInputBuffer = nullptr;
-        NeedMoreData();
-        return;
-      }
 
       // We can't feed some demuxers (WebMDemuxer) with data that do not have
       // monotonizally increasing timestamps. So we check if we have a
       // discontinuity from the previous segment parsed.
       // If so, recreate a new demuxer to ensure that the demuxer is only fed
       // monotonically increasing data.
-      if (newData) {
-        if (mNewSegmentStarted && mLastParsedEndTime.isSome() &&
+      if (mNewMediaSegmentStarted) {
+        if (newData && mLastParsedEndTime.isSome() &&
             start < mLastParsedEndTime.ref().ToMicroseconds()) {
+          MSE_DEBUG("Re-creating demuxer");
           ResetDemuxingState();
           return;
         }
-        mNewSegmentStarted = false;
-        mLastParsedEndTime = Some(TimeUnit::FromMicroseconds(end));
+        if (newData || !mParser->MediaSegmentRange().IsNull()) {
+          if (mPendingInputBuffer) {
+            // We now have a complete media segment header. We can resume parsing
+            // the data.
+            AppendDataToCurrentInputBuffer(mPendingInputBuffer);
+            mPendingInputBuffer = nullptr;
+          }
+          mNewMediaSegmentStarted = false;
+        } else {
+          // We don't have any data to demux yet, stash aside the data.
+          // This also handles the case:
+          // 2. If the input buffer does not contain a complete media segment header yet, then jump to the need more data step below.
+          if (!mPendingInputBuffer) {
+            mPendingInputBuffer = mInputBuffer;
+          } else {
+            mPendingInputBuffer->AppendElements(*mInputBuffer);
+          }
+          mInputBuffer = nullptr;
+          NeedMoreData();
+          return;
+        }
       }
 
       // 3. If the input buffer contains one or more complete coded frames, then run the coded frame processing algorithm.
       nsRefPtr<TrackBuffersManager> self = this;
       mProcessingRequest.Begin(CodedFrameProcessing()
           ->Then(GetTaskQueue(), __func__,
                  [self] (bool aNeedMoreData) {
                    self->mProcessingRequest.Complete();
@@ -844,16 +856,24 @@ TrackBuffersManager::OnDemuxerResetDone(
 
   uint32_t numAudios = mInputDemuxer->GetNumberTracks(TrackInfo::kAudioTrack);
   if (numAudios) {
     // We currently only handle the first audio track.
     mAudioTracks.mDemuxer = mInputDemuxer->GetTrackDemuxer(TrackInfo::kAudioTrack, 0);
     MOZ_ASSERT(mAudioTracks.mDemuxer);
   }
 
+  if (mPendingInputBuffer) {
+    // We had a partial media segment header stashed aside.
+    // Reparse its content so we can continue parsing the current input buffer.
+    int64_t start, end;
+    mParser->ParseStartAndEndTimestamps(mPendingInputBuffer, start, end);
+    mProcessedInput += mPendingInputBuffer->Length();
+  }
+
   SegmentParserLoop();
 }
 
 void
 TrackBuffersManager::AppendDataToCurrentInputBuffer(MediaByteBuffer* aData)
 {
   MOZ_ASSERT(mCurrentInputBuffer);
   int64_t offset = mCurrentInputBuffer->GetLength();
@@ -1288,16 +1308,19 @@ TrackBuffersManager::CompleteCodedFrameP
   }
 
   // 5. If the input buffer does not contain a complete media segment, then jump to the need more data step below.
   if (mParser->MediaSegmentRange().IsNull()) {
     ResolveProcessing(true, __func__);
     return;
   }
 
+  mLastParsedEndTime = Some(std::max(mAudioTracks.mLastParsedEndTime,
+                                     mVideoTracks.mLastParsedEndTime));
+
   // 6. Remove the media segment bytes from the beginning of the input buffer.
   // Clear our demuxer from any already processed data.
   // As we have handled a complete media segment, it is safe to evict all data
   // from the resource.
   mCurrentInputBuffer->EvictAll();
   mInputDemuxer->NotifyDataRemoved();
   RecreateParser(true);
 
@@ -1367,26 +1390,36 @@ TrackBuffersManager::ProcessFrames(Track
   TrackBuffer samples; // array that will contain the frames to be added
                        // to our track buffer.
 
   // We assume that no frames are contiguous within a media segment and as such
   // don't need to check for discontinuity except for the first frame and should
   // a frame be ignored due to the target window.
   bool needDiscontinuityCheck = true;
 
+  if (aSamples.Length()) {
+    aTrackData.mLastParsedEndTime = TimeUnit();
+  }
+
   for (auto& sample : aSamples) {
     SAMPLE_DEBUG("Processing %s frame(pts:%lld end:%lld, dts:%lld, duration:%lld, "
                "kf:%d)",
                aTrackData.mInfo->mMimeType.get(),
                sample->mTime,
                sample->GetEndTime(),
                sample->mTimecode,
                sample->mDuration,
                sample->mKeyframe);
 
+    const TimeUnit sampleEndTime =
+      TimeUnit::FromMicroseconds(sample->GetEndTime());
+    if (sampleEndTime > aTrackData.mLastParsedEndTime) {
+      aTrackData.mLastParsedEndTime = sampleEndTime;
+    }
+
     // We perform step 10 right away as we can't do anything should a keyframe
     // be needed until we have one.
 
     // 10. If the need random access point flag on track buffer equals true, then run the following steps:
     if (trackBuffer.mNeedRandomAccessPoint) {
       // 1. If the coded frame is not a random access point, then drop the coded frame and jump to the top of the loop to start processing the next coded frame.
       if (!sample->mKeyframe) {
         continue;
--- a/dom/media/mediasource/TrackBuffersManager.h
+++ b/dom/media/mediasource/TrackBuffersManager.h
@@ -148,33 +148,38 @@ private:
   // Accessed on both the main thread and the task queue.
   Atomic<AppendState> mAppendState;
   // Buffer full flag as per https://w3c.github.io/media-source/#sourcebuffer-buffer-full-flag.
   // Accessed on both the main thread and the task queue.
   // TODO: Unused for now.
   Atomic<bool> mBufferFull;
   bool mFirstInitializationSegmentReceived;
   // Set to true once a new segment is started.
-  bool mNewSegmentStarted;
+  bool mNewMediaSegmentStarted;
   bool mActiveTrack;
   Maybe<media::TimeUnit> mGroupStartTimestamp;
   media::TimeUnit mGroupEndTimestamp;
   nsCString mType;
 
   // ContainerParser objects and methods.
   // Those are used to parse the incoming input buffer.
 
   // Recreate the ContainerParser and if aReuseInitData is true then
   // feed it with the previous init segment found.
   void RecreateParser(bool aReuseInitData);
   nsAutoPtr<ContainerParser> mParser;
 
   // Demuxer objects and methods.
   void AppendDataToCurrentInputBuffer(MediaByteBuffer* aData);
   nsRefPtr<MediaByteBuffer> mInitData;
+  // Temporary input buffer to handle partial media segment header.
+  // We store the current input buffer content into it should we need to
+  // reinitialize the demuxer once we have some samples and a discontinuity is
+  // detected.
+  nsRefPtr<MediaByteBuffer> mPendingInputBuffer;
   nsRefPtr<SourceBufferResource> mCurrentInputBuffer;
   nsRefPtr<MediaDataDemuxer> mInputDemuxer;
   // Length already processed in current media segment.
   uint32_t mProcessedInput;
   Maybe<media::TimeUnit> mLastParsedEndTime;
 
   void OnDemuxerInitDone(nsresult);
   void OnDemuxerInitFailed(DemuxerFailureReason aFailure);
@@ -230,16 +235,19 @@ private:
     // Need random access point flag variable that keeps track of whether the
     // track buffer is waiting for a random access point coded frame.
     // The variable is initially set to true to indicate that random access
     // point coded frame is needed before anything can be added to the track
     // buffer.
     bool mNeedRandomAccessPoint;
     nsRefPtr<MediaTrackDemuxer> mDemuxer;
     MozPromiseRequestHolder<MediaTrackDemuxer::SamplesPromise> mDemuxRequest;
+    // Highest end timestamp of the last media segment demuxed.
+    media::TimeUnit mLastParsedEndTime;
+
     // If set, position where the next contiguous frame will be inserted.
     // If a discontinuity is detected, it will be unset and recalculated upon
     // the next insertion.
     Maybe<size_t> mNextInsertionIndex;
     // Samples just demuxed, but not yet parsed.
     TrackBuffer mQueuedSamples;
     // We only manage a single track of each type at this time.
     nsTArray<TrackBuffer> mBuffers;
--- a/dom/media/mediasource/test/mochitest.ini
+++ b/dom/media/mediasource/test/mochitest.ini
@@ -33,16 +33,17 @@ support-files =
   bipbop/bipbop11.m4s^headers^ bipbop/bipbop_audio11.m4s^headers^ bipbop/bipbop_video11.m4s^headers^
   bipbop/bipbop12.m4s^headers^ bipbop/bipbop_video12.m4s^headers^
   bipbop/bipbop13.m4s^headers^ bipbop/bipbop_video13.m4s^headers^
 
 [test_BufferedSeek.html]
 [test_BufferedSeek_mp4.html]
 skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac")) # Only supported on osx and vista+
 [test_BufferingWait.html]
+skip-if = toolkit == 'android' #timeout android bug 1199531
 [test_BufferingWait_mp4.html]
 skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac") || (os == "win" && os_version == "6.1")) # Only supported on osx and vista+, disabling on win7 bug 1191138
 [test_EndOfStream.html]
 skip-if = (true || toolkit == 'android' || buildapp == 'mulet') #timeout android/mulet only bug 1101187 and bug 1182946
 [test_EndOfStream_mp4.html]
 skip-if = (toolkit == 'android' || buildapp == 'mulet') || ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac")) # Only supported on osx and vista+
 [test_DurationUpdated.html]
 [test_DurationUpdated_mp4.html]
--- a/dom/media/tests/mochitest/mochitest.ini
+++ b/dom/media/tests/mochitest/mochitest.ini
@@ -67,19 +67,19 @@ skip-if = toolkit == 'gonk' # B2G emulat
 skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
 [test_peerConnection_basicAudioVideo.html]
 skip-if = toolkit == 'gonk' || buildapp == 'mulet' || (android_version == '18' && debug) # b2g(Bug 960442, video support for WebRTC is disabled on b2g), android(Bug 1189784, timeouts on 4.3 emulator)
 [test_peerConnection_basicAudioVideoCombined.html]
 skip-if = toolkit == 'gonk' || buildapp == 'mulet' || (android_version == '18' && debug) # b2g(Bug 960442, video support for WebRTC is disabled on b2g), android(Bug 1189784, timeouts on 4.3 emulator)
 [test_peerConnection_basicAudioVideoNoBundle.html]
 skip-if = toolkit == 'gonk' || buildapp == 'mulet' || (android_version == '18' && debug) # b2g(Bug 960442, video support for WebRTC is disabled on b2g), android(Bug 1189784, timeouts on 4.3 emulator)
 [test_peerConnection_basicAudioVideoNoBundleNoRtcpMux.html]
-skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
+skip-if = toolkit == 'gonk' || buildapp == 'mulet' || android_version == '18' # b2g(Bug 960442, video support for WebRTC is disabled on b2g), android(Bug 1189784, timeouts on 4.3 emulator)
 [test_peerConnection_basicAudioVideoNoRtcpMux.html]
-skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
+skip-if = toolkit == 'gonk' || buildapp == 'mulet' || android_version == '18' # b2g(Bug 960442, video support for WebRTC is disabled on b2g), android(Bug 1189784, timeouts on 4.3 emulator)
 [test_peerConnection_basicVideo.html]
 skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
 [test_peerConnection_basicScreenshare.html]
 # no screenshare on b2g/android
 # frequent timeouts/crashes on e10s (bug 1048455)
 skip-if = buildapp == 'b2g' || buildapp == 'mulet' || toolkit == 'android' || e10s # Bug 1141029 Mulet parity with B2G Desktop for TC
 [test_peerConnection_basicWindowshare.html]
 # no screenshare on b2g/android
@@ -165,17 +165,17 @@ skip-if = toolkit == 'gonk' # B2G emulat
 [test_peerConnection_answererAddSecondAudioStream.html]
 skip-if = toolkit == 'gonk' # B2G emulator is too slow to finish a renegotiation test in under 5 minutes
 [test_peerConnection_removeAudioTrack.html]
 skip-if = toolkit == 'gonk' || (android_version == '18' && debug) # B2G emulator is too slow to finish a renegotiation test in under 5 minutes, android(Bug 1189784, timeouts on 4.3 emulator)
 [test_peerConnection_removeThenAddAudioTrack.html]
 skip-if = toolkit == 'gonk' || (android_version == '18' && debug) # B2G emulator is too slow to finish a renegotiation test in under 5 minutes, android(Bug 1189784, timeouts on 4.3 emulator)
 [test_peerConnection_addSecondVideoStream.html]
 # B2G emulator is too slow to finish a renegotiation test in under 5 minutes, Bug 1180000 for Linux debug e10s, android(Bug 1189784, timeouts on 4.3 emulator)
-skip-if = toolkit == 'gonk' || (os == 'linux' && debug && e10s) || (android_version == '18' && debug)
+skip-if = toolkit == 'gonk' || (os == 'linux' && debug && e10s) || android_version == '18'
 [test_peerConnection_removeVideoTrack.html]
 # B2G emulator is too slow to finish a renegotiation test in under 5 minutes, Bug 1180000 for Linux debug e10s, android(Bug 1189784, timeouts on 4.3 emulator)
 skip-if = toolkit == 'gonk' || (os == 'linux' && debug && e10s) || (android_version == '18' && debug)
 [test_peerConnection_removeThenAddVideoTrack.html]
 # B2G emulator is too slow to finish a renegotiation test in under 5 minutes, Bug 1180000 for Linux debug e10s, android(Bug 1189784, timeouts on 4.3 emulator)
 skip-if = toolkit == 'gonk' || (os == 'linux' && debug && e10s) || (android_version == '18' && debug)
 [test_peerConnection_replaceVideoThenRenegotiate.html]
 # B2G emulator is too slow to finish a renegotiation test in under 5 minutes, Bug 1180000 for Linux debug e10s, android(Bug 1189784, timeouts on 4.3 emulator)
--- a/dom/plugins/base/nsPluginInstanceOwner.cpp
+++ b/dom/plugins/base/nsPluginInstanceOwner.cpp
@@ -1678,17 +1678,17 @@ nsresult nsPluginInstanceOwner::Dispatch
   if (mouseEvent && mouseEvent->mClass == eMouseEventClass) {
     nsEventStatus rv = ProcessEvent(*mouseEvent);
     if (nsEventStatus_eConsumeNoDefault == rv) {
       aMouseEvent->PreventDefault();
       if (!aAllowPropagate) {
         aMouseEvent->StopPropagation();
       }
     }
-    if (mouseEvent->mMessage == NS_MOUSE_BUTTON_UP) {
+    if (mouseEvent->mMessage == eMouseUp) {
       mLastMouseDownButtonType = -1;
     }
   }
   return NS_OK;
 }
 
 nsresult
 nsPluginInstanceOwner::HandleEvent(nsIDOMEvent* aEvent)
@@ -1803,38 +1803,37 @@ static NPCocoaEventType
 CocoaEventTypeForEvent(const WidgetGUIEvent& anEvent, nsIFrame* aObjectFrame)
 {
   const NPCocoaEvent* event = static_cast<const NPCocoaEvent*>(anEvent.mPluginEvent);
   if (event) {
     return event->type;
   }
 
   switch (anEvent.mMessage) {
-    case NS_MOUSE_OVER:
+    case eMouseOver:
       return NPCocoaEventMouseEntered;
-    case NS_MOUSE_OUT:
+    case eMouseOut:
       return NPCocoaEventMouseExited;
-    case NS_MOUSE_MOVE:
-    {
+    case eMouseMove: {
       // We don't know via information on events from the widget code whether or not
       // we're dragging. The widget code just generates mouse move events from native
       // drag events. If anybody is capturing, this is a drag event.
       if (nsIPresShell::GetCapturingContent()) {
         return NPCocoaEventMouseDragged;
       }
 
       return NPCocoaEventMouseMoved;
     }
-    case NS_MOUSE_BUTTON_DOWN:
+    case eMouseDown:
       return NPCocoaEventMouseDown;
-    case NS_MOUSE_BUTTON_UP:
+    case eMouseUp:
       return NPCocoaEventMouseUp;
-    case NS_KEY_DOWN:
+    case eKeyDown:
       return NPCocoaEventKeyDown;
-    case NS_KEY_UP:
+    case eKeyUp:
       return NPCocoaEventKeyUp;
     case NS_FOCUS_CONTENT:
     case NS_BLUR_CONTENT:
       return NPCocoaEventFocusChanged;
     case NS_MOUSE_SCROLL:
       return NPCocoaEventScrollWheel;
     default:
       return (NPCocoaEventType)0;
@@ -1843,41 +1842,40 @@ CocoaEventTypeForEvent(const WidgetGUIEv
 
 static NPCocoaEvent
 TranslateToNPCocoaEvent(WidgetGUIEvent* anEvent, nsIFrame* aObjectFrame)
 {
   NPCocoaEvent cocoaEvent;
   InitializeNPCocoaEvent(&cocoaEvent);
   cocoaEvent.type = CocoaEventTypeForEvent(*anEvent, aObjectFrame);
 
-  if (anEvent->mMessage == NS_MOUSE_MOVE ||
-      anEvent->mMessage == NS_MOUSE_BUTTON_DOWN ||
-      anEvent->mMessage == NS_MOUSE_BUTTON_UP ||
+  if (anEvent->mMessage == eMouseMove ||
+      anEvent->mMessage == eMouseDown ||
+      anEvent->mMessage == eMouseUp ||
       anEvent->mMessage == NS_MOUSE_SCROLL ||
-      anEvent->mMessage == NS_MOUSE_OVER ||
-      anEvent->mMessage == NS_MOUSE_OUT)
+      anEvent->mMessage == eMouseOver ||
+      anEvent->mMessage == eMouseOut)
   {
     nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(anEvent, aObjectFrame) -
                  aObjectFrame->GetContentRectRelativeToSelf().TopLeft();
     nsPresContext* presContext = aObjectFrame->PresContext();
     // Plugin event coordinates need to be translated from device pixels
     // into "display pixels" in HiDPI modes.
     double scaleFactor = double(nsPresContext::AppUnitsPerCSSPixel())/
       aObjectFrame->PresContext()->DeviceContext()->AppUnitsPerDevPixelAtUnitFullZoom();
     size_t intScaleFactor = ceil(scaleFactor);
     nsIntPoint ptPx(presContext->AppUnitsToDevPixels(pt.x) / intScaleFactor,
                     presContext->AppUnitsToDevPixels(pt.y) / intScaleFactor);
     cocoaEvent.data.mouse.pluginX = double(ptPx.x);
     cocoaEvent.data.mouse.pluginY = double(ptPx.y);
   }
 
   switch (anEvent->mMessage) {
-    case NS_MOUSE_BUTTON_DOWN:
-    case NS_MOUSE_BUTTON_UP:
-    {
+    case eMouseDown:
+    case eMouseUp: {
       WidgetMouseEvent* mouseEvent = anEvent->AsMouseEvent();
       if (mouseEvent) {
         switch (mouseEvent->button) {
           case WidgetMouseEvent::eLeftButton:
             cocoaEvent.data.mouse.buttonNumber = 0;
             break;
           case WidgetMouseEvent::eRightButton:
             cocoaEvent.data.mouse.buttonNumber = 1;
@@ -1885,39 +1883,39 @@ TranslateToNPCocoaEvent(WidgetGUIEvent* 
           case WidgetMouseEvent::eMiddleButton:
             cocoaEvent.data.mouse.buttonNumber = 2;
             break;
           default:
             NS_WARNING("Mouse button we don't know about?");
         }
         cocoaEvent.data.mouse.clickCount = mouseEvent->clickCount;
       } else {
-        NS_WARNING("NS_MOUSE_BUTTON_UP/DOWN is not a WidgetMouseEvent?");
+        NS_WARNING("eMouseUp/DOWN is not a WidgetMouseEvent?");
       }
       break;
     }
     case NS_MOUSE_SCROLL:
     {
       WidgetWheelEvent* wheelEvent = anEvent->AsWheelEvent();
       if (wheelEvent) {
         cocoaEvent.data.mouse.deltaX = wheelEvent->lineOrPageDeltaX;
         cocoaEvent.data.mouse.deltaY = wheelEvent->lineOrPageDeltaY;
       } else {
         NS_WARNING("NS_MOUSE_SCROLL is not a WidgetWheelEvent? (could be, haven't checked)");
       }
       break;
     }
-    case NS_KEY_DOWN:
-    case NS_KEY_UP:
+    case eKeyDown:
+    case eKeyUp:
     {
       WidgetKeyboardEvent* keyEvent = anEvent->AsKeyboardEvent();
 
       // That keyEvent->mPluginTextEventString is non-empty is a signal that we should
       // create a text event for the plugin, instead of a key event.
-      if (anEvent->mMessage == NS_KEY_DOWN &&
+      if (anEvent->mMessage == eKeyDown &&
           !keyEvent->mPluginTextEventString.IsEmpty()) {
         cocoaEvent.type = NPCocoaEventTextInput;
         const char16_t* pluginTextEventString = keyEvent->mPluginTextEventString.get();
         cocoaEvent.data.text.text = (NPNSString*)
           ::CFStringCreateWithCharacters(NULL,
                                          reinterpret_cast<const UniChar*>(pluginTextEventString),
                                          keyEvent->mPluginTextEventString.Length());
       } else {
@@ -2037,17 +2035,17 @@ nsEventStatus nsPluginInstanceOwner::Pro
         textEvent.type = NPCocoaEventTextInput;
         textEvent.data.text.text = (NPNSString*)cfString;
         mInstance->HandleEvent(&textEvent, nullptr);
       }
     }
   }
 
   bool handled = (response == kNPEventHandled || response == kNPEventStartIME);
-  bool leftMouseButtonDown = (anEvent.mMessage == NS_MOUSE_BUTTON_DOWN) &&
+  bool leftMouseButtonDown = (anEvent.mMessage == eMouseDown) &&
                              (anEvent.AsMouseEvent()->button == WidgetMouseEvent::eLeftButton);
   if (handled && !(leftMouseButtonDown && !mContentFocused)) {
     rv = nsEventStatus_eConsumeNoDefault;
   }
 #endif
 
 #ifdef XP_WIN
   // this code supports windowless plugins
@@ -2057,38 +2055,38 @@ nsEventStatus nsPluginInstanceOwner::Pro
   NPEvent pluginEvent;
   if (anEvent.mClass == eMouseEventClass) {
     if (!pPluginEvent) {
       // XXX Should extend this list to synthesize events for more event
       // types
       pluginEvent.event = 0;
       const WidgetMouseEvent* mouseEvent = anEvent.AsMouseEvent();
       switch (anEvent.mMessage) {
-      case NS_MOUSE_MOVE:
+      case eMouseMove:
         pluginEvent.event = WM_MOUSEMOVE;
         break;
-      case NS_MOUSE_BUTTON_DOWN: {
+      case eMouseDown: {
         static const int downMsgs[] =
           { WM_LBUTTONDOWN, WM_MBUTTONDOWN, WM_RBUTTONDOWN };
         static const int dblClickMsgs[] =
           { WM_LBUTTONDBLCLK, WM_MBUTTONDBLCLK, WM_RBUTTONDBLCLK };
         if (mouseEvent->clickCount == 2) {
           pluginEvent.event = dblClickMsgs[mouseEvent->button];
         } else {
           pluginEvent.event = downMsgs[mouseEvent->button];
         }
         break;
       }
-      case NS_MOUSE_BUTTON_UP: {
+      case eMouseUp: {
         static const int upMsgs[] =
           { WM_LBUTTONUP, WM_MBUTTONUP, WM_RBUTTONUP };
         pluginEvent.event = upMsgs[mouseEvent->button];
         break;
       }
-      // don't synthesize anything for NS_MOUSE_DOUBLECLICK, since that
+      // don't synthesize anything for eMouseDoubleClick, since that
       // is a synthetic event generated on mouse-up, and Windows WM_*DBLCLK
       // messages are sent on mouse-down
       default:
         break;
       }
       if (pluginEvent.event) {
         pPluginEvent = &pluginEvent;
         pluginEvent.wParam =
@@ -2101,22 +2099,22 @@ nsEventStatus nsPluginInstanceOwner::Pro
           (::GetKeyState(VK_XBUTTON2) ? MK_XBUTTON2 : 0);
       }
     }
     if (pPluginEvent) {
       // Make event coordinates relative to our enclosing widget,
       // not the widget they were received on.
       // See use of NPEvent in widget/windows/nsWindow.cpp
       // for why this assert should be safe
-      NS_ASSERTION(anEvent.mMessage == NS_MOUSE_BUTTON_DOWN ||
-                   anEvent.mMessage == NS_MOUSE_BUTTON_UP ||
-                   anEvent.mMessage == NS_MOUSE_DOUBLECLICK ||
-                   anEvent.mMessage == NS_MOUSE_OVER ||
-                   anEvent.mMessage == NS_MOUSE_OUT ||
-                   anEvent.mMessage == NS_MOUSE_MOVE,
+      NS_ASSERTION(anEvent.mMessage == eMouseDown ||
+                   anEvent.mMessage == eMouseUp ||
+                   anEvent.mMessage == eMouseDoubleClick ||
+                   anEvent.mMessage == eMouseOver ||
+                   anEvent.mMessage == eMouseOut ||
+                   anEvent.mMessage == eMouseMove,
                    "Incorrect event type for coordinate translation");
       nsPoint pt =
         nsLayoutUtils::GetEventCoordinatesRelativeTo(&anEvent, mPluginFrame) -
         mPluginFrame->GetContentRectRelativeToSelf().TopLeft();
       nsPresContext* presContext = mPluginFrame->PresContext();
       nsIntPoint ptPx(presContext->AppUnitsToDevPixels(pt.x),
                       presContext->AppUnitsToDevPixels(pt.y));
       nsIntPoint widgetPtPx = ptPx + mPluginFrame->GetWindowOriginInPixels(true);
@@ -2162,20 +2160,19 @@ nsEventStatus nsPluginInstanceOwner::Pro
   // this code supports windowless plugins
   nsIWidget* widget = anEvent.widget;
   XEvent pluginEvent = XEvent();
   pluginEvent.type = 0;
 
   switch(anEvent.mClass) {
     case eMouseEventClass:
       {
-        switch (anEvent.mMessage)
-          {
-          case NS_MOUSE_CLICK:
-          case NS_MOUSE_DOUBLECLICK:
+        switch (anEvent.mMessage) {
+          case eMouseClick:
+          case eMouseDoubleClick:
             // Button up/down events sent instead.
             return rv;
           default:
             break;
           }
 
         // Get reference point relative to plugin origin.
         const nsPresContext* presContext = mPluginFrame->PresContext();
@@ -2192,61 +2189,60 @@ nsEventStatus nsPluginInstanceOwner::Pro
 #ifdef MOZ_WIDGET_GTK
         Window root = GDK_ROOT_WINDOW();
 #elif defined(MOZ_WIDGET_QT)
         Window root = RootWindowOfScreen(DefaultScreenOfDisplay(mozilla::DefaultXDisplay()));
 #else
         Window root = None; // Could XQueryTree, but this is not important.
 #endif
 
-        switch (anEvent.mMessage)
-          {
-          case NS_MOUSE_OVER:
-          case NS_MOUSE_OUT:
+        switch (anEvent.mMessage) {
+          case eMouseOver:
+          case eMouseOut:
             {
               XCrossingEvent& event = pluginEvent.xcrossing;
-              event.type = anEvent.mMessage == NS_MOUSE_OVER ?
+              event.type = anEvent.mMessage == eMouseOver ?
                 EnterNotify : LeaveNotify;
               event.root = root;
               event.time = anEvent.time;
               event.x = pluginPoint.x;
               event.y = pluginPoint.y;
               event.x_root = rootPoint.x;
               event.y_root = rootPoint.y;
               event.state = XInputEventState(mouseEvent);
               // information lost
               event.subwindow = None;
               event.mode = -1;
               event.detail = NotifyDetailNone;
               event.same_screen = True;
               event.focus = mContentFocused;
             }
             break;
-          case NS_MOUSE_MOVE:
+          case eMouseMove:
             {
               XMotionEvent& event = pluginEvent.xmotion;
               event.type = MotionNotify;
               event.root = root;
               event.time = anEvent.time;
               event.x = pluginPoint.x;
               event.y = pluginPoint.y;
               event.x_root = rootPoint.x;
               event.y_root = rootPoint.y;
               event.state = XInputEventState(mouseEvent);
               // information lost
               event.subwindow = None;
               event.is_hint = NotifyNormal;
               event.same_screen = True;
             }
             break;
-          case NS_MOUSE_BUTTON_DOWN:
-          case NS_MOUSE_BUTTON_UP:
+          case eMouseDown:
+          case eMouseUp:
             {
               XButtonEvent& event = pluginEvent.xbutton;
-              event.type = anEvent.mMessage == NS_MOUSE_BUTTON_DOWN ?
+              event.type = anEvent.mMessage == eMouseDown ?
                 ButtonPress : ButtonRelease;
               event.root = root;
               event.time = anEvent.time;
               event.x = pluginPoint.x;
               event.y = pluginPoint.y;
               event.x_root = rootPoint.x;
               event.y_root = rootPoint.y;
               event.state = XInputEventState(mouseEvent);
@@ -2283,26 +2279,26 @@ nsEventStatus nsPluginInstanceOwner::Pro
           event.root = GDK_ROOT_WINDOW();
           event.time = anEvent.time;
           const GdkEventKey* gdkEvent =
             static_cast<const GdkEventKey*>(anEvent.mPluginEvent);
           event.keycode = gdkEvent->hardware_keycode;
           event.state = gdkEvent->state;
           switch (anEvent.mMessage)
             {
-            case NS_KEY_DOWN:
-              // Handle NS_KEY_DOWN for modifier key presses
-              // For non-modifiers we get NS_KEY_PRESS
+            case eKeyDown:
+              // Handle eKeyDown for modifier key presses
+              // For non-modifiers we get eKeyPress
               if (gdkEvent->is_modifier)
                 event.type = XKeyPress;
               break;
-            case NS_KEY_PRESS:
+            case eKeyPress:
               event.type = XKeyPress;
               break;
-            case NS_KEY_UP:
+            case eKeyUp:
               event.type = KeyRelease;
               break;
             default:
               break;
             }
 #endif
 
           // Information that could be obtained from pluginEvent but we may not
@@ -2369,55 +2365,53 @@ nsEventStatus nsPluginInstanceOwner::Pro
     if (fm) {
       nsCOMPtr<nsIDOMElement> elem = do_QueryReferent(mContent);
       fm->SetFocus(elem, 0);
     }
   }
   switch(anEvent.mClass) {
     case eMouseEventClass:
       {
-        switch (anEvent.mMessage)
-          {
-          case NS_MOUSE_CLICK:
-          case NS_MOUSE_DOUBLECLICK:
+        switch (anEvent.mMessage) {
+          case eMouseClick:
+          case eMouseDoubleClick:
             // Button up/down events sent instead.
             return rv;
           default:
             break;
           }
 
         // Get reference point relative to plugin origin.
         const nsPresContext* presContext = mPluginFrame->PresContext();
         nsPoint appPoint =
           nsLayoutUtils::GetEventCoordinatesRelativeTo(&anEvent, mPluginFrame) -
           mPluginFrame->GetContentRectRelativeToSelf().TopLeft();
         nsIntPoint pluginPoint(presContext->AppUnitsToDevPixels(appPoint.x),
                                presContext->AppUnitsToDevPixels(appPoint.y));
 
-        switch (anEvent.mMessage)
-          {
-          case NS_MOUSE_MOVE:
+        switch (anEvent.mMessage) {
+          case eMouseMove:
             {
               // are these going to be touch events?
               // pluginPoint.x;
               // pluginPoint.y;
             }
             break;
-          case NS_MOUSE_BUTTON_DOWN:
+          case eMouseDown:
             {
               ANPEvent event;
               event.inSize = sizeof(ANPEvent);
               event.eventType = kMouse_ANPEventType;
               event.data.mouse.action = kDown_ANPMouseAction;
               event.data.mouse.x = pluginPoint.x;
               event.data.mouse.y = pluginPoint.y;
               mInstance->HandleEvent(&event, nullptr, NS_PLUGIN_CALL_SAFE_TO_REENTER_GECKO);
             }
             break;
-          case NS_MOUSE_BUTTON_UP:
+          case eMouseUp:
             {
               ANPEvent event;
               event.inSize = sizeof(ANPEvent);
               event.eventType = kMouse_ANPEventType;
               event.data.mouse.action = kUp_ANPMouseAction;
               event.data.mouse.x = pluginPoint.x;
               event.data.mouse.y = pluginPoint.y;
               mInstance->HandleEvent(&event, nullptr, NS_PLUGIN_CALL_SAFE_TO_REENTER_GECKO);
--- a/dom/plugins/base/nsPluginNativeWindowWin.cpp
+++ b/dom/plugins/base/nsPluginNativeWindowWin.cpp
@@ -191,17 +191,17 @@ static LRESULT CALLBACK PluginWndProc(HW
  * to rip out.
  */
 static LRESULT CALLBACK PluginWndProcInternal(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
 {
   nsPluginNativeWindowWin * win = (nsPluginNativeWindowWin *)::GetProp(hWnd, NS_PLUGIN_WINDOW_PROPERTY_ASSOCIATION);
   if (!win)
     return TRUE;
 
-  // The DispatchEvent(NS_PLUGIN_ACTIVATE) below can trigger a reentrant focus
+  // The DispatchEvent(ePluginActivate) below can trigger a reentrant focus
   // event which might destroy us.  Hold a strong ref on the plugin instance
   // to prevent that, bug 374229.
   nsRefPtr<nsNPAPIPluginInstance> inst;
   win->GetPluginInstance(inst);
 
   // Real may go into a state where it recursivly dispatches the same event
   // when subclassed. If this is Real, lets examine the event and drop it
   // on the floor if we get into this recursive situation. See bug 192914.
@@ -266,17 +266,17 @@ static LRESULT CALLBACK PluginWndProcInt
         // window in the child process receives focus via a mouse click.
         // WM_MOUSEACTIVATE is sent by nsWindow via a custom window event
         // sent from PluginInstanceParent in response to focus events sent
         // from the child. (bug 540052) Note, this gui event could also be
         // sent directly from widget.
         nsCOMPtr<nsIWidget> widget;
         win->GetPluginWidget(getter_AddRefs(widget));
         if (widget) {
-          WidgetGUIEvent event(true, NS_PLUGIN_ACTIVATE, widget);
+          WidgetGUIEvent event(true, ePluginActivate, widget);
           nsEventStatus status;
           widget->DispatchEvent(&event, status);
         }
       }
     }
     break;
 
     case WM_SETFOCUS:
--- a/dom/plugins/ipc/PluginAsyncSurrogate.cpp
+++ b/dom/plugins/ipc/PluginAsyncSurrogate.cpp
@@ -560,16 +560,20 @@ PluginAsyncSurrogate::NotifyAsyncInitFai
     // Clean up any pending NewStream requests
     for (uint32_t i = 0, len = mPendingNewStreamCalls.Length(); i < len; ++i) {
       PendingNewStreamCall& curPendingCall = mPendingNewStreamCalls[i];
       DestroyAsyncStream(curPendingCall.mStream);
     }
   }
   mPendingNewStreamCalls.Clear();
 
+  // Make sure that any WaitForInit calls on this surrogate will fail, or else
+  // we'll be perma-blocked
+  mInitCancelled = true;
+
   nsNPAPIPluginInstance* inst =
     static_cast<nsNPAPIPluginInstance*>(mInstance->ndata);
   if (!inst) {
       return;
   }
   nsPluginInstanceOwner* owner = inst->GetOwner();
   MOZ_ASSERT(owner);
   owner->NotifyHostAsyncInitFailed();
--- a/dom/security/nsCORSListenerProxy.cpp
+++ b/dom/security/nsCORSListenerProxy.cpp
@@ -407,17 +407,18 @@ nsPreflightCache::GetCacheKey(nsIURI* aU
   return true;
 }
 
 //////////////////////////////////////////////////////////////////////////
 // nsCORSListenerProxy
 
 NS_IMPL_ISUPPORTS(nsCORSListenerProxy, nsIStreamListener,
                   nsIRequestObserver, nsIChannelEventSink,
-                  nsIInterfaceRequestor, nsIAsyncVerifyRedirectCallback)
+                  nsIInterfaceRequestor, nsIAsyncVerifyRedirectCallback,
+                  nsIThreadRetargetableStreamListener)
 
 /* static */
 void
 nsCORSListenerProxy::Startup()
 {
   Preferences::AddBoolVarCache(&gDisableCORS,
                                "content.cors.disable");
   Preferences::AddBoolVarCache(&gDisableCORSPrivateData,
@@ -670,21 +671,25 @@ nsCORSListenerProxy::OnStopRequest(nsIRe
   mRedirectCallback = nullptr;
   mOldRedirectChannel = nullptr;
   mNewRedirectChannel = nullptr;
   return rv;
 }
 
 NS_IMETHODIMP
 nsCORSListenerProxy::OnDataAvailable(nsIRequest* aRequest,
-                                     nsISupports* aContext, 
+                                     nsISupports* aContext,
                                      nsIInputStream* aInputStream,
                                      uint64_t aOffset,
                                      uint32_t aCount)
 {
+  // NB: This can be called on any thread!  But we're guaranteed that it is
+  // called between OnStartRequest and OnStopRequest, so we don't need to worry
+  // about races.
+
   MOZ_ASSERT(mInited, "nsCORSListenerProxy has not been initialized properly");
   if (!mRequestApproved) {
     return NS_ERROR_DOM_BAD_URI;
   }
   return mOuterListener->OnDataAvailable(aRequest, aContext, aInputStream,
                                          aOffset, aCount);
 }
 
@@ -821,16 +826,29 @@ nsCORSListenerProxy::OnRedirectVerifyCal
 
   mOldRedirectChannel = nullptr;
   mNewRedirectChannel = nullptr;
   mRedirectCallback->OnRedirectVerifyCallback(result);
   mRedirectCallback   = nullptr;
   return NS_OK;
 }
 
+NS_IMETHODIMP
+nsCORSListenerProxy::CheckListenerChain()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  if (nsCOMPtr<nsIThreadRetargetableStreamListener> retargetableListener =
+        do_QueryInterface(mOuterListener)) {
+    return retargetableListener->CheckListenerChain();
+  }
+
+  return NS_ERROR_NO_INTERFACE;
+}
+
 // Please note that the CSP directive 'upgrade-insecure-requests' relies
 // on the promise that channels get updated from http: to https: before
 // the channel fetches any data from the netwerk. Such channels should
 // not be blocked by CORS and marked as cross origin requests. E.g.:
 // toplevel page: https://www.example.com loads
 //           xhr: http://www.example.com/foo which gets updated to
 //                https://www.example.com/foo
 // In such a case we should bail out of CORS and rely on the promise that
@@ -1258,17 +1276,16 @@ nsCORSPreflightListener::AsyncOnChannelR
 }
 
 NS_IMETHODIMP
 nsCORSPreflightListener::GetInterface(const nsIID & aIID, void **aResult)
 {
   return QueryInterface(aIID, aResult);
 }
 
-
 nsresult
 NS_StartCORSPreflight(nsIChannel* aRequestChannel,
                       nsIStreamListener* aListener,
                       nsIPrincipal* aPrincipal,
                       bool aWithCredentials,
                       nsTArray<nsCString>& aUnsafeHeaders,
                       nsIChannel** aPreflightChannel)
 {
--- a/dom/security/nsCORSListenerProxy.h
+++ b/dom/security/nsCORSListenerProxy.h
@@ -11,16 +11,17 @@
 #include "nsIInterfaceRequestor.h"
 #include "nsCOMPtr.h"
 #include "nsString.h"
 #include "nsIURI.h"
 #include "nsTArray.h"
 #include "nsIInterfaceRequestor.h"
 #include "nsIChannelEventSink.h"
 #include "nsIAsyncVerifyRedirectCallback.h"
+#include "nsIThreadRetargetableStreamListener.h"
 #include "mozilla/Attributes.h"
 
 class nsIURI;
 class nsIPrincipal;
 class nsINetworkInterceptController;
 
 nsresult
 NS_StartCORSPreflight(nsIChannel* aRequestChannel,
@@ -34,17 +35,18 @@ enum class DataURIHandling
 {
   Allow,
   Disallow
 };
 
 class nsCORSListenerProxy final : public nsIStreamListener,
                                   public nsIInterfaceRequestor,
                                   public nsIChannelEventSink,
-                                  public nsIAsyncVerifyRedirectCallback
+                                  public nsIAsyncVerifyRedirectCallback,
+                                  public nsIThreadRetargetableStreamListener
 {
 public:
   nsCORSListenerProxy(nsIStreamListener* aOuter,
                       nsIPrincipal* aRequestingPrincipal,
                       bool aWithCredentials);
   nsCORSListenerProxy(nsIStreamListener* aOuter,
                       nsIPrincipal* aRequestingPrincipal,
                       bool aWithCredentials,
@@ -52,16 +54,17 @@ public:
                       const nsTArray<nsCString>& aPreflightHeaders);
 
   NS_DECL_ISUPPORTS
   NS_DECL_NSIREQUESTOBSERVER
   NS_DECL_NSISTREAMLISTENER
   NS_DECL_NSIINTERFACEREQUESTOR
   NS_DECL_NSICHANNELEVENTSINK
   NS_DECL_NSIASYNCVERIFYREDIRECTCALLBACK
+  NS_DECL_NSITHREADRETARGETABLESTREAMLISTENER
 
   // Must be called at startup.
   static void Startup();
 
   static void Shutdown();
 
   nsresult Init(nsIChannel* aChannel, DataURIHandling aAllowDataURI);
 
--- a/dom/smil/TimeEvent.cpp
+++ b/dom/smil/TimeEvent.cpp
@@ -12,17 +12,17 @@
 
 namespace mozilla {
 namespace dom {
 
 TimeEvent::TimeEvent(EventTarget* aOwner,
                      nsPresContext* aPresContext,
                      InternalSMILTimeEvent* aEvent)
   : Event(aOwner, aPresContext,
-          aEvent ? aEvent : new InternalSMILTimeEvent(false, NS_EVENT_NULL))
+          aEvent ? aEvent : new InternalSMILTimeEvent(false, eVoidEvent))
   , mDetail(mEvent->AsSMILTimeEvent()->detail)
 {
   if (aEvent) {
     mEventIsInternal = false;
   } else {
     mEventIsInternal = true;
   }
 
--- a/dom/xul/nsXULElement.cpp
+++ b/dom/xul/nsXULElement.cpp
@@ -1260,18 +1260,18 @@ nsXULElement::List(FILE* out, int32_t aI
 #endif
 
 nsresult
 nsXULElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
 {
     aVisitor.mForceContentDispatch = true; //FIXME! Bug 329119
     if (IsRootOfNativeAnonymousSubtree() &&
         (IsAnyOfXULElements(nsGkAtoms::scrollbar, nsGkAtoms::scrollcorner)) &&
-        (aVisitor.mEvent->mMessage == NS_MOUSE_CLICK ||
-         aVisitor.mEvent->mMessage == NS_MOUSE_DOUBLECLICK ||
+        (aVisitor.mEvent->mMessage == eMouseClick ||
+         aVisitor.mEvent->mMessage == eMouseDoubleClick ||
          aVisitor.mEvent->mMessage == NS_XUL_COMMAND ||
          aVisitor.mEvent->mMessage == NS_CONTEXTMENU ||
          aVisitor.mEvent->mMessage == NS_DRAGDROP_START ||
          aVisitor.mEvent->mMessage == NS_DRAGDROP_GESTURE)) {
         // Don't propagate these events from native anonymous scrollbar.
         aVisitor.mCanHandle = true;
         aVisitor.mParentTarget = nullptr;
         return NS_OK;
@@ -1735,21 +1735,21 @@ nsXULElement::ClickWithInputSource(uint1
     if (doc) {
         nsCOMPtr<nsIPresShell> shell = doc->GetShell();
         if (shell) {
             // strong ref to PresContext so events don't destroy it
             nsRefPtr<nsPresContext> context = shell->GetPresContext();
 
             bool isCallerChrome = nsContentUtils::IsCallerChrome();
 
-            WidgetMouseEvent eventDown(isCallerChrome, NS_MOUSE_BUTTON_DOWN,
+            WidgetMouseEvent eventDown(isCallerChrome, eMouseDown,
                                        nullptr, WidgetMouseEvent::eReal);
-            WidgetMouseEvent eventUp(isCallerChrome, NS_MOUSE_BUTTON_UP,
+            WidgetMouseEvent eventUp(isCallerChrome, eMouseUp,
                                      nullptr, WidgetMouseEvent::eReal);
-            WidgetMouseEvent eventClick(isCallerChrome, NS_MOUSE_CLICK, nullptr,
+            WidgetMouseEvent eventClick(isCallerChrome, eMouseClick, nullptr,
                                         WidgetMouseEvent::eReal);
             eventDown.inputSource = eventUp.inputSource = eventClick.inputSource
                                   = aInputSource;
 
             // send mouse down
             nsEventStatus status = nsEventStatus_eIgnore;
             EventDispatcher::Dispatch(static_cast<nsIContent*>(this),
                                       context, &eventDown,  nullptr, &status);
--- a/editor/libeditor/nsEditor.cpp
+++ b/editor/libeditor/nsEditor.cpp
@@ -4690,17 +4690,17 @@ nsEditor::HandleKeyPressEvent(nsIDOMKeyE
   //   * editor/libeditor/tests/test_htmleditor_keyevent_handling.html
   //
   // And also when you add new key handling, you need to change the subclass's
   // HandleKeyPressEvent()'s switch statement.
 
   WidgetKeyboardEvent* nativeKeyEvent =
     aKeyEvent->GetInternalNSEvent()->AsKeyboardEvent();
   NS_ENSURE_TRUE(nativeKeyEvent, NS_ERROR_UNEXPECTED);
-  NS_ASSERTION(nativeKeyEvent->mMessage == NS_KEY_PRESS,
+  NS_ASSERTION(nativeKeyEvent->mMessage == eKeyPress,
                "HandleKeyPressEvent gets non-keypress event");
 
   // if we are readonly or disabled, then do nothing.
   if (IsReadonly() || IsDisabled()) {
     // consume backspace for disabled and readonly textfields, to prevent
     // back in history, which could be confusing to users
     if (nativeKeyEvent->keyCode == nsIDOMKeyEvent::DOM_VK_BACK_SPACE) {
       aKeyEvent->PreventDefault();
--- a/editor/libeditor/nsEditorEventListener.cpp
+++ b/editor/libeditor/nsEditorEventListener.cpp
@@ -387,66 +387,66 @@ nsEditorEventListener::HandleEvent(nsIDO
     }
     // drop
     case NS_DRAGDROP_DROP: {
       nsCOMPtr<nsIDOMDragEvent> dragEvent = do_QueryInterface(aEvent);
       return Drop(dragEvent);
     }
 #ifdef HANDLE_NATIVE_TEXT_DIRECTION_SWITCH
     // keydown
-    case NS_KEY_DOWN: {
+    case eKeyDown: {
       nsCOMPtr<nsIDOMKeyEvent> keyEvent = do_QueryInterface(aEvent);
       return KeyDown(keyEvent);
     }
     // keyup
-    case NS_KEY_UP: {
+    case eKeyUp: {
       nsCOMPtr<nsIDOMKeyEvent> keyEvent = do_QueryInterface(aEvent);
       return KeyUp(keyEvent);
     }
 #endif // #ifdef HANDLE_NATIVE_TEXT_DIRECTION_SWITCH
     // keypress
-    case NS_KEY_PRESS: {
+    case eKeyPress: {
       nsCOMPtr<nsIDOMKeyEvent> keyEvent = do_QueryInterface(aEvent);
       return KeyPress(keyEvent);
     }
     // mousedown
-    case NS_MOUSE_BUTTON_DOWN: {
+    case eMouseDown: {
       nsCOMPtr<nsIDOMMouseEvent> mouseEvent = do_QueryInterface(aEvent);
       NS_ENSURE_TRUE(mouseEvent, NS_OK);
       // nsEditorEventListener may receive (1) all mousedown, mouseup and click
       // events, (2) only mousedown event or (3) only mouseup event.
       // mMouseDownOrUpConsumedByIME is used only for ignoring click event if
       // preceding mousedown and/or mouseup event is consumed by IME.
       // Therefore, even if case #2 or case #3 occurs,
       // mMouseDownOrUpConsumedByIME is true here.  Therefore, we should always
       // overwrite it here.
       mMouseDownOrUpConsumedByIME = NotifyIMEOfMouseButtonEvent(mouseEvent);
       return mMouseDownOrUpConsumedByIME ? NS_OK : MouseDown(mouseEvent);
     }
     // mouseup
-    case NS_MOUSE_BUTTON_UP: {
+    case eMouseUp: {
       nsCOMPtr<nsIDOMMouseEvent> mouseEvent = do_QueryInterface(aEvent);
       NS_ENSURE_TRUE(mouseEvent, NS_OK);
-      // See above comment in the NS_MOUSE_BUTTON_DOWN case, first.
+      // See above comment in the eMouseDown case, first.
       // This code assumes that case #1 is occuring.  However, if case #3 may
       // occurs after case #2 and the mousedown is consumed,
       // mMouseDownOrUpConsumedByIME is true even though nsEditorEventListener
       // has not received the preceding mousedown event of this mouseup event.
       // So, mMouseDownOrUpConsumedByIME may be invalid here.  However,
       // this is not a matter because mMouseDownOrUpConsumedByIME is referred
-      // only by NS_MOUSE_CLICK case but click event is fired only in case #1.
+      // only by eMouseClick case but click event is fired only in case #1.
       // So, before a click event is fired, mMouseDownOrUpConsumedByIME is
-      // always initialized in the NS_MOUSE_BUTTON_DOWN case if it's referred.
+      // always initialized in the eMouseDown case if it's referred.
       if (NotifyIMEOfMouseButtonEvent(mouseEvent)) {
         mMouseDownOrUpConsumedByIME = true;
       }
       return mMouseDownOrUpConsumedByIME ? NS_OK : MouseUp(mouseEvent);
     }
     // click
-    case NS_MOUSE_CLICK: {
+    case eMouseClick: {
       nsCOMPtr<nsIDOMMouseEvent> mouseEvent = do_QueryInterface(aEvent);
       NS_ENSURE_TRUE(mouseEvent, NS_OK);
       // If the preceding mousedown event or mouseup event was consumed,
       // editor shouldn't handle this click event.
       if (mMouseDownOrUpConsumedByIME) {
         mMouseDownOrUpConsumedByIME = false;
         mouseEvent->PreventDefault();
         return NS_OK;
--- a/editor/libeditor/nsHTMLEditor.cpp
+++ b/editor/libeditor/nsHTMLEditor.cpp
@@ -589,17 +589,17 @@ nsHTMLEditor::HandleKeyPressEvent(nsIDOM
     // When we're not editable, the events are handled on nsEditor, so, we can
     // bypass nsPlaintextEditor.
     return nsEditor::HandleKeyPressEvent(aKeyEvent);
   }
 
   WidgetKeyboardEvent* nativeKeyEvent =
     aKeyEvent->GetInternalNSEvent()->AsKeyboardEvent();
   NS_ENSURE_TRUE(nativeKeyEvent, NS_ERROR_UNEXPECTED);
-  NS_ASSERTION(nativeKeyEvent->mMessage == NS_KEY_PRESS,
+  NS_ASSERTION(nativeKeyEvent->mMessage == eKeyPress,
                "HandleKeyPressEvent gets non-keypress event");
 
   switch (nativeKeyEvent->keyCode) {
     case nsIDOMKeyEvent::DOM_VK_META:
     case nsIDOMKeyEvent::DOM_VK_WIN:
     case nsIDOMKeyEvent::DOM_VK_SHIFT:
     case nsIDOMKeyEvent::DOM_VK_CONTROL:
     case nsIDOMKeyEvent::DOM_VK_ALT:
--- a/editor/libeditor/nsPlaintextEditor.cpp
+++ b/editor/libeditor/nsPlaintextEditor.cpp
@@ -357,17 +357,17 @@ nsPlaintextEditor::HandleKeyPressEvent(n
   if (IsReadonly() || IsDisabled()) {
     // When we're not editable, the events handled on nsEditor.
     return nsEditor::HandleKeyPressEvent(aKeyEvent);
   }
 
   WidgetKeyboardEvent* nativeKeyEvent =
     aKeyEvent->GetInternalNSEvent()->AsKeyboardEvent();
   NS_ENSURE_TRUE(nativeKeyEvent, NS_ERROR_UNEXPECTED);
-  NS_ASSERTION(nativeKeyEvent->mMessage == NS_KEY_PRESS,
+  NS_ASSERTION(nativeKeyEvent->mMessage == eKeyPress,
                "HandleKeyPressEvent gets non-keypress event");
 
   switch (nativeKeyEvent->keyCode) {
     case nsIDOMKeyEvent::DOM_VK_META:
     case nsIDOMKeyEvent::DOM_VK_WIN:
     case nsIDOMKeyEvent::DOM_VK_SHIFT:
     case nsIDOMKeyEvent::DOM_VK_CONTROL:
     case nsIDOMKeyEvent::DOM_VK_ALT:
--- a/gfx/layers/AxisPhysicsMSDModel.cpp
+++ b/gfx/layers/AxisPhysicsMSDModel.cpp
@@ -65,36 +65,29 @@ AxisPhysicsMSDModel::GetDestination()
 
 void
 AxisPhysicsMSDModel::SetDestination(double aDestination)
 {
   mDestination = aDestination;
 }
 
 bool
-AxisPhysicsMSDModel::IsFinished()
+AxisPhysicsMSDModel::IsFinished(double aSmallestVisibleIncrement)
 {
   // In order to satisfy the condition of reaching the destination, the distance
   // between the simulation position and the destination must be less than
-  // kFinishDistance while the speed is simultaneously less than
-  // kFinishVelocity.  This enables an under-damped system to overshoot the
+  // aSmallestVisibleIncrement while the speed is simultaneously less than
+  // finishVelocity.  This enables an under-damped system to overshoot the
   // destination when desired without prematurely triggering the finished state.
-
-  // As the number of app units per css pixel is 60 and retina / HiDPI displays
-  // may display two pixels for every css pixel, setting kFinishDistance to 30.0
-  // ensures that there will be no perceptable shift in position at the end
-  // of the animation.
-  const double kFinishDistance = 30.0;
-
-  // If kFinishVelocity is set too low, the animation may end long after
+  // If finishVelocity is set too low, the animation may end long after
   // oscillation has finished, resulting in unnecessary processing.
   // If set too high, the animation may prematurely terminate when expected
   // to overshoot the destination in an under-damped system.
-  // 60.0 was selected through experimentation that revealed that a
-  // critically damped system will terminate within 100ms.
-  const double kFinishVelocity = 60.0;
+  // aSmallestVisibleIncrement * 2 was selected through experimentation that
+  // revealed that a critically damped system will terminate within 100ms.
+  const double finishVelocity = aSmallestVisibleIncrement * 2;
 
-  return fabs(mDestination - GetPosition ()) < kFinishDistance
-    && fabs(GetVelocity()) <= kFinishVelocity;
+  return fabs(mDestination - GetPosition ()) < aSmallestVisibleIncrement
+    && fabs(GetVelocity()) <= finishVelocity;
 }
 
 } // namespace layers
 } // namespace mozilla
--- a/gfx/layers/AxisPhysicsMSDModel.h
+++ b/gfx/layers/AxisPhysicsMSDModel.h
@@ -33,17 +33,17 @@ public:
    * Sets the raw destination of this axis at this moment.
    */
   void SetDestination(double aDestination);
 
   /**
    * Returns true when the position is close to the destination and the
    * velocity is low.
    */
-  bool IsFinished();
+  bool IsFinished(double aSmallestVisibleIncrement);
 
 protected:
   virtual double Acceleration(const State &aState);
 
 private:
 
   /**
    * mDestination represents the target position and the resting position of
--- a/gfx/layers/apz/src/APZCTreeManager.cpp
+++ b/gfx/layers/apz/src/APZCTreeManager.cpp
@@ -869,35 +869,35 @@ APZCTreeManager::UpdateWheelTransaction(
 
   // If the transaction has simply timed out, we don't need to do anything
   // else.
   if (txn->MaybeTimeout(TimeStamp::Now())) {
     return;
   }
 
   switch (aEvent.mMessage) {
-   case NS_MOUSE_MOVE:
+   case eMouseMove:
    case NS_DRAGDROP_OVER: {
      WidgetMouseEvent* mouseEvent = aEvent.AsMouseEvent();
      if (!mouseEvent->IsReal()) {
        return;
      }
 
      ScreenIntPoint point =
        ViewAs<ScreenPixel>(aEvent.refPoint, PixelCastJustification::LayoutDeviceToScreenForUntransformedEvent);
      txn->OnMouseMove(point);
      return;
    }
-   case NS_KEY_PRESS:
-   case NS_KEY_UP:
-   case NS_KEY_DOWN:
-   case NS_MOUSE_BUTTON_UP:
-   case NS_MOUSE_BUTTON_DOWN:
-   case NS_MOUSE_DOUBLECLICK:
-   case NS_MOUSE_CLICK:
+   case eKeyPress:
+   case eKeyUp:
+   case eKeyDown:
+   case eMouseUp:
+   case eMouseDown:
+   case eMouseDoubleClick:
+   case eMouseClick:
    case NS_CONTEXTMENU:
    case NS_DRAGDROP_DROP:
      txn->EndTransaction();
      return;
    default:
      break;
   }
 }
--- a/gfx/layers/apz/src/AsyncPanZoomController.cpp
+++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp
@@ -690,39 +690,42 @@ public:
 
   /**
    * Advances a smooth scroll simulation based on the time passed in |aDelta|.
    * This should be called whenever sampling the content transform for this
    * frame. Returns true if the smooth scroll should be advanced by one frame,
    * or false if the smooth scroll has ended.
    */
   bool DoSample(FrameMetrics& aFrameMetrics, const TimeDuration& aDelta) {
-    if (mXAxisModel.IsFinished() && mYAxisModel.IsFinished()) {
+    nsPoint oneParentLayerPixel =
+      CSSPoint::ToAppUnits(ParentLayerPoint(1, 1) / aFrameMetrics.GetZoom());
+    if (mXAxisModel.IsFinished(oneParentLayerPixel.x) &&
+        mYAxisModel.IsFinished(oneParentLayerPixel.y)) {
       return false;
     }
 
     mXAxisModel.Simulate(aDelta);
     mYAxisModel.Simulate(aDelta);
 
     CSSPoint position = CSSPoint::FromAppUnits(nsPoint(mXAxisModel.GetPosition(),
                                                        mYAxisModel.GetPosition()));
     CSSPoint css_velocity = CSSPoint::FromAppUnits(nsPoint(mXAxisModel.GetVelocity(),
                                                            mYAxisModel.GetVelocity()));
 
     // Convert from points/second to points/ms
     ParentLayerPoint velocity = ParentLayerPoint(css_velocity.x, css_velocity.y) / 1000.0f;
 
     // Keep the velocity updated for the Axis class so that any animations
     // chained off of the smooth scroll will inherit it.
-    if (mXAxisModel.IsFinished()) {
+    if (mXAxisModel.IsFinished(oneParentLayerPixel.x)) {
       mApzc.mX.SetVelocity(0);
     } else {
       mApzc.mX.SetVelocity(velocity.x);
     }
-    if (mYAxisModel.IsFinished()) {
+    if (mYAxisModel.IsFinished(oneParentLayerPixel.y)) {
       mApzc.mY.SetVelocity(0);
     } else {
       mApzc.mY.SetVelocity(velocity.y);
     }
     // If we overscroll, hand off to a fling animation that will complete the
     // spring back.
     CSSToParentLayerScale2D zoom = aFrameMetrics.GetZoom();
     ParentLayerPoint displacement = (position - aFrameMetrics.GetScrollOffset()) * zoom;
--- a/gfx/layers/apz/src/InputBlockState.cpp
+++ b/gfx/layers/apz/src/InputBlockState.cpp
@@ -421,16 +421,17 @@ WheelBlockState::EndTransaction()
   mTransactionEnded = true;
 }
 
 PanGestureBlockState::PanGestureBlockState(const nsRefPtr<AsyncPanZoomController>& aTargetApzc,
                                            bool aTargetConfirmed,
                                            const PanGestureInput& aInitialEvent)
   : CancelableBlockState(aTargetApzc, aTargetConfirmed)
   , mInterrupted(false)
+  , mWaitingForContentResponse(false)
 {
   if (aTargetConfirmed) {
     // Find the nearest APZC in the overscroll handoff chain that is scrollable.
     // If we get a content confirmation later that the apzc is different, then
     // content should have found a scrollable apzc, so we don't need to handle
     // that case.
     nsRefPtr<AsyncPanZoomController> apzc =
       mOverscrollHandoffChain->FindFirstScrollable(aInitialEvent);
@@ -504,25 +505,46 @@ PanGestureBlockState::Type()
 }
 
 bool
 PanGestureBlockState::SetContentResponse(bool aPreventDefault)
 {
   if (aPreventDefault) {
     mInterrupted = true;
   }
-  return CancelableBlockState::SetContentResponse(aPreventDefault);
+  bool stateChanged = CancelableBlockState::SetContentResponse(aPreventDefault);
+  if (mWaitingForContentResponse) {
+    mWaitingForContentResponse = false;
+    stateChanged = true;
+  }
+  return stateChanged;
+}
+
+bool
+PanGestureBlockState::IsReadyForHandling() const
+{
+  if (!CancelableBlockState::IsReadyForHandling()) {
+    return false;
+  }
+  return !mWaitingForContentResponse ||
+         IsContentResponseTimerExpired();
 }
 
 bool
 PanGestureBlockState::AllowScrollHandoff() const
 {
   return false;
 }
 
+void
+PanGestureBlockState::SetNeedsToWaitForContentResponse(bool aWaitForContentResponse)
+{
+  mWaitingForContentResponse = aWaitForContentResponse;
+}
+
 TouchBlockState::TouchBlockState(const nsRefPtr<AsyncPanZoomController>& aTargetApzc,
                                  bool aTargetConfirmed, TouchCounter& aCounter)
   : CancelableBlockState(aTargetApzc, aTargetConfirmed)
   , mAllowedTouchBehaviorSet(false)
   , mDuringFastFling(false)
   , mSingleTapOccurred(false)
   , mTouchCounter(aCounter)
 {
--- a/gfx/layers/apz/src/InputBlockState.h
+++ b/gfx/layers/apz/src/InputBlockState.h
@@ -257,16 +257,17 @@ private:
 class PanGestureBlockState : public CancelableBlockState
 {
 public:
   PanGestureBlockState(const nsRefPtr<AsyncPanZoomController>& aTargetApzc,
                        bool aTargetConfirmed,
                        const PanGestureInput& aEvent);
 
   bool SetContentResponse(bool aPreventDefault) override;
+  bool IsReadyForHandling() const override;
   bool HasEvents() const override;
   void DropEvents() override;
   void HandleEvents() override;
   bool MustStayActive() override;
   const char* Type() override;
   bool SetConfirmedTargetApzc(const nsRefPtr<AsyncPanZoomController>& aTargetApzc) override;
 
   void AddEvent(const PanGestureInput& aEvent);
@@ -277,19 +278,22 @@ public:
 
   /**
    * @return Whether or not overscrolling is prevented for this block.
    */
   bool AllowScrollHandoff() const;
 
   bool WasInterrupted() const { return mInterrupted; }
 
+  void SetNeedsToWaitForContentResponse(bool aWaitForContentResponse);
+
 private:
   nsTArray<PanGestureInput> mEvents;
   bool mInterrupted;
+  bool mWaitingForContentResponse;
 };
 
 /**
  * This class represents a single touch block. A touch block is
  * a set of touch events that can be cancelled by web content via
  * touch event listeners.
  *
  * Every touch-start event creates a new touch block. In this case, the
--- a/gfx/layers/apz/src/InputQueue.cpp
+++ b/gfx/layers/apz/src/InputQueue.cpp
@@ -209,16 +209,27 @@ InputQueue::ReceiveScrollWheelInput(cons
   // MaybeHandleCurrentBlock() does.
   if (!MaybeHandleCurrentBlock(block, aEvent)) {
     block->AddEvent(aEvent.AsScrollWheelInput());
   }
 
   return nsEventStatus_eConsumeDoDefault;
 }
 
+static bool
+CanScrollTargetHorizontally(const PanGestureInput& aInitialEvent,
+                            PanGestureBlockState* aBlock)
+{
+  PanGestureInput horizontalComponent = aInitialEvent;
+  horizontalComponent.mPanDisplacement.y = 0;
+  nsRefPtr<AsyncPanZoomController> horizontallyScrollableAPZC =
+    aBlock->GetOverscrollHandoffChain()->FindFirstScrollable(horizontalComponent);
+  return horizontallyScrollableAPZC && horizontallyScrollableAPZC == aBlock->GetTargetApzc();
+}
+
 nsEventStatus
 InputQueue::ReceivePanGestureInput(const nsRefPtr<AsyncPanZoomController>& aTarget,
                                    bool aTargetConfirmed,
                                    const PanGestureInput& aEvent,
                                    uint64_t* aOutInputBlockId) {
   if (aEvent.mType == PanGestureInput::PANGESTURE_MAYSTART ||
       aEvent.mType == PanGestureInput::PANGESTURE_CANCELLED) {
     // Ignore these events for now.
@@ -226,24 +237,40 @@ InputQueue::ReceivePanGestureInput(const
   }
 
   PanGestureBlockState* block = nullptr;
   if (!mInputBlockQueue.IsEmpty() &&
       aEvent.mType != PanGestureInput::PANGESTURE_START) {
     block = mInputBlockQueue.LastElement()->AsPanGestureBlock();
   }
 
+  nsEventStatus result = nsEventStatus_eConsumeDoDefault;
+
   if (!block || block->WasInterrupted()) {
     if (aEvent.mType != PanGestureInput::PANGESTURE_START) {
       // Only PANGESTURE_START events are allowed to start a new pan gesture block.
       return nsEventStatus_eConsumeDoDefault;
     }
     block = new PanGestureBlockState(aTarget, aTargetConfirmed, aEvent);
     INPQ_LOG("started new pan gesture block %p for target %p\n", block, aTarget.get());
 
+    if (aTargetConfirmed &&
+        aEvent.mRequiresContentResponseIfCannotScrollHorizontallyInStartDirection &&
+        !CanScrollTargetHorizontally(aEvent, block)) {
+      // This event may trigger a swipe gesture, depending on what our caller
+      // wants to do it. We need to suspend handling of this block until we get
+      // a content response which will tell us whether to proceed or abort the
+      // block.
+      block->SetNeedsToWaitForContentResponse(true);
+
+      // Inform our caller that we haven't scrolled in response to the event
+      // and that a swipe can be started from this event if desired.
+      result = nsEventStatus_eIgnore;
+    }
+
     SweepDepletedBlocks();
     mInputBlockQueue.AppendElement(block);
 
     CancelAnimationsForNewBlock(block);
     MaybeRequestContentResponse(aTarget, block);
   } else {
     INPQ_LOG("received new event in block %p\n", block);
   }
@@ -256,17 +283,17 @@ InputQueue::ReceivePanGestureInput(const
   // target set on the block. In this case the confirmed target (which may be
   // null) should take priority. This is equivalent to just always using the
   // target (confirmed or not) from the block, which is what
   // MaybeHandleCurrentBlock() does.
   if (!MaybeHandleCurrentBlock(block, aEvent)) {
     block->AddEvent(aEvent.AsPanGestureInput());
   }
 
-  return nsEventStatus_eConsumeDoDefault;
+  return result;
 }
 
 void
 InputQueue::CancelAnimationsForNewBlock(CancelableBlockState* aBlock)
 {
   // We want to cancel animations here as soon as possible (i.e. without waiting for
   // content responses) because a finger has gone down and we don't want to keep moving
   // the content under the finger. However, to prevent "future" touchstart events from
--- a/gfx/layers/apz/test/mochitest.ini
+++ b/gfx/layers/apz/test/mochitest.ini
@@ -12,14 +12,16 @@ support-files =
   helper_iframe_pan.html
 tags = apz
 [test_bug982141.html]
 skip-if = toolkit != 'gonk'  # bug 991198
 [test_bug1151663.html]
 skip-if = toolkit != 'gonk'  # bug 991198
 [test_wheel_scroll.html]
 skip-if = (os == 'android') || (os == 'b2g') || (buildapp == 'mulet') # wheel events not supported on mobile; see bug 1164274 for mulet
+[test_wheel_transactions.html]
+skip-if = (os == 'android') || (os == 'b2g') || (buildapp == 'mulet') # wheel events not supported on mobile; see bug 1164274 for mulet
 [test_bug1151667.html]
 skip-if = (os == 'android') || (os == 'b2g') # wheel events not supported on mobile
 [test_layerization.html]
 skip-if = (os == 'android') || (os == 'b2g') # uses wheel events which are not supported on mobile
 [test_basic_pan.html]
 skip-if = toolkit != 'gonk'
new file mode 100644
--- /dev/null
+++ b/gfx/layers/apz/test/test_wheel_transactions.html
@@ -0,0 +1,142 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1175585
+-->
+<head>
+  <title>Test for Bug 1175585</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+  <script type="application/javascript" src="apz_test_native_event_utils.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+  <style>
+  #outer-frame {
+      height: 500px;
+      overflow: scroll;
+      background: repeating-linear-gradient(#CCC, #CCC 100px, #BBB 100px, #BBB 200px);
+  }
+  #inner-frame {
+      margin-top: 25%;
+      height: 200%;
+      width: 75%;
+      overflow: scroll;
+  }
+  #inner-content {
+      height: 200%;
+      width: 200%;
+      background: repeating-linear-gradient(#EEE, #EEE 100px, #DDD 100px, #DDD 200px);
+  }
+  </style>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1175585">APZ wheel transactions test</a>
+<p id="display"></p>
+<div id="outer-frame">
+    <div id="inner-frame">
+        <div id="inner-content"></div>
+    </div>
+</div>
+<pre id="test">
+<script type="application/javascript;version=1.7">
+
+function scrollWheelOver(element, deltaY) {
+  synthesizeNativeWheelAndWaitForScrollEvent(element, 10, 10, 0, deltaY, driveTest);
+}
+
+function* runTest() {
+  var outer = document.getElementById('outer-frame');
+  var inner = document.getElementById('inner-frame');
+  var innerContent = document.getElementById('inner-content');
+
+  // Register a wheel event listener that records the target of
+  // the last wheel event, so that we can make assertions about it.
+  var lastWheelTarget;
+  var wheelTargetRecorder = function(e) { lastWheelTarget = e.target; };
+  window.addEventListener("wheel", wheelTargetRecorder);
+
+  // Scroll |outer| to the bottom.
+  while (outer.scrollTop < outer.scrollTopMax) {
+    yield scrollWheelOver(outer, -10);
+  }
+
+  // Verify that this has brought |inner| under the wheel.
+  is(lastWheelTarget, innerContent, "'inner-content' should have been brought under the wheel");
+  window.removeEventListener("wheel", wheelTargetRecorder);
+
+  // Immediately after, scroll it back up a bit.
+  yield scrollWheelOver(outer, 10);
+
+  // Check that it was |outer| that scrolled back, and |inner| didn't
+  // scroll at all, as all the above scrolls should be in the same
+  // transaction.
+  ok(outer.scrollTop < outer.scrollTopMax, "'outer' should have scrolled back a bit");
+  is(inner.scrollTop, 0, "'inner' should not have scrolled");
+
+  // The next part of the test is related to the transaction timeout.
+  // Turn it down a bit so waiting for the timeout to elapse doesn't
+  // slow down the test harness too much.
+  var timeout = 5;
+  yield SpecialPowers.pushPrefEnv({"set": [["mousewheel.transaction.timeout", timeout]]}, driveTest);
+  SimpleTest.requestFlakyTimeout("we are testing code that measures actual elapsed time between two events");
+
+  // Scroll up a bit more. It's still |outer| scrolling because
+  // |inner| is still scrolled all the way to the top.
+  yield scrollWheelOver(outer, 10);
+
+  // Wait for the transaction timeout to elapse.
+  yield window.setTimeout(driveTest, timeout);
+
+  // Now scroll down. The transaction having timed out, the event
+  // should pick up a new target, and that should be |inner|.
+  yield scrollWheelOver(outer, -10);
+  ok(inner.scrollTop > 0, "'inner' should have been scrolled");
+
+  // Finally, test scroll handoff after a timeout.
+
+  // Continue scrolling |inner| down to the bottom.
+  var prevScrollTop = inner.scrollTop;
+  while (inner.scrollTop < inner.scrollTopMax) {
+    yield scrollWheelOver(outer, -10);
+    // Avoid a failure getting us into an infinite loop.
+    ok(inner.scrollTop > prevScrollTop, "scrolling down should increase scrollTop");
+    prevScrollTop = inner.scrollTop;
+  }
+
+  // Wait for the transaction timeout to elapse.
+  yield window.setTimeout(driveTest, timeout);
+
+  // Continued downward scrolling should scroll |outer| to the bottom.
+  prevScrollTop = outer.scrollTop;
+  while (outer.scrollTop < outer.scrollTopMax) {
+    yield scrollWheelOver(outer, -10);
+    // Avoid a failure getting us into an infinite loop.
+    ok(outer.scrollTop > prevScrollTop, "scrolling down should increase scrollTop");
+    prevScrollTop = outer.scrollTop;
+  }
+}
+
+var gTestContinuation = null;
+function driveTest() {
+  if (!gTestContinuation) {
+    gTestContinuation = runTest();
+  }
+  var ret = gTestContinuation.next();
+  if (ret.done) {
+    SimpleTest.finish();
+  }
+}
+
+function startTest() {
+  // Disable smooth scrolling because it makes the test flaky (we don't have a good
+  // way of detecting when the scrolling is finished).
+  SpecialPowers.pushPrefEnv({"set": [["general.smoothScroll", false]]}, driveTest);
+}
+
+SimpleTest.waitForExplicitFinish();
+SimpleTest.waitForFocus(startTest, window);
+
+</script>
+</pre>
+
+</body>
+</html>
--- a/gfx/layers/apz/util/APZCCallbackHelper.cpp
+++ b/gfx/layers/apz/util/APZCCallbackHelper.cpp
@@ -491,27 +491,27 @@ APZCCallbackHelper::DispatchWidgetEvent(
 
 nsEventStatus
 APZCCallbackHelper::DispatchSynthesizedMouseEvent(EventMessage aMsg,
                                                   uint64_t aTime,
                                                   const LayoutDevicePoint& aRefPoint,
                                                   Modifiers aModifiers,
                                                   nsIWidget* aWidget)
 {
-  MOZ_ASSERT(aMsg == NS_MOUSE_MOVE || aMsg == NS_MOUSE_BUTTON_DOWN ||
-             aMsg == NS_MOUSE_BUTTON_UP || aMsg == NS_MOUSE_MOZLONGTAP);
+  MOZ_ASSERT(aMsg == eMouseMove || aMsg == eMouseDown ||
+             aMsg == eMouseUp || aMsg == eMouseLongTap);
 
   WidgetMouseEvent event(true, aMsg, nullptr,
                          WidgetMouseEvent::eReal, WidgetMouseEvent::eNormal);
   event.refPoint = LayoutDeviceIntPoint(aRefPoint.x, aRefPoint.y);
   event.time = aTime;
   event.button = WidgetMouseEvent::eLeftButton;
   event.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH;
   event.ignoreRootScrollFrame = true;
-  if (aMsg != NS_MOUSE_MOVE) {
+  if (aMsg != eMouseMove) {
     event.clickCount = 1;
   }
   event.modifiers = aModifiers;
   event.widget = aWidget;
 
   return DispatchWidgetEvent(event);
 }
 
@@ -541,19 +541,19 @@ APZCCallbackHelper::FireSingleTapEvent(c
                                        nsIWidget* aWidget)
 {
   if (aWidget->Destroyed()) {
     return;
   }
   APZCCH_LOG("Dispatching single-tap component events to %s\n",
     Stringify(aPoint).c_str());
   int time = 0;
-  DispatchSynthesizedMouseEvent(NS_MOUSE_MOVE, time, aPoint, aModifiers, aWidget);
-  DispatchSynthesizedMouseEvent(NS_MOUSE_BUTTON_DOWN, time, aPoint, aModifiers, aWidget);
-  DispatchSynthesizedMouseEvent(NS_MOUSE_BUTTON_UP, time, aPoint, aModifiers, aWidget);
+  DispatchSynthesizedMouseEvent(eMouseMove, time, aPoint, aModifiers, aWidget);
+  DispatchSynthesizedMouseEvent(eMouseDown, time, aPoint, aModifiers, aWidget);
+  DispatchSynthesizedMouseEvent(eMouseUp, time, aPoint, aModifiers, aWidget);
 }
 
 static nsIScrollableFrame*
 GetScrollableAncestorFrame(nsIFrame* aTarget)
 {
   uint32_t flags = nsLayoutUtils::SCROLLABLE_ALWAYS_MATCH_ROOT
                  | nsLayoutUtils::SCROLLABLE_ONLY_ASYNC_SCROLLABLE;
   return nsLayoutUtils::GetNearestScrollableFrame(aTarget, flags);
--- a/gfx/layers/apz/util/APZEventState.cpp
+++ b/gfx/layers/apz/util/APZEventState.cpp
@@ -232,17 +232,19 @@ APZEventState::ProcessLongTap(const nsCO
 
   // If no one handle context menu, fire MOZLONGTAP event
   if (!eventHandled) {
     LayoutDevicePoint currentPoint =
         APZCCallbackHelper::ApplyCallbackTransform(aPoint, aGuid)
       * widget->GetDefaultScale();
     int time = 0;
     nsEventStatus status =
-        APZCCallbackHelper::DispatchSynthesizedMouseEvent(NS_MOUSE_MOZLONGTAP, time, currentPoint, aModifiers, widget);
+        APZCCallbackHelper::DispatchSynthesizedMouseEvent(eMouseLongTap, time,
+                                                          currentPoint,
+                                                          aModifiers, widget);
     eventHandled = (status == nsEventStatus_eConsumeNoDefault);
     APZES_LOG("MOZLONGTAP event handled: %d\n", eventHandled);
   }
 
   mContentReceivedInputBlockCallback->Run(aGuid, aInputBlockId, eventHandled);
 }
 
 void
@@ -317,17 +319,21 @@ APZEventState::ProcessTouchEvent(const W
   }
 }
 
 void
 APZEventState::ProcessWheelEvent(const WidgetWheelEvent& aEvent,
                                  const ScrollableLayerGuid& aGuid,
                                  uint64_t aInputBlockId)
 {
-  mContentReceivedInputBlockCallback->Run(aGuid, aInputBlockId, aEvent.mFlags.mDefaultPrevented);
+  // If this event starts a swipe, indicate that it shouldn't result in a
+  // scroll by setting defaultPrevented to true.
+  bool defaultPrevented =
+    aEvent.mFlags.mDefaultPrevented || aEvent.TriggersSwipe();
+  mContentReceivedInputBlockCallback->Run(aGuid, aInputBlockId, defaultPrevented);
 }
 
 void
 APZEventState::ProcessAPZStateChange(const nsCOMPtr<nsIDocument>& aDocument,
                                      ViewID aViewId,
                                      APZStateChange aChange,
                                      int aArg)
 {
--- a/gfx/layers/client/ClientTiledPaintedLayer.cpp
+++ b/gfx/layers/client/ClientTiledPaintedLayer.cpp
@@ -50,20 +50,20 @@ ClientTiledPaintedLayer::ClearCachedReso
 }
 
 void
 ClientTiledPaintedLayer::FillSpecificAttributes(SpecificLayerAttributes& aAttrs)
 {
   aAttrs = PaintedLayerAttributes(GetValidRegion());
 }
 
-static LayerRect
-ApplyParentLayerToLayerTransform(const gfx::Matrix4x4& aTransform, const ParentLayerRect& aParentLayerRect)
+static Maybe<LayerRect>
+ApplyParentLayerToLayerTransform(const gfx::Matrix4x4& aTransform, const ParentLayerRect& aParentLayerRect, const LayerRect& aClip)
 {
-  return TransformTo<LayerPixel>(aTransform, aParentLayerRect);
+  return UntransformTo<LayerPixel>(aTransform, aParentLayerRect, aClip);
 }
 
 static gfx::Matrix4x4
 GetTransformToAncestorsParentLayer(Layer* aStart, const LayerMetricsWrapper& aAncestor)
 {
   gfx::Matrix4x4 transform;
   const LayerMetricsWrapper& ancestorParent = aAncestor.GetParent();
   for (LayerMetricsWrapper iter(aStart, LayerMetricsWrapper::StartAt::BOTTOM);
@@ -119,20 +119,17 @@ ClientTiledPaintedLayer::GetAncestorLaye
   if (aOutHasTransformAnimation) {
     *aOutHasTransformAnimation = hasTransformAnimation;
   }
 }
 
 void
 ClientTiledPaintedLayer::BeginPaint()
 {
-  mPaintData.mLowPrecisionPaintCount = 0;
-  mPaintData.mPaintFinished = false;
-  mPaintData.mCompositionBounds.SetEmpty();
-  mPaintData.mCriticalDisplayPort.SetEmpty();
+  mPaintData.ResetPaintData();
 
   if (!GetBaseTransform().Is2D()) {
     // Give up if there is a complex CSS transform on the layer. We might
     // eventually support these but for now it's too complicated to handle
     // given that it's a pretty rare scenario.
     return;
   }
 
@@ -160,43 +157,55 @@ ClientTiledPaintedLayer::BeginPaint()
   const FrameMetrics& displayportMetrics = displayPortAncestor.Metrics();
 
   // Calculate the transform required to convert ParentLayer space of our
   // display port ancestor to the Layer space of this layer.
   gfx::Matrix4x4 transformDisplayPortToLayer =
     GetTransformToAncestorsParentLayer(this, displayPortAncestor);
   transformDisplayPortToLayer.Invert();
 
+  LayerRect layerBounds = ViewAs<LayerPixel>(Rect(GetLayerBounds()));
+
   // Compute the critical display port that applies to this layer in the
   // LayoutDevice space of this layer, but only if there is no OMT animation
   // on this layer. If there is an OMT animation then we need to draw the whole
   // visible region of this layer as determined by layout, because we don't know
   // what parts of it might move into view in the compositor.
   if (!hasTransformAnimation &&
       mContentClient->GetLowPrecisionTiledBuffer()) {
     ParentLayerRect criticalDisplayPort =
       (displayportMetrics.GetCriticalDisplayPort() * displayportMetrics.GetZoom())
       + displayportMetrics.GetCompositionBounds().TopLeft();
-    mPaintData.mCriticalDisplayPort = RoundedToInt(
-      ApplyParentLayerToLayerTransform(transformDisplayPortToLayer, criticalDisplayPort));
+    Maybe<LayerRect> criticalDisplayPortTransformed =
+      ApplyParentLayerToLayerTransform(transformDisplayPortToLayer, criticalDisplayPort, layerBounds);
+    if (!criticalDisplayPortTransformed) {
+      mPaintData.ResetPaintData();
+      return;
+    }
+    mPaintData.mCriticalDisplayPort = RoundedToInt(*criticalDisplayPortTransformed);
   }
   TILING_LOG("TILING %p: Critical displayport %s\n", this, Stringify(mPaintData.mCriticalDisplayPort).c_str());
 
   // Store the resolution from the displayport ancestor layer. Because this is Gecko-side,
   // before any async transforms have occurred, we can use the zoom for this.
   mPaintData.mResolution = displayportMetrics.GetZoom();
   TILING_LOG("TILING %p: Resolution %s\n", this, Stringify(mPaintData.mResolution).c_str());
 
   // Store the applicable composition bounds in this layer's Layer units.
   mPaintData.mTransformToCompBounds =
     GetTransformToAncestorsParentLayer(this, scrollAncestor);
   gfx::Matrix4x4 transformToBounds = mPaintData.mTransformToCompBounds;
   transformToBounds.Invert();
-  mPaintData.mCompositionBounds = ApplyParentLayerToLayerTransform(
-    transformToBounds, scrollMetrics.GetCompositionBounds());
+  Maybe<LayerRect> compositionBoundsTransformed = ApplyParentLayerToLayerTransform(
+    transformToBounds, scrollMetrics.GetCompositionBounds(), layerBounds);
+  if (!compositionBoundsTransformed) {
+    mPaintData.ResetPaintData();
+    return;
+  }
+  mPaintData.mCompositionBounds = *compositionBoundsTransformed;
   TILING_LOG("TILING %p: Composition bounds %s\n", this, Stringify(mPaintData.mCompositionBounds).c_str());
 
   // Calculate the scroll offset since the last transaction
   mPaintData.mScrollOffset = displayportMetrics.GetScrollOffset() * displayportMetrics.GetZoom();
   TILING_LOG("TILING %p: Scroll offset %s\n", this, Stringify(mPaintData.mScrollOffset).c_str());
 }
 
 bool
--- a/gfx/layers/client/TiledContentClient.cpp
+++ b/gfx/layers/client/TiledContentClient.cpp
@@ -1393,24 +1393,26 @@ ClientMultiTiledLayerBuffer::ValidateTil
  * (which was generated in GetTransformToAncestorsParentLayer), and
  * modifies it with the ViewTransform from the compositor side so that
  * it reflects what the compositor is actually rendering. This operation
  * basically adds in the layer's async transform.
  * This function then returns the scroll ancestor's composition bounds,
  * transformed into the painted layer's LayerPixel coordinates, accounting
  * for the compositor state.
  */
-static LayerRect
+static Maybe<LayerRect>
 GetCompositorSideCompositionBounds(const LayerMetricsWrapper& aScrollAncestor,
                                    const Matrix4x4& aTransformToCompBounds,
-                                   const ViewTransform& aAPZTransform)
+                                   const ViewTransform& aAPZTransform,
+                                   const LayerRect& aClip)
 {
   Matrix4x4 transform = aTransformToCompBounds * Matrix4x4(aAPZTransform);
-  return TransformTo<LayerPixel>(transform.Inverse(),
-            aScrollAncestor.Metrics().GetCompositionBounds());
+
+  return UntransformTo<LayerPixel>(transform.Inverse(),
+    aScrollAncestor.Metrics().GetCompositionBounds(), aClip);
 }
 
 bool
 ClientMultiTiledLayerBuffer::ComputeProgressiveUpdateRegion(const nsIntRegion& aInvalidRegion,
                                                             const nsIntRegion& aOldValidRegion,
                                                             nsIntRegion& aRegionToPaint,
                                                             BasicTiledLayerPaintData* aPaintData,
                                                             bool aIsRepeated)
@@ -1479,37 +1481,43 @@ ClientMultiTiledLayerBuffer::ComputeProg
       PROFILER_LABEL("ClientMultiTiledLayerBuffer", "ComputeProgressiveUpdateRegion",
         js::ProfileEntry::Category::GRAPHICS);
 
       aRegionToPaint.SetEmpty();
       return aIsRepeated;
     }
   }
 
-  LayerRect transformedCompositionBounds =
+  Maybe<LayerRect> transformedCompositionBounds =
     GetCompositorSideCompositionBounds(scrollAncestor,
                                        aPaintData->mTransformToCompBounds,
-                                       viewTransform);
+                                       viewTransform,
+                                       ViewAs<LayerPixel>(Rect(mPaintedLayer->GetLayerBounds())));
 
-  TILING_LOG("TILING %p: Progressive update transformed compositor bounds %s\n", mPaintedLayer, Stringify(transformedCompositionBounds).c_str());
+  if (!transformedCompositionBounds) {
+    aPaintData->mPaintFinished = true;
+    return false;
+  }
+
+  TILING_LOG("TILING %p: Progressive update transformed compositor bounds %s\n", mPaintedLayer, Stringify(*transformedCompositionBounds).c_str());
 
   // Compute a "coherent update rect" that we should paint all at once in a
   // single transaction. This is to avoid rendering glitches on animated
   // page content, and when layers change size/shape.
   // On Fennec uploads are more expensive because we're not using gralloc, so
   // we use a coherent update rect that is intersected with the screen at the
   // time of issuing the draw command. This will paint faster but also potentially
   // make the progressive paint more visible to the user while scrolling.
   // On B2G uploads are cheaper and we value coherency more, especially outside
   // the browser, so we always use the entire user-visible area.
   IntRect coherentUpdateRect(LayerIntRect::ToUntyped(RoundedOut(
 #ifdef MOZ_WIDGET_ANDROID
-    transformedCompositionBounds.Intersect(aPaintData->mCompositionBounds)
+    transformedCompositionBounds->Intersect(aPaintData->mCompositionBounds)
 #else
-    transformedCompositionBounds
+    *transformedCompositionBounds
 #endif
   )));
 
   TILING_LOG("TILING %p: Progressive update final coherency rect %s\n", mPaintedLayer, Stringify(coherentUpdateRect).c_str());
 
   aRegionToPaint.And(aInvalidRegion, coherentUpdateRect);
   aRegionToPaint.Or(aRegionToPaint, staleRegion);
   bool drawingStale = !aRegionToPaint.IsEmpty();
@@ -1674,10 +1682,19 @@ TiledContentClient::PrintInfo(std::strin
 void
 TiledContentClient::Dump(std::stringstream& aStream,
                          const char* aPrefix,
                          bool aDumpHtml)
 {
   GetTiledBuffer()->Dump(aStream, aPrefix, aDumpHtml);
 }
 
+void
+BasicTiledLayerPaintData::ResetPaintData()
+{
+  mLowPrecisionPaintCount = 0;
+  mPaintFinished = false;
+  mCompositionBounds.SetEmpty();
+  mCriticalDisplayPort.SetEmpty();
+}
+
 } // namespace layers
 } // namespace mozilla
--- a/gfx/layers/client/TiledContentClient.h
+++ b/gfx/layers/client/TiledContentClient.h
@@ -347,16 +347,21 @@ struct BasicTiledLayerPaintData {
   bool mFirstPaint : 1;
 
   /*
    * Whether there is further work to complete this paint. This is used to
    * determine whether or not to repeat the transaction when painting
    * progressively.
    */
   bool mPaintFinished : 1;
+
+  /*
+   * Initializes/clears data to prepare for paint action.
+   */
+  void ResetPaintData();
 };
 
 class SharedFrameMetricsHelper
 {
 public:
   SharedFrameMetricsHelper();
   ~SharedFrameMetricsHelper();
 
--- a/gfx/layers/composite/AsyncCompositionManager.cpp
+++ b/gfx/layers/composite/AsyncCompositionManager.cpp
@@ -153,16 +153,17 @@ GetBaseTransform(Layer* aLayer, Matrix4x
         ? aLayer->GetLocalTransform()
         : aLayer->GetTransform());
 }
 
 static void
 TransformClipRect(Layer* aLayer,
                   const Matrix4x4& aTransform)
 {
+  MOZ_ASSERT(aTransform.Is2D());
   const Maybe<ParentLayerIntRect>& clipRect = aLayer->AsLayerComposite()->GetShadowClipRect();
   if (clipRect) {
     ParentLayerIntRect transformed = TransformTo<ParentLayerPixel>(aTransform, *clipRect);
     aLayer->AsLayerComposite()->SetShadowClipRect(Some(transformed));
   }
 }
 
 /**
@@ -658,16 +659,17 @@ AsyncCompositionManager::ApplyAsyncConte
 
     mIsFirstPaint = false;
     mLayersUpdated = false;
 
     // Transform the current local clip by this APZC's async transform. If we're
     // using containerful scrolling, then the clip is not part of the scrolled
     // frame and should not be transformed.
     if (asyncClip && !metrics.UsesContainerScrolling()) {
+      MOZ_ASSERT(asyncTransform.Is2D());
       asyncClip = Some(TransformTo<ParentLayerPixel>(asyncTransform, *asyncClip));
     }
 
     // Combine the local clip with the ancestor scrollframe clip. This is not
     // included in the async transform above, since the ancestor clip should not
     // move with this APZC.
     if (metrics.HasClipRect()) {
       ParentLayerIntRect clip = metrics.ClipRect();
--- a/ipc/glue/BackgroundChildImpl.cpp
+++ b/ipc/glue/BackgroundChildImpl.cpp
@@ -5,16 +5,17 @@
 #include "BackgroundChildImpl.h"
 
 #include "ActorsChild.h" // IndexedDB
 #include "BroadcastChannelChild.h"
 #include "ServiceWorkerManagerChild.h"
 #include "FileDescriptorSetChild.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/dom/PBlobChild.h"
+#include "mozilla/dom/asmjscache/AsmJSCache.h"
 #include "mozilla/dom/cache/ActorUtils.h"
 #include "mozilla/dom/indexedDB/PBackgroundIDBFactoryChild.h"
 #include "mozilla/dom/ipc/BlobChild.h"
 #include "mozilla/dom/MessagePortChild.h"
 #include "mozilla/dom/NuwaChild.h"
 #include "mozilla/ipc/PBackgroundTestChild.h"
 #include "mozilla/layout/VsyncChild.h"
 #include "mozilla/net/PUDPSocketChild.h"
@@ -50,16 +51,17 @@ public:
 } // namespace
 
 namespace mozilla {
 namespace ipc {
 
 using mozilla::dom::UDPSocketChild;
 using mozilla::net::PUDPSocketChild;
 
+using mozilla::dom::asmjscache::PAsmJSCacheEntryChild;
 using mozilla::dom::cache::PCacheChild;
 using mozilla::dom::cache::PCacheStorageChild;
 using mozilla::dom::cache::PCacheStreamControlChild;
 using mozilla::dom::PNuwaChild;
 
 // -----------------------------------------------------------------------------
 // BackgroundChildImpl::ThreadLocal
 // -----------------------------------------------------------------------------
@@ -362,16 +364,34 @@ bool
 BackgroundChildImpl::DeallocPNuwaChild(PNuwaChild* aActor)
 {
   MOZ_ASSERT(aActor);
 
   delete aActor;
   return true;
 }
 
+PAsmJSCacheEntryChild*
+BackgroundChildImpl::AllocPAsmJSCacheEntryChild(
+                               const dom::asmjscache::OpenMode& aOpenMode,
+                               const dom::asmjscache::WriteParams& aWriteParams,
+                               const PrincipalInfo& aPrincipalInfo)
+{
+  MOZ_CRASH("PAsmJSCacheEntryChild actors should be manually constructed!");
+}
+
+bool
+BackgroundChildImpl::DeallocPAsmJSCacheEntryChild(PAsmJSCacheEntryChild* aActor)
+{
+  MOZ_ASSERT(aActor);
+
+  dom::asmjscache::DeallocEntryChild(aActor);
+  return true;
+}
+
 } // namespace ipc
 } // namespace mozilla
 
 bool
 TestChild::Recv__delete__(const nsCString& aTestArg)
 {
   MOZ_RELEASE_ASSERT(aTestArg == mTestArg,
                      "BackgroundTest message was corrupted!");
--- a/ipc/glue/BackgroundChildImpl.h
+++ b/ipc/glue/BackgroundChildImpl.h
@@ -123,16 +123,24 @@ protected:
   virtual bool
   DeallocPMessagePortChild(PMessagePortChild* aActor) override;
 
   virtual PNuwaChild*
   AllocPNuwaChild() override;
 
   virtual bool
   DeallocPNuwaChild(PNuwaChild* aActor) override;
+
+  virtual PAsmJSCacheEntryChild*
+  AllocPAsmJSCacheEntryChild(const dom::asmjscache::OpenMode& aOpenMode,
+                             const dom::asmjscache::WriteParams& aWriteParams,
+                             const PrincipalInfo& aPrincipalInfo) override;
+
+  virtual bool
+  DeallocPAsmJSCacheEntryChild(PAsmJSCacheEntryChild* aActor) override;
 };
 
 class BackgroundChildImpl::ThreadLocal final
 {
   friend class nsAutoPtr<ThreadLocal>;
 
 public:
   nsAutoPtr<mozilla::dom::indexedDB::ThreadLocal> mIndexedDBThreadLocal;
--- a/ipc/glue/BackgroundParentImpl.cpp
+++ b/ipc/glue/BackgroundParentImpl.cpp
@@ -8,16 +8,17 @@
 #include "FileDescriptorSetParent.h"
 #include "mozilla/AppProcessChecker.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/dom/ContentParent.h"
 #include "mozilla/dom/NuwaParent.h"
 #include "mozilla/dom/PBlobParent.h"
 #include "mozilla/dom/MessagePortParent.h"
 #include "mozilla/dom/ServiceWorkerRegistrar.h"
+#include "mozilla/dom/asmjscache/AsmJSCache.h"
 #include "mozilla/dom/cache/ActorUtils.h"
 #include "mozilla/dom/indexedDB/ActorsParent.h"
 #include "mozilla/dom/ipc/BlobParent.h"
 #include "mozilla/ipc/BackgroundParent.h"
 #include "mozilla/ipc/BackgroundUtils.h"
 #include "mozilla/ipc/PBackgroundSharedTypes.h"
 #include "mozilla/ipc/PBackgroundTestParent.h"
 #include "mozilla/layout/VsyncParent.h"
@@ -33,16 +34,17 @@
 
 #ifdef DISABLE_ASSERTS_FOR_FUZZING
 #define ASSERT_UNLESS_FUZZING(...) do { } while (0)
 #else
 #define ASSERT_UNLESS_FUZZING(...) MOZ_ASSERT(false)
 #endif
 
 using mozilla::ipc::AssertIsOnBackgroundThread;
+using mozilla::dom::asmjscache::PAsmJSCacheEntryParent;
 using mozilla::dom::cache::PCacheParent;
 using mozilla::dom::cache::PCacheStorageParent;
 using mozilla::dom::cache::PCacheStreamControlParent;
 using mozilla::dom::MessagePortParent;
 using mozilla::dom::PMessagePortParent;
 using mozilla::dom::PNuwaParent;
 using mozilla::dom::NuwaParent;
 using mozilla::dom::UDPSocketParent;
@@ -614,16 +616,40 @@ BackgroundParentImpl::RecvMessagePortFor
                                                 const uint32_t& aSequenceID)
 {
   AssertIsInMainProcess();
   AssertIsOnBackgroundThread();
 
   return MessagePortParent::ForceClose(aUUID, aDestinationUUID, aSequenceID);
 }
 
+PAsmJSCacheEntryParent*
+BackgroundParentImpl::AllocPAsmJSCacheEntryParent(
+                               const dom::asmjscache::OpenMode& aOpenMode,
+                               const dom::asmjscache::WriteParams& aWriteParams,
+                               const PrincipalInfo& aPrincipalInfo)
+{
+  AssertIsInMainProcess();
+  AssertIsOnBackgroundThread();
+
+  return
+    dom::asmjscache::AllocEntryParent(aOpenMode, aWriteParams, aPrincipalInfo);
+}
+
+bool
+BackgroundParentImpl::DeallocPAsmJSCacheEntryParent(
+                                                 PAsmJSCacheEntryParent* aActor)
+{
+  AssertIsInMainProcess();
+  AssertIsOnBackgroundThread();
+
+  dom::asmjscache::DeallocEntryParent(aActor);
+  return true;
+}
+
 } // namespace ipc
 } // namespace mozilla
 
 void
 TestParent::ActorDestroy(ActorDestroyReason aWhy)
 {
   AssertIsInMainProcess();
   AssertIsOnBackgroundThread();
--- a/ipc/glue/BackgroundParentImpl.h
+++ b/ipc/glue/BackgroundParentImpl.h
@@ -146,14 +146,22 @@ protected:
 
   virtual bool
   DeallocPMessagePortParent(PMessagePortParent* aActor) override;
 
   virtual bool
   RecvMessagePortForceClose(const nsID& aUUID,
                             const nsID& aDestinationUUID,
                             const uint32_t& aSequenceID) override;
+
+  virtual PAsmJSCacheEntryParent*
+  AllocPAsmJSCacheEntryParent(const dom::asmjscache::OpenMode& aOpenMode,
+                              const dom::asmjscache::WriteParams& aWriteParams,
+                              const PrincipalInfo& aPrincipalInfo) override;
+
+  virtual bool
+  DeallocPAsmJSCacheEntryParent(PAsmJSCacheEntryParent* aActor) override;
 };
 
 } // namespace ipc
 } // namespace mozilla
 
 #endif // mozilla_ipc_backgroundparentimpl_h__
--- a/ipc/glue/MessageChannel.cpp
+++ b/ipc/glue/MessageChannel.cpp
@@ -990,17 +990,16 @@ MessageChannel::Send(Message* aMsg, Mess
 bool
 MessageChannel::Call(Message* aMsg, Message* aReply)
 {
     AssertWorkerThread();
     mMonitor->AssertNotCurrentThreadOwns();
 
 #ifdef OS_WIN
     SyncStackFrame frame(this, true);
-    NeuteredWindowRegion neuteredRgn(mFlags & REQUIRE_DEFERRED_MESSAGE_PROTECTION);
 #endif
 
     // This must come before MonitorAutoLock, as its destructor acquires the
     // monitor lock.
     CxxStackFrame cxxframe(*this, OUT_MESSAGE, aMsg);
 
     MonitorAutoLock lock(*mMonitor);
     if (!Connected()) {
@@ -1030,19 +1029,26 @@ MessageChannel::Call(Message* aMsg, Mess
         // trying another loop iteration will be futile because
         // channel state will have been cleared
         if (!Connected()) {
             ReportConnectionError("MessageChannel::Call");
             return false;
         }
 
 #ifdef OS_WIN
-        /* We should pump messages at this point to ensure that the IPC peer
-           does not become deadlocked on a pending inter-thread SendMessage() */
-        neuteredRgn.PumpOnce();
+        // We need to limit the scoped of neuteredRgn to this spot in the code.
+        // Window neutering can't be enabled during some plugin calls because
+        // we then risk the neutered window procedure being subclassed by a
+        // plugin.
+        {
+            NeuteredWindowRegion neuteredRgn(mFlags & REQUIRE_DEFERRED_MESSAGE_PROTECTION);
+            /* We should pump messages at this point to ensure that the IPC peer
+               does not become deadlocked on a pending inter-thread SendMessage() */
+            neuteredRgn.PumpOnce();
+        }
 #endif
 
         // Now might be the time to process a message deferred because of race
         // resolution.
         MaybeUndeferIncall();
 
         // Wait for an event to occur.
         while (!InterruptEventOccurred()) {
--- a/ipc/glue/PBackground.ipdl
+++ b/ipc/glue/PBackground.ipdl
@@ -1,12 +1,13 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+include protocol PAsmJSCacheEntry;
 include protocol PBackgroundIDBFactory;
 include protocol PBackgroundTest;
 include protocol PBlob;
 include protocol PBroadcastChannel;
 include protocol PCache;
 include protocol PCacheStorage;
 include protocol PCacheStreamControl;
 include protocol PFileDescriptorSet;
@@ -15,24 +16,33 @@ include protocol PNuwa;
 include protocol PServiceWorkerManager;
 include protocol PUDPSocket;
 include protocol PVsync;
 
 include DOMTypes;
 include PBackgroundSharedTypes;
 include PBackgroundIDBSharedTypes;
 
-using mozilla::dom::cache::Namespace from "mozilla/dom/cache/Types.h";
 include "mozilla/dom/cache/IPCUtils.h";
 
+using mozilla::dom::cache::Namespace
+  from "mozilla/dom/cache/Types.h";
+
+using mozilla::dom::asmjscache::OpenMode
+  from "mozilla/dom/asmjscache/AsmJSCache.h";
+
+using mozilla::dom::asmjscache::WriteParams
+  from "mozilla/dom/asmjscache/AsmJSCache.h";
+
 namespace mozilla {
 namespace ipc {
 
 sync protocol PBackground
 {
+  manages PAsmJSCacheEntry;
   manages PBackgroundIDBFactory;
   manages PBackgroundTest;
   manages PBlob;
   manages PBroadcastChannel;
   manages PCache;
   manages PCacheStorage;
   manages PCacheStreamControl;
   manages PFileDescriptorSet;
@@ -61,16 +71,20 @@ parent:
   PCacheStorage(Namespace aNamespace, PrincipalInfo aPrincipalInfo);
 
   PMessagePort(nsID uuid, nsID destinationUuid, uint32_t sequenceId);
 
   PNuwa();
 
   MessagePortForceClose(nsID uuid, nsID destinationUuid, uint32_t sequenceId);
 
+  PAsmJSCacheEntry(OpenMode openMode,
+                   WriteParams write,
+                   PrincipalInfo principalInfo);
+
 child:
   PCache();
   PCacheStreamControl();
 
 both:
   PBlob(BlobConstructorParams params);
 
   PFileDescriptorSet(FileDescriptor fd);
--- a/ipc/glue/WindowsMessageLoop.cpp
+++ b/ipc/glue/WindowsMessageLoop.cpp
@@ -889,34 +889,39 @@ StopNeutering()
   // we received during the IPC call. The hook will unset itself as soon as
   // someone else calls GetMessage, PeekMessage, or runs code that generates
   // a "nonqueued" message.
   ::ScheduleDeferredMessageRun();
   MessageChannel::SetIsPumpingMessages(false);
 }
 
 NeuteredWindowRegion::NeuteredWindowRegion(bool aDoNeuter MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
-  : mNeuteredByThis(!gWindowHook)
+  : mNeuteredByThis(!gWindowHook && aDoNeuter)
 {
   MOZ_GUARD_OBJECT_NOTIFIER_INIT;
-  if (aDoNeuter && mNeuteredByThis) {
+  if (mNeuteredByThis) {
     StartNeutering();
   }
 }
 
 NeuteredWindowRegion::~NeuteredWindowRegion()
 {
   if (gWindowHook && mNeuteredByThis) {
     StopNeutering();
   }
 }
 
 void
 NeuteredWindowRegion::PumpOnce()
 {
+  if (!gWindowHook) {
+    // This should be a no-op if nothing has been neutered.
+    return;
+  }
+
   MSG msg = {0};
   // Pump any COM messages so that we don't hang due to STA marshaling.
   if (gCOMWindow && ::PeekMessageW(&msg, gCOMWindow, 0, 0, PM_REMOVE)) {
       ::TranslateMessage(&msg);
       ::DispatchMessageW(&msg);
   }
   // Expunge any nonqueued messages on the current thread.
   ::PeekMessageW(&msg, nullptr, 0, 0, PM_NOREMOVE);
--- a/js/src/NamespaceImports.h
+++ b/js/src/NamespaceImports.h
@@ -95,16 +95,17 @@ using JS::CallArgs;
 using JS::CallNonGenericMethod;
 using JS::CallReceiver;
 using JS::CompileOptions;
 using JS::IsAcceptableThis;
 using JS::NativeImpl;
 using JS::OwningCompileOptions;
 using JS::ReadOnlyCompileOptions;
 using JS::SourceBufferHolder;
+using JS::TransitiveCompileOptions;
 
 using JS::Rooted;
 using JS::RootedFunction;
 using JS::RootedId;
 using JS::RootedObject;
 using JS::RootedScript;
 using JS::RootedString;
 using JS::RootedSymbol;
--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -2706,16 +2706,66 @@ SetARMHwCapFlags(JSContext* cx, unsigned
 
     jit::ParseARMHwCapFlags(flagsList.ptr());
 #endif
 
     args.rval().setUndefined();
     return true;
 }
 
+static bool
+GetLcovInfo(JSContext* cx, unsigned argc, Value* vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+
+    if (args.length() > 1) {
+        JS_ReportError(cx, "Wrong number of arguments");
+        return false;
+    }
+
+    RootedObject global(cx);
+    if (args.hasDefined(0)) {
+        global = ToObject(cx, args[0]);
+        if (!global) {
+            JS_ReportError(cx, "First argument should be an object");
+            return false;
+        }
+        global = CheckedUnwrap(global);
+        if (!global) {
+            JS_ReportError(cx, "Permission denied to access global");
+            return false;
+        }
+        if (!global->is<GlobalObject>()) {
+            JS_ReportError(cx, "Argument must be a global object");
+            return false;
+        }
+    } else {
+        global = JS::CurrentGlobalOrNull(cx);
+    }
+
+    size_t length = 0;
+    char* content = nullptr;
+    {
+        AutoCompartment ac(cx, global);
+        content = js::GetCodeCoverageSummary(cx, &length);
+    }
+
+    if (!content)
+        return false;
+
+    JSString* str = JS_NewStringCopyN(cx, content, length);
+    free(content);
+
+    if (!str)
+        return false;
+
+    args.rval().setString(str);
+    return true;
+}
+
 static const JSFunctionSpecWithHelp TestingFunctions[] = {
     JS_FN_HELP("gc", ::GC, 0, 0,
 "gc([obj] | 'compartment' [, 'shrinking'])",
 "  Run the garbage collector. When obj is given, GC only its compartment.\n"
 "  If 'compartment' is given, GC any compartments that were scheduled for\n"
 "  GC via schedulegc.\n"
 "  If 'shrinking' is passed as the optional second argument, perform a\n"
 "  shrinking GC rather than a normal GC."),
@@ -3148,16 +3198,21 @@ gc::ZealModeHelpText),
 "    'minorGC' - run a nursery collection\n"
 "    'majorGC' - run a major collection, nesting up to a given 'depth'\n"),
 
     JS_FN_HELP("setARMHwCapFlags", SetARMHwCapFlags, 1, 0,
 "setARMHwCapFlags(\"flag1,flag2 flag3\")",
 "  On non-ARM, no-op. On ARM, set the hardware capabilities. The list of \n"
 "  flags is available by calling this function with \"help\" as the flag's name"),
 
+    JS_FN_HELP("getLcovInfo", GetLcovInfo, 1, 0,
+"getLcovInfo(global)",
+"  Generate LCOV tracefile for the given compartment.  If no global are provided then\n"
+"  the current global is used as the default one.\n"),
+
     JS_FS_HELP_END
 };
 
 static const JSPropertySpec TestingProperties[] = {
     JS_PSG("timesAccessed", TimesAccessed, 0),
     JS_PS_END
 };
 
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -5804,23 +5804,23 @@ BytecodeEmitter::emitFunction(ParseNode*
                 fun->lazyScript()->setTreatAsRunOnce();
         } else {
             SharedContext* outersc = sc;
 
             if (outersc->isFunctionBox() && outersc->asFunctionBox()->mightAliasLocals())
                 funbox->setMightAliasLocals();      // inherit mightAliasLocals from parent
             MOZ_ASSERT_IF(outersc->strict(), funbox->strictScript);
 
-            // Inherit most things (principals, version, etc) from the parent.
+            // Inherit most things (principals, version, etc) from the
+            // parent.  Use default values for the rest.
             Rooted<JSScript*> parent(cx, script);
-            CompileOptions options(cx, parser->options());
-            options.setMutedErrors(parent->mutedErrors())
-                   .setNoScriptRval(false)
-                   .setForEval(false)
-                   .setVersion(parent->getVersion());
+            MOZ_ASSERT(parent->getVersion() == parser->options().version);
+            MOZ_ASSERT(parent->mutedErrors() == parser->options().mutedErrors());
+            const TransitiveCompileOptions& transitiveOptions = parser->options();
+            CompileOptions options(cx, transitiveOptions);
 
             Rooted<JSObject*> enclosingScope(cx, innermostStaticScope());
             Rooted<JSObject*> sourceObject(cx, script->sourceObject());
             Rooted<JSScript*> script(cx, JSScript::Create(cx, enclosingScope, false, options,
                                                           sourceObject,
                                                           funbox->bufStart, funbox->bufEnd));
             if (!script)
                 return false;
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/coverage/simple.js
@@ -0,0 +1,215 @@
+// |jit-test| --code-coverage;
+
+// Currently the Jit integration has a few issues, let's keep this test
+// case deterministic.
+//
+//  - Baseline OSR increments the loop header twice.
+//  - Ion is not updating any counter yet.
+//
+if (getJitCompilerOptions()["ion.warmup.trigger"] != 30)
+  setJitCompilerOption("ion.warmup.trigger", 30);
+if (getJitCompilerOptions()["baseline.warmup.trigger"] != 10)
+  setJitCompilerOption("baseline.warmup.trigger", 10);
+
+function checkLcov(fun) {
+  var keys = [ "TN", "SF", "FN", "FNDA", "FNF", "FNH", "BRDA", "BRF", "BRH", "DA", "LF", "LH" ];
+  function startsWithKey(s) {
+    for (k of keys) {
+      if (s.startsWith(k))
+        return true;
+    }
+    return false;
+  };
+
+  // Extract the body of the function, as the code to be executed.
+  var source = fun.toSource();
+  source = source.slice(source.indexOf('{') + 1, source.lastIndexOf('}'));
+
+  // Extract comment starting with the previous keys, as a reference of the
+  // output expected from getLcovInfo.
+  var lcovRef = [];
+  var currLine = 0;
+  var currFun = "<badfunction>";
+  for (var line of source.split('\n')) {
+    currLine++;
+    for (var comment of line.split("//").slice(1)) {
+      if (!startsWithKey(comment))
+        continue;
+      comment = comment.trim();
+      if (comment.startsWith("FN:"))
+        currFun = comment.split(',')[1];
+      comment = comment.replace('$', currLine);
+      comment = comment.replace('%', currFun);
+      lcovRef.push(comment);
+    }
+  }
+
+  // Evaluate the code, and generate the Lcov result from the execution.
+  var g = newGlobal();
+  g.eval(source);
+  var lcovResRaw = getLcovInfo(g);
+
+  // Check that all the lines are present the result.
+  var lcovRes = lcovResRaw.split('\n');
+  for (ref of lcovRef) {
+    if (lcovRes.indexOf(ref) == -1) {
+      print("Cannot find `" + ref + "` in the following Lcov result:\n", lcovResRaw);
+      print("In the following source:\n", source);
+      assertEq(true, false);
+    }
+  }
+}
+
+checkLcov(function () { //FN:$,top-level //FNDA:1,%
+  ",".split(','); //DA:$,1
+  //FNF:1
+  //FNH:1
+  //LF:1
+  //LH:1
+});
+
+checkLcov(function () { //FN:$,top-level //FNDA:1,%
+  function f() {    //FN:$,f
+    ",".split(','); //DA:$,0
+  }
+  ",".split(',');   //DA:$,1
+  //FNF:2
+  //FNH:1
+  //LF:2
+  //LH:1
+});
+
+checkLcov(function () { //FN:$,top-level //FNDA:1,%
+  function f() {    //FN:$,f //FNDA:1,%
+    ",".split(','); //DA:$,1
+  }
+  f();              //DA:$,1
+  //FNF:2
+  //FNH:2
+  //LF:2
+  //LH:2
+});
+
+checkLcov(function () { //FN:$,top-level //FNDA:1,%
+  var l = ",".split(','); //DA:$,1
+  if (l.length == 3)      //DA:$,1
+    l.push('');           //DA:$,0
+  else
+    l.pop();              //DA:$,1
+  //FNF:1
+  //FNH:1
+  //LF:4
+  //LH:3
+  //BRF:1
+  //BRH:1
+});
+
+checkLcov(function () { //FN:$,top-level //FNDA:1,%
+  var l = ",".split(','); //DA:$,1
+  if (l.length == 2)      //DA:$,1
+    l.push('');           //DA:$,1
+  else
+    l.pop();              //DA:$,0
+  //FNF:1
+  //FNH:1
+  //LF:4
+  //LH:3
+  //BRF:1
+  //BRH:1
+});
+
+checkLcov(function () { //FN:$,top-level //FNDA:1,%
+  var l = ",".split(','); //DA:$,1
+  if (l.length == 2)      //DA:$,1
+    l.push('');           //DA:$,1
+  else {
+    if (l.length == 1)    //DA:$,0
+      l.pop();            //DA:$,0
+  }
+  //FNF:1
+  //FNH:1
+  //LF:5
+  //LH:3
+  //BRF:2
+  //BRH:1
+});
+
+checkLcov(function () { //FN:$,top-level //FNDA:1,%
+  function f(i) { //FN:$,f //FNDA:2,%
+    var x = 0;    //DA:$,2
+    while (i--) { // Currently OSR wrongly count the loop header twice.
+                  // So instead of DA:$,12 , we have DA:$,13 .
+      x += i;     //DA:$,10
+      x = x / 2;  //DA:$,10
+    }
+    return x;     //DA:$,2
+    //BRF:1
+    //BRH:1
+  }
+
+  f(5);           //DA:$,1
+  f(5);           //DA:$,1
+  //FNF:2
+  //FNH:2
+});
+
+checkLcov(function () { //FN:$,top-level //FNDA:1,%
+  try {                     //DA:$,1
+    var l = ",".split(','); //DA:$,1
+    if (l.length == 2) {    //DA:$,1 // BRDA:$,0
+      l.push('');           //DA:$,1
+      throw l;              //DA:$,1
+    }
+    l.pop();                //DA:$,0
+  } catch (x) {             //DA:$,1
+    x.pop();                //DA:$,1
+  }
+  //FNF:1
+  //FNH:1
+  //LF:9 // Expected LF:8 , Apparently if the first statement is a try, the
+         // statement following the "try{" statement is visited twice.
+  //LH:8 // Expected LH:7
+  //BRF:1
+  //BRH:1
+});
+
+checkLcov(function () { //FN:$,top-level //FNDA:1,%
+  var l = ",".split(',');   //DA:$,1
+  try {                     //DA:$,1
+    try {                   //DA:$,1
+      if (l.length == 2) {  //DA:$,1 // BRDA:$,0
+        l.push('');         //DA:$,1
+        throw l;            //DA:$,1
+      }
+      l.pop();              //DA:$,0 // BRDA:$,-
+    } finally {             //DA:$,1
+      l.pop();              //DA:$,1
+    }
+  } catch (x) {             //DA:$,1
+  }
+  //FNF:1
+  //FNH:1
+  //LF:10
+  //LH:9
+  //BRF:2
+  //BRH:1
+});
+
+checkLcov(function () { //FN:$,top-level //FNDA:1,%
+  function f() {            //FN:$,f //FNDA:1,%
+    throw 1;                //DA:$,1
+    f();                    //DA:$,0
+  }
+  var l = ",".split(',');   //DA:$,1
+  try {                     //DA:$,1
+    f();                    //DA:$,1
+    f();                    //DA:$,0
+  } catch (x) {             //DA:$,1
+  }
+  //FNF:2
+  //FNH:2
+  //LF:7
+  //LH:5
+  //BRF:0
+  //BRH:0
+});
--- a/js/src/jit/BaselineCompiler.cpp
+++ b/js/src/jit/BaselineCompiler.cpp
@@ -803,27 +803,22 @@ BaselineCompiler::emitDebugTrap()
 
     // Add an IC entry for the return offset -> pc mapping.
     return appendICEntry(ICEntry::Kind_DebugTrap, masm.currentOffset());
 }
 
 void
 BaselineCompiler::emitCoverage(jsbytecode* pc)
 {
-    double* counterAddr = &script->getPCCounts(pc).numExec();
-    AllocatableRegisterSet regs(RegisterSet::Volatile());
-    Register counterAddrReg = R2.scratchReg();
-    FloatRegister counter = regs.takeAnyFloat();
-    FloatRegister one = regs.takeAnyFloat();
-
-    masm.movePtr(ImmPtr(counterAddr), counterAddrReg);
-    masm.loadDouble(Address(counterAddrReg, 0), counter);
-    masm.loadConstantDouble(1.0, one);
-    masm.addDouble(one, counter);
-    masm.storeDouble(counter, Address(counterAddrReg, 0));
+    PCCounts* counts = script->maybeGetPCCounts(pc);
+    if (!counts)
+        return;
+
+    uint64_t* counterAddr = &counts->numExec();
+    masm.inc64(AbsoluteAddress(counterAddr));
 }
 
 #ifdef JS_TRACE_LOGGING
 bool
 BaselineCompiler::emitTraceLoggerEnter()
 {
     TraceLoggerThread* logger = TraceLoggerForMainThread(cx->runtime());
     AllocatableRegisterSet regs(RegisterSet::Volatile());
--- a/js/src/jit/JitFrames.cpp
+++ b/js/src/jit/JitFrames.cpp
@@ -688,28 +688,36 @@ ProcessTryNotesBaseline(JSContext* cx, c
 }
 
 static void
 HandleExceptionBaseline(JSContext* cx, const JitFrameIterator& frame, ResumeFromException* rfe,
                         jsbytecode* pc)
 {
     MOZ_ASSERT(frame.isBaselineJS());
 
+    bool frameOk = false;
+    RootedScript script(cx, frame.baselineFrame()->script());
+
+    if (script->hasScriptCounts()) {
+        PCCounts* counts = script->getThrowCounts(pc);
+        // If we failed to allocate, then skip the increment and continue to
+        // handle the exception.
+        if (counts)
+            counts->numExec()++;
+    }
+
     // We may be propagating a forced return from the interrupt
     // callback, which cannot easily force a return.
     if (cx->isPropagatingForcedReturn()) {
         cx->clearPropagatingForcedReturn();
         ForcedReturn(cx, frame, pc, rfe);
         return;
     }
 
-    bool frameOk = false;
-    RootedScript script(cx, frame.baselineFrame()->script());
-
-again:
+  again:
     if (cx->isExceptionPending()) {
         if (!cx->isClosingGenerator()) {
             switch (Debugger::onExceptionUnwind(cx, frame.baselineFrame())) {
               case JSTRAP_ERROR:
                 // Uncatchable exception.
                 MOZ_ASSERT(!cx->isExceptionPending());
                 goto again;
 
@@ -728,18 +736,22 @@ again:
                 MOZ_CRASH("Invalid trap status");
             }
         }
 
         if (script->hasTrynotes()) {
             ScopeIter si(cx, frame.baselineFrame(), pc);
             if (!ProcessTryNotesBaseline(cx, frame, si, rfe, &pc))
                 goto again;
-            if (rfe->kind != ResumeFromException::RESUME_ENTRY_FRAME)
+            if (rfe->kind != ResumeFromException::RESUME_ENTRY_FRAME) {
+                // No need to increment the PCCounts number of execution here,
+                // as the interpreter increments any PCCounts if present.
+                MOZ_ASSERT_IF(script->hasScriptCounts(), script->maybeGetPCCounts(pc));
                 return;
+            }
         }
 
         frameOk = HandleClosingGeneratorReturn(cx, frame.baselineFrame(), frameOk);
         frameOk = Debugger::onLeaveFrame(cx, frame.baselineFrame(), frameOk);
     } else if (script->hasTrynotes()) {
         CloseLiveIteratorsBaselineForUncatchableException(cx, frame, pc);
     }
 
--- a/js/src/jit/MacroAssembler.cpp
+++ b/js/src/jit/MacroAssembler.cpp
@@ -2571,16 +2571,19 @@ MacroAssembler::MacroAssembler(JSContext
 }
 
 void
 MacroAssembler::resetForNewCodeGenerator(TempAllocator& alloc)
 {
     setFramePushed(0);
     moveResolver_.clearTempObjectPool();
     moveResolver_.setAllocator(alloc);
+#ifdef DEBUG
+    debugTrackedRegisters_.clear();
+#endif
 }
 
 MacroAssembler::AfterICSaveLive
 MacroAssembler::icSaveLive(LiveRegisterSet& liveRegs)
 {
     PushRegsInMask(liveRegs);
     AfterICSaveLive aic(framePushed());
     alignFrameForICArguments(aic);
@@ -2867,8 +2870,38 @@ MacroAssembler::callWithABINoProfiler(As
 {
     uint32_t stackAdjust;
     callWithABIPre(&stackAdjust, /* callFromAsmJS = */ true);
     call(imm);
     callWithABIPost(stackAdjust, result);
 }
 
 //}}} check_macroassembler_style
+
+namespace js {
+namespace jit {
+
+#ifdef DEBUG
+template <class RegisterType>
+AutoGenericRegisterScope<RegisterType>::AutoGenericRegisterScope(MacroAssembler& masm, RegisterType reg)
+  : RegisterType(reg), masm_(masm)
+{
+    masm.debugTrackedRegisters_.add(reg);
+}
+
+template AutoGenericRegisterScope<Register>::AutoGenericRegisterScope(MacroAssembler& masm, Register reg);
+template AutoGenericRegisterScope<FloatRegister>::AutoGenericRegisterScope(MacroAssembler& masm, FloatRegister reg);
+#endif // DEBUG
+
+#ifdef DEBUG
+template <class RegisterType>
+AutoGenericRegisterScope<RegisterType>::~AutoGenericRegisterScope()
+{
+    const RegisterType& reg = *dynamic_cast<RegisterType*>(this);
+    masm_.debugTrackedRegisters_.take(reg);
+}
+
+template AutoGenericRegisterScope<Register>::~AutoGenericRegisterScope();
+template AutoGenericRegisterScope<FloatRegister>::~AutoGenericRegisterScope();
+#endif // DEBUG
+
+} // namespace jit
+} // namespace js
--- a/js/src/jit/MacroAssembler.h
+++ b/js/src/jit/MacroAssembler.h
@@ -457,16 +457,27 @@ class MacroAssembler : public MacroAssem
     // Move the stack pointer based on the requested amount.
     void adjustStack(int amount);
     void reserveStack(uint32_t amount) PER_ARCH;
     void freeStack(uint32_t amount);
 
     // Warning: This method does not update the framePushed() counter.
     void freeStack(Register amount);
 
+  private:
+    // ===============================================================
+    // Register allocation fields.
+#ifdef DEBUG
+    friend AutoRegisterScope;
+    friend AutoFloatRegisterScope;
+    // Used to track register scopes for debug builds.
+    // Manipulated by the AutoGenericRegisterScope class.
+    AllocatableRegisterSet debugTrackedRegisters_;
+#endif // DEBUG
+
   public:
     // ===============================================================
     // Simple call functions.
 
     void call(Register reg) PER_SHARED_ARCH;
     void call(const Address& addr) DEFINED_ON(x86_shared);
     void call(Label* label) PER_SHARED_ARCH;
     void call(ImmWord imm) PER_SHARED_ARCH;
--- a/js/src/jit/RegisterSets.h
+++ b/js/src/jit/RegisterSets.h
@@ -369,16 +369,19 @@ class TypedRegisterSet
     }
     static inline TypedRegisterSet NonVolatile() {
         return TypedRegisterSet(T::Codes::AllocatableMask & T::Codes::NonVolatileMask);
     }
 
     bool empty() const {
         return !bits_;
     }
+    void clear() {
+        bits_ = 0;
+    }
 
     bool hasRegisterIndex(T reg) const {
         return !!(bits_ & (SetType(1) << reg.code()));
     }
     bool hasAllocatable(T reg) const {
         return !(~bits_ & reg.alignedOrDominatedAliasedSet());
     }
 
@@ -471,16 +474,20 @@ class RegisterSet {
     }
     static inline RegisterSet Volatile() {
         return RegisterSet(GeneralRegisterSet::Volatile(), FloatRegisterSet::Volatile());
     }
 
     bool empty() const {
         return fpu_.empty() && gpr_.empty();
     }
+    void clear() {
+        fpu_.clear();
+        gpr_.clear();
+    }
     bool emptyGeneral() const {
         return gpr_.empty();
     }
     bool emptyFloat() const {
         return fpu_.empty();
     }
     MOZ_CONSTEXPR GeneralRegisterSet gprs() const {
         return gpr_;
@@ -932,16 +939,19 @@ class CommonRegSet : public SpecializedR
     }
     RegSet& set() {
         return this->Parent::set_;
     }
 
     bool empty() const {
         return this->Parent::set_.empty();
     }
+    void clear() {
+        this->Parent::set_.clear();
+    }
 
     using Parent::add;
     void add(ValueOperand value) {
 #if defined(JS_NUNBOX32)
         add(value.payloadReg());
         add(value.typeReg());
 #elif defined(JS_PUNBOX64)
         add(value.valueReg());
--- a/js/src/jit/Registers.h
+++ b/js/src/jit/Registers.h
@@ -162,12 +162,40 @@ class MachineState
     void write(Register reg, uintptr_t value) const {
         regs_[reg.code()]->r = value;
     }
     const FloatRegisters::RegisterContent* address(FloatRegister reg) const {
         return fpregs_[reg.code()];
     }
 };
 
+class MacroAssembler;
+
+// Declares a register as owned within the scope of the object.
+// In debug mode, owned register state is tracked within the MacroAssembler,
+// and an assert will fire if ownership is conflicting.
+// In contrast to ARM64's UseScratchRegisterScope, this class has no overhead
+// in non-debug builds.
+template <class RegisterType>
+struct AutoGenericRegisterScope : public RegisterType
+{
+    // Prevent MacroAssembler templates from creating copies,
+    // which causes the destructor to fire more than once.
+    AutoGenericRegisterScope(const AutoGenericRegisterScope& other) = delete;
+
+#ifdef DEBUG
+    MacroAssembler& masm_;
+    explicit AutoGenericRegisterScope(MacroAssembler& masm, RegisterType reg);
+    ~AutoGenericRegisterScope();
+#else
+    MOZ_CONSTEXPR explicit AutoGenericRegisterScope(MacroAssembler& masm, RegisterType reg)
+      : RegisterType(reg)
+    { }
+#endif
+};
+
+typedef AutoGenericRegisterScope<Register> AutoRegisterScope;
+typedef AutoGenericRegisterScope<FloatRegister> AutoFloatRegisterScope;
+
 } // namespace jit
 } // namespace js
 
 #endif /* jit_Registers_h */
--- a/js/src/jit/arm/Assembler-arm.h
+++ b/js/src/jit/arm/Assembler-arm.h
@@ -41,16 +41,25 @@ static MOZ_CONSTEXPR_VAR Register r12 = 
 static MOZ_CONSTEXPR_VAR Register ip  = { Registers::ip };
 static MOZ_CONSTEXPR_VAR Register sp  = { Registers::sp };
 static MOZ_CONSTEXPR_VAR Register r14 = { Registers::lr };
 static MOZ_CONSTEXPR_VAR Register lr  = { Registers::lr };
 static MOZ_CONSTEXPR_VAR Register pc  = { Registers::pc };
 
 static MOZ_CONSTEXPR_VAR Register ScratchRegister = {Registers::ip};
 
+// Helper class for ScratchRegister usage. Asserts that only one piece
+// of code thinks it has exclusive ownership of the scratch register.
+struct ScratchRegisterScope : public AutoRegisterScope
+{
+    explicit ScratchRegisterScope(MacroAssembler& masm)
+      : AutoRegisterScope(masm, ScratchRegister)
+    { }
+};
+
 static MOZ_CONSTEXPR_VAR Register OsrFrameReg = r3;
 static MOZ_CONSTEXPR_VAR Register ArgumentsRectifierReg = r8;
 static MOZ_CONSTEXPR_VAR Register CallTempReg0 = r5;
 static MOZ_CONSTEXPR_VAR Register CallTempReg1 = r6;
 static MOZ_CONSTEXPR_VAR Register CallTempReg2 = r7;
 static MOZ_CONSTEXPR_VAR Register CallTempReg3 = r8;
 static MOZ_CONSTEXPR_VAR Register CallTempReg4 = r0;
 static MOZ_CONSTEXPR_VAR Register CallTempReg5 = r1;
@@ -114,16 +123,29 @@ static MOZ_CONSTEXPR_VAR FloatRegister R
 static MOZ_CONSTEXPR_VAR FloatRegister ReturnInt32x4Reg = InvalidFloatReg;
 static MOZ_CONSTEXPR_VAR FloatRegister ReturnFloat32x4Reg = InvalidFloatReg;
 static MOZ_CONSTEXPR_VAR FloatRegister ScratchFloat32Reg = { FloatRegisters::d30, VFPRegister::Single };
 static MOZ_CONSTEXPR_VAR FloatRegister ScratchDoubleReg = { FloatRegisters::d15, VFPRegister::Double };
 static MOZ_CONSTEXPR_VAR FloatRegister ScratchSimdReg = InvalidFloatReg;
 static MOZ_CONSTEXPR_VAR FloatRegister ScratchUIntReg = { FloatRegisters::d15, VFPRegister::UInt };
 static MOZ_CONSTEXPR_VAR FloatRegister ScratchIntReg = { FloatRegisters::d15, VFPRegister::Int };
 
+struct ScratchFloat32Scope : public AutoFloatRegisterScope
+{
+    explicit ScratchFloat32Scope(MacroAssembler& masm)
+      : AutoFloatRegisterScope(masm, ScratchFloat32Reg)
+    { }
+};
+struct ScratchDoubleScope : public AutoFloatRegisterScope
+{
+    explicit ScratchDoubleScope(MacroAssembler& masm)
+      : AutoFloatRegisterScope(masm, ScratchDoubleReg)
+    { }
+};
+
 // A bias applied to the GlobalReg to allow the use of instructions with small
 // negative immediate offsets which doubles the range of global data that can be
 // accessed with a single instruction.
 static const int32_t AsmJSGlobalRegBias = 1024;
 
 // Registers used in the GenerateFFIIonExit Enable Activation block.
 static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegCallee = r4;
 static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegE0 = r0;
--- a/js/src/jit/arm/BaselineIC-arm.cpp
+++ b/js/src/jit/arm/BaselineIC-arm.cpp
@@ -185,18 +185,19 @@ ICBinaryArith_Int32::Compiler::generateS
             Label toUint;
             masm.j(Assembler::LessThan, &toUint);
 
             // Move result and box for return.
             masm.mov(scratchReg, R0.payloadReg());
             EmitReturnFromIC(masm);
 
             masm.bind(&toUint);
-            masm.convertUInt32ToDouble(scratchReg, ScratchDoubleReg);
-            masm.boxDouble(ScratchDoubleReg, R0);
+            ScratchDoubleScope scratchDouble(masm);
+            masm.convertUInt32ToDouble(scratchReg, scratchDouble);
+            masm.boxDouble(scratchDouble, R0);
         } else {
             masm.j(Assembler::LessThan, &failure);
             // Move result for return.
             masm.mov(scratchReg, R0.payloadReg());
         }
         break;
       default:
         MOZ_CRASH("Unhandled op for BinaryArith_Int32.");
--- a/js/src/jit/arm/CodeGenerator-arm.cpp
+++ b/js/src/jit/arm/CodeGenerator-arm.cpp
@@ -189,19 +189,20 @@ CodeGeneratorARM::bailout(LSnapshot* sna
     Label label;
     masm.ma_b(&label);
     bailoutFrom(&label, snapshot);
 }
 
 void
 CodeGeneratorARM::visitOutOfLineBailout(OutOfLineBailout* ool)
 {
-    masm.ma_mov(Imm32(ool->snapshot()->snapshotOffset()), ScratchRegister);
-    masm.ma_push(ScratchRegister); // BailoutStack::padding_
-    masm.ma_push(ScratchRegister); // BailoutStack::snapshotOffset_
+    ScratchRegisterScope scratch(masm);
+    masm.ma_mov(Imm32(ool->snapshot()->snapshotOffset()), scratch);
+    masm.ma_push(scratch); // BailoutStack::padding_
+    masm.ma_push(scratch); // BailoutStack::snapshotOffset_
     masm.ma_b(&deoptLabel_);
 }
 
 void
 CodeGeneratorARM::visitMinMaxD(LMinMaxD* ins)
 {
     FloatRegister first = ToFloatRegister(ins->first());
     FloatRegister second = ToFloatRegister(ins->second());
@@ -541,21 +542,22 @@ CodeGeneratorARM::visitDivI(LDivI* ins)
     MDiv* mir = ins->mir();
 
     Label done;
     divICommon(mir, lhs, rhs, output, ins->snapshot(), done);
 
     if (mir->canTruncateRemainder()) {
         masm.ma_sdiv(lhs, rhs, output);
     } else {
-        masm.ma_sdiv(lhs, rhs, ScratchRegister);
-        masm.ma_mul(ScratchRegister, rhs, temp);
+        ScratchRegisterScope scratch(masm);
+        masm.ma_sdiv(lhs, rhs, scratch);
+        masm.ma_mul(scratch, rhs, temp);
         masm.ma_cmp(lhs, temp);
         bailoutIf(Assembler::NotEqual, ins->snapshot());
-        masm.ma_mov(ScratchRegister, output);
+        masm.ma_mov(scratch, output);
     }
 
     masm.bind(&done);
 }
 
 extern "C" {
     extern MOZ_EXPORT int64_t __aeabi_idivmod(int,int);
     extern MOZ_EXPORT int64_t __aeabi_uidivmod(int,int);
@@ -589,48 +591,57 @@ CodeGeneratorARM::visitSoftDivI(LSoftDiv
     }
 
     masm.bind(&done);
 }
 
 void
 CodeGeneratorARM::visitDivPowTwoI(LDivPowTwoI* ins)
 {
+    MDiv* mir = ins->mir();
     Register lhs = ToRegister(ins->numerator());
     Register output = ToRegister(ins->output());
     int32_t shift = ins->shift();
 
-    if (shift != 0) {
-        MDiv* mir = ins->mir();
-        if (!mir->isTruncated()) {
-            // If the remainder is != 0, bailout since this must be a double.
-            masm.as_mov(ScratchRegister, lsl(lhs, 32 - shift), SetCC);
-            bailoutIf(Assembler::NonZero, ins->snapshot());
+    if (shift == 0) {
+        masm.ma_mov(lhs, output);
+        return;
+    }
+
+    if (!mir->isTruncated()) {
+        // If the remainder is != 0, bailout since this must be a double.
+        {
+            // The bailout code also needs the scratch register.
+            // Here it is only used as a dummy target to set CC flags.
+            ScratchRegisterScope scratch(masm);
+            masm.as_mov(scratch, lsl(lhs, 32 - shift), SetCC);
         }
-
-        if (!mir->canBeNegativeDividend()) {
-            // Numerator is unsigned, so needs no adjusting. Do the shift.
-            masm.as_mov(output, asr(lhs, shift));
-            return;
-        }
+        bailoutIf(Assembler::NonZero, ins->snapshot());
+    }
 
-        // Adjust the value so that shifting produces a correctly rounded result
-        // when the numerator is negative. See 10-1 "Signed Division by a Known
-        // Power of 2" in Henry S. Warren, Jr.'s Hacker's Delight.
-        if (shift > 1) {
-            masm.as_mov(ScratchRegister, asr(lhs, 31));
-            masm.as_add(ScratchRegister, lhs, lsr(ScratchRegister, 32 - shift));
-        } else
-            masm.as_add(ScratchRegister, lhs, lsr(lhs, 32 - shift));
+    if (!mir->canBeNegativeDividend()) {
+        // Numerator is unsigned, so needs no adjusting. Do the shift.
+        masm.as_mov(output, asr(lhs, shift));
+        return;
+    }
 
-        // Do the shift.
-        masm.as_mov(output, asr(ScratchRegister, shift));
+    // Adjust the value so that shifting produces a correctly rounded result
+    // when the numerator is negative. See 10-1 "Signed Division by a Known
+    // Power of 2" in Henry S. Warren, Jr.'s Hacker's Delight.
+    ScratchRegisterScope scratch(masm);
+
+    if (shift > 1) {
+        masm.as_mov(scratch, asr(lhs, 31));
+        masm.as_add(scratch, lhs, lsr(scratch, 32 - shift));
     } else {
-        masm.ma_mov(lhs, output);
+        masm.as_add(scratch, lhs, lsr(lhs, 32 - shift));
     }
+
+    // Do the shift.
+    masm.as_mov(output, asr(scratch, shift));
 }
 
 void
 CodeGeneratorARM::modICommon(MMod* mir, Register lhs, Register rhs, Register output,
                              LSnapshot* snapshot, Label& done)
 {
     // 0/X (with X < 0) is bad because both of these values *should* be doubles,
     // and the result should be -0.0, which cannot be represented in integers.
@@ -941,29 +952,30 @@ CodeGeneratorARM::visitClzI(LClzI* ins)
     masm.ma_clz(input, output);
 }
 
 void
 CodeGeneratorARM::visitPowHalfD(LPowHalfD* ins)
 {
     FloatRegister input = ToFloatRegister(ins->input());
     FloatRegister output = ToFloatRegister(ins->output());
+    ScratchDoubleScope scratch(masm);
 
     Label done;
 
     // Masm.pow(-Infinity, 0.5) == Infinity.
-    masm.ma_vimm(NegativeInfinity<double>(), ScratchDoubleReg);
-    masm.compareDouble(input, ScratchDoubleReg);
-    masm.ma_vneg(ScratchDoubleReg, output, Assembler::Equal);
+    masm.ma_vimm(NegativeInfinity<double>(), scratch);
+    masm.compareDouble(input, scratch);
+    masm.ma_vneg(scratch, output, Assembler::Equal);
     masm.ma_b(&done, Assembler::Equal);
 
     // Math.pow(-0, 0.5) == 0 == Math.pow(0, 0.5).
     // Adding 0 converts any -0 to 0.
-    masm.ma_vimm(0.0, ScratchDoubleReg);
-    masm.ma_vadd(ScratchDoubleReg, input, output);
+    masm.ma_vimm(0.0, scratch);
+    masm.ma_vadd(scratch, input, output);
     masm.ma_vsqrt(output, output);
 
     masm.bind(&done);
 }
 
 MoveOperand
 CodeGeneratorARM::toMoveOperand(LAllocation a) const
 {
@@ -1191,18 +1203,20 @@ CodeGeneratorARM::visitRoundF(LRoundF* l
     // to a clamped case.
     masm.roundf(input, output, &bail, tmp);
     bailoutFrom(&bail, lir->snapshot());
 }
 
 void
 CodeGeneratorARM::emitRoundDouble(FloatRegister src, Register dest, Label* fail)
 {
-    masm.ma_vcvt_F64_I32(src, ScratchDoubleReg);
-    masm.ma_vxfer(ScratchDoubleReg, dest);
+    ScratchDoubleScope scratch(masm);
+
+    masm.ma_vcvt_F64_I32(src, scratch);
+    masm.ma_vxfer(scratch, dest);
     masm.ma_cmp(dest, Imm32(0x7fffffff));
     masm.ma_cmp(dest, Imm32(0x80000000), Assembler::NotEqual);
     masm.ma_b(fail, Assembler::Equal);
 }
 
 void
 CodeGeneratorARM::visitTruncateDToInt32(LTruncateDToInt32* ins)
 {
@@ -1289,26 +1303,25 @@ CodeGeneratorARM::visitBox(LBox* box)
 }
 
 void
 CodeGeneratorARM::visitBoxFloatingPoint(LBoxFloatingPoint* box)
 {
     const LDefinition* payload = box->getDef(PAYLOAD_INDEX);
     const LDefinition* type = box->getDef(TYPE_INDEX);
     const LAllocation* in = box->getOperand(0);
+    FloatRegister reg = ToFloatRegister(in);
 
-    FloatRegister reg = ToFloatRegister(in);
     if (box->type() == MIRType_Float32) {
-        masm.convertFloat32ToDouble(reg, ScratchFloat32Reg);
-        reg = ScratchFloat32Reg;
+        ScratchFloat32Scope scratch(masm);
+        masm.convertFloat32ToDouble(reg, scratch);
+        masm.ma_vxfer(VFPRegister(scratch), ToRegister(payload), ToRegister(type));
+    } else {
+        masm.ma_vxfer(VFPRegister(reg), ToRegister(payload), ToRegister(type));
     }
-
-    //masm.as_vxfer(ToRegister(payload), ToRegister(type),
-    //              VFPRegister(ToFloatRegister(in)), Assembler::FloatToCore);
-    masm.ma_vxfer(VFPRegister(reg), ToRegister(payload), ToRegister(type));
 }
 
 void
 CodeGeneratorARM::visitUnbox(LUnbox* unbox)
 {
     // Note that for unbox, the type and payload indexes are switched on the
     // inputs.
     MUnbox* mir = unbox->mir();
@@ -1912,22 +1925,24 @@ CodeGeneratorARM::visitAsmJSCompareExcha
     Scalar::Type viewType = mir->accessType();
     Register ptr = ToRegister(ins->ptr());
     Register oldval = ToRegister(ins->oldval());
     Register newval = ToRegister(ins->newval());
 
     MOZ_ASSERT(ToRegister(ins->output()) == ReturnReg);
 
     masm.setupAlignedABICall();
-    masm.ma_mov(Imm32(viewType), ScratchRegister);
-    masm.passABIArg(ScratchRegister);
-    masm.passABIArg(ptr);
-    masm.passABIArg(oldval);
-    masm.passABIArg(newval);
-
+    {
+        ScratchRegisterScope scratch(masm);
+        masm.ma_mov(Imm32(viewType), scratch);
+        masm.passABIArg(scratch);
+        masm.passABIArg(ptr);
+        masm.passABIArg(oldval);
+        masm.passABIArg(newval);
+    }
     masm.callWithABI(AsmJSImm_AtomicCmpXchg);
 }
 
 void
 CodeGeneratorARM::visitAsmJSAtomicExchangeHeap(LAsmJSAtomicExchangeHeap* ins)
 {
     MAsmJSAtomicExchangeHeap* mir = ins->mir();
     Scalar::Type vt = mir->accessType();
@@ -1965,18 +1980,21 @@ CodeGeneratorARM::visitAsmJSAtomicExchan
     const MAsmJSAtomicExchangeHeap* mir = ins->mir();
     Scalar::Type viewType = mir->accessType();
     Register ptr = ToRegister(ins->ptr());
     Register value = ToRegister(ins->value());
 
     MOZ_ASSERT(ToRegister(ins->output()) == ReturnReg);
 
     masm.setupAlignedABICall();
-    masm.ma_mov(Imm32(viewType), ScratchRegister);
-    masm.passABIArg(ScratchRegister);
+    {
+        ScratchRegisterScope scratch(masm);
+        masm.ma_mov(Imm32(viewType), scratch);
+        masm.passABIArg(scratch);
+    }
     masm.passABIArg(ptr);
     masm.passABIArg(value);
 
     masm.callWithABI(AsmJSImm_AtomicXchg);
 }
 
 void
 CodeGeneratorARM::visitAsmJSAtomicBinopHeap(LAsmJSAtomicBinopHeap* ins)
@@ -2062,18 +2080,21 @@ void
 CodeGeneratorARM::visitAsmJSAtomicBinopCallout(LAsmJSAtomicBinopCallout* ins)
 {
     const MAsmJSAtomicBinopHeap* mir = ins->mir();
     Scalar::Type viewType = mir->accessType();
     Register ptr = ToRegister(ins->ptr());
     Register value = ToRegister(ins->value());
 
     masm.setupAlignedABICall();
-    masm.ma_mov(Imm32(viewType), ScratchRegister);
-    masm.passABIArg(ScratchRegister);
+    {
+        ScratchRegisterScope scratch(masm);
+        masm.move32(Imm32(viewType), scratch);
+        masm.passABIArg(scratch);
+    }
     masm.passABIArg(ptr);
     masm.passABIArg(value);
 
     switch (mir->operation()) {
       case AtomicFetchAddOp:
         masm.callWithABI(AsmJSImm_AtomicFetchAdd);
         break;
       case AtomicFetchSubOp:
--- a/js/src/jit/arm/MacroAssembler-arm.cpp
+++ b/js/src/jit/arm/MacroAssembler-arm.cpp
@@ -54,33 +54,36 @@ MacroAssemblerARM::convertInt32ToDouble(
     as_vxfer(src, InvalidReg, dest.sintOverlay(),
              CoreToFloat);
     as_vcvt(dest, dest.sintOverlay());
 }
 
 void
 MacroAssemblerARM::convertInt32ToDouble(const Address& src, FloatRegister dest)
 {
-    ma_vldr(src, ScratchDoubleReg);
-    as_vcvt(dest, VFPRegister(ScratchDoubleReg).sintOverlay());
+    ScratchDoubleScope scratch(asMasm());
+    ma_vldr(src, scratch);
+    as_vcvt(dest, VFPRegister(scratch).sintOverlay());
 }
 
 void
 MacroAssemblerARM::convertInt32ToDouble(const BaseIndex& src, FloatRegister dest)
 {
     Register base = src.base;
     uint32_t scale = Imm32::ShiftOf(src.scale).value;
 
+    ScratchRegisterScope scratch(asMasm());
+
     if (src.offset != 0) {
-        ma_mov(base, ScratchRegister);
-        base = ScratchRegister;
+        ma_mov(base, scratch);
+        base = scratch;
         ma_add(Imm32(src.offset), base);
     }
-    ma_ldr(DTRAddr(base, DtrRegImmShift(src.index, LSL, scale)), ScratchRegister);
-    convertInt32ToDouble(ScratchRegister, dest);
+    ma_ldr(DTRAddr(base, DtrRegImmShift(src.index, LSL, scale)), scratch);
+    convertInt32ToDouble(scratch, dest);
 }
 
 void
 MacroAssemblerARM::convertUInt32ToDouble(Register src, FloatRegister dest_)
 {
     // Direct conversions aren't possible.
     VFPRegister dest = VFPRegister(dest_);
     as_vxfer(src, InvalidReg, dest.uintOverlay(), CoreToFloat);
@@ -108,40 +111,44 @@ void MacroAssemblerARM::convertDoubleToF
 // was clamped to INT_MIN/INT_MAX, and we can test it. NOTE: if the value
 // really was supposed to be INT_MAX / INT_MIN then it will be wrong.
 //
 // 2. Convert the floating point value to an integer, if it did not fit, then it
 // set one or two bits in the fpcsr. Check those.
 void
 MacroAssemblerARM::branchTruncateDouble(FloatRegister src, Register dest, Label* fail)
 {
-    FloatRegister ScratchSIntReg = ScratchDoubleReg.sintOverlay();
-    ma_vcvt_F64_I32(src, ScratchSIntReg);
-    ma_vxfer(ScratchSIntReg, dest);
+    ScratchDoubleScope scratch(asMasm());
+    FloatRegister scratchSIntReg = scratch.sintOverlay();
+
+    ma_vcvt_F64_I32(src, scratchSIntReg);
+    ma_vxfer(scratchSIntReg, dest);
     ma_cmp(dest, Imm32(0x7fffffff));
     ma_cmp(dest, Imm32(0x80000000), Assembler::NotEqual);
     ma_b(fail, Assembler::Equal);
 }
 
 // Checks whether a double is representable as a 32-bit integer. If so, the
 // integer is written to the output register. Otherwise, a bailout is taken to
 // the given snapshot. This function overwrites the scratch float register.
 void
 MacroAssemblerARM::convertDoubleToInt32(FloatRegister src, Register dest,
                                         Label* fail, bool negativeZeroCheck)
 {
     // Convert the floating point value to an integer, if it did not fit, then
     // when we convert it *back* to a float, it will have a different value,
     // which we can test.
-    FloatRegister ScratchSIntReg = ScratchDoubleReg.sintOverlay();
-    ma_vcvt_F64_I32(src, ScratchSIntReg);
+    ScratchDoubleScope scratchDouble(asMasm());
+    FloatRegister scratchSIntReg = scratchDouble.sintOverlay();
+
+    ma_vcvt_F64_I32(src, scratchSIntReg);
     // Move the value into the dest register.
-    ma_vxfer(ScratchSIntReg, dest);
-    ma_vcvt_I32_F64(ScratchSIntReg, ScratchDoubleReg);
-    ma_vcmp(src, ScratchDoubleReg);
+    ma_vxfer(scratchSIntReg, dest);
+    ma_vcvt_I32_F64(scratchSIntReg, scratchDouble);
+    ma_vcmp(src, scratchDouble);
     as_vmrs(pc);
     ma_b(fail, Assembler::VFP_NotEqualOrUnordered);
 
     if (negativeZeroCheck) {
         ma_cmp(dest, Imm32(0));
         // Test and bail for -0.0, when integer result is 0. Move the top word
         // of the double into the output reg, if it is non-zero, then the
         // original value was -0.0.
@@ -158,24 +165,26 @@ void
 MacroAssemblerARM::convertFloat32ToInt32(FloatRegister src, Register dest,
                                          Label* fail, bool negativeZeroCheck)
 {
     // Converting the floating point value to an integer and then converting it
     // back to a float32 would not work, as float to int32 conversions are
     // clamping (e.g. float(INT32_MAX + 1) would get converted into INT32_MAX
     // and then back to float(INT32_MAX + 1)).  If this ever happens, we just
     // bail out.
-    FloatRegister ScratchSIntReg = ScratchFloat32Reg.sintOverlay();
+    ScratchFloat32Scope scratchFloat(asMasm());
+
+    FloatRegister ScratchSIntReg = scratchFloat.sintOverlay();
     ma_vcvt_F32_I32(src, ScratchSIntReg);
 
     // Store the result
     ma_vxfer(ScratchSIntReg, dest);
 
-    ma_vcvt_I32_F32(ScratchSIntReg, ScratchFloat32Reg);
-    ma_vcmp(src, ScratchFloat32Reg);
+    ma_vcvt_I32_F32(ScratchSIntReg, scratchFloat);
+    ma_vcmp(src, scratchFloat);
     as_vmrs(pc);
     ma_b(fail, Assembler::VFP_NotEqualOrUnordered);
 
     // Bail out in the clamped cases.
     ma_cmp(dest, Imm32(0x7fffffff));
     ma_cmp(dest, Imm32(0x80000000), Assembler::NotEqual);
     ma_b(fail, Assembler::Equal);
 
@@ -186,43 +195,48 @@ MacroAssemblerARM::convertFloat32ToInt32
         // -0.0
         as_vxfer(dest, InvalidReg, VFPRegister(src).singleOverlay(), FloatToCore, Assembler::Equal, 0);
         ma_cmp(dest, Imm32(0x80000000), Assembler::Equal);
         ma_b(fail, Assembler::Equal);
     }
 }
 
 void
-MacroAssemblerARM::convertFloat32ToDouble(FloatRegister src, FloatRegister dest) {
+MacroAssemblerARM::convertFloat32ToDouble(FloatRegister src, FloatRegister dest)
+{
     MOZ_ASSERT(dest.isDouble());
     MOZ_ASSERT(src.isSingle());
     as_vcvt(VFPRegister(dest), VFPRegister(src).singleOverlay());
 }
 
 void
-MacroAssemblerARM::branchTruncateFloat32(FloatRegister src, Register dest, Label* fail) {
-    ma_vcvt_F32_I32(src, ScratchFloat32Reg.sintOverlay());
-    ma_vxfer(ScratchFloat32Reg, dest);
+MacroAssemblerARM::branchTruncateFloat32(FloatRegister src, Register dest, Label* fail)
+{
+    ScratchFloat32Scope scratch(asMasm());
+    ma_vcvt_F32_I32(src, scratch.sintOverlay());
+    ma_vxfer(scratch, dest);
     ma_cmp(dest, Imm32(0x7fffffff));
     ma_cmp(dest, Imm32(0x80000000), Assembler::NotEqual);
     ma_b(fail, Assembler::Equal);
 }
 
 void
-MacroAssemblerARM::convertInt32ToFloat32(Register src, FloatRegister dest) {
+MacroAssemblerARM::convertInt32ToFloat32(Register src, FloatRegister dest)
+{
     // Direct conversions aren't possible.
-    as_vxfer(src, InvalidReg, dest.sintOverlay(),
-             CoreToFloat);
+    as_vxfer(src, InvalidReg, dest.sintOverlay(), CoreToFloat);
     as_vcvt(dest.singleOverlay(), dest.sintOverlay());
 }
 
 void
-MacroAssemblerARM::convertInt32ToFloat32(const Address& src, FloatRegister dest) {
-    ma_vldr(src, ScratchFloat32Reg);
-    as_vcvt(dest, VFPRegister(ScratchFloat32Reg).sintOverlay());
+MacroAssemblerARM::convertInt32ToFloat32(const Address& src, FloatRegister dest)
+{
+    ScratchFloat32Scope scratch(asMasm());
+    ma_vldr(src, scratch);
+    as_vcvt(dest, VFPRegister(scratch).sintOverlay());
 }
 
 void
 MacroAssemblerARM::addDouble(FloatRegister src, FloatRegister dest)
 {
     ma_vadd(dest, src, dest);
 }
 
@@ -248,49 +262,50 @@ void
 MacroAssemblerARM::negateDouble(FloatRegister reg)
 {
     ma_vneg(reg, reg);
 }
 
 void
 MacroAssemblerARM::inc64(AbsoluteAddress dest)
 {
+    ScratchRegisterScope scratch(asMasm());
 
     ma_strd(r0, r1, EDtrAddr(sp, EDtrOffImm(-8)), PreIndex);
 
-    ma_mov(Imm32((int32_t)dest.addr), ScratchRegister);
-
-    ma_ldrd(EDtrAddr(ScratchRegister, EDtrOffImm(0)), r0, r1);
+    ma_mov(Imm32((int32_t)dest.addr), scratch);
+    ma_ldrd(EDtrAddr(scratch, EDtrOffImm(0)), r0, r1);
 
     ma_add(Imm32(1), r0, SetCC);
     ma_adc(Imm32(0), r1, LeaveCC);
 
-    ma_strd(r0, r1, EDtrAddr(ScratchRegister, EDtrOffImm(0)));
-
+    ma_strd(r0, r1, EDtrAddr(scratch, EDtrOffImm(0)));
     ma_ldrd(EDtrAddr(sp, EDtrOffImm(8)), r0, r1, PostIndex);
-
 }
 
 bool
 MacroAssemblerARM::alu_dbl(Register src1, Imm32 imm, Register dest, ALUOp op,
                            SBit s, Condition c)
 {
     if ((s == SetCC && ! condsAreSafe(op)) || !can_dbl(op))
         return false;
     ALUOp interop = getDestVariant(op);
     Imm8::TwoImm8mData both = Imm8::EncodeTwoImms(imm.value);
     if (both.fst.invalid)
         return false;
+
+    ScratchRegisterScope scratch(asMasm());
+
     // For the most part, there is no good reason to set the condition codes for
     // the first instruction. We can do better things if the second instruction
     // doesn't have a dest, such as check for overflow by doing first operation
     // don't do second operation if first operation overflowed. This preserves
     // the overflow condition code. Unfortunately, it is horribly brittle.
-    as_alu(ScratchRegister, src1, Operand2(both.fst), interop, LeaveCC, c);
-    as_alu(dest, ScratchRegister, Operand2(both.snd), op, s, c);
+    as_alu(scratch, src1, Operand2(both.fst), interop, LeaveCC, c);
+    as_alu(dest, scratch, Operand2(both.snd), op, s, c);
     return true;
 }
 
 
 void
 MacroAssemblerARM::ma_alu(Register src1, Imm32 imm, Register dest,
                           ALUOp op,
                           SBit s, Condition c)
@@ -385,36 +400,38 @@ MacroAssemblerARM::ma_alu(Register src1,
     if (alu_dbl(src1, imm, dest, op, s, c))
         return;
 
     // And try with its negative.
     if (negOp != OpInvalid &&
         alu_dbl(src1, negImm, negDest, negOp, s, c))
         return;
 
+    ScratchRegisterScope scratch(asMasm());
+
     // Well, damn. We can use two 16 bit mov's, then do the op or we can do a
     // single load from a pool then op.
     if (HasMOVWT()) {
         // Try to load the immediate into a scratch register then use that
-        as_movw(ScratchRegister, Imm16(imm.value & 0xffff), c);
+        as_movw(scratch, Imm16(imm.value & 0xffff), c);
         if ((imm.value >> 16) != 0)
-            as_