author | Ryan VanderMeulen <ryanvm@gmail.com> |
Fri, 18 Apr 2014 22:08:16 -0400 | |
changeset 197840 | 5f558788549ed778f676b6cd7dcf28cb36e8cf7d |
parent 197839 | 7c5d076dd141770a70e7235e6ac7fe589ca5034e (current diff) |
parent 197811 | 582b2d81ebe148856358b97f5395dd714c2efa5c (diff) |
child 197841 | 8a8c87fcd2d900c15c9de53a47b7e1aac48b5ffe |
push id | 3624 |
push user | asasaki@mozilla.com |
push date | Mon, 09 Jun 2014 21:49:01 +0000 |
treeherder | mozilla-beta@b1a5da15899a [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
milestone | 31.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
toolkit/components/places/tests/unit/test_PlacesUtils_nodeIsXXX_invalidArg.js | file | annotate | diff | comparison | revisions |
--- a/accessible/tests/mochitest/autocomplete.js +++ b/accessible/tests/mochitest/autocomplete.js @@ -194,16 +194,21 @@ AutoCompleteResult.prototype = return null; }, getImageAt: function(aIndex) { return ""; }, + getFinalCompleteValueAt: function(aIndex) + { + return this.getValueAt(aIndex); + }, + removeValueAt: function (aRowIndex, aRemoveFromDb) {}, // nsISupports implementation QueryInterface: function(iid) { if (iid.equals(nsISupports) || iid.equals(nsIAutoCompleteResult)) return this;
--- a/b2g/chrome/content/shell.js +++ b/b2g/chrome/content/shell.js @@ -778,20 +778,16 @@ var CustomEventManager = { JSON.stringify({ callerID: detail.chromeEventID, keyword: detail.keyword, manifestURL: detail.manifestURL, selectedApps: detail.peers })); break; case 'inputmethod-update-layouts': KeyboardHelper.handleEvent(detail); break; - case 'nfc-hardware-state-change': - Services.obs.notifyObservers(null, 'nfc-hardware-state-change', - JSON.stringify({ nfcHardwareState: detail.nfcHardwareState })); - break; } } } var AlertsHelper = { _listeners: {}, _count: 0,
--- a/b2g/config/emulator-ics/sources.xml +++ b/b2g/config/emulator-ics/sources.xml @@ -14,17 +14,17 @@ <!--original fetch url was git://github.com/apitrace/--> <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/> <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/> <!-- Gonk specific things and forks --> <project name="platform_build" path="build" remote="b2g" revision="1ad48c4be51b279f7f63c1a13025b52fe087d231"> <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="76c94ac5dc3b8e17cc23d9cc3e2662b0d5d28b2e"/> + <project name="gaia.git" path="gaia" remote="mozillaorg" revision="7e93b6de9633a162b735252e8182974456f741f4"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/> <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/> <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="55bcc2d7e44dc805c24b57d1e783fc26e8a2ee86"/> <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="99a67a75855d8ca077018c819aedd90bf0447d9b"/> <project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/> <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d6c36d74ba9aefbc8c3618fc93dd4907a0dbf5e"/> <!-- Stock Android things --> <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- a/b2g/config/emulator-jb/sources.xml +++ b/b2g/config/emulator-jb/sources.xml @@ -12,17 +12,17 @@ <!--original fetch url was https://git.mozilla.org/releases--> <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/> <!-- B2G specific things. --> <project name="platform_build" path="build" remote="b2g" revision="e6383e6e785cc3ea237e902beb1092f9aa88e29d"> <copyfile dest="Makefile" src="core/root.mk"/> </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="76c94ac5dc3b8e17cc23d9cc3e2662b0d5d28b2e"/> + <project name="gaia" path="gaia" remote="mozillaorg" revision="7e93b6de9633a162b735252e8182974456f741f4"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/> <project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/> <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d6c36d74ba9aefbc8c3618fc93dd4907a0dbf5e"/> <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/> <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/> <!-- Stock Android things --> <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/> <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/> @@ -126,11 +126,11 @@ <!-- Emulator specific things --> <project name="android-development" path="development" remote="b2g" revision="dab55669da8f48b6e57df95d5af9f16b4a87b0b1"/> <project name="device/generic/armv7-a-neon" path="device/generic/armv7-a-neon" revision="3a9a17613cc685aa232432566ad6cc607eab4ec1"/> <project name="device_generic_goldfish" path="device/generic/goldfish" remote="b2g" revision="09485b73629856b21b2ed6073e327ab0e69a1189"/> <project name="platform/external/libnfc-nci" path="external/libnfc-nci" revision="7d33aaf740bbf6c7c6e9c34a92b371eda311b66b"/> <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="8afce6d5d48b71b6e7cb917179fb6147fb747521"/> <project name="platform/external/wpa_supplicant_8" path="external/wpa_supplicant_8" revision="0e56e450367cd802241b27164a2979188242b95f"/> <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="72e3a520e3c700839f07ba0113fd527b923c3330"/> - <project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="6a7ada569fd37c09ed4bbee6eb78cea5b467b229"/> + <project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="baaf899afb158b9530690002f3656e958e3eb047"/> <project name="android-sdk" path="sdk" remote="b2g" revision="8b1365af38c9a653df97349ee53a3f5d64fd590a"/> </manifest>
--- a/b2g/config/emulator-kk/sources.xml +++ b/b2g/config/emulator-kk/sources.xml @@ -10,17 +10,17 @@ <!--original fetch url was git://codeaurora.org/--> <remote fetch="https://git.mozilla.org/external/caf" name="caf"/> <!--original fetch url was https://git.mozilla.org/releases--> <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/> <!-- B2G specific things. --> <project name="platform_build" path="build" remote="b2g" revision="52c909ccead537f8f9dbf634f3e6639078a8b0bd"> <copyfile dest="Makefile" src="core/root.mk"/> </project> - <project name="gaia" path="gaia" remote="mozillaorg" revision="76c94ac5dc3b8e17cc23d9cc3e2662b0d5d28b2e"/> + <project name="gaia" path="gaia" remote="mozillaorg" revision="7e93b6de9633a162b735252e8182974456f741f4"/> <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/> <project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/> <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="8d6c36d74ba9aefbc8c3618fc93dd4907a0dbf5e"/> <!-- Stock Android things -->
--- a/b2g/config/emulator/sources.xml +++ b/b2g/config/emulator/sources.xml @@ -14,17 +14,17 @@ <!--original fetch url was git://github.com/apitrace/--> <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/> <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/> <!-- Gonk specific things and forks --> <project name="platform_build" path="build" remote="b2g" revision="1ad48c4be51b279f7f63c1a13025b52fe087d231"> <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="76c94ac5dc3b8e17cc23d9cc3e2662b0d5d28b2e"/> + <project name="gaia.git" path="gaia" remote="mozillaorg" revision="7e93b6de9633a162b735252e8182974456f741f4"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/> <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/> <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="55bcc2d7e44dc805c24b57d1e783fc26e8a2ee86"/> <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="99a67a75855d8ca077018c819aedd90bf0447d9b"/> <project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/> <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d6c36d74ba9aefbc8c3618fc93dd4907a0dbf5e"/> <!-- Stock Android things --> <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- a/b2g/config/flame/sources.xml +++ b/b2g/config/flame/sources.xml @@ -13,17 +13,17 @@ <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/> <!-- B2G specific things. --> <project name="platform_build" path="build" remote="b2g" revision="e6383e6e785cc3ea237e902beb1092f9aa88e29d"> <copyfile dest="Makefile" src="core/root.mk"/> </project> <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/> <project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/> <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/> - <project name="gaia" path="gaia" remote="mozillaorg" revision="76c94ac5dc3b8e17cc23d9cc3e2662b0d5d28b2e"/> + <project name="gaia" path="gaia" remote="mozillaorg" revision="7e93b6de9633a162b735252e8182974456f741f4"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/> <project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/> <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d6c36d74ba9aefbc8c3618fc93dd4907a0dbf5e"/> <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/> <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/> <!-- Stock Android things --> <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="e95b4ce22c825da44d14299e1190ea39a5260bde"/> <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="471afab478649078ad7c75ec6b252481a59e19b8"/>
--- a/b2g/config/gaia.json +++ b/b2g/config/gaia.json @@ -1,9 +1,9 @@ { "git": { "git_revision": "", "remote": "", "branch": "" }, - "revision": "26f2c60c0ba0e64114467663c33c82360c13f4cf", + "revision": "38d1561fe26c12f371c44a47c498722ce06518c2", "repo_path": "/integration/gaia-central" }
--- a/b2g/config/hamachi/sources.xml +++ b/b2g/config/hamachi/sources.xml @@ -12,17 +12,17 @@ <!--original fetch url was git://github.com/apitrace/--> <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/> <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/> <!-- Gonk specific things and forks --> <project name="platform_build" path="build" remote="b2g" revision="1ad48c4be51b279f7f63c1a13025b52fe087d231"> <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="76c94ac5dc3b8e17cc23d9cc3e2662b0d5d28b2e"/> + <project name="gaia.git" path="gaia" remote="mozillaorg" revision="7e93b6de9633a162b735252e8182974456f741f4"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/> <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/> <project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/> <project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/> <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d6c36d74ba9aefbc8c3618fc93dd4907a0dbf5e"/> <!-- Stock Android things --> <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/> <project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
--- a/b2g/config/helix/sources.xml +++ b/b2g/config/helix/sources.xml @@ -10,17 +10,17 @@ <!--original fetch url was https://git.mozilla.org/releases--> <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/> <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/> <!-- Gonk specific things and forks --> <project name="platform_build" path="build" remote="b2g" revision="1ad48c4be51b279f7f63c1a13025b52fe087d231"> <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="76c94ac5dc3b8e17cc23d9cc3e2662b0d5d28b2e"/> + <project name="gaia.git" path="gaia" remote="mozillaorg" revision="7e93b6de9633a162b735252e8182974456f741f4"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/> <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/> <project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/> <project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/> <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/> <!-- Stock Android things --> <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/> <project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
--- a/b2g/config/inari/sources.xml +++ b/b2g/config/inari/sources.xml @@ -14,17 +14,17 @@ <!--original fetch url was git://github.com/apitrace/--> <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/> <default remote="caf" revision="ics_chocolate_rb4.2" sync-j="4"/> <!-- Gonk specific things and forks --> <project name="platform_build" path="build" remote="b2g" revision="1ad48c4be51b279f7f63c1a13025b52fe087d231"> <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="76c94ac5dc3b8e17cc23d9cc3e2662b0d5d28b2e"/> + <project name="gaia.git" path="gaia" remote="mozillaorg" revision="7e93b6de9633a162b735252e8182974456f741f4"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/> <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/> <project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/> <project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/> <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d6c36d74ba9aefbc8c3618fc93dd4907a0dbf5e"/> <!-- Stock Android things --> <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/> <project name="platform/bionic" path="bionic" revision="cd5dfce80bc3f0139a56b58aca633202ccaee7f8"/>
--- a/b2g/config/leo/sources.xml +++ b/b2g/config/leo/sources.xml @@ -12,17 +12,17 @@ <!--original fetch url was git://github.com/apitrace/--> <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/> <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/> <!-- Gonk specific things and forks --> <project name="platform_build" path="build" remote="b2g" revision="1ad48c4be51b279f7f63c1a13025b52fe087d231"> <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="76c94ac5dc3b8e17cc23d9cc3e2662b0d5d28b2e"/> + <project name="gaia.git" path="gaia" remote="mozillaorg" revision="7e93b6de9633a162b735252e8182974456f741f4"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/> <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/> <project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/> <project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/> <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d6c36d74ba9aefbc8c3618fc93dd4907a0dbf5e"/> <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/> <!-- Stock Android things --> <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
--- a/b2g/config/mako/sources.xml +++ b/b2g/config/mako/sources.xml @@ -12,17 +12,17 @@ <!--original fetch url was https://git.mozilla.org/releases--> <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/> <!-- B2G specific things. --> <project name="platform_build" path="build" remote="b2g" revision="e6383e6e785cc3ea237e902beb1092f9aa88e29d"> <copyfile dest="Makefile" src="core/root.mk"/> </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="76c94ac5dc3b8e17cc23d9cc3e2662b0d5d28b2e"/> + <project name="gaia" path="gaia" remote="mozillaorg" revision="7e93b6de9633a162b735252e8182974456f741f4"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/> <project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/> <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d6c36d74ba9aefbc8c3618fc93dd4907a0dbf5e"/> <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/> <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/> <!-- Stock Android things --> <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/> <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/> @@ -122,17 +122,17 @@ <project name="platform/system/netd" path="system/netd" revision="56112dd7b811301b718d0643a82fd5cac9522073"/> <project name="platform/system/security" path="system/security" revision="f48ff68fedbcdc12b570b7699745abb6e7574907"/> <project name="platform/system/vold" path="system/vold" revision="8de05d4a52b5a91e7336e6baa4592f945a6ddbea"/> <default remote="caf" revision="refs/tags/android-4.3_r2.1" sync-j="4"/> <!-- Nexus 4 specific things --> <project name="device-mako" path="device/lge/mako" remote="b2g" revision="78d17f0c117f0c66dd55ee8d5c5dde8ccc93ecba"/> <project name="device/generic/armv7-a-neon" path="device/generic/armv7-a-neon" revision="3a9a17613cc685aa232432566ad6cc607eab4ec1"/> <project name="device/lge/mako-kernel" path="device/lge/mako-kernel" revision="d1729e53d71d711c8fde25eab8728ff2b9b4df0e"/> - <project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="6a7ada569fd37c09ed4bbee6eb78cea5b467b229"/> + <project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="baaf899afb158b9530690002f3656e958e3eb047"/> <project name="platform/external/libnfc-nci" path="external/libnfc-nci" revision="7d33aaf740bbf6c7c6e9c34a92b371eda311b66b"/> <project name="platform/external/wpa_supplicant_8" path="external/wpa_supplicant_8" revision="0e56e450367cd802241b27164a2979188242b95f"/> <project name="platform/hardware/broadcom/wlan" path="hardware/broadcom/wlan" revision="0e1929fa3aa38bf9d40e9e953d619fab8164c82e"/> <project name="platform/hardware/qcom/audio" path="hardware/qcom/audio" revision="b0a528d839cfd9d170d092fe3743b5252b4243a6"/> <project name="platform/hardware/qcom/bt" path="hardware/qcom/bt" revision="380945eaa249a2dbdde0daa4c8adb8ca325edba6"/> <project name="platform/hardware/qcom/display" path="hardware/qcom/display" revision="6f3b0272cefaffeaed2a7d2bb8f633059f163ddc"/> <project name="platform/hardware/qcom/keymaster" path="hardware/qcom/keymaster" revision="16da8262c997a5a0d797885788a64a0771b26910"/> <project name="platform/hardware/qcom/media" path="hardware/qcom/media" revision="689b476ba3eb46c34b81343295fe144a0e81a18e"/>
--- a/b2g/config/wasabi/sources.xml +++ b/b2g/config/wasabi/sources.xml @@ -12,17 +12,17 @@ <!--original fetch url was git://github.com/apitrace/--> <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/> <default remote="caf" revision="ics_chocolate_rb4.2" sync-j="4"/> <!-- Gonk specific things and forks --> <project name="platform_build" path="build" remote="b2g" revision="1ad48c4be51b279f7f63c1a13025b52fe087d231"> <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="76c94ac5dc3b8e17cc23d9cc3e2662b0d5d28b2e"/> + <project name="gaia.git" path="gaia" remote="mozillaorg" revision="7e93b6de9633a162b735252e8182974456f741f4"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/> <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/> <project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/> <project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/> <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d6c36d74ba9aefbc8c3618fc93dd4907a0dbf5e"/> <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/> <!-- Stock Android things --> <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
--- a/browser/base/content/browser.css +++ b/browser/base/content/browser.css @@ -117,47 +117,48 @@ tabbrowser { } .tabbrowser-tab:not([pinned]):not([fadein]) { max-width: 0.1px; min-width: 0.1px; visibility: hidden; } -.tab-background { - /* Explicitly set the visibility to override the value (collapsed) - * we inherit from #TabsToolbar[collapsed] upon opening a browser window. */ - visibility: visible; - /* The transition is only delayed for opening tabs. */ - transition: visibility 0ms 25ms; -} - -.tab-background:not([fadein]):not([pinned]) { - visibility: hidden; - /* Closing tabs are hidden without a delay. */ - transition-delay: 0ms; -} - +.tab-background, .tab-close-button, .tab-label { /* Explicitly set the visibility to override the value (collapsed) * we inherit from #TabsToolbar[collapsed] upon opening a browser window. */ visibility: visible; +} + +.tab-background[fadein] { + /* This transition is only wanted for opening tabs. */ + transition: visibility 0ms 25ms; +} + +.tab-background:not([fadein]) { + visibility: hidden; +} + +.tab-close-button[fadein], +.tab-label[fadein] { + /* This transition is only wanted for opening tabs. */ transition: opacity 70ms 230ms, visibility 0ms 230ms; } -.tab-close-button:not([fadein]):not([pinned]), -.tab-label:not([fadein]):not([pinned]) { +.tab-close-button:not([fadein]), +.tab-label:not([fadein]) { visibility: collapse; opacity: .6; } -.tab-throbber:not([fadein]):not([pinned]), -.tab-icon-image:not([fadein]):not([pinned]) { +.tab-throbber:not([fadein]), +.tab-icon-image:not([fadein]) { display: none; } .tabbrowser-tabs[positionpinnedtabs] > .tabbrowser-tab[pinned] { position: fixed !important; display: block; /* position:fixed already does this (bug 579776), but let's be explicit */ }
--- a/browser/base/content/newtab/page.js +++ b/browser/base/content/newtab/page.js @@ -14,19 +14,20 @@ let gPage = { */ init: function Page_init() { // Add ourselves to the list of pages to receive notifications. gAllPages.register(this); // Listen for 'unload' to unregister this page. addEventListener("unload", this, false); - // Listen for toggle button clicks. - let button = document.getElementById("newtab-toggle"); - button.addEventListener("click", this, false); + // XXX bug 991111 - Not all click events are correctly triggered when + // listening from xhtml nodes -- in particular middle clicks on sites, so + // listen from the xul window and filter then delegate + addEventListener("click", this, false); // Initialize sponsored panel this._sponsoredPanel = document.getElementById("sponsored-panel"); let link = this._sponsoredPanel.querySelector(".text-link"); link.addEventListener("click", () => this._sponsoredPanel.hidePopup()); // Check if the new tab feature is enabled. let enabled = gAllPages.enabled; @@ -191,17 +192,32 @@ let gPage = { handleEvent: function Page_handleEvent(aEvent) { switch (aEvent.type) { case "unload": if (this._mutationObserver) this._mutationObserver.disconnect(); gAllPages.unregister(this); break; case "click": - gAllPages.enabled = !gAllPages.enabled; + let {button, target} = aEvent; + if (target.id == "newtab-toggle") { + if (button == 0) { + gAllPages.enabled = !gAllPages.enabled; + } + break; + } + + // Go up ancestors until we find a Site or not + while (target) { + if (target.hasOwnProperty("_newtabSite")) { + target._newtabSite.onClick(aEvent); + break; + } + target = target.parentNode; + } break; case "dragover": if (gDrag.isValid(aEvent) && gDrag.draggedSite) aEvent.preventDefault(); break; case "drop": if (gDrag.isValid(aEvent) && gDrag.draggedSite) { aEvent.preventDefault();
--- a/browser/base/content/newtab/sites.js +++ b/browser/base/content/newtab/sites.js @@ -165,20 +165,16 @@ Site.prototype = { * Adds event handlers for the site and its buttons. */ _addEventHandlers: function Site_addEventHandlers() { // Register drag-and-drop event handlers. this._node.addEventListener("dragstart", this, false); this._node.addEventListener("dragend", this, false); this._node.addEventListener("mouseover", this, false); - // XXX bug 991111 - Not all click events are correctly triggered when - // listening from the xhtml node, so listen from the xul window and filter - addEventListener("click", this, false); - // Specially treat the sponsored icon to prevent regular hover effects let sponsored = this._querySelector(".newtab-control-sponsored"); sponsored.addEventListener("mouseover", () => { this.cell.node.setAttribute("ignorehover", "true"); }); sponsored.addEventListener("mouseout", () => { this.cell.node.removeAttribute("ignorehover"); }); @@ -213,21 +209,29 @@ Site.prototype = { Services.telemetry.getHistogramById("NEWTAB_PAGE_DIRECTORY_TYPE_CLICKED") .add(typeIndex); } }, /** * Handles site click events. */ - _onClick: function Site_onClick(aEvent) { - let target = aEvent.target; + onClick: function Site_onClick(aEvent) { + let {button, target} = aEvent; if (target.classList.contains("newtab-link") || target.parentElement.classList.contains("newtab-link")) { - this._recordSiteClicked(this.cell.index); + // Record for primary and middle clicks + if (button == 0 || button == 1) { + this._recordSiteClicked(this.cell.index); + } + return; + } + + // Only handle primary clicks for the remaining targets + if (button != 0) { return; } aEvent.preventDefault(); if (aEvent.target.classList.contains("newtab-control-block")) this.block(); else if (target.classList.contains("newtab-control-sponsored")) gPage.showSponsoredPanel(target); @@ -237,23 +241,16 @@ Site.prototype = { this.pin(); }, /** * Handles all site events. */ handleEvent: function Site_handleEvent(aEvent) { switch (aEvent.type) { - case "click": - // Check the bitmask if the click event is for the site's descendants - if (this._node.compareDocumentPosition(aEvent.target) & - this._node.DOCUMENT_POSITION_CONTAINED_BY) { - this._onClick(aEvent); - } - break; case "mouseover": this._node.removeEventListener("mouseover", this, false); this._speculativeConnect(); break; case "dragstart": gDrag.start(this, aEvent); break; case "dragend":
--- a/browser/base/content/tabbrowser.xml +++ b/browser/base/content/tabbrowser.xml @@ -285,17 +285,16 @@ <method name="unpinTab"> <parameter name="aTab"/> <body><![CDATA[ if (!aTab.pinned) return; this.moveTabTo(aTab, this._numPinnedTabs - 1); - aTab.setAttribute("fadein", "true"); aTab.removeAttribute("pinned"); aTab.style.MozMarginStart = ""; this.tabContainer._unlockTabSizing(); this.tabContainer._positionPinnedTabs(); this.tabContainer.adjustTabstrip(); // Bug 961867 - [e10s] Implement the logic for app tabs if (!gMultiProcessBrowser)
--- a/browser/base/content/test/newtab/browser.ini +++ b/browser/base/content/test/newtab/browser.ini @@ -12,16 +12,17 @@ skip-if = e10s # Bug ?????? - about:newt [browser_newtab_bug734043.js] [browser_newtab_bug735987.js] skip-if = os == "mac" # Intermittent failures, bug 898317 [browser_newtab_bug752841.js] [browser_newtab_bug765628.js] [browser_newtab_bug876313.js] [browser_newtab_bug991111.js] [browser_newtab_bug991210.js] +[browser_newtab_bug998387.js] [browser_newtab_disable.js] [browser_newtab_drag_drop.js] [browser_newtab_drag_drop_ext.js] [browser_newtab_drop_preview.js] [browser_newtab_focus.js] [browser_newtab_perwindow_private_browsing.js] [browser_newtab_reset.js] [browser_newtab_sponsored_icon_click.js]
--- a/browser/base/content/test/newtab/browser_newtab_bug991111.js +++ b/browser/base/content/test/newtab/browser_newtab_bug991111.js @@ -3,17 +3,17 @@ function runTests() { yield setLinks("0"); yield addNewTabPageTab(); // Remember if the click handler was triggered let cell = getCell(0); let clicked = false; - cell.site._onClick = e => { + cell.site.onClick = e => { clicked = true; executeSoon(TestRunner.next); }; // Send a middle-click and make sure it happened yield EventUtils.synthesizeMouseAtCenter(cell.node, {button: 1}, getContentWindow()); ok(clicked, "middle click triggered click listener"); }
new file mode 100644 --- /dev/null +++ b/browser/base/content/test/newtab/browser_newtab_bug998387.js @@ -0,0 +1,25 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +function runTests() { + yield setLinks("0"); + yield addNewTabPageTab(); + + // Remember if the click handler was triggered + let {site} = getCell(0); + let origOnClick = site.onClick; + let clicked = false; + site.onClick = e => { + origOnClick.call(site, e); + clicked = true; + executeSoon(TestRunner.next); + }; + + // Send a middle-click and make sure it happened + let block = getContentDocument().querySelector(".newtab-control-block"); + yield EventUtils.synthesizeMouseAtCenter(block, {button: 1}, getContentWindow()); + ok(clicked, "middle click triggered click listener"); + + // Make sure the cell didn't actually get blocked + checkGrid("0"); +}
--- a/browser/devtools/debugger/test/browser.ini +++ b/browser/devtools/debugger/test/browser.ini @@ -144,16 +144,17 @@ support-files = [browser_dbg_global-method-override.js] [browser_dbg_globalactor.js] [browser_dbg_host-layout.js] [browser_dbg_iframes.js] [browser_dbg_instruments-pane-collapse.js] [browser_dbg_listaddons.js] [browser_dbg_listtabs-01.js] [browser_dbg_listtabs-02.js] +[browser_dbg_listtabs-03.js] [browser_dbg_location-changes-01-simple.js] [browser_dbg_location-changes-02-blank.js] [browser_dbg_location-changes-03-new.js] [browser_dbg_location-changes-04-breakpoint.js] [browser_dbg_multiple-windows.js] [browser_dbg_navigation.js] [browser_dbg_no-page-sources.js] [browser_dbg_on-pause-highlight.js]
new file mode 100644 --- /dev/null +++ b/browser/devtools/debugger/test/browser_dbg_listtabs-03.js @@ -0,0 +1,80 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +/** + * Make sure the listTabs request works as specified. + */ + +const TAB1_URL = EXAMPLE_URL + "doc_empty-tab-01.html"; + +let gTab1, gTab1Actor, gTab2, gTab2Actor, gClient; + +function listTabs() { + let deferred = promise.defer(); + + gClient.listTabs(aResponse => { + deferred.resolve(aResponse.tabs); + }); + + return deferred.promise; +} + +function request(params) { + let deferred = promise.defer(); + gClient.request(params, deferred.resolve); + return deferred.promise; +} + +function test() { + if (!DebuggerServer.initialized) { + DebuggerServer.init(() => true); + DebuggerServer.addBrowserActors(); + } + + let transport = DebuggerServer.connectPipe(); + gClient = new DebuggerClient(transport); + gClient.connect(Task.async(function*(aType, aTraits) { + is(aType, "browser", + "Root actor should identify itself as a browser."); + let tab = yield addTab(TAB1_URL); + + let tabs = yield listTabs(); + is(tabs.length, 2, "Should be two tabs"); + let tabGrip = tabs.filter(a => a.url ==TAB1_URL).pop(); + ok(tabGrip, "Should have an actor for the tab"); + + let response = yield request({ to: tabGrip.actor, type: "attach" }); + is(response.type, "tabAttached", "Should have attached"); + + tabs = yield listTabs(); + + response = yield request({ to: tabGrip.actor, type: "detach" }); + is(response.type, "detached", "Should have detached"); + + let newGrip = tabs.filter(a => a.url ==TAB1_URL).pop(); + is(newGrip.actor, tabGrip.actor, "Should have the same actor for the same tab"); + + response = yield request({ to: tabGrip.actor, type: "attach" }); + is(response.type, "tabAttached", "Should have attached"); + response = yield request({ to: tabGrip.actor, type: "detach" }); + is(response.type, "detached", "Should have detached"); + + yield removeTab(tab); + yield closeConnection(); + finish(); + })); +} + +function closeConnection() { + let deferred = promise.defer(); + gClient.close(deferred.resolve); + return deferred.promise; +} + +registerCleanupFunction(function() { + gTab1 = null; + gTab1Actor = null; + gTab2 = null; + gTab2Actor = null; + gClient = null; +});
--- a/content/base/src/nsScriptLoader.cpp +++ b/content/base/src/nsScriptLoader.cpp @@ -48,16 +48,17 @@ #include "nsCrossSiteListenerProxy.h" #include "nsSandboxFlags.h" #include "nsContentTypeParser.h" #include "nsINetworkSeer.h" #include "mozilla/dom/EncodingUtils.h" #include "mozilla/CORSMode.h" #include "mozilla/Attributes.h" +#include "mozilla/unused.h" #ifdef PR_LOGGING static PRLogModuleInfo* gCspPRLog; #endif using namespace mozilla; using namespace mozilla::dom; @@ -809,21 +810,20 @@ NotifyOffThreadScriptLoadCompletedRunnab } return rv; } static void OffThreadScriptLoaderCallback(void *aToken, void *aCallbackData) { - NotifyOffThreadScriptLoadCompletedRunnable* aRunnable = - static_cast<NotifyOffThreadScriptLoadCompletedRunnable*>(aCallbackData); + nsRefPtr<NotifyOffThreadScriptLoadCompletedRunnable> aRunnable = + dont_AddRef(static_cast<NotifyOffThreadScriptLoadCompletedRunnable*>(aCallbackData)); aRunnable->SetToken(aToken); NS_DispatchToMainThread(aRunnable); - NS_RELEASE(aRunnable); } nsresult nsScriptLoader::AttemptAsyncScriptParse(nsScriptLoadRequest* aRequest) { if (!aRequest->mElement->GetScriptAsync() || aRequest->mIsInline) { return NS_ERROR_FAILURE; } @@ -843,31 +843,29 @@ nsScriptLoader::AttemptAsyncScriptParse( JS::CompileOptions options(cx); FillCompileOptionsForRequest(aRequest, global, &options); if (!JS::CanCompileOffThread(cx, options, aRequest->mScriptText.Length())) { return NS_ERROR_FAILURE; } - NotifyOffThreadScriptLoadCompletedRunnable* runnable = + nsRefPtr<NotifyOffThreadScriptLoadCompletedRunnable> runnable = new NotifyOffThreadScriptLoadCompletedRunnable(aRequest, this); - // This reference will be consumed by OffThreadScriptLoaderCallback. - NS_ADDREF(runnable); - if (!JS::CompileOffThread(cx, options, aRequest->mScriptText.get(), aRequest->mScriptText.Length(), OffThreadScriptLoaderCallback, static_cast<void*>(runnable))) { return NS_ERROR_OUT_OF_MEMORY; } mDocument->BlockOnload(); + unused << runnable.forget(); return NS_OK; } nsresult nsScriptLoader::ProcessRequest(nsScriptLoadRequest* aRequest, void **aOffThreadToken) { NS_ASSERTION(nsContentUtils::IsSafeToRunScript(), "Processing requests when running scripts is unsafe.");
--- a/dom/apps/src/InterAppCommService.js +++ b/dom/apps/src/InterAppCommService.js @@ -71,31 +71,28 @@ function InterAppCommService() { // // For example: // // { // "foo": { // "app://subApp1.gaiamobile.org/manifest.webapp": { // pageURL: "app://subApp1.gaiamobile.org/handler.html", // description: "blah blah", - // appStatus: Ci.nsIPrincipal.APP_STATUS_CERTIFIED, // rules: { ... } // }, // "app://subApp2.gaiamobile.org/manifest.webapp": { // pageURL: "app://subApp2.gaiamobile.org/handler.html", // description: "blah blah", - // appStatus: Ci.nsIPrincipal.APP_STATUS_PRIVILEGED, // rules: { ... } // } // }, // "bar": { // "app://subApp3.gaiamobile.org/manifest.webapp": { // pageURL: "app://subApp3.gaiamobile.org/handler.html", // description: "blah blah", - // appStatus: Ci.nsIPrincipal.APP_STATUS_INSTALLED, // rules: { ... } // } // } // } // // TODO Bug 908999 - Update registered connections when app gets uninstalled. this._registeredConnections = {}; @@ -209,38 +206,37 @@ function InterAppCommService() { // } // } // } this._messagePortPairs = {}; } InterAppCommService.prototype = { registerConnection: function(aKeyword, aHandlerPageURI, aManifestURI, - aDescription, aAppStatus, aRules) { + aDescription, aRules) { let manifestURL = aManifestURI.spec; let pageURL = aHandlerPageURI.spec; if (DEBUG) { debug("registerConnection: aKeyword: " + aKeyword + " manifestURL: " + manifestURL + " pageURL: " + pageURL + - " aDescription: " + aDescription + " aAppStatus: " + aAppStatus + + " aDescription: " + aDescription + " aRules.minimumAccessLevel: " + aRules.minimumAccessLevel + " aRules.manifestURLs: " + aRules.manifestURLs + " aRules.installOrigins: " + aRules.installOrigins); } let subAppManifestURLs = this._registeredConnections[aKeyword]; if (!subAppManifestURLs) { subAppManifestURLs = this._registeredConnections[aKeyword] = {}; } subAppManifestURLs[manifestURL] = { pageURL: pageURL, description: aDescription, - appStatus: aAppStatus, rules: aRules, manifestURL: manifestURL }; }, _matchMinimumAccessLevel: function(aRules, aAppStatus) { if (!aRules || !aRules.minimumAccessLevel) { if (DEBUG) { @@ -295,77 +291,76 @@ InterAppCommService.prototype = { if (DEBUG) { debug("rules.manifestURLs is not matched!" + " manifestURLs: " + manifestURLs + " aManifestURL : " + aManifestURL); } return false; }, - _matchInstallOrigins: function(aRules, aManifestURL) { + _matchInstallOrigins: function(aRules, aInstallOrigin) { if (!aRules || !Array.isArray(aRules.installOrigins)) { if (DEBUG) { debug("rules.installOrigins is not available. No need to match."); } return true; } - let installOrigin = - appsService.getAppByManifestURL(aManifestURL).installOrigin; - let installOrigins = aRules.installOrigins; - if (installOrigins.indexOf(installOrigin) != -1) { + if (installOrigins.indexOf(aInstallOrigin) != -1) { return true; } if (DEBUG) { debug("rules.installOrigins is not matched!" + - " aManifestURL: " + aManifestURL + " installOrigins: " + installOrigins + - " installOrigin : " + installOrigin); + " installOrigin : " + aInstallOrigin); } return false; }, - _matchRules: function(aPubAppManifestURL, aPubAppStatus, aPubRules, - aSubAppManifestURL, aSubAppStatus, aSubRules) { + _matchRules: function(aPubAppManifestURL, aPubRules, + aSubAppManifestURL, aSubRules) { + let pubApp = appsService.getAppByManifestURL(aPubAppManifestURL); + let subApp = appsService.getAppByManifestURL(aSubAppManifestURL); + // TODO Bug 907068 In the initiative step, we only expose this API to // certified apps to meet the time line. Eventually, we need to make // it available for the non-certified apps as well. For now, only the // certified apps can match the rules. - if (aPubAppStatus != Ci.nsIPrincipal.APP_STATUS_CERTIFIED || - aSubAppStatus != Ci.nsIPrincipal.APP_STATUS_CERTIFIED) { + if (pubApp.appStatus != Ci.nsIPrincipal.APP_STATUS_CERTIFIED || + subApp.appStatus != Ci.nsIPrincipal.APP_STATUS_CERTIFIED) { if (DEBUG) { debug("Only certified apps are allowed to do connections."); } return false; } if (!aPubRules && !aSubRules) { if (DEBUG) { debug("No rules for publisher and subscriber. No need to match."); } return true; } // Check minimumAccessLevel. - if (!this._matchMinimumAccessLevel(aPubRules, aSubAppStatus) || - !this._matchMinimumAccessLevel(aSubRules, aPubAppStatus)) { + if (!this._matchMinimumAccessLevel(aPubRules, subApp.appStatus) || + !this._matchMinimumAccessLevel(aSubRules, pubApp.appStatus)) { return false; } // Check manifestURLs. if (!this._matchManifestURLs(aPubRules, aSubAppManifestURL) || !this._matchManifestURLs(aSubRules, aPubAppManifestURL)) { return false; } // Check installOrigins. - if (!this._matchInstallOrigins(aPubRules, aSubAppManifestURL) || - !this._matchInstallOrigins(aSubRules, aPubAppManifestURL)) { + if (!this._matchInstallOrigins(aPubRules, subApp.installOrigin) || + !this._matchInstallOrigins(aSubRules, pubApp.installOrigin)) { return false; } // Check developers. // TODO Do we really want to check this? This one seems naive. if (DEBUG) debug("All rules are matched."); return true; @@ -447,17 +442,16 @@ InterAppCommService.prototype = { }, _connect: function(aMessage, aTarget) { let keyword = aMessage.keyword; let pubRules = aMessage.rules; let pubAppManifestURL = aMessage.manifestURL; let outerWindowID = aMessage.outerWindowID; let requestID = aMessage.requestID; - let pubAppStatus = aMessage.appStatus; let subAppManifestURLs = this._registeredConnections[keyword]; if (!subAppManifestURLs) { if (DEBUG) { debug("No apps are subscribed for this connection. Returning."); } this._dispatchMessagePorts(keyword, pubAppManifestURL, [], aTarget, outerWindowID, requestID); @@ -481,22 +475,21 @@ InterAppCommService.prototype = { if (DEBUG) { debug("Don't need to select again. Skipping: " + subAppManifestURL); } continue; } // Only rule-matched publishers/subscribers are allowed to connect. let subscribedInfo = subAppManifestURLs[subAppManifestURL]; - let subAppStatus = subscribedInfo.appStatus; let subRules = subscribedInfo.rules; let matched = - this._matchRules(pubAppManifestURL, pubAppStatus, pubRules, - subAppManifestURL, subAppStatus, subRules); + this._matchRules(pubAppManifestURL, pubRules, + subAppManifestURL, subRules); if (!matched) { if (DEBUG) { debug("Rules are not matched. Skipping: " + subAppManifestURL); } continue; } appsToSelect.push({
new file mode 100644 --- /dev/null +++ b/dom/apps/src/ScriptPreloader.jsm @@ -0,0 +1,76 @@ +/* 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/. */ + +"use strict"; + +const Cu = Components.utils; +const Ci = Components.interfaces; + +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +Cu.import("resource://gre/modules/Services.jsm"); +Cu.import("resource://gre/modules/Promise.jsm"); + +this.EXPORTED_SYMBOLS = ["ScriptPreloader"]; + +function debug(aMsg) { + //dump("--*-- ScriptPreloader: " + aMsg + "\n"); +} + +this.ScriptPreloader = { +#ifdef MOZ_B2G + _enabled: true, +#else + _enabled: false, +#endif + + preload: function(aApp, aManifest) { + debug("Preloading " + aApp.origin); + let deferred = Promise.defer(); + + if (!this._enabled) { + deferred.resolve(); + return deferred.promise; + } + + if (aManifest.precompile && + Array.isArray(aManifest.precompile) && + aManifest.precompile.length > 0) { + let origin = Services.io.newURI(aApp.origin, null, null); + let toLoad = aManifest.precompile.length; + let principal = + Services.scriptSecurityManager + .getAppCodebasePrincipal(origin, aApp.localId, false); + + aManifest.precompile.forEach((aPath) => { + let uri = Services.io.newURI(aPath, null, origin); + debug("Script to compile: " + uri.spec); + try { + Services.scriptloader.precompileScript(uri, principal, + (aSubject, aTopic, aData) => { + let uri = aSubject.QueryInterface(Ci.nsIURI); + debug("Done compiling " + uri.spec); + + toLoad--; + if (toLoad == 0) { + deferred.resolve(); + } + }); + } catch (e) { + // Resolve the promise if precompileScript throws. + deferred.resolve(); + } + }); + } else { + // The precompile field is not an array, let the developer know. + // We don't want to have to enable debug for that to show up. + if (aManifest.precompile) { + Cu.reportError("ASM.JS compilation failed: the 'precompile' manifest " + + "property should be an array of script uris.\n"); + } + deferred.resolve(); + } + + return deferred.promise; + } +}
--- a/dom/apps/src/Webapps.js +++ b/dom/apps/src/Webapps.js @@ -481,17 +481,16 @@ WebappsApplication.prototype = { connect: function(aKeyword, aRules) { return this.createPromise(function (aResolve, aReject) { cpmm.sendAsyncMessage("Webapps:Connect", { keyword: aKeyword, rules: aRules, manifestURL: this.manifestURL, outerWindowID: this._id, - appStatus: this._appStatus, requestID: this.getPromiseResolverId({ resolve: aResolve, reject: aReject })}); }.bind(this)); }, getConnections: function() {
--- a/dom/apps/src/Webapps.jsm +++ b/dom/apps/src/Webapps.jsm @@ -56,16 +56,19 @@ XPCOMUtils.defineLazyModuleGetter(this, "resource://gre/modules/SystemMessagePermissionsChecker.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "WebappOSUtils", "resource://gre/modules/WebappOSUtils.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "NetUtil", "resource://gre/modules/NetUtil.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "ScriptPreloader", + "resource://gre/modules/ScriptPreloader.jsm"); + #ifdef MOZ_WIDGET_GONK XPCOMUtils.defineLazyGetter(this, "libcutils", function() { Cu.import("resource://gre/modules/systemlibs.js"); return libcutils; }); #endif function debug(aMsg) { @@ -729,17 +732,16 @@ this.DOMApplicationRegistry = { msgmgr.registerPage("connection", handlerPageURI, manifestURI); } interAppCommService. registerConnection(keyword, handlerPageURI, manifestURI, connection.description, - AppsUtils.getAppManifestStatus(manifest), connection.rules); } }, _registerSystemMessages: function(aManifest, aApp) { this._registerSystemMessagesForEntryPoint(aManifest, aApp, null); if (!aManifest.entry_points) { @@ -1484,17 +1486,19 @@ this.DOMApplicationRegistry = { for (let prop in app.staged) { app[prop] = app.staged[prop]; } delete app.staged; } delete app.retryingDownload; - this._saveApps().then(() => { + // Update the asm.js scripts we need to compile. + ScriptPreloader.preload(app, aData) + .then(() => this._saveApps()).then(() => { // Update the handlers and permissions for this app. this.updateAppHandlers(aOldManifest, aData, app); AppsUtils.loadJSONAsync(staged.path).then((aUpdateManifest) => { let appObject = AppsUtils.cloneAppObject(app); appObject.updateManifest = aUpdateManifest; this.notifyUpdateHandlers(appObject, aData, appFile.path); }); @@ -2590,23 +2594,29 @@ onInstallSuccessAck: function onInstallS this.updateDataStore(this.webapps[aId].localId, aNewApp.origin, aNewApp.manifestURL, aManifest, aNewApp.appStatus); this.broadcastMessage("Webapps:UpdateState", { app: app, manifest: aManifest, manifestURL: aNewApp.manifestURL }); - this.broadcastMessage("Webapps:FireEvent", { - eventType: ["downloadsuccess", "downloadapplied"], - manifestURL: aNewApp.manifestURL - }); - if (aInstallSuccessCallback) { - aInstallSuccessCallback(aManifest, zipFile.path); - } + + // Check if we have asm.js code to preload for this application. + ScriptPreloader.preload(aNewApp, aManifest) + .then(() => { + this.broadcastMessage("Webapps:FireEvent", { + eventType: ["downloadsuccess", "downloadapplied"], + manifestURL: aNewApp.manifestURL + }); + if (aInstallSuccessCallback) { + aInstallSuccessCallback(aManifest, zipFile.path); + } + } + ); }); }, _nextLocalId: function() { let id = Services.prefs.getIntPref("dom.mozApps.maxLocalId") + 1; while (this.getManifestURLByLocalId(id)) { id++;
--- a/dom/apps/src/moz.build +++ b/dom/apps/src/moz.build @@ -31,16 +31,17 @@ EXTRA_JS_MODULES += [ 'PermissionsInstaller.jsm', 'PermissionsTable.jsm', 'StoreTrustAnchor.jsm', ] EXTRA_PP_JS_MODULES += [ 'AppsUtils.jsm', 'OperatorApps.jsm', + 'ScriptPreloader.jsm', 'Webapps.jsm', ] FAIL_ON_WARNINGS = True FINAL_LIBRARY = 'gklayout' LOCAL_INCLUDES += [
--- a/dom/interfaces/apps/nsIInterAppCommService.idl +++ b/dom/interfaces/apps/nsIInterAppCommService.idl @@ -11,30 +11,27 @@ interface nsIURI; * * This interface contains helpers for Inter-App Communication API [1] related * purposes. A singleton service of this interface will be instantiated during * the system boot-up, which plays the role of the central service receiving * messages from and interacting with the content processes. * * [1] https://wiki.mozilla.org/WebAPI/Inter_App_Communication_Alt_proposal */ -[scriptable, uuid(7fdd8b68-0b0a-11e3-9b4c-afbc236da250)] +[scriptable, uuid(b3d711a4-c6a4-11e3-8fd3-738e7fbcb6d6)] interface nsIInterAppCommService : nsISupports { /* * Registration of a page that wants to be connected to other apps through * the Inter-App Communication API. * * @param keyword The connection's keyword. * @param handlerPageURI The URI of the handler's page. * @param manifestURI The webapp's manifest URI. * @param description The connection's description. - * @param appStatus The app status can be Ci.nsIPrincipal.APP_STATUS_[ - * NOT_INSTALLED, INSTALLED, PRIVILEGED, CERTIFIED]. * @param rules The connection's rules. */ void registerConnection(in DOMString keyword, in nsIURI handlerPageURI, in nsIURI manifestURI, in DOMString description, - in unsigned short appStatus, in jsval rules); };
--- a/dom/system/gonk/Nfc.js +++ b/dom/system/gonk/Nfc.js @@ -411,17 +411,16 @@ XPCOMUtils.defineLazyGetter(this, "gMess function Nfc() { debug("Starting Worker"); this.worker = new ChromeWorker("resource://gre/modules/nfc_worker.js"); this.worker.onerror = this.onerror.bind(this); this.worker.onmessage = this.onmessage.bind(this); Services.obs.addObserver(this, NFC.TOPIC_MOZSETTINGS_CHANGED, false); - Services.obs.addObserver(this, NFC.TOPIC_HARDWARE_STATE, false); gMessageManager.init(this); let lock = gSettingsService.createLock(); lock.get(NFC.SETTING_NFC_ENABLED, this); // Maps sessionId (that are generated from nfcd) with a unique guid : 'SessionToken' this.sessionTokenMap = {}; this.targetsByRequestId = {}; @@ -652,36 +651,19 @@ Nfc.prototype = { switch (topic) { case NFC.TOPIC_MOZSETTINGS_CHANGED: let setting = JSON.parse(data); if (setting) { let setting = JSON.parse(data); this.handle(setting.key, setting.value); } break; - case NFC.TOPIC_HARDWARE_STATE: - let state = JSON.parse(data); - if (state) { - let level = this.hardwareStateToPowerlevel(state.nfcHardwareState); - this.setConfig({ powerLevel: level }); - } - break; } }, setConfig: function setConfig(prop) { this.sendToWorker("config", prop); - }, - - hardwareStateToPowerlevel: function hardwareStateToPowerlevel(state) { - switch (state) { - case 0: return NFC.NFC_POWER_LEVEL_DISABLED; - case 1: return NFC.NFC_POWER_LEVEL_ENABLED; - case 2: return NFC.NFC_POWER_LEVEL_ENABLED; - case 3: return NFC.NFC_POWER_LEVEL_LOW; - default: return NFC.NFC_POWER_LEVEL_UNKNOWN; - } } }; if (NFC_ENABLED) { this.NSGetFactory = XPCOMUtils.generateNSGetFactory([Nfc]); }
--- a/dom/system/gonk/nfc_consts.js +++ b/dom/system/gonk/nfc_consts.js @@ -40,34 +40,38 @@ this.NFC_RESPONSE_CONFIG = 1001; this.NFC_RESPONSE_READ_NDEF_DETAILS = 1002; this.NFC_RESPONSE_READ_NDEF = 1003; this.NFC_NOTIFICATION_INITIALIZED = 2000; this.NFC_NOTIFICATION_TECH_DISCOVERED = 2001; this.NFC_NOTIFICATION_TECH_LOST = 2002; this.NFC_TECHS = { - 0:'NDEF', - 1:'NDEF_WRITEABLE', - 2:'NDEF_FORMATABLE', - 3:'P2P' + 0:"NDEF", + 1:"NDEF_WRITEABLE", + 2:"NDEF_FORMATABLE", + 3:"P2P", + 4:"NFC_A", + 5:"NFC_B", + 6:"NFC_F", + 7:"NFC_V", + 8:"NFC_ISO_DEP" }; // TODO: Bug 933595. Fill-in all error codes for Gonk/nfcd protocol this.GECKO_NFC_ERROR_SUCCESS = 0; this.GECKO_NFC_ERROR_GENERIC_FAILURE = 1; // NFC powerlevels must match config PDUs. this.NFC_POWER_LEVEL_UNKNOWN = -1; 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.TOPIC_HARDWARE_STATE = "nfc-hardware-state-change"; this.SETTING_NFC_ENABLED = "nfc.enabled"; this.NFC_PEER_EVENT_READY = 0x01; this.NFC_PEER_EVENT_LOST = 0x02; // Allow this file to be imported via Components.utils.import(). this.EXPORTED_SYMBOLS = Object.keys(this);
--- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -4341,16 +4341,18 @@ JS::ReadOnlyCompileOptions::copyPODOptio forEval = rhs.forEval; noScriptRval = rhs.noScriptRval; selfHostingMode = rhs.selfHostingMode; canLazilyParse = rhs.canLazilyParse; strictOption = rhs.strictOption; extraWarningsOption = rhs.extraWarningsOption; werrorOption = rhs.werrorOption; asmJSOption = rhs.asmJSOption; + forceAsync = rhs.forceAsync; + installedFile = rhs.installedFile; sourcePolicy = rhs.sourcePolicy; introductionType = rhs.introductionType; introductionLineno = rhs.introductionLineno; introductionOffset = rhs.introductionOffset; hasIntroductionInfo = rhs.hasIntroductionInfo; } JSPrincipals *
--- a/js/xpconnect/idl/mozIJSSubScriptLoader.idl +++ b/js/xpconnect/idl/mozIJSSubScriptLoader.idl @@ -1,17 +1,21 @@ /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * 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 "nsISupports.idl" -[scriptable, uuid(b21f1579-d994-4e99-a85d-a685140f3ec1)] +interface nsIURI; +interface nsIPrincipal; +interface nsIObserver; + +[scriptable, uuid(19533e7b-f321-4ef1-bc59-6e812dc2a733)] interface mozIJSSubScriptLoader : nsISupports { /** * This method should only be called from JS! * In JS, the signature looks like: * rv loadSubScript (url [, obj] [, charset]); * @param url the url of the sub-script, it MUST be either a file:, * resource:, or chrome: url, and MUST be local. @@ -34,9 +38,27 @@ interface mozIJSSubScriptLoader : nsISup * @param optionsObject an object with parameters. Valid parameters are: * - charset: specifying the character encoding of the file (default: ASCII) * - target: an object to evaluate onto (default: global object of the caller) * - ignoreCache: if set to true, will bypass the cache for reading the file. * @retval rv the value returned by the sub-script */ [implicit_jscontext] jsval loadSubScriptWithOptions(in AString url, in jsval options); + + /* + * Compiles a JS script off the main thread and calls back the + * observer once it's done. + * The script will be cached in temporary or persistent storage depending + * on the principal used. + * We fire the notification callback in all cases - there is no fatal + * error there. + * @param uri the uri of the script to load. + * @param principal the principal from which we get the app id if any. + * @param observer this observer will be called once the script has + * been precompiled. The notification topic will be + * 'script-precompiled' and the subject the uri of the + * script as a nsIURI. + */ + void precompileScript(in nsIURI uri, + in nsIPrincipal principal, + in nsIObserver observer); };
--- a/js/xpconnect/loader/mozJSSubScriptLoader.cpp +++ b/js/xpconnect/loader/mozJSSubScriptLoader.cpp @@ -13,30 +13,34 @@ #include "nsIIOService.h" #include "nsIChannel.h" #include "nsIInputStream.h" #include "nsNetCID.h" #include "nsNetUtil.h" #include "nsIFileURL.h" #include "nsScriptLoader.h" #include "nsIScriptSecurityManager.h" +#include "nsThreadUtils.h" #include "jsapi.h" #include "jsfriendapi.h" #include "js/OldDebugAPI.h" #include "nsJSPrincipals.h" #include "xpcpublic.h" // For xpc::SystemErrorReporter #include "xpcprivate.h" // For xpc::OptionsBase +#include "jswrapper.h" #include "mozilla/scache/StartupCache.h" #include "mozilla/scache/StartupCacheUtils.h" +#include "mozilla/unused.h" using namespace mozilla::scache; using namespace JS; using namespace xpc; +using namespace mozilla; class MOZ_STACK_CLASS LoadSubScriptOptions : public OptionsBase { public: LoadSubScriptOptions(JSContext *cx = xpc_GetSafeJSContext(), JSObject *options = nullptr) : OptionsBase(cx, options) , target(cx) , charset(NullString()) @@ -360,8 +364,216 @@ mozJSSubScriptLoader::DoLoadSubScriptWit } if (cache && ok && writeScript) { WriteCachedScript(cache, cachePath, cx, mSystemPrincipal, script); } return NS_OK; } + +/** + * Let us compile scripts from a URI off the main thread. + */ + +class ScriptPrecompiler : public nsIStreamLoaderObserver +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSISTREAMLOADEROBSERVER + + ScriptPrecompiler(nsIObserver* aObserver, + nsIPrincipal* aPrincipal, + nsIChannel* aChannel) + : mObserver(aObserver) + , mPrincipal(aPrincipal) + , mChannel(aChannel) + {} + + virtual ~ScriptPrecompiler() + {} + + static void OffThreadCallback(void *aToken, void *aData); + + /* Sends the "done" notification back. Main thread only. */ + void SendObserverNotification(); + +private: + nsRefPtr<nsIObserver> mObserver; + nsRefPtr<nsIPrincipal> mPrincipal; + nsRefPtr<nsIChannel> mChannel; + nsString mScript; +}; + +NS_IMPL_ISUPPORTS1(ScriptPrecompiler, nsIStreamLoaderObserver); + +class NotifyPrecompilationCompleteRunnable : public nsRunnable +{ +public: + NS_DECL_NSIRUNNABLE + + NotifyPrecompilationCompleteRunnable(ScriptPrecompiler* aPrecompiler) + : mPrecompiler(aPrecompiler) + , mToken(nullptr) + {} + + void SetToken(void* aToken) { + MOZ_ASSERT(aToken && !mToken); + mToken = aToken; + } + +protected: + nsRefPtr<ScriptPrecompiler> mPrecompiler; + void* mToken; +}; + +/* RAII helper class to send observer notifications */ +class AutoSendObserverNotification { +public: + AutoSendObserverNotification(ScriptPrecompiler* aPrecompiler) + : mPrecompiler(aPrecompiler) + {} + + ~AutoSendObserverNotification() { + if (mPrecompiler) { + mPrecompiler->SendObserverNotification(); + } + } + + void Disarm() { + mPrecompiler = nullptr; + } + +private: + ScriptPrecompiler* mPrecompiler; +}; + +NS_IMETHODIMP +NotifyPrecompilationCompleteRunnable::Run(void) +{ + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(mPrecompiler); + + AutoSendObserverNotification notifier(mPrecompiler); + + if (mToken) { + JSRuntime *rt = XPCJSRuntime::Get()->Runtime(); + NS_ENSURE_TRUE(rt, NS_ERROR_FAILURE); + JS::FinishOffThreadScript(nullptr, rt, mToken); + } + + return NS_OK; +} + +NS_IMETHODIMP +ScriptPrecompiler::OnStreamComplete(nsIStreamLoader* aLoader, + nsISupports* aContext, + nsresult aStatus, + uint32_t aLength, + const uint8_t* aString) +{ + AutoSendObserverNotification notifier(this); + + // Just notify that we are done with this load. + NS_ENSURE_SUCCESS(aStatus, NS_OK); + + // Convert data to jschar* and prepare to call CompileOffThread. + nsAutoString hintCharset; + nsresult rv = + nsScriptLoader::ConvertToUTF16(mChannel, aString, aLength, + hintCharset, nullptr, mScript); + + NS_ENSURE_SUCCESS(rv, NS_OK); + + // Our goal is to cache persistently the compiled script and to avoid quota + // checks. Since the caching mechanism decide the persistence type based on + // the principal, we create a new global with the app's principal. + // We then enter its compartment to compile with its principal. + AutoSafeJSContext cx; + RootedValue v(cx); + SandboxOptions sandboxOptions; + sandboxOptions.sandboxName.AssignASCII("asm.js precompilation"); + sandboxOptions.invisibleToDebugger = true; + rv = CreateSandboxObject(cx, &v, mPrincipal, sandboxOptions); + NS_ENSURE_SUCCESS(rv, NS_OK); + + JSAutoCompartment ac(cx, js::UncheckedUnwrap(&v.toObject())); + + JS::CompileOptions options(cx, JSVERSION_DEFAULT); + options.setSourcePolicy(CompileOptions::NO_SOURCE); + options.forceAsync = true; + options.compileAndGo = true; + options.installedFile = true; + + nsCOMPtr<nsIURI> uri; + mChannel->GetURI(getter_AddRefs(uri)); + nsAutoCString spec; + uri->GetSpec(spec); + options.setFile(spec.get()); + + if (!JS::CanCompileOffThread(cx, options, mScript.Length())) { + NS_WARNING("Can't compile script off thread!"); + return NS_OK; + } + + nsRefPtr<NotifyPrecompilationCompleteRunnable> runnable = + new NotifyPrecompilationCompleteRunnable(this); + + if (!JS::CompileOffThread(cx, options, + mScript.get(), mScript.Length(), + OffThreadCallback, + static_cast<void*>(runnable))) { + NS_WARNING("Failed to compile script off thread!"); + return NS_OK; + } + + unused << runnable.forget(); + notifier.Disarm(); + + return NS_OK; +} + +/* static */ +void +ScriptPrecompiler::OffThreadCallback(void* aToken, void* aData) +{ + nsRefPtr<NotifyPrecompilationCompleteRunnable> runnable = + dont_AddRef(static_cast<NotifyPrecompilationCompleteRunnable*>(aData)); + runnable->SetToken(aToken); + + NS_DispatchToMainThread(runnable); +} + +void +ScriptPrecompiler::SendObserverNotification() +{ + MOZ_ASSERT(mChannel && mObserver); + MOZ_ASSERT(NS_IsMainThread()); + + nsCOMPtr<nsIURI> uri; + mChannel->GetURI(getter_AddRefs(uri)); + mObserver->Observe(uri, "script-precompiled", nullptr); +} + +NS_IMETHODIMP +mozJSSubScriptLoader::PrecompileScript(nsIURI* aURI, + nsIPrincipal* aPrincipal, + nsIObserver *aObserver) +{ + nsCOMPtr<nsIChannel> channel; + nsresult rv = NS_NewChannel(getter_AddRefs(channel), + aURI, nullptr, nullptr, nullptr, + nsIRequest::LOAD_NORMAL, nullptr); + NS_ENSURE_SUCCESS(rv, rv); + + nsRefPtr<ScriptPrecompiler> loadObserver = + new ScriptPrecompiler(aObserver, aPrincipal, channel); + + nsCOMPtr<nsIStreamLoader> loader; + rv = NS_NewStreamLoader(getter_AddRefs(loader), loadObserver); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr<nsIStreamListener> listener = loader.get(); + rv = channel->AsyncOpen(listener, nullptr); + NS_ENSURE_SUCCESS(rv, rv); + + return NS_OK; +}
--- a/mobile/android/base/fxa/FirefoxAccounts.java +++ b/mobile/android/base/fxa/FirefoxAccounts.java @@ -7,16 +7,17 @@ package org.mozilla.gecko.fxa; import java.io.File; import java.util.EnumSet; import java.util.concurrent.CountDownLatch; import org.mozilla.gecko.background.common.log.Logger; import org.mozilla.gecko.fxa.authenticator.AccountPickler; import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount; import org.mozilla.gecko.fxa.sync.FxAccountSyncAdapter; +import org.mozilla.gecko.fxa.sync.FxAccountSyncStatusHelper; import org.mozilla.gecko.sync.ThreadPool; import org.mozilla.gecko.sync.Utils; import android.accounts.Account; import android.accounts.AccountManager; import android.content.ContentResolver; import android.content.Context; import android.os.Bundle; @@ -56,16 +57,23 @@ public class FirefoxAccounts { public static final EnumSet<SyncHint> NOW = EnumSet.of( SyncHint.SCHEDULE_NOW); public static final EnumSet<SyncHint> FORCE = EnumSet.of( SyncHint.SCHEDULE_NOW, SyncHint.IGNORE_LOCAL_RATE_LIMIT, SyncHint.IGNORE_REMOTE_SERVER_BACKOFF); + public interface SyncStatusListener { + public Context getContext(); + public Account getAccount(); + public void onSyncStarted(); + public void onSyncFinished(); + } + /** * Returns true if a FirefoxAccount exists, false otherwise. * * @param context Android context. * @return true if at least one Firefox account exists. */ public static boolean firefoxAccountsExist(final Context context) { return getFirefoxAccounts(context).length > 0; @@ -195,34 +203,65 @@ public class FirefoxAccounts { } /** * Request a sync for the given Android Account. * <p> * Any hints are strictly optional: the actual requested sync is scheduled by * the Android sync scheduler, and the sync mechanism may ignore hints as it * sees fit. + * <p> + * It is safe to call this method from any thread. * * @param account to sync. * @param syncHints to pass to sync. * @param stagesToSync stage names to sync. * @param stagesToSkip stage names to skip. */ - public static void requestSync(Account account, EnumSet<SyncHint> syncHints, String[] stagesToSync, String[] stagesToSkip) { + public static void requestSync(final Account account, EnumSet<SyncHint> syncHints, String[] stagesToSync, String[] stagesToSkip) { if (account == null) { throw new IllegalArgumentException("account must not be null"); } if (syncHints == null) { throw new IllegalArgumentException("syncHints must not be null"); } final Bundle extras = new Bundle(); putHintsToSync(extras, syncHints); Utils.putStageNamesToSync(extras, stagesToSync, stagesToSkip); Logger.info(LOG_TAG, "Requesting sync."); logSyncHints(syncHints); - for (String authority : AndroidFxAccount.getAndroidAuthorities()) { - ContentResolver.requestSync(account, authority, extras); - } + // We get strict mode warnings on some devices, so make the request on a + // background thread. + ThreadPool.run(new Runnable() { + @Override + public void run() { + for (String authority : AndroidFxAccount.getAndroidAuthorities()) { + ContentResolver.requestSync(account, authority, extras); + } + } + }); + } + + /** + * Start notifying <code>syncStatusListener</code> of sync status changes. + * <p> + * Only a weak reference to <code>syncStatusListener</code> is held. + * + * @param syncStatusListener to start notifying. + */ + public static void addSyncStatusListener(SyncStatusListener syncStatusListener) { + // startObserving null-checks its argument. + FxAccountSyncStatusHelper.getInstance().startObserving(syncStatusListener); + } + + /** + * Stop notifying <code>syncStatusListener</code> of sync status changes. + * + * @param syncStatusListener to stop notifying. + */ + public static void removeSyncStatusListener(SyncStatusListener syncStatusListener) { + // stopObserving null-checks its argument. + FxAccountSyncStatusHelper.getInstance().stopObserving(syncStatusListener); } }
--- a/mobile/android/base/fxa/activities/FxAccountConfirmAccountActivity.java +++ b/mobile/android/base/fxa/activities/FxAccountConfirmAccountActivity.java @@ -16,16 +16,17 @@ import org.mozilla.gecko.background.fxa. import org.mozilla.gecko.fxa.FirefoxAccounts; import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount; import org.mozilla.gecko.fxa.login.Engaged; import org.mozilla.gecko.fxa.login.State; import org.mozilla.gecko.fxa.login.State.Action; import org.mozilla.gecko.fxa.sync.FxAccountSyncStatusHelper; import org.mozilla.gecko.sync.setup.activities.ActivityUtils; +import android.accounts.Account; import android.app.Activity; import android.content.Context; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.TextView; import android.widget.Toast; @@ -38,17 +39,17 @@ public class FxAccountConfirmAccountActi // Set in onCreate. protected TextView verificationLinkTextView; protected View resendLink; // Set in onResume. protected AndroidFxAccount fxAccount; - protected final SyncStatusDelegate syncStatusDelegate = new SyncStatusDelegate(); + protected final InnerSyncStatusDelegate syncStatusDelegate = new InnerSyncStatusDelegate(); public FxAccountConfirmAccountActivity() { super(CANNOT_RESUME_WHEN_NO_ACCOUNTS_EXIST); } /** * {@inheritDoc} */ @@ -97,36 +98,41 @@ public class FxAccountConfirmAccountActi super.onPause(); FxAccountSyncStatusHelper.getInstance().stopObserving(syncStatusDelegate); if (fxAccount != null) { fxAccount.requestSync(FirefoxAccounts.SOON); } } - protected class SyncStatusDelegate implements FxAccountSyncStatusHelper.Delegate { + protected class InnerSyncStatusDelegate implements FirefoxAccounts.SyncStatusListener { protected final Runnable refreshRunnable = new Runnable() { @Override public void run() { refresh(); } }; @Override - public AndroidFxAccount getAccount() { - return fxAccount; + public Context getContext() { + return FxAccountConfirmAccountActivity.this; } @Override - public void handleSyncStarted() { + public Account getAccount() { + return fxAccount.getAndroidAccount(); + } + + @Override + public void onSyncStarted() { Logger.info(LOG_TAG, "Got sync started message; ignoring."); } @Override - public void handleSyncFinished() { + public void onSyncFinished() { if (fxAccount == null) { return; } Logger.info(LOG_TAG, "Got sync finished message; refreshing."); runOnUiThread(refreshRunnable); } }
--- a/mobile/android/base/fxa/activities/FxAccountStatusFragment.java +++ b/mobile/android/base/fxa/activities/FxAccountStatusFragment.java @@ -14,17 +14,19 @@ import org.mozilla.gecko.background.pref import org.mozilla.gecko.fxa.FirefoxAccounts; import org.mozilla.gecko.fxa.FxAccountConstants; import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount; import org.mozilla.gecko.fxa.login.Married; import org.mozilla.gecko.fxa.login.State; import org.mozilla.gecko.fxa.sync.FxAccountSyncStatusHelper; import org.mozilla.gecko.sync.SyncConfiguration; +import android.accounts.Account; import android.content.ContentResolver; +import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.os.Bundle; import android.os.Handler; import android.preference.CheckBoxPreference; import android.preference.Preference; import android.preference.Preference.OnPreferenceClickListener; import android.preference.PreferenceCategory; @@ -67,17 +69,17 @@ public class FxAccountStatusFragment ext // Used to post delayed sync requests. protected Handler handler; // Member variable so that re-posting pushes back the already posted instance. // This Runnable references the fxAccount above, but it is not specific to a // single account. (That is, it does not capture a single account instance.) protected Runnable requestSyncRunnable; - protected final SyncStatusDelegate syncStatusDelegate = new SyncStatusDelegate(); + protected final InnerSyncStatusDelegate syncStatusDelegate = new InnerSyncStatusDelegate(); protected Preference ensureFindPreference(String key) { Preference preference = findPreference(key); if (preference == null) { throw new IllegalStateException("Could not find preference with key: " + key); } return preference; } @@ -235,40 +237,45 @@ public class FxAccountStatusFragment ext } protected void showConnected() { syncCategory.setTitle(R.string.fxaccount_status_sync_enabled); showOnlyOneErrorPreference(null); setCheckboxesEnabled(true); } - protected class SyncStatusDelegate implements FxAccountSyncStatusHelper.Delegate { + protected class InnerSyncStatusDelegate implements FirefoxAccounts.SyncStatusListener { protected final Runnable refreshRunnable = new Runnable() { @Override public void run() { refresh(); } }; @Override - public AndroidFxAccount getAccount() { - return fxAccount; + public Context getContext() { + return FxAccountStatusFragment.this.getActivity(); } @Override - public void handleSyncStarted() { + public Account getAccount() { + return fxAccount.getAndroidAccount(); + } + + @Override + public void onSyncStarted() { if (fxAccount == null) { return; } Logger.info(LOG_TAG, "Got sync started message; refreshing."); getActivity().runOnUiThread(refreshRunnable); } @Override - public void handleSyncFinished() { + public void onSyncFinished() { if (fxAccount == null) { return; } Logger.info(LOG_TAG, "Got sync finished message; refreshing."); getActivity().runOnUiThread(refreshRunnable); } }
--- a/mobile/android/base/fxa/sync/FxAccountSyncStatusHelper.java +++ b/mobile/android/base/fxa/sync/FxAccountSyncStatusHelper.java @@ -3,77 +3,65 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package org.mozilla.gecko.fxa.sync; import java.util.Map; import java.util.Map.Entry; import java.util.WeakHashMap; +import org.mozilla.gecko.fxa.FirefoxAccounts; import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount; import android.content.ContentResolver; import android.content.SyncStatusObserver; /** * Abstract away some details of Android's SyncStatusObserver. * <p> * Provides a simplified sync started/sync finished delegate. - * <p> - * We would prefer to register multiple observers, but it's of limited value - * right now, so we support only a single observer, and we are as tolerant as - * possible of non-paired add/remove calls. */ public class FxAccountSyncStatusHelper implements SyncStatusObserver { @SuppressWarnings("unused") private static final String LOG_TAG = FxAccountSyncStatusHelper.class.getSimpleName(); protected static FxAccountSyncStatusHelper sInstance = null; public synchronized static FxAccountSyncStatusHelper getInstance() { if (sInstance == null) { sInstance = new FxAccountSyncStatusHelper(); } return sInstance; } - public interface Delegate { - public AndroidFxAccount getAccount(); - public void handleSyncStarted(); - public void handleSyncFinished(); - } - // Used to unregister this as a listener. protected Object handle = null; // Maps delegates to whether their underlying Android account was syncing the // last time we observed a status change. - protected Map<Delegate, Boolean> delegates = new WeakHashMap<Delegate, Boolean>(); + protected Map<FirefoxAccounts.SyncStatusListener, Boolean> delegates = new WeakHashMap<FirefoxAccounts.SyncStatusListener, Boolean>(); @Override public synchronized void onStatusChanged(int which) { - for (Entry<Delegate, Boolean> entry : delegates.entrySet()) { - final Delegate delegate = entry.getKey(); - final AndroidFxAccount fxAccount = delegate.getAccount(); - if (fxAccount == null) { - continue; - } + for (Entry<FirefoxAccounts.SyncStatusListener, Boolean> entry : delegates.entrySet()) { + final FirefoxAccounts.SyncStatusListener delegate = entry.getKey(); + final AndroidFxAccount fxAccount = new AndroidFxAccount(delegate.getContext(), delegate.getAccount()); final boolean active = fxAccount.isCurrentlySyncing(); // Remember for later. boolean wasActiveLastTime = entry.getValue(); // It's okay to update the value of an entry while iterating the entrySet. entry.setValue(active); if (active && !wasActiveLastTime) { // We've started a sync. - delegate.handleSyncStarted(); + delegate.onSyncStarted(); } if (!active && wasActiveLastTime) { // We've finished a sync. - delegate.handleSyncFinished(); + delegate.onSyncFinished(); } } } protected void addListener() { final int mask = ContentResolver.SYNC_OBSERVER_TYPE_ACTIVE; if (this.handle != null) { throw new IllegalStateException("Already registered this as an observer?"); @@ -84,30 +72,30 @@ public class FxAccountSyncStatusHelper i protected void removeListener() { Object handle = this.handle; this.handle = null; if (handle != null) { ContentResolver.removeStatusChangeListener(handle); } } - public synchronized void startObserving(Delegate delegate) { + public synchronized void startObserving(FirefoxAccounts.SyncStatusListener delegate) { if (delegate == null) { throw new IllegalArgumentException("delegate must not be null"); } if (delegates.containsKey(delegate)) { return; } // If we are the first delegate to the party, start listening. if (delegates.isEmpty()) { addListener(); } delegates.put(delegate, Boolean.FALSE); } - public synchronized void stopObserving(Delegate delegate) { + public synchronized void stopObserving(FirefoxAccounts.SyncStatusListener delegate) { delegates.remove(delegate); // If we are the last delegate leaving the party, stop listening. if (delegates.isEmpty()) { removeListener(); } } }
--- a/toolkit/components/autocomplete/nsAutoCompleteController.cpp +++ b/toolkit/components/autocomplete/nsAutoCompleteController.cpp @@ -405,17 +405,17 @@ nsAutoCompleteController::HandleKeyNavig if (completeSelection) { int32_t selectedIndex; popup->GetSelectedIndex(&selectedIndex); if (selectedIndex >= 0) { // A result is selected, so fill in its value nsAutoString value; - if (NS_SUCCEEDED(GetResultValueAt(selectedIndex, true, value))) { + if (NS_SUCCEEDED(GetResultValueAt(selectedIndex, false, value))) { input->SetTextValue(value); input->SelectTextRange(value.Length(), value.Length()); } } else { // Nothing is selected, so fill in the last typed value input->SetTextValue(mSearchString); input->SelectTextRange(mSearchString.Length(), mSearchString.Length()); } @@ -476,17 +476,17 @@ nsAutoCompleteController::HandleKeyNavig if (isOpen) { int32_t selectedIndex; popup->GetSelectedIndex(&selectedIndex); bool shouldComplete; input->GetCompleteDefaultIndex(&shouldComplete); if (selectedIndex >= 0) { // The pop-up is open and has a selection, take its value nsAutoString value; - if (NS_SUCCEEDED(GetResultValueAt(selectedIndex, true, value))) { + if (NS_SUCCEEDED(GetResultValueAt(selectedIndex, false, value))) { input->SetTextValue(value); input->SelectTextRange(value.Length(), value.Length()); } } else if (shouldComplete) { // We usually try to preserve the casing of what user has typed, but // if he wants to autocomplete, we will replace the value with the // actual autocomplete result. @@ -574,17 +574,17 @@ nsAutoCompleteController::HandleDelete(b // There are still rows in the popup, select the current index again. popup->SetSelectedIndex(index); // Complete to the new current value. bool shouldComplete = false; input->GetCompleteDefaultIndex(&shouldComplete); if (shouldComplete) { nsAutoString value; - if (NS_SUCCEEDED(GetResultValueAt(index, true, value))) { + if (NS_SUCCEEDED(GetResultValueAt(index, false, value))) { CompleteValue(value); } } // Invalidate the popup. popup->Invalidate(); } else { // Nothing left in the popup, clear any pending search timers and @@ -611,25 +611,25 @@ nsAutoCompleteController::GetResultAt(in *aResult = mResults[searchIndex]; NS_ENSURE_TRUE(*aResult, NS_ERROR_FAILURE); return NS_OK; } NS_IMETHODIMP nsAutoCompleteController::GetValueAt(int32_t aIndex, nsAString & _retval) { - GetResultLabelAt(aIndex, false, _retval); + GetResultLabelAt(aIndex, _retval); return NS_OK; } NS_IMETHODIMP nsAutoCompleteController::GetLabelAt(int32_t aIndex, nsAString & _retval) { - GetResultLabelAt(aIndex, false, _retval); + GetResultLabelAt(aIndex, _retval); return NS_OK; } NS_IMETHODIMP nsAutoCompleteController::GetCommentAt(int32_t aIndex, nsAString & _retval) { int32_t rowIndex; @@ -658,16 +658,28 @@ nsAutoCompleteController::GetImageAt(int nsIAutoCompleteResult* result; nsresult rv = GetResultAt(aIndex, &result, &rowIndex); NS_ENSURE_SUCCESS(rv, rv); return result->GetImageAt(rowIndex, _retval); } NS_IMETHODIMP +nsAutoCompleteController::GetFinalCompleteValueAt(int32_t aIndex, + nsAString & _retval) +{ + int32_t rowIndex; + nsIAutoCompleteResult* result; + nsresult rv = GetResultAt(aIndex, &result, &rowIndex); + NS_ENSURE_SUCCESS(rv, rv); + + return result->GetFinalCompleteValueAt(rowIndex, _retval); +} + +NS_IMETHODIMP nsAutoCompleteController::SetSearchString(const nsAString &aSearchString) { mSearchString = aSearchString; return NS_OK; } NS_IMETHODIMP nsAutoCompleteController::GetSearchString(nsAString &aSearchString) @@ -1176,19 +1188,24 @@ nsAutoCompleteController::EnterMatch(boo int32_t selectedIndex; popup->GetSelectedIndex(&selectedIndex); if (selectedIndex >= 0) { // If completeselectedindex is false or a row was selected from the popup, // enter it into the textbox. If completeselectedindex is true, or // EnterMatch was called via other means, for instance pressing Enter, // don't fill in the value as it will have already been filled in as - // needed. - if (!completeSelection || aIsPopupSelection) - GetResultValueAt(selectedIndex, true, value); + // needed, unless the final complete value differs. + nsAutoString finalValue, inputValue; + GetResultValueAt(selectedIndex, true, finalValue); + input->GetTextValue(inputValue); + if (!completeSelection || aIsPopupSelection || + !finalValue.Equals(inputValue)) { + value = finalValue; + } } else if (shouldComplete) { // We usually try to preserve the casing of what user has typed, but // if he wants to autocomplete, we will replace the value with the // actual autocomplete result. // The user wants explicitely to use that result, so this ensures // association of the result with the autocompleted text. nsAutoString defaultIndexValue; @@ -1201,17 +1218,17 @@ nsAutoCompleteController::EnterMatch(boo // we have to find the first default match and enter it instead for (uint32_t i = 0; i < mResults.Length(); ++i) { nsIAutoCompleteResult *result = mResults[i]; if (result) { int32_t defaultIndex; result->GetDefaultIndex(&defaultIndex); if (defaultIndex >= 0) { - result->GetValueAt(defaultIndex, value); + result->GetFinalCompleteValueAt(defaultIndex, value); break; } } } } } nsCOMPtr<nsIObserverService> obsSvc = @@ -1544,28 +1561,20 @@ nsAutoCompleteController::GetFinalDefaul result->GetValueAt(defaultIndex, _retval); nsAutoString inputValue; mInput->GetTextValue(inputValue); if (!_retval.Equals(inputValue, nsCaseInsensitiveStringComparator())) { return NS_ERROR_FAILURE; } - // Hack: For typeAheadResults allow the comment to be used as the final - // defaultComplete value if provided, otherwise fall back to the usual - // value. This allows to provide a different complete text when the user - // confirms the match. Don't rely on this for production code, since it's a - // temporary solution that needs a dedicated API (bug 754265). - bool isTypeAheadResult = false; - nsAutoString commentValue; - if (NS_SUCCEEDED(result->GetTypeAheadResult(&isTypeAheadResult)) && - isTypeAheadResult && - NS_SUCCEEDED(result->GetCommentAt(defaultIndex, commentValue)) && - !commentValue.IsEmpty()) { - _retval = commentValue; + nsAutoString finalCompleteValue; + rv = result->GetFinalCompleteValueAt(defaultIndex, finalCompleteValue); + if (NS_SUCCEEDED(rv)) { + _retval = finalCompleteValue; } MOZ_ASSERT(FindInReadable(inputValue, _retval, nsCaseInsensitiveStringComparator()), "Return value must include input value."); return NS_OK; } nsresult @@ -1620,48 +1629,53 @@ nsAutoCompleteController::CompleteValue( } mInput->SelectTextRange(mSearchStringLength, endSelect); return NS_OK; } nsresult -nsAutoCompleteController::GetResultLabelAt(int32_t aIndex, bool aValueOnly, nsAString & _retval) +nsAutoCompleteController::GetResultLabelAt(int32_t aIndex, nsAString & _retval) { - return GetResultValueLabelAt(aIndex, aValueOnly, false, _retval); + return GetResultValueLabelAt(aIndex, false, false, _retval); } nsresult -nsAutoCompleteController::GetResultValueAt(int32_t aIndex, bool aValueOnly, nsAString & _retval) +nsAutoCompleteController::GetResultValueAt(int32_t aIndex, bool aGetFinalValue, + nsAString & _retval) { - return GetResultValueLabelAt(aIndex, aValueOnly, true, _retval); + return GetResultValueLabelAt(aIndex, aGetFinalValue, true, _retval); } nsresult -nsAutoCompleteController::GetResultValueLabelAt(int32_t aIndex, bool aValueOnly, - bool aGetValue, nsAString & _retval) +nsAutoCompleteController::GetResultValueLabelAt(int32_t aIndex, + bool aGetFinalValue, + bool aGetValue, + nsAString & _retval) { NS_ENSURE_TRUE(aIndex >= 0 && (uint32_t) aIndex < mRowCount, NS_ERROR_ILLEGAL_VALUE); int32_t rowIndex; nsIAutoCompleteResult *result; nsresult rv = GetResultAt(aIndex, &result, &rowIndex); NS_ENSURE_SUCCESS(rv, rv); uint16_t searchResult; result->GetSearchResult(&searchResult); if (searchResult == nsIAutoCompleteResult::RESULT_FAILURE) { - if (aValueOnly) + if (aGetValue) return NS_ERROR_FAILURE; result->GetErrorDescription(_retval); } else if (searchResult == nsIAutoCompleteResult::RESULT_SUCCESS || searchResult == nsIAutoCompleteResult::RESULT_SUCCESS_ONGOING) { - if (aGetValue) + if (aGetFinalValue) + result->GetFinalCompleteValueAt(rowIndex, _retval); + else if (aGetValue) result->GetValueAt(rowIndex, _retval); else result->GetLabelAt(rowIndex, _retval); } return NS_OK; }
--- a/toolkit/components/autocomplete/nsAutoCompleteController.h +++ b/toolkit/components/autocomplete/nsAutoCompleteController.h @@ -54,22 +54,21 @@ protected: nsresult EnterMatch(bool aIsPopupSelection); nsresult RevertTextValue(); nsresult CompleteDefaultIndex(int32_t aResultIndex); nsresult CompleteValue(nsString &aValue); nsresult GetResultAt(int32_t aIndex, nsIAutoCompleteResult** aResult, int32_t* aRowIndex); - nsresult GetResultValueAt(int32_t aIndex, bool aValueOnly, + nsresult GetResultValueAt(int32_t aIndex, bool aGetFinalValue, nsAString & _retval); - nsresult GetResultLabelAt(int32_t aIndex, bool aValueOnly, - nsAString & _retval); + nsresult GetResultLabelAt(int32_t aIndex, nsAString & _retval); private: - nsresult GetResultValueLabelAt(int32_t aIndex, bool aValueOnly, + nsresult GetResultValueLabelAt(int32_t aIndex, bool aGetFinalValue, bool aGetValue, nsAString & _retval); protected: /** * Gets and validates the defaultComplete result and the relative * defaultIndex value. * * @param aResultIndex
--- a/toolkit/components/autocomplete/nsAutoCompleteSimpleResult.cpp +++ b/toolkit/components/autocomplete/nsAutoCompleteSimpleResult.cpp @@ -85,17 +85,18 @@ nsAutoCompleteSimpleResult::SetTypeAhead mTypeAheadResult = aTypeAheadResult; return NS_OK; } NS_IMETHODIMP nsAutoCompleteSimpleResult::AppendMatch(const nsAString& aValue, const nsAString& aComment, const nsAString& aImage, - const nsAString& aStyle) + const nsAString& aStyle, + const nsAString& aFinalCompleteValue) { CheckInvariants(); if (! mValues.AppendElement(aValue)) return NS_ERROR_OUT_OF_MEMORY; if (! mComments.AppendElement(aComment)) { mValues.RemoveElementAt(mValues.Length() - 1); return NS_ERROR_OUT_OF_MEMORY; @@ -106,16 +107,23 @@ nsAutoCompleteSimpleResult::AppendMatch( return NS_ERROR_OUT_OF_MEMORY; } if (! mStyles.AppendElement(aStyle)) { mValues.RemoveElementAt(mValues.Length() - 1); mComments.RemoveElementAt(mComments.Length() - 1); mImages.RemoveElementAt(mImages.Length() - 1); return NS_ERROR_OUT_OF_MEMORY; } + if (!mFinalCompleteValues.AppendElement(aFinalCompleteValue)) { + mValues.RemoveElementAt(mValues.Length() - 1); + mComments.RemoveElementAt(mComments.Length() - 1); + mImages.RemoveElementAt(mImages.Length() - 1); + mStyles.RemoveElementAt(mStyles.Length() - 1); + return NS_ERROR_OUT_OF_MEMORY; + } return NS_OK; } NS_IMETHODIMP nsAutoCompleteSimpleResult::GetMatchCount(uint32_t *aMatchCount) { CheckInvariants(); @@ -166,16 +174,29 @@ nsAutoCompleteSimpleResult::GetStyleAt(i NS_ENSURE_TRUE(aIndex >= 0 && aIndex < int32_t(mStyles.Length()), NS_ERROR_ILLEGAL_VALUE); CheckInvariants(); _retval = mStyles[aIndex]; return NS_OK; } NS_IMETHODIMP +nsAutoCompleteSimpleResult::GetFinalCompleteValueAt(int32_t aIndex, + nsAString& _retval) +{ + NS_ENSURE_TRUE(aIndex >= 0 && aIndex < int32_t(mFinalCompleteValues.Length()), + NS_ERROR_ILLEGAL_VALUE); + CheckInvariants(); + _retval = mFinalCompleteValues[aIndex]; + if (_retval.Length() == 0) + _retval = mValues[aIndex]; + return NS_OK; +} + +NS_IMETHODIMP nsAutoCompleteSimpleResult::SetListener(nsIAutoCompleteSimpleResultListener* aListener) { mListener = aListener; return NS_OK; } NS_IMETHODIMP nsAutoCompleteSimpleResult::RemoveValueAt(int32_t aRowIndex, @@ -184,14 +205,15 @@ nsAutoCompleteSimpleResult::RemoveValueA NS_ENSURE_TRUE(aRowIndex >= 0 && aRowIndex < int32_t(mValues.Length()), NS_ERROR_ILLEGAL_VALUE); nsAutoString removedValue(mValues[aRowIndex]); mValues.RemoveElementAt(aRowIndex); mComments.RemoveElementAt(aRowIndex); mImages.RemoveElementAt(aRowIndex); mStyles.RemoveElementAt(aRowIndex); + mFinalCompleteValues.RemoveElementAt(aRowIndex); if (mListener) mListener->OnValueRemoved(this, removedValue, aRemoveFromDb); return NS_OK; }
--- a/toolkit/components/autocomplete/nsAutoCompleteSimpleResult.h +++ b/toolkit/components/autocomplete/nsAutoCompleteSimpleResult.h @@ -16,16 +16,17 @@ class nsAutoCompleteSimpleResult MOZ_FINAL : public nsIAutoCompleteSimpleResult { public: nsAutoCompleteSimpleResult(); inline void CheckInvariants() { NS_ASSERTION(mValues.Length() == mComments.Length(), "Arrays out of sync"); NS_ASSERTION(mValues.Length() == mImages.Length(), "Arrays out of sync"); NS_ASSERTION(mValues.Length() == mStyles.Length(), "Arrays out of sync"); + NS_ASSERTION(mValues.Length() == mFinalCompleteValues.Length(), "Arrays out of sync"); } NS_DECL_ISUPPORTS NS_DECL_NSIAUTOCOMPLETERESULT NS_DECL_NSIAUTOCOMPLETESIMPLERESULT private: ~nsAutoCompleteSimpleResult() {} @@ -34,16 +35,17 @@ protected: // What we really want is an array of structs with value/comment/image/style contents. // But then we'd either have to use COM or manage object lifetimes ourselves. // Having four arrays of string simplifies this, but is stupid. nsTArray<nsString> mValues; nsTArray<nsString> mComments; nsTArray<nsString> mImages; nsTArray<nsString> mStyles; + nsTArray<nsString> mFinalCompleteValues; nsString mSearchString; nsString mErrorDescription; int32_t mDefaultIndex; uint32_t mSearchResult; bool mTypeAheadResult;
--- a/toolkit/components/autocomplete/nsIAutoCompleteController.idl +++ b/toolkit/components/autocomplete/nsIAutoCompleteController.idl @@ -1,17 +1,17 @@ /* 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 "nsISupports.idl" interface nsIAutoCompleteInput; -[scriptable, uuid(dd2c4489-e4bd-4702-86bc-e1691744e556)] +[scriptable, uuid(ff9f8465-204a-47a6-b3c9-0628b3856684)] interface nsIAutoCompleteController : nsISupports { /* * Possible values for the searchStatus attribute */ const unsigned short STATUS_NONE = 1; const unsigned short STATUS_SEARCHING = 2; const unsigned short STATUS_COMPLETE_NO_MATCH = 3; @@ -130,12 +130,18 @@ interface nsIAutoCompleteController : ns AString getStyleAt(in long index); /* * Get the url of the image of the result at a given index in the last completed search */ AString getImageAt(in long index); /* + * For the last completed search, get the final value that should be completed + * when the user confirms the match at the given index + */ + AString getFinalCompleteValueAt(in long index); + + /* * Get / set the current search string. Note, setting will not start searching */ attribute AString searchString; };
--- a/toolkit/components/autocomplete/nsIAutoCompleteResult.idl +++ b/toolkit/components/autocomplete/nsIAutoCompleteResult.idl @@ -1,15 +1,15 @@ /* 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 "nsISupports.idl" -[scriptable, uuid(7b43fad1-c735-4b45-9383-c3f057fed20d)] +[scriptable, uuid(9203c031-c4e7-4537-a4ec-81443d623d5a)] interface nsIAutoCompleteResult : nsISupports { /** * Possible values for the searchResult attribute */ const unsigned short RESULT_IGNORED = 1; /* indicates invalid searchString */ const unsigned short RESULT_FAILURE = 2; /* indicates failure */ const unsigned short RESULT_NOMATCH = 3; /* indicates success with no matches @@ -77,14 +77,20 @@ interface nsIAutoCompleteResult : nsISup AString getStyleAt(in long index); /** * Get the image of the result at the given index */ AString getImageAt(in long index); /** + * Get the final value that should be completed when the user confirms + * the match at the given index. + */ + AString getFinalCompleteValueAt(in long index); + + /** * Remove the value at the given index from the autocomplete results. * If removeFromDb is set to true, the value should be removed from * persistent storage as well. */ void removeValueAt(in long rowIndex, in boolean removeFromDb); };
--- a/toolkit/components/autocomplete/nsIAutoCompleteSimpleResult.idl +++ b/toolkit/components/autocomplete/nsIAutoCompleteSimpleResult.idl @@ -9,17 +9,17 @@ interface nsIAutoCompleteSimpleResultLis /** * This class implements nsIAutoCompleteResult and provides simple methods * for setting the value and result items. It can be used whenever some basic * auto complete results are needed that can be pre-generated and filled into * an array. */ -[scriptable, uuid(c738dc26-aa71-4561-a3fd-b5a0e4aa80d2)] +[scriptable, uuid(fe8802f9-c2b7-4141-8e5b-280df3f62251)] interface nsIAutoCompleteSimpleResult : nsIAutoCompleteResult { /** * A writer for the readonly attribute 'searchString' which should contain * the string that the user typed. */ void setSearchString(in AString aSearchString); @@ -43,22 +43,35 @@ interface nsIAutoCompleteSimpleResult : /** * A writer for the readonly attribute 'typeAheadResult', typically set * because a result is only intended for type-ahead completion. */ void setTypeAheadResult(in boolean aHidden); /** - * Appends a result item consisting of the given value, comment, image and style. - * This is how you add results. Note: image and style are optional. + * Appends a match consisting of the given value, comment, image, style and + * the value to use for defaultIndex completion. + * @param aValue + * The value to autocomplete to + * @param aComment + * Comment shown in the autocomplete widget to describe this match + * @param aImage + * Image shown in the autocomplete widget for this match. + * @param aStyle + * Describes how to style the match in the autocomplete widget + * @param aFinalCompleteValue + * Value used when the user confirms selecting this match. If not + * provided, aValue will be used. */ - void appendMatch(in AString aValue, in AString aComment, - [optional] in AString aImage, - [optional] in AString aStyle); + void appendMatch(in AString aValue, + in AString aComment, + [optional] in AString aImage, + [optional] in AString aStyle, + [optional] in AString aFinalCompleteValue); /** * Sets a listener for changes in the result. */ void setListener(in nsIAutoCompleteSimpleResultListener aListener); }; [scriptable, uuid(004efdc5-1989-4874-8a7a-345bf2fa33af)]
--- a/toolkit/components/autocomplete/tests/unit/head_autocomplete.js +++ b/toolkit/components/autocomplete/tests/unit/head_autocomplete.js @@ -73,17 +73,18 @@ function AutoCompleteResultBase(aValues) this._values = aValues; } AutoCompleteResultBase.prototype = { // Arrays _values: null, _comments: [], _styles: [], - + _finalCompleteValues: [], + searchString: "", searchResult: null, defaultIndex: -1, _typeAheadResult: false, get typeAheadResult() { return this._typeAheadResult; @@ -108,16 +109,20 @@ AutoCompleteResultBase.prototype = { getStyleAt: function(aIndex) { return this._styles[aIndex]; }, getImageAt: function(aIndex) { return ""; }, + getFinalCompleteValueAt: function(aIndex) { + return this._finalCompleteValues[aIndex] || this._values[aIndex]; + }, + removeValueAt: function (aRowIndex, aRemoveFromDb) {}, // nsISupports implementation QueryInterface: XPCOMUtils.generateQI([Ci.nsIAutoCompleteResult]) } /** * nsIAutoCompleteSearch implementation that always returns
--- a/toolkit/components/autocomplete/tests/unit/test_378079.js +++ b/toolkit/components/autocomplete/tests/unit/test_378079.js @@ -118,16 +118,20 @@ AutoCompleteResult.prototype = { getStyleAt: function(aIndex) { return this._styles[aIndex]; }, getImageAt: function(aIndex) { return ""; }, + getFinalCompleteValueAt: function(aIndex) { + return this.getValueAt(aIndex); + }, + removeValueAt: function (aRowIndex, aRemoveFromDb) {}, // nsISupports implementation QueryInterface: function(iid) { if (iid.equals(Ci.nsISupports) || iid.equals(Ci.nsIAutoCompleteResult)) return this;
--- a/toolkit/components/autocomplete/tests/unit/test_393191.js +++ b/toolkit/components/autocomplete/tests/unit/test_393191.js @@ -117,16 +117,20 @@ AutoCompleteResult.prototype = { getStyleAt: function(aIndex) { return this._styles[aIndex]; }, getImageAt: function(aIndex) { return ""; }, + getFinalCompleteValueAt: function(aIndex) { + return this.getValueAt(aIndex); + }, + removeValueAt: function (aRowIndex, aRemoveFromDb) {}, // nsISupports implementation QueryInterface: function(iid) { if (iid.equals(Ci.nsISupports) || iid.equals(Ci.nsIAutoCompleteResult)) return this;
--- a/toolkit/components/autocomplete/tests/unit/test_440866.js +++ b/toolkit/components/autocomplete/tests/unit/test_440866.js @@ -116,16 +116,20 @@ AutoCompleteResult.prototype = { getStyleAt: function(aIndex) { return this._styles[aIndex]; }, getImageAt: function(aIndex) { return ""; }, + getFinalCompleteValueAt: function(aIndex) { + return this.getValueAt(aIndex); + }, + removeValueAt: function (aRowIndex, aRemoveFromDb) {}, // nsISupports implementation QueryInterface: function(iid) { if (iid.equals(Ci.nsISupports) || iid.equals(Ci.nsIAutoCompleteResult)) return this;
--- a/toolkit/components/autocomplete/tests/unit/test_autocomplete_multiple.js +++ b/toolkit/components/autocomplete/tests/unit/test_autocomplete_multiple.js @@ -105,16 +105,20 @@ AutoCompleteResult.prototype = { getStyleAt: function(aIndex) { return this._styles[aIndex]; }, getImageAt: function(aIndex) { return ""; }, + getFinalCompleteValueAt: function(aIndex) { + return this.getValueAt(aIndex); + }, + removeValueAt: function (aRowIndex, aRemoveFromDb) {}, // nsISupports implementation QueryInterface: function(iid) { if (iid.equals(Ci.nsISupports) || iid.equals(Ci.nsIAutoCompleteResult)) return this;
new file mode 100644 --- /dev/null +++ b/toolkit/components/autocomplete/tests/unit/test_finalCompleteValue.js @@ -0,0 +1,54 @@ +/* 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/. */ + +function AutoCompleteResult(aValues, aFinalCompleteValues) { + this._values = aValues; + this._finalCompleteValues = aFinalCompleteValues; +} +AutoCompleteResult.prototype = Object.create(AutoCompleteResultBase.prototype); + +function AutoCompleteInput(aSearches) { + this.searches = aSearches; + this.popup.selectedIndex = 0; +} +AutoCompleteInput.prototype = Object.create(AutoCompleteInputBase.prototype); + +function run_test() { + run_next_test(); +} + +add_test(function test_handleEnter() { + doSearch("moz", "mozilla.com", "http://www.mozilla.com", function(aController) { + do_check_eq(aController.input.textValue, "moz"); + do_check_eq(aController.getFinalCompleteValueAt(0), "http://www.mozilla.com"); + aController.handleEnter(false); + do_check_eq(aController.input.textValue, "http://www.mozilla.com"); + }); +}); + +function doSearch(aSearchString, aResultValue, aFinalCompleteValue, aOnCompleteCallback) { + let search = new AutoCompleteSearchBase( + "search", + new AutoCompleteResult([ aResultValue ], [ aFinalCompleteValue ]) + ); + registerAutoCompleteSearch(search); + + let controller = Cc["@mozilla.org/autocomplete/controller;1"]. + getService(Ci.nsIAutoCompleteController); + + // Make an AutoCompleteInput that uses our searches and confirms results. + let input = new AutoCompleteInput([ search.name ]); + input.textValue = aSearchString; + + controller.input = input; + controller.startSearch(aSearchString); + + input.onSearchComplete = function onSearchComplete() { + aOnCompleteCallback(controller); + + // Clean up. + unregisterAutoCompleteSearch(search); + run_next_test(); + }; +}
new file mode 100644 --- /dev/null +++ b/toolkit/components/autocomplete/tests/unit/test_finalCompleteValue_forceComplete.js @@ -0,0 +1,56 @@ +/* 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/. */ + +function AutoCompleteResult(aValues, aFinalCompleteValues) { + this._values = aValues; + this._finalCompleteValues = aFinalCompleteValues; + this.defaultIndex = 0; +} +AutoCompleteResult.prototype = Object.create(AutoCompleteResultBase.prototype); + +function AutoCompleteInput(aSearches) { + this.searches = aSearches; + this.popup.selectedIndex = -1; +} +AutoCompleteInput.prototype = Object.create(AutoCompleteInputBase.prototype); + +function run_test() { + run_next_test(); +} + +add_test(function test_handleEnter() { + doSearch("", "mozilla.com", "http://www.mozilla.com", function(aController) { + do_check_eq(aController.input.textValue, ""); + do_check_eq(aController.getFinalCompleteValueAt(0), "http://www.mozilla.com"); + aController.input.forceComplete = true; + aController.handleEnter(false); + do_check_eq(aController.input.textValue, "http://www.mozilla.com"); + }); +}); + +function doSearch(aSearchString, aResultValue, aFinalCompleteValue, aOnCompleteCallback) { + let search = new AutoCompleteSearchBase( + "search", + new AutoCompleteResult([ aResultValue ], [ aFinalCompleteValue ]) + ); + registerAutoCompleteSearch(search); + + let controller = Cc["@mozilla.org/autocomplete/controller;1"]. + getService(Ci.nsIAutoCompleteController); + + // Make an AutoCompleteInput that uses our searches and confirms results. + let input = new AutoCompleteInput([ search.name ]); + input.textValue = aSearchString; + + controller.input = input; + controller.startSearch(aSearchString); + + input.onSearchComplete = function onSearchComplete() { + aOnCompleteCallback(controller); + + // Clean up. + unregisterAutoCompleteSearch(search); + run_next_test(); + }; +}
--- a/toolkit/components/autocomplete/tests/unit/test_finalDefaultCompleteValue.js +++ b/toolkit/components/autocomplete/tests/unit/test_finalDefaultCompleteValue.js @@ -1,17 +1,16 @@ /* 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/. */ -function AutoCompleteResult(aValues, aComments) { +function AutoCompleteResult(aValues, aFinalCompleteValues) { this._values = aValues; - this._comments = aComments; + this._finalCompleteValues = aFinalCompleteValues; this.defaultIndex = 0; - this._typeAheadResult = true; } AutoCompleteResult.prototype = Object.create(AutoCompleteResultBase.prototype); function AutoCompleteInput(aSearches) { this.searches = aSearches; this.popup.selectedIndex = -1; this.completeDefaultIndex = true; } @@ -32,20 +31,20 @@ add_test(function test_keyNavigation() { add_test(function test_handleEnter() { doSearch("moz", "mozilla.com", "http://www.mozilla.com", function(aController) { do_check_eq(aController.input.textValue, "mozilla.com"); aController.handleEnter(false); do_check_eq(aController.input.textValue, "http://www.mozilla.com"); }); }); -function doSearch(aSearchString, aResultValue, aCommentValue, aOnCompleteCallback) { +function doSearch(aSearchString, aResultValue, aFinalCompleteValue, aOnCompleteCallback) { let search = new AutoCompleteSearchBase( "search", - new AutoCompleteResult([ aResultValue ], [ aCommentValue ], 0) + new AutoCompleteResult([ aResultValue ], [ aFinalCompleteValue ]) ); registerAutoCompleteSearch(search); let controller = Cc["@mozilla.org/autocomplete/controller;1"]. getService(Ci.nsIAutoCompleteController); // Make an AutoCompleteInput that uses our searches and confirms results. let input = new AutoCompleteInput([ search.name ]);
--- a/toolkit/components/autocomplete/tests/unit/test_popupSelectionVsDefaultCompleteValue.js +++ b/toolkit/components/autocomplete/tests/unit/test_popupSelectionVsDefaultCompleteValue.js @@ -1,23 +1,22 @@ /* 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/. */ -function AutoCompleteTypeAheadResult(aValues, aComments) { +function AutoCompleteTypeAheadResult(aValues, aFinalCompleteValues) { this._values = aValues; - this._comments = aComments; + this._finalCompleteValues = aFinalCompleteValues; this.defaultIndex = 0; this._typeAheadResult = true; } AutoCompleteTypeAheadResult.prototype = Object.create(AutoCompleteResultBase.prototype); -function AutoCompleteResult(aValues, aComments) { +function AutoCompleteResult(aValues) { this._values = aValues; - this._comments = aComments; } AutoCompleteResult.prototype = Object.create(AutoCompleteResultBase.prototype); function AutoCompleteInput(aSearches) { this.searches = aSearches; this.popupOpen = true; this.completeDefaultIndex = true; this.completeSelectedIndex = true; @@ -40,17 +39,17 @@ function doSearch(aSearchString, aOnComp let typeAheadSearch = new AutoCompleteSearchBase( "typeAheadSearch", new AutoCompleteTypeAheadResult([ "mozilla.com" ], [ "http://www.mozilla.com" ]) ); registerAutoCompleteSearch(typeAheadSearch); let search = new AutoCompleteSearchBase( "search", - new AutoCompleteResult([ "mozilla.org" ], [ "http://www.mozilla.org" ]) + new AutoCompleteResult([ "mozilla.org" ]) ); registerAutoCompleteSearch(search); let controller = Cc["@mozilla.org/autocomplete/controller;1"]. getService(Ci.nsIAutoCompleteController); // Make an AutoCompleteInput that uses our searches and confirms results. let input = new AutoCompleteInput([ typeAheadSearch.name, search.name ]);
--- a/toolkit/components/autocomplete/tests/unit/test_previousResult.js +++ b/toolkit/components/autocomplete/tests/unit/test_previousResult.js @@ -116,16 +116,20 @@ AutoCompleteResult.prototype = { getStyleAt: function(aIndex) { return this._styles[aIndex]; }, getImageAt: function(aIndex) { return ""; }, + getFinalCompleteValueAt: function(aIndex) { + return this.getValueAt(aIndex); + }, + removeValueAt: function (aRowIndex, aRemoveFromDb) {}, // nsISupports implementation QueryInterface: function(iid) { if (iid.equals(Ci.nsISupports) || iid.equals(Ci.nsIAutoCompleteResult)) return this;
--- a/toolkit/components/autocomplete/tests/unit/xpcshell.ini +++ b/toolkit/components/autocomplete/tests/unit/xpcshell.ini @@ -6,14 +6,16 @@ tail = [test_378079.js] [test_393191.js] [test_440866.js] [test_463023.js] [test_660156.js] [test_autocomplete_multiple.js] [test_badDefaultIndex.js] [test_completeDefaultIndex_casing.js] +[test_finalCompleteValue.js] +[test_finalCompleteValue_forceComplete.js] [test_finalDefaultCompleteValue.js] [test_hiddenResult.js] [test_immediate_search.js] [test_popupSelectionVsDefaultCompleteValue.js] [test_previousResult.js] [test_stopSearch.js]
--- a/toolkit/components/filepicker/nsFileView.cpp +++ b/toolkit/components/filepicker/nsFileView.cpp @@ -167,16 +167,21 @@ NS_IMETHODIMP nsFileResult::GetStyleAt(i return NS_OK; } NS_IMETHODIMP nsFileResult::GetImageAt(int32_t index, nsAString & aImage) { aImage.Truncate(); return NS_OK; } +NS_IMETHODIMP nsFileResult::GetFinalCompleteValueAt(int32_t index, + nsAString & aValue) +{ + return GetValueAt(index, aValue); +} NS_IMETHODIMP nsFileResult::RemoveValueAt(int32_t rowIndex, bool removeFromDb) { return NS_OK; } class nsFileComplete MOZ_FINAL : public nsIAutoCompleteSearch {
--- a/toolkit/components/passwordmgr/nsLoginManager.js +++ b/toolkit/components/passwordmgr/nsLoginManager.js @@ -606,16 +606,20 @@ UserAutoCompleteResult.prototype = { getStyleAt : function (index) { return ""; }, getImageAt : function (index) { return ""; }, + getFinalCompleteValueAt : function (index) { + return this.getValueAt(index); + }, + removeValueAt : function (index, removeFromDB) { if (index < 0 || index >= this.logins.length) throw "Index out of range."; var [removedLogin] = this.logins.splice(index, 1); this.matchCount--; if (this.defaultIndex > this.logins.length)
--- a/toolkit/components/places/PlacesUtils.jsm +++ b/toolkit/components/places/PlacesUtils.jsm @@ -151,73 +151,58 @@ this.PlacesUtils = { /** * Determines whether or not a ResultNode is a Bookmark folder. * @param aNode * A result node * @returns true if the node is a Bookmark folder, false otherwise */ nodeIsFolder: function PU_nodeIsFolder(aNode) { - if (!(aNode instanceof Ci.nsINavHistoryResultNode)) { - throw new Error("Invalid Places node"); - } return (aNode.type == Ci.nsINavHistoryResultNode.RESULT_TYPE_FOLDER || aNode.type == Ci.nsINavHistoryResultNode.RESULT_TYPE_FOLDER_SHORTCUT); }, /** * Determines whether or not a ResultNode represents a bookmarked URI. * @param aNode * A result node * @returns true if the node represents a bookmarked URI, false otherwise */ nodeIsBookmark: function PU_nodeIsBookmark(aNode) { - if (!(aNode instanceof Ci.nsINavHistoryResultNode)) { - throw new Error("Invalid Places node"); - } return aNode.type == Ci.nsINavHistoryResultNode.RESULT_TYPE_URI && aNode.itemId != -1; }, /** * Determines whether or not a ResultNode is a Bookmark separator. * @param aNode * A result node * @returns true if the node is a Bookmark separator, false otherwise */ nodeIsSeparator: function PU_nodeIsSeparator(aNode) { - if (!(aNode instanceof Ci.nsINavHistoryResultNode)) { - throw new Error("Invalid Places node"); - } return aNode.type == Ci.nsINavHistoryResultNode.RESULT_TYPE_SEPARATOR; }, /** * Determines whether or not a ResultNode is a URL item. * @param aNode * A result node * @returns true if the node is a URL item, false otherwise */ nodeIsURI: function PU_nodeIsURI(aNode) { - if (!(aNode instanceof Ci.nsINavHistoryResultNode)) { - throw new Error("Invalid Places node"); - } return aNode.type == Ci.nsINavHistoryResultNode.RESULT_TYPE_URI; }, /** * Determines whether or not a ResultNode is a Query item. * @param aNode * A result node * @returns true if the node is a Query item, false otherwise */ nodeIsQuery: function PU_nodeIsQuery(aNode) { - if (!(aNode instanceof Ci.nsINavHistoryResultNode)) { - throw new Error("Invalid Places node"); - } return aNode.type == Ci.nsINavHistoryResultNode.RESULT_TYPE_QUERY; }, /** * Generator for a node's ancestors. * @param aNode * A result node */ @@ -367,19 +352,16 @@ this.PlacesUtils = { /** * Determines if a node is read only (children cannot be inserted, sometimes * they cannot be removed depending on the circumstance) * @param aNode * A result node * @returns true if the node is readonly, false otherwise */ nodeIsReadOnly: function PU_nodeIsReadOnly(aNode) { - if (!(aNode instanceof Ci.nsINavHistoryResultNode)) { - throw new Error("Invalid Places node"); - } let itemId = aNode.itemId; if (itemId != -1) { return this._readOnly.indexOf(itemId) != -1; } if (this.nodeIsQuery(aNode) && asQuery(aNode).queryOptions.resultType != Ci.nsINavHistoryQueryOptions.RESULTS_AS_TAG_CONTENTS) @@ -389,71 +371,59 @@ this.PlacesUtils = { /** * Determines whether or not a ResultNode is a host container. * @param aNode * A result node * @returns true if the node is a host container, false otherwise */ nodeIsHost: function PU_nodeIsHost(aNode) { - if (!(aNode instanceof Ci.nsINavHistoryResultNode)) { - throw new Error("Invalid Places node"); - } return aNode.type == Ci.nsINavHistoryResultNode.RESULT_TYPE_QUERY && aNode.parent && asQuery(aNode.parent).queryOptions.resultType == Ci.nsINavHistoryQueryOptions.RESULTS_AS_SITE_QUERY; }, /** * Determines whether or not a ResultNode is a day container. * @param node * A NavHistoryResultNode * @returns true if the node is a day container, false otherwise */ nodeIsDay: function PU_nodeIsDay(aNode) { - if (!(aNode instanceof Ci.nsINavHistoryResultNode)) { - throw new Error("Invalid Places node"); - } var resultType; return aNode.type == Ci.nsINavHistoryResultNode.RESULT_TYPE_QUERY && aNode.parent && ((resultType = asQuery(aNode.parent).queryOptions.resultType) == Ci.nsINavHistoryQueryOptions.RESULTS_AS_DATE_QUERY || resultType == Ci.nsINavHistoryQueryOptions.RESULTS_AS_DATE_SITE_QUERY); }, /** * Determines whether or not a result-node is a tag container. * @param aNode * A result-node * @returns true if the node is a tag container, false otherwise */ nodeIsTagQuery: function PU_nodeIsTagQuery(aNode) { - if (!(aNode instanceof Ci.nsINavHistoryResultNode)) { - throw new Error("Invalid Places node"); - } return aNode.type == Ci.nsINavHistoryResultNode.RESULT_TYPE_QUERY && asQuery(aNode).queryOptions.resultType == Ci.nsINavHistoryQueryOptions.RESULTS_AS_TAG_CONTENTS; }, /** * Determines whether or not a ResultNode is a container. * @param aNode * A result node * @returns true if the node is a container item, false otherwise */ containerTypes: [Ci.nsINavHistoryResultNode.RESULT_TYPE_FOLDER, Ci.nsINavHistoryResultNode.RESULT_TYPE_FOLDER_SHORTCUT, Ci.nsINavHistoryResultNode.RESULT_TYPE_QUERY], nodeIsContainer: function PU_nodeIsContainer(aNode) { - if (!(aNode instanceof Ci.nsINavHistoryResultNode)) { - throw new Error("Invalid Places node"); - } return this.containerTypes.indexOf(aNode.type) != -1; }, /** * Determines whether or not a ResultNode is an history related container. * @param node * A result node * @returns true if the node is an history related container, false otherwise
--- a/toolkit/components/places/nsPlacesAutoComplete.js +++ b/toolkit/components/places/nsPlacesAutoComplete.js @@ -1399,19 +1399,17 @@ urlInlineComplete.prototype = { let untrimmedHost = row.getResultByIndex(1); // If the untrimmed value doesn't preserve the user's input just // ignore it and complete to the found host. if (untrimmedHost && !untrimmedHost.toLowerCase().contains(ac._originalSearchString.toLowerCase())) { untrimmedHost = null; } - // TODO (bug 754265): this is a temporary solution introduced while - // waiting for a propert dedicated API. - ac._result.appendMatch(ac._strippedPrefix + trimmedHost, untrimmedHost); + ac._result.appendMatch(ac._strippedPrefix + trimmedHost, "", "", "", untrimmedHost); // handleCompletion() will cause the result listener to be called, and // will display the result in the UI. }, handleError: function (aError) { Components.utils.reportError( "URL Inline Complete: An async statement encountered an " + @@ -1475,19 +1473,17 @@ urlInlineComplete.prototype = { // If the untrimmed value doesn't preserve the user's input just // ignore it and complete to the found url. let untrimmedURL = prefix + url; if (untrimmedURL && !untrimmedURL.toLowerCase().contains(ac._originalSearchString.toLowerCase())) { untrimmedURL = null; } - // TODO (bug 754265): this is a temporary solution introduced while - // waiting for a propert dedicated API. - ac._result.appendMatch(ac._strippedPrefix + url, untrimmedURL); + ac._result.appendMatch(ac._strippedPrefix + url, "", "", "", untrimmedURL); // handleCompletion() will cause the result listener to be called, and // will display the result in the UI. }, handleError: function(aError) { Components.utils.reportError( "URL Inline Complete: An async statement encountered an " +
--- a/toolkit/components/places/nsTaggingService.js +++ b/toolkit/components/places/nsTaggingService.js @@ -538,16 +538,23 @@ TagAutoCompleteResult.prototype = { /** * Get the image for the result at the given index */ getImageAt: function PTACR_getImageAt(index) { return null; }, /** + * Get the image for the result at the given index + */ + getFinalCompleteValueAt: function PTACR_getFinalCompleteValueAt(index) { + return this.getValueAt(index); + }, + + /** * Remove the value at the given index from the autocomplete results. * If removeFromDb is set to true, the value should be removed from * persistent storage as well. */ removeValueAt: function PTACR_removeValueAt(index, removeFromDb) { this._results.splice(index, 1); this._comments.splice(index, 1); },
deleted file mode 100644 --- a/toolkit/components/places/tests/unit/test_PlacesUtils_nodeIsXXX_invalidArg.js +++ /dev/null @@ -1,24 +0,0 @@ - -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -function run_test() { - let nodeIsMethods = [ - "nodeIsFolder", - "nodeIsBookmark", - "nodeIsSeparator", - "nodeIsURI", - "nodeIsQuery", - "nodeIsReadOnly", - "nodeIsHost", - "nodeIsDay", - "nodeIsTagQuery", - "nodeIsContainer", - "nodeIsHistoryContainer", - "nodeIsQuery" - ]; - for (let methodName of nodeIsMethods) { - Assert.throws(() => PlacesUtils[methodName](true), /Invalid Places node/); - } -} -
--- a/toolkit/components/places/tests/unit/xpcshell.ini +++ b/toolkit/components/places/tests/unit/xpcshell.ini @@ -112,17 +112,16 @@ fail-if = os == "android" skip-if = true [test_null_interfaces.js] [test_onItemChanged_tags.js] [test_pageGuid_bookmarkGuid.js] [test_frecency_observers.js] [test_placeURIs.js] [test_PlacesUtils_asyncGetBookmarkIds.js] [test_PlacesUtils_lazyobservers.js] -[test_PlacesUtils_nodeIsXXX_invalidArg.js] [test_placesTxn.js] [test_preventive_maintenance.js] # Bug 676989: test hangs consistently on Android skip-if = os == "android" [test_preventive_maintenance_checkAndFixDatabase.js] # Bug 676989: test hangs consistently on Android skip-if = os == "android" [test_preventive_maintenance_runTasks.js]
--- a/toolkit/components/satchel/nsFormAutoComplete.js +++ b/toolkit/components/satchel/nsFormAutoComplete.js @@ -471,16 +471,20 @@ FormAutoCompleteResult.prototype = { return ""; }, getImageAt : function (index) { this._checkIndexBounds(index); return ""; }, + getFinalCompleteValueAt : function (index) { + return this.getValueAt(index); + }, + removeValueAt : function (index, removeFromDB) { this._checkIndexBounds(index); let [removedEntry] = this.entries.splice(index, 1); if (removeFromDB) { this.formHistory.update({ op: "remove", fieldname: this.fieldName,
--- a/toolkit/components/satchel/nsFormAutoCompleteResult.jsm +++ b/toolkit/components/satchel/nsFormAutoCompleteResult.jsm @@ -147,16 +147,25 @@ FormAutoCompleteResult.prototype = { * @return the image url at the specified index */ getImageAt: function(index) { this._checkIndexBounds(index); return ""; }, /** + * Retrieves a result + * @param index the index of the result requested + * @return the result at the specified index + */ + getFinalCompleteValueAt: function(index) { + return this.getValueAt(index); + }, + + /** * Removes a result from the resultset * @param index the index of the result to remove */ removeValueAt: function(index, removeFromDatabase) { this._checkIndexBounds(index); // Forward the removeValueAt call to the underlying result if we have one // Note: this assumes that the form history results were added to the top // of our arrays.
--- a/toolkit/content/tests/chrome/test_autocomplete2.xul +++ b/toolkit/content/tests/chrome/test_autocomplete2.xul @@ -39,16 +39,17 @@ nsAutoCompleteSimpleResult.prototype = { searchResult: ACR.RESULT_FAILURE, defaultIndex: -1, errorDescription: null, matchCount: 0, getValueAt: function() { return this._param; }, getCommentAt: function() { return null; }, getStyleAt: function() { return null; }, getImageAt: function() { return null; }, + getFinalCompleteValueAt: function() { return this.getValueAt(); }, getLabelAt: function() { return null; }, removeValueAt: function() {} }; // A basic autocomplete implementation that either returns one result or none var autoCompleteSimpleID = Components.ID("0a2afbdb-f30e-47d1-9cb1-0cd160240aca"); var autoCompleteSimpleName = "@mozilla.org/autocomplete/search;1?name=simple" var autoCompleteSimple = {
--- a/toolkit/content/tests/chrome/test_autocomplete3.xul +++ b/toolkit/content/tests/chrome/test_autocomplete3.xul @@ -39,16 +39,17 @@ nsAutoCompleteSimpleResult.prototype = { searchResult: ACR.RESULT_FAILURE, defaultIndex: 0, errorDescription: null, matchCount: 0, getValueAt: function() { return this._param; }, getCommentAt: function() { return null; }, getStyleAt: function() { return null; }, getImageAt: function() { return null; }, + getFinalCompleteValueAt: function() { return this.getValueAt(); }, getLabelAt: function() { return null; }, removeValueAt: function() {} }; // A basic autocomplete implementation that either returns one result or none var autoCompleteSimpleID = Components.ID("0a2afbdb-f30e-47d1-9cb1-0cd160240aca"); var autoCompleteSimpleName = "@mozilla.org/autocomplete/search;1?name=simple" var autoCompleteSimple = {
--- a/toolkit/content/tests/chrome/test_autocomplete4.xul +++ b/toolkit/content/tests/chrome/test_autocomplete4.xul @@ -41,16 +41,17 @@ nsAutoCompleteSimpleResult.prototype = { searchResult: ACR.RESULT_FAILURE, defaultIndex: 0, errorDescription: null, matchCount: 0, getValueAt: function() { return this._param; }, getCommentAt: function() { return null; }, getStyleAt: function() { return null; }, getImageAt: function() { return null; }, + getFinalCompleteValueAt: function() { return this.getValueAt(); }, getLabelAt: function() { return null; }, removeValueAt: function() {} }; // A basic autocomplete implementation that either returns one result or none var autoCompleteSimpleID = Components.ID("0a2afbdb-f30e-47d1-9cb1-0cd160240aca"); var autoCompleteSimpleName = "@mozilla.org/autocomplete/search;1?name=simple" var autoCompleteSimple = {
--- a/toolkit/content/tests/chrome/test_autocomplete5.xul +++ b/toolkit/content/tests/chrome/test_autocomplete5.xul @@ -37,16 +37,17 @@ nsAutoCompleteSimpleResult.prototype = { searchResult: ACR.RESULT_FAILURE, defaultIndex: -1, errorDescription: null, matchCount: 0, getValueAt: function() { return this._param; }, getCommentAt: function() { return null; }, getStyleAt: function() { return null; }, getImageAt: function() { return null; }, + getFinalCompleteValueAt: function() { return this.getValueAt(); }, getLabelAt: function() { return null; }, removeValueAt: function() {} }; // A basic autocomplete implementation that either returns one result or none var autoCompleteSimpleID = Components.ID("0a2afbdb-f30e-47d1-9cb1-0cd160240aca"); var autoCompleteSimpleName = "@mozilla.org/autocomplete/search;1?name=simple" var autoCompleteSimple = {
--- a/toolkit/content/tests/chrome/test_autocomplete_delayOnPaste.xul +++ b/toolkit/content/tests/chrome/test_autocomplete_delayOnPaste.xul @@ -37,16 +37,17 @@ autoCompleteSimpleResult.prototype = { searchResult: Components.interfaces.nsIAutoCompleteResult.RESULT_FAILURE, defaultIndex: 0, errorDescription: null, matchCount: 0, getValueAt: function() { return this._param; }, getCommentAt: function() { return null; }, getStyleAt: function() { return null; }, getImageAt: function() { return null; }, + getFinalCompleteValueAt: function() { return this.getValueAt(); }, getLabelAt: function() { return null; }, removeValueAt: function() {} }; // A basic autocomplete implementation that returns one result. let autoCompleteSimple = { classID: Components.ID("0a2afbdb-f30e-47d1-9cb1-0cd160240aca"), contractID: "@mozilla.org/autocomplete/search;1?name=simple",
--- a/toolkit/content/tests/chrome/test_autocomplete_with_composition_on_textbox.xul +++ b/toolkit/content/tests/chrome/test_autocomplete_with_composition_on_textbox.xul @@ -52,16 +52,17 @@ nsAutoCompleteSimpleResult.prototype = { searchResult: nsIAutoCompleteResult.RESULT_FAILURE, defaultIndex: 0, errorDescription: null, matchCount: 0, getValueAt: function(aIndex) { return aIndex == 0 ? this._value : null; }, getCommentAt: function() { return null; }, getStyleAt: function() { return null; }, getImageAt: function() { return null; }, + getFinalCompleteValueAt: function(aIndex) { return this.getValueAt(aIndex); }, getLabelAt: function() { return null; }, removeValueAt: function() {} }; // A basic autocomplete implementation that either returns one result or none var autoCompleteSimpleID = Components.ID("0a2afbdb-f30e-47d1-9cb1-0cd160240aca"); var autoCompleteSimpleName =
--- a/toolkit/content/widgets/videocontrols.css +++ b/toolkit/content/widgets/videocontrols.css @@ -29,16 +29,20 @@ font: normal normal normal 100%/normal sans-serif !important; text-decoration: none !important; } .controlsSpacer[hideCursor] { cursor: none; } +.controlsOverlay[scaled] { + -moz-box-align: center; +} + /* CSS Transitions * * These are overriden by the default theme; the rules here just * provide a fallback to drive the required transitionend event * (in case a 3rd party theme does not provide transitions). */ .controlBar:not([immediate]) { transition-property: opacity;
--- a/toolkit/content/widgets/videocontrols.xml +++ b/toolkit/content/widgets/videocontrols.xml @@ -320,16 +320,17 @@ scrubberThumb : null, scrubber : null, progressBar : null, bufferBar : null, statusOverlay : null, controlsSpacer : null, clickToPlay : null, stats : {}, + controlsOverlay : null, fullscreenButton : null, randomID : 0, videoEvents : ["play", "pause", "ended", "volumechange", "loadeddata", "loadstart", "timeupdate", "progress", "playing", "waiting", "canplay", "canplaythrough", "seeking", "seeked", "emptied", "loadedmetadata", "error", "suspend", "stalled", @@ -1385,20 +1386,46 @@ } let minHeightForControlBar = this._controlBarHeight; let minWidthOnlyPlayPause = this._playButtonWidth + this._muteButtonWidth; let videoHeight = isAudioOnly ? minHeightForControlBar : this.video.clientHeight; let videoWidth = isAudioOnly ? minWidthAllControls : this.video.clientWidth; - if ((this._overlayPlayButtonHeight + this._controlBarHeight) > videoHeight || this._overlayPlayButtonWidth > videoWidth) + // Adapt the size of the controls to the size of the video + if (this.video.readyState >= this.video.HAVE_METADATA) { + if (!this.isAudioOnly && this.video.videoWidth && this.video.videoHeight) { + var rect = this.video.getBoundingClientRect(); + var widthRatio = rect.width / this.video.videoWidth; + var heightRatio = rect.height / this.video.videoHeight; + var width = this.video.videoWidth * Math.min(widthRatio, heightRatio); + + this.controlsOverlay.setAttribute("scaled", true); + this.controlsOverlay.style.width = width + "px"; + this.controlsSpacer.style.width = width + "px"; + this.controlBar.style.width = width + "px"; + } else { + this.controlsOverlay.removeAttribute("scaled"); + this.controlsOverlay.style.width = ""; + this.controlsSpacer.style.width = ""; + this.controlBar.style.width = ""; + } + } + + if ((this._overlayPlayButtonHeight + this._controlBarHeight) > videoHeight || + this._overlayPlayButtonWidth > videoWidth) { this.clickToPlay.hidden = true; - else if (this.clickToPlay.hidden && !this.video.played.length) + } else if (this.clickToPlay.hidden && + !this.video.played.length && + this.video.paused) { + // Check this.video.paused to handle when a video is + // playing but hasn't processed any frames yet this.clickToPlay.hidden = false; + } let size = "normal"; if (videoHeight < minHeightForControlBar) size = "hidden"; else if (videoWidth < minWidthOnlyPlayPause) size = "hidden"; else if (videoWidth < minWidthAllControls) size = "small"; @@ -1417,16 +1444,17 @@ this.progressBar = document.getAnonymousElementByAttribute(binding, "class", "progressBar"); this.bufferBar = document.getAnonymousElementByAttribute(binding, "class", "bufferBar"); this.scrubber = document.getAnonymousElementByAttribute(binding, "class", "scrubber"); this.scrubberThumb = document.getAnonymousElementByAttribute(this.scrubber, "class", "scale-thumb"); this.durationLabel = document.getAnonymousElementByAttribute(binding, "class", "durationLabel"); this.positionLabel = document.getAnonymousElementByAttribute(binding, "class", "positionLabel"); this.statusOverlay = document.getAnonymousElementByAttribute(binding, "class", "statusOverlay"); this.statsOverlay = document.getAnonymousElementByAttribute(binding, "class", "statsOverlay"); + this.controlsOverlay = document.getAnonymousElementByAttribute(binding, "class", "controlsOverlay"); this.controlsSpacer = document.getAnonymousElementByAttribute(binding, "class", "controlsSpacer"); this.clickToPlay = document.getAnonymousElementByAttribute(binding, "class", "clickToPlay"); this.fullscreenButton = document.getAnonymousElementByAttribute(binding, "class", "fullscreenButton"); this.volumeForeground = document.getAnonymousElementByAttribute(binding, "anonid", "volumeForeground"); this.statsTable = document.getAnonymousElementByAttribute(binding, "class", "statsTable"); this.stats.filename = document.getAnonymousElementByAttribute(binding, "class", "statFilename"); this.stats.size = document.getAnonymousElementByAttribute(binding, "class", "statSize");
--- a/toolkit/devtools/server/actors/webbrowser.js +++ b/toolkit/devtools/server/actors/webbrowser.js @@ -937,19 +937,25 @@ TabActor.prototype = { * the page. * * @param nsIDOMWindow aWindow * The window object you want to check. * @return boolean * True if the window.console object is native, or false otherwise. */ hasNativeConsoleAPI: function BTA_hasNativeConsoleAPI(aWindow) { - // Do not expose WebConsoleActor function directly as it is always - // loaded after the BrowserTabActor - return WebConsoleActor.prototype.hasNativeConsoleAPI(aWindow); + let isNative = false; + try { + // We are very explicitly examining the "console" property of + // the non-Xrayed object here. + let console = aWindow.wrappedJSObject.console; + isNative = console instanceof aWindow.Console; + } + catch (ex) { } + return isNative; } }; /** * The request types this actor can handle. */ TabActor.prototype.requestTypes = { "attach": TabActor.prototype.onAttach,
--- a/toolkit/devtools/server/actors/webconsole.js +++ b/toolkit/devtools/server/actors/webconsole.js @@ -1,48 +1,54 @@ /* -*- js2-basic-offset: 2; indent-tabs-mode: nil; -*- */ /* vim: set ts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ "use strict"; -let Cc = Components.classes; -let Ci = Components.interfaces; -let Cu = Components.utils; +let {Cc, Ci, Cu} = require("chrome"); Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -let devtools = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools; +let { DebuggerServer, ActorPool } = Cu.import("resource://gre/modules/devtools/dbg-server.jsm", {}); +// Symbols from script.js +let { ThreadActor, EnvironmentActor, ObjectActor, LongStringActor } = DebuggerServer; + +Cu.import("resource://gre/modules/jsdebugger.jsm"); +addDebuggerToGlobal(this); XPCOMUtils.defineLazyModuleGetter(this, "Services", "resource://gre/modules/Services.jsm"); XPCOMUtils.defineLazyGetter(this, "NetworkMonitor", () => { - return devtools.require("devtools/toolkit/webconsole/network-monitor") + return require("devtools/toolkit/webconsole/network-monitor") .NetworkMonitor; }); XPCOMUtils.defineLazyGetter(this, "NetworkMonitorChild", () => { - return devtools.require("devtools/toolkit/webconsole/network-monitor") + return require("devtools/toolkit/webconsole/network-monitor") .NetworkMonitorChild; }); XPCOMUtils.defineLazyGetter(this, "ConsoleProgressListener", () => { - return devtools.require("devtools/toolkit/webconsole/network-monitor") + return require("devtools/toolkit/webconsole/network-monitor") .ConsoleProgressListener; }); +XPCOMUtils.defineLazyGetter(this, "events", () => { + return require("sdk/event/core"); +}); for (let name of ["WebConsoleUtils", "ConsoleServiceListener", "ConsoleAPIListener", "JSTermHelpers", "JSPropertyProvider", "ConsoleReflowListener"]) { Object.defineProperty(this, name, { get: function(prop) { if (prop == "WebConsoleUtils") { prop = "Utils"; } - return devtools.require("devtools/toolkit/webconsole/utils")[prop]; + return require("devtools/toolkit/webconsole/utils")[prop]; }.bind(null, name), configurable: true, enumerable: true }); } /** @@ -1823,11 +1829,17 @@ NetworkEventActor.prototype.requestTypes "getRequestCookies": NetworkEventActor.prototype.onGetRequestCookies, "getRequestPostData": NetworkEventActor.prototype.onGetRequestPostData, "getResponseHeaders": NetworkEventActor.prototype.onGetResponseHeaders, "getResponseCookies": NetworkEventActor.prototype.onGetResponseCookies, "getResponseContent": NetworkEventActor.prototype.onGetResponseContent, "getEventTimings": NetworkEventActor.prototype.onGetEventTimings, }; -DebuggerServer.addTabActor(WebConsoleActor, "consoleActor"); -DebuggerServer.addGlobalActor(WebConsoleActor, "consoleActor"); +exports.register = function(handle) { + handle.addGlobalActor(WebConsoleActor, "consoleActor"); + handle.addTabActor(WebConsoleActor, "consoleActor"); +}; +exports.unregister = function(handle) { + handle.removeGlobalActor(WebConsoleActor, "consoleActor"); + handle.removeTabActor(WebConsoleActor, "consoleActor"); +};
--- a/toolkit/devtools/server/main.js +++ b/toolkit/devtools/server/main.js @@ -355,34 +355,34 @@ var DebuggerServer = { /** * Install tab actors in documents loaded in content childs */ addChildActors: function () { // In case of apps being loaded in parent process, DebuggerServer is already // initialized and browser actors are already loaded, // but childtab.js hasn't been loaded yet. - if (!("WebConsoleActor" in this)) { + if (!DebuggerServer.tabActorFactories.hasOwnProperty("consoleActor")) { this.addTabActors(); } // But webbrowser.js and childtab.js aren't loaded from shell.js. if (!("BrowserTabActor" in this)) { this.addActors("resource://gre/modules/devtools/server/actors/webbrowser.js"); } if (!("ContentActor" in this)) { this.addActors("resource://gre/modules/devtools/server/actors/childtab.js"); } }, /** * Install tab actors. */ addTabActors: function() { this.addActors("resource://gre/modules/devtools/server/actors/script.js"); - this.addActors("resource://gre/modules/devtools/server/actors/webconsole.js"); + this.registerModule("devtools/server/actors/webconsole"); this.registerModule("devtools/server/actors/inspector"); this.registerModule("devtools/server/actors/call-watcher"); this.registerModule("devtools/server/actors/canvas"); this.registerModule("devtools/server/actors/webgl"); this.registerModule("devtools/server/actors/webaudio"); this.registerModule("devtools/server/actors/stylesheets"); this.registerModule("devtools/server/actors/styleeditor"); this.registerModule("devtools/server/actors/storage");