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
a276714066
@ -67,6 +67,11 @@ DocAccessibleParent::AddSubtree(ProxyAccessible* aParent,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (mAccessibles.Contains(newChild.ID())) {
|
||||
NS_ERROR("ID already in use");
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto role = static_cast<a11y::role>(newChild.Role());
|
||||
ProxyAccessible* newProxy =
|
||||
new ProxyAccessible(newChild.ID(), aParent, this, role);
|
||||
@ -95,6 +100,8 @@ DocAccessibleParent::RecvHideEvent(const uint64_t& aRootID)
|
||||
if (mShutdown)
|
||||
return true;
|
||||
|
||||
CheckDocTree();
|
||||
|
||||
ProxyEntry* rootEntry = mAccessibles.GetEntry(aRootID);
|
||||
if (!rootEntry) {
|
||||
NS_ERROR("invalid root being removed!");
|
||||
@ -236,5 +243,17 @@ DocAccessibleParent::Destroy()
|
||||
GetAccService()->RemoteDocShutdown(this);
|
||||
}
|
||||
|
||||
void
|
||||
DocAccessibleParent::CheckDocTree() const
|
||||
{
|
||||
size_t childDocs = mChildDocs.Length();
|
||||
for (size_t i = 0; i < childDocs; i++) {
|
||||
if (!mChildDocs[i] || mChildDocs[i]->mParentDoc != this)
|
||||
MOZ_CRASH("document tree is broken!");
|
||||
|
||||
mChildDocs[i]->CheckDocTree();
|
||||
}
|
||||
}
|
||||
|
||||
} // a11y
|
||||
} // mozilla
|
||||
|
@ -150,6 +150,8 @@ private:
|
||||
uint32_t AddSubtree(ProxyAccessible* aParent,
|
||||
const nsTArray<AccessibleData>& aNewTree, uint32_t aIdx,
|
||||
uint32_t aIdxInParent);
|
||||
void CheckDocTree() const;
|
||||
|
||||
static PLDHashOperator ShutdownAccessibles(ProxyEntry* entry, void* unused);
|
||||
|
||||
nsTArray<DocAccessibleParent*> mChildDocs;
|
||||
|
@ -15,7 +15,7 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="e862ab9177af664f00b4522e2350f4cb13866d73">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="981c61cdeb527fac8f8383c110df0e749eff67ea"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="77bc0d940bde2a5d2d4dfadfcccc6d8d77456d36"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="c490ae41c67f892232599f4ef049467a922b613e"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
@ -23,7 +23,7 @@
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
|
||||
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="7d810e5c522d146a3ee6d13b9422110119a3689f"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="f2a1305448efefacb2ec7e654d797bb9fbe7202e"/>
|
||||
<!-- Stock Android things -->
|
||||
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/>
|
||||
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="ebdad82e61c16772f6cd47e9f11936bf6ebe9aa0"/>
|
||||
@ -125,7 +125,7 @@
|
||||
<project name="device-shinano-common" path="device/sony/shinano-common" remote="b2g" revision="e9ef670a15d56ea312e70d4b11c4aaeac404f9d2"/>
|
||||
<project name="device/generic/armv7-a-neon" path="device/generic/armv7-a-neon" revision="1bb28abbc215f45220620af5cd60a8ac1be93722"/>
|
||||
<project name="device/qcom/common" path="device/qcom/common" revision="2501e5940ba69ece7654ff85611c76ae5bda299c"/>
|
||||
<project name="codeaurora_kernel_msm" path="kernel" remote="b2g" revision="d415406c7d810321a7cdd9af9c6271b2a378794c"/>
|
||||
<project name="codeaurora_kernel_msm" path="kernel" remote="b2g" revision="d620691cad7aee780018e98159ff03bf99840317"/>
|
||||
<project name="platform/external/bluetooth/bluedroid" path="external/bluetooth/bluedroid" revision="d61fc97258c8b0c362430dd2eb195dcc4d266f14"/>
|
||||
<project name="init_sh" path="external/init_sh" remote="b2g" revision="3bdd26e092db9c47c5beb04b4809a35f8f767b8a"/>
|
||||
<project name="platform/external/libnfc-nci" path="external/libnfc-nci" revision="0a01977f34d6e86fe23d6c0ec75e96ba988bbebb"/>
|
||||
|
@ -15,7 +15,7 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="e862ab9177af664f00b4522e2350f4cb13866d73">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="981c61cdeb527fac8f8383c110df0e749eff67ea"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="77bc0d940bde2a5d2d4dfadfcccc6d8d77456d36"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="c490ae41c67f892232599f4ef049467a922b613e"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
@ -23,7 +23,7 @@
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
|
||||
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="7d810e5c522d146a3ee6d13b9422110119a3689f"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="f2a1305448efefacb2ec7e654d797bb9fbe7202e"/>
|
||||
<!-- Stock Android things -->
|
||||
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/>
|
||||
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="ebdad82e61c16772f6cd47e9f11936bf6ebe9aa0"/>
|
||||
|
@ -19,10 +19,10 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="981c61cdeb527fac8f8383c110df0e749eff67ea"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="77bc0d940bde2a5d2d4dfadfcccc6d8d77456d36"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="c490ae41c67f892232599f4ef049467a922b613e"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="87a2d8ab9248540910e56921654367b78a587095"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="8bc59310552179f9a8bc6cdd0188e2475df52fb7"/>
|
||||
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="9d0e5057ee5404a31ec1bf76131cb11336a7c3b6"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="657894b4a1dc0a926117f4812e0940229f9f676f"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="34ea6163f9f0e0122fb0bb03607eccdca31ced7a"/>
|
||||
|
@ -17,10 +17,10 @@
|
||||
</project>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="981c61cdeb527fac8f8383c110df0e749eff67ea"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="77bc0d940bde2a5d2d4dfadfcccc6d8d77456d36"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="c490ae41c67f892232599f4ef049467a922b613e"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="657894b4a1dc0a926117f4812e0940229f9f676f"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="7d810e5c522d146a3ee6d13b9422110119a3689f"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="f2a1305448efefacb2ec7e654d797bb9fbe7202e"/>
|
||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
|
||||
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
|
||||
<!-- Stock Android things -->
|
||||
|
@ -15,7 +15,7 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="e862ab9177af664f00b4522e2350f4cb13866d73">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="981c61cdeb527fac8f8383c110df0e749eff67ea"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="77bc0d940bde2a5d2d4dfadfcccc6d8d77456d36"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="c490ae41c67f892232599f4ef049467a922b613e"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
@ -23,7 +23,7 @@
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
|
||||
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="7d810e5c522d146a3ee6d13b9422110119a3689f"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="f2a1305448efefacb2ec7e654d797bb9fbe7202e"/>
|
||||
<!-- Stock Android things -->
|
||||
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="f92a936f2aa97526d4593386754bdbf02db07a12"/>
|
||||
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="6e47ff2790f5656b5b074407829ceecf3e6188c4"/>
|
||||
|
@ -15,7 +15,7 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="61e82f99bb8bc78d52b5717e9a2481ec7267fa33">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="981c61cdeb527fac8f8383c110df0e749eff67ea"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="77bc0d940bde2a5d2d4dfadfcccc6d8d77456d36"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="c490ae41c67f892232599f4ef049467a922b613e"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
@ -23,7 +23,7 @@
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
|
||||
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="7d810e5c522d146a3ee6d13b9422110119a3689f"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="f2a1305448efefacb2ec7e654d797bb9fbe7202e"/>
|
||||
<!-- Stock Android things -->
|
||||
<project groups="pdk,linux" name="platform/prebuilts/clang/linux-x86/host/3.5" path="prebuilts/clang/linux-x86/host/3.5" revision="ffc05a232799fe8fcb3e47b7440b52b1fb4244c0"/>
|
||||
<project groups="pdk,linux,arm" name="platform/prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.8" path="prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.8" revision="337e0ef5e40f02a1ae59b90db0548976c70a7226"/>
|
||||
|
@ -19,10 +19,10 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="981c61cdeb527fac8f8383c110df0e749eff67ea"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="77bc0d940bde2a5d2d4dfadfcccc6d8d77456d36"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="c490ae41c67f892232599f4ef049467a922b613e"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="87a2d8ab9248540910e56921654367b78a587095"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="8bc59310552179f9a8bc6cdd0188e2475df52fb7"/>
|
||||
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="9d0e5057ee5404a31ec1bf76131cb11336a7c3b6"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="657894b4a1dc0a926117f4812e0940229f9f676f"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="34ea6163f9f0e0122fb0bb03607eccdca31ced7a"/>
|
||||
|
@ -15,7 +15,7 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="e862ab9177af664f00b4522e2350f4cb13866d73">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="981c61cdeb527fac8f8383c110df0e749eff67ea"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="77bc0d940bde2a5d2d4dfadfcccc6d8d77456d36"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="c490ae41c67f892232599f4ef049467a922b613e"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
@ -23,7 +23,7 @@
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
|
||||
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="7d810e5c522d146a3ee6d13b9422110119a3689f"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="f2a1305448efefacb2ec7e654d797bb9fbe7202e"/>
|
||||
<!-- Stock Android things -->
|
||||
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/>
|
||||
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="ebdad82e61c16772f6cd47e9f11936bf6ebe9aa0"/>
|
||||
|
@ -1,9 +1,9 @@
|
||||
{
|
||||
"git": {
|
||||
"git_revision": "981c61cdeb527fac8f8383c110df0e749eff67ea",
|
||||
"git_revision": "77bc0d940bde2a5d2d4dfadfcccc6d8d77456d36",
|
||||
"remote": "https://git.mozilla.org/releases/gaia.git",
|
||||
"branch": ""
|
||||
},
|
||||
"revision": "f0aa763ddba8274f1df27589dcfb69511ac8131e",
|
||||
"revision": "dfd4a9e8f31e64d427030d3612a48f7dbcada5d3",
|
||||
"repo_path": "integration/gaia-central"
|
||||
}
|
||||
|
@ -17,10 +17,10 @@
|
||||
</project>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="981c61cdeb527fac8f8383c110df0e749eff67ea"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="77bc0d940bde2a5d2d4dfadfcccc6d8d77456d36"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="c490ae41c67f892232599f4ef049467a922b613e"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="657894b4a1dc0a926117f4812e0940229f9f676f"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="7d810e5c522d146a3ee6d13b9422110119a3689f"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="f2a1305448efefacb2ec7e654d797bb9fbe7202e"/>
|
||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
|
||||
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
|
||||
<!-- Stock Android things -->
|
||||
|
@ -15,7 +15,7 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="61e82f99bb8bc78d52b5717e9a2481ec7267fa33">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="981c61cdeb527fac8f8383c110df0e749eff67ea"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="77bc0d940bde2a5d2d4dfadfcccc6d8d77456d36"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="c490ae41c67f892232599f4ef049467a922b613e"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
@ -23,7 +23,7 @@
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
|
||||
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="7d810e5c522d146a3ee6d13b9422110119a3689f"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="f2a1305448efefacb2ec7e654d797bb9fbe7202e"/>
|
||||
<!-- Stock Android things -->
|
||||
<project groups="pdk,linux" name="platform/prebuilts/clang/linux-x86/host/3.5" path="prebuilts/clang/linux-x86/host/3.5" revision="ffc05a232799fe8fcb3e47b7440b52b1fb4244c0"/>
|
||||
<project groups="pdk,linux,arm" name="platform/prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.8" path="prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.8" revision="337e0ef5e40f02a1ae59b90db0548976c70a7226"/>
|
||||
|
@ -1456,7 +1456,6 @@ pref("devtools.debugger.source-maps-enabled", true);
|
||||
pref("devtools.debugger.pretty-print-enabled", true);
|
||||
pref("devtools.debugger.auto-pretty-print", false);
|
||||
pref("devtools.debugger.auto-black-box", true);
|
||||
pref("devtools.debugger.tracer", false);
|
||||
pref("devtools.debugger.workers", false);
|
||||
pref("devtools.debugger.promise", false);
|
||||
|
||||
|
@ -183,9 +183,7 @@ let PanelFrame = {
|
||||
}
|
||||
});
|
||||
|
||||
// in overflow, the anchor is a normal toolbarbutton, in toolbar it is a badge button
|
||||
let anchor = aWindow.document.getAnonymousElementByAttribute(anchorBtn, "class", "toolbarbutton-badge-container") ||
|
||||
aWindow.document.getAnonymousElementByAttribute(anchorBtn, "class", "toolbarbutton-icon");
|
||||
let anchor = aWindow.document.getAnonymousElementByAttribute(anchorBtn, "class", "toolbarbutton-icon");
|
||||
// Bug 849216 - open the popup asynchronously so we avoid the auto-rollup
|
||||
// handling from preventing it being opened in some cases.
|
||||
Services.tm.mainThread.dispatch(function() {
|
||||
|
@ -584,7 +584,7 @@ menuitem:not([type]):not(.menuitem-tooltip):not(.menuitem-iconic-tooltip) {
|
||||
.findbar-button > .toolbarbutton-text,
|
||||
:-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1 > .toolbarbutton-menubutton-button > .toolbarbutton-icon,
|
||||
:-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon,
|
||||
:-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1 > .toolbarbutton-badge-container,
|
||||
:-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1 > .toolbarbutton-badge-stack,
|
||||
:-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1 > .toolbarbutton-icon {
|
||||
-moz-margin-end: 0;
|
||||
padding: 2px 6px;
|
||||
@ -595,14 +595,14 @@ menuitem:not([type]):not(.menuitem-tooltip):not(.menuitem-iconic-tooltip) {
|
||||
}
|
||||
|
||||
:-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1:not(:-moz-any(@primaryToolbarButtons@)) > .toolbarbutton-icon,
|
||||
:-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1:not(:-moz-any(@primaryToolbarButtons@)) > .toolbarbutton-badge-container,
|
||||
:-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1:not(:-moz-any(@primaryToolbarButtons@)) > .toolbarbutton-badge-stack,
|
||||
:-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1:not(:-moz-any(@primaryToolbarButtons@)) > .toolbarbutton-menubutton-button > .toolbarbutton-icon {
|
||||
padding: 3px 7px;
|
||||
}
|
||||
|
||||
/* Help SDK icons fit: */
|
||||
toolbarbutton[constrain-size="true"][cui-areatype="toolbar"] > .toolbarbutton-icon,
|
||||
toolbarbutton[constrain-size="true"][cui-areatype="toolbar"] > .toolbarbutton-badge-container > .toolbarbutton-icon {
|
||||
toolbarbutton[constrain-size="true"][cui-areatype="toolbar"] > .toolbarbutton-badge-stack > .toolbarbutton-icon {
|
||||
width: 16px;
|
||||
}
|
||||
|
||||
@ -620,7 +620,7 @@ toolbarbutton[constrain-size="true"][cui-areatype="toolbar"] > .toolbarbutton-ba
|
||||
:-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1[open]:not([disabled=true]) > .toolbarbutton-menubutton-button > .toolbarbutton-icon,
|
||||
:-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1:not([disabled=true]):not([open]):hover > .toolbarbutton-menubutton-button > .toolbarbutton-icon,
|
||||
:-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1:not([disabled=true]):not([open]):hover > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon,
|
||||
:-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1:not([disabled=true]):hover > .toolbarbutton-badge-container,
|
||||
:-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1:not([disabled=true]):hover > .toolbarbutton-badge-stack,
|
||||
:-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1:not([disabled=true]):hover > .toolbarbutton-icon {
|
||||
background: var(--toolbarbutton-hover-background);
|
||||
border-width: 1px;
|
||||
@ -638,7 +638,7 @@ toolbarbutton[constrain-size="true"][cui-areatype="toolbar"] > .toolbarbutton-ba
|
||||
.findbar-button:not([disabled=true]):-moz-any([checked="true"],:hover:active) > .toolbarbutton-text,
|
||||
:-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1 > .toolbarbutton-menubutton-button:not([disabled=true]):-moz-any(:hover:active, [open="true"]) > .toolbarbutton-icon,
|
||||
:-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1[open="true"] > .toolbarbutton-menubutton-dropmarker:not([disabled=true]) > .dropmarker-icon,
|
||||
:-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1:not([disabled=true]):-moz-any([open],[checked],:hover:active) > .toolbarbutton-badge-container,
|
||||
:-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1:not([disabled=true]):-moz-any([open],[checked],:hover:active) > .toolbarbutton-badge-stack,
|
||||
:-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1:not([disabled=true]):-moz-any([open],[checked],:hover:active) > .toolbarbutton-icon {
|
||||
background: var(--toolbarbutton-active-background);
|
||||
box-shadow: var(--toolbarbutton-active-boxshadow);
|
||||
|
@ -1067,7 +1067,7 @@ toolbar .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker > .dropmarker-ic
|
||||
}
|
||||
|
||||
:-moz-any(@primaryToolbarButtons@) > .toolbarbutton-icon,
|
||||
:-moz-any(@primaryToolbarButtons@) > .toolbarbutton-badge-container > .toolbarbutton-icon,
|
||||
:-moz-any(@primaryToolbarButtons@) > .toolbarbutton-badge-stack > .toolbarbutton-icon,
|
||||
:-moz-any(@primaryToolbarButtons@) > .toolbarbutton-menubutton-button > .toolbarbutton-icon {
|
||||
width: 18px;
|
||||
}
|
||||
@ -1090,25 +1090,25 @@ toolbar .toolbarbutton-1:not(:-moz-any(@primaryToolbarButtons@)) > .toolbarbutto
|
||||
|
||||
/* Help SDK icons fit: */
|
||||
toolbarbutton[constrain-size="true"][cui-areatype="toolbar"] > .toolbarbutton-icon,
|
||||
toolbarbutton[constrain-size="true"][cui-areatype="toolbar"] > .toolbarbutton-badge-container > .toolbarbutton-icon {
|
||||
toolbarbutton[constrain-size="true"][cui-areatype="toolbar"] > .toolbarbutton-badge-stack > .toolbarbutton-icon {
|
||||
width: 16px;
|
||||
}
|
||||
|
||||
#main-window:not([customizing]) .toolbarbutton-1[disabled="true"] > .toolbarbutton-icon,
|
||||
#main-window:not([customizing]) .toolbarbutton-1[disabled="true"] > .toolbarbutton-badge-container > .toolbarbutton-icon,
|
||||
#main-window:not([customizing]) .toolbarbutton-1[disabled="true"] > .toolbarbutton-badge-stack > .toolbarbutton-icon,
|
||||
#main-window:not([customizing]) .toolbarbutton-1 > .toolbarbutton-menubutton-button[disabled="true"] > .toolbarbutton-icon {
|
||||
opacity: .4;
|
||||
}
|
||||
|
||||
@media (-moz-mac-lion-theme) {
|
||||
#main-window:not([customizing]) .toolbarbutton-1[disabled="true"] > .toolbarbutton-icon,
|
||||
#main-window:not([customizing]) .toolbarbutton-1[disabled="true"] > .toolbarbutton-badge-container > .toolbarbutton-icon,
|
||||
#main-window:not([customizing]) .toolbarbutton-1[disabled="true"] > .toolbarbutton-badge-stack > .toolbarbutton-icon,
|
||||
#main-window:not([customizing]) .toolbarbutton-1 > .toolbarbutton-menubutton-button[disabled="true"] > .toolbarbutton-icon,
|
||||
#main-window:not([customizing]) .toolbarbutton-1[disabled="true"] > .toolbarbutton-menu-dropmarker,
|
||||
#main-window:not([customizing]) .toolbarbutton-1[disabled="true"] > .toolbarbutton-menubutton-dropmarker,
|
||||
.toolbarbutton-1:not(:hover):-moz-window-inactive > .toolbarbutton-icon,
|
||||
.toolbarbutton-1:not(:hover):-moz-window-inactive > .toolbarbutton-text,
|
||||
.toolbarbutton-1:not(:hover):-moz-window-inactive > .toolbarbutton-badge-container > .toolbarbutton-icon,
|
||||
.toolbarbutton-1:not(:hover):-moz-window-inactive > .toolbarbutton-badge-stack > .toolbarbutton-icon,
|
||||
.toolbarbutton-1:not(:hover):-moz-window-inactive > .toolbarbutton-menu-dropmarker,
|
||||
.toolbarbutton-1:not(:hover):-moz-window-inactive > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon,
|
||||
.toolbarbutton-1:not(:hover):-moz-window-inactive > .toolbarbutton-menubutton-button > .toolbarbutton-icon {
|
||||
@ -1116,7 +1116,7 @@ toolbarbutton[constrain-size="true"][cui-areatype="toolbar"] > .toolbarbutton-ba
|
||||
}
|
||||
|
||||
#main-window:not([customizing]) .toolbarbutton-1:-moz-window-inactive[disabled="true"] > .toolbarbutton-icon,
|
||||
#main-window:not([customizing]) .toolbarbutton-1:-moz-window-inactive[disabled="true"] > .toolbarbutton-badge-container > .toolbarbutton-icon,
|
||||
#main-window:not([customizing]) .toolbarbutton-1:-moz-window-inactive[disabled="true"] > .toolbarbutton-badge-stack > .toolbarbutton-icon,
|
||||
#main-window:not([customizing]) .toolbarbutton-1:-moz-window-inactive > .toolbarbutton-menubutton-button[disabled="true"] > .toolbarbutton-icon {
|
||||
opacity: .25;
|
||||
}
|
||||
|
@ -233,14 +233,14 @@ toolbarpaletteitem[notransition][place="panel"] {
|
||||
}
|
||||
|
||||
toolbarpaletteitem > toolbarbutton > .toolbarbutton-icon,
|
||||
toolbarpaletteitem > toolbarbutton > .toolbarbutton-badge-container > .toolbarbutton-icon,
|
||||
toolbarpaletteitem > toolbarbutton > .toolbarbutton-badge-stack > .toolbarbutton-icon,
|
||||
toolbarpaletteitem > toolbaritem.panel-wide-item,
|
||||
toolbarpaletteitem > toolbarbutton[type="menu-button"] {
|
||||
transition: transform .3s cubic-bezier(.6, 2, .75, 1.5) !important;
|
||||
}
|
||||
|
||||
toolbarpaletteitem[mousedown] > toolbarbutton > .toolbarbutton-icon,
|
||||
toolbarpaletteitem[mousedown] > toolbarbutton > .toolbarbutton-badge-container > .toolbarbutton-icon {
|
||||
toolbarpaletteitem[mousedown] > toolbarbutton > .toolbarbutton-badge-stack > .toolbarbutton-icon {
|
||||
transform: scale(1.3);
|
||||
}
|
||||
|
||||
|
@ -312,9 +312,9 @@ toolbarpaletteitem[place="panel"]:not([haswideitem=true]) > .toolbarbutton-1 {
|
||||
|
||||
/* Help SDK buttons fit in. */
|
||||
toolbarpaletteitem[place="palette"] > toolbarbutton[constrain-size="true"] > .toolbarbutton-icon,
|
||||
toolbarpaletteitem[place="palette"] > toolbarbutton[constrain-size="true"] > .toolbarbutton-badge-container > .toolbarbutton-icon,
|
||||
toolbarpaletteitem[place="palette"] > toolbarbutton[constrain-size="true"] > .toolbarbutton-badge-stack > .toolbarbutton-icon,
|
||||
toolbarbutton[constrain-size="true"][cui-areatype="menu-panel"] > .toolbarbutton-icon,
|
||||
toolbarbutton[constrain-size="true"][cui-areatype="menu-panel"] > .toolbarbutton-badge-container > .toolbarbutton-icon {
|
||||
toolbarbutton[constrain-size="true"][cui-areatype="menu-panel"] > .toolbarbutton-badge-stack > .toolbarbutton-icon {
|
||||
height: 32px;
|
||||
width: 32px;
|
||||
}
|
||||
@ -432,10 +432,10 @@ toolbaritem[cui-areatype="menu-panel"][sdkstylewidget="true"]:not(.panel-wide-it
|
||||
|
||||
.panelUI-grid .toolbarbutton-1 > .toolbarbutton-menubutton-button > .toolbarbutton-icon,
|
||||
.panelUI-grid .toolbarbutton-1 > .toolbarbutton-icon,
|
||||
.panelUI-grid .toolbarbutton-1 > .toolbarbutton-badge-container,
|
||||
.panelUI-grid .toolbarbutton-1 > .toolbarbutton-badge-stack,
|
||||
.customization-palette .toolbarbutton-1 > .toolbarbutton-menubutton-button > .toolbarbutton-icon,
|
||||
.customization-palette .toolbarbutton-1 > .toolbarbutton-icon,
|
||||
.customization-palette .toolbarbutton-1 > .toolbarbutton-badge-container,
|
||||
.customization-palette .toolbarbutton-1 > .toolbarbutton-badge-stack,
|
||||
.panelUI-grid #bookmarks-toolbar-placeholder > .toolbarbutton-icon,
|
||||
.customization-palette #bookmarks-toolbar-placeholder > .toolbarbutton-icon,
|
||||
.panel-customization-placeholder-child > .toolbarbutton-icon {
|
||||
@ -461,8 +461,8 @@ toolbaritem[cui-areatype="menu-panel"][sdkstylewidget="true"]:not(.panel-wide-it
|
||||
/* above we treat the container as the icon for the margins, that is so the
|
||||
/* badge itself is positioned correctly. Here we make sure that the icon itself
|
||||
/* has the minimum size we want, but no padding/margin. */
|
||||
.panelUI-grid .toolbarbutton-1 > .toolbarbutton-badge-container > .toolbarbutton-icon,
|
||||
.customization-palette .toolbarbutton-1 > .toolbarbutton-badge-container > .toolbarbutton-icon {
|
||||
.panelUI-grid .toolbarbutton-1 > .toolbarbutton-badge-stack > .toolbarbutton-icon,
|
||||
.customization-palette .toolbarbutton-1 > .toolbarbutton-badge-stack > .toolbarbutton-icon {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
min-width: 32px;
|
||||
|
@ -191,39 +191,39 @@
|
||||
-moz-image-region: rect(0, 832px, 32px, 800px);
|
||||
}
|
||||
|
||||
#loop-button[cui-areatype="menu-panel"] > .toolbarbutton-badge-container,
|
||||
toolbarpaletteitem[place="palette"] > #loop-button > .toolbarbutton-badge-container {
|
||||
#loop-button[cui-areatype="menu-panel"],
|
||||
toolbarpaletteitem[place="palette"] > #loop-button {
|
||||
list-style-image: url(chrome://browser/skin/loop/menuPanel.png);
|
||||
-moz-image-region: rect(0, 32px, 32px, 0);
|
||||
}
|
||||
|
||||
/* Make sure that the state icons are not shown in the customization palette. */
|
||||
toolbarpaletteitem[place="palette"] > #loop-button > .toolbarbutton-badge-container {
|
||||
toolbarpaletteitem[place="palette"] > #loop-button {
|
||||
-moz-image-region: rect(0, 32px, 32px, 0) !important;
|
||||
}
|
||||
|
||||
#loop-button[cui-areatype="menu-panel"][state="disabled"] > .toolbarbutton-badge-container,
|
||||
#loop-button[cui-areatype="menu-panel"][disabled="true"] > .toolbarbutton-badge-container {
|
||||
#loop-button[cui-areatype="menu-panel"][state="disabled"],
|
||||
#loop-button[cui-areatype="menu-panel"][disabled="true"] {
|
||||
-moz-image-region: rect(0, 64px, 32px, 32px);
|
||||
}
|
||||
|
||||
#loop-button[cui-areatype="menu-panel"]:not([disabled="true"])[state="error"] > .toolbarbutton-badge-container {
|
||||
#loop-button[cui-areatype="menu-panel"]:not([disabled="true"])[state="error"] {
|
||||
-moz-image-region: rect(0, 96px, 32px, 64px);
|
||||
}
|
||||
|
||||
#loop-button[cui-areatype="menu-panel"]:not([disabled="true"])[state="action"] > .toolbarbutton-badge-container {
|
||||
#loop-button[cui-areatype="menu-panel"]:not([disabled="true"])[state="action"] {
|
||||
-moz-image-region: rect(0, 128px, 32px, 96px);
|
||||
}
|
||||
|
||||
#loop-button[cui-areatype="menu-panel"]:not([disabled="true"])[state="action"]:-moz-any(:hover,:hover:active,[open]) > .toolbarbutton-badge-container {
|
||||
#loop-button[cui-areatype="menu-panel"]:not([disabled="true"])[state="action"]:-moz-any(:hover,:hover:active,[open]) {
|
||||
-moz-image-region: rect(0, 160px, 32px, 128px);
|
||||
}
|
||||
|
||||
#loop-button[cui-areatype="menu-panel"]:not([disabled="true"])[state="active"] > .toolbarbutton-badge-container {
|
||||
#loop-button[cui-areatype="menu-panel"]:not([disabled="true"])[state="active"] {
|
||||
-moz-image-region: rect(0, 192px, 32px, 160px);
|
||||
}
|
||||
|
||||
#loop-button[cui-areatype="menu-panel"]:not([disabled="true"])[state="active"]:-moz-any(:hover,:hover:active,[open]) > .toolbarbutton-badge-container {
|
||||
#loop-button[cui-areatype="menu-panel"]:not([disabled="true"])[state="active"]:-moz-any(:hover,:hover:active,[open]) {
|
||||
-moz-image-region: rect(0, 224px, 32px, 192px);
|
||||
}
|
||||
|
||||
@ -375,39 +375,39 @@
|
||||
-moz-image-region: rect(64px, 1984px, 128px, 1920px);
|
||||
}
|
||||
|
||||
#loop-button[cui-areatype="menu-panel"] > .toolbarbutton-badge-container,
|
||||
toolbarpaletteitem[place="palette"] > #loop-button > .toolbarbutton-badge-container {
|
||||
#loop-button[cui-areatype="menu-panel"],
|
||||
toolbarpaletteitem[place="palette"] > #loop-button {
|
||||
list-style-image: url(chrome://browser/skin/loop/menuPanel@2x.png);
|
||||
-moz-image-region: rect(0, 64px, 64px, 0);
|
||||
}
|
||||
|
||||
/* Make sure that the state icons are not shown in the customization palette. */
|
||||
toolbarpaletteitem[place="palette"] > #loop-button > .toolbarbutton-badge-container {
|
||||
toolbarpaletteitem[place="palette"] > #loop-button {
|
||||
-moz-image-region: rect(0, 64px, 64px, 0) !important;
|
||||
}
|
||||
|
||||
#loop-button[cui-areatype="menu-panel"][state="disabled"] > .toolbarbutton-badge-container,
|
||||
#loop-button[cui-areatype="menu-panel"][disabled="true"] > .toolbarbutton-badge-container {
|
||||
#loop-button[cui-areatype="menu-panel"][state="disabled"],
|
||||
#loop-button[cui-areatype="menu-panel"][disabled="true"] {
|
||||
-moz-image-region: rect(0, 128px, 64px, 64px);
|
||||
}
|
||||
|
||||
#loop-button[cui-areatype="menu-panel"]:not([disabled="true"])[state="error"] > .toolbarbutton-badge-container {
|
||||
#loop-button[cui-areatype="menu-panel"]:not([disabled="true"])[state="error"] {
|
||||
-moz-image-region: rect(0, 192px, 64px, 128px);
|
||||
}
|
||||
|
||||
#loop-button[cui-areatype="menu-panel"]:not([disabled="true"])[state="action"] > .toolbarbutton-badge-container {
|
||||
#loop-button[cui-areatype="menu-panel"]:not([disabled="true"])[state="action"] {
|
||||
-moz-image-region: rect(0, 256px, 64px, 192px);
|
||||
}
|
||||
|
||||
#loop-button[cui-areatype="menu-panel"]:not([disabled="true"])[state="action"]:-moz-any(:hover,:hover:active,[open]) > .toolbarbutton-badge-container {
|
||||
#loop-button[cui-areatype="menu-panel"]:not([disabled="true"])[state="action"]:-moz-any(:hover,:hover:active,[open]) {
|
||||
-moz-image-region: rect(0, 320px, 64px, 256px);
|
||||
}
|
||||
|
||||
#loop-button[cui-areatype="menu-panel"]:not([disabled="true"])[state="active"] > .toolbarbutton-badge-container {
|
||||
#loop-button[cui-areatype="menu-panel"]:not([disabled="true"])[state="active"] {
|
||||
-moz-image-region: rect(0, 384px, 64px, 320px);
|
||||
}
|
||||
|
||||
#loop-button[cui-areatype="menu-panel"]:not([disabled="true"])[state="active"]:-moz-any(:hover,:hover:active,[open]) > .toolbarbutton-badge-container {
|
||||
#loop-button[cui-areatype="menu-panel"]:not([disabled="true"])[state="active"]:-moz-any(:hover,:hover:active,[open]) {
|
||||
-moz-image-region: rect(0, 448px, 64px, 384px);
|
||||
}
|
||||
|
||||
|
@ -184,37 +184,37 @@ toolbar[brighttext] #sync-button[status="active"] {
|
||||
-moz-image-region: rect(0, 720px, 18px, 702px);
|
||||
}
|
||||
|
||||
#loop-button > .toolbarbutton-badge-container {
|
||||
#loop-button {
|
||||
list-style-image: url(chrome://browser/skin/loop/toolbar.png);
|
||||
-moz-image-region: rect(0, 18px, 18px, 0);
|
||||
}
|
||||
|
||||
toolbar[brighttext] #loop-button > .toolbarbutton-badge-container {
|
||||
toolbar[brighttext] #loop-button {
|
||||
list-style-image: url(chrome://browser/skin/loop/toolbar-inverted.png);
|
||||
}
|
||||
|
||||
#loop-button[state="disabled"] > .toolbarbutton-badge-container,
|
||||
#loop-button[disabled="true"] > .toolbarbutton-badge-container {
|
||||
#loop-button[state="disabled"],
|
||||
#loop-button[disabled="true"] {
|
||||
-moz-image-region: rect(0, 36px, 18px, 18px);
|
||||
}
|
||||
|
||||
#loop-button:not([disabled="true"])[state="error"] > .toolbarbutton-badge-container {
|
||||
#loop-button:not([disabled="true"])[state="error"] {
|
||||
-moz-image-region: rect(0, 54px, 18px, 36px);
|
||||
}
|
||||
|
||||
#loop-button:not([disabled="true"])[state="action"] > .toolbarbutton-badge-container {
|
||||
#loop-button:not([disabled="true"])[state="action"] {
|
||||
-moz-image-region: rect(0, 72px, 18px, 54px);
|
||||
}
|
||||
|
||||
#loop-button:not([disabled="true"])[state="action"]:-moz-any(:hover,:hover:active,[open]) > .toolbarbutton-badge-container {
|
||||
#loop-button:not([disabled="true"])[state="action"]:-moz-any(:hover,:hover:active,[open]) {
|
||||
-moz-image-region: rect(0, 90px, 18px, 72px);
|
||||
}
|
||||
|
||||
#loop-button:not([disabled="true"])[state="active"] > .toolbarbutton-badge-container {
|
||||
#loop-button:not([disabled="true"])[state="active"] {
|
||||
-moz-image-region: rect(0, 108px, 18px, 90px);
|
||||
}
|
||||
|
||||
#loop-button:not([disabled="true"])[state="active"]:-moz-any(:hover,:hover:active,[open]) > .toolbarbutton-badge-container {
|
||||
#loop-button:not([disabled="true"])[state="active"]:-moz-any(:hover,:hover:active,[open]) {
|
||||
-moz-image-region: rect(0, 126px, 18px, 108px);
|
||||
}
|
||||
|
||||
@ -430,37 +430,37 @@ toolbar[brighttext] #loop-button > .toolbarbutton-badge-container {
|
||||
%endif
|
||||
}
|
||||
|
||||
#loop-button > .toolbarbutton-badge-container {
|
||||
#loop-button {
|
||||
list-style-image: url("chrome://browser/skin/loop/toolbar@2x.png");
|
||||
-moz-image-region: rect(0, 36px, 36px, 0);
|
||||
}
|
||||
|
||||
toolbar[brighttext] #loop-button > .toolbarbutton-badge-container {
|
||||
toolbar[brighttext] #loop-button {
|
||||
list-style-image: url("chrome://browser/skin/loop/toolbar-inverted@2x.png");
|
||||
}
|
||||
|
||||
#loop-button[state="disabled"] > .toolbarbutton-badge-container,
|
||||
#loop-button[disabled="true"] > .toolbarbutton-badge-container {
|
||||
#loop-button[state="disabled"],
|
||||
#loop-button[disabled="true"] {
|
||||
-moz-image-region: rect(0, 72px, 36px, 36px);
|
||||
}
|
||||
|
||||
#loop-button:not([disabled="true"])[state="error"] > .toolbarbutton-badge-container {
|
||||
#loop-button:not([disabled="true"])[state="error"] {
|
||||
-moz-image-region: rect(0, 108px, 36px, 72px);
|
||||
}
|
||||
|
||||
#loop-button:not([disabled="true"])[state="action"] > .toolbarbutton-badge-container {
|
||||
#loop-button:not([disabled="true"])[state="action"] {
|
||||
-moz-image-region: rect(0, 144px, 36px, 108px);
|
||||
}
|
||||
|
||||
#loop-button:not([disabled="true"])[state="action"]:-moz-any(:hover,:hover:active,[open]) > .toolbarbutton-badge-container {
|
||||
#loop-button:not([disabled="true"])[state="action"]:-moz-any(:hover,:hover:active,[open]) {
|
||||
-moz-image-region: rect(0, 180px, 36px, 144px);
|
||||
}
|
||||
|
||||
#loop-button:not([disabled="true"])[state="active"] > .toolbarbutton-badge-container {
|
||||
#loop-button:not([disabled="true"])[state="active"] {
|
||||
-moz-image-region: rect(0, 216px, 36px, 180px);
|
||||
}
|
||||
|
||||
#loop-button:not([disabled="true"])[state="active"]:-moz-any(:hover,:hover:active,[open]) > .toolbarbutton-badge-container {
|
||||
#loop-button:not([disabled="true"])[state="active"]:-moz-any(:hover,:hover:active,[open]) {
|
||||
-moz-image-region: rect(0, 252px, 36px, 216px);
|
||||
}
|
||||
}
|
||||
|
@ -595,13 +595,13 @@ menuitem.bookmark-item {
|
||||
list-style-image: url("chrome://browser/skin/Toolbar-lunaSilver.png");
|
||||
}
|
||||
|
||||
#loop-button > .toolbarbutton-badge-container {
|
||||
#loop-button {
|
||||
list-style-image: url(chrome://browser/skin/loop/toolbar-lunaSilver.png)
|
||||
}
|
||||
}
|
||||
|
||||
@media (-moz-windows-theme: luna-silver) and (min-resolution: 1.1dppx) {
|
||||
#loop-button > .toolbarbutton-badge-container {
|
||||
#loop-button {
|
||||
list-style-image: url(chrome://browser/skin/loop/toolbar-lunaSilver@2x.png)
|
||||
}
|
||||
}
|
||||
@ -676,7 +676,7 @@ toolbar[brighttext] .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker {
|
||||
.findbar-button > .toolbarbutton-text,
|
||||
#nav-bar .toolbarbutton-1 > .toolbarbutton-icon,
|
||||
#nav-bar .toolbarbutton-1 > .toolbarbutton-text,
|
||||
#nav-bar .toolbarbutton-1 > .toolbarbutton-badge-container,
|
||||
#nav-bar .toolbarbutton-1 > .toolbarbutton-badge-stack,
|
||||
#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-button > .toolbarbutton-icon,
|
||||
#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon,
|
||||
@conditionalForwardWithUrlbar@ > .toolbarbutton-1:-moz-any([disabled],:not([open]):not([disabled]):not(:active)) > .toolbarbutton-icon {
|
||||
@ -689,7 +689,7 @@ toolbar[brighttext] .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker {
|
||||
|
||||
toolbarbutton[cui-areatype="toolbar"] > :-moz-any(@nestedButtons@) > .toolbarbutton-icon,
|
||||
:-moz-any(@primaryToolbarButtons@):-moz-any([cui-areatype="toolbar"],:not([cui-areatype])):not(:-moz-any(@nestedButtons@)) > .toolbarbutton-icon,
|
||||
:-moz-any(@primaryToolbarButtons@):-moz-any([cui-areatype="toolbar"],:not([cui-areatype])) > .toolbarbutton-badge-container > .toolbarbutton-icon,
|
||||
:-moz-any(@primaryToolbarButtons@):-moz-any([cui-areatype="toolbar"],:not([cui-areatype])) > .toolbarbutton-badge-stack > .toolbarbutton-icon,
|
||||
:-moz-any(@primaryToolbarButtons@):-moz-any([cui-areatype="toolbar"],:not([cui-areatype])) > .toolbarbutton-menubutton-button > .toolbarbutton-icon,
|
||||
#bookmarks-menu-button[cui-areatype="toolbar"] > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon {
|
||||
width: 18px;
|
||||
@ -730,7 +730,7 @@ toolbarbutton[cui-areatype="toolbar"] > :-moz-any(@nestedButtons@) > .toolbarbut
|
||||
.findbar-button > .toolbarbutton-text,
|
||||
#nav-bar .toolbarbutton-1 > .toolbarbutton-icon,
|
||||
#nav-bar .toolbarbutton-1 > .toolbarbutton-text,
|
||||
#nav-bar .toolbarbutton-1 > .toolbarbutton-badge-container,
|
||||
#nav-bar .toolbarbutton-1 > .toolbarbutton-badge-stack,
|
||||
#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-button > .toolbarbutton-icon,
|
||||
#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon {
|
||||
background-color: hsla(210,32%,93%,0);
|
||||
@ -746,14 +746,14 @@ toolbarbutton[cui-areatype="toolbar"] > :-moz-any(@nestedButtons@) > .toolbarbut
|
||||
}
|
||||
|
||||
#nav-bar .toolbarbutton-1:not(:-moz-any(@primaryToolbarButtons@)) > .toolbarbutton-icon,
|
||||
#nav-bar .toolbarbutton-1:not(:-moz-any(@primaryToolbarButtons@)) > .toolbarbutton-badge-container,
|
||||
#nav-bar .toolbarbutton-1:not(:-moz-any(@primaryToolbarButtons@)) > .toolbarbutton-badge-stack,
|
||||
#nav-bar .toolbarbutton-1:not(:-moz-any(@primaryToolbarButtons@)) > .toolbarbutton-menubutton-button > .toolbarbutton-icon {
|
||||
padding: calc(var(--toolbarbutton-vertical-inner-padding) + 1px) 7px;
|
||||
}
|
||||
|
||||
/* Help SDK icons fit: */
|
||||
toolbarbutton[constrain-size="true"][cui-areatype="toolbar"] > .toolbarbutton-icon,
|
||||
toolbarbutton[constrain-size="true"][cui-areatype="toolbar"] > .toolbarbutton-badge-container > .toolbarbutton-icon {
|
||||
toolbarbutton[constrain-size="true"][cui-areatype="toolbar"] > .toolbarbutton-badge-stack > .toolbarbutton-icon {
|
||||
width: 16px;
|
||||
}
|
||||
|
||||
@ -823,7 +823,7 @@ toolbarbutton[constrain-size="true"][cui-areatype="toolbar"] > .toolbarbutton-ba
|
||||
#nav-bar .toolbarbutton-1:not([disabled=true]):-moz-any(:hover,[open]) > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon,
|
||||
#nav-bar .toolbarbutton-1:not([disabled=true]):not([checked]):not([open]):not(:active):hover > .toolbarbutton-icon,
|
||||
#nav-bar .toolbarbutton-1:not([disabled=true]):not([checked]):not([open]):not(:active):hover > .toolbarbutton-text,
|
||||
#nav-bar .toolbarbutton-1:not([disabled=true]):not([checked]):not([open]):not(:active):hover > .toolbarbutton-badge-container,
|
||||
#nav-bar .toolbarbutton-1:not([disabled=true]):not([checked]):not([open]):not(:active):hover > .toolbarbutton-badge-stack,
|
||||
@conditionalForwardWithUrlbar@ > #forward-button:not([open]):not(:active):not([disabled]):hover > .toolbarbutton-icon,
|
||||
#nav-bar .toolbarbutton-1:not([buttonover]):not([open]):not(:active):hover > .toolbarbutton-menubutton-dropmarker:not([disabled]) > .dropmarker-icon {
|
||||
background: var(--toolbarbutton-hover-background);
|
||||
@ -868,7 +868,7 @@ toolbarbutton[constrain-size="true"][cui-areatype="toolbar"] > .toolbarbutton-ba
|
||||
#nav-bar .toolbarbutton-1[open] > .toolbarbutton-menubutton-dropmarker:not([disabled=true]) > .dropmarker-icon,
|
||||
#nav-bar .toolbarbutton-1:not([disabled=true]):-moz-any([open],[checked],:hover:active) > .toolbarbutton-icon,
|
||||
#nav-bar .toolbarbutton-1:not([disabled=true]):-moz-any([open],[checked],:hover:active) > .toolbarbutton-text,
|
||||
#nav-bar .toolbarbutton-1:not([disabled=true]):-moz-any([open],[checked],:hover:active) > .toolbarbutton-badge-container {
|
||||
#nav-bar .toolbarbutton-1:not([disabled=true]):-moz-any([open],[checked],:hover:active) > .toolbarbutton-badge-stack {
|
||||
background: var(--toolbarbutton-active-background);
|
||||
border-color: var(--toolbarbutton-active-bordercolor);
|
||||
box-shadow: var(--toolbarbutton-active-boxshadow);
|
||||
@ -884,7 +884,7 @@ toolbarbutton[constrain-size="true"][cui-areatype="toolbar"] > .toolbarbutton-ba
|
||||
#nav-bar .toolbarbutton-1[open] > .toolbarbutton-menubutton-dropmarker:not([disabled]) > .dropmarker-icon,
|
||||
#nav-bar .toolbarbutton-1:not([disabled]):-moz-any([open],[checked],:hover:active) > .toolbarbutton-icon,
|
||||
#nav-bar .toolbarbutton-1:not([disabled]):-moz-any([open],[checked],:hover:active) > .toolbarbutton-text,
|
||||
#nav-bar .toolbarbutton-1:not([disabled]):-moz-any([open],[checked],:hover:active) > .toolbarbutton-badge-container {
|
||||
#nav-bar .toolbarbutton-1:not([disabled]):-moz-any([open],[checked],:hover:active) > .toolbarbutton-badge-stack {
|
||||
text-shadow: none;
|
||||
transition: none;
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ class DomainPolicyClone;
|
||||
[ptr] native JSObjectPtr(JSObject);
|
||||
[ptr] native DomainPolicyClonePtr(mozilla::dom::DomainPolicyClone);
|
||||
|
||||
[scriptable, uuid(f4c578b8-5bac-4ba1-9582-f1140e09a3b4)]
|
||||
[scriptable, uuid(50418f5c-b0d8-42c3-ba5d-efffb6927e1c)]
|
||||
interface nsIScriptSecurityManager : nsISupports
|
||||
{
|
||||
/**
|
||||
@ -201,6 +201,20 @@ interface nsIScriptSecurityManager : nsISupports
|
||||
[implicit_jscontext]
|
||||
nsIPrincipal createNullPrincipal(in jsval originAttributes);
|
||||
|
||||
/**
|
||||
* Creates an expanded principal whose capabilities are the union of the
|
||||
* given principals. An expanded principal has an asymmetric privilege
|
||||
* relationship with its sub-principals (that is to say, it subsumes the
|
||||
* sub-principals, but the sub-principals do not subsume it), even if
|
||||
* there's only one. This presents a legitimate use-case for making an
|
||||
* expanded principal around a single sub-principal, which we do frequently.
|
||||
*
|
||||
* Expanded principals cannot have origin attributes themselves, but rather
|
||||
* have them through their sub-principals - so we don't accept them here.
|
||||
*/
|
||||
nsIPrincipal createExpandedPrincipal([array, size_is(aLength)] in nsIPrincipal aPrincipalArray,
|
||||
[optional] in unsigned long aLength);
|
||||
|
||||
/**
|
||||
* Returns OK if aSourceURI and target have the same "origin"
|
||||
* (scheme, host, and port).
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* vim: set ts=4 et sw=4 tw=80: */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
@ -1027,6 +1027,21 @@ nsScriptSecurityManager::CreateNullPrincipal(JS::Handle<JS::Value> aOriginAttrib
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsScriptSecurityManager::CreateExpandedPrincipal(nsIPrincipal** aPrincipalArray, uint32_t aLength,
|
||||
nsIPrincipal** aResult)
|
||||
{
|
||||
nsTArray<nsCOMPtr<nsIPrincipal>> principals;
|
||||
principals.SetCapacity(aLength);
|
||||
for (uint32_t i = 0; i < aLength; ++i) {
|
||||
principals.AppendElement(aPrincipalArray[i]);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIPrincipal> p = new nsExpandedPrincipal(principals);
|
||||
p.forget(aResult);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsScriptSecurityManager::GetAppCodebasePrincipal(nsIURI* aURI,
|
||||
uint32_t aAppId,
|
||||
|
@ -47,7 +47,7 @@ function run_test() {
|
||||
var nullPrin = Cu.getObjectPrincipal(new Cu.Sandbox(null));
|
||||
do_check_true(/^moz-nullprincipal:\{([0-9]|[a-z]|\-){36}\}$/.test(nullPrin.origin));
|
||||
checkOriginAttributes(nullPrin);
|
||||
var ep = Cu.getObjectPrincipal(new Cu.Sandbox([exampleCom, nullPrin, exampleOrg]));
|
||||
var ep = ssm.createExpandedPrincipal([exampleCom, nullPrin, exampleOrg]);
|
||||
checkOriginAttributes(ep);
|
||||
checkCrossOrigin(exampleCom, exampleOrg);
|
||||
checkCrossOrigin(exampleOrg, nullPrin);
|
||||
|
30
configure.in
30
configure.in
@ -476,17 +476,37 @@ dnl Special MacOS X checks
|
||||
dnl ========================================================
|
||||
|
||||
if test -n "$MACOSX_DEPLOYMENT_TARGET" -a -n "$MOZ_RUST"; then
|
||||
AC_MSG_CHECKING([MacOS X compatibility with rust])
|
||||
# rustc doesn't support MacOS X 10.6 or earlier.
|
||||
AC_MSG_CHECKING([rustc compatibility with MacOS X])
|
||||
# Stock rustc doesn't support MacOS X 10.6 or earlier.
|
||||
# https://github.com/rust-lang/rust/issues/25342
|
||||
_MACOSX_TARGET_MINOR=`echo "$MACOSX_DEPLOYMENT_TARGET" | cut -d. -f2`
|
||||
if test "$_MACOSX_TARGET_MINOR" -lt 7; then
|
||||
AC_MSG_ERROR([rustc does not support MacOS X $MACOSX_DEPLOYMENT_TARGET
|
||||
Add 'ac_add_options --enable-macos-target=10.7' (or later)
|
||||
to mozconfig, or disable rust support.])
|
||||
dnl Test C linkage against rust code to see if the rust
|
||||
dnl toolchain output is compatible.
|
||||
cat > conftest.rs <<EOF
|
||||
[#[no_mangle]]
|
||||
pub extern fn rusty_answer() -> u8 { 42 }
|
||||
EOF
|
||||
ac_try="$RUSTC --crate-type staticlib -o conftest.a conftest.rs >/dev/null"
|
||||
AC_TRY_EVAL(ac_try)
|
||||
save_LDFLAGS=$LDFLAGS
|
||||
LDFLAGS="$LDFLAGS conftest.a -lpthread -lm"
|
||||
AC_TRY_LINK_FUNC([rusty_answer], [
|
||||
AC_MSG_RESULT([$MACOSX_DEPLOYMENT_TARGET is ok with this rustc])
|
||||
], [
|
||||
AC_MSG_RESULT([cannot link on $MACOSX_DEPLOYMENT_TARGET])
|
||||
MOZ_RUST=
|
||||
])
|
||||
LDFLAGS=$save_LDFLAGS
|
||||
rm -rf conftest*
|
||||
else
|
||||
AC_MSG_RESULT([$MACOSX_DEPLOYMENT_TARGET is ok])
|
||||
fi
|
||||
if test -z "$MOZ_RUST"; then
|
||||
AC_MSG_ERROR([rustc does not support MacOS X $MACOSX_DEPLOYMENT_TARGET
|
||||
Add 'ac_add_options --enable-macos-target=10.7' (or later)
|
||||
to mozconfig, disable rust support, or use an alternate toolchain.])
|
||||
fi
|
||||
fi
|
||||
|
||||
dnl ========================================================
|
||||
|
@ -1315,7 +1315,9 @@ nsSHistory::RemoveDuplicate(int32_t aIndex, bool aKeepNext)
|
||||
nsCOMPtr<nsISHTransaction> txToRemove, txToKeep, txNext, txPrev;
|
||||
GetTransactionAtIndex(aIndex, getter_AddRefs(txToRemove));
|
||||
GetTransactionAtIndex(compareIndex, getter_AddRefs(txToKeep));
|
||||
NS_ENSURE_TRUE(txToRemove, false);
|
||||
if (!txToRemove) {
|
||||
return false;
|
||||
}
|
||||
NS_ENSURE_TRUE(txToKeep, false);
|
||||
txToRemove->GetNext(getter_AddRefs(txNext));
|
||||
txToRemove->GetPrev(getter_AddRefs(txPrev));
|
||||
|
@ -207,8 +207,7 @@ NS_IMPL_ADDREF(AudioChannelService)
|
||||
NS_IMPL_RELEASE(AudioChannelService)
|
||||
|
||||
AudioChannelService::AudioChannelService()
|
||||
: mDisabled(false)
|
||||
, mDefChannelChildID(CONTENT_PROCESS_ID_UNKNOWN)
|
||||
: mDefChannelChildID(CONTENT_PROCESS_ID_UNKNOWN)
|
||||
, mTelephonyChannel(false)
|
||||
, mContentOrNormalChannel(false)
|
||||
, mAnyChannel(false)
|
||||
@ -238,10 +237,6 @@ void
|
||||
AudioChannelService::RegisterAudioChannelAgent(AudioChannelAgent* aAgent,
|
||||
AudioChannel aChannel)
|
||||
{
|
||||
if (mDisabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint64_t windowID = aAgent->WindowID();
|
||||
AudioChannelWindow* winData = GetWindowData(windowID);
|
||||
if (!winData) {
|
||||
@ -272,10 +267,6 @@ AudioChannelService::RegisterAudioChannelAgent(AudioChannelAgent* aAgent,
|
||||
void
|
||||
AudioChannelService::UnregisterAudioChannelAgent(AudioChannelAgent* aAgent)
|
||||
{
|
||||
if (mDisabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
AudioChannelWindow* winData = GetWindowData(aAgent->WindowID());
|
||||
if (!winData) {
|
||||
return;
|
||||
@ -466,8 +457,8 @@ AudioChannelService::Observe(nsISupports* aSubject, const char* aTopic,
|
||||
const char16_t* aData)
|
||||
{
|
||||
if (!strcmp(aTopic, "xpcom-shutdown")) {
|
||||
mDisabled = true;
|
||||
mWindows.Clear();
|
||||
Shutdown();
|
||||
}
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
|
@ -43,11 +43,6 @@ public:
|
||||
*/
|
||||
static already_AddRefed<AudioChannelService> GetOrCreate();
|
||||
|
||||
/**
|
||||
* Shutdown the singleton.
|
||||
*/
|
||||
static void Shutdown();
|
||||
|
||||
static bool IsAudioChannelMutedByDefault();
|
||||
|
||||
/**
|
||||
@ -136,6 +131,11 @@ private:
|
||||
AudioChannelService();
|
||||
~AudioChannelService();
|
||||
|
||||
/**
|
||||
* Shutdown the singleton.
|
||||
*/
|
||||
static void Shutdown();
|
||||
|
||||
void MaybeSendStatusUpdate();
|
||||
|
||||
bool ContentOrNormalChannelIsActive();
|
||||
@ -204,8 +204,6 @@ private:
|
||||
nsTArray<SpeakerManagerService*> mSpeakerManager;
|
||||
#endif
|
||||
|
||||
bool mDisabled;
|
||||
|
||||
nsCOMPtr<nsIRunnable> mRunnable;
|
||||
|
||||
uint64_t mDefChannelChildID;
|
||||
|
@ -717,16 +717,6 @@ nsFocusManager::WindowRaised(nsIDOMWindow* aWindow)
|
||||
if (!currentWindow)
|
||||
return NS_OK;
|
||||
|
||||
nsCOMPtr<nsIDocShell> currentDocShell = currentWindow->GetDocShell();
|
||||
|
||||
nsCOMPtr<nsIPresShell> presShell = currentDocShell->GetPresShell();
|
||||
if (presShell) {
|
||||
// disable selection mousedown state on activation
|
||||
// XXXndeakin P3 not sure if this is necessary, but it doesn't hurt
|
||||
nsRefPtr<nsFrameSelection> frameSelection = presShell->FrameSelection();
|
||||
frameSelection->SetDragState(false);
|
||||
}
|
||||
|
||||
// If there is no nsIXULWindow, then this is an embedded or child process window.
|
||||
// Pass false for aWindowRaised so that commands get updated.
|
||||
nsCOMPtr<nsIXULWindow> xulWin(do_GetInterface(baseWindow));
|
||||
@ -764,6 +754,19 @@ nsFocusManager::WindowLowered(nsIDOMWindow* aWindow)
|
||||
// clear the mouse capture as the active window has changed
|
||||
nsIPresShell::SetCapturingContent(nullptr, 0);
|
||||
|
||||
// In addition, reset the drag state to ensure that we are no longer in
|
||||
// drag-select mode.
|
||||
if (mFocusedWindow) {
|
||||
nsCOMPtr<nsIDocShell> docShell = mFocusedWindow->GetDocShell();
|
||||
if (docShell) {
|
||||
nsCOMPtr<nsIPresShell> presShell = docShell->GetPresShell();
|
||||
if (presShell) {
|
||||
nsRefPtr<nsFrameSelection> frameSelection = presShell->FrameSelection();
|
||||
frameSelection->SetDragState(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If this is a parent or single process window, send the deactivate event.
|
||||
// Events for child process windows will be sent when ParentActivated
|
||||
// is called.
|
||||
|
@ -17,7 +17,9 @@ const Cu = Components.utils;
|
||||
sync_test,
|
||||
async_test,
|
||||
rpc_test,
|
||||
lifetime_test
|
||||
lifetime_test,
|
||||
cancel_test,
|
||||
cancel_test2,
|
||||
];
|
||||
|
||||
function go() {
|
||||
@ -266,3 +268,72 @@ function lifetime_test(finish)
|
||||
sendRpcMessage("cpows:lifetime_test_2");
|
||||
});
|
||||
}
|
||||
|
||||
function cancel_test(finish)
|
||||
{
|
||||
if (!is_remote) {
|
||||
// No point in doing this in single-process mode.
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
let fin1 = false, fin2 = false;
|
||||
|
||||
// CPOW from the parent runs f. When it sends a sync message, the
|
||||
// CPOW is canceled. The parent starts running again immediately
|
||||
// after the CPOW is canceled; f also continues running.
|
||||
function f() {
|
||||
let res = sendSyncMessage("cpows:cancel_sync_message");
|
||||
ok(res[0] == 12, "cancel_sync_message result correct");
|
||||
fin1 = true;
|
||||
if (fin1 && fin2) finish();
|
||||
}
|
||||
|
||||
sendAsyncMessage("cpows:cancel_test", null, {f: f});
|
||||
addMessageListener("cpows:cancel_test_done", msg => {
|
||||
fin2 = true;
|
||||
if (fin1 && fin2) finish();
|
||||
});
|
||||
}
|
||||
|
||||
function cancel_test2(finish)
|
||||
{
|
||||
if (!is_remote) {
|
||||
// No point in doing this in single-process mode.
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
let fin1 = false, fin2 = false;
|
||||
|
||||
// CPOW from the parent runs f. When it does a sync XHR, the
|
||||
// CPOW is canceled. The parent starts running again immediately
|
||||
// after the CPOW is canceled; f also continues running.
|
||||
function f() {
|
||||
let req = Components.classes["@mozilla.org/xmlextras/xmlhttprequest;1"].
|
||||
createInstance(Components.interfaces.nsIXMLHttpRequest);
|
||||
let fin = false;
|
||||
let reqListener = () => {
|
||||
if (req.readyState != req.DONE) {
|
||||
return;
|
||||
}
|
||||
ok(req.status == 200, "XHR succeeded");
|
||||
fin = true;
|
||||
};
|
||||
|
||||
req.onload = reqListener;
|
||||
req.open("get", "http://example.com", false);
|
||||
req.send(null);
|
||||
|
||||
ok(fin == true, "XHR happened");
|
||||
|
||||
fin1 = true;
|
||||
if (fin1 && fin2) finish();
|
||||
}
|
||||
|
||||
sendAsyncMessage("cpows:cancel_test2", null, {f: f});
|
||||
addMessageListener("cpows:cancel_test2_done", msg => {
|
||||
fin2 = true;
|
||||
if (fin1 && fin2) finish();
|
||||
});
|
||||
}
|
||||
|
@ -364,6 +364,32 @@
|
||||
});
|
||||
}
|
||||
|
||||
function recvCancelTest(msg) {
|
||||
let failed = false;
|
||||
try {
|
||||
msg.objects.f();
|
||||
} catch (e if /cross-process JS call failed/.test(String(e))) {
|
||||
failed = true;
|
||||
}
|
||||
ok(failed, "CPOW should fail due to cancelation");
|
||||
msg.target.messageManager.sendAsyncMessage("cpows:cancel_test_done");
|
||||
}
|
||||
|
||||
function recvCancelSyncMessage() {
|
||||
return 12;
|
||||
}
|
||||
|
||||
function recvCancelTest2(msg) {
|
||||
let failed = false;
|
||||
try {
|
||||
msg.objects.f();
|
||||
} catch (e if /cross-process JS call failed/.test(String(e))) {
|
||||
failed = true;
|
||||
}
|
||||
ok(failed, "CPOW should fail due to cancelation");
|
||||
msg.target.messageManager.sendAsyncMessage("cpows:cancel_test2_done");
|
||||
}
|
||||
|
||||
function run_tests(type) {
|
||||
info("Running tests: " + type);
|
||||
var node = document.getElementById('cpowbrowser_' + type);
|
||||
@ -400,6 +426,9 @@
|
||||
mm.addMessageListener("cpows:postmessage_test", recvPostMessageTest);
|
||||
mm.addMessageListener("cpows:lifetime_test_1", recvLifetimeTest1);
|
||||
mm.addMessageListener("cpows:lifetime_test_2", recvLifetimeTest2);
|
||||
mm.addMessageListener("cpows:cancel_test", recvCancelTest);
|
||||
mm.addMessageListener("cpows:cancel_sync_message", recvCancelSyncMessage);
|
||||
mm.addMessageListener("cpows:cancel_test2", recvCancelTest2);
|
||||
mm.loadFrameScript("chrome://mochitests/content/chrome/dom/base/test/chrome/cpows_child.js", true);
|
||||
}
|
||||
|
||||
|
23
dom/canvas/crashtests/1183363.html
Normal file
23
dom/canvas/crashtests/1183363.html
Normal file
@ -0,0 +1,23 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<script>
|
||||
|
||||
function boom()
|
||||
{
|
||||
var ctx = canvas.getContext('2d');
|
||||
ctx.rect(2, 6, 9, 8);
|
||||
ctx.setTransform(1, 2, 3, 0, 4, 1);
|
||||
setTimeout(function() {
|
||||
ctx.moveTo(0, 1);
|
||||
ctx.isPointInPath(0, 0, 'evenodd');
|
||||
}, 0);
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body onload="boom();">
|
||||
<canvas id="canvas"></canvas>
|
||||
</body>
|
||||
</html>
|
@ -22,3 +22,4 @@ load 896047-2.html
|
||||
load 916128-1.html
|
||||
load 934939-1.html
|
||||
load 1099143-1.html
|
||||
load 1183363.html
|
||||
|
@ -945,7 +945,7 @@ IMEStateManager::SetInputContextForChildProcess(
|
||||
GetActionFocusChangeName(aAction.mFocusChange),
|
||||
sPresContext, sActiveTabParent.get()));
|
||||
|
||||
if (NS_WARN_IF(aTabParent != sActiveTabParent)) {
|
||||
if (aTabParent != sActiveTabParent) {
|
||||
MOZ_LOG(sISMLog, LogLevel::Error,
|
||||
("ISM: IMEStateManager::SetInputContextForChildProcess(), FAILED, "
|
||||
"because non-focused tab parent tries to set input context"));
|
||||
|
@ -9,6 +9,7 @@ interface nsIArray;
|
||||
interface nsIDocument;
|
||||
interface nsIInterceptedChannel;
|
||||
interface nsIPrincipal;
|
||||
interface nsIRunnable;
|
||||
interface nsIURI;
|
||||
|
||||
[scriptable, uuid(52ee2c9d-ee87-4caf-9588-23ae77ff8798)]
|
||||
@ -33,7 +34,7 @@ interface nsIServiceWorkerInfo : nsISupports
|
||||
readonly attribute DOMString waitingCacheName;
|
||||
};
|
||||
|
||||
[scriptable, builtinclass, uuid(ed1cbbf2-0400-4caa-8eb2-b09d21a94e20)]
|
||||
[scriptable, builtinclass, uuid(8d80dd18-597b-4378-b41e-768bfe48dd4f)]
|
||||
interface nsIServiceWorkerManager : nsISupports
|
||||
{
|
||||
/**
|
||||
@ -93,8 +94,11 @@ interface nsIServiceWorkerManager : nsISupports
|
||||
|
||||
/*
|
||||
* Returns a ServiceWorker.
|
||||
* - aLoadFailedRunnable is an optional callback that will fire on main thread if
|
||||
* a ServiceWorker object is returned, but later fails to load for some reason.
|
||||
*/
|
||||
[noscript] nsISupports GetDocumentController(in nsIDOMWindow aWindow);
|
||||
[noscript] nsISupports GetDocumentController(in nsIDOMWindow aWindow,
|
||||
in nsIRunnable aLoadFailedRunnable);
|
||||
|
||||
/*
|
||||
* Clears ServiceWorker registrations from memory and disk for the specified
|
||||
|
@ -16,39 +16,6 @@ extern PRLogModuleInfo* gMediaDecoderLog;
|
||||
#define SINK_LOG_V(msg, ...) \
|
||||
MOZ_LOG(gMediaDecoderLog, LogLevel::Verbose, ("AudioSink=%p " msg, this, ##__VA_ARGS__))
|
||||
|
||||
AudioSink::OnAudioEndTimeUpdateTask::OnAudioEndTimeUpdateTask(
|
||||
MediaDecoderStateMachine* aStateMachine)
|
||||
: mMutex("OnAudioEndTimeUpdateTask")
|
||||
, mEndTime(0)
|
||||
, mStateMachine(aStateMachine)
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
AudioSink::OnAudioEndTimeUpdateTask::Run() {
|
||||
MutexAutoLock lock(mMutex);
|
||||
if (mStateMachine) {
|
||||
mStateMachine->OnAudioEndTimeUpdate(mEndTime);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
AudioSink::OnAudioEndTimeUpdateTask::Dispatch(int64_t aEndTime) {
|
||||
MutexAutoLock lock(mMutex);
|
||||
if (mStateMachine) {
|
||||
mEndTime = aEndTime;
|
||||
nsRefPtr<AudioSink::OnAudioEndTimeUpdateTask> runnable(this);
|
||||
mStateMachine->TaskQueue()->Dispatch(runnable.forget());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AudioSink::OnAudioEndTimeUpdateTask::Cancel() {
|
||||
MutexAutoLock lock(mMutex);
|
||||
mStateMachine = nullptr;
|
||||
}
|
||||
|
||||
// The amount of audio frames that is used to fuzz rounding errors.
|
||||
static const int64_t AUDIO_FUZZ_FRAMES = 1;
|
||||
|
||||
@ -68,7 +35,6 @@ AudioSink::AudioSink(MediaDecoderStateMachine* aStateMachine,
|
||||
, mSetPlaybackRate(false)
|
||||
, mSetPreservesPitch(false)
|
||||
, mPlaying(true)
|
||||
, mOnAudioEndTimeUpdateTask(new OnAudioEndTimeUpdateTask(aStateMachine))
|
||||
{
|
||||
}
|
||||
|
||||
@ -132,7 +98,6 @@ AudioSink::PrepareToShutdown()
|
||||
void
|
||||
AudioSink::Shutdown()
|
||||
{
|
||||
mOnAudioEndTimeUpdateTask->Cancel();
|
||||
mThread->Shutdown();
|
||||
mThread = nullptr;
|
||||
MOZ_ASSERT(!mAudioStream);
|
||||
@ -218,10 +183,6 @@ AudioSink::AudioLoop()
|
||||
} else {
|
||||
mWritten += PlayFromAudioQueue();
|
||||
}
|
||||
int64_t endTime = GetEndTime();
|
||||
if (endTime != -1) {
|
||||
mOnAudioEndTimeUpdateTask->Dispatch(endTime);
|
||||
}
|
||||
}
|
||||
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
|
||||
MOZ_ASSERT(mStopAudioThread || AudioQueue().AtEndOfStream());
|
||||
@ -427,7 +388,7 @@ AudioSink::WriteSilence(uint32_t aFrames)
|
||||
}
|
||||
|
||||
int64_t
|
||||
AudioSink::GetEndTime()
|
||||
AudioSink::GetEndTime() const
|
||||
{
|
||||
CheckedInt64 playedUsecs = FramesToUsecs(mWritten, mInfo.mRate) + mStartTime;
|
||||
if (!playedUsecs.isValid()) {
|
||||
|
@ -27,6 +27,9 @@ public:
|
||||
|
||||
int64_t GetPosition();
|
||||
|
||||
// Thread-safe. Can be called on any thread.
|
||||
int64_t GetEndTime() const;
|
||||
|
||||
// Check whether we've pushed more frames to the audio hardware than it has
|
||||
// played.
|
||||
bool HasUnplayedFrames();
|
||||
@ -90,8 +93,6 @@ private:
|
||||
void StartAudioStreamPlaybackIfNeeded();
|
||||
void WriteSilence(uint32_t aFrames);
|
||||
|
||||
int64_t GetEndTime();
|
||||
|
||||
MediaQueue<AudioData>& AudioQueue();
|
||||
|
||||
ReentrantMonitor& GetReentrantMonitor();
|
||||
@ -124,7 +125,7 @@ private:
|
||||
// stream error.
|
||||
int64_t mLastGoodPosition;
|
||||
|
||||
AudioInfo mInfo;
|
||||
const AudioInfo mInfo;
|
||||
|
||||
dom::AudioChannel mChannel;
|
||||
|
||||
@ -139,23 +140,6 @@ private:
|
||||
bool mSetPreservesPitch;
|
||||
|
||||
bool mPlaying;
|
||||
|
||||
class OnAudioEndTimeUpdateTask : public nsRunnable {
|
||||
public:
|
||||
explicit OnAudioEndTimeUpdateTask(MediaDecoderStateMachine* aStateMachine);
|
||||
|
||||
NS_IMETHOD Run() override;
|
||||
|
||||
void Dispatch(int64_t aEndTime);
|
||||
void Cancel();
|
||||
|
||||
private:
|
||||
Mutex mMutex;
|
||||
int64_t mEndTime;
|
||||
nsRefPtr<MediaDecoderStateMachine> mStateMachine;
|
||||
};
|
||||
|
||||
nsRefPtr<OnAudioEndTimeUpdateTask> mOnAudioEndTimeUpdateTask;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -282,10 +282,16 @@ static char const *const gMpegAudioCodecs[2] = {
|
||||
};
|
||||
|
||||
#ifdef MOZ_OMX_WEBM_DECODER
|
||||
static char const *const gOMXWebMCodecs[4] = {
|
||||
static char const *const gOMXWebMCodecs[] = {
|
||||
"vorbis",
|
||||
"vp8",
|
||||
"vp8.0",
|
||||
// Since Android KK, VP9 SW decoder is supported.
|
||||
// http://developer.android.com/guide/appendix/media-formats.html
|
||||
#if ANDROID_VERSION > 18
|
||||
"vp9",
|
||||
"vp9.0",
|
||||
#endif
|
||||
nullptr
|
||||
};
|
||||
#endif //MOZ_OMX_WEBM_DECODER
|
||||
|
@ -157,6 +157,11 @@ public:
|
||||
(aOther.mStart - aOther.mFuzz < mEnd + mFuzz);
|
||||
}
|
||||
|
||||
bool IntersectsStrict(const SelfType& aOther) const
|
||||
{
|
||||
return mStart < aOther.mEnd && aOther.mStart < mEnd;
|
||||
}
|
||||
|
||||
// Same as Intersects, but including the boundaries.
|
||||
bool Touches(const SelfType& aOther) const
|
||||
{
|
||||
@ -308,14 +313,18 @@ public:
|
||||
SelfType& operator= (const ElemType& aInterval)
|
||||
{
|
||||
mIntervals.Clear();
|
||||
mIntervals.AppendElement(aInterval);
|
||||
if (!aInterval.IsEmpty()) {
|
||||
mIntervals.AppendElement(aInterval);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
SelfType& operator= (ElemType&& aInterval)
|
||||
{
|
||||
mIntervals.Clear();
|
||||
mIntervals.AppendElement(Move(aInterval));
|
||||
if (!aInterval.IsEmpty()) {
|
||||
mIntervals.AppendElement(Move(aInterval));
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -463,7 +472,7 @@ public:
|
||||
const ContainerType& other = aOther.mIntervals;
|
||||
IndexType i = 0, j = 0;
|
||||
for (; i < mIntervals.Length() && j < other.Length();) {
|
||||
if (mIntervals[i].Intersects(other[j])) {
|
||||
if (mIntervals[i].IntersectsStrict(other[j])) {
|
||||
intersection.AppendElement(mIntervals[i].Intersection(other[j]));
|
||||
}
|
||||
if (mIntervals[i].mEnd < other[j].mEnd) {
|
||||
|
@ -358,8 +358,8 @@ int64_t MediaDecoderStateMachine::GetDecodedAudioDuration()
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
AssertCurrentThreadInMonitor();
|
||||
int64_t audioDecoded = AudioQueue().Duration();
|
||||
if (mAudioEndTime != -1) {
|
||||
audioDecoded += mAudioEndTime - GetMediaTime();
|
||||
if (AudioEndTime() != -1) {
|
||||
audioDecoded += AudioEndTime() - GetMediaTime();
|
||||
}
|
||||
return audioDecoded;
|
||||
}
|
||||
@ -1776,7 +1776,7 @@ int64_t MediaDecoderStateMachine::AudioDecodedUsecs()
|
||||
// The amount of audio we have decoded is the amount of audio data we've
|
||||
// already decoded and pushed to the hardware, plus the amount of audio
|
||||
// data waiting to be pushed to the hardware.
|
||||
int64_t pushed = (mAudioEndTime != -1) ? (mAudioEndTime - GetMediaTime()) : 0;
|
||||
int64_t pushed = (AudioEndTime() != -1) ? (AudioEndTime() - GetMediaTime()) : 0;
|
||||
|
||||
// Currently for real time streams, AudioQueue().Duration() produce
|
||||
// wrong values (Bug 1114434), so we use frame counts to calculate duration.
|
||||
@ -2422,13 +2422,10 @@ nsresult MediaDecoderStateMachine::RunStateMachine()
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
StopAudioThread();
|
||||
mDecodedStream->StopPlayback();
|
||||
|
||||
if (mPlayState == MediaDecoder::PLAY_STATE_PLAYING &&
|
||||
!mSentPlaybackEndedEvent)
|
||||
{
|
||||
int64_t clockTime = std::max(mAudioEndTime, mVideoFrameEndTime);
|
||||
int64_t clockTime = std::max(AudioEndTime(), mVideoFrameEndTime);
|
||||
clockTime = std::max(int64_t(0), std::max(clockTime, Duration().ToMicroseconds()));
|
||||
UpdatePlaybackPosition(clockTime);
|
||||
|
||||
@ -2438,6 +2435,12 @@ nsresult MediaDecoderStateMachine::RunStateMachine()
|
||||
|
||||
mSentPlaybackEndedEvent = true;
|
||||
}
|
||||
|
||||
// Stop audio sink after call to AudioEndTime() above, otherwise it will
|
||||
// return an incorrect value due to a null mAudioSink.
|
||||
StopAudioThread();
|
||||
mDecodedStream->StopPlayback();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
@ -2733,9 +2736,9 @@ void MediaDecoderStateMachine::UpdateRenderedVideoFrames()
|
||||
// Cap the current time to the larger of the audio and video end time.
|
||||
// This ensures that if we're running off the system clock, we don't
|
||||
// advance the clock to after the media end time.
|
||||
if (mVideoFrameEndTime != -1 || mAudioEndTime != -1) {
|
||||
if (mVideoFrameEndTime != -1 || AudioEndTime() != -1) {
|
||||
// These will be non -1 if we've displayed a video frame, or played an audio frame.
|
||||
int64_t t = std::min(clockTime, std::max(mVideoFrameEndTime, mAudioEndTime));
|
||||
int64_t t = std::min(clockTime, std::max(mVideoFrameEndTime, AudioEndTime()));
|
||||
// FIXME: Bug 1091422 - chained ogg files hit this assertion.
|
||||
//MOZ_ASSERT(t >= GetMediaTime());
|
||||
if (t > GetMediaTime()) {
|
||||
@ -3070,11 +3073,25 @@ void MediaDecoderStateMachine::QueueMetadata(int64_t aPublishTime,
|
||||
mMetadataManager.QueueMetadata(metadata);
|
||||
}
|
||||
|
||||
int64_t
|
||||
MediaDecoderStateMachine::AudioEndTime() const
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
AssertCurrentThreadInMonitor();
|
||||
if (mAudioSink) {
|
||||
return mAudioSink->GetEndTime();
|
||||
}
|
||||
// Don't call this after mAudioSink becomes null since we can't distinguish
|
||||
// "before StartAudioThread" and "after StopAudioThread".
|
||||
MOZ_ASSERT(mAudioCaptured || !mAudioCompleted);
|
||||
return mAudioEndTime;
|
||||
}
|
||||
|
||||
void MediaDecoderStateMachine::OnAudioEndTimeUpdate(int64_t aAudioEndTime)
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
MOZ_ASSERT(aAudioEndTime >= mAudioEndTime);
|
||||
MOZ_ASSERT(aAudioEndTime >= AudioEndTime());
|
||||
mAudioEndTime = aAudioEndTime;
|
||||
}
|
||||
|
||||
|
@ -1070,6 +1070,7 @@ protected:
|
||||
// hardware in microseconds. This will approximately be the end time of the
|
||||
// audio stream, unless another frame is pushed to the hardware.
|
||||
int64_t mAudioEndTime;
|
||||
int64_t AudioEndTime() const;
|
||||
|
||||
// The end time of the last decoded audio frame. This signifies the end of
|
||||
// decoded audio data. Used to check if we are low in decoded data.
|
||||
|
@ -81,16 +81,6 @@ MediaFormatReader::MediaFormatReader(AbstractMediaDecoder* aDecoder,
|
||||
MediaFormatReader::~MediaFormatReader()
|
||||
{
|
||||
MOZ_COUNT_DTOR(MediaFormatReader);
|
||||
// shutdown main thread demuxer and track demuxers.
|
||||
if (mAudioTrackDemuxer) {
|
||||
mAudioTrackDemuxer->BreakCycles();
|
||||
mAudioTrackDemuxer = nullptr;
|
||||
}
|
||||
if (mVideoTrackDemuxer) {
|
||||
mVideoTrackDemuxer->BreakCycles();
|
||||
mVideoTrackDemuxer = nullptr;
|
||||
}
|
||||
mMainThreadDemuxer = nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<ShutdownPromise>
|
||||
@ -99,6 +89,7 @@ MediaFormatReader::Shutdown()
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
|
||||
mDemuxerInitRequest.DisconnectIfExists();
|
||||
mMetadataPromise.RejectIfExists(ReadMetadataFailureReason::METADATA_ERROR, __func__);
|
||||
mSeekPromise.RejectIfExists(NS_ERROR_FAILURE, __func__);
|
||||
mSkipRequest.DisconnectIfExists();
|
||||
|
||||
@ -144,6 +135,17 @@ MediaFormatReader::Shutdown()
|
||||
|
||||
mDemuxer = nullptr;
|
||||
|
||||
// shutdown main thread demuxer and track demuxers.
|
||||
if (mAudioTrackDemuxer) {
|
||||
mAudioTrackDemuxer->BreakCycles();
|
||||
mAudioTrackDemuxer = nullptr;
|
||||
}
|
||||
if (mVideoTrackDemuxer) {
|
||||
mVideoTrackDemuxer->BreakCycles();
|
||||
mVideoTrackDemuxer = nullptr;
|
||||
}
|
||||
mMainThreadDemuxer = nullptr;
|
||||
|
||||
mPlatform = nullptr;
|
||||
|
||||
return MediaDecoderReader::Shutdown();
|
||||
@ -356,6 +358,11 @@ MediaFormatReader::OnDemuxerInitDone(nsresult)
|
||||
NS_WARNING("Unable to clone current MediaDataDemuxer");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!videoActive && !audioActive) {
|
||||
mMetadataPromise.Reject(ReadMetadataFailureReason::METADATA_ERROR, __func__);
|
||||
return;
|
||||
}
|
||||
if (videoActive) {
|
||||
mVideoTrackDemuxer =
|
||||
mMainThreadDemuxer->GetTrackDemuxer(TrackInfo::kVideoTrack, 0);
|
||||
@ -525,7 +532,8 @@ MediaFormatReader::RequestVideoData(bool aSkipToNextKeyframe,
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
MOZ_DIAGNOSTIC_ASSERT(mSeekPromise.IsEmpty(), "No sample requests allowed while seeking");
|
||||
MOZ_DIAGNOSTIC_ASSERT(!mVideo.HasPromise(), "No duplicate sample requests");
|
||||
MOZ_DIAGNOSTIC_ASSERT(!mVideo.mSeekRequest.Exists());
|
||||
MOZ_DIAGNOSTIC_ASSERT(!mVideo.mSeekRequest.Exists() ||
|
||||
mVideo.mTimeThreshold.isSome());
|
||||
MOZ_DIAGNOSTIC_ASSERT(!mSkipRequest.Exists(), "called mid-skipping");
|
||||
MOZ_DIAGNOSTIC_ASSERT(!IsSeeking(), "called mid-seek");
|
||||
LOGV("RequestVideoData(%d, %lld)", aSkipToNextKeyframe, aTimeThreshold);
|
||||
@ -622,7 +630,8 @@ MediaFormatReader::RequestAudioData()
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
MOZ_DIAGNOSTIC_ASSERT(mSeekPromise.IsEmpty(), "No sample requests allowed while seeking");
|
||||
MOZ_DIAGNOSTIC_ASSERT(!mAudio.mSeekRequest.Exists());
|
||||
MOZ_DIAGNOSTIC_ASSERT(!mAudio.mSeekRequest.Exists() ||
|
||||
mAudio.mTimeThreshold.isSome());
|
||||
MOZ_DIAGNOSTIC_ASSERT(!mAudio.HasPromise(), "No duplicate sample requests");
|
||||
MOZ_DIAGNOSTIC_ASSERT(!IsSeeking(), "called mid-seek");
|
||||
LOGV("");
|
||||
@ -719,6 +728,7 @@ MediaFormatReader::NotifyError(TrackType aTrack)
|
||||
LOGV("%s Decoding error", TrackTypeToStr(aTrack));
|
||||
auto& decoder = GetDecoderData(aTrack);
|
||||
decoder.mError = true;
|
||||
decoder.mNeedDraining = true;
|
||||
ScheduleUpdate(aTrack);
|
||||
}
|
||||
|
||||
@ -728,6 +738,7 @@ MediaFormatReader::NotifyWaitingForData(TrackType aTrack)
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
auto& decoder = GetDecoderData(aTrack);
|
||||
decoder.mWaitingForData = true;
|
||||
decoder.mNeedDraining = true;
|
||||
ScheduleUpdate(aTrack);
|
||||
}
|
||||
|
||||
@ -737,6 +748,7 @@ MediaFormatReader::NotifyEndOfStream(TrackType aTrack)
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
auto& decoder = GetDecoderData(aTrack);
|
||||
decoder.mDemuxEOS = true;
|
||||
decoder.mNeedDraining = true;
|
||||
ScheduleUpdate(aTrack);
|
||||
}
|
||||
|
||||
@ -750,6 +762,7 @@ MediaFormatReader::NeedInput(DecoderData& aDecoder)
|
||||
// run of input than we input, decoders fire an "input exhausted" callback,
|
||||
// which overrides our "few more samples" threshold.
|
||||
return
|
||||
!aDecoder.mDraining &&
|
||||
!aDecoder.mError &&
|
||||
(aDecoder.HasPromise() || aDecoder.mForceDecodeAhead) &&
|
||||
!aDecoder.mDemuxRequest.Exists() &&
|
||||
@ -797,7 +810,6 @@ MediaFormatReader::UpdateReceivedNewData(TrackType aTrack)
|
||||
(!hasLastEnd || decoder.mTimeRanges.GetEnd() > lastEnd)) {
|
||||
// New data was added after our previous end, we can clear the EOS flag.
|
||||
decoder.mDemuxEOS = false;
|
||||
decoder.mDemuxEOSServiced = false;
|
||||
}
|
||||
|
||||
if (decoder.mError) {
|
||||
@ -872,6 +884,17 @@ MediaFormatReader::DecodeDemuxedSamples(TrackType aTrack,
|
||||
return;
|
||||
}
|
||||
|
||||
if (decoder.mNextStreamSourceID.isNothing() ||
|
||||
decoder.mNextStreamSourceID.ref() != info->GetID()) {
|
||||
LOG("%s stream id has changed from:%d to:%d, draining decoder.",
|
||||
TrackTypeToStr(aTrack), decoder.mLastStreamSourceID,
|
||||
info->GetID());
|
||||
decoder.mNeedDraining = true;
|
||||
decoder.mNextStreamSourceID = Some(info->GetID());
|
||||
DrainDecoder(aTrack);
|
||||
return;
|
||||
}
|
||||
|
||||
LOG("%s stream id has changed from:%d to:%d, recreating decoder.",
|
||||
TrackTypeToStr(aTrack), decoder.mLastStreamSourceID,
|
||||
info->GetID());
|
||||
@ -944,6 +967,25 @@ MediaFormatReader::DecodeDemuxedSamples(TrackType aTrack,
|
||||
decoder.mInputExhausted = false;
|
||||
}
|
||||
|
||||
void
|
||||
MediaFormatReader::DrainDecoder(TrackType aTrack)
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
|
||||
auto& decoder = GetDecoderData(aTrack);
|
||||
if (!decoder.mNeedDraining || decoder.mDraining) {
|
||||
return;
|
||||
}
|
||||
decoder.mNeedDraining = false;
|
||||
if (!decoder.mDecoder) {
|
||||
return;
|
||||
}
|
||||
decoder.mOutputRequested = true;
|
||||
decoder.mDecoder->Drain();
|
||||
decoder.mDraining = true;
|
||||
LOG("Requesting %s decoder to drain", TrackTypeToStr(aTrack));
|
||||
}
|
||||
|
||||
void
|
||||
MediaFormatReader::Update(TrackType aTrack)
|
||||
{
|
||||
@ -965,23 +1007,6 @@ MediaFormatReader::Update(TrackType aTrack)
|
||||
return;
|
||||
}
|
||||
|
||||
if (decoder.HasPromise()) {
|
||||
// Handle pending requests from the MediaDecoderStateMachine.
|
||||
if (decoder.mError) {
|
||||
LOG("Decoding Error");
|
||||
decoder.RejectPromise(DECODE_ERROR, __func__);
|
||||
return;
|
||||
}
|
||||
if (decoder.mWaitingForData) {
|
||||
LOG("Waiting For Data");
|
||||
decoder.RejectPromise(WAITING_FOR_DATA, __func__);
|
||||
}
|
||||
} else if (decoder.mWaitingForData) {
|
||||
// Nothing more we can do at present.
|
||||
LOGV("Still waiting for data.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Record number of frames decoded and parsed. Automatically update the
|
||||
// stats counters using the AutoNotifyDecoded stack-based class.
|
||||
AbstractMediaDecoder::AutoNotifyDecoded a(mDecoder);
|
||||
@ -992,6 +1017,7 @@ MediaFormatReader::Update(TrackType aTrack)
|
||||
a.mDecoded = static_cast<uint32_t>(delta);
|
||||
mLastReportedNumDecodedFrames = decoder.mNumSamplesOutput;
|
||||
}
|
||||
|
||||
if (decoder.HasPromise()) {
|
||||
needOutput = true;
|
||||
if (!decoder.mOutput.IsEmpty()) {
|
||||
@ -1010,16 +1036,26 @@ MediaFormatReader::Update(TrackType aTrack)
|
||||
output->mKeyframe);
|
||||
}
|
||||
} else if (decoder.mDrainComplete) {
|
||||
decoder.RejectPromise(END_OF_STREAM, __func__);
|
||||
decoder.mDrainComplete = false;
|
||||
decoder.mDraining = false;
|
||||
if (decoder.mError) {
|
||||
LOG("Decoding Error");
|
||||
decoder.RejectPromise(DECODE_ERROR, __func__);
|
||||
return;
|
||||
} else if (decoder.mDemuxEOS) {
|
||||
decoder.RejectPromise(END_OF_STREAM, __func__);
|
||||
} else if (decoder.mWaitingForData) {
|
||||
LOG("Waiting For Data");
|
||||
decoder.RejectPromise(WAITING_FOR_DATA, __func__);
|
||||
}
|
||||
} else if (decoder.mError && !decoder.mDecoder) {
|
||||
decoder.RejectPromise(DECODE_ERROR, __func__);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (decoder.mDemuxEOS && !decoder.mDemuxEOSServiced) {
|
||||
decoder.mOutputRequested = true;
|
||||
decoder.mDecoder->Drain();
|
||||
decoder.mDemuxEOSServiced = true;
|
||||
LOGV("Requesting decoder to drain");
|
||||
if (decoder.mError || decoder.mDemuxEOS || decoder.mWaitingForData) {
|
||||
DrainDecoder(aTrack);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1500,10 +1536,12 @@ MediaFormatReader::NotifyDataArrivedInternal(uint32_t aLength, int64_t aOffset)
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
MOZ_ASSERT(aLength);
|
||||
|
||||
if (!mInitDone) {
|
||||
if (!mInitDone || mShutdown) {
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mMainThreadDemuxer);
|
||||
|
||||
// Queue a task to notify our main thread demuxer.
|
||||
nsCOMPtr<nsIRunnable> task =
|
||||
NS_NewRunnableMethodWithArgs<uint32_t, int64_t>(
|
||||
@ -1519,7 +1557,7 @@ MediaFormatReader::NotifyDataRemoved()
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
|
||||
if (!mInitDone) {
|
||||
if (!mInitDone || mShutdown) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -118,6 +118,8 @@ private:
|
||||
// Decode any pending already demuxed samples.
|
||||
void DecodeDemuxedSamples(TrackType aTrack,
|
||||
AbstractMediaDecoder::AutoNotifyDecoded& aA);
|
||||
// Drain the current decoder.
|
||||
void DrainDecoder(TrackType aTrack);
|
||||
void NotifyNewOutput(TrackType aTrack, MediaData* aSample);
|
||||
void NotifyInputExhausted(TrackType aTrack);
|
||||
void NotifyDrainComplete(TrackType aTrack);
|
||||
@ -188,13 +190,14 @@ private:
|
||||
, mForceDecodeAhead(false)
|
||||
, mUpdateScheduled(false)
|
||||
, mDemuxEOS(false)
|
||||
, mDemuxEOSServiced(false)
|
||||
, mWaitingForData(false)
|
||||
, mReceivedNewData(false)
|
||||
, mDiscontinuity(true)
|
||||
, mOutputRequested(false)
|
||||
, mInputExhausted(false)
|
||||
, mError(false)
|
||||
, mNeedDraining(false)
|
||||
, mDraining(false)
|
||||
, mDrainComplete(false)
|
||||
, mNumSamplesInput(0)
|
||||
, mNumSamplesOutput(0)
|
||||
@ -219,7 +222,6 @@ private:
|
||||
bool mForceDecodeAhead;
|
||||
bool mUpdateScheduled;
|
||||
bool mDemuxEOS;
|
||||
bool mDemuxEOSServiced;
|
||||
bool mWaitingForData;
|
||||
bool mReceivedNewData;
|
||||
bool mDiscontinuity;
|
||||
@ -241,6 +243,8 @@ private:
|
||||
bool mOutputRequested;
|
||||
bool mInputExhausted;
|
||||
bool mError;
|
||||
bool mNeedDraining;
|
||||
bool mDraining;
|
||||
bool mDrainComplete;
|
||||
// If set, all decoded samples prior mTimeThreshold will be dropped.
|
||||
// Used for internal seeking when a change of stream is detected.
|
||||
@ -270,25 +274,28 @@ private:
|
||||
MOZ_ASSERT(mOwner->OnTaskQueue());
|
||||
mForceDecodeAhead = false;
|
||||
mDemuxEOS = false;
|
||||
mDemuxEOSServiced = false;
|
||||
mWaitingForData = false;
|
||||
mReceivedNewData = false;
|
||||
mDiscontinuity = true;
|
||||
mQueuedSamples.Clear();
|
||||
mOutputRequested = false;
|
||||
mInputExhausted = false;
|
||||
mNeedDraining = false;
|
||||
mDraining = false;
|
||||
mDrainComplete = false;
|
||||
mTimeThreshold.reset();
|
||||
mOutput.Clear();
|
||||
mNumSamplesInput = 0;
|
||||
mNumSamplesOutput = 0;
|
||||
mSizeOfQueue = 0;
|
||||
mNextStreamSourceID.reset();
|
||||
}
|
||||
|
||||
// Used by the MDSM for logging purposes.
|
||||
Atomic<size_t> mSizeOfQueue;
|
||||
// Sample format monitoring.
|
||||
uint32_t mLastStreamSourceID;
|
||||
Maybe<uint32_t> mNextStreamSourceID;
|
||||
media::TimeIntervals mTimeRanges;
|
||||
nsRefPtr<SharedTrackInfo> mInfo;
|
||||
};
|
||||
|
@ -15,8 +15,49 @@
|
||||
#include "mp4_demuxer/ResourceStream.h"
|
||||
#include "mp4_demuxer/BufferStream.h"
|
||||
|
||||
// Used for telemetry
|
||||
#include "mozilla/Telemetry.h"
|
||||
#include "mp4_demuxer/AnnexB.h"
|
||||
#include "mp4_demuxer/H264.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
// Returns true if no SPS was found and search for it should continue.
|
||||
bool
|
||||
AccumulateSPSTelemetry(const MediaByteBuffer* aExtradata)
|
||||
{
|
||||
mp4_demuxer::SPSData spsdata;
|
||||
if (mp4_demuxer::H264::DecodeSPSFromExtraData(aExtradata, spsdata)) {
|
||||
uint8_t constraints = (spsdata.constraint_set0_flag ? (1 << 0) : 0) |
|
||||
(spsdata.constraint_set1_flag ? (1 << 1) : 0) |
|
||||
(spsdata.constraint_set2_flag ? (1 << 2) : 0) |
|
||||
(spsdata.constraint_set3_flag ? (1 << 3) : 0) |
|
||||
(spsdata.constraint_set4_flag ? (1 << 4) : 0) |
|
||||
(spsdata.constraint_set5_flag ? (1 << 5) : 0);
|
||||
Telemetry::Accumulate(Telemetry::VIDEO_DECODED_H264_SPS_CONSTRAINT_SET_FLAG,
|
||||
constraints);
|
||||
|
||||
// Collect profile_idc values up to 244, otherwise 0 for unknown.
|
||||
Telemetry::Accumulate(Telemetry::VIDEO_DECODED_H264_SPS_PROFILE,
|
||||
spsdata.profile_idc <= 244 ? spsdata.profile_idc : 0);
|
||||
|
||||
// Make sure level_idc represents a value between levels 1 and 5.2,
|
||||
// otherwise collect 0 for unknown level.
|
||||
Telemetry::Accumulate(Telemetry::VIDEO_DECODED_H264_SPS_LEVEL,
|
||||
(spsdata.level_idc >= 10 && spsdata.level_idc <= 52) ?
|
||||
spsdata.level_idc : 0);
|
||||
|
||||
// max_num_ref_frames should be between 0 and 16, anything larger will
|
||||
// be treated as invalid.
|
||||
Telemetry::Accumulate(Telemetry::VIDEO_H264_SPS_MAX_NUM_REF_FRAMES,
|
||||
std::min(spsdata.max_num_ref_frames, 17u));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
MP4Demuxer::MP4Demuxer(MediaResource* aResource)
|
||||
: mResource(aResource)
|
||||
, mStream(new mp4_demuxer::ResourceStream(aResource))
|
||||
@ -169,6 +210,17 @@ MP4TrackDemuxer::MP4TrackDemuxer(MP4Demuxer* aParent,
|
||||
&mMonitor);
|
||||
mIterator = MakeUnique<mp4_demuxer::SampleIterator>(mIndex);
|
||||
EnsureUpToDateIndex(); // Force update of index
|
||||
|
||||
// Collect telemetry from h264 AVCC SPS.
|
||||
if (mInfo->GetAsVideoInfo() &&
|
||||
(mInfo->mMimeType.EqualsLiteral("video/mp4") ||
|
||||
mInfo->mMimeType.EqualsLiteral("video/avc"))) {
|
||||
mNeedSPSForTelemetry =
|
||||
AccumulateSPSTelemetry(mInfo->GetAsVideoInfo()->mExtraData);
|
||||
} else {
|
||||
// No SPS to be found.
|
||||
mNeedSPSForTelemetry = false;
|
||||
}
|
||||
}
|
||||
|
||||
UniquePtr<TrackInfo>
|
||||
@ -268,6 +320,12 @@ MP4TrackDemuxer::UpdateSamples(nsTArray<nsRefPtr<MediaRawData>>& aSamples)
|
||||
{
|
||||
for (size_t i = 0; i < aSamples.Length(); i++) {
|
||||
MediaRawData* sample = aSamples[i];
|
||||
// Collect telemetry from h264 Annex B SPS.
|
||||
if (mNeedSPSForTelemetry && mp4_demuxer::AnnexB::HasSPS(sample)) {
|
||||
nsRefPtr<MediaByteBuffer> extradata =
|
||||
mp4_demuxer::AnnexB::ExtractExtraData(sample);
|
||||
mNeedSPSForTelemetry = AccumulateSPSTelemetry(extradata);
|
||||
}
|
||||
if (sample->mCrypto.mValid) {
|
||||
nsAutoPtr<MediaRawDataWriter> writer(sample->CreateWriter());
|
||||
writer->mCrypto.mMode = mInfo->mCrypto.mMode;
|
||||
|
@ -96,6 +96,7 @@ private:
|
||||
// Queued samples extracted by the demuxer, but not yet returned.
|
||||
nsRefPtr<MediaRawData> mQueuedSample;
|
||||
bool mNeedReIndex;
|
||||
bool mNeedSPSForTelemetry;
|
||||
|
||||
// We do not actually need a monitor, however MoofParser will assert
|
||||
// if a monitor isn't held.
|
||||
|
@ -66,40 +66,7 @@ TrackTypeToStr(TrackInfo::TrackType aTrack)
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
AccumulateSPSTelemetry(const MediaByteBuffer* aExtradata)
|
||||
{
|
||||
SPSData spsdata;
|
||||
if (H264::DecodeSPSFromExtraData(aExtradata, spsdata)) {
|
||||
uint8_t constraints = (spsdata.constraint_set0_flag ? (1 << 0) : 0) |
|
||||
(spsdata.constraint_set1_flag ? (1 << 1) : 0) |
|
||||
(spsdata.constraint_set2_flag ? (1 << 2) : 0) |
|
||||
(spsdata.constraint_set3_flag ? (1 << 3) : 0) |
|
||||
(spsdata.constraint_set4_flag ? (1 << 4) : 0) |
|
||||
(spsdata.constraint_set5_flag ? (1 << 5) : 0);
|
||||
Telemetry::Accumulate(Telemetry::VIDEO_DECODED_H264_SPS_CONSTRAINT_SET_FLAG,
|
||||
constraints);
|
||||
|
||||
// Collect profile_idc values up to 244, otherwise 0 for unknown.
|
||||
Telemetry::Accumulate(Telemetry::VIDEO_DECODED_H264_SPS_PROFILE,
|
||||
spsdata.profile_idc <= 244 ? spsdata.profile_idc : 0);
|
||||
|
||||
// Make sure level_idc represents a value between levels 1 and 5.2,
|
||||
// otherwise collect 0 for unknown level.
|
||||
Telemetry::Accumulate(Telemetry::VIDEO_DECODED_H264_SPS_LEVEL,
|
||||
(spsdata.level_idc >= 10 && spsdata.level_idc <= 52) ?
|
||||
spsdata.level_idc : 0);
|
||||
|
||||
// max_num_ref_frames should be between 0 and 16, anything larger will
|
||||
// be treated as invalid.
|
||||
Telemetry::Accumulate(Telemetry::VIDEO_H264_SPS_MAX_NUM_REF_FRAMES,
|
||||
std::min(spsdata.max_num_ref_frames, 17u));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
extern bool AccumulateSPSTelemetry(const MediaByteBuffer* aExtradata);
|
||||
|
||||
// MP4Demuxer wants to do various blocking reads, which cause deadlocks while
|
||||
// mDemuxerMonitor is held. This stuff should really be redesigned, but we don't
|
||||
|
@ -40,9 +40,9 @@ GMPSharedMemManager::MgrAllocShmem(GMPSharedMem::GMPMemoryClasses aClass, size_t
|
||||
size_t pagesize = ipc::SharedMemory::SystemPageSize();
|
||||
aSize = (aSize + (pagesize-1)) & ~(pagesize-1); // round up to page size
|
||||
bool retval = Alloc(aSize, aType, aMem);
|
||||
// The allocator (or NeedsShmem call) should never return less than we ask for...
|
||||
MOZ_ASSERT(aMem->Size<uint8_t>() >= aSize);
|
||||
if (retval) {
|
||||
// The allocator (or NeedsShmem call) should never return less than we ask for...
|
||||
MOZ_ASSERT(aMem->Size<uint8_t>() >= aSize);
|
||||
mData->mGmpAllocated[aClass]++;
|
||||
}
|
||||
return retval;
|
||||
|
@ -146,6 +146,7 @@ MediaSourceDecoder::Shutdown()
|
||||
if (mMediaSource) {
|
||||
mMediaSource->Detach();
|
||||
}
|
||||
mDemuxer = nullptr;
|
||||
|
||||
MediaDecoder::Shutdown();
|
||||
// Kick WaitForData out of its slumber.
|
||||
@ -292,6 +293,7 @@ void
|
||||
MediaSourceDecoder::GetMozDebugReaderData(nsAString& aString)
|
||||
{
|
||||
if (mIsUsingFormatReader) {
|
||||
mDemuxer->GetMozDebugReaderData(aString);
|
||||
return;
|
||||
}
|
||||
GetReader()->GetMozDebugReaderData(aString);
|
||||
|
@ -10,6 +10,7 @@
|
||||
|
||||
#include "MediaSourceDemuxer.h"
|
||||
#include "SourceBufferList.h"
|
||||
#include "nsPrintfCString.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
@ -224,6 +225,41 @@ MediaSourceDemuxer::~MediaSourceDemuxer()
|
||||
mTaskQueue = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
MediaSourceDemuxer::GetMozDebugReaderData(nsAString& aString)
|
||||
{
|
||||
MonitorAutoLock mon(mMonitor);
|
||||
nsAutoCString result;
|
||||
result += nsPrintfCString("Dumping data for demuxer %p:\n", this);
|
||||
if (mAudioTrack) {
|
||||
result += nsPrintfCString("\tDumping Audio Track Buffer(%s): - mLastAudioTime: %f\n"
|
||||
"\t\tNumSamples:%u Size:%u NextGetSampleIndex:%u NextInsertionIndex:%d\n",
|
||||
mAudioTrack->mAudioTracks.mInfo->mMimeType.get(),
|
||||
mAudioTrack->mAudioTracks.mNextSampleTime.ToSeconds(),
|
||||
mAudioTrack->mAudioTracks.mBuffers[0].Length(),
|
||||
mAudioTrack->mAudioTracks.mSizeBuffer,
|
||||
mAudioTrack->mAudioTracks.mNextGetSampleIndex.valueOr(-1),
|
||||
mAudioTrack->mAudioTracks.mNextInsertionIndex.valueOr(-1));
|
||||
|
||||
result += nsPrintfCString("\t\tBuffered: ranges=%s\n",
|
||||
DumpTimeRanges(mAudioTrack->SafeBuffered(TrackInfo::kAudioTrack)).get());
|
||||
}
|
||||
if (mVideoTrack) {
|
||||
result += nsPrintfCString("\tDumping Video Track Buffer(%s) - mLastVideoTime: %f\n"
|
||||
"\t\tNumSamples:%u Size:%u NextGetSampleIndex:%u NextInsertionIndex:%d\n",
|
||||
mVideoTrack->mVideoTracks.mInfo->mMimeType.get(),
|
||||
mVideoTrack->mVideoTracks.mNextSampleTime.ToSeconds(),
|
||||
mVideoTrack->mVideoTracks.mBuffers[0].Length(),
|
||||
mVideoTrack->mVideoTracks.mSizeBuffer,
|
||||
mVideoTrack->mVideoTracks.mNextGetSampleIndex.valueOr(-1),
|
||||
mVideoTrack->mVideoTracks.mNextInsertionIndex.valueOr(-1));
|
||||
|
||||
result += nsPrintfCString("\t\tBuffered: ranges=%s\n",
|
||||
DumpTimeRanges(mVideoTrack->SafeBuffered(TrackInfo::kVideoTrack)).get());
|
||||
}
|
||||
aString += NS_ConvertUTF8toUTF16(result);
|
||||
}
|
||||
|
||||
MediaSourceTrackDemuxer::MediaSourceTrackDemuxer(MediaSourceDemuxer* aParent,
|
||||
TrackInfo::TrackType aType,
|
||||
TrackBuffersManager* aManager)
|
||||
@ -314,7 +350,10 @@ MediaSourceTrackDemuxer::BreakCycles()
|
||||
{
|
||||
nsRefPtr<MediaSourceTrackDemuxer> self = this;
|
||||
nsCOMPtr<nsIRunnable> task =
|
||||
NS_NewRunnableFunction([self]() { self->mParent = nullptr; } );
|
||||
NS_NewRunnableFunction([self]() {
|
||||
self->mParent = nullptr;
|
||||
self->mManager = nullptr;
|
||||
} );
|
||||
mParent->GetTaskQueue()->Dispatch(task.forget());
|
||||
}
|
||||
|
||||
|
@ -55,6 +55,10 @@ public:
|
||||
MediaTaskQueue* GetTaskQueue() { return mTaskQueue; }
|
||||
void NotifyTimeRangesChanged();
|
||||
|
||||
// Returns a string describing the state of the MediaSource internal
|
||||
// buffered data. Used for debugging purposes.
|
||||
void GetMozDebugReaderData(nsAString& aString);
|
||||
|
||||
private:
|
||||
~MediaSourceDemuxer();
|
||||
friend class MediaSourceTrackDemuxer;
|
||||
|
@ -1713,6 +1713,15 @@ TrackBuffersManager::Buffered(TrackInfo::TrackType aTrack)
|
||||
return GetTracksData(aTrack).mBufferedRanges;
|
||||
}
|
||||
|
||||
TimeIntervals
|
||||
TrackBuffersManager::SafeBuffered(TrackInfo::TrackType aTrack) const
|
||||
{
|
||||
MonitorAutoLock mon(mMonitor);
|
||||
return aTrack == TrackInfo::kVideoTrack
|
||||
? mVideoBufferedRanges
|
||||
: mAudioBufferedRanges;
|
||||
}
|
||||
|
||||
const TrackBuffersManager::TrackBuffer&
|
||||
TrackBuffersManager::GetTrackBuffer(TrackInfo::TrackType aTrack)
|
||||
{
|
||||
|
@ -77,6 +77,7 @@ public:
|
||||
MediaInfo GetMetadata();
|
||||
const TrackBuffer& GetTrackBuffer(TrackInfo::TrackType aTrack);
|
||||
const TimeIntervals& Buffered(TrackInfo::TrackType);
|
||||
TimeIntervals SafeBuffered(TrackInfo::TrackType) const;
|
||||
bool IsEnded() const
|
||||
{
|
||||
return mEnded;
|
||||
@ -95,6 +96,8 @@ public:
|
||||
#endif
|
||||
|
||||
private:
|
||||
// for MediaSourceDemuxer::GetMozDebugReaderData
|
||||
friend class MediaSourceDemuxer;
|
||||
virtual ~TrackBuffersManager();
|
||||
// All following functions run on the taskqueue.
|
||||
nsRefPtr<AppendPromise> InitSegmentParserLoop();
|
||||
|
@ -23,10 +23,16 @@ function check_webm(v, enabled) {
|
||||
.getService(SpecialPowers.Ci.nsIPropertyBag2)
|
||||
.getProperty('sdk_version');
|
||||
info("android version:"+androidSDKVer);
|
||||
if (androidSDKVer > 15) {
|
||||
|
||||
// Since from Android KK, vp9 sw decoder is supported.
|
||||
if (androidSDKVer > 18) {
|
||||
video = ['vp8', 'vp8.0', 'vp9', 'vp9.0'];
|
||||
audio = ['vorbis'];
|
||||
} else if (androidSDKVer > 15) {
|
||||
video = ['vp8', 'vp8.0'];
|
||||
audio = ['vorbis'];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
audio.forEach(function(acodec) {
|
||||
|
@ -15,6 +15,10 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=495145
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=495145">Mozilla Bug 495145</a>
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
//longer timeout for slow platforms
|
||||
if (isSlowPlatform()) {
|
||||
SimpleTest.requestLongerTimeout(1.5);
|
||||
}
|
||||
|
||||
var manager = new MediaTestManager;
|
||||
|
||||
|
@ -9,6 +9,11 @@
|
||||
<body>
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
//longer timeout for slow platforms
|
||||
if (isSlowPlatform()) {
|
||||
SimpleTest.requestLongerTimeout(1.5);
|
||||
}
|
||||
|
||||
var manager = new MediaTestManager;
|
||||
|
||||
var canvas = document.createElement('canvas');
|
||||
|
@ -9,6 +9,11 @@
|
||||
<body>
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
//longer timeout for slow platforms
|
||||
if (isSlowPlatform()) {
|
||||
SimpleTest.requestLongerTimeout(1.5);
|
||||
}
|
||||
|
||||
var manager = new MediaTestManager;
|
||||
|
||||
function startTest(test, token) {
|
||||
|
@ -94,8 +94,8 @@ skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video suppo
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
|
||||
[test_peerConnection_captureStream_canvas_webgl.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
|
||||
[test_peerConnection_certificates.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
|
||||
# [test_peerConnection_certificates.html] # bug 1180968
|
||||
# skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
|
||||
[test_peerConnection_close.html]
|
||||
[test_peerConnection_closeDuringIce.html]
|
||||
[test_peerConnection_errorCallbacks.html]
|
||||
|
@ -14,33 +14,41 @@
|
||||
* E: element type, must be a POD type.
|
||||
* N: N bytes alignment for the first element, defaults to 32
|
||||
*/
|
||||
template <typename E, int N, typename Alloc>
|
||||
class AlignedTArray_Impl : public nsTArray_Impl<E, Alloc>
|
||||
template <typename E, int N = 32>
|
||||
class AlignedTArray : public nsTArray_Impl<E, nsTArrayInfallibleAllocator>
|
||||
{
|
||||
static_assert((N & (N-1)) == 0, "N must be power of 2");
|
||||
typedef nsTArray_Impl<E, Alloc> base_type;
|
||||
typedef nsTArray_Impl<E, nsTArrayInfallibleAllocator> base_type;
|
||||
public:
|
||||
typedef E elem_type;
|
||||
typedef typename base_type::size_type size_type;
|
||||
typedef typename base_type::index_type index_type;
|
||||
|
||||
AlignedTArray_Impl() {}
|
||||
explicit AlignedTArray_Impl(size_type capacity) : base_type(capacity+sExtra) {}
|
||||
AlignedTArray() {}
|
||||
explicit AlignedTArray(size_type capacity) : base_type(capacity + sExtra) {}
|
||||
elem_type* Elements() { return getAligned(base_type::Elements()); }
|
||||
const elem_type* Elements() const { return getAligned(base_type::Elements()); }
|
||||
elem_type& operator[](index_type i) { return Elements()[i];}
|
||||
const elem_type& operator[](index_type i) const { return Elements()[i]; }
|
||||
|
||||
typename Alloc::ResultType SetLength(size_type newLen) {
|
||||
return base_type::SetLength(newLen + sExtra);
|
||||
void SetLength(size_type newLen)
|
||||
{
|
||||
base_type::SetLength(newLen + sExtra);
|
||||
}
|
||||
|
||||
MOZ_WARN_UNUSED_RESULT
|
||||
bool SetLength(size_type newLen, const mozilla::fallible_t&)
|
||||
{
|
||||
return base_type::SetLength(newLen + sExtra, mozilla::fallible);
|
||||
}
|
||||
|
||||
size_type Length() const {
|
||||
return base_type::Length() <= sExtra ? 0 : base_type::Length() - sExtra;
|
||||
}
|
||||
|
||||
private:
|
||||
AlignedTArray_Impl(const AlignedTArray_Impl& other) = delete;
|
||||
void operator=(const AlignedTArray_Impl& other) = delete;
|
||||
AlignedTArray(const AlignedTArray& other) = delete;
|
||||
void operator=(const AlignedTArray& other) = delete;
|
||||
|
||||
static const size_type sPadding = N <= MOZ_ALIGNOF(E) ? 0 : N - MOZ_ALIGNOF(E);
|
||||
static const size_type sExtra = (sPadding + sizeof(E) - 1) / sizeof(E);
|
||||
@ -52,34 +60,4 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
template <typename E, int N=32>
|
||||
class AlignedTArray : public AlignedTArray_Impl<E, N, nsTArrayInfallibleAllocator>
|
||||
{
|
||||
public:
|
||||
typedef AlignedTArray_Impl<E, N, nsTArrayInfallibleAllocator> base_type;
|
||||
typedef AlignedTArray<E, N> self_type;
|
||||
typedef typename base_type::size_type size_type;
|
||||
|
||||
AlignedTArray() {}
|
||||
explicit AlignedTArray(size_type capacity) : base_type(capacity) {}
|
||||
private:
|
||||
AlignedTArray(const AlignedTArray& other) = delete;
|
||||
void operator=(const AlignedTArray& other) = delete;
|
||||
};
|
||||
|
||||
template <typename E, int N=32>
|
||||
class AlignedFallibleTArray : public AlignedTArray_Impl<E, N, nsTArrayFallibleAllocator>
|
||||
{
|
||||
public:
|
||||
typedef AlignedTArray_Impl<E, N, nsTArrayFallibleAllocator> base_type;
|
||||
typedef AlignedFallibleTArray<E, N> self_type;
|
||||
typedef typename base_type::size_type size_type;
|
||||
|
||||
AlignedFallibleTArray() {}
|
||||
explicit AlignedFallibleTArray(size_type capacity) : base_type(capacity) {}
|
||||
private:
|
||||
AlignedFallibleTArray(const AlignedFallibleTArray& other) = delete;
|
||||
void operator=(const AlignedFallibleTArray& other) = delete;
|
||||
};
|
||||
|
||||
#endif // AlignedTArray_h__
|
||||
|
@ -251,11 +251,11 @@ bool
|
||||
AnalyserNode::FFTAnalysis()
|
||||
{
|
||||
float* inputBuffer;
|
||||
AlignedFallibleTArray<float> tmpBuffer;
|
||||
AlignedTArray<float> tmpBuffer;
|
||||
if (mWriteIndex == 0) {
|
||||
inputBuffer = mBuffer.Elements();
|
||||
} else {
|
||||
if (!tmpBuffer.SetLength(FftSize())) {
|
||||
if (!tmpBuffer.SetLength(FftSize(), fallible)) {
|
||||
return false;
|
||||
}
|
||||
inputBuffer = tmpBuffer.Elements();
|
||||
@ -301,13 +301,13 @@ AnalyserNode::AllocateBuffer()
|
||||
{
|
||||
bool result = true;
|
||||
if (mBuffer.Length() != FftSize()) {
|
||||
if (!mBuffer.SetLength(FftSize())) {
|
||||
if (!mBuffer.SetLength(FftSize(), fallible)) {
|
||||
return false;
|
||||
}
|
||||
memset(mBuffer.Elements(), 0, sizeof(float) * FftSize());
|
||||
mWriteIndex = 0;
|
||||
|
||||
if (!mOutputBuffer.SetLength(FrequencyBinCount())) {
|
||||
if (!mOutputBuffer.SetLength(FrequencyBinCount(), fallible)) {
|
||||
return false;
|
||||
}
|
||||
memset(mOutputBuffer.Elements(), 0, sizeof(float) * FrequencyBinCount());
|
||||
|
@ -78,8 +78,8 @@ private:
|
||||
double mMaxDecibels;
|
||||
double mSmoothingTimeConstant;
|
||||
uint32_t mWriteIndex;
|
||||
AlignedFallibleTArray<float> mBuffer;
|
||||
AlignedFallibleTArray<float> mOutputBuffer;
|
||||
AlignedTArray<float> mBuffer;
|
||||
AlignedTArray<float> mOutputBuffer;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
@ -135,7 +135,7 @@ mozilla::plugins::SetupBridge(uint32_t aPluginId,
|
||||
// We are going to abort due to the failure, lets note the cause
|
||||
// in the report for diagnosing.
|
||||
nsAutoCString error;
|
||||
error.AppendPrintf("%X", *rv);
|
||||
error.AppendPrintf("%X %d", *rv, chromeParent->GetIPCChannel()->GetChannelState__TotallyRacy());
|
||||
CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("BridgePluginError"), error);
|
||||
#endif
|
||||
return false;
|
||||
|
@ -179,6 +179,20 @@ SpeakerManagerService::Observe(nsISupports* aSubject,
|
||||
} else {
|
||||
NS_WARNING("ipc:content-shutdown message without childID property");
|
||||
}
|
||||
} else if (!strcmp(aTopic, "xpcom-will-shutdown")) {
|
||||
// Note that we need to do this before xpcom-shutdown, since the
|
||||
// AudioChannelService cannot be used past that point.
|
||||
nsRefPtr<AudioChannelService> audioChannelService =
|
||||
AudioChannelService::GetOrCreate();
|
||||
audioChannelService->UnregisterSpeakerManager(this);
|
||||
|
||||
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
|
||||
if (obs) {
|
||||
obs->RemoveObserver(this, "ipc:content-shutdown");
|
||||
obs->RemoveObserver(this, "xpcom-will-shutdown");
|
||||
}
|
||||
|
||||
Shutdown();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
@ -192,6 +206,7 @@ SpeakerManagerService::SpeakerManagerService()
|
||||
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
|
||||
if (obs) {
|
||||
obs->AddObserver(this, "ipc:content-shutdown", false);
|
||||
obs->AddObserver(this, "xpcom-will-shutdown", false);
|
||||
}
|
||||
}
|
||||
nsRefPtr<AudioChannelService> audioChannelService =
|
||||
@ -202,7 +217,4 @@ SpeakerManagerService::SpeakerManagerService()
|
||||
SpeakerManagerService::~SpeakerManagerService()
|
||||
{
|
||||
MOZ_COUNT_DTOR(SpeakerManagerService);
|
||||
nsRefPtr<AudioChannelService> audioChannelService =
|
||||
AudioChannelService::GetOrCreate();
|
||||
audioChannelService->UnregisterSpeakerManager(this);
|
||||
}
|
||||
|
@ -46,10 +46,6 @@ public:
|
||||
{
|
||||
mRegisteredSpeakerManagers.RemoveElement(aSpeakerManager);
|
||||
}
|
||||
/**
|
||||
* Shutdown the singleton.
|
||||
*/
|
||||
static void Shutdown();
|
||||
|
||||
protected:
|
||||
SpeakerManagerService();
|
||||
@ -60,6 +56,11 @@ protected:
|
||||
|
||||
void TurnOnSpeaker(bool aEnable);
|
||||
|
||||
/**
|
||||
* Shutdown the singleton.
|
||||
*/
|
||||
static void Shutdown();
|
||||
|
||||
nsTArray<nsRefPtr<SpeakerManager> > mRegisteredSpeakerManagers;
|
||||
// Set for remember all the child speaker status
|
||||
nsCheapSet<nsUint64HashKey> mSpeakerStatusSet;
|
||||
|
@ -1729,6 +1729,7 @@ ScriptExecutorRunnable::WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
|
||||
if (NS_FAILED(loadInfo.mLoadResult)) {
|
||||
scriptloader::ReportLoadError(aCx, loadInfo.mURL, loadInfo.mLoadResult,
|
||||
false);
|
||||
aWorkerPrivate->MaybeDispatchLoadFailedRunnable();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -164,8 +164,13 @@ ServiceWorkerContainer::GetController()
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// TODO: What should we do here if the ServiceWorker script fails to load?
|
||||
// In theory the DOM ServiceWorker object can exist without the worker
|
||||
// thread running, but it seems our design does not expect that.
|
||||
nsCOMPtr<nsISupports> serviceWorker;
|
||||
rv = swm->GetDocumentController(GetOwner(), getter_AddRefs(serviceWorker));
|
||||
rv = swm->GetDocumentController(GetOwner(),
|
||||
nullptr, // aLoadFailedRunnable
|
||||
getter_AddRefs(serviceWorker));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -1062,6 +1062,11 @@ public:
|
||||
MOZ_ASSERT(!data->mSetOfScopesBeingUpdated.Contains(mRegistration->mScope));
|
||||
data->mSetOfScopesBeingUpdated.Put(mRegistration->mScope, true);
|
||||
|
||||
// Call FailScopeUpdate on main thread if the SW script load fails below.
|
||||
nsCOMPtr<nsIRunnable> failRunnable = NS_NewRunnableMethodWithArgs
|
||||
<StorensRefPtrPassByPtr<ServiceWorkerManager>, nsCString>
|
||||
(this, &ServiceWorkerRegisterJob::FailScopeUpdate, swm, scopeKey);
|
||||
|
||||
MOZ_ASSERT(!mUpdateAndInstallInfo);
|
||||
mUpdateAndInstallInfo =
|
||||
new ServiceWorkerInfo(mRegistration, mRegistration->mScriptSpec,
|
||||
@ -1069,11 +1074,11 @@ public:
|
||||
nsRefPtr<ServiceWorker> serviceWorker;
|
||||
rv = swm->CreateServiceWorker(mRegistration->mPrincipal,
|
||||
mUpdateAndInstallInfo,
|
||||
failRunnable,
|
||||
getter_AddRefs(serviceWorker));
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
data->mSetOfScopesBeingUpdated.Remove(mRegistration->mScope);
|
||||
return Fail(NS_ERROR_DOM_ABORT_ERR);
|
||||
return FailScopeUpdate(swm, scopeKey);
|
||||
}
|
||||
|
||||
nsRefPtr<ServiceWorkerJob> upcasted = this;
|
||||
@ -1088,11 +1093,22 @@ public:
|
||||
jsapi.Init();
|
||||
bool ok = r->Dispatch(jsapi.cx());
|
||||
if (NS_WARN_IF(!ok)) {
|
||||
data->mSetOfScopesBeingUpdated.Remove(mRegistration->mScope);
|
||||
return Fail(NS_ERROR_DOM_ABORT_ERR);
|
||||
return FailScopeUpdate(swm, scopeKey);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FailScopeUpdate(ServiceWorkerManager* aSwm, const nsACString& aScopeKey)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(aSwm);
|
||||
ServiceWorkerManager::RegistrationDataPerPrincipal* data;
|
||||
if (aSwm->mRegistrationInfos.Get(aScopeKey, &data)) {
|
||||
data->mSetOfScopesBeingUpdated.Remove(aScopeKey);
|
||||
}
|
||||
Fail(NS_ERROR_DOM_ABORT_ERR);
|
||||
}
|
||||
|
||||
// Public so our error handling code can use it.
|
||||
// Callers MUST hold a strong ref before calling this!
|
||||
void
|
||||
@ -1168,9 +1184,15 @@ public:
|
||||
|
||||
NS_DispatchToMainThread(upr);
|
||||
|
||||
// Call ContinueAfterInstallEvent(false, false) on main thread if the SW
|
||||
// script fails to load.
|
||||
nsCOMPtr<nsIRunnable> failRunnable = NS_NewRunnableMethodWithArgs<bool, bool>
|
||||
(this, &ServiceWorkerRegisterJob::ContinueAfterInstallEvent, false, false);
|
||||
|
||||
nsRefPtr<ServiceWorker> serviceWorker;
|
||||
rv = swm->CreateServiceWorker(mRegistration->mPrincipal,
|
||||
mRegistration->mInstallingWorker,
|
||||
failRunnable,
|
||||
getter_AddRefs(serviceWorker));
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
@ -1834,18 +1856,20 @@ ServiceWorkerRegistrationInfo::Activate()
|
||||
this);
|
||||
NS_DispatchToMainThread(controllerChangeRunnable);
|
||||
|
||||
nsCOMPtr<nsIRunnable> failRunnable =
|
||||
NS_NewRunnableMethodWithArg<bool>(this,
|
||||
&ServiceWorkerRegistrationInfo::FinishActivate,
|
||||
false /* success */);
|
||||
|
||||
MOZ_ASSERT(mActiveWorker);
|
||||
nsRefPtr<ServiceWorker> serviceWorker;
|
||||
nsresult rv =
|
||||
swm->CreateServiceWorker(mPrincipal,
|
||||
mActiveWorker,
|
||||
failRunnable,
|
||||
getter_AddRefs(serviceWorker));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
nsCOMPtr<nsIRunnable> r =
|
||||
NS_NewRunnableMethodWithArg<bool>(this,
|
||||
&ServiceWorkerRegistrationInfo::FinishActivate,
|
||||
false /* success */);
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(r)));
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(failRunnable)));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -2227,7 +2251,7 @@ ServiceWorkerManager::SendPushEvent(const nsACString& aOriginAttributes,
|
||||
}
|
||||
|
||||
nsRefPtr<ServiceWorker> serviceWorker =
|
||||
CreateServiceWorkerForScope(attrs, aScope);
|
||||
CreateServiceWorkerForScope(attrs, aScope, nullptr /* failure runnable */);
|
||||
if (!serviceWorker) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
@ -2262,7 +2286,7 @@ ServiceWorkerManager::SendPushSubscriptionChangeEvent(const nsACString& aOriginA
|
||||
}
|
||||
|
||||
nsRefPtr<ServiceWorker> serviceWorker =
|
||||
CreateServiceWorkerForScope(attrs, aScope);
|
||||
CreateServiceWorkerForScope(attrs, aScope, nullptr /* fail runnable */);
|
||||
if (!serviceWorker) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
@ -2387,7 +2411,8 @@ ServiceWorkerManager::SendNotificationClickEvent(const nsACString& aOriginSuffix
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
nsRefPtr<ServiceWorker> serviceWorker = CreateServiceWorkerForScope(attrs, aScope);
|
||||
nsRefPtr<ServiceWorker> serviceWorker =
|
||||
CreateServiceWorkerForScope(attrs, aScope, nullptr);
|
||||
if (!serviceWorker) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
@ -2525,7 +2550,8 @@ ServiceWorkerManager::CheckReadyPromise(nsPIDOMWindow* aWindow,
|
||||
|
||||
already_AddRefed<ServiceWorker>
|
||||
ServiceWorkerManager::CreateServiceWorkerForScope(const OriginAttributes& aOriginAttributes,
|
||||
const nsACString& aScope)
|
||||
const nsACString& aScope,
|
||||
nsIRunnable* aLoadFailedRunnable)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
|
||||
@ -2547,6 +2573,7 @@ ServiceWorkerManager::CreateServiceWorkerForScope(const OriginAttributes& aOrigi
|
||||
nsRefPtr<ServiceWorker> sw;
|
||||
rv = CreateServiceWorker(registration->mPrincipal,
|
||||
registration->mActiveWorker,
|
||||
aLoadFailedRunnable,
|
||||
getter_AddRefs(sw));
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
@ -2827,6 +2854,7 @@ ServiceWorkerRegistrationInfo::FinishActivate(bool aSuccess)
|
||||
NS_IMETHODIMP
|
||||
ServiceWorkerManager::CreateServiceWorkerForWindow(nsPIDOMWindow* aWindow,
|
||||
ServiceWorkerInfo* aInfo,
|
||||
nsIRunnable* aLoadFailedRunnable,
|
||||
ServiceWorker** aServiceWorker)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
@ -2851,6 +2879,7 @@ ServiceWorkerManager::CreateServiceWorkerForWindow(nsPIDOMWindow* aWindow,
|
||||
MOZ_ASSERT(!aInfo->CacheName().IsEmpty());
|
||||
loadInfo.mServiceWorkerCacheName = aInfo->CacheName();
|
||||
loadInfo.mServiceWorkerID = aInfo->ID();
|
||||
loadInfo.mLoadFailedAsyncRunnable = aLoadFailedRunnable;
|
||||
|
||||
RuntimeService* rs = RuntimeService::GetOrCreateService();
|
||||
if (!rs) {
|
||||
@ -3418,9 +3447,13 @@ ServiceWorkerManager::GetServiceWorkerForScope(nsIDOMWindow* aWindow,
|
||||
return NS_ERROR_DOM_NOT_FOUND_ERR;
|
||||
}
|
||||
|
||||
// TODO: How should we handle async failure of SW load for getters? In
|
||||
// theory getting a handle to the DOM ServiceWorker object should not
|
||||
// require the worker thread to actually be running.
|
||||
nsRefPtr<ServiceWorker> serviceWorker;
|
||||
rv = CreateServiceWorkerForWindow(window,
|
||||
info,
|
||||
nullptr, // load failed runnable
|
||||
getter_AddRefs(serviceWorker));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
@ -3690,11 +3723,17 @@ ServiceWorkerManager::DispatchFetchEvent(const OriginAttributes& aOriginAttribut
|
||||
return;
|
||||
}
|
||||
|
||||
// if the ServiceWorker script fails to load for some reason, just resume
|
||||
// the original channel.
|
||||
nsCOMPtr<nsIRunnable> failRunnable =
|
||||
NS_NewRunnableMethod(aChannel, &nsIInterceptedChannel::ResetInterception);
|
||||
|
||||
nsAutoPtr<ServiceWorkerClientInfo> clientInfo;
|
||||
|
||||
if (!isNavigation) {
|
||||
MOZ_ASSERT(aDoc);
|
||||
aRv = GetDocumentController(aDoc->GetInnerWindow(), getter_AddRefs(serviceWorker));
|
||||
aRv = GetDocumentController(aDoc->GetInnerWindow(), failRunnable,
|
||||
getter_AddRefs(serviceWorker));
|
||||
clientInfo = new ServiceWorkerClientInfo(aDoc, aDoc->GetWindow());
|
||||
} else {
|
||||
nsCOMPtr<nsIChannel> internalChannel;
|
||||
@ -3723,6 +3762,7 @@ ServiceWorkerManager::DispatchFetchEvent(const OriginAttributes& aOriginAttribut
|
||||
nsRefPtr<ServiceWorker> sw;
|
||||
aRv = CreateServiceWorker(registration->mPrincipal,
|
||||
registration->mActiveWorker,
|
||||
failRunnable,
|
||||
getter_AddRefs(sw));
|
||||
serviceWorker = sw.forget();
|
||||
}
|
||||
@ -3806,7 +3846,9 @@ ServiceWorkerManager::GetDocumentRegistration(nsIDocument* aDoc,
|
||||
* the document was loaded.
|
||||
*/
|
||||
NS_IMETHODIMP
|
||||
ServiceWorkerManager::GetDocumentController(nsIDOMWindow* aWindow, nsISupports** aServiceWorker)
|
||||
ServiceWorkerManager::GetDocumentController(nsIDOMWindow* aWindow,
|
||||
nsIRunnable* aLoadFailedRunnable,
|
||||
nsISupports** aServiceWorker)
|
||||
{
|
||||
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aWindow);
|
||||
MOZ_ASSERT(window);
|
||||
@ -3825,6 +3867,7 @@ ServiceWorkerManager::GetDocumentController(nsIDOMWindow* aWindow, nsISupports**
|
||||
nsRefPtr<ServiceWorker> serviceWorker;
|
||||
rv = CreateServiceWorkerForWindow(window,
|
||||
registration->mActiveWorker,
|
||||
aLoadFailedRunnable,
|
||||
getter_AddRefs(serviceWorker));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
@ -3867,6 +3910,7 @@ ServiceWorkerManager::GetActive(nsIDOMWindow* aWindow,
|
||||
NS_IMETHODIMP
|
||||
ServiceWorkerManager::CreateServiceWorker(nsIPrincipal* aPrincipal,
|
||||
ServiceWorkerInfo* aInfo,
|
||||
nsIRunnable* aLoadFailedRunnable,
|
||||
ServiceWorker** aServiceWorker)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
@ -3921,6 +3965,8 @@ ServiceWorkerManager::CreateServiceWorker(nsIPrincipal* aPrincipal,
|
||||
// them here.
|
||||
WorkerPrivate::OverrideLoadInfoLoadGroup(info);
|
||||
|
||||
info.mLoadFailedAsyncRunnable = aLoadFailedRunnable;
|
||||
|
||||
RuntimeService* rs = RuntimeService::GetOrCreateService();
|
||||
if (!rs) {
|
||||
return NS_ERROR_FAILURE;
|
||||
|
@ -420,11 +420,13 @@ private:
|
||||
NS_IMETHOD
|
||||
CreateServiceWorkerForWindow(nsPIDOMWindow* aWindow,
|
||||
ServiceWorkerInfo* aInfo,
|
||||
nsIRunnable* aLoadFailedRunnable,
|
||||
ServiceWorker** aServiceWorker);
|
||||
|
||||
NS_IMETHOD
|
||||
CreateServiceWorker(nsIPrincipal* aPrincipal,
|
||||
ServiceWorkerInfo* aInfo,
|
||||
nsIRunnable* aLoadFailedRunnable,
|
||||
ServiceWorker** aServiceWorker);
|
||||
|
||||
NS_IMETHODIMP
|
||||
@ -435,7 +437,8 @@ private:
|
||||
|
||||
already_AddRefed<ServiceWorker>
|
||||
CreateServiceWorkerForScope(const OriginAttributes& aOriginAttributes,
|
||||
const nsACString& aScope);
|
||||
const nsACString& aScope,
|
||||
nsIRunnable* aLoadFailedRunnable);
|
||||
|
||||
void
|
||||
InvalidateServiceWorkerRegistrationWorker(ServiceWorkerRegistrationInfo* aRegistration,
|
||||
|
@ -2384,6 +2384,9 @@ WorkerLoadInfo::StealFrom(WorkerLoadInfo& aOther)
|
||||
MOZ_ASSERT(!mLoadGroup);
|
||||
aOther.mLoadGroup.swap(mLoadGroup);
|
||||
|
||||
MOZ_ASSERT(!mLoadFailedAsyncRunnable);
|
||||
aOther.mLoadFailedAsyncRunnable.swap(mLoadFailedAsyncRunnable);
|
||||
|
||||
MOZ_ASSERT(!mInterfaceRequestor);
|
||||
aOther.mInterfaceRequestor.swap(mInterfaceRequestor);
|
||||
|
||||
@ -3418,7 +3421,7 @@ WorkerPrivateParent<Derived>::ForgetMainThreadObjects(
|
||||
AssertIsOnParentThread();
|
||||
MOZ_ASSERT(!mMainThreadObjectsForgotten);
|
||||
|
||||
static const uint32_t kDoomedCount = 9;
|
||||
static const uint32_t kDoomedCount = 10;
|
||||
|
||||
aDoomed.SetCapacity(kDoomedCount);
|
||||
|
||||
@ -3430,6 +3433,7 @@ WorkerPrivateParent<Derived>::ForgetMainThreadObjects(
|
||||
SwapToISupportsArray(mLoadInfo.mChannel, aDoomed);
|
||||
SwapToISupportsArray(mLoadInfo.mCSP, aDoomed);
|
||||
SwapToISupportsArray(mLoadInfo.mLoadGroup, aDoomed);
|
||||
SwapToISupportsArray(mLoadInfo.mLoadFailedAsyncRunnable, aDoomed);
|
||||
SwapToISupportsArray(mLoadInfo.mInterfaceRequestor, aDoomed);
|
||||
// Before adding anything here update kDoomedCount above!
|
||||
|
||||
@ -5466,6 +5470,19 @@ WorkerPrivate::RunBeforeNextEvent(nsIRunnable* aRunnable)
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
WorkerPrivate::MaybeDispatchLoadFailedRunnable()
|
||||
{
|
||||
AssertIsOnWorkerThread();
|
||||
|
||||
nsCOMPtr<nsIRunnable> runnable = StealLoadFailedAsyncRunnable();
|
||||
if (!runnable) {
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(runnable.forget())));
|
||||
}
|
||||
|
||||
void
|
||||
WorkerPrivate::InitializeGCTimers()
|
||||
{
|
||||
|
@ -798,6 +798,12 @@ public:
|
||||
void
|
||||
UpdateOverridenLoadGroup(nsILoadGroup* aBaseLoadGroup);
|
||||
|
||||
already_AddRefed<nsIRunnable>
|
||||
StealLoadFailedAsyncRunnable()
|
||||
{
|
||||
return mLoadInfo.mLoadFailedAsyncRunnable.forget();
|
||||
}
|
||||
|
||||
IMPL_EVENT_HANDLER(message)
|
||||
IMPL_EVENT_HANDLER(error)
|
||||
|
||||
@ -956,6 +962,9 @@ class WorkerPrivate : public WorkerPrivateParent<WorkerPrivate>
|
||||
|
||||
nsRefPtrHashtable<nsUint64HashKey, MessagePort> mWorkerPorts;
|
||||
|
||||
// fired on the main thread if the worker script fails to load
|
||||
nsCOMPtr<nsIRunnable> mLoadFailedRunnable;
|
||||
|
||||
TimeStamp mKillTime;
|
||||
uint32_t mErrorHandlerRecursionCount;
|
||||
uint32_t mNextTimeoutId;
|
||||
@ -1367,6 +1376,9 @@ public:
|
||||
bool
|
||||
RunBeforeNextEvent(nsIRunnable* aRunnable);
|
||||
|
||||
void
|
||||
MaybeDispatchLoadFailedRunnable();
|
||||
|
||||
private:
|
||||
WorkerPrivate(JSContext* aCx, WorkerPrivate* aParent,
|
||||
const nsAString& aScriptURL, bool aIsChromeWorker,
|
||||
|
@ -39,6 +39,7 @@ class nsIPrincipal;
|
||||
class nsILoadGroup;
|
||||
class nsITabChild;
|
||||
class nsIChannel;
|
||||
class nsIRunnable;
|
||||
class nsIURI;
|
||||
|
||||
namespace mozilla {
|
||||
@ -221,6 +222,12 @@ struct WorkerLoadInfo
|
||||
nsCOMPtr<nsIChannel> mChannel;
|
||||
nsCOMPtr<nsILoadGroup> mLoadGroup;
|
||||
|
||||
// mLoadFailedAsyncRunnable will execute on main thread if script loading
|
||||
// fails during script loading. If script loading is never started due to
|
||||
// a synchronous error, then the runnable is never executed. The runnable
|
||||
// is guaranteed to be released on the main thread.
|
||||
nsCOMPtr<nsIRunnable> mLoadFailedAsyncRunnable;
|
||||
|
||||
class InterfaceRequestor final : public nsIInterfaceRequestor
|
||||
{
|
||||
NS_DECL_ISUPPORTS
|
||||
|
@ -206,7 +206,9 @@ nsEditingSession::DisableJSAndPlugins(nsIDOMWindow *aWindow)
|
||||
NS_IMETHODIMP
|
||||
nsEditingSession::RestoreJSAndPlugins(nsIDOMWindow *aWindow)
|
||||
{
|
||||
NS_ENSURE_TRUE(mDisabledJSAndPlugins, NS_OK);
|
||||
if (!mDisabledJSAndPlugins) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
mDisabledJSAndPlugins = false;
|
||||
|
||||
|
@ -1455,57 +1455,31 @@ nsPermissionManager::GetPermissionHashKey(const nsACString& aHost,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// helper struct for passing arguments into hash enumeration callback.
|
||||
struct nsGetEnumeratorData
|
||||
{
|
||||
nsGetEnumeratorData(nsCOMArray<nsIPermission> *aArray,
|
||||
const nsTArray<nsCString> *aTypes,
|
||||
int64_t aSince = 0)
|
||||
: array(aArray)
|
||||
, types(aTypes)
|
||||
, since(aSince) {}
|
||||
|
||||
nsCOMArray<nsIPermission> *array;
|
||||
const nsTArray<nsCString> *types;
|
||||
int64_t since;
|
||||
};
|
||||
|
||||
static PLDHashOperator
|
||||
AddPermissionsToList(nsPermissionManager::PermissionHashKey* entry, void *arg)
|
||||
{
|
||||
nsGetEnumeratorData *data = static_cast<nsGetEnumeratorData *>(arg);
|
||||
|
||||
for (uint32_t i = 0; i < entry->GetPermissions().Length(); ++i) {
|
||||
nsPermissionManager::PermissionEntry& permEntry = entry->GetPermissions()[i];
|
||||
|
||||
// given how "default" permissions work and the possibility of them being
|
||||
// overridden with UNKNOWN_ACTION, we might see this value here - but we
|
||||
// do *not* want to return them via the enumerator.
|
||||
if (permEntry.mPermission == nsIPermissionManager::UNKNOWN_ACTION) {
|
||||
continue;
|
||||
}
|
||||
|
||||
nsPermission *perm = new nsPermission(entry->GetKey()->mHost,
|
||||
entry->GetKey()->mAppId,
|
||||
entry->GetKey()->mIsInBrowserElement,
|
||||
data->types->ElementAt(permEntry.mType),
|
||||
permEntry.mPermission,
|
||||
permEntry.mExpireType,
|
||||
permEntry.mExpireTime);
|
||||
|
||||
data->array->AppendObject(perm);
|
||||
}
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsPermissionManager::GetEnumerator(nsISimpleEnumerator **aEnum)
|
||||
{
|
||||
// roll an nsCOMArray of all our permissions, then hand out an enumerator
|
||||
nsCOMArray<nsIPermission> array;
|
||||
nsGetEnumeratorData data(&array, &mTypeArray);
|
||||
|
||||
mPermissionTable.EnumerateEntries(AddPermissionsToList, &data);
|
||||
for (auto iter = mPermissionTable.Iter(); !iter.Done(); iter.Next()) {
|
||||
PermissionHashKey* entry = iter.Get();
|
||||
for (const auto& permEntry : entry->GetPermissions()) {
|
||||
// Given how "default" permissions work and the possibility of them being
|
||||
// overridden with UNKNOWN_ACTION, we might see this value here - but we
|
||||
// do *not* want to return them via the enumerator.
|
||||
if (permEntry.mPermission == nsIPermissionManager::UNKNOWN_ACTION) {
|
||||
continue;
|
||||
}
|
||||
|
||||
array.AppendObject(
|
||||
new nsPermission(entry->GetKey()->mHost,
|
||||
entry->GetKey()->mAppId,
|
||||
entry->GetKey()->mIsInBrowserElement,
|
||||
mTypeArray.ElementAt(permEntry.mType),
|
||||
permEntry.mPermission,
|
||||
permEntry.mExpireType,
|
||||
permEntry.mExpireTime));
|
||||
}
|
||||
}
|
||||
|
||||
return NS_NewArrayEnumerator(aEnum, array);
|
||||
}
|
||||
@ -1529,42 +1503,29 @@ NS_IMETHODIMP nsPermissionManager::Observe(nsISupports *aSubject, const char *aT
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static PLDHashOperator
|
||||
AddPermissionsModifiedSinceToList(
|
||||
nsPermissionManager::PermissionHashKey* entry, void* arg)
|
||||
{
|
||||
nsGetEnumeratorData* data = static_cast<nsGetEnumeratorData *>(arg);
|
||||
|
||||
for (size_t i = 0; i < entry->GetPermissions().Length(); ++i) {
|
||||
const nsPermissionManager::PermissionEntry& permEntry = entry->GetPermissions()[i];
|
||||
|
||||
if (data->since > permEntry.mModificationTime) {
|
||||
continue;
|
||||
}
|
||||
|
||||
nsPermission* perm = new nsPermission(entry->GetKey()->mHost,
|
||||
entry->GetKey()->mAppId,
|
||||
entry->GetKey()->mIsInBrowserElement,
|
||||
data->types->ElementAt(permEntry.mType),
|
||||
permEntry.mPermission,
|
||||
permEntry.mExpireType,
|
||||
permEntry.mExpireTime);
|
||||
|
||||
data->array->AppendObject(perm);
|
||||
}
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsPermissionManager::RemoveAllModifiedSince(int64_t aModificationTime)
|
||||
{
|
||||
ENSURE_NOT_CHILD_PROCESS;
|
||||
|
||||
// roll an nsCOMArray of all our permissions, then hand out an enumerator
|
||||
nsCOMArray<nsIPermission> array;
|
||||
nsGetEnumeratorData data(&array, &mTypeArray, aModificationTime);
|
||||
for (auto iter = mPermissionTable.Iter(); !iter.Done(); iter.Next()) {
|
||||
PermissionHashKey* entry = iter.Get();
|
||||
for (const auto& permEntry : entry->GetPermissions()) {
|
||||
if (aModificationTime > permEntry.mModificationTime) {
|
||||
continue;
|
||||
}
|
||||
|
||||
mPermissionTable.EnumerateEntries(AddPermissionsModifiedSinceToList, &data);
|
||||
array.AppendObject(
|
||||
new nsPermission(entry->GetKey()->mHost,
|
||||
entry->GetKey()->mAppId,
|
||||
entry->GetKey()->mIsInBrowserElement,
|
||||
mTypeArray.ElementAt(permEntry.mType),
|
||||
permEntry.mPermission,
|
||||
permEntry.mExpireType,
|
||||
permEntry.mExpireTime));
|
||||
}
|
||||
}
|
||||
|
||||
for (int32_t i = 0; i<array.Count(); ++i) {
|
||||
nsAutoCString host;
|
||||
@ -1599,31 +1560,6 @@ nsPermissionManager::RemoveAllModifiedSince(int64_t aModificationTime)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
PLDHashOperator
|
||||
nsPermissionManager::GetPermissionsForApp(nsPermissionManager::PermissionHashKey* entry, void* arg)
|
||||
{
|
||||
GetPermissionsForAppStruct* data = static_cast<GetPermissionsForAppStruct*>(arg);
|
||||
|
||||
for (uint32_t i = 0; i < entry->GetPermissions().Length(); ++i) {
|
||||
nsPermissionManager::PermissionEntry& permEntry = entry->GetPermissions()[i];
|
||||
|
||||
if (entry->GetKey()->mAppId != data->appId ||
|
||||
(data->browserOnly && !entry->GetKey()->mIsInBrowserElement)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
data->permissions.AppendObject(new nsPermission(entry->GetKey()->mHost,
|
||||
entry->GetKey()->mAppId,
|
||||
entry->GetKey()->mIsInBrowserElement,
|
||||
gPermissionManager->mTypeArray.ElementAt(permEntry.mType),
|
||||
permEntry.mPermission,
|
||||
permEntry.mExpireType,
|
||||
permEntry.mExpireTime));
|
||||
}
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPermissionManager::RemovePermissionsForApp(uint32_t aAppId, bool aBrowserOnly)
|
||||
{
|
||||
@ -1634,9 +1570,9 @@ nsPermissionManager::RemovePermissionsForApp(uint32_t aAppId, bool aBrowserOnly)
|
||||
// After clearing the DB, we call AddInternal() to make sure that all
|
||||
// processes are aware of this change and the representation of the DB in
|
||||
// memory is updated.
|
||||
// We have to get all permissions associated with an application and then
|
||||
// remove those because doing so in EnumerateEntries() would fail because
|
||||
// we might happen to actually delete entries from the list.
|
||||
// We have to get all permissions associated with an application first
|
||||
// because removing entries from the permissions table while iterating over
|
||||
// it is dangerous.
|
||||
|
||||
nsAutoCString sql;
|
||||
sql.AppendLiteral("DELETE FROM moz_hosts WHERE appId=");
|
||||
@ -1654,17 +1590,34 @@ nsPermissionManager::RemovePermissionsForApp(uint32_t aAppId, bool aBrowserOnly)
|
||||
rv = removeStmt->ExecuteAsync(nullptr, getter_AddRefs(pending));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
GetPermissionsForAppStruct data(aAppId, aBrowserOnly);
|
||||
mPermissionTable.EnumerateEntries(GetPermissionsForApp, &data);
|
||||
nsCOMArray<nsIPermission> permissions;
|
||||
for (auto iter = mPermissionTable.Iter(); !iter.Done(); iter.Next()) {
|
||||
PermissionHashKey* entry = iter.Get();
|
||||
if (entry->GetKey()->mAppId != aAppId ||
|
||||
(aBrowserOnly && !entry->GetKey()->mIsInBrowserElement)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int32_t i=0; i<data.permissions.Count(); ++i) {
|
||||
for (const auto& permEntry : entry->GetPermissions()) {
|
||||
permissions.AppendObject(
|
||||
new nsPermission(entry->GetKey()->mHost,
|
||||
entry->GetKey()->mAppId,
|
||||
entry->GetKey()->mIsInBrowserElement,
|
||||
mTypeArray.ElementAt(permEntry.mType),
|
||||
permEntry.mPermission,
|
||||
permEntry.mExpireType,
|
||||
permEntry.mExpireTime));
|
||||
}
|
||||
}
|
||||
|
||||
for (int32_t i = 0; i < permissions.Count(); ++i) {
|
||||
nsAutoCString host;
|
||||
bool isInBrowserElement;
|
||||
nsAutoCString type;
|
||||
|
||||
data.permissions[i]->GetHost(host);
|
||||
data.permissions[i]->GetIsInBrowserElement(&isInBrowserElement);
|
||||
data.permissions[i]->GetType(type);
|
||||
permissions[i]->GetHost(host);
|
||||
permissions[i]->GetIsInBrowserElement(&isInBrowserElement);
|
||||
permissions[i]->GetType(type);
|
||||
|
||||
nsCOMPtr<nsIPrincipal> principal;
|
||||
if (NS_FAILED(GetPrincipal(host, aAppId, isInBrowserElement,
|
||||
@ -1687,63 +1640,59 @@ nsPermissionManager::RemovePermissionsForApp(uint32_t aAppId, bool aBrowserOnly)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
PLDHashOperator
|
||||
nsPermissionManager::RemoveExpiredPermissionsForAppEnumerator(
|
||||
nsPermissionManager::PermissionHashKey* entry, void* arg)
|
||||
{
|
||||
uint32_t* appId = static_cast<uint32_t*>(arg);
|
||||
|
||||
for (uint32_t i = 0; i < entry->GetPermissions().Length(); ++i) {
|
||||
if (entry->GetKey()->mAppId != *appId) {
|
||||
continue;
|
||||
}
|
||||
|
||||
nsPermissionManager::PermissionEntry& permEntry = entry->GetPermissions()[i];
|
||||
if (permEntry.mExpireType != nsIPermissionManager::EXPIRE_SESSION) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (permEntry.mNonSessionExpireType == nsIPermissionManager::EXPIRE_SESSION) {
|
||||
PermissionEntry oldPermissionEntry = entry->GetPermissions()[i];
|
||||
|
||||
entry->GetPermissions().RemoveElementAt(i);
|
||||
|
||||
gPermissionManager->NotifyObserversWithPermission(entry->GetKey()->mHost,
|
||||
entry->GetKey()->mAppId,
|
||||
entry->GetKey()->mIsInBrowserElement,
|
||||
gPermissionManager->mTypeArray.ElementAt(oldPermissionEntry.mType),
|
||||
oldPermissionEntry.mPermission,
|
||||
oldPermissionEntry.mExpireType,
|
||||
oldPermissionEntry.mExpireTime,
|
||||
MOZ_UTF16("deleted"));
|
||||
--i;
|
||||
continue;
|
||||
}
|
||||
|
||||
permEntry.mPermission = permEntry.mNonSessionPermission;
|
||||
permEntry.mExpireType = permEntry.mNonSessionExpireType;
|
||||
permEntry.mExpireTime = permEntry.mNonSessionExpireTime;
|
||||
|
||||
gPermissionManager->NotifyObserversWithPermission(entry->GetKey()->mHost,
|
||||
entry->GetKey()->mAppId,
|
||||
entry->GetKey()->mIsInBrowserElement,
|
||||
gPermissionManager->mTypeArray.ElementAt(permEntry.mType),
|
||||
permEntry.mPermission,
|
||||
permEntry.mExpireType,
|
||||
permEntry.mExpireTime,
|
||||
MOZ_UTF16("changed"));
|
||||
}
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsPermissionManager::RemoveExpiredPermissionsForApp(uint32_t aAppId)
|
||||
{
|
||||
ENSURE_NOT_CHILD_PROCESS;
|
||||
|
||||
if (aAppId != nsIScriptSecurityManager::NO_APP_ID) {
|
||||
mPermissionTable.EnumerateEntries(RemoveExpiredPermissionsForAppEnumerator, &aAppId);
|
||||
if (aAppId == nsIScriptSecurityManager::NO_APP_ID) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
for (auto iter = mPermissionTable.Iter(); !iter.Done(); iter.Next()) {
|
||||
PermissionHashKey* entry = iter.Get();
|
||||
if (entry->GetKey()->mAppId != aAppId) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < entry->GetPermissions().Length(); ++i) {
|
||||
PermissionEntry& permEntry = entry->GetPermissions()[i];
|
||||
if (permEntry.mExpireType != nsIPermissionManager::EXPIRE_SESSION) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (permEntry.mNonSessionExpireType ==
|
||||
nsIPermissionManager::EXPIRE_SESSION) {
|
||||
PermissionEntry oldPermEntry = entry->GetPermissions()[i];
|
||||
|
||||
entry->GetPermissions().RemoveElementAt(i);
|
||||
|
||||
NotifyObserversWithPermission(entry->GetKey()->mHost,
|
||||
entry->GetKey()->mAppId,
|
||||
entry->GetKey()->mIsInBrowserElement,
|
||||
mTypeArray.ElementAt(oldPermEntry.mType),
|
||||
oldPermEntry.mPermission,
|
||||
oldPermEntry.mExpireType,
|
||||
oldPermEntry.mExpireTime,
|
||||
MOZ_UTF16("deleted"));
|
||||
|
||||
--i;
|
||||
continue;
|
||||
}
|
||||
|
||||
permEntry.mPermission = permEntry.mNonSessionPermission;
|
||||
permEntry.mExpireType = permEntry.mNonSessionExpireType;
|
||||
permEntry.mExpireTime = permEntry.mNonSessionExpireTime;
|
||||
|
||||
NotifyObserversWithPermission(entry->GetKey()->mHost,
|
||||
entry->GetKey()->mAppId,
|
||||
entry->GetKey()->mIsInBrowserElement,
|
||||
mTypeArray.ElementAt(permEntry.mType),
|
||||
permEntry.mPermission,
|
||||
permEntry.mExpireType,
|
||||
permEntry.mExpireTime,
|
||||
MOZ_UTF16("changed"));
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
@ -272,41 +272,6 @@ private:
|
||||
|
||||
nsresult RemoveExpiredPermissionsForApp(uint32_t aAppId);
|
||||
|
||||
/**
|
||||
* This struct has to be passed as an argument to GetPermissionsForApp.
|
||||
* |appId| and |browserOnly| have to be defined.
|
||||
* |permissions| will be filed with permissions that are related to the app.
|
||||
* If |browserOnly| is true, only permissions related to a browserElement will
|
||||
* be in |permissions|.
|
||||
*/
|
||||
struct GetPermissionsForAppStruct {
|
||||
uint32_t appId;
|
||||
bool browserOnly;
|
||||
nsCOMArray<nsIPermission> permissions;
|
||||
|
||||
GetPermissionsForAppStruct() = delete;
|
||||
GetPermissionsForAppStruct(uint32_t aAppId, bool aBrowserOnly)
|
||||
: appId(aAppId)
|
||||
, browserOnly(aBrowserOnly)
|
||||
{}
|
||||
};
|
||||
|
||||
/**
|
||||
* This method will return the list of all permissions that are related to a
|
||||
* specific app.
|
||||
* @param arg has to be an instance of GetPermissionsForAppStruct.
|
||||
*/
|
||||
static PLDHashOperator
|
||||
GetPermissionsForApp(PermissionHashKey* entry, void* arg);
|
||||
|
||||
/**
|
||||
* This method restores an app's permissions when its session ends.
|
||||
*/
|
||||
static PLDHashOperator
|
||||
RemoveExpiredPermissionsForAppEnumerator(PermissionHashKey* entry,
|
||||
void* nonused);
|
||||
|
||||
|
||||
/**
|
||||
* This method removes all permissions modified after the specified time.
|
||||
*/
|
||||
|
@ -242,16 +242,6 @@ void mozPersonalDictionary::SyncLoadInternal()
|
||||
mDirty = false;
|
||||
}
|
||||
|
||||
// A little helper function to add the key to the list.
|
||||
// This is not threadsafe, and only safe if the consumer does not
|
||||
// modify the list.
|
||||
static PLDHashOperator
|
||||
AddHostToStringArray(nsUnicharPtrHashKey *aEntry, void *aArg)
|
||||
{
|
||||
static_cast<nsTArray<nsString>*>(aArg)->AppendElement(nsDependentString(aEntry->GetKey()));
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
/* void Save (); */
|
||||
NS_IMETHODIMP mozPersonalDictionary::Save()
|
||||
{
|
||||
@ -277,7 +267,9 @@ NS_IMETHODIMP mozPersonalDictionary::Save()
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
nsTArray<nsString> array(mDictionaryTable.Count());
|
||||
mDictionaryTable.EnumerateEntries(AddHostToStringArray, &array);
|
||||
for (auto iter = mDictionaryTable.Iter(); !iter.Done(); iter.Next()) {
|
||||
array.AppendElement(nsDependentString(iter.Get()->GetKey()));
|
||||
}
|
||||
|
||||
uint32_t bytesWritten;
|
||||
nsAutoCString utf8Key;
|
||||
@ -307,10 +299,9 @@ NS_IMETHODIMP mozPersonalDictionary::GetWordList(nsIStringEnumerator **aWords)
|
||||
WaitForLoad();
|
||||
|
||||
nsTArray<nsString> *array = new nsTArray<nsString>(mDictionaryTable.Count());
|
||||
if (!array)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
mDictionaryTable.EnumerateEntries(AddHostToStringArray, array);
|
||||
for (auto iter = mDictionaryTable.Iter(); !iter.Done(); iter.Next()) {
|
||||
array->AppendElement(nsDependentString(iter.Get()->GetKey()));
|
||||
}
|
||||
|
||||
array->Sort();
|
||||
|
||||
|
@ -866,7 +866,7 @@ ClientTiledLayerBuffer::GetSurfaceDescriptorTiles()
|
||||
// Reset the update rect
|
||||
tile.mUpdateRect = IntRect();
|
||||
}
|
||||
return SurfaceDescriptorTiles(mValidRegion, mPaintedRegion,
|
||||
return SurfaceDescriptorTiles(mValidRegion,
|
||||
tiles,
|
||||
mTiles.mFirst.x, mTiles.mFirst.y,
|
||||
mTiles.mSize.width, mTiles.mSize.height,
|
||||
|
@ -109,28 +109,13 @@ void
|
||||
UseTileTexture(CompositableTextureHostRef& aTexture,
|
||||
CompositableTextureSourceRef& aTextureSource,
|
||||
const IntRect& aUpdateRect,
|
||||
TextureHost* aNewTexture,
|
||||
Compositor* aCompositor)
|
||||
{
|
||||
MOZ_ASSERT(aNewTexture);
|
||||
if (!aNewTexture) {
|
||||
MOZ_ASSERT(aTexture);
|
||||
if (!aTexture) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (aTexture) {
|
||||
aTexture->SetCompositor(aCompositor);
|
||||
aNewTexture->SetCompositor(aCompositor);
|
||||
|
||||
if (aTexture->GetFormat() != aNewTexture->GetFormat()) {
|
||||
// Only reuse textures if their format match the new texture's.
|
||||
aTextureSource = nullptr;
|
||||
aTexture = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
aTexture = aNewTexture;
|
||||
|
||||
|
||||
if (aCompositor) {
|
||||
aTexture->SetCompositor(aCompositor);
|
||||
}
|
||||
@ -175,6 +160,83 @@ GetCopyOnWriteLock(const TileLock& ipcLock, TileHost& aTile, ISurfaceAllocator*
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
TiledLayerBufferComposite::MarkTilesForUnlock()
|
||||
{
|
||||
// Tiles without an internal buffer will have internal locks
|
||||
// held by the gpu driver until the previous draw operation has finished.
|
||||
// We don't know when that will be exactly, so wait until we start the
|
||||
// next composite before unlocking.
|
||||
for (TileHost& tile : mRetainedTiles) {
|
||||
// Tile with an internal buffer get unlocked as soon as we've uploaded,
|
||||
// so won't have a lock at this point.
|
||||
if (tile.mTextureHost && tile.mSharedLock) {
|
||||
mDelayedUnlocks.AppendElement(tile.mSharedLock);
|
||||
tile.mSharedLock = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class TextureSourceRecycler
|
||||
{
|
||||
public:
|
||||
explicit TextureSourceRecycler(nsTArray<TileHost>&& aTileSet)
|
||||
: mTiles(Move(aTileSet))
|
||||
, mFirstPossibility(0)
|
||||
{}
|
||||
|
||||
// Attempts to recycle a texture source that is already bound to the
|
||||
// texture host for aTile.
|
||||
void RecycleTextureSourceForTile(TileHost& aTile) {
|
||||
for (size_t i = mFirstPossibility; i < mTiles.Length(); i++) {
|
||||
// Skip over existing tiles without a retained texture source
|
||||
// and make sure we don't iterate them in the future.
|
||||
if (!mTiles[i].mTextureSource) {
|
||||
if (i == mFirstPossibility) {
|
||||
mFirstPossibility++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// If this tile matches, then copy across the retained texture source (if
|
||||
// any).
|
||||
if (aTile.mTextureHost == mTiles[i].mTextureHost) {
|
||||
aTile.mTextureSource = Move(mTiles[i].mTextureSource);
|
||||
if (aTile.mTextureHostOnWhite) {
|
||||
aTile.mTextureSourceOnWhite = Move(mTiles[i].mTextureSourceOnWhite);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Attempts to recycle any texture source to avoid needing to allocate
|
||||
// a new one.
|
||||
void RecycleTextureSource(TileHost& aTile) {
|
||||
for (size_t i = mFirstPossibility; i < mTiles.Length(); i++) {
|
||||
if (!mTiles[i].mTextureSource) {
|
||||
if (i == mFirstPossibility) {
|
||||
mFirstPossibility++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (mTiles[i].mTextureSource &&
|
||||
mTiles[i].mTextureHost->GetFormat() == aTile.mTextureHost->GetFormat()) {
|
||||
aTile.mTextureSource = Move(mTiles[i].mTextureSource);
|
||||
if (aTile.mTextureHostOnWhite) {
|
||||
aTile.mTextureSourceOnWhite = Move(mTiles[i].mTextureSourceOnWhite);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
nsTArray<TileHost> mTiles;
|
||||
size_t mFirstPossibility;
|
||||
};
|
||||
|
||||
bool
|
||||
TiledLayerBufferComposite::UseTiles(const SurfaceDescriptorTiles& aTiles,
|
||||
Compositor* aCompositor,
|
||||
@ -195,146 +257,97 @@ TiledLayerBufferComposite::UseTiles(const SurfaceDescriptorTiles& aTiles,
|
||||
return false;
|
||||
}
|
||||
|
||||
TilesPlacement oldTiles = mTiles;
|
||||
TilesPlacement newTiles(aTiles.firstTileX(), aTiles.firstTileY(),
|
||||
aTiles.retainedWidth(), aTiles.retainedHeight());
|
||||
|
||||
const InfallibleTArray<TileDescriptor>& tileDescriptors = aTiles.tiles();
|
||||
|
||||
nsTArray<TileHost> oldRetainedTiles;
|
||||
mRetainedTiles.SwapElements(oldRetainedTiles);
|
||||
// Step 1, unlock all the old tiles that haven't been unlocked yet. Any tiles that
|
||||
// exist in both the old and new sets will have been locked again by content, so this
|
||||
// doesn't result in the surface being writeable again.
|
||||
MarkTilesForUnlock();
|
||||
|
||||
TextureSourceRecycler oldRetainedTiles(Move(mRetainedTiles));
|
||||
mRetainedTiles.SetLength(tileDescriptors.Length());
|
||||
|
||||
// Step 1, we need to unlock tiles that don't have an internal buffer after the
|
||||
// next frame where they are replaced.
|
||||
// Since we are about to replace the tiles' textures, we need to keep their locks
|
||||
// somewhere (in mPreviousSharedLock) until we composite the layer.
|
||||
for (size_t i = 0; i < oldRetainedTiles.Length(); ++i) {
|
||||
TileHost& tile = oldRetainedTiles[i];
|
||||
// It can happen that we still have a previous lock at this point,
|
||||
// if we changed a tile's front buffer (causing mSharedLock to
|
||||
// go into mPreviousSharedLock, and then did not composite that tile until
|
||||
// the next transaction, either because the tile is offscreen or because the
|
||||
// two transactions happened with no composition in between (over-production).
|
||||
tile.ReadUnlockPrevious();
|
||||
|
||||
if (tile.mTextureHost && !tile.mTextureHost->HasInternalBuffer()) {
|
||||
MOZ_ASSERT(tile.mSharedLock);
|
||||
const TileIntPoint tilePosition = oldTiles.TilePosition(i);
|
||||
if (newTiles.HasTile(tilePosition)) {
|
||||
// This tile still exist in the new buffer
|
||||
tile.mPreviousSharedLock = tile.mSharedLock;
|
||||
tile.mSharedLock = nullptr;
|
||||
} else {
|
||||
// This tile does not exist anymore in the new buffer because the size
|
||||
// changed.
|
||||
tile.ReadUnlock();
|
||||
}
|
||||
}
|
||||
|
||||
// By now we should not have anything in mSharedLock.
|
||||
MOZ_ASSERT(!tile.mSharedLock);
|
||||
}
|
||||
|
||||
// Step 2, move the tiles in mRetainedTiles at places that correspond to where
|
||||
// they should be with the new retained with and height rather than the
|
||||
// old one.
|
||||
// Step 2, deserialize the incoming set of tiles into mRetainedTiles, and attempt
|
||||
// to recycle the TextureSource for any repeated tiles.
|
||||
//
|
||||
// Since we don't have any retained 'tile' object, we have to search for instances
|
||||
// of the same TextureHost in the old tile set. The cost of binding a TextureHost
|
||||
// to a TextureSource for gralloc (binding EGLImage to GL texture) can be really
|
||||
// high, so we avoid this whenever possible.
|
||||
for (size_t i = 0; i < tileDescriptors.Length(); i++) {
|
||||
const TileIntPoint tilePosition = newTiles.TilePosition(i);
|
||||
// First, get the already existing tiles to the right place in the array,
|
||||
// and use placeholders where there was no tiles.
|
||||
if (!oldTiles.HasTile(tilePosition)) {
|
||||
mRetainedTiles[i] = GetPlaceholderTile();
|
||||
} else {
|
||||
mRetainedTiles[i] = oldRetainedTiles[oldTiles.TileIndex(tilePosition)];
|
||||
// If we hit this assertion it means we probably mixed something up in the
|
||||
// logic that tries to reuse tiles on the compositor side. It is most likely
|
||||
// benign, but we are missing some fast paths so let's try to make it not happen.
|
||||
MOZ_ASSERT(tilePosition.x == mRetainedTiles[i].x &&
|
||||
tilePosition.y == mRetainedTiles[i].y);
|
||||
}
|
||||
}
|
||||
|
||||
// It is important to remove the duplicated reference to tiles before calling
|
||||
// TextureHost::PrepareTextureSource, etc. because depending on the textures
|
||||
// ref counts we may or may not get some of the fast paths.
|
||||
oldRetainedTiles.Clear();
|
||||
|
||||
// Step 3, handle the texture updates and release the copy-on-write locks.
|
||||
for (size_t i = 0; i < mRetainedTiles.Length(); i++) {
|
||||
const TileDescriptor& tileDesc = tileDescriptors[i];
|
||||
|
||||
TileHost& tile = mRetainedTiles[i];
|
||||
|
||||
switch (tileDesc.type()) {
|
||||
case TileDescriptor::TTexturedTileDescriptor: {
|
||||
const TexturedTileDescriptor& texturedDesc = tileDesc.get_TexturedTileDescriptor();
|
||||
|
||||
const TileLock& ipcLock = texturedDesc.sharedLock();
|
||||
if (!GetCopyOnWriteLock(ipcLock, tile, aAllocator)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RefPtr<TextureHost> textureHost = TextureHost::AsTextureHost(
|
||||
texturedDesc.textureParent()
|
||||
);
|
||||
|
||||
RefPtr<TextureHost> textureOnWhite = nullptr;
|
||||
if (texturedDesc.textureOnWhite().type() == MaybeTexture::TPTextureParent) {
|
||||
textureOnWhite = TextureHost::AsTextureHost(
|
||||
texturedDesc.textureOnWhite().get_PTextureParent()
|
||||
);
|
||||
}
|
||||
|
||||
UseTileTexture(tile.mTextureHost,
|
||||
tile.mTextureSource,
|
||||
texturedDesc.updateRect(),
|
||||
textureHost,
|
||||
aCompositor);
|
||||
|
||||
if (textureOnWhite) {
|
||||
UseTileTexture(tile.mTextureHostOnWhite,
|
||||
tile.mTextureSourceOnWhite,
|
||||
texturedDesc.updateRect(),
|
||||
textureOnWhite,
|
||||
aCompositor);
|
||||
} else {
|
||||
// We could still have component alpha textures from a previous frame.
|
||||
tile.mTextureSourceOnWhite = nullptr;
|
||||
tile.mTextureHostOnWhite = nullptr;
|
||||
}
|
||||
|
||||
if (textureHost->HasInternalBuffer()) {
|
||||
// Now that we did the texture upload (in UseTileTexture), we can release
|
||||
// the lock.
|
||||
tile.ReadUnlock();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
NS_WARNING("Unrecognised tile descriptor type");
|
||||
case TileDescriptor::TPlaceholderTileDescriptor: {
|
||||
|
||||
if (tile.mTextureHost) {
|
||||
tile.mTextureHost->UnbindTextureSource();
|
||||
tile.mTextureSource = nullptr;
|
||||
}
|
||||
if (tile.mTextureHostOnWhite) {
|
||||
tile.mTextureHostOnWhite->UnbindTextureSource();
|
||||
tile.mTextureSourceOnWhite = nullptr;
|
||||
}
|
||||
// we may have a previous lock, and are about to loose our reference to it.
|
||||
// It is okay to unlock it because we just destroyed the texture source.
|
||||
tile.ReadUnlockPrevious();
|
||||
tile = GetPlaceholderTile();
|
||||
|
||||
break;
|
||||
}
|
||||
if (tileDesc.type() != TileDescriptor::TTexturedTileDescriptor) {
|
||||
NS_WARN_IF_FALSE(tileDesc.type() == TileDescriptor::TPlaceholderTileDescriptor,
|
||||
"Unrecognised tile descriptor type");
|
||||
continue;
|
||||
}
|
||||
|
||||
const TexturedTileDescriptor& texturedDesc = tileDesc.get_TexturedTileDescriptor();
|
||||
|
||||
const TileLock& ipcLock = texturedDesc.sharedLock();
|
||||
if (!GetCopyOnWriteLock(ipcLock, tile, aAllocator)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
tile.mTextureHost = TextureHost::AsTextureHost(texturedDesc.textureParent());
|
||||
|
||||
if (texturedDesc.textureOnWhite().type() == MaybeTexture::TPTextureParent) {
|
||||
tile.mTextureHostOnWhite =
|
||||
TextureHost::AsTextureHost(texturedDesc.textureOnWhite().get_PTextureParent());
|
||||
}
|
||||
|
||||
tile.mTilePosition = newTiles.TilePosition(i);
|
||||
|
||||
// If this same tile texture existed in the old tile set then this will move the texture
|
||||
// source into our new tile.
|
||||
oldRetainedTiles.RecycleTextureSourceForTile(tile);
|
||||
}
|
||||
|
||||
// Step 3, attempt to recycle unused texture sources from the old tile set into new tiles.
|
||||
//
|
||||
// For gralloc, binding a new TextureHost to the existing TextureSource is the fastest way
|
||||
// to ensure that any implicit locking on the old gralloc image is released.
|
||||
for (TileHost& tile : mRetainedTiles) {
|
||||
if (!tile.mTextureHost || tile.mTextureSource) {
|
||||
continue;
|
||||
}
|
||||
oldRetainedTiles.RecycleTextureSource(tile);
|
||||
}
|
||||
|
||||
// Step 4, handle the texture uploads, texture source binding and release the
|
||||
// copy-on-write locks for textures with an internal buffer.
|
||||
for (size_t i = 0; i < mRetainedTiles.Length(); i++) {
|
||||
TileHost& tile = mRetainedTiles[i];
|
||||
if (!tile.mTextureHost) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const TileDescriptor& tileDesc = tileDescriptors[i];
|
||||
const TexturedTileDescriptor& texturedDesc = tileDesc.get_TexturedTileDescriptor();
|
||||
|
||||
UseTileTexture(tile.mTextureHost,
|
||||
tile.mTextureSource,
|
||||
texturedDesc.updateRect(),
|
||||
aCompositor);
|
||||
|
||||
if (tile.mTextureHostOnWhite) {
|
||||
UseTileTexture(tile.mTextureHostOnWhite,
|
||||
tile.mTextureSourceOnWhite,
|
||||
texturedDesc.updateRect(),
|
||||
aCompositor);
|
||||
}
|
||||
|
||||
if (tile.mTextureHost->HasInternalBuffer()) {
|
||||
// Now that we did the texture upload (in UseTileTexture), we can release
|
||||
// the lock.
|
||||
tile.ReadUnlock();
|
||||
}
|
||||
TileIntPoint tilePosition = newTiles.TilePosition(i);
|
||||
tile.x = tilePosition.x;
|
||||
tile.y = tilePosition.y;
|
||||
}
|
||||
|
||||
mTiles = newTiles;
|
||||
@ -346,18 +359,26 @@ TiledLayerBufferComposite::UseTiles(const SurfaceDescriptorTiles& aTiles,
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
TiledLayerBufferComposite::ProcessDelayedUnlocks()
|
||||
{
|
||||
for (gfxSharedReadLock* lock : mDelayedUnlocks) {
|
||||
lock->ReadUnlock();
|
||||
}
|
||||
mDelayedUnlocks.Clear();
|
||||
}
|
||||
|
||||
void
|
||||
TiledLayerBufferComposite::Clear()
|
||||
{
|
||||
for (TileHost& tile : mRetainedTiles) {
|
||||
tile.ReadUnlock();
|
||||
tile.ReadUnlockPrevious();
|
||||
}
|
||||
mRetainedTiles.Clear();
|
||||
ProcessDelayedUnlocks();
|
||||
mTiles.mFirst = TileIntPoint();
|
||||
mTiles.mSize = TileIntSize();
|
||||
mValidRegion = nsIntRegion();
|
||||
mPaintedRegion = nsIntRegion();
|
||||
mResolution = 1.0;
|
||||
}
|
||||
|
||||
@ -416,6 +437,8 @@ TiledContentHost::Composite(LayerComposite* aLayer,
|
||||
aFilter, aClipRect, *renderRegion, aTransform);
|
||||
RenderLayerBuffer(mTiledBuffer, nullptr, aEffectChain, aOpacity, aFilter,
|
||||
aClipRect, *renderRegion, aTransform);
|
||||
mLowPrecisionTiledBuffer.ProcessDelayedUnlocks();
|
||||
mTiledBuffer.ProcessDelayedUnlocks();
|
||||
}
|
||||
|
||||
|
||||
@ -479,7 +502,6 @@ TiledContentHost::RenderTile(TileHost& aTile,
|
||||
}
|
||||
mCompositor->DrawDiagnostics(flags,
|
||||
aScreenRegion, aClipRect, aTransform, mFlashCounter);
|
||||
aTile.ReadUnlockPrevious();
|
||||
}
|
||||
|
||||
void
|
||||
@ -558,7 +580,7 @@ TiledContentHost::RenderLayerBuffer(TiledLayerBufferComposite& aLayerBuffer,
|
||||
|
||||
TileIntPoint tilePosition = aLayerBuffer.GetPlacement().TilePosition(i);
|
||||
// A sanity check that catches a lot of mistakes.
|
||||
MOZ_ASSERT(tilePosition.x == tile.x && tilePosition.y == tile.y);
|
||||
MOZ_ASSERT(tilePosition.x == tile.mTilePosition.x && tilePosition.y == tile.mTilePosition.y);
|
||||
|
||||
IntPoint tileOffset = aLayerBuffer.GetTileOffset(tilePosition);
|
||||
nsIntRegion tileDrawRegion = IntRect(tileOffset, aLayerBuffer.GetScaledTileSize());
|
||||
|
@ -52,8 +52,6 @@ public:
|
||||
// essentially, this is a sentinel used to represent an invalid or blank
|
||||
// tile.
|
||||
TileHost()
|
||||
: x(-1)
|
||||
, y(-1)
|
||||
{}
|
||||
|
||||
// Constructs a TileHost from a gfxSharedReadLock and TextureHost.
|
||||
@ -67,8 +65,6 @@ public:
|
||||
, mTextureHostOnWhite(aTextureHostOnWhite)
|
||||
, mTextureSource(aSource)
|
||||
, mTextureSourceOnWhite(aSourceOnWhite)
|
||||
, x(-1)
|
||||
, y(-1)
|
||||
{}
|
||||
|
||||
TileHost(const TileHost& o) {
|
||||
@ -77,9 +73,7 @@ public:
|
||||
mTextureSource = o.mTextureSource;
|
||||
mTextureSourceOnWhite = o.mTextureSourceOnWhite;
|
||||
mSharedLock = o.mSharedLock;
|
||||
mPreviousSharedLock = o.mPreviousSharedLock;
|
||||
x = o.x;
|
||||
y = o.y;
|
||||
mTilePosition = o.mTilePosition;
|
||||
}
|
||||
TileHost& operator=(const TileHost& o) {
|
||||
if (this == &o) {
|
||||
@ -90,9 +84,7 @@ public:
|
||||
mTextureSource = o.mTextureSource;
|
||||
mTextureSourceOnWhite = o.mTextureSourceOnWhite;
|
||||
mSharedLock = o.mSharedLock;
|
||||
mPreviousSharedLock = o.mPreviousSharedLock;
|
||||
x = o.x;
|
||||
y = o.y;
|
||||
mTilePosition = o.mTilePosition;
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -112,13 +104,6 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void ReadUnlockPrevious() {
|
||||
if (mPreviousSharedLock) {
|
||||
mPreviousSharedLock->ReadUnlock();
|
||||
mPreviousSharedLock = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void Dump(std::stringstream& aStream) {
|
||||
aStream << "TileHost(...)"; // fill in as needed
|
||||
}
|
||||
@ -129,14 +114,12 @@ public:
|
||||
}
|
||||
|
||||
RefPtr<gfxSharedReadLock> mSharedLock;
|
||||
RefPtr<gfxSharedReadLock> mPreviousSharedLock;
|
||||
CompositableTextureHostRef mTextureHost;
|
||||
CompositableTextureHostRef mTextureHostOnWhite;
|
||||
mutable CompositableTextureSourceRef mTextureSource;
|
||||
mutable CompositableTextureSourceRef mTextureSourceOnWhite;
|
||||
// This is not strictly necessary but makes debugging whole lot easier.
|
||||
int x;
|
||||
int y;
|
||||
TileIntPoint mTilePosition;
|
||||
};
|
||||
|
||||
class TiledLayerBufferComposite
|
||||
@ -154,6 +137,9 @@ public:
|
||||
|
||||
void Clear();
|
||||
|
||||
void MarkTilesForUnlock();
|
||||
void ProcessDelayedUnlocks();
|
||||
|
||||
TileHost GetPlaceholderTile() const { return TileHost(); }
|
||||
|
||||
// Stores the absolute resolution of the containing frame, calculated
|
||||
@ -167,7 +153,9 @@ public:
|
||||
static void RecycleCallback(TextureHost* textureHost, void* aClosure);
|
||||
|
||||
protected:
|
||||
|
||||
CSSToParentLayerScale2D mFrameResolution;
|
||||
nsTArray<RefPtr<gfxSharedReadLock>> mDelayedUnlocks;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -332,7 +332,6 @@ union TileDescriptor {
|
||||
|
||||
struct SurfaceDescriptorTiles {
|
||||
nsIntRegion validRegion;
|
||||
nsIntRegion paintedRegion;
|
||||
TileDescriptor[] tiles;
|
||||
int firstTileX;
|
||||
int firstTileY;
|
||||
|
@ -230,6 +230,7 @@ private:
|
||||
// This should be set to values in the DriverInitStatus enumeration found in
|
||||
// DriverInitCrashDetection.h.
|
||||
DECL_GFX_PREF(Live, "gfx.driver-init.status", DriverInitStatus, int32_t, 0);
|
||||
DECL_GFX_PREF(Once, "gfx.font_rendering.directwrite.enabled", DirectWriteFontRenderingEnabled, bool, false);
|
||||
DECL_GFX_PREF(Live, "gfx.gralloc.fence-with-readpixels", GrallocFenceWithReadPixels, bool, false);
|
||||
DECL_GFX_PREF(Live, "gfx.layerscope.enabled", LayerScopeEnabled, bool, false);
|
||||
DECL_GFX_PREF(Live, "gfx.layerscope.port", LayerScopePort, int32_t, 23456);
|
||||
|
504
gfx/thebes/gfxWindowsPlatform.cpp
Normal file → Executable file
504
gfx/thebes/gfxWindowsPlatform.cpp
Normal file → Executable file
@ -436,6 +436,95 @@ gfxWindowsPlatform::CanUseHardwareVideoDecoding()
|
||||
return !IsWARP() && gfxPlatform::CanUseHardwareVideoDecoding();
|
||||
}
|
||||
|
||||
void
|
||||
gfxWindowsPlatform::InitD2DSupport()
|
||||
{
|
||||
#ifdef CAIRO_HAS_D2D_SURFACE
|
||||
bool d2dBlocked = false;
|
||||
nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo();
|
||||
if (gfxInfo) {
|
||||
int32_t status;
|
||||
if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DIRECT2D, &status))) {
|
||||
if (status != nsIGfxInfo::FEATURE_STATUS_OK) {
|
||||
d2dBlocked = true;
|
||||
}
|
||||
}
|
||||
if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DIRECT3D_11_LAYERS, &status))) {
|
||||
if (status != nsIGfxInfo::FEATURE_STATUS_OK) {
|
||||
d2dBlocked = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If D2D is blocked or D3D9 is prefered, and D2D is not force-enabled, then
|
||||
// we don't attempt to use D2D.
|
||||
if ((d2dBlocked || gfxPrefs::LayersPreferD3D9()) && !gfxPrefs::Direct2DForceEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Do not ever try to use D2D if it's explicitly disabled or if we're not
|
||||
// using DWrite fonts.
|
||||
if (gfxPrefs::Direct2DDisabled() || mUsingGDIFonts) {
|
||||
return;
|
||||
}
|
||||
|
||||
ID3D11Device* device = GetD3D11Device();
|
||||
if (IsVistaOrLater() &&
|
||||
!InSafeMode() &&
|
||||
device &&
|
||||
mDoesD3D11TextureSharingWork)
|
||||
{
|
||||
VerifyD2DDevice(gfxPrefs::Direct2DForceEnabled());
|
||||
if (mD3D10Device && GetD3D11Device()) {
|
||||
mRenderMode = RENDER_DIRECT2D;
|
||||
mUseDirectWrite = true;
|
||||
}
|
||||
} else {
|
||||
mD3D10Device = nullptr;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
gfxWindowsPlatform::InitDWriteSupport()
|
||||
{
|
||||
#ifdef CAIRO_HAS_DWRITE_FONT
|
||||
// Enable when it's preffed on -and- we're using Vista or higher. Or when
|
||||
// we're going to use D2D.
|
||||
if (mDWriteFactory || (!mUseDirectWrite || !IsVistaOrLater())) {
|
||||
return;
|
||||
}
|
||||
|
||||
mozilla::ScopedGfxFeatureReporter reporter("DWrite");
|
||||
decltype(DWriteCreateFactory)* createDWriteFactory = (decltype(DWriteCreateFactory)*)
|
||||
GetProcAddress(LoadLibraryW(L"dwrite.dll"), "DWriteCreateFactory");
|
||||
|
||||
if (!createDWriteFactory) {
|
||||
return;
|
||||
}
|
||||
|
||||
// I need a direct pointer to be able to cast to IUnknown**, I also need to
|
||||
// remember to release this because the nsRefPtr will AddRef it.
|
||||
IDWriteFactory *factory;
|
||||
HRESULT hr = createDWriteFactory(
|
||||
DWRITE_FACTORY_TYPE_SHARED,
|
||||
__uuidof(IDWriteFactory),
|
||||
reinterpret_cast<IUnknown**>(&factory));
|
||||
|
||||
if (SUCCEEDED(hr) && factory) {
|
||||
mDWriteFactory = factory;
|
||||
factory->Release();
|
||||
hr = mDWriteFactory->CreateTextAnalyzer(getter_AddRefs(mDWriteAnalyzer));
|
||||
}
|
||||
|
||||
SetupClearTypeParams();
|
||||
|
||||
if (hr == S_OK) {
|
||||
reporter.SetSuccessful();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
gfxWindowsPlatform::UpdateRenderMode()
|
||||
{
|
||||
@ -461,92 +550,10 @@ gfxWindowsPlatform::UpdateRenderMode()
|
||||
}
|
||||
|
||||
mRenderMode = RENDER_GDI;
|
||||
mUseDirectWrite = gfxPrefs::DirectWriteFontRenderingEnabled();
|
||||
|
||||
bool isVistaOrHigher = IsVistaOrLater();
|
||||
|
||||
mUseDirectWrite = Preferences::GetBool("gfx.font_rendering.directwrite.enabled", false);
|
||||
|
||||
#ifdef CAIRO_HAS_D2D_SURFACE
|
||||
bool d2dDisabled = false;
|
||||
bool d2dForceEnabled = false;
|
||||
bool d2dBlocked = false;
|
||||
|
||||
nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo();
|
||||
if (gfxInfo) {
|
||||
int32_t status;
|
||||
if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DIRECT2D, &status))) {
|
||||
if (status != nsIGfxInfo::FEATURE_STATUS_OK) {
|
||||
d2dBlocked = true;
|
||||
}
|
||||
}
|
||||
if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DIRECT3D_11_LAYERS, &status))) {
|
||||
if (status != nsIGfxInfo::FEATURE_STATUS_OK) {
|
||||
d2dBlocked = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// These will only be evaluated once, and any subsequent changes to
|
||||
// the preferences will be ignored until restart.
|
||||
d2dDisabled = gfxPrefs::Direct2DDisabled();
|
||||
d2dForceEnabled = gfxPrefs::Direct2DForceEnabled();
|
||||
|
||||
bool tryD2D = d2dForceEnabled || (!d2dBlocked && !gfxPrefs::LayersPreferD3D9());
|
||||
|
||||
// Do not ever try if d2d is explicitly disabled,
|
||||
// or if we're not using DWrite fonts.
|
||||
if (d2dDisabled || mUsingGDIFonts) {
|
||||
tryD2D = false;
|
||||
}
|
||||
|
||||
ID3D11Device *device = GetD3D11Device();
|
||||
if (isVistaOrHigher && !InSafeMode() && tryD2D && device &&
|
||||
mDoesD3D11TextureSharingWork) {
|
||||
|
||||
VerifyD2DDevice(d2dForceEnabled);
|
||||
if (mD3D10Device && GetD3D11Device()) {
|
||||
mRenderMode = RENDER_DIRECT2D;
|
||||
mUseDirectWrite = true;
|
||||
}
|
||||
} else {
|
||||
mD3D10Device = nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CAIRO_HAS_DWRITE_FONT
|
||||
// Enable when it's preffed on -and- we're using Vista or higher. Or when
|
||||
// we're going to use D2D.
|
||||
if (!mDWriteFactory && (mUseDirectWrite && isVistaOrHigher)) {
|
||||
mozilla::ScopedGfxFeatureReporter reporter("DWrite");
|
||||
decltype(DWriteCreateFactory)* createDWriteFactory = (decltype(DWriteCreateFactory)*)
|
||||
GetProcAddress(LoadLibraryW(L"dwrite.dll"), "DWriteCreateFactory");
|
||||
|
||||
if (createDWriteFactory) {
|
||||
/**
|
||||
* I need a direct pointer to be able to cast to IUnknown**, I also
|
||||
* need to remember to release this because the nsRefPtr will
|
||||
* AddRef it.
|
||||
*/
|
||||
IDWriteFactory *factory;
|
||||
HRESULT hr = createDWriteFactory(
|
||||
DWRITE_FACTORY_TYPE_SHARED,
|
||||
__uuidof(IDWriteFactory),
|
||||
reinterpret_cast<IUnknown**>(&factory));
|
||||
|
||||
if (SUCCEEDED(hr) && factory) {
|
||||
mDWriteFactory = factory;
|
||||
factory->Release();
|
||||
hr = mDWriteFactory->CreateTextAnalyzer(
|
||||
getter_AddRefs(mDWriteAnalyzer));
|
||||
}
|
||||
|
||||
SetupClearTypeParams();
|
||||
|
||||
if (hr == S_OK)
|
||||
reporter.SetSuccessful();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
InitD2DSupport();
|
||||
InitDWriteSupport();
|
||||
|
||||
uint32_t canvasMask = BackendTypeBit(BackendType::CAIRO);
|
||||
uint32_t contentMask = BackendTypeBit(BackendType::CAIRO);
|
||||
@ -1890,6 +1897,163 @@ bool DoesD3D11AlphaTextureSharingWork(ID3D11Device *device)
|
||||
return DoesD3D11TextureSharingWorkInternal(device, DXGI_FORMAT_R8_UNORM, D3D11_BIND_SHADER_RESOURCE);
|
||||
}
|
||||
|
||||
auto
|
||||
gfxWindowsPlatform::CheckD3D11Support() -> D3D11Status
|
||||
{
|
||||
if (gfxPrefs::LayersD3D11ForceWARP()) {
|
||||
return D3D11Status::ForceWARP;
|
||||
}
|
||||
|
||||
if (nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo()) {
|
||||
int32_t status;
|
||||
if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DIRECT3D_11_LAYERS, &status))) {
|
||||
if (status != nsIGfxInfo::FEATURE_STATUS_OK) {
|
||||
// See if we can use WARP instead.
|
||||
//
|
||||
// It seems like nvdxgiwrap makes a mess of WARP. See bug 1154703 for more.
|
||||
if (gfxPrefs::LayersD3D11DisableWARP() || GetModuleHandleA("nvdxgiwrap.dll")) {
|
||||
return D3D11Status::Blocked;
|
||||
}
|
||||
|
||||
if (!IsWin8OrLater()) {
|
||||
// We do not use WARP on Windows 7 or earlier.
|
||||
return D3D11Status::Blocked;
|
||||
}
|
||||
|
||||
return D3D11Status::TryWARP;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Either nsIGfxInfo was bugged or we're not blacklisted.
|
||||
if (!GetDXGIAdapter()) {
|
||||
return D3D11Status::TryWARP;
|
||||
}
|
||||
return D3D11Status::Ok;
|
||||
}
|
||||
|
||||
// We don't have access to the D3D11CreateDevice type in gfxWindowsPlatform.h,
|
||||
// since it doesn't include d3d11.h, so we use a static here. It should only
|
||||
// be used within InitD3D11Devices.
|
||||
decltype(D3D11CreateDevice)* sD3D11CreateDeviceFn = nullptr;
|
||||
|
||||
bool
|
||||
gfxWindowsPlatform::AttemptD3D11DeviceCreation(const nsTArray<D3D_FEATURE_LEVEL>& aFeatureLevels)
|
||||
{
|
||||
RefPtr<IDXGIAdapter1> adapter = GetDXGIAdapter();
|
||||
MOZ_ASSERT(adapter);
|
||||
|
||||
HRESULT hr = E_INVALIDARG;
|
||||
MOZ_SEH_TRY {
|
||||
hr =
|
||||
sD3D11CreateDeviceFn(adapter, D3D_DRIVER_TYPE_UNKNOWN, nullptr,
|
||||
// Use
|
||||
// D3D11_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS
|
||||
// to prevent bug 1092260. IE 11 also uses this flag.
|
||||
D3D11_CREATE_DEVICE_BGRA_SUPPORT | D3D11_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS,
|
||||
aFeatureLevels.Elements(), aFeatureLevels.Length(),
|
||||
D3D11_SDK_VERSION, byRef(mD3D11Device), nullptr, nullptr);
|
||||
} MOZ_SEH_EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
|
||||
gfxCriticalError() << "Crash during D3D11 device creation";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (FAILED(hr) || !DoesD3D11DeviceWork(mD3D11Device)) {
|
||||
gfxCriticalError() << "D3D11 device creation failed" << hexa(hr);
|
||||
return false;
|
||||
}
|
||||
if (!mD3D11Device) {
|
||||
return false;
|
||||
}
|
||||
|
||||
CheckIfRenderTargetViewNeedsRecreating(mD3D11Device);
|
||||
|
||||
// Only test this when not using WARP since it can fail and cause
|
||||
// GetDeviceRemovedReason to return weird values.
|
||||
mDoesD3D11TextureSharingWork = ::DoesD3D11TextureSharingWork(mD3D11Device);
|
||||
mIsWARP = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
gfxWindowsPlatform::AttemptWARPDeviceCreation(const nsTArray<D3D_FEATURE_LEVEL>& aFeatureLevels)
|
||||
{
|
||||
if (gfxPrefs::LayersD3D11DisableWARP()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(!mD3D11Device);
|
||||
|
||||
ScopedGfxFeatureReporter reporterWARP("D3D11-WARP", gfxPrefs::LayersD3D11ForceWARP());
|
||||
|
||||
MOZ_SEH_TRY {
|
||||
HRESULT hr =
|
||||
sD3D11CreateDeviceFn(nullptr, D3D_DRIVER_TYPE_WARP, nullptr,
|
||||
// Use
|
||||
// D3D11_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS
|
||||
// to prevent bug 1092260. IE 11 also uses this flag.
|
||||
D3D11_CREATE_DEVICE_BGRA_SUPPORT,
|
||||
aFeatureLevels.Elements(), aFeatureLevels.Length(),
|
||||
D3D11_SDK_VERSION, byRef(mD3D11Device), nullptr, nullptr);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
// This should always succeed... in theory.
|
||||
gfxCriticalError() << "Failed to initialize WARP D3D11 device! " << hexa(hr);
|
||||
return false;
|
||||
}
|
||||
|
||||
reporterWARP.SetSuccessful();
|
||||
} MOZ_SEH_EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
|
||||
gfxCriticalError() << "Exception occurred initializing WARP D3D11 device!";
|
||||
return false;
|
||||
}
|
||||
|
||||
mIsWARP = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
gfxWindowsPlatform::AttemptD3D11ContentDeviceCreation(const nsTArray<D3D_FEATURE_LEVEL>& aFeatureLevels)
|
||||
{
|
||||
HRESULT hr = E_INVALIDARG;
|
||||
MOZ_SEH_TRY {
|
||||
hr =
|
||||
sD3D11CreateDeviceFn(mIsWARP ? nullptr : GetDXGIAdapter(),
|
||||
mIsWARP ? D3D_DRIVER_TYPE_WARP : D3D_DRIVER_TYPE_UNKNOWN,
|
||||
nullptr,
|
||||
D3D11_CREATE_DEVICE_BGRA_SUPPORT,
|
||||
aFeatureLevels.Elements(), aFeatureLevels.Length(),
|
||||
D3D11_SDK_VERSION, byRef(mD3D11ContentDevice), nullptr, nullptr);
|
||||
} MOZ_SEH_EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return SUCCEEDED(hr);
|
||||
}
|
||||
|
||||
bool
|
||||
gfxWindowsPlatform::AttemptD3D11ImageBridgeDeviceCreation(const nsTArray<D3D_FEATURE_LEVEL>& aFeatureLevels)
|
||||
{
|
||||
HRESULT hr = E_INVALIDARG;
|
||||
MOZ_SEH_TRY{
|
||||
hr =
|
||||
sD3D11CreateDeviceFn(GetDXGIAdapter(), D3D_DRIVER_TYPE_UNKNOWN, nullptr,
|
||||
D3D11_CREATE_DEVICE_BGRA_SUPPORT,
|
||||
aFeatureLevels.Elements(), aFeatureLevels.Length(),
|
||||
D3D11_SDK_VERSION, byRef(mD3D11ImageBridgeDevice), nullptr, nullptr);
|
||||
} MOZ_SEH_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (FAILED(hr)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mD3D11ImageBridgeDevice->SetExceptionMode(0);
|
||||
|
||||
return DoesD3D11AlphaTextureSharingWork(mD3D11ImageBridgeDevice);
|
||||
}
|
||||
|
||||
void
|
||||
gfxWindowsPlatform::InitD3D11Devices()
|
||||
{
|
||||
@ -1899,7 +2063,6 @@ gfxWindowsPlatform::InitD3D11Devices()
|
||||
// blacklisted, then this function will abort if WARP is disabled, causing us
|
||||
// to fallback to D3D9 or Basic layers. If WARP is not disabled it will use
|
||||
// a WARP device which should always be available on Windows 7 and higher.
|
||||
|
||||
mD3D11DeviceInitialized = true;
|
||||
mDoesD3D11TextureSharingWork = false;
|
||||
|
||||
@ -1910,49 +2073,16 @@ gfxWindowsPlatform::InitD3D11Devices()
|
||||
return;
|
||||
}
|
||||
|
||||
bool useWARP = false;
|
||||
bool allowWARP = false;
|
||||
|
||||
if (IsWin8OrLater()) {
|
||||
allowWARP = true;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo();
|
||||
if (gfxInfo) {
|
||||
int32_t status;
|
||||
if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DIRECT3D_11_LAYERS, &status))) {
|
||||
if (status != nsIGfxInfo::FEATURE_STATUS_OK) {
|
||||
|
||||
// It seems like nvdxgiwrap makes a mess of WARP. See bug 1154703 for more.
|
||||
if (gfxPrefs::LayersD3D11DisableWARP() || GetModuleHandleA("nvdxgiwrap.dll")) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!IsWin8OrLater()) {
|
||||
/* On Windows 7 WARP runs very badly on the builtin vga driver */
|
||||
nsString driver;
|
||||
gfxInfo->GetAdapterDriver(driver);
|
||||
// driver can start with vga or svga so only look for "framebuf..."
|
||||
if (driver.Find("framebuf vga256 vga64k") != kNotFound) {
|
||||
gfxCriticalError(CriticalLog::DefaultOptions(false)) << "Disabling WARP on builtin vga driver";
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
useWARP = allowWARP;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (gfxPrefs::LayersD3D11ForceWARP()) {
|
||||
useWARP = true;
|
||||
D3D11Status status = CheckD3D11Support();
|
||||
if (status == D3D11Status::Blocked) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsModuleHandle d3d11Module(LoadLibrarySystem32(L"d3d11.dll"));
|
||||
decltype(D3D11CreateDevice)* d3d11CreateDevice = (decltype(D3D11CreateDevice)*)
|
||||
GetProcAddress(d3d11Module, "D3D11CreateDevice");
|
||||
sD3D11CreateDeviceFn =
|
||||
(decltype(D3D11CreateDevice)*)GetProcAddress(d3d11Module, "D3D11CreateDevice");
|
||||
|
||||
if (!d3d11CreateDevice) {
|
||||
if (!sD3D11CreateDeviceFn) {
|
||||
// We should just be on Windows Vista or XP in this case.
|
||||
return;
|
||||
}
|
||||
@ -1966,114 +2096,36 @@ gfxWindowsPlatform::InitD3D11Devices()
|
||||
featureLevels.AppendElement(D3D_FEATURE_LEVEL_10_0);
|
||||
featureLevels.AppendElement(D3D_FEATURE_LEVEL_9_3);
|
||||
|
||||
RefPtr<IDXGIAdapter1> adapter;
|
||||
|
||||
if (!useWARP) {
|
||||
adapter = GetDXGIAdapter();
|
||||
|
||||
if (!adapter) {
|
||||
if (!gfxPrefs::LayersD3D11DisableWARP()) {
|
||||
return;
|
||||
}
|
||||
useWARP = allowWARP;
|
||||
if (status == D3D11Status::Ok) {
|
||||
if (!AttemptD3D11DeviceCreation(featureLevels)) {
|
||||
status = D3D11Status::TryWARP;
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT hr = E_INVALIDARG;
|
||||
|
||||
if (!useWARP) {
|
||||
MOZ_SEH_TRY {
|
||||
hr = d3d11CreateDevice(adapter, D3D_DRIVER_TYPE_UNKNOWN, nullptr,
|
||||
// Use
|
||||
// D3D11_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS
|
||||
// to prevent bug 1092260. IE 11 also uses this flag.
|
||||
D3D11_CREATE_DEVICE_BGRA_SUPPORT | D3D11_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS,
|
||||
featureLevels.Elements(), featureLevels.Length(),
|
||||
D3D11_SDK_VERSION, byRef(mD3D11Device), nullptr, nullptr);
|
||||
} MOZ_SEH_EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
|
||||
gfxCriticalError() << "Crash during D3D11 device creation";
|
||||
|
||||
if (gfxPrefs::LayersD3D11DisableWARP()) {
|
||||
return;
|
||||
}
|
||||
|
||||
useWARP = allowWARP;
|
||||
adapter = nullptr;
|
||||
}
|
||||
|
||||
if (FAILED(hr) || !DoesD3D11DeviceWork(mD3D11Device)) {
|
||||
gfxCriticalError() << "D3D11 device creation failed" << hexa(hr);
|
||||
if (gfxPrefs::LayersD3D11DisableWARP()) {
|
||||
return;
|
||||
}
|
||||
|
||||
useWARP = allowWARP;
|
||||
adapter = nullptr;
|
||||
}
|
||||
|
||||
if (mD3D11Device) {
|
||||
CheckIfRenderTargetViewNeedsRecreating(mD3D11Device);
|
||||
// Only test this when not using WARP since it can fail and cause GetDeviceRemovedReason to return
|
||||
// weird values.
|
||||
mDoesD3D11TextureSharingWork = ::DoesD3D11TextureSharingWork(mD3D11Device);
|
||||
}
|
||||
}
|
||||
|
||||
if (useWARP) {
|
||||
MOZ_ASSERT(!gfxPrefs::LayersD3D11DisableWARP());
|
||||
MOZ_ASSERT(!mD3D11Device);
|
||||
MOZ_ASSERT(!adapter);
|
||||
|
||||
ScopedGfxFeatureReporter reporterWARP("D3D11-WARP", gfxPrefs::LayersD3D11ForceWARP());
|
||||
|
||||
MOZ_SEH_TRY {
|
||||
hr = d3d11CreateDevice(nullptr, D3D_DRIVER_TYPE_WARP, nullptr,
|
||||
// Use
|
||||
// D3D11_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS
|
||||
// to prevent bug 1092260. IE 11 also uses this flag.
|
||||
D3D11_CREATE_DEVICE_BGRA_SUPPORT,
|
||||
featureLevels.Elements(), featureLevels.Length(),
|
||||
D3D11_SDK_VERSION, byRef(mD3D11Device), nullptr, nullptr);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
// This should always succeed... in theory.
|
||||
gfxCriticalError() << "Failed to initialize WARP D3D11 device! " << hexa(hr);
|
||||
return;
|
||||
}
|
||||
|
||||
mIsWARP = true;
|
||||
reporterWARP.SetSuccessful();
|
||||
} MOZ_SEH_EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
|
||||
gfxCriticalError() << "Exception occurred initializing WARP D3D11 device!";
|
||||
if (status == D3D11Status::TryWARP || status == D3D11Status::ForceWARP) {
|
||||
if (!AttemptWARPDeviceCreation(featureLevels)) {
|
||||
// Nothing more we can do.
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!mD3D11Device) {
|
||||
return;
|
||||
}
|
||||
|
||||
mD3D11Device->SetExceptionMode(0);
|
||||
|
||||
// We create our device for D2D content drawing here. Normally we don't use
|
||||
// D2D content drawing when using WARP. However when WARP is forced by
|
||||
// default we will let Direct2D use WARP as well.
|
||||
if (Factory::SupportsD2D1() && (!useWARP || gfxPrefs::LayersD3D11ForceWARP())) {
|
||||
MOZ_ASSERT((useWARP && !adapter) || !useWARP);
|
||||
|
||||
hr = E_INVALIDARG;
|
||||
MOZ_SEH_TRY {
|
||||
hr = d3d11CreateDevice(adapter, useWARP ? D3D_DRIVER_TYPE_WARP : D3D_DRIVER_TYPE_UNKNOWN, nullptr,
|
||||
D3D11_CREATE_DEVICE_BGRA_SUPPORT,
|
||||
featureLevels.Elements(), featureLevels.Length(),
|
||||
D3D11_SDK_VERSION, byRef(mD3D11ContentDevice), nullptr, nullptr);
|
||||
} MOZ_SEH_EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
|
||||
if (Factory::SupportsD2D1() && (!mIsWARP || (status == D3D11Status::ForceWARP))) {
|
||||
if (!AttemptD3D11ContentDeviceCreation(featureLevels)) {
|
||||
mD3D11ContentDevice = nullptr;
|
||||
}
|
||||
|
||||
if (FAILED(hr)) {
|
||||
d3d11Module.disown();
|
||||
return;
|
||||
}
|
||||
|
||||
mD3D11ContentDevice->SetExceptionMode(0);
|
||||
|
||||
nsRefPtr<ID3D10Multithread> multi;
|
||||
mD3D11ContentDevice->QueryInterface(__uuidof(ID3D10Multithread), getter_AddRefs(multi));
|
||||
multi->SetMultithreadProtected(TRUE);
|
||||
@ -2081,26 +2133,8 @@ gfxWindowsPlatform::InitD3D11Devices()
|
||||
Factory::SetDirect3D11Device(mD3D11ContentDevice);
|
||||
}
|
||||
|
||||
if (!useWARP) {
|
||||
hr = E_INVALIDARG;
|
||||
|
||||
MOZ_SEH_TRY{
|
||||
hr = d3d11CreateDevice(adapter, D3D_DRIVER_TYPE_UNKNOWN, nullptr,
|
||||
D3D11_CREATE_DEVICE_BGRA_SUPPORT,
|
||||
featureLevels.Elements(), featureLevels.Length(),
|
||||
D3D11_SDK_VERSION, byRef(mD3D11ImageBridgeDevice), nullptr, nullptr);
|
||||
} MOZ_SEH_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
|
||||
mD3D11ImageBridgeDevice = nullptr;
|
||||
}
|
||||
|
||||
if (FAILED(hr)) {
|
||||
d3d11Module.disown();
|
||||
return;
|
||||
}
|
||||
|
||||
mD3D11ImageBridgeDevice->SetExceptionMode(0);
|
||||
|
||||
if (!DoesD3D11AlphaTextureSharingWork(mD3D11ImageBridgeDevice)) {
|
||||
if (!mIsWARP) {
|
||||
if (!AttemptD3D11ImageBridgeDeviceCreation(featureLevels)) {
|
||||
mD3D11ImageBridgeDevice = nullptr;
|
||||
}
|
||||
}
|
||||
|
@ -275,7 +275,26 @@ protected:
|
||||
|
||||
private:
|
||||
void Init();
|
||||
|
||||
void InitD3D11Devices();
|
||||
|
||||
// Used by InitD3D11Devices().
|
||||
enum class D3D11Status {
|
||||
Ok,
|
||||
TryWARP,
|
||||
ForceWARP,
|
||||
Blocked
|
||||
};
|
||||
D3D11Status CheckD3D11Support();
|
||||
bool AttemptD3D11DeviceCreation(const nsTArray<D3D_FEATURE_LEVEL>& aFeatureLevels);
|
||||
bool AttemptWARPDeviceCreation(const nsTArray<D3D_FEATURE_LEVEL>& aFeatureLevels);
|
||||
bool AttemptD3D11ImageBridgeDeviceCreation(const nsTArray<D3D_FEATURE_LEVEL>& aFeatureLevels);
|
||||
bool AttemptD3D11ContentDeviceCreation(const nsTArray<D3D_FEATURE_LEVEL>& aFeatureLevels);
|
||||
|
||||
// Used by UpdateRenderMode().
|
||||
void InitD2DSupport();
|
||||
void InitDWriteSupport();
|
||||
|
||||
IDXGIAdapter1 *GetDXGIAdapter();
|
||||
bool IsDeviceReset(HRESULT hr, DeviceResetReason* aReason);
|
||||
|
||||
|
@ -867,7 +867,8 @@ MessageChannel::Send(Message* aMsg, Message* aReply)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (DispatchingSyncMessagePriority() == IPC::Message::PRIORITY_NORMAL &&
|
||||
if (mCurrentTransaction &&
|
||||
DispatchingSyncMessagePriority() == IPC::Message::PRIORITY_NORMAL &&
|
||||
msg->priority() > IPC::Message::PRIORITY_NORMAL)
|
||||
{
|
||||
// Don't allow sending CPOWs while we're dispatching a sync message.
|
||||
@ -877,22 +878,23 @@ MessageChannel::Send(Message* aMsg, Message* aReply)
|
||||
|
||||
if (mCurrentTransaction &&
|
||||
(msg->priority() < DispatchingSyncMessagePriority() ||
|
||||
mAwaitingSyncReplyPriority > msg->priority() ||
|
||||
DispatchingSyncMessagePriority() == IPC::Message::PRIORITY_URGENT ||
|
||||
DispatchingAsyncMessagePriority() == IPC::Message::PRIORITY_URGENT))
|
||||
mAwaitingSyncReplyPriority > msg->priority()))
|
||||
{
|
||||
CancelCurrentTransactionInternal();
|
||||
mLink->SendMessage(new CancelMessage());
|
||||
}
|
||||
|
||||
IPC_ASSERT(msg->is_sync(), "can only Send() sync messages here");
|
||||
IPC_ASSERT(msg->priority() >= DispatchingSyncMessagePriority(),
|
||||
"can't send sync message of a lesser priority than what's being dispatched");
|
||||
IPC_ASSERT(AwaitingSyncReplyPriority() <= msg->priority(),
|
||||
"nested sync message sends must be of increasing priority");
|
||||
|
||||
IPC_ASSERT(DispatchingSyncMessagePriority() != IPC::Message::PRIORITY_URGENT,
|
||||
"not allowed to send messages while dispatching urgent messages");
|
||||
if (mCurrentTransaction) {
|
||||
IPC_ASSERT(msg->priority() >= DispatchingSyncMessagePriority(),
|
||||
"can't send sync message of a lesser priority than what's being dispatched");
|
||||
IPC_ASSERT(AwaitingSyncReplyPriority() <= msg->priority(),
|
||||
"nested sync message sends must be of increasing priority");
|
||||
IPC_ASSERT(DispatchingSyncMessagePriority() != IPC::Message::PRIORITY_URGENT,
|
||||
"not allowed to send messages while dispatching urgent messages");
|
||||
}
|
||||
|
||||
IPC_ASSERT(DispatchingAsyncMessagePriority() != IPC::Message::PRIORITY_URGENT,
|
||||
"not allowed to send messages while dispatching urgent messages");
|
||||
|
||||
@ -1316,11 +1318,6 @@ MessageChannel::DispatchSyncMessage(const Message& aMsg, Message*& aReply)
|
||||
MOZ_ASSERT_IF(prio > IPC::Message::PRIORITY_NORMAL, NS_IsMainThread());
|
||||
MaybeScriptBlocker scriptBlocker(this, prio > IPC::Message::PRIORITY_NORMAL);
|
||||
|
||||
IPC_ASSERT(prio >= DispatchingSyncMessagePriority(),
|
||||
"priority inversion while dispatching sync message");
|
||||
IPC_ASSERT(prio >= mAwaitingSyncReplyPriority,
|
||||
"dispatching a message of lower priority while waiting for a response");
|
||||
|
||||
MessageChannel* dummy;
|
||||
MessageChannel*& blockingVar = ShouldBlockScripts() ? gParentProcessBlocker : dummy;
|
||||
|
||||
@ -2022,16 +2019,26 @@ MessageChannel::CancelCurrentTransactionInternal()
|
||||
// tampered with (by us). If so, they don't reset the variable to the old
|
||||
// value.
|
||||
|
||||
MOZ_ASSERT(!mCurrentTransaction);
|
||||
MOZ_ASSERT(mCurrentTransaction);
|
||||
mCurrentTransaction = 0;
|
||||
|
||||
mAwaitingSyncReply = false;
|
||||
mAwaitingSyncReplyPriority = 0;
|
||||
|
||||
// We could also zero out mDispatchingSyncMessage here. However, that would
|
||||
// cause a race because mDispatchingSyncMessage is a worker-thread-only
|
||||
// field and we can be called on the I/O thread. Luckily, we can check to
|
||||
// see if mCurrentTransaction is 0 before examining DispatchSyncMessage.
|
||||
}
|
||||
|
||||
void
|
||||
MessageChannel::CancelCurrentTransaction()
|
||||
{
|
||||
MonitorAutoLock lock(*mMonitor);
|
||||
CancelCurrentTransactionInternal();
|
||||
mLink->SendMessage(new CancelMessage());
|
||||
if (mCurrentTransaction) {
|
||||
CancelCurrentTransactionInternal();
|
||||
mLink->SendMessage(new CancelMessage());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -129,6 +129,11 @@ class MessageChannel : HasResultCodes
|
||||
|
||||
bool CanSend() const;
|
||||
|
||||
// Currently only for debugging purposes, doesn't aquire mMonitor.
|
||||
ChannelState GetChannelState__TotallyRacy() const {
|
||||
return mChannelState;
|
||||
}
|
||||
|
||||
void SetReplyTimeoutMs(int32_t aTimeoutMs);
|
||||
|
||||
bool IsOnCxxStack() const {
|
||||
@ -554,7 +559,7 @@ class MessageChannel : HasResultCodes
|
||||
public:
|
||||
explicit AutoEnterTransaction(MessageChannel *aChan, int32_t aMsgSeqno)
|
||||
: mChan(aChan),
|
||||
mNewTransaction(0),
|
||||
mNewTransaction(INT32_MAX),
|
||||
mOldTransaction(mChan->mCurrentTransaction)
|
||||
{
|
||||
mChan->mMonitor->AssertCurrentThreadOwns();
|
||||
|
@ -133,7 +133,7 @@ TestBridgeSubParent::Main()
|
||||
bool
|
||||
TestBridgeSubParent::RecvBridgeEm()
|
||||
{
|
||||
if (!PTestBridgeMainSub::Bridge(gBridgeMainChild, this))
|
||||
if (NS_FAILED(PTestBridgeMainSub::Bridge(gBridgeMainChild, this)))
|
||||
fail("bridging Main and Sub");
|
||||
return true;
|
||||
}
|
||||
|
@ -4135,28 +4135,48 @@ BytecodeEmitter::emitTemplateString(ParseNode* pn)
|
||||
{
|
||||
MOZ_ASSERT(pn->isArity(PN_LIST));
|
||||
|
||||
bool pushedString = false;
|
||||
|
||||
for (ParseNode* pn2 = pn->pn_head; pn2 != NULL; pn2 = pn2->pn_next) {
|
||||
if (pn2->getKind() != PNK_STRING && pn2->getKind() != PNK_TEMPLATE_STRING) {
|
||||
bool isString = (pn2->getKind() == PNK_STRING || pn2->getKind() == PNK_TEMPLATE_STRING);
|
||||
|
||||
// Skip empty strings. These are very common: a template string like
|
||||
// `${a}${b}` has three empty strings and without this optimization
|
||||
// we'd emit four JSOP_ADD operations instead of just one.
|
||||
if (isString && pn2->pn_atom->empty())
|
||||
continue;
|
||||
|
||||
if (!isString) {
|
||||
// We update source notes before emitting the expression
|
||||
if (!updateSourceCoordNotes(pn2->pn_pos.begin))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!emitTree(pn2))
|
||||
return false;
|
||||
|
||||
if (pn2->getKind() != PNK_STRING && pn2->getKind() != PNK_TEMPLATE_STRING) {
|
||||
if (!isString) {
|
||||
// We need to convert the expression to a string
|
||||
if (!emit1(JSOP_TOSTRING))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pn2 != pn->pn_head) {
|
||||
if (pushedString) {
|
||||
// We've pushed two strings onto the stack. Add them together, leaving just one.
|
||||
if (!emit1(JSOP_ADD))
|
||||
return false;
|
||||
} else {
|
||||
pushedString = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!pushedString) {
|
||||
// All strings were empty, this can happen for something like `${""}`.
|
||||
// Just push an empty string.
|
||||
if (!emitAtomOp(cx->names().empty, JSOP_STRING))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1259,9 +1259,11 @@ SavedNonVolatileRegisters(AllocatableGeneralRegisterSet unused)
|
||||
result.add(reg);
|
||||
}
|
||||
|
||||
// ARM and MIPS require an additional register to be saved, if calls can be made.
|
||||
// Some platforms require the link register to be saved, if calls can be made.
|
||||
#if defined(JS_CODEGEN_ARM)
|
||||
result.add(Register::FromCode(Registers::lr));
|
||||
#elif defined(JS_CODEGEN_ARM64)
|
||||
result.add(Register::FromCode(Registers::lr));
|
||||
#elif defined(JS_CODEGEN_MIPS)
|
||||
result.add(Register::FromCode(Registers::ra));
|
||||
#endif
|
||||
|
@ -220,7 +220,7 @@ IsObjectEscaped(MInstruction* ins, JSObject* objDefault)
|
||||
case MDefinition::Op_GuardShape: {
|
||||
MGuardShape* guard = def->toGuardShape();
|
||||
MOZ_ASSERT(!ins->isGuardShape());
|
||||
if (obj->as<NativeObject>().lastProperty() != guard->shape()) {
|
||||
if (obj->maybeShape() != guard->shape()) {
|
||||
JitSpewDef(JitSpew_Escape, "has a non-matching guard shape\n", guard);
|
||||
return true;
|
||||
}
|
||||
|
@ -1029,8 +1029,9 @@ xpc::CreateSandboxObject(JSContext* cx, MutableHandleValue vp, nsISupports* prin
|
||||
if (!sandbox)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
CompartmentPrivate::Get(sandbox)->writeToGlobalPrototype =
|
||||
options.writeToGlobalPrototype;
|
||||
CompartmentPrivate* priv = CompartmentPrivate::Get(sandbox);
|
||||
priv->allowWaivers = options.allowWaivers;
|
||||
priv->writeToGlobalPrototype = options.writeToGlobalPrototype;
|
||||
|
||||
// Set up the wantXrays flag, which indicates whether xrays are desired even
|
||||
// for same-origin access.
|
||||
@ -1041,7 +1042,7 @@ xpc::CreateSandboxObject(JSContext* cx, MutableHandleValue vp, nsISupports* prin
|
||||
// Arguably we should just flip the default for chrome and still honor the
|
||||
// flag, but such a change would break code in subtle ways for minimal
|
||||
// benefit. So we just switch it off here.
|
||||
CompartmentPrivate::Get(sandbox)->wantXrays =
|
||||
priv->wantXrays =
|
||||
AccessCheck::isChrome(sandbox) ? false : options.wantXrays;
|
||||
|
||||
{
|
||||
@ -1480,6 +1481,7 @@ SandboxOptions::Parse()
|
||||
{
|
||||
bool ok = ParseObject("sandboxPrototype", &proto) &&
|
||||
ParseBoolean("wantXrays", &wantXrays) &&
|
||||
ParseBoolean("allowWaivers", &allowWaivers) &&
|
||||
ParseBoolean("wantComponents", &wantComponents) &&
|
||||
ParseBoolean("wantExportHelpers", &wantExportHelpers) &&
|
||||
ParseString("sandboxName", sandboxName) &&
|
||||
|
@ -1297,7 +1297,7 @@ class MOZ_STACK_CLASS CallMethodHelper
|
||||
const uint32_t mArgc;
|
||||
|
||||
MOZ_ALWAYS_INLINE bool
|
||||
GetArraySizeFromParam(uint8_t paramIndex, uint32_t* result) const;
|
||||
GetArraySizeFromParam(uint8_t paramIndex, HandleValue maybeArray, uint32_t* result);
|
||||
|
||||
MOZ_ALWAYS_INLINE bool
|
||||
GetInterfaceTypeFromParam(uint8_t paramIndex,
|
||||
@ -1446,7 +1446,7 @@ CallMethodHelper::~CallMethodHelper()
|
||||
// We need some basic information to properly destroy the array.
|
||||
uint32_t array_count = 0;
|
||||
nsXPTType datum_type;
|
||||
if (!GetArraySizeFromParam(i, &array_count) ||
|
||||
if (!GetArraySizeFromParam(i, UndefinedHandleValue, &array_count) ||
|
||||
!NS_SUCCEEDED(mIFaceInfo->GetTypeForParam(mVTableIndex,
|
||||
¶mInfo,
|
||||
1, &datum_type))) {
|
||||
@ -1480,7 +1480,8 @@ CallMethodHelper::~CallMethodHelper()
|
||||
|
||||
bool
|
||||
CallMethodHelper::GetArraySizeFromParam(uint8_t paramIndex,
|
||||
uint32_t* result) const
|
||||
HandleValue maybeArray,
|
||||
uint32_t* result)
|
||||
{
|
||||
nsresult rv;
|
||||
const nsXPTParamInfo& paramInfo = mMethodInfo->GetParam(paramIndex);
|
||||
@ -1491,6 +1492,22 @@ CallMethodHelper::GetArraySizeFromParam(uint8_t paramIndex,
|
||||
if (NS_FAILED(rv))
|
||||
return Throw(NS_ERROR_XPC_CANT_GET_ARRAY_INFO, mCallContext);
|
||||
|
||||
// If the array length wasn't passed, it might have been listed as optional.
|
||||
// When converting arguments from JS to C++, we pass the array as |maybeArray|,
|
||||
// and give ourselves the chance to infer the length. Once we have it, we stick
|
||||
// it in the right slot so that we can find it again when cleaning up the params.
|
||||
// from the array.
|
||||
if (paramIndex >= mArgc && maybeArray.isObject()) {
|
||||
MOZ_ASSERT(mMethodInfo->GetParam(paramIndex).IsOptional());
|
||||
RootedObject arrayOrNull(mCallContext, maybeArray.isObject() ? &maybeArray.toObject()
|
||||
: nullptr);
|
||||
if (!JS_IsArrayObject(mCallContext, maybeArray) ||
|
||||
!JS_GetArrayLength(mCallContext, arrayOrNull, &GetDispatchParam(paramIndex)->val.u32))
|
||||
{
|
||||
return Throw(NS_ERROR_XPC_CANT_CONVERT_OBJECT_TO_ARRAY, mCallContext);
|
||||
}
|
||||
}
|
||||
|
||||
*result = GetDispatchParam(paramIndex)->val.u32;
|
||||
|
||||
return true;
|
||||
@ -1586,7 +1603,7 @@ CallMethodHelper::GatherAndConvertResults()
|
||||
datum_type = type;
|
||||
|
||||
if (isArray || isSizedString) {
|
||||
if (!GetArraySizeFromParam(i, &array_count))
|
||||
if (!GetArraySizeFromParam(i, UndefinedHandleValue, &array_count))
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1968,7 +1985,7 @@ CallMethodHelper::ConvertDependentParam(uint8_t i)
|
||||
nsresult err;
|
||||
|
||||
if (isArray || isSizedString) {
|
||||
if (!GetArraySizeFromParam(i, &array_count))
|
||||
if (!GetArraySizeFromParam(i, src, &array_count))
|
||||
return false;
|
||||
|
||||
if (isArray) {
|
||||
|
@ -32,16 +32,14 @@ UnwrapNW(JSContext* cx, unsigned argc, jsval* vp)
|
||||
}
|
||||
|
||||
JS::RootedValue v(cx, args[0]);
|
||||
if (!v.isObject() || !js::IsWrapper(&v.toObject())) {
|
||||
if (!v.isObject() || !js::IsCrossCompartmentWrapper(&v.toObject()) ||
|
||||
!WrapperFactory::AllowWaiver(&v.toObject())) {
|
||||
args.rval().set(v);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (AccessCheck::wrapperSubsumes(&v.toObject())) {
|
||||
bool ok = xpc::WrapperFactory::WaiveXrayAndWrap(cx, &v);
|
||||
NS_ENSURE_TRUE(ok, false);
|
||||
}
|
||||
|
||||
bool ok = xpc::WrapperFactory::WaiveXrayAndWrap(cx, &v);
|
||||
NS_ENSURE_TRUE(ok, false);
|
||||
args.rval().set(v);
|
||||
return true;
|
||||
}
|
||||
|
@ -3043,7 +3043,7 @@ public:
|
||||
uint32_t flags,
|
||||
const char* category) override;
|
||||
|
||||
NS_IMETHOD GetStack(JS::MutableHandleValue);
|
||||
NS_IMETHOD GetStack(JS::MutableHandleValue) override;
|
||||
|
||||
private:
|
||||
virtual ~nsScriptErrorWithStack();
|
||||
@ -3472,6 +3472,7 @@ public:
|
||||
JSObject* options = nullptr)
|
||||
: OptionsBase(cx, options)
|
||||
, wantXrays(true)
|
||||
, allowWaivers(true)
|
||||
, wantComponents(true)
|
||||
, wantExportHelpers(false)
|
||||
, proto(cx)
|
||||
@ -3487,6 +3488,7 @@ public:
|
||||
virtual bool Parse();
|
||||
|
||||
bool wantXrays;
|
||||
bool allowWaivers;
|
||||
bool wantComponents;
|
||||
bool wantExportHelpers;
|
||||
JS::RootedObject proto;
|
||||
@ -3683,6 +3685,7 @@ public:
|
||||
|
||||
explicit CompartmentPrivate(JSCompartment* c)
|
||||
: wantXrays(false)
|
||||
, allowWaivers(true)
|
||||
, writeToGlobalPrototype(false)
|
||||
, skipWriteToGlobalPrototype(false)
|
||||
, universalXPConnectEnabled(false)
|
||||
@ -3710,9 +3713,17 @@ public:
|
||||
return Get(compartment);
|
||||
}
|
||||
|
||||
|
||||
// Controls whether this compartment gets Xrays to same-origin. This behavior
|
||||
// is deprecated, but is still the default for sandboxes for compatibity
|
||||
// reasons.
|
||||
bool wantXrays;
|
||||
|
||||
// Controls whether this compartment is allowed to waive Xrays to content
|
||||
// that it subsumes. This should generally be true, except in cases where we
|
||||
// want to prevent code from depending on Xray Waivers (which might make it
|
||||
// more portable to other browser architectures).
|
||||
bool allowWaivers;
|
||||
|
||||
// This flag is intended for a very specific use, internal to Gecko. It may
|
||||
// go away or change behavior at any time. It should not be added to any
|
||||
// documentation and it should not be used without consulting the XPConnect
|
||||
|
@ -73,7 +73,13 @@ TestParams.prototype = {
|
||||
testSizedWstring: f_is,
|
||||
testInterfaceIs: f_is,
|
||||
testInterfaceIsArray: f_size_and_iid,
|
||||
testOutAString: function(o) { o.value = "out"; }
|
||||
testOutAString: function(o) { o.value = "out"; },
|
||||
testStringArrayOptionalSize: function(arr, size) {
|
||||
if (arr.length != size) { throw "bad size passed to test method"; }
|
||||
var rv = "";
|
||||
arr.forEach((x) => rv += x);
|
||||
return rv;
|
||||
}
|
||||
};
|
||||
|
||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([TestParams]);
|
||||
|
@ -346,3 +346,16 @@ NS_IMETHODIMP nsXPCTestParams::TestOutAString(nsAString & o)
|
||||
o.AssignLiteral("out");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* ACString testStringArrayOptionalSize([array, size_is(aLength)] in string a, [optional] in unsigned long aLength);
|
||||
*/
|
||||
NS_IMETHODIMP nsXPCTestParams::TestStringArrayOptionalSize(const char * *a, uint32_t length, nsACString& out)
|
||||
{
|
||||
out.Truncate();
|
||||
for (uint32_t i = 0; i < length; ++i) {
|
||||
out.Append(a[i]);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -15,7 +15,7 @@
|
||||
interface nsIXPCTestInterfaceA;
|
||||
interface nsIXPCTestInterfaceB;
|
||||
|
||||
[scriptable, uuid(fe2b7433-ac3b-49ef-9344-b67228bfdd46)]
|
||||
[scriptable, uuid(812145c7-9fcc-425e-a878-36ad1b7730b7)]
|
||||
interface nsIXPCTestParams : nsISupports {
|
||||
|
||||
// These types correspond to the ones in typelib.py
|
||||
@ -84,4 +84,7 @@ interface nsIXPCTestParams : nsISupports {
|
||||
|
||||
// Test for out dipper parameters
|
||||
void testOutAString(out AString o);
|
||||
|
||||
// Test for optional array size_is.
|
||||
ACString testStringArrayOptionalSize([array, size_is(aLength)] in string a, [optional] in unsigned long aLength);
|
||||
};
|
||||
|
30
js/xpconnect/tests/unit/test_allowWaivers.js
Normal file
30
js/xpconnect/tests/unit/test_allowWaivers.js
Normal file
@ -0,0 +1,30 @@
|
||||
const Cu = Components.utils;
|
||||
function checkWaivers(from, allowed) {
|
||||
var sb = new Cu.Sandbox('http://example.com');
|
||||
from.test = sb.eval('var o = {prop: 2, f: function() {return 42;}}; o');
|
||||
|
||||
// Make sure that |from| has Xrays to sb.
|
||||
do_check_eq(from.eval('test.prop'), 2);
|
||||
do_check_eq(from.eval('test.f'), undefined);
|
||||
|
||||
// Make sure that waivability works as expected.
|
||||
do_check_eq(from.eval('!!test.wrappedJSObject'), allowed);
|
||||
do_check_eq(from.eval('XPCNativeWrapper.unwrap(test) !== test'), allowed);
|
||||
|
||||
// Make a sandbox with the same principal as |from|, but without any waiver
|
||||
// restrictions, and make sure that the waiver does not transfer.
|
||||
var friend = new Cu.Sandbox(Cu.getObjectPrincipal(from));
|
||||
friend.test = from.test;
|
||||
friend.eval('var waived = test.wrappedJSObject;');
|
||||
do_check_true(friend.eval('waived.f()'), 42);
|
||||
friend.from = from;
|
||||
friend.eval('from.waived = waived');
|
||||
do_check_eq(from.eval('!!waived.f'), allowed);
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
checkWaivers(new Cu.Sandbox('http://example.com'), true);
|
||||
checkWaivers(new Cu.Sandbox('http://example.com', {allowWaivers: false}), false);
|
||||
checkWaivers(new Cu.Sandbox(['http://example.com']), true);
|
||||
checkWaivers(new Cu.Sandbox(['http://example.com'], {allowWaivers: false}), false);
|
||||
}
|
@ -188,6 +188,9 @@ function test_component(contractid) {
|
||||
doIs2Test("testInterfaceIsArray", [makeA(), makeA(), makeA(), makeA(), makeA()], 5, Ci['nsIXPCTestInterfaceA'],
|
||||
[makeB(), makeB(), makeB()], 3, Ci['nsIXPCTestInterfaceB']);
|
||||
|
||||
// Test optional array size.
|
||||
do_check_eq(o.testStringArrayOptionalSize(["some", "string", "array"]), "somestringarray");
|
||||
|
||||
// Test incorrect (too big) array size parameter; this should throw NOT_ENOUGH_ELEMENTS.
|
||||
doTypedArrayMismatchTest("testShortArray", new Int16Array([-3, 7, 4]), 4,
|
||||
new Int16Array([1, -32, 6]), 3);
|
||||
|
@ -18,6 +18,7 @@ support-files =
|
||||
recursive_importB.jsm
|
||||
syntax_error.jsm
|
||||
|
||||
[test_allowWaivers.js]
|
||||
[test_bogus_files.js]
|
||||
[test_bug408412.js]
|
||||
[test_bug451678.js]
|
||||
|
@ -106,6 +106,20 @@ WrapperFactory::WaiveXray(JSContext* cx, JSObject* objArg)
|
||||
return CreateXrayWaiver(cx, obj);
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
WrapperFactory::AllowWaiver(JSCompartment* target, JSCompartment* origin)
|
||||
{
|
||||
return CompartmentPrivate::Get(target)->allowWaivers &&
|
||||
AccessCheck::subsumes(target, origin);
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
WrapperFactory::AllowWaiver(JSObject* wrapper) {
|
||||
MOZ_ASSERT(js::IsCrossCompartmentWrapper(wrapper));
|
||||
return AllowWaiver(js::GetObjectCompartment(wrapper),
|
||||
js::GetObjectCompartment(js::UncheckedUnwrap(wrapper)));
|
||||
}
|
||||
|
||||
inline bool
|
||||
ShouldWaiveXray(JSContext* cx, JSObject* originalObj)
|
||||
{
|
||||
@ -468,8 +482,10 @@ WrapperFactory::Rewrap(JSContext* cx, HandleObject existing, HandleObject obj)
|
||||
bool wantXrays = !sameOrigin || sameOriginXrays;
|
||||
|
||||
// If Xrays are warranted, the caller may waive them for non-security
|
||||
// wrappers.
|
||||
bool waiveXrays = wantXrays && !securityWrapper && HasWaiveXrayFlag(obj);
|
||||
// wrappers (unless explicitly forbidden from doing so).
|
||||
bool waiveXrays = wantXrays && !securityWrapper &&
|
||||
CompartmentPrivate::Get(target)->allowWaivers &&
|
||||
HasWaiveXrayFlag(obj);
|
||||
|
||||
// We have slightly different behavior for the case when the object
|
||||
// being wrapped is in an XBL scope.
|
||||
@ -542,7 +558,7 @@ WrapperFactory::WaiveXrayAndWrap(JSContext* cx, MutableHandleObject argObj)
|
||||
// to things in |obj|'s compartment.
|
||||
JSCompartment* target = js::GetContextCompartment(cx);
|
||||
JSCompartment* origin = js::GetObjectCompartment(obj);
|
||||
obj = AccessCheck::subsumes(target, origin) ? WaiveXray(cx, obj) : obj;
|
||||
obj = AllowWaiver(target, origin) ? WaiveXray(cx, obj) : obj;
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
|
@ -37,6 +37,13 @@ class WrapperFactory {
|
||||
static JSObject* CreateXrayWaiver(JSContext* cx, JS::HandleObject obj);
|
||||
static JSObject* WaiveXray(JSContext* cx, JSObject* obj);
|
||||
|
||||
// Computes whether we should allow the creation of an Xray waiver from
|
||||
// |target| to |origin|.
|
||||
static bool AllowWaiver(JSCompartment* target, JSCompartment* origin);
|
||||
|
||||
// Convenience method for the above, operating on a wrapper.
|
||||
static bool AllowWaiver(JSObject* wrapper);
|
||||
|
||||
// Prepare a given object for wrapping in a new compartment.
|
||||
static JSObject* PrepareForWrapping(JSContext* cx,
|
||||
JS::HandleObject scope,
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user