Merge m-c to cedar
authorPhil Ringnalda <philringnalda@gmail.com>
Sat, 17 Jan 2015 18:45:26 -0800
changeset 326726 fd859bff31fd66d399b4360e56a9e79575cac351
parent 326725 336eba646adc2da1ffa4b47aed565042e67bbfcb (current diff)
parent 237675 0c454540fc2b709e1b32456be700ebcfa8713093 (diff)
child 326727 7b186fd1105cab6d49e551329fbbea6dc765ee87
push id10169
push userdminor@mozilla.com
push dateThu, 28 Jan 2016 13:10:48 +0000
milestone38.0a1
Merge m-c to cedar
dom/network/interfaces/nsIDOMTCPServerSocket.idl
dom/network/interfaces/nsIDOMTCPSocket.idl
js/src/tests/ecma_5/strict/function-name.js
memory/mozalloc/VolatileBuffer.h
memory/mozalloc/VolatileBufferAshmem.cpp
memory/mozalloc/VolatileBufferFallback.cpp
memory/mozalloc/VolatileBufferOSX.cpp
memory/mozalloc/VolatileBufferWindows.cpp
memory/mozalloc/tests/TestVolatileBuffer.cpp
memory/mozalloc/tests/moz.build
--- a/CLOBBER
+++ b/CLOBBER
@@ -17,9 +17,9 @@
 #
 # Modifying this file will now automatically clobber the buildbot machines \o/
 #
 
 # Are you updating CLOBBER because you think it's needed for your WebIDL
 # changes to stick? As of bug 928195, this shouldn't be necessary! Please
 # don't change CLOBBER for WebIDL changes any more.
 
-Bug 1118618's backout needed a clobber
+Bug 1121297 - Converted VolatileBuffer's CPP tests to GTests
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -210,16 +210,17 @@ pref("content.sink.perf_parse_time", 500
 // Maximum scripts runtime before showing an alert
 // Disable the watchdog thread for B2G. See bug 870043 comment 31.
 pref("dom.use_watchdog", false);
 
 // The slow script dialog can be triggered from inside the JS engine as well,
 // ensure that those calls don't accidentally trigger the dialog.
 pref("dom.max_script_run_time", 0);
 pref("dom.max_chrome_script_run_time", 0);
+pref("dom.max_child_script_run_time", 0);
 
 // plugins
 pref("plugin.disable", true);
 pref("dom.ipc.plugins.enabled", true);
 
 // product URLs
 // The breakpad report server to link to in about:crashes
 pref("breakpad.reportURL", "https://crash-stats.mozilla.com/report/index/");
--- 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="e0c735ec89df011ea7dd435087a9045ecff9ff9e">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="8922318d56a95ae04e3e97bdf6a09880140e7805"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="0f65b258bceddd9d479b3c027d9bd234c1e99aaf"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="049c281ad212bf528b2af8fc246b0dd0c9f97415"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <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="c28e606f7656de3a3a8808b68eb048528397d5a7"/>
--- 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="df362ace56338da8173d30d3e09e08c42c1accfa">
     <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="8922318d56a95ae04e3e97bdf6a09880140e7805"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="0f65b258bceddd9d479b3c027d9bd234c1e99aaf"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="049c281ad212bf528b2af8fc246b0dd0c9f97415"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="d5d3f93914558b6f168447b805cd799c8233e300"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="6fa7a4936414ceb4055fd27f7a30e76790f834fb"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="c28e606f7656de3a3a8808b68eb048528397d5a7"/>
   <!-- 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="0e94c080bee081a50aa2097527b0b40852f9143f">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="8922318d56a95ae04e3e97bdf6a09880140e7805"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="0f65b258bceddd9d479b3c027d9bd234c1e99aaf"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="049c281ad212bf528b2af8fc246b0dd0c9f97415"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="c28e606f7656de3a3a8808b68eb048528397d5a7"/>
   <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="e0c735ec89df011ea7dd435087a9045ecff9ff9e">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="8922318d56a95ae04e3e97bdf6a09880140e7805"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="0f65b258bceddd9d479b3c027d9bd234c1e99aaf"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="049c281ad212bf528b2af8fc246b0dd0c9f97415"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <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="c28e606f7656de3a3a8808b68eb048528397d5a7"/>
--- 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="df362ace56338da8173d30d3e09e08c42c1accfa">
     <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="8922318d56a95ae04e3e97bdf6a09880140e7805"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="0f65b258bceddd9d479b3c027d9bd234c1e99aaf"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="049c281ad212bf528b2af8fc246b0dd0c9f97415"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="d5d3f93914558b6f168447b805cd799c8233e300"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="6fa7a4936414ceb4055fd27f7a30e76790f834fb"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="c28e606f7656de3a3a8808b68eb048528397d5a7"/>
   <!-- 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="e0c735ec89df011ea7dd435087a9045ecff9ff9e">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="8922318d56a95ae04e3e97bdf6a09880140e7805"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="0f65b258bceddd9d479b3c027d9bd234c1e99aaf"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="049c281ad212bf528b2af8fc246b0dd0c9f97415"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <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="c28e606f7656de3a3a8808b68eb048528397d5a7"/>
--- a/b2g/config/flame/sources.xml
+++ b/b2g/config/flame/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="0e94c080bee081a50aa2097527b0b40852f9143f">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="8922318d56a95ae04e3e97bdf6a09880140e7805"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="0f65b258bceddd9d479b3c027d9bd234c1e99aaf"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="049c281ad212bf528b2af8fc246b0dd0c9f97415"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="c28e606f7656de3a3a8808b68eb048528397d5a7"/>
   <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="e95b4ce22c825da44d14299e1190ea39a5260bde"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="471afab478649078ad7c75ec6b252481a59e19b8"/>
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,9 +1,9 @@
 {
     "git": {
         "git_revision": "", 
         "remote": "", 
         "branch": ""
     }, 
-    "revision": "69e6f863a1c3f323c3725eebe888dfc9e87295ae", 
+    "revision": "9afe83aea4c5b5ca1161f3901bfb6118aa5c5600", 
     "repo_path": "integration/gaia-central"
 }
--- a/b2g/config/hamachi/sources.xml
+++ b/b2g/config/hamachi/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="df362ace56338da8173d30d3e09e08c42c1accfa">
     <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="8922318d56a95ae04e3e97bdf6a09880140e7805"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="0f65b258bceddd9d479b3c027d9bd234c1e99aaf"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="049c281ad212bf528b2af8fc246b0dd0c9f97415"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="c28e606f7656de3a3a8808b68eb048528397d5a7"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform_bionic" path="bionic" remote="b2g" revision="1a2a32eda22ef2cd18f57f423a5e7b22a105a6f8"/>
   <project name="platform/bootable/recovery" path="bootable/recovery" revision="746bc48f34f5060f90801925dcdd964030c1ab6d"/>
--- a/b2g/config/helix/sources.xml
+++ b/b2g/config/helix/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="df362ace56338da8173d30d3e09e08c42c1accfa">
     <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="8922318d56a95ae04e3e97bdf6a09880140e7805"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="0f65b258bceddd9d479b3c027d9bd234c1e99aaf"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="049c281ad212bf528b2af8fc246b0dd0c9f97415"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform_bionic" path="bionic" remote="b2g" revision="1a2a32eda22ef2cd18f57f423a5e7b22a105a6f8"/>
--- 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="0e94c080bee081a50aa2097527b0b40852f9143f">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="8922318d56a95ae04e3e97bdf6a09880140e7805"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="0f65b258bceddd9d479b3c027d9bd234c1e99aaf"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="049c281ad212bf528b2af8fc246b0dd0c9f97415"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="c28e606f7656de3a3a8808b68eb048528397d5a7"/>
   <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/wasabi/sources.xml
+++ b/b2g/config/wasabi/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="ics_chocolate_rb4.2" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="df362ace56338da8173d30d3e09e08c42c1accfa">
     <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="8922318d56a95ae04e3e97bdf6a09880140e7805"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="0f65b258bceddd9d479b3c027d9bd234c1e99aaf"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="049c281ad212bf528b2af8fc246b0dd0c9f97415"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="c28e606f7656de3a3a8808b68eb048528397d5a7"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1799,10 +1799,16 @@ pref("print.enable_e10s_testing", true);
 #ifdef NIGHTLY_BUILD
 // Enable e10s add-on interposition by default.
 pref("extensions.interposition.enabled", true);
 pref("extensions.interposition.prefetching", true);
 #endif
 
 pref("browser.defaultbrowser.notificationbar", false);
 
-// How many milliseconds to wait for a CPOW response from the child process.
-pref("dom.ipc.cpow.timeout", 0);
+// How often to check for CPOW timeouts. CPOWs are only timed out by
+// the hang monitor.
+pref("dom.ipc.cpow.timeout", 500);
+
+// Enable e10s hang monitoring (slow script checking and plugin hang
+// detection).
+pref("dom.ipc.processHangMonitor", true);
+pref("dom.ipc.reportProcessHangs", true);
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -144,16 +144,19 @@ XPCOMUtils.defineLazyGetter(this, "Brows
 });
 
 XPCOMUtils.defineLazyModuleGetter(this, "Social",
   "resource:///modules/Social.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "PageThumbs",
   "resource://gre/modules/PageThumbs.jsm");
 
+XPCOMUtils.defineLazyModuleGetter(this, "ProcessHangMonitor",
+  "resource:///modules/ProcessHangMonitor.jsm");
+
 #ifdef MOZ_SAFE_BROWSING
 XPCOMUtils.defineLazyModuleGetter(this, "SafeBrowsing",
   "resource://gre/modules/SafeBrowsing.jsm");
 #endif
 
 XPCOMUtils.defineLazyModuleGetter(this, "gCustomizationTabPreloader",
   "resource:///modules/CustomizationTabPreloader.jsm", "CustomizationTabPreloader");
 
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -329,16 +329,36 @@
            noautofocus="true"/>
 
     <panel id="loop-panel"
            class="loop-panel social-panel"
            type="arrow"
            orient="horizontal"
            hidden="true"/>
 
+    <menupopup id="processHangOptions"
+               onpopupshowing="ProcessHangMonitor.refreshMenu(window);">
+      <menuitem id="processHangTerminateScript"
+                oncommand="ProcessHangMonitor.terminateScript(window)"
+                accesskey="&processHang.terminateScript.accessKey;"
+                label="&processHang.terminateScript.label;"/>
+      <menuitem id="processHangDebugScript"
+                oncommand="ProcessHangMonitor.debugScript(window)"
+                accesskey="&processHang.debugScript.accessKey;"
+                label="&processHang.debugScript.label;"/>
+      <menuitem id="processHangTerminatePlugin"
+                oncommand="ProcessHangMonitor.terminatePlugin(window)"
+                accesskey="&processHang.terminatePlugin.accessKey;"
+                label="&processHang.terminatePlugin.label;"/>
+      <menuitem id="processHangTerminateProcess"
+                oncommand="ProcessHangMonitor.terminateProcess(window)"
+                accesskey="&processHang.terminateProcess.accessKey;"
+                label="&processHang.terminateProcess.label;"/>
+    </menupopup>
+
     <menupopup id="toolbar-context-menu"
                onpopupshowing="onViewToolbarsPopupShowing(event, document.getElementById('viewToolbarsMenuSeparator'));">
       <menuitem oncommand="gCustomizeMode.addToPanel(document.popupNode)"
                 accesskey="&customizeMenu.moveToPanel.accesskey;"
                 label="&customizeMenu.moveToPanel.label;"
                 contexttype="toolbaritem"
                 class="customize-context-moveToPanel"/>
       <menuitem oncommand="gCustomizeMode.removeFromArea(document.popupNode)"
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -1487,16 +1487,20 @@
             } else {
               tab.removeAttribute("remote");
               aBrowser.messageManager.sendAsyncMessage("Browser:AppTab", { isAppTab: tab.pinned })
             }
 
             if (wasActive)
               aBrowser.focus();
 
+            let evt = document.createEvent("Events");
+            evt.initEvent("TabRemotenessChange", true, false);
+            tab.dispatchEvent(evt);
+
             return true;
           ]]>
         </body>
       </method>
 
       <method name="updateBrowserRemotenessByURL">
         <parameter name="aBrowser"/>
         <parameter name="aURL"/>
--- a/browser/base/content/urlbarBindings.xml
+++ b/browser/base/content/urlbarBindings.xml
@@ -919,31 +919,34 @@
         <parameter name="aEvent"/>
         <body><![CDATA[
           // Ignore all right-clicks
           if (aEvent.button == 2)
             return;
 
           var controller = this.view.QueryInterface(Components.interfaces.nsIAutoCompleteController);
 
+          var searchBar = BrowserSearch.searchBar;
+          var popupForSearchBar = searchBar && searchBar.textbox == this.mInput;
+          if (popupForSearchBar) {
+            searchBar.telemetrySearchDetails = {
+              index: controller.selection.currentIndex,
+              kind: "mouse"
+            };
+          }
+
           // Check for unmodified left-click, and use default behavior
-          var searchBar = BrowserSearch.searchBar;
-          searchBar.telemetrySearchDetails = {
-            index: controller.selection.currentIndex,
-            kind: "mouse"
-          };
-
           if (aEvent.button == 0 && !aEvent.shiftKey && !aEvent.ctrlKey &&
               !aEvent.altKey && !aEvent.metaKey) {
             controller.handleEnter(true);
             return;
           }
 
           // Check for middle-click or modified clicks on the search bar
-          if (searchBar && searchBar.textbox == this.mInput) {
+          if (popupForSearchBar) {
             // Handle search bar popup clicks
             var search = controller.getValueAt(this.selectedIndex);
 
             // close the autocomplete popup and revert the entered search term
             this.closePopup();
             controller.handleEscape();
 
             // open the search results according to the clicking subtlety
--- a/browser/components/nsBrowserGlue.js
+++ b/browser/components/nsBrowserGlue.js
@@ -54,16 +54,19 @@ XPCOMUtils.defineLazyModuleGetter(this, 
                                   "resource://gre/modules/NewTabUtils.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "CustomizationTabPreloader",
                                   "resource:///modules/CustomizationTabPreloader.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "PdfJs",
                                   "resource://pdf.js/PdfJs.jsm");
 
+XPCOMUtils.defineLazyModuleGetter(this, "ProcessHangMonitor",
+                                  "resource:///modules/ProcessHangMonitor.jsm");
+
 #ifdef NIGHTLY_BUILD
 XPCOMUtils.defineLazyModuleGetter(this, "ShumwayUtils",
                                   "resource://shumway/ShumwayUtils.jsm");
 #endif
 
 XPCOMUtils.defineLazyModuleGetter(this, "webrtcUI",
                                   "resource:///modules/webrtcUI.jsm");
 
@@ -755,16 +758,18 @@ BrowserGlue.prototype = {
     if (WINTASKBAR_CONTRACTID in Cc &&
         Cc[WINTASKBAR_CONTRACTID].getService(Ci.nsIWinTaskbar).available) {
       let temp = {};
       Cu.import("resource:///modules/WindowsJumpLists.jsm", temp);
       temp.WinTaskbarJumpList.startup();
     }
 #endif
 
+    ProcessHangMonitor.init();
+
     // A channel for "remote troubleshooting" code...
     let channel = new WebChannel("remote-troubleshooting", "remote-troubleshooting");
     channel.listen((id, data, target) => {
       if (data.command == "request") {
         let {Troubleshoot} = Cu.import("resource://gre/modules/Troubleshoot.jsm", {});
         Troubleshoot.snapshot(data => {
           // for privacy we remove crash IDs and all preferences (but bug 1091944
           // exists to expose prefs once we are confident of privacy implications)
--- a/browser/devtools/framework/gDevTools.jsm
+++ b/browser/devtools/framework/gDevTools.jsm
@@ -849,70 +849,88 @@ let gDevToolsBrowser = {
    * Hook the JS debugger tool to the "Debug Script" button of the slow script
    * dialog.
    */
   setSlowScriptDebugHandler: function DT_setSlowScriptDebugHandler() {
     let debugService = Cc["@mozilla.org/dom/slow-script-debug;1"]
                          .getService(Ci.nsISlowScriptDebug);
     let tm = Cc["@mozilla.org/thread-manager;1"].getService(Ci.nsIThreadManager);
 
-    debugService.activationHandler = function(aWindow) {
-      let chromeWindow = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
-                                .getInterface(Ci.nsIWebNavigation)
-                                .QueryInterface(Ci.nsIDocShellTreeItem)
-                                .rootTreeItem
-                                .QueryInterface(Ci.nsIInterfaceRequestor)
-                                .getInterface(Ci.nsIDOMWindow)
-                                .QueryInterface(Ci.nsIDOMChromeWindow);
-      let target = devtools.TargetFactory.forTab(chromeWindow.gBrowser.selectedTab);
+    function slowScriptDebugHandler(aTab, aCallback) {
+      let target = devtools.TargetFactory.forTab(aTab);
 
-      let setupFinished = false;
       gDevTools.showToolbox(target, "jsdebugger").then(toolbox => {
         let threadClient = toolbox.getCurrentPanel().panelWin.gThreadClient;
 
         // Break in place, which means resuming the debuggee thread and pausing
         // right before the next step happens.
         switch (threadClient.state) {
           case "paused":
             // When the debugger is already paused.
             threadClient.breakOnNext();
-            setupFinished = true;
+            aCallback();
             break;
           case "attached":
             // When the debugger is already open.
             threadClient.interrupt(() => {
               threadClient.breakOnNext();
-              setupFinished = true;
+              aCallback();
             });
             break;
           case "resuming":
             // The debugger is newly opened.
             threadClient.addOneTimeListener("resumed", () => {
               threadClient.interrupt(() => {
                 threadClient.breakOnNext();
-                setupFinished = true;
+                aCallback();
               });
             });
             break;
           default:
             throw Error("invalid thread client state in slow script debug handler: " +
                         threadClient.state);
           }
       });
+    }
+
+    debugService.activationHandler = function(aWindow) {
+      let chromeWindow = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
+                                .getInterface(Ci.nsIWebNavigation)
+                                .QueryInterface(Ci.nsIDocShellTreeItem)
+                                .rootTreeItem
+                                .QueryInterface(Ci.nsIInterfaceRequestor)
+                                .getInterface(Ci.nsIDOMWindow)
+                                .QueryInterface(Ci.nsIDOMChromeWindow);
+
+      let setupFinished = false;
+      slowScriptDebugHandler(chromeWindow.gBrowser.selectedTab,
+                             () => { setupFinished = true; });
 
       // Don't return from the interrupt handler until the debugger is brought
       // up; no reason to continue executing the slow script.
       let utils = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
                          .getInterface(Ci.nsIDOMWindowUtils);
       utils.enterModalState();
       while (!setupFinished) {
         tm.currentThread.processNextEvent(true);
       }
       utils.leaveModalState();
     };
+
+    debugService.remoteActivationHandler = function(aBrowser, aCallback) {
+      let chromeWindow = aBrowser.ownerDocument.defaultView;
+      let tab = chromeWindow.gBrowser.getTabForBrowser(aBrowser);
+      chromeWindow.gBrowser.selected = tab;
+
+      function callback() {
+        aCallback.finishDebuggerStartup();
+      }
+
+      slowScriptDebugHandler(tab, callback);
+    };
   },
 
   /**
    * Unset the slow script debug handler.
    */
   unsetSlowScriptDebugHandler: function DT_unsetSlowScriptDebugHandler() {
     let debugService = Cc["@mozilla.org/dom/slow-script-debug;1"]
                          .getService(Ci.nsISlowScriptDebug);
--- a/browser/devtools/layoutview/view.js
+++ b/browser/devtools/layoutview/view.js
@@ -169,43 +169,33 @@ LayoutView.prototype = {
                  property: "position",
                  value: undefined},
       marginTop: {selector: ".margin.top > span",
                   property: "margin-top",
                   value: undefined},
       marginBottom: {selector: ".margin.bottom > span",
                   property: "margin-bottom",
                   value: undefined},
-      // margin-left is a shorthand for some internal properties,
-      // margin-left-ltr-source and margin-left-rtl-source for example. The
-      // real margin value we want is in margin-left-value
       marginLeft: {selector: ".margin.left > span",
                   property: "margin-left",
-                  realProperty: "margin-left-value",
                   value: undefined},
-      // margin-right behaves the same as margin-left
       marginRight: {selector: ".margin.right > span",
                   property: "margin-right",
-                  realProperty: "margin-right-value",
                   value: undefined},
       paddingTop: {selector: ".padding.top > span",
                   property: "padding-top",
                   value: undefined},
       paddingBottom: {selector: ".padding.bottom > span",
                   property: "padding-bottom",
                   value: undefined},
-      // padding-left behaves the same as margin-left
       paddingLeft: {selector: ".padding.left > span",
                   property: "padding-left",
-                  realProperty: "padding-left-value",
                   value: undefined},
-      // padding-right behaves the same as margin-left
       paddingRight: {selector: ".padding.right > span",
                   property: "padding-right",
-                  realProperty: "padding-right-value",
                   value: undefined},
       borderTop: {selector: ".border.top > span",
                   property: "border-top-width",
                   value: undefined},
       borderBottom: {selector: ".border.bottom > span",
                   property: "border-bottom-width",
                   value: undefined},
       borderLeft: {selector: ".border.left > span",
@@ -260,21 +250,19 @@ LayoutView.prototype = {
     this.reflowFront.off("reflows", this.update);
     this.reflowFront.stop();
   },
 
   /**
    * Called when the user clicks on one of the editable values in the layoutview
    */
   initEditor: function(element, event, dimension) {
-    let { property, realProperty } = dimension;
-    if (!realProperty)
-      realProperty = property;
+    let { property } = dimension;
     let session = new EditingSession(document, this.elementRules);
-    let initialValue = session.getProperty(realProperty);
+    let initialValue = session.getProperty(property);
 
     let editor = new InplaceEditor({
       element: element,
       initial: initialValue,
 
       start: (editor) => {
         editor.elt.parentNode.classList.add("editing");
       },
--- a/browser/devtools/styleinspector/test/browser_ruleview_completion-existing-property_01.js
+++ b/browser/devtools/styleinspector/test/browser_ruleview_completion-existing-property_01.js
@@ -12,27 +12,25 @@ const MAX_ENTRIES = 10;
 // format :
 //  [
 //    what key to press,
 //    expected input box value after keypress,
 //    selectedIndex of the popup,
 //    total items in the popup
 //  ]
 let testData = [
-  ["VK_RIGHT", "border", -1, 0],
-  ["-","border-bottom", 0, 10],
-  ["b","border-bottom", 0, 6],
-  ["VK_BACK_SPACE", "border-b", -1, 0],
-  ["VK_BACK_SPACE", "border-", -1, 0],
-  ["VK_BACK_SPACE", "border", -1, 0],
-  ["VK_BACK_SPACE", "borde", -1, 0],
-  ["VK_BACK_SPACE", "bord", -1, 0],
-  ["VK_BACK_SPACE", "bor", -1, 0],
-  ["VK_BACK_SPACE", "bo", -1, 0],
-  ["VK_BACK_SPACE", "b", -1, 0],
+  ["VK_RIGHT", "font", -1, 0],
+  ["-","font-family", 0, MAX_ENTRIES],
+  ["f","font-family", 0, 2],
+  ["VK_BACK_SPACE", "font-f", -1, 0],
+  ["VK_BACK_SPACE", "font-", -1, 0],
+  ["VK_BACK_SPACE", "font", -1, 0],
+  ["VK_BACK_SPACE", "fon", -1, 0],
+  ["VK_BACK_SPACE", "fo", -1, 0],
+  ["VK_BACK_SPACE", "f", -1, 0],
   ["VK_BACK_SPACE", "", -1, 0],
   ["d", "direction", 0, 3],
   ["VK_DOWN", "display", 1, 3],
   ["VK_DOWN", "dominant-baseline", 2, 3],
   ["VK_DOWN", "direction", 0, 3],
   ["VK_DOWN", "display", 1, 3],
   ["VK_UP", "direction", 0, 3],
   ["VK_UP", "dominant-baseline", 2, 3],
@@ -47,17 +45,17 @@ let testData = [
   ["f", "fill", 0, MAX_ENTRIES],
   ["i", "fill", 0, 4],
   ["VK_LEFT", "fill", -1, 0],
   ["VK_LEFT", "fill", -1, 0],
   ["i", "fiill", -1, 0],
   ["VK_ESCAPE", null, -1, 0],
 ];
 
-let TEST_URL = "data:text/html;charset=utf-8,<h1 style='border: 1px solid red'>Filename" +
+let TEST_URL = "data:text/html;charset=utf-8,<h1 style='font: 24px serif'>Filename" +
                ": browser_bug893965_css_property_completion_existing_property.js</h1>";
 
 add_task(function*() {
   yield addTab(TEST_URL);
   let {toolbox, inspector, view} = yield openRuleView();
 
   info("Selecting the test node");
   yield selectNode("h1", inspector);
--- a/browser/locales/en-US/chrome/browser/browser.dtd
+++ b/browser/locales/en-US/chrome/browser/browser.dtd
@@ -826,8 +826,16 @@ just addresses the organization to follo
 
 <!ENTITY panicButton.view.undoWarning             "This action cannot be undone.">
 <!ENTITY panicButton.view.forgetButton            "Forget!">
 
 <!ENTITY panicButton.thankyou.msg1                "Your recent history is cleared.">
 <!ENTITY panicButton.thankyou.msg2                "Safe browsing!">
 <!ENTITY panicButton.thankyou.buttonlabel         "Thanks!">
 
+<!ENTITY processHang.terminateScript.label        "Stop Script">
+<!ENTITY processHang.terminateScript.accessKey    "S">
+<!ENTITY processHang.debugScript.label            "Debug Script">
+<!ENTITY processHang.debugScript.accessKey        "D">
+<!ENTITY processHang.terminatePlugin.label        "Kill Plugin">
+<!ENTITY processHang.terminatePlugin.accessKey    "P">
+<!ENTITY processHang.terminateProcess.label       "Kill Web Process">
+<!ENTITY processHang.terminateProcess.accessKey   "K">
--- a/browser/locales/en-US/chrome/browser/browser.properties
+++ b/browser/locales/en-US/chrome/browser/browser.properties
@@ -430,16 +430,21 @@ syncPromoNotification.addons.description
 # The final space separates this text from the Learn More link.
 syncPromoNotification.addons-sync-disabled.description=You can use your %S account to synchronize add-ons across multiple devices.\u0020
 
 # Mozilla data reporting notification (Telemetry, Firefox Health Report, etc)
 dataReportingNotification.message       = %1$S automatically sends some data to %2$S so that we can improve your experience.
 dataReportingNotification.button.label  = Choose What I Share
 dataReportingNotification.button.accessKey  = C
 
+# Process hang reporter
+processHang.message = A web page is causing %1$S to run slowly. What would you like to do?
+processHang.button.label = Options
+processHang.button.accessKey = O
+
 # Webapps notification popup
 webapps.install = Install
 webapps.install.accesskey = I
 #LOCALIZATION NOTE (webapps.requestInstall) %1$S is the web app name, %2$S is the site from which the web app is installed
 webapps.requestInstall = Do you want to install "%1$S" from this site (%2$S)?
 webapps.install.success = Application Installed
 webapps.install.inprogress = Installation in progress
 webapps.uninstall = Uninstall
new file mode 100644
--- /dev/null
+++ b/browser/modules/ProcessHangMonitor.jsm
@@ -0,0 +1,309 @@
+/* -*- mode: js; indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+let Cc = Components.classes;
+let Ci = Components.interfaces;
+let Cu = Components.utils;
+
+this.EXPORTED_SYMBOLS = ["ProcessHangMonitor"];
+
+Cu.import("resource://gre/modules/Services.jsm");
+
+/**
+ * This JSM is responsible for observing content process hang reports
+ * and asking the user what to do about them. See nsIHangReport for
+ * the platform interface.
+ */
+
+/**
+ * If a hang hasn't been reported for more than 5 seconds, assume the
+ * content process has gotten unstuck (and hide the hang notification).
+ */
+const HANG_EXPIRATION_TIME = 5000;
+
+let ProcessHangMonitor = {
+  /**
+   * Collection of hang reports that haven't expired or been dismissed
+   * by the user. The keys are nsIHangReports and values keys are
+   * timers. Each time the hang is reported, the timer is refreshed so
+   * it expires after HANG_EXPIRATION_TIME.
+   */
+  _activeReports: new Map(),
+
+  /**
+   * Initialize hang reporting. Called once in the parent process.
+   */
+  init: function() {
+    Services.obs.addObserver(this, "process-hang-report", false);
+    Services.obs.addObserver(this, "xpcom-shutdown", false);
+    Services.ww.registerNotification(this);
+  },
+
+  /**
+   * Terminate JavaScript associated with the hang being reported for
+   * the selected browser in |win|.
+   */
+  terminateScript: function(win) {
+    this.handleUserInput(win, report => report.terminateScript());
+  },
+
+  /**
+   * Start devtools debugger for JavaScript associated with the hang
+   * being reported for the selected browser in |win|.
+   */
+  debugScript: function(win) {
+    this.handleUserInput(win, report => {
+      function callback() {
+        report.endStartingDebugger();
+      }
+
+      report.beginStartingDebugger();
+
+      let svc = Cc["@mozilla.org/dom/slow-script-debug;1"].getService(Ci.nsISlowScriptDebug);
+      let handler = svc.remoteActivationHandler;
+      handler.handleSlowScriptDebug(report.scriptBrowser, callback);
+    });
+  },
+
+  /**
+   * Kill the plugin process causing the hang being reported for the
+   * selected browser in |win|.
+   */
+  terminatePlugin: function(win) {
+    this.handleUserInput(win, report => report.terminatePlugin());
+  },
+
+  /**
+   * Kill the content process causing the hang being reported for the selected
+   * browser in |win|.
+   */
+  terminateProcess: function(win) {
+    this.handleUserInput(win, report => report.terminateProcess());
+  },
+
+  /**
+   * Update the "Options" pop-up menu for the hang notification
+   * associated with the selected browser in |win|. The menu should
+   * display only options that are relevant to the given report.
+   */
+  refreshMenu: function(win) {
+    let report = this.findReport(win.gBrowser.selectedBrowser);
+    if (!report) {
+      return;
+    }
+
+    function setVisible(id, visible) {
+      let item = win.document.getElementById(id);
+      item.hidden = !visible;
+    }
+
+    if (report.hangType == report.SLOW_SCRIPT) {
+      setVisible("processHangTerminateScript", true);
+      setVisible("processHangDebugScript", true);
+      setVisible("processHangTerminatePlugin", false);
+    } else if (report.hangType == report.PLUGIN_HANG) {
+      setVisible("processHangTerminateScript", false);
+      setVisible("processHangDebugScript", false);
+      setVisible("processHangTerminatePlugin", true);
+    }
+  },
+
+  /**
+   * If there is a hang report associated with the selected browser in
+   * |win|, invoke |func| on that report and stop notifying the user
+   * about it.
+   */
+  handleUserInput: function(win, func) {
+    let report = this.findReport(win.gBrowser.selectedBrowser);
+    if (!report) {
+      return;
+    }
+    this.removeReport(report);
+
+    return func(report);
+  },
+
+  observe: function(subject, topic, data) {
+    switch (topic) {
+      case "xpcom-shutdown":
+        Services.obs.removeObserver(this, "xpcom-shutdown");
+        Services.obs.removeObserver(this, "process-hang-report");
+        Services.ww.unregisterNotification(this);
+        break;
+
+      case "process-hang-report":
+        this.reportHang(subject.QueryInterface(Ci.nsIHangReport));
+        break;
+
+      case "domwindowopened":
+        // Install event listeners on the new window in case one of
+        // its tabs is already hung.
+        let win = subject.QueryInterface(Ci.nsIDOMWindow);
+        let listener = (ev) => {
+          win.removeEventListener("load", listener, true);
+          this.updateWindows();
+        };
+        win.addEventListener("load", listener, true);
+        break;
+    }
+  },
+
+  /**
+   * Find any active hang reports for the given <browser> element.
+   */
+  findReport: function(browser) {
+    let frameLoader = browser.QueryInterface(Ci.nsIFrameLoaderOwner).frameLoader;
+    for (let [report, timer] of this._activeReports) {
+      if (report.isReportForBrowser(frameLoader)) {
+        return report;
+      }
+    }
+    return null;
+  },
+
+  /**
+   * Iterate over all XUL windows and ensure that the proper hang
+   * reports are shown for each one. Also install event handlers in
+   * each window to watch for events that would cause a different hang
+   * report to be displayed.
+   */
+  updateWindows: function() {
+    let e = Services.wm.getEnumerator("navigator:browser");
+    while (e.hasMoreElements()) {
+      let win = e.getNext();
+
+      this.updateWindow(win);
+
+      // Only listen for these events if there are active hang reports.
+      if (this._activeReports.size) {
+        this.trackWindow(win);
+      } else {
+        this.untrackWindow(win);
+      }
+    }
+  },
+
+  /**
+   * If there is a hang report for the current tab in |win|, display it.
+   */
+  updateWindow: function(win) {
+    let report = this.findReport(win.gBrowser.selectedBrowser);
+
+    if (report) {
+      this.showNotification(win, report);
+    } else {
+      this.hideNotification(win);
+    }
+  },
+
+  /**
+   * Show the notification for a hang.
+   */
+  showNotification: function(win, report) {
+    let nb = win.document.getElementById("high-priority-global-notificationbox");
+    let notification = nb.getNotificationWithValue("process-hang");
+    if (notification) {
+      return;
+    }
+
+    let bundle = win.gNavigatorBundle;
+    let brandBundle = win.document.getElementById("bundle_brand");
+    let appName = brandBundle.getString("brandShortName");
+    let message = bundle.getFormattedString(
+      "processHang.message",
+      [appName]);
+
+    let buttons = [{
+      label: bundle.getString("processHang.button.label"),
+      accessKey: bundle.getString("processHang.button.accessKey"),
+      popup: "processHangOptions",
+      callback: null,
+    }];
+
+    nb.appendNotification(message, "process-hang",
+                          "chrome://browser/content/aboutRobots-icon.png",
+                          nb.PRIORITY_WARNING_HIGH, buttons);
+  },
+
+  /**
+   * Ensure that no hang notifications are visible in |win|.
+   */
+  hideNotification: function(win) {
+    let nb = win.document.getElementById("high-priority-global-notificationbox");
+    let notification = nb.getNotificationWithValue("process-hang");
+    if (notification) {
+      nb.removeNotification(notification);
+    }
+  },
+
+  /**
+   * Install event handlers on |win| to watch for events that would
+   * cause a different hang report to be displayed.
+   */
+  trackWindow: function(win) {
+    win.gBrowser.tabContainer.addEventListener("TabSelect", this, true);
+    win.gBrowser.tabContainer.addEventListener("TabRemotenessChange", this, true);
+  },
+
+  untrackWindow: function(win) {
+    win.gBrowser.tabContainer.removeEventListener("TabSelect", this, true);
+    win.gBrowser.tabContainer.removeEventListener("TabRemotenessChange", this, true);
+  },
+
+  handleEvent: function(event) {
+    let win = event.target.ownerDocument.defaultView;
+
+    // If a new tab is selected or if a tab changes remoteness, then
+    // we may need to show or hide a hang notification.
+
+    if (event.type == "TabSelect" || event.type == "TabRemotenessChange") {
+      this.updateWindow(win);
+    }
+  },
+
+  /**
+   * Handle a potentially new hang report. If it hasn't been seen
+   * before, show a notification for it in all open XUL windows.
+   */
+  reportHang: function(report) {
+    // If this hang was already reported, then reset the timer for it.
+    if (this._activeReports.has(report)) {
+      let timer = this._activeReports.get(report);
+      timer.cancel();
+      timer.initWithCallback(this, HANG_EXPIRATION_TIME, timer.TYPE_ONE_SHOT);
+      return;
+    }
+
+    // Otherwise create a new timer and display the report.
+    let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
+    timer.initWithCallback(this, HANG_EXPIRATION_TIME, timer.TYPE_ONE_SHOT);
+
+    this._activeReports.set(report, timer);
+    this.updateWindows();
+  },
+
+  /**
+   * Dismiss a hang report because the user closed the notification
+   * for it or the report expired.
+   */
+  removeReport: function(report) {
+    this._activeReports.delete(report);
+    this.updateWindows();
+  },
+
+  /**
+   * Callback for when HANG_EXPIRATION_TIME has elapsed.
+   */
+  notify: function(timer) {
+    for (let [otherReport, otherTimer] of this._activeReports) {
+      if (otherTimer === timer) {
+        this.removeReport(otherReport);
+        break;
+      }
+    }
+  },
+};
--- a/browser/modules/moz.build
+++ b/browser/modules/moz.build
@@ -22,16 +22,17 @@ EXTRA_JS_MODULES += [
     'DirectoryLinksProvider.jsm',
     'E10SUtils.jsm',
     'Feeds.jsm',
     'FormSubmitObserver.jsm',
     'FormValidationHandler.jsm',
     'NetworkPrioritizer.jsm',
     'offlineAppCache.jsm',
     'PanelFrame.jsm',
+    'ProcessHangMonitor.jsm',
     'RemotePrompt.jsm',
     'SitePermissions.jsm',
     'Social.jsm',
     'TabCrashReporter.jsm',
     'WebappManager.jsm',
 ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
--- a/dom/apps/UserCustomizations.jsm
+++ b/dom/apps/UserCustomizations.jsm
@@ -32,29 +32,31 @@ XPCOMUtils.defineLazyServiceGetter(this,
   *  {
   *    "filter": "http://youtube.com",
   *    "css": ["file1.css", "file2.css"],
   *    "scripts": ["script1.js", "script2.js"]
   *  }
   * ]
   */
 
-let debug = Services.prefs.getBoolPref("dom.mozApps.debug")
-  ? (aMsg) => {
-      dump("-*-*- UserCustomizations (" +
+function debug(aMsg) {
+  if (!UserCustomizations._debug) {
+    return;
+  }
+  dump("-*-*- UserCustomizations (" +
            (UserCustomizations._inParent ? "parent" : "child") +
            "): " + aMsg + "\n");
-    }
-  : (aMsg) => {};
+}
 
 function log(aStr) {
   console.logStringMessage(aStr);
 }
 
 this.UserCustomizations = {
+  _debug: false,
   _items: [],
   _loaded : {},   // Keep track per manifestURL of css and scripts loaded.
   _windows: null, // Set of currently opened windows.
   _enabled: false,
 
   _addItem: function(aItem) {
     debug("_addItem: " + uneval(aItem));
     this._items.push(aItem);
--- a/dom/apps/tests/test_app_addons.html
+++ b/dom/apps/tests/test_app_addons.html
@@ -27,22 +27,24 @@ let gGenerator = runTest();
 function go() {
   gGenerator.next();
 }
 
 function continueTest() {
   try {
     gGenerator.next();
   } catch (e if e instanceof StopIteration) {
+    SpecialPowers.debugUserCustomizations(false);
     SimpleTest.finish();
   }
 }
 
 function mozAppsError() {
   ok(false, "mozApps error: " + this.error.name);
+  SpecialPowers.debugUserCustomizations(false);
   SimpleTest.finish();
 }
 
 // Triggers one navigation test to the given page.
 // Waits for alert() messages before tearing down the iframe.
 function openPage(pageURL, messages) {
   info("Navigating to " + pageURL);
   let ifr = document.createElement("iframe");
@@ -84,16 +86,17 @@ function installApp(manifestURL) {
   }
   req.onerror = mozAppsError;
 }
 
 function runTest() {
   // Set up.
   SpecialPowers.setAllAppsLaunchable(true);
   SpecialPowers.allowUnsignedAddons();
+  SpecialPowers.debugUserCustomizations(true);
   SpecialPowers.pushPrefEnv({'set': [
     ["dom.mozBrowserFramesEnabled", true],
     ["dom.apps.customization.enabled", true],
     ]},continueTest);
   yield undefined;
 
   SpecialPowers.pushPermissions(
     [{ "type": "webapps-manage", "allow": 1, "context": document },
--- a/dom/base/SlowScriptDebug.js
+++ b/dom/base/SlowScriptDebug.js
@@ -11,11 +11,14 @@ function SlowScriptDebug() { }
 SlowScriptDebug.prototype = {
   classID: Components.ID("{e740ddb4-18b4-4aac-8ae1-9b0f4320769d}"),
   classDescription: "Slow script debug handler",
   contractID: "@mozilla.org/dom/slow-script-debug;1",
   QueryInterface: XPCOMUtils.generateQI([Components.interfaces.nsISlowScriptDebug]),
 
   get activationHandler()   { return this._activationHandler; },
   set activationHandler(cb) { return this._activationHandler = cb; },
+
+  get remoteActivationHandler()   { return this._remoteActivationHandler; },
+  set remoteActivationHandler(cb) { return this._remoteActivationHandler = cb; },
 };
 
 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([SlowScriptDebug]);
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -2769,28 +2769,20 @@ nsDOMWindowUtils::ComputeAnimationDistan
                                            double* aResult)
 {
   MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
 
   nsresult rv;
   nsCOMPtr<nsIContent> content = do_QueryInterface(aElement, &rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  // Convert direction-dependent properties as appropriate, e.g.,
-  // border-left to border-left-value.
   nsCSSProperty property =
     nsCSSProps::LookupProperty(aProperty, nsCSSProps::eIgnoreEnabledState);
   if (property != eCSSProperty_UNKNOWN && nsCSSProps::IsShorthand(property)) {
-    nsCSSProperty subprop0 = *nsCSSProps::SubpropertyEntryFor(property);
-    if (nsCSSProps::PropHasFlags(subprop0, CSS_PROPERTY_REPORT_OTHER_NAME) &&
-        nsCSSProps::OtherNameFor(subprop0) == property) {
-      property = subprop0;
-    } else {
-      property = eCSSProperty_UNKNOWN;
-    }
+    property = eCSSProperty_UNKNOWN;
   }
 
   NS_ABORT_IF_FALSE(property == eCSSProperty_UNKNOWN ||
                     !nsCSSProps::IsShorthand(property),
                     "should not have shorthand");
 
   StyleAnimationValue v1, v2;
   if (property == eCSSProperty_UNKNOWN ||
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -62,16 +62,17 @@
 #include "mozilla/dom/MessagePortList.h"
 #include "mozilla/dom/ToJSValue.h"
 #include "nsJSPrincipals.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/Debug.h"
 #include "mozilla/EventListenerManager.h"
 #include "mozilla/EventStates.h"
 #include "mozilla/MouseEvents.h"
+#include "mozilla/ProcessHangMonitor.h"
 #include "AudioChannelService.h"
 #include "MessageEvent.h"
 #include "nsAboutProtocolUtils.h"
 #include "nsCharTraits.h" // NS_IS_HIGH/LOW_SURROGATE
 
 // Interfaces Needed
 #include "nsIFrame.h"
 #include "nsCanvasFrame.h"
@@ -10964,27 +10965,55 @@ nsGlobalWindow::ShowSlowScriptDialog()
     return KillSlowScript;
   }
 
   // If our document is not active, just kill the script: we've been unloaded
   if (!HasActiveDocument()) {
     return KillSlowScript;
   }
 
+  // Check if we should offer the option to debug
+  JS::AutoFilename filename;
+  unsigned lineno;
+  bool hasFrame = JS::DescribeScriptedCaller(cx, &filename, &lineno);
+
+  if (XRE_GetProcessType() == GeckoProcessType_Content &&
+      ProcessHangMonitor::Get()) {
+    ProcessHangMonitor::SlowScriptAction action;
+    nsRefPtr<ProcessHangMonitor> monitor = ProcessHangMonitor::Get();
+    nsCOMPtr<nsITabChild> child = do_GetInterface(GetDocShell());
+    action = monitor->NotifySlowScript(child,
+                                       filename.get(),
+                                       lineno);
+    if (action == ProcessHangMonitor::Terminate) {
+      return KillSlowScript;
+    }
+
+    if (action == ProcessHangMonitor::StartDebugger) {
+      // Spin a nested event loop so that the debugger in the parent can fetch
+      // any information it needs. Once the debugger has started, return to the
+      // script.
+      nsRefPtr<nsGlobalWindow> outer = GetOuterWindowInternal();
+      outer->EnterModalState();
+      while (!monitor->IsDebuggerStartupComplete()) {
+        NS_ProcessNextEvent(nullptr, true);
+      }
+      outer->LeaveModalState();
+      return ContinueSlowScript;
+    }
+
+    return ContinueSlowScriptAndKeepNotifying;
+  }
+
   // Get the nsIPrompt interface from the docshell
   nsCOMPtr<nsIDocShell> ds = GetDocShell();
   NS_ENSURE_TRUE(ds, KillSlowScript);
   nsCOMPtr<nsIPrompt> prompt = do_GetInterface(ds);
   NS_ENSURE_TRUE(prompt, KillSlowScript);
 
-  // Check if we should offer the option to debug
-  JS::AutoFilename filename;
-  unsigned lineno;
-  bool hasFrame = JS::DescribeScriptedCaller(cx, &filename, &lineno);
-
   // Prioritize the SlowScriptDebug interface over JSD1.
   nsCOMPtr<nsISlowScriptDebugCallback> debugCallback;
 
   if (hasFrame) {
     const char *debugCID = "@mozilla.org/dom/slow-script-debug;1";
     nsCOMPtr<nsISlowScriptDebug> debugService = do_GetService(debugCID, &rv);
     if (NS_SUCCEEDED(rv)) {
       debugService->GetActivationHandler(getter_AddRefs(debugCallback));
--- a/dom/base/nsGlobalWindow.h
+++ b/dom/base/nsGlobalWindow.h
@@ -721,16 +721,17 @@ public:
 
   void AllowScriptsToClose()
   {
     mAllowScriptsToClose = true;
   }
 
   enum SlowScriptResponse {
     ContinueSlowScript = 0,
+    ContinueSlowScriptAndKeepNotifying,
     AlwaysContinueSlowScript,
     KillSlowScript
   };
   SlowScriptResponse ShowSlowScriptDialog();
 
 #ifdef MOZ_GAMEPAD
   // Inner windows only.
   void AddGamepad(uint32_t aIndex, mozilla::dom::Gamepad* aGamepad);
--- a/dom/base/nsISlowScriptDebug.idl
+++ b/dom/base/nsISlowScriptDebug.idl
@@ -1,19 +1,34 @@
 /* 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 "nsISupports.idl"
 
 interface nsIDOMWindow;
+interface nsIDOMEventTarget;
 
 [scriptable, function, uuid(f7dbb80c-5d1e-4fd9-b55c-a9ffda4a75b1)]
 interface nsISlowScriptDebugCallback : nsISupports
 {
   void handleSlowScriptDebug(in nsIDOMWindow aWindow);
 };
 
+[scriptable, function, uuid(b1c6ecd0-8fa4-11e4-b4a9-0800200c9a66)]
+interface nsISlowScriptDebugerStartupCallback : nsISupports
+{
+  void finishDebuggerStartup();
+};
+
+[scriptable, function, uuid(dbee14b0-8fa0-11e4-b4a9-0800200c9a66)]
+interface nsISlowScriptDebugRemoteCallback : nsISupports
+{
+  void handleSlowScriptDebug(in nsIDOMEventTarget aBrowser,
+      	                     in nsISlowScriptDebugerStartupCallback aCallback);
+};
+
 [scriptable, uuid(f75d4164-3aa7-4395-ba44-a5f95b2e8427)]
 interface nsISlowScriptDebug : nsISupports
 {
   attribute nsISlowScriptDebugCallback activationHandler;
+  attribute nsISlowScriptDebugRemoteCallback remoteActivationHandler;
 };
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -5,17 +5,17 @@
 # Common codegen classes.
 
 import os
 import re
 import string
 import math
 import textwrap
 
-from WebIDL import BuiltinTypes, IDLBuiltinType, IDLNullValue, IDLSequenceType, IDLType, IDLAttribute, IDLUndefinedValue, IDLEmptySequenceValue, IDLDictionary
+from WebIDL import BuiltinTypes, IDLBuiltinType, IDLNullValue, IDLSequenceType, IDLType, IDLAttribute, IDLInterfaceMember, IDLUndefinedValue, IDLEmptySequenceValue, IDLDictionary
 from Configuration import NoSuchDescriptorError, getTypesFromDescriptor, getTypesFromDictionary, getTypesFromCallback, getAllTypes, Descriptor
 
 AUTOGENERATED_WARNING_COMMENT = \
     "/* THIS FILE IS AUTOGENERATED - DO NOT EDIT */\n\n"
 ADDPROPERTY_HOOK_NAME = '_addProperty'
 FINALIZE_HOOK_NAME = '_finalize'
 OBJECT_MOVED_HOOK_NAME = '_objectMoved'
 CONSTRUCT_HOOK_NAME = '_constructor'
@@ -2109,18 +2109,17 @@ def isMaybeExposedIn(member, descriptor)
     # All we can say for sure is that if this is a worker descriptor
     # and member is only exposed in windows, then it's not exposed.
     return not descriptor.workers or member.exposureSet != set(["Window"])
 
 def clearableCachedAttrs(descriptor):
     return (m for m in descriptor.interface.members if
             m.isAttr() and
             # Constants should never need clearing!
-            not m.getExtendedAttribute("Constant") and
-            not m.getExtendedAttribute("SameObject") and
+            m.dependsOn != "Nothing" and
             m.slotIndex is not None)
 
 def MakeClearCachedValueNativeName(member):
     return "ClearCached%sValue" % MakeNativeName(member.identifier.name)
 
 def MakeJSImplClearCachedValueNativeName(member):
     return "_" + MakeClearCachedValueNativeName(member)
 
@@ -8075,26 +8074,19 @@ class CGMemberJITInfo(CGThing):
         if self.member.isAttr():
             getterinfo = ("%s_getterinfo" %
                           IDLToCIdentifier(self.member.identifier.name))
             # We need the cast here because JSJitGetterOp has a "void* self"
             # while we have the right type.
             getter = ("(JSJitGetterOp)get_%s" %
                       IDLToCIdentifier(self.member.identifier.name))
             getterinfal = "infallible" in self.descriptor.getExtendedAttributes(self.member, getter=True)
-            getterconst = (self.member.getExtendedAttribute("SameObject") or
-                           self.member.getExtendedAttribute("Constant"))
-            getterpure = getterconst or self.member.getExtendedAttribute("Pure")
-            if getterconst:
-                aliasSet = "AliasNone"
-            elif getterpure:
-                aliasSet = "AliasDOMSets"
-            else:
-                aliasSet = "AliasEverything"
-            movable = getterpure and getterinfal
+
+            movable = self.mayBeMovable() and getterinfal
+            aliasSet = self.aliasSet()
 
             getterinfal = getterinfal and infallibleForMember(self.member, self.member.type, self.descriptor)
             isAlwaysInSlot = self.member.getExtendedAttribute("StoreInSlot")
             if self.member.slotIndex is not None:
                 assert isAlwaysInSlot or self.member.getExtendedAttribute("Cached")
                 isLazilyCachedInSlot = not isAlwaysInSlot
                 slotIndex = memberReservedSlot(self.member)
                 # We'll statically assert that this is not too big in
@@ -8129,62 +8121,94 @@ class CGMemberJITInfo(CGThing):
             methodinfo = ("%s_methodinfo" %
                           IDLToCIdentifier(self.member.identifier.name))
             name = CppKeywords.checkMethodName(
                 IDLToCIdentifier(self.member.identifier.name))
             if self.member.returnsPromise():
                 name = CGMethodPromiseWrapper.makeName(name)
             # Actually a JSJitMethodOp, but JSJitGetterOp is first in the union.
             method = ("(JSJitGetterOp)%s" % name)
-            methodPure = self.member.getExtendedAttribute("Pure")
 
             # Methods are infallible if they are infallible, have no arguments
             # to unwrap, and have a return type that's infallible to wrap up for
             # return.
             sigs = self.member.signatures()
             if len(sigs) != 1:
                 # Don't handle overloading.  If there's more than one signature,
                 # one of them must take arguments.
                 methodInfal = False
                 args = None
                 movable = False
             else:
                 sig = sigs[0]
-                # For pure methods, it's OK to set movable to our notion of
-                # infallible on the C++ side, without considering argument
-                # conversions, since argument conversions that can reliably
-                # throw would be effectful anyway and the jit doesn't move
-                # effectful things.
+                # For methods that affect nothing, it's OK to set movable to our
+                # notion of infallible on the C++ side, without considering
+                # argument conversions, since argument conversions that can
+                # reliably throw would be effectful anyway and the jit doesn't
+                # move effectful things.
                 hasInfallibleImpl = "infallible" in self.descriptor.getExtendedAttributes(self.member)
-                movable = methodPure and hasInfallibleImpl
+                movable = self.mayBeMovable() and hasInfallibleImpl
                 # XXXbz can we move the smarts about fallibility due to arg
                 # conversions into the JIT, using our new args stuff?
                 if (len(sig[1]) != 0 or
                     not infallibleForMember(self.member, sig[0], self.descriptor)):
                     # We have arguments or our return-value boxing can fail
                     methodInfal = False
                 else:
                     methodInfal = hasInfallibleImpl
-                # For now, only bother to output args if we're pure
-                if methodPure:
+                # For now, only bother to output args if we're side-effect-free.
+                if self.member.affects == "Nothing":
                     args = sig[1]
                 else:
                     args = None
 
-            if args is not None:
-                aliasSet = "AliasDOMSets"
-            else:
-                aliasSet = "AliasEverything"
+            aliasSet = self.aliasSet()
             result = self.defineJitInfo(methodinfo, method, "Method",
                                         methodInfal, movable, aliasSet,
                                         False, False, "0",
                                         [s[0] for s in sigs], args)
             return result
         raise TypeError("Illegal member type to CGPropertyJITInfo")
 
+    def mayBeMovable(self):
+        """
+        Returns whether this attribute or method may be movable, just
+        based on Affects/DependsOn annotations.
+        """
+        affects = self.member.affects
+        dependsOn = self.member.dependsOn
+        assert affects in IDLInterfaceMember.AffectsValues
+        assert dependsOn in IDLInterfaceMember.DependsOnValues
+        # Things that are DependsOn=DeviceState are not movable, because we
+        # don't want them coalesced with each other or loop-hoisted, since
+        # their return value can change even if nothing is going on from our
+        # point of view.
+        return (affects == "Nothing" and
+                (dependsOn != "Everything" and dependsOn != "DeviceState"))
+
+    def aliasSet(self):
+        """Returns the alias set to store in the jitinfo.  This may not be the
+        effective alias set the JIT uses, depending on whether we have enough
+        information about our args to allow the JIT to prove that effectful
+        argument conversions won't happen.
+
+        """
+        dependsOn = self.member.dependsOn
+        assert dependsOn in IDLInterfaceMember.DependsOnValues
+
+        if dependsOn == "Nothing" or dependsOn == "DeviceState":
+            assert self.member.affects == "Nothing"
+            return "AliasNone"
+
+        if dependsOn == "DOMState":
+            assert self.member.affects == "Nothing"
+            return "AliasDOMSets"
+
+        return "AliasEverything"
+
     @staticmethod
     def getJSReturnTypeTag(t):
         if t.nullable():
             # Sometimes it might return null, sometimes not
             return "JSVAL_TYPE_UNKNOWN"
         if t.isVoid():
             # No return, every time
             return "JSVAL_TYPE_UNDEFINED"
--- a/dom/bindings/parser/WebIDL.py
+++ b/dom/bindings/parser/WebIDL.py
@@ -3038,16 +3038,19 @@ class IDLInterfaceMember(IDLObjectWithId
         'Method'
     )
 
     Special = enum(
         'Static',
         'Stringifier'
     )
 
+    AffectsValues = ("Nothing", "Everything")
+    DependsOnValues = ("Nothing", "DOMState", "DeviceState", "Everything")
+
     def __init__(self, location, identifier, tag):
         IDLObjectWithIdentifier.__init__(self, location, None, identifier)
         self.tag = tag
         self._extendedAttrDict = {}
         # _exposureGlobalNames are the global names listed in our [Exposed]
         # extended attribute.  exposureSet is the exposure set as defined in the
         # Web IDL spec: it contains interface names.
         self._exposureGlobalNames = set()
@@ -3092,16 +3095,43 @@ class IDLInterfaceMember(IDLObjectWithId
 
         if (self.getExtendedAttribute("CheckPermissions") and
             self.exposureSet != set([self._scope.primaryGlobalName])):
             raise WebIDLError("[CheckPermissions] used on an interface member "
                               "that is not %s-only" %
                               self._scope.primaryGlobalName,
                               [self.location])
 
+        if self.isAttr() or self.isMethod():
+            if self.affects == "Everything" and self.dependsOn != "Everything":
+                raise WebIDLError("Interface member is flagged as affecting "
+                                  "everything but not depending on everything. "
+                                  "That seems rather unlikely.",
+                                  [self.location])
+
+    def _setDependsOn(self, dependsOn):
+        if self.dependsOn != "Everything":
+            raise WebIDLError("Trying to specify multiple different DependsOn, "
+                              "Pure, or Constant extended attributes for "
+                              "attribute", [self.location])
+        if dependsOn not in IDLInterfaceMember.DependsOnValues:
+            raise WebIDLError("Invalid [DependsOn=%s] on attribute" % dependsOn,
+                              [self.location])
+        self.dependsOn = dependsOn
+
+    def _setAffects(self, affects):
+        if self.affects != "Everything":
+            raise WebIDLError("Trying to specify multiple different Affects, "
+                              "Pure, or Constant extended attributes for "
+                              "attribute", [self.location])
+        if affects not in IDLInterfaceMember.AffectsValues:
+            raise WebIDLError("Invalid [Affects=%s] on attribute" % dependsOn,
+                              [self.location])
+        self.affects = affects
+
 class IDLConst(IDLInterfaceMember):
     def __init__(self, location, identifier, type, value):
         IDLInterfaceMember.__init__(self, location, identifier,
                                     IDLInterfaceMember.Tags.Const)
 
         assert isinstance(type, IDLType)
         if type.isDictionary():
             raise WebIDLError("A constant cannot be of a dictionary type",
@@ -3170,16 +3200,18 @@ class IDLAttribute(IDLInterfaceMember):
         self.inherit = inherit
         self.static = static
         self.lenientThis = False
         self._unforgeable = False
         self.stringifier = stringifier
         self.enforceRange = False
         self.clamp = False
         self.slotIndex = None
+        self.dependsOn = "Everything"
+        self.affects = "Everything"
 
         if static and identifier.name == "prototype":
             raise WebIDLError("The identifier of a static attribute must not be 'prototype'",
                               [location])
 
         if readonly and inherit:
             raise WebIDLError("An attribute cannot be both 'readonly' and 'inherit'",
                               [self.location])
@@ -3238,21 +3270,21 @@ class IDLAttribute(IDLInterfaceMember):
             raise WebIDLError("An attribute with [SameObject] must have an "
                               "interface type as its type", [self.location])
 
     def validate(self):
         IDLInterfaceMember.validate(self)
 
         if ((self.getExtendedAttribute("Cached") or
              self.getExtendedAttribute("StoreInSlot")) and
-            not self.getExtendedAttribute("Constant") and
-            not self.getExtendedAttribute("Pure")):
+            not self.affects == "Nothing"):
             raise WebIDLError("Cached attributes and attributes stored in "
-                              "slots must be constant or pure, since the "
-                              "getter won't always be called.",
+                              "slots must be Constant or Pure or "
+                              "Affects=Nothing, since the getter won't always "
+                              "be called.",
                               [self.location])
         if self.getExtendedAttribute("Frozen"):
             if (not self.type.isSequence() and not self.type.isDictionary() and
                 not self.type.isMozMap()):
                 raise WebIDLError("[Frozen] is only allowed on "
                                   "sequence-valued, dictionary-valued, and "
                                   "MozMap-valued attributes",
                                   [self.location])
@@ -3367,24 +3399,48 @@ class IDLAttribute(IDLInterfaceMember):
                                   "attributes" % identifier,
                                   [attr.location, self.location])
             if self.getExtendedAttribute("LenientThis"):
                 raise WebIDLError("[LenientThis] is not allowed in combination "
                                   "with [%s]" % identifier,
                                   [attr.location, self.location])
         elif identifier == "Exposed":
             convertExposedAttrToGlobalNameSet(attr, self._exposureGlobalNames)
+        elif identifier == "Pure":
+            if not attr.noArguments():
+                raise WebIDLError("[Pure] must take no arguments",
+                                  [attr.location])
+            self._setDependsOn("DOMState")
+            self._setAffects("Nothing")
+        elif identifier == "Constant" or identifier == "SameObject":
+            if not attr.noArguments():
+                raise WebIDLError("[%s] must take no arguments" % identifier,
+                                  [attr.location])
+            self._setDependsOn("Nothing")
+            self._setAffects("Nothing")
+        elif identifier == "Affects":
+            if not attr.hasValue():
+                raise WebIDLError("[Affects] takes an identifier",
+                                  [attr.location])
+            self._setAffects(attr.value())
+        elif identifier == "DependsOn":
+            if not attr.hasValue():
+                raise WebIDLError("[DependsOn] takes an identifier",
+                                  [attr.location])
+            if (attr.value() != "Everything" and attr.value() != "DOMState" and
+                not self.readonly):
+                raise WebIDLError("[DependsOn=%s] only allowed on "
+                                  "readonly attributes" % attr.value(),
+                                  [attr.location, self.location])
+            self._setDependsOn(attr.value())
         elif (identifier == "Pref" or
               identifier == "SetterThrows" or
-              identifier == "Pure" or
               identifier == "Throws" or
               identifier == "GetterThrows" or
               identifier == "ChromeOnly" or
-              identifier == "SameObject" or
-              identifier == "Constant" or
               identifier == "Func" or
               identifier == "Frozen" or
               identifier == "AvailableIn" or
               identifier == "NewObject" or
               identifier == "UnsafeInPrerendering" or
               identifier == "CheckPermissions" or
               identifier == "BinaryName"):
             # Known attributes that we don't need to do anything with here
@@ -3658,16 +3714,18 @@ class IDLMethod(IDLInterfaceMember, IDLS
         assert isinstance(legacycaller, bool)
         self._legacycaller = legacycaller
         assert isinstance(stringifier, bool)
         self._stringifier = stringifier
         assert isinstance(jsonifier, bool)
         self._jsonifier = jsonifier
         self._specialType = specialType
         self._unforgeable = False
+        self.dependsOn = "Everything"
+        self.affects = "Everything"
 
         if static and identifier.name == "prototype":
             raise WebIDLError("The identifier of a static operation must not be 'prototype'",
                               [location])
 
         self.assertSignatureConstraints()
 
     def __str__(self):
@@ -3969,23 +4027,38 @@ class IDLMethod(IDLInterfaceMember, IDLS
                 raise WebIDLError("[LenientFloat] used on a non-void method",
                                   [attr.location, self.location])
             if not any(arg.type.includesRestrictedFloat() for arg in sig[1]):
                 raise WebIDLError("[LenientFloat] used on an operation with no "
                                   "restricted float type arguments",
                                   [attr.location, self.location])
         elif identifier == "Exposed":
             convertExposedAttrToGlobalNameSet(attr, self._exposureGlobalNames)
-        elif (identifier == "Pure" or
-              identifier == "CrossOriginCallable" or
+        elif (identifier == "CrossOriginCallable" or
               identifier == "WebGLHandlesContextLoss"):
             # Known no-argument attributes.
             if not attr.noArguments():
                 raise WebIDLError("[%s] must take no arguments" % identifier,
                                   [attr.location])
+        elif identifier == "Pure":
+            if not attr.noArguments():
+                raise WebIDLError("[Pure] must take no arguments",
+                                  [attr.location])
+            self._setDependsOn("DOMState")
+            self._setAffects("Nothing")
+        elif identifier == "Affects":
+            if not attr.hasValue():
+                raise WebIDLError("[Affects] takes an identifier",
+                                  [attr.location])
+            self._setAffects(attr.value())
+        elif identifier == "DependsOn":
+            if not attr.hasValue():
+                raise WebIDLError("[DependsOn] takes an identifier",
+                                  [attr.location])
+            self._setDependsOn(attr.value())
         elif (identifier == "Throws" or
               identifier == "NewObject" or
               identifier == "ChromeOnly" or
               identifier == "UnsafeInPrerendering" or
               identifier == "Pref" or
               identifier == "Func" or
               identifier == "AvailableIn" or
               identifier == "CheckPermissions" or
--- a/dom/bindings/test/TestBindingHeader.h
+++ b/dom/bindings/test/TestBindingHeader.h
@@ -177,16 +177,26 @@ public:
   void PassOptionalByteWithDefaultBeforeRequired(int8_t, int8_t);
   void PassNullableByte(const Nullable<int8_t>&);
   void PassOptionalNullableByte(const Optional< Nullable<int8_t> >&);
   void PassVariadicByte(const Sequence<int8_t>&);
   int8_t CachedByte();
   int8_t CachedConstantByte();
   int8_t CachedWritableByte();
   void SetCachedWritableByte(int8_t);
+  int8_t SideEffectFreeByte();
+  int8_t SetSideEffectFreeByte(int8_t);
+  int8_t DomDependentByte();
+  int8_t SetDomDependentByte(int8_t);
+  int8_t ConstantByte();
+  int8_t DeviceStateDependentByte();
+  int8_t ReturnByteSideEffectFree();
+  int8_t ReturnDOMDependentByte();
+  int8_t ReturnConstantByte();
+  int8_t ReturnDeviceStateDependentByte();
 
   void UnsafePrerenderMethod();
   int32_t UnsafePrerenderWritable();
   void SetUnsafePrerenderWritable(int32_t);
   int32_t UnsafePrerenderReadonly();
   int16_t ReadonlyShort();
   int16_t WritableShort();
   void SetWritableShort(int16_t);
--- a/dom/bindings/test/TestCodeGen.webidl
+++ b/dom/bindings/test/TestCodeGen.webidl
@@ -152,16 +152,32 @@ interface TestInterface {
   void passOptionalNullableByte(optional byte? arg);
   void passVariadicByte(byte... arg);
   [StoreInSlot, Pure]
   readonly attribute byte cachedByte;
   [StoreInSlot, Constant]
   readonly attribute byte cachedConstantByte;
   [StoreInSlot, Pure]
   attribute byte cachedWritableByte;
+  [Affects=Nothing]
+  attribute byte sideEffectFreeByte;
+  [Affects=Nothing, DependsOn=DOMState]
+  attribute byte domDependentByte;
+  [Affects=Nothing, DependsOn=Nothing]
+  readonly attribute byte constantByte;
+  [DependsOn=DeviceState, Affects=Nothing]
+  readonly attribute byte deviceStateDependentByte;
+  [Affects=Nothing]
+  byte returnByteSideEffectFree();
+  [Affects=Nothing, DependsOn=DOMState]
+  byte returnDOMDependentByte();
+  [Affects=Nothing, DependsOn=Nothing]
+  byte returnConstantByte();
+  [DependsOn=DeviceState, Affects=Nothing]
+  byte returnDeviceStateDependentByte();
 
   [UnsafeInPrerendering]
   void unsafePrerenderMethod();
   [UnsafeInPrerendering]
   attribute long unsafePrerenderWritable;
   [UnsafeInPrerendering]
   readonly attribute long unsafePrerenderReadonly;
   readonly attribute short readonlyShort;
--- a/dom/bindings/test/TestExampleGen.webidl
+++ b/dom/bindings/test/TestExampleGen.webidl
@@ -31,16 +31,32 @@ interface TestExampleInterface {
   void passOptionalNullableByte(optional byte? arg);
   void passVariadicByte(byte... arg);
   [Cached, Pure]
   readonly attribute byte cachedByte;
   [StoreInSlot, Constant]
   readonly attribute byte cachedConstantByte;
   [Cached, Pure]
   attribute byte cachedWritableByte;
+  [Affects=Nothing]
+  attribute byte sideEffectFreeByte;
+  [Affects=Nothing, DependsOn=DOMState]
+  attribute byte domDependentByte;
+  [Affects=Nothing, DependsOn=Nothing]
+  readonly attribute byte constantByte;
+  [DependsOn=DeviceState, Affects=Nothing]
+  readonly attribute byte deviceStateDependentByte;
+  [Affects=Nothing]
+  byte returnByteSideEffectFree();
+  [Affects=Nothing, DependsOn=DOMState]
+  byte returnDOMDependentByte();
+  [Affects=Nothing, DependsOn=Nothing]
+  byte returnConstantByte();
+  [DependsOn=DeviceState, Affects=Nothing]
+  byte returnDeviceStateDependentByte();
 
   readonly attribute short readonlyShort;
   attribute short writableShort;
   void passShort(short arg);
   short receiveShort();
   void passOptionalShort(optional short arg);
   void passOptionalShortWithDefault(optional short arg = 5);
 
--- a/dom/bindings/test/TestJSImplGen.webidl
+++ b/dom/bindings/test/TestJSImplGen.webidl
@@ -40,16 +40,32 @@ interface TestJSImplInterface {
   void passOptionalNullableByte(optional byte? arg);
   void passVariadicByte(byte... arg);
   [Cached, Pure]
   readonly attribute byte cachedByte;
   [Cached, Constant]
   readonly attribute byte cachedConstantByte;
   [Cached, Pure]
   attribute byte cachedWritableByte;
+  [Affects=Nothing]
+  attribute byte sideEffectFreeByte;
+  [Affects=Nothing, DependsOn=DOMState]
+  attribute byte domDependentByte;
+  [Affects=Nothing, DependsOn=Nothing]
+  readonly attribute byte constantByte;
+  [DependsOn=DeviceState, Affects=Nothing]
+  readonly attribute byte deviceStateDependentByte;
+  [Affects=Nothing]
+  byte returnByteSideEffectFree();
+  [Affects=Nothing, DependsOn=DOMState]
+  byte returnDOMDependentByte();
+  [Affects=Nothing, DependsOn=Nothing]
+  byte returnConstantByte();
+  [DependsOn=DeviceState, Affects=Nothing]
+  byte returnDeviceStateDependentByte();
 
   readonly attribute short readonlyShort;
   attribute short writableShort;
   void passShort(short arg);
   short receiveShort();
   void passOptionalShort(optional short arg);
   void passOptionalShortWithDefault(optional short arg = 5);
 
--- a/dom/broadcastchannel/BroadcastChannelParent.cpp
+++ b/dom/broadcastchannel/BroadcastChannelParent.cpp
@@ -77,18 +77,20 @@ BroadcastChannelParent::ActorDestroy(Act
 void
 BroadcastChannelParent::CheckAndDeliver(const ClonedMessageData& aData,
                                         const nsString& aOrigin,
                                         const nsString& aChannel)
 {
   AssertIsOnBackgroundThread();
 
   if (aOrigin == mOrigin && aChannel == mChannel) {
-    // We need to duplicate data only if we have blobs.
-    if (aData.blobsParent().IsEmpty()) {
+    // 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.
--- a/dom/broadcastchannel/BroadcastChannelService.cpp
+++ b/dom/broadcastchannel/BroadcastChannelService.cpp
@@ -1,15 +1,17 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "BroadcastChannelService.h"
 #include "BroadcastChannelParent.h"
+#include "mozilla/dom/File.h"
+#include "mozilla/dom/ipc/BlobParent.h"
 #include "mozilla/ipc/BackgroundParent.h"
 
 #ifdef XP_WIN
 #undef PostMessage
 #endif
 
 namespace mozilla {
 
@@ -84,25 +86,39 @@ struct MOZ_STACK_CLASS PostMessageData M
                   const nsAString& aChannel)
     : mParent(aParent)
     , mData(aData)
     , mOrigin(aOrigin)
     , mChannel(aChannel)
   {
     MOZ_ASSERT(aParent);
     MOZ_COUNT_CTOR(PostMessageData);
+
+    // We need to keep the array alive for the life-time of this
+    // PostMessageData.
+    if (!aData.blobsParent().IsEmpty()) {
+      mFiles.SetCapacity(aData.blobsParent().Length());
+
+      for (uint32_t i = 0, len = aData.blobsParent().Length(); i < len; ++i) {
+        nsRefPtr<FileImpl> impl =
+          static_cast<BlobParent*>(aData.blobsParent()[i])->GetBlobImpl();
+       MOZ_ASSERT(impl);
+       mFiles.AppendElement(impl);
+      }
+    }
   }
 
   ~PostMessageData()
   {
     MOZ_COUNT_DTOR(PostMessageData);
   }
 
   BroadcastChannelParent* mParent;
   const ClonedMessageData& mData;
+  nsTArray<nsRefPtr<FileImpl>> mFiles;
   const nsString mOrigin;
   const nsString mChannel;
 };
 
 PLDHashOperator
 PostMessageEnumerator(nsPtrHashKey<BroadcastChannelParent>* aKey, void* aPtr)
 {
   AssertIsOnBackgroundThread();
--- a/dom/broadcastchannel/tests/test_broadcastchannel_any.html
+++ b/dom/broadcastchannel/tests/test_broadcastchannel_any.html
@@ -70,32 +70,60 @@ function compare(a, b) {
   }
 
   if (type != 'null') {
     is (a.toSource(), b.toSource(), 'Matching using toSource()');
   }
 }
 
 function runTest() {
+  var count = 2;
+
   var bc = new BroadcastChannel("foobar");
   ok(bc, "BroadcastChannel can be created");
 
   bc.onmessage = function(event) {
+    ok(count < 2, "Still comparing...");
+    info("bc: " + currentTest);
     compare(event.data, currentTest);
+    ++count;
+    next();
+  }
+
+  var bc2 = new BroadcastChannel("foobar");
+  ok(bc2, "BroadcastChannel can be created");
+
+  var toSkip = true;
+  bc2.onmessage = function(event) {
+    toSkip = !toSkip;
+    if (toSkip) return;
+
+    ok(count < 2, "Still comparing...");
+    info("bc2: " + currentTest);
+    compare(event.data, currentTest);
+    ++count;
     next();
   }
 
   function next() {
+    if (count < 2) {
+      return;
+    }
+
+    is(count, 2, "Just 2 comparations");
+    count = 0;
+
     if (!tests.length) {
       SimpleTest.finish();
       return;
     }
 
     currentTest = tests.shift();
     bc.postMessage(currentTest);
+    info("Posted: " + currentTest);
   }
 
   var worker = new Worker("broadcastchannel_worker_any.js");
   worker.onmessage = function(event) {
     if (event.data == "READY") {
       next();
     }
   };
--- a/dom/events/EventStateManager.cpp
+++ b/dom/events/EventStateManager.cpp
@@ -4685,16 +4685,21 @@ EventStateManager::SetContentState(nsICo
     if (mCurrentTarget)
     {
       const nsStyleUserInterface* ui = mCurrentTarget->StyleUserInterface();
       if (ui->mUserInput == NS_STYLE_USER_INPUT_NONE)
         return false;
     }
 
     if (aState == NS_EVENT_STATE_ACTIVE) {
+      // Editable content can never become active since their default actions
+      // are disabled.
+      if (aContent && aContent->IsEditable()) {
+        aContent = nullptr;
+      }
       if (aContent != mActiveContent) {
         notifyContent1 = aContent;
         notifyContent2 = mActiveContent;
         mActiveContent = aContent;
       }
     } else {
       NS_ASSERTION(aState == NS_EVENT_STATE_HOVER, "How did that happen?");
       nsIContent* newHover;
--- a/dom/events/test/mochitest.ini
+++ b/dom/events/test/mochitest.ini
@@ -120,16 +120,17 @@ skip-if = toolkit == 'android' #CRASH_DU
 [test_bug704423.html]
 [test_bug741666.html]
 skip-if = toolkit == 'android'
 [test_bug742376.html]
 [test_bug812744.html]
 [test_bug855741.html]
 [test_bug864040.html]
 skip-if = buildapp == 'mulet' || buildapp == 'b2g' # b2g(failing when the test gets moved around, and on debug)
+[test_bug924087.html]
 [test_bug930374-content.html]
 [test_bug944011.html]
 [test_bug944847.html]
 [test_bug946632.html]
 [test_bug967796.html]
 skip-if = toolkit == "gonk" || e10s
 [test_bug985988.html]
 [test_bug998809.html]
new file mode 100644
--- /dev/null
+++ b/dom/events/test/test_bug924087.html
@@ -0,0 +1,36 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=924087
+-->
+<head>
+  <title>Test for Bug 924087</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<div contenteditable><a id="editable" href="#">editable link</a></div>
+<a id="noneditable" href="#">non-editable link</a>
+<pre id="test">
+<script type="application/javascript;version=1.8">
+
+/** Test for Bug 924087 **/
+SimpleTest.waitForExplicitFinish();
+SimpleTest.waitForFocus(function() {
+  var editable = document.querySelector("#editable");
+  var noneditable = document.querySelector("#noneditable");
+  synthesizeMouseAtCenter(noneditable, {type:"mousedown"});
+  is(document.querySelector(":active:link"), noneditable, "Normal links should become :active");
+  synthesizeMouseAtCenter(noneditable, {type:"mouseup"});
+  synthesizeMouseAtCenter(editable, {type:"mousedown"});
+  is(document.querySelector(":active:link"), null, "Editable links should not become :active");
+  synthesizeMouseAtCenter(editable, {type:"mouseup"});
+  SimpleTest.finish();
+});
+
+</script>
+</pre>
+
+</body>
+</html>
--- a/dom/html/HTMLBodyElement.cpp
+++ b/dom/html/HTMLBodyElement.cpp
@@ -57,20 +57,20 @@ BodyRule::MapRuleInfoInto(nsRuleData* aD
 
   const nsAttrValue* value;
   if (mPart->GetAttrCount() > 0) {
     // if marginwidth/marginheight are set, reflect them as 'margin'
     value = mPart->GetParsedAttr(nsGkAtoms::marginwidth);
     if (value && value->Type() == nsAttrValue::eInteger) {
       bodyMarginWidth = value->GetIntegerValue();
       if (bodyMarginWidth < 0) bodyMarginWidth = 0;
-      nsCSSValue* marginLeft = aData->ValueForMarginLeftValue();
+      nsCSSValue* marginLeft = aData->ValueForMarginLeft();
       if (marginLeft->GetUnit() == eCSSUnit_Null)
         marginLeft->SetFloatValue((float)bodyMarginWidth, eCSSUnit_Pixel);
-      nsCSSValue* marginRight = aData->ValueForMarginRightValue();
+      nsCSSValue* marginRight = aData->ValueForMarginRight();
       if (marginRight->GetUnit() == eCSSUnit_Null)
         marginRight->SetFloatValue((float)bodyMarginWidth, eCSSUnit_Pixel);
     }
 
     value = mPart->GetParsedAttr(nsGkAtoms::marginheight);
     if (value && value->Type() == nsAttrValue::eInteger) {
       bodyMarginHeight = value->GetIntegerValue();
       if (bodyMarginHeight < 0) bodyMarginHeight = 0;
@@ -102,27 +102,27 @@ BodyRule::MapRuleInfoInto(nsRuleData* aD
         marginBottom->SetFloatValue((float)bodyBottomMargin, eCSSUnit_Pixel);
     }
 
       // leftmargin (IE-attribute)
     value = mPart->GetParsedAttr(nsGkAtoms::leftmargin);
     if (value && value->Type() == nsAttrValue::eInteger) {
       bodyLeftMargin = value->GetIntegerValue();
       if (bodyLeftMargin < 0) bodyLeftMargin = 0;
-      nsCSSValue* marginLeft = aData->ValueForMarginLeftValue();
+      nsCSSValue* marginLeft = aData->ValueForMarginLeft();
       if (marginLeft->GetUnit() == eCSSUnit_Null)
         marginLeft->SetFloatValue((float)bodyLeftMargin, eCSSUnit_Pixel);
     }
 
       // rightmargin (IE-attribute)
     value = mPart->GetParsedAttr(nsGkAtoms::rightmargin);
     if (value && value->Type() == nsAttrValue::eInteger) {
       bodyRightMargin = value->GetIntegerValue();
       if (bodyRightMargin < 0) bodyRightMargin = 0;
-      nsCSSValue* marginRight = aData->ValueForMarginRightValue();
+      nsCSSValue* marginRight = aData->ValueForMarginRight();
       if (marginRight->GetUnit() == eCSSUnit_Null)
         marginRight->SetFloatValue((float)bodyRightMargin, eCSSUnit_Pixel);
     }
 
   }
 
   // if marginwidth or marginheight is set in the <frame> and not set in the <body>
   // reflect them as margin in the <body>
@@ -142,20 +142,20 @@ BodyRule::MapRuleInfoInto(nsRuleData* aD
       if ((frameMarginHeight >= 0) && (bodyMarginHeight == -1)) { // set in <frame> & not in <body>
         if (eCompatibility_NavQuirks == mode) {
           if ((bodyMarginWidth == -1) && (0 > frameMarginWidth)) // nav quirk
             frameMarginWidth = 0;
         }
       }
 
       if ((bodyMarginWidth == -1) && (frameMarginWidth >= 0)) {
-        nsCSSValue* marginLeft = aData->ValueForMarginLeftValue();
+        nsCSSValue* marginLeft = aData->ValueForMarginLeft();
         if (marginLeft->GetUnit() == eCSSUnit_Null)
           marginLeft->SetFloatValue((float)frameMarginWidth, eCSSUnit_Pixel);
-        nsCSSValue* marginRight = aData->ValueForMarginRightValue();
+        nsCSSValue* marginRight = aData->ValueForMarginRight();
         if (marginRight->GetUnit() == eCSSUnit_Null)
           marginRight->SetFloatValue((float)frameMarginWidth, eCSSUnit_Pixel);
       }
 
       if ((bodyMarginHeight == -1) && (frameMarginHeight >= 0)) {
         nsCSSValue* marginTop = aData->ValueForMarginTop();
         if (marginTop->GetUnit() == eCSSUnit_Null)
           marginTop->SetFloatValue((float)frameMarginHeight, eCSSUnit_Pixel);
--- a/dom/html/HTMLHRElement.cpp
+++ b/dom/html/HTMLHRElement.cpp
@@ -83,18 +83,18 @@ HTMLHRElement::MapAttributesIntoRule(con
     }
   }
 
   if (aData->mSIDs & NS_STYLE_INHERIT_BIT(Margin)) {
     // align: enum
     const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::align);
     if (value && value->Type() == nsAttrValue::eEnum) {
       // Map align attribute into auto side margins
-      nsCSSValue* marginLeft = aData->ValueForMarginLeftValue();
-      nsCSSValue* marginRight = aData->ValueForMarginRightValue();
+      nsCSSValue* marginLeft = aData->ValueForMarginLeft();
+      nsCSSValue* marginRight = aData->ValueForMarginRight();
       switch (value->GetEnumValue()) {
       case NS_STYLE_TEXT_ALIGN_LEFT:
         if (marginLeft->GetUnit() == eCSSUnit_Null)
           marginLeft->SetFloatValue(0.0f, eCSSUnit_Pixel);
         if (marginRight->GetUnit() == eCSSUnit_Null)
           marginRight->SetAutoValue();
         break;
       case NS_STYLE_TEXT_ALIGN_RIGHT:
@@ -160,47 +160,47 @@ HTMLHRElement::MapAttributesIntoRule(con
     } else {
       sizePerSide = 1.0f; // default to a 2px high line
     }
     nsCSSValue* borderTopWidth = aData->ValueForBorderTopWidth();
     if (borderTopWidth->GetUnit() == eCSSUnit_Null) {
       borderTopWidth->SetFloatValue(sizePerSide, eCSSUnit_Pixel);
     }
     if (allSides) {
-      nsCSSValue* borderRightWidth = aData->ValueForBorderRightWidthValue();
+      nsCSSValue* borderRightWidth = aData->ValueForBorderRightWidth();
       if (borderRightWidth->GetUnit() == eCSSUnit_Null) {
         borderRightWidth->SetFloatValue(sizePerSide, eCSSUnit_Pixel);
       }
       nsCSSValue* borderBottomWidth = aData->ValueForBorderBottomWidth();
       if (borderBottomWidth->GetUnit() == eCSSUnit_Null) {
         borderBottomWidth->SetFloatValue(sizePerSide, eCSSUnit_Pixel);
       }
-      nsCSSValue* borderLeftWidth = aData->ValueForBorderLeftWidthValue();
+      nsCSSValue* borderLeftWidth = aData->ValueForBorderLeftWidth();
       if (borderLeftWidth->GetUnit() == eCSSUnit_Null) {
         borderLeftWidth->SetFloatValue(sizePerSide, eCSSUnit_Pixel);
       }
     }
 
     nsCSSValue* borderTopStyle = aData->ValueForBorderTopStyle();
     if (borderTopStyle->GetUnit() == eCSSUnit_Null) {
       borderTopStyle->SetIntValue(NS_STYLE_BORDER_STYLE_SOLID,
                                   eCSSUnit_Enumerated);
     }
     if (allSides) {
-      nsCSSValue* borderRightStyle = aData->ValueForBorderRightStyleValue();
+      nsCSSValue* borderRightStyle = aData->ValueForBorderRightStyle();
       if (borderRightStyle->GetUnit() == eCSSUnit_Null) {
         borderRightStyle->SetIntValue(NS_STYLE_BORDER_STYLE_SOLID,
                                       eCSSUnit_Enumerated);
       }
       nsCSSValue* borderBottomStyle = aData->ValueForBorderBottomStyle();
       if (borderBottomStyle->GetUnit() == eCSSUnit_Null) {
         borderBottomStyle->SetIntValue(NS_STYLE_BORDER_STYLE_SOLID,
                                        eCSSUnit_Enumerated);
       }
-      nsCSSValue* borderLeftStyle = aData->ValueForBorderLeftStyleValue();
+      nsCSSValue* borderLeftStyle = aData->ValueForBorderLeftStyle();
       if (borderLeftStyle->GetUnit() == eCSSUnit_Null) {
         borderLeftStyle->SetIntValue(NS_STYLE_BORDER_STYLE_SOLID,
                                      eCSSUnit_Enumerated);
       }
 
       // If it would be noticeable, set the border radius to
       // 10000px on all corners; this triggers the clamping to make
       // circular ends.  This assumes the <hr> isn't larger than
--- a/dom/html/HTMLIFrameElement.cpp
+++ b/dom/html/HTMLIFrameElement.cpp
@@ -116,20 +116,20 @@ HTMLIFrameElement::MapAttributesIntoRule
     // If frameborder is 0 or No, set border to 0
     // else leave it as the value set in html.css
     const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::frameborder);
     if (value && value->Type() == nsAttrValue::eEnum) {
       int32_t frameborder = value->GetEnumValue();
       if (NS_STYLE_FRAME_0 == frameborder ||
           NS_STYLE_FRAME_NO == frameborder ||
           NS_STYLE_FRAME_OFF == frameborder) {
-        nsCSSValue* borderLeftWidth = aData->ValueForBorderLeftWidthValue();
+        nsCSSValue* borderLeftWidth = aData->ValueForBorderLeftWidth();
         if (borderLeftWidth->GetUnit() == eCSSUnit_Null)
           borderLeftWidth->SetFloatValue(0.0f, eCSSUnit_Pixel);
-        nsCSSValue* borderRightWidth = aData->ValueForBorderRightWidthValue();
+        nsCSSValue* borderRightWidth = aData->ValueForBorderRightWidth();
         if (borderRightWidth->GetUnit() == eCSSUnit_Null)
           borderRightWidth->SetFloatValue(0.0f, eCSSUnit_Pixel);
         nsCSSValue* borderTopWidth = aData->ValueForBorderTopWidth();
         if (borderTopWidth->GetUnit() == eCSSUnit_Null)
           borderTopWidth->SetFloatValue(0.0f, eCSSUnit_Pixel);
         nsCSSValue* borderBottomWidth = aData->ValueForBorderBottomWidth();
         if (borderBottomWidth->GetUnit() == eCSSUnit_Null)
           borderBottomWidth->SetFloatValue(0.0f, eCSSUnit_Pixel);
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -1197,22 +1197,31 @@ nsresult HTMLMediaElement::LoadResource(
       return NS_ERROR_FAILURE;
     }
     mMediaSource = source.forget();
     nsRefPtr<MediaResource> resource =
       MediaSourceDecoder::CreateResource(mMediaSource->GetPrincipal());
     return FinishDecoderSetup(decoder, resource, nullptr, nullptr);
   }
 
+  nsSecurityFlags securityFlags = nsILoadInfo::SEC_NORMAL;
+  if (nsContentUtils::ChannelShouldInheritPrincipal(NodePrincipal(),
+                                                    mLoadingSrc,
+                                                    false, // aInheritForAboutBlank
+                                                    false // aForceInherit
+                                                    )) {
+    securityFlags = nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL;
+  }
+
   nsCOMPtr<nsILoadGroup> loadGroup = GetDocumentLoadGroup();
   nsCOMPtr<nsIChannel> channel;
   rv = NS_NewChannel(getter_AddRefs(channel),
                      mLoadingSrc,
                      static_cast<Element*>(this),
-                     nsILoadInfo::SEC_NORMAL,
+                     securityFlags,
                      nsIContentPolicy::TYPE_MEDIA,
                      loadGroup,
                      nullptr,   // aCallbacks
                      nsICachingChannel::LOAD_BYPASS_LOCAL_CACHE_IF_BUSY |
                      nsIChannel::LOAD_MEDIA_SNIFFER_OVERRIDES_CONTENT_TYPE |
                      nsIChannel::LOAD_CALL_CONTENT_SNIFFERS);
 
   NS_ENSURE_SUCCESS(rv,rv);
--- a/dom/html/HTMLTableElement.cpp
+++ b/dom/html/HTMLTableElement.cpp
@@ -700,36 +700,36 @@ HTMLTableElement::MapAttributesIntoRule(
   if (aData->mSIDs & NS_STYLE_INHERIT_BIT(Margin)) {
     // align; Check for enumerated type (it may be another type if
     // illegal)
     const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::align);
 
     if (value && value->Type() == nsAttrValue::eEnum) {
       if (value->GetEnumValue() == NS_STYLE_TEXT_ALIGN_CENTER ||
           value->GetEnumValue() == NS_STYLE_TEXT_ALIGN_MOZ_CENTER) {
-        nsCSSValue* marginLeft = aData->ValueForMarginLeftValue();
+        nsCSSValue* marginLeft = aData->ValueForMarginLeft();
         if (marginLeft->GetUnit() == eCSSUnit_Null)
           marginLeft->SetAutoValue();
-        nsCSSValue* marginRight = aData->ValueForMarginRightValue();
+        nsCSSValue* marginRight = aData->ValueForMarginRight();
         if (marginRight->GetUnit() == eCSSUnit_Null)
           marginRight->SetAutoValue();
       }
     }
 
     // hspace is mapped into left and right margin,
     // vspace is mapped into top and bottom margins
     // - *** Quirks Mode only ***
     if (eCompatibility_NavQuirks == mode) {
       value = aAttributes->GetAttr(nsGkAtoms::hspace);
 
       if (value && value->Type() == nsAttrValue::eInteger) {
-        nsCSSValue* marginLeft = aData->ValueForMarginLeftValue();
+        nsCSSValue* marginLeft = aData->ValueForMarginLeft();
         if (marginLeft->GetUnit() == eCSSUnit_Null)
           marginLeft->SetFloatValue((float)value->GetIntegerValue(), eCSSUnit_Pixel); 
-        nsCSSValue* marginRight = aData->ValueForMarginRightValue();
+        nsCSSValue* marginRight = aData->ValueForMarginRight();
         if (marginRight->GetUnit() == eCSSUnit_Null)
           marginRight->SetFloatValue((float)value->GetIntegerValue(), eCSSUnit_Pixel);
       }
 
       value = aAttributes->GetAttr(nsGkAtoms::vspace);
 
       if (value && value->Type() == nsAttrValue::eInteger) {
         nsCSSValue* marginTop = aData->ValueForMarginTop();
@@ -763,20 +763,20 @@ HTMLTableElement::MapAttributesIntoRule(
     }
   }
   if (aData->mSIDs & NS_STYLE_INHERIT_BIT(Border)) {
     // bordercolor
     const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::bordercolor);
     nscolor color;
     if (value && presContext->UseDocumentColors() &&
         value->GetColorValue(color)) {
-      nsCSSValue* borderLeftColor = aData->ValueForBorderLeftColorValue();
+      nsCSSValue* borderLeftColor = aData->ValueForBorderLeftColor();
       if (borderLeftColor->GetUnit() == eCSSUnit_Null)
         borderLeftColor->SetColorValue(color);
-      nsCSSValue* borderRightColor = aData->ValueForBorderRightColorValue();
+      nsCSSValue* borderRightColor = aData->ValueForBorderRightColor();
       if (borderRightColor->GetUnit() == eCSSUnit_Null)
         borderRightColor->SetColorValue(color);
       nsCSSValue* borderTopColor = aData->ValueForBorderTopColor();
       if (borderTopColor->GetUnit() == eCSSUnit_Null)
         borderTopColor->SetColorValue(color);
       nsCSSValue* borderBottomColor = aData->ValueForBorderBottomColor();
       if (borderBottomColor->GetUnit() == eCSSUnit_Null)
         borderBottomColor->SetColorValue(color);
@@ -787,20 +787,20 @@ HTMLTableElement::MapAttributesIntoRule(
     if (borderValue) {
       // border = 1 pixel default
       int32_t borderThickness = 1;
 
       if (borderValue->Type() == nsAttrValue::eInteger)
         borderThickness = borderValue->GetIntegerValue();
 
       // by default, set all border sides to the specified width
-      nsCSSValue* borderLeftWidth = aData->ValueForBorderLeftWidthValue();
+      nsCSSValue* borderLeftWidth = aData->ValueForBorderLeftWidth();
       if (borderLeftWidth->GetUnit() == eCSSUnit_Null)
         borderLeftWidth->SetFloatValue((float)borderThickness, eCSSUnit_Pixel);
-      nsCSSValue* borderRightWidth = aData->ValueForBorderRightWidthValue();
+      nsCSSValue* borderRightWidth = aData->ValueForBorderRightWidth();
       if (borderRightWidth->GetUnit() == eCSSUnit_Null)
         borderRightWidth->SetFloatValue((float)borderThickness, eCSSUnit_Pixel);
       nsCSSValue* borderTopWidth = aData->ValueForBorderTopWidth();
       if (borderTopWidth->GetUnit() == eCSSUnit_Null)
         borderTopWidth->SetFloatValue((float)borderThickness, eCSSUnit_Pixel);
       nsCSSValue* borderBottomWidth = aData->ValueForBorderBottomWidth();
       if (borderBottomWidth->GetUnit() == eCSSUnit_Null)
         borderBottomWidth->SetFloatValue((float)borderThickness, eCSSUnit_Pixel);
@@ -849,22 +849,22 @@ MapInheritedTableAttributesIntoRule(cons
 {
   if (aData->mSIDs & NS_STYLE_INHERIT_BIT(Padding)) {
     const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::cellpadding);
     if (value && value->Type() == nsAttrValue::eInteger) {
       // We have cellpadding.  This will override our padding values if we
       // don't have any set.
       nsCSSValue padVal(float(value->GetIntegerValue()), eCSSUnit_Pixel);
 
-      nsCSSValue* paddingLeft = aData->ValueForPaddingLeftValue();
+      nsCSSValue* paddingLeft = aData->ValueForPaddingLeft();
       if (paddingLeft->GetUnit() == eCSSUnit_Null) {
         *paddingLeft = padVal;
       }
 
-      nsCSSValue* paddingRight = aData->ValueForPaddingRightValue();
+      nsCSSValue* paddingRight = aData->ValueForPaddingRight();
       if (paddingRight->GetUnit() == eCSSUnit_Null) {
         *paddingRight = padVal;
       }
 
       nsCSSValue* paddingTop = aData->ValueForPaddingTop();
       if (paddingTop->GetUnit() == eCSSUnit_Null) {
         *paddingTop = padVal;
       }
--- a/dom/html/nsGenericHTMLElement.cpp
+++ b/dom/html/nsGenericHTMLElement.cpp
@@ -1439,20 +1439,20 @@ nsGenericHTMLElement::MapImageMarginAttr
   if (value) {
     nsCSSValue hval;
     if (value->Type() == nsAttrValue::eInteger)
       hval.SetFloatValue((float)value->GetIntegerValue(), eCSSUnit_Pixel);
     else if (value->Type() == nsAttrValue::ePercent)
       hval.SetPercentValue(value->GetPercentValue());
 
     if (hval.GetUnit() != eCSSUnit_Null) {
-      nsCSSValue* left = aData->ValueForMarginLeftValue();
+      nsCSSValue* left = aData->ValueForMarginLeft();
       if (left->GetUnit() == eCSSUnit_Null)
         *left = hval;
-      nsCSSValue* right = aData->ValueForMarginRightValue();
+      nsCSSValue* right = aData->ValueForMarginRight();
       if (right->GetUnit() == eCSSUnit_Null)
         *right = hval;
     }
   }
 
   // vspace: value
   value = aAttributes->GetAttr(nsGkAtoms::vspace);
   if (value) {
@@ -1512,49 +1512,49 @@ nsGenericHTMLElement::MapImageBorderAttr
   const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::border);
   if (!value)
     return;
   
   nscoord val = 0;
   if (value->Type() == nsAttrValue::eInteger)
     val = value->GetIntegerValue();
 
-  nsCSSValue* borderLeftWidth = aData->ValueForBorderLeftWidthValue();
+  nsCSSValue* borderLeftWidth = aData->ValueForBorderLeftWidth();
   if (borderLeftWidth->GetUnit() == eCSSUnit_Null)
     borderLeftWidth->SetFloatValue((float)val, eCSSUnit_Pixel);
   nsCSSValue* borderTopWidth = aData->ValueForBorderTopWidth();
   if (borderTopWidth->GetUnit() == eCSSUnit_Null)
     borderTopWidth->SetFloatValue((float)val, eCSSUnit_Pixel);
-  nsCSSValue* borderRightWidth = aData->ValueForBorderRightWidthValue();
+  nsCSSValue* borderRightWidth = aData->ValueForBorderRightWidth();
   if (borderRightWidth->GetUnit() == eCSSUnit_Null)
     borderRightWidth->SetFloatValue((float)val, eCSSUnit_Pixel);
   nsCSSValue* borderBottomWidth = aData->ValueForBorderBottomWidth();
   if (borderBottomWidth->GetUnit() == eCSSUnit_Null)
     borderBottomWidth->SetFloatValue((float)val, eCSSUnit_Pixel);
 
-  nsCSSValue* borderLeftStyle = aData->ValueForBorderLeftStyleValue();
+  nsCSSValue* borderLeftStyle = aData->ValueForBorderLeftStyle();
   if (borderLeftStyle->GetUnit() == eCSSUnit_Null)
     borderLeftStyle->SetIntValue(NS_STYLE_BORDER_STYLE_SOLID, eCSSUnit_Enumerated);
   nsCSSValue* borderTopStyle = aData->ValueForBorderTopStyle();
   if (borderTopStyle->GetUnit() == eCSSUnit_Null)
     borderTopStyle->SetIntValue(NS_STYLE_BORDER_STYLE_SOLID, eCSSUnit_Enumerated);
-  nsCSSValue* borderRightStyle = aData->ValueForBorderRightStyleValue();
+  nsCSSValue* borderRightStyle = aData->ValueForBorderRightStyle();
   if (borderRightStyle->GetUnit() == eCSSUnit_Null)
     borderRightStyle->SetIntValue(NS_STYLE_BORDER_STYLE_SOLID, eCSSUnit_Enumerated);
   nsCSSValue* borderBottomStyle = aData->ValueForBorderBottomStyle();
   if (borderBottomStyle->GetUnit() == eCSSUnit_Null)
     borderBottomStyle->SetIntValue(NS_STYLE_BORDER_STYLE_SOLID, eCSSUnit_Enumerated);
 
-  nsCSSValue* borderLeftColor = aData->ValueForBorderLeftColorValue();
+  nsCSSValue* borderLeftColor = aData->ValueForBorderLeftColor();
   if (borderLeftColor->GetUnit() == eCSSUnit_Null)
     borderLeftColor->SetIntValue(NS_STYLE_COLOR_MOZ_USE_TEXT_COLOR, eCSSUnit_Enumerated);
   nsCSSValue* borderTopColor = aData->ValueForBorderTopColor();
   if (borderTopColor->GetUnit() == eCSSUnit_Null)
     borderTopColor->SetIntValue(NS_STYLE_COLOR_MOZ_USE_TEXT_COLOR, eCSSUnit_Enumerated);
-  nsCSSValue* borderRightColor = aData->ValueForBorderRightColorValue();
+  nsCSSValue* borderRightColor = aData->ValueForBorderRightColor();
   if (borderRightColor->GetUnit() == eCSSUnit_Null)
     borderRightColor->SetIntValue(NS_STYLE_COLOR_MOZ_USE_TEXT_COLOR, eCSSUnit_Enumerated);
   nsCSSValue* borderBottomColor = aData->ValueForBorderBottomColor();
   if (borderBottomColor->GetUnit() == eCSSUnit_Null)
     borderBottomColor->SetIntValue(NS_STYLE_COLOR_MOZ_USE_TEXT_COLOR, eCSSUnit_Enumerated);
 }
 
 void
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -19,16 +19,17 @@
 #include "GeckoProfiler.h"
 #include "TabChild.h"
 
 #include "mozilla/Attributes.h"
 #ifdef ACCESSIBILITY
 #include "mozilla/a11y/DocAccessibleChild.h"
 #endif
 #include "mozilla/Preferences.h"
+#include "mozilla/ProcessHangMonitorIPC.h"
 #include "mozilla/docshell/OfflineCacheUpdateChild.h"
 #include "mozilla/dom/ContentBridgeChild.h"
 #include "mozilla/dom/ContentBridgeParent.h"
 #include "mozilla/dom/DOMStorageIPC.h"
 #include "mozilla/dom/ExternalHelperAppChild.h"
 #include "mozilla/dom/PCrashReporterChild.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/dom/asmjscache/AsmJSCache.h"
@@ -994,16 +995,23 @@ ContentChild::AllocPImageBridgeChild(moz
 
 PBackgroundChild*
 ContentChild::AllocPBackgroundChild(Transport* aTransport,
                                     ProcessId aOtherProcess)
 {
     return BackgroundChild::Alloc(aTransport, aOtherProcess);
 }
 
+PProcessHangMonitorChild*
+ContentChild::AllocPProcessHangMonitorChild(Transport* aTransport,
+                                            ProcessId aOtherProcess)
+{
+    return CreateHangMonitorChild(aTransport, aOtherProcess);
+}
+
 #if defined(XP_WIN) && defined(MOZ_CONTENT_SANDBOX)
 static void
 SetUpSandboxEnvironment()
 {
     // Set up a low integrity temp directory. This only makes sense if the
     // delayed integrity level for the content process is INTEGRITY_LEVEL_LOW.
     nsresult rv;
     nsCOMPtr<nsIProperties> directoryService =
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -121,16 +121,20 @@ public:
     PSharedBufferManagerChild*
     AllocPSharedBufferManagerChild(mozilla::ipc::Transport* aTransport,
                                     base::ProcessId aOtherProcess) MOZ_OVERRIDE;
 
     PImageBridgeChild*
     AllocPImageBridgeChild(mozilla::ipc::Transport* aTransport,
                            base::ProcessId aOtherProcess) MOZ_OVERRIDE;
 
+    PProcessHangMonitorChild*
+    AllocPProcessHangMonitorChild(Transport* aTransport,
+                                  ProcessId aOtherProcess) MOZ_OVERRIDE;
+
 #if defined(XP_WIN) && defined(MOZ_CONTENT_SANDBOX)
     // Cleans up any resources used by the process when sandboxed.
     void CleanUpSandboxEnvironment();
 #endif
 
     virtual bool RecvSetProcessSandbox() MOZ_OVERRIDE;
 
     PBackgroundChild*
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -68,16 +68,18 @@
 #include "mozilla/ipc/TestShellParent.h"
 #include "mozilla/ipc/InputStreamUtils.h"
 #include "mozilla/layers/CompositorParent.h"
 #include "mozilla/layers/ImageBridgeParent.h"
 #include "mozilla/layers/SharedBufferManagerParent.h"
 #include "mozilla/net/NeckoParent.h"
 #include "mozilla/plugins/PluginBridge.h"
 #include "mozilla/Preferences.h"
+#include "mozilla/ProcessHangMonitor.h"
+#include "mozilla/ProcessHangMonitorIPC.h"
 #include "mozilla/Services.h"
 #include "mozilla/StaticPtr.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/unused.h"
 #include "nsAnonymousTemporaryFile.h"
 #include "nsAppRunner.h"
 #include "nsAutoPtr.h"
 #include "nsCDefaultURIFixup.h"
@@ -1797,16 +1799,21 @@ ContentParent::ActorDestroy(ActorDestroy
         mForceKillTimer->Cancel();
         mForceKillTimer = nullptr;
     }
 
     // Signal shutdown completion regardless of error state, so we can
     // finish waiting in the xpcom-shutdown/profile-before-change observer.
     mIPCOpen = false;
 
+    if (mHangMonitorActor) {
+        ProcessHangMonitor::RemoveProcess(mHangMonitorActor);
+        mHangMonitorActor = nullptr;
+    }
+
     if (why == NormalShutdown && !mCalledClose) {
         // If we shut down normally but haven't called Close, assume somebody
         // else called Close on us. In that case, we still need to call
         // ShutDownProcess below to perform other necessary clean up.
         mCalledClose = true;
     }
 
     // Make sure we always clean up.
@@ -2029,16 +2036,17 @@ ContentParent::InitializeMembers()
     mSendPermissionUpdates = false;
     mSendDataStoreInfos = false;
     mCalledClose = false;
     mCalledCloseWithError = false;
     mCalledKillHard = false;
     mCreatedPairedMinidumps = false;
     mShutdownPending = false;
     mIPCOpen = true;
+    mHangMonitorActor = nullptr;
 }
 
 ContentParent::ContentParent(mozIApplication* aApp,
                              ContentParent* aOpener,
                              bool aIsForBrowser,
                              bool aIsForPreallocated,
                              ProcessPriority aInitialPriority /* = PROCESS_PRIORITY_FOREGROUND */,
                              bool aIsNuwaProcess /* = false */)
@@ -2108,16 +2116,18 @@ ContentParent::ContentParent(mozIApplica
     Open(mSubprocess->GetChannel(), mSubprocess->GetOwnedChildProcessHandle());
 
     InitInternal(aInitialPriority,
                  true, /* Setup off-main thread compositing */
                  true  /* Send registered chrome */);
 
     ContentProcessManager::GetSingleton()->AddContentProcess(this);
 
+    ProcessHangMonitor::AddProcess(this);
+
     // Set a reply timeout for CPOWs.
     SetReplyTimeoutMs(Preferences::GetInt("dom.ipc.cpow.timeout", 0));
 }
 
 #ifdef MOZ_NUWA_PROCESS
 static const mozilla::ipc::FileDescriptor*
 FindFdProtocolFdMapping(const nsTArray<ProtocolFdMapping>& aFds,
                         ProtocolId aProtoId)
@@ -3045,16 +3055,24 @@ ContentParent::AllocPImageBridgeParent(m
 
 PBackgroundParent*
 ContentParent::AllocPBackgroundParent(Transport* aTransport,
                                       ProcessId aOtherProcess)
 {
     return BackgroundParent::Alloc(this, aTransport, aOtherProcess);
 }
 
+PProcessHangMonitorParent*
+ContentParent::AllocPProcessHangMonitorParent(Transport* aTransport,
+                                              ProcessId aOtherProcess)
+{
+    mHangMonitorActor = CreateHangMonitorParent(this, aTransport, aOtherProcess);
+    return mHangMonitorActor;
+}
+
 PSharedBufferManagerParent*
 ContentParent::AllocPSharedBufferManagerParent(mozilla::ipc::Transport* aTransport,
                                                 base::ProcessId aOtherProcess)
 {
     return SharedBufferManagerParent::Create(aTransport, aOtherProcess);
 }
 
 bool
@@ -4294,17 +4312,18 @@ ContentParent::RecvNotifyKeywordSearchLo
     }
 #endif
     return true;
 }
 
 bool
 ContentParent::ShouldContinueFromReplyTimeout()
 {
-    return false;
+    nsRefPtr<ProcessHangMonitor> monitor = ProcessHangMonitor::Get();
+    return !monitor || !monitor->ShouldTimeOutCPOWs();
 }
 
 bool
 ContentParent::RecvRecordingDeviceEvents(const nsString& aRecordingStatus,
                                          const nsString& aPageURL,
                                          const bool& aIsAudio,
                                          const bool& aIsVideo)
 {
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -480,16 +480,20 @@ private:
 
     PSharedBufferManagerParent*
     AllocPSharedBufferManagerParent(mozilla::ipc::Transport* aTranport,
                                      base::ProcessId aOtherProcess) MOZ_OVERRIDE;
     PBackgroundParent*
     AllocPBackgroundParent(Transport* aTransport, ProcessId aOtherProcess)
                            MOZ_OVERRIDE;
 
+    PProcessHangMonitorParent*
+    AllocPProcessHangMonitorParent(Transport* aTransport,
+                                   ProcessId aOtherProcess) MOZ_OVERRIDE;
+
     virtual bool RecvGetProcessAttributes(ContentParentId* aCpId,
                                           bool* aIsForApp,
                                           bool* aIsForBrowser) MOZ_OVERRIDE;
     virtual bool RecvGetXPCOMProcessAttributes(bool* aIsOffline,
                                                InfallibleTArray<nsString>* dictionaries,
                                                ClipboardCapabilities* clipboardCaps)
         MOZ_OVERRIDE;
 
@@ -834,16 +838,18 @@ private:
     // object instead of the child process's lifetime.
     ScopedClose mChildXSocketFdDup;
 #endif
 
 #ifdef MOZ_NUWA_PROCESS
     static int32_t sNuwaPid;
     static bool sNuwaReady;
 #endif
+
+    PProcessHangMonitorParent* mHangMonitorActor;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 class ParentIdleListener : public nsIObserver {
 public:
   NS_DECL_ISUPPORTS
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -16,16 +16,17 @@ include protocol PCycleCollectWithLogs;
 include protocol PCrashReporter;
 include protocol PDocAccessible;
 include protocol PExternalHelperApp;
 include protocol PDeviceStorageRequest;
 include protocol PFileDescriptorSet;
 include protocol PFMRadio;
 include protocol PFileSystemRequest;
 include protocol PHal;
+include protocol PProcessHangMonitor;
 include protocol PImageBridge;
 include protocol PMemoryReportRequest;
 include protocol PMobileConnection;
 include protocol PNecko;
 include protocol PPluginModule;
 include protocol PPrinting;
 include protocol POfflineCacheUpdate;
 include protocol PScreenManager;
@@ -340,16 +341,17 @@ union OptionalContentId
   void_t;
 };
 
 prio(normal upto urgent) intr protocol PContent
 {
     parent spawns PPluginModule;
 
     parent opens PCompositor;
+    parent opens PProcessHangMonitor;
     parent opens PSharedBufferManager;
     parent opens PImageBridge;
     child opens PBackground;
 
     manages PAsmJSCacheEntry;
     manages PBlob;
     manages PBluetooth;
     manages PBrowser;
new file mode 100644
--- /dev/null
+++ b/dom/ipc/PProcessHangMonitor.ipdl
@@ -0,0 +1,42 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: sw=2 ts=8 et :
+ */
+/* 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/. */
+
+using mozilla::dom::TabId from "mozilla/dom/ipc/IdType.h";
+
+namespace mozilla {
+
+struct SlowScriptData
+{
+  TabId tabId;
+  nsCString filename;
+  uint32_t lineno;
+};
+
+struct PluginHangData
+{
+  uint32_t pluginId;
+};
+
+union HangData
+{
+  SlowScriptData;
+  PluginHangData;
+};
+
+protocol PProcessHangMonitor
+{
+parent:
+  async HangEvidence(HangData data);
+
+child:
+  async TerminateScript();
+
+  async BeginStartingDebugger();
+  async EndStartingDebugger();
+};
+
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/ipc/ProcessHangMonitor.cpp
@@ -0,0 +1,954 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/ProcessHangMonitor.h"
+#include "mozilla/ProcessHangMonitorIPC.h"
+
+#include "mozilla/Atomics.h"
+#include "mozilla/dom/ContentParent.h"
+#include "mozilla/dom/Element.h"
+#include "mozilla/dom/TabChild.h"
+#include "mozilla/dom/TabParent.h"
+#include "mozilla/Monitor.h"
+#include "mozilla/plugins/PluginBridge.h"
+#include "mozilla/Preferences.h"
+#include "mozilla/unused.h"
+
+#include "nsIFrameLoader.h"
+#include "nsIHangReport.h"
+#include "nsITabParent.h"
+#include "nsPluginHost.h"
+#include "nsThreadUtils.h"
+
+#include "base/task.h"
+#include "base/thread.h"
+
+using namespace mozilla;
+using namespace mozilla::dom;
+
+/*
+ * Basic architecture:
+ *
+ * Each process has its own ProcessHangMonitor singleton. This singleton exists
+ * as long as there is at least one content process in the system. Each content
+ * process has a HangMonitorChild and the chrome process has one
+ * HangMonitorParent per process. Each process (including the chrome process)
+ * runs a hang monitoring thread. The PHangMonitor actors are bound to this
+ * thread so that they never block on the main thread.
+ *
+ * When the content process detects a hang, it posts a task to its hang thread,
+ * which sends an IPC message to the hang thread in the parent. The parent
+ * cancels any ongoing CPOW requests and then posts a runnable to the main
+ * thread that notifies Firefox frontend code of the hang. The frontend code is
+ * passed an nsIHangReport, which can be used to terminate the hang.
+ *
+ * If the user chooses to terminate a script, a task is posted to the chrome
+ * process's hang monitoring thread, which sends an IPC message to the hang
+ * thread in the content process. That thread sets a flag to indicate that JS
+ * execution should be terminated the next time it hits the interrupt
+ * callback. A similar scheme is used for debugging slow scripts. If a content
+ * process or plug-in needs to be terminated, the chrome process does so
+ * directly, without messaging the content process.
+ */
+
+namespace {
+
+/* Child process objects */
+
+class HangMonitorChild
+  : public PProcessHangMonitorChild
+{
+ public:
+  explicit HangMonitorChild(ProcessHangMonitor* aMonitor);
+  virtual ~HangMonitorChild();
+
+  void Open(Transport* aTransport, ProcessHandle aHandle,
+            MessageLoop* aIOLoop);
+
+  typedef ProcessHangMonitor::SlowScriptAction SlowScriptAction;
+  SlowScriptAction NotifySlowScript(nsITabChild* aTabChild,
+                                    const char* aFileName,
+                                    unsigned aLineNo);
+  void NotifySlowScriptAsync(TabId aTabId,
+                             const nsCString& aFileName,
+                             unsigned aLineNo);
+
+  bool IsDebuggerStartupComplete();
+
+  void NotifyPluginHang(uint32_t aPluginId);
+  void NotifyPluginHangAsync(uint32_t aPluginId);
+
+  void ClearHang();
+
+  virtual bool RecvTerminateScript() MOZ_OVERRIDE;
+  virtual bool RecvBeginStartingDebugger() MOZ_OVERRIDE;
+  virtual bool RecvEndStartingDebugger() MOZ_OVERRIDE;
+
+  virtual void ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
+
+  void Shutdown();
+
+  static HangMonitorChild* Get() { return sInstance; }
+
+  MessageLoop* MonitorLoop() { return mHangMonitor->MonitorLoop(); }
+
+ private:
+  void ShutdownOnThread();
+
+  static HangMonitorChild* sInstance;
+
+  const nsRefPtr<ProcessHangMonitor> mHangMonitor;
+  Monitor mMonitor;
+
+  // Main thread-only.
+  bool mSentReport;
+
+  // These fields must be accessed with mMonitor held.
+  bool mTerminateScript;
+  bool mStartDebugger;
+  bool mFinishedStartingDebugger;
+  bool mShutdownDone;
+
+  // This field is only accessed on the hang thread.
+  bool mIPCOpen;
+};
+
+HangMonitorChild* HangMonitorChild::sInstance;
+
+/* Parent process objects */
+
+class HangMonitorParent;
+
+class HangMonitoredProcess MOZ_FINAL
+  : public nsIHangReport
+{
+public:
+  NS_DECL_THREADSAFE_ISUPPORTS
+
+  HangMonitoredProcess(HangMonitorParent* aActor,
+                       ContentParent* aContentParent)
+    : mActor(aActor), mContentParent(aContentParent) {}
+
+  NS_IMETHOD GetHangType(uint32_t* aHangType) MOZ_OVERRIDE;
+  NS_IMETHOD GetScriptBrowser(nsIDOMElement** aBrowser) MOZ_OVERRIDE;
+  NS_IMETHOD GetScriptFileName(nsACString& aFileName) MOZ_OVERRIDE;
+  NS_IMETHOD GetScriptLineNo(uint32_t* aLineNo) MOZ_OVERRIDE;
+
+  NS_IMETHOD GetPluginName(nsACString& aPluginName) MOZ_OVERRIDE;
+
+  NS_IMETHOD TerminateScript() MOZ_OVERRIDE;
+  NS_IMETHOD BeginStartingDebugger() MOZ_OVERRIDE;
+  NS_IMETHOD EndStartingDebugger() MOZ_OVERRIDE;
+  NS_IMETHOD TerminatePlugin() MOZ_OVERRIDE;
+  NS_IMETHOD TerminateProcess() MOZ_OVERRIDE;
+
+  NS_IMETHOD IsReportForBrowser(nsIFrameLoader* aFrameLoader, bool* aResult);
+
+  void Clear() { mContentParent = nullptr; mActor = nullptr; }
+
+  void SetHangData(const HangData& aHangData) { mHangData = aHangData; }
+
+private:
+  ~HangMonitoredProcess() {}
+
+  // Everything here is main thread-only.
+  HangMonitorParent* mActor;
+  ContentParent* mContentParent;
+  HangData mHangData;
+};
+
+class HangMonitorParent
+  : public PProcessHangMonitorParent
+{
+public:
+  explicit HangMonitorParent(ProcessHangMonitor* aMonitor);
+  virtual ~HangMonitorParent();
+
+  void Open(Transport* aTransport, ProcessHandle aHandle,
+            MessageLoop* aIOLoop);
+
+  virtual bool RecvHangEvidence(const HangData& aHangData) MOZ_OVERRIDE;
+
+  virtual void ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
+
+  void SetProcess(HangMonitoredProcess* aProcess) { mProcess = aProcess; }
+
+  void Shutdown();
+
+  void TerminateScript();
+  void BeginStartingDebugger();
+  void EndStartingDebugger();
+
+  MessageLoop* MonitorLoop() { return mHangMonitor->MonitorLoop(); }
+
+ private:
+  void ShutdownOnThread();
+
+  const nsRefPtr<ProcessHangMonitor> mHangMonitor;
+
+  // This field is read-only after construction.
+  bool mReportHangs;
+
+  // This field is only accessed on the hang thread.
+  bool mIPCOpen;
+
+  Monitor mMonitor;
+
+  // Must be accessed with mMonitor held.
+  nsRefPtr<HangMonitoredProcess> mProcess;
+  bool mShutdownDone;
+};
+
+} // namespace
+
+template<>
+struct RunnableMethodTraits<HangMonitorChild>
+{
+  typedef HangMonitorChild Class;
+  static void RetainCallee(Class* obj) { }
+  static void ReleaseCallee(Class* obj) { }
+};
+
+template<>
+struct RunnableMethodTraits<HangMonitorParent>
+{
+  typedef HangMonitorParent Class;
+  static void RetainCallee(Class* obj) { }
+  static void ReleaseCallee(Class* obj) { }
+};
+
+/* HangMonitorChild implementation */
+
+HangMonitorChild::HangMonitorChild(ProcessHangMonitor* aMonitor)
+ : mHangMonitor(aMonitor),
+   mMonitor("HangMonitorChild lock"),
+   mSentReport(false),
+   mTerminateScript(false),
+   mStartDebugger(false),
+   mFinishedStartingDebugger(false),
+   mShutdownDone(false),
+   mIPCOpen(true)
+{
+  MOZ_RELEASE_ASSERT(NS_IsMainThread());
+}
+
+HangMonitorChild::~HangMonitorChild()
+{
+  MOZ_RELEASE_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(sInstance == this);
+  sInstance = nullptr;
+}
+
+void
+HangMonitorChild::Shutdown()
+{
+  MOZ_RELEASE_ASSERT(NS_IsMainThread());
+
+  MonitorAutoLock lock(mMonitor);
+  while (!mShutdownDone) {
+    mMonitor.Wait();
+  }
+}
+
+void
+HangMonitorChild::ShutdownOnThread()
+{
+  MOZ_RELEASE_ASSERT(MessageLoop::current() == MonitorLoop());
+
+  MonitorAutoLock lock(mMonitor);
+  mShutdownDone = true;
+  mMonitor.Notify();
+}
+
+void
+HangMonitorChild::ActorDestroy(ActorDestroyReason aWhy)
+{
+  MOZ_RELEASE_ASSERT(MessageLoop::current() == MonitorLoop());
+
+  mIPCOpen = false;
+
+  // We use a task here to ensure that IPDL is finished with this
+  // HangMonitorChild before it gets deleted on the main thread.
+  MonitorLoop()->PostTask(
+    FROM_HERE,
+    NewRunnableMethod(this, &HangMonitorChild::ShutdownOnThread));
+}
+
+bool
+HangMonitorChild::RecvTerminateScript()
+{
+  MOZ_RELEASE_ASSERT(MessageLoop::current() == MonitorLoop());
+
+  MonitorAutoLock lock(mMonitor);
+  mTerminateScript = true;
+  return true;
+}
+
+bool
+HangMonitorChild::RecvBeginStartingDebugger()
+{
+  MOZ_RELEASE_ASSERT(MessageLoop::current() == MonitorLoop());
+
+  MonitorAutoLock lock(mMonitor);
+  mStartDebugger = true;
+  return true;
+}
+
+bool
+HangMonitorChild::RecvEndStartingDebugger()
+{
+  MOZ_RELEASE_ASSERT(MessageLoop::current() == MonitorLoop());
+
+  MonitorAutoLock lock(mMonitor);
+  mFinishedStartingDebugger = true;
+  return true;
+}
+
+void
+HangMonitorChild::Open(Transport* aTransport, ProcessHandle aHandle,
+                       MessageLoop* aIOLoop)
+{
+  MOZ_RELEASE_ASSERT(MessageLoop::current() == MonitorLoop());
+
+  MOZ_ASSERT(!sInstance);
+  sInstance = this;
+
+  DebugOnly<bool> ok = PProcessHangMonitorChild::Open(aTransport, aHandle, aIOLoop);
+  MOZ_ASSERT(ok);
+}
+
+void
+HangMonitorChild::NotifySlowScriptAsync(TabId aTabId,
+                                        const nsCString& aFileName,
+                                        unsigned aLineNo)
+{
+  if (mIPCOpen) {
+    unused << SendHangEvidence(SlowScriptData(aTabId, aFileName, aLineNo));
+  }
+}
+
+HangMonitorChild::SlowScriptAction
+HangMonitorChild::NotifySlowScript(nsITabChild* aTabChild,
+                                   const char* aFileName,
+                                   unsigned aLineNo)
+{
+  MOZ_RELEASE_ASSERT(NS_IsMainThread());
+
+  mSentReport = true;
+
+  {
+    MonitorAutoLock lock(mMonitor);
+
+    if (mTerminateScript) {
+      mTerminateScript = false;
+      return SlowScriptAction::Terminate;
+    }
+
+    if (mStartDebugger) {
+      mStartDebugger = false;
+      return SlowScriptAction::StartDebugger;
+    }
+  }
+
+  TabId id;
+  if (aTabChild) {
+    nsRefPtr<TabChild> tabChild = static_cast<TabChild*>(aTabChild);
+    id = tabChild->GetTabId();
+  }
+  nsAutoCString filename(aFileName);
+
+  MonitorLoop()->PostTask(
+    FROM_HERE,
+    NewRunnableMethod(this, &HangMonitorChild::NotifySlowScriptAsync,
+                      id, filename, aLineNo));
+  return SlowScriptAction::Continue;
+}
+
+bool
+HangMonitorChild::IsDebuggerStartupComplete()
+{
+  MOZ_RELEASE_ASSERT(NS_IsMainThread());
+
+  MonitorAutoLock lock(mMonitor);
+
+  if (mFinishedStartingDebugger) {
+    mFinishedStartingDebugger = false;
+    return true;
+  }
+
+  return false;
+}
+
+void
+HangMonitorChild::NotifyPluginHang(uint32_t aPluginId)
+{
+  MOZ_RELEASE_ASSERT(NS_IsMainThread());
+
+  mSentReport = true;
+
+  MonitorLoop()->PostTask(
+    FROM_HERE,
+    NewRunnableMethod(this,
+                      &HangMonitorChild::NotifyPluginHangAsync,
+                      aPluginId));
+}
+
+void
+HangMonitorChild::NotifyPluginHangAsync(uint32_t aPluginId)
+{
+  MOZ_RELEASE_ASSERT(MessageLoop::current() == MonitorLoop());
+
+  if (mIPCOpen) {
+    unused << SendHangEvidence(PluginHangData(aPluginId));
+  }
+}
+
+void
+HangMonitorChild::ClearHang()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  if (mSentReport) {
+    MonitorAutoLock lock(mMonitor);
+    mSentReport = false;
+    mTerminateScript = false;
+    mStartDebugger = false;
+    mFinishedStartingDebugger = false;
+  }
+}
+
+/* HangMonitorParent implementation */
+
+HangMonitorParent::HangMonitorParent(ProcessHangMonitor* aMonitor)
+ : mHangMonitor(aMonitor),
+   mIPCOpen(true),
+   mMonitor("HangMonitorParent lock"),
+   mShutdownDone(false)
+{
+  MOZ_RELEASE_ASSERT(NS_IsMainThread());
+  mReportHangs = mozilla::Preferences::GetBool("dom.ipc.reportProcessHangs", false);
+}
+
+HangMonitorParent::~HangMonitorParent()
+{
+  // For some reason IPDL doesn't autmatically delete the channel for a
+  // bridged protocol (bug 1090570). So we have to do it ourselves.
+  XRE_GetIOMessageLoop()->PostTask(FROM_HERE, new DeleteTask<Transport>(GetTransport()));
+}
+
+void
+HangMonitorParent::Shutdown()
+{
+  MOZ_RELEASE_ASSERT(NS_IsMainThread());
+
+  MonitorAutoLock lock(mMonitor);
+
+  if (mProcess) {
+    mProcess->Clear();
+    mProcess = nullptr;
+  }
+
+  MonitorLoop()->PostTask(
+    FROM_HERE,
+    NewRunnableMethod(this, &HangMonitorParent::ShutdownOnThread));
+
+  while (!mShutdownDone) {
+    mMonitor.Wait();
+  }
+}
+
+void
+HangMonitorParent::ShutdownOnThread()
+{
+  MOZ_RELEASE_ASSERT(MessageLoop::current() == MonitorLoop());
+
+  // mIPCOpen is only written from this thread, so need need to take the lock
+  // here. We'd be shooting ourselves in the foot, because ActorDestroy takes
+  // it.
+  if (mIPCOpen) {
+    Close();
+  }
+
+  MonitorAutoLock lock(mMonitor);
+  mShutdownDone = true;
+  mMonitor.Notify();
+}
+
+void
+HangMonitorParent::ActorDestroy(ActorDestroyReason aWhy)
+{
+  MOZ_RELEASE_ASSERT(MessageLoop::current() == MonitorLoop());
+  mIPCOpen = false;
+}
+
+void
+HangMonitorParent::Open(Transport* aTransport, ProcessHandle aHandle,
+                        MessageLoop* aIOLoop)
+{
+  MOZ_RELEASE_ASSERT(MessageLoop::current() == MonitorLoop());
+
+  DebugOnly<bool> ok = PProcessHangMonitorParent::Open(aTransport, aHandle, aIOLoop);
+  MOZ_ASSERT(ok);
+}
+
+class HangObserverNotifier MOZ_FINAL : public nsRunnable
+{
+public:
+  HangObserverNotifier(HangMonitoredProcess* aProcess, const HangData& aHangData)
+    : mProcess(aProcess),
+      mHangData(aHangData)
+  {}
+
+  NS_IMETHOD
+  Run()
+  {
+    MOZ_RELEASE_ASSERT(NS_IsMainThread());
+    mProcess->SetHangData(mHangData);
+
+    nsCOMPtr<nsIObserverService> observerService =
+      mozilla::services::GetObserverService();
+    observerService->NotifyObservers(mProcess, "process-hang-report", nullptr);
+    return NS_OK;
+  }
+
+private:
+  nsRefPtr<HangMonitoredProcess> mProcess;
+  HangData mHangData;
+};
+
+bool
+HangMonitorParent::RecvHangEvidence(const HangData& aHangData)
+{
+  MOZ_RELEASE_ASSERT(MessageLoop::current() == MonitorLoop());
+
+  if (!mReportHangs) {
+    return true;
+  }
+
+  mHangMonitor->InitiateCPOWTimeout();
+
+  MonitorAutoLock lock(mMonitor);
+
+  nsCOMPtr<nsIRunnable> notifier = new HangObserverNotifier(mProcess, aHangData);
+  NS_DispatchToMainThread(notifier);
+
+  return true;
+}
+
+void
+HangMonitorParent::TerminateScript()
+{
+  MOZ_RELEASE_ASSERT(MessageLoop::current() == MonitorLoop());
+
+  if (mIPCOpen) {
+    unused << SendTerminateScript();
+  }
+}
+
+void
+HangMonitorParent::BeginStartingDebugger()
+{
+  MOZ_RELEASE_ASSERT(MessageLoop::current() == MonitorLoop());
+
+  if (mIPCOpen) {
+    unused << SendBeginStartingDebugger();
+  }
+}
+
+void
+HangMonitorParent::EndStartingDebugger()
+{
+  MOZ_RELEASE_ASSERT(MessageLoop::current() == MonitorLoop());
+
+  if (mIPCOpen) {
+    unused << SendEndStartingDebugger();
+  }
+}
+
+/* HangMonitoredProcess implementation */
+
+NS_IMPL_ISUPPORTS(HangMonitoredProcess, nsIHangReport)
+
+NS_IMETHODIMP
+HangMonitoredProcess::GetHangType(uint32_t* aHangType)
+{
+  MOZ_RELEASE_ASSERT(NS_IsMainThread());
+  switch (mHangData.type()) {
+   case HangData::TSlowScriptData:
+    *aHangType = SLOW_SCRIPT;
+    break;
+   case HangData::TPluginHangData:
+    *aHangType = PLUGIN_HANG;
+    break;
+   default:
+    MOZ_ASSERT(false);
+    return NS_ERROR_UNEXPECTED;
+    break;
+  }
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+HangMonitoredProcess::GetScriptBrowser(nsIDOMElement** aBrowser)
+{
+  MOZ_RELEASE_ASSERT(NS_IsMainThread());
+  if (mHangData.type() != HangData::TSlowScriptData) {
+    return NS_ERROR_NOT_AVAILABLE;
+  }
+
+  TabId tabId = mHangData.get_SlowScriptData().tabId();
+  if (!mContentParent) {
+    return NS_ERROR_NOT_AVAILABLE;
+  }
+
+  nsTArray<PBrowserParent*> tabs;
+  mContentParent->ManagedPBrowserParent(tabs);
+  for (size_t i = 0; i < tabs.Length(); i++) {
+    TabParent* tp = static_cast<TabParent*>(tabs[i]);
+    if (tp->GetTabId() == tabId) {
+      nsCOMPtr<nsIDOMElement> node = do_QueryInterface(tp->GetOwnerElement());
+      node.forget(aBrowser);
+      return NS_OK;
+    }
+  }
+
+  *aBrowser = nullptr;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+HangMonitoredProcess::GetScriptFileName(nsACString& aFileName)
+{
+  MOZ_RELEASE_ASSERT(NS_IsMainThread());
+  if (mHangData.type() != HangData::TSlowScriptData) {
+    return NS_ERROR_NOT_AVAILABLE;
+  }
+
+  aFileName = mHangData.get_SlowScriptData().filename();
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+HangMonitoredProcess::GetScriptLineNo(uint32_t* aLineNo)
+{
+  MOZ_RELEASE_ASSERT(NS_IsMainThread());
+  if (mHangData.type() != HangData::TSlowScriptData) {
+    return NS_ERROR_NOT_AVAILABLE;
+  }
+
+  *aLineNo = mHangData.get_SlowScriptData().lineno();
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+HangMonitoredProcess::GetPluginName(nsACString& aPluginName)
+{
+  MOZ_RELEASE_ASSERT(NS_IsMainThread());
+  if (mHangData.type() != HangData::TPluginHangData) {
+    return NS_ERROR_NOT_AVAILABLE;
+  }
+
+  uint32_t id = mHangData.get_PluginHangData().pluginId();
+
+  nsRefPtr<nsPluginHost> host = nsPluginHost::GetInst();
+  nsPluginTag* tag = host->PluginWithId(id);
+  if (!tag) {
+    return NS_ERROR_UNEXPECTED;
+  }
+
+  aPluginName = tag->mName;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+HangMonitoredProcess::TerminateScript()
+{
+  MOZ_RELEASE_ASSERT(NS_IsMainThread());
+  if (mHangData.type() != HangData::TSlowScriptData) {
+    return NS_ERROR_UNEXPECTED;
+  }
+
+  if (!mActor) {
+    return NS_ERROR_UNEXPECTED;
+  }
+
+  ProcessHangMonitor::Get()->MonitorLoop()->PostTask(
+    FROM_HERE,
+    NewRunnableMethod(mActor, &HangMonitorParent::TerminateScript));
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+HangMonitoredProcess::BeginStartingDebugger()
+{
+  MOZ_RELEASE_ASSERT(NS_IsMainThread());
+  if (mHangData.type() != HangData::TSlowScriptData) {
+    return NS_ERROR_UNEXPECTED;
+  }
+
+  if (!mActor) {
+    return NS_ERROR_UNEXPECTED;
+  }
+
+  ProcessHangMonitor::Get()->MonitorLoop()->PostTask(
+    FROM_HERE,
+    NewRunnableMethod(mActor, &HangMonitorParent::BeginStartingDebugger));
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+HangMonitoredProcess::EndStartingDebugger()
+{
+  MOZ_RELEASE_ASSERT(NS_IsMainThread());
+  if (mHangData.type() != HangData::TSlowScriptData) {
+    return NS_ERROR_UNEXPECTED;
+  }
+
+  if (!mActor) {
+    return NS_ERROR_UNEXPECTED;
+  }
+
+  ProcessHangMonitor::Get()->MonitorLoop()->PostTask(
+    FROM_HERE,
+    NewRunnableMethod(mActor, &HangMonitorParent::EndStartingDebugger));
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+HangMonitoredProcess::TerminatePlugin()
+{
+  MOZ_RELEASE_ASSERT(NS_IsMainThread());
+  if (mHangData.type() != HangData::TPluginHangData) {
+    return NS_ERROR_UNEXPECTED;
+  }
+
+  uint32_t id = mHangData.get_PluginHangData().pluginId();
+  plugins::TerminatePlugin(id);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+HangMonitoredProcess::TerminateProcess()
+{
+  MOZ_RELEASE_ASSERT(NS_IsMainThread());
+
+  if (!mContentParent) {
+    return NS_ERROR_UNEXPECTED;
+  }
+
+  mContentParent->KillHard();
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+HangMonitoredProcess::IsReportForBrowser(nsIFrameLoader* aFrameLoader, bool* aResult)
+{
+  MOZ_RELEASE_ASSERT(NS_IsMainThread());
+
+  if (!mActor) {
+    *aResult = false;
+    return NS_OK;
+  }
+
+  nsCOMPtr<nsITabParent> itp;
+  aFrameLoader->GetTabParent(getter_AddRefs(itp));
+  if (!itp) {
+    *aResult = false;
+    return NS_OK;
+  }
+
+  *aResult = mContentParent == static_cast<TabParent*>(itp.get())->Manager();
+  return NS_OK;
+}
+
+ProcessHangMonitor* ProcessHangMonitor::sInstance;
+
+ProcessHangMonitor::ProcessHangMonitor()
+ : mCPOWTimeout(false)
+{
+  MOZ_RELEASE_ASSERT(NS_IsMainThread());
+
+  MOZ_COUNT_CTOR(ProcessHangMonitor);
+
+  if (XRE_GetProcessType() == GeckoProcessType_Content) {
+    nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
+    obs->AddObserver(this, "xpcom-shutdown", false);
+  }
+
+  mThread = new base::Thread("ProcessHangMonitor");
+  if (!mThread->Start()) {
+    delete mThread;
+    mThread = nullptr;
+  }
+}
+
+ProcessHangMonitor::~ProcessHangMonitor()
+{
+  MOZ_RELEASE_ASSERT(NS_IsMainThread());
+
+  MOZ_COUNT_DTOR(ProcessHangMonitor);
+
+  MOZ_ASSERT(sInstance == this);
+  sInstance = nullptr;
+
+  delete mThread;
+}
+
+ProcessHangMonitor*
+ProcessHangMonitor::GetOrCreate()
+{
+  MOZ_RELEASE_ASSERT(NS_IsMainThread());
+  if (!sInstance) {
+    sInstance = new ProcessHangMonitor();
+  }
+  return sInstance;
+}
+
+NS_IMPL_ISUPPORTS(ProcessHangMonitor, nsIObserver)
+
+NS_IMETHODIMP
+ProcessHangMonitor::Observe(nsISupports* aSubject, const char* aTopic, const char16_t* aData)
+{
+  MOZ_RELEASE_ASSERT(NS_IsMainThread());
+  if (!strcmp(aTopic, "xpcom-shutdown")) {
+    if (HangMonitorChild* child = HangMonitorChild::Get()) {
+      child->Shutdown();
+      delete child;
+    }
+
+    nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
+    if (obs) {
+      obs->RemoveObserver(this, "xpcom-shutdown");
+    }
+  }
+  return NS_OK;
+}
+
+ProcessHangMonitor::SlowScriptAction
+ProcessHangMonitor::NotifySlowScript(nsITabChild* aTabChild,
+                                     const char* aFileName,
+                                     unsigned aLineNo)
+{
+  MOZ_RELEASE_ASSERT(NS_IsMainThread());
+  return HangMonitorChild::Get()->NotifySlowScript(aTabChild, aFileName, aLineNo);
+}
+
+bool
+ProcessHangMonitor::IsDebuggerStartupComplete()
+{
+  MOZ_RELEASE_ASSERT(NS_IsMainThread());
+  return HangMonitorChild::Get()->IsDebuggerStartupComplete();
+}
+
+bool
+ProcessHangMonitor::ShouldTimeOutCPOWs()
+{
+  MOZ_RELEASE_ASSERT(NS_IsMainThread());
+
+  if (mCPOWTimeout) {
+    mCPOWTimeout = false;
+    return true;
+  }
+  return false;
+}
+
+void
+ProcessHangMonitor::InitiateCPOWTimeout()
+{
+  MOZ_RELEASE_ASSERT(MessageLoop::current() == MonitorLoop());
+  mCPOWTimeout = true;
+}
+
+void
+ProcessHangMonitor::NotifyPluginHang(uint32_t aPluginId)
+{
+  MOZ_RELEASE_ASSERT(NS_IsMainThread());
+  return HangMonitorChild::Get()->NotifyPluginHang(aPluginId);
+}
+
+PProcessHangMonitorParent*
+mozilla::CreateHangMonitorParent(ContentParent* aContentParent,
+                                 mozilla::ipc::Transport* aTransport,
+                                 base::ProcessId aOtherProcess)
+{
+  MOZ_RELEASE_ASSERT(NS_IsMainThread());
+
+  ProcessHangMonitor* monitor = ProcessHangMonitor::GetOrCreate();
+  HangMonitorParent* parent = new HangMonitorParent(monitor);
+
+  HangMonitoredProcess* process = new HangMonitoredProcess(parent, aContentParent);
+  parent->SetProcess(process);
+
+  base::ProcessHandle handle;
+  if (!base::OpenProcessHandle(aOtherProcess, &handle)) {
+    // XXX need to kill |aOtherProcess|, it's boned
+    return nullptr;
+  }
+
+  monitor->MonitorLoop()->PostTask(
+    FROM_HERE,
+    NewRunnableMethod(parent, &HangMonitorParent::Open,
+                      aTransport, handle, XRE_GetIOMessageLoop()));
+
+  return parent;
+}
+
+PProcessHangMonitorChild*
+mozilla::CreateHangMonitorChild(mozilla::ipc::Transport* aTransport,
+                                base::ProcessId aOtherProcess)
+{
+  MOZ_RELEASE_ASSERT(NS_IsMainThread());
+
+  ProcessHangMonitor* monitor = ProcessHangMonitor::GetOrCreate();
+  HangMonitorChild* child = new HangMonitorChild(monitor);
+
+  base::ProcessHandle handle;
+  if (!base::OpenProcessHandle(aOtherProcess, &handle)) {
+    // XXX need to kill |aOtherProcess|, it's boned
+    return nullptr;
+  }
+
+  monitor->MonitorLoop()->PostTask(
+    FROM_HERE,
+    NewRunnableMethod(child, &HangMonitorChild::Open,
+                      aTransport, handle, XRE_GetIOMessageLoop()));
+
+  return child;
+}
+
+MessageLoop*
+ProcessHangMonitor::MonitorLoop()
+{
+  return mThread->message_loop();
+}
+
+/* static */ void
+ProcessHangMonitor::AddProcess(ContentParent* aContentParent)
+{
+  MOZ_RELEASE_ASSERT(NS_IsMainThread());
+
+  if (mozilla::Preferences::GetBool("dom.ipc.processHangMonitor", false)) {
+    DebugOnly<bool> opened = PProcessHangMonitor::Open(aContentParent);
+    MOZ_ASSERT(opened);
+  }
+}
+
+/* static */ void
+ProcessHangMonitor::RemoveProcess(PProcessHangMonitorParent* aParent)
+{
+  MOZ_RELEASE_ASSERT(NS_IsMainThread());
+  auto parent = static_cast<HangMonitorParent*>(aParent);
+  parent->Shutdown();
+  delete parent;
+}
+
+/* static */ void
+ProcessHangMonitor::ClearHang()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  if (HangMonitorChild* child = HangMonitorChild::Get()) {
+    child->ClearHang();
+  }
+}
new file mode 100644
--- /dev/null
+++ b/dom/ipc/ProcessHangMonitor.h
@@ -0,0 +1,78 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_ProcessHangMonitor_h
+#define mozilla_ProcessHangMonitor_h
+
+#include "mozilla/Atomics.h"
+#include "nsIObserver.h"
+
+class nsGlobalWindow;
+class nsITabChild;
+
+class MessageLoop;
+
+namespace base {
+class Thread;
+};
+
+namespace mozilla {
+
+namespace dom {
+class ContentParent;
+}
+
+class PProcessHangMonitorParent;
+class PProcessHangMonitorChild;
+
+class ProcessHangMonitor MOZ_FINAL
+  : public nsIObserver
+{
+ private:
+  ProcessHangMonitor();
+  virtual ~ProcessHangMonitor();
+
+ public:
+  static ProcessHangMonitor* Get() { return sInstance; }
+  static ProcessHangMonitor* GetOrCreate();
+
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIOBSERVER
+
+  static void AddProcess(dom::ContentParent* aContentParent);
+  static void RemoveProcess(PProcessHangMonitorParent* aParent);
+
+  static void ClearHang();
+
+  enum SlowScriptAction {
+    Continue,
+    Terminate,
+    StartDebugger
+  };
+  SlowScriptAction NotifySlowScript(nsITabChild* aTabChild,
+                                    const char* aFileName,
+                                    unsigned aLineNo);
+
+  void NotifyPluginHang(uint32_t aPluginId);
+
+  bool IsDebuggerStartupComplete();
+
+  void InitiateCPOWTimeout();
+  bool ShouldTimeOutCPOWs();
+
+  MessageLoop* MonitorLoop();
+
+ private:
+  static ProcessHangMonitor* sInstance;
+
+  Atomic<bool> mCPOWTimeout;
+
+  base::Thread* mThread;
+};
+
+} // namespace mozilla
+
+#endif // mozilla_ProcessHangMonitor_h
new file mode 100644
--- /dev/null
+++ b/dom/ipc/ProcessHangMonitorIPC.h
@@ -0,0 +1,34 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_ProcessHangMonitorIPC_h
+#define mozilla_ProcessHangMonitorIPC_h
+
+#include "base/task.h"
+#include "base/thread.h"
+
+#include "mozilla/PProcessHangMonitor.h"
+#include "mozilla/PProcessHangMonitorParent.h"
+#include "mozilla/PProcessHangMonitorChild.h"
+
+namespace mozilla {
+
+namespace dom {
+class ContentParent;
+}
+
+PProcessHangMonitorParent*
+CreateHangMonitorParent(mozilla::dom::ContentParent* aContentParent,
+                        mozilla::ipc::Transport* aTransport,
+                        base::ProcessId aOtherProcess);
+
+PProcessHangMonitorChild*
+CreateHangMonitorChild(mozilla::ipc::Transport* aTransport,
+                       base::ProcessId aOtherProcess);
+
+} // namespace mozilla
+
+#endif // mozilla_ProcessHangMonitorIPC_h
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -490,17 +490,17 @@ already_AddRefed<nsIDOMWindowUtils>
 TabChildBase::GetDOMWindowUtils()
 {
   nsCOMPtr<nsPIDOMWindow> window = do_GetInterface(WebNavigation());
   nsCOMPtr<nsIDOMWindowUtils> utils = do_GetInterface(window);
   return utils.forget();
 }
 
 already_AddRefed<nsIDocument>
-TabChildBase::GetDocument()
+TabChildBase::GetDocument() const
 {
   nsCOMPtr<nsIDOMDocument> domDoc;
   WebNavigation()->GetDocument(getter_AddRefs(domDoc));
   nsCOMPtr<nsIDocument> doc(do_QueryInterface(domDoc));
   return doc.forget();
 }
 
 void
@@ -2109,17 +2109,18 @@ TabChild::RecvHandleDoubleTap(const CSSP
 {
     TABC_LOG("Handling double tap at %s with %p %p\n",
       Stringify(aPoint).c_str(), mGlobal.get(), mTabChildGlobal.get());
 
     if (!mGlobal || !mTabChildGlobal) {
         return true;
     }
 
-    CSSPoint point = APZCCallbackHelper::ApplyCallbackTransform(aPoint, aGuid);
+    CSSPoint point = APZCCallbackHelper::ApplyCallbackTransform(aPoint, aGuid,
+        GetPresShellResolution());
     nsString data;
     data.AppendLiteral("{ \"x\" : ");
     data.AppendFloat(point.x);
     data.AppendLiteral(", \"y\" : ");
     data.AppendFloat(point.y);
     data.AppendLiteral(" }");
 
     DispatchMessageManagerMessage(NS_LITERAL_STRING("Gesture:DoubleTap"), data);
@@ -2137,17 +2138,19 @@ TabChild::RecvHandleSingleTap(const CSSP
   if (!mGlobal || !mTabChildGlobal) {
     return true;
   }
 
   if (mTouchEndCancelled) {
     return true;
   }
 
-  LayoutDevicePoint currentPoint = APZCCallbackHelper::ApplyCallbackTransform(aPoint, aGuid) * mWidget->GetDefaultScale();;
+  LayoutDevicePoint currentPoint =
+      APZCCallbackHelper::ApplyCallbackTransform(aPoint, aGuid, GetPresShellResolution())
+    * mWidget->GetDefaultScale();;
   if (!mActiveElementManager->ActiveElementUsesStyle()) {
     // If the active element isn't visually affected by the :active style, we
     // have no need to wait the extra sActiveDurationMs to make the activation
     // visually obvious to the user.
     FireSingleTapEvent(currentPoint);
     return true;
   }
 
@@ -2189,26 +2192,27 @@ TabChild::RecvHandleLongTap(const CSSPoi
   if (!mGlobal || !mTabChildGlobal) {
     return true;
   }
 
   SendPendingTouchPreventedResponse(false, aGuid);
 
   bool eventHandled =
       DispatchMouseEvent(NS_LITERAL_STRING("contextmenu"),
-                         APZCCallbackHelper::ApplyCallbackTransform(aPoint, aGuid),
+                         APZCCallbackHelper::ApplyCallbackTransform(aPoint, aGuid, GetPresShellResolution()),
                          2, 1, 0, true,
                          nsIDOMMouseEvent::MOZ_SOURCE_TOUCH);
 
   TABC_LOG("Contextmenu event handled: %d\n", eventHandled);
 
   // If no one handle context menu, fire MOZLONGTAP event
   if (!eventHandled) {
     LayoutDevicePoint currentPoint =
-      APZCCallbackHelper::ApplyCallbackTransform(aPoint, aGuid) * mWidget->GetDefaultScale();
+        APZCCallbackHelper::ApplyCallbackTransform(aPoint, aGuid, GetPresShellResolution())
+      * mWidget->GetDefaultScale();
     int time = 0;
     nsEventStatus status =
       DispatchSynthesizedMouseEvent(NS_MOUSE_MOZLONGTAP, time, currentPoint, mWidget);
     eventHandled = (status == nsEventStatus_eConsumeNoDefault);
     TABC_LOG("MOZLONGTAP event handled: %d\n", eventHandled);
   }
 
   SendContentReceivedInputBlock(aGuid, aInputBlockId, eventHandled);
@@ -2657,25 +2661,38 @@ TabChild::SendSetTargetAPZCNotification(
   nsTArray<ScrollableLayerGuid> targets;
   for (size_t i = 0; i < aEvent.touches.Length(); i++) {
     waitForRefresh |= PrepareForSetTargetAPZCNotification(aGuid, aInputBlockId,
         rootFrame, aEvent.touches[i]->mRefPoint, &targets);
   }
   SendSetTargetAPZCNotification(shell, aInputBlockId, targets, waitForRefresh);
 }
 
+float
+TabChild::GetPresShellResolution() const
+{
+  nsCOMPtr<nsIDocument> document(GetDocument());
+  nsIPresShell* shell = document->GetShell();
+  if (!shell) {
+    return 1.0f;
+  }
+  return shell->GetXResolution();
+}
+
 bool
 TabChild::RecvRealTouchEvent(const WidgetTouchEvent& aEvent,
                              const ScrollableLayerGuid& aGuid,
                              const uint64_t& aInputBlockId)
 {
   TABC_LOG("Receiving touch event of type %d\n", aEvent.message);
 
   for (size_t i = 0; i < aEvent.touches.Length(); i++) {
-    aEvent.touches[i]->mRefPoint = APZCCallbackHelper::ApplyCallbackTransform(aEvent.touches[i]->mRefPoint, aGuid, mWidget->GetDefaultScale());
+    aEvent.touches[i]->mRefPoint = APZCCallbackHelper::ApplyCallbackTransform(
+        aEvent.touches[i]->mRefPoint, aGuid, mWidget->GetDefaultScale(),
+        GetPresShellResolution());
   }
 
   if (aEvent.message == NS_TOUCH_START && IsAsyncPanZoomEnabled()) {
     SendSetTargetAPZCNotification(aEvent, aGuid, aInputBlockId);
   }
 
   WidgetTouchEvent localEvent(aEvent);
   localEvent.widget = mWidget;
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -175,17 +175,17 @@ class TabChildBase : public nsISupports,
                      public ipc::MessageManagerCallback
 {
 public:
     TabChildBase();
 
     NS_DECL_CYCLE_COLLECTING_ISUPPORTS
     NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(TabChildBase)
 
-    virtual nsIWebNavigation* WebNavigation() = 0;
+    virtual nsIWebNavigation* WebNavigation() const = 0;
     virtual nsIWidget* WebWidget() = 0;
     nsIPrincipal* GetPrincipal() { return mPrincipal; }
     bool IsAsyncPanZoomEnabled();
     // Recalculates the display state, including the CSS
     // viewport. This should be called whenever we believe the
     // viewport data on a document may have changed. If it didn't
     // change, this function doesn't do anything.  However, it should
     // not be called all the time as it is fairly expensive.
@@ -201,17 +201,17 @@ public:
 
 protected:
     virtual ~TabChildBase();
     CSSSize GetPageSize(nsCOMPtr<nsIDocument> aDocument, const CSSSize& aViewport);
 
     // Get the DOMWindowUtils for the top-level window in this tab.
     already_AddRefed<nsIDOMWindowUtils> GetDOMWindowUtils();
     // Get the Document for the top-level window in this tab.
-    already_AddRefed<nsIDocument> GetDocument();
+    already_AddRefed<nsIDocument> GetDocument() const;
 
     // Wrapper for nsIDOMWindowUtils.setCSSViewport(). This updates some state
     // variables local to this class before setting it.
     void SetCSSViewport(const CSSSize& aSize);
 
     // Wraps up a JSON object as a structured clone and sends it to the browser
     // chrome script.
     //
@@ -413,17 +413,17 @@ public:
     AllocPIndexedDBPermissionRequestChild(const Principal& aPrincipal)
                                           MOZ_OVERRIDE;
 
     virtual bool
     DeallocPIndexedDBPermissionRequestChild(
                                        PIndexedDBPermissionRequestChild* aActor)
                                        MOZ_OVERRIDE;
 
-    virtual nsIWebNavigation* WebNavigation() MOZ_OVERRIDE { return mWebNav; }
+    virtual nsIWebNavigation* WebNavigation() const MOZ_OVERRIDE { return mWebNav; }
     virtual nsIWidget* WebWidget() MOZ_OVERRIDE { return mWidget; }
 
     /** Return the DPI of the widget this TabChild draws to. */
     void GetDPI(float* aDPI);
     void GetDefaultScale(double *aScale);
 
     ScreenOrientation GetOrientation() { return mOrientation; }
 
@@ -606,16 +606,19 @@ private:
                                        const uint64_t& aInputBlockId,
                                        const nsTArray<ScrollableLayerGuid>& aTargets,
                                        bool aWaitForRefresh);
 
     void SendSetTargetAPZCNotification(const WidgetTouchEvent& aEvent,
                                        const mozilla::layers::ScrollableLayerGuid& aGuid,
                                        const uint64_t& aInputBlockId);
 
+    // Get the pres shell resolution of the document in this tab.
+    float GetPresShellResolution() const;
+
     void SetTabId(const TabId& aTabId)
     {
       MOZ_ASSERT(mUniqueId == 0);
 
       mUniqueId = aTabId;
       NestedTabChildMap()[mUniqueId] = this;
     }
 
--- a/dom/ipc/moz.build
+++ b/dom/ipc/moz.build
@@ -1,14 +1,20 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
+XPIDL_SOURCES += [
+    'nsIHangReport.idl',
+]
+
+XPIDL_MODULE = 'dom'
+
 EXPORTS += [
     'nsICachedFileDescriptorListener.h',
 ]
 
 EXPORTS.mozilla.dom.ipc += [
     'BlobChild.h',
     'BlobParent.h',
     'IdType.h',
@@ -34,16 +40,18 @@ EXPORTS.mozilla.dom += [
     'TabContext.h',
     'TabMessageUtils.h',
     'TabParent.h',
 ]
 
 EXPORTS.mozilla += [
     'AppProcessChecker.h',
     'PreallocatedProcessManager.h',
+    'ProcessHangMonitor.h',
+    'ProcessHangMonitorIPC.h',
     'ProcessPriorityManager.h',
 ]
 
 UNIFIED_SOURCES += [
     'AppProcessChecker.cpp',
     'ColorPickerParent.cpp',
     'ContentBridgeChild.cpp',
     'ContentBridgeParent.cpp',
@@ -68,16 +76,17 @@ UNIFIED_SOURCES += [
 # Blob.cpp cannot be compiled in unified mode because it triggers a fatal gcc warning.
 # CrashReporterChild.cpp cannot be compiled in unified mode because of name clashes
 # in OS X headers.
 # ContentChild.cpp cannot be compiled in unified mode on  linux due to Time conflict
 SOURCES += [
     'Blob.cpp',
     'ContentChild.cpp',
     'CrashReporterChild.cpp',
+    'ProcessHangMonitor.cpp',
 ]
 
 IPDL_SOURCES += [
     'DOMTypes.ipdlh',
     'PBlob.ipdl',
     'PBlobStream.ipdl',
     'PBrowser.ipdl',
     'PBrowserOrId.ipdlh',
@@ -87,16 +96,17 @@ IPDL_SOURCES += [
     'PContentPermission.ipdlh',
     'PContentPermissionRequest.ipdl',
     'PCrashReporter.ipdl',
     'PCycleCollectWithLogs.ipdl',
     'PDocumentRenderer.ipdl',
     'PFilePicker.ipdl',
     'PMemoryReportRequest.ipdl',
     'PPluginWidget.ipdl',
+    'PProcessHangMonitor.ipdl',
     'PScreenManager.ipdl',
     'PTabContext.ipdlh',
 ]
 
 FAIL_ON_WARNINGS = True
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
new file mode 100644
--- /dev/null
+++ b/dom/ipc/nsIHangReport.idl
@@ -0,0 +1,66 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* 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 "nsISupports.idl"
+
+interface nsIDOMElement;
+interface nsIFrameLoader;
+
+/**
+ * When a content process hangs, Gecko notifies "process-hang-report" observers
+ * and passes an nsIHangReport for the subject parameter. There is at most one
+ * nsIHangReport associated with a given content process. As long as the content
+ * process stays stuck, the "process-hang-report" observer will continue to be
+ * notified at regular intervals (approximately once per second). The content
+ * process will continue to run uninhibitedly during this time.
+ */
+
+[scriptable, uuid(3b88d100-8d5b-11e4-b4a9-0800200c9a66)]
+interface nsIHangReport : nsISupports
+{
+  const unsigned long SLOW_SCRIPT = 1;
+  const unsigned long PLUGIN_HANG = 2;
+
+  // The type of hang being reported: SLOW_SCRIPT or PLUGIN_HANG.
+  readonly attribute unsigned long hangType;
+
+  // For SLOW_SCRIPT reports, these fields contain information about the
+  // slow script.
+  // Only valid for SLOW_SCRIPT reports.
+  readonly attribute nsIDOMElement scriptBrowser;
+  readonly attribute ACString scriptFileName;
+  readonly attribute unsigned long scriptLineNo;
+
+  // For PLUGIN_HANGs, this field contains information about the plugin.
+  // Only valid for PLUGIN_HANG reports.
+  readonly attribute ACString pluginName;
+
+  // Terminate the slow script if it is still running.
+  // Only valid for SLOW_SCRIPT reports.
+  void terminateScript();
+
+  // Terminate the plugin if it is still hung.
+  // Only valid for PLUGIN_HANG reports.
+  void terminatePlugin();
+
+  // Terminate the hung content process unconditionally.
+  // Valid for any type of hang.
+  void terminateProcess();
+
+  // Ask the content process to start up the slow script debugger.
+  // Only valid for SLOW_SCRIPT reports.
+  void beginStartingDebugger();
+
+  // Inform the content process that the slow script debugger has finished
+  // spinning up. The content process will run a nested event loop until this
+  // method is called.
+  // Only valid for SLOW_SCRIPT reports.
+  void endStartingDebugger();
+
+  // Inquire whether the report is for a content process loaded by the given
+  // frameloader.
+  bool isReportForBrowser(in nsIFrameLoader aFrameLoader);
+};
--- a/dom/media/MediaResource.cpp
+++ b/dom/media/MediaResource.cpp
@@ -913,20 +913,29 @@ ChannelMediaResource::RecreateChannel()
   dom::HTMLMediaElement* element = owner->GetMediaElement();
   if (!element) {
     // The decoder is being shut down, so don't bother opening a new channel
     return NS_OK;
   }
   nsCOMPtr<nsILoadGroup> loadGroup = element->GetDocumentLoadGroup();
   NS_ENSURE_TRUE(loadGroup, NS_ERROR_NULL_POINTER);
 
+  nsSecurityFlags securityFlags = nsILoadInfo::SEC_NORMAL;
+  if (nsContentUtils::ChannelShouldInheritPrincipal(element->NodePrincipal(),
+                                                    mURI,
+                                                    false, // aInheritForAboutBlank
+                                                    false // aForceInherit
+                                                    )) {
+    securityFlags = nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL;
+  }
+
   nsresult rv = NS_NewChannel(getter_AddRefs(mChannel),
                               mURI,
                               element,
-                              nsILoadInfo::SEC_NORMAL,
+                              securityFlags,
                               nsIContentPolicy::TYPE_MEDIA,
                               loadGroup,
                               nullptr,  // aCallbacks
                               loadFlags);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // We have cached the Content-Type, which should not change. Give a hint to
   // the channel to avoid a sniffing failure, which would be expected because we
@@ -1431,22 +1440,31 @@ already_AddRefed<MediaResource> FileMedi
   dom::HTMLMediaElement* element = owner->GetMediaElement();
   if (!element) {
     // The decoder is being shut down, so we can't clone
     return nullptr;
   }
   nsCOMPtr<nsILoadGroup> loadGroup = element->GetDocumentLoadGroup();
   NS_ENSURE_TRUE(loadGroup, nullptr);
 
+  nsSecurityFlags securityFlags = nsILoadInfo::SEC_NORMAL;
+  if (nsContentUtils::ChannelShouldInheritPrincipal(element->NodePrincipal(),
+                                                    mURI,
+                                                    false, // aInheritForAboutBlank
+                                                    false // aForceInherit
+                                                    )) {
+    securityFlags = nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL;
+  }
+
   nsCOMPtr<nsIChannel> channel;
   nsresult rv =
     NS_NewChannel(getter_AddRefs(channel),
                   mURI,
                   element,
-                  nsILoadInfo::SEC_NORMAL,
+                  securityFlags,
                   nsIContentPolicy::TYPE_MEDIA,
                   loadGroup);
 
   if (NS_FAILED(rv))
     return nullptr;
 
   nsRefPtr<MediaResource> resource(new FileMediaResource(aDecoder, channel, mURI, GetContentType()));
   return resource.forget();
--- a/dom/plugins/base/nsPluginHost.h
+++ b/dom/plugins/base/nsPluginHost.h
@@ -196,16 +196,18 @@ public:
   // and don't need to set up a new stream.
   nsresult InstantiatePluginInstance(const char *aMimeType, nsIURI* aURL,
                                      nsObjectLoadingContent *aContent,
                                      nsPluginInstanceOwner** aOwner);
 
   // Does not accept nullptr and should never fail.
   nsPluginTag* TagForPlugin(nsNPAPIPlugin* aPlugin);
 
+  nsPluginTag* PluginWithId(uint32_t aId);
+
   nsresult GetPlugin(const char *aMimeType, nsNPAPIPlugin** aPlugin);
   nsresult GetPluginForContentProcess(uint32_t aPluginId, nsNPAPIPlugin** aPlugin);
   void NotifyContentModuleDestroyed(uint32_t aPluginId);
 
   nsresult NewPluginStreamListener(nsIURI* aURL,
                                    nsNPAPIPluginInstance* aInstance,
                                    nsIStreamListener **aStreamListener);
 
@@ -271,17 +273,16 @@ private:
   // Checks to see if a tag object is in our list of live tags.
   bool IsLiveTag(nsIPluginTag* tag);
   
   // Checks our list of live tags for an equivalent tag.
   nsPluginTag* HaveSamePlugin(const nsPluginTag * aPluginTag);
     
   // Returns the first plugin at |path|
   nsPluginTag* FirstPluginWithPath(const nsCString& path);
-  nsPluginTag* PluginWithId(uint32_t aId);
 
   nsresult EnsurePrivateDirServiceProvider();
 
   void OnPluginInstanceDestroyed(nsPluginTag* aPluginTag);
 
   // To be used by the chrome process whenever the set of plugins changes.
   void IncrementChromeEpoch();
 
--- a/dom/plugins/ipc/PluginBridge.h
+++ b/dom/plugins/ipc/PluginBridge.h
@@ -19,12 +19,15 @@ bool
 SetupBridge(uint32_t aPluginId, dom::ContentParent* aContentParent,
             bool aForceBridgeNow = false);
 
 bool
 FindPluginsForContent(uint32_t aPluginEpoch,
                       nsTArray<PluginTag>* aPlugins,
                       uint32_t* aNewPluginEpoch);
 
+void
+TerminatePlugin(uint32_t aPluginId);
+
 } // namespace plugins
 } // namespace mozilla
 
 #endif // mozilla_plugins_PluginBridge_h
--- a/dom/plugins/ipc/PluginModuleParent.cpp
+++ b/dom/plugins/ipc/PluginModuleParent.cpp
@@ -16,16 +16,17 @@
 #include "mozilla/dom/ContentChild.h"
 #include "mozilla/dom/PCrashReporterParent.h"
 #include "mozilla/ipc/MessageChannel.h"
 #include "mozilla/plugins/BrowserStreamParent.h"
 #include "mozilla/plugins/PluginAsyncSurrogate.h"
 #include "mozilla/plugins/PluginBridge.h"
 #include "mozilla/plugins/PluginInstanceParent.h"
 #include "mozilla/Preferences.h"
+#include "mozilla/ProcessHangMonitor.h"
 #include "mozilla/Services.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/unused.h"
 #include "nsAutoPtr.h"
 #include "nsCRT.h"
 #include "nsIFile.h"
 #include "nsIObserverService.h"
 #include "nsNPAPIPlugin.h"
@@ -64,16 +65,17 @@ using namespace mozilla::plugins;
 using namespace mozilla::plugins::parent;
 
 #ifdef MOZ_CRASHREPORTER
 #include "mozilla/dom/CrashReporterParent.h"
 
 using namespace CrashReporter;
 #endif
 
+static const char kContentTimeoutPref[] = "dom.ipc.plugins.contentTimeoutSecs";
 static const char kChildTimeoutPref[] = "dom.ipc.plugins.timeoutSecs";
 static const char kParentTimeoutPref[] = "dom.ipc.plugins.parentTimeoutSecs";
 static const char kLaunchTimeoutPref[] = "dom.ipc.plugins.processLaunchTimeoutSecs";
 static const char kAsyncInitPref[] = "dom.ipc.plugins.asyncInit";
 #ifdef XP_WIN
 static const char kHangUITimeoutPref[] = "dom.ipc.plugins.hangUITimeoutSecs";
 static const char kHangUIMinDisplayPref[] = "dom.ipc.plugins.hangUIMinDisplaySecs";
 #define CHILD_TIMEOUT_PREF kHangUITimeoutPref
@@ -254,16 +256,32 @@ private:
     static bool sIsLoadModuleOnStack;
 };
 
 PRCList PluginModuleMapping::sModuleListHead =
     PR_INIT_STATIC_CLIST(&PluginModuleMapping::sModuleListHead);
 
 bool PluginModuleMapping::sIsLoadModuleOnStack = false;
 
+void
+mozilla::plugins::TerminatePlugin(uint32_t aPluginId)
+{
+    MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
+
+    nsRefPtr<nsPluginHost> host = nsPluginHost::GetInst();
+    nsPluginTag* pluginTag = host->PluginWithId(aPluginId);
+    if (!pluginTag || !pluginTag->mPlugin) {
+        return;
+    }
+
+    nsRefPtr<nsNPAPIPlugin> plugin = pluginTag->mPlugin;
+    PluginModuleChromeParent* chromeParent = static_cast<PluginModuleChromeParent*>(plugin->GetLibrary());
+    chromeParent->TerminateChildProcess(MessageLoop::current());
+}
+
 /* static */ PluginLibrary*
 PluginModuleContentParent::LoadModule(uint32_t aPluginId)
 {
     PluginModuleMapping::NotifyLoadingModule loadingModule;
     nsAutoPtr<PluginModuleMapping> mapping(new PluginModuleMapping(aPluginId));
 
     MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Content);
 
@@ -284,16 +302,18 @@ PluginModuleContentParent::LoadModule(ui
 
     if (!mapping->IsChannelOpened()) {
         // mapping is linked into PluginModuleMapping::sModuleListHead and is
         // needed later, so since this function is returning successfully we
         // forget it here.
         mapping.forget();
     }
 
+    parent->mPluginId = aPluginId;
+
     return parent;
 }
 
 /* static */ void
 PluginModuleContentParent::AssociatePluginId(uint32_t aPluginId,
                                              base::ProcessId aProcessId)
 {
     DebugOnly<PluginModuleMapping*> mapping =
@@ -323,16 +343,18 @@ PluginModuleContentParent::Initialize(mo
 
     moduleMapping->SetChannelOpened();
 
     // Request Windows message deferral behavior on our channel. This
     // applies to the top level and all sub plugin protocols since they
     // all share the same channel.
     parent->GetIPCChannel()->SetChannelFlags(MessageChannel::REQUIRE_DEFERRED_MESSAGE_PROTECTION);
 
+    TimeoutChanged(kContentTimeoutPref, parent);
+
     // moduleMapping is linked into PluginModuleMapping::sModuleListHead and is
     // needed later, so since this function is returning successfully we
     // forget it here.
     moduleMapping.forget();
     return parent;
 }
 
 /* static */ void
@@ -512,16 +534,22 @@ PluginModuleParent::~PluginModuleParent(
         NPError err;
         NP_Shutdown(&err);
     }
 }
 
 PluginModuleContentParent::PluginModuleContentParent()
     : PluginModuleParent(false)
 {
+    Preferences::RegisterCallback(TimeoutChanged, kContentTimeoutPref, this);
+}
+
+PluginModuleContentParent::~PluginModuleContentParent()
+{
+    Preferences::UnregisterCallback(TimeoutChanged, kContentTimeoutPref, this);
 }
 
 PluginModuleChromeParent::PluginModuleChromeParent(const char* aFilePath, uint32_t aPluginId)
     : PluginModuleParent(true)
     , mSubprocess(new PluginProcessParent(aFilePath))
     , mPluginId(aPluginId)
     , mChromeTaskFactory(this)
     , mHangAnnotationFlags(0)
@@ -645,42 +673,51 @@ PluginModuleChromeParent::WriteExtraData
 #endif
         }
 #endif
     }
 }
 #endif  // MOZ_CRASHREPORTER
 
 void
-PluginModuleChromeParent::SetChildTimeout(const int32_t aChildTimeout)
+PluginModuleParent::SetChildTimeout(const int32_t aChildTimeout)
 {
     int32_t timeoutMs = (aChildTimeout > 0) ? (1000 * aChildTimeout) :
                       MessageChannel::kNoTimeout;
     SetReplyTimeoutMs(timeoutMs);
 }
 
 void
-PluginModuleChromeParent::TimeoutChanged(const char* aPref, void* aModule)
+PluginModuleParent::TimeoutChanged(const char* aPref, void* aModule)
 {
+    PluginModuleParent* module = static_cast<PluginModuleParent*>(aModule);
+
     NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 #ifndef XP_WIN
     if (!strcmp(aPref, kChildTimeoutPref)) {
+      MOZ_ASSERT(module->IsChrome());
       // The timeout value used by the parent for children
       int32_t timeoutSecs = Preferences::GetInt(kChildTimeoutPref, 0);
-      static_cast<PluginModuleChromeParent*>(aModule)->SetChildTimeout(timeoutSecs);
+      module->SetChildTimeout(timeoutSecs);
 #else
     if (!strcmp(aPref, kChildTimeoutPref) ||
         !strcmp(aPref, kHangUIMinDisplayPref) ||
         !strcmp(aPref, kHangUITimeoutPref)) {
-      static_cast<PluginModuleChromeParent*>(aModule)->EvaluateHangUIState(true);
+      MOZ_ASSERT(module->IsChrome());
+      static_cast<PluginModuleChromeParent*>(module)->EvaluateHangUIState(true);
 #endif // XP_WIN
     } else if (!strcmp(aPref, kParentTimeoutPref)) {
       // The timeout value used by the child for its parent
+      MOZ_ASSERT(module->IsChrome());
       int32_t timeoutSecs = Preferences::GetInt(kParentTimeoutPref, 0);
-      unused << static_cast<PluginModuleChromeParent*>(aModule)->SendSetParentHangTimeout(timeoutSecs);
+      unused << static_cast<PluginModuleChromeParent*>(module)->SendSetParentHangTimeout(timeoutSecs);
+    } else if (!strcmp(aPref, kContentTimeoutPref)) {
+      MOZ_ASSERT(!module->IsChrome());
+      int32_t timeoutSecs = Preferences::GetInt(kContentTimeoutPref, 0);
+      module->SetChildTimeout(timeoutSecs);
     }
 }
 
 void
 PluginModuleChromeParent::CleanupFromTimeout(const bool aFromHangUI)
 {
     if (mShutdown) {
       return;
@@ -854,16 +891,33 @@ PluginModuleChromeParent::ShouldContinue
     // original plugin hang behaviour and kill the plugin container.
     FinishHangUI();
 #endif // XP_WIN
     TerminateChildProcess(MessageLoop::current());
     GetIPCChannel()->CloseWithTimeout();
     return false;
 }
 
+bool
+PluginModuleContentParent::ShouldContinueFromReplyTimeout()
+{
+    nsRefPtr<ProcessHangMonitor> monitor = ProcessHangMonitor::Get();
+    if (!monitor) {
+        return true;
+    }
+    monitor->NotifyPluginHang(mPluginId);
+    return true;
+}
+
+void
+PluginModuleContentParent::OnExitedSyncSend()
+{
+    ProcessHangMonitor::ClearHang();
+}
+
 void
 PluginModuleChromeParent::TerminateChildProcess(MessageLoop* aMsgLoop)
 {
 #ifdef MOZ_CRASHREPORTER
 #ifdef XP_WIN
     mozilla::MutexAutoLock lock(mCrashReporterMutex);
     CrashReporterParent* crashReporter = mCrashReporter;
     if (!crashReporter) {
--- a/dom/plugins/ipc/PluginModuleParent.h
+++ b/dom/plugins/ipc/PluginModuleParent.h
@@ -171,16 +171,19 @@ protected:
 
     virtual bool
     RecvNP_InitializeResult(const NPError& aError) MOZ_OVERRIDE;
 
     static BrowserStreamParent* StreamCast(NPP instance, NPStream* s,
                                            PluginAsyncSurrogate** aSurrogate = nullptr);
 
 protected:
+    void SetChildTimeout(const int32_t aChildTimeout);
+    static void TimeoutChanged(const char* aPref, void* aModule);
+
     virtual void UpdatePluginTimeout() {}
 
     virtual bool RecvNotifyContentModuleDestroyed() MOZ_OVERRIDE { return true; }
 
     void SetPluginFuncs(NPPluginFuncs* aFuncs);
 
     nsresult NPP_NewInternal(NPMIMEType pluginType, NPP instance, uint16_t mode,
                              InfallibleTArray<nsCString>& names,
@@ -304,23 +307,29 @@ class PluginModuleContentParent : public
     static PluginLibrary* LoadModule(uint32_t aPluginId);
 
     static PluginModuleContentParent* Initialize(mozilla::ipc::Transport* aTransport,
                                                  base::ProcessId aOtherProcess);
 
     static void OnLoadPluginResult(const uint32_t& aPluginId, const bool& aResult);
     static void AssociatePluginId(uint32_t aPluginId, base::ProcessId aProcessId);
 
+    virtual ~PluginModuleContentParent();
+
   private:
+    virtual bool ShouldContinueFromReplyTimeout() MOZ_OVERRIDE;
+    virtual void OnExitedSyncSend() MOZ_OVERRIDE;
 
 #ifdef MOZ_CRASHREPORTER_INJECTOR
     void OnCrash(DWORD processID) MOZ_OVERRIDE {}
 #endif
 
     static PluginModuleContentParent* sSavedModuleParent;
+
+    uint32_t mPluginId;
 };
 
 class PluginModuleChromeParent
     : public PluginModuleParent
     , public mozilla::HangMonitor::Annotator
 {
   public:
     /**
@@ -338,16 +347,19 @@ class PluginModuleChromeParent
 
 #ifdef XP_WIN
     /**
      * Called by Plugin Hang UI to notify that the user has clicked continue.
      * Used for chrome hang annotations.
      */
     void
     OnHangUIContinue();
+
+    void
+    EvaluateHangUIState(const bool aReset);
 #endif // XP_WIN
 
     virtual bool WaitForIPCConnection() MOZ_OVERRIDE;
 
     virtual bool
     RecvNP_InitializeResult(const NPError& aError) MOZ_OVERRIDE;
 
     void
@@ -397,18 +409,16 @@ private:
     virtual void ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE;
 
     // aFilePath is UTF8, not native!
     explicit PluginModuleChromeParent(const char* aFilePath, uint32_t aPluginId);
 
     CrashReporterParent* CrashReporter();
 
     void CleanupFromTimeout(const bool aByHangUI);
-    void SetChildTimeout(const int32_t aChildTimeout);
-    static void TimeoutChanged(const char* aPref, void* aModule);
 
     virtual void UpdatePluginTimeout() MOZ_OVERRIDE;
 
 #ifdef MOZ_ENABLE_PROFILER_SPS
     void InitPluginProfiling();
     void ShutdownPluginProfiling();
 #endif
 
@@ -444,19 +454,16 @@ private:
      * the mCrashReporter variable in addition to the CrashReporterParent object
      * that mCrashReporter refers to.
      */
     mozilla::Mutex mCrashReporterMutex;
     CrashReporterParent* mCrashReporter;
 #endif // MOZ_CRASHREPORTER
 
 
-    void
-    EvaluateHangUIState(const bool aReset);
-
     /**
      * Launches the Plugin Hang UI.
      *
      * @return true if plugin-hang-ui.exe has been successfully launched.
      *         false if the Plugin Hang UI is disabled, already showing,
      *               or the launch failed.
      */
     bool
--- a/dom/webidl/CSS2PropertiesProps.h
+++ b/dom/webidl/CSS2PropertiesProps.h
@@ -12,19 +12,21 @@
   [ #name, #method, #id, PROP_STRINGIFY(flags), pref ],
 #define CSS_PROP(name, id, method, flags, pref, parsevariant, kwtable, \
 		 stylestruct, stylestructofset, animtype) \
   DO_PROP(name, method, id, flags, pref)
 #define CSS_PROP_SHORTHAND(name, id, method, flags, pref) \
   DO_PROP(name, method, id, flags, pref)
 #define CSS_PROP_PUBLIC_OR_PRIVATE(publicname_, privatename_) publicname_
 #define CSS_PROP_LIST_EXCLUDE_INTERNAL
+#define CSS_PROP_LIST_INCLUDE_LOGICAL
 
 #include "nsCSSPropList.h"
 
+#undef CSS_PROP_LIST_INCLUDE_LOGICAL
 #undef CSS_PROP_LIST_EXCLUDE_INTERNAL
 #undef CSS_PROP_PUBLIC_OR_PRIVATE
 #undef CSS_PROP_SHORTHAND
 #undef CSS_PROP
 
 #define CSS_PROP_ALIAS(name, id, method, pref) \
   DO_PROP(name, method, id, 0, pref)
 
--- a/dom/webidl/MozNFCTag.webidl
+++ b/dom/webidl/MozNFCTag.webidl
@@ -42,17 +42,17 @@ interface MozNFCTag {
   /**
    * The supported technologies of this tag, null if unknown.
    */
   [Cached, Pure] readonly attribute sequence<NFCTechType>? techList;
 
   /**
    * The identifier of this tag.
    */
-  [Pure, Constant] readonly attribute Uint8Array? id;
+  [Constant] readonly attribute Uint8Array? id;
 
   /**
    * The type of this tag, null if unknown.
    */
   readonly attribute NFCTagType? type;
 
   /**
    * The maximum size of the NDEF supported on this tag, null if unknown.
--- a/dom/webidl/Performance.webidl
+++ b/dom/webidl/Performance.webidl
@@ -10,16 +10,17 @@
  * liability, trademark and document use rules apply.
  */
 
 typedef double DOMHighResTimeStamp;
 typedef sequence <PerformanceEntry> PerformanceEntryList;
 
 [Exposed=(Window,Worker)]
 interface Performance {
+  [DependsOn=DeviceState, Affects=Nothing]
   DOMHighResTimeStamp now();
 };
 
 [Exposed=Window]
 partial interface Performance {
   [Constant]
   readonly attribute PerformanceTiming timing;
   [Constant]
--- a/gfx/layers/apz/src/APZCTreeManager.cpp
+++ b/gfx/layers/apz/src/APZCTreeManager.cpp
@@ -951,23 +951,23 @@ APZCTreeManager::SetTargetAPZC(uint64_t 
   nsRefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(aTarget);
   mInputQueue->SetConfirmedTargetApzc(aInputBlockId, apzc);
 }
 
 void
 APZCTreeManager::UpdateZoomConstraints(const ScrollableLayerGuid& aGuid,
                                        const ZoomConstraints& aConstraints)
 {
+  MonitorAutoLock lock(mTreeLock);
   nsRefPtr<HitTestingTreeNode> node = GetTargetNode(aGuid, nullptr);
   MOZ_ASSERT(!node || node->GetApzc()); // any node returned must have an APZC
 
   // For a given layers id, non-root APZCs inherit the zoom constraints
   // of their root.
   if (node && node->GetApzc()->IsRootForLayersId()) {
-    MonitorAutoLock lock(mTreeLock);
     UpdateZoomConstraintsRecursively(node.get(), aConstraints);
   }
 }
 
 void
 APZCTreeManager::UpdateZoomConstraintsRecursively(HitTestingTreeNode* aNode,
                                                   const ZoomConstraints& aConstraints)
 {
@@ -1163,30 +1163,30 @@ APZCTreeManager::DispatchFling(AsyncPanZ
 bool
 APZCTreeManager::HitTestAPZC(const ScreenIntPoint& aPoint)
 {
   nsRefPtr<AsyncPanZoomController> target = GetTargetAPZC(aPoint, nullptr);
   return target != nullptr;
 }
 
 already_AddRefed<AsyncPanZoomController>
-APZCTreeManager::GetTargetAPZC(const ScrollableLayerGuid& aGuid,
-                               GuidComparator aComparator)
+APZCTreeManager::GetTargetAPZC(const ScrollableLayerGuid& aGuid)
 {
-  nsRefPtr<HitTestingTreeNode> node = GetTargetNode(aGuid, aComparator);
+  MonitorAutoLock lock(mTreeLock);
+  nsRefPtr<HitTestingTreeNode> node = GetTargetNode(aGuid, nullptr);
   MOZ_ASSERT(!node || node->GetApzc()); // any node returned must have an APZC
   nsRefPtr<AsyncPanZoomController> apzc = node ? node->GetApzc() : nullptr;
   return apzc.forget();
 }
 
 already_AddRefed<HitTestingTreeNode>
 APZCTreeManager::GetTargetNode(const ScrollableLayerGuid& aGuid,
                                GuidComparator aComparator)
 {
-  MonitorAutoLock lock(mTreeLock);
+  mTreeLock.AssertCurrentThreadOwns();
   nsRefPtr<HitTestingTreeNode> target = FindTargetNode(mRootNode, aGuid, aComparator);
   return target.forget();
 }
 
 already_AddRefed<AsyncPanZoomController>
 APZCTreeManager::GetTargetAPZC(const ScreenPoint& aPoint, HitTestResult* aOutHitResult)
 {
   MonitorAutoLock lock(mTreeLock);
@@ -1257,18 +1257,19 @@ APZCTreeManager::BuildOverscrollHandoffC
       // just abort here.
       if (parent->GetGuid().mScrollId == apzc->GetScrollHandoffParentId()) {
         scrollParent = parent;
         break;
       }
     }
     if (!scrollParent) {
       ScrollableLayerGuid guid(parent->GetGuid().mLayersId, 0, apzc->GetScrollHandoffParentId());
-      nsRefPtr<AsyncPanZoomController> scrollParentPtr = GetTargetAPZC(guid, &GuidComparatorIgnoringPresShell);
-      scrollParent = scrollParentPtr.get();
+      nsRefPtr<HitTestingTreeNode> node = GetTargetNode(guid, &GuidComparatorIgnoringPresShell);
+      MOZ_ASSERT(!node || node->GetApzc()); // any node returned must have an APZC
+      scrollParent = node ? node->GetApzc() : nullptr;
     }
     apzc = scrollParent;
   }
 
   // Now adjust the chain to account for scroll grabbing. Sorting is a bit
   // of an overkill here, but scroll grabbing will likely be generalized
   // to scroll priorities, so we might as well do it this way.
   result->SortByScrollPriority();
--- a/gfx/layers/apz/src/APZCTreeManager.h
+++ b/gfx/layers/apz/src/APZCTreeManager.h
@@ -408,18 +408,17 @@ public:
   gfx::Matrix4x4 GetApzcToGeckoTransform(const AsyncPanZoomController *aApzc) const;
 private:
   typedef bool (*GuidComparator)(const ScrollableLayerGuid&, const ScrollableLayerGuid&);
 
   /* Helpers */
   void AttachNodeToTree(HitTestingTreeNode* aNode,
                         HitTestingTreeNode* aParent,
                         HitTestingTreeNode* aNextSibling);
-  already_AddRefed<AsyncPanZoomController> GetTargetAPZC(const ScrollableLayerGuid& aGuid,
-                                                         GuidComparator aComparator = nullptr);
+  already_AddRefed<AsyncPanZoomController> GetTargetAPZC(const ScrollableLayerGuid& aGuid);
   already_AddRefed<HitTestingTreeNode> GetTargetNode(const ScrollableLayerGuid& aGuid,
                                                      GuidComparator aComparator);
   HitTestingTreeNode* FindTargetNode(HitTestingTreeNode* aNode,
                                      const ScrollableLayerGuid& aGuid,
                                      GuidComparator aComparator);
   AsyncPanZoomController* GetAPZCAtPoint(HitTestingTreeNode* aNode,
                                          const ParentLayerPoint& aHitTestPoint,
                                          HitTestResult* aOutHitResult);
--- a/gfx/layers/apz/util/APZCCallbackHelper.cpp
+++ b/gfx/layers/apz/util/APZCCallbackHelper.cpp
@@ -307,18 +307,28 @@ APZCCallbackHelper::UpdateCallbackTransf
         return;
     }
     CSSPoint scrollDelta = aApzcMetrics.GetScrollOffset() - aActualMetrics.GetScrollOffset();
     content->SetProperty(nsGkAtoms::apzCallbackTransform, new CSSPoint(scrollDelta),
                          nsINode::DeleteProperty<CSSPoint>);
 }
 
 CSSPoint
-APZCCallbackHelper::ApplyCallbackTransform(const CSSPoint& aInput, const ScrollableLayerGuid& aGuid)
+APZCCallbackHelper::ApplyCallbackTransform(const CSSPoint& aInput,
+                                           const ScrollableLayerGuid& aGuid,
+                                           float aPresShellResolution)
 {
+    // First, scale inversely by the pres shell resolution to cancel the
+    // scale-to-resolution transform that the compositor adds to the layer with
+    // the pres shell resolution. The points sent to Gecko by APZ don't have
+    // this transform unapplied (unlike other compositor-side transforms)
+    // because APZ doesn't know about it.
+    CSSPoint input = aInput / aPresShellResolution;
+
+    // Now apply the callback-transform.
     // XXX: technically we need to walk all the way up the layer tree from the layer
     // represented by |aGuid.mScrollId| up to the root of the layer tree and apply
     // the input transforms at each level in turn. However, it is quite difficult
     // to do this given that the structure of the layer tree may be different from
     // the structure of the content tree. Also it may be impossible to do correctly
     // at this point because there are other CSS transforms and such interleaved in
     // between so applying the inputTransforms all in a row at the end may leave
     // some things transformed improperly. In practice we should rarely hit scenarios
@@ -326,28 +336,29 @@ APZCCallbackHelper::ApplyCallbackTransfo
     // transform for the layer that the input hit.
 
     if (aGuid.mScrollId != FrameMetrics::NULL_SCROLL_ID) {
         nsCOMPtr<nsIContent> content = nsLayoutUtils::FindContentFor(aGuid.mScrollId);
         if (content) {
             void* property = content->GetProperty(nsGkAtoms::apzCallbackTransform);
             if (property) {
                 CSSPoint delta = (*static_cast<CSSPoint*>(property));
-                return aInput + delta;
+                return input + delta;
             }
         }
     }
-    return aInput;
+    return input;
 }
 
 nsIntPoint
 APZCCallbackHelper::ApplyCallbackTransform(const nsIntPoint& aPoint,
-                                        const ScrollableLayerGuid& aGuid,
-                                        const CSSToLayoutDeviceScale& aScale)
+                                           const ScrollableLayerGuid& aGuid,
+                                           const CSSToLayoutDeviceScale& aScale,
+                                           float aPresShellResolution)
 {
     LayoutDevicePoint point = LayoutDevicePoint(aPoint.x, aPoint.y);
-    point = ApplyCallbackTransform(point / aScale, aGuid) * aScale;
+    point = ApplyCallbackTransform(point / aScale, aGuid, aPresShellResolution) * aScale;
     LayoutDeviceIntPoint ret = gfx::RoundedToInt(point);
     return nsIntPoint(ret.x, ret.y);
 }
 
 }
 }
--- a/gfx/layers/apz/util/APZCCallbackHelper.h
+++ b/gfx/layers/apz/util/APZCCallbackHelper.h
@@ -84,24 +84,29 @@ public:
        |aActualMetrics| argument are the metrics representing the gecko state after we
        applied some or all of the APZ metrics. */
     static void UpdateCallbackTransform(const FrameMetrics& aApzcMetrics,
                                         const FrameMetrics& aActualMetrics);
 
     /* Apply an "input transform" to the given |aInput| and return the transformed value.
        The input transform applied is the one for the content element corresponding to
        |aGuid|; this is populated in a previous call to UpdateCallbackTransform. See that
-       method's documentations for details. */
+       method's documentations for details.
+       This method additionally adjusts |aInput| by inversely scaling by the provided
+       pres shell resolution, to cancel out a compositor-side transform (added in
+       bug 1076241) that APZ doesn't unapply. */
     static CSSPoint ApplyCallbackTransform(const CSSPoint& aInput,
-                                           const ScrollableLayerGuid& aGuid);
+                                           const ScrollableLayerGuid& aGuid,
+                                           float aPresShellResolution);
 
     /* Same as above, but operates on nsIntPoint that are assumed to be in LayoutDevice
        pixel space. Requires an additonal |aScale| parameter to convert between CSS and
        LayoutDevice space. */
     static nsIntPoint ApplyCallbackTransform(const nsIntPoint& aPoint,
                                              const ScrollableLayerGuid& aGuid,
-                                             const CSSToLayoutDeviceScale& aScale);
+                                             const CSSToLayoutDeviceScale& aScale,
+                                             float aPresShellResolution);
 };
 
 }
 }
 
 #endif /* mozilla_layers_APZCCallbackHelper_h */
--- a/gfx/layers/ipc/CompositorParent.cpp
+++ b/gfx/layers/ipc/CompositorParent.cpp
@@ -1244,33 +1244,34 @@ CompositorParent* CompositorParent::Remo
   CompositorParent *retval = it->second;
   sCompositorMap->erase(it);
   return retval;
 }
 
 bool
 CompositorParent::RecvNotifyChildCreated(const uint64_t& child)
 {
+  MonitorAutoLock lock(*sIndirectLayerTreesLock);
   NotifyChildCreated(child);
   return true;
 }
 
 void
 CompositorParent::NotifyChildCreated(const uint64_t& aChild)
 {
-  MonitorAutoLock lock(*sIndirectLayerTreesLock);
+  sIndirectLayerTreesLock->AssertCurrentThreadOwns();
   sIndirectLayerTrees[aChild].mParent = this;
   sIndirectLayerTrees[aChild].mLayerManager = mLayerManager;
 }
 
 bool
 CompositorParent::RecvAdoptChild(const uint64_t& child)
 {
+  MonitorAutoLock lock(*sIndirectLayerTreesLock);
   NotifyChildCreated(child);
-  MonitorAutoLock lock(*sIndirectLayerTreesLock);
   if (sIndirectLayerTrees[child].mLayerTree) {
     sIndirectLayerTrees[child].mLayerTree->mLayerManager = mLayerManager;
   }
   if (sIndirectLayerTrees[child].mRoot) {
     sIndirectLayerTrees[child].mRoot->AsLayerComposite()->SetLayerManager(mLayerManager);
   }
   return true;
 }
--- a/image/src/ImageFactory.cpp
+++ b/image/src/ImageFactory.cpp
@@ -72,38 +72,16 @@ ComputeImageFlags(ImageURL* uri, bool is
   }
   if (isMultiPart) {
     imageFlags |= Image::INIT_FLAG_TRANSIENT;
   }
 
   return imageFlags;
 }
 
-/* static */ bool
-ImageFactory::CanRetargetOnDataAvailable(ImageURL* aURI, bool aIsMultiPart)
-{
-  // We can't retarget OnDataAvailable safely in cases where we aren't storing
-  // source data (and thus need to sync decode in ODA) because allocating frames
-  // off-main-thread is currently not possible and we don't have a workaround in
-  // place yet. (See bug 967985.) For now, we detect those cases and refuse to
-  // retarget. When the problem is fixed, this function can be removed.
-
-  if (aIsMultiPart) {
-    return false;
-  }
-
-  uint32_t imageFlags = ComputeImageFlags(aURI, aIsMultiPart);
-  if (!(imageFlags & Image::INIT_FLAG_DISCARDABLE) &&
-      !(imageFlags & Image::INIT_FLAG_DECODE_ON_DRAW)) {
-    return false;
-  }
-
-  return true;
-}
-
 /* static */ already_AddRefed<Image>
 ImageFactory::CreateImage(nsIRequest* aRequest,
                           ProgressTracker* aProgressTracker,
                           const nsCString& aMimeType,
                           ImageURL* aURI,
                           bool aIsMultiPart,
                           uint32_t aInnerWindowId)
 {
--- a/image/src/ImageFactory.h
+++ b/image/src/ImageFactory.h
@@ -24,24 +24,16 @@ class ImageFactory
 {
 public:
   /**
    * Registers vars with Preferences. Should only be called on the main thread.
    */
   static void Initialize();
 
   /**
-   * Determines whether it's safe to retarget OnDataAvailable for an image.
-   *
-   * @param aURI          The URI of the image.
-   * @param aIsMultipart  Whether the image is part of a multipart request.
-   */
-  static bool CanRetargetOnDataAvailable(ImageURL* aURI, bool aIsMultiPart);
-
-  /**
    * Creates a new image with the given properties.
    * Can be called on or off the main thread.
    *
    * @param aRequest         The associated request.
    * @param aProgressTracker A status tracker for the image to use.
    * @param aMimeType        The mimetype of the image.
    * @param aURI             The URI of the image.
    * @param aIsMultiPart     Whether the image is part of a multipart request.
--- a/image/src/RasterImage.cpp
+++ b/image/src/RasterImage.cpp
@@ -1173,22 +1173,16 @@ RasterImage::OnImageDataAvailable(nsIReq
 
   NS_ABORT_IF_FALSE(bytesRead == aCount || HasError() || NS_FAILED(rv),
     "WriteToSourceBuffer should consume everything if ReadSegments succeeds or "
     "the image must be in error!");
 
   return rv;
 }
 
-/* static */ already_AddRefed<nsIEventTarget>
-RasterImage::GetEventTarget()
-{
-  return DecodePool::Singleton()->GetEventTarget();
-}
-
 nsresult
 RasterImage::SetSourceSizeHint(uint32_t aSizeHint)
 {
   return mSourceBuffer->ExpectLength(aSizeHint);
 }
 
 /********* Methods to implement lazy allocation of nsIProperties object *************/
 NS_IMETHODIMP
--- a/image/src/RasterImage.h
+++ b/image/src/RasterImage.h
@@ -237,18 +237,16 @@ public:
                                         nsIInputStream* aInStr,
                                         uint64_t aSourceOffset,
                                         uint32_t aCount) MOZ_OVERRIDE;
   virtual nsresult OnImageDataComplete(nsIRequest* aRequest,
                                        nsISupports* aContext,
                                        nsresult aStatus,
                                        bool aLastPart) MOZ_OVERRIDE;
 
-  static already_AddRefed<nsIEventTarget> GetEventTarget();
-
   /**
    * A hint of the number of bytes of source data that the image contains. If
    * called early on, this can help reduce copying and reallocations by
    * appropriately preallocating the source data buffer.
    *
    * We take this approach rather than having the source data management code do
    * something more complicated (like chunklisting) because HTTP is by far the
    * dominant source of images, and the Content-Length header is quite reliable.
--- a/image/src/imgRequest.cpp
+++ b/image/src/imgRequest.cpp
@@ -4,16 +4,17 @@
  * 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 "imgRequest.h"
 #include "ImageLogging.h"
 
 #include "imgLoader.h"
 #include "imgRequestProxy.h"
+#include "DecodePool.h"
 #include "ProgressTracker.h"
 #include "ImageFactory.h"
 #include "Image.h"
 #include "MultipartImage.h"
 #include "RasterImage.h"
 
 #include "nsIChannel.h"
 #include "nsICachingChannel.h"
@@ -689,24 +690,24 @@ NS_IMETHODIMP imgRequest::OnStartRequest
   if (progressTracker->ObserverCount() == 0) {
     this->Cancel(NS_IMAGELIB_ERROR_FAILURE);
   }
 
   // Try to retarget OnDataAvailable to a decode thread.
   nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aRequest);
   nsCOMPtr<nsIThreadRetargetableRequest> retargetable =
     do_QueryInterface(aRequest);
-  if (httpChannel && retargetable &&
-      ImageFactory::CanRetargetOnDataAvailable(mURI, mIsMultiPartChannel)) {
+  if (httpChannel && retargetable) {
     nsAutoCString mimeType;
     nsresult rv = httpChannel->GetContentType(mimeType);
     if (NS_SUCCEEDED(rv) && !mimeType.EqualsLiteral(IMAGE_SVG_XML)) {
       // Image object not created until OnDataAvailable, so forward to static
       // DecodePool directly.
-      nsCOMPtr<nsIEventTarget> target = RasterImage::GetEventTarget();
+      nsCOMPtr<nsIEventTarget> target =
+        DecodePool::Singleton()->GetEventTarget();
       rv = retargetable->RetargetDeliveryTo(target);
     }
     PR_LOG(GetImgLog(), PR_LOG_WARNING,
            ("[this=%p] imgRequest::OnStartRequest -- "
             "RetargetDeliveryTo rv %d=%s\n",
             this, rv, NS_SUCCEEDED(rv) ? "succeeded" : "failed"));
   }
 
--- a/ipc/glue/MessageChannel.cpp
+++ b/ipc/glue/MessageChannel.cpp
@@ -172,16 +172,21 @@ public:
         return INTR_SEMS == mMesageSemantics && IN_MESSAGE == mDirection;
     }
 
     bool IsInterruptOutcall() const
     {
         return INTR_SEMS == mMesageSemantics && OUT_MESSAGE == mDirection;
     }
 
+    bool IsOutgoingSync() const {
+        return (mMesageSemantics == INTR_SEMS || mMesageSemantics == SYNC_SEMS) &&
+               mDirection == OUT_MESSAGE;
+    }
+
     void Describe(int32_t* id, const char** dir, const char** sems,
                   const char** name) const
     {
         *id = mMessageRoutingId;
         *dir = (IN_MESSAGE == mDirection) ? "in" : "out";
         *sems = (INTR_SEMS == mMesageSemantics) ? "intr" :
                 (SYNC_SEMS == mMesageSemantics) ? "sync" :
                 "async";
@@ -213,37 +218,45 @@ public:
 
         mThat.mCxxStackFrames.append(InterruptFrame(direction, msg));
 
         const InterruptFrame& frame = mThat.mCxxStackFrames.back();
 
         if (frame.IsInterruptIncall())
             mThat.EnteredCall();
 
+        if (frame.IsOutgoingSync())
+            mThat.EnteredSyncSend();
+
         mThat.mSawInterruptOutMsg |= frame.IsInterruptOutcall();
     }
 
     ~CxxStackFrame() {
         mThat.AssertWorkerThread();
 
         MOZ_ASSERT(!mThat.mCxxStackFrames.empty());
 
-        bool exitingCall = mThat.mCxxStackFrames.back().IsInterruptIncall();
+        const InterruptFrame& frame = mThat.mCxxStackFrames.back();
+        bool exitingSync = frame.IsOutgoingSync();
+        bool exitingCall = frame.IsInterruptIncall();
         mThat.mCxxStackFrames.shrinkBy(1);
 
         bool exitingStack = mThat.mCxxStackFrames.empty();
 
         // mListener could have gone away if Close() was called while
         // MessageChannel code was still on the stack
         if (!mThat.mListener)
             return;
 
         if (exitingCall)
             mThat.ExitedCall();
 
+        if (exitingSync)
+            mThat.ExitedSyncSend();
+
         if (exitingStack)
             mThat.ExitedCxxStack();
     }
 private:
     MessageChannel& mThat;
 
     // Disable harmful methods.
     CxxStackFrame() = delete;
--- a/ipc/glue/MessageChannel.h
+++ b/ipc/glue/MessageChannel.h
@@ -286,16 +286,24 @@ class MessageChannel : HasResultCodes
     void EnteredCall() {
         mListener->OnEnteredCall();
     }
 
     void ExitedCall() {
         mListener->OnExitedCall();
     }
 
+    void EnteredSyncSend() {
+        mListener->OnEnteredSyncSend();
+    }
+
+    void ExitedSyncSend() {
+        mListener->OnExitedSyncSend();
+    }
+
     MessageListener *Listener() const {
         return mListener.get();
     }
 
     void DebugAbort(const char* file, int line, const char* cond,
                     const char* why,
                     bool reply=false) const;
 
--- a/ipc/glue/MessageLink.h
+++ b/ipc/glue/MessageLink.h
@@ -93,16 +93,21 @@ class MessageListener
     virtual void OnBeginSyncTransaction() {
     }
     virtual RacyInterruptPolicy MediateInterruptRace(const Message& parent,
                                                      const Message& child)
     {
         return RIPChildWins;
     }
 
+    virtual void OnEnteredSyncSend() {
+    }
+    virtual void OnExitedSyncSend() {
+    }
+
     virtual void ProcessRemoteNativeEventsInInterruptCall() {
     }
 
     // FIXME/bug 792652: this doesn't really belong here, but a
     // large refactoring is needed to put it where it belongs.
     virtual int32_t GetProtocolTypeId() = 0;
 };
 
--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -335,16 +335,40 @@ GCParameter(JSContext *cx, unsigned argc
         }
     }
 
     JS_SetGCParameter(cx->runtime(), param, value);
     args.rval().setUndefined();
     return true;
 }
 
+static void
+SetAllowRelazification(JSContext *cx, bool allow)
+{
+    JSRuntime *rt = cx->runtime();
+    MOZ_ASSERT(rt->allowRelazificationForTesting != allow);
+    rt->allowRelazificationForTesting = allow;
+
+    for (AllFramesIter i(cx); !i.done(); ++i)
+        i.script()->setDoNotRelazify(allow);
+}
+
+static bool
+RelazifyFunctions(JSContext *cx, unsigned argc, Value *vp)
+{
+    // Relazifying functions on GC is usually only done for compartments that are
+    // not active. To aid fuzzing, this testing function allows us to relazify
+    // even if the compartment is active.
+
+    SetAllowRelazification(cx, true);
+    bool res = GC(cx, argc, vp);
+    SetAllowRelazification(cx, false);
+    return res;
+}
+
 static bool
 IsProxy(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     if (args.length() != 1) {
         JS_ReportError(cx, "the function takes exactly one argument");
         return false;
     }
@@ -2231,16 +2255,21 @@ static const JSFunctionSpecWithHelp Test
 "minorgc([aboutToOverflow])",
 "  Run a minor collector on the Nursery. When aboutToOverflow is true, marks\n"
 "  the store buffer as about-to-overflow before collecting."),
 
     JS_FN_HELP("gcparam", GCParameter, 2, 0,
 "gcparam(name [, value])",
 "  Wrapper for JS_[GS]etGCParameter. The name is one of " GC_PARAMETER_ARGS_LIST),
 
+    JS_FN_HELP("relazifyFunctions", RelazifyFunctions, 0, 0,
+"relazifyFunctions(...)",
+"  Perform a GC and allow relazification of functions. Accepts the same\n"
+"  arguments as gc()."),
+
     JS_FN_HELP("getBuildConfiguration", GetBuildConfiguration, 0, 0,
 "getBuildConfiguration()",
 "  Return an object describing some of the configuration options SpiderMonkey\n"
 "  was built with."),
 
     JS_FN_HELP("countHeap", CountHeap, 0, 0,
 "countHeap([start[, kind[, thing]]])",
 "  Count the number of live GC things in the heap or things reachable from\n"
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -1972,20 +1972,22 @@ Parser<FullParseHandler>::checkFunctionD
 
     return true;
 }
 
 template <class T, class U>
 static inline void
 PropagateTransitiveParseFlags(const T *inner, U *outer)
 {
-   if (inner->bindingsAccessedDynamically())
-     outer->setBindingsAccessedDynamically();
-   if (inner->hasDebuggerStatement())
-     outer->setHasDebuggerStatement();
+    if (inner->bindingsAccessedDynamically())
+        outer->setBindingsAccessedDynamically();
+    if (inner->hasDebuggerStatement())
+        outer->setHasDebuggerStatement();
+    if (inner->hasDirectEval())
+        outer->setHasDirectEval();
 }
 
 template <typename ParseHandler>
 bool
 Parser<ParseHandler>::addFreeVariablesFromLazyFunction(JSFunction *fun,
                                                        ParseContext<ParseHandler> *pc)
 {
     // Update any definition nodes in this context according to free variables
@@ -7581,16 +7583,17 @@ Parser<ParseHandler>::memberExpr(TokenKi
             if (!nextMember)
                 return null();
 
             if (JSAtom *atom = handler.isName(lhs)) {
                 if (tt == TOK_LP && atom == context->names().eval) {
                     /* Select JSOP_EVAL and flag pc as heavyweight. */
                     op = pc->sc->strict ? JSOP_STRICTEVAL : JSOP_EVAL;
                     pc->sc->setBindingsAccessedDynamically();
+                    pc->sc->setHasDirectEval();
 
                     /*
                      * In non-strict mode code, direct calls to eval can add
                      * variables to the call object.
                      */
                     if (pc->sc->isFunctionBox() && !pc->sc->strict)
                         pc->sc->asFunctionBox()->setHasExtensibleScope();
                 }
--- a/js/src/frontend/SharedContext.h
+++ b/js/src/frontend/SharedContext.h
@@ -53,21 +53,25 @@ class AnyContextFlags
     //
     bool            bindingsAccessedDynamically:1;
 
     // Whether this script, or any of its inner scripts contains a debugger
     // statement which could potentially read or write anywhere along the
     // scope chain.
     bool            hasDebuggerStatement:1;
 
+    // A direct eval occurs in the body of the script.
+    bool            hasDirectEval:1;
+
   public:
     AnyContextFlags()
      :  hasExplicitUseStrict(false),
         bindingsAccessedDynamically(false),
-        hasDebuggerStatement(false)
+        hasDebuggerStatement(false),
+        hasDirectEval(false)
     { }
 };
 
 class FunctionContextFlags
 {
     // This class's data is all private and so only visible to these friends.
     friend class FunctionBox;
 
@@ -190,20 +194,22 @@ class SharedContext
     inline bool isGlobalSharedContext() { return toObjectBox() == nullptr; }
     inline bool isFunctionBox() { return toObjectBox() && toObjectBox()->isFunctionBox(); }
     inline GlobalSharedContext *asGlobalSharedContext();
     inline FunctionBox *asFunctionBox();
 
     bool hasExplicitUseStrict()        const { return anyCxFlags.hasExplicitUseStrict; }
     bool bindingsAccessedDynamically() const { return anyCxFlags.bindingsAccessedDynamically; }
     bool hasDebuggerStatement()        const { return anyCxFlags.hasDebuggerStatement; }
+    bool hasDirectEval()               const { return anyCxFlags.hasDirectEval; }
 
     void setExplicitUseStrict()           { anyCxFlags.hasExplicitUseStrict        = true; }
     void setBindingsAccessedDynamically() { anyCxFlags.bindingsAccessedDynamically = true; }
     void setHasDebuggerStatement()        { anyCxFlags.hasDebuggerStatement        = true; }
+    void setHasDirectEval()               { anyCxFlags.hasDirectEval               = true; }
 
     inline bool allLocalsAliased();
 
     // JSOPTION_EXTRA_WARNINGS warnings or strict mode errors.
     bool needStrictChecks() {
         return strict || extraWarnings;
     }
 
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/bug1122534.js
@@ -0,0 +1,16 @@
+// |jit-test| error: TypeError
+
+function newFunc(x) { new Function(x)(); };
+newFunc("\
+function GetUnicodeValues(c) {\
+    u = new Array();\
+    if ((c >= 0x0100 && c < 0x0138) || (c > 0x1Bedb  && c < 0x0178))\
+        return;\
+    return u;\
+}\
+function Unicode(c) {\
+    u = GetUnicodeValues(c);\
+    this.upper = u[0];\
+}\
+for (var i = 0; i <= 0x017f; i++) { var U = new Unicode(i); }\
+");
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/relazify.js
@@ -0,0 +1,16 @@
+function f(x) {
+    return x * 3;
+}
+for (var i=0; i<100; i++) {
+    f(i);
+}
+relazifyFunctions();
+
+f(1);
+f(1);
+
+relazifyFunctions();
+
+for (var i=0; i<10; i++) {
+    f.call(null, i);
+}
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -2082,39 +2082,16 @@ RemoveScriptRootRT(JSRuntime *rt, JS::He
  */
 extern JS_PUBLIC_API(bool)
 JS_AddExtraGCRootsTracer(JSRuntime *rt, JSTraceDataOp traceOp, void *data);
 
 /* Undo a call to JS_AddExtraGCRootsTracer. */
 extern JS_PUBLIC_API(void)
 JS_RemoveExtraGCRootsTracer(JSRuntime *rt, JSTraceDataOp traceOp, void *data);
 
-#ifdef JS_DEBUG
-
-/*
- * Debug-only method to dump the object graph of heap-allocated things.
- *
- * fp:              file for the dump output.
- * start:           when non-null, dump only things reachable from start
- *                  thing. Otherwise dump all things reachable from the
- *                  runtime roots.
- * startKind:       trace kind of start if start is not null. Must be
- *                  JSTRACE_OBJECT when start is null.
- * thingToFind:     dump only paths in the object graph leading to thingToFind
- *                  when non-null.
- * maxDepth:        the upper bound on the number of edges to descend from the
- *                  graph roots.
- * thingToIgnore:   thing to ignore during the graph traversal when non-null.
- */
-extern JS_PUBLIC_API(bool)
-JS_DumpHeap(JSRuntime *rt, FILE *fp, void* startThing, JSGCTraceKind kind,
-            void *thingToFind, size_t maxDepth, void *thingToIgnore);
-
-#endif
-
 /*
  * Garbage collector API.
  */
 extern JS_PUBLIC_API(void)
 JS_GC(JSRuntime *rt);
 
 extern JS_PUBLIC_API(void)
 JS_MaybeGC(JSContext *cx);
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -481,46 +481,54 @@ js::fun_resolve(JSContext *cx, HandleObj
         return true;
     }
 
     bool isLength = JSID_IS_ATOM(id, cx->names().length);
     if (isLength || JSID_IS_ATOM(id, cx->names().name)) {
         MOZ_ASSERT(!IsInternalFunctionObject(obj));
 
         RootedValue v(cx);
-        uint32_t attrs;
+
+        // Since f.length and f.name are configurable, they could be resolved
+        // and then deleted:
+        //     function f(x) {}
+        //     assertEq(f.length, 1);
+        //     delete f.length;
+        //     assertEq(f.name, "f");
+        //     delete f.name;
+        // Afterwards, asking for f.length or f.name again will cause this
+        // resolve hook to run again. Defining the property again the second
+        // time through would be a bug.
+        //     assertEq(f.length, 0);  // gets Function.prototype.length!
+        //     assertEq(f.name, "");  // gets Function.prototype.name!
+        // We use the RESOLVED_LENGTH and RESOLVED_NAME flags as a hack to prevent this
+        // bug.
         if (isLength) {
-            // Since f.length is configurable, it could be resolved and then deleted:
-            //     function f(x) {}
-            //     assertEq(f.length, 1);
-            //     delete f.length;
-            // Afterwards, asking for f.length again will cause this resolve
-            // hook to run again. Defining the property again the second
-            // time through would be a bug.
-            //     assertEq(f.length, 0);  // gets Function.prototype.length!
-            // We use the RESOLVED_LENGTH flag as a hack to prevent this bug.
             if (fun->hasResolvedLength())
                 return true;
 
             if (fun->isInterpretedLazy() && !fun->getOrCreateScript(cx))
                 return false;
             uint16_t length = fun->hasScript() ? fun->nonLazyScript()->funLength() :
                 fun->nargs() - fun->hasRest();
             v.setInt32(length);
-            attrs = JSPROP_READONLY;
         } else {
+            if (fun->hasResolvedName())
+                return true;
+
             v.setString(fun->atom() == nullptr ? cx->runtime()->emptyString : fun->atom());
-            attrs = JSPROP_READONLY | JSPROP_PERMANENT;
         }
 
-        if (!NativeDefineProperty(cx, fun, id, v, nullptr, nullptr, attrs))
+        if (!NativeDefineProperty(cx, fun, id, v, nullptr, nullptr, JSPROP_READONLY))
             return false;
 
         if (isLength)
             fun->setResolvedLength();
+        else
+            fun->setResolvedName();
 
         *resolvedp = true;
         return true;
     }
 
     return true;
 }
 
@@ -749,17 +757,19 @@ JSFunction::trace(JSTracer *trc)
             // - they are not in the self-hosting compartment
             // - they aren't generators
             // - they don't have JIT code attached
             // - they don't have child functions
             // - they have information for un-lazifying them again later
             // This information can either be a LazyScript, or the name of a
             // self-hosted function which can be cloned over again. The latter
             // is stored in the first extended slot.
-            if (IS_GC_MARKING_TRACER(trc) && !compartment()->hasBeenEntered() &&
+            JSRuntime *rt = trc->runtime();
+            if (IS_GC_MARKING_TRACER(trc) &&
+                (rt->allowRelazificationForTesting || !compartment()->hasBeenEntered()) &&
                 !compartment()->isDebuggee() && !compartment()->isSelfHosting &&
                 u.i.s.script_->isRelazifiable() && (!isSelfHostedBuiltin() || isExtended()))
             {
                 relazify(trc);
             } else {
                 MarkScriptUnbarriered(trc, &u.i.s.script_, "script");
             }
         } else if (isInterpretedLazy() && u.i.s.lazy_) {
@@ -1407,22 +1417,29 @@ JSFunction::createScriptForLazilyInterpr
 
         // Suppress GC for now although we should be able to remove this by
         // making 'lazy' a Rooted<LazyScript*> (which requires adding a
         // THING_ROOT_LAZY_SCRIPT).
         AutoSuppressGC suppressGC(cx);
 
         RootedScript script(cx, lazy->maybeScript());
 
+        // Only functions without inner functions or direct eval are
+        // re-lazified. Functions with either of those are on the static scope
+        // chain of their inner functions, or in the case of eval, possibly
+        // eval'd inner functions. This prohibits re-lazification as
+        // StaticScopeIter queries isHeavyweight of those functions, which
+        // requires a non-lazy script.
+        bool canRelazify = !lazy->numInnerFunctions() && !lazy->hasDirectEval();
+
         if (script) {
             fun->setUnlazifiedScript(script);
             // Remember the lazy script on the compiled script, so it can be
             // stored on the function again in case of re-lazification.
-            // Only functions without inner functions are re-lazified.
-            if (!lazy->numInnerFunctions())
+            if (canRelazify)
                 script->setLazyScript(lazy);
             return true;
         }
 
         if (fun != lazy->functionNonDelazifying()) {
             if (!lazy->functionDelazifying(cx))
                 return false;
             script = lazy->functionNonDelazifying()->nonLazyScript();
@@ -1436,17 +1453,17 @@ JSFunction::createScriptForLazilyInterpr
         // Lazy script caching is only supported for leaf functions. If a
         // script with inner functions was returned by the cache, those inner
         // functions would be delazified when deep cloning the script, even if
         // they have never executed.
         //
         // Additionally, the lazy script cache is not used during incremental
         // GCs, to avoid resurrecting dead scripts after incremental sweeping
         // has started.
-        if (!lazy->numInnerFunctions() && !JS::IsIncrementalGCInProgress(cx->runtime())) {
+        if (canRelazify && !JS::IsIncrementalGCInProgress(cx->runtime())) {
             LazyScriptCache::Lookup lookup(cx, lazy);
             cx->runtime()->lazyScriptCache.lookup(lookup, script.address());
         }
 
         if (script) {
             RootedObject enclosingScope(cx, lazy->enclosingScope());
             RootedScript clonedScript(cx, CloneScript(cx, enclosingScope, fun, script));
             if (!clonedScript)
@@ -1481,17 +1498,17 @@ JSFunction::createScriptForLazilyInterpr
         script = fun->nonLazyScript();
 
         // Remember the compiled script on the lazy script itself, in case
         // there are clones of the function still pointing to the lazy script.
         if (!lazy->maybeScript())
             lazy->initScript(script);
 
         // Try to insert the newly compiled script into the lazy script cache.
-        if (!lazy->numInnerFunctions()) {
+        if (canRelazify) {
             // A script's starting column isn't set by the bytecode emitter, so
             // specify this from the lazy script so that if an identical lazy
             // script is encountered later a match can be determined.
             script->setColumn(lazy->column());
 
             LazyScriptCache::Lookup lookup(cx, lazy);
             cx->runtime()->lazyScriptCache.insert(lookup, script);
 
@@ -1512,17 +1529,17 @@ JSFunction::createScriptForLazilyInterpr
     return cx->runtime()->cloneSelfHostedFunctionScript(cx, funName, fun);
 }
 
 void
 JSFunction::relazify(JSTracer *trc)
 {
     JSScript *script = nonLazyScript();
     MOZ_ASSERT(script->isRelazifiable());
-    MOZ_ASSERT(!compartment()->hasBeenEntered());
+    MOZ_ASSERT(trc->runtime()->allowRelazificationForTesting || !compartment()->hasBeenEntered());
     MOZ_ASSERT(!compartment()->isDebuggee());
 
     // If the script's canonical function isn't lazy, we have to mark the
     // script. Otherwise, the following scenario would leave it unmarked
     // and cause it to be swept while a function is still expecting it to be
     // valid:
     // 1. an incremental GC slice causes the canonical function to relazify
     // 2. a clone is used and delazifies the canonical function
--- a/js/src/jsfun.h
+++ b/js/src/jsfun.h
@@ -43,16 +43,17 @@ class JSFunction : public js::NativeObje
                                        decompilable nor constructible. */
         SELF_HOSTED_CTOR = 0x0200,  /* function is self-hosted builtin constructor and
                                        must be constructible but not decompilable. */
         HAS_REST         = 0x0400,  /* function has a rest (...) parameter */
         ASMJS            = 0x0800,  /* function is an asm.js module or exported function */
         INTERPRETED_LAZY = 0x1000,  /* function is interpreted but doesn't have a script yet */
         ARROW            = 0x2000,  /* ES6 '(args) => body' syntax */
         RESOLVED_LENGTH  = 0x4000,  /* f.length has been resolved (see js::fun_resolve). */
+        RESOLVED_NAME    = 0x8000,  /* f.name has been resolved (see js::fun_resolve). */
 
         /* Derived Flags values for convenience: */
         NATIVE_FUN = 0,
         ASMJS_CTOR = ASMJS | NATIVE_CTOR,
         ASMJS_LAMBDA_CTOR = ASMJS | NATIVE_CTOR | LAMBDA,
         INTERPRETED_LAMBDA = INTERPRETED | LAMBDA,
         INTERPRETED_LAMBDA_ARROW = INTERPRETED | LAMBDA | ARROW,
         STABLE_ACROSS_CLONES = NATIVE_CTOR | IS_FUN_PROTO | EXPR_CLOSURE | HAS_GUESSED_ATOM |
@@ -129,16 +130,17 @@ class JSFunction : public js::NativeObje
     bool hasRest()                  const { return flags() & HAS_REST; }
     bool isInterpretedLazy()        const { return flags() & INTERPRETED_LAZY; }
     bool hasScript()                const { return flags() & INTERPRETED; }
 
     // Arrow functions store their lexical |this| in the first extended slot.
     bool isArrow()                  const { return flags() & ARROW; }
 
     bool hasResolvedLength()        const { return flags() & RESOLVED_LENGTH; }
+    bool hasResolvedName()          const { return flags() & RESOLVED_NAME; }
 
     bool hasJITCode() const {
         if (!hasScript())
             return false;
 
         return nonLazyScript()->hasBaselineScript() || nonLazyScript()->hasIonScript();
     }
 
@@ -201,16 +203,20 @@ class JSFunction : public js::NativeObje
     void setArrow() {
         flags_ |= ARROW;
     }
 
     void setResolvedLength() {
         flags_ |= RESOLVED_LENGTH;
     }
 
+    void setResolvedName() {
+        flags_ |= RESOLVED_NAME;
+    }
+
     JSAtom *atom() const { return hasGuessedAtom() ? nullptr : atom_.get(); }
 
     js::PropertyName *name() const {
         return hasGuessedAtom() || !atom_ ? nullptr : atom_->asPropertyName();
     }
 
     void initAtom(JSAtom *atom) { atom_.init(atom); }
 
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -3784,16 +3784,17 @@ LazyScript::CreateRaw(ExclusiveContext *
 
     p.version = version;
     p.numFreeVariables = numFreeVariables;
     p.numInnerFunctions = numInnerFunctions;
     p.generatorKindBits = GeneratorKindAsBits(NotGenerator);
     p.strict = false;
     p.bindingsAccessedDynamically = false;
     p.hasDebuggerStatement = false;
+    p.hasDirectEval = false;
     p.directlyInsideEval = false;
     p.usesArgumentsApplyAndThis = false;
 
     LazyScript *res = LazyScript::CreateRaw(cx, fun, packedFields, begin, end, lineno, column);
     MOZ_ASSERT_IF(res, res->version() == version);
     return res;
 }
 
--- a/js/src/jsscript.h
+++ b/js/src/jsscript.h
@@ -1007,16 +1007,21 @@ class JSScript : public js::gc::TenuredC
 
     // Generation for this script's TypeScript. If out of sync with the
     // TypeZone's generation, the TypeScript needs to be swept.
     //
     // This should be a uint32 but is instead a bool so that MSVC packs it
     // correctly.
     bool typesGeneration_:1;
 
+    // Do not relazify this script. This is only used by the relazify()
+    // testing function for scripts that are on the stack. Usually we don't
+    // relazify functions in compartments with scripts on the stack.
+    bool doNotRelazify_:1;
+
     // Add padding so JSScript is gc::Cell aligned. Make padding protected
     // instead of private to suppress -Wunused-private-field compiler warnings.
   protected:
 #if JS_BITS_PER_WORD == 32
     uint32_t padding;
 #endif
 
     //
@@ -1311,16 +1316,20 @@ class JSScript : public js::gc::TenuredC
         return (uint32_t) typesGeneration_;
     }
 
     void setTypesGeneration(uint32_t generation) {
         MOZ_ASSERT(generation <= 1);
         typesGeneration_ = (bool) generation;
     }
 
+    void setDoNotRelazify(bool b) {
+        doNotRelazify_ = b;
+    }
+
     bool hasAnyIonScript() const {
         return hasIonScript();
     }
 
     bool hasIonScript() const {
         bool res = ion && ion != ION_DISABLED_SCRIPT && ion != ION_COMPILING_SCRIPT;
         MOZ_ASSERT_IF(res, baseline);
         return res;
@@ -1390,17 +1399,17 @@ class JSScript : public js::gc::TenuredC
         return baselineOrIonRaw;
     }
     static size_t offsetOfBaselineOrIonSkipArgCheck() {
         return offsetof(JSScript, baselineOrIonSkipArgCheck);
     }
 
     bool isRelazifiable() const {
         return (selfHosted() || lazyScript) &&
-               !isGenerator() && !hasBaselineScript() && !hasAnyIonScript();
+               !isGenerator() && !hasBaselineScript() && !hasAnyIonScript() && !doNotRelazify_;
     }
     void setLazyScript(js::LazyScript *lazy) {
         lazyScript = lazy;
     }
     js::LazyScript *maybeLazyScript() {
         return lazyScript;
     }
 
@@ -1868,24 +1877,25 @@ class LazyScript : public gc::TenuredCel
 #endif
   private:
 
     struct PackedView {
         // Assorted bits that should really be in ScriptSourceObject.
         uint32_t version : 8;
 
         uint32_t numFreeVariables : 24;
-        uint32_t numInnerFunctions : 23;
+        uint32_t numInnerFunctions : 22;
 
         uint32_t generatorKindBits : 2;
 
         // N.B. These are booleans but need to be uint32_t to pack correctly on MSVC.
         uint32_t strict : 1;
         uint32_t bindingsAccessedDynamically : 1;
         uint32_t hasDebuggerStatement : 1;
+        uint32_t hasDirectEval : 1;
         uint32_t directlyInsideEval : 1;
         uint32_t usesArgumentsApplyAndThis : 1;
         uint32_t hasBeenCloned : 1;
         uint32_t treatAsRunOnce : 1;
     };
 
     union {
         PackedView p_;
@@ -2001,16 +2011,23 @@ class LazyScript : public gc::TenuredCel
 
     bool hasDebuggerStatement() const {
         return p_.hasDebuggerStatement;
     }
     void setHasDebuggerStatement() {
         p_.hasDebuggerStatement = true;
     }
 
+    bool hasDirectEval() const {
+        return p_.hasDirectEval;
+    }
+    void setHasDirectEval() {
+        p_.hasDirectEval = true;
+    }
+
     bool directlyInsideEval() const {
         return p_.directlyInsideEval;
     }
     void setDirectlyInsideEval() {
         p_.directlyInsideEval = true;
     }
 
     bool usesArgumentsApplyAndThis() const {
rename from js/src/tests/ecma_5/strict/function-name.js
rename to js/src/tests/ecma_6/Function/function-name.js
--- a/js/src/tests/ecma_5/strict/function-name.js
+++ b/js/src/tests/ecma_6/Function/function-name.js
@@ -1,19 +1,64 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-
-/*
- * Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/licenses/publicdomain/
- */
-
-function fn() {
-  return function f(a, b, c) { };
+function testFunctionName(f) {
+    var name = f.name;
+    f.name = 'g';
+    assertEq(f.name, name);
+    assertEq(delete f.name, true);
+    assertEq(f.name, '');
+    assertEq(f.hasOwnProperty('name'), false);
+    f.name = 'g';
+    assertEq(f.name, '');
+    Object.defineProperty(f, 'name', {value: 'g'});
+    assertEq(f.name, 'g');
+}
+function testFunctionNameStrict(f) {
+    "use strict";
+    var name = f.name;
+    var error;
+    try {
+        f.name = 'g';
+    } catch (e) {
+        error = e;
+    }
+    assertEq(f.name, name);
+    assertEq(error instanceof TypeError, true);
+    assertEq(delete f.name, true);
+    assertEq(f.name, '');
+    assertEq(f.hasOwnProperty('name'), false);
+    error = null;
+    try {
+        f.name = 'g';
+    } catch (e) {
+        error = e;
+    }
+    assertEq(f.name, '');
+    assertEq(error instanceof TypeError, true);
+    Object.defineProperty(f, 'name', {value: 'g'});
+    assertEq(f.name, 'g');
 }
 
-assertEq(testLenientAndStrict('var f = fn(); f.name = "g"; f.name',
-                              returns("f"), raisesException(TypeError)),
-         true);
-assertEq(testLenientAndStrict('var f = fn(); delete f.name',
-                              returns(false), raisesException(TypeError)),
-         true);
+assertEq(Object.getOwnPropertyDescriptor(Object, "name").writable, false);
+assertEq(Object.getOwnPropertyDescriptor(Object, "name").enumerable, false);
+assertEq(Object.getOwnPropertyDescriptor(Object, "name").configurable, true);
+assertEq(Object.getOwnPropertyDescriptor(Object, "name").value, 'Object');
+assertEq(Object.getOwnPropertyDescriptor(function f(){}, "name").writable, false);
+assertEq(Object.getOwnPropertyDescriptor(function f(){}, "name").enumerable, false);
+assertEq(Object.getOwnPropertyDescriptor(function f(){}, "name").configurable, true);
+assertEq(Object.getOwnPropertyDescriptor(function f(){}, "name").value, 'f');
 
-reportCompare(true, true);
+// Basic test ensuring that Object.defineProperty works on pristine function.
+function f() {};
+Object.defineProperty(f, 'name', {value: 'g'});
+assertEq(f.name, 'g');
+
+// .name behaves as expected on scripted function.
+testFunctionName(function f(){});
+testFunctionNameStrict(function f(){});
+// .name behaves as expected on builtin function.
+testFunctionName(Function.prototype.apply);
+testFunctionNameStrict(Function.prototype.call);
+// .name behaves as expected on self-hosted builtin function.
+testFunctionName(Array.prototype.forEach);
+testFunctionNameStrict(Array.prototype.some);
+
+if (typeof reportCompare === "function")
+    reportCompare(0, 0);
--- a/js/src/vm/Runtime.cpp
+++ b/js/src/vm/Runtime.cpp
@@ -178,16 +178,17 @@ JSRuntime::JSRuntime(JSRuntime *parentRu
 #ifdef NIGHTLY_BUILD
     assertOnScriptEntryHook_(nullptr),
 #endif
     spsProfiler(thisFromCtor()),
     profilingScripts(false),
     suppressProfilerSampling(false),
     hadOutOfMemory(false),
     haveCreatedContext(false),
+    allowRelazificationForTesting(false),
     data(nullptr),
     signalHandlersInstalled_(false),
     canUseSignalHandlers_(false),
     defaultFreeOp_(thisFromCtor()),
     debuggerMutations(0),
     securityCallbacks(const_cast<JSSecurityCallbacks *>(&NullSecurityCallbacks)),
     DOMcallbacks(nullptr),
     destroyPrincipals(nullptr),
--- a/js/src/vm/Runtime.h
+++ b/js/src/vm/Runtime.h
@@ -1046,16 +1046,22 @@ struct JSRuntime : public JS::shadow::Ru
     }
 
     /* Had an out-of-memory error which did not populate an exception. */
     bool                hadOutOfMemory;
 
     /* A context has been created on this runtime. */
     bool                haveCreatedContext;
 
+    /*
+     * Allow relazifying functions in compartments that are active. This is
+     * only used by the relazifyFunctions() testing function.
+     */
+    bool                allowRelazificationForTesting;
+
     /* Linked list of all Debugger objects in the runtime. */
     mozilla::LinkedList<js::Debugger> debuggerList;
 
     /*
      * Head of circular list of all enabled Debuggers that have
      * onNewGlobalObject handler methods established.
      */
     JSCList             onNewGlobalObjectWatchers;
--- a/js/src/vm/ScopeObject.cpp
+++ b/js/src/vm/ScopeObject.cpp
@@ -1162,39 +1162,41 @@ ScopeIter::ScopeIter(JSContext *cx, Abst
     frame_(frame)
 {
     assertSameCompartment(cx, frame);
     settle();
     MOZ_GUARD_OBJECT_NOTIFIER_INIT;
 }
 
 void
-ScopeIter::settle()
+ScopeIter::incrementStaticScopeIter()
 {
+    ssi_++;
+
     // For named lambdas, DeclEnvObject scopes are always attached to their
     // CallObjects. Skip it here, as they are special cased in users of
     // ScopeIter.
     if (!ssi_.done() && ssi_.type() == StaticScopeIter<CanGC>::NamedLambda)
         ssi_++;
-
+}
+
+void
+ScopeIter::settle()
+{
     // Check for trying to iterate a heavyweight function frame before
     // the prologue has created the CallObject, in which case we have to skip.
     if (frame_ && frame_.isNonEvalFunctionFrame() &&
         frame_.fun()->isHeavyweight() && !frame_.hasCallObj())
     {
         MOZ_ASSERT(ssi_.type() == StaticScopeIter<CanGC>::Function);
-        ssi_++;
+        incrementStaticScopeIter();
     }
 
-    // Check if we have left the extent of the initial frame. This check must
-    // come between the named lambda check above and the direct eval check
-    // below. We must check the static scope after skipping the named lambda,
-    // as an SSI settled on a named lambda scope has no static scope. We must
-    // check the static scope before skipping the direct eval, as by then we
-    // would have already left the frame.
+    // Check if we have left the extent of the initial frame after we've
+    // settled on a static scope.
     if (frame_ && (ssi_.done() || maybeStaticScope() == frame_.script()->enclosingStaticScope()))
         frame_ = NullFramePtr();
 
 #ifdef DEBUG
     if (!ssi_.done() && hasScopeObject()) {
         switch (ssi_.type()) {
           case StaticScopeIter<CanGC>::Function:
             MOZ_ASSERT(scope_->as<CallObject>().callee().nonLazyScript() == ssi_.funScript());
@@ -1219,17 +1221,17 @@ ScopeIter &
 ScopeIter::operator++()
 {
     if (hasScopeObject()) {
         scope_ = &scope_->as<ScopeObject>().enclosingScope();
         if (scope_->is<DeclEnvObject>())
             scope_ = &scope_->as<DeclEnvObject>().enclosingScope();
     }
 
-    ssi_++;
+    incrementStaticScopeIter();
     settle();
 
     return *this;
 }
 
 ScopeIter::Type
 ScopeIter::type() const
 {
--- a/js/src/vm/ScopeObject.h
+++ b/js/src/vm/ScopeObject.h
@@ -719,16 +719,17 @@ CloneNestedScopeObject(JSContext *cx, Ha
 // Here, "frame" means a single activation of: a function, eval, or global
 // code.
 class ScopeIter
 {
     StaticScopeIter<CanGC> ssi_;
     RootedObject scope_;
     AbstractFramePtr frame_;
 
+    void incrementStaticScopeIter();
     void settle();
 
     // No value semantics.
     ScopeIter(const ScopeIter &si) = delete;
 
   public:
     // Constructing from a copy of an existing ScopeIter.
     ScopeIter(JSContext *cx, const ScopeIter &si
--- a/js/xpconnect/src/XPCJSRuntime.cpp
+++ b/js/xpconnect/src/XPCJSRuntime.cpp
@@ -35,16 +35,17 @@
 #include "jsprf.h"
 #include "js/MemoryMetrics.h"
 #include "mozilla/dom/GeneratedAtomList.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/WindowBinding.h"
 #include "mozilla/Atomics.h"
 #include "mozilla/Attributes.h"
+#include "mozilla/ProcessHangMonitor.h"
 #include "AccessCheck.h"
 #include "nsGlobalWindow.h"
 #include "nsAboutProtocolUtils.h"
 
 #include "GeckoProfiler.h"
 #include "nsIXULRuntime.h"
 #include "nsJSPrincipals.h"
 
@@ -1107,16 +1108,17 @@ class Watchdog
     bool mShuttingDown;
     mozilla::Atomic<int32_t> mMinScriptRunTimeSeconds;
 };
 
 #ifdef MOZ_NUWA_PROCESS
 #include "ipc/Nuwa.h"
 #endif
 
+#define PREF_MAX_SCRIPT_RUN_TIME_CHILD "dom.max_child_script_run_time"
 #define PREF_MAX_SCRIPT_RUN_TIME_CONTENT "dom.max_script_run_time"
 #define PREF_MAX_SCRIPT_RUN_TIME_CHROME "dom.max_chrome_script_run_time"
 
 class WatchdogManager : public nsIObserver
 {
   public:
 
     NS_DECL_ISUPPORTS
@@ -1129,29 +1131,31 @@ class WatchdogManager : public nsIObserv
 
         // Enable the watchdog, if appropriate.
         RefreshWatchdog();
 
         // Register ourselves as an observer to get updates on the pref.
         mozilla::Preferences::AddStrongObserver(this, "dom.use_watchdog");
         mozilla::Preferences::AddStrongObserver(this, PREF_MAX_SCRIPT_RUN_TIME_CONTENT);
         mozilla::Preferences::AddStrongObserver(this, PREF_MAX_SCRIPT_RUN_TIME_CHROME);
+        mozilla::Preferences::AddStrongObserver(this, PREF_MAX_SCRIPT_RUN_TIME_CHILD);
     }
 
   protected:
 
     virtual ~WatchdogManager()
     {
         // Shutting down the watchdog requires context-switching to the watchdog
         // thread, which isn't great to do in a destructor. So we require
         // consumers to shut it down manually before releasing it.
         MOZ_ASSERT(!mWatchdog);
         mozilla::Preferences::RemoveObserver(this, "dom.use_watchdog");
         mozilla::Preferences::RemoveObserver(this, PREF_MAX_SCRIPT_RUN_TIME_CONTENT);
         mozilla::Preferences::RemoveObserver(this, PREF_MAX_SCRIPT_RUN_TIME_CHROME);
+        mozilla::Preferences::RemoveObserver(this, PREF_MAX_SCRIPT_RUN_TIME_CHILD);
     }
 
   public:
 
     NS_IMETHOD Observe(nsISupports* aSubject, const char* aTopic,
                        const char16_t* aData)
     {
         RefreshWatchdog();
@@ -1219,17 +1223,20 @@ class WatchdogManager : public nsIObserv
 
         if (mWatchdog) {
             int32_t contentTime = Preferences::GetInt(PREF_MAX_SCRIPT_RUN_TIME_CONTENT, 10);
             if (contentTime <= 0)
                 contentTime = INT32_MAX;
             int32_t chromeTime = Preferences::GetInt(PREF_MAX_SCRIPT_RUN_TIME_CHROME, 20);
             if (chromeTime <= 0)
                 chromeTime = INT32_MAX;
-            mWatchdog->SetMinScriptRunTimeSeconds(std::min(contentTime, chromeTime));
+            int32_t childTime = Preferences::GetInt(PREF_MAX_SCRIPT_RUN_TIME_CHILD, 3);
+            if (childTime <= 0)
+                childTime = INT32_MAX;
+            mWatchdog->SetMinScriptRunTimeSeconds(std::min(std::min(contentTime, chromeTime), childTime));
         }
     }
 
     void StartWatchdog()
     {
         MOZ_ASSERT(!mWatchdog);
         mWatchdog = new Watchdog(this);
         mWatchdog->Init();
@@ -1336,16 +1343,20 @@ XPCJSRuntime::DefaultJSContextCallback(J
     MOZ_ASSERT(rt == Get()->Runtime());
     return Get()->GetJSContextStack()->GetSafeJSContext();
 }
 
 // static
 void
 XPCJSRuntime::ActivityCallback(void *arg, bool active)
 {
+    if (!active) {
+        ProcessHangMonitor::ClearHang();
+    }
+
     XPCJSRuntime* self = static_cast<XPCJSRuntime*>(arg);
     self->mWatchdogManager->RecordRuntimeActivity(active);
 }
 
 // static
 //
 // JS-CTypes creates and caches a JSContext that it uses when executing JS
 // callbacks. When we're notified that ctypes is about to call into some JS,
@@ -1374,23 +1385,26 @@ XPCJSRuntime::InterruptCallback(JSContex
         return true;
     }
 
     // Sometimes we get called back during XPConnect initialization, before Gecko
     // has finished bootstrapping. Avoid crashing in nsContentUtils below.
     if (!nsContentUtils::IsInitialized())
         return true;
 
+    bool contentProcess = XRE_GetProcessType() == GeckoProcessType_Content;
+
     // This is at least the second interrupt callback we've received since
     // returning to the event loop. See how long it's been, and what the limit
     // is.
     TimeDuration duration = TimeStamp::NowLoRes() - self->mSlowScriptCheckpoint;
     bool chrome = nsContentUtils::IsCallerChrome();
-    const char *prefName = chrome ? PREF_MAX_SCRIPT_RUN_TIME_CHROME
-                                  : PREF_MAX_SCRIPT_RUN_TIME_CONTENT;
+    const char *prefName = contentProcess ? PREF_MAX_SCRIPT_RUN_TIME_CHILD
+                                 : chrome ? PREF_MAX_SCRIPT_RUN_TIME_CHROME
+                                          : PREF_MAX_SCRIPT_RUN_TIME_CONTENT;
     int32_t limit = Preferences::GetInt(prefName, chrome ? 20 : 10);
 
     // If there's no limit, or we're within the limit, let it go.
     if (limit == 0 || duration.ToSeconds() < limit)
         return true;
 
     //
     // This has gone on long enough! Time to take action. ;-)
@@ -1418,17 +1432,19 @@ XPCJSRuntime::InterruptCallback(JSContex
 
     // Show the prompt to the user, and kill if requested.
     nsGlobalWindow::SlowScriptResponse response = win->ShowSlowScriptDialog();
     if (response == nsGlobalWindow::KillSlowScript)
         return false;
 
     // The user chose to continue the script. Reset the timer, and disable this
     // machinery with a pref of the user opted out of future slow-script dialogs.
-    self->mSlowScriptCheckpoint = TimeStamp::NowLoRes();
+    if (response != nsGlobalWindow::ContinueSlowScriptAndKeepNotifying)
+        self->mSlowScriptCheckpoint = TimeStamp::NowLoRes();
+
     if (response == nsGlobalWindow::AlwaysContinueSlowScript)
         Preferences::SetInt(prefName, 0);
 
     return true;
 }
 
 void
 XPCJSRuntime::CustomOutOfMemoryCallback()
--- a/layout/generic/WritingModes.h
+++ b/layout/generic/WritingModes.h
@@ -24,19 +24,59 @@
 // (In some cases, there are internal (private) methods that don't do this;
 // such methods should only be used by other methods that have already checked
 // the writing modes.)
 
 #define CHECK_WRITING_MODE(param) \
    NS_ASSERTION(param == GetWritingMode(), "writing-mode mismatch")
 
 namespace mozilla {
-// Logical side constants for use in various places.
-enum LogicalSide { eLogicalSideBStart, eLogicalSideBEnd,
-                   eLogicalSideIStart, eLogicalSideIEnd };
+
+// Physical axis constants.
+enum PhysicalAxis {
+  eAxisVertical      = 0x0,
+  eAxisHorizontal    = 0x1
+};
+
+// Logical axis, edge and side constants for use in various places.
+enum LogicalAxis {
+  eLogicalAxisBlock  = 0x0,
+  eLogicalAxisInline = 0x1
+};
+enum LogicalEdge {
+  eLogicalEdgeStart  = 0x0,
+  eLogicalEdgeEnd    = 0x1
+};
+enum LogicalSide {
+  eLogicalSideBStart = (eLogicalAxisBlock  << 1) | eLogicalEdgeStart,  // 0x0
+  eLogicalSideBEnd   = (eLogicalAxisBlock  << 1) | eLogicalEdgeEnd,    // 0x1
+  eLogicalSideIStart = (eLogicalAxisInline << 1) | eLogicalEdgeStart,  // 0x2
+  eLogicalSideIEnd   = (eLogicalAxisInline << 1) | eLogicalEdgeEnd     // 0x3
+};
+
+inline bool IsInline(LogicalSide aSide) { return aSide & 0x2; }
+inline bool IsBlock(LogicalSide aSide) { return !IsInline(aSide); }
+inline bool IsEnd(LogicalSide aSide) { return aSide & 0x1; }
+inline bool IsStart(LogicalSide aSide) { return !IsEnd(aSide); }
+
+inline LogicalAxis GetAxis(LogicalSide aSide)
+{
+  return IsInline(aSide) ? eLogicalAxisInline : eLogicalAxisBlock;
+}
+
+inline LogicalEdge GetEdge(LogicalSide aSide)
+{
+  return IsEnd(aSide) ? eLogicalEdgeEnd : eLogicalEdgeStart;
+}
+
+inline LogicalSide
+MakeLogicalSide(LogicalAxis aAxis, LogicalEdge aEdge)
+{
+  return LogicalSide((aAxis << 1) | aEdge);
+}
 
 enum LogicalSideBits {
   eLogicalSideBitsNone   = 0,
   eLogicalSideBitsBStart = 1 << eLogicalSideBStart,
   eLogicalSideBitsBEnd   = 1 << eLogicalSideBEnd,
   eLogicalSideBitsIEnd   = 1 << eLogicalSideIEnd,
   eLogicalSideBitsIStart = 1 << eLogicalSideIStart,
   eLogicalSideBitsBBoth = eLogicalSideBitsBStart | eLogicalSideBitsBEnd,
@@ -202,16 +242,119 @@ public:
    * in vertical lines, in which case we should prefer an alphabetic baseline;
    * otherwise, the default is centered.
    * Note that some glyph runs may be rendered sideways even if this is false,
    * due to text-orientation:mixed resolution, but in that case the dominant
    * baseline remains centered.
    */
   bool IsSideways() const { return !!(mWritingMode & eSidewaysMask); }
 
+  static mozilla::PhysicalAxis PhysicalAxisForLogicalAxis(
+                                              uint8_t aWritingModeValue,
+                                              LogicalAxis aAxis)
+  {
+    // This relies on bit 0 of a writing-value mode indicating vertical
+    // orientation and bit 0 of a LogicalAxis value indicating the inline axis,
+    // so that it can correctly form mozilla::PhysicalAxis values using bit
+    // manipulation.
+    static_assert(NS_STYLE_WRITING_MODE_HORIZONTAL_TB == 0 &&
+                  NS_STYLE_WRITING_MODE_VERTICAL_RL == 1 &&
+                  NS_STYLE_WRITING_MODE_VERTICAL_LR == 3 &&
+                  eLogicalAxisBlock == 0 &&
+                  eLogicalAxisInline == 1 &&
+                  eAxisVertical == 0 && 
+                  eAxisHorizontal == 1,
+                  "unexpected writing-mode, logical axis or physical axis "
+                  "constant values");
+    return mozilla::PhysicalAxis((aWritingModeValue ^ aAxis) & 0x1);
+  }
+
+  mozilla::PhysicalAxis PhysicalAxis(LogicalAxis aAxis) const
+  {
+    // This will set wm to either NS_STYLE_WRITING_MODE_HORIZONTAL_TB or
+    // NS_STYLE_WRITING_MODE_VERTICAL_RL, and not the other two (real
+    // and hypothetical) values.  But this is fine; we only need to
+    // distinguish between vertical and horizontal in
+    // PhysicalAxisForLogicalAxis.
+    int wm = mWritingMode & eOrientationMask;
+    return PhysicalAxisForLogicalAxis(wm, aAxis);
+  }
+
+  static mozilla::Side PhysicalSideForBlockAxis(uint8_t aWritingModeValue,
+                                                LogicalEdge aEdge)
+  {
+    // indexes are NS_STYLE_WRITING_MODE_* values, which are the same as these
+    // two-bit values:
+    //   bit 0 = the eOrientationMask value
+    //   bit 1 = the eBlockFlowMask value
+    static const mozilla::css::Side kLogicalBlockSides[][2] = {
+      { NS_SIDE_TOP,    NS_SIDE_BOTTOM },  // horizontal-tb
+      { NS_SIDE_RIGHT,  NS_SIDE_LEFT   },  // vertical-rl
+      { NS_SIDE_BOTTOM, NS_SIDE_TOP    },  // (horizontal-bt)
+      { NS_SIDE_LEFT,   NS_SIDE_RIGHT  },  // vertical-lr
+    };
+
+    NS_ASSERTION(aWritingModeValue < 4, "invalid aWritingModeValue value");
+    return kLogicalBlockSides[aWritingModeValue][aEdge];
+  }
+
+  mozilla::Side PhysicalSideForInlineAxis(LogicalEdge aEdge) const
+  {
+    // indexes are four-bit values:
+    //   bit 0 = the eOrientationMask value
+    //   bit 1 = the eInlineFlowMask value
+    //   bit 2 = the eBlockFlowMask value
+    //   bit 3 = the eLineOrientMask value
+    static const mozilla::css::Side kLogicalInlineSides[][2] = {
+      { NS_SIDE_LEFT,   NS_SIDE_RIGHT  },  // horizontal-tb                  ltr
+      { NS_SIDE_TOP,    NS_SIDE_BOTTOM },  // vertical-rl                    ltr
+      { NS_SIDE_RIGHT,  NS_SIDE_LEFT   },  // horizontal-tb                  rtl
+      { NS_SIDE_BOTTOM, NS_SIDE_TOP    },  // vertical-rl                    rtl
+      { NS_SIDE_RIGHT,  NS_SIDE_LEFT   },  // (horizontal-bt)  (inverted)    ltr
+      { NS_SIDE_TOP,    NS_SIDE_BOTTOM },  // vertical-lr      sideways-left rtl
+      { NS_SIDE_LEFT,   NS_SIDE_RIGHT  },  // (horizontal-bt)  (inverted)    rtl
+      { NS_SIDE_BOTTOM, NS_SIDE_TOP    },  // vertical-lr      sideways-left ltr
+      { NS_SIDE_LEFT,   NS_SIDE_RIGHT  },  // horizontal-tb    (inverted)    rtl
+      { NS_SIDE_TOP,    NS_SIDE_BOTTOM },  // vertical-rl      sideways-left rtl
+      { NS_SIDE_RIGHT,  NS_SIDE_LEFT   },  // horizontal-tb    (inverted)    ltr
+      { NS_SIDE_BOTTOM, NS_SIDE_TOP    },  // vertical-rl      sideways-left ltr
+      { NS_SIDE_LEFT,   NS_SIDE_RIGHT  },  // (horizontal-bt)                ltr
+      { NS_SIDE_TOP,    NS_SIDE_BOTTOM },  // vertical-lr                    ltr
+      { NS_SIDE_RIGHT,  NS_SIDE_LEFT   },  // (horizontal-bt)                rtl
+      { NS_SIDE_BOTTOM, NS_SIDE_TOP    },  // vertical-lr                    rtl
+    };
+
+    // Inline axis sides depend on all three of writing-mode, text-orientation
+    // and direction, which are encoded in the eOrientationMask,
+    // eInlineFlowMask, eBlockFlowMask and eLineOrientMask bits.  Use these four
+    // bits to index into kLogicalInlineSides.
+    static_assert(eOrientationMask == 0x01 && eInlineFlowMask == 0x02 &&
+                  eBlockFlowMask == 0x04 && eLineOrientMask == 0x08,
+                  "unexpected mask values");
+    int index = mWritingMode & 0x0F;
+    return kLogicalInlineSides[index][aEdge];
+  }
+
+  /**
+   * Returns the physical side corresponding to the specified logical side,
+   * given the current writing mode.
+   */
+  mozilla::Side PhysicalSide(LogicalSide aSide) const
+  {
+    if (IsBlock(aSide)) {
+      static_assert(eOrientationMask == 0x01 && eBlockFlowMask == 0x04,
+                    "unexpected mask values");
+      int wm = ((mWritingMode & eBlockFlowMask) >> 1) |
+               (mWritingMode & eOrientationMask);
+      return PhysicalSideForBlockAxis(wm, GetEdge(aSide));
+    }
+
+    return PhysicalSideForInlineAxis(GetEdge(aSide));
+  }
+
   /**
    * Default constructor gives us a horizontal, LTR writing mode.
    * XXX We will probably eliminate this and require explicit initialization
    *     in all cases once transition is complete.
    */
   WritingMode()
     : mWritingMode(0)
   { }
--- a/layout/generic/nsBlockFrame.cpp
+++ b/layout/generic/nsBlockFrame.cpp
@@ -2938,32 +2938,52 @@ IsNonAutoNonZeroHeight(const nsStyleCoor
 }
 
 /* virtual */ bool
 nsBlockFrame::IsSelfEmpty()
 {
   // Blocks which are margin-roots (including inline-blocks) cannot be treated
   // as empty for margin-collapsing and other purposes. They're more like
   // replaced elements.
-  if (GetStateBits() & NS_BLOCK_MARGIN_ROOT)
+  if (GetStateBits() & NS_BLOCK_MARGIN_ROOT) {
     return false;
+  }
 
   const nsStylePosition* position = StylePosition();
-
-  if (IsNonAutoNonZeroHeight(position->mMinHeight) ||
-      IsNonAutoNonZeroHeight(position->mHeight))
-    return false;
+  bool vertical = GetWritingMode().IsVertical();
+
+  if (vertical) {
+    if (IsNonAutoNonZeroHeight(position->mMinWidth) ||
+        IsNonAutoNonZeroHeight(position->mWidth)) {
+      return false;
+    }
+  } else {
+    if (IsNonAutoNonZeroHeight(position->mMinHeight) ||
+        IsNonAutoNonZeroHeight(position->mHeight)) {
+      return false;
+    }
+  }
 
   const nsStyleBorder* border = StyleBorder();
   const nsStylePadding* padding = StylePadding();
-  if (border->GetComputedBorderWidth(NS_SIDE_TOP) != 0 ||
-      border->GetComputedBorderWidth(NS_SIDE_BOTTOM) != 0 ||
-      !nsLayoutUtils::IsPaddingZero(padding->mPadding.GetTop()) ||
-      !nsLayoutUtils::IsPaddingZero(padding->mPadding.GetBottom())) {
-    return false;
+
+  if (vertical) {
+    if (border->GetComputedBorderWidth(NS_SIDE_LEFT) != 0 ||
+        border->GetComputedBorderWidth(NS_SIDE_RIGHT) != 0 ||
+        !nsLayoutUtils::IsPaddingZero(padding->mPadding.GetLeft()) ||
+        !nsLayoutUtils::IsPaddingZero(padding->mPadding.GetRight())) {
+      return false;
+    }
+  } else {
+    if (border->GetComputedBorderWidth(NS_SIDE_TOP) != 0 ||
+        border->GetComputedBorderWidth(NS_SIDE_BOTTOM) != 0 ||
+        !nsLayoutUtils::IsPaddingZero(padding->mPadding.GetTop()) ||
+        !nsLayoutUtils::IsPaddingZero(padding->mPadding.GetBottom())) {
+      return false;
+    }
   }
 
   if (HasOutsideBullet() && !BulletIsEmpty()) {
     return false;
   }
 
   return true;
 }
--- a/layout/generic/nsInlineFrame.cpp
+++ b/layout/generic/nsInlineFrame.cpp
@@ -99,40 +99,53 @@ nsInlineFrame::IsSelfEmpty()
   // don't.  At least not in our codebase.
   if (GetPresContext()->CompatibilityMode() == eCompatibility_FullStandards) {
     return false;
   }
 #endif
   const nsStyleMargin* margin = StyleMargin();
   const nsStyleBorder* border = StyleBorder();
   const nsStylePadding* padding = StylePadding();
-  // XXX Top and bottom removed, since they shouldn't affect things, but this
+  // Block-start and -end ignored, since they shouldn't affect things, but this
   // doesn't really match with nsLineLayout.cpp's setting of
   // ZeroEffectiveSpanBox, anymore, so what should this really be?
-  bool haveRight =
-    border->GetComputedBorderWidth(NS_SIDE_RIGHT) != 0 ||
-    !nsLayoutUtils::IsPaddingZero(padding->mPadding.GetRight()) ||
-    !IsMarginZero(margin->mMargin.GetRight());
-  bool haveLeft =
-    border->GetComputedBorderWidth(NS_SIDE_LEFT) != 0 ||
-    !nsLayoutUtils::IsPaddingZero(padding->mPadding.GetLeft()) ||
-    !IsMarginZero(margin->mMargin.GetLeft());
-  if (haveLeft || haveRight) {
+  WritingMode wm = GetWritingMode();
+  bool haveStart, haveEnd;
+  // Initially set up haveStart and haveEnd in terms of visual (LTR/TTB)
+  // coordinates; we'll exchange them later if bidi-RTL is in effect to
+  // get logical start and end flags.
+  if (wm.IsVertical()) {
+    haveStart =
+      border->GetComputedBorderWidth(NS_SIDE_TOP) != 0 ||
+      !nsLayoutUtils::IsPaddingZero(padding->mPadding.GetTop()) ||
+      !IsMarginZero(margin->mMargin.GetTop());
+    haveEnd =
+      border->GetComputedBorderWidth(NS_SIDE_BOTTOM) != 0 ||
+      !nsLayoutUtils::IsPaddingZero(padding->mPadding.GetBottom()) ||
+      !IsMarginZero(margin->mMargin.GetBottom());
+  } else {
+    haveStart =
+      border->GetComputedBorderWidth(NS_SIDE_LEFT) != 0 ||
+      !nsLayoutUtils::IsPaddingZero(padding->mPadding.GetLeft()) ||
+      !IsMarginZero(margin->mMargin.GetLeft());
+    haveEnd =
+      border->GetComputedBorderWidth(NS_SIDE_RIGHT) != 0 ||
+      !nsLayoutUtils::IsPaddingZero(padding->mPadding.GetRight()) ||
+      !IsMarginZero(margin->mMargin.GetRight());
+  }
+  if (haveStart || haveEnd) {
     // We skip this block and return false for box-decoration-break:clone since
     // in that case all the continuations will have the border/padding/margin.
     if ((GetStateBits() & NS_FRAME_PART_OF_IBSPLIT) &&
         StyleBorder()->mBoxDecorationBreak ==
           NS_STYLE_BOX_DECORATION_BREAK_SLICE) {
-      bool haveStart, haveEnd;
-      if (NS_STYLE_DIRECTION_LTR == StyleVisibility()->mDirection) {
-        haveStart = haveLeft;
-        haveEnd = haveRight;
-      } else {
-        haveStart = haveRight;
-        haveEnd = haveLeft;
+      // When direction=rtl, we need to consider logical rather than visual
+      // start and end, so swap the flags.
+      if (!wm.IsBidiLTR()) {
+        Swap(haveStart, haveEnd);
       }
       // For ib-split frames, ignore things we know we'll skip in GetSkipSides.
       // XXXbz should we be doing this for non-ib-split frames too, in a more
       // general way?
 
       // Get the first continuation eagerly, as a performance optimization, to
       // avoid having to get it twice..
       nsIFrame* firstCont = FirstContinuation();
--- a/layout/inspector/inDOMUtils.cpp
+++ b/layout/inspector/inDOMUtils.cpp
@@ -517,17 +517,17 @@ static void GetKeywordsForProperty(const
                                    nsTArray<nsString>& aArray)
 {
   if (nsCSSProps::IsShorthand(aProperty)) {
     // Shorthand props have no keywords.
     return;
   }
   const nsCSSProps::KTableValue *keywordTable =
     nsCSSProps::kKeywordTableTable[aProperty];
-  if (keywordTable && keywordTable != nsCSSProps::kBoxPropSourceKTable) {
+  if (keywordTable) {
     size_t i = 0;
     while (nsCSSKeyword(keywordTable[i]) != eCSSKeyword_UNKNOWN) {
       nsCSSKeyword word = nsCSSKeyword(keywordTable[i]);
       InsertNoDuplicates(aArray,
                          NS_ConvertASCIItoUTF16(nsCSSKeywords::GetStringValue(word)));
       // Increment counter by 2, because in this table every second
       // element is a nsCSSKeyword.
       i += 2;
@@ -743,25 +743,27 @@ inDOMUtils::GetCSSValuesForProperty(cons
     // Get colors first.
     GetColorsForProperty(propertyParserVariant, array);
     if (propertyParserVariant & VARIANT_KEYWORD) {
       GetKeywordsForProperty(propertyID, array);
     }
     GetOtherValuesForProperty(propertyParserVariant, array);
   } else {
     // Property is shorthand.
-    CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(subproperty, propertyID) {
+    CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(subproperty, propertyID,
+                                         nsCSSProps::eEnabledForAllContent) {
       // Get colors (once) first.
       uint32_t propertyParserVariant = nsCSSProps::ParserVariant(*subproperty);
       if (propertyParserVariant & VARIANT_COLOR) {
         GetColorsForProperty(propertyParserVariant, array);
         break;
       }
     }
-    CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(subproperty, propertyID) {
+    CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(subproperty, propertyID,
+                                         nsCSSProps::eEnabledForAllContent) {
       uint32_t propertyParserVariant = nsCSSProps::ParserVariant(*subproperty);
       if (propertyParserVariant & VARIANT_KEYWORD) {
         GetKeywordsForProperty(*subproperty, array);
       }
       GetOtherValuesForProperty(propertyParserVariant, array);
     }
   }
   // All CSS properties take initial, inherit and unset.
--- a/layout/inspector/tests/test_bug1006595.html
+++ b/layout/inspector/tests/test_bug1006595.html
@@ -18,21 +18,19 @@ https://bugzilla.mozilla.org/show_bug.cg
     }
   }
   var utils = SpecialPowers.Cc["@mozilla.org/inspector/dom-utils;1"]
     .getService(SpecialPowers.Ci.inIDOMUtils);
 
   var paddingSubProps = utils.getSubpropertiesForCSSProperty("padding");
   arraysEqual(paddingSubProps,
               [ "padding-top",
-                "padding-right-value",
+                "padding-right",
                 "padding-bottom",
-                "padding-left-value",
-                "padding-left-ltr-source", "padding-left-rtl-source",
-                "padding-right-ltr-source", "padding-right-rtl-source" ],
+                "padding-left" ],
               "'padding' subproperties");
 
   var displaySubProps = utils.getSubpropertiesForCSSProperty("color");
   arraysEqual(displaySubProps, [ "color" ],
               "'color' subproperties");
 
   ok(utils.cssPropertyIsShorthand("padding"), "'padding' is a shorthand")
   ok(!utils.cssPropertyIsShorthand("color"), "'color' is not a shorthand")
new file mode 100644
--- /dev/null
+++ b/layout/reftests/writing-mode/1122366-1-margin-collapse-ref.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html>
+ <head>
+  <title>Bug 1122366 - margin collapsing</title>
+  <style type="text/css">
+  div {
+    font: 40px/1em serif;
+    height: 4em;
+  }
+  div.wrapper {
+    margin: 10px;
+    background: blue;
+    border-left: green solid .5em;
+    border-right: green solid 1.5em;
+    width: 2em;
+  }
+  </style>
+ </head>
+ <body>
+  <div class="wrapper">
+  </div>
+  <div class="wrapper">
+  </div>
+ </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/writing-mode/1122366-1-margin-collapse.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<html>
+ <head>
+  <title>Bug 1122366 - margin collapsing</title>
+  <style type="text/css">
+  div {
+    font: 40px/1em serif;
+    height: 4em;
+  }
+  div.wrapper {
+    margin: 10px;
+    background: blue;
+    border-left: green solid .5em;
+    border-right: green solid 1.5em;
+  }
+  div.lr {
+    -webkit-writing-mode: vertical-lr;
+    writing-mode: tb-lr; /* IE11 */
+    writing-mode: vertical-lr;
+  }
+  div.rl {
+    -webkit-writing-mode: vertical-rl;
+    writing-mode: tb-rl; /* IE11 */
+    writing-mode: vertical-rl;
+  }
+  div.widthless
+  {
+    margin-right: 2em;
+    width: 0;
+  }
+  </style>
+ </head>
+ <body>
+  <div class="wrapper lr">
+    <div class="widthless"></div>
+    <div class="widthless"></div>
+  </div>
+  <div class="wrapper rl">
+    <div class="widthless"></div>
+    <div class="widthless"></div>
+  </div>
+ </body>
+</html>
--- a/layout/reftests/writing-mode/reftest.list
+++ b/layout/reftests/writing-mode/reftest.list
@@ -28,9 +28,10 @@ random-if(gtk2Widget) == 1094434-2.html 
 fails == 1102175-1a.html 1102175-1-ref.html
 == 1102175-1b.html 1102175-1-ref.html
 == 1103613-1.html 1103613-1-ref.html
 == 1105268-1-min-max-dimensions.html 1105268-1-min-max-dimensions-ref.html
 == 1105268-2-min-max-dimensions.html 1105268-2-min-max-dimensions-ref.html
 == 1106669-1-intrinsic-for-container.html 1106669-1-intrinsic-for-container-ref.html
 == 1108923-1-percentage-margins.html 1108923-1-percentage-margins-ref.html
 == 1111944-1-list-marker.html 1111944-1-list-marker-ref.html
-HTTP(..) == 1115916-1-vertical-metrics.html 1115916-1-vertical-metrics-ref.html
\ No newline at end of file
+HTTP(..) == 1115916-1-vertical-metrics.html 1115916-1-vertical-metrics-ref.html
+== 1122366-1-margin-collapse.html 1122366-1-margin-collapse-ref.html
--- a/layout/style/Declaration.cpp
+++ b/layout/style/Declaration.cpp
@@ -64,17 +64,18 @@ Declaration::RemoveProperty(nsCSSPropert
 {
   MOZ_ASSERT(0 <= aProperty && aProperty < eCSSProperty_COUNT);
 
   nsCSSExpandedDataBlock data;
   ExpandTo(&data);
   NS_ABORT_IF_FALSE(!mData && !mImportantData, "Expand didn't null things out");
 
   if (nsCSSProps::IsShorthand(aProperty)) {
-    CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(p, aProperty) {
+    CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(p, aProperty,
+                                         nsCSSProps::eEnabledForAllContent) {
       data.ClearLonghandProperty(*p);
       mOrder.RemoveElement(static_cast<uint32_t>(*p));
     }
   } else {
     data.ClearLonghandProperty(aProperty);
     mOrder.RemoveElement(static_cast<uint32_t>(aProperty));
   }
 
@@ -163,20 +164,20 @@ Declaration::GetValue(nsCSSProperty aPro
   // Additionally, if a shorthand property was set using a value with a
   // variable reference and none of its component longhand properties were
   // then overridden on the declaration, we return the token stream
   // assigned to the shorthand.
   const nsCSSValue* tokenStream = nullptr;
   uint32_t totalCount = 0, importantCount = 0,
            initialCount = 0, inheritCount = 0, unsetCount = 0,
            matchingTokenStreamCount = 0, nonMatchingTokenStreamCount = 0;
-  CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(p, aProperty) {
-    if (*p == eCSSProperty__x_system_font ||
-         nsCSSProps::PropHasFlags(*p, CSS_PROPERTY_DIRECTIONAL_SOURCE)) {
-      // The system-font subproperty and the *-source properties don't count.
+  CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(p, aProperty,
+                                       nsCSSProps::eEnabledForAllContent) {
+    if (*p == eCSSProperty__x_system_font) {
+      // The system-font subproperty doesn't count.
       continue;
     }
     ++totalCount;
     const nsCSSValue *val = mData->ValueFor(*p);
     NS_ABORT_IF_FALSE(!val || !mImportantData || !mImportantData->ValueFor(*p),
                       "can't be in both blocks");
     if (!val && mImportantData) {
       ++importantCount;
@@ -344,18 +345,16 @@ Declaration::GetValue(nsCSSProperty aPro
         nsCSSProps::SubpropertyEntryFor(eCSSProperty_border_color),
         nsCSSProps::SubpropertyEntryFor(eCSSProperty_border_style),
         nsCSSProps::SubpropertyEntryFor(eCSSProperty_border_width)
       };
       bool match = true;
       for (const nsCSSProperty** subprops = subproptables,
                **subprops_end = ArrayEnd(subproptables);
            subprops < subprops_end; ++subprops) {
-        // Check only the first four subprops in each table, since the
-        // others are extras for dimensional box properties.
         const nsCSSValue *firstSide = data->ValueFor((*subprops)[0]);
         for (int32_t side = 1; side < 4; ++side) {
           const nsCSSValue *otherSide =
             data->ValueFor((*subprops)[side]);
           if (*firstSide != *otherSide)
             match = false;
         }
       }
@@ -372,62 +371,33 @@ Declaration::GetValue(nsCSSProperty aPro
     case eCSSProperty_border_left:
     case eCSSProperty_border_start:
     case eCSSProperty_border_end:
     case eCSSProperty__moz_column_rule:
     case eCSSProperty_outline: {
       const nsCSSProperty* subprops =
         nsCSSProps::SubpropertyEntryFor(aProperty);
       NS_ABORT_IF_FALSE(StringEndsWith(nsCSSProps::GetStringValue(subprops[2]),
-                                       NS_LITERAL_CSTRING("-color")) ||
-                        StringEndsWith(nsCSSProps::GetStringValue(subprops[2]),
-                                       NS_LITERAL_CSTRING("-color-value")),
+                                       NS_LITERAL_CSTRING("-color")),
                         "third subprop must be the color property");
       const nsCSSValue *colorValue = data->ValueFor(subprops[2]);
       bool isMozUseTextColor =
         colorValue->GetUnit() == eCSSUnit_Enumerated &&
         colorValue->GetIntValue() == NS_STYLE_COLOR_MOZ_USE_TEXT_COLOR;
       if (!AppendValueToString(subprops[0], aValue, aSerialization) ||
           !(aValue.Append(char16_t(' ')),
             AppendValueToString(subprops[1], aValue, aSerialization)) ||
           // Don't output a third value when it's -moz-use-text-color.
           !(isMozUseTextColor ||
             (aValue.Append(char16_t(' ')),
              AppendValueToString(subprops[2], aValue, aSerialization)))) {
         aValue.Truncate();
       }
       break;
     }
-    case eCSSProperty_margin_left:
-    case eCSSProperty_margin_right:
-    case eCSSProperty_margin_start:
-    case eCSSProperty_margin_end:
-    case eCSSProperty_padding_left:
-    case eCSSProperty_padding_right:
-    case eCSSProperty_padding_start:
-    case eCSSProperty_padding_end:
-    case eCSSProperty_border_left_color:
-    case eCSSProperty_border_left_style:
-    case eCSSProperty_border_left_width:
-    case eCSSProperty_border_right_color:
-    case eCSSProperty_border_right_style:
-    case eCSSProperty_border_right_width:
-    case eCSSProperty_border_start_color:
-    case eCSSProperty_border_start_style:
-    case eCSSProperty_border_start_width:
-    case eCSSProperty_border_end_color:
-    case eCSSProperty_border_end_style:
-    case eCSSProperty_border_end_width: {
-      const nsCSSProperty* subprops =
-        nsCSSProps::SubpropertyEntryFor(aProperty);
-      NS_ABORT_IF_FALSE(subprops[3] == eCSSProperty_UNKNOWN,
-                        "not box property with physical vs. logical cascading");
-      AppendValueToString(subprops[0], aValue, aSerialization);
-      break;
-    }
     case eCSSProperty_background: {
       // We know from above that all subproperties were specified.
       // However, we still can't represent that in the shorthand unless
       // they're all lists of the same length.  So if they're different
       // lengths, we need to bail out.
       // We also need to bail out if an item has background-clip and
       // background-origin that are different and not the default
       // values.  (We omit them if they're both default.)
@@ -1149,17 +1119,18 @@ Declaration::GetValueIsImportant(nsCSSPr
     return false;
 
   // Calling ValueFor is inefficient, but we can assume '!important' is rare.
 
   if (!nsCSSProps::IsShorthand(aProperty)) {
     return mImportantData->ValueFor(aProperty) != nullptr;
   }
 
-  CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(p, aProperty) {
+  CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(p, aProperty,
+                                       nsCSSProps::eEnabledForAllContent) {
     if (*p == eCSSProperty__x_system_font) {
       // The system_font subproperty doesn't count.
       continue;
     }
     if (!mImportantData->ValueFor(*p)) {
       return false;
     }
   }
--- a/layout/style/StyleAnimationValue.cpp
+++ b/layout/style/StyleAnimationValue.cpp
@@ -2534,23 +2534,19 @@ StyleAnimationValue::ComputeValue(nsCSSP
                                   StyleAnimationValue& aComputedValue,
                                   bool* aIsContextSensitive)
 {
   NS_ABORT_IF_FALSE(aTargetElement, "null target element");
   NS_ABORT_IF_FALSE(aTargetElement->GetCurrentDoc(),
                     "we should only be able to actively animate nodes that "
                     "are in a document");
 
-  nsCSSProperty propToParse =
-    nsCSSProps::PropHasFlags(aProperty, CSS_PROPERTY_REPORT_OTHER_NAME)
-      ? nsCSSProps::OtherNameFor(aProperty) : aProperty;
-
   // Parse specified value into a temporary css::StyleRule
   nsRefPtr<css::StyleRule> styleRule =
-    BuildStyleRule(propToParse, aTargetElement, aSpecifiedValue, aUseSVGMode);
+    BuildStyleRule(aProperty, aTargetElement, aSpecifiedValue, aUseSVGMode);
   if (!styleRule) {
     return false;
   }
 
   if (nsCSSProps::IsShorthand(aProperty) ||
       nsCSSProps::kAnimTypeTable[aProperty] == eStyleAnimType_None) {
     // Just capture the specified value
     aComputedValue.SetUnparsedStringValue(nsString(aSpecifiedValue));
@@ -2922,36 +2918,36 @@ StyleAnimationValue::ExtractComputedValu
 
         #define BORDER_WIDTH_CASE(prop_, side_)                               \
         case prop_:                                                           \
           aComputedValue.SetCoordValue(                                       \
             static_cast<const nsStyleBorder*>(styleStruct)->                  \
               GetComputedBorder().side_);                                     \
           break;
         BORDER_WIDTH_CASE(eCSSProperty_border_bottom_width, bottom)
-        BORDER_WIDTH_CASE(eCSSProperty_border_left_width_value, left)
-        BORDER_WIDTH_CASE(eCSSProperty_border_right_width_value, right)
+        BORDER_WIDTH_CASE(eCSSProperty_border_left_width, left)
+        BORDER_WIDTH_CASE(eCSSProperty_border_right_width, right)
         BORDER_WIDTH_CASE(eCSSProperty_border_top_width, top)
         #undef BORDER_WIDTH_CASE
 
         case eCSSProperty__moz_column_rule_width:
           aComputedValue.SetCoordValue(
             static_cast<const nsStyleColumn*>(styleStruct)->
               GetComputedColumnRuleWidth());
           break;
 
         case eCSSProperty_border_bottom_color:
           ExtractBorderColor(aStyleContext, styleStruct, NS_SIDE_BOTTOM,
                              aComputedValue);
           break;
-        case eCSSProperty_border_left_color_value:
+        case eCSSProperty_border_left_color:
           ExtractBorderColor(aStyleContext, styleStruct, NS_SIDE_LEFT,
                              aComputedValue);
           break;
-        case eCSSProperty_border_right_color_value:
+        case eCSSProperty_border_right_color:
           ExtractBorderColor(aStyleContext, styleStruct, NS_SIDE_RIGHT,
                              aComputedValue);
           break;
         case eCSSProperty_border_top_color:
           ExtractBorderColor(aStyleContext, styleStruct, NS_SIDE_TOP,
                              aComputedValue);
           break;
 
--- a/layout/style/moz.build
+++ b/layout/style/moz.build
@@ -18,16 +18,17 @@ EXPORTS += [
     'nsCSSFontDescList.h',
     'nsCSSKeywordList.h',
     'nsCSSKeywords.h',
     'nsCSSParser.h',
     'nsCSSPropAliasList.h',
     'nsCSSProperty.h',
     'nsCSSPropertySet.h',
     'nsCSSPropList.h',
+    'nsCSSPropLogicalGroupList.h',
     'nsCSSProps.h',
     'nsCSSPseudoClasses.h',
     'nsCSSPseudoClassList.h',
     'nsCSSPseudoElementList.h',
     'nsCSSPseudoElements.h',
     'nsCSSRuleProcessor.h',
     'nsCSSScanner.h',
     'nsCSSValue.h',
--- a/layout/style/nsCSSDataBlock.cpp
+++ b/layout/style/nsCSSDataBlock.cpp
@@ -11,16 +11,17 @@
 #include "nsCSSDataBlock.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/css/Declaration.h"
 #include "mozilla/css/ImageLoader.h"
 #include "nsRuleData.h"
 #include "nsStyleSet.h"
 #include "nsStyleContext.h"
 #include "nsIDocument.h"
+#include "WritingModes.h"
 
 using namespace mozilla;
 
 /**
  * Does a fast move of aSource to aDest.  The previous value in
  * aDest is cleanly destroyed, and aSource is cleared.  Returns
  * true if, before the copy, the value at aSource compared unequal
  * to the value at aDest; false otherwise.
@@ -158,30 +159,107 @@ MapSinglePropertyInto(nsCSSProperty aPro
             }
         } else {
             // Ignore 'color', 'border-*-color', etc.
             *aTarget = nsCSSValue();
         }
     }
 }
 
+/**
+ * If aProperty is a logical property, converts it to the equivalent physical
+ * property based on writing mode information obtained from aRuleData's
+ * style context.
+ */
+static inline void
+EnsurePhysicalProperty(nsCSSProperty& aProperty, nsRuleData* aRuleData)
+{
+  bool isAxisProperty =
+    nsCSSProps::PropHasFlags(aProperty, CSS_PROPERTY_LOGICAL_AXIS);
+  bool isBlock =
+    nsCSSProps::PropHasFlags(aProperty, CSS_PROPERTY_LOGICAL_BLOCK_AXIS);
+
+  int index;
+
+  if (isAxisProperty) {
+    LogicalAxis logicalAxis = isBlock ? eLogicalAxisBlock : eLogicalAxisInline;
+    uint8_t wm = aRuleData->mStyleContext->StyleVisibility()->mWritingMode;
+    PhysicalAxis axis =
+      WritingMode::PhysicalAxisForLogicalAxis(wm, logicalAxis);
+
+    // We rely on physical axis constants values matching the order of the
+    // physical properties in the logical group array.
+    static_assert(eAxisVertical == 0 && eAxisHorizontal == 1,
+                  "unexpected axis constant values");
+    index = axis;
+  } else {
+    bool isEnd =
+      nsCSSProps::PropHasFlags(aProperty, CSS_PROPERTY_LOGICAL_END_EDGE);
+
+    LogicalEdge edge = isEnd ? eLogicalEdgeEnd : eLogicalEdgeStart;
+
+    // We handle block axis logical properties separately to save a bit of
+    // work that the WritingMode constructor does that is unnecessary
+    // unless we have an inline axis property.
+    mozilla::css::Side side;
+    if (isBlock) {
+      uint8_t wm = aRuleData->mStyleContext->StyleVisibility()->mWritingMode;
+      side = WritingMode::PhysicalSideForBlockAxis(wm, edge);
+    } else {
+      WritingMode wm(aRuleData->mStyleContext);
+      side = wm.PhysicalSideForInlineAxis(edge);
+    }
+
+    // We rely on the physical side constant values matching the order of
+    // the physical properties in the logical group array.
+    static_assert(NS_SIDE_TOP == 0 && NS_SIDE_RIGHT == 1 &&
+                  NS_SIDE_BOTTOM == 2 && NS_SIDE_LEFT == 3,
+                  "unexpected side constant values");
+    index = side;
+  }
+
+  const nsCSSProperty* props = nsCSSProps::LogicalGroup(aProperty);
+#ifdef DEBUG
+  {
+    size_t len = isAxisProperty ? 2 : 4;
+    for (size_t i = 0; i < len; i++) {
+      MOZ_ASSERT(props[i] != eCSSProperty_UNKNOWN,
+                 "unexpected logical group length");
+    }
+    MOZ_ASSERT(props[len] == eCSSProperty_UNKNOWN,
+               "unexpected logical group length");
+  }
+#endif
+  aProperty = props[index];
+}
+
 void
 nsCSSCompressedDataBlock::MapRuleInfoInto(nsRuleData *aRuleData) const
 {
     // If we have no data for these structs, then return immediately.
     // This optimization should make us return most of the time, so we
     // have to worry much less (although still some) about the speed of
     // the rest of the function.
     if (!(aRuleData->mSIDs & mStyleBits))
         return;
 
-    for (uint32_t i = 0; i < mNumProps; i++) {
+    // We process these in reverse order so that we end up mapping the
+    // right property when one can be expressed using both logical and
+    // physical property names.
+    for (uint32_t i = mNumProps; i-- > 0; ) {
         nsCSSProperty iProp = PropertyAtIndex(i);
         if (nsCachedStyleData::GetBitForSID(nsCSSProps::kSIDTable[iProp]) &
             aRuleData->mSIDs) {
+            if (nsCSSProps::PropHasFlags(iProp, CSS_PROPERTY_LOGICAL)) {
+                EnsurePhysicalProperty(iProp, aRuleData);
+                // We can't cache anything on the rule tree if we use any data from
+                // the style context, since data cached in the rule tree could be
+                // used with a style context with a different value.
+                aRuleData->mCanStoreInRuleTree = false;
+            }
             nsCSSValue* target = aRuleData->ValueFor(iProp);
             if (target->GetUnit() == eCSSUnit_Null) {
                 const nsCSSValue *val = ValueAtIndex(i);
                 MapSinglePropertyInto(iProp, val, target, aRuleData);
             }
         }
     }
 }
@@ -504,17 +582,18 @@ nsCSSExpandedDataBlock::Clear()
 
     AssertInitialState();
 }
 
 void
 nsCSSExpandedDataBlock::ClearProperty(nsCSSProperty aPropID)
 {
   if (nsCSSProps::IsShorthand(aPropID)) {
-    CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(p, aPropID) {
+    CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(p, aPropID,
+                                         nsCSSProps::eIgnoreEnabledState) {
       ClearLonghandProperty(*p);
     }
   } else {
     ClearLonghandProperty(aPropID);
   }
 }
 
 void
@@ -525,29 +604,35 @@ nsCSSExpandedDataBlock::ClearLonghandPro
     ClearPropertyBit(aPropID);
     ClearImportantBit(aPropID);
     PropertyAt(aPropID)->Reset();
 }
 
 bool
 nsCSSExpandedDataBlock::TransferFromBlock(nsCSSExpandedDataBlock& aFromBlock,
                                           nsCSSProperty aPropID,
+                                          nsCSSProps::EnabledState aEnabledState,
                                           bool aIsImportant,
                                           bool aOverrideImportant,
                                           bool aMustCallValueAppended,
                                           css::Declaration* aDeclaration)
 {
     if (!nsCSSProps::IsShorthand(aPropID)) {
         return DoTransferFromBlock(aFromBlock, aPropID,
                                    aIsImportant, aOverrideImportant,
                                    aMustCallValueAppended, aDeclaration);
     }
 
+    // We can pass eIgnoreEnabledState (here, and in ClearProperty above) rather
+    // than a value corresponding to whether we're parsing a UA style sheet or
+    // certified app because we assert in nsCSSProps::AddRefTable that shorthand
+    // properties available in these contexts also have all of their
+    // subproperties available in these contexts.
     bool changed = false;
-    CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(p, aPropID) {
+    CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(p, aPropID, aEnabledState) {
         changed |= DoTransferFromBlock(aFromBlock, *p,
                                        aIsImportant, aOverrideImportant,
                                        aMustCallValueAppended, aDeclaration);
     }
     return changed;
 }
 
 bool
@@ -600,21 +685,27 @@ void
 nsCSSExpandedDataBlock::MapRuleInfoInto(nsCSSProperty aPropID,
                                         nsRuleData* aRuleData) const
 {
   MOZ_ASSERT(!nsCSSProps::IsShorthand(aPropID));
 
   const nsCSSValue* src = PropertyAt(aPropID);
   MOZ_ASSERT(src->GetUnit() != eCSSUnit_Null);
 
-  nsCSSValue* dest = aRuleData->ValueFor(aPropID);
+  nsCSSProperty physicalProp = aPropID;
+  if (nsCSSProps::PropHasFlags(aPropID, CSS_PROPERTY_LOGICAL)) {
+    EnsurePhysicalProperty(physicalProp, aRuleData);
+    aRuleData->mCanStoreInRuleTree = false;
+  }
+
+  nsCSSValue* dest = aRuleData->ValueFor(physicalProp);
   MOZ_ASSERT(dest->GetUnit() == eCSSUnit_TokenStream &&
              dest->GetTokenStreamValue()->mPropertyID == aPropID);
 
-  MapSinglePropertyInto(aPropID, src, dest, aRuleData);
+  MapSinglePropertyInto(physicalProp, src, dest, aRuleData);
 }
 
 #ifdef DEBUG
 void
 nsCSSExpandedDataBlock::DoAssertInitialState()
 {
     mPropertiesSet.AssertIsEmpty("not initial state");
     mPropertiesImportant.AssertIsEmpty("not initial state");
--- a/layout/style/nsCSSDataBlock.h
+++ b/layout/style/nsCSSDataBlock.h
@@ -237,28 +237,31 @@ public:
      */
     void ClearLonghandProperty(nsCSSProperty aPropID);
 
     /**
      * Transfer the state for |aPropID| (which may be a shorthand)
      * from |aFromBlock| to this block.  The property being transferred
      * is !important if |aIsImportant| is true, and should replace an
      * existing !important property regardless of its own importance
-     * if |aOverrideImportant| is true.
+     * if |aOverrideImportant| is true.  |aEnabledState| is used to
+     * determine which longhand components of |aPropID| (if it is a
+     * shorthand) to transfer.
      *
      * Returns true if something changed, false otherwise.  Calls
      * |ValueAppended| on |aDeclaration| if the property was not
      * previously set, or in any case if |aMustCallValueAppended| is true.
      */
     bool TransferFromBlock(nsCSSExpandedDataBlock& aFromBlock,
-                             nsCSSProperty aPropID,
-                             bool aIsImportant,
-                             bool aOverrideImportant,
-                             bool aMustCallValueAppended,
-                             mozilla::css::Declaration* aDeclaration);
+                           nsCSSProperty aPropID,
+                           nsCSSProps::EnabledState aEnabledState,
+                           bool aIsImportant,
+                           bool aOverrideImportant,
+                           bool aMustCallValueAppended,
+                           mozilla::css::Declaration* aDeclaration);
 
     /**
      * Copies the values for aPropID into the specified aRuleData object.
      *
      * This is used for copying parsed-at-computed-value-time properties
      * that had variable references.  aPropID must be a longhand property.
      */
     void MapRuleInfoInto(nsCSSProperty aPropID, nsRuleData* aRuleData) const;
--- a/layout/style/nsCSSParser.cpp
+++ b/layout/style/nsCSSParser.cpp
@@ -54,17 +54,19 @@ using namespace mozilla;
 
 typedef nsCSSProps::KTableValue KTableValue;
 
 const uint32_t
 nsCSSProps::kParserVariantTable[eCSSProperty_COUNT_no_shorthands] = {
 #define CSS_PROP(name_, id_, method_, flags_, pref_, parsevariant_, kwtable_, \
                  stylestruct_, stylestructoffset_, animtype_)                 \
   parsevariant_,
+#define CSS_PROP_LIST_INCLUDE_LOGICAL
 #include "nsCSSPropList.h"
+#undef CSS_PROP_LIST_INCLUDE_LOGICAL
 #undef CSS_PROP
 };
 
 // Maximum number of repetitions for the repeat() function
 // in the grid-template-columns and grid-template-rows properties,
 // to limit high memory usage from small stylesheets.
 // Must be a positive integer. Should be large-ish.
 #define GRID_TEMPLATE_MAX_REPETITIONS 10000
@@ -295,28 +297,32 @@ public:
                                            nsRuleData* aRuleData,
                                            nsIURI* aDocURL,
                                            nsIURI* aBaseURL,
                                            nsIPrincipal* aDocPrincipal,
                                            CSSStyleSheet* aSheet,
                                            uint32_t aLineNumber,
                                            uint32_t aLineOffset);
 
-  nsCSSProperty LookupEnabledProperty(const nsAString& aProperty) {
+  nsCSSProps::EnabledState PropertyEnabledState() const {
     static_assert(nsCSSProps::eEnabledForAllContent == 0,
                   "nsCSSProps::eEnabledForAllContent should be zero for "
                   "this bitfield to work");
     nsCSSProps::EnabledState enabledState = nsCSSProps::eEnabledForAllContent;
     if (mUnsafeRulesEnabled) {
       enabledState |= nsCSSProps::eEnabledInUASheets;
     }
     if (mIsChromeOrCertifiedApp) {
       enabledState |= nsCSSProps::eEnabledInChromeOrCertifiedApp;
     }
-    return nsCSSProps::LookupProperty(aProperty, enabledState);
+    return enabledState;
+  }
+
+  nsCSSProperty LookupEnabledProperty(const nsAString& aProperty) {
+    return nsCSSProps::LookupProperty(aProperty, PropertyEnabledState());
   }
 
 protected:
   class nsAutoParseCompoundProperty;
   friend class nsAutoParseCompoundProperty;
 
   class nsAutoFailingSupportsRule;
   friend class nsAutoFailingSupportsRule;
@@ -623,18 +629,16 @@ protected:
     ePriority_Error
   };
   PriorityParsingStatus ParsePriority();
 
 #ifdef MOZ_XUL
   bool ParseTreePseudoElement(nsAtomList **aPseudoElementArgs);
 #endif
 
-  void InitBoxPropsAsPhysical(const nsCSSProperty *aSourceProperties);
-
   // Property specific parsing routines
   bool ParseBackground();
 
   struct BackgroundParseState {
     nsCSSValue&  mColor;
     nsCSSValueList* mImage;
     nsCSSValuePairList* mRepeat;
     nsCSSValueList* mAttachment;
@@ -681,18 +685,16 @@ protected:
   // aConsumedTokens is always true.
   bool ParseBorderImageSlice(bool aAcceptsInherit, bool* aConsumedTokens);
   bool ParseBorderImageWidth(bool aAcceptsInherit);
   bool ParseBorderImageOutset(bool aAcceptsInherit);
   bool ParseBorderImage();
   bool ParseBorderSpacing();
   bool ParseBorderSide(const nsCSSProperty aPropIDs[],
                          bool aSetAllSides);
-  bool ParseDirectionalBorderSide(const nsCSSProperty aPropIDs[],
-                                    int32_t aSourceType);
   bool ParseBorderStyle();
   bool ParseBorderWidth();
 
   bool ParseCalc(nsCSSValue &aValue, int32_t aVariantMask);
   bool ParseCalcAdditiveExpression(nsCSSValue& aValue,
                                      int32_t& aVariantMask);
   bool ParseCalcMultiplicativeExpression(nsCSSValue& aValue,
                                            int32_t& aVariantMask,
@@ -882,18 +884,16 @@ protected:
    */
   void AppendImpliedEOFCharacters(nsAString& aResult);
 
   // Reused utility parsing routines
   void AppendValue(nsCSSProperty aPropID, const nsCSSValue& aValue);
   bool ParseBoxProperties(const nsCSSProperty aPropIDs[]);
   bool ParseGroupedBoxProperty(int32_t aVariantMask,
                                nsCSSValue& aValue);
-  bool ParseDirectionalBoxProperty(nsCSSProperty aProperty,
-                                     int32_t aSourceType);
   bool ParseBoxCornerRadius(const nsCSSProperty aPropID);
   bool ParseBoxCornerRadiiInternals(nsCSSValue array[]);
   bool ParseBoxCornerRadii(const nsCSSProperty aPropIDs[]);
 
   int32_t ParseChoice(nsCSSValue aValues[],
                       const nsCSSProperty aPropIDs[], int32_t aNumIDs);
   bool ParseColor(nsCSSValue& aValue);
   bool ParseNumberColorComponent(uint8_t& aComponent, char aStop);
@@ -1530,17 +1530,18 @@ CSSParserImpl::ParseProperty(const nsCSS
     // already a value for this property in the declaration at the
     // same importance level, then we can just copy our parsed value
     // directly into the declaration without going through the whole
     // expand/compress thing.
     if (!aDeclaration->TryReplaceValue(aPropID, aIsImportant, mTempData,
                                        aChanged)) {
       // Do it the slow way
       aDeclaration->ExpandTo(&mData);
-      *aChanged = mData.TransferFromBlock(mTempData, aPropID, aIsImportant,
+      *aChanged = mData.TransferFromBlock(mTempData, aPropID,
+                                          PropertyEnabledState(), aIsImportant,
                                           true, false, aDeclaration);
       aDeclaration->CompressFrom(&mData);
     }
     CLEAR_ERROR();
   }
 
   mTempData.AssertInitialState();
 
@@ -6593,66 +6594,65 @@ CSSParserImpl::ParseDeclaration(css::Dec
     MOZ_ASSERT(Substring(propertyName, 0,
                          CSS_CUSTOM_NAME_PREFIX_LENGTH).EqualsLiteral("--"));
     // remove '--'
     nsDependentString varName(propertyName, CSS_CUSTOM_NAME_PREFIX_LENGTH);
     aDeclaration->AddVariableDeclaration(varName, variableType, variableValue,
                                          status == ePriority_Important, false);
   } else {
     *aChanged |= mData.TransferFromBlock(mTempData, propID,
+                                         PropertyEnabledState(),
                                          status == ePriority_Important,
                                          false, aMustCallValueAppended,
                                          aDeclaration);
   }
 
   return true;
 }
 
 static const nsCSSProperty kBorderTopIDs[] = {
   eCSSProperty_border_top_width,
   eCSSProperty_border_top_style,
   eCSSProperty_border_top_color
 };
 static const nsCSSProperty kBorderRightIDs[] = {
-  eCSSProperty_border_right_width_value,
-  eCSSProperty_border_right_style_value,
-  eCSSProperty_border_right_color_value,
   eCSSProperty_border_right_width,
   eCSSProperty_border_right_style,
   eCSSProperty_border_right_color
 };
 static const nsCSSProperty kBorderBottomIDs[] = {
   eCSSProperty_border_bottom_width,
   eCSSProperty_border_bottom_style,
   eCSSProperty_border_bottom_color
 };
 static const nsCSSProperty kBorderLeftIDs[] = {
-  eCSSProperty_border_left_width_value,
-  eCSSProperty_border_left_style_value,
-  eCSSProperty_border_left_color_value,
   eCSSProperty_border_left_width,
   eCSSProperty_border_left_style,
   eCSSProperty_border_left_color
 };
 static const nsCSSProperty kBorderStartIDs[] = {
-  eCSSProperty_border_start_width_value,
-  eCSSProperty_border_start_style_value,
-  eCSSProperty_border_start_color_value,
   eCSSProperty_border_start_width,
   eCSSProperty_border_start_style,
   eCSSProperty_border_start_color
 };
 static const nsCSSProperty kBorderEndIDs[] = {
-  eCSSProperty_border_end_width_value,
-  eCSSProperty_border_end_style_value,
-  eCSSProperty_border_end_color_value,
   eCSSProperty_border_end_width,
   eCSSProperty_border_end_style,
   eCSSProperty_border_end_color
 };
+static const nsCSSProperty kBorderBlockStartIDs[] = {
+  eCSSProperty_border_block_start_width,
+  eCSSProperty_border_block_start_style,
+  eCSSProperty_border_block_start_color
+};
+static const nsCSSProperty kBorderBlockEndIDs[] = {
+  eCSSProperty_border_block_end_width,
+  eCSSProperty_border_block_end_style,
+  eCSSProperty_border_block_end_color
+};
 static const nsCSSProperty kColumnRuleIDs[] = {
   eCSSProperty__moz_column_rule_width,
   eCSSProperty__moz_column_rule_style,
   eCSSProperty__moz_column_rule_color
 };
 
 bool
 CSSParserImpl::ParseEnum(nsCSSValue& aValue,
@@ -9317,35 +9317,16 @@ CSSParserImpl::ParseGroupedBoxProperty(i
     case 3: // Make left == right
       result.mLeft = result.mRight;
   }
 
   return true;
 }
 
 bool
-CSSParserImpl::ParseDirectionalBoxProperty(nsCSSProperty aProperty,
-                                           int32_t aSourceType)
-{
-  const nsCSSProperty* subprops = nsCSSProps::SubpropertyEntryFor(aProperty);
-  NS_ASSERTION(subprops[3] == eCSSProperty_UNKNOWN,
-               "not box property with physical vs. logical cascading");
-  nsCSSValue value;
-  if (!ParseSingleValueProperty(value, subprops[0])) {
-    return false;
-  }
-
-  AppendValue(subprops[0], value);
-  nsCSSValue typeVal(aSourceType, eCSSUnit_Enumerated);
-  AppendValue(subprops[1], typeVal);
-  AppendValue(subprops[2], typeVal);
-  return true;
-}
-
-bool
 CSSParserImpl::ParseBoxCornerRadius(nsCSSProperty aPropID)
 {
   nsCSSValue dimenX, dimenY;
   // required first value
   if (! ParseNonNegativeVariant(dimenX, VARIANT_HLP | VARIANT_CALC, nullptr))
     return false;
 
   // optional second value (forbidden if first value is inherit/initial/unset)
@@ -9451,31 +9432,31 @@ CSSParserImpl::ParseBoxCornerRadii(const
     AppendValue(aPropIDs[side], value[side]);
   }
   return true;
 }
 
 // These must be in CSS order (top,right,bottom,left) for indexing to work
 static const nsCSSProperty kBorderStyleIDs[] = {
   eCSSProperty_border_top_style,
-  eCSSProperty_border_right_style_value,
+  eCSSProperty_border_right_style,
   eCSSProperty_border_bottom_style,
-  eCSSProperty_border_left_style_value
+  eCSSProperty_border_left_style
 };
 static const nsCSSProperty kBorderWidthIDs[] = {
   eCSSProperty_border_top_width,
-  eCSSProperty_border_right_width_value,
+  eCSSProperty_border_right_width,
   eCSSProperty_border_bottom_width,
-  eCSSProperty_border_left_width_value
+  eCSSProperty_border_left_width
 };
 static const nsCSSProperty kBorderColorIDs[] = {
   eCSSProperty_border_top_color,
-  eCSSProperty_border_right_color_value,
+  eCSSProperty_border_right_color,
   eCSSProperty_border_bottom_color,
-  eCSSProperty_border_left_color_value
+  eCSSProperty_border_left_color
 };
 static const nsCSSProperty kBorderRadiusIDs[] = {
   eCSSProperty_border_top_left_radius,
   eCSSProperty_border_top_right_radius,
   eCSSProperty_border_bottom_right_radius,
   eCSSProperty_border_bottom_left_radius
 };
 static const nsCSSProperty kOutlineRadiusIDs[] = {
@@ -9664,17 +9645,18 @@ CSSParserImpl::ParseProperty(nsCSSProper
           propertyValue.Truncate(propertyValue.Length() - 1);
         }
       }
 
       if (!mInSupportsCondition) {
         if (nsCSSProps::IsShorthand(aPropID)) {
           // If this is a shorthand property, we store the token stream on each
           // of its corresponding longhand properties.
-          CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(p, aPropID) {
+          CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(p, aPropID,
+                                               PropertyEnabledState()) {
             nsCSSValueTokenStream* tokenStream = new nsCSSValueTokenStream;
             tokenStream->mPropertyID = *p;
             tokenStream->mShorthandPropertyID = aPropID;
             tokenStream->mTokenStream = propertyValue;
             tokenStream->mBaseURI = mBaseURI;
             tokenStream->mSheetURI = mSheetURI;
             tokenStream->mSheetPrincipal = mSheetPrincipal;
             tokenStream->mSheet = mSheet;
@@ -9728,30 +9710,30 @@ CSSParserImpl::ParsePropertyByFunction(n
   case eCSSProperty_border:
     return ParseBorderSide(kBorderTopIDs, true);
   case eCSSProperty_border_color:
     return ParseBorderColor();
   case eCSSProperty_border_spacing:
     return ParseBorderSpacing();
   case eCSSProperty_border_style:
     return ParseBorderStyle();
+  case eCSSProperty_border_block_end:
+    return ParseBorderSide(kBorderBlockEndIDs, false);
+  case eCSSProperty_border_block_start:
+    return ParseBorderSide(kBorderBlockStartIDs, false);
   case eCSSProperty_border_bottom:
     return ParseBorderSide(kBorderBottomIDs, false);
   case eCSSProperty_border_end:
-    return ParseDirectionalBorderSide(kBorderEndIDs,
-                                      NS_BOXPROP_SOURCE_LOGICAL);
+    return ParseBorderSide(kBorderEndIDs, false);
+  case eCSSProperty_border_start:
+    return ParseBorderSide(kBorderStartIDs, false);
   case eCSSProperty_border_left:
-    return ParseDirectionalBorderSide(kBorderLeftIDs,
-                                      NS_BOXPROP_SOURCE_PHYSICAL);
+    return ParseBorderSide(kBorderLeftIDs, false);
   case eCSSProperty_border_right:
-    return ParseDirectionalBorderSide(kBorderRightIDs,
-                                      NS_BOXPROP_SOURCE_PHYSICAL);
-  case eCSSProperty_border_start:
-    return ParseDirectionalBorderSide(kBorderStartIDs,
-                                      NS_BOXPROP_SOURCE_LOGICAL);
+    return ParseBorderSide(kBorderRightIDs, false);
   case eCSSProperty_border_top:
     return ParseBorderSide(kBorderTopIDs, false);
   case eCSSProperty_border_bottom_colors:
   case eCSSProperty_border_left_colors:
   case eCSSProperty_border_right_colors:
   case eCSSProperty_border_top_colors:
     return ParseBorderColors(aPropID);
   case eCSSProperty_border_image_slice:
@@ -9761,52 +9743,16 @@ CSSParserImpl::ParsePropertyByFunction(n
   case eCSSProperty_border_image_outset:
     return ParseBorderImageOutset(true);
   case eCSSProperty_border_image_repeat:
     return ParseBorderImageRepeat(true);
   case eCSSProperty_border_image:
     return ParseBorderImage();
   case eCSSProperty_border_width:
     return ParseBorderWidth();
-  case eCSSProperty_border_end_color:
-    return ParseDirectionalBoxProperty(eCSSProperty_border_end_color,
-                                       NS_BOXPROP_SOURCE_LOGICAL);
-  case eCSSProperty_border_left_color:
-    return ParseDirectionalBoxProperty(eCSSProperty_border_left_color,
-                                       NS_BOXPROP_SOURCE_PHYSICAL);
-  case eCSSProperty_border_right_color:
-    return ParseDirectionalBoxProperty(eCSSProperty_border_right_color,
-                                       NS_BOXPROP_SOURCE_PHYSICAL);
-  case eCSSProperty_border_start_color:
-    return ParseDirectionalBoxProperty(eCSSProperty_border_start_color,
-                                       NS_BOXPROP_SOURCE_LOGICAL);
-  case eCSSProperty_border_end_width:
-    return ParseDirectionalBoxProperty(eCSSProperty_border_end_width,
-                                       NS_BOXPROP_SOURCE_LOGICAL);
-  case eCSSProperty_border_left_width:
-    return ParseDirectionalBoxProperty(eCSSProperty_border_left_width,
-                                       NS_BOXPROP_SOURCE_PHYSICAL);
-  case eCSSProperty_border_right_width:
-    return ParseDirectionalBoxProperty(eCSSProperty_border_right_width,
-                                       NS_BOXPROP_SOURCE_PHYSICAL);
-  case eCSSProperty_border_start_width:
-    return ParseDirectionalBoxProperty(eCSSProperty_border_start_width,
-                                       NS_BOXPROP_SOURCE_LOGICAL);
-  case eCSSProperty_border_end_style:
-    return ParseDirectionalBoxProperty(eCSSProperty_border_end_style,
-                                       NS_BOXPROP_SOURCE_LOGICAL);
-  case eCSSProperty_border_left_style:
-    return ParseDirectionalBoxProperty(eCSSProperty_border_left_style,
-                                       NS_BOXPROP_SOURCE_PHYSICAL);
-  case eCSSProperty_border_right_style:
-    return ParseDirectionalBoxProperty(eCSSProperty_border_right_style,
-                                       NS_BOXPROP_SOURCE_PHYSICAL);
-  case eCSSProperty_border_start_style:
-    return ParseDirectionalBoxProperty(eCSSProperty_border_start_style,
-                                       NS_BOXPROP_SOURCE_LOGICAL);
   case eCSSProperty_border_radius:
     return ParseBoxCornerRadii(kBorderRadiusIDs);
   case eCSSProperty__moz_outline_radius:
     return ParseBoxCornerRadii(kOutlineRadiusIDs);
 
   case eCSSProperty_border_top_left_radius:
   case eCSSProperty_border_top_right_radius:
   case eCSSProperty_border_bottom_right_radius:
@@ -9872,48 +9818,24 @@ CSSParserImpl::ParsePropertyByFunction(n
   case eCSSProperty_grid_area:
     return ParseGridArea();
   case eCSSProperty_image_region:
     return ParseRect(eCSSProperty_image_region);
   case eCSSProperty_list_style:
     return ParseListStyle();
   case eCSSProperty_margin:
     return ParseMargin();
-  case eCSSProperty_margin_end:
-    return ParseDirectionalBoxProperty(eCSSProperty_margin_end,
-                                       NS_BOXPROP_SOURCE_LOGICAL);
-  case eCSSProperty_margin_left:
-    return ParseDirectionalBoxProperty(eCSSProperty_margin_left,
-                                       NS_BOXPROP_SOURCE_PHYSICAL);
-  case eCSSProperty_margin_right:
-    return ParseDirectionalBoxProperty(eCSSProperty_margin_right,
-                                       NS_BOXPROP_SOURCE_PHYSICAL);
-  case eCSSProperty_margin_start:
-    return ParseDirectionalBoxProperty(eCSSProperty_margin_start,
-                                       NS_BOXPROP_SOURCE_LOGICAL);
   case eCSSProperty_object_position:
     return ParseObjectPosition();
   case eCSSProperty_outline:
     return ParseOutline();
   case eCSSProperty_overflow:
     return ParseOverflow();
   case eCSSProperty_padding:
     return ParsePadding();
-  case eCSSProperty_padding_end:
-    return ParseDirectionalBoxProperty(eCSSProperty_padding_end,
-                                       NS_BOXPROP_SOURCE_LOGICAL);
-  case eCSSProperty_padding_left:
-    return ParseDirectionalBoxProperty(eCSSProperty_padding_left,
-                                       NS_BOXPROP_SOURCE_PHYSICAL);
-  case eCSSProperty_padding_right:
-    return ParseDirectionalBoxProperty(eCSSProperty_padding_right,
-                                       NS_BOXPROP_SOURCE_PHYSICAL);
-  case eCSSProperty_padding_start:
-    return ParseDirectionalBoxProperty(eCSSProperty_padding_start,
-                                       NS_BOXPROP_SOURCE_LOGICAL);
   case eCSSProperty_quotes:
     return ParseQuotes();
   case eCSSProperty_size:
     return ParseSize();
   case eCSSProperty_text_decoration:
     return ParseTextDecoration();
   case eCSSProperty_will_change:
     return ParseWillChange();
@@ -10113,26 +10035,16 @@ CSSParserImpl::ParseFontDescriptorValue(
   case eCSSFontDesc_COUNT:
     NS_NOTREACHED("bad nsCSSFontDesc code");
   }
   // explicitly do NOT have a default case to let the compiler
   // help find missing descriptors
   return false;
 }
 
-void
-CSSParserImpl::InitBoxPropsAsPhysical(const nsCSSProperty *aSourceProperties)
-{
-  nsCSSValue physical(NS_BOXPROP_SOURCE_PHYSICAL, eCSSUnit_Enumerated);
-  for (const nsCSSProperty *prop = aSourceProperties;
-       *prop != eCSSProperty_UNKNOWN; ++prop) {
-    AppendValue(*prop, physical);
-  }
-}
-
 static nsCSSValue
 BoxPositionMaskToCSSValue(int32_t aMask, bool isX)
 {
   int32_t val = NS_STYLE_BG_POSITION_CENTER;
   if (isX) {
     if (aMask & BG_LEFT) {
       val = NS_STYLE_BG_POSITION_LEFT;
     }
@@ -10865,26 +10777,16 @@ bool CSSParserImpl::ParseBackgroundSizeV
   yValue.Reset();
   return true;
 }
 #undef BG_SIZE_VARIANT
 
 bool
 CSSParserImpl::ParseBorderColor()
 {
-  static const nsCSSProperty kBorderColorSources[] = {
-    eCSSProperty_border_left_color_ltr_source,
-    eCSSProperty_border_left_color_rtl_source,
-    eCSSProperty_border_right_color_ltr_source,
-    eCSSProperty_border_right_color_rtl_source,
-    eCSSProperty_UNKNOWN
-  };
-
-  // do this now, in case 4 values weren't specified
-  InitBoxPropsAsPhysical(kBorderColorSources);
   return ParseBoxProperties(kBorderColorIDs);
 }
 
 void
 CSSParserImpl::SetBorderImageInitialValues()
 {
   // border-image-source: none
   nsCSSValue source;
@@ -11181,34 +11083,16 @@ CSSParserImpl::ParseBorderSide(const nsC
   if ((found & 2) == 0) { // Provide default border-style
     values[1].SetIntValue(NS_STYLE_BORDER_STYLE_NONE, eCSSUnit_Enumerated);
   }
   if ((found & 4) == 0) { // text color will be used
     values[2].SetIntValue(NS_STYLE_COLOR_MOZ_USE_TEXT_COLOR, eCSSUnit_Enumerated);
   }
 
   if (aSetAllSides) {
-    static const nsCSSProperty kBorderSources[] = {
-      eCSSProperty_border_left_color_ltr_source,
-      eCSSProperty_border_left_color_rtl_source,
-      eCSSProperty_border_right_color_ltr_source,
-      eCSSProperty_border_right_color_rtl_source,
-      eCSSProperty_border_left_style_ltr_source,
-      eCSSProperty_border_left_style_rtl_source,
-      eCSSProperty_border_right_style_ltr_source,
-      eCSSProperty_border_right_style_rtl_source,
-      eCSSProperty_border_left_width_ltr_source,
-      eCSSProperty_border_left_width_rtl_source,
-      eCSSProperty_border_right_width_ltr_source,
-      eCSSProperty_border_right_width_rtl_source,
-      eCSSProperty_UNKNOWN
-    };
-
-    InitBoxPropsAsPhysical(kBorderSources);
-
     // Parsing "border" shorthand; set all four sides to the same thing
     for (int32_t index = 0; index < 4; index++) {
       NS_ASSERTION(numProps == 3, "This code needs updating");
       AppendValue(kBorderWidthIDs[index], values[0]);
       AppendValue(kBorderStyleIDs[index], values[1]);
       AppendValue(kBorderColorIDs[index], values[2]);
     }
 
@@ -11248,78 +11132,24 @@ CSSParserImpl::ParseBorderSide(const nsC
     for (int32_t index = 0; index < numProps; index++) {
       AppendValue(aPropIDs[index], values[index]);
     }
   }
   return true;
 }
 
 bool
-CSSParserImpl::ParseDirectionalBorderSide(const nsCSSProperty aPropIDs[],
-                                          int32_t aSourceType)
-{
-  const int32_t numProps = 3;
-  nsCSSValue  values[numProps];
-
-  int32_t found = ParseChoice(values, aPropIDs, numProps);
-  if (found < 1) {
-    return false;
-  }
-
-  if ((found & 1) == 0) { // Provide default border-width
-    values[0].SetIntValue(NS_STYLE_BORDER_WIDTH_MEDIUM, eCSSUnit_Enumerated);
-  }
-  if ((found & 2) == 0) { // Provide default border-style
-    values[1].SetIntValue(NS_STYLE_BORDER_STYLE_NONE, eCSSUnit_Enumerated);
-  }
-  if ((found & 4) == 0) { // text color will be used
-    values[2].SetIntValue(NS_STYLE_COLOR_MOZ_USE_TEXT_COLOR, eCSSUnit_Enumerated);
-  }
-  for (int32_t index = 0; index < numProps; index++) {
-    const nsCSSProperty* subprops =
-      nsCSSProps::SubpropertyEntryFor(aPropIDs[index + numProps]);
-    NS_ASSERTION(subprops[3] == eCSSProperty_UNKNOWN,
-                 "not box property with physical vs. logical cascading");
-    AppendValue(subprops[0], values[index]);
-    nsCSSValue typeVal(aSourceType, eCSSUnit_Enumerated);
-    AppendValue(subprops[1], typeVal);
-    AppendValue(subprops[2], typeVal);
-  }
-  return true;
-}
-
-bool
 CSSParserImpl::ParseBorderStyle()
 {
-  static const nsCSSProperty kBorderStyleSources[] = {
-    eCSSProperty_border_left_style_ltr_source,
-    eCSSProperty_border_left_style_rtl_source,
-    eCSSProperty_border_right_style_ltr_source,
-    eCSSProperty_border_right_style_rtl_source,
-    eCSSProperty_UNKNOWN
-  };
-
-  // do this now, in case 4 values weren't specified
-  InitBoxPropsAsPhysical(kBorderStyleSources);
   return ParseBoxProperties(kBorderStyleIDs);
 }
 
 bool
 CSSParserImpl::ParseBorderWidth()
 {
-  static const nsCSSProperty kBorderWidthSources[] = {
-    eCSSProperty_border_left_width_ltr_source,
-    eCSSProperty_border_left_width_rtl_source,
-    eCSSProperty_border_right_width_ltr_source,
-    eCSSProperty_border_right_width_rtl_source,
-    eCSSProperty_UNKNOWN
-  };
-
-  // do this now, in case 4 values weren't specified
-  InitBoxPropsAsPhysical(kBorderWidthSources);
   return ParseBoxProperties(kBorderWidthIDs);
 }
 
 bool
 CSSParserImpl::ParseBorderColors(nsCSSProperty aProperty)
 {
   nsCSSValue value;
   // 'inherit', 'initial', 'unset' and 'none' are only allowed on their own
@@ -12952,30 +12782,21 @@ CSSParserImpl::ParseListStyleType(nsCSSV
   return false;
 }
 
 bool
 CSSParserImpl::ParseMargin()
 {
   static const nsCSSProperty kMarginSideIDs[] = {
     eCSSProperty_margin_top,
-    eCSSProperty_margin_right_value,
+    eCSSProperty_margin_right,
     eCSSProperty_margin_bottom,
-    eCSSProperty_margin_left_value
+    eCSSProperty_margin_left
   };
-  static const nsCSSProperty kMarginSources[] = {
-    eCSSProperty_margin_left_ltr_source,
-    eCSSProperty_margin_left_rtl_source,
-    eCSSProperty_margin_right_ltr_source,
-    eCSSProperty_margin_right_rtl_source,
-    eCSSProperty_UNKNOWN
-  };
-
-  // do this now, in case 4 values weren't specified
-  InitBoxPropsAsPhysical(kMarginSources);
+
   return ParseBoxProperties(kMarginSideIDs);
 }
 
 bool
 CSSParserImpl::ParseMarks(nsCSSValue& aValue)
 {
   if (ParseVariant(aValue, VARIANT_HK, nsCSSProps::kPageMarksKTable)) {
     if (eCSSUnit_Enumerated == aValue.GetUnit()) {
@@ -13070,30 +12891,21 @@ CSSParserImpl::ParseOverflow()
   return true;
 }
 
 bool
 CSSParserImpl::ParsePadding()
 {
   static const nsCSSProperty kPaddingSideIDs[] = {
     eCSSProperty_padding_top,
-    eCSSProperty_padding_right_value,
+    eCSSProperty_padding_right,
     eCSSProperty_padding_bottom,
-    eCSSProperty_padding_left_value
+    eCSSProperty_padding_left
   };
-  static const nsCSSProperty kPaddingSources[] = {
-    eCSSProperty_padding_left_ltr_source,
-    eCSSProperty_padding_left_rtl_source,
-    eCSSProperty_padding_right_ltr_source,
-    eCSSProperty_padding_right_rtl_source,
-    eCSSProperty_UNKNOWN
-  };
-
-  // do this now, in case 4 values weren't specified
-  InitBoxPropsAsPhysical(kPaddingSources);
+
   return ParseBoxProperties(kPaddingSideIDs);
 }
 
 bool
 CSSParserImpl::ParseQuotes()
 {
   nsCSSValue value;
   if (!ParseVariant(value, VARIANT_HOS, nullptr)) {
@@ -14933,17 +14745,21 @@ CSSParserImpl::AppendImpliedEOFCharacter
 bool
 CSSParserImpl::ParseAll()
 {
   nsCSSValue value;
   if (!ParseVariant(value, VARIANT_INHERIT, nullptr)) {
     return false;
   }
 
-  CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(p, eCSSProperty_all) {
+  // It's unlikely we'll want to use 'all' from within a UA style sheet, so
+  // instead of computing the correct EnabledState value we just expand out
+  // to all content-visible properties.
+  CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(p, eCSSProperty_all,
+                                       nsCSSProps::eEnabledForAllContent) {
     AppendValue(*p, value);
   }
   return true;
 }
 
 bool
 CSSParserImpl::ParseVariableDeclaration(CSSVariableDeclarations::Type* aType,
                                         nsString& aValue)
--- a/layout/style/nsCSSPropAliasList.h
+++ b/layout/style/nsCSSPropAliasList.h
@@ -134,8 +134,56 @@ CSS_PROP_ALIAS(-moz-text-decoration-colo
 CSS_PROP_ALIAS(-moz-text-decoration-line,
                text_decoration_line,
                MozTextDecorationLine,
                "")
 CSS_PROP_ALIAS(-moz-text-decoration-style,
                text_decoration_style,
                MozTextDecorationStyle,
                "")
+CSS_PROP_ALIAS(padding-inline-end,
+               padding_end,
+               PaddingInlineEnd,
+               "layout.css.vertical-text.enabled")
+CSS_PROP_ALIAS(padding-inline-start,
+               padding_start,
+               PaddingInlineStart,
+               "layout.css.vertical-text.enabled")
+CSS_PROP_ALIAS(margin-inline-end,
+               margin_end,
+               MarginInlineEnd,
+               "layout.css.vertical-text.enabled")
+CSS_PROP_ALIAS(margin-inline-start,
+               margin_start,
+               MarginInlineStart,
+               "layout.css.vertical-text.enabled")
+CSS_PROP_ALIAS(border-inline-end,
+               border_end,
+               BorderInlineEnd,
+               "layout.css.vertical-text.enabled")
+CSS_PROP_ALIAS(border-inline-end-color,
+               border_end_color,
+               BorderInlineEndColor,
+               "layout.css.vertical-text.enabled")
+CSS_PROP_ALIAS(border-inline-end-style,
+               border_end_style,
+               BorderInlineEndStyle,
+               "layout.css.vertical-text.enabled")
+CSS_PROP_ALIAS(border-inline-end-width,
+               border_end_width,
+               BorderInlineEndWidth,
+               "layout.css.vertical-text.enabled")
+CSS_PROP_ALIAS(border-inline-start,
+               border_start,
+               BorderInlineStart,
+               "layout.css.vertical-text.enabled")
+CSS_PROP_ALIAS(border-inline-start-color,
+               border_start_color,
+               BorderInlineStartColor,
+               "layout.css.vertical-text.enabled")
+CSS_PROP_ALIAS(border-inline-start-style,
+               border_start_style,
+               BorderInlineStartStyle,
+               "layout.css.vertical-text.enabled")
+CSS_PROP_ALIAS(border-inline-start-width,
+               border_start_width,
+               BorderInlineStartWidth,
+               "layout.css.vertical-text.enabled")
--- a/layout/style/nsCSSPropList.h
+++ b/layout/style/nsCSSPropList.h
@@ -12,17 +12,17 @@
 
   This file contains the list of all parsed CSS properties.  It is
   designed to be used as inline input through the magic of C
   preprocessing.  All entries must be enclosed in the appropriate
   CSS_PROP_* macro which will have cruel and unusual things done to it.
   It is recommended (but not strictly necessary) to keep all entries in
   alphabetical order.
 
-  The arguments to CSS_PROP and CSS_PROP_* are:
+  The arguments to CSS_PROP, CSS_PROP_LOGICAL and CSS_PROP_* are:
 
   -. 'name' entries represent a CSS property name and *must* use only
   lowercase characters.
 
   -. 'id' should be the same as 'name' except that all hyphens ('-')
   in 'name' are converted to underscores ('_') in 'id'. For properties
   on a standards track, any '-moz-' prefix is removed in 'id'. This
   lets us do nice things with the macros without having to copy/convert
@@ -46,30 +46,41 @@
   or if the boolean property whose name is 'pref' is set to true.
 
   -. 'parsevariant', to be passed to ParseVariant in the parser.
 
   -. 'kwtable', which is either nullptr or the name of the appropriate
   keyword table member of class nsCSSProps, for use in
   nsCSSProps::LookupPropertyValue.
 
-  -. 'stylestruct_' [used only for CSS_PROP, not CSS_PROP_*] gives the
-  name of the style struct.  Can be used to make nsStyle##stylestruct_
-  and eStyleStruct_##stylestruct_
+  -. 'group_' [used only for CSS_PROP_LOGICAL] is the name of
+  the logical property group that contains the physical properties
+  that can be set by this logical property.  The name must be one
+  from nsCSSPropLogicalGroupList.h.  For example, this would be
+  'BorderColor' for 'border-block-start-color'.
+
+  -. 'stylestruct_' [used only for CSS_PROP and CSS_PROP_LOGICAL, not
+  CSS_PROP_*] gives the name of the style struct.  Can be used to make
+  nsStyle##stylestruct_ and eStyleStruct_##stylestruct_
 
   -. 'stylestructoffset_' [not used for CSS_PROP_BACKENDONLY] gives the
   result of offsetof(nsStyle*, member).  Ignored (and generally
   CSS_PROP_NO_OFFSET, or -1) for properties whose animtype_ is
   eStyleAnimType_None.
 
   -. 'animtype_' [not used for CSS_PROP_BACKENDONLY] gives the
   animation type (see nsStyleAnimType) of this property.
 
   CSS_PROP_SHORTHAND only takes 1-5.
 
+  CSS_PROP_LOGICAL should be used instead of CSS_PROP_struct when
+  defining logical properties (which also must be defined with the
+  CSS_PROPERTY_LOGICAL flag).  Logical shorthand properties should still
+  be defined with CSS_PROP_SHORTHAND.
+
  ******/
 
 
 /*************************************************************************/
 
 
 // All includers must explicitly define CSS_PROP_SHORTHAND if they
 // want it.
@@ -82,16 +93,36 @@
   CSS_PROP_PUBLIC_OR_PRIVATE(Moz ## name_, name_)
 
 #define CSS_PROP_NO_OFFSET (-1)
 
 // Callers may define CSS_PROP_LIST_EXCLUDE_INTERNAL if they want to
 // exclude internal properties that are not represented in the DOM (only
 // the DOM style code defines this).
 
+// When capturing all properties by defining CSS_PROP, callers must also
+// define one of the following three macros:
+//
+//   CSS_PROP_LIST_EXCLUDE_LOGICAL
+//     Does not include logical properties (defined with CSS_PROP_LOGICAL,
+//     such as -moz-margin-start) when capturing properties to CSS_PROP.
+//
+//   CSS_PROP_LIST_INCLUDE_LOGICAL
+//     Does include logical properties when capturing properties to
+//     CSS_PROP.
+//
+//   CSS_PROP_LOGICAL
+//     Captures logical properties separately to CSS_PROP_LOGICAL.
+//
+// (CSS_PROP_LIST_EXCLUDE_LOGICAL is used for example to ensure
+// gPropertyCountInStruct and gPropertyIndexInStruct do not allocate any
+// storage to logical properties, since the result of the cascade, stored
+// in an nsRuleData, does not need to store both logical and physical
+// property values.)
+
 // Callers may also define CSS_PROP_LIST_ONLY_COMPONENTS_OF_ALL_SHORTHAND
 // to exclude properties that are not considered to be components of the 'all'
 // shorthand property.  Currently this excludes 'direction' and 'unicode-bidi',
 // as required by the CSS Cascading and Inheritance specification, and any
 // internal properties that cannot be changed by using CSS syntax.  For example,
 // the internal '-moz-system-font' property is not excluded, as it is set by the
 // 'font' shorthand, while '-x-lang' is excluded as there is no way to set this
 // internal property from a style sheet.
@@ -129,22 +160,46 @@
 // For properties that are stored in the CSS backend but are not
 // computed.  An includer may define this in addition to CSS_PROP, but
 // otherwise we treat it as the same.
 #ifndef CSS_PROP_BACKENDONLY
 #define CSS_PROP_BACKENDONLY(name_, id_, method_, flags_, pref_, parsevariant_, kwtable_) CSS_PROP(name_, id_, method_, flags_, pref_, parsevariant_, kwtable_, BackendOnly, CSS_PROP_NO_OFFSET, eStyleAnimType_None)
 #define DEFINED_CSS_PROP_BACKENDONLY
 #endif
 
+// And similarly for logical properties.  An includer can define
+// CSS_PROP_LOGICAL to capture all logical properties, but otherwise they
+// are included in CSS_PROP (as long as CSS_PROP_LIST_INCLUDE_LOGICAL is
+// defined).
+#if defined(CSS_PROP_LOGICAL) && defined(CSS_PROP_LIST_EXCLUDE_LOGICAL) || defined(CSS_PROP_LOGICAL) && defined(CSS_PROP_LIST_INCLUDE_LOGICAL) || defined(CSS_PROP_LIST_EXCLUDE_LOGICAL) && defined(CSS_PROP_LIST_INCLUDE_LOGICAL)
+#error Do not define more than one of CSS_PROP_LOGICAL, CSS_PROP_LIST_EXCLUDE_LOGICAL and CSS_PROP_LIST_INCLUDE_LOGICAL when capturing properties using CSS_PROP.
+#endif
+
+#ifndef CSS_PROP_LOGICAL
+#ifdef CSS_PROP_LIST_INCLUDE_LOGICAL
+#define CSS_PROP_LOGICAL(name_, id_, method_, flags_, pref_, parsevariant_, kwtable_, group_, struct_, stylestructoffset_, animtype_) CSS_PROP(name_, id_, method_, flags_, pref_, parsevariant_, kwtable_, struct_, stylestructoffset_, animtype_)
+#else
+#ifndef CSS_PROP_LIST_EXCLUDE_LOGICAL
+#error Must define exactly one of CSS_PROP_LOGICAL, CSS_PROP_LIST_EXCLUDE_LOGICAL and CSS_PROP_LIST_INCLUDE_LOGICAL when capturing properties using CSS_PROP.
+#endif
+#define CSS_PROP_LOGICAL(name_, id_, method_, flags_, pref_, parsevariant_, kwtable_, group_, struct_, stylestructoffset_, animtype_) /* nothing */
+#endif
+#define DEFINED_CSS_PROP_LOGICAL
+#endif
+
 #else /* !defined(CSS_PROP) */
 
 // An includer who does not define CSS_PROP can define any or all of the
 // per-struct macros that are equivalent to it, and the rest will be
 // ignored.
 
+#if defined(CSS_PROP_LIST_EXCLUDE_LOGICAL) || defined(CSS_PROP_LIST_INCLUDE_LOGICAL)
+#error Do not define CSS_PROP_LIST_EXCLUDE_LOGICAL or CSS_PROP_LIST_INCLUDE_LOGICAL when not capturing properties using CSS_PROP.
+#endif
+
 #ifndef CSS_PROP_FONT
 #define CSS_PROP_FONT(name_, id_, method_, flags_, pref_, parsevariant_, kwtable_, stylestructoffset_, animtype_) /* nothing */
 #define DEFINED_CSS_PROP_FONT
 #endif
 #ifndef CSS_PROP_COLOR
 #define CSS_PROP_COLOR(name_, id_, method_, flags_, pref_, parsevariant_, kwtable_, stylestructoffset_, animtype_) /* nothing */
 #define DEFINED_CSS_PROP_COLOR
 #endif
@@ -236,16 +291,20 @@
 #define CSS_PROP_VARIABLES(name_, id_, method_, flags_, pref_, parsevariant_, kwtable_, stylestructoffset_, animtype_) /* nothing */
 #define DEFINED_CSS_PROP_VARIABLES
 #endif
 
 #ifndef CSS_PROP_BACKENDONLY
 #define CSS_PROP_BACKENDONLY(name_, id_, method_, flags_, pref_, parsevariant_, kwtable_) /* nothing */
 #define DEFINED_CSS_PROP_BACKENDONLY
 #endif
+#ifndef CSS_PROP_LOGICAL
+#define CSS_PROP_LOGICAL(name_, id_, method_, flags_, pref_, parsevariant_, kwtable_, group_, struct_, stylestructoffset_, animtype_) /* nothing */
+#define DEFINED_CSS_PROP_LOGICAL
+#endif
 
 #endif /* !defined(CSS_PROP) */
 
 /*************************************************************************/
 
 // For notes XXX bug 3935 below, the names being parsed do not correspond
 // to the constants used internally.  It would be nice to bring the
 // constants into line sometime.
@@ -607,23 +666,150 @@ CSS_PROP_DISPLAY(
     binding,
     CSS_PROP_DOMPROP_PREFIXED(Binding),
     CSS_PROPERTY_PARSE_VALUE,
     "",
     VARIANT_HUO,
     nullptr,
     CSS_PROP_NO_OFFSET,
     eStyleAnimType_None) // XXX bug 3935
+CSS_PROP_LOGICAL(
+    block-size,
+    block_size,
+    BlockSize,
+    CSS_PROPERTY_PARSE_VALUE |
+        CSS_PROPERTY_VALUE_NONNEGATIVE |
+        CSS_PROPERTY_STORES_CALC |
+        CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH |
+        CSS_PROPERTY_LOGICAL |
+        CSS_PROPERTY_LOGICAL_AXIS |
+        CSS_PROPERTY_LOGICAL_BLOCK_AXIS,
+    "layout.css.vertical-text.enabled",
+    VARIANT_AHKLP | VARIANT_CALC,
+    kWidthKTable,
+    Size,
+    Position,
+    CSS_PROP_NO_OFFSET,
+    eStyleAnimType_None)
 CSS_PROP_SHORTHAND(
     border,
     border,
     Border,
     CSS_PROPERTY_PARSE_FUNCTION,
     "")
 CSS_PROP_SHORTHAND(
+    border-block-end,
+    border_block_end,
+    BorderBlockEnd,
+    CSS_PROPERTY_PARSE_FUNCTION,
+    "layout.css.vertical-text.enabled")
+CSS_PROP_SHORTHAND(
+    border-block-start,
+    border_block_start,
+    BorderBlockStart,
+    CSS_PROPERTY_PARSE_FUNCTION,
+    "layout.css.vertical-text.enabled")
+CSS_PROP_LOGICAL(
+    border-block-end-color,
+    border_block_end_color,
+    BorderBlockEndColor,
+    CSS_PROPERTY_PARSE_VALUE |
+        CSS_PROPERTY_APPLIES_TO_FIRST_LETTER |
+        CSS_PROPERTY_LOGICAL |
+        CSS_PROPERTY_LOGICAL_BLOCK_AXIS |
+        CSS_PROPERTY_LOGICAL_END_EDGE,
+    "layout.css.vertical-text.enabled",
+    VARIANT_HCK,
+    kBorderColorKTable,
+    BorderColor,
+    Border,
+    CSS_PROP_NO_OFFSET,
+    eStyleAnimType_None)
+CSS_PROP_LOGICAL(
+    border-block-end-style,
+    border_block_end_style,
+    BorderBlockEndStyle,
+    CSS_PROPERTY_PARSE_VALUE |
+        CSS_PROPERTY_APPLIES_TO_FIRST_LETTER |
+        CSS_PROPERTY_LOGICAL |
+        CSS_PROPERTY_LOGICAL_BLOCK_AXIS |
+        CSS_PROPERTY_LOGICAL_END_EDGE,
+    "layout.css.vertical-text.enabled",
+    VARIANT_HK,
+    kBorderStyleKTable,
+    BorderStyle,
+    Border,
+    CSS_PROP_NO_OFFSET,
+    eStyleAnimType_None)
+CSS_PROP_LOGICAL(
+    border-block-end-width,
+    border_block_end_width,
+    BorderBlockEndWidth,
+    CSS_PROPERTY_PARSE_VALUE |
+        CSS_PROPERTY_VALUE_NONNEGATIVE |
+        CSS_PROPERTY_APPLIES_TO_FIRST_LETTER |
+        CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH |
+        CSS_PROPERTY_LOGICAL |
+        CSS_PROPERTY_LOGICAL_BLOCK_AXIS |
+        CSS_PROPERTY_LOGICAL_END_EDGE,
+    "layout.css.vertical-text.enabled",
+    VARIANT_HKL | VARIANT_CALC,
+    kBorderWidthKTable,
+    BorderWidth,
+    Border,
+    CSS_PROP_NO_OFFSET,
+    eStyleAnimType_None)
+CSS_PROP_LOGICAL(
+    border-block-start-color,
+    border_block_start_color,
+    BorderBlockStartColor,
+    CSS_PROPERTY_PARSE_VALUE |
+        CSS_PROPERTY_APPLIES_TO_FIRST_LETTER |
+        CSS_PROPERTY_LOGICAL |
+        CSS_PROPERTY_LOGICAL_BLOCK_AXIS,
+    "layout.css.vertical-text.enabled",
+    VARIANT_HCK,
+    kBorderColorKTable,
+    BorderColor,
+    Border,
+    CSS_PROP_NO_OFFSET,
+    eStyleAnimType_None)
+CSS_PROP_LOGICAL(
+    border-block-start-style,
+    border_block_start_style,
+    BorderBlockStartStyle,
+    CSS_PROPERTY_PARSE_VALUE |
+        CSS_PROPERTY_APPLIES_TO_FIRST_LETTER |
+        CSS_PROPERTY_LOGICAL |
+        CSS_PROPERTY_LOGICAL_BLOCK_AXIS,
+    "layout.css.vertical-text.enabled",
+    VARIANT_HK,
+    kBorderStyleKTable,
+    BorderStyle,
+    Border,
+    CSS_PROP_NO_OFFSET,
+    eStyleAnimType_None)
+CSS_PROP_LOGICAL(
+    border-block-start-width,
+    border_block_start_width,
+    BorderBlockStartWidth,
+    CSS_PROPERTY_PARSE_VALUE |
+        CSS_PROPERTY_VALUE_NONNEGATIVE |
+        CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH |
+        CSS_PROPERTY_APPLIES_TO_FIRST_LETTER |
+        CSS_PROPERTY_LOGICAL |
+        CSS_PROPERTY_LOGICAL_BLOCK_AXIS,
+    "layout.css.vertical-text.enabled",
+    VARIANT_HKL | VARIANT_CALC,
+    kBorderWidthKTable,
+    BorderWidth,
+    Border,
+    CSS_PROP_NO_OFFSET,
+    eStyleAnimType_None)
+CSS_PROP_SHORTHAND(
     border-bottom,
     border_bottom,
     BorderBottom,
     CSS_PROPERTY_PARSE_FUNCTION,
     "")
 CSS_PROP_BORDER(
     border-bottom-color,
     border_bottom_color,
@@ -687,80 +873,16 @@ CSS_PROP_TABLEBORDER(
 CSS_PROP_SHORTHAND(
     border-color,
     border_color,
     BorderColor,
     CSS_PROPERTY_PARSE_FUNCTION |
         CSS_PROPERTY_HASHLESS_COLOR_QUIRK,
     "")
 CSS_PROP_SHORTHAND(
-    -moz-border-end,
-    border_end,
-    CSS_PROP_DOMPROP_PREFIXED(BorderEnd),
-    CSS_PROPERTY_PARSE_FUNCTION,
-    "")
-CSS_PROP_SHORTHAND(
-    -moz-border-end-color,
-    border_end_color,
-    CSS_PROP_DOMPROP_PREFIXED(BorderEndColor),
-    CSS_PROPERTY_PARSE_FUNCTION,
-    "")
-#ifndef CSS_PROP_LIST_EXCLUDE_INTERNAL
-CSS_PROP_BORDER(
-    border-end-color-value,
-    border_end_color_value,
-    BorderEndColorValue,
-    CSS_PROPERTY_PARSE_INACCESSIBLE |
-        CSS_PROPERTY_APPLIES_TO_FIRST_LETTER,
-    "",
-    VARIANT_HCK, // used only internally
-    kBorderColorKTable,
-    CSS_PROP_NO_OFFSET,
-    eStyleAnimType_None)
-#endif
-CSS_PROP_SHORTHAND(
-    -moz-border-end-style,
-    border_end_style,
-    CSS_PROP_DOMPROP_PREFIXED(BorderEndStyle),
-    CSS_PROPERTY_PARSE_FUNCTION,
-    "")
-#ifndef CSS_PROP_LIST_EXCLUDE_INTERNAL
-CSS_PROP_BORDER(
-    border-end-style-value,
-    border_end_style_value,
-    BorderEndStyleValue,
-    CSS_PROPERTY_PARSE_INACCESSIBLE |
-        CSS_PROPERTY_APPLIES_TO_FIRST_LETTER,
-    "",
-    VARIANT_HK, // used only internally
-    kBorderStyleKTable,
-    CSS_PROP_NO_OFFSET,
-    eStyleAnimType_None)
-#endif
-CSS_PROP_SHORTHAND(
-    -moz-border-end-width,
-    border_end_width,
-    CSS_PROP_DOMPROP_PREFIXED(BorderEndWidth),
-    CSS_PROPERTY_PARSE_FUNCTION,
-    "")
-#ifndef CSS_PROP_LIST_EXCLUDE_INTERNAL
-CSS_PROP_BORDER(
-    border-end-width-value,
-    border_end_width_value,
-    BorderEndWidthValue,
-    CSS_PROPERTY_PARSE_INACCESSIBLE |
-        CSS_PROPERTY_VALUE_NONNEGATIVE |
-        CSS_PROPERTY_APPLIES_TO_FIRST_LETTER,
-    "",
-    VARIANT_HKL | VARIANT_CALC,
-    kBorderWidthKTable,
-    CSS_PROP_NO_OFFSET,
-    eStyleAnimType_None)
-#endif
-CSS_PROP_SHORTHAND(
     border-image,
     border_image,
     BorderImage,
     CSS_PROPERTY_PARSE_FUNCTION,
     "")
 CSS_PROP_BORDER(
     border-image-source,
     border_image_source,
@@ -813,406 +935,243 @@ CSS_PROP_BORDER(
     CSS_PROPERTY_PARSE_FUNCTION |
         CSS_PROPERTY_APPLIES_TO_FIRST_LETTER,
     "",
     0,
     kBorderImageRepeatKTable,
     CSS_PROP_NO_OFFSET,
     eStyleAnimType_None)
 CSS_PROP_SHORTHAND(
+    -moz-border-end,
+    border_end,
+    CSS_PROP_DOMPROP_PREFIXED(BorderEnd),
+    CSS_PROPERTY_PARSE_FUNCTION,
+    "")
+CSS_PROP_LOGICAL(
+    -moz-border-end-color,
+    border_end_color,
+    CSS_PROP_DOMPROP_PREFIXED(BorderEndColor),
+    CSS_PROPERTY_PARSE_VALUE |
+        CSS_PROPERTY_APPLIES_TO_FIRST_LETTER |
+        CSS_PROPERTY_LOGICAL |
+        CSS_PROPERTY_LOGICAL_END_EDGE,
+    "",
+    VARIANT_HCK,
+    kBorderColorKTable,
+    BorderColor,
+    Border,
+    CSS_PROP_NO_OFFSET,
+    eStyleAnimType_None)
+CSS_PROP_LOGICAL(
+    -moz-border-end-style,
+    border_end_style,
+    CSS_PROP_DOMPROP_PREFIXED(BorderEndStyle),
+    CSS_PROPERTY_PARSE_VALUE |
+        CSS_PROPERTY_APPLIES_TO_FIRST_LETTER |
+        CSS_PROPERTY_LOGICAL |
+        CSS_PROPERTY_LOGICAL_END_EDGE,
+    "",
+    VARIANT_HK,
+    kBorderStyleKTable,
+    BorderStyle,
+    Border,
+    CSS_PROP_NO_OFFSET,
+    eStyleAnimType_None)
+CSS_PROP_LOGICAL(
+    -moz-border-end-width,
+    border_end_width,
+    CSS_PROP_DOMPROP_PREFIXED(BorderEndWidth),
+    CSS_PROPERTY_PARSE_VALUE |
+        CSS_PROPERTY_VALUE_NONNEGATIVE |
+        CSS_PROPERTY_APPLIES_TO_FIRST_LETTER |
+        CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH |
+        CSS_PROPERTY_LOGICAL |
+        CSS_PROPERTY_LOGICAL_END_EDGE,
+    "",
+    VARIANT_HKL | VARIANT_CALC,
+    kBorderWidthKTable,
+    BorderWidth,
+    Border,
+    CSS_PROP_NO_OFFSET,
+    eStyleAnimType_None)
+CSS_PROP_SHORTHAND(
+    -moz-border-start,
+    border_start,
+    CSS_PROP_DOMPROP_PREFIXED(BorderStart),
+    CSS_PROPERTY_PARSE_FUNCTION,
+    "")
+CSS_PROP_LOGICAL(
+    -moz-border-start-color,
+    border_start_color,
+    CSS_PROP_DOMPROP_PREFIXED(BorderStartColor),
+    CSS_PROPERTY_PARSE_VALUE |
+        CSS_PROPERTY_APPLIES_TO_FIRST_LETTER |
+        CSS_PROPERTY_LOGICAL,
+    "",
+    VARIANT_HCK,
+    kBorderColorKTable,
+    BorderColor,
+    Border,
+    CSS_PROP_NO_OFFSET,
+    eStyleAnimType_None)
+CSS_PROP_LOGICAL(
+    -moz-border-start-style,
+    border_start_style,
+    CSS_PROP_DOMPROP_PREFIXED(BorderStartStyle),
+    CSS_PROPERTY_PARSE_VALUE |
+        CSS_PROPERTY_APPLIES_TO_FIRST_LETTER |
+        CSS_PROPERTY_LOGICAL,
+    "",
+    VARIANT_HK,
+    kBorderStyleKTable,
+    BorderStyle,
+    Border,
+    CSS_PROP_NO_OFFSET,
+    eStyleAnimType_None)
+CSS_PROP_LOGICAL(
+    -moz-border-start-width,
+    border_start_width,
+    CSS_PROP_DOMPROP_PREFIXED(BorderStartWidth),
+    CSS_PROPERTY_PARSE_VALUE |
+        CSS_PROPERTY_VALUE_NONNEGATIVE |
+        CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH |
+        CSS_PROPERTY_APPLIES_TO_FIRST_LETTER |
+        CSS_PROPERTY_LOGICAL,
+    "",
+    VARIANT_HKL | VARIANT_CALC,
+    kBorderWidthKTable,
+    BorderWidth,
+    Border,
+    CSS_PROP_NO_OFFSET,
+    eStyleAnimType_None)
+CSS_PROP_SHORTHAND(
     border-left,
     border_left,
     BorderLeft,
     CSS_PROPERTY_PARSE_FUNCTION,
     "")
-CSS_PROP_SHORTHAND(
+CSS_PROP_BORDER(
     border-left-color,
     border_left_color,
     BorderLeftColor,
-    CSS_PROPERTY_PARSE_FUNCTION |
-        CSS_PROPERTY_HASHLESS_COLOR_QUIRK,
-    "")
-#ifndef CSS_PROP_LIST_EXCLUDE_INTERNAL
-CSS_PROP_BORDER(
-    border-left-color-value,
-    border_left_color_value,
-    BorderLeftColorValue,
-    CSS_PROPERTY_PARSE_INACCESSIBLE |
+    CSS_PROPERTY_PARSE_VALUE |
+        CSS_PROPERTY_HASHLESS_COLOR_QUIRK |
         CSS_PROPERTY_APPLIES_TO_FIRST_LETTER |
-        CSS_PROPERTY_IGNORED_WHEN_COLORS_DISABLED |
-        CSS_PROPERTY_REPORT_OTHER_NAME,
-    "",
-    VARIANT_HCK, // used only internally
+        CSS_PROPERTY_IGNORED_WHEN_COLORS_DISABLED,
+    "",
+    VARIANT_HCK,
     kBorderColorKTable,
     CSS_PROP_NO_OFFSET,
     eStyleAnimType_Custom)
 CSS_PROP_BORDER(
-    border-left-color-ltr-source,
-    border_left_color_ltr_source,
-    BorderLeftColorLTRSource,
-    CSS_PROPERTY_PARSE_INACCESSIBLE |
-        CSS_PROPERTY_APPLIES_TO_FIRST_LETTER |
-        CSS_PROPERTY_DIRECTIONAL_SOURCE |
-        CSS_PROPERTY_IGNORED_WHEN_COLORS_DISABLED,
-    "",
-    0,
-    kBoxPropSourceKTable,
-    CSS_PROP_NO_OFFSET,
-    eStyleAnimType_None)
-CSS_PROP_BORDER(
-    border-left-color-rtl-source,
-    border_left_color_rtl_source,
-    BorderLeftColorRTLSource,
-    CSS_PROPERTY_PARSE_INACCESSIBLE |
-        CSS_PROPERTY_APPLIES_TO_FIRST_LETTER |
-        CSS_PROPERTY_DIRECTIONAL_SOURCE |
-        CSS_PROPERTY_IGNORED_WHEN_COLORS_DISABLED,
-    "",
-    0,
-    kBoxPropSourceKTable,
-    CSS_PROP_NO_OFFSET,
-    eStyleAnimType_None)
-#endif
-CSS_PROP_BORDER(
     -moz-border-left-colors,
     border_left_colors,
     CSS_PROP_DOMPROP_PREFIXED(BorderLeftColors),
     CSS_PROPERTY_PARSE_FUNCTION |
         CSS_PROPERTY_APPLIES_TO_FIRST_LETTER |
         CSS_PROPERTY_IGNORED_WHEN_COLORS_DISABLED,
     "",
     0,
     nullptr,
     CSS_PROP_NO_OFFSET,
     eStyleAnimType_None)
-CSS_PROP_SHORTHAND(
+CSS_PROP_BORDER(
     border-left-style,
     border_left_style,
     BorderLeftStyle,
-    CSS_PROPERTY_PARSE_FUNCTION,
-    "") // on/off will need reflow
-#ifndef CSS_PROP_LIST_EXCLUDE_INTERNAL
-CSS_PROP_BORDER(
-    border-left-style-value,
-    border_left_style_value,
-    BorderLeftStyleValue,
-    CSS_PROPERTY_PARSE_INACCESSIBLE |
-        CSS_PROPERTY_APPLIES_TO_FIRST_LETTER |
-        CSS_PROPERTY_REPORT_OTHER_NAME,
-    "",
-    VARIANT_HK, // used only internally
+    CSS_PROPERTY_PARSE_VALUE |
+        CSS_PROPERTY_APPLIES_TO_FIRST_LETTER,
+    "",
+    VARIANT_HK,
     kBorderStyleKTable,
     CSS_PROP_NO_OFFSET,
     eStyleAnimType_None)
 CSS_PROP_BORDER(
-    border-left-style-ltr-source,
-    border_left_style_ltr_source,
-    BorderLeftStyleLTRSource,
-    CSS_PROPERTY_PARSE_INACCESSIBLE |
-        CSS_PROPERTY_APPLIES_TO_FIRST_LETTER |
-        CSS_PROPERTY_DIRECTIONAL_SOURCE,
-    "",
-    0,
-    kBoxPropSourceKTable,
-    CSS_PROP_NO_OFFSET,
-    eStyleAnimType_None)
-CSS_PROP_BORDER(
-    border-left-style-rtl-source,
-    border_left_style_rtl_source,
-    BorderLeftStyleRTLSource,
-    CSS_PROPERTY_PARSE_INACCESSIBLE |
-        CSS_PROPERTY_APPLIES_TO_FIRST_LETTER |
-        CSS_PROPERTY_DIRECTIONAL_SOURCE,
-    "",
-    0,
-    kBoxPropSourceKTable,
-    CSS_PROP_NO_OFFSET,
-    eStyleAnimType_None)
-#endif
-CSS_PROP_SHORTHAND(
     border-left-width,
     border_left_width,
     BorderLeftWidth,
-    CSS_PROPERTY_PARSE_FUNCTION |
+    CSS_PROPERTY_PARSE_VALUE |
         CSS_PROPERTY_UNITLESS_LENGTH_QUIRK |
-        CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH,
-    "")
-#ifndef CSS_PROP_LIST_EXCLUDE_INTERNAL
-CSS_PROP_BORDER(
-    border-left-width-value,
-    border_left_width_value,
-    BorderLeftWidthValue,
-    CSS_PROPERTY_PARSE_INACCESSIBLE |
         CSS_PROPERTY_VALUE_NONNEGATIVE |
-        CSS_PROPERTY_APPLIES_TO_FIRST_LETTER |
-        CSS_PROPERTY_REPORT_OTHER_NAME,
+        CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH |
+        CSS_PROPERTY_APPLIES_TO_FIRST_LETTER,
     "",
     VARIANT_HKL | VARIANT_CALC,
     kBorderWidthKTable,
     CSS_PROP_NO_OFFSET,
     eStyleAnimType_Custom)
-CSS_PROP_BORDER(
-    border-left-width-ltr-source,
-    border_left_width_ltr_source,
-    BorderLeftWidthLTRSource,
-    CSS_PROPERTY_PARSE_INACCESSIBLE |
-        CSS_PROPERTY_APPLIES_TO_FIRST_LETTER |
-        CSS_PROPERTY_DIRECTIONAL_SOURCE,
-    "",
-    0,
-    kBoxPropSourceKTable,
-    CSS_PROP_NO_OFFSET,
-    eStyleAnimType_None)
-CSS_PROP_BORDER(
-    border-left-width-rtl-source,
-    border_left_width_rtl_source,
-    BorderLeftWidthRTLSource,
-    CSS_PROPERTY_PARSE_INACCESSIBLE |
-        CSS_PROPERTY_APPLIES_TO_FIRST_LETTER |
-        CSS_PROPERTY_DIRECTIONAL_SOURCE,
-    "",
-    0,
-    kBoxPropSourceKTable,
-    CSS_PROP_NO_OFFSET,
-    eStyleAnimType_None)
-#endif
 CSS_PROP_SHORTHAND(
     border-right,
     border_right,
     BorderRight,
     CSS_PROPERTY_PARSE_FUNCTION,
     "")
-CSS_PROP_SHORTHAND(
+CSS_PROP_BORDER(
     border-right-color,
     border_right_color,
     BorderRightColor,
-    CSS_PROPERTY_PARSE_FUNCTION |
-        CSS_PROPERTY_HASHLESS_COLOR_QUIRK,
-    "")
-#ifndef CSS_PROP_LIST_EXCLUDE_INTERNAL
-CSS_PROP_BORDER(
-    border-right-color-value,
-    border_right_color_value,
-    BorderRightColorValue,
-    CSS_PROPERTY_PARSE_INACCESSIBLE |
+    CSS_PROPERTY_PARSE_VALUE |
+        CSS_PROPERTY_HASHLESS_COLOR_QUIRK |
         CSS_PROPERTY_APPLIES_TO_FIRST_LETTER |
-        CSS_PROPERTY_IGNORED_WHEN_COLORS_DISABLED |
-        CSS_PROPERTY_REPORT_OTHER_NAME,
-    "",
-    VARIANT_HCK, // used only internally
+        CSS_PROPERTY_IGNORED_WHEN_COLORS_DISABLED,
+    "",
+    VARIANT_HCK,
     kBorderColorKTable,
     CSS_PROP_NO_OFFSET,
     eStyleAnimType_Custom)
 CSS_PROP_BORDER(
-    border-right-color-ltr-source,
-    border_right_color_ltr_source,
-    BorderRightColorLTRSource,
-    CSS_PROPERTY_PARSE_INACCESSIBLE |
-        CSS_PROPERTY_APPLIES_TO_FIRST_LETTER |
-        CSS_PROPERTY_DIRECTIONAL_SOURCE |
-        CSS_PROPERTY_IGNORED_WHEN_COLORS_DISABLED,
-    "",
-    0,
-    kBoxPropSourceKTable,
-    CSS_PROP_NO_OFFSET,
-    eStyleAnimType_None)
-CSS_PROP_BORDER(
-    border-right-color-rtl-source,
-    border_right_color_rtl_source,
-    BorderRightColorRTLSource,
-    CSS_PROPERTY_PARSE_INACCESSIBLE |
-        CSS_PROPERTY_APPLIES_TO_FIRST_LETTER |
-        CSS_PROPERTY_DIRECTIONAL_SOURCE |
-        CSS_PROPERTY_IGNORED_WHEN_COLORS_DISABLED,
-    "",
-    0,
-    kBoxPropSourceKTable,
-    CSS_PROP_NO_OFFSET,
-    eStyleAnimType_None)
-#endif
-CSS_PROP_BORDER(
     -moz-border-right-colors,
     border_right_colors,
     CSS_PROP_DOMPROP_PREFIXED(BorderRightColors),
     CSS_PROPERTY_PARSE_FUNCTION |
         CSS_PROPERTY_APPLIES_TO_FIRST_LETTER |
         CSS_PROPERTY_IGNORED_WHEN_COLORS_DISABLED,
     "",
     0,
     nullptr,
     CSS_PROP_NO_OFFSET,
     eStyleAnimType_None)
-CSS_PROP_SHORTHAND(
+CSS_PROP_BORDER(
     border-right-style,
     border_right_style,
     BorderRightStyle,
-    CSS_PROPERTY_PARSE_FUNCTION,
-    "") // on/off will need reflow
-#ifndef CSS_PROP_LIST_EXCLUDE_INTERNAL
-CSS_PROP_BORDER(
-    border-right-style-value,
-    border_right_style_value,
-    BorderRightStyleValue,
-    CSS_PROPERTY_PARSE_INACCESSIBLE |
-        CSS_PROPERTY_APPLIES_TO_FIRST_LETTER |
-        CSS_PROPERTY_REPORT_OTHER_NAME,
-    "",
-    VARIANT_HK, // used only internally
+    CSS_PROPERTY_PARSE_VALUE |
+        CSS_PROPERTY_APPLIES_TO_FIRST_LETTER,
+    "",
+    VARIANT_HK,
     kBorderStyleKTable,
     CSS_PROP_NO_OFFSET,
     eStyleAnimType_None)
 CSS_PROP_BORDER(
-    border-right-style-ltr-source,
-    border_right_style_ltr_source,
-    BorderRightStyleLTRSource,
-    CSS_PROPERTY_PARSE_INACCESSIBLE |
-        CSS_PROPERTY_APPLIES_TO_FIRST_LETTER |
-        CSS_PROPERTY_DIRECTIONAL_SOURCE,
-    "",
-    0,
-    kBoxPropSourceKTable,
-    CSS_PROP_NO_OFFSET,
-    eStyleAnimType_None)
-CSS_PROP_BORDER(
-    border-right-style-rtl-source,
-    border_right_style_rtl_source,
-    BorderRightStyleRTLSource,
-    CSS_PROPERTY_PARSE_INACCESSIBLE |
-        CSS_PROPERTY_APPLIES_TO_FIRST_LETTER |
-        CSS_PROPERTY_DIRECTIONAL_SOURCE,
-    "",
-    0,
-    kBoxPropSourceKTable,
-    CSS_PROP_NO_OFFSET,
-    eStyleAnimType_None)
-#endif
-CSS_PROP_SHORTHAND(
     border-right-width,
     border_right_width,
     BorderRightWidth,
-    CSS_PROPERTY_PARSE_FUNCTION |
+    CSS_PROPERTY_PARSE_VALUE |
+        CSS_PROPERTY_VALUE_NONNEGATIVE |
         CSS_PROPERTY_UNITLESS_LENGTH_QUIRK |
-        CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH,
-    "")
-#ifndef CSS_PROP_LIST_EXCLUDE_INTERNAL
-CSS_PROP_BORDER(
-    border-right-width-value,
-    border_right_width_value,
-    BorderRightWidthValue,
-    CSS_PROPERTY_PARSE_INACCESSIBLE |
-        CSS_PROPERTY_VALUE_NONNEGATIVE |
-        CSS_PROPERTY_APPLIES_TO_FIRST_LETTER |
-        CSS_PROPERTY_REPORT_OTHER_NAME,
+        CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH |
+        CSS_PROPERTY_APPLIES_TO_FIRST_LETTER,
     "",
     VARIANT_HKL | VARIANT_CALC,
     kBorderWidthKTable,
     CSS_PROP_NO_OFFSET,
     eStyleAnimType_Custom)
-CSS_PROP_BORDER(
-    border-right-width-ltr-source,
-    border_right_width_ltr_source,
-    BorderRightWidthLTRSource,
-    CSS_PROPERTY_PARSE_INACCESSIBLE |
-        CSS_PROPERTY_APPLIES_TO_FIRST_LETTER |
-        CSS_PROPERTY_DIRECTIONAL_SOURCE,
-    "",
-    0,
-    kBoxPropSourceKTable,
-    CSS_PROP_NO_OFFSET,
-    eStyleAnimType_None)
-CSS_PROP_BORDER(
-    border-right-width-rtl-source,
-    border_right_width_rtl_source,
-    BorderRightWidthRTLSource,
-    CSS_PROPERTY_PARSE_INACCESSIBLE |
-        CSS_PROPERTY_APPLIES_TO_FIRST_LETTER |
-        CSS_PROPERTY_DIRECTIONAL_SOURCE,
-    "",
-    0,
-    kBoxPropSourceKTable,
-    CSS_PROP_NO_OFFSET,
-    eStyleAnimType_None)
-#endif
 CSS_PROP_TABLEBORDER(
     border-spacing,
     border_spacing,
     BorderSpacing,
     CSS_PROPERTY_PARSE_FUNCTION |
         CSS_PROPERTY_UNITLESS_LENGTH_QUIRK |
         CSS_PROPERTY_VALUE_NONNEGATIVE,
     "",
     0,
     nullptr,
     CSS_PROP_NO_OFFSET,
     eStyleAnimType_Custom)
 CSS_PROP_SHORTHAND(
-    -moz-border-start,
-    border_start,
-    CSS_PROP_DOMPROP_PREFIXED(BorderStart),
-    CSS_PROPERTY_PARSE_FUNCTION,
-    "")
-CSS_PROP_SHORTHAND(
-    -moz-border-start-color,
-    border_start_color,
-    CSS_PROP_DOMPROP_PREFIXED(BorderStartColor),
-    CSS_PROPERTY_PARSE_FUNCTION,
-    "")
-#ifndef CSS_PROP_LIST_EXCLUDE_INTERNAL
-CSS_PROP_BORDER(
-    border-start-color-value,
-    border_start_color_value,
-    BorderStartColorValue,
-    CSS_PROPERTY_PARSE_INACCESSIBLE |
-        CSS_PROPERTY_APPLIES_TO_FIRST_LETTER,
-    "",
-    VARIANT_HCK, // used only internally
-    kBorderColorKTable,
-    CSS_PROP_NO_OFFSET,
-    eStyleAnimType_None)
-#endif
-CSS_PROP_SHORTHAND(
-    -moz-border-start-style,
-    border_start_style,
-    CSS_PROP_DOMPROP_PREFIXED(BorderStartStyle),
-    CSS_PROPERTY_PARSE_FUNCTION,
-    "")
-#ifndef CSS_PROP_LIST_EXCLUDE_INTERNAL
-CSS_PROP_BORDER(
-    border-start-style-value,
-    border_start_style_value,
-    BorderStartStyleValue,
-    CSS_PROPERTY_PARSE_INACCESSIBLE |
-        CSS_PROPERTY_APPLIES_TO_FIRST_LETTER,
-    "",
-    VARIANT_HK, // used only internally
-    kBorderStyleKTable,
-    CSS_PROP_NO_OFFSET,
-    eStyleAnimType_None)
-#endif
-CSS_PROP_SHORTHAND(
-    -moz-border-start-width,
-    border_start_width,
-    CSS_PROP_DOMPROP_PREFIXED(BorderStartWidth),
-    CSS_PROPERTY_PARSE_FUNCTION,
-    "")
-#ifndef CSS_PROP_LIST_EXCLUDE_INTERNAL
-CSS_PROP_BORDER(
-    border-start-width-value,
-    border_start_width_value,
-    BorderStartWidthValue,
-    CSS_PROPERTY_PARSE_INACCESSIBLE |
-        CSS_PROPERTY_VALUE_NONNEGATIVE |
-        CSS_PROPERTY_APPLIES_TO_FIRST_LETTER,
-    "",
-    VARIANT_HKL | VARIANT_CALC,
-    kBorderWidthKTable,
-    CSS_PROP_NO_OFFSET,
-    eStyleAnimType_None)
-#endif
-CSS_PROP_SHORTHAND(
     border-style,
     border_style,
     BorderStyle,
     CSS_PROPERTY_PARSE_FUNCTION,
     "")  // on/off will need reflow
 CSS_PROP_SHORTHAND(
     border-top,
     border_top,
@@ -2174,16 +2133,33 @@ CSS_PROP_UIRESET(
     ime_mode,
     ImeMode,
     CSS_PROPERTY_PARSE_VALUE,
     "",
     VARIANT_HK,
     kIMEModeKTable,
     CSS_PROP_NO_OFFSET,
     eStyleAnimType_None)
+CSS_PROP_LOGICAL(
+    inline-size,
+    inline_size,
+    InlineSize,
+    CSS_PROPERTY_PARSE_VALUE |
+        CSS_PROPERTY_VALUE_NONNEGATIVE |
+        CSS_PROPERTY_STORES_CALC |
+        CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH |
+        CSS_PROPERTY_LOGICAL |
+        CSS_PROPERTY_LOGICAL_AXIS,
+    "layout.css.vertical-text.enabled",
+    VARIANT_AHKLP | VARIANT_CALC,
+    kWidthKTable,
+    Size,
+    Position,
+    CSS_PROP_NO_OFFSET,
+    eStyleAnimType_None)
 CSS_PROP_POSITION(
     left,
     left,
     Left,
     CSS_PROPERTY_PARSE_VALUE |
         CSS_PROPERTY_STORES_CALC |
         CSS_PROPERTY_UNITLESS_LENGTH_QUIRK |
         CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH,
@@ -2260,178 +2236,132 @@ CSS_PROP_LIST(
 CSS_PROP_SHORTHAND(
     margin,
     margin,
     Margin,
     CSS_PROPERTY_PARSE_FUNCTION |
         CSS_PROPERTY_UNITLESS_LENGTH_QUIRK |
         CSS_PROPERTY_APPLIES_TO_PAGE_RULE,
     "")
+CSS_PROP_LOGICAL(
+    margin-block-end,
+    margin_block_end,
+    MarginBlockEnd,
+    CSS_PROPERTY_PARSE_VALUE |
+        CSS_PROPERTY_APPLIES_TO_FIRST_LETTER |
+        CSS_PROPERTY_STORES_CALC |
+        CSS_PROPERTY_APPLIES_TO_PAGE_RULE |
+        CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH |
+        CSS_PROPERTY_LOGICAL |
+        CSS_PROPERTY_LOGICAL_BLOCK_AXIS |
+        CSS_PROPERTY_LOGICAL_END_EDGE,
+    "layout.css.vertical-text.enabled",
+    VARIANT_AHLP | VARIANT_CALC,
+    nullptr,
+    Margin,
+    Margin,
+    CSS_PROP_NO_OFFSET,
+    eStyleAnimType_None)
+CSS_PROP_LOGICAL(
+    margin-block-start,
+    margin_block_start,
+    MarginBlockStart,
+    CSS_PROPERTY_PARSE_VALUE |
+        CSS_PROPERTY_APPLIES_TO_FIRST_LETTER |
+        CSS_PROPERTY_STORES_CALC |
+        CSS_PROPERTY_APPLIES_TO_PAGE_RULE |
+        CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH |
+        CSS_PROPERTY_LOGICAL |
+        CSS_PROPERTY_LOGICAL_BLOCK_AXIS,
+    "layout.css.vertical-text.enabled",
+    VARIANT_AHLP | VARIANT_CALC,
+    nullptr,
+    Margin,
+    Margin,
+    CSS_PROP_NO_OFFSET,
+    eStyleAnimType_None)
 CSS_PROP_MARGIN(
     margin-bottom,
     margin_bottom,
     MarginBottom,
     CSS_PROPERTY_PARSE_VALUE |
         CSS_PROPERTY_APPLIES_TO_FIRST_LETTER |
         CSS_PROPERTY_STORES_CALC |
         CSS_PROPERTY_UNITLESS_LENGTH_QUIRK |
         CSS_PROPERTY_APPLIES_TO_PAGE_RULE |
         CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH,
     "",
     VARIANT_AHLP | VARIANT_CALC,
     nullptr,
     offsetof(nsStyleMargin, mMargin),
     eStyleAnimType_Sides_Bottom)
-CSS_PROP_SHORTHAND(
+CSS_PROP_LOGICAL(
     -moz-margin-end,
     margin_end,
     CSS_PROP_DOMPROP_PREFIXED(MarginEnd),
-    CSS_PROPERTY_PARSE_FUNCTION |
-        CSS_PROPERTY_APPLIES_TO_PAGE_RULE,
-    "")
-#ifndef CSS_PROP_LIST_EXCLUDE_INTERNAL
-CSS_PROP_MARGIN(
-    margin-end-value,
-    margin_end_value,
-    MarginEndValue,
-    CSS_PROPERTY_PARSE_INACCESSIBLE |
+    CSS_PROPERTY_PARSE_VALUE |
         CSS_PROPERTY_APPLIES_TO_FIRST_LETTER |
         CSS_PROPERTY_STORES_CALC |
-        CSS_PROPERTY_APPLIES_TO_PAGE_RULE,
-    "",
-    VARIANT_AHLP | VARIANT_CALC, // for internal use
+        CSS_PROPERTY_APPLIES_TO_PAGE_RULE |
+        CSS_PROPERTY_LOGICAL |
+        CSS_PROPERTY_LOGICAL_END_EDGE,
+    "",
+    VARIANT_AHLP | VARIANT_CALC,
     nullptr,
+    Margin,
+    Margin,
     CSS_PROP_NO_OFFSET,
     eStyleAnimType_None)
-#endif
-CSS_PROP_SHORTHAND(
+CSS_PROP_LOGICAL(
+    -moz-margin-start,
+    margin_start,
+    CSS_PROP_DOMPROP_PREFIXED(MarginStart),
+    CSS_PROPERTY_PARSE_VALUE |
+        CSS_PROPERTY_APPLIES_TO_FIRST_LETTER |
+        CSS_PROPERTY_STORES_CALC |
+        CSS_PROPERTY_APPLIES_TO_PAGE_RULE |
+        CSS_PROPERTY_LOGICAL,
+    "",
+    VARIANT_AHLP | VARIANT_CALC,
+    nullptr,
+    Margin,
+    Margin,
+    CSS_PROP_NO_OFFSET,
+    eStyleAnimType_None)
+CSS_PROP_MARGIN(
     margin-left,
     margin_left,
     MarginLeft,
-    CSS_PROPERTY_PARSE_FUNCTION |
+    CSS_PROPERTY_PARSE_VALUE |
         CSS_PROPERTY_UNITLESS_LENGTH_QUIRK |
+        CSS_PROPERTY_APPLIES_TO_FIRST_LETTER |
+        CSS_PROPERTY_STORES_CALC |
         CSS_PROPERTY_APPLIES_TO_PAGE_RULE |
         CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH,
-    "")
-#ifndef CSS_PROP_LIST_EXCLUDE_INTERNAL
-CSS_PROP_MARGIN(
-    margin-left-value,
-    margin_left_value,
-    MarginLeftValue,
-    CSS_PROPERTY_PARSE_INACCESSIBLE |
-        CSS_PROPERTY_APPLIES_TO_FIRST_LETTER |
-        CSS_PROPERTY_REPORT_OTHER_NAME |
-        CSS_PROPERTY_STORES_CALC |
-        CSS_PROPERTY_APPLIES_TO_PAGE_RULE,
-    "",
-    VARIANT_AHLP | VARIANT_CALC, // for internal use
+    "",
+    VARIANT_AHLP | VARIANT_CALC,
     nullptr,
     offsetof(nsStyleMargin, mMargin),
     eStyleAnimType_Sides_Left)
 CSS_PROP_MARGIN(
-    margin-left-ltr-source,
-    margin_left_ltr_source,
-    MarginLeftLTRSource,
-    CSS_PROPERTY_PARSE_INACCESSIBLE |
-        CSS_PROPERTY_APPLIES_TO_FIRST_LETTER |
-        CSS_PROPERTY_DIRECTIONAL_SOURCE |
-        CSS_PROPERTY_APPLIES_TO_PAGE_RULE,
-    "",
-    0,
-    kBoxPropSourceKTable,
-    CSS_PROP_NO_OFFSET,
-    eStyleAnimType_None)
-CSS_PROP_MARGIN(
-    margin-left-rtl-source,
-    margin_left_rtl_source,
-    MarginLeftRTLSource,
-    CSS_PROPERTY_PARSE_INACCESSIBLE |
-        CSS_PROPERTY_APPLIES_TO_FIRST_LETTER |
-        CSS_PROPERTY_DIRECTIONAL_SOURCE |
-        CSS_PROPERTY_APPLIES_TO_PAGE_RULE,
-    "",
-    0,
-    kBoxPropSourceKTable,
-    CSS_PROP_NO_OFFSET,
-    eStyleAnimType_None)
-#endif
-CSS_PROP_SHORTHAND(
     margin-right,
     margin_right,
     MarginRight,
-    CSS_PROPERTY_PARSE_FUNCTION |
+    CSS_PROPERTY_PARSE_VALUE |
         CSS_PROPERTY_UNITLESS_LENGTH_QUIRK |
+        CSS_PROPERTY_APPLIES_TO_FIRST_LETTER |
+        CSS_PROPERTY_STORES_CALC |
         CSS_PROPERTY_APPLIES_TO_PAGE_RULE |
         CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH,
-    "")
-#ifndef CSS_PROP_LIST_EXCLUDE_INTERNAL
-CSS_PROP_MARGIN(
-    margin-right-value,
-    margin_right_value,
-    MarginRightValue,
-    CSS_PROPERTY_PARSE_INACCESSIBLE |
-        CSS_PROPERTY_APPLIES_TO_FIRST_LETTER |
-        CSS_PROPERTY_REPORT_OTHER_NAME |
-        CSS_PROPERTY_STORES_CALC |
-        CSS_PROPERTY_APPLIES_TO_PAGE_RULE,
-    "",
-    VARIANT_AHLP | VARIANT_CALC, // for internal use
+    "",
+    VARIANT_AHLP | VARIANT_CALC,
     nullptr,
     offsetof(nsStyleMargin, mMargin),
     eStyleAnimType_Sides_Right)
 CSS_PROP_MARGIN(
-    margin-right-ltr-source,
-    margin_right_ltr_source,
-    MarginRightLTRSource,
-    CSS_PROPERTY_PARSE_INACCESSIBLE |
-        CSS_PROPERTY_APPLIES_TO_FIRST_LETTER |
-        CSS_PROPERTY_DIRECTIONAL_SOURCE |
-        CSS_PROPERTY_APPLIES_TO_PAGE_RULE,
-    "",
-    0,
-    kBoxPropSourceKTable,
-    CSS_PROP_NO_OFFSET,
-    eStyleAnimType_None)
-CSS_PROP_MARGIN(
-    margin-right-rtl-source,
-    margin_right_rtl_source,
-    MarginRightRTLSource,
-    CSS_PROPERTY_PARSE_INACCESSIBLE |
-        CSS_PROPERTY_APPLIES_TO_FIRST_LETTER |
-        CSS_PROPERTY_DIRECTIONAL_SOURCE |
-        CSS_PROPERTY_APPLIES_TO_PAGE_RULE,
-    "",
-    0,
-    kBoxPropSourceKTable,
-    CSS_PROP_NO_OFFSET,
-    eStyleAnimType_None)
-#endif
-CSS_PROP_SHORTHAND(
-    -moz-margin-start,
-    margin_start,
-    CSS_PROP_DOMPROP_PREFIXED(MarginStart),
-    CSS_PROPERTY_PARSE_FUNCTION |
-    CSS_PROPERTY_APPLIES_TO_PAGE_RULE,
-    "")
-#ifndef CSS_PROP_LIST_EXCLUDE_INTERNAL
-CSS_PROP_MARGIN(
-    margin-start-value,
-    margin_start_value,
-    MarginStartValue,
-    CSS_PROPERTY_PARSE_INACCESSIBLE |
-        CSS_PROPERTY_APPLIES_TO_FIRST_LETTER |
-        CSS_PROPERTY_STORES_CALC |
-        CSS_PROPERTY_APPLIES_TO_PAGE_RULE,
-    "",
-    VARIANT_AHLP | VARIANT_CALC, // for internal use
-    nullptr,
-    CSS_PROP_NO_OFFSET,
-    eStyleAnimType_None)
-#endif
-CSS_PROP_MARGIN(
     margin-top,
     margin_top,
     MarginTop,
     CSS_PROPERTY_PARSE_VALUE |
         CSS_PROPERTY_APPLIES_TO_FIRST_LETTER |
         CSS_PROPERTY_STORES_CALC |
         CSS_PROPERTY_UNITLESS_LENGTH_QUIRK |
         CSS_PROPERTY_APPLIES_TO_PAGE_RULE |
@@ -2455,30 +2385,65 @@ CSS_PROP_BACKENDONLY(
     marks,
     marks,
     Marks,
     CSS_PROPERTY_PARSE_VALUE |
         CSS_PROPERTY_VALUE_PARSER_FUNCTION,
     "",
     0,
     kPageMarksKTable)
+CSS_PROP_LOGICAL(
+    max-block-size,
+    max_block_size,
+    MaxBlockSize,
+    CSS_PROPERTY_PARSE_VALUE |
+        CSS_PROPERTY_VALUE_NONNEGATIVE |
+        CSS_PROPERTY_STORES_CALC |
+        CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH |
+        CSS_PROPERTY_LOGICAL |
+        CSS_PROPERTY_LOGICAL_AXIS |
+        CSS_PROPERTY_LOGICAL_BLOCK_AXIS,
+    "layout.css.vertical-text.enabled",
+    VARIANT_HKLPO | VARIANT_CALC,
+    kWidthKTable,
+    MaxSize,
+    Position,
+    CSS_PROP_NO_OFFSET,
+    eStyleAnimType_None)
 CSS_PROP_POSITION(
     max-height,
     max_height,
     MaxHeight,
     CSS_PROPERTY_PARSE_VALUE |
         CSS_PROPERTY_VALUE_NONNEGATIVE |
         CSS_PROPERTY_STORES_CALC |
         CSS_PROPERTY_UNITLESS_LENGTH_QUIRK |
         CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH,
     "",
     VARIANT_HLPO | VARIANT_CALC,
     nullptr,
     offsetof(nsStylePosition, mMaxHeight),
     eStyleAnimType_Coord)
+CSS_PROP_LOGICAL(
+    max-inline-size,
+    max_inline_size,
+    MaxInlineSize,
+    CSS_PROPERTY_PARSE_VALUE |
+        CSS_PROPERTY_VALUE_NONNEGATIVE |
+        CSS_PROPERTY_STORES_CALC |
+        CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH |
+        CSS_PROPERTY_LOGICAL |
+        CSS_PROPERTY_LOGICAL_AXIS,
+    "layout.css.vertical-text.enabled",
+    VARIANT_HKLPO | VARIANT_CALC,
+    kWidthKTable,
+    MaxSize,
+    Position,
+    CSS_PROP_NO_OFFSET,
+    eStyleAnimType_None)
 CSS_PROP_POSITION(
     max-width,
     max_width,
     MaxWidth,
     CSS_PROPERTY_PARSE_VALUE |
         CSS_PROPERTY_VALUE_NONNEGATIVE |
         CSS_PROPERTY_STORES_CALC |
         CSS_PROPERTY_UNITLESS_LENGTH_QUIRK |
@@ -2497,16 +2462,51 @@ CSS_PROP_POSITION(
         CSS_PROPERTY_STORES_CALC |
         CSS_PROPERTY_UNITLESS_LENGTH_QUIRK |
         CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH,
     "",
     VARIANT_AHLP | VARIANT_CALC,
     nullptr,
     offsetof(nsStylePosition, mMinHeight),
     eStyleAnimType_Coord)
+CSS_PROP_LOGICAL(
+    min-block-size,
+    min_block_size,
+    MinBlockSize,
+    CSS_PROPERTY_PARSE_VALUE |
+        CSS_PROPERTY_VALUE_NONNEGATIVE |
+        CSS_PROPERTY_STORES_CALC |
+        CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH |
+        CSS_PROPERTY_LOGICAL |
+        CSS_PROPERTY_LOGICAL_AXIS |
+        CSS_PROPERTY_LOGICAL_BLOCK_AXIS,
+    "layout.css.vertical-text.enabled",
+    VARIANT_AHKLP | VARIANT_CALC,
+    kWidthKTable,
+    MinSize,
+    Position,
+    CSS_PROP_NO_OFFSET,
+    eStyleAnimType_None)
+CSS_PROP_LOGICAL(
+    min-inline-size,
+    min_inline_size,
+    MinInlineSize,
+    CSS_PROPERTY_PARSE_VALUE |
+        CSS_PROPERTY_VALUE_NONNEGATIVE |
+        CSS_PROPERTY_STORES_CALC |
+        CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH |
+        CSS_PROPERTY_LOGICAL |
+        CSS_PROPERTY_LOGICAL_AXIS,
+    "layout.css.vertical-text.enabled",
+    VARIANT_AHKLP | VARIANT_CALC,
+    kWidthKTable,
+    MinSize,
+    Position,
+    CSS_PROP_NO_OFFSET,
+    eStyleAnimType_None)
 CSS_PROP_POSITION(
     min-width,
     min_width,
     MinWidth,
     CSS_PROPERTY_PARSE_VALUE |
         CSS_PROPERTY_VALUE_NONNEGATIVE |
         CSS_PROPERTY_STORES_CALC |
         CSS_PROPERTY_UNITLESS_LENGTH_QUIRK |
@@ -2556,16 +2556,80 @@ CSS_PROP_POSITION(
     CSS_PROPERTY_PARSE_FUNCTION |
         CSS_PROPERTY_STORES_CALC |
         CSS_PROPERTY_ALWAYS_ENABLED_IN_UA_SHEETS,
     "layout.css.object-fit-and-position.enabled",
     0,
     kBackgroundPositionKTable,
     offsetof(nsStylePosition, mObjectPosition),
     eStyleAnimType_Custom)
+CSS_PROP_LOGICAL(
+    offset-block-end,
+    offset_block_end,
+    OffsetBlockEnd,
+    CSS_PROPERTY_PARSE_VALUE |
+        CSS_PROPERTY_STORES_CALC |
+        CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH |
+        CSS_PROPERTY_LOGICAL |
+        CSS_PROPERTY_LOGICAL_BLOCK_AXIS |
+        CSS_PROPERTY_LOGICAL_END_EDGE,
+    "layout.css.vertical-text.enabled",
+    VARIANT_AHLP | VARIANT_CALC,
+    nullptr,
+    Offset,
+    Position,
+    CSS_PROP_NO_OFFSET,
+    eStyleAnimType_None)
+CSS_PROP_LOGICAL(
+    offset-block-start,
+    offset_block_start,
+    OffsetBlockStart,
+    CSS_PROPERTY_PARSE_VALUE |
+        CSS_PROPERTY_STORES_CALC |
+        CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH |
+        CSS_PROPERTY_LOGICAL |
+        CSS_PROPERTY_LOGICAL_BLOCK_AXIS,
+    "layout.css.vertical-text.enabled",
+    VARIANT_AHLP | VARIANT_CALC,
+    nullptr,
+    Offset,
+    Position,
+    CSS_PROP_NO_OFFSET,
+    eStyleAnimType_None)
+CSS_PROP_LOGICAL(
+    offset-inline-end,
+    offset_inline_end,
+    OffsetInlineEnd,
+    CSS_PROPERTY_PARSE_VALUE |
+        CSS_PROPERTY_STORES_CALC |
+        CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH |
+        CSS_PROPERTY_LOGICAL |
+        CSS_PROPERTY_LOGICAL_END_EDGE,
+    "layout.css.vertical-text.enabled",
+    VARIANT_AHLP | VARIANT_CALC,
+    nullptr,
+    Offset,
+    Position,
+    CSS_PROP_NO_OFFSET,
+    eStyleAnimType_None)
+CSS_PROP_LOGICAL(
+    offset-inline-start,
+    offset_inline_start,
+    OffsetInlineStart,
+    CSS_PROPERTY_PARSE_VALUE |
+        CSS_PROPERTY_STORES_CALC |
+        CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH |
+        CSS_PROPERTY_LOGICAL,
+    "layout.css.vertical-text.enabled",
+    VARIANT_AHLP | VARIANT_CALC,
+    nullptr,
+    Offset,
+    Position,
+    CSS_PROP_NO_OFFSET,
+    eStyleAnimType_None)
 CSS_PROP_DISPLAY(
     opacity,
     opacity,
     Opacity,
     CSS_PROPERTY_PARSE_VALUE |
         CSS_PROPERTY_APPLIES_TO_PLACEHOLDER,
     "",
     VARIANT_HN,
@@ -2683,16 +2747,57 @@ CSS_PROP_DISPLAY(
     eStyleAnimType_None)
 CSS_PROP_SHORTHAND(
     padding,
     padding,
     Padding,
     CSS_PROPERTY_PARSE_FUNCTION |
         CSS_PROPERTY_UNITLESS_LENGTH_QUIRK,
     "")
+CSS_PROP_LOGICAL(
+    padding-block-end,
+    padding_block_end,
+    PaddingBlockEnd,
+    CSS_PROPERTY_PARSE_VALUE |
+        CSS_PROPERTY_VALUE_NONNEGATIVE |
+        CSS_PROPERTY_APPLIES_TO_FIRST_LETTER |
+        // This is required by the UA stylesheet and can't be overridden.
+        CSS_PROPERTY_APPLIES_TO_PLACEHOLDER |
+        CSS_PROPERTY_STORES_CALC |
+        CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH |
+        CSS_PROPERTY_LOGICAL |
+        CSS_PROPERTY_LOGICAL_BLOCK_AXIS |
+        CSS_PROPERTY_LOGICAL_END_EDGE,
+    "layout.css.vertical-text.enabled",
+    VARIANT_HLP | VARIANT_CALC,
+    nullptr,
+    Padding,
+    Padding,
+    CSS_PROP_NO_OFFSET,
+    eStyleAnimType_None)
+CSS_PROP_LOGICAL(
+    padding-block-start,
+    padding_block_start,
+    PaddingBlockStart,
+    CSS_PROPERTY_PARSE_VALUE |
+        CSS_PROPERTY_VALUE_NONNEGATIVE |
+        CSS_PROPERTY_APPLIES_TO_FIRST_LETTER |
+        // This is required by the UA stylesheet and can't be overridden.
+        CSS_PROPERTY_APPLIES_TO_PLACEHOLDER |
+        CSS_PROPERTY_STORES_CALC |
+        CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH |
+        CSS_PROPERTY_LOGICAL |
+        CSS_PROPERTY_LOGICAL_BLOCK_AXIS,
+    "layout.css.vertical-text.enabled",
+    VARIANT_HLP | VARIANT_CALC,
+    nullptr,
+    Padding,
+    Padding,
+    CSS_PROP_NO_OFFSET,
+    eStyleAnimType_None)
 CSS_PROP_PADDING(
     padding-bottom,
     padding_bottom,
     PaddingBottom,
     CSS_PROPERTY_PARSE_VALUE |
         CSS_PROPERTY_VALUE_NONNEGATIVE |
         CSS_PROPERTY_APPLIES_TO_FIRST_LETTER |
         // This is required by the UA stylesheet and can't be overridden.
@@ -2700,169 +2805,90 @@ CSS_PROP_PADDING(
         CSS_PROPERTY_STORES_CALC |
         CSS_PROPERTY_UNITLESS_LENGTH_QUIRK |
         CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH,
     "",
     VARIANT_HLP | VARIANT_CALC,
     nullptr,
     offsetof(nsStylePadding, mPadding),
     eStyleAnimType_Sides_Bottom)
-CSS_PROP_SHORTHAND(
+CSS_PROP_LOGICAL(
     -moz-padding-end,
     padding_end,
     CSS_PROP_DOMPROP_PREFIXED(PaddingEnd),
-    CSS_PROPERTY_PARSE_FUNCTION,
-    "")
-#ifndef CSS_PROP_LIST_EXCLUDE_INTERNAL
-CSS_PROP_PADDING(
-    padding-end-value,
-    padding_end_value,
-    PaddingEndValue,
-    CSS_PROPERTY_PARSE_INACCESSIBLE |
+    CSS_PROPERTY_PARSE_VALUE |
         CSS_PROPERTY_VALUE_NONNEGATIVE |
         CSS_PROPERTY_APPLIES_TO_FIRST_LETTER |
         // This is required by the UA stylesheet and can't be overridden.
         CSS_PROPERTY_APPLIES_TO_PLACEHOLDER |
-        CSS_PROPERTY_STORES_CALC,
-    "",
-    VARIANT_HLP | VARIANT_CALC, // for internal use
+        CSS_PROPERTY_STORES_CALC |
+        CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH |
+        CSS_PROPERTY_LOGICAL |
+        CSS_PROPERTY_LOGICAL_END_EDGE,
+    "",
+    VARIANT_HLP | VARIANT_CALC,
     nullptr,
+    Padding,
+    Padding,
     CSS_PROP_NO_OFFSET,
     eStyleAnimType_None)
-#endif
-CSS_PROP_SHORTHAND(
-    padding-left,
-    padding_left,
-    PaddingLeft,
-    CSS_PROPERTY_PARSE_FUNCTION |
-        CSS_PROPERTY_UNITLESS_LENGTH_QUIRK |
-        CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH,
-    "")
-#ifndef CSS_PROP_LIST_EXCLUDE_INTERNAL
-CSS_PROP_PADDING(
-    padding-left-value,
-    padding_left_value,
-    PaddingLeftValue,
-    CSS_PROPERTY_PARSE_INACCESSIBLE |
+CSS_PROP_LOGICAL(
+    -moz-padding-start,
+    padding_start,
+    CSS_PROP_DOMPROP_PREFIXED(PaddingStart),
+    CSS_PROPERTY_PARSE_VALUE |
         CSS_PROPERTY_VALUE_NONNEGATIVE |
         CSS_PROPERTY_APPLIES_TO_FIRST_LETTER |
         // This is required by the UA stylesheet and can't be overridden.
         CSS_PROPERTY_APPLIES_TO_PLACEHOLDER |
-        CSS_PROPERTY_REPORT_OTHER_NAME |
-        CSS_PROPERTY_STORES_CALC,
-    "",
-    VARIANT_HLP | VARIANT_CALC, // for internal use
+        CSS_PROPERTY_STORES_CALC |
+        CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH |
+        CSS_PROPERTY_LOGICAL,
+    "",
+    VARIANT_HLP | VARIANT_CALC,
+    nullptr,
+    Padding,
+    Padding,
+    CSS_PROP_NO_OFFSET,
+    eStyleAnimType_None)
+CSS_PROP_PADDING(
+    padding-left,
+    padding_left,
+    PaddingLeft,
+    CSS_PROPERTY_PARSE_VALUE |
+        CSS_PROPERTY_VALUE_NONNEGATIVE |
+        CSS_PROPERTY_UNITLESS_LENGTH_QUIRK |
+        CSS_PROPERTY_APPLIES_TO_FIRST_LETTER |
+        // This is required by the UA stylesheet and can't be overridden.
+        CSS_PROPERTY_APPLIES_TO_PLACEHOLDER |
+        CSS_PROPERTY_STORES_CALC |
+        CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH,
+    "",
+    VARIANT_HLP | VARIANT_CALC,
     nullptr,
     offsetof(nsStylePadding, mPadding),
     eStyleAnimType_Sides_Left)
 CSS_PROP_PADDING(
-    padding-left-ltr-source,
-    padding_left_ltr_source,
-    PaddingLeftLTRSource,
-    CSS_PROPERTY_PARSE_INACCESSIBLE |
-        CSS_PROPERTY_APPLIES_TO_FIRST_LETTER |
-        // This is required by the UA stylesheet and can't be overridden.
-        CSS_PROPERTY_APPLIES_TO_PLACEHOLDER |
-        CSS_PROPERTY_DIRECTIONAL_SOURCE,
-    "",
-    0,
-    kBoxPropSourceKTable,
-    CSS_PROP_NO_OFFSET,
-    eStyleAnimType_None)
-CSS_PROP_PADDING(
-    padding-left-rtl-source,
-    padding_left_rtl_source,
-    PaddingLeftRTLSource,
-    CSS_PROPERTY_PARSE_INACCESSIBLE |
-        CSS_PROPERTY_APPLIES_TO_FIRST_LETTER |
-        // This is required by the UA stylesheet and can't be overridden.
-        CSS_PROPERTY_APPLIES_TO_PLACEHOLDER |
-        CSS_PROPERTY_DIRECTIONAL_SOURCE,
-    "",
-    0,
-    kBoxPropSourceKTable,
-    CSS_PROP_NO_OFFSET,
-    eStyleAnimType_None)
-#endif
-CSS_PROP_SHORTHAND(
     padding-right,
     padding_right,
     PaddingRight,
-    CSS_PROPERTY_PARSE_FUNCTION |
+    CSS_PROPERTY_PARSE_VALUE |
+        CSS_PROPERTY_VALUE_NONNEGATIVE |
         CSS_PROPERTY_UNITLESS_LENGTH_QUIRK |
-        CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH,
-    "")
-#ifndef CSS_PROP_LIST_EXCLUDE_INTERNAL
-CSS_PROP_PADDING(
-    padding-right-value,
-    padding_right_value,
-    PaddingRightValue,
-    CSS_PROPERTY_PARSE_INACCESSIBLE |
-        CSS_PROPERTY_VALUE_NONNEGATIVE |
         CSS_PROPERTY_APPLIES_TO_FIRST_LETTER |
         // This is required by the UA stylesheet and can't be overridden.
         CSS_PROPERTY_APPLIES_TO_PLACEHOLDER |
-        CSS_PROPERTY_REPORT_OTHER_NAME |
-        CSS_PROPERTY_STORES_CALC,
-    "",
-    VARIANT_HLP | VARIANT_CALC, // for internal use
+        CSS_PROPERTY_STORES_CALC |
+        CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH,
+    "",
+    VARIANT_HLP | VARIANT_CALC,
     nullptr,
     offsetof(nsStylePadding, mPadding),
     eStyleAnimType_Sides_Right)
 CSS_PROP_PADDING(
-    padding-right-ltr-source,
-    padding_right_ltr_source,
-    PaddingRightLTRSource,
-    CSS_PROPERTY_PARSE_INACCESSIBLE |
-        CSS_PROPERTY_APPLIES_TO_FIRST_LETTER |
-        // This is required by the UA stylesheet and can't be overridden.
-        CSS_PROPERTY_APPLIES_TO_PLACEHOLDER |
-        CSS_PROPERTY_DIRECTIONAL_SOURCE,
-    "",
-    0,
-    kBoxPropSourceKTable,
-    CSS_PROP_NO_OFFSET,
-    eStyleAnimType_None)
-CSS_PROP_PADDING(
-    padding-right-rtl-source,
-    padding_right_rtl_source,
-    PaddingRightRTLSource,
-    CSS_PROPERTY_PARSE_INACCESSIBLE |
-        CSS_PROPERTY_APPLIES_TO_FIRST_LETTER |
-        CSS_PROPERTY_DIRECTIONAL_SOURCE,
-    "",
-    0,
-    kBoxPropSourceKTable,
-    CSS_PROP_NO_OFFSET,
-    eStyleAnimType_None)
-#endif
-CSS_PROP_SHORTHAND(
-    -moz-padding-start,
-    padding_start,
-    CSS_PROP_DOMPROP_PREFIXED(PaddingStart),
-    CSS_PROPERTY_PARSE_FUNCTION,
-    "")
-#ifndef CSS_PROP_LIST_EXCLUDE_INTERNAL
-CSS_PROP_PADDING(
-    padding-start-value,
-    padding_start_value,
-    PaddingStartValue,
-    CSS_PROPERTY_PARSE_INACCESSIBLE |
-        CSS_PROPERTY_VALUE_NONNEGATIVE |
-        CSS_PROPERTY_APPLIES_TO_FIRST_LETTER |
-        // This is required by the UA stylesheet and can't be overridden.
-        CSS_PROPERTY_APPLIES_TO_PLACEHOLDER |
-        CSS_PROPERTY_STORES_CALC,
-    "",
-    VARIANT_HLP | VARIANT_CALC, // for internal use
-    nullptr,
-    CSS_PROP_NO_OFFSET,
-    eStyleAnimType_None)
-#endif
-CSS_PROP_PADDING(
     padding-top,
     padding_top,
     PaddingTop,
     CSS_PROPERTY_PARSE_VALUE |
         CSS_PROPERTY_VALUE_NONNEGATIVE |
         CSS_PROPERTY_APPLIES_TO_FIRST_LETTER |
         // This is required by the UA stylesheet and can't be overridden.
         CSS_PROPERTY_APPLIES_TO_PLACEHOLDER |
@@ -4192,10 +4218,14 @@ CSS_PROP_FONT(
 #endif
 
 #endif /* !defined(USED_CSS_PROP) */
 
 #ifdef DEFINED_CSS_PROP_SHORTHAND
 #undef CSS_PROP_SHORTHAND
 #undef DEFINED_CSS_PROP_SHORTHAND
 #endif
+#ifdef DEFINED_CSS_PROP_LOGICAL
+#undef CSS_PROP_LOGICAL
+#undef DEFINED_CSS_PROP_LOGICAL
+#endif
 
 #undef CSS_PROP_DOMPROP_PREFIXED
new file mode 100644
--- /dev/null
+++ b/layout/style/nsCSSPropLogicalGroupList.h
@@ -0,0 +1,56 @@
+/* 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/. */
+
+/*
+ * a list of groups of logical properties, for preprocessing
+ */
+
+// A logical property group is one that defines the corresponding physical
+// longhand properties that could be set by a given set of logical longhand
+// properties.  For example, the logical property group for margin-block-start
+// (and the other three logical margin properties) is one that contains
+// margin-top, margin-right, margin-bottom and margin-left.
+//
+// Logical property groups are defined below using one of the following
+// macros, where the name_ argument must be capitalized LikeThis and
+// must not collide with the name of a property's DOM method (its
+// method_ in nsCSSPropList.h):
+//
+//   CSS_PROP_LOGICAL_GROUP_SHORTHAND(name_)
+//     Defines a logical property group whose corresponding physical
+//     properties are those in a given shorthand.  For example, the
+//     logical property group for margin-{block,inline}-{start,end}
+//     is defined by the margin shorthand.  The name_ argument must
+//     be the method_ name of the shorthand (so Margin rather than
+//     margin).
+//
+//   CSS_PROP_LOGICAL_GROUP_BOX(name_)
+//     Defines a logical property group whose corresponding physical
+//     properties are a set of four box properties which are not
+//     already represented by an existing shorthand property.  For
+//     example, the logical property group for
+//     offset-{block,inline}-{start,end} contains the top, right,
+//     bottom and left physical properties, but there is no shorthand
+//     that sets those four properties.  A table must be defined in
+//     nsCSSProps.cpp named g<name_>LogicalGroupTable containing the
+//     four physical properties in top/right/bottom/left order.
+//
+//   CSS_PROP_LOGICAL_GROUP_AXIS(name_)
+//     Defines a logical property group whose corresponding physical
+//     properties are a set of two axis-related properties.  For
+//     example, the logical property group for {block,inline}-size
+//     contains the width and height properties.  A table must be
+//     defined in nCSSProps.cpp named g<name_>LogicalGroupTable
+//     containing the two physical properties in vertical/horizontal
+//     order, followed by an nsCSSProperty_UNKNOWN entry.
+
+CSS_PROP_LOGICAL_GROUP_SHORTHAND(BorderColor)
+CSS_PROP_LOGICAL_GROUP_SHORTHAND(BorderStyle)
+CSS_PROP_LOGICAL_GROUP_SHORTHAND(BorderWidth)
+CSS_PROP_LOGICAL_GROUP_SHORTHAND(Margin)
+CSS_PROP_LOGICAL_GROUP_AXIS(MaxSize)
+CSS_PROP_LOGICAL_GROUP_BOX(Offset)
+CSS_PROP_LOGICAL_GROUP_SHORTHAND(Padding)
+CSS_PROP_LOGICAL_GROUP_AXIS(MinSize)
+CSS_PROP_LOGICAL_GROUP_AXIS(Size)
--- a/layout/style/nsCSSProperty.h
+++ b/layout/style/nsCSSProperty.h
@@ -16,17 +16,19 @@
 
  */
 enum nsCSSProperty {
   eCSSProperty_UNKNOWN = -1,
 
   #define CSS_PROP(name_, id_, method_, flags_, pref_, parsevariant_, \
                    kwtable_, stylestruct_, stylestructoffset_, animtype_) \
     eCSSProperty_##id_,
+  #define CSS_PROP_LIST_INCLUDE_LOGICAL
   #include "nsCSSPropList.h"
+  #undef CSS_PROP_LIST_INCLUDE_LOGICAL
   #undef CSS_PROP
 
   eCSSProperty_COUNT_no_shorthands,
   // Make the count continue where it left off:
   eCSSProperty_COUNT_DUMMY = eCSSProperty_COUNT_no_shorthands - 1,
 
   #define CSS_PROP_SHORTHAND(name_, id_, method_, flags_, pref_) \
     eCSSProperty_##id_,
@@ -77,9 +79,24 @@ enum nsCSSFontDesc {
 enum nsCSSCounterDesc {
   eCSSCounterDesc_UNKNOWN = -1,
 #define CSS_COUNTER_DESC(name_, method_) eCSSCounterDesc_##method_,
 #include "nsCSSCounterDescList.h"
 #undef CSS_COUNTER_DESC
   eCSSCounterDesc_COUNT
 };
 
+enum nsCSSPropertyLogicalGroup {
+  eCSSPropertyLogicalGroup_UNKNOWN = -1,
+#define CSS_PROP_LOGICAL_GROUP_AXIS(name_) \
+  eCSSPropertyLogicalGroup_##name_,
+#define CSS_PROP_LOGICAL_GROUP_BOX(name_) \
+  eCSSPropertyLogicalGroup_##name_,
+#define CSS_PROP_LOGICAL_GROUP_SHORTHAND(name_) \
+  eCSSPropertyLogicalGroup_##name_,
+#include "nsCSSPropLogicalGroupList.h"
+#undef CSS_PROP_LOGICAL_GROUP_SHORTHAND
+#undef CSS_PROP_LOGICAL_GROUP_BOX
+#undef CSS_PROP_LOGICAL_GROUP_AXIS
+  eCSSPropertyLogicalGroup_COUNT
+};
+
 #endif /* nsCSSProperty_h___ */
--- a/layout/style/nsCSSProps.cpp
+++ b/layout/style/nsCSSProps.cpp
@@ -31,17 +31,19 @@ typedef nsCSSProps::KTableValue KTableVa
 // required to make the symbol external, so that TestCSSPropertyLookup.cpp can link with it
 extern const char* const kCSSRawProperties[];
 
 // define an array of all CSS properties
 const char* const kCSSRawProperties[eCSSProperty_COUNT_with_aliases] = {
 #define CSS_PROP(name_, id_, method_, flags_, pref_, parsevariant_, kwtable_, \
                  stylestruct_, stylestructoffset_, animtype_)                 \
   #name_,
+#define CSS_PROP_LIST_INCLUDE_LOGICAL
 #include "nsCSSPropList.h"
+#undef CSS_PROP_LIST_INCLUDE_LOGICAL
 #undef CSS_PROP
 #define CSS_PROP_SHORTHAND(name_, id_, method_, flags_, pref_) #name_,
 #include "nsCSSPropList.h"
 #undef CSS_PROP_SHORTHAND
 #define CSS_PROP_ALIAS(aliasname_, id_, method_, pref_) #aliasname_,
 #include "nsCSSPropAliasList.h"
 #undef CSS_PROP_ALIAS
 };
@@ -164,31 +166,65 @@ nsCSSProps::AddRefTable(void)
         if (pref_[0]) {                                                       \
           Preferences::AddBoolVarCache(&gPropertyEnabled[id_],                \
                                        pref_);                                \
         }
 
       #define CSS_PROP(name_, id_, method_, flags_, pref_, parsevariant_,     \
                        kwtable_, stylestruct_, stylestructoffset_, animtype_) \
         OBSERVE_PROP(pref_, eCSSProperty_##id_)
+      #define CSS_PROP_LIST_INCLUDE_LOGICAL
       #include "nsCSSPropList.h"
+      #undef CSS_PROP_LIST_INCLUDE_LOGICAL
       #undef CSS_PROP
 
       #define  CSS_PROP_SHORTHAND(name_, id_, method_, flags_, pref_) \
         OBSERVE_PROP(pref_, eCSSProperty_##id_)
       #include "nsCSSPropList.h"
       #undef CSS_PROP_SHORTHAND
 
       #define CSS_PROP_ALIAS(aliasname_, propid_, aliasmethod_, pref_)    \
         OBSERVE_PROP(pref_, eCSSPropertyAlias_##aliasmethod_)
       #include "nsCSSPropAliasList.h"
       #undef CSS_PROP_ALIAS
 
       #undef OBSERVE_PROP
     }
+
+#ifdef DEBUG
+    {
+      // Assert that if CSS_PROPERTY_ALWAYS_ENABLED_IN_UA_SHEETS or
+      // CSS_PROPERTY_ALWAYS_ENABLED_IN_CHROME_OR_CERTIFIED_APP is used on
+      // a shorthand property that all of its component longhands also
+      // has the flag.
+      static uint32_t flagsToCheck[] = {
+        CSS_PROPERTY_ALWAYS_ENABLED_IN_UA_SHEETS,
+        CSS_PROPERTY_ALWAYS_ENABLED_IN_CHROME_OR_CERTIFIED_APP
+      };
+      for (nsCSSProperty shorthand = eCSSProperty_COUNT_no_shorthands;
+           shorthand < eCSSProperty_COUNT;
+           shorthand = nsCSSProperty(shorthand + 1)) {
+        for (size_t i = 0; i < ArrayLength(flagsToCheck); i++) {
+          uint32_t flag = flagsToCheck[i];
+          if (!nsCSSProps::PropHasFlags(shorthand, flag)) {
+            continue;
+          }
+          for (const nsCSSProperty* p =
+                 nsCSSProps::SubpropertyEntryFor(shorthand);
+               *p != eCSSProperty_UNKNOWN;
+               ++p) {
+            MOZ_ASSERT(nsCSSProps::PropHasFlags(*p, flag),
+                       "all subproperties of a property with a "
+                       "CSS_PROPERTY_ALWAYS_ENABLED_* flag must also have "
+                       "the flag");
+          }
+        }
+      }
+    }
+#endif
   }
 }
 
 #undef  DEBUG_SHORTHANDS_CONTAINING
 
 bool
 nsCSSProps::BuildShorthandsContainingTable()
 {
@@ -549,46 +585,16 @@ nsCSSProps::GetStringValue(nsCSSCounterD
   if (gCounterDescTable) {
     return gCounterDescTable->GetStringValue(int32_t(aCounterDesc));
   } else {
     static nsDependentCString sNullStr("");
     return sNullStr;
   }
 }
 
-nsCSSProperty
-nsCSSProps::OtherNameFor(nsCSSProperty aProperty)
-{
-  switch (aProperty) {
-    case eCSSProperty_border_left_color_value:
-      return eCSSProperty_border_left_color;
-    case eCSSProperty_border_left_style_value:
-      return eCSSProperty_border_left_style;
-    case eCSSProperty_border_left_width_value:
-      return eCSSProperty_border_left_width;
-    case eCSSProperty_border_right_color_value:
-      return eCSSProperty_border_right_color;
-    case eCSSProperty_border_right_style_value:
-      return eCSSProperty_border_right_style;
-    case eCSSProperty_border_right_width_value:
-      return eCSSProperty_border_right_width;
-    case eCSSProperty_margin_left_value:
-      return eCSSProperty_margin_left;
-    case eCSSProperty_margin_right_value:
-      return eCSSProperty_margin_right;
-    case eCSSProperty_padding_left_value:
-      return eCSSProperty_padding_left;
-    case eCSSProperty_padding_right_value:
-      return eCSSProperty_padding_right;
-    default:
-      NS_ABORT_IF_FALSE(false, "bad caller");
-  }
-  return eCSSProperty_UNKNOWN;
-}
-
 /***************************************************************************/
 
 const KTableValue nsCSSProps::kAnimationDirectionKTable[] = {
   eCSSKeyword_normal, NS_STYLE_ANIMATION_DIRECTION_NORMAL,
   eCSSKeyword_reverse, NS_STYLE_ANIMATION_DIRECTION_REVERSE,
   eCSSKeyword_alternate, NS_STYLE_ANIMATION_DIRECTION_ALTERNATE,
   eCSSKeyword_alternate_reverse, NS_STYLE_ANIMATION_DIRECTION_ALTERNATE_REVERSE,
   eCSSKeyword_UNKNOWN,-1
@@ -856,22 +862,16 @@ const KTableValue nsCSSProps::kBorderSty
 
 const KTableValue nsCSSProps::kBorderWidthKTable[] = {
   eCSSKeyword_thin, NS_STYLE_BORDER_WIDTH_THIN,
   eCSSKeyword_medium, NS_STYLE_BORDER_WIDTH_MEDIUM,
   eCSSKeyword_thick, NS_STYLE_BORDER_WIDTH_THICK,
   eCSSKeyword_UNKNOWN,-1
 };
 
-const KTableValue nsCSSProps::kBoxPropSourceKTable[] = {
-  eCSSKeyword_physical,     NS_BOXPROP_SOURCE_PHYSICAL,
-  eCSSKeyword_logical,      NS_BOXPROP_SOURCE_LOGICAL,
-  eCSSKeyword_UNKNOWN,-1
-};
-
 const KTableValue nsCSSProps::kBoxDecorationBreakKTable[] = {
   eCSSKeyword_slice, NS_STYLE_BOX_DECORATION_BREAK_SLICE,
   eCSSKeyword_clone, NS_STYLE_BOX_DECORATION_BREAK_CLONE,
   eCSSKeyword_UNKNOWN,-1
 };
 
 const KTableValue nsCSSProps::kBoxShadowTypeKTable[] = {
   eCSSKeyword_inset, NS_STYLE_BOX_SHADOW_INSET,
@@ -2113,17 +2113,19 @@ nsCSSProps::ValueToKeyword(int32_t aValu
   }
 }
 
 /* static */ const KTableValue* const
 nsCSSProps::kKeywordTableTable[eCSSProperty_COUNT_no_shorthands] = {
   #define CSS_PROP(name_, id_, method_, flags_, pref_, parsevariant_,     \
                    kwtable_, stylestruct_, stylestructoffset_, animtype_) \
     kwtable_,
+  #define CSS_PROP_LIST_INCLUDE_LOGICAL
   #include "nsCSSPropList.h"
+  #undef CSS_PROP_LIST_INCLUDE_LOGICAL
   #undef CSS_PROP
 };
 
 const nsAFlatCString&
 nsCSSProps::LookupPropertyValue(nsCSSProperty aProp, int32_t aValue)
 {
   NS_ABORT_IF_FALSE(aProp >= 0 && aProp < eCSSProperty_COUNT,
                     "property out of range");
@@ -2159,58 +2161,68 @@ bool nsCSSProps::GetColorName(int32_t aP
 
 const nsStyleStructID nsCSSProps::kSIDTable[eCSSProperty_COUNT_no_shorthands] = {
     // Note that this uses the special BackendOnly style struct ID
     // (which does need to be valid for storing in the
     // nsCSSCompressedDataBlock::mStyleBits bitfield).
     #define CSS_PROP(name_, id_, method_, flags_, pref_, parsevariant_,     \
                      kwtable_, stylestruct_, stylestructoffset_, animtype_) \
         eStyleStruct_##stylestruct_,
+    #define CSS_PROP_LIST_INCLUDE_LOGICAL
 
     #include "nsCSSPropList.h"
 
+    #undef CSS_PROP_LIST_INCLUDE_LOGICAL
     #undef CSS_PROP
 };
 
 const nsStyleAnimType
 nsCSSProps::kAnimTypeTable[eCSSProperty_COUNT_no_shorthands] = {
 #define CSS_PROP(name_, id_, method_, flags_, pref_, parsevariant_, kwtable_, \
                  stylestruct_, stylestructoffset_, animtype_)                 \
   animtype_,
+#define CSS_PROP_LIST_INCLUDE_LOGICAL
 #include "nsCSSPropList.h"
+#undef CSS_PROP_LIST_INCLUDE_LOGICAL
 #undef CSS_PROP
 };
 
 const ptrdiff_t
 nsCSSProps::kStyleStructOffsetTable[eCSSProperty_COUNT_no_shorthands] = {
 #define CSS_PROP(name_, id_, method_, flags_, pref_, parsevariant_, kwtable_, \
                  stylestruct_, stylestructoffset_, animtype_)                 \
   stylestructoffset_,
+#define CSS_PROP_LIST_INCLUDE_LOGICAL
 #include "nsCSSPropList.h"
+#undef CSS_PROP_LIST_INCLUDE_LOGICAL
 #undef CSS_PROP
 };
 
 const uint32_t nsCSSProps::kFlagsTable[eCSSProperty_COUNT] = {
 #define CSS_PROP(name_, id_, method_, flags_, pref_, parsevariant_, kwtable_, \
                  stylestruct_, stylestructoffset_, animtype_)                 \
   flags_,
+#define CSS_PROP_LIST_INCLUDE_LOGICAL
 #include "nsCSSPropList.h"
+#undef CSS_PROP_LIST_INCLUDE_LOGICAL
 #undef CSS_PROP
 #define CSS_PROP_SHORTHAND(name_, id_, method_, flags_, pref_) flags_,
 #include "nsCSSPropList.h"
 #undef CSS_PROP_SHORTHAND
 };
 
 static const nsCSSProperty gAllSubpropTable[] = {
 #define CSS_PROP_LIST_ONLY_COMPONENTS_OF_ALL_SHORTHAND
+#define CSS_PROP_LIST_INCLUDE_LOGICAL
 #define CSS_PROP(name_, id_, method_, flags_, pref_, parsevariant_, kwtable_, \
                  stylestruct_, stylestructoffset_, animtype_)                 \
   eCSSProperty_##id_,
 #include "nsCSSPropList.h"
 #undef CSS_PROP
+#undef CSS_PROP_LIST_INCLUDE_LOGICAL
 #undef CSS_PROP_LIST_ONLY_COMPONENTS_OF_ALL_SHORTHAND
   eCSSProperty_UNKNOWN
 };
 
 static const nsCSSProperty gAnimationSubpropTable[] = {
   eCSSProperty_animation_duration,
   eCSSProperty_animation_timing_function,
   eCSSProperty_animation_delay,
@@ -2254,272 +2266,139 @@ static const nsCSSProperty gBackgroundSu
   eCSSProperty_background_clip,
   eCSSProperty_background_origin,
   eCSSProperty_background_size,
   eCSSProperty_UNKNOWN
 };
 
 static const nsCSSProperty gBorderSubpropTable[] = {
   eCSSProperty_border_top_width,
-  eCSSProperty_border_right_width_value,
-  eCSSProperty_border_right_width_ltr_source,
-  eCSSProperty_border_right_width_rtl_source,
+  eCSSProperty_border_right_width,
   eCSSProperty_border_bottom_width,
-  eCSSProperty_border_left_width_value,
-  eCSSProperty_border_left_width_ltr_source,
-  eCSSProperty_border_left_width_rtl_source,
+  eCSSProperty_border_left_width,
   eCSSProperty_border_top_style,
-  eCSSProperty_border_right_style_value,
-  eCSSProperty_border_right_style_ltr_source,
-  eCSSProperty_border_right_style_rtl_source,
+  eCSSProperty_border_right_style,
   eCSSProperty_border_bottom_style,
-  eCSSProperty_border_left_style_value,
-  eCSSProperty_border_left_style_ltr_source,
-  eCSSProperty_border_left_style_rtl_source,
+  eCSSProperty_border_left_style,
   eCSSProperty_border_top_color,
-  eCSSProperty_border_right_color_value,
-  eCSSProperty_border_right_color_ltr_source,
-  eCSSProperty_border_right_color_rtl_source,
+  eCSSProperty_border_right_color,
   eCSSProperty_border_bottom_color,
-  eCSSProperty_border_left_color_value,
-  eCSSProperty_border_left_color_ltr_source,
-  eCSSProperty_border_left_color_rtl_source,
+  eCSSProperty_border_left_color,
   eCSSProperty_border_top_colors,
   eCSSProperty_border_right_colors,
   eCSSProperty_border_bottom_colors,
   eCSSProperty_border_left_colors,
   eCSSProperty_border_image_source,
   eCSSProperty_border_image_slice,
   eCSSProperty_border_image_width,
   eCSSProperty_border_image_outset,
   eCSSProperty_border_image_repeat,
   eCSSProperty_UNKNOWN
 };
 
+static const nsCSSProperty gBorderBlockEndSubpropTable[] = {
+  // Declaration.cpp outputs the subproperties in this order.
+  // It also depends on the color being third.
+  eCSSProperty_border_block_end_width,
+  eCSSProperty_border_block_end_style,
+  eCSSProperty_border_block_end_color,
+  eCSSProperty_UNKNOWN
+};
+
+static const nsCSSProperty gBorderBlockStartSubpropTable[] = {
+  // Declaration.cpp outputs the subproperties in this order.
+  // It also depends on the color being third.
+  eCSSProperty_border_block_start_width,
+  eCSSProperty_border_block_start_style,
+  eCSSProperty_border_block_start_color,
+  eCSSProperty_UNKNOWN
+};
+
 static const nsCSSProperty gBorderBottomSubpropTable[] = {
-  // nsCSSDeclaration.cpp outputs the subproperties in this order.
+  // Declaration.cpp outputs the subproperties in this order.
   // It also depends on the color being third.
   eCSSProperty_border_bottom_width,
   eCSSProperty_border_bottom_style,
   eCSSProperty_border_bottom_color,
   eCSSProperty_UNKNOWN
 };
 
 static_assert(NS_SIDE_TOP == 0 && NS_SIDE_RIGHT == 1 &&
               NS_SIDE_BOTTOM == 2 && NS_SIDE_LEFT == 3,
               "box side constants not top/right/bottom/left == 0/1/2/3");
 static const nsCSSProperty gBorderColorSubpropTable[] = {
   // Code relies on these being in top-right-bottom-left order.
   // Code relies on these matching the NS_SIDE_* constants.
   eCSSProperty_border_top_color,
-  eCSSProperty_border_right_color_value,
+  eCSSProperty_border_right_color,
   eCSSProperty_border_bottom_color,
-  eCSSProperty_border_left_color_value,
-  // extras:
-  eCSSProperty_border_left_color_ltr_source,
-  eCSSProperty_border_left_color_rtl_source,
-  eCSSProperty_border_right_color_ltr_source,
-  eCSSProperty_border_right_color_rtl_source,
-  eCSSProperty_UNKNOWN
-};
-
-static const nsCSSProperty gBorderEndColorSubpropTable[] = {
-  // nsCSSParser::ParseDirectionalBoxProperty depends on this order
-  eCSSProperty_border_end_color_value,
-  eCSSProperty_border_right_color_ltr_source,
-  eCSSProperty_border_left_color_rtl_source,
-  eCSSProperty_UNKNOWN
-};
-
-static const nsCSSProperty gBorderLeftColorSubpropTable[] = {
-  // nsCSSParser::ParseDirectionalBoxProperty depends on this order
-  eCSSProperty_border_left_color_value,
-  eCSSProperty_border_left_color_ltr_source,
-  eCSSProperty_border_left_color_rtl_source,
-  eCSSProperty_UNKNOWN
-};
-
-static const nsCSSProperty gBorderRightColorSubpropTable[] = {
-  // nsCSSParser::ParseDirectionalBoxProperty depends on this order
-  eCSSProperty_border_right_color_value,
-  eCSSProperty_border_right_color_ltr_source,
-  eCSSProperty_border_right_color_rtl_source,
-  eCSSProperty_UNKNOWN
-};
-
-static const nsCSSProperty gBorderStartColorSubpropTable[] = {
-  // nsCSSParser::ParseDirectionalBoxProperty depends on this order
-  eCSSProperty_border_start_color_value,
-  eCSSProperty_border_left_color_ltr_source,
-  eCSSProperty_border_right_color_rtl_source,
+  eCSSProperty_border_left_color,
   eCSSProperty_UNKNOWN
 };
 
 static const nsCSSProperty gBorderEndSubpropTable[] = {
-  // nsCSSDeclaration.cpp output the subproperties in this order.
+  // Declaration.cpp output the subproperties in this order.
   // It also depends on the color being third.
-  eCSSProperty_border_end_width_value,
-  eCSSProperty_border_end_style_value,
-  eCSSProperty_border_end_color_value,
-  // extras:
-  eCSSProperty_border_right_width_ltr_source,
-  eCSSProperty_border_left_width_rtl_source,
-  eCSSProperty_border_right_style_ltr_source,
-  eCSSProperty_border_left_style_rtl_source,
-  eCSSProperty_border_right_color_ltr_source,
-  eCSSProperty_border_left_color_rtl_source,
+  eCSSProperty_border_end_width,
+  eCSSProperty_border_end_style,
+  eCSSProperty_border_end_color,
   eCSSProperty_UNKNOWN
 };
 
 static const nsCSSProperty gBorderLeftSubpropTable[] = {
-  // nsCSSDeclaration.cpp outputs the subproperties in this order.
+  // Declaration.cpp outputs the subproperties in this order.
   // It also depends on the color being third.
-  eCSSProperty_border_left_width_value,
-  eCSSProperty_border_left_style_value,
-  eCSSProperty_border_left_color_value,
-  // extras:
-  eCSSProperty_border_left_width_ltr_source,
-  eCSSProperty_border_left_width_rtl_source,
-  eCSSProperty_border_left_style_ltr_source,
-  eCSSProperty_border_left_style_rtl_source,
-  eCSSProperty_border_left_color_ltr_source,
-  eCSSProperty_border_left_color_rtl_source,
+  eCSSProperty_border_left_width,
+  eCSSProperty_border_left_style,
+  eCSSProperty_border_left_color,
   eCSSProperty_UNKNOWN
 };
 
 static const nsCSSProperty gBorderRightSubpropTable[] = {
-  // nsCSSDeclaration.cpp outputs the subproperties in this order.
+  // Declaration.cpp outputs the subproperties in this order.
   // It also depends on the color being third.
-  eCSSProperty_border_right_width_value,
-  eCSSProperty_border_right_style_value,
-  eCSSProperty_border_right_color_value,
-  // extras:
-  eCSSProperty_border_right_width_ltr_source,
-  eCSSProperty_border_right_width_rtl_source,
-  eCSSProperty_border_right_style_ltr_source,
-  eCSSProperty_border_right_style_rtl_source,
-  eCSSProperty_border_right_color_ltr_source,
-  eCSSProperty_border_right_color_rtl_source,
+  eCSSProperty_border_right_width,
+  eCSSProperty_border_right_style,
+  eCSSProperty_border_right_color,
   eCSSProperty_UNKNOWN
 };
 
 static const nsCSSProperty gBorderStartSubpropTable[] = {
-  // nsCSSDeclaration.cpp outputs the subproperties in this order.
+  // Declaration.cpp outputs the subproperties in this order.
   // It also depends on the color being third.
-  eCSSProperty_border_start_width_value,
-  eCSSProperty_border_start_style_value,
-  eCSSProperty_border_start_color_value,
-  // extras:
-  eCSSProperty_border_left_width_ltr_source,
-  eCSSProperty_border_right_width_rtl_source,
-  eCSSProperty_border_left_style_ltr_source,