Merge m-c to f-t
authorPhil Ringnalda <philringnalda@gmail.com>
Sat, 19 Apr 2014 18:31:04 -0700
changeset 179785 53a7716781454e6ba40ac94d010b4809d5c09d95
parent 179784 62bedf537dfd51b81f1c52cf2346201fb604a283 (current diff)
parent 179768 53a6c96cea62c46160ce9ea80e0d9188fe5ed2df (diff)
child 179786 f6b4679502a976c7b1ab5cfdd5524ce67aaf554d
push id272
push userpvanderbeken@mozilla.com
push dateMon, 05 May 2014 16:31:18 +0000
milestone31.0a1
Merge m-c to f-t
layout/reftests/backgrounds/background-size-bounding-box.html
layout/reftests/backgrounds/background-size-continuous.html
layout/reftests/backgrounds/background-size-cover-bounding-box.html
layout/reftests/backgrounds/background-size-cover-continuous.html
layout/reftests/backgrounds/background-size-cover-each-box.html
layout/reftests/backgrounds/background-size-each-box.html
layout/reftests/bugs/368020-4-ref.html
layout/reftests/bugs/368020-4.html
--- 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="1ad48c4be51b279f7f63c1a13025b52fe087d231">
     <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="7e93b6de9633a162b735252e8182974456f741f4"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="eb97461e75cd44d20967bc410b5653dff031ef5a"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="55bcc2d7e44dc805c24b57d1e783fc26e8a2ee86"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="99a67a75855d8ca077018c819aedd90bf0447d9b"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d6c36d74ba9aefbc8c3618fc93dd4907a0dbf5e"/>
   <!-- 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="e6383e6e785cc3ea237e902beb1092f9aa88e29d">
     <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="7e93b6de9633a162b735252e8182974456f741f4"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="eb97461e75cd44d20967bc410b5653dff031ef5a"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d6c36d74ba9aefbc8c3618fc93dd4907a0dbf5e"/>
   <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="52c909ccead537f8f9dbf634f3e6639078a8b0bd">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="7e93b6de9633a162b735252e8182974456f741f4"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="eb97461e75cd44d20967bc410b5653dff031ef5a"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
   <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="8d6c36d74ba9aefbc8c3618fc93dd4907a0dbf5e"/>
   <!-- Stock Android things -->
--- 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="1ad48c4be51b279f7f63c1a13025b52fe087d231">
     <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="7e93b6de9633a162b735252e8182974456f741f4"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="eb97461e75cd44d20967bc410b5653dff031ef5a"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="55bcc2d7e44dc805c24b57d1e783fc26e8a2ee86"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="99a67a75855d8ca077018c819aedd90bf0447d9b"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d6c36d74ba9aefbc8c3618fc93dd4907a0dbf5e"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- a/b2g/config/flame/sources.xml
+++ b/b2g/config/flame/sources.xml
@@ -13,17 +13,17 @@
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="e6383e6e785cc3ea237e902beb1092f9aa88e29d">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="7e93b6de9633a162b735252e8182974456f741f4"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="eb97461e75cd44d20967bc410b5653dff031ef5a"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d6c36d74ba9aefbc8c3618fc93dd4907a0dbf5e"/>
   <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": "38d1561fe26c12f371c44a47c498722ce06518c2", 
+    "revision": "27357877d17b1547c81a26b66e97a27ed7b954ca", 
     "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="1ad48c4be51b279f7f63c1a13025b52fe087d231">
     <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="7e93b6de9633a162b735252e8182974456f741f4"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="eb97461e75cd44d20967bc410b5653dff031ef5a"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d6c36d74ba9aefbc8c3618fc93dd4907a0dbf5e"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
--- 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="1ad48c4be51b279f7f63c1a13025b52fe087d231">
     <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="7e93b6de9633a162b735252e8182974456f741f4"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="eb97461e75cd44d20967bc410b5653dff031ef5a"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
   <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" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
--- a/b2g/config/inari/sources.xml
+++ b/b2g/config/inari/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="ics_chocolate_rb4.2" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="1ad48c4be51b279f7f63c1a13025b52fe087d231">
     <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="7e93b6de9633a162b735252e8182974456f741f4"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="eb97461e75cd44d20967bc410b5653dff031ef5a"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d6c36d74ba9aefbc8c3618fc93dd4907a0dbf5e"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="cd5dfce80bc3f0139a56b58aca633202ccaee7f8"/>
--- a/b2g/config/leo/sources.xml
+++ b/b2g/config/leo/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="1ad48c4be51b279f7f63c1a13025b52fe087d231">
     <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="7e93b6de9633a162b735252e8182974456f741f4"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="eb97461e75cd44d20967bc410b5653dff031ef5a"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d6c36d74ba9aefbc8c3618fc93dd4907a0dbf5e"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
--- a/b2g/config/mako/sources.xml
+++ b/b2g/config/mako/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="e6383e6e785cc3ea237e902beb1092f9aa88e29d">
     <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="7e93b6de9633a162b735252e8182974456f741f4"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="eb97461e75cd44d20967bc410b5653dff031ef5a"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d6c36d74ba9aefbc8c3618fc93dd4907a0dbf5e"/>
   <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="1ad48c4be51b279f7f63c1a13025b52fe087d231">
     <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="7e93b6de9633a162b735252e8182974456f741f4"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="eb97461e75cd44d20967bc410b5653dff031ef5a"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d6c36d74ba9aefbc8c3618fc93dd4907a0dbf5e"/>
   <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
@@ -666,16 +666,19 @@ pref("plugins.hideMissingPluginsNotifica
 #ifdef RELEASE_BUILD
 // For now, plugins other than Java and Flash are enabled in beta/release
 // and click-to-activate in earlier channels.
 pref("plugin.default.state", 2);
 #else
 pref("plugin.default.state", 1);
 #endif
 
+// Plugins bundled in XPIs are enabled by default.
+pref("plugin.defaultXpi.state", 2);
+
 // Flash is enabled by default, and Java is click-to-activate by default on
 // all channels.
 pref("plugin.state.flash", 2);
 pref("plugin.state.java", 1);
 
 // display door hanger if flash not installed
 pref("plugins.notifyMissingFlash", true);
 
--- a/caps/idl/nsIScriptSecurityManager.idl
+++ b/caps/idl/nsIScriptSecurityManager.idl
@@ -6,17 +6,17 @@
 #include "nsISupports.idl"
 #include "nsIPrincipal.idl"
 #include "nsIXPCSecurityManager.idl"
 interface nsIURI;
 interface nsIChannel;
 interface nsIDocShell;
 interface nsIDomainPolicy;
 
-[scriptable, uuid(3b6e408b-e774-4612-89e8-3ef303564392)]
+[scriptable, uuid(4c087cc3-e0cc-4ec3-88df-8d68f3023b45)]
 interface nsIScriptSecurityManager : nsIXPCSecurityManager
 {
     /**
      * Check that the script currently running in context "cx" can load "uri".
      *
      * Will return error code NS_ERROR_DOM_BAD_URI if the load request
      * should be denied.
      *
@@ -146,21 +146,16 @@ interface nsIScriptSecurityManager : nsI
     /**
      * Legacy name for getNoAppCodebasePrincipal.
      *
      * @deprecated use getNoAppCodebasePrincipal instead.
      */
     [deprecated] nsIPrincipal getCodebasePrincipal(in nsIURI uri);
 
     /**
-     * Return the principal of the specified object in the specified context.
-     */
-    [implicit_jscontext] nsIPrincipal getObjectPrincipal(in jsval aObject);
-
-    /**
      * Returns true if the principal of the currently running script is the
      * system principal, false otherwise.
      */
     [noscript] boolean subjectPrincipalIsSystem();
 
     /**
      * Returns OK if aJSContext and target have the same "origin"
      * (scheme, host, and port).
--- a/caps/src/nsScriptSecurityManager.cpp
+++ b/caps/src/nsScriptSecurityManager.cpp
@@ -1113,28 +1113,16 @@ nsScriptSecurityManager::GetSubjectPrinc
     // The context should always be in a compartment, either one it has entered
     // or the one associated with its global.
     MOZ_ASSERT(!!compartment);
 
     JSPrincipals *principals = JS_GetCompartmentPrincipals(compartment);
     return nsJSPrincipals::get(principals);
 }
 
-NS_IMETHODIMP
-nsScriptSecurityManager::GetObjectPrincipal(JS::Handle<JS::Value> aObjectVal,
-                                            JSContext *aCx,
-                                            nsIPrincipal **result)
-{
-    NS_ENSURE_TRUE(aObjectVal.isObject(), NS_ERROR_FAILURE);
-    JS::RootedObject obj(aCx, &aObjectVal.toObject());
-    nsCOMPtr<nsIPrincipal> principal = doGetObjectPrincipal(obj);
-    principal.forget(result);
-    return NS_OK;
-}
-
 // static
 nsIPrincipal*
 nsScriptSecurityManager::doGetObjectPrincipal(JSObject *aObj)
 {
     JSCompartment *compartment = js::GetObjectCompartment(aObj);
     JSPrincipals *principals = JS_GetCompartmentPrincipals(compartment);
     return nsJSPrincipals::get(principals);
 }
--- a/content/base/src/nsInProcessTabChildGlobal.cpp
+++ b/content/base/src/nsInProcessTabChildGlobal.cpp
@@ -96,17 +96,17 @@ nsInProcessTabChildGlobal::DoSendAsyncMe
   NS_DispatchToCurrentThread(ev);
   return true;
 }
 
 nsInProcessTabChildGlobal::nsInProcessTabChildGlobal(nsIDocShell* aShell,
                                                      nsIContent* aOwner,
                                                      nsFrameMessageManager* aChrome)
 : mDocShell(aShell), mInitialized(false), mLoadingScript(false),
-  mDelayedDisconnect(false), mOwner(aOwner), mChromeMessageManager(aChrome)
+  mOwner(aOwner), mChromeMessageManager(aChrome)
 {
 
   // If owner corresponds to an <iframe mozbrowser> or <iframe mozapp>, we'll
   // have to tweak our PreHandleEvent implementation.
   nsCOMPtr<nsIMozBrowserFrame> browserFrame = do_QueryInterface(mOwner);
   if (browserFrame) {
     mIsBrowserOrAppFrame = browserFrame->GetReallyIsBrowserOrApp();
   }
@@ -229,23 +229,16 @@ nsInProcessTabChildGlobal::DelayedDiscon
   mChromeMessageManager = nullptr;
   if (mMessageManager) {
     static_cast<nsFrameMessageManager*>(mMessageManager.get())->Disconnect();
     mMessageManager = nullptr;
   }
   if (mListenerManager) {
     mListenerManager->Disconnect();
   }
-
-  if (!mLoadingScript) {
-    ReleaseWrapper(static_cast<EventTarget*>(this));
-    mGlobal = nullptr;
-  } else {
-    mDelayedDisconnect = true;
-  }
 }
 
 NS_IMETHODIMP_(nsIContent *)
 nsInProcessTabChildGlobal::GetOwnerContent()
 {
   return mOwner;
 }
 
@@ -326,13 +319,9 @@ nsInProcessTabChildGlobal::LoadFrameScri
   if (!mInitialized) {
     mInitialized = true;
     Init();
   }
   bool tmp = mLoadingScript;
   mLoadingScript = true;
   LoadFrameScriptInternal(aURL, aRunInGlobalScope);
   mLoadingScript = tmp;
-  if (!mLoadingScript && mDelayedDisconnect) {
-    mDelayedDisconnect = false;
-    Disconnect();
-  }
 }
--- a/content/base/src/nsInProcessTabChildGlobal.h
+++ b/content/base/src/nsInProcessTabChildGlobal.h
@@ -156,17 +156,16 @@ public:
   }
 protected:
   nsresult Init();
   nsresult InitTabChildGlobal();
   nsCOMPtr<nsIContentFrameMessageManager> mMessageManager;
   nsCOMPtr<nsIDocShell> mDocShell;
   bool mInitialized;
   bool mLoadingScript;
-  bool mDelayedDisconnect;
 
   // Is this the message manager for an in-process <iframe mozbrowser> or
   // <iframe mozapp>?  This affects where events get sent, so it affects
   // PreHandleEvent.
   bool mIsBrowserOrAppFrame;
 public:
   nsIContent* mOwner;
   nsFrameMessageManager* mChromeMessageManager;
--- a/dom/plugins/base/nsPluginHost.cpp
+++ b/dom/plugins/base/nsPluginHost.cpp
@@ -138,18 +138,19 @@ static const char *kPrefJavaMIME = "plug
 // 0.09 the file encoding is changed to UTF-8, bug 420285
 // 0.10 added plugin versions on appropriate platforms, bug 427743
 // 0.11 file name and full path fields now store expected values on all platforms, bug 488181
 // 0.12 force refresh due to quicktime pdf claim fix, bug 611197
 // 0.13 add architecture and list of invalid plugins, bug 616271
 // 0.14 force refresh due to locale comparison fix, bug 611296
 // 0.15 force refresh due to bug in reading Java plist MIME data, bug 638171
 // 0.16 version bump to avoid importing the plugin flags in newer versions
+// 0.17 added flag on whether plugin is loaded from an XPI
 // The current plugin registry version (and the maximum version we know how to read)
-static const char *kPluginRegistryVersion = "0.16";
+static const char *kPluginRegistryVersion = "0.17";
 // The minimum registry version we know how to read
 static const char *kMinimumRegistryVersion = "0.9";
 
 static const char kDirectoryServiceContractID[] = "@mozilla.org/file/directory_service;1";
 
 #define kPluginRegistryFilename NS_LITERAL_CSTRING("pluginreg.dat")
 
 #ifdef PLUGIN_LOGGING
@@ -1622,16 +1623,72 @@ int64_t GetPluginLastModifiedTime(const 
   }
 #else
   localfile->GetLastModifiedTime(&fileModTime);
 #endif
 
   return fileModTime;
 }
 
+bool
+GetPluginIsFromExtension(const nsCOMPtr<nsIFile>& pluginFile,
+                         const nsCOMPtr<nsISimpleEnumerator>& extensionDirs)
+{
+  if (!extensionDirs) {
+    return false;
+  }
+
+  bool hasMore;
+  while (NS_SUCCEEDED(extensionDirs->HasMoreElements(&hasMore)) && hasMore) {
+    nsCOMPtr<nsISupports> supports;
+    nsresult rv = extensionDirs->GetNext(getter_AddRefs(supports));
+    if (NS_FAILED(rv)) {
+      continue;
+    }
+
+    nsCOMPtr<nsIFile> extDir(do_QueryInterface(supports, &rv));
+    if (NS_FAILED(rv)) {
+      continue;
+    }
+
+    nsCOMPtr<nsIFile> dir;
+    if (NS_FAILED(extDir->Clone(getter_AddRefs(dir)))) {
+      continue;
+    }
+
+    bool contains;
+    if (NS_FAILED(dir->Contains(pluginFile, true, &contains)) || !contains) {
+      continue;
+    }
+
+    return true;
+  }
+
+  return false;
+}
+
+nsCOMPtr<nsISimpleEnumerator>
+GetExtensionDirectories()
+{
+  nsCOMPtr<nsIProperties> dirService = do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID);
+  if (!dirService) {
+    return nullptr;
+  }
+
+  nsCOMPtr<nsISimpleEnumerator> list;
+  nsresult rv = dirService->Get(XRE_EXTENSIONS_DIR_LIST,
+                                NS_GET_IID(nsISimpleEnumerator),
+                                getter_AddRefs(list));
+  if (NS_FAILED(rv)) {
+    return nullptr;
+  }
+
+  return list;
+}
+
 struct CompareFilesByTime
 {
   bool
   LessThan(const nsCOMPtr<nsIFile>& a, const nsCOMPtr<nsIFile>& b) const
   {
     return GetPluginLastModifiedTime(a) < GetPluginLastModifiedTime(b);
   }
 
@@ -1685,27 +1742,33 @@ nsresult nsPluginHost::ScanPluginsDirect
 
     if (nsPluginsDir::IsPluginFile(dirEntry)) {
       pluginFiles.AppendElement(dirEntry);
     }
   }
 
   pluginFiles.Sort(CompareFilesByTime());
 
+  nsCOMPtr<nsISimpleEnumerator> extensionDirs = GetExtensionDirectories();
+  if (!extensionDirs) {
+    PLUGIN_LOG(PLUGIN_LOG_ALWAYS, ("Could not get extension directories."));
+  }
+
   bool warnOutdated = false;
 
   for (int32_t i = (pluginFiles.Length() - 1); i >= 0; i--) {
     nsCOMPtr<nsIFile>& localfile = pluginFiles[i];
 
     nsString utf16FilePath;
     rv = localfile->GetPath(utf16FilePath);
     if (NS_FAILED(rv))
       continue;
 
-    int64_t fileModTime = GetPluginLastModifiedTime(localfile);
+    const int64_t fileModTime = GetPluginLastModifiedTime(localfile);
+    const bool fromExtension = GetPluginIsFromExtension(localfile, extensionDirs);
 
     // Look for it in our cache
     NS_ConvertUTF16toUTF8 filePath(utf16FilePath);
     nsRefPtr<nsPluginTag> pluginTag;
     RemoveCachedPluginsInfo(filePath.get(), getter_AddRefs(pluginTag));
 
     bool seenBefore = false;
 
@@ -1776,17 +1839,17 @@ nsresult nsPluginHost::ScanPluginsDirect
         }
         mInvalidPlugins = invalidTag;
 
         // Mark aPluginsChanged so pluginreg is rewritten
         *aPluginsChanged = true;
         continue;
       }
 
-      pluginTag = new nsPluginTag(&info, fileModTime);
+      pluginTag = new nsPluginTag(&info, fileModTime, fromExtension);
       pluginFile.FreePluginInfo(info);
       if (!pluginTag)
         return NS_ERROR_OUT_OF_MEMORY;
 
       pluginTag->mLibrary = library;
       uint32_t state = pluginTag->GetBlocklistState();
 
       // If the blocklist says it is risky and we have never seen this
@@ -2267,24 +2330,26 @@ nsPluginHost::WritePluginInfo()
       PLUGIN_REGISTRY_END_OF_LINE_MARKER,
       (tag->mFullPath.get()),
       PLUGIN_REGISTRY_FIELD_DELIMITER,
       PLUGIN_REGISTRY_END_OF_LINE_MARKER,
       (tag->mVersion.get()),
       PLUGIN_REGISTRY_FIELD_DELIMITER,
       PLUGIN_REGISTRY_END_OF_LINE_MARKER);
 
-    // lastModifiedTimeStamp|canUnload|tag->mFlags
-    PR_fprintf(fd, "%lld%c%d%c%lu%c%c\n",
+    // lastModifiedTimeStamp|canUnload|tag->mFlags|fromExtension
+    PR_fprintf(fd, "%lld%c%d%c%lu%c%d%c%c\n",
       tag->mLastModifiedTime,
       PLUGIN_REGISTRY_FIELD_DELIMITER,
       false, // did store whether or not to unload in-process plugins
       PLUGIN_REGISTRY_FIELD_DELIMITER,
       0, // legacy field for flags
       PLUGIN_REGISTRY_FIELD_DELIMITER,
+      tag->IsFromExtension(),
+      PLUGIN_REGISTRY_FIELD_DELIMITER,
       PLUGIN_REGISTRY_END_OF_LINE_MARKER);
 
     //description, name & mtypecount are on separate line
     PR_fprintf(fd, "%s%c%c\n%s%c%c\n%d\n",
       (tag->mDescription.get()),
       PLUGIN_REGISTRY_FIELD_DELIMITER,
       PLUGIN_REGISTRY_END_OF_LINE_MARKER,
       (tag->mName.get()),
@@ -2481,30 +2546,33 @@ nsPluginHost::ReadPluginInfo()
 
     // If this is a registry from a different architecture then don't attempt to read it
     if (PL_strcmp(archValues[1], arch.get())) {
       return rv;
     }
   }
 
   // Registry v0.13 and upwards includes the list of invalid plugins
-  bool hasInvalidPlugins = (version >= "0.13");
+  const bool hasInvalidPlugins = (version >= "0.13");
 
   // Registry v0.16 and upwards always have 0 for their plugin flags, prefs are used instead
   const bool hasValidFlags = (version < "0.16");
 
+  // Registry v0.17 and upwards store whether the plugin comes from an XPI.
+  const bool hasFromExtension = (version >= "0.17");
+
+#if defined(XP_MACOSX)
+  const bool hasFullPathInFileNameField = false;
+#else
+  const bool hasFullPathInFileNameField = (version < "0.11");
+#endif
+
   if (!ReadSectionHeader(reader, "PLUGINS"))
     return rv;
 
-#if defined(XP_MACOSX)
-  bool hasFullPathInFileNameField = false;
-#else
-  bool hasFullPathInFileNameField = (version < "0.11");
-#endif
-
   while (reader.NextLine()) {
     const char *filename;
     const char *fullpath;
     nsAutoCString derivedFileName;
 
     if (hasInvalidPlugins && *reader.LinePtr() == '[') {
       break;
     }
@@ -2540,23 +2608,28 @@ nsPluginHost::ReadPluginInfo()
     if (regHasVersion) {
       version = reader.LinePtr();
       if (!reader.NextLine())
         return rv;
     } else {
       version = "0";
     }
 
-    // lastModifiedTimeStamp|canUnload|tag.mFlag
-    if (reader.ParseLine(values, 3) != 3)
+    // lastModifiedTimeStamp|canUnload|tag.mFlag|fromExtension
+    const int count = hasFromExtension ? 4 : 3;
+    if (reader.ParseLine(values, count) != count)
       return rv;
 
     // If this is an old plugin registry mark this plugin tag to be refreshed
     int64_t lastmod = (vdiff == 0) ? nsCRT::atoll(values[0]) : -1;
     uint32_t tagflag = atoi(values[2]);
+    bool fromExtension = false;
+    if (hasFromExtension) {
+      fromExtension = atoi(values[3]);
+    }
     if (!reader.NextLine())
       return rv;
 
     char *description = reader.LinePtr();
     if (!reader.NextLine())
       return rv;
 
 #if MOZ_WIDGET_ANDROID
@@ -2617,17 +2690,17 @@ nsPluginHost::ReadPluginInfo()
     nsRefPtr<nsPluginTag> tag = new nsPluginTag(name,
       description,
       filename,
       fullpath,
       version,
       (const char* const*)mimetypes,
       (const char* const*)mimedescriptions,
       (const char* const*)extensions,
-      mimetypecount, lastmod, true);
+      mimetypecount, lastmod, fromExtension, true);
     if (heapalloced)
       delete [] heapalloced;
 
     // Import flags from registry into prefs for old registry versions
     if (hasValidFlags && !pluginStateImported) {
       tag->ImportFlagsToPrefs(tagflag);
     }
 
--- a/dom/plugins/base/nsPluginTags.cpp
+++ b/dom/plugins/base/nsPluginTags.cpp
@@ -25,16 +25,19 @@ using namespace mozilla;
 // These legacy flags are used in the plugin registry. The states are now
 // stored in prefs, but we still need to be able to import them.
 #define NS_PLUGIN_FLAG_ENABLED      0x0001    // is this plugin enabled?
 // no longer used                   0x0002    // reuse only if regenerating pluginreg.dat
 #define NS_PLUGIN_FLAG_FROMCACHE    0x0004    // this plugintag info was loaded from cache
 // no longer used                   0x0008    // reuse only if regenerating pluginreg.dat
 #define NS_PLUGIN_FLAG_CLICKTOPLAY  0x0020    // this is a click-to-play plugin
 
+static const char kPrefDefaultEnabledState[] = "plugin.default.state";
+static const char kPrefDefaultEnabledStateXpi[] = "plugin.defaultXpi.state";
+
 inline char* new_str(const char* str)
 {
   if (str == nullptr)
     return nullptr;
   
   char* result = new char[strlen(str) + 1];
   if (result != nullptr)
     return strcpy(result, str);
@@ -57,29 +60,32 @@ MakePrefNameForPlugin(const char* const 
 static nsCString
 GetStatePrefNameForPlugin(nsPluginTag* aTag)
 {
   return MakePrefNameForPlugin("state", aTag);
 }
 
 /* nsPluginTag */
 
-nsPluginTag::nsPluginTag(nsPluginInfo* aPluginInfo, int64_t aLastModifiedTime)
+nsPluginTag::nsPluginTag(nsPluginInfo* aPluginInfo,
+                         int64_t aLastModifiedTime,
+                         bool fromExtension)
   : mName(aPluginInfo->fName),
     mDescription(aPluginInfo->fDescription),
     mLibrary(nullptr),
     mIsJavaPlugin(false),
     mIsFlashPlugin(false),
     mFileName(aPluginInfo->fFileName),
     mFullPath(aPluginInfo->fFullPath),
     mVersion(aPluginInfo->fVersion),
     mLastModifiedTime(aLastModifiedTime),
     mNiceFileName(),
     mCachedBlocklistState(nsIBlocklistService::STATE_NOT_BLOCKED),
-    mCachedBlocklistStateValid(false)
+    mCachedBlocklistStateValid(false),
+    mIsFromExtension(fromExtension)
 {
   InitMime(aPluginInfo->fMimeTypeArray,
            aPluginInfo->fMimeDescriptionArray,
            aPluginInfo->fExtensionArray,
            aPluginInfo->fVariantCount);
   EnsureMembersAreUTF8();
   FixupVersion();
 }
@@ -89,29 +95,31 @@ nsPluginTag::nsPluginTag(const char* aNa
                          const char* aFileName,
                          const char* aFullPath,
                          const char* aVersion,
                          const char* const* aMimeTypes,
                          const char* const* aMimeDescriptions,
                          const char* const* aExtensions,
                          int32_t aVariants,
                          int64_t aLastModifiedTime,
+                         bool fromExtension,
                          bool aArgsAreUTF8)
   : mName(aName),
     mDescription(aDescription),
     mLibrary(nullptr),
     mIsJavaPlugin(false),
     mIsFlashPlugin(false),
     mFileName(aFileName),
     mFullPath(aFullPath),
     mVersion(aVersion),
     mLastModifiedTime(aLastModifiedTime),
     mNiceFileName(),
     mCachedBlocklistState(nsIBlocklistService::STATE_NOT_BLOCKED),
-    mCachedBlocklistStateValid(false)
+    mCachedBlocklistStateValid(false),
+    mIsFromExtension(fromExtension)
 {
   InitMime(aMimeTypes, aMimeDescriptions, aExtensions,
            static_cast<uint32_t>(aVariants));
   if (!aArgsAreUTF8)
     EnsureMembersAreUTF8();
   FixupVersion();
 }
 
@@ -360,18 +368,20 @@ nsPluginTag::GetEnabledState(uint32_t *a
                                     &enabledState);
   if (NS_SUCCEEDED(rv) &&
       enabledState >= nsIPluginTag::STATE_DISABLED &&
       enabledState <= nsIPluginTag::STATE_ENABLED) {
     *aEnabledState = (uint32_t)enabledState;
     return rv;
   }
 
-  enabledState = Preferences::GetInt("plugin.default.state",
-                                     nsIPluginTag::STATE_ENABLED);
+  const char* const pref = mIsFromExtension ? kPrefDefaultEnabledStateXpi
+                                            : kPrefDefaultEnabledState;
+
+  enabledState = Preferences::GetInt(pref, nsIPluginTag::STATE_ENABLED);
   if (enabledState >= nsIPluginTag::STATE_DISABLED &&
       enabledState <= nsIPluginTag::STATE_ENABLED) {
     *aEnabledState = (uint32_t)enabledState;
     return NS_OK;
   }
 
   return NS_ERROR_UNEXPECTED;
 }
@@ -569,8 +579,13 @@ nsPluginTag::InvalidateBlocklistState()
 
 NS_IMETHODIMP
 nsPluginTag::GetLastModifiedTime(PRTime* aLastModifiedTime)
 {
   MOZ_ASSERT(aLastModifiedTime);
   *aLastModifiedTime = mLastModifiedTime;
   return NS_OK;
 }
+
+bool nsPluginTag::IsFromExtension() const
+{
+  return mIsFromExtension;
+}
--- a/dom/plugins/base/nsPluginTags.h
+++ b/dom/plugins/base/nsPluginTags.h
@@ -31,27 +31,30 @@ public:
   // These must match the STATE_* values in nsIPluginTag.idl
   enum PluginState {
     ePluginState_Disabled = 0,
     ePluginState_Clicktoplay = 1,
     ePluginState_Enabled = 2,
     ePluginState_MaxValue = 3,
   };
 
-  nsPluginTag(nsPluginInfo* aPluginInfo, int64_t aLastModifiedTime);
+  nsPluginTag(nsPluginInfo* aPluginInfo,
+              int64_t aLastModifiedTime,
+              bool fromExtension);
   nsPluginTag(const char* aName,
               const char* aDescription,
               const char* aFileName,
               const char* aFullPath,
               const char* aVersion,
               const char* const* aMimeTypes,
               const char* const* aMimeDescriptions,
               const char* const* aExtensions,
               int32_t aVariants,
               int64_t aLastModifiedTime,
+              bool fromExtension,
               bool aArgsAreUTF8 = false);
   virtual ~nsPluginTag();
 
   void TryUnloadPlugin(bool inShutdown);
 
   // plugin is enabled and not blocklisted
   bool IsActive();
 
@@ -64,16 +67,18 @@ public:
   void SetPluginState(PluginState state);
 
   // import legacy flags from plugin registry into the preferences
   void ImportFlagsToPrefs(uint32_t flag);
 
   bool HasSameNameAndMimes(const nsPluginTag *aPluginTag) const;
   nsCString GetNiceFileName();
 
+  bool IsFromExtension() const;
+
   nsRefPtr<nsPluginTag> mNext;
   nsCString     mName; // UTF-8
   nsCString     mDescription; // UTF-8
   nsTArray<nsCString> mMimeTypes; // UTF-8
   nsTArray<nsCString> mMimeDescriptions; // UTF-8
   nsTArray<nsCString> mExtensions; // UTF-8
   PRLibrary     *mLibrary;
   nsRefPtr<nsNPAPIPlugin> mPlugin;
@@ -87,16 +92,17 @@ public:
 
   uint32_t      GetBlocklistState();
   void          InvalidateBlocklistState();
 
 private:
   nsCString     mNiceFileName; // UTF-8
   uint16_t      mCachedBlocklistState;
   bool          mCachedBlocklistStateValid;
+  bool          mIsFromExtension;
 
   void InitMime(const char* const* aMimeTypes,
                 const char* const* aMimeDescriptions,
                 const char* const* aExtensions,
                 uint32_t aVariantCount);
   nsresult EnsureMembersAreUTF8();
   void FixupVersion();
 };
--- a/dom/plugins/ipc/hangui/PluginHangUIChild.cpp
+++ b/dom/plugins/ipc/hangui/PluginHangUIChild.cpp
@@ -304,16 +304,17 @@ PluginHangUIChild::HangUIDlgProc(HWND aD
           break;
         default:
           break;
       }
       break;
     }
     case WM_DESTROY: {
       EnableWindow(mParentWindow, TRUE);
+      SetForegroundWindow(mParentWindow);
       break;
     }
     default:
       break;
   }
   return FALSE;
 }
 
--- a/dom/plugins/test/mochitest/chrome.ini
+++ b/dom/plugins/test/mochitest/chrome.ini
@@ -14,16 +14,19 @@ skip-if = toolkit != "cocoa"
 [test_crash_notify.xul]
 skip-if = !crashreporter
 [test_crash_notify_no_report.xul]
 skip-if = !crashreporter
 [test_crash_submit.xul]
 skip-if = !crashreporter
 [test_hang_submit.xul]
 skip-if = !crashreporter
+[test_hangui.xul]
+skip-if = (!crashreporter) || (os != "win")
+support-files = hangui_subpage.html hangui_common.js hangui_iface.js dialog_watcher.js
 [test_idle_hang.xul]
 skip-if = (!crashreporter) || (os != "win")
 [test_npruntime.xul]
 [test_plugin_tag_clicktoplay.html]
 [test_privatemode_perwindowpb.xul]
 [test_refresh_navigator_plugins.html]
 [test_xulbrowser_plugin_visibility.xul]
 skip-if = (toolkit == "cocoa") || (os == "win")
new file mode 100644
--- /dev/null
+++ b/dom/plugins/test/mochitest/dialog_watcher.js
@@ -0,0 +1,172 @@
+const EVENT_OBJECT_SHOW = 0x8002;
+const EVENT_OBJECT_HIDE = 0x8003;
+const WINEVENT_OUTOFCONTEXT = 0;
+const WINEVENT_SKIPOWNPROCESS = 2;
+const QS_ALLINPUT = 0x04FF;
+const INFINITE = 0xFFFFFFFF;
+const WAIT_OBJECT_0 = 0;
+const WAIT_TIMEOUT = 258;
+const PM_NOREMOVE = 0;
+
+function DialogWatcher(titleText, onDialogStart, onDialogEnd) {
+  this.titleText = titleText;
+  this.onDialogStart = onDialogStart;
+  this.onDialogEnd = onDialogEnd;
+}
+
+DialogWatcher.prototype.init = function() {
+  this.hwnd = undefined;
+  if (!this.user32) {
+    this.user32 = ctypes.open("user32.dll");
+  }
+  if (!this.findWindow) {
+    this.findWindow = user32.declare("FindWindowW",
+                                     ctypes.winapi_abi,
+                                     ctypes.uintptr_t,
+                                     ctypes.jschar.ptr,
+                                     ctypes.jschar.ptr);
+  }
+  if (!this.winEventProcType) {
+    this.winEventProcType = ctypes.FunctionType(ctypes.stdcall_abi,
+                                                ctypes.void_t,
+                                                [ctypes.uintptr_t,
+                                                ctypes.uint32_t,
+                                                ctypes.uintptr_t,
+                                                ctypes.long,
+                                                ctypes.long,
+                                                ctypes.uint32_t,
+                                                ctypes.uint32_t]).ptr;
+  }
+  if (!this.setWinEventHook) {
+    this.setWinEventHook = user32.declare("SetWinEventHook",
+                                          ctypes.winapi_abi,
+                                          ctypes.uintptr_t,
+                                          ctypes.uint32_t,
+                                          ctypes.uint32_t,
+                                          ctypes.uintptr_t,
+                                          this.winEventProcType,
+                                          ctypes.uint32_t,
+                                          ctypes.uint32_t,
+                                          ctypes.uint32_t);
+  }
+  if (!this.unhookWinEvent) {
+    this.unhookWinEvent = user32.declare("UnhookWinEvent",
+                                         ctypes.winapi_abi,
+                                         ctypes.int,
+                                         ctypes.uintptr_t);
+  }
+  if (!this.pointType) {
+    this.pointType = ctypes.StructType("tagPOINT",
+                                       [ { "x": ctypes.long },
+                                         { "y": ctypes.long } ] );
+  }
+  if (!this.msgType) {
+    this.msgType = ctypes.StructType("tagMSG",
+                                     [ { "hwnd": ctypes.uintptr_t },
+                                       { "message": ctypes.uint32_t },
+                                       { "wParam": ctypes.uintptr_t },
+                                       { "lParam": ctypes.intptr_t },
+                                       { "time": ctypes.uint32_t },
+                                       { "pt": this.pointType } ] );
+  }
+  if (!this.peekMessage) {
+    this.peekMessage = user32.declare("PeekMessageW",
+                                      ctypes.winapi_abi,
+                                      ctypes.int,
+                                      this.msgType.ptr,
+                                      ctypes.uintptr_t,
+                                      ctypes.uint32_t,
+                                      ctypes.uint32_t,
+                                      ctypes.uint32_t);
+  }
+  if (!this.msgWaitForMultipleObjects) {
+    this.msgWaitForMultipleObjects = user32.declare("MsgWaitForMultipleObjects",
+                                                    ctypes.winapi_abi,
+                                                    ctypes.uint32_t,
+                                                    ctypes.uint32_t,
+                                                    ctypes.uintptr_t.ptr,
+                                                    ctypes.int,
+                                                    ctypes.uint32_t,
+                                                    ctypes.uint32_t);
+  }
+  if (!this.getWindowTextW) {
+    this.getWindowTextW = user32.declare("GetWindowTextW",
+                                         ctypes.winapi_abi,
+                                         ctypes.int,
+                                         ctypes.uintptr_t,
+                                         ctypes.jschar.ptr,
+                                         ctypes.int);
+  }
+};
+
+DialogWatcher.prototype.getWindowText = function(hwnd) {
+  var bufType = ctypes.ArrayType(ctypes.jschar);
+  var buffer = new bufType(256);
+  
+  if (this.getWindowTextW(hwnd, buffer, buffer.length)) {
+    return buffer.readString();
+  }
+};
+
+DialogWatcher.prototype.processWindowEvents = function(timeout) {
+  var onWinEvent = function(self, hook, event, hwnd, idObject, idChild, dwEventThread, dwmsEventTime) {
+    var nhwnd = Number(hwnd)
+    if (event == EVENT_OBJECT_SHOW) {
+      if (nhwnd == self.hwnd) {
+        // We've already picked up this event via FindWindow
+        return;
+      }
+      var windowText = self.getWindowText(hwnd);
+      if (windowText == self.titleText && self.onDialogStart) {
+        self.hwnd = nhwnd;
+        self.onDialogStart(nhwnd);
+      }
+    } else if (event == EVENT_OBJECT_HIDE && nhwnd == self.hwnd && self.onDialogEnd) {
+      self.onDialogEnd();
+      self.hwnd = null;
+    }
+  };
+  var self = this;
+  var callback = this.winEventProcType(function(hook, event, hwnd, idObject,
+                                                idChild, dwEventThread,
+                                                dwmsEventTime) {
+      onWinEvent(self, hook, event, hwnd, idObject, idChild, dwEventThread,
+                 dwmsEventTime);
+    } );
+  var hook = this.setWinEventHook(EVENT_OBJECT_SHOW, EVENT_OBJECT_HIDE,
+                                  0, callback, 0, 0,
+                                  WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS);
+  if (!hook) {
+    return;
+  }
+  // Check if the window is already showing
+  var hwnd = this.findWindow(null, this.titleText);
+  if (hwnd && hwnd > 0) {
+    this.hwnd = Number(hwnd);
+    if (this.onDialogStart) {
+      this.onDialogStart(this.hwnd);
+    }
+  }
+
+  if (!timeout) {
+    timeout = INFINITE;
+  }
+
+  var waitStatus = WAIT_OBJECT_0;
+  var expectingStart = this.onDialogStart && this.hwnd === undefined;
+  while (this.hwnd === undefined || this.onDialogEnd && this.hwnd) {
+    waitStatus = this.msgWaitForMultipleObjects(0, null, 0, expectingStart ?
+                                                            INFINITE : timeout, 0);
+    if (waitStatus == WAIT_OBJECT_0) {
+      var msg = new this.msgType;
+      this.peekMessage(msg.address(), 0, 0, 0, PM_NOREMOVE);
+    } else if (waitStatus == WAIT_TIMEOUT) {
+      break;
+    }
+  }
+
+  this.unhookWinEvent(hook);
+  // Returns true if the hook was successful, something was found, and we never timed out
+  return this.hwnd !== undefined && waitStatus == WAIT_OBJECT_0;
+};
+
new file mode 100644
--- /dev/null
+++ b/dom/plugins/test/mochitest/hangui_common.js
@@ -0,0 +1,20 @@
+// Plugin Hang UI constants
+const HANGUIOP_NOTHING = 0;
+const HANGUIOP_CANCEL = 1;
+const HANGUIOP_COMMAND = 2;
+const IDC_CONTINUE = 1001;
+const IDC_STOP = 1002;
+const IDC_NOFUTURE = 1003;
+
+// Windows constants
+const WM_CLOSE = 0x0010;
+const WM_COMMAND = 0x0111;
+const BM_GETCHECK = 0x00F0;
+const BM_SETCHECK = 0x00F1;
+const BN_CLICKED = 0;
+const BST_CHECKED = 1;
+
+// Test-specific constants
+const EPSILON_MS = 1000;
+const STALL_DURATION = 2;
+
new file mode 100644
--- /dev/null
+++ b/dom/plugins/test/mochitest/hangui_iface.js
@@ -0,0 +1,121 @@
+var user32;
+var sendMessage;
+var getDlgItem;
+var messageBox;
+var watcher;
+
+importScripts("hangui_common.js");
+importScripts("dialog_watcher.js");
+
+function initCTypes() {
+  if (!user32) {
+    user32 = ctypes.open("user32.dll");
+  }
+  if (!getDlgItem) {
+    getDlgItem = user32.declare("GetDlgItem",
+                                ctypes.winapi_abi,
+                                ctypes.uintptr_t,
+                                ctypes.uintptr_t,
+                                ctypes.int);
+  }
+  if (!sendMessage) {
+    sendMessage = user32.declare("SendMessageW",
+                                 ctypes.winapi_abi,
+                                 ctypes.intptr_t,
+                                 ctypes.uintptr_t,
+                                 ctypes.uint32_t,
+                                 ctypes.uintptr_t,
+                                 ctypes.intptr_t);
+  }
+  if (!messageBox) {
+    // Handy for debugging the test itself
+    messageBox = user32.declare("MessageBoxW",
+                                ctypes.winapi_abi,
+                                ctypes.int,
+                                ctypes.uintptr_t,
+                                ctypes.jschar.ptr,
+                                ctypes.jschar.ptr,
+                                ctypes.uint32_t);
+  }
+  if (!watcher) {
+    watcher = new DialogWatcher("Warning: Unresponsive plugin");
+  }
+}
+
+function postSuccess(params) {
+  self.postMessage({"status": true, "params": params});
+}
+
+function postFail(params, msg) {
+  self.postMessage({"status": false, "params": params, "msg": msg});
+}
+
+function onDialogStart(inparams, hwnd) {
+  var params = Object.create(inparams);
+  params.testName += " (Start)";
+  params.callback = null;
+  if (!params.expectToFind) {
+    postFail(params, "Dialog showed when we weren't expecting it to!");
+    return;
+  }
+  if (params.opCode == HANGUIOP_CANCEL) {
+    sendMessage(hwnd, WM_CLOSE, 0, 0);
+  } else if (params.opCode == HANGUIOP_COMMAND) {
+    if (params.check) {
+      var checkbox = getDlgItem(hwnd, IDC_NOFUTURE);
+      if (!checkbox) {
+        postFail(params, "Couldn't find checkbox");
+        return;
+      }
+      sendMessage(checkbox, BM_SETCHECK, BST_CHECKED, 0);
+      sendMessage(hwnd, WM_COMMAND, (BN_CLICKED << 16) | IDC_NOFUTURE, checkbox);
+    }
+    var button = getDlgItem(hwnd, params.commandId);
+    if (!button) {
+      postFail(params,
+               "GetDlgItem failed to find button with ID " + params.commandId);
+      return;
+    }
+    sendMessage(hwnd, WM_COMMAND, (BN_CLICKED << 16) | params.commandId, button);
+  }
+  postSuccess(params);
+}
+
+function onDialogEnd(inparams) {
+  var params = Object.create(inparams);
+  params.testName += " (End)";
+  params.callback = inparams.callback;
+  postSuccess(params);
+}
+
+self.onmessage = function(event) {
+  initCTypes();
+  watcher.init();
+  var params = event.data;
+  var timeout = params.timeoutMs;
+  if (params.expectToFind) {
+    watcher.onDialogStart = function(hwnd) { onDialogStart(params, hwnd); };
+    if (params.expectToClose) {
+      watcher.onDialogEnd = function() { onDialogEnd(params); };
+    }
+  } else {
+    watcher.onDialogStart = null;
+    watcher.onDialogEnd = null;
+  }
+  var result = watcher.processWindowEvents(timeout);
+  if (result === null) {
+    postFail(params, "Hook failed");
+  } else if (!result) {
+    if (params.expectToFind) {
+      postFail(params, "The dialog didn't show but we were expecting it to");
+    } else {
+      postSuccess(params);
+    }
+  }
+}
+
+self.onerror = function(event) {
+  var msg = "Error: " + event.message + " at " + event.filename + ":" + event.lineno;
+  postFail(null, msg);
+};
+
new file mode 100644
--- /dev/null
+++ b/dom/plugins/test/mochitest/hangui_subpage.html
@@ -0,0 +1,4 @@
+<html>
+<body onload="window.parent.frameLoaded()">
+  <embed id="plugin1" type="application/x-test" width="400" height="400"></embed>
+
new file mode 100644
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_hangui.xul
@@ -0,0 +1,263 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
+                 type="text/css"?>
+<window title="Basic Plugin Tests"
+  xmlns:html="http://www.w3.org/1999/xhtml"
+  xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+  <title>Plugin Hang UI Test</title>
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
+  <script type="application/javascript"
+          src="http://mochi.test:8888/chrome/dom/plugins/test/mochitest/hang_test.js" />
+  <script type="application/javascript"
+          src="http://mochi.test:8888/chrome/dom/plugins/test/mochitest/hangui_common.js" />
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+  <iframe id="iframe1" src="hangui_subpage.html" width="400" height="400"></iframe>
+</body>
+<script class="testbody" type="application/javascript">
+<![CDATA[
+SimpleTest.waitForExplicitFinish();
+
+Components.utils.import("resource://gre/modules/Services.jsm");
+
+const hangUITimeoutPref = "dom.ipc.plugins.hangUITimeoutSecs";
+const hangUIMinDisplayPref = "dom.ipc.plugins.hangUIMinDisplaySecs";
+const timeoutPref = "dom.ipc.plugins.timeoutSecs";
+
+var worker = new ChromeWorker("hangui_iface.js");
+worker.onmessage = function(event) {
+  var result = event.data;
+  var params = result.params;
+  var output = params.testName;
+  if (result.msg) {
+    output += ": " + result.msg;
+  }
+  ok(result.status, output);
+  if (params.callback) {
+    var cb = eval(params.callback);
+    var timeout = setTimeout(function() { clearTimeout(timeout); cb(); }, 100);
+  }
+};
+worker.onerror = function(event) {
+  var output = "Error: " + event.message + " at " + event.filename + ":" + event.lineno;
+  ok(false, output);
+};
+
+var iframe;
+var p;
+var os = Components.classes["@mozilla.org/observer-service;1"].getService(Components.interfaces.nsIObserverService);
+
+function hanguiOperation(testName, timeoutSec, expectFind, expectClose, opCode,
+                         commandId, check, cb) {
+  var timeoutMs = timeoutSec * 1000 + EPSILON_MS;
+  worker.postMessage({ "timeoutMs": timeoutMs, "expectToFind": expectFind,
+                       "expectToClose": expectClose, "opCode": opCode,
+                       "commandId": commandId, "check": check,
+                       "testName": testName, "callback": cb });
+}
+
+function hanguiExpect(testName, shouldBeShowing, shouldClose, cb) {
+  var timeoutSec = Services.prefs.getIntPref(hangUITimeoutPref);
+  if (!shouldBeShowing && !timeoutSec) {
+    timeoutSec = Services.prefs.getIntPref(timeoutPref);
+  }
+  hanguiOperation(testName, timeoutSec, shouldBeShowing, shouldClose, HANGUIOP_NOTHING, 0, false, cb);
+}
+
+function hanguiContinue(testName, check, cb) {
+  var timeoutSec = Services.prefs.getIntPref(hangUITimeoutPref);
+  hanguiOperation(testName, timeoutSec, true, true, HANGUIOP_COMMAND, IDC_CONTINUE, check, cb);
+}
+
+function hanguiStop(testName, check, cb) {
+  var timeoutSec = Services.prefs.getIntPref(hangUITimeoutPref);
+  hanguiOperation(testName, timeoutSec, true, true, HANGUIOP_COMMAND, IDC_STOP, check, cb);
+}
+
+function hanguiCancel(testName, cb) {
+  var timeoutSec = Services.prefs.getIntPref(hangUITimeoutPref);
+  hanguiOperation(testName, timeoutSec, true, true, HANGUIOP_CANCEL, 0, false, cb);
+}
+
+function finishTest() {
+  if (obsCount > 0) {
+    os.removeObserver(testObserver, "plugin-crashed");
+    --obsCount;
+  }
+  SpecialPowers.clearUserPref(hangUITimeoutPref);
+  SpecialPowers.clearUserPref(hangUIMinDisplayPref);
+  SpecialPowers.clearUserPref(timeoutPref);
+  SimpleTest.finish();
+}
+
+function runTests() {
+  if (!SimpleTest.testPluginIsOOP()) {
+    ok(true, "Skipping this test when test plugin is not OOP.");
+    SimpleTest.finish();
+  }
+
+  resetVars();
+
+  hanguiExpect("Prime ChromeWorker", false, false, "test1");
+}
+
+window.frameLoaded = runTests;
+
+var obsCount = 0;
+
+function onPluginCrashedHangUI(aEvent) {
+  ok(true, "Plugin crashed notification received");
+  is(aEvent.type, "PluginCrashed", "event is correct type");
+
+  is(p, aEvent.target, "Plugin crashed event target is plugin element");
+
+  ok(aEvent instanceof Components.interfaces.nsIDOMCustomEvent,
+     "plugin crashed event has the right interface");
+
+  var propBag = aEvent.detail.QueryInterface(Components.interfaces.nsIPropertyBag2);
+  var pluginDumpID = propBag.getPropertyAsAString("pluginDumpID");
+  isnot(pluginDumpID, "", "got a non-empty dump ID");
+  var pluginName = propBag.getPropertyAsAString("pluginName");
+  is(pluginName, "Test Plug-in", "got correct plugin name");
+  var pluginFilename = propBag.getPropertyAsAString("pluginFilename");
+  isnot(pluginFilename, "", "got a non-empty filename");
+  var didReport = propBag.getPropertyAsBool("submittedCrashReport");
+  // The app itself may or may not have decided to submit the report, so
+  // allow either true or false here.
+  ok((didReport == true || didReport == false), "event said crash report was submitted");
+  os.removeObserver(testObserver, "plugin-crashed");
+  --obsCount;
+}
+
+function resetVars() {
+  iframe = document.getElementById('iframe1');
+  p = iframe.contentDocument.getElementById("plugin1");
+  if (obsCount == 0) {
+    os.addObserver(testObserver, "plugin-crashed", true);
+    ++obsCount;
+  }
+  iframe.contentDocument.addEventListener("PluginCrashed",
+                                          onPluginCrashedHangUI,
+                                          false);
+}
+
+function test9b() {
+  hanguiExpect("test9b: Plugin Hang UI is not showing (checkbox)", false);
+  p.stall(STALL_DURATION);
+  hanguiExpect("test9b: Plugin Hang UI is still not showing (checkbox)", false, false, "finishTest");
+  p.stall(STALL_DURATION);
+}
+
+function test9a() {
+  resetVars();
+  SpecialPowers.setIntPref(hangUITimeoutPref, 1);
+  SpecialPowers.setIntPref(hangUIMinDisplayPref, 1);
+  SpecialPowers.setIntPref(timeoutPref, 45);
+  hanguiContinue("test9a: Continue button works with checkbox", true, "test9b");
+  p.stall(STALL_DURATION);
+}
+
+function test9() {
+  window.frameLoaded = test9a;
+  iframe.contentWindow.location.reload();
+}
+
+function test8a() {
+  resetVars();
+  SpecialPowers.setIntPref(hangUITimeoutPref, 1);
+  SpecialPowers.setIntPref(hangUIMinDisplayPref, 4);
+  hanguiExpect("test8a: Plugin Hang UI is not showing (disabled due to hangUIMinDisplaySecs)", false, false, "test9");
+  var exceptionThrown = false;
+  try {
+    p.hang();
+  } catch(e) {
+    exceptionThrown = true;
+  }
+  ok(exceptionThrown, "test8a: Exception thrown from hang() when plugin was terminated");
+}
+
+function test8() {
+  window.frameLoaded = test8a;
+  iframe.contentWindow.location.reload();
+}
+
+function test7a() {
+  resetVars();
+  SpecialPowers.setIntPref(hangUITimeoutPref, 0);
+  hanguiExpect("test7a: Plugin Hang UI is not showing (disabled)", false, false, "test8");
+  var exceptionThrown = false;
+  try {
+    p.hang();
+  } catch(e) {
+    exceptionThrown = true;
+  }
+  ok(exceptionThrown, "test7a: Exception thrown from hang() when plugin was terminated");
+}
+
+function test7() {
+  window.frameLoaded = test7a;
+  iframe.contentWindow.location.reload();
+}
+
+function test6() {
+  SpecialPowers.setIntPref(hangUITimeoutPref, 1);
+  SpecialPowers.setIntPref(hangUIMinDisplayPref, 1);
+  SpecialPowers.setIntPref(timeoutPref, 3);
+  hanguiExpect("test6: Plugin Hang UI is showing", true, true, "test7");
+  var exceptionThrown = false;
+  try {
+    p.hang();
+  } catch(e) {
+    exceptionThrown = true;
+  }
+  ok(exceptionThrown, "test6: Exception thrown from hang() when plugin was terminated (child timeout)");
+}
+
+function test5a() {
+  resetVars();
+  hanguiCancel("test5a: Close button works", "test6");
+  p.stall(STALL_DURATION);
+}
+
+function test5() {
+  window.frameLoaded = test5a;
+  iframe.contentWindow.location.reload();
+}
+
+function test4() {
+  hanguiStop("test4: Stop button works", false, "test5");
+  // We'll get an exception here because the plugin was terminated
+  var exceptionThrown = false;
+  try {
+    p.hang();
+  } catch(e) {
+    exceptionThrown = true;
+  }
+  ok(exceptionThrown, "test4: Exception thrown from hang() when plugin was terminated");
+}
+
+function test3() {
+  hanguiContinue("test3: Continue button works", false, "test4");
+  p.stall(STALL_DURATION);
+}
+
+function test2() {
+  // This test is identical to test1 because there were some bugs where the 
+  // Hang UI would show on the first hang but not on subsequent hangs
+  hanguiExpect("test2: Plugin Hang UI is showing", true, true, "test3");
+  p.stall(STALL_DURATION);
+}
+
+function test1() {
+  SpecialPowers.setIntPref(hangUITimeoutPref, 1);
+  SpecialPowers.setIntPref(hangUIMinDisplayPref, 1);
+  SpecialPowers.setIntPref(timeoutPref, 45);
+  hanguiExpect("test1: Plugin Hang UI is showing", true, true, "test2");
+  p.stall(STALL_DURATION);
+}
+
+]]>
+</script>
+</window>
--- a/dom/plugins/test/moz.build
+++ b/dom/plugins/test/moz.build
@@ -1,14 +1,14 @@
 # -*- 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/.
 
-DIRS += ['testplugin']
+DIRS += ['testplugin', 'testaddon']
 
 XPCSHELL_TESTS_MANIFESTS += ['unit/xpcshell.ini']
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('gtk2', 'gtk3', 'cocoa', 'windows'):
     MOCHITEST_MANIFESTS += ['mochitest/mochitest.ini']
     MOCHITEST_CHROME_MANIFESTS += ['mochitest/chrome.ini']
 
new file mode 100644
--- /dev/null
+++ b/dom/plugins/test/testaddon/Makefile.in
@@ -0,0 +1,23 @@
+# 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 $(topsrcdir)/config/rules.mk
+
+ifeq ($(MOZ_WIDGET_TOOLKIT),cocoa)
+plugin_file_name = Test.plugin
+addon_file_name = testaddon_$(TARGET_XPCOM_ABI).xpi
+else
+plugin_file_name = $(DLL_PREFIX)nptest$(DLL_SUFFIX)
+addon_file_name = testaddon.xpi
+endif
+
+# This is so hacky. Waiting on bug 988938.
+testdir = $(abspath $(DEPTH)/_tests/xpcshell/dom/plugins/test/unit/)
+addonpath = $(testdir)/$(addon_file_name)
+
+libs::
+	$(NSINSTALL) -D $(testdir)
+	rm -f $(addonpath)
+	cd $(srcdir) && zip -rD $(addonpath) install.rdf
+	cd $(DIST) && zip -rD $(addonpath) plugins/$(plugin_file_name)
new file mode 100644
--- /dev/null
+++ b/dom/plugins/test/testaddon/install.rdf
@@ -0,0 +1,23 @@
+<?xml version="1.0"?>
+
+<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+     xmlns:em="http://www.mozilla.org/2004/em-rdf#">
+
+  <Description about="urn:mozilla:install-manifest">
+    <em:id>test-plugin-from-xpi@tests.mozilla.org</em:id>
+    <em:version>1</em:version>
+    <em:name>Test plugin from XPI</em:name>
+    <em:description>This tests shipping a plugin through an extensions.</em:description>
+
+    <em:targetApplication>
+      <Description>
+        <em:id>toolkit@mozilla.org</em:id>
+        <em:minVersion>0</em:minVersion>
+        <em:maxVersion>*</em:maxVersion>
+      </Description>
+    </em:targetApplication>
+
+    <em:unpack>true</em:unpack>
+
+  </Description>
+</RDF>
new file mode 100644
--- /dev/null
+++ b/dom/plugins/test/testaddon/moz.build
@@ -0,0 +1,5 @@
+# -*- 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/.
--- a/dom/plugins/test/testplugin/nptest.cpp
+++ b/dom/plugins/test/testplugin/nptest.cpp
@@ -144,16 +144,17 @@ static bool getJavaCodebase(NPObject* np
 static bool checkObjectValue(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
 static bool enableFPExceptions(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
 static bool setCookie(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
 static bool getCookie(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
 static bool getAuthInfo(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
 static bool asyncCallbackTest(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
 static bool checkGCRace(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
 static bool hangPlugin(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
+static bool stallPlugin(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
 static bool getClipboardText(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
 static bool callOnDestroy(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
 static bool reinitWidget(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
 static bool crashPluginInNestedLoop(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
 static bool destroySharedGfxStuff(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
 static bool propertyAndMethod(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
 static bool getTopLevelWindowActivationState(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
 static bool getTopLevelWindowActivationEventCount(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
@@ -208,16 +209,17 @@ static const NPUTF8* sPluginMethodIdenti
   "checkObjectValue",
   "enableFPExceptions",
   "setCookie",
   "getCookie",
   "getAuthInfo",
   "asyncCallbackTest",
   "checkGCRace",
   "hang",
+  "stall",
   "getClipboardText",
   "callOnDestroy",
   "reinitWidget",
   "crashInNestedLoop",
   "destroySharedGfxStuff",
   "propertyAndMethod",
   "getTopLevelWindowActivationState",
   "getTopLevelWindowActivationEventCount",
@@ -273,16 +275,17 @@ static const ScriptableFunction sPluginM
   checkObjectValue,
   enableFPExceptions,
   setCookie,
   getCookie,
   getAuthInfo,
   asyncCallbackTest,
   checkGCRace,
   hangPlugin,
+  stallPlugin,
   getClipboardText,
   callOnDestroy,
   reinitWidget,
   crashPluginInNestedLoop,
   destroySharedGfxStuff,
   propertyAndMethod,
   getTopLevelWindowActivationState,
   getTopLevelWindowActivationEventCount,
@@ -3350,16 +3353,34 @@ hangPlugin(NPObject* npobj, const NPVari
 
   // NB: returning true here means that we weren't terminated, and
   // thus the hang detection/handling didn't work correctly.  The
   // test harness will succeed in calling this function, and the
   // test will fail.
   return true;
 }
 
+bool
+stallPlugin(NPObject* npobj, const NPVariant* args, uint32_t argCount,
+           NPVariant* result)
+{
+  uint32_t stallTimeSeconds = 0;
+  if ((argCount == 1) && NPVARIANT_IS_INT32(args[0])) {
+    stallTimeSeconds = (uint32_t) NPVARIANT_TO_INT32(args[0]);
+  }
+
+#ifdef XP_WIN
+  Sleep(stallTimeSeconds * 1000U);
+#else
+  sleep(stallTimeSeconds);
+#endif
+
+  return true;
+}
+
 #if defined(MOZ_WIDGET_GTK)
 bool
 getClipboardText(NPObject* npobj, const NPVariant* args, uint32_t argCount,
                  NPVariant* result)
 {
   NPP npp = static_cast<TestNPObject*>(npobj)->npp;
   InstanceData* id = static_cast<InstanceData*>(npp->pdata);
   string sel = pluginGetClipboardText(id);
--- a/dom/plugins/test/unit/head_plugins.js
+++ b/dom/plugins/test/unit/head_plugins.js
@@ -1,20 +1,22 @@
 /* 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/.
  */
 
-const Cc = Components.classes;
-const Ci = Components.interfaces;
+const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
+
+Cu.import("resource://gre/modules/Promise.jsm");
 
 const gIsWindows = ("@mozilla.org/windows-registry-key;1" in Cc);
 const gIsOSX = ("nsILocalFileMac" in Ci);
 const gIsLinux = ("@mozilla.org/gnome-gconf-service;1" in Cc) ||
   ("@mozilla.org/gio-service;1" in Cc);
+const gDirSvc = Cc["@mozilla.org/file/directory_service;1"].getService(Ci.nsIProperties);
 
 // Finds the test plugin library
 function get_test_plugin() {
   var pluginEnum = gDirSvc.get("APluginsDL", Ci.nsISimpleEnumerator);
   while (pluginEnum.hasMoreElements()) {
     let dir = pluginEnum.getNext().QueryInterface(Ci.nsILocalFile);
     let plugin = dir.clone();
     // OSX plugin
@@ -37,17 +39,17 @@ function get_test_plugin() {
       plugin.normalize();
       return plugin;
     }
   }
   return null;
 }
 
 // Finds the test nsIPluginTag
-function get_test_plugintag(aName) {
+function get_test_plugintag(aName="Test Plug-in") {
   const Cc = Components.classes;
   const Ci = Components.interfaces;
 
   var name = aName || "Test Plug-in";
   var host = Cc["@mozilla.org/plugin/host;1"].
              getService(Ci.nsIPluginHost);
   var tags = host.getPluginTags();
 
@@ -114,8 +116,84 @@ function get_test_plugin_no_symlink() {
     let plugin = dir.clone();
     plugin.append(get_platform_specific_plugin_name());
     if (plugin.exists()) {
       return plugin;
     }
   }
   return null;
 }
+
+let gGlobalScope = this;
+function loadAddonManager() {
+  let ns = {};
+  Cu.import("resource://gre/modules/Services.jsm", ns);
+  let head = "../../../../toolkit/mozapps/extensions/test/xpcshell/head_addons.js";
+  let file = do_get_file(head);
+  let uri = ns.Services.io.newFileURI(file);
+  ns.Services.scriptloader.loadSubScript(uri.spec, gGlobalScope);
+  createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9.2");
+  startupManager();
+}
+
+// Install addon and return a Promise<boolean> that is
+// resolve with true on success, false otherwise.
+function installAddon(relativePath) {
+  let deferred = Promise.defer();
+  let success = () => deferred.resolve(true);
+  let fail = () => deferred.resolve(false);
+  let listener = {
+    onDownloadCancelled: fail,
+    onDownloadFailed: fail,
+    onInstallCancelled: fail,
+    onInstallFailed: fail,
+    onInstallEnded: success,
+  };
+
+  let installCallback = install => {
+    install.addListener(listener);
+    install.install();
+  };
+
+  let file = do_get_file(relativePath, false);
+  AddonManager.getInstallForFile(file, installCallback,
+                                 "application/x-xpinstall");
+
+  return deferred.promise;
+}
+
+// Uninstall addon and return a Promise<boolean> that is
+// resolve with true on success, false otherwise.
+function uninstallAddon(id) {
+  let deferred = Promise.defer();
+
+  AddonManager.getAddonByID(id, addon => {
+    if (!addon) {
+      deferred.resolve(false);
+    }
+
+    let listener = {};
+    let handler = addon => {
+      if (addon.id !== id) {
+        return;
+      }
+
+      AddonManager.removeAddonListener(listener);
+      deferred.resolve(true);
+    };
+
+    listener.onUninstalled = handler;
+    listener.onDisabled = handler;
+
+    AddonManager.addAddonListener(listener);
+    addon.uninstall();
+  });
+
+  return deferred.promise;
+}
+
+// Returns a Promise<Addon> that is resolved with
+// the corresponding addon or rejected.
+function getAddonByID(id) {
+  let deferred = Promise.defer();
+  AddonManager.getAddonByID(id, addon => deferred.resolve(addon));
+  return deferred.promise;
+}
new file mode 100644
--- /dev/null
+++ b/dom/plugins/test/unit/test_plugin_default_state_xpi.js
@@ -0,0 +1,108 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/Promise.jsm");
+
+const ADDON_ID = "test-plugin-from-xpi@tests.mozilla.org";
+const XRE_EXTENSIONS_DIR_LIST = "XREExtDL";
+const NS_APP_PLUGINS_DIR_LIST = "APluginsDL";
+
+const gPluginHost = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
+const gXPCOMABI = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime).XPCOMABI;
+let gProfileDir = null;
+
+function getAddonRoot(profileDir, id) {
+  let dir = profileDir.clone();
+  dir.append("extensions");
+  Assert.ok(dir.exists(), "Extensions dir should exist: " + dir.path);
+  dir.append(id);
+  return dir;
+}
+
+function getTestaddonFilename() {
+  let abiPart = "";
+  if (gIsOSX) {
+    abiPart = "_" + gXPCOMABI;
+  }
+  return "testaddon" + abiPart + ".xpi";
+}
+
+function run_test() {
+  loadAddonManager();
+  gProfileDir = do_get_profile();
+  do_register_cleanup(() => shutdownManager());
+  run_next_test();
+}
+
+add_task(function* test_state() {
+  // Remove test so we will have only one "Test Plug-in" registered.
+  // xpcshell tests have plugins in per-test profiles, so that's fine.
+  let file = get_test_plugin();
+  file.remove(true);
+
+  let success = yield installAddon(getTestaddonFilename());
+  Assert.ok(success, "Should have installed addon.");
+  let addonDir = getAddonRoot(gProfileDir, ADDON_ID);
+
+  let provider = {
+    classID: Components.ID("{0af6b2d7-a06c-49b7-babc-636d292b0dbb}"),
+    QueryInterface: XPCOMUtils.generateQI([Ci.nsIDirectoryServiceProvider,
+                                           Ci.nsIDirectoryServiceProvider2]),
+
+    getFile: function (prop, persistant) {
+      throw Cr.NS_ERROR_FAILURE;
+    },
+
+    getFiles: function (prop) {
+      let result = [];
+
+      switch (prop) {
+      case XRE_EXTENSIONS_DIR_LIST:
+        result.push(addonDir);
+        break;
+      case NS_APP_PLUGINS_DIR_LIST:
+        let pluginDir = addonDir.clone();
+        pluginDir.append("plugins");
+        result.push(pluginDir);
+        break;
+      default:
+        throw Cr.NS_ERROR_FAILURE;
+      }
+
+      return {
+        QueryInterface: XPCOMUtils.generateQI([Ci.nsISimpleEnumerator]),
+        hasMoreElements: () => result.length > 0,
+        getNext: () => result.shift(),
+      };
+    },
+  };
+
+  let dirSvc = Cc["@mozilla.org/file/directory_service;1"].getService(Ci.nsIProperties);
+  dirSvc.QueryInterface(Ci.nsIDirectoryService).registerProvider(provider);
+
+  // We installed a non-restartless addon, need to restart the manager.
+  restartManager();
+  gPluginHost.reloadPlugins();
+
+  Assert.ok(addonDir.exists(), "Addon path should exist: " + addonDir.path);
+  Assert.ok(addonDir.isDirectory(), "Addon path should be a directory: " + addonDir.path);
+  let pluginDir = addonDir.clone();
+  pluginDir.append("plugins");
+  Assert.ok(pluginDir.exists(), "Addon plugins path should exist: " + pluginDir.path);
+  Assert.ok(pluginDir.isDirectory(), "Addon plugins path should be a directory: " + pluginDir.path);
+
+  let addon = yield getAddonByID(ADDON_ID);
+  Assert.ok(!addon.appDisabled, "Addon should not be appDisabled");
+  Assert.ok(addon.isActive, "Addon should be active");
+  Assert.ok(addon.isCompatible, "Addon should be compatible");
+  Assert.ok(!addon.userDisabled, "Addon should not be user disabled");
+
+  let testPlugin = get_test_plugintag();
+  Assert.notEqual(testPlugin, null, "Test plugin should have been found");
+  Assert.equal(testPlugin.enabledState, Ci.nsIPluginTag.STATE_ENABLED, "Test plugin from addon should have state enabled");
+
+  pluginDir.append(testPlugin.filename);
+  Assert.ok(pluginDir.exists(), "Plugin file should exist in addon directory: " + pluginDir.path);
+});
--- a/dom/plugins/test/unit/xpcshell.ini
+++ b/dom/plugins/test/unit/xpcshell.ini
@@ -12,8 +12,9 @@ fail-if = os == "android"
 # Bug 676953: test fails consistently on Android
 fail-if = os == "android"
 [test_nice_plugin_name.js]
 # Bug 676953: test fails consistently on Android
 fail-if = os == "android"
 [test_persist_in_prefs.js]
 [test_bug854467.js]
 [test_plugin_default_state.js]
+[test_plugin_default_state_xpi.js]
--- a/dom/system/gonk/RadioInterfaceLayer.js
+++ b/dom/system/gonk/RadioInterfaceLayer.js
@@ -65,16 +65,17 @@ const RILNETWORKINTERFACE_CID =
 const GSMICCINFO_CID =
   Components.ID("{d90c4261-a99d-47bc-8b05-b057bb7e8f8a}");
 const CDMAICCINFO_CID =
   Components.ID("{39ba3c08-aacc-46d0-8c04-9b619c387061}");
 
 const NS_XPCOM_SHUTDOWN_OBSERVER_ID      = "xpcom-shutdown";
 const kNetworkInterfaceStateChangedTopic = "network-interface-state-changed";
 const kNetworkConnStateChangedTopic      = "network-connection-state-changed";
+const kNetworkActiveChangedTopic         = "network-active-changed";
 const kSmsReceivedObserverTopic          = "sms-received";
 const kSilentSmsReceivedObserverTopic    = "silent-sms-received";
 const kSmsSendingObserverTopic           = "sms-sending";
 const kSmsSentObserverTopic              = "sms-sent";
 const kSmsFailedObserverTopic            = "sms-failed";
 const kSmsDeliverySuccessObserverTopic   = "sms-delivery-success";
 const kSmsDeliveryErrorObserverTopic     = "sms-delivery-error";
 const kMozSettingsChangedObserverTopic   = "mozsettings-changed";
@@ -1387,22 +1388,16 @@ DataConnectionHandler.prototype = {
     // We just call connect() function, so this interface should be in
     // connecting state. If this interface is already in connected state, we
     // are sure that this interface have successfully established connection
     // for other data call types before we call connect() function for current
     // data call type. In this circumstance, we have to directly update the
     // necessary data call and interface information to RILContentHelper
     // and network manager for current data call type.
     if (apnSetting.iface.connected) {
-      if (apnType == "default" && !dataInfo.connected) {
-        dataInfo.connected = true;
-        gMessageManager.sendMobileConnectionMessage("RIL:DataInfoChanged",
-                                                    this.clientId, dataInfo);
-      }
-
       // Update the interface status via-registration if the interface has
       // already been registered in the network manager.
       if (apnSetting.iface.name in gNetworkManager.networkInterfaces) {
         gNetworkManager.unregisterNetworkInterface(apnSetting.iface);
       }
       gNetworkManager.registerNetworkInterface(apnSetting.iface);
 
       Services.obs.notifyObservers(apnSetting.iface,
@@ -1426,23 +1421,16 @@ DataConnectionHandler.prototype = {
     apnSetting.iface.disconnect(apnType);
     // We just call disconnect() function, so this interface should be in
     // disconnecting state. If this interface is still in connected state, we
     // are sure that other data call types still need this connection of this
     // interface. In this circumstance, we have to directly update the
     // necessary data call and interface information to RILContentHelper
     // and network manager for current data call type.
     if (apnSetting.iface.connectedTypes.length && apnSetting.iface.connected) {
-      let dataInfo = this.radioInterface.rilContext.data;
-      if (apnType == "default" && dataInfo.connected) {
-        dataInfo.connected = false;
-        gMessageManager.sendMobileConnectionMessage("RIL:DataInfoChanged",
-                                                    this.clientId, dataInfo);
-      }
-
       // Update the interface status via-registration if the interface has
       // already been registered in the network manager.
       if (apnSetting.iface.name in gNetworkManager.networkInterfaces) {
         gNetworkManager.unregisterNetworkInterface(apnSetting.iface);
       }
       gNetworkManager.registerNetworkInterface(apnSetting.iface);
 
       Services.obs.notifyObservers(apnSetting.iface,
@@ -1506,35 +1494,16 @@ DataConnectionHandler.prototype = {
 
     this._deliverDataCallCallback("dataCallError", [message]);
   },
 
   /**
    * Handle data call state changes.
    */
   handleDataCallState: function(datacall) {
-    let data = this.radioInterface.rilContext.data;
-    let defaultApnSetting = this.apnSettings && this.apnSettings.byType.default;
-    let dataCallConnected =
-        (datacall.state == RIL.GECKO_NETWORK_STATE_CONNECTED);
-    if (defaultApnSetting && datacall.ifname) {
-      if (dataCallConnected && datacall.apn == defaultApnSetting.apn &&
-          defaultApnSetting.iface.inConnectedTypes("default")) {
-        data.connected = dataCallConnected;
-        gMessageManager.sendMobileConnectionMessage("RIL:DataInfoChanged",
-                                                     this.clientId, data);
-        data.apn = datacall.apn;
-      } else if (!dataCallConnected && datacall.apn == data.apn) {
-        data.connected = dataCallConnected;
-        delete data.apn;
-        gMessageManager.sendMobileConnectionMessage("RIL:DataInfoChanged",
-                                                     this.clientId, data);
-      }
-    }
-
     this._deliverDataCallCallback("dataCallStateChanged", [datacall]);
 
     // Process pending radio power off request after all data calls
     // are disconnected.
     if (datacall.state == RIL.GECKO_NETWORK_STATE_UNKNOWN &&
         this.allDataDisconnected()) {
       if (gRadioEnabledController.isDeactivatingDataCalls()) {
         if (DEBUG) {
@@ -1873,16 +1842,17 @@ function RadioInterface(aClientId, aWork
   // ranges separated by comma, to set listening channels.
   lock.get(kSettingsCellBroadcastSearchList, this);
 
   Services.obs.addObserver(this, kMozSettingsChangedObserverTopic, false);
   Services.obs.addObserver(this, kSysClockChangeObserverTopic, false);
   Services.obs.addObserver(this, kScreenStateChangedTopic, false);
 
   Services.obs.addObserver(this, kNetworkConnStateChangedTopic, false);
+  Services.obs.addObserver(this, kNetworkActiveChangedTopic, false);
   Services.prefs.addObserver(kPrefCellBroadcastDisabled, this, false);
 
   this.portAddressedSmsApps = {};
   this.portAddressedSmsApps[WAP.WDP_PORT_PUSH] = this.handleSmsWdpPortPush.bind(this);
 
   this._receivedSmsSegmentsMap = {};
 
   this._sntp = new Sntp(this.setClockBySntp.bind(this),
@@ -1914,16 +1884,17 @@ RadioInterface.prototype = {
   shutdown: function() {
     // Release the CPU wake lock for handling the received SMS.
     this._releaseSmsHandledWakeLock();
 
     Services.obs.removeObserver(this, kMozSettingsChangedObserverTopic);
     Services.obs.removeObserver(this, kSysClockChangeObserverTopic);
     Services.obs.removeObserver(this, kScreenStateChangedTopic);
     Services.obs.removeObserver(this, kNetworkConnStateChangedTopic);
+    Services.obs.removeObserver(this, kNetworkActiveChangedTopic);
   },
 
   /**
    * A utility function to copy objects. The srcInfo may contain
    * "rilMessageType", should ignore it.
    */
   updateInfo: function(srcInfo, destInfo) {
     for (let key in srcInfo) {
@@ -2445,23 +2416,22 @@ RadioInterface.prototype = {
   updateDataConnection: function(newInfo, batch) {
     let dataInfo = this.rilContext.data;
     dataInfo.state = newInfo.state;
     dataInfo.roaming = newInfo.roaming;
     dataInfo.emergencyCallsOnly = newInfo.emergencyCallsOnly;
     dataInfo.type = newInfo.type;
     // For the data connection, the `connected` flag indicates whether
     // there's an active data call.
-    let connHandler = gDataConnectionManager.getConnectionHandler(this.clientId);
-    let apnSettings = connHandler.apnSettings;
-    let apnSetting = apnSettings && apnSettings.byType.default;
     dataInfo.connected = false;
-    if (apnSetting) {
-      dataInfo.connected = (connHandler.getDataCallStateByType("default") ==
-                            RIL.GECKO_NETWORK_STATE_CONNECTED);
+    if (gNetworkManager.active &&
+        gNetworkManager.active.type ===
+          Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE &&
+        gNetworkManager.active.serviceId === this.clientId) {
+      dataInfo.connected = true;
     }
 
     // Make sure we also reset the operator and signal strength information
     // if we drop off the network.
     if (newInfo.state !== RIL.GECKO_MOBILE_CONNECTION_STATE_REGISTERED) {
       dataInfo.cell = null;
       dataInfo.network = null;
       dataInfo.signalStrength = null;
@@ -2470,16 +2440,18 @@ RadioInterface.prototype = {
       dataInfo.cell = newInfo.cell;
       dataInfo.network = this.operatorInfo;
     }
 
     if (!batch) {
       gMessageManager.sendMobileConnectionMessage("RIL:DataInfoChanged",
                                                   this.clientId, dataInfo);
     }
+
+    let connHandler = gDataConnectionManager.getConnectionHandler(this.clientId);
     connHandler.updateRILNetworkInterface();
   },
 
   getPreferredNetworkType: function(target, message) {
     this.workerMessenger.send("getPreferredNetworkType", message, (function(response) {
       if (response.success) {
         response.type = RIL.RIL_PREFERRED_NETWORK_TYPE_TO_GECKO[response.networkType];
       }
@@ -3359,16 +3331,31 @@ RadioInterface.prototype = {
           }
         }
 
         // SNTP won't update unless the SNTP is already expired.
         if (this._sntp.isExpired()) {
           this._sntp.request();
         }
         break;
+      case kNetworkActiveChangedTopic:
+        let dataInfo = this.rilContext.data;
+        let connected = false;
+        if (gNetworkManager.active &&
+            gNetworkManager.active.type ===
+              Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE &&
+            gNetworkManager.active.serviceId === this.clientId) {
+          connected = true;
+        }
+        if (dataInfo.connected !== connected) {
+          dataInfo.connected = connected;
+          gMessageManager.sendMobileConnectionMessage("RIL:DataInfoChanged",
+                                                      this.clientId, dataInfo);
+        }
+        break;
       case kScreenStateChangedTopic:
         this.workerMessenger.send("setScreenState", { on: (data === "on") });
         break;
     }
   },
 
   supportedNetworkTypes: null,
 
--- a/gfx/thebes/gfxContext.h
+++ b/gfx/thebes/gfxContext.h
@@ -826,24 +826,22 @@ public:
   }
 
   void SetContext(gfxContext *aContext) {
     NS_ASSERTION(!mContext, "Not going to call Restore() on some context!!!");
     mContext = aContext;
     mContext->Save();    
   }
 
-  void Reset(gfxContext *aContext) {
-    // Do the equivalent of destroying and re-creating this object.
-    NS_PRECONDITION(aContext, "must provide a context");
-    if (mContext) {
-      mContext->Restore();
+  void EnsureSaved(gfxContext *aContext) {
+    MOZ_ASSERT(!mContext || mContext == aContext, "wrong context");
+    if (!mContext) {
+        mContext = aContext;
+        mContext->Save();
     }
-    mContext = aContext;
-    mContext->Save();
   }
 
 private:
   gfxContext *mContext;
 };
 
 /**
  * Sentry helper class for functions with multiple return points that need to
--- a/js/src/assembler/assembler/X86Assembler.h
+++ b/js/src/assembler/assembler/X86Assembler.h
@@ -361,16 +361,17 @@ private:
 
         GROUP2_OP_SHL = 4,
         GROUP2_OP_SHR = 5,
         GROUP2_OP_SAR = 7,
 
         GROUP3_OP_TEST = 0,
         GROUP3_OP_NOT  = 2,
         GROUP3_OP_NEG  = 3,
+        GROUP3_OP_IMUL = 5,
         GROUP3_OP_DIV  = 6,
         GROUP3_OP_IDIV = 7,
 
         GROUP5_OP_INC   = 0,
         GROUP5_OP_DEC   = 1,
         GROUP5_OP_CALLN = 2,
         GROUP5_OP_JMPN  = 4,
         GROUP5_OP_PUSH  = 6,
@@ -1150,16 +1151,23 @@ public:
 #endif
 
     void imull_rr(RegisterID src, RegisterID dst)
     {
         spew("imull      %s, %s", nameIReg(4,src), nameIReg(4, dst));
         m_formatter.twoByteOp(OP2_IMUL_GvEv, dst, src);
     }
 
+    void imull_r(RegisterID multiplier)
+    {
+        spew("imull      %s",
+             nameIReg(4, multiplier));
+        m_formatter.oneByteOp(OP_GROUP3_Ev, GROUP3_OP_IMUL, multiplier);
+    }
+
     void imull_mr(int offset, RegisterID base, RegisterID dst)
     {
         spew("imull      %s0x%x(%s), %s",
              PRETTY_PRINT_OFFSET(offset), nameIReg(base), nameIReg(4,dst));
         m_formatter.twoByteOp(OP2_IMUL_GvEv, dst, base, offset);
     }
 
     void imull_i32r(RegisterID src, int32_t value, RegisterID dst)
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/testDivModWithIntMin.js
@@ -0,0 +1,19 @@
+var intMin = -2147483648;
+
+assertEq(intMin % (-2147483648), -0);
+assertEq(intMin % (-3), -2);
+assertEq(intMin % (-1), -0);
+assertEq(intMin % 1, -0);
+assertEq(intMin % 3, -2);
+assertEq(intMin % 10, -8);
+assertEq(intMin % 2147483647, -1);
+
+assertEq((-2147483648) % (-2147483648), -0);
+for (var i = -10; i <= 10; ++i)
+    assertEq(i % (-2147483648), i);
+assertEq(2147483647 % (-2147483648), 2147483647);
+
+assertEq((-2147483648) / (-2147483648), 1);
+assertEq(0 / (-2147483648), -0);
+assertEq((-2147483648) / (-1), 2147483648);
+assertEq((-0) / (-2147483648), 0);
--- a/js/src/jit/BaselineBailouts.cpp
+++ b/js/src/jit/BaselineBailouts.cpp
@@ -1334,36 +1334,36 @@ jit::BailoutIonToBaseline(JSContext *cx,
     BaselineStackBuilder builder(iter, 1024);
     if (!builder.init())
         return BAILOUT_RETURN_FATAL_ERROR;
     IonSpew(IonSpew_BaselineBailouts, "  Incoming frame ptr = %p", builder.startFrame());
 
     SnapshotIterator snapIter(iter);
 
     RootedFunction callee(cx, iter.maybeCallee());
+    RootedScript scr(cx, iter.script());
     if (callee) {
         IonSpew(IonSpew_BaselineBailouts, "  Callee function (%s:%u)",
-                callee->existingScript()->filename(), callee->existingScript()->lineno());
+                scr->filename(), scr->lineno());
     } else {
         IonSpew(IonSpew_BaselineBailouts, "  No callee!");
     }
 
     if (iter.isConstructing())
         IonSpew(IonSpew_BaselineBailouts, "  Constructing!");
     else
         IonSpew(IonSpew_BaselineBailouts, "  Not constructing!");
 
     IonSpew(IonSpew_BaselineBailouts, "  Restoring frames:");
     size_t frameNo = 0;
 
     // Reconstruct baseline frames using the builder.
     RootedScript caller(cx);
     jsbytecode *callerPC = nullptr;
     RootedFunction fun(cx, callee);
-    RootedScript scr(cx, iter.script());
     AutoValueVector startFrameFormals(cx);
 
     RootedScript topCaller(cx);
     jsbytecode *topCallerPC = nullptr;
 
     while (true) {
         MOZ_ASSERT(snapIter.instruction()->isResumePoint());
 
@@ -1395,17 +1395,17 @@ jit::BailoutIonToBaseline(JSContext *cx,
         if (handleException)
             break;
 
         JS_ASSERT(nextCallee);
         JS_ASSERT(callPC);
         caller = scr;
         callerPC = callPC;
         fun = nextCallee;
-        scr = fun->existingScript();
+        scr = fun->existingScriptForInlinedFunction();
 
         // Save top caller info for adjusting SPS frames later.
         if (!topCaller) {
             JS_ASSERT(frameNo == 0);
             topCaller = caller;
             topCallerPC = callerPC;
         }
 
--- a/js/src/jit/IonFrames.cpp
+++ b/js/src/jit/IonFrames.cpp
@@ -1647,17 +1647,17 @@ InlineFrameIteratorMaybeGC<allowGC>::fin
 
         si_.nextFrame();
 
         callee_ = &funval.toObject().as<JSFunction>();
 
         // Inlined functions may be clones that still point to the lazy script
         // for the executed script, if they are clones. The actual script
         // exists though, just make sure the function points to it.
-        script_ = callee_->existingScript();
+        script_ = callee_->existingScriptForInlinedFunction();
         MOZ_ASSERT(script_->hasBaselineScript());
 
         pc_ = script_->offsetToPC(si_.pcOffset());
     }
 
     // The first time we do not know the number of frames, we only settle on the
     // last frame, and update the number of frames based on the number of
     // iteration that we have done.
--- a/js/src/jit/MIR.cpp
+++ b/js/src/jit/MIR.cpp
@@ -153,17 +153,17 @@ MDefinition::valueHash() const
     for (size_t i = 0, e = numOperands(); i < e; i++) {
         uint32_t valueNumber = getOperand(i)->valueNumber();
         out = valueNumber + (out << 6) + (out << 16) - out;
     }
     return out;
 }
 
 bool
-MDefinition::congruentIfOperandsEqual(MDefinition *ins) const
+MDefinition::congruentIfOperandsEqual(const MDefinition *ins) const
 {
     if (op() != ins->op())
         return false;
 
     if (type() != ins->type())
         return false;
 
     if (isEffectful() || ins->isEffectful())
@@ -486,17 +486,17 @@ MConstant::MConstant(const js::Value &vp
 HashNumber
 MConstant::valueHash() const
 {
     // This disregards some state, since values are 64 bits. But for a hash,
     // it's completely acceptable.
     return (HashNumber)JSVAL_TO_IMPL(value_).asBits;
 }
 bool
-MConstant::congruentTo(MDefinition *ins) const
+MConstant::congruentTo(const MDefinition *ins) const
 {
     if (!ins->isConstant())
         return false;
     return ins->toConstant()->value() == value();
 }
 
 void
 MConstant::printOpcode(FILE *fp) const
@@ -669,17 +669,17 @@ MParameter::printOpcode(FILE *fp) const
 
 HashNumber
 MParameter::valueHash() const
 {
     return index_; // Why not?
 }
 
 bool
-MParameter::congruentTo(MDefinition *ins) const
+MParameter::congruentTo(const MDefinition *ins) const
 {
     if (!ins->isParameter())
         return false;
 
     return ins->toParameter()->index() == index_;
 }
 
 MCall *
@@ -755,25 +755,25 @@ MCallDOMNative::computeMovable()
     JS_ASSERT_IF(jitInfo->isMovable,
                  jitInfo->aliasSet() != JSJitInfo::AliasEverything);
 
     if (jitInfo->isMovable && !isEffectful())
         setMovable();
 }
 
 bool
-MCallDOMNative::congruentTo(MDefinition *ins) const
+MCallDOMNative::congruentTo(const MDefinition *ins) const
 {
     if (!isMovable())
         return false;
 
     if (!ins->isCall())
         return false;
 
-    MCall *call = ins->toCall();
+    const MCall *call = ins->toCall();
 
     if (!call->isCallDOMNative())
         return false;
 
     if (getSingleTarget() != call->getSingleTarget())
         return false;
 
     if (isConstructing() != call->isConstructing())
@@ -976,17 +976,17 @@ MPhi::foldsTo(TempAllocator &alloc, bool
 {
     if (MDefinition *def = operandIfRedundant())
         return def;
 
     return this;
 }
 
 bool
-MPhi::congruentTo(MDefinition *ins) const
+MPhi::congruentTo(const MDefinition *ins) const
 {
     if (!ins->isPhi())
         return false;
     // Since we do not know which predecessor we are merging from, we must
     // assume that phi instructions in different blocks are not equal.
     // (Bug 674656)
     if (ins->block()->id() != block()->id())
         return false;
@@ -2712,69 +2712,69 @@ MNewArray::shouldUseVM() const
     // when mir hints it needs to get allocated immediately,
     // but only when data doesn't fit the available array slots.
     bool allocating = isAllocating() && count() > arraySlots;
 
     return templateObject()->hasSingletonType() || allocating;
 }
 
 bool
-MLoadFixedSlot::mightAlias(MDefinition *store)
+MLoadFixedSlot::mightAlias(const MDefinition *store) const
 {
     if (store->isStoreFixedSlot() && store->toStoreFixedSlot()->slot() != slot())
         return false;
     return true;
 }
 
 bool
-MAsmJSLoadHeap::mightAlias(MDefinition *def)
+MAsmJSLoadHeap::mightAlias(const MDefinition *def) const
 {
     if (def->isAsmJSStoreHeap()) {
-        MAsmJSStoreHeap *store = def->toAsmJSStoreHeap();
+        const MAsmJSStoreHeap *store = def->toAsmJSStoreHeap();
         if (store->viewType() != viewType())
             return true;
         if (!ptr()->isConstant() || !store->ptr()->isConstant())
             return true;
-        MConstant *otherPtr = store->ptr()->toConstant();
+        const MConstant *otherPtr = store->ptr()->toConstant();
         return ptr()->toConstant()->value() == otherPtr->value();
     }
     return true;
 }
 
 bool
-MAsmJSLoadHeap::congruentTo(MDefinition *ins) const
+MAsmJSLoadHeap::congruentTo(const MDefinition *ins) const
 {
     if (!ins->isAsmJSLoadHeap())
         return false;
-    MAsmJSLoadHeap *load = ins->toAsmJSLoadHeap();
+    const MAsmJSLoadHeap *load = ins->toAsmJSLoadHeap();
     return load->viewType() == viewType() && congruentIfOperandsEqual(load);
 }
 
 bool
-MAsmJSLoadGlobalVar::mightAlias(MDefinition *def)
+MAsmJSLoadGlobalVar::mightAlias(const MDefinition *def) const
 {
     if (def->isAsmJSStoreGlobalVar()) {
-        MAsmJSStoreGlobalVar *store = def->toAsmJSStoreGlobalVar();
+        const MAsmJSStoreGlobalVar *store = def->toAsmJSStoreGlobalVar();
         return store->globalDataOffset() == globalDataOffset_;
     }
     return true;
 }
 
 bool
-MAsmJSLoadGlobalVar::congruentTo(MDefinition *ins) const
+MAsmJSLoadGlobalVar::congruentTo(const MDefinition *ins) const
 {
     if (ins->isAsmJSLoadGlobalVar()) {
-        MAsmJSLoadGlobalVar *load = ins->toAsmJSLoadGlobalVar();
+        const MAsmJSLoadGlobalVar *load = ins->toAsmJSLoadGlobalVar();
         return globalDataOffset_ == load->globalDataOffset_;
     }
     return false;
 }
 
 bool
-MLoadSlot::mightAlias(MDefinition *store)
+MLoadSlot::mightAlias(const MDefinition *store) const
 {
     if (store->isStoreSlot() && store->toStoreSlot()->slot() != slot())
         return false;
     return true;
 }
 
 void
 InlinePropertyTable::trimTo(ObjectVector &targets, BoolVector &choiceSet)
@@ -2875,26 +2875,26 @@ MGetElementCache::allowDoubleResult() co
 
 size_t
 MStoreTypedArrayElementStatic::length() const
 {
     return typedArray_->byteLength();
 }
 
 bool
-MGetPropertyPolymorphic::mightAlias(MDefinition *store)
+MGetPropertyPolymorphic::mightAlias(const MDefinition *store) const
 {
     // Allow hoisting this instruction if the store does not write to a
     // slot read by this instruction.
 
     if (!store->isStoreFixedSlot() && !store->isStoreSlot())
         return true;
 
     for (size_t i = 0; i < numShapes(); i++) {
-        Shape *shape = this->shape(i);
+        const Shape *shape = this->shape(i);
         if (shape->slot() < shape->numFixedSlots()) {
             // Fixed slot.
             uint32_t slot = shape->slot();
             if (store->isStoreFixedSlot() && store->toStoreFixedSlot()->slot() != slot)
                 continue;
             if (store->isStoreSlot())
                 continue;
         } else {
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -371,20 +371,20 @@ class MDefinition : public MNode
         return range_;
     }
     void setRange(Range *range) {
         JS_ASSERT(type() != MIRType_None);
         range_ = range;
     }
 
     virtual HashNumber valueHash() const;
-    virtual bool congruentTo(MDefinition *ins) const {
+    virtual bool congruentTo(const MDefinition *ins) const {
         return false;
     }
-    bool congruentIfOperandsEqual(MDefinition *ins) const;
+    bool congruentIfOperandsEqual(const MDefinition *ins) const;
     virtual MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers);
     virtual void analyzeEdgeCasesForward();
     virtual void analyzeEdgeCasesBackward();
 
     virtual bool truncate();
     virtual bool isOperandTruncated(size_t index) const;
 
     // Compute an absolute or symbolic range for the value of this node.
@@ -579,17 +579,17 @@ class MDefinition : public MNode
     }
     virtual AliasSet getAliasSet() const {
         // Instructions are effectful by default.
         return AliasSet::Store(AliasSet::Any);
     }
     bool isEffectful() const {
         return getAliasSet().isStore();
     }
-    virtual bool mightAlias(MDefinition *store) {
+    virtual bool mightAlias(const MDefinition *store) const {
         // Return whether this load may depend on the specified store, given
         // that the alias sets intersect. This may be refined to exclude
         // possible aliasing in cases where alias set flags are too imprecise.
         JS_ASSERT(!isEffectful() && store->isEffectful());
         JS_ASSERT(getAliasSet().flags() & store->getAliasSet().flags());
         return true;
     }
 };
@@ -740,40 +740,40 @@ class MBinaryInstruction : public MAryIn
         return op() ^ lhs->valueNumber() ^ rhs->valueNumber();
     }
     void swapOperands() {
         MDefinition *temp = getOperand(0);
         replaceOperand(0, getOperand(1));
         replaceOperand(1, temp);
     }
 
-    bool binaryCongruentTo(MDefinition *ins) const
+    bool binaryCongruentTo(const MDefinition *ins) const
     {
         if (op() != ins->op())
             return false;
 
         if (type() != ins->type())
             return false;
 
         if (isEffectful() || ins->isEffectful())
             return false;
 
-        MDefinition *left = getOperand(0);
-        MDefinition *right = getOperand(1);
-        MDefinition *tmp;
+        const MDefinition *left = getOperand(0);
+        const MDefinition *right = getOperand(1);
+        const MDefinition *tmp;
 
         if (isCommutative() && left->valueNumber() > right->valueNumber()) {
             tmp = right;
             right = left;
             left = tmp;
         }
 
-        MBinaryInstruction *bi = static_cast<MBinaryInstruction *>(ins);
-        MDefinition *insLeft = bi->getOperand(0);
-        MDefinition *insRight = bi->getOperand(1);
+        const MBinaryInstruction *bi = static_cast<const MBinaryInstruction *>(ins);
+        const MDefinition *insLeft = bi->getOperand(0);
+        const MDefinition *insRight = bi->getOperand(1);
         if (isCommutative() && insLeft->valueNumber() > insRight->valueNumber()) {
             tmp = insRight;
             insRight = insLeft;
             insLeft = tmp;
         }
 
         return (left->valueNumber() == insLeft->valueNumber()) &&
                (right->valueNumber() == insRight->valueNumber());
@@ -918,17 +918,17 @@ class MConstant : public MNullaryInstruc
     const bool valueToBoolean() const {
         // A hack to avoid this wordy pattern everywhere in the JIT.
         return ToBoolean(HandleValue::fromMarkedLocation(&value_));
     }
 
     void printOpcode(FILE *fp) const;
 
     HashNumber valueHash() const;
-    bool congruentTo(MDefinition *ins) const;
+    bool congruentTo(const MDefinition *ins) const;
 
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 
     bool updateForReplacement(MDefinition *def) {
         MConstant *c = def->toConstant();
         // During constant folding, we don't want to replace a float32
@@ -986,32 +986,32 @@ class MParameter : public MNullaryInstru
     static MParameter *New(TempAllocator &alloc, int32_t index, types::TemporaryTypeSet *types);
 
     int32_t index() const {
         return index_;
     }
     void printOpcode(FILE *fp) const;
 
     HashNumber valueHash() const;
-    bool congruentTo(MDefinition *ins) const;
+    bool congruentTo(const MDefinition *ins) const;
 };
 
 class MCallee : public MNullaryInstruction
 {
   public:
     MCallee()
     {
         setResultType(MIRType_Object);
         setMovable();
     }
 
   public:
     INSTRUCTION_HEADER(Callee)
 
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
 
     static MCallee *New(TempAllocator &alloc) {
         return new(alloc) MCallee();
     }
     AliasSet getAliasSet() const {
         return AliasSet::None();
@@ -1915,17 +1915,17 @@ class MCallDOMNative : public MCall
 
     friend MCall *MCall::New(TempAllocator &alloc, JSFunction *target, size_t maxArgc,
                              size_t numActualArgs, bool construct, bool isDOMCall);
 
     const JSJitInfo *getJitInfo() const;
   public:
     virtual AliasSet getAliasSet() const MOZ_OVERRIDE;
 
-    virtual bool congruentTo(MDefinition *ins) const MOZ_OVERRIDE;
+    virtual bool congruentTo(const MDefinition *ins) const MOZ_OVERRIDE;
 
     virtual bool isCallDOMNative() const MOZ_OVERRIDE {
         return true;
     }
 
     virtual void computeMovable() MOZ_OVERRIDE;
 };
 
@@ -2294,17 +2294,17 @@ class MCompare
 # ifdef DEBUG
     bool isConsistentFloat32Use(MUse *use) const {
         // Both sides of the compare can be Float32
         return compareType_ == Compare_Float32;
     }
 # endif
 
   protected:
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         if (!binaryCongruentTo(ins))
             return false;
         return compareType() == ins->toCompare()->compareType() &&
                jsop() == ins->toCompare()->jsop();
     }
 };
 
 // Takes a typed value and returns an untyped value.
@@ -2330,17 +2330,17 @@ class MBox : public MUnaryInstruction
     static MBox *New(TempAllocator &alloc, MDefinition *ins)
     {
         // Cannot box a box.
         JS_ASSERT(ins->type() != MIRType_Value);
 
         return new(alloc) MBox(alloc, ins);
     }
 
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 };
 
 // Note: the op may have been inverted during lowering (to put constants in a
@@ -2412,17 +2412,17 @@ class MUnbox : public MUnaryInstruction,
     BailoutKind bailoutKind() const {
         // If infallible, no bailout should be generated.
         JS_ASSERT(fallible());
         return bailoutKind_;
     }
     bool fallible() const {
         return mode() != Infallible;
     }
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         if (!ins->isUnbox() || ins->toUnbox()->mode() != mode())
             return false;
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
     void printOpcode(FILE *fp) const;
@@ -2840,17 +2840,17 @@ class MToDouble
         return conversion_;
     }
 
     TypePolicy *typePolicy() {
         return this;
     }
 
     MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers);
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         if (!ins->isToDouble() || ins->toToDouble()->conversion() != conversion())
             return false;
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 
@@ -2902,17 +2902,17 @@ class MToFloat32
         return conversion_;
     }
 
     TypePolicy *typePolicy() {
         return this;
     }
 
     virtual MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers);
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         if (!ins->isToFloat32() || ins->toToFloat32()->conversion() != conversion())
             return false;
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 
@@ -2935,17 +2935,17 @@ class MAsmJSUnsignedToDouble
 
   public:
     INSTRUCTION_HEADER(AsmJSUnsignedToDouble);
     static MAsmJSUnsignedToDouble *NewAsmJS(TempAllocator &alloc, MDefinition *def) {
         return new(alloc) MAsmJSUnsignedToDouble(def);
     }
 
     MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers);
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 };
 
 // Converts a uint32 to a float32 (coming from asm.js).
@@ -2961,17 +2961,17 @@ class MAsmJSUnsignedToFloat32
 
   public:
     INSTRUCTION_HEADER(AsmJSUnsignedToFloat32);
     static MAsmJSUnsignedToFloat32 *NewAsmJS(TempAllocator &alloc, MDefinition *def) {
         return new(alloc) MAsmJSUnsignedToFloat32(def);
     }
 
     MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers);
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 
     bool canProduceFloat32() const { return true; }
 };
@@ -3019,17 +3019,17 @@ class MToInt32
     TypePolicy *typePolicy() {
         return this;
     }
 
     MacroAssembler::IntConversionInputKind conversion() const {
         return conversion_;
     }
 
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
 
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
     void computeRange(TempAllocator &alloc);
 
@@ -3055,17 +3055,17 @@ class MTruncateToInt32 : public MUnaryIn
         return new(alloc) MTruncateToInt32(def);
     }
     static MTruncateToInt32 *NewAsmJS(TempAllocator &alloc, MDefinition *def) {
         return new(alloc) MTruncateToInt32(def);
     }
 
     MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers);
 
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 
     void computeRange(TempAllocator &alloc);
     bool isOperandTruncated(size_t index) const;
@@ -3096,17 +3096,17 @@ class MToString : public MUnaryInstructi
     INSTRUCTION_HEADER(ToString)
     static MToString *New(TempAllocator &alloc, MDefinition *def)
     {
         return new(alloc) MToString(def);
     }
 
     MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers);
 
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const {
         JS_ASSERT(!input()->mightBeType(MIRType_Object));
         return AliasSet::None();
     }
 };
 
@@ -3129,17 +3129,17 @@ class MBitNot
 
     TypePolicy *typePolicy() {
         return this;
     }
 
     MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers);
     void infer();
 
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const {
         if (specialization_ == MIRType_None)
             return AliasSet::Store(AliasSet::Any);
         return AliasSet::None();
     }
     void computeRange(TempAllocator &alloc);
@@ -3232,17 +3232,17 @@ class MBinaryBitwiseInstruction
 
     MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers);
     MDefinition *foldUnnecessaryBitop();
     virtual MDefinition *foldIfZero(size_t operand) = 0;
     virtual MDefinition *foldIfNegOne(size_t operand) = 0;
     virtual MDefinition *foldIfEqual()  = 0;
     virtual void infer(BaselineInspector *inspector, jsbytecode *pc);
 
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         return binaryCongruentTo(ins);
     }
     AliasSet getAliasSet() const {
         if (specialization_ >= MIRType_Object)
             return AliasSet::Store(AliasSet::Any);
         return AliasSet::None();
     }
 
@@ -3448,17 +3448,17 @@ class MBinaryArithInstruction
 
     void setInt32() {
         specialization_ = MIRType_Int32;
         setResultType(MIRType_Int32);
     }
 
     virtual void trySpecializeFloat32(TempAllocator &alloc);
 
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         return binaryCongruentTo(ins);
     }
     AliasSet getAliasSet() const {
         if (specialization_ >= MIRType_Object)
             return AliasSet::Store(AliasSet::Any);
         return AliasSet::None();
     }
 
@@ -3499,17 +3499,17 @@ class MMinMax
     }
     MIRType specialization() const {
         return specialization_;
     }
 
     TypePolicy *typePolicy() {
         return this;
     }
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         if (!ins->isMinMax())
             return false;
         if (isMax() != ins->toMinMax()->isMax())
             return false;
         return congruentIfOperandsEqual(ins);
     }
 
     AliasSet getAliasSet() const {
@@ -3546,17 +3546,17 @@ class MAbs
         return ins;
     }
     MDefinition *num() const {
         return getOperand(0);
     }
     TypePolicy *typePolicy() {
         return this;
     }
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
     bool fallible() const;
 
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
     void computeRange(TempAllocator &alloc);
@@ -3587,17 +3587,17 @@ class MSqrt
         return new(alloc) MSqrt(num, type);
     }
     MDefinition *num() const {
         return getOperand(0);
     }
     TypePolicy *typePolicy() {
         return this;
     }
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
 
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
     void computeRange(TempAllocator &alloc);
 
@@ -3630,17 +3630,17 @@ class MAtan2
     MDefinition *x() const {
         return getOperand(1);
     }
 
     TypePolicy *typePolicy() {
         return this;
     }
 
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
 
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 
     bool possiblyCalls() const {
@@ -3673,17 +3673,17 @@ class MHypot
     MDefinition *y() const {
         return getOperand(1);
     }
 
     TypePolicy *typePolicy() {
         return this;
     }
 
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
 
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 
     bool possiblyCalls() const {
@@ -3714,17 +3714,17 @@ class MPow
     }
 
     MDefinition *input() const {
         return lhs();
     }
     MDefinition *power() const {
         return rhs();
     }
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
     TypePolicy *typePolicy() {
         return this;
     }
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
@@ -3752,17 +3752,17 @@ class MPowHalf
         setMovable();
     }
 
   public:
     INSTRUCTION_HEADER(PowHalf)
     static MPowHalf *New(TempAllocator &alloc, MDefinition *input) {
         return new(alloc) MPowHalf(input);
     }
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
     bool operandIsNeverNegativeInfinity() const {
         return operandIsNeverNegativeInfinity_;
     }
     bool operandIsNeverNegativeZero() const {
         return operandIsNeverNegativeZero_;
     }
@@ -3860,17 +3860,17 @@ class MMathFunction
         return function_;
     }
     const MathCache *cache() const {
         return cache_;
     }
     TypePolicy *typePolicy() {
         return this;
     }
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         if (!ins->isMathFunction())
             return false;
         if (ins->toMathFunction()->function() != function())
             return false;
         return congruentIfOperandsEqual(ins);
     }
 
     AliasSet getAliasSet() const {
@@ -4016,21 +4016,21 @@ class MMul : public MBinaryArithInstruct
     MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers);
     void analyzeEdgeCasesForward();
     void analyzeEdgeCasesBackward();
 
     double getIdentity() {
         return 1;
     }
 
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         if (!ins->isMul())
             return false;
 
-        MMul *mul = ins->toMul();
+        const MMul *mul = ins->toMul();
         if (canBeNegativeZero_ != mul->canBeNegativeZero())
             return false;
 
         if (mode_ != mul->mode())
             return false;
 
         return binaryCongruentTo(ins);
     }
@@ -4055,17 +4055,17 @@ class MMul : public MBinaryArithInstruct
     }
 
     bool isFloat32Commutative() const { return true; }
 
     void computeRange(TempAllocator &alloc);
     bool truncate();
     bool isOperandTruncated(size_t index) const;
 
-    Mode mode() { return mode_; }
+    Mode mode() const { return mode_; }
 };
 
 class MDiv : public MBinaryArithInstruction
 {
     bool canBeNegativeZero_;
     bool canBeNegativeOverflow_;
     bool canBeDivideByZero_;
     bool canBeNegativeDividend_;
@@ -4252,17 +4252,17 @@ class MConcat
     INSTRUCTION_HEADER(Concat)
     static MConcat *New(TempAllocator &alloc, MDefinition *left, MDefinition *right) {
         return new(alloc) MConcat(left, right);
     }
 
     TypePolicy *typePolicy() {
         return this;
     }
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 };
 
 class MConcatPar
@@ -4291,17 +4291,17 @@ class MConcatPar
     }
     MDefinition *lhs() const {
         return getOperand(1);
     }
     MDefinition *rhs() const {
         return getOperand(2);
     }
 
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 };
 
 class MCharCodeAt
@@ -4321,17 +4321,17 @@ class MCharCodeAt
     static MCharCodeAt *New(TempAllocator &alloc, MDefinition *str, MDefinition *index) {
         return new(alloc) MCharCodeAt(str, index);
     }
 
     TypePolicy *typePolicy() {
         return this;
     }
 
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
 
     virtual AliasSet getAliasSet() const {
         // Strings are immutable, so there is no implicit dependency.
         return AliasSet::None();
     }
 
@@ -4459,17 +4459,17 @@ class MLoadArrowThis
         return new(alloc) MLoadArrowThis(callee);
     }
     MDefinition *callee() const {
         return getOperand(0);
     }
     TypePolicy *typePolicy() {
         return this;
     }
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const {
         // An arrow function's lexical |this| value is immutable.
         return AliasSet::None();
     }
 };
 
@@ -4565,17 +4565,17 @@ class MPhi MOZ_FINAL : public MDefinitio
     void addInput(MDefinition *ins);
 
     // Appends a new input to the input vector. May call realloc_().
     // Prefer reserveLength() and addInput() instead, where possible.
     bool addInputSlow(MDefinition *ins, bool *ptypeChange = nullptr);
 
     MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers);
 
-    bool congruentTo(MDefinition *ins) const;
+    bool congruentTo(const MDefinition *ins) const;
 
     bool isIterator() const {
         return isIterator_;
     }
     void setIterator() {
         isIterator_ = true;
     }
 
@@ -5050,17 +5050,17 @@ class MStringReplace
 
   public:
     INSTRUCTION_HEADER(StringReplace);
 
     static MStringReplace *New(TempAllocator &alloc, MDefinition *string, MDefinition *pattern, MDefinition *replacement) {
         return new(alloc) MStringReplace(string, pattern, replacement);
     }
 
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 };
 
 struct LambdaFunctionInfo
@@ -5249,17 +5249,17 @@ class MSlots
     }
 
     TypePolicy *typePolicy() {
         return this;
     }
     MDefinition *object() const {
         return getOperand(0);
     }
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const {
         return AliasSet::Load(AliasSet::ObjectFields);
     }
 };
 
 // Returns obj->elements.
@@ -5282,17 +5282,17 @@ class MElements
     }
 
     TypePolicy *typePolicy() {
         return this;
     }
     MDefinition *object() const {
         return getOperand(0);
     }
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const {
         return AliasSet::Load(AliasSet::ObjectFields);
     }
 };
 
 // A constant value for some object's array elements or typed array elements.
@@ -5319,17 +5319,17 @@ class MConstantElements : public MNullar
     }
 
     void printOpcode(FILE *fp) const;
 
     HashNumber valueHash() const {
         return (HashNumber)(size_t) value_;
     }
 
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         return ins->isConstantElements() && ins->toConstantElements()->value() == value();
     }
 
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 };
 
@@ -5350,17 +5350,17 @@ class MConvertElementsToDoubles
 
     static MConvertElementsToDoubles *New(TempAllocator &alloc, MDefinition *elements) {
         return new(alloc) MConvertElementsToDoubles(elements);
     }
 
     MDefinition *elements() const {
         return getOperand(0);
     }
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const {
         // This instruction can read and write to the elements' contents.
         // However, it is alright to hoist this from loops which explicitly
         // read or write to the elements: such reads and writes will use double
         // values and can be reordered freely wrt this conversion, except that
         // definite double loads must follow the conversion. The latter
@@ -5398,17 +5398,17 @@ class MMaybeToDoubleElement
     }
 
     MDefinition *elements() const {
         return getOperand(0);
     }
     MDefinition *value() const {
         return getOperand(1);
     }
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const {
         return AliasSet::Load(AliasSet::ObjectFields);
     }
 };
 
 // Load the initialized length from an elements header.
@@ -5427,17 +5427,17 @@ class MInitializedLength
 
     static MInitializedLength *New(TempAllocator &alloc, MDefinition *elements) {
         return new(alloc) MInitializedLength(elements);
     }
 
     MDefinition *elements() const {
         return getOperand(0);
     }
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const {
         return AliasSet::Load(AliasSet::ObjectFields);
     }
 
     void computeRange(TempAllocator &alloc);
 };
@@ -5486,17 +5486,17 @@ class MArrayLength
 
     static MArrayLength *New(TempAllocator &alloc, MDefinition *elements) {
         return new(alloc) MArrayLength(elements);
     }
 
     MDefinition *elements() const {
         return getOperand(0);
     }
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const {
         return AliasSet::Load(AliasSet::ObjectFields);
     }
 
     void computeRange(TempAllocator &alloc);
 };
@@ -5549,17 +5549,17 @@ class MTypedArrayLength
     }
 
     TypePolicy *typePolicy() {
         return this;
     }
     MDefinition *object() const {
         return getOperand(0);
     }
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const {
         // The typed array |length| property is immutable, so there is no
         // implicit dependency.
         return AliasSet::None();
     }
 
@@ -5586,17 +5586,17 @@ class MTypedArrayElements
     }
 
     TypePolicy *typePolicy() {
         return this;
     }
     MDefinition *object() const {
         return getOperand(0);
     }
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const {
         return AliasSet::Load(AliasSet::ObjectFields);
     }
 };
 
 // Checks whether a typed object is neutered.
@@ -5620,17 +5620,17 @@ class MNeuterCheck
     static MNeuterCheck *New(TempAllocator &alloc, MDefinition *object) {
         return new(alloc) MNeuterCheck(object);
     }
 
     MDefinition *object() const {
         return getOperand(0);
     }
 
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
 
     AliasSet getAliasSet() const {
         return AliasSet::Load(AliasSet::ObjectFields);
     }
 };
 
@@ -5657,17 +5657,17 @@ class MTypedObjectElements
     }
 
     TypePolicy *typePolicy() {
         return this;
     }
     MDefinition *object() const {
         return getOperand(0);
     }
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const {
         return AliasSet::Load(AliasSet::ObjectFields);
     }
 };
 
 // Inlined version of the js::SetTypedObjectOffset() intrinsic.
@@ -5812,20 +5812,20 @@ class MBoundsCheck
         minimum_ = n;
     }
     int32_t maximum() const {
         return maximum_;
     }
     void setMaximum(int32_t n) {
         maximum_ = n;
     }
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         if (!ins->isBoundsCheck())
             return false;
-        MBoundsCheck *other = ins->toBoundsCheck();
+        const MBoundsCheck *other = ins->toBoundsCheck();
         if (minimum() != other->minimum() || maximum() != other->maximum())
             return false;
         return congruentIfOperandsEqual(other);
     }
     virtual AliasSet getAliasSet() const {
         return AliasSet::None();
     }
     void computeRange(TempAllocator &alloc);
@@ -5918,20 +5918,20 @@ class MLoadElement
         return needsHoleCheck_;
     }
     bool loadDoubles() const {
         return loadDoubles_;
     }
     bool fallible() const {
         return needsHoleCheck();
     }
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         if (!ins->isLoadElement())
             return false;
-        MLoadElement *other = ins->toLoadElement();
+        const MLoadElement *other = ins->toLoadElement();
         if (needsHoleCheck() != other->needsHoleCheck())
             return false;
         if (loadDoubles() != other->loadDoubles())
             return false;
         return congruentIfOperandsEqual(other);
     }
     AliasSet getAliasSet() const {
         return AliasSet::Load(AliasSet::Element);
@@ -5981,20 +5981,20 @@ class MLoadElementHole
         return getOperand(2);
     }
     bool needsNegativeIntCheck() const {
         return needsNegativeIntCheck_;
     }
     bool needsHoleCheck() const {
         return needsHoleCheck_;
     }
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         if (!ins->isLoadElementHole())
             return false;
-        MLoadElementHole *other = ins->toLoadElementHole();
+        const MLoadElementHole *other = ins->toLoadElementHole();
         if (needsHoleCheck() != other->needsHoleCheck())
             return false;
         if (needsNegativeIntCheck() != other->needsNegativeIntCheck())
             return false;
         return congruentIfOperandsEqual(other);
     }
     AliasSet getAliasSet() const {
         return AliasSet::Load(AliasSet::Element);
@@ -6300,20 +6300,20 @@ class MLoadTypedArrayElement
     }
     MDefinition *index() const {
         return getOperand(1);
     }
     AliasSet getAliasSet() const {
         return AliasSet::Load(AliasSet::TypedArrayElement);
     }
 
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         if (!ins->isLoadTypedArrayElement())
             return false;
-        MLoadTypedArrayElement *other = ins->toLoadTypedArrayElement();
+        const MLoadTypedArrayElement *other = ins->toLoadTypedArrayElement();
         if (arrayType_ != other->arrayType_)
             return false;
         return congruentIfOperandsEqual(other);
     }
 
     void printOpcode(FILE *fp) const;
 
     void computeRange(TempAllocator &alloc);
@@ -6361,20 +6361,20 @@ class MLoadTypedArrayElementHole
         return this;
     }
     MDefinition *object() const {
         return getOperand(0);
     }
     MDefinition *index() const {
         return getOperand(1);
     }
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         if (!ins->isLoadTypedArrayElementHole())
             return false;
-        MLoadTypedArrayElementHole *other = ins->toLoadTypedArrayElementHole();
+        const MLoadTypedArrayElementHole *other = ins->toLoadTypedArrayElementHole();
         if (arrayType() != other->arrayType())
             return false;
         if (allowDouble() != other->allowDouble())
             return false;
         return congruentIfOperandsEqual(other);
     }
     AliasSet getAliasSet() const {
         return AliasSet::Load(AliasSet::TypedArrayElement);
@@ -6679,17 +6679,17 @@ class MClampToUint8
         return new(alloc) MClampToUint8(input);
     }
 
     MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers);
 
     TypePolicy *typePolicy() {
         return this;
     }
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
     void computeRange(TempAllocator &alloc);
 };
 
@@ -6719,29 +6719,29 @@ class MLoadFixedSlot
     }
 
     MDefinition *object() const {
         return getOperand(0);
     }
     size_t slot() const {
         return slot_;
     }
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         if (!ins->isLoadFixedSlot())
             return false;
         if (slot() != ins->toLoadFixedSlot()->slot())
             return false;
         return congruentIfOperandsEqual(ins);
     }
 
     AliasSet getAliasSet() const {
         return AliasSet::Load(AliasSet::FixedSlot);
     }
 
-    bool mightAlias(MDefinition *store);
+    bool mightAlias(const MDefinition *store) const;
 };
 
 class MStoreFixedSlot
   : public MBinaryInstruction,
     public MixPolicy<SingleObjectPolicy, NoFloatPolicy<1> >
 {
     bool needsBarrier_;
     size_t slot_;
@@ -6933,17 +6933,17 @@ class MGetPropertyCache
     bool monitoredResult() const {
         return monitoredResult_;
     }
     CacheLocationList &location() {
         return location_;
     }
     TypePolicy *typePolicy() { return this; }
 
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         if (!idempotent_)
             return false;
         if (!ins->isGetPropertyCache())
             return false;
         if (name() != ins->toGetPropertyCache()->name())
             return false;
         return congruentIfOperandsEqual(ins);
     }
@@ -6993,17 +6993,17 @@ class MGetPropertyPolymorphic
 
   public:
     INSTRUCTION_HEADER(GetPropertyPolymorphic)
 
     static MGetPropertyPolymorphic *New(TempAllocator &alloc, MDefinition *obj, PropertyName *name) {
         return new(alloc) MGetPropertyPolymorphic(alloc, obj, name);
     }
 
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         if (!ins->isGetPropertyPolymorphic())
             return false;
         if (name() != ins->toGetPropertyPolymorphic()->name())
             return false;
         return congruentIfOperandsEqual(ins);
     }
 
     TypePolicy *typePolicy() {
@@ -7026,17 +7026,17 @@ class MGetPropertyPolymorphic
     }
     MDefinition *obj() const {
         return getOperand(0);
     }
     AliasSet getAliasSet() const {
         return AliasSet::Load(AliasSet::ObjectFields | AliasSet::FixedSlot | AliasSet::DynamicSlot);
     }
 
-    bool mightAlias(MDefinition *store);
+    bool mightAlias(const MDefinition *store) const;
 };
 
 // Emit code to store a value to an object's slots if its shape matches
 // one of the shapes observed by the baseline IC, else bails out.
 class MSetPropertyPolymorphic
   : public MBinaryInstruction,
     public SingleObjectPolicy
 {
@@ -7357,17 +7357,17 @@ class MGuardShape
         return getOperand(0);
     }
     const Shape *shape() const {
         return shape_;
     }
     BailoutKind bailoutKind() const {
         return bailoutKind_;
     }
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         if (!ins->isGuardShape())
             return false;
         if (shape() != ins->toGuardShape()->shape())
             return false;
         if (bailoutKind() != ins->toGuardShape()->bailoutKind())
             return false;
         return congruentIfOperandsEqual(ins);
     }
@@ -7409,17 +7409,17 @@ class MGuardObjectType
         return getOperand(0);
     }
     const types::TypeObject *typeObject() const {
         return typeObject_;
     }
     bool bailOnEquality() const {
         return bailOnEquality_;
     }
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         if (!ins->isGuardObjectType())
             return false;
         if (typeObject() != ins->toGuardObjectType()->typeObject())
             return false;
         if (bailOnEquality() != ins->toGuardObjectType()->bailOnEquality())
             return false;
         return congruentIfOperandsEqual(ins);
     }
@@ -7461,17 +7461,17 @@ class MGuardObjectIdentity
         return getOperand(0);
     }
     JSObject *singleObject() const {
         return singleObject_;
     }
     bool bailOnEquality() const {
         return bailOnEquality_;
     }
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         if (!ins->isGuardObjectIdentity())
             return false;
         if (singleObject() != ins->toGuardObjectIdentity()->singleObject())
             return false;
         if (bailOnEquality() != ins->toGuardObjectIdentity()->bailOnEquality())
             return false;
         return congruentIfOperandsEqual(ins);
     }
@@ -7506,17 +7506,17 @@ class MGuardClass
         return this;
     }
     MDefinition *obj() const {
         return getOperand(0);
     }
     const Class *getClass() const {
         return class_;
     }
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         if (!ins->isGuardClass())
             return false;
         if (getClass() != ins->toGuardClass()->getClass())
             return false;
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const {
         return AliasSet::Load(AliasSet::ObjectFields);
@@ -7551,28 +7551,28 @@ class MLoadSlot
     }
     MDefinition *slots() const {
         return getOperand(0);
     }
     uint32_t slot() const {
         return slot_;
     }
 
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         if (!ins->isLoadSlot())
             return false;
         if (slot() != ins->toLoadSlot()->slot())
             return false;
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const {
         JS_ASSERT(slots()->type() == MIRType_Slots);
         return AliasSet::Load(AliasSet::DynamicSlot);
     }
-    bool mightAlias(MDefinition *store);
+    bool mightAlias(const MDefinition *store) const;
 };
 
 // Inline call to access a function's environment (scope chain).
 class MFunctionEnvironment
   : public MUnaryInstruction,
     public SingleObjectPolicy
 {
   public:
@@ -8292,17 +8292,17 @@ class MGetDOMProperty
     MDefinition *object() {
         return getOperand(0);
     }
 
     TypePolicy *typePolicy() {
         return this;
     }
 
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         if (!isDomMovable())
             return false;
 
         if (!ins->isGetDOMProperty())
             return false;
 
         // Checking the jitinfo is the same as checking the constant function
         if (!(info() == ins->toGetDOMProperty()->info()))
@@ -8369,17 +8369,17 @@ class MStringLength
 
     TypePolicy *typePolicy() {
         return this;
     }
 
     MDefinition *string() const {
         return getOperand(0);
     }
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const {
         // The string |length| property is immutable, so there is no
         // implicit dependency.
         return AliasSet::None();
     }
 
@@ -8646,20 +8646,20 @@ class MInArray
     }
     bool needsNegativeIntCheck() const {
         return needsNegativeIntCheck_;
     }
     void collectRangeInfoPreTrunc();
     AliasSet getAliasSet() const {
         return AliasSet::Load(AliasSet::Element);
     }
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         if (!ins->isInArray())
             return false;
-        MInArray *other = ins->toInArray();
+        const MInArray *other = ins->toInArray();
         if (needsHoleCheck() != other->needsHoleCheck())
             return false;
         if (needsNegativeIntCheck() != other->needsNegativeIntCheck())
             return false;
         return congruentIfOperandsEqual(other);
     }
     TypePolicy *typePolicy() {
         return this;
@@ -8730,17 +8730,17 @@ class MArgumentsLength : public MNullary
 
   public:
     INSTRUCTION_HEADER(ArgumentsLength)
 
     static MArgumentsLength *New(TempAllocator &alloc) {
         return new(alloc) MArgumentsLength();
     }
 
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const {
         // Arguments |length| cannot be mutated by Ion Code.
         return AliasSet::None();
    }
 
     void computeRange(TempAllocator &alloc);
@@ -8770,17 +8770,17 @@ class MGetFrameArgument
 
     MDefinition *index() const {
         return getOperand(0);
     }
 
     TypePolicy *typePolicy() {
         return this;
     }
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const {
         // If the script doesn't have any JSOP_SETARG ops, then this instruction is never
         // aliased.
         if (scriptHasSetArg_)
             return AliasSet::Load(AliasSet::FrameArgument);
         return AliasSet::None();
@@ -8811,17 +8811,17 @@ class MSetFrameArgument
     uint32_t argno() const {
         return argno_;
     }
 
     MDefinition *value() const {
         return getOperand(0);
     }
 
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         return false;
     }
     AliasSet getAliasSet() const {
         return AliasSet::Store(AliasSet::FrameArgument);
     }
     TypePolicy *typePolicy() {
         return this;
     }
@@ -8949,17 +8949,17 @@ class MGuardThreadExclusive
         return getOperand(0);
     }
     MDefinition *object() const {
         return getOperand(1);
     }
     BailoutKind bailoutKind() const {
         return Bailout_Normal;
     }
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
     bool possiblyCalls() const {
         return true;
     }
@@ -8980,17 +8980,17 @@ class MFilterTypeSet
 
   public:
     INSTRUCTION_HEADER(FilterTypeSet)
 
     static MFilterTypeSet *New(TempAllocator &alloc, MDefinition *def, types::TemporaryTypeSet *types) {
         return new(alloc) MFilterTypeSet(def, types);
     }
 
-    bool congruentTo(MDefinition *def) const {
+    bool congruentTo(const MDefinition *def) const {
         return false;
     }
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
     virtual bool neverHoist() const {
         return resultTypeSet()->empty();
     }
@@ -9023,17 +9023,17 @@ class MTypeBarrier
     }
 
     void printOpcode(FILE *fp) const;
 
     TypePolicy *typePolicy() {
         return this;
     }
 
-    bool congruentTo(MDefinition *def) const {
+    bool congruentTo(const MDefinition *def) const {
         return false;
     }
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
     virtual bool neverHoist() const {
         return resultTypeSet()->empty();
     }
@@ -9554,17 +9554,17 @@ class MHaveSameClass
 
     static MHaveSameClass *New(TempAllocator &alloc, MDefinition *left, MDefinition *right) {
         return new(alloc) MHaveSameClass(left, right);
     }
 
     TypePolicy *typePolicy() {
         return this;
     }
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 };
 
 class MHasClass
@@ -9684,21 +9684,21 @@ class MAsmJSLoadHeap : public MUnaryInst
     INSTRUCTION_HEADER(AsmJSLoadHeap);
 
     static MAsmJSLoadHeap *New(TempAllocator &alloc, ArrayBufferView::ViewType vt, MDefinition *ptr) {
         return new(alloc) MAsmJSLoadHeap(vt, ptr);
     }
 
     MDefinition *ptr() const { return getOperand(0); }
 
-    bool congruentTo(MDefinition *ins) const;
+    bool congruentTo(const MDefinition *ins) const;
     AliasSet getAliasSet() const {
         return AliasSet::Load(AliasSet::AsmJSHeap);
     }
-    bool mightAlias(MDefinition *def);
+    bool mightAlias(const MDefinition *def) const;
 };
 
 class MAsmJSStoreHeap : public MBinaryInstruction, public MAsmJSHeapAccess
 {
     MAsmJSStoreHeap(ArrayBufferView::ViewType vt, MDefinition *ptr, MDefinition *v)
       : MBinaryInstruction(ptr, v) , MAsmJSHeapAccess(vt, false)
     {}
 
@@ -9738,23 +9738,23 @@ class MAsmJSLoadGlobalVar : public MNull
     static MAsmJSLoadGlobalVar *New(TempAllocator &alloc, MIRType type, unsigned globalDataOffset,
                                     bool isConstant)
     {
         return new(alloc) MAsmJSLoadGlobalVar(type, globalDataOffset, isConstant);
     }
 
     unsigned globalDataOffset() const { return globalDataOffset_; }
 
-    bool congruentTo(MDefinition *ins) const;
+    bool congruentTo(const MDefinition *ins) const;
 
     AliasSet getAliasSet() const {
         return isConstant_ ? AliasSet::None() : AliasSet::Load(AliasSet::AsmJSGlobalVar);
     }
 
-    bool mightAlias(MDefinition *def);
+    bool mightAlias(const MDefinition *def) const;
 };
 
 class MAsmJSStoreGlobalVar : public MUnaryInstruction
 {
     MAsmJSStoreGlobalVar(unsigned globalDataOffset, MDefinition *v)
       : MUnaryInstruction(v), globalDataOffset_(globalDataOffset)
     {}
 
--- a/js/src/jit/shared/Assembler-x86-shared.h
+++ b/js/src/jit/shared/Assembler-x86-shared.h
@@ -1057,22 +1057,28 @@ class AssemblerX86Shared
             break;
           case Operand::MEM_REG_DISP:
             masm.andl_mr(src.disp(), src.base(), dest.code());
             break;
           default:
             MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
         }
     }
+    void imull(const Register &multiplier) {
+        masm.imull_r(multiplier.code());
+    }
     void imull(Imm32 imm, const Register &dest) {
         masm.imull_i32r(dest.code(), imm.value, dest.code());
     }
     void imull(const Register &src, const Register &dest) {
         masm.imull_rr(src.code(), dest.code());
     }
+    void imull(Imm32 imm, const Register &src, const Register &dest) {
+        masm.imull_i32r(src.code(), imm.value, dest.code());
+    }
     void imull(const Operand &src, const Register &dest) {
         switch (src.kind()) {
           case Operand::REG:
             masm.imull_rr(src.reg(), dest.code());
             break;
           case Operand::MEM_REG_DISP:
             masm.imull_mr(src.disp(), src.base(), dest.code());
             break;
--- a/js/src/jit/shared/CodeGenerator-shared.cpp
+++ b/js/src/jit/shared/CodeGenerator-shared.cpp
@@ -1002,16 +1002,84 @@ CodeGeneratorShared::addCacheLocations(c
         new (&runtimeData_[curIndex]) CacheLocation(iter->pc, iter->script);
         numLocations++;
     }
     JS_ASSERT(numLocations != 0);
     *numLocs = numLocations;
     return firstIndex;
 }
 
+ReciprocalMulConstants
+CodeGeneratorShared::computeDivisionConstants(int d) {
+    // In what follows, d is positive and is not a power of 2.
+    JS_ASSERT(d > 0 && (d & (d - 1)) != 0);
+
+    // Speeding up division by non power-of-2 constants is possible by
+    // calculating, during compilation, a value M such that high-order
+    // bits of M*n correspond to the result of the division. Formally,
+    // we compute values 0 <= M < 2^32 and 0 <= s < 31 such that
+    //         (M * n) >> (32 + s) = floor(n/d)    if n >= 0
+    //         (M * n) >> (32 + s) = ceil(n/d) - 1 if n < 0.
+    // The original presentation of this technique appears in Hacker's
+    // Delight, a book by Henry S. Warren, Jr.. A proof of correctness
+    // for our version follows.
+
+    // Define p = 32 + s, M = ceil(2^p/d), and assume that s satisfies
+    //                     M - 2^p/d <= 2^(s+1)/d.                 (1)
+    // (Observe that s = FloorLog32(d) satisfies this, because in this
+    // case d <= 2^(s+1) and so the RHS of (1) is at least one). Then,
+    //
+    // a) If s <= FloorLog32(d), then M <= 2^32 - 1.
+    // Proof: Indeed, M is monotone in s and, for s = FloorLog32(d),
+    // the inequalities 2^31 > d >= 2^s + 1 readily imply
+    //    2^p / d  = 2^p/(d - 1) * (d - 1)/d
+    //            <= 2^32 * (1 - 1/d) < 2 * (2^31 - 1) = 2^32 - 2.
+    // The claim follows by applying the ceiling function.
+    //
+    // b) For any 0 <= n < 2^31, floor(Mn/2^p) = floor(n/d).
+    // Proof: Put x = floor(Mn/2^p); it's the unique integer for which
+    //                    Mn/2^p - 1 < x <= Mn/2^p.                (2)
+    // Using M >= 2^p/d on the LHS and (1) on the RHS, we get
+    //           n/d - 1 < x <= n/d + n/(2^31 d) < n/d + 1/d.
+    // Since x is an integer, it's not in the interval (n/d, (n+1)/d),
+    // and so n/d - 1 < x <= n/d, which implies x = floor(n/d).
+    //
+    // c) For any -2^31 <= n < 0, floor(Mn/2^p) + 1 = ceil(n/d).
+    // Proof: The proof is similar. Equation (2) holds as above. Using
+    // M > 2^p/d (d isn't a power of 2) on the RHS and (1) on the LHS,
+    //                 n/d + n/(2^31 d) - 1 < x < n/d.
+    // Using n >= -2^31 and summing 1,
+    //                  n/d - 1/d < x + 1 < n/d + 1.
+    // Since x + 1 is an integer, this implies n/d <= x + 1 < n/d + 1.
+    // In other words, x + 1 = ceil(n/d).
+    //
+    // Condition (1) isn't necessary for the existence of M and s with
+    // the properties above. Hacker's Delight provides a slightly less
+    // restrictive condition when d >= 196611, at the cost of a 3-page
+    // proof of correctness.
+
+    // Note that, since d*M - 2^p = d - (2^p)%d, (1) can be written as
+    //                   2^(s+1) >= d - (2^p)%d.
+    // We now compute the least s with this property...
+
+    int32_t shift = 0;
+    while ((int64_t(1) << (shift+1)) + (int64_t(1) << (shift+32)) % d < d)
+        shift++;
+
+    // ...and the corresponding M. This may not fit in a signed 32-bit
+    // integer; we will compute (M - 2^32) * n + (2^32 * n) instead of
+    // M * n if this is the case (cf. item (a) above).
+    ReciprocalMulConstants rmc;
+    rmc.multiplier = int32_t((int64_t(1) << (shift+32))/d + 1);
+    rmc.shift_amount = shift;
+
+    return rmc;
+}
+
+
 #ifdef JS_TRACE_LOGGING
 
 bool
 CodeGeneratorShared::emitTracelogScript(bool isStart)
 {
     RegisterSet regs = RegisterSet::Volatile();
     Register logger = regs.takeGeneral();
     Register script = regs.takeGeneral();
--- a/js/src/jit/shared/CodeGenerator-shared.h
+++ b/js/src/jit/shared/CodeGenerator-shared.h
@@ -40,16 +40,21 @@ struct PatchableBackedgeInfo
     Label *loopHeader;
     Label *interruptCheck;
 
     PatchableBackedgeInfo(CodeOffsetJump backedge, Label *loopHeader, Label *interruptCheck)
       : backedge(backedge), loopHeader(loopHeader), interruptCheck(interruptCheck)
     {}
 };
 
+struct ReciprocalMulConstants {
+    int32_t multiplier;
+    int32_t shift_amount;
+};
+
 class CodeGeneratorShared : public LInstructionVisitor
 {
     js::Vector<OutOfLineCode *, 0, SystemAllocPolicy> outOfLineCode_;
     OutOfLineCode *oolIns;
 
     MacroAssembler &ensureMasm(MacroAssembler *masm);
     mozilla::Maybe<MacroAssembler> maybeMasm_;
 
@@ -397,16 +402,17 @@ class CodeGeneratorShared : public LInst
     inline OutOfLineCode *oolCallVM(const VMFunctionsModal &f, LInstruction *ins,
                                     const ArgSeq &args, const StoreOutputTo &out)
     {
         return oolCallVM(f[gen->info().executionMode()], ins, args, out);
     }
 
     bool addCache(LInstruction *lir, size_t cacheIndex);
     size_t addCacheLocations(const CacheLocationList &locs, size_t *numLocs);
+    ReciprocalMulConstants computeDivisionConstants(int d);
 
   protected:
     bool addOutOfLineCode(OutOfLineCode *code);
     bool hasOutOfLineCode() { return !outOfLineCode_.empty(); }
     bool generateOutOfLineCode();
 
     Label *labelForBackedgeWithImplicitCheck(MBasicBlock *mir);
 
--- a/js/src/jit/shared/CodeGenerator-x86-shared.cpp
+++ b/js/src/jit/shared/CodeGenerator-x86-shared.cpp
@@ -17,16 +17,17 @@
 #include "jit/RangeAnalysis.h"
 #include "vm/TraceLogging.h"
 
 #include "jit/shared/CodeGenerator-shared-inl.h"
 
 using namespace js;
 using namespace js::jit;
 
+using mozilla::Abs;
 using mozilla::FloatingPoint;
 using mozilla::FloorLog2;
 using mozilla::NegativeInfinity;
 using mozilla::SpecificNaN;
 
 namespace js {
 namespace jit {
 
@@ -864,49 +865,142 @@ CodeGeneratorX86Shared::visitMulNegative
     return true;
 }
 
 bool
 CodeGeneratorX86Shared::visitDivPowTwoI(LDivPowTwoI *ins)
 {
     Register lhs = ToRegister(ins->numerator());
     mozilla::DebugOnly<Register> output = ToRegister(ins->output());
+
     int32_t shift = ins->shift();
+    bool negativeDivisor = ins->negativeDivisor();
+    MDiv *mir = ins->mir();
 
     // We use defineReuseInput so these should always be the same, which is
     // convenient since all of our instructions here are two-address.
     JS_ASSERT(lhs == output);
 
+    if (!mir->isTruncated() && negativeDivisor) {
+        // 0 divided by a negative number must return a double.
+        masm.testl(lhs, lhs);
+        if (!bailoutIf(Assembler::Zero, ins->snapshot()))
+            return false;
+    }
+
     if (shift != 0) {
-        MDiv *mir = ins->mir();
         if (!mir->isTruncated()) {
             // If the remainder is != 0, bailout since this must be a double.
             masm.testl(lhs, Imm32(UINT32_MAX >> (32 - shift)));
             if (!bailoutIf(Assembler::NonZero, ins->snapshot()))
                 return false;
         }
 
-        if (!mir->canBeNegativeDividend()) {
-            // Numerator is unsigned, so needs no adjusting. Do the shift.
-            masm.sarl(Imm32(shift), lhs);
-            return true;
-        }
-
         // Adjust the value so that shifting produces a correctly rounded result
         // when the numerator is negative. See 10-1 "Signed Division by a Known
         // Power of 2" in Henry S. Warren, Jr.'s Hacker's Delight.
-        Register lhsCopy = ToRegister(ins->numeratorCopy());
-        JS_ASSERT(lhsCopy != lhs);
-        if (shift > 1)
-            masm.sarl(Imm32(31), lhs);
-        masm.shrl(Imm32(32 - shift), lhs);
-        masm.addl(lhsCopy, lhs);
+        if (mir->canBeNegativeDividend()) {
+            Register lhsCopy = ToRegister(ins->numeratorCopy());
+            JS_ASSERT(lhsCopy != lhs);
+            if (shift > 1)
+                masm.sarl(Imm32(31), lhs);
+            masm.shrl(Imm32(32 - shift), lhs);
+            masm.addl(lhsCopy, lhs);
+        }
+
+        masm.sarl(Imm32(shift), lhs);
+        if (negativeDivisor)
+            masm.negl(lhs);
+    } else if (shift == 0 && negativeDivisor) {
+        // INT32_MIN / -1 overflows.
+        masm.negl(lhs);
+        if (!mir->isTruncated() && !bailoutIf(Assembler::Overflow, ins->snapshot()))
+            return false;
+    }
+
+    return true;
+}
+
+bool
+CodeGeneratorX86Shared::visitDivOrModConstantI(LDivOrModConstantI *ins) {
+    Register lhs = ToRegister(ins->numerator());
+    Register output = ToRegister(ins->output());
+    int32_t d = ins->denominator();
+
+    // This emits the division answer into edx or the modulus answer into eax.
+    JS_ASSERT(output == eax || output == edx);
+    JS_ASSERT(lhs != eax && lhs != edx);
+
+    // The absolute value of the denominator isn't a power of 2 (see LDivPowTwoI
+    // and LModPowTwoI).
+    JS_ASSERT((Abs(d) & (Abs(d) - 1)) != 0);
+
+    // We will first divide by Abs(d), and negate the answer if d is negative.
+    // If desired, this can be avoided by generalizing computeDivisionConstants.
+    ReciprocalMulConstants rmc = computeDivisionConstants(Abs(d));
 
-        // Do the shift.
-        masm.sarl(Imm32(shift), lhs);
+    // As explained in the comments of computeDivisionConstants, we first compute
+    // X >> (32 + shift), where X is either (rmc.multiplier * n) if the multiplier
+    // is non-negative or (rmc.multiplier * n) + (2^32 * n) otherwise. This is the
+    // desired division result if n is non-negative, and is one less than the result
+    // otherwise.
+    masm.movl(lhs, eax);
+    masm.movl(Imm32(rmc.multiplier), edx);
+    masm.imull(edx);
+    if (rmc.multiplier < 0)
+        masm.addl(lhs, edx);
+    masm.sarl(Imm32(rmc.shift_amount), edx);
+
+    // We'll subtract -1 instead of adding 1, because (n < 0 ? -1 : 0) can be
+    // computed with just a sign-extending shift of 31 bits.
+    if (ins->canBeNegativeDividend()) {
+        masm.movl(lhs, eax);
+        masm.sarl(Imm32(31), eax);
+        masm.subl(eax, edx);
+    }
+
+    // After this, edx contains the correct division result.
+    if (d < 0)
+        masm.negl(edx);
+
+    if (output == eax) {
+        masm.imull(Imm32(-d), edx, eax);
+        masm.addl(lhs, eax);
+    }
+
+    if (!ins->mir()->isTruncated()) {
+        if (output == edx) {
+            // This is a division op. Multiply the obtained value by d to check if
+            // the correct answer is an integer. This cannot overflow, since |d| > 1.
+            masm.imull(Imm32(d), edx, eax);
+            masm.cmpl(lhs, eax);
+            if (!bailoutIf(Assembler::NotEqual, ins->snapshot()))
+                return false;
+
+            // If lhs is zero and the divisor is negative, the answer should have
+            // been -0.
+            if (d < 0) {
+                masm.testl(lhs, lhs);
+                if (!bailoutIf(Assembler::Zero, ins->snapshot()))
+                    return false;
+            }
+        } else if (ins->canBeNegativeDividend()) {
+            // This is a mod op. If the computed value is zero and lhs
+            // is negative, the answer should have been -0.
+            Label done;
+
+            masm.cmpl(lhs, Imm32(0));
+            masm.j(Assembler::GreaterThanOrEqual, &done);
+
+            masm.testl(eax, eax);
+            if (!bailoutIf(Assembler::Zero, ins->snapshot()))
+                return false;
+
+            masm.bind(&done);
+        }
     }
 
     return true;
 }
 
 bool
 CodeGeneratorX86Shared::visitDivI(LDivI *ins)
 {
@@ -1007,29 +1101,37 @@ CodeGeneratorX86Shared::visitModPowTwoI(
     Label negative;
 
     if (ins->mir()->canBeNegativeDividend()) {
         // Switch based on sign of the lhs.
         // Positive numbers are just a bitmask
         masm.branchTest32(Assembler::Signed, lhs, lhs, &negative);
     }
 
-    masm.andl(Imm32((1 << shift) - 1), lhs);
+    masm.andl(Imm32((uint32_t(1) << shift) - 1), lhs);
 
     if (ins->mir()->canBeNegativeDividend()) {
         Label done;
         masm.jump(&done);
 
         // Negative numbers need a negate, bitmask, negate
         masm.bind(&negative);
-        // visitModI has an overflow check here to catch INT_MIN % -1, but
-        // here the rhs is a power of 2, and cannot be -1, so the check is not generated.
+
+        // Unlike in the visitModI case, we are not computing the mod by means of a
+        // division. Therefore, the divisor = -1 case isn't problematic (the andl
+        // always returns 0, which is what we expect).
+        //
+        // The negl instruction overflows if lhs == INT32_MIN, but this is also not
+        // a problem: shift is at most 31, and so the andl also always returns 0.
         masm.negl(lhs);
-        masm.andl(Imm32((1 << shift) - 1), lhs);
+        masm.andl(Imm32((uint32_t(1) << shift) - 1), lhs);
         masm.negl(lhs);
+
+        // Since a%b has the same sign as b, and a is negative in this branch,
+        // an answer of 0 means the correct result is actually -0. Bail out.
         if (!ins->mir()->isTruncated() && !bailoutIf(Assembler::Zero, ins->snapshot()))
             return false;
         masm.bind(&done);
     }
     return true;
 
 }
 
--- a/js/src/jit/shared/CodeGenerator-x86-shared.h
+++ b/js/src/jit/shared/CodeGenerator-x86-shared.h
@@ -119,16 +119,17 @@ class CodeGeneratorX86Shared : public Co
     virtual bool visitSqrtD(LSqrtD *ins);
     virtual bool visitSqrtF(LSqrtF *ins);
     virtual bool visitPowHalfD(LPowHalfD *ins);
     virtual bool visitAddI(LAddI *ins);
     virtual bool visitSubI(LSubI *ins);
     virtual bool visitMulI(LMulI *ins);
     virtual bool visitDivI(LDivI *ins);
     virtual bool visitDivPowTwoI(LDivPowTwoI *ins);
+    virtual bool visitDivOrModConstantI(LDivOrModConstantI *ins);
     virtual bool visitModI(LModI *ins);
     virtual bool visitModPowTwoI(LModPowTwoI *ins);
     virtual bool visitBitNotI(LBitNotI *ins);
     virtual bool visitBitOpI(LBitOpI *ins);
     virtual bool visitShiftI(LShiftI *ins);
     virtual bool visitUrshD(LUrshD *ins);
     virtual bool visitTestIAndBranch(LTestIAndBranch *test);
     virtual bool visitTestDAndBranch(LTestDAndBranch *test);
--- a/js/src/jit/shared/LIR-x86-shared.h
+++ b/js/src/jit/shared/LIR-x86-shared.h
@@ -42,41 +42,76 @@ class LDivI : public LBinaryMath<1>
         return mir_->toDiv();
     }
 };
 
 // Signed division by a power-of-two constant.
 class LDivPowTwoI : public LBinaryMath<0>
 {
     const int32_t shift_;
+    const bool negativeDivisor_;
 
   public:
     LIR_HEADER(DivPowTwoI)
 
-    LDivPowTwoI(const LAllocation &lhs, const LAllocation &lhsCopy, int32_t shift)
-      : shift_(shift)
+    LDivPowTwoI(const LAllocation &lhs, const LAllocation &lhsCopy, int32_t shift, bool negativeDivisor)
+      : shift_(shift), negativeDivisor_(negativeDivisor)
     {
         setOperand(0, lhs);
         setOperand(1, lhsCopy);
     }
 
     const LAllocation *numerator() {
         return getOperand(0);
     }
     const LAllocation *numeratorCopy() {
         return getOperand(1);
     }
     int32_t shift() const {
         return shift_;
     }
+    bool negativeDivisor() const {
+        return negativeDivisor_;
+    }
     MDiv *mir() const {
         return mir_->toDiv();
     }
 };
 
+class LDivOrModConstantI : public LInstructionHelper<1, 1, 1>
+{
+    const int32_t denominator_;
+
+  public:
+    LIR_HEADER(DivOrModConstantI)
+
+    LDivOrModConstantI(const LAllocation &lhs, int32_t denominator, const LDefinition& temp)
+    : denominator_(denominator)
+    {
+        setOperand(0, lhs);
+        setTemp(0, temp);
+    }
+
+    const LAllocation *numerator() {
+        return getOperand(0);
+    }
+    int32_t denominator() const {
+        return denominator_;
+    }
+    MBinaryArithInstruction *mir() const {
+        JS_ASSERT(mir_->isDiv() || mir_->isMod());
+        return static_cast<MBinaryArithInstruction *>(mir_);
+    }
+    bool canBeNegativeDividend() const {
+        if (mir_->isMod())
+            return mir_->toMod()->canBeNegativeDividend();
+        return mir_->toDiv()->canBeNegativeDividend();
+    }
+};
+
 class LModI : public LBinaryMath<1>
 {
   public:
     LIR_HEADER(ModI)
 
     LModI(const LAllocation &lhs, const LAllocation &rhs, const LDefinition &temp) {
         setOperand(0, lhs);
         setOperand(1, rhs);
--- a/js/src/jit/shared/Lowering-x86-shared.cpp
+++ b/js/src/jit/shared/Lowering-x86-shared.cpp
@@ -10,16 +10,17 @@
 
 #include "jit/MIR.h"
 
 #include "jit/shared/Lowering-shared-inl.h"
 
 using namespace js;
 using namespace js::jit;
 
+using mozilla::Abs;
 using mozilla::FloorLog2;
 
 LTableSwitch *
 LIRGeneratorX86Shared::newLTableSwitch(const LAllocation &in, const LDefinition &inputCopy,
                                        MTableSwitch *tableswitch)
 {
     return new(alloc()) LTableSwitch(in, inputCopy, temp(), tableswitch);
 }
@@ -132,36 +133,39 @@ LIRGeneratorX86Shared::lowerDivI(MDiv *d
     if (div->isUnsigned())
         return lowerUDiv(div);
 
     // Division instructions are slow. Division by constant denominators can be
     // rewritten to use other instructions.
     if (div->rhs()->isConstant()) {
         int32_t rhs = div->rhs()->toConstant()->value().toInt32();
 
-        // Check for division by a positive power of two, which is an easy and
-        // important case to optimize. Note that other optimizations are also
-        // possible; division by negative powers of two can be optimized in a
-        // similar manner as positive powers of two, and division by other
-        // constants can be optimized by a reciprocal multiplication technique.
-        int32_t shift = FloorLog2(rhs);
-        if (rhs > 0 && 1 << shift == rhs) {
+        // Division by powers of two can be done by shifting, and division by
+        // other numbers can be done by a reciprocal multiplication technique.
+        int32_t shift = FloorLog2(Abs(rhs));
+        if (rhs != 0 && uint32_t(1) << shift == Abs(rhs)) {
             LAllocation lhs = useRegisterAtStart(div->lhs());
             LDivPowTwoI *lir;
             if (!div->canBeNegativeDividend()) {
                 // Numerator is unsigned, so does not need adjusting.
-                lir = new(alloc()) LDivPowTwoI(lhs, lhs, shift);
+                lir = new(alloc()) LDivPowTwoI(lhs, lhs, shift, rhs < 0);
             } else {
                 // Numerator is signed, and needs adjusting, and an extra
                 // lhs copy register is needed.
-                lir = new(alloc()) LDivPowTwoI(lhs, useRegister(div->lhs()), shift);
+                lir = new(alloc()) LDivPowTwoI(lhs, useRegister(div->lhs()), shift, rhs < 0);
             }
             if (div->fallible() && !assignSnapshot(lir, Bailout_BaselineInfo))
                 return false;
             return defineReuseInput(lir, div, 0);
+        } else if (rhs != 0) {
+            LDivOrModConstantI *lir;
+            lir = new(alloc()) LDivOrModConstantI(useRegister(div->lhs()), rhs, tempFixed(eax));
+            if (div->fallible() && !assignSnapshot(lir, Bailout_BaselineInfo))
+                return false;
+            return defineFixed(lir, div, LAllocation(AnyRegister(edx)));
         }
     }
 
     LDivI *lir = new(alloc()) LDivI(useRegister(div->lhs()), useRegister(div->rhs()),
                                     tempFixed(edx));
     if (div->fallible() && !assignSnapshot(lir, Bailout_BaselineInfo))
         return false;
     return defineFixed(lir, div, LAllocation(AnyRegister(eax)));
@@ -170,22 +174,28 @@ LIRGeneratorX86Shared::lowerDivI(MDiv *d
 bool
 LIRGeneratorX86Shared::lowerModI(MMod *mod)
 {
     if (mod->isUnsigned())
         return lowerUMod(mod);
 
     if (mod->rhs()->isConstant()) {
         int32_t rhs = mod->rhs()->toConstant()->value().toInt32();
-        int32_t shift = FloorLog2(rhs);
-        if (rhs > 0 && 1 << shift == rhs) {
+        int32_t shift = FloorLog2(Abs(rhs));
+        if (rhs != 0 && uint32_t(1) << shift == Abs(rhs)) {
             LModPowTwoI *lir = new(alloc()) LModPowTwoI(useRegisterAtStart(mod->lhs()), shift);
             if (mod->fallible() && !assignSnapshot(lir, Bailout_BaselineInfo))
                 return false;
             return defineReuseInput(lir, mod, 0);
+        } else if (rhs != 0) {
+            LDivOrModConstantI *lir;
+            lir = new(alloc()) LDivOrModConstantI(useRegister(mod->lhs()), rhs, tempFixed(edx));
+            if (mod->fallible() && !assignSnapshot(lir, Bailout_BaselineInfo))
+                return false;
+            return defineFixed(lir, mod, LAllocation(AnyRegister(eax)));
         }
     }
 
     LModI *lir = new(alloc()) LModI(useRegister(mod->lhs()),
                                     useRegister(mod->rhs()),
                                     tempFixed(eax));
     if (mod->fallible() && !assignSnapshot(lir, Bailout_BaselineInfo))
         return false;
--- a/js/src/jit/x64/LOpcodes-x64.h
+++ b/js/src/jit/x64/LOpcodes-x64.h
@@ -8,16 +8,17 @@
 #define jit_x64_LOpcodes_x64_h
 
 #define LIR_CPU_OPCODE_LIST(_)      \
     _(Box)                          \
     _(Unbox)                        \
     _(UnboxFloatingPoint)           \
     _(DivI)                         \
     _(DivPowTwoI)                   \
+    _(DivOrModConstantI)            \
     _(ModI)                         \
     _(ModPowTwoI)                   \
     _(PowHalfD)                     \
     _(AsmJSUInt32ToDouble)          \
     _(AsmJSUInt32ToFloat32)         \
     _(AsmJSLoadFuncPtr)             \
     _(UDivOrMod)
 
--- a/js/src/jit/x86/LOpcodes-x86.h
+++ b/js/src/jit/x86/LOpcodes-x86.h
@@ -9,16 +9,17 @@
 
 #define LIR_CPU_OPCODE_LIST(_)  \
     _(Unbox)                    \
     _(UnboxFloatingPoint)       \
     _(Box)                      \
     _(BoxFloatingPoint)         \
     _(DivI)                     \
     _(DivPowTwoI)               \
+    _(DivOrModConstantI)        \
     _(ModI)                     \
     _(ModPowTwoI)               \
     _(PowHalfD)                 \
     _(AsmJSUInt32ToDouble)      \
     _(AsmJSUInt32ToFloat32)     \
     _(AsmJSLoadFuncPtr)         \
     _(UDivOrMod)
 
--- a/js/src/jsfun.h
+++ b/js/src/jsfun.h
@@ -263,40 +263,46 @@ class JSFunction : public JSObject
     // source, or nullptr if the function is a clone of a self hosted function.
     //
     // There are several methods to get the script of an interpreted function:
     //
     // - For all interpreted functions, getOrCreateScript() will get the
     //   JSScript, delazifying the function if necessary. This is the safest to
     //   use, but has extra checks, requires a cx and may trigger a GC.
     //
-    // - For functions which may have a LazyScript but whose JSScript is known
-    //   to exist, existingScript() will get the script and delazify the
-    //   function if necessary.
+    // - For inlined functions which may have a LazyScript but whose JSScript
+    //   is known to exist, existingScriptForInlinedFunction() will get the
+    //   script and delazify the function if necessary.
     //
     // - For functions known to have a JSScript, nonLazyScript() will get it.
 
     JSScript *getOrCreateScript(JSContext *cx) {
         JS_ASSERT(isInterpreted());
         JS_ASSERT(cx);
         if (isInterpretedLazy()) {
             JS::RootedFunction self(cx, this);
             if (!createScriptForLazilyInterpretedFunction(cx, self))
                 return nullptr;
             return self->nonLazyScript();
         }
         return nonLazyScript();
     }
 
-    JSScript *existingScript() {
-        JS_ASSERT(isInterpreted());
+    JSScript *existingScriptForInlinedFunction() {
+        MOZ_ASSERT(isInterpreted());
         if (isInterpretedLazy()) {
+            // Get the script from the canonical function. Ion used the
+            // canonical function to inline the script and because it has
+            // Baseline code it has not been relazified. Note that we can't
+            // use lazyScript->script_ here as it may be null in some cases,
+            // see bug 976536.
             js::LazyScript *lazy = lazyScript();
-            JSScript *script = lazy->maybeScript();
-            JS_ASSERT(script);
+            JSFunction *fun = lazy->functionNonDelazifying();
+            MOZ_ASSERT(fun);
+            JSScript *script = fun->nonLazyScript();
 
             if (shadowZone()->needsBarrier())
                 js::LazyScript::writeBarrierPre(lazy);
 
             flags_ &= ~INTERPRETED_LAZY;
             flags_ |= INTERPRETED;
             initScript(script);
         }
--- a/js/xpconnect/idl/xpccomponents.idl
+++ b/js/xpconnect/idl/xpccomponents.idl
@@ -116,17 +116,17 @@ interface nsIXPCComponents_utils_Sandbox
 interface ScheduledGCCallback : nsISupports
 {
     void callback();
 };
 
 /**
 * interface of Components.utils
 */
-[scriptable, uuid(5e253a02-f91f-4fb3-9335-db0fca23f2e0)]
+[scriptable, uuid(45b80e00-fb0d-439e-b7bf-54f24af0c4a6)]
 interface nsIXPCComponents_Utils : nsISupports
 {
 
     /* reportError is designed to be called from JavaScript only.
      *
      * It will report a JS Error object to the JS console, and return. It
      * is meant for use in exception handler blocks which want to "eat"
      * an exception, but still want to report it to the console.
@@ -563,16 +563,23 @@ interface nsIXPCComponents_Utils : nsISu
      *
      * Hence the notion of the "WebIDL Caller". If the current Entry Script on
      * the Script Settings Stack represents the invocation of JS-implemented
      * WebIDL, this API returns the principal of the caller at the time
      * of invocation. Otherwise (i.e. outside of JS-implemented WebIDL), this
      * function throws. If it throws, you probably shouldn't be using it.
      */
     nsIPrincipal getWebIDLCallerPrincipal();
+
+    /*
+     * Gets the principal of a script object, after unwrapping any cross-
+     * compartment wrappers.
+     */
+    [implicit_jscontext]
+    nsIPrincipal getObjectPrincipal(in jsval obj);
 };
 
 /**
 * Interface for the 'Components' object.
 *
 * The first interface contains things that are available to non-chrome XBL code
 * that runs in a scope with an nsExpandedPrincipal. The second interface
 * includes members that are only exposed to chrome.
--- a/js/xpconnect/src/XPCComponents.cpp
+++ b/js/xpconnect/src/XPCComponents.cpp
@@ -3252,33 +3252,33 @@ nsXPCComponents_Utils::NukeSandbox(Handl
 NS_IMETHODIMP
 nsXPCComponents_Utils::BlockScriptForGlobal(HandleValue globalArg,
                                             JSContext *cx)
 {
     NS_ENSURE_TRUE(globalArg.isObject(), NS_ERROR_INVALID_ARG);
     RootedObject global(cx, UncheckedUnwrap(&globalArg.toObject(),
                                             /* stopAtOuter = */ false));
     NS_ENSURE_TRUE(JS_IsGlobalObject(global), NS_ERROR_INVALID_ARG);
-    if (nsContentUtils::IsSystemPrincipal(GetObjectPrincipal(global))) {
+    if (nsContentUtils::IsSystemPrincipal(xpc::GetObjectPrincipal(global))) {
         JS_ReportError(cx, "Script may not be disabled for system globals");
         return NS_ERROR_FAILURE;
     }
     Scriptability::Get(global).Block();
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsXPCComponents_Utils::UnblockScriptForGlobal(HandleValue globalArg,
                                               JSContext *cx)
 {
     NS_ENSURE_TRUE(globalArg.isObject(), NS_ERROR_INVALID_ARG);
     RootedObject global(cx, UncheckedUnwrap(&globalArg.toObject(),
                                             /* stopAtOuter = */ false));
     NS_ENSURE_TRUE(JS_IsGlobalObject(global), NS_ERROR_INVALID_ARG);
-    if (nsContentUtils::IsSystemPrincipal(GetObjectPrincipal(global))) {
+    if (nsContentUtils::IsSystemPrincipal(xpc::GetObjectPrincipal(global))) {
         JS_ReportError(cx, "Script may not be disabled for system globals");
         return NS_ERROR_FAILURE;
     }
     Scriptability::Get(global).Unblock();
     return NS_OK;
 }
 
 NS_IMETHODIMP
@@ -3611,16 +3611,31 @@ nsXPCComponents_Utils::GetWebIDLCallerPr
     // and we throw.
     nsCOMPtr<nsIPrincipal> callerPrin = mozilla::dom::GetWebIDLCallerPrincipal();
     if (!callerPrin)
         return NS_ERROR_NOT_AVAILABLE;
     callerPrin.forget(aResult);
     return NS_OK;
 }
 
+NS_IMETHODIMP
+nsXPCComponents_Utils::GetObjectPrincipal(HandleValue val, JSContext *cx,
+                                          nsIPrincipal **result)
+{
+    if (!val.isObject())
+        return NS_ERROR_INVALID_ARG;
+    RootedObject obj(cx, &val.toObject());
+    obj = js::CheckedUnwrap(obj);
+    MOZ_ASSERT(obj);
+
+    nsCOMPtr<nsIPrincipal> prin = nsContentUtils::GetObjectPrincipal(obj);
+    prin.forget(result);
+    return NS_OK;
+}
+
 /***************************************************************************/
 /***************************************************************************/
 /***************************************************************************/
 
 
 nsXPCComponentsBase::nsXPCComponentsBase(XPCWrappedNativeScope* aScope)
     :   mScope(aScope)
 {
--- a/js/xpconnect/tests/unit/test_getObjectPrincipal.js
+++ b/js/xpconnect/tests/unit/test_getObjectPrincipal.js
@@ -1,6 +1,11 @@
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+const Cu = Components.utils;
+
 function run_test() {
-  var secMan = Components.classes["@mozilla.org/scriptsecuritymanager;1"].getService(
-    Components.interfaces.nsIScriptSecurityManager);
-
-  do_check_true(secMan.isSystemPrincipal(secMan.getObjectPrincipal({})));
+  var secMan = Cc["@mozilla.org/scriptsecuritymanager;1"].getService(Ci.nsIScriptSecurityManager);
+  do_check_true(secMan.isSystemPrincipal(Cu.getObjectPrincipal({})));
+  var sb = new Cu.Sandbox('http://www.example.com');
+  Cu.evalInSandbox('var obj = { foo: 42 };', sb);
+  do_check_eq(Cu.getObjectPrincipal(sb.obj).origin, 'http://www.example.com');
 }
--- a/layout/base/nsCSSRendering.cpp
+++ b/layout/base/nsCSSRendering.cpp
@@ -56,16 +56,29 @@
 using namespace mozilla;
 using namespace mozilla::css;
 using namespace mozilla::gfx;
 using mozilla::image::ImageOps;
 using mozilla::CSSSizeOrRatio;
 
 static int gFrameTreeLockCount = 0;
 
+static void
+ApplySkipSides(int aSkipSides, nsMargin* aMargin)
+{
+  if (aSkipSides & SIDE_BIT_LEFT)
+    aMargin->left = 0;
+  if (aSkipSides & SIDE_BIT_TOP)
+    aMargin->top = 0;
+  if (aSkipSides & SIDE_BIT_RIGHT)
+    aMargin->right = 0;
+  if (aSkipSides & SIDE_BIT_BOTTOM)
+    aMargin->bottom = 0;
+}
+
 // To avoid storing this data on nsInlineFrame (bloat) and to avoid
 // recalculating this for each frame in a continuation (perf), hold
 // a cache of various coordinate information that we need in order
 // to paint inline backgrounds.
 struct InlineBackgroundData
 {
   InlineBackgroundData()
       : mFrame(nullptr), mBlockFrame(nullptr)
@@ -76,39 +89,44 @@ struct InlineBackgroundData
   {
   }
 
   void Reset()
   {
     mBoundingBox.SetRect(0,0,0,0);
     mContinuationPoint = mLineContinuationPoint = mUnbrokenWidth = 0;
     mFrame = mBlockFrame = nullptr;
+    mLeftBorderData.Reset();
   }
 
+  /**
+   * Return a continuous rect for (an inline) aFrame relative to the
+   * continuation that draws the left-most part of the background.
+   * This is used when painting backgrounds.
+   */
   nsRect GetContinuousRect(nsIFrame* aFrame)
   {
+    MOZ_ASSERT(aFrame->GetType() == nsGkAtoms::inlineFrame);
+
     SetFrame(aFrame);
 
     nscoord x;
     if (mBidiEnabled) {
       x = mLineContinuationPoint;
 
       // Scan continuations on the same line as aFrame and accumulate the widths
       // of frames that are to the left (if this is an LTR block) or right
       // (if it's RTL) of the current one.
       bool isRtlBlock = (mBlockFrame->StyleVisibility()->mDirection ==
                            NS_STYLE_DIRECTION_RTL);
       nscoord curOffset = aFrame->GetOffsetTo(mBlockFrame).x;
 
-      // No need to use our GetPrevContinuation/GetNextContinuation methods
-      // here, since ib-split siblings are certainly not on the same line.
-
-      nsIFrame* inlineFrame = aFrame->GetPrevContinuation();
       // If the continuation is fluid we know inlineFrame is not on the same line.
       // If it's not fluid, we need to test further to be sure.
+      nsIFrame* inlineFrame = aFrame->GetPrevContinuation();
       while (inlineFrame && !inlineFrame->GetNextInFlow() &&
              AreOnSameLine(aFrame, inlineFrame)) {
         nscoord frameXOffset = inlineFrame->GetOffsetTo(mBlockFrame).x;
         if(isRtlBlock == (frameXOffset >= curOffset)) {
           x += inlineFrame->GetSize().width;
         }
         inlineFrame = inlineFrame->GetPrevContinuation();
       }
@@ -135,16 +153,49 @@ struct InlineBackgroundData
     }
 
     // Assume background-origin: border and return a rect with offsets
     // relative to (0,0).  If we have a different background-origin,
     // then our rect should be deflated appropriately by our caller.
     return nsRect(-x, 0, mUnbrokenWidth, mFrame->GetSize().height);
   }
 
+  /**
+   * Return a continuous rect for (an inline) aFrame relative to the
+   * continuation that should draw the left-border.  This is used when painting
+   * borders and clipping backgrounds.  This may NOT be the same continuous rect
+   * as for drawing backgrounds; the continuation with the left-border might be
+   * somewhere in the middle of that rect (e.g. BIDI), in those cases we need
+   * the reverse background order starting at the left-border continuation.
+   */
+  nsRect GetBorderContinuousRect(nsIFrame* aFrame, nsRect aBorderArea)
+  {
+    // Calling GetContinuousRect(aFrame) here may lead to Reset/Init which
+    // resets our mLeftBorderData so we save it ...
+    LeftBorderData saved(mLeftBorderData);
+    nsRect joinedBorderArea = GetContinuousRect(aFrame);
+    if (!saved.mIsValid || saved.mFrame != mLeftBorderData.mFrame) {
+      if (aFrame == mLeftBorderData.mFrame) {
+        mLeftBorderData.SetX(joinedBorderArea.x);
+      } else if (mLeftBorderData.mFrame) {
+        mLeftBorderData.SetX(GetContinuousRect(mLeftBorderData.mFrame).x);
+      }
+    } else {
+      // ... and restore it when possible.
+      mLeftBorderData.mX = saved.mX;
+    }
+    if (joinedBorderArea.x > mLeftBorderData.mX) {
+      joinedBorderArea.x =
+        -(mUnbrokenWidth + joinedBorderArea.x - aBorderArea.width);
+    } else {
+      joinedBorderArea.x -= mLeftBorderData.mX;
+    }
+    return joinedBorderArea;
+  }
+
   nsRect GetBoundingRect(nsIFrame* aFrame)
   {
     SetFrame(aFrame);
 
     // Move the offsets relative to (0,0) which puts the bounding box into
     // our coordinate system rather than our parent's.  We do this by
     // moving it the back distance from us to the bounding box.
     // This also assumes background-origin: border, so our caller will
@@ -152,23 +203,32 @@ struct InlineBackgroundData
     nsRect boundingBox(mBoundingBox);
     nsPoint point = mFrame->GetPosition();
     boundingBox.MoveBy(-point.x, -point.y);
 
     return boundingBox;
   }
 
 protected:
-  nsIFrame*     mFrame;
-  nsBlockFrame* mBlockFrame;
-  nsRect        mBoundingBox;
-  nscoord       mContinuationPoint;
-  nscoord       mUnbrokenWidth;
-  nscoord       mLineContinuationPoint;
-  bool          mBidiEnabled;
+  struct LeftBorderData {
+    nsIFrame* mFrame;   // the continuation that may have a left-border
+    nscoord   mX;       // cached GetContinuousRect(mFrame).x
+    bool      mIsValid; // true if mX is valid
+    void Reset() { mFrame = nullptr; mIsValid = false; }
+    void SetX(nscoord aX) { mX = aX; mIsValid = true; }
+  };
+
+  nsIFrame*      mFrame;
+  nsBlockFrame*  mBlockFrame;
+  nsRect         mBoundingBox;
+  nscoord        mContinuationPoint;
+  nscoord        mUnbrokenWidth;
+  nscoord        mLineContinuationPoint;
+  LeftBorderData mLeftBorderData;
+  bool           mBidiEnabled;
 
   void SetFrame(nsIFrame* aFrame)
   {
     NS_PRECONDITION(aFrame, "Need a frame");
     NS_ASSERTION(gFrameTreeLockCount > 0,
                  "Can't call this when frame tree is not locked");
 
     if (aFrame == mFrame) {
@@ -231,48 +291,56 @@ protected:
         NS_ASSERTION(nextCont, "How did that happen?");
       }
     }
     return nextCont;
   }
 
   void Init(nsIFrame* aFrame)
   {
+    mLeftBorderData.Reset();
     mBidiEnabled = aFrame->PresContext()->BidiEnabled();
     if (mBidiEnabled) {
       // Find the containing block frame
       nsIFrame* frame = aFrame;
       do {
         frame = frame->GetParent();
         mBlockFrame = do_QueryFrame(frame);
       }
       while (frame && frame->IsFrameOfType(nsIFrame::eLineParticipant));
 
       NS_ASSERTION(mBlockFrame, "Cannot find containing block.");
     }
 
     // Start with the previous flow frame as our continuation point
     // is the total of the widths of the previous frames.
     nsIFrame* inlineFrame = GetPrevContinuation(aFrame);
-
     while (inlineFrame) {
+      if (!mLeftBorderData.mFrame &&
+          !(inlineFrame->GetSkipSides() & SIDE_BIT_LEFT)) {
+        mLeftBorderData.mFrame = inlineFrame;
+      }
       nsRect rect = inlineFrame->GetRect();
       mContinuationPoint += rect.width;
       if (mBidiEnabled && !AreOnSameLine(aFrame, inlineFrame)) {
         mLineContinuationPoint += rect.width;
       }
       mUnbrokenWidth += rect.width;
       mBoundingBox.UnionRect(mBoundingBox, rect);
       inlineFrame = GetPrevContinuation(inlineFrame);
     }
 
     // Next add this frame and subsequent frames to the bounding box and
     // unbroken width.
     inlineFrame = aFrame;
     while (inlineFrame) {
+      if (!mLeftBorderData.mFrame &&
+          !(inlineFrame->GetSkipSides() & SIDE_BIT_LEFT)) {
+        mLeftBorderData.mFrame = inlineFrame;
+      }
       nsRect rect = inlineFrame->GetRect();
       mUnbrokenWidth += rect.width;
       mBoundingBox.UnionRect(mBoundingBox, rect);
       inlineFrame = GetNextContinuation(inlineFrame);
     }
 
     mFrame = aFrame;
   }
@@ -300,17 +368,18 @@ struct ColorStop {
 };
 
 /* Local functions */
 static void DrawBorderImage(nsPresContext* aPresContext,
                             nsRenderingContext& aRenderingContext,
                             nsIFrame* aForFrame,
                             const nsRect& aBorderArea,
                             const nsStyleBorder& aStyleBorder,
-                            const nsRect& aDirtyRect);
+                            const nsRect& aDirtyRect,
+                            int aSkipSides);
 
 static nscolor MakeBevelColor(mozilla::css::Side whichSide, uint8_t style,
                               nscolor aBackgroundColor,
                               nscolor aBorderColor);
 
 static InlineBackgroundData* gInlineBGData = nullptr;
 
 // Initialize any static variables used by nsCSSRendering.
@@ -366,16 +435,116 @@ MakeBevelColor(mozilla::css::Side whichS
   case NS_SIDE_LEFT:
   default:
     theColor = colors[0];
     break;
   }
   return theColor;
 }
 
+static bool
+GetRadii(nsIFrame* aForFrame, const nsStyleBorder& aBorder,
+         const nsRect& aOrigBorderArea, const nsRect& aBorderArea,
+         gfxCornerSizes* aBgRadii)
+{
+  nscoord radii[8];
+  bool haveRoundedCorners;
+  nsSize sz = aBorderArea.Size();
+  nsSize frameSize = aForFrame->GetSize();
+  if (&aBorder == aForFrame->StyleBorder() &&
+      frameSize == aOrigBorderArea.Size()) {
+    haveRoundedCorners = aForFrame->GetBorderRadii(sz, sz, 0, radii);
+   } else {
+    haveRoundedCorners =
+      nsIFrame::ComputeBorderRadii(aBorder.mBorderRadius, frameSize, sz, 0, radii);
+  }
+  if (haveRoundedCorners) {
+    auto d2a = aForFrame->PresContext()->AppUnitsPerDevPixel();
+    nsCSSRendering::ComputePixelRadii(radii, d2a, aBgRadii);
+  }
+  return haveRoundedCorners;
+}
+
+static nsRect
+JoinBoxesForVerticalSlice(nsIFrame* aFrame, const nsRect& aBorderArea)
+{
+  // Inflate vertically as if our continuations were laid out vertically
+  // adjacent. Note that we don't touch the width.
+  nsRect borderArea = aBorderArea;
+  nscoord h = 0;
+  nsIFrame* f = aFrame->GetNextContinuation();
+  for (; f; f = f->GetNextContinuation()) {
+    MOZ_ASSERT(!(f->GetStateBits() & NS_FRAME_PART_OF_IBSPLIT),
+               "anonymous ib-split block shouldn't have border/background");
+    h += f->GetRect().height;
+  }
+  borderArea.height += h;
+  h = 0;
+  f = aFrame->GetPrevContinuation();
+  for (; f; f = f->GetPrevContinuation()) {
+    MOZ_ASSERT(!(f->GetStateBits() & NS_FRAME_PART_OF_IBSPLIT),
+               "anonymous ib-split block shouldn't have border/background");
+    h += f->GetRect().height;
+  }
+  borderArea.y -= h;
+  borderArea.height += h;
+  return borderArea;
+}
+
+/**
+ * Inflate aBorderArea which is relative to aFrame's origin to calculate
+ * a hypothetical non-split frame area for all the continuations.
+ * See "Joining Boxes for 'slice'" in
+ * http://dev.w3.org/csswg/css-break/#break-decoration
+ */
+enum InlineBoxOrder { eForBorder, eForBackground };
+static nsRect
+JoinBoxesForSlice(nsIFrame* aFrame, const nsRect& aBorderArea,
+                  InlineBoxOrder aOrder)
+{
+  if (aFrame->GetType() == nsGkAtoms::inlineFrame) {
+    return (aOrder == eForBorder
+            ? gInlineBGData->GetBorderContinuousRect(aFrame, aBorderArea)
+            : gInlineBGData->GetContinuousRect(aFrame)) +
+      aBorderArea.TopLeft();
+  }
+  return JoinBoxesForVerticalSlice(aFrame, aBorderArea);
+}
+
+static bool
+IsBoxDecorationSlice(const nsStyleBorder& aStyleBorder)
+{
+  return aStyleBorder.mBoxDecorationBreak ==
+           NS_STYLE_BOX_DECORATION_BREAK_SLICE;
+}
+
+static nsRect
+BoxDecorationRectForBorder(nsIFrame* aFrame, const nsRect& aBorderArea,
+                           const nsStyleBorder* aStyleBorder = nullptr)
+{
+  if (!aStyleBorder) {
+    aStyleBorder = aFrame->StyleBorder();
+  }
+  return ::IsBoxDecorationSlice(*aStyleBorder)
+           ? ::JoinBoxesForSlice(aFrame, aBorderArea, eForBorder)
+           : aBorderArea;
+}
+
+static nsRect
+BoxDecorationRectForBackground(nsIFrame* aFrame, const nsRect& aBorderArea,
+                               const nsStyleBorder* aStyleBorder = nullptr)
+{
+  if (!aStyleBorder) {
+    aStyleBorder = aFrame->StyleBorder();
+  }
+  return ::IsBoxDecorationSlice(*aStyleBorder)
+           ? ::JoinBoxesForSlice(aFrame, aBorderArea, eForBackground)
+           : aBorderArea;
+}
+
 //----------------------------------------------------------------------
 // Thebes Border Rendering Code Start
 
 /*
  * Compute the float-pixel radii that should be used for drawing
  * this border/outline, given the various input bits.
  */
 /* static */ void
@@ -444,136 +613,133 @@ nsCSSRendering::PaintBorderWithStyleBord
                                            nsRenderingContext& aRenderingContext,
                                            nsIFrame* aForFrame,
                                            const nsRect& aDirtyRect,
                                            const nsRect& aBorderArea,
                                            const nsStyleBorder& aStyleBorder,
                                            nsStyleContext* aStyleContext,
                                            int aSkipSides)
 {
-  nsMargin            border;
-  nscoord             twipsRadii[8];
-  nsCompatibility     compatMode = aPresContext->CompatibilityMode();
-
   SN("++ PaintBorder");
 
   // Check to see if we have an appearance defined.  If so, we let the theme
   // renderer draw the border.  DO not get the data from aForFrame, since the passed in style context
   // may be different!  Always use |aStyleContext|!
   const nsStyleDisplay* displayData = aStyleContext->StyleDisplay();
   if (displayData->mAppearance) {
     nsITheme *theme = aPresContext->GetTheme();
     if (theme && theme->ThemeSupportsWidget(aPresContext, aForFrame, displayData->mAppearance))
       return; // Let the theme handle it.
   }
 
   if (aStyleBorder.IsBorderImageLoaded()) {
     DrawBorderImage(aPresContext, aRenderingContext, aForFrame,
-                    aBorderArea, aStyleBorder, aDirtyRect);
+                    aBorderArea, aStyleBorder, aDirtyRect, aSkipSides);
     return;
   }
 
   // Get our style context's color struct.
   const nsStyleColor* ourColor = aStyleContext->StyleColor();
 
-  // in NavQuirks mode we want to use the parent's context as a starting point
-  // for determining the background color
-  nsIFrame* bgFrame = nsCSSRendering::FindNonTransparentBackgroundFrame
-    (aForFrame, compatMode == eCompatibility_NavQuirks ? true : false);
+  // In NavQuirks mode we want to use the parent's context as a starting point
+  // for determining the background color.
+  bool quirks = aPresContext->CompatibilityMode() == eCompatibility_NavQuirks;
+  nsIFrame* bgFrame = FindNonTransparentBackgroundFrame(aForFrame, quirks);
   nsStyleContext* bgContext = bgFrame->StyleContext();
   nscolor bgColor =
     bgContext->GetVisitedDependentColor(eCSSProperty_background_color);
 
-  border = aStyleBorder.GetComputedBorder();
-  if ((0 == border.left) && (0 == border.right) &&
-      (0 == border.top) && (0 == border.bottom)) {
+  nsMargin border = aStyleBorder.GetComputedBorder();
+  if (0 == border.left && 0 == border.right &&
+      0 == border.top  && 0 == border.bottom) {
     // Empty border area
     return;
   }
 
-  nsSize frameSize = aForFrame->GetSize();
-  if (&aStyleBorder == aForFrame->StyleBorder() &&
-      frameSize == aBorderArea.Size()) {
-    aForFrame->GetBorderRadii(twipsRadii);
+  // Compute the outermost boundary of the area that might be painted.
+  // Same coordinate space as aBorderArea & aBGClipRect.
+  nsRect joinedBorderArea =
+    ::BoxDecorationRectForBorder(aForFrame, aBorderArea, &aStyleBorder);
+  gfxCornerSizes bgRadii;
+  ::GetRadii(aForFrame, aStyleBorder, aBorderArea, joinedBorderArea, &bgRadii);
+
+
+  SF(" joinedBorderArea: %d %d %d %d\n", joinedBorderArea.x, joinedBorderArea.y,
+     joinedBorderArea.width, joinedBorderArea.height);
+
+  // start drawing
+  gfxContext* ctx = aRenderingContext.ThebesContext();
+  ctx->Save();
+
+  if (::IsBoxDecorationSlice(aStyleBorder)) {
+    if (aSkipSides == 0) {
+      // No continuations most likely, or ::first-letter that wants all border-
+      // sides on the first continuation.
+      joinedBorderArea = aBorderArea;
+    } else if (joinedBorderArea.IsEqualEdges(aBorderArea)) {
+      // No need for a clip, just skip the sides we don't want.
+      ::ApplySkipSides(aSkipSides, &border);
+    } else {
+      // We're drawing borders around the joined continuation boxes so we need
+      // to clip that to the slice that we want for this frame.
+      aRenderingContext.IntersectClip(aBorderArea);
+    }
   } else {
-    nsIFrame::ComputeBorderRadii(aStyleBorder.mBorderRadius, frameSize,
-                                 aBorderArea.Size(), aSkipSides, twipsRadii);
+    MOZ_ASSERT(joinedBorderArea.IsEqualEdges(aBorderArea),
+               "Should use aBorderArea for box-decoration-break:clone");
+    MOZ_ASSERT(aForFrame->GetSkipSides() == 0,
+               "Should not skip sides for box-decoration-break:clone except "
+               "::first-letter/line continuations or other frame types that "
+               "don't have borders but those shouldn't reach this point.");
   }
 
-  // Turn off rendering for all of the zero sized sides
-  if (aSkipSides & SIDE_BIT_TOP) border.top = 0;
-  if (aSkipSides & SIDE_BIT_RIGHT) border.right = 0;
-  if (aSkipSides & SIDE_BIT_BOTTOM) border.bottom = 0;
-  if (aSkipSides & SIDE_BIT_LEFT) border.left = 0;
-
-  // get the inside and outside parts of the border
-  nsRect outerRect(aBorderArea);
-
-  SF(" outerRect: %d %d %d %d\n", outerRect.x, outerRect.y, outerRect.width, outerRect.height);
-
-  // we can assume that we're already clipped to aDirtyRect -- I think? (!?)
-
-  // Get our conversion values
+  // Convert to dev pixels.
   nscoord twipsPerPixel = aPresContext->DevPixelsToAppUnits(1);
-
-  // convert outer and inner rects
-  gfxRect oRect(nsLayoutUtils::RectToGfxRect(outerRect, twipsPerPixel));
-
-  // convert the border widths
+  gfxRect joinedBorderAreaPx =
+    nsLayoutUtils::RectToGfxRect(joinedBorderArea, twipsPerPixel);
   gfxFloat borderWidths[4] = { gfxFloat(border.top / twipsPerPixel),
                                gfxFloat(border.right / twipsPerPixel),
                                gfxFloat(border.bottom / twipsPerPixel),
                                gfxFloat(border.left / twipsPerPixel) };
 
-  // convert the radii
-  gfxCornerSizes borderRadii;
-  ComputePixelRadii(twipsRadii, twipsPerPixel, &borderRadii);
-
   uint8_t borderStyles[4];
   nscolor borderColors[4];
   nsBorderColors *compositeColors[4];
 
   // pull out styles, colors, composite colors
   NS_FOR_CSS_SIDES (i) {
     bool foreground;
     borderStyles[i] = aStyleBorder.GetBorderStyle(i);
     aStyleBorder.GetBorderColor(i, borderColors[i], foreground);
     aStyleBorder.GetCompositeColors(i, &compositeColors[i]);
 
     if (foreground)
       borderColors[i] = ourColor->mColor;
   }
 
   SF(" borderStyles: %d %d %d %d\n", borderStyles[0], borderStyles[1], borderStyles[2], borderStyles[3]);
-
-  // start drawing
-  gfxContext *ctx = aRenderingContext.ThebesContext();
-
-  ctx->Save();
+  //SF ("bgRadii: %f %f %f %f\n", bgRadii[0], bgRadii[1], bgRadii[2], bgRadii[3]);
 
 #if 0
-  // this will draw a transparent red backround underneath the oRect area
+  // this will draw a transparent red backround underneath the border area
   ctx->Save();
-  ctx->Rectangle(oRect);
+  ctx->Rectangle(joinedBorderAreaPx);
   ctx->SetColor(gfxRGBA(1.0, 0.0, 0.0, 0.5));
   ctx->Fill();
   ctx->Restore();
 #endif
 
-  //SF ("borderRadii: %f %f %f %f\n", borderRadii[0], borderRadii[1], borderRadii[2], borderRadii[3]);
-
   nsCSSBorderRenderer br(twipsPerPixel,
                          ctx,
-                         oRect,
+                         joinedBorderAreaPx,
                          borderStyles,
                          borderWidths,
-                         borderRadii,
+                         bgRadii,
                          borderColors,
                          compositeColors,
-                         aSkipSides,
                          bgColor);
   br.DrawBorders();
 
   ctx->Restore();
 
   SN();
 }
 
@@ -683,17 +849,17 @@ nsCSSRendering::PaintOutline(nsPresConte
 
   nsCSSBorderRenderer br(twipsPerPixel,
                          ctx,
                          oRect,
                          outlineStyles,
                          outlineWidths,
                          outlineRadii,
                          outlineColors,
-                         nullptr, 0,
+                         nullptr,
                          bgColor);
   br.DrawBorders();
 
   ctx->Restore();
 
   SN();
 }
 
@@ -736,17 +902,17 @@ nsCSSRendering::PaintFocus(nsPresContext
   // and PaintOutline do.)
   nsCSSBorderRenderer br(oneDevPixel,
                          ctx,
                          focusRect,
                          focusStyles,
                          focusWidths,
                          focusRadii,
                          focusColors,
-                         nullptr, 0,
+                         nullptr,
                          NS_RGB(255, 0, 0));
   br.DrawBorders();
 
   ctx->Restore();
 
   SN();
 }
 
@@ -991,44 +1157,53 @@ nsCSSRendering::PaintBoxShadowOuter(nsPr
                                     const nsRect& aFrameArea,
                                     const nsRect& aDirtyRect,
                                     float aOpacity)
 {
   const nsStyleBorder* styleBorder = aForFrame->StyleBorder();
   nsCSSShadowArray* shadows = styleBorder->mBoxShadow;
   if (!shadows)
     return;
-  nscoord twipsPerPixel = aPresContext->DevPixelsToAppUnits(1);
-
+
+  gfxContextAutoSaveRestore gfxStateRestorer;
   bool hasBorderRadius;
   bool nativeTheme; // mutually exclusive with hasBorderRadius
-  gfxCornerSizes borderRadii;
-
-  // Get any border radius, since box-shadow must also have rounded corners if the frame does
   const nsStyleDisplay* styleDisplay = aForFrame->StyleDisplay();
   nsITheme::Transparency transparency;
   if (aForFrame->IsThemed(styleDisplay, &transparency)) {
     // We don't respect border-radius for native-themed widgets
     hasBorderRadius = false;
     // For opaque (rectangular) theme widgets we can take the generic
     // border-box path with border-radius disabled.
     nativeTheme = transparency != nsITheme::eOpaque;
   } else {
     nativeTheme = false;
+    hasBorderRadius = true; // we'll update this below
+  }
+
+  nsRect frameRect = nativeTheme ?
+    aForFrame->GetVisualOverflowRectRelativeToSelf() + aFrameArea.TopLeft() :
+    aFrameArea;
+  frameRect = ::BoxDecorationRectForBorder(aForFrame, frameRect);
+
+  // Get any border radius, since box-shadow must also have rounded corners if
+  // the frame does.
+  gfxCornerSizes borderRadii;
+  const nscoord twipsPerPixel = aPresContext->DevPixelsToAppUnits(1);
+  if (hasBorderRadius) {
     nscoord twipsRadii[8];
     NS_ASSERTION(aFrameArea.Size() == aForFrame->VisualBorderRectRelativeToSelf().Size(),
                  "unexpected size");
-    hasBorderRadius = aForFrame->GetBorderRadii(twipsRadii);
+    nsSize sz = frameRect.Size();
+    hasBorderRadius = aForFrame->GetBorderRadii(sz, sz, 0, twipsRadii);
     if (hasBorderRadius) {
       ComputePixelRadii(twipsRadii, twipsPerPixel, &borderRadii);
     }
   }
 
-  nsRect frameRect =
-    nativeTheme ? aForFrame->GetVisualOverflowRectRelativeToSelf() + aFrameArea.TopLeft() : aFrameArea;
   gfxRect frameGfxRect(nsLayoutUtils::RectToGfxRect(frameRect, twipsPerPixel));
   frameGfxRect.Round();
 
   // We don't show anything that intersects with the frame we're blurring on. So tell the
   // blurrer not to do unnecessary work there.
   gfxRect skipGfxRect = frameGfxRect;
   bool useSkipGfxRect = true;
   if (nativeTheme) {
@@ -1042,16 +1217,17 @@ nsCSSRendering::PaintBoxShadowOuter(nsPr
       aForFrame->GetPaddingRect() - aForFrame->GetPosition() + aFrameArea.TopLeft();
     skipGfxRect = nsLayoutUtils::RectToGfxRect(paddingRect, twipsPerPixel);
   } else if (hasBorderRadius) {
     skipGfxRect.Deflate(gfxMargin(
         std::max(borderRadii[C_TL].height, borderRadii[C_TR].height), 0,
         std::max(borderRadii[C_BL].height, borderRadii[C_BR].height), 0));
   }
 
+  int skipSides = aForFrame->GetSkipSides();
   for (uint32_t i = shadows->Length(); i > 0; --i) {
     nsCSSShadowItem* shadowItem = shadows->ShadowAt(i - 1);
     if (shadowItem->mInset)
       continue;
 
     nsRect shadowRect = frameRect;
     shadowRect.MoveBy(shadowItem->mXOffset, shadowItem->mYOffset);
     if (!nativeTheme) {
@@ -1122,28 +1298,58 @@ nsCSSRendering::PaintBoxShadowOuter(nsPr
       aPresContext->GetTheme()->DrawWidgetBackground(wrapperCtx, aForFrame,
           styleDisplay->mAppearance, aFrameArea, nativeRect);
 
       blurringArea.DoPaint();
       renderContext->Restore();
     } else {
       renderContext->Save();
       // Clip out the area of the actual frame so the shadow is not shown within
-      // the frame
+      // the frame.
       renderContext->NewPath();
       renderContext->Rectangle(shadowGfxRectPlusBlur);
       if (hasBorderRadius) {
         renderContext->RoundedRectangle(frameGfxRect, borderRadii);
       } else {
         renderContext->Rectangle(frameGfxRect);
       }
 
       renderContext->SetFillRule(gfxContext::FILL_RULE_EVEN_ODD);
       renderContext->Clip();
 
+      // Clip the shadow so that we only get the part that applies to aForFrame.
+      nsRect fragmentClip = shadowRectPlusBlur;
+      if (skipSides) {
+        if (skipSides & SIDE_BIT_LEFT) {
+          nscoord xmost = fragmentClip.XMost();
+          fragmentClip.x = aFrameArea.x;
+          fragmentClip.width = xmost - fragmentClip.x;
+        }
+        if (skipSides & SIDE_BIT_RIGHT) {
+          nscoord xmost = fragmentClip.XMost();
+          nscoord overflow = xmost - aFrameArea.XMost();
+          if (overflow > 0) {
+            fragmentClip.width -= overflow;
+          }
+        }
+        if (skipSides & SIDE_BIT_TOP) {
+          nscoord ymost = fragmentClip.YMost();
+          fragmentClip.y = aFrameArea.y;
+          fragmentClip.height = ymost - fragmentClip.y;
+        }
+        if (skipSides & SIDE_BIT_BOTTOM) {
+          nscoord ymost = fragmentClip.YMost();
+          nscoord overflow = ymost - aFrameArea.YMost();
+          if (overflow > 0) {
+            fragmentClip.height -= overflow;
+          }
+        }
+      }
+      aRenderingContext.IntersectClip(fragmentClip);
+
       gfxCornerSizes clipRectRadii;
       if (hasBorderRadius) {
         gfxFloat spreadDistance = shadowItem->mSpread / twipsPerPixel;
 
         gfxFloat borderSizes[4];
 
         borderSizes[NS_SIDE_LEFT] = spreadDistance;
         borderSizes[NS_SIDE_TOP] = spreadDistance;
@@ -1183,28 +1389,30 @@ nsCSSRendering::PaintBoxShadowInner(nsPr
       !nsContentUtils::IsChromeDoc(aForFrame->GetContent()->GetCurrentDoc())) {
     // There's no way of getting hold of a shape corresponding to a
     // "padding-box" for native-themed widgets, so just don't draw
     // inner box-shadows for them. But we allow chrome to paint inner
     // box shadows since chrome can be aware of the platform theme.
     return;
   }
 
+  NS_ASSERTION(aForFrame->GetType() == nsGkAtoms::fieldSetFrame ||
+               aFrameArea.Size() == aForFrame->GetSize(), "unexpected size");
+
+  nsRect frameRect = ::BoxDecorationRectForBorder(aForFrame, aFrameArea);
+  nsRect paddingRect = frameRect;
+  nsMargin border = aForFrame->GetUsedBorder();
+  paddingRect.Deflate(border);
+
   // Get any border radius, since box-shadow must also have rounded corners
   // if the frame does.
   nscoord twipsRadii[8];
-  NS_ASSERTION(aForFrame->GetType() == nsGkAtoms::fieldSetFrame ||
-               aFrameArea.Size() == aForFrame->GetSize(), "unexpected size");
-  bool hasBorderRadius = aForFrame->GetBorderRadii(twipsRadii);
-  nscoord twipsPerPixel = aPresContext->DevPixelsToAppUnits(1);
-
-  nsRect paddingRect = aFrameArea;
-  nsMargin border = aForFrame->GetUsedBorder();
-  aForFrame->ApplySkipSides(border);
-  paddingRect.Deflate(border);
+  nsSize sz = frameRect.Size();
+  bool hasBorderRadius = aForFrame->GetBorderRadii(sz, sz, 0, twipsRadii);
+  const nscoord twipsPerPixel = aPresContext->DevPixelsToAppUnits(1);
 
   gfxCornerSizes innerRadii;
   if (hasBorderRadius) {
     gfxCornerSizes borderRadii;
 
     ComputePixelRadii(twipsRadii, twipsPerPixel, &borderRadii);
     gfxFloat borderSizes[4] = {
       gfxFloat(border.top / twipsPerPixel),
@@ -1216,23 +1424,19 @@ nsCSSRendering::PaintBoxShadowInner(nsPr
                                            &innerRadii);
   }
 
   for (uint32_t i = shadows->Length(); i > 0; --i) {
     nsCSSShadowItem* shadowItem = shadows->ShadowAt(i - 1);
     if (!shadowItem->mInset)
       continue;
 
-    /*
-     * shadowRect: the frame's padding rect
-     * shadowPaintRect: the area to paint on the temp surface, larger than shadowRect
-     *                  so that blurs still happen properly near the edges
-     * shadowClipRect: the area on the temporary surface within shadowPaintRect
-     *                 that we will NOT paint in
-     */
+    // shadowPaintRect: the area to paint on the temp surface
+    // shadowClipRect: the area on the temporary surface within shadowPaintRect
+    //                 that we will NOT paint in
     nscoord blurRadius = shadowItem->mRadius;
     nsMargin blurMargin =
       nsContextBoxBlur::GetBlurRadiusMargin(blurRadius, twipsPerPixel);
     nsRect shadowPaintRect = paddingRect;
     shadowPaintRect.Inflate(blurMargin);
 
     nsRect shadowClipRect = paddingRect;
     shadowClipRect.MoveBy(shadowItem->mXOffset, shadowItem->mYOffset);
@@ -1501,16 +1705,17 @@ GetBackgroundClip(gfxContext *aCtx, uint
                   const gfxCornerSizes& aBGRadii, nscoord aAppUnitsPerPixel,
                   /* out */ BackgroundClipState* aClipState)
 {
   aClipState->mBGClipArea = aBorderArea;
   aClipState->mHasAdditionalBGClipArea = false;
   aClipState->mCustomClip = false;
   aClipState->mRadiiAreOuter = true;
   aClipState->mClippedRadii = aBGRadii;
+
   if (aForFrame->GetType() == nsGkAtoms::scrollFrame &&
         NS_STYLE_BG_ATTACHMENT_LOCAL == aBackgroundAttachment) {
     // As of this writing, this is still in discussion in the CSS Working Group
     // http://lists.w3.org/Archives/Public/www-style/2013Jul/0250.html
 
     // The rectangle for 'background-clip' scrolls with the content,
     // but the background is also clipped at a non-scrolling 'padding-box'
     // like the content. (See below.)
@@ -1599,25 +1804,23 @@ SetupBackgroundClip(BackgroundClipState&
 
   // If we have rounded corners, clip all subsequent drawing to the
   // rounded rectangle defined by bgArea and bgRadii (we don't know
   // whether the rounded corners intrude on the dirtyRect or not).
   // Do not do this if we have a caller-provided clip rect --
   // as above with bgArea, arguably a bug, but table painting seems
   // to depend on it.
 
-  if (aHaveRoundedCorners || aClipState.mHasAdditionalBGClipArea) {
-    aAutoSR->Reset(aCtx);
-  }
-
   if (aClipState.mHasAdditionalBGClipArea) {
     gfxRect bgAreaGfx = nsLayoutUtils::RectToGfxRect(
       aClipState.mAdditionalBGClipArea, aAppUnitsPerPixel);
     bgAreaGfx.Round();
     bgAreaGfx.Condition();
+
+    aAutoSR->EnsureSaved(aCtx);
     aCtx->NewPath();
     aCtx->Rectangle(bgAreaGfx, true);
     aCtx->Clip();
   }
 
   if (aHaveRoundedCorners) {
     gfxRect bgAreaGfx =
       nsLayoutUtils::RectToGfxRect(aClipState.mBGClipArea, aAppUnitsPerPixel);
@@ -1628,16 +1831,17 @@ SetupBackgroundClip(BackgroundClipState&
       // I think it's become possible to hit this since
       // http://hg.mozilla.org/mozilla-central/rev/50e934e4979b landed.
       NS_WARNING("converted background area should not be empty");
       // Make our caller not do anything.
       aClipState.mDirtyRectGfx.SizeTo(gfxSize(0.0, 0.0));
       return;
     }
 
+    aAutoSR->EnsureSaved(aCtx);
     aCtx->NewPath();
     aCtx->RoundedRectangle(bgAreaGfx, aClipState.mClippedRadii, aClipState.mRadiiAreOuter);
     aCtx->Clip();
   }
 }
 
 static void
 DrawBackgroundColor(BackgroundClipState& aClipState, gfxContext *aCtx,
@@ -2402,43 +2606,33 @@ nsCSSRendering::PaintBackgroundWithSC(ns
 
   // At this point, drawBackgroundImage and drawBackgroundColor are
   // true if and only if we are actually supposed to paint an image or
   // color into aDirtyRect, respectively.
   if (!drawBackgroundImage && !drawBackgroundColor)
     return;
 
   // Compute the outermost boundary of the area that might be painted.
-  gfxContext *ctx = aRenderingContext.ThebesContext();
-  nscoord appUnitsPerPixel = aPresContext->AppUnitsPerDevPixel();
-
-  // Same coordinate space as aBorderArea & aBGClipRect
+  // Same coordinate space as aBorderArea & aBGClipRect.
+  nsRect paintBorderArea =
+    ::BoxDecorationRectForBackground(aForFrame, aBorderArea, &aBorder);
+  nsRect clipBorderArea =
+    ::BoxDecorationRectForBorder(aForFrame, aBorderArea, &aBorder);
   gfxCornerSizes bgRadii;
-  bool haveRoundedCorners;
-  {
-    nscoord radii[8];
-    nsSize frameSize = aForFrame->GetSize();
-    if (&aBorder == aForFrame->StyleBorder() &&
-        frameSize == aBorderArea.Size()) {
-      haveRoundedCorners = aForFrame->GetBorderRadii(radii);
-    } else {
-      haveRoundedCorners = nsIFrame::ComputeBorderRadii(aBorder.mBorderRadius,
-                                   frameSize, aBorderArea.Size(),
-                                   aForFrame->GetSkipSides(), radii);
-    }
-    if (haveRoundedCorners)
-      ComputePixelRadii(radii, appUnitsPerPixel, &bgRadii);
-  }
+  bool haveRoundedCorners =
+    ::GetRadii(aForFrame, aBorder, aBorderArea, clipBorderArea, &bgRadii);
 
   // The 'bgClipArea' (used only by the image tiling logic, far below)
   // is the caller-provided aBGClipRect if any, or else the area
   // determined by the value of 'background-clip' in
   // SetupCurrentBackgroundClip.  (Arguably it should be the
   // intersection, but that breaks the table painter -- in particular,
   // taking the intersection breaks reftests/bugs/403249-1[ab].)
+  gfxContext* ctx = aRenderingContext.ThebesContext();
+  nscoord appUnitsPerPixel = aPresContext->AppUnitsPerDevPixel();
   BackgroundClipState clipState;
   uint8_t currentBackgroundClip;
   bool isSolidBorder;
   if (aBGClipRect) {
     clipState.mBGClipArea = *aBGClipRect;
     clipState.mCustomClip = true;
     SetupDirtyRects(clipState.mBGClipArea, aDirtyRect, appUnitsPerPixel,
                     &clipState.mDirtyRect, &clipState.mDirtyRectGfx);
@@ -2458,25 +2652,27 @@ nsCSSRendering::PaintBackgroundWithSC(ns
       // If we have rounded corners, we need to inflate the background
       // drawing area a bit to avoid seams between the border and
       // background.
       currentBackgroundClip = haveRoundedCorners ?
         NS_STYLE_BG_CLIP_MOZ_ALMOST_PADDING : NS_STYLE_BG_CLIP_PADDING;
     }
 
     GetBackgroundClip(ctx, currentBackgroundClip, bg->BottomLayer().mAttachment,
-                      aForFrame, aBorderArea,
+                      aForFrame, clipBorderArea,
                       aDirtyRect, haveRoundedCorners, bgRadii, appUnitsPerPixel,
                       &clipState);
   }
 
   // If we might be using a background color, go ahead and set it now.
   if (drawBackgroundColor && !isCanvasFrame)
     ctx->SetColor(gfxRGBA(bgColor));
 
+  // NOTE: no Save() yet, we do that later by calling autoSR.EnsureSaved(ctx)
+  // in the cases we need it.
   gfxContextAutoSaveRestore autoSR;
 
   // If there is no background image, draw a color.  (If there is
   // neither a background image nor a color, we wouldn't have gotten
   // this far.)
   if (!drawBackgroundImage) {
     if (!isCanvasFrame) {
       DrawBackgroundColor(clipState, ctx, haveRoundedCorners, appUnitsPerPixel);
@@ -2526,38 +2722,49 @@ nsCSSRendering::PaintBackgroundWithSC(ns
             NS_STYLE_BG_CLIP_MOZ_ALMOST_PADDING : NS_STYLE_BG_CLIP_PADDING;
         }
         if (currentBackgroundClip != newBackgroundClip || !clipSet) {
           currentBackgroundClip = newBackgroundClip;
           // If clipSet is false that means this is the bottom layer and we
           // already called GetBackgroundClip above and it stored its results
           // in clipState.
           if (clipSet) {
+            autoSR = gfxContextAutoSaveRestore(); // reset the previous one
             GetBackgroundClip(ctx, currentBackgroundClip, layer.mAttachment, aForFrame,
-                              aBorderArea, aDirtyRect, haveRoundedCorners,
+                              clipBorderArea, aDirtyRect, haveRoundedCorners,
                               bgRadii, appUnitsPerPixel, &clipState);
           }
           SetupBackgroundClip(clipState, ctx, haveRoundedCorners,
                               appUnitsPerPixel, &autoSR);
           clipSet = true;
+          if (!clipBorderArea.IsEqualEdges(aBorderArea)) {
+            // We're drawing the background for the joined continuation boxes
+            // so we need to clip that to the slice that we want for this frame.
+            gfxRect clip =
+              nsLayoutUtils::RectToGfxRect(aBorderArea, appUnitsPerPixel);
+            autoSR.EnsureSaved(ctx);
+            ctx->NewPath();
+            ctx->SnappedRectangle(clip);
+            ctx->Clip();
+          }
         }
       }
       if ((aLayer < 0 || i == (uint32_t)startLayer) &&
           !clipState.mDirtyRectGfx.IsEmpty()) {
         nsBackgroundLayerState state = PrepareBackgroundLayer(aPresContext, aForFrame,
-            aFlags, aBorderArea, clipState.mBGClipArea, *bg, layer);
+            aFlags, paintBorderArea, clipState.mBGClipArea, layer);
         if (!state.mFillArea.IsEmpty()) {
           if (state.mCompositingOp != gfxContext::OPERATOR_OVER) {
             NS_ASSERTION(ctx->CurrentOperator() == gfxContext::OPERATOR_OVER,
                          "It is assumed the initial operator is OPERATOR_OVER, when it is restored later");
             ctx->SetOperator(state.mCompositingOp);
           }
           state.mImageRenderer.DrawBackground(aPresContext, aRenderingContext,
                                               state.mDestArea, state.mFillArea,
-                                              state.mAnchor + aBorderArea.TopLeft(),
+                                              state.mAnchor + paintBorderArea.TopLeft(),
                                               clipState.mDirtyRect);
           if (state.mCompositingOp != gfxContext::OPERATOR_OVER) {
             ctx->SetOperator(gfxContext::OPERATOR_OVER);
           }
         }
       }
     }
   }
@@ -2602,60 +2809,48 @@ nsCSSRendering::PaintBackgroundColorWith
 
   NS_ASSERTION(drawBackgroundImage || drawBackgroundColor,
                "Should not be trying to paint a background if we don't have one");
   if (!drawBackgroundColor) {
     return;
   }
 
   // Compute the outermost boundary of the area that might be painted.
-  gfxContext *ctx = aRenderingContext.ThebesContext();
-  nscoord appUnitsPerPixel = aPresContext->AppUnitsPerDevPixel();
-
-  // Same coordinate space as aBorderArea
+  // Same coordinate space as aBorderArea.
+  nsRect clipBorderArea =
+    ::BoxDecorationRectForBorder(aForFrame, aBorderArea, &aBorder);
   gfxCornerSizes bgRadii;
-  bool haveRoundedCorners;
-  {
-    nscoord radii[8];
-    nsSize frameSize = aForFrame->GetSize();
-    if (&aBorder == aForFrame->StyleBorder() &&
-        frameSize == aBorderArea.Size()) {
-      haveRoundedCorners = aForFrame->GetBorderRadii(radii);
-    } else {
-      haveRoundedCorners = nsIFrame::ComputeBorderRadii(aBorder.mBorderRadius,
-                                   frameSize, aBorderArea.Size(),
-                                   aForFrame->GetSkipSides(), radii);
-    }
-    if (haveRoundedCorners)
-      ComputePixelRadii(radii, appUnitsPerPixel, &bgRadii);
-  }
+  bool haveRoundedCorners =
+    ::GetRadii(aForFrame, aBorder, aBorderArea, clipBorderArea, &bgRadii);
 
   // The background is rendered over the 'background-clip' area,
   // which is normally equal to the border area but may be reduced
   // to the padding area by CSS.  Also, if the border is solid, we
   // don't need to draw outside the padding area.  In either case,
   // if the borders are rounded, make sure we use the same inner
   // radii as the border code will.
   // The background-color is drawn based on the bottom
   // background-clip.
+  gfxContext* ctx = aRenderingContext.ThebesContext();
+  nscoord appUnitsPerPixel = aPresContext->AppUnitsPerDevPixel();
   const nsStyleBackground *bg = aBackgroundSC->StyleBackground();
   uint8_t currentBackgroundClip = bg->BottomLayer().mClip;
   bool isSolidBorder =
     (aFlags & PAINTBG_WILL_PAINT_BORDER) && IsOpaqueBorder(aBorder);
   if (isSolidBorder && currentBackgroundClip == NS_STYLE_BG_CLIP_BORDER) {
     // If we have rounded corners, we need to inflate the background
     // drawing area a bit to avoid seams between the border and
     // background.
     currentBackgroundClip = haveRoundedCorners ?
       NS_STYLE_BG_CLIP_MOZ_ALMOST_PADDING : NS_STYLE_BG_CLIP_PADDING;
   }
 
   BackgroundClipState clipState;
   GetBackgroundClip(ctx, currentBackgroundClip, bg->BottomLayer().mAttachment,
-                    aForFrame, aBorderArea,
+                    aForFrame, clipBorderArea,
                     aDirtyRect, haveRoundedCorners, bgRadii, appUnitsPerPixel,
                     &clipState);
 
   ctx->SetColor(gfxRGBA(bgColor));
 
   gfxContextAutoSaveRestore autoSR;
   DrawBackgroundColor(clipState, ctx, haveRoundedCorners, appUnitsPerPixel);
 }
@@ -2670,57 +2865,27 @@ IsTransformed(nsIFrame* aForFrame, nsIFr
   }
   return false;
 }
 
 nsRect
 nsCSSRendering::ComputeBackgroundPositioningArea(nsPresContext* aPresContext,
                                                  nsIFrame* aForFrame,
                                                  const nsRect& aBorderArea,
-                                                 const nsStyleBackground& aBackground,
                                                  const nsStyleBackground::Layer& aLayer,
                                                  nsIFrame** aAttachedToFrame)
 {
   // Compute background origin area relative to aBorderArea now as we may need
   // it to compute the effective image size for a CSS gradient.
-  nsRect bgPositioningArea(0, 0, 0, 0);
+  nsRect bgPositioningArea;
 
   nsIAtom* frameType = aForFrame->GetType();
   nsIFrame* geometryFrame = aForFrame;
-  if (frameType == nsGkAtoms::inlineFrame) {
-    // XXXjwalden Strictly speaking this is not quite faithful to how
-    // background-break is supposed to interact with background-origin values,
-    // but it's a non-trivial amount of work to make it fully conformant, and
-    // until the specification is more finalized (and assuming background-break
-    // even makes the cut) it doesn't make sense to hammer out exact behavior.
-    switch (aBackground.mBackgroundInlinePolicy) {
-    case NS_STYLE_BG_INLINE_POLICY_EACH_BOX:
-      bgPositioningArea = nsRect(nsPoint(0,0), aBorderArea.Size());
-      break;
-    case NS_STYLE_BG_INLINE_POLICY_BOUNDING_BOX:
-      bgPositioningArea = gInlineBGData->GetBoundingRect(aForFrame);
-      break;
-    default:
-      NS_ERROR("Unknown background-inline-policy value!  "
-               "Please, teach me what to do.");
-    case NS_STYLE_BG_INLINE_POLICY_CONTINUOUS:
-      bgPositioningArea = gInlineBGData->GetContinuousRect(aForFrame);
-      break;
-    }
-  } else if (frameType == nsGkAtoms::canvasFrame) {
-    geometryFrame = aForFrame->GetFirstPrincipalChild();
-    // geometryFrame might be null if this canvas is a page created
-    // as an overflow container (e.g. the in-flow content has already
-    // finished and this page only displays the continuations of
-    // absolutely positioned content).
-    if (geometryFrame) {
-      bgPositioningArea = geometryFrame->GetRect();
-    }
-  } else if (frameType == nsGkAtoms::scrollFrame &&
-             NS_STYLE_BG_ATTACHMENT_LOCAL == aLayer.mAttachment) {
+  if (MOZ_UNLIKELY(frameType == nsGkAtoms::scrollFrame &&
+                   NS_STYLE_BG_ATTACHMENT_LOCAL == aLayer.mAttachment)) {
     nsIScrollableFrame* scrollableFrame = do_QueryFrame(aForFrame);
     bgPositioningArea = nsRect(
       scrollableFrame->GetScrolledFrame()->GetPosition()
         // For the dir=rtl case:
         + scrollableFrame->GetScrollRange().TopLeft(),
       scrollableFrame->GetScrolledRect().Size());
     // The ScrolledRect’s size does not include the borders or scrollbars,
     // reverse the handling of background-origin
@@ -2734,30 +2899,40 @@ nsCSSRendering::ComputeBackgroundPositio
       nsMargin padding = geometryFrame->GetUsedPadding();
       geometryFrame->ApplySkipSides(padding);
       bgPositioningArea.Deflate(padding);
       NS_ASSERTION(aLayer.mOrigin == NS_STYLE_BG_ORIGIN_CONTENT,
                    "unknown background-origin value");
     }
     *aAttachedToFrame = aForFrame;
     return bgPositioningArea;
+  }
+
+  if (MOZ_UNLIKELY(frameType == nsGkAtoms::canvasFrame)) {
+    geometryFrame = aForFrame->GetFirstPrincipalChild();
+    // geometryFrame might be null if this canvas is a page created
+    // as an overflow container (e.g. the in-flow content has already
+    // finished and this page only displays the continuations of
+    // absolutely positioned content).
+    if (geometryFrame) {
+      bgPositioningArea = geometryFrame->GetRect();
+    }
   } else {
     bgPositioningArea = nsRect(nsPoint(0,0), aBorderArea.Size());
   }
 
   // Background images are tiled over the 'background-clip' area
   // but the origin of the tiling is based on the 'background-origin' area
   if (aLayer.mOrigin != NS_STYLE_BG_ORIGIN_BORDER && geometryFrame) {
     nsMargin border = geometryFrame->GetUsedBorder();
     if (aLayer.mOrigin != NS_STYLE_BG_ORIGIN_PADDING) {
       border += geometryFrame->GetUsedPadding();
       NS_ASSERTION(aLayer.mOrigin == NS_STYLE_BG_ORIGIN_CONTENT,
                    "unknown background-origin value");
     }
-    geometryFrame->ApplySkipSides(border);
     bgPositioningArea.Deflate(border);
   }
 
   nsIFrame* attachedToFrame = aForFrame;
   if (NS_STYLE_BG_ATTACHMENT_FIXED == aLayer.mAttachment) {
     // If it's a fixed background attachment, then the image is placed
     // relative to the viewport, which is the area of the root frame
     // in a screen context or the page content frame in a print context.
@@ -2831,32 +3006,31 @@ ComputeDrawnSizeForBackground(const CSSS
 }
 
 nsBackgroundLayerState
 nsCSSRendering::PrepareBackgroundLayer(nsPresContext* aPresContext,
                                        nsIFrame* aForFrame,
                                        uint32_t aFlags,
                                        const nsRect& aBorderArea,
                                        const nsRect& aBGClipRect,
-                                       const nsStyleBackground& aBackground,
                                        const nsStyleBackground::Layer& aLayer)
 {
   /*
-   * The background properties we need to keep in mind when drawing background
+   * The properties we need to keep in mind when drawing background
    * layers are:
    *
    *   background-image
    *   background-repeat
    *   background-attachment
    *   background-position
    *   background-clip
    *   background-origin
    *   background-size
-   *   background-break (-moz-background-inline-policy)
    *   background-blend-mode
+   *   box-decoration-break
    *
    * (background-color applies to the entire element and not to individual
    * layers, so it is irrelevant to this method.)
    *
    * These properties have the following dependencies upon each other when
    * determining rendering:
    *
    *   background-image
@@ -2869,32 +3043,31 @@ nsCSSRendering::PrepareBackgroundLayer(n
    *     depends upon background-size (for the image's scaled size) and
    *     background-break (for the background positioning area)
    *   background-clip
    *     no dependencies
    *   background-origin
    *     depends upon background-attachment (only in the case where that value
    *     is 'fixed')
    *   background-size
-   *     depends upon background-break (for the background positioning area for
-   *     resolving percentages), background-image (for the image's intrinsic
+   *     depends upon box-decoration-break (for the background positioning area
+   *     for resolving percentages), background-image (for the image's intrinsic
    *     size), background-repeat (if that value is 'round'), and
    *     background-origin (for the background painting area, when
    *     background-repeat is 'round')
-   *   background-break
-   *     depends upon background-origin (specifying how the boxes making up the
-   *     background positioning area are determined)
+   *   box-decoration-break
+   *     no dependencies
    *
    * As a result of only-if dependencies we don't strictly do a topological
    * sort of the above properties when processing, but it's pretty close to one:
    *
    *   background-clip (by caller)
    *   background-image
-   *   background-break, background-origin
-   *   background-attachment (postfix for background-{origin,break} if 'fixed')
+   *   box-decoration-break, background-origin
+   *   background-attachment (postfix for background-origin if 'fixed')
    *   background-size
    *   background-position
    *   background-repeat
    */
 
   uint32_t irFlags = 0;
   if (aFlags & nsCSSRendering::PAINTBG_SYNC_DECODE_IMAGES) {
     irFlags |= nsImageRenderer::FLAG_SYNC_DECODE_IMAGES;
@@ -2910,17 +3083,17 @@ nsCSSRendering::PrepareBackgroundLayer(n
   }
 
   // The frame to which the background is attached
   nsIFrame* attachedToFrame = aForFrame;
   // Compute background origin area relative to aBorderArea now as we may need
   // it to compute the effective image size for a CSS gradient.
   nsRect bgPositioningArea =
     ComputeBackgroundPositioningArea(aPresContext, aForFrame, aBorderArea,
-                                     aBackground, aLayer, &attachedToFrame);
+                                     aLayer, &attachedToFrame);
 
   // For background-attachment:fixed backgrounds, we'll limit the area
   // where the background can be drawn to the viewport.
   nsRect bgClipRect = aBGClipRect;
 
   // Compute the anchor point.
   //
   // relative to aBorderArea.TopLeft() (which is where the top-left
@@ -2980,23 +3153,23 @@ nsCSSRendering::PrepareBackgroundLayer(n
   return state;
 }
 
 nsRect
 nsCSSRendering::GetBackgroundLayerRect(nsPresContext* aPresContext,
                                        nsIFrame* aForFrame,
                                        const nsRect& aBorderArea,
                                        const nsRect& aClipRect,
-                                       const nsStyleBackground& aBackground,
                                        const nsStyleBackground::Layer& aLayer,
                                        uint32_t aFlags)
 {
+  nsRect borderArea = ::BoxDecorationRectForBackground(aForFrame, aBorderArea);
   nsBackgroundLayerState state =
-      PrepareBackgroundLayer(aPresContext, aForFrame, aFlags, aBorderArea,
-                             aClipRect, aBackground, aLayer);
+      PrepareBackgroundLayer(aPresContext, aForFrame, aFlags, borderArea,
+                             aClipRect, aLayer);
   return state.mFillArea;
 }
 
 /* static */ bool
 nsCSSRendering::IsBackgroundImageDecodedForStyleContextAndLayer(
   const nsStyleBackground *aBackground, uint32_t aLayer)
 {
   const nsStyleImage* image = &aBackground->mLayers[aLayer].mImage;
@@ -3024,17 +3197,18 @@ nsCSSRendering::AreAllBackgroundImagesDe
 }
 
 static void
 DrawBorderImage(nsPresContext*       aPresContext,
                 nsRenderingContext&  aRenderingContext,
                 nsIFrame*            aForFrame,
                 const nsRect&        aBorderArea,
                 const nsStyleBorder& aStyleBorder,
-                const nsRect&        aDirtyRect)
+                const nsRect&        aDirtyRect,
+                int                  aSkipSides)
 {
   NS_PRECONDITION(aStyleBorder.IsBorderImageLoaded(),
                   "drawing border image that isn't successfully loaded");
 
   if (aDirtyRect.IsEmpty())
     return;
 
   nsImageRenderer renderer(aForFrame, &aStyleBorder.mBorderImageSource, 0);
@@ -3046,20 +3220,49 @@ DrawBorderImage(nsPresContext*       aPr
   // different style, they'll potentially have the wrong size for the
   // border too.
   aForFrame->AssociateImage(aStyleBorder.mBorderImageSource, aPresContext);
 
   if (!renderer.PrepareImage()) {
     return;
   }
 
+  // NOTE: no Save() yet, we do that later by calling autoSR.EnsureSaved()
+  // in case we need it.
+  gfxContextAutoSaveRestore autoSR;
+
   // Determine the border image area, which by default corresponds to the
   // border box but can be modified by 'border-image-outset'.
-  nsRect borderImgArea(aBorderArea);
-  borderImgArea.Inflate(aStyleBorder.GetImageOutset());
+  // Note that 'border-radius' do not apply to 'border-image' borders per
+  // <http://dev.w3.org/csswg/css-backgrounds/#corner-clipping>.
+  nsRect borderImgArea;
+  nsMargin borderWidths(aStyleBorder.GetComputedBorder());
+  nsMargin imageOutset(aStyleBorder.GetImageOutset());
+  if (::IsBoxDecorationSlice(aStyleBorder) && aSkipSides != 0) {
+    borderImgArea =
+      ::BoxDecorationRectForBorder(aForFrame, aBorderArea, &aStyleBorder);
+    if (borderImgArea.IsEqualEdges(aBorderArea)) {
+      // No need for a clip, just skip the sides we don't want.
+      ::ApplySkipSides(aSkipSides, &borderWidths);
+      ::ApplySkipSides(aSkipSides, &imageOutset);
+      borderImgArea.Inflate(imageOutset);
+    } else {
+      // We're drawing borders around the joined continuation boxes so we need
+      // to clip that to the slice that we want for this frame.
+      borderImgArea.Inflate(imageOutset);
+      ::ApplySkipSides(aSkipSides, &imageOutset);
+      nsRect clip = aBorderArea;
+      clip.Inflate(imageOutset);
+      autoSR.EnsureSaved(aRenderingContext.ThebesContext());
+      aRenderingContext.IntersectClip(clip);
+    }
+  } else {
+    borderImgArea = aBorderArea;
+    borderImgArea.Inflate(imageOutset);
+  }
 
   // Calculate the image size used to compute slice points.
   CSSSizeOrRatio intrinsicSize = renderer.ComputeIntrinsicSize();
   nsSize imageSize = nsImageRenderer::ComputeConcreteSize(CSSSizeOrRatio(),
                                                           intrinsicSize,
                                                           borderImgArea.Size());
   renderer.SetPreferredSize(intrinsicSize, imageSize);
 
@@ -3088,17 +3291,16 @@ DrawBorderImage(nsPresContext*       aPr
         break;
     }
     if (value < 0)
       value = 0;
     if (value > imgDimension)
       value = imgDimension;
     slice.Side(s) = value;
 
-    nsMargin borderWidths(aStyleBorder.GetComputedBorder());
     coord = aStyleBorder.mBorderImageWidth.Get(s);
     switch (coord.GetUnit()) {
       case eStyleUnit_Coord: // absolute dimension
         value = coord.GetCoordValue();
         break;
       case eStyleUnit_Percent:
         value = coord.GetPercentValue() * borderDimension;
         break;
@@ -4930,20 +5132,18 @@ nsContextBoxBlur::GetContext()
 
 /* static */ nsMargin
 nsContextBoxBlur::GetBlurRadiusMargin(nscoord aBlurRadius,
                                       int32_t aAppUnitsPerDevPixel)
 {
   gfxIntSize blurRadius = ComputeBlurRadius(aBlurRadius, aAppUnitsPerDevPixel);
 
   nsMargin result;
-  result.top    = blurRadius.height * aAppUnitsPerDevPixel;
-  result.right  = blurRadius.width  * aAppUnitsPerDevPixel;
-  result.bottom = blurRadius.height * aAppUnitsPerDevPixel;
-  result.left   = blurRadius.width  * aAppUnitsPerDevPixel;
+  result.top = result.bottom = blurRadius.height * aAppUnitsPerDevPixel;
+  result.left = result.right = blurRadius.width  * aAppUnitsPerDevPixel;
   return result;
 }
 
 /* static */ void
 nsContextBoxBlur::BlurRectangle(gfxContext* aDestinationCtx,
                                 const nsRect& aRect,
                                 int32_t aAppUnitsPerDevPixel,
                                 gfxCornerSizes* aCornerRadii,
--- a/layout/base/nsCSSRendering.h
+++ b/layout/base/nsCSSRendering.h
@@ -451,27 +451,25 @@ struct nsCSSRendering {
                            nsIFrame* aFrame,
                            bool& aDrawBackgroundImage,
                            bool& aDrawBackgroundColor);
 
   static nsRect
   ComputeBackgroundPositioningArea(nsPresContext* aPresContext,
                                    nsIFrame* aForFrame,
                                    const nsRect& aBorderArea,
-                                   const nsStyleBackground& aBackground,
                                    const nsStyleBackground::Layer& aLayer,
                                    nsIFrame** aAttachedToFrame);
 
   static nsBackgroundLayerState
   PrepareBackgroundLayer(nsPresContext* aPresContext,
                          nsIFrame* aForFrame,
                          uint32_t aFlags,
                          const nsRect& aBorderArea,
                          const nsRect& aBGClipRect,
-                         const nsStyleBackground& aBackground,
                          const nsStyleBackground::Layer& aLayer);
 
   /**
    * Render the background for an element using css rendering rules
    * for backgrounds.
    */
   enum {
     /**
@@ -537,17 +535,16 @@ struct nsCSSRendering {
    * Returns the rectangle covered by the given background layer image, taking
    * into account background positioning, sizing, and repetition, but not
    * clipping.
    */
   static nsRect GetBackgroundLayerRect(nsPresContext* aPresContext,
                                        nsIFrame* aForFrame,
                                        const nsRect& aBorderArea,
                                        const nsRect& aClipRect,
-                                       const nsStyleBackground& aBackground,
                                        const nsStyleBackground::Layer& aLayer,
                                        uint32_t aFlags);
 
   /**
    * Checks if image in layer aLayer of aBackground is currently decoded.
    */
   static bool IsBackgroundImageDecodedForStyleContextAndLayer(
     const nsStyleBackground *aBackground, uint32_t aLayer);
--- a/layout/base/nsCSSRenderingBorders.cpp
+++ b/layout/base/nsCSSRenderingBorders.cpp
@@ -115,27 +115,25 @@ typedef enum {
 nsCSSBorderRenderer::nsCSSBorderRenderer(int32_t aAppUnitsPerPixel,
                                          gfxContext* aDestContext,
                                          gfxRect& aOuterRect,
                                          const uint8_t* aBorderStyles,
                                          const gfxFloat* aBorderWidths,
                                          gfxCornerSizes& aBorderRadii,
                                          const nscolor* aBorderColors,
                                          nsBorderColors* const* aCompositeColors,
-                                         int aSkipSides,
                                          nscolor aBackgroundColor)
   : mContext(aDestContext),
     mOuterRect(aOuterRect),
     mBorderStyles(aBorderStyles),
     mBorderWidths(aBorderWidths),
     mBorderRadii(aBorderRadii),
     mBorderColors(aBorderColors),
     mCompositeColors(aCompositeColors),
     mAUPP(aAppUnitsPerPixel),
-    mSkipSides(aSkipSides),
     mBackgroundColor(aBackgroundColor)
 {
   if (!mCompositeColors) {
     static nsBorderColors * const noColors[4] = { nullptr };
     mCompositeColors = &noColors[0];
   }
 
   mInnerRect = mOuterRect;
--- a/layout/base/nsCSSRenderingBorders.h
+++ b/layout/base/nsCSSRenderingBorders.h
@@ -74,17 +74,16 @@ struct nsCSSBorderRenderer {
   nsCSSBorderRenderer(int32_t aAppUnitsPerPixel,
                       gfxContext* aDestContext,
                       gfxRect& aOuterRect,
                       const uint8_t* aBorderStyles,
                       const gfxFloat* aBorderWidths,
                       gfxCornerSizes& aBorderRadii,
                       const nscolor* aBorderColors,
                       nsBorderColors* const* aCompositeColors,
-                      int aSkipSides,
                       nscolor aBackgroundColor);
 
   gfxCornerSizes mBorderCornerDimensions;
 
   // destination context
   gfxContext* mContext;
 
   // the rectangle of the outside and the inside of the border
@@ -100,18 +99,17 @@ struct nsCSSBorderRenderer {
 
   // colors
   const nscolor* mBorderColors;
   nsBorderColors* const* mCompositeColors;
 
   // core app units per pixel
   int32_t mAUPP;
 
-  // misc -- which sides to skip, the background color
-  int mSkipSides;
+  // the background color
   nscolor mBackgroundColor;
 
   // calculated values
   bool mOneUnitBorder;
   bool mNoBorderRadius;
   bool mAvoidStroke;
 
   // For all the sides in the bitmask, would they be rendered
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -1929,24 +1929,18 @@ nsDisplayBackgroundImage::IsSingleFixedP
   uint32_t flags = aBuilder->GetBackgroundPaintFlags();
   nsRect borderArea = nsRect(ToReferenceFrame(), mFrame->GetSize());
   const nsStyleBackground::Layer &layer = mBackgroundStyle->mLayers[mLayer];
 
   if (layer.mAttachment != NS_STYLE_BG_ATTACHMENT_FIXED)
     return false;
 
   nsBackgroundLayerState state =
-    nsCSSRendering::PrepareBackgroundLayer(presContext,
-                                           mFrame,
-                                           flags,
-                                           borderArea,
-                                           aClipRect,
-                                           *mBackgroundStyle,
-                                           layer);
-
+    nsCSSRendering::PrepareBackgroundLayer(presContext, mFrame, flags,
+                                           borderArea, aClipRect, layer);
   nsImageRenderer* imageRenderer = &state.mImageRenderer;
   // We only care about images here, not gradients.
   if (!imageRenderer->IsRasterImage())
     return false;
 
   int32_t appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
   *aDestRect = nsLayoutUtils::RectToGfxRect(state.mFillArea, appUnitsPerDevPixel);
 
@@ -1969,24 +1963,18 @@ nsDisplayBackgroundImage::TryOptimizeToI
     return false;
   }
   nscoord radii[8];
   if (mFrame->GetBorderRadii(radii)) {
     return false;
   }
 
   nsBackgroundLayerState state =
-    nsCSSRendering::PrepareBackgroundLayer(presContext,
-                                           mFrame,
-                                           flags,
-                                           borderArea,
-                                           borderArea,
-                                           *mBackgroundStyle,
-                                           layer);
-
+    nsCSSRendering::PrepareBackgroundLayer(presContext, mFrame, flags,
+                                           borderArea, borderArea, layer);
   nsImageRenderer* imageRenderer = &state.mImageRenderer;
   // We only care about images here, not gradients.
   if (!imageRenderer->IsRasterImage())
     return false;
 
   nsRefPtr<ImageContainer> imageContainer = imageRenderer->GetContainer(aManager);
   // Image is not ready to be made into a layer yet
   if (!imageContainer)
@@ -2189,22 +2177,23 @@ nsDisplayBackgroundImage::GetOpaqueRegio
   *aSnap = false;
 
   if (!mBackgroundStyle)
     return result;
 
 
   *aSnap = true;
 
-  // For policies other than EACH_BOX, don't try to optimize here, since
+  // For NS_STYLE_BOX_DECORATION_BREAK_SLICE, don't try to optimize here, since
   // this could easily lead to O(N^2) behavior inside InlineBackgroundData,
   // which expects frames to be sent to it in content order, not reverse
   // content order which we'll produce here.
   // Of course, if there's only one frame in the flow, it doesn't matter.
-  if (mBackgroundStyle->mBackgroundInlinePolicy == NS_STYLE_BG_INLINE_POLICY_EACH_BOX ||
+  if (mFrame->StyleBorder()->mBoxDecorationBreak ==
+        NS_STYLE_BOX_DECORATION_BREAK_CLONE ||
       (!mFrame->GetPrevContinuation() && !mFrame->GetNextContinuation())) {
     const nsStyleBackground::Layer& layer = mBackgroundStyle->mLayers[mLayer];
     if (layer.mImage.IsOpaque() && layer.mBlendMode == NS_STYLE_BLEND_NORMAL) {
       nsPresContext* presContext = mFrame->PresContext();
       result = GetInsideClipRegion(this, presContext, layer.mClip, mBounds, aSnap);
     }
   }
 
@@ -2242,17 +2231,17 @@ nsDisplayBackgroundImage::GetPositioning
 {
   if (!mBackgroundStyle) {
     return nsRect();
   }
   nsIFrame* attachedToFrame;
   return nsCSSRendering::ComputeBackgroundPositioningArea(
       mFrame->PresContext(), mFrame,
       nsRect(ToReferenceFrame(), mFrame->GetSize()),
-      *mBackgroundStyle, mBackgroundStyle->mLayers[mLayer],
+      mBackgroundStyle->mLayers[mLayer],
       &attachedToFrame) + ToReferenceFrame();
 }
 
 bool
 nsDisplayBackgroundImage::RenderingMightDependOnPositioningAreaSizeChange()
 {
   if (!mBackgroundStyle)
     return false;
@@ -2356,18 +2345,17 @@ nsDisplayBackgroundImage::GetBoundsInter
   nsRect borderBox = nsRect(ToReferenceFrame(), mFrame->GetSize());
   nsRect clipRect = borderBox;
   if (mFrame->GetType() == nsGkAtoms::canvasFrame) {
     nsCanvasFrame* frame = static_cast<nsCanvasFrame*>(mFrame);
     clipRect = frame->CanvasArea() + ToReferenceFrame();
   }
   const nsStyleBackground::Layer& layer = mBackgroundStyle->mLayers[mLayer];
   return nsCSSRendering::GetBackgroundLayerRect(presContext, mFrame,
-                                                borderBox, clipRect,
-                                                *mBackgroundStyle, layer,
+                                                borderBox, clipRect, layer,
                                                 aBuilder->GetBackgroundPaintFlags());
 }
 
 uint32_t
 nsDisplayBackgroundImage::GetPerFrameKey()
 {
   return (mLayer << nsDisplayItem::TYPE_BITS) |
     nsDisplayItem::GetPerFrameKey();
@@ -2834,21 +2822,18 @@ nsDisplayBoxShadowOuter::Paint(nsDisplay
   nsPoint offset = ToReferenceFrame();
   nsRect borderRect = mFrame->VisualBorderRectRelativeToSelf() + offset;
   nsPresContext* presContext = mFrame->PresContext();
   nsAutoTArray<nsRect,10> rects;
   ComputeDisjointRectangles(mVisibleRegion, &rects);
 
   PROFILER_LABEL("nsDisplayBoxShadowOuter", "Paint");
   for (uint32_t i = 0; i < rects.Length(); ++i) {
-    aCtx->PushState();
-    aCtx->IntersectClip(rects[i]);
     nsCSSRendering::PaintBoxShadowOuter(presContext, *aCtx, mFrame,
                                         borderRect, rects[i], mOpacity);
-    aCtx->PopState();
   }
 }
 
 nsRect
 nsDisplayBoxShadowOuter::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) {
   *aSnap = false;
   return mBounds;
 }
--- a/layout/generic/crashtests/383089-1.html
+++ b/layout/generic/crashtests/383089-1.html
@@ -73,14 +73,14 @@ function foo()
 </style>
 
 </head><body onload="setTimeout(olo, 30);">
 
 <br style="overflow: visible;" id="br1">
 <br style="clear: none;" id="br2">
 <br style="height: auto; clear: both; width: auto;" id="br3">
 <br style="position: static;" id="br4">
-<br style="background: yellow none repeat scroll 0% 0%; background-clip: initial; background-origin: initial; -moz-background-inline-policy: initial; display: inline;" id="br5">
+<br style="background: yellow none repeat scroll 0% 0%; background-clip: initial; background-origin: initial; display: inline;" id="br5">
 <br style="width: 1px; visibility: visible;" id="br6">
 <br style="color: black; width: 2px; display: table-cell;" id="br7">
 <table border="1"><tbody><tr style="display: list-item;" id="tableRow"><td>x</td></tr></tbody></table>
 
 </body></html>
--- a/layout/generic/nsContainerFrame.cpp
+++ b/layout/generic/nsContainerFrame.cpp
@@ -844,30 +844,52 @@ nsContainerFrame::DoInlineIntrinsicWidth
 
   // This goes at the beginning no matter how things are broken and how
   // messy the bidi situations are, since per CSS2.1 section 8.6
   // (implemented in bug 328168), the startSide border is always on the
   // first line.
   // This frame is a first-in-flow, but it might have a previous bidi
   // continuation, in which case that continuation should handle the startSide
   // border.
+  // For box-decoration-break:clone we setup clonePBM = startPBM + endPBM and
+  // add that to each line.  For box-decoration-break:slice clonePBM is zero.
+  nscoord clonePBM = 0; // PBM = PaddingBorderMargin
+  const bool sliceBreak =
+    styleBorder->mBoxDecorationBreak == NS_STYLE_BOX_DECORATION_BREAK_SLICE;
   if (!GetPrevContinuation()) {
-    aData->currentLine +=
+    nscoord startPBM =
       // clamp negative calc() to 0
       std::max(GetCoord(stylePadding->mPadding.Get(startSide), 0), 0) +
       styleBorder->GetComputedBorderWidth(startSide) +
       GetCoord(styleMargin->mMargin.Get(startSide), 0);
+    if (MOZ_LIKELY(sliceBreak)) {
+      aData->currentLine += startPBM;
+    } else {
+      clonePBM = startPBM;
+    }
+  }
+
+  nscoord endPBM =
+    // clamp negative calc() to 0
+    std::max(GetCoord(stylePadding->mPadding.Get(endSide), 0), 0) +
+    styleBorder->GetComputedBorderWidth(endSide) +
+    GetCoord(styleMargin->mMargin.Get(endSide), 0);
+  if (MOZ_UNLIKELY(!sliceBreak)) {
+    clonePBM += endPBM;
   }
 
   const nsLineList_iterator* savedLine = aData->line;
   nsIFrame* const savedLineContainer = aData->lineContainer;
 
   nsContainerFrame *lastInFlow;
   for (nsContainerFrame *nif = this; nif;
        nif = static_cast<nsContainerFrame*>(nif->GetNextInFlow())) {
+    if (aData->currentLine == 0) {
+      aData->currentLine = clonePBM;
+    }
     for (nsIFrame *kid = nif->mFrames.FirstChild(); kid;
          kid = kid->GetNextSibling()) {
       if (aType == nsLayoutUtils::MIN_WIDTH)
         kid->AddInlineMinWidth(aRenderingContext,
                                static_cast<InlineMinWidthData*>(aData));
       else
         kid->AddInlinePrefWidth(aRenderingContext,
                                 static_cast<InlinePrefWidthData*>(aData));
@@ -886,22 +908,18 @@ nsContainerFrame::DoInlineIntrinsicWidth
 
   // This goes at the end no matter how things are broken and how
   // messy the bidi situations are, since per CSS2.1 section 8.6
   // (implemented in bug 328168), the endSide border is always on the
   // last line.
   // We reached the last-in-flow, but it might have a next bidi
   // continuation, in which case that continuation should handle
   // the endSide border.
-  if (!lastInFlow->GetNextContinuation()) {
-    aData->currentLine +=
-      // clamp negative calc() to 0
-      std::max(GetCoord(stylePadding->mPadding.Get(endSide), 0), 0) +
-      styleBorder->GetComputedBorderWidth(endSide) +
-      GetCoord(styleMargin->mMargin.Get(endSide), 0);
+  if (MOZ_LIKELY(!lastInFlow->GetNextContinuation() && sliceBreak)) {
+    aData->currentLine += endPBM;
   }
 }
 
 /* virtual */ nsSize
 nsContainerFrame::ComputeAutoSize(nsRenderingContext *aRenderingContext,
                                   nsSize aCBSize, nscoord aAvailableWidth,
                                   nsSize aMargin, nsSize aBorder,
                                   nsSize aPadding, bool aShrinkWrap)
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -948,16 +948,21 @@ nsIFrame::GetUsedPadding() const
     NS_ASSERTION(hasPadding, "We should have padding here! (out of memory?)");
   }
   return padding;
 }
 
 int
 nsIFrame::GetSkipSides(const nsHTMLReflowState* aReflowState) const
 {
+  if (MOZ_UNLIKELY(StyleBorder()->mBoxDecorationBreak ==
+                     NS_STYLE_BOX_DECORATION_BREAK_CLONE)) {
+    return 0;
+  }
+
   // Convert the logical skip sides to physical sides using the frame's
   // writing mode
   WritingMode writingMode = GetWritingMode();
   int logicalSkip = GetLogicalSkipSides(aReflowState);
   int skip = 0;
 
   if (logicalSkip & LOGICAL_SIDE_B_START) {
     if (writingMode.IsVertical()) {
@@ -1272,34 +1277,42 @@ nsIFrame::OutsetBorderRadii(nscoord aRad
     if (aRadii[hc1] > 0)
       aRadii[hc1] += offset;
     if (aRadii[hc2] > 0)
       aRadii[hc2] += offset;
   }
 }
 
 /* virtual */ bool
-nsIFrame::GetBorderRadii(nscoord aRadii[8]) const
+nsIFrame::GetBorderRadii(const nsSize& aFrameSize, const nsSize& aBorderArea,
+                         int aSkipSides, nscoord aRadii[8]) const
 {
   if (IsThemed()) {
     // When we're themed, the native theme code draws the border and
     // background, and therefore it doesn't make sense to tell other
     // code that's interested in border-radius that we have any radii.
     //
     // In an ideal world, we might have a way for the them to tell us an
     // border radius, but since we don't, we're better off assuming
     // zero.
     NS_FOR_CSS_HALF_CORNERS(corner) {
       aRadii[corner] = 0;
     }
     return false;
   }
-  nsSize size = GetSize();
-  return ComputeBorderRadii(StyleBorder()->mBorderRadius, size, size,
-                            GetSkipSides(), aRadii);
+  return ComputeBorderRadii(StyleBorder()->mBorderRadius,
+                            aFrameSize, aBorderArea,
+                            aSkipSides, aRadii);
+}
+
+bool
+nsIFrame::GetBorderRadii(nscoord aRadii[8]) const
+{
+  nsSize sz = GetSize();
+  return GetBorderRadii(sz, sz, GetSkipSides(), aRadii);
 }
 
 bool
 nsIFrame::GetPaddingBoxBorderRadii(nscoord aRadii[8]) const
 {
   if (!GetBorderRadii(aRadii))
     return false;
   InsetBorderRadii(aRadii, GetUsedBorder());
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -4361,20 +4361,25 @@ ReduceRadii(nscoord aXBorder, nscoord aY
  * Implement an override for nsIFrame::GetBorderRadii to ensure that
  * the clipping region for the border radius does not clip the scrollbars.
  *
  * In other words, we require that the border radius be reduced until the
  * inner border radius at the inner edge of the border is 0 wherever we
  * have scrollbars.
  */
 bool
-ScrollFrameHelper::GetBorderRadii(nscoord aRadii[8]) const
+ScrollFrameHelper::GetBorderRadii(const nsSize& aFrameSize,
+                                  const nsSize& aBorderArea,
+                                  int aSkipSides,
+                                  nscoord aRadii[8]) const
 {
-  if (!mOuter->nsContainerFrame::GetBorderRadii(aRadii))
+  if (!mOuter->nsContainerFrame::GetBorderRadii(aFrameSize, aBorderArea,
+                                                aSkipSides, aRadii)) {
     return false;
+  }
 
   // Since we can use GetActualScrollbarSizes (rather than
   // GetDesiredScrollbarSizes) since this doesn't affect reflow, we
   // probably should.
   nsMargin sb = GetActualScrollbarSizes();
   nsMargin border = mOuter->GetUsedBorder();
 
   if (sb.left > 0 || sb.top > 0) {
--- a/layout/generic/nsGfxScrollFrame.h
+++ b/layout/generic/nsGfxScrollFrame.h
@@ -66,17 +66,18 @@ public:
                         const nsDisplayListSet& aLists);
 
   void AppendScrollPartsTo(nsDisplayListBuilder*   aBuilder,
                            const nsRect&           aDirtyRect,
                            const nsDisplayListSet& aLists,
                            bool&                   aCreateLayer,
                            bool                    aPositioned);
 
-  bool GetBorderRadii(nscoord aRadii[8]) const;
+  bool GetBorderRadii(const nsSize& aFrameSize, const nsSize& aBorderArea,
+                      int aSkipSides, nscoord aRadii[8]) const;
 
   // nsIReflowCallback
   virtual bool ReflowFinished() MOZ_OVERRIDE;
   virtual void ReflowCallbackCanceled() MOZ_OVERRIDE;
 
   /**
    * @note This method might destroy the frame, pres shell and other objects.
    * Called when the 'curpos' attribute on one of the scrollbars changes.
@@ -466,18 +467,19 @@ public:
                                nsHTMLReflowMetrics* aMetrics,
                                bool aFirstPass);
   nsresult ReflowContents(ScrollReflowState* aState,
                           const nsHTMLReflowMetrics& aDesiredSize);
   void PlaceScrollArea(const ScrollReflowState& aState,
                        const nsPoint& aScrollPosition);
   nscoord GetIntrinsicVScrollbarWidth(nsRenderingContext *aRenderingContext);
 
-  virtual bool GetBorderRadii(nscoord aRadii[8]) const MOZ_OVERRIDE {
-    return mHelper.GetBorderRadii(aRadii);
+  virtual bool GetBorderRadii(const nsSize& aFrameSize, const nsSize& aBorderArea,
+                              int aSkipSides, nscoord aRadii[8]) const MOZ_OVERRIDE {
+    return mHelper.GetBorderRadii(aFrameSize, aBorderArea, aSkipSides, aRadii);
   }
 
   virtual nscoord GetMinWidth(nsRenderingContext *aRenderingContext) MOZ_OVERRIDE;
   virtual nscoord GetPrefWidth(nsRenderingContext *aRenderingContext) MOZ_OVERRIDE;
   virtual nsresult GetPadding(nsMargin& aPadding) MOZ_OVERRIDE;
   virtual bool IsCollapsed() MOZ_OVERRIDE;
   
   virtual nsresult Reflow(nsPresContext*           aPresContext,
@@ -803,18 +805,19 @@ public:
   virtual nsSize GetMinSize(nsBoxLayoutState& aBoxLayoutState) MOZ_OVERRIDE;
   virtual nsSize GetPrefSize(nsBoxLayoutState& aBoxLayoutState) MOZ_OVERRIDE;
   virtual nsSize GetMaxSize(nsBoxLayoutState& aBoxLayoutState) MOZ_OVERRIDE;
   virtual nscoord GetBoxAscent(nsBoxLayoutState& aBoxLayoutState) MOZ_OVERRIDE;
 
   NS_IMETHOD DoLayout(nsBoxLayoutState& aBoxLayoutState) MOZ_OVERRIDE;
   virtual nsresult GetPadding(nsMargin& aPadding) MOZ_OVERRIDE;
 
-  virtual bool GetBorderRadii(nscoord aRadii[8]) const MOZ_OVERRIDE {
-    return mHelper.GetBorderRadii(aRadii);
+  virtual bool GetBorderRadii(const nsSize& aFrameSize, const nsSize& aBorderArea,
+                              int aSkipSides, nscoord aRadii[8]) const MOZ_OVERRIDE {
+    return mHelper.GetBorderRadii(aFrameSize, aBorderArea, aSkipSides, aRadii);
   }
 
   nsresult Layout(nsBoxLayoutState& aState);
   void LayoutScrollArea(nsBoxLayoutState& aState, const nsPoint& aScrollPosition);
 
   static bool AddRemoveScrollbar(bool& aHasScrollbar, 
                                    nscoord& aXY, 
                                    nscoord& aSize, 
--- a/layout/generic/nsIFrame.h
+++ b/layout/generic/nsIFrame.h
@@ -1037,22 +1037,26 @@ public:
    * radii into zero, and OutsetBorderRadii does not inflate zero radii.
    * Therefore, callers should always inset or outset directly from the
    * original value coming from style.
    */
   static void InsetBorderRadii(nscoord aRadii[8], const nsMargin &aOffsets);
   static void OutsetBorderRadii(nscoord aRadii[8], const nsMargin &aOffsets);
 
   /**
-   * Fill in border radii for this frame.  Return whether any are
-   * nonzero.
-   *
+   * Fill in border radii for this frame.  Return whether any are nonzero.
    * Indices into aRadii are the NS_CORNER_* constants in nsStyleConsts.h
+   * aSkipSides is a union of SIDE_BIT_LEFT/RIGHT/TOP/BOTTOM bits that says
+   * which side(s) to skip.
    */
-  virtual bool GetBorderRadii(nscoord aRadii[8]) const;
+  virtual bool GetBorderRadii(const nsSize& aFrameSize,
+                              const nsSize& aBorderArea,
+                              int aSkipSides,
+                              nscoord aRadii[8]) const;
+  bool GetBorderRadii(nscoord aRadii[8]) const;
 
   bool GetPaddingBoxBorderRadii(nscoord aRadii[8]) const;
   bool GetContentBoxBorderRadii(nscoord aRadii[8]) const;
 
   /**
    * Get the position of the frame's baseline, relative to the top of
    * the frame (its top border edge).  Only valid when Reflow is not
    * needed.
--- a/layout/generic/nsImageFrame.cpp
+++ b/layout/generic/nsImageFrame.cpp
@@ -1777,16 +1777,20 @@ nsImageFrame::List(FILE* out, const char
   }
   fprintf_stderr(out, "%s\n", str.get());
 }
 #endif
 
 int
 nsImageFrame::GetLogicalSkipSides(const nsHTMLReflowState* aReflowState) const
 {
+  if (MOZ_UNLIKELY(StyleBorder()->mBoxDecorationBreak ==
+                     NS_STYLE_BOX_DECORATION_BREAK_CLONE)) {
+    return 0;
+  }
   int skip = 0;
   if (nullptr != GetPrevInFlow()) {
     skip |= LOGICAL_SIDE_B_START;
   }
   if (nullptr != GetNextInFlow()) {
     skip |= LOGICAL_SIDE_B_END;
   }
   return skip;
--- a/layout/generic/nsInlineFrame.cpp
+++ b/layout/generic/nsInlineFrame.cpp
@@ -110,17 +110,21 @@ nsInlineFrame::IsSelfEmpty()
     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) {
-    if (GetStateBits() & NS_FRAME_PART_OF_IBSPLIT) {
+    // 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;
       }
@@ -486,19 +490,25 @@ nsInlineFrame::ReflowFrames(nsPresContex
   nsresult rv = NS_OK;
   aStatus = NS_FRAME_COMPLETE;
 
   nsLineLayout* lineLayout = aReflowState.mLineLayout;
   bool inFirstLine = aReflowState.mLineLayout->GetInFirstLine();
   RestyleManager* restyleManager = aPresContext->RestyleManager();
   WritingMode wm = aReflowState.GetWritingMode();
   nscoord startEdge = 0;
+  const bool boxDecorationBreakClone =
+    MOZ_UNLIKELY(StyleBorder()->mBoxDecorationBreak ==
+                   NS_STYLE_BOX_DECORATION_BREAK_CLONE);
   // Don't offset by our start borderpadding if we have a prev continuation or
-  // if we're in a part of an {ib} split other than the first one.
-  if (!GetPrevContinuation() && !FrameIsNonFirstInIBSplit()) {
+  // if we're in a part of an {ib} split other than the first one. For
+  // box-decoration-break:clone we always offset our start since all
+  // continuations have border/padding.
+  if ((!GetPrevContinuation() && !FrameIsNonFirstInIBSplit()) ||
+      boxDecorationBreakClone) {
     startEdge = aReflowState.ComputedLogicalBorderPadding().IStart(wm);
   }
   nscoord availableISize = aReflowState.AvailableISize();
   NS_ASSERTION(availableISize != NS_UNCONSTRAINEDSIZE,
                "should no longer use available widths");
   // Subtract off inline axis border+padding from availableISize
   availableISize -= startEdge;
   availableISize -= aReflowState.ComputedLogicalBorderPadding().IEnd(wm);
@@ -649,31 +659,35 @@ nsInlineFrame::ReflowFrames(nsPresContex
   // that are empty we force to empty so that things like collapsed
   // whitespace in an inline element don't affect the line-height.
   aMetrics.ISize() = lineLayout->EndSpan(this);
 
   // Compute final width.
 
   // Make sure to not include our start border and padding if we have a prev
   // continuation or if we're in a part of an {ib} split other than the first
-  // one.
-  if (!GetPrevContinuation() && !FrameIsNonFirstInIBSplit()) {
+  // one.  For box-decoration-break:clone we always include our start border
+  // and padding since all continuations have them.
+  if ((!GetPrevContinuation() && !FrameIsNonFirstInIBSplit()) ||
+      boxDecorationBreakClone) {
     aMetrics.ISize() += aReflowState.ComputedLogicalBorderPadding().IStart(wm);
   }
 
   /*
    * We want to only apply the end border and padding if we're the last
    * continuation and either not in an {ib} split or the last part of it.  To
    * be the last continuation we have to be complete (so that we won't get a
    * next-in-flow) and have no non-fluid continuations on our continuation
-   * chain.
+   * chain.  For box-decoration-break:clone we always apply the end border and
+   * padding since all continuations have them.
    */
-  if (NS_FRAME_IS_COMPLETE(aStatus) &&
-      !LastInFlow()->GetNextContinuation() &&
-      !FrameIsNonLastInIBSplit()) {
+  if ((NS_FRAME_IS_COMPLETE(aStatus) &&
+       !LastInFlow()->GetNextContinuation() &&
+       !FrameIsNonLastInIBSplit()) ||
+      boxDecorationBreakClone) {
     aMetrics.Width() += aReflowState.ComputedLogicalBorderPadding().IEnd(wm);
   }
 
   nsRefPtr<nsFontMetrics> fm;
   float inflation = nsLayoutUtils::FontSizeInflationFor(this);
   nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm), inflation);
   aReflowState.rendContext->SetFont(fm);
 
@@ -867,16 +881,21 @@ nsInlineFrame::PushFrames(nsPresContext*
 }
 
 
 //////////////////////////////////////////////////////////////////////
 
 int
 nsInlineFrame::GetLogicalSkipSides(const nsHTMLReflowState* aReflowState) const
 {
+  if (MOZ_UNLIKELY(StyleBorder()->mBoxDecorationBreak ==
+                     NS_STYLE_BOX_DECORATION_BREAK_CLONE)) {
+    return 0;
+  }
+
   int skip = 0;
   if (!IsFirst()) {
     nsInlineFrame* prev = (nsInlineFrame*) GetPrevContinuation();
     if ((GetStateBits() & NS_INLINE_FRAME_BIDI_VISUAL_STATE_IS_SET) ||
         (prev && (prev->mRect.height || prev->mRect.width))) {
       // Prev continuation is not empty therefore we don't render our start
       // border edge.
       skip |= LOGICAL_SIDE_I_START;
--- a/layout/generic/nsLineLayout.cpp
+++ b/layout/generic/nsLineLayout.cpp
@@ -1071,19 +1071,22 @@ nsLineLayout::ApplyStartMargin(PerFrameD
   WritingMode frameWM = pfd->mFrame->GetWritingMode();
   WritingMode lineWM = mRootSpan->mWritingMode;
 
   // Only apply start-margin on the first-in flow for inline frames,
   // and make sure to not apply it to any inline other than the first
   // in an ib split.  Note that the ib sibling (block-in-inline
   // sibling) annotations only live on the first continuation, but we
   // don't want to apply the start margin for later continuations
-  // anyway.
-  if (pfd->mFrame->GetPrevContinuation() ||
-      pfd->mFrame->FrameIsNonFirstInIBSplit()) {
+  // anyway.  For box-decoration-break:clone we apply the start-margin
+  // on all continuations.
+  if ((pfd->mFrame->GetPrevContinuation() ||
+       pfd->mFrame->FrameIsNonFirstInIBSplit()) &&
+      aReflowState.mStyleBorder->mBoxDecorationBreak ==
+        NS_STYLE_BOX_DECORATION_BREAK_SLICE) {
     // Zero this out so that when we compute the max-element-width of
     // the frame we will properly avoid adding in the starting margin.
     pfd->mMargin.IStart(frameWM) = 0;
   }
   if ((pfd->mFrame->LastInFlow()->GetNextContinuation() ||
       pfd->mFrame->FrameIsNonLastInIBSplit())
     && !pfd->GetFlag(PFD_ISLETTERFRAME)) {
     pfd->mMargin.IEnd(frameWM) = 0;
@@ -1155,25 +1158,30 @@ nsLineLayout::CanPlaceFrame(PerFrameData
    * 1) The frame is not complete (in this case it will get a next-in-flow)
    * 2) The frame is complete but has a non-fluid continuation on its
    *    continuation chain.  Note that if it has a fluid continuation, that
    *    continuation will get destroyed later, so we don't want to drop the
    *    end-margin in that case.
    * 3) The frame is in an {ib} split and is not the last part.
    *
    * However, none of that applies if this is a letter frame (XXXbz why?)
+   *
+   * For box-decoration-break:clone we apply the end margin on all
+   * continuations (that are not letter frames).
    */
   if (pfd->mFrame->GetPrevContinuation() ||
       pfd->mFrame->FrameIsNonFirstInIBSplit()) {
     pfd->mMargin.IStart(frameWM) = 0;
   }
   if ((NS_FRAME_IS_NOT_COMPLETE(aStatus) ||
        pfd->mFrame->LastInFlow()->GetNextContinuation() ||
-       pfd->mFrame->FrameIsNonLastInIBSplit())
-      && !pfd->GetFlag(PFD_ISLETTERFRAME)) {
+       pfd->mFrame->FrameIsNonLastInIBSplit()) &&
+      !pfd->GetFlag(PFD_ISLETTERFRAME) &&
+      pfd->mFrame->StyleBorder()->mBoxDecorationBreak ==
+        NS_STYLE_BOX_DECORATION_BREAK_SLICE) {
     pfd->mMargin.IEnd(frameWM) = 0;
   }
   LogicalMargin usedMargins = pfd->mMargin.ConvertTo(lineWM, frameWM);
   nscoord startMargin = usedMargins.IStart(lineWM);
   nscoord endMargin = usedMargins.IEnd(lineWM);
 
   if (!(lineWM.IsBidiLTR() && frameWM.IsBidiLTR())) {
     pfd->mBounds.IStart(lineWM) += startMargin;
--- a/layout/generic/nsSplittableFrame.cpp
+++ b/layout/generic/nsSplittableFrame.cpp
@@ -248,18 +248,22 @@ nsSplittableFrame::GetEffectiveComputedH
 
 int
 nsSplittableFrame::GetLogicalSkipSides(const nsHTMLReflowState* aReflowState) const
 {
   if (IS_TRUE_OVERFLOW_CONTAINER(this)) {
     return LOGICAL_SIDES_B_BOTH;
   }
 
+  if (MOZ_UNLIKELY(StyleBorder()->mBoxDecorationBreak ==
+                     NS_STYLE_BOX_DECORATION_BREAK_CLONE)) {
+    return 0;
+  }
+
   int skip = 0;
-
   if (GetPrevInFlow()) {
     skip |= LOGICAL_SIDE_B_START;
   }
 
   if (aReflowState) {
     // We're in the midst of reflow right now, so it's possible that we haven't
     // created a nif yet. If our content height is going to exceed our available
     // height, though, then we're going to need a next-in-flow, it just hasn't
deleted file mode 100644
--- a/layout/reftests/backgrounds/background-size-bounding-box.html
+++ /dev/null
@@ -1,36 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-  <title>background-break: bounding-box</title>
-  <style type="text/css">
-@font-face
-{
-  font-family: Ahem;
-  src: url(../fonts/Ahem.ttf);
-}
-
-#outer
-{
-  border: 1px solid black;
-  width: 10em;
-}
-#ahem-lines
-{
-  font-family: Ahem;
-  font-size: 32px;
-  white-space: pre;
-  background-image: url(blue-8x20-green-8x20.png);
-  background-repeat: no-repeat;
-  -moz-background-inline-policy: bounding-box;
-}
-</style>
-</head>
-<body>
-<div id="outer">
-<span id="ahem-lines">      <!-- EOL -->
-        <!-- mix it up for each-box and bounding-box --><!-- EOL -->
-      <!-- EOL -->
-      <!-- EOL -->
-      </span></div>
-</body>
-</html>
rename from layout/reftests/backgrounds/background-size-each-box.html
rename to layout/reftests/backgrounds/background-size-clone.html
--- a/layout/reftests/backgrounds/background-size-each-box.html
+++ b/layout/reftests/backgrounds/background-size-clone.html
@@ -1,12 +1,12 @@
 <!DOCTYPE html>
 <html>
 <head>
-  <title>background-break: each-box</title>
+  <title>box-decoration-break: clone</title>
   <style type="text/css">
 @font-face
 {
   font-family: Ahem;
   src: url(../fonts/Ahem.ttf);
 }
 
 #outer
@@ -16,21 +16,21 @@
 }
 #ahem-lines
 {
   font-family: Ahem;
   font-size: 32px;
   white-space: pre;
   background-image: url(blue-8x20-green-8x20.png);
   background-repeat: no-repeat;
-  -moz-background-inline-policy: each-box;
+  box-decoration-break: clone;
 }
 </style>
 </head>
 <body>
 <div id="outer">
 <span id="ahem-lines">      <!-- EOL -->
-        <!-- mix it up for each-box and bounding-box --><!-- EOL -->
+        <!-- mix it up for clone --><!-- EOL -->
       <!-- EOL -->
       <!-- EOL -->
       </span></div>
 </body>
 </html>
deleted file mode 100644
--- a/layout/reftests/backgrounds/background-size-cover-bounding-box.html
+++ /dev/null
@@ -1,37 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-  <title>background-size: cover; background-break: bounding-box</title>
-  <style type="text/css">
-@font-face
-{
-  font-family: Ahem;
-  src: url(../fonts/Ahem.ttf);
-}
-
-#outer
-{
-  border: 1px solid black;
-  width: 10em;
-}
-#ahem-lines
-{
-  font-family: Ahem;
-  font-size: 32px;
-  white-space: pre;
-  background-image: url(blue-8x20-green-8x20.png);
-  background-repeat: no-repeat;
-  background-size: cover;
-  -moz-background-inline-policy: bounding-box;
-}
-</style>
-</head>
-<body>
-<div id="outer">
-<span id="ahem-lines">      <!-- EOL -->
-        <!-- mix it up for each-box and bounding-box --><!-- EOL -->
-      <!-- EOL -->
-      <!-- EOL -->
-      </span></div>
-</body>
-</html>
rename from layout/reftests/backgrounds/background-size-cover-each-box.html
rename to layout/reftests/backgrounds/background-size-cover-clone.html
--- a/layout/reftests/backgrounds/background-size-cover-each-box.html
+++ b/layout/reftests/backgrounds/background-size-cover-clone.html
@@ -1,12 +1,12 @@
 <!DOCTYPE html>
 <html>
 <head>
-  <title>background-size: cover; background-break: each-box</title>
+  <title>background-size: cover; box-decoration-break: clone</title>
   <style type="text/css">
 @font-face
 {
   font-family: Ahem;
   src: url(../fonts/Ahem.ttf);
 }
 
 #outer
@@ -17,21 +17,21 @@
 #ahem-lines
 {
   font-family: Ahem;
   font-size: 32px;
   white-space: pre;
   background-image: url(blue-8x20-green-8x20.png);
   background-repeat: no-repeat;
   background-size: cover;
-  -moz-background-inline-policy: each-box;
+  box-decoration-break: clone;
 }
 </style>
 </head>
 <body>
 <div id="outer">
 <span id="ahem-lines">      <!-- EOL -->
-        <!-- mix it up for each-box and bounding-box --><!-- EOL -->
+        <!-- mix it up for clone --><!-- EOL -->
       <!-- EOL -->
       <!-- EOL -->
       </span></div>
 </body>
 </html>
rename from layout/reftests/backgrounds/background-size-cover-continuous.html
rename to layout/reftests/backgrounds/background-size-cover-slice.html
--- a/layout/reftests/backgrounds/background-size-cover-continuous.html
+++ b/layout/reftests/backgrounds/background-size-cover-slice.html
@@ -1,12 +1,12 @@
 <!DOCTYPE html>
 <html>
 <head>
-  <title>background-size: cover; background-break: continuous</title>
+  <title>background-size: cover; box-decoration-break: slice</title>
   <style type="text/css">
 @font-face
 {
   font-family: Ahem;
   src: url(../fonts/Ahem.ttf);
 }
 
 #outer
@@ -17,21 +17,21 @@
 #ahem-lines
 {
   font-family: Ahem;
   font-size: 32px;
   white-space: pre;
   background-image: url(blue-8x20-green-8x20.png);
   background-repeat: no-repeat;
   background-size: cover;
-  -moz-background-inline-policy: continuous;
+  box-decoration-break: slice;
 }
 </style>
 </head>
 <body>
 <div id="outer">
 <span id="ahem-lines">      <!-- EOL -->
-        <!-- mix it up for each-box and bounding-box --><!-- EOL -->
+        <!-- mix it up for slice --><!-- EOL -->
       <!-- EOL -->
       <!-- EOL -->
       </span></div>
 </body>
 </html>
rename from layout/reftests/backgrounds/background-size-continuous.html
rename to layout/reftests/backgrounds/background-size-slice.html
--- a/layout/reftests/backgrounds/background-size-continuous.html
+++ b/layout/reftests/backgrounds/background-size-slice.html
@@ -1,12 +1,12 @@
 <!DOCTYPE html>
 <html>
 <head>
-  <title>background-break: continuous</title>
+  <title>box-decoration-break: slice</title>
   <style type="text/css">
 @font-face
 {
   font-family: Ahem;
   src: url(../fonts/Ahem.ttf);
 }
 
 #outer
@@ -16,21 +16,21 @@
 }
 #ahem-lines
 {
   font-family: Ahem;
   font-size: 32px;
   white-space: pre;
   background-image: url(blue-8x20-green-8x20.png);
   background-repeat: no-repeat;
-  -moz-background-inline-policy: continuous;
+  box-decoration-break: slice;
 }
 </style>
 </head>
 <body>
 <div id="outer">
 <span id="ahem-lines">      <!-- EOL -->
-        <!-- mix it up for each-box and bounding-box --><!-- EOL -->
+        <!-- mix it up for slice --><!-- EOL -->
       <!-- EOL -->
       <!-- EOL -->
       </span></div>
 </body>
 </html>
--- a/layout/reftests/backgrounds/reftest.list
+++ b/layout/reftests/backgrounds/reftest.list
@@ -85,29 +85,25 @@ fails-if(smallScreen&&Android) != backgr
 == background-size-contain-clip-border.html background-size-contain-clip-border-ref.html
 == background-size-contain-position-fifty-fifty.html background-size-contain-position-fifty-fifty-ref.html
 == background-size-contain-clip-padding-origin-border.html background-size-contain-clip-padding-origin-border-ref.html
 == background-size-contain-clip-padding-origin-border-padding.html background-size-contain-clip-padding-origin-border-padding-ref.html
 
 skip-if(B2G) == background-layers-1a.html background-layers-1-ref.html # bug 773482
 == background-layers-1b.html background-layers-1-ref.html
 
-# -moz-background-inline-policy is touchy and hard to test due to stretching
-# artifacts and the difficulty of covering exact lines, and its CSS3 analog is
-# on the chopping block at the moment, so just make sure background-size results
-# in a different rendering when present.
-!= background-size-cover-continuous.html background-size-continuous.html
-!= background-size-cover-each-box.html background-size-each-box.html
-!= background-size-cover-bounding-box.html background-size-bounding-box.html
+# box-decoration-break's effect on backgrounds is touchy and hard to test due to stretching
+# artifacts and the difficulty of covering exact lines, so just make sure
+# background-size results in a different rendering when present.
+pref(layout.css.box-decoration-break.enabled,true) != background-size-cover-slice.html background-size-slice.html
+pref(layout.css.box-decoration-break.enabled,true) != background-size-cover-clone.html background-size-clone.html
 
 # ...and make sure each rendering with background-size is different from the
-# others
-!= background-size-cover-continuous.html background-size-cover-each-box.html
-!= background-size-cover-continuous.html background-size-cover-bounding-box.html
-!= background-size-cover-each-box.html background-size-cover-bounding-box.html
+# other
+pref(layout.css.box-decoration-break.enabled,true) != background-size-cover-slice.html background-size-cover-clone.html
 
 == background-size-monster-ch.html background-size-monster-ref.html
 == background-size-monster-cm.html background-size-monster-ref.html
 == background-size-monster-em.html background-size-monster-ref.html
 == background-size-monster-ex.html background-size-monster-ref.html
 == background-size-monster-inches.html background-size-monster-ref.html
 == background-size-monster-mm.html background-size-monster-ref.html
 == background-size-monster-pc.html background-size-monster-ref.html
--- a/layout/reftests/bugs/368020-3-ref.html
+++ b/layout/reftests/bugs/368020-3-ref.html
@@ -1,15 +1,15 @@
 <!DOCTYPE HTML>
 <html>
 <head>
 <title>Testcase, bug 368020</title>
 </head>
 <body style="line-height: 3; width: 500px; height: 250px;">
 
-    <span style="background: url(repeatable-diagonal-gradient.png); background-clip: border-box; background-clip: border; background-origin: padding-box; background-origin: padding; margin: 7px 4px 2px 18px; border: 6px transparent solid; border-width: 2px 10px 15px 2px; -moz-background-inline-policy: continuous; background-inline-policy: continuous;">
+    <span style="background: url(repeatable-diagonal-gradient.png); background-clip: border-box; background-origin: padding-box; margin: 7px 4px 2px 18px; border: 6px transparent solid; border-width: 2px 10px 15px 2px;">
         blah<br>
         blah<br>
         blah
     </span>
 
 </body>
 </html>
--- a/layout/reftests/bugs/368020-3.html
+++ b/layout/reftests/bugs/368020-3.html
@@ -1,15 +1,15 @@
 <!DOCTYPE HTML>
 <html>
 <head>
 <title>Testcase, bug 368020</title>
 </head>
 <body style="line-height: 3; width: 500px; height: 250px;">
 
-    <span style="background: url(repeatable-diagonal-gradient.png); background-clip: padding-box; background-clip: padding; background-origin: content-box; background-origin: content; border: medium transparent solid; border-width: 7px 4px 2px 18px; padding: 2px 2% 3% 2px; -moz-background-inline-policy: continuous; background-inline-policy: continuous;">
+    <span style="background: url(repeatable-diagonal-gradient.png); background-clip: padding-box; background-origin: content-box; border: medium transparent solid; border-width: 7px 4px 2px 18px; padding: 2px 2% 3% 2px;">
         blah<br>
         blah<br>
         blah
     </span>
 
 </body>
 </html>
deleted file mode 100644
--- a/layout/reftests/bugs/368020-4-ref.html
+++ /dev/null
@@ -1,15 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<head>
-<title>Testcase, bug 368020</title>
-</head>
-<body style="line-height: 3; width: 500px; height: 250px;">
-
-    <span style="background: url(repeatable-diagonal-gradient.png); background-clip: border-box; background-clip: border; background-origin: padding-box; background-origin: padding; margin: 7px 4px 2px 18px; border: 6px transparent solid; border-width: 2px 10px 15px 2px; -moz-background-inline-policy: bounding-box; background-inline-policy: bounding-box;">
-        blah<br>
-        blah<br>
-        blah
-    </span>
-
-</body>
-</html>
deleted file mode 100644
--- a/layout/reftests/bugs/368020-4.html
+++ /dev/null
@@ -1,15 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<head>
-<title>Testcase, bug 368020</title>
-</head>
-<body style="line-height: 3; width: 500px; height: 250px;">
-
-    <span style="background: url(repeatable-diagonal-gradient.png); background-clip: padding-box; background-clip: padding; background-origin: content-box; background-origin: content; border: medium transparent solid; border-width: 7px 4px 2px 18px; padding: 2px 2% 3% 2px; -moz-background-inline-policy: bounding-box; background-inline-policy: bounding-box;">
-        blah<br>
-        blah<br>
-        blah
-    </span>
-
-</body>
-</html>
--- a/layout/reftests/bugs/368020-5-ref.html
+++ b/layout/reftests/bugs/368020-5-ref.html
@@ -1,15 +1,15 @@
 <!DOCTYPE HTML>
 <html>
 <head>
 <title>Testcase, bug 368020</title>
 </head>
 <body style="line-height: 3; width: 500px; height: 250px;">
 
-    <span style="background: url(repeatable-diagonal-gradient.png); background-clip: border-box; background-clip: border; background-origin: padding-box; background-origin: padding; margin: 7px 4px 2px 18px; border: 6px transparent solid; border-width: 2px 10px 15px 2px; -moz-background-inline-policy: each-box; background-inline-policy: each-box;">
+    <span style="background: url(repeatable-diagonal-gradient.png); background-clip: border-box; background-origin: padding-box; margin: 7px 4px 2px 18px; border: 6px transparent solid; border-width: 2px 10px 15px 2px; box-decoration-break: clone;">
         blah<br>
         blah<br>
         blah
     </span>
 
 </body>
 </html>
--- a/layout/reftests/bugs/368020-5.html
+++ b/layout/reftests/bugs/368020-5.html
@@ -1,15 +1,15 @@
 <!DOCTYPE HTML>
 <html>
 <head>
 <title>Testcase, bug 368020</title>
 </head>
 <body style="line-height: 3; width: 500px; height: 250px;">
 
-    <span style="background: url(repeatable-diagonal-gradient.png); background-clip: padding-box; background-clip: padding; background-origin: content-box; background-origin: content; border: medium transparent solid; border-width: 7px 4px 2px 18px; padding: 2px 10px 15px 2px; -moz-background-inline-policy: each-box; background-inline-policy: each-box;">
+    <span style="background: url(repeatable-diagonal-gradient.png); background-clip: padding-box; background-origin: content-box; border: medium transparent solid; border-width: 7px 4px 2px 18px; padding: 2px 10px 15px 2px; box-decoration-break: clone;">
         blah<br>
         blah<br>
         blah
     </span>
 
 </body>
 </html>
--- a/layout/reftests/bugs/reftest.list
+++ b/layout/reftests/bugs/reftest.list
@@ -590,19 +590,18 @@ skip-if(B2G) == 367247-l-scroll.html 367
 == 367612-1b.html 367612-1-ref.html
 == 367612-1c.html 367612-1-ref.html
 == 367612-1d.html 367612-1-ref.html
 == 367612-1e.html 367612-1-ref.html
 == 367612-1f.html 367612-1-ref.html
 != 367612-1g.html 367612-1-ref.html
 skip-if(B2G) random-if(/^Windows\x20NT\x205\.1/.test(http.oscpu)) == 368020-1.html 368020-1-ref.html
 == 368020-2.html 368020-2-ref.html
-fails == 368020-3.html 368020-3-ref.html # bug 368085
-fails == 368020-4.html 368020-4-ref.html # bug 368085
-== 368020-5.html 368020-5-ref.html
+== 368020-3.html 368020-3-ref.html
+pref(layout.css.box-decoration-break.enabled,true) == 368020-5.html 368020-5-ref.html
 == 368155-1.xhtml 368155-1-ref.xhtml
 asserts(4) == 368155-negative-margins-1.html 368155-negative-margins-1-ref.html # bug 387205 / bug 457397
 # we can't test this because there's antialiasing involved, and our comparison
 # is too exact
 # == 368247-1.html 368247-1-ref.html
 == 368247-2.html 368247-2-ref.html
 == 368504-1.html 368504-1-ref.html
 == 368504-2.html 368504-2-ref.html
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-break/box-decoration-break-1-ref.html
@@ -0,0 +1,67 @@
+<!DOCTYPE HTML>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html>
+<head>
+  <title>CSS Test: Testing box-decoration-break:clone</title>
+  <link rel="author" title="Mats Palmgren" href="https://bugzilla.mozilla.org/show_bug.cgi?id=613659">
+  <meta charset="utf-8">
+<style>
+
+span {
+  line-height:4em;
+  font-family:monospace;
+  padding: 3px 5px 7px 11px;
+  background-color: #0F0;
+  margin: 13px 17px 19px 23px;
+  border-left:13px dashed pink;
+  border-top:7px dashed blue;
+  border-right:3px dashed black;
+  border-bottom:1px dashed blue;
+}
+.o0 {
+  border-radius: 17px;
+}
+.o10 {
+  border-radius: 17px;
+  margin-left:0;
+}
+.o10x {
+  border-radius: 17px;
+  padding-right:0;
+}
+.so0 {
+  border-radius: 0px;
+}
+.so10 {
+  border-radius: 0px;
+  margin-right:0;
+}
+.so10x {
+  border-radius: 0px;
+  padding-left:0;
+}
+</style>
+</head>
+<body style="margin:10px">
+
+<table border=1 cellpadding=10><tr>
+<td><span class="o0"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="o0"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="o0"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span></td>
+<td><span class="o10"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="o10"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="o10"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span></td>
+<td><span class="o10x"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="o10x"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="o10x"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span></td>
+</tr>
+</table>
+
+<br>
+
+<table border=1 cellpadding=10><tr>
+<td><span class="so0"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="so0"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="so0"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span></td>
+<td><span class="so10"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="so10"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="so10"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span></td>
+<td><span class="so10x"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="so10x"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="so10x"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span></td>
+</tr>
+</table>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-break/box-decoration-break-1.html
@@ -0,0 +1,71 @@
+<!DOCTYPE HTML>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html>
+<head>
+  <title>CSS Test: Testing box-decoration-break:clone</title>
+  <link rel="author" title="Mats Palmgren" href="https://bugzilla.mozilla.org/show_bug.cgi?id=613659">
+  <link rel="help" href="http://dev.w3.org/csswg/css-break/#break-decoration">
+  <link rel="match" href="box-decoration-break-1-ref.html">
+  <meta charset="utf-8">
+<style>
+
+span {
+  box-decoration-break:clone;
+
+  line-height:4em;
+  font-family:monospace;
+  padding: 3px 5px 7px 11px;
+  background-color: #0F0;
+  margin: 13px 17px 19px 23px;
+  border-left:13px dashed pink;
+  border-top:7px dashed blue;
+  border-right:3px dashed black;
+  border-bottom:1px dashed blue;
+}
+.o0 {
+  border-radius: 17px;
+}
+.o10 {
+  border-radius: 17px;
+  margin-left:0;
+}
+.o10x {
+  border-radius: 17px;
+  padding-right:0;
+}
+.so0 {
+  border-radius: 0px;
+}
+.so10 {
+  border-radius: 0px;
+  margin-right:0;
+}
+.so10x {
+  border-radius: 0px;
+  padding-left:0;
+}
+</style>
+</head>
+<body style="margin:10px">
+
+<table border=1 cellpadding=10><tr>
+<td><span class="o0"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span></td>
+<td><span class="o10"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span></td>
+<td><span class="o10x"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span></td>
+</tr>
+</table>
+
+<br>
+
+<table border=1 cellpadding=10><tr>
+<td><span class="so0"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br></td>
+<td><span class="so10"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br></td>
+<td><span class="so10x"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br></td>
+</tr>
+</table>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-break/box-decoration-break-border-image-ref.html
@@ -0,0 +1,135 @@
+<!DOCTYPE HTML>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html>
+<head>
+  <title>Testcase for border-image + box-decoration-break</title>
+  <link rel="author" title="Mats Palmgren" href="https://bugzilla.mozilla.org/show_bug.cgi?id=988653">
+  <meta charset="utf-8">
+  <style type="text/css">
+@font-face {
+  font-family: DejaVuSansMono;
+  src: url(../fonts/DejaVuSansMono.woff),url(DejaVuSansMono.woff);
+}
+* { font-family: DejaVuSansMono; }
+
+html,body {
+  color:black; background-color:white; font-size:16px; padding:0; padding-left:10px; margin:0;
+}
+
+b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,.b.clone {
+  border: 5px solid red;
+  border-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAIAAAD%2FgAIDAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAoUlEQVR42u3bwQ0AIAgEwcOmtXttgScmsxWQCTyp3EysJo61IliwYMGCBUuwYMGCBQuWYMGCBQsWLMGCBQsWLFiCBQsWLFiwBAsWLFiwYAkWLFiwYMESLFiwYMGCpXaVka%2BsO8dmOUNYggULFixYsAQLFixYsGAJFixYsGDBEixYsGDBgiVYsGDBggVLsGDBggULlmDBggULFizBggUL1t89N%2FYEtBGStpoAAAAASUVORK5CYII%3D) 10 10 repeat;
+  border-image-outset: 7px 3px 5px 9px;
+}
+.b {
+  border: 5px solid transparent;
+  background: pink;
+}
+.b.clone {
+  background: pink;
+  height:28px;
+}
+.col3 .b.clone {
+  height:32px;
+}
+
+.columns {
+  -moz-columns: 2;
+  width: 200px;
+  height: 50px;
+  background: grey;
+  margin-right: 20px;
+  margin-bottom: 20px;
+  float:left;
+}
+.col3 {
+  -moz-columns: 3;
+}
+.vbreak { height:65px; width:41px; }
+.h { width:30px;height:30px; background:grey; }
+.m { margin-left:15px; }
+.col3 .vbreak { height:115px; }
+x { display:inline-block; width:31px; height:18px; line-height:1; }
+y { display:inline-block; width:47px; height:18px; line-height:1; }
+pos1 { position:absolute; top:50px; width:700px; }
+pos2 { position:absolute; top:150px; width:700px; }
+pos3 { position:absolute; top:380px; width:700px; }
+pos4 { position:absolute; top:510px; width:700px; }
+
+b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,c1,c2,c3,c4,c5,c6,c7,c8,c9,c10,m1,m2,m3,m4,m5,m6,m7,m8,m9,m10 {position:absolute;}
+c1,c2,c3,c4,c5,c6,c7,c8,c9,c10 {position:absolute; overflow:hidden; z-index:1;}
+
+
+b1 { top:50px; left:20px; height:65px; width:41px; }
+c1 { top:0; left:0; height:88px; width:200px; }
+
+b2 { top:-38px; left:128px; height:66px; width:41px; }
+c2 { top:50px; left:0; height:61px; width:200px; }
+
+b3 { top:50px; left:240px; height:115px; width:41px; }
+c3 { top:0; left:0; height:92px; width:600px; }
+
+b4 { top:-42px; left:312px; height:115px; width:41px; }
+c4 { top:50px; left:0; height:42px; width:600px; }
+
+b5 { top:-84px; left:384px; height:116px; width:41px; }
+c5 { top:50px; left:0; height:100px; width:600px; }
+
+b6 { top:148px; left:20px; height:19px; z-index:1; }
+m6 { top:135px; left:56px; height:55px; width:100px; background:white; z-index:2; }
+
+b7 { top:30px; left:-36px; width:78px; height:19px; }
+c7 { top:170px; left:20px; height:300px; width:200px; }
+
+b8 { top:30px; left:77px; width:125px; height:19px; }
+m8 { top:15px; left:113px; width:125px; height:55px; background:white; }
+c8 { top:170px; left:20px; height:300px; width:600px; }
+
+b9 { top:30px; left:-36px; width:125px; height:19px; }
+c9 { top:222px; left:20px; height:300px; width:47px; }
+
+b10 { top:30px; left:-83px; width:125px; height:19px; }
+c10 { top:274px; left:20px; height:300px; width:156px; }
+
+  </style>
+</head>
+<body>
+<c1><b1></b1></c1>
+<c2><b2></b2></c2>
+<c3><b3></b3></c3>
+<c4><b4></b4></c4>
+<c5><b5></b5></c5>
+<b6><x></x><y></y><br></b6><m6></m6>
+<c7><b7><x></x><y></y></b7></c7>
+<c8><b8><x></x><y></y><y></y></b8><m8></m8></c8>
+<c9><b9><x></x><y></y><y></y></b9></c9>
+<c10><b10><x></x><y></y><y></y></b10></c10>
+<pre>box-decoration-break:slice</pre>
+
+<pos1>
+<div class="columns"><div class="b vbreak slice"></div></div>
+<div class="columns col3"><div class="b vbreak slice"></div></div>
+</pos1>
+
+<pos2>
+<span class="b slice"><x></x><div class="h"></div><y></y></span>
+<span class="b slice m"><x></x><div class="h"></div><y></y><div class="h"></div><y></y></span>
+
+<pre>box-decoration-break:clone</pre>
+</pos2>
+
+<pos3>
+<div class="columns"><div class="b vbreak clone"></div><div class="b vbreak clone"></div></div>
+<div class="columns col3"><div class="b vbreak clone"></div><div class="b vbreak clone"></div><div class="b vbreak clone"></div></div>
+</pos3>
+
+<pos4>
+<span class="b clone"><x></x></span><div class="h"></div><span class="b clone"><y></y></span>
+<span class="b clone m"><x></x></span><div class="h"></div><span class="b clone m"><y></y></span><div class="h"></div><span class="b clone m"><y></y></span>
+</pos4>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-break/box-decoration-break-border-image.html
@@ -0,0 +1,83 @@
+<!DOCTYPE HTML>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html>
+<head>
+  <title>Testcase for border-image + box-decoration-break</title>
+  <link rel="author" title="Mats Palmgren" href="https://bugzilla.mozilla.org/show_bug.cgi?id=988653">
+  <link rel="help" href="http://dev.w3.org/csswg/css-break/#break-decoration">
+  <link rel="match" href="box-decoration-break-border-image-ref.html">
+  <meta charset="utf-8">
+  <style type="text/css">
+@font-face {
+  font-family: DejaVuSansMono;
+  src: url(../fonts/DejaVuSansMono.woff),url(DejaVuSansMono.woff);
+}
+* { font-family: DejaVuSansMono; }
+
+html,body {
+  color:black; background-color:white; font-size:16px; padding:0; padding-left:10px; margin:0;
+}
+
+.b {
+  border: 5px solid red;
+  border-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAIAAAD%2FgAIDAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAoUlEQVR42u3bwQ0AIAgEwcOmtXttgScmsxWQCTyp3EysJo61IliwYMGCBUuwYMGCBQuWYMGCBQsWLMGCBQsWLFiCBQsWLFiwBAsWLFiwYAkWLFiwYMESLFiwYMGCpXaVka%2BsO8dmOUNYggULFixYsAQLFixYsGAJFixYsGDBEixYsGDBgiVYsGDBggVLsGDBggULlmDBggULFizBggUL1t89N%2FYEtBGStpoAAAAASUVORK5CYII%3D) 10 10 repeat;
+  background: pink;
+  border-image-outset: 7px 3px 5px 9px;
+}
+
+.columns {
+  -moz-columns: 2;
+  width: 200px;
+  height: 50px;
+  background: grey;
+  margin-right: 20px;
+  margin-bottom: 20px;
+  float:left;
+}
+.col3 {
+  -moz-columns: 3;
+}
+.vbreak { height:65px; width:41px; }
+.h { width:30px;height:30px; background:grey; }
+.m { margin-left:15px; }
+.col3 .vbreak { height:115px; }
+.clone { box-decoration-break:clone; }
+.slice { box-decoration-break:slice; }
+x { display:inline-block; width:31px; height:18px; line-height:1; }
+y { display:inline-block; width:47px; height:18px; line-height:1; }
+pos1 { position:absolute; top:50px; width:700px; }
+pos2 { position:absolute; top:150px; width:700px; }
+pos3 { position:absolute; top:380px; width:700px; }
+pos4 { position:absolute; top:510px; width:700px; }
+  </style>
+</head>
+<body>
+<pre>box-decoration-break:slice</pre>
+
+<pos1>
+<div class="columns"><div class="b vbreak slice"></div></div>
+<div class="columns col3"><div class="b vbreak slice"></div></div>
+</pos1>
+
+<pos2>
+<span class="b slice" style="border-style:dashed;"><x></x><div class="h"></div><y></y></span>
+<span class="b slice m" style="border-style:dashed;"><x></x><div class="h"></div><y></y><div class="h"></div><y></y></span>
+
+<pre>box-decoration-break:clone</pre>
+</pos2>
+
+<pos3>
+<div class="columns"><div class="b vbreak clone"></div></div>
+<div class="columns col3"><div class="b vbreak clone"></div></div>
+</pos3>
+
+<pos4>
+<span class="b clone" style="border-style:dashed;"><x></x><div class="h"></div><y></y></span>
+<span class="b clone m" style="border-style:dashed;"><x></x><div class="h"></div><y></y><div class="h"></div><y></y></span>
+</pos4>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-break/box-decoration-break-with-inset-box-shadow-1-ref.html
@@ -0,0 +1,132 @@
+<!DOCTYPE HTML>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html>
+<head>
+  <title>CSS Test: Testing box-decoration-break:clone with inset box-shadow</title>
+  <link rel="author" title="Mats Palmgren" href="https://bugzilla.mozilla.org/show_bug.cgi?id=613659">
+  <meta charset="utf-8">
+<style>
+span {  border:3px dashed pink; margin:0 1em; line-height:4em; }
+
+span {
+  font-family:monospace;
+  padding:1em 1em;
+  background-image: url(green-circle-alpha-32x32.png);
+}
+.o0 {
+  border-radius: 12px;
+  -webkit-box-shadow: inset 0px 0px 0px 10px #00F;
+          box-shadow: inset 0px 0px 0px 10px #00F;
+}
+.o10 {
+  border-radius: 12px;
+  -webkit-box-shadow: inset 0px 0px 7px 10px #00F;
+          box-shadow: inset 0px 0px 7px 10px #00F;
+}
+.o10x {
+  border-radius: 12px;
+  -webkit-box-shadow: inset 0px 0px 7px 0px #00F;
+          box-shadow: inset 0px 0px 7px 0px #00F;
+}
+.p0 {
+  border-radius: 12px;
+  -webkit-box-shadow: inset 15px 9px 0px 10px #00F;
+          box-shadow: inset 15px 9px 0px 10px #00F;
+}
+.p10 {
+  border-radius: 12px;
+  -webkit-box-shadow: inset 15px 9px 7px 10px #00F;
+          box-shadow: inset 15px 9px 7px 10px #00F;
+}
+.p10x {
+  border-radius: 12px;
+  -webkit-box-shadow: inset 15px 9px 7px 0px #00F;
+          box-shadow: inset 15px 9px 7px 0px #00F;
+}
+.so0 {
+  border-radius: 0px;
+  -webkit-box-shadow: inset 0px 0px 0px 10px #00F;
+          box-shadow: inset 0px 0px 0px 10px #00F;
+}
+.so10 {
+  border-radius: 0px;
+  -webkit-box-shadow: inset 0px 0px 7px 10px #00F;
+          box-shadow: inset 0px 0px 7px 10px #00F;
+}
+.so10x {
+  border-radius: 0px;
+  -webkit-box-shadow: inset 0px 0px 7px 0px #00F;
+          box-shadow: inset 0px 0px 7px 0px #00F;
+}
+.sp0 {
+  border-radius: 0px;
+  -webkit-box-shadow: inset 15px 9px 0px 10px #00F;
+          box-shadow: inset 15px 9px 0px 10px #00F;
+}
+.sp10 {
+  border-radius: 0px;
+  -webkit-box-shadow: inset 15px 9px 7px 10px #00F;
+          box-shadow: inset 15px 9px 7px 10px #00F;
+}
+.sp10x {
+  border-radius: 0px;
+  -webkit-box-shadow: inset 15px 9px 7px 0px #00F;
+          box-shadow: inset 15px 9px 7px 0px #00F;
+}
+
+.m b { visibility:hidden; }
+.m { box-shadow:none; background:none; border-style:solid; border-radius:0; border-color:transparent; }
+.m.o0, .m.o10, .m.o10x, .m.p0, .m.p10, .m.p10x { border-bottom-color: black; }
+</style>
+</head>
+<body style="margin:49px 50px;">
+
+<div style="position:relative">
+<table border=1 cellpadding=10><tr><td>
+<span class="o0"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="o0"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="o0"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="o10"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="o10"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="o10"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="o10x"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="o10x"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="o10x"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+</td><td>
+<span class="p0"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="p0"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br></span><span class="p0"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="p10"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="p10"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="p10"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="p10x"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="p10x"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="p10x"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+</td><td>
+<span class="so0"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="so0"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="so0"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="so10"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="so10"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="so10"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="so10x"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="so10x"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="so10x"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+</td><td>
+<span class="sp0"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="sp0"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="sp0"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="sp10"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="sp10"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="sp10"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="sp10x"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="sp10x"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="sp10x"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+</td></tr>
+</table>
+
+<div style="position:absolute; top:0px;left:0;">
+<!-- mask out 1px of outer edge of the rounded borders at some places due to rounding errors -->
+<table border=1 cellpadding=10><tr><td>
+<span class="m o0"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="m o0"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="m o0"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="m o10"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="m o10"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="m o10"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="m o10x"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="m o10x"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="m o10x"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+</td><td>
+<span class="m p0"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="m p0"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br></span><span class="m p0"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="m p10"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="m p10"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="m p10"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="m p10x"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="m p10x"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="m p10x"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+</td><td>
+<span class="m so0"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="m so0"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="m so0"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="m so10"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="m so10"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="m so10"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="m so10x"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="m so10x"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="m so10x"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+</td><td>
+<span class="m sp0"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="m sp0"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="m sp0"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="m sp10"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="m sp10"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="m sp10"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="m sp10x"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="m sp10x"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="m sp10x"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+</td></tr>
+</table>
+</div>
+
+</div>
+
+</body>
+
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-break/box-decoration-break-with-inset-box-shadow-1.html
@@ -0,0 +1,134 @@
+<!DOCTYPE HTML>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html>
+<head>
+  <title>CSS Test: Testing box-decoration-break:clone with inset box-shadow</title>
+  <link rel="author" title="Mats Palmgren" href="https://bugzilla.mozilla.org/show_bug.cgi?id=613659">
+  <link rel="help" href="http://dev.w3.org/csswg/css-break/#break-decoration">
+  <link rel="match" href="box-decoration-break-with-inset-box-shadow-1-ref.html">
+  <meta charset="utf-8">
+<style>
+span {  border:3px dashed pink; margin:0 1em; line-height:4em; box-decoration-break:clone; }
+
+span {
+  font-family:monospace;
+  padding:1em 1em;
+  background-image: url(green-circle-alpha-32x32.png);
+}
+.o0 {
+  border-radius: 12px;
+  -webkit-box-shadow: inset 0px 0px 0px 10px #00F;
+          box-shadow: inset 0px 0px 0px 10px #00F;
+}
+.o10 {
+  border-radius: 12px;
+  -webkit-box-shadow: inset 0px 0px 7px 10px #00F;
+          box-shadow: inset 0px 0px 7px 10px #00F;
+}
+.o10x {
+  border-radius: 12px;
+  -webkit-box-shadow: inset 0px 0px 7px 0px #00F;
+          box-shadow: inset 0px 0px 7px 0px #00F;
+}
+.p0 {
+  border-radius: 12px;
+  -webkit-box-shadow: inset 15px 9px 0px 10px #00F;
+          box-shadow: inset 15px 9px 0px 10px #00F;
+}
+.p10 {
+  border-radius: 12px;
+  -webkit-box-shadow: inset 15px 9px 7px 10px #00F;
+          box-shadow: inset 15px 9px 7px 10px #00F;
+}
+.p10x {
+  border-radius: 12px;
+  -webkit-box-shadow: inset 15px 9px 7px 0px #00F;
+          box-shadow: inset 15px 9px 7px 0px #00F;
+}
+.so0 {
+  border-radius: 0px;
+  -webkit-box-shadow: inset 0px 0px 0px 10px #00F;
+          box-shadow: inset 0px 0px 0px 10px #00F;
+}
+.so10 {
+  border-radius: 0px;
+  -webkit-box-shadow: inset 0px 0px 7px 10px #00F;
+          box-shadow: inset 0px 0px 7px 10px #00F;
+}
+.so10x {
+  border-radius: 0px;
+  -webkit-box-shadow: inset 0px 0px 7px 0px #00F;
+          box-shadow: inset 0px 0px 7px 0px #00F;
+}
+.sp0 {
+  border-radius: 0px;
+  -webkit-box-shadow: inset 15px 9px 0px 10px #00F;
+          box-shadow: inset 15px 9px 0px 10px #00F;
+}
+.sp10 {
+  border-radius: 0px;
+  -webkit-box-shadow: inset 15px 9px 7px 10px #00F;
+          box-shadow: inset 15px 9px 7px 10px #00F;
+}
+.sp10x {
+  border-radius: 0px;
+  -webkit-box-shadow: inset 15px 9px 7px 0px #00F;
+          box-shadow: inset 15px 9px 7px 0px #00F;
+}
+
+.m b { visibility:hidden; }
+.m { box-shadow:none; background:none; border-style:solid; border-radius:0; border-color:transparent; }
+.m.o0, .m.o10, .m.o10x, .m.p0, .m.p10, .m.p10x { border-bottom-color: black; }
+</style>
+</head>
+<body style="margin:49px 50px;">
+
+<div style="position:relative">
+<table border=1 cellpadding=10><tr><td>
+<span class="o0"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="o10"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="o10x"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+</td><td>
+<span class="p0"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="p10"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="p10x"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+</td><td>
+<span class="so0"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="so10"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="so10x"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+</td><td>
+<span class="sp0"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="sp10"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="sp10x"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+</td></tr>
+</table>
+
+<div style="position:absolute; top:0px;left:0;">
+<!-- mask out 1px of outer edge of the rounded borders at some places due to rounding errors -->
+<table border=1 cellpadding=10><tr><td>
+<span class="m o0"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="m o10"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="m o10x"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+</td><td>
+<span class="m p0"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="m p10"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="m p10x"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+</td><td>
+<span class="m so0"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="m so10"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="m so10x"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+</td><td>
+<span class="m sp0"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="m sp10"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="m sp10x"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+</td></tr>
+</table>
+</div>
+
+</div>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-break/box-decoration-break-with-outset-box-shadow-1-ref.html
@@ -0,0 +1,131 @@
+<!DOCTYPE HTML>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html>
+<head>
+  <title>CSS Test: Testing box-decoration-break:clone with outset box-shadow</title>
+  <link rel="author" title="Mats Palmgren" href="https://bugzilla.mozilla.org/show_bug.cgi?id=613659">
+  <meta charset="utf-8">
+<style>
+span { border:3px dashed pink; line-height:80px; }
+
+span {
+  font-family:monospace;
+  padding:1em 1em;
+  background-image: url(green-circle-alpha-32x32.png);
+}
+.o0 {
+  border-radius: 12px;
+  -webkit-box-shadow: 0px 0px 0px 10px #00F;
+          box-shadow: 0px 0px 0px 10px #00F;
+}
+.o10 {
+  border-radius: 12px;
+  -webkit-box-shadow: 0px 0px 7px 10px #00F;
+          box-shadow: 0px 0px 7px 10px #00F;
+}
+.o10x {
+  border-radius: 12px;
+  -webkit-box-shadow: 0px 0px 7px 0px #00F;
+          box-shadow: 0px 0px 7px 0px #00F;
+}
+.p0 {
+  border-radius: 12px;
+  -webkit-box-shadow: 15px 9px 0px 10px #00F;
+          box-shadow: 15px 9px 0px 10px #00F;
+}
+.p10 {
+  border-radius: 12px;
+  -webkit-box-shadow: 15px 9px 7px 10px #00F;
+          box-shadow: 15px 9px 7px 10px #00F;
+}
+.p10x {
+  border-radius: 12px;
+  -webkit-box-shadow: 15px 9px 7px 0px #00F;
+          box-shadow: 15px 9px 7px 0px #00F;
+}
+.so0 {
+  border-radius: 0px;
+  -webkit-box-shadow: 0px 0px 0px 10px #00F;
+          box-shadow: 0px 0px 0px 10px #00F;
+}
+.so10 {
+  border-radius: 0px;
+  -webkit-box-shadow: 0px 0px 7px 10px #00F;
+          box-shadow: 0px 0px 7px 10px #00F;
+}
+.so10x {
+  border-radius: 0px;
+  -webkit-box-shadow: 0px 0px 7px 0px #00F;
+          box-shadow: 0px 0px 7px 0px #00F;
+}
+.sp0 {
+  border-radius: 0px;
+  -webkit-box-shadow: 15px 9px 0px 10px #00F;
+          box-shadow: 15px 9px 0px 10px #00F;
+}
+.sp10 {
+  border-radius: 0px;
+  -webkit-box-shadow: 15px 9px 7px 10px #00F;
+          box-shadow: 15px 9px 7px 10px #00F;
+}
+.sp10x {
+  border-radius: 0px;
+  -webkit-box-shadow: 15px 9px 7px 0px #00F;
+          box-shadow: 15px 9px 7px 0px #00F;
+}
+
+.m b { visibility:hidden; }
+.m { box-shadow:none; background:none; border-style:solid; border-radius:0; border-color:transparent; }
+.m.o0, .m.o10, .m.o10x, .m.p0, .m.p10, .m.p10x { border-bottom-color: black; }
+</style>
+</head>
+<body style="margin:49px 50px;">
+
+<div style="position:relative">
+<table border=1 cellpadding=50 ><tr><td>
+<span class="o0"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="o0"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="o0"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="o10"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="o10"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="o10"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="o10x"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="o10x"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="o10x"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+</td><td>
+<span class="p0"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="p0"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="p0"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="p10"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="p10"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="p10"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="p10x"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="p10x"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="p10x"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+</td><td>
+<span class="so0"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="so0"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="so0"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="so10"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="so10"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="so10"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="so10x"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="so10x"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="so10x"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+</td><td>
+<span class="sp0"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="sp0"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="sp0"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="sp10"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="sp10"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="sp10"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="sp10x"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="sp10x"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="sp10x"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+</td></tr>
+</table>
+
+<div style="position:absolute; top:0px;left:0;">
+<!-- mask out 1px of outer edge of the rounded borders at some places due to rounding errors -->
+<table border=1 cellpadding=50 ><tr><td>
+<span class="m o0"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="m o0"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="m o0"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="m o10"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="m o10"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="m o10"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="m o10x"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="m o10x"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="m o10x"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+</td><td>
+<span class="m p0"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="m p0"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="m p0"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="m p10"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="m p10"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="m p10"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="m p10x"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="m p10x"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="m p10x"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+</td><td>
+<span class="m so0"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="m so0"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="m so0"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="m so10"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="m so10"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="m so10"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="m so10x"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="m so10x"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="m so10x"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+</td><td>
+<span class="m sp0"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="m sp0"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="m sp0"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="m sp10"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="m sp10"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="m sp10"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="m sp10x"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="m sp10x"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="m sp10x"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+</td></tr>
+</table>
+</div>
+
+</div>
+</body>
+
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-break/box-decoration-break-with-outset-box-shadow-1.html
@@ -0,0 +1,133 @@
+<!DOCTYPE HTML>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html>
+<head>
+  <title>CSS Test: Testing box-decoration-break:clone with outset box-shadow</title>
+  <link rel="author" title="Mats Palmgren" href="https://bugzilla.mozilla.org/show_bug.cgi?id=613659">
+  <link rel="help" href="http://dev.w3.org/csswg/css-break/#break-decoration">
+  <link rel="match" href="box-decoration-break-with-outset-box-shadow-1-ref.html">
+  <meta charset="utf-8">
+<style>
+span { border:3px dashed pink; line-height:80px; box-decoration-break:clone; }
+
+span {
+  font-family:monospace;
+  padding:1em 1em;
+  background-image: url(green-circle-alpha-32x32.png);
+}
+.o0 {
+  border-radius: 12px;
+  -webkit-box-shadow: 0px 0px 0px 10px #00F;
+          box-shadow: 0px 0px 0px 10px #00F;
+}
+.o10 {
+  border-radius: 12px;
+  -webkit-box-shadow: 0px 0px 7px 10px #00F;
+          box-shadow: 0px 0px 7px 10px #00F;
+}
+.o10x {
+  border-radius: 12px;
+  -webkit-box-shadow: 0px 0px 7px 0px #00F;
+          box-shadow: 0px 0px 7px 0px #00F;
+}
+.p0 {
+  border-radius: 12px;
+  -webkit-box-shadow: 15px 9px 0px 10px #00F;
+          box-shadow: 15px 9px 0px 10px #00F;
+}
+.p10 {
+  border-radius: 12px;
+  -webkit-box-shadow: 15px 9px 7px 10px #00F;
+          box-shadow: 15px 9px 7px 10px #00F;
+}
+.p10x {
+  border-radius: 12px;
+  -webkit-box-shadow: 15px 9px 7px 0px #00F;
+          box-shadow: 15px 9px 7px 0px #00F;
+}
+.so0 {
+  border-radius: 0px;
+  -webkit-box-shadow: 0px 0px 0px 10px #00F;
+          box-shadow: 0px 0px 0px 10px #00F;
+}
+.so10 {
+  border-radius: 0px;
+  -webkit-box-shadow: 0px 0px 7px 10px #00F;
+          box-shadow: 0px 0px 7px 10px #00F;
+}
+.so10x {
+  border-radius: 0px;
+  -webkit-box-shadow: 0px 0px 7px 0px #00F;
+          box-shadow: 0px 0px 7px 0px #00F;
+}
+.sp0 {
+  border-radius: 0px;
+  -webkit-box-shadow: 15px 9px 0px 10px #00F;
+          box-shadow: 15px 9px 0px 10px #00F;
+}
+.sp10 {
+  border-radius: 0px;
+  -webkit-box-shadow: 15px 9px 7px 10px #00F;
+          box-shadow: 15px 9px 7px 10px #00F;
+}
+.sp10x {
+  border-radius: 0px;
+  -webkit-box-shadow: 15px 9px 7px 0px #00F;
+          box-shadow: 15px 9px 7px 0px #00F;
+}
+
+.m b { visibility:hidden; }
+.m { box-shadow:none; background:none; border-style:solid; border-radius:0; border-color:transparent; }
+.m.o0, .m.o10, .m.o10x, .m.p0, .m.p10, .m.p10x { border-bottom-color: black; }
+</style>
+</head>
+<body style="margin:49px 50px;">
+
+<div style="position:relative">
+<table border=1 cellpadding=50 ><tr><td>
+<span class="o0"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="o10"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="o10x"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+</td><td>
+<span class="p0"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="p10"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="p10x"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+</td><td>
+<span class="so0"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="so10"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="so10x"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+</td><td>
+<span class="sp0"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="sp10"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="sp10x"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+</td></tr>
+</table>
+
+<div style="position:absolute; top:0px;left:0;">
+<!-- mask out 1px of outer edge of the rounded borders at some places due to rounding errors -->
+<table border=1 cellpadding=50 ><tr><td>
+<span class="m o0"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="m o10"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="m o10x"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+</td><td>
+<span class="m p0"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="m p10"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="m p10x"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+</td><td>
+<span class="m so0"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="m so10"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="m so10x"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+</td><td>
+<span class="m sp0"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="m sp10"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="m sp10x"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+</td></tr>
+</table>
+</div>
+
+</div>
+</body>
+
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..a007675a176123cab7291d684537dde8961ecec7
GIT binary patch
literal 396
zc%17D@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdzwj^(N7l!{JxM1({$v_d#0*}aI
z1_o|n5N2eUHAey{$X?><>&kwIla1GcWoG4q7eFD|%#er@=ltB<)VvY~5O6L^O)N=G
zQ7F$W$xv|j^bJVSOJxU&fADm142d}Wbh@EXvx0!De5T6w6S{BK=xp8Q{d%uWd#F`^
z!u042t)K<Qepgg_b|{|w=XK!ce10A7Kh+w~?RnG{7=sk#qNEqF>1nL{mnx;ilg=ai
zOm$ac&XaDN>gE#Oo7W=4rBAqryvvLDbdC9E$2H%U`7_VY6^JN)Zo4q;n)Ck87q4sN
zJwE<$;bwsownvTGtsLI#EO0NJW1V0;N36hsKW4M42g~|~6i){&4TV@C0dB62>wb+D
zKCC89d(KX3hzfAn8<QbnIETr{#mtNG_vr?G<=YeAd(87c$*k+qq;b+NZVFrAG;Uj;
feNQsKoi1coD}A1I>bY1VC{R3I{an^LB{Ts5V_A-C
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-break/reftest.list
@@ -0,0 +1,5 @@
+pref(layout.css.box-decoration-break.enabled,true) == box-decoration-break-1.html box-decoration-break-1-ref.html
+
+fuzzy(1,20) pref(layout.css.box-decoration-break.enabled,true) == box-decoration-break-with-inset-box-shadow-1.html box-decoration-break-with-inset-box-shadow-1-ref.html
+fuzzy(16,460) pref(layout.css.box-decoration-break.enabled,true) == box-decoration-break-with-outset-box-shadow-1.html box-decoration-break-with-outset-box-shadow-1-ref.html
+random-if(!gtk2Widget) pref(layout.css.box-decoration-break.enabled,true) HTTP(..) == box-decoration-break-border-image.html box-decoration-break-border-image-ref.html
--- a/layout/reftests/reftest.list
+++ b/layout/reftests/reftest.list
@@ -51,16 +51,19 @@ include bugs/reftest.list
 include canvas/reftest.list
 
 # css animations
 include css-animations/reftest.list
 
 # blending/
 include css-blending/reftest.list
 
+# Tests for the css-break spec
+include css-break/reftest.list
+
 # css calc() tests
 include css-calc/reftest.list
 
 # css character encoding tests
 include css-charset/reftest.list
 
 # css default pseudo class tests
 include css-default/reftest.list
--- a/layout/style/nsCSSKeywordList.h
+++ b/layout/style/nsCSSKeywordList.h
@@ -183,17 +183,16 @@ CSS_KEY(bold-fraktur, bold_fraktur)
 CSS_KEY(bold-italic, bold_italic)
 CSS_KEY(bold-sans-serif, bold_sans_serif)
 CSS_KEY(bold-script, bold_script)
 CSS_KEY(bolder, bolder)
 CSS_KEY(border-box, border_box)
 CSS_KEY(both, both)
 CSS_KEY(bottom, bottom)
 CSS_KEY(bottom-outside, bottom_outside)
-CSS_KEY(bounding-box, bounding_box)
 CSS_KEY(break-all, break_all)
 CSS_KEY(break-word, break_word)
 CSS_KEY(brightness, brightness)
 CSS_KEY(button, button)
 CSS_KEY(buttonface, buttonface)
 CSS_KEY(buttonhighlight, buttonhighlight)
 CSS_KEY(buttonshadow, buttonshadow)
 CSS_KEY(buttontext, buttontext)
@@ -203,16 +202,17 @@ CSS_KEY(captiontext, captiontext)
 CSS_KEY(cell, cell)
 CSS_KEY(center, center)
 CSS_KEY(ch, ch)
 CSS_KEY(character-variant, character_variant)
 CSS_KEY(circle, circle)
 CSS_KEY(cjk-decimal, cjk_decimal)
 CSS_KEY(cjk-ideographic, cjk_ideographic)
 CSS_KEY(clip, clip)
+CSS_KEY(clone, clone)
 CSS_KEY(close-quote, close_quote)
 CSS_KEY(closest-corner, closest_corner)
 CSS_KEY(closest-side, closest_side)
 CSS_KEY(cm, cm)
 CSS_KEY(col-resize, col_resize)
 CSS_KEY(collapse, collapse)
 CSS_KEY(color, color)
 CSS_KEY(color-burn, color_burn)
@@ -252,17 +252,16 @@ CSS_KEY(digits, digits)
 CSS_KEY(disabled, disabled)
 CSS_KEY(disc, disc)
 CSS_KEY(discretionary-ligatures, discretionary_ligatures)
 CSS_KEY(dotted, dotted)
 CSS_KEY(double, double)
 CSS_KEY(double-struck, double_struck)
 CSS_KEY(drop-shadow, drop_shadow)
 CSS_KEY(e-resize, e_resize)
-CSS_KEY(each-box, each_box)
 CSS_KEY(ease, ease)
 CSS_KEY(ease-in, ease_in)
 CSS_KEY(ease-in-out, ease_in_out)
 CSS_KEY(ease-out, ease_out)
 CSS_KEY(element, element)
 CSS_KEY(elements, elements)
 CSS_KEY(ellipse, ellipse)
 CSS_KEY(ellipsis, ellipsis)
@@ -491,16 +490,17 @@ CSS_KEY(show, show)
 CSS_KEY(sideways, sideways)
 CSS_KEY(simp-chinese-formal, simp_chinese_formal)
 CSS_KEY(simp-chinese-informal, simp_chinese_informal)
 CSS_KEY(simplified, simplified)
 CSS_KEY(skew, skew)
 CSS_KEY(skewx, skewx)
 CSS_KEY(skewy, skewy)
 CSS_KEY(slashed-zero, slashed_zero)
+CSS_KEY(slice, slice)
 CSS_KEY(small, small)
 CSS_KEY(small-caps, small_caps)
 CSS_KEY(small-caption, small_caption)
 CSS_KEY(smaller, smaller)
 CSS_KEY(soft, soft)
 CSS_KEY(soft-light, soft_light)
 CSS_KEY(solid, solid)
 CSS_KEY(space-around, space_around)
--- a/layout/style/nsCSSPropList.h
+++ b/layout/style/nsCSSPropList.h
@@ -269,20 +269,16 @@
 // :first-letter are: font properties, 'text-decoration',
 // 'text-transform', 'letter-spacing', 'word-spacing' (when
 // appropriate), 'line-height', 'float', 'vertical-align' (only if
 // 'float' is 'none'), margin properties, padding properties, border
 // properties, 'color', and background properties.  We also allow
 // 'text-shadow' (see above) and 'box-shadow' (which is like the
 // border properties).
 
-// We include '-moz-background-inline-policy' (css3-background's
-// 'background-break') in both as a background property, although this
-// is somewhat questionable.
-
 CSS_PROP_DISPLAY(
     -moz-appearance,
     appearance,
     CSS_PROP_DOMPROP_PREFIXED(Appearance),
     CSS_PROPERTY_PARSE_VALUE,
     "",
     VARIANT_HK,
     kAppearanceKTable,
@@ -533,28 +529,16 @@ CSS_PROP_BACKGROUND(
         CSS_PROPERTY_IGNORED_WHEN_COLORS_DISABLED |
         CSS_PROPERTY_START_IMAGE_LOADS,
     "",
     VARIANT_IMAGE, // used by list parsing
     nullptr,
     CSS_PROP_NO_OFFSET,
     eStyleAnimType_None)
 CSS_PROP_BACKGROUND(
-    -moz-background-inline-policy,
-    _moz_background_inline_policy,
-    CSS_PROP_DOMPROP_PREFIXED(BackgroundInlinePolicy),
-    CSS_PROPERTY_PARSE_VALUE |
-        CSS_PROPERTY_APPLIES_TO_FIRST_LETTER_AND_FIRST_LINE |
-        CSS_PROPERTY_APPLIES_TO_PLACEHOLDER,
-    "",
-    VARIANT_HK,
-    kBackgroundInlinePolicyKTable,
-    CSS_PROP_NO_OFFSET,
-    eStyleAnimType_None)
-CSS_PROP_BACKGROUND(
     background-blend-mode,
     background_blend_mode,
     BackgroundBlendMode,
     CSS_PROPERTY_PARSE_VALUE_LIST |
         CSS_PROPERTY_APPLIES_TO_FIRST_LETTER_AND_FIRST_LINE |
         CSS_PROPERTY_APPLIES_TO_PLACEHOLDER |
         CSS_PROPERTY_VALUE_LIST_USES_COMMAS,
     "layout.css.background-blend-mode.enabled",
@@ -1361,16 +1345,26 @@ CSS_PROP_POSITION(
         CSS_PROPERTY_UNITLESS_LENGTH_QUIRK |
         CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH,
     "",
     VARIANT_AHLP | VARIANT_CALC,
     nullptr,
     offsetof(nsStylePosition, mOffset),
     eStyleAnimType_Sides_Bottom)
 CSS_PROP_BORDER(
+    box-decoration-break,
+    box_decoration_break,
+    BoxDecorationBreak,
+    CSS_PROPERTY_PARSE_VALUE,
+    "layout.css.box-decoration-break.enabled",
+    VARIANT_HK,
+    kBoxDecorationBreakKTable,
+    CSS_PROP_NO_OFFSET,
+    eStyleAnimType_None)
+CSS_PROP_BORDER(
     box-shadow,
     box_shadow,
     BoxShadow,
     CSS_PROPERTY_PARSE_FUNCTION |
         CSS_PROPERTY_APPLIES_TO_FIRST_LETTER |
         CSS_PROPERTY_VALUE_LIST_USES_COMMAS |
         CSS_PROPERTY_IGNORED_WHEN_COLORS_DISABLED,
         // NOTE: some components must be nonnegative
--- a/layout/style/nsCSSProps.cpp
+++ b/layout/style/nsCSSProps.cpp
@@ -671,23 +671,16 @@ const KTableValue nsCSSProps::kTransform
 
 const KTableValue nsCSSProps::kBackgroundAttachmentKTable[] = {
   eCSSKeyword_fixed, NS_STYLE_BG_ATTACHMENT_FIXED,
   eCSSKeyword_scroll, NS_STYLE_BG_ATTACHMENT_SCROLL,
   eCSSKeyword_local, NS_STYLE_BG_ATTACHMENT_LOCAL,
   eCSSKeyword_UNKNOWN,-1
 };
 
-const KTableValue nsCSSProps::kBackgroundInlinePolicyKTable[] = {
-  eCSSKeyword_each_box,     NS_STYLE_BG_INLINE_POLICY_EACH_BOX,
-  eCSSKeyword_continuous,   NS_STYLE_BG_INLINE_POLICY_CONTINUOUS,
-  eCSSKeyword_bounding_box, NS_STYLE_BG_INLINE_POLICY_BOUNDING_BOX,
-  eCSSKeyword_UNKNOWN,-1
-};
-
 static_assert(NS_STYLE_BG_CLIP_BORDER == NS_STYLE_BG_ORIGIN_BORDER &&
               NS_STYLE_BG_CLIP_PADDING == NS_STYLE_BG_ORIGIN_PADDING &&
               NS_STYLE_BG_CLIP_CONTENT == NS_STYLE_BG_ORIGIN_CONTENT,
               "bg-clip and bg-origin style constants must agree");
 const KTableValue nsCSSProps::kBackgroundOriginKTable[] = {
   eCSSKeyword_border_box, NS_STYLE_BG_ORIGIN_BORDER,
   eCSSKeyword_padding_box, NS_STYLE_BG_ORIGIN_PADDING,
   eCSSKeyword_content_box, NS_STYLE_BG_ORIGIN_CONTENT,
@@ -791,16 +784,22 @@ const KTableValue nsCSSProps::kBorderWid
 };
 
 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,
   eCSSKeyword_UNKNOWN,-1
 };
 
 const KTableValue nsCSSProps::kBoxSizingKTable[] = {
   eCSSKeyword_content_box,  NS_STYLE_BOX_SIZING_CONTENT,
   eCSSKeyword_border_box,   NS_STYLE_BOX_SIZING_BORDER,
--- a/layout/style/nsCSSProps.h
+++ b/layout/style/nsCSSProps.h
@@ -501,30 +501,30 @@ public:
   static const KTableValue kAnimationIterationCountKTable[];
   static const KTableValue kAnimationPlayStateKTable[];
   static const KTableValue kAnimationTimingFunctionKTable[];
   static const KTableValue kAppearanceKTable[];
   static const KTableValue kAzimuthKTable[];
   static const KTableValue kBackfaceVisibilityKTable[];
   static const KTableValue kTransformStyleKTable[];
   static const KTableValue kBackgroundAttachmentKTable[];
-  static const KTableValue kBackgroundInlinePolicyKTable[];
   static const KTableValue kBackgroundOriginKTable[];
   static const KTableValue kBackgroundPositionKTable[];
   static const KTableValue kBackgroundRepeatKTable[];
   static const KTableValue kBackgroundRepeatPartKTable[];
   static const KTableValue kBackgroundSizeKTable[];
   static const KTableValue kBlendModeKTable[];
   static const KTableValue kBorderCollapseKTable[];
   static const KTableValue kBorderColorKTable[];
   static const KTableValue kBorderImageRepeatKTable[];
   static const KTableValue kBorderImageSliceKTable[];
   static const KTableValue kBorderStyleKTable[];
   static const KTableValue kBorderWidthKTable[];
   static const KTableValue kBoxAlignKTable[];
+  static const KTableValue kBoxDecorationBreakKTable[];
   static const KTableValue kBoxDirectionKTable[];
   static const KTableValue kBoxOrientKTable[];
   static const KTableValue kBoxPackKTable[];
   static const KTableValue kDominantBaselineKTable[];
   static const KTableValue kFillRuleKTable[];
   static const KTableValue kFilterFunctionKTable[];
   static const KTableValue kImageRenderingKTable[];
   static const KTableValue kShapeRenderingKTable[];
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -2069,26 +2069,16 @@ nsComputedDOMStyle::DoGetBackgroundImage
     const nsStyleImage& image = bg->mLayers[i].mImage;
     SetValueToStyleImage(image, val);
   }
 
   return valueList;
 }
 
 CSSValue*
-nsComputedDOMStyle::DoGetBackgroundInlinePolicy()
-{
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
-  val->SetIdent(nsCSSProps::ValueToKeywordEnum(
-                  StyleBackground()->mBackgroundInlinePolicy,
-                  nsCSSProps::kBackgroundInlinePolicyKTable));
-  return val;
-}
-
-CSSValue*
 nsComputedDOMStyle::DoGetBackgroundBlendMode()
 {
   return GetBackgroundList(&nsStyleBackground::Layer::mBlendMode,
                            &nsStyleBackground::mBlendModeCount,
                            nsCSSProps::kBlendModeKTable);
 }
 
 CSSValue*
@@ -2976,16 +2966,26 @@ nsComputedDOMStyle::GetCSSShadowArray(ns
                                        nsCSSProps::kBoxShadowTypeKTable));
     }
   }
 
   return valueList;
 }
 
 CSSValue*
+nsComputedDOMStyle::DoGetBoxDecorationBreak()
+{
+  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+  val->SetIdent(
+    nsCSSProps::ValueToKeywordEnum(StyleBorder()->mBoxDecorationBreak,
+                                   nsCSSProps::kBoxDecorationBreakKTable));
+  return val;
+}
+
+CSSValue*
 nsComputedDOMStyle::DoGetBoxShadow()
 {
   return GetCSSShadowArray(StyleBorder()->mBoxShadow,
                            StyleColor()->mColor,
                            true);
 }
 
 CSSValue*
--- a/layout/style/nsComputedDOMStyle.h
+++ b/layout/style/nsComputedDOMStyle.h
@@ -217,16 +217,17 @@ private:
    * To avoid a name conflict with nsIDOM*CSS2Properties, these are all
    * DoGetXXX instead of GetXXX.
    */
 
   mozilla::dom::CSSValue* DoGetAppearance();
 
   /* Box properties */
   mozilla::dom::CSSValue* DoGetBoxAlign();
+  mozilla::dom::CSSValue* DoGetBoxDecorationBreak();
   mozilla::dom::CSSValue* DoGetBoxDirection();
   mozilla::dom::CSSValue* DoGetBoxFlex();
   mozilla::dom::CSSValue* DoGetBoxOrdinalGroup();
   mozilla::dom::CSSValue* DoGetBoxOrient();
   mozilla::dom::CSSValue* DoGetBoxPack();
   mozilla::dom::CSSValue* DoGetBoxSizing();
 
   mozilla::dom::CSSValue* DoGetWidth();
@@ -278,17 +279,16 @@ private:
 
   /* Background properties */
   mozilla::dom::CSSValue* DoGetBackgroundAttachment();
   mozilla::dom::CSSValue* DoGetBackgroundColor();
   mozilla::dom::CSSValue* DoGetBackgroundImage();
   mozilla::dom::CSSValue* DoGetBackgroundPosition();
   mozilla::dom::CSSValue* DoGetBackgroundRepeat();
   mozilla::dom::CSSValue* DoGetBackgroundClip();
-  mozilla::dom::CSSValue* DoGetBackgroundInlinePolicy();
   mozilla::dom::CSSValue* DoGetBackgroundBlendMode();
   mozilla::dom::CSSValue* DoGetBackgroundOrigin();
   mozilla::dom::CSSValue* DoGetBackgroundSize();
 
   /* Padding properties */
   mozilla::dom::CSSValue* DoGetPaddingTop();
   mozilla::dom::CSSValue* DoGetPaddingBottom();
   mozilla::dom::CSSValue* DoGetPaddingLeft();
--- a/layout/style/nsComputedDOMStylePropertyList.h
+++ b/layout/style/nsComputedDOMStylePropertyList.h
@@ -225,17 +225,16 @@ COMPUTED_STYLE_PROP(word_wrap,          
 COMPUTED_STYLE_PROP(writing_mode,                  WritingMode)
 COMPUTED_STYLE_PROP(z_index,                       ZIndex)
 
 /* ******************************* *\
  * Implementations of -moz- styles *
 \* ******************************* */
 
 COMPUTED_STYLE_PROP(appearance,                    Appearance)
-COMPUTED_STYLE_PROP(_moz_background_inline_policy, BackgroundInlinePolicy)
 COMPUTED_STYLE_PROP(binding,                       Binding)
 COMPUTED_STYLE_PROP(border_bottom_colors,          BorderBottomColors)
 COMPUTED_STYLE_PROP(border_left_colors,            BorderLeftColors)
 COMPUTED_STYLE_PROP(border_right_colors,           BorderRightColors)
 COMPUTED_STYLE_PROP(border_top_colors,             BorderTopColors)
 COMPUTED_STYLE_PROP(box_align,                     BoxAlign)
 COMPUTED_STYLE_PROP(box_direction,                 BoxDirection)
 COMPUTED_STYLE_PROP(box_flex,                      BoxFlex)
--- a/layout/style/nsRuleNode.cpp
+++ b/layout/style/nsRuleNode.cpp
@@ -6234,24 +6234,16 @@ nsRuleNode::ComputeBackgroundData(void* 
 
   // background-clip: enum, inherit, initial [list]
   SetBackgroundList(aContext, *aRuleData->ValueForBackgroundClip(),
                     bg->mLayers,
                     parentBG->mLayers, &nsStyleBackground::Layer::mClip,
                     uint8_t(NS_STYLE_BG_CLIP_BORDER), parentBG->mClipCount,
                     bg->mClipCount, maxItemCount, rebuild, canStoreInRuleTree);
 
-  // background-inline-policy: enum, inherit, initial
-  SetDiscrete(*aRuleData->ValueForBackgroundInlinePolicy(),
-              bg->mBackgroundInlinePolicy,
-              canStoreInRuleTree,
-              SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
-              parentBG->mBackgroundInlinePolicy,
-              NS_STYLE_BG_INLINE_POLICY_CONTINUOUS, 0, 0, 0, 0);
-
   // background-blend-mode: enum, inherit, initial [list]
   SetBackgroundList(aContext, *aRuleData->ValueForBackgroundBlendMode(),
                     bg->mLayers,
                     parentBG->mLayers, &nsStyleBackground::Layer::mBlendMode,
                     uint8_t(NS_STYLE_BLEND_NORMAL), parentBG->mBlendModeCount,
                     bg->mBlendModeCount, maxItemCount, rebuild,
                     canStoreInRuleTree);
 
@@ -6440,16 +6432,23 @@ nsRuleNode::ComputeBorderData(void* aSta
                               const nsRuleData* aRuleData,
                               nsStyleContext* aContext,
                               nsRuleNode* aHighestNode,
                               const RuleDetail aRuleDetail,
                               const bool aCanStoreInRuleTree)
 {
   COMPUTE_START_RESET(Border, (mPresContext), border, parentBorder)
 
+  // box-decoration-break: enum, inherit, initial
+  SetDiscrete(*aRuleData->ValueForBoxDecorationBreak(),
+              border->mBoxDecorationBreak, canStoreInRuleTree,
+              SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
+              parentBorder->mBoxDecorationBreak,
+              NS_STYLE_BOX_DECORATION_BREAK_SLICE, 0, 0, 0, 0);
+
   // box-shadow: none, list, inherit, initial
   const nsCSSValue* boxShadowValue = aRuleData->ValueForBoxShadow();
   switch (boxShadowValue->GetUnit()) {
   case eCSSUnit_Null:
     break;
 
   case eCSSUnit_Initial:
   case eCSSUnit_Unset:
--- a/layout/style/nsStyleConsts.h
+++ b/layout/style/nsStyleConsts.h
@@ -112,16 +112,20 @@ static inline mozilla::css::Side operato
 #define NS_STYLE_BOX_ALIGN_END         4
 
 // box-pack
 #define NS_STYLE_BOX_PACK_START        0
 #define NS_STYLE_BOX_PACK_CENTER       1
 #define NS_STYLE_BOX_PACK_END          2
 #define NS_STYLE_BOX_PACK_JUSTIFY      3
 
+// box-decoration-break
+#define NS_STYLE_BOX_DECORATION_BREAK_SLICE  0
+#define NS_STYLE_BOX_DECORATION_BREAK_CLONE  1
+
 // box-direction
 #define NS_STYLE_BOX_DIRECTION_NORMAL    0
 #define NS_STYLE_BOX_DIRECTION_REVERSE   1
 
 // box-orient
 #define NS_STYLE_BOX_ORIENT_HORIZONTAL 0
 #define NS_STYLE_BOX_ORIENT_VERTICAL   1
 
--- a/layout/style/nsStyleStruct.cpp
+++ b/layout/style/nsStyleStruct.cpp
@@ -383,16 +383,17 @@ nsChangeHint nsStylePadding::CalcDiffere
 
 nsStyleBorder::nsStyleBorder(nsPresContext* aPresContext)
   : mBorderColors(nullptr),
     mBoxShadow(nullptr),
     mBorderImageFill(NS_STYLE_BORDER_IMAGE_SLICE_NOFILL),
     mBorderImageRepeatH(NS_STYLE_BORDER_IMAGE_REPEAT_STRETCH),
     mBorderImageRepeatV(NS_STYLE_BORDER_IMAGE_REPEAT_STRETCH),
     mFloatEdge(NS_STYLE_FLOAT_EDGE_CONTENT),
+    mBoxDecorationBreak(NS_STYLE_BOX_DECORATION_BREAK_SLICE),
     mComputedBorder(0, 0, 0, 0)
 {
   MOZ_COUNT_CTOR(nsStyleBorder);
 
   NS_FOR_CSS_HALF_CORNERS (corner) {
     mBorderRadius.Set(corner, nsStyleCoord(0, nsStyleCoord::CoordConstructor));
   }
 
@@ -434,16 +435,17 @@ nsStyleBorder::nsStyleBorder(const nsSty
     mBorderImageSource(aSrc.mBorderImageSource),
     mBorderImageSlice(aSrc.mBorderImageSlice),
     mBorderImageWidth(aSrc.mBorderImageWidth),
     mBorderImageOutset(aSrc.mBorderImageOutset),
     mBorderImageFill(aSrc.mBorderImageFill),
     mBorderImageRepeatH(aSrc.mBorderImageRepeatH),
     mBorderImageRepeatV(aSrc.mBorderImageRepeatV),
     mFloatEdge(aSrc.mFloatEdge),
+    mBoxDecorationBreak(aSrc.mBoxDecorationBreak),
     mComputedBorder(aSrc.mComputedBorder),
     mBorder(aSrc.mBorder),
     mTwipsPerPixel(aSrc.mTwipsPerPixel)
 {
   MOZ_COUNT_CTOR(nsStyleBorder);
   if (aSrc.mBorderColors) {
     EnsureBorderColors();
     for (int32_t i = 0; i < 4; i++)
@@ -523,17 +525,18 @@ nsChangeHint nsStyleBorder::CalcDifferen
   // Note that differences in mBorder don't affect rendering (which should only
   // use mComputedBorder), so don't need to be tested for here.
   // XXXbz we should be able to return a more specific change hint for
   // at least GetComputedBorder() differences...
   if (mTwipsPerPixel != aOther.mTwipsPerPixel ||
       GetComputedBorder() != aOther.GetComputedBorder() ||
       mFloatEdge != aOther.mFloatEdge ||
       mBorderImageOutset != aOther.mBorderImageOutset ||
-      (shadowDifference & nsChangeHint_NeedReflow))
+      (shadowDifference & nsChangeHint_NeedReflow) ||
+      mBoxDecorationBreak != aOther.mBoxDecorationBreak)
     return NS_STYLE_HINT_REFLOW;
 
   NS_FOR_CSS_SIDES(ix) {
     // See the explanation in nsChangeHint.h of
     // nsChangeHint_BorderStyleNoneChange .
     // Furthermore, even though we know *this* side is 0 width, just
     // assume a visual hint for some other change rather than bother
     // tracking this result through the rest of the function.
@@ -1963,17 +1966,16 @@ nsStyleBackground::nsStyleBackground()
   , mClipCount(1)
   , mOriginCount(1)
   , mRepeatCount(1)
   , mPositionCount(1)
   , mImageCount(1)
   , mSizeCount(1)
   , mBlendModeCount(1)
   , mBackgroundColor(NS_RGBA(0, 0, 0, 0))
-  , mBackgroundInlinePolicy(NS_STYLE_BG_INLINE_POLICY_CONTINUOUS)
 {
   MOZ_COUNT_CTOR(nsStyleBackground);
   Layer *onlyLayer = mLayers.AppendElement();
   NS_ASSERTION(onlyLayer, "auto array must have room for 1 element");
   onlyLayer->SetInitialValues();
 }
 
 nsStyleBackground::nsStyleBackground(const nsStyleBackground& aSource)
@@ -1982,17 +1984,16 @@ nsStyleBackground::nsStyleBackground(con
   , mOriginCount(aSource.mOriginCount)
   , mRepeatCount(aSource.mRepeatCount)
   , mPositionCount(aSource.mPositionCount)
   , mImageCount(aSource.mImageCount)
   , mSizeCount(aSource.mSizeCount)
   , mBlendModeCount(aSource.mBlendModeCount)
   , mLayers(aSource.mLayers) // deep copy
   , mBackgroundColor(aSource.mBackgroundColor)
-  , mBackgroundInlinePolicy(aSource.mBackgroundInlinePolicy)
 {
   MOZ_COUNT_CTOR(nsStyleBackground);
   // If the deep copy of mLayers failed, truncate the counts.
   uint32_t count = mLayers.Length();
   if (count != aSource.mLayers.Length()) {
     NS_WARNING("truncating counts due to out-of-memory");
     mAttachmentCount = std::max(mAttachmentCount, count);
     mClipCount = std::max(mClipCount, count);
@@ -2040,19 +2041,17 @@ nsChangeHint nsStyleBackground::CalcDiff
       }
     } else {
       if (moreLayers->mLayers[i].mImage.GetType() == eStyleImageType_Element)
         return NS_CombineHint(nsChangeHint_UpdateEffects, NS_STYLE_HINT_VISUAL);
       hasVisualDifference = true;
     }
   }
 
-  if (hasVisualDifference ||
-      mBackgroundColor != aOther.mBackgroundColor ||
-      mBackgroundInlinePolicy != aOther.mBackgroundInlinePolicy)
+  if (hasVisualDifference || mBackgroundColor != aOther.mBackgroundColor)
     return NS_STYLE_HINT_VISUAL;
 
   return NS_STYLE_HINT_NONE;
 }
 
 bool nsStyleBackground::HasFixedBackground() const
 {
   NS_FOR_VISIBLE_BACKGROUND_LAYERS_BACK_TO_FRONT(i, this) {
--- a/layout/style/nsStyleStruct.h
+++ b/layout/style/nsStyleStruct.h
@@ -534,21 +534,16 @@ struct nsStyleBackground {
     for (uint32_t var_ = (stylebg_) ? (stylebg_)->mImageCount : 1; var_-- != 0; )
   #define NS_FOR_VISIBLE_BACKGROUND_LAYERS_BACK_TO_FRONT_WITH_RANGE(var_, stylebg_, start_, count_) \
     NS_ASSERTION((int32_t)(start_) >= 0 && (uint32_t)(start_) < ((stylebg_) ? (stylebg_)->mImageCount : 1), "Invalid layer start!"); \
     NS_ASSERTION((count_) > 0 && (count_) <= (start_) + 1, "Invalid layer range!"); \
     for (uint32_t var_ = (start_) + 1; var_-- != (uint32_t)((start_) + 1 - (count_)); )
 
   nscolor mBackgroundColor;       // [reset]
 
-  // FIXME: This (now background-break in css3-background) should
-  // probably move into a different struct so that everything in
-  // nsStyleBackground is set by the background shorthand.
-  uint8_t mBackgroundInlinePolicy; // [reset] See nsStyleConsts.h
-
   // True if this background is completely transparent.
   bool IsTransparent() const;
 
   // We have to take slower codepaths for fixed background attachment,
   // but we don't want to do that when there's no image.
   // Not inline because it uses an nsCOMPtr<imgIRequest>
   // FIXME: Should be in nsStyleStructInlines.h.
   bool HasFixedBackground() const;
@@ -981,16 +976,17 @@ public:
   nsStyleSides   mBorderImageSlice;   // [reset] factor, percent
   nsStyleSides   mBorderImageWidth;   // [reset] length, factor, percent, auto
   nsStyleSides   mBorderImageOutset;  // [reset] length, factor
 
   uint8_t        mBorderImageFill;    // [reset]
   uint8_t        mBorderImageRepeatH; // [reset] see nsStyleConsts.h
   uint8_t        mBorderImageRepeatV; // [reset]
   uint8_t        mFloatEdge;          // [reset]
+  uint8_t        mBoxDecorationBreak; // [reset] see nsStyleConsts.h
 
 protected:
   // mComputedBorder holds the CSS2.1 computed border-width values.
   // In particular, these widths take into account the border-style
   // for the relevant side, and the values are rounded to the nearest
   // device pixel (which is not part of the definition of computed
   // values). The presence or absence of a border-image does not
   // affect border-width values.
--- a/layout/style/test/property_database.js
+++ b/layout/style/test/property_database.js
@@ -1,5395 +1,5398 @@
-/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
-/* vim: set shiftwidth=4 tabstop=4 autoindent cindent noexpandtab: */
+/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 sw=2 sts=2 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/. */
 
 // True longhand properties.
 const CSS_TYPE_LONGHAND = 0;
 
 // True shorthand properties.
 const CSS_TYPE_TRUE_SHORTHAND = 1;
 
 // Properties that we handle as shorthands but were longhands either in
 // the current spec or earlier versions of the spec.
 const CSS_TYPE_SHORTHAND_AND_LONGHAND = 2;
 
 // Each property has the following fields:
-//	 domProp: The name of the relevant member of nsIDOM[NS]CSS2Properties
-//	 inherited: Whether the property is inherited by default (stated as
-//	   yes or no in the property header in all CSS specs)
-//	 type: see above
-//	 alias_for: optional, indicates that the property is an alias for
-//	   some other property that is the preferred serialization.  (Type
-//	   must not be CSS_TYPE_LONGHAND.)
-//	 get_computed: if present, the property's computed value shows up on
-//	   another property, and this is a function used to get it
-//	 initial_values: Values whose computed value should be the same as the
-//	   computed value for the property's initial value.
-//	 other_values: Values whose computed value should be different from the
-//	   computed value for the property's initial value.
-//	 XXX Should have a third field for values whose computed value may or
-//	   may not be the same as for the property's initial value.
-//	 invalid_values: Things that are not values for the property and
-//	   should be rejected, but which are balanced and should not absorb
-//	   what follows
-//	 quirks_values: Values that should be accepted in quirks mode only,
-//	   mapped to the values they are equivalent to.
-//	 unbalanced_values: Things that are not values for the property and
-//	   should be rejected, and which also contain unbalanced constructs
-//	   that should absorb what follows
+//   domProp: The name of the relevant member of nsIDOM[NS]CSS2Properties
+//   inherited: Whether the property is inherited by default (stated as
+//     yes or no in the property header in all CSS specs)
+//   type: see above
+//   alias_for: optional, indicates that the property is an alias for
+//     some other property that is the preferred serialization.  (Type
+//     must not be CSS_TYPE_LONGHAND.)
+//   get_computed: if present, the property's computed value shows up on
+//     another property, and this is a function used to get it
+//   initial_values: Values whose computed value should be the same as the
+//     computed value for the property's initial value.
+//   other_values: Values whose computed value should be different from the
+//     computed value for the property's initial value.
+//   XXX Should have a third field for values whose computed value may or
+//     may not be the same as for the property's initial value.
+//   invalid_values: Things that are not values for the property and
+//     should be rejected, but which are balanced and should not absorb
+//     what follows
+//   quirks_values: Values that should be accepted in quirks mode only,
+//     mapped to the values they are equivalent to.
+//   unbalanced_values: Things that are not values for the property and
+//     should be rejected, and which also contain unbalanced constructs
+//     that should absorb what follows
 
 // Helper functions used to construct gCSSProperties.
 
 function initial_font_family_is_sans_serif()
 {
-	// The initial value of 'font-family' might be 'serif' or
-	// 'sans-serif'.
-	var div = document.createElement("div");
-	div.setAttribute("style", "font: initial");
-	return getComputedStyle(div, "").fontFamily == "sans-serif";
+  // The initial value of 'font-family' might be 'serif' or
+  // 'sans-serif'.
+  var div = document.createElement("div");
+  div.setAttribute("style", "font: initial");
+  return getComputedStyle(div, "").fontFamily == "sans-serif";
 }
 var gInitialFontFamilyIsSansSerif = initial_font_family_is_sans_serif();
 
 // shared by background-image and border-image-source
 var validGradientAndElementValues = [
-	"-moz-element(#a)",
-	"-moz-element(  #a  )",
-	"-moz-element(#a-1)",
-	"-moz-element(#a\\:1)",
-	/* gradient torture test */
-	"linear-gradient(red, blue)",
-	"linear-gradient(red, yellow, blue)",
-	"linear-gradient(red 1px, yellow 20%, blue 24em, green)",
-	"linear-gradient(red, yellow, green, blue 50%)",
-	"linear-gradient(red -50%, yellow -25%, green, blue)",
-	"linear-gradient(red -99px, yellow, green, blue 120%)",
-	"linear-gradient(#ffff00, #ef3, rgba(10, 20, 30, 0.4))",
-	"linear-gradient(rgba(10, 20, 30, 0.4), #ffff00, #ef3)",
+  "-moz-element(#a)",
+  "-moz-element(  #a  )",
+  "-moz-element(#a-1)",
+  "-moz-element(#a\\:1)",
+  /* gradient torture test */
+  "linear-gradient(red, blue)",
+  "linear-gradient(red, yellow, blue)",
+  "linear-gradient(red 1px, yellow 20%, blue 24em, green)",
+  "linear-gradient(red, yellow, green, blue 50%)",
+  "linear-gradient(red -50%, yellow -25%, green, blue)",
+  "linear-gradient(red -99px, yellow, green, blue 120%)",
+  "linear-gradient(#ffff00, #ef3, rgba(10, 20, 30, 0.4))",
+  "linear-gradient(rgba(10, 20, 30, 0.4), #ffff00, #ef3)",
 
-	"linear-gradient(to top, red, blue)",
-	"linear-gradient(to bottom, red, blue)",
-	"linear-gradient(to left, red, blue)",
-	"linear-gradient(to right, red, blue)",
-	"linear-gradient(to top left, red, blue)",
-	"linear-gradient(to top right, red, blue)",
-	"linear-gradient(to bottom left, red, blue)",
-	"linear-gradient(to bottom right, red, blue)",
-	"linear-gradient(to left top, red, blue)",
-	"linear-gradient(to left bottom, red, blue)",
-	"linear-gradient(to right top, red, blue)",
-	"linear-gradient(to right bottom, red, blue)",
+  "linear-gradient(to top, red, blue)",
+  "linear-gradient(to bottom, red, blue)",
+  "linear-gradient(to left, red, blue)",
+  "linear-gradient(to right, red, blue)",
+  "linear-gradient(to top left, red, blue)",
+  "linear-gradient(to top right, red, blue)",
+  "linear-gradient(to bottom left, red, blue)",
+  "linear-gradient(to bottom right, red, blue)",
+  "linear-gradient(to left top, red, blue)",
+  "linear-gradient(to left bottom, red, blue)",
+  "linear-gradient(to right top, red, blue)",
+  "linear-gradient(to right bottom, red, blue)",
 
-	"linear-gradient(-33deg, red, blue)",
-	"linear-gradient(30grad, red, blue)",
-	"linear-gradient(10deg, red, blue)",
-	"linear-gradient(1turn, red, blue)",
-	"linear-gradient(.414rad, red, blue)",
+  "linear-gradient(-33deg, red, blue)",
+  "linear-gradient(30grad, red, blue)",
+  "linear-gradient(10deg, red, blue)",
+  "linear-gradient(1turn, red, blue)",
+  "linear-gradient(.414rad, red, blue)",
 
-	"-moz-linear-gradient(red, blue)",
-	"-moz-linear-gradient(red, yellow, blue)",
-	"-moz-linear-gradient(red 1px, yellow 20%, blue 24em, green)",
-	"-moz-linear-gradient(red, yellow, green, blue 50%)",
-	"-moz-linear-gradient(red -50%, yellow -25%, green, blue)",
-	"-moz-linear-gradient(red -99px, yellow, green, blue 120%)",
-	"-moz-linear-gradient(#ffff00, #ef3, rgba(10, 20, 30, 0.4))",
-	"-moz-linear-gradient(rgba(10, 20, 30, 0.4), #ffff00, #ef3)",
+  "-moz-linear-gradient(red, blue)",
+  "-moz-linear-gradient(red, yellow, blue)",
+  "-moz-linear-gradient(red 1px, yellow 20%, blue 24em, green)",
+  "-moz-linear-gradient(red, yellow, green, blue 50%)",
+  "-moz-linear-gradient(red -50%, yellow -25%, green, blue)",
+  "-moz-linear-gradient(red -99px, yellow, green, blue 120%)",
+  "-moz-linear-gradient(#ffff00, #ef3, rgba(10, 20, 30, 0.4))",
+  "-moz-linear-gradient(rgba(10, 20, 30, 0.4), #ffff00, #ef3)",
 
-	"-moz-linear-gradient(to top, red, blue)",
-	"-moz-linear-gradient(to bottom, red, blue)",
-	"-moz-linear-gradient(to left, red, blue)",
-	"-moz-linear-gradient(to right, red, blue)",
-	"-moz-linear-gradient(to top left, red, blue)",
-	"-moz-linear-gradient(to top right, red, blue)",
-	"-moz-linear-gradient(to bottom left, red, blue)",
-	"-moz-linear-gradient(to bottom right, red, blue)",
-	"-moz-linear-gradient(to left top, red, blue)",
-	"-moz-linear-gradient(to left bottom, red, blue)",
-	"-moz-linear-gradient(to right top, red, blue)",
-	"-moz-linear-gradient(to right bottom, red, blue)",
+  "-moz-linear-gradient(to top, red, blue)",
+  "-moz-linear-gradient(to bottom, red, blue)",
+  "-moz-linear-gradient(to left, red, blue)",
+  "-moz-linear-gradient(to right, red, blue)",
+  "-moz-linear-gradient(to top left, red, blue)",
+  "-moz-linear-gradient(to top right, red, blue)",
+  "-moz-linear-gradient(to bottom left, red, blue)",
+  "-moz-linear-gradient(to bottom right, red, blue)",
+  "-moz-linear-gradient(to left top, red, blue)",
+  "-moz-linear-gradient(to left bottom, red, blue)",
+  "-moz-linear-gradient(to right top, red, blue)",
+  "-moz-linear-gradient(to right bottom, red, blue)",
 
-	"-moz-linear-gradient(top left, red, blue)",
-	"-moz-linear-gradient(0 0, red, blue)",
-	"-moz-linear-gradient(20% bottom, red, blue)",
-	"-moz-linear-gradient(center 20%, red, blue)",
-	"-moz-linear-gradient(left 35px, red, blue)",
-	"-moz-linear-gradient(10% 10em, red, blue)",
-	"-moz-linear-gradient(44px top, red, blue)",
+  "-moz-linear-gradient(top left, red, blue)",
+  "-moz-linear-gradient(0 0, red, blue)",
+  "-moz-linear-gradient(20% bottom, red, blue)",
+  "-moz-linear-gradient(center 20%, red, blue)",
+  "-moz-linear-gradient(left 35px, red, blue)",
+  "-moz-linear-gradient(10% 10em, red, blue)",
+  "-moz-linear-gradient(44px top, red, blue)",
 
-	"-moz-linear-gradient(top left 45deg, red, blue)",
-	"-moz-linear-gradient(20% bottom -300deg, red, blue)",
-	"-moz-linear-gradient(center 20% 1.95929rad, red, blue)",
-	"-moz-linear-gradient(left 35px 30grad, red, blue)",
-	"-moz-linear-gradient(left 35px 0.1turn, red, blue)",
-	"-moz-linear-gradient(10% 10em 99999deg, red, blue)",
-	"-moz-linear-gradient(44px top -33deg, red, blue)",
+  "-moz-linear-gradient(top left 45deg, red, blue)",
+  "-moz-linear-gradient(20% bottom -300deg, red, blue)",
+  "-moz-linear-gradient(center 20% 1.95929rad, red, blue)",
+  "-moz-linear-gradient(left 35px 30grad, red, blue)",
+  "-moz-linear-gradient(left 35px 0.1turn, red, blue)",
+  "-moz-linear-gradient(10% 10em 99999deg, red, blue)",
+  "-moz-linear-gradient(44px top -33deg, red, blue)",
 
-	"-moz-linear-gradient(-33deg, red, blue)",
-	"-moz-linear-gradient(30grad left 35px, red, blue)",
-	"-moz-linear-gradient(10deg 20px, red, blue)",
-	"-moz-linear-gradient(1turn 20px, red, blue)",
-	"-moz-linear-gradient(.414rad bottom, red, blue)",
+  "-moz-linear-gradient(-33deg, red, blue)",
+  "-moz-linear-gradient(30grad left 35px, red, blue)",
+  "-moz-linear-gradient(10deg 20px, red, blue)",
+  "-moz-linear-gradient(1turn 20px, red, blue)",
+  "-moz-linear-gradient(.414rad bottom, red, blue)",
 
-	"-moz-linear-gradient(blue calc(0px) ,green calc(25%) ,red calc(40px) ,blue calc(60px) , yellow  calc(100px))",
-	"-moz-linear-gradient(-33deg, blue calc(-25%) ,red 40px)",
-	"-moz-linear-gradient(10deg, blue calc(100px + -25%),red calc(40px))",
-	"-moz-linear-gradient(10deg, blue calc(-25px),red calc(100%))",
-	"-moz-linear-gradient(.414rad, blue calc(100px + -25px) ,green calc(100px + -25px) ,red calc(100px + -25%) ,blue calc(-25px) , yellow  calc(-25px))",
-	"-moz-linear-gradient(1turn, blue calc(-25%) ,green calc(25px) ,red calc(25%),blue calc(0px),white 50px, yellow  calc(-25px))",
+  "-moz-linear-gradient(blue calc(0px) ,green calc(25%) ,red calc(40px) ,blue calc(60px) , yellow  calc(100px))",
+  "-moz-linear-gradient(-33deg, blue calc(-25%) ,red 40px)",
+  "-moz-linear-gradient(10deg, blue calc(100px + -25%),red calc(40px))",
+  "-moz-linear-gradient(10deg, blue calc(-25px),red calc(100%))",
+  "-moz-linear-gradient(.414rad, blue calc(100px + -25px) ,green calc(100px + -25px) ,red calc(100px + -25%) ,blue calc(-25px) , yellow  calc(-25px))",
+  "-moz-linear-gradient(1turn, blue calc(-25%) ,green calc(25px) ,red calc(25%),blue calc(0px),white 50px, yellow  calc(-25px))",
 
-	"radial-gradient(red, blue)",
-	"radial-gradient(red, yellow, blue)",
-	"radial-gradient(red 1px, yellow 20%, blue 24em, green)",
-	"radial-gradient(red, yellow, green, blue 50%)",
-	"radial-gradient(red -50%, yellow -25%, green, blue)",
-	"radial-gradient(red -99px, yellow, green, blue 120%)",
-	"radial-gradient(#ffff00, #ef3, rgba(10, 20, 30, 0.4))",
+  "radial-gradient(red, blue)",
+  "radial-gradient(red, yellow, blue)",
+  "radial-gradient(red 1px, yellow 20%, blue 24em, green)",
+  "radial-gradient(red, yellow, green, blue 50%)",
+  "radial-gradient(red -50%, yellow -25%, green, blue)",
+  "radial-gradient(red -99px, yellow, green, blue 120%)",
+  "radial-gradient(#ffff00, #ef3, rgba(10, 20, 30, 0.4))",
 
-	"radial-gradient(0 0, red, blue)",
-	"radial-gradient(rgba(10, 20, 30, 0.4), #ffff00, #ef3)",
+  "radial-gradient(0 0, red, blue)",
+  "radial-gradient(rgba(10, 20, 30, 0.4), #ffff00, #ef3)",
 
-	"radial-gradient(at top left, red, blue)",
-	"radial-gradient(at 20% bottom, red, blue)",
-	"radial-gradient(at center 20%, red, blue)",
-	"radial-gradient(at left 35px, red, blue)",
-	"radial-gradient(at 10% 10em, red, blue)",
-	"radial-gradient(at 44px top, red, blue)",
-	"radial-gradient(at 0 0, red, blue)",
+  "radial-gradient(at top left, red, blue)",
+  "radial-gradient(at 20% bottom, red, blue)",
+  "radial-gradient(at center 20%, red, blue)",
+  "radial-gradient(at left 35px, red, blue)",
+  "radial-gradient(at 10% 10em, red, blue)",
+  "radial-gradient(at 44px top, red, blue)",
+  "radial-gradient(at 0 0, red, blue)",
 
-	"radial-gradient(farthest-corner, red, blue)",
-	"radial-gradient(circle, red, blue)",
-	"radial-gradient(ellipse closest-corner, red, blue)",
-	"radial-gradient(closest-corner ellipse, red, blue)",
+  "radial-gradient(farthest-corner, red, blue)",
+  "radial-gradient(circle, red, blue)",
+  "radial-gradient(ellipse closest-corner, red, blue)",
+  "radial-gradient(closest-corner ellipse, red, blue)",
 
-	"radial-gradient(43px, red, blue)",
-	"radial-gradient(43px 43px, red, blue)",
-	"radial-gradient(50% 50%, red, blue)",
-	"radial-gradient(43px 50%, red, blue)",
-	"radial-gradient(50% 43px, red, blue)",
-	"radial-gradient(circle 43px, red, blue)",
-	"radial-gradient(43px circle, red, blue)",
-	"radial-gradient(ellipse 43px 43px, red, blue)",
-	"radial-gradient(ellipse 50% 50%, red, blue)",
-	"radial-gradient(ellipse 43px 50%, red, blue)",
-	"radial-gradient(ellipse 50% 43px, red, blue)",
-	"radial-gradient(50% 43px ellipse, red, blue)",
+  "radial-gradient(43px, red, blue)",
+  "radial-gradient(43px 43px, red, blue)",
+  "radial-gradient(50% 50%, red, blue)",
+  "radial-gradient(43px 50%, red, blue)",
+  "radial-gradient(50% 43px, red, blue)",
+  "radial-gradient(circle 43px, red, blue)",
+  "radial-gradient(43px circle, red, blue)",
+  "radial-gradient(ellipse 43px 43px, red, blue)",
+  "radial-gradient(ellipse 50% 50%, red, blue)",
+  "radial-gradient(ellipse 43px 50%, red, blue)",
+  "radial-gradient(ellipse 50% 43px, red, blue)",
+  "radial-gradient(50% 43px ellipse, red, blue)",
 
-	"radial-gradient(farthest-corner at top left, red, blue)",
-	"radial-gradient(ellipse closest-corner at 45px, red, blue)",
-	"radial-gradient(circle farthest-side at 45px, red, blue)",
-	"radial-gradient(closest-side ellipse at 50%, red, blue)",
-	"radial-gradient(farthest-corner circle at 4em, red, blue)",
+  "radial-gradient(farthest-corner at top left, red, blue)",
+  "radial-gradient(ellipse closest-corner at 45px, red, blue)",
+  "radial-gradient(circle farthest-side at 45px, red, blue)",
+  "radial-gradient(closest-side ellipse at 50%, red, blue)",
+  "radial-gradient(farthest-corner circle at 4em, red, blue)",
 
-	"radial-gradient(30% 40% at top left, red, blue)",
-	"radial-gradient(50px 60px at 15% 20%, red, blue)",
-	"radial-gradient(7em 8em at 45px, red, blue)",
+  "radial-gradient(30% 40% at top left, red, blue)",
+  "radial-gradient(50px 60px at 15% 20%, red, blue)",
+  "radial-gradient(7em 8em at 45px, red, blue)",
 
-	"-moz-radial-gradient(red, blue)",
-	"-moz-radial-gradient(red, yellow, blue)",
-	"-moz-radial-gradient(red 1px, yellow 20%, blue 24em, green)",
-	"-moz-radial-gradient(red, yellow, green, blue 50%)",
-	"-moz-radial-gradient(red -50%, yellow -25%, green, blue)",
-	"-moz-radial-gradient(red -99px, yellow, green, blue 120%)",
-	"-moz-radial-gradient(#ffff00, #ef3, rgba(10, 20, 30, 0.4))",
+  "-moz-radial-gradient(red, blue)",
+  "-moz-radial-gradient(red, yellow, blue)",
+  "-moz-radial-gradient(red 1px, yellow 20%, blue 24em, green)",
+  "-moz-radial-gradient(red, yellow, green, blue 50%)",
+  "-moz-radial-gradient(red -50%, yellow -25%, green, blue)",
+  "-moz-radial-gradient(red -99px, yellow, green, blue 120%)",
+  "-moz-radial-gradient(#ffff00, #ef3, rgba(10, 20, 30, 0.4))",
 
-	"-moz-radial-gradient(top left, red, blue)",
-	"-moz-radial-gradient(20% bottom, red, blue)",
-	"-moz-radial-gradient(center 20%, red, blue)",
-	"-moz-radial-gradient(left 35px, red, blue)",
-	"-moz-radial-gradient(10% 10em, red, blue)",
-	"-moz-radial-gradient(44px top, red, blue)",
+  "-moz-radial-gradient(top left, red, blue)",
+  "-moz-radial-gradient(20% bottom, red, blue)",
+  "-moz-radial-gradient(center 20%, red, blue)",
+  "-moz-radial-gradient(left 35px, red, blue)",
+  "-moz-radial-gradient(10% 10em, red, blue)",
+  "-moz-radial-gradient(44px top, red, blue)",
 
-	"-moz-radial-gradient(top left 45deg, red, blue)",
-	"-moz-radial-gradient(0 0, red, blue)",
-	"-moz-radial-gradient(20% bottom -300deg, red, blue)",
-	"-moz-radial-gradient(center 20% 1.95929rad, red, blue)",
-	"-moz-radial-gradient(left 35px 30grad, red, blue)",
-	"-moz-radial-gradient(10% 10em 99999deg, red, blue)",
-	"-moz-radial-gradient(44px top -33deg, red, blue)",
-	"-moz-radial-gradient(rgba(10, 20, 30, 0.4), #ffff00, #ef3)",
+  "-moz-radial-gradient(top left 45deg, red, blue)",
+  "-moz-radial-gradient(0 0, red, blue)",
+  "-moz-radial-gradient(20% bottom -300deg, red, blue)",
+  "-moz-radial-gradient(center 20% 1.95929rad, red, blue)",
+  "-moz-radial-gradient(left 35px 30grad, red, blue)",
+  "-moz-radial-gradient(10% 10em 99999deg, red, blue)",
+  "-moz-radial-gradient(44px top -33deg, red, blue)",
+  "-moz-radial-gradient(rgba(10, 20, 30, 0.4), #ffff00, #ef3)",
 
-	"-moz-radial-gradient(-33deg, red, blue)",
-	"-moz-radial-gradient(30grad left 35px, red, blue)",
-	"-moz-radial-gradient(10deg 20px, red, blue)",
-	"-moz-radial-gradient(.414rad bottom, red, blue)",
+  "-moz-radial-gradient(-33deg, red, blue)",
+  "-moz-radial-gradient(30grad left 35px, red, blue)",
+  "-moz-radial-gradient(10deg 20px, red, blue)",
+  "-moz-radial-gradient(.414rad bottom, red, blue)",
 
-	"-moz-radial-gradient(cover, red, blue)",
-	"-moz-radial-gradient(circle, red, blue)",
-	"-moz-radial-gradient(ellipse closest-corner, red, blue)",
-	"-moz-radial-gradient(farthest-side circle, red, blue)",
+  "-moz-radial-gradient(cover, red, blue)",
+  "-moz-radial-gradient(circle, red, blue)",
+  "-moz-radial-gradient(ellipse closest-corner, red, blue)",
+  "-moz-radial-gradient(farthest-side circle, red, blue)",
 
-	"-moz-radial-gradient(top left, cover, red, blue)",
-	"-moz-radial-gradient(15% 20%, circle, red, blue)",
-	"-moz-radial-gradient(45px, ellipse closest-corner, red, blue)",
-	"-moz-radial-gradient(45px, farthest-side circle, red, blue)",
+  "-moz-radial-gradient(top left, cover, red, blue)",
+  "-moz-radial-gradient(15% 20%, circle, red, blue)",
+  "-moz-radial-gradient(45px, ellipse closest-corner, red, blue)",
+  "-moz-radial-gradient(45px, farthest-side circle, red, blue)",
 
-	"-moz-radial-gradient(99deg, cover, red, blue)",
-	"-moz-radial-gradient(-1.2345rad, circle, red, blue)",
-	"-moz-radial-gradient(399grad, ellipse closest-corner, red, blue)",
-	"-moz-radial-gradient(399grad, farthest-side circle, red, blue)",
+  "-moz-radial-gradient(99deg, cover, red, blue)",
+  "-moz-radial-gradient(-1.2345rad, circle, red, blue)",
+  "-moz-radial-gradient(399grad, ellipse closest-corner, red, blue)",
+  "-moz-radial-gradient(399grad, farthest-side circle, red, blue)",
 
-	"-moz-radial-gradient(top left 99deg, cover, red, blue)",
-	"-moz-radial-gradient(15% 20% -1.2345rad, circle, red, blue)",
-	"-moz-radial-gradient(45px 399grad, ellipse closest-corner, red, blue)",
-	"-moz-radial-gradient(45px 399grad, farthest-side circle, red, blue)",
+  "-moz-radial-gradient(top left 99deg, cover, red, blue)",
+  "-moz-radial-gradient(15% 20% -1.2345rad, circle, red, blue)",
+  "-moz-radial-gradient(45px 399grad, ellipse closest-corner, red, blue)",
+  "-moz-radial-gradient(45px 399grad, farthest-side circle, red, blue)",
 
-	"-moz-repeating-linear-gradient(red, blue)",
-	"-moz-repeating-linear-gradient(red, yellow, blue)",
-	"-moz-repeating-linear-gradient(red 1px, yellow 20%, blue 24em, green)",
-	"-moz-repeating-linear-gradient(red, yellow, green, blue 50%)",
-	"-moz-repeating-linear-gradient(red -50%, yellow -25%, green, blue)",
-	"-moz-repeating-linear-gradient(red -99px, yellow, green, blue 120%)",
-	"-moz-repeating-linear-gradient(#ffff00, #ef3, rgba(10, 20, 30, 0.4))",
-	"-moz-repeating-linear-gradient(rgba(10, 20, 30, 0.4), #ffff00, #ef3)",
+  "-moz-repeating-linear-gradient(red, blue)",
+  "-moz-repeating-linear-gradient(red, yellow, blue)",
+  "-moz-repeating-linear-gradient(red 1px, yellow 20%, blue 24em, green)",
+  "-moz-repeating-linear-gradient(red, yellow, green, blue 50%)",
+  "-moz-repeating-linear-gradient(red -50%, yellow -25%, green, blue)",
+  "-moz-repeating-linear-gradient(red -99px, yellow, green, blue 120%)",
+  "-moz-repeating-linear-gradient(#ffff00, #ef3, rgba(10, 20, 30, 0.4))",
+  "-moz-repeating-linear-gradient(rgba(10, 20, 30, 0.4), #ffff00, #ef3)",
 
-	"-moz-repeating-linear-gradient(to top, red, blue)",
-	"-moz-repeating-linear-gradient(to bottom, red, blue)",
-	"-moz-repeating-linear-gradient(to left, red, blue)",
-	"-moz-repeating-linear-gradient(to right, red, blue)",
-	"-moz-repeating-linear-gradient(to top left, red, blue)",
-	"-moz-repeating-linear-gradient(to top right, red, blue)",
-	"-moz-repeating-linear-gradient(to bottom left, red, blue)",
-	"-moz-repeating-linear-gradient(to bottom right, red, blue)",
-	"-moz-repeating-linear-gradient(to left top, red, blue)",
-	"-moz-repeating-linear-gradient(to left bottom, red, blue)",
-	"-moz-repeating-linear-gradient(to right top, red, blue)",
-	"-moz-repeating-linear-gradient(to right bottom, red, blue)",
+  "-moz-repeating-linear-gradient(to top, red, blue)",
+  "-moz-repeating-linear-gradient(to bottom, red, blue)",
+  "-moz-repeating-linear-gradient(to left, red, blue)",
+  "-moz-repeating-linear-gradient(to right, red, blue)",
+  "-moz-repeating-linear-gradient(to top left, red, blue)",
+  "-moz-repeating-linear-gradient(to top right, red, blue)",
+  "-moz-repeating-linear-gradient(to bottom left, red, blue)",
+  "-moz-repeating-linear-gradient(to bottom right, red, blue)",
+  "-moz-repeating-linear-gradient(to left top, red, blue)",
+  "-moz-repeating-linear-gradient(to left bottom, red, blue)",
+  "-moz-repeating-linear-gradient(to right top, red, blue)",
+  "-moz-repeating-linear-gradient(to right bottom, red, blue)",
 
-	"-moz-repeating-linear-gradient(top left, red, blue)",
-	"-moz-repeating-linear-gradient(0 0, red, blue)",
-	"-moz-repeating-linear-gradient(20% bottom, red, blue)",
-	"-moz-repeating-linear-gradient(center 20%, red, blue)",
-	"-moz-repeating-linear-gradient(left 35px, red, blue)",
-	"-moz-repeating-linear-gradient(10% 10em, red, blue)",
-	"-moz-repeating-linear-gradient(44px top, red, blue)",
+  "-moz-repeating-linear-gradient(top left, red, blue)",
+  "-moz-repeating-linear-gradient(0 0, red, blue)",
+  "-moz-repeating-linear-gradient(20% bottom, red, blue)",
+  "-moz-repeating-linear-gradient(center 20%, red, blue)",
+  "-moz-repeating-linear-gradient(left 35px, red, blue)",
+  "-moz-repeating-linear-gradient(10% 10em, red, blue)",
+  "-moz-repeating-linear-gradient(44px top, red, blue)",
 
-	"-moz-repeating-linear-gradient(top left 45deg, red, blue)",
-	"-moz-repeating-linear-gradient(20% bottom -300deg, red, blue)",
-	"-moz-repeating-linear-gradient(center 20% 1.95929rad, red, blue)",
-	"-moz-repeating-linear-gradient(left 35px 30grad, red, blue)",
-	"-moz-repeating-linear-gradient(10% 10em 99999deg, red, blue)",
-	"-moz-repeating-linear-gradient(44px top -33deg, red, blue)",
+  "-moz-repeating-linear-gradient(top left 45deg, red, blue)",
+  "-moz-repeating-linear-gradient(20% bottom -300deg, red, blue)",
+  "-moz-repeating-linear-gradient(center 20% 1.95929rad, red, blue)",
+  "-moz-repeating-linear-gradient(left 35px 30grad, red, blue)",
+  "-moz-repeating-linear-gradient(10% 10em 99999deg, red, blue)",
+  "-moz-repeating-linear-gradient(44px top -33deg, red, blue)",
 
-	"-moz-repeating-linear-gradient(-33deg, red, blue)",
-	"-moz-repeating-linear-gradient(30grad left 35px, red, blue)",
-	"-moz-repeating-linear-gradient(10deg 20px, red, blue)",
-	"-moz-repeating-linear-gradient(.414rad bottom, red, blue)",
+  "-moz-repeating-linear-gradient(-33deg, red, blue)",
+  "-moz-repeating-linear-gradient(30grad left 35px, red, blue)",
+  "-moz-repeating-linear-gradient(10deg 20px, red, blue)",
+  "-moz-repeating-linear-gradient(.414rad bottom, red, blue)",
 
-	"-moz-repeating-radial-gradient(red, blue)",
-	"-moz-repeating-radial-gradient(red, yellow, blue)",
-	"-moz-repeating-radial-gradient(red 1px, yellow 20%, blue 24em, green)",
-	"-moz-repeating-radial-gradient(red, yellow, green, blue 50%)",
-	"-moz-repeating-radial-gradient(red -50%, yellow -25%, green, blue)",
-	"-moz-repeating-radial-gradient(red -99px, yellow, green, blue 120%)",
-	"-moz-repeating-radial-gradient(#ffff00, #ef3, rgba(10, 20, 30, 0.4))",
-	"-moz-repeating-radial-gradient(rgba(10, 20, 30, 0.4), #ffff00, #ef3)",
+  "-moz-repeating-radial-gradient(red, blue)",
+  "-moz-repeating-radial-gradient(red, yellow, blue)",
+  "-moz-repeating-radial-gradient(red 1px, yellow 20%, blue 24em, green)",
+  "-moz-repeating-radial-gradient(red, yellow, green, blue 50%)",
+  "-moz-repeating-radial-gradient(red -50%, yellow -25%, green, blue)",
+  "-moz-repeating-radial-gradient(red -99px, yellow, green, blue 120%)",
+  "-moz-repeating-radial-gradient(#ffff00, #ef3, rgba(10, 20, 30, 0.4))",
+  "-moz-repeating-radial-gradient(rgba(10, 20, 30, 0.4), #ffff00, #ef3)",
 
-	"repeating-radial-gradient(at top left, red, blue)",
-	"repeating-radial-gradient(at 0 0, red, blue)",
-	"repeating-radial-gradient(at 20% bottom, red, blue)",
-	"repeating-radial-gradient(at center 20%, red, blue)",
-	"repeating-radial-gradient(at left 35px, red, blue)",
-	"repeating-radial-gradient(at 10% 10em, red, blue)",
-	"repeating-radial-gradient(at 44px top, red, blue)",
+  "repeating-radial-gradient(at top left, red, blue)",
+  "repeating-radial-gradient(at 0 0, red, blue)",
+  "repeating-radial-gradient(at 20% bottom, red, blue)",
+  "repeating-radial-gradient(at center 20%, red, blue)",
+  "repeating-radial-gradient(at left 35px, red, blue)",
+  "repeating-radial-gradient(at 10% 10em, red, blue)",
+  "repeating-radial-gradient(at 44px top, red, blue)",
 
-	"-moz-repeating-radial-gradient(farthest-corner, red, blue)",
-	"-moz-repeating-radial-gradient(circle, red, blue)",
-	"-moz-repeating-radial-gradient(ellipse closest-corner, red, blue)",
+  "-moz-repeating-radial-gradient(farthest-corner, red, blue)",
+  "-moz-repeating-radial-gradient(circle, red, blue)",
+  "-moz-repeating-radial-gradient(ellipse closest-corner, red, blue)",
 
-	"repeating-radial-gradient(farthest-corner at top left, red, blue)",
-	"repeating-radial-gradient(closest-corner ellipse at 45px, red, blue)",
-	"repeating-radial-gradient(farthest-side circle at 45px, red, blue)",
-	"repeating-radial-gradient(ellipse closest-side at 50%, red, blue)",
-	"repeating-radial-gradient(circle farthest-corner at 4em, red, blue)",
+  "repeating-radial-gradient(farthest-corner at top left, red, blue)",
+  "repeating-radial-gradient(closest-corner ellipse at 45px, red, blue)",
+  "repeating-radial-gradient(farthest-side circle at 45px, red, blue)",
+  "repeating-radial-gradient(ellipse closest-side at 50%, red, blue)",
+  "repeating-radial-gradient(circle farthest-corner at 4em, red, blue)",
 
-	"repeating-radial-gradient(30% 40% at top left, red, blue)",
-	"repeating-radial-gradient(50px 60px at 15% 20%, red, blue)",
-	"repeating-radial-gradient(7em 8em at 45px, red, blue)",
+  "repeating-radial-gradient(30% 40% at top left, red, blue)",
+  "repeating-radial-gradient(50px 60px at 15% 20%, red, blue)",
+  "repeating-radial-gradient(7em 8em at 45px, red, blue)",
 
-	"-moz-image-rect(url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAKElEQVR42u3NQQ0AAAgEoNP+nTWFDzcoQE1udQQCgUAgEAgEAsGTYAGjxAE/G/Q2tQAAAABJRU5ErkJggg==), 2, 10, 10, 2)",
-	"-moz-image-rect(url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAKElEQVR42u3NQQ0AAAgEoNP+nTWFDzcoQE1udQQCgUAgEAgEAsGTYAGjxAE/G/Q2tQAAAABJRU5ErkJggg==), 10%, 50%, 30%, 0%)",
-	"-moz-image-rect(url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAKElEQVR42u3NQQ0AAAgEoNP+nTWFDzcoQE1udQQCgUAgEAgEAsGTYAGjxAE/G/Q2tQAAAABJRU5ErkJggg==), 10, 50%, 30%, 0)",
+  "-moz-image-rect(url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAKElEQVR42u3NQQ0AAAgEoNP+nTWFDzcoQE1udQQCgUAgEAgEAsGTYAGjxAE/G/Q2tQAAAABJRU5ErkJggg==), 2, 10, 10, 2)",
+  "-moz-image-rect(url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAKElEQVR42u3NQQ0AAAgEoNP+nTWFDzcoQE1udQQCgUAgEAgEAsGTYAGjxAE/G/Q2tQAAAABJRU5ErkJggg==), 10%, 50%, 30%, 0%)",
+  "-moz-image-rect(url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAKElEQVR42u3NQQ0AAAgEoNP+nTWFDzcoQE1udQQCgUAgEAgEAsGTYAGjxAE/G/Q2tQAAAABJRU5ErkJggg==), 10, 50%, 30%, 0)",
 
-	"-moz-radial-gradient(calc(25%) top, red, blue)",
-	"-moz-radial-gradient(left calc(25%), red, blue)",
-	"-moz-radial-gradient(calc(25px) top, red, blue)",
-	"-moz-radial-gradient(left calc(25px), red, blue)",
-	"-moz-radial-gradient(calc(-25%) top, red, blue)",
-	"-moz-radial-gradient(left calc(-25%), red, blue)",
-	"-moz-radial-gradient(calc(-25px) top, red, blue)",
-	"-moz-radial-gradient(left calc(-25px), red, blue)",
-	"-moz-radial-gradient(calc(100px + -25%) top, red, blue)",
-	"-moz-radial-gradient(left calc(100px + -25%), red, blue)",
-	"-moz-radial-gradient(calc(100px + -25px) top, red, blue)",
-	"-moz-radial-gradient(left calc(100px + -25px), red, blue)"
+  "-moz-radial-gradient(calc(25%) top, red, blue)",
+  "-moz-radial-gradient(left calc(25%), red, blue)",
+  "-moz-radial-gradient(calc(25px) top, red, blue)",
+  "-moz-radial-gradient(left calc(25px), red, blue)",
+  "-moz-radial-gradient(calc(-25%) top, red, blue)",
+  "-moz-radial-gradient(left calc(-25%), red, blue)",
+  "-moz-radial-gradient(calc(-25px) top, red, blue)",
+  "-moz-radial-gradient(left calc(-25px), red, blue)",
+  "-moz-radial-gradient(calc(100px + -25%) top, red, blue)",
+  "-moz-radial-gradient(left calc(100px + -25%), red, blue)",
+  "-moz-radial-gradient(calc(100px + -25px) top, red, blue)",
+  "-moz-radial-gradient(left calc(100px + -25px), red, blue)"
 ];
 var invalidGradientAndElementValues = [
-	"-moz-element(#a:1)",
-	"-moz-element(a#a)",
-	"-moz-element(#a a)",
-	"-moz-element(#a+a)",
-	"-moz-element(#a())",
-	/* no quirks mode colors */
-	"linear-gradient(red, ff00ff)",
-	/* no quirks mode colors */
-	"-moz-radial-gradient(10% bottom, ffffff, black) scroll no-repeat",
-	/* no quirks mode lengths */
-	"-moz-linear-gradient(10 10px -45deg, red, blue) repeat",
-	"-moz-linear-gradient(10px 10 -45deg, red, blue) repeat",
-	"linear-gradient(red -99, yellow, green, blue 120%)",
-	/* Old syntax */
-	"-moz-linear-gradient(10px 10px, 20px, 30px 30px, 40px, from(blue), to(red))",
-	"-moz-radial-gradient(20px 20px, 10px 10px, from(green), to(#ff00ff))",
-	"-moz-radial-gradient(10px 10px, 20%, 40px 40px, 10px, from(green), to(#ff00ff))",
-	"-moz-linear-gradient(10px, 20px, 30px, 40px, color-stop(0.5, #00ccff))",
-	"-moz-linear-gradient(20px 20px, from(blue), to(red))",
-	"-moz-linear-gradient(40px 40px, 10px 10px, from(blue) to(red) color-stop(10%, fuchsia))",
-	"-moz-linear-gradient(20px 20px 30px, 10px 10px, from(red), to(#ff0000))",
-	"-moz-radial-gradient(left top, center, 20px 20px, 10px, from(blue), to(red))",
-	"-moz-linear-gradient(left left, top top, from(blue))",
-	"-moz-linear-gradient(inherit, 10px 10px, from(blue))",
-	/* New syntax */
-	"-moz-linear-gradient(10px 10px, 20px, 30px 30px, 40px, blue 0, red 100%)",
-	"-moz-radial-gradient(20px 20px, 10px 10px, from(green), to(#ff00ff))",
-	"-moz-radial-gradient(10px 10px, 20%, 40px 40px, 10px, from(green), to(#ff00ff))",
-	"-moz-linear-gradient(10px, 20px, 30px, 40px, #00ccff 50%)",
-	"-moz-linear-gradient(40px 40px, 10px 10px, blue 0 fuchsia 10% red 100%)",
-	"-moz-linear-gradient(20px 20px 30px, 10px 10px, red 0, #ff0000 100%)",
-	"-moz-radial-gradient(left top, center, 20px 20px, 10px, from(blue), to(red))",
-	"-moz-linear-gradient(left left, top top, blue 0)",
-	"-moz-linear-gradient(inherit, 10px 10px, blue 0)",
-	"-moz-linear-gradient(left left blue red)",
-	"-moz-linear-gradient(left left blue, red)",
-	"-moz-linear-gradient()",
-	"-moz-linear-gradient(cover, red, blue)",
-	"-moz-linear-gradient(auto, red, blue)",
-	"-moz-linear-gradient(22 top, red, blue)",
-	"-moz-linear-gradient(10% red blue)",
-	"-moz-linear-gradient(10%, red blue)",
-	"-moz-linear-gradient(10%,, red, blue)",
-	"-moz-linear-gradient(45px, center, red, blue)",
-	"-moz-linear-gradient(45px, center red, blue)",
-	"-moz-radial-gradient(contain, ellipse, red, blue)",
-	"-moz-radial-gradient(10deg contain, red, blue)",
-	"-moz-radial-gradient(10deg, contain,, red, blue)",
-	"-moz-radial-gradient(contain contain, red, blue)",
-	"-moz-radial-gradient(ellipse circle, red, blue)",
-	"-moz-radial-gradient(to top left, red, blue)",
-	"-moz-radial-gradient(center, 10%, red, blue)",
-	"-moz-radial-gradient(5rad, 20px, red, blue)",
-	"-moz-radial-gradient(40%, -100px -10%, red, blue)",
+  "-moz-element(#a:1)",
+  "-moz-element(a#a)",
+  "-moz-element(#a a)",
+  "-moz-element(#a+a)",
+  "-moz-element(#a())",
+  /* no quirks mode colors */
+  "linear-gradient(red, ff00ff)",
+  /* no quirks mode colors */
+  "-moz-radial-gradient(10% bottom, ffffff, black) scroll no-repeat",
+  /* no quirks mode lengths */
+  "-moz-linear-gradient(10 10px -45deg, red, blue) repeat",
+  "-moz-linear-gradient(10px 10 -45deg, red, blue) repeat",
+  "linear-gradient(red -99, yellow, green, blue 120%)",
+  /* Old syntax */
+  "-moz-linear-gradient(10px 10px, 20px, 30px 30px, 40px, from(blue), to(red))",
+  "-moz-radial-gradient(20px 20px, 10px 10px, from(green), to(#ff00ff))",
+  "-moz-radial-gradient(10px 10px, 20%, 40px 40px, 10px, from(green), to(#ff00ff))",
+  "-moz-linear-gradient(10px, 20px, 30px, 40px, color-stop(0.5, #00ccff))",
+  "-moz-linear-gradient(20px 20px, from(blue), to(red))",
+  "-moz-linear-gradient(40px 40px, 10px 10px, from(blue) to(red) color-stop(10%, fuchsia))",
+  "-moz-linear-gradient(20px 20px 30px, 10px 10px, from(red), to(#ff0000))",
+  "-moz-radial-gradient(left top, center, 20px 20px, 10px, from(blue), to(red))",
+  "-moz-linear-gradient(left left, top top, from(blue))",
+  "-moz-linear-gradient(inherit, 10px 10px, from(blue))",
+  /* New syntax */
+  "-moz-linear-gradient(10px 10px, 20px, 30px 30px, 40px, blue 0, red 100%)",
+  "-moz-radial-gradient(20px 20px, 10px 10px, from(green), to(#ff00ff))",
+  "-moz-radial-gradient(10px 10px, 20%, 40px 40px, 10px, from(green), to(#ff00ff))",
+  "-moz-linear-gradient(10px, 20px, 30px, 40px, #00ccff 50%)",
+  "-moz-linear-gradient(40px 40px, 10px 10px, blue 0 fuchsia 10% red 100%)",
+  "-moz-linear-gradient(20px 20px 30px, 10px 10px, red 0, #ff0000 100%)",
+  "-moz-radial-gradient(left top, center, 20px 20px, 10px, from(blue), to(red))",
+  "-moz-linear-gradient(left left, top top, blue 0)",
+  "-moz-linear-gradient(inherit, 10px 10px, blue 0)",
+  "-moz-linear-gradient(left left blue red)",
+  "-moz-linear-gradient(left left blue, red)",
+  "-moz-linear-gradient()",
+  "-moz-linear-gradient(cover, red, blue)",
+  "-moz-linear-gradient(auto, red, blue)",
+  "-moz-linear-gradient(22 top, red, blue)",
+  "-moz-linear-gradient(10% red blue)",
+  "-moz-linear-gradient(10%, red blue)",
+  "-moz-linear-gradient(10%,, red, blue)",
+  "-moz-linear-gradient(45px, center, red, blue)",
+  "-moz-linear-gradient(45px, center red, blue)",
+  "-moz-radial-gradient(contain, ellipse, red, blue)",
+  "-moz-radial-gradient(10deg contain, red, blue)",
+  "-moz-radial-gradient(10deg, contain,, red, blue)",
+  "-moz-radial-gradient(contain contain, red, blue)",
+  "-moz-radial-gradient(ellipse circle, red, blue)",
+  "-moz-radial-gradient(to top left, red, blue)",
+  "-moz-radial-gradient(center, 10%, red, blue)",
+  "-moz-radial-gradient(5rad, 20px, red, blue)",
+  "-moz-radial-gradient(40%, -100px -10%, red, blue)",
 
-	"-moz-radial-gradient(at top left to cover, red, blue)",
-	"-moz-radial-gradient(at 15% 20% circle, red, blue)",
+  "-moz-radial-gradient(at top left to cover, red, blue)",
+  "-moz-radial-gradient(at 15% 20% circle, red, blue)",
 
-	"-moz-radial-gradient(to cover, red, blue)",
-	"-moz-radial-gradient(to contain, red, blue)",
-	"-moz-radial-gradient(to closest-side circle, red, blue)",
-	"-moz-radial-gradient(to farthest-corner ellipse, red, blue)",
+  "-moz-radial-gradient(to cover, red, blue)",
+  "-moz-radial-gradient(to contain, red, blue)",
+  "-moz-radial-gradient(to closest-side circle, red, blue)",
+  "-moz-radial-gradient(to farthest-corner ellipse, red, blue)",
 
-	"-moz-radial-gradient(ellipse at 45px closest-corner, red, blue)",
-	"-moz-radial-gradient(circle at 45px farthest-side, red, blue)",
-	"-moz-radial-gradient(ellipse 45px, closest-side, red, blue)",
-	"-moz-radial-gradient(circle 45px, farthest-corner, red, blue)",
-	"-moz-radial-gradient(ellipse, ellipse closest-side, red, blue)",
-	"-moz-radial-gradient(circle, circle farthest-corner, red, blue)",
+  "-moz-radial-gradient(ellipse at 45px closest-corner, red, blue)",
+  "-moz-radial-gradient(circle at 45px farthest-side, red, blue)",
+  "-moz-radial-gradient(ellipse 45px, closest-side, red, blue)",
+  "-moz-radial-gradient(circle 45px, farthest-corner, red, blue)",
+  "-moz-radial-gradient(ellipse, ellipse closest-side, red, blue)",
+  "-moz-radial-gradient(circle, circle farthest-corner, red, blue)",
 
-	"-moz-radial-gradient(99deg to farthest-corner, red, blue)",
-	"-moz-radial-gradient(-1.2345rad circle, red, blue)",
-	"-moz-radial-gradient(ellipse 399grad to closest-corner, red, blue)",
-	"-moz-radial-gradient(circle 399grad to farthest-side, red, blue)",
+  "-moz-radial-gradient(99deg to farthest-corner, red, blue)",
+  "-moz-radial-gradient(-1.2345rad circle, red, blue)",
+  "-moz-radial-gradient(ellipse 399grad to closest-corner, red, blue)",
+  "-moz-radial-gradient(circle 399grad to farthest-side, red, blue)",
 
-	"-moz-radial-gradient(at top left 99deg, to farthest-corner, red, blue)",
-	"-moz-radial-gradient(circle at 15% 20% -1.2345rad, red, blue)",
-	"-moz-radial-gradient(to top left at 30% 40%, red, blue)",
-	"-moz-radial-gradient(ellipse at 45px 399grad, to closest-corner, red, blue)",
-	"-moz-radial-gradient(at 45px 399grad to farthest-side circle, red, blue)",
+  "-moz-radial-gradient(at top left 99deg, to farthest-corner, red, blue)",
+  "-moz-radial-gradient(circle at 15% 20% -1.2345rad, red, blue)",
+  "-moz-radial-gradient(to top left at 30% 40%, red, blue)",
+  "-moz-radial-gradient(ellipse at 45px 399grad, to closest-corner, red, blue)",
+  "-moz-radial-gradient(at 45px 399grad to farthest-side circle, red, blue)",
 
-	"-moz-radial-gradient(to 50%, red, blue)",
-	"-moz-radial-gradient(circle to 50%, red, blue)",
-	"-moz-radial-gradient(circle to 43px 43px, red, blue)",
-	"-moz-radial-gradient(circle to 50% 50%, red, blue)",
-	"-moz-radial-gradient(circle to 43px 50%, red, blue)",
-	"-moz-radial-gradient(circle to 50% 43px, red, blue)",
-	"-moz-radial-gradient(ellipse to 43px, red, blue)",
-	"-moz-radial-gradient(ellipse to 50%, red, blue)",
+  "-moz-radial-gradient(to 50%, red, blue)",
+  "-moz-radial-gradient(circle to 50%, red, blue)",
+  "-moz-radial-gradient(circle to 43px 43px, red, blue)",
+  "-moz-radial-gradient(circle to 50% 50%, red, blue)",
+  "-moz-radial-gradient(circle to 43px 50%, red, blue)",
+  "-moz-radial-gradient(circle to 50% 43px, red, blue)",
+  "-moz-radial-gradient(ellipse to 43px, red, blue)",
+  "-moz-radial-gradient(ellipse to 50%, red, blue)",
 
-	"-moz-linear-gradient(to 0 0, red, blue)",
-	"-moz-linear-gradient(to 20% bottom, red, blue)",
-	"-moz-linear-gradient(to center 20%, red, blue)",
-	"-moz-linear-gradient(to left 35px, red, blue)",
-	"-moz-linear-gradient(to 10% 10em, red, blue)",
-	"-moz-linear-gradient(to 44px top, red, blue)",
-	"-moz-linear-gradient(to top left 45deg, red, blue)",
-	"-moz-linear-gradient(to 20% bottom -300deg, red, blue)",
-	"-moz-linear-gradient(to center 20% 1.95929rad, red, blue)",
-	"-moz-linear-gradient(to left 35px 30grad, red, blue)",
-	"-moz-linear-gradient(to 10% 10em 99999deg, red, blue)",
-	"-moz-linear-gradient(to 44px top -33deg, red, blue)",
-	"-moz-linear-gradient(to -33deg, red, blue)",
-	"-moz-linear-gradient(to 30grad left 35px, red, blue)",
-	"-moz-linear-gradient(to 10deg 20px, red, blue)",
-	"-moz-linear-gradient(to .414rad bottom, red, blue)",
+  "-moz-linear-gradient(to 0 0, red, blue)",
+  "-moz-linear-gradient(to 20% bottom, red, blue)",
+  "-moz-linear-gradient(to center 20%, red, blue)",
+  "-moz-linear-gradient(to left 35px, red, blue)",
+  "-moz-linear-gradient(to 10% 10em, red, blue)",
+  "-moz-linear-gradient(to 44px top, red, blue)",
+  "-moz-linear-gradient(to top left 45deg, red, blue)",
+  "-moz-linear-gradient(to 20% bottom -300deg, red, blue)",
+  "-moz-linear-gradient(to center 20% 1.95929rad, red, blue)",
+  "-moz-linear-gradient(to left 35px 30grad, red, blue)",
+  "-moz-linear-gradient(to 10% 10em 99999deg, red, blue)",
+  "-moz-linear-gradient(to 44px top -33deg, red, blue)",
+  "-moz-linear-gradient(to -33deg, red, blue)",
+  "-moz-linear-gradient(to 30grad left 35px, red, blue)",
+  "-moz-linear-gradient(to 10deg 20px, red, blue)",
+  "-moz-linear-gradient(to .414rad bottom, red, blue)",
 
-	"-moz-linear-gradient(to top top, red, blue)",
-	"-moz-linear-gradient(to bottom bottom, red, blue)",
-	"-moz-linear-gradient(to left left, red, blue)",
-	"-moz-linear-gradient(to right right, red, blue)",
+  "-moz-linear-gradient(to top top, red, blue)",
+  "-moz-linear-gradient(to bottom bottom, red, blue)",
+  "-moz-linear-gradient(to left left, red, blue)",
+  "-moz-linear-gradient(to right right, red, blue)",
 
-	"-moz-repeating-linear-gradient(10px 10px, 20px, 30px 30px, 40px, blue 0, red 100%)",
-	"-moz-repeating-radial-gradient(20px 20px, 10px 10px, from(green), to(#ff00ff))",
-	"-moz-repeating-radial-gradient(10px 10px, 20%, 40px 40px, 10px, from(green), to(#ff00ff))",
-	"-moz-repeating-linear-gradient(10px, 20px, 30px, 40px, #00ccff 50%)",
-	"-moz-repeating-linear-gradient(40px 40px, 10px 10px, blue 0 fuchsia 10% red 100%)",
-	"-moz-repeating-linear-gradient(20px 20px 30px, 10px 10px, red 0, #ff0000 100%)",
-	"-moz-repeating-radial-gradient(left top, center, 20px 20px, 10px, from(blue), to(red))",
-	"-moz-repeating-linear-gradient(left left, top top, blue 0)",
-	"-moz-repeating-linear-gradient(inherit, 10px 10px, blue 0)",
-	"-moz-repeating-linear-gradient(left left blue red)",
-	"-moz-repeating-linear-gradient()",
+  "-moz-repeating-linear-gradient(10px 10px, 20px, 30px 30px, 40px, blue 0, red 100%)",
+  "-moz-repeating-radial-gradient(20px 20px, 10px 10px, from(green), to(#ff00ff))",
+  "-moz-repeating-radial-gradient(10px 10px, 20%, 40px 40px, 10px, from(green), to(#ff00ff))",
+  "-moz-repeating-linear-gradient(10px, 20px, 30px, 40px, #00ccff 50%)",
+  "-moz-repeating-linear-gradient(40px 40px, 10px 10px, blue 0 fuchsia 10% red 100%)",
+  "-moz-repeating-linear-gradient(20px 20px 30px, 10px 10px, red 0, #ff0000 100%)",
+  "-moz-repeating-radial-gradient(left top, center, 20px 20px, 10px, from(blue), to(red))",
+  "-moz-repeating-linear-gradient(left left, top top, blue 0)",
+  "-moz-repeating-linear-gradient(inherit, 10px 10px, blue 0)",
+  "-moz-repeating-linear-gradient(left left blue red)",
+  "-moz-repeating-linear-gradient()",
 
-	"-moz-repeating-linear-gradient(to 0 0, red, blue)",
-	"-moz-repeating-linear-gradient(to 20% bottom, red, blue)",
-	"-moz-repeating-linear-gradient(to center 20%, red, blue)",
-	"-moz-repeating-linear-gradient(to left 35px, red, blue)",
-	"-moz-repeating-linear-gradient(to 10% 10em, red, blue)",
-	"-moz-repeating-linear-gradient(to 44px top, red, blue)",
-	"-moz-repeating-linear-gradient(to top left 45deg, red, blue)",
-	"-moz-repeating-linear-gradient(to 20% bottom -300deg, red, blue)",
-	"-moz-repeating-linear-gradient(to center 20% 1.95929rad, red, blue)",
-	"-moz-repeating-linear-gradient(to left 35px 30grad, red, blue)",
-	"-moz-repeating-linear-gradient(to 10% 10em 99999deg, red, blue)",
-	"-moz-repeating-linear-gradient(to 44px top -33deg, red, blue)",
-	"-moz-repeating-linear-gradient(to -33deg, red, blue)",
-	"-moz-repeating-linear-gradient(to 30grad left 35px, red, blue)",
-	"-moz-repeating-linear-gradient(to 10deg 20px, red, blue)",
-	"-moz-repeating-linear-gradient(to .414rad bottom, red, blue)",
+  "-moz-repeating-linear-gradient(to 0 0, red, blue)",
+  "-moz-repeating-linear-gradient(to 20% bottom, red, blue)",
+  "-moz-repeating-linear-gradient(to center 20%, red, blue)",
+  "-moz-repeating-linear-gradient(to left 35px, red, blue)",
+  "-moz-repeating-linear-gradient(to 10% 10em, red, blue)",
+  "-moz-repeating-linear-gradient(to 44px top, red, blue)",
+  "-moz-repeating-linear-gradient(to top left 45deg, red, blue)",
+  "-moz-repeating-linear-gradient(to 20% bottom -300deg, red, blue)",
+  "-moz-repeating-linear-gradient(to center 20% 1.95929rad, red, blue)",
+  "-moz-repeating-linear-gradient(to left 35px 30grad, red, blue)",
+  "-moz-repeating-linear-gradient(to 10% 10em 99999deg, red, blue)",
+  "-moz-repeating-linear-gradient(to 44px top -33deg, red, blue)",
+  "-moz-repeating-linear-gradient(to -33deg, red, blue)",
+  "-moz-repeating-linear-gradient(to 30grad left 35px, red, blue)",
+  "-moz-repeating-linear-gradient(to 10deg 20px, red, blue)",
+  "-moz-repeating-linear-gradient(to .414rad bottom, red, blue)",
 
-	"-moz-repeating-linear-gradient(to top top, red, blue)",
-	"-moz-repeating-linear-gradient(to bottom bottom, red, blue)",
-	"-moz-repeating-linear-gradient(to left left, red, blue)",
-	"-moz-repeating-linear-gradient(to right right, red, blue)",
+  "-moz-repeating-linear-gradient(to top top, red, blue)",
+  "-moz-repeating-linear-gradient(to bottom bottom, red, blue)",
+  "-moz-repeating-linear-gradient(to left left, red, blue)",
+  "-moz-repeating-linear-gradient(to right right, red, blue)",
 
-	"-moz-repeating-radial-gradient(to top left at 30% 40%, red, blue)",
-	"-moz-repeating-radial-gradient(ellipse at 45px closest-corner, red, blue)",
-	"-moz-repeating-radial-gradient(circle at 45px farthest-side, red, blue)",
+  "-moz-repeating-radial-gradient(to top left at 30% 40%, red, blue)",
+  "-moz-repeating-radial-gradient(ellipse at 45px closest-corner, red, blue)",
+  "-moz-repeating-radial-gradient(circle at 45px farthest-side, red, blue)",
 
-	"radial-gradient(circle 175px 20px, black, white)",
-	"radial-gradient(175px 20px circle, black, white)",
-	"radial-gradient(ellipse 175px, black, white)",
-	"radial-gradient(175px ellipse, black, white)",
-	"radial-gradient(50%, red, blue)",
-	"radial-gradient(circle 50%, red, blue)",
-	"radial-gradient(50% circle, red, blue)",
+  "radial-gradient(circle 175px 20px, black, white)",
+  "radial-gradient(175px 20px circle, black, white)",
+  "radial-gradient(ellipse 175px, black, white)",
+  "radial-gradient(175px ellipse, black, white)",
+  "radial-gradient(50%, red, blue)",
+  "radial-gradient(circle 50%, red, blue)",
+  "radial-gradient(50% circle, red, blue)",
 
-	/* Valid only when prefixed */
-	"linear-gradient(top left, red, blue)",
-	"linear-gradient(0 0, red, blue)",
-	"linear-gradient(20% bottom, red, blue)",
-	"linear-gradient(center 20%, red, blue)",
-	"linear-gradient(left 35px, red, blue)",
-	"linear-gradient(10% 10em, red, blue)",
-	"linear-gradient(44px top, red, blue)",
+  /* Valid only when prefixed */
+  "linear-gradient(top left, red, blue)",
+  "linear-gradient(0 0, red, blue)",
+  "linear-gradient(20% bottom, red, blue)",
+  "linear-gradient(center 20%, red, blue)",
+  "linear-gradient(left 35px, red, blue)",
+  "linear-gradient(10% 10em, red, blue)",
+  "linear-gradient(44px top, red, blue)",
 
-	"linear-gradient(top left 45deg, red, blue)",
-	"linear-gradient(20% bottom -300deg, red, blue)",
-	"linear-gradient(center 20% 1.95929rad, red, blue)",
-	"linear-gradient(left 35px 30grad, red, blue)",
-	"linear-gradient(left 35px 0.1turn, red, blue)",
-	"linear-gradient(10% 10em 99999deg, red, blue)",
-	"linear-gradient(44px top -33deg, red, blue)",
+  "linear-gradient(top left 45deg, red, blue)",
+  "linear-gradient(20% bottom -300deg, red, blue)",
+  "linear-gradient(center 20% 1.95929rad, red, blue)",
+  "linear-gradient(left 35px 30grad, red, blue)",
+  "linear-gradient(left 35px 0.1turn, red, blue)",
+  "linear-gradient(10% 10em 99999deg, red, blue)",
+  "linear-gradient(44px top -33deg, red, blue)",
 
-	"linear-gradient(30grad left 35px, red, blue)",
-	"linear-gradient(10deg 20px, red, blue)",
-	"linear-gradient(1turn 20px, red, blue)",
-	"linear-gradient(.414rad bottom, red, blue)",