mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge m-c to fx-team. a=merge
This commit is contained in:
commit
4d85d8809e
@ -19,13 +19,13 @@
|
|||||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||||
</project>
|
</project>
|
||||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="d0d773c277a9105288ee35da2121f4ae62709be8"/>
|
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="fe933e0c958f80b241a9b580cad980ff1338b038"/>
|
||||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
|
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
|
||||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>
|
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>
|
||||||
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="f0592d4814d738e3f8d840915ef799c13601bdef"/>
|
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="f0592d4814d738e3f8d840915ef799c13601bdef"/>
|
||||||
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
|
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
|
||||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="ac3d46419118a5ac515940f748aaed3273d165d8"/>
|
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="dbc46f0bc269791c52becbef22f84c63469ee8be"/>
|
||||||
<!-- Stock Android things -->
|
<!-- Stock Android things -->
|
||||||
<project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
|
<project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
|
||||||
<project name="platform/bionic" path="bionic" revision="c72b8f6359de7ed17c11ddc9dfdde3f615d188a9"/>
|
<project name="platform/bionic" path="bionic" revision="c72b8f6359de7ed17c11ddc9dfdde3f615d188a9"/>
|
||||||
|
@ -17,10 +17,10 @@
|
|||||||
</project>
|
</project>
|
||||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="d0d773c277a9105288ee35da2121f4ae62709be8"/>
|
<project name="gaia" path="gaia" remote="mozillaorg" revision="fe933e0c958f80b241a9b580cad980ff1338b038"/>
|
||||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
|
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
|
||||||
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
|
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
|
||||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="ac3d46419118a5ac515940f748aaed3273d165d8"/>
|
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="dbc46f0bc269791c52becbef22f84c63469ee8be"/>
|
||||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
|
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
|
||||||
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
|
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
|
||||||
<!-- Stock Android things -->
|
<!-- Stock Android things -->
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
<project name="platform_build" path="build" remote="b2g" revision="7945ca73e687be5edbc7b928dc7fe3a208242144">
|
<project name="platform_build" path="build" remote="b2g" revision="7945ca73e687be5edbc7b928dc7fe3a208242144">
|
||||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||||
</project>
|
</project>
|
||||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="d0d773c277a9105288ee35da2121f4ae62709be8"/>
|
<project name="gaia" path="gaia" remote="mozillaorg" revision="fe933e0c958f80b241a9b580cad980ff1338b038"/>
|
||||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
|
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
|
||||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||||
@ -23,7 +23,7 @@
|
|||||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
|
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
|
||||||
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
|
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
|
||||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="ac3d46419118a5ac515940f748aaed3273d165d8"/>
|
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="dbc46f0bc269791c52becbef22f84c63469ee8be"/>
|
||||||
<!-- Stock Android things -->
|
<!-- Stock Android things -->
|
||||||
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="f92a936f2aa97526d4593386754bdbf02db07a12"/>
|
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="f92a936f2aa97526d4593386754bdbf02db07a12"/>
|
||||||
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="6e47ff2790f5656b5b074407829ceecf3e6188c4"/>
|
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="6e47ff2790f5656b5b074407829ceecf3e6188c4"/>
|
||||||
|
@ -19,13 +19,13 @@
|
|||||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||||
</project>
|
</project>
|
||||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="d0d773c277a9105288ee35da2121f4ae62709be8"/>
|
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="fe933e0c958f80b241a9b580cad980ff1338b038"/>
|
||||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
|
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
|
||||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>
|
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>
|
||||||
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="f0592d4814d738e3f8d840915ef799c13601bdef"/>
|
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="f0592d4814d738e3f8d840915ef799c13601bdef"/>
|
||||||
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
|
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
|
||||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="ac3d46419118a5ac515940f748aaed3273d165d8"/>
|
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="dbc46f0bc269791c52becbef22f84c63469ee8be"/>
|
||||||
<!-- Stock Android things -->
|
<!-- Stock Android things -->
|
||||||
<project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
|
<project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
|
||||||
<project name="platform/bionic" path="bionic" revision="c72b8f6359de7ed17c11ddc9dfdde3f615d188a9"/>
|
<project name="platform/bionic" path="bionic" revision="c72b8f6359de7ed17c11ddc9dfdde3f615d188a9"/>
|
||||||
|
@ -17,10 +17,10 @@
|
|||||||
</project>
|
</project>
|
||||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="d0d773c277a9105288ee35da2121f4ae62709be8"/>
|
<project name="gaia" path="gaia" remote="mozillaorg" revision="fe933e0c958f80b241a9b580cad980ff1338b038"/>
|
||||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
|
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
|
||||||
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
|
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
|
||||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="ac3d46419118a5ac515940f748aaed3273d165d8"/>
|
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="dbc46f0bc269791c52becbef22f84c63469ee8be"/>
|
||||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
|
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
|
||||||
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
|
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
|
||||||
<!-- Stock Android things -->
|
<!-- Stock Android things -->
|
||||||
|
@ -4,6 +4,6 @@
|
|||||||
"remote": "",
|
"remote": "",
|
||||||
"branch": ""
|
"branch": ""
|
||||||
},
|
},
|
||||||
"revision": "87505dbb861f8c1e5437bcf92cc5a0040e6fdf3f",
|
"revision": "0cf972fdd11ec591d6a1dd4a8139e2703c40f1e1",
|
||||||
"repo_path": "/integration/gaia-central"
|
"repo_path": "/integration/gaia-central"
|
||||||
}
|
}
|
||||||
|
@ -17,12 +17,12 @@
|
|||||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||||
</project>
|
</project>
|
||||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="d0d773c277a9105288ee35da2121f4ae62709be8"/>
|
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="fe933e0c958f80b241a9b580cad980ff1338b038"/>
|
||||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
|
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
|
||||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||||
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
|
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
|
||||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="ac3d46419118a5ac515940f748aaed3273d165d8"/>
|
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="dbc46f0bc269791c52becbef22f84c63469ee8be"/>
|
||||||
<!-- Stock Android things -->
|
<!-- Stock Android things -->
|
||||||
<project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
|
<project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
|
||||||
<project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
|
<project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||||
</project>
|
</project>
|
||||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="d0d773c277a9105288ee35da2121f4ae62709be8"/>
|
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="fe933e0c958f80b241a9b580cad980ff1338b038"/>
|
||||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
|
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
|
||||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||||
|
@ -17,10 +17,10 @@
|
|||||||
</project>
|
</project>
|
||||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="d0d773c277a9105288ee35da2121f4ae62709be8"/>
|
<project name="gaia" path="gaia" remote="mozillaorg" revision="fe933e0c958f80b241a9b580cad980ff1338b038"/>
|
||||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
|
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
|
||||||
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
|
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
|
||||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="ac3d46419118a5ac515940f748aaed3273d165d8"/>
|
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="dbc46f0bc269791c52becbef22f84c63469ee8be"/>
|
||||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
|
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
|
||||||
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
|
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
|
||||||
<!-- Stock Android things -->
|
<!-- Stock Android things -->
|
||||||
|
@ -17,12 +17,12 @@
|
|||||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||||
</project>
|
</project>
|
||||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="d0d773c277a9105288ee35da2121f4ae62709be8"/>
|
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="fe933e0c958f80b241a9b580cad980ff1338b038"/>
|
||||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
|
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
|
||||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||||
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
|
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
|
||||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="ac3d46419118a5ac515940f748aaed3273d165d8"/>
|
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="dbc46f0bc269791c52becbef22f84c63469ee8be"/>
|
||||||
<project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
|
<project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
|
||||||
<!-- Stock Android things -->
|
<!-- Stock Android things -->
|
||||||
<project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
|
<project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
|
||||||
|
@ -657,9 +657,6 @@
|
|||||||
; [Layout Engine Resources]
|
; [Layout Engine Resources]
|
||||||
; Style Sheets, Graphics and other Resources used by the layout engine.
|
; Style Sheets, Graphics and other Resources used by the layout engine.
|
||||||
@BINPATH@/res/EditorOverride.css
|
@BINPATH@/res/EditorOverride.css
|
||||||
@BINPATH@/res/caret_left.svg
|
|
||||||
@BINPATH@/res/caret_middle.svg
|
|
||||||
@BINPATH@/res/caret_right.svg
|
|
||||||
@BINPATH@/res/contenteditable.css
|
@BINPATH@/res/contenteditable.css
|
||||||
@BINPATH@/res/designmode.css
|
@BINPATH@/res/designmode.css
|
||||||
@BINPATH@/res/ImageDocument.css
|
@BINPATH@/res/ImageDocument.css
|
||||||
@ -683,6 +680,21 @@
|
|||||||
@BINPATH@/res/table-remove-row-active.gif
|
@BINPATH@/res/table-remove-row-active.gif
|
||||||
@BINPATH@/res/table-remove-row-hover.gif
|
@BINPATH@/res/table-remove-row-hover.gif
|
||||||
@BINPATH@/res/table-remove-row.gif
|
@BINPATH@/res/table-remove-row.gif
|
||||||
|
@BINPATH@/res/text_caret.png
|
||||||
|
@BINPATH@/res/text_caret@1.5x.png
|
||||||
|
@BINPATH@/res/text_caret@2.25x.png
|
||||||
|
@BINPATH@/res/text_caret@2x.png
|
||||||
|
@BINPATH@/res/text_caret_tilt_left.png
|
||||||
|
@BINPATH@/res/text_caret_tilt_left@1.5x.png
|
||||||
|
@BINPATH@/res/text_caret_tilt_left@2.25x.png
|
||||||
|
@BINPATH@/res/text_caret_tilt_left@2x.png
|
||||||
|
@BINPATH@/res/text_caret_tilt_right.png
|
||||||
|
@BINPATH@/res/text_caret_tilt_right@1.5x.png
|
||||||
|
@BINPATH@/res/text_caret_tilt_right@2.25x.png
|
||||||
|
@BINPATH@/res/text_caret_tilt_right@2x.png
|
||||||
|
@BINPATH@/res/text_selection_handle.png
|
||||||
|
@BINPATH@/res/text_selection_handle@1.5.png
|
||||||
|
@BINPATH@/res/text_selection_handle@2.png
|
||||||
@BINPATH@/res/grabber.gif
|
@BINPATH@/res/grabber.gif
|
||||||
#ifdef XP_MACOSX
|
#ifdef XP_MACOSX
|
||||||
@BINPATH@/res/cursors/*
|
@BINPATH@/res/cursors/*
|
||||||
|
@ -34,7 +34,6 @@ XPCOMUtils.defineLazyServiceGetter(this, "gDNSService",
|
|||||||
const nsIWebNavigation = Ci.nsIWebNavigation;
|
const nsIWebNavigation = Ci.nsIWebNavigation;
|
||||||
|
|
||||||
var gLastBrowserCharset = null;
|
var gLastBrowserCharset = null;
|
||||||
var gPrevCharset = null;
|
|
||||||
var gProxyFavIcon = null;
|
var gProxyFavIcon = null;
|
||||||
var gLastValidURLStr = "";
|
var gLastValidURLStr = "";
|
||||||
var gInPrintPreviewMode = false;
|
var gInPrintPreviewMode = false;
|
||||||
@ -246,7 +245,6 @@ XPCOMUtils.defineLazyGetter(this, "PageMenu", function() {
|
|||||||
* one listener that calls all real handlers.
|
* one listener that calls all real handlers.
|
||||||
*/
|
*/
|
||||||
function pageShowEventHandlers(persisted) {
|
function pageShowEventHandlers(persisted) {
|
||||||
charsetLoadListener();
|
|
||||||
XULBrowserWindow.asyncUpdateUI();
|
XULBrowserWindow.asyncUpdateUI();
|
||||||
|
|
||||||
// The PluginClickToPlay events are not fired when navigating using the
|
// The PluginClickToPlay events are not fired when navigating using the
|
||||||
@ -2592,7 +2590,7 @@ let BrowserOnClick = {
|
|||||||
anchorTarget.classList.contains("newtab-link")) {
|
anchorTarget.classList.contains("newtab-link")) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
let where = whereToOpenLink(event, false, false);
|
let where = whereToOpenLink(event, false, false);
|
||||||
openUILinkIn(anchorTarget.href, where);
|
openLinkIn(anchorTarget.href, where, { charset: ownerDoc.characterSet });
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -3524,9 +3522,7 @@ function updateCharacterEncodingMenuState()
|
|||||||
// gBrowser is null on Mac when the menubar shows in the context of
|
// gBrowser is null on Mac when the menubar shows in the context of
|
||||||
// non-browser windows. The above elements may be null depending on
|
// non-browser windows. The above elements may be null depending on
|
||||||
// what parts of the menubar are present. E.g. no app menu on Mac.
|
// what parts of the menubar are present. E.g. no app menu on Mac.
|
||||||
if (gBrowser &&
|
if (gBrowser && gBrowser.selectedBrowser.mayEnableCharacterEncodingMenu) {
|
||||||
gBrowser.docShell &&
|
|
||||||
gBrowser.docShell.mayEnableCharacterEncodingMenu) {
|
|
||||||
if (charsetMenu) {
|
if (charsetMenu) {
|
||||||
charsetMenu.removeAttribute("disabled");
|
charsetMenu.removeAttribute("disabled");
|
||||||
}
|
}
|
||||||
@ -5371,8 +5367,7 @@ function handleDroppedLink(event, url, name)
|
|||||||
function BrowserSetForcedCharacterSet(aCharset)
|
function BrowserSetForcedCharacterSet(aCharset)
|
||||||
{
|
{
|
||||||
if (aCharset) {
|
if (aCharset) {
|
||||||
gBrowser.docShell.gatherCharsetMenuTelemetry();
|
gBrowser.selectedBrowser.characterSet = aCharset;
|
||||||
gBrowser.docShell.charset = aCharset;
|
|
||||||
// Save the forced character-set
|
// Save the forced character-set
|
||||||
if (!PrivateBrowsingUtils.isWindowPrivate(window))
|
if (!PrivateBrowsingUtils.isWindowPrivate(window))
|
||||||
PlacesUtils.setCharsetForURI(getWebNavigation().currentURI, aCharset);
|
PlacesUtils.setCharsetForURI(getWebNavigation().currentURI, aCharset);
|
||||||
@ -5385,35 +5380,11 @@ function BrowserCharsetReload()
|
|||||||
BrowserReloadWithFlags(nsIWebNavigation.LOAD_FLAGS_CHARSET_CHANGE);
|
BrowserReloadWithFlags(nsIWebNavigation.LOAD_FLAGS_CHARSET_CHANGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
function charsetMenuGetElement(parent, charset) {
|
|
||||||
return parent.getElementsByAttribute("charset", charset)[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
function UpdateCurrentCharset(target) {
|
function UpdateCurrentCharset(target) {
|
||||||
// extract the charset from DOM
|
for (let menuItem of target.getElementsByTagName("menuitem")) {
|
||||||
var wnd = document.commandDispatcher.focusedWindow;
|
let isSelected = menuItem.getAttribute("charset") ===
|
||||||
if ((window == wnd) || (wnd == null)) wnd = window.content;
|
CharsetMenu.foldCharset(gBrowser.selectedBrowser.characterSet);
|
||||||
|
menuItem.setAttribute("checked", isSelected);
|
||||||
// Uncheck previous item
|
|
||||||
if (gPrevCharset) {
|
|
||||||
var pref_item = charsetMenuGetElement(target, gPrevCharset);
|
|
||||||
if (pref_item)
|
|
||||||
pref_item.setAttribute('checked', 'false');
|
|
||||||
}
|
|
||||||
|
|
||||||
var menuitem = charsetMenuGetElement(target, CharsetMenu.foldCharset(wnd.document.characterSet));
|
|
||||||
if (menuitem) {
|
|
||||||
menuitem.setAttribute('checked', 'true');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function charsetLoadListener() {
|
|
||||||
let currCharset = gBrowser.selectedBrowser.characterSet;
|
|
||||||
let charset = CharsetMenu.foldCharset(currCharset);
|
|
||||||
|
|
||||||
if (charset.length > 0 && (charset != gLastBrowserCharset)) {
|
|
||||||
gPrevCharset = gLastBrowserCharset;
|
|
||||||
gLastBrowserCharset = charset;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -735,8 +735,7 @@ const CustomizableWidgets = [{
|
|||||||
maybeDisableMenu: function(aDocument) {
|
maybeDisableMenu: function(aDocument) {
|
||||||
let window = aDocument.defaultView;
|
let window = aDocument.defaultView;
|
||||||
return !(window.gBrowser &&
|
return !(window.gBrowser &&
|
||||||
window.gBrowser.docShell &&
|
window.gBrowser.selectedBrowser.mayEnableCharacterEncodingMenu);
|
||||||
window.gBrowser.docShell.mayEnableCharacterEncodingMenu);
|
|
||||||
},
|
},
|
||||||
populateList: function(aDocument, aContainerId, aSection) {
|
populateList: function(aDocument, aContainerId, aSection) {
|
||||||
let containerElem = aDocument.getElementById(aContainerId);
|
let containerElem = aDocument.getElementById(aContainerId);
|
||||||
@ -756,8 +755,7 @@ const CustomizableWidgets = [{
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
updateCurrentCharset: function(aDocument) {
|
updateCurrentCharset: function(aDocument) {
|
||||||
let content = aDocument.defaultView.content;
|
let currentCharset = aDocument.defaultView.gBrowser.selectedBrowser.characterSet;
|
||||||
let currentCharset = content && content.document && content.document.characterSet;
|
|
||||||
currentCharset = CharsetMenu.foldCharset(currentCharset);
|
currentCharset = CharsetMenu.foldCharset(currentCharset);
|
||||||
|
|
||||||
let pinnedContainer = aDocument.getElementById("PanelUI-characterEncodingView-pinned");
|
let pinnedContainer = aDocument.getElementById("PanelUI-characterEncodingView-pinned");
|
||||||
|
@ -64,6 +64,8 @@ const PREF_TELEMETRY_ENABLED = "enabled";
|
|||||||
const URI_EXTENSION_STRINGS = "chrome://mozapps/locale/extensions/extensions.properties";
|
const URI_EXTENSION_STRINGS = "chrome://mozapps/locale/extensions/extensions.properties";
|
||||||
const STRING_TYPE_NAME = "type.%ID%.name";
|
const STRING_TYPE_NAME = "type.%ID%.name";
|
||||||
|
|
||||||
|
const CACHE_WRITE_RETRY_DELAY_SEC = 60 * 3;
|
||||||
|
|
||||||
const TELEMETRY_LOG = {
|
const TELEMETRY_LOG = {
|
||||||
// log(key, [kind, experimentId, details])
|
// log(key, [kind, experimentId, details])
|
||||||
ACTIVATION_KEY: "EXPERIMENT_ACTIVATION",
|
ACTIVATION_KEY: "EXPERIMENT_ACTIVATION",
|
||||||
@ -331,10 +333,19 @@ function AlreadyShutdownError(message="already shut down") {
|
|||||||
this.message = message;
|
this.message = message;
|
||||||
this.stack = error.stack;
|
this.stack = error.stack;
|
||||||
}
|
}
|
||||||
|
|
||||||
AlreadyShutdownError.prototype = Object.create(Error.prototype);
|
AlreadyShutdownError.prototype = Object.create(Error.prototype);
|
||||||
AlreadyShutdownError.prototype.constructor = AlreadyShutdownError;
|
AlreadyShutdownError.prototype.constructor = AlreadyShutdownError;
|
||||||
|
|
||||||
|
function CacheWriteError(message="Error writing cache file") {
|
||||||
|
Error.call(this, message);
|
||||||
|
let error = new Error();
|
||||||
|
this.name = "CacheWriteError";
|
||||||
|
this.message = message;
|
||||||
|
this.stack = error.stack;
|
||||||
|
}
|
||||||
|
CacheWriteError.prototype = Object.create(Error.prototype);
|
||||||
|
CacheWriteError.prototype.constructor = CacheWriteError;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manages the experiments and provides an interface to control them.
|
* Manages the experiments and provides an interface to control them.
|
||||||
*/
|
*/
|
||||||
@ -690,6 +701,7 @@ Experiments.Experiments.prototype = {
|
|||||||
throw new Error("Experiment not found");
|
throw new Error("Experiment not found");
|
||||||
}
|
}
|
||||||
e.branch = String(branchstr);
|
e.branch = String(branchstr);
|
||||||
|
this._log.trace("setExperimentBranch(" + id + ", " + e.branch + ") _dirty=" + this._dirty);
|
||||||
this._dirty = true;
|
this._dirty = true;
|
||||||
Services.obs.notifyObservers(null, EXPERIMENTS_CHANGED_TOPIC, null);
|
Services.obs.notifyObservers(null, EXPERIMENTS_CHANGED_TOPIC, null);
|
||||||
yield this._run();
|
yield this._run();
|
||||||
@ -766,6 +778,8 @@ Experiments.Experiments.prototype = {
|
|||||||
this._mainTask = Task.spawn(function*() {
|
this._mainTask = Task.spawn(function*() {
|
||||||
try {
|
try {
|
||||||
yield this._main();
|
yield this._main();
|
||||||
|
} catch (e if e instanceof CacheWriteError) {
|
||||||
|
// In this case we want to reschedule
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this._log.error("_main caught error: " + e);
|
this._log.error("_main caught error: " + e);
|
||||||
return;
|
return;
|
||||||
@ -801,7 +815,7 @@ Experiments.Experiments.prototype = {
|
|||||||
// If somebody called .updateManifest() or disableExperiment()
|
// If somebody called .updateManifest() or disableExperiment()
|
||||||
// while we were running, go again right now.
|
// while we were running, go again right now.
|
||||||
}
|
}
|
||||||
while (this._refresh || this._terminateReason);
|
while (this._refresh || this._terminateReason || this._dirty);
|
||||||
},
|
},
|
||||||
|
|
||||||
_loadManifest: function*() {
|
_loadManifest: function*() {
|
||||||
@ -992,7 +1006,7 @@ Experiments.Experiments.prototype = {
|
|||||||
// We failed to write the cache, it's still dirty.
|
// We failed to write the cache, it's still dirty.
|
||||||
this._dirty = true;
|
this._dirty = true;
|
||||||
this._log.error("_saveToCache failed and caught error: " + e);
|
this._log.error("_saveToCache failed and caught error: " + e);
|
||||||
return;
|
throw new CacheWriteError();
|
||||||
}
|
}
|
||||||
|
|
||||||
this._log.debug("_saveToCache saved to " + path);
|
this._log.debug("_saveToCache saved to " + path);
|
||||||
@ -1307,6 +1321,10 @@ Experiments.Experiments.prototype = {
|
|||||||
|
|
||||||
let time = null;
|
let time = null;
|
||||||
let now = this._policy.now().getTime();
|
let now = this._policy.now().getTime();
|
||||||
|
if (this._dirty) {
|
||||||
|
// If we failed to write the cache, we should try again periodically
|
||||||
|
time = now + 1000 * CACHE_WRITE_RETRY_DELAY_SEC;
|
||||||
|
}
|
||||||
|
|
||||||
for (let [id, experiment] of this._experiments) {
|
for (let [id, experiment] of this._experiments) {
|
||||||
let scheduleTime = experiment.getScheduleTime();
|
let scheduleTime = experiment.getScheduleTime();
|
||||||
|
@ -311,7 +311,7 @@ def print_command(out, args):
|
|||||||
print >>out, "".join([" " + l for l in file.readlines()])
|
print >>out, "".join([" " + l for l in file.readlines()])
|
||||||
out.flush()
|
out.flush()
|
||||||
|
|
||||||
def main():
|
def main(args, proc_callback=None):
|
||||||
parser = OptionParser()
|
parser = OptionParser()
|
||||||
parser.add_option("--extract", action="store_true", dest="extract",
|
parser.add_option("--extract", action="store_true", dest="extract",
|
||||||
help="when a library has no descriptor file, extract it first, when possible")
|
help="when a library has no descriptor file, extract it first, when possible")
|
||||||
@ -322,7 +322,7 @@ def main():
|
|||||||
parser.add_option("--symbol-order", dest="symbol_order", metavar="FILE",
|
parser.add_option("--symbol-order", dest="symbol_order", metavar="FILE",
|
||||||
help="use the given list of symbols to order symbols in the resulting binary when using with a linker")
|
help="use the given list of symbols to order symbols in the resulting binary when using with a linker")
|
||||||
|
|
||||||
(options, args) = parser.parse_args()
|
(options, args) = parser.parse_args(args)
|
||||||
|
|
||||||
with ExpandArgsMore(args) as args:
|
with ExpandArgsMore(args) as args:
|
||||||
if options.extract:
|
if options.extract:
|
||||||
@ -336,6 +336,8 @@ def main():
|
|||||||
print_command(sys.stderr, args)
|
print_command(sys.stderr, args)
|
||||||
try:
|
try:
|
||||||
proc = subprocess.Popen(args, stdout = subprocess.PIPE, stderr = subprocess.STDOUT)
|
proc = subprocess.Popen(args, stdout = subprocess.PIPE, stderr = subprocess.STDOUT)
|
||||||
|
if proc_callback:
|
||||||
|
proc_callback(proc)
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
print >>sys.stderr, 'error: Launching', args, ':', e
|
print >>sys.stderr, 'error: Launching', args, ':', e
|
||||||
raise e
|
raise e
|
||||||
@ -345,7 +347,8 @@ def main():
|
|||||||
sys.stderr.write(stdout)
|
sys.stderr.write(stdout)
|
||||||
sys.stderr.flush()
|
sys.stderr.flush()
|
||||||
if proc.returncode:
|
if proc.returncode:
|
||||||
exit(proc.returncode)
|
return proc.returncode
|
||||||
|
return 0
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
main()
|
exit(main(sys.argv[1:]))
|
||||||
|
@ -2,8 +2,11 @@
|
|||||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
# 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/.
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
from __future__ import with_statement
|
import expandlibs_exec
|
||||||
import os, subprocess, sys, threading, time
|
import sys
|
||||||
|
import threading
|
||||||
|
import time
|
||||||
|
|
||||||
from win32 import procmem
|
from win32 import procmem
|
||||||
|
|
||||||
def measure_vsize_threadfunc(proc, output_file):
|
def measure_vsize_threadfunc(proc, output_file):
|
||||||
@ -33,14 +36,17 @@ def measure_link_vsize(output_file, args):
|
|||||||
Execute |args|, and measure the maximum virtual memory usage of the process,
|
Execute |args|, and measure the maximum virtual memory usage of the process,
|
||||||
printing it to stdout when finished.
|
printing it to stdout when finished.
|
||||||
"""
|
"""
|
||||||
proc = subprocess.Popen(args)
|
|
||||||
t = threading.Thread(target=measure_vsize_threadfunc,
|
# This needs to be a list in order for the callback to set the
|
||||||
args=(proc, output_file))
|
# variable properly with python-2's scoping rules.
|
||||||
t.start()
|
t = [None]
|
||||||
# Wait for the linker to finish.
|
def callback(proc):
|
||||||
exitcode = proc.wait()
|
t[0] = threading.Thread(target=measure_vsize_threadfunc,
|
||||||
# ...and then wait for the background thread to finish.
|
args=(proc, output_file))
|
||||||
t.join()
|
t[0].start()
|
||||||
|
exitcode = expandlibs_exec.main(args, proc_callback=callback)
|
||||||
|
# Wait for the background thread to finish.
|
||||||
|
t[0].join()
|
||||||
return exitcode
|
return exitcode
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
@ -50,4 +56,5 @@ if __name__ == "__main__":
|
|||||||
if len(sys.argv) < 3:
|
if len(sys.argv) < 3:
|
||||||
print >>sys.stderr, "Usage: link.py <output filename> <commandline>"
|
print >>sys.stderr, "Usage: link.py <output filename> <commandline>"
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
sys.exit(measure_link_vsize(sys.argv[1], sys.argv[2:]))
|
output_file = sys.argv.pop(1)
|
||||||
|
sys.exit(measure_link_vsize(output_file, sys.argv[1:]))
|
@ -3973,11 +3973,15 @@ ArrayBufferBuilder::setCapacity(uint32_t aNewCap)
|
|||||||
{
|
{
|
||||||
MOZ_ASSERT(!mMapPtr);
|
MOZ_ASSERT(!mMapPtr);
|
||||||
|
|
||||||
uint8_t *newdata = (uint8_t *) JS_ReallocateArrayBufferContents(nullptr, aNewCap, mDataPtr, mCapacity);
|
uint8_t *newdata = (uint8_t *) realloc(mDataPtr, aNewCap);
|
||||||
if (!newdata) {
|
if (!newdata) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (aNewCap > mCapacity) {
|
||||||
|
memset(newdata + mCapacity, 0, aNewCap - mCapacity);
|
||||||
|
}
|
||||||
|
|
||||||
mDataPtr = newdata;
|
mDataPtr = newdata;
|
||||||
mCapacity = aNewCap;
|
mCapacity = aNewCap;
|
||||||
if (mLength > aNewCap) {
|
if (mLength > aNewCap) {
|
||||||
|
@ -178,7 +178,7 @@ LOCAL_INCLUDES += [
|
|||||||
'/dom/base',
|
'/dom/base',
|
||||||
'/dom/canvas',
|
'/dom/canvas',
|
||||||
'/dom/xbl',
|
'/dom/xbl',
|
||||||
'/editor/libeditor/base',
|
'/editor/libeditor',
|
||||||
'/editor/libeditor/text',
|
'/editor/libeditor/text',
|
||||||
'/editor/txmgr',
|
'/editor/txmgr',
|
||||||
'/layout/forms',
|
'/layout/forms',
|
||||||
|
@ -113,12 +113,14 @@ ImageListener::OnStartRequest(nsIRequest* request, nsISupports *ctxt)
|
|||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(imgDoc->mImageContent);
|
if (!imgDoc->mObservingImageLoader) {
|
||||||
NS_ENSURE_TRUE(imageLoader, NS_ERROR_UNEXPECTED);
|
nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(imgDoc->mImageContent);
|
||||||
|
NS_ENSURE_TRUE(imageLoader, NS_ERROR_UNEXPECTED);
|
||||||
|
|
||||||
imageLoader->AddObserver(imgDoc);
|
imageLoader->AddObserver(imgDoc);
|
||||||
imgDoc->mObservingImageLoader = true;
|
imgDoc->mObservingImageLoader = true;
|
||||||
imageLoader->LoadImageWithChannel(channel, getter_AddRefs(mNextStream));
|
imageLoader->LoadImageWithChannel(channel, getter_AddRefs(mNextStream));
|
||||||
|
}
|
||||||
|
|
||||||
return MediaDocumentStreamListener::OnStartRequest(request, ctxt);
|
return MediaDocumentStreamListener::OnStartRequest(request, ctxt);
|
||||||
}
|
}
|
||||||
@ -384,12 +386,14 @@ ImageDocument::ScrollImageTo(int32_t aX, int32_t aY, bool restoreImage)
|
|||||||
}
|
}
|
||||||
|
|
||||||
nsCOMPtr<nsIPresShell> shell = GetShell();
|
nsCOMPtr<nsIPresShell> shell = GetShell();
|
||||||
if (!shell)
|
if (!shell) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
nsIScrollableFrame* sf = shell->GetRootScrollFrameAsScrollable();
|
nsIScrollableFrame* sf = shell->GetRootScrollFrameAsScrollable();
|
||||||
if (!sf)
|
if (!sf) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
nsRect portRect = sf->GetScrollPortRect();
|
nsRect portRect = sf->GetScrollPortRect();
|
||||||
sf->ScrollTo(nsPoint(nsPresContext::CSSPixelsToAppUnits(aX/ratio) - portRect.width/2,
|
sf->ScrollTo(nsPoint(nsPresContext::CSSPixelsToAppUnits(aX/ratio) - portRect.width/2,
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
#include "mozilla/Services.h"
|
#include "mozilla/Services.h"
|
||||||
#include "nsServiceManagerUtils.h"
|
#include "nsServiceManagerUtils.h"
|
||||||
#include "nsIPrincipal.h"
|
#include "nsIPrincipal.h"
|
||||||
|
#include "nsIMultiPartChannel.h"
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
namespace dom {
|
namespace dom {
|
||||||
@ -70,9 +71,16 @@ MediaDocumentStreamListener::OnStopRequest(nsIRequest* request,
|
|||||||
rv = mNextStream->OnStopRequest(request, ctxt, status);
|
rv = mNextStream->OnStopRequest(request, ctxt, status);
|
||||||
}
|
}
|
||||||
|
|
||||||
// No more need for our document so clear our reference and prevent leaks
|
// Don't release mDocument here if we're in the middle of a multipart response.
|
||||||
mDocument = nullptr;
|
bool lastPart = true;
|
||||||
|
nsCOMPtr<nsIMultiPartChannel> mpchan(do_QueryInterface(request));
|
||||||
|
if (mpchan) {
|
||||||
|
mpchan->GetIsLastPart(&lastPart);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lastPart) {
|
||||||
|
mDocument = nullptr;
|
||||||
|
}
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -758,6 +758,9 @@ public:
|
|||||||
MediaInfo* aInfo,
|
MediaInfo* aInfo,
|
||||||
MetadataTags* aTags);
|
MetadataTags* aTags);
|
||||||
|
|
||||||
|
int64_t GetSeekTime() { return mRequestedSeekTarget.mTime; }
|
||||||
|
void ResetSeekTime() { mRequestedSeekTarget.Reset(); }
|
||||||
|
|
||||||
/******
|
/******
|
||||||
* The following methods must only be called on the main
|
* The following methods must only be called on the main
|
||||||
* thread.
|
* thread.
|
||||||
|
@ -1518,17 +1518,16 @@ MediaDecoderStateMachine::EnqueueDecodeMetadataTask()
|
|||||||
mDispatchedDecodeMetadataTask) {
|
mDispatchedDecodeMetadataTask) {
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mDispatchedDecodeMetadataTask = true;
|
||||||
RefPtr<nsIRunnable> task(
|
RefPtr<nsIRunnable> task(
|
||||||
NS_NewRunnableMethod(this, &MediaDecoderStateMachine::CallDecodeMetadata));
|
NS_NewRunnableMethod(this, &MediaDecoderStateMachine::CallDecodeMetadata));
|
||||||
nsresult rv = mDecodeTaskQueue->Dispatch(task);
|
nsresult rv = mDecodeTaskQueue->Dispatch(task);
|
||||||
if (NS_SUCCEEDED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
mDispatchedDecodeMetadataTask = true;
|
|
||||||
} else {
|
|
||||||
NS_WARNING("Dispatch ReadMetadata task failed.");
|
NS_WARNING("Dispatch ReadMetadata task failed.");
|
||||||
return rv;
|
mDispatchedDecodeMetadataTask = false;
|
||||||
}
|
}
|
||||||
|
return rv;
|
||||||
return NS_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -1842,7 +1841,6 @@ void
|
|||||||
MediaDecoderStateMachine::CallDecodeMetadata()
|
MediaDecoderStateMachine::CallDecodeMetadata()
|
||||||
{
|
{
|
||||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||||
AutoSetOnScopeExit<bool> unsetOnExit(mDispatchedDecodeMetadataTask, false);
|
|
||||||
if (mState != DECODER_STATE_DECODING_METADATA) {
|
if (mState != DECODER_STATE_DECODING_METADATA) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1874,6 +1872,7 @@ nsresult MediaDecoderStateMachine::DecodeMetadata()
|
|||||||
// change state to DECODER_STATE_WAIT_FOR_RESOURCES
|
// change state to DECODER_STATE_WAIT_FOR_RESOURCES
|
||||||
StartWaitForResources();
|
StartWaitForResources();
|
||||||
// affect values only if ReadMetadata succeeds
|
// affect values only if ReadMetadata succeeds
|
||||||
|
mDispatchedDecodeMetadataTask = false;
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1996,6 +1995,7 @@ MediaDecoderStateMachine::FinishDecodeMetadata()
|
|||||||
StartPlayback();
|
StartPlayback();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mDispatchedDecodeMetadataTask = false;
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2443,23 +2443,23 @@ MediaDecoderStateMachine::FlushDecoding()
|
|||||||
"Should be on state machine or decode thread.");
|
"Should be on state machine or decode thread.");
|
||||||
mDecoder->GetReentrantMonitor().AssertNotCurrentThreadIn();
|
mDecoder->GetReentrantMonitor().AssertNotCurrentThreadIn();
|
||||||
|
|
||||||
// Put a task in the decode queue to abort any decoding operations.
|
|
||||||
// The reader is not supposed to put any tasks to deliver samples into
|
|
||||||
// the queue after we call this (unless we request another sample from it).
|
|
||||||
RefPtr<nsIRunnable> task;
|
|
||||||
task = NS_NewRunnableMethod(mReader, &MediaDecoderReader::ResetDecode);
|
|
||||||
mDecodeTaskQueue->Dispatch(task);
|
|
||||||
|
|
||||||
{
|
{
|
||||||
// Wait for the thread decoding to abort decoding operations and run
|
// Put a task in the decode queue to abort any decoding operations.
|
||||||
// any pending callbacks. This is important, as we don't want any
|
// The reader is not supposed to put any tasks to deliver samples into
|
||||||
// pending tasks posted to the task queue by the reader to deliver
|
// the queue after this runs (unless we request another sample from it).
|
||||||
// any samples after we've posted the reader Shutdown() task below,
|
RefPtr<nsIRunnable> task;
|
||||||
// as the sample-delivery tasks will keep video frames alive until
|
task = NS_NewRunnableMethod(mReader, &MediaDecoderReader::ResetDecode);
|
||||||
// after we've called Reader::Shutdown(), and shutdown on B2G will
|
|
||||||
// fail as there are outstanding video frames alive.
|
// Wait for the ResetDecode to run and for the decoder to abort
|
||||||
|
// decoding operations and run any pending callbacks. This is
|
||||||
|
// important, as we don't want any pending tasks posted to the task
|
||||||
|
// queue by the reader to deliver any samples after we've posted the
|
||||||
|
// reader Shutdown() task below, as the sample-delivery tasks will
|
||||||
|
// keep video frames alive until after we've called Reader::Shutdown(),
|
||||||
|
// and shutdown on B2G will fail as there are outstanding video frames
|
||||||
|
// alive.
|
||||||
ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor());
|
ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor());
|
||||||
mDecodeTaskQueue->Flush();
|
mDecodeTaskQueue->FlushAndDispatch(task);
|
||||||
}
|
}
|
||||||
|
|
||||||
// We must reset playback so that all references to frames queued
|
// We must reset playback so that all references to frames queued
|
||||||
|
@ -15,6 +15,7 @@ MediaTaskQueue::MediaTaskQueue(TemporaryRef<SharedThreadPool> aPool)
|
|||||||
, mQueueMonitor("MediaTaskQueue::Queue")
|
, mQueueMonitor("MediaTaskQueue::Queue")
|
||||||
, mIsRunning(false)
|
, mIsRunning(false)
|
||||||
, mIsShutdown(false)
|
, mIsShutdown(false)
|
||||||
|
, mIsFlushing(false)
|
||||||
{
|
{
|
||||||
MOZ_COUNT_CTOR(MediaTaskQueue);
|
MOZ_COUNT_CTOR(MediaTaskQueue);
|
||||||
}
|
}
|
||||||
@ -30,6 +31,17 @@ nsresult
|
|||||||
MediaTaskQueue::Dispatch(TemporaryRef<nsIRunnable> aRunnable)
|
MediaTaskQueue::Dispatch(TemporaryRef<nsIRunnable> aRunnable)
|
||||||
{
|
{
|
||||||
MonitorAutoLock mon(mQueueMonitor);
|
MonitorAutoLock mon(mQueueMonitor);
|
||||||
|
return DispatchLocked(aRunnable, AbortIfFlushing);
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
MediaTaskQueue::DispatchLocked(TemporaryRef<nsIRunnable> aRunnable,
|
||||||
|
DispatchMode aMode)
|
||||||
|
{
|
||||||
|
mQueueMonitor.AssertCurrentThreadOwns();
|
||||||
|
if (mIsFlushing && aMode == AbortIfFlushing) {
|
||||||
|
return NS_ERROR_ABORT;
|
||||||
|
}
|
||||||
if (mIsShutdown) {
|
if (mIsShutdown) {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
@ -113,10 +125,25 @@ MediaTaskQueue::Shutdown()
|
|||||||
AwaitIdleLocked();
|
AwaitIdleLocked();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
MediaTaskQueue::FlushAndDispatch(TemporaryRef<nsIRunnable> aRunnable)
|
||||||
|
{
|
||||||
|
MonitorAutoLock mon(mQueueMonitor);
|
||||||
|
AutoSetFlushing autoFlush(this);
|
||||||
|
while (!mTasks.empty()) {
|
||||||
|
mTasks.pop();
|
||||||
|
}
|
||||||
|
nsresult rv = DispatchLocked(aRunnable, IgnoreFlushing);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
AwaitIdleLocked();
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MediaTaskQueue::Flush()
|
MediaTaskQueue::Flush()
|
||||||
{
|
{
|
||||||
MonitorAutoLock mon(mQueueMonitor);
|
MonitorAutoLock mon(mQueueMonitor);
|
||||||
|
AutoSetFlushing autoFlush(this);
|
||||||
while (!mTasks.empty()) {
|
while (!mTasks.empty()) {
|
||||||
mTasks.pop();
|
mTasks.pop();
|
||||||
}
|
}
|
||||||
|
@ -35,6 +35,8 @@ public:
|
|||||||
|
|
||||||
nsresult SyncDispatch(TemporaryRef<nsIRunnable> aRunnable);
|
nsresult SyncDispatch(TemporaryRef<nsIRunnable> aRunnable);
|
||||||
|
|
||||||
|
nsresult FlushAndDispatch(TemporaryRef<nsIRunnable> aRunnable);
|
||||||
|
|
||||||
// Removes all pending tasks from the task queue, and blocks until
|
// Removes all pending tasks from the task queue, and blocks until
|
||||||
// the currently running task (if any) finishes.
|
// the currently running task (if any) finishes.
|
||||||
void Flush();
|
void Flush();
|
||||||
@ -59,6 +61,11 @@ private:
|
|||||||
// mQueueMonitor must be held.
|
// mQueueMonitor must be held.
|
||||||
void AwaitIdleLocked();
|
void AwaitIdleLocked();
|
||||||
|
|
||||||
|
enum DispatchMode { AbortIfFlushing, IgnoreFlushing };
|
||||||
|
|
||||||
|
nsresult DispatchLocked(TemporaryRef<nsIRunnable> aRunnable,
|
||||||
|
DispatchMode aMode);
|
||||||
|
|
||||||
RefPtr<SharedThreadPool> mPool;
|
RefPtr<SharedThreadPool> mPool;
|
||||||
|
|
||||||
// Monitor that protects the queue and mIsRunning;
|
// Monitor that protects the queue and mIsRunning;
|
||||||
@ -79,6 +86,27 @@ private:
|
|||||||
// True if we've started our shutdown process.
|
// True if we've started our shutdown process.
|
||||||
bool mIsShutdown;
|
bool mIsShutdown;
|
||||||
|
|
||||||
|
class MOZ_STACK_CLASS AutoSetFlushing
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AutoSetFlushing(MediaTaskQueue* aTaskQueue) : mTaskQueue(aTaskQueue)
|
||||||
|
{
|
||||||
|
mTaskQueue->mQueueMonitor.AssertCurrentThreadOwns();
|
||||||
|
mTaskQueue->mIsFlushing = true;
|
||||||
|
}
|
||||||
|
~AutoSetFlushing()
|
||||||
|
{
|
||||||
|
mTaskQueue->mQueueMonitor.AssertCurrentThreadOwns();
|
||||||
|
mTaskQueue->mIsFlushing = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
MediaTaskQueue* mTaskQueue;
|
||||||
|
};
|
||||||
|
|
||||||
|
// True if we're flushing; we reject new tasks if we're flushing.
|
||||||
|
bool mIsFlushing;
|
||||||
|
|
||||||
class Runner : public nsRunnable {
|
class Runner : public nsRunnable {
|
||||||
public:
|
public:
|
||||||
Runner(MediaTaskQueue* aQueue)
|
Runner(MediaTaskQueue* aQueue)
|
||||||
|
@ -54,10 +54,10 @@ AppleATDecoder::~AppleATDecoder()
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
_MetadataCallback(void *aDecoder,
|
_MetadataCallback(void* aDecoder,
|
||||||
AudioFileStreamID aStream,
|
AudioFileStreamID aStream,
|
||||||
AudioFileStreamPropertyID aProperty,
|
AudioFileStreamPropertyID aProperty,
|
||||||
UInt32 *aFlags)
|
UInt32* aFlags)
|
||||||
{
|
{
|
||||||
LOG("AppleATDecoder metadata callback");
|
LOG("AppleATDecoder metadata callback");
|
||||||
AppleATDecoder* decoder = static_cast<AppleATDecoder*>(aDecoder);
|
AppleATDecoder* decoder = static_cast<AppleATDecoder*>(aDecoder);
|
||||||
@ -65,10 +65,11 @@ _MetadataCallback(void *aDecoder,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
_SampleCallback(void *aDecoder,
|
_SampleCallback(void* aDecoder,
|
||||||
UInt32 aNumBytes, UInt32 aNumPackets,
|
UInt32 aNumBytes,
|
||||||
const void *aData,
|
UInt32 aNumPackets,
|
||||||
AudioStreamPacketDescription *aPackets)
|
const void* aData,
|
||||||
|
AudioStreamPacketDescription* aPackets)
|
||||||
{
|
{
|
||||||
LOG("AppleATDecoder sample callback %u bytes %u packets",
|
LOG("AppleATDecoder sample callback %u bytes %u packets",
|
||||||
aNumBytes, aNumPackets);
|
aNumBytes, aNumPackets);
|
||||||
@ -170,8 +171,8 @@ struct PassthroughUserData {
|
|||||||
AppleATDecoder* mDecoder;
|
AppleATDecoder* mDecoder;
|
||||||
UInt32 mNumPackets;
|
UInt32 mNumPackets;
|
||||||
UInt32 mDataSize;
|
UInt32 mDataSize;
|
||||||
const void *mData;
|
const void* mData;
|
||||||
AudioStreamPacketDescription *mPacketDesc;
|
AudioStreamPacketDescription* mPacketDesc;
|
||||||
bool mDone;
|
bool mDone;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -181,12 +182,12 @@ const uint32_t kNeedMoreData = 'MOAR';
|
|||||||
|
|
||||||
static OSStatus
|
static OSStatus
|
||||||
_PassthroughInputDataCallback(AudioConverterRef aAudioConverter,
|
_PassthroughInputDataCallback(AudioConverterRef aAudioConverter,
|
||||||
UInt32 *aNumDataPackets /* in/out */,
|
UInt32* aNumDataPackets /* in/out */,
|
||||||
AudioBufferList *aData /* in/out */,
|
AudioBufferList* aData /* in/out */,
|
||||||
AudioStreamPacketDescription **aPacketDesc,
|
AudioStreamPacketDescription** aPacketDesc,
|
||||||
void *aUserData)
|
void* aUserData)
|
||||||
{
|
{
|
||||||
PassthroughUserData *userData = (PassthroughUserData *)aUserData;
|
PassthroughUserData* userData = (PassthroughUserData*)aUserData;
|
||||||
if (userData->mDone) {
|
if (userData->mDone) {
|
||||||
// We make sure this callback is run _once_, with all the data we received
|
// We make sure this callback is run _once_, with all the data we received
|
||||||
// from |AudioFileStreamParseBytes|. When we return an error, the decoder
|
// from |AudioFileStreamParseBytes|. When we return an error, the decoder
|
||||||
@ -207,7 +208,7 @@ _PassthroughInputDataCallback(AudioConverterRef aAudioConverter,
|
|||||||
|
|
||||||
aData->mBuffers[0].mNumberChannels = userData->mDecoder->mConfig.channel_count;
|
aData->mBuffers[0].mNumberChannels = userData->mDecoder->mConfig.channel_count;
|
||||||
aData->mBuffers[0].mDataByteSize = userData->mDataSize;
|
aData->mBuffers[0].mDataByteSize = userData->mDataSize;
|
||||||
aData->mBuffers[0].mData = const_cast<void *>(userData->mData);
|
aData->mBuffers[0].mData = const_cast<void*>(userData->mData);
|
||||||
|
|
||||||
return noErr;
|
return noErr;
|
||||||
}
|
}
|
||||||
@ -280,9 +281,9 @@ AppleATDecoder::SampleCallback(uint32_t aNumBytes,
|
|||||||
LOG("pushed audio at time %lfs; duration %lfs\n",
|
LOG("pushed audio at time %lfs; duration %lfs\n",
|
||||||
(double)time / USECS_PER_S, (double)duration / USECS_PER_S);
|
(double)time / USECS_PER_S, (double)duration / USECS_PER_S);
|
||||||
|
|
||||||
AudioData *audio = new AudioData(mSamplePosition,
|
AudioData* audio = new AudioData(mSamplePosition,
|
||||||
time, duration, numFrames,
|
time, duration, numFrames,
|
||||||
reinterpret_cast<AudioDataValue *>(decoded.forget()),
|
reinterpret_cast<AudioDataValue*>(decoded.forget()),
|
||||||
channels, rate);
|
channels, rate);
|
||||||
mCallback->Output(audio);
|
mCallback->Output(audio);
|
||||||
mHaveOutput = true;
|
mHaveOutput = true;
|
||||||
@ -302,9 +303,14 @@ void
|
|||||||
AppleATDecoder::SetupDecoder()
|
AppleATDecoder::SetupDecoder()
|
||||||
{
|
{
|
||||||
AudioStreamBasicDescription inputFormat;
|
AudioStreamBasicDescription inputFormat;
|
||||||
// Fill in the input format description from the stream.
|
|
||||||
AppleUtils::GetProperty(mStream,
|
mHaveOutput = false;
|
||||||
kAudioFileStreamProperty_DataFormat, &inputFormat);
|
|
||||||
|
nsresult rv = AppleUtils::GetRichestDecodableFormat(mStream, inputFormat);
|
||||||
|
if (NS_FAILED(rv)) {
|
||||||
|
mCallback->Error();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Fill in the output format manually.
|
// Fill in the output format manually.
|
||||||
PodZero(&mOutputFormat);
|
PodZero(&mOutputFormat);
|
||||||
@ -324,13 +330,13 @@ AppleATDecoder::SetupDecoder()
|
|||||||
mOutputFormat.mBytesPerPacket = mOutputFormat.mBytesPerFrame
|
mOutputFormat.mBytesPerPacket = mOutputFormat.mBytesPerFrame
|
||||||
= mOutputFormat.mChannelsPerFrame * mOutputFormat.mBitsPerChannel / 8;
|
= mOutputFormat.mChannelsPerFrame * mOutputFormat.mBitsPerChannel / 8;
|
||||||
|
|
||||||
OSStatus rv = AudioConverterNew(&inputFormat, &mOutputFormat, &mConverter);
|
OSStatus status =
|
||||||
if (rv) {
|
AudioConverterNew(&inputFormat, &mOutputFormat, &mConverter);
|
||||||
|
if (status) {
|
||||||
LOG("Error %d constructing AudioConverter", rv);
|
LOG("Error %d constructing AudioConverter", rv);
|
||||||
mConverter = nullptr;
|
mConverter = nullptr;
|
||||||
mCallback->Error();
|
mCallback->Error();
|
||||||
}
|
}
|
||||||
mHaveOutput = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -4,9 +4,9 @@
|
|||||||
|
|
||||||
// Utility functions to help with Apple API calls.
|
// Utility functions to help with Apple API calls.
|
||||||
|
|
||||||
#include <AudioToolbox/AudioToolbox.h>
|
|
||||||
#include "AppleUtils.h"
|
#include "AppleUtils.h"
|
||||||
#include "prlog.h"
|
#include "prlog.h"
|
||||||
|
#include "nsAutoPtr.h"
|
||||||
|
|
||||||
#ifdef PR_LOGGING
|
#ifdef PR_LOGGING
|
||||||
PRLogModuleInfo* GetDemuxerLog();
|
PRLogModuleInfo* GetDemuxerLog();
|
||||||
@ -26,12 +26,12 @@ namespace mozilla {
|
|||||||
nsresult
|
nsresult
|
||||||
AppleUtils::GetProperty(AudioFileStreamID aAudioFileStream,
|
AppleUtils::GetProperty(AudioFileStreamID aAudioFileStream,
|
||||||
AudioFileStreamPropertyID aPropertyID,
|
AudioFileStreamPropertyID aPropertyID,
|
||||||
void *aData)
|
void* aData)
|
||||||
{
|
{
|
||||||
UInt32 size;
|
UInt32 size;
|
||||||
Boolean writeable;
|
Boolean writeable;
|
||||||
OSStatus rv = AudioFileStreamGetPropertyInfo(aAudioFileStream, aPropertyID,
|
OSStatus rv = AudioFileStreamGetPropertyInfo(aAudioFileStream, aPropertyID,
|
||||||
&size, &writeable);
|
&size, &writeable);
|
||||||
|
|
||||||
if (rv) {
|
if (rv) {
|
||||||
WARN("Couldn't get property " PROPERTY_ID_FORMAT "\n",
|
WARN("Couldn't get property " PROPERTY_ID_FORMAT "\n",
|
||||||
@ -80,5 +80,52 @@ AppleUtils::SetCFDict(CFMutableDictionaryRef dict,
|
|||||||
CFDictionarySetValue(dict, keyRef, value ? kCFBooleanTrue : kCFBooleanFalse);
|
CFDictionarySetValue(dict, keyRef, value ? kCFBooleanTrue : kCFBooleanFalse);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
AppleUtils::GetRichestDecodableFormat(AudioFileStreamID aAudioFileStream,
|
||||||
|
AudioStreamBasicDescription& aFormat)
|
||||||
|
{
|
||||||
|
// Fill in the default format description from the stream.
|
||||||
|
nsresult rv = GetProperty(aAudioFileStream,
|
||||||
|
kAudioFileStreamProperty_DataFormat, &aFormat);
|
||||||
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
UInt32 propertySize;
|
||||||
|
OSStatus status = AudioFileStreamGetPropertyInfo(
|
||||||
|
aAudioFileStream, kAudioFileStreamProperty_FormatList, &propertySize, NULL);
|
||||||
|
if (NS_WARN_IF(status)) {
|
||||||
|
// Return the default format description.
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
MOZ_ASSERT(propertySize % sizeof(AudioFormatListItem) == 0);
|
||||||
|
uint32_t sizeList = propertySize / sizeof(AudioFormatListItem);
|
||||||
|
nsAutoArrayPtr<AudioFormatListItem> formatListPtr(
|
||||||
|
new AudioFormatListItem[sizeList]);
|
||||||
|
|
||||||
|
rv = GetProperty(aAudioFileStream, kAudioFileStreamProperty_FormatList,
|
||||||
|
formatListPtr);
|
||||||
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
|
// Return the default format description.
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the index number of the first playable format.
|
||||||
|
// This index number will be for the highest quality layer the platform
|
||||||
|
// is capable of playing.
|
||||||
|
UInt32 itemIndex;
|
||||||
|
UInt32 indexSize = sizeof(itemIndex);
|
||||||
|
status =
|
||||||
|
AudioFormatGetProperty(kAudioFormatProperty_FirstPlayableFormatFromList,
|
||||||
|
propertySize, formatListPtr, &indexSize, &itemIndex);
|
||||||
|
if (NS_WARN_IF(status)) {
|
||||||
|
// Return the default format description.
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
aFormat = formatListPtr[itemIndex].mASBD;
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
@ -16,7 +16,7 @@ struct AppleUtils {
|
|||||||
// Helper to retrieve properties from AudioFileStream objects.
|
// Helper to retrieve properties from AudioFileStream objects.
|
||||||
static nsresult GetProperty(AudioFileStreamID aAudioFileStream,
|
static nsresult GetProperty(AudioFileStreamID aAudioFileStream,
|
||||||
AudioFileStreamPropertyID aPropertyID,
|
AudioFileStreamPropertyID aPropertyID,
|
||||||
void *aData);
|
void* aData);
|
||||||
|
|
||||||
// Helper to set a string, string pair on a CFMutableDictionaryRef.
|
// Helper to set a string, string pair on a CFMutableDictionaryRef.
|
||||||
static void SetCFDict(CFMutableDictionaryRef dict,
|
static void SetCFDict(CFMutableDictionaryRef dict,
|
||||||
@ -30,6 +30,12 @@ struct AppleUtils {
|
|||||||
static void SetCFDict(CFMutableDictionaryRef dict,
|
static void SetCFDict(CFMutableDictionaryRef dict,
|
||||||
const char* key,
|
const char* key,
|
||||||
bool value);
|
bool value);
|
||||||
|
|
||||||
|
// Helper to retrieve the best audio format available in the given
|
||||||
|
// audio stream.
|
||||||
|
// The basic format will be returned by default should an error occur.
|
||||||
|
static nsresult GetRichestDecodableFormat(
|
||||||
|
AudioFileStreamID aAudioFileStream, AudioStreamBasicDescription& aFormat);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Wrapper class to call CFRelease on reference types
|
// Wrapper class to call CFRelease on reference types
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
#include "nsAutoRef.h"
|
#include "nsAutoRef.h"
|
||||||
#include "GMPParent.h"
|
#include "GMPParent.h"
|
||||||
#include "mozilla/gmp/GMPTypes.h"
|
#include "mozilla/gmp/GMPTypes.h"
|
||||||
|
#include "nsThread.h"
|
||||||
#include "nsThreadUtils.h"
|
#include "nsThreadUtils.h"
|
||||||
#include "runnable_utils.h"
|
#include "runnable_utils.h"
|
||||||
|
|
||||||
@ -72,7 +73,9 @@ GMPVideoEncoderParent::GMPVideoEncoderParent(GMPParent *aPlugin)
|
|||||||
|
|
||||||
GMPVideoEncoderParent::~GMPVideoEncoderParent()
|
GMPVideoEncoderParent::~GMPVideoEncoderParent()
|
||||||
{
|
{
|
||||||
mEncodedThread->Shutdown();
|
if (mEncodedThread) {
|
||||||
|
mEncodedThread->Shutdown();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GMPVideoHostImpl&
|
GMPVideoHostImpl&
|
||||||
@ -238,6 +241,12 @@ GMPVideoEncoderParent::Shutdown()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ShutdownEncodedThread(nsCOMPtr<nsIThread>& aThread)
|
||||||
|
{
|
||||||
|
aThread->Shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
// Note: Keep this sync'd up with Shutdown
|
// Note: Keep this sync'd up with Shutdown
|
||||||
void
|
void
|
||||||
GMPVideoEncoderParent::ActorDestroy(ActorDestroyReason aWhy)
|
GMPVideoEncoderParent::ActorDestroy(ActorDestroyReason aWhy)
|
||||||
@ -249,6 +258,15 @@ GMPVideoEncoderParent::ActorDestroy(ActorDestroyReason aWhy)
|
|||||||
mCallback->Terminated();
|
mCallback->Terminated();
|
||||||
mCallback = nullptr;
|
mCallback = nullptr;
|
||||||
}
|
}
|
||||||
|
// Must be shut down before VideoEncoderDestroyed(), since this can recurse
|
||||||
|
// the GMPThread event loop. See bug 1049501
|
||||||
|
if (mEncodedThread) {
|
||||||
|
// Can't get it to allow me to use WrapRunnable with a nsCOMPtr<nsIThread>()
|
||||||
|
NS_DispatchToMainThread(
|
||||||
|
WrapRunnableNM<decltype(&ShutdownEncodedThread),
|
||||||
|
nsCOMPtr<nsIThread> >(&ShutdownEncodedThread, mEncodedThread));
|
||||||
|
mEncodedThread = nullptr;
|
||||||
|
}
|
||||||
if (mPlugin) {
|
if (mPlugin) {
|
||||||
// Ignore any return code. It is OK for this to fail without killing the process.
|
// Ignore any return code. It is OK for this to fail without killing the process.
|
||||||
mPlugin->VideoEncoderDestroyed(this);
|
mPlugin->VideoEncoderDestroyed(this);
|
||||||
|
10
content/media/omx/AudioOffloadPlayer.cpp
Executable file → Normal file
10
content/media/omx/AudioOffloadPlayer.cpp
Executable file → Normal file
@ -21,6 +21,7 @@
|
|||||||
#include "nsComponentManagerUtils.h"
|
#include "nsComponentManagerUtils.h"
|
||||||
#include "nsITimer.h"
|
#include "nsITimer.h"
|
||||||
#include "mozilla/dom/HTMLMediaElement.h"
|
#include "mozilla/dom/HTMLMediaElement.h"
|
||||||
|
#include "VideoUtils.h"
|
||||||
|
|
||||||
#include <binder/IPCThreadState.h>
|
#include <binder/IPCThreadState.h>
|
||||||
#include <stagefright/foundation/ADebug.h>
|
#include <stagefright/foundation/ADebug.h>
|
||||||
@ -51,7 +52,7 @@ PRLogModuleInfo* gAudioOffloadPlayerLog;
|
|||||||
// When elapsed, the AudioSink is destroyed to allow the audio DSP to power down.
|
// When elapsed, the AudioSink is destroyed to allow the audio DSP to power down.
|
||||||
static const uint64_t OFFLOAD_PAUSE_MAX_MSECS = 60000ll;
|
static const uint64_t OFFLOAD_PAUSE_MAX_MSECS = 60000ll;
|
||||||
|
|
||||||
AudioOffloadPlayer::AudioOffloadPlayer(MediaOmxDecoder* aObserver) :
|
AudioOffloadPlayer::AudioOffloadPlayer(MediaOmxCommonDecoder* aObserver) :
|
||||||
mObserver(aObserver),
|
mObserver(aObserver),
|
||||||
mInputBuffer(nullptr),
|
mInputBuffer(nullptr),
|
||||||
mSampleRate(0),
|
mSampleRate(0),
|
||||||
@ -197,7 +198,8 @@ status_t AudioOffloadPlayer::ChangeState(MediaDecoder::PlayState aState)
|
|||||||
case MediaDecoder::PLAY_STATE_PAUSED:
|
case MediaDecoder::PLAY_STATE_PAUSED:
|
||||||
case MediaDecoder::PLAY_STATE_SHUTDOWN:
|
case MediaDecoder::PLAY_STATE_SHUTDOWN:
|
||||||
// Just pause here during play state shutdown as well to stop playing
|
// Just pause here during play state shutdown as well to stop playing
|
||||||
// offload track immediately. Resources will be freed by MediaOmxDecoder
|
// offload track immediately. Resources will be freed by
|
||||||
|
// MediaOmxCommonDecoder
|
||||||
Pause();
|
Pause();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -421,14 +423,14 @@ void AudioOffloadPlayer::NotifyAudioEOS()
|
|||||||
void AudioOffloadPlayer::NotifyPositionChanged()
|
void AudioOffloadPlayer::NotifyPositionChanged()
|
||||||
{
|
{
|
||||||
nsCOMPtr<nsIRunnable> nsEvent = NS_NewRunnableMethod(mObserver,
|
nsCOMPtr<nsIRunnable> nsEvent = NS_NewRunnableMethod(mObserver,
|
||||||
&MediaOmxDecoder::PlaybackPositionChanged);
|
&MediaOmxCommonDecoder::PlaybackPositionChanged);
|
||||||
NS_DispatchToMainThread(nsEvent);
|
NS_DispatchToMainThread(nsEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioOffloadPlayer::NotifyAudioTearDown()
|
void AudioOffloadPlayer::NotifyAudioTearDown()
|
||||||
{
|
{
|
||||||
nsCOMPtr<nsIRunnable> nsEvent = NS_NewRunnableMethod(mObserver,
|
nsCOMPtr<nsIRunnable> nsEvent = NS_NewRunnableMethod(mObserver,
|
||||||
&MediaOmxDecoder::AudioOffloadTearDown);
|
&MediaOmxCommonDecoder::AudioOffloadTearDown);
|
||||||
NS_DispatchToMainThread(nsEvent);
|
NS_DispatchToMainThread(nsEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
26
content/media/omx/AudioOffloadPlayer.h
Executable file → Normal file
26
content/media/omx/AudioOffloadPlayer.h
Executable file → Normal file
@ -27,14 +27,12 @@
|
|||||||
#include <utils/RefBase.h>
|
#include <utils/RefBase.h>
|
||||||
|
|
||||||
#include "AudioOutput.h"
|
#include "AudioOutput.h"
|
||||||
|
#include "AudioOffloadPlayerBase.h"
|
||||||
#include "MediaDecoderOwner.h"
|
#include "MediaDecoderOwner.h"
|
||||||
#include "MediaOmxDecoder.h"
|
#include "MediaOmxCommonDecoder.h"
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
|
|
||||||
class MediaOmxDecoder;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* AudioOffloadPlayer adds support for audio tunneling to a digital signal
|
* AudioOffloadPlayer adds support for audio tunneling to a digital signal
|
||||||
* processor (DSP) in the device chipset. With tunneling, audio decoding is
|
* processor (DSP) in the device chipset. With tunneling, audio decoding is
|
||||||
@ -47,11 +45,12 @@ class MediaOmxDecoder;
|
|||||||
* data, FillBuffer() will read data from compressed audio source and provide
|
* data, FillBuffer() will read data from compressed audio source and provide
|
||||||
* it to the sink
|
* it to the sink
|
||||||
*
|
*
|
||||||
* Also this class passes state changes (play/pause/seek) from MediaOmxDecoder
|
* Also this class passes state changes (play/pause/seek) from
|
||||||
* to AudioSink as well as provide AudioSink status (position changed,
|
* MediaOmxCommonDecoder to AudioSink as well as provide AudioSink status
|
||||||
* playback ended, seek complete, audio tear down) back to MediaOmxDecoder
|
* (position changed, playback ended, seek complete, audio tear down) back to
|
||||||
|
* MediaOmxCommonDecoder
|
||||||
*
|
*
|
||||||
* It acts as a bridge between MediaOmxDecoder and AudioSink during
|
* It acts as a bridge between MediaOmxCommonDecoder and AudioSink during
|
||||||
* offload playback
|
* offload playback
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -70,7 +69,7 @@ public:
|
|||||||
SEEK_COMPLETE
|
SEEK_COMPLETE
|
||||||
};
|
};
|
||||||
|
|
||||||
AudioOffloadPlayer(MediaOmxDecoder* aDecoder = nullptr);
|
AudioOffloadPlayer(MediaOmxCommonDecoder* aDecoder = nullptr);
|
||||||
|
|
||||||
~AudioOffloadPlayer();
|
~AudioOffloadPlayer();
|
||||||
|
|
||||||
@ -146,7 +145,8 @@ private:
|
|||||||
// relative to the seeked position. And seeked position may be slightly
|
// relative to the seeked position. And seeked position may be slightly
|
||||||
// different than given mSeekTimeUs, if audio source cannot find a frame at
|
// different than given mSeekTimeUs, if audio source cannot find a frame at
|
||||||
// that position. Store seeked position in mStartPosUs and provide
|
// that position. Store seeked position in mStartPosUs and provide
|
||||||
// mStartPosUs + GetPosition() (i.e. absolute position) to MediaOmxDecoder
|
// mStartPosUs + GetPosition() (i.e. absolute position) to
|
||||||
|
// MediaOmxCommonDecoder
|
||||||
// Used in main thread and offload callback thread, protected by Mutex
|
// Used in main thread and offload callback thread, protected by Mutex
|
||||||
// mLock
|
// mLock
|
||||||
int64_t mStartPosUs;
|
int64_t mStartPosUs;
|
||||||
@ -161,7 +161,7 @@ private:
|
|||||||
// mLock
|
// mLock
|
||||||
int64_t mPositionTimeMediaUs;
|
int64_t mPositionTimeMediaUs;
|
||||||
|
|
||||||
// State obtained from MediaOmxDecoder. Used only in main thread
|
// State obtained from MediaOmxCommonDecoder. Used only in main thread
|
||||||
MediaDecoder::PlayState mPlayState;
|
MediaDecoder::PlayState mPlayState;
|
||||||
|
|
||||||
// Protect accessing audio position related variables between main thread and
|
// Protect accessing audio position related variables between main thread and
|
||||||
@ -180,8 +180,8 @@ private:
|
|||||||
// Buffer used to get date from audio source. Used in offload callback thread
|
// Buffer used to get date from audio source. Used in offload callback thread
|
||||||
MediaBuffer* mInputBuffer;
|
MediaBuffer* mInputBuffer;
|
||||||
|
|
||||||
// MediaOmxDecoder object used mainly to notify the audio sink status
|
// MediaOmxCommonDecoder object used mainly to notify the audio sink status
|
||||||
MediaOmxDecoder* mObserver;
|
MediaOmxCommonDecoder* mObserver;
|
||||||
|
|
||||||
TimeStamp mLastFireUpdateTime;
|
TimeStamp mLastFireUpdateTime;
|
||||||
|
|
||||||
|
@ -20,13 +20,11 @@
|
|||||||
#ifndef AUDIO_OFFLOAD_PLAYER_BASE_H_
|
#ifndef AUDIO_OFFLOAD_PLAYER_BASE_H_
|
||||||
#define AUDIO_OFFLOAD_PLAYER_BASE_H_
|
#define AUDIO_OFFLOAD_PLAYER_BASE_H_
|
||||||
|
|
||||||
|
#include "MediaDecoder.h"
|
||||||
#include "MediaDecoderOwner.h"
|
#include "MediaDecoderOwner.h"
|
||||||
#include "MediaOmxDecoder.h"
|
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
|
|
||||||
class MediaOmxDecoder;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* AudioOffloadPlayer interface class which has funtions used by MediaOmxDecoder
|
* AudioOffloadPlayer interface class which has funtions used by MediaOmxDecoder
|
||||||
* This is to reduce the dependency of AudioOffloadPlayer in MediaOmxDecoder
|
* This is to reduce the dependency of AudioOffloadPlayer in MediaOmxDecoder
|
||||||
|
@ -5,6 +5,9 @@
|
|||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
#include "MediaCodecDecoder.h"
|
#include "MediaCodecDecoder.h"
|
||||||
|
|
||||||
|
#include <stagefright/MediaSource.h>
|
||||||
|
|
||||||
#include "MediaCodecReader.h"
|
#include "MediaCodecReader.h"
|
||||||
#include "MediaDecoderStateMachine.h"
|
#include "MediaDecoderStateMachine.h"
|
||||||
|
|
||||||
@ -16,10 +19,16 @@ MediaCodecDecoder::Clone()
|
|||||||
return new MediaCodecDecoder();
|
return new MediaCodecDecoder();
|
||||||
}
|
}
|
||||||
|
|
||||||
MediaDecoderStateMachine*
|
MediaOmxCommonReader*
|
||||||
MediaCodecDecoder::CreateStateMachine()
|
MediaCodecDecoder::CreateReader()
|
||||||
{
|
{
|
||||||
return new MediaDecoderStateMachine(this, new MediaCodecReader(this));
|
return new MediaCodecReader(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
MediaDecoderStateMachine*
|
||||||
|
MediaCodecDecoder::CreateStateMachine(MediaOmxCommonReader* aReader)
|
||||||
|
{
|
||||||
|
return new MediaDecoderStateMachine(this, aReader);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
@ -7,18 +7,20 @@
|
|||||||
#ifndef MEDIA_CODEC_DECODER_H
|
#ifndef MEDIA_CODEC_DECODER_H
|
||||||
#define MEDIA_CODEC_DECODER_H
|
#define MEDIA_CODEC_DECODER_H
|
||||||
|
|
||||||
#include "MediaDecoder.h"
|
#include "MediaOmxCommonDecoder.h"
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
|
|
||||||
// MediaDecoder that uses MediaCodecReader.
|
// MediaDecoder that uses MediaCodecReader.
|
||||||
class MediaCodecDecoder : public MediaDecoder
|
class MediaCodecDecoder : public MediaOmxCommonDecoder
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
virtual MediaDecoder* Clone();
|
virtual MediaDecoder* Clone();
|
||||||
|
|
||||||
virtual MediaDecoderStateMachine* CreateStateMachine();
|
virtual MediaOmxCommonReader* CreateReader();
|
||||||
|
|
||||||
|
virtual MediaDecoderStateMachine* CreateStateMachine(MediaOmxCommonReader* aReader);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
@ -106,7 +106,8 @@ MediaCodecReader::VideoResourceListener::codecCanceled()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MediaCodecReader::TrackInputCopier::Copy(MediaBuffer* aSourceBuffer, sp<ABuffer> aCodecBuffer)
|
bool
|
||||||
|
MediaCodecReader::TrackInputCopier::Copy(MediaBuffer* aSourceBuffer, sp<ABuffer> aCodecBuffer)
|
||||||
{
|
{
|
||||||
if (aSourceBuffer == nullptr ||
|
if (aSourceBuffer == nullptr ||
|
||||||
aCodecBuffer == nullptr ||
|
aCodecBuffer == nullptr ||
|
||||||
@ -132,7 +133,8 @@ MediaCodecReader::Track::Track()
|
|||||||
// Append the value of |kKeyValidSamples| to the end of each vorbis buffer.
|
// Append the value of |kKeyValidSamples| to the end of each vorbis buffer.
|
||||||
// https://github.com/mozilla-b2g/platform_frameworks_av/blob/master/media/libstagefright/OMXCodec.cpp#L3128
|
// https://github.com/mozilla-b2g/platform_frameworks_av/blob/master/media/libstagefright/OMXCodec.cpp#L3128
|
||||||
// https://github.com/mozilla-b2g/platform_frameworks_av/blob/master/media/libstagefright/NuMediaExtractor.cpp#L472
|
// https://github.com/mozilla-b2g/platform_frameworks_av/blob/master/media/libstagefright/NuMediaExtractor.cpp#L472
|
||||||
bool MediaCodecReader::VorbisInputCopier::Copy(MediaBuffer* aSourceBuffer, sp<ABuffer> aCodecBuffer)
|
bool
|
||||||
|
MediaCodecReader::VorbisInputCopier::Copy(MediaBuffer* aSourceBuffer, sp<ABuffer> aCodecBuffer)
|
||||||
{
|
{
|
||||||
if (aSourceBuffer == nullptr ||
|
if (aSourceBuffer == nullptr ||
|
||||||
aCodecBuffer == nullptr ||
|
aCodecBuffer == nullptr ||
|
||||||
@ -176,7 +178,7 @@ MediaCodecReader::CodecBufferInfo::CodecBufferInfo()
|
|||||||
}
|
}
|
||||||
|
|
||||||
MediaCodecReader::MediaCodecReader(AbstractMediaDecoder* aDecoder)
|
MediaCodecReader::MediaCodecReader(AbstractMediaDecoder* aDecoder)
|
||||||
: MediaDecoderReader(aDecoder)
|
: MediaOmxCommonReader(aDecoder)
|
||||||
, mColorConverterBufferSize(0)
|
, mColorConverterBufferSize(0)
|
||||||
{
|
{
|
||||||
mHandler = new MessageHandler(this);
|
mHandler = new MessageHandler(this);
|
||||||
@ -427,6 +429,10 @@ MediaCodecReader::ReadMetadata(MediaInfo* aInfo,
|
|||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef MOZ_AUDIO_OFFLOAD
|
||||||
|
CheckAudioOffload();
|
||||||
|
#endif
|
||||||
|
|
||||||
if (IsWaitingMediaResources()) {
|
if (IsWaitingMediaResources()) {
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
@ -524,6 +530,12 @@ MediaCodecReader::IsMediaSeekable()
|
|||||||
return (mExtractor != nullptr) && (mExtractor->flags() & MediaExtractor::CAN_SEEK);
|
return (mExtractor != nullptr) && (mExtractor->flags() & MediaExtractor::CAN_SEEK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
android::sp<android::MediaSource>
|
||||||
|
MediaCodecReader::GetAudioOffloadTrack()
|
||||||
|
{
|
||||||
|
return mAudioOffloadTrack.mSource;
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
MediaCodecReader::ReallocateResources()
|
MediaCodecReader::ReallocateResources()
|
||||||
{
|
{
|
||||||
@ -675,6 +687,8 @@ MediaCodecReader::CreateMediaSources()
|
|||||||
if (audioSource != nullptr && audioSource->start() == OK) {
|
if (audioSource != nullptr && audioSource->start() == OK) {
|
||||||
mAudioTrack.mSource = audioSource;
|
mAudioTrack.mSource = audioSource;
|
||||||
}
|
}
|
||||||
|
// Get one another track instance for audio offload playback.
|
||||||
|
mAudioOffloadTrack.mSource = mExtractor->getTrack(audioTrackIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (videoTrackIndex != invalidTrackIndex && mVideoTrack.mSource == nullptr) {
|
if (videoTrackIndex != invalidTrackIndex && mVideoTrack.mSource == nullptr) {
|
||||||
@ -694,6 +708,7 @@ MediaCodecReader::DestroyMediaSources()
|
|||||||
{
|
{
|
||||||
mAudioTrack.mSource = nullptr;
|
mAudioTrack.mSource = nullptr;
|
||||||
mVideoTrack.mSource = nullptr;
|
mVideoTrack.mSource = nullptr;
|
||||||
|
mAudioOffloadTrack.mSource = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
@ -1227,8 +1242,6 @@ MediaCodecReader::onMessageReceived(const sp<AMessage> &aMessage)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
TRESPASS();
|
TRESPASS();
|
||||||
break;
|
break;
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
|
|
||||||
#include "I420ColorConverterHelper.h"
|
#include "I420ColorConverterHelper.h"
|
||||||
#include "MediaCodecProxy.h"
|
#include "MediaCodecProxy.h"
|
||||||
#include "MediaDecoderReader.h"
|
#include "MediaOmxCommonReader.h"
|
||||||
|
|
||||||
namespace android {
|
namespace android {
|
||||||
struct ALooper;
|
struct ALooper;
|
||||||
@ -29,7 +29,7 @@ struct MediaCodec;
|
|||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
|
|
||||||
class MediaCodecReader : public MediaDecoderReader
|
class MediaCodecReader : public MediaOmxCommonReader
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
MediaCodecReader(AbstractMediaDecoder* aDecoder);
|
MediaCodecReader(AbstractMediaDecoder* aDecoder);
|
||||||
@ -85,6 +85,8 @@ public:
|
|||||||
|
|
||||||
virtual bool IsMediaSeekable() MOZ_OVERRIDE;
|
virtual bool IsMediaSeekable() MOZ_OVERRIDE;
|
||||||
|
|
||||||
|
virtual android::sp<android::MediaSource> GetAudioOffloadTrack();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
struct TrackInputCopier
|
struct TrackInputCopier
|
||||||
{
|
{
|
||||||
@ -249,9 +251,10 @@ private:
|
|||||||
android::sp<android::ALooper> mLooper;
|
android::sp<android::ALooper> mLooper;
|
||||||
android::sp<android::MediaExtractor> mExtractor;
|
android::sp<android::MediaExtractor> mExtractor;
|
||||||
|
|
||||||
// media elements
|
// media tracks
|
||||||
AudioTrack mAudioTrack;
|
AudioTrack mAudioTrack;
|
||||||
VideoTrack mVideoTrack;
|
VideoTrack mVideoTrack;
|
||||||
|
AudioTrack mAudioOffloadTrack; // only Track::mSource is valid
|
||||||
|
|
||||||
// color converter
|
// color converter
|
||||||
android::I420ColorConverterHelper mColorConverter;
|
android::I420ColorConverterHelper mColorConverter;
|
||||||
|
264
content/media/omx/MediaOmxCommonDecoder.cpp
Normal file
264
content/media/omx/MediaOmxCommonDecoder.cpp
Normal file
@ -0,0 +1,264 @@
|
|||||||
|
/* -*- 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 "MediaOmxCommonDecoder.h"
|
||||||
|
|
||||||
|
#include <stagefright/MediaSource.h>
|
||||||
|
|
||||||
|
#include "AudioOffloadPlayerBase.h"
|
||||||
|
#include "MediaDecoderStateMachine.h"
|
||||||
|
#include "MediaOmxCommonReader.h"
|
||||||
|
|
||||||
|
#ifdef MOZ_AUDIO_OFFLOAD
|
||||||
|
#include "AudioOffloadPlayer.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
using namespace android;
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
|
||||||
|
#ifdef PR_LOGGING
|
||||||
|
extern PRLogModuleInfo* gMediaDecoderLog;
|
||||||
|
#define DECODER_LOG(type, msg) PR_LOG(gMediaDecoderLog, type, msg)
|
||||||
|
#else
|
||||||
|
#define DECODER_LOG(type, msg)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
MediaOmxCommonDecoder::MediaOmxCommonDecoder()
|
||||||
|
: MediaDecoder()
|
||||||
|
, mReader(nullptr)
|
||||||
|
, mCanOffloadAudio(false)
|
||||||
|
, mFallbackToStateMachine(false)
|
||||||
|
{
|
||||||
|
#ifdef PR_LOGGING
|
||||||
|
if (!gMediaDecoderLog) {
|
||||||
|
gMediaDecoderLog = PR_NewLogModule("MediaDecoder");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MediaOmxCommonDecoder::SetCanOffloadAudio(bool aCanOffloadAudio)
|
||||||
|
{
|
||||||
|
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
|
||||||
|
mCanOffloadAudio = aCanOffloadAudio;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MediaOmxCommonDecoder::MetadataLoaded(MediaInfo* aInfo,
|
||||||
|
MetadataTags* aTags)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
MediaDecoder::MetadataLoaded(aInfo, aTags);
|
||||||
|
|
||||||
|
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
|
||||||
|
if (!mCanOffloadAudio || mFallbackToStateMachine || mOutputStreams.Length() ||
|
||||||
|
mInitialPlaybackRate != 1.0) {
|
||||||
|
DECODER_LOG(PR_LOG_DEBUG, ("In %s Offload Audio check failed",
|
||||||
|
__PRETTY_FUNCTION__));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef MOZ_AUDIO_OFFLOAD
|
||||||
|
mAudioOffloadPlayer = new AudioOffloadPlayer(this);
|
||||||
|
#endif
|
||||||
|
if (!mAudioOffloadPlayer) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mAudioOffloadPlayer->SetSource(mReader->GetAudioOffloadTrack());
|
||||||
|
status_t err = mAudioOffloadPlayer->Start(false);
|
||||||
|
if (err == OK) {
|
||||||
|
PauseStateMachine();
|
||||||
|
// Call ChangeState() to run AudioOffloadPlayer since offload state enabled
|
||||||
|
ChangeState(mPlayState);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mAudioOffloadPlayer = nullptr;
|
||||||
|
DECODER_LOG(PR_LOG_DEBUG, ("In %s Unable to start offload audio %d."
|
||||||
|
"Switching to normal mode", __PRETTY_FUNCTION__, err));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MediaOmxCommonDecoder::PauseStateMachine()
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
GetReentrantMonitor().AssertCurrentThreadIn();
|
||||||
|
DECODER_LOG(PR_LOG_DEBUG, ("%s", __PRETTY_FUNCTION__));
|
||||||
|
if (!mDecoderStateMachine) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
StopProgress();
|
||||||
|
mDecoderStateMachine->SetDormant(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MediaOmxCommonDecoder::ResumeStateMachine()
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
|
||||||
|
DECODER_LOG(PR_LOG_DEBUG, ("%s current time %f", __PRETTY_FUNCTION__,
|
||||||
|
mCurrentTime));
|
||||||
|
|
||||||
|
if (!mDecoderStateMachine) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mFallbackToStateMachine = true;
|
||||||
|
mAudioOffloadPlayer = nullptr;
|
||||||
|
int64_t timeUsecs = 0;
|
||||||
|
SecondsToUsecs(mCurrentTime, timeUsecs);
|
||||||
|
mRequestedSeekTarget = SeekTarget(timeUsecs, SeekTarget::Accurate);
|
||||||
|
|
||||||
|
mNextState = mPlayState;
|
||||||
|
ChangeState(PLAY_STATE_LOADING);
|
||||||
|
mDecoderStateMachine->SetDormant(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MediaOmxCommonDecoder::AudioOffloadTearDown()
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
DECODER_LOG(PR_LOG_DEBUG, ("%s", __PRETTY_FUNCTION__));
|
||||||
|
|
||||||
|
// mAudioOffloadPlayer can be null here if ResumeStateMachine was called
|
||||||
|
// just before because of some other error.
|
||||||
|
if (mAudioOffloadPlayer) {
|
||||||
|
// Audio offload player sent tear down event. Fallback to state machine
|
||||||
|
PlaybackPositionChanged();
|
||||||
|
ResumeStateMachine();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MediaOmxCommonDecoder::AddOutputStream(ProcessedMediaStream* aStream,
|
||||||
|
bool aFinishWhenEnded)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
|
||||||
|
if (mAudioOffloadPlayer) {
|
||||||
|
// Offload player cannot handle MediaStream. Fallback
|
||||||
|
PlaybackPositionChanged();
|
||||||
|
ResumeStateMachine();
|
||||||
|
}
|
||||||
|
|
||||||
|
MediaDecoder::AddOutputStream(aStream, aFinishWhenEnded);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MediaOmxCommonDecoder::SetPlaybackRate(double aPlaybackRate)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
|
||||||
|
if (mAudioOffloadPlayer &&
|
||||||
|
((aPlaybackRate != 0.0) || (aPlaybackRate != 1.0))) {
|
||||||
|
// Offload player cannot handle playback rate other than 1/0. Fallback
|
||||||
|
PlaybackPositionChanged();
|
||||||
|
ResumeStateMachine();
|
||||||
|
}
|
||||||
|
|
||||||
|
MediaDecoder::SetPlaybackRate(aPlaybackRate);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MediaOmxCommonDecoder::ChangeState(PlayState aState)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
// Keep MediaDecoder state in sync with MediaElement irrespective of offload
|
||||||
|
// playback so it will continue to work in normal mode when offloading fails
|
||||||
|
// in between
|
||||||
|
MediaDecoder::ChangeState(aState);
|
||||||
|
|
||||||
|
if (mAudioOffloadPlayer) {
|
||||||
|
status_t err = mAudioOffloadPlayer->ChangeState(aState);
|
||||||
|
if (err != OK) {
|
||||||
|
ResumeStateMachine();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MediaOmxCommonDecoder::ApplyStateToStateMachine(PlayState aState)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
// During offload playback, state machine should be in dormant state.
|
||||||
|
// ApplyStateToStateMachine() can change state machine state to
|
||||||
|
// something else or reset the seek time. So don't call this when audio is
|
||||||
|
// offloaded
|
||||||
|
if (!mAudioOffloadPlayer) {
|
||||||
|
MediaDecoder::ApplyStateToStateMachine(aState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MediaOmxCommonDecoder::PlaybackPositionChanged()
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
if (!mAudioOffloadPlayer) {
|
||||||
|
MediaDecoder::PlaybackPositionChanged();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mOwner || mShuttingDown) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
double lastTime = mCurrentTime;
|
||||||
|
{
|
||||||
|
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
|
||||||
|
mCurrentTime = mAudioOffloadPlayer->GetMediaTimeSecs();
|
||||||
|
}
|
||||||
|
if (mOwner && lastTime != mCurrentTime) {
|
||||||
|
FireTimeUpdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MediaOmxCommonDecoder::SetElementVisibility(bool aIsVisible)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
if (mAudioOffloadPlayer) {
|
||||||
|
mAudioOffloadPlayer->SetElementVisibility(aIsVisible);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MediaOmxCommonDecoder::UpdateReadyStateForData()
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
if (!mAudioOffloadPlayer) {
|
||||||
|
MediaDecoder::UpdateReadyStateForData();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mOwner || mShuttingDown)
|
||||||
|
return;
|
||||||
|
mOwner->UpdateReadyStateForData(mAudioOffloadPlayer->GetNextFrameStatus());
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MediaOmxCommonDecoder::SetVolume(double aVolume)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
if (!mAudioOffloadPlayer) {
|
||||||
|
MediaDecoder::SetVolume(aVolume);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mAudioOffloadPlayer->SetVolume(aVolume);
|
||||||
|
}
|
||||||
|
|
||||||
|
MediaDecoderStateMachine*
|
||||||
|
MediaOmxCommonDecoder::CreateStateMachine()
|
||||||
|
{
|
||||||
|
mReader = CreateReader();
|
||||||
|
if (mReader != nullptr) {
|
||||||
|
mReader->SetAudioChannel(GetAudioChannel());
|
||||||
|
}
|
||||||
|
return CreateStateMachine(mReader);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace mozilla
|
67
content/media/omx/MediaOmxCommonDecoder.h
Normal file
67
content/media/omx/MediaOmxCommonDecoder.h
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
/* -*- 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/. */
|
||||||
|
|
||||||
|
#ifndef MEDIA_OMX_COMMON_DECODER_H
|
||||||
|
#define MEDIA_OMX_COMMON_DECODER_H
|
||||||
|
|
||||||
|
#include "MediaDecoder.h"
|
||||||
|
|
||||||
|
namespace android {
|
||||||
|
struct MOZ_EXPORT MediaSource;
|
||||||
|
} // namespace android
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
|
||||||
|
class AudioOffloadPlayerBase;
|
||||||
|
class MediaOmxCommonReader;
|
||||||
|
|
||||||
|
class MediaOmxCommonDecoder : public MediaDecoder
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MediaOmxCommonDecoder();
|
||||||
|
|
||||||
|
virtual void MetadataLoaded(MediaInfo* aInfo,
|
||||||
|
MetadataTags* aTags);
|
||||||
|
virtual void ChangeState(PlayState aState);
|
||||||
|
virtual void ApplyStateToStateMachine(PlayState aState);
|
||||||
|
virtual void SetVolume(double aVolume);
|
||||||
|
virtual void PlaybackPositionChanged();
|
||||||
|
virtual void UpdateReadyStateForData();
|
||||||
|
virtual void SetElementVisibility(bool aIsVisible);
|
||||||
|
virtual void SetCanOffloadAudio(bool aCanOffloadAudio);
|
||||||
|
virtual void AddOutputStream(ProcessedMediaStream* aStream,
|
||||||
|
bool aFinishWhenEnded);
|
||||||
|
virtual void SetPlaybackRate(double aPlaybackRate);
|
||||||
|
|
||||||
|
void AudioOffloadTearDown();
|
||||||
|
|
||||||
|
virtual MediaDecoderStateMachine* CreateStateMachine();
|
||||||
|
|
||||||
|
virtual MediaOmxCommonReader* CreateReader() = 0;
|
||||||
|
virtual MediaDecoderStateMachine* CreateStateMachine(MediaOmxCommonReader* aReader) = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void PauseStateMachine();
|
||||||
|
void ResumeStateMachine();
|
||||||
|
|
||||||
|
MediaOmxCommonReader* mReader;
|
||||||
|
|
||||||
|
// Offloaded audio track
|
||||||
|
android::sp<android::MediaSource> mAudioTrack;
|
||||||
|
|
||||||
|
nsAutoPtr<AudioOffloadPlayerBase> mAudioOffloadPlayer;
|
||||||
|
|
||||||
|
// Set by Media*Reader to denote current track can be offloaded
|
||||||
|
bool mCanOffloadAudio;
|
||||||
|
|
||||||
|
// Set when offload playback of current track fails in the middle and need to
|
||||||
|
// fallback to state machine
|
||||||
|
bool mFallbackToStateMachine;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace mozilla
|
||||||
|
|
||||||
|
#endif // MEDIA_OMX_COMMON_DECODER_H
|
81
content/media/omx/MediaOmxCommonReader.cpp
Normal file
81
content/media/omx/MediaOmxCommonReader.cpp
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
/* -*- 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 "MediaOmxCommonReader.h"
|
||||||
|
|
||||||
|
#include <stagefright/MediaSource.h>
|
||||||
|
|
||||||
|
#include "AbstractMediaDecoder.h"
|
||||||
|
#include "AudioChannelService.h"
|
||||||
|
#include "MediaStreamSource.h"
|
||||||
|
|
||||||
|
#ifdef MOZ_AUDIO_OFFLOAD
|
||||||
|
#include <stagefright/Utils.h>
|
||||||
|
#include <cutils/properties.h>
|
||||||
|
#include <stagefright/MetaData.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
using namespace android;
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
|
||||||
|
#ifdef PR_LOGGING
|
||||||
|
extern PRLogModuleInfo* gMediaDecoderLog;
|
||||||
|
#define DECODER_LOG(type, msg) PR_LOG(gMediaDecoderLog, type, msg)
|
||||||
|
#else
|
||||||
|
#define DECODER_LOG(type, msg)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
MediaOmxCommonReader::MediaOmxCommonReader(AbstractMediaDecoder *aDecoder)
|
||||||
|
: MediaDecoderReader(aDecoder)
|
||||||
|
{
|
||||||
|
#ifdef PR_LOGGING
|
||||||
|
if (!gMediaDecoderLog) {
|
||||||
|
gMediaDecoderLog = PR_NewLogModule("MediaDecoder");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
mAudioChannel = dom::AudioChannelService::GetDefaultAudioChannel();
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef MOZ_AUDIO_OFFLOAD
|
||||||
|
void MediaOmxCommonReader::CheckAudioOffload()
|
||||||
|
{
|
||||||
|
NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
|
||||||
|
|
||||||
|
char offloadProp[128];
|
||||||
|
property_get("audio.offload.disable", offloadProp, "0");
|
||||||
|
bool offloadDisable = atoi(offloadProp) != 0;
|
||||||
|
if (offloadDisable) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sp<MediaSource> audioOffloadTrack = GetAudioOffloadTrack();
|
||||||
|
sp<MetaData> meta = audioOffloadTrack.get()
|
||||||
|
? audioOffloadTrack->getFormat() : nullptr;
|
||||||
|
|
||||||
|
// Supporting audio offload only when there is no video, no streaming
|
||||||
|
bool hasNoVideo = !HasVideo();
|
||||||
|
bool isNotStreaming
|
||||||
|
= mDecoder->GetResource()->IsDataCachedToEndOfResource(0);
|
||||||
|
|
||||||
|
// Not much benefit in trying to offload other channel types. Most of them
|
||||||
|
// aren't supported and also duration would be less than a minute
|
||||||
|
bool isTypeMusic = mAudioChannel == dom::AudioChannel::Content;
|
||||||
|
|
||||||
|
DECODER_LOG(PR_LOG_DEBUG, ("%s meta %p, no video %d, no streaming %d,"
|
||||||
|
" channel type %d", __FUNCTION__, meta.get(), hasNoVideo,
|
||||||
|
isNotStreaming, mAudioChannel));
|
||||||
|
|
||||||
|
if ((meta.get()) && hasNoVideo && isNotStreaming && isTypeMusic &&
|
||||||
|
canOffloadStream(meta, false, false, AUDIO_STREAM_MUSIC)) {
|
||||||
|
DECODER_LOG(PR_LOG_DEBUG, ("Can offload this audio stream"));
|
||||||
|
mDecoder->SetCanOffloadAudio(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // namespace mozilla
|
48
content/media/omx/MediaOmxCommonReader.h
Normal file
48
content/media/omx/MediaOmxCommonReader.h
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
/* -*- 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/. */
|
||||||
|
|
||||||
|
#ifndef MEDIA_OMX_COMMON_READER_H
|
||||||
|
#define MEDIA_OMX_COMMON_READER_H
|
||||||
|
|
||||||
|
#include "MediaDecoderReader.h"
|
||||||
|
|
||||||
|
#include <utils/RefBase.h>
|
||||||
|
|
||||||
|
#include "mozilla/dom/AudioChannelBinding.h"
|
||||||
|
|
||||||
|
namespace android {
|
||||||
|
struct MOZ_EXPORT MediaSource;
|
||||||
|
} // namespace android
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
|
||||||
|
class AbstractMediaDecoder;
|
||||||
|
|
||||||
|
class MediaOmxCommonReader : public MediaDecoderReader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MediaOmxCommonReader(AbstractMediaDecoder* aDecoder);
|
||||||
|
|
||||||
|
void SetAudioChannel(dom::AudioChannel aAudioChannel) {
|
||||||
|
mAudioChannel = aAudioChannel;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual android::sp<android::MediaSource> GetAudioOffloadTrack() = 0;
|
||||||
|
|
||||||
|
#ifdef MOZ_AUDIO_OFFLOAD
|
||||||
|
// Check whether it is possible to offload current audio track. This access
|
||||||
|
// canOffloadStream() from libStageFright Utils.cpp, which is not there in
|
||||||
|
// ANDROID_VERSION < 19
|
||||||
|
void CheckAudioOffload();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
protected:
|
||||||
|
dom::AudioChannel mAudioChannel;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace mozilla
|
||||||
|
|
||||||
|
#endif // MEDIA_OMX_COMMON_READER_H
|
230
content/media/omx/MediaOmxDecoder.cpp
Executable file → Normal file
230
content/media/omx/MediaOmxDecoder.cpp
Executable file → Normal file
@ -7,241 +7,27 @@
|
|||||||
#include "MediaOmxDecoder.h"
|
#include "MediaOmxDecoder.h"
|
||||||
#include "MediaOmxReader.h"
|
#include "MediaOmxReader.h"
|
||||||
#include "MediaDecoderStateMachine.h"
|
#include "MediaDecoderStateMachine.h"
|
||||||
#include "VideoUtils.h"
|
|
||||||
|
|
||||||
#include "OmxDecoder.h"
|
|
||||||
|
|
||||||
#ifdef MOZ_AUDIO_OFFLOAD
|
|
||||||
#include "AudioOffloadPlayer.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
using namespace android;
|
using namespace android;
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
|
|
||||||
#ifdef PR_LOGGING
|
MediaDecoder*
|
||||||
extern PRLogModuleInfo* gMediaDecoderLog;
|
MediaOmxDecoder::Clone()
|
||||||
#define DECODER_LOG(type, msg) PR_LOG(gMediaDecoderLog, type, msg)
|
|
||||||
#else
|
|
||||||
#define DECODER_LOG(type, msg)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
MediaOmxDecoder::MediaOmxDecoder() :
|
|
||||||
MediaDecoder(),
|
|
||||||
mCanOffloadAudio(false),
|
|
||||||
mFallbackToStateMachine(false)
|
|
||||||
{
|
|
||||||
#ifdef PR_LOGGING
|
|
||||||
if (!gMediaDecoderLog) {
|
|
||||||
gMediaDecoderLog = PR_NewLogModule("MediaDecoder");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
MediaDecoder* MediaOmxDecoder::Clone()
|
|
||||||
{
|
{
|
||||||
return new MediaOmxDecoder();
|
return new MediaOmxDecoder();
|
||||||
}
|
}
|
||||||
|
|
||||||
MediaDecoderStateMachine* MediaOmxDecoder::CreateStateMachine()
|
MediaOmxCommonReader*
|
||||||
|
MediaOmxDecoder::CreateReader()
|
||||||
{
|
{
|
||||||
mReader = new MediaOmxReader(this);
|
return new MediaOmxReader(this);
|
||||||
mReader->SetAudioChannel(GetAudioChannel());
|
|
||||||
return new MediaDecoderStateMachine(this, mReader);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MediaOmxDecoder::SetCanOffloadAudio(bool aCanOffloadAudio)
|
MediaDecoderStateMachine*
|
||||||
|
MediaOmxDecoder::CreateStateMachine(MediaOmxCommonReader* aReader)
|
||||||
{
|
{
|
||||||
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
|
return new MediaDecoderStateMachine(this, aReader);
|
||||||
mCanOffloadAudio = aCanOffloadAudio;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MediaOmxDecoder::MetadataLoaded(MediaInfo* aInfo,
|
|
||||||
MetadataTags* aTags)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
|
||||||
MediaDecoder::MetadataLoaded(aInfo, aTags);
|
|
||||||
|
|
||||||
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
|
|
||||||
if (!mCanOffloadAudio || mFallbackToStateMachine || mOutputStreams.Length() ||
|
|
||||||
mInitialPlaybackRate != 1.0) {
|
|
||||||
DECODER_LOG(PR_LOG_DEBUG, ("In %s Offload Audio check failed",
|
|
||||||
__PRETTY_FUNCTION__));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef MOZ_AUDIO_OFFLOAD
|
|
||||||
mAudioOffloadPlayer = new AudioOffloadPlayer(this);
|
|
||||||
#endif
|
|
||||||
mAudioOffloadPlayer->SetSource(mReader->GetAudioOffloadTrack());
|
|
||||||
status_t err = mAudioOffloadPlayer->Start(false);
|
|
||||||
if (err == OK) {
|
|
||||||
PauseStateMachine();
|
|
||||||
// Call ChangeState() to run AudioOffloadPlayer since offload state enabled
|
|
||||||
ChangeState(mPlayState);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
mAudioOffloadPlayer = nullptr;
|
|
||||||
DECODER_LOG(PR_LOG_DEBUG, ("In %s Unable to start offload audio %d."
|
|
||||||
"Switching to normal mode", __PRETTY_FUNCTION__, err));
|
|
||||||
}
|
|
||||||
|
|
||||||
void MediaOmxDecoder::PauseStateMachine()
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
|
||||||
GetReentrantMonitor().AssertCurrentThreadIn();
|
|
||||||
DECODER_LOG(PR_LOG_DEBUG, ("%s", __PRETTY_FUNCTION__));
|
|
||||||
if (!mDecoderStateMachine) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
StopProgress();
|
|
||||||
mDecoderStateMachine->SetDormant(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MediaOmxDecoder::ResumeStateMachine()
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
|
||||||
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
|
|
||||||
DECODER_LOG(PR_LOG_DEBUG, ("%s current time %f", __PRETTY_FUNCTION__,
|
|
||||||
mCurrentTime));
|
|
||||||
|
|
||||||
if (!mDecoderStateMachine) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
mFallbackToStateMachine = true;
|
|
||||||
mAudioOffloadPlayer = nullptr;
|
|
||||||
int64_t timeUsecs = 0;
|
|
||||||
SecondsToUsecs(mCurrentTime, timeUsecs);
|
|
||||||
mRequestedSeekTarget = SeekTarget(timeUsecs, SeekTarget::Accurate);
|
|
||||||
|
|
||||||
mNextState = mPlayState;
|
|
||||||
ChangeState(PLAY_STATE_LOADING);
|
|
||||||
mDecoderStateMachine->SetDormant(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MediaOmxDecoder::AudioOffloadTearDown()
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
|
||||||
DECODER_LOG(PR_LOG_DEBUG, ("%s", __PRETTY_FUNCTION__));
|
|
||||||
|
|
||||||
// mAudioOffloadPlayer can be null here if ResumeStateMachine was called
|
|
||||||
// just before because of some other error.
|
|
||||||
if (mAudioOffloadPlayer) {
|
|
||||||
// Audio offload player sent tear down event. Fallback to state machine
|
|
||||||
PlaybackPositionChanged();
|
|
||||||
ResumeStateMachine();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MediaOmxDecoder::AddOutputStream(ProcessedMediaStream* aStream,
|
|
||||||
bool aFinishWhenEnded)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
|
||||||
|
|
||||||
if (mAudioOffloadPlayer) {
|
|
||||||
// Offload player cannot handle MediaStream. Fallback
|
|
||||||
PlaybackPositionChanged();
|
|
||||||
ResumeStateMachine();
|
|
||||||
}
|
|
||||||
|
|
||||||
MediaDecoder::AddOutputStream(aStream, aFinishWhenEnded);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MediaOmxDecoder::SetPlaybackRate(double aPlaybackRate)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
|
||||||
|
|
||||||
if (mAudioOffloadPlayer &&
|
|
||||||
((aPlaybackRate != 0.0) || (aPlaybackRate != 1.0))) {
|
|
||||||
// Offload player cannot handle playback rate other than 1/0. Fallback
|
|
||||||
PlaybackPositionChanged();
|
|
||||||
ResumeStateMachine();
|
|
||||||
}
|
|
||||||
|
|
||||||
MediaDecoder::SetPlaybackRate(aPlaybackRate);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MediaOmxDecoder::ChangeState(PlayState aState)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
|
||||||
// Keep MediaDecoder state in sync with MediaElement irrespective of offload
|
|
||||||
// playback so it will continue to work in normal mode when offloading fails
|
|
||||||
// in between
|
|
||||||
MediaDecoder::ChangeState(aState);
|
|
||||||
|
|
||||||
if (mAudioOffloadPlayer) {
|
|
||||||
status_t err = mAudioOffloadPlayer->ChangeState(aState);
|
|
||||||
if (err != OK) {
|
|
||||||
ResumeStateMachine();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MediaOmxDecoder::ApplyStateToStateMachine(PlayState aState)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
|
||||||
// During offload playback, state machine should be in dormant state.
|
|
||||||
// ApplyStateToStateMachine() can change state machine state to
|
|
||||||
// something else or reset the seek time. So don't call this when audio is
|
|
||||||
// offloaded
|
|
||||||
if (!mAudioOffloadPlayer) {
|
|
||||||
MediaDecoder::ApplyStateToStateMachine(aState);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MediaOmxDecoder::PlaybackPositionChanged()
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
|
||||||
if (!mAudioOffloadPlayer) {
|
|
||||||
MediaDecoder::PlaybackPositionChanged();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!mOwner || mShuttingDown) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
double lastTime = mCurrentTime;
|
|
||||||
{
|
|
||||||
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
|
|
||||||
mCurrentTime = mAudioOffloadPlayer->GetMediaTimeSecs();
|
|
||||||
}
|
|
||||||
if (mOwner && lastTime != mCurrentTime) {
|
|
||||||
FireTimeUpdate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MediaOmxDecoder::SetElementVisibility(bool aIsVisible)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
|
||||||
if (mAudioOffloadPlayer) {
|
|
||||||
mAudioOffloadPlayer->SetElementVisibility(aIsVisible);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MediaOmxDecoder::UpdateReadyStateForData()
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
|
||||||
if (!mAudioOffloadPlayer) {
|
|
||||||
MediaDecoder::UpdateReadyStateForData();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!mOwner || mShuttingDown)
|
|
||||||
return;
|
|
||||||
mOwner->UpdateReadyStateForData(mAudioOffloadPlayer->GetNextFrameStatus());
|
|
||||||
}
|
|
||||||
|
|
||||||
void MediaOmxDecoder::SetVolume(double aVolume)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
|
||||||
if (!mAudioOffloadPlayer) {
|
|
||||||
MediaDecoder::SetVolume(aVolume);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
mAudioOffloadPlayer->SetVolume(aVolume);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
47
content/media/omx/MediaOmxDecoder.h
Executable file → Normal file
47
content/media/omx/MediaOmxDecoder.h
Executable file → Normal file
@ -6,55 +6,16 @@
|
|||||||
#if !defined(MediaOmxDecoder_h_)
|
#if !defined(MediaOmxDecoder_h_)
|
||||||
#define MediaOmxDecoder_h_
|
#define MediaOmxDecoder_h_
|
||||||
|
|
||||||
#include "base/basictypes.h"
|
#include "MediaOmxCommonDecoder.h"
|
||||||
#include "MediaDecoder.h"
|
|
||||||
#include "MediaOmxReader.h"
|
|
||||||
#include "AudioOffloadPlayerBase.h"
|
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
|
|
||||||
class MediaOmxDecoder : public MediaDecoder
|
class MediaOmxDecoder : public MediaOmxCommonDecoder
|
||||||
{
|
{
|
||||||
typedef android::MediaSource MediaSource;
|
|
||||||
public:
|
public:
|
||||||
MediaOmxDecoder();
|
|
||||||
virtual MediaDecoder* Clone();
|
virtual MediaDecoder* Clone();
|
||||||
virtual MediaDecoderStateMachine* CreateStateMachine();
|
virtual MediaOmxCommonReader* CreateReader();
|
||||||
|
virtual MediaDecoderStateMachine* CreateStateMachine(MediaOmxCommonReader* aReader);
|
||||||
virtual void MetadataLoaded(MediaInfo* aInfo,
|
|
||||||
MetadataTags* aTags);
|
|
||||||
virtual void ChangeState(PlayState aState);
|
|
||||||
virtual void ApplyStateToStateMachine(PlayState aState);
|
|
||||||
virtual void SetVolume(double aVolume);
|
|
||||||
virtual void PlaybackPositionChanged();
|
|
||||||
virtual void UpdateReadyStateForData();
|
|
||||||
virtual void SetElementVisibility(bool aIsVisible);
|
|
||||||
virtual void SetCanOffloadAudio(bool aCanOffloadAudio);
|
|
||||||
virtual void AddOutputStream(ProcessedMediaStream* aStream,
|
|
||||||
bool aFinishWhenEnded);
|
|
||||||
virtual void SetPlaybackRate(double aPlaybackRate);
|
|
||||||
|
|
||||||
void AudioOffloadTearDown();
|
|
||||||
int64_t GetSeekTime() { return mRequestedSeekTarget.mTime; }
|
|
||||||
void ResetSeekTime() { mRequestedSeekTarget.Reset(); }
|
|
||||||
|
|
||||||
private:
|
|
||||||
void PauseStateMachine();
|
|
||||||
void ResumeStateMachine();
|
|
||||||
|
|
||||||
MediaOmxReader* mReader;
|
|
||||||
|
|
||||||
// Offloaded audio track
|
|
||||||
android::sp<MediaSource> mAudioTrack;
|
|
||||||
|
|
||||||
nsAutoPtr<AudioOffloadPlayerBase> mAudioOffloadPlayer;
|
|
||||||
|
|
||||||
// Set by MediaOmxReader to denote current track can be offloaded
|
|
||||||
bool mCanOffloadAudio;
|
|
||||||
|
|
||||||
// Set when offload playback of current track fails in the middle and need to
|
|
||||||
// fallback to state machine
|
|
||||||
bool mFallbackToStateMachine;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
@ -19,12 +19,6 @@
|
|||||||
#include "gfx2DGlue.h"
|
#include "gfx2DGlue.h"
|
||||||
#include "MediaStreamSource.h"
|
#include "MediaStreamSource.h"
|
||||||
|
|
||||||
#ifdef MOZ_AUDIO_OFFLOAD
|
|
||||||
#include <stagefright/Utils.h>
|
|
||||||
#include <cutils/properties.h>
|
|
||||||
#include <stagefright/MetaData.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define MAX_DROPPED_FRAMES 25
|
#define MAX_DROPPED_FRAMES 25
|
||||||
// Try not to spend more than this much time in a single call to DecodeVideoFrame.
|
// Try not to spend more than this much time in a single call to DecodeVideoFrame.
|
||||||
#define MAX_VIDEO_DECODE_SECONDS 0.1
|
#define MAX_VIDEO_DECODE_SECONDS 0.1
|
||||||
@ -42,7 +36,7 @@ extern PRLogModuleInfo* gMediaDecoderLog;
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
MediaOmxReader::MediaOmxReader(AbstractMediaDecoder *aDecoder)
|
MediaOmxReader::MediaOmxReader(AbstractMediaDecoder *aDecoder)
|
||||||
: MediaDecoderReader(aDecoder)
|
: MediaOmxCommonReader(aDecoder)
|
||||||
, mHasVideo(false)
|
, mHasVideo(false)
|
||||||
, mHasAudio(false)
|
, mHasAudio(false)
|
||||||
, mVideoSeekTimeUs(-1)
|
, mVideoSeekTimeUs(-1)
|
||||||
@ -425,41 +419,12 @@ void MediaOmxReader::EnsureActive() {
|
|||||||
NS_ASSERTION(result == NS_OK, "OmxDecoder should be in play state to continue decoding");
|
NS_ASSERTION(result == NS_OK, "OmxDecoder should be in play state to continue decoding");
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef MOZ_AUDIO_OFFLOAD
|
android::sp<android::MediaSource> MediaOmxReader::GetAudioOffloadTrack()
|
||||||
void MediaOmxReader::CheckAudioOffload()
|
|
||||||
{
|
{
|
||||||
NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
|
if (!mOmxDecoder.get()) {
|
||||||
|
return nullptr;
|
||||||
char offloadProp[128];
|
|
||||||
property_get("audio.offload.disable", offloadProp, "0");
|
|
||||||
bool offloadDisable = atoi(offloadProp) != 0;
|
|
||||||
if (offloadDisable) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
mAudioOffloadTrack = mOmxDecoder->GetAudioOffloadTrack();
|
|
||||||
sp<MetaData> meta = (mAudioOffloadTrack.get()) ?
|
|
||||||
mAudioOffloadTrack->getFormat() : nullptr;
|
|
||||||
|
|
||||||
// Supporting audio offload only when there is no video, no streaming
|
|
||||||
bool hasNoVideo = !mOmxDecoder->HasVideo();
|
|
||||||
bool isNotStreaming
|
|
||||||
= mDecoder->GetResource()->IsDataCachedToEndOfResource(0);
|
|
||||||
|
|
||||||
// Not much benefit in trying to offload other channel types. Most of them
|
|
||||||
// aren't supported and also duration would be less than a minute
|
|
||||||
bool isTypeMusic = mAudioChannel == dom::AudioChannel::Content;
|
|
||||||
|
|
||||||
DECODER_LOG(PR_LOG_DEBUG, ("%s meta %p, no video %d, no streaming %d,"
|
|
||||||
" channel type %d", __FUNCTION__, meta.get(), hasNoVideo,
|
|
||||||
isNotStreaming, mAudioChannel));
|
|
||||||
|
|
||||||
if ((meta.get()) && hasNoVideo && isNotStreaming && isTypeMusic &&
|
|
||||||
canOffloadStream(meta, false, false, AUDIO_STREAM_MUSIC)) {
|
|
||||||
DECODER_LOG(PR_LOG_DEBUG, ("Can offload this audio stream"));
|
|
||||||
mDecoder->SetCanOffloadAudio(true);
|
|
||||||
}
|
}
|
||||||
|
return mOmxDecoder->GetAudioOffloadTrack();
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
@ -6,10 +6,10 @@
|
|||||||
#if !defined(MediaOmxReader_h_)
|
#if !defined(MediaOmxReader_h_)
|
||||||
#define MediaOmxReader_h_
|
#define MediaOmxReader_h_
|
||||||
|
|
||||||
|
#include "MediaOmxCommonReader.h"
|
||||||
#include "MediaResource.h"
|
#include "MediaResource.h"
|
||||||
#include "MediaDecoderReader.h"
|
#include "MediaDecoderReader.h"
|
||||||
#include "nsRect.h"
|
#include "nsRect.h"
|
||||||
#include "mozilla/dom/AudioChannelBinding.h"
|
|
||||||
#include <ui/GraphicBuffer.h>
|
#include <ui/GraphicBuffer.h>
|
||||||
#include <stagefright/MediaSource.h>
|
#include <stagefright/MediaSource.h>
|
||||||
|
|
||||||
@ -26,7 +26,7 @@ namespace dom {
|
|||||||
|
|
||||||
class AbstractMediaDecoder;
|
class AbstractMediaDecoder;
|
||||||
|
|
||||||
class MediaOmxReader : public MediaDecoderReader
|
class MediaOmxReader : public MediaOmxCommonReader
|
||||||
{
|
{
|
||||||
nsCString mType;
|
nsCString mType;
|
||||||
bool mHasVideo;
|
bool mHasVideo;
|
||||||
@ -36,8 +36,6 @@ class MediaOmxReader : public MediaDecoderReader
|
|||||||
int64_t mVideoSeekTimeUs;
|
int64_t mVideoSeekTimeUs;
|
||||||
int64_t mAudioSeekTimeUs;
|
int64_t mAudioSeekTimeUs;
|
||||||
int32_t mSkipCount;
|
int32_t mSkipCount;
|
||||||
dom::AudioChannel mAudioChannel;
|
|
||||||
android::sp<android::MediaSource> mAudioOffloadTrack;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
android::sp<android::OmxDecoder> mOmxDecoder;
|
android::sp<android::OmxDecoder> mOmxDecoder;
|
||||||
@ -90,22 +88,9 @@ public:
|
|||||||
|
|
||||||
virtual void Shutdown() MOZ_OVERRIDE;
|
virtual void Shutdown() MOZ_OVERRIDE;
|
||||||
|
|
||||||
void SetAudioChannel(dom::AudioChannel aAudioChannel) {
|
|
||||||
mAudioChannel = aAudioChannel;
|
|
||||||
}
|
|
||||||
|
|
||||||
android::sp<android::MediaSource> GetAudioOffloadTrack() {
|
|
||||||
return mAudioOffloadTrack;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef MOZ_AUDIO_OFFLOAD
|
|
||||||
// Check whether it is possible to offload current audio track. This access
|
|
||||||
// canOffloadStream() from libStageFright Utils.cpp, which is not there in
|
|
||||||
// ANDROID_VERSION < 19
|
|
||||||
void CheckAudioOffload();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void ReleaseDecoder();
|
void ReleaseDecoder();
|
||||||
|
|
||||||
|
android::sp<android::MediaSource> GetAudioOffloadTrack();
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
@ -6,11 +6,15 @@
|
|||||||
|
|
||||||
EXPORTS += [
|
EXPORTS += [
|
||||||
'AudioOffloadPlayerBase.h',
|
'AudioOffloadPlayerBase.h',
|
||||||
|
'MediaOmxCommonDecoder.h',
|
||||||
|
'MediaOmxCommonReader.h',
|
||||||
'MediaOmxDecoder.h',
|
'MediaOmxDecoder.h',
|
||||||
'MediaOmxReader.h',
|
'MediaOmxReader.h',
|
||||||
]
|
]
|
||||||
|
|
||||||
SOURCES += [
|
SOURCES += [
|
||||||
|
'MediaOmxCommonDecoder.cpp',
|
||||||
|
'MediaOmxCommonReader.cpp',
|
||||||
'MediaOmxDecoder.cpp',
|
'MediaOmxDecoder.cpp',
|
||||||
'MediaOmxReader.cpp',
|
'MediaOmxReader.cpp',
|
||||||
'MediaStreamSource.cpp',
|
'MediaStreamSource.cpp',
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
#include "nsIConsoleService.h"
|
#include "nsIConsoleService.h"
|
||||||
#include "nsIScriptError.h"
|
#include "nsIScriptError.h"
|
||||||
#include "nsDocShellLoadTypes.h"
|
#include "nsDocShellLoadTypes.h"
|
||||||
|
#include "nsIMultiPartChannel.h"
|
||||||
|
|
||||||
using namespace mozilla;
|
using namespace mozilla;
|
||||||
|
|
||||||
@ -28,8 +29,9 @@ using namespace mozilla;
|
|||||||
//*****************************************************************************
|
//*****************************************************************************
|
||||||
|
|
||||||
nsDSURIContentListener::nsDSURIContentListener(nsDocShell* aDocShell)
|
nsDSURIContentListener::nsDSURIContentListener(nsDocShell* aDocShell)
|
||||||
: mDocShell(aDocShell),
|
: mDocShell(aDocShell)
|
||||||
mParentContentListener(nullptr)
|
, mExistingJPEGRequest(nullptr)
|
||||||
|
, mParentContentListener(nullptr)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -118,8 +120,33 @@ nsDSURIContentListener::DoContent(const char* aContentType,
|
|||||||
|
|
||||||
mDocShell->SetLoadType(aIsContentPreferred ? LOAD_LINK : LOAD_NORMAL);
|
mDocShell->SetLoadType(aIsContentPreferred ? LOAD_LINK : LOAD_NORMAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// In case of multipart jpeg request (mjpeg) we don't really want to
|
||||||
|
// create new viewer since the one we already have is capable of
|
||||||
|
// rendering multipart jpeg correctly (see bug 625012)
|
||||||
|
nsCOMPtr<nsIChannel> baseChannel;
|
||||||
|
if (nsCOMPtr<nsIMultiPartChannel> mpchan = do_QueryInterface(request)) {
|
||||||
|
mpchan->GetBaseChannel(getter_AddRefs(baseChannel));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool reuseCV = baseChannel
|
||||||
|
&& baseChannel == mExistingJPEGRequest
|
||||||
|
&& nsDependentCString(aContentType).EqualsLiteral("image/jpeg");
|
||||||
|
|
||||||
|
if (mExistingJPEGStreamListener && reuseCV) {
|
||||||
|
nsRefPtr<nsIStreamListener> copy(mExistingJPEGStreamListener);
|
||||||
|
copy.forget(aContentHandler);
|
||||||
|
rv = NS_OK;
|
||||||
|
} else {
|
||||||
|
rv = mDocShell->CreateContentViewer(aContentType, request, aContentHandler);
|
||||||
|
if (NS_SUCCEEDED(rv) && reuseCV) {
|
||||||
|
mExistingJPEGStreamListener = *aContentHandler;
|
||||||
|
} else {
|
||||||
|
mExistingJPEGStreamListener = nullptr;
|
||||||
|
}
|
||||||
|
mExistingJPEGRequest = baseChannel;
|
||||||
|
}
|
||||||
|
|
||||||
rv = mDocShell->CreateContentViewer(aContentType, request, aContentHandler);
|
|
||||||
|
|
||||||
if (rv == NS_ERROR_REMOTE_XUL) {
|
if (rv == NS_ERROR_REMOTE_XUL) {
|
||||||
request->Cancel(rv);
|
request->Cancel(rv);
|
||||||
|
@ -34,6 +34,8 @@ protected:
|
|||||||
|
|
||||||
void DropDocShellreference() {
|
void DropDocShellreference() {
|
||||||
mDocShell = nullptr;
|
mDocShell = nullptr;
|
||||||
|
mExistingJPEGRequest = nullptr;
|
||||||
|
mExistingJPEGStreamListener = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine if X-Frame-Options allows content to be framed
|
// Determine if X-Frame-Options allows content to be framed
|
||||||
@ -53,6 +55,9 @@ protected:
|
|||||||
XFOHeader aHeader);
|
XFOHeader aHeader);
|
||||||
protected:
|
protected:
|
||||||
nsDocShell* mDocShell;
|
nsDocShell* mDocShell;
|
||||||
|
// Hack to handle multipart images without creating a new viewer
|
||||||
|
nsCOMPtr<nsIStreamListener> mExistingJPEGStreamListener;
|
||||||
|
nsCOMPtr<nsIChannel> mExistingJPEGRequest;
|
||||||
|
|
||||||
// Store the parent listener in either of these depending on
|
// Store the parent listener in either of these depending on
|
||||||
// if supports weak references or not. Proper weak refs are
|
// if supports weak references or not. Proper weak refs are
|
||||||
|
@ -58,7 +58,7 @@ GonkCameraHardware::OnNewFrame()
|
|||||||
}
|
}
|
||||||
RefPtr<TextureClient> buffer = mNativeWindow->getCurrentBuffer();
|
RefPtr<TextureClient> buffer = mNativeWindow->getCurrentBuffer();
|
||||||
if (!buffer) {
|
if (!buffer) {
|
||||||
DOM_CAMERA_LOGW("received null frame");
|
DOM_CAMERA_LOGE("received null frame");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
OnNewPreviewFrame(mTarget, buffer);
|
OnNewPreviewFrame(mTarget, buffer);
|
||||||
@ -185,9 +185,13 @@ GonkCameraHardware::Init()
|
|||||||
|
|
||||||
#if ANDROID_VERSION >= 19
|
#if ANDROID_VERSION >= 19
|
||||||
mNativeWindow = new GonkNativeWindow(GonkCameraHardware::MIN_UNDEQUEUED_BUFFERS);
|
mNativeWindow = new GonkNativeWindow(GonkCameraHardware::MIN_UNDEQUEUED_BUFFERS);
|
||||||
|
sp<GonkBufferQueue> bq = mNativeWindow->getBufferQueue();
|
||||||
|
bq->setSynchronousMode(false);
|
||||||
mCamera->setPreviewTarget(mNativeWindow->getBufferQueue());
|
mCamera->setPreviewTarget(mNativeWindow->getBufferQueue());
|
||||||
#elif ANDROID_VERSION >= 17
|
#elif ANDROID_VERSION >= 17
|
||||||
mNativeWindow = new GonkNativeWindow(GonkCameraHardware::MIN_UNDEQUEUED_BUFFERS);
|
mNativeWindow = new GonkNativeWindow(GonkCameraHardware::MIN_UNDEQUEUED_BUFFERS);
|
||||||
|
sp<GonkBufferQueue> bq = mNativeWindow->getBufferQueue();
|
||||||
|
bq->setSynchronousMode(false);
|
||||||
mCamera->setPreviewTexture(mNativeWindow->getBufferQueue());
|
mCamera->setPreviewTexture(mNativeWindow->getBufferQueue());
|
||||||
#else
|
#else
|
||||||
mNativeWindow = new GonkNativeWindow();
|
mNativeWindow = new GonkNativeWindow();
|
||||||
|
@ -452,6 +452,11 @@ MozInputContext.prototype = {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update context first before resolving promise to avoid race condition
|
||||||
|
if (json.selectioninfo) {
|
||||||
|
this.updateSelectionContext(json.selectioninfo);
|
||||||
|
}
|
||||||
|
|
||||||
switch (msg.name) {
|
switch (msg.name) {
|
||||||
case "Keyboard:SendKey:Result:OK":
|
case "Keyboard:SendKey:Result:OK":
|
||||||
resolver.resolve();
|
resolver.resolve();
|
||||||
|
@ -224,6 +224,7 @@ let FormAssistant = {
|
|||||||
_documentEncoder: null,
|
_documentEncoder: null,
|
||||||
_editor: null,
|
_editor: null,
|
||||||
_editing: false,
|
_editing: false,
|
||||||
|
_selectionPrivate: null,
|
||||||
|
|
||||||
get focusedElement() {
|
get focusedElement() {
|
||||||
if (this._focusedElement && Cu.isDeadWrapper(this._focusedElement))
|
if (this._focusedElement && Cu.isDeadWrapper(this._focusedElement))
|
||||||
@ -244,8 +245,6 @@ let FormAssistant = {
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
if (this.focusedElement) {
|
if (this.focusedElement) {
|
||||||
this.focusedElement.removeEventListener('mousedown', this);
|
|
||||||
this.focusedElement.removeEventListener('mouseup', this);
|
|
||||||
this.focusedElement.removeEventListener('compositionend', this);
|
this.focusedElement.removeEventListener('compositionend', this);
|
||||||
if (this._observer) {
|
if (this._observer) {
|
||||||
this._observer.disconnect();
|
this._observer.disconnect();
|
||||||
@ -254,6 +253,10 @@ let FormAssistant = {
|
|||||||
if (!element) {
|
if (!element) {
|
||||||
this.focusedElement.blur();
|
this.focusedElement.blur();
|
||||||
}
|
}
|
||||||
|
if (this._selectionPrivate) {
|
||||||
|
this._selectionPrivate.removeSelectionListener(this);
|
||||||
|
this._selectionPrivate = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this._documentEncoder = null;
|
this._documentEncoder = null;
|
||||||
@ -269,8 +272,6 @@ let FormAssistant = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (element) {
|
if (element) {
|
||||||
element.addEventListener('mousedown', this);
|
|
||||||
element.addEventListener('mouseup', this);
|
|
||||||
element.addEventListener('compositionend', this);
|
element.addEventListener('compositionend', this);
|
||||||
if (isContentEditable(element)) {
|
if (isContentEditable(element)) {
|
||||||
this._documentEncoder = getDocumentEncoder(element);
|
this._documentEncoder = getDocumentEncoder(element);
|
||||||
@ -280,6 +281,12 @@ let FormAssistant = {
|
|||||||
// Add a nsIEditorObserver to monitor the text content of the focused
|
// Add a nsIEditorObserver to monitor the text content of the focused
|
||||||
// element.
|
// element.
|
||||||
this._editor.addEditorObserver(this);
|
this._editor.addEditorObserver(this);
|
||||||
|
|
||||||
|
let selection = this._editor.selection;
|
||||||
|
if (selection) {
|
||||||
|
this._selectionPrivate = selection.QueryInterface(Ci.nsISelectionPrivate);
|
||||||
|
this._selectionPrivate.addSelectionListener(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If our focusedElement is removed from DOM we want to handle it properly
|
// If our focusedElement is removed from DOM we want to handle it properly
|
||||||
@ -305,6 +312,10 @@ let FormAssistant = {
|
|||||||
this.focusedElement = element;
|
this.focusedElement = element;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
notifySelectionChanged: function(aDocument, aSelection, aReason) {
|
||||||
|
this.updateSelection();
|
||||||
|
},
|
||||||
|
|
||||||
get documentEncoder() {
|
get documentEncoder() {
|
||||||
return this._documentEncoder;
|
return this._documentEncoder;
|
||||||
},
|
},
|
||||||
@ -376,32 +387,6 @@ let FormAssistant = {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'mousedown':
|
|
||||||
if (!this.focusedElement) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We only listen for this event on the currently focused element.
|
|
||||||
// When the mouse goes down, note the cursor/selection position
|
|
||||||
this.updateSelection();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'mouseup':
|
|
||||||
if (!this.focusedElement) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We only listen for this event on the currently focused element.
|
|
||||||
// When the mouse goes up, see if the cursor has moved (or the
|
|
||||||
// selection changed) since the mouse went down. If it has, we
|
|
||||||
// need to tell the keyboard about it
|
|
||||||
range = getSelectionRange(this.focusedElement);
|
|
||||||
if (range[0] !== this.selectionStart ||
|
|
||||||
range[1] !== this.selectionEnd) {
|
|
||||||
this.updateSelection();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "resize":
|
case "resize":
|
||||||
if (!this.isKeyboardOpened)
|
if (!this.isKeyboardOpened)
|
||||||
return;
|
return;
|
||||||
@ -423,25 +408,12 @@ let FormAssistant = {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "input":
|
|
||||||
if (this.focusedElement) {
|
|
||||||
// When the text content changes, notify the keyboard
|
|
||||||
this.updateSelection();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "keydown":
|
case "keydown":
|
||||||
if (!this.focusedElement) {
|
if (!this.focusedElement) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
CompositionManager.endComposition('');
|
CompositionManager.endComposition('');
|
||||||
|
|
||||||
// We use 'setTimeout' to wait until the input element accomplishes the
|
|
||||||
// change in selection range.
|
|
||||||
content.setTimeout(function() {
|
|
||||||
this.updateSelection();
|
|
||||||
}.bind(this), 0);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "keyup":
|
case "keyup":
|
||||||
@ -450,7 +422,6 @@ let FormAssistant = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
CompositionManager.endComposition('');
|
CompositionManager.endComposition('');
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "compositionend":
|
case "compositionend":
|
||||||
@ -526,7 +497,8 @@ let FormAssistant = {
|
|||||||
|
|
||||||
if (json.requestId && doKeypress) {
|
if (json.requestId && doKeypress) {
|
||||||
sendAsyncMessage("Forms:SendKey:Result:OK", {
|
sendAsyncMessage("Forms:SendKey:Result:OK", {
|
||||||
requestId: json.requestId
|
requestId: json.requestId,
|
||||||
|
selectioninfo: this.getSelectionInfo()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else if (json.requestId && !doKeypress) {
|
else if (json.requestId && !doKeypress) {
|
||||||
@ -584,8 +556,6 @@ let FormAssistant = {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.updateSelection();
|
|
||||||
|
|
||||||
if (json.requestId) {
|
if (json.requestId) {
|
||||||
sendAsyncMessage("Forms:SetSelectionRange:Result:OK", {
|
sendAsyncMessage("Forms:SetSelectionRange:Result:OK", {
|
||||||
requestId: json.requestId,
|
requestId: json.requestId,
|
||||||
@ -652,6 +622,7 @@ let FormAssistant = {
|
|||||||
json.clauses);
|
json.clauses);
|
||||||
sendAsyncMessage("Forms:SetComposition:Result:OK", {
|
sendAsyncMessage("Forms:SetComposition:Result:OK", {
|
||||||
requestId: json.requestId,
|
requestId: json.requestId,
|
||||||
|
selectioninfo: this.getSelectionInfo()
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -660,6 +631,7 @@ let FormAssistant = {
|
|||||||
CompositionManager.endComposition(json.text);
|
CompositionManager.endComposition(json.text);
|
||||||
sendAsyncMessage("Forms:EndComposition:Result:OK", {
|
sendAsyncMessage("Forms:EndComposition:Result:OK", {
|
||||||
requestId: json.requestId,
|
requestId: json.requestId,
|
||||||
|
selectioninfo: this.getSelectionInfo()
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -758,15 +730,29 @@ let FormAssistant = {
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_selectionTimeout: null,
|
||||||
|
|
||||||
// Notify when the selection range changes
|
// Notify when the selection range changes
|
||||||
updateSelection: function fa_updateSelection() {
|
updateSelection: function fa_updateSelection() {
|
||||||
if (!this.focusedElement) {
|
// A call to setSelectionRange on input field causes 2 selection changes
|
||||||
return;
|
// one to [0,0] and one to actual value. Both are sent in same tick.
|
||||||
}
|
// Prevent firing two events in that scenario, always only use the last 1.
|
||||||
let selectionInfo = this.getSelectionInfo();
|
//
|
||||||
if (selectionInfo.changed) {
|
// It is also a workaround for Bug 1053048, which prevents
|
||||||
sendAsyncMessage("Forms:SelectionChange", this.getSelectionInfo());
|
// getSelectionInfo() accessing selectionStart or selectionEnd in the
|
||||||
|
// callback function of nsISelectionListener::NotifySelectionChanged().
|
||||||
|
if (this._selectionTimeout) {
|
||||||
|
content.clearTimeout(this._selectionTimeout);
|
||||||
}
|
}
|
||||||
|
this._selectionTimeout = content.setTimeout(function() {
|
||||||
|
if (!this.focusedElement) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let selectionInfo = this.getSelectionInfo();
|
||||||
|
if (selectionInfo.changed) {
|
||||||
|
sendAsyncMessage("Forms:SelectionChange", selectionInfo);
|
||||||
|
}
|
||||||
|
}.bind(this), 0);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -15,6 +15,7 @@ support-files =
|
|||||||
[test_bug953044.html]
|
[test_bug953044.html]
|
||||||
[test_bug960946.html]
|
[test_bug960946.html]
|
||||||
[test_bug978918.html]
|
[test_bug978918.html]
|
||||||
|
[test_bug1026997.html]
|
||||||
[test_bug1043828.html]
|
[test_bug1043828.html]
|
||||||
[test_delete_focused_element.html]
|
[test_delete_focused_element.html]
|
||||||
[test_sendkey_cancel.html]
|
[test_sendkey_cancel.html]
|
||||||
|
101
dom/inputmethod/mochitest/test_bug1026997.html
Normal file
101
dom/inputmethod/mochitest/test_bug1026997.html
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html>
|
||||||
|
<!--
|
||||||
|
https://bugzilla.mozilla.org/show_bug.cgi?id=1026997
|
||||||
|
-->
|
||||||
|
<head>
|
||||||
|
<title>SelectionChange on InputMethod API.</title>
|
||||||
|
<script type="application/javascript;version=1.7" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||||
|
<script type="application/javascript;version=1.7" src="inputmethod_common.js"></script>
|
||||||
|
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1026997">Mozilla Bug 1026997</a>
|
||||||
|
<p id="display"></p>
|
||||||
|
<pre id="test">
|
||||||
|
<script class="testbody" type="application/javascript;version=1.7">
|
||||||
|
|
||||||
|
inputmethod_setup(function() {
|
||||||
|
runTest();
|
||||||
|
});
|
||||||
|
|
||||||
|
// The frame script running in file_test_app.html.
|
||||||
|
function appFrameScript() {
|
||||||
|
let input = content.document.getElementById('test-input');
|
||||||
|
|
||||||
|
input.focus();
|
||||||
|
|
||||||
|
function next(start, end) {
|
||||||
|
input.setSelectionRange(start, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
addMessageListener("test:KeyBoard:nextSelection", function(event) {
|
||||||
|
let json = event.json;
|
||||||
|
next(json[0], json[1]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function runTest() {
|
||||||
|
let actions = [
|
||||||
|
[0, 4],
|
||||||
|
[1, 1],
|
||||||
|
[3, 3],
|
||||||
|
[2, 3]
|
||||||
|
];
|
||||||
|
|
||||||
|
let counter = 0;
|
||||||
|
let mm = null;
|
||||||
|
let ic = null;
|
||||||
|
|
||||||
|
let im = navigator.mozInputMethod;
|
||||||
|
im.oninputcontextchange = function() {
|
||||||
|
ok(true, 'inputcontextchange event was fired.');
|
||||||
|
im.oninputcontextchange = null;
|
||||||
|
|
||||||
|
ic = im.inputcontext;
|
||||||
|
if (!ic) {
|
||||||
|
ok(false, 'Should have a non-null inputcontext.');
|
||||||
|
inputmethod_cleanup();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ic.onselectionchange = function() {
|
||||||
|
is(ic.selectionStart, actions[counter][0], "start");
|
||||||
|
is(ic.selectionEnd, actions[counter][1], "end");
|
||||||
|
|
||||||
|
if (++counter === actions.length) {
|
||||||
|
inputmethod_cleanup();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
next();
|
||||||
|
};
|
||||||
|
|
||||||
|
next();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Set current page as an input method.
|
||||||
|
SpecialPowers.wrap(im).setActive(true);
|
||||||
|
|
||||||
|
// Create an app frame to recieve keyboard inputs.
|
||||||
|
let app = document.createElement('iframe');
|
||||||
|
app.src = 'file_test_app.html';
|
||||||
|
app.setAttribute('mozbrowser', true);
|
||||||
|
document.body.appendChild(app);
|
||||||
|
app.addEventListener('mozbrowserloadend', function() {
|
||||||
|
mm = SpecialPowers.getBrowserFrameMessageManager(app);
|
||||||
|
mm.loadFrameScript('data:,(' + appFrameScript.toString() + ')();', false);
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
|
||||||
|
function next() {
|
||||||
|
if (ic && mm) {
|
||||||
|
mm.sendAsyncMessage('test:KeyBoard:nextSelection', actions[counter]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</pre>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
@ -236,9 +236,16 @@ SystemMessageInternal.prototype = {
|
|||||||
|
|
||||||
debug("Broadcasting " + aType + " " + JSON.stringify(aMessage) +
|
debug("Broadcasting " + aType + " " + JSON.stringify(aMessage) +
|
||||||
'; extra = ' + JSON.stringify(aExtra));
|
'; extra = ' + JSON.stringify(aExtra));
|
||||||
|
|
||||||
|
let shouldDispatchFunc = this._getMessageConfigurator(aType).shouldDispatch;
|
||||||
|
|
||||||
// Find pages that registered an handler for this type.
|
// Find pages that registered an handler for this type.
|
||||||
this._pages.forEach(function(aPage) {
|
this._pages.forEach(function(aPage) {
|
||||||
if (aPage.type == aType) {
|
if (aPage.type !== aType) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let doDispatch = () => {
|
||||||
let result = this._sendMessageCommon(aType,
|
let result = this._sendMessageCommon(aType,
|
||||||
aMessage,
|
aMessage,
|
||||||
messageID,
|
messageID,
|
||||||
@ -258,7 +265,22 @@ SystemMessageInternal.prototype = {
|
|||||||
this._queueMessage(aPage, aMessage, messageID);
|
this._queueMessage(aPage, aMessage, messageID);
|
||||||
|
|
||||||
this._openAppPage(aPage, aMessage, aExtra, result);
|
this._openAppPage(aPage, aMessage, aExtra, result);
|
||||||
|
};
|
||||||
|
|
||||||
|
if ('function' !== typeof shouldDispatchFunc) {
|
||||||
|
// If the configurator has no 'shouldDispatch' defined,
|
||||||
|
// always dispatch this message.
|
||||||
|
doDispatch();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
shouldDispatchFunc(aPage.manifestURL, aPage.pageURL, aType, aMessage, aExtra)
|
||||||
|
.then(aShouldDispatch => {
|
||||||
|
if (aShouldDispatch) {
|
||||||
|
doDispatch();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
}, this);
|
}, this);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -56,7 +56,7 @@ interface nsISystemMessagesWrapper: nsISupports
|
|||||||
* Implements an interface to allow specific message types to
|
* Implements an interface to allow specific message types to
|
||||||
* configure some behaviors
|
* configure some behaviors
|
||||||
*/
|
*/
|
||||||
[scriptable, uuid(a0e970f6-faa9-4605-89d6-fafae8b10a80)]
|
[scriptable, uuid(31b78730-21c6-11e4-8c21-0800200c9a66)]
|
||||||
interface nsISystemMessagesConfigurator: nsISupports
|
interface nsISystemMessagesConfigurator: nsISupports
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
@ -64,4 +64,13 @@ interface nsISystemMessagesConfigurator: nsISupports
|
|||||||
* that the app will be brought to the front always.
|
* that the app will be brought to the front always.
|
||||||
*/
|
*/
|
||||||
readonly attribute boolean mustShowRunningApp;
|
readonly attribute boolean mustShowRunningApp;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A broadcast filter for a specific message type.
|
||||||
|
*
|
||||||
|
* @return Promise which resolves with |true| or |false| to indicate if
|
||||||
|
* we want to dispatch this message.
|
||||||
|
*/
|
||||||
|
jsval shouldDispatch(in DOMString manifestURL, in DOMString pageURL,
|
||||||
|
in DOMString type, in jsval message, [optional] in jsval extra);
|
||||||
};
|
};
|
||||||
|
@ -27,9 +27,6 @@ FAIL_ON_WARNINGS = True
|
|||||||
|
|
||||||
FINAL_LIBRARY = 'xul'
|
FINAL_LIBRARY = 'xul'
|
||||||
RESOURCE_FILES += [
|
RESOURCE_FILES += [
|
||||||
'res/caret_left.svg',
|
|
||||||
'res/caret_middle.svg',
|
|
||||||
'res/caret_right.svg',
|
|
||||||
'res/EditorOverride.css',
|
'res/EditorOverride.css',
|
||||||
'res/grabber.gif',
|
'res/grabber.gif',
|
||||||
'res/table-add-column-after-active.gif',
|
'res/table-add-column-after-active.gif',
|
||||||
@ -50,4 +47,19 @@ RESOURCE_FILES += [
|
|||||||
'res/table-remove-row-active.gif',
|
'res/table-remove-row-active.gif',
|
||||||
'res/table-remove-row-hover.gif',
|
'res/table-remove-row-hover.gif',
|
||||||
'res/table-remove-row.gif',
|
'res/table-remove-row.gif',
|
||||||
|
'res/text_caret.png',
|
||||||
|
'res/text_caret@1.5x.png',
|
||||||
|
'res/text_caret@2.25x.png',
|
||||||
|
'res/text_caret@2x.png',
|
||||||
|
'res/text_caret_tilt_left.png',
|
||||||
|
'res/text_caret_tilt_left@1.5x.png',
|
||||||
|
'res/text_caret_tilt_left@2.25x.png',
|
||||||
|
'res/text_caret_tilt_left@2x.png',
|
||||||
|
'res/text_caret_tilt_right.png',
|
||||||
|
'res/text_caret_tilt_right@1.5x.png',
|
||||||
|
'res/text_caret_tilt_right@2.25x.png',
|
||||||
|
'res/text_caret_tilt_right@2x.png',
|
||||||
|
'res/text_selection_handle.png',
|
||||||
|
'res/text_selection_handle@1.5.png',
|
||||||
|
'res/text_selection_handle@2.png',
|
||||||
]
|
]
|
||||||
|
@ -1,24 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
|
||||||
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
|
||||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
|
||||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
|
||||||
width="29px" height="31px" viewBox="0 0 29 31" style="enable-background:new 0 0 29 31;" xml:space="preserve">
|
|
||||||
<!-- TODO: Enable shadow after bug 1015575 is resolved.
|
|
||||||
<defs>
|
|
||||||
<filter id="caretFilter">
|
|
||||||
<feOffset result="offsetOut" in="SourceAlpha" dx="1" dy="1" />
|
|
||||||
<feGaussianBlur result="blurOut" in="offsetOut" stdDeviation="0.5" />
|
|
||||||
<feBlend in="SourceGraphic" in2="blurOut" mode="normal" />
|
|
||||||
</filter>
|
|
||||||
</defs>
|
|
||||||
<g fill="#2da9e3" filter="url(#caretFilter)">
|
|
||||||
-->
|
|
||||||
<g fill="#2da9e3">
|
|
||||||
<path d="M25.368,2.674c-0.049,0.104-0.09,0.209-0.134,0.314C25.304,2.893,25.347,2.786,25.368,2.674z"/>
|
|
||||||
<path d="M24.27,1.734c0.003-0.001,0.008-0.003,0.013-0.004C24.277,1.73,24.272,1.733,24.27,1.734z"/>
|
|
||||||
<path d="M24.583,8.574C24.25,6.7,24.478,4.755,25.234,2.989c0.044-0.105,0.085-0.21,0.134-0.314
|
|
||||||
c0.053-0.254-0.016-0.528-0.204-0.73c-0.232-0.249-0.581-0.322-0.882-0.215c-0.005,0.001-0.01,0.003-0.013,0.004
|
|
||||||
c-1.915,0.71-4.001,0.798-5.954,0.277C15.015,0.898,11.222,1.587,8.5,4.134c-3.947,3.691-4.155,9.882-0.464,13.828
|
|
||||||
c3.691,3.947,9.881,4.154,13.828,0.462C24.64,15.828,25.562,11.994,24.583,8.574z"/>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 1.5 KiB |
@ -1,24 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
|
||||||
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
|
||||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
|
||||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
|
||||||
width="29px" height="31px" style="enable-background:new 0 0 29 31;" xml:space="preserve">
|
|
||||||
<!-- TODO: Enable shadow after bug 1015575 is resolved.
|
|
||||||
<defs>
|
|
||||||
<filter id="caretFilter">
|
|
||||||
<feOffset result="offsetOut" in="SourceAlpha" dx="1" dy="1" />
|
|
||||||
<feGaussianBlur result="blurOut" in="offsetOut" stdDeviation="0.5" />
|
|
||||||
<feBlend in="SourceGraphic" in2="blurOut" mode="normal" />
|
|
||||||
</filter>
|
|
||||||
</defs>
|
|
||||||
<g fill="#2da9e3" filter="url(#caretFilter)">
|
|
||||||
-->
|
|
||||||
<g fill="#2da9e3">
|
|
||||||
<path d="M15.174,1.374c0.042,0.106,0.091,0.208,0.138,0.312C15.288,1.57,15.239,1.466,15.174,1.374z"/>
|
|
||||||
<path d="M13.735,1.534c0.002-0.003,0.004-0.009,0.006-0.013C13.739,1.525,13.737,1.531,13.735,1.534z"/>
|
|
||||||
<path d="M18.945,5.978c-1.596-1.038-2.861-2.532-3.634-4.292c-0.047-0.104-0.096-0.206-0.138-0.312
|
|
||||||
c-0.15-0.212-0.396-0.349-0.674-0.349c-0.34,0-0.631,0.204-0.759,0.497c-0.002,0.004-0.004,0.009-0.006,0.013
|
|
||||||
c-0.789,1.883-2.149,3.467-3.864,4.538c-3.068,1.651-5.155,4.892-5.155,8.62c0,5.404,4.379,9.784,9.783,9.784
|
|
||||||
c5.403,0,9.783-4.38,9.783-9.784C24.283,10.891,22.113,7.598,18.945,5.978z"/>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 1.5 KiB |
@ -1,24 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
|
||||||
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
|
||||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
|
||||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
|
||||||
width="29px" height="31px" viewBox="0 0 29 31" style="enable-background:new 0 0 29 31;" xml:space="preserve">
|
|
||||||
<!-- TODO: Enable shadow after bug 1015575 is resolved.
|
|
||||||
<defs>
|
|
||||||
<filter id="caretFilter">
|
|
||||||
<feOffset result="offsetOut" in="SourceAlpha" dx="1" dy="1" />
|
|
||||||
<feGaussianBlur result="blurOut" in="offsetOut" stdDeviation="0.5" />
|
|
||||||
<feBlend in="SourceGraphic" in2="blurOut" mode="normal" />
|
|
||||||
</filter>
|
|
||||||
</defs>
|
|
||||||
<g fill="#2da9e3" filter="url(#caretFilter)">
|
|
||||||
-->
|
|
||||||
<g fill="#2da9e3">
|
|
||||||
<path fill="#2da9e3" d="M27.296,2.674c-0.049,0.104-0.09,0.209-0.134,0.314C27.231,2.893,27.274,2.786,27.296,2.674z"/>
|
|
||||||
<path fill="#2da9e3" d="M26.197,1.734C26.2,1.733,26.205,1.73,26.21,1.729C26.205,1.73,26.2,1.733,26.197,1.734z"/>
|
|
||||||
<path fill="#2da9e3" d="M4.299,8.574C4.632,6.7,4.404,4.755,3.647,2.989c-0.044-0.105-0.085-0.21-0.134-0.314C3.461,2.42,3.529,2.146,3.718,1.944
|
|
||||||
C3.95,1.696,4.299,1.623,4.6,1.729c0.005,0.001,0.01,0.003,0.013,0.004c1.915,0.71,4.001,0.798,5.954,0.277
|
|
||||||
c3.301-1.113,7.094-0.423,9.815,2.123c3.947,3.691,4.156,9.882,0.465,13.828c-3.691,3.947-9.881,4.154-13.828,0.462
|
|
||||||
C4.242,15.828,3.319,11.994,4.299,8.574z"/>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 1.6 KiB |
@ -3,7 +3,7 @@
|
|||||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
include libeditor/html/crashtests/crashtests.list
|
include libeditor/html/crashtests/crashtests.list
|
||||||
include libeditor/base/crashtests/crashtests.list
|
include libeditor/crashtests/crashtests.list
|
||||||
include libeditor/text/crashtests/crashtests.list
|
include libeditor/text/crashtests/crashtests.list
|
||||||
include composer/crashtests/crashtests.list
|
include composer/crashtests/crashtests.list
|
||||||
include txmgr/tests/crashtests/crashtests.list
|
include txmgr/tests/crashtests/crashtests.list
|
||||||
|
@ -1,44 +0,0 @@
|
|||||||
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
|
|
||||||
# vim: set filetype=python:
|
|
||||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
||||||
|
|
||||||
TEST_DIRS += ['tests']
|
|
||||||
|
|
||||||
UNIFIED_SOURCES += [
|
|
||||||
'ChangeAttributeTxn.cpp',
|
|
||||||
'ChangeCSSInlineStyleTxn.cpp',
|
|
||||||
'CreateElementTxn.cpp',
|
|
||||||
'DeleteNodeTxn.cpp',
|
|
||||||
'DeleteRangeTxn.cpp',
|
|
||||||
'DeleteTextTxn.cpp',
|
|
||||||
'EditAggregateTxn.cpp',
|
|
||||||
'EditTxn.cpp',
|
|
||||||
'IMETextTxn.cpp',
|
|
||||||
'InsertElementTxn.cpp',
|
|
||||||
'InsertTextTxn.cpp',
|
|
||||||
'JoinElementTxn.cpp',
|
|
||||||
'nsEditor.cpp',
|
|
||||||
'nsEditorCommands.cpp',
|
|
||||||
'nsEditorController.cpp',
|
|
||||||
'nsEditorEventListener.cpp',
|
|
||||||
'nsEditorUtils.cpp',
|
|
||||||
'nsSelectionState.cpp',
|
|
||||||
'nsStyleSheetTxns.cpp',
|
|
||||||
'PlaceholderTxn.cpp',
|
|
||||||
'SetDocTitleTxn.cpp',
|
|
||||||
'SplitElementTxn.cpp',
|
|
||||||
]
|
|
||||||
|
|
||||||
FAIL_ON_WARNINGS = True
|
|
||||||
|
|
||||||
LOCAL_INCLUDES += [
|
|
||||||
'../text',
|
|
||||||
'/content/base/src',
|
|
||||||
'/editor/txmgr',
|
|
||||||
'/extensions/spellcheck/src',
|
|
||||||
'/layout/style',
|
|
||||||
]
|
|
||||||
|
|
||||||
FINAL_LIBRARY = 'xul'
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user