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

This commit is contained in:
Wes Kocher 2015-06-02 18:44:31 -07:00
commit f9926c89e5
273 changed files with 3930 additions and 2531 deletions

View File

@ -63,6 +63,18 @@ function ConsoleMessage(aMsg, aLevel) {
}
}
function toggleUnrestrictedDevtools(unrestricted) {
Services.prefs.setBoolPref("devtools.debugger.forbid-certified-apps",
!unrestricted);
Services.prefs.setBoolPref("dom.apps.developer_mode", unrestricted);
// TODO: Remove once bug 1125916 is fixed.
Services.prefs.setBoolPref("network.disable.ipc.security", unrestricted);
Services.prefs.setBoolPref("dom.webcomponents.enabled", unrestricted);
let lock = settings.createLock();
lock.set("developer.menu.enabled", unrestricted, null);
lock.set("devtools.unrestricted", unrestricted, null);
}
ConsoleMessage.prototype = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIConsoleMessage]),
toString: function() { return this.msg; }
@ -99,17 +111,17 @@ ProcessGlobal.prototype = {
lines.forEach((line) => {
log(line);
let params = line.split(" ");
if (params[0] == "wipe") {
this.wipeDir(params[1]);
} else if (params[0] == "root") {
log("unrestrict devtools");
Services.prefs.setBoolPref("devtools.debugger.forbid-certified-apps", false);
Services.prefs.setBoolPref("dom.apps.developer_mode", true);
// TODO: Remove once bug 1125916 is fixed.
Services.prefs.setBoolPref("network.disable.ipc.security", true);
Services.prefs.setBoolPref("dom.webcomponents.enabled", true);
let lock = settings.createLock();
lock.set("developer.menu.enabled", true, null);
switch (params[0]) {
case "root":
log("unrestrict devtools");
toggleUnrestrictedDevtools(true);
break;
case "wipe":
this.wipeDir(params[1]);
case "normal":
log("restrict devtools");
toggleUnrestrictedDevtools(false);
break;
}
});
},

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="6d477a7884273886605049b20f60af5c1583a150"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="9b7ed13e0dee26b9f16ae5fbc076fa8bd588b256"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="fffc68521ebb1501d6b015c6d1c4a17a04fdb2e2"/>
<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="4a697ec692aa762eb8cdb7812f5a051c5870020f"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="15a220c3e411f9606e4059e4c9fd0c57a4290c13"/>
<!-- 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

@ -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="6d477a7884273886605049b20f60af5c1583a150"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="9b7ed13e0dee26b9f16ae5fbc076fa8bd588b256"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="fffc68521ebb1501d6b015c6d1c4a17a04fdb2e2"/>
<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="4a697ec692aa762eb8cdb7812f5a051c5870020f"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="15a220c3e411f9606e4059e4c9fd0c57a4290c13"/>
<!-- 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,11 +19,11 @@
<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="6d477a7884273886605049b20f60af5c1583a150"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="9b7ed13e0dee26b9f16ae5fbc076fa8bd588b256"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="fffc68521ebb1501d6b015c6d1c4a17a04fdb2e2"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="22664edc4c73e5fe8f5095ff1d5549db78a2bc10"/>
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="218a5637399d023f4326e12c8a486dad95403b6c"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="aac9cc4bb94cf720baf8f7ee419b4d76ac86b1ac"/>
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="10b3daf0093db94c64e78a72ac43a93b68976087"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="46da1a05ac04157669685246d70ac59d48699c9e"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="34ea6163f9f0e0122fb0bb03607eccdca31ced7a"/>
<!-- Stock Android things -->

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="6d477a7884273886605049b20f60af5c1583a150"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="9b7ed13e0dee26b9f16ae5fbc076fa8bd588b256"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="fffc68521ebb1501d6b015c6d1c4a17a04fdb2e2"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="46da1a05ac04157669685246d70ac59d48699c9e"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="4a697ec692aa762eb8cdb7812f5a051c5870020f"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="15a220c3e411f9606e4059e4c9fd0c57a4290c13"/>
<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="6d477a7884273886605049b20f60af5c1583a150"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="9b7ed13e0dee26b9f16ae5fbc076fa8bd588b256"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="fffc68521ebb1501d6b015c6d1c4a17a04fdb2e2"/>
<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="4a697ec692aa762eb8cdb7812f5a051c5870020f"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="15a220c3e411f9606e4059e4c9fd0c57a4290c13"/>
<!-- 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"/>
@ -129,10 +129,10 @@
<!-- Emulator specific things -->
<project name="device/generic/armv7-a-neon" path="device/generic/armv7-a-neon" revision="72ffdf71c68a96309212eb13d63560d66db14c9e"/>
<project name="device_generic_goldfish" path="device/generic/goldfish" remote="b2g" revision="f390788a00706c06e5248edfd8d27b365387e84a"/>
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="d2f58dbee70cba71bd3fad8cdd0fee620d10cf92"/>
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="c4d9746e5f1a3a2e6cb53d59d5d721e9888cd2e1"/>
<project name="platform/external/libnfc-nci" path="external/libnfc-nci" revision="f37bd545063039e30a92f2550ae78c0e6e4e2d08"/>
<project name="platform_external_wpa_supplicant_8" path="external/wpa_supplicant_8" remote="b2g" revision="0c6a6547cd1fd302fa2b0f6e375654df36bf0ec4"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="42f61f665e7a9857da8cd14b455e15bae98e6b44"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="de4bfffbbc2aabe5b5eca485e459da75e49097e2"/>
<project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="d82e00fb6380b4f6cea7a96213913ee9eb441239"/>
<project name="platform/development" path="development" revision="5968ff4e13e0d696ad8d972281fc27ae5a12829b"/>
<project name="android-sdk" path="sdk" remote="b2g" revision="0951179277915335251c5e11d242e4e1a8c2236f"/>

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="6d477a7884273886605049b20f60af5c1583a150"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="9b7ed13e0dee26b9f16ae5fbc076fa8bd588b256"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="fffc68521ebb1501d6b015c6d1c4a17a04fdb2e2"/>
<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="4a697ec692aa762eb8cdb7812f5a051c5870020f"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="15a220c3e411f9606e4059e4c9fd0c57a4290c13"/>
<!-- 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,11 +19,11 @@
<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="6d477a7884273886605049b20f60af5c1583a150"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="9b7ed13e0dee26b9f16ae5fbc076fa8bd588b256"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="fffc68521ebb1501d6b015c6d1c4a17a04fdb2e2"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="22664edc4c73e5fe8f5095ff1d5549db78a2bc10"/>
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="218a5637399d023f4326e12c8a486dad95403b6c"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="aac9cc4bb94cf720baf8f7ee419b4d76ac86b1ac"/>
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="10b3daf0093db94c64e78a72ac43a93b68976087"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="46da1a05ac04157669685246d70ac59d48699c9e"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="34ea6163f9f0e0122fb0bb03607eccdca31ced7a"/>
<!-- 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="6d477a7884273886605049b20f60af5c1583a150"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="9b7ed13e0dee26b9f16ae5fbc076fa8bd588b256"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="fffc68521ebb1501d6b015c6d1c4a17a04fdb2e2"/>
<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="4a697ec692aa762eb8cdb7812f5a051c5870020f"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="15a220c3e411f9606e4059e4c9fd0c57a4290c13"/>
<!-- 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": "6d477a7884273886605049b20f60af5c1583a150",
"git_revision": "9b7ed13e0dee26b9f16ae5fbc076fa8bd588b256",
"remote": "https://git.mozilla.org/releases/gaia.git",
"branch": ""
},
"revision": "c7beef2b034d2308a85e8c866395c78245bc554f",
"revision": "d5e509fd9697316bcbc267413a30478dcd4dbca9",
"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="6d477a7884273886605049b20f60af5c1583a150"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="9b7ed13e0dee26b9f16ae5fbc076fa8bd588b256"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="fffc68521ebb1501d6b015c6d1c4a17a04fdb2e2"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="46da1a05ac04157669685246d70ac59d48699c9e"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="4a697ec692aa762eb8cdb7812f5a051c5870020f"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="15a220c3e411f9606e4059e4c9fd0c57a4290c13"/>
<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="6d477a7884273886605049b20f60af5c1583a150"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="9b7ed13e0dee26b9f16ae5fbc076fa8bd588b256"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="fffc68521ebb1501d6b015c6d1c4a17a04fdb2e2"/>
<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="4a697ec692aa762eb8cdb7812f5a051c5870020f"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="15a220c3e411f9606e4059e4c9fd0c57a4290c13"/>
<!-- 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

@ -76,14 +76,14 @@ BasePrincipal::GetOriginNoSuffix(nsACString& aOrigin)
bool
BasePrincipal::Subsumes(nsIPrincipal* aOther, DocumentDomainConsideration aConsideration)
{
MOZ_RELEASE_ASSERT(aOther, "The caller is performing a nonsensical security check!");
MOZ_ASSERT(aOther);
return SubsumesInternal(aOther, aConsideration);
}
NS_IMETHODIMP
BasePrincipal::Equals(nsIPrincipal *aOther, bool *aResult)
{
NS_ENSURE_TRUE(aOther, NS_ERROR_INVALID_ARG);
*aResult = Subsumes(aOther, DontConsiderDocumentDomain) &&
Cast(aOther)->Subsumes(this, DontConsiderDocumentDomain);
return NS_OK;
@ -92,6 +92,7 @@ BasePrincipal::Equals(nsIPrincipal *aOther, bool *aResult)
NS_IMETHODIMP
BasePrincipal::EqualsConsideringDomain(nsIPrincipal *aOther, bool *aResult)
{
NS_ENSURE_TRUE(aOther, NS_ERROR_INVALID_ARG);
*aResult = Subsumes(aOther, ConsiderDocumentDomain) &&
Cast(aOther)->Subsumes(this, ConsiderDocumentDomain);
return NS_OK;
@ -100,6 +101,7 @@ BasePrincipal::EqualsConsideringDomain(nsIPrincipal *aOther, bool *aResult)
NS_IMETHODIMP
BasePrincipal::Subsumes(nsIPrincipal *aOther, bool *aResult)
{
NS_ENSURE_TRUE(aOther, NS_ERROR_INVALID_ARG);
*aResult = Subsumes(aOther, DontConsiderDocumentDomain);
return NS_OK;
}
@ -107,6 +109,7 @@ BasePrincipal::Subsumes(nsIPrincipal *aOther, bool *aResult)
NS_IMETHODIMP
BasePrincipal::SubsumesConsideringDomain(nsIPrincipal *aOther, bool *aResult)
{
NS_ENSURE_TRUE(aOther, NS_ERROR_INVALID_ARG);
*aResult = Subsumes(aOther, ConsiderDocumentDomain);
return NS_OK;
}

View File

@ -175,9 +175,6 @@ function runTest() {
runApp(app, continueTest);
yield undefined;
SpecialPowers.popPermissions(continueTest);
yield undefined;
// Uninstall the app to cleanup after ourself.
navigator.mozApps.mgmt.onuninstall = function(event) {
var app = event.application;

View File

@ -36,6 +36,10 @@
#include "nsIWebNavigation.h"
#include "nsIXPConnect.h"
#ifdef MOZ_ENABLE_PROFILER_SPS
#include "nsIProfiler.h"
#endif
// The maximum allowed number of concurrent timers per page.
#define MAX_PAGE_TIMERS 10000
@ -860,6 +864,23 @@ Console::TimeStamp(JSContext* aCx, const JS::Handle<JS::Value> aData)
return;
}
#ifdef MOZ_ENABLE_PROFILER_SPS
if (aData.isString() && NS_IsMainThread()) {
if (!mProfiler) {
mProfiler = do_GetService("@mozilla.org/tools/profiler;1");
}
if (mProfiler) {
bool active = false;
if (NS_SUCCEEDED(mProfiler->IsActive(&active)) && active) {
nsAutoJSString stringValue;
if (stringValue.init(aCx, aData)) {
mProfiler->AddMarker(NS_ConvertUTF16toUTF8(stringValue).get());
}
}
}
}
#endif
Method(aCx, MethodTimeStamp, NS_LITERAL_STRING("timeStamp"), data);
}

View File

@ -18,6 +18,7 @@
#include "nsPIDOMWindow.h"
class nsIConsoleAPIStorage;
class nsIProfiler;
class nsIXPConnectJSObjectHolder;
namespace mozilla {
@ -203,6 +204,9 @@ private:
nsCOMPtr<nsPIDOMWindow> mWindow;
nsCOMPtr<nsIConsoleAPIStorage> mStorage;
nsCOMPtr<nsIXPConnectJSObjectHolder> mSandbox;
#ifdef MOZ_ENABLE_PROFILER_SPS
nsCOMPtr<nsIProfiler> mProfiler;
#endif
nsDataHashtable<nsStringHashKey, DOMHighResTimeStamp> mTimerRegistry;
nsDataHashtable<nsStringHashKey, uint32_t> mCounterRegistry;

View File

@ -113,6 +113,7 @@ NS_CP_ContentTypeName(uint32_t contentType)
CASE_RETURN( TYPE_BEACON );
CASE_RETURN( TYPE_FETCH );
CASE_RETURN( TYPE_IMAGESET );
CASE_RETURN( TYPE_WEB_MANIFEST );
default:
return "<Unknown Type>";
}

View File

@ -1660,7 +1660,7 @@ nsContentUtils::ParseLegacyFontSize(const nsAString& aValue)
++iter;
}
if (*iter < char16_t('0') || *iter > char16_t('9')) {
if (iter == end || *iter < char16_t('0') || *iter > char16_t('9')) {
return 0;
}

View File

@ -123,7 +123,8 @@ nsDataDocumentContentPolicy::ShouldLoad(uint32_t aContentType,
aContentType == nsIContentPolicy::TYPE_SUBDOCUMENT ||
aContentType == nsIContentPolicy::TYPE_SCRIPT ||
aContentType == nsIContentPolicy::TYPE_XSLT ||
aContentType == nsIContentPolicy::TYPE_FETCH) {
aContentType == nsIContentPolicy::TYPE_FETCH ||
aContentType == nsIContentPolicy::TYPE_WEB_MANIFEST) {
*aDecision = nsIContentPolicy::REJECT_TYPE;
}

View File

@ -20,7 +20,7 @@ interface nsIPrincipal;
* by launching a dialog to prompt the user for something).
*/
[scriptable,uuid(447a2300-ab3c-11e4-bcd8-0800200c9a66)]
[scriptable,uuid(cb978019-0c5b-4067-abb6-c914461208c1)]
interface nsIContentPolicy : nsIContentPolicyBase
{
/**

View File

@ -24,7 +24,7 @@ typedef unsigned long nsContentPolicyType;
* by launching a dialog to prompt the user for something).
*/
[scriptable,uuid(21bb54b0-ab3c-11e4-bcd8-0800200c9a66)]
[scriptable,uuid(4f2655e8-6365-4583-8510-732bff2186c5)]
interface nsIContentPolicyBase : nsISupports
{
/**
@ -172,6 +172,11 @@ interface nsIContentPolicyBase : nsISupports
*/
const nsContentPolicyType TYPE_IMAGESET = 21;
/**
* Indicates a web manifest.
*/
const nsContentPolicyType TYPE_WEB_MANIFEST = 22;
/* When adding new content types, please update nsContentBlocker,
* NS_CP_ContentTypeName, nsCSPContext, all nsIContentPolicy
* implementations, and other things that are not listed here that are

View File

@ -28,7 +28,7 @@ interface nsIDOMElement;
* by launching a dialog to prompt the user for something).
*/
[scriptable,uuid(83d93c70-ab46-11e4-bcd8-0800200c9a66)]
[scriptable,uuid(704b4b8e-2287-498a-9c0a-d1bde547a2d4)]
interface nsISimpleContentPolicy : nsIContentPolicyBase
{
/**

View File

@ -0,0 +1,4 @@
[DEFAULT]
skip-if = e10s # Bug 1170385 - csp-on-violate-policy message not sent in browser tests with e10s
[browser_test_web_manifest.js]
[browser_test_web_manifest_mixed_content.js]

View File

@ -0,0 +1,265 @@
/*
* Description of the tests:
* These tests check for conformance to the CSP spec as they relate to Web Manifests.
*
* In particular, the tests check that default-src and manifest-src directives are
* are respected by the ManifestObtainer.
*/
/*globals Components*/
'use strict';
requestLongerTimeout(10); // e10s tests take time.
const {
ManifestObtainer
} = Components.utils.import('resource://gre/modules/WebManifest.jsm', {});
const path = '/tests/dom/base/test/csp/';
const testFile = `file=${path}file_CSP_web_manifest.html`;
const remoteFile = `file=${path}file_CSP_web_manifest_remote.html`;
const httpsManifest = `file=${path}file_CSP_web_manifest_https.html`;
const mixedContent = `file=${path}file_CSP_web_manifest_mixed_content.html`;
const server = 'file_csp_testserver.sjs';
const defaultURL = `http://example.org${path}${server}`;
const remoteURL = `http://mochi.test:8888`;
const secureURL = `https://example.com${path}${server}`;
const tests = [
// CSP block everything, so trying to load a manifest
// will result in a policy violation.
{
expected: `default-src 'none' blocks fetching manifest.`,
get tabURL() {
let queryParts = [
`csp=default-src 'none'`,
testFile
];
return `${defaultURL}?${queryParts.join('&')}`;
},
run(topic) {
is(topic, 'csp-on-violate-policy', this.expected);
}
},
// CSP allows fetching only from mochi.test:8888,
// so trying to load a manifest from same origin
// triggers a CSP violation.
{
expected: `default-src mochi.test:8888 blocks manifest fetching.`,
get tabURL() {
let queryParts = [
`csp=default-src mochi.test:8888`,
testFile
];
return `${defaultURL}?${queryParts.join('&')}`;
},
run(topic) {
is(topic, 'csp-on-violate-policy', this.expected);
}
},
// CSP restricts fetching to 'self', so allowing the manifest
// to load. The name of the manifest is then checked.
{
expected: `CSP default-src 'self' allows fetch of manifest.`,
get tabURL() {
let queryParts = [
`csp=default-src 'self'`,
testFile
];
return `${defaultURL}?${queryParts.join('&')}`;
},
run(manifest) {
is(manifest.name, 'loaded', this.expected);
}
},
// CSP only allows fetching from mochi.test:8888 and remoteFile
// requests a manifest from that origin, so manifest should load.
{
expected: 'CSP default-src mochi.test:8888 allows fetching manifest.',
get tabURL() {
let queryParts = [
`csp=default-src http://mochi.test:8888`,
remoteFile
];
return `${defaultURL}?${queryParts.join('&')}`;
},
run(manifest) {
is(manifest.name, 'loaded', this.expected);
}
},
// default-src blocks everything, so any attempt to
// fetch a manifest from another origin will trigger a
// policy violation.
{
expected: `default-src 'none' blocks mochi.test:8888`,
get tabURL() {
let queryParts = [
`csp=default-src 'none'`,
remoteFile
];
return `${defaultURL}?${queryParts.join('&')}`;
},
run(topic) {
is(topic, 'csp-on-violate-policy', this.expected);
}
},
// CSP allows fetching from self, so manifest should load.
{
expected: `CSP manifest-src allows self`,
get tabURL() {
let queryParts = [
`manifest-src 'self'`,
testFile
];
return `${defaultURL}?${queryParts.join('&')}`;
},
run(manifest) {
is(manifest.name, 'loaded', this.expected);
}
},
// CSP allows fetching from example.org, so manifest should load.
{
expected: `CSP manifest-src allows http://example.org`,
get tabURL() {
let queryParts = [
`manifest-src http://example.org`,
testFile
];
return `${defaultURL}?${queryParts.join('&')}`;
},
run(manifest) {
is(manifest.name, 'loaded', this.expected);
}
},
// Check interaction with default-src and another origin,
// CSP allows fetching from example.org, so manifest should load.
{
expected: `CSP manifest-src overrides default-src of elsewhere.com`,
get tabURL() {
let queryParts = [
`default-src: http://elsewhere.com; manifest-src http://example.org`,
testFile
];
return `${defaultURL}?${queryParts.join('&')}`;
},
run(manifest) {
is(manifest.name, 'loaded', this.expected);
}
},
// Check interaction with default-src none,
// CSP allows fetching manifest from example.org, so manifest should load.
{
expected: `CSP manifest-src overrides default-src`,
get tabURL() {
let queryParts = [
`default-src: 'none'; manifest-src 'self'`,
testFile
];
return `${defaultURL}?${queryParts.join('&')}`;
},
run(manifest) {
is(manifest.name, 'loaded', this.expected);
}
},
// CSP allows fetching from mochi.test:8888, which has a
// CORS header set to '*'. So the manifest should load.
{
expected: `CSP manifest-src allows mochi.test:8888`,
get tabURL() {
let queryParts = [
`csp=default-src *; manifest-src http://mochi.test:8888`,
remoteFile
];
return `${defaultURL}?${queryParts.join('&')}`;
},
run(manifest) {
is(manifest.name, 'loaded', this.expected);
}
},
// CSP restricts fetching to mochi.test:8888, but the test
// file is at example.org. Hence, a policy violation is
// triggered.
{
expected: `CSP blocks manifest fetching from example.org.`,
get tabURL() {
let queryParts = [
`csp=manifest-src mochi.test:8888`,
testFile
];
return `${defaultURL}?${queryParts.join('&')}`;
},
run(topic) {
is(topic, 'csp-on-violate-policy', this.expected);
}
},
// CSP is set to only allow manifest to be loaded from same origin,
// but the remote file attempts to load from a different origin. Thus
// this causes a CSP violation.
{
expected: `CSP manifest-src 'self' blocks cross-origin fetch.`,
get tabURL() {
let queryParts = [
`csp=manifest-src 'self'`,
remoteFile
];
return `${defaultURL}?${queryParts.join('&')}`;
},
run(topic) {
is(topic, 'csp-on-violate-policy', this.expected);
}
}
];
//jscs:disable
add_task(function* () {
//jscs:enable
for (let test of tests) {
let tabOptions = {
gBrowser: gBrowser,
url: test.tabURL,
};
yield BrowserTestUtils.withNewTab(
tabOptions,
browser => testObtainingManifest(browser, test)
);
}
function* testObtainingManifest(aBrowser, aTest) {
const observer = (/blocks/.test(aTest.expected)) ? new NetworkObserver(aTest) : null;
const obtainer = new ManifestObtainer();
let manifest;
// Expect an exception (from promise rejection) if there a content policy
// that is violated.
try {
manifest = yield obtainer.obtainManifest(aBrowser);
} catch (e) {
const msg = `Expected promise rejection obtaining.`;
ok(/blocked the loading of a resource/.test(e.message), msg);
if (observer) {
yield observer.finished;
}
return;
}
// otherwise, we test manifest's content.
if (manifest) {
aTest.run(manifest);
}
}
});
// Helper object used to observe policy violations. It waits 10 seconds
// for a response, and then times out causing its associated test to fail.
function NetworkObserver(test) {
let finishedTest;
let success = false;
this.finished = new Promise((resolver) => {
finishedTest = resolver;
})
this.observe = function observer(subject, topic) {
SpecialPowers.removeObserver(this, 'csp-on-violate-policy');
test.run(topic);
finishedTest();
success = true;
};
SpecialPowers.addObserver(this, 'csp-on-violate-policy', false);
setTimeout(() => {
if (!success) {
test.run('This test timed out.');
finishedTest();
}
}, 1000);
}

View File

@ -0,0 +1,55 @@
/*
* Description of the test:
* Check that mixed content blocker works prevents fetches of
* mixed content manifests.
*/
'use strict';
const {
ManifestObtainer
} = Components.utils.import('resource://gre/modules/WebManifest.jsm', {});
const path = '/tests/dom/base/test/csp/';
const mixedContent = `file=${path}file_CSP_web_manifest_mixed_content.html`;
const server = 'file_csp_testserver.sjs';
const secureURL = `https://example.com${path}${server}`;
const tests = [
// Trying to load mixed content in file_CSP_web_manifest_mixed_content.html
// needs to result in an error.
{
expected: `Mixed Content Blocker prevents fetching manifest.`,
get tabURL() {
let queryParts = [
mixedContent
];
return `${secureURL}?${queryParts.join('&')}`;
},
run(error) {
// Check reason for error.
const check = /blocked the loading of a resource/.test(error.message);
ok(check, this.expected);
}
}
];
//jscs:disable
add_task(function*() {
//jscs:enable
for (let test of tests) {
let tabOptions = {
gBrowser: gBrowser,
url: test.tabURL,
};
yield BrowserTestUtils.withNewTab(
tabOptions,
browser => testObtainingManifest(browser, test)
);
}
function* testObtainingManifest(aBrowser, aTest) {
const obtainer = new ManifestObtainer();
try {
yield obtainer.obtainManifest(aBrowser);
} catch (e) {
aTest.run(e)
}
}
});

View File

@ -0,0 +1,6 @@
<!doctype html>
<meta charset=utf-8>
<head>
<link rel="manifest" href="file_CSP_web_manifest.json">
</head>
<h1>Support Page for Web Manifest Tests</h1>

View File

@ -0,0 +1 @@
{"name": "loaded"}

View File

@ -0,0 +1 @@
Access-Control-Allow-Origin: http://example.org

View File

@ -0,0 +1,4 @@
<!doctype html>
<meta charset=utf-8>
<link rel="manifest" href="https://example.com:443/tests/dom/base/test/csp/file_CSP_web_manifest_https.json">
<h1>Support Page for Web Manifest Tests</h1>

View File

@ -0,0 +1 @@
{"name": "loaded"}

View File

@ -0,0 +1,9 @@
<!doctype html>
<meta charset=utf-8>
<head>
<link
rel="manifest"
href="http://example.org/tests/dom/base/test/csp/file_csp_testserver.sjs?file=/test/dom/base/test/csp/file_CSP_web_manifest.json&amp;cors=*">
</head>
<h1>Support Page for Web Manifest Tests</h1>
<p>Used to try to load a resource over an insecure connection to trigger mixed content blocking.</p>

View File

@ -0,0 +1,8 @@
<!doctype html>
<meta charset=utf-8>
<link rel="manifest"
crossorigin
href="//mochi.test:8888/tests/dom/base/test/csp/file_csp_testserver.sjs?file=/tests/dom/base/test/csp/file_CSP_web_manifest.json&amp;cors=*">
<h1>Support Page for Web Manifest Tests</h1>
<p>Loads a manifest from mochi.test:8888 with CORS set to "*".</p>

View File

@ -22,6 +22,7 @@ function loadHTMLFromFile(path) {
return testHTML;
}
function handleRequest(request, response)
{
var query = {};
@ -30,16 +31,23 @@ function handleRequest(request, response)
query[name] = unescape(value);
});
var csp = unescape(query['csp']);
var csp = (query['csp']) ? unescape(query['csp']) : "";
var file = unescape(query['file']);
var cors = unescape(query['cors']);
// avoid confusing cache behaviors
response.setHeader("Cache-Control", "no-cache", false);
// Deliver the CSP policy encoded in the URI
response.setHeader("Content-Security-Policy", csp, false);
if(csp){
response.setHeader("Content-Security-Policy", csp, false);
}
// Deliver the CORS header in the URI
if(cors){
response.setHeader("Access-Control-Allow-Origin", cors, false);
}
// Send HTML to test allowed/blocked behaviors
response.setHeader("Content-Type", "text/html", false);
response.write(loadHTMLFromFile(file));
}

View File

@ -43,6 +43,13 @@ support-files =
file_CSP_main.html
file_CSP_main.html^headers^
file_CSP_main.js
file_CSP_web_manifest.html
file_CSP_web_manifest_remote.html
file_CSP_web_manifest_https.html
file_CSP_web_manifest.json
file_CSP_web_manifest.json^headers^
file_CSP_web_manifest_https.json
file_CSP_web_manifest_mixed_content.html
file_bug836922_npolicies.html
file_bug836922_npolicies.html^headers^
file_bug836922_npolicies_ro_violation.sjs

View File

@ -37,4 +37,7 @@ MOCHITEST_CHROME_MANIFESTS += [
'csp/chrome.ini',
]
BROWSER_CHROME_MANIFESTS += ['browser.ini']
BROWSER_CHROME_MANIFESTS += [
'browser.ini',
'csp/browser.ini',
]

View File

@ -812,7 +812,7 @@ MaybeWrapStringValue(JSContext* cx, JS::MutableHandle<JS::Value> rval)
{
MOZ_ASSERT(rval.isString());
JSString* str = rval.toString();
if (JS::GetTenuredGCThingZone(str) != js::GetContextZone(cx)) {
if (JS::GetStringZone(str) != js::GetContextZone(cx)) {
return JS_WrapValue(cx, rval);
}
return true;

View File

@ -13301,6 +13301,9 @@ class CGBindingImplClass(CGClass):
wrapArgs = [Argument('JSContext*', 'aCx'),
Argument('JS::Handle<JSObject*>', 'aGivenProto')]
if not descriptor.wrapperCache:
wrapArgs.append(Argument('JS::MutableHandle<JSObject*>',
'aReflector'))
self.methodDecls.insert(0,
ClassMethod(wrapMethodName, "JSObject*",
wrapArgs, virtual=descriptor.wrapperCache,
@ -13418,18 +13421,26 @@ class CGExampleClass(CGBindingImplClass):
""")
if self.descriptor.wrapperCache:
reflectorArg = ""
reflectorPassArg = ""
else:
reflectorArg = ", JS::MutableHandle<JSObject*> aReflector"
reflectorPassArg = ", aReflector"
classImpl = ccImpl + ctordtor + "\n" + dedent("""
JSObject*
${nativeType}::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
${nativeType}::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto${reflectorArg})
{
return ${ifaceName}Binding::Wrap(aCx, this, aGivenProto);
return ${ifaceName}Binding::Wrap(aCx, this, aGivenProto${reflectorPassArg});
}
""")
return string.Template(classImpl).substitute(
ifaceName=self.descriptor.name,
nativeType=self.nativeLeafName(self.descriptor),
parentType=self.nativeLeafName(self.parentDesc) if self.parentIface else "")
parentType=self.nativeLeafName(self.parentDesc) if self.parentIface else "",
reflectorArg=reflectorArg,
reflectorPassArg=reflectorPassArg)
@staticmethod
def nativeLeafName(descriptor):

View File

@ -522,8 +522,7 @@ public:
gattManager->UnregisterClient(mClient->mClientIf, result);
}
DispatchReplyError(mClient->mStartLeScanRunnable,
BluetoothValue(mClient->mAppUuid));
DispatchReplyError(mClient->mStartLeScanRunnable, aStatus);
mClient->mStartLeScanRunnable = nullptr;
}

View File

@ -74,8 +74,11 @@ public:
SOCKET_IS_CONNECTED
};
DroidSocketImpl(MessageLoop* aIOLoop, BluetoothSocket* aConsumer)
DroidSocketImpl(nsIThread* aConsumerThread,
MessageLoop* aIOLoop,
BluetoothSocket* aConsumer)
: ipc::UnixFdWatcher(aIOLoop)
, DataSocketIO(aConsumerThread)
, mConsumer(aConsumer)
, mShuttingDownOnIOThread(false)
, mConnectionStatus(SOCKET_IS_DISCONNECTED)
@ -83,7 +86,7 @@ public:
~DroidSocketImpl()
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(IsConsumerThread());
}
void Send(UnixSocketIOBuffer* aBuffer)
@ -120,8 +123,8 @@ public:
/**
* Consumer pointer. Non-thread safe RefPtr, so should only be manipulated
* directly from main thread. All non-main-thread accesses should happen with
* mImpl as container.
* directly from consumer thread. All non-consumer-thread accesses should
* happen with mImpl as container.
*/
RefPtr<BluetoothSocket> mConsumer;
@ -140,9 +143,10 @@ public:
return GetDataSocket();
}
bool IsShutdownOnMainThread() const override
bool IsShutdownOnConsumerThread() const override
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(IsConsumerThread());
return mConsumer == nullptr;
}
@ -151,16 +155,17 @@ public:
return mShuttingDownOnIOThread;
}
void ShutdownOnMainThread() override
void ShutdownOnConsumerThread() override
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!IsShutdownOnMainThread());
MOZ_ASSERT(IsConsumerThread());
MOZ_ASSERT(!IsShutdownOnConsumerThread());
mConsumer = nullptr;
}
void ShutdownOnIOThread() override
{
MOZ_ASSERT(!NS_IsMainThread());
MOZ_ASSERT(!IsConsumerThread());
MOZ_ASSERT(!mShuttingDownOnIOThread);
Close(); // will also remove fd from I/O loop
@ -214,7 +219,7 @@ public:
void Run() override
{
MOZ_ASSERT(!NS_IsMainThread());
MOZ_ASSERT(!GetIO()->IsConsumerThread());
MOZ_ASSERT(!IsCanceled());
GetIO()->Connect(mFd);
@ -234,7 +239,7 @@ public:
void Run() override
{
MOZ_ASSERT(!NS_IsMainThread());
MOZ_ASSERT(!GetIO()->IsConsumerThread());
if (!IsCanceled()) {
GetIO()->Listen(mFd);
@ -254,7 +259,7 @@ class SocketConnectClientFdTask final
void Run() override
{
MOZ_ASSERT(!NS_IsMainThread());
MOZ_ASSERT(!GetIO()->IsConsumerThread());
GetIO()->ConnectClientFd();
}
@ -314,8 +319,9 @@ DroidSocketImpl::Accept(int aFd)
SetFd(aFd);
mConnectionStatus = SOCKET_IS_CONNECTED;
NS_DispatchToMainThread(
new SocketIOEventRunnable(this, SocketIOEventRunnable::CONNECT_SUCCESS));
GetConsumerThread()->Dispatch(
new SocketIOEventRunnable(this, SocketIOEventRunnable::CONNECT_SUCCESS),
NS_DISPATCH_NORMAL);
AddWatchers(READ_WATCHER, true);
if (HasPendingData()) {
@ -338,7 +344,7 @@ DroidSocketImpl::OnFileCanReadWithoutBlocking(int aFd)
void
DroidSocketImpl::OnSocketCanReceiveWithoutBlocking(int aFd)
{
MOZ_ASSERT(!NS_IsMainThread());
MOZ_ASSERT(!IsConsumerThread());
MOZ_ASSERT(!mShuttingDownOnIOThread);
ssize_t res = ReceiveData(aFd);
@ -361,7 +367,7 @@ public:
void Run() override
{
MOZ_ASSERT(!NS_IsMainThread());
MOZ_ASSERT(!GetIO()->IsConsumerThread());
MOZ_ASSERT(!IsCanceled());
GetIO()->Accept(mFd);
@ -383,11 +389,11 @@ public:
void Accept(int aFd, const nsAString& aBdAddress,
int aConnectionStatus) override
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mImpl->IsConsumerThread());
mozilla::ScopedClose fd(aFd); // Close received socket fd on error
if (mImpl->IsShutdownOnMainThread()) {
if (mImpl->IsShutdownOnConsumerThread()) {
BT_LOGD("mConsumer is null, aborting receive!");
return;
}
@ -398,16 +404,16 @@ public:
}
mImpl->mConsumer->SetAddress(aBdAddress);
XRE_GetIOMessageLoop()->PostTask(FROM_HERE,
new AcceptTask(mImpl, fd.forget()));
mImpl->GetIOLoop()->PostTask(FROM_HERE,
new AcceptTask(mImpl, fd.forget()));
}
void OnError(BluetoothStatus aStatus) override
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mImpl->IsConsumerThread());
BT_LOGR("BluetoothSocketInterface::Accept failed: %d", (int)aStatus);
if (!mImpl->IsShutdownOnMainThread()) {
if (!mImpl->IsShutdownOnConsumerThread()) {
// Instead of NotifyError(), call NotifyDisconnect() to trigger
// BluetoothOppManager::OnSocketDisconnect() as
// DroidSocketImpl::OnFileCanReadWithoutBlocking() in Firefox OS 2.0 in
@ -430,7 +436,7 @@ public:
NS_IMETHOD Run() override
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(GetIO()->IsConsumerThread());
MOZ_ASSERT(sBluetoothSocketInterface);
BluetoothSocketResultHandler* res = new AcceptResultHandler(GetIO());
@ -448,7 +454,7 @@ private:
void
DroidSocketImpl::OnSocketCanAcceptWithoutBlocking(int aFd)
{
MOZ_ASSERT(!NS_IsMainThread());
MOZ_ASSERT(!IsConsumerThread());
MOZ_ASSERT(!mShuttingDownOnIOThread);
/* When a listening socket is ready for receiving data,
@ -456,8 +462,8 @@ DroidSocketImpl::OnSocketCanAcceptWithoutBlocking(int aFd)
*/
RemoveWatchers(READ_WATCHER);
nsRefPtr<AcceptRunnable> t = new AcceptRunnable(this, aFd);
NS_DispatchToMainThread(t);
GetConsumerThread()->Dispatch(new AcceptRunnable(this, aFd),
NS_DISPATCH_NORMAL);
}
void
@ -475,7 +481,7 @@ DroidSocketImpl::OnFileCanWriteWithoutBlocking(int aFd)
void
DroidSocketImpl::OnSocketCanSendWithoutBlocking(int aFd)
{
MOZ_ASSERT(!NS_IsMainThread());
MOZ_ASSERT(!IsConsumerThread());
MOZ_ASSERT(!mShuttingDownOnIOThread);
MOZ_ASSERT(aFd >= 0);
@ -492,7 +498,7 @@ DroidSocketImpl::OnSocketCanSendWithoutBlocking(int aFd)
void
DroidSocketImpl::OnSocketCanConnectWithoutBlocking(int aFd)
{
MOZ_ASSERT(!NS_IsMainThread());
MOZ_ASSERT(!IsConsumerThread());
MOZ_ASSERT(!mShuttingDownOnIOThread);
/* We follow Posix behaviour here: Connect operations are
@ -501,8 +507,9 @@ DroidSocketImpl::OnSocketCanConnectWithoutBlocking(int aFd)
mConnectionStatus = SOCKET_IS_CONNECTED;
NS_DispatchToMainThread(
new SocketIOEventRunnable(this, SocketIOEventRunnable::CONNECT_SUCCESS));
GetConsumerThread()->Dispatch(
new SocketIOEventRunnable(this, SocketIOEventRunnable::CONNECT_SUCCESS),
NS_DISPATCH_NORMAL);
AddWatchers(READ_WATCHER, true);
if (HasPendingData()) {
@ -528,7 +535,7 @@ DroidSocketImpl::QueryReceiveBuffer(
/**
* |ReceiveRunnable| transfers data received on the I/O thread
* to an instance of |BluetoothSocket| on the main thread.
* to an instance of |BluetoothSocket| on the consumer thread.
*/
class DroidSocketImpl::ReceiveRunnable final
: public SocketIORunnable<DroidSocketImpl>
@ -541,11 +548,11 @@ public:
NS_IMETHOD Run() override
{
MOZ_ASSERT(NS_IsMainThread());
DroidSocketImpl* io = SocketIORunnable<DroidSocketImpl>::GetIO();
if (NS_WARN_IF(io->IsShutdownOnMainThread())) {
MOZ_ASSERT(io->IsConsumerThread());
if (NS_WARN_IF(io->IsShutdownOnConsumerThread())) {
// Since we've already explicitly closed and the close
// happened before this, this isn't really an error.
return NS_OK;
@ -566,7 +573,8 @@ private:
void
DroidSocketImpl::ConsumeBuffer()
{
NS_DispatchToMainThread(new ReceiveRunnable(this, mBuffer.forget()));
GetConsumerThread()->Dispatch(new ReceiveRunnable(this, mBuffer.forget()),
NS_DISPATCH_NORMAL);
}
void
@ -602,9 +610,9 @@ public:
void Connect(int aFd, const nsAString& aBdAddress,
int aConnectionStatus) override
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mImpl->IsConsumerThread());
if (mImpl->IsShutdownOnMainThread()) {
if (mImpl->IsShutdownOnConsumerThread()) {
BT_LOGD("mConsumer is null, aborting send!");
return;
}
@ -615,16 +623,16 @@ public:
}
mImpl->mConsumer->SetAddress(aBdAddress);
XRE_GetIOMessageLoop()->PostTask(FROM_HERE,
new SocketConnectTask(mImpl, aFd));
mImpl->GetIOLoop()->PostTask(FROM_HERE,
new SocketConnectTask(mImpl, aFd));
}
void OnError(BluetoothStatus aStatus) override
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mImpl->IsConsumerThread());
BT_WARNING("Connect failed: %d", (int)aStatus);
if (!mImpl->IsShutdownOnMainThread()) {
if (!mImpl->IsShutdownOnConsumerThread()) {
// Instead of NotifyError(), call NotifyDisconnect() to trigger
// BluetoothOppManager::OnSocketDisconnect() as
// DroidSocketImpl::OnFileCanReadWithoutBlocking() in Firefox OS 2.0 in
@ -642,14 +650,15 @@ BluetoothSocket::Connect(const nsAString& aDeviceAddress,
const BluetoothUuid& aServiceUuid,
BluetoothSocketType aType,
int aChannel,
bool aAuth, bool aEncrypt)
bool aAuth, bool aEncrypt,
nsIThread* aConsumerThread,
MessageLoop* aIOLoop)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!mImpl);
SetConnectionStatus(SOCKET_CONNECTING);
mImpl = new DroidSocketImpl(XRE_GetIOMessageLoop(), this);
mImpl = new DroidSocketImpl(aConsumerThread, aIOLoop, this);
BluetoothSocketResultHandler* res = new ConnectSocketResultHandler(mImpl);
SetCurrentResultHandler(res);
@ -662,6 +671,23 @@ BluetoothSocket::Connect(const nsAString& aDeviceAddress,
return NS_OK;
}
nsresult
BluetoothSocket::Connect(const nsAString& aDeviceAddress,
const BluetoothUuid& aServiceUuid,
BluetoothSocketType aType,
int aChannel,
bool aAuth, bool aEncrypt)
{
nsIThread* consumerThread = nullptr;
nsresult rv = NS_GetCurrentThread(&consumerThread);
if (NS_FAILED(rv)) {
return rv;
}
return Connect(aDeviceAddress, aServiceUuid, aType, aChannel, aAuth,
aEncrypt, consumerThread, XRE_GetIOMessageLoop());
}
class ListenResultHandler final : public BluetoothSocketResultHandler
{
public:
@ -673,15 +699,14 @@ public:
void Listen(int aFd) override
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mImpl->IsConsumerThread());
XRE_GetIOMessageLoop()->PostTask(FROM_HERE,
new SocketListenTask(mImpl, aFd));
mImpl->GetIOLoop()->PostTask(FROM_HERE, new SocketListenTask(mImpl, aFd));
}
void OnError(BluetoothStatus aStatus) override
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mImpl->IsConsumerThread());
BT_WARNING("Listen failed: %d", (int)aStatus);
}
@ -695,14 +720,15 @@ BluetoothSocket::Listen(const nsAString& aServiceName,
const BluetoothUuid& aServiceUuid,
BluetoothSocketType aType,
int aChannel,
bool aAuth, bool aEncrypt)
bool aAuth, bool aEncrypt,
nsIThread* aConsumerThread,
MessageLoop* aIOLoop)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!mImpl);
SetConnectionStatus(SOCKET_LISTENING);
mImpl = new DroidSocketImpl(XRE_GetIOMessageLoop(), this);
mImpl = new DroidSocketImpl(aConsumerThread, aIOLoop, this);
BluetoothSocketResultHandler* res = new ListenResultHandler(mImpl);
SetCurrentResultHandler(res);
@ -715,10 +741,26 @@ BluetoothSocket::Listen(const nsAString& aServiceName,
return NS_OK;
}
nsresult
BluetoothSocket::Listen(const nsAString& aServiceName,
const BluetoothUuid& aServiceUuid,
BluetoothSocketType aType,
int aChannel,
bool aAuth, bool aEncrypt)
{
nsIThread* consumerThread = nullptr;
nsresult rv = NS_GetCurrentThread(&consumerThread);
if (NS_FAILED(rv)) {
return rv;
}
return Listen(aServiceName, aServiceUuid, aType, aChannel, aAuth, aEncrypt,
consumerThread, XRE_GetIOMessageLoop());
}
void
BluetoothSocket::ReceiveSocketData(nsAutoPtr<UnixSocketBuffer>& aBuffer)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mObserver);
mObserver->ReceiveSocketData(this, aBuffer);
@ -729,11 +771,11 @@ BluetoothSocket::ReceiveSocketData(nsAutoPtr<UnixSocketBuffer>& aBuffer)
void
BluetoothSocket::SendSocketData(UnixSocketIOBuffer* aBuffer)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mImpl);
MOZ_ASSERT(!mImpl->IsShutdownOnMainThread());
MOZ_ASSERT(mImpl->IsConsumerThread());
MOZ_ASSERT(!mImpl->IsShutdownOnConsumerThread());
XRE_GetIOMessageLoop()->PostTask(
mImpl->GetIOLoop()->PostTask(
FROM_HERE,
new SocketIOSendTask<DroidSocketImpl, UnixSocketIOBuffer>(mImpl, aBuffer));
}
@ -743,12 +785,14 @@ BluetoothSocket::SendSocketData(UnixSocketIOBuffer* aBuffer)
void
BluetoothSocket::Close()
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(sBluetoothSocketInterface);
if (!mImpl) {
return;
}
MOZ_ASSERT(mImpl->IsConsumerThread());
// Stop any watching |SocketMessageWatcher|
if (mCurrentRes) {
sBluetoothSocketInterface->Close(mCurrentRes);
@ -757,10 +801,8 @@ BluetoothSocket::Close()
// From this point on, we consider mImpl as being deleted.
// We sever the relationship here so any future calls to listen or connect
// will create a new implementation.
mImpl->ShutdownOnMainThread();
XRE_GetIOMessageLoop()->PostTask(FROM_HERE, new SocketIOShutdownTask(mImpl));
mImpl->ShutdownOnConsumerThread();
mImpl->GetIOLoop()->PostTask(FROM_HERE, new SocketIOShutdownTask(mImpl));
mImpl = nullptr;
NotifyDisconnect();
@ -769,7 +811,6 @@ BluetoothSocket::Close()
void
BluetoothSocket::OnConnectSuccess()
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mObserver);
SetCurrentResultHandler(nullptr);
@ -779,7 +820,6 @@ BluetoothSocket::OnConnectSuccess()
void
BluetoothSocket::OnConnectError()
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mObserver);
SetCurrentResultHandler(nullptr);
@ -789,7 +829,6 @@ BluetoothSocket::OnConnectError()
void
BluetoothSocket::OnDisconnect()
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mObserver);
mObserver->OnSocketDisconnect(this);
}

View File

@ -10,6 +10,9 @@
#include "BluetoothCommon.h"
#include "mozilla/ipc/DataSocket.h"
class MessageLoop;
class nsIThread;
BEGIN_BLUETOOTH_NAMESPACE
class BluetoothSocketObserver;
@ -21,12 +24,28 @@ class BluetoothSocket final : public mozilla::ipc::DataSocket
public:
BluetoothSocket(BluetoothSocketObserver* aObserver);
nsresult Connect(const nsAString& aDeviceAddress,
const BluetoothUuid& aServiceUuid,
BluetoothSocketType aType,
int aChannel,
bool aAuth, bool aEncrypt,
nsIThread* aConsumerThread,
MessageLoop* aIOLoop);
nsresult Connect(const nsAString& aDeviceAddress,
const BluetoothUuid& aServiceUuid,
BluetoothSocketType aType,
int aChannel,
bool aAuth, bool aEncrypt);
nsresult Listen(const nsAString& aServiceName,
const BluetoothUuid& aServiceUuid,
BluetoothSocketType aType,
int aChannel,
bool aAuth, bool aEncrypt,
nsIThread* aConsumerThread,
MessageLoop* aIOLoop);
nsresult Listen(const nsAString& aServiceName,
const BluetoothUuid& aServiceUuid,
BluetoothSocketType aType,
@ -35,7 +54,7 @@ public:
/**
* Method to be called whenever data is received. This is only called on the
* main thread.
* consumer thread.
*
* @param aBuffer Data received from the socket.
*/

View File

@ -28,7 +28,8 @@ class BluetoothSocket::BluetoothSocketIO final
, public DataSocketIO
{
public:
BluetoothSocketIO(MessageLoop* mIOLoop,
BluetoothSocketIO(nsIThread* aConsumerThread,
MessageLoop* aIOLoop,
BluetoothSocket* aConsumer,
UnixSocketConnector* aConnector);
~BluetoothSocketIO();
@ -82,10 +83,10 @@ public:
SocketBase* GetSocketBase() override;
bool IsShutdownOnMainThread() const override;
bool IsShutdownOnConsumerThread() const override;
bool IsShutdownOnIOThread() const override;
void ShutdownOnMainThread() override;
void ShutdownOnConsumerThread() override;
void ShutdownOnIOThread() override;
private:
@ -95,8 +96,8 @@ private:
/**
* Consumer pointer. Non-thread safe RefPtr, so should only be manipulated
* directly from main thread. All non-main-thread accesses should happen with
* mIO as container.
* directly from consumer thread. All non-consumer-thread accesses should
* happen with mIO as container.
*/
RefPtr<BluetoothSocket> mConsumer;
@ -121,7 +122,8 @@ private:
struct sockaddr_storage mAddress;
/**
* Task member for delayed connect task. Should only be access on main thread.
* Task member for delayed connect task. Should only be access on consumer
* thread.
*/
CancelableTask* mDelayedConnectTask;
@ -132,10 +134,12 @@ private:
};
BluetoothSocket::BluetoothSocketIO::BluetoothSocketIO(
MessageLoop* mIOLoop,
nsIThread* aConsumerThread,
MessageLoop* aIOLoop,
BluetoothSocket* aConsumer,
UnixSocketConnector* aConnector)
: UnixSocketWatcher(mIOLoop)
: UnixSocketWatcher(aIOLoop)
, DataSocketIO(aConsumerThread)
, mConsumer(aConsumer)
, mConnector(aConnector)
, mShuttingDownOnIOThread(false)
@ -148,8 +152,8 @@ BluetoothSocket::BluetoothSocketIO::BluetoothSocketIO(
BluetoothSocket::BluetoothSocketIO::~BluetoothSocketIO()
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(IsShutdownOnMainThread());
MOZ_ASSERT(IsConsumerThread());
MOZ_ASSERT(IsShutdownOnConsumerThread());
}
void
@ -188,7 +192,7 @@ BluetoothSocket::BluetoothSocketIO::GetDataSocket()
void
BluetoothSocket::BluetoothSocketIO::SetDelayedConnectTask(CancelableTask* aTask)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(IsConsumerThread());
mDelayedConnectTask = aTask;
}
@ -196,7 +200,7 @@ BluetoothSocket::BluetoothSocketIO::SetDelayedConnectTask(CancelableTask* aTask)
void
BluetoothSocket::BluetoothSocketIO::ClearDelayedConnectTask()
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(IsConsumerThread());
mDelayedConnectTask = nullptr;
}
@ -204,7 +208,7 @@ BluetoothSocket::BluetoothSocketIO::ClearDelayedConnectTask()
void
BluetoothSocket::BluetoothSocketIO::CancelDelayedConnectTask()
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(IsConsumerThread());
if (!mDelayedConnectTask) {
return;
@ -277,8 +281,9 @@ BluetoothSocket::BluetoothSocketIO::OnConnected()
MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
MOZ_ASSERT(GetConnectionStatus() == SOCKET_IS_CONNECTED);
NS_DispatchToMainThread(
new SocketIOEventRunnable(this, SocketIOEventRunnable::CONNECT_SUCCESS));
GetConsumerThread()->Dispatch(
new SocketIOEventRunnable(this, SocketIOEventRunnable::CONNECT_SUCCESS),
NS_DISPATCH_NORMAL);
AddWatchers(READ_WATCHER, true);
if (HasPendingData()) {
@ -326,8 +331,9 @@ BluetoothSocket::BluetoothSocketIO::OnSocketCanAcceptWithoutBlocking()
Close();
SetSocket(fd, SOCKET_IS_CONNECTED);
NS_DispatchToMainThread(
new SocketIOEventRunnable(this, SocketIOEventRunnable::CONNECT_SUCCESS));
GetConsumerThread()->Dispatch(
new SocketIOEventRunnable(this, SocketIOEventRunnable::CONNECT_SUCCESS),
NS_DISPATCH_NORMAL);
AddWatchers(READ_WATCHER, true);
if (HasPendingData()) {
@ -375,9 +381,10 @@ BluetoothSocket::BluetoothSocketIO::FireSocketError()
// Clean up watchers, statuses, fds
Close();
// Tell the main thread we've errored
NS_DispatchToMainThread(
new SocketIOEventRunnable(this, SocketIOEventRunnable::CONNECT_ERROR));
// Tell the consumer thread we've errored
GetConsumerThread()->Dispatch(
new SocketIOEventRunnable(this, SocketIOEventRunnable::CONNECT_ERROR),
NS_DISPATCH_NORMAL);
}
@ -399,7 +406,7 @@ BluetoothSocket::BluetoothSocketIO::QueryReceiveBuffer(
/**
* |ReceiveRunnable| transfers data received on the I/O thread
* to an instance of |BluetoothSocket| on the main thread.
* to an instance of |BluetoothSocket| on the consumer thread.
*/
class BluetoothSocket::BluetoothSocketIO::ReceiveRunnable final
: public SocketIORunnable<BluetoothSocketIO>
@ -412,11 +419,11 @@ public:
NS_IMETHOD Run() override
{
MOZ_ASSERT(NS_IsMainThread());
BluetoothSocketIO* io = SocketIORunnable<BluetoothSocketIO>::GetIO();
if (NS_WARN_IF(io->IsShutdownOnMainThread())) {
MOZ_ASSERT(io->IsConsumerThread());
if (NS_WARN_IF(io->IsShutdownOnConsumerThread())) {
// Since we've already explicitly closed and the close
// happened before this, this isn't really an error.
return NS_OK;
@ -437,7 +444,8 @@ private:
void
BluetoothSocket::BluetoothSocketIO::ConsumeBuffer()
{
NS_DispatchToMainThread(new ReceiveRunnable(this, mBuffer.forget()));
GetConsumerThread()->Dispatch(new ReceiveRunnable(this, mBuffer.forget()),
NS_DISPATCH_NORMAL);
}
void
@ -455,18 +463,18 @@ BluetoothSocket::BluetoothSocketIO::GetSocketBase()
}
bool
BluetoothSocket::BluetoothSocketIO::IsShutdownOnMainThread() const
BluetoothSocket::BluetoothSocketIO::IsShutdownOnConsumerThread() const
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(IsConsumerThread());
return mConsumer == nullptr;
}
void
BluetoothSocket::BluetoothSocketIO::ShutdownOnMainThread()
BluetoothSocket::BluetoothSocketIO::ShutdownOnConsumerThread()
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!IsShutdownOnMainThread());
MOZ_ASSERT(IsConsumerThread());
MOZ_ASSERT(!IsShutdownOnConsumerThread());
mConsumer = nullptr;
}
@ -480,7 +488,7 @@ BluetoothSocket::BluetoothSocketIO::IsShutdownOnIOThread() const
void
BluetoothSocket::BluetoothSocketIO::ShutdownOnIOThread()
{
MOZ_ASSERT(!NS_IsMainThread());
MOZ_ASSERT(!IsConsumerThread());
MOZ_ASSERT(!mShuttingDownOnIOThread);
Close(); // will also remove fd from I/O loop
@ -502,7 +510,7 @@ public:
void Run() override
{
MOZ_ASSERT(!NS_IsMainThread());
MOZ_ASSERT(!GetIO()->IsConsumerThread());
if (!IsCanceled()) {
GetIO()->Listen();
@ -520,7 +528,7 @@ public:
void Run() override
{
MOZ_ASSERT(!NS_IsMainThread());
MOZ_ASSERT(!GetIO()->IsConsumerThread());
MOZ_ASSERT(!IsCanceled());
GetIO()->Connect();
@ -537,19 +545,19 @@ public:
void Run() override
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(GetIO()->IsConsumerThread());
if (IsCanceled()) {
return;
}
BluetoothSocketIO* io = GetIO();
if (io->IsShutdownOnMainThread()) {
if (io->IsShutdownOnConsumerThread()) {
return;
}
io->ClearDelayedConnectTask();
XRE_GetIOMessageLoop()->PostTask(FROM_HERE, new ConnectTask(io));
io->GetIOLoop()->PostTask(FROM_HERE, new ConnectTask(io));
}
};
@ -576,7 +584,6 @@ BluetoothSocket::Connect(const nsAString& aDeviceAddress,
int aChannel,
bool aAuth, bool aEncrypt)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!aDeviceAddress.IsEmpty());
nsAutoPtr<BluetoothUnixSocketConnector> connector(
@ -603,8 +610,6 @@ BluetoothSocket::Listen(const nsAString& aServiceName,
int aChannel,
bool aAuth, bool aEncrypt)
{
MOZ_ASSERT(NS_IsMainThread());
nsAutoPtr<BluetoothUnixSocketConnector> connector(
new BluetoothUnixSocketConnector(NS_LITERAL_CSTRING(BLUETOOTH_ADDRESS_NONE),
aType, aChannel, aAuth, aEncrypt));
@ -625,7 +630,6 @@ BluetoothSocket::Listen(const nsAString& aServiceName,
void
BluetoothSocket::ReceiveSocketData(nsAutoPtr<UnixSocketBuffer>& aBuffer)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mObserver);
mObserver->ReceiveSocketData(this, aBuffer);
@ -645,39 +649,68 @@ BluetoothSocket::SendSocketData(const nsACString& aStr)
nsresult
BluetoothSocket::Connect(BluetoothUnixSocketConnector* aConnector,
int aDelayMs)
int aDelayMs,
nsIThread* aConsumerThread, MessageLoop* aIOLoop)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aConnector);
MOZ_ASSERT(aConsumerThread);
MOZ_ASSERT(aIOLoop);
MOZ_ASSERT(!mIO);
MessageLoop* ioLoop = XRE_GetIOMessageLoop();
mIO = new BluetoothSocketIO(ioLoop, this, aConnector);
mIO = new BluetoothSocketIO(aConsumerThread, aIOLoop, this, aConnector);
SetConnectionStatus(SOCKET_CONNECTING);
if (aDelayMs > 0) {
DelayedConnectTask* connectTask = new DelayedConnectTask(mIO);
mIO->SetDelayedConnectTask(connectTask);
MessageLoop::current()->PostDelayedTask(FROM_HERE, connectTask, aDelayMs);
} else {
ioLoop->PostTask(FROM_HERE, new ConnectTask(mIO));
aIOLoop->PostTask(FROM_HERE, new ConnectTask(mIO));
}
return NS_OK;
}
nsresult
BluetoothSocket::Connect(BluetoothUnixSocketConnector* aConnector,
int aDelayMs)
{
nsIThread* consumerThread = nullptr;
nsresult rv = NS_GetCurrentThread(&consumerThread);
if (NS_FAILED(rv)) {
return rv;
}
return Connect(aConnector, aDelayMs, consumerThread, XRE_GetIOMessageLoop());
}
nsresult
BluetoothSocket::Listen(BluetoothUnixSocketConnector* aConnector,
nsIThread* aConsumerThread, MessageLoop* aIOLoop)
{
MOZ_ASSERT(aConnector);
MOZ_ASSERT(aConsumerThread);
MOZ_ASSERT(aIOLoop);
MOZ_ASSERT(!mIO);
mIO = new BluetoothSocketIO(aConsumerThread, aIOLoop, this, aConnector);
SetConnectionStatus(SOCKET_LISTENING);
aIOLoop->PostTask(FROM_HERE, new ListenTask(mIO));
return NS_OK;
}
nsresult
BluetoothSocket::Listen(BluetoothUnixSocketConnector* aConnector)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aConnector);
MOZ_ASSERT(!mIO);
nsIThread* consumerThread = nullptr;
nsresult rv = NS_GetCurrentThread(&consumerThread);
if (NS_FAILED(rv)) {
return rv;
}
MessageLoop* ioLoop = XRE_GetIOMessageLoop();
mIO = new BluetoothSocketIO(ioLoop, this, aConnector);
SetConnectionStatus(SOCKET_LISTENING);
ioLoop->PostTask(FROM_HERE, new ListenTask(mIO));
return NS_OK;
return Listen(aConnector, consumerThread, XRE_GetIOMessageLoop());
}
void
@ -696,11 +729,11 @@ BluetoothSocket::GetAddress(nsAString& aAddrStr)
void
BluetoothSocket::SendSocketData(UnixSocketIOBuffer* aBuffer)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mIO);
MOZ_ASSERT(!mIO->IsShutdownOnMainThread());
MOZ_ASSERT(mIO->IsConsumerThread());
MOZ_ASSERT(!mIO->IsShutdownOnConsumerThread());
XRE_GetIOMessageLoop()->PostTask(
mIO->GetIOLoop()->PostTask(
FROM_HERE,
new SocketIOSendTask<BluetoothSocketIO, UnixSocketIOBuffer>(mIO, aBuffer));
}
@ -710,20 +743,19 @@ BluetoothSocket::SendSocketData(UnixSocketIOBuffer* aBuffer)
void
BluetoothSocket::Close()
{
MOZ_ASSERT(NS_IsMainThread());
if (!mIO) {
return;
}
MOZ_ASSERT(mIO->IsConsumerThread());
mIO->CancelDelayedConnectTask();
// From this point on, we consider mIO as being deleted.
// We sever the relationship here so any future calls to listen or connect
// will create a new implementation.
mIO->ShutdownOnMainThread();
XRE_GetIOMessageLoop()->PostTask(FROM_HERE, new SocketIOShutdownTask(mIO));
mIO->ShutdownOnConsumerThread();
mIO->GetIOLoop()->PostTask(FROM_HERE, new SocketIOShutdownTask(mIO));
mIO = nullptr;
NotifyDisconnect();
@ -732,7 +764,6 @@ BluetoothSocket::Close()
void
BluetoothSocket::OnConnectSuccess()
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mObserver);
mObserver->OnSocketConnectSuccess(this);
}
@ -740,7 +771,6 @@ BluetoothSocket::OnConnectSuccess()
void
BluetoothSocket::OnConnectError()
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mObserver);
mObserver->OnSocketConnectError(this);
}
@ -748,7 +778,6 @@ BluetoothSocket::OnConnectError()
void
BluetoothSocket::OnDisconnect()
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mObserver);
mObserver->OnSocketDisconnect(this);
}

View File

@ -16,6 +16,8 @@
#include "nsString.h"
#include "nsThreadUtils.h"
class MessageLoop;
BEGIN_BLUETOOTH_NAMESPACE
class BluetoothSocketObserver;
@ -41,7 +43,7 @@ public:
/**
* Method to be called whenever data is received. This is only called on the
* main thread.
* consumer thread.
*
* @param aBuffer Data received from the socket.
*/
@ -58,6 +60,19 @@ public:
*/
bool SendSocketData(const nsACString& aMessage);
/**
* Starts a task on the socket that will try to connect to a socket in a
* non-blocking manner.
*
* @param aConnector Connector object for socket type specific functions
* @param aDelayMs Time delay in milli-seconds.
* @param aConsumerThread The socket's consumer thread.
* @param aIOLoop The socket's I/O thread.
* @return NS_OK on success, or an XPCOM error code otherwise.
*/
nsresult Connect(BluetoothUnixSocketConnector* aConnector, int aDelayMs,
nsIThread* aConsumerThread, MessageLoop* aIOLoop);
/**
* Starts a task on the socket that will try to connect to a socket in a
* non-blocking manner.
@ -69,6 +84,18 @@ public:
nsresult Connect(BluetoothUnixSocketConnector* aConnector,
int aDelayMs = 0);
/**
* Starts a task on the socket that will try to accept a new connection in a
* non-blocking manner.
*
* @param aConnector Connector object for socket type specific functions
* @param aConsumerThread The socket's consumer thread.
* @param aIOLoop The socket's I/O thread.
* @return NS_OK on success, or an XPCOM error code otherwise.
*/
nsresult Listen(BluetoothUnixSocketConnector* aConnector,
nsIThread* aConsumerThread, MessageLoop* aIOLoop);
/**
* Starts a task on the socket that will try to accept a new connection in a
* non-blocking manner.

View File

@ -168,6 +168,9 @@ InternalRequest::SetContentPolicyType(nsContentPolicyType aContentPolicyType)
case nsIContentPolicy::TYPE_IMAGESET:
mContext = RequestContext::Imageset;
break;
case nsIContentPolicy::TYPE_WEB_MANIFEST:
mContext = RequestContext::Manifest;
break;
default:
MOZ_ASSERT(false, "Unhandled nsContentPolicyType value");
mContext = RequestContext::Internal;

View File

@ -49,7 +49,7 @@ namespace dom {
* import | Not supported by Gecko
* internal | TYPE_DOCUMENT, TYPE_XBL, TYPE_OTHER
* location |
* manifest |
* manifest | TYPE_WEB_MANIFEST
* object | TYPE_OBJECT
* ping | TYPE_PING
* plugin | TYPE_OBJECT_SUBREQUEST

View File

@ -20,7 +20,7 @@ interface nsIURI;
typedef unsigned short CSPDirective;
[scriptable, uuid(459fe61a-203e-4460-9ced-352a9bd3aa71)]
[scriptable, uuid(059b94e3-45c2-4794-ac2a-5b66a66b5967)]
interface nsIContentSecurityPolicy : nsISerializable
{
/**
@ -48,6 +48,7 @@ interface nsIContentSecurityPolicy : nsISerializable
const unsigned short BASE_URI_DIRECTIVE = 13;
const unsigned short FORM_ACTION_DIRECTIVE = 14;
const unsigned short REFERRER_DIRECTIVE = 15;
const unsigned short WEB_MANIFEST_SRC_DIRECTIVE = 16;
/**
* Accessor method for a read-only string version of the policy at a given

View File

@ -14,27 +14,33 @@
/*globals content, sendAsyncMessage, addMessageListener, Components*/
'use strict';
const {
utils: Cu
utils: Cu,
classes: Cc,
interfaces: Ci
} = Components;
const {
ManifestProcessor
} = Cu.import('resource://gre/modules/WebManifest.jsm', {});
const {
Task: {
spawn, async
}
} = Components.utils.import('resource://gre/modules/Task.jsm', {});
addMessageListener('DOM:ManifestObtainer:Obtain', (aMsg) => {
fetchManifest()
.then(
manifest => sendAsyncMessage('DOM:ManifestObtainer:Obtain', {
success: true,
result: manifest,
msgId: aMsg.data.msgId
}),
error => sendAsyncMessage('DOM:ManifestObtainer:Obtain', {
success: false,
result: cloneError(error),
msgId: aMsg.data.msgId
})
);
});
addMessageListener('DOM:ManifestObtainer:Obtain', async(function* (aMsg) {
const response = {
msgId: aMsg.data.msgId,
success: true,
result: undefined
};
try {
response.result = yield fetchManifest();
} catch (err) {
response.success = false;
response.result = cloneError(err);
}
sendAsyncMessage('DOM:ManifestObtainer:Obtain', response);
}));
function cloneError(aError) {
const clone = {
@ -49,19 +55,23 @@ function cloneError(aError) {
}
function fetchManifest() {
const manifestQuery = 'link[rel~="manifest"]';
return new Promise((resolve, reject) => {
return spawn(function* () {
if (!content || content.top !== content) {
let msg = 'Content window must be a top-level browsing context.';
return reject(new Error(msg));
throw new Error(msg);
}
const elem = content.document.querySelector(manifestQuery);
const elem = content.document.querySelector('link[rel~="manifest"]');
if (!elem || !elem.getAttribute('href')) {
let msg = 'No manifest to fetch.';
return reject(new Error(msg));
throw new Error(msg);
}
// Will throw on "about:blank" and possibly other invalid URIs.
// Throws on malformed URLs
const manifestURL = new content.URL(elem.href, elem.baseURI);
if (!canLoadManifest(elem)) {
let msg = `Content Security Policy: The page's settings blocked the `;
msg += `loading of a resource at ${elem.href}`;
throw new Error(msg);
}
const reqInit = {
mode: 'cors'
};
@ -70,34 +80,43 @@ function fetchManifest() {
}
const req = new content.Request(manifestURL, reqInit);
req.setContext('manifest');
content
.fetch(req)
.then(resp => processResponse(resp, content))
.then(resolve)
.catch(reject);
const response = yield content.fetch(req);
const manifest = yield processResponse(response, content);
return manifest;
});
}
function canLoadManifest(aElem) {
const contentPolicy = Cc['@mozilla.org/layout/content-policy;1']
.getService(Ci.nsIContentPolicy);
const mimeType = aElem.type || 'application/manifest+json';
const elemURI = BrowserUtils.makeURI(
aElem.href, aElem.ownerDocument.characterSet
);
const shouldLoad = contentPolicy.shouldLoad(
Ci.nsIContentPolicy.TYPE_WEB_MANIFEST, elemURI,
aElem.ownerDocument.documentURIObject,
aElem, mimeType, null
);
return shouldLoad === Ci.nsIContentPolicy.ACCEPT;
}
function processResponse(aResp, aContentWindow) {
const manifestURL = aResp.url;
return new Promise((resolve, reject) => {
return spawn(function* () {
const badStatus = aResp.status < 200 || aResp.status >= 300;
if (aResp.type === 'error' || badStatus) {
let msg =
`Fetch error: ${aResp.status} - ${aResp.statusText} at ${aResp.url}`;
return reject(new Error(msg));
throw new Error(msg);
}
aResp
.text()
.then((text) => {
const args = {
jsonText: text,
manifestURL: manifestURL,
docURL: aContentWindow.location.href
};
const processor = new ManifestProcessor();
const manifest = processor.process(args);
resolve(Cu.cloneInto(manifest, content));
}, reject);
const text = yield aResp.text();
const args = {
jsonText: text,
manifestURL: aResp.url,
docURL: aContentWindow.location.href
};
const processor = new ManifestProcessor();
const manifest = processor.process(args);
return Cu.cloneInto(manifest, content);
});
}

View File

@ -74,7 +74,14 @@ ManifestObtainer.prototype = {
});
function toError(aErrorClone) {
const error = new Error();
let error;
switch (aErrorClone.name) {
case 'TypeError':
error = new TypeError();
break;
default:
error = new Error();
}
Object.getOwnPropertyNames(aErrorClone)
.forEach(name => error[name] = aErrorClone[name]);
return error;

View File

@ -109,6 +109,51 @@ const tests = [
href='${remoteURL}?${body}&${CORS}'>`;
return link;
}
},{
expected: 'Trying to load from about:whatever is a TypeError.',
get tabURL() {
let query = [
`body=<h1>${this.expected}</h1>`,
'Content-Type=text/html; charset=utf-8',
];
const URL = `${defaultURL}?${query.join('&')}`;
return URL;
},
run(err) {
Assert.strictEqual(err.name, 'TypeError', this.expected);
},
testData: `<link rel="manifest" href='about:whatever'>`
},
{
expected: 'Trying to load from file://whatever is a TypeError.',
get tabURL() {
let query = [
`body=<h1>${this.expected}</h1>`,
'Content-Type=text/html; charset=utf-8',
];
const URL = `${defaultURL}?${query.join('&')}`;
return URL;
},
run(err) {
Assert.strictEqual(err.name, 'TypeError', this.expected);
},
testData: `<link rel="manifest" href='file://manifest'>`
},
//URL parsing tests
{
expected: 'Trying to load invalid URL is a TypeError.',
get tabURL() {
let query = [
`body=<h1>${this.expected}</h1>`,
'Content-Type=text/html; charset=utf-8',
];
const URL = `${defaultURL}?${query.join('&')}`;
return URL;
},
run(err) {
Assert.strictEqual(err.name, 'TypeError', this.expected);
},
testData: `<link rel="manifest" href='http://[12.1212.21.21.12.21.12]'>`
},
];

View File

@ -272,16 +272,18 @@ private:
* so that it may be called on the main thread. The error callback is also
* passed so it can be released correctly.
*/
class DeviceSuccessCallbackRunnable: public nsRunnable
class DeviceSuccessCallbackRunnable : public nsRunnable
{
public:
DeviceSuccessCallbackRunnable(
uint64_t aWindowID,
nsCOMPtr<nsIGetUserMediaDevicesSuccessCallback>& aOnSuccess,
nsCOMPtr<nsIDOMGetUserMediaErrorCallback>& aOnFailure,
nsTArray<nsRefPtr<MediaDevice>>* aDevices)
nsTArray<nsRefPtr<MediaDevice>>* aDevices,
bool aIsGum)
: mDevices(aDevices)
, mWindowID(aWindowID)
, mIsGum(aIsGum)
, mManager(MediaManager::GetInstance())
{
mOnSuccess.swap(aOnSuccess);
@ -358,38 +360,43 @@ public:
do_CreateInstance("@mozilla.org/variant;1");
size_t len = mDevices->Length();
if (len == 0) {
// XXX
// We should in the future return an empty array, and dynamically add
// devices to the dropdowns if things are hotplugged while the
// requester is up.
nsGlobalWindow* window = nsGlobalWindow::GetInnerWindowWithId(mWindowID);
if (window) {
nsRefPtr<MediaStreamError> error = new MediaStreamError(window,
NS_LITERAL_STRING("NotFoundError"));
mOnFailure->OnError(error);
if (!len) {
if (mIsGum) { // gUM fails on 0 devices whereas enumerateDevices doesn't.
// XXX
// We should in the future return an empty array, and dynamically add
// devices to the dropdowns if things are hotplugged while the
// requester is up.
nsGlobalWindow* window = nsGlobalWindow::GetInnerWindowWithId(mWindowID);
if (window) {
nsRefPtr<MediaStreamError> error = new MediaStreamError(window,
NS_LITERAL_STRING("NotFoundError"));
mOnFailure->OnError(error);
}
return NS_OK;
}
return NS_OK;
}
nsTArray<nsIMediaDevice*> tmp(len);
for (auto& device : *mDevices) {
if (!mOriginKey.IsEmpty()) {
nsString id;
device->GetId(id);
AnonymizeId(id, mOriginKey);
device->SetId(id);
devices->SetAsEmptyArray(); // SetAsArray() fails on zero length arrays.
} else {
nsTArray<nsIMediaDevice*> tmp(len);
for (auto& device : *mDevices) {
if (!mOriginKey.IsEmpty()) {
nsString id;
device->GetId(id);
AnonymizeId(id, mOriginKey);
device->SetId(id);
}
tmp.AppendElement(device);
}
nsresult rv = devices->SetAsArray(nsIDataType::VTYPE_INTERFACE,
&NS_GET_IID(nsIMediaDevice),
mDevices->Length(),
const_cast<void*>(
static_cast<const void*>(tmp.Elements())
));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
tmp.AppendElement(device);
}
devices->SetAsArray(nsIDataType::VTYPE_INTERFACE,
&NS_GET_IID(nsIMediaDevice),
mDevices->Length(),
const_cast<void*>(
static_cast<const void*>(tmp.Elements())
));
mOnSuccess->OnSuccess(devices);
return NS_OK;
}
@ -400,6 +407,7 @@ private:
nsCOMPtr<nsIDOMGetUserMediaErrorCallback> mOnFailure;
nsAutoPtr<nsTArray<nsRefPtr<MediaDevice>>> mDevices;
uint64_t mWindowID;
bool mIsGum;
nsRefPtr<MediaManager> mManager;
};
@ -1512,7 +1520,7 @@ public:
}
nsRefPtr<DeviceSuccessCallbackRunnable> runnable =
new DeviceSuccessCallbackRunnable(mWindowId, mOnSuccess, mOnFailure,
result.forget());
result.forget(), mPrivileged);
if (mPrivileged) {
NS_DispatchToMainThread(runnable);
} else {

View File

@ -403,12 +403,14 @@ GMPChild::RecvStartPlugin()
mGMPLoader = GMPProcessChild::GetGMPLoader();
if (!mGMPLoader) {
NS_WARNING("Failed to get GMPLoader");
delete platformAPI;
return false;
}
#if defined(MOZ_GMP_SANDBOX) && defined(XP_MACOSX)
if (!SetMacSandboxInfo()) {
NS_WARNING("Failed to set Mac GMP sandbox info");
delete platformAPI;
return false;
}
#endif
@ -419,6 +421,7 @@ GMPChild::RecvStartPlugin()
mNodeId.size(),
platformAPI)) {
NS_WARNING("Failed to load GMP");
delete platformAPI;
return false;
}

View File

@ -224,10 +224,14 @@ void GStreamerReader::ElementAddedCb(GstBin *aPlayBin,
GstElement *aElement,
gpointer aUserData)
{
const gchar *name =
gst_plugin_feature_get_name(GST_PLUGIN_FEATURE(gst_element_get_factory(aElement)));
GstElementFactory *factory = gst_element_get_factory(aElement);
if (!strcmp(name, "uridecodebin")) {
if (!factory)
return;
const gchar *name = gst_plugin_feature_get_name(GST_PLUGIN_FEATURE(factory));
if (name && !strcmp(name, "uridecodebin")) {
g_signal_connect(G_OBJECT(aElement), "autoplug-sort",
G_CALLBACK(GStreamerReader::ElementFilterCb), aUserData);
}

View File

@ -60,6 +60,9 @@ const kCHILD_PROCESS_MESSAGES = ["Push:Register", "Push:Unregister",
const kWS_MAX_WENTDOWN = 2;
// 1 minute is the least allowed ping interval
const kWS_MIN_PING_INTERVAL = 60000;
// This is a singleton
this.PushDB = function PushDB() {
debug("PushDB()");
@ -803,7 +806,11 @@ this.PushService = {
this._wsWentDownCounter = 0;
this._recalculatePing = true;
this._lastGoodPingInterval = Math.floor(lastTriedPingInterval / 2);
nextPingInterval = this._lastGoodPingInterval;
if (this._lastGoodPingInterval < kWS_MIN_PING_INTERVAL) {
nextPingInterval = kWS_MIN_PING_INTERVAL;
} else {
nextPingInterval = this._lastGoodPingInterval;
}
prefs.set('pingInterval', nextPingInterval);
this._save(ns, nextPingInterval);
return;

View File

@ -149,6 +149,9 @@ CSP_ContentTypeToDirective(nsContentPolicyType aType)
case nsIContentPolicy::TYPE_MEDIA:
return nsIContentSecurityPolicy::MEDIA_SRC_DIRECTIVE;
case nsIContentPolicy::TYPE_WEB_MANIFEST:
return nsIContentSecurityPolicy::WEB_MANIFEST_SRC_DIRECTIVE;
case nsIContentPolicy::TYPE_SUBDOCUMENT:
return nsIContentSecurityPolicy::FRAME_SRC_DIRECTIVE;
@ -836,6 +839,10 @@ nsCSPDirective::toDomCSPStruct(mozilla::dom::CSP& outCSP) const
outCSP.mFrame_ancestors.Value() = srcs;
return;
case nsIContentSecurityPolicy::WEB_MANIFEST_SRC_DIRECTIVE:
outCSP.mManifest_src.Construct();
outCSP.mManifest_src.Value() = srcs;
return;
// not supporting REFLECTED_XSS_DIRECTIVE
case nsIContentSecurityPolicy::BASE_URI_DIRECTIVE:

View File

@ -64,8 +64,11 @@ void CSP_LogMessage(const nsAString& aMessage,
// these strings map to the CSPDirectives in nsIContentSecurityPolicy
// NOTE: When implementing a new directive, you will need to add it here but also
// add a corresponding entry to the constants in nsIContentSecurityPolicy.idl and
// also create an entry for the new directive in nsCSPDirective::toDomCSPStruct().
// add a corresponding entry to the constants in nsIContentSecurityPolicy.idl
// and also create an entry for the new directive in
// nsCSPDirective::toDomCSPStruct() and add it to CSPDictionaries.webidl.
// Order of elements below important! Make sure it matches the order as in
// nsIContentSecurityPolicy.idl
static const char* CSPStrDirectives[] = {
"-error-", // NO_DIRECTIVE
"default-src", // DEFAULT_SRC_DIRECTIVE
@ -82,7 +85,8 @@ static const char* CSPStrDirectives[] = {
"reflected-xss", // REFLECTED_XSS_DIRECTIVE
"base-uri", // BASE_URI_DIRECTIVE
"form-action", // FORM_ACTION_DIRECTIVE
"referrer" // REFERRER_DIRECTIVE
"referrer", // REFERRER_DIRECTIVE
"manifest-src" // MANIFEST_SRC_DIRECTIVE
};
inline const char* CSP_CSPDirectiveToString(CSPDirective aDir)

View File

@ -439,6 +439,7 @@ nsMixedContentBlocker::ShouldLoad(bool aHadInsecureImageRedirect,
case TYPE_SCRIPT:
case TYPE_STYLESHEET:
case TYPE_SUBDOCUMENT:
case TYPE_WEB_MANIFEST:
case TYPE_XBL:
case TYPE_XMLHTTPREQUEST:
case TYPE_XSLT:

View File

@ -24,6 +24,7 @@ dictionary CSP {
sequence<DOMString> base-uri;
sequence<DOMString> form-action;
sequence<DOMString> referrer;
sequence<DOMString> manifest-src;
};
dictionary CSPPolicies {

View File

@ -66,6 +66,9 @@ partial interface Selection {
[ChromeOnly,Throws]
attribute boolean interlinePosition;
[Throws]
attribute short? caretBidiLevel;
[ChromeOnly,Throws]
DOMString toStringWithFormat(DOMString formatType, unsigned long flags, long wrapColumn);
[ChromeOnly,Throws]

View File

@ -1049,21 +1049,22 @@ ServiceWorkerManager::Register(nsIDOMWindow* aWindow,
{
AssertIsOnMainThread();
// XXXnsm Don't allow chrome callers for now, we don't support chrome
// ServiceWorkers.
MOZ_ASSERT(!nsContentUtils::IsCallerChrome());
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aWindow);
nsCOMPtr<nsPIDOMWindow> outerWindow = window->GetOuterWindow();
bool serviceWorkersTestingEnabled =
outerWindow->GetServiceWorkersTestingEnabled();
MOZ_ASSERT(window);
nsCOMPtr<nsIDocument> doc = window->GetExtantDoc();
if (!doc) {
return NS_ERROR_FAILURE;
}
// Don't allow service workers to register when the *document* is chrome for
// now.
MOZ_ASSERT(!nsContentUtils::IsSystemPrincipal(doc->NodePrincipal()));
nsCOMPtr<nsPIDOMWindow> outerWindow = window->GetOuterWindow();
bool serviceWorkersTestingEnabled =
outerWindow->GetServiceWorkersTestingEnabled();
nsCOMPtr<nsIURI> documentURI = doc->GetBaseURI();
bool authenticatedOrigin = false;
@ -1474,15 +1475,18 @@ ServiceWorkerManager::GetRegistrations(nsIDOMWindow* aWindow,
AssertIsOnMainThread();
MOZ_ASSERT(aWindow);
// XXXnsm Don't allow chrome callers for now, we don't support chrome
// ServiceWorkers.
MOZ_ASSERT(!nsContentUtils::IsCallerChrome());
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aWindow);
if (!window) {
MOZ_ASSERT(window);
nsCOMPtr<nsIDocument> doc = window->GetExtantDoc();
if (!doc) {
return NS_ERROR_FAILURE;
}
// Don't allow service workers to register when the *document* is chrome for
// now.
MOZ_ASSERT(!nsContentUtils::IsSystemPrincipal(doc->NodePrincipal()));
nsCOMPtr<nsIGlobalObject> sgo = do_QueryInterface(window);
ErrorResult result;
nsRefPtr<Promise> promise = Promise::Create(sgo, result);
@ -1575,15 +1579,18 @@ ServiceWorkerManager::GetRegistration(nsIDOMWindow* aWindow,
AssertIsOnMainThread();
MOZ_ASSERT(aWindow);
// XXXnsm Don't allow chrome callers for now, we don't support chrome
// ServiceWorkers.
MOZ_ASSERT(!nsContentUtils::IsCallerChrome());
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aWindow);
if (!window) {
MOZ_ASSERT(window);
nsCOMPtr<nsIDocument> doc = window->GetExtantDoc();
if (!doc) {
return NS_ERROR_FAILURE;
}
// Don't allow service workers to register when the *document* is chrome for
// now.
MOZ_ASSERT(!nsContentUtils::IsSystemPrincipal(doc->NodePrincipal()));
nsCOMPtr<nsIGlobalObject> sgo = do_QueryInterface(window);
ErrorResult result;
nsRefPtr<Promise> promise = Promise::Create(sgo, result);
@ -1784,15 +1791,18 @@ ServiceWorkerManager::GetReadyPromise(nsIDOMWindow* aWindow,
AssertIsOnMainThread();
MOZ_ASSERT(aWindow);
// XXXnsm Don't allow chrome callers for now, we don't support chrome
// ServiceWorkers.
MOZ_ASSERT(!nsContentUtils::IsCallerChrome());
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aWindow);
if (!window) {
MOZ_ASSERT(window);
nsCOMPtr<nsIDocument> doc = window->GetExtantDoc();
if (!doc) {
return NS_ERROR_FAILURE;
}
// Don't allow service workers to register when the *document* is chrome for
// now.
MOZ_ASSERT(!nsContentUtils::IsSystemPrincipal(doc->NodePrincipal()));
MOZ_ASSERT(!mPendingReadyPromises.Contains(window));
nsCOMPtr<nsIGlobalObject> sgo = do_QueryInterface(window);

View File

@ -614,11 +614,13 @@ nsHTMLEditRules::WillDoAction(Selection* aSelection,
switch (info->action) {
case EditAction::insertText:
case EditAction::insertIMEText:
UndefineCaretBidiLevel(aSelection);
return WillInsertText(info->action, aSelection, aCancel, aHandled,
info->inString, info->outString, info->maxLength);
case EditAction::loadHTML:
return WillLoadHTML(aSelection, aCancel);
case EditAction::insertBreak:
UndefineCaretBidiLevel(aSelection);
return WillInsertBreak(aSelection, aCancel, aHandled);
case EditAction::deleteSelection:
return WillDeleteSelection(aSelection, info->collapsedAction,

View File

@ -252,9 +252,11 @@ nsTextEditRules::WillDoAction(Selection* aSelection,
switch (info->action) {
case EditAction::insertBreak:
UndefineCaretBidiLevel(aSelection);
return WillInsertBreak(aSelection, aCancel, aHandled, info->maxLength);
case EditAction::insertText:
case EditAction::insertIMEText:
UndefineCaretBidiLevel(aSelection);
return WillInsertText(info->action, aSelection, aCancel, aHandled,
info->inString, info->outString, info->maxLength);
case EditAction::deleteSelection:

View File

@ -193,6 +193,8 @@ protected:
nsresult CreateMozBR(nsIDOMNode* inParent, int32_t inOffset,
nsIDOMNode** outBRNode = nullptr);
void UndefineCaretBidiLevel(Selection* aSelection);
nsresult CheckBidiLevelForDeletion(mozilla::dom::Selection* aSelection,
nsIDOMNode *aSelNode,
int32_t aSelOffset,

View File

@ -80,3 +80,19 @@ nsTextEditRules::CheckBidiLevelForDeletion(Selection* aSelection,
return NS_OK;
}
void
nsTextEditRules::UndefineCaretBidiLevel(Selection* aSelection)
{
/**
* After inserting text the caret Bidi level must be set to the level of the
* inserted text.This is difficult, because we cannot know what the level is
* until after the Bidi algorithm is applied to the whole paragraph.
*
* So we set the caret Bidi level to UNDEFINED here, and the caret code will
* set it correctly later
*/
nsRefPtr<nsFrameSelection> frameSelection = aSelection->GetFrameSelection();
if (frameSelection) {
frameSelection->UndefineCaretBidiLevel();
}
}

View File

@ -39,7 +39,11 @@ static const char *kTypeString[] = {"other",
"media",
"websocket",
"csp_report",
"xslt"};
"xslt",
"beacon",
"fetch",
"imageset",
"manifest"};
#define NUMBER_OF_TYPES MOZ_ARRAY_LENGTH(kTypeString)
uint8_t nsContentBlocker::mBehaviorPref[NUMBER_OF_TYPES];

View File

@ -549,8 +549,8 @@ FilterNodeD2D1::Create(ID2D1DeviceContext *aDC, FilterType aType)
hr = aDC->CreateEffect(GetCLDIDForFilterType(aType), byRef(effect));
if (FAILED(hr)) {
gfxWarning() << "Failed to create effect for FilterType: " << hexa(hr);
if (FAILED(hr) || !effect) {
gfxCriticalErrorOnce() << "Failed to create effect for FilterType: " << hexa(hr);
return nullptr;
}

View File

@ -227,6 +227,81 @@ Rect Matrix4x4::ProjectRectBounds(const Rect& aRect, const Rect &aClip) const
return Rect(min_x, min_y, max_x - min_x, max_y - min_y);
}
size_t
Matrix4x4::TransformAndClipRect(const Rect& aRect, const Rect& aClip,
Point* aVerts) const
{
// Initialize a double-buffered array of points in homogenous space with
// the input rectangle, aRect.
Point4D points[2][kTransformAndClipRectMaxVerts];
Point4D* dstPoint = points[0];
*dstPoint++ = *this * Point4D(aRect.x, aRect.y, 0, 1);
*dstPoint++ = *this * Point4D(aRect.XMost(), aRect.y, 0, 1);
*dstPoint++ = *this * Point4D(aRect.XMost(), aRect.YMost(), 0, 1);
*dstPoint++ = *this * Point4D(aRect.x, aRect.YMost(), 0, 1);
// View frustum clipping planes are described as normals originating from
// the 0,0,0,0 origin.
Point4D planeNormals[4];
planeNormals[0] = Point4D(1.0, 0.0, 0.0, -aClip.x);
planeNormals[1] = Point4D(-1.0, 0.0, 0.0, aClip.XMost());
planeNormals[2] = Point4D(0.0, 1.0, 0.0, -aClip.y);
planeNormals[3] = Point4D(0.0, -1.0, 0.0, aClip.YMost());
// Iterate through each clipping plane and clip the polygon.
// In each pass, we double buffer, alternating between points[0] and
// points[1].
for (int plane=0; plane < 4; plane++) {
planeNormals[plane].Normalize();
Point4D* srcPoint = points[plane & 1];
Point4D* srcPointEnd = dstPoint;
dstPoint = points[~plane & 1];
Point4D* prevPoint = srcPointEnd - 1;
float prevDot = planeNormals[plane].DotProduct(*prevPoint);
while (srcPoint < srcPointEnd) {
float nextDot = planeNormals[plane].DotProduct(*srcPoint);
if ((nextDot >= 0.0) != (prevDot >= 0.0)) {
// An intersection with the clipping plane has been detected.
// Interpolate to find the intersecting point and emit it.
float t = -prevDot / (nextDot - prevDot);
*dstPoint++ = *srcPoint * t + *prevPoint * (1.0 - t);
}
if (nextDot >= 0.0) {
// Emit any source points that are on the positive side of the
// clipping plane.
*dstPoint++ = *srcPoint;
}
prevPoint = srcPoint++;
prevDot = nextDot;
}
}
size_t dstPointCount = 0;
size_t srcPointCount = dstPoint - points[0];
for (Point4D* srcPoint = points[0]; srcPoint < points[0] + srcPointCount; srcPoint++) {
Point p;
if (srcPoint->w == 0.0) {
// If a point lies on the intersection of the clipping planes at
// (0,0,0,0), we must avoid a division by zero w component.
p = Point(0.0, 0.0);
} else {
p = srcPoint->As2DPoint();
}
// Emit only unique points
if (dstPointCount == 0 || p != aVerts[dstPointCount - 1]) {
aVerts[dstPointCount++] = p;
}
}
return dstPointCount;
}
bool
Matrix4x4::Invert()
{

View File

@ -499,6 +499,19 @@ public:
Rect ProjectRectBounds(const Rect& aRect, const Rect &aClip) const;
/**
* TransformAndClipRect projects a rectangle and clips against view frustum
* clipping planes in homogenous space so that its projected vertices are
* constrained within the 2d rectangle passed in aClip.
* The resulting vertices are populated in aVerts. aVerts must be
* pre-allocated to hold at least kTransformAndClipRectMaxVerts Points.
* The vertex count is returned by TransformAndClipRect. It is possible to
* emit fewer that 3 vertices, indicating that aRect will not be visible
* within aClip.
*/
size_t TransformAndClipRect(const Rect& aRect, const Rect& aClip, Point* aVerts) const;
static const size_t kTransformAndClipRectMaxVerts = 32;
static Matrix4x4 From2D(const Matrix &aMatrix) {
Matrix4x4 matrix;
matrix._11 = aMatrix._11;

View File

@ -297,10 +297,24 @@ public:
* drawn is specified by aEffectChain. aRect is the quad to draw, in user space.
* aTransform transforms from user space to screen space. If texture coords are
* required, these will be in the primary effect in the effect chain.
* aVisibleRect is used to determine which edges should be antialiased,
* without applying the effect to the inner edges of a tiled layer.
*/
virtual void DrawQuad(const gfx::Rect& aRect, const gfx::Rect& aClipRect,
const EffectChain& aEffectChain,
gfx::Float aOpacity, const gfx::Matrix4x4 &aTransform) = 0;
gfx::Float aOpacity, const gfx::Matrix4x4& aTransform,
const gfx::Rect& aVisibleRect) = 0;
/**
* Overload of DrawQuad, with aVisibleRect defaulted to the value of aRect.
* Use this when you are drawing a single quad that is not part of a tiled
* layer.
*/
void DrawQuad(const gfx::Rect& aRect, const gfx::Rect& aClipRect,
const EffectChain& aEffectChain,
gfx::Float aOpacity, const gfx::Matrix4x4& aTransform) {
DrawQuad(aRect, aClipRect, aEffectChain, aOpacity, aTransform, aRect);
}
/*
* Clear aRect on current render target.

View File

@ -178,37 +178,141 @@ private:
nsCOMPtr<nsIServerSocket> mServerSocket;
};
// Static class to create and destory LayerScopeWebSocketManager object
class WebSocketHelper
class DrawSession {
public:
DrawSession()
: mOffsetX(0.0)
, mOffsetY(0.0)
, mRects(0)
{ }
float mOffsetX;
float mOffsetY;
gfx::Matrix4x4 mMVMatrix;
size_t mRects;
gfx::Rect mLayerRects[4];
};
class ContentMonitor {
public:
using THArray = nsTArray<const TextureHost *>;
// Notify the content of a TextureHost was changed.
void SetChangedHost(const TextureHost* host) {
if (THArray::NoIndex == mChangedHosts.IndexOf(host)) {
mChangedHosts.AppendElement(host);
}
}
// Clear changed flag of a host.
void ClearChangedHost(const TextureHost* host) {
if (THArray::NoIndex != mChangedHosts.IndexOf(host)) {
mChangedHosts.RemoveElement(host);
}
}
// Return true iff host is a new one or the content of it had been changed.
bool IsChangedOrNew(const TextureHost* host) {
if (THArray::NoIndex == mSeenHosts.IndexOf(host)) {
mSeenHosts.AppendElement(host);
return true;
}
if (decltype(mChangedHosts)::NoIndex != mChangedHosts.IndexOf(host)) {
return true;
}
return false;
}
void Empty() {
mSeenHosts.SetLength(0);
mChangedHosts.SetLength(0);
}
private:
THArray mSeenHosts;
THArray mChangedHosts;
};
// Hold all singleton objects used by LayerScope
class LayerScopeManager
{
public:
static void CreateServerSocket()
void CreateServerSocket()
{
// Create Web Server Socket (which has to be on the main thread)
MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
if (!sWebSocketManager) {
sWebSocketManager = new LayerScopeWebSocketManager();
// WebSocketManager must be created on the main thread.
if (NS_IsMainThread()) {
mWebSocketManager = mozilla::MakeUnique<LayerScopeWebSocketManager>();
} else {
// Dispatch creation to main thread, and make sure we
// dispatch this only once after booting
static bool dispatched = false;
if (dispatched) {
return;
}
DebugOnly<nsresult> rv =
NS_DispatchToMainThread(new CreateServerSocketRunnable(this));
MOZ_ASSERT(NS_SUCCEEDED(rv),
"Failed to dispatch WebSocket Creation to main thread");
dispatched = true;
}
}
static void DestroyServerSocket()
void DestroyServerSocket()
{
// Destroy Web Server Socket
if (sWebSocketManager) {
sWebSocketManager->RemoveAllConnections();
if (mWebSocketManager) {
mWebSocketManager->RemoveAllConnections();
}
}
static LayerScopeWebSocketManager* GetSocketManager()
LayerScopeWebSocketManager* GetSocketManager()
{
return sWebSocketManager;
return mWebSocketManager.get();
}
ContentMonitor* GetContentMonitor()
{
if (!mContentMonitor.get()) {
mContentMonitor = mozilla::MakeUnique<ContentMonitor>();
}
return mContentMonitor.get();
}
void NewDrawSession() {
mSession = mozilla::MakeUnique<DrawSession>();
}
DrawSession& CurrentSession() {
return *mSession;
}
private:
static StaticAutoPtr<LayerScopeWebSocketManager> sWebSocketManager;
friend class CreateServerSocketRunnable;
class CreateServerSocketRunnable : public nsRunnable
{
public:
explicit CreateServerSocketRunnable(LayerScopeManager *aLayerScopeManager)
: mLayerScopeManager(aLayerScopeManager)
{
}
NS_IMETHOD Run() {
mLayerScopeManager->mWebSocketManager =
mozilla::MakeUnique<LayerScopeWebSocketManager>();
return NS_OK;
}
private:
LayerScopeManager* mLayerScopeManager;
};
mozilla::UniquePtr<LayerScopeWebSocketManager> mWebSocketManager;
mozilla::UniquePtr<DrawSession> mSession;
mozilla::UniquePtr<ContentMonitor> mContentMonitor;
};
StaticAutoPtr<LayerScopeWebSocketManager> WebSocketHelper::sWebSocketManager;
LayerScopeManager gLayerScopeManager;
/*
* DebugGLData is the base class of
@ -230,13 +334,13 @@ public:
protected:
static bool WriteToStream(Packet& aPacket) {
if (!WebSocketHelper::GetSocketManager())
if (!gLayerScopeManager.GetSocketManager())
return true;
uint32_t size = aPacket.ByteSize();
auto data = MakeUnique<uint8_t[]>(size);
aPacket.SerializeToArray(data.get(), size);
return WebSocketHelper::GetSocketManager()->WriteAll(data.get(), size);
return gLayerScopeManager.GetSocketManager()->WriteAll(data.get(), size);
}
Packet::DataType mDataType;
@ -290,7 +394,7 @@ public:
return WriteToStream(mPacket);
}
bool TryPack() {
bool TryPack(bool packData) {
android::sp<android::GraphicBuffer> buffer = mState.mSurface;
MOZ_ASSERT(buffer.get());
@ -300,16 +404,9 @@ public:
tp->set_name(mName);
tp->set_target(mTarget);
int format = buffer->getPixelFormat();
if (HAL_PIXEL_FORMAT_RGBA_8888 != format &&
HAL_PIXEL_FORMAT_RGBX_8888 != format) {
return false;
}
uint8_t* grallocData;
if (BAD_VALUE == buffer->lock(GRALLOC_USAGE_SW_READ_OFTEN |
GRALLOC_USAGE_SW_WRITE_NEVER,
reinterpret_cast<void**>(&grallocData))) {
int pFormat = buffer->getPixelFormat();
if (HAL_PIXEL_FORMAT_RGBA_8888 != pFormat &&
HAL_PIXEL_FORMAT_RGBX_8888 != pFormat) {
return false;
}
@ -317,29 +414,44 @@ public:
int32_t height = buffer->getHeight();
int32_t width = buffer->getWidth();
int32_t sourceSize = stride * height;
bool ret = false;
if (sourceSize <= 0) {
return false;
}
if (sourceSize > 0) {
auto compressedData = MakeUnique<char[]>(LZ4::maxCompressedSize(sourceSize));
uint32_t dFormat = mState.FormatRBSwapped() ?
LOCAL_GL_BGRA : LOCAL_GL_RGBA;
tp->set_dataformat(dFormat);
tp->set_dataformat((1 << 16 | tp->dataformat()));
tp->set_width(width);
tp->set_height(height);
tp->set_stride(stride);
if (packData) {
uint8_t* grallocData = nullptr;
if (BAD_VALUE == buffer->lock(GRALLOC_USAGE_SW_READ_OFTEN |
GRALLOC_USAGE_SW_WRITE_NEVER,
reinterpret_cast<void**>(&grallocData)))
{
return false;
}
// Do not return before buffer->unlock();
auto compressedData =
MakeUnique<char[]>(LZ4::maxCompressedSize(sourceSize));
int compressedSize = LZ4::compress((char*)grallocData,
sourceSize,
compressedData.get());
if (compressedSize > 0) {
uint32_t format = mState.FormatRBSwapped() ?
LOCAL_GL_BGRA : LOCAL_GL_RGBA;
tp->set_dataformat(format);
tp->set_dataformat((1 << 16 | tp->dataformat()));
tp->set_width(width);
tp->set_height(height);
tp->set_stride(stride);
tp->set_data(compressedData.get(), compressedSize);
ret = true;
}
} else {
buffer->unlock();
return false;
}
buffer->unlock();
}
buffer->unlock();
return ret;
return true;
}
private:
@ -576,11 +688,12 @@ public:
NS_IMETHODIMP OnSocketAccepted(nsIServerSocket *aServ,
nsISocketTransport *aTransport) override
{
if (!WebSocketHelper::GetSocketManager())
if (!gLayerScopeManager.GetSocketManager())
return NS_OK;
printf_stderr("*** LayerScope: Accepted connection\n");
WebSocketHelper::GetSocketManager()->AddConnection(aTransport);
gLayerScopeManager.GetSocketManager()->AddConnection(aTransport);
gLayerScopeManager.GetContentMonitor()->Empty();
return NS_OK;
}
@ -619,8 +732,6 @@ public:
delete d;
}
/* nsIRunnable impl; send the data */
NS_IMETHODIMP Run() override {
DebugGLData *d;
nsresult rv = NS_OK;
@ -636,7 +747,7 @@ public:
Cleanup();
if (NS_FAILED(rv)) {
WebSocketHelper::DestroyServerSocket();
gLayerScopeManager.DestroyServerSocket();
}
return NS_OK;
@ -649,15 +760,6 @@ protected:
NS_IMPL_ISUPPORTS(DebugDataSender, nsIRunnable);
class CreateServerSocketRunnable : public nsRunnable
{
public:
NS_IMETHOD Run() {
WebSocketHelper::CreateServerSocket();
return NS_OK;
}
};
/*
* LayerScope SendXXX Structure
* 1. SendLayer
@ -799,7 +901,7 @@ SenderHelper::SendColor(void* aLayerRef,
int aWidth,
int aHeight)
{
WebSocketHelper::GetSocketManager()->AppendDebugData(
gLayerScopeManager.GetSocketManager()->AppendDebugData(
new DebugGLColorData(aLayerRef, aColor, aWidth, aHeight));
}
@ -848,7 +950,7 @@ SenderHelper::SendTextureSource(GLContext* aGLContext,
aGLContext->ReadTexImageHelper()->ReadTexImage(0, textureTarget,
size,
shaderConfig, aFlipY);
WebSocketHelper::GetSocketManager()->AppendDebugData(
gLayerScopeManager.GetSocketManager()->AppendDebugData(
new DebugGLTextureData(aGLContext, aLayerRef, textureTarget,
aTexID, img));
@ -869,13 +971,19 @@ SenderHelper::SendGraphicBuffer(void* aLayerRef,
mozilla::UniquePtr<DebugGLGraphicBuffer> package =
MakeUnique<DebugGLGraphicBuffer>(aLayerRef, target, aTexID, aEffect->mState);
if (!package->TryPack()) {
// The texure content in this TexureHost is not altered,
// we don't need to send it again.
bool changed = gLayerScopeManager.GetContentMonitor()->IsChangedOrNew(
aEffect->mState.mTexture);
if (!package->TryPack(changed)) {
return false;
}
// Transfer ownership to SocketManager.
WebSocketHelper::GetSocketManager()->AppendDebugData(package.release());
gLayerScopeManager.GetSocketManager()->AppendDebugData(package.release());
sTextureIdList.push_back(aTexID);
gLayerScopeManager.GetContentMonitor()->ClearChangedHost(aEffect->mState.mTexture);
return true;
}
#endif
@ -897,9 +1005,10 @@ SenderHelper::SendTexturedEffect(GLContext* aGLContext,
#ifdef MOZ_WIDGET_GONK
if (SendGraphicBuffer(aLayerRef, source, texID, aEffect)) {
return;
return;
}
#endif
// Fallback texture sending path.
// Render to texture and read pixels back.
SendTextureSource(aGLContext, aLayerRef, source, texID, false);
}
@ -976,6 +1085,16 @@ SenderHelper::SendEffectChain(GLContext* aGLContext,
// TODO:
}
void
LayerScope::ContentChanged(TextureHost *host)
{
if (!CheckSendable()) {
return;
}
gLayerScopeManager.GetContentMonitor()->SetChangedHost(host);
}
// ----------------------------------------------
// LayerScopeWebSocketHandler implementation
// ----------------------------------------------
@ -1383,7 +1502,7 @@ LayerScopeWebSocketHandler::HandleDataFrame(uint8_t *aData,
void
LayerScopeWebSocketHandler::CloseConnection()
{
WebSocketHelper::GetSocketManager()->CleanDebugData();
gLayerScopeManager.GetSocketManager()->CleanDebugData();
if (mInputStream) {
mInputStream->AsyncWait(nullptr, 0, 0, nullptr);
mInputStream = nullptr;
@ -1453,56 +1572,9 @@ LayerScope::Init()
return;
}
if (NS_IsMainThread()) {
WebSocketHelper::CreateServerSocket();
} else {
// Dispatch creation to main thread, and make sure we
// dispatch this only once after booting
static bool dispatched = false;
if (dispatched) {
return;
}
DebugOnly<nsresult> rv = NS_DispatchToMainThread(new CreateServerSocketRunnable());
MOZ_ASSERT(NS_SUCCEEDED(rv), "Failed to dispatch WebSocket Creation to main thread");
dispatched = true;
}
gLayerScopeManager.CreateServerSocket();
}
class DrawSession {
public:
NS_INLINE_DECL_REFCOUNTING(DrawSession)
DrawSession()
: mOffsetX(0.0),
mOffsetY(0.0),
mRects(0)
{ }
float mOffsetX;
float mOffsetY;
gfx::Matrix4x4 mMVMatrix;
size_t mRects;
gfx::Rect mLayerRects[4];
private:
~DrawSession() {}
};
class DrawSessionHolder {
public:
static void setSession(DrawSession *aSession) {
mSession = aSession;
}
static DrawSession& current() {
return *mSession;
}
private:
static nsRefPtr<DrawSession> mSession;
};
nsRefPtr<DrawSession> DrawSessionHolder::mSession;
void
LayerScope::DrawBegin()
{
@ -1510,7 +1582,7 @@ LayerScope::DrawBegin()
return;
}
DrawSessionHolder::setSession(new DrawSession());
gLayerScopeManager.NewDrawSession();
}
void LayerScope::SetRenderOffset(float aX, float aY)
@ -1519,8 +1591,8 @@ void LayerScope::SetRenderOffset(float aX, float aY)
return;
}
DrawSessionHolder::current().mOffsetX = aX;
DrawSessionHolder::current().mOffsetY = aY;
gLayerScopeManager.CurrentSession().mOffsetX = aX;
gLayerScopeManager.CurrentSession().mOffsetY = aY;
}
void LayerScope::SetLayerTransform(const gfx::Matrix4x4& aMatrix)
@ -1529,7 +1601,7 @@ void LayerScope::SetLayerTransform(const gfx::Matrix4x4& aMatrix)
return;
}
DrawSessionHolder::current().mMVMatrix = aMatrix;
gLayerScopeManager.CurrentSession().mMVMatrix = aMatrix;
}
void LayerScope::SetLayerRects(size_t aRects, const gfx::Rect* aLayerRects)
@ -1541,10 +1613,10 @@ void LayerScope::SetLayerRects(size_t aRects, const gfx::Rect* aLayerRects)
MOZ_ASSERT(aRects > 0 && aRects <= 4);
MOZ_ASSERT(aLayerRects);
DrawSessionHolder::current().mRects = aRects;
gLayerScopeManager.CurrentSession().mRects = aRects;
for (size_t i = 0; i < aRects; i++){
DrawSessionHolder::current().mLayerRects[i] = aLayerRects[i];
gLayerScopeManager.CurrentSession().mLayerRects[i] = aLayerRects[i];
}
}
@ -1561,8 +1633,8 @@ LayerScope::DrawEnd(gl::GLContext* aGLContext,
// 1. Send parameters of draw call, such as uniforms and attributes of
// vertex adnd fragment shader.
DrawSession& draws = DrawSessionHolder::current();
WebSocketHelper::GetSocketManager()->AppendDebugData(
DrawSession& draws = gLayerScopeManager.CurrentSession();
gLayerScopeManager.GetSocketManager()->AppendDebugData(
new DebugGLDrawData(draws.mOffsetX, draws.mOffsetY,
draws.mMVMatrix, draws.mRects,
draws.mLayerRects,
@ -1591,7 +1663,7 @@ LayerScope::SendLayerDump(UniquePtr<Packet> aPacket)
if (!CheckSendable() || !SenderHelper::GetLayersTreeSendable()) {
return;
}
WebSocketHelper::GetSocketManager()->AppendDebugData(
gLayerScopeManager.GetSocketManager()->AppendDebugData(
new DebugGLLayersData(Move(aPacket)));
}
@ -1604,11 +1676,11 @@ LayerScope::CheckSendable()
if (!gfxPrefs::LayerScopeEnabled()) {
return false;
}
if (!WebSocketHelper::GetSocketManager()) {
if (!gLayerScopeManager.GetSocketManager()) {
Init();
return false;
}
if (!WebSocketHelper::GetSocketManager()->IsConnected()) {
if (!gLayerScopeManager.GetSocketManager()->IsConnected()) {
return false;
}
return true;
@ -1618,7 +1690,7 @@ void
LayerScope::CleanLayer()
{
if (CheckSendable()) {
WebSocketHelper::GetSocketManager()->CleanDebugData();
gLayerScopeManager.GetSocketManager()->CleanDebugData();
}
}
@ -1626,7 +1698,7 @@ void
LayerScope::SetHWComposed()
{
if (CheckSendable()) {
WebSocketHelper::GetSocketManager()->AppendDebugData(
gLayerScopeManager.GetSocketManager()->AppendDebugData(
new DebugGLMetaData(Packet::META, true));
}
}
@ -1655,7 +1727,7 @@ LayerScopeAutoFrame::BeginFrame(int64_t aFrameStamp)
return;
}
WebSocketHelper::GetSocketManager()->AppendDebugData(
gLayerScopeManager.GetSocketManager()->AppendDebugData(
new DebugGLFrameStatusData(Packet::FRAMESTART, aFrameStamp));
}
@ -1666,9 +1738,9 @@ LayerScopeAutoFrame::EndFrame()
return;
}
WebSocketHelper::GetSocketManager()->AppendDebugData(
gLayerScopeManager.GetSocketManager()->AppendDebugData(
new DebugGLFrameStatusData(Packet::FRAMEEND));
WebSocketHelper::GetSocketManager()->DispatchDebugData();
gLayerScopeManager.GetSocketManager()->DispatchDebugData();
}
} /* layers */

View File

@ -40,6 +40,7 @@ public:
static void CleanLayer();
static void SetHWComposed();
static void ContentChanged(TextureHost *host);
private:
static void Init();
};

View File

@ -297,7 +297,7 @@ DIBTextureHost::DIBTextureHost(TextureFlags aFlags,
}
void
DIBTextureHost::Updated(const nsIntRegion* aRegion)
DIBTextureHost::UpdatedInternal(const nsIntRegion* aRegion)
{
if (!mCompositor) {
// This can happen if we send textures to a compositable that isn't yet
@ -331,7 +331,7 @@ TextureHostFileMapping::~TextureHostFileMapping()
}
void
TextureHostFileMapping::Updated(const nsIntRegion* aRegion)
TextureHostFileMapping::UpdatedInternal(const nsIntRegion* aRegion)
{
if (!mCompositor) {
// This can happen if we send textures to a compositable that isn't yet

View File

@ -155,14 +155,14 @@ public:
DIBTextureHost(TextureFlags aFlags,
const SurfaceDescriptorDIB& aDescriptor);
virtual void Updated(const nsIntRegion* aRegion = nullptr) override;
virtual TemporaryRef<gfx::DataSourceSurface> GetAsSurface() override
{
return nullptr; // TODO: cf bug 872568
}
protected:
virtual void UpdatedInternal(const nsIntRegion* aRegion = nullptr) override;
nsRefPtr<gfxWindowsSurface> mSurface;
};
@ -173,8 +173,6 @@ public:
const SurfaceDescriptorFileMapping& aDescriptor);
~TextureHostFileMapping();
virtual void Updated(const nsIntRegion* aRegion = nullptr) override;
virtual TemporaryRef<gfx::DataSourceSurface> GetAsSurface() override
{
MOZ_CRASH(); // Not implemented! It would be tricky to keep track of the
@ -183,6 +181,8 @@ public:
}
protected:
virtual void UpdatedInternal(const nsIntRegion* aRegion = nullptr) override;
HANDLE mFileMapping;
};

View File

@ -541,7 +541,7 @@ TiledLayerBuffer<Derived, Tile>::Update(const nsIntRegion& newValidRegion,
#ifdef DEBUG
int currTileX = floor_div(x - newBufferOrigin.x, scaledTileSize.width);
int currTileY = floor_div(y - newBufferOrigin.y, scaledTileSize.height);
int index = currTileX * mRetainedHeight + currTileY;
int index = TileIndex(currTileX, currTileY);
// If allocating a tile failed we can run into this assertion.
// Rendering is going to be glitchy but we don't want to crash.
NS_ASSERTION(!newValidRegion.Intersects(tileRect) ||
@ -556,7 +556,7 @@ TiledLayerBuffer<Derived, Tile>::Update(const nsIntRegion& newValidRegion,
int tileX = floor_div(x - newBufferOrigin.x, scaledTileSize.width);
int tileY = floor_div(y - newBufferOrigin.y, scaledTileSize.height);
int index = tileX * mRetainedHeight + tileY;
int index = TileIndex(tileX, tileY);
MOZ_ASSERT(index >= 0 &&
static_cast<unsigned>(index) < newRetainedTiles.Length(),
"index out of range");

View File

@ -323,7 +323,8 @@ BasicCompositor::DrawQuad(const gfx::Rect& aRect,
const gfx::Rect& aClipRect,
const EffectChain &aEffectChain,
gfx::Float aOpacity,
const gfx::Matrix4x4 &aTransform)
const gfx::Matrix4x4& aTransform,
const gfx::Rect& aVisibleRect)
{
RefPtr<DrawTarget> buffer = mRenderTarget->mDrawTarget;

View File

@ -84,7 +84,8 @@ public:
const gfx::Rect& aClipRect,
const EffectChain &aEffectChain,
gfx::Float aOpacity,
const gfx::Matrix4x4 &aTransform) override;
const gfx::Matrix4x4& aTransform,
const gfx::Rect& aVisibleRect) override;
virtual void ClearRect(const gfx::Rect& aRect) override;

View File

@ -128,6 +128,7 @@ CompositableClient::CompositableClient(CompositableForwarder* aForwarder,
: mCompositableChild(nullptr)
, mForwarder(aForwarder)
, mTextureFlags(aTextureFlags)
, mDestroyed(false)
{
MOZ_COUNT_CTOR(CompositableClient);
}
@ -169,6 +170,8 @@ CompositableClient::Connect()
void
CompositableClient::Destroy()
{
mDestroyed = true;
if (!mCompositableChild) {
return;
}

View File

@ -149,6 +149,8 @@ public:
void Destroy();
bool IsDestroyed() { return mDestroyed; }
PCompositableChild* GetIPDLActor() const;
// should only be called by a CompositableForwarder
@ -232,6 +234,7 @@ protected:
// Some layers may want to enforce some flags to all their textures
// (like disallowing tiling)
TextureFlags mTextureFlags;
bool mDestroyed;
RefPtr<TextureClientRecycleAllocator> mTextureClientRecycler;
friend class CompositableChild;

View File

@ -540,6 +540,7 @@ protected:
{
MOZ_COUNT_DTOR(TiledContentClient);
mDestroyed = true;
mTiledBuffer.Release();
mLowPrecisionTiledBuffer.Release();
}

View File

@ -353,6 +353,13 @@ TextureHost::PrintInfo(std::stringstream& aStream, const char* aPrefix)
#endif
}
void
TextureHost::Updated(const nsIntRegion* aRegion)
{
LayerScope::ContentChanged(this);
UpdatedInternal(aRegion);
}
TextureSource::TextureSource()
: mCompositableCount(0)
{
@ -401,7 +408,7 @@ BufferTextureHost::~BufferTextureHost()
{}
void
BufferTextureHost::Updated(const nsIntRegion* aRegion)
BufferTextureHost::UpdatedInternal(const nsIntRegion* aRegion)
{
++mUpdateSerial;
// If the last frame wasn't uploaded yet, and we -don't- have a partial update,

View File

@ -388,7 +388,7 @@ public:
* @param aRegion The region that has been changed, if nil, it means that the
* entire surface should be updated.
*/
virtual void Updated(const nsIntRegion* aRegion = nullptr) {}
void Updated(const nsIntRegion* aRegion = nullptr);
/**
* Sets this TextureHost's compositor.
@ -538,6 +538,8 @@ protected:
void RecycleTexture(TextureFlags aFlags);
virtual void UpdatedInternal(const nsIntRegion *Region) {}
PTextureParent* mActor;
TextureFlags mFlags;
int mCompositableCount;
@ -570,8 +572,6 @@ public:
virtual size_t GetBufferSize() = 0;
virtual void Updated(const nsIntRegion* aRegion = nullptr) override;
virtual bool Lock() override;
virtual void Unlock() override;
@ -603,6 +603,8 @@ protected:
void InitSize();
virtual void UpdatedInternal(const nsIntRegion* aRegion = nullptr) override;
RefPtr<Compositor> mCompositor;
RefPtr<DataTextureSource> mFirstSource;
nsIntRegion mMaybeUpdatedRegion;

View File

@ -213,8 +213,8 @@ TiledLayerBufferComposite::UseTiles(const SurfaceDescriptorTiles& aTiles,
if (tile.mTextureHost && !tile.mTextureHost->HasInternalBuffer()) {
MOZ_ASSERT(tile.mSharedLock);
int tileX = i % oldRetainedWidth + oldFirstTileX;
int tileY = i / oldRetainedWidth + oldFirstTileY;
int tileX = i / oldRetainedHeight + oldFirstTileX;
int tileY = i % oldRetainedHeight + oldFirstTileY;
if (tileX >= newFirstTileX && tileY >= newFirstTileY &&
tileX < (newFirstTileX + newRetainedWidth) &&
@ -237,8 +237,8 @@ TiledLayerBufferComposite::UseTiles(const SurfaceDescriptorTiles& aTiles,
// they should be with the new retained with and height rather than the
// old one.
for (size_t i = 0; i < tileDescriptors.Length(); i++) {
int tileX = i % newRetainedWidth + newFirstTileX;
int tileY = i / newRetainedWidth + newFirstTileY;
int tileX = i / newRetainedHeight + newFirstTileX;
int tileY = i % newRetainedHeight + newFirstTileY;
// First, get the already existing tiles to the right place in the array,
// and use placeholders where there was no tiles.
@ -247,8 +247,8 @@ TiledLayerBufferComposite::UseTiles(const SurfaceDescriptorTiles& aTiles,
tileY >= (oldFirstTileY + oldRetainedHeight)) {
mRetainedTiles[i] = GetPlaceholderTile();
} else {
mRetainedTiles[i] = oldTiles[(tileY - oldFirstTileY) * oldRetainedWidth +
(tileX - oldFirstTileX)];
mRetainedTiles[i] = oldTiles[(tileX - oldFirstTileX) * oldRetainedHeight +
(tileY - oldFirstTileY)];
// 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.
@ -334,8 +334,8 @@ TiledLayerBufferComposite::UseTiles(const SurfaceDescriptorTiles& aTiles,
}
}
tile.x = i % newRetainedWidth + newFirstTileX;
tile.y = i / newRetainedWidth + newFirstTileY;
tile.x = i / newRetainedHeight + newFirstTileX;
tile.y = i % newRetainedHeight + newFirstTileY;
}
mFirstTileX = newFirstTileX;
@ -435,7 +435,8 @@ TiledContentHost::RenderTile(TileHost& aTile,
const gfx::Rect& aClipRect,
const nsIntRegion& aScreenRegion,
const IntPoint& aTextureOffset,
const nsIntSize& aTextureBounds)
const nsIntSize& aTextureBounds,
const gfx::Rect& aVisibleRect)
{
if (aTile.IsPlaceholderTile()) {
// This shouldn't ever happen, but let's fail semi-gracefully. No need
@ -490,7 +491,7 @@ TiledContentHost::RenderTile(TileHost& aTile,
textureRect.y / aTextureBounds.height,
textureRect.width / aTextureBounds.width,
textureRect.height / aTextureBounds.height);
mCompositor->DrawQuad(graphicsRect, aClipRect, aEffectChain, aOpacity, aTransform);
mCompositor->DrawQuad(graphicsRect, aClipRect, aEffectChain, aOpacity, aTransform, aVisibleRect);
}
DiagnosticFlags flags = DiagnosticFlags::CONTENT | DiagnosticFlags::TILE;
if (aTile.mTextureHostOnWhite) {
@ -582,7 +583,9 @@ TiledContentHost::RenderLayerBuffer(TiledLayerBufferComposite& aLayerBuffer,
gfx::IntSize tileSize = aLayerBuffer.GetTileSize();
RenderTile(tileTexture, aBackgroundColor, aEffectChain, aOpacity, aTransform,
aFilter, aClipRect, tileDrawRegion, tileOffset,
nsIntSize(tileSize.width, tileSize.height));
nsIntSize(tileSize.width, tileSize.height),
gfx::Rect(visibleRect.x, visibleRect.y,
visibleRect.width, visibleRect.height));
if (tileTexture.mTextureHostOnWhite) {
componentAlphaDiagnostic = DiagnosticFlags::COMPONENT_ALPHA;
}

View File

@ -283,7 +283,8 @@ private:
const gfx::Rect& aClipRect,
const nsIntRegion& aScreenRegion,
const gfx::IntPoint& aTextureOffset,
const gfx::IntSize& aTextureBounds);
const gfx::IntSize& aTextureBounds,
const gfx::Rect& aVisibleRect);
void EnsureTileStore() {}

View File

@ -741,7 +741,8 @@ CompositorD3D11::DrawQuad(const gfx::Rect& aRect,
const gfx::Rect& aClipRect,
const EffectChain& aEffectChain,
gfx::Float aOpacity,
const gfx::Matrix4x4& aTransform)
const gfx::Matrix4x4& aTransform,
const gfx::Rect& aVisibleRect)
{
if (mCurrentClip.IsEmpty()) {
return;
@ -1023,7 +1024,7 @@ CompositorD3D11::BeginFrame(const nsIntRegion& aInvalidRegion,
// Failed to create a render target or the view.
if (!mDefaultRT || !mDefaultRT->mRTView ||
mSize.width == 0 || mSize.height == 0) {
mSize.width <= 0 || mSize.height <= 0) {
*aRenderBoundsOut = Rect();
return;
}
@ -1092,6 +1093,10 @@ CompositorD3D11::EndFrame()
nsIntSize oldSize = mSize;
EnsureSize();
if (mSize.width <= 0 || mSize.height <= 0) {
return;
}
UINT presentInterval = 0;
if (gfxWindowsPlatform::GetPlatform()->IsWARP()) {
@ -1180,6 +1185,7 @@ CompositorD3D11::VerifyBufferSize()
hr = mSwapChain->GetDesc(&swapDesc);
if (Failed(hr)) {
gfxCriticalError() << "Failed to get the description " << hexa(hr);
return false;
}
@ -1210,12 +1216,20 @@ void
CompositorD3D11::UpdateRenderTarget()
{
EnsureSize();
VerifyBufferSize();
if (!VerifyBufferSize()) {
gfxCriticalError(gfxCriticalError::DefaultOptions(false)) << "Failed VerifyBufferSize in UpdateRenderTarget";
return;
}
if (mDefaultRT) {
return;
}
if (mSize.width <= 0 || mSize.height <= 0) {
gfxCriticalError(gfxCriticalError::DefaultOptions(false)) << "Invalid size in UpdateRenderTarget " << mSize;
return;
}
HRESULT hr;
nsRefPtr<ID3D11Texture2D> backBuf;

View File

@ -94,7 +94,8 @@ public:
const gfx::Rect &aClipRect,
const EffectChain &aEffectChain,
gfx::Float aOpacity,
const gfx::Matrix4x4 &aTransform) override;
const gfx::Matrix4x4& aTransform,
const gfx::Rect& aVisibleRect) override;
/* Helper for when the primary effect is VR_DISTORTION */
void DrawVRDistortion(const gfx::Rect &aRect,

View File

@ -241,7 +241,8 @@ CompositorD3D9::DrawQuad(const gfx::Rect &aRect,
const gfx::Rect &aClipRect,
const EffectChain &aEffectChain,
gfx::Float aOpacity,
const gfx::Matrix4x4 &aTransform)
const gfx::Matrix4x4& aTransform,
const gfx::Rect& aVisibleRect)
{
if (!mDeviceManager) {
return;

View File

@ -57,7 +57,8 @@ public:
const gfx::Rect &aClipRect,
const EffectChain &aEffectChain,
gfx::Float aOpacity,
const gfx::Matrix4x4 &aTransform) override;
const gfx::Matrix4x4& aTransform,
const gfx::Rect& aVisibleRect) override;
virtual void BeginFrame(const nsIntRegion& aInvalidRegion,
const gfx::Rect *aClipRectIn,

View File

@ -914,7 +914,7 @@ DataTextureSourceD3D9::UpdateFromTexture(IDirect3DTexture9* aTexture,
}
void
TextureHostD3D9::Updated(const nsIntRegion* aRegion)
TextureHostD3D9::UpdatedInternal(const nsIntRegion* aRegion)
{
MOZ_ASSERT(mTexture);
if (!mTexture) {

View File

@ -308,8 +308,6 @@ public:
virtual void Unlock() override;
virtual void Updated(const nsIntRegion* aRegion) override;
virtual gfx::IntSize GetSize() const override { return mSize; }
virtual TemporaryRef<gfx::DataSourceSurface> GetAsSurface() override
@ -323,6 +321,8 @@ protected:
TextureHostD3D9(TextureFlags aFlags);
IDirect3DDevice9* GetDevice();
virtual void UpdatedInternal(const nsIntRegion* aRegion) override;
RefPtr<DataTextureSourceD3D9> mTextureSource;
RefPtr<IDirect3DTexture9> mTexture;
RefPtr<CompositorD3D9> mCompositor;

View File

@ -428,7 +428,7 @@ ShadowLayerForwarder::RemoveTextureFromCompositableAsync(AsyncTransactionTracker
CompositableClient* aCompositable,
TextureClient* aTexture)
{
if (mTxn->Opened()) {
if (mTxn->Opened() && !aCompositable->IsDestroyed()) {
mTxn->AddEdit(OpRemoveTextureAsync(CompositableClient::GetTrackersHolderId(aCompositable->GetIPDLActor()),
aAsyncTransactionTracker->GetId(),
nullptr, aCompositable->GetIPDLActor(),

View File

@ -47,7 +47,7 @@ EXPORTS += [
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
SOURCES += [
'D3D11ShareHandleImage.cpp',
'D3D11ShareHandleImage.cpp',
]
UNIFIED_SOURCES += [
'D3D9SurfaceImage.cpp',

View File

@ -87,7 +87,7 @@ CompositorOGL::CompositorOGL(nsIWidget *aWidget, int aSurfaceWidth,
, mUseExternalSurfaceSize(aUseExternalSurfaceSize)
, mFrameInProgress(false)
, mDestroyed(false)
, mHeight(0)
, mViewportSize(0, 0)
, mCurrentProgram(nullptr)
{
MOZ_COUNT_CTOR(CompositorOGL);
@ -441,7 +441,7 @@ CompositorOGL::PrepareViewport(const gfx::IntSize& aSize)
// Set the viewport correctly.
mGLContext->fViewport(0, 0, aSize.width, aSize.height);
mHeight = aSize.height;
mViewportSize = aSize;
// We flip the view matrix around so that everything is right-side up; we're
// drawing directly into the window's back buffer, so this keeps things
@ -575,7 +575,7 @@ void
CompositorOGL::ClearRect(const gfx::Rect& aRect)
{
// Map aRect to OGL coordinates, origin:bottom-left
GLint y = mHeight - (aRect.y + aRect.height);
GLint y = mViewportSize.height - (aRect.y + aRect.height);
ScopedGLState scopedScissorTestState(mGLContext, LOCAL_GL_SCISSOR_TEST, true);
ScopedScissorRect autoScissorRect(mGLContext, aRect.x, y, aRect.width, aRect.height);
@ -770,7 +770,8 @@ ShaderConfigOGL
CompositorOGL::GetShaderConfigFor(Effect *aEffect,
MaskType aMask,
gfx::CompositionOp aOp,
bool aColorMatrix) const
bool aColorMatrix,
bool aDEAAEnabled) const
{
ShaderConfigOGL config;
@ -821,6 +822,7 @@ CompositorOGL::GetShaderConfigFor(Effect *aEffect,
config.SetColorMatrix(aColorMatrix);
config.SetMask2D(aMask == MaskType::Mask2d);
config.SetMask3D(aMask == MaskType::Mask3d);
config.SetDEAA(aDEAAEnabled);
return config;
}
@ -902,12 +904,41 @@ static bool SetBlendMode(GLContext* aGL, gfx::CompositionOp aBlendMode, bool aIs
return true;
}
gfx::Point3D
CompositorOGL::GetLineCoefficients(const gfx::Point& aPoint1,
const gfx::Point& aPoint2)
{
// Return standard coefficients for a line between aPoint1 and aPoint2
// for standard line equation:
//
// Ax + By + C = 0
//
// A = (p1.y p2.y)
// B = (p2.x p1.x)
// C = (p1.x * p2.y) (p2.x * p1.y)
gfx::Point3D coeffecients;
coeffecients.x = aPoint1.y - aPoint2.y;
coeffecients.y = aPoint2.x - aPoint1.x;
coeffecients.z = aPoint1.x * aPoint2.y - aPoint2.x * aPoint1.y;
coeffecients *= 1.0f / sqrtf(coeffecients.x * coeffecients.x +
coeffecients.y * coeffecients.y);
// Offset outwards by 0.5 pixel as the edge is considered to be 1 pixel
// wide and included within the interior of the polygon
coeffecients.z += 0.5f;
return coeffecients;
}
void
CompositorOGL::DrawQuad(const Rect& aRect,
const Rect& aClipRect,
const EffectChain &aEffectChain,
Float aOpacity,
const gfx::Matrix4x4 &aTransform)
const gfx::Matrix4x4& aTransform,
const gfx::Rect& aVisibleRect)
{
PROFILER_LABEL("CompositorOGL", "DrawQuad",
js::ProfileEntry::Category::GRAPHICS);
@ -1000,8 +1031,15 @@ CompositorOGL::DrawQuad(const Rect& aRect,
blendMode = blendEffect->mBlendMode;
}
// Only apply DEAA to quads that have been transformed such that aliasing
// could be visible
bool bEnableAA = gfxPrefs::LayersDEAAEnabled() &&
!aTransform.Is2DIntegerTranslation();
bool colorMatrix = aEffectChain.mSecondaryEffects[EffectTypes::COLOR_MATRIX];
ShaderConfigOGL config = GetShaderConfigFor(aEffectChain.mPrimaryEffect, maskType, blendMode, colorMatrix);
ShaderConfigOGL config = GetShaderConfigFor(aEffectChain.mPrimaryEffect,
maskType, blendMode, colorMatrix,
bEnableAA);
config.SetOpacity(aOpacity != 1.f);
ShaderProgramOGL *program = GetShaderProgramFor(config);
ActivateProgram(program);
@ -1028,6 +1066,74 @@ CompositorOGL::DrawQuad(const Rect& aRect,
program->SetTexCoordMultiplier(source->GetSize().width, source->GetSize().height);
}
// XXX kip - These calculations could be performed once per layer rather than
// for every tile. This might belong in Compositor.cpp once DEAA
// is implemented for DirectX.
if (bEnableAA) {
// Calculate the transformed vertices of aVisibleRect in screen space
// pixels, mirroring the calculations in the vertex shader
Matrix4x4 flatTransform = aTransform;
flatTransform.PostTranslate(-offset.x, -offset.y, 0.0f);
flatTransform *= mProjMatrix;
Rect viewportClip = Rect(-1.0f, -1.0f, 2.0f, 2.0f);
size_t edgeCount = 0;
Point3D coefficients[4];
Point points[Matrix4x4::kTransformAndClipRectMaxVerts];
size_t pointCount = flatTransform.TransformAndClipRect(aVisibleRect, viewportClip, points);
for (size_t i = 0; i < pointCount; i++) {
points[i] = Point((points[i].x * 0.5f + 0.5f) * mViewportSize.width,
(points[i].y * 0.5f + 0.5f) * mViewportSize.height);
}
if (pointCount > 2) {
// Use shoelace formula on a triangle in the clipped quad to determine if
// winding order is reversed. Iterate through the triangles until one is
// found with a non-zero area.
float winding = 0.0f;
size_t wp = 0;
while (winding == 0.0f && wp < pointCount) {
int wp1 = (wp + 1) % pointCount;
int wp2 = (wp + 2) % pointCount;
winding = (points[wp1].x - points[wp].x) * (points[wp1].y + points[wp].y) +
(points[wp2].x - points[wp1].x) * (points[wp2].y + points[wp1].y) +
(points[wp].x - points[wp2].x) * (points[wp].y + points[wp2].y);
wp++;
}
bool frontFacing = winding >= 0.0f;
// Calculate the line coefficients used by the DEAA shader to determine the
// sub-pixel coverage of the edge pixels
for (size_t i=0; i<pointCount; i++) {
const Point& p1 = points[i];
const Point& p2 = points[(i + 1) % pointCount];
// Create a DEAA edge for any non-straight lines, to a maximum of 4
if (p1.x != p2.x && p1.y != p2.y && edgeCount < 4) {
if (frontFacing) {
coefficients[edgeCount++] = GetLineCoefficients(p2, p1);
} else {
coefficients[edgeCount++] = GetLineCoefficients(p1, p2);
}
}
}
}
// The coefficients that are not needed must not cull any fragments.
// We fill these unused coefficients with a clipping plane that has no
// effect.
for (size_t i = edgeCount; i < 4; i++) {
coefficients[i] = Point3D(0.0f, 1.0f, mViewportSize.height);
}
// Set uniforms required by DEAA shader
Matrix4x4 transformInverted = aTransform;
transformInverted.Invert();
program->SetLayerTransformInverse(transformInverted);
program->SetDEAAEdges(coefficients);
program->SetVisibleCenter(aVisibleRect.Center());
program->SetViewportSize(mViewportSize);
}
bool didSetBlendMode = false;
switch (aEffectChain.mPrimaryEffect->mType) {
@ -1126,9 +1232,7 @@ CompositorOGL::DrawQuad(const Rect& aRect,
program->SetTextureUnit(0);
if (maskType != MaskType::MaskNone) {
sourceMask->BindTexture(LOCAL_GL_TEXTURE1, gfx::Filter::LINEAR);
program->SetMaskTextureUnit(1);
program->SetMaskLayerTransform(maskQuadTransform);
BindMaskForProgram(program, sourceMask, LOCAL_GL_TEXTURE1, maskQuadTransform);
}
if (config.mFeatures & ENABLE_TEXTURE_RECT) {

View File

@ -229,7 +229,8 @@ public:
const gfx::Rect& aClipRect,
const EffectChain &aEffectChain,
gfx::Float aOpacity,
const gfx::Matrix4x4 &aTransform) override;
const gfx::Matrix4x4& aTransform,
const gfx::Rect& aVisibleRect) override;
virtual void EndFrame() override;
virtual void SetDispAcquireFence(Layer* aLayer) override;
@ -335,7 +336,7 @@ private:
gfx::Matrix4x4 mProjMatrix;
/** The size of the surface we are rendering to */
nsIntSize mSurfaceSize;
gfx::IntSize mSurfaceSize;
ScreenPoint mRenderOffset;
@ -387,7 +388,8 @@ private:
ShaderConfigOGL GetShaderConfigFor(Effect *aEffect,
MaskType aMask = MaskType::MaskNone,
gfx::CompositionOp aOp = gfx::CompositionOp::OP_OVER,
bool aColorMatrix = false) const;
bool aColorMatrix = false,
bool aDEAAEnabled = false) const;
ShaderProgramOGL* GetShaderProgramFor(const ShaderConfigOGL &aConfig);
/**
@ -418,7 +420,8 @@ private:
const gfx::Rect& aRect,
const gfx::Rect& aTexCoordRect,
TextureSource *aTexture);
gfx::Point3D GetLineCoefficients(const gfx::Point& aPoint1,
const gfx::Point& aPoint2);
void ActivateProgram(ShaderProgramOGL *aProg);
void CleanupResources();
@ -437,7 +440,7 @@ private:
* y-axis pointing downwards, for good reason as Web pages are typically
* scrolled downwards. So, some flipping has to take place; FlippedY does it.
*/
GLint FlipY(GLint y) const { return mHeight - y; }
GLint FlipY(GLint y) const { return mViewportSize.height - y; }
RefPtr<CompositorTexturePoolOGL> mTexturePool;
@ -446,10 +449,10 @@ private:
bool mDestroyed;
/**
* Height of the OpenGL context's primary framebuffer in pixels. Used by
* FlipY for the y-flipping calculation.
* Size of the OpenGL context's primary framebuffer in pixels. Used by
* FlipY for the y-flipping calculation and by the DEAA shader.
*/
GLint mHeight;
gfx::IntSize mViewportSize;
FenceHandle mReleaseFenceHandle;
ShaderProgramOGL *mCurrentProgram;

View File

@ -24,8 +24,6 @@ public:
virtual ~GrallocTextureHostOGL();
virtual void Updated(const nsIntRegion* aRegion) override {}
virtual bool Lock() override;
virtual void Unlock() override;

View File

@ -30,6 +30,7 @@ AddUniforms(ProgramProfileOGL& aProfile)
// This needs to be kept in sync with the KnownUniformName enum
static const char *sKnownUniformNames[] = {
"uLayerTransform",
"uLayerTransformInverse",
"uMaskTransform",
"uLayerRects",
"uMatrixProj",
@ -53,6 +54,9 @@ AddUniforms(ProgramProfileOGL& aProfile)
"uBlurOffset",
"uBlurAlpha",
"uBlurGaussianKernel",
"uSSEdges",
"uViewportSize",
"uVisibleCenter",
nullptr
};
@ -142,6 +146,12 @@ ShaderConfigOGL::SetPremultiply(bool aEnabled)
SetFeature(ENABLE_PREMULTIPLY, aEnabled);
}
void
ShaderConfigOGL::SetDEAA(bool aEnabled)
{
SetFeature(ENABLE_DEAA, aEnabled);
}
/* static */ ProgramProfileOGL
ProgramProfileOGL::GetProfileFor(ShaderConfigOGL aConfig)
{
@ -153,8 +163,13 @@ ProgramProfileOGL::GetProfileFor(ShaderConfigOGL aConfig)
vs << "uniform mat4 uMatrixProj;" << endl;
vs << "uniform vec4 uLayerRects[4];" << endl;
vs << "uniform mat4 uLayerTransform;" << endl;
vs << "uniform vec4 uRenderTargetOffset;" << endl;
if (aConfig.mFeatures & ENABLE_DEAA) {
vs << "uniform mat4 uLayerTransformInverse;" << endl;
vs << "uniform vec3 uSSEdges[4];" << endl;
vs << "uniform vec2 uVisibleCenter;" << endl;
vs << "uniform vec2 uViewportSize;" << endl;
}
vs << "uniform vec2 uRenderTargetOffset;" << endl;
vs << "attribute vec4 aCoord;" << endl;
if (!(aConfig.mFeatures & ENABLE_RENDER_COLOR)) {
@ -174,27 +189,78 @@ ProgramProfileOGL::GetProfileFor(ShaderConfigOGL aConfig)
vs << " vec4 layerRect = uLayerRects[vertexID];" << endl;
vs << " vec4 finalPosition = vec4(aCoord.xy * layerRect.zw + layerRect.xy, 0.0, 1.0);" << endl;
vs << " finalPosition = uLayerTransform * finalPosition;" << endl;
vs << " finalPosition.xyz /= finalPosition.w;" << endl;
if (aConfig.mFeatures & ENABLE_MASK_3D) {
vs << " vMaskCoord.xy = (uMaskTransform * vec4(finalPosition.xyz, 1.0)).xy;" << endl;
// correct for perspective correct interpolation, see comment in D3D10 shader
vs << " vMaskCoord.z = 1.0;" << endl;
vs << " vMaskCoord *= finalPosition.w;" << endl;
} else if (aConfig.mFeatures & ENABLE_MASK_2D) {
vs << " vMaskCoord.xy = (uMaskTransform * finalPosition).xy;" << endl;
}
if (aConfig.mFeatures & ENABLE_DEAA) {
// XXX kip - The DEAA shader could be made simpler if we switch to
// using dynamic vertex buffers instead of sending everything
// in through uniforms. This would enable passing information
// about how to dilate each vertex explicitly and eliminate the
// need to extrapolate this with the sub-pixel coverage
// calculation in the vertex shader.
vs << " finalPosition = finalPosition - uRenderTargetOffset;" << endl;
vs << " finalPosition.xyz *= finalPosition.w;" << endl;
vs << " finalPosition = uMatrixProj * finalPosition;" << endl;
// Calculate the screen space position of this vertex, in screen pixels
vs << " vec4 ssPos = finalPosition;" << endl;
vs << " ssPos.xy -= uRenderTargetOffset * finalPosition.w;" << endl;
vs << " ssPos = uMatrixProj * ssPos;" << endl;
vs << " ssPos.xy = ((ssPos.xy/ssPos.w)*0.5+0.5)*uViewportSize;" << endl;
if (!(aConfig.mFeatures & ENABLE_RENDER_COLOR)) {
if (aConfig.mFeatures & ENABLE_MASK_2D ||
aConfig.mFeatures & ENABLE_MASK_3D ||
!(aConfig.mFeatures & ENABLE_RENDER_COLOR)) {
vs << " vec4 coordAdjusted;" << endl;
vs << " coordAdjusted.xy = aCoord.xy;" << endl;
}
// It is necessary to dilate edges away from uVisibleCenter to ensure that
// fragments with less than 50% sub-pixel coverage will be shaded.
// This offset is applied when the sub-pixel coverage of the vertex is
// less than 100%. Expanding by 0.5 pixels in screen space is sufficient
// to include these pixels.
vs << " if (dot(uSSEdges[0], vec3(ssPos.xy, 1.0)) < 1.5 ||" << endl;
vs << " dot(uSSEdges[1], vec3(ssPos.xy, 1.0)) < 1.5 ||" << endl;
vs << " dot(uSSEdges[2], vec3(ssPos.xy, 1.0)) < 1.5 ||" << endl;
vs << " dot(uSSEdges[3], vec3(ssPos.xy, 1.0)) < 1.5) {" << endl;
// If the shader reaches this branch, then this vertex is on the edge of
// the layer's visible rect and should be dilated away from the center of
// the visible rect. We don't want to hit this for inner facing
// edges between tiles, as the pixels may be covered twice without clipping
// against uSSEdges. If all edges were dilated, it would result in
// artifacts visible within semi-transparent layers with multiple tiles.
vs << " vec4 visibleCenter = uLayerTransform * vec4(uVisibleCenter, 0.0, 1.0);" << endl;
vs << " vec2 dilateDir = finalPosition.xy / finalPosition.w - visibleCenter.xy / visibleCenter.w;" << endl;
vs << " vec2 offset = sign(dilateDir) * 0.5;" << endl;
vs << " finalPosition.xy += offset * finalPosition.w;" << endl;
if (!(aConfig.mFeatures & ENABLE_RENDER_COLOR)) {
// We must adjust the texture coordinates to compensate for the dilation
vs << " coordAdjusted = uLayerTransformInverse * finalPosition;" << endl;
vs << " coordAdjusted /= coordAdjusted.w;" << endl;
vs << " coordAdjusted.xy -= layerRect.xy;" << endl;
vs << " coordAdjusted.xy /= layerRect.zw;" << endl;
}
vs << " }" << endl;
if (!(aConfig.mFeatures & ENABLE_RENDER_COLOR)) {
vs << " vec4 textureRect = uTextureRects[vertexID];" << endl;
vs << " vec2 texCoord = coordAdjusted.xy * textureRect.zw + textureRect.xy;" << endl;
vs << " vTexCoord = (uTextureTransform * vec4(texCoord, 0.0, 1.0)).xy;" << endl;
}
} else if (!(aConfig.mFeatures & ENABLE_RENDER_COLOR)) {
vs << " vec4 textureRect = uTextureRects[vertexID];" << endl;
vs << " vec2 texCoord = aCoord.xy * textureRect.zw + textureRect.xy;" << endl;
vs << " vTexCoord = (uTextureTransform * vec4(texCoord, 0.0, 1.0)).xy;" << endl;
}
if (aConfig.mFeatures & ENABLE_MASK_2D ||
aConfig.mFeatures & ENABLE_MASK_3D) {
vs << " vMaskCoord.xy = (uMaskTransform * (finalPosition / finalPosition.w)).xy;" << endl;
if (aConfig.mFeatures & ENABLE_MASK_3D) {
// correct for perspective correct interpolation, see comment in D3D10 shader
vs << " vMaskCoord.z = 1.0;" << endl;
vs << " vMaskCoord *= finalPosition.w;" << endl;
}
}
vs << " finalPosition.xy -= uRenderTargetOffset * finalPosition.w;" << endl;
vs << " finalPosition = uMatrixProj * finalPosition;" << endl;
vs << " gl_Position = finalPosition;" << endl;
vs << "}" << endl;
@ -261,6 +327,10 @@ ProgramProfileOGL::GetProfileFor(ShaderConfigOGL aConfig)
fs << "uniform sampler2D uMaskTexture;" << endl;
}
if (aConfig.mFeatures & ENABLE_DEAA) {
fs << "uniform vec3 uSSEdges[4];" << endl;
}
if (!(aConfig.mFeatures & ENABLE_RENDER_COLOR)) {
fs << "vec4 sample(vec2 coord) {" << endl;
fs << " vec4 color;" << endl;
@ -353,6 +423,16 @@ For [0,1] instead of [0,255], and to 5 places:
fs << " color.rgb *= color.a;" << endl;
}
}
if (aConfig.mFeatures & ENABLE_DEAA) {
// Calculate the sub-pixel coverage of the pixel and modulate its opacity
// by that amount to perform DEAA.
fs << " vec3 ssPos = vec3(gl_FragCoord.xy, 1.0);" << endl;
fs << " float deaaCoverage = clamp(dot(uSSEdges[0], ssPos), 0.0, 1.0);" << endl;
fs << " deaaCoverage *= clamp(dot(uSSEdges[1], ssPos), 0.0, 1.0);" << endl;
fs << " deaaCoverage *= clamp(dot(uSSEdges[2], ssPos), 0.0, 1.0);" << endl;
fs << " deaaCoverage *= clamp(dot(uSSEdges[3], ssPos), 0.0, 1.0);" << endl;
fs << " color *= deaaCoverage;" << endl;
}
if (aConfig.mFeatures & ENABLE_MASK_3D) {
fs << " vec2 maskCoords = vMaskCoord.xy / vMaskCoord.z;" << endl;
fs << " COLOR_PRECISION float mask = texture2D(uMaskTexture, maskCoords).r;" << endl;

View File

@ -40,7 +40,8 @@ enum ShaderFeatures {
ENABLE_COLOR_MATRIX=0x200,
ENABLE_MASK_2D=0x400,
ENABLE_MASK_3D=0x800,
ENABLE_PREMULTIPLY=0x1000
ENABLE_PREMULTIPLY=0x1000,
ENABLE_DEAA=0x2000
};
class KnownUniform {
@ -50,6 +51,7 @@ public:
NotAKnownUniform = -1,
LayerTransform = 0,
LayerTransformInverse,
MaskTransform,
LayerRects,
MatrixProj,
@ -73,6 +75,9 @@ public:
BlurOffset,
BlurAlpha,
BlurGaussianKernel,
SSEdges,
ViewportSize,
VisibleCenter,
KnownUniformCount
};
@ -163,6 +168,30 @@ public:
return false;
}
bool UpdateArrayUniform(int cnt, const gfx::Point3D* points) {
if (mLocation == -1) return false;
if (cnt > 4) {
return false;
}
float fp[12];
float *d = fp;
for(int i=0; i < cnt; i++) {
// Note: Do not want to make assumptions about .x, .y, .z member packing.
// If gfx::Point3D is updated to make this guarantee, SIMD optimizations
// may be possible
*d++ = points[i].x;
*d++ = points[i].y;
*d++ = points[i].z;
}
if (memcmp(mValue.f16v, fp, sizeof(float) * cnt * 3) != 0) {
memcpy(mValue.f16v, fp, sizeof(float) * cnt * 3);
return true;
}
return false;
}
KnownUniformName mName;
const char *mNameString;
int32_t mLocation;
@ -192,6 +221,7 @@ public:
void SetMask2D(bool aEnabled);
void SetMask3D(bool aEnabled);
void SetPremultiply(bool aEnabled);
void SetDEAA(bool aEnabled);
bool operator< (const ShaderConfigOGL& other) const {
return mFeatures < other.mFeatures;
@ -303,10 +333,28 @@ public:
SetMatrixUniform(KnownUniform::LayerTransform, aMatrix);
}
void SetLayerTransformInverse(const gfx::Matrix4x4& aMatrix) {
SetMatrixUniform(KnownUniform::LayerTransformInverse, aMatrix);
}
void SetMaskLayerTransform(const gfx::Matrix4x4& aMatrix) {
SetMatrixUniform(KnownUniform::MaskTransform, aMatrix);
}
void SetDEAAEdges(const gfx::Point3D* aEdges) {
SetArrayUniform(KnownUniform::SSEdges, 4, aEdges);
}
void SetViewportSize(const gfx::IntSize& aSize) {
float vals[2] = { (float)aSize.width, (float)aSize.height };
SetUniform(KnownUniform::ViewportSize, 2, vals);
}
void SetVisibleCenter(const gfx::Point& aVisibleCenter) {
float vals[2] = { aVisibleCenter.x, aVisibleCenter.y };
SetUniform(KnownUniform::VisibleCenter, 2, vals);
}
void SetLayerRects(const gfx::Rect* aRects) {
float vals[16] = { aRects[0].x, aRects[0].y, aRects[0].width, aRects[0].height,
aRects[1].x, aRects[1].y, aRects[1].width, aRects[1].height,
@ -333,13 +381,13 @@ public:
}
void SetRenderOffset(const nsIntPoint& aOffset) {
float vals[4] = { float(aOffset.x), float(aOffset.y), 0.0f, 0.0f };
SetUniform(KnownUniform::RenderTargetOffset, 4, vals);
float vals[4] = { float(aOffset.x), float(aOffset.y) };
SetUniform(KnownUniform::RenderTargetOffset, 2, vals);
}
void SetRenderOffset(float aX, float aY) {
float vals[4] = { aX, aY, 0.0f, 0.0f };
SetUniform(KnownUniform::RenderTargetOffset, 4, vals);
float vals[2] = { aX, aY };
SetUniform(KnownUniform::RenderTargetOffset, 2, vals);
}
void SetLayerOpacity(float aOpacity) {
@ -497,6 +545,17 @@ protected:
}
}
void SetArrayUniform(KnownUniform::KnownUniformName aKnownUniform, int aLength, const gfx::Point3D *aPointValues)
{
ASSERT_THIS_PROGRAM;
NS_ASSERTION(aKnownUniform >= 0 && aKnownUniform < KnownUniform::KnownUniformCount, "Invalid known uniform");
KnownUniform& ku(mProfile.mUniforms[aKnownUniform]);
if (ku.UpdateArrayUniform(aLength, aPointValues)) {
mGL->fUniform3fv(ku.mLocation, aLength, ku.mValue.f16v);
}
}
void SetUniform(KnownUniform::KnownUniformName aKnownUniform, GLint aIntValue) {
ASSERT_THIS_PROGRAM;
NS_ASSERTION(aKnownUniform >= 0 && aKnownUniform < KnownUniform::KnownUniformCount, "Invalid known uniform");

View File

@ -102,64 +102,82 @@ namespace FilterWrappers {
Unpremultiply(DrawTarget* aDT, FilterNode* aInput)
{
RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::UNPREMULTIPLY);
filter->SetInput(IN_UNPREMULTIPLY_IN, aInput);
return filter.forget();
if (filter) {
filter->SetInput(IN_UNPREMULTIPLY_IN, aInput);
return filter.forget();
}
return nullptr;
}
static TemporaryRef<FilterNode>
Premultiply(DrawTarget* aDT, FilterNode* aInput)
{
RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::PREMULTIPLY);
filter->SetInput(IN_PREMULTIPLY_IN, aInput);
return filter.forget();
if (filter) {
filter->SetInput(IN_PREMULTIPLY_IN, aInput);
return filter.forget();
}
return nullptr;
}
static TemporaryRef<FilterNode>
LinearRGBToSRGB(DrawTarget* aDT, FilterNode* aInput)
{
RefPtr<FilterNode> transfer = aDT->CreateFilter(FilterType::DISCRETE_TRANSFER);
transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_R, false);
transfer->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_R, glinearRGBTosRGBMap, 256);
transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_G, false);
transfer->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_G, glinearRGBTosRGBMap, 256);
transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_B, false);
transfer->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_B, glinearRGBTosRGBMap, 256);
transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_A, true);
transfer->SetInput(IN_DISCRETE_TRANSFER_IN, aInput);
return transfer.forget();
if (transfer) {
transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_R, false);
transfer->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_R, glinearRGBTosRGBMap, 256);
transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_G, false);
transfer->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_G, glinearRGBTosRGBMap, 256);
transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_B, false);
transfer->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_B, glinearRGBTosRGBMap, 256);
transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_A, true);
transfer->SetInput(IN_DISCRETE_TRANSFER_IN, aInput);
return transfer.forget();
}
return nullptr;
}
static TemporaryRef<FilterNode>
SRGBToLinearRGB(DrawTarget* aDT, FilterNode* aInput)
{
RefPtr<FilterNode> transfer = aDT->CreateFilter(FilterType::DISCRETE_TRANSFER);
transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_R, false);
transfer->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_R, gsRGBToLinearRGBMap, 256);
transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_G, false);
transfer->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_G, gsRGBToLinearRGBMap, 256);
transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_B, false);
transfer->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_B, gsRGBToLinearRGBMap, 256);
transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_A, true);
transfer->SetInput(IN_DISCRETE_TRANSFER_IN, aInput);
return transfer.forget();
if (transfer) {
transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_R, false);
transfer->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_R, gsRGBToLinearRGBMap, 256);
transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_G, false);
transfer->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_G, gsRGBToLinearRGBMap, 256);
transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_B, false);
transfer->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_B, gsRGBToLinearRGBMap, 256);
transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_A, true);
transfer->SetInput(IN_DISCRETE_TRANSFER_IN, aInput);
return transfer.forget();
}
return nullptr;
}
static TemporaryRef<FilterNode>
Crop(DrawTarget* aDT, FilterNode* aInputFilter, const IntRect& aRect)
{
RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::CROP);
filter->SetAttribute(ATT_CROP_RECT, Rect(aRect));
filter->SetInput(IN_CROP_IN, aInputFilter);
return filter.forget();
if (filter) {
filter->SetAttribute(ATT_CROP_RECT, Rect(aRect));
filter->SetInput(IN_CROP_IN, aInputFilter);
return filter.forget();
}
return nullptr;
}
static TemporaryRef<FilterNode>
Offset(DrawTarget* aDT, FilterNode* aInputFilter, const IntPoint& aOffset)
{
RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::TRANSFORM);
filter->SetAttribute(ATT_TRANSFORM_MATRIX, Matrix::Translation(aOffset.x, aOffset.y));
filter->SetInput(IN_TRANSFORM_IN, aInputFilter);
return filter.forget();
if (filter) {
filter->SetAttribute(ATT_TRANSFORM_MATRIX, Matrix::Translation(aOffset.x, aOffset.y));
filter->SetInput(IN_TRANSFORM_IN, aInputFilter);
return filter.forget();
}
return nullptr;
}
static TemporaryRef<FilterNode>
@ -169,27 +187,36 @@ namespace FilterWrappers {
float stdY = float(std::min(aStdDeviation.height, kMaxStdDeviation));
if (stdX == stdY) {
RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::GAUSSIAN_BLUR);
filter->SetAttribute(ATT_GAUSSIAN_BLUR_STD_DEVIATION, stdX);
filter->SetInput(IN_GAUSSIAN_BLUR_IN, aInputFilter);
return filter.forget();
if (filter) {
filter->SetAttribute(ATT_GAUSSIAN_BLUR_STD_DEVIATION, stdX);
filter->SetInput(IN_GAUSSIAN_BLUR_IN, aInputFilter);
return filter.forget();
}
return nullptr;
}
RefPtr<FilterNode> filterH = aDT->CreateFilter(FilterType::DIRECTIONAL_BLUR);
RefPtr<FilterNode> filterV = aDT->CreateFilter(FilterType::DIRECTIONAL_BLUR);
filterH->SetAttribute(ATT_DIRECTIONAL_BLUR_DIRECTION, (uint32_t)BLUR_DIRECTION_X);
filterH->SetAttribute(ATT_DIRECTIONAL_BLUR_STD_DEVIATION, stdX);
filterV->SetAttribute(ATT_DIRECTIONAL_BLUR_DIRECTION, (uint32_t)BLUR_DIRECTION_Y);
filterV->SetAttribute(ATT_DIRECTIONAL_BLUR_STD_DEVIATION, stdY);
filterH->SetInput(IN_DIRECTIONAL_BLUR_IN, aInputFilter);
filterV->SetInput(IN_DIRECTIONAL_BLUR_IN, filterH);
return filterV.forget();
if (filterH && filterV) {
filterH->SetAttribute(ATT_DIRECTIONAL_BLUR_DIRECTION, (uint32_t)BLUR_DIRECTION_X);
filterH->SetAttribute(ATT_DIRECTIONAL_BLUR_STD_DEVIATION, stdX);
filterV->SetAttribute(ATT_DIRECTIONAL_BLUR_DIRECTION, (uint32_t)BLUR_DIRECTION_Y);
filterV->SetAttribute(ATT_DIRECTIONAL_BLUR_STD_DEVIATION, stdY);
filterH->SetInput(IN_DIRECTIONAL_BLUR_IN, aInputFilter);
filterV->SetInput(IN_DIRECTIONAL_BLUR_IN, filterH);
return filterV.forget();
}
return nullptr;
}
static TemporaryRef<FilterNode>
Clear(DrawTarget* aDT)
{
RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::FLOOD);
filter->SetAttribute(ATT_FLOOD_COLOR, Color(0,0,0,0));
return filter.forget();
if (filter) {
filter->SetAttribute(ATT_FLOOD_COLOR, Color(0, 0, 0, 0));
return filter.forget();
}
return nullptr;
}
static TemporaryRef<FilterNode>
@ -197,10 +224,13 @@ namespace FilterWrappers {
const IntPoint& aSurfacePosition)
{
RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::TRANSFORM);
filter->SetAttribute(ATT_TRANSFORM_MATRIX,
Matrix::Translation(aSurfacePosition.x, aSurfacePosition.y));
filter->SetInput(IN_TRANSFORM_IN, aSurface);
return filter.forget();
if (filter) {
filter->SetAttribute(ATT_TRANSFORM_MATRIX,
Matrix::Translation(aSurfacePosition.x, aSurfacePosition.y));
filter->SetInput(IN_TRANSFORM_IN, aSurface);
return filter.forget();
}
return nullptr;
}
static TemporaryRef<FilterNode>
@ -208,15 +238,18 @@ namespace FilterWrappers {
{
float zero = 0.0f;
RefPtr<FilterNode> transfer = aDT->CreateFilter(FilterType::DISCRETE_TRANSFER);
transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_R, false);
transfer->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_R, &zero, 1);
transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_G, false);
transfer->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_G, &zero, 1);
transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_B, false);
transfer->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_B, &zero, 1);
transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_A, true);
transfer->SetInput(IN_DISCRETE_TRANSFER_IN, aInput);
return transfer.forget();
if (transfer) {
transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_R, false);
transfer->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_R, &zero, 1);
transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_G, false);
transfer->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_G, &zero, 1);
transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_B, false);
transfer->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_B, &zero, 1);
transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_A, true);
transfer->SetInput(IN_DISCRETE_TRANSFER_IN, aInput);
return transfer.forget();
}
return nullptr;
}
}
@ -535,6 +568,9 @@ ConvertComponentTransferFunctionToFilter(const AttributeMap& aFunctionAttributes
if (!aTableTransfer) {
aTableTransfer = aDT->CreateFilter(FilterType::TABLE_TRANSFER);
if (!aTableTransfer) {
return;
}
DisableAllTransfers(aTableTransfer);
}
filter = aTableTransfer;
@ -558,6 +594,9 @@ ConvertComponentTransferFunctionToFilter(const AttributeMap& aFunctionAttributes
if (!aDiscreteTransfer) {
aDiscreteTransfer = aDT->CreateFilter(FilterType::DISCRETE_TRANSFER);
if (!aDiscreteTransfer) {
return;
}
DisableAllTransfers(aDiscreteTransfer);
}
filter = aDiscreteTransfer;
@ -589,6 +628,9 @@ ConvertComponentTransferFunctionToFilter(const AttributeMap& aFunctionAttributes
};
if (!aLinearTransfer) {
aLinearTransfer = aDT->CreateFilter(FilterType::LINEAR_TRANSFER);
if (!aLinearTransfer) {
return;
}
DisableAllTransfers(aLinearTransfer);
}
filter = aLinearTransfer;
@ -622,6 +664,9 @@ ConvertComponentTransferFunctionToFilter(const AttributeMap& aFunctionAttributes
};
if (!aGammaTransfer) {
aGammaTransfer = aDT->CreateFilter(FilterType::GAMMA_TRANSFER);
if (!aGammaTransfer) {
return;
}
DisableAllTransfers(aGammaTransfer);
}
filter = aGammaTransfer;
@ -672,10 +717,16 @@ FilterNodeFromPrimitiveDescription(const FilterPrimitiveDescription& aDescriptio
}
if (mode == SVG_FEBLEND_MODE_NORMAL) {
filter = aDT->CreateFilter(FilterType::COMPOSITE);
if (!filter) {
return nullptr;
}
filter->SetInput(IN_COMPOSITE_IN_START, aSources[1]);
filter->SetInput(IN_COMPOSITE_IN_START + 1, aSources[0]);
} else {
filter = aDT->CreateFilter(FilterType::BLEND);
if (!filter) {
return nullptr;
}
static const uint8_t blendModes[SVG_FEBLEND_MODE_LUMINOSITY + 1] = {
0,
0,
@ -717,6 +768,9 @@ FilterNodeFromPrimitiveDescription(const FilterPrimitiveDescription& aDescriptio
colorMatrix[3], colorMatrix[8], colorMatrix[13], colorMatrix[18],
colorMatrix[4], colorMatrix[9], colorMatrix[14], colorMatrix[19]);
RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::COLOR_MATRIX);
if (!filter) {
return nullptr;
}
filter->SetAttribute(ATT_COLOR_MATRIX_MATRIX, matrix);
filter->SetAttribute(ATT_COLOR_MATRIX_ALPHA_MODE, (uint32_t)ALPHA_MODE_STRAIGHT);
filter->SetInput(IN_COLOR_MATRIX_IN, aSources[0]);
@ -744,6 +798,9 @@ FilterNodeFromPrimitiveDescription(const FilterPrimitiveDescription& aDescriptio
MORPHOLOGY_OPERATOR_ERODE : MORPHOLOGY_OPERATOR_DILATE;
RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::MORPHOLOGY);
if (!filter) {
return nullptr;
}
filter->SetAttribute(ATT_MORPHOLOGY_RADII, IntSize(rx, ry));
filter->SetAttribute(ATT_MORPHOLOGY_OPERATOR, (uint32_t)op);
filter->SetInput(IN_MORPHOLOGY_IN, aSources[0]);
@ -754,6 +811,9 @@ FilterNodeFromPrimitiveDescription(const FilterPrimitiveDescription& aDescriptio
{
Color color = atts.GetColor(eFloodColor);
RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::FLOOD);
if (!filter) {
return nullptr;
}
filter->SetAttribute(ATT_FLOOD_COLOR, color);
return filter.forget();
}
@ -761,6 +821,9 @@ FilterNodeFromPrimitiveDescription(const FilterPrimitiveDescription& aDescriptio
case PrimitiveType::Tile:
{
RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::TILE);
if (!filter) {
return nullptr;
}
filter->SetAttribute(ATT_TILE_SOURCE_RECT, aSourceRegions[0]);
filter->SetInput(IN_TILE_IN, aSources[0]);
return filter.forget();
@ -797,6 +860,9 @@ FilterNodeFromPrimitiveDescription(const FilterPrimitiveDescription& aDescriptio
case PrimitiveType::ConvolveMatrix:
{
RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::CONVOLVE_MATRIX);
if (!filter) {
return nullptr;
}
filter->SetAttribute(ATT_CONVOLVE_MATRIX_KERNEL_SIZE, atts.GetIntSize(eConvolveMatrixKernelSize));
const nsTArray<float>& matrix = atts.GetFloats(eConvolveMatrixKernelMatrix);
filter->SetAttribute(ATT_CONVOLVE_MATRIX_KERNEL_MATRIX,
@ -834,6 +900,9 @@ FilterNodeFromPrimitiveDescription(const FilterPrimitiveDescription& aDescriptio
case PrimitiveType::DisplacementMap:
{
RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::DISPLACEMENT_MAP);
if (!filter) {
return nullptr;
}
filter->SetAttribute(ATT_DISPLACEMENT_MAP_SCALE,
atts.GetFloat(eDisplacementMapScale));
static const uint8_t channel[SVG_CHANNEL_A+1] = {
@ -855,6 +924,9 @@ FilterNodeFromPrimitiveDescription(const FilterPrimitiveDescription& aDescriptio
case PrimitiveType::Turbulence:
{
RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::TURBULENCE);
if (!filter) {
return nullptr;
}
filter->SetAttribute(ATT_TURBULENCE_BASE_FREQUENCY,
atts.GetSize(eTurbulenceBaseFrequency));
filter->SetAttribute(ATT_TURBULENCE_NUM_OCTAVES,
@ -881,6 +953,9 @@ FilterNodeFromPrimitiveDescription(const FilterPrimitiveDescription& aDescriptio
uint32_t op = atts.GetUint(eCompositeOperator);
if (op == SVG_FECOMPOSITE_OPERATOR_ARITHMETIC) {
filter = aDT->CreateFilter(FilterType::ARITHMETIC_COMBINE);
if (!filter) {
return nullptr;
}
const nsTArray<float>& coefficients = atts.GetFloats(eCompositeCoefficients);
filter->SetAttribute(ATT_ARITHMETIC_COMBINE_COEFFICIENTS,
coefficients.Elements(), coefficients.Length());
@ -888,6 +963,9 @@ FilterNodeFromPrimitiveDescription(const FilterPrimitiveDescription& aDescriptio
filter->SetInput(IN_ARITHMETIC_COMBINE_IN2, aSources[1]);
} else {
filter = aDT->CreateFilter(FilterType::COMPOSITE);
if (!filter) {
return nullptr;
}
static const uint8_t operators[SVG_FECOMPOSITE_OPERATOR_ARITHMETIC] = {
COMPOSITE_OPERATOR_OVER, // SVG_FECOMPOSITE_OPERATOR_UNKNOWN
COMPOSITE_OPERATOR_OVER, // SVG_FECOMPOSITE_OPERATOR_OVER
@ -913,6 +991,9 @@ FilterNodeFromPrimitiveDescription(const FilterPrimitiveDescription& aDescriptio
return filter.forget();
}
RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::COMPOSITE);
if (!filter) {
return nullptr;
}
filter->SetAttribute(ATT_COMPOSITE_OPERATOR, (uint32_t)COMPOSITE_OPERATOR_OVER);
for (size_t i = 0; i < aSources.Length(); i++) {
filter->SetInput(IN_COMPOSITE_IN_START + i, aSources[i]);
@ -934,6 +1015,9 @@ FilterNodeFromPrimitiveDescription(const FilterPrimitiveDescription& aDescriptio
RefPtr<FilterNode> offsetBlur = FilterWrappers::Offset(aDT, blur,
atts.GetIntPoint(eDropShadowOffset));
RefPtr<FilterNode> flood = aDT->CreateFilter(FilterType::FLOOD);
if (!flood) {
return nullptr;
}
Color color = atts.GetColor(eDropShadowColor);
if (aDescription.InputColorSpace(0) == ColorSpace::LinearRGB) {
color = Color(gsRGBToLinearRGBMap[uint8_t(color.r * 255)],
@ -944,11 +1028,17 @@ FilterNodeFromPrimitiveDescription(const FilterPrimitiveDescription& aDescriptio
flood->SetAttribute(ATT_FLOOD_COLOR, color);
RefPtr<FilterNode> composite = aDT->CreateFilter(FilterType::COMPOSITE);
if (!composite) {
return nullptr;
}
composite->SetAttribute(ATT_COMPOSITE_OPERATOR, (uint32_t)COMPOSITE_OPERATOR_IN);
composite->SetInput(IN_COMPOSITE_IN_START, offsetBlur);
composite->SetInput(IN_COMPOSITE_IN_START + 1, flood);
RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::COMPOSITE);
if (!filter) {
return nullptr;
}
filter->SetAttribute(ATT_COMPOSITE_OPERATOR, (uint32_t)COMPOSITE_OPERATOR_OVER);
filter->SetInput(IN_COMPOSITE_IN_START, composite);
filter->SetInput(IN_COMPOSITE_IN_START + 1, aSources[0]);
@ -981,6 +1071,9 @@ FilterNodeFromPrimitiveDescription(const FilterPrimitiveDescription& aDescriptio
};
RefPtr<FilterNode> filter =
aDT->CreateFilter(filterType[isSpecular][lightType]);
if (!filter) {
return nullptr;
}
filter->SetAttribute(ATT_LIGHTING_COLOR,
atts.GetColor(eLightingColor));
@ -1040,6 +1133,9 @@ FilterNodeFromPrimitiveDescription(const FilterPrimitiveDescription& aDescriptio
aInputImages[atts.GetUint(eImageInputIndex)];
RefPtr<FilterNode> transform = aDT->CreateFilter(FilterType::TRANSFORM);
if (!transform) {
return nullptr;
}
transform->SetInput(IN_TRANSFORM_IN, inputImage);
transform->SetAttribute(ATT_TRANSFORM_MATRIX, TM);
transform->SetAttribute(ATT_TRANSFORM_FILTER, atts.GetUint(eImageFilter));
@ -1250,7 +1346,10 @@ FilterSupport::RenderFilterDescription(DrawTarget* aDT,
FilterNodeGraphFromDescription(aDT, aFilter, aRenderRect,
aSourceGraphic, aSourceGraphicRect, aFillPaint, aFillPaintRect,
aStrokePaint, aStrokePaintRect, aAdditionalImages);
if (!resultFilter) {
gfxWarning() << "Filter is NULL.";
return;
}
aDT->DrawFilter(resultFilter, aRenderRect, aDestPoint, aOptions);
}

View File

@ -1145,7 +1145,10 @@ gfxFcPlatformFontList::GetFontList(nsIAtom *aLangGroup,
gfxFontFamily*
gfxFcPlatformFontList::GetDefaultFont(const gfxFontStyle* aStyle)
{
return FindGenericFamily(NS_LITERAL_STRING("serif"), nsGkAtoms::x_western);
// Get the default font by using a fake name to retrieve the first
// scalable font that fontconfig suggests for the given language.
return FindGenericFamily(NS_LITERAL_STRING("-moz-default"),
aStyle->language);
}
gfxFontEntry*

View File

@ -293,6 +293,7 @@ private:
DECL_GFX_PREF(Live, "layers.composer2d.enabled", Composer2DCompositionEnabled, bool, false);
DECL_GFX_PREF(Once, "layers.d3d11.disable-warp", LayersD3D11DisableWARP, bool, false);
DECL_GFX_PREF(Once, "layers.d3d11.force-warp", LayersD3D11ForceWARP, bool, false);
DECL_GFX_PREF(Live, "layers.deaa.enabled", LayersDEAAEnabled, bool, false);
DECL_GFX_PREF(Live, "layers.draw-bigimage-borders", DrawBigImageBorders, bool, false);
DECL_GFX_PREF(Live, "layers.draw-borders", DrawLayerBorders, bool, false);
DECL_GFX_PREF(Live, "layers.draw-tile-borders", DrawTileBorders, bool, false);

View File

@ -71,7 +71,7 @@ if CONFIG['MOZ_SANDBOX'] and CONFIG['OS_TARGET'] in ('Linux', 'Android'):
# from the function using it which breaks the build. Work around that by
# forcing there to be only one partition.
if '-flto' in CONFIG['OS_CXXFLAGS'] and not CONFIG['CLANG_CXX']:
LDFLAGS += ['--param lto-partitions=1']
LDFLAGS += ['--param lto-partitions=1']
if CONFIG['MOZ_SANDBOX'] and CONFIG['OS_TARGET'] == 'Darwin':
USE_LIBS += [

View File

@ -206,8 +206,9 @@ class BluetoothDaemonConnectionIO final
, public ConnectionOrientedSocketIO
{
public:
BluetoothDaemonConnectionIO(MessageLoop* aIOLoop, int aFd,
ConnectionStatus aConnectionStatus,
BluetoothDaemonConnectionIO(nsIThread* aConsumerThread,
MessageLoop* aIOLoop,
int aFd, ConnectionStatus aConnectionStatus,
BluetoothDaemonConnection* aConnection,
BluetoothDaemonPDUConsumer* aConsumer);
@ -241,10 +242,10 @@ public:
SocketBase* GetSocketBase() override;
bool IsShutdownOnMainThread() const override;
bool IsShutdownOnConsumerThread() const override;
bool IsShutdownOnIOThread() const override;
void ShutdownOnMainThread() override;
void ShutdownOnConsumerThread() override;
void ShutdownOnIOThread() override;
private:
@ -255,14 +256,17 @@ private:
};
BluetoothDaemonConnectionIO::BluetoothDaemonConnectionIO(
MessageLoop* aIOLoop, int aFd,
nsIThread* aConsumerThread,
MessageLoop* aIOLoop,
int aFd,
ConnectionStatus aConnectionStatus,
BluetoothDaemonConnection* aConnection,
BluetoothDaemonPDUConsumer* aConsumer)
: UnixSocketWatcher(aIOLoop, aFd, aConnectionStatus)
, mConnection(aConnection)
, mConsumer(aConsumer)
, mShuttingDownOnIOThread(false)
: UnixSocketWatcher(aIOLoop, aFd, aConnectionStatus)
, ConnectionOrientedSocketIO(aConsumerThread)
, mConnection(aConnection)
, mConsumer(aConsumer)
, mShuttingDownOnIOThread(false)
{
MOZ_ASSERT(mConnection);
MOZ_ASSERT(mConsumer);
@ -308,8 +312,9 @@ BluetoothDaemonConnectionIO::OnConnected()
MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
MOZ_ASSERT(GetConnectionStatus() == SOCKET_IS_CONNECTED);
NS_DispatchToMainThread(
new SocketIOEventRunnable(this, SocketIOEventRunnable::CONNECT_SUCCESS));
GetConsumerThread()->Dispatch(
new SocketIOEventRunnable(this, SocketIOEventRunnable::CONNECT_SUCCESS),
NS_DISPATCH_NORMAL);
AddWatchers(READ_WATCHER, true);
if (HasPendingData()) {
@ -327,9 +332,10 @@ BluetoothDaemonConnectionIO::OnError(const char* aFunction, int aErrno)
// Clean up watchers, status, fd
Close();
// Tell the main thread we've errored
NS_DispatchToMainThread(
new SocketIOEventRunnable(this, SocketIOEventRunnable::CONNECT_ERROR));
// Tell the consumer thread we've errored
GetConsumerThread()->Dispatch(
new SocketIOEventRunnable(this, SocketIOEventRunnable::CONNECT_ERROR),
NS_DISPATCH_NORMAL);
}
// |ConnectionOrientedSocketIO|
@ -397,9 +403,9 @@ BluetoothDaemonConnectionIO::GetSocketBase()
}
bool
BluetoothDaemonConnectionIO::IsShutdownOnMainThread() const
BluetoothDaemonConnectionIO::IsShutdownOnConsumerThread() const
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(IsConsumerThread());
return mConnection == nullptr;
}
@ -411,10 +417,10 @@ BluetoothDaemonConnectionIO::IsShutdownOnIOThread() const
}
void
BluetoothDaemonConnectionIO::ShutdownOnMainThread()
BluetoothDaemonConnectionIO::ShutdownOnConsumerThread()
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!IsShutdownOnMainThread());
MOZ_ASSERT(IsConsumerThread());
MOZ_ASSERT(!IsShutdownOnConsumerThread());
mConnection = nullptr;
}
@ -422,7 +428,7 @@ BluetoothDaemonConnectionIO::ShutdownOnMainThread()
void
BluetoothDaemonConnectionIO::ShutdownOnIOThread()
{
MOZ_ASSERT(!NS_IsMainThread());
MOZ_ASSERT(!IsConsumerThread());
MOZ_ASSERT(!mShuttingDownOnIOThread);
Close(); // will also remove fd from I/O loop
@ -437,10 +443,10 @@ BluetoothDaemonConnection::BluetoothDaemonConnection(
BluetoothDaemonPDUConsumer* aPDUConsumer,
BluetoothDaemonConnectionConsumer* aConsumer,
int aIndex)
: mPDUConsumer(aPDUConsumer)
: mIO(nullptr)
, mPDUConsumer(aPDUConsumer)
, mConsumer(aConsumer)
, mIndex(aIndex)
, mIO(nullptr)
{
MOZ_ASSERT(mConsumer);
}
@ -452,9 +458,10 @@ BluetoothDaemonConnection::~BluetoothDaemonConnection()
nsresult
BluetoothDaemonConnection::PrepareAccept(UnixSocketConnector* aConnector,
nsIThread* aConsumerThread,
MessageLoop* aIOLoop,
ConnectionOrientedSocketIO*& aIO)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!mIO);
// |BluetoothDaemonConnection| now owns the connector, but doesn't
@ -465,7 +472,7 @@ BluetoothDaemonConnection::PrepareAccept(UnixSocketConnector* aConnector,
SetConnectionStatus(SOCKET_CONNECTING);
mIO = new BluetoothDaemonConnectionIO(
XRE_GetIOMessageLoop(), -1, UnixSocketWatcher::SOCKET_IS_CONNECTING,
aConsumerThread, aIOLoop, -1, UnixSocketWatcher::SOCKET_IS_CONNECTING,
this, mPDUConsumer);
aIO = mIO;
@ -477,10 +484,10 @@ BluetoothDaemonConnection::PrepareAccept(UnixSocketConnector* aConnector,
void
BluetoothDaemonConnection::SendSocketData(UnixSocketIOBuffer* aBuffer)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mIO);
MOZ_ASSERT(mIO->IsConsumerThread());
XRE_GetIOMessageLoop()->PostTask(
mIO->GetIOLoop()->PostTask(
FROM_HERE,
new SocketIOSendTask<BluetoothDaemonConnectionIO,
UnixSocketIOBuffer>(mIO, aBuffer));
@ -491,15 +498,15 @@ BluetoothDaemonConnection::SendSocketData(UnixSocketIOBuffer* aBuffer)
void
BluetoothDaemonConnection::Close()
{
MOZ_ASSERT(NS_IsMainThread());
if (!mIO) {
CHROMIUM_LOG("Bluetooth daemon already disconnected!");
return;
}
XRE_GetIOMessageLoop()->PostTask(FROM_HERE, new SocketIOShutdownTask(mIO));
MOZ_ASSERT(mIO->IsConsumerThread());
mIO->ShutdownOnConsumerThread();
mIO->GetIOLoop()->PostTask(FROM_HERE, new SocketIOShutdownTask(mIO));
mIO = nullptr;
NotifyDisconnect();
@ -508,24 +515,18 @@ BluetoothDaemonConnection::Close()
void
BluetoothDaemonConnection::OnConnectSuccess()
{
MOZ_ASSERT(NS_IsMainThread());
mConsumer->OnConnectSuccess(mIndex);
}
void
BluetoothDaemonConnection::OnConnectError()
{
MOZ_ASSERT(NS_IsMainThread());
mConsumer->OnConnectError(mIndex);
}
void
BluetoothDaemonConnection::OnDisconnect()
{
MOZ_ASSERT(NS_IsMainThread());
mConsumer->OnDisconnect(mIndex);
}

View File

@ -12,6 +12,8 @@
#include "mozilla/ipc/ConnectionOrientedSocket.h"
#include "nsAutoPtr.h"
class MessageLoop;
namespace mozilla {
namespace ipc {
@ -92,7 +94,7 @@ private:
/*
* |BluetoothDaemonPDUConsumer| processes incoming PDUs from the Bluetooth
* daemon. Please note that its method |Handle| runs on a different than the
* main thread.
* consumer thread.
*/
class BluetoothDaemonPDUConsumer
{
@ -123,6 +125,8 @@ public:
//
nsresult PrepareAccept(UnixSocketConnector* aConnector,
nsIThread* aConsumerThread,
MessageLoop* aIOLoop,
ConnectionOrientedSocketIO*& aIO) override;
// Methods for |DataSocket|
@ -139,10 +143,10 @@ public:
void OnDisconnect() override;
private:
BluetoothDaemonConnectionIO* mIO;
BluetoothDaemonPDUConsumer* mPDUConsumer;
BluetoothDaemonConnectionConsumer* mConsumer;
int mIndex;
BluetoothDaemonConnectionIO* mIO;
};
}

Some files were not shown because too many files have changed in this diff Show More