Merge mozilla-central to fx-team
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Mon, 12 Jan 2015 15:15:24 +0100
changeset 223287 0e9765732906250f27e59f014fadd38d8f69b32e
parent 223112 4c52eac505cf71070f85acdd2bdf0e19ea93ba7c (current diff)
parent 223286 ee55ebb9d533fb55aa588a8966b63bd8e812a920 (diff)
child 223288 baf96433f2afaa315a0dfed4dda95133efa0d43a
push id10769
push usercbook@mozilla.com
push dateMon, 12 Jan 2015 14:15:52 +0000
treeherderfx-team@0e9765732906 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone37.0a1
Merge mozilla-central to fx-team
browser/base/content/urlbarBindings.xml
build/stlport/fix-warnings-as-errors.patch
dom/canvas/WebGLUniformInfo.h
dom/plugins/base/nsPluginStreamListenerPeer.cpp
mobile/android/base/GeckoAppShell.java
testing/web-platform/meta/cors/basic.htm.ini
--- a/b2g/config/dolphin/sources.xml
+++ b/b2g/config/dolphin/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="e0c735ec89df011ea7dd435087a9045ecff9ff9e">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="f5e481d4caf9ffa561720a6fc9cf521a28bd8439"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="b0254d13e67b0bd4c74c2f2c9b9ea1251949d9fe"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cd63c7ae655ee08ffac32ce36a188f8fefc4b272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="34ea6163f9f0e0122fb0bb03607eccdca31ced7a"/>
--- a/b2g/config/emulator-ics/sources.xml
+++ b/b2g/config/emulator-ics/sources.xml
@@ -14,17 +14,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="df362ace56338da8173d30d3e09e08c42c1accfa">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="f5e481d4caf9ffa561720a6fc9cf521a28bd8439"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="b0254d13e67b0bd4c74c2f2c9b9ea1251949d9fe"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cd63c7ae655ee08ffac32ce36a188f8fefc4b272"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="d5d3f93914558b6f168447b805cd799c8233e300"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="6fa7a4936414ceb4055fd27f7a30e76790f834fb"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="34ea6163f9f0e0122fb0bb03607eccdca31ced7a"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- a/b2g/config/emulator-jb/sources.xml
+++ b/b2g/config/emulator-jb/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="0e94c080bee081a50aa2097527b0b40852f9143f">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="f5e481d4caf9ffa561720a6fc9cf521a28bd8439"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="b0254d13e67b0bd4c74c2f2c9b9ea1251949d9fe"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cd63c7ae655ee08ffac32ce36a188f8fefc4b272"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="34ea6163f9f0e0122fb0bb03607eccdca31ced7a"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
--- a/b2g/config/emulator-kk/sources.xml
+++ b/b2g/config/emulator-kk/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="e0c735ec89df011ea7dd435087a9045ecff9ff9e">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="f5e481d4caf9ffa561720a6fc9cf521a28bd8439"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="b0254d13e67b0bd4c74c2f2c9b9ea1251949d9fe"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cd63c7ae655ee08ffac32ce36a188f8fefc4b272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="34ea6163f9f0e0122fb0bb03607eccdca31ced7a"/>
--- a/b2g/config/emulator/sources.xml
+++ b/b2g/config/emulator/sources.xml
@@ -14,17 +14,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="df362ace56338da8173d30d3e09e08c42c1accfa">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="f5e481d4caf9ffa561720a6fc9cf521a28bd8439"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="b0254d13e67b0bd4c74c2f2c9b9ea1251949d9fe"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cd63c7ae655ee08ffac32ce36a188f8fefc4b272"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="d5d3f93914558b6f168447b805cd799c8233e300"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="6fa7a4936414ceb4055fd27f7a30e76790f834fb"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="34ea6163f9f0e0122fb0bb03607eccdca31ced7a"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- a/b2g/config/flame-kk/sources.xml
+++ b/b2g/config/flame-kk/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="e0c735ec89df011ea7dd435087a9045ecff9ff9e">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="f5e481d4caf9ffa561720a6fc9cf521a28bd8439"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="b0254d13e67b0bd4c74c2f2c9b9ea1251949d9fe"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cd63c7ae655ee08ffac32ce36a188f8fefc4b272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="34ea6163f9f0e0122fb0bb03607eccdca31ced7a"/>
--- a/b2g/config/flame/sources.xml
+++ b/b2g/config/flame/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="0e94c080bee081a50aa2097527b0b40852f9143f">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="f5e481d4caf9ffa561720a6fc9cf521a28bd8439"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="b0254d13e67b0bd4c74c2f2c9b9ea1251949d9fe"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cd63c7ae655ee08ffac32ce36a188f8fefc4b272"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="34ea6163f9f0e0122fb0bb03607eccdca31ced7a"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="e95b4ce22c825da44d14299e1190ea39a5260bde"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="471afab478649078ad7c75ec6b252481a59e19b8"/>
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,9 +1,9 @@
 {
     "git": {
         "git_revision": "", 
         "remote": "", 
         "branch": ""
     }, 
-    "revision": "3bf54932bcae08eb6cab2453a2be007835423cbd", 
+    "revision": "4f9b71ccf0770ad99ba7f802d951f569e10b1021", 
     "repo_path": "integration/gaia-central"
 }
--- a/b2g/config/hamachi/sources.xml
+++ b/b2g/config/hamachi/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="df362ace56338da8173d30d3e09e08c42c1accfa">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="f5e481d4caf9ffa561720a6fc9cf521a28bd8439"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="b0254d13e67b0bd4c74c2f2c9b9ea1251949d9fe"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cd63c7ae655ee08ffac32ce36a188f8fefc4b272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="34ea6163f9f0e0122fb0bb03607eccdca31ced7a"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform_bionic" path="bionic" remote="b2g" revision="1a2a32eda22ef2cd18f57f423a5e7b22a105a6f8"/>
   <project name="platform/bootable/recovery" path="bootable/recovery" revision="746bc48f34f5060f90801925dcdd964030c1ab6d"/>
--- a/b2g/config/helix/sources.xml
+++ b/b2g/config/helix/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="df362ace56338da8173d30d3e09e08c42c1accfa">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="f5e481d4caf9ffa561720a6fc9cf521a28bd8439"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="b0254d13e67b0bd4c74c2f2c9b9ea1251949d9fe"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cd63c7ae655ee08ffac32ce36a188f8fefc4b272"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform_bionic" path="bionic" remote="b2g" revision="1a2a32eda22ef2cd18f57f423a5e7b22a105a6f8"/>
--- a/b2g/config/nexus-4/sources.xml
+++ b/b2g/config/nexus-4/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="0e94c080bee081a50aa2097527b0b40852f9143f">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="f5e481d4caf9ffa561720a6fc9cf521a28bd8439"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="b0254d13e67b0bd4c74c2f2c9b9ea1251949d9fe"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cd63c7ae655ee08ffac32ce36a188f8fefc4b272"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="34ea6163f9f0e0122fb0bb03607eccdca31ced7a"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
--- a/b2g/config/wasabi/sources.xml
+++ b/b2g/config/wasabi/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="ics_chocolate_rb4.2" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="df362ace56338da8173d30d3e09e08c42c1accfa">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="f5e481d4caf9ffa561720a6fc9cf521a28bd8439"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="b0254d13e67b0bd4c74c2f2c9b9ea1251949d9fe"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cd63c7ae655ee08ffac32ce36a188f8fefc4b272"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="34ea6163f9f0e0122fb0bb03607eccdca31ced7a"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
--- a/browser/base/content/urlbarBindings.xml
+++ b/browser/base/content/urlbarBindings.xml
@@ -968,17 +968,17 @@
     </implementation>
   </binding>
 
   <!-- Note: this binding is applied to the autocomplete popup used in the Search bar -->
   <binding id="browser-search-autocomplete-result-popup" extends="chrome://browser/content/urlbarBindings.xml#browser-autocomplete-result-popup">
     <resources>
       <stylesheet src="chrome://browser/skin/searchbar.css"/>
     </resources>
-    <content ignorekeys="true" level="top">
+    <content ignorekeys="true" level="top" consumeoutsideclicks="never">
       <xul:hbox xbl:inherits="collapsed=showonlysettings" anonid="searchbar-engine"
                 class="search-panel-header search-panel-current-engine">
         <xul:image class="searchbar-engine-image" xbl:inherits="src"/>
         <xul:label anonid="searchbar-engine-name" flex="1" crop="end"
                    role="presentation"/>
       </xul:hbox>
       <xul:tree anonid="tree" flex="1"
                 class="autocomplete-tree plain search-panel-tree"
--- a/browser/components/safebrowsing/content/test/browser.ini
+++ b/browser/components/safebrowsing/content/test/browser.ini
@@ -1,11 +1,11 @@
 [DEFAULT]
 support-files = head.js
 
 [browser_bug400731.js]
-skip-if = e10s
+skip-if = (os == "win") || e10s
 [browser_bug415846.js]
 skip-if = true
 # Disabled because it seems to now touch network resources
 # skip-if = os == "mac"
 # Disabled on Mac because of its bizarre special-and-unique
 # snowflake of a help menu.
--- a/browser/components/search/content/search.xml
+++ b/browser/components/search/content/search.xml
@@ -901,20 +901,16 @@
             // in browser.xul) is hidden to avoid impacting startup / new
             // window performance. The base binding's openPopup would normally
             // call the overriden openAutocompletePopup in urlbarBindings.xml's
             // browser-autocomplete-result-popup binding to unhide the popup,
             // but since we're overriding openPopup we need to unhide the panel
             // ourselves.
             popup.hidden = false;
 
-            // showHistoryPopup sets consumeoutsideclicks to true so reset it
-            // here
-            popup.setAttribute("consumeoutsideclicks", "false");
-
             popup.mInput = this;
             popup.view = this.controller.QueryInterface(Components.interfaces.nsITreeView);
             popup.invalidate();
 
             popup.showCommentColumn = this.showCommentColumn;
             popup.showImageColumn = this.showImageColumn;
 
             document.popupNode = null;
--- a/browser/devtools/debugger/debugger-controller.js
+++ b/browser/devtools/debugger/debugger-controller.js
@@ -3,17 +3,17 @@
 /* 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;
 
 const DBG_STRINGS_URI = "chrome://browser/locale/devtools/debugger.properties";
-const NEW_SOURCE_IGNORED_URLS = ["debugger eval code", "self-hosted", "XStringBundle"];
+const NEW_SOURCE_IGNORED_URLS = ["debugger eval code", "XStringBundle"];
 const NEW_SOURCE_DISPLAY_DELAY = 200; // ms
 const FETCH_SOURCE_RESPONSE_DELAY = 200; // ms
 const FETCH_EVENT_LISTENERS_DELAY = 200; // ms
 const FRAME_STEP_CLEAR_DELAY = 100; // ms
 const CALL_STACK_PAGE_SIZE = 25; // frames
 
 // The panel's window global is an EventEmitter firing the following events:
 const EVENTS = {
--- a/browser/devtools/webconsole/console-output.js
+++ b/browser/devtools/webconsole/console-output.js
@@ -92,17 +92,17 @@ const CONSOLE_API_LEVELS_TO_SEVERITIES =
   groupCollapsed: "log",
   groupEnd: "log",
   time: "log",
   timeEnd: "log",
   count: "log"
 };
 
 // Array of known message source URLs we need to hide from output.
-const IGNORED_SOURCE_URLS = ["debugger eval code", "self-hosted"];
+const IGNORED_SOURCE_URLS = ["debugger eval code"];
 
 // The maximum length of strings to be displayed by the Web Console.
 const MAX_LONG_STRING_LENGTH = 200000;
 
 // Regular expression that matches the allowed CSS property names when using
 // the `window.console` API.
 const RE_ALLOWED_STYLES = /^(?:-moz-)?(?:background|border|box|clear|color|cursor|display|float|font|line|margin|padding|text|transition|outline|white-space|word|writing|(?:min-|max-)?width|(?:min-|max-)?height)/;
 
--- a/browser/devtools/webconsole/webconsole.js
+++ b/browser/devtools/webconsole/webconsole.js
@@ -47,17 +47,17 @@ const STRICT_TRANSPORT_SECURITY_LEARN_MO
 const WEAK_SIGNATURE_ALGORITHM_LEARN_MORE = "https://developer.mozilla.org/docs/Security/Weak_Signature_Algorithm";
 
 const HELP_URL = "https://developer.mozilla.org/docs/Tools/Web_Console/Helpers";
 
 const VARIABLES_VIEW_URL = "chrome://browser/content/devtools/widgets/VariablesView.xul";
 
 const CONSOLE_DIR_VIEW_HEIGHT = 0.6;
 
-const IGNORED_SOURCE_URLS = ["debugger eval code", "self-hosted"];
+const IGNORED_SOURCE_URLS = ["debugger eval code"];
 
 // The amount of time in milliseconds that we wait before performing a live
 // search.
 const SEARCH_DELAY = 200;
 
 // The number of lines that are displayed in the console output by default, for
 // each category. The user can change this number by adjusting the hidden
 // "devtools.hud.loglimit.{network,cssparser,exception,console}" preferences.
--- a/build/annotationProcessors/AnnotationInfo.java
+++ b/build/annotationProcessors/AnnotationInfo.java
@@ -17,14 +17,14 @@ public class AnnotationInfo {
     public AnnotationInfo(String aWrapperName, boolean aIsMultithreaded,
                           boolean aNoThrow, boolean aNarrowChars, boolean aCatchException) {
         wrapperName = aWrapperName;
         isMultithreaded = aIsMultithreaded;
         noThrow = aNoThrow;
         narrowChars = aNarrowChars;
         catchException = aCatchException;
 
-        if (!noThrow && catchException) {
+        if (noThrow && catchException) {
             // It doesn't make sense to have these together
             throw new IllegalArgumentException("noThrow and catchException are not allowed together");
         }
     }
 }
--- a/build/annotationProcessors/AnnotationProcessor.java
+++ b/build/annotationProcessors/AnnotationProcessor.java
@@ -15,19 +15,21 @@ import java.util.Arrays;
 import java.util.Iterator;
 
 public class AnnotationProcessor {
     public static final String OUTFILE = "GeneratedJNIWrappers.cpp";
     public static final String HEADERFILE = "GeneratedJNIWrappers.h";
 
     public static final String GENERATED_COMMENT =
             "// GENERATED CODE\n" +
-            "// Generated by the Java program at /build/annotationProcessors at compile time from\n" +
-            "// annotations on Java methods. To update, change the annotations on the corresponding Java\n" +
-            "// methods and rerun the build. Manually updating this file will cause your build to fail.\n\n";
+            "// Generated by the Java program at /build/annotationProcessors at compile time\n" +
+            "// from annotations on Java methods. To update, change the annotations on the\n" +
+            "// corresponding Javamethods and rerun the build. Manually updating this file\n" +
+            "// will cause your build to fail.\n" +
+            "\n";
 
     public static void main(String[] args) {
         // We expect a list of jars on the commandline. If missing, whinge about it.
         if (args.length <= 1) {
             System.err.println("Usage: java AnnotationProcessor jarfiles ...");
             System.exit(1);
         }
 
@@ -39,54 +41,47 @@ public class AnnotationProcessor {
 
         // Start the clock!
         long s = System.currentTimeMillis();
 
         // Get an iterator over the classes in the jar files given...
         Iterator<ClassWithOptions> jarClassIterator = IterableJarLoadingURLClassLoader.getIteratorOverJars(args);
 
         StringBuilder headerFile = new StringBuilder(GENERATED_COMMENT);
-        headerFile.append("#ifndef GeneratedJNIWrappers_h__\n" +
-                          "#define GeneratedJNIWrappers_h__\n\n" +
-                          "#include \"nsXPCOMStrings.h\"\n" +
-                          "#include \"AndroidJavaWrappers.h\"\n" +
-                          "\n" +
-                          "namespace mozilla {\n" +
-                          "namespace widget {\n" +
-                          "namespace android {\n" +
-                          "void InitStubs(JNIEnv *env);\n\n");
+        headerFile.append(
+                "#ifndef GeneratedJNIWrappers_h__\n" +
+                "#define GeneratedJNIWrappers_h__\n" +
+                "\n" +
+                "#include \"mozilla/jni/Refs.h\"\n" +
+                "\n" +
+                "namespace mozilla {\n" +
+                "namespace widget {\n" +
+                "\n");
 
         StringBuilder implementationFile = new StringBuilder(GENERATED_COMMENT);
-        implementationFile.append("#include \"GeneratedJNIWrappers.h\"\n" +
-                                  "#include \"AndroidBridgeUtilities.h\"\n" +
-                                  "#include \"nsXPCOMStrings.h\"\n" +
-                                  "#include \"AndroidBridge.h\"\n" +
-                                  "\n" +
-                                  "namespace mozilla {\n" +
-                                  "namespace widget {\n" +
-                                  "namespace android {\n");
-
-        // Used to track the calls to the various class-specific initialisation functions.
-        StringBuilder stubInitialiser = new StringBuilder();
-        stubInitialiser.append("void InitStubs(JNIEnv *env) {\n");
+        implementationFile.append(
+                "#include \"GeneratedJNIWrappers.h\"\n" +
+                "#include \"mozilla/jni/Accessors.h\"\n" +
+                "\n" +
+                "namespace mozilla {\n" +
+                "namespace widget {\n" +
+                "\n");
 
         while (jarClassIterator.hasNext()) {
             ClassWithOptions aClassTuple = jarClassIterator.next();
 
             CodeGenerator generatorInstance;
 
             // Get an iterator over the appropriately generated methods of this class
             Iterator<AnnotatableEntity> methodIterator = new GeneratableElementIterator(aClassTuple.wrappedClass);
 
             if (!methodIterator.hasNext()) {
                 continue;
             }
-            generatorInstance = new CodeGenerator(aClassTuple.wrappedClass, aClassTuple.generatedName);
-
-            stubInitialiser.append("    ").append(aClassTuple.generatedName).append("::InitStubs(env);\n");
+            generatorInstance = new CodeGenerator(aClassTuple);
 
             // Iterate all annotated members in this class..
             while (methodIterator.hasNext()) {
                 AnnotatableEntity aElementTuple = methodIterator.next();
                 switch (aElementTuple.mEntityType) {
                     case METHOD:
                         generatorInstance.generateMethod(aElementTuple);
                         break;
@@ -98,28 +93,26 @@ public class AnnotationProcessor {
                         break;
                 }
             }
 
             headerFile.append(generatorInstance.getHeaderFileContents());
             implementationFile.append(generatorInstance.getWrapperFileContents());
         }
 
-        implementationFile.append('\n');
-        stubInitialiser.append("}");
-        implementationFile.append(stubInitialiser);
+        implementationFile.append(
+                "\n" +
+                "} /* widget */\n" +
+                "} /* mozilla */\n");
 
-        implementationFile.append("\n} /* android */\n" +
-                                    "} /* widget */\n" +
-                                    "} /* mozilla */\n");
-
-        headerFile.append("\n} /* android */\n" +
-                            "} /* widget */\n" +
-                            "} /* mozilla */\n" +
-                            "#endif\n");
+        headerFile.append(
+                "\n" +
+                "} /* widget */\n" +
+                "} /* mozilla */\n" +
+                "#endif // GeneratedJNIWrappers_h__\n");
 
         writeOutputFiles(headerFile, implementationFile);
         long e = System.currentTimeMillis();
         System.out.println("Annotation processing complete in " + (e - s) + "ms");
     }
 
     private static void writeOutputFiles(StringBuilder aHeaderFile, StringBuilder aImplementationFile) {
         FileOutputStream headerStream = null;
@@ -153,9 +146,9 @@ public class AnnotationProcessor {
                     outStream.close();
                 } catch (IOException e) {
                     System.err.println("Unable to close outStream due to "+e);
                     e.printStackTrace(System.err);
                 }
             }
         }
     }
-}
\ No newline at end of file
+}
--- a/build/annotationProcessors/CodeGenerator.java
+++ b/build/annotationProcessors/CodeGenerator.java
@@ -1,693 +1,462 @@
 /* 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.annotationProcessors;
 
 import org.mozilla.gecko.annotationProcessors.classloader.AnnotatableEntity;
+import org.mozilla.gecko.annotationProcessors.classloader.ClassWithOptions;
 import org.mozilla.gecko.annotationProcessors.utils.Utils;
 
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Field;
 import java.lang.reflect.Member;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
-import java.util.HashMap;
 import java.util.HashSet;
 
 public class CodeGenerator {
     private static final Class<?>[] EMPTY_CLASS_ARRAY = new Class<?>[0];
-    private static final Annotation[][] GETTER_ARGUMENT_ANNOTATIONS = new Annotation[0][0];
-    private static final Annotation[][] SETTER_ARGUMENT_ANNOTATIONS = new Annotation[1][0];
 
     // Buffers holding the strings to ultimately be written to the output files.
-    private final StringBuilder zeroingCode = new StringBuilder();
-    private final StringBuilder wrapperStartupCode = new StringBuilder();
-    private final StringBuilder wrapperMethodBodies = new StringBuilder();
-    private final StringBuilder headerPublic = new StringBuilder();
-    private final StringBuilder headerProtected = new StringBuilder();
+    private final StringBuilder cpp = new StringBuilder();
+    private final StringBuilder header = new StringBuilder();
+
+    private final Class<?> cls;
+    private final String clsName;
 
-    private final HashSet<String> seenClasses = new HashSet<String>();
+    private final HashSet<String> takenMethodNames = new HashSet<String>();
 
-    private final String mCClassName;
-
-    private final Class<?> mClassToWrap;
+    public CodeGenerator(ClassWithOptions annotatedClass) {
+        this.cls = annotatedClass.wrappedClass;
+        this.clsName = annotatedClass.generatedName;
 
-    private boolean mHasEncounteredDefaultConstructor;
+        header.append(
+                "class " + clsName + " : public mozilla::jni::Class<" + clsName + "> {\n" +
+                "\n" +
+                "public:\n" +
+                "    typedef mozilla::jni::Ref<" + clsName + "> Ref;\n" +
+                "    typedef mozilla::jni::LocalRef<" + clsName + "> LocalRef;\n" +
+                "    typedef mozilla::jni::GlobalRef<" + clsName + "> GlobalRef;\n" +
+                "    typedef const typename mozilla::jni::Param<" + clsName + ">::Type& Param;\n" +
+                "\n" +
+                "    static constexpr char name[] =\n" +
+                "            \"" + cls.getName().replace('.', '/') + "\";\n" +
+                "\n" +
+                "protected:\n" +
+                "    " + clsName + "(jobject instance) : Class(instance) {}\n" +
+                "\n");
 
-    // Used for creating unique names for method ID fields in the face of
-    private final HashMap<Member, String> mMembersToIds = new HashMap<Member, String>();
-    private final HashSet<String> mTakenMemberNames = new HashSet<String>();
-    private int mNameMunger;
+        cpp.append(
+                "constexpr char " + clsName + "::name[];\n" +
+                "\n");
+    }
 
-    private final boolean mLazyInit;
+    private String getTraitsName(String uniqueName, boolean includeScope) {
+        return (includeScope ? clsName + "::" : "") + uniqueName + "_t";
+    }
 
-    public CodeGenerator(Class<?> aClass, String aGeneratedName) {
-        this(aClass, aGeneratedName, false);
+    private String getNativeParameterType(Class<?> type, AnnotationInfo info) {
+        if (type == cls) {
+            return clsName + "::Param";
+        }
+        return Utils.getNativeParameterType(type, info);
     }
 
-    public CodeGenerator(Class<?> aClass, String aGeneratedName, boolean aLazyInit) {
-        mClassToWrap = aClass;
-        mCClassName = aGeneratedName;
-        mLazyInit = aLazyInit;
+    private String getNativeReturnType(Class<?> type, AnnotationInfo info) {
+        if (type == cls) {
+            return clsName + "::LocalRef";
+        }
+        return Utils.getNativeReturnType(type, info);
+    }
 
-        // Write the file header things. Includes and so forth.
-        // GeneratedJNIWrappers.cpp is generated as the concatenation of wrapperStartupCode with
-        // wrapperMethodBodies. Similarly, GeneratedJNIWrappers.h is the concatenation of headerPublic
-        // with headerProtected.
-        wrapperStartupCode.append("void ").append(mCClassName).append("::InitStubs(JNIEnv *env) {\n");
+    private void generateMember(AnnotationInfo info, Member member,
+                                String uniqueName, Class<?> type) {
+        header.append(
+                "public:\n" +
+                "    struct " + getTraitsName(uniqueName, /* includeScope */ false) + " {\n" +
+                "        typedef " + clsName + " Owner;\n" +
+                "        typedef " + getNativeReturnType(type, info) + " ReturnType;\n" +
+                "        typedef " + getNativeParameterType(type, info) + " SetterType;\n" +
+                "        static constexpr char name[] = \"" +
+                        Utils.getMemberName(member) + "\";\n" +
+                "        static constexpr char signature[] =\n" +
+                "                \"" + Utils.getSignature(member) + "\";\n" +
+                "        static const bool isStatic = " + Utils.isStatic(member) + ";\n" +
+                "        static const bool isMultithreaded = " + info.isMultithreaded + ";\n" +
+                "        static const mozilla::jni::ExceptionMode exceptionMode = " + (
+                        info.catchException ? "mozilla::jni::ExceptionMode::NSRESULT" :
+                        info.noThrow ?        "mozilla::jni::ExceptionMode::IGNORE" :
+                                              "mozilla::jni::ExceptionMode::ABORT") + ";\n" +
+                "    };\n" +
+                "\n");
 
-        // Now we write the various GetStaticMethodID calls here...
-        headerPublic.append("class ").append(mCClassName).append(" : public AutoGlobalWrappedJavaObject {\n" +
-                            "public:\n" +
-                            "    static void InitStubs(JNIEnv *env);\n");
-        headerProtected.append("protected:");
+        cpp.append(
+                "constexpr char " + getTraitsName(uniqueName, /* includeScope */ true) +
+                        "::name[];\n" +
+                "constexpr char " + getTraitsName(uniqueName, /* includeScope */ true) +
+                        "::signature[];\n" +
+                "\n");
+    }
 
-        generateWrapperMethod();
+    private String getUniqueMethodName(String basename) {
+        String newName = basename;
+        int index = 1;
+
+        while (takenMethodNames.contains(newName)) {
+            newName = basename + (++index);
+        }
+
+        takenMethodNames.add(newName);
+        return newName;
     }
 
     /**
-     * Emit a static method which takes an instance of the class being wrapped and returns an instance
-     * of the C++ wrapper class backed by that object.
+     * Generate a method prototype that includes return and argument types,
+     * without specifiers (static, const, etc.).
      */
-    private void generateWrapperMethod() {
-        headerPublic.append("    static ").append(mCClassName).append("* Wrap(jobject obj);\n" +
-                "    ").append(mCClassName).append("(jobject obj, JNIEnv* env) : AutoGlobalWrappedJavaObject(obj, env) {};\n");
+    private String generatePrototype(String name, Class<?>[] argTypes,
+                                     Class<?> returnType, AnnotationInfo info,
+                                     boolean includeScope, boolean includeArgName) {
+
+        final StringBuilder proto = new StringBuilder();
+        int argIndex = 0;
+
+        if (info.catchException) {
+            proto.append("nsresult ");
+        } else {
+            proto.append(getNativeReturnType(returnType, info)).append(' ');
+        }
+
+        if (includeScope) {
+            proto.append(clsName).append("::");
+        }
+
+        proto.append(name).append('(');
 
-        wrapperMethodBodies.append("\n").append(mCClassName).append("* ").append(mCClassName).append("::Wrap(jobject obj) {\n" +
-                "    JNIEnv *env = GetJNIForThread();\n" +
-                "    ").append(mCClassName).append("* ret = new ").append(mCClassName).append("(obj, env);\n" +
-                "    env->DeleteLocalRef(obj);\n" +
-                "    return ret;\n" +
-                "}\n");
+        for (Class<?> argType : argTypes) {
+            proto.append(getNativeParameterType(argType, info));
+            if (includeArgName) {
+                proto.append(" a").append(argIndex++);
+            }
+            proto.append(", ");
+        }
+
+        if (info.catchException && returnType != void.class) {
+            proto.append(getNativeReturnType(returnType, info)).append('*');
+            if (includeArgName) {
+                proto.append(" a").append(argIndex++);
+            }
+            proto.append(", ");
+        }
+
+        if (proto.substring(proto.length() - 2).equals(", ")) {
+            proto.setLength(proto.length() - 2);
+        }
+
+        return proto.append(')').toString();
+    }
+
+    /**
+     * Generate a method declaration that includes the prototype with specifiers,
+     * but without the method body.
+     */
+    private String generateDeclaration(String name, Class<?>[] argTypes,
+                                       Class<?> returnType, AnnotationInfo info,
+                                       boolean isStatic) {
+
+        return (isStatic ? "static " : "") +
+            generatePrototype(name, argTypes, returnType, info,
+                              /* includeScope */ false, /* includeArgName */ false) +
+            (isStatic ? ";" : " const;");
     }
 
-    private void generateMemberCommon(Member theMethod, String aCMethodName, Class<?> aClass) {
-        ensureClassHeaderAndStartup(aClass);
-        writeMemberIdField(theMethod, aCMethodName);
+    /**
+     * Generate a method definition that includes the prototype with specifiers,
+     * and with the method body.
+     */
+    private String generateDefinition(String accessorName, String name, Class<?>[] argTypes,
+                                      Class<?> returnType, AnnotationInfo info, boolean isStatic) {
+
+        final StringBuilder def = new StringBuilder(
+                generatePrototype(name, argTypes, returnType, info,
+                                  /* includeScope */ true, /* includeArgName */ true));
+
+        if (!isStatic) {
+            def.append(" const");
+        }
+        def.append("\n{\n");
+
+
+        // Generate code to handle the return value, if needed.
+        // We initialize rv to NS_OK instead of NS_ERROR_* because loading NS_OK (0) uses
+        // fewer instructions. We are guaranteed to set rv to the correct value later.
+
+        if (info.catchException && returnType == void.class) {
+            def.append(
+                    "    nsresult rv = NS_OK;\n" +
+                    "    ");
 
-        if (!mLazyInit) {
-            writeMemberInit(theMethod, wrapperStartupCode);
+        } else if (info.catchException) {
+            // Non-void return type
+            final String resultArg = "a" + argTypes.length;
+            def.append(
+                    "    MOZ_ASSERT(" + resultArg + ");\n" +
+                    "    nsresult rv = NS_OK;\n" +
+                    "    *" + resultArg + " = ");
+
+        } else {
+            def.append(
+                    "    return ");
         }
+
+
+        // Generate a call, e.g., Method<Traits>::Call(a0, a1, a2);
+
+        def.append(accessorName).append("(")
+           .append(isStatic ? "nullptr" : "this");
+
+        if (info.catchException) {
+            def.append(", &rv");
+        } else {
+            def.append(", nullptr");
+        }
+
+        // Generate the call argument list.
+        for (int argIndex = 0; argIndex < argTypes.length; argIndex++) {
+            def.append(", a").append(argIndex);
+        }
+
+        def.append(");\n");
+
+
+        if (info.catchException) {
+            def.append("    return rv;\n");
+        }
+
+        return def.append("}").toString();
     }
 
     /**
      * Append the appropriate generated code to the buffers for the method provided.
      *
-     * @param aMethodTuple The Java method, plus annotation data.
+     * @param annotatedMethod The Java method, plus annotation data.
      */
-    public void generateMethod(AnnotatableEntity aMethodTuple) {
+    public void generateMethod(AnnotatableEntity annotatedMethod) {
         // Unpack the tuple and extract some useful fields from the Method..
-        Method theMethod = aMethodTuple.getMethod();
-
-        String CMethodName = aMethodTuple.mAnnotationInfo.wrapperName;
-
-        generateMemberCommon(theMethod, CMethodName, mClassToWrap);
-
-        boolean isFieldStatic = Utils.isMemberStatic(theMethod);
-
-        Class<?>[] parameterTypes = theMethod.getParameterTypes();
-        Class<?> returnType = theMethod.getReturnType();
+        final Method method = annotatedMethod.getMethod();
+        final AnnotationInfo info = annotatedMethod.mAnnotationInfo;
+        final String uniqueName = getUniqueMethodName(info.wrapperName);
+        final Class<?> returnType = method.getReturnType();
 
-        // Get the C++ method signature for this method.
-        String implementationSignature = Utils.getCImplementationMethodSignature(parameterTypes, returnType, CMethodName,
-            mCClassName, aMethodTuple.mAnnotationInfo.narrowChars, aMethodTuple.mAnnotationInfo.catchException);
-        String headerSignature = Utils.getCHeaderMethodSignature(parameterTypes, theMethod.getParameterAnnotations(), returnType,
-            CMethodName, mCClassName, isFieldStatic, aMethodTuple.mAnnotationInfo.narrowChars, aMethodTuple.mAnnotationInfo.catchException);
-
-        // Add the header signature to the header file.
-        writeSignatureToHeader(headerSignature);
-
-        // Use the implementation signature to generate the method body...
-        writeMethodBody(implementationSignature, theMethod, mClassToWrap,
-                        aMethodTuple.mAnnotationInfo.isMultithreaded,
-                        aMethodTuple.mAnnotationInfo.noThrow,
-                        aMethodTuple.mAnnotationInfo.narrowChars,
-                        aMethodTuple.mAnnotationInfo.catchException);
-    }
-
-    private void generateGetterOrSetterBody(Field aField, String aFieldName, boolean aIsFieldStatic, boolean isSetter, boolean aNarrowChars) {
-        StringBuilder argumentContent = null;
-        Class<?> fieldType = aField.getType();
-
-        if (isSetter) {
-            Class<?>[] setterArguments = new Class<?>[]{fieldType};
-            // Marshall the argument..
-            argumentContent = getArgumentMarshalling(setterArguments);
+        if (method.isSynthetic()) {
+            return;
         }
 
-        if (mLazyInit) {
-            writeMemberInit(aField, wrapperMethodBodies);
-        }
+        generateMember(info, method, uniqueName, returnType);
+
+        final Class<?>[] argTypes = method.getParameterTypes();
+        final boolean isStatic = Utils.isStatic(method);
+
+        header.append(
+                "    " + generateDeclaration(info.wrapperName, argTypes,
+                                             returnType, info, isStatic) + "\n" +
+                "\n");
+
+        cpp.append(
+                generateDefinition(
+                        "mozilla::jni::Method<" +
+                                getTraitsName(uniqueName, /* includeScope */ false) + ">::Call",
+                        info.wrapperName, argTypes, returnType, info, isStatic) + "\n" +
+                "\n");
+    }
 
-        boolean isObjectReturningMethod = Utils.isObjectType(fieldType);
-        wrapperMethodBodies.append("    ");
-        if (isSetter) {
-            wrapperMethodBodies.append("env->Set");
-        } else {
-            wrapperMethodBodies.append("return ");
+    private String getLiteral(Object val, AnnotationInfo info) {
+        final Class<?> type = val.getClass();
+
+        if (type == char.class || type == Character.class) {
+            final char c = (char) val;
+            if (c >= 0x20 && c < 0x7F) {
+                return "'" + c + '\'';
+            }
+            return "u'\\u" + Integer.toHexString(0x10000 | (int) c).substring(1) + '\'';
 
-            if (isObjectReturningMethod) {
-                wrapperMethodBodies.append("static_cast<").append(Utils.getCReturnType(fieldType, aNarrowChars)).append(">(");
+        } else if (type == CharSequence.class || type == String.class) {
+            final CharSequence str = (CharSequence) val;
+            final StringBuilder out = new StringBuilder(info.narrowChars ? "u8\"" : "u\"");
+            for (int i = 0; i < str.length(); i++) {
+                final char c = str.charAt(i);
+                if (c >= 0x20 && c < 0x7F) {
+                    out.append(c);
+                } else {
+                    out.append("\\u").append(Integer.toHexString(0x10000 | (int) c).substring(1));
+                }
             }
-
-            wrapperMethodBodies.append("env->Get");
+            return out.append('"').toString();
         }
 
-        if (aIsFieldStatic) {
-            wrapperMethodBodies.append("Static");
-        }
-        wrapperMethodBodies.append(Utils.getFieldType(fieldType))
-                           .append("Field(");
-
-        // Static will require the class and the field id. Nonstatic, the object and the field id.
-        if (aIsFieldStatic) {
-            wrapperMethodBodies.append(Utils.getClassReferenceName(mClassToWrap));
-        } else {
-            wrapperMethodBodies.append("wrapped_obj");
-        }
-        wrapperMethodBodies.append(", j")
-                           .append(aFieldName);
-        if (isSetter) {
-            wrapperMethodBodies.append(argumentContent);
-        }
-
-        if (!isSetter && isObjectReturningMethod) {
-            wrapperMethodBodies.append(')');
-        }
-        wrapperMethodBodies.append(");\n" +
-                               "}\n");
+        return String.valueOf(val);
     }
 
-    public void generateField(AnnotatableEntity aFieldTuple) {
-        Field theField = aFieldTuple.getField();
+    public void generateField(AnnotatableEntity annotatedField) {
+        final Field field = annotatedField.getField();
+        final AnnotationInfo info = annotatedField.mAnnotationInfo;
+        final String uniqueName = info.wrapperName;
+        final Class<?> type = field.getType();
 
         // Handles a peculiar case when dealing with enum types. We don't care about this field.
         // It just gets in the way and stops our code from compiling.
-        if (theField.getName().equals("$VALUES")) {
+        if (field.isSynthetic() || field.getName().equals("$VALUES")) {
             return;
         }
 
-        String CFieldName = aFieldTuple.mAnnotationInfo.wrapperName;
+        final boolean isStatic = Utils.isStatic(field);
+        final boolean isFinal = Utils.isFinal(field);
 
-        Class<?> fieldType = theField.getType();
-
-        generateMemberCommon(theField, CFieldName, mClassToWrap);
+        if (isStatic && isFinal && (type.isPrimitive() || type == String.class)) {
+            Object val = null;
+            try {
+                val = field.get(null);
+            } catch (final IllegalAccessException e) {
+            }
 
-        boolean isFieldStatic = Utils.isMemberStatic(theField);
-        boolean isFieldFinal = Utils.isMemberFinal(theField);
+            if (val != null && type.isPrimitive()) {
+                // For static final primitive fields, we can use a "static const" declaration.
+                header.append(
+                    "public:\n" +
+                    "    static const " + Utils.getNativeReturnType(type, info) +
+                            ' ' + info.wrapperName + " = " + getLiteral(val, info) + ";\n" +
+                    "\n");
+                return;
+
+            } else if (val != null && type == String.class) {
+                final String nativeType = info.narrowChars ? "char" : "char16_t";
 
-        String getterName = "get" + CFieldName;
-        String getterSignature = Utils.getCImplementationMethodSignature(EMPTY_CLASS_ARRAY, fieldType, getterName, mCClassName, aFieldTuple.mAnnotationInfo.narrowChars, false);
-        String getterHeaderSignature = Utils.getCHeaderMethodSignature(EMPTY_CLASS_ARRAY, GETTER_ARGUMENT_ANNOTATIONS, fieldType, getterName, mCClassName, isFieldStatic, aFieldTuple.mAnnotationInfo.narrowChars, false);
+                header.append(
+                    "public:\n" +
+                    "    static const " + nativeType + ' ' + info.wrapperName + "[];\n" +
+                    "\n");
 
-        writeSignatureToHeader(getterHeaderSignature);
-
-        writeFunctionStartupBoilerPlate(getterSignature, true);
+                cpp.append(
+                    "const " + nativeType + ' ' + clsName + "::" + info.wrapperName +
+                            "[] = " + getLiteral(val, info) + ";\n" +
+                    "\n");
+                return;
+            }
 
-        generateGetterOrSetterBody(theField, CFieldName, isFieldStatic, false, aFieldTuple.mAnnotationInfo.narrowChars);
+            // Fall back to using accessors if we encounter an exception.
+        }
+
+        generateMember(info, field, uniqueName, type);
 
-        // If field not final, also generate a setter function.
-        if (!isFieldFinal) {
-            String setterName = "set" + CFieldName;
+        final Class<?>[] getterArgs = EMPTY_CLASS_ARRAY;
 
-            Class<?>[] setterArguments = new Class<?>[]{fieldType};
+        header.append(
+                "    " + generateDeclaration(info.wrapperName, getterArgs,
+                                             type, info, isStatic) + "\n" +
+                "\n");
 
-            String setterSignature = Utils.getCImplementationMethodSignature(setterArguments, Void.class, setterName, mCClassName, aFieldTuple.mAnnotationInfo.narrowChars, false);
-            String setterHeaderSignature = Utils.getCHeaderMethodSignature(setterArguments, SETTER_ARGUMENT_ANNOTATIONS, Void.class, setterName, mCClassName, isFieldStatic, aFieldTuple.mAnnotationInfo.narrowChars, false);
+        cpp.append(
+                generateDefinition(
+                        "mozilla::jni::Field<" +
+                                getTraitsName(uniqueName, /* includeScope */ false) + ">::Get",
+                        info.wrapperName, getterArgs, type, info, isStatic) + "\n" +
+                "\n");
 
-            writeSignatureToHeader(setterHeaderSignature);
+        if (isFinal) {
+            return;
+        }
 
-            writeFunctionStartupBoilerPlate(setterSignature, true);
+        final Class<?>[] setterArgs = new Class<?>[] { type };
+
+        header.append(
+                "    " + generateDeclaration(info.wrapperName, setterArgs,
+                                             void.class, info, isStatic) + "\n" +
+                "\n");
 
-            generateGetterOrSetterBody(theField, CFieldName, isFieldStatic, true, aFieldTuple.mAnnotationInfo.narrowChars);
-        }
+        cpp.append(
+                generateDefinition(
+                        "mozilla::jni::Field<" +
+                                getTraitsName(uniqueName, /* includeScope */ false) + ">::Set",
+                        info.wrapperName, setterArgs, void.class, info, isStatic) + "\n" +
+                "\n");
     }
 
-    public void generateConstructor(AnnotatableEntity aCtorTuple) {
+    public void generateConstructor(AnnotatableEntity annotatedConstructor) {
         // Unpack the tuple and extract some useful fields from the Method..
-        Constructor<?> theCtor = aCtorTuple.getConstructor();
-        String CMethodName = mCClassName;
+        final Constructor<?> method = annotatedConstructor.getConstructor();
+        final AnnotationInfo info = annotatedConstructor.mAnnotationInfo;
+        final String wrapperName = "New";
+        final String uniqueName = getUniqueMethodName(wrapperName);
+        final Class<?> returnType = cls;
 
-        generateMemberCommon(theCtor, mCClassName, mClassToWrap);
+        if (method.isSynthetic()) {
+            return;
+        }
 
-        String implementationSignature = Utils.getCImplementationMethodSignature(theCtor.getParameterTypes(), Void.class, CMethodName,
-            mCClassName, aCtorTuple.mAnnotationInfo.narrowChars, aCtorTuple.mAnnotationInfo.catchException);
-        String headerSignature = Utils.getCHeaderMethodSignature(theCtor.getParameterTypes(), theCtor.getParameterAnnotations(), Void.class, CMethodName,
-            mCClassName, false, aCtorTuple.mAnnotationInfo.narrowChars, aCtorTuple.mAnnotationInfo.catchException);
+        generateMember(info, method, uniqueName, returnType);
 
-        // Slice off the "void " from the start of the constructor declaration.
-        headerSignature = headerSignature.substring(5);
-        implementationSignature = implementationSignature.substring(5);
+        final Class<?>[] argTypes = method.getParameterTypes();
 
-        // Add the header signatures to the header file.
-        writeSignatureToHeader(headerSignature);
+        header.append(
+                "    " + generateDeclaration(wrapperName, argTypes,
+                                             returnType, info, /* isStatic */ true) + "\n" +
+                "\n");
 
-        // Use the implementation signature to generate the method body...
-        writeCtorBody(implementationSignature, theCtor,
-            aCtorTuple.mAnnotationInfo.isMultithreaded,
-            aCtorTuple.mAnnotationInfo.noThrow,
-            aCtorTuple.mAnnotationInfo.catchException);
-
-        if (theCtor.getParameterTypes().length == 0) {
-            mHasEncounteredDefaultConstructor = true;
-        }
+        cpp.append(
+                generateDefinition(
+                        "mozilla::jni::Constructor<" +
+                                getTraitsName(uniqueName, /* includeScope */ false) + ">::Call",
+                        wrapperName, argTypes, returnType, info, /* isStatic */ true) + "\n" +
+                "\n");
     }
 
     public void generateMembers(Member[] members) {
         for (Member m : members) {
             if (!Modifier.isPublic(m.getModifiers())) {
                 continue;
             }
 
-            String name = m.getName();
+            String name = Utils.getMemberName(m);
             name = name.substring(0, 1).toUpperCase() + name.substring(1);
 
-            AnnotationInfo info = new AnnotationInfo(name, true, true, true, true);
-            AnnotatableEntity entity = new AnnotatableEntity(m, info);
+            final AnnotationInfo info = new AnnotationInfo(name,
+                    /* multithread */ true, /* nothrow */ false,
+                    /* narrow */ false, /* catchException */ true);
+            final AnnotatableEntity entity = new AnnotatableEntity(m, info);
+
             if (m instanceof Constructor) {
                 generateConstructor(entity);
             } else if (m instanceof Method) {
                 generateMethod(entity);
             } else if (m instanceof Field) {
                 generateField(entity);
             } else {
-                throw new IllegalArgumentException("expected member to be Constructor, Method, or Field");
-            }
-        }
-    }
-
-    /**
-     * Writes the appropriate header and startup code to ensure the existence of a reference to the
-     * class specified. If this is already done, does nothing.
-     *
-     * @param aClass The target class.
-     */
-    private void ensureClassHeaderAndStartup(Class<?> aClass) {
-        String className = aClass.getCanonicalName();
-        if (seenClasses.contains(className)) {
-            return;
-        }
-
-        zeroingCode.append("jclass ")
-                   .append(mCClassName)
-                   .append("::")
-                   .append(Utils.getClassReferenceName(aClass))
-                   .append(" = 0;\n");
-
-        // Add a field to hold the reference...
-        headerProtected.append("\n    static jclass ")
-                       .append(Utils.getClassReferenceName(aClass))
-                       .append(";\n");
-
-        // Add startup code to populate it..
-        wrapperStartupCode.append(Utils.getStartupLineForClass(aClass));
-
-        seenClasses.add(className);
-    }
-
-    /**
-     * Writes code for getting the JNIEnv instance.
-     */
-    private void writeFunctionStartupBoilerPlate(String methodSignature, boolean aIsThreaded) {
-        // The start-of-function boilerplate. Does the bridge exist? Does the env exist? etc.
-        wrapperMethodBodies.append('\n')
-                           .append(methodSignature)
-                           .append(" {\n");
-
-        wrapperMethodBodies.append("    JNIEnv *env = ");
-        if (!aIsThreaded) {
-            wrapperMethodBodies.append("AndroidBridge::GetJNIEnv();\n");
-        } else {
-            wrapperMethodBodies.append("GetJNIForThread();\n");
-        }
-    }
-
-    /**
-     * Write out the appropriate JNI frame pushing boilerplate for a call to the member provided (
-     * which must be a constructor or method).
-     *
-     * @param aMethod A constructor/method being wrapped.
-     * @param aIsObjectReturningMethod Does the method being wrapped return an object?
-     */
-    private void writeFramePushBoilerplate(Member aMethod,
-            boolean aIsObjectReturningMethod, boolean aNoThrow) {
-        if (aMethod instanceof Field) {
-            throw new IllegalArgumentException("Tried to push frame for a FIELD?!");
-        }
-
-        Method m;
-        Constructor<?> c;
-
-        Class<?> returnType;
-
-        int localReferencesNeeded;
-        if (aMethod instanceof Method) {
-            m = (Method) aMethod;
-            returnType = m.getReturnType();
-            localReferencesNeeded = Utils.enumerateReferenceArguments(m.getParameterTypes());
-        } else {
-            c = (Constructor<?>) aMethod;
-            returnType = Void.class;
-            localReferencesNeeded = Utils.enumerateReferenceArguments(c.getParameterTypes());
-        }
-
-        // Determine the number of local refs required for our local frame..
-        // AutoLocalJNIFrame is not applicable here due to it's inability to handle return values.
-        if (aIsObjectReturningMethod) {
-            localReferencesNeeded++;
-        }
-        wrapperMethodBodies.append(
-                "    if (env->PushLocalFrame(").append(localReferencesNeeded).append(") != 0) {\n");
-        if (!aNoThrow) {
-            wrapperMethodBodies.append(
-                "        AndroidBridge::HandleUncaughtException(env);\n" +
-                "        MOZ_CRASH(\"Exception should have caused crash.\");\n");
-        } else {
-            wrapperMethodBodies.append(
-                "        return").append(Utils.getFailureReturnForType(returnType)).append(";\n");
-        }
-        wrapperMethodBodies.append(
-                "    }\n\n");
-    }
-
-    private StringBuilder getArgumentMarshalling(Class<?>[] argumentTypes) {
-        StringBuilder argumentContent = new StringBuilder();
-
-        // If we have >2 arguments, use the jvalue[] calling approach.
-        argumentContent.append(", ");
-        if (argumentTypes.length > 2) {
-            wrapperMethodBodies.append("    jvalue args[").append(argumentTypes.length).append("];\n");
-            for (int aT = 0; aT < argumentTypes.length; aT++) {
-                wrapperMethodBodies.append("    args[").append(aT).append("].")
-                                   .append(Utils.getArrayArgumentMashallingLine(argumentTypes[aT], "a" + aT));
-            }
-
-            // The only argument is the array of arguments.
-            argumentContent.append("args");
-            wrapperMethodBodies.append('\n');
-        } else {
-            // Otherwise, use the vanilla calling approach.
-            boolean needsNewline = false;
-            for (int aT = 0; aT < argumentTypes.length; aT++) {
-                // If the argument is a string-esque type, create a jstring from it, otherwise
-                // it can be passed directly.
-                if (Utils.isCharSequence(argumentTypes[aT])) {
-                    wrapperMethodBodies.append("    jstring j").append(aT).append(" = AndroidBridge::NewJavaString(env, a").append(aT).append(");\n");
-                    needsNewline = true;
-                    // Ensure we refer to the newly constructed Java string - not to the original
-                    // parameter to the wrapper function.
-                    argumentContent.append('j').append(aT);
-                } else {
-                    argumentContent.append('a').append(aT);
-                }
-                if (aT != argumentTypes.length - 1) {
-                    argumentContent.append(", ");
-                }
-            }
-            if (needsNewline) {
-                wrapperMethodBodies.append('\n');
+                throw new IllegalArgumentException(
+                        "expected member to be Constructor, Method, or Field");
             }
         }
-
-        return argumentContent;
-    }
-
-    private void writeCatchException() {
-        wrapperMethodBodies.append(
-            "    if (env->ExceptionCheck()) {\n" +
-            "        env->ExceptionClear();\n" +
-            "        if (aResult) {\n" +
-            "            *aResult = NS_ERROR_FAILURE;\n" +
-            "        }\n" +
-            "    } else if (aResult) {\n" +
-            "        *aResult = NS_OK;\n" +
-            "    }\n\n");
-    }
-
-    private void writeCtorBody(String implementationSignature, Constructor<?> theCtor,
-            boolean aIsThreaded, boolean aNoThrow, boolean aCatchException) {
-        Class<?>[] argumentTypes = theCtor.getParameterTypes();
-
-        writeFunctionStartupBoilerPlate(implementationSignature, aIsThreaded);
-
-        writeFramePushBoilerplate(theCtor, false, aNoThrow);
-
-        if (mLazyInit) {
-            writeMemberInit(theCtor, wrapperMethodBodies);
-        }
-
-        // Marshall arguments for this constructor, if any...
-        boolean hasArguments = argumentTypes.length != 0;
-
-        StringBuilder argumentContent = new StringBuilder();
-        if (hasArguments) {
-            argumentContent = getArgumentMarshalling(argumentTypes);
-        }
-
-        // The call into Java
-        wrapperMethodBodies.append("    Init(env->NewObject");
-        if (argumentTypes.length > 2) {
-            wrapperMethodBodies.append('A');
-        }
-
-        wrapperMethodBodies.append('(');
-
-
-        // Call takes class id, method id of constructor method, then arguments.
-        wrapperMethodBodies.append(Utils.getClassReferenceName(mClassToWrap)).append(", ");
-
-        wrapperMethodBodies.append(mMembersToIds.get(theCtor))
-        // Tack on the arguments, if any..
-                           .append(argumentContent)
-                           .append("), env);\n");
-
-        // Check for exception and set aResult
-        if (aCatchException) {
-            writeCatchException();
-        }
-
-        wrapperMethodBodies.append("    env->PopLocalFrame(nullptr);\n}\n");
-    }
-
-    /**
-     * Generates the method body of the C++ wrapper function for the Java method indicated.
-     *
-     * @param methodSignature The previously-generated C++ method signature for the method to be
-     *                        generated.
-     * @param aMethod         The Java method to be wrapped by the C++ method being generated.
-     * @param aClass          The Java class to which the method belongs.
-     */
-    private void writeMethodBody(String methodSignature, Method aMethod,
-                                 Class<?> aClass, boolean aIsMultithreaded,
-                                 boolean aNoThrow, boolean aNarrowChars,
-                                 boolean aCatchException) {
-        Class<?>[] argumentTypes = aMethod.getParameterTypes();
-        Class<?> returnType = aMethod.getReturnType();
-
-        writeFunctionStartupBoilerPlate(methodSignature, aIsMultithreaded);
-
-        boolean isObjectReturningMethod = !returnType.getCanonicalName().equals("void") && Utils.isObjectType(returnType);
-
-        writeFramePushBoilerplate(aMethod, isObjectReturningMethod, aNoThrow);
-
-        if (mLazyInit) {
-            writeMemberInit(aMethod, wrapperMethodBodies);
-        }
-
-        // Marshall arguments, if we have any.
-        boolean hasArguments = argumentTypes.length != 0;
-
-        // We buffer the arguments to the call separately to avoid needing to repeatedly iterate the
-        // argument list while building this line. In the coming code block, we simultaneously
-        // construct any argument marshalling code (Creation of jstrings, placement of arguments
-        // into an argument array, etc. and the actual argument list passed to the function (in
-        // argumentContent).
-        StringBuilder argumentContent = new StringBuilder();
-        if (hasArguments) {
-            argumentContent = getArgumentMarshalling(argumentTypes);
-        }
-
-        // Allocate a temporary variable to hold the return type from Java.
-        wrapperMethodBodies.append("    ");
-        if (!returnType.getCanonicalName().equals("void")) {
-            if (isObjectReturningMethod) {
-                wrapperMethodBodies.append("jobject");
-            } else {
-                wrapperMethodBodies.append(Utils.getCReturnType(returnType, aNarrowChars));
-            }
-            wrapperMethodBodies.append(" temp = ");
-        }
-
-        boolean isStaticJavaMethod = Utils.isMemberStatic(aMethod);
-
-        // The call into Java
-        wrapperMethodBodies.append("env->")
-                           .append(Utils.getCallPrefix(returnType, isStaticJavaMethod));
-        if (argumentTypes.length > 2) {
-            wrapperMethodBodies.append('A');
-        }
-
-        wrapperMethodBodies.append('(');
-        // If the underlying Java method is nonstatic, we provide the target object to the JNI.
-        if (!isStaticJavaMethod) {
-            wrapperMethodBodies.append("wrapped_obj, ");
-        } else {
-            // If this is a static underlying Java method, we need to use the class reference in our
-            // call.
-            wrapperMethodBodies.append(Utils.getClassReferenceName(aClass)).append(", ");
-        }
-
-        wrapperMethodBodies.append(mMembersToIds.get(aMethod));
-
-        // Tack on the arguments, if any..
-        wrapperMethodBodies.append(argumentContent)
-                           .append(");\n");
-
-        // Check for exception and crash if any...
-        if (!aNoThrow) {
-            wrapperMethodBodies.append("    AndroidBridge::HandleUncaughtException(env);\n");
-        }
-
-        // Check for exception and set aResult
-        if (aCatchException) {
-            writeCatchException();
-        }
-
-        // If we're returning an object, pop the callee's stack frame extracting our ref as the return
-        // value.
-        if (isObjectReturningMethod) {
-            wrapperMethodBodies.append("    ")
-                               .append(Utils.getCReturnType(returnType, aNarrowChars))
-                               .append(" ret = static_cast<").append(Utils.getCReturnType(returnType, aNarrowChars)).append(">(env->PopLocalFrame(temp));\n" +
-                                       "    return ret;\n");
-        } else if (!returnType.getCanonicalName().equals("void")) {
-            // If we're a primitive-returning function, just return the directly-obtained primative
-            // from the call to Java.
-            wrapperMethodBodies.append("    env->PopLocalFrame(nullptr);\n" +
-                                       "    return temp;\n");
-        } else {
-            // If we don't return anything, just pop the stack frame and move on with life.
-            wrapperMethodBodies.append("    env->PopLocalFrame(nullptr);\n");
-        }
-        wrapperMethodBodies.append("}\n");
-    }
-
-    /**
-     * Generates the code to get the id of the given member on startup or in the member body if lazy init
-     * is requested.
-     *
-     * @param aMember         The Java member being wrapped.
-     */
-    private void writeMemberInit(Member aMember, StringBuilder aOutput) {
-        if (mLazyInit) {
-            aOutput.append("    if (!" + mMembersToIds.get(aMember) + ") {\n    ");
-        }
-
-        aOutput.append("    " + mMembersToIds.get(aMember)).append(" = AndroidBridge::Get");
-        if (Utils.isMemberStatic(aMember)) {
-            aOutput.append("Static");
-        }
-
-        boolean isField = aMember instanceof Field;
-        if (isField) {
-            aOutput.append("FieldID(env, " + Utils.getClassReferenceName(aMember.getDeclaringClass()) + ", \"");
-        } else {
-            aOutput.append("MethodID(env, " + Utils.getClassReferenceName(aMember.getDeclaringClass()) + ", \"");
-        }
-
-        if (aMember instanceof Constructor) {
-            aOutput.append("<init>");
-        } else {
-            aOutput.append(aMember.getName());
-        }
-
-        aOutput.append("\", \"")
-                          .append(Utils.getTypeSignatureStringForMember(aMember))
-                          .append("\");\n");
-
-        if (mLazyInit) {
-            aOutput.append("    }\n\n");
-        }
-    }
-
-    private void writeZeroingFor(Member aMember, final String aMemberName) {
-        if (aMember instanceof Field) {
-            zeroingCode.append("jfieldID ");
-        } else {
-            zeroingCode.append("jmethodID ");
-        }
-        zeroingCode.append(mCClassName)
-                   .append("::")
-                   .append(aMemberName)
-                   .append(" = 0;\n");
-    }
-
-    /**
-     * Write the field declaration for the C++ id field of the given member.
-     *
-     * @param aMember Member for which an id field needs to be generated.
-     */
-    private void writeMemberIdField(Member aMember, final String aCMethodName) {
-        String memberName = 'j'+ aCMethodName;
-
-        if (aMember instanceof Field) {
-            headerProtected.append("    static jfieldID ");
-        } else {
-            headerProtected.append("    static jmethodID ");
-        }
-
-        while(mTakenMemberNames.contains(memberName)) {
-            memberName = 'j' + aCMethodName + mNameMunger;
-            mNameMunger++;
-        }
-
-        writeZeroingFor(aMember, memberName);
-        mMembersToIds.put(aMember, memberName);
-        mTakenMemberNames.add(memberName);
-
-        headerProtected.append(memberName)
-                       .append(";\n");
-    }
-
-    /**
-     * Helper function to add a provided method signature to the public section of the generated header.
-     *
-     * @param aSignature The header to add.
-     */
-    private void writeSignatureToHeader(String aSignature) {
-        headerPublic.append("    ")
-                    .append(aSignature)
-                    .append(";\n");
     }
 
     /**
      * Get the finalised bytes to go into the generated wrappers file.
      *
      * @return The bytes to be written to the wrappers file.
      */
     public String getWrapperFileContents() {
-        wrapperStartupCode.append("}\n");
-        zeroingCode.append(wrapperStartupCode)
-                   .append(wrapperMethodBodies);
-        wrapperMethodBodies.setLength(0);
-        wrapperStartupCode.setLength(0);
-        return zeroingCode.toString();
+        return cpp.toString();
     }
 
     /**
      * Get the finalised bytes to go into the generated header file.
      *
      * @return The bytes to be written to the header file.
      */
     public String getHeaderFileContents() {
-        if (!mHasEncounteredDefaultConstructor) {
-            headerPublic.append("    ").append(mCClassName).append("() : AutoGlobalWrappedJavaObject() {};\n");
-        }
-        headerProtected.append("};\n\n");
-        headerPublic.append(headerProtected);
-        headerProtected.setLength(0);
-        return headerPublic.toString();
+        header.append(
+                "};\n" +
+                "\n");
+        return header.toString();
     }
 }
--- a/build/annotationProcessors/SDKProcessor.java
+++ b/build/annotationProcessors/SDKProcessor.java
@@ -31,19 +31,21 @@ import java.lang.reflect.Constructor;
 import java.lang.reflect.Field;
 import java.lang.reflect.Member;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 
 public class SDKProcessor {
     public static final String GENERATED_COMMENT =
             "// GENERATED CODE\n" +
-            "// Generated by the Java program at /build/annotationProcessors at compile time from\n" +
-            "// annotations on Java methods. To update, change the annotations on the corresponding Java\n" +
-            "// methods and rerun the build. Manually updating this file will cause your build to fail.\n\n";
+            "// Generated by the Java program at /build/annotationProcessors at compile time\n" +
+            "// from annotations on Java methods. To update, change the annotations on the\n" +
+            "// corresponding Javamethods and rerun the build. Manually updating this file\n" +
+            "// will cause your build to fail.\n" +
+            "\n";
 
     private static ApiLookup sApiLookup;
     private static int sMaxSdkVersion;
 
     public static void main(String[] args) throws Exception {
         // We expect a list of jars on the commandline. If missing, whinge about it.
         if (args.length < 5) {
             System.err.println("Usage: java SDKProcessor sdkjar classlistfile outdir fileprefix max-sdk-version");
@@ -63,74 +65,65 @@ public class SDKProcessor {
 
         // Start the clock!
         long s = System.currentTimeMillis();
 
         // Get an iterator over the classes in the jar files given...
         // Iterator<ClassWithOptions> jarClassIterator = IterableJarLoadingURLClassLoader.getIteratorOverJars(args);
 
         StringBuilder headerFile = new StringBuilder(GENERATED_COMMENT);
-        headerFile.append("#ifndef " + generatedFilePrefix + "_h__\n" +
-                          "#define " + generatedFilePrefix + "_h__\n" +
-                          "#include \"nsXPCOMStrings.h\"\n" +
-                          "#include \"AndroidJavaWrappers.h\"\n" +
-                          "\n" +
-                          "namespace mozilla {\n" +
-                          "namespace widget {\n" +
-                          "namespace android {\n" +
-                          "namespace sdk {\n" +
-                          "void Init" + generatedFilePrefix + "Stubs(JNIEnv *jEnv);\n\n");
+        headerFile.append(
+                "#ifndef " + generatedFilePrefix + "_h__\n" +
+                "#define " + generatedFilePrefix + "_h__\n" +
+                "\n" +
+                "#include \"mozilla/jni/Refs.h\"\n" +
+                "\n" +
+                "namespace mozilla {\n" +
+                "namespace widget {\n" +
+                "namespace sdk {\n" +
+                "\n");
 
         StringBuilder implementationFile = new StringBuilder(GENERATED_COMMENT);
-        implementationFile.append("#include \"" + generatedFilePrefix + ".h\"\n" +
-                                  "#include \"AndroidBridgeUtilities.h\"\n" +
-                                  "#include \"nsXPCOMStrings.h\"\n" +
-                                  "#include \"AndroidBridge.h\"\n" +
-                                  "\n" +
-                                  "namespace mozilla {\n" +
-                                  "namespace widget {\n" +
-                                  "namespace android {\n" +
-                                  "namespace sdk {\n");
+        implementationFile.append(
+                "#include \"" + generatedFilePrefix + ".h\"\n" +
+                "#include \"mozilla/jni/Accessors.h\"\n" +
+                "\n" +
+                "namespace mozilla {\n" +
+                "namespace widget {\n" +
+                "namespace sdk {\n" +
+                "\n");
 
         // Used to track the calls to the various class-specific initialisation functions.
-        StringBuilder stubInitializer = new StringBuilder();
-        stubInitializer.append("void Init" + generatedFilePrefix + "Stubs(JNIEnv *jEnv) {\n");
-
         ClassLoader loader = null;
         try {
             loader = URLClassLoader.newInstance(new URL[] { new URL("file://" + sdkJar) },
                                                 SDKProcessor.class.getClassLoader());
         } catch (Exception e) {
-            System.out.println(e);
+            throw new RuntimeException(e.toString());
         }
 
         for (Iterator<String> i = classes.iterator(); i.hasNext(); ) {
             String className = i.next();
             System.out.println("Looking up: " + className);
 
             generateClass(Class.forName(className, true, loader),
-                          stubInitializer,
                           implementationFile,
                           headerFile);
         }
 
-        implementationFile.append('\n');
-        stubInitializer.append("}");
-        implementationFile.append(stubInitializer);
+        implementationFile.append(
+                "} /* sdk */\n" +
+                "} /* widget */\n" +
+                "} /* mozilla */\n");
 
-        implementationFile.append("\n} /* sdk */\n" +
-                                    "} /* android */\n" +
-                                    "} /* widget */\n" +
-                                    "} /* mozilla */\n");
-
-        headerFile.append("\n} /* sdk */\n" +
-                            "} /* android */\n" +
-                            "} /* widget */\n" +
-                            "} /* mozilla */\n" +
-                            "#endif\n");
+        headerFile.append(
+                "} /* sdk */\n" +
+                "} /* widget */\n" +
+                "} /* mozilla */\n" +
+                "#endif\n");
 
         writeOutputFiles(outdir, generatedFilePrefix, headerFile, implementationFile);
         long e = System.currentTimeMillis();
         System.out.println("SDK processing complete in " + (e - s) + "ms");
     }
 
     private static Member[] sortAndFilterMembers(Member[] members) {
         Arrays.sort(members, new Comparator<Member>() {
@@ -140,22 +133,23 @@ public class SDKProcessor {
             }
         });
 
         ArrayList<Member> list = new ArrayList<>();
         for (Member m : members) {
             int version = 0;
 
             if (m instanceof Method || m instanceof Constructor) {
-                version = sApiLookup.getCallVersion(Utils.getTypeSignatureStringForClass(m.getDeclaringClass()),
-                                                    m.getName(),
-                                                    Utils.getTypeSignatureStringForMember(m));
+                version = sApiLookup.getCallVersion(
+                        Utils.getClassDescriptor(m.getDeclaringClass()),
+                        m.getName(),
+                        Utils.getSignature(m));
             } else if (m instanceof Field) {
-                version = sApiLookup.getFieldVersion(Utils.getTypeSignatureStringForClass(m.getDeclaringClass()),
-                                                     m.getName());
+                version = sApiLookup.getFieldVersion(
+                        Utils.getClassDescriptor(m.getDeclaringClass()), m.getName());
             } else {
                 throw new IllegalArgumentException("expected member to be Method, Constructor, or Field");
             }
 
             if (version > sMaxSdkVersion) {
                 System.out.println("Skipping " + m.getDeclaringClass().getName() + "." + m.getName() +
                     ", version " + version + " > " + sMaxSdkVersion);
                 continue;
@@ -163,23 +157,21 @@ public class SDKProcessor {
 
             list.add(m);
         }
 
         return list.toArray(new Member[list.size()]);
     }
 
     private static void generateClass(Class<?> clazz,
-                                      StringBuilder stubInitializer,
                                       StringBuilder implementationFile,
                                       StringBuilder headerFile) {
         String generatedName = clazz.getSimpleName();
 
-        CodeGenerator generator = new CodeGenerator(clazz, generatedName, true);
-        stubInitializer.append("    ").append(generatedName).append("::InitStubs(jEnv);\n");
+        CodeGenerator generator = new CodeGenerator(new ClassWithOptions(clazz, generatedName));
 
         generator.generateMembers(sortAndFilterMembers(clazz.getDeclaredConstructors()));
         generator.generateMembers(sortAndFilterMembers(clazz.getDeclaredMethods()));
         generator.generateMembers(sortAndFilterMembers(clazz.getDeclaredFields()));
 
         headerFile.append(generator.getHeaderFileContents());
         implementationFile.append(generator.getWrapperFileContents());
     }
--- a/build/annotationProcessors/utils/AlphabeticAnnotatableEntityComparator.java
+++ b/build/annotationProcessors/utils/AlphabeticAnnotatableEntityComparator.java
@@ -52,26 +52,26 @@ public class AlphabeticAnnotatableEntity
         String rName = aRhs.getName();
 
         int ret = lName.compareTo(rName);
         if (ret != 0) {
             return ret;
         }
 
         // The names were the same, so we need to compare signatures to find their uniqueness..
-        lName = Utils.getTypeSignatureStringForMethod(aLhs);
-        rName = Utils.getTypeSignatureStringForMethod(aRhs);
+        lName = Utils.getSignature(aLhs);
+        rName = Utils.getSignature(aRhs);
 
         return lName.compareTo(rName);
     }
 
     private static int compare(Constructor<?> aLhs, Constructor<?> aRhs) {
         // The names will be the same, so we need to compare signatures to find their uniqueness..
-        String lName = Utils.getTypeSignatureString(aLhs);
-        String rName = Utils.getTypeSignatureString(aRhs);
+        String lName = Utils.getSignature(aLhs);
+        String rName = Utils.getSignature(aRhs);
 
         return lName.compareTo(rName);
     }
 
     private static int compare(Field aLhs, Field aRhs) {
         // Compare field names..
         String lName = aLhs.getName();
         String rName = aRhs.getName();
--- a/build/annotationProcessors/utils/GeneratableElementIterator.java
+++ b/build/annotationProcessors/utils/GeneratableElementIterator.java
@@ -114,32 +114,35 @@ public class GeneratableElementIterator 
                     } catch (InvocationTargetException e) {
                         System.err.println("InvocationTargetException reading fields on WrapElementForJNI annotation. This really shouldn't happen.");
                         e.printStackTrace(System.err);
                         System.exit(5);
                     }
 
                     // If the method name was not explicitly given in the annotation generate one...
                     if (stubName.isEmpty()) {
-                        String aMethodName = candidateElement.getName();
-                        stubName = aMethodName.substring(0, 1).toUpperCase() + aMethodName.substring(1);
+                        stubName = Utils.getNativeName(candidateElement);
                     }
 
                     AnnotationInfo annotationInfo = new AnnotationInfo(
                         stubName, isMultithreadedStub, noThrow, narrowChars, catchException);
                     mNextReturnValue = new AnnotatableEntity(candidateElement, annotationInfo);
                     return;
                 }
             }
 
-            // If no annotation found, we might be expected to generate anyway using default arguments,
-            // thanks to the "Generate everything" annotation.
+            // If no annotation found, we might be expected to generate anyway
+            // using default arguments, thanks to the "Generate everything" annotation.
             if (mIterateEveryEntry) {
                 AnnotationInfo annotationInfo = new AnnotationInfo(
-                    candidateElement.getName(), false, false, false, false);
+                    Utils.getNativeName(candidateElement),
+                    /* multithreaded */ true,
+                    /* noThrow */ false,
+                    /* narrowChars */ false,
+                    /* catchException */ false);
                 mNextReturnValue = new AnnotatableEntity(candidateElement, annotationInfo);
                 return;
             }
         }
         mNextReturnValue = null;
     }
 
     @Override
--- a/build/annotationProcessors/utils/Utils.java
+++ b/build/annotationProcessors/utils/Utils.java
@@ -1,664 +1,247 @@
 /* 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.annotationProcessors.utils;
 
-import java.lang.annotation.Annotation;
+import org.mozilla.gecko.annotationProcessors.AnnotationInfo;
+
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Field;
 import java.lang.reflect.Member;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 import java.util.HashMap;
 
 /**
  * A collection of utility methods used by CodeGenerator. Largely used for translating types.
  */
 public class Utils {
 
     // A collection of lookup tables to simplify the functions to follow...
-    private static final HashMap<String, String> sBasicCTypes = new HashMap<String, String>();
-
-    static {
-        sBasicCTypes.put("void", "void");
-        sBasicCTypes.put("int", "int32_t");
-        sBasicCTypes.put("boolean", "bool");
-        sBasicCTypes.put("long", "int64_t");
-        sBasicCTypes.put("double", "jdouble");
-        sBasicCTypes.put("float", "jfloat");
-        sBasicCTypes.put("char", "uint16_t");
-        sBasicCTypes.put("byte", "int8_t");
-        sBasicCTypes.put("short", "int16_t");
-    }
-
-    private static final HashMap<String, String> sArrayCTypes = new HashMap<String, String>();
+    private static final HashMap<String, String> NATIVE_TYPES = new HashMap<String, String>();
 
     static {
-        sArrayCTypes.put("int", "jintArray");
-        sArrayCTypes.put("boolean", "jbooleanArray");
-        sArrayCTypes.put("long", "jlongArray");
-        sArrayCTypes.put("double", "jdoubleArray");
-        sArrayCTypes.put("float", "jfloatArray");
-        sArrayCTypes.put("char", "jcharArray");
-        sArrayCTypes.put("byte", "jbyteArray");
-        sArrayCTypes.put("short", "jshortArray");
-    }
-
-    private static final HashMap<String, String> sStaticCallTypes = new HashMap<String, String>();
-
-    static {
-        sStaticCallTypes.put("void", "CallStaticVoidMethod");
-        sStaticCallTypes.put("int", "CallStaticIntMethod");
-        sStaticCallTypes.put("boolean", "CallStaticBooleanMethod");
-        sStaticCallTypes.put("long", "CallStaticLongMethod");
-        sStaticCallTypes.put("double", "CallStaticDoubleMethod");
-        sStaticCallTypes.put("float", "CallStaticFloatMethod");
-        sStaticCallTypes.put("char", "CallStaticCharMethod");
-        sStaticCallTypes.put("byte", "CallStaticByteMethod");
-        sStaticCallTypes.put("short", "CallStaticShortMethod");
-    }
-
-    private static final HashMap<String, String> sInstanceCallTypes = new HashMap<String, String>();
-
-    static {
-        sInstanceCallTypes.put("void", "CallVoidMethod");
-        sInstanceCallTypes.put("int", "CallIntMethod");
-        sInstanceCallTypes.put("boolean", "CallBooleanMethod");
-        sInstanceCallTypes.put("long", "CallLongMethod");
-        sInstanceCallTypes.put("double", "CallDoubleMethod");
-        sInstanceCallTypes.put("float", "CallFloatMethod");
-        sInstanceCallTypes.put("char", "CallCharMethod");
-        sInstanceCallTypes.put("byte", "CallByteMethod");
-        sInstanceCallTypes.put("short", "CallShortMethod");
+        NATIVE_TYPES.put("void", "void");
+        NATIVE_TYPES.put("boolean", "bool");
+        NATIVE_TYPES.put("byte", "int8_t");
+        NATIVE_TYPES.put("char", "char16_t");
+        NATIVE_TYPES.put("short", "int16_t");
+        NATIVE_TYPES.put("int", "int32_t");
+        NATIVE_TYPES.put("long", "int64_t");
+        NATIVE_TYPES.put("float", "float");
+        NATIVE_TYPES.put("double", "double");
     }
 
-    private static final HashMap<String, String> sFieldTypes = new HashMap<String, String>();
+    private static final HashMap<String, String> NATIVE_ARRAY_TYPES = new HashMap<String, String>();
 
     static {
-        sFieldTypes.put("int", "Int");
-        sFieldTypes.put("boolean", "Boolean");
-        sFieldTypes.put("long", "Long");
-        sFieldTypes.put("double", "Double");
-        sFieldTypes.put("float", "Float");
-        sFieldTypes.put("char", "Char");
-        sFieldTypes.put("byte", "Byte");
-        sFieldTypes.put("short", "Short");
-    }
-
-    private static final HashMap<String, String> sFailureReturns = new HashMap<String, String>();
-
-    static {
-        sFailureReturns.put("java.lang.Void", "");
-        sFailureReturns.put("void", "");
-        sFailureReturns.put("int", " 0");
-        sFailureReturns.put("boolean", " false");
-        sFailureReturns.put("long", " 0");
-        sFailureReturns.put("double", " 0.0");
-        sFailureReturns.put("float", " 0.0");
-        sFailureReturns.put("char", " 0");
-        sFailureReturns.put("byte", " 0");
-        sFailureReturns.put("short", " 0");
+        NATIVE_ARRAY_TYPES.put("boolean", "mozilla::jni::BooleanArray");
+        NATIVE_ARRAY_TYPES.put("byte", "mozilla::jni::ByteArray");
+        NATIVE_ARRAY_TYPES.put("char", "mozilla::jni::CharArray");
+        NATIVE_ARRAY_TYPES.put("short", "mozilla::jni::ShortArray");
+        NATIVE_ARRAY_TYPES.put("int", "mozilla::jni::IntArray");
+        NATIVE_ARRAY_TYPES.put("long", "mozilla::jni::LongArray");
+        NATIVE_ARRAY_TYPES.put("float", "mozilla::jni::FloatArray");
+        NATIVE_ARRAY_TYPES.put("double", "mozilla::jni::DoubleArray");
     }
 
-    private static final HashMap<String, String> sCanonicalSignatureParts = new HashMap<String, String>();
+    private static final HashMap<String, String> CLASS_DESCRIPTORS = new HashMap<String, String>();
 
     static {
-        sCanonicalSignatureParts.put("java/lang/Void", "V");
-        sCanonicalSignatureParts.put("void", "V");
-        sCanonicalSignatureParts.put("int", "I");
-        sCanonicalSignatureParts.put("boolean", "Z");
-        sCanonicalSignatureParts.put("long", "J");
-        sCanonicalSignatureParts.put("double", "D");
-        sCanonicalSignatureParts.put("float", "F");
-        sCanonicalSignatureParts.put("char", "C");
-        sCanonicalSignatureParts.put("byte", "B");
-        sCanonicalSignatureParts.put("short", "S");
-    }
-
-
-    private static final HashMap<String, String> sDefaultParameterValues = new HashMap<String, String>();
-
-    static {
-        sDefaultParameterValues.put("int", "0");
-        sDefaultParameterValues.put("boolean", "false");
-        sDefaultParameterValues.put("long", "0");
-        sDefaultParameterValues.put("double", "0");
-        sDefaultParameterValues.put("float", "0.0");
-        sDefaultParameterValues.put("char", "0");
-        sDefaultParameterValues.put("byte", "0");
-        sDefaultParameterValues.put("short", "0");
+        CLASS_DESCRIPTORS.put("void", "V");
+        CLASS_DESCRIPTORS.put("boolean", "Z");
+        CLASS_DESCRIPTORS.put("byte", "B");
+        CLASS_DESCRIPTORS.put("char", "C");
+        CLASS_DESCRIPTORS.put("short", "S");
+        CLASS_DESCRIPTORS.put("int", "I");
+        CLASS_DESCRIPTORS.put("long", "J");
+        CLASS_DESCRIPTORS.put("float", "F");
+        CLASS_DESCRIPTORS.put("double", "D");
     }
 
     /**
-     * Get the C type corresponding to the provided type parameter. Used for generating argument
-     * types for the wrapper method.
+     * Get the C++ type corresponding to the provided type parameter.
      *
      * @param type Class to determine the corresponding JNI type for.
-     * @return true if the type an object type, false otherwise.
+     * @return C++ type as a String
      */
-    public static String getCParameterType(Class<?> type, boolean aNarrowChars) {
-        String name = type.getCanonicalName();
-        if (sBasicCTypes.containsKey(name)) {
-            return sBasicCTypes.get(name);
-        }
-        // Are we dealing with an array type?
-        int len = name.length();
-        if (name.endsWith("[]")) {
-            // Determine if it is a 2D array - these map to jobjectArrays
-            name = name.substring(0, len - 2);
-            if (name.endsWith("[]")) {
-                return "jobjectArray";
-            } else {
-                // Which flavour of Array is it?
-                if (sArrayCTypes.containsKey(name)) {
-                    return sArrayCTypes.get(name);
-                }
-                return "jobjectArray";
-            }
-        }
-        // Not an array type, check the remaining possibilities before we fall back to jobject
+    public static String getNativeParameterType(Class<?> type, AnnotationInfo info) {
+        final String name = type.getName().replace('.', '/');
 
-        // Check for CharSequences (Strings and things that are string-like)
-        if (isCharSequence(type)) {
-            if (aNarrowChars) {
-                return "const nsACString&";
-            }
-            return "const nsAString&";
+        if (NATIVE_TYPES.containsKey(name)) {
+            return NATIVE_TYPES.get(name);
         }
 
-        if (name.equals("java.lang.Class")) {
+        if (type.isArray()) {
+            final String compName = type.getComponentType().getName();
+            if (NATIVE_ARRAY_TYPES.containsKey(compName)) {
+                return NATIVE_ARRAY_TYPES.get(compName) + "::Param";
+            }
+            return "mozilla::jni::ObjectArray::Param";
+        }
+
+        if (type == String.class || type == CharSequence.class) {
+            return "mozilla::jni::String::Param";
+        }
+
+        if (type == Class.class) {
             // You're doing reflection on Java objects from inside C, returning Class objects
             // to C, generating the corresponding code using this Java program. Really?!
-            return "jclass";
-        }
-        if (name.equals("java.lang.Throwable")) {
-            return "jthrowable";
-        }
-        return "jobject";
-    }
-
-    /**
-     * For a given Java type, get the corresponding C++ type if we're returning it from a function.
-     *
-     * @param type The Java return type.
-     * @return A string representation of the C++ return type.
-     */
-     public static String getCReturnType(Class<?> type, boolean aNarrowChars) {
-        if (type.getCanonicalName().equals("java.lang.Void")) {
-            return "void";
+            return "mozilla::jni::ClassObject::Param";
         }
-        String cParameterType = getCParameterType(type, aNarrowChars);
-        if (cParameterType.equals("const nsAString&") || cParameterType.equals("const nsACString&")) {
-            return "jstring";
-        } else {
-            return cParameterType;
-        }
-    }
 
-    /**
-     * Gets the type-specific part of the  JNI function to use to get or set a field of a given type.
-     *
-     * @param aFieldType The Java type of the field.
-     * @return A string representation of the JNI call function substring to use.
-     */
-    public static String getFieldType(Class<?> aFieldType) {
-        String name = aFieldType.getCanonicalName();
+        if (type == Throwable.class) {
+            return "mozilla::jni::Throwable::Param";
+        }
 
-        if (sFieldTypes.containsKey(name)) {
-            return sFieldTypes.get(name);
-        }
-        return "Object";
+        return "mozilla::jni::Object::Param";
     }
 
-    /**
-     * Gets the appropriate JNI call function to use to invoke a Java method with the given return
-     * type. This, plus a call postfix (Such as "A") forms a complete JNI call function name.
-     *
-     * @param aReturnType The Java return type of the method being generated.
-     * @param isStatic Boolean indicating if the underlying Java method is declared static.
-     * @return A string representation of the JNI call function prefix to use.
-     */
-    public static String getCallPrefix(Class<?> aReturnType, boolean isStatic) {
-        String name = aReturnType.getCanonicalName();
-        if (isStatic) {
-            if (sStaticCallTypes.containsKey(name)) {
-                return sStaticCallTypes.get(name);
-            }
-            return "CallStaticObjectMethod";
-        } else {
-            if (sInstanceCallTypes.containsKey(name)) {
-                return sInstanceCallTypes.get(name);
-            }
-            return "CallObjectMethod";
-        }
-    }
+    public static String getNativeReturnType(Class<?> type, AnnotationInfo info) {
+        final String name = type.getName().replace('.', '/');
 
-    /**
-     * On failure, the generated method returns a null-esque value. This helper method gets the
-     * appropriate failure return value for a given Java return type, plus a leading space.
-     *
-     * @param type Java return type of method being generated
-     * @return String representation of the failure return value to be used in the generated code.
-     */
-    public static String getFailureReturnForType(Class<?> type) {
-        String name = type.getCanonicalName();
-        if (sFailureReturns.containsKey(name)) {
-            return sFailureReturns.get(name);
+        if (NATIVE_TYPES.containsKey(name)) {
+            return NATIVE_TYPES.get(name);
         }
-        return " nullptr";
-    }
-
-    /**
-     * Helper method to get the type signature for methods, given argument and return type.
-     * Allows for the near-identical logic needed for constructors and methods to be shared.
-     * (Alas, constructor does not extend method)
-     *
-     * @param arguments Argument types of the underlying method.
-     * @param returnType Return type of the underlying method.
-     * @return The canonical Java type string for the method. eg. (IIIIFZ)Lorg/mozilla/gecko/gfx/ViewTransform;
-     */
-    private static String getTypeSignatureInternal(Class<?>[] arguments, Class<?> returnType) {
-        StringBuilder sb = new StringBuilder();
-        sb.append('(');
-
-        // For each argument, write its signature component to the buffer..
-        for (int i = 0; i < arguments.length; i++) {
-            writeTypeSignature(sb, arguments[i]);
-        }
-        sb.append(')');
 
-        // Write the return value's signature..
-        writeTypeSignature(sb, returnType);
-        return sb.toString();
-    }
-
-    /**
-     * Get the canonical JNI type signature for a Field.
-     *
-     * @param aField The field to generate a signature for.
-     * @return The canonical JNI type signature for this method.
-     */
-    protected static String getTypeSignatureStringForField(Field aField) {
-        StringBuilder sb = new StringBuilder();
-        writeTypeSignature(sb, aField.getType());
-        return sb.toString();
-    }
-
-    /**
-     * Get the canonical JNI type signature for a method.
-     *
-     * @param aMethod The method to generate a signature for.
-     * @return The canonical JNI type signature for this method.
-     */
-    protected static String getTypeSignatureStringForMethod(Method aMethod) {
-        Class<?>[] arguments = aMethod.getParameterTypes();
-        Class<?> returnType = aMethod.getReturnType();
-        return getTypeSignatureInternal(arguments, returnType);
-    }
-
-    /**
-     * Get the canonical JNI type signature for a Constructor.
-     *
-     * @param aConstructor The Constructor to generate a signature for.
-     * @return The canonical JNI type signature for this method.
-     */
-    protected static String getTypeSignatureStringForConstructor(Constructor<?> aConstructor) {
-        Class<?>[] arguments = aConstructor.getParameterTypes();
-        return getTypeSignatureInternal(arguments, Void.class);
-    }
-
-    public static String getTypeSignatureStringForMember(Member aMember) {
-        if (aMember instanceof Method) {
-            return getTypeSignatureStringForMethod((Method) aMember);
-        } else if (aMember instanceof Field) {
-            return getTypeSignatureStringForField((Field) aMember);
-        } else {
-            return getTypeSignatureStringForConstructor((Constructor<?>) aMember);
-        }
-    }
-
-    public static String getTypeSignatureStringForClass(Class<?> clazz) {
-        return clazz.getCanonicalName().replace('.', '/');
-    }
-
-    public static String getTypeSignatureString(Constructor<?> aConstructor) {
-        Class<?>[] arguments = aConstructor.getParameterTypes();
-        StringBuilder sb = new StringBuilder();
-        sb.append('(');
-
-        // For each argument, write its signature component to the buffer..
-        for (int i = 0; i < arguments.length; i++) {
-            writeTypeSignature(sb, arguments[i]);
+        if (type.isArray()) {
+            final String compName = type.getComponentType().getName();
+            if (NATIVE_ARRAY_TYPES.containsKey(compName)) {
+                return NATIVE_ARRAY_TYPES.get(compName) + "::LocalRef";
+            }
+            return "mozilla::jni::ObjectArray::LocalRef";
         }
 
-        // Constructors always return Void.
-        sb.append(")V");
-        return sb.toString();
+        if (type == String.class) {
+            return "mozilla::jni::String::LocalRef";
+        }
+
+        if (type == Class.class) {
+            // You're doing reflection on Java objects from inside C, returning Class objects
+            // to C, generating the corresponding code using this Java program. Really?!
+            return "mozilla::jni::ClassObject::LocalRef";
+        }
+
+        if (type == Throwable.class) {
+            return "mozilla::jni::Throwable::LocalRef";
+        }
+
+        return "mozilla::jni::Object::LocalRef";
     }
 
     /**
-     * Helper method used by getTypeSignatureStringForMethod to build the signature. Write the subsignature
-     * of a given type into the buffer.
+     * Get the JNI class descriptor corresponding to the provided type parameter.
      *
-     * @param sb The buffer to write into.
-     * @param c  The type of the element to write the subsignature of.
+     * @param type Class to determine the corresponding JNI descriptor for.
+     * @return Class descripor as a String
      */
-    private static void writeTypeSignature(StringBuilder sb, Class<?> c) {
-        String name = Utils.getTypeSignatureStringForClass(c);
+    public static String getClassDescriptor(Class<?> type) {
+        final String name = type.getName().replace('.', '/');
 
-        // Determine if this is an array type and, if so, peel away the array operators..
-        int len = name.length();
-        while (name.endsWith("[]")) {
-            sb.append('[');
-            name = name.substring(0, len - 2);
-            len = len - 2;
+        if (CLASS_DESCRIPTORS.containsKey(name)) {
+            return CLASS_DESCRIPTORS.get(name);
         }
 
-        if (c.isArray()) {
-            c = c.getComponentType();
-        }
-
-        Class<?> containerClass = c.getDeclaringClass();
-        if (containerClass != null) {
-            // Is an inner class. Add the $ symbol.
-            final int lastSlash = name.lastIndexOf('/');
-            name = name.substring(0, lastSlash) + '$' + name.substring(lastSlash+1);
+        if (type.isArray()) {
+            // Array names are already in class descriptor form.
+            return name;
         }
 
-        // Look in the hashmap for the remainder...
-        if (sCanonicalSignatureParts.containsKey(name)) {
-            // It was a primitive type, so lookup was a success.
-            sb.append(sCanonicalSignatureParts.get(name));
-        } else {
-            // It was a reference type - generate.
-            sb.append('L');
-            sb.append(name);
-            sb.append(';');
-        }
+        return "L" + name + ';';
     }
 
     /**
-     * Produces a C method signature, sans semicolon, for the given Java Method. Useful for both
-     * generating header files and method bodies.
+     * Get the JNI signaure for a member.
      *
-     * @param aArgumentTypes Argument types of the Java method being wrapped.
-     * @param aReturnType Return type of the Java method being wrapped.
-     * @param aCMethodName Name of the method to generate in the C++ class.
-     * @param aCClassName Name of the C++ class into which the method is declared.
-     * @return The C++ method implementation signature for the method described.
+     * @param member Member to get the signature for.
+     * @return JNI signature as a string
      */
-    public static String getCImplementationMethodSignature(Class<?>[] aArgumentTypes, Class<?> aReturnType,
-        String aCMethodName, String aCClassName, boolean aNarrowChars, boolean aCatchException) {
-        StringBuilder retBuffer = new StringBuilder();
-
-        retBuffer.append(getCReturnType(aReturnType, aNarrowChars));
-        retBuffer.append(' ');
-        retBuffer.append(aCClassName);
-        retBuffer.append("::");
-        retBuffer.append(aCMethodName);
-        retBuffer.append('(');
-
-        // Write argument types...
-        for (int aT = 0; aT < aArgumentTypes.length; aT++) {
-            retBuffer.append(getCParameterType(aArgumentTypes[aT], aNarrowChars));
-            retBuffer.append(" a");
-            // We, imaginatively, call our arguments a1, a2, a3...
-            // The only way to preserve the names from Java would be to parse the
-            // Java source, which would be computationally hard.
-            retBuffer.append(aT);
-            if (aT != aArgumentTypes.length - 1) {
-                retBuffer.append(", ");
-            }
-        }
-
-        if (aCatchException) {
-            if (aArgumentTypes.length > 0) {
-                retBuffer.append(", ");
-            }
-            retBuffer.append("nsresult* aResult");
-        }
-
-        retBuffer.append(')');
-        return retBuffer.toString();
+    public static String getSignature(Member member) {
+        return member instanceof Field ?  getSignature((Field) member) :
+               member instanceof Method ? getSignature((Method) member) :
+                                          getSignature((Constructor<?>) member);
     }
 
     /**
-     * Produces a C method signature, sans semicolon, for the given Java Method. Useful for both
-     * generating header files and method bodies.
+     * Get the JNI signaure for a field.
      *
-     * @param aArgumentTypes Argument types of the Java method being wrapped.
-     * @param aArgumentAnnotations The annotations on the Java method arguments. Used to specify
-     *                             default values etc.
-     * @param aReturnType Return type of the Java method being wrapped.
-     * @param aCMethodName Name of the method to generate in the C++ class.
-     * @param aCClassName Name of the C++ class into which the method is declared.e
-     * @param aIsStaticStub true if the generated C++ method should be static, false otherwise.
-     * @return The generated C++ header method signature for the method described.
+     * @param member Field to get the signature for.
+     * @return JNI signature as a string
      */
-    public static String getCHeaderMethodSignature(Class<?>[] aArgumentTypes, Annotation[][] aArgumentAnnotations, Class<?> aReturnType,
-        String aCMethodName, String aCClassName, boolean aIsStaticStub, boolean aNarrowChars, boolean aCatchException) {
-        StringBuilder retBuffer = new StringBuilder();
-
-        // Add the static keyword, if applicable.
-        if (aIsStaticStub) {
-            retBuffer.append("static ");
-        }
-
-        // Write return type..
-        retBuffer.append(getCReturnType(aReturnType, aNarrowChars));
-        retBuffer.append(' ');
-        retBuffer.append(aCMethodName);
-        retBuffer.append('(');
+    public static String getSignature(Field member) {
+        return getClassDescriptor(member.getType());
+    }
 
-        // Write argument types...
-        for (int aT = 0; aT < aArgumentTypes.length; aT++) {
-            retBuffer.append(getCParameterType(aArgumentTypes[aT], aNarrowChars));
-            retBuffer.append(" a");
-            // We, imaginatively, call our arguments a1, a2, a3...
-            // The only way to preserve the names from Java would be to parse the
-            // Java source, which would be computationally hard.
-            retBuffer.append(aT);
-
-            // Append the default value, if there is one..
-            retBuffer.append(getDefaultValueString(aArgumentTypes[aT], aArgumentAnnotations[aT]));
-
-            if (aT != aArgumentTypes.length - 1) {
-                retBuffer.append(", ");
-            }
+    private static String getSignature(Class<?>[] args, Class<?> ret) {
+        final StringBuilder sig = new StringBuilder("(");
+        for (int i = 0; i < args.length; i++) {
+            sig.append(getClassDescriptor(args[i]));
         }
-
-        if (aCatchException) {
-            if (aArgumentTypes.length > 0) {
-                retBuffer.append(", ");
-            }
-            retBuffer.append("nsresult* aResult = nullptr");
-        }
-
-        retBuffer.append(')');
-        return retBuffer.toString();
+        return sig.append(')').append(getClassDescriptor(ret)).toString();
     }
 
     /**
-     * If the given Annotation[] contains an OptionalGeneratedParameter annotation then return a
-     * string assigning an argument of type aArgumentType to the default value for that type.
-     * Otherwise, return the empty string.
+     * Get the JNI signaure for a method.
      *
-     * @param aArgumentType        The type of the argument to consider.
-     * @param aArgumentAnnotations The annotations on the argument to consider.
-     * @return An appropriate string to append to the signature of this argument assigning it to a
-     *         default value (Or not, as applicable).
+     * @param member Method to get the signature for.
+     * @return JNI signature as a string
      */
-    public static String getDefaultValueString(Class<?> aArgumentType, Annotation[] aArgumentAnnotations) {
-        for (int i = 0; i < aArgumentAnnotations.length; i++) {
-            Class<? extends Annotation> annotationType = aArgumentAnnotations[i].annotationType();
-            final String annotationTypeName = annotationType.getName();
-            if (annotationTypeName.equals("org.mozilla.gecko.mozglue.generatorannotations.OptionalGeneratedParameter")) {
-                return " = " + getDefaultParameterValueForType(aArgumentType);
-            }
-        }
-        return "";
+    public static String getSignature(Method member) {
+        return getSignature(member.getParameterTypes(), member.getReturnType());
     }
 
     /**
-     * Helper method to return an appropriate default parameter value for an argument of a given type.
-     * The lookup table contains values for primitive types and strings. All other object types default
-     * to null pointers.
+     * Get the JNI signaure for a constructor.
      *
-     * @param aArgumentType The parameter type for which a default value is desired.
-     * @return An appropriate string representation of the default value selected, for use in generated
-     *         C++ code.
+     * @param member Constructor to get the signature for.
+     * @return JNI signature as a string
      */
-    private static String getDefaultParameterValueForType(Class<?> aArgumentType) {
-        String typeName = aArgumentType.getCanonicalName();
-        if (sDefaultParameterValues.containsKey(typeName)) {
-            return sDefaultParameterValues.get(typeName);
-        } else if (isCharSequence(aArgumentType)) {
-            return "EmptyString()";
-        } else {
-            return "nullptr";
-        }
+    public static String getSignature(Constructor<?> member) {
+        return getSignature(member.getParameterTypes(), void.class);
     }
 
     /**
-     * Helper method that returns the number of reference types in the arguments of m.
+     * Get the C++ name for a member.
      *
-     * @param aArgs The method arguments to consider.
-     * @return How many of the arguments of m are nonprimitive.
+     * @param member Member to get the name for.
+     * @return JNI name as a string
      */
-    public static int enumerateReferenceArguments(Class<?>[] aArgs) {
-        int ret = 0;
-        for (int i = 0; i < aArgs.length; i++) {
-            String name = aArgs[i].getCanonicalName();
-            if (!sBasicCTypes.containsKey(name)) {
-                ret++;
-            }
-        }
-        return ret;
-    }
-
-    /**
-     * Helper method that returns true iff the given method has a string argument.
-     *
-     * @param m The method to consider.
-     * @return True if the given method has a string argument, false otherwise.
-     */
-    public static boolean hasStringArgument(Method m) {
-        Class<?>[] args = m.getParameterTypes();
-        for (int i = 0; i < args.length; i++) {
-            if (isCharSequence(args[i])) {
-                return true;
-            }
-        }
-        return false;
+    public static String getNativeName(Member member) {
+        final String name = getMemberName(member);
+        return name.substring(0, 1).toUpperCase() + name.substring(1);
     }
 
     /**
-     * Write the argument array assignment line for the given argument type. Does not support array
-     * types.
+     * Get the JNI name for a member.
      *
-     * @param type    Type of this argument according to the target Java method's signature.
-     * @param argName Wrapper function argument name corresponding to this argument.
+     * @param member Member to get the name for.
+     * @return JNI name as a string
      */
-    public static String getArrayArgumentMashallingLine(Class<?> type, String argName) {
-        StringBuilder sb = new StringBuilder();
-
-        String name = type.getCanonicalName();
-        if (sCanonicalSignatureParts.containsKey(name)) {
-            sb.append(sCanonicalSignatureParts.get(name).toLowerCase());
-            sb.append(" = ").append(argName).append(";\n");
-        } else {
-            if (isCharSequence(type)) {
-                sb.append("l = AndroidBridge::NewJavaString(env, ").append(argName).append(");\n");
-            } else {
-                sb.append("l = ").append(argName).append(";\n");
-            }
+    public static String getMemberName(Member member) {
+        if (member instanceof Constructor) {
+            return "<init>";
         }
-
-        return sb.toString();
-    }
-
-    /**
-     * Returns true if the type provided is an object type. Returns false otherwise
-     *
-     * @param aType The type to consider.
-     * @return true if the method provided is an object type, false otherwise.
-     */
-    public static boolean isObjectType(Class<?> aType) {
-        return !sBasicCTypes.containsKey(aType.getCanonicalName());
-    }
-
-    /**
-     * For a given Java class, get the name of the value in C++ which holds a reference to it.
-     *
-     * @param aClass Target Java class.
-     * @return The name of the C++ jclass entity referencing the given class.
-     */
-    public static String getClassReferenceName(Class<?> aClass) {
-        String className = aClass.getSimpleName();
-        return 'm' + className + "Class";
+        return member.getName();
     }
 
     /**
-     * Generate a line to get a global reference to the Java class given.
+     * Determine if a member is declared static.
      *
-     * @param aClass The target Java class.
-     * @return The generated code to populate the reference to the class.
+     * @param member The Member to check.
+     * @return true if the member is declared static, false otherwise.
      */
-    public static String getStartupLineForClass(Class<?> aClass) {
-        StringBuilder sb = new StringBuilder();
-        sb.append("    ");
-        sb.append(getClassReferenceName(aClass));
-        sb.append(" = AndroidBridge::GetClassGlobalRef(env, \"");
-
-        String name = Utils.getTypeSignatureStringForClass(aClass);
-        Class<?> containerClass = aClass.getDeclaringClass();
-        if (containerClass != null) {
-            // Is an inner class. Add the $ symbol.
-            final int lastSlash = name.lastIndexOf('/');
-            name = name.substring(0, lastSlash) + '$' + name.substring(lastSlash+1);
-        }
-
-        sb.append(name);
-        sb.append("\");\n");
-        return sb.toString();
+    public static boolean isStatic(final Member member) {
+        return Modifier.isStatic(member.getModifiers());
     }
 
     /**
-     * Helper method to determine if this object implements CharSequence
-     * @param aClass Class to check for CharSequence-esqueness
-     * @return True if the given class implements CharSequence, false otherwise.
+     * Determine if a member is declared final.
+     *
+     * @param member The Member to check.
+     * @return true if the member is declared final, false otherwise.
      */
-    public static boolean isCharSequence(Class<?> aClass) {
-        if (aClass.getCanonicalName().equals("java.lang.CharSequence")) {
-            return true;
-        }
-        Class<?>[] interfaces = aClass.getInterfaces();
-        for (Class<?> c : interfaces) {
-            if (c.getCanonicalName().equals("java.lang.CharSequence")) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    /**
-     * Helper method to read the modifier bits of the given method to determine if it is static.
-     * @param aMember The Member to check.
-     * @return true of the method is declared static, false otherwise.
-     */
-    public static boolean isMemberStatic(Member aMember) {
-        int aMethodModifiers = aMember.getModifiers();
-        return Modifier.isStatic(aMethodModifiers);
-    }
-
-    /**
-     * Helper method to read the modifier bits of the given method to determine if it is static.
-     * @param aMember The Member to check.
-     * @return true of the method is declared static, false otherwise.
-     */
-    public static boolean isMemberFinal(Member aMember) {
-        int aMethodModifiers = aMember.getModifiers();
-        return Modifier.isFinal(aMethodModifiers);
+    public static boolean isFinal(final Member member) {
+        return Modifier.isFinal(member.getModifiers());
     }
 }
--- a/build/stlport/Android.mk
+++ b/build/stlport/Android.mk
@@ -1,19 +1,19 @@
 LOCAL_PATH := $(call my-dir)
 
 # Normally, we distribute the NDK with prebuilt binaries of STLport
-# in $LOCAL_PATH/<abi>/. However,
+# in $LOCAL_PATH/libs/<abi>/. However,
 #
 
 STLPORT_FORCE_REBUILD := $(strip $(STLPORT_FORCE_REBUILD))
 ifndef STLPORT_FORCE_REBUILD
-  ifeq (,$(strip $(wildcard $(LOCAL_PATH)/libs/$(TARGET_ARCH_ABI)/libstlport_static.a)))
+  ifeq (,$(strip $(wildcard $(LOCAL_PATH)/libs/$(TARGET_ARCH_ABI)/libstlport_static$(TARGET_LIB_EXTENSION))))
     $(call __ndk_info,WARNING: Rebuilding STLport libraries from sources!)
-    $(call __ndk_info,You might want to use $$NDK/build/tools/build-stlport.sh)
+    $(call __ndk_info,You might want to use $$NDK/build/tools/build-cxx-stl.sh --stl=stlport)
     $(call __ndk_info,in order to build prebuilt versions to speed up your builds!)
     STLPORT_FORCE_REBUILD := true
   endif
 endif
 
 libstlport_path := $(LOCAL_PATH)
 
 libstlport_src_files := \
@@ -60,31 +60,49 @@ libstlport_c_includes := $(libstlport_pa
 #
 # This simplifies usage, since you only have to list a single library
 # as a dependency, instead of two, especially when using the standalone
 # toolchain.
 #
 include $(dir $(LOCAL_PATH))/gabi++/sources.mk
 
 libstlport_c_includes += $(libgabi++_c_includes)
+ifneq ($(strip $(filter-out $(NDK_KNOWN_ARCHS),$(TARGET_ARCH))),)
+libgabi++_src_files := src/delete.cc \
+                       src/new.cc
+endif
 
 ifneq ($(STLPORT_FORCE_REBUILD),true)
 
 $(call ndk_log,Using prebuilt STLport libraries)
 
 include $(CLEAR_VARS)
 LOCAL_MODULE := stlport_static
-LOCAL_SRC_FILES := libs/$(TARGET_ARCH_ABI)/lib$(LOCAL_MODULE).a
+LOCAL_SRC_FILES := libs/$(TARGET_ARCH_ABI)/lib$(LOCAL_MODULE)$(TARGET_LIB_EXTENSION)
+# For armeabi*, choose thumb mode unless LOCAL_ARM_MODE := arm
+ifneq (,$(filter armeabi%,$(TARGET_ARCH_ABI)))
+ifneq (arm,$(LOCAL_ARM_MODE))
+LOCAL_SRC_FILES := libs/$(TARGET_ARCH_ABI)/thumb/lib$(LOCAL_MODULE)$(TARGET_LIB_EXTENSION)
+endif
+endif
 LOCAL_EXPORT_C_INCLUDES := $(libstlport_c_includes)
 LOCAL_CPP_FEATURES := rtti
 include $(PREBUILT_STATIC_LIBRARY)
 
 include $(CLEAR_VARS)
 LOCAL_MODULE := stlport_shared
-LOCAL_SRC_FILES := libs/$(TARGET_ARCH_ABI)/lib$(LOCAL_MODULE).so
+LOCAL_SRC_FILES := libs/$(TARGET_ARCH_ABI)/lib$(LOCAL_MODULE)$(TARGET_SONAME_EXTENSION)
+# For armeabi*, choose thumb mode unless LOCAL_ARM_MODE := arm
+$(info TARGET_ARCH_ABI=$(TARGET_ARCH_ABI))
+$(info LOCAL_ARM_MODE=$(LOCAL_ARM_MODE))
+ifneq (,$(filter armeabi%,$(TARGET_ARCH_ABI)))
+ifneq (arm,$(LOCAL_ARM_MODE))
+LOCAL_SRC_FILES := libs/$(TARGET_ARCH_ABI)/thumb/lib$(LOCAL_MODULE)$(TARGET_SONAME_EXTENSION)
+endif
+endif
 LOCAL_EXPORT_C_INCLUDES := $(libstlport_c_includes)
 LOCAL_CPP_FEATURES := rtti
 include $(PREBUILT_SHARED_LIBRARY)
 
 else # STLPORT_FORCE_REBUILD == true
 
 $(call ndk_log,Rebuilding STLport libraries from sources)
 
--- a/build/stlport/README.mozilla
+++ b/build/stlport/README.mozilla
@@ -1,12 +1,11 @@
-This copy of STLport was taken from the Android NDK r8e.
-Android specific changes are listed in README.android.
-The libs/ directory containing prebuilt static libraries was removed.
+This copy of STLport was taken from the Android NDK git repository:
+https://android.googlesource.com/platform/ndk.git
+under sources/cxx-stl/stlport/.
+The last changes to that directory come from commit ba4baa4
+
 The overrides/ directory contains Mozilla-specific overrides to the standard
   C++ headers found in the NDK.
 
 The following patches are applied on top:
 - android-mozilla-config.patch: Adjusts Android-specific configuration
   to the mozilla codebase use of the STL.
-
-- fix-warnings-as-errors.patch: Fixes warnings which were causing the
-  B2G emulator-ICS build to fail (related to bug 1073003).
deleted file mode 100644
--- a/build/stlport/fix-warnings-as-errors.patch
+++ /dev/null
@@ -1,70 +0,0 @@
-# HG changeset patch
-# Parent f89b28ea7c7b7fcb54c34e74fcb047626300bfba
-# User Dave Hylands <dhylands@mozilla.com>
-Bug 1073003 - Fix warnings in stlport causing errors in emulator build.
-
-diff --git a/build/stlport/stlport/stl/_istream.c b/build/stlport/stlport/stl/_istream.c
---- a/build/stlport/stlport/stl/_istream.c
-+++ b/build/stlport/stlport/stl/_istream.c
-@@ -1140,17 +1140,16 @@ basic_istream<_CharT, _Traits>::ignore(s
- template <class _CharT, class _Traits>
- basic_istream<_CharT, _Traits>&
- basic_istream<_CharT, _Traits>::ignore(streamsize __n, int_type __delim) {
-   sentry __sentry(*this, _No_Skip_WS());
-   this->_M_gcount = 0;
- 
-   if (__sentry) {
-     basic_streambuf<_CharT, _Traits>* __buf = this->rdbuf();
--    typedef _STLP_PRIV _Constant_unary_fun<bool, int_type> _Const_bool;
-     typedef _STLP_PRIV _Constant_binary_fun<streamsize, streamsize, streamsize>
-       _Const_streamsize;
-     const streamsize __maxss = (numeric_limits<streamsize>::max)();
- 
-     if (__n == (numeric_limits<int>::max)()) {
-       if (__buf->gptr() != __buf->egptr())
-         _M_gcount = _M_ignore_buffered(this,  __buf,
-                                        __maxss, _Const_streamsize(__maxss),
-diff --git a/build/stlport/stlport/stl/_slist.c b/build/stlport/stlport/stl/_slist.c
---- a/build/stlport/stlport/stl/_slist.c
-+++ b/build/stlport/stlport/stl/_slist.c
-@@ -143,17 +143,16 @@ void _Slist_unique(slist<_Tp, _Alloc>& _
-     }
-   }
- }
- 
- template <class _Tp, class _Alloc, class _StrictWeakOrdering>
- void _Slist_merge(slist<_Tp, _Alloc>& __that, slist<_Tp, _Alloc>& __x,
-                   _StrictWeakOrdering __comp) {
-   typedef _Slist_node<_Tp> _Node;
--  typedef _STLP_PRIV _Slist_node_base _Node_base;
-   if (__that.get_allocator() == __x.get_allocator()) {
-     typename slist<_Tp, _Alloc>::iterator __ite(__that.before_begin());
-     while (__ite._M_node->_M_next && !__x.empty()) {
-       if (__comp(__x.front(), __STATIC_CAST(_Node*, __ite._M_node->_M_next)->_M_data)) {
-         _STLP_VERBOSE_ASSERT(!__comp(__STATIC_CAST(_Node*, __ite._M_node->_M_next)->_M_data, __x.front()),
-                              _StlMsg_INVALID_STRICT_WEAK_PREDICATE)
-         __that.splice_after(__ite, __x, __x.before_begin());
-       }
-diff --git a/build/stlport/stlport/stl/config/features.h b/build/stlport/stlport/stl/config/features.h
---- a/build/stlport/stlport/stl/config/features.h
-+++ b/build/stlport/stlport/stl/config/features.h
-@@ -303,17 +303,18 @@
- #  undef  _STLP_NO_DEFAULT_NON_TYPE_PARAM
- #  define _STLP_NO_DEFAULT_NON_TYPE_PARAM 1
- #endif
- 
- #if !defined (_STLP_STATIC_ASSERT)
- /* Some compiler support 0 size array so we use negative size array to generate
-  * a compilation time error.
-  */
--#  define _STLP_STATIC_ASSERT(expr) typedef char __static_assert[expr ? 1 : -1];
-+//#  define _STLP_STATIC_ASSERT(expr) typedef char __static_assert[expr ? 1 : -1];
-+#  define _STLP_STATIC_ASSERT(expr) static_assert(expr, "static_assert failed");
- #endif
- 
- /* apple mpw exception handling bug */
- #ifndef _STLP_MPWFIX_TRY
- #  define _STLP_MPWFIX_TRY
- #endif
- #ifndef _STLP_MPWFIX_CATCH
- #  define _STLP_MPWFIX_CATCH
--- a/build/stlport/stlport/stl/_stdexcept_base.c
+++ b/build/stlport/stlport/stl/_stdexcept_base.c
@@ -59,17 +59,17 @@
   _M_name[__size - 1] = '\0';
 #else
   strncpy_s(_M_name, __size, __x._M_name, __size - 1);
 #endif
 }
 
 __Named_exception& __Named_exception::operator = (const __Named_exception& __x) {
   size_t __size = strlen(__x._M_name) + 1;
-  size_t __buf_size = _M_name != _M_static_name ? *(__REINTERPRET_CAST(size_t*, &_M_static_name[0])) : _S_bufsize;
+  size_t __buf_size = _M_name != _M_static_name ? *(__REINTERPRET_CAST(size_t*, &_M_static_name[0])) : static_cast<size_t>(_S_bufsize);
   if (__size > __buf_size) {
     // Being here necessarily mean that we need to allocate a buffer:
     if (_M_name != _M_static_name) free(_M_name);
     _M_name = __STATIC_CAST(char*, malloc(__size * sizeof(char)));
     if (!_M_name) {
       __size = _S_bufsize;
       _M_name = _M_static_name;
     }
--- a/build/stlport/stlport/stl/_time_facets.c
+++ b/build/stlport/stlport/stl/_time_facets.c
@@ -146,17 +146,16 @@ size_t _STLP_CALL
 // the correct overloading for the calls to __get_integer_nogroup.
 template <class _InIt1, class _Ch, class _TimeInfo>
 string::const_iterator _STLP_CALL
 __get_formatted_time _STLP_WEAK (_InIt1 __first,  _InIt1 __last,
                                  string::const_iterator __format, string::const_iterator __format_end,
                                  _Ch*, const _TimeInfo& __table,
                                  const ios_base& __s, ios_base::iostate& __err, tm* __t) {
   const ctype<_Ch>& __ct = use_facet<ctype<_Ch> >(__s.getloc());
-  typedef basic_string<_Ch, char_traits<_Ch>, allocator<_Ch> > string_type;
   size_t offset;
 
   while (__first != __last && __format != __format_end) {
     offset = 0;
     if (*__format == '%') {
       ++__format;
       char __c = *__format;
       if (__c == '#') { //MS extension
--- a/build/stlport/stlport/stl/config/_android.h
+++ b/build/stlport/stlport/stl/config/_android.h
@@ -47,17 +47,17 @@
 #define _STLP_USE_SIMPLE_NODE_ALLOC 1
 
 // Don't use extern versions of range errors, so we don't need to
 // compile as a library.
 #define _STLP_USE_NO_EXTERN_RANGE_ERRORS 1
 
 // The system math library doesn't have long double variants, e.g
 // sinl, cosl, etc
-#define _STLP_NO_VENDOR_MATH_L 1
+#define _STLP_NO_VENDOR_MATH_L
 
 // Include most of the gcc settings.
 #include <stl/config/_gcc.h>
 
 // Do not use glibc, Android is missing some things.
 #undef _STLP_USE_GLIBC
 
 // No exceptions.
--- a/build/stlport/stlport/stl/config/_linux.h
+++ b/build/stlport/stlport/stl/config/_linux.h
@@ -110,16 +110,17 @@
  *   - ARM
  *   - SH4
  */
 #  if defined(__alpha__) || \
       defined(__ppc__) || defined(PPC) || defined(__powerpc__) || \
       ((defined(__sparc) || defined(__sparcv9) || defined(__sparcv8plus)) && !defined ( __WORD64 ) && !defined(__arch64__)) /* ? */ || \
       (defined(_MIPS_SIM) && (_MIPS_SIM == _ABIO32)) || \
       defined(__arm__) || \
+      defined(__le32__) || \
       defined(__sh__)
  /* #  if defined(__NO_LONG_DOUBLE_MATH) */
 #    define _STLP_NO_LONG_DOUBLE
 #  endif
 #endif
 
 
 #endif /* __stl_config__linux_h */
--- a/build/stlport/stlport/stl/config/features.h
+++ b/build/stlport/stlport/stl/config/features.h
@@ -303,18 +303,17 @@
 #  undef  _STLP_NO_DEFAULT_NON_TYPE_PARAM
 #  define _STLP_NO_DEFAULT_NON_TYPE_PARAM 1
 #endif
 
 #if !defined (_STLP_STATIC_ASSERT)
 /* Some compiler support 0 size array so we use negative size array to generate
  * a compilation time error.
  */
-//#  define _STLP_STATIC_ASSERT(expr) typedef char __static_assert[expr ? 1 : -1];
-#  define _STLP_STATIC_ASSERT(expr) static_assert(expr, "static_assert failed");
+#  define _STLP_STATIC_ASSERT(expr) typedef char __static_assert[expr ? 1 : -1]  __attribute__((unused));
 #endif
 
 /* apple mpw exception handling bug */
 #ifndef _STLP_MPWFIX_TRY
 #  define _STLP_MPWFIX_TRY
 #endif
 #ifndef _STLP_MPWFIX_CATCH
 #  define _STLP_MPWFIX_CATCH
@@ -1048,17 +1047,17 @@ typedef int bool;
 #  include <stl/_abbrevs.h>
 #endif
 
 /* Some really useful macro */
 #define _STLP_ARRAY_SIZE(A) sizeof(A) / sizeof(A[0])
 #define _STLP_ARRAY_AND_SIZE(A) A, sizeof(A) / sizeof(A[0])
 
 #if !defined (_STLP_MARK_PARAMETER_AS_UNUSED)
-#  define _STLP_MARK_PARAMETER_AS_UNUSED(X) (void*)X;
+#  define _STLP_MARK_PARAMETER_AS_UNUSED(X) (void)X;
 #endif
 
 #if defined (_STLP_CHECK_RUNTIME_COMPATIBILITY)
 #  if defined (_STLP_USE_NO_IOSTREAMS)
 #    undef _STLP_CHECK_RUNTIME_COMPATIBILITY
 #  else
 /* The extern "C" simply makes the symbol simpler. */
 #if defined (__cplusplus)
--- a/build/stlport/stlport/stl/config/stl_confix.h
+++ b/build/stlport/stlport/stl/config/stl_confix.h
@@ -75,17 +75,17 @@
 #    define _STLP_HAS_NO_EXCEPTIONS
 #  endif
 #  undef __EDG_SWITCHES
 #endif /* EDG */
 
 /* __EDG_VERSION__ is an official EDG macro, compilers based
  * on EDG have to define it. */
 #if defined (__EDG_VERSION__)
-#  if (__EDG_VERSION__ >= 244) && !defined (_STLP_HAS_INCLUDE_NEXT)
+#  if (__EDG_VERSION__ >= 244) && !defined (_STLP_HAS_INCLUDE_NEXT) && !defined(__ANDROID__)
 #    define _STLP_HAS_INCLUDE_NEXT
 #  endif
 #  if (__EDG_VERSION__ <= 240) && !defined (_STLP_DONT_RETURN_VOID)
 #    define _STLP_DONT_RETURN_VOID
 #  endif
 #  if !defined (__EXCEPTIONS) && !defined (_STLP_HAS_NO_EXCEPTIONS)
 #    define _STLP_HAS_NO_EXCEPTIONS
 #  endif
--- a/build/unix/elfhack/elfxx.h
+++ b/build/unix/elfhack/elfxx.h
@@ -1,14 +1,12 @@
 /* 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/NullPtr.h"
-
 #include <stdexcept>
 #include <list>
 #include <vector>
 #include <cstring>
 #include <iostream>
 #include <fstream>
 #include <algorithm>
 #include <elf.h>
--- a/configure.in
+++ b/configure.in
@@ -285,16 +285,17 @@ if test -n "$gonkdir" ; then
         ;;
     21)
         GONK_INCLUDES="-I$gonkdir/frameworks/native/include -I$gonkdir/frameworks/av/include -I$gonkdir/frameworks/av/include/media -I$gonkdir/frameworks/av/include/camera -I$gonkdir/frameworks/native/include/media/openmax -I$gonkdir/frameworks/av/media/libstagefright/include"
         MOZ_AUDIO_OFFLOAD=1
         MOZ_OMX_DECODER=1
         AC_SUBST(MOZ_AUDIO_OFFLOAD)
         AC_DEFINE(MOZ_AUDIO_OFFLOAD)
         MOZ_FMP4=
+        MOZ_B2G_CAMERA=1
         MOZ_B2G_BT=1
         MOZ_B2G_BT_BLUEDROID=1
         if test -d "$gonkdir/system/bluetoothd"; then
             MOZ_B2G_BT_DAEMON=1
         fi
         ;;
     *)
         AC_MSG_ERROR([Unsupported platform version: $ANDROID_VERSION])
@@ -3380,16 +3381,29 @@ for file in $MALLOC_HEADERS; do
   fi
 done
 
 MOZ_CHECK_HEADERS(alloca.h)
 
 AC_CHECK_FUNCS(strndup posix_memalign memalign)
 
 AC_CHECK_FUNCS(malloc_usable_size)
+MALLOC_USABLE_SIZE_CONST_PTR=const
+MOZ_CHECK_HEADERS([malloc.h], [
+  AC_MSG_CHECKING([whether malloc_usable_size definition can use const argument])
+  AC_TRY_COMPILE([#include <malloc.h>
+                  #include <stddef.h>
+                  size_t malloc_usable_size(const void *ptr);],
+                  [return malloc_usable_size(0);],
+                  AC_MSG_RESULT([yes]),
+                  AC_MSG_RESULT([no])
+                  MALLOC_USABLE_SIZE_CONST_PTR=)
+])
+AC_DEFINE_UNQUOTED([MALLOC_USABLE_SIZE_CONST_PTR],[$MALLOC_USABLE_SIZE_CONST_PTR])
+
 
 dnl In newer bionic headers, valloc is built but not defined,
 dnl so we check more carefully here.
 AC_MSG_CHECKING([for valloc in malloc.h])
 AC_EGREP_HEADER(valloc, malloc.h,
                 AC_DEFINE(HAVE_VALLOC)
                 AC_MSG_RESULT([yes]),
                 AC_MSG_RESULT([no]))
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -5157,16 +5157,25 @@ nsDocShell::DisplayLoadError(nsresult aE
             strs, formatStrCount, getter_Copies(str));
         NS_ENSURE_SUCCESS(rv, rv);
         messageStr.Assign(str.get());
     }
 
     // Display the error as a page or an alert prompt
     NS_ENSURE_FALSE(messageStr.IsEmpty(), NS_ERROR_FAILURE);
 
+    if (NS_ERROR_NET_INTERRUPT == aError || NS_ERROR_NET_RESET == aError) {
+        bool isSecureURI = false;
+        rv = aURI->SchemeIs("https", &isSecureURI);
+        if (NS_SUCCEEDED(rv) && isSecureURI) {
+            // Maybe TLS intolerant. Treat this as an SSL error.
+            error.AssignLiteral("nssFailure2");
+        }
+    }
+
     if (UseErrorPages()) {
         // Display an error page
         LoadErrorPage(aURI, aURL, errorPage.get(), error.get(),
                       messageStr.get(), cssClass.get(), aFailedChannel);
     } 
     else
     {
         // The prompter reqires that our private window has a document (or it
--- a/dom/archivereader/ArchiveReader.cpp
+++ b/dom/archivereader/ArchiveReader.cpp
@@ -43,17 +43,17 @@ ArchiveReader::Constructor(const GlobalO
 
   nsRefPtr<ArchiveReader> reader =
     new ArchiveReader(aBlob, window, encoding);
   return reader.forget();
 }
 
 ArchiveReader::ArchiveReader(File& aBlob, nsPIDOMWindow* aWindow,
                              const nsACString& aEncoding)
-  : mBlob(&aBlob)
+  : mFileImpl(aBlob.Impl())
   , mWindow(aWindow)
   , mStatus(NOT_STARTED)
   , mEncoding(aEncoding)
 {
   MOZ_ASSERT(aWindow);
 }
 
 ArchiveReader::~ArchiveReader()
@@ -90,27 +90,27 @@ ArchiveReader::RegisterRequest(ArchiveRe
   return NS_OK;
 }
 
 // This returns the input stream
 nsresult
 ArchiveReader::GetInputStream(nsIInputStream** aInputStream)
 {
   // Getting the input stream
-  mBlob->GetInternalStream(aInputStream);
+  mFileImpl->GetInternalStream(aInputStream);
   NS_ENSURE_TRUE(*aInputStream, NS_ERROR_UNEXPECTED);
   return NS_OK;
 }
 
 nsresult
 ArchiveReader::GetSize(uint64_t* aSize)
 {
-  nsresult rv = mBlob->GetSize(aSize);
-  NS_ENSURE_SUCCESS(rv, rv);
-  return NS_OK;
+  ErrorResult rv;
+  *aSize = mFileImpl->GetSize(rv);
+  return rv.ErrorCode();
 }
 
 // Here we open the archive:
 nsresult
 ArchiveReader::OpenArchive()
 {
   mStatus = WORKING;
   nsresult rv;
@@ -194,17 +194,17 @@ ArchiveReader::GetFiles()
 already_AddRefed<ArchiveRequest>
 ArchiveReader::GenerateArchiveRequest()
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   return ArchiveRequest::Create(mWindow, this);
 }
 
 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(ArchiveReader,
-                                      mBlob,
+                                      mFileImpl,
                                       mWindow,
                                       mData.fileList,
                                       mRequests)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ArchiveReader)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
--- a/dom/archivereader/ArchiveReader.h
+++ b/dom/archivereader/ArchiveReader.h
@@ -15,16 +15,17 @@
 #include "nsIChannel.h"
 #include "nsIDOMFile.h"
 #include "mozilla/Attributes.h"
 
 namespace mozilla {
 namespace dom {
 struct ArchiveReaderOptions;
 class File;
+class FileImpl;
 class GlobalObject;
 } // namespace dom
 } // namespace mozilla
 
 BEGIN_ARCHIVEREADER_NAMESPACE
 
 class ArchiveRequest;
 
@@ -44,44 +45,50 @@ public:
 
   ArchiveReader(File& aBlob, nsPIDOMWindow* aWindow,
                 const nsACString& aEncoding);
 
   nsIDOMWindow* GetParentObject() const
   {
     return mWindow;
   }
+
   virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE;
 
   already_AddRefed<ArchiveRequest> GetFilenames();
   already_AddRefed<ArchiveRequest> GetFile(const nsAString& filename);
   already_AddRefed<ArchiveRequest> GetFiles();
 
   nsresult GetInputStream(nsIInputStream** aInputStream);
   nsresult GetSize(uint64_t* aSize);
 
 public: // for the ArchiveRequest:
   nsresult RegisterRequest(ArchiveRequest* aRequest);
 
 public: // For events:
+  FileImpl* GetFileImpl() const
+  {
+    return mFileImpl;
+  }
+
   void Ready(nsTArray<nsCOMPtr<nsIDOMFile> >& aFileList,
              nsresult aStatus);
 
 private:
   ~ArchiveReader();
 
   already_AddRefed<ArchiveRequest> GenerateArchiveRequest();
 
   nsresult OpenArchive();
 
   void RequestReady(ArchiveRequest* aRequest);
 
 protected:
   // The archive blob/file
-  nsRefPtr<File> mBlob;
+  nsRefPtr<FileImpl> mFileImpl;
 
   // The window is needed by the requests
   nsCOMPtr<nsPIDOMWindow> mWindow;
 
   // Are we ready to return data?
   enum {
     NOT_STARTED = 0,
     WORKING,
--- a/dom/archivereader/ArchiveZipEvent.cpp
+++ b/dom/archivereader/ArchiveZipEvent.cpp
@@ -83,17 +83,17 @@ ArchiveZipItem::File(ArchiveReader* aArc
   if (NS_FAILED(GetFilename(filename))) {
     return nullptr;
   }
 
   return new dom::File(aArchiveReader,
     new ArchiveZipFileImpl(filename,
                            NS_ConvertUTF8toUTF16(GetType()),
                            StrToInt32(mCentralStruct.orglen),
-                           mCentralStruct, aArchiveReader));
+                           mCentralStruct, aArchiveReader->GetFileImpl()));
 }
 
 uint32_t
 ArchiveZipItem::StrToInt32(const uint8_t* aStr)
 {
   return (uint32_t)( (aStr [0] <<  0) |
                      (aStr [1] <<  8) |
                      (aStr [2] << 16) |
--- a/dom/archivereader/ArchiveZipFile.cpp
+++ b/dom/archivereader/ArchiveZipFile.cpp
@@ -357,56 +357,44 @@ ArchiveInputStream::SetEOF()
 
 nsresult
 ArchiveZipFileImpl::GetInternalStream(nsIInputStream** aStream)
 {
   if (mLength > INT32_MAX) {
     return NS_ERROR_FAILURE;
   }
 
-  uint64_t size;
-  nsresult rv = mArchiveReader->GetSize(&size);
-  NS_ENSURE_SUCCESS(rv, rv);
+  ErrorResult rv;
+  uint64_t size = mFileImpl->GetSize(rv);
+  if (NS_WARN_IF(rv.Failed())) {
+    return rv.ErrorCode();
+  }
 
   nsCOMPtr<nsIInputStream> inputStream;
-  rv = mArchiveReader->GetInputStream(getter_AddRefs(inputStream));
-  if (NS_FAILED(rv) || !inputStream) {
+  rv = mFileImpl->GetInternalStream(getter_AddRefs(inputStream));
+  if (NS_WARN_IF(rv.Failed()) || !inputStream) {
     return NS_ERROR_UNEXPECTED;
   }
 
   nsRefPtr<ArchiveInputStream> stream = new ArchiveInputStream(size,
                                                                inputStream,
                                                                mFilename,
                                                                mStart,
                                                                mLength,
                                                                mCentral);
 
   stream.forget(aStream);
   return NS_OK;
 }
 
-void
-ArchiveZipFileImpl::Unlink()
-{
-  ArchiveZipFileImpl* tmp = this;
-  NS_IMPL_CYCLE_COLLECTION_UNLINK(mArchiveReader);
-}
-
-void
-ArchiveZipFileImpl::Traverse(nsCycleCollectionTraversalCallback &cb)
-{
-  ArchiveZipFileImpl* tmp = this;
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mArchiveReader);
-}
-
 already_AddRefed<mozilla::dom::FileImpl>
 ArchiveZipFileImpl::CreateSlice(uint64_t aStart,
                                 uint64_t aLength,
                                 const nsAString& aContentType,
                                 mozilla::ErrorResult& aRv)
 {
   nsRefPtr<FileImpl> impl =
     new ArchiveZipFileImpl(mFilename, mContentType, aStart, mLength, mCentral,
-                           mArchiveReader);
+                           mFileImpl);
   return impl.forget();
 }
 
 NS_IMPL_ISUPPORTS_INHERITED0(ArchiveZipFileImpl, FileImpl)
--- a/dom/archivereader/ArchiveZipFile.h
+++ b/dom/archivereader/ArchiveZipFile.h
@@ -25,64 +25,55 @@ class ArchiveZipFileImpl : public FileIm
 {
 public:
   NS_DECL_ISUPPORTS_INHERITED
 
   ArchiveZipFileImpl(const nsAString& aName,
                      const nsAString& aContentType,
                      uint64_t aLength,
                      ZipCentral& aCentral,
-                     ArchiveReader* aReader)
+                     FileImpl* aFileImpl)
   : FileImplBase(aName, aContentType, aLength),
     mCentral(aCentral),
-    mArchiveReader(aReader),
+    mFileImpl(aFileImpl),
     mFilename(aName)
   {
-    NS_ASSERTION(mArchiveReader, "must have a reader");
+    MOZ_ASSERT(mFileImpl);
     MOZ_COUNT_CTOR(ArchiveZipFileImpl);
   }
 
   ArchiveZipFileImpl(const nsAString& aName,
                      const nsAString& aContentType,
                      uint64_t aStart,
                      uint64_t aLength,
                      ZipCentral& aCentral,
-                     ArchiveReader* aReader)
+                     FileImpl* aFileImpl)
   : FileImplBase(aContentType, aStart, aLength),
     mCentral(aCentral),
-    mArchiveReader(aReader),
+    mFileImpl(aFileImpl),
     mFilename(aName)
   {
-    NS_ASSERTION(mArchiveReader, "must have a reader");
+    MOZ_ASSERT(mFileImpl);
     MOZ_COUNT_CTOR(ArchiveZipFileImpl);
   }
 
   // Overrides:
   virtual nsresult GetInternalStream(nsIInputStream**) MOZ_OVERRIDE;
-
-  virtual void Unlink() MOZ_OVERRIDE;
-  virtual void Traverse(nsCycleCollectionTraversalCallback &aCb) MOZ_OVERRIDE;
-
-  virtual bool IsCCed() const MOZ_OVERRIDE
-  {
-    return true;
-  }
-
 protected:
   virtual ~ArchiveZipFileImpl()
   {
     MOZ_COUNT_DTOR(ArchiveZipFileImpl);
   }
 
   virtual already_AddRefed<FileImpl>
   CreateSlice(uint64_t aStart, uint64_t aLength, const nsAString& aContentType,
               mozilla::ErrorResult& aRv) MOZ_OVERRIDE;
 
 private: // Data
   ZipCentral mCentral;
-  nsRefPtr<ArchiveReader> mArchiveReader;
+  nsRefPtr<FileImpl> mFileImpl;
 
   nsString mFilename;
 };
 
 END_ARCHIVEREADER_NAMESPACE
 
 #endif // mozilla_dom_archivereader_domarchivefile_h__
--- a/dom/base/Crypto.cpp
+++ b/dom/base/Crypto.cpp
@@ -1,16 +1,15 @@
 /* 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 "Crypto.h"
 #include "jsfriendapi.h"
 #include "nsCOMPtr.h"
 #include "nsIRandomGenerator.h"
-#include "nsPIDOMWindow.h"
 #include "MainThreadUtils.h"
 #include "nsXULAppAPI.h"
 
 #include "mozilla/dom/ContentChild.h"
 #include "mozilla/dom/CryptoBinding.h"
 #include "nsServiceManagerUtils.h"
 
 using mozilla::dom::ContentChild;
@@ -22,45 +21,45 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
   NS_INTERFACE_MAP_ENTRY(nsIDOMCrypto)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(Crypto)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(Crypto)
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Crypto, mWindow, mSubtle)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Crypto, mParent, mSubtle)
 
 Crypto::Crypto()
 {
   MOZ_COUNT_CTOR(Crypto);
 }
 
 Crypto::~Crypto()
 {
   MOZ_COUNT_DTOR(Crypto);
 }
 
 void
-Crypto::Init(nsIDOMWindow* aWindow)
+Crypto::Init(nsIGlobalObject* aParent)
 {
-  mWindow = do_QueryInterface(aWindow);
-  MOZ_ASSERT(mWindow);
+  mParent = do_QueryInterface(aParent);
+  MOZ_ASSERT(mParent);
 }
 
 /* virtual */ JSObject*
 Crypto::WrapObject(JSContext* aCx)
 {
   return CryptoBinding::Wrap(aCx, this);
 }
 
 void
 Crypto::GetRandomValues(JSContext* aCx, const ArrayBufferView& aArray,
-			JS::MutableHandle<JSObject*> aRetval,
-			ErrorResult& aRv)
+                        JS::MutableHandle<JSObject*> aRetval,
+                        ErrorResult& aRv)
 {
   NS_ABORT_IF_FALSE(NS_IsMainThread(), "Called on the wrong thread");
 
   JS::Rooted<JSObject*> view(aCx, aArray.Obj());
 
   // Throw if the wrong type of ArrayBufferView is passed in
   // (Part of the Web Crypto API spec)
   switch (JS_GetArrayBufferViewType(view)) {
--- a/dom/base/Crypto.h
+++ b/dom/base/Crypto.h
@@ -1,17 +1,17 @@
 /* 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_dom_Crypto_h
 #define mozilla_dom_Crypto_h
 
 #include "nsIDOMCrypto.h"
 #include "mozilla/dom/SubtleCrypto.h"
-#include "nsPIDOMWindow.h"
+#include "nsIGlobalObject.h"
 
 #include "nsWrapperCache.h"
 #include "mozilla/dom/TypedArray.h"
 #define NS_DOMCRYPTO_CID \
   {0x929d9320, 0x251e, 0x11d4, { 0x8a, 0x7c, 0x00, 0x60, 0x08, 0xc8, 0x44, 0xc3} }
 
 namespace mozilla {
 
@@ -30,37 +30,37 @@ public:
 
   NS_DECL_NSIDOMCRYPTO
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(Crypto)
 
   void
   GetRandomValues(JSContext* aCx, const ArrayBufferView& aArray,
-		  JS::MutableHandle<JSObject*> aRetval,
-		  ErrorResult& aRv);
+                  JS::MutableHandle<JSObject*> aRetval,
+                  ErrorResult& aRv);
 
   SubtleCrypto*
   Subtle();
 
   // WebIDL
 
-  nsPIDOMWindow*
+  nsIGlobalObject*
   GetParentObject() const
   {
-    return mWindow;
+    return mParent;
   }
 
   virtual JSObject*
   WrapObject(JSContext* aCx) MOZ_OVERRIDE;
 
   static uint8_t*
   GetRandomValues(uint32_t aLength);
 
 private:
-  nsCOMPtr<nsPIDOMWindow> mWindow;
+  nsCOMPtr<nsIGlobalObject> mParent;
   nsRefPtr<SubtleCrypto> mSubtle;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_Crypto_h
--- a/dom/base/File.cpp
+++ b/dom/base/File.cpp
@@ -124,25 +124,24 @@ nsresult DataOwnerAdapter::Create(DataOw
 }
 
 ////////////////////////////////////////////////////////////////////////////
 // mozilla::dom::File implementation
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(File)
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(File)
-  MOZ_ASSERT(tmp->mImpl);
-  tmp->mImpl->Unlink();
+  // No unlink for mImpl bacause FileImpl is not CC-able.
+  tmp->mImpl = nullptr;
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mParent)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(File)
-  MOZ_ASSERT(tmp->mImpl);
-  tmp->mImpl->Traverse(cb);
+  // No traverse for mImpl bacause FileImpl is not CC-able.
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(File)
   NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
@@ -713,17 +712,17 @@ FileImpl::Slice(const Optional<int64_t>&
 
   return CreateSlice((uint64_t)start, (uint64_t)(end - start),
                      aContentType, aRv);
 }
 
 ////////////////////////////////////////////////////////////////////////////
 // FileImpl implementation
 
-NS_IMPL_ISUPPORTS(FileImpl, PIFileImpl)
+NS_IMPL_ISUPPORTS(FileImpl, FileImpl)
 
 ////////////////////////////////////////////////////////////////////////////
 // FileImplFile implementation
 
 NS_IMPL_ISUPPORTS_INHERITED0(FileImplFile, FileImpl)
 
 void
 FileImplBase::GetName(nsAString& aName)
--- a/dom/base/File.h
+++ b/dom/base/File.h
@@ -29,27 +29,19 @@
 #include "nsWrapperCache.h"
 #include "nsWeakReference.h"
 
 class nsDOMMultipartFile;
 class nsIFile;
 class nsIInputStream;
 class nsIClassInfo;
 
-#define PIFILEIMPL_IID \
-  { 0x218ee173, 0xf44f, 0x4d30, \
-    { 0xab, 0x0c, 0xd6, 0x66, 0xea, 0xc2, 0x84, 0x47 } }
-
-class PIFileImpl : public nsISupports
-{
-public:
-  NS_DECLARE_STATIC_IID_ACCESSOR(PIFILEIMPL_IID)
-};
-
-NS_DEFINE_STATIC_IID_ACCESSOR(PIFileImpl, PIFILEIMPL_IID)
+#define FILEIMPL_IID \
+  { 0xbccb3275, 0x6778, 0x4ac5, \
+    { 0xaf, 0x03, 0x90, 0xed, 0x37, 0xad, 0xdf, 0x5d } }
 
 namespace mozilla {
 namespace dom {
 
 namespace indexedDB {
 class FileInfo;
 };
 
@@ -218,26 +210,27 @@ public:
 
 private:
   ~File() {};
 
   // The member is the real backend implementation of this File/Blob.
   // It's thread-safe and not CC-able and it's the only element that is moved
   // between threads.
   // Note: we should not store any other state in this class!
-  const nsRefPtr<FileImpl> mImpl;
+  nsRefPtr<FileImpl> mImpl;
 
   nsCOMPtr<nsISupports> mParent;
 };
 
 // This is the abstract class for any File backend. It must be nsISupports
 // because this class must be ref-counted and it has to work with IPC.
-class FileImpl : public PIFileImpl
+class FileImpl : public nsISupports
 {
 public:
+  NS_DECLARE_STATIC_IID_ACCESSOR(FILEIMPL_IID)
   NS_DECL_THREADSAFE_ISUPPORTS
 
   FileImpl() {}
 
   virtual void GetName(nsAString& aName) = 0;
 
   virtual nsresult GetPath(nsAString& aName) = 0;
 
@@ -288,29 +281,28 @@ public:
   virtual bool IsMemoryFile() const = 0;
 
   virtual bool IsSizeUnknown() const = 0;
 
   virtual bool IsDateUnknown() const = 0;
 
   virtual bool IsFile() const = 0;
 
-  // These 2 methods are used when the implementation has to CC something.
-  virtual void Unlink() = 0;
-  virtual void Traverse(nsCycleCollectionTraversalCallback &aCb) = 0;
-
-  virtual bool IsCCed() const
+  // True if this implementation can be sent to other threads.
+  virtual bool MayBeClonedToOtherThreads() const
   {
-    return false;
+    return true;
   }
 
 protected:
   virtual ~FileImpl() {}
 };
 
+NS_DEFINE_STATIC_IID_ACCESSOR(FileImpl, FILEIMPL_IID)
+
 class FileImplBase : public FileImpl
 {
 public:
   FileImplBase(const nsAString& aName, const nsAString& aContentType,
                uint64_t aLength, uint64_t aLastModifiedDate)
     : mIsFile(true)
     , mImmutable(false)
     , mContentType(aContentType)
@@ -460,19 +452,16 @@ public:
     return false;
   }
 
   virtual bool IsSizeUnknown() const MOZ_OVERRIDE
   {
     return mLength == UINT64_MAX;
   }
 
-  virtual void Unlink() MOZ_OVERRIDE {}
-  virtual void Traverse(nsCycleCollectionTraversalCallback &aCb) MOZ_OVERRIDE {}
-
 protected:
   virtual ~FileImplBase() {}
 
   indexedDB::FileInfo* GetFileInfo() const
   {
     NS_ASSERTION(IsStoredFile(), "Should only be called on stored files!");
     NS_ASSERTION(!mFileInfos.IsEmpty(), "Must have at least one file info!");
 
--- a/dom/base/FragmentOrElement.cpp
+++ b/dom/base/FragmentOrElement.cpp
@@ -149,17 +149,18 @@ nsIContent::FindFirstNonChromeOnlyAccess
   return nullptr;
 }
 
 nsIContent*
 nsIContent::GetFlattenedTreeParent() const
 {
   nsIContent* parent = GetParent();
 
-  if (nsContentUtils::HasDistributedChildren(parent)) {
+  if (parent && nsContentUtils::HasDistributedChildren(parent) &&
+      nsContentUtils::IsInSameAnonymousTree(parent, this)) {
     // This node is distributed to insertion points, thus we
     // need to consult the destination insertion points list to
     // figure out where this node was inserted in the flattened tree.
     // It may be the case that |parent| distributes its children
     // but the child does not match any insertion points, thus
     // the flattened tree parent is nullptr.
     nsTArray<nsIContent*>* destInsertionPoints = GetExistingDestInsertionPoints();
     parent = destInsertionPoints && !destInsertionPoints->IsEmpty() ?
@@ -2104,17 +2105,17 @@ private:
       const char*           mLiteral;
       nsAutoString*         mString;
       const nsTextFragment* mTextFragment;
     };
     Type     mType;
     uint32_t mLength;
   };
 public:
-  StringBuilder() : mLast(MOZ_THIS_IN_INITIALIZER_LIST()), mLength(0)
+  StringBuilder() : mLast(this), mLength(0)
   {
     MOZ_COUNT_CTOR(StringBuilder);
   }
 
   ~StringBuilder()
   {
     MOZ_COUNT_DTOR(StringBuilder);
   }
--- a/dom/base/ImportManager.cpp
+++ b/dom/base/ImportManager.cpp
@@ -288,17 +288,17 @@ NS_IMPL_CYCLE_COLLECTION(ImportLoader,
 
 ImportLoader::ImportLoader(nsIURI* aURI, nsIDocument* aImportParent)
   : mURI(aURI)
   , mImportParent(aImportParent)
   , mBlockingPredecessor(nullptr)
   , mReady(false)
   , mStopped(false)
   , mBlockingScripts(false)
-  , mUpdater(MOZ_THIS_IN_INITIALIZER_LIST())
+  , mUpdater(this)
 {
 }
 
 void
 ImportLoader::BlockScripts()
 {
   MOZ_ASSERT(!mBlockingScripts);
   mImportParent->ScriptLoader()->AddExecuteBlocker();
--- a/dom/base/MultipartFileImpl.cpp
+++ b/dom/base/MultipartFileImpl.cpp
@@ -347,8 +347,20 @@ MultipartFileImpl::InitializeChromeFile(
   nsCOMPtr<nsIFile> file;
   aRv = NS_NewLocalFile(aData, false, getter_AddRefs(file));
   if (NS_WARN_IF(aRv.Failed())) {
     return;
   }
 
   InitializeChromeFile(aWindow, file, aBag, false, aRv);
 }
+
+bool
+MultipartFileImpl::MayBeClonedToOtherThreads() const
+{
+  for (uint32_t i = 0; i < mBlobImpls.Length(); ++i) {
+    if (!mBlobImpls[i]->MayBeClonedToOtherThreads()) {
+      return false;
+    }
+  }
+
+  return true;
+}
--- a/dom/base/MultipartFileImpl.h
+++ b/dom/base/MultipartFileImpl.h
@@ -106,16 +106,18 @@ public:
     mName = aName;
   }
 
   void SetFromNsIFile(bool aValue)
   {
     mIsFromNsIFile = aValue;
   }
 
+  virtual bool MayBeClonedToOtherThreads() const MOZ_OVERRIDE;
+
 protected:
   virtual ~MultipartFileImpl() {}
 
   void SetLengthAndModifiedDate();
 
   nsTArray<nsRefPtr<FileImpl>> mBlobImpls;
   bool mIsFromNsIFile;
 };
--- a/dom/base/ShadowRoot.cpp
+++ b/dom/base/ShadowRoot.cpp
@@ -583,18 +583,22 @@ ShadowRoot::IsPooledNode(nsIContent* aCo
                          nsIContent* aHost)
 {
   if (nsContentUtils::IsContentInsertionPoint(aContent) ||
       IsShadowInsertionPoint(aContent)) {
     // Insertion points never end up in the pool.
     return false;
   }
 
-  if (aContainer == aHost) {
-    // Any other child nodes of the host will end up in the pool.
+  if (aContainer == aHost &&
+      nsContentUtils::IsInSameAnonymousTree(aContainer, aContent)) {
+    // Children of the host will end up in the pool. We check to ensure
+    // that the content is in the same anonymous tree as the container
+    // because anonymous content may report its container as the host
+    // but it may not be in the host's child list.
     return true;
   }
 
   if (aContainer && aContainer->IsHTML(nsGkAtoms::content)) {
     // Fallback content will end up in pool if its parent is a child of the host.
     HTMLContentElement* content = static_cast<HTMLContentElement*>(aContainer);
     return content->IsInsertionPoint() && content->MatchedNodes().IsEmpty() &&
            aContainer->GetParentNode() == aHost;
--- a/dom/base/SubtleCrypto.cpp
+++ b/dom/base/SubtleCrypto.cpp
@@ -8,41 +8,40 @@
 
 #include "mozilla/dom/Promise.h"
 #include "mozilla/dom/SubtleCryptoBinding.h"
 #include "mozilla/dom/WebCryptoTask.h"
 
 namespace mozilla {
 namespace dom {
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(SubtleCrypto, mWindow)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(SubtleCrypto, mParent)
 NS_IMPL_CYCLE_COLLECTING_ADDREF(SubtleCrypto)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(SubtleCrypto)
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SubtleCrypto)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
 
 
-SubtleCrypto::SubtleCrypto(nsPIDOMWindow* aWindow)
-  : mWindow(aWindow)
+SubtleCrypto::SubtleCrypto(nsIGlobalObject* aParent)
+  : mParent(aParent)
 {
 }
 
 JSObject*
 SubtleCrypto::WrapObject(JSContext* aCx)
 {
   return SubtleCryptoBinding::Wrap(aCx, this);
 }
 
 #define SUBTLECRYPTO_METHOD_BODY(Operation, aRv, ...)                   \
-  nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(mWindow);        \
-  MOZ_ASSERT(global);                                                   \
-  nsRefPtr<Promise> p = Promise::Create(global, aRv);                   \
+  MOZ_ASSERT(mParent);                                                  \
+  nsRefPtr<Promise> p = Promise::Create(mParent, aRv);                  \
   if (aRv.Failed()) {                                                   \
     return nullptr;                                                     \
   }                                                                     \
   nsRefPtr<WebCryptoTask> task = WebCryptoTask::Create ## Operation ## Task(__VA_ARGS__); \
   task->DispatchWithPromise(p); \
   return p.forget();
 
 already_AddRefed<Promise>
--- a/dom/base/SubtleCrypto.h
+++ b/dom/base/SubtleCrypto.h
@@ -4,17 +4,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_SubtleCrypto_h
 #define mozilla_dom_SubtleCrypto_h
 
 #include "nsCycleCollectionParticipant.h"
 #include "nsWrapperCache.h"
-#include "nsPIDOMWindow.h"
+#include "nsIGlobalObject.h"
 #include "mozilla/dom/CryptoKey.h"
 #include "js/TypeDecls.h"
 
 namespace mozilla {
 namespace dom {
 
 class ObjectOrString;
 class Promise;
@@ -26,21 +26,21 @@ class SubtleCrypto MOZ_FINAL : public ns
 {
   ~SubtleCrypto() {}
 
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(SubtleCrypto)
 
 public:
-  explicit SubtleCrypto(nsPIDOMWindow* aWindow);
+  explicit SubtleCrypto(nsIGlobalObject* aParent);
 
-  nsPIDOMWindow* GetParentObject() const
+  nsIGlobalObject* GetParentObject() const
   {
-    return mWindow;
+    return mParent;
   }
 
   virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE;
 
   already_AddRefed<Promise> Encrypt(JSContext* cx,
                                     const ObjectOrString& algorithm,
                                     CryptoKey& key,
                                     const CryptoOperationData& data,
@@ -114,15 +114,15 @@ public:
                                       CryptoKey& unwrappingKey,
                                       const ObjectOrString& unwrapAlgorithm,
                                       const ObjectOrString& unwrappedKeyAlgorithm,
                                       bool extractable,
                                       const Sequence<nsString>& keyUsages,
                                       ErrorResult& aRv);
 
 private:
-  nsCOMPtr<nsPIDOMWindow> mWindow;
+  nsCOMPtr<nsIGlobalObject> mParent;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_SubtleCrypto_h
new file mode 100644
--- /dev/null
+++ b/dom/base/crashtests/1118764.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html>
+<body>
+<style>
+#foo {
+  overflow: scroll;
+  height: 100px;
+}
+</style>
+<div id="foo">
+Mozilla Firefox<br>
+Mozilla Firefox<br>
+Mozilla Firefox<br>
+Mozilla Firefox<br>
+Mozilla Firefox<br>
+Mozilla Firefox<br>
+Mozilla Firefox<br>
+Mozilla Firefox<br>
+Mozilla Firefox<br>
+Mozilla Firefox<br>
+Mozilla Firefox<br>
+Mozilla Firefox<br>
+Mozilla Firefox<br>
+Mozilla Firefox<br>
+Mozilla Firefox<br>
+Mozilla Firefox<br>
+Mozilla Firefox<br>
+Mozilla Firefox<br>
+<script>
+foo.createShadowRoot().innerHTML = "<content></content>";
+</script>
+</body>
+</html>
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -3987,16 +3987,40 @@ nsDOMWindowUtils::XpconnectArgument(nsID
 
 NS_IMETHODIMP
 nsDOMWindowUtils::AskPermission(nsIContentPermissionRequest* aRequest)
 {
   nsCOMPtr<nsPIDOMWindow> window = do_QueryReferent(mWindow);
   return nsContentPermissionUtils::AskPermission(aRequest, window->GetCurrentInnerWindow());
 }
 
+NS_IMETHODIMP
+nsDOMWindowUtils::GetFramesConstructed(uint64_t* aResult)
+{
+  nsPresContext* presContext = GetPresContext();
+  if (!presContext) {
+    return NS_ERROR_NOT_AVAILABLE;
+  }
+
+  *aResult = presContext->FramesConstructedCount();
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDOMWindowUtils::GetFramesReflowed(uint64_t* aResult)
+{
+  nsPresContext* presContext = GetPresContext();
+  if (!presContext) {
+    return NS_ERROR_NOT_AVAILABLE;
+  }
+
+  *aResult = presContext->FramesReflowedCount();
+  return NS_OK;
+}
+
 NS_INTERFACE_MAP_BEGIN(nsTranslationNodeList)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
   NS_INTERFACE_MAP_ENTRY(nsITranslationNodeList)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_ADDREF(nsTranslationNodeList)
 NS_IMPL_RELEASE(nsTranslationNodeList)
 
--- a/dom/base/nsHostObjectProtocolHandler.cpp
+++ b/dom/base/nsHostObjectProtocolHandler.cpp
@@ -494,31 +494,30 @@ nsHostObjectProtocolHandler::NewChannel2
   uri->GetSpec(spec);
 
   DataInfo* info = GetDataInfo(spec);
 
   if (!info) {
     return NS_ERROR_DOM_BAD_URI;
   }
 
-  nsCOMPtr<PIFileImpl> blobImpl = do_QueryInterface(info->mObject);
-  if (!blobImpl) {
+  nsCOMPtr<FileImpl> blob = do_QueryInterface(info->mObject);
+  if (!blob) {
     return NS_ERROR_DOM_BAD_URI;
   }
 
 #ifdef DEBUG
   {
     nsCOMPtr<nsIURIWithPrincipal> uriPrinc = do_QueryInterface(uri);
     nsCOMPtr<nsIPrincipal> principal;
     uriPrinc->GetPrincipal(getter_AddRefs(principal));
     NS_ASSERTION(info->mPrincipal == principal, "Wrong principal!");
   }
 #endif
 
-  FileImpl* blob = static_cast<FileImpl*>(blobImpl.get());
   nsCOMPtr<nsIInputStream> stream;
   nsresult rv = blob->GetInternalStream(getter_AddRefs(stream));
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIChannel> channel;
   // Bug 1087720 (and Bug 1099296):
   // Once all callsites have been updated to call NewChannel2() instead of NewChannel()
   // we should have a non-null loadInfo consistently. Until then we have to brach on the
@@ -610,22 +609,21 @@ nsFontTableProtocolHandler::GetScheme(ns
 
 nsresult
 NS_GetBlobForBlobURI(nsIURI* aURI, FileImpl** aBlob)
 {
   NS_ASSERTION(IsBlobURI(aURI), "Only call this with blob URIs");
 
   *aBlob = nullptr;
 
-  nsCOMPtr<PIFileImpl> blobImpl = do_QueryInterface(GetDataObject(aURI));
-  if (!blobImpl) {
+  nsCOMPtr<FileImpl> blob = do_QueryInterface(GetDataObject(aURI));
+  if (!blob) {
     return NS_ERROR_DOM_BAD_URI;
   }
 
-  nsRefPtr<FileImpl> blob = static_cast<FileImpl*>(blobImpl.get());
   blob.forget(aBlob);
   return NS_OK;
 }
 
 nsresult
 NS_GetStreamForBlobURI(nsIURI* aURI, nsIInputStream** aStream)
 {
   nsRefPtr<FileImpl> blobImpl;
--- a/dom/base/nsINode.h
+++ b/dom/base/nsINode.h
@@ -312,17 +312,17 @@ public:
 #ifdef MOZILLA_INTERNAL_API
   explicit nsINode(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
   : mNodeInfo(aNodeInfo),
     mParent(nullptr),
     mBoolFlags(0),
     mNextSibling(nullptr),
     mPreviousSibling(nullptr),
     mFirstChild(nullptr),
-    mSubtreeRoot(MOZ_THIS_IN_INITIALIZER_LIST()),
+    mSubtreeRoot(this),
     mSlots(nullptr)
   {
   }
 #endif
 
   virtual ~nsINode();
 
   /**
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -14343,16 +14343,23 @@ class GlobalGenRoots():
 
         # Add the auto-generated comment.
         curr = CGWrapper(curr, pre=AUTOGENERATED_WARNING_COMMENT)
 
         # Done.
         return curr
 
     @staticmethod
+    def GeneratedEventList(config):
+        eventList = CGList([]);
+        for generatedEvent in config.generatedEvents:
+            eventList.append(CGGeneric(declare=("GENERATED_EVENT(%s)\n" % generatedEvent)))
+        return eventList
+
+    @staticmethod
     def PrototypeList(config):
 
         # Prototype ID enum.
         descriptorsWithPrototype = config.getDescriptors(hasInterfacePrototypeObject=True)
         protos = [d.name for d in descriptorsWithPrototype]
         idEnum = CGNamespacedEnum('id', 'ID', ['_ID_Start'] + protos,
                                   [0, '_ID_Start'])
         idEnum = CGList([idEnum])
@@ -14904,17 +14911,18 @@ class CGEventClass(CGBindingImplClass):
             parentType=self.parentType)
 
         className = descriptor.nativeType.split('::')[-1]
         asConcreteTypeMethod = ClassMethod("As%s" % className,
                                            "%s*" % className,
                                            [],
                                            virtual=True,
                                            body="return this;\n",
-                                           breakAfterReturnDecl=" ")
+                                           breakAfterReturnDecl=" ",
+                                           override=True)
 
         CGClass.__init__(self, className,
                          bases=[ClassBase(self.parentType)],
                          methods=[asConcreteTypeMethod]+self.methodDecls,
                          members=members,
                          extradeclarations=baseDeclarations)
 
     def getWrapObjectBody(self):
--- a/dom/bindings/Configuration.py
+++ b/dom/bindings/Configuration.py
@@ -8,28 +8,29 @@ from collections import defaultdict
 
 autogenerated_comment = "/* THIS FILE IS AUTOGENERATED - DO NOT EDIT */\n"
 
 class Configuration:
     """
     Represents global configuration state based on IDL parse data and
     the configuration file.
     """
-    def __init__(self, filename, parseData):
+    def __init__(self, filename, parseData, generatedEvents=[]):
 
         # Read the configuration file.
         glbl = {}
         execfile(filename, glbl)
         config = glbl['DOMInterfaces']
 
         # Build descriptors for all the interfaces we have in the parse data.
         # This allows callers to specify a subset of interfaces by filtering
         # |parseData|.
         self.descriptors = []
         self.interfaces = {}
+        self.generatedEvents = generatedEvents;
         self.maxProtoChainLength = 0;
         for thing in parseData:
             if isinstance(thing, IDLImplementsStatement):
                 # Our build system doesn't support dep build involving
                 # addition/removal of "implements" statements that appear in a
                 # different .webidl file than their LHS interface.  Make sure we
                 # don't have any of those.
                 #
--- a/dom/bindings/TypedArray.h
+++ b/dom/bindings/TypedArray.h
@@ -131,17 +131,16 @@ public:
     GetLengthAndData(mTypedObj, &mLength, &mData);
     mComputed = true;
   }
 
 private:
   TypedArray_base(const TypedArray_base&) = delete;
 };
 
-
 template<typename T,
          JSObject* UnwrapArray(JSObject*),
          T* GetData(JSObject*, const JS::AutoCheckCannotGC&),
          void GetLengthAndData(JSObject*, uint32_t*, T**),
          JSObject* CreateNew(JSContext*, uint32_t)>
 struct TypedArray : public TypedArray_base<T, UnwrapArray, GetLengthAndData> {
 private:
   typedef TypedArray_base<T, UnwrapArray, GetLengthAndData> Base;
@@ -296,26 +295,24 @@ private:
 // Class for easily setting up a rooted typed array object on the stack
 template<typename ArrayType>
 class MOZ_STACK_CLASS RootedTypedArray : public ArrayType,
                                          private TypedArrayRooter<ArrayType>
 {
 public:
   explicit RootedTypedArray(JSContext* cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM) :
     ArrayType(),
-    TypedArrayRooter<ArrayType>(cx,
-                                MOZ_THIS_IN_INITIALIZER_LIST()
+    TypedArrayRooter<ArrayType>(cx, this
                                 MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT)
   {
   }
 
   RootedTypedArray(JSContext* cx, JSObject* obj MOZ_GUARD_OBJECT_NOTIFIER_PARAM) :
     ArrayType(obj),
-    TypedArrayRooter<ArrayType>(cx,
-                                MOZ_THIS_IN_INITIALIZER_LIST()
+    TypedArrayRooter<ArrayType>(cx, this
                                 MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT)
   {
   }
 };
 
 } // namespace dom
 } // namespace mozilla
 
--- a/dom/bindings/mozwebidlcodegen/__init__.py
+++ b/dom/bindings/mozwebidlcodegen/__init__.py
@@ -124,16 +124,17 @@ class WebIDLCodegenManager(LoggingMixin)
     To facilitate testing, this object is meant to be generic and reusable.
     Paths, etc should be parameters and not hardcoded.
     """
 
     # Global parser derived declaration files.
     GLOBAL_DECLARE_FILES = {
         'FeatureList.h',
         'GeneratedAtomList.h',
+        'GeneratedEventList.h',
         'PrototypeList.h',
         'RegisterBindings.h',
         'RegisterWorkerBindings.h',
         'ResolveSystemBinding.h',
         'UnionConversions.h',
         'UnionTypes.h',
     }
 
@@ -170,16 +171,17 @@ class WebIDLCodegenManager(LoggingMixin)
         self.populate_logger()
 
         input_paths, exported_stems, generated_events_stems, example_interfaces = inputs
 
         self._config_path = config_path
         self._input_paths = set(input_paths)
         self._exported_stems = set(exported_stems)
         self._generated_events_stems = set(generated_events_stems)
+        self._generated_events_stems_as_array = generated_events_stems;
         self._example_interfaces = set(example_interfaces)
         self._exported_header_dir = exported_header_dir
         self._codegen_dir = codegen_dir
         self._state_path = state_path
         self._cache_dir = cache_dir
         self._make_deps_path = make_deps_path
         self._make_deps_target = make_deps_target
 
@@ -319,17 +321,18 @@ class WebIDLCodegenManager(LoggingMixin)
 
         for path in sorted(self._input_paths):
             with open(path, 'rb') as fh:
                 data = fh.read()
                 hashes[path] = hashlib.sha1(data).hexdigest()
                 parser.parse(data, path)
 
         self._parser_results = parser.finish()
-        self._config = Configuration(self._config_path, self._parser_results)
+        self._config = Configuration(self._config_path, self._parser_results,
+                                     self._generated_events_stems_as_array)
         self._input_hashes = hashes
 
     def _write_global_derived(self):
         from Codegen import GlobalGenRoots
 
         things = [('declare', f) for f in self.GLOBAL_DECLARE_FILES]
         things.extend(('define', f) for f in self.GLOBAL_DEFINE_FILES)
 
--- a/dom/bluetooth/bluez/BluetoothDBusService.cpp
+++ b/dom/bluetooth/bluez/BluetoothDBusService.cpp
@@ -41,17 +41,16 @@
 #include "mozilla/dom/bluetooth/BluetoothTypes.h"
 #include "mozilla/Hal.h"
 #include "mozilla/ipc/UnixSocket.h"
 #include "mozilla/ipc/DBusUtils.h"
 #include "mozilla/ipc/RawDBusConnection.h"
 #include "mozilla/LazyIdleThread.h"
 #include "mozilla/Monitor.h"
 #include "mozilla/Mutex.h"
-#include "mozilla/NullPtr.h"
 #include "mozilla/StaticMutex.h"
 #include "mozilla/unused.h"
 
 #if defined(MOZ_WIDGET_GONK)
 #include "cutils/properties.h"
 #include <dlfcn.h>
 #endif
 
--- a/dom/bluetooth2/bluez/BluetoothDBusService.cpp
+++ b/dom/bluetooth2/bluez/BluetoothDBusService.cpp
@@ -40,17 +40,16 @@
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/dom/bluetooth/BluetoothTypes.h"
 #include "mozilla/Hal.h"
 #include "mozilla/ipc/UnixSocket.h"
 #include "mozilla/ipc/DBusUtils.h"
 #include "mozilla/ipc/RawDBusConnection.h"
 #include "mozilla/LazyIdleThread.h"
 #include "mozilla/Mutex.h"
-#include "mozilla/NullPtr.h"
 #include "mozilla/StaticMutex.h"
 #include "mozilla/unused.h"
 
 #if defined(MOZ_WIDGET_GONK)
 #include "cutils/properties.h"
 #include <dlfcn.h>
 #endif
 
--- a/dom/camera/DOMCameraDetectedFace.cpp
+++ b/dom/camera/DOMCameraDetectedFace.cpp
@@ -31,17 +31,17 @@ DOMCameraDetectedFace::WrapObject(JSCont
   return CameraDetectedFaceBinding::Wrap(aCx, this);
 }
 
 DOMCameraDetectedFace::DOMCameraDetectedFace(nsISupports* aParent,
                                              const ICameraControl::Face& aFace)
   : mParent(aParent)
   , mId(aFace.id)
   , mScore(aFace.score)
-  , mBounds(new DOMRect(MOZ_THIS_IN_INITIALIZER_LIST()))
+  , mBounds(new DOMRect(this))
 {
   mBounds->SetRect(aFace.bound.left,
                    aFace.bound.top,
                    aFace.bound.right - aFace.bound.left,
                    aFace.bound.bottom - aFace.bound.top);
 
   if (aFace.hasLeftEye) {
     mLeftEye = new DOMPoint(this, aFace.leftEye.x, aFace.leftEye.y);
--- a/dom/camera/GonkCameraControl.cpp
+++ b/dom/camera/GonkCameraControl.cpp
@@ -35,16 +35,17 @@
 #include <media/mediaplayer.h>
 #include "nsPrintfCString.h"
 #include "nsIObserverService.h"
 #include "nsIVolume.h"
 #include "nsIVolumeService.h"
 #include "AutoRwLock.h"
 #include "GonkCameraHwMgr.h"
 #include "GonkRecorderProfiles.h"
+#include "GrallocImages.h"
 #include "CameraCommon.h"
 #include "GonkCameraParameters.h"
 #include "DeviceStorageFileDescriptor.h"
 
 using namespace mozilla;
 using namespace mozilla::layers;
 using namespace mozilla::gfx;
 using namespace mozilla::ipc;
--- a/dom/camera/GonkCameraHwMgr.cpp
+++ b/dom/camera/GonkCameraHwMgr.cpp
@@ -178,17 +178,23 @@ GonkCameraHardware::Init()
   }
   DOM_CAMERA_LOGI("Sensor orientation: base=%d, offset=%d, final=%d\n", info.orientation, offset, mSensorOrientation);
 
   // Disable shutter sound in android CameraService because gaia camera app will play it
   mCamera->sendCommand(CAMERA_CMD_ENABLE_SHUTTER_SOUND, 0, 0);
 
 #if defined(MOZ_WIDGET_GONK)
 
-#if ANDROID_VERSION >= 19
+#if ANDROID_VERSION >= 21
+  sp<IGraphicBufferProducer> producer;
+  sp<IGonkGraphicBufferConsumer> consumer;
+  GonkBufferQueue::createBufferQueue(&producer, &consumer);
+  mNativeWindow = new GonkNativeWindow(consumer, GonkCameraHardware::MIN_UNDEQUEUED_BUFFERS);
+  mCamera->setPreviewTarget(producer);
+#elif ANDROID_VERSION >= 19
   mNativeWindow = new GonkNativeWindow(GonkCameraHardware::MIN_UNDEQUEUED_BUFFERS);
   sp<GonkBufferQueue> bq = mNativeWindow->getBufferQueue();
   bq->setSynchronousMode(false);
   mCamera->setPreviewTarget(mNativeWindow->getBufferQueue());
 #elif ANDROID_VERSION >= 17
   mNativeWindow = new GonkNativeWindow(GonkCameraHardware::MIN_UNDEQUEUED_BUFFERS);
   sp<GonkBufferQueue> bq = mNativeWindow->getBufferQueue();
   bq->setSynchronousMode(false);
--- a/dom/camera/GonkRecorder.cpp
+++ b/dom/camera/GonkRecorder.cpp
@@ -1149,17 +1149,21 @@ status_t GonkRecorder::setupMediaSource(
     if (mVideoSource == VIDEO_SOURCE_DEFAULT
             || mVideoSource == VIDEO_SOURCE_CAMERA) {
         sp<GonkCameraSource> cameraSource;
         status_t err = setupCameraSource(&cameraSource);
         if (err != OK) {
             return err;
         }
         *mediaSource = cameraSource;
+#if ANDROID_VERSION >= 21
+    } else if (mVideoSource == VIDEO_SOURCE_SURFACE) {
+#else
     } else if (mVideoSource == VIDEO_SOURCE_GRALLOC_BUFFER) {
+#endif
         return BAD_VALUE;
     } else {
         return INVALID_OPERATION;
     }
     return OK;
 }
 
 status_t GonkRecorder::setupCameraSource(
--- a/dom/events/Event.h
+++ b/dom/events/Event.h
@@ -23,19 +23,20 @@
 class nsIContent;
 class nsIDOMEventTarget;
 class nsPresContext;
 
 namespace mozilla {
 namespace dom {
 
 class EventTarget;
-class ErrorEvent;
-class ProgressEvent;
 class WantsPopupControlCheck;
+#define GENERATED_EVENT(EventClass_) class EventClass_;
+#include "mozilla/dom/GeneratedEventList.h"
+#undef GENERATED_EVENT
 
 // Dummy class so we can cast through it to get from nsISupports to
 // Event subclasses with only two non-ambiguous static casts.
 class EventBase : public nsIDOMEvent
 {
 };
 
 class Event : public EventBase,
@@ -90,25 +91,23 @@ public:
   {
     return mOwner;
   }
 
   virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE MOZ_FINAL;
 
   virtual JSObject* WrapObjectInternal(JSContext* aCx);
 
-  virtual ErrorEvent* AsErrorEvent()
-  {
-    return nullptr;
+#define GENERATED_EVENT(EventClass_) \
+  virtual EventClass_* As##EventClass_()  \
+  {                                       \
+    return nullptr;                       \
   }
-
-  virtual ProgressEvent* AsProgressEvent()
-  {
-    return nullptr;
-  }
+#include "mozilla/dom/GeneratedEventList.h"
+#undef GENERATED_EVENT
 
   // nsIDOMEvent Interface
   NS_DECL_NSIDOMEVENT
 
   void InitPresContextData(nsPresContext* aPresContext);
 
   // Returns true if the event should be trusted.
   bool Init(EventTarget* aGlobal);
--- a/dom/events/EventListenerManager.cpp
+++ b/dom/events/EventListenerManager.cpp
@@ -96,16 +96,18 @@ EventListenerManager::EventListenerManag
   : mMayHavePaintEventListener(false)
   , mMayHaveMutationListeners(false)
   , mMayHaveCapturingListeners(false)
   , mMayHaveSystemGroupListeners(false)
   , mMayHaveTouchEventListener(false)
   , mMayHaveScrollWheelEventListener(false)
   , mMayHaveMouseEnterLeaveEventListener(false)
   , mMayHavePointerEnterLeaveEventListener(false)
+  , mMayHaveKeyEventListener(false)
+  , mMayHaveInputOrCompositionEventListener(false)
   , mClearingListeners(false)
   , mIsMainThreadELM(NS_IsMainThread())
   , mNoListenerForEvent(0)
   , mTarget(aTarget)
 {
   NS_ASSERTION(aTarget, "unexpected null pointer");
 
   if (mIsMainThreadELM) {
@@ -381,17 +383,31 @@ EventListenerManager::AddEventListenerIn
 #ifdef MOZ_GAMEPAD
   } else if (aType >= NS_GAMEPAD_START &&
              aType <= NS_GAMEPAD_END) {
     nsPIDOMWindow* window = GetInnerWindowForTarget();
     if (window) {
       window->SetHasGamepadEventListener();
     }
 #endif
+  } else if (aTypeAtom == nsGkAtoms::onkeydown ||
+             aTypeAtom == nsGkAtoms::onkeypress ||
+             aTypeAtom == nsGkAtoms::onkeyup) {
+    if (!aFlags.mInSystemGroup) {
+      mMayHaveKeyEventListener = true;
+    }
+  } else if (aTypeAtom == nsGkAtoms::oncompositionend ||
+             aTypeAtom == nsGkAtoms::oncompositionstart ||
+             aTypeAtom == nsGkAtoms::oncompositionupdate ||
+             aTypeAtom == nsGkAtoms::oninput) {
+    if (!aFlags.mInSystemGroup) {
+      mMayHaveInputOrCompositionEventListener = true;
+    }
   }
+
   if (aTypeAtom && mTarget) {
     mTarget->EventListenerAdded(aTypeAtom);
   }
 }
 
 bool
 EventListenerManager::IsDeviceType(uint32_t aType)
 {
--- a/dom/events/EventListenerManager.h
+++ b/dom/events/EventListenerManager.h
@@ -398,16 +398,29 @@ public:
    * Returns true if there may be a scroll wheel listener registered,
    * false if there definitely isn't.
    */
   bool MayHaveScrollWheelEventListener() { return mMayHaveScrollWheelEventListener; }
 
   bool MayHaveMouseEnterLeaveEventListener() { return mMayHaveMouseEnterLeaveEventListener; }
   bool MayHavePointerEnterLeaveEventListener() { return mMayHavePointerEnterLeaveEventListener; }
 
+  /**
+   * Returns true if there may be a key event listener (keydown, keypress,
+   * or keyup) registered, or false if there definitely isn't.
+   */
+  bool MayHaveKeyEventListener() { return mMayHaveKeyEventListener; }
+
+  /**
+   * Returns true if there may be an advanced input event listener (input,
+   * compositionstart, compositionupdate, or compositionend) registered,
+   * or false if there definitely isn't.
+   */
+  bool MayHaveInputOrCompositionEventListener() { return mMayHaveInputOrCompositionEventListener; }
+
   size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const;
 
   uint32_t ListenerCount() const
   {
     return mListeners.Length();
   }
 
   void MarkForCC();
@@ -548,19 +561,21 @@ protected:
   uint32_t mMayHavePaintEventListener : 1;
   uint32_t mMayHaveMutationListeners : 1;
   uint32_t mMayHaveCapturingListeners : 1;
   uint32_t mMayHaveSystemGroupListeners : 1;
   uint32_t mMayHaveTouchEventListener : 1;
   uint32_t mMayHaveScrollWheelEventListener : 1;
   uint32_t mMayHaveMouseEnterLeaveEventListener : 1;
   uint32_t mMayHavePointerEnterLeaveEventListener : 1;
+  uint32_t mMayHaveKeyEventListener : 1;
+  uint32_t mMayHaveInputOrCompositionEventListener : 1;
   uint32_t mClearingListeners : 1;
   uint32_t mIsMainThreadELM : 1;
-  uint32_t mNoListenerForEvent : 23;
+  uint32_t mNoListenerForEvent : 20;
 
   nsAutoTObserverArray<Listener, 2> mListeners;
   dom::EventTarget* mTarget;  // WEAK
   nsCOMPtr<nsIAtom> mNoListenerForEventAtom;
 
   friend class ELMCreationDetector;
   static uint32_t sMainThreadCreatedCount;
 };
--- a/dom/events/IMEStateManager.cpp
+++ b/dom/events/IMEStateManager.cpp
@@ -4,16 +4,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "prlog.h"
 
 #include "mozilla/IMEStateManager.h"
 
 #include "mozilla/Attributes.h"
+#include "mozilla/EventListenerManager.h"
 #include "mozilla/EventStates.h"
 #include "mozilla/MouseEvents.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Services.h"
 #include "mozilla/TextComposition.h"
 #include "mozilla/TextEvents.h"
 #include "mozilla/dom/HTMLFormElement.h"
 
@@ -176,31 +177,36 @@ GetNotifyIMEMessageName(IMEMessage aMess
 }
 #endif // #ifdef PR_LOGGING
 
 nsIContent* IMEStateManager::sContent = nullptr;
 nsPresContext* IMEStateManager::sPresContext = nullptr;
 bool IMEStateManager::sInstalledMenuKeyboardListener = false;
 bool IMEStateManager::sIsTestingIME = false;
 bool IMEStateManager::sIsGettingNewIMEState = false;
+bool IMEStateManager::sCheckForIMEUnawareWebApps = false;
 
 // sActiveIMEContentObserver points to the currently active IMEContentObserver.
 // sActiveIMEContentObserver is null if there is no focused editor.
 IMEContentObserver* IMEStateManager::sActiveIMEContentObserver = nullptr;
 TextCompositionArray* IMEStateManager::sTextCompositions = nullptr;
 
 // static
 void
 IMEStateManager::Init()
 {
 #ifdef PR_LOGGING
   if (!sISMLog) {
     sISMLog = PR_NewLogModule("IMEStateManager");
   }
 #endif
+  Preferences::AddBoolVarCache(
+    &sCheckForIMEUnawareWebApps,
+    "intl.ime.hack.on_ime_unaware_apps.fire_key_events_for_composition",
+    false);
 }
 
 // static
 void
 IMEStateManager::Shutdown()
 {
   PR_LOG(sISMLog, PR_LOG_ALWAYS,
     ("ISM: IMEStateManager::Shutdown(), "
@@ -742,16 +748,35 @@ public:
     }
     return NS_OK;
   }
 
 private:
   uint32_t mState;
 };
 
+static bool
+MayBeIMEUnawareWebApp(nsINode* aNode)
+{
+  bool haveKeyEventsListener = false;
+
+  while (aNode) {
+    EventListenerManager* const mgr = aNode->GetExistingListenerManager();
+    if (mgr) {
+      if (mgr->MayHaveInputOrCompositionEventListener()) {
+        return false;
+      }
+      haveKeyEventsListener |= mgr->MayHaveKeyEventListener();
+    }
+    aNode = aNode->GetParentNode();
+  }
+
+  return haveKeyEventsListener;
+}
+
 // static
 void
 IMEStateManager::SetIMEState(const IMEState& aState,
                              nsIContent* aContent,
                              nsIWidget* aWidget,
                              InputContextAction aAction)
 {
   PR_LOG(sISMLog, PR_LOG_ALWAYS,
@@ -764,16 +789,19 @@ IMEStateManager::SetIMEState(const IMESt
 
   NS_ENSURE_TRUE_VOID(aWidget);
 
   InputContext oldContext = aWidget->GetInputContext();
 
   InputContext context;
   context.mIMEState = aState;
 
+  context.mMayBeIMEUnaware = context.mIMEState.IsEditable() &&
+    sCheckForIMEUnawareWebApps && MayBeIMEUnawareWebApp(aContent);
+
   if (aContent && aContent->GetNameSpaceID() == kNameSpaceID_XHTML &&
       (aContent->Tag() == nsGkAtoms::input ||
        aContent->Tag() == nsGkAtoms::textarea)) {
     if (aContent->Tag() != nsGkAtoms::textarea) {
       // <input type=number> has an anonymous <input type=text> descendant
       // that gets focus whenever anyone tries to focus the number control. We
       // need to check if aContent is one of those anonymous text controls and,
       // if so, use the number control instead:
--- a/dom/events/IMEStateManager.h
+++ b/dom/events/IMEStateManager.h
@@ -159,16 +159,17 @@ protected:
 
   static bool IsEditableIMEState(nsIWidget* aWidget);
 
   static nsIContent*    sContent;
   static nsPresContext* sPresContext;
   static bool           sInstalledMenuKeyboardListener;
   static bool           sIsTestingIME;
   static bool           sIsGettingNewIMEState;
+  static bool           sCheckForIMEUnawareWebApps;
 
   class MOZ_STACK_CLASS GettingNewIMEStateBlocker MOZ_FINAL
   {
   public:
     GettingNewIMEStateBlocker()
       : mOldValue(IMEStateManager::sIsGettingNewIMEState)
     {
       IMEStateManager::sIsGettingNewIMEState = true;
--- a/dom/events/KeyNameList.h
+++ b/dom/events/KeyNameList.h
@@ -24,16 +24,17 @@
  * Special Key Values
  *****************************************************************************/
 DEFINE_KEYNAME_WITH_SAME_NAME(Unidentified)
 
 /******************************************************************************
  * Our Internal Key Values (must have "Moz" prefix)
  *****************************************************************************/
 DEFINE_KEYNAME_INTERNAL(PrintableKey, "MozPrintableKey")
+DEFINE_KEYNAME_INTERNAL(HomeScreen, "MozHomeScreen")
 
 /******************************************************************************
  * Modifier Keys
  *****************************************************************************/
 DEFINE_KEYNAME_WITH_SAME_NAME(Alt)
 DEFINE_KEYNAME_WITH_SAME_NAME(AltGraph)
 DEFINE_KEYNAME_WITH_SAME_NAME(CapsLock)
 DEFINE_KEYNAME_WITH_SAME_NAME(Control)
--- a/dom/html/HTMLAnchorElement.h
+++ b/dom/html/HTMLAnchorElement.h
@@ -23,17 +23,17 @@ class HTMLAnchorElement MOZ_FINAL : publ
                                     public Link
 {
 public:
   using Element::GetText;
   using Element::SetText;
 
   explicit HTMLAnchorElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
     : nsGenericHTMLElement(aNodeInfo)
-    , Link(MOZ_THIS_IN_INITIALIZER_LIST())
+    , Link(this)
   {
   }
 
   // nsISupports
   NS_DECL_ISUPPORTS_INHERITED
 
   // CC
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLAnchorElement,
--- a/dom/html/HTMLAreaElement.cpp
+++ b/dom/html/HTMLAreaElement.cpp
@@ -14,17 +14,17 @@
 
 NS_IMPL_NS_NEW_HTML_ELEMENT(Area)
 
 namespace mozilla {
 namespace dom {
 
 HTMLAreaElement::HTMLAreaElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
   : nsGenericHTMLElement(aNodeInfo)
-  , Link(MOZ_THIS_IN_INITIALIZER_LIST())
+  , Link(this)
 {
 }
 
 HTMLAreaElement::~HTMLAreaElement()
 {
 }
 
 NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(HTMLAreaElement)
--- a/dom/html/HTMLFormElement.cpp
+++ b/dom/html/HTMLFormElement.cpp
@@ -83,17 +83,17 @@ static const nsAttrValue::EnumTable kFor
 // Default autocomplete value is 'on'.
 static const nsAttrValue::EnumTable* kFormDefaultAutocomplete = &kFormAutocompleteTable[0];
 
 bool HTMLFormElement::gFirstFormSubmitted = false;
 bool HTMLFormElement::gPasswordManagerInitialized = false;
 
 HTMLFormElement::HTMLFormElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
   : nsGenericHTMLElement(aNodeInfo),
-    mControls(new HTMLFormControlsCollection(MOZ_THIS_IN_INITIALIZER_LIST())),
+    mControls(new HTMLFormControlsCollection(this)),
     mSelectedRadioButtons(2),
     mRequiredRadioButtonCounts(2),
     mValueMissingRadioGroups(2),
     mGeneratingSubmit(false),
     mGeneratingReset(false),
     mIsSubmitting(false),
     mDeferSubmission(false),
     mNotifiedObservers(false),
--- a/dom/html/HTMLLinkElement.cpp
+++ b/dom/html/HTMLLinkElement.cpp
@@ -32,17 +32,17 @@
 
 NS_IMPL_NS_NEW_HTML_ELEMENT(Link)
 
 namespace mozilla {
 namespace dom {
 
 HTMLLinkElement::HTMLLinkElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
   : nsGenericHTMLElement(aNodeInfo)
-  , Link(MOZ_THIS_IN_INITIALIZER_LIST())
+  , Link(this)
 {
 }
 
 HTMLLinkElement::~HTMLLinkElement()
 {
 }
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(HTMLLinkElement)
--- a/dom/html/HTMLSelectElement.cpp
+++ b/dom/html/HTMLSelectElement.cpp
@@ -99,17 +99,17 @@ SafeOptionListMutation::~SafeOptionListM
 //
 
 // construction, destruction
 
 
 HTMLSelectElement::HTMLSelectElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo,
                                      FromParser aFromParser)
   : nsGenericHTMLFormElementWithState(aNodeInfo),
-    mOptions(new HTMLOptionsCollection(MOZ_THIS_IN_INITIALIZER_LIST())),
+    mOptions(new HTMLOptionsCollection(this)),
     mAutocompleteAttrState(nsContentUtils::eAutocompleteAttrState_Unknown),
     mIsDoneAddingChildren(!aFromParser),
     mDisabledChanged(false),
     mMutating(false),
     mInhibitStateRestoration(!!(aFromParser & FROM_PARSER_FRAGMENT)),
     mSelectionHasChanged(false),
     mDefaultSelectionSet(false),
     mCanShowInvalidUI(true),
--- a/dom/html/HTMLTextAreaElement.cpp
+++ b/dom/html/HTMLTextAreaElement.cpp
@@ -56,17 +56,17 @@ HTMLTextAreaElement::HTMLTextAreaElement
   : nsGenericHTMLFormElementWithState(aNodeInfo),
     mValueChanged(false),
     mHandlingSelect(false),
     mDoneAddingChildren(!aFromParser),
     mInhibitStateRestoration(!!(aFromParser & FROM_PARSER_FRAGMENT)),
     mDisabledChanged(false),
     mCanShowInvalidUI(true),
     mCanShowValidUI(true),
-    mState(MOZ_THIS_IN_INITIALIZER_LIST())
+    mState(this)
 {
   AddMutationObserver(this);
 
   // Set up our default state.  By default we're enabled (since we're
   // a control type that can be disabled but not actually disabled
   // right now), optional, and valid.  We are NOT readwrite by default
   // until someone calls UpdateEditableState on us, apparently!  Also
   // by default we don't have to show validity UI and so forth.
--- a/dom/html/TimeRanges.cpp
+++ b/dom/html/TimeRanges.cpp
@@ -151,20 +151,20 @@ TimeRanges::Intersection(const TimeRange
       j += 1;
     }
   }
 
   mRanges = intersection;
 }
 
 TimeRanges::index_type
-TimeRanges::Find(double aTime)
+TimeRanges::Find(double aTime, double aError /* = 0 */)
 {
   for (index_type i = 0; i < mRanges.Length(); ++i) {
-    if (aTime >= mRanges[i].mStart && aTime < mRanges[i].mEnd) {
+    if (aTime < mRanges[i].mEnd && (aTime + aError) >= mRanges[i].mStart) {
       return i;
     }
   }
   return NoIndex;
 }
 
 JSObject*
 TimeRanges::WrapObject(JSContext* aCx)
--- a/dom/html/TimeRanges.h
+++ b/dom/html/TimeRanges.h
@@ -86,17 +86,17 @@ private:
   };
 
   nsAutoTArray<TimeRange,4> mRanges;
 
 public:
   typedef nsTArray<TimeRange>::index_type index_type;
   static const index_type NoIndex = index_type(-1);
 
-  index_type Find(double aTime);
+  index_type Find(double aTime, double aError = 0);
 
   bool Contains(double aStart, double aEnd) {
     index_type target = Find(aStart);
     if (target == NoIndex) {
       return false;
     }
 
     return mRanges[target].mEnd >= aEnd;
--- a/dom/indexedDB/FileSnapshot.cpp
+++ b/dom/indexedDB/FileSnapshot.cpp
@@ -26,28 +26,30 @@ FileImplSnapshot::FileImplSnapshot(const
                                    nsIFile* aFile,
                                    IDBFileHandle* aFileHandle,
                                    FileInfo* aFileInfo)
   : FileImplBase(aName,
                  aContentType,
                  aMetadataParams->Size(),
                  aMetadataParams->LastModified())
   , mFile(aFile)
-  , mFileHandle(aFileHandle)
   , mWholeFile(true)
 {
   AssertSanity();
   MOZ_ASSERT(aMetadataParams);
   MOZ_ASSERT(aMetadataParams->Size() != UINT64_MAX);
   MOZ_ASSERT(aMetadataParams->LastModified() != INT64_MAX);
   MOZ_ASSERT(aFile);
   MOZ_ASSERT(aFileHandle);
   MOZ_ASSERT(aFileInfo);
 
   mFileInfos.AppendElement(aFileInfo);
+
+  mFileHandle =
+    do_GetWeakReference(NS_ISUPPORTS_CAST(EventTarget*, aFileHandle));
 }
 
 // Create slice
 FileImplSnapshot::FileImplSnapshot(const FileImplSnapshot* aOther,
                                    uint64_t aStart,
                                    uint64_t aLength,
                                    const nsAString& aContentType)
   : FileImplBase(aContentType, aOther->mStart + aStart, aLength)
@@ -83,49 +85,29 @@ FileImplSnapshot::AssertSanity()
   MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
   MOZ_ASSERT(NS_IsMainThread());
 }
 
 #endif // DEBUG
 
 NS_IMPL_ISUPPORTS_INHERITED(FileImplSnapshot, FileImpl, PIFileImplSnapshot)
 
-void
-FileImplSnapshot::Unlink()
-{
-  AssertSanity();
-
-  FileImplSnapshot* tmp = this;
-  NS_IMPL_CYCLE_COLLECTION_UNLINK(mFileHandle);
-}
-
-void
-FileImplSnapshot::Traverse(nsCycleCollectionTraversalCallback &cb)
-{
-  AssertSanity();
-
-  FileImplSnapshot* tmp = this;
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFileHandle);
-}
-
-bool
-FileImplSnapshot::IsCCed() const
-{
-  AssertSanity();
-
-  return true;
-}
-
 nsresult
 FileImplSnapshot::GetInternalStream(nsIInputStream** aStream)
 {
   AssertSanity();
 
-  nsresult rv = mFileHandle->OpenInputStream(mWholeFile, mStart, mLength,
-                                             aStream);
+  nsCOMPtr<EventTarget> et = do_QueryReferent(mFileHandle);
+  nsRefPtr<IDBFileHandle> fileHandle = static_cast<IDBFileHandle*>(et.get());
+  if (!fileHandle) {
+    return NS_ERROR_DOM_FILEHANDLE_INACTIVE_ERR;
+  }
+
+  nsresult rv = fileHandle->OpenInputStream(mWholeFile, mStart, mLength,
+                                            aStream);
   if (NS_FAILED(rv)) {
     return rv;
   }
 
   return NS_OK;
 }
 
 already_AddRefed<FileImpl>
--- a/dom/indexedDB/FileSnapshot.h
+++ b/dom/indexedDB/FileSnapshot.h
@@ -7,16 +7,17 @@
 #ifndef mozilla_dom_indexeddb_filesnapshot_h__
 #define mozilla_dom_indexeddb_filesnapshot_h__
 
 #include "mozilla/Attributes.h"
 #include "mozilla/dom/File.h"
 #include "nsAutoPtr.h"
 #include "nsCOMPtr.h"
 #include "nsISupports.h"
+#include "nsWeakPtr.h"
 
 #define FILEIMPLSNAPSHOT_IID \
   {0x0dfc11b1, 0x75d3, 0x473b, {0x8c, 0x67, 0xb7, 0x23, 0xf4, 0x67, 0xd6, 0x73}}
 
 class PIFileImplSnapshot : public nsISupports
 {
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(FILEIMPLSNAPSHOT_IID)
@@ -35,17 +36,17 @@ class IDBFileHandle;
 
 class FileImplSnapshot MOZ_FINAL
   : public FileImplBase
   , public PIFileImplSnapshot
 {
   typedef mozilla::dom::MetadataParameters MetadataParameters;
 
   nsCOMPtr<nsIFile> mFile;
-  nsRefPtr<IDBFileHandle> mFileHandle;
+  nsWeakPtr mFileHandle;
 
   bool mWholeFile;
 
 public:
   // Create as a stored file
   FileImplSnapshot(const nsAString& aName,
                    const nsAString& aContentType,
                    MetadataParameters* aMetadataParams,
@@ -73,24 +74,20 @@ private:
 #endif
 
   virtual void
   GetMozFullPathInternal(nsAString& aFullPath, ErrorResult& aRv) MOZ_OVERRIDE;
 
   virtual nsresult
   GetInternalStream(nsIInputStream** aStream) MOZ_OVERRIDE;
 
-  virtual void
-  Unlink() MOZ_OVERRIDE;
-
-  virtual void
-  Traverse(nsCycleCollectionTraversalCallback &aCb) MOZ_OVERRIDE;
-
-  virtual bool
-  IsCCed() const MOZ_OVERRIDE;
+  virtual bool MayBeClonedToOtherThreads() const MOZ_OVERRIDE
+  {
+    return false;
+  }
 
   virtual already_AddRefed<FileImpl>
   CreateSlice(uint64_t aStart,
               uint64_t aLength,
               const nsAString& aContentType,
               ErrorResult& aRv) MOZ_OVERRIDE;
 
   virtual bool
--- a/dom/indexedDB/IDBFileHandle.cpp
+++ b/dom/indexedDB/IDBFileHandle.cpp
@@ -82,16 +82,17 @@ IDBFileHandle::MutableFile() const
   return mMutableFile;
 }
 
 NS_IMPL_CYCLE_COLLECTION_INHERITED(IDBFileHandle, DOMEventTargetHelper,
                                    mMutableFile)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(IDBFileHandle)
   NS_INTERFACE_MAP_ENTRY(nsIRunnable)
+  NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
 
 NS_IMPL_ADDREF_INHERITED(IDBFileHandle, DOMEventTargetHelper)
 NS_IMPL_RELEASE_INHERITED(IDBFileHandle, DOMEventTargetHelper)
 
 nsresult
 IDBFileHandle::PreHandleEvent(EventChainPreVisitor& aVisitor)
 {
--- a/dom/indexedDB/IDBFileHandle.h
+++ b/dom/indexedDB/IDBFileHandle.h
@@ -10,31 +10,33 @@
 #include "IDBFileRequest.h"
 #include "js/TypeDecls.h"
 #include "MainThreadUtils.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/dom/FileHandle.h"
 #include "mozilla/DOMEventTargetHelper.h"
 #include "nsCycleCollectionParticipant.h"
+#include "nsWeakReference.h"
 
 class nsPIDOMWindow;
 
 namespace mozilla {
 namespace dom {
 
 struct IDBFileMetadataParameters;
 
 namespace indexedDB {
 
 class IDBMutableFile;
 
 class IDBFileHandle MOZ_FINAL : public DOMEventTargetHelper,
                                 public nsIRunnable,
-                                public FileHandleBase
+                                public FileHandleBase,
+                                public nsSupportsWeakReference
 {
 public:
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_NSIRUNNABLE
 
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(IDBFileHandle, DOMEventTargetHelper)
 
   static already_AddRefed<IDBFileHandle>
--- a/dom/interfaces/base/nsIDOMCrypto.idl
+++ b/dom/interfaces/base/nsIDOMCrypto.idl
@@ -1,14 +1,14 @@
 /* -*- Mode: IDL; 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 "nsISupports.idl"
 
-interface nsIDOMWindow;
+interface nsIGlobalObject;
 
-[uuid(729cfcad-11b4-4338-b97e-5c023ae295fa)]
+[uuid(48d7f7fd-bb85-4c04-9b8b-5cd9131acdef)]
 interface nsIDOMCrypto : nsISupports
 {
-  [notxpcom] void init(in nsIDOMWindow window);
+  [notxpcom] void init(in nsIGlobalObject parent);
 };
--- a/dom/interfaces/base/nsIDOMWindowUtils.idl
+++ b/dom/interfaces/base/nsIDOMWindowUtils.idl
@@ -46,17 +46,17 @@ interface nsIDOMClientRect;
 interface nsIURI;
 interface nsIDOMEventTarget;
 interface nsIRunnable;
 interface nsICompositionStringSynthesizer;
 interface nsITranslationNodeList;
 interface nsIJSRAIIHelper;
 interface nsIContentPermissionRequest;
 
-[scriptable, uuid(4922a706-a17e-48e0-ab6f-9fe1bbe4e5f7)]
+[scriptable, uuid(0281e107-394d-4c96-830b-2f830b07c6c0)]
 interface nsIDOMWindowUtils : nsISupports {
 
   /**
    * Image animation mode of the window. When this attribute's value
    * is changed, the implementation should set all images in the window
    * to the given value. That is, when set to kDontAnimMode, all images
    * will stop animating. The attribute's value must be one of the
    * animationMode values from imgIContainer.
@@ -1747,16 +1747,31 @@ interface nsIDOMWindowUtils : nsISupport
      */
     void xpconnectArgument(in nsIDOMWindowUtils aThis);
 
     /**
      * Helper for JS components that need to send permission requests with
      * e10s support properly.
      */
      void askPermission(in nsIContentPermissionRequest aRequest);
+
+  /**
+   * Number of frames constructed (excluding breaking) for the curent
+   * document.
+   *
+   * May throw NS_ERROR_NOT_AVAILABLE.
+   */
+  readonly attribute unsigned long long framesConstructed;
+
+  /**
+   * Number of frames reflowed for the curent document.
+   *
+   * May throw NS_ERROR_NOT_AVAILABLE.
+   */
+  readonly attribute unsigned long long framesReflowed;
 };
 
 [scriptable, uuid(c694e359-7227-4392-a138-33c0cc1f15a6)]
 interface nsITranslationNodeList : nsISupports {
   readonly attribute unsigned long length;
   nsIDOMNode item(in unsigned long index);
 
   // A translation root is a block element, or an inline element
--- a/dom/ipc/Blob.cpp
+++ b/dom/ipc/Blob.cpp
@@ -2102,21 +2102,18 @@ public:
   IsSizeUnknown() const MOZ_OVERRIDE;
 
   virtual bool
   IsDateUnknown() const MOZ_OVERRIDE;
 
   virtual bool
   IsFile() const MOZ_OVERRIDE;
 
-  virtual void
-  Unlink() MOZ_OVERRIDE;
-
-  virtual void
-  Traverse(nsCycleCollectionTraversalCallback& aCallback) MOZ_OVERRIDE;
+  virtual bool
+  MayBeClonedToOtherThreads() const MOZ_OVERRIDE;
 
   virtual BlobChild*
   GetBlobChild() MOZ_OVERRIDE;
 
   virtual BlobParent*
   GetBlobParent() MOZ_OVERRIDE;
 
 private:
@@ -2835,28 +2832,21 @@ RemoteBlobImpl::IsDateUnknown() const
 
 bool
 BlobParent::
 RemoteBlobImpl::IsFile() const
 {
   return mBlobImpl->IsFile();
 }
 
-void
+bool
 BlobParent::
-RemoteBlobImpl::Unlink()
+RemoteBlobImpl::MayBeClonedToOtherThreads() const
 {
-  return mBlobImpl->Unlink();
-}
-
-void
-BlobParent::
-RemoteBlobImpl::Traverse(nsCycleCollectionTraversalCallback& aCallback)
-{
-  return mBlobImpl->Traverse(aCallback);
+  return mBlobImpl->MayBeClonedToOtherThreads();
 }
 
 BlobChild*
 BlobParent::
 RemoteBlobImpl::GetBlobChild()
 {
   return nullptr;
 }
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -2484,16 +2484,30 @@ ContentChild::RecvLoadPluginResult(const
 bool
 ContentChild::RecvAssociatePluginId(const uint32_t& aPluginId,
                                     const base::ProcessId& aProcessId)
 {
     plugins::PluginModuleContentParent::AssociatePluginId(aPluginId, aProcessId);
     return true;
 }
 
+bool
+ContentChild::RecvShutdown()
+{
+    nsCOMPtr<nsIObserverService> os = services::GetObserverService();
+    if (os) {
+        os->NotifyObservers(this, "content-child-shutdown", nullptr);
+    }
+
+    // Ignore errors here. If this fails, the parent will kill us after a
+    // timeout.
+    unused << SendFinishShutdown();
+    return true;
+}
+
 PBrowserOrId
 ContentChild::GetBrowserOrId(TabChild* aTabChild)
 {
     if (!aTabChild ||
         this == aTabChild->Manager()) {
         return PBrowserOrId(aTabChild);
     }
     else {
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -372,16 +372,17 @@ public:
                                       const bool& aResult) MOZ_OVERRIDE;
 
     virtual bool RecvStartProfiler(const uint32_t& aEntries,
                                    const double& aInterval,
                                    const nsTArray<nsCString>& aFeatures,
                                    const nsTArray<nsCString>& aThreadNameFilters) MOZ_OVERRIDE;
     virtual bool RecvStopProfiler() MOZ_OVERRIDE;
     virtual bool RecvGetProfile(nsCString* aProfile) MOZ_OVERRIDE;
+    virtual bool RecvShutdown() MOZ_OVERRIDE;
 
 #ifdef ANDROID
     gfxIntSize GetScreenSize() { return mScreenSize; }
 #endif
 
     // Get the directory for IndexedDB files. We query the parent for this and
     // cache the value
     nsString &GetIndexedDBPath();
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -111,16 +111,17 @@
 #include "nsIMutable.h"
 #include "nsIObserverService.h"
 #include "nsIPresShell.h"
 #include "nsIScriptError.h"
 #include "nsISiteSecurityService.h"
 #include "nsISpellChecker.h"
 #include "nsIStyleSheet.h"
 #include "nsISupportsPrimitives.h"
+#include "nsITimer.h"
 #include "nsIURIFixup.h"
 #include "nsIWindowWatcher.h"
 #include "nsIXULRuntime.h"
 #include "nsMemoryInfoDumper.h"
 #include "nsMemoryReporterManager.h"
 #include "nsServiceManagerUtils.h"
 #include "nsStyleSheetService.h"
 #include "nsThreadUtils.h"
@@ -581,16 +582,17 @@ static uint64_t gContentChildID = 1;
 
 // We want the prelaunched process to know that it's for apps, but not
 // actually for any app in particular.  Use a magic manifest URL.
 // Can't be a static constant.
 #define MAGIC_PREALLOCATED_APP_MANIFEST_URL NS_LITERAL_STRING("{{template}}")
 
 static const char* sObserverTopics[] = {
     "xpcom-shutdown",
+    "profile-before-change",
     NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC,
     "child-memory-reporter-request",
     "memory-pressure",
     "child-gc-request",
     "child-cc-request",
     "child-mmu-request",
     "last-pb-context-exited",
     "file-watcher-update",
@@ -1491,43 +1493,66 @@ ContentParent::TransformPreallocatedInto
 {
     // Reset mAppManifestURL, mIsForBrowser and mOSPrivileges for browser.
     mOpener = aOpener;
     mAppManifestURL.Truncate();
     mIsForBrowser = true;
 }
 
 void
-ContentParent::ShutDownProcess(bool aCloseWithError)
-{
+ContentParent::ShutDownProcess(ShutDownMethod aMethod)
+{
+#ifdef MOZ_NUWA_PROCESS
+    if (aMethod == SEND_SHUTDOWN_MESSAGE && IsNuwaProcess()) {
+        // We shouldn't send shutdown messages to frozen Nuwa processes,
+        // so just close the channel.
+        aMethod = CLOSE_CHANNEL;
+    }
+#endif
+
+    // Shutting down by sending a shutdown message works differently than the
+    // other methods. We first call Shutdown() in the child. After the child is
+    // ready, it calls FinishShutdown() on us. Then we close the channel.
+    if (aMethod == SEND_SHUTDOWN_MESSAGE) {
+        if (mIPCOpen && !mShutdownPending && SendShutdown()) {
+            mShutdownPending = true;
+            // Start the force-kill timer if we haven't already.
+            StartForceKillTimer();
+        }
+
+        // If call was not successful, the channel must have been broken
+        // somehow, and we will clean up the error in ActorDestroy.
+        return;
+    }
+
     using mozilla::dom::quota::QuotaManager;
 
     if (QuotaManager* quotaManager = QuotaManager::Get()) {
         quotaManager->AbortCloseStoragesForProcess(this);
     }
 
     // If Close() fails with an error, we'll end up back in this function, but
-    // with aCloseWithError = true.  It's important that we call
+    // with aMethod = CLOSE_CHANNEL_WITH_ERROR.  It's important that we call
     // CloseWithError() in this case; see bug 895204.
 
-    if (!aCloseWithError && !mCalledClose) {
+    if (aMethod == CLOSE_CHANNEL && !mCalledClose) {
         // Close() can only be called once: It kicks off the destruction
         // sequence.
         mCalledClose = true;
         Close();
 #ifdef MOZ_NUWA_PROCESS
         // Kill Nuwa process forcibly to break its IPC channels and finalize
         // corresponding parents.
         if (IsNuwaProcess()) {
             KillHard();
         }
 #endif
     }
 
-    if (aCloseWithError && !mCalledCloseWithError) {
+    if (aMethod == CLOSE_CHANNEL_WITH_ERROR && !mCalledCloseWithError) {
         MessageChannel* channel = GetIPCChannel();
         if (channel) {
             mCalledCloseWithError = true;
             channel->CloseWithError();
         }
     }
 
     const InfallibleTArray<POfflineCacheUpdateParent*>& ocuParents =
@@ -1544,16 +1569,27 @@ ContentParent::ShutDownProcess(bool aClo
 
     // A ContentParent object might not get freed until after XPCOM shutdown has
     // shut down the cycle collector.  But by then it's too late to release any
     // CC'ed objects, so we need to null them out here, while we still can.  See
     // bug 899761.
     ShutDownMessageManager();
 }
 
+bool
+ContentParent::RecvFinishShutdown()
+{
+    // At this point, we already called ShutDownProcess once with
+    // SEND_SHUTDOWN_MESSAGE. To actually close the channel, we call
+    // ShutDownProcess again with CLOSE_CHANNEL.
+    MOZ_ASSERT(mShutdownPending);
+    ShutDownProcess(CLOSE_CHANNEL);
+    return true;
+}
+
 void
 ContentParent::ShutDownMessageManager()
 {
   if (!mMessageManager) {
     return;
   }
 
   mMessageManager->ReceiveMessage(
@@ -1739,22 +1775,35 @@ struct DelayedDeleteContentParentTask : 
     nsRefPtr<ContentParent> mObj;
 };
 
 }
 
 void
 ContentParent::ActorDestroy(ActorDestroyReason why)
 {
-    if (mForceKillTask) {
-        mForceKillTask->Cancel();
-        mForceKillTask = nullptr;
+    if (mForceKillTimer) {
+        mForceKillTimer->Cancel();
+        mForceKillTimer = nullptr;
     }
 
-    ShutDownMessageManager();
+    // Signal shutdown completion regardless of error state, so we can
+    // finish waiting in the xpcom-shutdown/profile-before-change observer.
+    mIPCOpen = false;
+
+    if (why == NormalShutdown && !mCalledClose) {
+        // If we shut down normally but haven't called Close, assume somebody
+        // else called Close on us. In that case, we still need to call
+        // ShutDownProcess below to perform other necessary clean up.
+        mCalledClose = true;
+    }
+
+    // Make sure we always clean up.
+    ShutDownProcess(why == NormalShutdown ? CLOSE_CHANNEL
+                                          : CLOSE_CHANNEL_WITH_ERROR);
 
     nsRefPtr<ContentParent> kungFuDeathGrip(this);
     nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
     if (obs) {
         size_t length = ArrayLength(sObserverTopics);
         for (size_t i = 0; i < length; ++i) {
             obs->RemoveObserver(static_cast<nsIObserver*>(this),
                                 sObserverTopics[i]);
@@ -1783,18 +1832,16 @@ ContentParent::ActorDestroy(ActorDestroy
         sNuwaPrefUpdates = nullptr;
     }
 #endif
 
     RecvRemoveGeolocationListener();
 
     mConsoleService = nullptr;
 
-    MarkAsDead();
-
     if (obs) {
         nsRefPtr<nsHashPropertyBag> props = new nsHashPropertyBag();
 
         props->SetPropertyAsUint64(NS_LITERAL_STRING("childID"), mChildID);
 
         if (AbnormalShutdown == why) {
             Telemetry::Accumulate(Telemetry::SUBPROCESS_ABNORMAL_ABORT,
                                   NS_LITERAL_CSTRING("content"), 1);
@@ -1836,21 +1883,16 @@ ContentParent::ActorDestroy(ActorDestroy
             }
 #endif
         }
         obs->NotifyObservers((nsIPropertyBag2*) props, "ipc:content-shutdown", nullptr);
     }
 
     mIdleListeners.Clear();
 
-    // If the child process was terminated due to a SIGKIL, ShutDownProcess
-    // might not have been called yet.  We must call it to ensure that our
-    // channel is closed, etc.
-    ShutDownProcess(/* closeWithError */ true);
-
     MessageLoop::current()->
         PostTask(FROM_HERE,
                  NewRunnableFunction(DelayedDeleteSubprocess, mSubprocess));
     mSubprocess = nullptr;
 
     // IPDL rules require actors to live on past ActorDestroy, but it
     // may be that the kungFuDeathGrip above is the last reference to
     // |this|.  If so, when we go out of scope here, we're deleted and
@@ -1864,17 +1906,17 @@ ContentParent::ActorDestroy(ActorDestroy
     ContentProcessManager *cpm = ContentProcessManager::GetSingleton();
     nsTArray<ContentParentId> childIDArray =
         cpm->GetAllChildProcessById(this->ChildID());
     for(uint32_t i = 0; i < childIDArray.Length(); i++) {
         ContentParent* cp = cpm->GetContentProcessById(childIDArray[i]);
         MessageLoop::current()->PostTask(
             FROM_HERE,
             NewRunnableMethod(cp, &ContentParent::ShutDownProcess,
-                              /* closeWithError */ false));
+                              CLOSE_CHANNEL));
     }
     cpm->RemoveContentProcess(this->ChildID());
 }
 
 void
 ContentParent::NotifyTabDestroying(PBrowserParent* aTab)
 {
     // There can be more than one PBrowser for a given app process
@@ -1886,44 +1928,56 @@ ContentParent::NotifyTabDestroying(PBrow
     ++mNumDestroyingTabs;
     if (mNumDestroyingTabs != numLiveTabs) {
         return;
     }
 
     // We're dying now, so prevent this content process from being
     // recycled during its shutdown procedure.
     MarkAsDead();
-
-    MOZ_ASSERT(!mForceKillTask);
+    StartForceKillTimer();
+}
+
+void
+ContentParent::StartForceKillTimer()
+{
+    if (mForceKillTimer || !mIPCOpen) {
+        return;
+    }
+
     int32_t timeoutSecs =
         Preferences::GetInt("dom.ipc.tabs.shutdownTimeoutSecs", 5);
     if (timeoutSecs > 0) {
-        MessageLoop::current()->PostDelayedTask(
-            FROM_HERE,
-            mForceKillTask = NewRunnableMethod(this, &ContentParent::KillHard),
-            timeoutSecs * 1000);
+        mForceKillTimer = do_CreateInstance("@mozilla.org/timer;1");
+        MOZ_ASSERT(mForceKillTimer);
+        mForceKillTimer->InitWithFuncCallback(ContentParent::ForceKillTimerCallback,
+                                              this,
+                                              timeoutSecs * 1000,
+                                              nsITimer::TYPE_ONE_SHOT);
     }
 }
 
 void
 ContentParent::NotifyTabDestroyed(PBrowserParent* aTab,
                                   bool aNotifiedDestroying)
 {
     if (aNotifiedDestroying) {
         --mNumDestroyingTabs;
     }
 
     // There can be more than one PBrowser for a given app process
     // because of popup windows.  When the last one closes, shut
     // us down.
     if (ManagedPBrowserParent().Length() == 1) {
+        // In the case of normal shutdown, send a shutdown message to child to
+        // allow it to perform shutdown tasks.
         MessageLoop::current()->PostTask(
             FROM_HERE,
             NewRunnableMethod(this, &ContentParent::ShutDownProcess,
-                              /* force */ false));
+                              SEND_SHUTDOWN_MESSAGE));
     }
 }
 
 jsipc::JavaScriptShared*
 ContentParent::GetCPOWManager()
 {
     if (ManagedPJavaScriptParent().Length()) {
         return static_cast<JavaScriptParent*>(ManagedPJavaScriptParent()[0]);
@@ -1952,25 +2006,26 @@ ContentParent::GetTestShellSingleton()
 }
 
 void
 ContentParent::InitializeMembers()
 {
     mSubprocess = nullptr;
     mChildID = gContentChildID++;
     mGeolocationWatchID = -1;
-    mForceKillTask = nullptr;
     mNumDestroyingTabs = 0;
     mIsAlive = true;
     mSendPermissionUpdates = false;
     mSendDataStoreInfos = false;
     mCalledClose = false;
     mCalledCloseWithError = false;
     mCalledKillHard = false;
     mCreatedPairedMinidumps = false;
+    mShutdownPending = false;
+    mIPCOpen = true;
 }
 
 ContentParent::ContentParent(mozIApplication* aApp,
                              ContentParent* aOpener,
                              bool aIsForBrowser,
                              bool aIsForPreallocated,
                              ProcessPriority aInitialPriority /* = PROCESS_PRIORITY_FOREGROUND */,
                              bool aIsNuwaProcess /* = false */)
@@ -2128,18 +2183,18 @@ ContentParent::ContentParent(ContentPare
                  false  /* Send registered chrome */);
 
     ContentProcessManager::GetSingleton()->AddContentProcess(this);
 }
 #endif  // MOZ_NUWA_PROCESS
 
 ContentParent::~ContentParent()
 {
-    if (mForceKillTask) {
-        mForceKillTask->Cancel();
+    if (mForceKillTimer) {
+        mForceKillTimer->Cancel();
     }
 
     if (OtherProcess())
         base::CloseProcessHandle(OtherProcess());
 
     NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
     // We should be removed from all these lists in ActorDestroy.
@@ -2488,17 +2543,17 @@ ContentParent::RecvGetIconForExtension(c
 bool
 ContentParent::RecvGetShowPasswordSetting(bool* showPassword)
 {
     // default behavior is to show the last password character
     *showPassword = true;
 #ifdef MOZ_WIDGET_ANDROID
     NS_ASSERTION(AndroidBridge::Bridge() != nullptr, "AndroidBridge is not available");
 
-    *showPassword = mozilla::widget::android::GeckoAppShell::GetShowPasswordSetting();
+    *showPassword = mozilla::widget::GeckoAppShell::GetShowPasswordSetting();
 #endif
     return true;
 }
 
 bool
 ContentParent::RecvFirstIdle()
 {
     // When the ContentChild goes idle, it sends us a FirstIdle message
@@ -2704,18 +2759,27 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIObserver)
 NS_INTERFACE_MAP_END
 
 NS_IMETHODIMP
 ContentParent::Observe(nsISupports* aSubject,
                        const char* aTopic,
                        const char16_t* aData)
 {
-    if (!strcmp(aTopic, "xpcom-shutdown") && mSubprocess) {
-        ShutDownProcess(/* closeWithError */ false);
+    if (mSubprocess && (!strcmp(aTopic, "profile-before-change") ||
+                        !strcmp(aTopic, "xpcom-shutdown"))) {
+        // Okay to call ShutDownProcess multiple times.
+        ShutDownProcess(SEND_SHUTDOWN_MESSAGE);
+
+        // Wait for shutdown to complete, so that we receive any shutdown
+        // data (e.g. telemetry) from the child before we quit.
+        // This loop terminate prematurely based on mForceKillTimer.
+        while (mIPCOpen) {
+            NS_ProcessNextEvent(nullptr, true);
+        }
         NS_ASSERTION(!mSubprocess, "Close should have nulled mSubprocess");
     }
 
     if (!mIsAlive || !mSubprocess)
         return NS_OK;
 
     // listening for memory pressure event
     if (!strcmp(aTopic, "memory-pressure") &&
@@ -3111,27 +3175,34 @@ ContentParent::AllocPRemoteSpellcheckEng
 
 bool
 ContentParent::DeallocPRemoteSpellcheckEngineParent(PRemoteSpellcheckEngineParent *parent)
 {
     delete parent;
     return true;
 }
 
+/* static */ void
+ContentParent::ForceKillTimerCallback(nsITimer* aTimer, void* aClosure)
+{
+    auto self = static_cast<ContentParent*>(aClosure);
+    self->KillHard();
+}
+
 void
 ContentParent::KillHard()
 {
     // On Windows, calling KillHard multiple times causes problems - the
     // process handle becomes invalid on the first call, causing a second call
     // to crash our process - more details in bug 890840.
     if (mCalledKillHard) {
         return;
     }
     mCalledKillHard = true;
-    mForceKillTask = nullptr;
+    mForceKillTimer = nullptr;
 
 #if defined(MOZ_CRASHREPORTER) && !defined(MOZ_B2G)
     if (ManagedPCrashReporterParent().Length() > 0) {
         CrashReporterParent* crashReporter =
             static_cast<CrashReporterParent*>(ManagedPCrashReporterParent()[0]);
 
         // We're about to kill the child process associated with this
         // ContentParent. Something has gone wrong to get us here,
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -28,16 +28,17 @@
 #define CHILD_PROCESS_SHUTDOWN_MESSAGE NS_LITERAL_STRING("child-process-shutdown")
 
 class mozIApplication;
 class nsConsoleService;
 class nsICycleCollectorLogSink;
 class nsIDOMBlob;
 class nsIDumpGCAndCCLogsCallback;
 class nsIMemoryReporter;
+class nsITimer;
 class ParentIdleListener;
 
 namespace mozilla {
 class PRemoteSpellcheckEngineParent;
 
 namespace ipc {
 class OptionalURIParams;
 class PFileDescriptorSetParent;
@@ -329,16 +330,18 @@ public:
                                        const URIParams& aDocumentURI,
                                        const bool& stickDocument,
                                        const TabId& aTabId) MOZ_OVERRIDE;
     virtual bool
     DeallocPOfflineCacheUpdateParent(POfflineCacheUpdateParent* aActor) MOZ_OVERRIDE;
 
     virtual bool RecvSetOfflinePermission(const IPC::Principal& principal) MOZ_OVERRIDE;
 
+    virtual bool RecvFinishShutdown() MOZ_OVERRIDE;
+
 protected:
     void OnChannelConnected(int32_t pid) MOZ_OVERRIDE;
     virtual void ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE;
     void OnNuwaForkTimeout();
 
     bool ShouldContinueFromReplyTimeout() MOZ_OVERRIDE;
 
 private:
@@ -429,32 +432,49 @@ private:
 
     /**
      * Mark this ContentParent as dead for the purposes of Get*().
      * This method is idempotent.
      */
     void MarkAsDead();
 
     /**
+     * How we will shut down this ContentParent and its subprocess.
+     */
+    enum ShutDownMethod {
+        // Send a shutdown message and wait for FinishShutdown call back.
+        SEND_SHUTDOWN_MESSAGE,
+        // Close the channel ourselves and let the subprocess clean up itself.
+        CLOSE_CHANNEL,
+        // Close the channel with error and let the subprocess clean up itself.
+        CLOSE_CHANNEL_WITH_ERROR,
+    };
+
+    /**
      * Exit the subprocess and vamoose.  After this call IsAlive()
      * will return false and this ContentParent will not be returned
      * by the Get*() funtions.  However, the shutdown sequence itself
      * may be asynchronous.
      *
-     * If aCloseWithError is true and this is the first call to
-     * ShutDownProcess, then we'll close our channel using CloseWithError()
+     * If aMethod is CLOSE_CHANNEL_WITH_ERROR and this is the first call
+     * to ShutDownProcess, then we'll close our channel using CloseWithError()
      * rather than vanilla Close().  CloseWithError() indicates to IPC that this
      * is an abnormal shutdown (e.g. a crash).
      */
-    void ShutDownProcess(bool aCloseWithError);
+    void ShutDownProcess(ShutDownMethod aMethod);
 
     // Perform any steps necesssary to gracefully shtudown the message
     // manager and null out mMessageManager.
     void ShutDownMessageManager();
 
+    // Start the force-kill timer on shutdown.
+    void StartForceKillTimer();
+
+    static void ForceKillTimerCallback(nsITimer* aTimer, void* aClosure);
+
     PCompositorParent*
     AllocPCompositorParent(mozilla::ipc::Transport* aTransport,
                            base::ProcessId aOtherProcess) MOZ_OVERRIDE;
     PImageBridgeParent*
     AllocPImageBridgeParent(mozilla::ipc::Transport* aTransport,
                             base::ProcessId aOtherProcess) MOZ_OVERRIDE;
 
     PSharedBufferManagerParent*
@@ -771,17 +791,17 @@ private:
      * expensive.
      */
     nsString mAppName;
 
     // After we initiate shutdown, we also start a timer to ensure
     // that even content processes that are 100% blocked (say from
     // SIGSTOP), are still killed eventually.  This task enforces that
     // timer.
-    CancelableTask* mForceKillTask;
+    nsCOMPtr<nsITimer> mForceKillTimer;
     // How many tabs we're waiting to finish their destruction
     // sequence.  Precisely, how many TabParents have called
     // NotifyTabDestroying() but not called NotifyTabDestroyed().
     int32_t mNumDestroyingTabs;
     // True only while this is ready to be used to host remote tabs.
     // This must not be used for new purposes after mIsAlive goes to
     // false, but some previously scheduled IPC traffic may still pass
     // through.
@@ -793,16 +813,18 @@ private:
     bool mIsNuwaProcess;
 
     // These variables track whether we've called Close(), CloseWithError()
     // and KillHard() on our channel.
     bool mCalledClose;
     bool mCalledCloseWithError;
     bool mCalledKillHard;
     bool mCreatedPairedMinidumps;
+    bool mShutdownPending;
+    bool mIPCOpen;
 
     friend class CrashReporterParent;
 
     nsRefPtr<nsConsoleService>  mConsoleService;
     nsConsoleService* GetConsoleService();
 
     nsDataHashtable<nsUint64HashKey, nsRefPtr<ParentIdleListener> > mIdleListeners;
 
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -537,16 +537,23 @@ child:
      */
     async StartProfiler(uint32_t aEntries, double aInterval, nsCString[] aFeatures,
                         nsCString[] aThreadNameFilters);
     async StopProfiler();
     prio(high) sync GetProfile()
       returns (nsCString aProfile);
 
     NuwaFreeze();
+
+    /**
+     * Notify the child to shutdown. The child will in turn call FinishShutdown
+     * and let the parent close the channel.
+     */
+    async Shutdown();
+
 parent:
     /**
      * Tell the parent process a new accessible document has been created.
      * aParentDoc is the accessible document it was created in if any, and
      * aParentAcc is the id of the accessible in that document the new document
      * is a child of.
      */
     PDocAccessible(nullable PDocAccessible aParentDoc, uint64_t aParentAcc);
@@ -872,15 +879,21 @@ parent:
 
     /**
      * Sets "offline-app" permission for the principal.  Called when we hit
      * a web app with the manifest attribute in <html> and
      * offline-apps.allow_by_default is set to true.
      */
     SetOfflinePermission(Principal principal);
 
+    /**
+     * Notifies the parent to continue shutting down after the child performs
+     * its shutdown tasks.
+     */
+    async FinishShutdown();
+
 both:
      AsyncMessage(nsString aMessage, ClonedMessageData aData,
                   CpowEntry[] aCpows, Principal aPrincipal);
 };
 
 }
 }
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -772,17 +772,20 @@ private:
     }
 
     NS_IMETHOD
     Run()
     {
         MOZ_ASSERT(NS_IsMainThread());
         MOZ_ASSERT(mTabChild);
 
-        unused << PBrowserChild::Send__delete__(mTabChild);
+        // Check in case ActorDestroy was called after RecvDestroy message.
+        if (mTabChild->IPCOpen()) {
+            unused << PBrowserChild::Send__delete__(mTabChild);
+        }
 
         mTabChild = nullptr;
         return NS_OK;
     }
 };
 
 StaticRefPtr<TabChild> sPreallocatedTab;
 
@@ -900,16 +903,17 @@ TabChild::TabChild(nsIContentChild* aMan
   , mEndTouchIsClick(false)
   , mIgnoreKeyPressEvent(false)
   , mActiveElementManager(new ActiveElementManager())
   , mHasValidInnerSize(false)
   , mDestroyed(false)
   , mUniqueId(aTabId)
   , mDPI(0)
   , mDefaultScale(0)
+  , mIPCOpen(true)
 {
   if (!sActiveDurationMsSet) {
     Preferences::AddIntVarCache(&sActiveDurationMs,
                                 "ui.touch_activation.duration_ms",
                                 sActiveDurationMs);
     sActiveDurationMsSet = true;
   }
 
@@ -1649,16 +1653,18 @@ TabChild::DestroyWindow()
     }
 
     mCachedFileDescriptorInfos.Clear();
 }
 
 void
 TabChild::ActorDestroy(ActorDestroyReason why)
 {
+  mIPCOpen = false;
+
   DestroyWindow();
 
   if (mTabChildGlobal) {
     // The messageManager relays messages via the TabChild which
     // no longer exists.
     static_cast<nsFrameMessageManager*>
       (mTabChildGlobal->mMessageManager.get())->Disconnect();
     mTabChildGlobal->mMessageManager = nullptr;
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -494,16 +494,18 @@ public:
      * Native widget remoting protocol for use with windowed plugins with e10s.
      */
     PPluginWidgetChild* AllocPPluginWidgetChild() MOZ_OVERRIDE;
     bool DeallocPPluginWidgetChild(PPluginWidgetChild* aActor) MOZ_OVERRIDE;
     already_AddRefed<nsIWidget> CreatePluginWidget(nsIWidget* aParent);
 
     nsIntPoint GetChromeDisplacement() { return mChromeDisp; };
 
+    bool IPCOpen() { return mIPCOpen; }
+
 protected:
     virtual ~TabChild();
 
     virtual PRenderFrameChild* AllocPRenderFrameChild() MOZ_OVERRIDE;
     virtual bool DeallocPRenderFrameChild(PRenderFrameChild* aFrame) MOZ_OVERRIDE;
     virtual bool RecvDestroy() MOZ_OVERRIDE;
     virtual bool RecvSetUpdateHitRegion(const bool& aEnabled) MOZ_OVERRIDE;
     virtual bool RecvSetIsDocShellActive(const bool& aIsActive) MOZ_OVERRIDE;
@@ -657,16 +659,17 @@ private:
     nsRefPtr<ActiveElementManager> mActiveElementManager;
     bool mHasValidInnerSize;
     bool mDestroyed;
     // Position of tab, relative to parent widget (typically the window)
     nsIntPoint mChromeDisp;
     TabId mUniqueId;
     float mDPI;
     double mDefaultScale;
+    bool mIPCOpen;
 
     DISALLOW_EVIL_CONSTRUCTORS(TabChild);
 };
 
 }
 }
 
 #endif // mozilla_dom_TabChild_h
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -137,63 +137,81 @@ private:
         return NS_OK;
     }
 
     void SendResponse()
     {
         MOZ_ASSERT(NS_IsMainThread());
         MOZ_ASSERT(mTabParent);
         MOZ_ASSERT(mEventTarget);
-        MOZ_ASSERT(mFD);
 
         nsRefPtr<TabParent> tabParent;
         mTabParent.swap(tabParent);
 
         using mozilla::ipc::FileDescriptor;
 
-        FileDescriptor::PlatformHandleType handle =
-            FileDescriptor::PlatformHandleType(PR_FileDesc2NativeHandle(mFD));
+        FileDescriptor fd;
+        if (mFD) {
+            FileDescriptor::PlatformHandleType handle =
+                FileDescriptor::PlatformHandleType(PR_FileDesc2NativeHandle(mFD));
+            fd = FileDescriptor(handle);
+        }
 
         // Our TabParent may have been destroyed already.  If so, don't send any
         // fds over, just go back to the IO thread and close them.
         if (!tabParent->IsDestroyed()) {
-          mozilla::unused << tabParent->SendCacheFileDescriptor(mPath,
-                                                                FileDescriptor(handle));
+            mozilla::unused << tabParent->SendCacheFileDescriptor(mPath, fd);
+        }
+
+        if (!mFD) {
+            return;
         }
 
         nsCOMPtr<nsIEventTarget> eventTarget;
         mEventTarget.swap(eventTarget);
 
         if (NS_FAILED(eventTarget->Dispatch(this, NS_DISPATCH_NORMAL))) {
             NS_WARNING("Failed to dispatch to stream transport service!");
 
             // It's probably safer to take the main thread IO hit here rather
             // than leak a file descriptor.
             CloseFile();
         }
     }
 
-    void OpenFile()
+    // Helper method to avoid gnarly control flow for failures.
+    void OpenFileImpl()
     {
         MOZ_ASSERT(!NS_IsMainThread());
         MOZ_ASSERT(!mFD);
 
         nsCOMPtr<nsIFile> file;
         nsresult rv = NS_NewLocalFile(mPath, false, getter_AddRefs(file));
         NS_ENSURE_SUCCESS_VOID(rv);
 
         PRFileDesc* fd;
         rv = file->OpenNSPRFileDesc(PR_RDONLY, 0, &fd);
         NS_ENSURE_SUCCESS_VOID(rv);
 
         mFD = fd;
+    }
+
+    void OpenFile()
+    {
+        MOZ_ASSERT(!NS_IsMainThread());
+
+        OpenFileImpl();
 
         if (NS_FAILED(NS_DispatchToMainThread(this))) {
             NS_WARNING("Failed to dispatch to main thread!");
 
+            // Intentionally leak the runnable (but not the fd) rather
+            // than crash when trying to release a main thread object
+            // off the main thread.
+            mTabParent.forget();
             CloseFile();
         }
     }
 
     void CloseFile()
     {
         // It's possible for this to happen on the main thread if the dispatch
         // to the stream service fails after we've already opened the file so
@@ -2172,17 +2190,21 @@ TabParent::UseAsyncPanZoom()
           GetScrollingBehavior() == ASYNC_PAN_ZOOM);
 }
 
 nsEventStatus
 TabParent::MaybeForwardEventToRenderFrame(WidgetInputEvent& aEvent,
                                           ScrollableLayerGuid* aOutTargetGuid,
                                           uint64_t* aOutInputBlockId)
 {
-  if (aEvent.mClass == eWheelEventClass) {
+  if (aEvent.mClass == eWheelEventClass
+#ifdef MOZ_WIDGET_GONK
+      || aEvent.mClass == eTouchEventClass
+#endif
+     ) {
     // Wheel events must be sent to APZ directly from the widget. New APZ-
     // aware events should follow suit and move there as well. However, we
     // do need to inform the child process of the correct target and block
     // id.
     if (aOutTargetGuid) {
       *aOutTargetGuid = InputAPZContext::GetTargetLayerGuid();
     }
     if (aOutInputBlockId) {
--- a/dom/media/AbstractMediaDecoder.h
+++ b/dom/media/AbstractMediaDecoder.h
@@ -138,17 +138,19 @@ public:
   // Stack based class to assist in notifying the frame statistics of
   // parsed and decoded frames. Use inside video demux & decode functions
   // to ensure all parsed and decoded frames are reported on all return paths.
   class AutoNotifyDecoded {
   public:
     AutoNotifyDecoded(AbstractMediaDecoder* aDecoder, uint32_t& aParsed, uint32_t& aDecoded)
       : mDecoder(aDecoder), mParsed(aParsed), mDecoded(aDecoded) {}
     ~AutoNotifyDecoded() {
-      mDecoder->NotifyDecodedFrames(mParsed, mDecoded);
+      if (mDecoder) {
+        mDecoder->NotifyDecodedFrames(mParsed, mDecoded);
+      }
     }
   private:
     AbstractMediaDecoder* mDecoder;
     uint32_t& mParsed;
     uint32_t& mDecoded;
   };
 
 #ifdef MOZ_EME
--- a/dom/media/AudioStream.cpp
+++ b/dom/media/AudioStream.cpp
@@ -127,17 +127,17 @@ private:
 
 AudioStream::AudioStream()
   : mMonitor("AudioStream")
   , mInRate(0)
   , mOutRate(0)
   , mChannels(0)
   , mOutChannels(0)
   , mWritten(0)
-  , mAudioClock(MOZ_THIS_IN_INITIALIZER_LIST())
+  , mAudioClock(this)
   , mLatencyRequest(HighLatency)
   , mReadPoint(0)
   , mDumpFile(nullptr)
   , mBytesPerFrame(0)
   , mState(INITIALIZED)
   , mNeedsStart(false)
   , mShouldDropFrames(false)
   , mPendingAudioInitTask(false)
--- a/dom/media/MediaDecoderReader.cpp
+++ b/dom/media/MediaDecoderReader.cpp
@@ -69,20 +69,20 @@ public:
 };
 
 MediaDecoderReader::MediaDecoderReader(AbstractMediaDecoder* aDecoder)
   : mAudioCompactor(mAudioQueue)
   , mDecoder(aDecoder)
   , mIgnoreAudioOutputFormat(false)
   , mStartTime(-1)
   , mHitAudioDecodeError(false)
+  , mShutdown(false)
   , mTaskQueueIsBorrowed(false)
   , mAudioDiscontinuity(false)
   , mVideoDiscontinuity(false)
-  , mShutdown(false)
 {
   MOZ_COUNT_CTOR(MediaDecoderReader);
   EnsureMediaPromiseLog();
 }
 
 MediaDecoderReader::~MediaDecoderReader()
 {
   MOZ_ASSERT(mShutdown);
--- a/dom/media/MediaDecoderReader.h
+++ b/dom/media/MediaDecoderReader.h
@@ -47,17 +47,17 @@ public:
     END_OF_STREAM,
     DECODE_ERROR,
     WAITING_FOR_DATA,
     CANCELED
   };
 
   typedef MediaPromise<nsRefPtr<AudioData>, NotDecodedReason> AudioDataPromise;
   typedef MediaPromise<nsRefPtr<VideoData>, NotDecodedReason> VideoDataPromise;
-  typedef MediaPromise<bool, nsresult> SeekPromise;
+  typedef MediaPromise<int64_t, nsresult> SeekPromise;
   typedef MediaPromise<MediaData::Type, WaitForDataRejectValue> WaitForDataPromise;
 
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaDecoderReader)
 
   explicit MediaDecoderReader(AbstractMediaDecoder* aDecoder);
 
   // Initializes the reader, returns NS_OK on success, or NS_ERROR_FAILURE
   // on failure.
@@ -295,28 +295,28 @@ protected:
   // after which point it never changes.
   int64_t mStartTime;
 
   // This is a quick-and-dirty way for DecodeAudioData implementations to
   // communicate the presence of a decoding error to RequestAudioData. We should
   // replace this with a promise-y mechanism as we make this stuff properly
   // async.
   bool mHitAudioDecodeError;
+  bool mShutdown;
 
 private:
   // Promises used only for the base-class (sync->async adapter) implementation
   // of Request{Audio,Video}Data.
   MediaPromiseHolder<AudioDataPromise> mBaseAudioPromise;
   MediaPromiseHolder<VideoDataPromise> mBaseVideoPromise;
 
   nsRefPtr<MediaTaskQueue> mTaskQueue;
   bool mTaskQueueIsBorrowed;
 
   // Flags whether a the next audio/video sample comes after a "gap" or
   // "discontinuity" in the stream. For example after a seek.
   bool mAudioDiscontinuity;
   bool mVideoDiscontinuity;
-  bool mShutdown;
 };
 
 } // namespace mozilla
 
 #endif
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -176,18 +176,17 @@ static int64_t DurationToUsecs(TimeDurat
 }
 
 MediaDecoderStateMachine::MediaDecoderStateMachine(MediaDecoder* aDecoder,
                                                    MediaDecoderReader* aReader,
                                                    bool aRealTime) :
   mDecoder(aDecoder),
   mScheduler(new MediaDecoderStateMachineScheduler(
       aDecoder->GetReentrantMonitor(),
-      &MediaDecoderStateMachine::TimeoutExpired,
-      MOZ_THIS_IN_INITIALIZER_LIST(), aRealTime)),
+      &MediaDecoderStateMachine::TimeoutExpired, this, aRealTime)),
   mState(DECODER_STATE_DECODING_NONE),
   mSyncPointInMediaStream(-1),
   mSyncPointInDecodedStream(-1),
   mPlayDuration(0),
   mStartTime(-1),
   mEndTime(-1),
   mFragmentEndTime(-1),
   mReader(aReader),
@@ -571,16 +570,19 @@ MediaDecoderStateMachine::NeedToDecodeVi
          ((mState == DECODER_STATE_SEEKING && mDecodeToSeekTarget) ||
           (!mMinimizePreroll && !HaveEnoughDecodedVideo()));
 }
 
 bool
 MediaDecoderStateMachine::NeedToSkipToNextKeyframe()
 {
   AssertCurrentThreadInMonitor();
+  if (mState == DECODER_STATE_DECODING_FIRSTFRAME) {
+    return false;
+  }
   MOZ_ASSERT(mState == DECODER_STATE_DECODING ||
              mState == DECODER_STATE_BUFFERING ||
              mState == DECODER_STATE_SEEKING);
 
   // We are in seeking or buffering states, don't skip frame.
   if (!IsVideoDecoding() || mState == DECODER_STATE_BUFFERING ||
       mState == DECODER_STATE_SEEKING) {
     return false;
@@ -618,16 +620,17 @@ MediaDecoderStateMachine::DecodeVideo()
 {
   int64_t currentTime = 0;
   bool skipToNextKeyFrame = false;
   {
     ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
     NS_ASSERTION(OnDecodeThread(), "Should be on decode thread.");
 
     if (mState != DECODER_STATE_DECODING &&
+        mState != DECODER_STATE_DECODING_FIRSTFRAME &&
         mState != DECODER_STATE_BUFFERING &&
         mState != DECODER_STATE_SEEKING) {
       mVideoRequestStatus = RequestStatus::Idle;
       DispatchDecodeTasksIfNeeded();
       return;
     }
 
     skipToNextKeyFrame = NeedToSkipToNextKeyframe();
@@ -667,16 +670,17 @@ MediaDecoderStateMachine::NeedToDecodeAu
 void
 MediaDecoderStateMachine::DecodeAudio()
 {
   {
     ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
     NS_ASSERTION(OnDecodeThread(), "Should be on decode thread.");
 
     if (mState != DECODER_STATE_DECODING &&
+        mState != DECODER_STATE_DECODING_FIRSTFRAME &&
         mState != DECODER_STATE_BUFFERING &&
         mState != DECODER_STATE_SEEKING) {
       mAudioRequestStatus = RequestStatus::Idle;
       DispatchDecodeTasksIfNeeded();
       mon.NotifyAll();
       return;
     }
   }
@@ -1772,16 +1776,17 @@ MediaDecoderStateMachine::SetReaderIdle(
 }
 
 void
 MediaDecoderStateMachine::DispatchDecodeTasksIfNeeded()
 {
   AssertCurrentThreadInMonitor();
 
   if (mState != DECODER_STATE_DECODING &&
+      mState != DECODER_STATE_DECODING_FIRSTFRAME &&
       mState != DECODER_STATE_BUFFERING &&
       mState != DECODER_STATE_SEEKING) {
     return;
   }
 
   if (mState == DECODER_STATE_DECODING && mDecodingFrozenAtStateDecoding) {
     DECODER_LOG("DispatchDecodeTasksIfNeeded return due to "
                 "mFreezeDecodingAtStateDecoding");
@@ -1820,17 +1825,16 @@ MediaDecoderStateMachine::DispatchDecode
 
   if (needToDecodeAudio) {
     EnsureAudioDecodeTaskQueued();
   }
   if (needToDecodeVideo) {
     EnsureVideoDecodeTaskQueued();
   }
 
-
   if (needIdle) {
     RefPtr<nsIRunnable> event = NS_NewRunnableMethod(
         this, &MediaDecoderStateMachine::SetReaderIdle);
     nsresult rv = DecodeTaskQueue()->Dispatch(event.forget());
     if (NS_FAILED(rv) && mState != DECODER_STATE_SHUTDOWN) {
       DECODER_WARN("Failed to dispatch event to set decoder idle state");
     }
   }
@@ -1887,17 +1891,17 @@ MediaDecoderStateMachine::EnsureAudioDec
 
   SAMPLE_LOG("EnsureAudioDecodeTaskQueued isDecoding=%d status=%d",
               IsAudioDecoding(), mAudioRequestStatus);
 
   if (mState >= DECODER_STATE_COMPLETED) {
     return NS_OK;
   }
 
-  MOZ_ASSERT(mState > DECODER_STATE_DECODING_FIRSTFRAME);
+  MOZ_ASSERT(mState >= DECODER_STATE_DECODING_FIRSTFRAME);
 
   if (IsAudioDecoding() && mAudioRequestStatus == RequestStatus::Idle && !mWaitingForDecoderSeek) {
     RefPtr<nsIRunnable> task(
       NS_NewRunnableMethod(this, &MediaDecoderStateMachine::DecodeAudio));
     nsresult rv = DecodeTaskQueue()->Dispatch(task);
     if (NS_SUCCEEDED(rv)) {
       mAudioRequestStatus = RequestStatus::Pending;
     } else {
@@ -1932,17 +1936,17 @@ MediaDecoderStateMachine::EnsureVideoDec
 
   NS_ASSERTION(OnStateMachineThread() || OnDecodeThread(),
                "Should be on state machine or decode thread.");
 
   if (mState >= DECODER_STATE_COMPLETED) {
     return NS_OK;
   }
 
-  MOZ_ASSERT(mState > DECODER_STATE_DECODING_FIRSTFRAME);
+  MOZ_ASSERT(mState >= DECODER_STATE_DECODING_FIRSTFRAME);
 
   if (IsVideoDecoding() && mVideoRequestStatus == RequestStatus::Idle && !mWaitingForDecoderSeek) {
     RefPtr<nsIRunnable> task(
       NS_NewRunnableMethod(this, &MediaDecoderStateMachine::DecodeVideo));
     nsresult rv = DecodeTaskQueue()->Dispatch(task);
     if (NS_SUCCEEDED(rv)) {
       mVideoRequestStatus = RequestStatus::Pending;
     } else {
@@ -2386,17 +2390,17 @@ void MediaDecoderStateMachine::DecodeSee
       DecodeError();
       return;
     }
     mWaitingForDecoderSeek = true;
   }
 }
 
 void
-MediaDecoderStateMachine::OnSeekCompleted()
+MediaDecoderStateMachine::OnSeekCompleted(int64_t aTime)
 {
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
   mWaitingForDecoderSeek = false;
 
   // We must decode the first samples of active streams, so we can determine
   // the new stream time. So dispatch tasks to do that.
   mDecodeToSeekTarget = true;
   DispatchDecodeTasksIfNeeded();
--- a/dom/media/MediaDecoderStateMachine.h
+++ b/dom/media/MediaDecoderStateMachine.h
@@ -395,17 +395,17 @@ public:
     OnNotDecoded(MediaData::AUDIO_DATA, aReason);
   }
   void OnVideoNotDecoded(MediaDecoderReader::NotDecodedReason aReason)
   {
     MOZ_ASSERT(OnDecodeThread());
     OnNotDecoded(MediaData::VIDEO_DATA, aReason);
   }
 
-  void OnSeekCompleted();
+  void OnSeekCompleted(int64_t aTime);
   void OnSeekFailed(nsresult aResult);
 
   void OnWaitForDataResolved(MediaData::Type aType)
   {
     ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
     if (RequestStatusRef(aType) == RequestStatus::Waiting) {
       RequestStatusRef(aType) = RequestStatus::Idle;
       DispatchDecodeTasksIfNeeded();
--- a/dom/media/MediaResource.cpp
+++ b/dom/media/MediaResource.cpp
@@ -75,17 +75,17 @@ NS_IMPL_QUERY_INTERFACE0(MediaResource)
 
 ChannelMediaResource::ChannelMediaResource(MediaDecoder* aDecoder,
                                            nsIChannel* aChannel,
                                            nsIURI* aURI,
                                            const nsACString& aContentType)
   : BaseMediaResource(aDecoder, aChannel, aURI, aContentType),
     mOffset(0), mSuspendCount(0),
     mReopenOnError(false), mIgnoreClose(false),
-    mCacheStream(MOZ_THIS_IN_INITIALIZER_LIST()),
+    mCacheStream(this),
     mLock("ChannelMediaResource.mLock"),
     mIgnoreResume(false),
     mIsTransportSeekable(true)
 {
 #ifdef PR_LOGGING
   if (!gMediaResourceLog) {
     gMediaResourceLog = PR_NewLogModule("MediaResource");
   }
--- a/dom/media/MediaStreamGraph.cpp
+++ b/dom/media/MediaStreamGraph.cpp
@@ -2737,17 +2737,17 @@ MediaStreamGraphImpl::MediaStreamGraphIm
   , mRealtime(aRealtime)
   , mNonRealtimeProcessing(false)
   , mStreamOrderDirty(false)
   , mLatencyLog(AsyncLatencyLogger::Get())
 #ifdef MOZ_WEBRTC
   , mFarendObserverRef(nullptr)
 #endif
   , mMemoryReportMonitor("MSGIMemory")
-  , mSelfRef(MOZ_THIS_IN_INITIALIZER_LIST())
+  , mSelfRef(this)
   , mAudioStreamSizes()
   , mNeedsMemoryReport(false)
 #ifdef DEBUG
   , mCanRunMessagesSynchronously(false)
 #endif
   , mAudioChannel(static_cast<uint32_t>(aChannel))
 {
 #ifdef PR_LOGGING
--- a/dom/media/android/AndroidMediaReader.cpp
+++ b/dom/media/android/AndroidMediaReader.cpp
@@ -335,17 +335,17 @@ AndroidMediaReader::Seek(int64_t aTarget
     // audio and video streams won't be in sync after the seek.
     mVideoSeekTimeUs = aTarget;
     const VideoData* v = DecodeToFirstVideoData();
     mAudioSeekTimeUs = v ? v->mTime : aTarget;
   } else {
     mAudioSeekTimeUs = mVideoSeekTimeUs = aTarget;
   }
 
-  return SeekPromise::CreateAndResolve(true, __func__);
+  return SeekPromise::CreateAndResolve(mAudioSeekTimeUs, __func__);
 }
 
 AndroidMediaReader::ImageBufferCallback::ImageBufferCallback(mozilla::layers::ImageContainer *aImageContainer) :
   mImageContainer(aImageContainer)
 {
 }
 
 void *
--- a/dom/media/apple/AppleMP3Reader.cpp
+++ b/dom/media/apple/AppleMP3Reader.cpp
@@ -524,17 +524,17 @@ AppleMP3Reader::Seek(int64_t aTime,
   LOGD("computed byte offset = %lld; estimated = %s\n",
        byteOffset,
        (flags & kAudioFileStreamSeekFlag_OffsetIsEstimated) ? "YES" : "NO");
 
   mDecoder->GetResource()->Seek(nsISeekableStream::NS_SEEK_SET, byteOffset);
 
   ResetDecode();
 
-  return SeekPromise::CreateAndResolve(true, __func__);
+  return SeekPromise::CreateAndResolve(aTime, __func__);
 }
 
 void
 AppleMP3Reader::NotifyDataArrived(const char* aBuffer,
                                   uint32_t aLength,
                                   int64_t aOffset)
 {
   MOZ_ASSERT(NS_IsMainThread());
--- a/dom/media/compiledtest/TestAudioBuffers.cpp
+++ b/dom/media/compiledtest/TestAudioBuffers.cpp
@@ -1,16 +1,15 @@
 /* -*- 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 <stdint.h>
 #include <assert.h>
-#include <mozilla/NullPtr.h>
 #include "AudioBufferUtils.h"
 
 const uint32_t FRAMES = 256;
 const uint32_t CHANNELS = 2;
 const uint32_t SAMPLES = CHANNELS * FRAMES;
 
 int main() {
   mozilla::AudioCallbackBufferWrapper<float, CHANNELS> mBuffer;
--- a/dom/media/directshow/DirectShowReader.cpp
+++ b/dom/media/directshow/DirectShowReader.cpp
@@ -372,17 +372,17 @@ DirectShowReader::Seek(int64_t aTargetUs
                        int64_t aStartTime,
                        int64_t aEndTime,
                        int64_t aCurrentTime)
 {
   nsresult res = SeekInternal(aTargetUs);
   if (NS_FAILED(res)) {
     return SeekPromise::CreateAndReject(res, __func__);
   } else {
-    return SeekPromise::CreateAndResolve(true, __func__);
+    return SeekPromise::CreateAndResolve(aTargetUs, __func__);
   }
 }
 
 nsresult
 DirectShowReader::SeekInternal(int64_t aTargetUs)
 {
   HRESULT hr;
   MOZ_ASSERT(mDecoder->OnDecodeThread(), "Should be on decode thread.");\
--- a/dom/media/eme/EMELog.cpp
+++ b/dom/media/eme/EMELog.cpp
@@ -1,16 +1,15 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "EMELog.h"
-#include "mozilla/NullPtr.h"
 
 namespace mozilla {
 
 #ifdef PR_LOGGING
 
 PRLogModuleInfo* GetEMELog() {
   static PRLogModuleInfo* log = nullptr;
   if (!log) {
--- a/dom/media/fmp4/MP4Reader.cpp
+++ b/dom/media/fmp4/MP4Reader.cpp
@@ -58,16 +58,73 @@ TrackTypeToStr(TrackType aTrack)
   case kVideo:
     return "Video";
   default:
     return "Unknown";
   }
 }
 #endif
 
+// MP4Demuxer wants to do various blocking reads, which cause deadlocks while
+// mDemuxerMonitor is held. This stuff should really be redesigned, but we don't
+// have time for that right now. So in order to get proper synchronization while
+// keeping behavior as similar as possible, we do the following nasty hack:
+//
+// The demuxer has a Stream object with APIs to do both blocking and non-blocking
+// reads. When it does a blocking read, MP4Stream actually redirects it to a non-
+// blocking read, but records the parameters of the read on the MP4Stream itself.
+// This means that, when the read failure bubbles up to MP4Reader.cpp, we can
+// detect whether we in fact just needed to block, and do that while releasing the
+// monitor. We distinguish these fake failures from bonafide EOS by tracking the
+// previous failed read as well. If we ever do a blocking read on the same segment
+// twice, we know we've hit EOS.
+template<typename ThisType, typename ReturnType>
+ReturnType
+InvokeAndRetry(ThisType* aThisVal, ReturnType(ThisType::*aMethod)(), MP4Stream* aStream, Monitor* aMonitor)
+{
+  AutoPinned<MP4Stream> stream(aStream);
+  MP4Stream::ReadRecord prevFailure(-1, 0);
+  while (true) {
+    ReturnType result = ((*aThisVal).*aMethod)();
+    if (result) {
+      return result;
+    }
+    MP4Stream::ReadRecord failure(-1, 0);
+    if (!stream->LastReadFailed(&failure) || failure == prevFailure) {
+      return result;
+    }
+    prevFailure = failure;
+
+    // Our goal here is to forcibly read the data we want into the cache: since
+    // the stream is pinned, the data is guaranteed to stay in the cache once
+    // it's there, which means that retrying the non-blocking read from inside
+    // the demuxer should succeed.
+    //
+    // But there's one wrinkle: if we read less than an entire cache line and
+    // the data ends up in MediaCacheStream's mPartialBlockBuffer, the data can
+    // be returned by a blocking read but never actually committed to the cache,
+    // and abandoned by a subsequent seek (possibly by another stream accessing
+    // the same underlying resource).
+    //
+    // The way to work around this problem is to round our "priming" read up to the
+    // size of an entire cache block. Note that this may hit EOS for bytes that the
+    // original demuxer read never actually requested. This is OK though because the
+    // call to BlockingReadAt will still return true (just with a less-than-expected
+    // number of actually read bytes, which we ignore).
+    size_t bufferSize = failure.mCount + (MediaCacheStream::BLOCK_SIZE - failure.mCount % MediaCacheStream::BLOCK_SIZE);
+    nsAutoArrayPtr<uint8_t> dummyBuffer(new uint8_t[bufferSize]);
+    MonitorAutoUnlock unlock(*aMonitor);
+    size_t ignored;
+    if (NS_WARN_IF(!stream->BlockingReadAt(failure.mOffset, dummyBuffer, bufferSize, &ignored))) {
+      return result;
+    }
+  }
+}
+
+
 MP4Reader::MP4Reader(AbstractMediaDecoder* aDecoder)
   : MediaDecoderReader(aDecoder)
   , mAudio(MediaData::AUDIO_DATA, Preferences::GetUint("media.mp4-audio-decode-ahead", 2))
   , mVideo(MediaData::VIDEO_DATA, Preferences::GetUint("media.mp4-video-decode-ahead", 2))
   , mLastReportedNumDecodedFrames(0)
   , mLayersBackendType(layers::LayersBackend::LAYERS_NONE)
   , mDemuxerInitialized(false)
   , mIsEncrypted(false)
@@ -152,17 +209,18 @@ MP4Reader::InitLayersBackendType()
 
 static bool sIsEMEEnabled = false;
 
 nsresult
 MP4Reader::Init(MediaDecoderReader* aCloneDonor)
 {
   MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread.");
   PlatformDecoderModule::Init();
-  mDemuxer = new MP4Demuxer(new MP4Stream(mDecoder->GetResource(), &mDemuxerMonitor), GetDecoder()->GetTimestampOffset(), &mDemuxerMonitor);
+  mStream = new MP4Stream(mDecoder->GetResource());
+  mTimestampOffset = GetDecoder()->GetTimestampOffset();
 
   InitLayersBackendType();
 
   mAudio.mTaskQueue = new MediaTaskQueue(GetMediaDecodeThreadPool());
   NS_ENSURE_TRUE(mAudio.mTaskQueue, NS_ERROR_FAILURE);
 
   mVideo.mTaskQueue = new MediaTaskQueue(GetMediaDecodeThreadPool());
   NS_ENSURE_TRUE(mVideo.mTaskQueue, NS_ERROR_FAILURE);
@@ -284,23 +342,30 @@ MP4Reader::IsSupportedVideoMimeType(cons
 void
 MP4Reader::PreReadMetadata()
 {
   if (mPlatform) {
     RequestCodecResource();
   }
 }
 
+bool
+MP4Reader::InitDemuxer()
+{
+  mDemuxer = new MP4Demuxer(mStream, mTimestampOffset, &mDemuxerMonitor);
+  return mDemuxer->Init();
+}
+
 nsresult
 MP4Reader::ReadMetadata(MediaInfo* aInfo,
                         MetadataTags** aTags)
 {
   if (!mDemuxerInitialized) {
     MonitorAutoLock mon(mDemuxerMonitor);
-    bool ok = mDemuxer->Init();
+    bool ok = InvokeAndRetry(this, &MP4Reader::InitDemuxer, mStream, &mDemuxerMonitor);
     NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE);
     mIndexReady = true;
 
     // To decode, we need valid video and a place to put it.
     mInfo.mVideo.mHasVideo = mVideo.mActive = mDemuxer->HasValidVideo() &&
                                               mDecoder->GetImageContainer();
 
     mInfo.mAudio.mHasAudio = mAudio.mActive = mDemuxer->HasValidAudio();
@@ -540,16 +605,20 @@ MP4Reader::NeedInput(DecoderData& aDecod
      aDecoder.mNumSamplesInput - aDecoder.mNumSamplesOutput < aDecoder.mDecodeAhead);
 }
 
 void
 MP4Reader::Update(TrackType aTrack)
 {
   MOZ_ASSERT(GetTaskQueue()->IsCurrentThreadIn());
 
+  if (mShutdown) {
+    return;
+  }
+
   // Record number of frames decoded and parsed. Automatically update the
   // stats counters using the AutoNotifyDecoded stack-based class.
   uint32_t parsed = 0, decoded = 0;
   AbstractMediaDecoder::AutoNotifyDecoded autoNotify(mDecoder, parsed, decoded);
 
   bool needInput = false;
   bool needOutput = false;
   auto& decoder = GetDecoderData(aTrack);
@@ -640,23 +709,22 @@ MP4Reader::PopSample(TrackType aTrack)
 }
 
 MP4Sample*
 MP4Reader::PopSampleLocked(TrackType aTrack)
 {
   mDemuxerMonitor.AssertCurrentThreadOwns();
   switch (aTrack) {
     case kAudio:
-      return mDemuxer->DemuxAudioSample();
-
+      return InvokeAndRetry(mDemuxer.get(), &MP4Demuxer::DemuxAudioSample, mStream, &mDemuxerMonitor);
     case kVideo:
       if (mQueuedVideoSample) {
         return mQueuedVideoSample.forget();
       }
-      return mDemuxer->DemuxVideoSample();
+      return InvokeAndRetry(mDemuxer.get(), &MP4Demuxer::DemuxVideoSample, mStream, &mDemuxerMonitor);
 
     default:
       return nullptr;
   }
 }
 
 size_t
 MP4Reader::SizeOfVideoQueueInFrames()
@@ -833,27 +901,30 @@ MP4Reader::Seek(int64_t aTime,
   LOG("MP4Reader::Seek(%lld)", aTime);
   MOZ_ASSERT(GetTaskQueue()->IsCurrentThreadIn());
   MonitorAutoLock mon(mDemuxerMonitor);
   if (!mDecoder->GetResource()->IsTransportSeekable() || !mDemuxer->CanSeek()) {
     VLOG("Seek() END (Unseekable)");
     return SeekPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
   }
 
+  int64_t seekTime = aTime;
   mQueuedVideoSample = nullptr;
   if (mDemuxer->HasValidVideo()) {
-    mDemuxer->SeekVideo(aTime);
+    mDemuxer->SeekVideo(seekTime);
     mQueuedVideoSample = PopSampleLocked(kVideo);
+    if (mQueuedVideoSample) {
+      seekTime = mQueuedVideoSample->composition_timestamp;
+    }
   }
   if (mDemuxer->HasValidAudio()) {
-    mDemuxer->SeekAudio(
-      mQueuedVideoSample ? mQueuedVideoSample->composition_timestamp : aTime);
+    mDemuxer->SeekAudio(seekTime);
   }
   LOG("MP4Reader::Seek(%lld) exit", aTime);
-  return SeekPromise::CreateAndResolve(true, __func__);
+  return SeekPromise::CreateAndResolve(seekTime, __func__);
 }
 
 void
 MP4Reader::UpdateIndex()
 {
   if (!mIndexReady) {
     return;
   }
--- a/dom/media/fmp4/MP4Reader.h
+++ b/dom/media/fmp4/MP4Reader.h
@@ -79,16 +79,17 @@ public:
     MOZ_OVERRIDE;
 
   virtual nsresult ResetDecode() MOZ_OVERRIDE;
 
   virtual nsRefPtr<ShutdownPromise> Shutdown() MOZ_OVERRIDE;
 
 private:
 
+  bool InitDemuxer();
   void ReturnOutput(MediaData* aData, TrackType aTrack);
 
   // Sends input to decoder for aTrack, and output to the state machine,
   // if necessary.
   void Update(TrackType aTrack);
 
   // Enqueues a task to call Update(aTrack) on the decoder task queue.
   // Lock for corresponding track must be held.
@@ -118,16 +119,18 @@ private:
   bool IsSupportedVideoMimeType(const char* aMimeType);
   void NotifyResourcesStatusChanged();
   void RequestCodecResource();
   bool IsWaitingOnCodecResource();
   virtual bool IsWaitingOnCDMResource() MOZ_OVERRIDE;
 
   size_t SizeOfQueue(TrackType aTrack);
 
+  nsRefPtr<MP4Stream> mStream;
+  int64_t mTimestampOffset;
   nsAutoPtr<mp4_demuxer::MP4Demuxer> mDemuxer;
   nsRefPtr<PlatformDecoderModule> mPlatform;
 
   class DecoderCallback : public MediaDataDecoderCallback {
   public:
     DecoderCallback(MP4Reader* aReader,
                     mp4_demuxer::TrackType aType)
       : mReader(aReader)
--- a/dom/media/fmp4/MP4Stream.cpp
+++ b/dom/media/fmp4/MP4Stream.cpp
@@ -4,64 +4,71 @@
  * 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 "MP4Stream.h"
 #include "MediaResource.h"
 
 namespace mozilla {
 
-MP4Stream::MP4Stream(MediaResource* aResource, Monitor* aDemuxerMonitor)
+MP4Stream::MP4Stream(MediaResource* aResource)
   : mResource(aResource)
-  , mDemuxerMonitor(aDemuxerMonitor)
 {
   MOZ_COUNT_CTOR(MP4Stream);
   MOZ_ASSERT(aResource);
 }
 
 MP4Stream::~MP4Stream()
 {
   MOZ_COUNT_DTOR(MP4Stream);
 }
 
 bool
-MP4Stream::ReadAt(int64_t aOffset, void* aBuffer, size_t aCount,
-                  size_t* aBytesRead)
+MP4Stream::BlockingReadAt(int64_t aOffset, void* aBuffer, size_t aCount,
+                          size_t* aBytesRead)
 {
-  // The read call can acquire various monitors, including both the decoder
-  // monitor and gMediaCache's monitor. So we need to unlock ours to avoid
-  // deadlock.
-  mDemuxerMonitor->AssertCurrentThreadOwns();
-  MonitorAutoUnlock unlock(*mDemuxerMonitor);
-
   uint32_t sum = 0;
   uint32_t bytesRead = 0;
   do {
     uint64_t offset = aOffset + sum;
     char* buffer = reinterpret_cast<char*>(aBuffer) + sum;
     uint32_t toRead = aCount - sum;
     nsresult rv = mResource->ReadAt(offset, buffer, toRead, &bytesRead);
     if (NS_FAILED(rv)) {
       return false;
     }
     sum += bytesRead;
   } while (sum < aCount && bytesRead > 0);
   *aBytesRead = sum;
   return true;
 }
 
+// We surreptitiously reimplement the supposedly-blocking ReadAt as a non-
+// blocking CachedReadAt, and record when it fails. This allows MP4Reader
+// to retry the read as an actual blocking read without holding the lock.
+bool
+MP4Stream::ReadAt(int64_t aOffset, void* aBuffer, size_t aCount,
+                  size_t* aBytesRead)
+{
+  if (mFailedRead.isSome()) {
+    mFailedRead.reset();
+  }
+
+  if (!CachedReadAt(aOffset, aBuffer, aCount, aBytesRead)) {
+    mFailedRead.emplace(aOffset, aCount);
+    return false;
+  }
+
+  return true;
+}
+
 bool
 MP4Stream::CachedReadAt(int64_t aOffset, void* aBuffer, size_t aCount,
                         size_t* aBytesRead)
 {
-  // The read call can acquire various monitors, including both the decoder
-  // monitor and gMediaCache's monitor. So we need to unlock ours to avoid
-  // deadlock.
-  mDemuxerMonitor->AssertCurrentThreadOwns();
-  MonitorAutoUnlock unlock(*mDemuxerMonitor);
 
   nsresult rv = mResource->ReadFromCache(reinterpret_cast<char*>(aBuffer),
                                          aOffset, aCount);
   if (NS_FAILED(rv)) {
     *aBytesRead = 0;
     return false;
   }
   *aBytesRead = aCount;
--- a/dom/media/fmp4/MP4Stream.h
+++ b/dom/media/fmp4/MP4Stream.h
@@ -4,32 +4,54 @@
  * 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 MP4_STREAM_H_
 #define MP4_STREAM_H_
 
 #include "mp4_demuxer/mp4_demuxer.h"
 
-#include "mozilla/Monitor.h"
+#include "MediaResource.h"
+
+#include "mozilla/Maybe.h"
 
 namespace mozilla {
 
-class MediaResource;
+class Monitor;
 
 class MP4Stream : public mp4_demuxer::Stream {
 public:
-  explicit MP4Stream(MediaResource* aResource, Monitor* aDemuxerMonitor);
+  explicit MP4Stream(MediaResource* aResource);
   virtual ~MP4Stream();
+  bool BlockingReadAt(int64_t aOffset, void* aBuffer, size_t aCount, size_t* aBytesRead);
   virtual bool ReadAt(int64_t aOffset, void* aBuffer, size_t aCount,
                       size_t* aBytesRead) MOZ_OVERRIDE;
   virtual bool CachedReadAt(int64_t aOffset, void* aBuffer, size_t aCount,
                             size_t* aBytesRead) MOZ_OVERRIDE;
   virtual bool Length(int64_t* aSize) MOZ_OVERRIDE;
 
+  struct ReadRecord {
+    ReadRecord(int64_t aOffset, size_t aCount) : mOffset(aOffset), mCount(aCount) {}
+    bool operator==(const ReadRecord& aOther) { return mOffset == aOther.mOffset && mCount == aOther.mCount; }
+    int64_t mOffset;
+    size_t mCount;
+  };
+  bool LastReadFailed(ReadRecord* aOut)
+  {
+    if (mFailedRead.isSome()) {
+      *aOut = mFailedRead.ref();
+      return true;
+    }
+
+    return false;
+  }
+
+  void Pin() { mResource->Pin(); }
+  void Unpin() { mResource->Unpin(); }
+
 private:
   nsRefPtr<MediaResource> mResource;
-  Monitor* mDemuxerMonitor;
+  Maybe<ReadRecord> mFailedRead;
 };
 
 }
 
 #endif
--- a/dom/media/fmp4/android/AndroidDecoderModule.cpp
+++ b/dom/media/fmp4/android/AndroidDecoderModule.cpp
@@ -19,35 +19,35 @@
 #include "nsThreadUtils.h"
 #include "nsAutoPtr.h"
 
 #include <jni.h>
 #include <string.h>
 
 using namespace mozilla;
 using namespace mozilla::gl;
-using namespace mozilla::widget::android::sdk;
+using namespace mozilla::widget::sdk;
 
 namespace mozilla {
 
-static MediaCodec* CreateDecoder(JNIEnv* aEnv, const char* aMimeType)
+static MediaCodec::LocalRef CreateDecoder(const char* aMimeType)
 {
   if (!aMimeType) {
     return nullptr;
   }
 
-  jobject decoder = MediaCodec::CreateDecoderByType(nsCString(aMimeType));
-
-  return new MediaCodec(decoder, aEnv);
+  MediaCodec::LocalRef codec;
+  NS_ENSURE_SUCCESS(MediaCodec::CreateDecoderByType(aMimeType, &codec), nullptr);
+  return codec;
 }
 
 class VideoDataDecoder : public MediaCodecDataDecoder {
 public:
   VideoDataDecoder(const mp4_demuxer::VideoDecoderConfig& aConfig,
-                   MediaFormat* aFormat, MediaDataDecoderCallback* aCallback,
+                   MediaFormat::Param aFormat, MediaDataDecoderCallback* aCallback,
                    layers::ImageContainer* aImageContainer)
     : MediaCodecDataDecoder(MediaData::Type::VIDEO_DATA, aConfig.mime_type, aFormat, aCallback)
     , mImageContainer(aImageContainer)
     , mConfig(aConfig)
   {
 
   }
 
@@ -103,17 +103,17 @@ public:
     EGLImage eglImage = sEGLLibrary.fCreateImage(EGL_DISPLAY(), eglContext,
                                                  LOCAL_EGL_GL_TEXTURE_2D_KHR,
                                                  (EGLClientBuffer)tex, attribs);
     mGLContext->fDeleteTextures(1, &tex);
 
     return eglImage;
   }
 
-  virtual nsresult PostOutput(BufferInfo* aInfo, MediaFormat* aFormat, Microseconds aDuration) MOZ_OVERRIDE {
+  virtual nsresult PostOutput(BufferInfo::Param aInfo, MediaFormat::Param aFormat, Microseconds aDuration) MOZ_OVERRIDE {
     VideoInfo videoInfo;
     videoInfo.mDisplay = nsIntSize(mConfig.display_width, mConfig.display_height);
 
     EGLImage eglImage = CopySurface();
     if (!eglImage) {
       return NS_ERROR_FAILURE;
     }
 
@@ -138,23 +138,33 @@ public:
     data.mSync = eglSync;
     data.mOwns = true;
     data.mSize = gfx::IntSize(mConfig.display_width, mConfig.display_height);
     data.mOriginPos = gl::OriginPos::BottomLeft;
 
     layers::EGLImageImage* typedImg = static_cast<layers::EGLImageImage*>(img.get());
     typedImg->SetData(data);
 
-    bool isSync = !!(MediaCodec::getBUFFER_FLAG_SYNC_FRAME() & aInfo->getFlags());
+    nsresult rv;
+    int32_t flags;
+    NS_ENSURE_SUCCESS(rv = aInfo->Flags(&flags), rv);
+
+    bool isSync = !!(flags & MediaCodec::BUFFER_FLAG_SYNC_FRAME);
 
-    nsRefPtr<VideoData> v = VideoData::CreateFromImage(videoInfo, mImageContainer, aInfo->getOffset(),
-                                                       aInfo->getPresentationTimeUs(),
+    int32_t offset;
+    NS_ENSURE_SUCCESS(rv = aInfo->Offset(&offset), rv);
+
+    int64_t presentationTimeUs;
+    NS_ENSURE_SUCCESS(rv = aInfo->PresentationTimeUs(&presentationTimeUs), rv);
+
+    nsRefPtr<VideoData> v = VideoData::CreateFromImage(videoInfo, mImageContainer, offset,
+                                                       presentationTimeUs,
                                                        aDuration,
                                                        img, isSync,
-                                                       aInfo->getPresentationTimeUs(),
+                                                       presentationTimeUs,
                                                        gfx::IntRect(0, 0,
                                                          mConfig.display_width,
                                                          mConfig.display_height));
     mCallback->Output(v);
     return NS_OK;
   }
 
 protected:
@@ -169,129 +179,131 @@ protected:
 
   layers::ImageContainer* mImageContainer;
   const mp4_demuxer::VideoDecoderConfig& mConfig;
   RefPtr<AndroidSurfaceTexture> mSurfaceTexture;
   nsRefPtr<GLContext> mGLContext;
 };
 
 class AudioDataDecoder : public MediaCodecDataDecoder {
+private:
+  uint8_t csd0[2];
+
 public:
-  AudioDataDecoder(const char* aMimeType, MediaFormat* aFormat, MediaDataDecoderCallback* aCallback)
-  : MediaCodecDataDecoder(MediaData::Type::AUDIO_DATA, aMimeType, aFormat, aCallback)
+  AudioDataDecoder(const mp4_demuxer::AudioDecoderConfig& aConfig, MediaFormat::Param aFormat, MediaDataDecoderCallback* aCallback)
+    : MediaCodecDataDecoder(MediaData::Type::AUDIO_DATA, aConfig.mime_type, aFormat, aCallback)
   {
+    JNIEnv* env = GetJNIForThread();
+
+    jni::Object::LocalRef buffer(env);
+    NS_ENSURE_SUCCESS_VOID(aFormat->GetByteBuffer(NS_LITERAL_STRING("csd-0"), &buffer));
+
+    if (!buffer) {
+      csd0[0] = (*aConfig.audio_specific_config)[0];
+      csd0[1] = (*aConfig.audio_specific_config)[1];
+
+      buffer = jni::Object::LocalRef::Adopt(env, env->NewDirectByteBuffer(csd0, 2));
+      NS_ENSURE_SUCCESS_VOID(aFormat->SetByteBuffer(NS_LITERAL_STRING("csd-0"), buffer));
+    }
   }
 
-  nsresult Output(BufferInfo* aInfo, void* aBuffer, MediaFormat* aFormat, Microseconds aDuration) {
+  nsresult Output(BufferInfo::Param aInfo, void* aBuffer, MediaFormat::Param aFormat, Microseconds aDuration) {
     // The output on Android is always 16-bit signed
 
-    uint32_t numChannels = aFormat->GetInteger(NS_LITERAL_CSTRING("channel-count"));
-    uint32_t sampleRate = aFormat->GetInteger(NS_LITERAL_CSTRING("sample-rate"));
-    uint32_t numFrames = (aInfo->getSize() / numChannels) / 2;
+    nsresult rv;
+    int32_t numChannels;
+    NS_ENSURE_SUCCESS(rv =
+        aFormat->GetInteger(NS_LITERAL_STRING("channel-count"), &numChannels), rv);
+
+    int32_t sampleRate;
+    NS_ENSURE_SUCCESS(rv =
+        aFormat->GetInteger(NS_LITERAL_STRING("sample-rate"), &sampleRate), rv);
+
+    int32_t size;
+    NS_ENSURE_SUCCESS(rv = aInfo->Size(&size), rv);
 
-    AudioDataValue* audio = new AudioDataValue[aInfo->getSize()];
-    PodCopy(audio, static_cast<AudioDataValue*>(aBuffer), aInfo->getSize());
+    const int32_t numFrames = (size / numChannels) / 2;
+    AudioDataValue* audio = new AudioDataValue[size];
+    PodCopy(audio, static_cast<AudioDataValue*>(aBuffer), size);
 
-    nsRefPtr<AudioData> data = new AudioData(aInfo->getOffset(), aInfo->getPresentationTimeUs(),
+    int32_t offset;
+    NS_ENSURE_SUCCESS(rv = aInfo->Offset(&offset), rv);
+
+    int64_t presentationTimeUs;
+    NS_ENSURE_SUCCESS(rv = aInfo->PresentationTimeUs(&presentationTimeUs), rv);
+
+    nsRefPtr<AudioData> data = new AudioData(offset, presentationTimeUs,
                                              aDuration,
                                              numFrames,
                                              audio,
                                              numChannels,
                                              sampleRate);
     mCallback->Output(data);
     return NS_OK;
   }
 };
 
 
 bool AndroidDecoderModule::SupportsAudioMimeType(const char* aMimeType) {
-  JNIEnv* env = GetJNIForThread();
-  MediaCodec* decoder = CreateDecoder(env, aMimeType);
-  bool supports = (decoder != nullptr);
-  delete decoder;
-  return supports;
+  return static_cast<bool>(CreateDecoder(aMimeType));
 }
 
 already_AddRefed<MediaDataDecoder>
 AndroidDecoderModule::CreateVideoDecoder(
                                 const mp4_demuxer::VideoDecoderConfig& aConfig,
                                 layers::LayersBackend aLayersBackend,
                                 layers::ImageContainer* aImageContainer,
                                 MediaTaskQueue* aVideoTaskQueue,
                                 MediaDataDecoderCallback* aCallback)
 {
-  jobject jFormat = MediaFormat::CreateVideoFormat(nsCString(aConfig.mime_type),
-                                                   aConfig.display_width,
-                                                   aConfig.display_height);
+  MediaFormat::LocalRef format;
 
-  if (!jFormat) {
-    return nullptr;
-  }
-
-  MediaFormat* format = MediaFormat::Wrap(jFormat);
-
-  if (!format) {
-    return nullptr;
-  }
+  NS_ENSURE_SUCCESS(MediaFormat::CreateVideoFormat(
+      aConfig.mime_type,
+      aConfig.display_width,
+      aConfig.display_height,
+      &format), nullptr);
 
   nsRefPtr<MediaDataDecoder> decoder =
     new VideoDataDecoder(aConfig, format, aCallback, aImageContainer);
 
   return decoder.forget();
 }
 
 already_AddRefed<MediaDataDecoder>
 AndroidDecoderModule::CreateAudioDecoder(const mp4_demuxer::AudioDecoderConfig& aConfig,
                                          MediaTaskQueue* aAudioTaskQueue,
                                          MediaDataDecoderCallback* aCallback)
 {
   MOZ_ASSERT(aConfig.bits_per_sample == 16, "We only handle 16-bit audio!");
 
-  jobject jFormat = MediaFormat::CreateAudioFormat(nsCString(aConfig.mime_type),
-                                                   aConfig.samples_per_second,
-                                                   aConfig.channel_count);
-
-  if (jFormat == nullptr)
-    return nullptr;
-
-  MediaFormat* format = MediaFormat::Wrap(jFormat);
-
-  if(format == nullptr)
-    return nullptr;
+  MediaFormat::LocalRef format;
 
-  JNIEnv* env = GetJNIForThread();
-
-  if (!format->GetByteBuffer(NS_LITERAL_CSTRING("csd-0"))) {
-    uint8_t* csd0 = new uint8_t[2];
-
-    csd0[0] = (*aConfig.audio_specific_config)[0];
-    csd0[1] = (*aConfig.audio_specific_config)[1];
-
-    jobject buffer = env->NewDirectByteBuffer(csd0, 2);
-    format->SetByteBuffer(NS_LITERAL_CSTRING("csd-0"), buffer);
-
-    env->DeleteLocalRef(buffer);
-  }
+  NS_ENSURE_SUCCESS(MediaFormat::CreateAudioFormat(
+      aConfig.mime_type,
+      aConfig.samples_per_second,
+      aConfig.channel_count,
+      &format), nullptr);
 
   nsRefPtr<MediaDataDecoder> decoder =
-    new AudioDataDecoder(aConfig.mime_type, format, aCallback);
+    new AudioDataDecoder(aConfig, format, aCallback);
 
   return decoder.forget();
 
 }
 
 
 nsresult AndroidDecoderModule::Shutdown()
 {
   return NS_OK;
 }
 
 MediaCodecDataDecoder::MediaCodecDataDecoder(MediaData::Type aType,
                                              const char* aMimeType,
-                                             MediaFormat* aFormat,
+                                             MediaFormat::Param aFormat,
                                              MediaDataDecoderCallback* aCallback)
   : mType(aType)
   , mMimeType(strdup(aMimeType))
   , mFormat(aFormat)
   , mCallback(aCallback)
   , mInputBuffers(nullptr)
   , mOutputBuffers(nullptr)
   , mMonitor("MediaCodecDataDecoder::mMonitor")
@@ -299,65 +311,38 @@ MediaCodecDataDecoder::MediaCodecDataDec
   , mDraining(false)
   , mStopping(false)
 {
 
 }
 
 MediaCodecDataDecoder::~MediaCodecDataDecoder()
 {
-  JNIEnv* env = GetJNIForThread();
-
   Shutdown();
-
-  if (mInputBuffers) {
-    env->DeleteGlobalRef(mInputBuffers);
-    mInputBuffers = nullptr;
-  }
-
-  if (mOutputBuffers) {
-    env->DeleteGlobalRef(mOutputBuffers);
-    mOutputBuffers = nullptr;
-  }
 }
 
 nsresult MediaCodecDataDecoder::Init()
 {
-  return InitDecoder();
+  return InitDecoder(nullptr);
 }
 
-nsresult MediaCodecDataDecoder::InitDecoder(jobject aSurface)
+nsresult MediaCodecDataDecoder::InitDecoder(Surface::Param aSurface)
 {
-  JNIEnv* env = GetJNIForThread();
-  mDecoder = CreateDecoder(env, mMimeType);
+  mDecoder = CreateDecoder(mMimeType);
   if (!mDecoder) {
     mCallback->Error();
     return NS_ERROR_FAILURE;
   }
 
-  nsresult res;
-  mDecoder->Configure(mFormat->wrappedObject(), aSurface, nullptr, 0, &res);
-  if (NS_FAILED(res)) {
-    return res;
-  }
+  nsresult rv;
+  NS_ENSURE_SUCCESS(rv = mDecoder->Configure(mFormat, aSurface, nullptr, 0), rv);
+  NS_ENSURE_SUCCESS(rv = mDecoder->Start(), rv);
 
-  mDecoder->Start(&res);
-  if (NS_FAILED(res)) {
-    return res;
-  }
-
-  res = ResetInputBuffers();
-  if (NS_FAILED(res)) {
-    return res;
-  }
-
-  res = ResetOutputBuffers();
-  if (NS_FAILED(res)) {
-    return res;
-  }
+  NS_ENSURE_SUCCESS(rv = ResetInputBuffers(), rv);
+  NS_ENSURE_SUCCESS(rv = ResetOutputBuffers(), rv);
 
   NS_NewNamedThread("MC Decoder", getter_AddRefs(mThread),
                     NS_NewRunnableMethod(this, &MediaCodecDataDecoder::DecoderLoop));
 
   return NS_OK;
 }
 
 // This is in usec, so that's 10ms
@@ -372,20 +357,20 @@ nsresult MediaCodecDataDecoder::InitDeco
 
 void MediaCodecDataDecoder::DecoderLoop()
 {
   bool outputDone = false;
 
   bool draining = false;
   bool waitingEOF = false;
 
-  JNIEnv* env = GetJNIForThread();
+  AutoLocalJNIFrame frame(GetJNIForThread(), 1);
   mp4_demuxer::MP4Sample* sample = nullptr;
 
-  nsAutoPtr<MediaFormat> outputFormat;
+  MediaFormat::LocalRef outputFormat(frame.GetEnv());
   nsresult res;
 
   for (;;) {
     {
       MonitorAutoLock lock(mMonitor);
       while (!mStopping && !mDraining && !mFlushing && mQueue.empty()) {
         if (mQueue.empty()) {
           // We could be waiting here forever if we don't signal that we need more input
@@ -415,80 +400,92 @@ void MediaCodecDataDecoder::DecoderLoop(
       if (!mQueue.empty()) {
         sample = mQueue.front();
       }
     }
 
     if (draining && !waitingEOF) {
       MOZ_ASSERT(!sample, "Shouldn't have a sample when pushing EOF frame");
 
-      int inputIndex = mDecoder->DequeueInputBuffer(DECODER_TIMEOUT, &res);
+      int32_t inputIndex;
+      res = mDecoder->DequeueInputBuffer(DECODER_TIMEOUT, &inputIndex);
       HANDLE_DECODER_ERROR();
 
       if (inputIndex >= 0) {
-        mDecoder->QueueInputBuffer(inputIndex, 0, 0, 0, MediaCodec::getBUFFER_FLAG_END_OF_STREAM(), &res);
+        res = mDecoder->QueueInputBuffer(inputIndex, 0, 0, 0, MediaCodec::BUFFER_FLAG_END_OF_STREAM);
+        HANDLE_DECODER_ERROR();
+
         waitingEOF = true;
       }
     }
 
     if (sample) {
       // We have a sample, try to feed it to the decoder
-      int inputIndex = mDecoder->DequeueInputBuffer(DECODER_TIMEOUT, &res);
+      int inputIndex;
+      res = mDecoder->DequeueInputBuffer(DECODER_TIMEOUT, &inputIndex);
       HANDLE_DECODER_ERROR();
 
       if (inputIndex >= 0) {
-        jobject buffer = env->GetObjectArrayElement(mInputBuffers, inputIndex);
-        void* directBuffer = env->GetDirectBufferAddress(buffer);
+        auto buffer = jni::Object::LocalRef::Adopt(
+            frame.GetEnv()->GetObjectArrayElement(mInputBuffers.Get(), inputIndex));
+        void* directBuffer = frame.GetEnv()->GetDirectBufferAddress(buffer.Get());
 
-        // We're feeding this to the decoder, so remove it from the queue
-        mMonitor.Lock();
-        mQueue.pop();
-        mMonitor.Unlock();
+        MOZ_ASSERT(frame.GetEnv()->GetDirectBufferCapacity(buffer.Get()) >= sample->size,
+          "Decoder buffer is not large enough for sample");
 
-        MOZ_ASSERT(env->GetDirectBufferCapacity(buffer) >= sample->size,
-          "Decoder buffer is not large enough for sample");
+        {
+          // We're feeding this to the decoder, so remove it from the queue
+          MonitorAutoLock lock(mMonitor);
+          mQueue.pop();
+        }
 
         PodCopy((uint8_t*)directBuffer, sample->data, sample->size);
 
-        mDecoder->QueueInputBuffer(inputIndex, 0, sample->size, sample->composition_timestamp, 0, &res);
+        res = mDecoder->QueueInputBuffer(inputIndex, 0, sample->size,
+                                         sample->composition_timestamp, 0);
         HANDLE_DECODER_ERROR();
 
         mDurations.push(sample->duration);
-
         delete sample;
         sample = nullptr;
-
         outputDone = false;
-        env->DeleteLocalRef(buffer);
       }
     }
 
     if (!outputDone) {
-      BufferInfo bufferInfo;
+      BufferInfo::LocalRef bufferInfo;
+      res = BufferInfo::New(&bufferInfo);
+      HANDLE_DECODER_ERROR();
 
-      int outputStatus = mDecoder->DequeueOutputBuffer(bufferInfo.wrappedObject(), DECODER_TIMEOUT, &res);
+      int32_t outputStatus;
+      res = mDecoder->DequeueOutputBuffer(bufferInfo, DECODER_TIMEOUT, &outputStatus);
       HANDLE_DECODER_ERROR();
 
-      if (outputStatus == MediaCodec::getINFO_TRY_AGAIN_LATER()) {
+      if (outputStatus == MediaCodec::INFO_TRY_AGAIN_LATER) {
         // We might want to call mCallback->InputExhausted() here, but there seems to be
         // some possible bad interactions here with the threading
-      } else if (outputStatus == MediaCodec::getINFO_OUTPUT_BUFFERS_CHANGED()) {
+      } else if (outputStatus == MediaCodec::INFO_OUTPUT_BUFFERS_CHANGED) {
         res = ResetOutputBuffers();
         HANDLE_DECODER_ERROR();
-      } else if (outputStatus == MediaCodec::getINFO_OUTPUT_FORMAT_CHANGED()) {
-        outputFormat = new MediaFormat(mDecoder->GetOutputFormat(), GetJNIForThread());
+      } else if (outputStatus == MediaCodec::INFO_OUTPUT_FORMAT_CHANGED) {
+        res = mDecoder->GetOutputFormat(ReturnTo(&outputFormat));
+        HANDLE_DECODER_ERROR();
       } else if (outputStatus < 0) {
         NS_WARNING("unknown error from decoder!");
         mCallback->Error();
 
         // Don't break here just in case it's recoverable. If it's not, others stuff will fail later and
         // we'll bail out.
       } else {
+        int32_t flags;
+        res = bufferInfo->Flags(&flags);
+        HANDLE_DECODER_ERROR();
+
         // We have a valid buffer index >= 0 here
-        if (bufferInfo.getFlags() & MediaCodec::getBUFFER_FLAG_END_OF_STREAM()) {
+        if (flags & MediaCodec::BUFFER_FLAG_END_OF_STREAM) {
           if (draining) {
             draining = false;
             waitingEOF = false;
 
             mMonitor.Lock();
             mDraining = false;
             mMonitor.Notify();
             mMonitor.Unlock();
@@ -506,42 +503,38 @@ void MediaCodecDataDecoder::DecoderLoop(
         MOZ_ASSERT(!mDurations.empty(), "Should have had a duration queued");
 
         Microseconds duration = 0;
         if (!mDurations.empty()) {
           duration = mDurations.front();
           mDurations.pop();
         }
 
-        jobject buffer = env->GetObjectArrayElement(mOutputBuffers, outputStatus);
+        auto buffer = jni::Object::LocalRef::Adopt(
+            frame.GetEnv()->GetObjectArrayElement(mOutputBuffers.Get(), outputStatus));
         if (buffer) {
           // The buffer will be null on Android L if we are decoding to a Surface
-          void* directBuffer = env->GetDirectBufferAddress(buffer);
-          Output(&bufferInfo, directBuffer, outputFormat, duration);
+          void* directBuffer = frame.GetEnv()->GetDirectBufferAddress(buffer.Get());
+          Output(bufferInfo, directBuffer, outputFormat, duration);
         }
 
         // The Surface will be updated at this point (for video)
         mDecoder->ReleaseOutputBuffer(outputStatus, true);
 
-        PostOutput(&bufferInfo, outputFormat, duration);
-
-        if (buffer) {
-          env->DeleteLocalRef(buffer);
-        }
+        PostOutput(bufferInfo, outputFormat, duration);
       }
     }
   }
 
   Cleanup();
 
   // We're done
-  mMonitor.Lock();
+  MonitorAutoLock lock(mMonitor);
   mStopping = false;
   mMonitor.Notify();
-  mMonitor.Unlock();
 }
 
 void MediaCodecDataDecoder::ClearQueue()
 {
   mMonitor.AssertCurrentThreadOwns();
   while (!mQueue.empty()) {
     delete mQueue.front();
     mQueue.pop();
@@ -556,46 +549,22 @@ nsresult MediaCodecDataDecoder::Input(mp
   mQueue.push(aSample);
   lock.NotifyAll();
 
   return NS_OK;
 }
 
 nsresult MediaCodecDataDecoder::ResetInputBuffers()
 {
-  JNIEnv* env = GetJNIForThread();
-
-  if (mInputBuffers) {
-    env->DeleteGlobalRef(mInputBuffers);
-  }
-
-  nsresult res;
-  mInputBuffers = (jobjectArray) env->NewGlobalRef(mDecoder->GetInputBuffers(&res));
-  if (NS_FAILED(res)) {
-    return res;
-  }
-
-  return NS_OK;
+  return mDecoder->GetInputBuffers(ReturnTo(&mInputBuffers));
 }
 
 nsresult MediaCodecDataDecoder::ResetOutputBuffers()
 {
-  JNIEnv* env = GetJNIForThread();
-
-  if (mOutputBuffers) {
-    env->DeleteGlobalRef(mOutputBuffers);
-  }
-
-  nsresult res;
-  mOutputBuffers = (jobjectArray) env->NewGlobalRef(mDecoder->GetOutputBuffers(&res));
-  if (NS_FAILED(res)) {
-    return res;
-  }
-
-  return NS_OK;
+  return mDecoder->GetOutputBuffers(ReturnTo(&mOutputBuffers));
 }
 
 nsresult MediaCodecDataDecoder::Flush() {
   MonitorAutoLock lock(mMonitor);
   mFlushing = true;
   lock.Notify();
 
   while (mFlushing) {
--- a/dom/media/fmp4/android/AndroidDecoderModule.h
+++ b/dom/media/fmp4/android/AndroidDecoderModule.h
@@ -12,28 +12,16 @@
 #include "mozilla/Monitor.h"
 
 #include <queue>
 
 namespace mozilla {
 
 typedef std::queue<mp4_demuxer::MP4Sample*> SampleQueue;
 
-namespace widget {
-namespace android {
-namespace sdk {
-  class MediaCodec;
-  class MediaFormat;
-  class ByteBuffer;
-}
-}
-}
-
-class MediaCodecDataDecoder;
-
 class AndroidDecoderModule : public PlatformDecoderModule {
 public:
   virtual nsresult Shutdown() MOZ_OVERRIDE;
 
   virtual already_AddRefed<MediaDataDecoder>
   CreateVideoDecoder(const mp4_demuxer::VideoDecoderConfig& aConfig,
                      layers::LayersBackend aLayersBackend,
                      layers::ImageContainer* aImageContainer,
@@ -52,57 +40,57 @@ public:
   virtual bool SupportsAudioMimeType(const char* aMimeType) MOZ_OVERRIDE;
 };
 
 class MediaCodecDataDecoder : public MediaDataDecoder {
 public:
 
   MediaCodecDataDecoder(MediaData::Type aType,
                         const char* aMimeType,
-                        mozilla::widget::android::sdk::MediaFormat* aFormat,
+                        widget::sdk::MediaFormat::Param aFormat,
                         MediaDataDecoderCallback* aCallback);
 
   virtual ~MediaCodecDataDecoder();
 
   virtual nsresult Init() MOZ_OVERRIDE;
   virtual nsresult Flush() MOZ_OVERRIDE;
   virtual nsresult Drain() MOZ_OVERRIDE;
   virtual nsresult Shutdown() MOZ_OVERRIDE;
   virtual nsresult Input(mp4_demuxer::MP4Sample* aSample);
 
 protected:
   friend class AndroidDecoderModule;
 
   MediaData::Type mType;
 
   nsAutoPtr<char> mMimeType;
-  nsAutoPtr<mozilla::widget::android::sdk::MediaFormat> mFormat;
+  widget::sdk::MediaFormat::GlobalRef mFormat;
 
   MediaDataDecoderCallback* mCallback;
 
-  nsAutoPtr<mozilla::widget::android::sdk::MediaCodec> mDecoder;
+  widget::sdk::MediaCodec::GlobalRef mDecoder;
 
-  jobjectArray mInputBuffers;
-  jobjectArray mOutputBuffers;
+  jni::ObjectArray::GlobalRef mInputBuffers;
+  jni::ObjectArray::GlobalRef mOutputBuffers;
 
   nsCOMPtr<nsIThread> mThread;
 
   // Only these members are protected by mMonitor.
   Monitor mMonitor;
   bool mFlushing;
   bool mDraining;
   bool mStopping;
 
   SampleQueue mQueue;
   std::queue<Microseconds> mDurations;
 
-  virtual nsresult InitDecoder(jobject aSurface = nullptr);
+  virtual nsresult InitDecoder(widget::sdk::Surface::Param aSurface);
 
-  virtual nsresult Output(mozilla::widget::android::sdk::BufferInfo* aInfo, void* aBuffer, mozilla::widget::android::sdk::MediaFormat* aFormat, Microseconds aDuration) { return NS_OK; }
-  virtual nsresult PostOutput(mozilla::widget::android::sdk::BufferInfo* aInfo, mozilla::widget::android::sdk::MediaFormat* aFormat, Microseconds aDuration) { return NS_OK; }
+  virtual nsresult Output(widget::sdk::BufferInfo::Param aInfo, void* aBuffer, widget::sdk::MediaFormat::Param aFormat, Microseconds aDuration) { return NS_OK; }
+  virtual nsresult PostOutput(widget::sdk::BufferInfo::Param aInfo, widget::sdk::MediaFormat::Param aFormat, Microseconds aDuration) { return NS_OK; }
   virtual void Cleanup() {};
 
   nsresult ResetInputBuffers();
   nsresult ResetOutputBuffers();
 
   void DecoderLoop();
   virtual void ClearQueue();
 };
--- a/dom/media/gmp-plugin/gmp-test-decryptor.cpp
+++ b/dom/media/gmp-plugin/gmp-test-decryptor.cpp
@@ -12,17 +12,16 @@
 #include <iostream>
 #include <istream>
 #include <iterator>
 #include <sstream>
 #include <set>
 
 #include "mozilla/Assertions.h"
 #include "mozilla/Attributes.h"
-#include "mozilla/NullPtr.h"
 
 using namespace std;
 
 FakeDecryptor* FakeDecryptor::sInstance = nullptr;
 extern GMPPlatformAPI* g_platform_api; // Defined in gmp-fake.cpp
 
 class GMPMutexAutoLock
 {
--- a/dom/media/gmp-plugin/gmp-test-storage.cpp
+++ b/dom/media/gmp-plugin/gmp-test-storage.cpp
@@ -3,17 +3,16 @@
  * 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 "gmp-test-storage.h"
 #include <vector>
 
 #include "mozilla/Assertions.h"
 #include "mozilla/Attributes.h"
-#include "mozilla/NullPtr.h"
 
 class WriteRecordClient : public GMPRecordClient {
 public:
   GMPErr Init(GMPRecord* aRecord,
               GMPTask* aOnSuccess,
               GMPTask* aOnFailure,
               const uint8_t* aData,
               uint32_t aDataSize) {
--- a/dom/media/gmp/GMPLoader.cpp
+++ b/dom/media/gmp/GMPLoader.cpp
@@ -2,17 +2,16 @@
  * vim: sw=4 ts=4 et :
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "GMPLoader.h"
 #include <stdio.h>
 #include "mozilla/Attributes.h"
-#include "mozilla/NullPtr.h"
 #include "gmp-entrypoints.h"
 #include "prlink.h"
 
 #include <string>
 
 #if defined(XP_WIN) && defined(MOZ_SANDBOX)
 #include "mozilla/sandboxTarget.h"
 #include "windows.h"
--- a/dom/media/gmp/GMPVideoDecoderChild.cpp
+++ b/dom/media/gmp/GMPVideoDecoderChild.cpp
@@ -12,17 +12,17 @@
 
 namespace mozilla {
 namespace gmp {
 
 GMPVideoDecoderChild::GMPVideoDecoderChild(GMPChild* aPlugin)
 : GMPSharedMemManager(aPlugin),
   mPlugin(aPlugin),
   mVideoDecoder(nullptr),
-  mVideoHost(MOZ_THIS_IN_INITIALIZER_LIST())
+  mVideoHost(this)
 {
   MOZ_ASSERT(mPlugin);
 }
 
 GMPVideoDecoderChild::~GMPVideoDecoderChild()
 {
 }
 
--- a/dom/media/gmp/GMPVideoDecoderParent.cpp
+++ b/dom/media/gmp/GMPVideoDecoderParent.cpp
@@ -43,17 +43,17 @@ namespace gmp {
 // Dead: mIsOpen == false
 
 GMPVideoDecoderParent::GMPVideoDecoderParent(GMPParent* aPlugin)
   : GMPSharedMemManager(aPlugin)
   , mIsOpen(false)
   , mShuttingDown(false)
   , mPlugin(aPlugin)
   , mCallback(nullptr)
-  , mVideoHost(MOZ_THIS_IN_INITIALIZER_LIST())
+  , mVideoHost(this)
 {
   MOZ_ASSERT(mPlugin);
 }
 
 GMPVideoDecoderParent::~GMPVideoDecoderParent()
 {
 }
 
--- a/dom/media/gmp/GMPVideoEncoderChild.cpp
+++ b/dom/media/gmp/GMPVideoEncoderChild.cpp
@@ -12,17 +12,17 @@
 
 namespace mozilla {
 namespace gmp {
 
 GMPVideoEncoderChild::GMPVideoEncoderChild(GMPChild* aPlugin)
 : GMPSharedMemManager(aPlugin),
   mPlugin(aPlugin),
   mVideoEncoder(nullptr),
-  mVideoHost(MOZ_THIS_IN_INITIALIZER_LIST())
+  mVideoHost(this)
 {
   MOZ_ASSERT(mPlugin);
 }
 
 GMPVideoEncoderChild::~GMPVideoEncoderChild()
 {
 }
 
--- a/dom/media/gmp/GMPVideoEncoderParent.cpp
+++ b/dom/media/gmp/GMPVideoEncoderParent.cpp
@@ -50,17 +50,17 @@ namespace gmp {
 // Dead: mIsOpen == false
 
 GMPVideoEncoderParent::GMPVideoEncoderParent(GMPParent *aPlugin)
 : GMPSharedMemManager(aPlugin),
   mIsOpen(false),
   mShuttingDown(false),
   mPlugin(aPlugin),
   mCallback(nullptr),
-  mVideoHost(MOZ_THIS_IN_INITIALIZER_LIST())
+  mVideoHost(this)
 {
   MOZ_ASSERT(mPlugin);
 
   nsresult rv = NS_NewNamedThread("GMPEncoded", getter_AddRefs(mEncodedThread));
   if (NS_FAILED(rv)) {
     MOZ_CRASH();
   }
 }
--- a/dom/media/gstreamer/GStreamerLoader.cpp
+++ b/dom/media/gstreamer/GStreamerLoader.cpp
@@ -2,17 +2,16 @@
 /* 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 <dlfcn.h>
 #include <stdio.h>
 
 #include "nsDebug.h"
-#include "mozilla/NullPtr.h"
 
 #include "GStreamerLoader.h"
 
 #define LIBGSTREAMER 0
 #define LIBGSTAPP 1
 #define LIBGSTVIDEO 2
 
 #ifdef __OpenBSD__
--- a/dom/media/gstreamer/GStreamerReader.cpp
+++ b/dom/media/gstreamer/GStreamerReader.cpp
@@ -809,17 +809,17 @@ GStreamerReader::Seek(int64_t aTarget,
     return SeekPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
   }
   LOG(PR_LOG_DEBUG, "seek succeeded");
   GstMessage* message = gst_bus_timed_pop_filtered(mBus, GST_CLOCK_TIME_NONE,
                (GstMessageType)(GST_MESSAGE_ASYNC_DONE | GST_MESSAGE_ERROR));
   gst_message_unref(message);
   LOG(PR_LOG_DEBUG, "seek completed");
 
-  return SeekPromise::CreateAndResolve(true, __func__);
+  return SeekPromise::CreateAndResolve(aTarget, __func__);
 }
 
 nsresult GStreamerReader::GetBuffered(dom::TimeRanges* aBuffered)
 {
   if (!mInfo.HasValidMedia()) {
     return NS_OK;
   }
 
--- a/dom/media/gtest/MockMediaResource.cpp
+++ b/dom/media/gtest/MockMediaResource.cpp
@@ -44,17 +44,18 @@ MockMediaResource::ReadAt(int64_t aOffse
 
   // Make it fail if we're re-entrant
   if (mEntry++) {
     MOZ_ASSERT(false);
     return NS_ERROR_FAILURE;
   }
 
   fseek(mFileHandle, aOffset, SEEK_SET);
-  *aBytes = (uint32_t) fread(aBuffer, aCount, 1, mFileHandle);
+  size_t objectsRead = fread(aBuffer, aCount, 1, mFileHandle);
+  *aBytes = objectsRead == 1 ? aCount : 0;
 
   mEntry--;
 
   return ferror(mFileHandle) ? NS_ERROR_FAILURE : NS_OK;
 }
 
 int64_t
 MockMediaResource::GetLength()
--- a/dom/media/gtest/MockMediaResource.h
+++ b/dom/media/gtest/MockMediaResource.h
@@ -54,18 +54,22 @@ public:
   {
     return false;
   }
   virtual bool IsSuspendedByCache() MOZ_OVERRIDE { return false; }
   virtual bool IsSuspended() MOZ_OVERRIDE { return false; }
   virtual nsresult ReadFromCache(char* aBuffer, int64_t aOffset,
                                  uint32_t aCount) MOZ_OVERRIDE
   {
-    return NS_OK;
+    uint32_t bytesRead = 0;
+    nsresult rv = ReadAt(aOffset, aBuffer, aCount, &bytesRead);
+    NS_ENSURE_SUCCESS(rv, rv);
+    return bytesRead == aCount ? NS_OK : NS_ERROR_FAILURE;
   }
+
   virtual bool IsTransportSeekable() MOZ_OVERRIDE { return true; }
   virtual nsresult Open(nsIStreamListener** aStreamListener) MOZ_OVERRIDE;
   virtual nsresult GetCachedRanges(nsTArray<MediaByteRange>& aRanges)
     MOZ_OVERRIDE;
   virtual const nsCString& GetContentType() const MOZ_OVERRIDE
   {
     return mContentType;
   }
--- a/dom/media/gtest/TestMP4Demuxer.cpp
+++ b/dom/media/gtest/TestMP4Demuxer.cpp
@@ -19,17 +19,17 @@ public:
 
   nsRefPtr<MockMediaResource> resource;
   Monitor mMonitor;
   nsAutoPtr<MP4Demuxer> demuxer;
 
   explicit MP4DemuxerBinding(const char* aFileName = "dash_dashinit.mp4")
     : resource(new MockMediaResource(aFileName))
     , mMonitor("TestMP4Demuxer monitor")
-    , demuxer(new MP4Demuxer(new MP4Stream(resource, &mMonitor), 0, &mMonitor))
+    , demuxer(new MP4Demuxer(new MP4Stream(resource), 0, &mMonitor))
   {
     EXPECT_EQ(NS_OK, resource->Open(nullptr));
   }
 
 private:
   virtual ~MP4DemuxerBinding()
   {
   }
--- a/dom/media/mediasource/ContainerParser.cpp
+++ b/dom/media/mediasource/ContainerParser.cpp
@@ -284,19 +284,21 @@ public:
     }
     aStart = compositionRange.start;
     aEnd = compositionRange.end;
     MSE_DEBUG("MP4ContainerParser(%p)::ParseStartAndEndTimestamps: [%lld, %lld]",
               this, aStart, aEnd);
     return true;
   }
 
+  // Gaps of up to 20ms (marginally longer than a single frame at 60fps) are considered
+  // to be sequential frames.
   int64_t GetRoundingError()
   {
-    return 1000;
+    return 20000;
   }
 
 private:
   nsRefPtr<mp4_demuxer::BufferStream> mStream;
   nsAutoPtr<mp4_demuxer::MoofParser> mParser;
   Monitor mMonitor;
 };
 
--- a/dom/media/mediasource/MediaSource.cpp
+++ b/dom/media/mediasource/MediaSource.cpp
@@ -26,16 +26,17 @@
 #include "nsIRunnable.h"
 #include "nsIScriptObjectPrincipal.h"
 #include "nsIURI.h"
 #include "nsNetCID.h"
 #include "nsPIDOMWindow.h"
 #include "nsString.h"
 #include "nsThreadUtils.h"
 #include "prlog.h"
+#include "nsServiceManagerUtils.h"
 
 struct JSContext;
 class JSObject;
 
 #ifdef PR_LOGGING
 PRLogModuleInfo* GetMediaSourceLog()
 {
   static PRLogModuleInfo* sLogModule;
--- a/dom/media/mediasource/MediaSourceReader.cpp
+++ b/dom/media/mediasource/MediaSourceReader.cpp
@@ -41,25 +41,23 @@ extern PRLogModuleInfo* GetMediaSourceAP
 #define EOS_FUZZ_US 125000
 
 using mozilla::dom::TimeRanges;
 
 namespace mozilla {
 
 MediaSourceReader::MediaSourceReader(MediaSourceDecoder* aDecoder)
   : MediaDecoderReader(aDecoder)
-  , mLastAudioTime(-1)
-  , mLastVideoTime(-1)
+  , mLastAudioTime(0)
+  , mLastVideoTime(0)
   , mPendingSeekTime(-1)
   , mPendingStartTime(-1)
   , mPendingEndTime(-1)
   , mPendingCurrentTime(-1)
   , mWaitingForSeekData(false)
-  , mPendingSeeks(0)
-  , mSeekResult(NS_OK)
   , mTimeThreshold(-1)
   , mDropAudioBeforeThreshold(false)
   , mDropVideoBeforeThreshold(false)
   , mEnded(false)
   , mAudioIsSeeking(false)
   , mVideoIsSeeking(false)
   , mHasEssentialTrackBuffers(false)
 #ifdef MOZ_FMP4
@@ -119,21 +117,39 @@ MediaSourceReader::RequestAudioData()
   nsRefPtr<AudioDataPromise> p = mAudioPromise.Ensure(__func__);
   MSE_DEBUGV("MediaSourceReader(%p)::RequestAudioData", this);
   if (!mAudioReader) {
     MSE_DEBUG("MediaSourceReader(%p)::RequestAudioData called with no audio reader", this);
     mAudioPromise.Reject(DECODE_ERROR, __func__);
     return p;
   }
   mAudioIsSeeking = false;
-  SwitchAudioReader(mLastAudioTime);
+  if (SwitchAudioReader(mLastAudioTime)) {
+    mAudioReader->Seek(mLastAudioTime, 0, 0, 0)
+                ->Then(GetTaskQueue(), __func__, this,
+                       &MediaSourceReader::RequestAudioDataComplete,
+                       &MediaSourceReader::RequestAudioDataFailed);
+  } else {
+    RequestAudioDataComplete(0);
+  }
+  return p;
+}
+
+void
+MediaSourceReader::RequestAudioDataComplete(int64_t aTime)
+{
   mAudioReader->RequestAudioData()->Then(GetTaskQueue(), __func__, this,
                                          &MediaSourceReader::OnAudioDecoded,
                                          &MediaSourceReader::OnAudioNotDecoded);
-  return p;
+}
+
+void
+MediaSourceReader::RequestAudioDataFailed(nsresult aResult)
+{
+  OnAudioNotDecoded(DECODE_ERROR);
 }
 
 void
 MediaSourceReader::OnAudioDecoded(AudioData* aSample)
 {
   MSE_DEBUGV("MediaSourceReader(%p)::OnAudioDecoded [mTime=%lld mDuration=%lld mDiscontinuity=%d]",
              this, aSample->mTime, aSample->mDuration, aSample->mDiscontinuity);
   if (mDropAudioBeforeThreshold) {
@@ -198,20 +214,21 @@ MediaSourceReader::OnAudioNotDecoded(Not
   MOZ_ASSERT(aReason == END_OF_STREAM);
   if (mAudioReader) {
     AdjustEndTime(&mLastAudioTime, mAudioReader);
   }
 
   // See if we can find a different reader that can pick up where we left off. We use the
   // EOS_FUZZ_US to allow for the fact that our end time can be inaccurate due to bug
   // 1065207.
-  if (SwitchAudioReader(mLastAudioTime + EOS_FUZZ_US)) {
-    mAudioReader->RequestAudioData()->Then(GetTaskQueue(), __func__, this,
-                                           &MediaSourceReader::OnAudioDecoded,
-                                           &MediaSourceReader::OnAudioNotDecoded);
+  if (SwitchAudioReader(mLastAudioTime, EOS_FUZZ_US)) {
+    mAudioReader->Seek(mLastAudioTime, 0, 0, 0)
+                ->Then(GetTaskQueue(), __func__, this,
+                       &MediaSourceReader::RequestAudioDataComplete,
+                       &MediaSourceReader::RequestAudioDataFailed);
     return;
   }
 
   // If the entire MediaSource is done, generate an EndOfStream.
   if (IsEnded()) {
     mAudioPromise.Reject(END_OF_STREAM, __func__);
     return;
   }
@@ -234,22 +251,42 @@ MediaSourceReader::RequestVideoData(bool
     return p;
   }
   if (aSkipToNextKeyframe) {
     mTimeThreshold = aTimeThreshold;
     mDropAudioBeforeThreshold = true;
     mDropVideoBeforeThreshold = true;
   }
   mVideoIsSeeking = false;
-  SwitchVideoReader(mLastVideoTime);
+  if (SwitchVideoReader(mLastVideoTime)) {
+    mVideoReader->Seek(mLastVideoTime, 0, 0, 0)
+                ->Then(GetTaskQueue(), __func__, this,
+                       &MediaSourceReader::RequestVideoDataComplete,
+                       &MediaSourceReader::RequestVideoDataFailed);
+  } else {
+    mVideoReader->RequestVideoData(aSkipToNextKeyframe, aTimeThreshold)
+                ->Then(GetTaskQueue(), __func__, this,
+                       &MediaSourceReader::OnVideoDecoded, &MediaSourceReader::OnVideoNotDecoded);
+  }
 
-  mVideoReader->RequestVideoData(aSkipToNextKeyframe, aTimeThreshold)
+  return p;
+}
+
+void
+MediaSourceReader::RequestVideoDataComplete(int64_t aTime)
+{
+  mVideoReader->RequestVideoData(false, 0)
               ->Then(GetTaskQueue(), __func__, this,
                      &MediaSourceReader::OnVideoDecoded, &MediaSourceReader::OnVideoNotDecoded);
-  return p;
+}
+
+void
+MediaSourceReader::RequestVideoDataFailed(nsresult aResult)
+{
+  OnVideoNotDecoded(DECODE_ERROR);
 }
 
 void
 MediaSourceReader::OnVideoDecoded(VideoData* aSample)
 {
   MSE_DEBUGV("MediaSourceReader(%p)::OnVideoDecoded [mTime=%lld mDuration=%lld mDiscontinuity=%d]",
              this, aSample->mTime, aSample->mDuration, aSample->mDiscontinuity);
   if (mDropVideoBeforeThreshold) {
@@ -288,21 +325,21 @@ MediaSourceReader::OnVideoNotDecoded(Not
   MOZ_ASSERT(aReason == END_OF_STREAM);
   if (mVideoReader) {
     AdjustEndTime(&mLastVideoTime, mVideoReader);
   }
 
   // See if we can find a different reader that can pick up where we left off. We use the
   // EOS_FUZZ_US to allow for the fact that our end time can be inaccurate due to bug
   // 1065207.
-  if (SwitchVideoReader(mLastVideoTime + EOS_FUZZ_US)) {
-    mVideoReader->RequestVideoData(false, 0)
+  if (SwitchVideoReader(mLastVideoTime, EOS_FUZZ_US)) {
+    mVideoReader->Seek(mLastVideoTime, 0, 0, 0)
                 ->Then(GetTaskQueue(), __func__, this,
-                       &MediaSourceReader::OnVideoDecoded,
-                       &MediaSourceReader::OnVideoNotDecoded);
+                       &MediaSourceReader::RequestVideoDataComplete,
+                       &MediaSourceReader::RequestVideoDataFailed);
     return;
   }
 
   // If the entire MediaSource is done, generate an EndOfStream.
   if (IsEnded()) {
     mVideoPromise.Reject(END_OF_STREAM, __func__);
     return;
   }
@@ -366,75 +403,77 @@ MediaSourceReader::BreakCycles()
   for (uint32_t i = 0; i < mShutdownTrackBuffers.Length(); ++i) {
     mShutdownTrackBuffers[i]->BreakCycles();
   }
   mShutdownTrackBuffers.Clear();
 }
 
 already_AddRefed<MediaDecoderReader>
 MediaSourceReader::SelectReader(int64_t aTarget,
+                                int64_t aError,
                                 const nsTArray<nsRefPtr<SourceBufferDecoder>>& aTrackDecoders)
 {
   mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
 
   // Consider decoders in order of newest to oldest, as a newer decoder
   // providing a given buffered range is expected to replace an older one.
   for (int32_t i = aTrackDecoders.Length() - 1; i >= 0; --i) {
     nsRefPtr<MediaDecoderReader> newReader = aTrackDecoders[i]->GetReader();
 
     nsRefPtr<dom::TimeRanges> ranges = new dom::TimeRanges();
     aTrackDecoders[i]->GetBuffered(ranges);
-    if (ranges->Find(double(aTarget) / USECS_PER_S) == dom::TimeRanges::NoIndex) {
+    if (ranges->Find(double(aTarget) / USECS_PER_S,
+                     double(aError) / USECS_PER_S) == dom::TimeRanges::NoIndex) {
       MSE_DEBUGV("MediaSourceReader(%p)::SelectReader(%lld) newReader=%p target not in ranges=%s",
                  this, aTarget, newReader.get(), DumpTimeRanges(ranges).get());
       continue;
     }
 
     return newReader.forget();
   }
 
   return nullptr;
 }
 
 bool
 MediaSourceReader::HaveData(int64_t aTarget, MediaData::Type aType)
 {
   TrackBuffer* trackBuffer = aType == MediaData::AUDIO_DATA ? mAudioTrack : mVideoTrack;
   MOZ_ASSERT(trackBuffer);
-  nsRefPtr<MediaDecoderReader> reader = SelectReader(aTarget, trackBuffer->Decoders());
+  nsRefPtr<MediaDecoderReader> reader = SelectReader(aTarget, EOS_FUZZ_US, trackBuffer->Decoders());
   return !!reader;
 }
 
 bool
-MediaSourceReader::SwitchAudioReader(int64_t aTarget)
+MediaSourceReader::SwitchAudioReader(int64_t aTarget, int64_t aError)
 {
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
   // XXX: Can't handle adding an audio track after ReadMetadata.
   if (!mAudioTrack) {
     return false;
   }
-  nsRefPtr<MediaDecoderReader> newReader = SelectReader(aTarget, mAudioTrack->Decoders());
+  nsRefPtr<MediaDecoderReader> newReader = SelectReader(aTarget, aError, mAudioTrack->Decoders());
   if (newReader && newReader != mAudioReader) {
     mAudioReader->SetIdle();
     mAudioReader = newReader;
     MSE_DEBUGV("MediaSourceReader(%p)::SwitchAudioReader switched reader to %p", this, mAudioReader.get());
     return true;
   }
   return false;
 }
 
 bool
-MediaSourceReader::SwitchVideoReader(int64_t aTarget)
+MediaSourceReader::SwitchVideoReader(int64_t aTarget, int64_t aError)
 {
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
   // XXX: Can't handle adding a video track after ReadMetadata.
   if (!mVideoTrack) {
     return false;
   }
-  nsRefPtr<MediaDecoderReader> newReader = SelectReader(aTarget, mVideoTrack->Decoders());
+  nsRefPtr<MediaDecoderReader> newReader = SelectReader(aTarget, aError, mVideoTrack->Decoders());
   if (newReader && newReader != mVideoReader) {
     mVideoReader->SetIdle();
     mVideoReader = newReader;
     MSE_DEBUGV("MediaSourceReader(%p)::SwitchVideoReader switched reader to %p", this, mVideoReader.get());
     return true;
   }
   return false;
 }
@@ -587,63 +626,58 @@ MediaSourceReader::Seek(int64_t aTime, i
   mPendingEndTime = aEndTime;
   mPendingCurrentTime = aCurrentTime;
 
   // Only increment the number of expected OnSeekCompleted
   // notifications if we weren't already waiting for AttemptSeek
   // to complete (and they would have been accounted for already).
   {
     ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
-
-    if (!mWaitingForSeekData) {
-      mWaitingForSeekData = true;
-      if (mAudioTrack) {
-        mPendingSeeks++;
-      }
-      if (mVideoTrack) {
-        mPendingSeeks++;
-      }
-    }
+    mWaitingForSeekData = true;
   }
 
   AttemptSeek();
   return p;
 }
 
 void
-MediaSourceReader::OnSeekCompleted()
+MediaSourceReader::OnVideoSeekCompleted(int64_t aTime)
 {
-  mPendingSeeks--;
-  FinalizeSeek();
+  mPendingSeekTime = aTime;
+  if (mAudioTrack) {
+    mAudioIsSeeking = true;
+    SwitchAudioReader(mPendingSeekTime);
+    mAudioReader->Seek(mPendingSeekTime,
+                       mPendingStartTime,
+                       mPendingEndTime,
+                       mPendingCurrentTime)
+                ->Then(GetTaskQueue(), __func__, this,
+                       &MediaSourceReader::OnAudioSeekCompleted,
+                       &MediaSourceReader::OnSeekFailed);
+    MSE_DEBUG("MediaSourceReader(%p)::Seek audio reader=%p", this, mAudioReader.get());
+    return;
+  }
+  mSeekPromise.Resolve(mPendingSeekTime, __func__);
+}
+
+void
+MediaSourceReader::OnAudioSeekCompleted(int64_t aTime)
+{
+  mSeekPromise.Resolve(mPendingSeekTime, __func__);
 }
 
 void
 MediaSourceReader::OnSeekFailed(nsresult aResult)
 {
-  mPendingSeeks--;
   // Keep the most recent failed result (if any)
   if (NS_FAILED(aResult)) {
-    mSeekResult = aResult;
+    mSeekPromise.Reject(aResult, __func__);
+    return;
   }
-  FinalizeSeek();
-}
-
-void
-MediaSourceReader::FinalizeSeek()
-{
-  // Only dispatch the final event onto the state machine
-  // since it's only expecting one response.
-  if (!mPendingSeeks) {
-    if (NS_FAILED(mSeekResult)) {
-      mSeekPromise.Reject(mSeekResult, __func__);
-    } else {
-      mSeekPromise.Resolve(true, __func__);
-    }
-    mSeekResult = NS_OK;
-  }
+  mSeekPromise.Resolve(mPendingSeekTime, __func__);
 }
 
 void
 MediaSourceReader::AttemptSeek()
 {
   // Make sure we don't hold the monitor while calling into the reader
   // Seek methods since it can deadlock.
   {
@@ -657,40 +691,31 @@ MediaSourceReader::AttemptSeek()
   for (uint32_t i = 0; i < mTrackBuffers.Length(); ++i) {
     mTrackBuffers[i]->ResetDecode();
   }
 
   // Decoding discontinuity upon seek, reset last times to seek target.
   mLastAudioTime = mPendingSeekTime;
   mLastVideoTime = mPendingSeekTime;
 
-  if (mAudioTrack) {
-    mAudioIsSeeking = true;
-    SwitchAudioReader(mPendingSeekTime);
-    mAudioReader->Seek(mPendingSeekTime,
-                       mPendingStartTime,
-                       mPendingEndTime,
-                       mPendingCurrentTime)
-                ->Then(GetTaskQueue(), __func__, this,
-                       &MediaSourceReader::OnSeekCompleted,
-                       &MediaSourceReader::OnSeekFailed);
-    MSE_DEBUG("MediaSourceReader(%p)::Seek audio reader=%p", this, mAudioReader.get());
-  }
   if (mVideoTrack) {
     mVideoIsSeeking = true;
     SwitchVideoReader(mPendingSeekTime);
     mVideoReader->Seek(mPendingSeekTime,
                        mPendingStartTime,
                        mPendingEndTime,
                        mPendingCurrentTime)
                 ->Then(GetTaskQueue(), __func__, this,
-                       &MediaSourceReader::OnSeekCompleted,
+                       &MediaSourceReader::OnVideoSeekCompleted,
                        &MediaSourceReader::OnSeekFailed);
     MSE_DEBUG("MediaSourceReader(%p)::Seek video reader=%p", this, mVideoReader.get());
+  } else {
+    OnVideoSeekCompleted(mPendingSeekTime);
   }
+
   {
     ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
     mWaitingForSeekData = false;
   }
 }
 
 nsresult
 MediaSourceReader::GetBuffered(dom::TimeRanges* aBuffered)
--- a/dom/media/mediasource/MediaSourceReader.h
+++ b/dom/media/mediasource/MediaSourceReader.h
@@ -53,17 +53,18 @@ public:
   virtual size_t SizeOfVideoQueueInFrames() MOZ_OVERRIDE;
   virtual size_t SizeOfAudioQueueInFrames() MOZ_OVERRIDE;
 
   void OnAudioDecoded(AudioData* aSample);
   void OnAudioNotDecoded(NotDecodedReason aReason);
   void OnVideoDecoded(VideoData* aSample);
   void OnVideoNotDecoded(NotDecodedReason aReason);
 
-  void OnSeekCompleted();
+  void OnVideoSeekCompleted(int64_t aTime);
+  void OnAudioSeekCompleted(int64_t aTime);
   void OnSeekFailed(nsresult aResult);
 
   virtual bool IsWaitForDataSupported() MOZ_OVERRIDE { return true; }
   virtual nsRefPtr<WaitForDataPromise> WaitForData(MediaData::Type aType) MOZ_OVERRIDE;
   void MaybeNotifyHaveData();
 
   bool HasVideo() MOZ_OVERRIDE
   {
@@ -125,27 +126,34 @@ public:
   // Return true if the Ended method has been called
   bool IsEnded();
 
 #ifdef MOZ_EME
   nsresult SetCDMProxy(CDMProxy* aProxy);
 #endif
 
 private:
-  bool SwitchAudioReader(int64_t aTarget);
-  bool SwitchVideoReader(int64_t aTarget);
+  // Switch the current audio/video reader to the reader that
+  // contains aTarget (or up to aError after target). Both
+  // aTarget and aError are in microseconds.
+  bool SwitchAudioReader(int64_t aTarget, int64_t aError = 0);
+  bool SwitchVideoReader(int64_t aTarget, int64_t aError = 0);
+  void RequestAudioDataComplete(int64_t aTime);
+  void RequestAudioDataFailed(nsresult aResult);
+  void RequestVideoDataComplete(int64_t aTime);
+  void RequestVideoDataFailed(nsresult aResult);
 
   // Return a reader from the set available in aTrackDecoders that has data
   // available in the range requested by aTarget.
   already_AddRefed<MediaDecoderReader> SelectReader(int64_t aTarget,
+                                                    int64_t aError,
                                                     const nsTArray<nsRefPtr<SourceBufferDecoder>>& aTrackDecoders);
   bool HaveData(int64_t aTarget, MediaData::Type aType);
 
   void AttemptSeek();
-  void FinalizeSeek();
 
   nsRefPtr<MediaDecoderReader> mAudioReader;
   nsRefPtr<MediaDecoderReader> mVideoReader;
 
   nsTArray<nsRefPtr<TrackBuffer>> mTrackBuffers;
   nsTArray<nsRefPtr<TrackBuffer>> mShutdownTrackBuffers;
   nsTArray<nsRefPtr<TrackBuffer>> mEssentialTrackBuffers;
   nsRefPtr<TrackBuffer> mAudioTrack;
@@ -173,22 +181,16 @@ private:
   // to be added to the track buffer.
   MediaPromiseHolder<SeekPromise> mSeekPromise;
   int64_t mPendingSeekTime;
   int64_t mPendingStartTime;
   int64_t mPendingEndTime;
   int64_t mPendingCurrentTime;
   bool mWaitingForSeekData;
 
-  // Number of outstanding OnSeekCompleted notifications
-  // we're expecting to get from child decoders, and the
-  // result we're going to forward onto our callback.
-  uint32_t mPendingSeeks;
-  nsresult mSeekResult;
-
   int64_t mTimeThreshold;
   bool mDropAudioBeforeThreshold;
   bool mDropVideoBeforeThreshold;
 
   bool mEnded;
 
   // For a seek to complete we need to send a sample with
   // the mDiscontinuity field set to true once we have the
--- a/dom/media/mediasource/SourceBufferResource.cpp
+++ b/dom/media/mediasource/SourceBufferResource.cpp
@@ -43,52 +43,79 @@ SourceBufferResource::Close()
 }
 
 nsresult
 SourceBufferResource::Read(char* aBuffer, uint32_t aCount, uint32_t* aBytes)
 {
   SBR_DEBUGV("SourceBufferResource(%p)::Read(aBuffer=%p, aCount=%u, aBytes=%p)",
              this, aBytes, aCount, aBytes);
   ReentrantMonitorAutoEnter mon(mMonitor);
-  bool blockingRead = !!aBytes;
+
+  return ReadInternal(aBuffer, aCount, aBytes, /* aMayBlock = */ true);
+}
 
-  while (blockingRead &&
+nsresult
+SourceBufferResource::ReadInternal(char* aBuffer, uint32_t aCount, uint32_t* aBytes, bool aMayBlock)
+{
+  mMonitor.AssertCurrentThreadIn();
+  MOZ_ASSERT_IF(!aMayBlock, aBytes);
+
+  // Cache the offset for the read in case mOffset changes while waiting on the
+  // monitor below. It's basically impossible to implement these API semantics
+  // sanely. :-(
+  uint64_t readOffset = mOffset;
+
+  while (aMayBlock &&
          !mEnded &&
-         mOffset + aCount > static_cast<uint64_t>(GetLength())) {
-    SBR_DEBUGV("SourceBufferResource(%p)::Read waiting for data", this);
-    mon.Wait();
+         readOffset + aCount > static_cast<uint64_t>(GetLength())) {
+    SBR_DEBUGV("SourceBufferResource(%p)::ReadInternal waiting for data", this);
+    mMonitor.Wait();
   }
 
-  uint32_t available = GetLength() - mOffset;
+  uint32_t available = GetLength() - readOffset;
   uint32_t count = std::min(aCount, available);
-  SBR_DEBUGV("SourceBufferResource(%p)::Read() mOffset=%llu GetLength()=%u available=%u count=%u mEnded=%d",
-             this, mOffset, GetLength(), available, count, mEnded);
+  SBR_DEBUGV("SourceBufferResource(%p)::ReadInternal() readOffset=%llu GetLength()=%u available=%u count=%u mEnded=%d",
+             this, readOffset, GetLength(), available, count, mEnded);
   if (available == 0) {
-    SBR_DEBUGV("SourceBufferResource(%p)::Read() reached EOF", this);
+    SBR_DEBUGV("SourceBufferResource(%p)::ReadInternal() reached EOF", this);
     *aBytes = 0;
     return NS_OK;
   }
 
-  mInputBuffer.CopyData(mOffset, count, aBuffer);
+  mInputBuffer.CopyData(readOffset, count, aBuffer);
   *aBytes = count;
-  mOffset += count;
+
+  // From IRC:
+  // <@cpearce>bholley: *this* is why there should only every be a ReadAt() and
+  // no Read() on a Stream abstraction! there's no good answer, they all suck.
+  mOffset = readOffset + count;
+
   return NS_OK;
 }
 
 nsresult
 SourceBufferResource::ReadAt(int64_t aOffset, char* aBuffer, uint32_t aCount, uint32_t* aBytes)
 {
   SBR_DEBUG("SourceBufferResource(%p)::ReadAt(aOffset=%lld, aBuffer=%p, aCount=%u, aBytes=%p)",
             this, aOffset, aBytes, aCount, aBytes);
   ReentrantMonitorAutoEnter mon(mMonitor);
+  return ReadAtInternal(aOffset, aBuffer, aCount, aBytes, /* aMayBlock = */ true);
+}
+
+nsresult
+SourceBufferResource::ReadAtInternal(int64_t aOffset, char* aBuffer, uint32_t aCount, uint32_t* aBytes,
+                                     bool aMayBlock)
+{
+  mMonitor.AssertCurrentThreadIn();
   nsresult rv = SeekInternal(aOffset);
   if (NS_FAILED(rv)) {
     return rv;
   }
-  return Read(aBuffer, aCount, aBytes);
+
+  return ReadInternal(aBuffer, aCount, aBytes, aMayBlock);
 }
 
 nsresult
 SourceBufferResource::Seek(int32_t aWhence, int64_t aOffset)
 {
   SBR_DEBUG("SourceBufferResource(%p)::Seek(aWhence=%d, aOffset=%lld)", this, aWhence, aOffset);
   ReentrantMonitorAutoEnter mon(mMonitor);
 
@@ -129,21 +156,24 @@ SourceBufferResource::SeekInternal(int64
 }
 
 nsresult
 SourceBufferResource::ReadFromCache(char* aBuffer, int64_t aOffset, uint32_t aCount)
 {
   SBR_DEBUG("SourceBufferResource(%p)::ReadFromCache(aBuffer=%p, aOffset=%lld, aCount=%u)",
             this, aBuffer, aOffset, aCount);
   ReentrantMonitorAutoEnter mon(mMonitor);
+  uint32_t bytesRead;
   int64_t oldOffset = mOffset;
-  uint32_t bytesRead;
-  nsresult rv = ReadAt(aOffset, aBuffer, aCount, &bytesRead);
-  mOffset = oldOffset;
-  return rv;
+  nsresult rv = ReadAtInternal(aOffset, aBuffer, aCount, &bytesRead, /* aMayBlock = */ false);
+  mOffset = oldOffset; // ReadFromCache isn't supposed to affect the seek position.
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  // ReadFromCache return failure if not all the data is cached.
+  return bytesRead == aCount ? NS_OK : NS_ERROR_FAILURE;
 }
 
 uint32_t
 SourceBufferResource::EvictData(uint32_t aThreshold)
 {
   SBR_DEBUG("SourceBufferResource(%p)::EvictData(aThreshold=%u)", this, aThreshold);
   ReentrantMonitorAutoEnter mon(mMonitor);
   return mInputBuffer.Evict(mOffset, aThreshold);
--- a/dom/media/mediasource/SourceBufferResource.h
+++ b/dom/media/mediasource/SourceBufferResource.h
@@ -130,16 +130,18 @@ public:
   void Dump(const char* aPath) {
     mInputBuffer.Dump(aPath);
   }
 #endif
 
 private:
   ~SourceBufferResource();
   nsresult SeekInternal(int64_t aOffset);
+  nsresult ReadInternal(char* aBuffer, uint32_t aCount, uint32_t* aBytes, bool aMayBlock);
+  nsresult ReadAtInternal(int64_t aOffset, char* aBuffer, uint32_t aCount, uint32_t* aBytes, bool aMayBlock);
 
   const nsCString mType;
 
   // Provides synchronization between SourceBuffers and InputAdapters.
   // Protects all of the member variables below.  Read() will await a
   // Notify() (from Seek, AppendData, Ended, or Close) when insufficient
   // data is available in mData.
   mutable ReentrantMonitor mMonitor;
--- a/dom/media/mediasource/TrackBuffer.cpp
+++ b/dom/media/mediasource/TrackBuffer.cpp
@@ -246,17 +246,17 @@ TrackBuffer::EvictData(uint32_t aThresho
   ReentrantMonitorAutoEnter mon(mParentDecoder->GetReentrantMonitor());
 
   int64_t totalSize = 0;
   for (uint32_t i = 0; i < mDecoders.Length(); ++i) {
     totalSize += mDecoders[i]->GetResource()->GetSize();
   }
 
   int64_t toEvict = totalSize - aThreshold;
-  if (toEvict <= 0) {
+  if (toEvict <= 0 || mInitializedDecoders.IsEmpty()) {
     return false;
   }
 
   // Get a list of initialized decoders, sorted by their start times.
   nsTArray<SourceBufferDecoder*> decoders;
   decoders.AppendElements(mInitializedDecoders);
   decoders.Sort(DecoderSorter());
 
--- a/dom/media/ogg/OggReader.cpp
+++ b/dom/media/ogg/OggReader.cpp
@@ -1429,17 +1429,17 @@ OggReader::Seek(int64_t aTarget,
                 int64_t aStartTime,
                 int64_t aEndTime,
                 int64_t aCurrentTime)
 {
   nsresult res = SeekInternal(aTarget, aStartTime, aEndTime, aCurrentTime);
   if (NS_FAILED(res)) {
     return SeekPromise::CreateAndReject(res, __func__);
   } else {
-    return SeekPromise::CreateAndResolve(true, __func__);
+    return SeekPromise::CreateAndResolve(aTarget, __func__);
   }
 }
 
 nsresult OggReader::SeekInternal(int64_t aTarget,
                                  int64_t aStartTime,
                                  int64_t aEndTime,
                                  int64_t aCurrentTime)
 {
--- a/dom/media/omx/MediaCodecReader.cpp
+++ b/dom/media/omx/MediaCodecReader.cpp
@@ -1051,17 +1051,17 @@ MediaCodecReader::Seek(int64_t aTime,
     if (CheckAudioResources()) {
       MOZ_ASSERT(mAudioTrack.mTaskQueue->IsEmpty());
       DispatchAudioTask();
     }
   } else if (CheckAudioResources()) {// Audio only
     MOZ_ASSERT(mAudioTrack.mTaskQueue->IsEmpty());
     DispatchAudioTask();
   }
-  return SeekPromise::CreateAndResolve(true, __func__);
+  return SeekPromise::CreateAndResolve(aTime, __func__);
 }
 
 bool
 MediaCodecReader::IsMediaSeekable()
 {
   // Check the MediaExtract flag if the source is seekable.
   return (mExtractor != nullptr) &&
          (mExtractor->flags() & MediaExtractor::CAN_SEEK);
--- a/dom/media/omx/MediaOmxReader.cpp
+++ b/dom/media/omx/MediaOmxReader.cpp
@@ -567,17 +567,17 @@ MediaOmxReader::Seek(int64_t aTarget, in
     // audio and video streams won't be in sync after the seek.
     mVideoSeekTimeUs = aTarget;
     const VideoData* v = DecodeToFirstVideoData();
     mAudioSeekTimeUs = v ? v->mTime : aTarget;
   } else {
     mAudioSeekTimeUs = mVideoSeekTimeUs = aTarget;
   }
 
-  return SeekPromise::CreateAndResolve(true, __func__);
+  return SeekPromise::CreateAndResolve(mAudioSeekTimeUs, __func__);
 }
 
 void MediaOmxReader::SetIdle() {
   if (!mOmxDecoder.get()) {
     return;
   }
   mOmxDecoder->Pause();
 }
--- a/dom/media/omx/mediaresourcemanager/MediaResourceHandler.cpp
+++ b/dom/media/omx/mediaresourcemanager/MediaResourceHandler.cpp
@@ -1,16 +1,15 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "MediaResourceHandler.h"
-#include "mozilla/NullPtr.h"
 
 namespace android {
 
 MediaResourceHandler::MediaResourceHandler(const wp<ResourceListener> &aListener)
   : mListener(aListener)
   , mType(IMediaResourceManagerService::INVALID_RESOURCE_TYPE)
   , mWaitingResource(false)
 {
--- a/dom/media/raw/RawReader.cpp
+++ b/dom/media/raw/RawReader.cpp
@@ -237,17 +237,17 @@ bool RawReader::DecodeVideoFrame(bool &a
 
 nsRefPtr<MediaDecoderReader::SeekPromise>
 RawReader::Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime, int64_t aCurrentTime)
 {
   nsresult res = SeekInternal(aTime);
   if (NS_FAILED(res)) {
     return SeekPromise::CreateAndReject(res, __func__);
   } else {
-    return SeekPromise::CreateAndResolve(true, __func__);
+    return SeekPromise::CreateAndResolve(aTime, __func__);
   }
 }
 
 nsresult RawReader::SeekInternal(int64_t aTime)
 {
   NS_ASSERTION(mDecoder->OnDecodeThread(),
                "Should be on decode thread.");
 
--- a/dom/media/systemservices/OSXRunLoopSingleton.cpp
+++ b/dom/media/systemservices/OSXRunLoopSingleton.cpp
@@ -1,16 +1,15 @@
 /* -*- 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 "OSXRunLoopSingleton.h"
 #include <mozilla/StaticMutex.h>
-#include <mozilla/NullPtr.h>
 
 #include <AudioUnit/AudioUnit.h>
 #include <CoreAudio/AudioHardware.h>
 #include <CoreAudio/HostTime.h>
 #include <CoreFoundation/CoreFoundation.h>
 
 static bool gRunLoopSet = false;
 static mozilla::StaticMutex gMutex;
--- a/dom/media/systemservices/OpenSLESProvider.cpp
+++ b/dom/media/systemservices/OpenSLESProvider.cpp
@@ -1,17 +1,16 @@
 /* -*- Mode: C++; tab-width: 50; 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 "OpenSLESProvider.h"
 #include "prlog.h"
 #include "nsDebug.h"
-#include "mozilla/NullPtr.h"
 
 #include <dlfcn.h>
 #include <SLES/OpenSLES_Android.h>
 #include <SLES/OpenSLES_AndroidConfiguration.h>
 
 // NSPR_LOG_MODULES=OpenSLESProvider:5
 #undef LOG
 #undef LOG_ENABLED
--- a/dom/media/wave/WaveReader.cpp
+++ b/dom/media/wave/WaveReader.cpp
@@ -272,17 +272,17 @@ WaveReader::Seek(int64_t aTarget, int64_
   double seekTime = std::min(aTarget, duration) / static_cast<double>(USECS_PER_S);
   int64_t position = RoundDownToFrame(static_cast<int64_t>(TimeToBytes(seekTime)));
   NS_ASSERTION(INT64_MAX - mWavePCMOffset > position, "Integer overflow during wave seek");
   position += mWavePCMOffset;
   nsresult res = mDecoder->GetResource()->Seek(nsISeekableStream::NS_SEEK_SET, position);
   if (NS_FAILED(res)) {
     return SeekPromise::CreateAndReject(res, __func__);
   } else {
-    return SeekPromise::CreateAndResolve(true, __func__);
+    return SeekPromise::CreateAndResolve(aTarget, __func__);
   }
 }
 
 static double RoundToUsecs(double aSeconds) {
   return floor(aSeconds * USECS_PER_S) / USECS_PER_S;
 }
 
 nsresult WaveReader::GetBuffered(dom::TimeRanges* aBuffered)
--- a/dom/media/webaudio/AudioBufferSourceNode.cpp
+++ b/dom/media/webaudio/AudioBufferSourceNode.cpp
@@ -536,18 +536,17 @@ public:
 AudioBufferSourceNode::AudioBufferSourceNode(AudioContext* aContext)
   : AudioNode(aContext,
               2,
               ChannelCountMode::Max,
               ChannelInterpretation::Speakers)
   , mLoopStart(0.0)
   , mLoopEnd(0.0)
   // mOffset and mDuration are initialized in Start().
-  , mPlaybackRate(new AudioParam(MOZ_THIS_IN_INITIALIZER_LIST(),
-                  SendPlaybackRateToStream, 1.0f))
+  , mPlaybackRate(new AudioParam(this, SendPlaybackRateToStream, 1.0f))
   , mLoop(false)
   , mStartCalled(false)
   , mStopped(false)
 {
   AudioBufferSourceNodeEngine* engine = new AudioBufferSourceNodeEngine(this, aContext->Destination());
   mStream = aContext->Graph()->CreateAudioNodeStream(engine, MediaStreamGraph::SOURCE_STREAM);
   engine->SetSourceStream(static_cast<AudioNodeStream*>(mStream.get()));
   mStream->AddMainThreadListener(this);
--- a/dom/media/webaudio/BiquadFilterNode.cpp
+++ b/dom/media/webaudio/BiquadFilterNode.cpp
@@ -239,24 +239,20 @@ private:
 };
 
 BiquadFilterNode::BiquadFilterNode(AudioContext* aContext)
   : AudioNode(aContext,
               2,
               ChannelCountMode::Max,
               ChannelInterpretation::Speakers)
   , mType(BiquadFilterType::Lowpass)
-  , mFrequency(new AudioParam(MOZ_THIS_IN_INITIALIZER_LIST(),
-                              SendFrequencyToStream, 350.f))
-  , mDetune(new AudioParam(MOZ_THIS_IN_INITIALIZER_LIST(),
-                           SendDetuneToStream, 0.f))
-  , mQ(new AudioParam(MOZ_THIS_IN_INITIALIZER_LIST(),
-                      SendQToStream, 1.f))
-  , mGain(new AudioParam(MOZ_THIS_IN_INITIALIZER_LIST(),
-                         SendGainToStream, 0.f))
+  , mFrequency(new AudioParam(this, SendFrequencyToStream, 350.f))
+  , mDetune(new AudioParam(this, SendDetuneToStream, 0.f))
+  , mQ(new AudioParam(this, SendQToStream, 1.f))
+  , mGain(new AudioParam(this, SendGainToStream, 0.f))
 {
   BiquadFilterNodeEngine* engine = new BiquadFilterNodeEngine(this, aContext->Destination());
   mStream = aContext->Graph()->CreateAudioNodeStream(engine, MediaStreamGraph::INTERNAL_STREAM);
   engine->SetSourceStream(static_cast<AudioNodeStream*> (mStream.get()));
 }
 
 BiquadFilterNode::~BiquadFilterNode()
 {
@@ -367,9 +363,8 @@ void
 BiquadFilterNode::SendGainToStream(AudioNode* aNode)
 {
   BiquadFilterNode* This = static_cast<BiquadFilterNode*>(aNode);
   SendTimelineParameterToStream(This, BiquadFilterNodeEngine::GAIN, *This->mGain);
 }
 
 }
 }
-
--- a/dom/media/webaudio/DelayNode.cpp
+++ b/dom/media/webaudio/DelayNode.cpp
@@ -185,18 +185,17 @@ public:
   int32_t mLeftOverData;
 };
 
 DelayNode::DelayNode(AudioContext* aContext, double aMaxDelay)
   : AudioNode(aContext,
               2,
               ChannelCountMode::Max,
               ChannelInterpretation::Speakers)
-  , mDelay(new AudioParam(MOZ_THIS_IN_INITIALIZER_LIST(),
-                          SendDelayToStream, 0.0f))
+  , mDelay(new AudioParam(this, SendDelayToStream, 0.0f))
 {
   DelayNodeEngine* engine =
     new DelayNodeEngine(this, aContext->Destination(),
                         aContext->SampleRate() * aMaxDelay);
   mStream = aContext->Graph()->CreateAudioNodeStream(engine, MediaStreamGraph::INTERNAL_STREAM);
   engine->SetSourceStream(static_cast<AudioNodeStream*> (mStream.get()));
 }
 
@@ -228,9 +227,8 @@ void
 DelayNode::SendDelayToStream(AudioNode* aNode)
 {
   DelayNode* This = static_cast<DelayNode*>(aNode);
   SendTimelineParameterToStream(This, DelayNodeEngine::DELAY, *This->mDelay);
 }
 
 }
 }
-
--- a/dom/media/webaudio/DynamicsCompressorNode.cpp
+++ b/dom/media/webaudio/DynamicsCompressorNode.cpp
@@ -199,28 +199,22 @@ private:
   nsAutoPtr<DynamicsCompressor> mCompressor;
 };
 
 DynamicsCompressorNode::DynamicsCompressorNode(AudioContext* aContext)
   : AudioNode(aContext,
               2,
               ChannelCountMode::Explicit,
               ChannelInterpretation::Speakers)
-  , mThreshold(new AudioParam(MOZ_THIS_IN_INITIALIZER_LIST(),
-                              SendThresholdToStream, -24.f))
-  , mKnee(new AudioParam(MOZ_THIS_IN_INITIALIZER_LIST(),
-                         SendKneeToStream, 30.f))
-  , mRatio(new AudioParam(MOZ_THIS_IN_INITIALIZER_LIST(),
-                          SendRatioToStream, 12.f))
-  , mReduction(new AudioParam(MOZ_THIS_IN_INITIALIZER_LIST(),
-                              Callback, 0.f))
-  , mAttack(new AudioParam(MOZ_THIS_IN_INITIALIZER_LIST(),
-                           SendAttackToStream, 0.003f))
-  , mRelease(new AudioParam(MOZ_THIS_IN_INITIALIZER_LIST(),
-                            SendReleaseToStream, 0.25f))
+  , mThreshold(new AudioParam(this, SendThresholdToStream, -24.f))
+  , mKnee(new AudioParam(this, SendKneeToStream, 30.f))
+  , mRatio(new AudioParam(this, SendRatioToStream, 12.f))
+  , mReduction(new AudioParam(this, Callback, 0.f))
+  , mAttack(new AudioParam(this, SendAttackToStream, 0.003f))
+  , mRelease(new AudioParam(this, SendReleaseToStream, 0.25f))
 {
   DynamicsCompressorNodeEngine* engine = new DynamicsCompressorNodeEngine(this, aContext->Destination());
   mStream = aContext->Graph()->CreateAudioNodeStream(engine, MediaStreamGraph::INTERNAL_STREAM);
   engine->SetSourceStream(static_cast<AudioNodeStream*> (mStream.get()));
 }
 
 DynamicsCompressorNode::~DynamicsCompressorNode()
 {
@@ -282,9 +276,8 @@ void
 DynamicsCompressorNode::SendReleaseToStream(AudioNode* aNode)
 {
   DynamicsCompressorNode* This = static_cast<DynamicsCompressorNode*>(aNode);
   SendTimelineParameterToStream(This, DynamicsCompressorNodeEngine::RELEASE, *This->mRelease);
 }
 
 }
 }
-
--- a/dom/media/webaudio/GainNode.cpp
+++ b/dom/media/webaudio/GainNode.cpp
@@ -120,18 +120,17 @@ public:
   AudioParamTimeline mGain;
 };
 
 GainNode::GainNode(AudioContext* aContext)
   : AudioNode(aContext,
               2,
               ChannelCountMode::Max,
               ChannelInterpretation::Speakers)
-  , mGain(new AudioParam(MOZ_THIS_IN_INITIALIZER_LIST(),
-                         SendGainToStream, 1.0f))
+  , mGain(new AudioParam(this, SendGainToStream, 1.0f))
 {
   GainNodeEngine* engine = new GainNodeEngine(this, aContext->Destination());
   mStream = aContext->Graph()->CreateAudioNodeStream(engine, MediaStreamGraph::INTERNAL_STREAM);
   engine->SetSourceStream(static_cast<AudioNodeStream*> (mStream.get()));
 }
 
 GainNode::~GainNode()
 {
@@ -161,9 +160,8 @@ void
 GainNode::SendGainToStream(AudioNode* aNode)
 {
   GainNode* This = static_cast<GainNode*>(aNode);
   SendTimelineParameterToStream(This, GainNodeEngine::GAIN, *This->mGain);
 }
 
 }
 }
-
--- a/dom/media/webaudio/MediaStreamAudioDestinationNode.cpp
+++ b/dom/media/webaudio/MediaStreamAudioDestinationNode.cpp
@@ -63,17 +63,17 @@ static bool FilterAudioNodeStreamTrack(S
 }
 
 MediaStreamAudioDestinationNode::MediaStreamAudioDestinationNode(AudioContext* aContext)
   : AudioNode(aContext,
               2,
               ChannelCountMode::Explicit,
               ChannelInterpretation::Speakers)
   , mDOMStream(DOMAudioNodeMediaStream::CreateTrackUnionStream(GetOwner(),
-                                                               MOZ_THIS_IN_INITIALIZER_LIST(),
+                                                               this,
                                                                DOMMediaStream::HINT_CONTENTS_AUDIO))
 {
   TrackUnionStream* tus = static_cast<TrackUnionStream*>(mDOMStream->GetStream());
   MOZ_ASSERT(tus == mDOMStream->GetStream()->AsProcessedStream());
   tus->SetTrackIDFilter(FilterAudioNodeStreamTrack);
 
   MediaStreamDestinationEngine* engine = new MediaStreamDestinationEngine(this, tus);
   mStream = aContext->Graph()->CreateAudioNodeStream(engine, MediaStreamGraph::INTERNAL_STREAM);
--- a/dom/media/webaudio/OscillatorNode.cpp
+++ b/dom/media/webaudio/OscillatorNode.cpp
@@ -376,20 +376,18 @@ public:
 };
 
 OscillatorNode::OscillatorNode(AudioContext* aContext)
   : AudioNode(aContext,
               2,
               ChannelCountMode::Max,
               ChannelInterpretation::Speakers)
   , mType(OscillatorType::Sine)
-  , mFrequency(new AudioParam(MOZ_THIS_IN_INITIALIZER_LIST(),
-               SendFrequencyToStream, 440.0f))
-  , mDetune(new AudioParam(MOZ_THIS_IN_INITIALIZER_LIST(),
-            SendDetuneToStream, 0.0f))
+  , mFrequency(new AudioParam(this, SendFrequencyToStream, 440.0f))
+  , mDetune(new AudioParam(this, SendDetuneToStream, 0.0f))
   , mStartCalled(false)
   , mStopped(false)
 {
   OscillatorNodeEngine* engine = new OscillatorNodeEngine(this, aContext->Destination());
   mStream = aContext->Graph()->CreateAudioNodeStream(engine, MediaStreamGraph::SOURCE_STREAM);
   engine->SetSourceStream(static_cast<AudioNodeStream*> (mStream.get()));
   mStream->AddMainThreadListener(this);
 }
@@ -545,9 +543,8 @@ OscillatorNode::NotifyMainThreadStateCha
     // Drop the playing reference
     // Warning: The below line might delete this.
     MarkInactive();
   }
 }
 
 }
 }
-
--- a/dom/media/webaudio/StereoPannerNode.cpp
+++ b/dom/media/webaudio/StereoPannerNode.cpp
@@ -171,18 +171,17 @@ public:
   AudioParamTimeline mPan;
 };
 
 StereoPannerNode::StereoPannerNode(AudioContext* aContext)
   : AudioNode(aContext,
               2,
               ChannelCountMode::Clamped_max,
               ChannelInterpretation::Speakers)
-  , mPan(new AudioParam(MOZ_THIS_IN_INITIALIZER_LIST(),
-                        SendPanToStream, 0.f))
+  , mPan(new AudioParam(this, SendPanToStream, 0.f))
 {
   StereoPannerNodeEngine* engine = new StereoPannerNodeEngine(this, aContext->Destination());
   mStream = aContext->Graph()->CreateAudioNodeStream(engine,
                                                      MediaStreamGraph::INTERNAL_STREAM);
   engine->SetSourceStream(static_cast<AudioNodeStream*>(mStream.get()));
 }
 
 StereoPannerNode::~StereoPannerNode()
@@ -213,9 +212,8 @@ void
 StereoPannerNode::SendPanToStream(AudioNode* aNode)
 {
   StereoPannerNode* This = static_cast<StereoPannerNode*>(aNode);
   SendTimelineParameterToStream(This, StereoPannerNodeEngine::PAN, *This->mPan);
 }
 
 }
 }
-
--- a/dom/media/webm/WebMReader.cpp
+++ b/dom/media/webm/WebMReader.cpp
@@ -954,17 +954,17 @@ void WebMReader::PushVideoPacket(Nestegg
 nsRefPtr<MediaDecoderReader::SeekPromise>
 WebMReader::Seek(int64_t aTarget, int64_t aStartTime, int64_t aEndTime,
                       int64_t aCurrentTime)
 {
   nsresult res = SeekInternal(aTarget, aStartTime);
   if (NS_FAILED(res)) {
     return SeekPromise::CreateAndReject(res, __func__);
   } else {
-    return SeekPromise::CreateAndResolve(true, __func__);
+    return SeekPromise::CreateAndResolve(aTarget, __func__);
   }
 }
 
 nsresult WebMReader::SeekInternal(int64_t aTarget, int64_t aStartTime)
 {
   NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
   if (mVideoDecoder) {
     nsresult rv = mVideoDecoder->Flush();
--- a/dom/media/wmf/WMFReader.cpp
+++ b/dom/media/wmf/WMFReader.cpp
@@ -893,17 +893,17 @@ WMFReader::Seek(int64_t aTargetUs,
                 int64_t aStartTime,
                 int64_t aEndTime,
                 int64_t aCurrentTime)
 {
   nsresult res = SeekInternal(aTargetUs);
   if (NS_FAILED(res)) {
     return SeekPromise::CreateAndReject(res, __func__);
   } else {
-    return SeekPromise::CreateAndResolve(true, __func__);
+    return SeekPromise::CreateAndResolve(aTargetUs, __func__);
   }
 }
 
 nsresult
 WMFReader::SeekInternal(int64_t aTargetUs)
 {
   DECODER_LOG("WMFReader::Seek() %lld", aTargetUs);
 
--- a/dom/network/UDPSocketParent.cpp
+++ b/dom/network/UDPSocketParent.cpp
@@ -82,17 +82,17 @@ UDPSocketParent::Init(const nsACString& 
     nsAutoCString contractId(NS_NETWORK_UDP_SOCKET_FILTER_HANDLER_PREFIX);
     contractId.Append(aFilter);
     nsCOMPtr<nsIUDPSocketFilterHandler> filterHandler =
       do_GetService(contractId.get());
     if (filterHandler) {
       nsresult rv = filterHandler->NewFilter(getter_AddRefs(mFilter));
       if (NS_FAILED(rv)) {
         printf_stderr("Cannot create filter that content specified. "
-                      "filter name: %s, error code: %d.", aFilter.BeginReading(), rv);
+                      "filter name: %s, error code: %u.", aFilter.BeginReading(),  static_cast<uint32_t>(rv));
         return false;
       }
     } else {
       printf_stderr("Content doesn't have a valid filter. "
                     "filter name: %s.", aFilter.BeginReading());
       return false;
     }
   }
--- a/dom/plugins/base/android/ANPSystem.cpp
+++ b/dom/plugins/base/android/ANPSystem.cpp
@@ -45,30 +45,27 @@ anp_system_getApplicationDataDirectory(N
 }
 
 const char*
 anp_system_getApplicationDataDirectory()
 {
   return anp_system_getApplicationDataDirectory(nullptr);
 }
 
-jclass anp_system_loadJavaClass(NPP instance, const char* classNameStr)
+jclass anp_system_loadJavaClass(NPP instance, const char* className)
 {
   LOG("%s", __PRETTY_FUNCTION__);
 
   nsNPAPIPluginInstance* pinst = static_cast<nsNPAPIPluginInstance*>(instance->ndata);
   mozilla::PluginPRLibrary* lib = static_cast<mozilla::PluginPRLibrary*>(pinst->GetPlugin()->GetLibrary());
 
-  NS_ConvertUTF8toUTF16 className(classNameStr);
+  nsCString libName;
+  lib->GetLibraryPath(libName);
 
-  nsCString libNameUtf8;
-  lib->GetLibraryPath(libNameUtf8);
-  NS_ConvertUTF8toUTF16 libName(libNameUtf8);
-
-  return mozilla::widget::android::GeckoAppShell::LoadPluginClass(className, libName);
+  return mozilla::widget::GeckoAppShell::LoadPluginClass(className, libName).Forget();
 }
 
 void anp_system_setPowerState(NPP instance, ANPPowerState powerState)
 {
   nsNPAPIPluginInstance* pinst = nsNPAPIPluginInstance::GetFromNPP(instance);
 
   if (pinst) {
     pinst->SetWakeLock(powerState == kScreenOn_ANPPowerState);
--- a/dom/plugins/base/nsNPAPIPlugin.cpp
+++ b/dom/plugins/base/nsNPAPIPlugin.cpp
@@ -2264,22 +2264,21 @@ NPError
     case kSupportedDrawingModel_ANPGetValue: {
       LOG("get supported drawing model");
       uint32_t* bits = reinterpret_cast<uint32_t*>(result);
       *bits = kBitmap_ANPDrawingModel && kSurface_ANPDrawingModel;
       return NPERR_NO_ERROR;
     }
 
     case kJavaContext_ANPGetValue: {
-      jobject ret = mozilla::widget::android::GeckoAppShell::GetContext();
+      auto ret = widget::GeckoAppShell::GetContext();
       if (!ret)
         return NPERR_GENERIC_ERROR;
 
-      int32_t* i  = reinterpret_cast<int32_t*>(result);
-      *i = reinterpret_cast<int32_t>(ret);
+      *static_cast<jobject*>(result) = ret.Forget();
       return NPERR_NO_ERROR;
     }
 
     case kAudioTrackInterfaceV1_ANPGetValue: {
       LOG("get audio interface v1");
       ANPAudioTrackInterfaceV1 *i = (ANPAudioTrackInterfaceV1 *) result;
       InitAudioTrackInterfaceV1(i);
       return NPERR_NO_ERROR;
--- a/dom/plugins/base/nsNPAPIPluginInstance.cpp
+++ b/dom/plugins/base/nsNPAPIPluginInstance.cpp
@@ -844,17 +844,17 @@ void nsNPAPIPluginInstance::NotifyFullSc
 
   if (RUNNING != mRunning || mFullScreen == aFullScreen)
     return;
 
   mFullScreen = aFullScreen;
   SendLifecycleEvent(this, mFullScreen ? kEnterFullScreen_ANPLifecycleAction : kExitFullScreen_ANPLifecycleAction);
 
   if (mFullScreen && mFullScreenOrientation != dom::eScreenOrientation_None) {
-    mozilla::widget::android::GeckoAppShell::LockScreenOrientation(mFullScreenOrientation);
+    widget::GeckoAppShell::LockScreenOrientation(mFullScreenOrientation);
   }
 }
 
 void nsNPAPIPluginInstance::NotifySize(nsIntSize size)
 {
   if (kOpenGL_ANPDrawingModel != GetANPDrawingModel() ||
       size == mCurrentSize)
     return;
@@ -901,21 +901,21 @@ void nsNPAPIPluginInstance::SetFullScree
 
   uint32_t oldOrientation = mFullScreenOrientation;
   mFullScreenOrientation = orientation;
 
   if (mFullScreen) {
     // We're already fullscreen so immediately apply the orientation change
 
     if (mFullScreenOrientation != dom::eScreenOrientation_None) {
-      mozilla::widget::android::GeckoAppShell::LockScreenOrientation(mFullScreenOrientation);
+      widget::GeckoAppShell::LockScreenOrientation(mFullScreenOrientation);
     } else if (oldOrientation != dom::eScreenOrientation_None) {
       // We applied an orientation when we entered fullscreen, but
       // we don't want it anymore
-      mozilla::widget::android::GeckoAppShell::UnlockScreenOrientation();
+      widget::GeckoAppShell::UnlockScreenOrientation();
     }
   }
 }
 
 void nsNPAPIPluginInstance::PopPostedEvent(PluginEventRunnable* r)
 {
   mPostedEvents.RemoveElement(r);
 }
--- a/dom/plugins/base/nsPluginHost.cpp
+++ b/dom/plugins/base/nsPluginHost.cpp
@@ -575,18 +575,17 @@ nsresult nsPluginHost::PostURL(nsISuppor
       } else if (0 == PL_strcmp(target, "_current")) {
         target = "_self";
       }
       rv = owner->GetURL(url, target, postStream,
                          (void*)postHeaders, postHeadersLength);
     }
   }
 
-  // if we don't have a target, just create a stream.  This does
-  // NS_OpenURI()!
+  // if we don't have a target, just create a stream.
   if (streamListener)
     rv = NewPluginURLStream(NS_ConvertUTF8toUTF16(url), instance,
                             streamListener,
                             postStream, postHeaders, postHeadersLength);
 
   return rv;
 }
 
--- a/dom/plugins/base/nsPluginInstanceOwner.cpp
+++ b/dom/plugins/base/nsPluginInstanceOwner.cpp
@@ -1351,17 +1351,18 @@ bool nsPluginInstanceOwner::AddPluginVie
   return true;
 }
 
 void nsPluginInstanceOwner::RemovePluginView()
 {
   if (!mInstance || !mJavaView)
     return;
 
-  mozilla::widget::android::GeckoAppShell::RemovePluginView((jobject)mJavaView, mFullScreen);
+  widget::GeckoAppShell::RemovePluginView(
+      jni::Object::Ref::From(jobject(mJavaView)), mFullScreen);
   AndroidBridge::GetJNIEnv()->DeleteGlobalRef((jobject)mJavaView);
   mJavaView = nullptr;
 
   if (mFullScreen)
     sFullScreenInstance = nullptr;
 }
 
 void
--- a/dom/plugins/ipc/BrowserStreamChild.cpp
+++ b/dom/plugins/ipc/BrowserStreamChild.cpp
@@ -23,17 +23,17 @@ BrowserStreamChild::BrowserStreamChild(P
   , mDestroyPending(NOT_DESTROYED)
   , mNotifyPending(false)
   , mStreamAsFilePending(false)
   , mInstanceDying(false)
   , mState(CONSTRUCTING)
   , mURL(url)
   , mHeaders(headers)
   , mStreamNotify(notifyData)
-  , mDeliveryTracker(MOZ_THIS_IN_INITIALIZER_LIST())
+  , mDeliveryTracker(this)
 {
   PLUGIN_LOG_DEBUG(("%s (%s, %i, %i, %p, %s)", FULLFUNCTION,
                     url.get(), length, lastmodified, (void*) notifyData,
                     headers.get()));
 
   AssertPluginThread();
 
   memset(&mStream, 0, sizeof(mStream));
--- a/dom/plugins/ipc/PluginModuleParent.cpp
+++ b/dom/plugins/ipc/PluginModuleParent.cpp
@@ -483,17 +483,17 @@ PluginModuleChromeParent::WaitForIPCConn
 
 PluginModuleParent::PluginModuleParent(bool aIsChrome)
     : mIsChrome(aIsChrome)
     , mShutdown(false)
     , mClearSiteDataSupported(false)
     , mGetSitesWithDataSupported(false)
     , mNPNIface(nullptr)
     , mPlugin(nullptr)
-    , mTaskFactory(MOZ_THIS_IN_INITIALIZER_LIST())
+    , mTaskFactory(this)
     , mIsStartingAsync(false)
     , mNPInitialized(false)
     , mAsyncNewRv(NS_ERROR_NOT_INITIALIZED)
     , mAsyncInitPluginFuncs(nullptr)
 {
 #if defined(XP_WIN) || defined(XP_MACOSX) || defined(MOZ_WIDGET_GTK)
     mIsStartingAsync = Preferences::GetBool(kAsyncInitPref, false);
 #endif
@@ -516,17 +516,17 @@ PluginModuleContentParent::PluginModuleC
     : PluginModuleParent(false)
 {
 }
 
 PluginModuleChromeParent::PluginModuleChromeParent(const char* aFilePath, uint32_t aPluginId)
     : PluginModuleParent(true)
     , mSubprocess(new PluginProcessParent(aFilePath))
     , mPluginId(aPluginId)
-    , mChromeTaskFactory(MOZ_THIS_IN_INITIALIZER_LIST())
+    , mChromeTaskFactory(this)
     , mHangAnnotationFlags(0)
 #ifdef XP_WIN
     , mPluginCpuUsageOnHang()
     , mHangUIParent(nullptr)
     , mHangUIEnabled(true)
     , mIsTimerReset(true)
 #ifdef MOZ_CRASHREPORTER
     , mCrashReporterMutex("PluginModuleParent::mCrashReporterMutex")
--- a/dom/plugins/test/testplugin/nptest.cpp
+++ b/dom/plugins/test/testplugin/nptest.cpp
@@ -53,18 +53,16 @@
 #include <windows.h>
 #define getpid _getpid
 #define strcasecmp _stricmp
 #else
 #include <unistd.h>
 #include <pthread.h>
 #endif
 
-#include "mozilla/NullPtr.h"
-
 using namespace std;
 
 #define PLUGIN_VERSION     "1.0.0.0"
 #define ARRAY_LENGTH(a) (sizeof(a)/sizeof(a[0]))
 #define STATIC_ASSERT(condition)                                \
     extern void np_static_assert(int arg[(condition) ? 1 : -1])
 
 extern const char *sPluginName;
--- a/dom/plugins/test/testplugin/nptest_gtk2.cpp
+++ b/dom/plugins/test/testplugin/nptest_gtk2.cpp
@@ -40,17 +40,16 @@
 #ifdef MOZ_X11
 #include <gdk/gdkx.h>
 #include <X11/extensions/shape.h>
 #endif
 #include <glib.h>
 #include <gtk/gtk.h>
 #include <unistd.h>
 
-#include "mozilla/NullPtr.h"
 #include "mozilla/IntentionalCrash.h"
 
  using namespace std;
 
 struct _PlatformData {
 #ifdef MOZ_X11
   Display* display;
   Visual* visual;
--- a/dom/plugins/test/testplugin/nptest_utils.cpp
+++ b/dom/plugins/test/testplugin/nptest_utils.cpp
@@ -28,17 +28,16 @@
  * 
  * ***** END LICENSE BLOCK ***** */
 
 #include "nptest_utils.h"
 
 #include <stdlib.h>
 #include <string.h>
 #include <assert.h>
-#include "mozilla/NullPtr.h"
 
 NPUTF8*
 createCStringFromNPVariant(const NPVariant* variant)
 {
   size_t length = NPVARIANT_TO_STRING(*variant).UTF8Length;
   NPUTF8* result = (NPUTF8*)malloc(length + 1);
   memcpy(result, NPVARIANT_TO_STRING(*variant).UTF8Characters, length);
   result[length] = '\0';
--- a/dom/quota/QuotaManager.cpp
+++ b/dom/quota/QuotaManager.cpp
@@ -53,16 +53,18 @@
 #include "CheckQuotaHelper.h"
 #include "OriginCollection.h"
 #include "OriginOrPatternString.h"
 #include "QuotaObject.h"
 #include "StorageMatcher.h"
 #include "UsageInfo.h"
 #include "Utilities.h"
 
+#define BAD_TLS_INDEX ((uint32_t) -1)
+
 // The amount of time, in milliseconds, that our IO thread will stay alive
 // after the last event it processes.
 #define DEFAULT_THREAD_TIMEOUT_MS 30000
 
 // The amount of time, in milliseconds, that we will wait for active storage
 // transactions on shutdown before aborting them.
 #define DEFAULT_SHUTDOWN_TIMER_MS 30000
 
--- a/dom/smil/nsSMILTimeValueSpec.cpp
+++ b/dom/smil/nsSMILTimeValueSpec.cpp
@@ -36,17 +36,17 @@ nsSMILTimeValueSpec::EventListener::Hand
 
 //----------------------------------------------------------------------
 // Implementation
 
 nsSMILTimeValueSpec::nsSMILTimeValueSpec(nsSMILTimedElement& aOwner,
                                          bool aIsBegin)
   : mOwner(&aOwner),
     mIsBegin(aIsBegin),
-    mReferencedElement(MOZ_THIS_IN_INITIALIZER_LIST())
+    mReferencedElement(this)
 {
 }
 
 nsSMILTimeValueSpec::~nsSMILTimeValueSpec()
 {
   UnregisterFromReferencedElement(mReferencedElement.get());
   if (mEventListener) {
     mEventListener->Disconnect();
--- a/dom/svg/SVGAElement.cpp
+++ b/dom/svg/SVGAElement.cpp
@@ -59,17 +59,17 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 NS_IMPL_ADDREF_INHERITED(SVGAElement, SVGAElementBase)
 NS_IMPL_RELEASE_INHERITED(SVGAElement, SVGAElementBase)
 
 //----------------------------------------------------------------------
 // Implementation
 
 SVGAElement::SVGAElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
   : SVGAElementBase(aNodeInfo)
-  , Link(MOZ_THIS_IN_INITIALIZER_LIST())
+  , Link(this)
 {
 }
 
 SVGAElement::~SVGAElement()
 {
 }
 
 already_AddRefed<SVGAnimatedString>
--- a/dom/svg/SVGAnimationElement.cpp
+++ b/dom/svg/SVGAnimationElement.cpp
@@ -29,17 +29,17 @@ NS_IMPL_CYCLE_COLLECTION_INHERITED(SVGAn
                                    SVGAnimationElementBase,
                                    mHrefTarget, mTimedElement)
 
 //----------------------------------------------------------------------
 // Implementation
 
 SVGAnimationElement::SVGAnimationElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
   : SVGAnimationElementBase(aNodeInfo),
-    mHrefTarget(MOZ_THIS_IN_INITIALIZER_LIST())
+    mHrefTarget(this)
 {
 }
 
 SVGAnimationElement::~SVGAnimationElement()
 {
 }
 
 nsresult
--- a/dom/svg/SVGContentUtils.cpp
+++ b/dom/svg/SVGContentUtils.cpp
@@ -133,22 +133,34 @@ GetStrokeDashData(SVGContentUtils::AutoS
     // When deciding whether to return eNoStroke or eContinuousStroke below we
     // need to take into account that in the repeat pattern the dashes become
     // gaps, and the gaps become dashes.
     Float origTotalLengthOfDashes = totalLengthOfDashes;
     totalLengthOfDashes += totalLengthOfGaps;
     totalLengthOfGaps += origTotalLengthOfDashes;
   }
 
-  if (totalLengthOfDashes <= 0 || totalLengthOfGaps <= 0) {
-    if (totalLengthOfGaps > 0 && totalLengthOfDashes <= 0) {
-      return eNoStroke;
-    }
+  // Stroking using dashes is much slower than stroking a continuous line
+  // (see bug 609361 comment 40), and much, much slower than not stroking the
+  // line at all. Here we check for cases when the dash pattern causes the
+  // stroke to essentially be continuous or to be nonexistent in which case
+  // we can avoid expensive stroking operations (the underlying platform
+  // graphics libraries don't seem to optimize for this).
+  if (totalLengthOfDashes <= 0 && totalLengthOfGaps <= 0) {
+    return eNoStroke;
+  }
+  if (totalLengthOfGaps <= 0) {
     return eContinuousStroke;
   }
+  // We can only return eNoStroke if the value of stroke-linecap isn't
+  // adding caps to zero length dashes.
+  if (totalLengthOfDashes <= 0 &&
+      aStyleSVG->mStrokeLinecap == NS_STYLE_STROKE_LINECAP_BUTT) {
+    return eNoStroke;
+  }
 
   if (aContextPaint && aStyleSVG->mStrokeDashoffsetFromObject) {
     aStrokeOptions->mDashOffset = Float(aContextPaint->GetStrokeDashOffset());
   } else {
     aStrokeOptions->mDashOffset =
       SVGContentUtils::CoordToFloat(aElement, aStyleSVG->mStrokeDashoffset);
   }
 
--- a/dom/svg/SVGMPathElement.cpp
+++ b/dom/svg/SVGMPathElement.cpp
@@ -52,17 +52,17 @@ NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION
   NS_INTERFACE_TABLE_INHERITED(SVGMPathElement, nsIDOMNode, nsIDOMElement,
                                nsIDOMSVGElement,
                                nsIMutationObserver)
 NS_INTERFACE_TABLE_TAIL_INHERITING(SVGMPathElementBase)
 
 // Constructor
 SVGMPathElement::SVGMPathElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
   : SVGMPathElementBase(aNodeInfo),
-    mHrefTarget(MOZ_THIS_IN_INITIALIZER_LIST())
+    mHrefTarget(this)
 {
 }
 
 SVGMPathElement::~SVGMPathElement()
 {
   UnlinkHrefTarget(false);
 }
 
--- a/dom/svg/SVGUseElement.cpp
+++ b/dom/svg/SVGUseElement.cpp
@@ -67,17 +67,17 @@ NS_IMPL_RELEASE_INHERITED(SVGUseElement,
 NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(SVGUseElement)
   NS_INTERFACE_TABLE_INHERITED(SVGUseElement, nsIMutationObserver)
 NS_INTERFACE_TABLE_TAIL_INHERITING(SVGUseElementBase)
 
 //----------------------------------------------------------------------
 // Implementation
 
 SVGUseElement::SVGUseElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
-  : SVGUseElementBase(aNodeInfo), mSource(MOZ_THIS_IN_INITIALIZER_LIST())
+  : SVGUseElementBase(aNodeInfo), mSource(this)
 {
 }
 
 SVGUseElement::~SVGUseElement()
 {
   UnlinkSource();
 }
 
--- a/dom/system/android/AndroidLocationProvider.cpp
+++ b/dom/system/android/AndroidLocationProvider.cpp
@@ -21,34 +21,34 @@ AndroidLocationProvider::AndroidLocation
 AndroidLocationProvider::~AndroidLocationProvider()
 {
     NS_IF_RELEASE(gLocationCallback);
 }
 
 NS_IMETHODIMP
 AndroidLocationProvider::Startup()
 {
-    mozilla::widget::android::GeckoAppShell::EnableLocation(true);
+    widget::GeckoAppShell::EnableLocation(true);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 AndroidLocationProvider::Watch(nsIGeolocationUpdate* aCallback)
 {
     NS_IF_RELEASE(gLocationCallback);
     gLocationCallback = aCallback;
     NS_IF_ADDREF(gLocationCallback);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 AndroidLocationProvider::Shutdown()
 {
-    mozilla::widget::android::GeckoAppShell::EnableLocation(false);
+    widget::GeckoAppShell::EnableLocation(false);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 AndroidLocationProvider::SetHighAccuracy(bool enable)
 {
-    mozilla::widget::android::GeckoAppShell::EnableLocationHighAccuracy(enable);
+    widget::GeckoAppShell::EnableLocationHighAccuracy(enable);
     return NS_OK;
 }
--- a/dom/system/android/nsHapticFeedback.cpp
+++ b/dom/system/android/nsHapticFeedback.cpp
@@ -9,11 +9,11 @@
 
 using namespace mozilla;
 
 NS_IMPL_ISUPPORTS(nsHapticFeedback, nsIHapticFeedback)
 
 NS_IMETHODIMP
 nsHapticFeedback::PerformSimpleAction(int32_t aType)
 {
-    mozilla::widget::android::GeckoAppShell::PerformHapticFeedback(aType == LongPress);
+    widget::GeckoAppShell::PerformHapticFeedback(aType == LongPress);
     return NS_OK;
 }
--- a/dom/system/gonk/AutoMounter.cpp
+++ b/dom/system/gonk/AutoMounter.cpp
@@ -1054,25 +1054,26 @@ AutoMounter::UpdateState()
           }
 
           // Volume is mounted, we need to unmount before
           // we can share.
           LOG("UpdateState: Unmounting %s", vol->NameStr());
           vol->StartUnmount(mResponseCallback);
           return; // UpdateState will be called again when the Unmount command completes
         }
-        case nsIVolume::STATE_IDLE: {
-          LOG("UpdateState: Volume %s is nsIVolume::STATE_IDLE", vol->NameStr());
+        case nsIVolume::STATE_IDLE:
+        case nsIVolume::STATE_MOUNT_FAIL: {
+          LOG("UpdateState: Volume %s is %s", vol->NameStr(), vol->StateStr());
           if (vol->IsFormatting() && !vol->IsFormatRequested()) {
             vol->SetFormatRequested(false);
             LOG("UpdateState: Mounting %s", vol->NameStr());
             vol->StartMount(mResponseCallback);
             break;
           }
-          if (tryToShare && vol->IsSharingEnabled()) {
+          if (tryToShare && vol->IsSharingEnabled() && volState == nsIVolume::STATE_IDLE) {
             // Volume is unmounted. We can go ahead and share.
             LOG("UpdateState: Sharing %s", vol->NameStr());
             vol->StartShare(mResponseCallback);
           } else if (vol->IsFormatRequested()){
             // Volume is unmounted. We can go ahead and format.
             LOG("UpdateState: Formatting %s", vol->NameStr());
             vol->StartFormat(mResponseCallback);
           }
--- a/dom/system/gonk/Volume.cpp
+++ b/dom/system/gonk/Volume.cpp
@@ -332,21 +332,23 @@ Volume::SetState(Volume::STATE aNewState
        mMediaPresent = false;
        mIsSharing = false;
        mUnmountRequested = false;
        mMountRequested = false;
        mIsUnmounting = false;
        break;
 
      case nsIVolume::STATE_MOUNTED:
+     case nsIVolume::STATE_MOUNT_FAIL:
        mMountRequested = false;
        mIsFormatting = false;
        mIsSharing = false;
        mIsUnmounting = false;
        break;
+
      case nsIVolume::STATE_FORMATTING:
        mFormatRequested = false;
        mIsFormatting = true;
        mIsSharing = false;
        mIsUnmounting = false;
        break;
 
      case nsIVolume::STATE_SHARED:
@@ -536,17 +538,22 @@ Volume::HandleVoldResponse(int aResponse
           token = aTokenizer.nextToken();
           STATE newState = (STATE)(token.ToInteger(&errCode));
           if (newState == nsIVolume::STATE_MOUNTED) {
             // We set the state to STATE_CHECKMNT here, and the once the
             // AutoMounter detects that the volume is actually accessible
             // then the AutoMounter will set the volume as STATE_MOUNTED.
             SetState(nsIVolume::STATE_CHECKMNT);
           } else {
-            SetState(newState);
+            if (State() == nsIVolume::STATE_CHECKING && newState == nsIVolume::STATE_IDLE) {
+              LOG("Mount of volume '%s' failed", NameStr());
+              SetState(nsIVolume::STATE_MOUNT_FAIL);
+            } else {
+              SetState(newState);
+            }
           }
           break;
         }
       }
       break;
     }
 
     case ::ResponseCode::VolumeDiskInserted:
--- a/dom/system/gonk/nsIVolume.idl
+++ b/dom/system/gonk/nsIVolume.idl
@@ -1,30 +1,33 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsISupports.idl"
 #include "nsIVolumeStat.idl"
 
-[scriptable, uuid(946B5334-6EC9-11E4-8689-F3061E5D46B0)]
+[scriptable, uuid(EE752CB8-8FD7-11E4-A602-70221D5D46B0)]
 interface nsIVolume : nsISupports
 {
   // These MUST match the states from android's system/vold/Volume.h header
+  // Note: Changes made to the STATE_xxx names should also be reflected in the
+  //       NS_VolumeStateStr function found in Volume.cpp
   const long STATE_INIT        = -1;
   const long STATE_NOMEDIA     = 0;
   const long STATE_IDLE        = 1;
   const long STATE_PENDING     = 2;
   const long STATE_CHECKING    = 3;
   const long STATE_MOUNTED     = 4;
   const long STATE_UNMOUNTING  = 5;
   const long STATE_FORMATTING  = 6;
   const long STATE_SHARED      = 7;
   const long STATE_SHAREDMNT   = 8;
   const long STATE_CHECKMNT    = 100;
+  const long STATE_MOUNT_FAIL  = 101;
 
   // The name of the volume. Often there is only one volume, called sdcard.
   // But some phones support multiple volumes.
   readonly attribute DOMString name;
 
   // The mount point is the path on the system where the volume is mounted
   // and is only valid when state == STATE_MOUNTED.
   readonly attribute DOMString mountPoint;
--- a/dom/system/gonk/nsVolume.cpp
+++ b/dom/system/gonk/nsVolume.cpp
@@ -33,16 +33,17 @@ NS_VolumeStateStr(int32_t aState)
     case nsIVolume::STATE_PENDING:    return "Pending";
     case nsIVolume::STATE_CHECKING:   return "Checking";
     case nsIVolume::STATE_MOUNTED:    return "Mounted";
     case nsIVolume::STATE_UNMOUNTING: return "Unmounting";
     case nsIVolume::STATE_FORMATTING: return "Formatting";
     case nsIVolume::STATE_SHARED:     return "Shared";
     case nsIVolume::STATE_SHAREDMNT:  return "Shared-Mounted";
     case nsIVolume::STATE_CHECKMNT:   return "Check-Mounted";
+    case nsIVolume::STATE_MOUNT_FAIL: return "Mount-Fail";
   }
   return "???";
 }
 
 // While nsVolumes can only be used on the main thread, in the
 // UpdateVolumeRunnable constructor (which is called from IOThread) we
 // allocate an nsVolume which is then passed to MainThread. Since we
 // have a situation where we allocate on one thread and free on another
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -520,18 +520,18 @@ struct MainThreadWorkerStructuredCloneCa
 
     // See if this is a Blob/File object.
     {
       nsRefPtr<File> blob;
       if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, aObj, blob))) {
         FileImpl* blobImpl = blob->Impl();
         MOZ_ASSERT(blobImpl);
 
-        if (blobImpl->IsCCed()) {
-          NS_WARNING("Cycle collected blob objects are not supported!");
+        if (!blobImpl->MayBeClonedToOtherThreads()) {
+          NS_WARNING("Not all the blob implementations can be sent between threads.");
         } else if (WriteBlobOrFile(aCx, aWriter, blobImpl, *clonedObjects)) {
           return true;
         }
       }
     }
 
     JS_ClearPendingException(aCx);
     return NS_DOMWriteStructuredClone(aCx, aWriter, aObj, nullptr);
--- a/dom/xul/XULDocument.cpp
+++ b/dom/xul/XULDocument.cpp
@@ -2706,29 +2706,27 @@ XULDocument::LoadOverlayInternal(nsIURI*
         if (NS_FAILED(rv)) {
             // Abandon this prototype
             mCurrentPrototype = nullptr;
 
             // The parser won't get an OnStartRequest and
             // OnStopRequest, so it needs a Terminate.
             parser->Terminate();
 
-            // Just move on to the next overlay.  NS_OpenURI could fail
-            // just because a channel could not be opened, which can happen
-            // if a file or chrome package does not exist.
+            // Just move on to the next overlay.
             ReportMissingOverlay(aURI);
-            
+
             // XXX the error could indicate an internal error as well...
             *aFailureFromContent = true;
             return rv;
         }
 
         // If it's a 'chrome:' prototype document, then put it into
         // the prototype cache; other XUL documents will be reloaded
-        // each time.  We must do this after NS_OpenURI and AsyncOpen,
+        // each time.  We must do this after AsyncOpen,
         // or chrome code will wrongly create a cached chrome channel
         // instead of a real one. Prototypes are only cached when the
         // document to be overlayed is chrome to avoid caching overlay
         // scripts with incorrect principals, see bug 565610.
         if (useXULCache && overlayIsChrome && documentIsChrome) {
             nsXULPrototypeCache::GetInstance()->PutPrototype(mCurrentPrototype);
         }
 
--- a/editor/libeditor/nsHTMLDataTransfer.cpp
+++ b/editor/libeditor/nsHTMLDataTransfer.cpp
@@ -1078,22 +1078,25 @@ nsresult nsHTMLEditor::InsertObject(cons
       0 == nsCRT::strcmp(type, kJPGImageMime) ||
       0 == nsCRT::strcmp(type, kPNGImageMime) ||
       0 == nsCRT::strcmp(type, kGIFImageMime) ||
       insertAsImage)
   {
     nsCOMPtr<nsIInputStream> imageStream;
     if (insertAsImage) {
       NS_ASSERTION(fileURI, "The file URI should be retrieved earlier");
-      rv = NS_OpenURI(getter_AddRefs(imageStream),
-                      fileURI,
-                      nsContentUtils::GetSystemPrincipal(),
-                      nsILoadInfo::SEC_NORMAL,
-                      nsIContentPolicy::TYPE_OTHER);
 
+      nsCOMPtr<nsIChannel> channel;
+      rv = NS_NewChannel(getter_AddRefs(channel),
+                         fileURI,
+                         nsContentUtils::GetSystemPrincipal(),
+                         nsILoadInfo::SEC_NORMAL,
+                         nsIContentPolicy::TYPE_OTHER);
+      NS_ENSURE_SUCCESS(rv, rv);
+      rv = channel->Open(getter_AddRefs(imageStream));
       NS_ENSURE_SUCCESS(rv, rv);
     } else {
       imageStream = do_QueryInterface(aObject);
       NS_ENSURE_TRUE(imageStream, NS_ERROR_FAILURE);
     }
 
     nsCString imageData;
     rv = NS_ConsumeStream(imageStream, UINT32_MAX, imageData);
--- a/gfx/2d/Types.h
+++ b/gfx/2d/Types.h
@@ -1,17 +1,16 @@
 /* -*- Mode: C++; tab-width: 20; 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 MOZILLA_GFX_TYPES_H_
 #define MOZILLA_GFX_TYPES_H_
 
-#include "mozilla/NullPtr.h"
 #include "mozilla/TypedEnum.h"
 
 #include <stddef.h>
 #include <stdint.h>
 
 namespace mozilla {
 namespace gfx {
 
--- a/gfx/gl/AndroidSurfaceTexture.cpp
+++ b/gfx/gl/AndroidSurfaceTexture.cpp
@@ -14,18 +14,19 @@
 #include "AndroidBridge.h"
 #include "nsThreadUtils.h"
 #include "mozilla/gfx/Matrix.h"
 #include "GeneratedJNIWrappers.h"
 #include "SurfaceTexture.h"
 #include "GLContext.h"
 
 using namespace mozilla;
-using namespace mozilla::widget::android;
-using namespace mozilla::widget::android::sdk;
+using namespace mozilla::jni;
+using namespace mozilla::widget;
+using namespace mozilla::widget::sdk;
 
 namespace mozilla {
 namespace gl {
 
 // UGH
 static std::map<int, AndroidSurfaceTexture*> sInstances;
 static int sNextID = 0;
 
@@ -98,19 +99,17 @@ AndroidSurfaceTexture::Attach(GLContext*
   }
 
   MOZ_ASSERT(aContext->IsOwningThreadCurrent(), "Trying to attach GLContext from different thread");
 
   mAttachedContext = aContext;
   mAttachedContext->MakeCurrent();
   aContext->fGenTextures(1, &mTexture);
 
-  nsresult res;
-  mSurfaceTexture->AttachToGLContext(mTexture, &res);
-  return res;
+  return mSurfaceTexture->AttachToGLContext(mTexture);
 }
 
 nsresult
 AndroidSurfaceTexture::Detach()
 {
   MonitorAutoLock lock(mMonitor);
 
   if (!IsDetachSupported() ||
@@ -131,81 +130,78 @@ AndroidSurfaceTexture::Detach()
 bool
 AndroidSurfaceTexture::Init(GLContext* aContext, GLuint aTexture)
 {
   if (!aTexture && !IsDetachSupported()) {
     // We have no texture and cannot initialize detached, bail out
     return false;
   }
 
-  nsresult res;
-  mSurfaceTexture = new SurfaceTexture(aTexture, &res);
-  if (NS_FAILED(res)) {
+  if (NS_WARN_IF(NS_FAILED(
+      SurfaceTexture::New(aTexture, ReturnTo(&mSurfaceTexture))))) {
     return false;
   }
 
   if (!aTexture) {
     mSurfaceTexture->DetachFromGLContext();
   }
 
   mAttachedContext = aContext;
 
-  mSurface = new Surface(mSurfaceTexture->wrappedObject(), &res);
-  if (NS_FAILED(res)) {
+  if (NS_WARN_IF(NS_FAILED(
+      Surface::New(mSurfaceTexture, ReturnTo(&mSurface))))) {
     return false;
   }
 
   mNativeWindow = AndroidNativeWindow::CreateFromSurface(GetJNIForThread(),
-                                                         mSurface->wrappedObject());
+                                                         mSurface.Get());
   MOZ_ASSERT(mNativeWindow, "Failed to create native window from surface");
 
   mID = ++sNextID;
   sInstances.insert(std::pair<int, AndroidSurfaceTexture*>(mID, this));
 
   return true;
 }
 
 AndroidSurfaceTexture::AndroidSurfaceTexture()
   : mTexture(0)
-  , mSurfaceTexture(nullptr)
-  , mSurface(nullptr)
+  , mSurfaceTexture()
+  , mSurface()
   , mMonitor("AndroidSurfaceTexture::mContextMonitor")
   , mAttachedContext(nullptr)
 {
 }
 
 AndroidSurfaceTexture::~AndroidSurfaceTexture()
 {
   sInstances.erase(mID);
 
   mFrameAvailableCallback = nullptr;
 
   if (mSurfaceTexture) {
-    GeckoAppShell::UnregisterSurfaceTextureFrameListener(mSurfaceTexture->wrappedObject());
+    GeckoAppShell::UnregisterSurfaceTextureFrameListener(mSurfaceTexture);
     mSurfaceTexture = nullptr;
   }
 }
 
 void
 AndroidSurfaceTexture::UpdateTexImage()
 {
   mSurfaceTexture->UpdateTexImage();
 }
 
 void
 AndroidSurfaceTexture::GetTransformMatrix(gfx::Matrix4x4& aMatrix)
 {
   JNIEnv* env = GetJNIForThread();
 
-  AutoLocalJNIFrame jniFrame(env);
-
-  jfloatArray jarray = env->NewFloatArray(16);
+  auto jarray = FloatArray::LocalRef::Adopt(env, env->NewFloatArray(16));
   mSurfaceTexture->GetTransformMatrix(jarray);
 
-  jfloat* array = env->GetFloatArrayElements(jarray, nullptr);
+  jfloat* array = env->GetFloatArrayElements(jarray.Get(), nullptr);
 
   aMatrix._11 = array[0];
   aMatrix._12 = array[1];
   aMatrix._13 = array[2];
   aMatrix._14 = array[3];
 
   aMatrix._21 = array[4];
   aMatrix._22 = array[5];
@@ -217,26 +213,26 @@ AndroidSurfaceTexture::GetTransformMatri
   aMatrix._33 = array[10];
   aMatrix._34 = array[11];
 
   aMatrix._41 = array[12];
   aMatrix._42 = array[13];
   aMatrix._43 = array[14];
   aMatrix._44 = array[15];
 
-  env->ReleaseFloatArrayElements(jarray, array, 0);
+  env->ReleaseFloatArrayElements(jarray.Get(), array, 0);
 }
 
 void
 AndroidSurfaceTexture::SetFrameAvailableCallback(nsIRunnable* aRunnable)
 {
   if (aRunnable) {
-    GeckoAppShell::RegisterSurfaceTextureFrameListener(mSurfaceTexture->wrappedObject(), mID);
+    GeckoAppShell::RegisterSurfaceTextureFrameListener(mSurfaceTexture, mID);
   } else {
-     GeckoAppShell::UnregisterSurfaceTextureFrameListener(mSurfaceTexture->wrappedObject());
+     GeckoAppShell::UnregisterSurfaceTextureFrameListener(mSurfaceTexture);
   }
 
   mFrameAvailableCallback = aRunnable;
 }
 
 void
 AndroidSurfaceTexture::SetDefaultSize(mozilla::gfx::IntSize size)
 {
--- a/gfx/gl/AndroidSurfaceTexture.h
+++ b/gfx/gl/AndroidSurfaceTexture.h
@@ -82,26 +82,27 @@ public:
   // if the upstream callback is received on a different thread
   void SetFrameAvailableCallback(nsIRunnable* aRunnable);
 
   // Only should be called by AndroidJNI when we get a
   // callback from the underlying SurfaceTexture instance
   void NotifyFrameAvailable();
 
   GLuint Texture() { return mTexture; }
-  jobject JavaSurface() { return mSurface->wrappedObject(); }
+  const widget::sdk::Surface::Ref& JavaSurface() { return mSurface; }
+
 private:
   AndroidSurfaceTexture();
   ~AndroidSurfaceTexture();
 
   bool Init(GLContext* aContext, GLuint aTexture);
 
   GLuint mTexture;
-  nsAutoPtr<mozilla::widget::android::sdk::SurfaceTexture> mSurfaceTexture;
-  nsAutoPtr<mozilla::widget::android::sdk::Surface> mSurface;
+  widget::sdk::SurfaceTexture::GlobalRef mSurfaceTexture;
+  widget::sdk::Surface::GlobalRef mSurface;
 
   Monitor mMonitor;
   GLContext* mAttachedContext;
 
   RefPtr<AndroidNativeWindow> mNativeWindow;
   int mID;
   nsRefPtr<nsIRunnable> mFrameAvailableCallback;
 };
--- a/gfx/gl/SharedSurfaceANGLE.cpp
+++ b/gfx/gl/SharedSurfaceANGLE.cpp
@@ -153,18 +153,22 @@ bool
 SharedSurface_ANGLEShareHandle::PollSync()
 {
     return true;
 }
 
 void
 SharedSurface_ANGLEShareHandle::ProducerAcquireImpl()
 {
-  if (mKeyedMutex)
-      mKeyedMutex->AcquireSync(0, INFINITE);
+    if (mKeyedMutex) {
+        HRESULT hr = mKeyedMutex->AcquireSync(0, 10000);
+        if (hr == WAIT_TIMEOUT) {
+            MOZ_CRASH();
+        }
+    }
 }
 
 void
 SharedSurface_ANGLEShareHandle::ProducerReleaseImpl()
 {
     if (mKeyedMutex) {
         GLLibraryEGL* egl = &sEGLLibrary;
         mGL->fFlush();
@@ -192,18 +196,22 @@ SharedSurface_ANGLEShareHandle::Consumer
             hr = tex->QueryInterface((IDXGIKeyedMutex**)byRef(mutex));
 
             if (SUCCEEDED(hr)) {
                 mConsumerKeyedMutex = mutex;
             }
         }
     }
 
-    if (mConsumerKeyedMutex)
-        mConsumerKeyedMutex->AcquireSync(0, INFINITE);
+    if (mConsumerKeyedMutex) {
+      HRESULT hr = mConsumerKeyedMutex->AcquireSync(0, 10000);
+      if (hr == WAIT_TIMEOUT) {
+        MOZ_CRASH();
+      }
+    }
 }
 
 void
 SharedSurface_ANGLEShareHandle::ConsumerReleaseImpl()
 {
     if (mConsumerKeyedMutex) {
         mConsumerKeyedMutex->ReleaseSync(0);
     }
--- a/gfx/layers/AtomicRefCountedWithFinalize.h
+++ b/gfx/layers/AtomicRefCountedWithFinalize.h
@@ -2,17 +2,16 @@
  * 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_ATOMICREFCOUNTEDWITHFINALIZE_H_
 #define MOZILLA_ATOMICREFCOUNTEDWITHFINALIZE_H_
 
 #include "mozilla/RefPtr.h"
-#include "mozilla/NullPtr.h"
 #include "mozilla/Likely.h"
 #include "MainThreadUtils.h"
 #include "base/message_loop.h"
 #include "base/task.h"
 
 namespace mozilla {
 
 template<typename T>
--- a/gfx/layers/apz/src/APZCTreeManager.cpp
+++ b/gfx/layers/apz/src/APZCTreeManager.cpp
@@ -84,17 +84,17 @@ APZCTreeManager::CalculatePendingDisplay
 {
   return AsyncPanZoomController::CalculatePendingDisplayPort(
     aFrameMetrics, aVelocity, aEstimatedPaintDuration);
 }
 
 APZCTreeManager::APZCTreeManager()
     : mInputQueue(new InputQueue()),
       mTreeLock("APZCTreeLock"),
-      mHitResultForInputBlock(NoApzcHit),
+      mHitResultForInputBlock(HitNothing),
       mRetainedTouchIdentifier(-1),
       mTouchCount(0),
       mApzcTreeLog("apzctree")
 {
   MOZ_ASSERT(NS_IsMainThread());
   AsyncPanZoomController::InitializeGlobalState();
   mApzcTreeLog.ConditionOnPrefFunction(gfxPrefs::APZPrintTree);
 }
@@ -556,114 +556,114 @@ APZCTreeManager::ReceiveInputEvent(Input
 {
   // Initialize aOutInputBlockId to a sane value, and then later we overwrite
   // it if the input event goes into a block.
   if (aOutInputBlockId) {
     *aOutInputBlockId = InputBlockState::NO_BLOCK_ID;
   }
   nsEventStatus result = nsEventStatus_eIgnore;
   Matrix4x4 transformToApzc;
-  HitTestResult hitResult = NoApzcHit;
+  HitTestResult hitResult = HitNothing;
   switch (aEvent.mInputType) {
     case MULTITOUCH_INPUT: {
       MultiTouchInput& touchInput = aEvent.AsMultiTouchInput();
       result = ProcessTouchInput(touchInput, aOutTargetGuid, aOutInputBlockId);
       break;
     } case SCROLLWHEEL_INPUT: {
       ScrollWheelInput& wheelInput = aEvent.AsScrollWheelInput();
       nsRefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(wheelInput.mOrigin,
                                                             &hitResult);
       if (apzc) {
-        MOZ_ASSERT(hitResult == ApzcHitRegion || hitResult == ApzcContentRegion);
+        MOZ_ASSERT(hitResult == HitLayer || hitResult == HitDispatchToContentRegion);
 
         transformToApzc = GetScreenToApzcTransform(apzc);
         wheelInput.mLocalOrigin =
           TransformTo<ParentLayerPixel>(transformToApzc, wheelInput.mOrigin);
 
         result = mInputQueue->ReceiveInputEvent(
           apzc,
-          /* aTargetConfirmed = */ hitResult == ApzcHitRegion,
+          /* aTargetConfirmed = */ hitResult == HitLayer,
           wheelInput, aOutInputBlockId);
 
         // Update the out-parameters so they are what the caller expects.
         apzc->GetGuid(aOutTargetGuid);
         Matrix4x4 transformToGecko = transformToApzc * GetApzcToGeckoTransform(apzc);
         wheelInput.mOrigin =
           TransformTo<ScreenPixel>(transformToGecko, wheelInput.mOrigin);
       }
       break;
     } case PANGESTURE_INPUT: {
       PanGestureInput& panInput = aEvent.AsPanGestureInput();
       nsRefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(panInput.mPanStartPoint,
                                                             &hitResult);
       if (apzc) {
-        MOZ_ASSERT(hitResult == ApzcHitRegion || hitResult == ApzcContentRegion);
+        MOZ_ASSERT(hitResult == HitLayer || hitResult == HitDispatchToContentRegion);
         transformToApzc = GetScreenToApzcTransform(apzc);
         panInput.mLocalPanStartPoint = TransformTo<ParentLayerPixel>(
             transformToApzc, panInput.mPanStartPoint);
         panInput.mLocalPanDisplacement = TransformVector<ParentLayerPixel>(
             transformToApzc, panInput.mPanDisplacement, panInput.mPanStartPoint);
         result = mInputQueue->ReceiveInputEvent(
             apzc,
-            /* aTargetConfirmed = */ hitResult == ApzcHitRegion,
+            /* aTargetConfirmed = */ hitResult == HitLayer,
             panInput, aOutInputBlockId);
 
         // Update the out-parameters so they are what the caller expects.
         apzc->GetGuid(aOutTargetGuid);
         Matrix4x4 transformToGecko = transformToApzc * GetApzcToGeckoTransform(apzc);
         panInput.mPanStartPoint = TransformTo<ScreenPixel>(
             transformToGecko, panInput.mPanStartPoint);
         panInput.mPanDisplacement = TransformVector<ScreenPixel>(
             transformToGecko, panInput.mPanDisplacement, panInput.mPanStartPoint);
       }
       break;
     } case PINCHGESTURE_INPUT: {  // note: no one currently sends these
       PinchGestureInput& pinchInput = aEvent.AsPinchGestureInput();
       nsRefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(pinchInput.mFocusPoint,
                                                             &hitResult);
       if (apzc) {
-        MOZ_ASSERT(hitResult == ApzcHitRegion || hitResult == ApzcContentRegion);
+        MOZ_ASSERT(hitResult == HitLayer || hitResult == HitDispatchToContentRegion);
         transformToApzc = GetScreenToApzcTransform(apzc);
         pinchInput.mLocalFocusPoint = TransformTo<ParentLayerPixel>(
             transformToApzc, pinchInput.mFocusPoint);
         result = mInputQueue->ReceiveInputEvent(
             apzc,
-            /* aTargetConfirmed = */ hitResult == ApzcHitRegion,
+            /* aTargetConfirmed = */ hitResult == HitLayer,
             pinchInput, aOutInputBlockId);
 
         // Update the out-parameters so they are what the caller expects.
         apzc->GetGuid(aOutTargetGuid);
         Matrix4x4 outTransform = transformToApzc * GetApzcToGeckoTransform(apzc);
         pinchInput.mFocusPoint = TransformTo<ScreenPixel>(
             outTransform, pinchInput.mFocusPoint);
       }
       break;
     } case TAPGESTURE_INPUT: {  // note: no one currently sends these
       TapGestureInput& tapInput = aEvent.AsTapGestureInput();
       nsRefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(tapInput.mPoint,
                                                             &hitResult);
       if (apzc) {
-        MOZ_ASSERT(hitResult == ApzcHitRegion || hitResult == ApzcContentRegion);
+        MOZ_ASSERT(hitResult == HitLayer || hitResult == HitDispatchToContentRegion);
         transformToApzc = GetScreenToApzcTransform(apzc);
         tapInput.mLocalPoint = TransformTo<ParentLayerPixel>(
             transformToApzc, tapInput.mPoint);
         result = mInputQueue->ReceiveInputEvent(
             apzc,
-            /* aTargetConfirmed = */ hitResult == ApzcHitRegion,
+            /* aTargetConfirmed = */ hitResult == HitLayer,
             tapInput, aOutInputBlockId);
 
         // Update the out-parameters so they are what the caller expects.
         apzc->GetGuid(aOutTargetGuid);
         Matrix4x4 outTransform = transformToApzc * GetApzcToGeckoTransform(apzc);
         tapInput.mPoint = TransformTo<ScreenPixel>(outTransform, tapInput.mPoint);
       }
       break;
     }
   }
-  if (hitResult == OverscrolledApzc) {
+  if (hitResult == HitOverscrolledApzc) {
     result = nsEventStatus_eConsumeNoDefault;
   }
   return result;
 }
 
 already_AddRefed<AsyncPanZoomController>
 APZCTreeManager::GetTouchInputBlockAPZC(const MultiTouchInput& aEvent,
                                         HitTestResult* aOutHitResult)
@@ -710,19 +710,19 @@ APZCTreeManager::ProcessTouchInput(Multi
         mRetainedTouchIdentifier = mApzcForInputBlock->GetLastTouchIdentifier();
       }
       return nsEventStatus_eConsumeNoDefault;
     }
 
     // NS_TOUCH_START event contains all active touches of the current
     // session thus resetting mTouchCount.
     mTouchCount = aInput.mTouches.Length();
-    mHitResultForInputBlock = NoApzcHit;
+    mHitResultForInputBlock = HitNothing;
     nsRefPtr<AsyncPanZoomController> apzc = GetTouchInputBlockAPZC(aInput, &mHitResultForInputBlock);
-    // XXX the following check assumes mHitResultForInputBlock == ApzcHitRegion
+    // XXX the following check assumes mHitResultForInputBlock == HitLayer
     // (and that mApzcForInputBlock was the confirmed target of the previous
     // input block). Eventually it would be better to move this into InputQueue
     // and have it auto-generated when we start processing events in a new
     // event block.
     if (apzc != mApzcForInputBlock) {
       // If we're moving to a different APZC as our input target, then send a cancel event
       // to the old one so that it clears its internal state. Otherwise it could get left
       // in the middle of a panning touch block (for example) and not clean up properly.
@@ -764,45 +764,45 @@ APZCTreeManager::ProcessTouchInput(Multi
     }
     if (aInput.mTouches.IsEmpty()) {
       return nsEventStatus_eConsumeNoDefault;
     }
   }
 
   nsEventStatus result = nsEventStatus_eIgnore;
   if (mApzcForInputBlock) {
-    MOZ_ASSERT(mHitResultForInputBlock == ApzcHitRegion || mHitResultForInputBlock == ApzcContentRegion);
+    MOZ_ASSERT(mHitResultForInputBlock == HitLayer || mHitResultForInputBlock == HitDispatchToContentRegion);
 
     mApzcForInputBlock->GetGuid(aOutTargetGuid);
     // For computing the input for the APZC, used the cached transform.
     // This ensures that the sequence of touch points an APZC sees in an
     // input block are all in the same coordinate space.
     Matrix4x4 transformToApzc = mCachedTransformToApzcForInputBlock;
     for (size_t i = 0; i < aInput.mTouches.Length(); i++) {
       SingleTouchData& touchData = aInput.mTouches[i];
       touchData.mLocalScreenPoint = TransformTo<ParentLayerPixel>(
           transformToApzc, ScreenPoint(touchData.mScreenPoint));
     }
     result = mInputQueue->ReceiveInputEvent(mApzcForInputBlock,
-        /* aTargetConfirmed = */ mHitResultForInputBlock == ApzcHitRegion,
+        /* aTargetConfirmed = */ mHitResultForInputBlock == HitLayer,
         aInput, aOutInputBlockId);
 
     // For computing the event to pass back to Gecko, use the up-to-date transforms.
     // This ensures that transformToApzc and transformToGecko are in sync
     // (note that transformToGecko isn't cached).
     transformToApzc = GetScreenToApzcTransform(mApzcForInputBlock);
     Matrix4x4 transformToGecko = GetApzcToGeckoTransform(mApzcForInputBlock);
     Matrix4x4 outTransform = transformToApzc * transformToGecko;
     for (size_t i = 0; i < aInput.mTouches.Length(); i++) {
       SingleTouchData& touchData = aInput.mTouches[i];
       touchData.mScreenPoint = TransformTo<ScreenPixel>(
           outTransform, touchData.mScreenPoint);
     }
   }
-  if (mHitResultForInputBlock == OverscrolledApzc) {
+  if (mHitResultForInputBlock == HitOverscrolledApzc) {
     result = nsEventStatus_eConsumeNoDefault;
   }
 
   if (aInput.mType == MultiTouchInput::MULTITOUCH_END) {
     if (mTouchCount >= aInput.mTouches.Length()) {
       // NS_TOUCH_END event contains only released touches thus decrementing.
       mTouchCount -= aInput.mTouches.Length();
     } else {
@@ -812,17 +812,17 @@ APZCTreeManager::ProcessTouchInput(Multi
   } else if (aInput.mType == MultiTouchInput::MULTITOUCH_CANCEL) {
     mTouchCount = 0;
   }
 
   // If it's the end of the touch sequence then clear out variables so we
   // don't keep dangling references and leak things.
   if (mTouchCount == 0) {
     mApzcForInputBlock = nullptr;
-    mHitResultForInputBlock = NoApzcHit;
+    mHitResultForInputBlock = HitNothing;
     mRetainedTouchIdentifier = -1;
   }
 
   return result;
 }
 
 void
 APZCTreeManager::TransformCoordinateToGecko(const ScreenIntPoint& aPoint,
@@ -843,28 +843,28 @@ APZCTreeManager::ProcessEvent(WidgetInpu
                               ScrollableLayerGuid* aOutTargetGuid,
                               uint64_t* aOutInputBlockId)
 {
   MOZ_ASSERT(NS_IsMainThread());
   nsEventStatus result = nsEventStatus_eIgnore;
 
   // Transform the refPoint.
   // If the event hits an overscrolled APZC, instruct the caller to ignore it.
-  HitTestResult hitResult = NoApzcHit;
+  HitTestResult hitResult = HitNothing;
   nsRefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(ScreenPoint(aEvent.refPoint.x, aEvent.refPoint.y),
                                                         &hitResult);
   if (apzc) {
-    MOZ_ASSERT(hitResult == ApzcHitRegion || hitResult == ApzcContentRegion);
+    MOZ_ASSERT(hitResult == HitLayer || hitResult == HitDispatchToContentRegion);
     apzc->GetGuid(aOutTargetGuid);
     Matrix4x4 transformToApzc = GetScreenToApzcTransform(apzc);
     Matrix4x4 transformToGecko = GetApzcToGeckoTransform(apzc);
     Matrix4x4 outTransform = transformToApzc * transformToGecko;
     aEvent.refPoint = TransformTo<LayoutDevicePixel>(outTransform, aEvent.refPoint);
   }
-  if (hitResult == OverscrolledApzc) {
+  if (hitResult == HitOverscrolledApzc) {
     result = nsEventStatus_eConsumeNoDefault;
   }
   return result;
 }
 
 nsEventStatus
 APZCTreeManager::ProcessWheelEvent(WidgetWheelEvent& aEvent,
                                    ScrollableLayerGuid* aOutTargetGuid,
@@ -1210,23 +1210,23 @@ APZCTreeManager::GetTargetNode(const Scr
   nsRefPtr<HitTestingTreeNode> target = FindTargetNode(mRootNode, aGuid, aComparator);
   return target.forget();
 }
 
 already_AddRefed<AsyncPanZoomController>
 APZCTreeManager::GetTargetAPZC(const ScreenPoint& aPoint, HitTestResult* aOutHitResult)
 {
   MonitorAutoLock lock(mTreeLock);
-  HitTestResult hitResult = NoApzcHit;
+  HitTestResult hitResult = HitNothing;
   ParentLayerPoint point = ViewAs<ParentLayerPixel>(aPoint,
     PixelCastJustification::ScreenIsParentLayerForRoot);
   nsRefPtr<AsyncPanZoomController> target = GetAPZCAtPoint(mRootNode, point, &hitResult);
 
   // If we are in an overscrolled APZC, we should be returning nullptr.
-  MOZ_ASSERT(!(target && (hitResult == OverscrolledApzc)));
+  MOZ_ASSERT(!(target && (hitResult == HitOverscrolledApzc)));
   if (aOutHitResult) {
     *aOutHitResult = hitResult;
   }
   return target.forget();
 }
 
 static bool
 GuidComparatorIgnoringPresShell(const ScrollableLayerGuid& aOne, const ScrollableLayerGuid& aTwo)
@@ -1361,50 +1361,50 @@ APZCTreeManager::GetAPZCAtPoint(HitTesti
 
     // First check the subtree rooted at this node, because deeper nodes
     // are more "in front".
     Maybe<LayerPoint> hitTestPointForChildLayers = node->Untransform(aHitTestPoint);
     if (hitTestPointForChildLayers) {
       ParentLayerPoint childPoint = ViewAs<ParentLayerPixel>(hitTestPointForChildLayers.ref(),
         PixelCastJustification::MovingDownToChildren);
       result = GetAPZCAtPoint(node->GetLastChild(), childPoint, aOutHitResult);
-      if (*aOutHitResult == OverscrolledApzc) {
+      if (*aOutHitResult == HitOverscrolledApzc) {
         // We matched an overscrolled APZC, abort.
         return nullptr;
       }
     }
 
     // If we didn't match anything in the subtree, check |node|.
-    if (!result) {
+    if (*aOutHitResult == HitNothing) {
       APZCTM_LOG("Testing ParentLayer point %s (Layer %s) against node %p\n",
           Stringify(aHitTestPoint).c_str(),
           hitTestPointForChildLayers ? Stringify(hitTestPointForChildLayers.ref()).c_str() : "nil",
           node);
       HitTestResult hitResult = node->HitTest(aHitTestPoint);
-      if (hitResult != HitTestResult::NoApzcHit) {
+      if (hitResult != HitTestResult::HitNothing) {
         result = node->GetNearestContainingApzc();
         APZCTM_LOG("Successfully matched APZC %p via node %p (hit result %d)\n",
              result, node, hitResult);
-        MOZ_ASSERT(hitResult == ApzcHitRegion || hitResult == ApzcContentRegion);
-        // If event regions are disabled, *aOutHitResult will be ApzcHitRegion
+        MOZ_ASSERT(hitResult == HitLayer || hitResult == HitDispatchToContentRegion);
+        // If event regions are disabled, *aOutHitResult will be HitLayer
         *aOutHitResult = hitResult;
       }
     }
 
     // If we are overscrolled, and the point matches us or one of our children,
     // the result is inside an overscrolled APZC, inform our caller of this
     // (callers typically ignore events targeted at overscrolled APZCs).
-    if (result && apzc && apzc->IsOverscrolled()) {
+    if (*aOutHitResult != HitNothing && apzc && apzc->IsOverscrolled()) {
       APZCTM_LOG("Result is inside overscrolled APZC %p\n", apzc);
-      *aOutHitResult = OverscrolledApzc;
+      *aOutHitResult = HitOverscrolledApzc;
       return nullptr;
     }
 
-    if (result) {
-      if (!gfxPrefs::LayoutEventRegionsEnabled()) {
+    if (*aOutHitResult != HitNothing) {
+      if (result && !gfxPrefs::LayoutEventRegionsEnabled()) {
         // When event-regions are disabled, we treat scrollinfo layers as
         // regular scrollable layers. Unfortunately, their "hit region" (which
         // we create from the composition bounds) is their full area, and they
         // sit on top of their non-scrollinfo siblings. This means they will get
         // a HitTestingTreeNode with a hit region that will aggressively match
         // any input events that might be directed to sub-APZCs of their non-
         // scrollinfo siblings. Therefore, we need to keep looping through to
         // see if there are any other non-scrollinfo siblings that have children
--- a/gfx/layers/apz/src/APZUtils.h
+++ b/gfx/layers/apz/src/APZUtils.h
@@ -6,18 +6,18 @@
 
 #ifndef mozilla_layers_APZUtils_h
 #define mozilla_layers_APZUtils_h
 
 namespace mozilla {
 namespace layers {
 
 enum HitTestResult {
-  NoApzcHit,
-  ApzcHitRegion,
-  ApzcContentRegion,
-  OverscrolledApzc,
+  HitNothing,
+  HitLayer,
+  HitDispatchToContentRegion,
+  HitOverscrolledApzc,
 };
 
 }
 }
 
 #endif // mozilla_layers_APZUtils_h
--- a/gfx/layers/apz/src/AsyncPanZoomController.cpp
+++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp
@@ -889,18 +889,18 @@ AsyncPanZoomController::AsyncPanZoomCont
                                                GeckoContentController* aGeckoContentController,
                                                GestureBehavior aGestures)
   :  mLayersId(aLayersId),
      mPaintThrottler(GetFrameTime(), TimeDuration::FromMilliseconds(500)),
      mGeckoContentController(aGeckoContentController),
      mRefPtrMonitor("RefPtrMonitor"),
      mSharingFrameMetricsAcrossProcesses(false),
      mMonitor("AsyncPanZoomController"),
-     mX(MOZ_THIS_IN_INITIALIZER_LIST()),
-     mY(MOZ_THIS_IN_INITIALIZER_LIST()),
+     mX(this),
+     mY(this),
      mPanDirRestricted(false),
      mZoomConstraints(false, false, MIN_ZOOM, MAX_ZOOM),
      mLastSampleTime(GetFrameTime()),
      mLastAsyncScrollTime(GetFrameTime()),
      mLastAsyncScrollOffset(0, 0),
      mCurrentAsyncScrollOffset(0, 0),
      mAsyncScrollTimeoutTask(nullptr),
      mState(NOTHING),
--- a/gfx/layers/apz/src/HitTestingTreeNode.cpp
+++ b/gfx/layers/apz/src/HitTestingTreeNode.cpp
@@ -190,34 +190,34 @@ HitTestingTreeNode::HitTest(const Parent
   MOZ_ASSERT(!IsOutsideClip(aPoint));
 
   // When event regions are disabled and we have an APZC on this node, we are
   // actually storing the touch-sensitive section of the composition bounds in
   // the clip region, and we don't need to check against the mEventRegions.
   // If there's no APZC, then we do need to check against the mEventRegions
   // (which contains the layer's visible region) for obscuration purposes.
   if (!gfxPrefs::LayoutEventRegionsEnabled() && GetApzc()) {
-    return HitTestResult::ApzcHitRegion;
+    return HitTestResult::HitLayer;
   }
 
   // convert into Layer coordinate space
   Maybe<LayerPoint> pointInLayerPixels = Untransform(aPoint);
   if (!pointInLayerPixels) {
-    return HitTestResult::NoApzcHit;
+    return HitTestResult::HitNothing;
   }
   LayerIntPoint point = RoundedToInt(pointInLayerPixels.ref());
 
   // test against event regions in Layer coordinate space
   if (!mEventRegions.mHitRegion.Contains(point.x, point.y)) {
-    return HitTestResult::NoApzcHit;
+    return HitTestResult::HitNothing;
   }
   if (mEventRegions.mDispatchToContentHitRegion.Contains(point.x, point.y)) {
-    return HitTestResult::ApzcContentRegion;
+    return HitTestResult::HitDispatchToContentRegion;
   }
-  return HitTestResult::ApzcHitRegion;
+  return HitTestResult::HitLayer;
 }
 
 void
 HitTestingTreeNode::Dump(const char* aPrefix) const
 {
   if (mPrevSibling) {
     mPrevSibling->Dump(aPrefix);
   }
--- a/gfx/layers/basic/BasicCanvasLayer.h
+++ b/gfx/layers/basic/BasicCanvasLayer.h