--- 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