Merge m-c to inbound a=merge
authorWes Kocher <wkocher@mozilla.com>
Tue, 28 Oct 2014 19:09:36 -0700
changeset 212805 6bc7eedcee7f1b1255193808186d2c23597cb826
parent 212804 7584884dbed7eec2164448d115b9797d9f5e0f16 (current diff)
parent 212789 7e3c85754d32544625f785703d98e0e7d0ee4daf (diff)
child 212806 79b64654f809b9294d5142e31c0c33471c85532f
push id27730
push usercbook@mozilla.com
push dateWed, 29 Oct 2014 12:26:03 +0000
treeherdermozilla-central@fe5c1cb8075a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone36.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge m-c to inbound a=merge
--- a/b2g/config/dolphin/sources.xml
+++ b/b2g/config/dolphin/sources.xml
@@ -10,25 +10,25 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="3a2947df41a480de1457a6dcdbf46ad0af70d8e0">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="b48f66220dff75f767eddf28a1d58192fc811410"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="35e87ac4324f0f3abd93dcc70d61c9f37256a0f5"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="f718a14ed4963ac99d613b7ba7a997dae7b13d70"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="28be739bcdcbc9eb91c0bdbff1f7d3eab717969b"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="ebdad82e61c16772f6cd47e9f11936bf6ebe9aa0"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="8b880805d454664b3eed11d0f053cdeafa1ff06e"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" revision="a1e239a0bb5cd1d69680bf1075883aa9a7bf2429"/>
   <project groups="linux,x86" name="platform/prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" path="prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" revision="c7931763d41be602407ed9d71e2c0292c6597e00"/>
   <project groups="linux,x86" name="platform/prebuilts/python/linux-x86/2.7.5" path="prebuilts/python/linux-x86/2.7.5" revision="83760d213fb3bec7b4117d266fcfbf6fe2ba14ab"/>
   <project name="device/common" path="device/common" revision="6a2995683de147791e516aae2ccb31fdfbe2ad30"/>
--- a/b2g/config/emulator-ics/sources.xml
+++ b/b2g/config/emulator-ics/sources.xml
@@ -14,23 +14,23 @@
   <!--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="70eb0cb0977d6295e7da8896f9efb9f3ca1c13ea">
     <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="b48f66220dff75f767eddf28a1d58192fc811410"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="35e87ac4324f0f3abd93dcc70d61c9f37256a0f5"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="c058843242068d0df7c107e09da31b53d2e08fa6"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="f718a14ed4963ac99d613b7ba7a997dae7b13d70"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="28be739bcdcbc9eb91c0bdbff1f7d3eab717969b"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
   <project name="platform/bionic" path="bionic" revision="c72b8f6359de7ed17c11ddc9dfdde3f615d188a9"/>
   <project name="platform/bootable/recovery" path="bootable/recovery" revision="425f8b5fadf5889834c5acd27d23c9e0b2129c28"/>
   <project name="device/common" path="device/common" revision="42b808b7e93d0619286ae8e59110b176b7732389"/>
   <project name="device/sample" path="device/sample" revision="237bd668d0f114d801a8d6455ef5e02cc3577587"/>
   <project name="platform_external_apriori" path="external/apriori" remote="b2g" revision="11816ad0406744f963537b23d68ed9c2afb412bd"/>
   <project name="platform/external/bluetooth/bluez" path="external/bluetooth/bluez" revision="52a1a862a8bac319652b8f82d9541ba40bfa45ce"/>
--- a/b2g/config/emulator-jb/sources.xml
+++ b/b2g/config/emulator-jb/sources.xml
@@ -12,20 +12,20 @@
   <!--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="8986df0f82e15ac2798df0b6c2ee3435400677ac">
     <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="b48f66220dff75f767eddf28a1d58192fc811410"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="35e87ac4324f0f3abd93dcc70d61c9f37256a0f5"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="f718a14ed4963ac99d613b7ba7a997dae7b13d70"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="28be739bcdcbc9eb91c0bdbff1f7d3eab717969b"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="9025e50b9d29b3cabbbb21e1dd94d0d13121a17e"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="b89fda71fcd0fa0cf969310e75be3ea33e048b44"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="2e7d5348f35575870b3c7e567a9a9f6d66f8d6c5"/>
--- a/b2g/config/emulator-kk/sources.xml
+++ b/b2g/config/emulator-kk/sources.xml
@@ -10,25 +10,25 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="3a2947df41a480de1457a6dcdbf46ad0af70d8e0">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="b48f66220dff75f767eddf28a1d58192fc811410"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="35e87ac4324f0f3abd93dcc70d61c9f37256a0f5"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="f718a14ed4963ac99d613b7ba7a997dae7b13d70"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="28be739bcdcbc9eb91c0bdbff1f7d3eab717969b"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="f92a936f2aa97526d4593386754bdbf02db07a12"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="6e47ff2790f5656b5b074407829ceecf3e6188c4"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="1950e4760fa14688b83cdbb5acaa1af9f82ef434"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" revision="ac6eb97a37035c09fb5ede0852f0881e9aadf9ad"/>
   <project groups="linux,x86" name="platform/prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" path="prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" revision="737f591c5f95477148d26602c7be56cbea0cdeb9"/>
   <project groups="linux,x86" name="platform/prebuilts/python/linux-x86/2.7.5" path="prebuilts/python/linux-x86/2.7.5" revision="51da9b1981be481b92a59a826d4d78dc73d0989a"/>
   <project name="device/common" path="device/common" revision="798a3664597e6041985feab9aef42e98d458bc3d"/>
--- a/b2g/config/emulator/sources.xml
+++ b/b2g/config/emulator/sources.xml
@@ -14,23 +14,23 @@
   <!--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="70eb0cb0977d6295e7da8896f9efb9f3ca1c13ea">
     <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="b48f66220dff75f767eddf28a1d58192fc811410"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="35e87ac4324f0f3abd93dcc70d61c9f37256a0f5"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="c058843242068d0df7c107e09da31b53d2e08fa6"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="f718a14ed4963ac99d613b7ba7a997dae7b13d70"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="28be739bcdcbc9eb91c0bdbff1f7d3eab717969b"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
   <project name="platform/bionic" path="bionic" revision="c72b8f6359de7ed17c11ddc9dfdde3f615d188a9"/>
   <project name="platform/bootable/recovery" path="bootable/recovery" revision="425f8b5fadf5889834c5acd27d23c9e0b2129c28"/>
   <project name="device/common" path="device/common" revision="42b808b7e93d0619286ae8e59110b176b7732389"/>
   <project name="device/sample" path="device/sample" revision="237bd668d0f114d801a8d6455ef5e02cc3577587"/>
   <project name="platform_external_apriori" path="external/apriori" remote="b2g" revision="11816ad0406744f963537b23d68ed9c2afb412bd"/>
   <project name="platform/external/bluetooth/bluez" path="external/bluetooth/bluez" revision="52a1a862a8bac319652b8f82d9541ba40bfa45ce"/>
--- a/b2g/config/flame-kk/sources.xml
+++ b/b2g/config/flame-kk/sources.xml
@@ -10,25 +10,25 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="3a2947df41a480de1457a6dcdbf46ad0af70d8e0">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="b48f66220dff75f767eddf28a1d58192fc811410"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="35e87ac4324f0f3abd93dcc70d61c9f37256a0f5"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="f718a14ed4963ac99d613b7ba7a997dae7b13d70"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="28be739bcdcbc9eb91c0bdbff1f7d3eab717969b"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="ebdad82e61c16772f6cd47e9f11936bf6ebe9aa0"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="8b880805d454664b3eed11d0f053cdeafa1ff06e"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" revision="a1e239a0bb5cd1d69680bf1075883aa9a7bf2429"/>
   <project groups="linux,x86" name="platform/prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" path="prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" revision="c7931763d41be602407ed9d71e2c0292c6597e00"/>
   <project groups="linux,x86" name="platform/prebuilts/python/linux-x86/2.7.5" path="prebuilts/python/linux-x86/2.7.5" revision="a32003194f707f66a2d8cdb913ed1869f1926c5d"/>
   <project name="device/common" path="device/common" revision="96d4d2006c4fcb2f19a3fa47ab10cb409faa017b"/>
@@ -127,17 +127,17 @@
   <remove-project name="platform/hardware/libhardware"/>
   <remove-project name="platform/external/bluetooth/bluedroid"/>
   <!--original fetch url was git://github.com/t2m-foxfone/-->
   <remote fetch="https://git.mozilla.org/external/t2m-foxfone" name="t2m"/>
   <default remote="caf" revision="LNX.LA.3.5.2.1.1" sync-j="4"/>
   <!-- Flame specific things -->
   <project name="device/generic/armv7-a-neon" path="device/generic/armv7-a-neon" revision="1bb28abbc215f45220620af5cd60a8ac1be93722"/>
   <project name="device/qcom/common" path="device/qcom/common" revision="54c32c2ddef066fbdf611d29e4b7c47e0363599e"/>
-  <project name="device-flame" path="device/t2m/flame" remote="b2g" revision="6e51d9216901d39d192d9e6dd86a5e15b0641a89"/>
+  <project name="device-flame" path="device/t2m/flame" remote="b2g" revision="48835395daa6a49b281db62c50805bd6ca24077e"/>
   <project name="codeaurora_kernel_msm" path="kernel" remote="b2g" revision="3c4f041e3e3dc676f2111caf20a186ec0467dbdb"/>
   <project name="kernel_lk" path="bootable/bootloader/lk" remote="b2g" revision="fda40423ffa573dc6cafd3780515010cb2a086be"/>
   <project name="platform/external/bluetooth/bluedroid" path="external/bluetooth/bluedroid" revision="30b96dfca99cb384bf520a16b81f3aba56f09907"/>
   <project name="platform/external/wpa_supplicant_8" path="external/wpa_supplicant_8" revision="5b71e40213f650459e95d35b6f14af7e88d8ab62"/>
   <project name="platform_external_libnfc-nci" path="external/libnfc-nci" remote="t2m" revision="4186bdecb4dae911b39a8202252cc2310d91b0be"/>
   <project name="platform/frameworks/av" path="frameworks/av" revision="c00de33ebfad57ae79ad5f93c2819ee2c40c8bcd"/>
   <project name="platform/frameworks/base" path="frameworks/base" revision="6b58ab45e3e56c1fc20708cc39fa2264c52558df"/>
   <project name="platform/frameworks/native" path="frameworks/native" revision="a46a9f1ac0ed5662d614c277cbb14eb3f332f365"/>
--- a/b2g/config/flame/sources.xml
+++ b/b2g/config/flame/sources.xml
@@ -12,20 +12,20 @@
   <!--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="8986df0f82e15ac2798df0b6c2ee3435400677ac">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="b48f66220dff75f767eddf28a1d58192fc811410"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="35e87ac4324f0f3abd93dcc70d61c9f37256a0f5"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="f718a14ed4963ac99d613b7ba7a997dae7b13d70"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="28be739bcdcbc9eb91c0bdbff1f7d3eab717969b"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="e95b4ce22c825da44d14299e1190ea39a5260bde"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="471afab478649078ad7c75ec6b252481a59e19b8"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="ebdad82e61c16772f6cd47e9f11936bf6ebe9aa0"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="8b880805d454664b3eed11d0f053cdeafa1ff06e"/>
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,9 +1,9 @@
 {
     "git": {
         "git_revision": "", 
         "remote": "", 
         "branch": ""
     }, 
-    "revision": "f797c345e7f872424ce9fd24f1bd3b769cd6dc9d", 
+    "revision": "05b9edce84513940b9fdfe582d005bdf7171fa5a", 
     "repo_path": "/integration/gaia-central"
 }
--- a/b2g/config/hamachi/sources.xml
+++ b/b2g/config/hamachi/sources.xml
@@ -12,22 +12,22 @@
   <!--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="70eb0cb0977d6295e7da8896f9efb9f3ca1c13ea">
     <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="b48f66220dff75f767eddf28a1d58192fc811410"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="35e87ac4324f0f3abd93dcc70d61c9f37256a0f5"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="f718a14ed4963ac99d613b7ba7a997dae7b13d70"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="28be739bcdcbc9eb91c0bdbff1f7d3eab717969b"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
   <project name="platform/bootable/recovery" path="bootable/recovery" revision="746bc48f34f5060f90801925dcdd964030c1ab6d"/>
   <project name="platform/development" path="development" revision="2460485184bc8535440bb63876d4e63ec1b4770c"/>
   <project name="device/common" path="device/common" revision="0dcc1e03659db33b77392529466f9eb685cdd3c7"/>
   <project name="device/sample" path="device/sample" revision="68b1cb978a20806176123b959cb05d4fa8adaea4"/>
   <project name="platform_external_apriori" path="external/apriori" remote="b2g" revision="11816ad0406744f963537b23d68ed9c2afb412bd"/>
--- 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="70eb0cb0977d6295e7da8896f9efb9f3ca1c13ea">
     <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="b48f66220dff75f767eddf28a1d58192fc811410"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="35e87ac4324f0f3abd93dcc70d61c9f37256a0f5"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <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/nexus-4/sources.xml
+++ b/b2g/config/nexus-4/sources.xml
@@ -12,20 +12,20 @@
   <!--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="8986df0f82e15ac2798df0b6c2ee3435400677ac">
     <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="b48f66220dff75f767eddf28a1d58192fc811410"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="35e87ac4324f0f3abd93dcc70d61c9f37256a0f5"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="f718a14ed4963ac99d613b7ba7a997dae7b13d70"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="28be739bcdcbc9eb91c0bdbff1f7d3eab717969b"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="9025e50b9d29b3cabbbb21e1dd94d0d13121a17e"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="b89fda71fcd0fa0cf969310e75be3ea33e048b44"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="2e7d5348f35575870b3c7e567a9a9f6d66f8d6c5"/>
--- a/b2g/config/wasabi/sources.xml
+++ b/b2g/config/wasabi/sources.xml
@@ -12,22 +12,22 @@
   <!--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="70eb0cb0977d6295e7da8896f9efb9f3ca1c13ea">
     <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="b48f66220dff75f767eddf28a1d58192fc811410"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="35e87ac4324f0f3abd93dcc70d61c9f37256a0f5"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="f718a14ed4963ac99d613b7ba7a997dae7b13d70"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="28be739bcdcbc9eb91c0bdbff1f7d3eab717969b"/>
   <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="cd5dfce80bc3f0139a56b58aca633202ccaee7f8"/>
   <project name="platform/bootable/recovery" path="bootable/recovery" revision="e0a9ac010df3afaa47ba107192c05ac8b5516435"/>
   <project name="platform/development" path="development" revision="a384622f5fcb1d2bebb9102591ff7ae91fe8ed2d"/>
   <project name="device/common" path="device/common" revision="7c65ea240157763b8ded6154a17d3c033167afb7"/>
   <project name="device/sample" path="device/sample" revision="c328f3d4409db801628861baa8d279fb8855892f"/>
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1761,8 +1761,15 @@ pref("experiments.supported", true);
 
 // Enable the OpenH264 plugin support in the addon manager.
 pref("media.gmp-gmpopenh264.provider.enabled", true);
 
 pref("browser.apps.URL", "https://marketplace.firefox.com/discovery/");
 
 pref("browser.polaris.enabled", false);
 pref("privacy.trackingprotection.ui.enabled", false);
+
+// Temporary pref to allow printing in e10s windows on some platforms.
+#ifdef UNIX_BUT_NOT_MAC
+pref("print.enable_e10s_testing", false);
+#else
+pref("print.enable_e10s_testing", true);
+#endif
--- a/browser/base/content/browser-sets.inc
+++ b/browser/base/content/browser-sets.inc
@@ -23,17 +23,17 @@
     <command id="cmd_newNavigatorTab" oncommand="BrowserOpenNewTabOrWindow(event);"/>
     <command id="Browser:OpenFile"  oncommand="BrowserOpenFileWindow();"/>
     <command id="Browser:SavePage" oncommand="saveDocument(window.content.document);"/>
 
     <command id="Browser:SendLink"
              oncommand="MailIntegration.sendLinkForWindow(window.content);"/>
 
     <command id="cmd_pageSetup" oncommand="PrintUtils.showPageSetup();"/>
-    <command id="cmd_print" oncommand="PrintUtils.print();"/>
+    <command id="cmd_print" oncommand="PrintUtils.print(window.gBrowser.selectedBrowser.contentWindowAsCPOW, window.gBrowser.selectedBrowser);"/>
     <command id="cmd_printPreview" oncommand="PrintUtils.printPreview(PrintPreviewListener);"/>
     <command id="cmd_close" oncommand="BrowserCloseTabOrWindow()"/>
     <command id="cmd_closeWindow" oncommand="BrowserTryToCloseWindow()"/>
     <command id="cmd_CustomizeToolbars" oncommand="BrowserCustomizeToolbar()"/>
     <command id="cmd_quitApplication" oncommand="goQuitApplication()"/>
 
 
     <commandset id="editMenuCommands"/>
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -1658,17 +1658,18 @@ function HandleAppCommandEvent(evt) {
     break;
   case "Help":
     openHelpLink('firefox-help');
     break;
   case "Open":
     BrowserOpenFileWindow();
     break;
   case "Print":
-    PrintUtils.print();
+    PrintUtils.print(gBrowser.selectedBrowser.contentWindowAsCPOW,
+                     gBrowser.selectedBrowser);
     break;
   case "Save":
     saveDocument(window.content.document);
     break;
   case "SendMail":
     MailIntegration.sendLinkForWindow(window.content);
     break;
   default:
--- a/browser/components/loop/LoopCalls.jsm
+++ b/browser/components/loop/LoopCalls.jsm
@@ -289,17 +289,18 @@ let LoopCallsInternal = {
    */
   startDirectCall: function(contact, callType) {
     if (this.callsData.inUse)
       return false;
 
     var callData = {
       contact: contact,
       callType: callType,
-      callId: Math.floor((Math.random() * 10))
+      // XXX Really we shouldn't be using random numbers, bug 1090209 will fix this.
+      callId: Math.floor((Math.random() * 100000000))
     };
 
     this._startCall(callData, "outgoing");
     return true;
   },
 
    /**
    * Open call progress websocket and terminate with a reason of busy
--- a/browser/components/loop/content/shared/css/conversation.css
+++ b/browser/components/loop/content/shared/css/conversation.css
@@ -566,28 +566,27 @@
   background-position: center;
   border-radius: 50%;
 }
 
   .fx-embedded-tiny-video-icon.muted {
     background-color: rgba(0,0,0,.2)
   }
 
-@media screen and (min-width:640px) {
+/* Force full height on all parents up to the video elements
+ * this way we can ensure the aspect ratio and use height 100%
+ * on the video element
+ * */
+html, .fx-embedded, #main,
+.video-layout-wrapper,
+.conversation {
+  height: 100%;
+}
 
-  /* Force full height on all parents up to the video elements
-   * this way we can ensure the aspect ratio and use height 100%
-   * on the video element
-   * */
-  html, body, #main,
-  .video-layout-wrapper,
-  .conversation {
-    height: 100%;
-  }
-
+@media screen and (min-width:640px) {
   .standalone .conversation-toolbar {
     position: absolute;
     bottom: 0;
     left: 0;
     right: 0;
   }
 
   .fx-embedded .local-stream {
--- a/browser/devtools/main.js
+++ b/browser/devtools/main.js
@@ -112,17 +112,17 @@ Tools.inspector = {
   ],
 
   preventClosingOnKey: true,
   onkey: function(panel) {
     panel.toolbox.highlighterUtils.togglePicker();
   },
 
   isTargetSupported: function(target) {
-    return !target.isAddon;
+    return !target.isAddon && target.hasActor("inspector");
   },
 
   build: function(iframeWindow, toolbox) {
     return new InspectorPanel(iframeWindow, toolbox);
   }
 };
 
 Tools.webConsole = {
@@ -194,17 +194,18 @@ Tools.styleEditor = {
   url: "chrome://browser/content/devtools/styleeditor.xul",
   label: l10n("ToolboxStyleEditor.label", styleEditorStrings),
   panelLabel: l10n("ToolboxStyleEditor.panelLabel", styleEditorStrings),
   tooltip: l10n("ToolboxStyleEditor.tooltip2", styleEditorStrings),
   inMenu: true,
   commands: "devtools/styleeditor/styleeditor-commands",
 
   isTargetSupported: function(target) {
-    return !target.isAddon;
+    return !target.isAddon &&
+      (target.hasActor("styleEditor") || target.hasActor("styleSheets"));
   },
 
   build: function(iframeWindow, toolbox) {
     return new StyleEditorPanel(iframeWindow, toolbox);
   }
 };
 
 Tools.shaderEditor = {
@@ -262,17 +263,17 @@ Tools.jsprofiler = {
   label: l10n("profiler.label2", profilerStrings),
   panelLabel: l10n("profiler.panelLabel2", profilerStrings),
   tooltip: l10n("profiler.tooltip2", profilerStrings),
   inMenu: true,
 
   isTargetSupported: function (target) {
     // Hide the profiler when debugging devices pre bug 1046394,
     // that don't expose profiler actor in content processes.
-    return !target.isAddon && (!target.isApp || target.form.profilerActor);
+    return !target.isAddon && target.hasActor("profiler");
   },
 
   build: function (frame, target) {
     return new ProfilerPanel(frame, target);
   }
 };
 
 Tools.performance = {
@@ -286,19 +287,17 @@ Tools.performance = {
   panelLabel: "Performance++", //l10n("profiler.panelLabel2", profilerStrings),
   tooltip: l10n("profiler.tooltip2", profilerStrings),
   accesskey: l10n("profiler.accesskey", profilerStrings),
   key: l10n("profiler.commandkey2", profilerStrings),
   modifiers: "shift",
   inMenu: true,
 
   isTargetSupported: function (target) {
-    // Hide the profiler when debugging devices pre bug 1046394,
-    // that don't expose profiler actor in content processes.
-    return !target.isAddon && (!target.isApp || target.form.profilerActor);
+    return !target.isAddon && target.hasActor("profiler");
   },
 
   build: function (frame, target) {
     return new PerformancePanel(frame, target);
   }
 };
 
 Tools.timeline = {
@@ -333,18 +332,17 @@ Tools.netMonitor = {
   invertIconForLightTheme: true,
   url: "chrome://browser/content/devtools/netmonitor.xul",
   label: l10n("netmonitor.label", netMonitorStrings),
   panelLabel: l10n("netmonitor.panelLabel", netMonitorStrings),
   tooltip: l10n("netmonitor.tooltip", netMonitorStrings),
   inMenu: true,
 
   isTargetSupported: function(target) {
-    let root = target.client.mainRoot;
-    return !target.isAddon && (root.traits.networkMonitor || !target.isApp);
+    return !target.isAddon && target.getTrait("networkMonitor");
   },
 
   build: function(iframeWindow, toolbox) {
     return new NetMonitorPanel(iframeWindow, toolbox);
   }
 };
 
 Tools.storage = {
--- a/browser/devtools/profiler/test/browser_profiler_tree-view-01.js
+++ b/browser/devtools/profiler/test/browser_profiler_tree-view-01.js
@@ -24,17 +24,17 @@ function test() {
 
   is(container.childNodes[0].childNodes.length, 6,
     "The root node in the tree has the correct number of children.");
   is(container.childNodes[0].querySelectorAll(".call-tree-cell").length, 6,
     "The root node in the tree has only 'call-tree-cell' children.");
 
   is(container.childNodes[0].childNodes[0].getAttribute("type"), "duration",
     "The root node in the tree has a duration cell.");
-  is(container.childNodes[0].childNodes[0].getAttribute("value"), "18",
+  is(container.childNodes[0].childNodes[0].getAttribute("value"), "15",
     "The root node in the tree has the correct duration cell value.");
 
   is(container.childNodes[0].childNodes[1].getAttribute("type"), "percentage",
     "The root node in the tree has a percentage cell.");
   is(container.childNodes[0].childNodes[1].getAttribute("value"), "100%",
     "The root node in the tree has the correct percentage cell value.");
 
   is(container.childNodes[0].childNodes[2].getAttribute("type"), "self-duration",
@@ -44,17 +44,17 @@ function test() {
 
   is(container.childNodes[0].childNodes[3].getAttribute("type"), "self-percentage",
     "The root node in the tree has a self-percentage cell.");
   is(container.childNodes[0].childNodes[3].getAttribute("value"), "0%",
     "The root node in the tree has the correct self-percentage cell value.");
 
   is(container.childNodes[0].childNodes[4].getAttribute("type"), "samples",
     "The root node in the tree has an samples cell.");
-  is(container.childNodes[0].childNodes[4].getAttribute("value"), "3",
+  is(container.childNodes[0].childNodes[4].getAttribute("value"), "4",
     "The root node in the tree has the correct samples cell value.");
 
   is(container.childNodes[0].childNodes[5].getAttribute("type"), "function",
     "The root node in the tree has a function cell.");
   is(container.childNodes[0].childNodes[5].style.MozMarginStart, "0px",
     "The root node in the tree has the correct indentation.");
 
   finish();
@@ -64,24 +64,32 @@ let gSamples = [{
   time: 5,
   frames: [
     { category: 8,  location: "(root)" },
     { category: 8,  location: "A (http://foo/bar/baz:12)" },
     { category: 16, location: "B (http://foo/bar/baz:34)" },
     { category: 32, location: "C (http://foo/bar/baz:56)" }
   ]
 }, {
-  time: 5 + 6,
+  time: 5 + 1,
   frames: [
     { category: 8,  location: "(root)" },
     { category: 8,  location: "A (http://foo/bar/baz:12)" },
     { category: 16, location: "B (http://foo/bar/baz:34)" },
     { category: 64, location: "D (http://foo/bar/baz:78)" }
   ]
 }, {
-  time: 5 + 6 + 7,
+  time: 5 + 1 + 2,
+  frames: [
+    { category: 8,  location: "(root)" },
+    { category: 8,  location: "A (http://foo/bar/baz:12)" },
+    { category: 16, location: "B (http://foo/bar/baz:34)" },
+    { category: 64, location: "D (http://foo/bar/baz:78)" }
+  ]
+}, {
+  time: 5 + 1 + 2 + 7,
   frames: [
     { category: 8,   location: "(root)" },
     { category: 8,   location: "A (http://foo/bar/baz:12)" },
     { category: 128, location: "E (http://foo/bar/baz:90)" },
     { category: 256, location: "F (http://foo/bar/baz:99)" }
   ]
 }];
--- a/browser/devtools/profiler/test/browser_profiler_tree-view-02.js
+++ b/browser/devtools/profiler/test/browser_profiler_tree-view-02.js
@@ -22,21 +22,21 @@ function test() {
   let $$perc = i => container.querySelectorAll(".call-tree-cell[type=percentage]")[i];
   let $$sampl = i => container.querySelectorAll(".call-tree-cell[type=samples]")[i];
 
   is(container.childNodes.length, 1,
     "The container node should have one child available.");
   is(container.childNodes[0].className, "call-tree-item",
     "The root node in the tree has the correct class name.");
 
-  is($$dur(0).getAttribute("value"), "18",
+  is($$dur(0).getAttribute("value"), "15",
     "The root's duration cell displays the correct value.");
   is($$perc(0).getAttribute("value"), "100%",
     "The root's percentage cell displays the correct value.");
-  is($$sampl(0).getAttribute("value"), "3",
+  is($$sampl(0).getAttribute("value"), "4",
     "The root's samples cell displays the correct value.");
   is($$fun(".call-tree-name")[0].getAttribute("value"), "(root)",
     "The root's function cell displays the correct name.");
   is($$fun(".call-tree-url")[0].getAttribute("value"), "",
     "The root's function cell displays the correct url.");
   is($$fun(".call-tree-line")[0].getAttribute("value"), "",
     "The root's function cell displays the correct line.");
   is($$fun(".call-tree-host")[0].getAttribute("value"), "",
@@ -48,21 +48,21 @@ function test() {
 
   is(container.childNodes.length, 2,
     "The container node should have two children available.");
   is(container.childNodes[0].className, "call-tree-item",
     "The root node in the tree has the correct class name.");
   is(container.childNodes[1].className, "call-tree-item",
     "The .A node in the tree has the correct class name.");
 
-  is($$dur(1).getAttribute("value"), "18",
+  is($$dur(1).getAttribute("value"), "15",
     "The .A node's duration cell displays the correct value.");
   is($$perc(1).getAttribute("value"), "100%",
     "The .A node's percentage cell displays the correct value.");
-  is($$sampl(1).getAttribute("value"), "3",
+  is($$sampl(1).getAttribute("value"), "4",
     "The .A node's samples cell displays the correct value.");
   is($$fun(".call-tree-name")[1].getAttribute("value"), "A",
     "The .A node's function cell displays the correct name.");
   is($$fun(".call-tree-url")[1].getAttribute("value"), "baz",
     "The .A node's function cell displays the correct url.");
   ok($$fun(".call-tree-url")[1].getAttribute("tooltiptext").contains("http://foo/bar/baz"),
     "The .A node's function cell displays the correct url tooltiptext.");
   is($$fun(".call-tree-line")[1].getAttribute("value"), ":12",
@@ -77,38 +77,38 @@ function test() {
 
   is(container.childNodes.length, 4,
     "The container node should have four children available.");
   is(container.childNodes[2].className, "call-tree-item",
     "The .B node in the tree has the correct class name.");
   is(container.childNodes[3].className, "call-tree-item",
     "The .E node in the tree has the correct class name.");
 
-  is($$dur(2).getAttribute("value"), "11",
+  is($$dur(2).getAttribute("value"), "8",
     "The .A.B node's duration cell displays the correct value.");
-  is($$perc(2).getAttribute("value"), "66.66%",
+  is($$perc(2).getAttribute("value"), "75%",
     "The .A.B node's percentage cell displays the correct value.");
-  is($$sampl(2).getAttribute("value"), "2",
+  is($$sampl(2).getAttribute("value"), "3",
     "The .A.B node's samples cell displays the correct value.");
   is($$fun(".call-tree-name")[2].getAttribute("value"), "B",
     "The .A.B node's function cell displays the correct name.");
   is($$fun(".call-tree-url")[2].getAttribute("value"), "baz",
     "The .A.B node's function cell displays the correct url.");
   ok($$fun(".call-tree-url")[2].getAttribute("tooltiptext").contains("http://foo/bar/baz"),
     "The .A.B node's function cell displays the correct url tooltiptext.");
   is($$fun(".call-tree-line")[2].getAttribute("value"), ":34",
     "The .A.B node's function cell displays the correct line.");
   is($$fun(".call-tree-host")[2].getAttribute("value"), "foo",
     "The .A.B node's function cell displays the correct host.");
   is($$fun(".call-tree-category")[2].getAttribute("value"), "Styles",
     "The .A.B node's function cell displays the correct category.");
 
   is($$dur(3).getAttribute("value"), "7",
     "The .A.E node's duration cell displays the correct value.");
-  is($$perc(3).getAttribute("value"), "33.33%",
+  is($$perc(3).getAttribute("value"), "25%",
     "The .A.E node's percentage cell displays the correct value.");
   is($$sampl(3).getAttribute("value"), "1",
     "The .A.E node's samples cell displays the correct value.");
   is($$fun(".call-tree-name")[3].getAttribute("value"), "E",
     "The .A.E node's function cell displays the correct name.");
   is($$fun(".call-tree-url")[3].getAttribute("value"), "baz",
     "The .A.E node's function cell displays the correct url.");
   ok($$fun(".call-tree-url")[3].getAttribute("tooltiptext").contains("http://foo/bar/baz"),
@@ -127,24 +127,32 @@ let gSamples = [{
   time: 5,
   frames: [
     { category: 8,  location: "(root)" },
     { category: 8,  location: "A (http://foo/bar/baz:12)" },
     { category: 16, location: "B (http://foo/bar/baz:34)" },
     { category: 32, location: "C (http://foo/bar/baz:56)" }
   ]
 }, {
-  time: 5 + 6,
+  time: 5 + 1,
   frames: [
     { category: 8,  location: "(root)" },
     { category: 8,  location: "A (http://foo/bar/baz:12)" },
     { category: 16, location: "B (http://foo/bar/baz:34)" },
     { category: 64, location: "D (http://foo/bar/baz:78)" }
   ]
 }, {
-  time: 5 + 6 + 7,
+  time: 5 + 1 + 2,
+  frames: [
+    { category: 8,  location: "(root)" },
+    { category: 8,  location: "A (http://foo/bar/baz:12)" },
+    { category: 16, location: "B (http://foo/bar/baz:34)" },
+    { category: 64, location: "D (http://foo/bar/baz:78)" }
+  ]
+}, {
+  time: 5 + 1 + 2 + 7,
   frames: [
     { category: 8,   location: "(root)" },
     { category: 8,   location: "A (http://foo/bar/baz:12)" },
     { category: 128, location: "E (http://foo/bar/baz:90)" },
     { category: 256, location: "F (http://foo/bar/baz:99)" }
   ]
 }];
--- a/browser/devtools/profiler/test/browser_profiler_tree-view-03.js
+++ b/browser/devtools/profiler/test/browser_profiler_tree-view-03.js
@@ -50,23 +50,23 @@ function test() {
     "The .A.B.D node's function cell displays the correct name.");
   is($$name(4).getAttribute("value"), "C",
     "The .A.B.C node's function cell displays the correct name.");
   is($$name(5).getAttribute("value"), "E",
     "The .A.E node's function cell displays the correct name.");
   is($$name(6).getAttribute("value"), "F",
     "The .A.E.F node's function cell displays the correct name.");
 
-  is($$duration(0).getAttribute("value"), "18",
+  is($$duration(0).getAttribute("value"), "15",
     "The root node's function cell displays the correct duration.");
-  is($$duration(1).getAttribute("value"), "18",
+  is($$duration(1).getAttribute("value"), "15",
     "The .A node's function cell displays the correct duration.");
-  is($$duration(2).getAttribute("value"), "11",
+  is($$duration(2).getAttribute("value"), "8",
     "The .A.B node's function cell displays the correct duration.");
-  is($$duration(3).getAttribute("value"), "6",
+  is($$duration(3).getAttribute("value"), "3",
     "The .A.B.D node's function cell displays the correct duration.");
   is($$duration(4).getAttribute("value"), "5",
     "The .A.B.C node's function cell displays the correct duration.");
   is($$duration(5).getAttribute("value"), "7",
     "The .A.E node's function cell displays the correct duration.");
   is($$duration(6).getAttribute("value"), "7",
     "The .A.E.F node's function cell displays the correct duration.");
 
@@ -77,25 +77,33 @@ let gSamples = [{
   time: 5,
   frames: [
     { category: 8,  location: "(root)" },
     { category: 8,  location: "A (http://foo/bar/baz:12)" },
     { category: 16, location: "B (http://foo/bar/baz:34)" },
     { category: 32, location: "C (http://foo/bar/baz:56)" }
   ]
 }, {
-  time: 5 + 6,
+  time: 5 + 1,
   frames: [
     { category: 8,  location: "(root)" },
     { category: 8,  location: "A (http://foo/bar/baz:12)" },
     { category: 16, location: "B (http://foo/bar/baz:34)" },
     { category: 64, location: "D (http://foo/bar/baz:78)" }
   ]
 }, {
-  time: 5 + 6 + 7,
+  time: 5 + 1 + 2,
+  frames: [
+    { category: 8,  location: "(root)" },
+    { category: 8,  location: "A (http://foo/bar/baz:12)" },
+    { category: 16, location: "B (http://foo/bar/baz:34)" },
+    { category: 64, location: "D (http://foo/bar/baz:78)" }
+  ]
+}, {
+  time: 5 + 1 + 2 + 7,
   frames: [
     { category: 8,   location: "(root)" },
     { category: 8,   location: "A (http://foo/bar/baz:12)" },
     { category: 128, location: "E (http://foo/bar/baz:90)" },
     { category: 256, location: "F (http://foo/bar/baz:99)" }
   ]
 }];
 
--- a/browser/devtools/profiler/test/browser_profiler_tree-view-04.js
+++ b/browser/devtools/profiler/test/browser_profiler_tree-view-04.js
@@ -24,45 +24,45 @@ function test() {
     "The root node's 'tooltiptext' attribute is correct.");
   ok(treeRoot.target.querySelector(".call-tree-zoom").hidden,
     "The root node's zoom button cell should be hidden.");
   ok(treeRoot.target.querySelector(".call-tree-category").hidden,
     "The root node's category label cell should be hidden.");
 
   let A = treeRoot.getChild();
   let B = A.getChild();
-  let C = B.getChild();
+  let D = B.getChild();
 
-  is(C.target.getAttribute("origin"), "chrome",
-    "The .A.B.C node's 'origin' attribute is correct.");
-  is(C.target.getAttribute("category"), "gc",
-    "The .A.B.C node's 'category' attribute is correct.");
-  is(C.target.getAttribute("tooltiptext"), "D (http://foo/bar/baz:78)",
-    "The .A.B.C node's 'tooltiptext' attribute is correct.");
+  is(D.target.getAttribute("origin"), "chrome",
+    "The .A.B.D node's 'origin' attribute is correct.");
+  is(D.target.getAttribute("category"), "gc",
+    "The .A.B.D node's 'category' attribute is correct.");
+  is(D.target.getAttribute("tooltiptext"), "D (http://foo/bar/baz:78)",
+    "The .A.B.D node's 'tooltiptext' attribute is correct.");
   ok(!A.target.querySelector(".call-tree-zoom").hidden,
-    "The .A.B.C node's zoom button cell should not be hidden.");
+    "The .A.B.D node's zoom button cell should not be hidden.");
   ok(!A.target.querySelector(".call-tree-category").hidden,
-    "The .A.B.C node's category label cell should not be hidden.");
+    "The .A.B.D node's category label cell should not be hidden.");
 
-  is(C.target.childNodes.length, 6,
+  is(D.target.childNodes.length, 6,
     "The number of columns displayed for tree items is correct.");
-  is(C.target.childNodes[0].getAttribute("type"), "duration",
+  is(D.target.childNodes[0].getAttribute("type"), "duration",
     "The first column displayed for tree items is correct.");
-  is(C.target.childNodes[1].getAttribute("type"), "percentage",
+  is(D.target.childNodes[1].getAttribute("type"), "percentage",
     "The third column displayed for tree items is correct.");
-  is(C.target.childNodes[2].getAttribute("type"), "self-duration",
+  is(D.target.childNodes[2].getAttribute("type"), "self-duration",
     "The second column displayed for tree items is correct.");
-  is(C.target.childNodes[3].getAttribute("type"), "self-percentage",
+  is(D.target.childNodes[3].getAttribute("type"), "self-percentage",
     "The fourth column displayed for tree items is correct.");
-  is(C.target.childNodes[4].getAttribute("type"), "samples",
+  is(D.target.childNodes[4].getAttribute("type"), "samples",
     "The fifth column displayed for tree items is correct.");
-  is(C.target.childNodes[5].getAttribute("type"), "function",
+  is(D.target.childNodes[5].getAttribute("type"), "function",
     "The sixth column displayed for tree items is correct.");
 
-  let functionCell = C.target.childNodes[5];
+  let functionCell = D.target.childNodes[5];
 
   is(functionCell.childNodes.length, 8,
     "The number of columns displayed for function cells is correct.");
   is(functionCell.childNodes[0].className, "arrow theme-twisty",
     "The first node displayed for function cells is correct.");
   is(functionCell.childNodes[1].className, "plain call-tree-name",
     "The second node displayed for function cells is correct.");
   is(functionCell.childNodes[2].className, "plain call-tree-url",
@@ -85,25 +85,33 @@ let gSamples = [{
   time: 5,
   frames: [
     { category: 8,  location: "(root)" },
     { category: 8,  location: "A (http://foo/bar/baz:12)" },
     { category: 16, location: "B (http://foo/bar/baz:34)" },
     { category: 32, location: "C (http://foo/bar/baz:56)" }
   ]
 }, {
-  time: 5 + 6,
+  time: 5 + 1,
   frames: [
     { category: 8,  location: "(root)" },
     { category: 8,  location: "A (http://foo/bar/baz:12)" },
     { category: 16, location: "B (http://foo/bar/baz:34)" },
     { category: 64, location: "D (http://foo/bar/baz:78)" }
   ]
 }, {
-  time: 5 + 6 + 7,
+  time: 5 + 1 + 2,
+  frames: [
+    { category: 8,  location: "(root)" },
+    { category: 8,  location: "A (http://foo/bar/baz:12)" },
+    { category: 16, location: "B (http://foo/bar/baz:34)" },
+    { category: 64, location: "D (http://foo/bar/baz:78)" }
+  ]
+}, {
+  time: 5 + 1 + 2 + 7,
   frames: [
     { category: 8,   location: "(root)" },
     { category: 8,   location: "A (http://foo/bar/baz:12)" },
     { category: 128, location: "E (http://foo/bar/baz:90)" },
     { category: 256, location: "F (http://foo/bar/baz:99)" }
   ]
 }];
 
--- a/browser/devtools/profiler/test/browser_profiler_tree-view-05.js
+++ b/browser/devtools/profiler/test/browser_profiler_tree-view-05.js
@@ -35,24 +35,32 @@ let gSamples = [{
   time: 5,
   frames: [
     { category: 8,  location: "(root)" },
     { category: 8,  location: "A (http://foo/bar/baz:12)" },
     { category: 16, location: "B (http://foo/bar/baz:34)" },
     { category: 32, location: "C (http://foo/bar/baz:56)" }
   ]
 }, {
-  time: 5 + 6,
+  time: 5 + 1,
   frames: [
     { category: 8,  location: "(root)" },
     { category: 8,  location: "A (http://foo/bar/baz:12)" },
     { category: 16, location: "B (http://foo/bar/baz:34)" },
     { category: 64, location: "D (http://foo/bar/baz:78)" }
   ]
 }, {
-  time: 5 + 6 + 7,
+  time: 5 + 1 + 2,
+  frames: [
+    { category: 8,  location: "(root)" },
+    { category: 8,  location: "A (http://foo/bar/baz:12)" },
+    { category: 16, location: "B (http://foo/bar/baz:34)" },
+    { category: 64, location: "D (http://foo/bar/baz:78)" }
+  ]
+}, {
+  time: 5 + 1 + 2 + 7,
   frames: [
     { category: 8,   location: "(root)" },
     { category: 8,   location: "A (http://foo/bar/baz:12)" },
     { category: 128, location: "E (http://foo/bar/baz:90)" },
     { category: 256, location: "F (http://foo/bar/baz:99)" }
   ]
 }];
--- a/browser/devtools/profiler/test/browser_profiler_tree-view-06.js
+++ b/browser/devtools/profiler/test/browser_profiler_tree-view-06.js
@@ -13,50 +13,58 @@ let test = Task.async(function*() {
   let threadNode = new ThreadNode(gSamples);
   let treeRoot = new CallView({ frame: threadNode });
 
   let container = document.createElement("vbox");
   treeRoot.attachTo(container);
 
   let A = treeRoot.getChild();
   let B = A.getChild();
-  let C = B.getChild();
+  let D = B.getChild();
 
   let receivedLinkEvent = treeRoot.once("link");
-  EventUtils.sendMouseEvent({ type: "mousedown" }, C.target.querySelector(".call-tree-url"));
+  EventUtils.sendMouseEvent({ type: "mousedown" }, D.target.querySelector(".call-tree-url"));
 
   let eventItem = yield receivedLinkEvent;
-  is(eventItem, C, "The 'link' event target is correct.");
+  is(eventItem, D, "The 'link' event target is correct.");
 
   let receivedZoomEvent = treeRoot.once("zoom");
-  EventUtils.sendMouseEvent({ type: "mousedown" }, C.target.querySelector(".call-tree-zoom"));
+  EventUtils.sendMouseEvent({ type: "mousedown" }, D.target.querySelector(".call-tree-zoom"));
 
   eventItem = yield receivedZoomEvent;
-  is(eventItem, C, "The 'zoom' event target is correct.");
+  is(eventItem, D, "The 'zoom' event target is correct.");
 
   finish();
 });
 
 let gSamples = [{
   time: 5,
   frames: [
     { category: 8,  location: "(root)" },
     { category: 8,  location: "A (http://foo/bar/baz:12)" },
     { category: 16, location: "B (http://foo/bar/baz:34)" },
     { category: 32, location: "C (http://foo/bar/baz:56)" }
   ]
 }, {
-  time: 5 + 6,
+  time: 5 + 1,
   frames: [
     { category: 8,  location: "(root)" },
     { category: 8,  location: "A (http://foo/bar/baz:12)" },
     { category: 16, location: "B (http://foo/bar/baz:34)" },
     { category: 64, location: "D (http://foo/bar/baz:78)" }
   ]
 }, {
-  time: 5 + 6 + 7,
+  time: 5 + 1 + 2,
+  frames: [
+    { category: 8,  location: "(root)" },
+    { category: 8,  location: "A (http://foo/bar/baz:12)" },
+    { category: 16, location: "B (http://foo/bar/baz:34)" },
+    { category: 64, location: "D (http://foo/bar/baz:78)" }
+  ]
+}, {
+  time: 5 + 1 + 2 + 7,
   frames: [
     { category: 8,   location: "(root)" },
     { category: 8,   location: "A (http://foo/bar/baz:12)" },
     { category: 128, location: "E (http://foo/bar/baz:90)" },
     { category: 256, location: "F (http://foo/bar/baz:99)" }
   ]
 }];
--- a/browser/devtools/profiler/test/browser_profiler_tree-view-07.js
+++ b/browser/devtools/profiler/test/browser_profiler_tree-view-07.js
@@ -14,49 +14,57 @@ function test() {
   let treeRoot = new CallView({ frame: threadNode });
 
   let container = document.createElement("vbox");
   container.id = "call-tree-container";
   treeRoot.attachTo(container);
 
   let A = treeRoot.getChild();
   let B = A.getChild();
-  let C = B.getChild();
+  let D = B.getChild();
 
-  is(C.root, treeRoot,
-    "The .A.B.C node has the correct root.");
-  is(C.parent, B,
-    "The .A.B.C node has the correct parent.");
-  is(C.level, 3,
-    "The .A.B.C node has the correct level.");
-  is(C.target.className, "call-tree-item",
-    "The .A.B.C node has the correct target node.");
-  is(C.container.id, "call-tree-container",
-    "The .A.B.C node has the correct container node.");
+  is(D.root, treeRoot,
+    "The .A.B.D node has the correct root.");
+  is(D.parent, B,
+    "The .A.B.D node has the correct parent.");
+  is(D.level, 3,
+    "The .A.B.D node has the correct level.");
+  is(D.target.className, "call-tree-item",
+    "The .A.B.D node has the correct target node.");
+  is(D.container.id, "call-tree-container",
+    "The .A.B.D node has the correct container node.");
 
   finish();
 }
 
 let gSamples = [{
   time: 5,
   frames: [
     { category: 8,  location: "(root)" },
     { category: 8,  location: "A (http://foo/bar/baz:12)" },
     { category: 16, location: "B (http://foo/bar/baz:34)" },
     { category: 32, location: "C (http://foo/bar/baz:56)" }
   ]
 }, {
-  time: 5 + 6,
+  time: 5 + 1,
   frames: [
     { category: 8,  location: "(root)" },
     { category: 8,  location: "A (http://foo/bar/baz:12)" },
     { category: 16, location: "B (http://foo/bar/baz:34)" },
     { category: 64, location: "D (http://foo/bar/baz:78)" }
   ]
 }, {
-  time: 5 + 6 + 7,
+  time: 5 + 1 + 2,
+  frames: [
+    { category: 8,  location: "(root)" },
+    { category: 8,  location: "A (http://foo/bar/baz:12)" },
+    { category: 16, location: "B (http://foo/bar/baz:34)" },
+    { category: 64, location: "D (http://foo/bar/baz:78)" }
+  ]
+}, {
+  time: 5 + 1 + 2 + 7,
   frames: [
     { category: 8,   location: "(root)" },
     { category: 8,   location: "A (http://foo/bar/baz:12)" },
     { category: 128, location: "E (http://foo/bar/baz:90)" },
     { category: 256, location: "F (http://foo/bar/baz:99)" }
   ]
 }];
--- a/browser/devtools/profiler/utils/tree-view.js
+++ b/browser/devtools/profiler/utils/tree-view.js
@@ -169,18 +169,18 @@ CallView.prototype = Heritage.extend(Abs
       children.push(new CallView({
         caller: this,
         frame: newFrame,
         level: newLevel,
         inverted: this.inverted
       }));
     }
 
-    // Sort the "callees" asc. by duration, before inserting them in the tree.
-    children.sort((a, b) => a.frame.duration < b.frame.duration ? 1 : -1);
+    // Sort the "callees" asc. by samples, before inserting them in the tree.
+    children.sort((a, b) => a.frame.samples < b.frame.samples ? 1 : -1);
   },
 
   /**
    * Functions creating each cell in this call view.
    * Invoked by `_displaySelf`.
    */
   _createTimeCell: function(duration, isSelf = false) {
     let cell = this.document.createElement("label");
--- a/browser/modules/ContentSearch.jsm
+++ b/browser/modules/ContentSearch.jsm
@@ -268,22 +268,24 @@ this.ContentSearch = {
       engineName: data.engineName,
       searchString: suggestions.term,
       formHistory: suggestions.local,
       remote: suggestions.remote,
     });
   }),
 
   _onMessageAddFormHistoryEntry: function (msg, entry) {
-    // There are some tests that use about:home and newtab that trigger a search
-    // and then immediately close the tab.  In those cases, the browser may have
-    // been destroyed by the time we receive this message, and as a result
-    // contentWindow is undefined.
-    if (!msg.target.contentWindow ||
-        PrivateBrowsingUtils.isBrowserPrivate(msg.target)) {
+    let isPrivate = true;
+    try {
+      // isBrowserPrivate assumes that the passed-in browser has all the normal
+      // properties, which won't be true if the browser has been destroyed.
+      // That may be the case here due to the asynchronous nature of messaging.
+      isPrivate = PrivateBrowsingUtils.isBrowserPrivate(msg.target);
+    } catch (err) {}
+    if (isPrivate || entry === "") {
       return Promise.resolve();
     }
     let browserData = this._suggestionDataForBrowser(msg.target, true);
     FormHistory.update({
       op: "bump",
       fieldname: browserData.controller.formHistoryParam,
       value: entry,
     }, {
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -170,16 +170,17 @@ using namespace mozilla::docshell;
 using namespace mozilla::dom::bluetooth;
 using namespace mozilla::dom::cellbroadcast;
 using namespace mozilla::dom::devicestorage;
 using namespace mozilla::dom::ipc;
 using namespace mozilla::dom::mobileconnection;
 using namespace mozilla::dom::mobilemessage;
 using namespace mozilla::dom::telephony;
 using namespace mozilla::dom::voicemail;
+using namespace mozilla::embedding;
 using namespace mozilla::hal_sandbox;
 using namespace mozilla::ipc;
 using namespace mozilla::layers;
 using namespace mozilla::net;
 using namespace mozilla::jsipc;
 #if defined(MOZ_WIDGET_GONK)
 using namespace mozilla::system;
 #endif
@@ -1386,16 +1387,34 @@ ContentChild::AllocPNeckoChild()
 
 bool
 ContentChild::DeallocPNeckoChild(PNeckoChild* necko)
 {
     delete necko;
     return true;
 }
 
+PPrintingChild*
+ContentChild::AllocPPrintingChild()
+{
+    // The ContentParent should never attempt to allocate the
+    // nsPrintingPromptServiceProxy, which implements PPrintingChild. Instead,
+    // the nsPrintingPromptServiceProxy service is requested and instantiated
+    // via XPCOM, and the constructor of nsPrintingPromptServiceProxy sets up
+    // the IPC connection.
+    NS_NOTREACHED("Should never get here!");
+    return nullptr;
+}
+
+bool
+ContentChild::DeallocPPrintingChild(PPrintingChild* printing)
+{
+    return true;
+}
+
 PScreenManagerChild*
 ContentChild::AllocPScreenManagerChild(uint32_t* aNumberOfScreens,
                                        float* aSystemDefaultScale,
                                        bool* aSuccess)
 {
     // The ContentParent should never attempt to allocate the
     // nsScreenManagerProxy. Instead, the nsScreenManagerProxy
     // service is requested and instantiated via XPCOM, and the
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -202,16 +202,19 @@ public:
     virtual PMobileConnectionChild*
     AllocPMobileConnectionChild(const uint32_t& aClientId) MOZ_OVERRIDE;
     virtual bool
     DeallocPMobileConnectionChild(PMobileConnectionChild* aActor) MOZ_OVERRIDE;
 
     virtual PNeckoChild* AllocPNeckoChild() MOZ_OVERRIDE;
     virtual bool DeallocPNeckoChild(PNeckoChild*) MOZ_OVERRIDE;
 
+    virtual PPrintingChild* AllocPPrintingChild() MOZ_OVERRIDE;
+    virtual bool DeallocPPrintingChild(PPrintingChild*) MOZ_OVERRIDE;
+
     virtual PScreenManagerChild*
     AllocPScreenManagerChild(uint32_t* aNumberOfScreens,
                              float* aSystemDefaultScale,
                              bool* aSuccess) MOZ_OVERRIDE;
     virtual bool DeallocPScreenManagerChild(PScreenManagerChild*) MOZ_OVERRIDE;
 
     virtual PExternalHelperAppChild *AllocPExternalHelperAppChild(
             const OptionalURIParams& uri,
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -52,16 +52,17 @@
 #include "mozilla/dom/devicestorage/DeviceStorageRequestParent.h"
 #include "mozilla/dom/mobileconnection/MobileConnectionParent.h"
 #include "mozilla/dom/mobilemessage/SmsParent.h"
 #include "mozilla/dom/power/PowerManagerService.h"
 #include "mozilla/dom/quota/QuotaManager.h"
 #include "mozilla/dom/telephony/TelephonyParent.h"
 #include "mozilla/dom/time/DateCacheCleaner.h"
 #include "mozilla/dom/voicemail/VoicemailParent.h"
+#include "mozilla/embedding/printingui/PrintingParent.h"
 #include "mozilla/hal_sandbox/PHalParent.h"
 #include "mozilla/ipc/BackgroundChild.h"
 #include "mozilla/ipc/BackgroundParent.h"
 #include "mozilla/ipc/FileDescriptorSetParent.h"
 #include "mozilla/ipc/FileDescriptorUtils.h"
 #include "mozilla/ipc/PFileDescriptorSetParent.h"
 #include "mozilla/ipc/TestShellParent.h"
 #include "mozilla/ipc/InputStreamUtils.h"
@@ -203,16 +204,17 @@ using namespace mozilla::dom::bluetooth;
 using namespace mozilla::dom::cellbroadcast;
 using namespace mozilla::dom::devicestorage;
 using namespace mozilla::dom::indexedDB;
 using namespace mozilla::dom::power;
 using namespace mozilla::dom::mobileconnection;
 using namespace mozilla::dom::mobilemessage;
 using namespace mozilla::dom::telephony;
 using namespace mozilla::dom::voicemail;
+using namespace mozilla::embedding;
 using namespace mozilla::hal;
 using namespace mozilla::ipc;
 using namespace mozilla::layers;
 using namespace mozilla::net;
 using namespace mozilla::jsipc;
 using namespace mozilla::widget;
 
 #ifdef ENABLE_TESTS
@@ -3111,16 +3113,35 @@ ContentParent::AllocPNeckoParent()
 
 bool
 ContentParent::DeallocPNeckoParent(PNeckoParent* necko)
 {
     delete necko;
     return true;
 }
 
+PPrintingParent*
+ContentParent::AllocPPrintingParent()
+{
+    return new PrintingParent();
+}
+
+bool
+ContentParent::RecvPPrintingConstructor(PPrintingParent* aActor)
+{
+    return true;
+}
+
+bool
+ContentParent::DeallocPPrintingParent(PPrintingParent* printing)
+{
+    delete printing;
+    return true;
+}
+
 PScreenManagerParent*
 ContentParent::AllocPScreenManagerParent(uint32_t* aNumberOfScreens,
                                          float* aSystemDefaultScale,
                                          bool* aSuccess)
 {
     return new ScreenManagerParent(aNumberOfScreens, aSystemDefaultScale, aSuccess);
 }
 
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -240,16 +240,20 @@ public:
                                   const NativeThreadId& tid,
                                   const uint32_t& processType) MOZ_OVERRIDE;
 
     virtual PNeckoParent* AllocPNeckoParent() MOZ_OVERRIDE;
     virtual bool RecvPNeckoConstructor(PNeckoParent* aActor) MOZ_OVERRIDE {
         return PContentParent::RecvPNeckoConstructor(aActor);
     }
 
+    virtual PPrintingParent* AllocPPrintingParent() MOZ_OVERRIDE;
+    virtual bool RecvPPrintingConstructor(PPrintingParent* aActor) MOZ_OVERRIDE;
+    virtual bool DeallocPPrintingParent(PPrintingParent* aActor) MOZ_OVERRIDE;
+
     virtual PScreenManagerParent*
     AllocPScreenManagerParent(uint32_t* aNumberOfScreens,
                               float* aSystemDefaultScale,
                               bool* aSuccess) MOZ_OVERRIDE;
     virtual bool DeallocPScreenManagerParent(PScreenManagerParent* aActor) MOZ_OVERRIDE;
 
     virtual PHalParent* AllocPHalParent() MOZ_OVERRIDE;
     virtual bool RecvPHalConstructor(PHalParent* aActor) MOZ_OVERRIDE {
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -20,16 +20,17 @@ include protocol PDeviceStorageRequest;
 include protocol PFileDescriptorSet;
 include protocol PFMRadio;
 include protocol PFileSystemRequest;
 include protocol PHal;
 include protocol PImageBridge;
 include protocol PMemoryReportRequest;
 include protocol PMobileConnection;
 include protocol PNecko;
+include protocol PPrinting;
 include protocol PScreenManager;
 include protocol PSharedBufferManager;
 include protocol PSms;
 include protocol PSpeechSynthesis;
 include protocol PStorage;
 include protocol PTelephony;
 include protocol PTestShell;
 include protocol PVoicemail;
@@ -344,16 +345,17 @@ prio(normal upto high) intr protocol PCo
     manages PFileSystemRequest;
     manages PExternalHelperApp;
     manages PFileDescriptorSet;
     manages PFMRadio;
     manages PHal;
     manages PMemoryReportRequest;
     manages PMobileConnection;
     manages PNecko;
+    manages PPrinting;
     manages PScreenManager;
     manages PSms;
     manages PSpeechSynthesis;
     manages PStorage;
     manages PTelephony;
     manages PTestShell;
     manages PVoicemail;
     manages PJavaScript;
@@ -548,16 +550,18 @@ parent:
         returns (bool isSecureURI);
 
     PHal();
 
     PMobileConnection(uint32_t clientId);
 
     PNecko();
 
+    PPrinting();
+
     prio(high) sync PScreenManager()
         returns (uint32_t numberOfScreens,
                  float systemDefaultScale,
                  bool success);
 
     PCellBroadcast();
 
     PSms();
--- a/dom/ipc/moz.build
+++ b/dom/ipc/moz.build
@@ -105,16 +105,17 @@ LOCAL_INCLUDES += [
     '/dom/devicestorage',
     '/dom/filesystem',
     '/dom/fmradio/ipc',
     '/dom/geolocation',
     '/dom/media/webspeech/synth/ipc',
     '/dom/mobilemessage/ipc',
     '/dom/storage',
     '/editor/libeditor',
+    '/embedding/components/printingui/ipc',
     '/extensions/cookie',
     '/extensions/spellcheck/src',
     '/hal/sandbox',
     '/js/ipc',
     '/layout/base',
     '/netwerk/base/src',
     '/toolkit/xre',
     '/uriloader/exthandler',
--- a/embedding/components/build/moz.build
+++ b/embedding/components/build/moz.build
@@ -10,26 +10,31 @@ SOURCES += [
 
 FAIL_ON_WARNINGS = True
 
 FINAL_LIBRARY = 'xul'
 LOCAL_INCLUDES += [
     '../appstartup',
     '../commandhandler',
     '../find',
+    '../printingui/ipc',
     '../webbrowserpersist',
     '../windowwatcher',
 ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
+    DEFINES['PROXY_PRINTING'] = 1
     LOCAL_INCLUDES += [
         '../printingui/win',
     ]
 elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
     LOCAL_INCLUDES += [
         '../printingui/mac',
     ]
 
 if CONFIG['MOZ_PDF_PRINTING']:
+    DEFINES['PROXY_PRINTING'] = 1
     LOCAL_INCLUDES += [
         '../printingui/unixshared',
     ]
 
+include('/ipc/chromium/chromium-config.mozbuild')
+
--- a/embedding/components/build/nsEmbeddingModule.cpp
+++ b/embedding/components/build/nsEmbeddingModule.cpp
@@ -15,16 +15,17 @@
 #include "nsCommandParams.h"
 #include "nsCommandGroup.h"
 #include "nsBaseCommandController.h"
 #include "nsNetCID.h"
 #include "nsEmbedCID.h"
 
 #ifdef NS_PRINTING
 #include "nsPrintingPromptService.h"
+#include "nsPrintingPromptServiceProxy.h"
 #endif
 
 
 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsWindowWatcher, Init)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsAppStartupNotifier)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsFind)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsWebBrowserFind)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsWebBrowserPersist)
@@ -33,16 +34,19 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsCommand
 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsCommandParams, Init)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsControllerCommandGroup)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsBaseCommandController)
 
 #ifdef MOZ_XUL
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsDialogParamBlock)
 #ifdef NS_PRINTING
 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsPrintingPromptService, Init)
+#ifdef PROXY_PRINTING
+NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsPrintingPromptServiceProxy, Init)
+#endif
 #endif
 #endif
 
 #ifdef MOZ_XUL
 NS_DEFINE_NAMED_CID(NS_DIALOGPARAMBLOCK_CID);
 #ifdef NS_PRINTING
 NS_DEFINE_NAMED_CID(NS_PRINTINGPROMPTSERVICE_CID);
 #endif
@@ -57,19 +61,27 @@ NS_DEFINE_NAMED_CID(NS_COMMAND_MANAGER_C
 NS_DEFINE_NAMED_CID(NS_COMMAND_PARAMS_CID);
 NS_DEFINE_NAMED_CID(NS_CONTROLLER_COMMAND_GROUP_CID);
 NS_DEFINE_NAMED_CID(NS_BASECOMMANDCONTROLLER_CID);
 
 static const mozilla::Module::CIDEntry kEmbeddingCIDs[] = {
 #ifdef MOZ_XUL
     { &kNS_DIALOGPARAMBLOCK_CID, false, nullptr, nsDialogParamBlockConstructor },
 #ifdef NS_PRINTING
+
+#ifdef PROXY_PRINTING
+    { &kNS_PRINTINGPROMPTSERVICE_CID, false, nullptr, nsPrintingPromptServiceConstructor,
+      mozilla::Module::MAIN_PROCESS_ONLY },
+    { &kNS_PRINTINGPROMPTSERVICE_CID, false, nullptr, nsPrintingPromptServiceProxyConstructor,
+      mozilla::Module::CONTENT_PROCESS_ONLY },
+#else
     { &kNS_PRINTINGPROMPTSERVICE_CID, false, nullptr, nsPrintingPromptServiceConstructor },
 #endif
 #endif
+#endif
     { &kNS_WINDOWWATCHER_CID, false, nullptr, nsWindowWatcherConstructor },
     { &kNS_FIND_CID, false, nullptr, nsFindConstructor },
     { &kNS_WEB_BROWSER_FIND_CID, false, nullptr, nsWebBrowserFindConstructor },
     { &kNS_APPSTARTUPNOTIFIER_CID, false, nullptr, nsAppStartupNotifierConstructor },
     { &kNS_WEBBROWSERPERSIST_CID, false, nullptr, nsWebBrowserPersistConstructor },
     { &kNS_CONTROLLERCOMMANDTABLE_CID, false, nullptr, nsControllerCommandTableConstructor },
     { &kNS_COMMAND_MANAGER_CID, false, nullptr, nsCommandManagerConstructor },
     { &kNS_COMMAND_PARAMS_CID, false, nullptr, nsCommandParamsConstructor },
new file mode 100644
--- /dev/null
+++ b/embedding/components/printingui/ipc/PPrinting.ipdl
@@ -0,0 +1,101 @@
+/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+include protocol PContent;
+include protocol PBrowser;
+
+namespace mozilla {
+namespace embedding {
+
+struct PrintData {
+  int32_t startPageRange;
+  int32_t endPageRange;
+  double edgeTop;
+  double edgeLeft;
+  double edgeBottom;
+  double edgeRight;
+  double marginTop;
+  double marginLeft;
+  double marginBottom;
+  double marginRight;
+  double unwriteableMarginTop;
+  double unwriteableMarginLeft;
+  double unwriteableMarginBottom;
+  double unwriteableMarginRight;
+  double scaling;
+  bool printBGColors;
+  bool printBGImages;
+  short printRange;
+  nsString title;
+  nsString docURL;
+  nsString headerStrLeft;
+  nsString headerStrCenter;
+  nsString headerStrRight;
+  nsString footerStrLeft;
+  nsString footerStrCenter;
+  nsString footerStrRight;
+
+  short  howToEnableFrameUI;
+  bool isCancelled;
+  short printFrameTypeUsage;
+  short  printFrameType;
+  bool printSilent;
+  bool shrinkToFit;
+  bool showPrintProgress;
+
+  nsString paperName;
+  short paperSizeType;
+  short paperData;
+  double paperWidth;
+  double paperHeight;
+  short paperSizeUnit;
+  nsString plexName;
+  nsString colorspace;
+  nsString resolutionName;
+  bool downloadFonts;
+  bool printReversed;
+  bool printInColor;
+  int32_t orientation;
+  nsString printCommand;
+  int32_t numCopies;
+  nsString printerName;
+  bool printToFile;
+  nsString toFileName;
+  short outputFormat;
+  int32_t printPageDelay;
+  int32_t resolution;
+  int32_t duplex;
+  bool isInitializedFromPrinter;
+  bool isInitializedFromPrefs;
+  bool persistMarginBoxSettings;
+
+  /* Windows-specific things */
+  nsString driverName;
+  nsString deviceName;
+  bool isFramesetDocument;
+  bool isFramesetFrameSelected;
+  bool isIFrameSelected;
+  bool isRangeSelection;
+
+  /* TODO: OS X specific things - specifically, an array of names for the
+   * document to be supplied by nsIWebBrowserPrint::enumerateDocumentNames
+   */
+};
+
+sync protocol PPrinting
+{
+  manager PContent;
+
+parent:
+  sync ShowProgress(PBrowser browser, bool isForPrinting);
+  sync ShowPrintDialog(PBrowser browser, PrintData settings)
+    returns(PrintData modifiedSettings, bool success);
+
+child:
+  __delete__();
+};
+
+} // namespace embedding
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/embedding/components/printingui/ipc/PrintDataUtils.cpp
@@ -0,0 +1,143 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim: set sw=4 ts=8 et tw=80 : */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "PrintDataUtils.h"
+#include "nsIPrintOptions.h"
+#include "nsIPrintSettings.h"
+#include "nsIServiceManager.h"
+#include "nsIWebBrowserPrint.h"
+#include "nsXPIDLString.h"
+
+namespace mozilla {
+namespace embedding {
+
+/**
+ * MockWebBrowserPrint is a mostly useless implementation of nsIWebBrowserPrint,
+ * but wraps a PrintData so that it's able to return information to print
+ * settings dialogs that need an nsIWebBrowserPrint to interrogate.
+ */
+
+NS_IMPL_ISUPPORTS(MockWebBrowserPrint, nsIWebBrowserPrint);
+
+MockWebBrowserPrint::MockWebBrowserPrint(PrintData aData)
+  : mData(aData)
+{
+  MOZ_COUNT_CTOR(MockWebBrowserPrint);
+}
+
+MockWebBrowserPrint::~MockWebBrowserPrint()
+{
+  MOZ_COUNT_DTOR(MockWebBrowserPrint);
+}
+
+NS_IMETHODIMP
+MockWebBrowserPrint::GetGlobalPrintSettings(nsIPrintSettings **aGlobalPrintSettings)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+MockWebBrowserPrint::GetCurrentPrintSettings(nsIPrintSettings **aCurrentPrintSettings)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+MockWebBrowserPrint::GetCurrentChildDOMWindow(nsIDOMWindow **aCurrentPrintSettings)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+MockWebBrowserPrint::GetDoingPrint(bool *aDoingPrint)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+MockWebBrowserPrint::GetDoingPrintPreview(bool *aDoingPrintPreview)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+MockWebBrowserPrint::GetIsFramesetDocument(bool *aIsFramesetDocument)
+{
+  *aIsFramesetDocument = mData.isFramesetDocument();
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+MockWebBrowserPrint::GetIsFramesetFrameSelected(bool *aIsFramesetFrameSelected)
+{
+  *aIsFramesetFrameSelected = mData.isFramesetFrameSelected();
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+MockWebBrowserPrint::GetIsIFrameSelected(bool *aIsIFrameSelected)
+{
+  *aIsIFrameSelected = mData.isIFrameSelected();
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+MockWebBrowserPrint::GetIsRangeSelection(bool *aIsRangeSelection)
+{
+  *aIsRangeSelection = mData.isRangeSelection();
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+MockWebBrowserPrint::GetPrintPreviewNumPages(int32_t *aPrintPreviewNumPages)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+MockWebBrowserPrint::Print(nsIPrintSettings* aThePrintSettings,
+                           nsIWebProgressListener* aWPListener)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+MockWebBrowserPrint::PrintPreview(nsIPrintSettings* aThePrintSettings,
+                                  nsIDOMWindow* aChildDOMWin,
+                                  nsIWebProgressListener* aWPListener)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+MockWebBrowserPrint::PrintPreviewNavigate(int16_t aNavType,
+                                          int32_t aPageNum)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+MockWebBrowserPrint::Cancel()
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+MockWebBrowserPrint::EnumerateDocumentNames(uint32_t* aCount,
+                                            char16_t*** aResult)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+MockWebBrowserPrint::ExitPrintPreview()
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+} // namespace embedding
+} // namespace mozilla
+
new file mode 100644
--- /dev/null
+++ b/embedding/components/printingui/ipc/PrintDataUtils.h
@@ -0,0 +1,39 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim: set sw=4 ts=8 et tw=80 : */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_embedding_PrintDataUtils_h
+#define mozilla_embedding_PrintDataUtils_h
+
+#include "mozilla/embedding/PPrinting.h"
+#include "nsIWebBrowserPrint.h"
+
+/**
+ * nsIPrintSettings and nsIWebBrowserPrint information is sent back and forth
+ * across PPrinting via the PrintData struct. These are utilities for
+ * manipulating PrintData that can be used on either side of the communications
+ * channel.
+ */
+
+namespace mozilla {
+namespace embedding {
+
+class MockWebBrowserPrint MOZ_FINAL : public nsIWebBrowserPrint
+{
+public:
+  MockWebBrowserPrint(PrintData aData);
+
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIWEBBROWSERPRINT
+
+private:
+  ~MockWebBrowserPrint();
+  PrintData mData;
+};
+
+} // namespace embedding
+} // namespace mozilla
+
+#endif
new file mode 100644
--- /dev/null
+++ b/embedding/components/printingui/ipc/PrintingParent.cpp
@@ -0,0 +1,150 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim: set sw=4 ts=8 et tw=80 : */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/dom/Element.h"
+#include "mozilla/dom/TabParent.h"
+#include "nsIContent.h"
+#include "nsIDocument.h"
+#include "nsIDOMWindow.h"
+#include "nsIPrintingPromptService.h"
+#include "nsIPrintProgressParams.h"
+#include "nsIServiceManager.h"
+#include "nsIWebProgressListener.h"
+#include "PrintingParent.h"
+#include "nsIPrintOptions.h"
+#include "PrintDataUtils.h"
+
+using namespace mozilla;
+using namespace mozilla::dom;
+
+namespace mozilla {
+namespace embedding {
+bool
+PrintingParent::RecvShowProgress(PBrowserParent* parent,
+                                 const bool& isForPrinting)
+{
+  TabParent* tabParent = static_cast<TabParent*>(parent);
+  if (!tabParent) {
+    return true;
+  }
+
+  nsCOMPtr<Element> frameElement = tabParent->GetOwnerElement();
+  if (!frameElement) {
+    return true;
+  }
+
+  nsCOMPtr<nsIContent> frame(do_QueryInterface(frameElement));
+  if (!frame) {
+    return true;
+  }
+
+  nsCOMPtr<nsIDOMWindow> parentWin = do_QueryInterface(frame->OwnerDoc()->GetWindow());
+  if (!parentWin) {
+    return true;
+  }
+
+  nsCOMPtr<nsIPrintingPromptService> pps(do_GetService("@mozilla.org/embedcomp/printingprompt-service;1"));
+
+  if (!pps) {
+    return true;
+  }
+
+  nsCOMPtr<nsIWebProgressListener> printProgressListener;
+  nsCOMPtr<nsIPrintProgressParams> printProgressParams;
+
+  // TODO: What do I do with this thing?
+  bool doNotify = false;
+
+  pps->ShowProgress(parentWin, nullptr, nullptr, nullptr,
+                    isForPrinting,
+                    getter_AddRefs(printProgressListener),
+                    getter_AddRefs(printProgressParams),
+                    &doNotify);
+
+  return true;
+}
+
+bool
+PrintingParent::RecvShowPrintDialog(PBrowserParent* parent,
+                                    const PrintData& data,
+                                    PrintData* retVal,
+                                    bool* success)
+{
+  *success = false;
+
+  TabParent* tabParent = static_cast<TabParent*>(parent);
+  if (!tabParent) {
+    return true;
+  }
+
+  nsCOMPtr<Element> frameElement = tabParent->GetOwnerElement();
+  if (!frameElement) {
+    return true;
+  }
+
+  nsCOMPtr<nsIContent> frame(do_QueryInterface(frameElement));
+  if (!frame) {
+    return true;
+  }
+
+  nsCOMPtr<nsIDOMWindow> parentWin = do_QueryInterface(frame->OwnerDoc()->GetWindow());
+  if (!parentWin) {
+    return true;
+  }
+
+  nsCOMPtr<nsIPrintingPromptService> pps(do_GetService("@mozilla.org/embedcomp/printingprompt-service;1"));
+
+  if (!pps) {
+    return true;
+  }
+
+  // The initSettings we got can be wrapped using
+  // PrintDataUtils' MockWebBrowserPrint, which implements enough of
+  // nsIWebBrowserPrint to keep the dialogs happy.
+  nsCOMPtr<nsIWebBrowserPrint> wbp = new MockWebBrowserPrint(data);
+
+  nsresult rv;
+  nsCOMPtr<nsIPrintOptions> po = do_GetService("@mozilla.org/gfx/printsettings-service;1", &rv);
+  NS_ENSURE_SUCCESS(rv, true);
+
+  nsCOMPtr<nsIPrintSettings> settings;
+  rv = po->CreatePrintSettings(getter_AddRefs(settings));
+  NS_ENSURE_SUCCESS(rv, true);
+
+  rv = po->DeserializeToPrintSettings(data, settings);
+  NS_ENSURE_SUCCESS(rv, true);
+
+  rv = pps->ShowPrintDialog(parentWin, wbp, settings);
+  NS_ENSURE_SUCCESS(rv, true);
+
+  // And send it back.
+  PrintData result;
+  rv = po->SerializeToPrintData(settings, nullptr, &result);
+  NS_ENSURE_SUCCESS(rv, true);
+
+  *retVal = result;
+  *success = true;
+  return true;
+}
+
+void
+PrintingParent::ActorDestroy(ActorDestroyReason aWhy)
+{
+}
+
+MOZ_IMPLICIT PrintingParent::PrintingParent()
+{
+    MOZ_COUNT_CTOR(PrintingParent);
+}
+
+MOZ_IMPLICIT PrintingParent::~PrintingParent()
+{
+    MOZ_COUNT_DTOR(PrintingParent);
+}
+
+} // namespace embedding
+} // namespace mozilla
+
new file mode 100644
--- /dev/null
+++ b/embedding/components/printingui/ipc/PrintingParent.h
@@ -0,0 +1,37 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim: set sw=4 ts=8 et tw=80 : */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_embedding_PrintingParent_h
+#define mozilla_embedding_PrintingParent_h
+
+#include "mozilla/embedding/PPrintingParent.h"
+#include "mozilla/dom/PBrowserParent.h"
+
+namespace mozilla {
+namespace embedding {
+class PrintingParent : public PPrintingParent
+{
+public:
+    virtual bool
+    RecvShowProgress(PBrowserParent* parent,
+                     const bool& isForPrinting);
+    virtual bool
+    RecvShowPrintDialog(PBrowserParent* parent,
+                        const PrintData& initSettings,
+                        PrintData* retVal,
+                        bool* success);
+
+    virtual void
+    ActorDestroy(ActorDestroyReason aWhy);
+
+    MOZ_IMPLICIT PrintingParent();
+    virtual ~PrintingParent();
+};
+} // namespace embedding
+} // namespace mozilla
+
+#endif
+
new file mode 100644
--- /dev/null
+++ b/embedding/components/printingui/ipc/moz.build
@@ -0,0 +1,25 @@
+# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+EXPORTS.mozilla.embedding.printingui += [
+    'PrintingParent.h',
+]
+
+UNIFIED_SOURCES += [
+    'nsPrintingPromptServiceProxy.cpp',
+    'PrintDataUtils.cpp',
+    'PrintingParent.cpp',
+]
+
+IPDL_SOURCES += [
+    'PPrinting.ipdl',
+]
+
+include('/ipc/chromium/chromium-config.mozbuild')
+
+FAIL_ON_WARNINGS = True
+
+FINAL_LIBRARY = 'xul'
new file mode 100644
--- /dev/null
+++ b/embedding/components/printingui/ipc/nsPrintingPromptServiceProxy.cpp
@@ -0,0 +1,135 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/dom/ContentChild.h"
+#include "mozilla/dom/TabChild.h"
+#include "mozilla/unused.h"
+#include "nsIDocShell.h"
+#include "nsIDocShellTreeOwner.h"
+#include "nsPIDOMWindow.h"
+#include "nsPrintingPromptServiceProxy.h"
+#include "nsIPrintingPromptService.h"
+#include "PrintDataUtils.h"
+#include "nsPrintOptionsImpl.h"
+
+using namespace mozilla;
+using namespace mozilla::dom;
+using namespace mozilla::embedding;
+
+NS_IMPL_ISUPPORTS(nsPrintingPromptServiceProxy, nsIPrintingPromptService)
+
+nsPrintingPromptServiceProxy::nsPrintingPromptServiceProxy()
+{
+}
+
+nsPrintingPromptServiceProxy::~nsPrintingPromptServiceProxy()
+{
+}
+
+nsresult
+nsPrintingPromptServiceProxy::Init()
+{
+  mozilla::unused << ContentChild::GetSingleton()->SendPPrintingConstructor(this);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsPrintingPromptServiceProxy::ShowPrintDialog(nsIDOMWindow *parent,
+                                              nsIWebBrowserPrint *webBrowserPrint,
+                                              nsIPrintSettings *printSettings)
+{
+  NS_ENSURE_ARG(parent);
+  NS_ENSURE_ARG(webBrowserPrint);
+  NS_ENSURE_ARG(printSettings);
+
+  // Get the root docshell owner of this nsIDOMWindow, which
+  // should map to a TabChild, which we can then pass up to
+  // the parent.
+  nsCOMPtr<nsPIDOMWindow> pwin = do_QueryInterface(parent);
+  NS_ENSURE_STATE(pwin);
+  nsCOMPtr<nsIDocShell> docShell = pwin->GetDocShell();
+  NS_ENSURE_STATE(docShell);
+  nsCOMPtr<nsIDocShellTreeOwner> owner;
+  nsresult rv = docShell->GetTreeOwner(getter_AddRefs(owner));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsCOMPtr<nsITabChild> tabchild = do_GetInterface(owner);
+  NS_ENSURE_STATE(tabchild);
+
+  TabChild* pBrowser = static_cast<TabChild*>(tabchild.get());
+
+  // Next, serialize the nsIWebBrowserPrint and nsIPrintSettings we were given.
+  nsCOMPtr<nsIPrintOptions> po =
+    do_GetService("@mozilla.org/gfx/printsettings-service;1", &rv);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  PrintData inSettings;
+  rv = po->SerializeToPrintData(printSettings, webBrowserPrint, &inSettings);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  PrintData modifiedSettings;
+  bool success;
+
+  mozilla::unused << SendShowPrintDialog(pBrowser, inSettings, &modifiedSettings, &success);
+
+  if (!success) {
+    // Something failed in the parent.
+    return NS_ERROR_FAILURE;
+  }
+
+  rv = po->DeserializeToPrintSettings(modifiedSettings, printSettings);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsPrintingPromptServiceProxy::ShowProgress(nsIDOMWindow*            parent,
+                                           nsIWebBrowserPrint*      webBrowserPrint,    // ok to be null
+                                           nsIPrintSettings*        printSettings,      // ok to be null
+                                           nsIObserver*             openDialogObserver, // ok to be null
+                                           bool                     isForPrinting,
+                                           nsIWebProgressListener** webProgressListener,
+                                           nsIPrintProgressParams** printProgressParams,
+                                           bool*                  notifyOnOpen)
+{
+  NS_ENSURE_ARG(parent);
+  NS_ENSURE_ARG(webProgressListener);
+  NS_ENSURE_ARG(printProgressParams);
+  NS_ENSURE_ARG(notifyOnOpen);
+
+  // Get the root docshell owner of this nsIDOMWindow, which
+  // should map to a TabChild, which we can then pass up to
+  // the parent.
+  nsCOMPtr<nsPIDOMWindow> pwin = do_QueryInterface(parent);
+  NS_ENSURE_STATE(pwin);
+  nsCOMPtr<nsIDocShell> docShell = pwin->GetDocShell();
+  NS_ENSURE_STATE(docShell);
+  nsCOMPtr<nsIDocShellTreeOwner> owner;
+  nsresult rv = docShell->GetTreeOwner(getter_AddRefs(owner));
+  NS_ENSURE_SUCCESS(rv, rv);
+  nsCOMPtr<nsITabChild> tabchild = do_GetInterface(owner);
+  TabChild* pBrowser = static_cast<TabChild*>(tabchild.get());
+
+  mozilla::unused << SendShowProgress(pBrowser, isForPrinting);
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsPrintingPromptServiceProxy::ShowPageSetup(nsIDOMWindow *parent,
+                                            nsIPrintSettings *printSettings,
+                                            nsIObserver *aObs)
+{
+    return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+nsPrintingPromptServiceProxy::ShowPrinterProperties(nsIDOMWindow *parent,
+                                                    const char16_t *printerName,
+                                                    nsIPrintSettings *printSettings)
+{
+    return NS_ERROR_NOT_IMPLEMENTED;
+}
+
new file mode 100644
--- /dev/null
+++ b/embedding/components/printingui/ipc/nsPrintingPromptServiceProxy.h
@@ -0,0 +1,27 @@
+/* -*- 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 __nsPrintingPromptServiceProxy_h
+#define __nsPrintingPromptServiceProxy_h
+
+#include "nsIPrintingPromptService.h"
+#include "mozilla/embedding/PPrintingChild.h"
+
+class nsPrintingPromptServiceProxy: public nsIPrintingPromptService,
+                                    public mozilla::embedding::PPrintingChild
+{
+    virtual ~nsPrintingPromptServiceProxy();
+
+public:
+    nsPrintingPromptServiceProxy();
+
+    nsresult Init();
+
+    NS_DECL_ISUPPORTS
+    NS_DECL_NSIPRINTINGPROMPTSERVICE
+};
+
+#endif
+
--- a/embedding/components/printingui/moz.build
+++ b/embedding/components/printingui/moz.build
@@ -1,14 +1,16 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 toolkit = CONFIG['MOZ_WIDGET_TOOLKIT']
 
+DIRS += ['ipc']
+
 if toolkit == 'windows':
     DIRS += ['win']
 elif toolkit == 'cocoa':
     DIRS += ['mac']
 elif CONFIG['MOZ_PDF_PRINTING']:
     DIRS += ['unixshared']
--- a/embedding/components/printingui/win/moz.build
+++ b/embedding/components/printingui/win/moz.build
@@ -6,11 +6,15 @@
 
 UNIFIED_SOURCES += [
     'nsPrintDialogUtil.cpp',
     'nsPrintingPromptService.cpp',
     'nsPrintProgress.cpp',
     'nsPrintProgressParams.cpp',
 ]
 
+EXPORTS += [
+    'nsPrintDialogUtil.h',
+]
+
 FAIL_ON_WARNINGS = True
 
 FINAL_LIBRARY = 'xul'
--- a/embedding/components/printingui/win/nsPrintDialogUtil.cpp
+++ b/embedding/components/printingui/win/nsPrintDialogUtil.cpp
@@ -677,17 +677,17 @@ static UINT CALLBACK PrintHookProc(HWND 
 //----------------------------------------------------------------------------------
 // Returns a Global Moveable Memory Handle to a DevMode
 // from the Printer by the name of aPrintName
 //
 // NOTE:
 //   This function assumes that aPrintName has already been converted from 
 //   unicode
 //
-static HGLOBAL CreateGlobalDevModeAndInit(const nsXPIDLString& aPrintName, nsIPrintSettings* aPS)
+HGLOBAL CreateGlobalDevModeAndInit(const nsXPIDLString& aPrintName, nsIPrintSettings* aPS)
 {
   HGLOBAL hGlobalDevMode = nullptr;
 
   HANDLE hPrinter = nullptr;
   // const cast kludge for silly Win32 api's
   LPWSTR printName = const_cast<wchar_t*>(static_cast<const wchar_t*>(aPrintName.get()));
   BOOL status = ::OpenPrinterW(printName, &hPrinter, nullptr);
   if (status) {
--- a/embedding/components/printingui/win/nsPrintDialogUtil.h
+++ b/embedding/components/printingui/win/nsPrintDialogUtil.h
@@ -4,9 +4,11 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 #ifndef nsFlyOwnDialog_h___
 #define nsFlyOwnDialog_h___
 
 nsresult NativeShowPrintDialog(HWND                aHWnd,
                                nsIWebBrowserPrint* aWebBrowserPrint,
                                nsIPrintSettings*   aPrintSettings);
 
+HGLOBAL CreateGlobalDevModeAndInit(const nsXPIDLString& aPrintName, nsIPrintSettings* aPS);
+
 #endif /* nsFlyOwnDialog_h___ */
--- a/mobile/android/base/BrowserApp.java
+++ b/mobile/android/base/BrowserApp.java
@@ -16,17 +16,16 @@ import java.util.Locale;
 import java.util.Vector;
 
 import org.json.JSONException;
 import org.json.JSONObject;
 import org.mozilla.gecko.AppConstants.Versions;
 import org.mozilla.gecko.DynamicToolbar.PinReason;
 import org.mozilla.gecko.DynamicToolbar.VisibilityTransition;
 import org.mozilla.gecko.GeckoProfileDirectories.NoMozillaDirectoryException;
-import org.mozilla.gecko.ReadingListHelper;
 import org.mozilla.gecko.animation.PropertyAnimator;
 import org.mozilla.gecko.animation.ViewHelper;
 import org.mozilla.gecko.db.BrowserContract.Combined;
 import org.mozilla.gecko.db.BrowserContract.SearchHistory;
 import org.mozilla.gecko.db.BrowserDB;
 import org.mozilla.gecko.db.SuggestedSites;
 import org.mozilla.gecko.distribution.Distribution;
 import org.mozilla.gecko.favicons.Favicons;
@@ -47,16 +46,17 @@ import org.mozilla.gecko.home.BrowserSea
 import org.mozilla.gecko.home.HomeBanner;
 import org.mozilla.gecko.home.HomePager;
 import org.mozilla.gecko.home.HomePager.OnUrlOpenInBackgroundListener;
 import org.mozilla.gecko.home.HomePager.OnUrlOpenListener;
 import org.mozilla.gecko.home.HomePanelsManager;
 import org.mozilla.gecko.home.SearchEngine;
 import org.mozilla.gecko.menu.GeckoMenu;
 import org.mozilla.gecko.menu.GeckoMenuItem;
+import org.mozilla.gecko.mozglue.ContextUtils;
 import org.mozilla.gecko.preferences.ClearOnShutdownPref;
 import org.mozilla.gecko.preferences.GeckoPreferences;
 import org.mozilla.gecko.prompts.Prompt;
 import org.mozilla.gecko.prompts.PromptListItem;
 import org.mozilla.gecko.sync.setup.SyncAccounts;
 import org.mozilla.gecko.tabs.TabsPanel;
 import org.mozilla.gecko.toolbar.AutocompleteHandler;
 import org.mozilla.gecko.toolbar.BrowserToolbar;
@@ -679,17 +679,17 @@ public class BrowserApp extends GeckoApp
         // We can't show Onboarding until Gecko has finished initialization (bug 1077583).
         checkStartPane(this, getIntent().getAction());
     }
 
     @Override
     public void onResume() {
         super.onResume();
 
-        final String args = StringUtils.getStringExtra(getIntent(), "args");
+        final String args = ContextUtils.getStringExtra(getIntent(), "args");
         // If an external intent tries to start Fennec in guest mode, and it's not already
         // in guest mode, this will change modes before opening the url.
         // NOTE: OnResume is called twice sometimes when showing on the lock screen.
         final boolean enableGuestSession = GuestSession.shouldUse(this, args);
         final boolean inGuestSession = GeckoProfile.get(this).inGuestMode();
         if (enableGuestSession != inGuestSession) {
             doRestart(getIntent());
             GeckoAppShell.systemExit();
@@ -2661,22 +2661,22 @@ public class BrowserApp extends GeckoApp
         if (AboutPages.isAboutReader(url)) {
             String urlFromReader = ReaderModeUtils.getUrlFromAboutReader(url);
             if (urlFromReader != null) {
                 url = urlFromReader;
             }
         }
 
         // Disable share menuitem for about:, chrome:, file:, and resource: URIs
-        final boolean shareEnabled = RestrictedProfiles.isAllowed(RestrictedProfiles.Restriction.DISALLOW_SHARE);
+        final boolean shareEnabled = RestrictedProfiles.isAllowed(this, RestrictedProfiles.Restriction.DISALLOW_SHARE);
         share.setVisible(shareEnabled);
         share.setEnabled(StringUtils.isShareableUrl(url) && shareEnabled);
-        MenuUtils.safeSetEnabled(aMenu, R.id.apps, RestrictedProfiles.isAllowed(RestrictedProfiles.Restriction.DISALLOW_INSTALL_APPS));
-        MenuUtils.safeSetEnabled(aMenu, R.id.addons, RestrictedProfiles.isAllowed(RestrictedProfiles.Restriction.DISALLOW_INSTALL_EXTENSION));
-        MenuUtils.safeSetEnabled(aMenu, R.id.downloads, RestrictedProfiles.isAllowed(RestrictedProfiles.Restriction.DISALLOW_DOWNLOADS));
+        MenuUtils.safeSetEnabled(aMenu, R.id.apps, RestrictedProfiles.isAllowed(this, RestrictedProfiles.Restriction.DISALLOW_INSTALL_APPS));
+        MenuUtils.safeSetEnabled(aMenu, R.id.addons, RestrictedProfiles.isAllowed(this, RestrictedProfiles.Restriction.DISALLOW_INSTALL_EXTENSION));
+        MenuUtils.safeSetEnabled(aMenu, R.id.downloads, RestrictedProfiles.isAllowed(this, RestrictedProfiles.Restriction.DISALLOW_DOWNLOADS));
 
         // NOTE: Use MenuUtils.safeSetEnabled because some actions might
         // be on the BrowserToolbar context menu.
         if (Versions.feature11Plus) {
             MenuUtils.safeSetEnabled(aMenu, R.id.page, !isAboutHome(tab));
         }
         MenuUtils.safeSetEnabled(aMenu, R.id.subscribe, tab.hasFeeds());
         MenuUtils.safeSetEnabled(aMenu, R.id.add_search_engine, tab.hasOpenSearch());
--- a/mobile/android/base/GeckoApp.java
+++ b/mobile/android/base/GeckoApp.java
@@ -35,32 +35,33 @@ import org.mozilla.gecko.gfx.Layer;
 import org.mozilla.gecko.gfx.LayerView;
 import org.mozilla.gecko.gfx.PluginLayer;
 import org.mozilla.gecko.health.HealthRecorder;
 import org.mozilla.gecko.health.SessionInformation;
 import org.mozilla.gecko.health.StubbedHealthRecorder;
 import org.mozilla.gecko.menu.GeckoMenu;
 import org.mozilla.gecko.menu.GeckoMenuInflater;
 import org.mozilla.gecko.menu.MenuPanel;
+import org.mozilla.gecko.mozglue.ContextUtils;
+import org.mozilla.gecko.mozglue.ContextUtils.SafeIntent;
 import org.mozilla.gecko.mozglue.GeckoLoader;
 import org.mozilla.gecko.preferences.ClearOnShutdownPref;
 import org.mozilla.gecko.preferences.GeckoPreferences;
 import org.mozilla.gecko.prompts.PromptService;
 import org.mozilla.gecko.updater.UpdateService;
 import org.mozilla.gecko.updater.UpdateServiceHelper;
 import org.mozilla.gecko.util.ActivityResultHandler;
 import org.mozilla.gecko.util.ActivityUtils;
 import org.mozilla.gecko.util.EventCallback;
 import org.mozilla.gecko.util.FileUtils;
 import org.mozilla.gecko.util.GeckoEventListener;
 import org.mozilla.gecko.util.HardwareUtils;
 import org.mozilla.gecko.util.NativeEventListener;
 import org.mozilla.gecko.util.NativeJSObject;
 import org.mozilla.gecko.util.PrefUtils;
-import org.mozilla.gecko.util.StringUtils;
 import org.mozilla.gecko.util.ThreadUtils;
 import org.mozilla.gecko.webapp.EventListener;
 import org.mozilla.gecko.webapp.UninstallListener;
 import org.mozilla.gecko.widget.ButtonToast;
 
 import android.app.Activity;
 import android.app.AlertDialog;
 import android.app.Dialog;
@@ -1097,18 +1098,18 @@ public abstract class GeckoApp
                 ActivityUtils.setFullScreen(GeckoApp.this, fullscreen);
             }
         });
     }
 
     /**
      * Check and start the Java profiler if MOZ_PROFILER_STARTUP env var is specified.
      **/
-    protected static void earlyStartJavaSampler(Intent intent) {
-        String env = StringUtils.getStringExtra(intent, "env0");
+    protected static void earlyStartJavaSampler(SafeIntent intent) {
+        String env = intent.getStringExtra("env0");
         for (int i = 1; env != null; i++) {
             if (env.startsWith("MOZ_PROFILER_STARTUP=")) {
                 if (!env.endsWith("=")) {
                     GeckoJavaSampler.start(10, 1000);
                     Log.d(LOGTAG, "Profiling Java on startup");
                 }
                 break;
             }
@@ -1118,32 +1119,31 @@ public abstract class GeckoApp
 
     /**
      * Called when the activity is first created.
      *
      * Here we initialize all of our profile settings, Firefox Health Report,
      * and other one-shot constructions.
      **/
     @Override
-    public void onCreate(Bundle savedInstanceState)
-    {
+    public void onCreate(Bundle savedInstanceState) {
         GeckoAppShell.ensureCrashHandling();
 
         // Enable Android Strict Mode for developers' local builds (the "default" channel).
         if ("default".equals(AppConstants.MOZ_UPDATE_CHANNEL)) {
             enableStrictMode();
         }
 
         // The clock starts...now. Better hurry!
         mJavaUiStartupTimer = new Telemetry.UptimeTimer("FENNEC_STARTUP_TIME_JAVAUI");
         mGeckoReadyStartupTimer = new Telemetry.UptimeTimer("FENNEC_STARTUP_TIME_GECKOREADY");
 
-        final Intent intent = getIntent();
+        final SafeIntent intent = new SafeIntent(getIntent());
         final String action = intent.getAction();
-        final String args = StringUtils.getStringExtra(intent, "args");
+        final String args = intent.getStringExtra("args");
 
         earlyStartJavaSampler(intent);
 
         // GeckoLoader wants to dig some environment variables out of the
         // incoming intent, so pass it in here. GeckoLoader will do its
         // business later and dispose of the reference.
         GeckoLoader.setLastIntent(intent);
 
@@ -1249,17 +1249,17 @@ public abstract class GeckoApp
                 @Override
                 public void run() {
                     GeckoThread.setLaunchState(GeckoThread.LaunchState.Launched);
                     GeckoThread.createAndStart();
                 }
             }, 1000 * 5 /* 5 seconds */);
         }
 
-        Bundle stateBundle = getIntent().getBundleExtra(EXTRA_STATE_BUNDLE);
+        Bundle stateBundle = ContextUtils.getBundleExtra(getIntent(), EXTRA_STATE_BUNDLE);
         if (stateBundle != null) {
             // Use the state bundle if it was given as an intent extra. This is
             // only intended to be used internally via Robocop, so a boolean
             // is read from a private shared pref to prevent other apps from
             // injecting states.
             final SharedPreferences prefs = getSharedPreferences();
             if (prefs.getBoolean(PREFS_ALLOW_STATE_BUNDLE, false)) {
                 prefs.edit().remove(PREFS_ALLOW_STATE_BUNDLE).apply();
@@ -1453,28 +1453,31 @@ public abstract class GeckoApp
             int flags = Tabs.LOADURL_NEW_TAB | Tabs.LOADURL_USER_ENTERED | Tabs.LOADURL_EXTERNAL;
             Tabs.getInstance().loadUrl(url, flags);
         }
     }
 
     private void initialize() {
         mInitialized = true;
 
-        Intent intent = getIntent();
-        String action = intent.getAction();
-
-        String passedUri = null;
+        final SafeIntent intent = new SafeIntent(getIntent());
+        final String action = intent.getAction();
+
         final String uri = getURIFromIntent(intent);
+
+        final String passedUri;
         if (!TextUtils.isEmpty(uri)) {
             passedUri = uri;
+        } else {
+            passedUri = null;
         }
 
         final boolean isExternalURL = passedUri != null &&
                                       !AboutPages.isAboutHome(passedUri);
-        StartupAction startupAction;
+        final StartupAction startupAction;
         if (isExternalURL) {
             startupAction = StartupAction.URL;
         } else {
             startupAction = StartupAction.NORMAL;
         }
 
         // Start migrating as early as possible, can do this in
         // parallel with Gecko load.
@@ -1527,17 +1530,17 @@ public abstract class GeckoApp
         }
 
         Telemetry.HistogramAdd("FENNEC_STARTUP_GECKOAPP_ACTION", startupAction.ordinal());
 
         // Check if launched from data reporting notification.
         if (ACTION_LAUNCH_SETTINGS.equals(action)) {
             Intent settingsIntent = new Intent(GeckoApp.this, GeckoPreferences.class);
             // Copy extras.
-            settingsIntent.putExtras(intent);
+            settingsIntent.putExtras(intent.getUnsafe());
             startActivity(settingsIntent);
         }
 
         //app state callbacks
         mAppStateListeners = new LinkedList<GeckoAppShell.AppStateListener>();
 
         //register for events
         EventDispatcher.getInstance().registerGeckoThreadListener((GeckoEventListener)this,
@@ -1727,17 +1730,17 @@ public abstract class GeckoApp
         return shouldRestore;
     }
 
     private String getSessionRestorePreference() {
         return getSharedPreferences().getString(GeckoPreferences.PREFS_RESTORE_SESSION, "quit");
     }
 
     private boolean getRestartFromIntent() {
-        return getIntent().getBooleanExtra("didRestart", false);
+        return ContextUtils.getBooleanExtra(getIntent(), "didRestart", false);
     }
 
     /**
      * Enable Android StrictMode checks (for supported OS versions).
      * http://developer.android.com/reference/android/os/StrictMode.html
      */
     private void enableStrictMode() {
         Log.d(LOGTAG, "Enabling Android StrictMode");
@@ -1793,44 +1796,46 @@ public abstract class GeckoApp
     }
 
     @Override
     public String getDefaultUAString() {
         return HardwareUtils.isTablet() ? AppConstants.USER_AGENT_FENNEC_TABLET :
                                           AppConstants.USER_AGENT_FENNEC_MOBILE;
     }
 
-    private void processAlertCallback(Intent intent) {
+    private void processAlertCallback(SafeIntent intent) {
         String alertName = "";
         String alertCookie = "";
         Uri data = intent.getData();
         if (data != null) {
             alertName = data.getQueryParameter("name");
             if (alertName == null)
                 alertName = "";
             alertCookie = data.getQueryParameter("cookie");
             if (alertCookie == null)
                 alertCookie = "";
         }
         handleNotification(ACTION_ALERT_CALLBACK, alertName, alertCookie);
     }
 
     @Override
-    protected void onNewIntent(Intent intent) {
+    protected void onNewIntent(Intent externalIntent) {
+        final SafeIntent intent = new SafeIntent(externalIntent);
+
         if (GeckoThread.checkLaunchState(GeckoThread.LaunchState.GeckoExiting)) {
             // We're exiting and shouldn't try to do anything else. In the case
             // where we are hung while exiting, we should force the process to exit.
             GeckoAppShell.systemExit();
             return;
         }
 
         // if we were previously OOM killed, we can end up here when launching
         // from external shortcuts, so set this as the intent for initialization
         if (!mInitialized) {
-            setIntent(intent);
+            setIntent(externalIntent);
             return;
         }
 
         final String action = intent.getAction();
 
         if (ACTION_LOAD.equals(action)) {
             String uri = intent.getDataString();
             Tabs.getInstance().loadUrl(uri);
@@ -1854,26 +1859,26 @@ public abstract class GeckoApp
         } else if (ACTION_ALERT_CALLBACK.equals(action)) {
             processAlertCallback(intent);
         } else if (NotificationHelper.HELPER_BROADCAST_ACTION.equals(action)) {
             NotificationHelper.getInstance(getApplicationContext()).handleNotificationIntent(intent);
         } else if (ACTION_LAUNCH_SETTINGS.equals(action)) {
             // Check if launched from data reporting notification.
             Intent settingsIntent = new Intent(GeckoApp.this, GeckoPreferences.class);
             // Copy extras.
-            settingsIntent.putExtras(intent);
+            settingsIntent.putExtras(intent.getUnsafe());
             startActivity(settingsIntent);
         }
     }
 
     /**
      * Handles getting a URI from an intent in a way that is backwards-
      * compatible with our previous implementations.
      */
-    protected String getURIFromIntent(Intent intent) {
+    protected String getURIFromIntent(SafeIntent intent) {
         final String action = intent.getAction();
         if (ACTION_ALERT_CALLBACK.equals(action) || NotificationHelper.HELPER_BROADCAST_ACTION.equals(action)) {
             return null;
         }
 
         return intent.getDataString();
     }
 
--- a/mobile/android/base/GeckoAppShell.java
+++ b/mobile/android/base/GeckoAppShell.java
@@ -20,45 +20,41 @@ import java.net.URLConnection;
 import java.nio.ByteBuffer;
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
 import java.util.NoSuchElementException;
 import java.util.Queue;
-import java.util.Set;
 import java.util.StringTokenizer;
 import java.util.TreeMap;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentLinkedQueue;
 
-import org.json.JSONException;
-import org.json.JSONObject;
 import org.mozilla.gecko.AppConstants.Versions;
 import org.mozilla.gecko.favicons.OnFaviconLoadedListener;
 import org.mozilla.gecko.favicons.decoders.FaviconDecoder;
 import org.mozilla.gecko.gfx.BitmapUtils;
 import org.mozilla.gecko.gfx.LayerView;
 import org.mozilla.gecko.gfx.PanZoomController;
+import org.mozilla.gecko.mozglue.ContextUtils;
 import org.mozilla.gecko.mozglue.GeckoLoader;
 import org.mozilla.gecko.mozglue.JNITarget;
 import org.mozilla.gecko.mozglue.RobocopTarget;
 import org.mozilla.gecko.mozglue.generatorannotations.OptionalGeneratedParameter;
 import org.mozilla.gecko.mozglue.generatorannotations.WrapElementForJNI;
 import org.mozilla.gecko.prompts.PromptService;
-import org.mozilla.gecko.SmsManager;
 import org.mozilla.gecko.util.EventCallback;
 import org.mozilla.gecko.util.GeckoRequest;
 import org.mozilla.gecko.util.HardwareUtils;
 import org.mozilla.gecko.util.NativeEventListener;
 import org.mozilla.gecko.util.NativeJSContainer;
 import org.mozilla.gecko.util.NativeJSObject;
 import org.mozilla.gecko.util.ProxySelector;
-import org.mozilla.gecko.util.StringUtils;
 import org.mozilla.gecko.util.ThreadUtils;
 
 import android.app.Activity;
 import android.app.ActivityManager;
 import android.app.PendingIntent;
 import android.content.ActivityNotFoundException;
 import android.content.Context;
 import android.content.Intent;
@@ -2514,17 +2510,17 @@ public class GeckoAppShell
         }
 
         return "DIRECT";
     }
 
     /* Downloads the URI pointed to by a share intent, and alters the intent to point to the locally stored file.
      */
     public static void downloadImageForIntent(final Intent intent) {
-        final String src = StringUtils.getStringExtra(intent, Intent.EXTRA_TEXT);
+        final String src = ContextUtils.getStringExtra(intent, Intent.EXTRA_TEXT);
         if (src == null) {
             showImageShareFailureToast();
             return;
         }
 
         final File dir = GeckoApp.getTempDirectory();
 
         if (dir == null) {
--- a/mobile/android/base/NotificationHelper.java
+++ b/mobile/android/base/NotificationHelper.java
@@ -1,36 +1,33 @@
 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
  * 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/. */
 
 package org.mozilla.gecko;
 
-import org.mozilla.gecko.gfx.BitmapUtils;
-import org.mozilla.gecko.util.GeckoEventListener;
-import org.mozilla.gecko.util.StringUtils;
+import java.util.HashMap;
+import java.util.Iterator;
+
 import org.json.JSONArray;
 import org.json.JSONException;
 import org.json.JSONObject;
+import org.mozilla.gecko.gfx.BitmapUtils;
+import org.mozilla.gecko.mozglue.ContextUtils.SafeIntent;
+import org.mozilla.gecko.util.GeckoEventListener;
 
-import android.app.NotificationManager;
 import android.app.PendingIntent;
-import android.content.BroadcastReceiver;
-import android.content.IntentFilter;
 import android.content.Context;
 import android.content.Intent;
 import android.graphics.Bitmap;
 import android.net.Uri;
 import android.support.v4.app.NotificationCompat;
 import android.util.Log;
 
-import java.util.Iterator;
-import java.util.HashMap;
-
 public final class NotificationHelper implements GeckoEventListener {
     public static final String HELPER_BROADCAST_ACTION = AppConstants.ANDROID_PACKAGE_NAME + ".helperBroadcastAction";
 
     public static final String NOTIFICATION_ID = "NotificationHelper_ID";
     private static final String LOGTAG = "GeckoNotificationHelper";
     private static final String HELPER_NOTIFICATION = "helperNotif";
 
     // Attributes mandatory to be used while sending a notification from js.
@@ -105,17 +102,17 @@ public final class NotificationHelper im
             hideNotification(message);
         }
     }
 
     public boolean isHelperIntent(Intent i) {
         return i.getBooleanExtra(HELPER_NOTIFICATION, false);
     }
 
-    public void handleNotificationIntent(Intent i) {
+    public void handleNotificationIntent(SafeIntent i) {
         final Uri data = i.getData();
         if (data == null) {
             Log.e(LOGTAG, "handleNotificationEvent: empty data");
             return;
         }
         final String id = data.getQueryParameter(ID_ATTR);
         final String notificationType = data.getQueryParameter(EVENT_TYPE_ATTR);
         if (id == null || notificationType == null) {
@@ -132,17 +129,17 @@ public final class NotificationHelper im
                 return;
             }
         }
 
         JSONObject args = new JSONObject();
 
         // The handler and cookie parameters are optional.
         final String handler = data.getQueryParameter(HANDLER_ATTR);
-        final String cookie = StringUtils.getStringExtra(i, COOKIE_ATTR);
+        final String cookie = i.getStringExtra(COOKIE_ATTR);
 
         try {
             args.put(ID_ATTR, id);
             args.put(EVENT_TYPE_ATTR, notificationType);
             args.put(HANDLER_ATTR, handler);
             args.put(COOKIE_ATTR, cookie);
 
             if (BUTTON_EVENT.equals(notificationType)) {
--- a/mobile/android/base/RestrictedProfiles.java
+++ b/mobile/android/base/RestrictedProfiles.java
@@ -20,27 +20,37 @@ import android.os.Build;
 import android.os.Bundle;
 import android.os.UserManager;
 import android.util.Log;
 
 @RobocopTarget
 public class RestrictedProfiles {
     private static final String LOGTAG = "GeckoRestrictedProfiles";
 
-    private static Boolean inGuest = null;
+    private static volatile Boolean inGuest = null;
 
     @SuppressWarnings("serial")
     private static final List<String> BANNED_SCHEMES = new ArrayList<String>() {{
         add("file");
         add("chrome");
         add("resource");
         add("jar");
         add("wyciwyg");
     }};
 
+    /**
+     * This is a hack to allow non-GeckoApp activities to safely call into
+     * RestrictedProfiles without reworking this class or GeckoProfile.
+     *
+     * It can be removed after Bug 1077590 lands.
+     */
+    public static void initWithProfile(GeckoProfile profile) {
+        inGuest = profile.inGuestMode();
+    }
+
     private static boolean getInGuest() {
         if (inGuest == null) {
             inGuest = GeckoAppShell.getGeckoInterface().getProfile().inGuestMode();
         }
 
         return inGuest;
     }
 
@@ -81,51 +91,50 @@ public class RestrictedProfiles {
                 return rest;
             }
         }
 
         throw new IllegalArgumentException("Unknown action " + action);
     }
 
     @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
-    @RobocopTarget
-    private static Bundle getRestrictions() {
-        final UserManager mgr = (UserManager) GeckoAppShell.getContext().getSystemService(Context.USER_SERVICE);
+    private static Bundle getRestrictions(final Context context) {
+        final UserManager mgr = (UserManager) context.getSystemService(Context.USER_SERVICE);
         return mgr.getUserRestrictions();
     }
 
     /**
      * This method does the system version check for you.
      *
      * Returns false if the system doesn't support restrictions,
      * or the provided value is not present in the set of user
      * restrictions.
      *
      * Returns true otherwise.
      */
-    private static boolean getRestriction(final String name) {
+    private static boolean getRestriction(final Context context, final String name) {
         // Early versions don't support restrictions at all,
         // so no action can be restricted.
         if (Versions.preJBMR2) {
             return false;
         }
 
-        return getRestrictions().getBoolean(name, false);
+        return getRestrictions(context).getBoolean(name, false);
     }
 
-    private static boolean canLoadUrl(final String url) {
+    private static boolean canLoadUrl(final Context context, final String url) {
         // Null URLs are always permitted.
         if (url == null) {
             return true;
         }
 
         try {
             // If we're not in guest mode, and the system restriction isn't in place, everything is allowed.
             if (!getInGuest() &&
-                !getRestriction(Restriction.DISALLOW_BROWSE_FILES.name)) {
+                !getRestriction(context, Restriction.DISALLOW_BROWSE_FILES.name)) {
                 return true;
             }
         } catch (IllegalArgumentException ex) {
             Log.i(LOGTAG, "Invalid action", ex);
         }
 
         final Uri u = Uri.parse(url);
         final String scheme = u.getScheme();
@@ -140,59 +149,71 @@ public class RestrictedProfiles {
         }
 
         // TODO: The UserManager should support blacklisting URLs by the device owner.
         return true;
     }
 
     @WrapElementForJNI
     public static boolean isUserRestricted() {
+        return isUserRestricted(GeckoAppShell.getContext());
+    }
+
+    private static boolean isUserRestricted(final Context context) {
         // Guest mode is supported in all Android versions.
         if (getInGuest()) {
             return true;
         }
 
         if (Versions.preJBMR2) {
             return false;
         }
 
-        return !getRestrictions().isEmpty();
+        return !getRestrictions(context).isEmpty();
     }
 
-    public static boolean isAllowed(Restriction action) {
-        return isAllowed(action.id, null);
+    public static boolean isAllowed(final Context context, final Restriction action) {
+        return isAllowed(context, action.id, null);
     }
 
     @WrapElementForJNI
     public static boolean isAllowed(int action, String url) {
+        return isAllowed(GeckoAppShell.getContext(), action, url);
+    }
+
+    private static boolean isAllowed(final Context context, int action, String url) {
         final Restriction restriction;
         try {
             restriction = geckoActionToRestriction(action);
         } catch (IllegalArgumentException ex) {
             // Unknown actions represent a coding error, so we
             // refuse the action and log.
             Log.e(LOGTAG, "Unknown action " + action + "; check calling code.");
             return false;
         }
 
         if (getInGuest()) {
             if (Restriction.DISALLOW_BROWSE_FILES == restriction) {
-                return canLoadUrl(url);
+                return canLoadUrl(context, url);
             }
 
             // Guest users can't do anything.
             return false;
         }
 
         // NOTE: Restrictions hold the opposite intention, so we need to flip it.
-        return !getRestriction(restriction.name);
+        return !getRestriction(context, restriction.name);
     }
 
     @WrapElementForJNI
     public static String getUserRestrictions() {
+        return getUserRestrictions(GeckoAppShell.getContext());
+    }
+
+    private static String getUserRestrictions(final Context context) {
         // Guest mode is supported in all Android versions
         if (getInGuest()) {
             StringBuilder builder = new StringBuilder("{ ");
 
             for (Restriction restriction : Restriction.values()) {
                 builder.append("\"" + restriction.name + "\": true, ");
             }
 
@@ -200,17 +221,17 @@ public class RestrictedProfiles {
             return builder.toString();
         }
 
         if (Versions.preJBMR2) {
             return "{}";
         }
 
         final JSONObject json = new JSONObject();
-        final Bundle restrictions = getRestrictions();
+        final Bundle restrictions = getRestrictions(context);
         final Set<String> keys = restrictions.keySet();
 
         for (String key : keys) {
             try {
                 json.put(key, restrictions.get(key));
             } catch (JSONException e) {
             }
         }
--- a/mobile/android/base/favicons/LoadFaviconTask.java
+++ b/mobile/android/base/favicons/LoadFaviconTask.java
@@ -333,27 +333,30 @@ public class LoadFaviconTask {
     Bitmap doInBackground() {
         if (isCancelled()) {
             return null;
         }
 
         // Attempt to decode the favicon URL as a data URL. We don't bother storing such URIs in
         // the database: the cost of decoding them here probably doesn't exceed the cost of mucking
         // about with the DB.
-        LoadFaviconResult uriBitmaps = FaviconDecoder.decodeDataURI(faviconURL);
-        if (uriBitmaps != null) {
-            return pushToCacheAndGetResult(uriBitmaps);
+        final boolean isEmpty = TextUtils.isEmpty(faviconURL);
+        if (!isEmpty) {
+            LoadFaviconResult uriBitmaps = FaviconDecoder.decodeDataURI(faviconURL);
+            if (uriBitmaps != null) {
+                return pushToCacheAndGetResult(uriBitmaps);
+            }
         }
 
         String storedFaviconUrl;
         boolean isUsingDefaultURL = false;
 
         // Handle the case of malformed favicon URL.
         // If favicon is empty, fall back to the stored one.
-        if (TextUtils.isEmpty(faviconURL)) {
+        if (isEmpty) {
             // Try to get the favicon URL from the memory cache.
             storedFaviconUrl = Favicons.getFaviconURLForPageURLFromCache(pageUrl);
 
             // If that failed, try to get the URL from the database.
             if (storedFaviconUrl == null) {
                 storedFaviconUrl = Favicons.getFaviconURLForPageURL(context, pageUrl);
                 if (storedFaviconUrl != null) {
                     // If that succeeded, cache the URL loaded from the database in memory.
--- a/mobile/android/base/home/HomeConfigPrefsBackend.java
+++ b/mobile/android/base/home/HomeConfigPrefsBackend.java
@@ -80,17 +80,17 @@ class HomeConfigPrefsBackend implements 
             panelConfigs.add(createBuiltinPanelConfig(mContext, PanelType.READING_LIST));
         }
 
         final PanelConfig historyEntry = createBuiltinPanelConfig(mContext, PanelType.HISTORY);
         final PanelConfig recentTabsEntry = createBuiltinPanelConfig(mContext, PanelType.RECENT_TABS);
 
         // We disable Synced Tabs for guest mode profiles.
         final PanelConfig remoteTabsEntry;
-        if (RestrictedProfiles.isAllowed(RestrictedProfiles.Restriction.DISALLOW_MODIFY_ACCOUNTS)) {
+        if (RestrictedProfiles.isAllowed(mContext, RestrictedProfiles.Restriction.DISALLOW_MODIFY_ACCOUNTS)) {
             remoteTabsEntry = createBuiltinPanelConfig(mContext, PanelType.REMOTE_TABS);
         } else {
             remoteTabsEntry = null;
         }
 
         // On tablets, we go [...|History|Recent Tabs|Synced Tabs].
         // On phones, we go [Synced Tabs|Recent Tabs|History|...].
         if (HardwareUtils.isTablet()) {
--- a/mobile/android/base/moz.build
+++ b/mobile/android/base/moz.build
@@ -22,16 +22,17 @@ if CONFIG['MOZ_NATIVE_DEVICES']:
     resjar.generated_sources += ['android/support/v7/appcompat/R.java']
     resjar.generated_sources += ['android/support/v7/mediarouter/R.java']
 
 resjar.javac_flags += ['-Xlint:all']
 
 mgjar = add_java_jar('gecko-mozglue')
 mgjar.sources += [
     'mozglue/ByteBufferInputStream.java',
+    'mozglue/ContextUtils.java',
     'mozglue/DirectBufferAllocator.java',
     'mozglue/generatorannotations/OptionalGeneratedParameter.java',
     'mozglue/generatorannotations/WrapElementForJNI.java',
     'mozglue/generatorannotations/WrapEntireClassForJNI.java',
     'mozglue/JNITarget.java',
     'mozglue/NativeReference.java',
     'mozglue/NativeZip.java',
     'mozglue/RobocopTarget.java',
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/mozglue/ContextUtils.java
@@ -0,0 +1,102 @@
+/* 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/. */
+
+package org.mozilla.gecko.mozglue;
+
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.util.Log;
+
+public class ContextUtils {
+    private static final String LOGTAG = "GeckoContextUtils";
+
+    public static Bundle getBundleExtra(final Intent intent, final String name) {
+        return new SafeIntent(intent).getBundleExtra(name);
+    }
+
+    public static String getStringExtra(final Intent intent, final String name) {
+        return new SafeIntent(intent).getStringExtra(name);
+    }
+
+    public static boolean getBooleanExtra(Intent intent, String name, boolean defaultValue) {
+        return new SafeIntent(intent).getBooleanExtra(name, defaultValue);
+    }
+
+    public static class SafeIntent {
+        private final Intent intent;
+
+        public SafeIntent(final Intent intent) {
+            this.intent = intent;
+        }
+
+        public boolean getBooleanExtra(final String name, final boolean defaultValue) {
+            try {
+                return intent.getBooleanExtra(name, defaultValue);
+            } catch (OutOfMemoryError e) {
+                Log.w(LOGTAG, "Couldn't get intent extras: OOM. Malformed?");
+                return defaultValue;
+            } catch (RuntimeException e) {
+                Log.w(LOGTAG, "Couldn't get intent extras.", e);
+                return defaultValue;
+            }
+        }
+
+        public String getStringExtra(final String name) {
+            try {
+                return intent.getStringExtra(name);
+            } catch (OutOfMemoryError e) {
+                Log.w(LOGTAG, "Couldn't get intent extras: OOM. Malformed?");
+                return null;
+            } catch (RuntimeException e) {
+                Log.w(LOGTAG, "Couldn't get intent extras.", e);
+                return null;
+            }
+        }
+
+        public Bundle getBundleExtra(final String name) {
+            try {
+                return intent.getBundleExtra(name);
+            } catch (OutOfMemoryError e) {
+                Log.w(LOGTAG, "Couldn't get intent extras: OOM. Malformed?");
+                return null;
+            } catch (RuntimeException e) {
+                Log.w(LOGTAG, "Couldn't get intent extras.", e);
+                return null;
+            }
+        }
+
+        public String getAction() {
+            return intent.getAction();
+        }
+
+        public String getDataString() {
+            try {
+                return intent.getDataString();
+            } catch (OutOfMemoryError e) {
+                Log.w(LOGTAG, "Couldn't get intent data string: OOM. Malformed?");
+                return null;
+            } catch (RuntimeException e) {
+                Log.w(LOGTAG, "Couldn't get intent data string.", e);
+                return null;
+            }
+        }
+
+        public Uri getData() {
+            try {
+                return intent.getData();
+            } catch (OutOfMemoryError e) {
+                Log.w(LOGTAG, "Couldn't get intent data: OOM. Malformed?");
+                return null;
+            } catch (RuntimeException e) {
+                Log.w(LOGTAG, "Couldn't get intent data.", e);
+                return null;
+            }
+        }
+
+        public Intent getUnsafe() {
+            return intent;
+        }
+    }
+}
--- a/mobile/android/base/mozglue/GeckoLoader.java.in
+++ b/mobile/android/base/mozglue/GeckoLoader.java.in
@@ -17,24 +17,26 @@ import java.util.zip.ZipEntry;
 import java.util.zip.ZipFile;
 
 import android.content.Context;
 import android.content.Intent;
 import android.os.Build;
 import android.os.Environment;
 import android.util.Log;
 
+import org.mozilla.gecko.mozglue.ContextUtils.SafeIntent;
+
 public final class GeckoLoader {
     private static final String LOGTAG = "GeckoLoader";
 
     // These match AppConstants, but we're built earlier.
     private static final String ANDROID_PACKAGE_NAME = "@ANDROID_PACKAGE_NAME@";
     private static final String MOZ_APP_ABI = "@MOZ_APP_ABI@";
 
-    private static volatile Intent sIntent;
+    private static volatile SafeIntent sIntent;
     private static File sCacheFile;
     private static File sGREDir;
 
     private static final Object sLibLoadingLock = new Object();
     // Must hold sLibLoadingLock while accessing the following boolean variables.
     private static boolean sSQLiteLibsLoaded;
     private static boolean sNSSLibsLoaded;
     private static boolean sMozGlueLoaded;
@@ -118,24 +120,24 @@ public final class GeckoLoader {
         // check if the old tmp dir is there
         File oldDir = new File(tmpDir.getParentFile(), "app_tmp");
         if (oldDir.exists()) {
             delTree(oldDir);
         }
         return tmpDir;
     }
 
-    public static void setLastIntent(Intent intent) {
+    public static void setLastIntent(SafeIntent intent) {
         sIntent = intent;
     }
 
     public static void setupGeckoEnvironment(Context context, String[] pluginDirs, String profilePath) {
         // if we have an intent (we're being launched by an activity)
         // read in any environmental variables from it here
-        final Intent intent = sIntent;
+        final SafeIntent intent = sIntent;
         if (intent != null) {
             String env = intent.getStringExtra("env0");
             Log.d(LOGTAG, "Gecko environment env0: " + env);
             for (int c = 1; env != null; c++) {
                 putenv(env);
                 env = intent.getStringExtra("env" + c);
                 Log.d(LOGTAG, "env" + c + ": " + env);
             }
--- a/mobile/android/base/overlays/ui/ShareDialog.java
+++ b/mobile/android/base/overlays/ui/ShareDialog.java
@@ -14,18 +14,18 @@ import org.mozilla.gecko.LocaleAware;
 import org.mozilla.gecko.R;
 import org.mozilla.gecko.db.LocalBrowserDB;
 import org.mozilla.gecko.overlays.OverlayConstants;
 import org.mozilla.gecko.overlays.service.OverlayActionService;
 import org.mozilla.gecko.overlays.service.sharemethods.ParcelableClientRecord;
 import org.mozilla.gecko.overlays.service.sharemethods.SendTab;
 import org.mozilla.gecko.overlays.service.sharemethods.ShareMethod;
 import org.mozilla.gecko.sync.setup.activities.WebURLFinder;
+import org.mozilla.gecko.mozglue.ContextUtils;
 import org.mozilla.gecko.util.HardwareUtils;
-import org.mozilla.gecko.util.StringUtils;
 import org.mozilla.gecko.util.ThreadUtils;
 import org.mozilla.gecko.util.UIAsyncTask;
 
 import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
@@ -116,17 +116,17 @@ public class ShareDialog extends LocaleA
         super.onCreate(savedInstanceState);
 
         getWindow().setWindowAnimations(0);
 
         Intent intent = getIntent();
         final Resources resources = getResources();
 
         // The URL is usually hiding somewhere in the extra text. Extract it.
-        final String extraText = StringUtils.getStringExtra(intent, Intent.EXTRA_TEXT);
+        final String extraText = ContextUtils.getStringExtra(intent, Intent.EXTRA_TEXT);
         if (TextUtils.isEmpty(extraText)) {
             abortDueToNoURL();
             return;
         }
 
         final String pageUrl = new WebURLFinder(extraText).bestWebURL();
         if (TextUtils.isEmpty(pageUrl)) {
             abortDueToNoURL();
--- a/mobile/android/base/preferences/AndroidImportPreference.java
+++ b/mobile/android/base/preferences/AndroidImportPreference.java
@@ -21,17 +21,17 @@ import android.util.Log;
 class AndroidImportPreference extends MultiPrefMultiChoicePreference {
     private static final String LOGTAG = "AndroidImport";
     public static final String PREF_KEY = "android.not_a_preference.import_android";
     private static final String PREF_KEY_PREFIX = "import_android.data.";
     private final Context mContext;
 
     public static class Handler implements GeckoPreferences.PrefHandler {
         public boolean setupPref(Context context, Preference pref) {
-            return RestrictedProfiles.isAllowed(Restriction.DISALLOW_IMPORT_SETTINGS);
+            return RestrictedProfiles.isAllowed(context, Restriction.DISALLOW_IMPORT_SETTINGS);
         }
 
         public void onChange(Context context, Preference pref, Object newValue) { }
     }
 
     public AndroidImportPreference(Context context, AttributeSet attrs) {
         super(context, attrs);
         mContext = context;
--- a/mobile/android/base/preferences/GeckoPreferences.java
+++ b/mobile/android/base/preferences/GeckoPreferences.java
@@ -291,16 +291,19 @@ OnSharedPreferenceChangeListener
             return;
         }
 
         onLocaleChanged(currentLocale);
     }
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
+        // Make sure RestrictedProfiles is ready.
+        RestrictedProfiles.initWithProfile(GeckoProfile.get(this));
+
         if (GeckoProfile.get(this).inGuestMode()) {
             GuestSession.configureWindow(getWindow());
         }
 
         // Apply the current user-selected locale, if necessary.
         checkLocale();
 
         // Track this so we can decide whether to show locale options.
@@ -695,17 +698,17 @@ OnSharedPreferenceChangeListener
                     continue;
                 } else if (!AppConstants.MOZ_STUMBLER_BUILD_TIME_ENABLED &&
                            (PREFS_GEO_REPORTING.equals(key) ||
                             PREFS_GEO_LEARN_MORE.equals(key))) {
                     preferences.removePreference(pref);
                     i--;
                     continue;
                 } else if (PREFS_DEVTOOLS_REMOTE_ENABLED.equals(key)) {
-                    if (!RestrictedProfiles.isAllowed(RestrictedProfiles.Restriction.DISALLOW_REMOTE_DEBUGGING)) {
+                    if (!RestrictedProfiles.isAllowed(this, RestrictedProfiles.Restriction.DISALLOW_REMOTE_DEBUGGING)) {
                         preferences.removePreference(pref);
                         i--;
                         continue;
                     }
 
                     final Context thisContext = this;
                     pref.setOnPreferenceClickListener(new OnPreferenceClickListener() {
                         @Override
@@ -723,17 +726,17 @@ OnSharedPreferenceChangeListener
                     // for other list prefs will be set in the PrefsHelper
                     // callback, but since this pref doesn't live in Gecko, we
                     // need to handle it separately.
                     ListPreference listPref = (ListPreference) pref;
                     CharSequence selectedEntry = listPref.getEntry();
                     listPref.setSummary(selectedEntry);
                     continue;
                 } else if (PREFS_SYNC.equals(key) &&
-                           !RestrictedProfiles.isAllowed(RestrictedProfiles.Restriction.DISALLOW_MODIFY_ACCOUNTS)) {
+                           !RestrictedProfiles.isAllowed(this, RestrictedProfiles.Restriction.DISALLOW_MODIFY_ACCOUNTS)) {
                     // Don't show sync prefs while in guest mode.
                     preferences.removePreference(pref);
                     i--;
                     continue;
                 } else if (PREFS_SEARCH_RESTORE_DEFAULTS.equals(key)) {
                     pref.setOnPreferenceClickListener(new OnPreferenceClickListener() {
                         @Override
                         public boolean onPreferenceClick(Preference preference) {
--- a/mobile/android/base/tabs/TabsPanel.java
+++ b/mobile/android/base/tabs/TabsPanel.java
@@ -178,17 +178,17 @@ public class TabsPanel extends LinearLay
             }
         });
 
         mTabWidget = (IconTabWidget) findViewById(R.id.tab_widget);
 
         mTabWidget.addTab(R.drawable.tabs_normal, R.string.tabs_normal);
         mTabWidget.addTab(R.drawable.tabs_private, R.string.tabs_private);
 
-        if (RestrictedProfiles.isAllowed(RestrictedProfiles.Restriction.DISALLOW_MODIFY_ACCOUNTS)) {
+        if (RestrictedProfiles.isAllowed(mContext, RestrictedProfiles.Restriction.DISALLOW_MODIFY_ACCOUNTS)) {
             // The initial icon is not the animated icon, because on Android
             // 4.4.2, the animation starts immediately (and can start at other
             // unpredictable times). See Bug 1015974.
             mTabWidget.addTab(R.drawable.tabs_synced, R.string.tabs_synced);
         }
 
         mTabWidget.setTabSelectionListener(this);
 
--- a/mobile/android/base/tests/robocop.ini
+++ b/mobile/android/base/tests/robocop.ini
@@ -99,16 +99,17 @@ skip-if = android_version == "10"
 # [testVkbOverlap] # see bug 907274
 
 # Using JavascriptTest
 [testAccounts]
 [testAndroidLog]
 [testBrowserDiscovery]
 [testDebuggerServer]
 [testDeviceSearchEngine]
+[testFilePicker]
 [testJNI]
 # [testMozPay] # see bug 945675
 [testNetworkManager]
 [testOfflinePage]
 [testOrderedBroadcast]
 [testOSLocale]
 [testResourceSubstitutions]
 [testRestrictedProfiles]
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/tests/testFilePicker.java
@@ -0,0 +1,52 @@
+/* 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/. */
+
+package org.mozilla.gecko.tests;
+
+import static org.mozilla.gecko.tests.helpers.AssertionHelper.fFail;
+
+import org.mozilla.gecko.EventDispatcher;
+import org.mozilla.gecko.GeckoAppShell;
+import org.mozilla.gecko.GeckoEvent;
+import org.mozilla.gecko.util.GeckoEventListener;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+public class testFilePicker extends JavascriptTest implements GeckoEventListener {
+    private static final String TEST_FILENAME = "/mnt/sdcard/my-favorite-martian.png";
+
+    public testFilePicker() {
+        super("testFilePicker.js");
+    }
+
+    @Override
+    public void handleMessage(String event, final JSONObject message) {
+        // We handle the FilePicker message here so we can send back hard coded file information. We
+        // don't want to try to emulate "picking" a file using the Android intent chooser.
+        if (event.equals("FilePicker:Show")) {
+            try {
+                message.put("file", TEST_FILENAME);
+            } catch (JSONException ex) {
+                fFail("Can't add filename to message " + TEST_FILENAME);
+            }
+
+            GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("FilePicker:Result", message.toString()));
+        }
+    }
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+
+        EventDispatcher.getInstance().registerGeckoThreadListener(this, "FilePicker:Show");
+    }
+
+    @Override
+    public void tearDown() throws Exception {
+        super.tearDown();
+
+        EventDispatcher.getInstance().unregisterGeckoThreadListener(this, "FilePicker:Show");
+    }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/tests/testFilePicker.js
@@ -0,0 +1,80 @@
+// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
+
+Cu.import("resource://gre/modules/Services.jsm");
+
+function ok(passed, text) {
+  do_report_result(passed, text, Components.stack.caller, false);
+}
+
+function is(lhs, rhs, text) {
+  do_report_result(lhs === rhs, text, Components.stack.caller, false);
+}
+
+add_test(function filepicker_open() {
+  let chromeWin = Services.wm.getMostRecentWindow("navigator:browser");
+
+  do_test_pending();
+
+  let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
+  fp.appendFilter("Martian files", "*.martian");
+  fp.appendFilters(Ci.nsIFilePicker.filterAll);
+  fp.filterIndex = 0;
+
+  let fpCallback = function(result) {
+    if (result == Ci.nsIFilePicker.returnOK || result == Ci.nsIFilePicker.returnReplace) {
+      do_print("File: " + fp.file.path);
+      is(fp.file.path, "/mnt/sdcard/my-favorite-martian.png", "Retrieve the right martian file!");
+
+      let files = fp.files;
+      while (files.hasMoreElements()) {
+        let file = files.getNext().QueryInterface(Ci.nsIFile);
+        do_print("File: " + file.path);
+        is(file.path, "/mnt/sdcard/my-favorite-martian.png", "Retrieve the right martian file from array!");
+      }
+
+      do_print("DOMFile: " + fp.domfile.mozFullPath);
+      is(fp.domfile.mozFullPath, "/mnt/sdcard/my-favorite-martian.png", "Retrieve the right martian domfile!");
+
+      let domfiles = fp.domfiles;
+      while (domfiles.hasMoreElements()) {
+        let domfile = domfiles.getNext();
+        do_print("DOMFile: " + domfile.mozFullPath);
+        is(domfile.mozFullPath, "/mnt/sdcard/my-favorite-martian.png", "Retrieve the right martian file from domfile array!");
+      }
+
+      do_test_finished();
+
+      run_next_test();
+    }
+  };
+
+  try {
+    fp.init(chromeWin, "Open", Ci.nsIFilePicker.modeOpen);
+  } catch(ex) {
+    ok(false, "Android should support FilePicker.modeOpen: " + ex);
+  }
+  fp.open(fpCallback);
+});
+
+add_test(function filepicker_save() {
+  let failed = false;
+  let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
+  try {
+    fp.init(null, "Save", Ci.nsIFilePicker.modeSave);
+  } catch(ex) {
+    failed = true;
+  }
+  ok(failed, "Android does not support FilePicker.modeSave");
+
+  run_next_test();
+});
+
+run_next_test();
+
--- a/mobile/android/base/util/StringUtils.java
+++ b/mobile/android/base/util/StringUtils.java
@@ -1,19 +1,17 @@
 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
  * 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/. */
 
 package org.mozilla.gecko.util;
 
-import android.content.Intent;
 import android.net.Uri;
 import android.text.TextUtils;
-import android.util.Log;
 
 public class StringUtils {
     private static final String LOGTAG = "GeckoStringUtils";
 
     private static final String FILTER_URL_PREFIX = "filter://";
     private static final String USER_ENTERED_URL_PREFIX = "user-entered:";
 
     /*
@@ -184,21 +182,9 @@ public class StringUtils {
             return uri.getSchemeSpecificPart();
         }
         return url;
     }
 
     public static String encodeUserEnteredUrl(String url) {
         return Uri.fromParts("user-entered", url, null).toString();
     }
-
-    public static String getStringExtra(Intent intent, String name) {
-        try {
-            return intent.getStringExtra(name);
-        } catch (android.os.BadParcelableException ex) {
-            Log.w(LOGTAG, "Couldn't get string extra: malformed intent.");
-            return null;
-        } catch (RuntimeException re) {
-            Log.w(LOGTAG, "Couldn't get string extra.", re);
-            return null;
-        }
-    }
 }
--- a/mobile/android/base/webapp/WebappImpl.java
+++ b/mobile/android/base/webapp/WebappImpl.java
@@ -13,16 +13,17 @@ import org.json.JSONException;
 import org.json.JSONObject;
 import org.mozilla.gecko.GeckoApp;
 import org.mozilla.gecko.GeckoAppShell;
 import org.mozilla.gecko.GeckoEvent;
 import org.mozilla.gecko.GeckoThread;
 import org.mozilla.gecko.R;
 import org.mozilla.gecko.Tab;
 import org.mozilla.gecko.Tabs;
+import org.mozilla.gecko.mozglue.ContextUtils.SafeIntent;
 import org.mozilla.gecko.util.NativeJSObject;
 import org.mozilla.gecko.webapp.InstallHelper.InstallCallback;
 
 import android.content.Intent;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.graphics.Color;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.GradientDrawable;
@@ -152,17 +153,17 @@ public class WebappImpl extends GeckoApp
         }
 
         launchWebapp(origin);
 
         setTitle(mAppName);
     }
 
     @Override
-    protected String getURIFromIntent(Intent intent) {
+    protected String getURIFromIntent(SafeIntent intent) {
         String uri = super.getURIFromIntent(intent);
         if (uri != null) {
             return uri;
         }
         // This is where we construct the URL from the Intent from the
         // the synthesized APK.
 
         // TODO Translate AndroidIntents into WebActivities here.
--- a/mobile/android/chrome/content/WebcompatReporter.js
+++ b/mobile/android/chrome/content/WebcompatReporter.js
@@ -71,17 +71,17 @@ var WebcompatReporter = {
         label: this.strings.GetStringFromName("webcompat.reportDesktopModeYes.label"),
         callback: () => this.reportIssue(currentURI)
       }
     };
     NativeWindow.toast.show(message, "long", options);
   },
 
   reportIssue: function(url) {
-    let webcompatURL = new URL("http://webcompat.com/");
+    let webcompatURL = new URL("https://webcompat.com/");
     webcompatURL.searchParams.append("open", "1");
     webcompatURL.searchParams.append("url", url);
     if (PrivateBrowsingUtils.isBrowserPrivate(BrowserApp.selectedTab.browser)) {
       BrowserApp.addTab(webcompatURL.href, {parentId: BrowserApp.selectedTab.id, isPrivate: true});
     } else {
       BrowserApp.addTab(webcompatURL.href);
     }
   }
--- a/mobile/android/components/FilePicker.js
+++ b/mobile/android/components/FilePicker.js
@@ -141,18 +141,20 @@ FilePicker.prototype = {
   },
 
   get domfile() {
     let f = this.file;
     if (!f) {
         return null;
     }
 
-    if (this._domWin) {
-      return new this._domWin.File(f);
+    let win = this._domWin;
+    if (win) {
+      let utils = win.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
+      return utils.wrapDOMFile(f);
     }
 
     return new File(f);
   },
 
   get domfiles() {
     let win = this._domWin;
     return this.getEnumerator([this.file], function(file) {
@@ -208,17 +210,16 @@ FilePicker.prototype = {
     this._callback = callback;
     this._sendMessage();
   },
 
   _sendMessage: function() {
     let msg = {
       type: "FilePicker:Show",
       guid: this.guid,
-      guid: this.guid,
       title: this._title,
     };
 
     // Knowing the window lets us destroy any temp files when the tab is closed
     // Other consumers of the file picker may have to either wait for Android
     // to clean up the temp dir (not guaranteed) or clean up after themselves.
     let win = Services.wm.getMostRecentWindow('navigator:browser');
     let tab = win.BrowserApp.getTabForWindow(this._domWin.top)
--- a/toolkit/components/printing/content/printPreviewBindings.xml
+++ b/toolkit/components/printing/content/printPreviewBindings.xml
@@ -18,17 +18,17 @@
   <binding id="printpreviewtoolbar" 
            extends="chrome://global/content/bindings/toolbar.xml#toolbar">
     <resources>
       <stylesheet src="chrome://global/skin/printPreview.css"/>
     </resources>
 
     <content>
       <xul:button label="&print.label;" accesskey="&print.accesskey;"
-        oncommand="PrintUtils.print();" icon="print"/>
+        oncommand="this.parentNode.print();" icon="print"/>
 
       <xul:button label="&pageSetup.label;" accesskey="&pageSetup.accesskey;"
         oncommand="this.parentNode.doPageSetup();"/>
 
       <xul:vbox align="center" pack="center">
         <xul:label value="&page.label;" accesskey="&page.accesskey;" control="pageNumber"/>
       </xul:vbox>
       <xul:toolbarbutton class="home-arrow tabbable"
@@ -88,17 +88,17 @@
       </xul:hbox>
 
       <xul:toolbarseparator class="toolbarseparator-primary"/>
       <xul:button label="&close.label;" accesskey="&close.accesskey;"
         oncommand="PrintUtils.exitPrintPreview();" icon="close"/>
       <xul:data value="&customPrompt.title;"/>
     </content>
 
-    <implementation>
+    <implementation implements="nsIMessageListener">
       <field name="mPrintButton">
         document.getAnonymousNodes(this)[0]
       </field>
       <field name="mPageTextBox">
         document.getAnonymousNodes(this)[5].childNodes[0]
       </field>
       <field name="mTotalPages">
         document.getAnonymousNodes(this)[5].childNodes[2]
@@ -120,26 +120,34 @@
       </field>
       <field name="mCustomTitle">
         document.getAnonymousNodes(this)[15].firstChild
       </field>
       <field name="mPrintPreviewObs">
       </field>
       <field name="mWebProgress">
       </field>
-     
-      <constructor>
-      <![CDATA[
-        var print = PrintUtils.getPrintPreview();
-        this.mTotalPages.value = print.printPreviewNumPages;
-        this.mPageTextBox.max = print.printPreviewNumPages;
+      <field name="mPPBrowser">
+        null
+      </field>
+      <field name="mMessageManager">
+        null
+      </field>
 
-        this.updateToolbar();
-      ]]>
-      </constructor>
+      <method name="initialize">
+        <parameter name="aPPBrowser"/>
+        <body>
+        <![CDATA[
+          this.mPPBrowser = aPPBrowser;
+          this.mMessageManager = aPPBrowser.messageManager;
+          this.mMessageManager.addMessageListener("Printing:Preview:UpdatePageCount", this);
+          this.updateToolbar();
+        ]]>
+        </body>
+      </method>
 
       <method name="doPageSetup">
         <body>
         <![CDATA[
           var didOK = PrintUtils.showPageSetup();
           if (didOK) {
             // the changes that effect the UI
             this.updateToolbar();
@@ -151,48 +159,57 @@
         </body>
       </method>
 
       <method name="navigate">
         <parameter name="aDirection"/>
         <parameter name="aPageNum"/>
         <parameter name="aHomeOrEnd"/>
         <body>
-        <![CDATA[          
-          var print = PrintUtils.getPrintPreview();
+        <![CDATA[
+          const nsIWebBrowserPrint = Components.interfaces.nsIWebBrowserPrint;
+          let navType, pageNum;
 
           // we use only one of aHomeOrEnd, aDirection, or aPageNum
-          if (aHomeOrEnd)
-          {
-            var homeOrEnd;
-            if (aHomeOrEnd == "home")
-            {
-              homeOrEnd = print.PRINTPREVIEW_HOME;
-              this.mPageTextBox.value = 1;  
-            }
-            else
-            {
-              homeOrEnd = print.PRINTPREVIEW_END;
-              this.mPageTextBox.value = print.printPreviewNumPages;
+          if (aHomeOrEnd) {
+            // We're going to either the very first page ("home"), or the
+            // very last page ("end").
+            if (aHomeOrEnd == "home") {
+              navType = nsIWebBrowserPrint.PRINTPREVIEW_HOME;
+              this.mPageTextBox.value = 1;
+            } else {
+              navType = nsIWebBrowserPrint.PRINTPREVIEW_END;
+              this.mPageTextBox.value = this.mPageTextBox.max;
             }
-            
-            print.printPreviewNavigate(homeOrEnd, 0);
-          }
-          else if (aDirection)
-          {
+            pageNum = 0;
+          } else if (aDirection) {
+            // aDirection is either +1 or -1, and allows us to increment
+            // or decrement our currently viewed page.
             this.mPageTextBox.valueNumber += aDirection;
-            print.printPreviewNavigate(
-              print.PRINTPREVIEW_GOTO_PAGENUM,
-              this.mPageTextBox.valueNumber);
+            navType = nsIWebBrowserPrint.PRINTPREVIEW_GOTO_PAGENUM;
+            pageNum = this.mPageTextBox.value;  // TODO: back to valueNumber?
+          } else {
+            // We're going to a specific page (aPageNum)
+            navType = nsIWebBrowserPrint.PRINTPREVIEW_GOTO_PAGENUM;
+            pageNum = aPageNum;
           }
-          else 
-          {
-            print.printPreviewNavigate(
-              print.PRINTPREVIEW_GOTO_PAGENUM, aPageNum);
-          }
+
+          this.mMessageManager.sendAsyncMessage("Printing:Preview:Navigate", {
+            navType: navType,
+            pageNum: pageNum,
+          });
+        ]]>
+        </body>
+      </method>
+
+      <method name="print">
+        <body>
+        <![CDATA[
+          let contentWindow = this.mPPBrowser.contentWindowAsCPOW;
+          PrintUtils.print(contentWindow, this.mPPBrowser);
         ]]>
         </body>
       </method>
 
       <method name="promptForScaleValue">
         <parameter name="aValue"/>
         <body>
         <![CDATA[
@@ -285,42 +302,55 @@
           }
         ]]>
         </body>
       </method>
 
       <method name="updateToolbar">
         <body>
         <![CDATA[
-          var print = PrintUtils.getPrintPreview();
           var settings = PrintUtils.getPrintSettings();
 
           var isPortrait = settings.orientation == Components.interfaces.nsIPrintSettings.kPortraitOrientation;
 
           this.mPortaitButton.checked = isPortrait;
           this.mLandscapeButton.checked = !isPortrait;
 
           if (settings.shrinkToFit) {
             this.mScaleCombobox.value = "ShrinkToFit";
           } else {
             this.setScaleCombobox(settings.scaling);
           }
 
-          this.mTotalPages.value = print.printPreviewNumPages;
-          this.mPageTextBox.max = print.printPreviewNumPages;
           this.mPageTextBox.value = 1;
+
+          this.mMessageManager.sendAsyncMessage("Printing:Preview:UpdatePageCount");
         ]]>
         </body>
       </method>
 
       <method name="savePrintSettings">
         <parameter name="settings"/>
         <parameter name="flags"/>
         <body><![CDATA[
           var PSSVC = Components.classes["@mozilla.org/gfx/printsettings-service;1"]
                                 .getService(Components.interfaces.nsIPrintSettingsService);
           PSSVC.savePrintSettingsToPrefs(settings, true, flags);
         ]]></body>
       </method>
+
+      <!-- nsIMessageListener -->
+      <method name="receiveMessage">
+        <parameter name="message"/>
+        <body>
+        <![CDATA[
+          if (message.name == "Printing:Preview:UpdatePageCount") {
+            let numPages = message.data.numPages;
+            this.mTotalPages.value = numPages;
+            this.mPageTextBox.max = numPages;
+          }
+        ]]>
+        </body>
+      </method>
     </implementation>
   </binding>
 
 </bindings>
--- a/toolkit/components/printing/content/printUtils.js
+++ b/toolkit/components/printing/content/printUtils.js
@@ -1,34 +1,98 @@
-
 // -*- tab-width: 2; indent-tabs-mode: nil; js-indent-level: 2 -*-
 
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+/**
+ * PrintUtils is a utility for front-end code to trigger common print
+ * operations (printing, show print preview, show page settings).
+ *
+ * Unfortunately, likely due to inconsistencies in how different operating
+ * systems do printing natively, our XPCOM-level printing interfaces
+ * are a bit confusing and the method by which we do something basic
+ * like printing a page is quite circuitous.
+ *
+ * To compound that, we need to support remote browsers, and that means
+ * kicking off the print jobs in the content process. This means we send
+ * messages back and forth to that process. browser-content.js contains
+ * the object that listens and responds to the messages that PrintUtils
+ * sends.
+ *
+ * PrintUtils sends messages at different points in its implementation, but
+ * their documentation is consolidated here for ease-of-access.
+ *
+ *
+ * Messages sent:
+ *
+ *   Printing:Print
+ *     This message is sent to kick off a print job for a particular content
+ *     window (which is passed along with the message). We also pass print
+ *     settings with this message - though bug 1088070 will have us gather
+ *     those settings from the content process instead.
+ *
+ *   Printing:Preview:Enter
+ *     This message is sent to put content into print preview mode. We pass
+ *     the content window of the browser we're showing the preview of, and
+ *     the target of the message is the browser that we'll be showing the
+ *     preview in. We also pass print settings in this message, but
+ *     bug 1088070 will have us gather those settings from the content process
+ *     instead.
+ *
+ *   Printing:Preview:Exit
+ *     This message is sent to take content out of print preview mode.
+ *
+ *
+ * Messages Received
+ *
+ *   Printing:Preview:Entered
+ *     This message is sent by the content process once it has completed
+ *     putting the content into print preview mode. We must wait for that to
+ *     to complete before switching the chrome UI to print preview mode,
+ *     otherwise we have layout issues.
+ *
+ *   Printing:Preview:StateChange, Printing:Preview:ProgressChange
+ *     Due to a timing issue resulting in a main-process crash, we have to
+ *     manually open the progress dialog for print preview. The progress
+ *     dialog is opened here in PrintUtils, and then we listen for update
+ *     messages from the child. Bug 1088061 has been filed to investigate
+ *     other solutions.
+ *
+ */
+
 var gPrintSettingsAreGlobal = false;
 var gSavePrintSettings = false;
 var gFocusedElement = null;
 
 var PrintUtils = {
   bailOut: function () {
-    let remote = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
-            .getInterface(Components.interfaces.nsIWebNavigation)
-            .QueryInterface(Components.interfaces.nsILoadContext)
-            .useRemoteTabs;
-    if (remote) {
+    let pref = Components.classes["@mozilla.org/preferences-service;1"]
+                         .getService(Components.interfaces.nsIPrefBranch);
+    let allow_for_testing = false;
+    try {
+      allow_for_testing = pref.getBoolPref("print.enable_e10s_testing");
+    } catch(e) {
+      // The pref wasn't set, so I guess we're not overriding.
+    }
+    if (this.usingRemoteTabs && !allow_for_testing) {
       alert("e10s printing is not implemented yet. Bug 927188.");
       return true;
     }
     return false;
   },
 
-  showPageSetup: function ()
-  {
+  /**
+   * Shows the page setup dialog, and saves any settings changed in
+   * that dialog if print.save_print_settings is set to true.
+   *
+   * @return true on success, false on failure
+   */
+  showPageSetup: function () {
     if (this.bailOut()) {
       return;
     }
     try {
       var printSettings = this.getPrintSettings();
       var PRINTPROMPTSVC = Components.classes["@mozilla.org/embedcomp/printingprompt-service;1"]
                                      .getService(Components.interfaces.nsIPrintingPromptService);
       PRINTPROMPTSVC.showPageSetup(window, printSettings, null);
@@ -40,112 +104,271 @@ var PrintUtils = {
       }
     } catch (e) {
       dump("showPageSetup "+e+"\n");
       return false;
     }
     return true;
   },
 
-  print: function (aWindow)
+  /**
+   * Starts printing the contents of aWindow.
+   *
+   * @param aWindow
+   *        An nsIDOMWindow to initiate the printing of. If the chrome window
+   *        is not running with remote tabs, this defaults to window.content if
+   *        omitted. If running with remote tabs, the caller must pass in the
+   *        content window to be printed. This function throws if that invariant
+   *        is violated.
+   * @param aBrowser (optional for non-remote browsers)
+   *        The remote <xul:browser> that contains aWindow. This argument is
+   *        not necessary if aWindow came from a non-remote browser, but is
+   *        strictly required otherwise. This function will throw if aWindow
+   *        comes from a remote browser and aBrowser is not provided.
+   */
+  print: function (aWindow, aBrowser)
   {
     if (this.bailOut()) {
       return;
     }
-    var webBrowserPrint = this.getWebBrowserPrint(aWindow);
-    var printSettings = this.getPrintSettings();
-    try {
-      webBrowserPrint.print(printSettings, null);
-      if (gPrintSettingsAreGlobal && gSavePrintSettings) {
-        var PSSVC = Components.classes["@mozilla.org/gfx/printsettings-service;1"]
-                              .getService(Components.interfaces.nsIPrintSettingsService);
-        PSSVC.savePrintSettingsToPrefs(printSettings, true,
-                                       printSettings.kInitSaveAll);
-        PSSVC.savePrintSettingsToPrefs(printSettings, false,
-                                       printSettings.kInitSavePrinterName);
+
+    if (!aWindow) {
+      // If we're using remote browsers, chances are that window.content will
+      // not be defined.
+      if (this.usingRemoteTabs) {
+        throw new Error("Windows running with remote tabs must explicitly pass " +
+                        "a content window to PrintUtils.print.");
+      }
+      // Otherwise, we should have access to window.content.
+      aWindow = window.content;
+    }
+
+    if (Cu.isCrossProcessWrapper(aWindow)) {
+      if (!aBrowser) {
+        throw new Error("PrintUtils.print expects a remote browser passed as " +
+                        "an argument if the content window is a CPOW.");
       }
-    } catch (e) {
-      // Pressing cancel is expressed as an NS_ERROR_ABORT return value,
-      // causing an exception to be thrown which we catch here.
-      // Unfortunately this will also consume helpful failures, so add a
-      // dump("print: "+e+"\n"); // if you need to debug
+    } else {
+      // For content windows coming from non-remote browsers, the browser can
+      // be resolved as the chromeEventHandler.
+      aBrowser = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
+                        .getInterface(Ci.nsIWebNavigation)
+                        .QueryInterface(Ci.nsIDocShell)
+                        .chromeEventHandler;
     }
+
+    if (!aBrowser) {
+      throw new Error("PrintUtils.print could not resolve content window " +
+                      "to a browser.");
+    }
+
+    let printSettings = this.getPrintSettings();
+
+    let mm = aBrowser.messageManager;
+    mm.sendAsyncMessage("Printing:Print", null, {
+      printSettings: printSettings,
+      contentWindow: aWindow,
+    });
   },
 
-  // If aCallback is not null, it must be an object which has the following methods:
-  // getPrintPreviewBrowser(), getSourceBrowser(),
-  // getNavToolbox(), onEnter() and onExit().
-  // If aCallback is null, then printPreview must previously have been called with
-  // non-null aCallback and that object will be reused.
-  printPreview: function (aCallback)
+  /**
+   * Initializes print preview.
+   *
+   * @param aListenerObj
+   *        An object that defines the following functions:
+   *
+   *        getPrintPreviewBrowser:
+   *          Returns the <xul:browser> to display the print preview in.
+   *
+   *        getSourceBrowser:
+   *          Returns the <xul:browser> that contains the document being
+   *          printed.
+   *
+   *        getNavToolbox:
+   *          Returns the primary toolbox for this window.
+   *
+   *        onEnter:
+   *          Called upon entering print preview.
+   *
+   *        onExit:
+   *          Called upon exiting print preview.
+   *
+   *        These methods must be defined. printPreview can be called
+   *        with aListenerObj as null iff this window is already displaying
+   *        print preview (in which case, the previous aListenerObj passed
+   *        to it will be used).
+   */
+  printPreview: function (aListenerObj)
   {
     if (this.bailOut()) {
       return;
     }
-    // if we're already in PP mode, don't set the callback; chances
+    // if we're already in PP mode, don't set the listener; chances
     // are it is null because someone is calling printPreview() to
     // get us to refresh the display.
-    if (!document.getElementById("print-preview-toolbar")) {
-      this._callback = aCallback;
-      this._sourceBrowser = aCallback.getSourceBrowser();
-      this._originalTitle = this._sourceBrowser.contentDocument.title;
+    if (!this.inPrintPreview) {
+      this._listener = aListenerObj;
+      this._sourceBrowser = aListenerObj.getSourceBrowser();
+      this._originalTitle = this._sourceBrowser.contentTitle;
       this._originalURL = this._sourceBrowser.currentURI.spec;
     } else {
       // collapse the browser here -- it will be shown in
       // enterPrintPreview; this forces a reflow which fixes display
       // issues in bug 267422.
-      this._sourceBrowser = this._callback.getPrintPreviewBrowser();
+      this._sourceBrowser = this._listener.getPrintPreviewBrowser();
       this._sourceBrowser.collapsed = true;
     }
 
     this._webProgressPP = {};
-    var ppParams        = {};
-    var notifyOnOpen    = {};
-    var webBrowserPrint = this.getWebBrowserPrint();
-    var printSettings   = this.getPrintSettings();
+    let ppParams        = {};
+    let notifyOnOpen    = {};
+    let printSettings   = this.getPrintSettings();
     // Here we get the PrintingPromptService so we can display the PP Progress from script
     // For the browser implemented via XUL with the PP toolbar we cannot let it be
     // automatically opened from the print engine because the XUL scrollbars in the PP window
     // will layout before the content window and a crash will occur.
     // Doing it all from script, means it lays out before hand and we can let printing do its own thing
-    var PPROMPTSVC = Components.classes["@mozilla.org/embedcomp/printingprompt-service;1"]
+    let PPROMPTSVC = Components.classes["@mozilla.org/embedcomp/printingprompt-service;1"]
                                .getService(Components.interfaces.nsIPrintingPromptService);
-    // just in case we are already printing, 
-    // an error code could be returned if the Prgress Dialog is already displayed
+    // just in case we are already printing,
+    // an error code could be returned if the Progress Dialog is already displayed
     try {
-      PPROMPTSVC.showProgress(window, webBrowserPrint, printSettings, this._obsPP, false,
+      PPROMPTSVC.showProgress(window, null, printSettings, this._obsPP, false,
                               this._webProgressPP, ppParams, notifyOnOpen);
       if (ppParams.value) {
         ppParams.value.docTitle = this._originalTitle;
         ppParams.value.docURL   = this._originalURL;
       }
 
-      // this tells us whether we should continue on with PP or 
+      // this tells us whether we should continue on with PP or
       // wait for the callback via the observer
-      if (!notifyOnOpen.value.valueOf() || this._webProgressPP.value == null)
+      if (!notifyOnOpen.value.valueOf() || this._webProgressPP.value == null) {
         this.enterPrintPreview();
+      }
     } catch (e) {
       this.enterPrintPreview();
     }
   },
 
+  /**
+   * Returns the nsIWebBrowserPrint associated with some content window.
+   * This method is being kept here for compatibility reasons, but should not
+   * be called by code hoping to support e10s / remote browsers.
+   *
+   * @param aWindow
+   *        The window from which to get the nsIWebBrowserPrint from.
+   * @return nsIWebBrowserPrint
+   */
   getWebBrowserPrint: function (aWindow)
   {
+    let Deprecated = Components.utils.import("resource://gre/modules/Deprecated.jsm", {}).Deprecated;
+    let text = "getWebBrowserPrint is now deprecated, and fully unsupported for " +
+               "multi-process browsers. Please use a frame script to get " +
+               "access to nsIWebBrowserPrint from content.";
+    let url = "https://developer.mozilla.org/en-US/docs/Printing_from_a_XUL_App";
+    Deprecated.warning(text, url);
+
+    if (this.usingRemoteTabs) {
+      return {};
+    }
+
     var contentWindow = aWindow || window.content;
     return contentWindow.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
                         .getInterface(Components.interfaces.nsIWebBrowserPrint);
   },
 
+  /**
+   * Returns the nsIWebBrowserPrint from the print preview browser's docShell.
+   * This method is being kept here for compatibility reasons, but should not
+   * be called by code hoping to support e10s / remote browsers.
+   *
+   * @return nsIWebBrowserPrint
+   */
   getPrintPreview: function() {
-    return this._callback.getPrintPreviewBrowser().docShell.printPreview;
+    let Deprecated = Components.utils.import("resource://gre/modules/Deprecated.jsm", {}).Deprecated;
+    let text = "getPrintPreview is now deprecated, and fully unsupported for " +
+               "multi-process browsers. Please use a frame script to get " +
+               "access to nsIWebBrowserPrint from content.";
+    let url = "https://developer.mozilla.org/en-US/docs/Printing_from_a_XUL_App";
+    Deprecated.warning(text, url);
+
+    if (this.usingRemoteTabs) {
+      return {};
+    }
+
+    return this._listener.getPrintPreviewBrowser().docShell.printPreview;
+  },
+
+  get inPrintPreview() {
+    return document.getElementById("print-preview-toolbar") != null;
   },
 
-  ////////////////////////////////////////
-  // "private" methods. Don't use them. //
-  ////////////////////////////////////////
+  ////////////////////////////////////////////////////
+  // "private" methods and members. Don't use them. //
+  ///////////////////////////////////////////////////
+
+  _listener: null,
+  _closeHandlerPP: null,
+  _webProgressPP: null,
+  _sourceBrowser: null,
+  _originalTitle: "",
+  _originalURL: "",
+
+  get usingRemoteTabs() {
+    // We memoize this, since it's highly unlikely to change over the lifetime
+    // of the window.
+    let usingRemoteTabs =
+      window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
+            .getInterface(Components.interfaces.nsIWebNavigation)
+            .QueryInterface(Components.interfaces.nsILoadContext)
+            .useRemoteTabs;
+    delete this.usingRemoteTabs;
+    return this.usingRemoteTabs = usingRemoteTabs;
+  },
+
+  receiveMessage(aMessage) {
+    if (!this._webProgressPP.value) {
+      // We somehow didn't get a nsIWebProgressListener to be updated...
+      // I guess there's nothing to do.
+      return;
+    }
+
+    let listener = this._webProgressPP.value;
+    let mm = aMessage.target.messageManager;
+    let data = aMessage.data;
+
+    switch (aMessage.name) {
+      case "Printing:Preview:ProgressChange": {
+        return listener.onProgressChange(null, null,
+                                         data.curSelfProgress,
+                                         data.maxSelfProgress,
+                                         data.curTotalProgress,
+                                         data.maxTotalProgress);
+        break;
+      }
+
+      case "Printing:Preview:StateChange": {
+        if (data.stateFlags & Components.interfaces.nsIWebProgressListener.STATE_STOP) {
+          // Strangely, the printing engine sends 2 STATE_STOP messages when
+          // print preview is finishing. One has the STATE_IS_DOCUMENT flag,
+          // the other has the STATE_IS_NETWORK flag. However, the webProgressPP
+          // listener stops listening once the first STATE_STOP is sent.
+          // Any subsequent messages result in NS_ERROR_FAILURE errors getting
+          // thrown. This should all get torn out once bug 1088061 is fixed.
+          mm.removeMessageListener("Printing:Preview:StateChange", this);
+          mm.removeMessageListener("Printing:Preview:ProgressChange", this);
+        }
+
+        return listener.onStateChange(null, null,
+                                      data.stateFlags,
+                                      data.status);
+        break;
+      }
+    }
+  },
 
   setPrinterDefaultsForSelectedPrinter: function (aPSSVC, aPrintSettings)
   {
     if (!aPrintSettings.printerName)
       aPrintSettings.printerName = aPSSVC.defaultPrinterName;
 
     // First get any defaults from the printer 
     aPSSVC.initPrintSettingsFromPrinter(aPrintSettings.printerName, aPrintSettings);
@@ -173,138 +396,131 @@ var PrintUtils = {
         printSettings = PSSVC.newPrintSettings;
       }
     } catch (e) {
       dump("getPrintSettings: "+e+"\n");
     }
     return printSettings;
   },
 
-  _closeHandlerPP: null,
-  _webProgressPP: null,
-  _callback: null,
-  _sourceBrowser: null,
-  _originalTitle: "",
-  _originalURL: "",
-
   // This observer is called once the progress dialog has been "opened"
-  _obsPP: 
+  _obsPP:
   {
     observe: function(aSubject, aTopic, aData)
     {
       // delay the print preview to show the content of the progress dialog
       setTimeout(function () { PrintUtils.enterPrintPreview(); }, 0);
     },
 
     QueryInterface : function(iid)
     {
       if (iid.equals(Components.interfaces.nsIObserver) ||
           iid.equals(Components.interfaces.nsISupportsWeakReference) ||
           iid.equals(Components.interfaces.nsISupports))
-        return this;   
+        return this;
       throw Components.results.NS_NOINTERFACE;
     }
   },
 
   enterPrintPreview: function ()
   {
-    gFocusedElement = document.commandDispatcher.focusedElement;
-
-    var webBrowserPrint;
-    var printSettings  = this.getPrintSettings();
-    var originalWindow = this._sourceBrowser.contentWindow;
+    // Send a message to the print preview browser to initialize
+    // print preview. If we happen to have gotten a print preview
+    // progress listener from nsIPrintingPromptService.showProgress
+    // in printPreview, we add listeners to feed that progress
+    // listener.
+    let ppBrowser = this._listener.getPrintPreviewBrowser();
+    let mm = ppBrowser.messageManager;
+    let printSettings = this.getPrintSettings();
+    mm.sendAsyncMessage("Printing:Preview:Enter", null, {
+      printSettings: printSettings,
+      contentWindow: this._sourceBrowser.contentWindowAsCPOW,
+    });
 
-    try {
-      webBrowserPrint = this.getPrintPreview();
-      webBrowserPrint.printPreview(printSettings, originalWindow,
-                                   this._webProgressPP.value);
-    } catch (e) {
-      // Pressing cancel is expressed as an NS_ERROR_ABORT return value,
-      // causing an exception to be thrown which we catch here.
-      // Unfortunately this will also consume helpful failures, so add a
-      // dump(e); // if you need to debug
-
-      // Need to call enter and exit so that UI gets back to normal.
-      this._callback.onEnter();
-      this._callback.onExit();
-      return;
-    }
-
-    var printPreviewTB = document.getElementById("print-preview-toolbar");
-    if (printPreviewTB) {
-      printPreviewTB.updateToolbar();
-      var browser = this._callback.getPrintPreviewBrowser();
-      browser.collapsed = false;
-      browser.contentWindow.focus();
-      return;
+    if (this._webProgressPP.value) {
+      mm.addMessageListener("Printing:Preview:StateChange", this);
+      mm.addMessageListener("Printing:Preview:ProgressChange", this);
     }
 
-    // Set the original window as an active window so any mozPrintCallbacks can
-    // run without delayed setTimeouts.
-    var docShell = originalWindow.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
-                                 .getInterface(Components.interfaces.nsIWebNavigation)
-                                 .QueryInterface(Components.interfaces.nsIDocShell);
-    docShell.isActive = true;
+    let onEntered = (message) => {
+      mm.removeMessageListener("Printing:PrintPreview:Entered", onEntered);
+      // Stash the focused element so that we can return to it after exiting
+      // print preview.
+      gFocusedElement = document.commandDispatcher.focusedElement;
 
-    // show the toolbar after we go into print preview mode so
-    // that we can initialize the toolbar with total num pages
-    var XUL_NS =
-      "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
-    printPreviewTB = document.createElementNS(XUL_NS, "toolbar");
-    printPreviewTB.setAttribute("printpreview", true);
-    printPreviewTB.id = "print-preview-toolbar";
-    printPreviewTB.className = "toolbar-primary";
+      let printPreviewTB = document.getElementById("print-preview-toolbar");
+      if (printPreviewTB) {
+        printPreviewTB.updateToolbar();
+        ppBrowser.collapsed = false;
+        ppBrowser.focus();
+        return;
+      }
+
+      // Set the original window as an active window so any mozPrintCallbacks can
+      // run without delayed setTimeouts.
+      this._sourceBrowser.docShellIsActive = true;
 
-    var navToolbox = this._callback.getNavToolbox();
-    navToolbox.parentNode.insertBefore(printPreviewTB, navToolbox);
+      // show the toolbar after we go into print preview mode so
+      // that we can initialize the toolbar with total num pages
+      const XUL_NS =
+        "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
+      printPreviewTB = document.createElementNS(XUL_NS, "toolbar");
+      printPreviewTB.setAttribute("printpreview", true);
+      printPreviewTB.id = "print-preview-toolbar";
+      printPreviewTB.className = "toolbar-primary";
 
-    // copy the window close handler
-    if (document.documentElement.hasAttribute("onclose"))
-      this._closeHandlerPP = document.documentElement.getAttribute("onclose");
-    else
-      this._closeHandlerPP = null;
-    document.documentElement.setAttribute("onclose", "PrintUtils.exitPrintPreview(); return false;");
+      let navToolbox = this._listener.getNavToolbox();
+      navToolbox.parentNode.insertBefore(printPreviewTB, navToolbox);
+      printPreviewTB.initialize(ppBrowser);
 
-    // disable chrome shortcuts...
-    window.addEventListener("keydown", this.onKeyDownPP, true);
-    window.addEventListener("keypress", this.onKeyPressPP, true);
+      // copy the window close handler
+      if (document.documentElement.hasAttribute("onclose"))
+        this._closeHandlerPP = document.documentElement.getAttribute("onclose");
+      else
+        this._closeHandlerPP = null;
+      document.documentElement.setAttribute("onclose", "PrintUtils.exitPrintPreview(); return false;");
 
-    var browser = this._callback.getPrintPreviewBrowser();
-    browser.collapsed = false;
-    browser.contentWindow.focus();
+      // disable chrome shortcuts...
+      window.addEventListener("keydown", this.onKeyDownPP, true);
+      window.addEventListener("keypress", this.onKeyPressPP, true);
 
-    // on Enter PP Call back
-    this._callback.onEnter();
+      ppBrowser.collapsed = false;
+      ppBrowser.focus();
+      // on Enter PP Call back
+      this._listener.onEnter();
+    };
+
+    mm.addMessageListener("Printing:Preview:Entered", onEntered);
   },
 
   exitPrintPreview: function ()
   {
+    let ppBrowser = this._listener.getPrintPreviewBrowser();
+    let browserMM = ppBrowser.messageManager;
+    browserMM.sendAsyncMessage("Printing:Preview:Exit");
     window.removeEventListener("keydown", this.onKeyDownPP, true);
     window.removeEventListener("keypress", this.onKeyPressPP, true);
 
     // restore the old close handler
     document.documentElement.setAttribute("onclose", this._closeHandlerPP);
     this._closeHandlerPP = null;
 
-    var webBrowserPrint = this.getPrintPreview();
-    webBrowserPrint.exitPrintPreview();
+    // remove the print preview toolbar
+    let printPreviewTB = document.getElementById("print-preview-toolbar");
+    this._listener.getNavToolbox().parentNode.removeChild(printPreviewTB);
 
-    // remove the print preview toolbar
-    var printPreviewTB = document.getElementById("print-preview-toolbar");
-    this._callback.getNavToolbox().parentNode.removeChild(printPreviewTB);
-
-    var fm = Components.classes["@mozilla.org/focus-manager;1"]
+    let fm = Components.classes["@mozilla.org/focus-manager;1"]
                        .getService(Components.interfaces.nsIFocusManager);
     if (gFocusedElement)
       fm.setFocus(gFocusedElement, fm.FLAG_NOSCROLL);
     else
       window.content.focus();
     gFocusedElement = null;
 
-    this._callback.onExit();
+    this._listener.onExit();
   },
 
   onKeyDownPP: function (aEvent)
   {
     // Esc exits the PP
     if (aEvent.keyCode == aEvent.DOM_VK_ESCAPE) {
       PrintUtils.exitPrintPreview();
     }
@@ -324,17 +540,17 @@ var PrintUtils = {
         (aEvent.charCode == closeKey || aEvent.charCode == closeKey + 32)) {
       PrintUtils.exitPrintPreview();
     }
     else if (isModif) {
       var printPreviewTB = document.getElementById("print-preview-toolbar");
       var printKey = document.getElementById("printKb").getAttribute("key").toUpperCase();
       var pressedKey = String.fromCharCode(aEvent.charCode).toUpperCase();
       if (printKey == pressedKey) {
-	  PrintUtils.print();
+        printPreviewTB.print();
       }
     }
     // cancel shortkeys
     if (isModif) {
       aEvent.preventDefault();
       aEvent.stopPropagation();
     }
   }
--- a/toolkit/content/browser-content.js
+++ b/toolkit/content/browser-content.js
@@ -1,18 +1,20 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 let Cc = Components.classes;
 let Ci = Components.interfaces;
 let Cu = Components.utils;
+let Cr = Components.results;
 
 Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 var global = this;
 
 let ClickEventHandler = {
   init: function init() {
     this._scrollable = null;
     this._scrolldir = "";
     this._startX = null;
@@ -348,8 +350,135 @@ let PopupBlocking = {
                      {blockedPopups: this.popupData, freshPopup: freshPopup});
   },
 };
 PopupBlocking.init();
 
 // Set up console.* for frame scripts.
 let Console = Components.utils.import("resource://gre/modules/devtools/Console.jsm", {});
 this.console = new Console.ConsoleAPI();
+
+let Printing = {
+  // Bug 1088061: nsPrintEngine's DoCommonPrint currently expects the
+  // progress listener passed to it to QI to an nsIPrintingPromptService
+  // in order to know that a printing progress dialog has been shown. That's
+  // really all the interface is used for, hence the fact that I don't actually
+  // implement the interface here. Bug 1088061 has been filed to remove
+  // this hackery.
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener,
+                                         Ci.nsIPrintingPromptService]),
+
+  MESSAGES: [
+    "Printing:Preview:Enter",
+    "Printing:Preview:Exit",
+    "Printing:Preview:Navigate",
+    "Printing:Preview:UpdatePageCount",
+    "Printing:Print",
+  ],
+
+  init() {
+    this.MESSAGES.forEach(msgName => addMessageListener(msgName, this));
+  },
+
+  receiveMessage(message) {
+    let objects = message.objects;
+    let data = message.data;
+    switch(message.name) {
+      case "Printing:Preview:Enter": {
+        this.enterPrintPreview(objects.printSettings, objects.contentWindow);
+        break;
+      }
+
+      case "Printing:Preview:Exit": {
+        this.exitPrintPreview();
+        break;
+      }
+
+      case "Printing:Preview:Navigate": {
+        this.navigate(data.navType, data.pageNum);
+        break;
+      }
+
+      case "Printing:Preview:UpdatePageCount": {
+        this.updatePageCount();
+        break;
+      }
+
+      case "Printing:Print": {
+        this.print(objects.printSettings, objects.contentWindow);
+        break;
+      }
+    }
+  },
+
+  enterPrintPreview(printSettings, contentWindow) {
+    // Bug 1088070 - we should instantiate nsIPrintSettings here in the
+    // content script instead of passing it down as a CPOW.
+    if (Cu.isCrossProcessWrapper(printSettings)) {
+      printSettings = null;
+    }
+
+    // We have to wait for the print engine to finish reflowing all of the
+    // documents and subdocuments before we can tell the parent to flip to
+    // the print preview UI - otherwise, the print preview UI might ask for
+    // information (like the number of pages in the document) before we have
+    // our PresShells set up.
+    addEventListener("printPreviewUpdate", function onPrintPreviewReady() {
+      removeEventListener("printPreviewUpdate", onPrintPreviewReady);
+      sendAsyncMessage("Printing:Preview:Entered");
+    });
+
+    docShell.printPreview.printPreview(printSettings, contentWindow, this);
+  },
+
+  exitPrintPreview() {
+    docShell.printPreview.exitPrintPreview();
+  },
+
+  print(printSettings, contentWindow) {
+    // Bug 1088070 - we should instantiate nsIPrintSettings here in the
+    // content script instead of passing it down as a CPOW.
+    if (Cu.isCrossProcessWrapper(printSettings)) {
+      printSettings = null;
+    }
+
+    let print = contentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
+                             .getInterface(Ci.nsIWebBrowserPrint);
+    print.print(printSettings, null);
+  },
+
+  updatePageCount() {
+    let numPages = docShell.printPreview.printPreviewNumPages;
+    sendAsyncMessage("Printing:Preview:UpdatePageCount", {
+      numPages: numPages,
+    });
+  },
+
+  navigate(navType, pageNum) {
+    docShell.printPreview.printPreviewNavigate(navType, pageNum);
+  },
+
+  /* nsIWebProgressListener for print preview */
+
+  onStateChange(aWebProgress, aRequest, aStateFlags, aStatus) {
+    sendAsyncMessage("Printing:Preview:StateChange", {
+      stateFlags: aStateFlags,
+      status: aStatus,
+    });
+  },
+
+  onProgressChange(aWebProgress, aRequest, aCurSelfProgress,
+                   aMaxSelfProgress, aCurTotalProgress,
+                   aMaxTotalProgress) {
+    sendAsyncMessage("Printing:Preview:ProgressChange", {
+      curSelfProgress: aCurSelfProgress,
+      maxSelfProgress: aMaxSelfProgress,
+      curTotalProgress: aCurTotalProgress,
+      maxTotalProgress: aMaxTotalProgress,
+    });
+  },
+
+  onLocationChange(aWebProgress, aRequest, aLocation, aFlags) {},
+  onStatusChange(aWebProgress, aRequest, aStatus, aMessage) {},
+  onSecurityChange(aWebProgress, aRequest, aState) {},
+}
+Printing.init();
+
--- a/toolkit/devtools/touch-events.js
+++ b/toolkit/devtools/touch-events.js
@@ -32,17 +32,17 @@ function TouchEventHandler (window) {
 
   let delay = 500;
   try {
     delay = Services.prefs.getIntPref('ui.click_hold_context_menus.delay');
   } catch(e) {}
 
   let TouchEventHandler = {
     enabled: false,
-    events: ['mousedown', 'mousemove', 'mouseup'],
+    events: ['mousedown', 'mousemove', 'mouseup', 'touchstart', 'touchend'],
     start: function teh_start() {
       if (this.enabled)
         return false;
       this.enabled = true;
       let isReloadNeeded = Services.prefs.getIntPref('dom.w3c_touch_events.enabled') != 1;
       Services.prefs.setIntPref('dom.w3c_touch_events.enabled', 1);
       this.events.forEach((function(evt) {
         // Only listen trusted events to prevent messing with
@@ -56,28 +56,53 @@ function TouchEventHandler (window) {
         return;
       this.enabled = false;
       Services.prefs.setIntPref('dom.w3c_touch_events.enabled', orig_w3c_touch_events);
       this.events.forEach((function(evt) {
         window.removeEventListener(evt, this, true);
       }).bind(this));
     },
     handleEvent: function teh_handleEvent(evt) {
+      // The gaia system window use an hybrid system even on the device which is
+      // a mix of mouse/touch events. So let's not cancel *all* mouse events
+      // if it is the current target.
+      let content = this.getContent(evt.target);
+      let isSystemWindow = content.location.toString().indexOf("system.gaiamobile.org") != -1;
+
+      // App touchstart & touchend should also be dispatched on the system app
+      // to match on-device behavior.
+      if (evt.type.startsWith('touch') && !isSystemWindow) {
+        let sysFrame = content.realFrameElement;
+        let sysDocument = sysFrame.ownerDocument;
+        let sysWindow = sysDocument.defaultView;
+
+        let touchEvent = sysDocument.createEvent('touchevent');
+        let touch = evt.touches[0] || evt.changedTouches[0];
+        let point = sysDocument.createTouch(sysWindow, sysFrame, 0,
+                                            touch.pageX, touch.pageY,
+                                            touch.screenX, touch.screenY,
+                                            touch.clientX, touch.clientY,
+                                            1, 1, 0, 0);
+
+        let touches = sysDocument.createTouchList(point);
+        let targetTouches = touches;
+        let changedTouches = touches;
+        touchEvent.initTouchEvent(evt.type, true, true, sysWindow, 0,
+                                  false, false, false, false,
+                                  touches, targetTouches, changedTouches);
+        sysFrame.dispatchEvent(touchEvent);
+        return;
+      }
+
       // Ignore all but real mouse event coming from physical mouse
       // (especially ignore mouse event being dispatched from a touch event)
       if (evt.button || evt.mozInputSource != Ci.nsIDOMMouseEvent.MOZ_SOURCE_MOUSE || evt.isSynthesized) {
         return;
       }
 
-      // The gaia system window use an hybrid system even on the device which is
-      // a mix of mouse/touch events. So let's not cancel *all* mouse events
-      // if it is the current target.
-      let content = this.getContent(evt.target);
-      let isSystemWindow = content.location.toString().indexOf("system.gaiamobile.org") != -1;
-
       let eventTarget = this.target;
       let type = '';
       switch (evt.type) {
         case 'mousedown':
           this.target = evt.target;
 
           contextMenuTimeout =
             this.sendContextMenu(evt.target, evt.pageX, evt.pageY, delay);
--- a/view/nsViewManager.cpp
+++ b/view/nsViewManager.cpp
@@ -1061,23 +1061,24 @@ nsViewManager::IsPainting(bool& aIsPaint
 void
 nsViewManager::ProcessPendingUpdates()
 {
   if (!IsRootVM()) {
     RootViewManager()->ProcessPendingUpdates();
     return;
   }
 
-  mPresShell->GetPresContext()->RefreshDriver()->RevokeViewManagerFlush();
-
   // Flush things like reflows by calling WillPaint on observer presShells.
   if (mPresShell) {
+    mPresShell->GetPresContext()->RefreshDriver()->RevokeViewManagerFlush();
+
     CallWillPaintOnObservers();
+
+    ProcessPendingUpdatesForView(mRootView, true);
   }
-  ProcessPendingUpdatesForView(mRootView, true);
 }
 
 void
 nsViewManager::UpdateWidgetGeometry()
 {
   if (!IsRootVM()) {
     RootViewManager()->UpdateWidgetGeometry();
     return;
--- a/widget/cocoa/nsPrintOptionsX.mm
+++ b/widget/cocoa/nsPrintOptionsX.mm
@@ -24,17 +24,17 @@ nsPrintOptionsX::ReadPrefs(nsIPrintSetti
   rv = nsPrintOptions::ReadPrefs(aPS, aPrinterName, aFlags);
   NS_ASSERTION(NS_SUCCEEDED(rv), "nsPrintOptions::ReadPrefs() failed");
   
   nsRefPtr<nsPrintSettingsX> printSettingsX(do_QueryObject(aPS));
   if (!printSettingsX)
     return NS_ERROR_NO_INTERFACE;
   rv = printSettingsX->ReadPageFormatFromPrefs();
   
-  return rv;
+  return NS_OK;
 }
 
 nsresult nsPrintOptionsX::_CreatePrintSettings(nsIPrintSettings **_retval)
 {
   nsresult rv;
   *_retval = nullptr;
 
   nsPrintSettingsX* printSettings = new nsPrintSettingsX; // does not initially ref count
--- a/widget/cocoa/nsWidgetFactory.mm
+++ b/widget/cocoa/nsWidgetFactory.mm
@@ -135,23 +135,20 @@ static const mozilla::Module::CIDEntry k
     mozilla::Module::MAIN_PROCESS_ONLY },
   { &kNS_CLIPBOARDHELPER_CID, false, NULL, nsClipboardHelperConstructor },
   { &kNS_DRAGSERVICE_CID, false, NULL, nsDragServiceConstructor,
     mozilla::Module::MAIN_PROCESS_ONLY },
   { &kNS_BIDIKEYBOARD_CID, false, NULL, nsBidiKeyboardConstructor },
   { &kNS_THEMERENDERER_CID, false, NULL, nsNativeThemeCocoaConstructor },
   { &kNS_SCREENMANAGER_CID, false, NULL, nsScreenManagerCocoaConstructor,
     mozilla::Module::MAIN_PROCESS_ONLY },
-  { &kNS_DEVICE_CONTEXT_SPEC_CID, false, NULL, nsDeviceContextSpecXConstructor,
-    mozilla::Module::MAIN_PROCESS_ONLY },
-  { &kNS_PRINTSESSION_CID, false, NULL, nsPrintSessionConstructor,
-    mozilla::Module::MAIN_PROCESS_ONLY },
+  { &kNS_DEVICE_CONTEXT_SPEC_CID, false, NULL, nsDeviceContextSpecXConstructor },
+  { &kNS_PRINTSESSION_CID, false, NULL, nsPrintSessionConstructor },
   { &kNS_PRINTSETTINGSSERVICE_CID, false, NULL, nsPrintOptionsXConstructor },
-  { &kNS_PRINTDIALOGSERVICE_CID, false, NULL, nsPrintDialogServiceXConstructor,
-    mozilla::Module::MAIN_PROCESS_ONLY },
+  { &kNS_PRINTDIALOGSERVICE_CID, false, NULL, nsPrintDialogServiceXConstructor },
   { &kNS_IDLE_SERVICE_CID, false, NULL, nsIdleServiceXConstructor },
   { &kNS_SYSTEMALERTSSERVICE_CID, false, NULL, OSXNotificationCenterConstructor },
   { &kNS_NATIVEMENUSERVICE_CID, false, NULL, nsNativeMenuServiceXConstructor },
   { &kNS_MACDOCKSUPPORT_CID, false, NULL, nsMacDockSupportConstructor },
   { &kNS_MACWEBAPPUTILS_CID, false, NULL, nsMacWebAppUtilsConstructor },
   { &kNS_STANDALONENATIVEMENU_CID, false, NULL, nsStandaloneNativeMenuConstructor },
   { &kNS_MACSYSTEMSTATUSBAR_CID, false, NULL, nsSystemStatusBarCocoaConstructor },
   { &kNS_GFXINFO_CID, false, NULL, mozilla::widget::GfxInfoConstructor },
@@ -175,23 +172,20 @@ static const mozilla::Module::ContractID
     mozilla::Module::MAIN_PROCESS_ONLY },
   { "@mozilla.org/widget/clipboardhelper;1", &kNS_CLIPBOARDHELPER_CID },
   { "@mozilla.org/widget/dragservice;1", &kNS_DRAGSERVICE_CID,
     mozilla::Module::MAIN_PROCESS_ONLY },
   { "@mozilla.org/widget/bidikeyboard;1", &kNS_BIDIKEYBOARD_CID },
   { "@mozilla.org/chrome/chrome-native-theme;1", &kNS_THEMERENDERER_CID },
   { "@mozilla.org/gfx/screenmanager;1", &kNS_SCREENMANAGER_CID,
     mozilla::Module::MAIN_PROCESS_ONLY },
-  { "@mozilla.org/gfx/devicecontextspec;1", &kNS_DEVICE_CONTEXT_SPEC_CID,
-    mozilla::Module::MAIN_PROCESS_ONLY },
-  { "@mozilla.org/gfx/printsession;1", &kNS_PRINTSESSION_CID,
-    mozilla::Module::MAIN_PROCESS_ONLY },
+  { "@mozilla.org/gfx/devicecontextspec;1", &kNS_DEVICE_CONTEXT_SPEC_CID },
+  { "@mozilla.org/gfx/printsession;1", &kNS_PRINTSESSION_CID },
   { "@mozilla.org/gfx/printsettings-service;1", &kNS_PRINTSETTINGSSERVICE_CID },
-  { NS_PRINTDIALOGSERVICE_CONTRACTID, &kNS_PRINTDIALOGSERVICE_CID,
-    mozilla::Module::MAIN_PROCESS_ONLY },
+  { NS_PRINTDIALOGSERVICE_CONTRACTID, &kNS_PRINTDIALOGSERVICE_CID },
   { "@mozilla.org/widget/idleservice;1", &kNS_IDLE_SERVICE_CID },
   { "@mozilla.org/system-alerts-service;1", &kNS_SYSTEMALERTSSERVICE_CID },
   { "@mozilla.org/widget/nativemenuservice;1", &kNS_NATIVEMENUSERVICE_CID },
   { "@mozilla.org/widget/macdocksupport;1", &kNS_MACDOCKSUPPORT_CID },
   { "@mozilla.org/widget/mac-web-app-utils;1", &kNS_MACWEBAPPUTILS_CID },
   { "@mozilla.org/widget/standalonenativemenu;1", &kNS_STANDALONENATIVEMENU_CID },
   { "@mozilla.org/widget/macsystemstatusbar;1", &kNS_MACSYSTEMSTATUSBAR_CID },
   { "@mozilla.org/gfx/info;1", &kNS_GFXINFO_CID },
--- a/widget/gtk/nsWidgetFactory.cpp
+++ b/widget/gtk/nsWidgetFactory.cpp
@@ -214,24 +214,20 @@ static const mozilla::Module::CIDEntry k
 #endif
     { &kNS_HTMLFORMATCONVERTER_CID, false, nullptr, nsHTMLFormatConverterConstructor },
     { &kNS_BIDIKEYBOARD_CID, false, nullptr, nsBidiKeyboardConstructor },
     { &kNS_SCREENMANAGER_CID, false, nullptr, nsScreenManagerGtkConstructor,
       Module::MAIN_PROCESS_ONLY },
     { &kNS_THEMERENDERER_CID, false, nullptr, nsNativeThemeGTKConstructor },
 #ifdef NS_PRINTING
     { &kNS_PRINTSETTINGSSERVICE_CID, false, nullptr, nsPrintOptionsGTKConstructor },
-    { &kNS_PRINTER_ENUMERATOR_CID, false, nullptr, nsPrinterEnumeratorGTKConstructor,
-      Module::MAIN_PROCESS_ONLY },
-    { &kNS_PRINTSESSION_CID, false, nullptr, nsPrintSessionConstructor,
-      Module::MAIN_PROCESS_ONLY },
-    { &kNS_DEVICE_CONTEXT_SPEC_CID, false, nullptr, nsDeviceContextSpecGTKConstructor,
-      Module::MAIN_PROCESS_ONLY },
-    { &kNS_PRINTDIALOGSERVICE_CID, false, nullptr, nsPrintDialogServiceGTKConstructor,
-      Module::MAIN_PROCESS_ONLY },
+    { &kNS_PRINTER_ENUMERATOR_CID, false, nullptr, nsPrinterEnumeratorGTKConstructor },
+    { &kNS_PRINTSESSION_CID, false, nullptr, nsPrintSessionConstructor },
+    { &kNS_DEVICE_CONTEXT_SPEC_CID, false, nullptr, nsDeviceContextSpecGTKConstructor },
+    { &kNS_PRINTDIALOGSERVICE_CID, false, nullptr, nsPrintDialogServiceGTKConstructor },
 #endif
     { &kNS_IMAGE_TO_PIXBUF_CID, false, nullptr, nsImageToPixbufConstructor },
 #if defined(MOZ_X11)
     { &kNS_IDLE_SERVICE_CID, false, nullptr, nsIdleServiceGTKConstructor },
     { &kNS_GFXINFO_CID, false, nullptr, mozilla::widget::GfxInfoConstructor },
 #endif
     { nullptr }
 };
@@ -251,24 +247,20 @@ static const mozilla::Module::ContractID
 #endif
     { "@mozilla.org/widget/htmlformatconverter;1", &kNS_HTMLFORMATCONVERTER_CID },
     { "@mozilla.org/widget/bidikeyboard;1", &kNS_BIDIKEYBOARD_CID },
     { "@mozilla.org/gfx/screenmanager;1", &kNS_SCREENMANAGER_CID,
       Module::MAIN_PROCESS_ONLY },
     { "@mozilla.org/chrome/chrome-native-theme;1", &kNS_THEMERENDERER_CID },
 #ifdef NS_PRINTING
     { "@mozilla.org/gfx/printsettings-service;1", &kNS_PRINTSETTINGSSERVICE_CID },
-    { "@mozilla.org/gfx/printerenumerator;1", &kNS_PRINTER_ENUMERATOR_CID,
-      Module::MAIN_PROCESS_ONLY },
-    { "@mozilla.org/gfx/printsession;1", &kNS_PRINTSESSION_CID,
-      Module::MAIN_PROCESS_ONLY },
-    { "@mozilla.org/gfx/devicecontextspec;1", &kNS_DEVICE_CONTEXT_SPEC_CID,
-      Module::MAIN_PROCESS_ONLY },
-    { NS_PRINTDIALOGSERVICE_CONTRACTID, &kNS_PRINTDIALOGSERVICE_CID,
-      Module::MAIN_PROCESS_ONLY },
+    { "@mozilla.org/gfx/printerenumerator;1", &kNS_PRINTER_ENUMERATOR_CID },
+    { "@mozilla.org/gfx/printsession;1", &kNS_PRINTSESSION_CID },
+    { "@mozilla.org/gfx/devicecontextspec;1", &kNS_DEVICE_CONTEXT_SPEC_CID },
+    { NS_PRINTDIALOGSERVICE_CONTRACTID, &kNS_PRINTDIALOGSERVICE_CID },
 #endif
     { "@mozilla.org/widget/image-to-gdk-pixbuf;1", &kNS_IMAGE_TO_PIXBUF_CID },
 #if defined(MOZ_X11)
     { "@mozilla.org/widget/idleservice;1", &kNS_IDLE_SERVICE_CID },
     { "@mozilla.org/gfx/info;1", &kNS_GFXINFO_CID },
 #endif
     { nullptr }
 };
--- a/widget/moz.build
+++ b/widget/moz.build
@@ -97,16 +97,17 @@ EXPORTS += [
     'GfxInfoBase.h',
     'GfxInfoCollector.h',
     'InputData.h',
     'nsIDeviceContextSpec.h',
     'nsIPluginWidget.h',
     'nsIRollupListener.h',
     'nsIWidget.h',
     'nsIWidgetListener.h',
+    'nsPrintOptionsImpl.h',
     'nsWidgetInitData.h',
     'nsWidgetsCID.h',
 ]
 
 EXPORTS.mozilla += [
     'BasicEvents.h',
     'CommandList.h',
     'ContentEvents.h',
--- a/widget/nsIPrintOptions.idl
+++ b/widget/nsIPrintOptions.idl
@@ -3,33 +3,42 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsISupports.idl"
 #include "nsIPrintSettings.idl"
 
 %{ C++
 struct nsFont;
+
+namespace mozilla {
+namespace embedding {
+  class PrintData;
+}
+}
 %}
 
 interface nsIStringEnumerator;
+interface nsIWebBrowserPrint;
 
 /**
  * Native types
  */
 [ref] native nsNativeFontRef(nsFont);
+[ref] native PrintDataRef(const mozilla::embedding::PrintData);
+[ptr] native PrintDataPtr(mozilla::embedding::PrintData);
 
 /**
  * Print options interface
  *
  * Do not attempt to freeze this API - it still needs lots of work. Consult
  * John Keiser <jkeiser@netscape.com> and Roland Mainz
  * <roland.mainz@informatik.med.uni-giessen.de> for futher details.
  */
-[scriptable, uuid(92597c2b-109b-40bb-8f93-9b9acfa31de8)]
+[scriptable, uuid(2ac74034-700e-40fd-8059-81d33223af58)]
 
 interface nsIPrintOptions : nsISupports
 {
   /**
    * Show Native Print Options dialog, this may not be supported on all platforms
    */
   void ShowPrintSetupDialog(in nsIPrintSettings aThePrintSettings);
 
@@ -52,16 +61,49 @@ interface nsIPrintOptions : nsISupports
                              aPrintSettings, out boolean aDisplayed);
 
   /**
    * Native data constants
    */
   const short kNativeDataPrintRecord        = 0;
 
   [noscript] voidPtr GetNativeData(in short aDataType);
+
+  /**
+   * Given some nsIPrintSettings and (optionally) an nsIWebBrowserPrint, populates
+   * a PrintData representing them which can be sent over IPC. Values are only
+   * ever read from aSettings and aWBP.
+   *
+   * @param aSettings
+   *        An nsIPrintSettings for a print job.
+   * @param aWBP (optional)
+   *        The nsIWebBrowserPrint for the print job.
+   * @param data
+   *        Pointer to a pre-existing PrintData to populate.
+   *
+   * @return nsresult
+   */
+  [noscript] void SerializeToPrintData(in nsIPrintSettings aPrintSettings,
+                                       in nsIWebBrowserPrint aWebBrowserPrint,
+                                       in PrintDataPtr data);
+
+  /**
+   * This function is the opposite of SerializeToPrintData, in that it takes
+   * a PrintData, and populates a pre-existing nsIPrintSettings with the data
+   * from PrintData.
+   *
+   * @param PrintData
+   *        Printing information sent through IPC.
+   * @param settings
+   *        A pre-existing nsIPrintSettings to populate with the PrintData.
+   *
+   * @return nsresult
+   */
+  [noscript] void DeserializeToPrintSettings(in PrintDataRef data,
+                                             in nsIPrintSettings aPrintSettings);
 };
 
 [scriptable, uuid(5e738fff-404c-4c94-9189-e8f2cce93e94)]
 
 interface nsIPrinterEnumerator : nsISupports
 {
   /**
    * The name of the system default printer. This name should also be
--- a/widget/nsPrintOptionsImpl.cpp
+++ b/widget/nsPrintOptionsImpl.cpp
@@ -1,13 +1,14 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+#include "mozilla/embedding/PPrinting.h"
 #include "nsPrintOptionsImpl.h"
 #include "nsReadableUtils.h"
 #include "nsPrintSettingsImpl.h"
 
 #include "nsIDOMWindow.h"
 #include "nsIServiceManager.h"
 #include "nsIDialogParamBlock.h"
 #include "nsXPCOM.h"
@@ -17,18 +18,20 @@
 #include "prprf.h"
 
 #include "nsIStringEnumerator.h"
 #include "nsISupportsPrimitives.h"
 #include "stdlib.h"
 #include "nsAutoPtr.h"
 #include "mozilla/Preferences.h"
 #include "nsPrintfCString.h"
+#include "nsIWebBrowserPrint.h"
 
 using namespace mozilla;
+using namespace mozilla::embedding;
 
 NS_IMPL_ISUPPORTS(nsPrintOptions, nsIPrintOptions, nsIPrintSettingsService)
 
 // Pref Constants
 static const char kMarginTop[]       = "print_margin_top";
 static const char kMarginLeft[]      = "print_margin_left";
 static const char kMarginBottom[]    = "print_margin_bottom";
 static const char kMarginRight[]     = "print_margin_right";
@@ -93,16 +96,231 @@ nsPrintOptions::~nsPrintOptions()
 
 nsresult
 nsPrintOptions::Init()
 {
   return NS_OK;
 }
 
 NS_IMETHODIMP
+nsPrintOptions::SerializeToPrintData(nsIPrintSettings* aSettings,
+                                     nsIWebBrowserPrint* aWBP,
+                                     PrintData* data)
+{
+  aSettings->GetStartPageRange(&data->startPageRange());
+  aSettings->GetEndPageRange(&data->endPageRange());
+
+  aSettings->GetEdgeTop(&data->edgeTop());
+  aSettings->GetEdgeLeft(&data->edgeLeft());
+  aSettings->GetEdgeBottom(&data->edgeBottom());
+  aSettings->GetEdgeRight(&data->edgeRight());
+
+  aSettings->GetMarginTop(&data->marginTop());
+  aSettings->GetMarginLeft(&data->marginLeft());
+  aSettings->GetMarginBottom(&data->marginBottom());
+  aSettings->GetMarginRight(&data->marginRight());
+  aSettings->GetUnwriteableMarginTop(&data->unwriteableMarginTop());
+  aSettings->GetUnwriteableMarginLeft(&data->unwriteableMarginLeft());
+  aSettings->GetUnwriteableMarginBottom(&data->unwriteableMarginBottom());
+  aSettings->GetUnwriteableMarginRight(&data->unwriteableMarginRight());
+
+  aSettings->GetScaling(&data->scaling());
+
+  aSettings->GetPrintBGColors(&data->printBGColors());
+  aSettings->GetPrintBGImages(&data->printBGImages());
+  aSettings->GetPrintRange(&data->printRange());
+
+  // I have no idea if I'm doing this string copying correctly...
+  nsXPIDLString title;
+  aSettings->GetTitle(getter_Copies(title));
+  data->title() = title;
+
+  nsXPIDLString docURL;
+  aSettings->GetDocURL(getter_Copies(docURL));
+  data->docURL() = docURL;
+
+  // Header strings...
+  nsXPIDLString headerStrLeft;
+  aSettings->GetHeaderStrLeft(getter_Copies(headerStrLeft));
+  data->headerStrLeft() = headerStrLeft;
+
+  nsXPIDLString headerStrCenter;
+  aSettings->GetHeaderStrCenter(getter_Copies(headerStrCenter));
+  data->headerStrCenter() = headerStrCenter;
+
+  nsXPIDLString headerStrRight;
+  aSettings->GetHeaderStrRight(getter_Copies(headerStrRight));
+  data->headerStrRight() = headerStrRight;
+
+  // Footer strings...
+  nsXPIDLString footerStrLeft;
+  aSettings->GetFooterStrLeft(getter_Copies(footerStrLeft));
+  data->footerStrLeft() = footerStrLeft;
+
+  nsXPIDLString footerStrCenter;
+  aSettings->GetFooterStrCenter(getter_Copies(footerStrCenter));
+  data->footerStrCenter() = footerStrCenter;
+
+  nsXPIDLString footerStrRight;
+  aSettings->GetFooterStrRight(getter_Copies(footerStrRight));
+  data->footerStrRight() = footerStrRight;
+
+  aSettings->GetHowToEnableFrameUI(&data->howToEnableFrameUI());
+  aSettings->GetIsCancelled(&data->isCancelled());
+  aSettings->GetPrintFrameTypeUsage(&data->printFrameTypeUsage());
+  aSettings->GetPrintFrameType(&data->printFrameType());
+  aSettings->GetPrintSilent(&data->printSilent());
+  aSettings->GetShrinkToFit(&data->shrinkToFit());
+  aSettings->GetShowPrintProgress(&data->showPrintProgress());
+
+  nsXPIDLString paperName;
+  aSettings->GetPaperName(getter_Copies(paperName));
+  data->paperName() = paperName;
+
+  aSettings->GetPaperSizeType(&data->paperSizeType());
+  aSettings->GetPaperData(&data->paperData());
+  aSettings->GetPaperWidth(&data->paperWidth());
+  aSettings->GetPaperHeight(&data->paperHeight());
+  aSettings->GetPaperSizeUnit(&data->paperSizeUnit());
+
+  nsXPIDLString plexName;
+  aSettings->GetPlexName(getter_Copies(plexName));
+  data->plexName() = plexName;
+
+  nsXPIDLString colorspace;
+  aSettings->GetColorspace(getter_Copies(colorspace));
+  data->colorspace() = colorspace;
+
+  nsXPIDLString resolutionName;
+  aSettings->GetResolutionName(getter_Copies(resolutionName));
+  data->resolutionName() = resolutionName;
+
+  aSettings->GetDownloadFonts(&data->downloadFonts());
+  aSettings->GetPrintReversed(&data->printReversed());
+  aSettings->GetPrintInColor(&data->printInColor());
+  aSettings->GetOrientation(&data->orientation());
+
+  nsXPIDLString printCommand;
+  aSettings->GetPrintCommand(getter_Copies(printCommand));
+  data->printCommand() = printCommand;
+
+  aSettings->GetNumCopies(&data->numCopies());
+
+  nsXPIDLString printerName;
+  aSettings->GetPrinterName(getter_Copies(printerName));
+  data->printerName() = printerName;
+
+  aSettings->GetPrintToFile(&data->printToFile());
+
+  nsXPIDLString toFileName;
+  aSettings->GetToFileName(getter_Copies(toFileName));
+  data->toFileName() = toFileName;
+
+  aSettings->GetOutputFormat(&data->outputFormat());
+  aSettings->GetPrintPageDelay(&data->printPageDelay());
+  aSettings->GetResolution(&data->resolution());
+  aSettings->GetDuplex(&data->duplex());
+  aSettings->GetIsInitializedFromPrinter(&data->isInitializedFromPrinter());
+  aSettings->GetIsInitializedFromPrefs(&data->isInitializedFromPrefs());
+  aSettings->GetPersistMarginBoxSettings(&data->persistMarginBoxSettings());
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsPrintOptions::DeserializeToPrintSettings(const PrintData& data,
+                                           nsIPrintSettings* settings)
+{
+  settings->SetStartPageRange(data.startPageRange());
+  settings->SetEndPageRange(data.endPageRange());
+
+  settings->SetEdgeTop(data.edgeTop());
+  settings->SetEdgeLeft(data.edgeLeft());
+  settings->SetEdgeBottom(data.edgeBottom());
+  settings->SetEdgeRight(data.edgeRight());
+
+  settings->SetMarginTop(data.marginTop());
+  settings->SetMarginLeft(data.marginLeft());
+  settings->SetMarginBottom(data.marginBottom());
+  settings->SetMarginRight(data.marginRight());
+  settings->SetUnwriteableMarginTop(data.unwriteableMarginTop());
+  settings->SetUnwriteableMarginLeft(data.unwriteableMarginLeft());
+  settings->SetUnwriteableMarginBottom(data.unwriteableMarginBottom());
+  settings->SetUnwriteableMarginRight(data.unwriteableMarginRight());
+
+  settings->SetScaling(data.scaling());
+
+  settings->SetPrintBGColors(data.printBGColors());
+  settings->SetPrintBGImages(data.printBGImages());
+  settings->SetPrintRange(data.printRange());
+
+  // I have no idea if I'm doing this string copying correctly...
+  settings->SetTitle(data.title().get());
+  settings->SetDocURL(data.docURL().get());
+
+  // Header strings...
+  settings->SetHeaderStrLeft(data.headerStrLeft().get());
+  settings->SetHeaderStrCenter(data.headerStrCenter().get());
+  settings->SetHeaderStrRight(data.headerStrRight().get());
+
+  // Footer strings...
+  settings->SetFooterStrLeft(data.footerStrLeft().get());
+  settings->SetFooterStrCenter(data.footerStrCenter().get());
+  settings->SetFooterStrRight(data.footerStrRight().get());
+
+  settings->SetHowToEnableFrameUI(data.howToEnableFrameUI());
+  settings->SetIsCancelled(data.isCancelled());
+  settings->SetPrintFrameTypeUsage(data.printFrameTypeUsage());
+  settings->SetPrintFrameType(data.printFrameType());
+  settings->SetPrintSilent(data.printSilent());
+  settings->SetShrinkToFit(data.shrinkToFit());
+  settings->SetShowPrintProgress(data.showPrintProgress());
+
+  settings->SetPaperName(data.paperName().get());
+
+  settings->SetPaperSizeType(data.paperSizeType());
+  settings->SetPaperData(data.paperData());
+  settings->SetPaperWidth(data.paperWidth());
+  settings->SetPaperHeight(data.paperHeight());
+  settings->SetPaperSizeUnit(data.paperSizeUnit());
+
+  settings->SetPlexName(data.plexName().get());
+
+  settings->SetColorspace(data.colorspace().get());
+
+  settings->SetResolutionName(data.resolutionName().get());
+
+  settings->SetDownloadFonts(data.downloadFonts());
+  settings->SetPrintReversed(data.printReversed());
+  settings->SetPrintInColor(data.printInColor());
+  settings->SetOrientation(data.orientation());
+
+  settings->SetPrintCommand(data.printCommand().get());
+
+  settings->SetNumCopies(data.numCopies());
+
+  settings->SetPrinterName(data.printerName().get());
+
+  settings->SetPrintToFile(data.printToFile());
+
+  settings->SetToFileName(data.toFileName().get());
+
+  settings->SetOutputFormat(data.outputFormat());
+  settings->SetPrintPageDelay(data.printPageDelay());
+  settings->SetResolution(data.resolution());
+  settings->SetDuplex(data.duplex());
+  settings->SetIsInitializedFromPrinter(data.isInitializedFromPrinter());
+  settings->SetIsInitializedFromPrefs(data.isInitializedFromPrefs());
+  settings->SetPersistMarginBoxSettings(data.persistMarginBoxSettings());
+
+  return NS_OK;
+}
+
+
+NS_IMETHODIMP
 nsPrintOptions::ShowPrintSetupDialog(nsIPrintSettings *aPS)
 {
   NS_ENSURE_ARG_POINTER(aPS);
   nsresult rv;
 
   // create a nsISupportsArray of the parameters
   // being passed to the window
   nsCOMPtr<nsISupportsArray> array;
--- a/widget/nsPrintOptionsImpl.h
+++ b/widget/nsPrintOptionsImpl.h
@@ -2,22 +2,26 @@
  *
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsPrintOptionsImpl_h__
 #define nsPrintOptionsImpl_h__
 
+#include "mozilla/embedding/PPrinting.h"
 #include "nsCOMPtr.h"
 #include "nsIPrintOptions.h"
 #include "nsIPrintSettingsService.h"
 #include "nsString.h"
 #include "nsFont.h"
 
+class nsIPrintSettings;
+class nsIWebBrowserPrint;
+
 /**
  *   Class nsPrintOptions
  */
 class nsPrintOptions : public nsIPrintOptions,
                        public nsIPrintSettingsService
 {
 public:
   NS_DECL_ISUPPORTS
--- a/widget/windows/nsPrintOptionsWin.cpp
+++ b/widget/windows/nsPrintOptionsWin.cpp
@@ -1,20 +1,25 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 #include "nsCOMPtr.h"
 #include "nsPrintOptionsWin.h"
 #include "nsPrintSettingsWin.h"
+#include "nsPrintDialogUtil.h"
 
 #include "nsGfxCIID.h"
 #include "nsIServiceManager.h"
+#include "nsIWebBrowserPrint.h"
+
 const char kPrinterEnumeratorContractID[] = "@mozilla.org/gfx/printerenumerator;1";
 
+using namespace mozilla::embedding;
+
 /** ---------------------------------------------------
  *  See documentation in nsPrintOptionsWin.h
  *	@update 6/21/00 dwc
  */
 nsPrintOptionsWin::nsPrintOptionsWin()
 {
 
 }
@@ -22,16 +27,81 @@ nsPrintOptionsWin::nsPrintOptionsWin()
 /** ---------------------------------------------------
  *  See documentation in nsPrintOptionsImpl.h
  *	@update 6/21/00 dwc
  */
 nsPrintOptionsWin::~nsPrintOptionsWin()
 {
 }
 
+NS_IMETHODIMP
+nsPrintOptionsWin::SerializeToPrintData(nsIPrintSettings* aSettings,
+                                        nsIWebBrowserPrint* aWBP,
+                                        PrintData* data)
+{
+  nsresult rv = nsPrintOptions::SerializeToPrintData(aSettings, aWBP, data);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  // Windows wants this information for its print dialogs
+  if (aWBP) {
+    aWBP->GetIsFramesetDocument(&data->isFramesetDocument());
+    aWBP->GetIsFramesetFrameSelected(&data->isFramesetFrameSelected());
+    aWBP->GetIsIFrameSelected(&data->isIFrameSelected());
+    aWBP->GetIsRangeSelection(&data->isRangeSelection());
+  }
+
+  nsCOMPtr<nsIPrintSettingsWin> psWin = do_QueryInterface(aSettings);
+  if (!psWin) {
+    return NS_ERROR_FAILURE;
+  }
+
+  char16_t* deviceName;
+  char16_t* driverName;
+
+  psWin->GetDeviceName(&deviceName);
+  psWin->GetDriverName(&driverName);
+
+  data->deviceName().Assign(deviceName);
+  data->driverName().Assign(driverName);
+
+  free(deviceName);
+  free(driverName);
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsPrintOptionsWin::DeserializeToPrintSettings(const PrintData& data,
+                                              nsIPrintSettings* settings)
+{
+  nsresult rv = nsPrintOptions::DeserializeToPrintSettings(data, settings);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsCOMPtr<nsIPrintSettingsWin> psWin = do_QueryInterface(settings);
+  if (!settings) {
+    return NS_ERROR_FAILURE;
+  }
+
+  psWin->SetDeviceName(data.deviceName().get());
+  psWin->SetDriverName(data.driverName().get());
+
+  // We also need to prepare a DevMode and stuff it into our newly
+  // created nsIPrintSettings...
+  nsXPIDLString printerName;
+  settings->GetPrinterName(getter_Copies(printerName));
+  HGLOBAL gDevMode = CreateGlobalDevModeAndInit(printerName, settings);
+  LPDEVMODEW devMode = (LPDEVMODEW)::GlobalLock(gDevMode);
+  psWin->SetDevMode(devMode);
+
+  ::GlobalUnlock(gDevMode);
+  ::GlobalFree(gDevMode);
+
+  return NS_OK;
+}
+
 /* nsIPrintSettings CreatePrintSettings (); */
 nsresult nsPrintOptionsWin::_CreatePrintSettings(nsIPrintSettings **_retval)
 {
   *_retval = nullptr;
   nsPrintSettingsWin* printSettings = new nsPrintSettingsWin(); // does not initially ref count
   NS_ENSURE_TRUE(printSettings, NS_ERROR_OUT_OF_MEMORY);
 
   NS_ADDREF(*_retval = printSettings); // ref count
--- a/widget/windows/nsPrintOptionsWin.h
+++ b/widget/windows/nsPrintOptionsWin.h
@@ -2,26 +2,35 @@
  *
  * 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 nsPrintOptionsWin_h__
 #define nsPrintOptionsWin_h__
 
+#include "mozilla/embedding/PPrinting.h"
 #include "nsPrintOptionsImpl.h"  
 
+class nsIPrintSettings;
+class nsIWebBrowserPrint;
 
 //*****************************************************************************
 //***    nsPrintOptions
 //*****************************************************************************
 class nsPrintOptionsWin : public nsPrintOptions
 {
 public:
   nsPrintOptionsWin();
   virtual ~nsPrintOptionsWin();
 
+  NS_IMETHODIMP SerializeToPrintData(nsIPrintSettings* aSettings,
+                                     nsIWebBrowserPrint* aWBP,
+                                     mozilla::embedding::PrintData* data);
+  NS_IMETHODIMP DeserializeToPrintSettings(const mozilla::embedding::PrintData& data,
+                                           nsIPrintSettings* settings);
+
   virtual nsresult _CreatePrintSettings(nsIPrintSettings **_retval);
 };
 
 
 
 #endif /* nsPrintOptions_h__ */
--- a/widget/windows/nsWidgetFactory.cpp
+++ b/widget/windows/nsWidgetFactory.cpp
@@ -239,22 +239,19 @@ static const mozilla::Module::CIDEntry k
   { &kNS_WIN_JUMPLISTSHORTCUT_CID, false, nullptr, JumpListShortcutConstructor },
   { &kNS_DRAGSERVICE_CID, false, nullptr, nsDragServiceConstructor, Module::MAIN_PROCESS_ONLY },
   { &kNS_BIDIKEYBOARD_CID, false, nullptr, nsBidiKeyboardConstructor },
 #ifdef MOZ_METRO
   { &kNS_WIN_METROUTILS_CID, false, nullptr, nsWinMetroUtilsConstructor },
 #endif
 #ifdef NS_PRINTING
   { &kNS_PRINTSETTINGSSERVICE_CID, false, nullptr, nsPrintOptionsWinConstructor },
-  { &kNS_PRINTER_ENUMERATOR_CID, false, nullptr, nsPrinterEnumeratorWinConstructor,
-    Module::MAIN_PROCESS_ONLY },
-  { &kNS_PRINTSESSION_CID, false, nullptr, nsPrintSessionConstructor,
-    Module::MAIN_PROCESS_ONLY },
-  { &kNS_DEVICE_CONTEXT_SPEC_CID, false, nullptr, nsDeviceContextSpecWinConstructor,
-    Module::MAIN_PROCESS_ONLY },
+  { &kNS_PRINTER_ENUMERATOR_CID, false, nullptr, nsPrinterEnumeratorWinConstructor },
+  { &kNS_PRINTSESSION_CID, false, nullptr, nsPrintSessionConstructor },
+  { &kNS_DEVICE_CONTEXT_SPEC_CID, false, nullptr, nsDeviceContextSpecWinConstructor },
 #endif
   { nullptr }
 };
 
 static const mozilla::Module::ContractIDEntry kWidgetContracts[] = {
   { "@mozilla.org/widgets/window/win;1", &kNS_WINDOW_CID },
   { "@mozilla.org/widgets/child_window/win;1", &kNS_CHILD_CID },
   { "@mozilla.org/filepicker;1", &kNS_FILEPICKER_CID, Module::MAIN_PROCESS_ONLY },
@@ -277,22 +274,19 @@ static const mozilla::Module::ContractID
   { "@mozilla.org/windows-jumplistshortcut;1", &kNS_WIN_JUMPLISTSHORTCUT_CID },
   { "@mozilla.org/widget/dragservice;1", &kNS_DRAGSERVICE_CID, Module::MAIN_PROCESS_ONLY },
   { "@mozilla.org/widget/bidikeyboard;1", &kNS_BIDIKEYBOARD_CID },
 #ifdef MOZ_METRO
   { "@mozilla.org/windows-metroutils;1", &kNS_WIN_METROUTILS_CID },
 #endif
 #ifdef NS_PRINTING
   { "@mozilla.org/gfx/printsettings-service;1", &kNS_PRINTSETTINGSSERVICE_CID },
-  { "@mozilla.org/gfx/printerenumerator;1", &kNS_PRINTER_ENUMERATOR_CID,
-    Module::MAIN_PROCESS_ONLY },
-  { "@mozilla.org/gfx/printsession;1", &kNS_PRINTSESSION_CID,
-    Module::MAIN_PROCESS_ONLY },
-  { "@mozilla.org/gfx/devicecontextspec;1", &kNS_DEVICE_CONTEXT_SPEC_CID,
-    Module::MAIN_PROCESS_ONLY },
+  { "@mozilla.org/gfx/printerenumerator;1", &kNS_PRINTER_ENUMERATOR_CID },
+  { "@mozilla.org/gfx/printsession;1", &kNS_PRINTSESSION_CID },
+  { "@mozilla.org/gfx/devicecontextspec;1", &kNS_DEVICE_CONTEXT_SPEC_CID },
 #endif
   { nullptr }
 };
 
 static void
 nsWidgetWindowsModuleDtor()
 {
   KeyboardLayout::Shutdown();