зеркало из https://github.com/mozilla/gecko-dev.git
Merge m-c to fx-team a=merge
This commit is contained in:
Коммит
047e5c3642
|
@ -788,6 +788,9 @@ pref("dom.ipc.systemMessageCPULockTimeoutSec", 30);
|
|||
// Ignore the "dialog=1" feature in window.open.
|
||||
pref("dom.disable_window_open_dialog_feature", true);
|
||||
|
||||
// Enable before keyboard events and after keyboard events.
|
||||
pref("dom.beforeAfterKeyboardEvent.enabled", true);
|
||||
|
||||
// Screen reader support
|
||||
pref("accessibility.accessfu.activate", 2);
|
||||
pref("accessibility.accessfu.quicknav_modes", "Link,Heading,FormElement,Landmark,ListItem");
|
||||
|
@ -873,6 +876,8 @@ pref("general.useragent.updates.enabled", true);
|
|||
pref("general.useragent.updates.url", "https://dynamicua.cdn.mozilla.net/0/%APP_ID%");
|
||||
pref("general.useragent.updates.interval", 604800); // 1 week
|
||||
pref("general.useragent.updates.retry", 86400); // 1 day
|
||||
// Device ID can be composed of letter, numbers, hyphen ("-") and dot (".")
|
||||
pref("general.useragent.device_id", "");
|
||||
|
||||
// Make <audio> and <video> talk to the AudioChannelService.
|
||||
pref("media.useAudioChannelService", true);
|
||||
|
|
|
@ -324,6 +324,8 @@ var shell = {
|
|||
chromeEventHandler.addEventListener('keydown', this, true);
|
||||
chromeEventHandler.addEventListener('keypress', this, true);
|
||||
chromeEventHandler.addEventListener('keyup', this, true);
|
||||
chromeEventHandler.addEventListener('mozbrowserbeforekeydown', this, true);
|
||||
chromeEventHandler.addEventListener('mozbrowserbeforekeyup', this, true);
|
||||
|
||||
window.addEventListener('MozApplicationManifest', this);
|
||||
window.addEventListener('mozfullscreenchange', this);
|
||||
|
@ -356,6 +358,8 @@ var shell = {
|
|||
window.removeEventListener('keydown', this, true);
|
||||
window.removeEventListener('keypress', this, true);
|
||||
window.removeEventListener('keyup', this, true);
|
||||
window.removeEventListener('mozbrowserbeforekeydown', this, true);
|
||||
window.removeEventListener('mozbrowserbeforekeyup', this, true);
|
||||
window.removeEventListener('MozApplicationManifest', this);
|
||||
window.removeEventListener('mozfullscreenchange', this);
|
||||
window.removeEventListener('sizemodechange', this);
|
||||
|
@ -420,17 +424,14 @@ var shell = {
|
|||
return;
|
||||
}
|
||||
|
||||
// If we didn't return, then the key event represents a hardware key
|
||||
// and we need to prevent it from propagating to Gaia
|
||||
evt.stopImmediatePropagation();
|
||||
evt.preventDefault(); // Prevent keypress events (when #501496 is fixed).
|
||||
|
||||
// If it is a key down or key up event, we send a chrome event to Gaia.
|
||||
// If it is a keypress event we just ignore it.
|
||||
switch (evt.type) {
|
||||
case 'mozbrowserbeforekeydown':
|
||||
case 'keydown':
|
||||
type = type + '-press';
|
||||
break;
|
||||
case 'mozbrowserbeforekeyup':
|
||||
case 'keyup':
|
||||
type = type + '-release';
|
||||
break;
|
||||
|
@ -473,6 +474,8 @@ var shell = {
|
|||
case 'keydown':
|
||||
case 'keyup':
|
||||
case 'keypress':
|
||||
case 'mozbrowserbeforekeydown':
|
||||
case 'mozbrowserbeforekeyup':
|
||||
this.filterHardwareKeys(evt);
|
||||
break;
|
||||
case 'mozfullscreenchange':
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<project name="platform_build" path="build" remote="b2g" revision="3a2947df41a480de1457a6dcdbf46ad0af70d8e0">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="de254419f3553f48187d003ee8e38034b429f069"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="5f1f0960ae9d22acf2a324ad37a48174d6df87f6"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
|
@ -23,7 +23,7 @@
|
|||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
|
||||
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="6ca2008ac50b163d31244ef9f036cb224f4f229b"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="9f6b7471c881ee689183d681658cf2ba3dfc5610"/>
|
||||
<!-- Stock Android things -->
|
||||
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/>
|
||||
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="ebdad82e61c16772f6cd47e9f11936bf6ebe9aa0"/>
|
||||
|
|
|
@ -19,13 +19,13 @@
|
|||
<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="de254419f3553f48187d003ee8e38034b429f069"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="5f1f0960ae9d22acf2a324ad37a48174d6df87f6"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>
|
||||
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="c058843242068d0df7c107e09da31b53d2e08fa6"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="6ca2008ac50b163d31244ef9f036cb224f4f229b"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="9f6b7471c881ee689183d681658cf2ba3dfc5610"/>
|
||||
<!-- Stock Android things -->
|
||||
<project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
|
||||
<project name="platform/bionic" path="bionic" revision="c72b8f6359de7ed17c11ddc9dfdde3f615d188a9"/>
|
||||
|
|
|
@ -17,10 +17,10 @@
|
|||
</project>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="de254419f3553f48187d003ee8e38034b429f069"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="5f1f0960ae9d22acf2a324ad37a48174d6df87f6"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="6ca2008ac50b163d31244ef9f036cb224f4f229b"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="9f6b7471c881ee689183d681658cf2ba3dfc5610"/>
|
||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
|
||||
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
|
||||
<!-- Stock Android things -->
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<project name="platform_build" path="build" remote="b2g" revision="3a2947df41a480de1457a6dcdbf46ad0af70d8e0">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="de254419f3553f48187d003ee8e38034b429f069"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="5f1f0960ae9d22acf2a324ad37a48174d6df87f6"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
|
@ -23,7 +23,7 @@
|
|||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
|
||||
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="6ca2008ac50b163d31244ef9f036cb224f4f229b"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="9f6b7471c881ee689183d681658cf2ba3dfc5610"/>
|
||||
<!-- 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"/>
|
||||
|
|
|
@ -19,13 +19,13 @@
|
|||
<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="de254419f3553f48187d003ee8e38034b429f069"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="5f1f0960ae9d22acf2a324ad37a48174d6df87f6"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>
|
||||
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="c058843242068d0df7c107e09da31b53d2e08fa6"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="6ca2008ac50b163d31244ef9f036cb224f4f229b"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="9f6b7471c881ee689183d681658cf2ba3dfc5610"/>
|
||||
<!-- Stock Android things -->
|
||||
<project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
|
||||
<project name="platform/bionic" path="bionic" revision="c72b8f6359de7ed17c11ddc9dfdde3f615d188a9"/>
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<project name="platform_build" path="build" remote="b2g" revision="3a2947df41a480de1457a6dcdbf46ad0af70d8e0">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="de254419f3553f48187d003ee8e38034b429f069"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="5f1f0960ae9d22acf2a324ad37a48174d6df87f6"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
|
@ -23,7 +23,7 @@
|
|||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
|
||||
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="6ca2008ac50b163d31244ef9f036cb224f4f229b"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="9f6b7471c881ee689183d681658cf2ba3dfc5610"/>
|
||||
<!-- 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"/>
|
||||
|
@ -133,7 +133,7 @@
|
|||
<project name="device/generic/armv7-a-neon" path="device/generic/armv7-a-neon" revision="1bb28abbc215f45220620af5cd60a8ac1be93722"/>
|
||||
<project name="device/qcom/common" path="device/qcom/common" revision="54c32c2ddef066fbdf611d29e4b7c47e0363599e"/>
|
||||
<project name="device-flame" path="device/t2m/flame" remote="b2g" revision="52c909e821d107d414f851e267dedcd7aae2cebf"/>
|
||||
<project name="codeaurora_kernel_msm" path="kernel" remote="b2g" revision="1072f7d31dc0bf3a2adc64177b1104da9f4ce4b6"/>
|
||||
<project name="codeaurora_kernel_msm" path="kernel" remote="b2g" revision="7731d63c809dbca4da408e1de0c1a044f0765e52"/>
|
||||
<project name="kernel_lk" path="bootable/bootloader/lk" remote="b2g" revision="fda40423ffa573dc6cafd3780515010cb2a086be"/>
|
||||
<project name="platform/external/bluetooth/bluedroid" path="external/bluetooth/bluedroid" revision="30b96dfca99cb384bf520a16b81f3aba56f09907"/>
|
||||
<project name="platform/external/wpa_supplicant_8" path="external/wpa_supplicant_8" revision="5b71e40213f650459e95d35b6f14af7e88d8ab62"/>
|
||||
|
|
|
@ -17,10 +17,10 @@
|
|||
</project>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="de254419f3553f48187d003ee8e38034b429f069"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="5f1f0960ae9d22acf2a324ad37a48174d6df87f6"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="6ca2008ac50b163d31244ef9f036cb224f4f229b"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="9f6b7471c881ee689183d681658cf2ba3dfc5610"/>
|
||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
|
||||
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
|
||||
<!-- Stock Android things -->
|
||||
|
|
|
@ -4,6 +4,6 @@
|
|||
"remote": "",
|
||||
"branch": ""
|
||||
},
|
||||
"revision": "3e3eb020773e765f4cb7775356ae9c22896db875",
|
||||
"revision": "b4f77d39d6d8eb153ede94f8a0d70247ccad74e8",
|
||||
"repo_path": "/integration/gaia-central"
|
||||
}
|
||||
|
|
|
@ -17,12 +17,12 @@
|
|||
<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="de254419f3553f48187d003ee8e38034b429f069"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="5f1f0960ae9d22acf2a324ad37a48174d6df87f6"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="6ca2008ac50b163d31244ef9f036cb224f4f229b"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="9f6b7471c881ee689183d681658cf2ba3dfc5610"/>
|
||||
<!-- Stock Android things -->
|
||||
<project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
|
||||
<project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<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="de254419f3553f48187d003ee8e38034b429f069"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="5f1f0960ae9d22acf2a324ad37a48174d6df87f6"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
|
|
|
@ -17,10 +17,10 @@
|
|||
</project>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="de254419f3553f48187d003ee8e38034b429f069"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="5f1f0960ae9d22acf2a324ad37a48174d6df87f6"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="6ca2008ac50b163d31244ef9f036cb224f4f229b"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="9f6b7471c881ee689183d681658cf2ba3dfc5610"/>
|
||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
|
||||
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
|
||||
<!-- Stock Android things -->
|
||||
|
|
|
@ -17,12 +17,12 @@
|
|||
<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="de254419f3553f48187d003ee8e38034b429f069"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="5f1f0960ae9d22acf2a324ad37a48174d6df87f6"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="6ca2008ac50b163d31244ef9f036cb224f4f229b"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="9f6b7471c881ee689183d681658cf2ba3dfc5610"/>
|
||||
<project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
|
||||
<!-- Stock Android things -->
|
||||
<project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
|
||||
|
|
|
@ -2361,8 +2361,8 @@ public:
|
|||
virtual nsHTMLDocument* AsHTMLDocument() { return nullptr; }
|
||||
virtual mozilla::dom::SVGDocument* AsSVGDocument() { return nullptr; }
|
||||
|
||||
// Each import tree has exactly one master document which is
|
||||
// the root of the tree, and owns the browser context.
|
||||
// The root document of the import tree. If this document is not an import
|
||||
// this will return the document itself.
|
||||
virtual nsIDocument* MasterDocument() = 0;
|
||||
virtual void SetMasterDocument(nsIDocument* master) = 0;
|
||||
virtual bool IsMasterDocument() = 0;
|
||||
|
|
|
@ -83,13 +83,9 @@ public:
|
|||
, mDisconnected(false)
|
||||
, mCloseEventWasClean(false)
|
||||
, mCloseEventCode(nsIWebSocketChannel::CLOSE_ABNORMAL)
|
||||
, mOutgoingBufferedAmount(0)
|
||||
, mBinaryType(dom::BinaryType::Blob)
|
||||
, mScriptLine(0)
|
||||
, mInnerWindowID(0)
|
||||
, mMutex("WebSocketImpl::mMutex")
|
||||
, mWorkerPrivate(nullptr)
|
||||
, mReadyState(WebSocket::CONNECTING)
|
||||
{
|
||||
if (!NS_IsMainThread()) {
|
||||
mWorkerPrivate = GetCurrentThreadWorkerPrivate();
|
||||
|
@ -104,51 +100,6 @@ public:
|
|||
|
||||
bool IsTargetThread() const;
|
||||
|
||||
uint16_t ReadyState()
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
return mReadyState;
|
||||
}
|
||||
|
||||
void SetReadyState(uint16_t aReadyState)
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
mReadyState = aReadyState;
|
||||
}
|
||||
|
||||
uint32_t BufferedAmount() const
|
||||
{
|
||||
AssertIsOnTargetThread();
|
||||
return mOutgoingBufferedAmount;
|
||||
}
|
||||
|
||||
dom::BinaryType BinaryType() const
|
||||
{
|
||||
AssertIsOnTargetThread();
|
||||
return mBinaryType;
|
||||
}
|
||||
|
||||
void SetBinaryType(dom::BinaryType aData)
|
||||
{
|
||||
AssertIsOnTargetThread();
|
||||
mBinaryType = aData;
|
||||
}
|
||||
|
||||
void GetUrl(nsAString& aURL) const
|
||||
{
|
||||
AssertIsOnTargetThread();
|
||||
|
||||
if (mEffectiveURL.IsEmpty()) {
|
||||
aURL = mOriginalURL;
|
||||
} else {
|
||||
aURL = mEffectiveURL;
|
||||
}
|
||||
}
|
||||
|
||||
void Close(const Optional<uint16_t>& aCode,
|
||||
const Optional<nsAString>& aReason,
|
||||
ErrorResult& aRv);
|
||||
|
||||
void Init(JSContext* aCx,
|
||||
nsIPrincipal* aPrincipal,
|
||||
const nsAString& aURL,
|
||||
|
@ -160,12 +111,6 @@ public:
|
|||
|
||||
void AsyncOpen(ErrorResult& aRv);
|
||||
|
||||
void Send(nsIInputStream* aMsgStream,
|
||||
const nsACString& aMsgString,
|
||||
uint32_t aMsgLength,
|
||||
bool aIsBinary,
|
||||
ErrorResult& aRv);
|
||||
|
||||
nsresult ParseURL(const nsAString& aURL);
|
||||
nsresult InitializeConnection();
|
||||
|
||||
|
@ -212,9 +157,6 @@ public:
|
|||
|
||||
nsCOMPtr<nsIWebSocketChannel> mChannel;
|
||||
|
||||
// related to the WebSocket constructor steps
|
||||
nsString mOriginalURL;
|
||||
nsString mEffectiveURL; // after redirects
|
||||
bool mSecure; // if true it is using SSL and the wss scheme,
|
||||
// otherwise it is using the ws scheme with no SSL
|
||||
|
||||
|
@ -234,16 +176,10 @@ public:
|
|||
|
||||
nsCString mURI;
|
||||
nsCString mRequestedProtocolList;
|
||||
nsCString mEstablishedProtocol;
|
||||
nsCString mEstablishedExtensions;
|
||||
|
||||
nsCOMPtr<nsIPrincipal> mPrincipal;
|
||||
nsWeakPtr mOriginDocument;
|
||||
|
||||
uint32_t mOutgoingBufferedAmount;
|
||||
|
||||
dom::BinaryType mBinaryType;
|
||||
|
||||
// Web Socket owner information:
|
||||
// - the script file name, UTF8 encoded.
|
||||
// - source code line number where the Web Socket object was constructed.
|
||||
|
@ -254,10 +190,6 @@ public:
|
|||
uint32_t mScriptLine;
|
||||
uint64_t mInnerWindowID;
|
||||
|
||||
// This mutex protects mReadyState that is the only variable that is used in
|
||||
// different threads.
|
||||
mozilla::Mutex mMutex;
|
||||
|
||||
WorkerPrivate* mWorkerPrivate;
|
||||
nsAutoPtr<WorkerFeature> mWorkerFeature;
|
||||
|
||||
|
@ -269,9 +201,6 @@ private:
|
|||
Disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
// This value should not be used directly but use ReadyState() instead.
|
||||
uint16_t mReadyState;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(WebSocketImpl,
|
||||
|
@ -450,7 +379,7 @@ WebSocketImpl::CloseConnection(uint16_t aReasonCode,
|
|||
{
|
||||
AssertIsOnTargetThread();
|
||||
|
||||
uint16_t readyState = ReadyState();
|
||||
uint16_t readyState = mWebSocket->ReadyState();
|
||||
if (readyState == WebSocket::CLOSING ||
|
||||
readyState == WebSocket::CLOSED) {
|
||||
return NS_OK;
|
||||
|
@ -458,7 +387,7 @@ WebSocketImpl::CloseConnection(uint16_t aReasonCode,
|
|||
|
||||
// The common case...
|
||||
if (mChannel) {
|
||||
SetReadyState(WebSocket::CLOSING);
|
||||
mWebSocket->SetReadyState(WebSocket::CLOSING);
|
||||
|
||||
// The channel has to be closed on the main-thread.
|
||||
|
||||
|
@ -481,7 +410,7 @@ WebSocketImpl::CloseConnection(uint16_t aReasonCode,
|
|||
mCloseEventCode = aReasonCode;
|
||||
CopyUTF8toUTF16(aReasonString, mCloseEventReason);
|
||||
|
||||
SetReadyState(WebSocket::CLOSING);
|
||||
mWebSocket->SetReadyState(WebSocket::CLOSING);
|
||||
|
||||
// Can be called from Cancel() or Init() codepaths, so need to dispatch
|
||||
// onerror/onclose asynchronously
|
||||
|
@ -503,7 +432,7 @@ WebSocketImpl::ConsoleError()
|
|||
NS_ConvertUTF8toUTF16 specUTF16(mURI);
|
||||
const char16_t* formatStrings[] = { specUTF16.get() };
|
||||
|
||||
if (ReadyState() < WebSocket::OPEN) {
|
||||
if (mWebSocket->ReadyState() < WebSocket::OPEN) {
|
||||
PrintErrorOnConsole("chrome://global/locale/appstrings.properties",
|
||||
MOZ_UTF16("connectionFailure"),
|
||||
formatStrings, ArrayLength(formatStrings));
|
||||
|
@ -621,7 +550,7 @@ WebSocketImpl::DoOnMessageAvailable(const nsACString& aMsg, bool isBinary)
|
|||
{
|
||||
AssertIsOnTargetThread();
|
||||
|
||||
int16_t readyState = ReadyState();
|
||||
int16_t readyState = mWebSocket->ReadyState();
|
||||
if (readyState == WebSocket::CLOSED) {
|
||||
NS_ERROR("Received message after CLOSED");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
|
@ -664,7 +593,7 @@ WebSocketImpl::OnStart(nsISupports* aContext)
|
|||
{
|
||||
AssertIsOnTargetThread();
|
||||
|
||||
int16_t readyState = ReadyState();
|
||||
int16_t readyState = mWebSocket->ReadyState();
|
||||
|
||||
// This is the only function that sets OPEN, and should be called only once
|
||||
MOZ_ASSERT(readyState != WebSocket::OPEN,
|
||||
|
@ -683,13 +612,13 @@ WebSocketImpl::OnStart(nsISupports* aContext)
|
|||
}
|
||||
|
||||
if (!mRequestedProtocolList.IsEmpty()) {
|
||||
mChannel->GetProtocol(mEstablishedProtocol);
|
||||
mChannel->GetProtocol(mWebSocket->mEstablishedProtocol);
|
||||
}
|
||||
|
||||
mChannel->GetExtensions(mEstablishedExtensions);
|
||||
mChannel->GetExtensions(mWebSocket->mEstablishedExtensions);
|
||||
UpdateURI();
|
||||
|
||||
SetReadyState(WebSocket::OPEN);
|
||||
mWebSocket->SetReadyState(WebSocket::OPEN);
|
||||
|
||||
// Call 'onopen'
|
||||
rv = mWebSocket->CreateAndDispatchSimpleEvent(NS_LITERAL_STRING("open"));
|
||||
|
@ -710,7 +639,7 @@ WebSocketImpl::OnStop(nsISupports* aContext, nsresult aStatusCode)
|
|||
// We can be CONNECTING here if connection failed.
|
||||
// We can be OPEN if we have encountered a fatal protocol error
|
||||
// We can be CLOSING if close() was called and/or server initiated close.
|
||||
MOZ_ASSERT(ReadyState() != WebSocket::CLOSED,
|
||||
MOZ_ASSERT(mWebSocket->ReadyState() != WebSocket::CLOSED,
|
||||
"Shouldn't already be CLOSED when OnStop called");
|
||||
|
||||
// called by network stack, not JS, so can dispatch JS events synchronously
|
||||
|
@ -755,11 +684,11 @@ WebSocketImpl::OnAcknowledge(nsISupports *aContext, uint32_t aSize)
|
|||
{
|
||||
AssertIsOnTargetThread();
|
||||
|
||||
if (aSize > mOutgoingBufferedAmount) {
|
||||
if (aSize > mWebSocket->mOutgoingBufferedAmount) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
mOutgoingBufferedAmount -= aSize;
|
||||
mWebSocket->mOutgoingBufferedAmount -= aSize;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -769,7 +698,7 @@ WebSocketImpl::OnServerClose(nsISupports *aContext, uint16_t aCode,
|
|||
{
|
||||
AssertIsOnTargetThread();
|
||||
|
||||
int16_t readyState = ReadyState();
|
||||
int16_t readyState = mWebSocket->ReadyState();
|
||||
|
||||
MOZ_ASSERT(readyState != WebSocket::CONNECTING,
|
||||
"Received server close before connected?");
|
||||
|
@ -807,7 +736,7 @@ WebSocketImpl::GetInterface(const nsIID& aIID, void** aResult)
|
|||
{
|
||||
AssertIsOnMainThread();
|
||||
|
||||
if (ReadyState() == WebSocket::CLOSED) {
|
||||
if (!mWebSocket || mWebSocket->ReadyState() == WebSocket::CLOSED) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
|
@ -841,6 +770,10 @@ WebSocket::WebSocket(nsPIDOMWindow* aOwnerWindow)
|
|||
, mWorkerPrivate(nullptr)
|
||||
, mKeepingAlive(false)
|
||||
, mCheckMustKeepAlive(true)
|
||||
, mOutgoingBufferedAmount(0)
|
||||
, mBinaryType(dom::BinaryType::Blob)
|
||||
, mMutex("WebSocketImpl::mMutex")
|
||||
, mReadyState(CONNECTING)
|
||||
{
|
||||
mImpl = new WebSocketImpl(this);
|
||||
mWorkerPrivate = mImpl->mWorkerPrivate;
|
||||
|
@ -1490,7 +1423,7 @@ void
|
|||
WebSocketImpl::DispatchConnectionCloseEvents()
|
||||
{
|
||||
AssertIsOnTargetThread();
|
||||
SetReadyState(WebSocket::CLOSED);
|
||||
mWebSocket->SetReadyState(WebSocket::CLOSED);
|
||||
|
||||
// Call 'onerror' if needed
|
||||
if (mFailed) {
|
||||
|
@ -1516,7 +1449,7 @@ nsresult
|
|||
WebSocket::CreateAndDispatchSimpleEvent(const nsAString& aName)
|
||||
{
|
||||
MOZ_ASSERT(mImpl);
|
||||
mImpl->AssertIsOnTargetThread();
|
||||
AssertIsOnTargetThread();
|
||||
|
||||
nsresult rv = CheckInnerWindowCorrectness();
|
||||
if (NS_FAILED(rv)) {
|
||||
|
@ -1541,7 +1474,7 @@ WebSocket::CreateAndDispatchMessageEvent(const nsACString& aData,
|
|||
bool aIsBinary)
|
||||
{
|
||||
MOZ_ASSERT(mImpl);
|
||||
mImpl->AssertIsOnTargetThread();
|
||||
AssertIsOnTargetThread();
|
||||
|
||||
AutoJSAPI jsapi;
|
||||
|
||||
|
@ -1565,7 +1498,7 @@ WebSocket::CreateAndDispatchMessageEvent(JSContext* aCx,
|
|||
bool aIsBinary)
|
||||
{
|
||||
MOZ_ASSERT(mImpl);
|
||||
mImpl->AssertIsOnTargetThread();
|
||||
AssertIsOnTargetThread();
|
||||
|
||||
nsresult rv = CheckInnerWindowCorrectness();
|
||||
if (NS_FAILED(rv)) {
|
||||
|
@ -1575,11 +1508,11 @@ WebSocket::CreateAndDispatchMessageEvent(JSContext* aCx,
|
|||
// Create appropriate JS object for message
|
||||
JS::Rooted<JS::Value> jsData(aCx);
|
||||
if (aIsBinary) {
|
||||
if (mImpl->mBinaryType == dom::BinaryType::Blob) {
|
||||
if (mBinaryType == dom::BinaryType::Blob) {
|
||||
nsresult rv = nsContentUtils::CreateBlobBuffer(aCx, GetOwner(), aData,
|
||||
&jsData);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
} else if (mImpl->mBinaryType == dom::BinaryType::Arraybuffer) {
|
||||
} else if (mBinaryType == dom::BinaryType::Arraybuffer) {
|
||||
JS::Rooted<JSObject*> arrayBuf(aCx);
|
||||
nsresult rv = nsContentUtils::CreateArrayBuffer(aCx, aData,
|
||||
arrayBuf.address());
|
||||
|
@ -1625,7 +1558,7 @@ WebSocket::CreateAndDispatchCloseEvent(bool aWasClean,
|
|||
const nsAString &aReason)
|
||||
{
|
||||
MOZ_ASSERT(mImpl);
|
||||
mImpl->AssertIsOnTargetThread();
|
||||
AssertIsOnTargetThread();
|
||||
|
||||
nsresult rv = CheckInnerWindowCorrectness();
|
||||
if (NS_FAILED(rv)) {
|
||||
|
@ -1767,7 +1700,7 @@ WebSocketImpl::ParseURL(const nsAString& aURL)
|
|||
}
|
||||
}
|
||||
|
||||
mOriginalURL = aURL;
|
||||
mWebSocket->mOriginalURL = aURL;
|
||||
|
||||
rv = parsedURL->GetSpec(mURI);
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
|
@ -1795,9 +1728,9 @@ WebSocket::UpdateMustKeepAlive()
|
|||
bool shouldKeepAlive = false;
|
||||
|
||||
if (mListenerManager) {
|
||||
switch (mImpl->ReadyState())
|
||||
switch (ReadyState())
|
||||
{
|
||||
case WebSocket::CONNECTING:
|
||||
case CONNECTING:
|
||||
{
|
||||
if (mListenerManager->HasListenersFor(nsGkAtoms::onopen) ||
|
||||
mListenerManager->HasListenersFor(nsGkAtoms::onmessage) ||
|
||||
|
@ -1808,19 +1741,19 @@ WebSocket::UpdateMustKeepAlive()
|
|||
}
|
||||
break;
|
||||
|
||||
case WebSocket::OPEN:
|
||||
case WebSocket::CLOSING:
|
||||
case OPEN:
|
||||
case CLOSING:
|
||||
{
|
||||
if (mListenerManager->HasListenersFor(nsGkAtoms::onmessage) ||
|
||||
mListenerManager->HasListenersFor(nsGkAtoms::onerror) ||
|
||||
mListenerManager->HasListenersFor(nsGkAtoms::onclose) ||
|
||||
mImpl->mOutgoingBufferedAmount != 0) {
|
||||
mOutgoingBufferedAmount != 0) {
|
||||
shouldKeepAlive = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case WebSocket::CLOSED:
|
||||
case CLOSED:
|
||||
{
|
||||
shouldKeepAlive = false;
|
||||
}
|
||||
|
@ -1940,7 +1873,7 @@ WebSocketImpl::UpdateURI()
|
|||
channel = static_cast<BaseWebSocketChannel*>(mChannel.get());
|
||||
MOZ_ASSERT(channel);
|
||||
|
||||
channel->GetEffectiveURL(mEffectiveURL);
|
||||
channel->GetEffectiveURL(mWebSocket->mEffectiveURL);
|
||||
mSecure = channel->IsEncrypted();
|
||||
|
||||
return NS_OK;
|
||||
|
@ -1966,62 +1899,70 @@ WebSocket::EventListenerRemoved(nsIAtom* aType)
|
|||
|
||||
// webIDL: readonly attribute unsigned short readyState;
|
||||
uint16_t
|
||||
WebSocket::ReadyState() const
|
||||
WebSocket::ReadyState()
|
||||
{
|
||||
MOZ_ASSERT(mImpl);
|
||||
return mImpl->ReadyState();
|
||||
MutexAutoLock lock(mMutex);
|
||||
return mReadyState;
|
||||
}
|
||||
|
||||
void
|
||||
WebSocket::SetReadyState(uint16_t aReadyState)
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
mReadyState = aReadyState;
|
||||
}
|
||||
|
||||
// webIDL: readonly attribute unsigned long bufferedAmount;
|
||||
uint32_t
|
||||
WebSocket::BufferedAmount() const
|
||||
{
|
||||
MOZ_ASSERT(mImpl);
|
||||
return mImpl->BufferedAmount();
|
||||
AssertIsOnTargetThread();
|
||||
return mOutgoingBufferedAmount;
|
||||
}
|
||||
|
||||
// webIDL: attribute BinaryType binaryType;
|
||||
dom::BinaryType
|
||||
WebSocket::BinaryType() const
|
||||
{
|
||||
MOZ_ASSERT(mImpl);
|
||||
return mImpl->BinaryType();
|
||||
AssertIsOnTargetThread();
|
||||
return mBinaryType;
|
||||
}
|
||||
|
||||
// webIDL: attribute BinaryType binaryType;
|
||||
void
|
||||
WebSocket::SetBinaryType(dom::BinaryType aData)
|
||||
{
|
||||
MOZ_ASSERT(mImpl);
|
||||
mImpl->SetBinaryType(aData);
|
||||
AssertIsOnTargetThread();
|
||||
mBinaryType = aData;
|
||||
}
|
||||
|
||||
// webIDL: readonly attribute DOMString url
|
||||
void
|
||||
WebSocket::GetUrl(nsAString& aURL)
|
||||
{
|
||||
MOZ_ASSERT(mImpl);
|
||||
mImpl->GetUrl(aURL);
|
||||
AssertIsOnTargetThread();
|
||||
|
||||
if (mEffectiveURL.IsEmpty()) {
|
||||
aURL = mOriginalURL;
|
||||
} else {
|
||||
aURL = mEffectiveURL;
|
||||
}
|
||||
}
|
||||
|
||||
// webIDL: readonly attribute DOMString extensions;
|
||||
void
|
||||
WebSocket::GetExtensions(nsAString& aExtensions)
|
||||
{
|
||||
MOZ_ASSERT(mImpl);
|
||||
mImpl->AssertIsOnTargetThread();
|
||||
|
||||
CopyUTF8toUTF16(mImpl->mEstablishedExtensions, aExtensions);
|
||||
AssertIsOnTargetThread();
|
||||
CopyUTF8toUTF16(mEstablishedExtensions, aExtensions);
|
||||
}
|
||||
|
||||
// webIDL: readonly attribute DOMString protocol;
|
||||
void
|
||||
WebSocket::GetProtocol(nsAString& aProtocol)
|
||||
{
|
||||
MOZ_ASSERT(mImpl);
|
||||
mImpl->AssertIsOnTargetThread();
|
||||
|
||||
CopyUTF8toUTF16(mImpl->mEstablishedProtocol, aProtocol);
|
||||
AssertIsOnTargetThread();
|
||||
CopyUTF8toUTF16(mEstablishedProtocol, aProtocol);
|
||||
}
|
||||
|
||||
// webIDL: void send(DOMString data);
|
||||
|
@ -2029,16 +1970,17 @@ void
|
|||
WebSocket::Send(const nsAString& aData,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(mImpl);
|
||||
mImpl->AssertIsOnTargetThread();
|
||||
AssertIsOnTargetThread();
|
||||
|
||||
NS_ConvertUTF16toUTF8 msgString(aData);
|
||||
mImpl->Send(nullptr, msgString, msgString.Length(), false, aRv);
|
||||
Send(nullptr, msgString, msgString.Length(), false, aRv);
|
||||
}
|
||||
|
||||
void
|
||||
WebSocket::Send(File& aData, ErrorResult& aRv)
|
||||
{
|
||||
AssertIsOnTargetThread();
|
||||
|
||||
nsCOMPtr<nsIInputStream> msgStream;
|
||||
nsresult rv = aData.GetInternalStream(getter_AddRefs(msgStream));
|
||||
if (NS_FAILED(rv)) {
|
||||
|
@ -2058,15 +2000,14 @@ WebSocket::Send(File& aData, ErrorResult& aRv)
|
|||
return;
|
||||
}
|
||||
|
||||
mImpl->Send(msgStream, EmptyCString(), msgLength, true, aRv);
|
||||
Send(msgStream, EmptyCString(), msgLength, true, aRv);
|
||||
}
|
||||
|
||||
void
|
||||
WebSocket::Send(const ArrayBuffer& aData,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(mImpl);
|
||||
mImpl->AssertIsOnTargetThread();
|
||||
AssertIsOnTargetThread();
|
||||
|
||||
aData.ComputeLengthAndData();
|
||||
|
||||
|
@ -2076,15 +2017,14 @@ WebSocket::Send(const ArrayBuffer& aData,
|
|||
char* data = reinterpret_cast<char*>(aData.Data());
|
||||
|
||||
nsDependentCSubstring msgString(data, len);
|
||||
mImpl->Send(nullptr, msgString, len, true, aRv);
|
||||
Send(nullptr, msgString, len, true, aRv);
|
||||
}
|
||||
|
||||
void
|
||||
WebSocket::Send(const ArrayBufferView& aData,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(mImpl);
|
||||
mImpl->AssertIsOnTargetThread();
|
||||
AssertIsOnTargetThread();
|
||||
|
||||
aData.ComputeLengthAndData();
|
||||
|
||||
|
@ -2094,20 +2034,20 @@ WebSocket::Send(const ArrayBufferView& aData,
|
|||
char* data = reinterpret_cast<char*>(aData.Data());
|
||||
|
||||
nsDependentCSubstring msgString(data, len);
|
||||
mImpl->Send(nullptr, msgString, len, true, aRv);
|
||||
Send(nullptr, msgString, len, true, aRv);
|
||||
}
|
||||
|
||||
void
|
||||
WebSocketImpl::Send(nsIInputStream* aMsgStream,
|
||||
const nsACString& aMsgString,
|
||||
uint32_t aMsgLength,
|
||||
bool aIsBinary,
|
||||
ErrorResult& aRv)
|
||||
WebSocket::Send(nsIInputStream* aMsgStream,
|
||||
const nsACString& aMsgString,
|
||||
uint32_t aMsgLength,
|
||||
bool aIsBinary,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
AssertIsOnTargetThread();
|
||||
|
||||
int64_t readyState = ReadyState();
|
||||
if (readyState == WebSocket::CONNECTING) {
|
||||
if (readyState == CONNECTING) {
|
||||
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return;
|
||||
}
|
||||
|
@ -2115,22 +2055,23 @@ WebSocketImpl::Send(nsIInputStream* aMsgStream,
|
|||
// Always increment outgoing buffer len, even if closed
|
||||
mOutgoingBufferedAmount += aMsgLength;
|
||||
|
||||
if (readyState == WebSocket::CLOSING ||
|
||||
readyState == WebSocket::CLOSED) {
|
||||
if (readyState == CLOSING ||
|
||||
readyState == CLOSED) {
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(readyState == WebSocket::OPEN,
|
||||
"Unknown state in WebSocket::Send");
|
||||
// We must have mImpl when connected.
|
||||
MOZ_ASSERT(mImpl);
|
||||
MOZ_ASSERT(readyState == OPEN, "Unknown state in WebSocket::Send");
|
||||
|
||||
nsresult rv;
|
||||
if (aMsgStream) {
|
||||
rv = mChannel->SendBinaryStream(aMsgStream, aMsgLength);
|
||||
rv = mImpl->mChannel->SendBinaryStream(aMsgStream, aMsgLength);
|
||||
} else {
|
||||
if (aIsBinary) {
|
||||
rv = mChannel->SendBinaryMsg(aMsgString);
|
||||
rv = mImpl->mChannel->SendBinaryMsg(aMsgString);
|
||||
} else {
|
||||
rv = mChannel->SendMsg(aMsgString);
|
||||
rv = mImpl->mChannel->SendMsg(aMsgString);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2139,7 +2080,7 @@ WebSocketImpl::Send(nsIInputStream* aMsgStream,
|
|||
return;
|
||||
}
|
||||
|
||||
mWebSocket->UpdateMustKeepAlive();
|
||||
UpdateMustKeepAlive();
|
||||
}
|
||||
|
||||
// webIDL: void close(optional unsigned short code, optional DOMString reason):
|
||||
|
@ -2147,15 +2088,6 @@ void
|
|||
WebSocket::Close(const Optional<uint16_t>& aCode,
|
||||
const Optional<nsAString>& aReason,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(mImpl);
|
||||
mImpl->Close(aCode, aReason, aRv);
|
||||
}
|
||||
|
||||
void
|
||||
WebSocketImpl::Close(const Optional<uint16_t>& aCode,
|
||||
const Optional<nsAString>& aReason,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
AssertIsOnTargetThread();
|
||||
|
||||
|
@ -2181,18 +2113,21 @@ WebSocketImpl::Close(const Optional<uint16_t>& aCode,
|
|||
}
|
||||
|
||||
int64_t readyState = ReadyState();
|
||||
if (readyState == WebSocket::CLOSING ||
|
||||
readyState == WebSocket::CLOSED) {
|
||||
if (readyState == CLOSING ||
|
||||
readyState == CLOSED) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (readyState == WebSocket::CONNECTING) {
|
||||
FailConnection(closeCode, closeReason);
|
||||
// If the webSocket is not closed we MUST have a mImpl.
|
||||
MOZ_ASSERT(mImpl);
|
||||
|
||||
if (readyState == CONNECTING) {
|
||||
mImpl->FailConnection(closeCode, closeReason);
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(readyState == WebSocket::OPEN);
|
||||
CloseConnection(closeCode, closeReason);
|
||||
MOZ_ASSERT(readyState == OPEN);
|
||||
mImpl->CloseConnection(closeCode, closeReason);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -2206,7 +2141,7 @@ WebSocketImpl::Observe(nsISupports* aSubject,
|
|||
{
|
||||
AssertIsOnMainThread();
|
||||
|
||||
int64_t readyState = ReadyState();
|
||||
int64_t readyState = mWebSocket->ReadyState();
|
||||
if ((readyState == WebSocket::CLOSING) ||
|
||||
(readyState == WebSocket::CLOSED)) {
|
||||
return NS_OK;
|
||||
|
@ -2235,7 +2170,7 @@ WebSocketImpl::GetName(nsACString& aName)
|
|||
{
|
||||
AssertIsOnMainThread();
|
||||
|
||||
CopyUTF16toUTF8(mOriginalURL, aName);
|
||||
CopyUTF16toUTF8(mWebSocket->mOriginalURL, aName);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -2244,7 +2179,7 @@ WebSocketImpl::IsPending(bool* aValue)
|
|||
{
|
||||
AssertIsOnTargetThread();
|
||||
|
||||
int64_t readyState = ReadyState();
|
||||
int64_t readyState = mWebSocket->ReadyState();
|
||||
*aValue = (readyState != WebSocket::CLOSED);
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -2323,7 +2258,7 @@ WebSocketImpl::CancelInternal()
|
|||
{
|
||||
AssertIsOnTargetThread();
|
||||
|
||||
int64_t readyState = ReadyState();
|
||||
int64_t readyState = mWebSocket->ReadyState();
|
||||
if (readyState == WebSocket::CLOSING || readyState == WebSocket::CLOSED) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -2484,5 +2419,11 @@ WebSocketImpl::IsTargetThread() const
|
|||
return NS_IsMainThread() == !mWorkerPrivate;
|
||||
}
|
||||
|
||||
void
|
||||
WebSocket::AssertIsOnTargetThread() const
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread() == !mWorkerPrivate);
|
||||
}
|
||||
|
||||
} // dom namespace
|
||||
} // mozilla namespace
|
||||
|
|
|
@ -23,6 +23,8 @@
|
|||
#define DEFAULT_WS_SCHEME_PORT 80
|
||||
#define DEFAULT_WSS_SCHEME_PORT 443
|
||||
|
||||
class nsIInputStream;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
|
@ -88,7 +90,7 @@ public: // WebIDL interface:
|
|||
void GetUrl(nsAString& aResult);
|
||||
|
||||
// webIDL: readonly attribute unsigned short readyState;
|
||||
uint16_t ReadyState() const;
|
||||
uint16_t ReadyState();
|
||||
|
||||
// webIDL: readonly attribute unsigned long bufferedAmount;
|
||||
uint32_t BufferedAmount() const;
|
||||
|
@ -134,6 +136,8 @@ private: // constructor && distructor
|
|||
explicit WebSocket(nsPIDOMWindow* aOwnerWindow);
|
||||
virtual ~WebSocket();
|
||||
|
||||
void SetReadyState(uint16_t aReadyState);
|
||||
|
||||
// These methods actually do the dispatch for various events.
|
||||
nsresult CreateAndDispatchSimpleEvent(const nsAString& aName);
|
||||
nsresult CreateAndDispatchMessageEvent(const nsACString& aData,
|
||||
|
@ -157,16 +161,39 @@ private:
|
|||
WebSocket(const WebSocket& x) MOZ_DELETE; // prevent bad usage
|
||||
WebSocket& operator=(const WebSocket& x) MOZ_DELETE;
|
||||
|
||||
void Send(nsIInputStream* aMsgStream,
|
||||
const nsACString& aMsgString,
|
||||
uint32_t aMsgLength,
|
||||
bool aIsBinary,
|
||||
ErrorResult& aRv);
|
||||
|
||||
void AssertIsOnTargetThread() const;
|
||||
|
||||
// Raw pointer because this WebSocketImpl is created, managed and destroyed by
|
||||
// WebSocket.
|
||||
WebSocketImpl* mImpl;
|
||||
|
||||
// This is used just to check in which thread this object is used when mImpl
|
||||
// is null.
|
||||
workers::WorkerPrivate* mWorkerPrivate;
|
||||
|
||||
bool mKeepingAlive;
|
||||
bool mCheckMustKeepAlive;
|
||||
|
||||
uint32_t mOutgoingBufferedAmount;
|
||||
|
||||
// related to the WebSocket constructor steps
|
||||
nsString mOriginalURL;
|
||||
nsString mEffectiveURL; // after redirects
|
||||
nsCString mEstablishedExtensions;
|
||||
nsCString mEstablishedProtocol;
|
||||
|
||||
dom::BinaryType mBinaryType;
|
||||
|
||||
// This mutex protects mReadyState that is the only variable that is used in
|
||||
// different threads.
|
||||
mozilla::Mutex mMutex;
|
||||
|
||||
// This value should not be used directly but use ReadyState() instead.
|
||||
uint16_t mReadyState;
|
||||
};
|
||||
|
||||
} //namespace dom
|
||||
|
|
|
@ -4703,10 +4703,6 @@ nsDocument::GetWindowInternal() const
|
|||
if (win) {
|
||||
// mScriptGlobalObject is always the inner window, let's get the outer.
|
||||
win = win->GetOuterWindow();
|
||||
} else if (mMasterDocument) {
|
||||
// For script execution in the imported document we need the window of
|
||||
// the master document.
|
||||
win = mMasterDocument->GetWindow();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -793,6 +793,10 @@ GK_ATOM(onmouseover, "onmouseover")
|
|||
GK_ATOM(onMozMouseHittest, "onMozMouseHittest")
|
||||
GK_ATOM(onmouseup, "onmouseup")
|
||||
GK_ATOM(onMozAfterPaint, "onMozAfterPaint")
|
||||
GK_ATOM(onmozbrowserafterkeydown, "onmozbrowserafterkeydown")
|
||||
GK_ATOM(onmozbrowserafterkeyup, "onmozbrowserafterkeyup")
|
||||
GK_ATOM(onmozbrowserbeforekeydown, "onmozbrowserbeforekeydown")
|
||||
GK_ATOM(onmozbrowserbeforekeyup, "onmozbrowserbeforekeyup")
|
||||
GK_ATOM(onmozfullscreenchange, "onmozfullscreenchange")
|
||||
GK_ATOM(onmozfullscreenerror, "onmozfullscreenerror")
|
||||
GK_ATOM(onmozpointerlockchange, "onmozpointerlockchange")
|
||||
|
|
|
@ -292,7 +292,8 @@ nsScriptLoader::StartLoad(nsScriptLoadRequest *aRequest, const nsAString &aType,
|
|||
|
||||
nsCOMPtr<nsILoadGroup> loadGroup = mDocument->GetDocumentLoadGroup();
|
||||
|
||||
nsCOMPtr<nsPIDOMWindow> window(do_QueryInterface(mDocument->GetWindow()));
|
||||
nsCOMPtr<nsPIDOMWindow> window(do_QueryInterface(mDocument->MasterDocument()->GetWindow()));
|
||||
|
||||
if (!window) {
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
}
|
||||
|
|
|
@ -659,3 +659,5 @@ support-files = file_bug1011748_redirect.sjs file_bug1011748_OK.sjs
|
|||
[test_element.matches.html]
|
||||
[test_user_select.html]
|
||||
skip-if = buildapp == 'mulet' || buildapp == 'b2g'
|
||||
[test_bug1081686.html]
|
||||
skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
-->
|
||||
<head>
|
||||
<title>bug 1081686</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body onload="testWebSocket()">
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
var ws;
|
||||
|
||||
function forcegc()
|
||||
{
|
||||
SpecialPowers.forceGC();
|
||||
SpecialPowers.gc();
|
||||
setTimeout(function()
|
||||
{
|
||||
SpecialPowers.gc();
|
||||
}, 0);
|
||||
}
|
||||
|
||||
function testWebSocket () {
|
||||
ws = new WebSocket("ws://mochi.test:8888/tests/content/base/test/file_websocket_hello");
|
||||
ws.onopen = function(e) {
|
||||
ws.send("data");
|
||||
}
|
||||
ws.onclose = function(e) {
|
||||
forcegc();
|
||||
setTimeout(function() {
|
||||
is(ws.readyState, 3, 'WebSocket is closed');
|
||||
is(ws.bufferedAmount, 0, 'WebSocket.bufferedAmount should be empty.');
|
||||
is(ws.binaryType, 'blob', 'WebSocket.binaryType is blob');
|
||||
ws.binaryType = 'arraybuffer';
|
||||
is(ws.binaryType, 'arraybuffer', 'WebSocket.binaryType is arraybuffer');
|
||||
is(ws.url, 'ws://mochi.test:8888/tests/content/base/test/file_websocket_hello', 'WebSocket.url is correct');
|
||||
ws.close();
|
||||
ws.send('foobar');
|
||||
SimpleTest.finish();
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
ws.onerror = function(e) {
|
||||
ok(false, "onerror called!");
|
||||
SimpleTest.finish();
|
||||
}
|
||||
ws.onmessage = function(e) {
|
||||
is(e.data, "Hello world!", "Wrong data");
|
||||
ws.close();
|
||||
}
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
<div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -445,16 +445,18 @@ MediaEngineGonkVideoSource::OnTakePictureComplete(uint8_t* aData, uint32_t aLeng
|
|||
uint8_t* aData,
|
||||
uint32_t aLength,
|
||||
const nsAString& aMimeType)
|
||||
: mPhotoDataLength(aLength)
|
||||
{
|
||||
mCallbacks.SwapElements(aCallbacks);
|
||||
mPhoto.AppendElements(aData, aLength);
|
||||
mPhotoData = (uint8_t*) moz_malloc(aLength);
|
||||
memcpy(mPhotoData, aData, mPhotoDataLength);
|
||||
mMimeType = aMimeType;
|
||||
}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
nsRefPtr<dom::File> blob =
|
||||
dom::File::CreateMemoryFile(nullptr, mPhoto.Elements(), mPhoto.Length(), mMimeType);
|
||||
dom::File::CreateMemoryFile(nullptr, mPhotoData, mPhotoDataLength, mMimeType);
|
||||
uint32_t callbackCounts = mCallbacks.Length();
|
||||
for (uint8_t i = 0; i < callbackCounts; i++) {
|
||||
nsRefPtr<dom::File> tempBlob = blob;
|
||||
|
@ -466,8 +468,9 @@ MediaEngineGonkVideoSource::OnTakePictureComplete(uint8_t* aData, uint32_t aLeng
|
|||
}
|
||||
|
||||
nsTArray<nsRefPtr<PhotoCallback>> mCallbacks;
|
||||
nsTArray<uint8_t> mPhoto;
|
||||
uint8_t* mPhotoData;
|
||||
nsString mMimeType;
|
||||
uint32_t mPhotoDataLength;
|
||||
};
|
||||
|
||||
// All elements in mPhotoCallbacks will be swapped in GenerateBlobRunnable
|
||||
|
|
|
@ -493,6 +493,12 @@ this.PermissionsTable = { geolocation: {
|
|||
trusted: DENY_ACTION,
|
||||
privileged: DENY_ACTION,
|
||||
certified: ALLOW_ACTION
|
||||
},
|
||||
"before-after-keyboard-event": {
|
||||
app: DENY_ACTION,
|
||||
trusted: DENY_ACTION,
|
||||
privileged: DENY_ACTION,
|
||||
certified: ALLOW_ACTION
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -43,6 +43,11 @@ protected:
|
|||
|
||||
private:
|
||||
DOMCursor() MOZ_DELETE;
|
||||
// Calling Then() on DOMCursor is a mistake, since the DOMCursor object
|
||||
// should not have a .then() method from JS' point of view.
|
||||
already_AddRefed<mozilla::dom::Promise>
|
||||
Then(JSContext* aCx, AnyCallback* aResolveCallback,
|
||||
AnyCallback* aRejectCallback, ErrorResult& aRv) MOZ_DELETE;
|
||||
|
||||
nsCOMPtr<nsICursorContinueCallback> mCallback;
|
||||
bool mFinished;
|
||||
|
|
|
@ -10,11 +10,16 @@
|
|||
#include "nsThreadUtils.h"
|
||||
#include "DOMCursor.h"
|
||||
#include "nsIDOMEvent.h"
|
||||
#include "mozilla/ErrorResult.h"
|
||||
#include "mozilla/dom/Promise.h"
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
|
||||
using mozilla::dom::AnyCallback;
|
||||
using mozilla::dom::DOMError;
|
||||
using mozilla::dom::DOMRequest;
|
||||
using mozilla::dom::DOMRequestService;
|
||||
using mozilla::dom::DOMCursor;
|
||||
using mozilla::dom::Promise;
|
||||
using mozilla::AutoSafeJSContext;
|
||||
|
||||
DOMRequest::DOMRequest(nsPIDOMWindow* aWindow)
|
||||
|
@ -25,16 +30,24 @@ DOMRequest::DOMRequest(nsPIDOMWindow* aWindow)
|
|||
{
|
||||
}
|
||||
|
||||
DOMRequest::~DOMRequest()
|
||||
{
|
||||
mResult.setUndefined();
|
||||
mozilla::DropJSObjects(this);
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(DOMRequest)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(DOMRequest,
|
||||
DOMEventTargetHelper)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mError)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPromise)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(DOMRequest,
|
||||
DOMEventTargetHelper)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mError)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mPromise)
|
||||
tmp->mResult = JSVAL_VOID;
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
|
@ -107,6 +120,10 @@ DOMRequest::FireSuccess(JS::Handle<JS::Value> aResult)
|
|||
mResult = aResult;
|
||||
|
||||
FireEvent(NS_LITERAL_STRING("success"), false, false);
|
||||
|
||||
if (mPromise) {
|
||||
mPromise->MaybeResolve(mResult);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -120,6 +137,10 @@ DOMRequest::FireError(const nsAString& aError)
|
|||
mError = new DOMError(GetOwner(), aError);
|
||||
|
||||
FireEvent(NS_LITERAL_STRING("error"), true, true);
|
||||
|
||||
if (mPromise) {
|
||||
mPromise->MaybeRejectBrokenly(mError);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -133,6 +154,10 @@ DOMRequest::FireError(nsresult aError)
|
|||
mError = new DOMError(GetOwner(), aError);
|
||||
|
||||
FireEvent(NS_LITERAL_STRING("error"), true, true);
|
||||
|
||||
if (mPromise) {
|
||||
mPromise->MaybeRejectBrokenly(mError);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -147,6 +172,10 @@ DOMRequest::FireDetailedError(DOMError* aError)
|
|||
mError = aError;
|
||||
|
||||
FireEvent(NS_LITERAL_STRING("error"), true, true);
|
||||
|
||||
if (mPromise) {
|
||||
mPromise->MaybeRejectBrokenly(mError);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -175,6 +204,31 @@ DOMRequest::RootResultVal()
|
|||
mozilla::HoldJSObjects(this);
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
DOMRequest::Then(JSContext* aCx, AnyCallback* aResolveCallback,
|
||||
AnyCallback* aRejectCallback, mozilla::ErrorResult& aRv)
|
||||
{
|
||||
if (!mPromise) {
|
||||
mPromise = Promise::Create(DOMEventTargetHelper::GetParentObject(), aRv);
|
||||
if (aRv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
if (mDone) {
|
||||
// Since we create mPromise lazily, it's possible that the DOMRequest object
|
||||
// has already fired its success/error event. In that case we should
|
||||
// manually resolve/reject mPromise here. mPromise will take care of
|
||||
// calling the callbacks on |promise| as needed.
|
||||
if (mError) {
|
||||
mPromise->MaybeRejectBrokenly(mError);
|
||||
} else {
|
||||
mPromise->MaybeResolve(mResult);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return mPromise->Then(aCx, aResolveCallback, aRejectCallback, aRv);
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(DOMRequestService, nsIDOMRequestService)
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -253,7 +307,7 @@ public:
|
|||
const JS::Value& aResult)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
AutoSafeJSContext cx;
|
||||
mozilla::ThreadsafeAutoSafeJSContext cx;
|
||||
nsRefPtr<FireSuccessAsyncTask> asyncTask = new FireSuccessAsyncTask(cx, aRequest, aResult);
|
||||
if (NS_FAILED(NS_DispatchToMainThread(asyncTask))) {
|
||||
NS_WARNING("Failed to dispatch to main thread!");
|
||||
|
|
|
@ -16,14 +16,21 @@
|
|||
#include "nsCOMPtr.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class ErrorResult;
|
||||
|
||||
namespace dom {
|
||||
|
||||
class AnyCallback;
|
||||
class Promise;
|
||||
|
||||
class DOMRequest : public DOMEventTargetHelper,
|
||||
public nsIDOMDOMRequest
|
||||
{
|
||||
protected:
|
||||
JS::Heap<JS::Value> mResult;
|
||||
nsRefPtr<DOMError> mError;
|
||||
nsRefPtr<Promise> mPromise;
|
||||
bool mDone;
|
||||
|
||||
public:
|
||||
|
@ -67,6 +74,9 @@ public:
|
|||
IMPL_EVENT_HANDLER(success)
|
||||
IMPL_EVENT_HANDLER(error)
|
||||
|
||||
already_AddRefed<mozilla::dom::Promise>
|
||||
Then(JSContext* aCx, AnyCallback* aResolveCallback,
|
||||
AnyCallback* aRejectCallback, mozilla::ErrorResult& aRv);
|
||||
|
||||
void FireSuccess(JS::Handle<JS::Value> aResult);
|
||||
void FireError(const nsAString& aError);
|
||||
|
@ -76,11 +86,7 @@ public:
|
|||
explicit DOMRequest(nsPIDOMWindow* aWindow);
|
||||
|
||||
protected:
|
||||
virtual ~DOMRequest()
|
||||
{
|
||||
mResult = JSVAL_VOID;
|
||||
mozilla::DropJSObjects(this);
|
||||
}
|
||||
virtual ~DOMRequest();
|
||||
|
||||
void FireEvent(const nsAString& aType, bool aBubble, bool aCancelable);
|
||||
|
||||
|
|
|
@ -51,6 +51,7 @@ var tests = [
|
|||
ok("readyState" in req, "cursor has readyState");
|
||||
ok("done" in req, "cursor has finished");
|
||||
ok("continue" in req, "cursor has continue");
|
||||
ok(!("then" in req), "cursor should not have a then method");
|
||||
|
||||
is(req.readyState, "pending", "readyState is pending");
|
||||
is(req.result, undefined, "result is undefined");
|
||||
|
|
|
@ -17,59 +17,212 @@
|
|||
var reqserv = SpecialPowers.getDOMRequestService();
|
||||
ok("createRequest" in reqserv, "appears to be a service");
|
||||
|
||||
// create a request
|
||||
var req = reqserv.createRequest(window);
|
||||
ok("result" in req, "request has result");
|
||||
ok("error" in req, "request has error");
|
||||
ok("onsuccess" in req, "request has onsuccess");
|
||||
ok("onerror" in req, "request has onerror");
|
||||
ok("readyState" in req, "request has readyState");
|
||||
function testBasics() {
|
||||
// create a request
|
||||
var req = reqserv.createRequest(window);
|
||||
ok("result" in req, "request has result");
|
||||
ok("error" in req, "request has error");
|
||||
ok("onsuccess" in req, "request has onsuccess");
|
||||
ok("onerror" in req, "request has onerror");
|
||||
ok("readyState" in req, "request has readyState");
|
||||
ok("then" in req, "request has then");
|
||||
|
||||
is(req.readyState, "pending", "readyState is pending");
|
||||
is(req.result, undefined, "result is undefined");
|
||||
is(req.onsuccess, null, "onsuccess is null");
|
||||
is(req.onerror, null, "onerror is null");
|
||||
is(req.readyState, "pending", "readyState is pending");
|
||||
is(req.result, undefined, "result is undefined");
|
||||
is(req.onsuccess, null, "onsuccess is null");
|
||||
is(req.onerror, null, "onerror is null");
|
||||
|
||||
// fire success
|
||||
var ev = null;
|
||||
req.onsuccess = function(e) {
|
||||
ev = e;
|
||||
runTest();
|
||||
}
|
||||
reqserv.fireSuccess(req, "my result");
|
||||
ok(ev, "got success event");
|
||||
is(ev.type, "success", "correct type during success");
|
||||
is(ev.target, req, "correct target during success");
|
||||
is(req.readyState, "done", "correct readyState after success");
|
||||
is(req.error, null, "correct error after success");
|
||||
is(req.result, "my result", "correct result after success");
|
||||
|
||||
// fire error
|
||||
req = reqserv.createRequest(window);
|
||||
ev = null;
|
||||
req.onerror = function(e) {
|
||||
ev = e;
|
||||
function testSuccess() {
|
||||
// fire success
|
||||
var req = reqserv.createRequest(window);
|
||||
var ev = null;
|
||||
req.onsuccess = function(e) {
|
||||
ev = e;
|
||||
}
|
||||
var result = null;
|
||||
var promise = req.then(function(r) {
|
||||
is(r, "my result", "correct result when resolving the promise");
|
||||
result = r;
|
||||
runTest();
|
||||
}, function(e) {
|
||||
ok(false, "promise should not be rejected");
|
||||
runTest();
|
||||
});
|
||||
ok(promise instanceof Promise, "then() should return a Promise");
|
||||
reqserv.fireSuccess(req, "my result");
|
||||
ok(ev, "got success event");
|
||||
is(ev.type, "success", "correct type during success");
|
||||
is(ev.target, req, "correct target during success");
|
||||
is(req.readyState, "done", "correct readyState after success");
|
||||
is(req.error, null, "correct error after success");
|
||||
is(req.result, "my result", "correct result after success");
|
||||
is(result, null, "Promise should not be resolved synchronously");
|
||||
}
|
||||
reqserv.fireError(req, "OhMyError");
|
||||
ok(ev, "got error event");
|
||||
is(ev.type, "error", "correct type during error");
|
||||
is(ev.target, req, "correct target during error");
|
||||
is(req.readyState, "done", "correct readyState after error");
|
||||
is(req.error.name, "OhMyError", "correct error after error");
|
||||
is(req.result, undefined, "correct result after error");
|
||||
|
||||
// fire detailed error
|
||||
req = reqserv.createRequest(window);
|
||||
ev = null;
|
||||
req.onerror = function(e) {
|
||||
ev = e;
|
||||
};
|
||||
reqserv.fireDetailedError(req, new DOMError("detailedError"));
|
||||
ok(ev, "got error event");
|
||||
is(ev.type, "error", "correct type during error");
|
||||
is(ev.target, req, "correct target during error");
|
||||
is(req.readyState, "done", "correct readyState after error");
|
||||
is(req.error.name, "detailedError", "correct error after error");
|
||||
is(req.result, undefined, "correct result after error");
|
||||
function testError() {
|
||||
// fire error
|
||||
var req = reqserv.createRequest(window);
|
||||
var ev = null;
|
||||
req.onerror = function(e) {
|
||||
ev = e;
|
||||
}
|
||||
var error = null;
|
||||
var promise = req.then(function(r) {
|
||||
ok(false, "promise should not be resolved");
|
||||
runTest();
|
||||
}, function(e) {
|
||||
ok(e instanceof DOMError, "got error rejection");
|
||||
ok(e === req.error, "got correct error when rejecting the promise");
|
||||
error = e;
|
||||
runTest();
|
||||
});
|
||||
ok(promise instanceof Promise, "then() should return a Promise");
|
||||
reqserv.fireError(req, "OhMyError");
|
||||
ok(ev, "got error event");
|
||||
is(ev.type, "error", "correct type during error");
|
||||
is(ev.target, req, "correct target during error");
|
||||
is(req.readyState, "done", "correct readyState after error");
|
||||
is(req.error.name, "OhMyError", "correct error after error");
|
||||
is(req.result, undefined, "correct result after error");
|
||||
is(error, null, "Promise should not be rejected synchronously");
|
||||
}
|
||||
|
||||
function testDetailedError() {
|
||||
// fire detailed error
|
||||
var req = reqserv.createRequest(window);
|
||||
var ev = null;
|
||||
req.onerror = function(e) {
|
||||
ev = e;
|
||||
};
|
||||
var error = null;
|
||||
var promise = req.then(function(r) {
|
||||
ok(false, "promise should not be resolved");
|
||||
runTest();
|
||||
}, function(e) {
|
||||
ok(e instanceof DOMError, "got error rejection");
|
||||
ok(e === req.error, "got correct error when rejecting the promise");
|
||||
error = e;
|
||||
runTest();
|
||||
});
|
||||
ok(promise instanceof Promise, "then() should return a Promise");
|
||||
reqserv.fireDetailedError(req, new DOMError("detailedError"));
|
||||
ok(ev, "got error event");
|
||||
is(ev.type, "error", "correct type during error");
|
||||
is(ev.target, req, "correct target during error");
|
||||
is(req.readyState, "done", "correct readyState after error");
|
||||
is(req.error.name, "detailedError", "correct error after error");
|
||||
is(req.result, undefined, "correct result after error");
|
||||
is(error, null, "Promise should not be rejected synchronously");
|
||||
}
|
||||
|
||||
function testThenAfterSuccess() {
|
||||
// fire success
|
||||
var req = reqserv.createRequest(window);
|
||||
var ev = null;
|
||||
req.onsuccess = function(e) {
|
||||
ev = e;
|
||||
}
|
||||
reqserv.fireSuccess(req, "my result");
|
||||
ok(ev, "got success event");
|
||||
is(ev.type, "success", "correct type during success");
|
||||
is(ev.target, req, "correct target during success");
|
||||
is(req.readyState, "done", "correct readyState after success");
|
||||
is(req.error, null, "correct error after success");
|
||||
is(req.result, "my result", "correct result after success");
|
||||
var result = null;
|
||||
var promise = req.then(function(r) {
|
||||
is(r, "my result", "correct result when resolving the promise");
|
||||
result = r;
|
||||
runTest();
|
||||
}, function(e) {
|
||||
ok(false, "promise should not be rejected");
|
||||
runTest();
|
||||
});
|
||||
ok(promise instanceof Promise, "then() should return a Promise");
|
||||
is(result, null, "Promise should not be resolved synchronously");
|
||||
}
|
||||
|
||||
function testThenAfterError() {
|
||||
// fire error
|
||||
var req = reqserv.createRequest(window);
|
||||
var ev = null;
|
||||
req.onerror = function(e) {
|
||||
ev = e;
|
||||
}
|
||||
reqserv.fireError(req, "OhMyError");
|
||||
ok(ev, "got error event");
|
||||
is(ev.type, "error", "correct type during error");
|
||||
is(ev.target, req, "correct target during error");
|
||||
is(req.readyState, "done", "correct readyState after error");
|
||||
is(req.error.name, "OhMyError", "correct error after error");
|
||||
is(req.result, undefined, "correct result after error");
|
||||
var error = null;
|
||||
var promise = req.then(function(r) {
|
||||
ok(false, "promise should not be resolved");
|
||||
runTest();
|
||||
}, function(e) {
|
||||
ok(e instanceof DOMError, "got error rejection");
|
||||
ok(e === req.error, "got correct error when rejecting the promise");
|
||||
error = e;
|
||||
runTest();
|
||||
});
|
||||
ok(promise instanceof Promise, "then() should return a Promise");
|
||||
is(error, null, "Promise should not be rejected synchronously");
|
||||
}
|
||||
|
||||
function testDetailedError() {
|
||||
// fire detailed error
|
||||
var req = reqserv.createRequest(window);
|
||||
var ev = null;
|
||||
req.onerror = function(e) {
|
||||
ev = e;
|
||||
};
|
||||
var error = null;
|
||||
var promise = req.then(function(r) {
|
||||
ok(false, "promise should not be resolved");
|
||||
runTest();
|
||||
}, function(e) {
|
||||
ok(e instanceof DOMError, "got error rejection");
|
||||
ok(e === req.error, "got correct error when rejecting the promise");
|
||||
error = e;
|
||||
runTest();
|
||||
});
|
||||
ok(promise instanceof Promise, "then() should return a Promise");
|
||||
reqserv.fireDetailedError(req, new DOMError("detailedError"));
|
||||
ok(ev, "got error event");
|
||||
is(ev.type, "error", "correct type during error");
|
||||
is(ev.target, req, "correct target during error");
|
||||
is(req.readyState, "done", "correct readyState after error");
|
||||
is(req.error.name, "detailedError", "correct error after error");
|
||||
is(req.result, undefined, "correct result after error");
|
||||
is(error, null, "Promise should not be rejected synchronously");
|
||||
}
|
||||
|
||||
var tests = [
|
||||
testBasics,
|
||||
testSuccess,
|
||||
testError,
|
||||
testDetailedError,
|
||||
testThenAfterSuccess,
|
||||
testThenAfterError,
|
||||
];
|
||||
|
||||
function runTest() {
|
||||
if (!tests.length) {
|
||||
SimpleTest.finish();
|
||||
return;
|
||||
}
|
||||
|
||||
var test = tests.shift();
|
||||
test();
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
runTest();
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
|
|
|
@ -352,6 +352,10 @@ DOMInterfaces = {
|
|||
'headerFile': 'mozilla/dom/DOMRect.h',
|
||||
},
|
||||
|
||||
'DOMRequest': {
|
||||
'implicitJSContext': [ 'then' ],
|
||||
},
|
||||
|
||||
'DOMSettableTokenList': {
|
||||
'nativeType': 'nsDOMSettableTokenList',
|
||||
},
|
||||
|
|
|
@ -236,6 +236,24 @@ ToJSValue(JSContext* aCx, JS::Handle<JS::Value> aArgument,
|
|||
return MaybeWrapValue(aCx, aValue);
|
||||
}
|
||||
|
||||
// Accept existing JS values on the Heap (which may not be same-compartment with us
|
||||
inline bool
|
||||
ToJSValue(JSContext* aCx, const JS::Heap<JS::Value>& aArgument,
|
||||
JS::MutableHandle<JS::Value> aValue)
|
||||
{
|
||||
aValue.set(aArgument);
|
||||
return MaybeWrapValue(aCx, aValue);
|
||||
}
|
||||
|
||||
// Accept existing rooted JS values (which may not be same-compartment with us
|
||||
inline bool
|
||||
ToJSValue(JSContext* aCx, const JS::Rooted<JS::Value>& aArgument,
|
||||
JS::MutableHandle<JS::Value> aValue)
|
||||
{
|
||||
aValue.set(aArgument);
|
||||
return MaybeWrapValue(aCx, aValue);
|
||||
}
|
||||
|
||||
// Accept nsresult, for use in rejections, and create an XPCOM
|
||||
// exception object representing that nsresult.
|
||||
bool
|
||||
|
|
|
@ -114,8 +114,8 @@
|
|||
|
||||
#undef free // apparently defined by some windows header, clashing with a free()
|
||||
// method in SkTypes.h
|
||||
#ifdef USE_SKIA
|
||||
#include "SkiaGLGlue.h"
|
||||
#ifdef USE_SKIA
|
||||
#include "SurfaceTypes.h"
|
||||
#endif
|
||||
|
||||
|
|
|
@ -141,6 +141,13 @@ WebGL2Context::TexStorage2D(GLenum target, GLsizei levels, GLenum internalformat
|
|||
if (!ValidateTexStorage(target, levels, internalformat, width, height, 1, "texStorage2D"))
|
||||
return;
|
||||
|
||||
GetAndFlushUnderlyingGLErrors();
|
||||
gl->fTexStorage2D(target, levels, internalformat, width, height);
|
||||
GLenum error = GetAndFlushUnderlyingGLErrors();
|
||||
if (error) {
|
||||
return GenerateWarning("texStorage2D generated error %s", ErrorName(error));
|
||||
}
|
||||
|
||||
WebGLTexture* tex = activeBoundTextureForTarget(target);
|
||||
tex->SetImmutable();
|
||||
|
||||
|
@ -157,8 +164,6 @@ WebGL2Context::TexStorage2D(GLenum target, GLsizei levels, GLenum internalformat
|
|||
w = std::max(1, w / 2);
|
||||
h = std::max(1, h / 2);
|
||||
}
|
||||
|
||||
gl->fTexStorage2D(target, levels, internalformat, width, height);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -175,6 +180,13 @@ WebGL2Context::TexStorage3D(GLenum target, GLsizei levels, GLenum internalformat
|
|||
if (!ValidateTexStorage(target, levels, internalformat, width, height, depth, "texStorage3D"))
|
||||
return;
|
||||
|
||||
GetAndFlushUnderlyingGLErrors();
|
||||
gl->fTexStorage3D(target, levels, internalformat, width, height, depth);
|
||||
GLenum error = GetAndFlushUnderlyingGLErrors();
|
||||
if (error) {
|
||||
return GenerateWarning("texStorage3D generated error %s", ErrorName(error));
|
||||
}
|
||||
|
||||
WebGLTexture* tex = activeBoundTextureForTarget(target);
|
||||
tex->SetImmutable();
|
||||
|
||||
|
@ -190,8 +202,6 @@ WebGL2Context::TexStorage3D(GLenum target, GLsizei levels, GLenum internalformat
|
|||
h = std::max(1, h >> 1);
|
||||
d = std::max(1, d >> 1);
|
||||
}
|
||||
|
||||
gl->fTexStorage3D(target, levels, internalformat, width, height, depth);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -272,8 +282,19 @@ WebGL2Context::TexSubImage3D(GLenum rawTarget, GLint level,
|
|||
if (dataLength < bytesNeeded)
|
||||
return ErrorInvalidOperation("texSubImage2D: not enough data for operation (need %d, have %d)", bytesNeeded, dataLength);
|
||||
|
||||
if (imageInfo.HasUninitializedImageData())
|
||||
tex->DoDeferredImageInitialization(texImageTarget, level);
|
||||
if (imageInfo.HasUninitializedImageData()) {
|
||||
bool coversWholeImage = xoffset == 0 &&
|
||||
yoffset == 0 &&
|
||||
zoffset == 0 &&
|
||||
width == imageInfo.Width() &&
|
||||
height == imageInfo.Height() &&
|
||||
depth == imageInfo.Depth();
|
||||
if (coversWholeImage) {
|
||||
tex->SetImageDataStatus(texImageTarget, level, WebGLImageDataStatus::InitializedImageData);
|
||||
} else {
|
||||
tex->DoDeferredImageInitialization(texImageTarget, level);
|
||||
}
|
||||
}
|
||||
|
||||
GLenum driverType = LOCAL_GL_NONE;
|
||||
GLenum driverInternalFormat = LOCAL_GL_NONE;
|
||||
|
|
|
@ -594,7 +594,15 @@ WebGLContext::CopyTexSubImage2D(GLenum rawTexImgTarget,
|
|||
ClearBackbufferIfNeeded();
|
||||
|
||||
if (imageInfo.HasUninitializedImageData()) {
|
||||
tex->DoDeferredImageInitialization(texImageTarget, level);
|
||||
bool coversWholeImage = xoffset == 0 &&
|
||||
yoffset == 0 &&
|
||||
width == texWidth &&
|
||||
height == texHeight;
|
||||
if (coversWholeImage) {
|
||||
tex->SetImageDataStatus(texImageTarget, level, WebGLImageDataStatus::InitializedImageData);
|
||||
} else {
|
||||
tex->DoDeferredImageInitialization(texImageTarget, level);
|
||||
}
|
||||
}
|
||||
|
||||
TexInternalFormat internalformat;
|
||||
|
@ -3414,8 +3422,17 @@ WebGLContext::CompressedTexSubImage2D(GLenum rawTexImgTarget, GLint level, GLint
|
|||
return;
|
||||
}
|
||||
|
||||
if (levelInfo.HasUninitializedImageData())
|
||||
tex->DoDeferredImageInitialization(texImageTarget, level);
|
||||
if (levelInfo.HasUninitializedImageData()) {
|
||||
bool coversWholeImage = xoffset == 0 &&
|
||||
yoffset == 0 &&
|
||||
width == levelInfo.Width() &&
|
||||
height == levelInfo.Height();
|
||||
if (coversWholeImage) {
|
||||
tex->SetImageDataStatus(texImageTarget, level, WebGLImageDataStatus::InitializedImageData);
|
||||
} else {
|
||||
tex->DoDeferredImageInitialization(texImageTarget, level);
|
||||
}
|
||||
}
|
||||
|
||||
MakeContextCurrent();
|
||||
gl->fCompressedTexSubImage2D(texImageTarget.get(), level, xoffset, yoffset, width, height, internalformat, byteLength, view.Data());
|
||||
|
@ -3941,9 +3958,17 @@ WebGLContext::TexSubImage2D_base(TexImageTarget texImageTarget, GLint level,
|
|||
if (byteLength < bytesNeeded)
|
||||
return ErrorInvalidOperation("texSubImage2D: not enough data for operation (need %d, have %d)", bytesNeeded, byteLength);
|
||||
|
||||
if (imageInfo.HasUninitializedImageData())
|
||||
tex->DoDeferredImageInitialization(texImageTarget, level);
|
||||
|
||||
if (imageInfo.HasUninitializedImageData()) {
|
||||
bool coversWholeImage = xoffset == 0 &&
|
||||
yoffset == 0 &&
|
||||
width == imageInfo.Width() &&
|
||||
height == imageInfo.Height();
|
||||
if (coversWholeImage) {
|
||||
tex->SetImageDataStatus(texImageTarget, level, WebGLImageDataStatus::InitializedImageData);
|
||||
} else {
|
||||
tex->DoDeferredImageInitialization(texImageTarget, level);
|
||||
}
|
||||
}
|
||||
MakeContextCurrent();
|
||||
|
||||
size_t srcStride = srcStrideOrZero ? srcStrideOrZero : checked_alignedRowSize.value();
|
||||
|
|
|
@ -113,6 +113,7 @@ public:
|
|||
size_t MemoryUsage() const;
|
||||
|
||||
TexInternalFormat EffectiveInternalFormat() const { return mEffectiveInternalFormat; }
|
||||
GLsizei Depth() const { return mDepth; }
|
||||
|
||||
protected:
|
||||
/*
|
||||
|
|
|
@ -129,6 +129,7 @@ LOCAL_INCLUDES += [
|
|||
'/content/svg/content/src',
|
||||
'/content/xul/content/src',
|
||||
'/dom/base',
|
||||
'/gfx/gl',
|
||||
'/image/src',
|
||||
'/js/xpconnect/src',
|
||||
'/layout/generic',
|
||||
|
|
|
@ -0,0 +1,92 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/dom/BeforeAfterKeyboardEvent.h"
|
||||
#include "mozilla/TextEvents.h"
|
||||
#include "prtime.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
BeforeAfterKeyboardEvent::BeforeAfterKeyboardEvent(
|
||||
EventTarget* aOwner,
|
||||
nsPresContext* aPresContext,
|
||||
InternalBeforeAfterKeyboardEvent* aEvent)
|
||||
: KeyboardEvent(aOwner, aPresContext,
|
||||
aEvent ? aEvent :
|
||||
new InternalBeforeAfterKeyboardEvent(false, 0,
|
||||
nullptr))
|
||||
{
|
||||
MOZ_ASSERT(mEvent->mClass == eBeforeAfterKeyboardEventClass,
|
||||
"event type mismatch eBeforeAfterKeyboardEventClass");
|
||||
|
||||
if (!aEvent) {
|
||||
mEventIsInternal = true;
|
||||
mEvent->time = PR_Now();
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
already_AddRefed<BeforeAfterKeyboardEvent>
|
||||
BeforeAfterKeyboardEvent::Constructor(
|
||||
EventTarget* aOwner,
|
||||
const nsAString& aType,
|
||||
const BeforeAfterKeyboardEventInit& aParam)
|
||||
{
|
||||
nsRefPtr<BeforeAfterKeyboardEvent> event =
|
||||
new BeforeAfterKeyboardEvent(aOwner, nullptr, nullptr);
|
||||
ErrorResult rv;
|
||||
event->InitWithKeyboardEventInit(aOwner, aType, aParam, rv);
|
||||
NS_WARN_IF(rv.Failed());
|
||||
|
||||
event->mEvent->AsBeforeAfterKeyboardEvent()->mEmbeddedCancelled =
|
||||
aParam.mEmbeddedCancelled;
|
||||
|
||||
return event.forget();
|
||||
}
|
||||
|
||||
// static
|
||||
already_AddRefed<BeforeAfterKeyboardEvent>
|
||||
BeforeAfterKeyboardEvent::Constructor(
|
||||
const GlobalObject& aGlobal,
|
||||
const nsAString& aType,
|
||||
const BeforeAfterKeyboardEventInit& aParam,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
nsCOMPtr<EventTarget> owner = do_QueryInterface(aGlobal.GetAsSupports());
|
||||
return Constructor(owner, aType, aParam);
|
||||
}
|
||||
|
||||
Nullable<bool>
|
||||
BeforeAfterKeyboardEvent::GetEmbeddedCancelled()
|
||||
{
|
||||
nsAutoString type;
|
||||
GetType(type);
|
||||
if (type.EqualsLiteral("mozbrowserafterkeydown") ||
|
||||
type.EqualsLiteral("mozbrowserafterkeyup")) {
|
||||
return mEvent->AsBeforeAfterKeyboardEvent()->mEmbeddedCancelled;
|
||||
}
|
||||
return Nullable<bool>();
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
|
||||
nsresult
|
||||
NS_NewDOMBeforeAfterKeyboardEvent(nsIDOMEvent** aInstancePtrResult,
|
||||
EventTarget* aOwner,
|
||||
nsPresContext* aPresContext,
|
||||
InternalBeforeAfterKeyboardEvent* aEvent)
|
||||
{
|
||||
BeforeAfterKeyboardEvent* it =
|
||||
new BeforeAfterKeyboardEvent(aOwner, aPresContext, aEvent);
|
||||
|
||||
NS_ADDREF(it);
|
||||
*aInstancePtrResult = static_cast<Event*>(it);
|
||||
return NS_OK;
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_BeforeAfterKeyboardEvent_h_
|
||||
#define mozilla_dom_BeforeAfterKeyboardEvent_h_
|
||||
|
||||
#include "mozilla/dom/KeyboardEvent.h"
|
||||
#include "mozilla/dom/BeforeAfterKeyboardEventBinding.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class BeforeAfterKeyboardEvent : public KeyboardEvent
|
||||
{
|
||||
public:
|
||||
BeforeAfterKeyboardEvent(EventTarget* aOwner,
|
||||
nsPresContext* aPresContext,
|
||||
InternalBeforeAfterKeyboardEvent* aEvent);
|
||||
|
||||
virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE
|
||||
{
|
||||
return BeforeAfterKeyboardEventBinding::Wrap(aCx, this);
|
||||
}
|
||||
|
||||
static already_AddRefed<BeforeAfterKeyboardEvent>
|
||||
Constructor(const GlobalObject& aGlobal,
|
||||
const nsAString& aType,
|
||||
const BeforeAfterKeyboardEventInit& aParam,
|
||||
ErrorResult& aRv);
|
||||
|
||||
static already_AddRefed<BeforeAfterKeyboardEvent>
|
||||
Constructor(EventTarget* aOwner, const nsAString& aType,
|
||||
const BeforeAfterKeyboardEventInit& aEventInitDict);
|
||||
|
||||
// This function returns a boolean value when event typs is either
|
||||
// "mozbrowserafterkeydown" or "mozbrowserafterkeyup".
|
||||
Nullable<bool> GetEmbeddedCancelled();
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_BeforeAfterKeyboardEvent_h_
|
|
@ -701,6 +701,9 @@ EventDispatcher::CreateEvent(EventTarget* aOwner,
|
|||
case eKeyboardEventClass:
|
||||
return NS_NewDOMKeyboardEvent(aDOMEvent, aOwner, aPresContext,
|
||||
aEvent->AsKeyboardEvent());
|
||||
case eBeforeAfterKeyboardEventClass:
|
||||
return NS_NewDOMBeforeAfterKeyboardEvent(aDOMEvent, aOwner, aPresContext,
|
||||
aEvent->AsBeforeAfterKeyboardEvent());
|
||||
case eCompositionEventClass:
|
||||
return NS_NewDOMCompositionEvent(aDOMEvent, aOwner, aPresContext,
|
||||
aEvent->AsCompositionEvent());
|
||||
|
|
|
@ -237,6 +237,22 @@ EVENT(keyup,
|
|||
NS_KEY_UP,
|
||||
EventNameType_HTMLXUL,
|
||||
eKeyboardEventClass)
|
||||
NON_IDL_EVENT(mozbrowserbeforekeydown,
|
||||
NS_KEY_BEFORE_DOWN,
|
||||
EventNameType_None,
|
||||
eBeforeAfterKeyboardEventClass)
|
||||
NON_IDL_EVENT(mozbrowserafterkeydown,
|
||||
NS_KEY_AFTER_DOWN,
|
||||
EventNameType_None,
|
||||
eBeforeAfterKeyboardEventClass)
|
||||
NON_IDL_EVENT(mozbrowserbeforekeyup,
|
||||
NS_KEY_BEFORE_UP,
|
||||
EventNameType_None,
|
||||
eBeforeAfterKeyboardEventClass)
|
||||
NON_IDL_EVENT(mozbrowserafterkeyup,
|
||||
NS_KEY_AFTER_UP,
|
||||
EventNameType_None,
|
||||
eBeforeAfterKeyboardEventClass)
|
||||
EVENT(loadeddata,
|
||||
NS_LOADEDDATA,
|
||||
EventNameType_HTML,
|
||||
|
|
|
@ -651,8 +651,12 @@ EventStateManager::PreHandleEvent(nsPresContext* aPresContext,
|
|||
}
|
||||
}
|
||||
// then fall through...
|
||||
case NS_KEY_BEFORE_DOWN:
|
||||
case NS_KEY_DOWN:
|
||||
case NS_KEY_AFTER_DOWN:
|
||||
case NS_KEY_BEFORE_UP:
|
||||
case NS_KEY_UP:
|
||||
case NS_KEY_AFTER_UP:
|
||||
{
|
||||
nsIContent* content = GetFocusedContent();
|
||||
if (content)
|
||||
|
@ -3159,7 +3163,9 @@ EventStateManager::PostHandleEvent(nsPresContext* aPresContext,
|
|||
GenerateDragDropEnterExit(presContext, aEvent->AsDragEvent());
|
||||
break;
|
||||
|
||||
case NS_KEY_BEFORE_UP:
|
||||
case NS_KEY_UP:
|
||||
case NS_KEY_AFTER_UP:
|
||||
break;
|
||||
|
||||
case NS_KEY_PRESS:
|
||||
|
|
|
@ -979,6 +979,16 @@ IMEStateManager::OnCompositionEventDiscarded(
|
|||
|
||||
nsRefPtr<TextComposition> composition =
|
||||
sTextCompositions->GetCompositionFor(aCompositionEvent->widget);
|
||||
if (!composition) {
|
||||
// If the PresShell has been being destroyed during composition,
|
||||
// a TextComposition instance for the composition was already removed from
|
||||
// the array and destroyed in OnDestroyPresContext(). Therefore, we may
|
||||
// fail to retrieve a TextComposition instance here.
|
||||
PR_LOG(sISMLog, PR_LOG_ALWAYS,
|
||||
("ISM: IMEStateManager::OnCompositionEventDiscarded(), "
|
||||
"TextComposition instance for the widget has already gone"));
|
||||
return;
|
||||
}
|
||||
composition->OnCompositionEventDiscarded(aCompositionEvent);
|
||||
}
|
||||
|
||||
|
|
|
@ -17,10 +17,8 @@ KeyboardEvent::KeyboardEvent(EventTarget* aOwner,
|
|||
: UIEvent(aOwner, aPresContext,
|
||||
aEvent ? aEvent : new WidgetKeyboardEvent(false, 0, nullptr))
|
||||
, mInitializedByCtor(false)
|
||||
, mInitialzedWhichValue(0)
|
||||
, mInitializedWhichValue(0)
|
||||
{
|
||||
NS_ASSERTION(mEvent->mClass == eKeyboardEventClass, "event type mismatch");
|
||||
|
||||
if (aEvent) {
|
||||
mEventIsInternal = false;
|
||||
}
|
||||
|
@ -257,8 +255,12 @@ KeyboardEvent::CharCode()
|
|||
}
|
||||
|
||||
switch (mEvent->message) {
|
||||
case NS_KEY_UP:
|
||||
case NS_KEY_BEFORE_DOWN:
|
||||
case NS_KEY_DOWN:
|
||||
case NS_KEY_AFTER_DOWN:
|
||||
case NS_KEY_BEFORE_UP:
|
||||
case NS_KEY_UP:
|
||||
case NS_KEY_AFTER_UP:
|
||||
return 0;
|
||||
case NS_KEY_PRESS:
|
||||
return mEvent->AsKeyboardEvent()->charCode;
|
||||
|
@ -282,10 +284,7 @@ KeyboardEvent::KeyCode()
|
|||
return mEvent->AsKeyboardEvent()->keyCode;
|
||||
}
|
||||
|
||||
switch (mEvent->message) {
|
||||
case NS_KEY_UP:
|
||||
case NS_KEY_PRESS:
|
||||
case NS_KEY_DOWN:
|
||||
if (mEvent->HasKeyEventMessage()) {
|
||||
return mEvent->AsKeyboardEvent()->keyCode;
|
||||
}
|
||||
return 0;
|
||||
|
@ -296,12 +295,16 @@ KeyboardEvent::Which()
|
|||
{
|
||||
// If this event is initialized with ctor, which can have independent value.
|
||||
if (mInitializedByCtor) {
|
||||
return mInitialzedWhichValue;
|
||||
return mInitializedWhichValue;
|
||||
}
|
||||
|
||||
switch (mEvent->message) {
|
||||
case NS_KEY_UP:
|
||||
case NS_KEY_BEFORE_DOWN:
|
||||
case NS_KEY_DOWN:
|
||||
case NS_KEY_AFTER_DOWN:
|
||||
case NS_KEY_BEFORE_UP:
|
||||
case NS_KEY_UP:
|
||||
case NS_KEY_AFTER_UP:
|
||||
return KeyCode();
|
||||
case NS_KEY_PRESS:
|
||||
//Special case for 4xp bug 62878. Try to make value of which
|
||||
|
@ -343,26 +346,35 @@ KeyboardEvent::Constructor(const GlobalObject& aGlobal,
|
|||
nsCOMPtr<EventTarget> target = do_QueryInterface(aGlobal.GetAsSupports());
|
||||
nsRefPtr<KeyboardEvent> newEvent =
|
||||
new KeyboardEvent(target, nullptr, nullptr);
|
||||
bool trusted = newEvent->Init(target);
|
||||
aRv = newEvent->InitKeyEvent(aType, aParam.mBubbles, aParam.mCancelable,
|
||||
aParam.mView, aParam.mCtrlKey, aParam.mAltKey,
|
||||
aParam.mShiftKey, aParam.mMetaKey,
|
||||
aParam.mKeyCode, aParam.mCharCode);
|
||||
newEvent->SetTrusted(trusted);
|
||||
newEvent->mDetail = aParam.mDetail;
|
||||
newEvent->mInitializedByCtor = true;
|
||||
newEvent->mInitialzedWhichValue = aParam.mWhich;
|
||||
newEvent->InitWithKeyboardEventInit(target, aType, aParam, aRv);
|
||||
|
||||
WidgetKeyboardEvent* internalEvent = newEvent->mEvent->AsKeyboardEvent();
|
||||
return newEvent.forget();
|
||||
}
|
||||
|
||||
void
|
||||
KeyboardEvent::InitWithKeyboardEventInit(EventTarget* aOwner,
|
||||
const nsAString& aType,
|
||||
const KeyboardEventInit& aParam,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
bool trusted = Init(aOwner);
|
||||
aRv = InitKeyEvent(aType, aParam.mBubbles, aParam.mCancelable,
|
||||
aParam.mView, aParam.mCtrlKey, aParam.mAltKey,
|
||||
aParam.mShiftKey, aParam.mMetaKey,
|
||||
aParam.mKeyCode, aParam.mCharCode);
|
||||
SetTrusted(trusted);
|
||||
mDetail = aParam.mDetail;
|
||||
mInitializedByCtor = true;
|
||||
mInitializedWhichValue = aParam.mWhich;
|
||||
|
||||
WidgetKeyboardEvent* internalEvent = mEvent->AsKeyboardEvent();
|
||||
internalEvent->location = aParam.mLocation;
|
||||
internalEvent->mIsRepeat = aParam.mRepeat;
|
||||
internalEvent->mIsComposing = aParam.mIsComposing;
|
||||
internalEvent->mKeyNameIndex = KEY_NAME_INDEX_USE_STRING;
|
||||
internalEvent->mKeyValue = aParam.mKey;
|
||||
internalEvent->mCodeNameIndex = CODE_NAME_INDEX_USE_STRING;
|
||||
internalEvent->mKeyValue = aParam.mKey;
|
||||
internalEvent->mCodeValue = aParam.mCode;
|
||||
|
||||
return newEvent.forget();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
|
|
@ -74,13 +74,19 @@ public:
|
|||
protected:
|
||||
~KeyboardEvent() {}
|
||||
|
||||
void InitWithKeyboardEventInit(EventTarget* aOwner,
|
||||
const nsAString& aType,
|
||||
const KeyboardEventInit& aParam,
|
||||
ErrorResult& aRv);
|
||||
|
||||
private:
|
||||
// True, if the instance is created with Constructor().
|
||||
bool mInitializedByCtor;
|
||||
|
||||
// If the instance is created with Constructor(), which may have independent
|
||||
// value. mInitializedWhichValue stores it. I.e., this is invalid when
|
||||
// mInitializedByCtor is false.
|
||||
uint32_t mInitialzedWhichValue;
|
||||
uint32_t mInitializedWhichValue;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
|
|
@ -32,6 +32,7 @@ EXPORTS.mozilla += [
|
|||
|
||||
EXPORTS.mozilla.dom += [
|
||||
'AnimationEvent.h',
|
||||
'BeforeAfterKeyboardEvent.h',
|
||||
'BeforeUnloadEvent.h',
|
||||
'ClipboardEvent.h',
|
||||
'CommandEvent.h',
|
||||
|
@ -71,6 +72,7 @@ if CONFIG['MOZ_WEBSPEECH']:
|
|||
UNIFIED_SOURCES += [
|
||||
'AnimationEvent.cpp',
|
||||
'AsyncEventDispatcher.cpp',
|
||||
'BeforeAfterKeyboardEvent.cpp',
|
||||
'BeforeUnloadEvent.cpp',
|
||||
'ClipboardEvent.cpp',
|
||||
'CommandEvent.cpp',
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Embedded iframe</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body onload="getFocus();">
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none"></div>
|
||||
<input id="input" style="display: block;">
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
function getFocus() {
|
||||
input = document.getElementById("input");
|
||||
input.focus();
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,200 @@
|
|||
/*
|
||||
* Constants and helper functions for testing BeforeAfterKeyboardEvent.
|
||||
*/
|
||||
|
||||
const kUnknownEvent = 0x000;
|
||||
const kKeyDownEvent = 0x001;
|
||||
const kKeyUpEvent = 0x002;
|
||||
const kBeforeEvent = 0x010;
|
||||
const kAfterEvent = 0x020;
|
||||
const kParent = 0x100;
|
||||
const kChild = 0x200;
|
||||
|
||||
var gCurrentTest;
|
||||
|
||||
function frameScript()
|
||||
{
|
||||
function handler(e) {
|
||||
var results = sendSyncMessage("forwardevent", { type: e.type });
|
||||
if (results[0]) {
|
||||
e.preventDefault();
|
||||
}
|
||||
}
|
||||
addEventListener('keydown', handler);
|
||||
addEventListener('keyup', handler);
|
||||
addEventListener('mozbrowserbeforekeydown', handler);
|
||||
addEventListener('mozbrowserbeforekeyup', handler);
|
||||
addEventListener('mozbrowserafterkeydown', handler);
|
||||
addEventListener('mozbrowserafterkeyup', handler);
|
||||
}
|
||||
|
||||
function prepareTest(useRemote)
|
||||
{
|
||||
setupHandlers(window, embedderHandler);
|
||||
|
||||
var iframe = document.createElement("iframe");
|
||||
iframe.id = "embedded";
|
||||
iframe.src = "bug989198_embedded.html";
|
||||
iframe.setAttribute("remote", useRemote ? "true" : "false");
|
||||
SpecialPowers.wrap(iframe).mozbrowser = true;
|
||||
|
||||
iframe.addEventListener("mozbrowserloadend", function onloadend() {
|
||||
iframe.removeEventListener("mozbrowserloadend", onloadend);
|
||||
iframe.focus();
|
||||
var mm = SpecialPowers.getBrowserFrameMessageManager(iframe);
|
||||
mm.addMessageListener("forwardevent", function(msg) {
|
||||
return embeddedHandler(msg.json);
|
||||
});
|
||||
mm.loadFrameScript("data:,(" + frameScript.toString() + ")();", false);
|
||||
runTests();
|
||||
return;
|
||||
});
|
||||
|
||||
document.body.appendChild(iframe);
|
||||
}
|
||||
|
||||
function cleanupTest()
|
||||
{
|
||||
teardownHandlers(window, embedderHandler);
|
||||
runTests();
|
||||
}
|
||||
|
||||
function setupHandlers(element, handler)
|
||||
{
|
||||
element.addEventListener('keydown', handler);
|
||||
element.addEventListener('keyup', handler);
|
||||
element.addEventListener('mozbrowserbeforekeydown', handler);
|
||||
element.addEventListener('mozbrowserbeforekeyup', handler);
|
||||
element.addEventListener('mozbrowserafterkeydown', handler);
|
||||
element.addEventListener('mozbrowserafterkeyup', handler);
|
||||
}
|
||||
|
||||
function teardownHandlers(element, handler)
|
||||
{
|
||||
element.removeEventListener('keydown', handler);
|
||||
element.removeEventListener('keyup', handler);
|
||||
element.removeEventListener('mozbrowserbeforekeydown', handler);
|
||||
element.removeEventListener('mozbrowserbeforekeyup', handler);
|
||||
element.removeEventListener('mozbrowserafterkeydown', handler);
|
||||
element.removeEventListener('mozbrowserafterkeyup', handler);
|
||||
}
|
||||
|
||||
function convertNameToCode(name)
|
||||
{
|
||||
switch (name) {
|
||||
case "mozbrowserbeforekeydown":
|
||||
return kBeforeEvent | kKeyDownEvent;
|
||||
case "mozbrowserafterkeydown":
|
||||
return kAfterEvent | kKeyDownEvent;
|
||||
case "mozbrowserbeforekeyup":
|
||||
return kBeforeEvent | kKeyUpEvent;
|
||||
case "mozbrowserafterkeyup":
|
||||
return kAfterEvent | kKeyUpEvent;
|
||||
case "keydown":
|
||||
return kKeyDownEvent;
|
||||
case "keyup":
|
||||
return kKeyUpEvent;
|
||||
default:
|
||||
return kUnknownEvent;
|
||||
}
|
||||
}
|
||||
|
||||
function classifyEvents(test)
|
||||
{
|
||||
// Categorize resultEvents into KEYDOWN group and KEYUP group.
|
||||
for (var i = 0; i < gCurrentTest.resultEvents.length ; i++) {
|
||||
var code = test.resultEvents[i];
|
||||
if ((code & 0xF) == 0x1) { // KEYDOWN
|
||||
test.classifiedEvents[0].push(code);
|
||||
} else if ((code & 0xF) == 0x2) { // KEYUP
|
||||
test.classifiedEvents[1].push(code);
|
||||
} else {
|
||||
ok(false, "Invalid code for events");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function verifyResults(test)
|
||||
{
|
||||
for (var i = 0; i < gCurrentTest.expectedEvents.length; i++) {
|
||||
is(test.classifiedEvents[i].length,
|
||||
test.expectedEvents[i].length,
|
||||
test.description + ": Wrong number of events");
|
||||
|
||||
for (var j = 0; j < gCurrentTest.classifiedEvents[i].length; j++) {
|
||||
var item = test.classifiedEvents[i][j];
|
||||
is(item, test.expectedEvents[i][j],
|
||||
test.description + ": Wrong order of events");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function embeddedHandler(e)
|
||||
{
|
||||
return handler(e, kChild);
|
||||
}
|
||||
|
||||
function embedderHandler(e)
|
||||
{
|
||||
// Verify value of attribute embeddedCancelled
|
||||
handler(e, kParent, function checkEmbeddedCancelled(code){
|
||||
switch (code) {
|
||||
case kBeforeEvent | kKeyDownEvent:
|
||||
case kBeforeEvent | kKeyUpEvent:
|
||||
is(e.embeddedCancelled, null,
|
||||
gCurrentTest.description + ': embeddedCancelled should be null');
|
||||
break;
|
||||
case kAfterEvent | kKeyDownEvent:
|
||||
if ((gCurrentTest.doPreventDefaultAt & 0xFF) == kKeyDownEvent) {
|
||||
is(e.embeddedCancelled, true,
|
||||
gCurrentTest.description + ': embeddedCancelled should be true');
|
||||
} else {
|
||||
is(e.embeddedCancelled, false,
|
||||
gCurrentTest.description + ': embeddedCancelled should be false');
|
||||
}
|
||||
break;
|
||||
case kAfterEvent | kKeyUpEvent:
|
||||
if ((gCurrentTest.doPreventDefaultAt & 0xFF) == kKeyUpEvent) {
|
||||
is(e.embeddedCancelled, true,
|
||||
gCurrentTest.description + ': embeddedCancelled should be true');
|
||||
} else {
|
||||
is(e.embeddedCancelled, false,
|
||||
gCurrentTest.description + ': embeddedCancelled should be false');
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function handler(e, highBit, callback)
|
||||
{
|
||||
var code = convertNameToCode(e.type);
|
||||
var newCode = highBit | code;
|
||||
gCurrentTest.resultEvents.push(newCode);
|
||||
|
||||
if (callback) {
|
||||
callback(code);
|
||||
}
|
||||
|
||||
// Return and let frameScript to handle
|
||||
if (highBit == kChild) {
|
||||
return newCode == gCurrentTest.doPreventDefaultAt;
|
||||
}
|
||||
|
||||
if (newCode == gCurrentTest.doPreventDefaultAt) {
|
||||
e.preventDefault();
|
||||
}
|
||||
}
|
||||
|
||||
function runTests()
|
||||
{
|
||||
if (!tests.length) {
|
||||
SimpleTest.finish();
|
||||
return;
|
||||
}
|
||||
|
||||
var test = tests.shift();
|
||||
test();
|
||||
}
|
|
@ -166,3 +166,12 @@ skip-if = buildapp == 'mulet'
|
|||
[test_onerror_handler_args.html]
|
||||
[test_wheel_default_action.html]
|
||||
skip-if = buildapp == 'mulet' || buildapp == 'b2g' || e10s
|
||||
[test_dom_before_after_keyboard_event.html]
|
||||
support-files =
|
||||
bug989198_embedded.html
|
||||
bug989198_helper.js
|
||||
[test_dom_before_after_keyboard_event_remote.html]
|
||||
support-files =
|
||||
bug989198_embedded.html
|
||||
bug989198_helper.js
|
||||
skip-if = buildapp == 'b2g' || e10s
|
||||
|
|
|
@ -34,6 +34,10 @@ const kEventConstructors = {
|
|||
},
|
||||
AudioProcessingEvent: { create: null, // Cannot create untrusted event from JS.
|
||||
},
|
||||
BeforeAfterKeyboardEvent: { create: function (aName, aProps) {
|
||||
return new BeforeAfterKeyboardEvent(aName, aProps);
|
||||
},
|
||||
},
|
||||
BeforeUnloadEvent: { create: function (aName, aProps) {
|
||||
var e = document.createEvent("beforeunloadevent");
|
||||
e.initEvent(aName, aProps.bubbles, aProps.cancelable);
|
||||
|
|
|
@ -0,0 +1,117 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for Bug 989198</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/NativeKeyCodes.js"></script>
|
||||
<script type="text/javascript" src="bug989198_helper.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body onload="runTests();">
|
||||
<a target="_blank"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=989198">Mozilla Bug 989198</a>
|
||||
<p id="display"></p>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
function testEventOrderAndAttr()
|
||||
{
|
||||
const mainDesc = 'Testing the order of the events';
|
||||
const kTests = [
|
||||
{
|
||||
description: mainDesc,
|
||||
expectedEvents: [ [ kParent | kBeforeEvent | kKeyDownEvent,
|
||||
kChild | kKeyDownEvent,
|
||||
kParent | kAfterEvent | kKeyDownEvent ],
|
||||
[ kParent | kBeforeEvent | kKeyUpEvent,
|
||||
kChild | kKeyUpEvent,
|
||||
kParent | kAfterEvent | kKeyUpEvent ] ],
|
||||
resultEvents: [],
|
||||
classifiedEvents: [ [], [] ],
|
||||
doPreventDefaultAt: kUnknownEvent
|
||||
},
|
||||
{
|
||||
description: mainDesc + ', calling preventDefault() at "mozbrowserbeforekeydown" event',
|
||||
expectedEvents: [ [ kParent | kBeforeEvent | kKeyDownEvent,
|
||||
kParent | kAfterEvent | kKeyDownEvent ],
|
||||
[ kParent | kBeforeEvent | kKeyUpEvent,
|
||||
kChild | kKeyUpEvent,
|
||||
kParent | kAfterEvent | kKeyUpEvent ] ],
|
||||
resultEvents: [],
|
||||
classifiedEvents: [ [], [] ],
|
||||
doPreventDefaultAt: kParent | kBeforeEvent | kKeyDownEvent
|
||||
},
|
||||
{
|
||||
description: mainDesc + ', calling preventDefault() at "mozbrowserbeforekeyup" event',
|
||||
expectedEvents: [ [ kParent | kBeforeEvent | kKeyDownEvent,
|
||||
kChild | kKeyDownEvent,
|
||||
kParent | kAfterEvent | kKeyDownEvent ],
|
||||
[ kParent | kBeforeEvent | kKeyUpEvent,
|
||||
kParent | kAfterEvent | kKeyUpEvent ] ],
|
||||
resultEvents: [],
|
||||
classifiedEvents: [ [], [] ],
|
||||
doPreventDefaultAt: kParent | kBeforeEvent | kKeyUpEvent
|
||||
},
|
||||
{
|
||||
description: mainDesc + ', calling preventDefault() at "keydown" event',
|
||||
expectedEvents: [ [ kParent | kBeforeEvent | kKeyDownEvent,
|
||||
kChild | kKeyDownEvent,
|
||||
kParent | kAfterEvent | kKeyDownEvent ],
|
||||
[ kParent | kBeforeEvent | kKeyUpEvent,
|
||||
kChild | kKeyUpEvent,
|
||||
kParent | kAfterEvent | kKeyUpEvent ] ],
|
||||
resultEvents: [],
|
||||
classifiedEvents: [ [], [] ],
|
||||
doPreventDefaultAt: kChild | kKeyDownEvent
|
||||
},
|
||||
{
|
||||
description: mainDesc + ', calling preventDefault() at "keyup" event',
|
||||
expectedEvents: [ [ kParent | kBeforeEvent | kKeyDownEvent,
|
||||
kChild | kKeyDownEvent,
|
||||
kParent | kAfterEvent | kKeyDownEvent ],
|
||||
[ kParent | kBeforeEvent | kKeyUpEvent,
|
||||
kChild | kKeyUpEvent,
|
||||
kParent | kAfterEvent | kKeyUpEvent ] ],
|
||||
resultEvents: [],
|
||||
classifiedEvents: [ [], [] ],
|
||||
doPreventDefaultAt: kChild | kKeyUpEvent
|
||||
}
|
||||
];
|
||||
|
||||
for (var k = 0; k < kTests.length; k++ ) {
|
||||
gCurrentTest = kTests[k];
|
||||
synthesizeKey('a', {}, document.getElementById("embedded").contentWindow);
|
||||
classifyEvents(kTests[k]);
|
||||
verifyResults(kTests[k]);
|
||||
}
|
||||
|
||||
runTests();
|
||||
}
|
||||
|
||||
var tests = [
|
||||
function addPermissions() {
|
||||
SpecialPowers.pushPermissions(
|
||||
[{ type: "before-after-keyboard-event", allow: true, context: document },
|
||||
{ type: "browser", allow: true, context: document }],
|
||||
runTests);
|
||||
},
|
||||
function addPreferences() {
|
||||
SpecialPowers.pushPrefEnv(
|
||||
{ "set": [["dom.beforeAfterKeyboardEvent.enabled", true],
|
||||
["dom.mozBrowserFramesEnabled", true],
|
||||
["dom.ipc.tabs.disabled", false]] },
|
||||
runTests);
|
||||
},
|
||||
|
||||
// Tests for in-process iframe, i.e. <iframe mozbrowser>.
|
||||
()=>prepareTest(false),
|
||||
testEventOrderAndAttr,
|
||||
cleanupTest,
|
||||
];
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,142 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for Bug 989198</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/NativeKeyCodes.js"></script>
|
||||
<script type="text/javascript" src="bug989198_helper.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body onload="runTests();">
|
||||
<a target="_blank"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=989198">Mozilla Bug 989198</a>
|
||||
<p id="display"></p>
|
||||
<div id="content">
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
const mainDesc = 'Testing the order of the events (OOP)';
|
||||
var testsForEventOrder = [
|
||||
{
|
||||
description: mainDesc,
|
||||
expectedEvents: [ [ kParent | kBeforeEvent | kKeyDownEvent,
|
||||
kParent | kKeyDownEvent,
|
||||
kChild | kKeyDownEvent,
|
||||
kParent | kAfterEvent | kKeyDownEvent ],
|
||||
[ kParent | kBeforeEvent | kKeyUpEvent,
|
||||
kParent | kKeyUpEvent,
|
||||
kChild | kKeyUpEvent,
|
||||
kParent | kAfterEvent | kKeyUpEvent ] ],
|
||||
resultEvents: [],
|
||||
classifiedEvents: [ [], [] ],
|
||||
doPreventDefaultAt: kUnknownEvent
|
||||
},
|
||||
{
|
||||
description: mainDesc + ', calling preventDefault() at "mozbrowserbeforekeydown" event',
|
||||
expectedEvents: [ [ kParent | kBeforeEvent | kKeyDownEvent,
|
||||
kParent | kAfterEvent | kKeyDownEvent ],
|
||||
[ kParent | kBeforeEvent | kKeyUpEvent,
|
||||
kParent | kKeyUpEvent,
|
||||
kChild | kKeyUpEvent,
|
||||
kParent | kAfterEvent | kKeyUpEvent ] ],
|
||||
resultEvents: [],
|
||||
classifiedEvents: [ [], [] ],
|
||||
doPreventDefaultAt: kParent | kBeforeEvent | kKeyDownEvent
|
||||
},
|
||||
{
|
||||
description: mainDesc + ', calling preventDefault() at "mozbrowserbeforekeyup" event',
|
||||
expectedEvents: [ [ kParent | kBeforeEvent | kKeyDownEvent,
|
||||
kParent | kKeyDownEvent,
|
||||
kChild | kKeyDownEvent,
|
||||
kParent | kAfterEvent | kKeyDownEvent ],
|
||||
[ kParent | kBeforeEvent | kKeyUpEvent,
|
||||
kParent | kAfterEvent | kKeyUpEvent ] ],
|
||||
resultEvents: [],
|
||||
classifiedEvents: [ [], [] ],
|
||||
doPreventDefaultAt: kParent | kBeforeEvent | kKeyUpEvent
|
||||
},
|
||||
{
|
||||
description: mainDesc + ', calling preventDefault() at "keydown" event',
|
||||
expectedEvents: [ [ kParent | kBeforeEvent | kKeyDownEvent,
|
||||
kParent | kKeyDownEvent,
|
||||
kChild | kKeyDownEvent,
|
||||
kParent | kAfterEvent | kKeyDownEvent ],
|
||||
[ kParent | kBeforeEvent | kKeyUpEvent,
|
||||
kParent | kKeyUpEvent,
|
||||
kChild | kKeyUpEvent,
|
||||
kParent | kAfterEvent | kKeyUpEvent ] ],
|
||||
resultEvents: [],
|
||||
classifiedEvents: [ [], [] ],
|
||||
doPreventDefaultAt: kChild | kKeyDownEvent
|
||||
},
|
||||
{
|
||||
description: mainDesc + ', calling preventDefault() at "keyup" event',
|
||||
expectedEvents: [ [ kParent | kBeforeEvent | kKeyDownEvent,
|
||||
kParent | kKeyDownEvent,
|
||||
kChild | kKeyDownEvent,
|
||||
kParent | kAfterEvent | kKeyDownEvent ],
|
||||
[ kParent | kBeforeEvent | kKeyUpEvent,
|
||||
kParent | kKeyUpEvent,
|
||||
kChild | kKeyUpEvent,
|
||||
kParent | kAfterEvent | kKeyUpEvent ] ],
|
||||
resultEvents: [],
|
||||
classifiedEvents: [ [], [] ],
|
||||
doPreventDefaultAt: kChild | kKeyUpEvent
|
||||
}
|
||||
];
|
||||
|
||||
function testEventOrder()
|
||||
{
|
||||
if (!testsForEventOrder.length) {
|
||||
runTests();
|
||||
return;
|
||||
}
|
||||
gCurrentTest = testsForEventOrder.shift();
|
||||
|
||||
synthesizeKey('a', {}, document.getElementById("embedded").contentWindow);
|
||||
// It take some time to propagate events to a remote iframe.
|
||||
|
||||
waitAndVerifyResult(0);
|
||||
}
|
||||
|
||||
function waitAndVerifyResult(count) {
|
||||
expectedEventLength = gCurrentTest.expectedEvents[0].length +
|
||||
gCurrentTest.expectedEvents[1].length;
|
||||
if (gCurrentTest.resultEvents.length >= expectedEventLength || count > 10) {
|
||||
classifyEvents(gCurrentTest);
|
||||
verifyResults(gCurrentTest);
|
||||
testEventOrder();
|
||||
}
|
||||
else {
|
||||
setTimeout(()=>waitAndVerifyResult(count + 1), 100);
|
||||
}
|
||||
}
|
||||
|
||||
var tests = [
|
||||
function addPermissions() {
|
||||
SpecialPowers.pushPermissions(
|
||||
[{ type: "before-after-keyboard-event", allow: true, context: document },
|
||||
{ type: "browser", allow: true, context: document }],
|
||||
runTests);
|
||||
},
|
||||
function addPreferences() {
|
||||
SpecialPowers.pushPrefEnv(
|
||||
{ "set": [["dom.beforeAfterKeyboardEvent.enabled", true],
|
||||
["dom.mozBrowserFramesEnabled", true],
|
||||
["dom.ipc.tabs.disabled", false]] },
|
||||
runTests);
|
||||
},
|
||||
|
||||
// Tests for out-of-process iframe, i.el. <iframe mozbrowser remote>
|
||||
()=>prepareTest(true),
|
||||
testEventOrder,
|
||||
cleanupTest
|
||||
];
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -918,7 +918,9 @@ nsGeolocationService::UpdateAccuracy(bool aForceHigh)
|
|||
|
||||
if (XRE_GetProcessType() == GeckoProcessType_Content) {
|
||||
ContentChild* cpc = ContentChild::GetSingleton();
|
||||
cpc->SendSetGeolocationHigherAccuracy(highRequired);
|
||||
if (cpc->IsAlive()) {
|
||||
cpc->SendSetGeolocationHigherAccuracy(highRequired);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -272,6 +272,13 @@ NS_NewDOMKeyboardEvent(nsIDOMEvent** aInstancePtrResult,
|
|||
mozilla::dom::EventTarget* aOwner,
|
||||
nsPresContext* aPresContext,
|
||||
mozilla::WidgetKeyboardEvent* aEvent);
|
||||
|
||||
nsresult
|
||||
NS_NewDOMBeforeAfterKeyboardEvent(nsIDOMEvent** aInstancePtrResult,
|
||||
mozilla::dom::EventTarget* aOwner,
|
||||
nsPresContext* aPresContext,
|
||||
mozilla::InternalBeforeAfterKeyboardEvent* aEvent);
|
||||
|
||||
nsresult
|
||||
NS_NewDOMCompositionEvent(nsIDOMEvent** aInstancePtrResult,
|
||||
mozilla::dom::EventTarget* aOwner,
|
||||
|
|
|
@ -515,12 +515,22 @@ InitOnContentProcessCreated()
|
|||
mozilla::dom::time::InitializeDateCacheCleaner();
|
||||
}
|
||||
|
||||
#if defined(MOZ_TASK_TRACER) && defined(MOZ_NUWA_PROCESS)
|
||||
static void
|
||||
ReinitTaskTracer(void* /*aUnused*/)
|
||||
{
|
||||
mozilla::tasktracer::InitTaskTracer(
|
||||
mozilla::tasktracer::FORKED_AFTER_NUWA);
|
||||
}
|
||||
#endif
|
||||
|
||||
ContentChild::ContentChild()
|
||||
: mID(uint64_t(-1))
|
||||
#ifdef ANDROID
|
||||
,mScreenSize(0, 0)
|
||||
#endif
|
||||
, mCanOverrideProcessName(true)
|
||||
, mIsAlive(true)
|
||||
{
|
||||
// This process is a content process, so it's clearly running in
|
||||
// multiprocess mode!
|
||||
|
@ -594,6 +604,12 @@ ContentChild::Init(MessageLoop* aIOLoop,
|
|||
SendGetProcessAttributes(&mID, &mIsForApp, &mIsForBrowser);
|
||||
InitProcessAttributes();
|
||||
|
||||
#if defined(MOZ_TASK_TRACER) && defined (MOZ_NUWA_PROCESS)
|
||||
if (IsNuwaProcess()) {
|
||||
NuwaAddConstructor(ReinitTaskTracer, nullptr);
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -653,6 +669,12 @@ ContentChild::GetProcessName(nsAString& aName)
|
|||
aName.Assign(mProcessName);
|
||||
}
|
||||
|
||||
bool
|
||||
ContentChild::IsAlive()
|
||||
{
|
||||
return mIsAlive;
|
||||
}
|
||||
|
||||
void
|
||||
ContentChild::GetProcessName(nsACString& aName)
|
||||
{
|
||||
|
@ -1625,6 +1647,7 @@ ContentChild::ActorDestroy(ActorDestroyReason why)
|
|||
svc->UnregisterListener(mConsoleListener);
|
||||
mConsoleListener->mChild = nullptr;
|
||||
}
|
||||
mIsAlive = false;
|
||||
|
||||
XRE_ShutdownChildProcess();
|
||||
}
|
||||
|
|
|
@ -87,10 +87,10 @@ public:
|
|||
const AppInfo& GetAppInfo() {
|
||||
return mAppInfo;
|
||||
}
|
||||
|
||||
void SetProcessName(const nsAString& aName, bool aDontOverride = false);
|
||||
void GetProcessName(nsAString& aName);
|
||||
void GetProcessName(nsACString& aName);
|
||||
bool IsAlive();
|
||||
static void AppendProcessId(nsACString& aName);
|
||||
|
||||
ContentBridgeParent* GetLastBridge() {
|
||||
|
@ -421,6 +421,7 @@ private:
|
|||
bool mIsForApp;
|
||||
bool mIsForBrowser;
|
||||
bool mCanOverrideProcessName;
|
||||
bool mIsAlive;
|
||||
nsString mProcessName;
|
||||
|
||||
static ContentChild* sSingleton;
|
||||
|
|
|
@ -398,6 +398,8 @@ parent:
|
|||
|
||||
ReplyKeyEvent(WidgetKeyboardEvent event);
|
||||
|
||||
DispatchAfterKeyboardEvent(WidgetKeyboardEvent event);
|
||||
|
||||
sync RequestNativeKeyBindings(WidgetKeyboardEvent event)
|
||||
returns (MaybeNativeKeyBinding bindings);
|
||||
|
||||
|
|
|
@ -81,8 +81,8 @@
|
|||
#include "ClientLayerManager.h"
|
||||
#include "LayersLogging.h"
|
||||
#include "nsIOService.h"
|
||||
|
||||
#include "nsColorPickerProxy.h"
|
||||
#include "nsPresShell.h"
|
||||
|
||||
#define BROWSER_ELEMENT_CHILD_SCRIPT \
|
||||
NS_LITERAL_STRING("chrome://global/content/BrowserElementChild.js")
|
||||
|
@ -2362,6 +2362,10 @@ TabChild::RecvRealKeyEvent(const WidgetKeyboardEvent& event,
|
|||
SendReplyKeyEvent(localEvent);
|
||||
}
|
||||
|
||||
if (PresShell::BeforeAfterKeyboardEventEnabled()) {
|
||||
SendDispatchAfterKeyboardEvent(localEvent);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -52,6 +52,7 @@
|
|||
#include "nsIWindowWatcher.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
#include "nsPIWindowWatcher.h"
|
||||
#include "nsPresShell.h"
|
||||
#include "nsPrintfCString.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
@ -1463,6 +1464,29 @@ TabParent::RecvReplyKeyEvent(const WidgetKeyboardEvent& event)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
TabParent::RecvDispatchAfterKeyboardEvent(const WidgetKeyboardEvent& aEvent)
|
||||
{
|
||||
NS_ENSURE_TRUE(mFrameElement, true);
|
||||
|
||||
WidgetKeyboardEvent localEvent(aEvent);
|
||||
localEvent.widget = GetWidget();
|
||||
|
||||
nsIDocument* doc = mFrameElement->OwnerDoc();
|
||||
nsCOMPtr<nsIPresShell> presShell = doc->GetShell();
|
||||
NS_ENSURE_TRUE(presShell, true);
|
||||
|
||||
if (mFrameElement &&
|
||||
PresShell::BeforeAfterKeyboardEventEnabled() &&
|
||||
localEvent.message != NS_KEY_PRESS) {
|
||||
nsCOMPtr<nsINode> node(do_QueryInterface(mFrameElement));
|
||||
presShell->DispatchAfterKeyboardEvent(mFrameElement, localEvent,
|
||||
aEvent.mFlags.mDefaultPrevented);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to answer query event using cached text.
|
||||
*
|
||||
|
|
|
@ -122,6 +122,7 @@ public:
|
|||
virtual bool RecvMoveFocus(const bool& aForward) MOZ_OVERRIDE;
|
||||
virtual bool RecvEvent(const RemoteDOMEvent& aEvent) MOZ_OVERRIDE;
|
||||
virtual bool RecvReplyKeyEvent(const WidgetKeyboardEvent& event);
|
||||
virtual bool RecvDispatchAfterKeyboardEvent(const WidgetKeyboardEvent& event);
|
||||
virtual bool RecvPRenderFrameConstructor(PRenderFrameParent* aActor,
|
||||
ScrollingBehavior* aScrolling,
|
||||
TextureFactoryIdentifier* aFactoryIdentifier,
|
||||
|
|
|
@ -36,13 +36,16 @@ const NFC_ENABLED = libcutils.property_get("ro.moz.nfc.enabled", "false") === "t
|
|||
let DEBUG = NFC.DEBUG_CONTENT_HELPER;
|
||||
|
||||
let debug;
|
||||
if (DEBUG) {
|
||||
debug = function (s) {
|
||||
dump("-*- NfcContentHelper: " + s + "\n");
|
||||
};
|
||||
} else {
|
||||
debug = function (s) {};
|
||||
}
|
||||
function updateDebug() {
|
||||
if (DEBUG) {
|
||||
debug = function (s) {
|
||||
dump("-*- NfcContentHelper: " + s + "\n");
|
||||
};
|
||||
} else {
|
||||
debug = function (s) {};
|
||||
}
|
||||
};
|
||||
updateDebug();
|
||||
|
||||
const NFCCONTENTHELPER_CID =
|
||||
Components.ID("{4d72c120-da5f-11e1-9b23-0800200c9a66}");
|
||||
|
@ -65,6 +68,8 @@ XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
|
|||
|
||||
function NfcContentHelper() {
|
||||
this.initDOMRequestHelper(/* aWindow */ null, NFC_IPC_MSG_NAMES);
|
||||
|
||||
Services.obs.addObserver(this, NFC.TOPIC_MOZSETTINGS_CHANGED, false);
|
||||
Services.obs.addObserver(this, "xpcom-shutdown", false);
|
||||
|
||||
this._requestMap = [];
|
||||
|
@ -86,6 +91,17 @@ NfcContentHelper.prototype = {
|
|||
_requestMap: null,
|
||||
eventTarget: null,
|
||||
|
||||
init: function init(aWindow) {
|
||||
if (aWindow && aWindow.navigator.mozSettings) {
|
||||
let lock = aWindow.navigator.mozSettings.createLock();
|
||||
var nfcDebug = lock.get(NFC.SETTING_NFC_DEBUG);
|
||||
nfcDebug.onsuccess = function _nfcDebug() {
|
||||
DEBUG = nfcDebug.result[NFC.SETTING_NFC_DEBUG];
|
||||
updateDebug();
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
encodeNDEFRecords: function encodeNDEFRecords(records) {
|
||||
let encodedRecords = [];
|
||||
for (let i = 0; i < records.length; i++) {
|
||||
|
@ -328,8 +344,16 @@ NfcContentHelper.prototype = {
|
|||
observe: function observe(subject, topic, data) {
|
||||
if (topic == "xpcom-shutdown") {
|
||||
this.destroyDOMRequestHelper();
|
||||
Services.obs.removeObserver(this, NFC.TOPIC_MOZSETTINGS_CHANGED);
|
||||
Services.obs.removeObserver(this, "xpcom-shutdown");
|
||||
cpmm = null;
|
||||
} else if (topic == NFC.TOPIC_MOZSETTINGS_CHANGED) {
|
||||
if ("wrappedJSObject" in subject) {
|
||||
subject = subject.wrappedJSObject;
|
||||
}
|
||||
if (subject) {
|
||||
this.handle(subject.key, subject.value);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -395,6 +419,15 @@ NfcContentHelper.prototype = {
|
|||
}
|
||||
},
|
||||
|
||||
handle: function handle(name, result) {
|
||||
switch (name) {
|
||||
case NFC.SETTING_NFC_DEBUG:
|
||||
DEBUG = result;
|
||||
updateDebug();
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
handleReadNDEFResponse: function handleReadNDEFResponse(result) {
|
||||
let requester = this._requestMap[result.requestId];
|
||||
if (!requester) {
|
||||
|
|
|
@ -22,6 +22,10 @@ const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
|||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "gSettingsService",
|
||||
"@mozilla.org/settingsService;1",
|
||||
"nsISettingsService");
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "NFC", function () {
|
||||
let obj = {};
|
||||
Cu.import("resource://gre/modules/nfc_consts.js", obj);
|
||||
|
@ -35,13 +39,16 @@ const NFC_ENABLED = libcutils.property_get("ro.moz.nfc.enabled", "false") === "t
|
|||
let DEBUG = NFC.DEBUG_NFC;
|
||||
|
||||
let debug;
|
||||
if (DEBUG) {
|
||||
debug = function (s) {
|
||||
dump("-*- Nfc: " + s + "\n");
|
||||
};
|
||||
} else {
|
||||
debug = function (s) {};
|
||||
}
|
||||
function updateDebug() {
|
||||
if (DEBUG) {
|
||||
debug = function (s) {
|
||||
dump("-*- Nfc: " + s + "\n");
|
||||
};
|
||||
} else {
|
||||
debug = function (s) {};
|
||||
}
|
||||
};
|
||||
updateDebug();
|
||||
|
||||
const NFC_CONTRACTID = "@mozilla.org/nfc;1";
|
||||
const NFC_CID =
|
||||
|
@ -103,6 +110,10 @@ XPCOMUtils.defineLazyGetter(this, "gMessageManager", function () {
|
|||
init: function init(nfc) {
|
||||
this.nfc = nfc;
|
||||
|
||||
let lock = gSettingsService.createLock();
|
||||
lock.get(NFC.SETTING_NFC_DEBUG, this.nfc);
|
||||
|
||||
Services.obs.addObserver(this, NFC.TOPIC_MOZSETTINGS_CHANGED, false);
|
||||
Services.obs.addObserver(this, NFC.TOPIC_XPCOM_SHUTDOWN, false);
|
||||
this._registerMessageListeners();
|
||||
},
|
||||
|
@ -111,6 +122,7 @@ XPCOMUtils.defineLazyGetter(this, "gMessageManager", function () {
|
|||
this.nfc.shutdown();
|
||||
this.nfc = null;
|
||||
|
||||
Services.obs.removeObserver(this, NFC.TOPIC_MOZSETTINGS_CHANGED);
|
||||
Services.obs.removeObserver(this, NFC.TOPIC_XPCOM_SHUTDOWN);
|
||||
this._unregisterMessageListeners();
|
||||
},
|
||||
|
@ -335,6 +347,14 @@ XPCOMUtils.defineLazyGetter(this, "gMessageManager", function () {
|
|||
|
||||
observe: function observe(subject, topic, data) {
|
||||
switch (topic) {
|
||||
case NFC.TOPIC_MOZSETTINGS_CHANGED:
|
||||
if ("wrappedJSObject" in subject) {
|
||||
subject = subject.wrappedJSObject;
|
||||
}
|
||||
if (subject) {
|
||||
this.nfc.handle(subject.key, subject.value);
|
||||
}
|
||||
break;
|
||||
case NFC.TOPIC_XPCOM_SHUTDOWN:
|
||||
this._shutdown();
|
||||
break;
|
||||
|
@ -649,6 +669,18 @@ Nfc.prototype = {
|
|||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* nsISettingsServiceCallback
|
||||
*/
|
||||
handle: function handle(name, result) {
|
||||
switch (name) {
|
||||
case NFC.SETTING_NFC_DEBUG:
|
||||
DEBUG = result;
|
||||
updateDebug();
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* nsIObserver interface methods.
|
||||
*/
|
||||
|
|
|
@ -105,8 +105,11 @@ this.NFC_POWER_LEVEL_DISABLED = 0;
|
|||
this.NFC_POWER_LEVEL_LOW = 1;
|
||||
this.NFC_POWER_LEVEL_ENABLED = 2;
|
||||
|
||||
this.TOPIC_MOZSETTINGS_CHANGED = "mozsettings-changed";
|
||||
this.TOPIC_XPCOM_SHUTDOWN = "xpcom-shutdown";
|
||||
|
||||
this.SETTING_NFC_DEBUG = "nfc.debugging.enabled";
|
||||
|
||||
this.NFC_PEER_EVENT_READY = 0x01;
|
||||
this.NFC_PEER_EVENT_LOST = 0x02;
|
||||
|
||||
|
|
|
@ -27,12 +27,14 @@ interface nsINfcDOMEventTarget : nsISupports
|
|||
void notifyPeerLost(in DOMString sessionToken);
|
||||
};
|
||||
|
||||
[scriptable, uuid(d3f1bdc1-048f-44a8-abe2-bc386edce40b)]
|
||||
[scriptable, uuid(cb9c934d-a7fa-422b-bcc1-4ac39741e6ec)]
|
||||
interface nsINfcContentHelper : nsISupports
|
||||
{
|
||||
const long NFC_EVENT_PEER_READY = 0x01;
|
||||
const long NFC_EVENT_PEER_LOST = 0x02;
|
||||
|
||||
void init(in nsIDOMWindow window);
|
||||
|
||||
boolean checkSessionToken(in DOMString sessionToken);
|
||||
|
||||
nsIDOMDOMRequest readNDEF(in nsIDOMWindow window, in DOMString sessionToken);
|
||||
|
|
|
@ -148,6 +148,9 @@ mozNfc.prototype = {
|
|||
init: function init(aWindow) {
|
||||
debug("mozNfc init called");
|
||||
this._window = aWindow;
|
||||
if (this._nfcContentHelper) {
|
||||
this._nfcContentHelper.init(aWindow);
|
||||
}
|
||||
},
|
||||
|
||||
// Only apps which have nfc-manager permission can call the following interfaces
|
||||
|
|
|
@ -1316,17 +1316,8 @@ function sendMMI(aMmi) {
|
|||
let deferred = Promise.defer();
|
||||
|
||||
telephony.dial(aMmi)
|
||||
.then(request => {
|
||||
ok(request instanceof DOMRequest,
|
||||
"request is instanceof " + request.constructor);
|
||||
|
||||
request.addEventListener("success", function(event) {
|
||||
deferred.resolve(request.result);
|
||||
});
|
||||
|
||||
request.addEventListener("error", function(event) {
|
||||
deferred.reject(request.error);
|
||||
});
|
||||
.then(result => {
|
||||
deferred.resolve(result);
|
||||
}, cause => {
|
||||
deferred.reject(cause);
|
||||
});
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
[DEFAULT]
|
||||
skip-if = !debug || (buildapp == 'b2g') || (toolkit == 'android') #Bug 932350 - Frequent timeouts
|
||||
support-files =
|
||||
child_ip_address.html
|
||||
file_crossdomainprops_inner.html
|
||||
|
@ -10,6 +9,7 @@ support-files =
|
|||
|
||||
[test_crossdomainprops.html]
|
||||
[test_innerWidthHeight_script.html]
|
||||
skip-if = buildapp == 'b2g' || buildapp == 'mulet' || toolkit == 'android' # Bug 1075071 - Permafail on Android/B2G/Mulet
|
||||
[test_location.html]
|
||||
[test_location_framed.html]
|
||||
[test_location_getters.html]
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
[DEFAULT]
|
||||
skip-if = !debug || (buildapp == 'b2g') || (toolkit == 'android') #android(bug 910229) #Bug 932350 - Frequent timeouts
|
||||
skip-if = toolkit == 'gonk' || toolkit == 'android' # Bug 932350 - Frequent timeouts
|
||||
support-files =
|
||||
DOMTestCase.js
|
||||
activity-home.css
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
[DEFAULT]
|
||||
skip-if = !debug || (buildapp == 'b2g') || (toolkit == 'android') # android(bug 910229) #Bug 932350 - Frequent timeouts
|
||||
skip-if = toolkit == 'gonk' || toolkit == 'android' # Bug 932350 - Frequent timeouts
|
||||
support-files =
|
||||
DOMTestCase.js
|
||||
exclusions.js
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
[DEFAULT]
|
||||
skip-if = !debug || (buildapp == 'b2g') || (toolkit == 'android') #android(bug 910229) #Bug 932350 - Frequent timeouts
|
||||
skip-if = toolkit == 'gonk' || toolkit == 'android' # Bug 932350 - Frequent timeouts
|
||||
support-files =
|
||||
DOMTestCase.js
|
||||
files/anchor.html
|
||||
|
|
|
@ -171,6 +171,10 @@ var interfaceNamesInGlobalScope =
|
|||
"BarProp",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"BatteryManager",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "BeforeAfterKeyboardEvent", b2g: true,
|
||||
pref: "dom.beforeAfterKeyboardEvent.enabled",
|
||||
permission: ["embed-apps", "before-after-keyboard-event"]},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"BeforeUnloadEvent",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
|
@ -180,18 +184,18 @@ var interfaceNamesInGlobalScope =
|
|||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"BlobEvent",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "BluetoothAdapter", b2g: true, permission: "bluetooth"},
|
||||
{name: "BluetoothAdapter", b2g: true, permission: ["bluetooth"]},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "BluetoothDevice", b2g: true, permission: "bluetooth"},
|
||||
{name: "BluetoothDevice", b2g: true, permission: ["bluetooth"]},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "BluetoothDeviceEvent", b2g: true, permission: "bluetooth"},
|
||||
{name: "BluetoothDeviceEvent", b2g: true, permission: ["bluetooth"]},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "BluetoothDiscoveryStateChangedEvent", b2g: true,
|
||||
permission: "bluetooth"},
|
||||
permission: ["bluetooth"]},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "BluetoothManager", b2g: true, permission: "bluetooth"},
|
||||
{name: "BluetoothManager", b2g: true, permission: ["bluetooth"]},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "BluetoothStatusChangedEvent", b2g: true, permission: "bluetooth"},
|
||||
{name: "BluetoothStatusChangedEvent", b2g: true, permission: ["bluetooth"]},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "BoxObject", xbl: true},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
|
@ -751,7 +755,7 @@ var interfaceNamesInGlobalScope =
|
|||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"MozSettingsEvent",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "MozSettingsTransactionEvent", permission: "settings-api-read"},
|
||||
{name: "MozSettingsTransactionEvent", permission: ["settings-api-read"]},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"MozSmsEvent",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
|
@ -771,23 +775,23 @@ var interfaceNamesInGlobalScope =
|
|||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "MozWakeLock", b2g: true, pref: "dom.wakelock.enabled"},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "MozWifiCapabilities", b2g: true, permission: "wifi-manage"},
|
||||
{name: "MozWifiCapabilities", b2g: true, permission: ["wifi-manage"]},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "MozWifiConnectionInfoEvent", b2g: true},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "MozWifiStationInfoEvent", b2g: true},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "MozWifiManager", b2g: true, permission: "wifi-manage"},
|
||||
{name: "MozWifiManager", b2g: true, permission: ["wifi-manage"]},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "MozWifiNetwork", b2g: true, permission: "wifi-manage"},
|
||||
{name: "MozWifiNetwork", b2g: true, permission: ["wifi-manage"]},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "MozWifiStatusChangeEvent", b2g: true},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "MozWifiP2pGroupOwner", b2g: true, permission: "wifi-manage"},
|
||||
{name: "MozWifiP2pGroupOwner", b2g: true, permission: ["wifi-manage"]},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "MozWifiP2pManager", b2g: true, permission: "wifi-manage"},
|
||||
{name: "MozWifiP2pManager", b2g: true, permission: ["wifi-manage"]},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "MozWifiP2pStatusChangeEvent", b2g: true, permission: "wifi-manage"},
|
||||
{name: "MozWifiP2pStatusChangeEvent", b2g: true, permission: ["wifi-manage"]},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"MutationEvent",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
|
@ -845,9 +849,9 @@ var interfaceNamesInGlobalScope =
|
|||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"PeriodicWave",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "PermissionSettings", b2g: true, permission: "permissions"},
|
||||
{name: "PermissionSettings", b2g: true, permission: ["permissions"]},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "PhoneNumberService", permission: "phonenumberservice"},
|
||||
{name: "PhoneNumberService", permission: ["phonenumberservice"]},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"Plugin",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
|
@ -1227,9 +1231,11 @@ var interfaceNamesInGlobalScope =
|
|||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"TreeWalker",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "UDPMessageEvent", pref: "dom.udpsocket.enabled", permission: "udp-socket"},
|
||||
{name: "UDPMessageEvent", pref: "dom.udpsocket.enabled",
|
||||
permission: ["udp-socket"]},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "UDPSocket", pref: "dom.udpsocket.enabled", permission: "udp-socket"},
|
||||
{name: "UDPSocket", pref: "dom.udpsocket.enabled",
|
||||
permission: ["udp-socket"]},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"UIEvent",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
|
@ -1339,8 +1345,12 @@ function createInterfaceMap(isXBLScope) {
|
|||
var isRelease = !version.contains("a");
|
||||
var isDesktop = !/Mobile|Tablet/.test(navigator.userAgent);
|
||||
var isB2G = !isDesktop && !navigator.userAgent.contains("Android");
|
||||
var hasPermission = function (aPermission) {
|
||||
return SpecialPowers.hasPermission(aPermission, window.document);
|
||||
var hasPermission = function (aPermissions) {
|
||||
var result = false;
|
||||
for (var p of aPermissions) {
|
||||
result = result || SpecialPowers.hasPermission(p, window.document);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
var interfaceMap = {};
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
[Constructor(DOMString typeArg,
|
||||
optional BeforeAfterKeyboardEventInit eventInitDict),
|
||||
CheckPermissions="embed-apps before-after-keyboard-event",
|
||||
Pref="dom.beforeAfterKeyboardEvent.enabled"]
|
||||
interface BeforeAfterKeyboardEvent : KeyboardEvent
|
||||
{
|
||||
// The valid value of embeddedCancelled is:
|
||||
// - "mozbrowserbeforekeydown": null
|
||||
// - "mozbrowserbeforekeyup": null
|
||||
// - "mozbrowserafterkeydown": true/false
|
||||
// - "mozbrowserafterkeyup": true/false
|
||||
readonly attribute boolean? embeddedCancelled;
|
||||
};
|
||||
|
||||
dictionary BeforeAfterKeyboardEventInit : KeyboardEventInit
|
||||
{
|
||||
boolean? embeddedCancelled = null;
|
||||
};
|
|
@ -3,8 +3,10 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
interface DOMCursor : DOMRequest {
|
||||
interface DOMCursor : EventTarget {
|
||||
readonly attribute boolean done;
|
||||
[Throws]
|
||||
void continue();
|
||||
};
|
||||
|
||||
DOMCursor implements DOMRequestShared;
|
||||
|
|
|
@ -5,7 +5,8 @@
|
|||
|
||||
enum DOMRequestReadyState { "pending", "done" };
|
||||
|
||||
interface DOMRequest : EventTarget {
|
||||
[NoInterfaceObject]
|
||||
interface DOMRequestShared {
|
||||
readonly attribute DOMRequestReadyState readyState;
|
||||
|
||||
readonly attribute any result;
|
||||
|
@ -14,3 +15,13 @@ interface DOMRequest : EventTarget {
|
|||
attribute EventHandler onsuccess;
|
||||
attribute EventHandler onerror;
|
||||
};
|
||||
|
||||
interface DOMRequest : EventTarget {
|
||||
// The [TreatNonCallableAsNull] annotation is required since then() should do
|
||||
// nothing instead of throwing errors when non-callable arguments are passed.
|
||||
[NewObject, Throws]
|
||||
Promise<any> then([TreatNonCallableAsNull] optional AnyCallback? fulfillCallback = null,
|
||||
[TreatNonCallableAsNull] optional AnyCallback? rejectCallback = null);
|
||||
};
|
||||
|
||||
DOMRequest implements DOMRequestShared;
|
||||
|
|
|
@ -49,6 +49,7 @@ WEBIDL_FILES = [
|
|||
'AutocompleteInfo.webidl',
|
||||
'BarProp.webidl',
|
||||
'BatteryManager.webidl',
|
||||
'BeforeAfterKeyboardEvent.webidl',
|
||||
'BeforeUnloadEvent.webidl',
|
||||
'BiquadFilterNode.webidl',
|
||||
'Blob.webidl',
|
||||
|
|
|
@ -545,9 +545,8 @@ static const FeatureInfo sFeatureInfoArr[] = {
|
|||
"transform_feedback2",
|
||||
400, // OpenGL version
|
||||
300, // OpenGL ES version
|
||||
GLContext::Extension_None,
|
||||
GLContext::ARB_transform_feedback2,
|
||||
{
|
||||
GLContext::ARB_transform_feedback2,
|
||||
GLContext::NV_transform_feedback2,
|
||||
GLContext::Extensions_End
|
||||
}
|
||||
|
|
|
@ -652,7 +652,12 @@ AddressOf(AsmJSImmKind kind, ExclusiveContext *cx)
|
|||
case AsmJSImm_ModD:
|
||||
return RedirectCall(FuncCast(NumberMod), Args_Double_DoubleDouble);
|
||||
case AsmJSImm_SinD:
|
||||
#ifdef _WIN64
|
||||
// Workaround a VS 2013 sin issue, see math_sin_uncached.
|
||||
return RedirectCall(FuncCast<double (double)>(js::math_sin_uncached), Args_Double_Double);
|
||||
#else
|
||||
return RedirectCall(FuncCast<double (double)>(sin), Args_Double_Double);
|
||||
#endif
|
||||
case AsmJSImm_CosD:
|
||||
return RedirectCall(FuncCast<double (double)>(cos), Args_Double_Double);
|
||||
case AsmJSImm_TanD:
|
||||
|
|
|
@ -516,7 +516,7 @@ class StructTypeDescr : public ComplexTypeDescr
|
|||
}
|
||||
|
||||
NativeObject &maybeForwardedFieldInfoObject(size_t slot) const {
|
||||
return *MaybeForwarded(&fieldInfoObject(slot));
|
||||
return MaybeForwarded(&getReservedSlot(slot).toObject())->as<NativeObject>();
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -472,6 +472,7 @@ class GCRuntime
|
|||
|
||||
template <AllowGC allowGC>
|
||||
static void *refillFreeListFromAnyThread(ThreadSafeContext *cx, AllocKind thingKind);
|
||||
static void *refillFreeListInGC(Zone *zone, AllocKind thingKind);
|
||||
|
||||
private:
|
||||
// For ArenaLists::allocateFromArena()
|
||||
|
@ -483,7 +484,6 @@ class GCRuntime
|
|||
static void *refillFreeListFromMainThread(JSContext *cx, AllocKind thingKind);
|
||||
static void *refillFreeListOffMainThread(ExclusiveContext *cx, AllocKind thingKind);
|
||||
static void *refillFreeListPJS(ForkJoinContext *cx, AllocKind thingKind);
|
||||
static void *refillFreeListInGC(Zone *zone, AllocKind thingKind);
|
||||
|
||||
/*
|
||||
* Return the list of chunks that can be released outside the GC lock.
|
||||
|
|
|
@ -4008,6 +4008,7 @@ CodeGenerator::emitDebugResultChecks(LInstruction *ins)
|
|||
default:
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -7459,10 +7460,18 @@ CodeGenerator::link(JSContext *cx, types::CompilerConstraintList *constraints)
|
|||
|
||||
// Check to make sure we didn't have a mid-build invalidation. If so, we
|
||||
// will trickle to jit::Compile() and return Method_Skipped.
|
||||
uint32_t warmUpCount = script->getWarmUpCount();
|
||||
types::RecompileInfo recompileInfo;
|
||||
if (!types::FinishCompilation(cx, script, executionMode, constraints, &recompileInfo))
|
||||
return true;
|
||||
|
||||
// IonMonkey could have inferred better type information during
|
||||
// compilation. Since adding the new information to the actual type
|
||||
// information can reset the usecount, increase it back to what it was
|
||||
// before.
|
||||
if (warmUpCount > script->getWarmUpCount())
|
||||
script->incWarmUpCounter(warmUpCount - script->getWarmUpCount());
|
||||
|
||||
uint32_t scriptFrameSize = frameClass_ == FrameSizeClass::None()
|
||||
? frameDepth_
|
||||
: FrameSizeClass::FromDepth(frameDepth_).frameSize();
|
||||
|
@ -9720,18 +9729,31 @@ CodeGenerator::visitAsmJSInterruptCheck(LAsmJSInterruptCheck *lir)
|
|||
typedef bool (*RecompileFn)(JSContext *);
|
||||
static const VMFunction RecompileFnInfo = FunctionInfo<RecompileFn>(Recompile);
|
||||
|
||||
typedef bool (*ForcedRecompileFn)(JSContext *);
|
||||
static const VMFunction ForcedRecompileFnInfo = FunctionInfo<ForcedRecompileFn>(ForcedRecompile);
|
||||
|
||||
bool
|
||||
CodeGenerator::visitRecompileCheck(LRecompileCheck *ins)
|
||||
{
|
||||
Label done;
|
||||
Register tmp = ToRegister(ins->scratch());
|
||||
OutOfLineCode *ool = oolCallVM(RecompileFnInfo, ins, (ArgList()), StoreRegisterTo(tmp));
|
||||
OutOfLineCode *ool;
|
||||
if (ins->mir()->forceRecompilation())
|
||||
ool = oolCallVM(ForcedRecompileFnInfo, ins, (ArgList()), StoreRegisterTo(tmp));
|
||||
else
|
||||
ool = oolCallVM(RecompileFnInfo, ins, (ArgList()), StoreRegisterTo(tmp));
|
||||
|
||||
// Check if warm-up counter is high enough.
|
||||
masm.movePtr(ImmPtr(ins->mir()->script()->addressOfWarmUpCounter()), tmp);
|
||||
Address ptr(tmp, 0);
|
||||
masm.add32(Imm32(1), tmp);
|
||||
masm.branch32(Assembler::BelowOrEqual, ptr, Imm32(ins->mir()->recompileThreshold()), &done);
|
||||
AbsoluteAddress warmUpCount = AbsoluteAddress(ins->mir()->script()->addressOfWarmUpCounter());
|
||||
if (ins->mir()->increaseWarmUpCounter()) {
|
||||
masm.load32(warmUpCount, tmp);
|
||||
masm.add32(Imm32(1), tmp);
|
||||
masm.store32(tmp, warmUpCount);
|
||||
masm.branch32(Assembler::BelowOrEqual, tmp, Imm32(ins->mir()->recompileThreshold()), &done);
|
||||
} else {
|
||||
masm.branch32(Assembler::BelowOrEqual, warmUpCount, Imm32(ins->mir()->recompileThreshold()),
|
||||
&done);
|
||||
}
|
||||
|
||||
// Check if not yet recompiling.
|
||||
CodeOffsetLabel label = masm.movWithPatch(ImmWord(uintptr_t(-1)), tmp);
|
||||
|
|
|
@ -2221,7 +2221,7 @@ GetOptimizationLevel(HandleScript script, jsbytecode *pc, ExecutionMode executio
|
|||
|
||||
static MethodStatus
|
||||
Compile(JSContext *cx, HandleScript script, BaselineFrame *osrFrame, jsbytecode *osrPc,
|
||||
bool constructing, ExecutionMode executionMode)
|
||||
bool constructing, ExecutionMode executionMode, bool forceRecompile = false)
|
||||
{
|
||||
MOZ_ASSERT(jit::IsIonEnabled(cx));
|
||||
MOZ_ASSERT(jit::IsBaselineEnabled(cx));
|
||||
|
@ -2258,35 +2258,17 @@ Compile(JSContext *cx, HandleScript script, BaselineFrame *osrFrame, jsbytecode
|
|||
if (!scriptIon->method())
|
||||
return Method_CantCompile;
|
||||
|
||||
MethodStatus failedState = Method_Compiled;
|
||||
|
||||
// If we keep failing to enter the script due to an OSR pc mismatch,
|
||||
// recompile with the right pc.
|
||||
if (osrPc && script->ionScript()->osrPc() != osrPc) {
|
||||
uint32_t count = script->ionScript()->incrOsrPcMismatchCounter();
|
||||
if (count <= js_JitOptions.osrPcMismatchesBeforeRecompile)
|
||||
return Method_Skipped;
|
||||
|
||||
failedState = Method_Skipped;
|
||||
}
|
||||
|
||||
// Don't recompile/overwrite higher optimized code,
|
||||
// with a lower optimization level.
|
||||
if (optimizationLevel < scriptIon->optimizationLevel())
|
||||
return failedState;
|
||||
|
||||
if (optimizationLevel == scriptIon->optimizationLevel() &&
|
||||
(!osrPc || script->ionScript()->osrPc() == osrPc))
|
||||
{
|
||||
return failedState;
|
||||
}
|
||||
if (optimizationLevel <= scriptIon->optimizationLevel() && !forceRecompile)
|
||||
return Method_Compiled;
|
||||
|
||||
// Don't start compiling if already compiling
|
||||
if (scriptIon->isRecompiling())
|
||||
return failedState;
|
||||
return Method_Compiled;
|
||||
|
||||
if (osrPc)
|
||||
script->ionScript()->resetOsrPcMismatchCounter();
|
||||
scriptIon->resetOsrPcMismatchCounter();
|
||||
|
||||
recompile = true;
|
||||
}
|
||||
|
@ -2305,11 +2287,8 @@ Compile(JSContext *cx, HandleScript script, BaselineFrame *osrFrame, jsbytecode
|
|||
}
|
||||
|
||||
// Compilation succeeded or we invalidated right away or an inlining/alloc abort
|
||||
if (HasIonScript(script, executionMode)) {
|
||||
if (osrPc && script->ionScript()->osrPc() != osrPc)
|
||||
return Method_Skipped;
|
||||
if (HasIonScript(script, executionMode))
|
||||
return Method_Compiled;
|
||||
}
|
||||
return Method_Skipped;
|
||||
}
|
||||
|
||||
|
@ -2347,6 +2326,16 @@ jit::CanEnterAtBranch(JSContext *cx, JSScript *script, BaselineFrame *osrFrame,
|
|||
return Method_CantCompile;
|
||||
}
|
||||
|
||||
// By default a recompilation doesn't happen on osr mismatch.
|
||||
// Decide if we want to force a recompilation if this happens too much.
|
||||
bool force = false;
|
||||
if (script->hasIonScript() && pc != script->ionScript()->osrPc()) {
|
||||
uint32_t count = script->ionScript()->incrOsrPcMismatchCounter();
|
||||
if (count <= js_JitOptions.osrPcMismatchesBeforeRecompile)
|
||||
return Method_Skipped;
|
||||
force = true;
|
||||
}
|
||||
|
||||
// Attempt compilation.
|
||||
// - Returns Method_Compiled if the right ionscript is present
|
||||
// (Meaning it was present or a sequantial compile finished)
|
||||
|
@ -2354,13 +2343,20 @@ jit::CanEnterAtBranch(JSContext *cx, JSScript *script, BaselineFrame *osrFrame,
|
|||
// (This means a background thread compilation with that pc could have started or not.)
|
||||
RootedScript rscript(cx, script);
|
||||
MethodStatus status = Compile(cx, rscript, osrFrame, pc, osrFrame->isConstructing(),
|
||||
SequentialExecution);
|
||||
SequentialExecution, force);
|
||||
if (status != Method_Compiled) {
|
||||
if (status == Method_CantCompile)
|
||||
ForbidCompilation(cx, script);
|
||||
return status;
|
||||
}
|
||||
|
||||
// Return the compilation was skipped when the osr pc wasn't adjusted.
|
||||
// This can happen when there was still an IonScript available and a
|
||||
// background compilation started, but hasn't finished yet.
|
||||
// Or when we didn't force a recompile.
|
||||
if (pc != script->ionScript()->osrPc())
|
||||
return Method_Skipped;
|
||||
|
||||
return Method_Compiled;
|
||||
}
|
||||
|
||||
|
@ -2461,14 +2457,14 @@ jit::CompileFunctionForBaseline(JSContext *cx, HandleScript script, BaselineFram
|
|||
|
||||
MethodStatus
|
||||
jit::Recompile(JSContext *cx, HandleScript script, BaselineFrame *osrFrame, jsbytecode *osrPc,
|
||||
bool constructing)
|
||||
bool constructing, bool force)
|
||||
{
|
||||
MOZ_ASSERT(script->hasIonScript());
|
||||
if (script->ionScript()->isRecompiling())
|
||||
return Method_Compiled;
|
||||
|
||||
MethodStatus status =
|
||||
Compile(cx, script, osrFrame, osrPc, constructing, SequentialExecution);
|
||||
Compile(cx, script, osrFrame, osrPc, constructing, SequentialExecution, force);
|
||||
if (status != Method_Compiled) {
|
||||
if (status == Method_CantCompile)
|
||||
ForbidCompilation(cx, script);
|
||||
|
|
|
@ -93,7 +93,7 @@ MethodStatus CanEnterInParallel(JSContext *cx, HandleScript script);
|
|||
|
||||
MethodStatus
|
||||
Recompile(JSContext *cx, HandleScript script, BaselineFrame *osrFrame, jsbytecode *osrPc,
|
||||
bool constructing);
|
||||
bool constructing, bool force);
|
||||
|
||||
enum IonExecStatus
|
||||
{
|
||||
|
|
|
@ -4454,7 +4454,9 @@ IonBuilder::makeInliningDecision(JSFunction *target, CallInfo &callInfo)
|
|||
!targetScript->baselineScript()->ionCompiledOrInlined() &&
|
||||
info().executionMode() != DefinitePropertiesAnalysis)
|
||||
{
|
||||
return DontInline(targetScript, "Vetoed: callee is insufficiently hot.");
|
||||
JitSpew(JitSpew_Inlining, "Cannot inline %s:%u: callee is insufficiently hot.",
|
||||
targetScript->filename(), targetScript->lineno());
|
||||
return InliningDecision_WarmUpCountTooLow;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4489,6 +4491,7 @@ IonBuilder::selectInliningTargets(ObjectVector &targets, CallInfo &callInfo, Boo
|
|||
case InliningDecision_Error:
|
||||
return false;
|
||||
case InliningDecision_DontInline:
|
||||
case InliningDecision_WarmUpCountTooLow:
|
||||
inlineable = false;
|
||||
break;
|
||||
case InliningDecision_Inline:
|
||||
|
@ -4664,6 +4667,8 @@ IonBuilder::inlineCallsite(ObjectVector &targets, ObjectVector &originals,
|
|||
return InliningStatus_Error;
|
||||
case InliningDecision_DontInline:
|
||||
return InliningStatus_NotInlined;
|
||||
case InliningDecision_WarmUpCountTooLow:
|
||||
return InliningStatus_WarmUpCountTooLow;
|
||||
case InliningDecision_Inline:
|
||||
break;
|
||||
}
|
||||
|
@ -5278,6 +5283,7 @@ IonBuilder::jsop_funcall(uint32_t argc)
|
|||
case InliningDecision_Error:
|
||||
return false;
|
||||
case InliningDecision_DontInline:
|
||||
case InliningDecision_WarmUpCountTooLow:
|
||||
break;
|
||||
case InliningDecision_Inline:
|
||||
if (target->isInterpreted())
|
||||
|
@ -5418,6 +5424,7 @@ IonBuilder::jsop_funapplyarguments(uint32_t argc)
|
|||
case InliningDecision_Error:
|
||||
return false;
|
||||
case InliningDecision_DontInline:
|
||||
case InliningDecision_WarmUpCountTooLow:
|
||||
break;
|
||||
case InliningDecision_Inline:
|
||||
if (target->isInterpreted())
|
||||
|
@ -5488,6 +5495,14 @@ IonBuilder::jsop_call(uint32_t argc, bool constructing)
|
|||
if (targets.length() == 1)
|
||||
target = &targets[0]->as<JSFunction>();
|
||||
|
||||
if (target && status == InliningStatus_WarmUpCountTooLow) {
|
||||
MRecompileCheck *check =
|
||||
MRecompileCheck::New(alloc(), target->nonLazyScript(),
|
||||
optimizationInfo().inliningRecompileThreshold(),
|
||||
MRecompileCheck::RecompileCheck_Inlining);
|
||||
current->add(check);
|
||||
}
|
||||
|
||||
return makeCall(target, callInfo, hasClones);
|
||||
}
|
||||
|
||||
|
@ -6504,7 +6519,9 @@ IonBuilder::insertRecompileCheck()
|
|||
OptimizationLevel nextLevel = js_IonOptimizations.nextLevel(curLevel);
|
||||
const OptimizationInfo *info = js_IonOptimizations.get(nextLevel);
|
||||
uint32_t warmUpThreshold = info->compilerWarmUpThreshold(topBuilder->script());
|
||||
current->add(MRecompileCheck::New(alloc(), topBuilder->script(), warmUpThreshold));
|
||||
MRecompileCheck *check = MRecompileCheck::New(alloc(), topBuilder->script(), warmUpThreshold,
|
||||
MRecompileCheck::RecompileCheck_OptimizationLevel);
|
||||
current->add(check);
|
||||
}
|
||||
|
||||
JSObject *
|
||||
|
@ -9425,6 +9442,7 @@ IonBuilder::getPropTryCommonGetter(bool *emitted, MDefinition *obj, PropertyName
|
|||
switch (status) {
|
||||
case InliningStatus_Error:
|
||||
return false;
|
||||
case InliningStatus_WarmUpCountTooLow:
|
||||
case InliningStatus_NotInlined:
|
||||
break;
|
||||
case InliningStatus_Inlined:
|
||||
|
@ -9441,6 +9459,7 @@ IonBuilder::getPropTryCommonGetter(bool *emitted, MDefinition *obj, PropertyName
|
|||
case InliningDecision_Error:
|
||||
return false;
|
||||
case InliningDecision_DontInline:
|
||||
case InliningDecision_WarmUpCountTooLow:
|
||||
break;
|
||||
case InliningDecision_Inline:
|
||||
inlineable = true;
|
||||
|
@ -9865,6 +9884,7 @@ IonBuilder::setPropTryCommonSetter(bool *emitted, MDefinition *obj,
|
|||
case InliningDecision_Error:
|
||||
return false;
|
||||
case InliningDecision_DontInline:
|
||||
case InliningDecision_WarmUpCountTooLow:
|
||||
break;
|
||||
case InliningDecision_Inline:
|
||||
if (!inlineScriptedCall(callInfo, commonSetter))
|
||||
|
|
|
@ -666,6 +666,7 @@ class IonBuilder
|
|||
{
|
||||
InliningStatus_Error,
|
||||
InliningStatus_NotInlined,
|
||||
InliningStatus_WarmUpCountTooLow,
|
||||
InliningStatus_Inlined
|
||||
};
|
||||
|
||||
|
@ -673,7 +674,8 @@ class IonBuilder
|
|||
{
|
||||
InliningDecision_Error,
|
||||
InliningDecision_Inline,
|
||||
InliningDecision_DontInline
|
||||
InliningDecision_DontInline,
|
||||
InliningDecision_WarmUpCountTooLow
|
||||
};
|
||||
|
||||
static InliningDecision DontInline(JSScript *targetScript, const char *reason);
|
||||
|
|
|
@ -42,6 +42,7 @@ OptimizationInfo::initNormalOptimizationInfo()
|
|||
smallFunctionMaxInlineDepth_ = 10;
|
||||
compilerWarmUpThreshold_ = 1000;
|
||||
inliningWarmUpThresholdFactor_ = 0.125;
|
||||
inliningRecompileThresholdFactor_ = 4;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -108,6 +108,11 @@ class OptimizationInfo
|
|||
// are inlined, as a fraction of compilerWarmUpThreshold.
|
||||
double inliningWarmUpThresholdFactor_;
|
||||
|
||||
// How many invocations or loop iterations are needed before a function
|
||||
// is hot enough to recompile the outerScript to inline that function,
|
||||
// as a multiplication of inliningWarmUpThreshold.
|
||||
uint32_t inliningRecompileThresholdFactor_;
|
||||
|
||||
OptimizationInfo()
|
||||
{ }
|
||||
|
||||
|
@ -194,6 +199,10 @@ class OptimizationInfo
|
|||
compilerWarmUpThreshold = js_JitOptions.forcedDefaultIonWarmUpThreshold;
|
||||
return compilerWarmUpThreshold * inliningWarmUpThresholdFactor_;
|
||||
}
|
||||
|
||||
uint32_t inliningRecompileThreshold() const {
|
||||
return inliningWarmUpThreshold() * inliningRecompileThresholdFactor_;
|
||||
}
|
||||
};
|
||||
|
||||
class OptimizationInfos
|
||||
|
|
|
@ -11205,21 +11205,45 @@ class MHasClass
|
|||
// outermost script (i.e. not the inlined script).
|
||||
class MRecompileCheck : public MNullaryInstruction
|
||||
{
|
||||
public:
|
||||
enum RecompileCheckType {
|
||||
RecompileCheck_OptimizationLevel,
|
||||
RecompileCheck_Inlining
|
||||
};
|
||||
|
||||
private:
|
||||
JSScript *script_;
|
||||
uint32_t recompileThreshold_;
|
||||
bool forceRecompilation_;
|
||||
bool increaseWarmUpCounter_;
|
||||
|
||||
MRecompileCheck(JSScript *script, uint32_t recompileThreshold)
|
||||
MRecompileCheck(JSScript *script, uint32_t recompileThreshold, RecompileCheckType type)
|
||||
: script_(script),
|
||||
recompileThreshold_(recompileThreshold)
|
||||
{
|
||||
switch (type) {
|
||||
case RecompileCheck_OptimizationLevel:
|
||||
forceRecompilation_ = false;
|
||||
increaseWarmUpCounter_ = true;
|
||||
break;
|
||||
case RecompileCheck_Inlining:
|
||||
forceRecompilation_ = true;
|
||||
increaseWarmUpCounter_ = false;
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("Unexpected recompile check type");
|
||||
}
|
||||
|
||||
setGuard();
|
||||
}
|
||||
|
||||
public:
|
||||
INSTRUCTION_HEADER(RecompileCheck);
|
||||
|
||||
static MRecompileCheck *New(TempAllocator &alloc, JSScript *script_, uint32_t recompileThreshold) {
|
||||
return new(alloc) MRecompileCheck(script_, recompileThreshold);
|
||||
static MRecompileCheck *New(TempAllocator &alloc, JSScript *script_, uint32_t recompileThreshold,
|
||||
RecompileCheckType type)
|
||||
{
|
||||
return new(alloc) MRecompileCheck(script_, recompileThreshold, type);
|
||||
}
|
||||
|
||||
JSScript *script() const {
|
||||
|
@ -11230,6 +11254,14 @@ class MRecompileCheck : public MNullaryInstruction
|
|||
return recompileThreshold_;
|
||||
}
|
||||
|
||||
bool forceRecompilation() const {
|
||||
return forceRecompilation_;
|
||||
}
|
||||
|
||||
bool increaseWarmUpCounter() const {
|
||||
return increaseWarmUpCounter_;
|
||||
}
|
||||
|
||||
AliasSet getAliasSet() const {
|
||||
return AliasSet::None();
|
||||
}
|
||||
|
|
|
@ -1049,7 +1049,7 @@ StringReplace(JSContext *cx, HandleString string, HandleString pattern, HandleSt
|
|||
}
|
||||
|
||||
bool
|
||||
Recompile(JSContext *cx)
|
||||
RecompileImpl(JSContext *cx, bool force)
|
||||
{
|
||||
MOZ_ASSERT(cx->currentlyRunningInJit());
|
||||
JitActivationIterator activations(cx->runtime());
|
||||
|
@ -1065,13 +1065,25 @@ Recompile(JSContext *cx)
|
|||
if (!IsIonEnabled(cx))
|
||||
return true;
|
||||
|
||||
MethodStatus status = Recompile(cx, script, nullptr, nullptr, isConstructing);
|
||||
MethodStatus status = Recompile(cx, script, nullptr, nullptr, isConstructing, force);
|
||||
if (status == Method_Error)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ForcedRecompile(JSContext *cx)
|
||||
{
|
||||
return RecompileImpl(cx, /* force = */ true);
|
||||
}
|
||||
|
||||
bool
|
||||
Recompile(JSContext *cx)
|
||||
{
|
||||
return RecompileImpl(cx, /* force = */ false);
|
||||
}
|
||||
|
||||
bool
|
||||
SetDenseElement(JSContext *cx, HandleNativeObject obj, int32_t index, HandleValue value,
|
||||
bool strict)
|
||||
|
|
|
@ -724,6 +724,7 @@ JSObject *CreateDerivedTypedObj(JSContext *cx, HandleObject descr,
|
|||
bool ArraySpliceDense(JSContext *cx, HandleObject obj, uint32_t start, uint32_t deleteCount);
|
||||
|
||||
bool Recompile(JSContext *cx);
|
||||
bool ForcedRecompile(JSContext *cx);
|
||||
JSString *RegExpReplace(JSContext *cx, HandleString string, HandleObject regexp,
|
||||
HandleString repl);
|
||||
JSString *StringReplace(JSContext *cx, HandleString string, HandleString pattern,
|
||||
|
|
|
@ -2157,7 +2157,7 @@ RelocateCell(Zone *zone, TenuredCell *src, AllocKind thingKind, size_t thingSize
|
|||
MOZ_ASSERT(zone == src->zone());
|
||||
void *dstAlloc = zone->allocator.arenas.allocateFromFreeList(thingKind, thingSize);
|
||||
if (!dstAlloc)
|
||||
dstAlloc = js::gc::ArenaLists::refillFreeListInGC(zone, thingKind);
|
||||
dstAlloc = GCRuntime::refillFreeListInGC(zone, thingKind);
|
||||
if (!dstAlloc)
|
||||
return false;
|
||||
TenuredCell *dst = TenuredCell::fromPointer(dstAlloc);
|
||||
|
@ -2572,14 +2572,22 @@ ArenaLists::backgroundFinalize(FreeOp *fop, ArenaHeader *listHead)
|
|||
// Flatten |finalizedSorted| into a regular ArenaList.
|
||||
ArenaList finalized = finalizedSorted.toArenaList();
|
||||
|
||||
AutoLockGC lock(fop->runtime());
|
||||
MOZ_ASSERT(lists->backgroundFinalizeState[thingKind] == BFS_RUN);
|
||||
// We must take the GC lock to be able to safely modify the ArenaList;
|
||||
// however, this does not by itself make the changes visible to all threads,
|
||||
// as not all threads take the GC lock to read the ArenaLists.
|
||||
// That safety is provided by the ReleaseAcquire memory ordering of the
|
||||
// background finalize state, which we explicitly set as the final step.
|
||||
{
|
||||
AutoLockGC lock(fop->runtime());
|
||||
MOZ_ASSERT(lists->backgroundFinalizeState[thingKind] == BFS_RUN);
|
||||
|
||||
// Join |al| and |finalized| into a single list.
|
||||
*al = finalized.insertListWithCursorAtEnd(*al);
|
||||
// Join |al| and |finalized| into a single list.
|
||||
*al = finalized.insertListWithCursorAtEnd(*al);
|
||||
|
||||
lists->arenaListsToSweep[thingKind] = nullptr;
|
||||
}
|
||||
|
||||
lists->backgroundFinalizeState[thingKind] = BFS_DONE;
|
||||
lists->arenaListsToSweep[thingKind] = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -78,6 +78,7 @@ class nsDisplayList;
|
|||
class nsDisplayListBuilder;
|
||||
class nsPIDOMWindow;
|
||||
struct nsPoint;
|
||||
class nsINode;
|
||||
struct nsIntPoint;
|
||||
struct nsIntRect;
|
||||
struct nsRect;
|
||||
|
@ -139,8 +140,8 @@ typedef struct CapturingContentInfo {
|
|||
} CapturingContentInfo;
|
||||
|
||||
#define NS_IPRESSHELL_IID \
|
||||
{ 0x42e9a352, 0x76f3, 0x4ba3, \
|
||||
{ 0x94, 0x0b, 0x78, 0x9e, 0x58, 0x38, 0x73, 0x4f } }
|
||||
{ 0xa0a4b515, 0x0b91, 0x4f13, \
|
||||
{ 0xa0, 0x60, 0x4b, 0xfb, 0x35, 0x00, 0xdc, 0x00 } }
|
||||
|
||||
// debug VerifyReflow flags
|
||||
#define VERIFY_REFLOW_ON 0x01
|
||||
|
@ -855,6 +856,13 @@ public:
|
|||
nsIDOMEvent* aEvent,
|
||||
nsEventStatus* aStatus) = 0;
|
||||
|
||||
/**
|
||||
* Dispatch AfterKeyboardEvent with specific target.
|
||||
*/
|
||||
virtual void DispatchAfterKeyboardEvent(nsINode* aTarget,
|
||||
const mozilla::WidgetKeyboardEvent& aEvent,
|
||||
bool aEmbeddedCancelled) = 0;
|
||||
|
||||
/**
|
||||
* Gets the current target event frame from the PresShell
|
||||
*/
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
#include "nsPresShell.h"
|
||||
#include "nsPresContext.h"
|
||||
#include "nsIContent.h"
|
||||
#include "mozilla/dom/BeforeAfterKeyboardEvent.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/dom/Event.h" // for Event::GetEventPopupControlState()
|
||||
#include "mozilla/dom/ShadowRoot.h"
|
||||
|
@ -72,6 +73,8 @@
|
|||
#include "nsAutoPtr.h"
|
||||
#include "nsReadableUtils.h"
|
||||
#include "nsIPageSequenceFrame.h"
|
||||
#include "nsIPermissionManager.h"
|
||||
#include "nsIMozBrowserFrame.h"
|
||||
#include "nsCaret.h"
|
||||
#include "TouchCaret.h"
|
||||
#include "SelectionCarets.h"
|
||||
|
@ -81,6 +84,7 @@
|
|||
#include "nsILayoutHistoryState.h"
|
||||
#include "nsILineIterator.h" // for ScrollContentIntoView
|
||||
#include "pldhash.h"
|
||||
#include "mozilla/dom/BeforeAfterKeyboardEventBinding.h"
|
||||
#include "mozilla/dom/Touch.h"
|
||||
#include "mozilla/dom/PointerEventBinding.h"
|
||||
#include "nsIObserverService.h"
|
||||
|
@ -705,6 +709,7 @@ static uint32_t sNextPresShellId;
|
|||
static bool sPointerEventEnabled = true;
|
||||
static bool sTouchCaretEnabled = false;
|
||||
static bool sSelectionCaretEnabled = false;
|
||||
static bool sBeforeAfterKeyboardEventEnabled = false;
|
||||
|
||||
/* static */ bool
|
||||
PresShell::TouchCaretPrefEnabled()
|
||||
|
@ -728,6 +733,18 @@ PresShell::SelectionCaretPrefEnabled()
|
|||
return sSelectionCaretEnabled;
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
PresShell::BeforeAfterKeyboardEventEnabled()
|
||||
{
|
||||
static bool sInitialized = false;
|
||||
if (!sInitialized) {
|
||||
Preferences::AddBoolVarCache(&sBeforeAfterKeyboardEventEnabled,
|
||||
"dom.beforeAfterKeyboardEvent.enabled");
|
||||
sInitialized = true;
|
||||
}
|
||||
return sBeforeAfterKeyboardEventEnabled;
|
||||
}
|
||||
|
||||
PresShell::PresShell()
|
||||
: mMouseLocation(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE)
|
||||
{
|
||||
|
@ -6862,6 +6879,236 @@ private:
|
|||
nsCOMPtr<nsIContent> mContent;
|
||||
};
|
||||
|
||||
static bool
|
||||
CheckPermissionForBeforeAfterKeyboardEvent(Element* aElement)
|
||||
{
|
||||
// An element which is chrome-privileged should be able to handle before
|
||||
// events and after events.
|
||||
nsIPrincipal* principal = aElement->NodePrincipal();
|
||||
if (nsContentUtils::IsSystemPrincipal(principal)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// An element which has "before-after-keyboard-event" permission should be
|
||||
// able to handle before events and after events.
|
||||
nsCOMPtr<nsIPermissionManager> permMgr = services::GetPermissionManager();
|
||||
uint32_t permission = nsIPermissionManager::DENY_ACTION;
|
||||
if (permMgr) {
|
||||
permMgr->TestPermissionFromPrincipal(principal, "before-after-keyboard-event", &permission);
|
||||
if (permission == nsIPermissionManager::ALLOW_ACTION) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check "embed-apps" permission for later use.
|
||||
permission = nsIPermissionManager::DENY_ACTION;
|
||||
permMgr->TestPermissionFromPrincipal(principal, "embed-apps", &permission);
|
||||
}
|
||||
|
||||
// An element can handle before events and after events if the following
|
||||
// conditions are met:
|
||||
// 1) <iframe mozbrowser mozapp>
|
||||
// 2) it has "embed-apps" permission.
|
||||
nsCOMPtr<nsIMozBrowserFrame> browserFrame(do_QueryInterface(aElement));
|
||||
if ((permission == nsIPermissionManager::ALLOW_ACTION) &&
|
||||
browserFrame && browserFrame->GetReallyIsApp()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void
|
||||
BuildTargetChainForBeforeAfterKeyboardEvent(nsINode* aTarget,
|
||||
nsTArray<nsCOMPtr<Element> >& aChain,
|
||||
bool& aTargetIsIframe)
|
||||
{
|
||||
nsCOMPtr<nsIContent> content(do_QueryInterface(aTarget));
|
||||
nsCOMPtr<nsPIDOMWindow> window;
|
||||
Element* frameElement;
|
||||
|
||||
// Initialize frameElement.
|
||||
if (content && content->IsHTML(nsGkAtoms::iframe)) {
|
||||
aTargetIsIframe = true;
|
||||
frameElement = aTarget->AsElement();
|
||||
} else {
|
||||
// If event target is not an iframe, dispatch keydown/keyup event to its
|
||||
// window after dispatching before events to its ancestors.
|
||||
aTargetIsIframe = false;
|
||||
|
||||
// And skip the event target and get its parent frame.
|
||||
window = aTarget->OwnerDoc()->GetWindow();
|
||||
if (window) {
|
||||
frameElement = window->GetFrameElementInternal();
|
||||
}
|
||||
}
|
||||
|
||||
// Check permission for all ancestors and add them into the target chain.
|
||||
while (frameElement) {
|
||||
if (CheckPermissionForBeforeAfterKeyboardEvent(frameElement)) {
|
||||
aChain.AppendElement(frameElement);
|
||||
}
|
||||
window = frameElement->OwnerDoc()->GetWindow();
|
||||
frameElement = window ? window->GetFrameElementInternal() : nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PresShell::DispatchBeforeKeyboardEventInternal(const nsTArray<nsCOMPtr<Element> >& aChain,
|
||||
const WidgetKeyboardEvent& aEvent,
|
||||
size_t& aChainIndex,
|
||||
bool& aDefaultPrevented)
|
||||
{
|
||||
size_t length = aChain.Length();
|
||||
if (!CanDispatchEvent(&aEvent) || !length) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t message =
|
||||
(aEvent.message == NS_KEY_DOWN) ? NS_KEY_BEFORE_DOWN : NS_KEY_BEFORE_UP;
|
||||
nsCOMPtr<EventTarget> eventTarget;
|
||||
// Dispatch before events from the outermost element.
|
||||
for (int32_t i = length - 1; i >= 0; i--) {
|
||||
eventTarget = do_QueryInterface(aChain[i]->OwnerDoc()->GetWindow());
|
||||
if (!eventTarget || !CanDispatchEvent(&aEvent)) {
|
||||
return;
|
||||
}
|
||||
|
||||
aChainIndex = i;
|
||||
InternalBeforeAfterKeyboardEvent beforeEvent(aEvent.mFlags.mIsTrusted,
|
||||
message, aEvent.widget);
|
||||
beforeEvent.AssignBeforeAfterKeyEventData(aEvent, false);
|
||||
EventDispatcher::Dispatch(eventTarget, mPresContext, &beforeEvent);
|
||||
|
||||
if (beforeEvent.mFlags.mDefaultPrevented) {
|
||||
aDefaultPrevented = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PresShell::DispatchAfterKeyboardEventInternal(const nsTArray<nsCOMPtr<Element> >& aChain,
|
||||
const WidgetKeyboardEvent& aEvent,
|
||||
bool aEmbeddedCancelled,
|
||||
size_t aStartOffset)
|
||||
{
|
||||
size_t length = aChain.Length();
|
||||
if (!CanDispatchEvent(&aEvent) || !length) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t message =
|
||||
(aEvent.message == NS_KEY_DOWN) ? NS_KEY_AFTER_DOWN : NS_KEY_AFTER_UP;
|
||||
bool embeddedCancelled = aEmbeddedCancelled;
|
||||
nsCOMPtr<EventTarget> eventTarget;
|
||||
// Dispatch after events from the innermost element.
|
||||
for (uint32_t i = aStartOffset; i < length; i++) {
|
||||
eventTarget = do_QueryInterface(aChain[i]->OwnerDoc()->GetWindow());
|
||||
if (!eventTarget || !CanDispatchEvent(&aEvent)) {
|
||||
return;
|
||||
}
|
||||
|
||||
InternalBeforeAfterKeyboardEvent afterEvent(aEvent.mFlags.mIsTrusted,
|
||||
message, aEvent.widget);
|
||||
afterEvent.AssignBeforeAfterKeyEventData(aEvent, false);
|
||||
afterEvent.mEmbeddedCancelled.SetValue(embeddedCancelled);
|
||||
EventDispatcher::Dispatch(eventTarget, mPresContext, &afterEvent);
|
||||
embeddedCancelled = afterEvent.mFlags.mDefaultPrevented;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PresShell::DispatchAfterKeyboardEvent(nsINode* aTarget,
|
||||
const WidgetKeyboardEvent& aEvent,
|
||||
bool aEmbeddedCancelled)
|
||||
{
|
||||
MOZ_ASSERT(aTarget);
|
||||
MOZ_ASSERT(BeforeAfterKeyboardEventEnabled());
|
||||
|
||||
if (NS_WARN_IF(aEvent.message != NS_KEY_DOWN &&
|
||||
aEvent.message != NS_KEY_UP)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Build up a target chain. Each item in the chain will receive an after event.
|
||||
nsAutoTArray<nsCOMPtr<Element>, 5> chain;
|
||||
bool targetIsIframe = false;
|
||||
BuildTargetChainForBeforeAfterKeyboardEvent(aTarget, chain, targetIsIframe);
|
||||
DispatchAfterKeyboardEventInternal(chain, aEvent, aEmbeddedCancelled);
|
||||
}
|
||||
|
||||
bool
|
||||
PresShell::CanDispatchEvent(const WidgetGUIEvent* aEvent) const
|
||||
{
|
||||
bool rv =
|
||||
mPresContext && !mHaveShutDown && nsContentUtils::IsSafeToRunScript();
|
||||
if (aEvent) {
|
||||
rv &= (aEvent && aEvent->widget && !aEvent->widget->Destroyed());
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
void
|
||||
PresShell::HandleKeyboardEvent(nsINode* aTarget,
|
||||
WidgetKeyboardEvent& aEvent,
|
||||
bool aEmbeddedCancelled,
|
||||
nsEventStatus* aStatus,
|
||||
EventDispatchingCallback* aEventCB)
|
||||
{
|
||||
if (aEvent.message == NS_KEY_PRESS ||
|
||||
!BeforeAfterKeyboardEventEnabled()) {
|
||||
EventDispatcher::Dispatch(aTarget, mPresContext,
|
||||
&aEvent, nullptr, aStatus, aEventCB);
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(aTarget);
|
||||
MOZ_ASSERT(aEvent.message == NS_KEY_DOWN || aEvent.message == NS_KEY_UP);
|
||||
|
||||
// Build up a target chain. Each item in the chain will receive a before event.
|
||||
nsAutoTArray<nsCOMPtr<Element>, 5> chain;
|
||||
bool targetIsIframe = false;
|
||||
BuildTargetChainForBeforeAfterKeyboardEvent(aTarget, chain, targetIsIframe);
|
||||
|
||||
// Dispatch before events. If each item in the chain consumes the before
|
||||
// event and doesn't prevent the default action, we will go further to
|
||||
// dispatch the actual key event and after events in the reverse order.
|
||||
// Otherwise, only items which has handled the before event will receive an
|
||||
// after event.
|
||||
size_t chainIndex;
|
||||
bool defaultPrevented = false;
|
||||
DispatchBeforeKeyboardEventInternal(chain, aEvent, chainIndex,
|
||||
defaultPrevented);
|
||||
|
||||
// Dispatch after events to partial items.
|
||||
if (defaultPrevented) {
|
||||
DispatchAfterKeyboardEventInternal(chain, aEvent,
|
||||
aEvent.mFlags.mDefaultPrevented, chainIndex);
|
||||
|
||||
// No need to forward the event to child process.
|
||||
aEvent.mFlags.mNoCrossProcessBoundaryForwarding = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// Event listeners may kill nsPresContext and nsPresShell.
|
||||
if (!CanDispatchEvent()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Dispatch actual key event to event target.
|
||||
EventDispatcher::Dispatch(aTarget, mPresContext,
|
||||
&aEvent, nullptr, aStatus, aEventCB);
|
||||
|
||||
// Event listeners may kill nsPresContext and nsPresShell.
|
||||
if (targetIsIframe || !CanDispatchEvent()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Dispatch after events to all items in the chain.
|
||||
DispatchAfterKeyboardEventInternal(chain, aEvent,
|
||||
aEvent.mFlags.mDefaultPrevented);
|
||||
}
|
||||
|
||||
nsresult
|
||||
PresShell::HandleEvent(nsIFrame* aFrame,
|
||||
WidgetGUIEvent* aEvent,
|
||||
|
@ -7866,6 +8113,9 @@ PresShell::HandleEventInternal(WidgetEvent* aEvent, nsEventStatus* aStatus)
|
|||
IMEStateManager::DispatchCompositionEvent(eventTarget,
|
||||
mPresContext, aEvent->AsCompositionEvent(), aStatus,
|
||||
eventCBPtr);
|
||||
} else if (aEvent->mClass == eKeyboardEventClass) {
|
||||
HandleKeyboardEvent(eventTarget, *(aEvent->AsKeyboardEvent()),
|
||||
false, aStatus, eventCBPtr);
|
||||
} else {
|
||||
EventDispatcher::Dispatch(eventTarget, mPresContext,
|
||||
aEvent, nullptr, aStatus, eventCBPtr);
|
||||
|
|
|
@ -50,6 +50,7 @@ class nsAutoCauseReflowNotifier;
|
|||
|
||||
namespace mozilla {
|
||||
class CSSStyleSheet;
|
||||
class EventDispatchingCallback;
|
||||
} // namespace mozilla
|
||||
|
||||
// 250ms. This is actually pref-controlled, but we use this value if we fail
|
||||
|
@ -75,6 +76,9 @@ public:
|
|||
// Selection caret preference
|
||||
static bool SelectionCaretPrefEnabled();
|
||||
|
||||
// BeforeAfterKeyboardEvent preference
|
||||
static bool BeforeAfterKeyboardEventEnabled();
|
||||
|
||||
void Init(nsIDocument* aDocument, nsPresContext* aPresContext,
|
||||
nsViewManager* aViewManager, nsStyleSet* aStyleSet,
|
||||
nsCompatibility aCompatMode);
|
||||
|
@ -369,6 +373,10 @@ public:
|
|||
|
||||
virtual void RecordShadowStyleChange(mozilla::dom::ShadowRoot* aShadowRoot);
|
||||
|
||||
virtual void DispatchAfterKeyboardEvent(nsINode* aTarget,
|
||||
const mozilla::WidgetKeyboardEvent& aEvent,
|
||||
bool aEmbeddedCancelled) MOZ_OVERRIDE;
|
||||
|
||||
void SetNextPaintCompressed() { mNextPaintCompressed = true; }
|
||||
|
||||
protected:
|
||||
|
@ -719,6 +727,24 @@ protected:
|
|||
|
||||
void EvictTouches();
|
||||
|
||||
// Methods for dispatching KeyboardEvent and BeforeAfterKeyboardEvent.
|
||||
void HandleKeyboardEvent(nsINode* aTarget,
|
||||
mozilla::WidgetKeyboardEvent& aEvent,
|
||||
bool aEmbeddedCancelled,
|
||||
nsEventStatus* aStatus,
|
||||
mozilla::EventDispatchingCallback* aEventCB);
|
||||
void DispatchBeforeKeyboardEventInternal(
|
||||
const nsTArray<nsCOMPtr<mozilla::dom::Element> >& aChain,
|
||||
const mozilla::WidgetKeyboardEvent& aEvent,
|
||||
size_t& aChainIndex,
|
||||
bool& aDefaultPrevented);
|
||||
void DispatchAfterKeyboardEventInternal(
|
||||
const nsTArray<nsCOMPtr<mozilla::dom::Element> >& aChain,
|
||||
const mozilla::WidgetKeyboardEvent& aEvent,
|
||||
bool aEmbeddedCancelled,
|
||||
size_t aChainIndex = 0);
|
||||
bool CanDispatchEvent(const mozilla::WidgetGUIEvent* aEvent = nullptr) const;
|
||||
|
||||
// A list of images that are visible or almost visible.
|
||||
nsTHashtable< nsRefPtrHashKey<nsIImageLoadingContent> > mVisibleImages;
|
||||
|
||||
|
|
|
@ -5183,8 +5183,6 @@ nsComputedDOMStyle::CreatePrimitiveValueForClipPath(
|
|||
|
||||
if (aStyleBasicShape &&
|
||||
aStyleBasicShape->GetShapeType() == nsStyleBasicShape::Type::ePolygon) {
|
||||
nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
|
||||
|
||||
// Shape function name and opening parenthesis.
|
||||
nsAutoString shapeFunctionString;
|
||||
AppendASCIItoUTF16(nsCSSKeywords::GetStringValue(eCSSKeyword_polygon),
|
||||
|
@ -5209,12 +5207,11 @@ nsComputedDOMStyle::CreatePrimitiveValueForClipPath(
|
|||
shapeFunctionString.Append(coordString);
|
||||
}
|
||||
shapeFunctionString.Append(')');
|
||||
nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
|
||||
val->SetString(shapeFunctionString);
|
||||
valueList->AppendCSSValue(val);
|
||||
}
|
||||
|
||||
nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
|
||||
|
||||
if (aSizingBox == NS_STYLE_CLIP_SHAPE_SIZING_NOBOX) {
|
||||
return valueList;
|
||||
}
|
||||
|
@ -5224,6 +5221,7 @@ nsComputedDOMStyle::CreatePrimitiveValueForClipPath(
|
|||
nsCSSProps::ValueToKeyword(aSizingBox,
|
||||
nsCSSProps::kClipShapeSizingKTable),
|
||||
boxString);
|
||||
nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
|
||||
val->SetString(boxString);
|
||||
valueList->AppendCSSValue(val);
|
||||
|
||||
|
|
|
@ -376,8 +376,9 @@ class ChromeCast implements GeckoMediaPlayer {
|
|||
}
|
||||
}
|
||||
private class MirrorCallback implements ResultCallback<ApplicationConnectionResult> {
|
||||
|
||||
final EventCallback callback;
|
||||
// See Bug 1055562, callback is set to null after it has been
|
||||
// invoked so that it will not be called a second time.
|
||||
EventCallback callback;
|
||||
MirrorCallback(final EventCallback callback) {
|
||||
this.callback = callback;
|
||||
}
|
||||
|
@ -385,6 +386,10 @@ class ChromeCast implements GeckoMediaPlayer {
|
|||
|
||||
@Override
|
||||
public void onResult(ApplicationConnectionResult result) {
|
||||
if (callback == null) {
|
||||
Log.e(LOGTAG, "Attempting to invoke MirrorChannel callback more than once.");
|
||||
return;
|
||||
}
|
||||
Status status = result.getStatus();
|
||||
if (status.isSuccess()) {
|
||||
ApplicationMetadata applicationMetadata = result.getApplicationMetadata();
|
||||
|
@ -402,6 +407,7 @@ class ChromeCast implements GeckoMediaPlayer {
|
|||
.getNamespace(),
|
||||
mMirrorChannel);
|
||||
callback.sendSuccess(null);
|
||||
callback = null;
|
||||
} catch (IOException e) {
|
||||
Log.e(LOGTAG, "Exception while creating channel", e);
|
||||
}
|
||||
|
@ -409,6 +415,7 @@ class ChromeCast implements GeckoMediaPlayer {
|
|||
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Casting:Mirror", route.getId()));
|
||||
} else {
|
||||
callback.sendError(status.toString());
|
||||
callback = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4347,6 +4347,9 @@ pref("camera.control.low_memory_thresholdMB", 404);
|
|||
// UDPSocket API
|
||||
pref("dom.udpsocket.enabled", false);
|
||||
|
||||
// Disable before keyboard events and after keyboard events by default.
|
||||
pref("dom.beforeAfterKeyboardEvent.enabled", false);
|
||||
|
||||
// Experiment: Get TTL from DNS records.
|
||||
// Unset initially (0); Randomly chosen on first run; will remain unchanged
|
||||
// unless adjusted by the user or experiment ends. Variants defined in
|
||||
|
|
|
@ -1489,7 +1489,6 @@ CacheIndex::UpdateEntryInIndex(CacheIndexEntry *aEntry, void* aClosure)
|
|||
LOGSHA1(aEntry->Hash())));
|
||||
|
||||
MOZ_ASSERT(aEntry->IsFresh());
|
||||
MOZ_ASSERT(aEntry->IsDirty());
|
||||
|
||||
CacheIndexEntry *entry = index->mIndex.GetEntry(*aEntry->Hash());
|
||||
|
||||
|
|
|
@ -464,19 +464,24 @@ nsHostRecord::GetPriority(uint16_t aFlags)
|
|||
return nsHostRecord::DNS_PRIORITY_LOW;
|
||||
}
|
||||
|
||||
// Returns true if the entry can be removed, or false if it was marked to get
|
||||
// refreshed.
|
||||
// Returns true if the entry can be removed, or false if it should be left.
|
||||
// Sets mResolveAgain true for entries being resolved right now.
|
||||
bool
|
||||
nsHostRecord::RemoveOrRefresh()
|
||||
{
|
||||
// This condition implies that the request has been passed to the OS
|
||||
// resolver. The resultant DNS record should be considered stale and not
|
||||
// trusted; set a flag to ensure it is called again.
|
||||
if (resolving && !onQueue) {
|
||||
mResolveAgain = true;
|
||||
if (resolving) {
|
||||
if (!onQueue) {
|
||||
// The request has been passed to the OS resolver. The resultant DNS
|
||||
// record should be considered stale and not trusted; set a flag to
|
||||
// ensure it is called again.
|
||||
mResolveAgain = true;
|
||||
}
|
||||
// if Onqueue is true, the host entry is already added to the cache
|
||||
// but is still pending to get resolved: just leave it in hash.
|
||||
return false;
|
||||
}
|
||||
return true; // can be removed now
|
||||
// Already resolved; not in a pending state; remove from cache.
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
@ -599,9 +604,9 @@ HostDB_PruneEntry(PLDHashTable *table,
|
|||
void *arg)
|
||||
{
|
||||
nsHostDBEnt* ent = static_cast<nsHostDBEnt *>(hdr);
|
||||
|
||||
// Try to remove the record, or mark it for refresh
|
||||
if (ent->rec->RemoveOrRefresh()) {
|
||||
PR_REMOVE_LINK(ent->rec);
|
||||
return PL_DHASH_REMOVE;
|
||||
}
|
||||
return PL_DHASH_NEXT;
|
||||
|
@ -786,26 +791,24 @@ nsHostResolver::ClearPendingQueue(PRCList *aPendingQ)
|
|||
void
|
||||
nsHostResolver::FlushCache()
|
||||
{
|
||||
PRCList evictionQ;
|
||||
PR_INIT_CLIST(&evictionQ);
|
||||
MutexAutoLock lock(mLock);
|
||||
mEvictionQSize = 0;
|
||||
|
||||
{
|
||||
MutexAutoLock lock(mLock);
|
||||
MoveCList(mEvictionQ, evictionQ);
|
||||
mEvictionQSize = 0;
|
||||
// Clear the evictionQ and remove all its corresponding entries from
|
||||
// the cache first
|
||||
if (!PR_CLIST_IS_EMPTY(&mEvictionQ)) {
|
||||
PRCList *node = mEvictionQ.next;
|
||||
while (node != &mEvictionQ) {
|
||||
nsHostRecord *rec = static_cast<nsHostRecord *>(node);
|
||||
node = node->next;
|
||||
PR_REMOVE_AND_INIT_LINK(rec);
|
||||
PL_DHashTableOperate(&mDB, (nsHostKey *) rec, PL_DHASH_REMOVE);
|
||||
NS_RELEASE(rec);
|
||||
}
|
||||
}
|
||||
|
||||
// prune the hash from all hosts already resolved
|
||||
PL_DHashTableEnumerate(&mDB, HostDB_PruneEntry, nullptr);
|
||||
}
|
||||
|
||||
if (!PR_CLIST_IS_EMPTY(&evictionQ)) {
|
||||
PRCList *node = evictionQ.next;
|
||||
while (node != &evictionQ) {
|
||||
nsHostRecord *rec = static_cast<nsHostRecord *>(node);
|
||||
node = node->next;
|
||||
NS_RELEASE(rec);
|
||||
}
|
||||
}
|
||||
// Refresh the cache entries that are resolving RIGHT now, remove the rest.
|
||||
PL_DHashTableEnumerate(&mDB, HostDB_PruneEntry, nullptr);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1459,6 +1462,17 @@ nsHostResolver::OnLookupComplete(nsHostRecord* rec, nsresult status, AddrInfo* r
|
|||
// release reference to rec owned by mEvictionQ
|
||||
NS_RELEASE(head);
|
||||
}
|
||||
#if TTL_AVAILABLE
|
||||
if (!rec->mGetTtl && sDnsVariant != DNS_EXP_VARIANT_CONTROL
|
||||
&& !rec->resolving) {
|
||||
LOG(("Issuing second async lookup for TTL for %s.", rec->host));
|
||||
rec->flags =
|
||||
(rec->flags & ~RES_PRIORITY_MEDIUM) | RES_PRIORITY_LOW;
|
||||
DebugOnly<nsresult> rv = IssueLookup(rec);
|
||||
NS_WARN_IF_FALSE(NS_SUCCEEDED(rv),
|
||||
"Could not issue second async lookup for TTL.");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1475,21 +1489,6 @@ nsHostResolver::OnLookupComplete(nsHostRecord* rec, nsresult status, AddrInfo* r
|
|||
}
|
||||
}
|
||||
|
||||
#if TTL_AVAILABLE
|
||||
{
|
||||
MutexAutoLock lock(mLock);
|
||||
if (!mShutdown && !rec->mGetTtl
|
||||
&& sDnsVariant != DNS_EXP_VARIANT_CONTROL && !rec->resolving) {
|
||||
LOG(("Issuing second async lookup for TTL for %s.", rec->host));
|
||||
rec->flags =
|
||||
(rec->flags & ~RES_PRIORITY_MEDIUM) | RES_PRIORITY_LOW;
|
||||
DebugOnly<nsresult> rv = IssueLookup(rec);
|
||||
NS_WARN_IF_FALSE(NS_SUCCEEDED(rv),
|
||||
"Could not issue second async lookup for TTL.");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
NS_RELEASE(rec);
|
||||
|
||||
return LOOKUP_OK;
|
||||
|
|
|
@ -119,8 +119,8 @@ public:
|
|||
};
|
||||
static DnsPriority GetPriority(uint16_t aFlags);
|
||||
|
||||
bool RemoveOrRefresh(); // Returns whether the host record can be removed
|
||||
// or needs to be refreshed
|
||||
bool RemoveOrRefresh(); // Mark records currently being resolved as needed
|
||||
// to resolve again.
|
||||
|
||||
private:
|
||||
friend class nsHostResolver;
|
||||
|
|
|
@ -616,6 +616,7 @@ nsHttpHandler::BuildUserAgent()
|
|||
mAppVersion.Length() +
|
||||
mCompatFirefox.Length() +
|
||||
mCompatDevice.Length() +
|
||||
mDeviceModelId.Length() +
|
||||
13);
|
||||
|
||||
// Application portion
|
||||
|
@ -640,6 +641,10 @@ nsHttpHandler::BuildUserAgent()
|
|||
mUserAgent += mOscpu;
|
||||
mUserAgent.AppendLiteral("; ");
|
||||
}
|
||||
if (!mDeviceModelId.IsEmpty()) {
|
||||
mUserAgent += mDeviceModelId;
|
||||
mUserAgent.AppendLiteral("; ");
|
||||
}
|
||||
mUserAgent += mMisc;
|
||||
mUserAgent += ')';
|
||||
|
||||
|
@ -703,6 +708,31 @@ nsHttpHandler::InitUserAgentComponents()
|
|||
mCompatDevice.AssignLiteral("Mobile");
|
||||
#endif
|
||||
|
||||
#if defined(MOZ_WIDGET_GONK)
|
||||
// Device model identifier should be a simple token, which can be composed
|
||||
// of letters, numbers, hyphen ("-") and dot (".").
|
||||
// Any other characters means the identifier is invalid and ignored.
|
||||
nsCString deviceId;
|
||||
rv = Preferences::GetCString("general.useragent.device_id", &deviceId);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
bool valid = true;
|
||||
deviceId.Trim(" ", true, true);
|
||||
for (int i = 0; i < deviceId.Length(); i++) {
|
||||
char c = deviceId.CharAt(i);
|
||||
if (!(isalnum(c) || c == '-' || c == '.')) {
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (valid) {
|
||||
mDeviceModelId = deviceId;
|
||||
} else {
|
||||
LOG(("nsHttpHandler: Ignore invalid device ID: [%s]\n",
|
||||
deviceId.get()));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef MOZ_UA_OS_AGNOSTIC
|
||||
// Gather OS/CPU.
|
||||
#if defined(XP_WIN)
|
||||
|
|
|
@ -432,6 +432,7 @@ private:
|
|||
nsCString mCompatFirefox;
|
||||
bool mCompatFirefoxEnabled;
|
||||
nsXPIDLCString mCompatDevice;
|
||||
nsCString mDeviceModelId;
|
||||
|
||||
nsCString mUserAgent;
|
||||
nsXPIDLCString mUserAgentOverride;
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче