Merge latest green fx-team changeset and mozilla-central
authorEd Morley <emorley@mozilla.com>
Mon, 03 Mar 2014 14:48:02 +0000
changeset 171877 cb68b921c063ffdf6f16833ab76e943656d57565
parent 171876 4201e638f683f30e461b74e44a155fd400b0ab2b (current diff)
parent 171873 22d263f6edc4a1950f919b9ba81891dbd379e1bc (diff)
child 171878 ad8ef80593395c7e0a5e1f7c2b54eaca00199e51
child 171919 c8bea55437c176e58a7e19358cf523fdfbf930c9
child 171959 310a3bb87eb27407c53038272bc077d5ac667755
child 171996 5c3a452d198229d11ccfe3f1dd31061e86662abf
push id270
push userpvanderbeken@mozilla.com
push dateThu, 06 Mar 2014 09:24:21 +0000
milestone30.0a1
Merge latest green fx-team changeset and mozilla-central
toolkit/content/widgets/remote-browser.xml
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -181,17 +181,18 @@ pref("privacy.item.formdata", true);
 pref("privacy.item.downloads", true);
 pref("privacy.item.passwords", true);
 pref("privacy.item.sessions", true);
 pref("privacy.item.geolocation", true);
 pref("privacy.item.siteSettings", true);
 pref("privacy.item.syncAccount", true);
 
 // base url for the wifi geolocation network provider
-pref("geo.wifi.uri", "https://maps.googleapis.com/maps/api/browserlocation/json");
+pref("geo.provider.use_mls", false);
+pref("geo.wifi.uri", "https://location.services.mozilla.com/v1/geolocate?key=%MOZILLA_API_KEY%");
 
 // enable geo
 pref("geo.enabled", true);
 
 // content sink control -- controls responsiveness during page load
 // see https://bugzilla.mozilla.org/show_bug.cgi?id=481566#c9
 pref("content.sink.enable_perf_mode",  2); // 0 - switch, 1 - interactive, 2 - perf
 pref("content.sink.pending_event_mode", 0);
--- 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="59605a7c026ff06cc1613af3938579b1dddc6cfe">
     <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="a980b8f54956ed470667033630b02492efdf4a07"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="dfae3744607257206e37483dc3f431108baf70fb"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="15e8982284c4560f9c74c2b9fe8bb361ebfe0cb6"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="d11f524d00cacf5ba0dfbf25e4aa2158b1c3a036"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="456499c44d1ef39b602ea02e9ed460b6aab85b44"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="3d5c964015967ca8c86abe6dbbebee3cb82b1609"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="b2f773d8320d30648b89767dfe5b25ef94bc7e62"/>
   <!-- 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="97a5b461686757dbb8ecab2aac5903e41d2e1afe">
     <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="a980b8f54956ed470667033630b02492efdf4a07"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="dfae3744607257206e37483dc3f431108baf70fb"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="15e8982284c4560f9c74c2b9fe8bb361ebfe0cb6"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="3d5c964015967ca8c86abe6dbbebee3cb82b1609"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="b2f773d8320d30648b89767dfe5b25ef94bc7e62"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="905bfa3548eb75cf1792d0d8412b92113bbd4318"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="c3d7efc45414f1b44cd9c479bb2758c91c4707c0"/>
   <!-- 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/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="59605a7c026ff06cc1613af3938579b1dddc6cfe">
     <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="a980b8f54956ed470667033630b02492efdf4a07"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="dfae3744607257206e37483dc3f431108baf70fb"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="15e8982284c4560f9c74c2b9fe8bb361ebfe0cb6"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="d11f524d00cacf5ba0dfbf25e4aa2158b1c3a036"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="456499c44d1ef39b602ea02e9ed460b6aab85b44"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="3d5c964015967ca8c86abe6dbbebee3cb82b1609"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="b2f773d8320d30648b89767dfe5b25ef94bc7e62"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,9 +1,9 @@
 {
     "git": {
         "remote": "", 
         "branch": "", 
         "revision": ""
     }, 
-    "revision": "d0ed050535c3a5337c09c0de720de78954a42f31", 
+    "revision": "3d294ffa51afd8a8daafcdaa97cda8e38de81cb8", 
     "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="59605a7c026ff06cc1613af3938579b1dddc6cfe">
     <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="a980b8f54956ed470667033630b02492efdf4a07"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="dfae3744607257206e37483dc3f431108baf70fb"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="15e8982284c4560f9c74c2b9fe8bb361ebfe0cb6"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="3d5c964015967ca8c86abe6dbbebee3cb82b1609"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="b2f773d8320d30648b89767dfe5b25ef94bc7e62"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
@@ -91,17 +91,17 @@
   <project name="platform/prebuilt" path="prebuilt" revision="248d92592df169569c387a91db56b1fedd6e5d29"/>
   <project name="platform/system/bluetooth" path="system/bluetooth" revision="395aff045276107a285daf0392d0884a98b9f538"/>
   <project name="platform/system/core" path="system/core" revision="70229cf62037cfb70ec2257f7c78b5550628fb53"/>
   <project name="platform/system/extras" path="system/extras" revision="a5dd0ea60ce973c2c762b41835a43316fb4ff9e3"/>
   <project name="platform/system/media" path="system/media" revision="fbb3d9b4c5bf59071424e820e872e3f64f0a244a"/>
   <project name="platform/system/netd" path="system/netd" revision="2e226e6e636ca0a8cc4c51093e46f4baba1ffcce"/>
   <project name="platform/system/vold" path="system/vold" revision="8ac5eef8ea3a456b96d52ce2091bf6d814782d8c"/>
   <!-- hamachi specific things -->
-  <project name="quic/lf/b2g/build" path="device/qcom/b2g_common" revision="6d90df25658d59dfcfd34f83e74e75c3af3901af"/>
+  <project name="quic/lf/b2g/build" path="device/qcom/b2g_common" revision="901e2607afb2518d1666846bbcf572e65cd93bf4"/>
   <project name="quic/lf/b2g/external/jsmin" path="external/jsmin" revision="cec896f0affaa0226c02605ad28d42df1bc0e393"/>
   <project name="device/qcom/common" path="device/qcom/common" revision="d13aaf080177b7c48f243d51827db5c7a7873cd0"/>
   <project name="platform/vendor/qcom/msm7627a" path="device/qcom/msm7627a" revision="f06bcacc6f13cec895dc5d4c2385c076396194ec"/>
   <project name="android-device-hamachi" path="device/qcom/hamachi" remote="b2g" revision="9071ac8f0830979fe4a96ce47c7443d8adf0929d"/>
   <project name="kernel/msm" path="kernel" revision="a6578b9cacf9079f2dcf5bfe77c31b1be18809e3"/>
   <project name="platform/hardware/qcom/camera" path="hardware/qcom/camera" revision="19933e5d182a4799c6217b19a18562193a419298"/>
   <project name="platform/hardware/qcom/display" path="hardware/qcom/display" revision="5a58382180c70d0c446badc9c9837918ab69ec60"/>
   <project name="platform/hardware/qcom/media" path="hardware/qcom/media" revision="20d83ab382a1f813702421e76c2f9f994585990e"/>
--- 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="59605a7c026ff06cc1613af3938579b1dddc6cfe">
     <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="a980b8f54956ed470667033630b02492efdf4a07"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="dfae3744607257206e37483dc3f431108baf70fb"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="15e8982284c4560f9c74c2b9fe8bb361ebfe0cb6"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="3d5c964015967ca8c86abe6dbbebee3cb82b1609"/>
   <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="59605a7c026ff06cc1613af3938579b1dddc6cfe">
     <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="a980b8f54956ed470667033630b02492efdf4a07"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="dfae3744607257206e37483dc3f431108baf70fb"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="15e8982284c4560f9c74c2b9fe8bb361ebfe0cb6"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="3d5c964015967ca8c86abe6dbbebee3cb82b1609"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="b2f773d8320d30648b89767dfe5b25ef94bc7e62"/>
   <!-- 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="59605a7c026ff06cc1613af3938579b1dddc6cfe">
     <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="a980b8f54956ed470667033630b02492efdf4a07"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="dfae3744607257206e37483dc3f431108baf70fb"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="15e8982284c4560f9c74c2b9fe8bb361ebfe0cb6"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="3d5c964015967ca8c86abe6dbbebee3cb82b1609"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="b2f773d8320d30648b89767dfe5b25ef94bc7e62"/>
   <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="97a5b461686757dbb8ecab2aac5903e41d2e1afe">
     <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="a980b8f54956ed470667033630b02492efdf4a07"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="dfae3744607257206e37483dc3f431108baf70fb"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="15e8982284c4560f9c74c2b9fe8bb361ebfe0cb6"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="3d5c964015967ca8c86abe6dbbebee3cb82b1609"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="b2f773d8320d30648b89767dfe5b25ef94bc7e62"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="905bfa3548eb75cf1792d0d8412b92113bbd4318"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="c3d7efc45414f1b44cd9c479bb2758c91c4707c0"/>
   <!-- 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="59605a7c026ff06cc1613af3938579b1dddc6cfe">
     <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="a980b8f54956ed470667033630b02492efdf4a07"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="dfae3744607257206e37483dc3f431108baf70fb"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="15e8982284c4560f9c74c2b9fe8bb361ebfe0cb6"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="3d5c964015967ca8c86abe6dbbebee3cb82b1609"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="b2f773d8320d30648b89767dfe5b25ef94bc7e62"/>
   <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/installer/package-manifest.in
+++ b/b2g/installer/package-manifest.in
@@ -370,16 +370,18 @@
 @BINPATH@/components/BrowserPlaces.manifest
 @BINPATH@/components/toolkitsearch.manifest
 @BINPATH@/components/nsTryToClose.manifest
 @BINPATH@/components/nsTryToClose.js
 @BINPATH@/components/passwordmgr.manifest
 @BINPATH@/components/nsLoginInfo.js
 @BINPATH@/components/nsLoginManager.js
 @BINPATH@/components/nsLoginManagerPrompter.js
+@BINPATH@/components/NetworkGeolocationProvider.manifest
+@BINPATH@/components/NetworkGeolocationProvider.js
 #ifdef MOZ_WEBRTC
 @BINPATH@/components/PeerConnection.js
 @BINPATH@/components/PeerConnection.manifest
 #endif
 @BINPATH@/components/SiteSpecificUserAgent.js
 @BINPATH@/components/SiteSpecificUserAgent.manifest
 @BINPATH@/components/storage-mozStorage.js
 @BINPATH@/components/crypto-SDR.js
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -2993,20 +2993,19 @@
               if (titleChanged && !tab.selected && !tab.hasAttribute("busy"))
                 tab.setAttribute("titlechanged", "true");
               break;
             }
             case "contextmenu": {
               gContextMenuContentData = { event: aMessage.objects.event,
                                           browser: browser };
               let popup = browser.ownerDocument.getElementById("contentAreaContextMenu");
-              popup.openPopup(browser, "overlap",
-                              gContextMenuContentData.event.clientX,
-                              gContextMenuContentData.event.clientY,
-                              true, false, null);
+              let event = gContextMenuContentData.event;
+              let pos = browser.mapScreenCoordinatesFromContent(event.screenX, event.screenY);
+              popup.openPopupAtScreen(pos.x, pos.y, true);
               break;
             }
             case "DOMWebNotificationClicked": {
               let tab = this._getTabForBrowser(browser);
               if (!tab)
                 return;
               this.selectedTab = tab;
               window.focus();
@@ -3993,16 +3992,20 @@
                 sourceNode.ownerDocument.documentElement.getAttribute("windowtype") == "navigator:browser" &&
                 sourceNode.ownerDocument.defaultView.gBrowser.tabContainer == sourceNode.parentNode) {
               // Do not allow transfering a private tab to a non-private window
               // and vice versa.
               if (PrivateBrowsingUtils.isWindowPrivate(window) !=
                   PrivateBrowsingUtils.isWindowPrivate(sourceNode.ownerDocument.defaultView))
                 return dt.effectAllowed = "none";
 
+              if (window.gMultiProcessBrowser !=
+                  sourceNode.ownerDocument.defaultView.gMultiProcessBrowser)
+                return dt.effectAllowed = "none";
+
 #ifdef XP_MACOSX
               return dt.effectAllowed = event.altKey ? "copy" : "move";
 #else
               return dt.effectAllowed = event.ctrlKey ? "copy" : "move";
 #endif
             }
           }
 
--- a/browser/base/content/test/general/browser.ini
+++ b/browser/base/content/test/general/browser.ini
@@ -11,16 +11,17 @@ support-files =
   blockPluginVulnerableNoUpdate.xml
   blockPluginVulnerableUpdatable.xml
   browser_bug479408_sample.html
   browser_bug678392-1.html
   browser_bug678392-2.html
   browser_clearplugindata.html
   browser_clearplugindata_noage.html
   browser_registerProtocolHandler_notification.html
+  browser_star_hsts.sjs
   browser_tab_dragdrop2_frame1.xul
   bug564387.html
   bug564387_video1.ogv
   bug564387_video1.ogv^headers^
   bug592338.html
   bug792517-2.html
   bug792517.html
   bug792517.sjs
@@ -316,16 +317,17 @@ skip-if = true  # disabled until the tre
                 # back to the clear recent history dialog (sanitize.xul), if
                 # it ever is (bug 480169)
 [browser_save_link-perwindowpb.js]
 [browser_save_private_link_perwindowpb.js]
 skip-if = os == "linux" # bug 857427
 [browser_save_video.js]
 [browser_scope.js]
 [browser_selectTabAtIndex.js]
+[browser_star_hsts.js]
 [browser_subframe_favicons_not_used.js]
 [browser_tabDrop.js]
 [browser_tabMatchesInAwesomebar_perwindowpb.js]
 [browser_tab_drag_drop_perwindow.js]
 [browser_tab_dragdrop.js]
 [browser_tab_dragdrop2.js]
 [browser_tabbar_big_widgets.js]
 skip-if = os == "linux" || os == "mac" # No tabs in titlebar on linux
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/general/browser_star_hsts.js
@@ -0,0 +1,114 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+let secureURL = "https://example.com/browser/browser/base/content/test/general/browser_star_hsts.sjs";
+let unsecureURL = "http://example.com/browser/browser/base/content/test/general/browser_star_hsts.sjs";
+
+add_task(function* test_star_redirect() {
+  registerCleanupFunction(function() {
+    // Ensure to remove example.com from the HSTS list.
+    let sss = Cc["@mozilla.org/ssservice;1"]
+                .getService(Ci.nsISiteSecurityService);
+    sss.removeState(Ci.nsISiteSecurityService.HEADER_HSTS,
+                    NetUtil.newURI("http://example.com/"), 0);
+    PlacesUtils.bookmarks.removeFolderChildren(PlacesUtils.unfiledBookmarksFolderId);
+    gBrowser.removeCurrentTab();
+  });
+
+  let tab = gBrowser.selectedTab = gBrowser.addTab();
+  // This will add the page to the HSTS cache.
+  yield promiseTabLoadEvent(tab, secureURL, secureURL);
+  // This should transparently be redirected to the secure page.
+  yield promiseTabLoadEvent(tab, unsecureURL, secureURL);
+
+  yield promiseStarState(BookmarkingUI.STATUS_UNSTARRED);
+
+  let promiseBookmark = promiseOnItemAdded(gBrowser.currentURI);
+  BookmarkingUI.star.click();
+  // This resolves on the next tick, so the star should have already been
+  // updated at that point.
+  yield promiseBookmark;
+
+  is(BookmarkingUI.status, BookmarkingUI.STATUS_STARRED, "The star is starred");
+});
+
+/**
+ * Waits for the star to reflect the expected state.
+ */
+function promiseStarState(aValue) {
+  let deferred = Promise.defer();
+  let expectedStatus = aValue ? BookmarkingUI.STATUS_STARRED
+                              : BookmarkingUI.STATUS_UNSTARRED;
+  (function checkState() {
+    if (BookmarkingUI.status == BookmarkingUI.STATUS_UPDATING ||
+        BookmarkingUI.status != expectedStatus) {
+      info("Waiting for star button change.");
+      setTimeout(checkState, 1000);
+    } else {
+      deferred.resolve();
+    }
+  })();
+  return deferred.promise;
+}
+
+/**
+ * Starts a load in an existing tab and waits for it to finish (via some event).
+ *
+ * @param aTab
+ *        The tab to load into.
+ * @param aUrl
+ *        The url to load.
+ * @param [optional] aFinalURL
+ *        The url to wait for, same as aURL if not defined.
+ * @return {Promise} resolved when the event is handled.
+ */
+function promiseTabLoadEvent(aTab, aURL, aFinalURL)
+{
+  if (!aFinalURL)
+    aFinalURL = aURL;
+  let deferred = Promise.defer();
+  info("Wait for load tab event");
+  aTab.linkedBrowser.addEventListener("load", function load(event) {
+    if (event.originalTarget != aTab.linkedBrowser.contentDocument ||
+        event.target.location.href == "about:blank" ||
+        event.target.location.href != aFinalURL) {
+      info("skipping spurious load event");
+      return;
+    }
+    aTab.linkedBrowser.removeEventListener("load", load, true);
+    info("Tab load event received");
+    deferred.resolve();
+  }, true, true);
+  aTab.linkedBrowser.loadURI(aURL);
+  return deferred.promise;
+}
+
+/**
+ * Waits for a bookmark to be added for the given uri.
+ */
+function promiseOnItemAdded(aExpectedURI) {
+  let defer = Promise.defer();
+  let bookmarksObserver = {
+    onItemAdded: function (aItemId, aFolderId, aIndex, aItemType, aURI) {
+      info("Added a bookmark to " + aURI.spec);
+      PlacesUtils.bookmarks.removeObserver(bookmarksObserver);
+      if (aURI.equals(aExpectedURI))
+        defer.resolve();
+      else
+        defer.reject(new Error("Added an unexpected bookmark"));
+    },
+    onBeginUpdateBatch: function () {},
+    onEndUpdateBatch: function () {},
+    onItemRemoved: function () {},
+    onItemChanged: function () {},
+    onItemVisited: function () {},
+    onItemMoved: function () {},
+    QueryInterface: XPCOMUtils.generateQI([
+      Ci.nsINavBookmarkObserver,
+    ])
+  };
+  info("Waiting for a bookmark to be added");
+  PlacesUtils.bookmarks.addObserver(bookmarksObserver, false);
+  return defer.promise;
+}
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/general/browser_star_hsts.sjs
@@ -0,0 +1,13 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+function handleRequest(request, response)
+{
+  let page = "<!DOCTYPE html><html><body><p>HSTS page</p></body></html>";
+  response.setStatusLine(request.httpVersion, "200", "OK");
+  response.setHeader("Strict-Transport-Security", "max-age=60");
+  response.setHeader("Content-Type", "text/html", false);
+  response.setHeader("Content-Length", page.length + "", false);
+  response.write(page);
+}
--- a/config/config.mk
+++ b/config/config.mk
@@ -836,17 +836,17 @@ define CHECK_BINARY
 endef
 
 # autoconf.mk sets OBJ_SUFFIX to an error to avoid use before including
 # this file
 OBJ_SUFFIX := $(_OBJ_SUFFIX)
 
 # PGO builds with GCC build objects with instrumentation in a first pass,
 # then objects optimized, without instrumentation, in a second pass. If
-# we overwrite the ojects from the first pass with those from the second,
+# we overwrite the objects from the first pass with those from the second,
 # we end up not getting instrumentation data for better optimization on
 # incremental builds. As a consequence, we use a different object suffix
 # for the first pass.
 ifndef NO_PROFILE_GUIDED_OPTIMIZE
 ifdef MOZ_PROFILE_GENERATE
 ifdef GNU_CC
 OBJ_SUFFIX := i_o
 endif
--- a/configure.in
+++ b/configure.in
@@ -55,17 +55,17 @@ MOZPNG=10609
 NSPR_VERSION=4
 NSS_VERSION=3
 
 dnl Set the minimum version of toolkit libs used by mozilla
 dnl ========================================================
 GLIB_VERSION=1.2.0
 PERL_VERSION=5.006
 CAIRO_VERSION=1.10
-PANGO_VERSION=1.14.0
+PANGO_VERSION=1.22.0
 GTK2_VERSION=2.10.0
 GTK3_VERSION=3.0.0
 WINDRES_VERSION=2.14.90
 W32API_VERSION=3.14
 GNOMEVFS_VERSION=2.0
 GNOMEUI_VERSION=2.2.0
 GCONF_VERSION=1.2.1
 GIO_VERSION=2.20
@@ -246,20 +246,23 @@ if test -n "$gonkdir" ; then
         AC_SUBST(MOZ_OMX_DECODER)
         MOZ_OMX_ENCODER=1
         AC_SUBST(MOZ_OMX_ENCODER)
         AC_DEFINE(MOZ_OMX_ENCODER)
         ;;
     19)
         GONK_INCLUDES="-I$gonkdir/frameworks/native/include -I$gonkdir/frameworks/av/include -I$gonkdir/frameworks/av/include/media -I$gonkdir/frameworks/av/include/camera -I$gonkdir/frameworks/native/include/media/openmax -I$gonkdir/frameworks/av/media/libstagefright/include"
         MOZ_B2G_CAMERA=1
-        MOZ_OMX_DECODER=1
         MOZ_B2G_BT=1
         MOZ_B2G_BT_BLUEDROID=1
         MOZ_NFC=1
+        MOZ_RTSP=1
+        MOZ_OMX_DECODER=1
+        MOZ_OMX_ENCODER=1
+        AC_DEFINE(MOZ_OMX_ENCODER)
 
         ;;
     *)
         AC_MSG_ERROR([Unsupported platform version: $ANDROID_VERSION])
         ;;
     esac
     CPPFLAGS="-DANDROID -isystem $gonkdir/bionic/libc/$ARCH_DIR/include -isystem $gonkdir/bionic/libc/include/ -isystem $gonkdir/bionic/libc/kernel/common -isystem $gonkdir/bionic/libc/kernel/$ARCH_DIR -isystem $gonkdir/bionic/libm/include -I$gonkdir/system -I$gonkdir/system/core/include -isystem $gonkdir/bionic -I$gonkdir/hardware/libhardware/include -I$gonkdir/external/valgrind/fxos-include $GONK_INCLUDES $CPPFLAGS"
     CFLAGS="-mandroid -fno-short-enums -fno-exceptions $CFLAGS"
@@ -4045,16 +4048,26 @@ MOZ_ARG_ENABLE_STRING([update-channel],
     MOZ_UPDATE_CHANNEL=`echo $enableval | tr A-Z a-z`)
 
 if test -z "$MOZ_UPDATE_CHANNEL"; then
     MOZ_UPDATE_CHANNEL=default
 fi
 AC_DEFINE_UNQUOTED(MOZ_UPDATE_CHANNEL, $MOZ_UPDATE_CHANNEL)
 AC_SUBST(MOZ_UPDATE_CHANNEL)
 
+# Allow to specify a Mozilla API key file that contains the secret key to be
+# used for various Mozilla API requests.
+MOZ_ARG_WITH_STRING(mozilla-api-keyfile,
+[  --with-mozilla-api-keyfile=file   Use the secret key contained in the given keyfile for Mozilla API requests],
+  MOZ_MOZILLA_API_KEY=`cat $withval`)
+if test -z "$MOZ_MOZILLA_API_KEY"; then
+    MOZ_MOZILLA_API_KEY=no-mozilla-api-key
+fi
+AC_SUBST(MOZ_MOZILLA_API_KEY)
+
 # Allow to specify a Google API key file that contains the secret key to be
 # used for various Google API requests.
 MOZ_ARG_WITH_STRING(google-api-keyfile,
 [  --with-google-api-keyfile=file   Use the secret key contained in the given keyfile for Google API requests],
   MOZ_GOOGLE_API_KEY=`cat $withval`)
 if test -z "$MOZ_GOOGLE_API_KEY"; then
     MOZ_GOOGLE_API_KEY=no-google-api-key
 fi
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -958,17 +958,17 @@ TransferZoomLevels(nsIDocument* aFromDoc
   if (!toShell)
     return;
 
   nsPresContext* toCtxt = toShell->GetPresContext();
   if (!toCtxt)
     return;
 
   toCtxt->SetFullZoom(fromCtxt->GetFullZoom());
-  toCtxt->SetMinFontSize(fromCtxt->MinFontSize(nullptr));
+  toCtxt->SetBaseMinFontSize(fromCtxt->BaseMinFontSize());
   toCtxt->SetTextZoom(fromCtxt->TextZoom());
 }
 
 void
 TransferShowingState(nsIDocument* aFromDoc, nsIDocument* aToDoc)
 {
   NS_ABORT_IF_FALSE(aFromDoc && aToDoc,
                     "transferring showing state from/to null doc");
--- a/content/canvas/src/WebGLContextGL.cpp
+++ b/content/canvas/src/WebGLContextGL.cpp
@@ -503,18 +503,26 @@ WebGLContext::CopyTexImage2D(GLenum targ
                           0, 0, 0,
                           width, height, 0,
                           border, internalformat, type,
                           func))
     {
         return;
     }
 
-    if (mBoundFramebuffer && !mBoundFramebuffer->CheckAndInitializeAttachments())
-        return ErrorInvalidFramebufferOperation("copyTexImage2D: incomplete framebuffer");
+    if (mBoundFramebuffer) {
+        if (!mBoundFramebuffer->CheckAndInitializeAttachments())
+            return ErrorInvalidFramebufferOperation("copyTexImage2D: incomplete framebuffer");
+
+        GLenum readPlaneBits = LOCAL_GL_COLOR_BUFFER_BIT;
+        if (!mBoundFramebuffer->HasCompletePlanes(readPlaneBits)) {
+            return ErrorInvalidOperation("copyTexImage2D: Read source attachment doesn't have the"
+                                         " correct color/depth/stencil type.");
+        }
+    }
 
     bool texFormatRequiresAlpha = internalformat == LOCAL_GL_RGBA ||
                                   internalformat == LOCAL_GL_ALPHA ||
                                   internalformat == LOCAL_GL_LUMINANCE_ALPHA;
     bool fboFormatHasAlpha = mBoundFramebuffer ? mBoundFramebuffer->ColorAttachment(0).HasAlpha()
                                                : bool(gl->GetPixelFormat().alpha > 0);
     if (texFormatRequiresAlpha && !fboFormatHasAlpha)
         return ErrorInvalidOperation("copyTexImage2D: texture format requires an alpha channel "
@@ -608,20 +616,27 @@ WebGLContext::CopyTexSubImage2D(GLenum t
 
     GLenum internalFormat = imageInfo.InternalFormat();
     if (IsGLDepthFormat(internalFormat) ||
         IsGLDepthStencilFormat(internalFormat))
     {
         return ErrorInvalidOperation("copyTexSubImage2D: a base internal format of DEPTH_COMPONENT or DEPTH_STENCIL isn't supported");
     }
 
-    if (mBoundFramebuffer)
+    if (mBoundFramebuffer) {
         if (!mBoundFramebuffer->CheckAndInitializeAttachments())
             return ErrorInvalidFramebufferOperation("copyTexSubImage2D: incomplete framebuffer");
 
+        GLenum readPlaneBits = LOCAL_GL_COLOR_BUFFER_BIT;
+        if (!mBoundFramebuffer->HasCompletePlanes(readPlaneBits)) {
+            return ErrorInvalidOperation("copyTexSubImage2D: Read source attachment doesn't have the"
+                                         " correct color/depth/stencil type.");
+        }
+    }
+
     bool texFormatRequiresAlpha = (internalFormat == LOCAL_GL_RGBA ||
                                    internalFormat == LOCAL_GL_ALPHA ||
                                    internalFormat == LOCAL_GL_LUMINANCE_ALPHA);
     bool fboFormatHasAlpha = mBoundFramebuffer ? mBoundFramebuffer->ColorAttachment(0).HasAlpha()
                                                : bool(gl->GetPixelFormat().alpha > 0);
 
     if (texFormatRequiresAlpha && !fboFormatHasAlpha)
         return ErrorInvalidOperation("copyTexSubImage2D: texture format requires an alpha channel "
@@ -2302,16 +2317,22 @@ WebGLContext::ReadPixels(GLint x, GLint 
     }
 
     MakeContextCurrent();
 
     if (mBoundFramebuffer) {
         // prevent readback of arbitrary video memory through uninitialized renderbuffers!
         if (!mBoundFramebuffer->CheckAndInitializeAttachments())
             return ErrorInvalidFramebufferOperation("readPixels: incomplete framebuffer");
+
+        GLenum readPlaneBits = LOCAL_GL_COLOR_BUFFER_BIT;
+        if (!mBoundFramebuffer->HasCompletePlanes(readPlaneBits)) {
+            return ErrorInvalidOperation("readPixels: Read source attachment doesn't have the"
+                                         " correct color/depth/stencil type.");
+        }
     }
     // Now that the errors are out of the way, on to actually reading
 
     // If we won't be reading any pixels anyways, just skip the actual reading
     if (width == 0 || height == 0)
         return DummyFramebufferOperation("readPixels");
 
     if (CanvasUtils::CheckSaneSubrectSize(x, y, width, height, framebufferWidth, framebufferHeight)) {
--- a/content/canvas/src/WebGLFramebuffer.cpp
+++ b/content/canvas/src/WebGLFramebuffer.cpp
@@ -625,16 +625,41 @@ WebGLFramebuffer::CheckFramebufferStatus
     mContext->MakeContextCurrent();
 
     // Ok, attach our chosen flavor of {DEPTH, STENCIL, DEPTH_STENCIL}.
     FinalizeAttachments();
 
     return mContext->gl->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
 }
 
+bool
+WebGLFramebuffer::HasCompletePlanes(GLbitfield mask)
+{
+    if (CheckFramebufferStatus() != LOCAL_GL_FRAMEBUFFER_COMPLETE)
+        return false;
+
+    MOZ_ASSERT(mContext->mBoundFramebuffer == this);
+    bool hasPlanes = true;
+    if (mask & LOCAL_GL_COLOR_BUFFER_BIT) {
+        hasPlanes &= ColorAttachmentCount() &&
+                     ColorAttachment(0).IsDefined();
+    }
+
+    if (mask & LOCAL_GL_DEPTH_BUFFER_BIT) {
+        hasPlanes &= DepthAttachment().IsDefined() ||
+                     DepthStencilAttachment().IsDefined();
+    }
+
+    if (mask & LOCAL_GL_STENCIL_BUFFER_BIT) {
+        hasPlanes &= StencilAttachment().IsDefined() ||
+                     DepthStencilAttachment().IsDefined();
+    }
+
+    return hasPlanes;
+}
 
 bool
 WebGLFramebuffer::CheckAndInitializeAttachments()
 {
     MOZ_ASSERT(mContext->mBoundFramebuffer == this);
 
     if (CheckFramebufferStatus() != LOCAL_GL_FRAMEBUFFER_COMPLETE)
         return false;
--- a/content/canvas/src/WebGLFramebuffer.h
+++ b/content/canvas/src/WebGLFramebuffer.h
@@ -161,16 +161,19 @@ public:
     void FinalizeAttachments() const;
 
     virtual JSObject* WrapObject(JSContext* cx,
                                  JS::Handle<JSObject*> scope) MOZ_OVERRIDE;
 
     NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLFramebuffer)
     NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLFramebuffer)
 
+    // mask mirrors glClear.
+    bool HasCompletePlanes(GLbitfield mask);
+
     bool CheckAndInitializeAttachments();
 
     bool CheckColorAttachmentNumber(GLenum attachment, const char* functionName) const;
 
     GLuint mGLName;
     bool mHasEverBeenBound;
 
     void EnsureColorAttachments(size_t colorAttachmentId);
--- a/content/canvas/test/webgl/non-conf-tests/mochitest.ini
+++ b/content/canvas/test/webgl/non-conf-tests/mochitest.ini
@@ -1,12 +1,13 @@
 [DEFAULT]
 support-files =
   driver-info.js
   webgl-util.js
 
+[test_depth_readpixels.html]
 [test_highp_fs.html]
 [test_no_arr_points.html]
 [test_privileged_exts.html]
 [test_webgl_available.html]
 [test_webgl_conformance.html]
 [test_webgl_request_context.html]
 [test_webgl_request_mismatch.html]
new file mode 100644
--- /dev/null
+++ b/content/canvas/test/webgl/non-conf-tests/test_depth_readpixels.html
@@ -0,0 +1,61 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<title>WebGL test: Check for error on ReadPixels from a depth-only FB.</title>
+<script src="/MochiKit/MochiKit.js"></script>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" href="/tests/SimpleTest/test.css">
+<script src="webgl-util.js"></script>
+<script src="driver-info.js"></script>
+</head>
+<body>
+<canvas id="c"></canvas>
+<script>
+"use strict";
+
+(function() {
+  var gl = WebGLUtil.getWebGL('c');
+  if (!gl) {
+    todo(gl, 'Get GL working here first.');
+    return;
+  }
+
+  var rb = gl.createRenderbuffer();
+  gl.bindRenderbuffer(gl.RENDERBUFFER, rb);
+  gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, 4, 4);
+
+  var fb = gl.createFramebuffer();
+  gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
+  gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT,
+                             gl.RENDERBUFFER, rb);
+
+  if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) {
+    todo(false, 'Depth-only FB incomplete. This is valid.');
+    return;
+  }
+
+  ok(!gl.getError(), 'Should have no errors after constructing FB.');
+
+  var pixels = new Uint8Array([1, 2, 3, 4]);
+  gl.readPixels(0, 0, // x,y
+                1, 1, // w,h
+                gl.RGBA, gl.UNSIGNED_BYTE, pixels);
+
+  ok(gl.getError() == gl.INVALID_OPERATION,
+     '1x1 color read from a depth FB should generated INVALID_OP.');
+  console.log('Data after 1x1 color-from-depth readpixels:');
+  console.log(pixels);
+
+  gl.readPixels(0, 0, // x,y
+                0, 0, // w,h
+                gl.RGBA, gl.UNSIGNED_BYTE, pixels);
+
+  ok(gl.getError() == gl.INVALID_OPERATION,
+     '0x0 color read from a depth FB should generated INVALID_OP.');
+})();
+
+ok(true, 'Test complete.');
+
+</script>
+</body>
+</html>
--- a/content/html/content/src/HTMLBRElement.cpp
+++ b/content/html/content/src/HTMLBRElement.cpp
@@ -32,18 +32,18 @@ NS_IMPL_ISUPPORTS_INHERITED1(HTMLBREleme
 NS_IMPL_ELEMENT_CLONE(HTMLBRElement)
 
 
 NS_IMPL_STRING_ATTR(HTMLBRElement, Clear, clear)
 
 static const nsAttrValue::EnumTable kClearTable[] = {
   { "left", NS_STYLE_CLEAR_LEFT },
   { "right", NS_STYLE_CLEAR_RIGHT },
-  { "all", NS_STYLE_CLEAR_LEFT_AND_RIGHT },
-  { "both", NS_STYLE_CLEAR_LEFT_AND_RIGHT },
+  { "all", NS_STYLE_CLEAR_BOTH },
+  { "both", NS_STYLE_CLEAR_BOTH },
   { 0 }
 };
 
 bool
 HTMLBRElement::ParseAttribute(int32_t aNamespaceID,
                               nsIAtom* aAttribute,
                               const nsAString& aValue,
                               nsAttrValue& aResult)
--- a/content/html/content/src/HTMLInputElement.cpp
+++ b/content/html/content/src/HTMLInputElement.cpp
@@ -15,16 +15,17 @@
 #include "nsITextControlElement.h"
 #include "nsIDOMNSEditableElement.h"
 #include "nsIRadioVisitor.h"
 #include "nsIPhonetic.h"
 
 #include "nsIControllers.h"
 #include "nsIStringBundle.h"
 #include "nsFocusManager.h"
+#include "nsColorControlFrame.h"
 #include "nsNumberControlFrame.h"
 #include "nsPIDOMWindow.h"
 #include "nsRepeatService.h"
 #include "nsContentCID.h"
 #include "nsIComponentManager.h"
 #include "nsIDOMHTMLFormElement.h"
 #include "nsIDOMProgressEvent.h"
 #include "nsGkAtoms.h"
@@ -2800,22 +2801,22 @@ HTMLInputElement::SetValueInternal(const
             do_QueryFrame(GetPrimaryFrame());
           if (numberControlFrame) {
             numberControlFrame->SetValueOfAnonTextControl(value);
           }
         }
         OnValueChanged(!mParserCreating);
       }
 
-      // Call parent's SetAttr for color input so its control frame is notified
-      // and updated
       if (mType == NS_FORM_INPUT_COLOR) {
-        return nsGenericHTMLFormElement::SetAttr(kNameSpaceID_None,
-                                                 nsGkAtoms::value, aValue,
-                                                 true);
+        // Update color frame, to reflect color changes
+        nsColorControlFrame* colorControlFrame = do_QueryFrame(GetPrimaryFrame());
+        if (colorControlFrame) {
+          colorControlFrame->UpdateColor();
+        }
       }
 
       return NS_OK;
     }
 
     case VALUE_MODE_DEFAULT:
     case VALUE_MODE_DEFAULT_ON:
       // If the value of a hidden input was changed, we mark it changed so that we
--- a/content/html/content/test/forms/mochitest.ini
+++ b/content/html/content/test/forms/mochitest.ini
@@ -15,16 +15,17 @@ support-files =
 [test_form_attributes_reflection.html]
 [test_formaction_attribute.html]
 [test_formnovalidate_attribute.html]
 [test_input_attributes_reflection.html]
 [test_input_color_input_change_events.html]
 [test_input_color_picker_initial.html]
 [test_input_color_picker_popup.html]
 [test_input_color_picker_update.html]
+[test_input_defaultValue.html]
 [test_input_email.html]
 [test_input_event.html]
 [test_input_file_picker.html]
 [test_input_list_attribute.html]
 [test_input_number_l10n.html]
 # We don't build ICU for Firefox for Android or Firefox OS:
 skip-if = os == "android" || appname == "b2g"
 [test_input_number_key_events.html]
new file mode 100644
--- /dev/null
+++ b/content/html/content/test/forms/test_input_defaultValue.html
@@ -0,0 +1,81 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=977029
+-->
+<head>
+  <title>Test for Bug 977029</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+</head>
+<body>
+<div id="content">
+  <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=977029">Bug 977029</a>
+  <p>
+    Goal of this test is to check that modifying defaultValue and value attribute
+    of input types is working as expected.
+  </p>
+  <form>
+    <input id='a' type="color" value="#00ff00">
+    <input id='b' type="text" value="foo">
+    <input id='c' type="email" value="foo">
+    <input id='d' type="date" value="2010-09-20">
+    <input id='e' type="search" value="foo">
+    <input id='f' type="tel" value="foo">
+    <input id='g' type="url" value="foo">
+    <input id='h' type="number" value="42">
+    <input id='i' type="range" value="42" min="0" max="100">
+    <input id='j' type="time" value="17:00:25.54">
+  </form>
+</div>
+<script type="application/javascript">
+
+// [ element id | original defaultValue | another value | another default value]
+// Preferably use only valid values: the goal of this test isn't to test the 
+// value sanitization algorithm (for input types which have one) as this is
+// already part of another test)
+var testData = [["a", "#00ff00", "#00aaaa", "#00ccaa"],
+                ["b", "foo", "bar", "tulip"],
+                ["c", "foo", "foo@bar.org", "tulip"],
+                ["d", "2010-09-20", "2012-09-21", ""],
+                ["e", "foo", "bar", "tulip"],
+                ["f", "foo", "bar", "tulip"],
+                ["g", "foo", "bar", "tulip"],
+                ["h", "42", "1337", "3"],
+                ["i", "42", "17", "3"],
+                ["j", "17:00:25.54", "07:00:25", "03:00:03"],
+               ];
+
+for (var data of testData) {
+  id = data[0];
+  input = document.getElementById(id);
+  originalDefaultValue = data[1];
+  is(originalDefaultValue, input.defaultValue,
+    "Default value isn't the expected one");
+  is(originalDefaultValue, input.value,
+    "input.value original value is different from defaultValue");
+  input.defaultValue = data[2]
+  is(input.defaultValue, input.value,
+    "Changing default value before value was changed should change value too");
+  input.value = data[3];
+  input.defaultValue = originalDefaultValue;
+  is(input.value, data[3],
+    "Changing default value after value was changed should not change value");
+  input.value = data[2];
+  is(originalDefaultValue, input.defaultValue,
+    "defaultValue shouldn't change when changing value");
+  input.defaultValue = data[3];
+  is(input.defaultValue, data[3],
+    "defaultValue should have changed");
+  // Change the value...
+  input.value = data[2];
+  is(input.value, data[2],
+    "value should have changed");
+  // ...then reset the form
+  input.form.reset();
+  is(input.defaultValue, input.value,
+    "reset form should bring back the default value");
+}
+</script>
+</body>
+</html>
+
--- a/content/media/MediaDecoderStateMachine.cpp
+++ b/content/media/MediaDecoderStateMachine.cpp
@@ -2444,16 +2444,25 @@ bool MediaDecoderStateMachine::JustExite
     mQuickBuffering &&
     (TimeStamp::Now() - mDecodeStartTime) < TimeDuration::FromMicroseconds(QUICK_BUFFER_THRESHOLD_USECS);
 }
 
 void MediaDecoderStateMachine::StartBuffering()
 {
   AssertCurrentThreadInMonitor();
 
+  if (mState != DECODER_STATE_DECODING) {
+    // We only move into BUFFERING state if we're actually decoding.
+    // If we're currently doing something else, we don't need to buffer,
+    // and more importantly, we shouldn't overwrite mState to interrupt
+    // the current operation, as that could leave us in an inconsistent
+    // state!
+    return;
+  }
+
   if (IsPlaying()) {
     StopPlayback();
   }
 
   TimeDuration decodeDuration = TimeStamp::Now() - mDecodeStartTime;
   // Go into quick buffering mode provided we've not just left buffering using
   // a "quick exit". This stops us flip-flopping between playing and buffering
   // when the download speed is similar to the decode speed.
--- a/content/media/MediaResource.cpp
+++ b/content/media/MediaResource.cpp
@@ -1638,14 +1638,17 @@ public:
 
   RefPtr<MediaDecoder> mDecoder;
   int64_t mNumBytes;
   int64_t mOffset;
 };
 
 void BaseMediaResource::DispatchBytesConsumed(int64_t aNumBytes, int64_t aOffset)
 {
+  if (aNumBytes <= 0) {
+    return;
+  }
   RefPtr<nsIRunnable> event(new DispatchBytesConsumedEvent(mDecoder, aNumBytes, aOffset));
   NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
 }
 
 } // namespace mozilla
 
--- a/content/media/directshow/DirectShowReader.cpp
+++ b/content/media/directshow/DirectShowReader.cpp
@@ -79,16 +79,21 @@ ParseMP3Headers(MP3FrameParser *aParser,
   uint64_t offset = 0;
   while (aParser->NeedsData() && !aParser->ParsedHeaders()) {
     uint32_t bytesRead;
     char buffer[MAX_READ_SIZE];
     nsresult rv = aResource->ReadAt(offset, buffer,
                                     MAX_READ_SIZE, &bytesRead);
     NS_ENSURE_SUCCESS(rv, rv);
 
+    if (!bytesRead) {
+      // End of stream.
+      return NS_ERROR_FAILURE;
+    }
+
     aParser->Parse(buffer, bytesRead, offset);
     offset += bytesRead;
   }
 
   return aParser->IsMP3() ? NS_OK : NS_ERROR_FAILURE;
 }
 
 // Windows XP's MP3 decoder filter. This is available on XP only, on Vista
--- a/docshell/base/moz.build
+++ b/docshell/base/moz.build
@@ -32,16 +32,17 @@ XPIDL_SOURCES += [
     'nsIWebPageDescriptor.idl',
 ]
 
 XPIDL_MODULE = 'docshell'
 
 EXPORTS += [
     'nsDocShellLoadTypes.h',
     'nsILinkHandler.h',
+    'nsIScrollObserver.h',
     'nsIWebShellServices.h',
     'SerializedLoadContext.h',
 ]
 
 EXPORTS.mozilla += [
     'IHistory.h',
     'LoadContext.h',
 ]
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -62,16 +62,17 @@
 #include "nsWidgetsCID.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsView.h"
 #include "nsViewManager.h"
 #include "nsIScriptChannel.h"
 #include "nsITimedChannel.h"
 #include "nsIPrivacyTransitionObserver.h"
 #include "nsIReflowObserver.h"
+#include "nsIScrollObserver.h"
 #include "nsIDocShellTreeItem.h"
 #include "nsIChannel.h"
 #include "IHistory.h"
 #include "nsViewSourceHandler.h"
 
 // we want to explore making the document own the load group
 // so we can associate the document URI with the load group.
 // until this point, we have an evil hack:
@@ -2852,16 +2853,49 @@ nsDocShell::GetCurrentDocChannel()
         nsIDocument* doc = mContentViewer->GetDocument();
         if (doc) {
             return doc->GetChannel();
         }
     }
     return nullptr;
 }
 
+NS_IMETHODIMP
+nsDocShell::AddWeakScrollObserver(nsIScrollObserver* aObserver)
+{
+    nsWeakPtr weakObs = do_GetWeakReference(aObserver);
+    if (!weakObs) {
+        return NS_ERROR_FAILURE;
+    }
+    return mScrollObservers.AppendElement(weakObs) ? NS_OK : NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+nsDocShell::RemoveWeakScrollObserver(nsIScrollObserver* aObserver)
+{
+    nsWeakPtr obs = do_GetWeakReference(aObserver);
+    return mScrollObservers.RemoveElement(obs) ? NS_OK : NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+nsDocShell::NotifyScrollObservers()
+{
+    nsTObserverArray<nsWeakPtr>::ForwardIterator iter(mScrollObservers);
+    while (iter.HasMore()) {
+        nsWeakPtr ref = iter.GetNext();
+        nsCOMPtr<nsIScrollObserver> obs = do_QueryReferent(ref);
+        if (obs) {
+            obs->ScrollPositionChanged();
+        } else {
+            mScrollObservers.RemoveElement(ref);
+        }
+    }
+    return NS_OK;
+}
+
 //*****************************************************************************
 // nsDocShell::nsIDocShellTreeItem
 //*****************************************************************************   
 
 NS_IMETHODIMP
 nsDocShell::GetName(nsAString& aName)
 {
     aName = mName;
@@ -9275,29 +9309,16 @@ nsDocShell::InternalLoad(nsIURI * aURI,
         // that history.go(0) and the like trigger full refreshes, rather than
         // short-circuited loads.
         bool doShortCircuitedLoad =
           (historyNavBetweenSameDoc && mOSHE != aSHEntry) ||
           (!aSHEntry && aPostData == nullptr &&
            sameExceptHashes && !newHash.IsEmpty());
 
         if (doShortCircuitedLoad) {
-            // Cancel an outstanding new-document load if this is a history
-            // load.
-            //
-            // We can't cancel the oustanding load unconditionally, because if a
-            // page does
-            //   - load a.html
-            //   - start loading b.html
-            //   - load a.html#h
-            // we break the web if we cancel the load of b.html.
-            if (aSHEntry && mDocumentRequest) {
-                mDocumentRequest->Cancel(NS_BINDING_ABORTED);
-            }
-
             // Save the position of the scrollers.
             nscoord cx = 0, cy = 0;
             GetCurScrollPos(ScrollOrientation_X, &cx);
             GetCurScrollPos(ScrollOrientation_Y, &cy);
 
             // ScrollToAnchor doesn't necessarily cause us to scroll the window;
             // the function decides whether a scroll is appropriate based on the
             // arguments it receives.  But even if we don't end up scrolling,
@@ -9319,16 +9340,18 @@ nsDocShell::InternalLoad(nsIURI * aURI,
                 mLoadType = LOAD_NORMAL_REPLACE;
             }
             else {
                 mLoadType = aLoadType;
             }
 
             mURIResultedInDocument = true;
 
+            nsCOMPtr<nsISHEntry> oldLSHE = mLSHE;
+
             /* we need to assign mLSHE to aSHEntry right here, so that on History loads,
              * SetCurrentURI() called from OnNewURI() will send proper
              * onLocationChange() notifications to the browser to update
              * back/forward buttons.
              */
             SetHistoryEntry(&mLSHE, aSHEntry);
 
             /* This is a anchor traversal with in the same page.
@@ -9396,20 +9419,20 @@ nsDocShell::InternalLoad(nsIURI * aURI,
              */
             if (mOSHE && (aLoadType == LOAD_HISTORY || aLoadType == LOAD_RELOAD_NORMAL))
             {
                 nscoord bx, by;
                 mOSHE->GetScrollPosition(&bx, &by);
                 SetCurScrollPosEx(bx, by);
             }
 
-            /* Clear out mLSHE so that further anchor visits get
-             * recorded in SH and SH won't misbehave. 
+            /* Restore the original LSHE if we were loading something
+             * while short-circuited load was initiated.
              */
-            SetHistoryEntry(&mLSHE, nullptr);
+            SetHistoryEntry(&mLSHE, oldLSHE);
             /* Set the title for the SH entry for this target url. so that
              * SH menus in go/back/forward buttons won't be empty for this.
              */
             if (mSessionHistory) {
                 int32_t index = -1;
                 mSessionHistory->GetIndex(&index);
                 nsCOMPtr<nsISHEntry> shEntry;
                 mSessionHistory->GetEntryAtIndex(index, false,
--- a/docshell/base/nsDocShell.h
+++ b/docshell/base/nsDocShell.h
@@ -895,16 +895,17 @@ protected:
 
 private:
     nsCString         mForcedCharset;
     nsCString         mParentCharset;
     int32_t           mParentCharsetSource;
     nsCOMPtr<nsIPrincipal> mParentCharsetPrincipal;
     nsTObserverArray<nsWeakPtr> mPrivacyObservers;
     nsTObserverArray<nsWeakPtr> mReflowObservers;
+    nsTObserverArray<nsWeakPtr> mScrollObservers;
     nsCString         mOriginalUriString;
 
     // Separate function to do the actual name (i.e. not _top, _self etc.)
     // searching for FindItemWithName.
     nsresult DoFindItemWithName(const char16_t* aName,
                                 nsISupports* aRequestor,
                                 nsIDocShellTreeItem* aOriginalRequestor,
                                 nsIDocShellTreeItem** _retval);
--- a/docshell/base/nsIDocShell.idl
+++ b/docshell/base/nsIDocShell.idl
@@ -36,20 +36,21 @@ interface nsILayoutHistoryState;
 interface nsISecureBrowserUI;
 interface nsIScriptGlobalObject;
 interface nsIDOMStorage;
 interface nsIPrincipal;
 interface nsIWebBrowserPrint;
 interface nsIVariant;
 interface nsIPrivacyTransitionObserver;
 interface nsIReflowObserver;
+interface nsIScrollObserver;
 
 typedef unsigned long nsLoadFlags;
 
-[scriptable, builtinclass, uuid(d0eaef67-4234-47de-b05a-9c7b324eb4f4)]
+[scriptable, builtinclass, uuid(e46d924d-c20f-4add-8cf5-1e1c817b2181)]
 interface nsIDocShell : nsIDocShellTreeItem
 {
   /**
    * Loads a given URI.  This will give priority to loading the requested URI
    * in the object implementing	this interface.  If it can't be loaded here
    * however, the URL dispatcher will go through its normal process of content
    * loading.
    *
@@ -663,16 +664,34 @@ interface nsIDocShell : nsIDocShellTreeI
    * @param end           timestamp when reflow ended, in milliseconds since
    *                      navigationStart (accurate to 1/1000 of a ms)
    */
   [noscript] void notifyReflowObservers(in bool interruptible,
                                         in DOMHighResTimeStamp start,
                                         in DOMHighResTimeStamp end);
 
   /**
+   * Add an observer to the list of parties to be notified when scroll position
+   * of some elements is changed.
+   */
+  [noscript] void addWeakScrollObserver(in nsIScrollObserver obs);
+
+  /**
+   * Add an observer to the list of parties to be notified when scroll position
+   * of some elements is changed.
+   */
+  [noscript] void removeWeakScrollObserver(in nsIScrollObserver obs);
+
+  /**
+   * Notify all attached observers that the scroll position of some element
+   * has changed.
+   */
+  [noscript] void notifyScrollObservers();
+
+  /**
    * Returns true if this docshell corresponds to an <iframe mozbrowser>.
    * (<iframe mozapp mozbrowser> is not considered a browser.)
    */
   [infallible] readonly attribute boolean isBrowserElement;
 
   /**
    * Returns true iff the docshell corresponds to an <iframe mozapp>.
    */
new file mode 100644
--- /dev/null
+++ b/docshell/base/nsIScrollObserver.h
@@ -0,0 +1,28 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef nsIScrollObserver_h___
+#define nsIScrollObserver_h___
+
+#include "nsISupports.h"
+
+#define NS_ISCROLLOBSERVER_IID \
+  { 0x7c1a8b63, 0xe322, 0x4827, \
+    { 0xa4, 0xb1, 0x3b, 0x6e, 0x59, 0x03, 0x47, 0x7e } }
+
+class nsIScrollObserver : public nsISupports
+{
+public:
+  NS_DECLARE_STATIC_IID_ACCESSOR(NS_ISCROLLOBSERVER_IID)
+
+  /**
+   * Called when the scroll position of some element has changed.
+   */
+  virtual void ScrollPositionChanged() = 0;
+};
+
+NS_DEFINE_STATIC_IID_ACCESSOR(nsIScrollObserver, NS_ISCROLLOBSERVER_IID)
+
+#endif /* nsIScrollObserver_h___ */
new file mode 100644
--- /dev/null
+++ b/docshell/test/navigation/file_fragment_handling_during_load.html
@@ -0,0 +1,24 @@
+<html>
+  <head>
+    <script>
+      var timerID = 0;
+      function testDone() {
+        clearTimeout(timerID);
+        var l = document.body.firstChild.contentWindow.location.href;
+        opener.is(l, "data:text/html,bar", "Should have loaded a new document");
+        opener.nextTest();
+        window.close();
+      }
+      function test() {
+        var ifr = document.getElementsByTagName("iframe")[0];
+        ifr.onload = testDone;
+        ifr.contentWindow.location.hash = "b";
+        ifr.contentWindow.location.href = "data:text/html,bar";
+        history.back();
+        timerID = setTimeout(testDone, 2000);
+      }
+    </script>
+  </head>
+  <body onload="setTimeout(test, 0)"><iframe src="data:text/html,foo#a"></iframe>
+  </body>
+</html>
--- a/docshell/test/navigation/mochitest.ini
+++ b/docshell/test/navigation/mochitest.ini
@@ -3,16 +3,17 @@ support-files =
   NavigationUtils.js
   blank.html
   file_bug462076_1.html
   file_bug462076_2.html
   file_bug462076_3.html
   file_bug508537_1.html
   file_bug534178.html
   file_document_write_1.html
+  file_fragment_handling_during_load.html
   file_static_and_dynamic_1.html
   frame0.html
   frame1.html
   frame2.html
   frame3.html
   goback.html
   iframe.html
   navigate.html
--- a/docshell/test/navigation/test_sessionhistory.html
+++ b/docshell/test/navigation/test_sessionhistory.html
@@ -21,17 +21,18 @@ https://bugzilla.mozilla.org/show_bug.cg
 
 var testFiles =
   [ "file_bug462076_1.html",         // Dynamic frames before onload
     "file_bug462076_2.html",         // Dynamic frames when handling onload
     "file_bug462076_3.html",         // Dynamic frames after onload
     "file_bug508537_1.html",         // Dynamic frames and forward-back
     "file_document_write_1.html",    // Session history + document.write
     "file_static_and_dynamic_1.html",// Static and dynamic frames and forward-back
-    "file_bug534178.html"            // Session history transaction clean-up.
+    "file_bug534178.html",           // Session history transaction clean-up.
+    "file_fragment_handling_during_load.html"
   ];
 var testCount = 0; // Used by the test files.
 
 SimpleTest.waitForExplicitFinish();
 
 var testWindow;
 function nextTest_() {
   if (testFiles.length) {
--- a/dom/apps/src/AppsServiceChild.jsm
+++ b/dom/apps/src/AppsServiceChild.jsm
@@ -3,287 +3,76 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const Cu = Components.utils;
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 
-// This module exposes a subset of the functionalities of the parent DOM
-// Registry to content processes, to be used from the AppsService component.
+// This module exposes a subset of the functionnalities of the parent DOM
+// Registry to content processes, to be be used from the AppsService component.
 
-this.EXPORTED_SYMBOLS = ["DOMApplicationRegistry", "WrappedManifestCache"];
+this.EXPORTED_SYMBOLS = ["DOMApplicationRegistry"];
 
 Cu.import("resource://gre/modules/AppsUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 
 function debug(s) {
   //dump("-*- AppsServiceChild.jsm: " + s + "\n");
 }
 
-const APPS_IPC_MSG_NAMES = [
-  "Webapps:AddApp",
-  "Webapps:RemoveApp",
-  "Webapps:CheckForUpdate:Return:KO",
-  "Webapps:FireEvent",
-  "Webapps:UpdateState"
-];
-
-// A simple cache for the wrapped manifests.
-this.WrappedManifestCache = {
-  _cache: { },
-
-  // Gets an entry from the cache, and populates the cache if needed.
-  get: function mcache_get(aManifestURL, aManifest, aWindow, aInnerWindowID) {
-    if (!(aManifestURL in this._cache)) {
-      this._cache[aManifestURL] = { };
-    }
-
-    let winObjs = this._cache[aManifestURL];
-    if (!(aInnerWindowID in winObjs)) {
-      winObjs[aInnerWindowID] = Cu.cloneInto(aManifest, aWindow);
-    }
-
-    return winObjs[aInnerWindowID];
-  },
-
-  // Invalidates an entry in the cache.
-  evict: function mcache_evict(aManifestURL, aInnerWindowID) {
-    debug("Evicting manifest " + aManifestURL + " window ID " +
-          aInnerWindowID);
-    if (aManifestURL in this._cache) {
-      let winObjs = this._cache[aManifestURL];
-      if (aInnerWindowID in winObjs) {
-        delete winObjs[aInnerWindowID];
-      }
-
-      if (Object.keys(winObjs).length == 0) {
-        delete this._cache[aManifestURL];
-      }
-    }
-  },
-
-  observe: function(aSubject, aTopic, aData) {
-    // Clear the cache on memory pressure.
-    this._cache = { };
-    Cu.forceGC();
-  },
-
-  init: function() {
-    Services.obs.addObserver(this, "memory-pressure", false);
-  }
-};
-
-this.WrappedManifestCache.init();
-
-
-// DOMApplicationRegistry keeps a cache containing a list of apps in the device.
-// This information is updated with the data received from the main process and
-// it is queried by the DOM objects to set their state.
-// This module handle all the messages broadcasted from the parent process,
-// including DOM events, which are dispatched to the corresponding DOM objects.
-
 this.DOMApplicationRegistry = {
-  // DOMApps will hold a list of arrays of weak references to
-  // mozIDOMApplication objects indexed by manifest URL.
-  DOMApps: {},
-
   init: function init() {
+    debug("init");
     this.cpmm = Cc["@mozilla.org/childprocessmessagemanager;1"]
                   .getService(Ci.nsISyncMessageSender);
 
-    APPS_IPC_MSG_NAMES.forEach((function(aMsgName) {
+    ["Webapps:AddApp", "Webapps:RemoveApp"].forEach((function(aMsgName) {
       this.cpmm.addMessageListener(aMsgName, this);
     }).bind(this));
 
-    this.cpmm.sendAsyncMessage("Webapps:RegisterForMessages", {
-      messages: APPS_IPC_MSG_NAMES
-    });
-
     // We need to prime the cache with the list of apps.
-    // XXX should we do this async and block callers if it's not yet there?
-    let list = this.cpmm.sendSyncMessage("Webapps:GetList", { })[0];
-    this.webapps = list.webapps;
+    // XXX shoud we do this async and block callers if it's not yet there?
+    this.webapps = this.cpmm.sendSyncMessage("Webapps:GetList", { })[0];
 
     // We need a fast mapping from localId -> app, so we add an index.
-    // And add the manifest to the app object.
     this.localIdIndex = { };
     for (let id in this.webapps) {
       let app = this.webapps[id];
       this.localIdIndex[app.localId] = app;
-      app.manifest = list.manifests[id];
     }
 
     Services.obs.addObserver(this, "xpcom-shutdown", false);
   },
 
   observe: function(aSubject, aTopic, aData) {
-    // cpmm.addMessageListener causes the DOMApplicationRegistry object to
-    // live forever if we don't clean up properly.
+    // cpmm.addMessageListener causes the DOMApplicationRegistry object to live
+    // forever if we don't clean up properly.
     this.webapps = null;
-    this.DOMApps = null;
-
-    APPS_IPC_MSG_NAMES.forEach((aMsgName) => {
+    ["Webapps:AddApp", "Webapps:RemoveApp"].forEach((function(aMsgName) {
       this.cpmm.removeMessageListener(aMsgName, this);
-    });
-
-    this.cpmm.sendAsyncMessage("Webapps:UnregisterForMessages",
-                               APPS_IPC_MSG_NAMES)
+    }).bind(this));
   },
 
   receiveMessage: function receiveMessage(aMessage) {
     debug("Received " + aMessage.name + " message.");
-    let msg = aMessage.data;
+    let msg = aMessage.json;
     switch (aMessage.name) {
       case "Webapps:AddApp":
         this.webapps[msg.id] = msg.app;
         this.localIdIndex[msg.app.localId] = msg.app;
         break;
       case "Webapps:RemoveApp":
-        delete this.DOMApps[this.webapps[msg.id].manifestURL];
         delete this.localIdIndex[this.webapps[msg.id].localId];
         delete this.webapps[msg.id];
         break;
-      case "Webapps:FireEvent":
-        this._fireEvent(aMessage);
-        break;
-      case "Webapps:UpdateState":
-        this._updateState(msg);
-        break;
-      case "Webapps:CheckForUpdate:Return:KO":
-        let DOMApps = this.DOMApps[msg.manifestURL];
-        if (!DOMApps || !msg.requestID) {
-          return;
-        }
-        DOMApps.forEach((DOMApp) => {
-          let domApp = DOMApp.get();
-          if (msg.requestID) {
-            domApp._fireRequestResult(aMessage, true /* aIsError */);
-          }
-        });
-        break;
     }
   },
 
-  /**
-   * mozIDOMApplication management
-   */
-
-  // Every time a DOM app is created, we save a weak reference to it that will
-  // be used to dispatch events and fire request results.
-  addDOMApp: function(aApp, aManifestURL, aId) {
-    let weakRef = Cu.getWeakReference(aApp);
-
-    if (!this.DOMApps[aManifestURL]) {
-      this.DOMApps[aManifestURL] = [];
-    }
-
-    let apps = this.DOMApps[aManifestURL];
-
-    // Get rid of dead weak references.
-    for (let i = 0; i < apps.length; i++) {
-      if (!apps[i].get()) {
-        apps.splice(i);
-      }
-    }
-
-    apps.push(weakRef);
-
-    // Each DOM app contains a proxy object used to build their state. We
-    // return the handler for this proxy object with traps to get and set
-    // app properties kept in the DOMApplicationRegistry app cache.
-    return {
-      get: function(target, prop) {
-        if (!DOMApplicationRegistry.webapps[aId]) {
-          return;
-        }
-        return DOMApplicationRegistry.webapps[aId][prop];
-      },
-      set: function(target, prop, val) {
-        if (!DOMApplicationRegistry.webapps[aId]) {
-          return;
-        }
-        DOMApplicationRegistry.webapps[aId][prop] = val;
-        return;
-      },
-    };
-  },
-
-  _fireEvent: function(aMessage) {
-    let msg = aMessage.data;
-    debug("_fireEvent " + JSON.stringify(msg));
-    if (!this.DOMApps || !msg.manifestURL || !msg.eventType) {
-      return;
-    }
-
-    let DOMApps = this.DOMApps[msg.manifestURL];
-    if (!DOMApps) {
-      return;
-    }
-
-    // The parent might ask childs to trigger more than one event in one
-    // shot, so in order to avoid needless IPC we allow an array for the
-    // 'eventType' IPC message field.
-    if (!Array.isArray(msg.eventType)) {
-      msg.eventType = [msg.eventType];
-    }
-
-    DOMApps.forEach((DOMApp) => {
-      let domApp = DOMApp.get();
-      msg.eventType.forEach((aEventType) => {
-        if ('on' + aEventType in domApp) {
-          domApp._fireEvent(aEventType);
-        }
-      });
-
-      if (msg.requestID) {
-        aMessage.data.result = msg.manifestURL;
-        domApp._fireRequestResult(aMessage);
-      }
-    });
-  },
-
-  _updateState: function(aMessage) {
-    if (!this.DOMApps || !aMessage.id) {
-      return;
-    }
-
-    let app = this.webapps[aMessage.id];
-    if (!app) {
-      return;
-    }
-
-    if (aMessage.app) {
-      for (let prop in aMessage.app) {
-        app[prop] = aMessage.app[prop];
-      }
-    }
-
-    if (aMessage.error) {
-      app.downloadError = aMessage.error;
-    }
-
-    if (aMessage.manifest) {
-      app.manifest = aMessage.manifest;
-      // Evict the wrapped manifest cache for all the affected DOM objects.
-      let DOMApps = this.DOMApps[app.manifestURL];
-      if (!DOMApps) {
-        return;
-      }
-      DOMApps.forEach((DOMApp) => {
-        let domApp = DOMApp.get();
-        WrappedManifestCache.evict(app.manifestURL, domApp.innerWindowID);
-      });
-    }
-  },
-
-  /**
-   * nsIAppsService API
-   */
   getAppByManifestURL: function getAppByManifestURL(aManifestURL) {
     debug("getAppByManifestURL " + aManifestURL);
     return AppsUtils.getAppByManifestURL(this.webapps, aManifestURL);
   },
 
   getAppLocalIdByManifestURL: function getAppLocalIdByManifestURL(aManifestURL) {
     debug("getAppLocalIdByManifestURL " + aManifestURL);
     return AppsUtils.getAppLocalIdByManifestURL(this.webapps, aManifestURL);
--- a/dom/apps/src/Webapps.js
+++ b/dom/apps/src/Webapps.js
@@ -7,17 +7,16 @@ const Ci = Components.interfaces;
 const Cu = Components.utils;
 const Cr = Components.results;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/DOMRequestHelper.jsm");
 Cu.import("resource://gre/modules/AppsUtils.jsm");
 Cu.import("resource://gre/modules/BrowserElementPromptService.jsm");
-Cu.import("resource://gre/modules/AppsServiceChild.jsm");
 
 XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
                                    "@mozilla.org/childprocessmessagemanager;1",
                                    "nsIMessageSender");
 
 function convertAppsArray(aApps, aWindow) {
   let apps = Cu.createArrayIn(aWindow);
   for (let i = 0; i < aApps.length; i++) {
@@ -260,121 +259,134 @@ WebappsRegistry.prototype = {
                                     flags: Ci.nsIClassInfo.DOM_OBJECT,
                                     classDescription: "Webapps Registry"})
 }
 
 /**
   * mozIDOMApplication object
   */
 
+// A simple cache for the wrapped manifests.
+let manifestCache = {
+  _cache: { },
+
+  // Gets an entry from the cache, and populates the cache if needed.
+  get: function mcache_get(aManifestURL, aManifest, aWindow, aInnerWindowID) {
+    if (!(aManifestURL in this._cache)) {
+      this._cache[aManifestURL] = { };
+    }
+
+    let winObjs = this._cache[aManifestURL];
+    if (!(aInnerWindowID in winObjs)) {
+      winObjs[aInnerWindowID] = Cu.cloneInto(aManifest, aWindow);
+    }
+
+    return winObjs[aInnerWindowID];
+  },
+
+  // Invalidates an entry in the cache.
+  evict: function mcache_evict(aManifestURL, aInnerWindowID) {
+    if (aManifestURL in this._cache) {
+      let winObjs = this._cache[aManifestURL];
+      if (aInnerWindowID in winObjs) {
+        delete winObjs[aInnerWindowID];
+      }
+
+      if (Object.keys(winObjs).length == 0) {
+        delete this._cache[aManifestURL];
+      }
+    }
+  },
+
+  observe: function(aSubject, aTopic, aData) {
+    // Clear the cache on memory pressure.
+    this._cache = { };
+  },
+
+  init: function() {
+    Services.obs.addObserver(this, "memory-pressure", false);
+  }
+};
+
 function createApplicationObject(aWindow, aApp) {
-  let app = Cc["@mozilla.org/webapps/application;1"]
-              .createInstance(Ci.mozIDOMApplication);
+  let app = Cc["@mozilla.org/webapps/application;1"].createInstance(Ci.mozIDOMApplication);
   app.wrappedJSObject.init(aWindow, aApp);
   return app;
 }
 
 function WebappsApplication() {
   this.wrappedJSObject = this;
 }
 
 WebappsApplication.prototype = {
   __proto__: DOMRequestIpcHelper.prototype,
 
   init: function(aWindow, aApp) {
-    let proxyHandler = DOMApplicationRegistry.addDOMApp(this,
-                                                        aApp.manifestURL,
-                                                        aApp.id);
-    this._proxy = new Proxy(this, proxyHandler);
-
     this._window = aWindow;
+    let principal = this._window.document.nodePrincipal;
+    this._appStatus = principal.appStatus;
+    this.origin = aApp.origin;
+    this._manifest = aApp.manifest;
+    this._updateManifest = aApp.updateManifest;
+    this.manifestURL = aApp.manifestURL;
+    this.receipts = aApp.receipts;
+    this.installOrigin = aApp.installOrigin;
+    this.installTime = aApp.installTime;
+    this.installState = aApp.installState || "installed";
+    this.removable = aApp.removable;
+    this.lastUpdateCheck = aApp.lastUpdateCheck ? aApp.lastUpdateCheck
+                                                : Date.now();
+    this.updateTime = aApp.updateTime ? aApp.updateTime
+                                      : aApp.installTime;
+    this.progress = NaN;
+    this.downloadAvailable = aApp.downloadAvailable;
+    this.downloading = aApp.downloading;
+    this.readyToApplyDownload = aApp.readyToApplyDownload;
+    this.downloadSize = aApp.downloadSize || 0;
 
     this._onprogress = null;
     this._ondownloadsuccess = null;
     this._ondownloaderror = null;
     this._ondownloadavailable = null;
     this._ondownloadapplied = null;
 
-    this.initDOMRequestHelper(aWindow);
-  },
-
-  get _appStatus() {
-    return this._proxy.appStatus;
-  },
-
-  get downloadAvailable() {
-    return this._proxy.downloadAvailable;
-  },
-
-  get downloading() {
-    return this._proxy.downloading;
-  },
+    this._downloadError = null;
 
-  get downloadSize() {
-    return this._proxy.downloadSize;
-  },
-
-  get installOrigin() {
-    return this._proxy.installOrigin;
-  },
-
-  get installState() {
-    return this._proxy.installState;
-  },
-
-  get installTime() {
-    return this._proxy.installTime;
-  },
+    this.initDOMRequestHelper(aWindow, [
+      { name: "Webapps:CheckForUpdate:Return:KO", weakRef: true },
+      { name: "Webapps:Connect:Return:OK", weakRef: true },
+      { name: "Webapps:Connect:Return:KO", weakRef: true },
+      { name: "Webapps:FireEvent", weakRef: true },
+      { name: "Webapps:GetConnections:Return:OK", weakRef: true },
+      { name: "Webapps:UpdateState", weakRef: true }
+    ]);
 
-  get lastUpdateCheck() {
-    return this._proxy.lastUpdateCheck;
-  },
-
-  get manifestURL() {
-    return this._proxy.manifestURL;
-  },
-
-  get origin() {
-    return this._proxy.origin;
-  },
-
-  get progress() {
-    return this._proxy.progress;
-  },
-
-  get readyToApplyDownload() {
-    return this._proxy.readyToApplyDownload;
-  },
-
-  get receipts() {
-    return this._proxy.receipts;
-  },
-
-  set receipts(aReceipts) {
-    this._proxy.receipts = aReceipts;
-  },
-
-  get removable() {
-    return this._proxy.removable;
-  },
-
-  get updateTime() {
-    return this._proxy.updateTime;
+    cpmm.sendAsyncMessage("Webapps:RegisterForMessages", {
+      messages: ["Webapps:FireEvent",
+                 "Webapps:UpdateState"],
+      app: {
+        id: this.id,
+        manifestURL: this.manifestURL,
+        installState: this.installState,
+        downloading: this.downloading
+      }
+    });
   },
 
   get manifest() {
-    return WrappedManifestCache.get(this.manifestURL,
-                                    this._proxy.manifest,
-                                    this._window,
-                                    this.innerWindowID);
+    return manifestCache.get(this.manifestURL,
+                             this._manifest,
+                             this._window,
+                             this.innerWindowID);
   },
 
   get updateManifest() {
-    return this._proxy.updateManifest ?
-      Cu.cloneInto(this._proxy.updateManifest, this._window) : null;
+    return this.updateManifest =
+      this._updateManifest ? Cu.cloneInto(this._updateManifest, this._window)
+                           : null;
   },
 
   set onprogress(aCallback) {
     this._onprogress = aCallback;
   },
 
   get onprogress() {
     return this._onprogress;
@@ -408,17 +420,17 @@ WebappsApplication.prototype = {
     this._ondownloadapplied = aCallback;
   },
 
   get ondownloadapplied() {
     return this._ondownloadapplied;
   },
 
   get downloadError() {
-    return new this._window.DOMError(this._proxy.downloadError || '');
+    return new this._window.DOMError(this._downloadError || '');
   },
 
   download: function() {
     cpmm.sendAsyncMessage("Webapps:Download",
                           { manifestURL: this.manifestURL });
   },
 
   cancelDownload: function() {
@@ -450,56 +462,52 @@ WebappsApplication.prototype = {
   },
 
   clearBrowserData: function() {
     let request = this.createRequest();
     let browserChild =
       BrowserElementPromptService.getBrowserElementChildForWindow(this._window);
     if (browserChild) {
       this.addMessageListeners("Webapps:ClearBrowserData:Return");
-      browserChild.messageManager.sendAsyncMessage("Webapps:ClearBrowserData", {
-        manifestURL: this.manifestURL,
-        oid: this._id,
-        requestID: this.getRequestId(request)
-      });
+      browserChild.messageManager.sendAsyncMessage(
+        "Webapps:ClearBrowserData",
+        { manifestURL: this.manifestURL,
+          oid: this._id,
+          requestID: this.getRequestId(request) }
+      );
     } else {
       Services.DOMRequest.fireErrorAsync(request, "NO_CLEARABLE_BROWSER");
     }
     return request;
   },
 
   connect: function(aKeyword, aRules) {
-    this.addMessageListeners(["Webapps:Connect:Return:OK",
-                              "Webapps:Connect:Return:KO"]);
     return this.createPromise(function (aResolve, aReject) {
-      cpmm.sendAsyncMessage("Webapps:Connect", {
-        keyword: aKeyword,
-        rules: aRules,
-        manifestURL: this.manifestURL,
-        outerWindowID: this._id,
-        appStatus: this._appStatus,
-        requestID: this.getPromiseResolverId({
-          resolve: aResolve,
-          reject: aReject
-        })
-      });
+      cpmm.sendAsyncMessage("Webapps:Connect",
+                            { keyword: aKeyword,
+                              rules: aRules,
+                              manifestURL: this.manifestURL,
+                              outerWindowID: this._id,
+                              appStatus: this._appStatus,
+                              requestID: this.getPromiseResolverId({
+                                resolve: aResolve,
+                                reject: aReject
+                              })});
     }.bind(this));
   },
 
   getConnections: function() {
-    this.addMessageListeners("Webapps:getConnections:Return:OK");
     return this.createPromise(function (aResolve, aReject) {
-      cpmm.sendAsyncMessage("Webapps:GetConnections", {
-        manifestURL: this.manifestURL,
-        outerWindowID: this._id,
-        requestID: this.getPromiseResolverId({
-          resolve: aResolve,
-          reject: aReject
-        })
-      });
+      cpmm.sendAsyncMessage("Webapps:GetConnections",
+                            { manifestURL: this.manifestURL,
+                              outerWindowID: this._id,
+                              requestID: this.getPromiseResolverId({
+                                resolve: aResolve,
+                                reject: aReject
+                              })});
     }.bind(this));
   },
 
   addReceipt: function(receipt) {
     let request = this.createRequest();
 
     this.addMessageListeners(["Webapps:AddReceipt:Return:OK",
                               "Webapps:AddReceipt:Return:KO"]);
@@ -538,91 +546,134 @@ WebappsApplication.prototype = {
                                                       oid: this._id,
                                                       requestID: this.getRequestId(request) });
 
     return request;
   },
 
   uninit: function() {
     this._onprogress = null;
-    WrappedManifestCache.evict(this.manifestURL, this.innerWindowID);
+    cpmm.sendAsyncMessage("Webapps:UnregisterForMessages", [
+      "Webapps:FireEvent",
+      "Webapps:UpdateState"
+    ]);
+
+    manifestCache.evict(this.manifestURL, this.innerWindowID);
   },
 
   _fireEvent: function(aName) {
     let handler = this["_on" + aName];
     if (handler) {
       let event = new this._window.MozApplicationEvent(aName, {
         application: this
       });
       try {
         handler.handleEvent(event);
       } catch (ex) {
         dump("Event handler expection " + ex + "\n");
       }
     }
   },
 
-  _fireRequestResult: function(aMessage, aIsError) {
-    let req;
-    let msg = aMessage.data;
-    req = this.takeRequest(msg.requestID);
-    if (!req) {
-      return;
+  _updateState: function(aMsg) {
+    if (aMsg.app) {
+      for (let prop in aMsg.app) {
+        this[prop] = aMsg.app[prop];
+      }
     }
-    aIsError ? Services.DOMRequest.fireError(req, msg.error)
-             : Services.DOMRequest.fireSuccess(req, msg.result);
+
+    if (aMsg.error) {
+      this._downloadError = aMsg.error;
+    }
+
+    if (aMsg.manifest) {
+      this._manifest = aMsg.manifest;
+      manifestCache.evict(this.manifestURL, this.innerWindowID);
+    }
   },
 
   receiveMessage: function(aMessage) {
     let msg = aMessage.json;
     let req;
     if (aMessage.name == "Webapps:Connect:Return:OK" ||
         aMessage.name == "Webapps:Connect:Return:KO" ||
         aMessage.name == "Webapps:GetConnections:Return:OK") {
       req = this.takePromiseResolver(msg.requestID);
     } else {
       req = this.takeRequest(msg.requestID);
     }
 
-    if (msg.oid != this._id || !req) {
+    // ondownload* callbacks should be triggered on all app instances
+    if ((msg.oid != this._id || !req) &&
+        aMessage.name !== "Webapps:FireEvent" &&
+        aMessage.name !== "Webapps:UpdateState") {
       return;
     }
 
     switch (aMessage.name) {
       case "Webapps:Launch:Return:KO":
         this.removeMessageListeners(["Webapps:Launch:Return:OK",
                                      "Webapps:Launch:Return:KO"]);
         Services.DOMRequest.fireError(req, "APP_INSTALL_PENDING");
         break;
       case "Webapps:Launch:Return:OK":
         this.removeMessageListeners(["Webapps:Launch:Return:OK",
                                      "Webapps:Launch:Return:KO"]);
         Services.DOMRequest.fireSuccess(req, null);
         break;
+      case "Webapps:CheckForUpdate:Return:KO":
+        Services.DOMRequest.fireError(req, msg.error);
+        break;
+      case "Webapps:FireEvent":
+        if (msg.manifestURL != this.manifestURL) {
+           return;
+        }
+
+        // The parent might ask childs to trigger more than one event in one
+        // shot, so in order to avoid needless IPC we allow an array for the
+        // 'eventType' IPC message field.
+        if (!Array.isArray(msg.eventType)) {
+          msg.eventType = [msg.eventType];
+        }
+
+        msg.eventType.forEach((aEventType) => {
+          if ("_on" + aEventType in this) {
+            this._fireEvent(aEventType);
+          } else {
+            dump("Unsupported event type " + aEventType + "\n");
+          }
+        });
+
+        if (req) {
+          Services.DOMRequest.fireSuccess(req, this.manifestURL);
+        }
+        break;
+      case "Webapps:UpdateState":
+        if (msg.manifestURL != this.manifestURL) {
+          return;
+        }
+
+        this._updateState(msg);
+        break;
       case "Webapps:ClearBrowserData:Return":
         this.removeMessageListeners(aMessage.name);
         Services.DOMRequest.fireSuccess(req, null);
         break;
       case "Webapps:Connect:Return:OK":
-        this.removeMessageListeners(["Webapps:Connect:Return:OK",
-                                     "Webapps:Connect:Return:KO"]);
         let messagePorts = [];
         msg.messagePortIDs.forEach((aPortID) => {
           let port = new this._window.MozInterAppMessagePort(aPortID);
           messagePorts.push(port);
         });
         req.resolve(messagePorts);
         break;
       case "Webapps:Connect:Return:KO":
-        this.removeMessageListeners(["Webapps:Connect:Return:OK",
-                                     "Webapps:Connect:Return:KO"]);
         req.reject("No connections registered");
         break;
       case "Webapps:GetConnections:Return:OK":
-        this.removeMessageListeners(aMessage.name);
         let connections = [];
         msg.connections.forEach((aConnection) => {
           let connection =
             new this._window.MozInterAppConnection(aConnection.keyword,
                                                    aConnection.pubAppManifestURL,
                                                    aConnection.subAppManifestURL);
           connections.push(connection);
         });
@@ -794,18 +845,22 @@ WebappsApplicationMgmt.prototype = {
           let app = msg.app;
           let event = new this._window.MozApplicationEvent("applicationinstall",
                            { application : createApplicationObject(this._window, app) });
           this._oninstall.handleEvent(event);
         }
         break;
       case "Webapps:Uninstall:Broadcast:Return:OK":
         if (this._onuninstall) {
+          let detail = {
+            manifestURL: msg.manifestURL,
+            origin: msg.origin
+          };
           let event = new this._window.MozApplicationEvent("applicationuninstall",
-                           { application : createApplicationObject(this._window, msg) });
+                           { application : createApplicationObject(this._window, detail) });
           this._onuninstall.handleEvent(event);
         }
         break;
       case "Webapps:Uninstall:Return:OK":
         Services.DOMRequest.fireSuccess(req, msg.origin);
         break;
       case "Webapps:Uninstall:Return:KO":
         Services.DOMRequest.fireError(req, "NOT_INSTALLED");
@@ -824,10 +879,12 @@ WebappsApplicationMgmt.prototype = {
 
   classInfo: XPCOMUtils.generateCI({classID: Components.ID("{8c1bca96-266f-493a-8d57-ec7a95098c15}"),
                                     contractID: "@mozilla.org/webapps/application-mgmt;1",
                                     interfaces: [Ci.mozIDOMApplicationMgmt],
                                     flags: Ci.nsIClassInfo.DOM_OBJECT,
                                     classDescription: "Webapps Application Mgmt"})
 }
 
+manifestCache.init();
+
 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([WebappsRegistry,
                                                      WebappsApplication]);
--- a/dom/apps/src/Webapps.jsm
+++ b/dom/apps/src/Webapps.jsm
@@ -1137,17 +1137,18 @@ this.DOMApplicationRegistry = {
         break;
       case "Webapps:UnregisterForMessages":
         this.removeMessageListener(msg, mm);
         break;
       case "child-process-shutdown":
         this.removeMessageListener(["Webapps:Internal:AllMessages"], mm);
         break;
       case "Webapps:GetList":
-        return { webapps: this.webapps, manifests: this._manifestCache };
+        this.addMessageListener(["Webapps:AddApp", "Webapps:RemoveApp"], null, mm);
+        return this.webapps;
       case "Webapps:Download":
         this.startDownload(msg.manifestURL);
         break;
       case "Webapps:CancelDownload":
         this.cancelDownload(msg.manifestURL);
         break;
       case "Webapps:CheckForUpdate":
         this.checkForUpdate(msg, mm);
@@ -1282,17 +1283,17 @@ this.DOMApplicationRegistry = {
     this._saveApps().then(() => {
       this.broadcastMessage("Webapps:UpdateState", {
         app: {
           progress: 0,
           installState: download.previousState,
           downloading: false
         },
         error: error,
-        id: app.id
+        manifestURL: app.manifestURL,
       })
       this.broadcastMessage("Webapps:FireEvent", {
         eventType: "downloaderror",
         manifestURL: app.manifestURL
       });
     });
     AppDownloadManager.remove(aManifestURL);
   },
@@ -1311,17 +1312,17 @@ this.DOMApplicationRegistry = {
       return;
     }
 
     // If the caller is trying to start a download but we have nothing to
     // download, send an error.
     if (!app.downloadAvailable) {
       this.broadcastMessage("Webapps:UpdateState", {
         error: "NO_DOWNLOAD_AVAILABLE",
-        id: app.id
+        manifestURL: app.manifestURL
       });
       this.broadcastMessage("Webapps:FireEvent", {
         eventType: "downloaderror",
         manifestURL: app.manifestURL
       });
       return;
     }
 
@@ -1356,17 +1357,17 @@ this.DOMApplicationRegistry = {
           // Hosted app with no appcache, nothing to do, but we fire a
           // downloaded event.
           debug("No appcache found, sending 'downloaded' for " + aManifestURL);
           app.downloadAvailable = false;
           this._saveApps().then(() => {
             this.broadcastMessage("Webapps:UpdateState", {
               app: app,
               manifest: jsonManifest,
-              id: app.id
+              manifestURL: aManifestURL
             });
             this.broadcastMessage("Webapps:FireEvent", {
               eventType: "downloadsuccess",
               manifestURL: aManifestURL
             });
           });
         }
       });
@@ -1399,17 +1400,17 @@ this.DOMApplicationRegistry = {
           // Set state and fire events.
           app.downloading = false;
           app.downloadAvailable = false;
           app.readyToApplyDownload = true;
           app.updateTime = Date.now();
           DOMApplicationRegistry._saveApps().then(() => {
             DOMApplicationRegistry.broadcastMessage("Webapps:UpdateState", {
               app: app,
-              id: app.id
+              manifestURL: aManifestURL
             });
             DOMApplicationRegistry.broadcastMessage("Webapps:FireEvent", {
               eventType: "downloadsuccess",
               manifestURL: aManifestURL
             });
             if (app.installState == "pending") {
               // We restarted a failed download, apply it automatically.
               DOMApplicationRegistry.applyDownload(aManifestURL);
@@ -1493,17 +1494,17 @@ this.DOMApplicationRegistry = {
                 manifestURL: app.manifestURL },
               true);
           }
           this.updateDataStore(this.webapps[id].localId, app.origin,
                                app.manifestURL, aData, app.appStatus);
           this.broadcastMessage("Webapps:UpdateState", {
             app: app,
             manifest: aData,
-            id: app.id
+            manifestURL: app.manifestURL
           });
           this.broadcastMessage("Webapps:FireEvent", {
             eventType: "downloadapplied",
             manifestURL: app.manifestURL
           });
         });
       });
     });
@@ -1533,17 +1534,17 @@ this.DOMApplicationRegistry = {
     aApp.progress = 0;
     DOMApplicationRegistry._saveApps().then(() => {
       DOMApplicationRegistry.broadcastMessage("Webapps:UpdateState", {
         app: {
           downloading: true,
           installState: aApp.installState,
           progress: 0
         },
-        id: aApp.id
+        manifestURL: aApp.manifestURL
       });
       let cacheUpdate = updateSvc.scheduleAppUpdate(
         appcacheURI, docURI, aApp.localId, false, aProfileDir);
 
       // We save the download details for potential further usage like
       // cancelling it.
       let download = {
         cacheUpdate: cacheUpdate,
@@ -1583,17 +1584,16 @@ this.DOMApplicationRegistry = {
       this.notifyAppsRegistryReady();
     }
   },
 
   checkForUpdate: function(aData, aMm) {
     debug("checkForUpdate for " + aData.manifestURL);
 
     function sendError(aError) {
-      debug("checkForUpdate error " + aError);
       aData.error = aError;
       aMm.sendAsyncMessage("Webapps:CheckForUpdate:Return:KO", aData);
     }
 
     let id = this._appIdForManifestURL(aData.manifestURL);
     let app = this.webapps[id];
 
     // We cannot update an app that does not exists.
@@ -1613,67 +1613,71 @@ this.DOMApplicationRegistry = {
       sendError("APP_IS_DOWNLOADING");
       return;
     }
 
     // If the app is packaged and its manifestURL has an app:// scheme,
     // then we can't have an update.
     if (app.origin.startsWith("app://") &&
         app.manifestURL.startsWith("app://")) {
-      sendError("NOT_UPDATABLE");
+      aData.error = "NOT_UPDATABLE";
+      aMm.sendAsyncMessage("Webapps:CheckForUpdate:Return:KO", aData);
       return;
     }
 
     // For non-removable hosted apps that lives in the core apps dir we
     // only check the appcache because we can't modify the manifest even
     // if it has changed.
     let onlyCheckAppCache = false;
 
 #ifdef MOZ_WIDGET_GONK
     let appDir = FileUtils.getDir("coreAppsDir", ["webapps"], false);
     onlyCheckAppCache = (app.basePath == appDir.path);
 #endif
 
     if (onlyCheckAppCache) {
       // Bail out for packaged apps.
       if (app.origin.startsWith("app://")) {
-        sendError("NOT_UPDATABLE");
+        aData.error = "NOT_UPDATABLE";
+        aMm.sendAsyncMessage("Webapps:CheckForUpdate:Return:KO", aData);
         return;
       }
 
       // We need the manifest to check if we have an appcache.
       this._readManifests([{ id: id }]).then((aResult) => {
         let manifest = aResult[0].manifest;
         if (!manifest.appcache_path) {
-          sendError("NOT_UPDATABLE");
+          aData.error = "NOT_UPDATABLE";
+          aMm.sendAsyncMessage("Webapps:CheckForUpdate:Return:KO", aData);
           return;
         }
 
         debug("Checking only appcache for " + aData.manifestURL);
         // Check if the appcache is updatable, and send "downloadavailable" or
         // "downloadapplied".
         let updateObserver = {
           observe: function(aSubject, aTopic, aObsData) {
             debug("onlyCheckAppCache updateSvc.checkForUpdate return for " +
                   app.manifestURL + " - event is " + aTopic);
             if (aTopic == "offline-cache-update-available") {
               app.downloadAvailable = true;
               this._saveApps().then(() => {
                 this.broadcastMessage("Webapps:UpdateState", {
                   app: app,
-                  id: app.id
+                  manifestURL: app.manifestURL
                 });
                 this.broadcastMessage("Webapps:FireEvent", {
                   eventType: "downloadavailable",
                   manifestURL: app.manifestURL,
                   requestID: aData.requestID
                 });
               });
             } else {
-              sendError("NOT_UPDATABLE");
+              aData.error = "NOT_UPDATABLE";
+              aMm.sendAsyncMessage("Webapps:CheckForUpdate:Return:KO", aData);
             }
           }
         };
         let helper = new ManifestHelper(manifest);
         debug("onlyCheckAppCache - launch updateSvc.checkForUpdate for " +
               helper.fullAppcachePath());
         updateSvc.checkForUpdate(Services.io.newURI(helper.fullAppcachePath(), null, null),
                                  app.localId, false, updateObserver);
@@ -1723,17 +1727,17 @@ this.DOMApplicationRegistry = {
             } else {
               this._saveApps().then(() => {
                 // Like if we got a 304, just send a 'downloadapplied'
                 // or downloadavailable event.
                 let eventType = app.downloadAvailable ? "downloadavailable"
                                                       : "downloadapplied";
                 aMm.sendAsyncMessage("Webapps:UpdateState", {
                   app: app,
-                  id: app.id
+                  manifestURL: app.manifestURL
                 });
                 aMm.sendAsyncMessage("Webapps:FireEvent", {
                   eventType: eventType,
                   manifestURL: app.manifestURL,
                   requestID: aData.requestID
                 });
               });
             }
@@ -1750,17 +1754,17 @@ this.DOMApplicationRegistry = {
           app.lastCheckedUpdate = Date.now();
           this._saveApps().then(() => {
             // If the app is a packaged app, we just send a 'downloadapplied'
             // or downloadavailable event.
             let eventType = app.downloadAvailable ? "downloadavailable"
                                                   : "downloadapplied";
             aMm.sendAsyncMessage("Webapps:UpdateState", {
               app: app,
-              id: app.id
+              manifestURL: app.manifestURL
             });
             aMm.sendAsyncMessage("Webapps:FireEvent", {
               eventType: eventType,
               manifestURL: app.manifestURL,
               requestID: aData.requestID
             });
           });
         } else {
@@ -1858,17 +1862,17 @@ this.DOMApplicationRegistry = {
     // A package is available: set downloadAvailable to fire the matching
     // event.
     aApp.downloadAvailable = true;
     aApp.downloadSize = manifest.size;
     aApp.updateManifest = aNewManifest;
     this._saveApps().then(() => {
       this.broadcastMessage("Webapps:UpdateState", {
         app: aApp,
-        id: aApp.id
+        manifestURL: aApp.manifestURL
       });
       this.broadcastMessage("Webapps:FireEvent", {
         eventType: "downloadavailable",
         manifestURL: aApp.manifestURL,
         requestID: aData.requestID
       });
     });
   },
@@ -1922,17 +1926,17 @@ this.DOMApplicationRegistry = {
     // Update the registry.
     this.webapps[aId] = aApp;
     this._saveApps().then(() => {
       let reg = DOMApplicationRegistry;
       if (!manifest.appcache_path) {
         reg.broadcastMessage("Webapps:UpdateState", {
           app: aApp,
           manifest: aApp.manifest,
-          id: aApp.id
+          manifestURL: aApp.manifestURL
         });
         reg.broadcastMessage("Webapps:FireEvent", {
           eventType: "downloadapplied",
           manifestURL: aApp.manifestURL,
           requestID: aData.requestID
         });
       } else {
         // Check if the appcache is updatable, and send "downloadavailable" or
@@ -1944,17 +1948,17 @@ this.DOMApplicationRegistry = {
             let eventType =
               aTopic == "offline-cache-update-available" ? "downloadavailable"
                                                          : "downloadapplied";
             aApp.downloadAvailable = (eventType == "downloadavailable");
             reg._saveApps().then(() => {
               reg.broadcastMessage("Webapps:UpdateState", {
                 app: aApp,
                 manifest: aApp.manifest,
-                id: aApp.id
+                manifestURL: aApp.manifestURL
               });
               reg.broadcastMessage("Webapps:FireEvent", {
                 eventType: eventType,
                 manifestURL: aApp.manifestURL,
                 requestID: aData.requestID
               });
             });
           }
@@ -2209,18 +2213,18 @@ this.DOMApplicationRegistry = {
   },
 
   // This function is called after we called the onsuccess callback on the
   // content side. This let the webpage the opportunity to set event handlers
   // on the app before we start firing progress events.
   queuedDownload: {},
   queuedPackageDownload: {},
 
-  onInstallSuccessAck: function onInstallSuccessAck(aManifestURL,
-                                                    aDontNeedNetwork) {
+onInstallSuccessAck: function onInstallSuccessAck(aManifestURL,
+                                                  aDontNeedNetwork) {
     // If we are offline, register to run when we'll be online.
     if ((Services.io.offline) && !aDontNeedNetwork) {
       let onlineWrapper = {
         observe: function(aSubject, aTopic, aData) {
           Services.obs.removeObserver(onlineWrapper,
                                       "network:offline-status-changed");
           DOMApplicationRegistry.onInstallSuccessAck(aManifestURL);
         }
@@ -2340,16 +2344,17 @@ this.DOMApplicationRegistry = {
       localId = this._nextLocalId();
     }
 
     let app = this._setupApp(aData, id);
 
     let jsonManifest = aData.isPackage ? app.updateManifest : app.manifest;
     this._writeManifestFile(id, aData.isPackage, jsonManifest);
 
+    debug("app.origin: " + app.origin);
     let manifest = new ManifestHelper(jsonManifest, app.origin);
 
     let appObject = this._cloneApp(aData, app, manifest, id, localId);
 
     this.webapps[id] = appObject;
 
     // For package apps, the permissions are not in the mini-manifest, so
     // don't update the permissions yet.
@@ -2383,18 +2388,16 @@ this.DOMApplicationRegistry = {
         profileDir: aProfileDir
       }
     }
 
     // We notify about the successful installation via mgmt.oninstall and the
     // corresponging DOMRequest.onsuccess event as soon as the app is properly
     // saved in the registry.
     this._saveApps().then(() => {
-      aData.isPackage ? appObject.updateManifest = jsonManifest :
-                        appObject.manifest = jsonManifest;
       this.broadcastMessage("Webapps:AddApp", { id: id, app: appObject });
       if (aData.isPackage && aData.autoInstall) {
         // Skip directly to onInstallSuccessAck, since there isn't
         // a WebappsRegistry to receive Webapps:Install:Return:OK and respond
         // Webapps:Install:Return:Ack when an app is being auto-installed.
         this.onInstallSuccessAck(app.manifestURL);
       } else {
         // Broadcast Webapps:Install:Return:OK so the WebappsRegistry can notify
@@ -2501,17 +2504,17 @@ this.DOMApplicationRegistry = {
       }
 
       this.updateDataStore(this.webapps[aId].localId, aNewApp.origin,
                            aNewApp.manifestURL, aManifest, aNewApp.appStatus);
 
       this.broadcastMessage("Webapps:UpdateState", {
         app: app,
         manifest: aManifest,
-        id: app.id
+        manifestURL: aNewApp.manifestURL
       });
       this.broadcastMessage("Webapps:FireEvent", {
         eventType: ["downloadsuccess", "downloadapplied"],
         manifestURL: aNewApp.manifestURL
       });
       if (aInstallSuccessCallback) {
         aInstallSuccessCallback(aManifest, zipFile.path);
       }
@@ -2611,21 +2614,24 @@ this.DOMApplicationRegistry = {
 
       debug("About to download " + fullPackagePath);
 
       let requestChannel = this._getRequestChannel(fullPackagePath,
                                                    isLocalFileInstall,
                                                    oldApp,
                                                    aNewApp);
 
-      AppDownloadManager.add(aNewApp.manifestURL, {
-        channel: requestChannel,
-        appId: id,
-        previousState: aIsUpdate ? "installed" : "pending"
-      });
+      AppDownloadManager.add(
+        aNewApp.manifestURL,
+        {
+          channel: requestChannel,
+          appId: id,
+          previousState: aIsUpdate ? "installed" : "pending"
+        }
+      );
 
       // We set the 'downloading' flag to true right before starting the fetch.
       oldApp.downloading = true;
 
       // We determine the app's 'installState' according to its previous
       // state. Cancelled download should remain as 'pending'. Successfully
       // installed apps should morph to 'updating'.
       oldApp.installState = aIsUpdate ? "updating" : "pending";
@@ -2638,17 +2644,17 @@ this.DOMApplicationRegistry = {
 
       let responseStatus = requestChannel.responseStatus;
       let oldPackage = (responseStatus == 304 || hash == oldApp.packageHash);
 
       if (oldPackage) {
         debug("package's etag or hash unchanged; sending 'applied' event");
         // The package's Etag or hash has not changed.
         // We send a "applied" event right away.
-        this._sendAppliedEvent(oldApp);
+        this._sendAppliedEvent(aNewApp, oldApp, id);
         return;
       }
 
       let newManifest = yield this._openAndReadPackage(zipFile, oldApp, aNewApp,
               isLocalFileInstall, aIsUpdate, aManifest, requestChannel, hash);
 
       AppDownloadManager.remove(aNewApp.manifestURL);
 
@@ -2778,17 +2784,17 @@ this.DOMApplicationRegistry = {
     return requestChannel;
   },
 
   _sendDownloadProgressEvent: function(aNewApp, aProgress) {
     this.broadcastMessage("Webapps:UpdateState", {
       app: {
         progress: aProgress
       },
-      id: aNewApp.id
+      manifestURL: aNewApp.manifestURL
     });
     this.broadcastMessage("Webapps:FireEvent", {
       eventType: "progress",
       manifestURL: aNewApp.manifestURL
     });
   },
 
   _getPackage: function(aRequestChannel, aId, aOldApp, aNewApp) {
@@ -2906,49 +2912,49 @@ this.DOMApplicationRegistry = {
    * package is identical to the last one we installed.  Presumably we do
    * something similar after updating the app, and we could refactor both cases
    * to use the same code to send the "applied" event.
    *
    * @param aNewApp {Object} the new app data
    * @param aOldApp {Object} the currently stored app data
    * @param aId {String} the unique id of the app
    */
-  _sendAppliedEvent: function(aApp) {
-    aApp.downloading = false;
-    aApp.downloadAvailable = false;
-    aApp.downloadSize = 0;
-    aApp.installState = "installed";
-    aApp.readyToApplyDownload = false;
-    if (aApp.staged && aApp.staged.manifestHash) {
+  _sendAppliedEvent: function(aNewApp, aOldApp, aId) {
+    aOldApp.downloading = false;
+    aOldApp.downloadAvailable = false;
+    aOldApp.downloadSize = 0;
+    aOldApp.installState = "installed";
+    aOldApp.readyToApplyDownload = false;
+    if (aOldApp.staged && aOldApp.staged.manifestHash) {
       // If we're here then the manifest has changed but the package
       // hasn't. Let's clear this, so we don't keep offering
       // a bogus update to the user
-      aApp.manifestHash = aApp.staged.manifestHash;
-      aApp.etag = aApp.staged.etag || aApp.etag;
-      aApp.staged = {};
+      aOldApp.manifestHash = aOldApp.staged.manifestHash;
+      aOldApp.etag = aOldApp.staged.etag || aOldApp.etag;
+      aOldApp.staged = {};
       // Move the staged update manifest to a non staged one.
-      let dirPath = this._getAppDir(aApp.id).path;
+      let dirPath = this._getAppDir(aId).path;
 
       // We don't really mind much if this fails.
       OS.File.move(OS.Path.join(dirPath, "staged-update.webapp"),
                    OS.Path.join(dirPath, "update.webapp"));
     }
 
     // Save the updated registry, and cleanup the tmp directory.
     this._saveApps().then(() => {
       this.broadcastMessage("Webapps:UpdateState", {
-        app: aApp,
-        id: aApp.id
+        app: aOldApp,
+        manifestURL: aNewApp.manifestURL
       });
       this.broadcastMessage("Webapps:FireEvent", {
-        manifestURL: aApp.manifestURL,
+        manifestURL: aNewApp.manifestURL,
         eventType: ["downloadsuccess", "downloadapplied"]
       });
     });
-    let file = FileUtils.getFile("TmpD", ["webapps", aApp.id], false);
+    let file = FileUtils.getFile("TmpD", ["webapps", aId], false);
     if (file && file.exists()) {
       file.remove(true);
     }
   },
 
   _openAndReadPackage: function(aZipFile, aOldApp, aNewApp, aIsLocalFileInstall,
                                 aIsUpdate, aManifest, aRequestChannel, aHash) {
     return Task.spawn((function*() {
@@ -3317,17 +3323,17 @@ this.DOMApplicationRegistry = {
     if (aOldApp.staged) {
       delete aOldApp.staged;
     }
 
     this._saveApps().then(() => {
       this.broadcastMessage("Webapps:UpdateState", {
         app: aOldApp,
         error: aError,
-        id: aNewApp.id
+        manifestURL: aNewApp.manifestURL
       });
       this.broadcastMessage("Webapps:FireEvent", {
         eventType: "downloaderror",
         manifestURL:  aNewApp.manifestURL
       });
     });
     AppDownloadManager.remove(aNewApp.manifestURL);
   },
@@ -3867,17 +3873,17 @@ let AppcacheObserver = function(aApp) {
 };
 
 AppcacheObserver.prototype = {
   // nsIOfflineCacheUpdateObserver implementation
   _sendProgressEvent: function() {
     let app = this.app;
     DOMApplicationRegistry.broadcastMessage("Webapps:UpdateState", {
       app: app,
-      id: app.id
+      manifestURL: app.manifestURL
     });
     DOMApplicationRegistry.broadcastMessage("Webapps:FireEvent", {
       eventType: "progress",
       manifestURL: app.manifestURL
     });
   },
 
   updateStateChanged: function appObs_Update(aUpdate, aState) {
@@ -3899,30 +3905,30 @@ AppcacheObserver.prototype = {
         return;
       }
 
       app.updateTime = Date.now();
       app.downloading = false;
       app.downloadAvailable = false;
       DOMApplicationRegistry.broadcastMessage("Webapps:UpdateState", {
         app: app,
-        id: app.id
+        manifestURL: app.manifestURL
       });
       DOMApplicationRegistry.broadcastMessage("Webapps:FireEvent", {
         eventType: ["downloadsuccess", "downloadapplied"],
         manifestURL: app.manifestURL
       });
     }
 
     let setError = function appObs_setError(aError) {
       debug("Offlinecache setError to " + aError);
       app.downloading = false;
       DOMApplicationRegistry.broadcastMessage("Webapps:UpdateState", {
         app: app,
-        id: app.id
+        manifestURL: app.manifestURL
       });
       DOMApplicationRegistry.broadcastMessage("Webapps:FireEvent", {
         error: aError,
         eventType: "downloaderror",
         manifestURL: app.manifestURL
       });
       mustSave = true;
     }
--- a/dom/apps/tests/test_packaged_app_common.js
+++ b/dom/apps/tests/test_packaged_app_common.js
@@ -94,17 +94,16 @@ var PackagedTestHelper = (function Packa
       ok(false, "Got unexpected " + evt.target.error.name);
       finish();
     };
 
     navigator.mozApps.mgmt.oninstall = function(evt) {
       var aApp = evt.application;
       aApp.ondownloaderror = function(evt) {
         var error = aApp.downloadError.name;
-        ok(true, "Got downloaderror " + error);
         if (error == aExpectedError) {
           ok(true, "Got expected " + aExpectedError);
           var expected = {
             name: aName,
             manifestURL: aMiniManifestURL,
             installOrigin: gInstallOrigin,
             progress: 0,
             installState: "pending",
--- a/dom/apps/tests/test_packaged_app_update.html
+++ b/dom/apps/tests/test_packaged_app_update.html
@@ -74,25 +74,26 @@ function checkLastAppState(aMiniManifest
 
 function updateApp(aExpectedReady, aPreviousVersion, aNextVersion) {
   var lApp = PackagedTestHelper.gApp;
 
   var ondownloadappliedhandler =
     checkLastAppState.bind(PackagedTestHelper, miniManifestURL, false, false,
                            aNextVersion, PackagedTestHelper.next);
 
-  var ondownloadsuccesshandler =
-    checkLastAppState.bind(undefined, miniManifestURL,
-                           aExpectedReady, false, aPreviousVersion,
-                           function() {
-      navigator.mozApps.mgmt.applyDownload(lApp);
-  });
+    var ondownloadsuccesshandler =
+      checkLastAppState.bind(undefined, miniManifestURL,
+                             aExpectedReady, false, aPreviousVersion,
+                             function() {
+        navigator.mozApps.mgmt.applyDownload(lApp);
+    });
 
-  checkForUpdate(true, ondownloadsuccesshandler, ondownloadappliedhandler, null,
-                 true);
+    checkForUpdate(true, ondownloadsuccesshandler, ondownloadappliedhandler, null,
+                   true);
+
 }
 
 
 var steps = [
   function() {
     // Set up
     PackagedTestHelper.launchableValue =
       SpecialPowers.setAllAppsLaunchable(true);
@@ -169,17 +170,17 @@ var steps = [
   },
   function() {
     ok(true, "== TEST == Update packaged app - Updating a pending app");
     miniManifestURL = PackagedTestHelper.gSJS +
                       "?getManifest=true" +
                       "&appName=arandomname" +
                       "&appToFail1";
     PackagedTestHelper.checkAppDownloadError(miniManifestURL,
-                                            "MANIFEST_MISMATCH", 1, false, true,
+                                            "MANIFEST_MISMATCH", 2, false, true,
                                              "arandomname",
                                              function () {
       checkForUpdate(false, null, null, null, false,
                      function (request) {
         if (request.error.name === "PENDING_APP_NOT_UPDATABLE") {
           ok(true, "Got expected PENDING_APP_NOT_UPDATEABLE");
         } else {
           ok(false, "Got unexpected " + request.error.name);
--- a/dom/apps/tests/test_receipt_operations.html
+++ b/dom/apps/tests/test_receipt_operations.html
@@ -242,9 +242,9 @@ function runTest() {
   finish();
 }
 
 addLoadEvent(go);
 
 </script>
 </pre>
 </body>
-</html>
+</html>
\ No newline at end of file
--- a/dom/base/Console.cpp
+++ b/dom/base/Console.cpp
@@ -127,25 +127,31 @@ ConsoleStructuredCloneCallbacksError(JSC
 }
 
 JSStructuredCloneCallbacks gConsoleCallbacks = {
   ConsoleStructuredCloneCallbacksRead,
   ConsoleStructuredCloneCallbacksWrite,
   ConsoleStructuredCloneCallbacksError
 };
 
-class ConsoleCallData
+class ConsoleCallData MOZ_FINAL : public LinkedListElement<ConsoleCallData>
 {
 public:
   ConsoleCallData()
     : mMethodName(Console::MethodLog)
     , mPrivate(false)
     , mTimeStamp(JS_Now())
     , mMonotonicTimer(0)
   {
+    MOZ_COUNT_CTOR(ConsoleCallData);
+  }
+
+  ~ConsoleCallData()
+  {
+    MOZ_COUNT_DTOR(ConsoleCallData);
   }
 
   void
   Initialize(JSContext* aCx, Console::MethodName aName,
              const nsAString& aString, const Sequence<JS::Value>& aArguments)
   {
     mGlobal = JS::CurrentGlobalOrNull(aCx);
     mMethodName = aName;
@@ -254,49 +260,49 @@ private:
   nsCOMPtr<nsIEventTarget> mSyncLoopTarget;
 };
 
 // This runnable appends a CallData object into the Console queue running on
 // the main-thread.
 class ConsoleCallDataRunnable MOZ_FINAL : public ConsoleRunnable
 {
 public:
-  ConsoleCallDataRunnable(const ConsoleCallData& aCallData)
+  ConsoleCallDataRunnable(ConsoleCallData* aCallData)
     : mCallData(aCallData)
   {
   }
 
 private:
   bool
   PreDispatch(JSContext* aCx) MOZ_OVERRIDE
   {
     ClearException ce(aCx);
-    JSAutoCompartment ac(aCx, mCallData.mGlobal);
+    JSAutoCompartment ac(aCx, mCallData->mGlobal);
 
     JS::Rooted<JSObject*> arguments(aCx,
-      JS_NewArrayObject(aCx, mCallData.mArguments.Length()));
+      JS_NewArrayObject(aCx, mCallData->mArguments.Length()));
     if (!arguments) {
       return false;
     }
 
-    for (uint32_t i = 0; i < mCallData.mArguments.Length(); ++i) {
-      if (!JS_DefineElement(aCx, arguments, i, mCallData.mArguments[i],
+    for (uint32_t i = 0; i < mCallData->mArguments.Length(); ++i) {
+      if (!JS_DefineElement(aCx, arguments, i, mCallData->mArguments[i],
                             nullptr, nullptr, JSPROP_ENUMERATE)) {
         return false;
       }
     }
 
     JS::Rooted<JS::Value> value(aCx, JS::ObjectValue(*arguments));
 
     if (!mArguments.write(aCx, value, &gConsoleCallbacks, &mStrings)) {
       return false;
     }
 
-    mCallData.mArguments.Clear();
-    mCallData.mGlobal = nullptr;
+    mCallData->mArguments.Clear();
+    mCallData->mGlobal = nullptr;
     return true;
   }
 
   void
   RunConsole() MOZ_OVERRIDE
   {
     // Walk up to our containing page
     WorkerPrivate* wp = mWorkerPrivate;
@@ -336,27 +342,27 @@ private:
 
     for (uint32_t i = 0; i < length; ++i) {
       JS::Rooted<JS::Value> value(cx);
 
       if (!JS_GetElement(cx, argumentsObj, i, &value)) {
         return;
       }
 
-      mCallData.mArguments.AppendElement(value);
+      mCallData->mArguments.AppendElement(value);
     }
 
-    MOZ_ASSERT(mCallData.mArguments.Length() == length);
+    MOZ_ASSERT(mCallData->mArguments.Length() == length);
 
-    mCallData.mGlobal = JS::CurrentGlobalOrNull(cx);
-    console->AppendCallData(mCallData);
+    mCallData->mGlobal = JS::CurrentGlobalOrNull(cx);
+    console->AppendCallData(mCallData.forget());
   }
 
 private:
-  ConsoleCallData mCallData;
+  nsAutoPtr<ConsoleCallData> mCallData;
 
   JSAutoStructuredCloneBuffer mArguments;
   nsTArray<nsString> mStrings;
 };
 
 // This runnable calls ProfileMethod() on the console on the main-thread.
 class ConsoleProfileRunnable MOZ_FINAL : public ConsoleRunnable
 {
@@ -475,35 +481,40 @@ private:
 NS_IMPL_CYCLE_COLLECTION_CLASS(Console)
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Console)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mWindow)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mTimer)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mStorage)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
 
-  tmp->mQueuedCalls.Clear();
+  tmp->ClearConsoleData();
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Console)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTimer)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStorage)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(Console)
   NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
 
-  for (uint32_t i = 0; i < tmp->mQueuedCalls.Length(); ++i) {
-    NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mQueuedCalls[i].mGlobal);
+  for (ConsoleCallData* data = tmp->mQueuedCalls.getFirst(); data != nullptr;
+       data = data->getNext()) {
+    if (data->mGlobal) {
+      aCallbacks.Trace(&data->mGlobal, "data->mGlobal", aClosure);
+    }
 
-    for (uint32_t j = 0; j < tmp->mQueuedCalls[i].mArguments.Length(); ++j) {
-      NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mQueuedCalls[i].mArguments[j]);
+    for (uint32_t i = 0; i < data->mArguments.Length(); ++i) {
+      if (JSVAL_IS_TRACEABLE(data->mArguments[i])) {
+        aCallbacks.Trace(&data->mArguments[i], "data->mArguments[i]", aClosure);
+      }
     }
   }
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(Console)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(Console)
 
@@ -563,17 +574,17 @@ Console::Observe(nsISupports* aSubject, 
 
   if (innerID == mInnerID) {
     nsCOMPtr<nsIObserverService> obs =
       do_GetService("@mozilla.org/observer-service;1");
     if (obs) {
       obs->RemoveObserver(this, "inner-window-destroyed");
     }
 
-    mQueuedCalls.Clear();
+    ClearConsoleData();
     mTimerRegistry.Clear();
 
     if (mTimer) {
       mTimer->Cancel();
       mTimer = nullptr;
     }
   }
 
@@ -730,55 +741,59 @@ void
 Console::Method(JSContext* aCx, MethodName aMethodName,
                 const nsAString& aMethodString,
                 const Sequence<JS::Value>& aData)
 {
   // This RAII class removes the last element of the mQueuedCalls if something
   // goes wrong.
   class RAII {
   public:
-    RAII(nsTArray<ConsoleCallData>& aArray)
-      : mArray(aArray)
+    RAII(LinkedList<ConsoleCallData>& aList)
+      : mList(aList)
       , mUnfinished(true)
     {
     }
 
     ~RAII()
     {
       if (mUnfinished) {
-        mArray.RemoveElementAt(mArray.Length() - 1);
+        ConsoleCallData* data = mList.popLast();
+        MOZ_ASSERT(data);
+        delete data;
       }
     }
 
     void
     Finished()
     {
       mUnfinished = false;
     }
 
   private:
-    nsTArray<ConsoleCallData>& mArray;
+    LinkedList<ConsoleCallData>& mList;
     bool mUnfinished;
   };
 
-  ConsoleCallData& callData = *mQueuedCalls.AppendElement();
-  callData.Initialize(aCx, aMethodName, aMethodString, aData);
+  ConsoleCallData* callData = new ConsoleCallData();
+  mQueuedCalls.insertBack(callData);
+
+  callData->Initialize(aCx, aMethodName, aMethodString, aData);
   RAII raii(mQueuedCalls);
 
   if (mWindow) {
     nsCOMPtr<nsIWebNavigation> webNav = do_GetInterface(mWindow);
     if (!webNav) {
       Throw(aCx, NS_ERROR_FAILURE);
       return;
     }
 
     nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(webNav);
     MOZ_ASSERT(loadContext);
 
-    loadContext->GetUsePrivateBrowsing(&callData.mPrivate);
+    loadContext->GetUsePrivateBrowsing(&callData->mPrivate);
   }
 
   uint32_t maxDepth = aMethodName == MethodTrace ?
                        DEFAULT_MAX_STACKTRACE_DEPTH : 1;
   nsCOMPtr<nsIStackFrame> stack = CreateStack(aCx, maxDepth);
 
   if (!stack) {
     Throw(aCx, NS_ERROR_FAILURE);
@@ -792,17 +807,17 @@ Console::Method(JSContext* aCx, MethodNa
     nsresult rv = stack->GetLanguage(&language);
     if (NS_FAILED(rv)) {
       Throw(aCx, rv);
       return;
     }
 
     if (language == nsIProgrammingLanguage::JAVASCRIPT ||
         language == nsIProgrammingLanguage::JAVASCRIPT2) {
-      ConsoleStackEntry& data = *callData.mStack.AppendElement();
+      ConsoleStackEntry& data = *callData->mStack.AppendElement();
 
       nsCString string;
       rv = stack->GetFilename(string);
       if (NS_FAILED(rv)) {
         Throw(aCx, rv);
         return;
       }
 
@@ -845,141 +860,149 @@ Console::Method(JSContext* aCx, MethodNa
 
     ErrorResult rv;
     nsRefPtr<nsPerformance> performance = win->GetPerformance(rv);
     if (rv.Failed()) {
       Throw(aCx, rv.ErrorCode());
       return;
     }
 
-    callData.mMonotonicTimer = performance->Now();
+    callData->mMonotonicTimer = performance->Now();
   }
 
+  // The operation is completed. RAII class has to be disabled.
+  raii.Finished();
+
   if (!NS_IsMainThread()) {
-    // Here we are in a worker thread.
+    // Here we are in a worker thread. The ConsoleCallData has to been removed
+    // from the list and it will be deleted by the ConsoleCallDataRunnable or
+    // by the Main-Thread Console object.
+    mQueuedCalls.popLast();
+
     nsRefPtr<ConsoleCallDataRunnable> runnable =
       new ConsoleCallDataRunnable(callData);
     runnable->Dispatch();
     return;
   }
 
-  // The operation is completed. RAII class has to be disabled.
-  raii.Finished();
-
   if (!mTimer) {
     mTimer = do_CreateInstance("@mozilla.org/timer;1");
     mTimer->InitWithCallback(this, CALL_DELAY,
                              nsITimer::TYPE_REPEATING_SLACK);
   }
 }
 
 void
-Console::AppendCallData(const ConsoleCallData& aCallData)
+Console::AppendCallData(ConsoleCallData* aCallData)
 {
-  mQueuedCalls.AppendElement(aCallData);
+  mQueuedCalls.insertBack(aCallData);
 
   if (!mTimer) {
     mTimer = do_CreateInstance("@mozilla.org/timer;1");
     mTimer->InitWithCallback(this, CALL_DELAY,
                              nsITimer::TYPE_REPEATING_SLACK);
   }
 }
 
 // Timer callback used to process each of the queued calls.
 NS_IMETHODIMP
 Console::Notify(nsITimer *timer)
 {
-  MOZ_ASSERT(!mQueuedCalls.IsEmpty());
+  MOZ_ASSERT(!mQueuedCalls.isEmpty());
 
-  uint32_t i = 0;
-  for (; i < MESSAGES_IN_INTERVAL && i < mQueuedCalls.Length();
-       ++i) {
-    ProcessCallData(mQueuedCalls[i]);
+  for (uint32_t i = 0; i < MESSAGES_IN_INTERVAL; ++i) {
+    ConsoleCallData* data = mQueuedCalls.popFirst();
+    if (!data) {
+      break;
+    }
+
+    ProcessCallData(data);
+    delete data;
   }
 
-  mQueuedCalls.RemoveElementsAt(0, i);
-
-  if (mQueuedCalls.IsEmpty()) {
+  if (mQueuedCalls.isEmpty()) {
     mTimer->Cancel();
     mTimer = nullptr;
   }
 
   return NS_OK;
 }
 
 void
-Console::ProcessCallData(ConsoleCallData& aData)
+Console::ProcessCallData(ConsoleCallData* aData)
 {
+  MOZ_ASSERT(aData);
+
   ConsoleStackEntry frame;
-  if (!aData.mStack.IsEmpty()) {
-    frame = aData.mStack[0];
+  if (!aData->mStack.IsEmpty()) {
+    frame = aData->mStack[0];
   }
 
   AutoSafeJSContext cx;
   ClearException ce(cx);
   RootedDictionary<ConsoleEvent> event(cx);
 
-  JSAutoCompartment ac(cx, aData.mGlobal);
+  JSAutoCompartment ac(cx, aData->mGlobal);
 
   event.mID.Construct();
   event.mInnerID.Construct();
   if (mWindow) {
     event.mID.Value().SetAsUnsignedLong() = mOuterID;
     event.mInnerID.Value().SetAsUnsignedLong() = mInnerID;
   } else {
     // If we are in a JSM, the window doesn't exist.
     event.mID.Value().SetAsString() = NS_LITERAL_STRING("jsm");
     event.mInnerID.Value().SetAsString() = frame.mFilename;
   }
 
-  event.mLevel = aData.mMethodString;
+  event.mLevel = aData->mMethodString;
   event.mFilename = frame.mFilename;
   event.mLineNumber = frame.mLineNumber;
   event.mFunctionName = frame.mFunctionName;
-  event.mTimeStamp = aData.mTimeStamp;
-  event.mPrivate = aData.mPrivate;
+  event.mTimeStamp = aData->mTimeStamp;
+  event.mPrivate = aData->mPrivate;
 
-  switch (aData.mMethodName) {
+  switch (aData->mMethodName) {
     case MethodLog:
     case MethodInfo:
     case MethodWarn:
     case MethodError:
     case MethodException:
     case MethodDebug:
     case MethodAssert:
       event.mArguments.Construct();
-      ProcessArguments(cx, aData.mArguments, event.mArguments.Value());
+      ProcessArguments(cx, aData->mArguments, event.mArguments.Value());
       break;
 
     default:
       event.mArguments.Construct();
-      ArgumentsToValueList(aData.mArguments, event.mArguments.Value());
+      ArgumentsToValueList(aData->mArguments, event.mArguments.Value());
   }
 
-  if (aData.mMethodName == MethodTrace) {
+  if (aData->mMethodName == MethodTrace) {
     event.mStacktrace.Construct();
-    event.mStacktrace.Value().SwapElements(aData.mStack);
+    event.mStacktrace.Value().SwapElements(aData->mStack);
   }
 
-  else if (aData.mMethodName == MethodGroup ||
-           aData.mMethodName == MethodGroupCollapsed ||
-           aData.mMethodName == MethodGroupEnd) {
-    ComposeGroupName(cx, aData.mArguments, event.mGroupName);
+  else if (aData->mMethodName == MethodGroup ||
+           aData->mMethodName == MethodGroupCollapsed ||
+           aData->mMethodName == MethodGroupEnd) {
+    ComposeGroupName(cx, aData->mArguments, event.mGroupName);
   }
 
-  else if (aData.mMethodName == MethodTime && !aData.mArguments.IsEmpty()) {
-    event.mTimer = StartTimer(cx, aData.mArguments[0], aData.mMonotonicTimer);
+  else if (aData->mMethodName == MethodTime && !aData->mArguments.IsEmpty()) {
+    event.mTimer = StartTimer(cx, aData->mArguments[0], aData->mMonotonicTimer);
   }
 
-  else if (aData.mMethodName == MethodTimeEnd && !aData.mArguments.IsEmpty()) {
-    event.mTimer = StopTimer(cx, aData.mArguments[0], aData.mMonotonicTimer);
+  else if (aData->mMethodName == MethodTimeEnd && !aData->mArguments.IsEmpty()) {
+    event.mTimer = StopTimer(cx, aData->mArguments[0], aData->mMonotonicTimer);
   }
 
-  else if (aData.mMethodName == MethodCount) {
-    event.mCounter = IncreaseCounter(cx, frame, aData.mArguments);
+  else if (aData->mMethodName == MethodCount) {
+    event.mCounter = IncreaseCounter(cx, frame, aData->mArguments);
   }
 
   JS::Rooted<JS::Value> eventValue(cx);
   if (!event.ToObject(cx, JS::NullPtr(), &eventValue)) {
     Throw(cx, NS_ERROR_FAILURE);
     return;
   }
 
@@ -1390,10 +1413,18 @@ Console::IncreaseCounter(JSContext* aCx,
   JS::Rooted<JS::Value> value(aCx);
   if (!data.ToObject(aCx, JS::NullPtr(), &value)) {
     return JS::UndefinedValue();
   }
 
   return value;
 }
 
+void
+Console::ClearConsoleData()
+{
+  while (ConsoleCallData* data = mQueuedCalls.popFirst()) {
+    delete data;
+  }
+}
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/base/Console.h
+++ b/dom/base/Console.h
@@ -123,20 +123,20 @@ private:
     MethodCount
   };
 
   void
   Method(JSContext* aCx, MethodName aName, const nsAString& aString,
          const Sequence<JS::Value>& aData);
 
   void
-  AppendCallData(const ConsoleCallData& aData);
+  AppendCallData(ConsoleCallData* aData);
 
   void
-  ProcessCallData(ConsoleCallData& aData);
+  ProcessCallData(ConsoleCallData* aData);
 
   // If the first JS::Value of the array is a string, this method uses it to
   // format a string. The supported sequences are:
   //   %s    - string
   //   %d,%i - integer
   //   %f    - double
   //   %o    - a JS object.
   // The output is an array where any object is a separated item, the rest is
@@ -176,21 +176,24 @@ private:
   ProfileMethod(JSContext* aCx, const nsAString& aAction,
                 const Sequence<JS::Value>& aData,
                 ErrorResult& aRv);
 
   JS::Value
   IncreaseCounter(JSContext* aCx, const ConsoleStackEntry& aFrame,
                    const nsTArray<JS::Heap<JS::Value>>& aArguments);
 
+  void
+  ClearConsoleData();
+
   nsCOMPtr<nsPIDOMWindow> mWindow;
   nsCOMPtr<nsITimer> mTimer;
   nsCOMPtr<nsIConsoleAPIStorage> mStorage;
 
-  nsTArray<ConsoleCallData> mQueuedCalls;
+  LinkedList<ConsoleCallData> mQueuedCalls;
   nsDataHashtable<nsStringHashKey, DOMHighResTimeStamp> mTimerRegistry;
   nsDataHashtable<nsStringHashKey, uint32_t> mCounterRegistry;
 
   uint64_t mOuterID;
   uint64_t mInnerID;
 
   friend class ConsoleCallData;
   friend class ConsoleCallDataRunnable;
--- a/dom/base/test/mochitest.ini
+++ b/dom/base/test/mochitest.ini
@@ -4,23 +4,25 @@ support-files =
   iframe_messageChannel_pingpong.html
   iframe_messageChannel_post.html
   file_empty.html
   iframe_postMessage_solidus.html
 
 [test_Image_constructor.html]
 [test_appname_override.html]
 [test_bug913761.html]
+[test_bug978522.html]
 [test_clearTimeoutIntervalNoArg.html]
 [test_consoleEmptyStack.html]
 [test_constructor-assignment.html]
 [test_constructor.html]
 [test_document.all_unqualified.html]
 [test_domcursor.html]
 [test_domrequest.html]
+[test_domwindowutils.html]
 [test_e4x_for_each.html]
 [test_error.html]
 [test_gsp-qualified.html]
 [test_gsp-quirks.html]
 [test_gsp-standards.html]
 [test_history_document_open.html]
 [test_history_state_null.html]
 [test_innersize_scrollport.html]
@@ -47,9 +49,8 @@ support-files =
 [test_urlSearchParams.html]
 [test_urlutils_stringify.html]
 [test_window_constructor.html]
 [test_window_cross_origin_props.html]
 [test_window_enumeration.html]
 [test_window_extensible.html]
 [test_window_indexing.html]
 [test_writable-replaceable.html]
-[test_domwindowutils.html]
new file mode 100644
--- /dev/null
+++ b/dom/base/test/test_bug978522.html
@@ -0,0 +1,32 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=978522
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 978522 - basic support</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=978522">Mozilla Bug 978522</a>
+<script type="application/javascript">
+
+  console.log('%s', {
+    toString: function() {
+      console.log('%s', {
+        toString: function() {
+          ok(true, "Still alive \\o/");
+          SimpleTest.finish();
+          return "hello world";
+        }
+      });
+    }
+  });
+
+  SimpleTest.waitForExplicitFinish();
+
+</script>
+</body>
+</html>
--- a/dom/camera/GonkCameraParameters.cpp
+++ b/dom/camera/GonkCameraParameters.cpp
@@ -142,25 +142,28 @@ GonkCameraParameters::~GonkCameraParamet
 // need to get handled in here.
 nsresult
 GonkCameraParameters::Initialize()
 {
   nsresult rv;
 
   rv = GetImpl(CAMERA_PARAM_SUPPORTED_MINEXPOSURECOMPENSATION, mExposureCompensationMin);
   if (NS_FAILED(rv)) {
-    return rv;
+    NS_WARNING("Failed to initialize minimum exposure compensation");
+    mExposureCompensationMin = 0;
   }
   rv = GetImpl(CAMERA_PARAM_SUPPORTED_EXPOSURECOMPENSATIONSTEP, mExposureCompensationStep);
   if (NS_FAILED(rv)) {
-    return rv;
+    NS_WARNING("Failed to initialize exposure compensation step size");
+    mExposureCompensationStep = 0;
   }
   rv = GetListAsArray(CAMERA_PARAM_SUPPORTED_ZOOMRATIOS, mZoomRatios);
   if (NS_FAILED(rv)) {
-    return rv;
+    // zoom is not supported
+    mZoomRatios.Clear();
   }
 
   mInitialized = true;
   return NS_OK;
 }
 
 // Handle nsAStrings
 nsresult
@@ -405,56 +408,73 @@ GonkCameraParameters::GetTranslated(uint
 nsresult
 GonkCameraParameters::SetTranslated(uint32_t aKey, const double& aValue)
 {
   int index;
   int value;
 
   switch (aKey) {
     case CAMERA_PARAM_EXPOSURECOMPENSATION:
+      if (mExposureCompensationStep == 0) {
+        DOM_CAMERA_LOGE("Exposure compensation not supported, can't set %f\n", aValue);
+        return NS_ERROR_NOT_AVAILABLE;
+      }
+
       /**
        * Convert from real value to a Gonk index, round
        * to the nearest step; index is 1-based.
        */
       index =
         (aValue - mExposureCompensationMin + mExposureCompensationStep / 2) /
         mExposureCompensationStep + 1;
       DOM_CAMERA_LOGI("Exposure compensation = %f --> index = %d\n", aValue, index);
       return SetImpl(CAMERA_PARAM_EXPOSURECOMPENSATION, index);
 
     case CAMERA_PARAM_ZOOM:
       {
+        if (mZoomRatios.Length() == 0) {
+          DOM_CAMERA_LOGE("Zoom not supported, can't set %fx\n", aValue);
+          return NS_ERROR_NOT_AVAILABLE;
+        }
+
         /**
          * Convert from a real zoom multipler (e.g. 2.5x) to
          * the index of the nearest supported value.
          */
         value = aValue * 100.0;
 
-        // mZoomRatios is sorted, so we can binary search it
-        unsigned int bottom = 0;
-        unsigned int top = mZoomRatios.Length() - 1;
-        unsigned int middle;
+        if (value < mZoomRatios[0]) {
+          index = 0;
+        } else if (value > mZoomRatios.LastElement()) {
+          index = mZoomRatios.Length() - 1;
+        } else {
+          // mZoomRatios is sorted, so we can binary search it
+          int bottom = 0;
+          int top = mZoomRatios.Length() - 1;
+          int middle;
 
-        while (bottom != top) {
-          middle = (top + bottom) / 2;
-          if (value == mZoomRatios[middle]) {
-            // exact match
-            break;
+          while (top >= bottom) {
+            middle = (top + bottom) / 2;
+            if (value == mZoomRatios[middle]) {
+              // exact match
+              break;
+            }
+            if (value > mZoomRatios[middle] && value < mZoomRatios[middle + 1]) {
+              // the specified zoom value lies in this interval
+              break;
+            }
+            if (value > mZoomRatios[middle]) {
+              bottom = middle + 1;
+            } else {
+              top = middle - 1;
+            }
           }
-          if (value > mZoomRatios[middle] && value < mZoomRatios[middle + 1]) {
-            // the specified zoom value lies in this interval
-            break;
-          }
-          if (value > mZoomRatios[middle]) {
-            bottom = middle + 1;
-          } else {
-            top = middle - 1;
-          }
+          index = middle;
         }
-        index = middle;
+        DOM_CAMERA_LOGI("Zoom = %fx --> index = %d\n", aValue, index);
       }
       return SetImpl(CAMERA_PARAM_ZOOM, index);
   }
 
   return SetImpl(aKey, aValue);
 }
 
 nsresult
@@ -611,26 +631,29 @@ ParseItem(const char* aStart, const char
 template<class T> nsresult
 GonkCameraParameters::GetListAsArray(uint32_t aKey, nsTArray<T>& aArray)
 {
   const char* p;
   nsresult rv = GetImpl(aKey, p);
   if (NS_FAILED(rv)) {
     return rv;
   }
+
+  aArray.Clear();
+
+  // If there is no value available, just return the empty array.
   if (!p) {
-    DOM_CAMERA_LOGW("Camera parameter %d not available (value is null)\n", aKey);
-    return NS_ERROR_NOT_AVAILABLE;
+    DOM_CAMERA_LOGI("Camera parameter %d not available (value is null)\n", aKey);
+    return NS_OK;
   }
   if (*p == '\0') {
-    DOM_CAMERA_LOGW("Camera parameter %d not available (value is empty string)\n", aKey);
-    return NS_ERROR_NOT_AVAILABLE;
+    DOM_CAMERA_LOGI("Camera parameter %d not available (value is empty string)\n", aKey);
+    return NS_OK;
   }
 
-  aArray.Clear();
   const char* comma;
 
   while (p) {
     T* v = aArray.AppendElement();
     if (!v) {
       aArray.Clear();
       return NS_ERROR_OUT_OF_MEMORY;
     }
--- a/dom/camera/TestGonkCameraHardware.cpp
+++ b/dom/camera/TestGonkCameraHardware.cpp
@@ -51,16 +51,43 @@ TestGonkCameraHardware::Init()
 
 const nsCString
 TestGonkCameraHardware::TestCase()
 {
   const nsCString test = Preferences::GetCString("camera.control.test.hardware");
   return test;
 }
 
+const nsCString
+TestGonkCameraHardware::GetExtraParameters()
+{
+  /**
+   * The contents of this pref are appended to the flattened string of
+   * parameters stuffed into GonkCameraParameters by the camera library.
+   * It consists of semicolon-delimited key=value pairs, e.g.
+   *
+   *   focus-mode=auto;flash-mode=auto;preview-size=1024x768
+   *
+   * The unflattening process breaks this string up on semicolon boundaries
+   * and sets an entry in a hashtable of strings with the token before
+   * the equals sign as the key, and the token after as the value. Because
+   * the string is parsed in order, key=value pairs occuring later in the
+   * string will replace value pairs appearing earlier, making it easy to
+   * inject fake, testable values into the parameters table.
+   *
+   * One constraint of this approach is that neither the key nor the value
+   * may contain equals signs or semicolons. We don't enforce that here
+   * so that we can also test correct handling of improperly-formatted values.
+   */
+  const nsCString parameters = Preferences::GetCString("camera.control.test.hardware.gonk.parameters");
+  DOM_CAMERA_LOGA("TestGonkCameraHardware : extra-parameters '%s'\n",
+    parameters.get());
+  return parameters;
+}
+
 bool
 TestGonkCameraHardware::IsTestCaseInternal(const char* aTest, const char* aFile, int aLine)
 {
   if (TestCase().EqualsASCII(aTest)) {
     DOM_CAMERA_LOGA("TestGonkCameraHardware : test-case '%s' (%s:%d)\n",
       aTest, aFile, aLine);
     return true;
   }
@@ -169,17 +196,24 @@ TestGonkCameraHardware::PushParameters(c
 
 nsresult
 TestGonkCameraHardware::PullParameters(GonkCameraParameters& aParams)
 {
   if (IsTestCase("pull-parameters-failure")) {
     return static_cast<nsresult>(TestCaseError(UNKNOWN_ERROR));
   }
 
-  return GonkCameraHardware::PullParameters(aParams);
+  String8 s = mCamera->getParameters();
+  nsCString extra = GetExtraParameters();
+  if (!extra.IsEmpty()) {
+    s += ";";
+    s += extra.get();
+  }
+
+  return aParams.Unflatten(s);
 }
 
 int
 TestGonkCameraHardware::StartRecording()
 {
   if (IsTestCase("start-recording-failure")) {
     return TestCaseError(UNKNOWN_ERROR);
   }
--- a/dom/camera/TestGonkCameraHardware.h
+++ b/dom/camera/TestGonkCameraHardware.h
@@ -50,16 +50,17 @@ public:
                          uint32_t aCameraId,
                          const sp<Camera>& aCamera);
   virtual ~TestGonkCameraHardware();
 
   virtual nsresult Init() MOZ_OVERRIDE;
 
 protected:
   const nsCString TestCase();
+  const nsCString GetExtraParameters();
   bool IsTestCaseInternal(const char* aTest, const char* aFile, int aLine);
   int TestCaseError(int aDefaultError);
 
 private:
   TestGonkCameraHardware(const TestGonkCameraHardware&) MOZ_DELETE;
   TestGonkCameraHardware& operator=(const TestGonkCameraHardware&) MOZ_DELETE;
 };
 
--- a/dom/camera/test/camera_common.js
+++ b/dom/camera/test/camera_common.js
@@ -13,23 +13,51 @@ var CameraTest = (function() {
    * TestGonkCameraHardware.cpp.
    *
    * Some API calls are simple: e.g. 'start-recording-failure' will cause
    * the DOM-facing startRecording() call to fail. More complex tests like
    * 'take-picture-failure' will cause the takePicture() API to fail, while
    * 'take-picture-process-failure' will simulate a failure of the
    * asynchronous picture-taking process, even if the initial API call
    * path seems to have succeeded.
+   *
+   * If 'camera.control.test.hardware.gonk.parameters' is set, it will cause
+   * the contents of that string to be appended to the string of parameters
+   * pulled from the Gonk camera library. This allows tests to inject fake
+   * settings/capabilities for features not supported by the emulator. These
+   * parameters are one or more semicolon-delimited key=value pairs, e.g. to
+   * pretend the emulator supports zoom:
+   *
+   *   zoom-ratios=100,150,200,300,400;max-zoom=4
+   *
+   * This means (of course) that neither the key not the value tokens can
+   * contain either equals signs or semicolons. The test shim doesn't enforce
+   * this so that we can test getting junk from the camera library as well.
    */
   const PREF_TEST_ENABLED = "camera.control.test.enabled";
   const PREF_TEST_HARDWARE = "camera.control.test.hardware";
+  const PREF_TEST_EXTRA_PARAMETERS = "camera.control.test.hardware.gonk.parameters";
   var oldTestEnabled;
   var oldTestHw;
   var testMode;
 
+  function testHardwareSetFakeParameters(parameters, callback) {
+    SpecialPowers.pushPrefEnv({'set': [[PREF_TEST_EXTRA_PARAMETERS, parameters]]}, function() {
+      var setParams = SpecialPowers.getCharPref(PREF_TEST_EXTRA_PARAMETERS);
+      ise(setParams, parameters, "Extra test parameters '" + setParams + "'");
+      if (callback) {
+        callback(setParams);
+      }
+    });
+  }
+
+  function testHardwareClearFakeParameters(callback) {
+    SpecialPowers.pushPrefEnv({'clear': [[PREF_TEST_EXTRA_PARAMETERS]]}, callback);
+  }
+
   function testHardwareSet(test, callback) {
     SpecialPowers.pushPrefEnv({'set': [[PREF_TEST_HARDWARE, test]]}, function() {
       var setTest = SpecialPowers.getCharPref(PREF_TEST_HARDWARE);
       ise(setTest, test, "Test subtype set to " + setTest);
       if (callback) {
         callback(setTest);
       }
     });
@@ -53,52 +81,62 @@ var CameraTest = (function() {
       var setMode = SpecialPowers.getCharPref(PREF_TEST_ENABLED);
       ise(setMode, mode, "Test mode set to " + setMode);
       if (setMode === "hardware") {
         try {
           oldTestHw = SpecialPowers.getCharPref(PREF_TEST_HARDWARE);
         } catch(e) { }
         testMode = {
           set: testHardwareSet,
+          setFakeParameters: testHardwareSetFakeParameters,
+          clearFakeParameters: testHardwareClearFakeParameters,
           done: testHardwareDone
         };
         if (callback) {
           callback(testMode);
         }
       }
     });
   }
 
   function testEnd(callback) {
-    function allDone(cb) {
-      function cb2() {
-        SimpleTest.finish();
-        if (cb) {
-          cb();
-        }
+    // A chain of clean-up functions....
+    function allCleanedUp() {
+      SimpleTest.finish();
+      if (callback) {
+        callback();
+      }
+    }
+    function cleanUpTestEnabled() {
+      var next = allCleanedUp;
+      if (oldTestEnabled) {
+        SpecialPowers.pushPrefEnv({'set': [[PREF_TEST_ENABLED, oldTestEnabled]]}, next);
+      } else {
+        SpecialPowers.pushPrefEnv({'clear': [[PREF_TEST_ENABLED]]}, next);
       }
-      if (oldTestEnabled) {
-        SpecialPowers.pushPrefEnv({'set': [[PREF_TEST_ENABLED, oldTestEnabled]]}, cb2);
+    }
+    function cleanUpTest() {
+      var next = cleanUpTestEnabled;
+      if (testMode) {
+        testMode.done(next);
+        testMode = null;
       } else {
-        SpecialPowers.pushPrefEnv({'clear': [[PREF_TEST_ENABLED]]}, cb2);
+        next();
+      }
+    }
+    function cleanUpExtraParameters() {
+      var next = cleanUpTest;
+      if (testMode) {
+        testMode.clearFakeParameters(next);
+      } else {
+        next();
       }
     }
 
-    if (testMode) {
-      testMode.done(function() {
-        allDone(callback);
-      });
-      testMode = null;
-    } else {
-      allDone(function() {
-        if (callback) {
-          callback();
-        }
-      });
-    }
+    cleanUpExtraParameters();
   }
 
   ise(SpecialPowers.sanityCheck(), "foo", "SpecialPowers passed sanity check");
   return {
     begin: testBegin,
     end: testEnd
   };
 
--- a/dom/camera/test/mochitest.ini
+++ b/dom/camera/test/mochitest.ini
@@ -2,8 +2,9 @@
 support-files = camera_common.js
 
 [test_camera.html]
 [test_camera_2.html]
 [test_camera_3.html]
 [test_camera_hardware_init_failure.html]
 [test_camera_hardware_failures.html]
 [test_bug975472.html]
+[test_camera_fake_parameters.html]
new file mode 100644
--- /dev/null
+++ b/dom/camera/test/test_camera_fake_parameters.html
@@ -0,0 +1,135 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test for CameraParameters we need to fake</title>
+  <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="camera_common.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+  <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=976802">Mozilla Bug 976802</a>
+  <video id="viewfinder" width="200" height="200" autoplay></video>
+  <img src="#" alt="This image is going to load" id="testimage"/>
+
+<script class="testbody" type="text/javascript;version=1.7">
+
+var whichCamera = navigator.mozCameras.getListOfCameras()[0];
+var initialConfig = {
+  mode: 'picture',
+  recorderProfile: 'cif',
+  previewSize: {
+    width: 352,
+    height: 288
+  }
+};
+
+var cameraObj = null;
+
+// Shorthand functions
+function end() {
+  CameraTest.end();
+}
+function next() {
+  CameraTest.next();
+}
+function run() {
+  CameraTest.run();
+}
+
+function onError(e) {
+  ok(false, "Error" + JSON.stringify(e));
+}
+
+// The array of tests
+var tests = [
+  {
+    key: "fake-zoom",
+    prep: function setupFakeZoom(test) {
+      test.setFakeParameters("zoom-ratios=100,150,200,300,400;max-zoom=4", function() {
+        run();
+      });
+    },
+    test: function testFakeZoom(cam, cap) {
+      ok(cap.zoomRatios.length == 5, "zoom ratios length = " + cap.zoomRatios.length);
+
+      // test individual zoom ratios
+      cap.zoomRatios.forEach(function(zoom, index) {
+        cam.zoom = zoom;
+        ok(cam.zoom === zoom,
+          "zoom[" + index + "] = " + zoom + "x, cam.zoom = " + cam.zoom + "x");
+      });
+
+      // test below-lower-bound zoom ratio
+      var zoom = cap.zoomRatios[0] - 0.1;
+      cam.zoom = zoom;
+      ok(cam.zoom === cap.zoomRatios[0],
+        zoom + "x zoom clamps to minimum: " +
+        cap.zoomRatios[0] + "x, cam.zoom = " + cam.zoom + "x");
+
+      // test above-upper-bound zoom ratio
+      zoom = cap.zoomRatios.slice(-1)[0] + 1.0;
+      cam.zoom = zoom;
+      ok(cam.zoom === cap.zoomRatios.slice(-1)[0],
+        zoom + "x zoom clamps to maximum: " + cap.zoomRatios.slice(-1)[0] +
+        "x, cam.zoom = " + cam.zoom + "x");
+
+      // test snapping to supported zoom ratio
+      if (cap.zoomRatios.length > 1) {
+        zoom = (cap.zoomRatios[0] + cap.zoomRatios[1]) / 2;
+        cam.zoom = zoom;
+        ok(cam.zoom === cap.zoomRatios[0],
+          zoom + "x zoom rounded down to: " + cap.zoomRatios[0] +
+          "x, cam.zoom = " + cam.zoom + "x");
+      }
+
+      next();
+    }
+  },
+];
+
+var testGenerator = function() {
+  for (var i = 0; i < tests.length; ++i ) {
+    yield tests[i];
+  }
+}();
+
+window.addEventListener('beforeunload', function() {
+  document.getElementById('viewfinder').mozSrcObject = null;
+  cameraObj.release();
+  cameraObj = null;
+});
+
+CameraTest.begin("hardware", function(test) {
+  function onError(error) {
+    ok(false, "getCamera() failed with: " + error);
+    end();
+  }
+
+  CameraTest.next = function() {
+    try {
+      var t = testGenerator.next();
+      info("test: " + t.key);
+      function onSuccess(camera, config) {
+        cameraObj = camera;
+        t.test(camera, camera.capabilities);
+      }
+      CameraTest.run = function() {
+        navigator.mozCameras.getCamera(whichCamera, initialConfig, onSuccess, onError);
+      };
+      t.prep(test);
+    } catch(e) {
+      if (e instanceof StopIteration) {
+        end();
+      } else {
+        throw e;
+      }
+    }
+  };
+  next();
+});
+
+</script>
+</body>
+
+</html>
--- a/dom/devicestorage/nsDeviceStorage.cpp
+++ b/dom/devicestorage/nsDeviceStorage.cpp
@@ -13,16 +13,17 @@
 #include "mozilla/dom/DeviceStorageBinding.h"
 #include "mozilla/dom/devicestorage/PDeviceStorageRequestChild.h"
 #include "mozilla/dom/ipc/Blob.h"
 #include "mozilla/dom/PBrowserChild.h"
 #include "mozilla/dom/PContentPermissionRequestChild.h"
 #include "mozilla/dom/PermissionMessageUtils.h"
 #include "mozilla/LazyIdleThread.h"
 #include "mozilla/Preferences.h"
+#include "mozilla/Scoped.h"
 #include "mozilla/Services.h"
 
 #include "nsAutoPtr.h"
 #include "nsDOMEvent.h"
 #include "nsServiceManagerUtils.h"
 #include "nsIFile.h"
 #include "nsIDirectoryEnumerator.h"
 #include "nsAppDirectoryServiceDefs.h"
@@ -69,16 +70,20 @@
 
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace mozilla::dom::devicestorage;
 using namespace mozilla::ipc;
 
 #include "nsDirectoryServiceDefs.h"
 
+namespace mozilla {
+  MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedPRFileDesc, PRFileDesc, PR_Close);
+}
+
 StaticAutoPtr<DeviceStorageUsedSpaceCache>
   DeviceStorageUsedSpaceCache::sDeviceStorageUsedSpaceCache;
 
 DeviceStorageUsedSpaceCache::DeviceStorageUsedSpaceCache()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   mIOThread = new LazyIdleThread(
@@ -928,24 +933,26 @@ DeviceStorageFile::AppendRelativePath(co
 #else
   mFile->AppendRelativePath(aPath);
 #endif
 }
 
 nsresult
 DeviceStorageFile::CreateFileDescriptor(FileDescriptor& aFileDescriptor)
 {
-  PRFileDesc* fd;
+  ScopedPRFileDesc fd;
   nsresult rv = mFile->OpenNSPRFileDesc(PR_RDWR | PR_CREATE_FILE,
-                                        0660, &fd);
+                                        0660, &fd.rwget());
   NS_ENSURE_SUCCESS(rv, rv);
 
+  // NOTE: The FileDescriptor::PlatformHandleType constructor returns a dup of
+  //       the file descriptor, so we don't need the original fd after this.
+  //       Our scoped file descriptor will automatically close fd.
   aFileDescriptor =
     FileDescriptor::PlatformHandleType(PR_FileDesc2NativeHandle(fd));
-
   return NS_OK;
 }
 
 nsresult
 DeviceStorageFile::Write(nsIInputStream* aInputStream)
 {
   if (!aInputStream || !mFile) {
     return NS_ERROR_FAILURE;
--- a/dom/events/DataTransfer.cpp
+++ b/dom/events/DataTransfer.cpp
@@ -51,16 +51,17 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(DataTransfer)
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(DataTransfer)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(DataTransfer)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DataTransfer)
+  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(mozilla::dom::DataTransfer)
   NS_INTERFACE_MAP_ENTRY(nsIDOMDataTransfer)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMDataTransfer)
 NS_INTERFACE_MAP_END
 
 // the size of the array
 const char DataTransfer::sEffects[8][9] = {
   "none", "copy", "move", "copyMove", "link", "copyLink", "linkMove", "all"
--- a/dom/events/nsIMEStateManager.cpp
+++ b/dom/events/nsIMEStateManager.cpp
@@ -30,42 +30,53 @@
 #include "nsIFormControl.h"
 #include "nsIForm.h"
 #include "mozilla/dom/HTMLFormElement.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/TextEvents.h"
 #include "TextComposition.h"
 #include "mozilla/Preferences.h"
 #include "nsAsyncDOMEvent.h"
+#include "nsIDocShell.h"
+#include "nsIReflowObserver.h"
+#include "nsIScrollObserver.h"
+#include "nsWeakReference.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace mozilla::widget;
 
 // nsTextStateManager notifies widget of any text and selection changes
 //  in the currently focused editor
 // sTextStateObserver points to the currently active nsTextStateManager
 // sTextStateObserver is null if there is no focused editor
 
 class nsTextStateManager MOZ_FINAL : public nsISelectionListener,
-                                     public nsStubMutationObserver
+                                     public nsStubMutationObserver,
+                                     public nsIReflowObserver,
+                                     public nsIScrollObserver,
+                                     public nsSupportsWeakReference
 {
 public:
   nsTextStateManager()
   {
   }
 
   NS_DECL_ISUPPORTS
   NS_DECL_NSISELECTIONLISTENER
   NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATACHANGED
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
   NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTEWILLCHANGE
   NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
+  NS_DECL_NSIREFLOWOBSERVER
+
+  // nsIScrollObserver
+  virtual void ScrollPositionChanged() MOZ_OVERRIDE;
 
   void     Init(nsIWidget* aWidget,
                 nsPresContext* aPresContext,
                 nsIContent* aContent);
   void     Destroy(void);
   bool     IsManaging(nsPresContext* aPresContext, nsIContent* aContent);
   bool     IsEditorHandlingEventForComposition() const;
   bool     KeepAliveDuringDeactive() const
@@ -77,16 +88,17 @@ public:
   nsCOMPtr<nsISelection>         mSel;
   nsCOMPtr<nsIContent>           mRootContent;
   nsCOMPtr<nsINode>              mEditableNode;
 
 private:
   void NotifyContentAdded(nsINode* aContainer, int32_t aStart, int32_t aEnd);
   void ObserveEditableNode();
 
+  nsCOMPtr<nsIDocShell>          mDocShell;
   nsIMEUpdatePreference mUpdatePreference;
   uint32_t mPreAttrChangeLength;
 };
 
 /******************************************************************/
 /* nsIMEStateManager                                              */
 /******************************************************************/
 
@@ -747,16 +759,18 @@ nsTextStateManager::Init(nsIWidget* aWid
 
   // NOTIFY_IME_OF_FOCUS might cause recreating nsTextStateManager
   // instance via nsIMEStateManager::UpdateIMEState().  So, this
   // instance might already have been destroyed, check it.
   if (!mRootContent) {
     return;
   }
 
+  mDocShell = aPresContext->GetDocShell();
+
   ObserveEditableNode();
 }
 
 void
 nsTextStateManager::ObserveEditableNode()
 {
   MOZ_ASSERT(mSel);
   MOZ_ASSERT(mRootContent);
@@ -769,16 +783,23 @@ nsTextStateManager::ObserveEditableNode(
     nsresult rv = selPrivate->AddSelectionListener(this);
     NS_ENSURE_SUCCESS_VOID(rv);
   }
 
   if (mUpdatePreference.WantTextChange()) {
     // add text change observer
     mRootContent->AddMutationObserver(this);
   }
+
+  if (mUpdatePreference.WantPositionChanged() && mDocShell) {
+    // Add scroll position listener and reflow observer to detect position and
+    // size changes
+    mDocShell->AddWeakScrollObserver(this);
+    mDocShell->AddWeakReflowObserver(this);
+  }
 }
 
 void
 nsTextStateManager::Destroy(void)
 {
   // If CreateTextStateManager failed, mRootContent will be null,
   // and we should not call NotifyIME(IMENotification(NOTIFY_IME_OF_BLUR))
   if (mRootContent) {
@@ -795,18 +816,23 @@ nsTextStateManager::Destroy(void)
     nsCOMPtr<nsISelectionPrivate> selPrivate(do_QueryInterface(mSel));
     if (selPrivate)
       selPrivate->RemoveSelectionListener(this);
   }
   mSel = nullptr;
   if (mUpdatePreference.WantTextChange() && mRootContent) {
     mRootContent->RemoveMutationObserver(this);
   }
+  if (mUpdatePreference.WantPositionChanged() && mDocShell) {
+    mDocShell->RemoveWeakScrollObserver(this);
+    mDocShell->RemoveWeakReflowObserver(this);
+  }
   mRootContent = nullptr;
   mEditableNode = nullptr;
+  mDocShell = nullptr;
   mUpdatePreference.mWantUpdates = nsIMEUpdatePreference::NOTIFY_NOTHING;
 }
 
 bool
 nsTextStateManager::IsManaging(nsPresContext* aPresContext,
                                nsIContent* aContent)
 {
   if (!mSel || !mRootContent || !mEditableNode) {
@@ -828,19 +854,22 @@ nsTextStateManager::IsEditorHandlingEven
   nsRefPtr<TextComposition> composition =
     nsIMEStateManager::GetTextCompositionFor(mWidget);
   if (!composition) {
     return false;
   }
   return composition->IsEditorHandlingEvent();
 }
 
-NS_IMPL_ISUPPORTS2(nsTextStateManager,
+NS_IMPL_ISUPPORTS5(nsTextStateManager,
                    nsIMutationObserver,
-                   nsISelectionListener)
+                   nsISelectionListener,
+                   nsIReflowObserver,
+                   nsIScrollObserver,
+                   nsISupportsWeakReference)
 
 // Helper class, used for selection change notification
 class SelectionChangeEvent : public nsRunnable {
 public:
   SelectionChangeEvent(nsTextStateManager *aDispatcher,
                        bool aCausedByComposition)
     : mDispatcher(aDispatcher)
     , mCausedByComposition(aCausedByComposition)
@@ -912,16 +941,64 @@ public:
   }
 
 private:
   nsRefPtr<nsTextStateManager> mDispatcher;
   uint32_t mStart, mOldEnd, mNewEnd;
   bool mCausedByComposition;
 };
 
+class PositionChangeEvent MOZ_FINAL : public nsRunnable
+{
+public:
+  PositionChangeEvent(nsTextStateManager* aDispatcher)
+    : mDispatcher(aDispatcher) {
+    MOZ_ASSERT(mDispatcher);
+  }
+
+  NS_IMETHOD Run() {
+    if (mDispatcher->mWidget) {
+      mDispatcher->mWidget->NotifyIME(
+        IMENotification(NOTIFY_IME_OF_POSITION_CHANGE));
+    }
+    return NS_OK;
+  }
+
+private:
+  nsRefPtr<nsTextStateManager> mDispatcher;
+};
+
+void
+nsTextStateManager::ScrollPositionChanged()
+{
+  if (mWidget) {
+    nsContentUtils::AddScriptRunner(new PositionChangeEvent(this));
+  }
+}
+
+NS_IMETHODIMP
+nsTextStateManager::Reflow(DOMHighResTimeStamp aStart,
+                           DOMHighResTimeStamp aEnd)
+{
+  if (mWidget) {
+    nsContentUtils::AddScriptRunner(new PositionChangeEvent(this));
+  }
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsTextStateManager::ReflowInterruptible(DOMHighResTimeStamp aStart,
+                                        DOMHighResTimeStamp aEnd)
+{
+  if (mWidget) {
+    nsContentUtils::AddScriptRunner(new PositionChangeEvent(this));
+  }
+  return NS_OK;
+}
+
 void
 nsTextStateManager::CharacterDataChanged(nsIDocument* aDocument,
                                          nsIContent* aContent,
                                          CharacterDataChangeInfo* aInfo)
 {
   NS_ASSERTION(aContent->IsNodeOfType(nsINode::eTEXT),
                "character data changed for non-text node");
 
--- a/dom/src/geolocation/nsGeolocation.cpp
+++ b/dom/src/geolocation/nsGeolocation.cpp
@@ -689,16 +689,20 @@ nsresult nsGeolocationService::Init()
 
 #ifdef MOZ_WIDGET_COCOA
   if (Preferences::GetBool("geo.provider.use_corelocation", true) &&
       CoreLocationLocationProvider::IsCoreLocationAvailable()) {
     mProvider = new CoreLocationLocationProvider();
   }
 #endif
 
+  if (Preferences::GetBool("geo.provider.use_mls", false)) {
+    mProvider = do_GetService("@mozilla.org/geolocation/mls-provider;1");
+  }
+
   // Override platform-specific providers with the default (network)
   // provider while testing. Our tests are currently not meant to exercise
   // the provider, and some tests rely on the network provider being used.
   // "geo.provider.testing" is always set for all plain and browser chrome
   // mochitests, and also for xpcshell tests.
   if (!mProvider || Preferences::GetBool("geo.provider.testing", false)) {
     nsCOMPtr<nsIGeolocationProvider> override =
       do_GetService(NS_GEOLOCATION_PROVIDER_CONTRACTID);
--- a/dom/system/NetworkGeolocationProvider.manifest
+++ b/dom/system/NetworkGeolocationProvider.manifest
@@ -1,2 +1,3 @@
 component {77DA64D3-7458-4920-9491-86CC9914F904} NetworkGeolocationProvider.js
 contract @mozilla.org/geolocation/provider;1 {77DA64D3-7458-4920-9491-86CC9914F904}
+contract @mozilla.org/geolocation/mls-provider;1 {77DA64D3-7458-4920-9491-86CC9914F904}
--- a/dom/system/gonk/tests/test_ril_worker_icc.js
+++ b/dom/system/gonk/tests/test_ril_worker_icc.js
@@ -2097,16 +2097,40 @@ add_test(function test_error_message_upd
   };
 
   do_test({contactType: "adn", contact: {contactId: ICCID + "1"}},
           CONTACT_ERR_CANNOT_ACCESS_PHONEBOOK);
 
   run_next_test();
 });
 
+add_test(function test_process_icc_io_error() {
+  let worker = newUint8Worker();
+  let context = worker.ContextPool._contexts[0];
+  let ioHelper = context.ICCIOHelper;
+
+  function do_test(errorCode, expectedErrorMsg) {
+    let called = false;
+    function errorCb(errorMsg) {
+      called = true;
+      do_check_eq(errorMsg, expectedErrorMsg);
+    }
+
+    ioHelper.processICCIOError({rilRequestError: errorCode,
+                                onerror: errorCb});
+    do_check_true(called);
+  }
+
+  for (let i = 0; i < ERROR_REJECTED_BY_REMOTE + 1; i++) {
+    do_test(i, RIL_ERROR_TO_GECKO_ERROR[i]);
+  }
+
+  run_next_test();
+});
+
 add_test(function test_personalization_state() {
   let worker = newUint8Worker();
   let context = worker.ContextPool._contexts[0];
   let ril = context.RIL;
 
   context.ICCRecordHelper.readICCID = function fakeReadICCID() {};
 
   function testPersonalization(isCdma, cardPersoState, geckoCardState) {
--- a/dom/system/moz.build
+++ b/dom/system/moz.build
@@ -33,23 +33,20 @@ EXPORTS.mozilla += [
     'OSFileConstants.h',
 ]
 
 UNIFIED_SOURCES += [
     'nsDeviceSensors.cpp',
     'OSFileConstants.cpp',
 ]
 
-# On Systems that have build in geolocation providers,
-# we really do not need these.
-if CONFIG['OS_TARGET'] != 'Android' or CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
-    EXTRA_COMPONENTS += [
-        'NetworkGeolocationProvider.js',
-        'NetworkGeolocationProvider.manifest',
-    ]
+EXTRA_COMPONENTS += [
+    'NetworkGeolocationProvider.js',
+    'NetworkGeolocationProvider.manifest',
+]
 
 FAIL_ON_WARNINGS = True
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
 FINAL_LIBRARY = 'gklayout'
 # We fire the nsDOMDeviceAcceleration
 LOCAL_INCLUDES += [
--- a/dom/tests/mochitest/localstorage/test_localStorageEnablePref.html
+++ b/dom/tests/mochitest/localstorage/test_localStorageEnablePref.html
@@ -2,27 +2,29 @@
 <head>
 <title>localStorage enable preference test</title>
 
 <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
 <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 
 <script type="text/javascript">
 
+SimpleTest.requestCompleteLog();
+
 function checkException(func, exc)
 {
   var exceptionThrew = false;
   try {
     func();
   }
   catch (ex) {
     exceptionThrew = true;
     is(ex.name, exc, "Expected "+exc+" exception");
     if (ex.name != exc) {
-      ok(true, "The exception which was thrown is: " + ex);
+      info("The exception which was thrown is: " + ex);
     }
   }
   ok(exceptionThrew, "Exception "+exc+" threw");
 }
 
 var storage;
 function test1() {
   is(typeof(window.localStorage), "object", "Storage is present");
--- a/dom/webidl/DataTransfer.webidl
+++ b/dom/webidl/DataTransfer.webidl
@@ -20,17 +20,17 @@ interface DataTransfer {
   readonly attribute DOMStringList types;
   [Throws]
   DOMString getData(DOMString format);
   [Throws]
   void setData(DOMString format, DOMString data);
   [Throws]
   void clearData(optional DOMString format);
   [Throws]
-  readonly attribute FileList files;
+  readonly attribute FileList? files;
 };
 
 // Mozilla specific stuff
 partial interface DataTransfer {
   /*
    * Set the drag source. Usually you would not change this, but it will
    * affect which node the drag and dragend events are fired at. The
    * default target is the node that was dragged.
--- a/extensions/spellcheck/locales/en-US/hunspell/dictionary-sources/upstream-hunspell.diff
+++ b/extensions/spellcheck/locales/en-US/hunspell/dictionary-sources/upstream-hunspell.diff
@@ -9539,86 +9539,89 @@ 43328c49160
 ---
 > size/AMGBDRS
 43724,43726c49556
 < smoulder's
 < smouldered
 < smoulders
 ---
 > smoulder/GSMD
-44062c49892
+43766a49597,49598
+> snarkily
+> snarky/TR
+44062c49894
 < sonofabitch
 ---
 > sonofabitch/!
-44346a50177
+44346a50179
 > spelled
-44348a50180
+44348a50182
 > spelt
-44371a50204
+44371a50206
 > spick/S!
-44383c50216
+44383c50218
 < spik/S
 ---
 > spik/S!
-46106a51940
+46106a51942
 > syllabi
-46160c51994
+46160c51996
 < synch/GMD
 ---
 > synch/GMDS
-46167d52000
+46167d52002
 < synchs
-46203,46204c52036,52037
+46203,46204c52038,52039
 < sysadmin/S
 < sysop/S
 ---
 > sysadmin/MS
 > sysop/MS
-46752a52586
+46752a52588
 > terabit/MS
-46753a52588,52589
+46753a52590,52591
 > terahertz/M
 > terapixel/MS
-46817a52654
+46817a52656
 > testcase/MS
-46831a52669
+46831a52671
 > testsuite/MS
-46925a52764
+46925a52766
 > theremin/MS
-47455c53294
+47455c53296
 < toolbar
 ---
 > toolbar/MS
-47755a53595
+47755a53597
 > transfect/DSMG
-47774a53615,53616
+47774a53617,53618
 > transgenderism
 > transgene/MS
-47951c53793
+47951c53795
 < triage/M
 ---
 > triage/MG
-48869a54712
+48869a54714
 > unlikeable
-49211c55054
+49211c55056
 < vagina/M
 ---
 > vagina/MS
-49368,49369c55211
+49368,49369c55213
 < velour's
 < velours's
 ---
 > velour/MS
-49478a55321
+49478a55323
 > vertices
-50148a55992
+50148a55994
 > weaponize/DSG
-50260,50261d56103
+50260,50261d56105
 < werwolf/M
 < werwolves
-50728c56570
+50728c56572
 < women
 ---
 > women/M
-50794c56636
+50794c56638
 < wop/S!
 ---
 > wop/MS!
--- a/extensions/spellcheck/locales/en-US/hunspell/en-US.dic
+++ b/extensions/spellcheck/locales/en-US/hunspell/en-US.dic
@@ -1,9 +1,9 @@
-57458
+57460
 0/nm
 0th/pt
 1/n1
 1st/p
 1th/tc
 2/nm
 2nd/p
 2th/tc
@@ -49933,16 +49933,18 @@ snappiness/M
 snapping/U
 snappish/YP
 snappishness/M
 snappy/TRP
 snapshot/SM
 snare/DSMG
 snarf/SDG
 snark/S
+snarkily
+snarky/TR
 snarl's
 snarl/USDG
 snarling/Y
 snarly/TR
 snatch/ZGMDRS
 snatcher/M
 snazzily
 snazzy/TR
--- a/gfx/gl/GLLibraryEGL.cpp
+++ b/gfx/gl/GLLibraryEGL.cpp
@@ -6,16 +6,17 @@
 
 #include "gfxCrashReporterUtils.h"
 #include "mozilla/Preferences.h"
 #include "nsDirectoryServiceDefs.h"
 #include "nsDirectoryServiceUtils.h"
 #include "nsPrintfCString.h"
 #include "prenv.h"
 #include "GLContext.h"
+#include "gfxPrefs.h"
 
 namespace mozilla {
 namespace gl {
 
 GLLibraryEGL sEGLLibrary;
 
 // should match the order of EGLExtensions, and be null-terminated.
 static const char *sEGLExtensionNames[] = {
@@ -27,23 +28,19 @@ static const char *sEGLExtensionNames[] 
     "EGL_EXT_create_context_robustness",
     "EGL_KHR_image",
     "EGL_KHR_fence_sync",
     nullptr
 };
 
 #if defined(ANDROID)
 
-static bool sUseApitraceInitialized = false;
-static bool sUseApitrace = false;
-
 static PRLibrary* LoadApitraceLibrary()
 {
-    MOZ_ASSERT(sUseApitraceInitialized);
-    if (!sUseApitrace) {
+    if (!gfxPrefs::UseApitrace()) {
         return nullptr;
     }
 
     static PRLibrary* sApitraceLibrary = nullptr;
 
     if (sApitraceLibrary)
         return sApitraceLibrary;
 
@@ -96,23 +93,16 @@ LoadLibraryForEGLOnWindows(const nsAStri
 
 bool
 GLLibraryEGL::EnsureInitialized()
 {
     if (mInitialized) {
         return true;
     }
 
-#if defined(ANDROID)
-    if (!sUseApitraceInitialized) {
-        sUseApitrace = Preferences::GetBool("gfx.apitrace.enabled", false);
-        sUseApitraceInitialized = true;
-    }
-#endif // ANDROID
-
     mozilla::ScopedGfxFeatureReporter reporter("EGL");
 
 #ifdef XP_WIN
 #ifdef MOZ_WEBGL
     if (!mEGLLibrary) {
         // On Windows, the GLESv2, EGL and DXSDK libraries are shipped with libxul and
         // we should look for them there. We have to load the libs in this
         // order, because libEGL.dll depends on libGLESv2.dll which depends on the DXSDK
--- a/gfx/gl/GLTextureImage.cpp
+++ b/gfx/gl/GLTextureImage.cpp
@@ -1,740 +1,740 @@
-/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40; -*- */
-/* 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 "GLTextureImage.h"
-#include "GLContext.h"
-#include "gfxContext.h"
-#include "gfxPlatform.h"
-#include "gfxUtils.h"
-#include "gfx2DGlue.h"
-#include "ScopedGLHelpers.h"
-#include "GLUploadHelpers.h"
-
-#include "TextureImageEGL.h"
-#ifdef XP_MACOSX
-#include "TextureImageCGL.h"
-#endif
-
-namespace mozilla {
-namespace gl {
-
-already_AddRefed<TextureImage>
-CreateTextureImage(GLContext* gl,
-                   const gfx::IntSize& aSize,
-                   TextureImage::ContentType aContentType,
-                   GLenum aWrapMode,
-                   TextureImage::Flags aFlags,
-                   TextureImage::ImageFormat aImageFormat)
-{
-    switch (gl->GetContextType()) {
-#ifdef XP_MACOSX
-        case GLContextType::CGL:
-            return CreateTextureImageCGL(gl, aSize, aContentType, aWrapMode, aFlags, aImageFormat);
-#endif
-        case GLContextType::EGL:
-            return CreateTextureImageEGL(gl, aSize, aContentType, aWrapMode, aFlags, aImageFormat);
-        default:
-            return CreateBasicTextureImage(gl, aSize, aContentType, aWrapMode, aFlags, aImageFormat);
-    }
-}
-
-
-static already_AddRefed<TextureImage>
-TileGenFunc(GLContext* gl,
-            const nsIntSize& aSize,
-            TextureImage::ContentType aContentType,
-            TextureImage::Flags aFlags,
-            TextureImage::ImageFormat aImageFormat)
-{
-    switch (gl->GetContextType()) {
-#ifdef XP_MACOSX
-        case GLContextType::CGL:
-            return TileGenFuncCGL(gl, aSize, aContentType, aFlags, aImageFormat);
-#endif
-        case GLContextType::EGL:
-            return TileGenFuncEGL(gl, aSize, aContentType, aFlags, aImageFormat);
-        default:
-            return nullptr;
-    }
-}
-
-already_AddRefed<TextureImage>
-TextureImage::Create(GLContext* gl,
-                     const nsIntSize& size,
-                     TextureImage::ContentType contentType,
-                     GLenum wrapMode,
-                     TextureImage::Flags flags)
-{
-    return Create(gl, size.ToIntSize(), contentType, wrapMode, flags);
-}
-
-// Moz2D equivalent...
-already_AddRefed<TextureImage>
-TextureImage::Create(GLContext* gl,
-                     const gfx::IntSize& size,
-                     TextureImage::ContentType contentType,
-                     GLenum wrapMode,
-                     TextureImage::Flags flags)
-{
-    return CreateTextureImage(gl, size, contentType, wrapMode, flags);
-}
-
-bool
-TextureImage::UpdateFromDataSource(gfx::DataSourceSurface *aSurface,
-                                   const nsIntRegion* aDestRegion,
-                                   const gfx::IntPoint* aSrcPoint)
-{
-    nsIntRegion destRegion = aDestRegion ? *aDestRegion
-                                         : nsIntRect(0, 0,
-                                                     aSurface->GetSize().width,
-                                                     aSurface->GetSize().height);
-    gfx::IntPoint srcPoint = aSrcPoint ? *aSrcPoint
-                                       : gfx::IntPoint(0, 0);
-    return DirectUpdate(aSurface, destRegion, srcPoint);
-}
-
-gfx::IntRect TextureImage::GetTileRect() {
-    return gfx::IntRect(gfx::IntPoint(0,0), mSize);
-}
-
-gfx::IntRect TextureImage::GetSrcTileRect() {
-    return GetTileRect();
-}
-
-BasicTextureImage::~BasicTextureImage()
-{
-    GLContext *ctx = mGLContext;
-    if (ctx->IsDestroyed() || !ctx->IsOwningThreadCurrent()) {
-        ctx = ctx->GetSharedContext();
-    }
-
-    // If we have a context, then we need to delete the texture;
-    // if we don't have a context (either real or shared),
-    // then they went away when the contex was deleted, because it
-    // was the only one that had access to it.
-    if (ctx && ctx->MakeCurrent()) {
-        ctx->fDeleteTextures(1, &mTexture);
-    }
-}
-
-gfx::DrawTarget*
-BasicTextureImage::BeginUpdate(nsIntRegion& aRegion)
-{
-    NS_ASSERTION(!mUpdateDrawTarget, "BeginUpdate() without EndUpdate()?");
-
-    // determine the region the client will need to repaint
-    if (CanUploadSubTextures(mGLContext)) {
-        GetUpdateRegion(aRegion);
-    } else {
-        aRegion = nsIntRect(nsIntPoint(0, 0), gfx::ThebesIntSize(mSize));
-    }
-
-    mUpdateRegion = aRegion;
-
-    nsIntRect rgnSize = mUpdateRegion.GetBounds();
-    if (!nsIntRect(nsIntPoint(0, 0), gfx::ThebesIntSize(mSize)).Contains(rgnSize)) {
-        NS_ERROR("update outside of image");
-        return nullptr;
-    }
-
-    gfx::SurfaceFormat format =
-        (GetContentType() == gfxContentType::COLOR) ?
-        gfx::SurfaceFormat::B8G8R8X8 : gfx::SurfaceFormat::B8G8R8A8;
-    mUpdateDrawTarget =
-        GetDrawTargetForUpdate(gfx::IntSize(rgnSize.width, rgnSize.height), format);
-
-    return mUpdateDrawTarget;
-}
-
-void
-BasicTextureImage::GetUpdateRegion(nsIntRegion& aForRegion)
-{
-  // if the texture hasn't been initialized yet, or something important
-  // changed, we need to recreate our backing surface and force the
-  // client to paint everything
-  if (mTextureState != Valid)
-      aForRegion = nsIntRect(nsIntPoint(0, 0), gfx::ThebesIntSize(mSize));
-}
-
-void
-BasicTextureImage::EndUpdate()
-{
-    NS_ASSERTION(!!mUpdateDrawTarget, "EndUpdate() without BeginUpdate()?");
-
-    // FIXME: this is the slow boat.  Make me fast (with GLXPixmap?).
-
-    RefPtr<gfx::SourceSurface> updateSnapshot = mUpdateDrawTarget->Snapshot();
-    RefPtr<gfx::DataSourceSurface> updateData = updateSnapshot->GetDataSurface();
-
-    bool relative = FinishedSurfaceUpdate();
-
-    mTextureFormat =
-        UploadSurfaceToTexture(mGLContext,
-                               updateData,
-                               mUpdateRegion,
-                               mTexture,
-                               mTextureState == Created,
-                               mUpdateOffset,
-                               relative);
-    FinishedSurfaceUpload();
-
-    mUpdateDrawTarget = nullptr;
-    mTextureState = Valid;
-}
-
-void
-BasicTextureImage::BindTexture(GLenum aTextureUnit)
-{
-    mGLContext->fActiveTexture(aTextureUnit);
-    mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);
-    mGLContext->fActiveTexture(LOCAL_GL_TEXTURE0);
-}
-
-TemporaryRef<gfx::DrawTarget>
-BasicTextureImage::GetDrawTargetForUpdate(const gfx::IntSize& aSize, gfx::SurfaceFormat aFmt)
-{
-    return gfx::Factory::CreateDrawTarget(gfx::BackendType::CAIRO, aSize, aFmt);
-}
-
-bool
-BasicTextureImage::FinishedSurfaceUpdate()
-{
-    return false;
-}
-
-void
-BasicTextureImage::FinishedSurfaceUpload()
-{
-}
-
-bool
-BasicTextureImage::DirectUpdate(gfx::DataSourceSurface* aSurf, const nsIntRegion& aRegion, const gfx::IntPoint& aFrom /* = gfx::IntPoint(0, 0) */)
-{
-    nsIntRect bounds = aRegion.GetBounds();
-    nsIntRegion region;
-    if (mTextureState != Valid) {
-        bounds = nsIntRect(0, 0, mSize.width, mSize.height);
-        region = nsIntRegion(bounds);
-    } else {
-        region = aRegion;
-    }
-
-    mTextureFormat =
-        UploadSurfaceToTexture(mGLContext,
-                               aSurf,
-                               region,
-                               mTexture,
-                               mTextureState == Created,
-                               bounds.TopLeft() + nsIntPoint(aFrom.x, aFrom.y),
-                               false);
-    mTextureState = Valid;
-    return true;
-}
-
-void
-BasicTextureImage::Resize(const gfx::IntSize& aSize)
-{
-    NS_ASSERTION(!mUpdateDrawTarget, "Resize() while in update?");
-
-    mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);
-
-    mGLContext->fTexImage2D(LOCAL_GL_TEXTURE_2D,
-                            0,
-                            LOCAL_GL_RGBA,
-                            aSize.width,
-                            aSize.height,
-                            0,
-                            LOCAL_GL_RGBA,
-                            LOCAL_GL_UNSIGNED_BYTE,
-                            nullptr);
-
-    mTextureState = Allocated;
-    mSize = aSize;
-}
-
-gfx::IntSize TextureImage::GetSize() const {
-  return mSize;
-}
-
-TextureImage::TextureImage(const gfx::IntSize& aSize,
-             GLenum aWrapMode, ContentType aContentType,
-             Flags aFlags)
-    : mSize(aSize)
-    , mWrapMode(aWrapMode)
-    , mContentType(aContentType)
-    , mFilter(GraphicsFilter::FILTER_GOOD)
-    , mFlags(aFlags)
-{}
-
-BasicTextureImage::BasicTextureImage(GLuint aTexture,
-                                     const nsIntSize& aSize,
-                                     GLenum aWrapMode,
-                                     ContentType aContentType,
-                                     GLContext* aContext,
-                                     TextureImage::Flags aFlags /* = TextureImage::NoFlags */,
-                                     TextureImage::ImageFormat aImageFormat /* = gfxImageFormat::Unknown */)
-    : TextureImage(aSize, aWrapMode, aContentType, aFlags, aImageFormat)
-    , mTexture(aTexture)
-    , mTextureState(Created)
-    , mGLContext(aContext)
-    , mUpdateOffset(0, 0)
-{
-}
-
-BasicTextureImage::BasicTextureImage(GLuint aTexture,
-                  const gfx::IntSize& aSize,
-                  GLenum aWrapMode,
-                  ContentType aContentType,
-                  GLContext* aContext,
-                  TextureImage::Flags aFlags,
-                  TextureImage::ImageFormat aImageFormat)
-  : TextureImage(ThebesIntSize(aSize), aWrapMode, aContentType, aFlags, aImageFormat)
-  , mTexture(aTexture)
-  , mTextureState(Created)
-  , mGLContext(aContext)
-  , mUpdateOffset(0, 0)
-{}
-
-static bool
-WantsSmallTiles(GLContext* gl)
-{
-    // We must use small tiles for good performance if we can't use
-    // glTexSubImage2D() for some reason.
-    if (!CanUploadSubTextures(gl))
-        return true;
-
-    // We can't use small tiles on the SGX 540, because of races in texture upload.
-    if (gl->WorkAroundDriverBugs() &&
-        gl->Renderer() == GLRenderer::SGX540)
-        return false;
-
-    // Don't use small tiles otherwise. (If we implement incremental texture upload,
-    // then we will want to revisit this.)
-    return false;
-}
-
-TiledTextureImage::TiledTextureImage(GLContext* aGL,
-                                     gfx::IntSize aSize,
-                                     TextureImage::ContentType aContentType,
-                                     TextureImage::Flags aFlags,
-                                     TextureImage::ImageFormat aImageFormat)
-    : TextureImage(aSize, LOCAL_GL_CLAMP_TO_EDGE, aContentType, aFlags)
-    , mCurrentImage(0)
-    , mIterationCallback(nullptr)
-    , mInUpdate(false)
-    , mRows(0)
-    , mColumns(0)
-    , mGL(aGL)
-    , mTextureState(Created)
-    , mImageFormat(aImageFormat)
-{
-    if (!(aFlags & TextureImage::DisallowBigImage) && WantsSmallTiles(mGL)) {
-      mTileSize = 256;
-    } else {
-      mGL->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_SIZE, (GLint*) &mTileSize);
-    }
-    if (aSize.width != 0 && aSize.height != 0) {
-        Resize(aSize);
-    }
-}
-
-TiledTextureImage::~TiledTextureImage()
-{
-}
-
-bool
-TiledTextureImage::DirectUpdate(gfx::DataSourceSurface* aSurf, const nsIntRegion& aRegion, const gfx::IntPoint& aFrom /* = gfx::IntPoint(0, 0) */)
-{
-    if (mSize.width == 0 || mSize.height == 0) {
-        return true;
-    }
-
-    nsIntRegion region;
-
-    if (mTextureState != Valid) {
-        nsIntRect bounds = nsIntRect(0, 0, mSize.width, mSize.height);
-        region = nsIntRegion(bounds);
-    } else {
-        region = aRegion;
-    }
-
-    bool result = true;
-    int oldCurrentImage = mCurrentImage;
-    BeginTileIteration();
-    do {
-        nsIntRect tileRect = ThebesIntRect(GetSrcTileRect());
-        int xPos = tileRect.x;
-        int yPos = tileRect.y;
-
-        nsIntRegion tileRegion;
-        tileRegion.And(region, tileRect); // intersect with tile
-
-        if (tileRegion.IsEmpty())
-            continue;
-
-        if (CanUploadSubTextures(mGL)) {
-          tileRegion.MoveBy(-xPos, -yPos); // translate into tile local space
-        } else {
-          // If sub-textures are unsupported, expand to tile boundaries
-          tileRect.x = tileRect.y = 0;
-          tileRegion = nsIntRegion(tileRect);
-        }
-
-        result &= mImages[mCurrentImage]->
-          DirectUpdate(aSurf, tileRegion, aFrom + gfx::IntPoint(xPos, yPos));
-
-        if (mCurrentImage == mImages.Length() - 1) {
-            // We know we're done, but we still need to ensure that the callback
-            // gets called (e.g. to update the uploaded region).
-            NextTile();
-            break;
-        }
-        // Override a callback cancelling iteration if the texture wasn't valid.
-        // We need to force the update in that situation, or we may end up
-        // showing invalid/out-of-date texture data.
-    } while (NextTile() || (mTextureState != Valid));
-    mCurrentImage = oldCurrentImage;
-
-    mTextureFormat = mImages[0]->GetTextureFormat();
-    mTextureState = Valid;
-    return result;
-}
-
-void
-TiledTextureImage::GetUpdateRegion(nsIntRegion& aForRegion)
-{
-    if (mTextureState != Valid) {
-        // if the texture hasn't been initialized yet, or something important
-        // changed, we need to recreate our backing surface and force the
-        // client to paint everything
-        aForRegion = nsIntRect(nsIntPoint(0, 0), gfx::ThebesIntSize(mSize));
-        return;
-    }
-
-    nsIntRegion newRegion;
-
-    // We need to query each texture with the region it will be drawing and
-    // set aForRegion to be the combination of all of these regions
-    for (unsigned i = 0; i < mImages.Length(); i++) {
-        int xPos = (i % mColumns) * mTileSize;
-        int yPos = (i / mColumns) * mTileSize;
-        nsIntRect imageRect = nsIntRect(nsIntPoint(xPos,yPos),
-                                        ThebesIntSize(mImages[i]->GetSize()));
-
-        if (aForRegion.Intersects(imageRect)) {
-            // Make a copy of the region
-            nsIntRegion subRegion;
-            subRegion.And(aForRegion, imageRect);
-            // Translate it into tile-space
-            subRegion.MoveBy(-xPos, -yPos);
-            // Query region
-            mImages[i]->GetUpdateRegion(subRegion);
-            // Translate back
-            subRegion.MoveBy(xPos, yPos);
-            // Add to the accumulated region
-            newRegion.Or(newRegion, subRegion);
-        }
-    }
-
-    aForRegion = newRegion;
-}
-
-gfx::DrawTarget*
-TiledTextureImage::BeginUpdate(nsIntRegion& aRegion)
-{
-    NS_ASSERTION(!mInUpdate, "nested update");
-    mInUpdate = true;
-
-    // Note, we don't call GetUpdateRegion here as if the updated region is
-    // fully contained in a single tile, we get to avoid iterating through
-    // the tiles again (and a little copying).
-    if (mTextureState != Valid)
-    {
-        // if the texture hasn't been initialized yet, or something important
-        // changed, we need to recreate our backing surface and force the
-        // client to paint everything
-        aRegion = nsIntRect(nsIntPoint(0, 0), gfx::ThebesIntSize(mSize));
-    }
-
-    nsIntRect bounds = aRegion.GetBounds();
-
-    for (unsigned i = 0; i < mImages.Length(); i++) {
-        int xPos = (i % mColumns) * mTileSize;
-        int yPos = (i / mColumns) * mTileSize;
-        nsIntRegion imageRegion =
-          nsIntRegion(nsIntRect(nsIntPoint(xPos,yPos),
-                                ThebesIntSize(mImages[i]->GetSize())));
-
-        // a single Image can handle this update request
-        if (imageRegion.Contains(aRegion)) {
-            // adjust for tile offset
-            aRegion.MoveBy(-xPos, -yPos);
-            // forward the actual call
-            RefPtr<gfx::DrawTarget> drawTarget = mImages[i]->BeginUpdate(aRegion);
-            // caller expects container space
-            aRegion.MoveBy(xPos, yPos);
-            // we don't have a temp surface
-            mUpdateDrawTarget = nullptr;
-            // remember which image to EndUpdate
-            mCurrentImage = i;
-            return drawTarget.get();
-        }
-    }
-
-    // Get the real updated region, taking into account the capabilities of
-    // each TextureImage tile
-    GetUpdateRegion(aRegion);
-    mUpdateRegion = aRegion;
-    bounds = aRegion.GetBounds();
-
-    // update covers multiple Images - create a temp surface to paint in
-    gfx::SurfaceFormat format =
-        (GetContentType() == gfxContentType::COLOR) ?
-        gfx::SurfaceFormat::B8G8R8X8: gfx::SurfaceFormat::B8G8R8A8;
-    mUpdateDrawTarget = gfx::Factory::CreateDrawTarget(gfx::BackendType::CAIRO,
-                                                       bounds.Size().ToIntSize(),
-                                                       format);
-
-    return mUpdateDrawTarget;;
-}
-
-void
-TiledTextureImage::EndUpdate()
-{
-    NS_ASSERTION(mInUpdate, "EndUpdate not in update");
-    if (!mUpdateDrawTarget) { // update was to a single TextureImage
-        mImages[mCurrentImage]->EndUpdate();
-        mInUpdate = false;
-        mTextureState = Valid;
-        mTextureFormat = mImages[mCurrentImage]->GetTextureFormat();
-        return;
-    }
-
-    RefPtr<gfx::SourceSurface> updateSnapshot = mUpdateDrawTarget->Snapshot();
-    RefPtr<gfx::DataSourceSurface> updateData = updateSnapshot->GetDataSurface();
-    nsRefPtr<gfxASurface> updateSurface = new gfxImageSurface(updateData->GetData(),
-                                                              gfx::ThebesIntSize(updateData->GetSize()),
-                                                              updateData->Stride(),
-                                                              gfx::SurfaceFormatToImageFormat(updateData->GetFormat()));
-
-    // upload tiles from temp surface
-    for (unsigned i = 0; i < mImages.Length(); i++) {
-        int xPos = (i % mColumns) * mTileSize;
-        int yPos = (i / mColumns) * mTileSize;
-        nsIntRect imageRect = nsIntRect(nsIntPoint(xPos,yPos),
-                                        ThebesIntSize(mImages[i]->GetSize()));
-
-        nsIntRegion subregion;
-        subregion.And(mUpdateRegion, imageRect);
-        if (subregion.IsEmpty())
-            continue;
-        subregion.MoveBy(-xPos, -yPos); // Tile-local space
-        // copy tile from temp target
-        gfx::DrawTarget* drawTarget = mImages[i]->BeginUpdate(subregion);
-        nsRefPtr<gfxContext> ctx = new gfxContext(drawTarget);
-        gfxUtils::ClipToRegion(ctx, subregion);
-        ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
-        ctx->SetSource(updateSurface, gfxPoint(-xPos, -yPos));
-        ctx->Paint();
-        mImages[i]->EndUpdate();
-    }
-
-    mUpdateDrawTarget = nullptr;
-    mInUpdate = false;
-    mTextureFormat = mImages[0]->GetTextureFormat();
-    mTextureState = Valid;
-}
-
-void TiledTextureImage::BeginTileIteration()
-{
-    mCurrentImage = 0;
-}
-
-bool TiledTextureImage::NextTile()
-{
-    bool continueIteration = true;
-
-    if (mIterationCallback)
-        continueIteration = mIterationCallback(this, mCurrentImage,
-                                               mIterationCallbackData);
-
-    if (mCurrentImage + 1 < mImages.Length()) {
-        mCurrentImage++;
-        return continueIteration;
-    }
-    return false;
-}
-
-void TiledTextureImage::SetIterationCallback(TileIterationCallback aCallback,
-                                             void* aCallbackData)
-{
-    mIterationCallback = aCallback;
-    mIterationCallbackData = aCallbackData;
-}
-
-gfx::IntRect TiledTextureImage::GetTileRect()
-{
-    if (!GetTileCount()) {
-        return gfx::IntRect();
-    }
-    gfx::IntRect rect = mImages[mCurrentImage]->GetTileRect();
-    unsigned int xPos = (mCurrentImage % mColumns) * mTileSize;
-    unsigned int yPos = (mCurrentImage / mColumns) * mTileSize;
-    rect.MoveBy(xPos, yPos);
-    return rect;
-}
-
-gfx::IntRect TiledTextureImage::GetSrcTileRect()
-{
-    gfx::IntRect rect = GetTileRect();
-    unsigned int srcY = mFlags & NeedsYFlip
-                        ? mSize.height - rect.height - rect.y
-                        : rect.y;
-    return gfx::IntRect(rect.x, srcY, rect.width, rect.height);
-}
-
-void
-TiledTextureImage::BindTexture(GLenum aTextureUnit)
-{
-    if (!GetTileCount()) {
-        return;
-    }
-    mImages[mCurrentImage]->BindTexture(aTextureUnit);
-}
-
-/*
- * Resize, trying to reuse tiles. The reuse strategy is to decide on reuse per
- * column. A tile on a column is reused if it hasn't changed size, otherwise it
- * is discarded/replaced. Extra tiles on a column are pruned after iterating
- * each column, and extra rows are pruned after iteration over the entire image
- * finishes.
- */
-void TiledTextureImage::Resize(const gfx::IntSize& aSize)
-{
-    if (mSize == aSize && mTextureState != Created) {
-        return;
-    }
-
-    // calculate rows and columns, rounding up
-    unsigned int columns = (aSize.width  + mTileSize - 1) / mTileSize;
-    unsigned int rows = (aSize.height + mTileSize - 1) / mTileSize;
-
-    // Iterate over old tile-store and insert/remove tiles as necessary
-    int row;
-    unsigned int i = 0;
-    for (row = 0; row < (int)rows; row++) {
-        // If we've gone beyond how many rows there were before, set mColumns to
-        // zero so that we only create new tiles.
-        if (row >= (int)mRows)
-            mColumns = 0;
-
-        // Similarly, if we're on the last row of old tiles and the height has
-        // changed, discard all tiles in that row.
-        // This will cause the pruning of columns not to work, but we don't need
-        // to worry about that, as no more tiles will be reused past this point
-        // anyway.
-        if ((row == (int)mRows - 1) && (aSize.height != mSize.height))
-            mColumns = 0;
-
-        int col;
-        for (col = 0; col < (int)columns; col++) {
-            nsIntSize size( // use tilesize first, then the remainder
-                    (col+1) * mTileSize > (unsigned int)aSize.width  ? aSize.width  % mTileSize : mTileSize,
-                    (row+1) * mTileSize > (unsigned int)aSize.height ? aSize.height % mTileSize : mTileSize);
-
-            bool replace = false;
-
-            // Check if we can re-use old tiles.
-            if (col < (int)mColumns) {
-                // Reuse an existing tile. If the tile is an end-tile and the
-                // width differs, replace it instead.
-                if (mSize.width != aSize.width) {
-                    if (col == (int)mColumns - 1) {
-                        // Tile at the end of the old column, replace it with
-                        // a new one.
-                        replace = true;
-                    } else if (col == (int)columns - 1) {
-                        // Tile at the end of the new column, create a new one.
-                    } else {
-                        // Before the last column on both the old and new sizes,
-                        // reuse existing tile.
-                        i++;
-                        continue;
-                    }
-                } else {
-                    // Width hasn't changed, reuse existing tile.
-                    i++;
-                    continue;
-                }
-            }
-
-            // Create a new tile.
-            nsRefPtr<TextureImage> teximg =
-                TileGenFunc(mGL, size, mContentType, mFlags, mImageFormat);
-            if (replace)
-                mImages.ReplaceElementAt(i, teximg.forget());
-            else
-                mImages.InsertElementAt(i, teximg.forget());
-            i++;
-        }
-
-        // Prune any unused tiles on the end of the column.
-        if (row < (int)mRows) {
-            for (col = (int)mColumns - col; col > 0; col--) {
-                mImages.RemoveElementAt(i);
-            }
-        }
-    }
-
-    // Prune any unused tiles at the end of the store.
-    unsigned int length = mImages.Length();
-    for (; i < length; i++)
-      mImages.RemoveElementAt(mImages.Length()-1);
-
-    // Reset tile-store properties.
-    mRows = rows;
-    mColumns = columns;
-    mSize = aSize;
-    mTextureState = Allocated;
-    mCurrentImage = 0;
-}
-
-uint32_t TiledTextureImage::GetTileCount()
-{
-    return mImages.Length();
-}
-
-already_AddRefed<TextureImage>
-CreateBasicTextureImage(GLContext* aGL,
-                        const gfx::IntSize& aSize,
-                        TextureImage::ContentType aContentType,
-                        GLenum aWrapMode,
-                        TextureImage::Flags aFlags,
-                        TextureImage::ImageFormat aImageFormat)
-{
-    bool useNearestFilter = aFlags & TextureImage::UseNearestFilter;
-    if (!aGL->MakeCurrent()) {
-      return nullptr;
-    }
-
-    GLuint texture = 0;
-    aGL->fGenTextures(1, &texture);
-
-    ScopedBindTexture bind(aGL, texture);
-
-    GLint texfilter = useNearestFilter ? LOCAL_GL_NEAREST : LOCAL_GL_LINEAR;
-    aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, texfilter);
-    aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, texfilter);
-    aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S, aWrapMode);
-    aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T, aWrapMode);
-
-    nsRefPtr<BasicTextureImage> texImage =
-        new BasicTextureImage(texture, aSize, aWrapMode, aContentType,
-                              aGL, aFlags, aImageFormat);
-    return texImage.forget();
-}
-
-} // namespace
-} // namespace
+/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40; -*- */
+/* 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 "GLTextureImage.h"
+#include "GLContext.h"
+#include "gfxContext.h"
+#include "gfxPlatform.h"
+#include "gfxUtils.h"
+#include "gfx2DGlue.h"
+#include "ScopedGLHelpers.h"
+#include "GLUploadHelpers.h"
+
+#include "TextureImageEGL.h"
+#ifdef XP_MACOSX
+#include "TextureImageCGL.h"
+#endif
+
+namespace mozilla {
+namespace gl {
+
+already_AddRefed<TextureImage>
+CreateTextureImage(GLContext* gl,
+                   const gfx::IntSize& aSize,
+                   TextureImage::ContentType aContentType,
+                   GLenum aWrapMode,
+                   TextureImage::Flags aFlags,
+                   TextureImage::ImageFormat aImageFormat)
+{
+    switch (gl->GetContextType()) {
+#ifdef XP_MACOSX
+        case GLContextType::CGL:
+            return CreateTextureImageCGL(gl, aSize, aContentType, aWrapMode, aFlags, aImageFormat);
+#endif
+        case GLContextType::EGL:
+            return CreateTextureImageEGL(gl, aSize, aContentType, aWrapMode, aFlags, aImageFormat);
+        default:
+            return CreateBasicTextureImage(gl, aSize, aContentType, aWrapMode, aFlags, aImageFormat);
+    }
+}
+
+
+static already_AddRefed<TextureImage>
+TileGenFunc(GLContext* gl,
+            const nsIntSize& aSize,
+            TextureImage::ContentType aContentType,
+            TextureImage::Flags aFlags,
+            TextureImage::ImageFormat aImageFormat)
+{
+    switch (gl->GetContextType()) {
+#ifdef XP_MACOSX
+        case GLContextType::CGL:
+            return TileGenFuncCGL(gl, aSize, aContentType, aFlags, aImageFormat);
+#endif
+        case GLContextType::EGL:
+            return TileGenFuncEGL(gl, aSize, aContentType, aFlags, aImageFormat);
+        default:
+            return nullptr;
+    }
+}
+
+already_AddRefed<TextureImage>
+TextureImage::Create(GLContext* gl,
+                     const nsIntSize& size,
+                     TextureImage::ContentType contentType,
+                     GLenum wrapMode,
+                     TextureImage::Flags flags)
+{
+    return Create(gl, size.ToIntSize(), contentType, wrapMode, flags);
+}
+
+// Moz2D equivalent...
+already_AddRefed<TextureImage>
+TextureImage::Create(GLContext* gl,
+                     const gfx::IntSize& size,
+                     TextureImage::ContentType contentType,
+                     GLenum wrapMode,
+                     TextureImage::Flags flags)
+{
+    return CreateTextureImage(gl, size, contentType, wrapMode, flags);
+}
+
+bool
+TextureImage::UpdateFromDataSource(gfx::DataSourceSurface *aSurface,
+                                   const nsIntRegion* aDestRegion,
+                                   const gfx::IntPoint* aSrcPoint)
+{
+    nsIntRegion destRegion = aDestRegion ? *aDestRegion
+                                         : nsIntRect(0, 0,
+                                                     aSurface->GetSize().width,
+                                                     aSurface->GetSize().height);
+    gfx::IntPoint srcPoint = aSrcPoint ? *aSrcPoint
+                                       : gfx::IntPoint(0, 0);
+    return DirectUpdate(aSurface, destRegion, srcPoint);
+}
+
+gfx::IntRect TextureImage::GetTileRect() {
+    return gfx::IntRect(gfx::IntPoint(0,0), mSize);
+}
+
+gfx::IntRect TextureImage::GetSrcTileRect() {
+    return GetTileRect();
+}
+
+BasicTextureImage::~BasicTextureImage()
+{
+    GLContext *ctx = mGLContext;
+    if (ctx->IsDestroyed() || !ctx->IsOwningThreadCurrent()) {
+        ctx = ctx->GetSharedContext();
+    }
+
+    // If we have a context, then we need to delete the texture;
+    // if we don't have a context (either real or shared),
+    // then they went away when the contex was deleted, because it
+    // was the only one that had access to it.
+    if (ctx && ctx->MakeCurrent()) {
+        ctx->fDeleteTextures(1, &mTexture);
+    }
+}
+
+gfx::DrawTarget*
+BasicTextureImage::BeginUpdate(nsIntRegion& aRegion)
+{
+    NS_ASSERTION(!mUpdateDrawTarget, "BeginUpdate() without EndUpdate()?");
+
+    // determine the region the client will need to repaint
+    if (CanUploadSubTextures(mGLContext)) {
+        GetUpdateRegion(aRegion);
+    } else {
+        aRegion = nsIntRect(nsIntPoint(0, 0), gfx::ThebesIntSize(mSize));
+    }
+
+    mUpdateRegion = aRegion;
+
+    nsIntRect rgnSize = mUpdateRegion.GetBounds();
+    if (!nsIntRect(nsIntPoint(0, 0), gfx::ThebesIntSize(mSize)).Contains(rgnSize)) {
+        NS_ERROR("update outside of image");
+        return nullptr;
+    }
+
+    gfx::SurfaceFormat format =
+        (GetContentType() == gfxContentType::COLOR) ?
+        gfx::SurfaceFormat::B8G8R8X8 : gfx::SurfaceFormat::B8G8R8A8;
+    mUpdateDrawTarget =
+        GetDrawTargetForUpdate(gfx::IntSize(rgnSize.width, rgnSize.height), format);
+
+    return mUpdateDrawTarget;
+}
+
+void
+BasicTextureImage::GetUpdateRegion(nsIntRegion& aForRegion)
+{
+  // if the texture hasn't been initialized yet, or something important
+  // changed, we need to recreate our backing surface and force the
+  // client to paint everything
+  if (mTextureState != Valid)
+      aForRegion = nsIntRect(nsIntPoint(0, 0), gfx::ThebesIntSize(mSize));
+}
+
+void
+BasicTextureImage::EndUpdate()
+{
+    NS_ASSERTION(!!mUpdateDrawTarget, "EndUpdate() without BeginUpdate()?");
+
+    // FIXME: this is the slow boat.  Make me fast (with GLXPixmap?).
+
+    RefPtr<gfx::SourceSurface> updateSnapshot = mUpdateDrawTarget->Snapshot();
+    RefPtr<gfx::DataSourceSurface> updateData = updateSnapshot->GetDataSurface();
+
+    bool relative = FinishedSurfaceUpdate();
+
+    mTextureFormat =
+        UploadSurfaceToTexture(mGLContext,
+                               updateData,
+                               mUpdateRegion,
+                               mTexture,
+                               mTextureState == Created,
+                               mUpdateOffset,
+                               relative);
+    FinishedSurfaceUpload();
+
+    mUpdateDrawTarget = nullptr;
+    mTextureState = Valid;
+}
+
+void
+BasicTextureImage::BindTexture(GLenum aTextureUnit)
+{
+    mGLContext->fActiveTexture(aTextureUnit);
+    mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);
+    mGLContext->fActiveTexture(LOCAL_GL_TEXTURE0);
+}
+
+TemporaryRef<gfx::DrawTarget>
+BasicTextureImage::GetDrawTargetForUpdate(const gfx::IntSize& aSize, gfx::SurfaceFormat aFmt)
+{
+    return gfx::Factory::CreateDrawTarget(gfx::BackendType::CAIRO, aSize, aFmt);
+}
+
+bool
+BasicTextureImage::FinishedSurfaceUpdate()
+{
+    return false;
+}
+
+void
+BasicTextureImage::FinishedSurfaceUpload()
+{
+}
+
+bool
+BasicTextureImage::DirectUpdate(gfx::DataSourceSurface* aSurf, const nsIntRegion& aRegion, const gfx::IntPoint& aFrom /* = gfx::IntPoint(0, 0) */)
+{
+    nsIntRect bounds = aRegion.GetBounds();
+    nsIntRegion region;
+    if (mTextureState != Valid) {
+        bounds = nsIntRect(0, 0, mSize.width, mSize.height);
+        region = nsIntRegion(bounds);
+    } else {
+        region = aRegion;
+    }
+
+    mTextureFormat =
+        UploadSurfaceToTexture(mGLContext,
+                               aSurf,
+                               region,
+                               mTexture,
+                               mTextureState == Created,
+                               bounds.TopLeft() + nsIntPoint(aFrom.x, aFrom.y),
+                               false);
+    mTextureState = Valid;
+    return true;
+}
+
+void
+BasicTextureImage::Resize(const gfx::IntSize& aSize)
+{
+    NS_ASSERTION(!mUpdateDrawTarget, "Resize() while in update?");
+
+    mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);
+
+    mGLContext->fTexImage2D(LOCAL_GL_TEXTURE_2D,
+                            0,
+                            LOCAL_GL_RGBA,
+                            aSize.width,
+                            aSize.height,
+                            0,
+                            LOCAL_GL_RGBA,
+                            LOCAL_GL_UNSIGNED_BYTE,
+                            nullptr);
+
+    mTextureState = Allocated;
+    mSize = aSize;
+}
+
+gfx::IntSize TextureImage::GetSize() const {
+  return mSize;
+}
+
+TextureImage::TextureImage(const gfx::IntSize& aSize,
+             GLenum aWrapMode, ContentType aContentType,
+             Flags aFlags)
+    : mSize(aSize)
+    , mWrapMode(aWrapMode)
+    , mContentType(aContentType)
+    , mFilter(GraphicsFilter::FILTER_GOOD)
+    , mFlags(aFlags)
+{}
+
+BasicTextureImage::BasicTextureImage(GLuint aTexture,
+                                     const nsIntSize& aSize,
+                                     GLenum aWrapMode,
+                                     ContentType aContentType,
+                                     GLContext* aContext,
+                                     TextureImage::Flags aFlags /* = TextureImage::NoFlags */,
+                                     TextureImage::ImageFormat aImageFormat /* = gfxImageFormat::Unknown */)
+    : TextureImage(aSize, aWrapMode, aContentType, aFlags, aImageFormat)
+    , mTexture(aTexture)
+    , mTextureState(Created)
+    , mGLContext(aContext)
+    , mUpdateOffset(0, 0)
+{
+}
+
+BasicTextureImage::BasicTextureImage(GLuint aTexture,
+                  const gfx::IntSize& aSize,
+                  GLenum aWrapMode,
+                  ContentType aContentType,
+                  GLContext* aContext,
+                  TextureImage::Flags aFlags,
+                  TextureImage::ImageFormat aImageFormat)
+  : TextureImage(ThebesIntSize(aSize), aWrapMode, aContentType, aFlags, aImageFormat)
+  , mTexture(aTexture)
+  , mTextureState(Created)
+  , mGLContext(aContext)
+  , mUpdateOffset(0, 0)
+{}
+
+static bool
+WantsSmallTiles(GLContext* gl)
+{
+    // We must use small tiles for good performance if we can't use
+    // glTexSubImage2D() for some reason.
+    if (!CanUploadSubTextures(gl))
+        return true;
+
+    // We can't use small tiles on the SGX 540, because of races in texture upload.
+    if (gl->WorkAroundDriverBugs() &&
+        gl->Renderer() == GLRenderer::SGX540)
+        return false;
+
+    // Don't use small tiles otherwise. (If we implement incremental texture upload,
+    // then we will want to revisit this.)
+    return false;
+}
+
+TiledTextureImage::TiledTextureImage(GLContext* aGL,
+                                     gfx::IntSize aSize,
+                                     TextureImage::ContentType aContentType,
+                                     TextureImage::Flags aFlags,
+                                     TextureImage::ImageFormat aImageFormat)
+    : TextureImage(aSize, LOCAL_GL_CLAMP_TO_EDGE, aContentType, aFlags)
+    , mCurrentImage(0)
+    , mIterationCallback(nullptr)
+    , mInUpdate(false)
+    , mRows(0)
+    , mColumns(0)
+    , mGL(aGL)
+    , mTextureState(Created)
+    , mImageFormat(aImageFormat)
+{
+    if (!(aFlags & TextureImage::DisallowBigImage) && WantsSmallTiles(mGL)) {
+      mTileSize = 256;
+    } else {
+      mGL->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_SIZE, (GLint*) &mTileSize);
+    }
+    if (aSize.width != 0 && aSize.height != 0) {
+        Resize(aSize);
+    }
+}
+
+TiledTextureImage::~TiledTextureImage()
+{
+}
+
+bool
+TiledTextureImage::DirectUpdate(gfx::DataSourceSurface* aSurf, const nsIntRegion& aRegion, const gfx::IntPoint& aFrom /* = gfx::IntPoint(0, 0) */)
+{
+    if (mSize.width == 0 || mSize.height == 0) {
+        return true;
+    }
+
+    nsIntRegion region;
+
+    if (mTextureState != Valid) {
+        nsIntRect bounds = nsIntRect(0, 0, mSize.width, mSize.height);
+        region = nsIntRegion(bounds);
+    } else {
+        region = aRegion;
+    }
+
+    bool result = true;
+    int oldCurrentImage = mCurrentImage;
+    BeginTileIteration();
+    do {
+        nsIntRect tileRect = ThebesIntRect(GetSrcTileRect());
+        int xPos = tileRect.x;
+        int yPos = tileRect.y;
+
+        nsIntRegion tileRegion;
+        tileRegion.And(region, tileRect); // intersect with tile
+
+        if (tileRegion.IsEmpty())
+            continue;
+
+        if (CanUploadSubTextures(mGL)) {
+          tileRegion.MoveBy(-xPos, -yPos); // translate into tile local space
+        } else {
+          // If sub-textures are unsupported, expand to tile boundaries
+          tileRect.x = tileRect.y = 0;
+          tileRegion = nsIntRegion(tileRect);
+        }
+
+        result &= mImages[mCurrentImage]->
+          DirectUpdate(aSurf, tileRegion, aFrom + gfx::IntPoint(xPos, yPos));
+
+        if (mCurrentImage == mImages.Length() - 1) {
+            // We know we're done, but we still need to ensure that the callback
+            // gets called (e.g. to update the uploaded region).
+            NextTile();
+            break;
+        }
+        // Override a callback cancelling iteration if the texture wasn't valid.
+        // We need to force the update in that situation, or we may end up
+        // showing invalid/out-of-date texture data.
+    } while (NextTile() || (mTextureState != Valid));
+    mCurrentImage = oldCurrentImage;
+
+    mTextureFormat = mImages[0]->GetTextureFormat();
+    mTextureState = Valid;
+    return result;
+}
+
+void
+TiledTextureImage::GetUpdateRegion(nsIntRegion& aForRegion)
+{
+    if (mTextureState != Valid) {
+        // if the texture hasn't been initialized yet, or something important
+        // changed, we need to recreate our backing surface and force the
+        // client to paint everything
+        aForRegion = nsIntRect(nsIntPoint(0, 0), gfx::ThebesIntSize(mSize));
+        return;
+    }
+
+    nsIntRegion newRegion;
+
+    // We need to query each texture with the region it will be drawing and
+    // set aForRegion to be the combination of all of these regions
+    for (unsigned i = 0; i < mImages.Length(); i++) {
+        int xPos = (i % mColumns) * mTileSize;
+        int yPos = (i / mColumns) * mTileSize;
+        nsIntRect imageRect = nsIntRect(nsIntPoint(xPos,yPos),
+                                        ThebesIntSize(mImages[i]->GetSize()));
+
+        if (aForRegion.Intersects(imageRect)) {
+            // Make a copy of the region
+            nsIntRegion subRegion;
+            subRegion.And(aForRegion, imageRect);
+            // Translate it into tile-space
+            subRegion.MoveBy(-xPos, -yPos);
+            // Query region
+            mImages[i]->GetUpdateRegion(subRegion);
+            // Translate back
+            subRegion.MoveBy(xPos, yPos);
+            // Add to the accumulated region
+            newRegion.Or(newRegion, subRegion);
+        }
+    }
+
+    aForRegion = newRegion;
+}
+
+gfx::DrawTarget*
+TiledTextureImage::BeginUpdate(nsIntRegion& aRegion)
+{
+    NS_ASSERTION(!mInUpdate, "nested update");
+    mInUpdate = true;
+
+    // Note, we don't call GetUpdateRegion here as if the updated region is
+    // fully contained in a single tile, we get to avoid iterating through
+    // the tiles again (and a little copying).
+    if (mTextureState != Valid)
+    {
+        // if the texture hasn't been initialized yet, or something important
+        // changed, we need to recreate our backing surface and force the
+        // client to paint everything
+        aRegion = nsIntRect(nsIntPoint(0, 0), gfx::ThebesIntSize(mSize));
+    }
+
+    nsIntRect bounds = aRegion.GetBounds();
+
+    for (unsigned i = 0; i < mImages.Length(); i++) {
+        int xPos = (i % mColumns) * mTileSize;
+        int yPos = (i / mColumns) * mTileSize;
+        nsIntRegion imageRegion =
+          nsIntRegion(nsIntRect(nsIntPoint(xPos,yPos),
+                                ThebesIntSize(mImages[i]->GetSize())));
+
+        // a single Image can handle this update request
+        if (imageRegion.Contains(aRegion)) {
+            // adjust for tile offset
+            aRegion.MoveBy(-xPos, -yPos);
+            // forward the actual call
+            RefPtr<gfx::DrawTarget> drawTarget = mImages[i]->BeginUpdate(aRegion);
+            // caller expects container space
+            aRegion.MoveBy(xPos, yPos);
+            // we don't have a temp surface
+            mUpdateDrawTarget = nullptr;
+            // remember which image to EndUpdate
+            mCurrentImage = i;
+            return drawTarget.get();
+        }
+    }
+
+    // Get the real updated region, taking into account the capabilities of
+    // each TextureImage tile
+    GetUpdateRegion(aRegion);
+    mUpdateRegion = aRegion;
+    bounds = aRegion.GetBounds();
+
+    // update covers multiple Images - create a temp surface to paint in
+    gfx::SurfaceFormat format =
+        (GetContentType() == gfxContentType::COLOR) ?
+        gfx::SurfaceFormat::B8G8R8X8: gfx::SurfaceFormat::B8G8R8A8;
+    mUpdateDrawTarget = gfx::Factory::CreateDrawTarget(gfx::BackendType::CAIRO,
+                                                       bounds.Size().ToIntSize(),
+                                                       format);
+
+    return mUpdateDrawTarget;;
+}
+
+void
+TiledTextureImage::EndUpdate()
+{
+    NS_ASSERTION(mInUpdate, "EndUpdate not in update");
+    if (!mUpdateDrawTarget) { // update was to a single TextureImage
+        mImages[mCurrentImage]->EndUpdate();
+        mInUpdate = false;
+        mTextureState = Valid;
+        mTextureFormat = mImages[mCurrentImage]->GetTextureFormat();
+        return;
+    }
+
+    RefPtr<gfx::SourceSurface> updateSnapshot = mUpdateDrawTarget->Snapshot();
+    RefPtr<gfx::DataSourceSurface> updateData = updateSnapshot->GetDataSurface();
+    nsRefPtr<gfxASurface> updateSurface = new gfxImageSurface(updateData->GetData(),
+                                                              gfx::ThebesIntSize(updateData->GetSize()),
+                                                              updateData->Stride(),
+                                                              gfx::SurfaceFormatToImageFormat(updateData->GetFormat()));
+
+    // upload tiles from temp surface
+    for (unsigned i = 0; i < mImages.Length(); i++) {
+        int xPos = (i % mColumns) * mTileSize;
+        int yPos = (i / mColumns) * mTileSize;
+        nsIntRect imageRect = nsIntRect(nsIntPoint(xPos,yPos),
+                                        ThebesIntSize(mImages[i]->GetSize()));
+
+        nsIntRegion subregion;
+        subregion.And(mUpdateRegion, imageRect);
+        if (subregion.IsEmpty())
+            continue;
+        subregion.MoveBy(-xPos, -yPos); // Tile-local space
+        // copy tile from temp target
+        gfx::DrawTarget* drawTarget = mImages[i]->BeginUpdate(subregion);
+        nsRefPtr<gfxContext> ctx = new gfxContext(drawTarget);
+        gfxUtils::ClipToRegion(ctx, subregion);
+        ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
+        ctx->SetSource(updateSurface, gfxPoint(-xPos, -yPos));
+        ctx->Paint();
+        mImages[i]->EndUpdate();
+    }
+
+    mUpdateDrawTarget = nullptr;
+    mInUpdate = false;
+    mTextureFormat = mImages[0]->GetTextureFormat();
+    mTextureState = Valid;
+}
+
+void TiledTextureImage::BeginTileIteration()
+{
+    mCurrentImage = 0;
+}
+
+bool TiledTextureImage::NextTile()
+{
+    bool continueIteration = true;
+
+    if (mIterationCallback)
+        continueIteration = mIterationCallback(this, mCurrentImage,
+                                               mIterationCallbackData);
+
+    if (mCurrentImage + 1 < mImages.Length()) {
+        mCurrentImage++;
+        return continueIteration;
+    }
+    return false;
+}
+
+void TiledTextureImage::SetIterationCallback(TileIterationCallback aCallback,
+                                             void* aCallbackData)
+{
+    mIterationCallback = aCallback;
+    mIterationCallbackData = aCallbackData;
+}
+
+gfx::IntRect TiledTextureImage::GetTileRect()
+{
+    if (!GetTileCount()) {
+        return gfx::IntRect();
+    }
+    gfx::IntRect rect = mImages[mCurrentImage]->GetTileRect();
+    unsigned int xPos = (mCurrentImage % mColumns) * mTileSize;
+    unsigned int yPos = (mCurrentImage / mColumns) * mTileSize;
+    rect.MoveBy(xPos, yPos);
+    return rect;
+}
+
+gfx::IntRect TiledTextureImage::GetSrcTileRect()
+{
+    gfx::IntRect rect = GetTileRect();
+    unsigned int srcY = mFlags & NeedsYFlip
+                        ? mSize.height - rect.height - rect.y
+                        : rect.y;
+    return gfx::IntRect(rect.x, srcY, rect.width, rect.height);
+}
+
+void
+TiledTextureImage::BindTexture(GLenum aTextureUnit)
+{
+    if (!GetTileCount()) {
+        return;
+    }
+    mImages[mCurrentImage]->BindTexture(aTextureUnit);
+}
+
+/*
+ * Resize, trying to reuse tiles. The reuse strategy is to decide on reuse per
+ * column. A tile on a column is reused if it hasn't changed size, otherwise it
+ * is discarded/replaced. Extra tiles on a column are pruned after iterating
+ * each column, and extra rows are pruned after iteration over the entire image
+ * finishes.
+ */
+void TiledTextureImage::Resize(const gfx::IntSize& aSize)
+{
+    if (mSize == aSize && mTextureState != Created) {
+        return;
+    }
+
+    // calculate rows and columns, rounding up
+    unsigned int columns = (aSize.width  + mTileSize - 1) / mTileSize;
+    unsigned int rows = (aSize.height + mTileSize - 1) / mTileSize;
+
+    // Iterate over old tile-store and insert/remove tiles as necessary
+    int row;
+    unsigned int i = 0;
+    for (row = 0; row < (int)rows; row++) {
+        // If we've gone beyond how many rows there were before, set mColumns to
+        // zero so that we only create new tiles.
+        if (row >= (int)mRows)
+            mColumns = 0;
+
+        // Similarly, if we're on the last row of old tiles and the height has
+        // changed, discard all tiles in that row.
+        // This will cause the pruning of columns not to work, but we don't need
+        // to worry about that, as no more tiles will be reused past this point
+        // anyway.
+        if ((row == (int)mRows - 1) && (aSize.height != mSize.height))
+            mColumns = 0;
+
+        int col;
+        for (col = 0; col < (int)columns; col++) {
+            nsIntSize size( // use tilesize first, then the remainder
+                    (col+1) * mTileSize > (unsigned int)aSize.width  ? aSize.width  % mTileSize : mTileSize,
+                    (row+1) * mTileSize > (unsigned int)aSize.height ? aSize.height % mTileSize : mTileSize);
+
+            bool replace = false;
+
+            // Check if we can re-use old tiles.
+            if (col < (int)mColumns) {
+                // Reuse an existing tile. If the tile is an end-tile and the
+                // width differs, replace it instead.
+                if (mSize.width != aSize.width) {
+                    if (col == (int)mColumns - 1) {
+                        // Tile at the end of the old column, replace it with
+                        // a new one.
+                        replace = true;
+                    } else if (col == (int)columns - 1) {
+                        // Tile at the end of the new column, create a new one.
+                    } else {
+                        // Before the last column on both the old and new sizes,
+                        // reuse existing tile.
+                        i++;
+                        continue;
+                    }
+                } else {
+                    // Width hasn't changed, reuse existing tile.
+                    i++;
+                    continue;
+                }
+            }
+
+            // Create a new tile.
+            nsRefPtr<TextureImage> teximg =
+                TileGenFunc(mGL, size, mContentType, mFlags, mImageFormat);
+            if (replace)
+                mImages.ReplaceElementAt(i, teximg.forget());
+            else
+                mImages.InsertElementAt(i, teximg.forget());
+            i++;
+        }
+
+        // Prune any unused tiles on the end of the column.
+        if (row < (int)mRows) {
+            for (col = (int)mColumns - col; col > 0; col--) {
+                mImages.RemoveElementAt(i);
+            }
+        }
+    }
+
+    // Prune any unused tiles at the end of the store.
+    unsigned int length = mImages.Length();
+    for (; i < length; i++)
+      mImages.RemoveElementAt(mImages.Length()-1);
+
+    // Reset tile-store properties.
+    mRows = rows;
+    mColumns = columns;
+    mSize = aSize;
+    mTextureState = Allocated;
+    mCurrentImage = 0;
+}
+
+uint32_t TiledTextureImage::GetTileCount()
+{
+    return mImages.Length();
+}
+
+already_AddRefed<TextureImage>
+CreateBasicTextureImage(GLContext* aGL,
+                        const gfx::IntSize& aSize,
+                        TextureImage::ContentType aContentType,
+                        GLenum aWrapMode,
+                        TextureImage::Flags aFlags,
+                        TextureImage::ImageFormat aImageFormat)
+{
+    bool useNearestFilter = aFlags & TextureImage::UseNearestFilter;
+    if (!aGL->MakeCurrent()) {
+      return nullptr;
+    }
+
+    GLuint texture = 0;
+    aGL->fGenTextures(1, &texture);
+
+    ScopedBindTexture bind(aGL, texture);
+
+    GLint texfilter = useNearestFilter ? LOCAL_GL_NEAREST : LOCAL_GL_LINEAR;
+    aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, texfilter);
+    aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, texfilter);
+    aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S, aWrapMode);
+    aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T, aWrapMode);
+
+    nsRefPtr<BasicTextureImage> texImage =
+        new BasicTextureImage(texture, aSize, aWrapMode, aContentType,
+                              aGL, aFlags, aImageFormat);
+    return texImage.forget();
+}
+
+} // namespace
+} // namespace
--- a/gfx/layers/CopyableCanvasLayer.cpp
+++ b/gfx/layers/CopyableCanvasLayer.cpp
@@ -29,17 +29,16 @@ using namespace mozilla::gl;
 
 namespace mozilla {
 namespace layers {
 
 CopyableCanvasLayer::CopyableCanvasLayer(LayerManager* aLayerManager, void *aImplData) :
   CanvasLayer(aLayerManager, aImplData)
 {
   MOZ_COUNT_CTOR(CopyableCanvasLayer);
-  mForceReadback = Preferences::GetBool("webgl.force-layers-readback", false);
 }
 
 CopyableCanvasLayer::~CopyableCanvasLayer()
 {
   MOZ_COUNT_DTOR(CopyableCanvasLayer);
 }
 
 void
--- a/gfx/layers/CopyableCanvasLayer.h
+++ b/gfx/layers/CopyableCanvasLayer.h
@@ -53,17 +53,16 @@ protected:
   nsRefPtr<gfxASurface> mDeprecatedSurface;
   nsRefPtr<mozilla::gl::GLContext> mGLContext;
   mozilla::RefPtr<mozilla::gfx::DrawTarget> mDrawTarget;
 
   uint32_t mCanvasFramebuffer;
 
   bool mIsGLAlphaPremult;
   bool mNeedsYFlip;
-  bool mForceReadback;
 
   RefPtr<gfx::DataSourceSurface> mCachedTempSurface;
   nsRefPtr<gfxImageSurface> mDeprecatedCachedTempSurface;
   gfx::IntSize mCachedSize;
   gfx::SurfaceFormat mCachedFormat;
   gfxImageFormat mDeprecatedCachedFormat;
 
   gfx::DataSourceSurface* GetTempSurface(const gfx::IntSize& aSize,
--- a/gfx/layers/LayerScope.cpp
+++ b/gfx/layers/LayerScope.cpp
@@ -12,17 +12,17 @@
 #include "mozilla/Preferences.h"
 #include "mozilla/Endian.h"
 #include "TexturePoolOGL.h"
 #include "mozilla/layers/TextureHostOGL.h"
 
 #include "gfxColor.h"
 #include "gfxContext.h"
 #include "gfxUtils.h"
-#include "gfxPlatform.h"
+#include "gfxPrefs.h"
 #include "nsIWidget.h"
 
 #include "GLContext.h"
 #include "GLContextProvider.h"
 #include "GLReadTexImageHelper.h"
 
 #include "nsIServiceManager.h"
 #include "nsIConsoleService.h"
@@ -632,17 +632,17 @@ protected:
     LinkedList<DebugGLData> *mList;
 };
 
 NS_IMPL_ISUPPORTS1(DebugDataSender, nsIRunnable);
 
 void
 LayerScope::CreateServerSocket()
 {
-    if (!Preferences::GetBool("gfx.layerscope.enabled", false)) {
+    if (!gfxPrefs::LayerScopeEnabled()) {
         return;
     }
 
     if (!gLayerScopeWebSocketManager) {
         gLayerScopeWebSocketManager = new LayerScopeWebSocketManager();
     }
 }
 
@@ -809,17 +809,17 @@ LayerScope::SendEffectChain(GLContext* a
     // TODO:
 }
 
 LayerScopeWebSocketManager::LayerScopeWebSocketManager()
 {
     NS_NewThread(getter_AddRefs(mDebugSenderThread));
 
     mServerSocket = do_CreateInstance(NS_SERVERSOCKET_CONTRACTID);
-    int port = Preferences::GetInt("gfx.layerscope.port", 23456);
+    int port = gfxPrefs::LayerScopePort();
     mServerSocket->Init(port, false, -1);
     mServerSocket->AsyncListen(new DebugListener);
 }
 
 LayerScopeWebSocketManager::~LayerScopeWebSocketManager()
 {
 }
 
--- a/gfx/layers/LayerTreeInvalidation.cpp
+++ b/gfx/layers/LayerTreeInvalidation.cpp
@@ -54,24 +54,22 @@ TransformRect(const nsIntRect& aRect, co
 static void
 AddTransformedRegion(nsIntRegion& aDest, const nsIntRegion& aSource, const gfx3DMatrix& aTransform)
 {
   nsIntRegionRectIterator iter(aSource);
   const nsIntRect *r;
   while ((r = iter.Next())) {
     aDest.Or(aDest, TransformRect(*r, aTransform));
   }
-  aDest.SimplifyOutward(4);
 }
 
 static void
 AddRegion(nsIntRegion& aDest, const nsIntRegion& aSource)
 {
   aDest.Or(aDest, aSource);
-  aDest.SimplifyOutward(4);
 }
 
 static nsIntRegion
 TransformRegion(const nsIntRegion& aRegion, const gfx3DMatrix& aTransform)
 {
   nsIntRegion result;
   AddTransformedRegion(result, aRegion, aTransform);
   return result;
--- a/gfx/layers/LayersTypes.h
+++ b/gfx/layers/LayersTypes.h
@@ -84,30 +84,30 @@ enum LayerRenderStateFlags {
   LAYER_RENDER_STATE_FORMAT_RB_SWAP = 1 << 2
 };
 
 // The 'ifdef MOZ_WIDGET_GONK' sadness here is because we don't want to include
 // android::sp unless we have to.
 struct LayerRenderState {
   LayerRenderState()
 #ifdef MOZ_WIDGET_GONK
-    : mSurface(nullptr), mFlags(0), mHasOwnOffset(false), mTexture(nullptr)
+    : mSurface(nullptr), mTexture(nullptr), mFlags(0), mHasOwnOffset(false)
 #endif
   {}
 
 #ifdef MOZ_WIDGET_GONK
   LayerRenderState(android::GraphicBuffer* aSurface,
                    const nsIntSize& aSize,
                    uint32_t aFlags,
                    TextureHost* aTexture)
     : mSurface(aSurface)
     , mSize(aSize)
+    , mTexture(aTexture)
     , mFlags(aFlags)
     , mHasOwnOffset(false)
-    , mTexture(aTexture)
   {}
 
   bool YFlipped() const
   { return mFlags & LAYER_RENDER_STATE_Y_FLIPPED; }
 
   bool BufferRotated() const
   { return mFlags & LAYER_RENDER_STATE_BUFFER_ROTATION; }
 
--- a/gfx/layers/RotatedBuffer.cpp
+++ b/gfx/layers/RotatedBuffer.cpp
@@ -120,27 +120,34 @@ RotatedBuffer::DrawBufferQuadrant(gfx::D
     // OP_SOURCE is unbounded in Azure, and we really don't want that behaviour here.
     // We also can't do a ClearRect+FillRect since we need the drawing to happen
     // as an atomic operation (to prevent flickering).
     aTarget->PushClipRect(gfx::Rect(fillRect.x, fillRect.y,
                                     fillRect.width, fillRect.height));
   }
 
   if (aMask) {
+    Matrix oldTransform = aTarget->GetTransform();
+
     // Transform from user -> buffer space.
     Matrix transform;
     transform.Translate(quadrantTranslation.x, quadrantTranslation.y);
 
+    Matrix inverseMask = *aMaskTransform;
+    inverseMask.Invert();
+
+    transform *= oldTransform;
+    transform *= inverseMask;
+
 #ifdef MOZ_GFX_OPTIMIZE_MOBILE
     SurfacePattern source(snapshot, ExtendMode::CLAMP, transform, Filter::POINT);
 #else
     SurfacePattern source(snapshot, ExtendMode::CLAMP, transform);
 #endif
 
-    Matrix oldTransform = aTarget->GetTransform();
     aTarget->SetTransform(*aMaskTransform);
     aTarget->MaskSurface(source, aMask, Point(0, 0), DrawOptions(aOpacity, aOperator));
     aTarget->SetTransform(oldTransform);
   } else {
 #ifdef MOZ_GFX_OPTIMIZE_MOBILE
     DrawSurfaceOptions options(Filter::POINT);
 #else
     DrawSurfaceOptions options;
--- a/gfx/layers/basic/BasicThebesLayer.h
+++ b/gfx/layers/basic/BasicThebesLayer.h
@@ -48,17 +48,16 @@ public:
                  "Can only set properties in construction phase");
     ThebesLayer::SetVisibleRegion(aRegion);
   }
   virtual void InvalidateRegion(const nsIntRegion& aRegion)
   {
     NS_ASSERTION(BasicManager()->InConstruction(),
                  "Can only set properties in construction phase");
     mInvalidRegion.Or(mInvalidRegion, aRegion);
-    mInvalidRegion.SimplifyOutward(10);
     mValidRegion.Sub(mValidRegion, mInvalidRegion);
   }
 
   virtual void PaintThebes(gfxContext* aContext,
                            Layer* aMaskLayer,
                            LayerManager::DrawThebesLayerCallback aCallback,
                            void* aCallbackData,
                            ReadbackProcessor* aReadback);
--- a/gfx/layers/basic/TextureClientX11.cpp
+++ b/gfx/layers/basic/TextureClientX11.cpp
@@ -15,17 +15,18 @@
 #include <X11/Xlib.h>
 
 using namespace mozilla;
 using namespace mozilla::gfx;
 using namespace mozilla::layers;
 
 TextureClientX11::TextureClientX11(SurfaceFormat aFormat, TextureFlags aFlags)
   : TextureClient(aFlags),
-    mFormat(aFormat)
+    mFormat(aFormat),
+    mLocked(false)
 {
   MOZ_COUNT_CTOR(TextureClientX11);
 }
 
 TextureClientX11::~TextureClientX11()
 {
   MOZ_COUNT_DTOR(TextureClientX11);
 }
--- a/gfx/layers/client/ClientCanvasLayer.cpp
+++ b/gfx/layers/client/ClientCanvasLayer.cpp
@@ -20,16 +20,17 @@
 #include "nsRect.h"                     // for nsIntRect
 #include "nsXULAppAPI.h"                // for XRE_GetProcessType, etc
 #ifdef MOZ_WIDGET_GONK
 #include "SharedSurfaceGralloc.h"
 #endif
 #ifdef XP_MACOSX
 #include "SharedSurfaceIO.h"
 #endif
+#include "gfxPrefs.h"                   // for WebGLForceLayersReadback
 
 using namespace mozilla::gfx;
 using namespace mozilla::gl;
 
 namespace mozilla {
 namespace layers {
 
 void
@@ -40,17 +41,17 @@ ClientCanvasLayer::Initialize(const Data
   mCanvasClient = nullptr;
 
   if (mGLContext) {
     GLScreenBuffer* screen = mGLContext->Screen();
     SurfaceStreamType streamType =
         SurfaceStream::ChooseGLStreamType(SurfaceStream::OffMainThread,
                                           screen->PreserveBuffer());
     SurfaceFactory_GL* factory = nullptr;
-    if (!mForceReadback) {
+    if (!gfxPrefs::WebGLForceLayersReadback()) {
       if (ClientManager()->AsShadowForwarder()->GetCompositorBackendType() == mozilla::layers::LayersBackend::LAYERS_OPENGL) {
         if (mGLContext->GetContextType() == GLContextType::EGL) {
           bool isCrossProcess = !(XRE_GetProcessType() == GeckoProcessType_Default);
 
           if (!isCrossProcess) {
             // [Basic/OGL Layers, OMTC] WebGL layer init.
             factory = SurfaceFactory_EGLImage::Create(mGLContext, screen->Caps());
           } else {
--- a/gfx/layers/client/ClientLayerManager.cpp
+++ b/gfx/layers/client/ClientLayerManager.cpp
@@ -254,18 +254,18 @@ ClientLayerManager::GetRemoteRenderer()
   }
 
   return mWidget->GetRemoteRenderer();
 }
 
 void
 ClientLayerManager::Composite()
 {
-  if (CompositorChild* remoteRenderer = GetRemoteRenderer()) {
-    remoteRenderer->SendForceComposite();
+  if (LayerTransactionChild* manager = mForwarder->GetShadowManager()) {
+    manager->SendForceComposite();
   }
 }
 
 void 
 ClientLayerManager::MakeSnapshotIfRequired()
 {
   if (!mShadowTarget) {
     return;
--- a/gfx/layers/client/ClientThebesLayer.h
+++ b/gfx/layers/client/ClientThebesLayer.h
@@ -55,17 +55,16 @@ public:
                  "Can only set properties in construction phase");
     ThebesLayer::SetVisibleRegion(aRegion);
   }
   virtual void InvalidateRegion(const nsIntRegion& aRegion)
   {
     NS_ASSERTION(ClientManager()->InConstruction(),
                  "Can only set properties in construction phase");
     mInvalidRegion.Or(mInvalidRegion, aRegion);
-    mInvalidRegion.SimplifyOutward(10);
     mValidRegion.Sub(mValidRegion, mInvalidRegion);
   }
 
   virtual void RenderLayer();
 
   virtual void ClearCachedResources()
   {
     if (mContentClient) {
--- a/gfx/layers/d3d10/CanvasLayerD3D10.cpp
+++ b/gfx/layers/d3d10/CanvasLayerD3D10.cpp
@@ -8,32 +8,32 @@
 #include "../d3d9/Nv3DVUtils.h"
 #include "gfxImageSurface.h"
 #include "gfxWindowsSurface.h"
 #include "gfxWindowsPlatform.h"
 #include "SurfaceStream.h"
 #include "SharedSurfaceANGLE.h"
 #include "gfxContext.h"
 #include "GLContext.h"
+#include "gfxPrefs.h"
 
 using namespace mozilla::gl;
 using namespace mozilla::gfx;
 
 namespace mozilla {
 namespace layers {
 
 CanvasLayerD3D10::CanvasLayerD3D10(LayerManagerD3D10 *aManager)
   : CanvasLayer(aManager, nullptr)
   , LayerD3D10(aManager)
   , mDataIsPremultiplied(false)
   , mNeedsYFlip(false)
   , mHasAlpha(true)
 {
     mImplData = static_cast<LayerD3D10*>(this);
-    mForceReadback = Preferences::GetBool("webgl.force-layers-readback", false);
 }
 
 CanvasLayerD3D10::~CanvasLayerD3D10()
 {
 }
 
 void
 CanvasLayerD3D10::Initialize(const Data& aData)
@@ -47,17 +47,17 @@ CanvasLayerD3D10::Initialize(const Data&
     mNeedsYFlip = true;
 
     GLScreenBuffer* screen = mGLContext->Screen();
     SurfaceStreamType streamType =
         SurfaceStream::ChooseGLStreamType(SurfaceStream::MainThread,
                                           screen->PreserveBuffer());
 
     SurfaceFactory_GL* factory = nullptr;
-    if (!mForceReadback) {
+    if (!gfxPrefs::WebGLForceLayersReadback()) {
       if (mGLContext->IsANGLE()) {
         factory = SurfaceFactory_ANGLEShareHandle::Create(mGLContext,
                                                           device(),
                                                           screen->Caps());
       }
     }
 
     if (factory) {
--- a/gfx/layers/d3d10/CanvasLayerD3D10.h
+++ b/gfx/layers/d3d10/CanvasLayerD3D10.h
@@ -45,17 +45,16 @@ private:
   nsRefPtr<ID3D10Texture2D> mTexture;
   nsRefPtr<ID3D10ShaderResourceView> mUploadSRView;
   nsRefPtr<ID3D10ShaderResourceView> mSRView;
 
   bool mDataIsPremultiplied;
   bool mNeedsYFlip;
   bool mIsD2DTexture;
   bool mHasAlpha;
-  bool mForceReadback;
 
   nsAutoArrayPtr<uint8_t> mCachedTempBlob;
   uint32_t mCachedTempBlob_Size;
 
   uint8_t* GetTempBlob(const uint32_t aSize)
   {
     if (!mCachedTempBlob || aSize != mCachedTempBlob_Size) {
       mCachedTempBlob = new uint8_t[aSize];
--- a/gfx/layers/d3d9/ThebesLayerD3D9.cpp
+++ b/gfx/layers/d3d9/ThebesLayerD3D9.cpp
@@ -47,17 +47,16 @@ ThebesLayerD3D9::~ThebesLayerD3D9()
  * figure out the optimal threshold.
  */
 #define RETENTION_THRESHOLD 16384
 
 void
 ThebesLayerD3D9::InvalidateRegion(const nsIntRegion &aRegion)
 {
   mInvalidRegion.Or(mInvalidRegion, aRegion);
-  mInvalidRegion.SimplifyOutward(10);
   mValidRegion.Sub(mValidRegion, mInvalidRegion);
 }
 
 void
 ThebesLayerD3D9::CopyRegion(IDirect3DTexture9* aSrc, const nsIntPoint &aSrcOffset,
                             IDirect3DTexture9* aDest, const nsIntPoint &aDestOffset,
                             const nsIntRegion &aCopyRegion, nsIntRegion* aValidRegion)
 {
--- a/gfx/layers/ipc/CompositorParent.cpp
+++ b/gfx/layers/ipc/CompositorParent.cpp
@@ -333,23 +333,16 @@ CompositorParent::RecvFlushRendering()
     mCurrentCompositeTask->Cancel();
     mCurrentCompositeTask = nullptr;
     ForceComposeToTarget(nullptr);
   }
   return true;
 }
 
 bool
-CompositorParent::RecvForceComposite()
-{
-  ScheduleComposition();
-  return true;
-}
-
-bool
 CompositorParent::RecvNotifyRegionInvalidated(const nsIntRegion& aRegion)
 {
   if (mLayerManager) {
     mLayerManager->AddInvalidRegion(aRegion);
   }
   return true;
 }
 
@@ -754,16 +747,22 @@ CompositorParent::ShadowLayersUpdated(La
   }
   if (aScheduleComposite) {
     ScheduleComposition();
   }
   mLayerManager->NotifyShadowTreeTransaction();
 }
 
 void
+CompositorParent::ForceComposite(LayerTransactionParent* aLayerTree)
+{
+  ScheduleComposition();
+}
+
+void
 CompositorParent::InitializeLayerManager(const nsTArray<LayersBackend>& aBackendHints)
 {
   NS_ASSERTION(!mLayerManager, "Already initialised mLayerManager");
   NS_ASSERTION(!mCompositor,   "Already initialised mCompositor");
 
   for (size_t i = 0; i < aBackendHints.Length(); ++i) {
     RefPtr<Compositor> compositor;
     if (aBackendHints[i] == LayersBackend::LAYERS_OPENGL) {
@@ -1012,17 +1011,16 @@ public:
   virtual bool RecvStop() MOZ_OVERRIDE { return true; }
   virtual bool RecvPause() MOZ_OVERRIDE { return true; }
   virtual bool RecvResume() MOZ_OVERRIDE { return true; }
   virtual bool RecvNotifyChildCreated(const uint64_t& child) MOZ_OVERRIDE;
   virtual bool RecvMakeSnapshot(const SurfaceDescriptor& aInSnapshot,
                                 SurfaceDescriptor* aOutSnapshot)
   { return true; }
   virtual bool RecvFlushRendering() MOZ_OVERRIDE { return true; }
-  virtual bool RecvForceComposite() MOZ_OVERRIDE { return true; }
   virtual bool RecvNotifyRegionInvalidated(const nsIntRegion& aRegion) { return true; }
   virtual bool RecvStartFrameTimeRecording(const int32_t& aBufferSize, uint32_t* aOutStartIndex) MOZ_OVERRIDE { return true; }
   virtual bool RecvStopFrameTimeRecording(const uint32_t& aStartIndex, InfallibleTArray<float>* intervals) MOZ_OVERRIDE  { return true; }
   virtual bool RecvSetTestSampleTime(const TimeStamp& aTime) MOZ_OVERRIDE { return true; }
   virtual bool RecvLeaveTestMode() MOZ_OVERRIDE { return true; }
 
   virtual PLayerTransactionParent*
     AllocPLayerTransactionParent(const nsTArray<LayersBackend>& aBackendHints,
@@ -1031,16 +1029,17 @@ public:
                                  bool *aSuccess) MOZ_OVERRIDE;
 
   virtual bool DeallocPLayerTransactionParent(PLayerTransactionParent* aLayers) MOZ_OVERRIDE;
 
   virtual void ShadowLayersUpdated(LayerTransactionParent* aLayerTree,
                                    const TargetConfig& aTargetConfig,
                                    bool aIsFirstPaint,
                                    bool aScheduleComposite) MOZ_OVERRIDE;
+  virtual void ForceComposite(LayerTransactionParent* aLayerTree) MOZ_OVERRIDE;
 
   virtual AsyncCompositionManager* GetCompositionManager(LayerTransactionParent* aParent) MOZ_OVERRIDE;
 
 private:
   void DeferredDestroy();
 
   // There can be many CPCPs, and IPDL-generated code doesn't hold a
   // reference to top-level actors.  So we hold a reference to
@@ -1183,16 +1182,24 @@ CrossProcessCompositorParent::ShadowLaye
   if (shadowRoot) {
     SetShadowProperties(shadowRoot);
   }
   UpdateIndirectTree(id, shadowRoot, aTargetConfig);
 
   sIndirectLayerTrees[id].mParent->NotifyShadowTreeTransaction(id, aIsFirstPaint, aScheduleComposite);
 }
 
+void
+CrossProcessCompositorParent::ForceComposite(LayerTransactionParent* aLayerTree)
+{
+  uint64_t id = aLayerTree->GetId();
+  MOZ_ASSERT(id != 0);
+  sIndirectLayerTrees[id].mParent->ForceComposite(aLayerTree);
+}
+
 AsyncCompositionManager*
 CrossProcessCompositorParent::GetCompositionManager(LayerTransactionParent* aLayerTree)
 {
   uint64_t id = aLayerTree->GetId();
   return sIndirectLayerTrees[id].mParent->GetCompositionManager(aLayerTree);
 }
 
 void
--- a/gfx/layers/ipc/CompositorParent.h
+++ b/gfx/layers/ipc/CompositorParent.h
@@ -83,30 +83,30 @@ public:
   virtual bool RecvWillStop() MOZ_OVERRIDE;
   virtual bool RecvStop() MOZ_OVERRIDE;
   virtual bool RecvPause() MOZ_OVERRIDE;
   virtual bool RecvResume() MOZ_OVERRIDE;
   virtual bool RecvNotifyChildCreated(const uint64_t& child) MOZ_OVERRIDE;
   virtual bool RecvMakeSnapshot(const SurfaceDescriptor& aInSnapshot,
                                 SurfaceDescriptor* aOutSnapshot) MOZ_OVERRIDE;
   virtual bool RecvFlushRendering() MOZ_OVERRIDE;
-  virtual bool RecvForceComposite() MOZ_OVERRIDE;
 
   virtual bool RecvNotifyRegionInvalidated(const nsIntRegion& aRegion) MOZ_OVERRIDE;
   virtual bool RecvStartFrameTimeRecording(const int32_t& aBufferSize, uint32_t* aOutStartIndex) MOZ_OVERRIDE;
   virtual bool RecvStopFrameTimeRecording(const uint32_t& aStartIndex, InfallibleTArray<float>* intervals) MOZ_OVERRIDE;
   virtual bool RecvSetTestSampleTime(const TimeStamp& aTime) MOZ_OVERRIDE;
   virtual bool RecvLeaveTestMode() MOZ_OVERRIDE;
 
   virtual void ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE;
 
   virtual void ShadowLayersUpdated(LayerTransactionParent* aLayerTree,
                                    const TargetConfig& aTargetConfig,
                                    bool aIsFirstPaint,
                                    bool aScheduleComposite) MOZ_OVERRIDE;
+  virtual void ForceComposite(LayerTransactionParent* aLayerTree) MOZ_OVERRIDE;
   virtual AsyncCompositionManager* GetCompositionManager(LayerTransactionParent* aLayerTree) MOZ_OVERRIDE { return mCompositionManager; }
   /**
    * This forces the is-first-paint flag to true. This is intended to
    * be called by the widget code when it loses its viewport information
    * (or for whatever reason wants to refresh the viewport information).
    * The information refresh happens because the compositor will call
    * SetFirstPaintViewport on the next frame of composition.
    */
--- a/gfx/layers/ipc/LayerTransactionParent.cpp
+++ b/gfx/layers/ipc/LayerTransactionParent.cpp
@@ -643,16 +643,24 @@ LayerTransactionParent::RecvClearCachedR
     // NB: |mRoot| here is the *child* context's root.  In this parent
     // context, it's just a subtree root.  We need to scope the clear
     // of resources to exactly that subtree, so we specify it here.
     mLayerManager->ClearCachedResources(mRoot);
   }
   return true;
 }
 
+bool
+LayerTransactionParent::RecvForceComposite()
+{
+  mShadowLayersManager->ForceComposite(this);
+  return true;
+}
+
+
 PGrallocBufferParent*
 LayerTransactionParent::AllocPGrallocBufferParent(const IntSize& aSize,
                                                   const uint32_t& aFormat,
                                                   const uint32_t& aUsage,
                                                   MaybeMagicGrallocBufferHandle* aOutHandle)
 {
 #ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC
   return GrallocBufferActor::Create(aSize, aFormat, aUsage, aOutHandle);
--- a/gfx/layers/ipc/LayerTransactionParent.h
+++ b/gfx/layers/ipc/LayerTransactionParent.h
@@ -85,16 +85,17 @@ protected:
                           EditReplyArray* reply) MOZ_OVERRIDE;
 
   virtual bool RecvUpdateNoSwap(const EditArray& cset,
                                 const TargetConfig& targetConfig,
                                 const bool& isFirstPaint,
                                 const bool& scheduleComposite) MOZ_OVERRIDE;
 
   virtual bool RecvClearCachedResources() MOZ_OVERRIDE;
+  virtual bool RecvForceComposite() MOZ_OVERRIDE;
   virtual bool RecvGetOpacity(PLayerParent* aParent,
                               float* aOpacity) MOZ_OVERRIDE;
   virtual bool RecvGetTransform(PLayerParent* aParent,
                                 gfx3DMatrix* aTransform) MOZ_OVERRIDE;
 
   virtual PGrallocBufferParent*
   AllocPGrallocBufferParent(const IntSize& aSize,
                             const uint32_t& aFormat, const uint32_t& aUsage,
--- a/gfx/layers/ipc/PCompositor.ipdl
+++ b/gfx/layers/ipc/PCompositor.ipdl
@@ -64,19 +64,16 @@ parent:
   // and so forth being interpolated.  That's what we want to happen.
   sync MakeSnapshot(SurfaceDescriptor inSnapshot)
     returns (SurfaceDescriptor outSnapshot);
 
   // Make sure any pending composites are started immediately and
   // block until they are completed.
   sync FlushRendering();
 
-  // Schedule a composite if one isn't already scheduled.
-  async ForceComposite();
-
   sync StartFrameTimeRecording(int32_t bufferSize)
     returns (uint32_t startIndex);
 
   sync StopFrameTimeRecording(uint32_t startIndex)
     returns (float[] intervals);
 
   // Enter test mode, set the sample time to sampleTime, and resample animations.
   // sampleTime must not be null.
--- a/gfx/layers/ipc/PLayerTransaction.ipdl
+++ b/gfx/layers/ipc/PLayerTransaction.ipdl
@@ -80,14 +80,17 @@ parent:
 
   // We don't need to send a sync transaction if
   // no transaction operate require a swap.
   async UpdateNoSwap(Edit[] cset, TargetConfig targetConfig, bool isFirstPaint, bool scheduleComposite);
 
   // Drop any front buffers that might be retained on the compositor
   // side.
   async ClearCachedResources();
+  
+  // Schedule a composite if one isn't already scheduled.
+  async ForceComposite();
 
   async __delete__();
 };
 
 } // namespace layers
 } // namespace mozilla
--- a/gfx/layers/ipc/ShadowLayersManager.h
+++ b/gfx/layers/ipc/ShadowLayersManager.h
@@ -18,14 +18,16 @@ class ShadowLayersManager
 {
 public:
     virtual void ShadowLayersUpdated(LayerTransactionParent* aLayerTree,
                                      const TargetConfig& aTargetConfig,
                                      bool aIsFirstPaint,
                                      bool aScheduleComposite) = 0;
 
     virtual AsyncCompositionManager* GetCompositionManager(LayerTransactionParent* aLayerTree) { return nullptr; }
+
+    virtual void ForceComposite(LayerTransactionParent* aLayerTree) { }
 };
 
 } // layers
 } // mozilla
 
 #endif // mozilla_layers_ShadowLayersManager_h
--- a/gfx/layers/opengl/CompositorOGL.h
+++ b/gfx/layers/opengl/CompositorOGL.h
@@ -302,17 +302,16 @@ private:
    */
   GLint FlipY(GLint y) const { return mHeight - y; }
 
   bool mDestroyed;
 
   // Textures used for direct texturing of buffers like gralloc.
   // The index of the texture in this array must correspond to the texture unit.
   nsTArray<GLuint> mTextures;
-  static bool sDrawFPS;
 
   /**
    * Height of the OpenGL context's primary framebuffer in pixels. Used by
    * FlipY for the y-flipping calculation.
    */
   GLint mHeight;
 };
 
--- a/gfx/tests/crashtests/crashtests.list
+++ b/gfx/tests/crashtests/crashtests.list
@@ -95,16 +95,16 @@ load 665218.html
 load 686190-1.html
 load 693143-1.html
 load 768079-1.html
 load 783041-1.html
 load 783041-2.html
 load 783041-3.html
 load 783041-4.html
 asserts-if(gtk2Widget,1) load 798853.html # bug 868792
-asserts-if(winWidget,0-1) skip-if(B2G) load 815489.html
+asserts-if(winWidget,0-1) skip-if(B2G) skip-if(Android&&AndroidVersion==10) load 815489.html # bug 978277
 load 836225-1.html
 load 839745-1.html
 load 856784-1.html
 load 893572-1.html
 load 893572-2.html
 load 893572-3.html
 load 893572-4.html
--- a/gfx/tests/gtest/TestAsyncPanZoomController.cpp
+++ b/gfx/tests/gtest/TestAsyncPanZoomController.cpp
@@ -11,29 +11,50 @@
 #include "mozilla/layers/AsyncPanZoomController.h"
 #include "mozilla/layers/LayerManagerComposite.h"
 #include "mozilla/layers/GeckoContentController.h"
 #include "mozilla/layers/CompositorParent.h"
 #include "mozilla/layers/APZCTreeManager.h"
 #include "base/task.h"
 #include "Layers.h"
 #include "TestLayers.h"
+#include "gfxPrefs.h"
 
 using namespace mozilla;
 using namespace mozilla::gfx;
 using namespace mozilla::layers;
 using ::testing::_;
 using ::testing::NiceMock;
 using ::testing::AtLeast;
 using ::testing::AtMost;
 using ::testing::MockFunction;
 using ::testing::InSequence;
 
 class Task;
 
+class AsyncPanZoomControllerTester : public ::testing::Test {
+protected:
+  virtual void SetUp() {
+    gfxPrefs::One();
+  }
+  virtual void TearDown() {
+    gfxPrefs::Destroy();
+  }
+};
+
+class APZCTreeManagerTester : public ::testing::Test {
+protected:
+  virtual void SetUp() {
+    gfxPrefs::One();
+  }
+  virtual void TearDown() {
+    gfxPrefs::Destroy();
+  }
+};
+
 class MockContentController : public GeckoContentController {
 public:
   MOCK_METHOD1(RequestContentRepaint, void(const FrameMetrics&));
   MOCK_METHOD2(AcknowledgeScrollUpdate, void(const FrameMetrics::ViewID&, const uint32_t& aScrollGeneration));
   MOCK_METHOD3(HandleDoubleTap, void(const CSSIntPoint&, int32_t, const ScrollableLayerGuid&));
   MOCK_METHOD3(HandleSingleTap, void(const CSSIntPoint&, int32_t, const ScrollableLayerGuid&));
   MOCK_METHOD3(HandleLongTap, void(const CSSIntPoint&, int32_t, const ScrollableLayerGuid&));
   MOCK_METHOD3(HandleLongTapUp, void(const CSSIntPoint&, int32_t, const ScrollableLayerGuid&));
@@ -539,43 +560,43 @@ TEST(AsyncPanZoomController, ComplexTran
 
   childMetrics.mZoom.scale *= 1.5f;
   childApzc->SetFrameMetrics(childMetrics);
   childApzc->SampleContentTransformForFrame(testStartTime, &viewTransformOut, pointOut);
   EXPECT_EQ(ViewTransform(LayerPoint(-30, 0), ParentLayerToScreenScale(3)), viewTransformOut);
   EXPECT_EQ(ScreenPoint(135, 90), pointOut);
 }
 
-TEST(AsyncPanZoomController, Pan) {
+TEST_F(AsyncPanZoomControllerTester, Pan) {
   DoPanTest(true, false, mozilla::layers::AllowedTouchBehavior::NONE);
 }
 
 // In the each of the following 4 pan tests we are performing two pan gestures: vertical pan from top
 // to bottom and back - from bottom to top.
 // According to the pointer-events/touch-action spec AUTO and PAN_Y touch-action values allow vertical
 // scrolling while NONE and PAN_X forbid it. The first parameter of DoPanTest method specifies this
 // behavior.
-TEST(AsyncPanZoomController, PanWithTouchActionAuto) {
+TEST_F(AsyncPanZoomControllerTester, PanWithTouchActionAuto) {
   DoPanTest(true, true,
             mozilla::layers::AllowedTouchBehavior::HORIZONTAL_PAN | mozilla::layers::AllowedTouchBehavior::VERTICAL_PAN);
 }
 
-TEST(AsyncPanZoomController, PanWithTouchActionNone) {
+TEST_F(AsyncPanZoomControllerTester, PanWithTouchActionNone) {
   DoPanTest(false, true, 0);
 }
 
-TEST(AsyncPanZoomController, PanWithTouchActionPanX) {
+TEST_F(AsyncPanZoomControllerTester, PanWithTouchActionPanX) {
   DoPanTest(false, true, mozilla::layers::AllowedTouchBehavior::HORIZONTAL_PAN);
 }
 
-TEST(AsyncPanZoomController, PanWithTouchActionPanY) {
+TEST_F(AsyncPanZoomControllerTester, PanWithTouchActionPanY) {
   DoPanTest(true, true, mozilla::layers::AllowedTouchBehavior::VERTICAL_PAN);
 }
 
-TEST(AsyncPanZoomController, PanWithPreventDefault) {
+TEST_F(AsyncPanZoomControllerTester, PanWithPreventDefault) {
   TimeStamp testStartTime = TimeStamp::Now();
   AsyncPanZoomController::SetFrameTime(testStartTime);
 
   nsRefPtr<MockContentController> mcc = new NiceMock<MockContentController>();
   nsRefPtr<TestAPZCTreeManager> tm = new TestAPZCTreeManager();
   nsRefPtr<TestAsyncPanZoomController> apzc = new TestAsyncPanZoomController(0, mcc, tm);
 
   FrameMetrics frameMetrics(TestFrameMetrics());
@@ -603,17 +624,17 @@ TEST(AsyncPanZoomController, PanWithPrev
 
   apzc->SampleContentTransformForFrame(testStartTime, &viewTransformOut, pointOut);
   EXPECT_EQ(pointOut, ScreenPoint());
   EXPECT_EQ(viewTransformOut, ViewTransform());
 
   apzc->Destroy();
 }
 
-TEST(AsyncPanZoomController, Fling) {
+TEST_F(AsyncPanZoomControllerTester, Fling) {
   TimeStamp testStartTime = TimeStamp::Now();
   AsyncPanZoomController::SetFrameTime(testStartTime);
 
   nsRefPtr<MockContentController> mcc = new NiceMock<MockContentController>();
   nsRefPtr<TestAPZCTreeManager> tm = new TestAPZCTreeManager();
   nsRefPtr<TestAsyncPanZoomController> apzc = new TestAsyncPanZoomController(0, mcc, tm);
 
   apzc->SetFrameMetrics(TestFrameMetrics());
@@ -633,17 +654,17 @@ TEST(AsyncPanZoomController, Fling) {
   ScreenPoint lastPoint;
   for (int i = 1; i < 50; i+=1) {
     apzc->SampleContentTransformForFrame(testStartTime+TimeDuration::FromMilliseconds(i), &viewTransformOut, pointOut);
     EXPECT_GT(pointOut.y, lastPoint.y);
     lastPoint = pointOut;
   }
 }
 
-TEST(AsyncPanZoomController, OverScrollPanning) {
+TEST_F(AsyncPanZoomControllerTester, OverScrollPanning) {
   TimeStamp testStartTime = TimeStamp::Now();
   AsyncPanZoomController::SetFrameTime(testStartTime);
 
   nsRefPtr<MockContentController> mcc = new NiceMock<MockContentController>();
   nsRefPtr<TestAPZCTreeManager> tm = new TestAPZCTreeManager();
   nsRefPtr<TestAsyncPanZoomController> apzc = new TestAsyncPanZoomController(0, mcc, tm);
 
   apzc->SetFrameMetrics(TestFrameMetrics());
@@ -994,17 +1015,17 @@ TEST(APZCTreeManager, HitTesting1) {
   EXPECT_EQ(nullAPZC, hit.get());
   EXPECT_EQ(gfx3DMatrix(), transformToApzc);
   EXPECT_EQ(gfx3DMatrix(), transformToGecko);
 
   manager->ClearTree();
 }
 
 // A more involved hit testing test that involves css and async transforms.
-TEST(APZCTreeManager, HitTesting2) {
+TEST_F(APZCTreeManagerTester, HitTesting2) {
   nsTArray<nsRefPtr<Layer> > layers;
   nsRefPtr<LayerManager> lm;
   nsRefPtr<Layer> root = CreateTestLayerTree2(lm, layers);
 
   TimeStamp testStartTime = TimeStamp::Now();
   AsyncPanZoomController::SetFrameTime(testStartTime);
   nsRefPtr<MockContentController> mcc = new NiceMock<MockContentController>();
   ScopedLayerTreeRegistration controller(0, root, mcc);
--- a/gfx/thebes/gfxFont.cpp
+++ b/gfx/thebes/gfxFont.cpp
@@ -5035,25 +5035,25 @@ gfxFontGroup::FindFontForChar(uint32_t a
         // we don't need to check the first font again below
         ++nextIndex;
     }
 
     if (aPrevMatchedFont) {
         // Don't switch fonts for control characters, regardless of
         // whether they are present in the current font, as they won't
         // actually be rendered (see bug 716229)
-        uint8_t category = GetGeneralCategory(aCh);
-        if (category == HB_UNICODE_GENERAL_CATEGORY_CONTROL) {
+        if (isJoinControl ||
+            GetGeneralCategory(aCh) == HB_UNICODE_GENERAL_CATEGORY_CONTROL) {
             nsRefPtr<gfxFont> ret = aPrevMatchedFont;
             return ret.forget();
         }
 
-        // if this character is a join-control or the previous is a join-causer,
+        // if previous character was a join-causer (ZWJ),
         // use the same font as the previous range if we can
-        if (isJoinControl || wasJoinCauser) {
+        if (wasJoinCauser) {
             if (aPrevMatchedFont->HasCharacter(aCh)) {
                 nsRefPtr<gfxFont> ret = aPrevMatchedFont;
                 return ret.forget();
             }
         }
     }
 
     // if this character is a variation selector,
@@ -5127,24 +5127,27 @@ template<typename T>
 void gfxFontGroup::ComputeRanges(nsTArray<gfxTextRange>& aRanges,
                                  const T *aString, uint32_t aLength,
                                  int32_t aRunScript)
 {
     NS_ASSERTION(aRanges.Length() == 0, "aRanges must be initially empty");
     NS_ASSERTION(aLength > 0, "don't call ComputeRanges for zero-length text");
 
     uint32_t prevCh = 0;
-    uint8_t matchType = 0;
     int32_t lastRangeIndex = -1;
 
     // initialize prevFont to the group's primary font, so that this will be
     // used for string-initial control chars, etc rather than risk hitting font
     // fallback for these (bug 716229)
     gfxFont *prevFont = GetFontAt(0);
 
+    // if we use the initial value of prevFont, we treat this as a match from
+    // the font group; fixes bug 978313
+    uint8_t matchType = gfxTextRange::kFontGroup;
+
     for (uint32_t i = 0; i < aLength; i++) {
 
         const uint32_t origI = i; // save off in case we increase for surrogate
 
         // set up current ch
         uint32_t ch = aString[i];
 
         // in 16-bit case only, check for surrogate pair
--- a/gfx/thebes/gfxFont.h
+++ b/gfx/thebes/gfxFont.h
@@ -1298,16 +1298,21 @@ private:
         }
 
         nsTArray<uintptr_t> mBlocks;
     };
 
     GlyphWidths             mContainedGlyphWidths;
     nsTHashtable<HashEntry> mTightGlyphExtents;
     int32_t                 mAppUnitsPerDevUnit;
+
+private:
+    // not implemented:
+    gfxGlyphExtents(const gfxGlyphExtents& aOther) MOZ_DELETE;
+    gfxGlyphExtents& operator=(const gfxGlyphExtents& aOther) MOZ_DELETE;
 };
 
 /**
  * gfxFontShaper
  *
  * This class implements text shaping (character to glyph mapping and
  * glyph layout). There is a gfxFontShaper subclass for each text layout
  * technology (uniscribe, core text, harfbuzz,....) we support.
--- a/gfx/thebes/gfxFontUtils.cpp
+++ b/gfx/thebes/gfxFontUtils.cpp
@@ -1270,17 +1270,21 @@ gfxFontUtils::GetCharsetForFontName(uint
 
 // convert a raw name from the name table to an nsString, if possible;
 // return value indicates whether conversion succeeded
 bool
 gfxFontUtils::DecodeFontName(const char *aNameData, int32_t aByteLen, 
                              uint32_t aPlatformCode, uint32_t aScriptCode,
                              uint32_t aLangCode, nsAString& aName)
 {
-    NS_ASSERTION(aByteLen > 0, "bad length for font name data");
+    if (aByteLen <= 0) {
+        NS_WARNING("empty font name");
+        aName.SetLength(0);
+        return true;
+    }
 
     const char *csName = GetCharsetForFontName(aPlatformCode, aScriptCode, aLangCode);
 
     if (!csName) {
         // nullptr -> unknown charset
 #ifdef DEBUG
         char warnBuf[128];
         if (aByteLen > 64)
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -529,24 +529,16 @@ gfxPlatform::~gfxPlatform()
     // Cairo objects e.g. through SkCairoFTTypeface
     SkGraphics::Term();
 #endif
 
 #if MOZ_TREE_CAIRO
     cairo_debug_reset_static_data();
 #endif
 #endif
-
-#if 0
-    // It would be nice to do this (although it might need to be after
-    // the cairo shutdown that happens in ~gfxPlatform).  It even looks
-    // idempotent.  But it has fatal assertions that fire if stuff is
-    // leaked, and we hit them.
-    FcFini();
-#endif
 }
 
 bool
 gfxPlatform::PreferMemoryOverShmem() const {
   MOZ_ASSERT(!CompositorParent::IsInCompositorThread());
   return mLayersPreferMemoryOverShmem;
 }
 
--- a/gfx/thebes/gfxPlatformGtk.cpp
+++ b/gfx/thebes/gfxPlatformGtk.cpp
@@ -70,24 +70,16 @@ gfxPlatformGtk::gfxPlatformGtk()
 }
 
 gfxPlatformGtk::~gfxPlatformGtk()
 {
     gfxFontconfigUtils::Shutdown();
     sFontconfigUtils = nullptr;
 
     gfxPangoFontGroup::Shutdown();
-
-#if 0
-    // It would be nice to do this (although it might need to be after
-    // the cairo shutdown that happens in ~gfxPlatform).  It even looks
-    // idempotent.  But it has fatal assertions that fire if stuff is
-    // leaked, and we hit them.
-    FcFini();
-#endif
 }
 
 already_AddRefed<gfxASurface>
 gfxPlatformGtk::CreateOffscreenSurface(const IntSize& size,
                                        gfxContentType contentType)
 {
     nsRefPtr<gfxASurface> newSurface;
     bool needsClear = true;
--- a/gfx/thebes/gfxPrefs.h
+++ b/gfx/thebes/gfxPrefs.h
@@ -97,23 +97,28 @@ private:
     }
     T mValue;
   };
 
   // This is where DECL_GFX_PREF for each of the preferences should go.
   // We will keep these in an alphabetical order to make it easier to see if
   // a method accessing a pref already exists. Just add yours in the list.
 
+#if defined(ANDROID)
+  DECL_GFX_PREF(Once, "gfx.apitrace.enabled",                  UseApitrace, bool, false);
+#endif
   DECL_GFX_PREF(Live, "gfx.canvas.azure.accelerated",          CanvasAzureAccelerated, bool, false);
   DECL_GFX_PREF(Once, "gfx.canvas.skiagl.dynamic-cache",       CanvasSkiaGLDynamicCache, bool, false);
   DECL_GFX_PREF(Once, "gfx.canvas.skiagl.cache-size",          CanvasSkiaGLCacheSize, int32_t, 96);
   DECL_GFX_PREF(Once, "gfx.canvas.skiagl.cache-items",         CanvasSkiaGLCacheItems, int32_t, 256);
 
   DECL_GFX_PREF(Once, "gfx.direct2d.disabled",                 Direct2DDisabled, bool, false);
   DECL_GFX_PREF(Once, "gfx.direct2d.force-enabled",            Direct2DForceEnabled, bool, false);
+  DECL_GFX_PREF(Live, "gfx.layerscope.enabled",                LayerScopeEnabled, bool, false);
+  DECL_GFX_PREF(Live, "gfx.layerscope.port",                   LayerScopePort, int32_t, 23456);
   DECL_GFX_PREF(Once, "gfx.work-around-driver-bugs",           WorkAroundDriverBugs, bool, true);
 
   DECL_GFX_PREF(Live, "gl.msaa-level",                         MSAALevel, uint32_t, 2);
 
   DECL_GFX_PREF(Once, "layers.acceleration.disabled",          LayersAccelerationDisabled, bool, false);
   DECL_GFX_PREF(Live, "layers.acceleration.draw-fps",          LayersDrawFPS, bool, true);
   DECL_GFX_PREF(Once, "layers.acceleration.force-enabled",     LayersAccelerationForceEnabled, bool, false);
 #ifdef XP_WIN
@@ -149,16 +154,18 @@ private:
   DECL_GFX_PREF(Once, "layers.prefer-opengl",                  LayersPreferOpenGL, bool, false);
   DECL_GFX_PREF(Once, "layers.progressive-paint",              UseProgressiveTilePainting, bool, false);
   DECL_GFX_PREF(Once, "layers.scroll-graph",                   LayersScrollGraph, bool, false);
 
   DECL_GFX_PREF(Once, "layout.frame_rate",                     LayoutFrameRate, int32_t, -1);
 
   DECL_GFX_PREF(Live, "nglayout.debug.widget_update_flashing", WidgetUpdateFlashing, bool, false);
 
+  DECL_GFX_PREF(Once, "webgl.force-layers-readback",           WebGLForceLayersReadback, bool, false);
+
 public:
   // Manage the singleton:
   static gfxPrefs& One()
   {
     if (!sInstance) {
       sInstance = new gfxPrefs;
     }
     return *sInstance;
--- a/image/decoders/nsJPEGDecoder.cpp
+++ b/image/decoders/nsJPEGDecoder.cpp
@@ -236,18 +236,27 @@ nsJPEGDecoder::WriteInternal(const char 
 
     /* Step 3: read file parameters with jpeg_read_header() */
     if (jpeg_read_header(&mInfo, TRUE) == JPEG_SUSPENDED) {
       PR_LOG(GetJPEGDecoderAccountingLog(), PR_LOG_DEBUG,
              ("} (JPEG_SUSPENDED)"));
       return; /* I/O suspension */
     }
 
+    int sampleSize = mImage.GetRequestedSampleSize();
+    if (sampleSize > 0) {
+      mInfo.scale_num = 1;
+      mInfo.scale_denom = sampleSize;
+    }
+
+    /* Used to set up image size so arrays can be allocated */
+    jpeg_calc_output_dimensions(&mInfo);
+
     // Post our size to the superclass
-    PostSize(mInfo.image_width, mInfo.image_height, ReadOrientationFromEXIF());
+    PostSize(mInfo.output_width, mInfo.output_height, ReadOrientationFromEXIF());
     if (HasError()) {
       // Setting the size led to an error.
       mState = JPEG_ERROR;
       return;
     }
 
     /* If we're doing a size decode, we're done. */
     if (IsSizeDecode())
@@ -370,30 +379,27 @@ nsJPEGDecoder::WriteInternal(const char 
     }
 
     /*
      * Don't allocate a giant and superfluous memory buffer
      * when not doing a progressive decode.
      */
     mInfo.buffered_image = mDecodeStyle == PROGRESSIVE && jpeg_has_multiple_scans(&mInfo);
 
-    /* Used to set up image size so arrays can be allocated */
-    jpeg_calc_output_dimensions(&mInfo);
-
     if (!mImageData) {
       mState = JPEG_ERROR;
       PostDecoderError(NS_ERROR_OUT_OF_MEMORY);
       PR_LOG(GetJPEGDecoderAccountingLog(), PR_LOG_DEBUG,
              ("} (could not initialize image frame)"));
       return;
     }
 
     PR_LOG(GetJPEGDecoderAccountingLog(), PR_LOG_DEBUG,
            ("        JPEGDecoderAccounting: nsJPEGDecoder::Write -- created image frame with %ux%u pixels",
-            mInfo.image_width, mInfo.image_height));
+            mInfo.output_width, mInfo.output_height));
 
     mState = JPEG_START_DECOMPRESS;
   }
 
   case JPEG_START_DECOMPRESS:
   {
     LOG_SCOPE(GetJPEGLog(), "nsJPEGDecoder::Write -- entering JPEG_START_DECOMPRESS case");
     /* Step 4: set parameters for decompression */
--- a/image/src/ImageFactory.cpp
+++ b/image/src/ImageFactory.cpp
@@ -14,34 +14,38 @@
 #include "nsIFile.h"
 #include "nsMimeTypes.h"
 #include "nsIRequest.h"
 
 #include "RasterImage.h"
 #include "VectorImage.h"
 #include "Image.h"
 #include "nsMediaFragmentURIParser.h"
+#include "nsContentUtils.h"
+#include "nsIScriptSecurityManager.h"
 
 #include "ImageFactory.h"
 
 namespace mozilla {
 namespace image {
 
 // Global preferences related to image containers.
 static bool gInitializedPrefCaches = false;
 static bool gDecodeOnDraw = false;
 static bool gDiscardable = false;
+static bool gEnableMozSampleSize = false;
 
 /*static*/ void
 ImageFactory::Initialize()
 {
   MOZ_ASSERT(NS_IsMainThread());
   if (!gInitializedPrefCaches) {
     Preferences::AddBoolVarCache(&gDiscardable, "image.mem.discardable");
     Preferences::AddBoolVarCache(&gDecodeOnDraw, "image.mem.decodeondraw");
+    Preferences::AddBoolVarCache(&gEnableMozSampleSize, "image.mozsamplesize.enabled");
     gInitializedPrefCaches = true;
   }
 }
 
 static uint32_t
 ComputeImageFlags(ImageURL* uri, bool isMultiPart)
 {
   nsresult rv;
@@ -207,16 +211,32 @@ ImageFactory::CreateRasterImage(nsIReque
 
   nsAutoCString ref;
   aURI->GetRef(ref);
   mozilla::net::nsMediaFragmentURIParser parser(ref);
   if (parser.HasResolution()) {
     newImage->SetRequestedResolution(parser.GetResolution());
   }
 
+  if (parser.HasSampleSize()) {
+      /* Get our principal */
+      nsCOMPtr<nsIChannel> chan(do_QueryInterface(aRequest));
+      nsCOMPtr<nsIPrincipal> principal;
+      if (chan) {
+        nsContentUtils::GetSecurityManager()->GetChannelPrincipal(chan,
+                                                                  getter_AddRefs(principal));
+      }
+
+      if ((principal &&
+           principal->GetAppStatus() == nsIPrincipal::APP_STATUS_CERTIFIED) ||
+          gEnableMozSampleSize) {
+        newImage->SetRequestedSampleSize(parser.GetSampleSize());
+      }
+  }
+
   return newImage.forget();
 }
 
 /* static */ already_AddRefed<Image>
 ImageFactory::CreateVectorImage(nsIRequest* aRequest,
                                 imgStatusTracker* aStatusTracker,
                                 const nsCString& aMimeType,
                                 ImageURL* aURI,
--- a/image/src/RasterImage.cpp
+++ b/image/src/RasterImage.cpp
@@ -382,16 +382,17 @@ RasterImage::RasterImage(imgStatusTracke
                          ImageURL* aURI /* = nullptr */) :
   ImageResource(aURI), // invoke superclass's constructor
   mSize(0,0),
   mFrameDecodeFlags(DECODE_FLAGS_DEFAULT),
   mMultipartDecodedFrame(nullptr),
   mAnim(nullptr),
   mLockCount(0),
   mDecodeCount(0),
+  mRequestedSampleSize(0),
 #ifdef DEBUG
   mFramesNotified(0),
 #endif
   mDecodingMonitor("RasterImage Decoding Monitor"),
   mDecoder(nullptr),
   mBytesDecoded(0),
   mInDecoder(false),
   mStatusDiff(ImageStatusDiff::NoChange()),
--- a/image/src/RasterImage.h
+++ b/image/src/RasterImage.h
@@ -271,16 +271,26 @@ public:
   /* Provide a hint for the requested resolution of the resulting image. */
   void SetRequestedResolution(const nsIntSize requestedResolution) {
     mRequestedResolution = requestedResolution;
   }
 
   nsIntSize GetRequestedResolution() {
     return mRequestedResolution;
   }
+  /* Provide a hint for the requested dimension of the resulting image. */
+  void SetRequestedSampleSize(int requestedSampleSize) {
+    mRequestedSampleSize = requestedSampleSize;
+  }
+
+  int GetRequestedSampleSize() {
+    return mRequestedSampleSize;
+  }
+
+
 
  nsCString GetURIString() {
     nsCString spec;
     if (GetURI()) {
       GetURI()->GetSpec(spec);
     }
     return spec;
   }
@@ -638,16 +648,19 @@ private: // data
 
   // How many times we've decoded this image.
   // This is currently only used for statistics
   int32_t                        mDecodeCount;
 
   // If the image contains multiple resolutions, a hint as to which one should be used
   nsIntSize                  mRequestedResolution;
 
+  // A hint for image decoder that directly scale the image to smaller buffer
+  int                        mRequestedSampleSize;
+
   // Cached value for GetImageContainer.
   nsRefPtr<mozilla::layers::ImageContainer> mImageContainer;
 
 #ifdef DEBUG
   uint32_t                       mFramesNotified;
 #endif
 
   // Below are the pieces of data that can be accessed on more than one thread
--- a/image/test/reftest/jpeg/reftest.list
+++ b/image/test/reftest/jpeg/reftest.list
@@ -47,8 +47,10 @@ random-if(Android) == jpg-srgb-icc.jpg j
 # <contents of blue.jpg> (no newline)
 # --BOUNDARYOMG--\r\n
 # 
 # (The boundary is arbitrary, and just has to be defined as something that
 # won't be in the text of the contents themselves. --$(boundary)\r\n means
 # "Here is the beginning of a boundary," and --$(boundary)-- means "All done
 # sending you parts.")
 HTTP == webcam-simulacrum.mjpg blue.jpg
+pref(image.mozsamplesize.enabled,true) fuzzy(21,256) == jpg-size-32x32.jpg#-moz-samplesize=2 jpg-size-16x16.png
+pref(image.mozsamplesize.enabled,true) fuzzy(92,16) == jpg-size-32x32.jpg#-moz-samplesize=8 jpg-size-4x4.png
--- a/js/public/GCAPI.h
+++ b/js/public/GCAPI.h
@@ -311,17 +311,17 @@ WasIncrementalGC(JSRuntime *rt);
  *       is non-functional unless SpiderMonkey was configured with
  *       --enable-gcgenerational.
  */
 
 /* Ensure that generational GC is disabled within some scope. */
 class JS_FRIEND_API(AutoDisableGenerationalGC)
 {
     JSRuntime *runtime;
-#ifdef JS_GC_ZEAL
+#if defined(JSGC_GENERATIONAL) && defined(JS_GC_ZEAL)
     bool restartVerifier;
 #endif
 
   public:
     AutoDisableGenerationalGC(JSRuntime *rt);
     ~AutoDisableGenerationalGC();
 };
 
--- a/js/src/builtin/TypedObject.js
+++ b/js/src/builtin/TypedObject.js
@@ -1433,16 +1433,18 @@ function MapTypedParImplDepth1(inArray, 
   const outGrainTypeSize = DESCR_SIZE(outGrainType);
   const inGrainTypeIsComplex = !TypeDescrIsSimpleType(inGrainType);
   const outGrainTypeIsComplex = !TypeDescrIsSimpleType(outGrainType);
 
   const length = inArray.length;
   const mode = undefined;
 
   const outArray = new outArrayType(length);
+  if (length === 0)
+    return outArray;
 
   const outGrainTypeIsTransparent = ObjectIsTransparentTypedObject(outArray);
 
   // Construct the slices and initial pointers for each worker:
   const slicesInfo = ComputeSlicesInfo(length);
   const numWorkers = ForkJoinNumWorkers();
   assert(numWorkers > 0, "Should have at least the main thread");
   const pointers = [];
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/parallel/bug977647.js
@@ -0,0 +1,12 @@
+// Check for mapPar() applied to an empty array.
+// Public domain.
+
+if (!this.hasOwnProperty("TypedObject"))
+  quit();
+
+var { ArrayType, StructType, uint32 } = TypedObject;
+var Point = new StructType({x: uint32, y: uint32});
+var Points = Point.array();
+var points = new Points();
+points.mapPar(function() {});
+
--- a/js/src/jsfriendapi.cpp
+++ b/js/src/jsfriendapi.cpp
@@ -927,17 +927,17 @@ JS::IsIncrementalGCInProgress(JSRuntime 
 JS_FRIEND_API(void)
 JS::DisableIncrementalGC(JSRuntime *rt)
 {
     rt->gcIncrementalEnabled = false;
 }
 
 JS::AutoDisableGenerationalGC::AutoDisableGenerationalGC(JSRuntime *rt)
   : runtime(rt)
-#ifdef JS_GC_ZEAL
+#if defined(JSGC_GENERATIONAL) && defined(JS_GC_ZEAL)
   , restartVerifier(rt->gcVerifyPostData)
 #endif
 {
 #ifdef JSGC_GENERATIONAL
     if (IsGenerationalGCEnabled(rt)) {
 #ifdef JS_GC_ZEAL
         if (restartVerifier)
             gc::EndVerifyPostBarriers(rt);
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -563,16 +563,17 @@ JSFunction::trace(JSTracer *trc)
         // Functions can be be marked as interpreted despite having no script
         // yet at some points when parsing, and can be lazy with no lazy script
         // for self-hosted code.
         if (hasScript() && u.i.s.script_) {
             // Functions can be relazified under the following conditions:
             // - their compartment isn't currently executing scripts or being
             //   debugged
             // - they are not in the self-hosting compartment
+            // - their 'arguments' object can't escape
             // - they aren't generators
             // - they don't have JIT code attached
             // - they don't have child functions
             // - they have information for un-lazifying them again later
             // This information can either be a LazyScript, or the name of a
             // self-hosted function which can be cloned over again. The latter
             // is stored in the first extended slot.
             if (IS_GC_MARKING_TRACER(trc) && !compartment()->hasBeenEntered() &&
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -3614,17 +3614,17 @@ LazyScript::CreateRaw(ExclusiveContext *
     p.generatorKindBits = GeneratorKindAsBits(NotGenerator);
     p.strict = false;
     p.bindingsAccessedDynamically = false;
     p.hasDebuggerStatement = false;
     p.directlyInsideEval = false;
     p.usesArgumentsAndApply = false;
 
     LazyScript *res = LazyScript::CreateRaw(cx, fun, packedFields, begin, end, lineno, column);
-    JS_ASSERT(res->version() == version);
+    JS_ASSERT_IF(res, res->version() == version);
     return res;
 }
 
 /* static */ LazyScript *
 LazyScript::Create(ExclusiveContext *cx, HandleFunction fun,
                    uint64_t packedFields, uint32_t begin, uint32_t end,
                    uint32_t lineno, uint32_t column)
 {
--- a/js/src/jsscript.h
+++ b/js/src/jsscript.h
@@ -1228,16 +1228,17 @@ class JSScript : public js::gc::Barriere
         return offsetof(JSScript, baselineOrIonRaw);
     }
     static size_t offsetOfBaselineOrIonSkipArgCheck() {
         return offsetof(JSScript, baselineOrIonSkipArgCheck);
     }
 
     bool isRelazifiable() const {
         return (selfHosted() || lazyScript) &&
+               !(analyzedArgsUsage() && needsArgsObj()) &&
                !isGenerator() && !hasBaselineScript() && !hasAnyIonScript();
     }
     void setLazyScript(js::LazyScript *lazy) {
         lazyScript = lazy;
     }
     js::LazyScript *maybeLazyScript() {
         return lazyScript;
     }
--- a/js/src/vm/MemoryMetrics.cpp
+++ b/js/src/vm/MemoryMetrics.cpp
@@ -323,16 +323,18 @@ enum Granularity {
     CoarseGrained   // Corresponds to AddSizeOfTab()
 };
 
 static void
 AddClassInfo(Granularity granularity, CompartmentStats *cStats, const char *className,
              JS::ClassInfo &info)
 {
     if (granularity == FineGrained) {
+        if (!className)
+            className = "<no class name>";
         CompartmentStats::ClassesHashMap::AddPtr p =
             cStats->allClasses->lookupForAdd(className);
         if (!p) {
             // Ignore failure -- we just won't record the
             // object/shape/base-shape as notable.
             (void)cStats->allClasses->add(p, className, info);
         } else {
             p->value().add(info);
--- a/layout/base/FrameLayerBuilder.cpp
+++ b/layout/base/FrameLayerBuilder.cpp
@@ -1699,66 +1699,75 @@ ContainerState::FindFixedPosFrameForLaye
 {
   if (!mManager->IsWidgetLayerManager()) {
     // Never attach any fixed-pos metadata to inactive layers, it's pointless!
     return nullptr;
   }
 
   nsPresContext* presContext = mContainerFrame->PresContext();
   nsIFrame* viewport = presContext->PresShell()->GetRootFrame();
-  const nsIFrame* result = nullptr;
-  nsRect displayPort;
 
   if (viewport == aAnimatedGeometryRoot && aDisplayItemFixedToViewport &&
-      nsLayoutUtils::ViewportHasDisplayPort(presContext, &displayPort)) {
+      nsLayoutUtils::ViewportHasDisplayPort(presContext)) {
     // Probably a background-attachment:fixed item
-    result = viewport;
-  } else {
-    // Viewports with no fixed-pos frames are not relevant.
-    if (!viewport->GetFirstChild(nsIFrame::kFixedList)) {
-      return nullptr;
+    return viewport;
+  }
+  // Viewports with no fixed-pos frames are not relevant.
+  if (!viewport->GetFirstChild(nsIFrame::kFixedList)) {
+    return nullptr;
+  }
+  for (const nsIFrame* f = aAnimatedGeometryRoot; f; f = f->GetParent()) {
+    if (nsLayoutUtils::IsFixedPosFrameInDisplayPort(f)) {
+      return f;
     }
-    for (const nsIFrame* f = aAnimatedGeometryRoot; f; f = f->GetParent()) {
-      if (nsLayoutUtils::IsFixedPosFrameInDisplayPort(f, &displayPort)) {
-        result = f;
-        break;
-      }
-      if (f == mContainerReferenceFrame) {
-        // The metadata will go on an ancestor layer if necessary.
-        return nullptr;
-      }
-    }
-    if (!result) {
+    if (f == mContainerReferenceFrame) {
+      // The metadata will go on an ancestor layer if necessary.
       return nullptr;
     }
   }
-  return result;
+  return nullptr;
 }
 
 void
 ContainerState::AdjustLayerDataForFixedPositioning(const nsIFrame* aFixedPosFrame,
                                                    const nsIntRegion& aDrawRegion,
                                                    nsIntRegion* aVisibleRegion,
                                                    bool* aIsSolidColorInVisibleRegion)
 {
   if (!aFixedPosFrame) {
     return;
   }
 
-  nsRect displayPort;
+  nsRect fixedVisibleRect;
   nsPresContext* presContext = aFixedPosFrame->PresContext();
+  nsIPresShell* presShell = presContext->PresShell();
   DebugOnly<bool> hasDisplayPort =
-    nsLayoutUtils::ViewportHasDisplayPort(presContext, &displayPort);
+    nsLayoutUtils::ViewportHasDisplayPort(presContext, &fixedVisibleRect);
   NS_ASSERTION(hasDisplayPort, "No fixed-pos layer data if there's no displayport");
   // Display ports are relative to the viewport, convert it to be relative
   // to our reference frame.
-  nsIFrame* viewport = presContext->PresShell()->GetRootFrame();
-  displayPort += viewport->GetOffsetToCrossDoc(mContainerReferenceFrame);
+  nsIFrame* viewport = presShell->GetRootFrame();
+  if (aFixedPosFrame != viewport) {
+    // position: fixed items are reflowed into and only drawn inside the
+    // viewport, or the scroll position clamping scrollport size, if one is
+    // set. We differentiate background-attachment: fixed items from
+    // position: fixed items by the fact that background-attachment: fixed
+    // items use the viewport as their aFixedPosFrame.
+    NS_ASSERTION(aFixedPosFrame->StyleDisplay()->mPosition == NS_STYLE_POSITION_FIXED,
+      "should be position fixed items only");
+    fixedVisibleRect.MoveTo(0, 0);
+    if (presShell->IsScrollPositionClampingScrollPortSizeSet()) {
+      fixedVisibleRect.SizeTo(presShell->GetScrollPositionClampingScrollPortSize());
+    } else {
+      fixedVisibleRect.SizeTo(viewport->GetSize());
+    }
+  }
+  fixedVisibleRect += viewport->GetOffsetToCrossDoc(mContainerReferenceFrame);
   nsIntRegion newVisibleRegion;
-  newVisibleRegion.And(ScaleToOutsidePixels(displayPort, false),
+  newVisibleRegion.And(ScaleToOutsidePixels(fixedVisibleRect, false),
                        aDrawRegion);
   if (!aVisibleRegion->Contains(newVisibleRegion)) {
     if (aIsSolidColorInVisibleRegion) {
       *aIsSolidColorInVisibleRegion = false;
     }
     *aVisibleRegion = newVisibleRegion;
   }
 }
@@ -1839,17 +1848,18 @@ ContainerState::PopThebesLayerData()
 
   AdjustLayerDataForFixedPositioning(data->mFixedPosFrameForLayerData,
                                      data->mDrawRegion,
                                      &data->mVisibleRegion,
                                      &data->mIsSolidColorInVisibleRegion);
   nsRefPtr<Layer> layer;
   nsRefPtr<ImageContainer> imageContainer = data->CanOptimizeImageLayer(mBuilder);
 
-  if ((data->mIsSolidColorInVisibleRegion || imageContainer) &&
+  bool isRetained = data->mLayer->Manager()->IsWidgetLayerManager();
+  if (isRetained && (data->mIsSolidColorInVisibleRegion || imageContainer) &&
       (data->mLayer->GetValidRegion().IsEmpty() || mLayerBuilder->CheckInLayerTreeCompressionMode())) {
     NS_ASSERTION(!(data->mIsSolidColorInVisibleRegion && imageContainer),
                  "Can't be a solid color as well as an image!");
     if (imageContainer) {
       nsRefPtr<ImageLayer> imageLayer = CreateOrRecycleImageLayer(data->mLayer);
       imageLayer->SetContainer(imageContainer);
       data->mImage->ConfigureLayer(imageLayer, mParameters.mOffset);
       imageLayer->SetPostScale(mParameters.mXScale,
@@ -2059,16 +2069,17 @@ ThebesLayerData::Accumulate(ContainerSta
    * we are the first visible item in the ThebesLayerData object.
    */
   if (mVisibleRegion.IsEmpty() &&
       aItem->SupportsOptimizingToImage()) {
     mImage = static_cast<nsDisplayImageContainer*>(aItem);
   } else {
     mImage = nullptr;
   }
+  bool clipMatches = mItemClip == aClip;
   mItemClip = aClip;
 
   if (!mIsSolidColorInVisibleRegion && mOpaqueRegion.Contains(aDrawRect) &&
       mVisibleRegion.Contains(aVisibleRect)) {
     // A very common case! Most pages have a ThebesLayer with the page
     // background (opaque) visible and most or all of the page content over the
     // top of that background.
     // The rest of this method won't do anything. mVisibleRegion, mOpaqueRegion
@@ -2092,23 +2103,24 @@ ThebesLayerData::Accumulate(ContainerSta
     // pixel-aligned (thus the item will not be truly uniform).
     if (isUniform) {
       bool snap;
       nsRect bounds = aItem->GetBounds(aState->mBuilder, &snap);
       if (!aState->ScaleToInsidePixels(bounds, snap).Contains(aVisibleRect)) {
         isUniform = false;
       }
     }
-    if (isUniform && aClip.GetRoundedRectCount() == 0) {
+    if (isUniform) {
       if (mVisibleRegion.IsEmpty()) {
         // This color is all we have
         mSolidColor = uniformColor;
         mIsSolidColorInVisibleRegion = true;
       } else if (mIsSolidColorInVisibleRegion &&
-                 mVisibleRegion.IsEqual(nsIntRegion(aVisibleRect))) {
+                 mVisibleRegion.IsEqual(nsIntRegion(aVisibleRect)) &&
+                 clipMatches) {
         // we can just blend the colors together
         mSolidColor = NS_ComposeColors(mSolidColor, uniformColor);
       } else {
         mIsSolidColorInVisibleRegion = false;
       }
     } else {
       mIsSolidColorInVisibleRegion = false;
     }
--- a/layout/base/RestyleManager.cpp
+++ b/layout/base/RestyleManager.cpp
@@ -303,31 +303,31 @@ RestyleManager::RecomputePosition(nsIFra
 {
   // Don't process position changes on table frames, since we already handle
   // the dynamic position change on the outer table frame, and the reflow-based
   // fallback code path also ignores positions on inner table frames.
   if (aFrame->GetType() == nsGkAtoms::tableFrame) {
     return true;
   }
 
+  const nsStyleDisplay* display = aFrame->StyleDisplay();
+  // Changes to the offsets of a non-positioned element can safely be ignored.
+  if (display->mPosition == NS_STYLE_POSITION_STATIC) {
+    return true;
+  }
+
   // Don't process position changes on frames which have views or the ones which
   // have a view somewhere in their descendants, because the corresponding view
   // needs to be repositioned properly as well.
   if (aFrame->HasView() ||
       (aFrame->GetStateBits() & NS_FRAME_HAS_CHILD_WITH_VIEW)) {
     StyleChangeReflow(aFrame, nsChangeHint_NeedReflow);
     return false;
   }
 
-  const nsStyleDisplay* display = aFrame->StyleDisplay();
-  // Changes to the offsets of a non-positioned element can safely be ignored.
-  if (display->mPosition == NS_STYLE_POSITION_STATIC) {
-    return true;
-  }
-
   aFrame->SchedulePaint();
 
   // For relative positioning, we can simply update the frame rect
   if (display->IsRelativelyPositionedStyle()) {
     if (display->IsInnerTableStyle()) {
       // We don't currently support relative positioning of inner table
       // elements (bug 35168).  If we apply offsets to things we haven't
       // previously offset, we'll get confused.  So bail.
--- a/layout/base/crashtests/crashtests.list
+++ b/layout/base/crashtests/crashtests.list
@@ -307,22 +307,22 @@ load 492112-1.xhtml
 load 492163-1.xhtml
 load 495350-1.html
 load 496011-1.xhtml
 load 497519-1.xhtml
 load 497519-2.xhtml
 load 499741-1.xhtml
 load 499841-1.xhtml
 load 499858-1.xhtml
-load 500467-1.html
+skip-if(Android&&AndroidVersion==10) load 500467-1.html # bug 978254
 load 501878-1.html
 load 503936-1.html
 load 507119.html
 load 514104-1.xul
-load 522374-1.html
+skip-if(Android&&AndroidVersion==10) load 522374-1.html # bug 978265
 load 522374-2.html
 load 526378-1.xul
 load 534367-1.xhtml
 load 534368-1.xhtml
 load 534768-1.html
 load 534768-2.html
 load 535721-1.xhtml
 load 535911-1.xhtml
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -535,20 +535,28 @@ static void MarkFrameForDisplay(nsIFrame
   }
 }
 
 void nsDisplayListBuilder::MarkOutOfFlowFrameForDisplay(nsIFrame* aDirtyFrame,
                                                         nsIFrame* aFrame,
                                                         const nsRect& aDirtyRect)
 {
   nsRect dirtyRectRelativeToDirtyFrame = aDirtyRect;
-  nsRect displayPort;
-  if (nsLayoutUtils::IsFixedPosFrameInDisplayPort(aFrame, &displayPort)) {
+  if (nsLayoutUtils::IsFixedPosFrameInDisplayPort(aFrame)) {
     NS_ASSERTION(aDirtyFrame == aFrame->GetParent(), "Dirty frame should be viewport frame");
-    dirtyRectRelativeToDirtyFrame = displayPort;
+    // position: fixed items are reflowed into and only drawn inside the
+    // viewport, or the scroll position clamping scrollport size, if one is
+    // set.
+    nsIPresShell* ps = aFrame->PresContext()->PresShell();
+    dirtyRectRelativeToDirtyFrame.MoveTo(0, 0);
+    if (ps->IsScrollPositionClampingScrollPortSizeSet()) {
+      dirtyRectRelativeToDirtyFrame.SizeTo(ps->GetScrollPositionClampingScrollPortSize());
+    } else {
+      dirtyRectRelativeToDirtyFrame.SizeTo(aDirtyFrame->GetSize());
+    }
   }
 
   nsRect dirty = dirtyRectRelativeToDirtyFrame - aFrame->GetOffsetTo(aDirtyFrame);
   nsRect overflowRect = aFrame->GetVisualOverflowRect();
 
   if (aFrame->IsTransformed() &&
       nsLayoutUtils::HasAnimationsForCompositor(aFrame->GetContent(),
                                                 eCSSProperty_transform)) {
@@ -1099,17 +1107,17 @@ nsDisplayList::ComputeVisibilityForSubli
         forceTransparentSurface = true;
       }
     }
     AppendToBottom(item);
   }
 
   mIsOpaque = !aVisibleRegion->Intersects(mVisibleRect);
   mForceTransparentSurface = forceTransparentSurface;
-#ifdef DEBUG
+#if defined(DEBUG) || defined(MOZ_DUMP_PAINTING)
   mDidComputeVisibility = true;
 #endif
   return anyVisible;
 }
 
 void nsDisplayList::PaintRoot(nsDisplayListBuilder* aBuilder,
                               nsRenderingContext* aCtx,
                               uint32_t aFlags) const {
--- a/layout/base/nsDisplayList.h
+++ b/layout/base/nsDisplayList.h
@@ -1285,17 +1285,17 @@ public:
   /**
    * Create an empty list.
    */
   nsDisplayList() :
     mIsOpaque(false)
   {
     mTop = &mSentinel;
     mSentinel.mAbove = nullptr;
-#ifdef DEBUG
+#if defined(DEBUG) || defined(MOZ_DUMP_PAINTING)
     mDidComputeVisibility = false;
 #endif
   }
   ~nsDisplayList() {
     if (mSentinel.mAbove) {
       NS_WARNING("Nonempty list left over?");
     }
     DeleteAll();
@@ -1535,17 +1535,17 @@ public:
   /**
    * Find the topmost display item that returns a non-null frame, and return
    * the frame.
    */
   void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
                nsDisplayItem::HitTestState* aState,
                nsTArray<nsIFrame*> *aOutFrames) const;
 
-#ifdef DEBUG
+#if defined(DEBUG) || defined(MOZ_DUMP_PAINTING)
   bool DidComputeVisibility() const { return mDidComputeVisibility; }
 #endif
 
   nsRect GetVisibleRect() const { return mVisibleRect; }
 
 private:
   // This class is only used on stack, so we don't have to worry about leaking
   // it.  Don't let us be heap-allocated!
@@ -1561,17 +1561,17 @@ private:
   nsRect mVisibleRect;
   // This is set to true by ComputeVisibility if the final visible region
   // is empty (i.e. everything that was visible is covered by some
   // opaque content in this list).
   bool mIsOpaque;
   // This is set to true by ComputeVisibility if any display item in this
   // list needs to force the surface containing this list to be transparent.
   bool mForceTransparentSurface;
-#ifdef DEBUG
+#if defined(DEBUG) || defined(MOZ_DUMP_PAINTING)
   bool mDidComputeVisibility;
 #endif
 };
 
 /**
  * This is passed as a parameter to nsIFrame::BuildDisplayList. That method
  * will put any generated items onto the appropriate list given here. It's
  * basically just a collection with one list for each separate stacking layer.
--- a/layout/base/nsDocumentViewer.cpp
+++ b/layout/base/nsDocumentViewer.cpp
@@ -678,17 +678,17 @@ nsDocumentViewer::InitPresentationStuff(
   int32_t p2a = mPresContext->AppUnitsPerDevPixel();
   MOZ_ASSERT(p2a == mPresContext->DeviceContext()->UnscaledAppUnitsPerDevPixel());
   nscoord width = p2a * mBounds.width;
   nscoord height = p2a * mBounds.height;
 
   mViewManager->SetWindowDimensions(width, height);
   mPresContext->SetTextZoom(mTextZoom);
   mPresContext->SetFullZoom(mPageZoom);
-  mPresContext->SetMinFontSize(mMinFontSize);
+  mPresContext->SetBaseMinFontSize(mMinFontSize);
 
   p2a = mPresContext->AppUnitsPerDevPixel();  // zoom may have changed it
   width = p2a * mBounds.width;
   height = p2a * mBounds.height;
   if (aDoInitialReflow) {
     nsCOMPtr<nsIPresShell> shellGrip = mPresShell;
     // Initial reflow
     mPresShell->Initialize(width, height);
@@ -2800,17 +2800,17 @@ SetExtResourceTextZoom(nsIDocument* aDoc
 
 static bool
 SetExtResourceMinFontSize(nsIDocument* aDocument, void* aClosure)
 {
   nsIPresShell* shell = aDocument->GetShell();
   if (shell) {
     nsPresContext* ctxt = shell->GetPresContext();
     if (ctxt) {
-      ctxt->SetMinFontSize(NS_PTR_TO_INT32(aClosure));
+      ctxt->SetBaseMinFontSize(NS_PTR_TO_INT32(aClosure));
     }
   }
 
   return true;
 }
 
 static bool
 SetExtResourceFullZoom(nsIDocument* aDocument, void* aClosure)
@@ -2892,32 +2892,32 @@ nsDocumentViewer::SetMinFontSize(int32_t
   // change, our children's min font may be different, though it would be unusual).
   // Do this first, in case kids are auto-sizing and post reflow commands on
   // our presshell (which should be subsumed into our own style change reflow).
   CallChildren(SetChildMinFontSize, NS_INT32_TO_PTR(aMinFontSize));
 
   // Now change our own min font
   nsPresContext* pc = GetPresContext();
   if (pc && aMinFontSize != mPresContext->MinFontSize(nullptr)) {
-    pc->SetMinFontSize(aMinFontSize);
+    pc->SetBaseMinFontSize(aMinFontSize);
   }
 
   // And do the external resources
   mDocument->EnumerateExternalResources(SetExtResourceMinFontSize,
                                         NS_INT32_TO_PTR(aMinFontSize));
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDocumentViewer::GetMinFontSize(int32_t* aMinFontSize)
 {
   NS_ENSURE_ARG_POINTER(aMinFontSize);
   nsPresContext* pc = GetPresContext();
-  *aMinFontSize = pc ? pc->MinFontSize(nullptr) : 0;
+  *aMinFontSize = pc ? pc->BaseMinFontSize() : 0;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDocumentViewer::SetFullZoom(float aFullZoom)
 {
 #ifdef NS_PRINT_PREVIEW
   if (GetIsPrintPreview()) {
--- a/layout/base/nsLayoutDebugger.cpp
+++ b/layout/base/nsLayoutDebugger.cpp
@@ -132,32 +132,30 @@ PrintDisplayItemTo(nsDisplayListBuilder*
   nsCString str;
   if (!aDumpHtml) {
     for (uint32_t indent = 0; indent < aIndent; indent++) {
       str += "  ";
     }
   }
   nsIFrame* f = aItem->Frame();
   nsAutoString fName;
-#ifdef DEBUG
+#ifdef DEBUG_FRAME_DUMP
   f->GetFrameName(fName);
 #endif
   bool snap;
   nsRect rect = aItem->GetBounds(aBuilder, &snap);
   nscolor color;
   nsRect vis = aItem->GetVisibleRect();
   nsRect component = aItem->GetComponentAlphaBounds(aBuilder);
   nsDisplayList* list = aItem->GetChildren();
   const DisplayItemClip& clip = aItem->GetClip();
   nsRegion opaque;
-#ifdef DEBUG
   if (!list || list->DidComputeVisibility()) {
     opaque = aItem->GetOpaqueRegion(aBuilder, &snap);
   }
-#endif
   if (aDumpHtml && aItem->Painted()) {
     nsCString string(aItem->Name());
     string.Append("-");
     string.AppendInt((uint64_t)aItem);
     str += nsPrintfCString("<a href=\"javascript:ViewImage('%s')\">", string.BeginReading());
   }
   str += nsPrintfCString("%s %p(%s) bounds(%d,%d,%d,%d) visible(%d,%d,%d,%d) componentAlpha(%d,%d,%d,%d) clip(%s) %s",
           aItem->Name(), (void*)f, NS_ConvertUTF16toUTF8(fName).get(),
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -2070,39 +2070,39 @@ nsLayoutUtils::TranslateWidgetToView(nsP
   }
 
   nsPoint widgetAppUnits(aPresContext->DevPixelsToAppUnits(widgetPoint.x),
                          aPresContext->DevPixelsToAppUnits(widgetPoint.y));
   return widgetAppUnits - viewOffset;
 }
 
 // Combine aNewBreakType with aOrigBreakType, but limit the break types
-// to NS_STYLE_CLEAR_LEFT, RIGHT, LEFT_AND_RIGHT.
+// to NS_STYLE_CLEAR_LEFT, RIGHT, BOTH.
 uint8_t
 nsLayoutUtils::CombineBreakType(uint8_t aOrigBreakType,
                                 uint8_t aNewBreakType)
 {
   uint8_t breakType = aOrigBreakType;
   switch(breakType) {
   case NS_STYLE_CLEAR_LEFT:
-    if ((NS_STYLE_CLEAR_RIGHT          == aNewBreakType) ||
-        (NS_STYLE_CLEAR_LEFT_AND_RIGHT == aNewBreakType)) {
-      breakType = NS_STYLE_CLEAR_LEFT_AND_RIGHT;
+    if (NS_STYLE_CLEAR_RIGHT == aNewBreakType ||
+        NS_STYLE_CLEAR_BOTH == aNewBreakType) {
+      breakType = NS_STYLE_CLEAR_BOTH;
     }
     break;
   case NS_STYLE_CLEAR_RIGHT:
-    if ((NS_STYLE_CLEAR_LEFT           == aNewBreakType) ||
-        (NS_STYLE_CLEAR_LEFT_AND_RIGHT == aNewBreakType)) {
-      breakType = NS_STYLE_CLEAR_LEFT_AND_RIGHT;
+    if (NS_STYLE_CLEAR_LEFT == aNewBreakType ||
+        NS_STYLE_CLEAR_BOTH == aNewBreakType) {
+      breakType = NS_STYLE_CLEAR_BOTH;
     }
     break;
   case NS_STYLE_CLEAR_NONE:
-    if ((NS_STYLE_CLEAR_LEFT           == aNewBreakType) ||
-        (NS_STYLE_CLEAR_RIGHT          == aNewBreakType) ||
-        (NS_STYLE_CLEAR_LEFT_AND_RIGHT == aNewBreakType)) {
+    if (NS_STYLE_CLEAR_LEFT == aNewBreakType ||
+        NS_STYLE_CLEAR_RIGHT == aNewBreakType ||
+        NS_STYLE_CLEAR_BOTH == aNewBreakType) {
       breakType = aNewBreakType;
     }
   }
   return breakType;
 }
 
 #ifdef MOZ_DUMP_PAINTING
 #include <stdio.h>
--- a/layout/base/nsPresContext.cpp
+++ b/layout/base/nsPresContext.cpp
@@ -241,17 +241,17 @@ IsVisualCharset(const nsCString& aCharse
   }
 }
 #endif // IBMBIDI
 
   // NOTE! nsPresContext::operator new() zeroes out all members, so don't
   // bother initializing members to 0.
 
 nsPresContext::nsPresContext(nsIDocument* aDocument, nsPresContextType aType)
-  : mType(aType), mDocument(aDocument), mMinFontSize(0),
+  : mType(aType), mDocument(aDocument), mBaseMinFontSize(0),
     mTextZoom(1.0), mFullZoom(1.0), mLastFontInflationScreenWidth(-1.0),
     mPageSize(-1, -1), mPPScale(1.0f),
     mViewportStyleOverflow(NS_STYLE_OVERFLOW_AUTO, NS_STYLE_OVERFLOW_AUTO),
     mImageAnimationModePref(imgIContainer::kNormalAnimMode),
     mAllInvalidated(false),
     mPaintFlashing(false), mPaintFlashingInitialized(false)
 {
   // NOTE! nsPresContext::operator new() zeroes out all members, so don't
--- a/layout/base/nsPresContext.h
+++ b/layout/base/nsPresContext.h
@@ -530,28 +530,42 @@ public:
       // Media queries could have changed, since we changed the meaning
       // of 'em' units in them.
       MediaFeatureValuesChanged(eAlwaysRebuildStyle, NS_STYLE_HINT_REFLOW);
     }
   }
 
   /**
    * Get the minimum font size for the specified language. If aLanguage
-   * is nullptr, then the document's language is used.
+   * is nullptr, then the document's language is used.  This combines
+   * the language-specific global preference with the per-presentation
+   * base minimum font size.
    */
   int32_t MinFontSize(nsIAtom *aLanguage) const {
     const LangGroupFontPrefs *prefs = GetFontPrefsForLang(aLanguage);
-    return std::max(mMinFontSize, prefs->mMinimumFontSize);
+    return std::max(mBaseMinFontSize, prefs->mMinimumFontSize);
   }
-
-  void SetMinFontSize(int32_t aMinFontSize) {
-    if (aMinFontSize == mMinFontSize)
+  
+  /**
+   * Get the per-presentation base minimum font size.  This size is
+   * independent of the language-specific global preference.
+   */
+  int32_t BaseMinFontSize() const {
+    return mBaseMinFontSize;
+  }
+  
+  /**
+   * Set the per-presentation base minimum font size.  This size is
+   * independent of the language-specific global preference.
+   */
+  void SetBaseMinFontSize(int32_t aMinFontSize) {
+    if (aMinFontSize == mBaseMinFontSize)
       return;
 
-    mMinFontSize = aMinFontSize;
+    mBaseMinFontSize = aMinFontSize;
     if (HasCachedStyleData()) {
       // Media queries could have changed, since we changed the meaning
       // of 'em' units in them.
       MediaFeatureValuesChanged(eAlwaysRebuildStyle, NS_STYLE_HINT_REFLOW);
     }
   }
 
   float GetFullZoom() { return mFullZoom; }
@@ -1174,17 +1188,18 @@ public:
   bool                  mInflationDisabledForShrinkWrap;
 
 protected:
 
   mozilla::WeakPtr<nsDocShell>             mContainer;
 
   PRCList               mDOMMediaQueryLists;
 
-  int32_t               mMinFontSize;   // Min font size, defaults to 0
+  // Base minimum font size, independent of the language-specific global preference. Defaults to 0
+  int32_t               mBaseMinFontSize;
   float                 mTextZoom;      // Text zoom, defaults to 1.0
   float                 mFullZoom;      // Page zoom, defaults to 1.0
 
   float                 mLastFontInflationScreenWidth;
 
   int32_t               mCurAppUnitsPerDevPixel;
   int32_t               mAutoQualityMinFontSizePixelsPref;
 
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -5258,21 +5258,16 @@ void PresShell::SetIgnoreViewportScrolli
     return;
   }
   RenderingState state(this);
   state.mRenderFlags = ChangeFlag(state.mRenderFlags, aIgnore,
                                   STATE_IGNORING_VIEWPORT_SCROLLING);
   SetRenderingState(state);
 }
 
-void PresShell::SetDisplayPort(const nsRect& aDisplayPort)
-{
-  NS_ABORT_IF_FALSE(false, "SetDisplayPort is deprecated");
-}
-
 nsresult PresShell::SetResolution(float aXResolution, float aYResolution)
 {
   if (!(aXResolution > 0.0 && aYResolution > 0.0)) {
     return NS_ERROR_ILLEGAL_VALUE;
   }
   if (aXResolution == mXResolution && aYResolution == mYResolution) {
     return NS_OK;
   }
--- a/layout/base/nsPresShell.h
+++ b/layout/base/nsPresShell.h
@@ -174,18 +174,16 @@ public:
                   nsIntRect* aScreenRect) MOZ_OVERRIDE;
 
   virtual already_AddRefed<nsPIDOMWindow> GetRootWindow() MOZ_OVERRIDE;
 
   virtual LayerManager* GetLayerManager() MOZ_OVERRIDE;
 
   virtual void SetIgnoreViewportScrolling(bool aIgnore) MOZ_OVERRIDE;
 
-  virtual void SetDisplayPort(const nsRect& aDisplayPort);
-
   virtual nsresult SetResolution(float aXResolution, float aYResolution) MOZ_OVERRIDE;
   virtual gfxSize GetCumulativeResolution() MOZ_OVERRIDE;
 
   //nsIViewObserver interface
 
   virtual void Paint(nsView* aViewToPaint, const nsRegion& aDirtyRegion,
                      uint32_t aFlags) MOZ_OVERRIDE;
   virtual nsresult HandleEvent(nsIFrame* aFrame,
new file mode 100644
--- /dev/null
+++ b/layout/base/tests/bug687297_a.html
@@ -0,0 +1,17 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+  <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+  <title>Test companion for Bug 687297</title>
+  <style type="text/css"> * { font-size:9px; } </style>
+</head>
+<body>
+  <div id="test_content">ABCDEFG 0123456</div>
+</body>
+<script type="application/javascript">
+  window.onload = function() {
+    opener.report_size_a(document.getElementById("test_content").clientHeight);
+    window.location.href = "bug687297_b.html";
+  };
+</script>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/base/tests/bug687297_b.html
@@ -0,0 +1,17 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+  <meta http-equiv="Content-Type" content="text/html; charset=Shift_JIS">
+  <title>Test companion for Bug 687297</title>
+  <style type="text/css"> * { font-size:9px; } </style>
+</head>
+<body>
+  <div id="test_content">ABCDEFG 0123456</div>
+</body>
+<script type="application/javascript">
+  window.onload = function() {
+    opener.report_size_b(document.getElementById("test_content").clientHeight);
+    window.location.href = "bug687297_c.html";
+  };
+</script>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/base/tests/bug687297_c.html
@@ -0,0 +1,17 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+  <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+  <title>Test companion for Bug 687297</title>
+  <style type="text/css"> * { font-size:9px; } </style>
+</head>
+<body>
+  <div id="test_content">ABCDEFG 0123456</div>
+</body>
+<script type="application/javascript">
+  window.onload = function() {
+    opener.report_size_c(document.getElementById("test_content").clientHeight);
+    window.close();
+  };
+</script>
+</html>
--- a/layout/base/tests/mochitest.ini
+++ b/layout/base/tests/mochitest.ini
@@ -448,8 +448,13 @@ skip-if = toolkit == "win"
 [test_bug570378-persian-5g.html]
 skip-if = toolkit == "win"
 [test_bug749186.html]
 skip-if = toolkit == "win"
 [test_bug644768.html]
 skip-if = toolkit == "win"
 [test_flush_on_paint.html]
 skip-if = true || (toolkit == 'android') || (toolkit == "cocoa") # Bug 688128, bug 539356
+[test_bug687297.html]
+support-files =
+  bug687297_a.html
+  bug687297_b.html
+  bug687297_c.html
new file mode 100644
--- /dev/null
+++ b/layout/base/tests/test_bug687297.html
@@ -0,0 +1,54 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=687297
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 687297</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="/tests/SimpleTest/SpecialPowers.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=687297">Mozilla Bug 687297</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+  <script class="testbody" type="text/javascript">
+    /** Test for Bug 687297 **/
+    
+    SimpleTest.waitForExplicitFinish();
+  
+    var size_a=0, size_b=0, size_c=0;
+    
+    window.report_size_a = function(s) {
+      size_a = s;
+    };
+  
+    window.report_size_b = function(s) {
+      size_b = s;
+    };
+  
+    window.report_size_c = function(s) {
+      size_c = s;
+      
+      isnot(size_a, size_b, "Font sizes are changing with global language-specific minimum font size");
+      is(size_c, size_a, "Font sizes are equal, propagating only the presentation-level base minimum font size");
+
+      SimpleTest.finish();
+    };
+  
+    SpecialPowers.pushPrefEnv(
+      {'set':[["font.minimum-size.ja", 120]]},
+      function() {
+        window.open("bug687297_a.html", '_blank');
+      }
+    );
+  
+  </script>
+</pre>
+</body>
+</html>
--- a/layout/forms/nsColorControlFrame.cpp
+++ b/layout/forms/nsColorControlFrame.cpp
@@ -26,16 +26,17 @@ nsIFrame*
 NS_NewColorControlFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
 {
   return new (aPresShell) nsColorControlFrame(aContext);
 }
 
 NS_IMPL_FRAMEARENA_HELPERS(nsColorControlFrame)
 
 NS_QUERYFRAME_HEAD(nsColorControlFrame)
+  NS_QUERYFRAME_ENTRY(nsColorControlFrame)
   NS_QUERYFRAME_ENTRY(nsIAnonymousContentCreator)
 NS_QUERYFRAME_TAIL_INHERITING(nsColorControlFrameSuper)
 
 
 void nsColorControlFrame::DestroyFrom(nsIFrame* aDestructRoot)
 {
   nsFormControlFrame::RegUnRegAccessKey(static_cast<nsIFrame*>(this), false);
   nsContentUtils::DestroyAnonymousContent(&mColorContent);
--- a/layout/forms/nsColorControlFrame.h
+++ b/layout/forms/nsColorControlFrame.h
@@ -20,18 +20,19 @@ class nsColorControlFrame MOZ_FINAL : pu
   typedef mozilla::dom::Element Element;
 
 public:
   friend nsIFrame* NS_NewColorControlFrame(nsIPresShell* aPresShell,
                                            nsStyleContext* aContext);
 
   virtual void DestroyFrom(nsIFrame* aDestructRoot) MOZ_OVERRIDE;
 
+  NS_DECL_QUERYFRAME_TARGET(nsColorControlFrame)
+  NS_DECL_QUERYFRAME
   NS_DECL_FRAMEARENA_HELPERS
-  NS_DECL_QUERYFRAME
 
   virtual nsIAtom* GetType() const MOZ_OVERRIDE;
 
 #ifdef DEBUG_FRAME_DUMP
   virtual nsresult GetFrameName(nsAString& aResult) const MOZ_OVERRIDE;
 #endif
 
   // nsIAnonymousContentCreator
@@ -43,19 +44,19 @@ public:
   virtual nsresult AttributeChanged(int32_t  aNameSpaceID,
                                     nsIAtom* aAttribute,
                                     int32_t  aModType) MOZ_OVERRIDE;
   virtual bool IsLeaf() const MOZ_OVERRIDE { return true; }
   virtual nsIFrame* GetContentInsertionFrame() MOZ_OVERRIDE;
 
   virtual Element* GetPseudoElement(nsCSSPseudoElements::Type aType) MOZ_OVERRIDE;
 
+  // Refresh the color swatch, using associated input's value
+  nsresult UpdateColor();
+
 private:
   nsColorControlFrame(nsStyleContext* aContext);
 
-  // Update the color swatch
-  nsresult UpdateColor();
-
   nsCOMPtr<Element> mColorContent;
 };
 
 
 #endif // nsColorControlFrame_h___
new file mode 100644
--- /dev/null
+++ b/layout/generic/crashtests/513110-1.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script type="text/javascript">
+
+function boom()
+{
+  var s = document.getElementById("s");
+  document.body.removeChild(s);
+  document.body.appendChild(s);  
+}
+
+window.addEventListener("load", boom, false);
+
+</script>
+</head>
+
+<body>
+<span style="word-spacing: -379660px">a </span>
+<span id="s"><br style="clear: both;"/></span>
+</body>
+  
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/generic/crashtests/513110-2.xhtml
@@ -0,0 +1,5 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<body style="width: 1px;" onload="document.documentElement.offsetHeight; document.getElementById('x').style.display = 'table-footer-group';">
+<span>1</span> <br id="x" style="clear: both;" />
+</body>
+</html>
--- a/layout/generic/crashtests/crashtests.list
+++ b/layout/generic/crashtests/crashtests.list
@@ -100,17 +100,17 @@ load 373859-1.html
 load 373868-1.xhtml
 load 374090.html
 load 374420.xhtml
 load 375462-1.html
 load 375831.html
 load 376419.html
 load 377522.html
 load 379217-1.xhtml
-asserts(1-2) load 379217-2.xhtml # Bug 439204
+load 379217-2.xhtml
 load 379917-1.xhtml
 load 380012-1.html
 load 381152-1.html
 load 381786-1.html
 asserts-if(gtk2Widget,0-2) load 382129-1.xhtml # Bug 540078
 asserts-if(gtk2Widget,0-1) load 382131-1.html # Bug 540078
 load 382199-1.html
 load 382208-1.xhtml
@@ -120,17 +120,17 @@ load 382745-1.xhtml
 load 383089-1.html
 load 385265-1.xhtml
 load 385295-1.xhtml
 load 385344-1.html
 load 385344-2.html
 load 385414-1.html
 load 385414-2.html
 load 385426-1.html
-skip-if(B2G) load 385526.html # Bug 891347
+skip-if(B2G) skip-if(Android&&AndroidVersion==10) load 385526.html # Bug 891347
 load 385681.html
 load 385885-1.xul
 load 386799-1.html
 load 386807-1.html
 load 386812-1.html
 load 386827-1.html
 load 387058-1.html
 load 387058-2.html
@@ -363,16 +363,18 @@ load 508168-1.html
 load 508816-1.xul
 load 508908-1.html
 load 505912-1.html
 load 509749-1.html
 load 511482.html
 load 512724-1.html
 load 512725-1.html
 load 512749-1.html
+load 513110-1.html
+load 513110-2.xhtml
 load 513394-1.html
 load 514098-1.xhtml
 load 514800-1.html
 load 515811-1.html
 load 517968.html
 load 519031.xhtml
 load 520340.html
 load 522170-1.html
@@ -518,8 +520,9 @@ asserts(1-4) load 876074-1.html # bug 87
 load 885009-1.html
 load 893496-1.html
 load 893523.html
 test-pref(layout.css.sticky.enabled,true) load 914891.html
 test-pref(layout.css.sticky.enabled,true) load 915475.xhtml
 load 943509-1.html
 asserts(4-8) load 944909-1.html
 test-pref(layout.css.sticky.enabled,true) load 949932.html
+load outline-on-frameset.xhtml
new file mode 100644
--- /dev/null
+++ b/layout/generic/crashtests/outline-on-frameset.xhtml
@@ -0,0 +1,1 @@
+<html xmlns="http://www.w3.org/1999/xhtml"><frameset style="outline-style: solid;"></frameset></html>
--- a/layout/generic/nsBlockFrame.cpp
+++ b/layout/generic/nsBlockFrame.cpp
@@ -1380,17 +1380,17 @@ nsBlockFrame::ComputeFinalSize(const nsH
         std::min(bottomEdgeOfChildren + aState.mPrevBottomMargin.get(),
                aState.mReflowState.AvailableHeight());
     }
   }
   if (aState.GetFlag(BRS_FLOAT_MGR)) {
     // Include the float manager's state to properly account for the
     // bottom margin of any floated elements; e.g., inside a table cell.
     nscoord floatHeight =
-      aState.ClearFloats(bottomEdgeOfChildren, NS_STYLE_CLEAR_LEFT_AND_RIGHT,
+      aState.ClearFloats(bottomEdgeOfChildren, NS_STYLE_CLEAR_BOTH,
                          nullptr, nsFloatManager::DONT_CLEAR_PUSHED_FLOATS);
     bottomEdgeOfChildren = std::max(bottomEdgeOfChildren, floatHeight);
   }
 
   if (NS_UNCONSTRAINEDSIZE != aReflowState.ComputedHeight()
       && (mParent->GetType() != nsGkAtoms::columnSetFrame ||
           aReflowState.parentReflowState->AvailableHeight() == NS_UNCONSTRAINEDSIZE)) {
     ComputeFinalHeight(aReflowState, &aState.mReflowStatus,
@@ -3751,17 +3751,17 @@ nsBlockFrame::ReflowInlineFrame(nsBlockR
     // Always abort the line reflow (because a line break is the
     // minimal amount of break we do).
     *aLineReflowStatus = LINE_REFLOW_STOP;
 
     // XXX what should aLine's break-type be set to in all these cases?
     uint8_t breakType = NS_INLINE_GET_BREAK_TYPE(frameReflowStatus);
     NS_ASSERTION((NS_STYLE_CLEAR_NONE != breakType) || 
                  (NS_STYLE_CLEAR_NONE != aState.mFloatBreakType), "bad break type");
-    NS_ASSERTION(NS_STYLE_CLEAR_LAST_VALUE >= breakType, "invalid break type");
+    NS_ASSERTION(NS_STYLE_CLEAR_MAX >= breakType, "invalid break type");
 
     if (NS_INLINE_IS_BREAK_BEFORE(frameReflowStatus)) {
       // Break-before cases.
       if (aFrame == aLine->mFirstChild) {
         // If we break before the first frame on the line then we must
         // be trying to place content where there's no room (e.g. on a
         // line with wide floats). Inform the caller to reflow the
         // line after skipping past a float.
@@ -5973,17 +5973,17 @@ nsBlockFrame::ReflowPushedFloats(nsBlock
     // Always call FlowAndPlaceFloat; we might need to place this float
     // if didn't belong to this block the last time it was reflowed.
     aState.FlowAndPlaceFloat(f);
 
     ConsiderChildOverflow(aOverflowAreas, f);
   }
 
   // If there are continued floats, then we may need to continue BR clearance
-  if (0 != aState.ClearFloats(0, NS_STYLE_CLEAR_LEFT_AND_RIGHT)) {
+  if (0 != aState.ClearFloats(0, NS_STYLE_CLEAR_BOTH)) {
     aState.mFloatBreakType = static_cast<nsBlockFrame*>(GetPrevInFlow())
                                ->FindTrailingClear();
   }
 }
 
 void
 nsBlockFrame::RecoverFloats(nsFloatManager& aFloatManager)
 {
--- a/layout/generic/nsFloatManager.cpp
+++ b/layout/generic/nsFloatManager.cpp
@@ -450,17 +450,17 @@ nsFloatManager::ClearFloats(nscoord aY, 
   if (!HasAnyFloats()) {
     return aY;
   }
 
   nscoord bottom = aY + mY;
 
   const FloatInfo &tail = mFloats[mFloats.Length() - 1];
   switch (aBreakType) {
-    case NS_STYLE_CLEAR_LEFT_AND_RIGHT:
+    case NS_STYLE_CLEAR_BOTH:
       bottom = std::max(bottom, tail.mLeftYMost);
       bottom = std::max(bottom, tail.mRightYMost);
       break;
     case NS_STYLE_CLEAR_LEFT:
       bottom = std::max(bottom, tail.mLeftYMost);
       break;
     case NS_STYLE_CLEAR_RIGHT:
       bottom = std::max(bottom, tail.mRightYMost);
@@ -474,20 +474,20 @@ nsFloatManager::ClearFloats(nscoord aY, 
 
   return bottom;
 }
 
 bool
 nsFloatManager::ClearContinues(uint8_t aBreakType) const
 {
   return ((mPushedLeftFloatPastBreak || mSplitLeftFloatAcrossBreak) &&
-          (aBreakType == NS_STYLE_CLEAR_LEFT_AND_RIGHT ||
+          (aBreakType == NS_STYLE_CLEAR_BOTH ||
            aBreakType == NS_STYLE_CLEAR_LEFT)) ||
          ((mPushedRightFloatPastBreak || mSplitRightFloatAcrossBreak) &&
-          (aBreakType == NS_STYLE_CLEAR_LEFT_AND_RIGHT ||
+          (aBreakType == NS_STYLE_CLEAR_BOTH ||
            aBreakType == NS_STYLE_CLEAR_RIGHT));
 }
 
 /////////////////////////////////////////////////////////////////////////////
 // FloatInfo
 
 nsFloatManager::FloatInfo::FloatInfo(nsIFrame* aFrame, const nsRect& aRect)
   : mFrame(aFrame), mRect(aRect)
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -3799,17 +3799,17 @@ nsIFrame::InlinePrefWidthData::ForceBrea
             floats_cur_left = 0,
             floats_cur_right = 0;
 
     for (uint32_t i = 0, i_end = floats.Length(); i != i_end; ++i) {
       const FloatInfo& floatInfo = floats[i];
       const nsStyleDisplay *floatDisp = floatInfo.Frame()->StyleDisplay();
       if (floatDisp->mBreakType == NS_STYLE_CLEAR_LEFT ||
           floatDisp->mBreakType == NS_STYLE_CLEAR_RIGHT ||
-          floatDisp->mBreakType == NS_STYLE_CLEAR_LEFT_AND_RIGHT) {
+          floatDisp->mBreakType == NS_STYLE_CLEAR_BOTH) {
         nscoord floats_cur = NSCoordSaturatingAdd(floats_cur_left,
                                                   floats_cur_right);
         if (floats_cur > floats_done)
           floats_done = floats_cur;
         if (floatDisp->mBreakType != NS_STYLE_CLEAR_RIGHT)
           floats_cur_left = 0;
         if (floatDisp->mBreakType != NS_STYLE_CLEAR_LEFT)
           floats_cur_right = 0;
--- a/layout/generic/nsFrameList.h
+++ b/layout/generic/nsFrameList.h
@@ -4,17 +4,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsFrameList_h___
 #define nsFrameList_h___
 
 #include <stdio.h> /* for FILE* */
 #include "nsDebug.h"
 
-#ifdef DEBUG
+#if defined(DEBUG) || defined(MOZ_DUMP_PAINTING)
 // DEBUG_FRAME_DUMP enables nsIFrame::List and related methods.
 // You can also define this in a non-DEBUG build if you need frame dumps.
 #define DEBUG_FRAME_DUMP 1
 #endif
 
 class nsIFrame;
 class nsIPresShell;
 class nsPresContext;
--- a/layout/generic/nsFrameSetFrame.cpp
+++ b/layout/generic/nsFrameSetFrame.cpp
@@ -1132,16 +1132,17 @@ nsHTMLFramesetFrame::Reflow(nsPresContex
     mChildFrameborder = nullptr;
     mChildBorderColors = nullptr;
   }
 
   aStatus = NS_FRAME_COMPLETE;
   mDrag.UnSet();
 
   aDesiredSize.SetOverflowAreasToDesiredBounds();
+  FinishAndStoreOverflow(&aDesiredSize);
 
   NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
   return NS_OK;
 }
 
 nsIAtom*
 nsHTMLFramesetFrame::GetType() const
 {
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -2080,16 +2080,18 @@ ScrollFrameHelper::ScrollToImpl(nsPoint 
     return;
   }
   PostScrollEvent();
 
   // notify the listeners.
   for (uint32_t i = 0; i < mListeners.Length(); i++) {
     mListeners[i]->ScrollPositionDidChange(pt.x, pt.y);
   }
+
+  presContext->GetDocShell()->NotifyScrollObservers();
 }
 
 static void
 AppendToTop(nsDisplayListBuilder* aBuilder, nsDisplayList* aDest,
             nsDisplayList* aSource, nsIFrame* aSourceFrame, bool aOwnLayer,
             uint32_t aFlags, mozilla::layers::FrameMetrics::ViewID aScrollTargetId)
 {
   if (aSource->IsEmpty())
--- a/layout/generic/nsLineBox.cpp
+++ b/layout/generic/nsLineBox.cpp
@@ -38,17 +38,17 @@ nsLineBox::nsLineBox(nsIFrame* aFrame, i
   NS_ASSERTION(!aIsBlock || aCount == 1, "Blocks must have exactly one child");
   nsIFrame* f = aFrame;
   for (int32_t n = aCount; n > 0; f = f->GetNextSibling(), --n) {
     NS_ASSERTION(aIsBlock == f->IsBlockOutside(),
                  "wrong kind of child frame");
   }
 #endif
 
-  static_assert(NS_STYLE_CLEAR_LAST_VALUE <= 15,
+  static_assert(NS_STYLE_CLEAR_MAX <= 15,
                 "FlagBits needs more bits to store the full range of "
                 "break type ('clear') values");
 #if NS_STYLE_CLEAR_NONE > 0
   mFlags.mBreakType = NS_STYLE_CLEAR_NONE;
 #endif
   mChildCount = aCount;
   MarkDirty();
   mFlags.mBlock = aIsBlock;
@@ -192,17 +192,17 @@ ListFloats(FILE* out, const char* aPrefi
 
 const char *
 BreakTypeToString(uint8_t aBreakType)
 {
   switch (aBreakType) {
   case NS_STYLE_CLEAR_NONE: return "nobr";
   case NS_STYLE_CLEAR_LEFT: return "leftbr";
   case NS_STYLE_CLEAR_RIGHT: return "rightbr";
-  case NS_STYLE_CLEAR_LEFT_AND_RIGHT: return "leftbr+rightbr";
+  case NS_STYLE_CLEAR_BOTH: return "leftbr+rightbr";
   case NS_STYLE_CLEAR_LINE: return "linebr";
   default:
     break;
   }
   return "unknown";
 }
 
 char*
--- a/layout/generic/nsLineBox.h
+++ b/layout/generic/nsLineBox.h
@@ -394,17 +394,20 @@ public:
   // Break information is applied *before* the line if the line is a block,
   // or *after* the line if the line is an inline. Confusing, I know, but
   // using different names should help.
   bool HasBreakBefore() const {
     return IsBlock() && NS_STYLE_CLEAR_NONE != mFlags.mBreakType;
   }
   void SetBreakTypeBefore(uint8_t aBreakType) {
     NS_ASSERTION(IsBlock(), "Only blocks have break-before");
-    NS_ASSERTION(aBreakType <= NS_STYLE_CLEAR_LEFT_AND_RIGHT,
+    NS_ASSERTION(aBreakType == NS_STYLE_CLEAR_NONE ||
+                 aBreakType == NS_STYLE_CLEAR_LEFT ||
+                 aBreakType == NS_STYLE_CLEAR_RIGHT ||
+                 aBreakType == NS_STYLE_CLEAR_BOTH,
                  "Only float break types are allowed before a line");
     mFlags.mBreakType = aBreakType;
   }
   uint8_t GetBreakTypeBefore() const {
     return IsBlock() ? mFlags.mBreakType : NS_STYLE_CLEAR_NONE;
   }
 
   bool HasBreakAfter() const {
@@ -413,17 +416,17 @@ public:
   void SetBreakTypeAfter(uint8_t aBreakType) {
     NS_ASSERTION(!IsBlock(), "Only inlines have break-after");
     NS_ASSERTION(aBreakType <= LINE_MAX_BREAK_TYPE, "bad break type");
     mFlags.mBreakType = aBreakType;
   }
   bool HasFloatBreakAfter() const {
     return !IsBlock() && (NS_STYLE_CLEAR_LEFT == mFlags.mBreakType ||
                           NS_STYLE_CLEAR_RIGHT == mFlags.mBreakType ||
-                          NS_STYLE_CLEAR_LEFT_AND_RIGHT == mFlags.mBreakType);
+                          NS_STYLE_CLEAR_BOTH == mFlags.mBreakType);
   }
   uint8_t GetBreakTypeAfter() const {
     return !IsBlock() ? mFlags.mBreakType : NS_STYLE_CLEAR_NONE;
   }
 
   // mCarriedOutBottomMargin value
   nsCollapsingMargin GetCarriedOutBottomMargin() const;
   // Returns true if the margin changed
--- a/layout/generic/nsLineLayout.cpp
+++ b/layout/generic/nsLineLayout.cpp
@@ -318,18 +318,16 @@ nsLineLayout::UpdateBand(const nsRect& a
   mRootSpan->mRightEdge += deltaX;
   mRootSpan->mX += deltaX;
 
   // Now update the right edges of the open spans to account for any
   // change in available space width
   for (PerSpanData* psd = mCurrentSpan; psd; psd = psd->mParent) {
     psd->mRightEdge += deltaWidth;
     psd->mContainsFloat = true;
-    NS_ASSERTION(psd->mX - mTrimmableWidth <= psd->mRightEdge,
-                 "We placed a float where there was no room!");
 #ifdef NOISY_REFLOW
     printf("  span %p: oldRightEdge=%d newRightEdge=%d\n",
            psd, psd->mRightEdge - deltaRightEdge, psd->mRightEdge);
 #endif
   }
   NS_ASSERTION(mRootSpan->mContainsFloat &&
                mRootSpan->mLeftEdge == aNewAvailSpace.x &&
                mRootSpan->mRightEdge == aNewAvailSpace.XMost(),
new file mode 100644
--- /dev/null
+++ b/layout/reftests/border-radius/clipping-6-ref.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
+</head>
+<body>
+    <div style="overflow:hidden; border-radius:25px; border:3px solid #f00; padding:1px; height:180px;">
+        <div style="transform: perspective(1px)">
+            <div style="height:100px; width:100px; background-color:lime"></div>
+            <div style="height:100px; width: 50px; background-color:red; position:relative; top: -20px;">Hi</div>
+        </div>
+    </div>
+    <div
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/border-radius/clipping-6.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
+</head>
+<body>
+    <div style="overflow:hidden; border-radius:25px; border:3px solid #f00; padding:1px; height:180px;">
+        <div style="height:100px; width:100px; transform:perspective(1px); background-color:lime"></div>
+        <div style="height:100px; width: 50px; background-color:red; position:relative; top: -20px;">Hi</div>
+    </div>
+    <div
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/border-radius/clipping-7-ref.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
+</head>
+<body>
+    <div style="overflow:hidden; border-radius:25px; border:3px solid #f00; padding:1px; height:180px;">
+        <div style="height:100px; width:100px; background-color:lime"></div>
+        <div style="height:100px; width: 50px; background-color:red; position:relative; top: -20px;"></div>
+    </div>
+    <div
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/border-radius/clipping-7.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
+</head>
+<body>
+    <div style="overflow:hidden; border-radius:25px; border:3px solid #f00; padding:1px; height:180px;">
+        <div style="height:100px; width:100px; transform:perspective(1px); background-color:lime"></div>
+        <div style="height:100px; width: 50px; background-color:red; position:relative; top: -20px;"></div>
+    </div>
+    <div
+</body>
+</html>
--- a/layout/reftests/border-radius/reftest.list
+++ b/layout/reftests/border-radius/reftest.list
@@ -44,16 +44,18 @@ fuzzy-if(Android&&AndroidVersion<15,9,73
 fuzzy-if(true,1,20) fuzzy-if(cocoaWidget,1,180) fuzzy-if(Android&&browserIsRemote,7,169) fuzzy-if(Android&&!browserIsRemote,140,237) == clipping-4-canvas.html clipping-4-ref.html # bug 732535
 fuzzy-if(Android,5,54) fuzzy-if(/^Windows\x20NT\x206\.2/.test(http.oscpu),1,10) == clipping-4-image.html clipping-4-ref.html
 fuzzy-if(/^Windows\x20NT\x206\.2/.test(http.oscpu),1,10) == clipping-4-overflow-hidden.html clipping-4-ref.html
 == clipping-5-canvas.html clipping-5-refc.html
 fuzzy-if(/^Windows\x20NT\x206\.2/.test(http.oscpu),1,5) == clipping-5-image.html clipping-5-refi.html
 fuzzy-if(/^Windows\x20NT\x206\.2/.test(http.oscpu),1,5) == clipping-5-overflow-hidden.html clipping-5-ref.html
 fuzzy-if(/^Windows\x20NT\x206\.2/.test(http.oscpu),1,5) fuzzy-if(Android,5,21) == clipping-5-refi.html clipping-5-ref.html
 fuzzy-if(true,1,7) fuzzy-if(cocoaWidget,1,99) fuzzy-if(Android&&browserIsRemote,7,89) fuzzy-if(Android&&!browserIsRemote,99,115) == clipping-5-refc.html clipping-5-ref.html # bug 732535
+fuzzy-if(winWidget,105,71) fuzzy-if(Android,8,464) == clipping-6.html clipping-6-ref.html # ThebesLayer and MaskLayer with transforms that aren't identical
+fuzzy-if(true,1,29) fuzzy-if(Android&&AndroidVersion<15,12,81) fuzzy-if(Android&&AndroidVersion>=15,255,586) == clipping-7.html clipping-7-ref.html # ColorLayer and MaskLayer with transforms that aren't identical. Reference image rendered without using layers (which causes fuzzy failures).
 fuzzy-if(/^Windows\x20NT\x206\.2/.test(http.oscpu),1,5) == clipping-and-zindex-1.html clipping-and-zindex-1-ref.html
 fuzzy-if(cocoaWidget,1,4) == intersecting-clipping-1-canvas.html intersecting-clipping-1-refc.html
 == intersecting-clipping-1-image.html intersecting-clipping-1-refi.html
 == intersecting-clipping-1-overflow-hidden.html intersecting-clipping-1-ref.html
 fuzzy-if(Android,5,105) fuzzy-if(d2d,1,20) == intersecting-clipping-1-refi.html intersecting-clipping-1-ref.html
 fuzzy-if(true,1,33) fuzzy-if(cocoaWidget,1,332) fuzzy-if(Android&&browserIsRemote,7,310) fuzzy-if(Android&&!browserIsRemote,124,440) == intersecting-clipping-1-refc.html intersecting-clipping-1-ref.html # bug 732535
 
 # Inheritance
--- a/layout/reftests/bugs/reftest.list
+++ b/layout/reftests/bugs/reftest.list
@@ -1716,17 +1716,17 @@ needs-focus == 731726-1.html 731726-1-re
 == 748692-1b.html 748692-1-ref.html
 skip-if(B2G) == 748803-1.html 748803-1-ref.html
 == 750551-1.html 750551-1-ref.html
 skip-if(B2G) == 751012-1a.html 751012-1-ref.html
 skip-if(B2G) == 751012-1b.html 751012-1-ref.html
 random-if(Android) == 753329-1.html about:blank
 == 758561-1.html 758561-1-ref.html
 fuzzy-if(true,1,19) fails-if(d2d) random-if(Android&&AndroidVersion<15) == 759036-1.html 759036-1-ref.html
-fuzzy-if(true,17,5860) random-if(Android&&AndroidVersion<15) == 759036-2.html 759036-2-ref.html
+fuzzy-if(true,17,5879) random-if(Android&&AndroidVersion<15) == 759036-2.html 759036-2-ref.html
 random-if(Android&&AndroidVersion<15) == 776265-1a.html 776265-1-ref.html
 == 776265-1b.html 776265-1-ref.html
 == 776265-1c.html 776265-1-ref.html
 == 776265-1d.html 776265-1-ref.html
 == 776265-2a.html 776265-2-ref.html
 == 776265-2b.html 776265-2-ref.html
 == 776265-2c.html 776265-2-ref.html
 == 776265-2d.html 776265-2-ref.html
--- a/layout/reftests/font-features/reftest.list
+++ b/layout/reftests/font-features/reftest.list
@@ -9,18 +9,17 @@ skip-if(B2G) HTTP(..) != font-features-t
 
 # check that disabling ligatures causes a change
 HTTP(..) != font-features-noliga.html font-features-ref.html
 
 # check that enabling optional ligatures causes a change
 HTTP(..) != font-features-hlig.html font-features-ref.html
 
 # compare Turkish rendering with reference using ZWNJ to break the ligature
-# (also works via Pango)
-fails-if(d2d) HTTP(..) == font-features-turkish.html font-features-turkish-ref.html
+HTTP(..) == font-features-turkish.html font-features-turkish-ref.html
 
 # compare Turkish rendering with explicitly disabled ligatures
 HTTP(..) == font-features-turkish.html font-features-noliga.html
 
 # The following should pass even if feature support isn't available,
 # because both testcase and reference will have the default rendering,
 # though they're not really meaningful unless the tests above passed already.
 
new file mode 100644
--- /dev/null
+++ b/layout/reftests/forms/input/color/block-invalidate-2-ref.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html>
+  <body>
+    <p>Test for bug <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=977038">977038</a></p>
+    <form>
+      <input type="color" value="#00ff00" />
+    </form>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/forms/input/color/block-invalidate-2.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html class='reftest-wait'>
+  <script>
+    function runTest() {
+      var p = document.getElementsByTagName('input')[0];
+      p.value = '#0000ff'
+      p.defaultValue = '#00ff00';
+      p.form.reset();
+      document.documentElement.className = '';
+    }
+    window.addEventListener("MozReftestInvalidate", runTest, false);
+  </script>
+  <body>
+    <p>Test for bug <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=977038">977038</a></p>
+    <form>
+      <input type="color" />
+    </form>
+  </body>
+</html>
--- a/layout/reftests/forms/input/color/reftest.list
+++ b/layout/reftests/forms/input/color/reftest.list
@@ -4,11 +4,12 @@
 fails-if(B2G||Android) == input-color-1.html input-color-1-ref.html
 
 default-preferences pref(dom.forms.color,true)
 
 # Despite the "default-preferences" line above, B2G and Android are still
 # excluded from some style in forms.css, which makes the following tests fail.
 fails-if(B2G||Android) == margin-padding-1.html margin-padding-1-ref.html
 == block-invalidate-1.html block-invalidate-1-ref.html
+== block-invalidate-2.html block-invalidate-2-ref.html
 fails-if(B2G||Android) == transformations-1.html transformations-1-ref.html
 fails-if(B2G||Android) == custom-style-1.html custom-style-1-ref.html
 fails-if(B2G||Android) == custom-style-2.html custom-style-2-ref.html
--- a/layout/reftests/invalidation/test-image-layers-ref.html
+++ b/layout/reftests/invalidation/test-image-layers-ref.html
@@ -1,8 +1,8 @@
 <!DOCTYPE HTML>
 <html>
 <body style="background:black">
 <div>
-<img id="image" src="./image_rgrg-256x256.png" style="-moz-transform: translatex(1px)"></img>
+<img id="image" src="./image_rgrg-256x256.png" style="-moz-transform: perspective(1px)"></img>
 </div>
 </body>
 </html>
--- a/layout/reftests/invalidation/test-image-layers.html
+++ b/layout/reftests/invalidation/test-image-layers.html
@@ -1,13 +1,13 @@
 <!DOCTYPE HTML>
 <html class="reftest-wait">
 <body>
 <div>
-<img id="image" class="reftest-no-paint" src="./image_rgrg-256x256.png" style="-moz-transform: translatex(1px)"></img>
+<img id="image" class="reftest-no-paint" src="./image_rgrg-256x256.png" style="-moz-transform: perspective(1px)"></img>
 </div>
 <script type="application/javascript">
 
 function doTest() {
   document.body.style.background = "black";
   document.documentElement.removeAttribute("class");
 }
 document.addEventListener("MozReftestInvalidate", doTest, false);
new file mode 100644
--- /dev/null
+++ b/layout/reftests/svg/filters/multiple-svg-filters-long-chain.svg
@@ -0,0 +1,24 @@
+<svg xmlns="http://www.w3.org/2000/svg">
+  <filter id="flood-with-yellow">
+    <!-- Turn the black rect into a yellow rect. -->
+    <feFlood x="20" y="20" width="100" height="100" flood-color="#ffff00"/>
+  </filter>
+  <filter id="extract-red-channel">
+    <!-- Turn the yellow rect into a red rect. -->
+    <feComponentTransfer x="0" y="0" width="120" height="120">
+      <feFuncR type="identity"/>
+      <feFuncG type="table" tableValues="0 0"/>
+      <feFuncB type="table" tableValues="0 0"/>
+      <feFuncA type="identity"/>
+    </feComponentTransfer>
+  </filter>
+  <filter id="blur">
+    <!-- Blur the red rect. -->
+    <feGaussianBlur stdDeviation="3" x="10" y="10" width="120" height="120"/>
+  </filter>
+  <filter id="hue-rotate">
+    <!-- Turn the red rect into a green rect. -->
+    <feColorMatrix type="hueRotate" values="90"/>
+  </filter>
+  <rect x="20" y="20" width="100" height="100" filter="url(#flood-with-yellow) url(#extract-red-channel) url(#blur) url(#hue-rotate)"/>
+</svg>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/svg/filters/multiple-svg-filters-ref.svg
@@ -0,0 +1,10 @@
+<svg xmlns="http://www.w3.org/2000/svg">
+  <!-- Test multiple SVG filters chained together against a single SVG filter. -->
+  <filter id="blur-and-hue-rotate">
+    <!-- Blur the red rect. -->
+    <feGaussianBlur stdDeviation="3"/>
+    <!-- Turn the red rect into a green rect. -->
+    <feColorMatrix type="hueRotate" values="90"/>
+  </filter>
+  <rect x="20" y="20" width="100" height="100" fill="#ff0000" filter="url(#blur-and-hue-rotate)"/>
+</svg>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/svg/filters/multiple-svg-filters-second-uses-SourceGraphic.svg
@@ -0,0 +1,13 @@
+<svg xmlns="http://www.w3.org/2000/svg">
+  <filter id="blur">
+    <!-- Blur the red rect. -->
+    <feGaussianBlur stdDeviation="3"/>
+  </filter>
+  <filter id="hue-rotate">
+    <feFlood flood-color="#0000ff"/>
+    <!-- Turn the red rect into a green rect. feColorMatrix should use the
+         result of the #blur filter, not feFlood, as its SourceGraphic. -->
+    <feColorMatrix in="SourceGraphic" type="hueRotate" values="90"/>
+  </filter>
+  <rect x="20" y="20" width="100" height="100" fill="#ff0000" filter="url(#blur) url(#hue-rotate)"/>
+</svg>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/svg/filters/multiple-svg-filters-with-multiple-primitives.svg
@@ -0,0 +1,20 @@
+<svg xmlns="http://www.w3.org/2000/svg">
+  <filter id="flood-with-red">
+    <!-- Turn the black rect into a yellow rect. -->
+    <feFlood x="20" y="20" width="100" height="100" flood-color="#ffff00"/>
+    <!-- Turn the yellow rect into a red rect. -->
+    <feComponentTransfer x="0" y="0" width="120" height="120">
+        <feFuncR type="identity"/>
+        <feFuncG type="table" tableValues="0 0"/>
+        <feFuncB type="table" tableValues="0 0"/>
+        <feFuncA type="identity"/>
+    </feComponentTransfer>
+  </filter>
+  <filter id="blur-and-hue-rotate">
+    <!-- Blur the red rect. -->
+    <feGaussianBlur stdDeviation="3" x="10" y="10" width="120" height="120"/>
+    <!-- Turn the red rect into a green rect. -->
+    <feColorMatrix type="hueRotate" values="90"/>
+  </filter>
+  <rect x="20" y="20" width="100" height="100" filter="url(#flood-with-red) url(#blur-and-hue-rotate)"/>
+</svg>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/svg/filters/multiple-svg-filters.svg
@@ -0,0 +1,11 @@
+<svg xmlns="http://www.w3.org/2000/svg">
+  <filter id="blur">
+    <!-- Blur the red rect. -->
+    <feGaussianBlur stdDeviation="3"/>
+  </filter>
+  <filter id="hue-rotate">
+    <!-- Turn the red rect into a green rect. -->
+    <feColorMatrix type="hueRotate" values="90"/>
+  </filter>
+  <rect x="20" y="20" width="100" height="100" fill="#ff0000" filter="url(#blur) url(#hue-rotate)"/>
+</svg>
--- a/layout/reftests/svg/filters/reftest.list
+++ b/layout/reftests/svg/filters/reftest.list
@@ -99,8 +99,12 @@ skip-if(B2G) fuzzy-if(cocoaWidget,4,184)
 == feTile-large-01.svg pass.svg
 == feTile-large-02.svg feTile-large-02-ref.svg
 == feTile-outside-01.svg feTile-outside-01-ref.svg
 
 fuzzy(1,119) == feDiffuseLighting-1.svg feDiffuseLighting-1-ref.svg
 
 skip-if(d2d) == feSpecularLighting-1.svg feSpecularLighting-1-ref.svg
 
+pref(layout.css.filters.enabled,true) == multiple-svg-filters.svg multiple-svg-filters-ref.svg
+pref(layout.css.filters.enabled,true) == multiple-svg-filters-long-chain.svg multiple-svg-filters-ref.svg
+pref(layout.css.filters.enabled,true) == multiple-svg-filters-second-uses-SourceGraphic.svg multiple-svg-filters-ref.svg
+pref(layout.css.filters.enabled,true) == multiple-svg-filters-with-multiple-primitives.svg multiple-svg-filters-ref.svg
new file mode 100644
--- /dev/null
+++ b/layout/reftests/text/initial-zwj-1-ref.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html lang="ar">
+<head>
+<title>Bug 978313</title>
+<meta charset="utf-8">
+<style>
+body {
+  font-family: Arial, DejaVu Sans, Droid Sans Arabic, Droid Arabic Naskh;
+  font-size: 36px;
+}
+</style>
+</head>
+<body>
+&zwj;ی&zwj;ت
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/text/initial-zwj-1.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html lang="ar">
+<head>
+<title>Bug 978313</title>
+<meta charset="utf-8">
+<style>
+body {
+  font-family: Arial, DejaVu Sans, Droid Sans Arabic, Droid Arabic Naskh;
+  font-size: 36px;
+}
+</style>
+</head>
+<body>
+&zwj;یت
+</body>
+</html>
--- a/layout/reftests/text/kerning-01-notref.html
+++ b/layout/reftests/text/kerning-01-notref.html
@@ -7,16 +7,19 @@
   /* a copy of M+ with OpenType tables removed, so only legacy 'kern' is present */
 }
 
 body {
   text-rendering: optimizeLegibility;
   font-size: 40px;
   font-family: mplus;
 }
+span {
+  font-family: serif;
+}
 </style>
 </head>
 <body>
-<!-- the ZWNJ characters should prevent kerning at those positions;
+<!-- the ZWNJ characters with font change should prevent kerning at those positions;
      if the testcase looks the same, then kerning failed altogether -->
-AVA&zwnj;V&zwnj;A
+AVA<span>&zwnj;</span>V<span>&zwnj;</span>A
 </body>
 </html>
--- a/layout/reftests/text/reftest.list
+++ b/layout/reftests/text/reftest.list
@@ -130,28 +130,28 @@ skip-if(B2G) != wordwrap-09.html wordwra
 skip-if(B2G) == wordwrap-09.html wordwrap-09-ref.html
 == wordwrap-10.html wordwrap-10-ref.html # bug 752459
 == word-spacing-01.html word-spacing-01-ref.html
 # the following will fail when rendering with Core Text (see bug 389074) due to what appears to be
 # an Apple bug: the presence of ZWNJ disturbs the positioning of an adjacent glyph. rdar://6427865
 random-if(cocoaWidget) HTTP(..) == zwnj-01.xhtml zwnj-01-ref.xhtml
 HTTP(..) == zwnj-02.xhtml zwnj-02-ref.xhtml # HTTP(..) for ../filters.svg
 != zwnj-01.html zwnj-01-notref.html
+== initial-zwj-1.html initial-zwj-1-ref.html
 == cgj-01.html cgj-01-ref.html
 == 444656.html 444656-ref.html
 == 449555-1.html 449555-1-ref.html
 == 467722.html 467722-ref.html
 skip-if(B2G) HTTP(..) == 475092-sub.html 475092-ref.html
 fails-if(!winWidget&&!gtk2Widget) skip-if(B2G) HTTP(..) == 475092-pos.html 475092-sub.html # bug 482596
 == 476378-soft-hyphen-fallback.html 476378-soft-hyphen-fallback-ref.html
 # Test for bug 484954
 == rgba-text.html rgba-text-ref.html
 # Test for bug 575695, 'kern' table support
-# Random on Windows because behavior depends on Uniscribe version(?)
-random-if(winWidget) HTTP(..) != kerning-01.html kerning-01-notref.html
+HTTP(..) != kerning-01.html kerning-01-notref.html
 # Test for bug 577380, support for AAT layout (on OS X only)
 random-if(!cocoaWidget) == 577380.html 577380-ref.html
 # Test for OpenType Arabic shaping support
 HTTP(..) == arabic-shaping-1.html arabic-shaping-1-ref.html
 # check ligature in Arial Bold on Windows, for bug 644184; may fail on other platforms depending on fonts
 random-if(!winWidget) == arial-bold-lam-alef-1.html arial-bold-lam-alef-1-ref.html
 # Fallback (presentation-forms) shaping with a font that lacks GSUB/GPOS
 # These tests are not valid on OS X because our masking of complex-script ranges
--- a/layout/style/AnimationCommon.cpp
+++ b/layout/style/AnimationCommon.cpp
@@ -250,31 +250,31 @@ CommonAnimationManager::UpdateThrottledS
           oldStyle->GetPseudoType(),
           false);
       NS_ASSERTION(ea,
         "Rule has level eAnimationSheet without animation on manager");
 
       mPresContext->AnimationManager()->EnsureStyleRuleFor(ea);
       curRule.mRule = ea->mStyleRule;
 
-      // FIXME: maybe not needed anymore:
+      // FIXME (bug 828173): maybe not needed anymore:
       ForceLayerRerendering(primaryFrame, ea);
     } else if (curRule.mLevel == nsStyleSet::eTransitionSheet) {
       ElementTransitions *et =
         mPresContext->TransitionManager()->GetElementTransitions(
           aElement,
           oldStyle->GetPseudoType(),
           false);
       NS_ASSERTION(et,
         "Rule has level eTransitionSheet without transition on manager");
 
       et->EnsureStyleRuleFor(mPresContext->RefreshDriver()->MostRecentRefresh());
       curRule.mRule = et->mStyleRule;
 
-      // FIXME: maybe not needed anymore:
+      // FIXME (bug 828173): maybe not needed anymore:
       ForceLayerRerendering(primaryFrame, et);
     } else {
       curRule.mRule = ruleNode->GetRule();
     }
 
     if (curRule.mRule) {
       rules.AppendElement(curRule);
     }
--- a/layout/style/nsCSSProps.cpp
+++ b/layout/style/nsCSSProps.cpp
@@ -830,17 +830,17 @@ const KTableValue nsCSSProps::kCaptionSi
   eCSSKeyword_bottom_outside,       NS_STYLE_CAPTION_SIDE_BOTTOM_OUTSIDE,
   eCSSKeyword_UNKNOWN,              -1
 };
 
 const KTableValue nsCSSProps::kClearKTable[] = {
   eCSSKeyword_none, NS_STYLE_CLEAR_NONE,
   eCSSKeyword_left, NS_STYLE_CLEAR_LEFT,
   eCSSKeyword_right, NS_STYLE_CLEAR_RIGHT,
-  eCSSKeyword_both, NS_STYLE_CLEAR_LEFT_AND_RIGHT,
+  eCSSKeyword_both, NS_STYLE_CLEAR_BOTH,
   eCSSKeyword_UNKNOWN,-1
 };
 
 // See also kContextPatternKTable for SVG paint-specific values
 const KTableValue nsCSSProps::kColorKTable[] = {
   eCSSKeyword_activeborder, LookAndFeel::eColorID_activeborder,
   eCSSKeyword_activecaption, LookAndFeel::eColorID_activecaption,
   eCSSKeyword_appworkspace, LookAndFeel::eColorID_appworkspace,
--- a/layout/style/nsStyleConsts.h
+++ b/layout/style/nsStyleConsts.h
@@ -312,19 +312,21 @@ static inline mozilla::css::Side operato
 
 #define NS_STYLE_BORDER_IMAGE_SLICE_NOFILL      0
 #define NS_STYLE_BORDER_IMAGE_SLICE_FILL        1
 
 // See nsStyleDisplay
 #define NS_STYLE_CLEAR_NONE                     0
 #define NS_STYLE_CLEAR_LEFT                     1
 #define NS_STYLE_CLEAR_RIGHT                    2
-#define NS_STYLE_CLEAR_LEFT_AND_RIGHT           3
+#define NS_STYLE_CLEAR_BOTH                     3
 #define NS_STYLE_CLEAR_LINE                     4
-#define NS_STYLE_CLEAR_LAST_VALUE NS_STYLE_CLEAR_LINE
+// @note NS_STYLE_CLEAR_LINE can be added to one of the other values in layout
+// so it needs to use a bit value that none of the other values can have.
+#define NS_STYLE_CLEAR_MAX (NS_STYLE_CLEAR_LINE | NS_STYLE_CLEAR_BOTH)
 
 // See nsStyleContent
 #define NS_STYLE_CONTENT_OPEN_QUOTE             0
 #define NS_STYLE_CONTENT_CLOSE_QUOTE            1
 #define NS_STYLE_CONTENT_NO_OPEN_QUOTE          2
 #define NS_STYLE_CONTENT_NO_CLOSE_QUOTE         3
 #define NS_STYLE_CONTENT_ALT_CONTENT            4
 
--- a/layout/svg/nsSVGFilterInstance.cpp
+++ b/layout/svg/nsSVGFilterInstance.cpp
@@ -296,61 +296,70 @@ nsSVGFilterInstance::GetInputsAreTainted
       // SourceGraphic, SourceAlpha, FillPaint and StrokePaint are tainted.
       aOutInputsAreTainted.AppendElement(true);
     } else {
       aOutInputsAreTainted.AppendElement(aPrimitiveDescrs[inputIndex].IsTainted());
     }
   }
 }
 
-static nsresult
-GetSourceIndices(nsSVGFE* aFilterElement,
-                 int32_t aCurrentIndex,
-                 const nsDataHashtable<nsStringHashKey, int32_t>& aImageTable,
-                 nsTArray<int32_t>& aSourceIndices)
+static int32_t
+GetLastResultIndex(const nsTArray<FilterPrimitiveDescription>& aPrimitiveDescrs)
+{
+  uint32_t numPrimitiveDescrs = aPrimitiveDescrs.Length();
+  return !numPrimitiveDescrs ?
+    FilterPrimitiveDescription::kPrimitiveIndexSourceGraphic :
+    numPrimitiveDescrs - 1;
+}
+
+nsresult
+nsSVGFilterInstance::GetSourceIndices(nsSVGFE* aPrimitiveElement,
+                                      const nsTArray<FilterPrimitiveDescription>& aPrimitiveDescrs,
+                                      const nsDataHashtable<nsStringHashKey, int32_t>& aImageTable,
+                                      nsTArray<int32_t>& aSourceIndices)
 {
   nsAutoTArray<nsSVGStringInfo,2> sources;
-  aFilterElement->GetSourceImageNames(sources);
+  aPrimitiveElement->GetSourceImageNames(sources);
 
   for (uint32_t j = 0; j < sources.Length(); j++) {
     nsAutoString str;
     sources[j].mString->GetAnimValue(str, sources[j].mElement);
 
     int32_t sourceIndex = 0;
     if (str.EqualsLiteral("SourceGraphic")) {
-      sourceIndex = FilterPrimitiveDescription::kPrimitiveIndexSourceGraphic;
+      sourceIndex = mSourceGraphicIndex;
     } else if (str.EqualsLiteral("SourceAlpha")) {
       sourceIndex = FilterPrimitiveDescription::kPrimitiveIndexSourceAlpha;
     } else if (str.EqualsLiteral("FillPaint")) {
       sourceIndex = FilterPrimitiveDescription::kPrimitiveIndexFillPaint;
     } else if (str.EqualsLiteral("StrokePaint")) {
       sourceIndex = FilterPrimitiveDescription::kPrimitiveIndexStrokePaint;
     } else if (str.EqualsLiteral("BackgroundImage") ||
                str.EqualsLiteral("BackgroundAlpha")) {
       return NS_ERROR_NOT_IMPLEMENTED;
     } else if (str.EqualsLiteral("")) {
-      sourceIndex = aCurrentIndex == 0 ?
-        FilterPrimitiveDescription::kPrimitiveIndexSourceGraphic :
-        aCurrentIndex - 1;
+      sourceIndex = GetLastResultIndex(aPrimitiveDescrs);
     } else {
       bool inputExists = aImageTable.Get(str, &sourceIndex);
       if (!inputExists)
         return NS_ERROR_FAILURE;
     }
 
-    MOZ_ASSERT(sourceIndex < aCurrentIndex);
     aSourceIndices.AppendElement(sourceIndex);
   }
   return NS_OK;
 }
 
 nsresult
 nsSVGFilterInstance::BuildPrimitives(nsTArray<FilterPrimitiveDescription>& aPrimitiveDescrs,
                                      nsTArray<mozilla::RefPtr<SourceSurface>>& aInputImages)
 {
+  mSourceGraphicIndex = GetLastResultIndex(aPrimitiveDescrs);
+
+  // Get the filter primitive elements.
   nsTArray<nsRefPtr<nsSVGFE> > primitives;
   for (nsIContent* child = mFilterElement->nsINode::GetFirstChild();
        child;
        child = child->GetNextSibling()) {
     nsRefPtr<nsSVGFE> primitive;
     CallQueryInterface(child, (nsSVGFE**)getter_AddRefs(primitive));
     if (primitive) {
       primitives.AppendElement(primitive);
@@ -358,55 +367,58 @@ nsSVGFilterInstance::BuildPrimitives(nsT
   }
 
   // Maps source image name to source index.
   nsDataHashtable<nsStringHashKey, int32_t> imageTable(10);
 
   // The principal that we check principals of any loaded images against.
   nsCOMPtr<nsIPrincipal> principal = mTargetFrame->GetContent()->NodePrincipal();
 
-  for (uint32_t i = 0; i < primitives.Length(); ++i) {
-    nsSVGFE* filter = primitives[i];
+  for (uint32_t primitiveElementIndex = 0;
+       primitiveElementIndex < primitives.Length();
+       ++primitiveElementIndex) {
+    nsSVGFE* filter = primitives[primitiveElementIndex];
 
     nsAutoTArray<int32_t,2> sourceIndices;
-    nsresult rv = GetSourceIndices(filter, i, imageTable, sourceIndices);
+    nsresult rv = GetSourceIndices(filter, aPrimitiveDescrs, imageTable, sourceIndices);
     if (NS_FAILED(rv)) {
       return rv;
     }
 
     IntRect primitiveSubregion =
       ComputeFilterPrimitiveSubregion(filter, aPrimitiveDescrs, sourceIndices);
 
     nsTArray<bool> sourcesAreTainted;
     GetInputsAreTainted(aPrimitiveDescrs, sourceIndices, sourcesAreTainted);
 
     FilterPrimitiveDescription descr =
       filter->GetPrimitiveDescription(this, primitiveSubregion, sourcesAreTainted, aInputImages);
 
     descr.SetIsTainted(filter->OutputIsTainted(sourcesAreTainted, principal));
     descr.SetPrimitiveSubregion(primitiveSubregion);
 
-    for (uint32_t j = 0; j < sourceIndices.Length(); j++) {
-      int32_t inputIndex = sourceIndices[j];
-      descr.SetInputPrimitive(j, inputIndex);
+    for (uint32_t i = 0; i < sourceIndices.Length(); i++) {
+      int32_t inputIndex = sourceIndices[i];
+      descr.SetInputPrimitive(i, inputIndex);
       ColorSpace inputColorSpace =
         inputIndex < 0 ? SRGB : aPrimitiveDescrs[inputIndex].OutputColorSpace();
-      ColorSpace desiredInputColorSpace = filter->GetInputColorSpace(j, inputColorSpace);
-      descr.SetInputColorSpace(j, desiredInputColorSpace);
-      if (j == 0) {
+      ColorSpace desiredInputColorSpace = filter->GetInputColorSpace(i, inputColorSpace);
+      descr.SetInputColorSpace(i, desiredInputColorSpace);
+      if (i == 0) {
         // the output color space is whatever in1 is if there is an in1
         descr.SetOutputColorSpace(desiredInputColorSpace);
       }
     }
 
     if (sourceIndices.Length() == 0) {
       descr.SetOutputColorSpace(filter->GetOutputColorSpace());
     }
 
     aPrimitiveDescrs.AppendElement(descr);
+    uint32_t primitiveDescrIndex = aPrimitiveDescrs.Length() - 1;
 
     nsAutoString str;
     filter->GetResultImageName().GetAnimValue(str, filter);
-    imageTable.Put(str, i);
+    imageTable.Put(str, primitiveDescrIndex);
   }
 
   return NS_OK;
 }
--- a/layout/svg/nsSVGFilterInstance.h
+++ b/layout/svg/nsSVGFilterInstance.h
@@ -135,16 +135,28 @@ private:
   /**
    * Returns the transform from frame space to the coordinate space that
    * GetCanvasTM transforms to. "Frame space" is the origin of a frame, aka the
    * top-left corner of its border box, aka the top left corner of its mRect.
    */
   gfxMatrix GetUserSpaceToFrameSpaceInCSSPxTransform() const;
 
   /**
+   * Finds the index in aPrimitiveDescrs of each input to aPrimitiveElement.
+   * For example, if aPrimitiveElement is:
+   *   <feGaussianBlur in="another-primitive" .../>
+   * Then, the resulting aSourceIndices will contain the index of the
+   * FilterPrimitiveDescription representing "another-primitive".
+   */
+  nsresult GetSourceIndices(nsSVGFE* aPrimitiveElement,
+                            const nsTArray<FilterPrimitiveDescription>& aPrimitiveDescrs,
+                            const nsDataHashtable<nsStringHashKey, int32_t>& aImageTable,
+                            nsTArray<int32_t>& aSourceIndices);
+
+  /**
    * The SVG reference filter originally from the style system.
    */
   const nsStyleFilter mFilter;
 
   /**
    * The frame for the element that is currently being filtered.
    */
   nsIFrame*               mTargetFrame;
@@ -170,12 +182,19 @@ private:
   gfxRect                 mFilterRegion;
   nsIntRect               mFilterSpaceBounds;
 
   /**
    * The 'primitiveUnits' attribute value (objectBoundingBox or userSpaceOnUse).
    */
   uint16_t                mPrimitiveUnits;
 
+  /**
+   * The index of the FilterPrimitiveDescription that this SVG filter should use
+   * as its SourceGraphic, or the SourceGraphic keyword index if this is the
+   * first filter in a chain.
+   */
+  int32_t mSourceGraphicIndex;
+
   bool                    mInitialized;
 };
 
 #endif
--- a/memory/mozalloc/VolatileBufferWindows.cpp
+++ b/memory/mozalloc/VolatileBufferWindows.cpp
@@ -1,19 +1,20 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#if defined(XP_WIN) || defined(XP_OS2)
+#if defined(XP_WIN)
 #  define MOZALLOC_EXPORT __declspec(dllexport)
 #endif
 
 #include "VolatileBuffer.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/mozalloc.h"
+#include "mozilla/WindowsVersion.h"
 
 #include <windows.h>
 
 #ifdef MOZ_MEMORY
 extern "C" int posix_memalign(void** memptr, size_t alignment, size_t size);
 #endif
 
 #ifndef MEM_RESET_UNDO
@@ -40,34 +41,17 @@ VolatileBuffer::Init(size_t aSize, size_
   MOZ_ASSERT(!(aAlignment % sizeof(void *)),
              "Alignment must be multiple of pointer size");
 
   mSize = aSize;
   if (aSize < MIN_VOLATILE_ALLOC_SIZE) {
     goto heap_alloc;
   }
 
-  static bool sCheckedVersion = false;
-  static bool sUndoSupported = false;
-  if (!sCheckedVersion) {
-    OSVERSIONINFOEX verinfo = { 0 };
-    verinfo.dwOSVersionInfoSize = sizeof(verinfo);
-    verinfo.dwMajorVersion = 6;
-    verinfo.dwMinorVersion = 2;
-
-    DWORDLONG mask = 0;
-    VER_SET_CONDITION(mask, VER_MAJORVERSION, VER_GREATER_EQUAL);
-    VER_SET_CONDITION(mask, VER_MINORVERSION, VER_GREATER_EQUAL);
-
-    sUndoSupported = VerifyVersionInfo(&verinfo,
-                                       VER_MAJORVERSION | VER_MINORVERSION,
-                                       mask);
-    sCheckedVersion = true;
-  }
-
+  static bool sUndoSupported = IsWin8OrLater();
   if (!sUndoSupported) {
     goto heap_alloc;
   }
 
   mBuf = VirtualAllocEx(GetCurrentProcess(),
                         nullptr,
                         mSize,
                         MEM_COMMIT | MEM_RESERVE,
--- a/mobile/android/base/tests/robocop.ini
+++ b/mobile/android/base/tests/robocop.ini
@@ -1,10 +1,12 @@
 # [test_bug720538] # disabled on fig - bug 897072
 [testAboutPage]
+# disabled on Android 2.3; bug 975187
+skip-if = android_version == "10"
 [testAddonManager]
 # disabled on x86 only; bug 936216
 skip-if = processor == "x86"
 [testAddSearchEngine]
 [testAdobeFlash]
 skip-if = processor == "x86"
 [testAwesomebar]
 [testAxisLocking]
@@ -18,16 +20,18 @@ skip-if = processor == "x86"
 [testBrowserProvider]
 [testBrowserSearchVisibility]
 [testClearPrivateData]
 # disabled on x86 only; bug 948591
 skip-if = processor == "x86"
 [testDistribution]
 [testDoorHanger]
 [testFindInPage]
+# disabled on Android 2.3; bug 975155
+skip-if = android_version == "10"
 [testFlingCorrectness]
 # disabled on x86 only; bug 927476
 skip-if = processor == "x86"
 [testFormHistory]
 [testGetUserMedia]
 # [testHistory] # see bug 915350
 [testHomeBanner]
 # disabled on x86 only; bug 957185
--- a/mobile/android/modules/WebappManager.jsm
+++ b/mobile/android/modules/WebappManager.jsm
@@ -184,31 +184,31 @@ this.WebappManager = {
       // We don't have to do anything, as the registry does all the work.
       return;
     }
 
     // TODO: uninstall the APK.
   },
 
   autoInstall: function(aData) {
-    let oldApp = DOMApplicationRegistry.getAppByManifestURL(aData.manifestUrl);
+    let oldApp = DOMApplicationRegistry.getAppByManifestURL(aData.manifestURL);
     if (oldApp) {
       // If the app is already installed, update the existing installation.
       this._autoUpdate(aData, oldApp);
       return;
     }
 
     let mm = {
       sendAsyncMessage: function (aMessageName, aData) {
         // TODO hook this back to Java to report errors.
         log("sendAsyncMessage " + aMessageName + ": " + JSON.stringify(aData));
       }
     };
 
-    let origin = Services.io.newURI(aData.manifestUrl, null, null).prePath;
+    let origin = Services.io.newURI(aData.manifestURL, null, null).prePath;
 
     let message = aData.request || {
       app: {
         origin: origin,
         receipts: [],
       }
     };
 
@@ -217,17 +217,17 @@ this.WebappManager = {
         aData.updateManifest.package_path = aData.zipFilePath;
       }
       message.app.updateManifest = aData.updateManifest;
     }
 
     // The manifest url may be subtly different between the
     // time the APK was built and the APK being installed.
     // Thus, we should take the APK as the source of truth.
-    message.app.manifestURL = aData.manifestUrl;
+    message.app.manifestURL = aData.manifestURL;
     message.app.manifest = aData.manifest;
     message.app.apkPackageName = aData.apkPackageName;
     message.profilePath = aData.profilePath;
     message.autoInstall = true;
     message.mm = mm;
 
     DOMApplicationRegistry.registryReady.then(() => {
       switch (aData.type) { // can be hosted or packaged.
--- a/modules/libpref/src/init/all.js
+++ b/modules/libpref/src/init/all.js
@@ -258,16 +258,29 @@ pref("media.peerconnection.identity.time
 // setting (for Xxx = Ec, Agc, or Ns).  Defaults are all set to kXxxDefault here.
 pref("media.peerconnection.turn.disable", false);
 pref("media.peerconnection.aec_enabled", true);
 pref("media.peerconnection.aec", 1);
 pref("media.peerconnection.agc_enabled", false);
 pref("media.peerconnection.agc", 1);
 pref("media.peerconnection.noise_enabled", false);
 pref("media.peerconnection.noise", 1);
+// Adjustments for OS mediastream+output+OS+input delay (lower bound)
+#if defined(XP_MACOSX)
+pref("media.peerconnection.capture_delay", 50);
+#elif defined(XP_WIN)
+pref("media.peerconnection.capture_delay", 50);
+#elif defined(ANDROID)
+pref("media.peerconnection.capture_delay", 100);
+#elif defined(XP_LINUX)
+pref("media.peerconnection.capture_delay", 70);
+#else
+// *BSD, others - merely a guess for now
+pref("media.peerconnection.capture_delay", 50);
+#endif
 #else
 #ifdef ANDROID
 pref("media.navigator.enabled", true);
 #endif
 #endif
 
 pref("media.tabstreaming.width", 320);
 pref("media.tabstreaming.height", 240);
@@ -2567,20 +2580,16 @@ pref("intl.keyboard.per_window_layout", 
 
 #ifdef NS_ENABLE_TSF
 // Enable/Disable TSF support
 pref("intl.tsf.enable", false);
 
 // Support IMEs implemented with IMM in TSF mode.
 pref("intl.tsf.support_imm", true);
 
-// We need to notify the layout change to TSF, but we cannot check the actual
-// change now, therefore, we always notify it by this fequency.
-pref("intl.tsf.on_layout_change_interval", 100);
-
 // Enables/Disables hack for specific TIP.
 
 // Whether creates native caret for ATOK or not.
 pref("intl.tsf.hack.atok.create_native_caret", true);
 #endif
 
 // See bug 448927, on topmost panel, some IMEs are not usable on Windows.
 pref("ui.panel.default_level_parent", false);
@@ -4318,8 +4327,11 @@ pref("urlclassifier.download_allow_table
 // Turn off Spatial navigation by default.
 pref("snav.enabled", false);
 
 // Wakelock is disabled by default.
 pref("dom.wakelock.enabled", false);
 
 // The URL of the Firefox Accounts auth server backend
 pref("identity.fxaccounts.auth.uri", "https://api.accounts.firefox.com/v1");
+
+// disable mozsample size for now
+pref("image.mozsamplesize.enabled", false);
--- a/netwerk/base/src/nsMediaFragmentURIParser.cpp
+++ b/netwerk/base/src/nsMediaFragmentURIParser.cpp
@@ -346,16 +346,29 @@ bool nsMediaFragmentURIParser::ParseMozR
       aString.Length() == 0) {
     mResolution.construct(w,h);
     return true;
   }
 
   return false;
 }
 
+bool nsMediaFragmentURIParser::ParseMozSampleSize(nsDependentSubstring aString)
+{
+  int32_t sampleSize;
+
+  // Read and validate coordinates.
+  if (ParseInteger(aString, sampleSize) && sampleSize > 0) {
+    mSampleSize.construct(sampleSize);
+    return true;
+  }
+
+  return false;
+}
+
 void nsMediaFragmentURIParser::Parse(nsACString& aRef)
 {
   // Create an array of possibly-invalid media fragments.
   nsTArray< std::pair<nsCString, nsCString> > fragments;
   nsCCharSeparatedTokenizer tokenizer(aRef, '&');
 
   while (tokenizer.hasMoreTokens()) {
     const nsCSubstring& nv = tokenizer.nextToken();
@@ -366,27 +379,31 @@ void nsMediaFragmentURIParser::Parse(nsA
       NS_UnescapeURL(StringHead(nv, index), esc_Ref | esc_AlwaysCopy, name);
       NS_UnescapeURL(Substring(nv, index + 1, nv.Length()),
                      esc_Ref | esc_AlwaysCopy, value);
       fragments.AppendElement(make_pair(name, value));
     }
   }
 
   // Parse the media fragment values.
-  bool gotTemporal = false, gotSpatial = false, gotResolution = false;
+  bool gotTemporal = false, gotSpatial = false,
+      gotResolution = false, gotSampleSize = false;
   for (int i = fragments.Length() - 1 ; i >= 0 ; --i) {
-    if (gotTemporal && gotSpatial && gotResolution) {
+    if (gotTemporal && gotSpatial && gotResolution && gotSampleSize) {
       // We've got one of each possible type. No need to look at the rest.
       break;
     } else if (!gotTemporal && fragments[i].first.EqualsLiteral("t")) {
       nsAutoString value = NS_ConvertUTF8toUTF16(fragments[i].second);
       gotTemporal = ParseNPT(nsDependentSubstring(value, 0));
     } else if (!gotSpatial && fragments[i].first.EqualsLiteral("xywh")) {
       nsAutoString value = NS_ConvertUTF8toUTF16(fragments[i].second);
       gotSpatial = ParseXYWH(nsDependentSubstring(value, 0));
     } else if (!gotResolution && fragments[i].first.EqualsLiteral("-moz-resolution")) {
       nsAutoString value = NS_ConvertUTF8toUTF16(fragments[i].second);
       gotResolution = ParseMozResolution(nsDependentSubstring(value, 0));
+    } else if (!gotSampleSize && fragments[i].first.EqualsLiteral("-moz-samplesize")) {
+      nsAutoString value = NS_ConvertUTF8toUTF16(fragments[i].second);
+      gotSampleSize = ParseMozSampleSize(nsDependentSubstring(value, 0));
     }
   }
 }
 
 }} // namespace mozilla::net
--- a/netwerk/base/src/nsMediaFragmentURIParser.h
+++ b/netwerk/base/src/nsMediaFragmentURIParser.h
@@ -65,16 +65,20 @@ public:
   // returns the region. If not, returns an empty region. The unit
   // used depends on the value returned by GetClipUnit().
   nsIntRect GetClip() const { return mClip.ref(); }
 
   // If a valid spatial media fragment indicated a clipping region,
   // returns the unit used.
   ClipUnit GetClipUnit() const { return mClipUnit; }
 
+  bool HasSampleSize() const { return !mSampleSize.empty(); }
+
+  int GetSampleSize() const { return mSampleSize.ref(); }
+
 private:
   // Parse the URI ref provided, looking for media fragments. This is
   // the top-level parser the invokes the others below.
   void Parse(nsACString& aRef);
 
   // The following methods parse the fragment as per the media
   // fragments specification. 'aString' contains the remaining
   // fragment data to be parsed. The method returns true
@@ -87,20 +91,22 @@ private:
   bool ParseNPTFraction(nsDependentSubstring& aString, double& aFraction);
   bool ParseNPTMMSS(nsDependentSubstring& aString, double& aTime);
   bool ParseNPTHHMMSS(nsDependentSubstring& aString, double& aTime);
   bool ParseNPTHH(nsDependentSubstring& aString, uint32_t& aHour);
   bool ParseNPTMM(nsDependentSubstring& aString, uint32_t& aMinute);
   bool ParseNPTSS(nsDependentSubstring& aString, uint32_t& aSecond);
   bool ParseXYWH(nsDependentSubstring aString);
   bool ParseMozResolution(nsDependentSubstring aString);
+  bool ParseMozSampleSize(nsDependentSubstring aString);
 
   // Media fragment information.
   Maybe<double>    mStart;
   Maybe<double>    mEnd;
   Maybe<nsIntRect> mClip;
   ClipUnit         mClipUnit;
   Maybe<nsIntSize> mResolution;
+  Maybe<int>       mSampleSize;
 };
 
 }} // namespace mozilla::net
 
 #endif
--- a/netwerk/protocol/http/nsHttpConnectionMgr.cpp
+++ b/netwerk/protocol/http/nsHttpConnectionMgr.cpp
@@ -2127,16 +2127,20 @@ nsHttpConnectionMgr::OnMsgShutdown(int32
 
     mCT.Enumerate(ShutdownPassCB, this);
 
     if (mTimeoutTick) {
         mTimeoutTick->Cancel();
         mTimeoutTick = nullptr;
         mTimeoutTickArmed = false;
     }
+    if (mTimer) {
+      mTimer->Cancel();
+      mTimer = nullptr;
+    }
 
     // signal shutdown complete
     nsRefPtr<nsIRunnable> runnable =
         new nsConnEvent(this, &nsHttpConnectionMgr::OnMsgShutdownConfirm,
                         0, param);
     NS_DispatchToMainThread(runnable);
 }
 
--- a/nsprpub/TAG-INFO
+++ b/nsprpub/TAG-INFO
@@ -1,1 +1,1 @@
-NSPR_4_10_4_BETA3
+NSPR_4_10_4_BETA4
--- a/nsprpub/config/prdepend.h
+++ b/nsprpub/config/prdepend.h
@@ -5,8 +5,9 @@
 
 /*
  * A dummy header file that is a dependency for all the object files.
  * Used to force a full recompilation of NSPR in Mozilla's Tinderbox
  * depend builds.  See comments in rules.mk.
  */
 
 #error "Do not include this header file."
+
--- a/nsprpub/configure
+++ b/nsprpub/configure
@@ -50,16 +50,18 @@ ac_help="$ac_help
 ac_help="$ac_help
   --enable-symbian-target=\$t
                           Specify symbian flavor. (WINSCW or GCCE)"
 ac_help="$ac_help
   --enable-debug-rtl      Use the MSVC debug runtime library"
 ac_help="$ac_help
   --enable-n32            Enable n32 ABI support (IRIX only)"
 ac_help="$ac_help
+  --enable-x32            Enable x32 ABI support (x86_64 only)"
+ac_help="$ac_help
   --enable-64bit          Enable 64-bit support (on certain platforms)"
 ac_help="$ac_help
   --enable-mdupdate       Enable use of certain compilers' mdupdate feature"
 ac_help="$ac_help
   --enable-cplus          Enable some c++ api routines"
 ac_help="$ac_help
   --with-arm-kuser        Use kuser helpers (Linux/ARM only)
                           (Requires kernel 2.6.13 or later)"
@@ -667,17 +669,17 @@ esac
 
 
 # Make sure we can run config.sub.
 if ${CONFIG_SHELL-/bin/sh} $ac_config_sub sun4 >/dev/null 2>&1; then :
 else { echo "configure: error: can not run $ac_config_sub" 1>&2; exit 1; }
 fi
 
 echo $ac_n "checking host system type""... $ac_c" 1>&6
-echo "configure:676: checking host system type" >&5
+echo "configure:678: checking host system type" >&5
 
 host_alias=$host
 case "$host_alias" in
 NONE)
   case $nonopt in
   NONE)
     if host_alias=`${CONFIG_SHELL-/bin/sh} $ac_config_guess`; then :
     else { echo "configure: error: can not guess host type; you must specify one" 1>&2; exit 1; }
@@ -688,17 +690,17 @@ esac
 
 host=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $host_alias`
 host_cpu=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
 host_vendor=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
 host_os=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
 echo "$ac_t""$host" 1>&6
 
 echo $ac_n "checking target system type""... $ac_c" 1>&6
-echo "configure:697: checking target system type" >&5
+echo "configure:699: checking target system type" >&5
 
 target_alias=$target
 case "$target_alias" in
 NONE)
   case $nonopt in
   NONE) target_alias=$host_alias ;;
   *) target_alias=$nonopt ;;
   esac ;;
@@ -706,17 +708,17 @@ esac
 
 target=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $target_alias`
 target_cpu=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
 target_vendor=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
 target_os=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
 echo "$ac_t""$target" 1>&6
 
 echo $ac_n "checking build system type""... $ac_c" 1>&6
-echo "configure:715: checking build system type" >&5
+echo "configure:717: checking build system type" >&5
 
 build_alias=$build
 case "$build_alias" in
 NONE)
   case $nonopt in
   NONE) build_alias=$host_alias ;;
   *) build_alias=$nonopt ;;
   esac ;;
@@ -738,16 +740,17 @@ MOD_MAJOR_VERSION=4
 MOD_MINOR_VERSION=10
 MOD_PATCH_VERSION=4
 NSPR_MODNAME=nspr20
 _HAVE_PTHREADS=
 USE_PTHREADS=
 USE_USER_PTHREADS=
 USE_NSPR_THREADS=
 USE_N32=
+USE_X32=
 USE_64=
 USE_CPLUS=
 USE_IPV6=
 USE_MDUPDATE=
 _MACOSX_DEPLOYMENT_TARGET=
 _OPTIMIZE_FLAGS=-O
 _DEBUG_FLAGS=-g
 MOZ_DEBUG=1
@@ -782,17 +785,17 @@ case "$target" in
 *-cygwin*|*-mingw*)
     # Check to see if we are really running in a msvc environemnt
     _WIN32_MSVC=
     for ac_prog in cl
 do
 # Extract the first word of "$ac_prog", so it can be a program name with args.
 set dummy $ac_prog; ac_word=$2
 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:791: checking for $ac_word" >&5
+echo "configure:794: checking for $ac_word" >&5
 if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   if test -n "$CC"; then
   ac_cv_prog_CC="$CC" # Let the user override the test.
 else
   IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
   ac_dummy="$PATH"
@@ -926,17 +929,17 @@ else
 case "$target" in
 *-android*|*-linuxandroid*)
     if test -z "$android_ndk" ; then
        { echo "configure: error: You must specify --with-android-ndk=/path/to/ndk when targeting Android." 1>&2; exit 1; }
     fi
 
     if test -z "$android_toolchain" ; then
         echo $ac_n "checking for android toolchain directory""... $ac_c" 1>&6
-echo "configure:935: checking for android toolchain directory" >&5
+echo "configure:938: checking for android toolchain directory" >&5
 
         kernel_name=`uname -s | tr "[:upper:]" "[:lower:]"`
 
         case "$target_cpu" in
         arm)
             target_name=arm-linux-androideabi-4.4.3
             ;;
         i?86)
@@ -952,17 +955,17 @@ echo "configure:935: checking for androi
             echo "$ac_t""$android_toolchain" 1>&6
         else
             { echo "configure: error: not found. You have to specify --with-android-toolchain=/path/to/ndk/toolchain." 1>&2; exit 1; }
         fi
     fi
 
     if test -z "$android_platform" ; then
         echo $ac_n "checking for android platform directory""... $ac_c" 1>&6
-echo "configure:961: checking for android platform directory" >&5
+echo "configure:964: checking for android platform directory" >&5
 
         case "$target_cpu" in
         arm)
             target_name=arm
             ;;
         i?86)
             target_name=x86
             ;;
@@ -1168,16 +1171,28 @@ if test "${enable_n32+set}" = set; then
 	USE_N32=1
       else if test "$enableval" = "no"; then
 	USE_N32=
       fi
     fi 
 fi
 
 
+# Check whether --enable-x32 or --disable-x32 was given.
+if test "${enable_x32+set}" = set; then
+  enableval="$enable_x32"
+   if test "$enableval" = "yes"; then
+        USE_X32=1
+      else if test "$enableval" = "no"; then
+        USE_X32=
+      fi
+    fi 
+fi
+
+
 # Check whether --enable-64bit or --disable-64bit was given.
 if test "${enable_64bit+set}" = set; then
   enableval="$enable_64bit"
    if test "$enableval" = "yes"; then
 	    USE_64=1
       fi 
 fi
 
@@ -1310,17 +1325,17 @@ if test -z "$CXX"; then
 
     esac
 fi
 
 if test -z "$SKIP_PATH_CHECKS"; then
     # Extract the first word of "$WHOAMI whoami", so it can be a program name with args.
 set dummy $WHOAMI whoami; ac_word=$2
 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:1319: checking for $ac_word" >&5
+echo "configure:1334: checking for $ac_word" >&5
 if eval "test \"`echo '$''{'ac_cv_path_WHOAMI'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   case "$WHOAMI" in
   /*)
   ac_cv_path_WHOAMI="$WHOAMI" # Let the user override the test with a path.
   ;;
   ?:/*)			 
@@ -1382,23 +1397,23 @@ if test "$target" != "$host" -o -n "$CRO
     echo "cross compiling from $host to $target"
     cross_compiling=yes
 
     _SAVE_CC="$CC"
     _SAVE_CFLAGS="$CFLAGS"
     _SAVE_LDFLAGS="$LDFLAGS"
 
     echo $ac_n "checking for $host compiler""... $ac_c" 1>&6
-echo "configure:1391: checking for $host compiler" >&5
+echo "configure:1406: checking for $host compiler" >&5
     for ac_prog in $HOST_CC gcc cc /usr/ucb/cc
 do
 # Extract the first word of "$ac_prog", so it can be a program name with args.
 set dummy $ac_prog; ac_word=$2
 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:1397: checking for $ac_word" >&5
+echo "configure:1412: checking for $ac_word" >&5
 if eval "test \"`echo '$''{'ac_cv_prog_HOST_CC'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   if test -n "$HOST_CC"; then
   ac_cv_prog_HOST_CC="$HOST_CC" # Let the user override the test.
 else
   IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
   ac_dummy="$PATH"
@@ -1434,26 +1449,26 @@ test -n "$HOST_CC" || HOST_CC=""""
         HOST_LDFLAGS="$LDFLAGS"
     fi
 
     CC="$HOST_CC"
     CFLAGS="$HOST_CFLAGS"
     LDFLAGS="$HOST_LDFLAGS"
 
     echo $ac_n "checking whether the $host compiler ($HOST_CC $HOST_CFLAGS $HOST_LDFLAGS) works""... $ac_c" 1>&6
-echo "configure:1443: checking whether the $host compiler ($HOST_CC $HOST_CFLAGS $HOST_LDFLAGS) works" >&5
+echo "configure:1458: checking whether the $host compiler ($HOST_CC $HOST_CFLAGS $HOST_LDFLAGS) works" >&5
     cat > conftest.$ac_ext <<EOF
-#line 1445 "configure"
+#line 1460 "configure"
 #include "confdefs.h"
 
 int main() {
 return 0;
 ; return 0; }
 EOF
-if { (eval echo configure:1452: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:1467: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
   rm -rf conftest*
   echo "$ac_t""yes" 1>&6
 else
   echo "configure: failed program was:" >&5
   cat conftest.$ac_ext >&5
   rm -rf conftest*
   { echo "configure: error: installation or configuration problem: $host compiler $HOST_CC cannot create executables." 1>&2; exit 1; } 
 fi
@@ -1478,17 +1493,17 @@ rm -f conftest*
         ;;
     esac
 
     for ac_prog in $CC "${target_alias}-gcc" "${target}-gcc"
 do
 # Extract the first word of "$ac_prog", so it can be a program name with args.
 set dummy $ac_prog; ac_word=$2
 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:1487: checking for $ac_word" >&5
+echo "configure:1502: checking for $ac_word" >&5
 if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   if test -n "$CC"; then
   ac_cv_prog_CC="$CC" # Let the user override the test.
 else
   IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
   ac_dummy="$PATH"
@@ -1512,17 +1527,17 @@ fi
 test -n "$CC" && break
 done
 test -n "$CC" || CC="echo"
 
     unset ac_cv_prog_CC
     # Extract the first word of "gcc", so it can be a program name with args.
 set dummy gcc; ac_word=$2
 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:1521: checking for $ac_word" >&5
+echo "configure:1536: checking for $ac_word" >&5
 if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   if test -n "$CC"; then
   ac_cv_prog_CC="$CC" # Let the user override the test.
 else
   IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
   ac_dummy="$PATH"
@@ -1542,17 +1557,17 @@ if test -n "$CC"; then
 else
   echo "$ac_t""no" 1>&6
 fi
 
 if test -z "$CC"; then
   # Extract the first word of "cc", so it can be a program name with args.
 set dummy cc; ac_word=$2
 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:1551: checking for $ac_word" >&5
+echo "configure:1566: checking for $ac_word" >&5
 if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   if test -n "$CC"; then
   ac_cv_prog_CC="$CC" # Let the user override the test.
 else
   IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
   ac_prog_rejected=no
@@ -1593,17 +1608,17 @@ else
 fi
 
   if test -z "$CC"; then
     case "`uname -s`" in
     *win32* | *WIN32*)
       # Extract the first word of "cl", so it can be a program name with args.
 set dummy cl; ac_word=$2
 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:1602: checking for $ac_word" >&5
+echo "configure:1617: checking for $ac_word" >&5
 if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   if test -n "$CC"; then
   ac_cv_prog_CC="$CC" # Let the user override the test.
 else
   IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
   ac_dummy="$PATH"
@@ -1625,33 +1640,33 @@ else
 fi
  ;;
     esac
   fi
   test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; }
 fi
 
 echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6
-echo "configure:1634: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5
+echo "configure:1649: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5
 
 ac_ext=c
 # CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
 ac_cpp='$CPP $CPPFLAGS'
 ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
 ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
 cross_compiling=$ac_cv_prog_cc_cross
 
 cat > conftest.$ac_ext << EOF
 
-#line 1645 "configure"
+#line 1660 "configure"
 #include "confdefs.h"
 
 main(){return(0);}
 EOF
-if { (eval echo configure:1650: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:1665: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
   ac_cv_prog_cc_works=yes
   # If we can't run a trivial program, we are probably using a cross compiler.
   if (./conftest; exit) 2>/dev/null; then
     ac_cv_prog_cc_cross=no
   else
     ac_cv_prog_cc_cross=yes
   fi
 else
@@ -1667,31 +1682,31 @@ ac_compile='${CC-cc} -c $CFLAGS $CPPFLAG
 ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
 cross_compiling=$ac_cv_prog_cc_cross
 
 echo "$ac_t""$ac_cv_prog_cc_works" 1>&6
 if test $ac_cv_prog_cc_works = no; then
   { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; }
 fi
 echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6
-echo "configure:1676: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5
+echo "configure:1691: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5
 echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6
 cross_compiling=$ac_cv_prog_cc_cross
 
 echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6
-echo "configure:1681: checking whether we are using GNU C" >&5
+echo "configure:1696: checking whether we are using GNU C" >&5
 if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.c <<EOF
 #ifdef __GNUC__
   yes;
 #endif
 EOF
-if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:1690: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
+if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:1705: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
   ac_cv_prog_gcc=yes
 else
   ac_cv_prog_gcc=no
 fi
 fi
 
 echo "$ac_t""$ac_cv_prog_gcc" 1>&6
 
@@ -1700,17 +1715,17 @@ if test $ac_cv_prog_gcc = yes; then
 else
   GCC=
 fi
 
 ac_test_CFLAGS="${CFLAGS+set}"
 ac_save_CFLAGS="$CFLAGS"
 CFLAGS=
 echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6
-echo "configure:1709: checking whether ${CC-cc} accepts -g" >&5
+echo "configure:1724: checking whether ${CC-cc} accepts -g" >&5
 if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   echo 'void f(){}' > conftest.c
 if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then
   ac_cv_prog_cc_g=yes
 else
   ac_cv_prog_cc_g=no
@@ -1737,17 +1752,17 @@ else
 fi
 
     if test -n "$USE_CPLUS"; then
         for ac_prog in $CXX "${target_alias}-g++" "${target}-g++"
 do
 # Extract the first word of "$ac_prog", so it can be a program name with args.
 set dummy $ac_prog; ac_word=$2
 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:1746: checking for $ac_word" >&5
+echo "configure:1761: checking for $ac_word" >&5
 if eval "test \"`echo '$''{'ac_cv_prog_CXX'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   if test -n "$CXX"; then
   ac_cv_prog_CXX="$CXX" # Let the user override the test.
 else
   IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
   ac_dummy="$PATH"
@@ -1773,17 +1788,17 @@ done
 test -n "$CXX" || CXX="echo"
 
         unset ac_cv_prog_CXX
         for ac_prog in $CCC c++ g++ gcc CC cxx cc++ cl
 do
 # Extract the first word of "$ac_prog", so it can be a program name with args.
 set dummy $ac_prog; ac_word=$2
 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:1782: checking for $ac_word" >&5
+echo "configure:1797: checking for $ac_word" >&5
 if eval "test \"`echo '$''{'ac_cv_prog_CXX'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   if test -n "$CXX"; then
   ac_cv_prog_CXX="$CXX" # Let the user override the test.
 else
   IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
   ac_dummy="$PATH"
@@ -1805,33 +1820,33 @@ else
 fi
 
 test -n "$CXX" && break
 done
 test -n "$CXX" || CXX="gcc"
 
 
 echo $ac_n "checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) works""... $ac_c" 1>&6
-echo "configure:1814: checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) works" >&5
+echo "configure:1829: checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) works" >&5
 
 ac_ext=C
 # CXXFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
 ac_cpp='$CXXCPP $CPPFLAGS'
 ac_compile='${CXX-g++} -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
 ac_link='${CXX-g++} -o conftest${ac_exeext} $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
 cross_compiling=$ac_cv_prog_cxx_cross
 
 cat > conftest.$ac_ext << EOF
 
-#line 1825 "configure"
+#line 1840 "configure"
 #include "confdefs.h"
 
 int main(){return(0);}
 EOF
-if { (eval echo configure:1830: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:1845: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
   ac_cv_prog_cxx_works=yes
   # If we can't run a trivial program, we are probably using a cross compiler.
   if (./conftest; exit) 2>/dev/null; then
     ac_cv_prog_cxx_cross=no
   else
     ac_cv_prog_cxx_cross=yes
   fi
 else
@@ -1847,31 +1862,31 @@ ac_compile='${CC-cc} -c $CFLAGS $CPPFLAG
 ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
 cross_compiling=$ac_cv_prog_cc_cross
 
 echo "$ac_t""$ac_cv_prog_cxx_works" 1>&6
 if test $ac_cv_prog_cxx_works = no; then
   { echo "configure: error: installation or configuration problem: C++ compiler cannot create executables." 1>&2; exit 1; }
 fi
 echo $ac_n "checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6
-echo "configure:1856: checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) is a cross-compiler" >&5
+echo "configure:1871: checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) is a cross-compiler" >&5
 echo "$ac_t""$ac_cv_prog_cxx_cross" 1>&6
 cross_compiling=$ac_cv_prog_cxx_cross
 
 echo $ac_n "checking whether we are using GNU C++""... $ac_c" 1>&6
-echo "configure:1861: checking whether we are using GNU C++" >&5
+echo "configure:1876: checking whether we are using GNU C++" >&5
 if eval "test \"`echo '$''{'ac_cv_prog_gxx'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.C <<EOF
 #ifdef __GNUC__
   yes;
 #endif
 EOF
-if { ac_try='${CXX-g++} -E conftest.C'; { (eval echo configure:1870: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
+if { ac_try='${CXX-g++} -E conftest.C'; { (eval echo configure:1885: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
   ac_cv_prog_gxx=yes
 else
   ac_cv_prog_gxx=no
 fi
 fi
 
 echo "$ac_t""$ac_cv_prog_gxx" 1>&6
 
@@ -1880,17 +1895,17 @@ if test $ac_cv_prog_gxx = yes; then
 else
   GXX=
 fi
 
 ac_test_CXXFLAGS="${CXXFLAGS+set}"
 ac_save_CXXFLAGS="$CXXFLAGS"
 CXXFLAGS=
 echo $ac_n "checking whether ${CXX-g++} accepts -g""... $ac_c" 1>&6
-echo "configure:1889: checking whether ${CXX-g++} accepts -g" >&5
+echo "configure:1904: checking whether ${CXX-g++} accepts -g" >&5
 if eval "test \"`echo '$''{'ac_cv_prog_cxx_g'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   echo 'void f(){}' > conftest.cc
 if test -z "`${CXX-g++} -g -c conftest.cc 2>&1`"; then
   ac_cv_prog_cxx_g=yes
 else
   ac_cv_prog_cxx_g=no
</