mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge m-c to fx-team
This commit is contained in:
commit
b8d6b378bf
@ -19,13 +19,13 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="135a13ea0ee333314b6a12cb19f18617308a3b46"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="ccd70903544486bea04e85d8a4aacf63f1de2a72"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="44b04243e31cd16f3baf54fcd4b5fecf9deb8b94"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>
|
||||
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="3326b51017252e09ccdd715dec6c5e12a7d1ecfe"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="c510babaf88dfa2cfe2c202afb2649ee124569af"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="26e84ee3e9ef5df2ca28b16aa6719c6e77b5f24f"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="8ba14125aba912707f44761f194339e6e59701b7"/>
|
||||
<!-- Stock Android things -->
|
||||
<project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
|
||||
<project name="platform/bionic" path="bionic" revision="c72b8f6359de7ed17c11ddc9dfdde3f615d188a9"/>
|
||||
@ -98,7 +98,7 @@
|
||||
<project name="platform/system/vold" path="system/vold" revision="919829940468066a32f403980b43f6ebfee5d314"/>
|
||||
<!-- Emulator specific things -->
|
||||
<project name="android-development" path="development" remote="b2g" revision="9abf0ab68376afae3e1c7beefa3e9cbee2fde202"/>
|
||||
<project name="device_generic_goldfish" path="device/generic/goldfish" remote="b2g" revision="2fee3bbbfc236b883ef8507e27d88b17b203fe25"/>
|
||||
<project name="device_generic_goldfish" path="device/generic/goldfish" remote="b2g" revision="3cae7eee1f7f00ba1eb53c733a8779f345055c6e"/>
|
||||
<project name="platform/external/iproute2" path="external/iproute2" revision="c66c5716d5335e450f7a7b71ccc6a604fb2f41d2"/>
|
||||
<project name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="d2685281e2e54ca14d1df304867aa82c37b27162"/>
|
||||
<project name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="627f9b20fc518937b93747a7ff1ed4f5ed46e06f"/>
|
||||
|
@ -17,10 +17,10 @@
|
||||
</project>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="135a13ea0ee333314b6a12cb19f18617308a3b46"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="ccd70903544486bea04e85d8a4aacf63f1de2a72"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="44b04243e31cd16f3baf54fcd4b5fecf9deb8b94"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="c510babaf88dfa2cfe2c202afb2649ee124569af"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="26e84ee3e9ef5df2ca28b16aa6719c6e77b5f24f"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="8ba14125aba912707f44761f194339e6e59701b7"/>
|
||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
|
||||
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
|
||||
<!-- Stock Android things -->
|
||||
|
@ -15,7 +15,7 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="276ce45e78b09c4a4ee643646f691d22804754c1">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="135a13ea0ee333314b6a12cb19f18617308a3b46"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="ccd70903544486bea04e85d8a4aacf63f1de2a72"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="44b04243e31cd16f3baf54fcd4b5fecf9deb8b94"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
@ -23,7 +23,7 @@
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
|
||||
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="26e84ee3e9ef5df2ca28b16aa6719c6e77b5f24f"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="8ba14125aba912707f44761f194339e6e59701b7"/>
|
||||
<!-- Stock Android things -->
|
||||
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="f92a936f2aa97526d4593386754bdbf02db07a12"/>
|
||||
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="6e47ff2790f5656b5b074407829ceecf3e6188c4"/>
|
||||
|
@ -19,13 +19,13 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="135a13ea0ee333314b6a12cb19f18617308a3b46"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="ccd70903544486bea04e85d8a4aacf63f1de2a72"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="44b04243e31cd16f3baf54fcd4b5fecf9deb8b94"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>
|
||||
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="3326b51017252e09ccdd715dec6c5e12a7d1ecfe"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="c510babaf88dfa2cfe2c202afb2649ee124569af"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="26e84ee3e9ef5df2ca28b16aa6719c6e77b5f24f"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="8ba14125aba912707f44761f194339e6e59701b7"/>
|
||||
<!-- Stock Android things -->
|
||||
<project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
|
||||
<project name="platform/bionic" path="bionic" revision="c72b8f6359de7ed17c11ddc9dfdde3f615d188a9"/>
|
||||
@ -98,7 +98,7 @@
|
||||
<project name="platform/system/vold" path="system/vold" revision="919829940468066a32f403980b43f6ebfee5d314"/>
|
||||
<!-- Emulator specific things -->
|
||||
<project name="android-development" path="development" remote="b2g" revision="9abf0ab68376afae3e1c7beefa3e9cbee2fde202"/>
|
||||
<project name="device_generic_goldfish" path="device/generic/goldfish" remote="b2g" revision="2fee3bbbfc236b883ef8507e27d88b17b203fe25"/>
|
||||
<project name="device_generic_goldfish" path="device/generic/goldfish" remote="b2g" revision="3cae7eee1f7f00ba1eb53c733a8779f345055c6e"/>
|
||||
<project name="platform/external/iproute2" path="external/iproute2" revision="c66c5716d5335e450f7a7b71ccc6a604fb2f41d2"/>
|
||||
<project name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="d2685281e2e54ca14d1df304867aa82c37b27162"/>
|
||||
<project name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="627f9b20fc518937b93747a7ff1ed4f5ed46e06f"/>
|
||||
|
@ -17,10 +17,10 @@
|
||||
</project>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="135a13ea0ee333314b6a12cb19f18617308a3b46"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="ccd70903544486bea04e85d8a4aacf63f1de2a72"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="44b04243e31cd16f3baf54fcd4b5fecf9deb8b94"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="c510babaf88dfa2cfe2c202afb2649ee124569af"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="26e84ee3e9ef5df2ca28b16aa6719c6e77b5f24f"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="8ba14125aba912707f44761f194339e6e59701b7"/>
|
||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
|
||||
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
|
||||
<!-- Stock Android things -->
|
||||
|
@ -4,6 +4,6 @@
|
||||
"remote": "",
|
||||
"branch": ""
|
||||
},
|
||||
"revision": "507ca54e4c4da9d3e1b1af92d7a306a71875d066",
|
||||
"revision": "dcb55fbcaa9bd33e662a2c5e99cdb7e4c9d7ad51",
|
||||
"repo_path": "/integration/gaia-central"
|
||||
}
|
||||
|
@ -17,12 +17,12 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="135a13ea0ee333314b6a12cb19f18617308a3b46"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="ccd70903544486bea04e85d8a4aacf63f1de2a72"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="44b04243e31cd16f3baf54fcd4b5fecf9deb8b94"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="c510babaf88dfa2cfe2c202afb2649ee124569af"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="26e84ee3e9ef5df2ca28b16aa6719c6e77b5f24f"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="8ba14125aba912707f44761f194339e6e59701b7"/>
|
||||
<!-- Stock Android things -->
|
||||
<project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
|
||||
<project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
|
||||
|
@ -15,7 +15,7 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="135a13ea0ee333314b6a12cb19f18617308a3b46"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="ccd70903544486bea04e85d8a4aacf63f1de2a72"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="44b04243e31cd16f3baf54fcd4b5fecf9deb8b94"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
|
@ -17,10 +17,10 @@
|
||||
</project>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="135a13ea0ee333314b6a12cb19f18617308a3b46"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="ccd70903544486bea04e85d8a4aacf63f1de2a72"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="44b04243e31cd16f3baf54fcd4b5fecf9deb8b94"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="c510babaf88dfa2cfe2c202afb2649ee124569af"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="26e84ee3e9ef5df2ca28b16aa6719c6e77b5f24f"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="8ba14125aba912707f44761f194339e6e59701b7"/>
|
||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
|
||||
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
|
||||
<!-- Stock Android things -->
|
||||
|
@ -17,12 +17,12 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="135a13ea0ee333314b6a12cb19f18617308a3b46"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="ccd70903544486bea04e85d8a4aacf63f1de2a72"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="44b04243e31cd16f3baf54fcd4b5fecf9deb8b94"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="c510babaf88dfa2cfe2c202afb2649ee124569af"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="26e84ee3e9ef5df2ca28b16aa6719c6e77b5f24f"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="8ba14125aba912707f44761f194339e6e59701b7"/>
|
||||
<project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
|
||||
<!-- Stock Android things -->
|
||||
<project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
|
||||
|
@ -48,9 +48,16 @@ this.Translation = {
|
||||
|
||||
documentStateReceived: function(aBrowser, aData) {
|
||||
if (aData.state == this.STATE_OFFER) {
|
||||
if (this.supportedSourceLanguages.indexOf(aData.detectedLanguage) == -1 ||
|
||||
aData.detectedLanguage == this.defaultTargetLanguage)
|
||||
if (aData.detectedLanguage == this.defaultTargetLanguage) {
|
||||
// Detected language is the same as the user's locale.
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.supportedSourceLanguages.indexOf(aData.detectedLanguage) == -1) {
|
||||
// Detected language is not part of the supported languages.
|
||||
TranslationHealthReport.recordMissedTranslationOpportunity(aData.detectedLanguage);
|
||||
return;
|
||||
}
|
||||
|
||||
TranslationHealthReport.recordTranslationOpportunity(aData.detectedLanguage);
|
||||
}
|
||||
@ -258,6 +265,17 @@ let TranslationHealthReport = {
|
||||
this._withProvider(provider => provider.recordTranslationOpportunity(language));
|
||||
},
|
||||
|
||||
/**
|
||||
* Record a missed translation opportunity in the health report.
|
||||
* A missed opportunity is when the language detected is not part
|
||||
* of the supported languages.
|
||||
* @param language
|
||||
* The language of the page.
|
||||
*/
|
||||
recordMissedTranslationOpportunity: function (language) {
|
||||
this._withProvider(provider => provider.recordMissedTranslationOpportunity(language));
|
||||
},
|
||||
|
||||
/**
|
||||
* Record a translation in the health report.
|
||||
* @param langFrom
|
||||
@ -337,9 +355,11 @@ TranslationMeasurement1.prototype = Object.freeze({
|
||||
|
||||
fields: {
|
||||
translationOpportunityCount: DAILY_COUNTER_FIELD,
|
||||
missedTranslationOpportunityCount: DAILY_COUNTER_FIELD,
|
||||
pageTranslatedCount: DAILY_COUNTER_FIELD,
|
||||
charactersTranslatedCount: DAILY_COUNTER_FIELD,
|
||||
translationOpportunityCountsByLanguage: DAILY_LAST_TEXT_FIELD,
|
||||
missedTranslationOpportunityCountsByLanguage: DAILY_LAST_TEXT_FIELD,
|
||||
pageTranslatedCountsByLanguage: DAILY_LAST_TEXT_FIELD,
|
||||
detectedLanguageChangedBefore: DAILY_COUNTER_FIELD,
|
||||
detectedLanguageChangedAfter: DAILY_COUNTER_FIELD,
|
||||
@ -384,6 +404,7 @@ TranslationMeasurement1.prototype = Object.freeze({
|
||||
// Special case the serialization of these fields so that
|
||||
// they are sent as objects, not stringified objects.
|
||||
_parseInPlace(result, "translationOpportunityCountsByLanguage");
|
||||
_parseInPlace(result, "missedTranslationOpportunityCountsByLanguage");
|
||||
_parseInPlace(result, "pageTranslatedCountsByLanguage");
|
||||
|
||||
return result;
|
||||
@ -423,6 +444,25 @@ TranslationProvider.prototype = Object.freeze({
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
recordMissedTranslationOpportunity: function (language, date=new Date()) {
|
||||
let m = this.getMeasurement(TranslationMeasurement1.prototype.name,
|
||||
TranslationMeasurement1.prototype.version);
|
||||
|
||||
return this._enqueueTelemetryStorageTask(function* recordTask() {
|
||||
yield m.incrementDailyCounter("missedTranslationOpportunityCount", date);
|
||||
|
||||
let langCounts = yield m._getDailyLastTextFieldAsJSON(
|
||||
"missedTranslationOpportunityCountsByLanguage", date);
|
||||
|
||||
langCounts[language] = (langCounts[language] || 0) + 1;
|
||||
langCounts = JSON.stringify(langCounts);
|
||||
|
||||
yield m.setDailyLastText("missedTranslationOpportunityCountsByLanguage",
|
||||
langCounts, date);
|
||||
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
recordTranslation: function (langFrom, langTo, numCharacters, date=new Date()) {
|
||||
let m = this.getMeasurement(TranslationMeasurement1.prototype.name,
|
||||
TranslationMeasurement1.prototype.version);
|
||||
|
@ -69,21 +69,47 @@ add_task(function* test_translation_opportunity() {
|
||||
let countsByLanguage = JSON.parse(day.get("translationOpportunityCountsByLanguage"));
|
||||
Assert.equal(countsByLanguage["fr"], 1);
|
||||
|
||||
// Record a missed opportunity.
|
||||
yield provider.recordMissedTranslationOpportunity("it", now);
|
||||
|
||||
values = yield m.getValues();
|
||||
day = values.days.getDay(now);
|
||||
Assert.equal(values.days.size, 1);
|
||||
Assert.ok(values.days.hasDay(now));
|
||||
Assert.ok(day.has("missedTranslationOpportunityCount"));
|
||||
Assert.equal(day.get("missedTranslationOpportunityCount"), 1);
|
||||
|
||||
Assert.ok(day.has("missedTranslationOpportunityCountsByLanguage"));
|
||||
let missedCountsByLanguage = JSON.parse(day.get("missedTranslationOpportunityCountsByLanguage"));
|
||||
Assert.equal(missedCountsByLanguage["it"], 1);
|
||||
|
||||
// Record more opportunities.
|
||||
yield provider.recordTranslationOpportunity("fr", now);
|
||||
yield provider.recordTranslationOpportunity("fr", now);
|
||||
yield provider.recordTranslationOpportunity("es", now);
|
||||
|
||||
yield provider.recordMissedTranslationOpportunity("it", now);
|
||||
yield provider.recordMissedTranslationOpportunity("cs", now);
|
||||
yield provider.recordMissedTranslationOpportunity("fi", now);
|
||||
|
||||
values = yield m.getValues();
|
||||
let day = values.days.getDay(now);
|
||||
day = values.days.getDay(now);
|
||||
Assert.ok(day.has("translationOpportunityCount"));
|
||||
Assert.equal(day.get("translationOpportunityCount"), 4);
|
||||
Assert.ok(day.has("missedTranslationOpportunityCount"));
|
||||
Assert.equal(day.get("missedTranslationOpportunityCount"), 4);
|
||||
|
||||
Assert.ok(day.has("translationOpportunityCountsByLanguage"));
|
||||
countsByLanguage = JSON.parse(day.get("translationOpportunityCountsByLanguage"));
|
||||
Assert.equal(countsByLanguage["fr"], 3);
|
||||
Assert.equal(countsByLanguage["es"], 1);
|
||||
|
||||
Assert.ok(day.has("missedTranslationOpportunityCountsByLanguage"));
|
||||
missedCountsByLanguage = JSON.parse(day.get("missedTranslationOpportunityCountsByLanguage"));
|
||||
Assert.equal(missedCountsByLanguage["it"], 2);
|
||||
Assert.equal(missedCountsByLanguage["cs"], 1);
|
||||
Assert.equal(missedCountsByLanguage["fi"], 1);
|
||||
|
||||
yield provider.shutdown();
|
||||
yield storage.close();
|
||||
});
|
||||
|
@ -190,11 +190,11 @@ Section "MaintenanceService"
|
||||
${GetParameters} $0
|
||||
${GetOptions} "$0" "/Upgrade" $0
|
||||
${If} ${Errors}
|
||||
nsExec::Exec '"$INSTDIR\$TempMaintServiceName" install'
|
||||
ExecWait '"$INSTDIR\$TempMaintServiceName" install'
|
||||
${Else}
|
||||
; The upgrade cmdline is the same as install except
|
||||
; It will fail if the service isn't already installed.
|
||||
nsExec::Exec '"$INSTDIR\$TempMaintServiceName" upgrade'
|
||||
ExecWait '"$INSTDIR\$TempMaintServiceName" upgrade'
|
||||
${EndIf}
|
||||
|
||||
WriteUninstaller "$INSTDIR\Uninstall.exe"
|
||||
@ -255,7 +255,7 @@ FunctionEnd
|
||||
|
||||
Section "Uninstall"
|
||||
; Delete the service so that no updates will be attempted
|
||||
nsExec::Exec '"$INSTDIR\maintenanceservice.exe" uninstall'
|
||||
ExecWait '"$INSTDIR\maintenanceservice.exe" uninstall'
|
||||
|
||||
Push "$INSTDIR\updater.ini"
|
||||
Call un.RenameDelete
|
||||
|
@ -197,11 +197,7 @@ if test "$CLANG_CXX"; then
|
||||
## returned by C functions. This is possible because we use knowledge about the ABI
|
||||
## to typedef it to a C type with the same layout when the headers are included
|
||||
## from C.
|
||||
##
|
||||
## mismatched-tags is disabled (bug 780474) mostly because it's useless.
|
||||
## Worse, it's not supported by gcc, so it will cause tryserver bustage
|
||||
## without any easy way for non-Clang users to check for it.
|
||||
_WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wno-unknown-warning-option -Wno-return-type-c-linkage -Wno-mismatched-tags"
|
||||
_WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wno-unknown-warning-option -Wno-return-type-c-linkage"
|
||||
fi
|
||||
|
||||
AC_MSG_CHECKING([whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) actually is a C++ compiler])
|
||||
@ -216,15 +212,6 @@ LIBS=$_SAVE_LIBS
|
||||
AC_LANG_RESTORE
|
||||
AC_MSG_RESULT([yes])
|
||||
|
||||
if test -z "$GNU_CC"; then
|
||||
case "$target" in
|
||||
*-mingw*)
|
||||
## Warning 4099 (equivalent of mismatched-tags) is disabled (bug 780474)
|
||||
## for the same reasons as above.
|
||||
_WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -wd4099"
|
||||
esac
|
||||
fi
|
||||
|
||||
if test -n "$DEVELOPER_OPTIONS"; then
|
||||
MOZ_FORCE_GOLD=1
|
||||
fi
|
||||
|
@ -194,7 +194,7 @@ class B2GRemoteAutomation(Automation):
|
||||
time.sleep(10)
|
||||
self._devicemanager._checkCmd(['shell', 'start', 'b2g'])
|
||||
if self._is_emulator:
|
||||
self.marionette.emulator.wait_for_port()
|
||||
self.marionette.emulator.wait_for_port(self.marionette.port)
|
||||
|
||||
def rebootDevice(self):
|
||||
# find device's current status and serial number
|
||||
@ -262,7 +262,7 @@ class B2GRemoteAutomation(Automation):
|
||||
'tcp:%s' % self.marionette.port])
|
||||
|
||||
if self._is_emulator:
|
||||
self.marionette.emulator.wait_for_port()
|
||||
self.marionette.emulator.wait_for_port(self.marionette.port)
|
||||
else:
|
||||
time.sleep(5)
|
||||
|
||||
|
@ -131,7 +131,7 @@ class MachCommands(MachCommandBase):
|
||||
binary=self.get_binary_path(),
|
||||
cmdargs=firefox_args,
|
||||
env=env,
|
||||
kp_kwargs=kp_kwargs)
|
||||
process_args=kp_kwargs)
|
||||
runner.start(debug_args=valgrind_args)
|
||||
exitcode = runner.wait()
|
||||
|
||||
|
@ -2040,11 +2040,8 @@ public:
|
||||
*
|
||||
* @return whether aAttr was valid and can be cached.
|
||||
*/
|
||||
static AutocompleteAttrState
|
||||
SerializeAutocompleteAttribute(const nsAttrValue* aAttr,
|
||||
nsAString& aResult,
|
||||
AutocompleteAttrState aCachedState =
|
||||
eAutocompleteAttrState_Unknown);
|
||||
static AutocompleteAttrState SerializeAutocompleteAttribute(const nsAttrValue* aAttr,
|
||||
nsAString& aResult);
|
||||
|
||||
/**
|
||||
* This will parse aSource, to extract the value of the pseudo attribute
|
||||
|
@ -855,26 +855,8 @@ nsContentUtils::IsAutocompleteEnabled(nsIDOMHTMLInputElement* aInput)
|
||||
|
||||
nsContentUtils::AutocompleteAttrState
|
||||
nsContentUtils::SerializeAutocompleteAttribute(const nsAttrValue* aAttr,
|
||||
nsAString& aResult,
|
||||
AutocompleteAttrState aCachedState)
|
||||
nsAString& aResult)
|
||||
{
|
||||
if (!aAttr ||
|
||||
aCachedState == nsContentUtils::eAutocompleteAttrState_Invalid) {
|
||||
return aCachedState;
|
||||
}
|
||||
|
||||
if (aCachedState == nsContentUtils::eAutocompleteAttrState_Valid) {
|
||||
uint32_t atomCount = aAttr->GetAtomCount();
|
||||
for (uint32_t i = 0; i < atomCount; i++) {
|
||||
if (i != 0) {
|
||||
aResult.Append(' ');
|
||||
}
|
||||
aResult.Append(nsDependentAtomString(aAttr->AtomAt(i)));
|
||||
}
|
||||
nsContentUtils::ASCIIToLower(aResult);
|
||||
return aCachedState;
|
||||
}
|
||||
|
||||
AutocompleteAttrState state = InternalSerializeAutocompleteAttribute(aAttr, aResult);
|
||||
if (state == eAutocompleteAttrState_Valid) {
|
||||
ASCIIToLower(aResult);
|
||||
@ -891,7 +873,7 @@ nsContentUtils::SerializeAutocompleteAttribute(const nsAttrValue* aAttr,
|
||||
*/
|
||||
nsContentUtils::AutocompleteAttrState
|
||||
nsContentUtils::InternalSerializeAutocompleteAttribute(const nsAttrValue* aAttrVal,
|
||||
nsAString& aResult)
|
||||
nsAString& aResult)
|
||||
{
|
||||
// No sandbox attribute so we are done
|
||||
if (!aAttrVal) {
|
||||
|
@ -1520,10 +1520,23 @@ HTMLInputElement::GetAutocomplete(nsAString& aValue)
|
||||
{
|
||||
aValue.Truncate(0);
|
||||
const nsAttrValue* attributeVal = GetParsedAttr(nsGkAtoms::autocomplete);
|
||||
if (!attributeVal ||
|
||||
mAutocompleteAttrState == nsContentUtils::eAutocompleteAttrState_Invalid) {
|
||||
return NS_OK;
|
||||
}
|
||||
if (mAutocompleteAttrState == nsContentUtils::eAutocompleteAttrState_Valid) {
|
||||
uint32_t atomCount = attributeVal->GetAtomCount();
|
||||
for (uint32_t i = 0; i < atomCount; i++) {
|
||||
if (i != 0) {
|
||||
aValue.Append(' ');
|
||||
}
|
||||
aValue.Append(nsDependentAtomString(attributeVal->AtomAt(i)));
|
||||
}
|
||||
nsContentUtils::ASCIIToLower(aValue);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
mAutocompleteAttrState =
|
||||
nsContentUtils::SerializeAutocompleteAttribute(attributeVal, aValue,
|
||||
mAutocompleteAttrState);
|
||||
mAutocompleteAttrState = nsContentUtils::SerializeAutocompleteAttribute(attributeVal, aValue);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -104,7 +104,6 @@ HTMLSelectElement::HTMLSelectElement(already_AddRefed<nsINodeInfo>& aNodeInfo,
|
||||
FromParser aFromParser)
|
||||
: nsGenericHTMLFormElementWithState(aNodeInfo),
|
||||
mOptions(new HTMLOptionsCollection(MOZ_THIS_IN_INITIALIZER_LIST())),
|
||||
mAutocompleteAttrState(nsContentUtils::eAutocompleteAttrState_Unknown),
|
||||
mIsDoneAddingChildren(!aFromParser),
|
||||
mDisabledChanged(false),
|
||||
mMutating(false),
|
||||
@ -178,16 +177,6 @@ HTMLSelectElement::SetCustomValidity(const nsAString& aError)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
HTMLSelectElement::GetAutocomplete(DOMString& aValue)
|
||||
{
|
||||
const nsAttrValue* attributeVal = GetParsedAttr(nsGkAtoms::autocomplete);
|
||||
|
||||
mAutocompleteAttrState =
|
||||
nsContentUtils::SerializeAutocompleteAttribute(attributeVal, aValue,
|
||||
mAutocompleteAttrState);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLSelectElement::GetForm(nsIDOMHTMLFormElement** aForm)
|
||||
{
|
||||
@ -1344,9 +1333,6 @@ HTMLSelectElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
UpdateBarredFromConstraintValidation();
|
||||
} else if (aName == nsGkAtoms::required) {
|
||||
UpdateValueMissingValidityState();
|
||||
} else if (aName == nsGkAtoms::autocomplete) {
|
||||
// Clear the cached @autocomplete attribute state
|
||||
mAutocompleteAttrState = nsContentUtils::eAutocompleteAttrState_Unknown;
|
||||
}
|
||||
|
||||
UpdateState(aNotify);
|
||||
@ -1434,13 +1420,8 @@ HTMLSelectElement::ParseAttribute(int32_t aNamespaceID,
|
||||
const nsAString& aValue,
|
||||
nsAttrValue& aResult)
|
||||
{
|
||||
if (kNameSpaceID_None == aNamespaceID) {
|
||||
if (aAttribute == nsGkAtoms::size) {
|
||||
return aResult.ParsePositiveIntValue(aValue);
|
||||
} else if (aAttribute == nsGkAtoms::autocomplete) {
|
||||
aResult.ParseAtomArray(aValue);
|
||||
return true;
|
||||
}
|
||||
if (aAttribute == nsGkAtoms::size && kNameSpaceID_None == aNamespaceID) {
|
||||
return aResult.ParsePositiveIntValue(aValue);
|
||||
}
|
||||
return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
|
||||
aResult);
|
||||
|
@ -17,7 +17,6 @@
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsError.h"
|
||||
#include "mozilla/dom/HTMLFormElement.h"
|
||||
#include "nsContentUtils.h"
|
||||
|
||||
class nsContentList;
|
||||
class nsIDOMHTMLOptionElement;
|
||||
@ -160,11 +159,6 @@ public:
|
||||
{
|
||||
SetHTMLBoolAttr(nsGkAtoms::autofocus, aVal, aRv);
|
||||
}
|
||||
void GetAutocomplete(DOMString& aValue);
|
||||
void SetAutocomplete(const nsAString& aValue, ErrorResult& aRv)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::autocomplete, aValue, aRv);
|
||||
}
|
||||
bool Disabled() const
|
||||
{
|
||||
return GetBoolAttr(nsGkAtoms::disabled);
|
||||
@ -611,7 +605,6 @@ protected:
|
||||
|
||||
/** The options[] array */
|
||||
nsRefPtr<HTMLOptionsCollection> mOptions;
|
||||
nsContentUtils::AutocompleteAttrState mAutocompleteAttrState;
|
||||
/** false if the parser is in the middle of adding children. */
|
||||
bool mIsDoneAddingChildren;
|
||||
/** true if our disabled state has changed from the default **/
|
||||
|
@ -13,8 +13,7 @@ Test @autocomplete on <input>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
<form>
|
||||
<input id="input-field" />
|
||||
<select id="select-field" />
|
||||
<input id="field" />
|
||||
</form>
|
||||
</div>
|
||||
<pre id="test">
|
||||
@ -70,8 +69,9 @@ var values = [
|
||||
];
|
||||
|
||||
var types = [undefined, "hidden", "text", "search"]; // Valid types for all non-multiline hints.
|
||||
var field = document.getElementById("field");
|
||||
|
||||
function checkAutocompleteValues(field, type) {
|
||||
function checkAutocompleteValues(type) {
|
||||
for (var test of values) {
|
||||
if (typeof(test[0]) === "undefined")
|
||||
field.removeAttribute("autocomplete");
|
||||
@ -83,18 +83,14 @@ function checkAutocompleteValues(field, type) {
|
||||
}
|
||||
|
||||
function start() {
|
||||
var inputField = document.getElementById("input-field");
|
||||
for (var type of types) {
|
||||
// Switch the input type
|
||||
if (typeof(type) === "undefined")
|
||||
inputField.removeAttribute("type");
|
||||
field.removeAttribute("type");
|
||||
else
|
||||
inputField.type = type;
|
||||
checkAutocompleteValues(inputField, type || "");
|
||||
field.type = type;
|
||||
checkAutocompleteValues(type || "");
|
||||
}
|
||||
|
||||
var selectField = document.getElementById("select-field");
|
||||
checkAutocompleteValues(selectField, "select");
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
|
@ -616,12 +616,13 @@ this.DOMApplicationRegistry = {
|
||||
}.bind(this)).then(null, Cu.reportError);
|
||||
},
|
||||
|
||||
updateDataStore: function(aId, aOrigin, aManifestURL, aManifest, aAppStatus) {
|
||||
// Just Certified Apps can use DataStores
|
||||
let prefName = "dom.testing.datastore_enabled_for_hosted_apps";
|
||||
if (aAppStatus != Ci.nsIPrincipal.APP_STATUS_CERTIFIED &&
|
||||
(Services.prefs.getPrefType(prefName) == Services.prefs.PREF_INVALID ||
|
||||
!Services.prefs.getBoolPref(prefName))) {
|
||||
updateDataStore: function(aId, aOrigin, aManifestURL, aManifest) {
|
||||
let uri = Services.io.newURI(aOrigin, null, null);
|
||||
let secMan = Cc["@mozilla.org/scriptsecuritymanager;1"]
|
||||
.getService(Ci.nsIScriptSecurityManager);
|
||||
let principal = secMan.getAppCodebasePrincipal(uri, aId,
|
||||
/*mozbrowser*/ false);
|
||||
if (!dataStoreService.checkPermission(principal)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1543,7 +1544,7 @@ this.DOMApplicationRegistry = {
|
||||
true);
|
||||
}
|
||||
this.updateDataStore(this.webapps[id].localId, app.origin,
|
||||
app.manifestURL, newManifest, app.appStatus);
|
||||
app.manifestURL, newManifest);
|
||||
this.broadcastMessage("Webapps:UpdateState", {
|
||||
app: app,
|
||||
manifest: newManifest,
|
||||
@ -1961,7 +1962,7 @@ this.DOMApplicationRegistry = {
|
||||
}
|
||||
|
||||
this.updateDataStore(this.webapps[aId].localId, aApp.origin,
|
||||
aApp.manifestURL, aApp.manifest, aApp.appStatus);
|
||||
aApp.manifestURL, aApp.manifest);
|
||||
|
||||
aApp.name = manifest.name;
|
||||
aApp.csp = manifest.csp || "";
|
||||
@ -2494,8 +2495,7 @@ this.DOMApplicationRegistry = {
|
||||
}
|
||||
|
||||
this.updateDataStore(this.webapps[id].localId, this.webapps[id].origin,
|
||||
this.webapps[id].manifestURL, jsonManifest,
|
||||
this.webapps[id].appStatus);
|
||||
this.webapps[id].manifestURL, jsonManifest);
|
||||
}
|
||||
|
||||
for each (let prop in ["installState", "downloadAvailable", "downloading",
|
||||
@ -2631,7 +2631,7 @@ this.DOMApplicationRegistry = {
|
||||
}
|
||||
|
||||
this.updateDataStore(this.webapps[aId].localId, aNewApp.origin,
|
||||
aNewApp.manifestURL, aManifest, aNewApp.appStatus);
|
||||
aNewApp.manifestURL, aManifest);
|
||||
|
||||
this.broadcastMessage("Webapps:UpdateState", {
|
||||
app: app,
|
||||
|
@ -2264,25 +2264,7 @@ Navigator::HasDataStoreSupport(nsIPrincipal* aPrincipal)
|
||||
{
|
||||
workers::AssertIsOnMainThread();
|
||||
|
||||
// First of all, the general pref has to be turned on.
|
||||
bool enabled = false;
|
||||
Preferences::GetBool("dom.datastore.enabled", &enabled);
|
||||
if (!enabled) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Just for testing, we can enable DataStore for any kind of app.
|
||||
if (Preferences::GetBool("dom.testing.datastore_enabled_for_hosted_apps", false)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
uint16_t status;
|
||||
if (NS_FAILED(aPrincipal->GetAppStatus(&status))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Only support DataStore API for certified apps for now.
|
||||
return status == nsIPrincipal::APP_STATUS_CERTIFIED;
|
||||
return DataStoreService::CheckPermission(aPrincipal);
|
||||
}
|
||||
|
||||
// A WorkerMainThreadRunnable to synchronously dispatch the call of
|
||||
|
243
dom/camera/CameraPreferences.cpp
Normal file
243
dom/camera/CameraPreferences.cpp
Normal file
@ -0,0 +1,243 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "CameraPreferences.h"
|
||||
#include "CameraCommon.h"
|
||||
#include "mozilla/Monitor.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
/* statics */
|
||||
static StaticAutoPtr<Monitor> sPrefMonitor;
|
||||
|
||||
StaticAutoPtr<nsCString> CameraPreferences::sPrefTestEnabled;
|
||||
StaticAutoPtr<nsCString> CameraPreferences::sPrefHardwareTest;
|
||||
StaticAutoPtr<nsCString> CameraPreferences::sPrefGonkParameters;
|
||||
|
||||
nsresult CameraPreferences::sPrefCameraControlMethodErrorOverride = NS_OK;
|
||||
nsresult CameraPreferences::sPrefCameraControlAsyncErrorOverride = NS_OK;
|
||||
|
||||
/* static */
|
||||
nsresult
|
||||
CameraPreferences::UpdatePref(const char* aPref, nsresult& aVal)
|
||||
{
|
||||
uint32_t val;
|
||||
nsresult rv = Preferences::GetUint(aPref, &val);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
aVal = static_cast<nsresult>(val);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
/* static */
|
||||
nsresult
|
||||
CameraPreferences::UpdatePref(const char* aPref, nsACString& aVal)
|
||||
{
|
||||
nsCString val;
|
||||
nsresult rv = Preferences::GetCString(aPref, &val);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
aVal = val;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
/* static */
|
||||
CameraPreferences::Pref CameraPreferences::sPrefs[] = {
|
||||
{
|
||||
"camera.control.test.enabled",
|
||||
kPrefValueIsCString,
|
||||
{ &sPrefTestEnabled }
|
||||
},
|
||||
{
|
||||
"camera.control.test.hardware",
|
||||
kPrefValueIsCString,
|
||||
{ &sPrefHardwareTest }
|
||||
},
|
||||
#ifdef MOZ_B2G
|
||||
{
|
||||
"camera.control.test.hardware.gonk.parameters",
|
||||
kPrefValueIsCString,
|
||||
{ &sPrefGonkParameters }
|
||||
},
|
||||
#endif
|
||||
{
|
||||
"camera.control.test.method.error",
|
||||
kPrefValueIsNSResult,
|
||||
{ &sPrefCameraControlMethodErrorOverride }
|
||||
},
|
||||
{
|
||||
"camera.control.test.async.error",
|
||||
kPrefValueIsNSResult,
|
||||
{ &sPrefCameraControlAsyncErrorOverride }
|
||||
},
|
||||
};
|
||||
|
||||
/* static */
|
||||
uint32_t
|
||||
CameraPreferences::PrefToIndex(const char* aPref)
|
||||
{
|
||||
for (uint32_t i = 0; i < ArrayLength(sPrefs); ++i) {
|
||||
if (strcmp(aPref, sPrefs[i].mPref) == 0) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return kPrefNotFound;
|
||||
}
|
||||
|
||||
/* static */
|
||||
void
|
||||
CameraPreferences::PreferenceChanged(const char* aPref, void* aClosure)
|
||||
{
|
||||
MonitorAutoLock mon(*sPrefMonitor);
|
||||
|
||||
uint32_t i = PrefToIndex(aPref);
|
||||
if (i == kPrefNotFound) {
|
||||
DOM_CAMERA_LOGE("Preference '%s' is not tracked by CameraPreferences\n", aPref);
|
||||
return;
|
||||
}
|
||||
|
||||
Pref& p = sPrefs[i];
|
||||
nsresult rv;
|
||||
switch (p.mValueType) {
|
||||
case kPrefValueIsNSResult:
|
||||
{
|
||||
nsresult& v = *p.mValue.mAsNsResult;
|
||||
rv = UpdatePref(aPref, v);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
DOM_CAMERA_LOGI("Preference '%s' has changed, 0x%x\n", aPref, v);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case kPrefValueIsCString:
|
||||
{
|
||||
nsCString& v = **p.mValue.mAsCString;
|
||||
rv = UpdatePref(aPref, v);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
DOM_CAMERA_LOGI("Preference '%s' has changed, '%s'\n", aPref, v.get());
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
MOZ_ASSERT_UNREACHABLE("Unhandled preference value type!");
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
if (NS_FAILED(rv)) {
|
||||
nsCString msg;
|
||||
msg.AppendPrintf("Failed to update pref '%s' (0x%x)\n", aPref, rv);
|
||||
NS_WARNING(msg.get());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool
|
||||
CameraPreferences::Initialize()
|
||||
{
|
||||
DOM_CAMERA_LOGI("Initializing camera preference callbacks\n");
|
||||
|
||||
nsresult rv;
|
||||
|
||||
sPrefMonitor = new Monitor("CameraPreferences.sPrefMonitor");
|
||||
|
||||
sPrefTestEnabled = new nsCString();
|
||||
sPrefHardwareTest = new nsCString();
|
||||
sPrefGonkParameters = new nsCString();
|
||||
|
||||
for (uint32_t i = 0; i < ArrayLength(sPrefs); ++i) {
|
||||
rv = Preferences::RegisterCallbackAndCall(CameraPreferences::PreferenceChanged,
|
||||
sPrefs[i].mPref);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
DOM_CAMERA_LOGI("Camera preferences initialized\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
/* static */
|
||||
void
|
||||
CameraPreferences::Shutdown()
|
||||
{
|
||||
DOM_CAMERA_LOGI("Shutting down camera preference callbacks\n");
|
||||
|
||||
for (uint32_t i = 0; i < ArrayLength(sPrefs); ++i) {
|
||||
Preferences::UnregisterCallback(CameraPreferences::PreferenceChanged,
|
||||
sPrefs[i].mPref);
|
||||
}
|
||||
|
||||
sPrefTestEnabled = nullptr;
|
||||
sPrefHardwareTest = nullptr;
|
||||
sPrefGonkParameters = nullptr;
|
||||
sPrefMonitor = nullptr;
|
||||
|
||||
DOM_CAMERA_LOGI("Camera preferences shut down\n");
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool
|
||||
CameraPreferences::GetPref(const char* aPref, nsACString& aVal)
|
||||
{
|
||||
MOZ_ASSERT(sPrefMonitor, "sPrefMonitor missing in CameraPreferences::GetPref()");
|
||||
MonitorAutoLock mon(*sPrefMonitor);
|
||||
|
||||
uint32_t i = PrefToIndex(aPref);
|
||||
if (i == kPrefNotFound || i >= ArrayLength(sPrefs)) {
|
||||
DOM_CAMERA_LOGW("Preference '%s' is not tracked by CameraPreferences\n", aPref);
|
||||
return false;
|
||||
}
|
||||
if (sPrefs[i].mValueType != kPrefValueIsCString) {
|
||||
DOM_CAMERA_LOGW("Preference '%s' is not a string type\n", aPref);
|
||||
return false;
|
||||
}
|
||||
|
||||
StaticAutoPtr<nsCString>* s = sPrefs[i].mValue.mAsCString;
|
||||
if (!*s) {
|
||||
DOM_CAMERA_LOGE("Preference '%s' cache is not initialized\n", aPref);
|
||||
return false;
|
||||
}
|
||||
if ((*s)->IsEmpty()) {
|
||||
DOM_CAMERA_LOGI("Preference '%s' is not set\n", aPref);
|
||||
return false;
|
||||
}
|
||||
|
||||
DOM_CAMERA_LOGI("Preference '%s', got '%s'\n", aPref, (*s)->get());
|
||||
aVal = **s;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool
|
||||
CameraPreferences::GetPref(const char* aPref, nsresult& aVal)
|
||||
{
|
||||
MOZ_ASSERT(sPrefMonitor, "sPrefMonitor missing in CameraPreferences::GetPref()");
|
||||
MonitorAutoLock mon(*sPrefMonitor);
|
||||
|
||||
uint32_t i = PrefToIndex(aPref);
|
||||
if (i == kPrefNotFound || i >= ArrayLength(sPrefs)) {
|
||||
DOM_CAMERA_LOGW("Preference '%s' is not tracked by CameraPreferences\n", aPref);
|
||||
return false;
|
||||
}
|
||||
if (sPrefs[i].mValueType != kPrefValueIsNSResult) {
|
||||
DOM_CAMERA_LOGW("Preference '%s' is not an nsresult type\n", aPref);
|
||||
return false;
|
||||
}
|
||||
|
||||
nsresult v = *sPrefs[i].mValue.mAsNsResult;
|
||||
if (v == NS_OK) {
|
||||
DOM_CAMERA_LOGI("Preference '%s' is not set\n", aPref);
|
||||
return false;
|
||||
}
|
||||
|
||||
DOM_CAMERA_LOGI("Preference '%s', got 0x%x\n", aPref, v);
|
||||
aVal = v;
|
||||
return true;
|
||||
}
|
67
dom/camera/CameraPreferences.h
Normal file
67
dom/camera/CameraPreferences.h
Normal file
@ -0,0 +1,67 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef DOM_CAMERA_CAMERAPREFERENCES_H
|
||||
#define DOM_CAMERA_CAMERAPREFERENCES_H
|
||||
|
||||
#include "nsString.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
template<class T> class StaticAutoPtr;
|
||||
|
||||
class CameraPreferences
|
||||
{
|
||||
public:
|
||||
static bool Initialize();
|
||||
static void Shutdown();
|
||||
|
||||
static bool GetPref(const char* aPref, nsACString& aVal);
|
||||
static bool GetPref(const char* aPref, nsresult& aVal);
|
||||
|
||||
protected:
|
||||
static const uint32_t kPrefNotFound = UINT32_MAX;
|
||||
static uint32_t PrefToIndex(const char* aPref);
|
||||
|
||||
static void PreferenceChanged(const char* aPref, void* aClosure);
|
||||
static nsresult UpdatePref(const char* aPref, nsresult& aVar);
|
||||
static nsresult UpdatePref(const char* aPref, nsACString& aVar);
|
||||
|
||||
enum PrefValueType {
|
||||
kPrefValueIsNSResult,
|
||||
kPrefValueIsCString
|
||||
};
|
||||
struct Pref {
|
||||
const char* const mPref;
|
||||
PrefValueType mValueType;
|
||||
union {
|
||||
// The 'mAsVoid' member must be first and is required to allow 'mValue'
|
||||
// to be initialized with any pointer type, as not all of our platforms
|
||||
// support the use of designated initializers; in their absence, only
|
||||
// the first element of a union can be statically initialized, and
|
||||
// 'void*' lets us stuff any pointer type into it.
|
||||
void* mAsVoid;
|
||||
StaticAutoPtr<nsCString>* mAsCString;
|
||||
nsresult* mAsNsResult;
|
||||
} mValue;
|
||||
};
|
||||
static Pref sPrefs[];
|
||||
|
||||
static StaticAutoPtr<nsCString> sPrefTestEnabled;
|
||||
static StaticAutoPtr<nsCString> sPrefHardwareTest;
|
||||
static StaticAutoPtr<nsCString> sPrefGonkParameters;
|
||||
|
||||
static nsresult sPrefCameraControlMethodErrorOverride;
|
||||
static nsresult sPrefCameraControlAsyncErrorOverride;
|
||||
|
||||
private:
|
||||
// static class only
|
||||
CameraPreferences();
|
||||
~CameraPreferences();
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // DOM_CAMERA_CAMERAPREFERENCES_H
|
@ -23,7 +23,7 @@
|
||||
#include "base/basictypes.h"
|
||||
#include "nsDebug.h"
|
||||
#include "mozilla/layers/TextureClient.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "CameraPreferences.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "GonkCameraControl.h"
|
||||
#include "GonkNativeWindow.h"
|
||||
@ -212,8 +212,8 @@ GonkCameraHardware::Connect(mozilla::nsGonkCameraControl* aTarget, uint32_t aCam
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const nsAdoptingCString& test =
|
||||
mozilla::Preferences::GetCString("camera.control.test.enabled");
|
||||
nsCString test;
|
||||
CameraPreferences::GetPref("camera.control.test.enabled", test);
|
||||
sp<GonkCameraHardware> cameraHardware;
|
||||
if (test.EqualsASCII("hardware")) {
|
||||
NS_WARNING("Using test Gonk hardware layer");
|
||||
|
@ -20,7 +20,7 @@
|
||||
|
||||
#include "CameraCommon.h"
|
||||
#include "GonkCameraControl.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "CameraPreferences.h"
|
||||
#include "TestGonkCameraControl.h"
|
||||
|
||||
using namespace mozilla;
|
||||
@ -117,13 +117,12 @@ ICameraControl::GetListOfCameras(nsTArray<nsString>& aList)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static const char* sTestModeEnabled = "camera.control.test.enabled";
|
||||
|
||||
// implementation-specific camera factory
|
||||
already_AddRefed<ICameraControl>
|
||||
ICameraControl::Create(uint32_t aCameraId)
|
||||
{
|
||||
const nsAdoptingCString& test = Preferences::GetCString(sTestModeEnabled);
|
||||
nsCString test;
|
||||
CameraPreferences::GetPref("camera.control.test.enabled", test);
|
||||
nsRefPtr<nsGonkCameraControl> control;
|
||||
if (test.EqualsASCII("control")) {
|
||||
NS_WARNING("Using test CameraControl layer");
|
||||
|
@ -15,13 +15,10 @@
|
||||
*/
|
||||
|
||||
#include "TestGonkCameraControl.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "CameraPreferences.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
static const char* sMethodErrorOverride = "camera.control.test.method.error";
|
||||
static const char* sAsyncErrorOverride = "camera.control.test.async.error";
|
||||
|
||||
TestGonkCameraControl::TestGonkCameraControl(uint32_t aCameraId)
|
||||
: nsGonkCameraControl(aCameraId)
|
||||
{
|
||||
@ -37,9 +34,8 @@ TestGonkCameraControl::~TestGonkCameraControl()
|
||||
nsresult
|
||||
TestGonkCameraControl::ForceMethodFailWithCodeInternal(const char* aFile, int aLine)
|
||||
{
|
||||
nsresult rv =
|
||||
static_cast<nsresult>(Preferences::GetInt(sMethodErrorOverride,
|
||||
static_cast<int32_t>(NS_OK)));
|
||||
nsresult rv = NS_OK;
|
||||
CameraPreferences::GetPref("camera.control.test.method.error", rv);
|
||||
if (NS_FAILED(rv)) {
|
||||
DOM_CAMERA_LOGI("[%s:%d] CameraControl method error override: 0x%x\n",
|
||||
aFile, aLine, rv);
|
||||
@ -50,9 +46,8 @@ TestGonkCameraControl::ForceMethodFailWithCodeInternal(const char* aFile, int aL
|
||||
nsresult
|
||||
TestGonkCameraControl::ForceAsyncFailWithCodeInternal(const char* aFile, int aLine)
|
||||
{
|
||||
nsresult rv =
|
||||
static_cast<nsresult>(Preferences::GetInt(sAsyncErrorOverride,
|
||||
static_cast<int32_t>(NS_OK)));
|
||||
nsresult rv = NS_OK;
|
||||
CameraPreferences::GetPref("camera.control.test.async.error", rv);
|
||||
if (NS_FAILED(rv)) {
|
||||
DOM_CAMERA_LOGI("[%s:%d] CameraControl async error override: 0x%x\n",
|
||||
aFile, aLine, rv);
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
#include "TestGonkCameraHardware.h"
|
||||
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "CameraPreferences.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
using namespace android;
|
||||
@ -52,7 +52,8 @@ TestGonkCameraHardware::Init()
|
||||
const nsCString
|
||||
TestGonkCameraHardware::TestCase()
|
||||
{
|
||||
const nsCString test = Preferences::GetCString("camera.control.test.hardware");
|
||||
nsCString test;
|
||||
CameraPreferences::GetPref("camera.control.test.hardware", test);
|
||||
return test;
|
||||
}
|
||||
|
||||
@ -77,7 +78,8 @@ TestGonkCameraHardware::GetExtraParameters()
|
||||
* may contain equals signs or semicolons. We don't enforce that here
|
||||
* so that we can also test correct handling of improperly-formatted values.
|
||||
*/
|
||||
const nsCString parameters = Preferences::GetCString("camera.control.test.hardware.gonk.parameters");
|
||||
nsCString parameters;
|
||||
CameraPreferences::GetPref("camera.control.test.hardware.gonk.parameters", parameters);
|
||||
DOM_CAMERA_LOGA("TestGonkCameraHardware : extra-parameters '%s'\n",
|
||||
parameters.get());
|
||||
return parameters;
|
||||
|
@ -9,13 +9,13 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
|
||||
|
||||
EXPORTS += [
|
||||
'CameraCommon.h',
|
||||
'CameraPreviewMediaStream.h',
|
||||
'CameraPreferences.h',
|
||||
'DOMCameraManager.h',
|
||||
'GonkCameraControl.h',
|
||||
]
|
||||
|
||||
SOURCES += [
|
||||
'CameraControlImpl.cpp',
|
||||
'CameraPreferences.cpp',
|
||||
'CameraPreviewMediaStream.cpp',
|
||||
'CameraRecorderProfiles.cpp',
|
||||
'DOMCameraCapabilities.cpp',
|
||||
|
@ -19,6 +19,10 @@ XPCOMUtils.defineLazyServiceGetter(this, "ppmm",
|
||||
"@mozilla.org/parentprocessmessagemanager;1",
|
||||
"nsIMessageBroadcaster");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "dataStoreService",
|
||||
"@mozilla.org/datastore-service;1",
|
||||
"nsIDataStoreService");
|
||||
|
||||
this.DataStoreChangeNotifier = {
|
||||
children: [],
|
||||
messages: [ "DataStore:Changed", "DataStore:RegisterForMessages",
|
||||
@ -65,17 +69,21 @@ this.DataStoreChangeNotifier = {
|
||||
|
||||
|
||||
receiveMessage: function(aMessage) {
|
||||
debug("receiveMessage");
|
||||
debug("receiveMessage ");
|
||||
|
||||
// No check has to be done when the message is 'child-process-shutdown'
|
||||
// because at this point the target is already disconnected from
|
||||
// nsFrameMessageManager, so that assertAppHasStatus will always fail.
|
||||
let prefName = 'dom.testing.datastore_enabled_for_hosted_apps';
|
||||
if (aMessage.name != 'child-process-shutdown' &&
|
||||
(Services.prefs.getPrefType(prefName) == Services.prefs.PREF_INVALID ||
|
||||
!Services.prefs.getBoolPref(prefName)) &&
|
||||
!aMessage.target.assertAppHasStatus(Ci.nsIPrincipal.APP_STATUS_CERTIFIED)) {
|
||||
return;
|
||||
// No check has to be done when the message is 'child-process-shutdown'.
|
||||
if (aMessage.name != "child-process-shutdown") {
|
||||
if (!("principal" in aMessage)) {
|
||||
return;
|
||||
}
|
||||
let secMan = Cc["@mozilla.org/scriptsecuritymanager;1"]
|
||||
.getService(Ci.nsIScriptSecurityManager);
|
||||
let uri = Services.io.newURI(aMessage.principal.origin, null, null);
|
||||
let principal = secMan.getAppCodebasePrincipal(uri,
|
||||
aMessage.principal.appId, aMessage.principal.isInBrowserElement);
|
||||
if (!principal || !dataStoreService.checkPermission(principal)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
switch (aMessage.name) {
|
||||
|
@ -100,7 +100,9 @@ DataStore.prototype = {
|
||||
cpmm.addMessageListener("DataStore:Changed:Return:OK", this);
|
||||
cpmm.sendAsyncMessage("DataStore:RegisterForMessages",
|
||||
{ store: this._name, owner: this._owner,
|
||||
innerWindowID: this._innerWindowID });
|
||||
innerWindowID: this._innerWindowID },
|
||||
null,
|
||||
this._window.document.nodePrincipal);
|
||||
},
|
||||
|
||||
observe: function(aSubject, aTopic, aData) {
|
||||
@ -110,7 +112,9 @@ DataStore.prototype = {
|
||||
|
||||
cpmm.removeMessageListener("DataStore:Changed:Return:OK", this);
|
||||
cpmm.sendAsyncMessage("DataStore:UnregisterForMessages",
|
||||
{ innerWindowID: this._innerWindowID });
|
||||
{ innerWindowID: this._innerWindowID },
|
||||
null,
|
||||
this._window.document.nodePrincipal);
|
||||
this._shuttingdown = true;
|
||||
this._db.close();
|
||||
}
|
||||
@ -336,7 +340,9 @@ DataStore.prototype = {
|
||||
cpmm.sendAsyncMessage("DataStore:Changed",
|
||||
{ store: this.name, owner: this._owner,
|
||||
message: { revisionId: aRevisionId, id: aId,
|
||||
operation: aOperation, owner: this._owner } } );
|
||||
operation: aOperation, owner: this._owner } },
|
||||
null,
|
||||
this._window.document.nodePrincipal);
|
||||
},
|
||||
|
||||
receiveMessage: function(aMessage) {
|
||||
|
@ -903,7 +903,7 @@ DataStoreService::GetDataStores(nsIDOMWindow* aWindow,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
rv = GetDataStoreInfos(aName, appId, stores);
|
||||
rv = GetDataStoreInfos(aName, appId, principal, stores);
|
||||
if (NS_FAILED(rv)) {
|
||||
RejectPromise(window, promise, rv);
|
||||
promise.forget(aDataStores);
|
||||
@ -1043,6 +1043,7 @@ DataStoreService::GetDataStoresResolve(nsPIDOMWindow* aWindow,
|
||||
nsresult
|
||||
DataStoreService::GetDataStoreInfos(const nsAString& aName,
|
||||
uint32_t aAppId,
|
||||
nsIPrincipal* aPrincipal,
|
||||
nsTArray<DataStoreInfo>& aStores)
|
||||
{
|
||||
AssertIsInMainProcess();
|
||||
@ -1064,15 +1065,7 @@ DataStoreService::GetDataStoreInfos(const nsAString& aName,
|
||||
return NS_ERROR_DOM_SECURITY_ERR;
|
||||
}
|
||||
|
||||
uint16_t status;
|
||||
rv = app->GetAppStatus(&status);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (status != nsIPrincipal::APP_STATUS_CERTIFIED &&
|
||||
!Preferences::GetBool("dom.testing.datastore_enabled_for_hosted_apps",
|
||||
false)) {
|
||||
if (!DataStoreService::CheckPermission(aPrincipal)) {
|
||||
return NS_ERROR_DOM_SECURITY_ERR;
|
||||
}
|
||||
|
||||
@ -1095,6 +1088,45 @@ DataStoreService::GetDataStoreInfos(const nsAString& aName,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
DataStoreService::CheckPermission(nsIPrincipal* aPrincipal)
|
||||
{
|
||||
// First of all, the general pref has to be turned on.
|
||||
bool enabled = false;
|
||||
Preferences::GetBool("dom.datastore.enabled", &enabled);
|
||||
if (!enabled) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Just for testing, we can enable DataStore for any kind of app.
|
||||
if (Preferences::GetBool("dom.testing.datastore_enabled_for_hosted_apps", false)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!aPrincipal) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint16_t status;
|
||||
if (NS_FAILED(aPrincipal->GetAppStatus(&status))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Only support DataStore API for certified apps for now.
|
||||
return status == nsIPrincipal::APP_STATUS_CERTIFIED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DataStoreService::CheckPermission(nsIPrincipal* aPrincipal,
|
||||
bool* aResult)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
*aResult = DataStoreService::CheckPermission(aPrincipal);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// This method is called when an app with DataStores is deleted.
|
||||
void
|
||||
DataStoreService::DeleteDataStores(uint32_t aAppId)
|
||||
@ -1311,7 +1343,7 @@ DataStoreService::GetDataStoresFromIPC(const nsAString& aName,
|
||||
}
|
||||
|
||||
nsTArray<DataStoreInfo> stores;
|
||||
rv = GetDataStoreInfos(aName, appId, stores);
|
||||
rv = GetDataStoreInfos(aName, appId, aPrincipal, stores);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -48,6 +48,8 @@ public:
|
||||
|
||||
static void Shutdown();
|
||||
|
||||
static bool CheckPermission(nsIPrincipal* principal);
|
||||
|
||||
nsresult GenerateUUID(nsAString& aID);
|
||||
|
||||
nsresult GetDataStoresFromIPC(const nsAString& aName,
|
||||
@ -82,6 +84,7 @@ private:
|
||||
const nsTArray<DataStoreInfo>& aStores);
|
||||
|
||||
nsresult GetDataStoreInfos(const nsAString& aName, uint32_t aAppId,
|
||||
nsIPrincipal* aPrincipal,
|
||||
nsTArray<DataStoreInfo>& aStores);
|
||||
|
||||
void DeleteDataStores(uint32_t aAppId);
|
||||
|
@ -6,8 +6,9 @@
|
||||
#include "nsISupports.idl"
|
||||
|
||||
interface nsIDOMWindow;
|
||||
interface nsIPrincipal;
|
||||
|
||||
[scriptable, uuid(0a050c4f-d292-4a14-8712-09bc1019840a)]
|
||||
[scriptable, uuid(43a731b9-0b5d-400a-8711-8c912c3c3572)]
|
||||
interface nsIDataStoreService : nsISupports
|
||||
{
|
||||
void installDataStore(in unsigned long appId,
|
||||
@ -24,4 +25,6 @@ interface nsIDataStoreService : nsISupports
|
||||
|
||||
nsISupports getDataStores(in nsIDOMWindow window,
|
||||
in DOMString name);
|
||||
|
||||
boolean checkPermission(in nsIPrincipal principal);
|
||||
};
|
||||
|
@ -10,8 +10,6 @@
|
||||
interface HTMLSelectElement : HTMLElement {
|
||||
[SetterThrows, Pure]
|
||||
attribute boolean autofocus;
|
||||
[Pref="dom.forms.autocomplete.experimental", SetterThrows, Pure]
|
||||
attribute DOMString autocomplete;
|
||||
[SetterThrows, Pure]
|
||||
attribute boolean disabled;
|
||||
[Pure]
|
||||
|
@ -126,8 +126,6 @@ TiledContentClient::UseTiledLayerBuffer(TiledBufferType aType)
|
||||
}
|
||||
|
||||
SharedFrameMetricsHelper::SharedFrameMetricsHelper()
|
||||
: mLastProgressiveUpdateWasLowPrecision(false)
|
||||
, mProgressiveUpdateWasInDanger(false)
|
||||
{
|
||||
MOZ_COUNT_CTOR(SharedFrameMetricsHelper);
|
||||
}
|
||||
@ -175,17 +173,6 @@ SharedFrameMetricsHelper::UpdateFromCompositorFrameMetrics(
|
||||
aCompositionBounds = ParentLayerRect(compositorMetrics.mCompositionBounds);
|
||||
aZoom = compositorMetrics.GetZoomToParent();
|
||||
|
||||
// Reset the checkerboard risk flag when switching to low precision
|
||||
// rendering.
|
||||
if (aLowPrecision && !mLastProgressiveUpdateWasLowPrecision) {
|
||||
// Skip low precision rendering until we're at risk of checkerboarding.
|
||||
if (!mProgressiveUpdateWasInDanger) {
|
||||
return true;
|
||||
}
|
||||
mProgressiveUpdateWasInDanger = false;
|
||||
}
|
||||
mLastProgressiveUpdateWasLowPrecision = aLowPrecision;
|
||||
|
||||
// Always abort updates if the resolution has changed. There's no use
|
||||
// in drawing at the incorrect resolution.
|
||||
if (!FuzzyEquals(compositorMetrics.GetZoom().scale, contentMetrics.GetZoom().scale)) {
|
||||
@ -205,13 +192,20 @@ SharedFrameMetricsHelper::UpdateFromCompositorFrameMetrics(
|
||||
return false;
|
||||
}
|
||||
|
||||
// When not a low precision pass and the page is in danger of checker boarding
|
||||
// abort update.
|
||||
if (!aLowPrecision && !mProgressiveUpdateWasInDanger) {
|
||||
if (AboutToCheckerboard(contentMetrics, compositorMetrics)) {
|
||||
mProgressiveUpdateWasInDanger = true;
|
||||
return true;
|
||||
}
|
||||
bool scrollUpdatePending = contentMetrics.GetScrollOffsetUpdated() &&
|
||||
contentMetrics.GetScrollGeneration() != compositorMetrics.GetScrollGeneration();
|
||||
// If scrollUpdatePending is true, then that means the content-side
|
||||
// metrics has a new scroll offset that is going to be forced into the
|
||||
// compositor but it hasn't gotten there yet.
|
||||
// Even though right now comparing the metrics might indicate we're
|
||||
// about to checkerboard (and that's true), the checkerboarding will
|
||||
// disappear as soon as the new scroll offset update is processed
|
||||
// on the compositor side. To avoid leaving things in a low-precision
|
||||
// paint, we need to detect and handle this case (bug 1026756).
|
||||
if (!aLowPrecision && !scrollUpdatePending && AboutToCheckerboard(contentMetrics, compositorMetrics)) {
|
||||
TILING_PRLOG_OBJ(("TILING: Checkerboard abort content %s\n", tmpstr.get()), contentMetrics);
|
||||
TILING_PRLOG_OBJ(("TILING: Checkerboard abort compositor %s\n", tmpstr.get()), compositorMetrics);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Abort drawing stale low-precision content if there's a more recent
|
||||
|
@ -336,9 +336,6 @@ public:
|
||||
*/
|
||||
bool AboutToCheckerboard(const FrameMetrics& aContentMetrics,
|
||||
const FrameMetrics& aCompositorMetrics);
|
||||
private:
|
||||
bool mLastProgressiveUpdateWasLowPrecision;
|
||||
bool mProgressiveUpdateWasInDanger;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -133,7 +133,7 @@ ThebesLayerComposite::RenderLayer(const nsIntRect& aClipRect)
|
||||
LayerManagerComposite::AutoAddMaskEffect autoMaskEffect(mMaskLayer, effectChain);
|
||||
AddBlendModeEffect(effectChain);
|
||||
|
||||
nsIntRegion visibleRegion = GetEffectiveVisibleRegion();
|
||||
const nsIntRegion& visibleRegion = GetEffectiveVisibleRegion();
|
||||
|
||||
TiledLayerProperties tiledLayerProps;
|
||||
if (mRequiresTiledProperties) {
|
||||
|
@ -755,7 +755,8 @@ NativeRegExpMacroAssembler::CheckNotBackReferenceIgnoreCase(int start_reg, Label
|
||||
masm.passABIArg(current_character);
|
||||
masm.passABIArg(current_position);
|
||||
masm.passABIArg(temp1);
|
||||
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, CaseInsensitiveCompareStrings));
|
||||
int (*fun)(const jschar*, const jschar*, size_t) = CaseInsensitiveCompareStrings;
|
||||
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, fun));
|
||||
masm.storeCallResult(temp0);
|
||||
|
||||
masm.PopRegsInMask(volatileRegs);
|
||||
@ -812,9 +813,12 @@ NativeRegExpMacroAssembler::CheckBitInTable(uint8_t *table, Label *on_bit_set)
|
||||
{
|
||||
IonSpew(SPEW_PREFIX "CheckBitInTable");
|
||||
|
||||
JS_ASSERT(mode_ != ASCII); // Ascii case not handled here.
|
||||
|
||||
masm.movePtr(ImmPtr(table), temp0);
|
||||
|
||||
// kTableMask is currently 127, so we need to mask even if the input is
|
||||
// Latin1. V8 has the same issue.
|
||||
static_assert(JSString::MAX_LATIN1_CHAR > kTableMask,
|
||||
"No need to mask if MAX_LATIN1_CHAR <= kTableMask");
|
||||
masm.move32(Imm32(kTableSize - 1), temp1);
|
||||
masm.and32(current_character, temp1);
|
||||
|
||||
@ -875,7 +879,15 @@ NativeRegExpMacroAssembler::LoadCurrentCharacterUnchecked(int cp_offset, int cha
|
||||
IonSpew(SPEW_PREFIX "LoadCurrentCharacterUnchecked(%d, %d)", cp_offset, characters);
|
||||
|
||||
if (mode_ == ASCII) {
|
||||
MOZ_ASSUME_UNREACHABLE("Ascii loading not implemented");
|
||||
BaseIndex address(input_end_pointer, current_position, TimesOne, cp_offset);
|
||||
if (characters == 4) {
|
||||
masm.load32(address, current_character);
|
||||
} else if (characters == 2) {
|
||||
masm.load16ZeroExtend(address, current_character);
|
||||
} else {
|
||||
JS_ASSERT(characters = 1);
|
||||
masm.load8ZeroExtend(address, current_character);
|
||||
}
|
||||
} else {
|
||||
JS_ASSERT(mode_ == JSCHAR);
|
||||
JS_ASSERT(characters <= 2);
|
||||
|
@ -40,8 +40,8 @@ namespace irregexp {
|
||||
|
||||
struct InputOutputData
|
||||
{
|
||||
const jschar *inputStart;
|
||||
const jschar *inputEnd;
|
||||
const void *inputStart;
|
||||
const void *inputEnd;
|
||||
|
||||
// Index into inputStart (in chars) at which to begin matching.
|
||||
size_t startIndex;
|
||||
@ -52,7 +52,8 @@ struct InputOutputData
|
||||
// for global regexps.
|
||||
int32_t result;
|
||||
|
||||
InputOutputData(const jschar *inputStart, const jschar *inputEnd,
|
||||
template <typename CharT>
|
||||
InputOutputData(const CharT *inputStart, const CharT *inputEnd,
|
||||
size_t startIndex, MatchPairs *matches)
|
||||
: inputStart(inputStart),
|
||||
inputEnd(inputEnd),
|
||||
|
@ -1666,9 +1666,10 @@ irregexp::CompilePattern(JSContext *cx, RegExpShared *shared, RegExpCompileData
|
||||
return compiler.Assemble(cx, assembler, node, data->capture_count);
|
||||
}
|
||||
|
||||
template <typename CharT>
|
||||
RegExpRunStatus
|
||||
irregexp::ExecuteCode(JSContext *cx, jit::JitCode *codeBlock,
|
||||
const jschar *chars, size_t start, size_t length, MatchPairs *matches)
|
||||
irregexp::ExecuteCode(JSContext *cx, jit::JitCode *codeBlock, const CharT *chars, size_t start,
|
||||
size_t length, MatchPairs *matches)
|
||||
{
|
||||
#ifdef JS_ION
|
||||
typedef void (*RegExpCodeSignature)(InputOutputData *);
|
||||
@ -1676,7 +1677,11 @@ irregexp::ExecuteCode(JSContext *cx, jit::JitCode *codeBlock,
|
||||
InputOutputData data(chars, chars + length, start, matches);
|
||||
|
||||
RegExpCodeSignature function = reinterpret_cast<RegExpCodeSignature>(codeBlock->raw());
|
||||
CALL_GENERATED_REGEXP(function, &data);
|
||||
|
||||
{
|
||||
JS::AutoSuppressGCAnalysis nogc;
|
||||
CALL_GENERATED_REGEXP(function, &data);
|
||||
}
|
||||
|
||||
return (RegExpRunStatus) data.result;
|
||||
#else
|
||||
@ -1684,6 +1689,14 @@ irregexp::ExecuteCode(JSContext *cx, jit::JitCode *codeBlock,
|
||||
#endif
|
||||
}
|
||||
|
||||
template RegExpRunStatus
|
||||
irregexp::ExecuteCode(JSContext *cx, jit::JitCode *codeBlock, const Latin1Char *chars, size_t start,
|
||||
size_t length, MatchPairs *matches);
|
||||
|
||||
template RegExpRunStatus
|
||||
irregexp::ExecuteCode(JSContext *cx, jit::JitCode *codeBlock, const jschar *chars, size_t start,
|
||||
size_t length, MatchPairs *matches);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Tree to graph conversion
|
||||
|
||||
|
@ -108,13 +108,15 @@ CompilePattern(JSContext *cx, RegExpShared *shared, RegExpCompileData *data,
|
||||
|
||||
// Note: this may return RegExpRunStatus_Error if an interrupt was requested
|
||||
// while the code was executing.
|
||||
template <typename CharT>
|
||||
RegExpRunStatus
|
||||
ExecuteCode(JSContext *cx, jit::JitCode *codeBlock,
|
||||
const jschar *chars, size_t start, size_t length, MatchPairs *matches);
|
||||
ExecuteCode(JSContext *cx, jit::JitCode *codeBlock, const CharT *chars, size_t start,
|
||||
size_t length, MatchPairs *matches);
|
||||
|
||||
template <typename CharT>
|
||||
RegExpRunStatus
|
||||
InterpretCode(JSContext *cx, const uint8_t *byteCode,
|
||||
const jschar *chars, size_t start, size_t length, MatchPairs *matches);
|
||||
InterpretCode(JSContext *cx, const uint8_t *byteCode, const CharT *chars, size_t start,
|
||||
size_t length, MatchPairs *matches);
|
||||
|
||||
#define FOR_EACH_NODE_TYPE(VISIT) \
|
||||
VISIT(End) \
|
||||
|
@ -104,13 +104,14 @@ Load16Aligned(const uint8_t* pc)
|
||||
|
||||
#define BYTECODE(name) case BC_##name:
|
||||
|
||||
template <typename CharT>
|
||||
RegExpRunStatus
|
||||
irregexp::InterpretCode(JSContext *cx, const uint8_t *byteCode,
|
||||
const jschar *chars, size_t current, size_t length, MatchPairs *matches)
|
||||
irregexp::InterpretCode(JSContext *cx, const uint8_t *byteCode, const CharT *chars, size_t current,
|
||||
size_t length, MatchPairs *matches)
|
||||
{
|
||||
const uint8_t* pc = byteCode;
|
||||
|
||||
jschar current_char = current ? chars[current - 1] : '\n';
|
||||
uint32_t current_char = current ? chars[current - 1] : '\n';
|
||||
|
||||
RegExpStackCursor stack(cx);
|
||||
|
||||
@ -226,8 +227,8 @@ irregexp::InterpretCode(JSContext *cx, const uint8_t *byteCode,
|
||||
if (pos + 2 > length) {
|
||||
pc = byteCode + Load32Aligned(pc + 4);
|
||||
} else {
|
||||
jschar next = chars[pos + 1];
|
||||
current_char = (chars[pos] | (next << (kBitsPerByte * sizeof(jschar))));
|
||||
CharT next = chars[pos + 1];
|
||||
current_char = (chars[pos] | (next << (kBitsPerByte * sizeof(CharT))));
|
||||
pc += BC_LOAD_2_CURRENT_CHARS_LENGTH;
|
||||
}
|
||||
break;
|
||||
@ -421,7 +422,7 @@ irregexp::InterpretCode(JSContext *cx, const uint8_t *byteCode,
|
||||
pc = byteCode + Load32Aligned(pc + 4);
|
||||
break;
|
||||
}
|
||||
if (CaseInsensitiveCompareStrings(chars + from, chars + current, len * 2)) {
|
||||
if (CaseInsensitiveCompareStrings(chars + from, chars + current, len * sizeof(CharT))) {
|
||||
current += len;
|
||||
pc += BC_CHECK_NOT_BACK_REF_NO_CASE_LENGTH;
|
||||
} else {
|
||||
@ -456,3 +457,11 @@ irregexp::InterpretCode(JSContext *cx, const uint8_t *byteCode,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template RegExpRunStatus
|
||||
irregexp::InterpretCode(JSContext *cx, const uint8_t *byteCode, const Latin1Char *chars, size_t current,
|
||||
size_t length, MatchPairs *matches);
|
||||
|
||||
template RegExpRunStatus
|
||||
irregexp::InterpretCode(JSContext *cx, const uint8_t *byteCode, const jschar *chars, size_t current,
|
||||
size_t length, MatchPairs *matches);
|
||||
|
@ -35,12 +35,13 @@
|
||||
using namespace js;
|
||||
using namespace js::irregexp;
|
||||
|
||||
template <typename CharT>
|
||||
int
|
||||
irregexp::CaseInsensitiveCompareStrings(const jschar *substring1, const jschar *substring2,
|
||||
irregexp::CaseInsensitiveCompareStrings(const CharT *substring1, const CharT *substring2,
|
||||
size_t byteLength)
|
||||
{
|
||||
JS_ASSERT(byteLength % 2 == 0);
|
||||
size_t length = byteLength >> 1;
|
||||
JS_ASSERT(byteLength % sizeof(CharT) == 0);
|
||||
size_t length = byteLength / sizeof(CharT);
|
||||
|
||||
for (size_t i = 0; i < length; i++) {
|
||||
jschar c1 = substring1[i];
|
||||
@ -56,6 +57,14 @@ irregexp::CaseInsensitiveCompareStrings(const jschar *substring1, const jschar *
|
||||
return 1;
|
||||
}
|
||||
|
||||
template int
|
||||
irregexp::CaseInsensitiveCompareStrings(const Latin1Char *substring1, const Latin1Char *substring2,
|
||||
size_t byteLength);
|
||||
|
||||
template int
|
||||
irregexp::CaseInsensitiveCompareStrings(const jschar *substring1, const jschar *substring2,
|
||||
size_t byteLength);
|
||||
|
||||
InterpretedRegExpMacroAssembler::InterpretedRegExpMacroAssembler(LifoAlloc *alloc, RegExpShared *shared,
|
||||
size_t numSavedRegisters)
|
||||
: RegExpMacroAssembler(*alloc, shared, numSavedRegisters),
|
||||
|
@ -217,8 +217,9 @@ class MOZ_STACK_CLASS RegExpMacroAssembler
|
||||
RegExpShared *shared;
|
||||
};
|
||||
|
||||
template <typename CharT>
|
||||
int
|
||||
CaseInsensitiveCompareStrings(const jschar *substring1, const jschar *substring2, size_t byteLength);
|
||||
CaseInsensitiveCompareStrings(const CharT *substring1, const CharT *substring2, size_t byteLength);
|
||||
|
||||
class MOZ_STACK_CLASS InterpretedRegExpMacroAssembler : public RegExpMacroAssembler
|
||||
{
|
||||
|
109
js/src/jit-test/tests/debug/Debugger-debuggees-28.js
Normal file
109
js/src/jit-test/tests/debug/Debugger-debuggees-28.js
Normal file
@ -0,0 +1,109 @@
|
||||
// Test that on->off->on and off->on->off toggles don't crash.
|
||||
|
||||
function addRemove(dbg, g) {
|
||||
dbg.addDebuggee(g);
|
||||
var f = dbg.getNewestFrame();
|
||||
while (f)
|
||||
f = f.older;
|
||||
dbg.removeDebuggee(g);
|
||||
}
|
||||
|
||||
function removeAdd(dbg, g) {
|
||||
dbg.removeDebuggee(g);
|
||||
dbg.addDebuggee(g);
|
||||
var f = dbg.getNewestFrame();
|
||||
while (f)
|
||||
f = f.older;
|
||||
}
|
||||
|
||||
function newGlobalDebuggerPair(toggleSeq) {
|
||||
var g = newGlobal();
|
||||
var dbg = new Debugger;
|
||||
|
||||
if (toggleSeq == removeAdd)
|
||||
dbg.addDebuggee(g);
|
||||
|
||||
g.eval("" + function f() { return g(); });
|
||||
g.eval("" + function g() { return h(); });
|
||||
g.eval("line0 = Error().lineNumber;");
|
||||
g.eval("" + function h() {
|
||||
for (var i = 0; i < 100; i++)
|
||||
interruptIf(i == 95);
|
||||
debugger;
|
||||
return i;
|
||||
});
|
||||
|
||||
setInterruptCallback(function () { return true; });
|
||||
|
||||
return [g, dbg];
|
||||
}
|
||||
|
||||
function testInterrupt(toggleSeq) {
|
||||
var [g, dbg] = newGlobalDebuggerPair(toggleSeq);
|
||||
|
||||
setInterruptCallback(function () {
|
||||
toggleSeq(dbg, g);
|
||||
return true;
|
||||
});
|
||||
|
||||
assertEq(g.f(), 100);
|
||||
}
|
||||
|
||||
function testPrologue(toggleSeq) {
|
||||
var [g, dbg] = newGlobalDebuggerPair(toggleSeq);
|
||||
|
||||
dbg.onEnterFrame = function (f) {
|
||||
if (f.callee && f.callee.name == "h")
|
||||
toggleSeq(dbg, g);
|
||||
};
|
||||
|
||||
assertEq(g.f(), 100);
|
||||
}
|
||||
|
||||
function testEpilogue(toggleSeq) {
|
||||
var [g, dbg] = newGlobalDebuggerPair(toggleSeq);
|
||||
|
||||
dbg.onEnterFrame = function (f) {
|
||||
if (f.callee && f.callee.name == "h") {
|
||||
f.onPop = function () {
|
||||
toggleSeq(dbg, g);
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
assertEq(g.f(), 100);
|
||||
}
|
||||
|
||||
function testTrap(toggleSeq) {
|
||||
var [g, dbg] = newGlobalDebuggerPair(toggleSeq);
|
||||
|
||||
dbg.onEnterFrame = function (f) {
|
||||
if (f.callee && f.callee.name == "h") {
|
||||
var offs = f.script.getLineOffsets(g.line0 + 2);
|
||||
assertEq(offs.length > 0, true);
|
||||
f.script.setBreakpoint(offs[0], { hit: function () {
|
||||
toggleSeq(dbg, g);
|
||||
}});
|
||||
}
|
||||
};
|
||||
|
||||
assertEq(g.f(), 100);
|
||||
}
|
||||
|
||||
function testDebugger(toggleSeq) {
|
||||
var [g, dbg] = newGlobalDebuggerPair(toggleSeq);
|
||||
|
||||
dbg.onDebuggerStatement = function () {
|
||||
toggleSeq(dbg, g);
|
||||
};
|
||||
|
||||
assertEq(g.f(), 100);
|
||||
}
|
||||
|
||||
testInterrupt(addRemove);
|
||||
testInterrupt(removeAdd);
|
||||
|
||||
testPrologue(removeAdd);
|
||||
testEpilogue(removeAdd);
|
||||
testTrap(removeAdd);
|
||||
testDebugger(removeAdd);
|
@ -13,3 +13,21 @@ assertEq(re.source, "foo[bB]a\\r\u1200");
|
||||
assertEq(re.multiline, true);
|
||||
assertEq(re.ignoreCase, true);
|
||||
assertEq(re.sticky, false);
|
||||
|
||||
re = /b[aA]r/;
|
||||
|
||||
// Latin1
|
||||
assertEq(toLatin1("foobAr1234").search(re), 3);
|
||||
assertEq(toLatin1("bar1234").search(re), 0);
|
||||
assertEq(toLatin1("foobbr1234").search(re), -1);
|
||||
|
||||
// TwoByte
|
||||
assertEq("foobAr1234\u1200".search(re), 3);
|
||||
assertEq("bar1234\u1200".search(re), 0);
|
||||
assertEq("foobbr1234\u1200".search(re), -1);
|
||||
|
||||
re = /abcdefghijklm[0-5]/;
|
||||
assertEq(toLatin1("1abcdefghijklm4").search(re), 1);
|
||||
assertEq("\u12001abcdefghijklm0".search(re), 2);
|
||||
assertEq(toLatin1("1abcdefghijklm8").search(re), -1);
|
||||
assertEq("\u12001abcdefghijklm8".search(re), -1);
|
||||
|
126
js/src/jit-test/tests/latin1/replace.js
Normal file
126
js/src/jit-test/tests/latin1/replace.js
Normal file
@ -0,0 +1,126 @@
|
||||
function testDollarReplacement() {
|
||||
// Latin1 input, pat and replacement
|
||||
var s = toLatin1("Foobarbaz123");
|
||||
var pat = toLatin1("bar");
|
||||
assertEq(s.replace(pat, toLatin1("AA")), "FooAAbaz123");
|
||||
assertEq(s.replace(pat, toLatin1("A$$A")), "FooA$Abaz123");
|
||||
assertEq(s.replace(pat, toLatin1("A$`A")), "FooAFooAbaz123");
|
||||
assertEq(s.replace(pat, toLatin1("A$&A")), "FooAbarAbaz123");
|
||||
assertEq(s.replace(pat, toLatin1("A$'A")), "FooAbaz123Abaz123");
|
||||
|
||||
// Latin1 input and pat, TwoByte replacement
|
||||
assertEq(s.replace(pat, "A\u1200"), "FooA\u1200baz123");
|
||||
assertEq(s.replace(pat, "A$$\u1200"), "FooA$\u1200baz123");
|
||||
assertEq(s.replace(pat, "A$`\u1200"), "FooAFoo\u1200baz123");
|
||||
assertEq(s.replace(pat, "A$&\u1200"), "FooAbar\u1200baz123");
|
||||
assertEq(s.replace(pat, "A$'\u1200"), "FooAbaz123\u1200baz123");
|
||||
|
||||
// TwoByte input, Latin1 pat and replacement
|
||||
s = "Foobarbaz123\u1200";
|
||||
assertEq(s.replace(pat, toLatin1("A")), "FooAbaz123\u1200");
|
||||
assertEq(s.replace(pat, toLatin1("A$$")), "FooA$baz123\u1200");
|
||||
assertEq(s.replace(pat, toLatin1("A$`")), "FooAFoobaz123\u1200");
|
||||
assertEq(s.replace(pat, toLatin1("A$&")), "FooAbarbaz123\u1200");
|
||||
assertEq(s.replace(pat, toLatin1("A$'")), "FooAbaz123\u1200baz123\u1200");
|
||||
|
||||
// TwoByte input and pat, Latin1 replacement
|
||||
s = "Foobar\u1200baz123";
|
||||
pat += "\u1200";
|
||||
assertEq(s.replace(pat, toLatin1("AB")), "FooABbaz123");
|
||||
assertEq(s.replace(pat, toLatin1("A$$B")), "FooA$Bbaz123");
|
||||
assertEq(s.replace(pat, toLatin1("A$`B")), "FooAFooBbaz123");
|
||||
assertEq(s.replace(pat, toLatin1("A$&B")), "FooAbar\u1200Bbaz123");
|
||||
assertEq(s.replace(pat, toLatin1("A$'B")), "FooAbaz123Bbaz123");
|
||||
|
||||
// TwoByte input, pat and replacement
|
||||
assertEq(s.replace(pat, "A\u1300"), "FooA\u1300baz123");
|
||||
assertEq(s.replace(pat, "A$$\u1300"), "FooA$\u1300baz123");
|
||||
assertEq(s.replace(pat, "A$`\u1300"), "FooAFoo\u1300baz123");
|
||||
assertEq(s.replace(pat, "A$&\u1300"), "FooAbar\u1200\u1300baz123");
|
||||
assertEq(s.replace(pat, "A$'\u1300"), "FooAbaz123\u1300baz123");
|
||||
}
|
||||
testDollarReplacement();
|
||||
|
||||
function testRegExp() {
|
||||
var s = toLatin1("Foobar123bar234");
|
||||
assertEq(s.replace(/bar\d\d/, "456"), "Foo4563bar234");
|
||||
|
||||
// Latin1 input and replacement
|
||||
var re1 = /bar\d\d/;
|
||||
var re2 = /bar\d\d/g;
|
||||
assertEq(s.replace(re1, toLatin1("789")), "Foo7893bar234");
|
||||
assertEq(s.replace(re2, toLatin1("789\u00ff")), "Foo789\u00ff3789\u00ff4");
|
||||
|
||||
// Latin1 input, TwoByte replacement
|
||||
assertEq(s.replace(re1, "789\u1200"), "Foo789\u12003bar234");
|
||||
assertEq(s.replace(re2, "789\u1200"), "Foo789\u12003789\u12004");
|
||||
|
||||
// TwoByte input, Latin1 replacement
|
||||
s += "\u1200";
|
||||
assertEq(s.replace(re1, toLatin1("7890")), "Foo78903bar234\u1200");
|
||||
assertEq(s.replace(re2, toLatin1("7890\u00ff")), "Foo7890\u00ff37890\u00ff4\u1200");
|
||||
|
||||
// TwoByte input and replacement
|
||||
assertEq(s.replace(re1, "789\u1200"), "Foo789\u12003bar234\u1200");
|
||||
assertEq(s.replace(re2, "789\u1200"), "Foo789\u12003789\u12004\u1200");
|
||||
}
|
||||
testRegExp();
|
||||
|
||||
function testRegExpDollar() {
|
||||
var s = toLatin1("Foobar123bar2345");
|
||||
|
||||
// Latin1 input and replacement
|
||||
var re1 = /bar\d\d/;
|
||||
var re2 = /bar(\d\d)/g;
|
||||
assertEq(s.replace(re1, toLatin1("--$&--")), "Foo--bar12--3bar2345");
|
||||
assertEq(s.replace(re2, toLatin1("--$'\u00ff--")), "Foo--3bar2345\xFF--3--45\xFF--45");
|
||||
assertEq(s.replace(re2, toLatin1("--$`--")), "Foo--Foo--3--Foobar123--45");
|
||||
|
||||
// Latin1 input, TwoByte replacement
|
||||
assertEq(s.replace(re1, "\u1200$$"), "Foo\u1200$3bar2345");
|
||||
assertEq(s.replace(re2, "\u1200$1"), "Foo\u1200123\u12002345");
|
||||
assertEq(s.replace(re2, "\u1200$'"), "Foo\u12003bar23453\u12004545");
|
||||
|
||||
// TwoByte input, Latin1 replacement
|
||||
s += "\u1200";
|
||||
assertEq(s.replace(re1, toLatin1("**$&**")), "Foo**bar12**3bar2345\u1200");
|
||||
assertEq(s.replace(re2, toLatin1("**$1**")), "Foo**12**3**23**45\u1200");
|
||||
assertEq(s.replace(re2, toLatin1("**$`**")), "Foo**Foo**3**Foobar123**45\u1200");
|
||||
assertEq(s.replace(re2, toLatin1("**$'$$**")), "Foo**3bar2345\u1200$**3**45\u1200$**45\u1200");
|
||||
|
||||
// TwoByte input and replacement
|
||||
assertEq(s.replace(re1, "**$&**\ueeee"), "Foo**bar12**\ueeee3bar2345\u1200");
|
||||
assertEq(s.replace(re2, "**$1**\ueeee"), "Foo**12**\ueeee3**23**\ueeee45\u1200");
|
||||
assertEq(s.replace(re2, "\ueeee**$`**"), "Foo\ueeee**Foo**3\ueeee**Foobar123**45\u1200");
|
||||
assertEq(s.replace(re2, "\ueeee**$'$$**"), "Foo\ueeee**3bar2345\u1200$**3\ueeee**45\u1200$**45\u1200");
|
||||
}
|
||||
testRegExpDollar();
|
||||
|
||||
function testFlattenPattern() {
|
||||
var s = "abcdef[g]abc";
|
||||
|
||||
// Latin1 pattern
|
||||
assertEq(s.replace(toLatin1("def[g]"), "--$&--", "gi"), "abc--def[g]--abc");
|
||||
|
||||
// TwoByte pattern
|
||||
s = "abcdef[g]\u1200abc";
|
||||
assertEq(s.replace("def[g]\u1200", "++$&++", "gi"), "abc++def[g]\u1200++abc");
|
||||
}
|
||||
testFlattenPattern();
|
||||
|
||||
function testReplaceEmpty() {
|
||||
// Latin1
|
||||
var s = toLatin1("--abcdefghijkl--abcdefghijkl--abcdefghijkl--abcdefghijkl");
|
||||
assertEq(s.replace(/abcd[eE]/g, ""), "--fghijkl--fghijkl--fghijkl--fghijkl");
|
||||
|
||||
s = "--abcdEf--";
|
||||
assertEq(s.replace(/abcd[eE]/g, ""), "--f--");
|
||||
|
||||
// TwoByte
|
||||
s = "--abcdefghijkl--abcdefghijkl--abcdefghijkl--abcdefghijkl\u1200";
|
||||
assertEq(s.replace(/abcd[eE]/g, ""), "--fghijkl--fghijkl--fghijkl--fghijkl\u1200");
|
||||
|
||||
s = "--abcdEf--\u1200";
|
||||
assertEq(s.replace(/abcd[eE]/g, ""), "--f--\u1200");
|
||||
}
|
||||
testReplaceEmpty();
|
@ -50,23 +50,21 @@ struct DebugModeOSREntry
|
||||
#ifdef DEBUG
|
||||
MOZ_ASSERT(pcOffset == icEntry.pcOffset());
|
||||
MOZ_ASSERT(frameKind == icEntry.kind());
|
||||
#endif
|
||||
}
|
||||
|
||||
// Assert that if we have a NonOp ICEntry, that there are no unsynced
|
||||
// slots, since such a recompile could have only been triggered from
|
||||
// either an interrupt check or a debug trap handler.
|
||||
//
|
||||
// If triggered from an interrupt check, the stack should be fully
|
||||
// synced.
|
||||
//
|
||||
// If triggered from a debug trap handler, we must be recompiling for
|
||||
// toggling debug mode on->off, in which case the old baseline script
|
||||
// should have fully synced stack at every bytecode.
|
||||
if (frameKind == ICEntry::Kind_NonOp) {
|
||||
PCMappingSlotInfo slotInfo;
|
||||
jsbytecode *pc = script->offsetToPC(pcOffset);
|
||||
oldBaselineScript->nativeCodeForPC(script, pc, &slotInfo);
|
||||
MOZ_ASSERT(slotInfo.numUnsynced() == 0);
|
||||
}
|
||||
DebugModeOSREntry(JSScript *script, BaselineDebugModeOSRInfo *info)
|
||||
: script(script),
|
||||
oldBaselineScript(script->baselineScript()),
|
||||
oldStub(nullptr),
|
||||
newStub(nullptr),
|
||||
recompInfo(nullptr),
|
||||
pcOffset(script->pcToOffset(info->pc)),
|
||||
frameKind(info->frameKind)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
MOZ_ASSERT(pcOffset == script->pcToOffset(info->pc));
|
||||
MOZ_ASSERT(frameKind == info->frameKind);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -99,7 +97,7 @@ struct DebugModeOSREntry
|
||||
}
|
||||
|
||||
BaselineDebugModeOSRInfo *takeRecompInfo() {
|
||||
MOZ_ASSERT(recompInfo);
|
||||
MOZ_ASSERT(needsRecompileInfo() && recompInfo);
|
||||
BaselineDebugModeOSRInfo *tmp = recompInfo;
|
||||
recompInfo = nullptr;
|
||||
return tmp;
|
||||
@ -175,11 +173,24 @@ CollectOnStackScripts(JSContext *cx, const JitActivationIterator &activation,
|
||||
switch (iter.type()) {
|
||||
case JitFrame_BaselineJS: {
|
||||
JSScript *script = iter.script();
|
||||
uint8_t *retAddr = iter.returnAddressToFp();
|
||||
ICEntry &entry = script->baselineScript()->icEntryFromReturnAddress(retAddr);
|
||||
|
||||
if (!entries.append(DebugModeOSREntry(script, entry)))
|
||||
return false;
|
||||
if (BaselineDebugModeOSRInfo *info = iter.baselineFrame()->getDebugModeOSRInfo()) {
|
||||
// If patching a previously patched yet unpopped frame, we can
|
||||
// use the BaselineDebugModeOSRInfo on the frame directly to
|
||||
// patch. Indeed, we cannot use iter.returnAddressToFp(), as
|
||||
// it points into the debug mode OSR handler and cannot be
|
||||
// used to look up a corresponding ICEntry.
|
||||
//
|
||||
// See cases F and G in PatchBaselineFrameForDebugMode.
|
||||
if (!entries.append(DebugModeOSREntry(script, info)))
|
||||
return false;
|
||||
} else {
|
||||
// Otherwise, use the return address to look up the ICEntry.
|
||||
uint8_t *retAddr = iter.returnAddressToFp();
|
||||
ICEntry &entry = script->baselineScript()->icEntryFromReturnAddress(retAddr);
|
||||
if (!entries.append(DebugModeOSREntry(script, entry)))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (entries.back().needsRecompileInfo()) {
|
||||
if (!entries.back().allocateRecompileInfo(cx))
|
||||
@ -284,6 +295,13 @@ PatchBaselineFramesForDebugMode(JSContext *cx, const JitActivationIterator &acti
|
||||
// D. From the debug prologue.
|
||||
// E. From the debug epilogue.
|
||||
//
|
||||
// Off to On to Off:
|
||||
// F. Undo case B above on previously patched yet unpopped frames.
|
||||
//
|
||||
// On to Off to On:
|
||||
// G. Undo cases B, C, D, or E above on previously patched yet unpopped
|
||||
// frames.
|
||||
//
|
||||
// In general, we patch the return address from the VM call to return to a
|
||||
// "continuation fixer" to fix up machine state (registers and stack
|
||||
// state). Specifics on what need to be done are documented below.
|
||||
@ -291,7 +309,7 @@ PatchBaselineFramesForDebugMode(JSContext *cx, const JitActivationIterator &acti
|
||||
|
||||
IonCommonFrameLayout *prev = nullptr;
|
||||
size_t entryIndex = *start;
|
||||
DebugOnly<bool> expectedDebugMode = cx->compartment()->debugMode();
|
||||
bool expectedDebugMode = cx->compartment()->debugMode();
|
||||
|
||||
for (JitFrameIterator iter(activation); !iter.done(); ++iter) {
|
||||
DebugModeOSREntry &entry = entries[entryIndex];
|
||||
@ -332,12 +350,33 @@ PatchBaselineFramesForDebugMode(JSContext *cx, const JitActivationIterator &acti
|
||||
break;
|
||||
}
|
||||
|
||||
bool popFrameReg;
|
||||
// Cases F and G above.
|
||||
//
|
||||
// We undo a previous recompile by handling cases B, C, D, and E
|
||||
// like normal, except that we retrieved the pc information via
|
||||
// the previous OSR debug info stashed on the frame.
|
||||
if (BaselineDebugModeOSRInfo *info = iter.baselineFrame()->getDebugModeOSRInfo()) {
|
||||
MOZ_ASSERT(info->pc == pc);
|
||||
MOZ_ASSERT(info->frameKind == kind);
|
||||
|
||||
// Case G, might need to undo B, C, D, or E.
|
||||
MOZ_ASSERT_IF(expectedDebugMode, (kind == ICEntry::Kind_CallVM ||
|
||||
kind == ICEntry::Kind_DebugTrap ||
|
||||
kind == ICEntry::Kind_DebugPrologue ||
|
||||
kind == ICEntry::Kind_DebugEpilogue));
|
||||
// Case F, should only need to undo case B.
|
||||
MOZ_ASSERT_IF(!expectedDebugMode, kind == ICEntry::Kind_CallVM);
|
||||
|
||||
// We will have allocated a new recompile info, so delete the
|
||||
// existing one.
|
||||
iter.baselineFrame()->deleteDebugModeOSRInfo();
|
||||
}
|
||||
|
||||
// The RecompileInfo must already be allocated so that this
|
||||
// function may be infallible.
|
||||
BaselineDebugModeOSRInfo *recompInfo = entry.takeRecompInfo();
|
||||
|
||||
bool popFrameReg;
|
||||
switch (kind) {
|
||||
case ICEntry::Kind_CallVM:
|
||||
// Case B above.
|
||||
|
@ -207,6 +207,16 @@ JitFrameIterator::script() const
|
||||
return script;
|
||||
}
|
||||
|
||||
uint8_t *
|
||||
JitFrameIterator::resumeAddressToFp() const
|
||||
{
|
||||
// If we are settled on a patched BaselineFrame due to debug mode OSR, get
|
||||
// the real return address via the stashed DebugModeOSRInfo.
|
||||
if (isBaselineJS() && baselineFrame()->getDebugModeOSRInfo())
|
||||
return baselineFrame()->debugModeOSRInfo()->resumeAddr;
|
||||
return returnAddressToFp();
|
||||
}
|
||||
|
||||
void
|
||||
JitFrameIterator::baselineScriptAndPc(JSScript **scriptRes, jsbytecode **pcRes) const
|
||||
{
|
||||
@ -214,7 +224,7 @@ JitFrameIterator::baselineScriptAndPc(JSScript **scriptRes, jsbytecode **pcRes)
|
||||
JSScript *script = this->script();
|
||||
if (scriptRes)
|
||||
*scriptRes = script;
|
||||
uint8_t *retAddr = returnAddressToFp();
|
||||
uint8_t *retAddr = resumeAddressToFp();
|
||||
|
||||
// If we have unwound the scope due to exception handling to a different
|
||||
// pc, the frame should behave as if it were settled on that pc.
|
||||
@ -223,11 +233,6 @@ JitFrameIterator::baselineScriptAndPc(JSScript **scriptRes, jsbytecode **pcRes)
|
||||
return;
|
||||
}
|
||||
|
||||
// If we are in the middle of a recompile handler, get the real return
|
||||
// address as stashed in the RecompileInfo.
|
||||
if (BaselineDebugModeOSRInfo *info = baselineFrame()->getDebugModeOSRInfo())
|
||||
retAddr = info->resumeAddr;
|
||||
|
||||
if (pcRes) {
|
||||
// If the return address is into the prologue entry address or just
|
||||
// after the debug prologue, then assume start of script.
|
||||
|
@ -191,6 +191,10 @@ class JitFrameIterator
|
||||
return returnAddressToFp_;
|
||||
}
|
||||
|
||||
// Returns the resume address. As above, except taking
|
||||
// BaselineDebugModeOSRInfo into account, if present.
|
||||
uint8_t *resumeAddressToFp() const;
|
||||
|
||||
// Previous frame information extracted from the current frame.
|
||||
inline size_t prevFrameLocalSize() const;
|
||||
inline FrameType prevType() const;
|
||||
|
@ -1491,8 +1491,8 @@ Simulator::setCallResult(int64_t res)
|
||||
int
|
||||
Simulator::readW(int32_t addr, SimInstruction *instr)
|
||||
{
|
||||
// The regexp engines emit unaligned loads, so we don't check for them here
|
||||
// like the other methods below.
|
||||
// The regexp engine emits unaligned loads, so we don't check for them here
|
||||
// like most of the other methods do.
|
||||
intptr_t *ptr = reinterpret_cast<intptr_t*>(addr);
|
||||
return *ptr;
|
||||
}
|
||||
@ -1512,13 +1512,10 @@ Simulator::writeW(int32_t addr, int value, SimInstruction *instr)
|
||||
uint16_t
|
||||
Simulator::readHU(int32_t addr, SimInstruction *instr)
|
||||
{
|
||||
if ((addr & 1) == 0) {
|
||||
uint16_t *ptr = reinterpret_cast<uint16_t*>(addr);
|
||||
return *ptr;
|
||||
}
|
||||
printf("Unaligned unsigned halfword read at 0x%08x, pc=%p\n", addr, instr);
|
||||
MOZ_CRASH();
|
||||
return 0;
|
||||
// The regexp engine emits unaligned loads, so we don't check for them here
|
||||
// like most of the other methods do.
|
||||
uint16_t *ptr = reinterpret_cast<uint16_t*>(addr);
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
int16_t
|
||||
|
@ -1764,7 +1764,7 @@ JS_GetClassPrototype(JSContext *cx, JSProtoKey key, JS::MutableHandle<JSObject*>
|
||||
namespace JS {
|
||||
|
||||
/*
|
||||
* Determine if the given object is an instance or prototype for a standard
|
||||
* Determine if the given object is an instance/prototype/constructor for a standard
|
||||
* class. If so, return the associated JSProtoKey. If not, return JSProto_Null.
|
||||
*/
|
||||
|
||||
@ -1777,6 +1777,9 @@ IdentifyStandardPrototype(JSObject *obj);
|
||||
extern JS_PUBLIC_API(JSProtoKey)
|
||||
IdentifyStandardInstanceOrPrototype(JSObject *obj);
|
||||
|
||||
extern JS_PUBLIC_API(JSProtoKey)
|
||||
IdentifyStandardConstructor(JSObject *obj);
|
||||
|
||||
} /* namespace JS */
|
||||
|
||||
extern JS_PUBLIC_API(JSProtoKey)
|
||||
|
@ -3439,6 +3439,26 @@ JS::IdentifyStandardInstanceOrPrototype(JSObject *obj)
|
||||
return JSCLASS_CACHED_PROTO_KEY(obj->getClass());
|
||||
}
|
||||
|
||||
JSProtoKey
|
||||
JS::IdentifyStandardConstructor(JSObject *obj)
|
||||
{
|
||||
// Note that NATIVE_CTOR does not imply that we are a standard constructor,
|
||||
// but the converse is true (at least until we start having self-hosted
|
||||
// constructors for standard classes). This lets us avoid a costly loop for
|
||||
// many functions (which, depending on the call site, may be the common case).
|
||||
if (!obj->is<JSFunction>() || !(obj->as<JSFunction>().flags() & JSFunction::NATIVE_CTOR))
|
||||
return JSProto_Null;
|
||||
|
||||
GlobalObject &global = obj->global();
|
||||
for (size_t k = 0; k < JSProto_LIMIT; ++k) {
|
||||
JSProtoKey key = static_cast<JSProtoKey>(k);
|
||||
if (global.getConstructor(key) == ObjectValue(*obj))
|
||||
return key;
|
||||
}
|
||||
|
||||
return JSProto_Null;
|
||||
}
|
||||
|
||||
bool
|
||||
js::FindClassObject(ExclusiveContext *cx, MutableHandleObject protop, const Class *clasp)
|
||||
{
|
||||
|
321
js/src/jsstr.cpp
321
js/src/jsstr.cpp
@ -2020,25 +2020,40 @@ class MOZ_STACK_CLASS StringRegExpGuard
|
||||
*/
|
||||
static const size_t MAX_FLAT_PAT_LEN = 256;
|
||||
|
||||
static JSAtom *
|
||||
flattenPattern(JSContext *cx, JSAtom *patstr)
|
||||
template <typename CharT>
|
||||
static bool
|
||||
flattenPattern(StringBuffer &sb, const CharT *chars, size_t len)
|
||||
{
|
||||
StringBuffer sb(cx);
|
||||
if (!sb.reserve(patstr->length()))
|
||||
return nullptr;
|
||||
|
||||
static const jschar ESCAPE_CHAR = '\\';
|
||||
const jschar *chars = patstr->chars();
|
||||
size_t len = patstr->length();
|
||||
for (const jschar *it = chars; it != chars + len; ++it) {
|
||||
static const char ESCAPE_CHAR = '\\';
|
||||
for (const CharT *it = chars; it < chars + len; ++it) {
|
||||
if (IsRegExpMetaChar(*it)) {
|
||||
if (!sb.append(ESCAPE_CHAR) || !sb.append(*it))
|
||||
return nullptr;
|
||||
return false;
|
||||
} else {
|
||||
if (!sb.append(*it))
|
||||
return nullptr;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static JSAtom *
|
||||
flattenPattern(JSContext *cx, JSAtom *pat)
|
||||
{
|
||||
StringBuffer sb(cx);
|
||||
if (!sb.reserve(pat->length()))
|
||||
return nullptr;
|
||||
|
||||
if (pat->hasLatin1Chars()) {
|
||||
AutoCheckCannotGC nogc;
|
||||
if (!flattenPattern(sb, pat->latin1Chars(nogc), pat->length()))
|
||||
return nullptr;
|
||||
} else {
|
||||
AutoCheckCannotGC nogc;
|
||||
if (!flattenPattern(sb, pat->twoByteChars(nogc), pat->length()))
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return sb.finishAtom();
|
||||
}
|
||||
|
||||
@ -2455,6 +2470,18 @@ class RopeBuilder {
|
||||
|
||||
namespace {
|
||||
|
||||
template <typename CharT>
|
||||
static uint32_t
|
||||
FindDollarIndex(const CharT *chars, size_t length)
|
||||
{
|
||||
if (const CharT *p = js_strchr_limit(chars, '$', chars + length)) {
|
||||
uint32_t dollarIndex = p - chars;
|
||||
MOZ_ASSERT(dollarIndex < length);
|
||||
return dollarIndex;
|
||||
}
|
||||
return UINT32_MAX;
|
||||
}
|
||||
|
||||
struct ReplaceData
|
||||
{
|
||||
explicit ReplaceData(JSContext *cx)
|
||||
@ -2468,13 +2495,10 @@ struct ReplaceData
|
||||
elembase = nullptr;
|
||||
repstr = string;
|
||||
|
||||
const jschar *chars = repstr->chars();
|
||||
if (const jschar *p = js_strchr_limit(chars, '$', chars + repstr->length())) {
|
||||
dollarIndex = p - chars;
|
||||
MOZ_ASSERT(dollarIndex < repstr->length());
|
||||
} else {
|
||||
dollarIndex = UINT32_MAX;
|
||||
}
|
||||
AutoCheckCannotGC nogc;
|
||||
dollarIndex = string->hasLatin1Chars()
|
||||
? FindDollarIndex(string->latin1Chars(nogc), string->length())
|
||||
: FindDollarIndex(string->twoByteChars(nogc), string->length());
|
||||
}
|
||||
|
||||
inline void setReplacementFunction(JSObject *func) {
|
||||
@ -2550,8 +2574,9 @@ DoMatchForReplaceGlobal(JSContext *cx, RegExpStatics *res, HandleLinearString li
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename CharT>
|
||||
static bool
|
||||
InterpretDollar(RegExpStatics *res, const jschar *dp, const jschar *ep,
|
||||
InterpretDollar(RegExpStatics *res, const CharT *bp, const CharT *dp, const CharT *ep,
|
||||
ReplaceData &rdata, JSSubString *out, size_t *skip)
|
||||
{
|
||||
JS_ASSERT(*dp == '$');
|
||||
@ -2568,7 +2593,7 @@ InterpretDollar(RegExpStatics *res, const jschar *dp, const jschar *ep,
|
||||
if (num > res->getMatches().parenCount())
|
||||
return false;
|
||||
|
||||
const jschar *cp = dp + 2;
|
||||
const CharT *cp = dp + 2;
|
||||
if (cp < ep && (dc = *cp, JS7_ISDEC(dc))) {
|
||||
unsigned tmp = 10 * num + JS7_UNDEC(dc);
|
||||
if (tmp <= res->getMatches().parenCount()) {
|
||||
@ -2594,7 +2619,7 @@ InterpretDollar(RegExpStatics *res, const jschar *dp, const jschar *ep,
|
||||
*skip = 2;
|
||||
switch (dc) {
|
||||
case '$':
|
||||
out->init(rdata.repstr, dp - rdata.repstr->chars(), 1);
|
||||
out->init(rdata.repstr, dp - bp, 1);
|
||||
return true;
|
||||
case '&':
|
||||
res->getLastMatch(out);
|
||||
@ -2612,6 +2637,45 @@ InterpretDollar(RegExpStatics *res, const jschar *dp, const jschar *ep,
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename CharT>
|
||||
static bool
|
||||
FindReplaceLengthString(JSContext *cx, RegExpStatics *res, ReplaceData &rdata, size_t *sizep)
|
||||
{
|
||||
JSLinearString *repstr = rdata.repstr;
|
||||
CheckedInt<uint32_t> replen = repstr->length();
|
||||
|
||||
if (rdata.dollarIndex != UINT32_MAX) {
|
||||
AutoCheckCannotGC nogc;
|
||||
MOZ_ASSERT(rdata.dollarIndex < repstr->length());
|
||||
const CharT *bp = repstr->chars<CharT>(nogc);
|
||||
const CharT *dp = bp + rdata.dollarIndex;
|
||||
const CharT *ep = bp + repstr->length();
|
||||
do {
|
||||
JSSubString sub;
|
||||
size_t skip;
|
||||
if (InterpretDollar(res, bp, dp, ep, rdata, &sub, &skip)) {
|
||||
if (sub.length > skip)
|
||||
replen += sub.length - skip;
|
||||
else
|
||||
replen -= skip - sub.length;
|
||||
dp += skip;
|
||||
} else {
|
||||
dp++;
|
||||
}
|
||||
|
||||
dp = js_strchr_limit(dp, '$', ep);
|
||||
} while (dp);
|
||||
}
|
||||
|
||||
if (!replen.isValid()) {
|
||||
js_ReportAllocationOverflow(cx);
|
||||
return false;
|
||||
}
|
||||
|
||||
*sizep = replen.value();
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
FindReplaceLength(JSContext *cx, RegExpStatics *res, ReplaceData &rdata, size_t *sizep)
|
||||
{
|
||||
@ -2701,36 +2765,9 @@ FindReplaceLength(JSContext *cx, RegExpStatics *res, ReplaceData &rdata, size_t
|
||||
return true;
|
||||
}
|
||||
|
||||
JSLinearString *repstr = rdata.repstr;
|
||||
CheckedInt<uint32_t> replen = repstr->length();
|
||||
if (rdata.dollarIndex != UINT32_MAX) {
|
||||
MOZ_ASSERT(rdata.dollarIndex < repstr->length());
|
||||
const jschar *dp = repstr->chars() + rdata.dollarIndex;
|
||||
const jschar *ep = repstr->chars() + repstr->length();
|
||||
do {
|
||||
JSSubString sub;
|
||||
size_t skip;
|
||||
if (InterpretDollar(res, dp, ep, rdata, &sub, &skip)) {
|
||||
if (sub.length > skip)
|
||||
replen += sub.length - skip;
|
||||
else
|
||||
replen -= skip - sub.length;
|
||||
dp += skip;
|
||||
} else {
|
||||
dp++;
|
||||
}
|
||||
|
||||
dp = js_strchr_limit(dp, '$', ep);
|
||||
} while (dp);
|
||||
}
|
||||
|
||||
if (!replen.isValid()) {
|
||||
js_ReportAllocationOverflow(cx);
|
||||
return false;
|
||||
}
|
||||
|
||||
*sizep = replen.value();
|
||||
return true;
|
||||
return rdata.repstr->hasLatin1Chars()
|
||||
? FindReplaceLengthString<Latin1Char>(cx, res, rdata, sizep)
|
||||
: FindReplaceLengthString<jschar>(cx, res, rdata, sizep);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2738,17 +2775,19 @@ FindReplaceLength(JSContext *cx, RegExpStatics *res, ReplaceData &rdata, size_t
|
||||
* derived from FindReplaceLength), and has been inflated to TwoByte if
|
||||
* necessary.
|
||||
*/
|
||||
template <typename CharT>
|
||||
static void
|
||||
DoReplace(RegExpStatics *res, ReplaceData &rdata)
|
||||
{
|
||||
AutoCheckCannotGC nogc;
|
||||
JSLinearString *repstr = rdata.repstr;
|
||||
const jschar *bp = repstr->chars();
|
||||
const jschar *cp = bp;
|
||||
const CharT *bp = repstr->chars<CharT>(nogc);
|
||||
const CharT *cp = bp;
|
||||
|
||||
if (rdata.dollarIndex != UINT32_MAX) {
|
||||
MOZ_ASSERT(rdata.dollarIndex < repstr->length());
|
||||
const jschar *dp = bp + rdata.dollarIndex;
|
||||
const jschar *ep = bp + repstr->length();
|
||||
const CharT *dp = bp + rdata.dollarIndex;
|
||||
const CharT *ep = bp + repstr->length();
|
||||
do {
|
||||
/* Move one of the constant portions of the replacement value. */
|
||||
size_t len = dp - cp;
|
||||
@ -2757,7 +2796,7 @@ DoReplace(RegExpStatics *res, ReplaceData &rdata)
|
||||
|
||||
JSSubString sub;
|
||||
size_t skip;
|
||||
if (InterpretDollar(res, dp, ep, rdata, &sub, &skip)) {
|
||||
if (InterpretDollar(res, bp, dp, ep, rdata, &sub, &skip)) {
|
||||
rdata.sb.infallibleAppendSubstring(sub.base, sub.offset, sub.length);
|
||||
cp += skip;
|
||||
dp += skip;
|
||||
@ -2810,10 +2849,12 @@ ReplaceRegExp(JSContext *cx, RegExpStatics *res, ReplaceData &rdata)
|
||||
return false;
|
||||
|
||||
/* Append skipped-over portion of the search value. */
|
||||
const jschar *left = str.chars() + leftoff;
|
||||
rdata.sb.infallibleAppend(left, leftlen);
|
||||
rdata.sb.infallibleAppendSubstring(&str, leftoff, leftlen);
|
||||
|
||||
DoReplace(res, rdata);
|
||||
if (rdata.repstr->hasLatin1Chars())
|
||||
DoReplace<Latin1Char>(res, rdata);
|
||||
else
|
||||
DoReplace<jschar>(res, rdata);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -2895,6 +2936,57 @@ BuildFlatReplacement(JSContext *cx, HandleString textstr, HandleString repstr,
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename CharT>
|
||||
static bool
|
||||
AppendDollarReplacement(StringBuffer &newReplaceChars, size_t firstDollarIndex,
|
||||
const FlatMatch &fm, JSLinearString *text,
|
||||
const CharT *repChars, size_t repLength)
|
||||
{
|
||||
JS_ASSERT(firstDollarIndex < repLength);
|
||||
|
||||
size_t matchStart = fm.match();
|
||||
size_t matchLimit = matchStart + fm.patternLength();
|
||||
|
||||
/* Move the pre-dollar chunk in bulk. */
|
||||
newReplaceChars.infallibleAppend(repChars, firstDollarIndex);
|
||||
|
||||
/* Move the rest char-by-char, interpreting dollars as we encounter them. */
|
||||
const CharT *repLimit = repChars + repLength;
|
||||
for (const CharT *it = repChars + firstDollarIndex; it < repLimit; ++it) {
|
||||
if (*it != '$' || it == repLimit - 1) {
|
||||
if (!newReplaceChars.append(*it))
|
||||
return false;
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (*(it + 1)) {
|
||||
case '$': /* Eat one of the dollars. */
|
||||
if (!newReplaceChars.append(*it))
|
||||
return false;
|
||||
break;
|
||||
case '&':
|
||||
if (!newReplaceChars.appendSubstring(text, matchStart, matchLimit - matchStart))
|
||||
return false;
|
||||
break;
|
||||
case '`':
|
||||
if (!newReplaceChars.appendSubstring(text, 0, matchStart))
|
||||
return false;
|
||||
break;
|
||||
case '\'':
|
||||
if (!newReplaceChars.appendSubstring(text, matchLimit, text->length() - matchLimit))
|
||||
return false;
|
||||
break;
|
||||
default: /* The dollar we saw was not special (no matter what its mother told it). */
|
||||
if (!newReplaceChars.append(*it))
|
||||
return false;
|
||||
continue;
|
||||
}
|
||||
++it; /* We always eat an extra char in the above switch. */
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform a linear-scan dollar substitution on the replacement text,
|
||||
* constructing a result string that looks like:
|
||||
@ -2926,45 +3018,18 @@ BuildDollarReplacement(JSContext *cx, JSString *textstrArg, JSLinearString *reps
|
||||
if (!newReplaceChars.reserve(textstr->length() - fm.patternLength() + repstr->length()))
|
||||
return false;
|
||||
|
||||
JS_ASSERT(firstDollarIndex < repstr->length());
|
||||
|
||||
/* Move the pre-dollar chunk in bulk. */
|
||||
newReplaceChars.infallibleAppend(repstr->chars(), firstDollarIndex);
|
||||
|
||||
/* Move the rest char-by-char, interpreting dollars as we encounter them. */
|
||||
const jschar *textchars = textstr->chars();
|
||||
const jschar *repstrLimit = repstr->chars() + repstr->length();
|
||||
for (const jschar *it = repstr->chars() + firstDollarIndex; it < repstrLimit; ++it) {
|
||||
if (*it != '$' || it == repstrLimit - 1) {
|
||||
if (!newReplaceChars.append(*it))
|
||||
return false;
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (*(it + 1)) {
|
||||
case '$': /* Eat one of the dollars. */
|
||||
if (!newReplaceChars.append(*it))
|
||||
return false;
|
||||
break;
|
||||
case '&':
|
||||
if (!newReplaceChars.append(textchars + matchStart, textchars + matchLimit))
|
||||
return false;
|
||||
break;
|
||||
case '`':
|
||||
if (!newReplaceChars.append(textchars, textchars + matchStart))
|
||||
return false;
|
||||
break;
|
||||
case '\'':
|
||||
if (!newReplaceChars.append(textchars + matchLimit, textchars + textstr->length()))
|
||||
return false;
|
||||
break;
|
||||
default: /* The dollar we saw was not special (no matter what its mother told it). */
|
||||
if (!newReplaceChars.append(*it))
|
||||
return false;
|
||||
continue;
|
||||
}
|
||||
++it; /* We always eat an extra char in the above switch. */
|
||||
bool res;
|
||||
if (repstr->hasLatin1Chars()) {
|
||||
AutoCheckCannotGC nogc;
|
||||
res = AppendDollarReplacement(newReplaceChars, firstDollarIndex, fm, textstr,
|
||||
repstr->latin1Chars(nogc), repstr->length());
|
||||
} else {
|
||||
AutoCheckCannotGC nogc;
|
||||
res = AppendDollarReplacement(newReplaceChars, firstDollarIndex, fm, textstr,
|
||||
repstr->twoByteChars(nogc), repstr->length());
|
||||
}
|
||||
if (!res)
|
||||
return false;
|
||||
|
||||
RootedString leftSide(cx, js_NewDependentString(cx, textstr, 0, matchStart));
|
||||
if (!leftSide)
|
||||
@ -2998,25 +3063,35 @@ struct StringRange
|
||||
{ }
|
||||
};
|
||||
|
||||
static inline JSFatInlineString *
|
||||
FlattenSubstrings(JSContext *cx, const jschar *chars,
|
||||
const StringRange *ranges, size_t rangesLen, size_t outputLen)
|
||||
template <typename CharT>
|
||||
static void
|
||||
CopySubstringsToFatInline(JSFatInlineString *dest, const CharT *src, const StringRange *ranges,
|
||||
size_t rangesLen, size_t outputLen)
|
||||
{
|
||||
JS_ASSERT(JSFatInlineString::twoByteLengthFits(outputLen));
|
||||
CharT *buf = dest->init<CharT>(outputLen);
|
||||
size_t pos = 0;
|
||||
for (size_t i = 0; i < rangesLen; i++) {
|
||||
PodCopy(buf + pos, src + ranges[i].start, ranges[i].length);
|
||||
pos += ranges[i].length;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(pos == outputLen);
|
||||
buf[outputLen] = 0;
|
||||
}
|
||||
|
||||
static inline JSFatInlineString *
|
||||
FlattenSubstrings(JSContext *cx, Handle<JSFlatString*> flatStr, const StringRange *ranges,
|
||||
size_t rangesLen, size_t outputLen)
|
||||
{
|
||||
JSFatInlineString *str = js_NewGCFatInlineString<CanGC>(cx);
|
||||
if (!str)
|
||||
return nullptr;
|
||||
|
||||
jschar *buf = str->initTwoByte(outputLen);
|
||||
size_t pos = 0;
|
||||
for (size_t i = 0; i < rangesLen; i++) {
|
||||
PodCopy(buf + pos, chars + ranges[i].start, ranges[i].length);
|
||||
pos += ranges[i].length;
|
||||
}
|
||||
JS_ASSERT(pos == outputLen);
|
||||
|
||||
buf[outputLen] = 0;
|
||||
AutoCheckCannotGC nogc;
|
||||
if (flatStr->hasLatin1Chars())
|
||||
CopySubstringsToFatInline(str, flatStr->latin1Chars(nogc), ranges, rangesLen, outputLen);
|
||||
else
|
||||
CopySubstringsToFatInline(str, flatStr->twoByteChars(nogc), ranges, rangesLen, outputLen);
|
||||
return str;
|
||||
}
|
||||
|
||||
@ -3030,9 +3105,10 @@ AppendSubstrings(JSContext *cx, Handle<JSFlatString*> flatStr,
|
||||
if (rangesLen == 1)
|
||||
return js_NewDependentString(cx, flatStr, ranges[0].start, ranges[0].length);
|
||||
|
||||
const jschar *chars = flatStr->getChars(cx);
|
||||
if (!chars)
|
||||
return nullptr;
|
||||
bool isLatin1 = flatStr->hasLatin1Chars();
|
||||
uint32_t fatInlineMaxLength = isLatin1
|
||||
? JSFatInlineString::MAX_LENGTH_LATIN1
|
||||
: JSFatInlineString::MAX_LENGTH_TWO_BYTE;
|
||||
|
||||
/* Collect substrings into a rope */
|
||||
size_t i = 0;
|
||||
@ -3044,7 +3120,7 @@ AppendSubstrings(JSContext *cx, Handle<JSFlatString*> flatStr,
|
||||
size_t substrLen = 0;
|
||||
size_t end = i;
|
||||
for (; end < rangesLen; end++) {
|
||||
if (substrLen + ranges[end].length > JSFatInlineString::MAX_LENGTH_TWO_BYTE)
|
||||
if (substrLen + ranges[end].length > fatInlineMaxLength)
|
||||
break;
|
||||
substrLen += ranges[end].length;
|
||||
}
|
||||
@ -3055,7 +3131,7 @@ AppendSubstrings(JSContext *cx, Handle<JSFlatString*> flatStr,
|
||||
part = js_NewDependentString(cx, flatStr, sr.start, sr.length);
|
||||
} else {
|
||||
/* Copy the ranges (linearly) into a JSFatInlineString */
|
||||
part = FlattenSubstrings(cx, chars, ranges + i, end - i, substrLen);
|
||||
part = FlattenSubstrings(cx, flatStr, ranges + i, end - i, substrLen);
|
||||
i = end;
|
||||
}
|
||||
|
||||
@ -4623,17 +4699,24 @@ js_strdup(js::ThreadSafeContext *cx, const jschar *s)
|
||||
return ret;
|
||||
}
|
||||
|
||||
jschar *
|
||||
js_strchr_limit(const jschar *s, jschar c, const jschar *limit)
|
||||
template <typename CharT>
|
||||
const CharT *
|
||||
js_strchr_limit(const CharT *s, jschar c, const CharT *limit)
|
||||
{
|
||||
while (s < limit) {
|
||||
if (*s == c)
|
||||
return (jschar *)s;
|
||||
return s;
|
||||
s++;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template const Latin1Char *
|
||||
js_strchr_limit(const Latin1Char *s, jschar c, const Latin1Char *limit);
|
||||
|
||||
template const jschar *
|
||||
js_strchr_limit(const jschar *s, jschar c, const jschar *limit);
|
||||
|
||||
jschar *
|
||||
js::InflateString(ThreadSafeContext *cx, const char *bytes, size_t *lengthp)
|
||||
{
|
||||
|
@ -231,8 +231,9 @@ js_strlen(const jschar *s);
|
||||
extern int32_t
|
||||
js_strcmp(const jschar *lhs, const jschar *rhs);
|
||||
|
||||
extern jschar *
|
||||
js_strchr_limit(const jschar *s, jschar c, const jschar *limit);
|
||||
template <typename CharT>
|
||||
extern const CharT *
|
||||
js_strchr_limit(const CharT *s, jschar c, const CharT *limit);
|
||||
|
||||
static MOZ_ALWAYS_INLINE void
|
||||
js_strncpy(jschar *dst, const jschar *src, size_t nelem)
|
||||
|
@ -343,10 +343,6 @@ function jsTestDriverBrowserInit()
|
||||
{
|
||||
properties.version = '1.8';
|
||||
}
|
||||
else if (properties.test.match(/^ecma_6\/LexicalEnvironment/))
|
||||
{
|
||||
properties.version = '1.8';
|
||||
}
|
||||
}
|
||||
|
||||
// default to language=type;text/javascript. required for
|
||||
|
@ -1,5 +0,0 @@
|
||||
// NOTE: This only turns on 1.8.5 in shell builds. The browser requires the
|
||||
// futzing in js/src/tests/browser.js (which only turns on 1.8, the most
|
||||
// the browser supports).
|
||||
if (typeof version != 'undefined')
|
||||
version(185);
|
@ -1,18 +0,0 @@
|
||||
// |reftest| fails-if(Function("try{Function('let\x20x=5;');return(1,eval)('let\x20x=3;\\'x\\'\x20in\x20this');}catch(e){return(true);}")()) -- needs bug 589199 fix (top-level let not same as var)
|
||||
// Any copyright is dedicated to the Public Domain.
|
||||
// http://creativecommons.org/licenses/publicdomain/
|
||||
|
||||
let v = "global-v";
|
||||
|
||||
function f(v, global)
|
||||
{
|
||||
with (global)
|
||||
return v;
|
||||
}
|
||||
|
||||
assertEq(f("argument-v", this), "argument-v");
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(true, true);
|
||||
|
||||
print("Tests complete");
|
@ -28,6 +28,8 @@ using mozilla::DebugOnly;
|
||||
using mozilla::Maybe;
|
||||
using js::frontend::TokenStream;
|
||||
|
||||
using JS::AutoCheckCannotGC;
|
||||
|
||||
JS_STATIC_ASSERT(IgnoreCaseFlag == JSREG_FOLD);
|
||||
JS_STATIC_ASSERT(GlobalFlag == JSREG_GLOB);
|
||||
JS_STATIC_ASSERT(MultilineFlag == JSREG_MULTILINE);
|
||||
@ -592,9 +594,20 @@ RegExpShared::execute(JSContext *cx, HandleLinearString input, size_t *lastIndex
|
||||
|
||||
if (uint8_t *byteCode = maybeByteCode(input->hasLatin1Chars())) {
|
||||
AutoTraceLog logInterpreter(logger, TraceLogger::IrregexpExecute);
|
||||
const jschar *chars = input->chars() + charsOffset;
|
||||
RegExpRunStatus result =
|
||||
irregexp::InterpretCode(cx, byteCode, chars, start, length, &matches);
|
||||
|
||||
AutoStableStringChars inputChars(cx, input);
|
||||
if (!inputChars.init())
|
||||
return RegExpRunStatus_Error;
|
||||
|
||||
RegExpRunStatus result;
|
||||
if (inputChars.isLatin1()) {
|
||||
const Latin1Char *chars = inputChars.latin1Range().start().get() + charsOffset;
|
||||
result = irregexp::InterpretCode(cx, byteCode, chars, start, length, &matches);
|
||||
} else {
|
||||
const jschar *chars = inputChars.twoByteRange().start().get() + charsOffset;
|
||||
result = irregexp::InterpretCode(cx, byteCode, chars, start, length, &matches);
|
||||
}
|
||||
|
||||
if (result == RegExpRunStatus_Success) {
|
||||
matches.displace(displacement);
|
||||
matches.checkAgainst(origLength);
|
||||
@ -608,8 +621,14 @@ RegExpShared::execute(JSContext *cx, HandleLinearString input, size_t *lastIndex
|
||||
RegExpRunStatus result;
|
||||
{
|
||||
AutoTraceLog logJIT(logger, TraceLogger::IrregexpExecute);
|
||||
const jschar *chars = input->chars() + charsOffset;
|
||||
result = irregexp::ExecuteCode(cx, jitCodeTwoByte, chars, start, length, &matches);
|
||||
AutoCheckCannotGC nogc;
|
||||
if (input->hasLatin1Chars()) {
|
||||
const Latin1Char *chars = input->latin1Chars(nogc) + charsOffset;
|
||||
result = irregexp::ExecuteCode(cx, jitCodeLatin1, chars, start, length, &matches);
|
||||
} else {
|
||||
const jschar *chars = input->twoByteChars(nogc) + charsOffset;
|
||||
result = irregexp::ExecuteCode(cx, jitCodeTwoByte, chars, start, length, &matches);
|
||||
}
|
||||
}
|
||||
|
||||
if (result == RegExpRunStatus_Error) {
|
||||
@ -885,10 +904,10 @@ js::ParseRegExpFlags(JSContext *cx, JSString *flagStr, RegExpFlag *flagsOut)
|
||||
bool ok;
|
||||
jschar lastParsed;
|
||||
if (linear->hasLatin1Chars()) {
|
||||
JS::AutoCheckCannotGC nogc;
|
||||
AutoCheckCannotGC nogc;
|
||||
ok = ::ParseRegExpFlags(linear->latin1Chars(nogc), len, flagsOut, &lastParsed);
|
||||
} else {
|
||||
JS::AutoCheckCannotGC nogc;
|
||||
AutoCheckCannotGC nogc;
|
||||
ok = ::ParseRegExpFlags(linear->twoByteChars(nogc), len, flagsOut, &lastParsed);
|
||||
}
|
||||
|
||||
|
@ -255,7 +255,7 @@ inline void
|
||||
StringBuffer::infallibleAppendSubstring(JSLinearString *base, size_t off, size_t len)
|
||||
{
|
||||
MOZ_ASSERT(off + len <= base->length());
|
||||
MOZ_ASSERT(base->hasLatin1Chars() == isLatin1());
|
||||
MOZ_ASSERT_IF(base->hasTwoByteChars(), isTwoByte());
|
||||
|
||||
JS::AutoCheckCannotGC nogc;
|
||||
if (base->hasLatin1Chars())
|
||||
|
@ -80,8 +80,10 @@ const char* const XPCJSRuntime::mStrings[] = {
|
||||
"__iterator__", // IDX_ITERATOR
|
||||
"__exposedProps__", // IDX_EXPOSEDPROPS
|
||||
"eval", // IDX_EVAL
|
||||
"controllers", // IDX_CONTROLLERS
|
||||
"controllers", // IDX_CONTROLLERS
|
||||
"realFrameElement", // IDX_REALFRAMEELEMENT
|
||||
"length", // IDX_LENGTH
|
||||
"name", // IDX_NAME
|
||||
};
|
||||
|
||||
/***************************************************************************/
|
||||
|
@ -480,6 +480,8 @@ public:
|
||||
IDX_EVAL ,
|
||||
IDX_CONTROLLERS ,
|
||||
IDX_REALFRAMEELEMENT ,
|
||||
IDX_LENGTH ,
|
||||
IDX_NAME ,
|
||||
IDX_TOTAL_COUNT // just a count of the above
|
||||
};
|
||||
|
||||
|
@ -29,8 +29,9 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=448587.xul
|
||||
const Cu = Components.utils;
|
||||
var sandbox = new Cu.Sandbox("about:blank");
|
||||
var fwrapper = Cu.evalInSandbox("function f() {} f", sandbox);
|
||||
is(fwrapper.prototype, Cu.evalInSandbox("f.prototype", sandbox),
|
||||
"we don't censor .prototype through .wrappedJSObject");
|
||||
is(Cu.unwaiveXrays(Cu.waiveXrays(fwrapper).prototype), Cu.evalInSandbox("f.prototype", sandbox),
|
||||
".prototype visible through .wrappedJSObject");
|
||||
is(fwrapper.prototype, undefined, ".prototype invisible through Xrays");
|
||||
]]>
|
||||
</script>
|
||||
</window>
|
||||
|
@ -56,7 +56,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=812415
|
||||
is(Cu.evalInSandbox('regFun.name', expanded), 'reg', "Expanded can see regular function's name");
|
||||
checkThrows('expFun.name', regular, "Regular can't see expanded function's name");
|
||||
Cu.evalInSandbox('regFun.expando = 30', expanded);
|
||||
is(expanded.regFun.expando, 30, "Expanded can set expandos");
|
||||
is(Cu.evalInSandbox('regFun.expando', expanded), 30, "Expanded can set expandos");
|
||||
checkThrows('expFun.expando = 29', regular, "Regular can't set expandos");
|
||||
|
||||
// Check __proto__ stuff.
|
||||
|
@ -53,8 +53,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=933681
|
||||
"we end up with the appropriate constructor: " + c);
|
||||
is(Cu.unwaiveXrays(Cu.waiveXrays(new iwin[c]).constructor), iwin[c],
|
||||
"constructor property is set up right: " + c);
|
||||
is(Object.getPrototypeOf(new iwin[c]),
|
||||
Cu.unwaiveXrays(Cu.waiveXrays(iwin[c]).prototype),
|
||||
is(Object.getPrototypeOf(new iwin[c]), iwin[c].prototype,
|
||||
"prototype is correct: " + c);
|
||||
is(global(new iwin[c]), iwin, "Got the right global: " + c);
|
||||
}
|
||||
@ -65,7 +64,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=933681
|
||||
is(global(num), iwin, "correct global for num");
|
||||
var obj = new iwin.Object();
|
||||
obj.foo = 2;
|
||||
var withProto = iwin.Object.create(obj);
|
||||
var withProto = Cu.unwaiveXrays(Cu.waiveXrays(iwin).Object.create(obj));
|
||||
is(global(withProto), iwin, "correct global for withProto");
|
||||
is(Cu.waiveXrays(withProto).foo, 2, "Inherits properly");
|
||||
|
||||
@ -85,6 +84,25 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=933681
|
||||
is(global(factoryFun), iwin, "proper global for factoryFun");
|
||||
is(factoryFun().foo, 32, "factoryFun invokable");
|
||||
is(global(factoryFun()), iwin, "minted objects live in the content scope");
|
||||
testXray('Function', factoryFun, new iwin.Function(), ['caller', 'arguments', 'length', 'name']);
|
||||
var echoThis = new iwin.Function('return this;');
|
||||
echoThis.wrappedJSObject.bind = 42;
|
||||
var boundEchoThis = echoThis.bind(document);
|
||||
is(boundEchoThis(), document, "bind() works correctly over Xrays");
|
||||
is(global(boundEchoThis), window, "bound functions live in the caller's scope");
|
||||
ok(/return this/.test(echoThis.toSource()), 'toSource works: ' + echoThis.toSource());
|
||||
ok(/return this/.test(echoThis.toString()), 'toString works: ' + echoThis.toString());
|
||||
is(iwin.Function.prototype, Object.getPrototypeOf(echoThis), "Function.prototype works for standard classes");
|
||||
is(echoThis.prototype, undefined, "Function.prototype not visible for non standard constructors");
|
||||
iwin.eval('var foopyFunction = function namedFoopyFunction(a, b, c) {}');
|
||||
var foopyFunction = Cu.unwaiveXrays(Cu.waiveXrays(iwin).foopyFunction);
|
||||
ok(Cu.isXrayWrapper(foopyFunction), "Should be Xrays");
|
||||
is(foopyFunction.name, "namedFoopyFunction", ".name works over Xrays");
|
||||
is(foopyFunction.length, 3, ".length works over Xrays");
|
||||
ok(Object.getOwnPropertyNames(foopyFunction).indexOf('length') >= 0, "Should list length");
|
||||
ok(Object.getOwnPropertyNames(foopyFunction).indexOf('name') >= 0, "Should list name");
|
||||
ok(Object.getOwnPropertyNames(foopyFunction).indexOf('prototype') == -1, "Should not list prototype");
|
||||
ok(Object.getOwnPropertyNames(iwin.Array).indexOf('prototype') >= 0, "Should list prototype for standard constructor");
|
||||
|
||||
// Test interface objects that don't actually construct things.
|
||||
is(iwin.Math.tan(4.5), Math.tan(4.5), "Math.tan works");
|
||||
@ -164,6 +182,9 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=933681
|
||||
if (!isReleaseBuild)
|
||||
gPrototypeProperties[c].push("move");
|
||||
}
|
||||
gPrototypeProperties['Function'] =
|
||||
["constructor", "toSource", "toString", "apply", "call", "bind",
|
||||
"isGenerator", "length", "name", "arguments", "caller"];
|
||||
|
||||
function filterOut(array, props) {
|
||||
return array.filter(p => props.indexOf(p) == -1);
|
||||
@ -242,7 +263,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=933681
|
||||
}
|
||||
|
||||
function testObject() {
|
||||
testXray('Object', iwin.Object.create(new iwin.Object()), new iwin.Object(), []);
|
||||
testXray('Object', Cu.unwaiveXrays(Cu.waiveXrays(iwin).Object.create(new iwin.Object())),
|
||||
new iwin.Object(), []);
|
||||
|
||||
// Construct an object full of tricky things.
|
||||
var trickyObject =
|
||||
|
@ -128,9 +128,9 @@ static bool
|
||||
ForceCOWBehavior(JSObject *obj)
|
||||
{
|
||||
JSProtoKey key = IdentifyStandardInstanceOrPrototype(obj);
|
||||
if (key == JSProto_Object || key == JSProto_Array) {
|
||||
if (key == JSProto_Object || key == JSProto_Array || key == JSProto_Function) {
|
||||
MOZ_ASSERT(GetXrayType(obj) == XrayForJSObject,
|
||||
"We should use XrayWrappers for standard ES Object and Array "
|
||||
"We should use XrayWrappers for standard ES Object, Array, and Function "
|
||||
"instances modulo this hack");
|
||||
return true;
|
||||
}
|
||||
@ -360,13 +360,6 @@ SelectWrapper(bool securityWrapper, bool wantXrays, XrayType xrayType,
|
||||
if (!wantXrays || xrayType == NotXray) {
|
||||
if (!securityWrapper)
|
||||
return &CrossCompartmentWrapper::singleton;
|
||||
// In general, we don't want opaque function wrappers to be callable.
|
||||
// But in the case of XBL, we rely on content being able to invoke
|
||||
// functions exposed from the XBL scope. We could remove this exception,
|
||||
// if needed, by using ExportFunction to generate the content-side
|
||||
// representations of XBL methods.
|
||||
else if (originIsXBLScope)
|
||||
return &FilteringWrapper<CrossCompartmentSecurityWrapper, OpaqueWithCall>::singleton;
|
||||
return &FilteringWrapper<CrossCompartmentSecurityWrapper, Opaque>::singleton;
|
||||
}
|
||||
|
||||
@ -390,7 +383,15 @@ SelectWrapper(bool securityWrapper, bool wantXrays, XrayType xrayType,
|
||||
CrossOriginAccessiblePropertiesOnly>::singleton;
|
||||
// There's never any reason to expose pure JS objects to non-subsuming actors.
|
||||
// Just use an opaque wrapper in this case.
|
||||
//
|
||||
// In general, we don't want opaque function wrappers to be callable.
|
||||
// But in the case of XBL, we rely on content being able to invoke
|
||||
// functions exposed from the XBL scope. We could remove this exception,
|
||||
// if needed, by using ExportFunction to generate the content-side
|
||||
// representations of XBL methods.
|
||||
MOZ_ASSERT(xrayType == XrayForJSObject);
|
||||
if (originIsXBLScope)
|
||||
return &FilteringWrapper<CrossCompartmentSecurityWrapper, OpaqueWithCall>::singleton;
|
||||
return &FilteringWrapper<CrossCompartmentSecurityWrapper, Opaque>::singleton;
|
||||
}
|
||||
|
||||
|
@ -71,6 +71,7 @@ IsJSXraySupported(JSProtoKey key)
|
||||
case JSProto_Date:
|
||||
case JSProto_Object:
|
||||
case JSProto_Array:
|
||||
case JSProto_Function:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
@ -171,6 +172,8 @@ public:
|
||||
class XrayTraits
|
||||
{
|
||||
public:
|
||||
XrayTraits() {}
|
||||
|
||||
static JSObject* getTargetObject(JSObject *wrapper) {
|
||||
return js::UncheckedUnwrap(wrapper, /* stopAtOuter = */ false);
|
||||
}
|
||||
@ -224,6 +227,9 @@ private:
|
||||
JSObject* attachExpandoObject(JSContext *cx, HandleObject target,
|
||||
nsIPrincipal *origin,
|
||||
HandleObject exclusiveGlobal);
|
||||
|
||||
XrayTraits(XrayTraits &) MOZ_DELETE;
|
||||
const XrayTraits& operator=(XrayTraits &) MOZ_DELETE;
|
||||
};
|
||||
|
||||
class XPCWrappedNativeXrayTraits : public XrayTraits
|
||||
@ -349,7 +355,11 @@ public:
|
||||
static bool call(JSContext *cx, HandleObject wrapper,
|
||||
const JS::CallArgs &args, js::Wrapper& baseInstance)
|
||||
{
|
||||
// We'll handle this when we start supporting Functions.
|
||||
JSXrayTraits &self = JSXrayTraits::singleton;
|
||||
RootedObject holder(cx, self.ensureHolder(cx, wrapper));
|
||||
if (self.getProtoKey(holder) == JSProto_Function)
|
||||
return baseInstance.call(cx, wrapper, args);
|
||||
|
||||
RootedValue v(cx, ObjectValue(*wrapper));
|
||||
js_ReportIsNotFunction(cx, v);
|
||||
return false;
|
||||
@ -358,7 +368,11 @@ public:
|
||||
static bool construct(JSContext *cx, HandleObject wrapper,
|
||||
const JS::CallArgs &args, js::Wrapper& baseInstance)
|
||||
{
|
||||
// We'll handle this when we start supporting Functions.
|
||||
JSXrayTraits &self = JSXrayTraits::singleton;
|
||||
RootedObject holder(cx, self.ensureHolder(cx, wrapper));
|
||||
if (self.getProtoKey(holder) == JSProto_Function)
|
||||
return baseInstance.construct(cx, wrapper, args);
|
||||
|
||||
RootedValue v(cx, ObjectValue(*wrapper));
|
||||
js_ReportIsNotFunction(cx, v);
|
||||
return false;
|
||||
@ -403,6 +417,7 @@ public:
|
||||
enum {
|
||||
SLOT_PROTOKEY = 0,
|
||||
SLOT_ISPROTOTYPE,
|
||||
SLOT_CONSTRUCTOR_FOR,
|
||||
SLOT_COUNT
|
||||
};
|
||||
virtual JSObject* createHolder(JSContext *cx, JSObject *wrapper) MOZ_OVERRIDE;
|
||||
@ -416,6 +431,11 @@ public:
|
||||
return js::GetReservedSlot(holder, SLOT_ISPROTOTYPE).toBoolean();
|
||||
}
|
||||
|
||||
static JSProtoKey constructorFor(JSObject *holder) {
|
||||
int32_t key = js::GetReservedSlot(holder, SLOT_CONSTRUCTOR_FOR).toInt32();
|
||||
return static_cast<JSProtoKey>(key);
|
||||
}
|
||||
|
||||
static bool getOwnPropertyFromTargetIfSafe(JSContext *cx,
|
||||
HandleObject target,
|
||||
HandleObject wrapper,
|
||||
@ -552,6 +572,32 @@ JSXrayTraits::resolveOwnProperty(JSContext *cx, Wrapper &jsWrapper,
|
||||
"across origin boundaries, consider using Components.utils.cloneInto().");
|
||||
return false;
|
||||
}
|
||||
} else if (key == JSProto_Function) {
|
||||
if (id == GetRTIdByIndex(cx, XPCJSRuntime::IDX_LENGTH)) {
|
||||
FillPropertyDescriptor(desc, wrapper, JSPROP_PERMANENT | JSPROP_READONLY,
|
||||
NumberValue(JS_GetFunctionArity(JS_GetObjectFunction(target))));
|
||||
return true;
|
||||
} else if (id == GetRTIdByIndex(cx, XPCJSRuntime::IDX_NAME)) {
|
||||
FillPropertyDescriptor(desc, wrapper, JSPROP_PERMANENT | JSPROP_READONLY,
|
||||
StringValue(JS_GetFunctionId(JS_GetObjectFunction(target))));
|
||||
} else if (id == GetRTIdByIndex(cx, XPCJSRuntime::IDX_PROTOTYPE)) {
|
||||
// Handle the 'prototype' property to make xrayedGlobal.StandardClass.prototype work.
|
||||
JSProtoKey standardConstructor = constructorFor(holder);
|
||||
if (standardConstructor != JSProto_Null) {
|
||||
RootedObject standardProto(cx);
|
||||
{
|
||||
JSAutoCompartment ac(cx, target);
|
||||
if (!JS_GetClassPrototype(cx, standardConstructor, &standardProto))
|
||||
return false;
|
||||
MOZ_ASSERT(standardProto);
|
||||
}
|
||||
if (!JS_WrapObject(cx, &standardProto))
|
||||
return false;
|
||||
FillPropertyDescriptor(desc, wrapper, JSPROP_PERMANENT | JSPROP_READONLY,
|
||||
ObjectValue(*standardProto));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The rest of this function applies only to prototypes.
|
||||
@ -805,6 +851,16 @@ JSXrayTraits::enumerateNames(JSContext *cx, HandleObject wrapper, unsigned flags
|
||||
return false;
|
||||
for (int32_t i = 0; i <= int32_t(length - 1); ++i)
|
||||
props.infallibleAppend(INT_TO_JSID(i));
|
||||
} else if (key == JSProto_Function) {
|
||||
if (!props.append(GetRTIdByIndex(cx, XPCJSRuntime::IDX_LENGTH)))
|
||||
return false;
|
||||
if (!props.append(GetRTIdByIndex(cx, XPCJSRuntime::IDX_NAME)))
|
||||
return false;
|
||||
// Handle the .prototype property on standard constructors.
|
||||
if (constructorFor(holder) != JSProto_Null) {
|
||||
if (!props.append(GetRTIdByIndex(cx, XPCJSRuntime::IDX_PROTOTYPE)))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// The rest of this function applies only to prototypes.
|
||||
@ -869,6 +925,13 @@ JSXrayTraits::createHolder(JSContext *cx, JSObject *wrapper)
|
||||
v.setBoolean(isPrototype);
|
||||
js::SetReservedSlot(holder, SLOT_ISPROTOTYPE, v);
|
||||
|
||||
// If this is a function, also compute whether it serves as a constructor
|
||||
// for a standard class.
|
||||
if (key == JSProto_Function) {
|
||||
v.setNumber(static_cast<uint32_t>(IdentifyStandardConstructor(target)));
|
||||
js::SetReservedSlot(holder, SLOT_CONSTRUCTOR_FOR, v);
|
||||
}
|
||||
|
||||
return holder;
|
||||
}
|
||||
|
||||
|
@ -132,6 +132,7 @@ using namespace mozilla::system;
|
||||
#include "mozilla/IMEStateManager.h"
|
||||
#include "nsDocument.h"
|
||||
#include "mozilla/dom/HTMLVideoElement.h"
|
||||
#include "CameraPreferences.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::net;
|
||||
@ -296,6 +297,8 @@ nsLayoutStatics::Initialize()
|
||||
|
||||
CounterStyleManager::InitializeBuiltinCounterStyles();
|
||||
|
||||
CameraPreferences::Initialize();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -426,4 +429,6 @@ nsLayoutStatics::Shutdown()
|
||||
nsDocument::XPCOMShutdown();
|
||||
|
||||
CacheObserver::Shutdown();
|
||||
|
||||
CameraPreferences::Shutdown();
|
||||
}
|
||||
|
@ -22,16 +22,19 @@ import mozlog
|
||||
log = mozlog.getLogger('REFTEST')
|
||||
|
||||
class B2GDesktopReftest(RefTest):
|
||||
def __init__(self, marionette):
|
||||
marionette = None
|
||||
|
||||
def __init__(self, marionette_args):
|
||||
RefTest.__init__(self)
|
||||
self.last_test = os.path.basename(__file__)
|
||||
self.marionette = marionette
|
||||
self.marionette_args = marionette_args
|
||||
self.profile = None
|
||||
self.runner = None
|
||||
self.test_script = os.path.join(here, 'b2g_start_script.js')
|
||||
self.timeout = None
|
||||
|
||||
def run_marionette_script(self):
|
||||
self.marionette = Marionette(**self.marionette_args)
|
||||
assert(self.marionette.wait_for_port())
|
||||
self.marionette.start_session()
|
||||
self.marionette.set_context(self.marionette.CONTEXT_CHROME)
|
||||
@ -71,8 +74,8 @@ class B2GDesktopReftest(RefTest):
|
||||
cmdargs=args,
|
||||
env=env,
|
||||
process_class=ProcessHandler,
|
||||
symbols_path=options.symbolsPath,
|
||||
kp_kwargs=kp_kwargs)
|
||||
process_args=kp_kwargs,
|
||||
symbols_path=options.symbolsPath)
|
||||
|
||||
status = 0
|
||||
try:
|
||||
@ -151,14 +154,13 @@ class B2GDesktopReftest(RefTest):
|
||||
|
||||
|
||||
def run_desktop_reftests(parser, options, args):
|
||||
kwargs = {}
|
||||
marionette_args = {}
|
||||
if options.marionette:
|
||||
host, port = options.marionette.split(':')
|
||||
kwargs['host'] = host
|
||||
kwargs['port'] = int(port)
|
||||
marionette = Marionette.getMarionetteOrExit(**kwargs)
|
||||
marionette_args['host'] = host
|
||||
marionette_args['port'] = int(port)
|
||||
|
||||
reftest = B2GDesktopReftest(marionette)
|
||||
reftest = B2GDesktopReftest(marionette_args)
|
||||
|
||||
options = ReftestOptions.verifyCommonOptions(parser, options, reftest)
|
||||
if options == None:
|
||||
|
@ -201,7 +201,7 @@ class ReftestRunner(MozbuildObject):
|
||||
raise Exception(ADB_NOT_FOUND % ('%s-remote' % suite, b2g_home))
|
||||
|
||||
options.b2gPath = b2g_home
|
||||
options.logcat_dir = self.reftest_dir
|
||||
options.logdir = self.reftest_dir
|
||||
options.httpdPath = os.path.join(self.topsrcdir, 'netwerk', 'test', 'httpserver')
|
||||
options.xrePath = xre_path
|
||||
options.ignoreWindowSize = True
|
||||
@ -335,9 +335,9 @@ def B2GCommand(func):
|
||||
help='Path to busybox binary to install on device')
|
||||
func = busybox(func)
|
||||
|
||||
logcatdir = CommandArgument('--logcat-dir', default=None,
|
||||
help='directory to store logcat dump files')
|
||||
func = logcatdir(func)
|
||||
logdir = CommandArgument('--logdir', default=None,
|
||||
help='directory to store log files')
|
||||
func = logdir(func)
|
||||
|
||||
sdcard = CommandArgument('--sdcard', default="10MB",
|
||||
help='Define size of sdcard: 1MB, 50MB...etc')
|
||||
|
@ -58,9 +58,9 @@ class B2GOptions(ReftestOptions):
|
||||
defaults["noWindow"] = False
|
||||
|
||||
self.add_option("--adbpath", action="store",
|
||||
type = "string", dest = "adbPath",
|
||||
type = "string", dest = "adb_path",
|
||||
help = "path to adb")
|
||||
defaults["adbPath"] = "adb"
|
||||
defaults["adb_path"] = "adb"
|
||||
|
||||
self.add_option("--deviceIP", action="store",
|
||||
type = "string", dest = "deviceIP",
|
||||
@ -101,10 +101,10 @@ class B2GOptions(ReftestOptions):
|
||||
help="the path to a gecko distribution that should "
|
||||
"be installed on the emulator prior to test")
|
||||
defaults["geckoPath"] = None
|
||||
self.add_option("--logcat-dir", action="store",
|
||||
type="string", dest="logcat_dir",
|
||||
help="directory to store logcat dump files")
|
||||
defaults["logcat_dir"] = None
|
||||
self.add_option("--logdir", action="store",
|
||||
type="string", dest="logdir",
|
||||
help="directory to store log files")
|
||||
defaults["logdir"] = None
|
||||
self.add_option('--busybox', action='store',
|
||||
type='string', dest='busybox',
|
||||
help="Path to busybox binary to install on device")
|
||||
@ -166,8 +166,8 @@ class B2GOptions(ReftestOptions):
|
||||
if options.geckoPath and not options.emulator:
|
||||
self.error("You must specify --emulator if you specify --gecko-path")
|
||||
|
||||
if options.logcat_dir and not options.emulator:
|
||||
self.error("You must specify --emulator if you specify --logcat-dir")
|
||||
if options.logdir and not options.emulator:
|
||||
self.error("You must specify --emulator if you specify --logdir")
|
||||
|
||||
#if not options.emulator and not options.deviceIP:
|
||||
# print "ERROR: you must provide a device IP"
|
||||
@ -497,8 +497,8 @@ def run_remote_reftests(parser, options, args):
|
||||
kwargs['noWindow'] = True
|
||||
if options.geckoPath:
|
||||
kwargs['gecko_path'] = options.geckoPath
|
||||
if options.logcat_dir:
|
||||
kwargs['logcat_dir'] = options.logcat_dir
|
||||
if options.logdir:
|
||||
kwargs['logdir'] = options.logdir
|
||||
if options.busybox:
|
||||
kwargs['busybox'] = options.busybox
|
||||
if options.symbolsPath:
|
||||
@ -511,19 +511,21 @@ def run_remote_reftests(parser, options, args):
|
||||
host,port = options.marionette.split(':')
|
||||
kwargs['host'] = host
|
||||
kwargs['port'] = int(port)
|
||||
marionette = Marionette.getMarionetteOrExit(**kwargs)
|
||||
if options.adb_path:
|
||||
kwargs['adb_path'] = options.adb_path
|
||||
marionette = Marionette(**kwargs)
|
||||
auto.marionette = marionette
|
||||
|
||||
if options.emulator:
|
||||
dm = marionette.emulator.dm
|
||||
else:
|
||||
# create the DeviceManager
|
||||
kwargs = {'adbPath': options.adbPath,
|
||||
kwargs = {'adbPath': options.adb_path,
|
||||
'deviceRoot': options.remoteTestRoot}
|
||||
if options.deviceIP:
|
||||
kwargs.update({'host': options.deviceIP,
|
||||
'port': options.devicePort})
|
||||
dm = DeviagerADB(**kwargs)
|
||||
dm = DeviceManagerADB(**kwargs)
|
||||
auto.setDeviceManager(dm)
|
||||
|
||||
options = parser.verifyRemoteOptions(options, auto)
|
||||
|
@ -110,6 +110,7 @@ if CONFIG['_MSC_VER']:
|
||||
'-wd4309', # '=' : truncation of constant value
|
||||
'-wd4355', # 'this' : used in base member initializer list
|
||||
'-wd4804', # '>' : unsafe use of type 'bool' in operation
|
||||
'-wd4099', # mismatched class/struct tags
|
||||
]
|
||||
elif CONFIG['GNU_CXX']:
|
||||
CFLAGS += [
|
||||
|
@ -137,8 +137,6 @@ namespace mozilla { namespace psm {
|
||||
|
||||
namespace {
|
||||
|
||||
NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
|
||||
|
||||
NSSCleanupAutoPtrClass(CERTCertificate, CERT_DestroyCertificate)
|
||||
NSSCleanupAutoPtrClass_WithParam(PLArenaPool, PORT_FreeArena, FalseParam, false)
|
||||
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "nsIProgrammingLanguage.h"
|
||||
#include "nsIArray.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsReadableUtils.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "PSMRunnable.h"
|
||||
|
||||
@ -624,12 +625,21 @@ GetSubjectAltNames(CERTCertificate *nssCert,
|
||||
nsAutoString name;
|
||||
switch (current->type) {
|
||||
case certDNSName:
|
||||
name.AssignASCII((char*)current->name.other.data, current->name.other.len);
|
||||
if (!allNames.IsEmpty()) {
|
||||
allNames.AppendLiteral(", ");
|
||||
{
|
||||
nsDependentCSubstring nameFromCert(reinterpret_cast<char*>
|
||||
(current->name.other.data),
|
||||
current->name.other.len);
|
||||
// dNSName fields are defined as type IA5String and thus should
|
||||
// be limited to ASCII characters.
|
||||
if (IsASCII(nameFromCert)) {
|
||||
name.Assign(NS_ConvertASCIItoUTF16(nameFromCert));
|
||||
if (!allNames.IsEmpty()) {
|
||||
allNames.AppendLiteral(", ");
|
||||
}
|
||||
++nameCount;
|
||||
allNames.Append(name);
|
||||
}
|
||||
}
|
||||
++nameCount;
|
||||
allNames.Append(name);
|
||||
break;
|
||||
|
||||
case certIPAddress:
|
||||
@ -709,8 +719,15 @@ AppendErrorTextMismatch(const nsString &host,
|
||||
if (!useSAN) {
|
||||
char *certName = CERT_GetCommonName(&nssCert->subject);
|
||||
if (certName) {
|
||||
++nameCount;
|
||||
allNames.Assign(NS_ConvertUTF8toUTF16(certName));
|
||||
nsDependentCSubstring commonName(certName, strlen(certName));
|
||||
if (IsUTF8(commonName)) {
|
||||
// Bug 1024781
|
||||
// We should actually check that the common name is a valid dns name or
|
||||
// ip address and not any string value before adding it to the display
|
||||
// list.
|
||||
++nameCount;
|
||||
allNames.Assign(NS_ConvertUTF8toUTF16(commonName));
|
||||
}
|
||||
PORT_Free(certName);
|
||||
}
|
||||
}
|
||||
|
@ -67,9 +67,6 @@ const SEC_ASN1Template SECKEY_PQGParamsTemplate[] = {
|
||||
{ 0, }
|
||||
};
|
||||
|
||||
|
||||
static NS_DEFINE_IID(kIDOMHTMLSelectElementIID, NS_IDOMHTMLSELECTELEMENT_IID);
|
||||
|
||||
static PQGParams *
|
||||
decode_pqg_params(char *aStr)
|
||||
{
|
||||
|
@ -1542,6 +1542,10 @@ Daily counts are reported in the following properties:
|
||||
|
||||
translationOpportunityCount
|
||||
Integer count of the number of opportunities there were to translate a page.
|
||||
missedTranslationOpportunityCount
|
||||
Integer count of the number of missed opportunities there were to translate a page.
|
||||
A missed opportunity is when the page language is not supported by the translation
|
||||
provider.
|
||||
pageTranslatedCount
|
||||
Integer count of the number of pages translated.
|
||||
charactersTranslatedCount
|
||||
@ -1559,6 +1563,9 @@ properties:
|
||||
translationOpportunityCountsByLanguage
|
||||
A mapping from language to count of opportunities to translate that
|
||||
language.
|
||||
missedTranslationOpportunityCountsByLanguage
|
||||
A mapping from language to count of missed opportunities to translate that
|
||||
language.
|
||||
pageTranslatedCountsByLanguage
|
||||
A mapping from language to the counts of pages translated from that
|
||||
language. Each language entry will be an object containing a "total" member
|
||||
|
@ -5,7 +5,7 @@
|
||||
config = {
|
||||
"jsreftest_options": [
|
||||
"--adbpath=%(adbpath)s", "--b2gpath=%(b2gpath)s", "--emulator=%(emulator)s",
|
||||
"--emulator-res=800x1000", "--logcat-dir=%(logcat_dir)s",
|
||||
"--emulator-res=800x1000", "--logdir=%(logcat_dir)s",
|
||||
"--remote-webserver=%(remote_webserver)s", "--ignore-window-size",
|
||||
"--xre-path=%(xre_path)s", "--symbols-path=%(symbols_path)s", "--busybox=%(busybox)s",
|
||||
"--total-chunks=%(total_chunks)s", "--this-chunk=%(this_chunk)s",
|
||||
@ -15,7 +15,7 @@ config = {
|
||||
|
||||
"mochitest_options": [
|
||||
"--adbpath=%(adbpath)s", "--b2gpath=%(b2gpath)s", "--console-level=INFO",
|
||||
"--emulator=%(emulator)s", "--logcat-dir=%(logcat_dir)s",
|
||||
"--emulator=%(emulator)s", "--logdir=%(logcat_dir)s",
|
||||
"--remote-webserver=%(remote_webserver)s", "%(test_manifest)s",
|
||||
"--xre-path=%(xre_path)s", "--symbols-path=%(symbols_path)s", "--busybox=%(busybox)s",
|
||||
"--total-chunks=%(total_chunks)s", "--this-chunk=%(this_chunk)s",
|
||||
@ -25,7 +25,7 @@ config = {
|
||||
|
||||
"reftest_options": [
|
||||
"--adbpath=%(adbpath)s", "--b2gpath=%(b2gpath)s", "--emulator=%(emulator)s",
|
||||
"--emulator-res=800x1000", "--logcat-dir=%(logcat_dir)s",
|
||||
"--emulator-res=800x1000", "--logdir=%(logcat_dir)s",
|
||||
"--remote-webserver=%(remote_webserver)s", "--ignore-window-size",
|
||||
"--xre-path=%(xre_path)s", "--symbols-path=%(symbols_path)s", "--busybox=%(busybox)s",
|
||||
"--total-chunks=%(total_chunks)s", "--this-chunk=%(this_chunk)s", "--enable-oop",
|
||||
@ -34,7 +34,7 @@ config = {
|
||||
|
||||
"crashtest_options": [
|
||||
"--adbpath=%(adbpath)s", "--b2gpath=%(b2gpath)s", "--emulator=%(emulator)s",
|
||||
"--emulator-res=800x1000", "--logcat-dir=%(logcat_dir)s",
|
||||
"--emulator-res=800x1000", "--logdir=%(logcat_dir)s",
|
||||
"--remote-webserver=%(remote_webserver)s", "--ignore-window-size",
|
||||
"--xre-path=%(xre_path)s", "--symbols-path=%(symbols_path)s", "--busybox=%(busybox)s",
|
||||
"--total-chunks=%(total_chunks)s", "--this-chunk=%(this_chunk)s",
|
||||
@ -43,7 +43,7 @@ config = {
|
||||
|
||||
"xpcshell_options": [
|
||||
"--adbpath=%(adbpath)s", "--b2gpath=%(b2gpath)s", "--emulator=%(emulator)s",
|
||||
"--logcat-dir=%(logcat_dir)s", "--manifest=%(test_manifest)s", "--use-device-libs",
|
||||
"--logdir=%(logcat_dir)s", "--manifest=%(test_manifest)s", "--use-device-libs",
|
||||
"--testing-modules-dir=%(modules_dir)s", "--symbols-path=%(symbols_path)s",
|
||||
"--busybox=%(busybox)s", "--total-chunks=%(total_chunks)s", "--this-chunk=%(this_chunk)s",
|
||||
],
|
||||
|
@ -6,21 +6,49 @@ from gestures import smooth_scroll, pinch
|
||||
from by import By
|
||||
from marionette import Marionette, HTMLElement, Actions, MultiActions
|
||||
from marionette_test import MarionetteTestCase, MarionetteJSTestCase, CommonTestCase, expectedFailure, skip, SkipTest
|
||||
from emulator import Emulator
|
||||
from errors import (
|
||||
ErrorCodes, MarionetteException, InstallGeckoError, TimeoutException, InvalidResponseException,
|
||||
JavascriptException, NoSuchElementException, XPathLookupException, NoSuchWindowException,
|
||||
StaleElementException, ScriptTimeoutException, ElementNotVisibleException,
|
||||
NoSuchFrameException, InvalidElementStateException, NoAlertPresentException,
|
||||
InvalidCookieDomainException, UnableToSetCookieException, InvalidSelectorException,
|
||||
MoveTargetOutOfBoundsException, FrameSendNotInitializedError, FrameSendFailureError
|
||||
)
|
||||
ElementNotVisibleException,
|
||||
ErrorCodes,
|
||||
FrameSendFailureError,
|
||||
FrameSendNotInitializedError,
|
||||
InvalidCookieDomainException,
|
||||
InvalidElementStateException,
|
||||
InvalidResponseException,
|
||||
InvalidSelectorException,
|
||||
JavascriptException,
|
||||
MarionetteException,
|
||||
MoveTargetOutOfBoundsException,
|
||||
NoAlertPresentException,
|
||||
NoSuchElementException,
|
||||
NoSuchFrameException,
|
||||
NoSuchWindowException,
|
||||
ScriptTimeoutException,
|
||||
StaleElementException,
|
||||
TimeoutException,
|
||||
UnableToSetCookieException,
|
||||
XPathLookupException,
|
||||
)
|
||||
from runner import (
|
||||
B2GTestCaseMixin, B2GTestResultMixin, BaseMarionetteOptions, BaseMarionetteTestRunner, EnduranceOptionsMixin,
|
||||
EnduranceTestCaseMixin, HTMLReportingOptionsMixin, HTMLReportingTestResultMixin, HTMLReportingTestRunnerMixin,
|
||||
Marionette, MarionetteTest, MarionetteTestResult, MarionetteTextTestRunner, MemoryEnduranceTestCaseMixin,
|
||||
MozHttpd, OptionParser, TestManifest, TestResult, TestResultCollection
|
||||
)
|
||||
B2GTestCaseMixin,
|
||||
B2GTestResultMixin,
|
||||
BaseMarionetteOptions,
|
||||
BaseMarionetteTestRunner,
|
||||
EnduranceOptionsMixin,
|
||||
EnduranceTestCaseMixin,
|
||||
HTMLReportingOptionsMixin,
|
||||
HTMLReportingTestResultMixin,
|
||||
HTMLReportingTestRunnerMixin,
|
||||
Marionette,
|
||||
MarionetteTest,
|
||||
MarionetteTestResult,
|
||||
MarionetteTextTestRunner,
|
||||
MemoryEnduranceTestCaseMixin,
|
||||
MozHttpd,
|
||||
OptionParser,
|
||||
TestManifest,
|
||||
TestResult,
|
||||
TestResultCollection
|
||||
)
|
||||
from wait import Wait
|
||||
from date_time_value import DateTimeValue
|
||||
import decorators
|
||||
|
@ -1,98 +0,0 @@
|
||||
# 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/.
|
||||
|
||||
import os
|
||||
import platform
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
|
||||
class B2GBuild(object):
|
||||
|
||||
@classmethod
|
||||
def find_b2g_dir(cls):
|
||||
for env_var in ('B2G_DIR', 'B2G_HOME'):
|
||||
if env_var in os.environ:
|
||||
env_dir = os.environ[env_var]
|
||||
env_dir = cls.check_b2g_dir(env_dir)
|
||||
if env_dir:
|
||||
return env_dir
|
||||
|
||||
cwd = os.getcwd()
|
||||
cwd = cls.check_b2g_dir(cwd)
|
||||
if cwd:
|
||||
return cwd
|
||||
|
||||
return None
|
||||
|
||||
@classmethod
|
||||
def check_adb(cls, homedir):
|
||||
if 'ADB' in os.environ:
|
||||
env_adb = os.environ['ADB']
|
||||
if os.path.exists(env_adb):
|
||||
return env_adb
|
||||
|
||||
return cls.check_host_binary(homedir, 'adb')
|
||||
|
||||
@classmethod
|
||||
def check_b2g_dir(cls, dir):
|
||||
if os.path.isfile(os.path.join(dir, 'load-config.sh')):
|
||||
return dir
|
||||
|
||||
oldstyle_dir = os.path.join(dir, 'glue', 'gonk-ics')
|
||||
if os.access(oldstyle_dir, os.F_OK):
|
||||
return oldstyle_dir
|
||||
|
||||
return None
|
||||
|
||||
@classmethod
|
||||
def check_fastboot(cls, homedir):
|
||||
return cls.check_host_binary(homedir, 'fastboot')
|
||||
|
||||
@classmethod
|
||||
def check_host_binary(cls, homedir, binary):
|
||||
host_dir = "linux-x86"
|
||||
if platform.system() == "Darwin":
|
||||
host_dir = "darwin-x86"
|
||||
binary_path = subprocess.Popen(['which', binary],
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT)
|
||||
if binary_path.wait() == 0:
|
||||
return binary_path.stdout.read().strip() # remove trailing newline
|
||||
binary_paths = [os.path.join(homedir, 'glue', 'gonk', 'out', 'host',
|
||||
host_dir, 'bin', binary),
|
||||
os.path.join(homedir, 'out', 'host', host_dir,
|
||||
'bin', binary),
|
||||
os.path.join(homedir, 'bin', binary)]
|
||||
for option in binary_paths:
|
||||
if os.path.exists(option):
|
||||
return option
|
||||
raise Exception('%s not found!' % binary)
|
||||
|
||||
def __init__(self, homedir=None, emulator=False):
|
||||
if not homedir:
|
||||
homedir = self.find_b2g_dir()
|
||||
else:
|
||||
homedir = self.check_b2g_dir(homedir)
|
||||
|
||||
if not homedir:
|
||||
raise EnvironmentError('Must define B2G_HOME or pass the homedir parameter')
|
||||
|
||||
self.homedir = homedir
|
||||
self.adb_path = self.check_adb(self.homedir)
|
||||
self.update_tools = os.path.join(self.homedir, 'tools', 'update-tools')
|
||||
self.fastboot_path = None if emulator else self.check_fastboot(self.homedir)
|
||||
|
||||
def import_update_tools(self):
|
||||
"""Import the update_tools package from B2G"""
|
||||
sys.path.append(self.update_tools)
|
||||
import update_tools
|
||||
sys.path.pop()
|
||||
return update_tools
|
||||
|
||||
def check_file(self, filePath):
|
||||
if not os.access(filePath, os.F_OK):
|
||||
raise Exception(('File not found: %s; did you pass the B2G home '
|
||||
'directory as the homedir parameter, or set '
|
||||
'B2G_HOME correctly?') % filePath)
|
@ -1,70 +0,0 @@
|
||||
# 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/.
|
||||
|
||||
from ConfigParser import ConfigParser
|
||||
import posixpath
|
||||
import shutil
|
||||
import tempfile
|
||||
import traceback
|
||||
|
||||
from b2gbuild import B2GBuild
|
||||
from mozdevice import DeviceManagerADB
|
||||
import mozcrash
|
||||
|
||||
|
||||
class B2GInstance(B2GBuild):
|
||||
|
||||
def __init__(self, devicemanager=None, symbols_path=None, **kwargs):
|
||||
B2GBuild.__init__(self, **kwargs)
|
||||
|
||||
self._dm = devicemanager
|
||||
self._remote_profiles = None
|
||||
self.symbols_path = symbols_path
|
||||
|
||||
@property
|
||||
def dm(self):
|
||||
if not self._dm:
|
||||
self._dm = DeviceManagerADB(adbPath=self.adb_path)
|
||||
return self._dm
|
||||
|
||||
@property
|
||||
def remote_profiles(self):
|
||||
if not self._remote_profiles:
|
||||
self.check_remote_profiles()
|
||||
return self._remote_profiles
|
||||
|
||||
def check_remote_profiles(self, remote_profiles_ini='/data/b2g/mozilla/profiles.ini'):
|
||||
if not self.dm.fileExists(remote_profiles_ini):
|
||||
raise Exception("Remote file '%s' not found" % remote_profiles_ini)
|
||||
|
||||
local_profiles_ini = tempfile.NamedTemporaryFile()
|
||||
self.dm.getFile(remote_profiles_ini, local_profiles_ini.name)
|
||||
cfg = ConfigParser()
|
||||
cfg.read(local_profiles_ini.name)
|
||||
|
||||
remote_profiles = []
|
||||
for section in cfg.sections():
|
||||
if cfg.has_option(section, 'Path'):
|
||||
if cfg.has_option(section, 'IsRelative') and cfg.getint(section, 'IsRelative'):
|
||||
remote_profiles.append(posixpath.join(posixpath.dirname(remote_profiles_ini), cfg.get(section, 'Path')))
|
||||
else:
|
||||
remote_profiles.append(cfg.get(section, 'Path'))
|
||||
self._remote_profiles = remote_profiles
|
||||
return remote_profiles
|
||||
|
||||
def check_for_crashes(self):
|
||||
remote_dump_dirs = [posixpath.join(p, 'minidumps') for p in self.remote_profiles]
|
||||
crashed = False
|
||||
for remote_dump_dir in remote_dump_dirs:
|
||||
local_dump_dir = tempfile.mkdtemp()
|
||||
self.dm.getDirectory(remote_dump_dir, local_dump_dir)
|
||||
try:
|
||||
if mozcrash.check_for_crashes(local_dump_dir, self.symbols_path):
|
||||
crashed = True
|
||||
except:
|
||||
traceback.print_exc()
|
||||
finally:
|
||||
shutil.rmtree(local_dump_dir)
|
||||
self.dm.removeDir(remote_dump_dir)
|
||||
return crashed
|
@ -1,539 +0,0 @@
|
||||
# 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/.
|
||||
|
||||
from b2ginstance import B2GInstance
|
||||
import datetime
|
||||
from mozdevice import devicemanagerADB, DMError
|
||||
from mozprocess import ProcessHandlerMixin
|
||||
import os
|
||||
import re
|
||||
import platform
|
||||
import shutil
|
||||
import socket
|
||||
import subprocess
|
||||
from telnetlib import Telnet
|
||||
import tempfile
|
||||
import time
|
||||
import traceback
|
||||
|
||||
from emulator_battery import EmulatorBattery
|
||||
from emulator_geo import EmulatorGeo
|
||||
from emulator_screen import EmulatorScreen
|
||||
from decorators import uses_marionette
|
||||
|
||||
from errors import (
|
||||
InstallGeckoError,
|
||||
InvalidResponseException,
|
||||
MarionetteException,
|
||||
ScriptTimeoutException,
|
||||
TimeoutException
|
||||
)
|
||||
|
||||
|
||||
class LogOutputProc(ProcessHandlerMixin):
|
||||
"""
|
||||
Process handler for processes which save all output to a logfile.
|
||||
If no logfile is specified, output will still be consumed to prevent
|
||||
the output pipe's from overflowing.
|
||||
"""
|
||||
|
||||
def __init__(self, cmd, logfile=None, **kwargs):
|
||||
self.logfile = logfile
|
||||
kwargs.setdefault('processOutputLine', []).append(self.log_output)
|
||||
ProcessHandlerMixin.__init__(self, cmd, **kwargs)
|
||||
|
||||
def log_output(self, line):
|
||||
if not self.logfile:
|
||||
return
|
||||
|
||||
f = open(self.logfile, 'a')
|
||||
f.write(line + "\n")
|
||||
f.flush()
|
||||
|
||||
|
||||
class Emulator(object):
|
||||
|
||||
deviceRe = re.compile(r"^emulator-(\d+)(\s*)(.*)$")
|
||||
_default_res = '320x480'
|
||||
prefs = {'app.update.enabled': False,
|
||||
'app.update.staging.enabled': False,
|
||||
'app.update.service.enabled': False}
|
||||
env = {'MOZ_CRASHREPORTER': '1',
|
||||
'MOZ_CRASHREPORTER_NO_REPORT': '1',
|
||||
'MOZ_CRASHREPORTER_SHUTDOWN': '1'}
|
||||
|
||||
def __init__(self, homedir=None, noWindow=False, logcat_dir=None,
|
||||
arch="x86", emulatorBinary=None, res=None, sdcard=None,
|
||||
symbols_path=None, userdata=None):
|
||||
self.port = None
|
||||
self.dm = None
|
||||
self._emulator_launched = False
|
||||
self.proc = None
|
||||
self.marionette_port = None
|
||||
self.telnet = None
|
||||
self._tmp_sdcard = None
|
||||
self._tmp_userdata = None
|
||||
self._adb_started = False
|
||||
self.logcat_dir = logcat_dir
|
||||
self.logcat_proc = None
|
||||
self.arch = arch
|
||||
self.binary = emulatorBinary
|
||||
self.res = res or self._default_res
|
||||
self.battery = EmulatorBattery(self)
|
||||
self.geo = EmulatorGeo(self)
|
||||
self.screen = EmulatorScreen(self)
|
||||
self.homedir = homedir
|
||||
self.sdcard = sdcard
|
||||
self.symbols_path = symbols_path
|
||||
self.noWindow = noWindow
|
||||
if self.homedir is not None:
|
||||
self.homedir = os.path.expanduser(homedir)
|
||||
self.dataImg = userdata
|
||||
self.copy_userdata = self.dataImg is None
|
||||
|
||||
def _check_for_b2g(self):
|
||||
self.b2g = B2GInstance(homedir=self.homedir, emulator=True,
|
||||
symbols_path=self.symbols_path)
|
||||
self.adb = self.b2g.adb_path
|
||||
self.homedir = self.b2g.homedir
|
||||
|
||||
if self.arch not in ("x86", "arm"):
|
||||
raise Exception("Emulator architecture must be one of x86, arm, got: %s" %
|
||||
self.arch)
|
||||
|
||||
host_dir = "linux-x86"
|
||||
if platform.system() == "Darwin":
|
||||
host_dir = "darwin-x86"
|
||||
|
||||
host_bin_dir = os.path.join("out", "host", host_dir, "bin")
|
||||
|
||||
if self.arch == "x86":
|
||||
binary = os.path.join(host_bin_dir, "emulator-x86")
|
||||
kernel = "prebuilts/qemu-kernel/x86/kernel-qemu"
|
||||
sysdir = "out/target/product/generic_x86"
|
||||
self.tail_args = []
|
||||
else:
|
||||
binary = os.path.join(host_bin_dir, "emulator")
|
||||
kernel = "prebuilts/qemu-kernel/arm/kernel-qemu-armv7"
|
||||
sysdir = "out/target/product/generic"
|
||||
self.tail_args = ["-cpu", "cortex-a8"]
|
||||
|
||||
if(self.sdcard):
|
||||
self.mksdcard = os.path.join(self.homedir, host_bin_dir, "mksdcard")
|
||||
self.create_sdcard(self.sdcard)
|
||||
|
||||
if not self.binary:
|
||||
self.binary = os.path.join(self.homedir, binary)
|
||||
|
||||
self.b2g.check_file(self.binary)
|
||||
|
||||
self.kernelImg = os.path.join(self.homedir, kernel)
|
||||
self.b2g.check_file(self.kernelImg)
|
||||
|
||||
self.sysDir = os.path.join(self.homedir, sysdir)
|
||||
self.b2g.check_file(self.sysDir)
|
||||
|
||||
if not self.dataImg:
|
||||
self.dataImg = os.path.join(self.sysDir, 'userdata.img')
|
||||
self.b2g.check_file(self.dataImg)
|
||||
|
||||
def __del__(self):
|
||||
if self.telnet:
|
||||
self.telnet.write('exit\n')
|
||||
self.telnet.read_all()
|
||||
|
||||
@property
|
||||
def args(self):
|
||||
qemuArgs = [self.binary,
|
||||
'-kernel', self.kernelImg,
|
||||
'-sysdir', self.sysDir,
|
||||
'-data', self.dataImg]
|
||||
if self._tmp_sdcard:
|
||||
qemuArgs.extend(['-sdcard', self._tmp_sdcard])
|
||||
if self.noWindow:
|
||||
qemuArgs.append('-no-window')
|
||||
qemuArgs.extend(['-memory', '512',
|
||||
'-partition-size', '512',
|
||||
'-verbose',
|
||||
'-skin', self.res,
|
||||
'-gpu', 'on',
|
||||
'-qemu'] + self.tail_args)
|
||||
return qemuArgs
|
||||
|
||||
@property
|
||||
def is_running(self):
|
||||
if self._emulator_launched:
|
||||
return self.proc is not None and self.proc.poll() is None
|
||||
else:
|
||||
return self.port is not None
|
||||
|
||||
def check_for_crash(self):
|
||||
"""
|
||||
Checks if the emulator has crashed or not. Always returns False if
|
||||
we've connected to an already-running emulator, since we can't track
|
||||
the emulator's pid in that case. Otherwise, returns True iff
|
||||
self.proc is not None (meaning the emulator hasn't been explicitly
|
||||
closed), and self.proc.poll() is also not None (meaning the emulator
|
||||
process has terminated).
|
||||
"""
|
||||
return self._emulator_launched and self.proc is not None \
|
||||
and self.proc.poll() is not None
|
||||
|
||||
def check_for_minidumps(self):
|
||||
return self.b2g.check_for_crashes()
|
||||
|
||||
def create_sdcard(self, sdcard):
|
||||
self._tmp_sdcard = tempfile.mktemp(prefix='sdcard')
|
||||
sdargs = [self.mksdcard, "-l", "mySdCard", sdcard, self._tmp_sdcard]
|
||||
sd = subprocess.Popen(sdargs, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||
retcode = sd.wait()
|
||||
if retcode:
|
||||
raise Exception('unable to create sdcard : exit code %d: %s'
|
||||
% (retcode, sd.stdout.read()))
|
||||
return None
|
||||
|
||||
def _run_adb(self, args):
|
||||
args.insert(0, self.adb)
|
||||
if self.port:
|
||||
args.insert(1, '-s')
|
||||
args.insert(2, 'emulator-%d' % self.port)
|
||||
adb = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||
retcode = adb.wait()
|
||||
if retcode:
|
||||
raise Exception('adb terminated with exit code %d: %s'
|
||||
% (retcode, adb.stdout.read()))
|
||||
return adb.stdout.read()
|
||||
|
||||
def _get_telnet_response(self, command=None):
|
||||
output = []
|
||||
assert(self.telnet)
|
||||
if command is not None:
|
||||
self.telnet.write('%s\n' % command)
|
||||
while True:
|
||||
line = self.telnet.read_until('\n')
|
||||
output.append(line.rstrip())
|
||||
if line.startswith('OK'):
|
||||
return output
|
||||
elif line.startswith('KO:'):
|
||||
raise Exception('bad telnet response: %s' % line)
|
||||
|
||||
def _run_telnet(self, command):
|
||||
if not self.telnet:
|
||||
self.telnet = Telnet('localhost', self.port)
|
||||
self._get_telnet_response()
|
||||
return self._get_telnet_response(command)
|
||||
|
||||
def _run_shell(self, args):
|
||||
args.insert(0, 'shell')
|
||||
return self._run_adb(args).split('\r\n')
|
||||
|
||||
def close(self):
|
||||
if self.is_running and self._emulator_launched:
|
||||
self.proc.kill()
|
||||
if self._adb_started:
|
||||
self._run_adb(['kill-server'])
|
||||
self._adb_started = False
|
||||
if self.proc:
|
||||
retcode = self.proc.poll()
|
||||
self.proc = None
|
||||
if self._tmp_userdata:
|
||||
os.remove(self._tmp_userdata)
|
||||
self._tmp_userdata = None
|
||||
if self._tmp_sdcard:
|
||||
os.remove(self._tmp_sdcard)
|
||||
self._tmp_sdcard = None
|
||||
return retcode
|
||||
if self.logcat_proc and self.logcat_proc.proc.poll() is None:
|
||||
self.logcat_proc.kill()
|
||||
return 0
|
||||
|
||||
def _get_adb_devices(self):
|
||||
offline = set()
|
||||
online = set()
|
||||
output = self._run_adb(['devices'])
|
||||
for line in output.split('\n'):
|
||||
m = self.deviceRe.match(line)
|
||||
if m:
|
||||
if m.group(3) == 'offline':
|
||||
offline.add(m.group(1))
|
||||
else:
|
||||
online.add(m.group(1))
|
||||
return (online, offline)
|
||||
|
||||
def start_adb(self):
|
||||
result = self._run_adb(['start-server'])
|
||||
# We keep track of whether we've started adb or not, so we know
|
||||
# if we need to kill it.
|
||||
if 'daemon started successfully' in result:
|
||||
self._adb_started = True
|
||||
else:
|
||||
self._adb_started = False
|
||||
|
||||
@uses_marionette
|
||||
def wait_for_system_message(self, marionette):
|
||||
marionette.set_script_timeout(45000)
|
||||
# Telephony API's won't be available immediately upon emulator
|
||||
# boot; we have to wait for the syste-message-listener-ready
|
||||
# message before we'll be able to use them successfully. See
|
||||
# bug 792647.
|
||||
print 'waiting for system-message-listener-ready...'
|
||||
try:
|
||||
marionette.execute_async_script("""
|
||||
waitFor(
|
||||
function() { marionetteScriptFinished(true); },
|
||||
function() { return isSystemMessageListenerReady(); }
|
||||
);
|
||||
""")
|
||||
except ScriptTimeoutException:
|
||||
print 'timed out'
|
||||
# We silently ignore the timeout if it occurs, since
|
||||
# isSystemMessageListenerReady() isn't available on
|
||||
# older emulators. 45s *should* be enough of a delay
|
||||
# to allow telephony API's to work.
|
||||
pass
|
||||
except (InvalidResponseException, IOError):
|
||||
self.check_for_minidumps()
|
||||
raise
|
||||
print '...done'
|
||||
|
||||
def connect(self):
|
||||
self.adb = B2GInstance.check_adb(self.homedir, emulator=True)
|
||||
self.start_adb()
|
||||
|
||||
online, offline = self._get_adb_devices()
|
||||
now = datetime.datetime.now()
|
||||
while online == set([]):
|
||||
time.sleep(1)
|
||||
if datetime.datetime.now() - now > datetime.timedelta(seconds=60):
|
||||
raise Exception('timed out waiting for emulator to be available')
|
||||
online, offline = self._get_adb_devices()
|
||||
self.port = int(list(online)[0])
|
||||
|
||||
self.dm = devicemanagerADB.DeviceManagerADB(adbPath=self.adb,
|
||||
deviceSerial='emulator-%d' % self.port)
|
||||
|
||||
def start(self):
|
||||
self._check_for_b2g()
|
||||
self.start_adb()
|
||||
|
||||
qemu_args = self.args[:]
|
||||
if self.copy_userdata:
|
||||
# Make a copy of the userdata.img for this instance of the emulator to use.
|
||||
self._tmp_userdata = tempfile.mktemp(prefix='marionette')
|
||||
shutil.copyfile(self.dataImg, self._tmp_userdata)
|
||||
qemu_args[qemu_args.index('-data') + 1] = self._tmp_userdata
|
||||
|
||||
original_online, original_offline = self._get_adb_devices()
|
||||
|
||||
filename = None
|
||||
if self.logcat_dir:
|
||||
filename = os.path.join(self.logcat_dir, 'qemu.log')
|
||||
if os.path.isfile(filename):
|
||||
self.rotate_log(filename)
|
||||
|
||||
self.proc = LogOutputProc(qemu_args, filename)
|
||||
self.proc.run()
|
||||
|
||||
online, offline = self._get_adb_devices()
|
||||
now = datetime.datetime.now()
|
||||
while online - original_online == set([]):
|
||||
time.sleep(1)
|
||||
if datetime.datetime.now() - now > datetime.timedelta(seconds=60):
|
||||
raise TimeoutException('timed out waiting for emulator to start')
|
||||
online, offline = self._get_adb_devices()
|
||||
self.port = int(list(online - original_online)[0])
|
||||
self._emulator_launched = True
|
||||
|
||||
self.dm = devicemanagerADB.DeviceManagerADB(adbPath=self.adb,
|
||||
deviceSerial='emulator-%d' % self.port)
|
||||
|
||||
# bug 802877
|
||||
time.sleep(10)
|
||||
self.geo.set_default_location()
|
||||
self.screen.initialize()
|
||||
|
||||
if self.logcat_dir:
|
||||
self.save_logcat()
|
||||
|
||||
# setup DNS fix for networking
|
||||
self._run_adb(['shell', 'setprop', 'net.dns1', '10.0.2.3'])
|
||||
|
||||
@uses_marionette
|
||||
def wait_for_homescreen(self, marionette):
|
||||
print 'waiting for homescreen...'
|
||||
|
||||
marionette.set_context(marionette.CONTEXT_CONTENT)
|
||||
marionette.execute_async_script("""
|
||||
log('waiting for mozbrowserloadend');
|
||||
window.addEventListener('mozbrowserloadend', function loaded(aEvent) {
|
||||
log('received mozbrowserloadend for ' + aEvent.target.src);
|
||||
if (aEvent.target.src.indexOf('ftu') != -1 || aEvent.target.src.indexOf('homescreen') != -1) {
|
||||
window.removeEventListener('mozbrowserloadend', loaded);
|
||||
marionetteScriptFinished();
|
||||
}
|
||||
});""", script_timeout=120000)
|
||||
print '...done'
|
||||
|
||||
def setup(self, marionette, gecko_path=None, busybox=None):
|
||||
self.set_environment(marionette)
|
||||
if busybox:
|
||||
self.install_busybox(busybox)
|
||||
|
||||
if gecko_path:
|
||||
self.install_gecko(gecko_path, marionette)
|
||||
|
||||
self.wait_for_system_message(marionette)
|
||||
self.set_prefs(marionette)
|
||||
|
||||
@uses_marionette
|
||||
def set_environment(self, marionette):
|
||||
for k, v in self.env.iteritems():
|
||||
marionette.execute_script("""
|
||||
let env = Cc["@mozilla.org/process/environment;1"].
|
||||
getService(Ci.nsIEnvironment);
|
||||
env.set("%s", "%s");
|
||||
""" % (k, v))
|
||||
|
||||
@uses_marionette
|
||||
def set_prefs(self, marionette):
|
||||
for pref in self.prefs:
|
||||
marionette.execute_script("""
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
let argtype = typeof(arguments[1]);
|
||||
switch(argtype) {
|
||||
case 'boolean':
|
||||
Services.prefs.setBoolPref(arguments[0], arguments[1]);
|
||||
break;
|
||||
case 'number':
|
||||
Services.prefs.setIntPref(arguments[0], arguments[1]);
|
||||
break;
|
||||
default:
|
||||
Services.prefs.setCharPref(arguments[0], arguments[1]);
|
||||
}
|
||||
""", [pref, self.prefs[pref]])
|
||||
|
||||
def restart_b2g(self):
|
||||
print 'restarting B2G'
|
||||
self.dm.shellCheckOutput(['stop', 'b2g'])
|
||||
time.sleep(10)
|
||||
self.dm.shellCheckOutput(['start', 'b2g'])
|
||||
|
||||
if not self.wait_for_port():
|
||||
raise TimeoutException("Timeout waiting for marionette on port '%s'" % self.marionette_port)
|
||||
|
||||
def install_gecko(self, gecko_path, marionette):
|
||||
"""
|
||||
Install gecko into the emulator using adb push. Restart b2g after the
|
||||
installation.
|
||||
"""
|
||||
# See bug 800102. We use this particular method of installing
|
||||
# gecko in order to avoid an adb bug in which adb will sometimes
|
||||
# hang indefinitely while copying large files to the system
|
||||
# partition.
|
||||
print 'installing gecko binaries...'
|
||||
|
||||
# see bug 809437 for the path that lead to this madness
|
||||
try:
|
||||
# need to remount so we can write to /system/b2g
|
||||
self._run_adb(['remount'])
|
||||
self.dm.removeDir('/data/local/b2g')
|
||||
self.dm.mkDir('/data/local/b2g')
|
||||
self.dm.pushDir(gecko_path, '/data/local/b2g', retryLimit=10)
|
||||
|
||||
self.dm.shellCheckOutput(['stop', 'b2g'])
|
||||
|
||||
for root, dirs, files in os.walk(gecko_path):
|
||||
for filename in files:
|
||||
rel_path = os.path.relpath(os.path.join(root, filename), gecko_path)
|
||||
data_local_file = os.path.join('/data/local/b2g', rel_path)
|
||||
system_b2g_file = os.path.join('/system/b2g', rel_path)
|
||||
|
||||
print 'copying', data_local_file, 'to', system_b2g_file
|
||||
self.dm.shellCheckOutput(['dd',
|
||||
'if=%s' % data_local_file,
|
||||
'of=%s' % system_b2g_file])
|
||||
self.restart_b2g()
|
||||
|
||||
except (DMError, MarionetteException):
|
||||
# Bug 812395 - raise a single exception type for these so we can
|
||||
# explicitly catch them elsewhere.
|
||||
|
||||
# print exception, but hide from mozharness error detection
|
||||
exc = traceback.format_exc()
|
||||
exc = exc.replace('Traceback', '_traceback')
|
||||
print exc
|
||||
|
||||
raise InstallGeckoError("unable to restart B2G after installing gecko")
|
||||
|
||||
def install_busybox(self, busybox):
|
||||
self._run_adb(['remount'])
|
||||
|
||||
remote_file = "/system/bin/busybox"
|
||||
print 'pushing %s' % remote_file
|
||||
self.dm.pushFile(busybox, remote_file, retryLimit=10)
|
||||
self._run_adb(['shell', 'cd /system/bin; chmod 555 busybox; for x in `./busybox --list`; do ln -s ./busybox $x; done'])
|
||||
self.dm._verifyZip()
|
||||
|
||||
def rotate_log(self, srclog, index=1):
|
||||
""" Rotate a logfile, by recursively rotating logs further in the sequence,
|
||||
deleting the last file if necessary.
|
||||
"""
|
||||
basename = os.path.basename(srclog)
|
||||
basename = basename[:-len('.log')]
|
||||
if index > 1:
|
||||
basename = basename[:-len('.1')]
|
||||
basename = '%s.%d.log' % (basename, index)
|
||||
|
||||
destlog = os.path.join(self.logcat_dir, basename)
|
||||
if os.path.isfile(destlog):
|
||||
if index == 3:
|
||||
os.remove(destlog)
|
||||
else:
|
||||
self.rotate_log(destlog, index+1)
|
||||
shutil.move(srclog, destlog)
|
||||
|
||||
def save_logcat(self):
|
||||
""" Save the output of logcat to a file.
|
||||
"""
|
||||
filename = os.path.join(self.logcat_dir, "emulator-%d.log" % self.port)
|
||||
if os.path.isfile(filename):
|
||||
self.rotate_log(filename)
|
||||
cmd = [self.adb, '-s', 'emulator-%d' % self.port, 'logcat', '-v', 'threadtime']
|
||||
|
||||
self.logcat_proc = LogOutputProc(cmd, filename)
|
||||
self.logcat_proc.run()
|
||||
|
||||
def setup_port_forwarding(self, remote_port):
|
||||
""" Set up TCP port forwarding to the specified port on the device,
|
||||
using any availble local port, and return the local port.
|
||||
"""
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
s.bind(("",0))
|
||||
local_port = s.getsockname()[1]
|
||||
s.close()
|
||||
|
||||
self._run_adb(['forward',
|
||||
'tcp:%d' % local_port,
|
||||
'tcp:%d' % remote_port])
|
||||
|
||||
self.marionette_port = local_port
|
||||
|
||||
return local_port
|
||||
|
||||
def wait_for_port(self, timeout=300):
|
||||
assert(self.marionette_port)
|
||||
starttime = datetime.datetime.now()
|
||||
while datetime.datetime.now() - starttime < datetime.timedelta(seconds=timeout):
|
||||
try:
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
sock.connect(('localhost', self.marionette_port))
|
||||
data = sock.recv(16)
|
||||
sock.close()
|
||||
if ':' in data:
|
||||
return True
|
||||
except:
|
||||
import traceback
|
||||
print traceback.format_exc()
|
||||
time.sleep(1)
|
||||
return False
|
@ -25,21 +25,20 @@ class GeckoInstance(object):
|
||||
self.marionette_host = host
|
||||
self.marionette_port = port
|
||||
self.bin = bin
|
||||
self.profile = profile
|
||||
self.profile_path = profile
|
||||
self.app_args = app_args or []
|
||||
self.runner = None
|
||||
self.symbols_path = symbols_path
|
||||
self.gecko_log = gecko_log
|
||||
|
||||
def start(self):
|
||||
profile_path = self.profile
|
||||
profile_args = {"preferences": self.required_prefs}
|
||||
if not profile_path:
|
||||
runner_class = Runner
|
||||
if not self.profile_path:
|
||||
profile_args["restore"] = False
|
||||
profile = Profile(**profile_args)
|
||||
else:
|
||||
runner_class = CloneRunner
|
||||
profile_args["path_from"] = profile_path
|
||||
profile_args["path_from"] = self.profile_path
|
||||
profile = Profile.clone(**profile_args)
|
||||
|
||||
if self.gecko_log is None:
|
||||
self.gecko_log = 'gecko.log'
|
||||
@ -57,13 +56,13 @@ class GeckoInstance(object):
|
||||
# https://developer.mozilla.org/docs/Environment_variables_affecting_crash_reporting
|
||||
env.update({ 'MOZ_CRASHREPORTER': '1',
|
||||
'MOZ_CRASHREPORTER_NO_REPORT': '1', })
|
||||
self.runner = runner_class.create(
|
||||
self.runner = Runner(
|
||||
binary=self.bin,
|
||||
profile_args=profile_args,
|
||||
profile=profile,
|
||||
cmdargs=['-no-remote', '-marionette'] + self.app_args,
|
||||
env=env,
|
||||
symbols_path=self.symbols_path,
|
||||
kp_kwargs={
|
||||
process_args={
|
||||
'processOutputLine': [NullOutput()],
|
||||
'logfile': self.gecko_log})
|
||||
self.runner.start()
|
||||
@ -72,24 +71,19 @@ class GeckoInstance(object):
|
||||
return self.runner.check_for_crashes()
|
||||
|
||||
def close(self):
|
||||
self.runner.stop()
|
||||
self.runner.cleanup()
|
||||
if self.runner:
|
||||
self.runner.stop()
|
||||
self.runner.cleanup()
|
||||
|
||||
|
||||
class B2GDesktopInstance(GeckoInstance):
|
||||
|
||||
required_prefs = {"focusmanager.testmode": True}
|
||||
|
||||
apps = {'b2g': B2GDesktopInstance,
|
||||
'b2gdesktop': B2GDesktopInstance}
|
||||
|
||||
|
||||
class CloneRunner(Runner):
|
||||
|
||||
profile_class = Profile.clone
|
||||
|
||||
|
||||
class NullOutput(object):
|
||||
|
||||
def __call__(self, line):
|
||||
pass
|
||||
|
||||
|
||||
apps = {'b2g': B2GDesktopInstance,
|
||||
'b2gdesktop': B2GDesktopInstance}
|
||||
|
@ -6,27 +6,20 @@ import ConfigParser
|
||||
import datetime
|
||||
import os
|
||||
import socket
|
||||
import sys
|
||||
import StringIO
|
||||
import time
|
||||
import traceback
|
||||
import base64
|
||||
|
||||
from application_cache import ApplicationCache
|
||||
from decorators import do_crash_check
|
||||
from emulator import Emulator
|
||||
from emulator_screen import EmulatorScreen
|
||||
from errors import (
|
||||
ErrorCodes, MarionetteException, InstallGeckoError, TimeoutException, InvalidResponseException,
|
||||
JavascriptException, NoSuchElementException, XPathLookupException, NoSuchWindowException,
|
||||
StaleElementException, ScriptTimeoutException, ElementNotVisibleException,
|
||||
NoSuchFrameException, InvalidElementStateException, NoAlertPresentException,
|
||||
InvalidCookieDomainException, UnableToSetCookieException, InvalidSelectorException,
|
||||
MoveTargetOutOfBoundsException, FrameSendNotInitializedError, FrameSendFailureError
|
||||
)
|
||||
from keys import Keys
|
||||
from marionette_transport import MarionetteTransport
|
||||
|
||||
from mozrunner import B2GEmulatorRunner
|
||||
|
||||
import geckoinstance
|
||||
import errors
|
||||
|
||||
class HTMLElement(object):
|
||||
"""
|
||||
@ -451,32 +444,24 @@ class Marionette(object):
|
||||
TIMEOUT_SEARCH = 'implicit'
|
||||
TIMEOUT_SCRIPT = 'script'
|
||||
TIMEOUT_PAGE = 'page load'
|
||||
SCREEN_ORIENTATIONS = {"portrait": EmulatorScreen.SO_PORTRAIT_PRIMARY,
|
||||
"landscape": EmulatorScreen.SO_LANDSCAPE_PRIMARY,
|
||||
"portrait-primary": EmulatorScreen.SO_PORTRAIT_PRIMARY,
|
||||
"landscape-primary": EmulatorScreen.SO_LANDSCAPE_PRIMARY,
|
||||
"portrait-secondary": EmulatorScreen.SO_PORTRAIT_SECONDARY,
|
||||
"landscape-secondary": EmulatorScreen.SO_LANDSCAPE_SECONDARY}
|
||||
|
||||
def __init__(self, host='localhost', port=2828, app=None, app_args=None, bin=None,
|
||||
profile=None, emulator=None, sdcard=None, emulatorBinary=None,
|
||||
emulatorImg=None, emulator_res=None, gecko_path=None,
|
||||
connectToRunningEmulator=False, homedir=None, baseurl=None,
|
||||
noWindow=False, logcat_dir=None, busybox=None, symbols_path=None,
|
||||
timeout=None, device_serial=None, gecko_log=None):
|
||||
profile=None, emulator=None, sdcard=None, emulator_img=None,
|
||||
emulator_binary=None, emulator_res=None, connect_to_running_emulator=False,
|
||||
gecko_log=None, homedir=None, baseurl=None, no_window=False, logdir=None,
|
||||
busybox=None, symbols_path=None, timeout=None, device_serial=None,
|
||||
adb_path=None):
|
||||
self.host = host
|
||||
self.port = self.local_port = port
|
||||
self.bin = bin
|
||||
self.instance = None
|
||||
self.profile = profile
|
||||
self.session = None
|
||||
self.window = None
|
||||
self.runner = None
|
||||
self.emulator = None
|
||||
self.extra_emulators = []
|
||||
self.homedir = homedir
|
||||
self.baseurl = baseurl
|
||||
self.noWindow = noWindow
|
||||
self.logcat_dir = logcat_dir
|
||||
self.no_window = no_window
|
||||
self._test_name = None
|
||||
self.timeout = timeout
|
||||
self.device_serial = device_serial
|
||||
@ -485,7 +470,7 @@ class Marionette(object):
|
||||
port = int(self.port)
|
||||
if not Marionette.is_port_available(port, host=self.host):
|
||||
ex_msg = "%s:%d is unavailable." % (self.host, port)
|
||||
raise MarionetteException(message=ex_msg)
|
||||
raise errors.MarionetteException(message=ex_msg)
|
||||
if app:
|
||||
# select instance class for the given app
|
||||
try:
|
||||
@ -504,52 +489,56 @@ class Marionette(object):
|
||||
KeyError):
|
||||
instance_class = geckoinstance.GeckoInstance
|
||||
self.instance = instance_class(host=self.host, port=self.port,
|
||||
bin=self.bin, profile=self.profile,
|
||||
bin=self.bin, profile=profile,
|
||||
app_args=app_args, symbols_path=symbols_path,
|
||||
gecko_log=gecko_log)
|
||||
self.instance.start()
|
||||
assert(self.wait_for_port()), "Timed out waiting for port!"
|
||||
|
||||
if emulator:
|
||||
self.emulator = Emulator(homedir=homedir,
|
||||
noWindow=self.noWindow,
|
||||
logcat_dir=self.logcat_dir,
|
||||
arch=emulator,
|
||||
sdcard=sdcard,
|
||||
symbols_path=symbols_path,
|
||||
emulatorBinary=emulatorBinary,
|
||||
userdata=emulatorImg,
|
||||
res=emulator_res)
|
||||
self.runner = B2GEmulatorRunner(b2g_home=homedir,
|
||||
no_window=self.no_window,
|
||||
logdir=logdir,
|
||||
arch=emulator,
|
||||
sdcard=sdcard,
|
||||
symbols_path=symbols_path,
|
||||
binary=emulator_binary,
|
||||
userdata=emulator_img,
|
||||
resolution=emulator_res,
|
||||
profile=profile,
|
||||
adb_path=adb_path)
|
||||
self.emulator = self.runner.device
|
||||
self.emulator.start()
|
||||
self.port = self.emulator.setup_port_forwarding(self.port)
|
||||
assert(self.emulator.wait_for_port()), "Timed out waiting for port!"
|
||||
assert(self.emulator.wait_for_port(self.port)), "Timed out waiting for port!"
|
||||
|
||||
if connectToRunningEmulator:
|
||||
self.emulator = Emulator(homedir=homedir,
|
||||
logcat_dir=self.logcat_dir)
|
||||
if connect_to_running_emulator:
|
||||
self.runner = B2GEmulatorRunner(b2g_home=homedir,
|
||||
logdir=logdir)
|
||||
self.emulator = self.runner.device
|
||||
self.emulator.connect()
|
||||
self.port = self.emulator.setup_port_forwarding(self.port)
|
||||
assert(self.emulator.wait_for_port()), "Timed out waiting for port!"
|
||||
assert(self.emulator.wait_for_port(self.port)), "Timed out waiting for port!"
|
||||
|
||||
self.client = MarionetteTransport(self.host, self.port)
|
||||
|
||||
if emulator:
|
||||
self.emulator.setup(self,
|
||||
gecko_path=gecko_path,
|
||||
busybox=busybox)
|
||||
if busybox:
|
||||
self.emulator.install_busybox(busybox=busybox)
|
||||
self.emulator.wait_for_system_message(self)
|
||||
|
||||
def cleanup(self):
|
||||
if self.session:
|
||||
try:
|
||||
self.delete_session()
|
||||
except (MarionetteException, socket.error, IOError):
|
||||
except (errors.MarionetteException, socket.error, IOError):
|
||||
# These exceptions get thrown if the Marionette server
|
||||
# hit an exception/died or the connection died. We can
|
||||
# do no further server-side cleanup in this case.
|
||||
pass
|
||||
self.session = None
|
||||
if self.emulator:
|
||||
self.emulator.close()
|
||||
if self.runner:
|
||||
self.runner.cleanup()
|
||||
if self.instance:
|
||||
self.instance.close()
|
||||
for qemu in self.extra_emulators:
|
||||
@ -570,26 +559,6 @@ class Marionette(object):
|
||||
finally:
|
||||
s.close()
|
||||
|
||||
@classmethod
|
||||
def getMarionetteOrExit(cls, *args, **kwargs):
|
||||
try:
|
||||
m = cls(*args, **kwargs)
|
||||
return m
|
||||
except InstallGeckoError:
|
||||
# Bug 812395 - the process of installing gecko into the emulator
|
||||
# and then restarting B2G tickles some bug in the emulator/b2g
|
||||
# that intermittently causes B2G to fail to restart. To work
|
||||
# around this in TBPL runs, we will fail gracefully from this
|
||||
# error so that the mozharness script can try the run again.
|
||||
|
||||
# This string will get caught by mozharness and will cause it
|
||||
# to retry the tests.
|
||||
print "Error installing gecko!"
|
||||
|
||||
# Exit without a normal exception to prevent mozharness from
|
||||
# flagging the error.
|
||||
sys.exit()
|
||||
|
||||
def wait_for_port(self, timeout=60):
|
||||
starttime = datetime.datetime.now()
|
||||
while datetime.datetime.now() - starttime < datetime.timedelta(seconds=timeout):
|
||||
@ -609,7 +578,7 @@ class Marionette(object):
|
||||
@do_crash_check
|
||||
def _send_message(self, command, response_key="ok", **kwargs):
|
||||
if not self.session and command != "newSession":
|
||||
raise MarionetteException("Please start a session")
|
||||
raise errors.MarionetteException("Please start a session")
|
||||
|
||||
message = {"name": command}
|
||||
if self.session:
|
||||
@ -623,8 +592,8 @@ class Marionette(object):
|
||||
self.session = None
|
||||
self.window = None
|
||||
self.client.close()
|
||||
raise TimeoutException(
|
||||
"Connection timed out", status=ErrorCodes.TIMEOUT)
|
||||
raise errors.TimeoutException(
|
||||
"Connection timed out", status=errors.ErrorCodes.TIMEOUT)
|
||||
|
||||
# Process any emulator commands that are sent from a script
|
||||
# while it's executing.
|
||||
@ -646,7 +615,7 @@ class Marionette(object):
|
||||
def _handle_emulator_cmd(self, response):
|
||||
cmd = response.get("emulator_cmd")
|
||||
if not cmd or not self.emulator:
|
||||
raise MarionetteException(
|
||||
raise errors.MarionetteException(
|
||||
"No emulator in this test to run command against")
|
||||
cmd = cmd.encode("ascii")
|
||||
result = self.emulator._run_telnet(cmd)
|
||||
@ -657,9 +626,12 @@ class Marionette(object):
|
||||
def _handle_emulator_shell(self, response):
|
||||
args = response.get("emulator_shell")
|
||||
if not isinstance(args, list) or not self.emulator:
|
||||
raise MarionetteException(
|
||||
raise errors.MarionetteException(
|
||||
"No emulator in this test to run shell command against")
|
||||
result = self.emulator._run_shell(args)
|
||||
buf = StringIO.StringIO()
|
||||
self.emulator.dm.shell(args, buf)
|
||||
result = str(buf.getvalue()[0:-1]).rstrip().splitlines()
|
||||
buf.close()
|
||||
return self.client.send({"name": "emulatorCmdResult",
|
||||
"id": response.get("id"),
|
||||
"result": result})
|
||||
@ -671,62 +643,59 @@ class Marionette(object):
|
||||
stacktrace = response['error'].get('stacktrace')
|
||||
# status numbers come from
|
||||
# http://code.google.com/p/selenium/wiki/JsonWireProtocol#Response_Status_Codes
|
||||
if status == ErrorCodes.NO_SUCH_ELEMENT:
|
||||
raise NoSuchElementException(message=message, status=status, stacktrace=stacktrace)
|
||||
elif status == ErrorCodes.NO_SUCH_FRAME:
|
||||
raise NoSuchFrameException(message=message, status=status, stacktrace=stacktrace)
|
||||
elif status == ErrorCodes.STALE_ELEMENT_REFERENCE:
|
||||
raise StaleElementException(message=message, status=status, stacktrace=stacktrace)
|
||||
elif status == ErrorCodes.ELEMENT_NOT_VISIBLE:
|
||||
raise ElementNotVisibleException(message=message, status=status, stacktrace=stacktrace)
|
||||
elif status == ErrorCodes.INVALID_ELEMENT_STATE:
|
||||
raise InvalidElementStateException(message=message, status=status, stacktrace=stacktrace)
|
||||
elif status == ErrorCodes.UNKNOWN_ERROR:
|
||||
raise MarionetteException(message=message, status=status, stacktrace=stacktrace)
|
||||
elif status == ErrorCodes.ELEMENT_IS_NOT_SELECTABLE:
|
||||
raise ElementNotSelectableException(message=message, status=status, stacktrace=stacktrace)
|
||||
elif status == ErrorCodes.JAVASCRIPT_ERROR:
|
||||
raise JavascriptException(message=message, status=status, stacktrace=stacktrace)
|
||||
elif status == ErrorCodes.XPATH_LOOKUP_ERROR:
|
||||
raise XPathLookupException(message=message, status=status, stacktrace=stacktrace)
|
||||
elif status == ErrorCodes.TIMEOUT:
|
||||
raise TimeoutException(message=message, status=status, stacktrace=stacktrace)
|
||||
elif status == ErrorCodes.NO_SUCH_WINDOW:
|
||||
raise NoSuchWindowException(message=message, status=status, stacktrace=stacktrace)
|
||||
elif status == ErrorCodes.INVALID_COOKIE_DOMAIN:
|
||||
raise InvalidCookieDomainException(message=message, status=status, stacktrace=stacktrace)
|
||||
elif status == ErrorCodes.UNABLE_TO_SET_COOKIE:
|
||||
raise UnableToSetCookieException(message=message, status=status, stacktrace=stacktrace)
|
||||
elif status == ErrorCodes.NO_ALERT_OPEN:
|
||||
raise NoAlertPresentException(message=message, status=status, stacktrace=stacktrace)
|
||||
elif status == ErrorCodes.SCRIPT_TIMEOUT:
|
||||
raise ScriptTimeoutException(message=message, status=status, stacktrace=stacktrace)
|
||||
elif status == ErrorCodes.INVALID_SELECTOR \
|
||||
or status == ErrorCodes.INVALID_XPATH_SELECTOR \
|
||||
or status == ErrorCodes.INVALID_XPATH_SELECTOR_RETURN_TYPER:
|
||||
raise InvalidSelectorException(message=message, status=status, stacktrace=stacktrace)
|
||||
elif status == ErrorCodes.MOVE_TARGET_OUT_OF_BOUNDS:
|
||||
raise MoveTargetOutOfBoundsException(message=message, status=status, stacktrace=stacktrace)
|
||||
elif status == ErrorCodes.FRAME_SEND_NOT_INITIALIZED_ERROR:
|
||||
raise FrameSendNotInitializedError(message=message, status=status, stacktrace=stacktrace)
|
||||
elif status == ErrorCodes.FRAME_SEND_FAILURE_ERROR:
|
||||
raise FrameSendFailureError(message=message, status=status, stacktrace=stacktrace)
|
||||
if status == errors.ErrorCodes.NO_SUCH_ELEMENT:
|
||||
raise errors.NoSuchElementException(message=message, status=status, stacktrace=stacktrace)
|
||||
elif status == errors.ErrorCodes.NO_SUCH_FRAME:
|
||||
raise errors.NoSuchFrameException(message=message, status=status, stacktrace=stacktrace)
|
||||
elif status == errors.ErrorCodes.STALE_ELEMENT_REFERENCE:
|
||||
raise errors.StaleElementException(message=message, status=status, stacktrace=stacktrace)
|
||||
elif status == errors.ErrorCodes.ELEMENT_NOT_VISIBLE:
|
||||
raise errors.ElementNotVisibleException(message=message, status=status, stacktrace=stacktrace)
|
||||
elif status == errors.ErrorCodes.INVALID_ELEMENT_STATE:
|
||||
raise errors.InvalidElementStateException(message=message, status=status, stacktrace=stacktrace)
|
||||
elif status == errors.ErrorCodes.UNKNOWN_ERROR:
|
||||
raise errors.MarionetteException(message=message, status=status, stacktrace=stacktrace)
|
||||
elif status == errors.ErrorCodes.ELEMENT_IS_NOT_SELECTABLE:
|
||||
raise errors.ElementNotSelectableException(message=message, status=status, stacktrace=stacktrace)
|
||||
elif status == errors.ErrorCodes.JAVASCRIPT_ERROR:
|
||||
raise errors.JavascriptException(message=message, status=status, stacktrace=stacktrace)
|
||||
elif status == errors.ErrorCodes.XPATH_LOOKUP_ERROR:
|
||||
raise errors.XPathLookupException(message=message, status=status, stacktrace=stacktrace)
|
||||
elif status == errors.ErrorCodes.TIMEOUT:
|
||||
raise errors.TimeoutException(message=message, status=status, stacktrace=stacktrace)
|
||||
elif status == errors.ErrorCodes.NO_SUCH_WINDOW:
|
||||
raise errors.NoSuchWindowException(message=message, status=status, stacktrace=stacktrace)
|
||||
elif status == errors.ErrorCodes.INVALID_COOKIE_DOMAIN:
|
||||
raise errors.InvalidCookieDomainException(message=message, status=status, stacktrace=stacktrace)
|
||||
elif status == errors.ErrorCodes.UNABLE_TO_SET_COOKIE:
|
||||
raise errors.UnableToSetCookieException(message=message, status=status, stacktrace=stacktrace)
|
||||
elif status == errors.ErrorCodes.NO_ALERT_OPEN:
|
||||
raise errors.NoAlertPresentException(message=message, status=status, stacktrace=stacktrace)
|
||||
elif status == errors.ErrorCodes.SCRIPT_TIMEOUT:
|
||||
raise errors.ScriptTimeoutException(message=message, status=status, stacktrace=stacktrace)
|
||||
elif status == errors.ErrorCodes.INVALID_SELECTOR \
|
||||
or status == errors.ErrorCodes.INVALID_XPATH_SELECTOR \
|
||||
or status == errors.ErrorCodes.INVALID_XPATH_SELECTOR_RETURN_TYPER:
|
||||
raise errors.InvalidSelectorException(message=message, status=status, stacktrace=stacktrace)
|
||||
elif status == errors.ErrorCodes.MOVE_TARGET_OUT_OF_BOUNDS:
|
||||
raise errors.MoveTargetOutOfBoundsException(message=message, status=status, stacktrace=stacktrace)
|
||||
elif status == errors.ErrorCodes.FRAME_SEND_NOT_INITIALIZED_ERROR:
|
||||
raise errors.FrameSendNotInitializedError(message=message, status=status, stacktrace=stacktrace)
|
||||
elif status == errors.ErrorCodes.FRAME_SEND_FAILURE_ERROR:
|
||||
raise errors.FrameSendFailureError(message=message, status=status, stacktrace=stacktrace)
|
||||
else:
|
||||
raise MarionetteException(message=message, status=status, stacktrace=stacktrace)
|
||||
raise MarionetteException(message=response, status=500)
|
||||
raise errors.MarionetteException(message=message, status=status, stacktrace=stacktrace)
|
||||
raise errors.MarionetteException(message=response, status=500)
|
||||
|
||||
def check_for_crash(self):
|
||||
returncode = None
|
||||
name = None
|
||||
crashed = False
|
||||
if self.emulator:
|
||||
if self.emulator.check_for_crash():
|
||||
if self.runner:
|
||||
if self.runner.check_for_crashes():
|
||||
returncode = self.emulator.proc.returncode
|
||||
name = 'emulator'
|
||||
crashed = True
|
||||
|
||||
if self.emulator.check_for_minidumps():
|
||||
crashed = True
|
||||
elif self.instance:
|
||||
if self.instance.check_for_crashes():
|
||||
crashed = True
|
||||
@ -1459,4 +1428,4 @@ class Marionette(object):
|
||||
"""
|
||||
self._send_message("setScreenOrientation", "ok", orientation=orientation)
|
||||
if self.emulator:
|
||||
self.emulator.screen.orientation = self.SCREEN_ORIENTATIONS[orientation.lower()]
|
||||
self.emulator.screen.orientation = orientation.lower()
|
||||
|
@ -367,11 +367,11 @@ class BaseMarionetteOptions(OptionParser):
|
||||
'specify which architecture to emulate for both cases')
|
||||
self.add_option('--emulator-binary',
|
||||
action='store',
|
||||
dest='emulatorBinary',
|
||||
dest='emulator_binary',
|
||||
help='launch a specific emulator binary rather than launching from the B2G built emulator')
|
||||
self.add_option('--emulator-img',
|
||||
action='store',
|
||||
dest='emulatorImg',
|
||||
dest='emulator_img',
|
||||
help='use a specific image file instead of a fresh one')
|
||||
self.add_option('--emulator-res',
|
||||
action='store',
|
||||
@ -385,11 +385,11 @@ class BaseMarionetteOptions(OptionParser):
|
||||
help='size of sdcard to create for the emulator')
|
||||
self.add_option('--no-window',
|
||||
action='store_true',
|
||||
dest='noWindow',
|
||||
dest='no_window',
|
||||
default=False,
|
||||
help='when Marionette launches an emulator, start it with the -no-window argument')
|
||||
self.add_option('--logcat-dir',
|
||||
dest='logcat_dir',
|
||||
dest='logdir',
|
||||
action='store',
|
||||
help='directory to store logcat dump files')
|
||||
self.add_option('--address',
|
||||
@ -441,10 +441,6 @@ class BaseMarionetteOptions(OptionParser):
|
||||
action='store',
|
||||
dest='xml_output',
|
||||
help='xml output')
|
||||
self.add_option('--gecko-path',
|
||||
dest='gecko_path',
|
||||
action='store',
|
||||
help='path to b2g gecko binaries that should be installed on the device or emulator')
|
||||
self.add_option('--testvars',
|
||||
dest='testvars',
|
||||
action='store',
|
||||
@ -525,8 +521,8 @@ class BaseMarionetteOptions(OptionParser):
|
||||
'elasticsearch-zlb.webapp.scl3.mozilla.com:9200']
|
||||
|
||||
# default to storing logcat output for emulator runs
|
||||
if options.emulator and not options.logcat_dir:
|
||||
options.logcat_dir = 'logcat'
|
||||
if options.emulator and not options.logdir:
|
||||
options.logdir = 'logcat'
|
||||
|
||||
# check for valid resolution string, strip whitespaces
|
||||
try:
|
||||
@ -562,11 +558,11 @@ class BaseMarionetteTestRunner(object):
|
||||
|
||||
textrunnerclass = MarionetteTextTestRunner
|
||||
|
||||
def __init__(self, address=None, emulator=None, emulatorBinary=None,
|
||||
emulatorImg=None, emulator_res='480x800', homedir=None,
|
||||
def __init__(self, address=None, emulator=None, emulator_binary=None,
|
||||
emulator_img=None, emulator_res='480x800', homedir=None,
|
||||
app=None, app_args=None, bin=None, profile=None, autolog=False,
|
||||
revision=None, logger=None, testgroup="marionette", noWindow=False,
|
||||
logcat_dir=None, xml_output=None, repeat=0, gecko_path=None,
|
||||
revision=None, logger=None, testgroup="marionette", no_window=False,
|
||||
logdir=None, xml_output=None, repeat=0,
|
||||
testvars=None, tree=None, type=None, device_serial=None,
|
||||
symbols_path=None, timeout=None, es_servers=None, shuffle=False,
|
||||
shuffle_seed=random.randint(0, sys.maxint), sdcard=None,
|
||||
@ -575,8 +571,8 @@ class BaseMarionetteTestRunner(object):
|
||||
**kwargs):
|
||||
self.address = address
|
||||
self.emulator = emulator
|
||||
self.emulatorBinary = emulatorBinary
|
||||
self.emulatorImg = emulatorImg
|
||||
self.emulator_binary = emulator_binary
|
||||
self.emulator_img = emulator_img
|
||||
self.emulator_res = emulator_res
|
||||
self.homedir = homedir
|
||||
self.app = app
|
||||
@ -587,13 +583,12 @@ class BaseMarionetteTestRunner(object):
|
||||
self.testgroup = testgroup
|
||||
self.revision = revision
|
||||
self.logger = logger
|
||||
self.noWindow = noWindow
|
||||
self.no_window = no_window
|
||||
self.httpd = None
|
||||
self.marionette = None
|
||||
self.logcat_dir = logcat_dir
|
||||
self.logdir = logdir
|
||||
self.xml_output = xml_output
|
||||
self.repeat = repeat
|
||||
self.gecko_path = gecko_path
|
||||
self.testvars = {}
|
||||
self.test_kwargs = kwargs
|
||||
self.tree = tree
|
||||
@ -640,9 +635,9 @@ class BaseMarionetteTestRunner(object):
|
||||
self.logger.setLevel(logging.INFO)
|
||||
self.logger.addHandler(logging.StreamHandler())
|
||||
|
||||
if self.logcat_dir:
|
||||
if not os.access(self.logcat_dir, os.F_OK):
|
||||
os.mkdir(self.logcat_dir)
|
||||
if self.logdir:
|
||||
if not os.access(self.logdir, os.F_OK):
|
||||
os.mkdir(self.logdir)
|
||||
|
||||
# for XML output
|
||||
self.testvars['xml_output'] = self.xml_output
|
||||
@ -717,8 +712,7 @@ class BaseMarionetteTestRunner(object):
|
||||
if self.emulator:
|
||||
kwargs.update({
|
||||
'homedir': self.homedir,
|
||||
'logcat_dir': self.logcat_dir,
|
||||
'gecko_path': self.gecko_path,
|
||||
'logdir': self.logdir,
|
||||
})
|
||||
|
||||
if self.address:
|
||||
@ -741,10 +735,10 @@ class BaseMarionetteTestRunner(object):
|
||||
elif self.emulator:
|
||||
kwargs.update({
|
||||
'emulator': self.emulator,
|
||||
'emulatorBinary': self.emulatorBinary,
|
||||
'emulatorImg': self.emulatorImg,
|
||||
'emulator_binary': self.emulator_binary,
|
||||
'emulator_img': self.emulator_img,
|
||||
'emulator_res': self.emulator_res,
|
||||
'noWindow': self.noWindow,
|
||||
'no_window': self.no_window,
|
||||
'sdcard': self.sdcard,
|
||||
})
|
||||
return kwargs
|
||||
@ -757,7 +751,7 @@ class BaseMarionetteTestRunner(object):
|
||||
|
||||
logfile = None
|
||||
if self.emulator:
|
||||
filename = os.path.join(os.path.abspath(self.logcat_dir),
|
||||
filename = os.path.join(os.path.abspath(self.logdir),
|
||||
"emulator-%d.log" % self.marionette.emulator.port)
|
||||
if os.access(filename, os.F_OK):
|
||||
logfile = filename
|
||||
|
@ -9,14 +9,10 @@ import re
|
||||
|
||||
def get_dm(marionette=None,**kwargs):
|
||||
dm_type = os.environ.get('DM_TRANS', 'adb')
|
||||
if marionette and marionette.emulator:
|
||||
adb_path = marionette.emulator.b2g.adb_path
|
||||
return mozdevice.DeviceManagerADB(adbPath=adb_path,
|
||||
deviceSerial='emulator-%d' % marionette.emulator.port,
|
||||
**kwargs)
|
||||
if marionette and hasattr(marionette.runner, 'device'):
|
||||
return marionette.runner.app_ctx.dm
|
||||
elif marionette and marionette.device_serial and dm_type == 'adb':
|
||||
return mozdevice.DeviceManagerADB(deviceSerial=marionette.device_serial,
|
||||
**kwargs)
|
||||
return mozdevice.DeviceManagerADB(deviceSerial=marionette.device_serial, **kwargs)
|
||||
else:
|
||||
if dm_type == 'adb':
|
||||
return mozdevice.DeviceManagerADB(**kwargs)
|
||||
|
@ -3,7 +3,7 @@
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
from marionette_test import MarionetteTestCase
|
||||
from marionette import InvalidElementStateException
|
||||
from errors import InvalidElementStateException
|
||||
|
||||
class TestClear(MarionetteTestCase):
|
||||
def testWriteableTextInputShouldClear(self):
|
||||
|
@ -3,7 +3,7 @@
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
from marionette_test import MarionetteTestCase
|
||||
from marionette import MarionetteException
|
||||
from errors import MarionetteException
|
||||
|
||||
class testElementTouch(MarionetteTestCase):
|
||||
def test_touch(self):
|
||||
|
@ -3,7 +3,7 @@
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
from marionette_test import MarionetteTestCase
|
||||
from marionette import JavascriptException, MarionetteException
|
||||
from errors import JavascriptException, MarionetteException
|
||||
|
||||
|
||||
class TestEmulatorContent(MarionetteTestCase):
|
||||
@ -19,7 +19,7 @@ class TestEmulatorContent(MarionetteTestCase):
|
||||
|
||||
def test_emulator_shell(self):
|
||||
self.marionette.set_script_timeout(10000)
|
||||
expected = ["Hello World!", ""]
|
||||
expected = ["Hello World!"]
|
||||
result = self.marionette.execute_async_script("""
|
||||
runEmulatorShell(["echo", "Hello World!"], marionetteScriptFinished)
|
||||
""");
|
||||
|
@ -3,7 +3,7 @@
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
from marionette_test import MarionetteTestCase
|
||||
from marionette import JavascriptException, MarionetteException, ScriptTimeoutException
|
||||
from errors import JavascriptException, MarionetteException, ScriptTimeoutException
|
||||
import time
|
||||
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
from marionette_test import MarionetteTestCase, skip_if_b2g
|
||||
from marionette import JavascriptException, MarionetteException, ScriptTimeoutException
|
||||
from errors import JavascriptException, MarionetteException, ScriptTimeoutException
|
||||
|
||||
class TestExecuteIsolationContent(MarionetteTestCase):
|
||||
def setUp(self):
|
||||
|
@ -5,7 +5,7 @@
|
||||
import urllib
|
||||
|
||||
from by import By
|
||||
from marionette import JavascriptException, MarionetteException
|
||||
from errors import JavascriptException, MarionetteException
|
||||
from marionette_test import MarionetteTestCase
|
||||
|
||||
def inline(doc):
|
||||
|
@ -5,7 +5,7 @@
|
||||
from marionette_test import MarionetteTestCase
|
||||
from marionette import HTMLElement
|
||||
from by import By
|
||||
from marionette import NoSuchElementException
|
||||
from errors import NoSuchElementException
|
||||
|
||||
|
||||
class TestElements(MarionetteTestCase):
|
||||
|
@ -5,7 +5,7 @@
|
||||
from marionette_test import MarionetteTestCase
|
||||
from marionette import HTMLElement
|
||||
from by import By
|
||||
from marionette import NoSuchElementException
|
||||
from errors import NoSuchElementException
|
||||
|
||||
|
||||
class TestElementsChrome(MarionetteTestCase):
|
||||
|
@ -3,7 +3,7 @@
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
from marionette_test import MarionetteTestCase
|
||||
from marionette import NoSuchElementException
|
||||
from errors import NoSuchElementException
|
||||
|
||||
class TestImplicitWaits(MarionetteTestCase):
|
||||
def testShouldImplicitlyWaitForASingleElement(self):
|
||||
|
@ -3,8 +3,7 @@
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
from marionette_test import MarionetteTestCase
|
||||
from marionette import MarionetteException
|
||||
from marionette import TimeoutException
|
||||
from errors import MarionetteException, TimeoutException
|
||||
|
||||
class TestNavigate(MarionetteTestCase):
|
||||
def test_navigate(self):
|
||||
|
@ -4,9 +4,9 @@
|
||||
# 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/.
|
||||
|
||||
from emulator_screen import EmulatorScreen
|
||||
from marionette import MarionetteException
|
||||
from errors import MarionetteException
|
||||
from marionette_test import MarionetteTestCase
|
||||
from mozrunner.devices.emulator_screen import EmulatorScreen
|
||||
|
||||
default_orientation = "portrait-primary"
|
||||
unknown_orientation = "Unknown screen orientation: %s"
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user