Merge m-c to fx-team. a=merge

This commit is contained in:
Ryan VanderMeulen 2015-07-16 16:23:27 -04:00
commit a276714066
217 changed files with 2889 additions and 2356 deletions

View File

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

View File

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

View File

@ -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"/>

View File

@ -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"/>

View File

@ -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"/>

View File

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

View File

@ -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"/>

View File

@ -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"/>

View File

@ -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"/>

View File

@ -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"/>

View File

@ -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"
}

View File

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

View File

@ -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"/>

View File

@ -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);

View File

@ -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() {

View File

@ -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);

View File

@ -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;
}

View File

@ -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);
}

View File

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

View File

@ -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);
}

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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).

View File

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

View File

@ -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);

View File

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

View File

@ -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));

View File

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

View File

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

View File

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

View File

@ -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();
});
}

View File

@ -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);
}

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

View File

@ -22,3 +22,4 @@ load 896047-2.html
load 916128-1.html
load 934939-1.html
load 1099143-1.html
load 1183363.html

View File

@ -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"));

View File

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

View File

@ -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()) {

View File

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

View File

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

View File

@ -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) {

View File

@ -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;
}

View File

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

View File

@ -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;
}

View File

@ -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;
};

View File

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

View File

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

View File

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

View File

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

View File

@ -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);

View File

@ -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());
}

View File

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

View File

@ -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)
{

View File

@ -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();

View File

@ -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) {

View File

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

View File

@ -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');

View File

@ -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) {

View File

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

View File

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

View File

@ -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());

View File

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

View File

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

View File

@ -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);
}

View File

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

View File

@ -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;
}

View File

@ -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;
}

View File

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

View File

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

View File

@ -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()
{

View File

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

View File

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

View File

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

View File

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

View File

@ -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.
*/

View File

@ -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();

View File

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

View File

@ -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());

View File

@ -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;
};
/**

View File

@ -332,7 +332,6 @@ union TileDescriptor {
struct SurfaceDescriptorTiles {
nsIntRegion validRegion;
nsIntRegion paintedRegion;
TileDescriptor[] tiles;
int firstTileX;
int firstTileY;

View File

@ -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
View 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;
}
}

View File

@ -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);

View File

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

View File

@ -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();

View File

@ -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;
}

View File

@ -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;
}

View File

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

View File

@ -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;
}

View File

@ -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) &&

View File

@ -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,
&paramInfo,
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) {

View File

@ -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;
}

View File

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

View File

@ -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]);

View File

@ -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;
}

View File

@ -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);
};

View 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);
}

View File

@ -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);

View File

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

View File

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

View File

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