merge mozilla-central to mozilla-inbound. r=merge a=merge

This commit is contained in:
Sebastian Hengst 2017-08-01 11:26:31 +02:00
Родитель 959a0efb8a ddd4030358
Коммит 9975089d4d
124 изменённых файлов: 3011 добавлений и 531 удалений

Просмотреть файл

@ -730,11 +730,7 @@ pref("browser.preferences.instantApply", true);
pref("browser.preferences.search", true);
// Use the new in-content about:preferences in Nightly only for now
#if defined(NIGHTLY_BUILD)
pref("browser.preferences.useOldOrganization", false);
#else
pref("browser.preferences.useOldOrganization", true);
#endif
// Once the Storage Management is completed.
// (The Storage Management-related prefs are browser.storageManager.* )

Просмотреть файл

@ -890,7 +890,7 @@ var gPopupBlockerObserver = {
allowVisible: true,
prefilledHost: prefillValue,
permissionType: "popup",
windowTitle: bundlePreferences.getString("popuppermissionstitle"),
windowTitle: bundlePreferences.getString("popuppermissionstitle2"),
introText: bundlePreferences.getString("popuppermissionstext") };
var existingWindow = Services.wm.getMostRecentWindow("Browser:Permissions");
if (existingWindow) {

Просмотреть файл

@ -250,21 +250,21 @@ var gPrivacyPane = {
let pkiBundle = document.getElementById("pkiBundle");
appendSearchKeywords("passwordExceptions", [
bundlePrefs.getString("savedLoginsExceptions_title"),
bundlePrefs.getString("savedLoginsExceptions_desc"),
bundlePrefs.getString("savedLoginsExceptions_desc2"),
]);
appendSearchKeywords("showPasswords", [
signonBundle.getString("loginsDescriptionAll"),
]);
appendSearchKeywords("trackingProtectionExceptions", [
bundlePrefs.getString("trackingprotectionpermissionstitle"),
bundlePrefs.getString("trackingprotectionpermissionstext"),
bundlePrefs.getString("trackingprotectionpermissionstext2"),
]);
appendSearchKeywords("changeBlockList", [
bundlePrefs.getString("blockliststitle"),
bundlePrefs.getString("blockliststext"),
]);
appendSearchKeywords("popupPolicyButton", [
bundlePrefs.getString("popuppermissionstitle"),
bundlePrefs.getString("popuppermissionstitle2"),
bundlePrefs.getString("popuppermissionstext"),
]);
appendSearchKeywords("notificationsPolicyButton", [
@ -272,14 +272,14 @@ var gPrivacyPane = {
bundlePrefs.getString("notificationspermissionstext4"),
]);
appendSearchKeywords("addonExceptions", [
bundlePrefs.getString("addons_permissions_title"),
bundlePrefs.getString("addons_permissions_title2"),
bundlePrefs.getString("addonspermissionstext"),
]);
appendSearchKeywords("viewSecurityDevicesButton", [
pkiBundle.getString("enable_fips"),
]);
appendSearchKeywords("siteDataSettings", [
bundlePrefs.getString("siteDataSettings.description"),
bundlePrefs.getString("siteDataSettings2.description"),
bundlePrefs.getString("removeAllCookies.label"),
bundlePrefs.getString("removeSelectedCookies.label"),
]);
@ -574,7 +574,7 @@ var gPrivacyPane = {
permissionType: "trackingprotection",
hideStatusColumn: true,
windowTitle: bundlePreferences.getString("trackingprotectionpermissionstitle"),
introText: bundlePreferences.getString("trackingprotectionpermissionstext"),
introText: bundlePreferences.getString("trackingprotectionpermissionstext2"),
};
gSubDialog.open("chrome://browser/content/preferences/permissions.xul",
null, params);
@ -830,7 +830,7 @@ var gPrivacyPane = {
var bundlePreferences = document.getElementById("bundlePreferences");
var params = { blockVisible: false, sessionVisible: false, allowVisible: true,
prefilledHost: "", permissionType: "popup" }
params.windowTitle = bundlePreferences.getString("popuppermissionstitle");
params.windowTitle = bundlePreferences.getString("popuppermissionstitle2");
params.introText = bundlePreferences.getString("popuppermissionstext");
gSubDialog.open("chrome://browser/content/preferences/permissions.xul",
@ -875,7 +875,7 @@ var gPrivacyPane = {
prefilledHost: "",
permissionType: "login-saving",
windowTitle: bundlePrefs.getString("savedLoginsExceptions_title"),
introText: bundlePrefs.getString("savedLoginsExceptions_desc")
introText: bundlePrefs.getString("savedLoginsExceptions_desc2")
};
gSubDialog.open("chrome://browser/content/preferences/permissions.xul",
@ -1073,7 +1073,7 @@ var gPrivacyPane = {
var params = this._addonParams;
if (!params.windowTitle || !params.introText) {
params.windowTitle = bundlePrefs.getString("addons_permissions_title");
params.windowTitle = bundlePrefs.getString("addons_permissions_title2");
params.introText = bundlePrefs.getString("addonspermissionstext");
}

Просмотреть файл

@ -185,7 +185,7 @@
<vbox id="passwordSettings">
<hbox id="savePasswordsBox">
<checkbox id="savePasswords"
label="&rememberLogins1.label;" accesskey="&rememberLogins1.accesskey;"
label="&rememberLogins2.label;" accesskey="&rememberLogins2.accesskey;"
preference="signon.rememberSignons"
onsyncfrompreference="return gPrivacyPane.readSavePasswords();"
flex="1" />
@ -250,7 +250,7 @@
<menuitem label="&historyHeader.custom.label;" value="custom" searchkeywords="&privateBrowsingPermanent2.label;
&rememberHistory2.label;
&rememberSearchForm.label;
&acceptCookies.label;
&acceptCookies2.label;
&cookieExceptions.label;
&acceptThirdParty.pre.label;
&acceptThirdParty.always.label;
@ -309,9 +309,9 @@
accesskey="&rememberSearchForm.accesskey;"
preference="browser.formfill.enable"/>
<hbox id="cookiesBox">
<checkbox id="acceptCookies" label="&acceptCookies.label;"
<checkbox id="acceptCookies" label="&acceptCookies2.label;"
preference="network.cookie.cookieBehavior"
accesskey="&acceptCookies.accesskey;"
accesskey="&acceptCookies2.accesskey;"
onsyncfrompreference="return gPrivacyPane.readAcceptCookies();"
onsynctopreference="return gPrivacyPane.writeAcceptCookies();"
flex="1" />
@ -497,8 +497,8 @@
label="&trackingProtectionExceptions.label;"
accesskey="&trackingProtectionExceptions.accesskey;"
preference="pref.privacy.disable_button.tracking_protection_exceptions"
searchkeywords="&removepermission.label;
&removeallpermissions.label;
searchkeywords="&removepermission2.label;
&removeallpermissions2.label;
&button.cancel.label;
&button.ok.label;"/>
</hbox>
@ -542,7 +542,7 @@
<rows>
<row id="notificationsPolicyRow" align="center">
<description flex="1">
<label id="notificationsPolicy">&notificationsPolicyDesc3.label;</label>
<label id="notificationsPolicy">&notificationsPolicyDesc4.label;</label>
<label id="notificationsPolicyLearnMore"
class="learnMore text-link">&notificationsPolicyLearnMore.label;</label>
</description>
@ -551,8 +551,8 @@
class="accessory-button"
label="&notificationsPolicyButton.label;"
accesskey="&notificationsPolicyButton.accesskey;"
searchkeywords="&removepermission.label;
&removeallpermissions.label;
searchkeywords="&removepermission2.label;
&removeallpermissions2.label;
&button.cancel.label;
&button.ok.label;"/>
</hbox>
@ -584,8 +584,8 @@
<hbox id="addonInstallBox">
<checkbox id="warnAddonInstall"
label="&warnOnAddonInstall.label;"
accesskey="&warnOnAddonInstall.accesskey;"
label="&warnOnAddonInstall2.label;"
accesskey="&warnOnAddonInstall2.accesskey;"
preference="xpinstall.whitelist.required"
onsyncfrompreference="return gPrivacyPane.readWarnAddonInstall();"
flex="1" />
@ -597,8 +597,8 @@
accesskey="&addonExceptions.accesskey;"
searchkeywords="&address.label;
&allow.label;
&removepermission.label;
&removeallpermissions.label;
&removepermission2.label;
&removeallpermissions2.label;
&button.cancel.label;
&button.ok.label;"/>
</hbox>

Просмотреть файл

@ -144,7 +144,7 @@ var gContentPane = {
var bundlePreferences = document.getElementById("bundlePreferences");
var params = { blockVisible: false, sessionVisible: false, allowVisible: true,
prefilledHost: "", permissionType: "popup" }
params.windowTitle = bundlePreferences.getString("popuppermissionstitle");
params.windowTitle = bundlePreferences.getString("popuppermissionstitle2");
params.introText = bundlePreferences.getString("popuppermissionstext");
gSubDialog.open("chrome://browser/content/preferences/permissions.xul",

Просмотреть файл

@ -69,7 +69,7 @@
<rows>
<row id="notificationsPolicyRow" align="center">
<hbox align="start">
<label id="notificationsPolicy">&notificationsPolicyDesc3.label;</label>
<label id="notificationsPolicy">&notificationsPolicyDesc4.label;</label>
<label id="notificationsPolicyLearnMore"
class="learnMore text-link"
value="&notificationsPolicyLearnMore.label;"/>

Просмотреть файл

@ -469,7 +469,7 @@ var gPrivacyPane = {
permissionType: "trackingprotection",
hideStatusColumn: true,
windowTitle: bundlePreferences.getString("trackingprotectionpermissionstitle"),
introText: bundlePreferences.getString("trackingprotectionpermissionstext"),
introText: bundlePreferences.getString("trackingprotectionpermissionstext2"),
};
gSubDialog.open("chrome://browser/content/preferences/permissions.xul",
null, params);

Просмотреть файл

@ -206,9 +206,9 @@
preference="browser.formfill.enable"/>
</vbox>
<hbox id="cookiesBox">
<checkbox id="acceptCookies" label="&acceptCookies.label;"
<checkbox id="acceptCookies" label="&acceptCookies2.label;"
preference="network.cookie.cookieBehavior"
accesskey="&acceptCookies.accesskey;"
accesskey="&acceptCookies2.accesskey;"
onsyncfrompreference="return gPrivacyPane.readAcceptCookies();"
onsynctopreference="return gPrivacyPane.writeAcceptCookies();"/>
<spacer flex="1" />

Просмотреть файл

@ -70,7 +70,7 @@ var gSecurityPane = {
var params = this._addonParams;
if (!params.windowTitle || !params.introText) {
params.windowTitle = bundlePrefs.getString("addons_permissions_title");
params.windowTitle = bundlePrefs.getString("addons_permissions_title2");
params.introText = bundlePrefs.getString("addonspermissionstext");
}
@ -132,7 +132,7 @@ var gSecurityPane = {
prefilledHost: "",
permissionType: "login-saving",
windowTitle: bundlePrefs.getString("savedLoginsExceptions_title"),
introText: bundlePrefs.getString("savedLoginsExceptions_desc")
introText: bundlePrefs.getString("savedLoginsExceptions_desc2")
};
gSubDialog.open("chrome://browser/content/preferences/permissions.xul",

Просмотреть файл

@ -62,8 +62,8 @@
<hbox id="addonInstallBox">
<checkbox id="warnAddonInstall"
label="&warnOnAddonInstall.label;"
accesskey="&warnOnAddonInstall.accesskey;"
label="&warnOnAddonInstall2.label;"
accesskey="&warnOnAddonInstall2.accesskey;"
preference="xpinstall.whitelist.required"
onsyncfrompreference="return gSecurityPane.readWarnAddonInstall();"/>
<spacer flex="1"/>
@ -100,7 +100,7 @@
<rows id="passwordRows">
<row id="savePasswordsBox">
<checkbox id="savePasswords"
label="&rememberLogins.label;" accesskey="&rememberLogins.accesskey;"
label="&rememberLogins2.label;" accesskey="&rememberLogins2.accesskey;"
preference="signon.rememberSignons"
onsyncfrompreference="return gSecurityPane.readSavePasswords();"/>
<button id="passwordExceptions"

Просмотреть файл

@ -52,7 +52,7 @@
onkeypress="gPermissionManager.onPermissionKeyPress(event)"
onselect="gPermissionManager.onPermissionSelected();">
<treecols>
<treecol id="siteCol" label="&treehead.sitename.label;" flex="3"
<treecol id="siteCol" label="&treehead.sitename2.label;" flex="3"
data-field-name="origin" persist="width"/>
<splitter class="tree-splitter"/>
<treecol id="statusCol" label="&treehead.status.label;" flex="1"
@ -64,12 +64,12 @@
<vbox>
<hbox class="actionButtons" align="left" flex="1">
<button id="removePermission" disabled="true"
accesskey="&removepermission.accesskey;"
icon="remove" label="&removepermission.label;"
accesskey="&removepermission2.accesskey;"
icon="remove" label="&removepermission2.label;"
oncommand="gPermissionManager.onPermissionDeleted();"/>
<button id="removeAllPermissions"
icon="clear" label="&removeallpermissions.label;"
accesskey="&removeallpermissions.accesskey;"
icon="clear" label="&removeallpermissions2.label;"
accesskey="&removeallpermissions2.accesskey;"
oncommand="gPermissionManager.onAllPermissionsDeleted();"/>
</hbox>
<spacer flex="1"/>

Просмотреть файл

@ -47,7 +47,7 @@ let gSiteDataSettings = {
let brandShortName = document.getElementById("bundle_brand").getString("brandShortName");
let settingsDescription = document.getElementById("settingsDescription");
settingsDescription.textContent = this._prefStrBundle.getFormattedString("siteDataSettings.description", [brandShortName]);
settingsDescription.textContent = this._prefStrBundle.getFormattedString("siteDataSettings2.description", [brandShortName]);
setEventListener("hostCol", "click", this.onClickTreeCol);
setEventListener("usageCol", "click", this.onClickTreeCol);

Просмотреть файл

@ -64,7 +64,7 @@
onkeypress="gTranslationExceptions.onSiteKeyPress(event)"
onselect="gTranslationExceptions.onSiteSelected();">
<treecols>
<treecol id="siteCol" label="&treehead.siteName.label;" flex="1"/>
<treecol id="siteCol" label="&treehead.siteName2.label;" flex="1"/>
</treecols>
<treechildren/>
</tree>

15
browser/extensions/e10srollout/bootstrap.js поставляемый
Просмотреть файл

@ -141,8 +141,8 @@ function defineCohort() {
// the proper prefs must already be set.
setCohort("optedOut");
} else if (userOptedIn.e10s) {
setCohort("optedIn");
eligibleForMulti = true;
setCohort("optedIn");
} else if (temporaryDisqualification != "") {
// Users who are disqualified by the backend (from multiprocessBlockPolicy)
// can be put into either the test or control groups, because e10s will
@ -152,25 +152,25 @@ function defineCohort() {
// For these volatile disqualification reasons, however, we must not try
// to activate e10s because the backend doesn't know about it. E10S_STATUS
// here will be accumulated as "2 - Disabled", which is fine too.
setCohort(`temp-disqualified-${temporaryDisqualification}`);
Services.prefs.clearUserPref(PREF_TOGGLE_E10S);
Services.prefs.clearUserPref(PREF_E10S_PROCESSCOUNT + ".web");
setCohort(`temp-disqualified-${temporaryDisqualification}`);
} else if (!disqualified && testThreshold < 1.0 &&
temporaryQualification != "") {
// Users who are qualified for e10s and on channels where some population
// would not receive e10s can be pushed into e10s anyway via a temporary
// qualification which overrides the user sample value when non-empty.
Services.prefs.setBoolPref.set(PREF_TOGGLE_E10S, true);
eligibleForMulti = true;
setCohort(`temp-qualified-${temporaryQualification}`);
Services.prefs.setBoolPref(PREF_TOGGLE_E10S, true);
eligibleForMulti = true;
} else if (testGroup) {
setCohort(`${cohortPrefix}test`);
Services.prefs.setBoolPref(PREF_TOGGLE_E10S, true);
eligibleForMulti = true;
setCohort(`${cohortPrefix}test`);
} else {
setCohort(`${cohortPrefix}control`);
Services.prefs.clearUserPref(PREF_TOGGLE_E10S);
Services.prefs.clearUserPref(PREF_E10S_PROCESSCOUNT + ".web");
setCohort(`${cohortPrefix}control`);
}
// Now determine if this user should be in the e10s-multi experiment.
@ -207,10 +207,9 @@ function defineCohort() {
let multiUserSample = getUserSample(true);
for (let sampleName of Object.getOwnPropertyNames(buckets)) {
if (multiUserSample < buckets[sampleName]) {
setCohort(`${cohortPrefix}multiBucket${sampleName}`);
// NB: Coerce sampleName to an integer because this is an integer pref.
Services.prefs.setIntPref(PREF_E10S_PROCESSCOUNT + ".web", +sampleName);
setCohort(`${cohortPrefix}multiBucket${sampleName}`);
break;
}
}

Просмотреть файл

@ -10,7 +10,7 @@
<Description about="urn:mozilla:install-manifest">
<em:id>e10srollout@mozilla.org</em:id>
<em:version>2.0</em:version>
<em:version>2.1</em:version>
<em:type>2</em:type>
<em:bootstrap>true</em:bootstrap>
<em:multiprocessCompatible>true</em:multiprocessCompatible>

Просмотреть файл

@ -155,6 +155,7 @@ FormAutofillHandler.prototype = {
_cacheValue: {
allFieldNames: null,
oneLineStreetAddress: null,
matchingSelectOption: null,
},
get allFieldNames() {
@ -198,9 +199,48 @@ FormAutofillHandler.prototype = {
}
},
_matchSelectOptions(profile) {
if (!this._cacheValue.matchingSelectOption) {
this._cacheValue.matchingSelectOption = new WeakMap();
}
for (let fieldName in profile) {
let fieldDetail = this.getFieldDetailByName(fieldName);
if (!fieldDetail) {
continue;
}
let element = fieldDetail.elementWeakRef.get();
if (!(element instanceof Ci.nsIDOMHTMLSelectElement)) {
continue;
}
let cache = this._cacheValue.matchingSelectOption.get(element) || {};
let value = profile[fieldName];
if (cache[value] && cache[value].get()) {
continue;
}
let option = FormAutofillUtils.findSelectOption(element, profile, fieldName);
if (option) {
cache[value] = Cu.getWeakReference(option);
this._cacheValue.matchingSelectOption.set(element, cache);
} else {
if (cache[value]) {
delete cache[value];
this._cacheValue.matchingSelectOption.set(element, cache);
}
// Delete the field so the phishing hint won't treat it as a "also fill"
// field.
delete profile[fieldName];
}
}
},
getAdaptedProfiles(originalProfiles) {
for (let profile of originalProfiles) {
this._addressTransformer(profile);
this._matchSelectOptions(profile);
}
return originalProfiles;
},
@ -237,7 +277,8 @@ FormAutofillHandler.prototype = {
}
this.changeFieldState(fieldDetail, "AUTO_FILLED");
} else if (element instanceof Ci.nsIDOMHTMLSelectElement) {
let option = FormAutofillUtils.findSelectOption(element, profile, fieldDetail.fieldName);
let cache = this._cacheValue.matchingSelectOption.get(element) || {};
let option = cache[value] && cache[value].get();
if (!option) {
continue;
}
@ -326,17 +367,21 @@ FormAutofillHandler.prototype = {
if (element instanceof Ci.nsIDOMHTMLSelectElement) {
// Unlike text input, select element is always previewed even if
// the option is already selected.
let option = FormAutofillUtils.findSelectOption(element, profile, fieldDetail.fieldName);
element.previewValue = option ? option.text : "";
this.changeFieldState(fieldDetail, option ? "PREVIEW" : "NORMAL");
} else {
// Skip the field if it already has text entered
if (element.value) {
continue;
if (value) {
let cache = this._cacheValue.matchingSelectOption.get(element) || {};
let option = cache[value] && cache[value].get();
if (option) {
value = option.text || "";
} else {
value = "";
}
}
element.previewValue = value;
this.changeFieldState(fieldDetail, value ? "PREVIEW" : "NORMAL");
} else if (element.value) {
// Skip the field if it already has text entered.
continue;
}
element.previewValue = value;
this.changeFieldState(fieldDetail, value ? "PREVIEW" : "NORMAL");
}
},

Просмотреть файл

@ -323,7 +323,7 @@ function do_test(testcases, testFn) {
let handler = new FormAutofillHandler(formLike);
let promises = [];
handler.address.fieldDetails = testcase.addressFieldDetails;
handler.fieldDetails = handler.address.fieldDetails = testcase.addressFieldDetails;
handler.address.fieldDetails.forEach((field, index) => {
let element = doc.querySelectorAll("input, select")[index];
field.elementWeakRef = Cu.getWeakReference(element);
@ -335,7 +335,8 @@ function do_test(testcases, testFn) {
promises.push(...testFn(testcase, element));
});
handler.autofillFormFields(testcase.profileData);
let [adaptedProfile] = handler.getAdaptedProfiles([testcase.profileData]);
handler.autofillFormFields(adaptedProfile);
Assert.equal(handler.address.filledRecordGUID, testcase.profileData.guid,
"Check if filledRecordGUID is set correctly");
await Promise.all(promises);

Просмотреть файл

@ -12,6 +12,8 @@ const DEFAULT_PROFILE = {
"address-line1": "2 Harrison St",
"address-line2": "line2",
"address-line3": "line3",
"address-level1": "CA",
"country": "US",
};
const TESTCASES = [
@ -28,6 +30,8 @@ const TESTCASES = [
"address-line1": "2 Harrison St",
"address-line2": "line2",
"address-line3": "line3",
"address-level1": "CA",
"country": "US",
}],
},
{
@ -46,6 +50,8 @@ const TESTCASES = [
"address-line1": "2 Harrison St",
"address-line2": "line2",
"address-line3": "line3",
"address-level1": "CA",
"country": "US",
}],
},
{
@ -62,6 +68,8 @@ const TESTCASES = [
"address-line1": "2 Harrison St line2 line3",
"address-line2": "line2",
"address-line3": "line3",
"address-level1": "CA",
"country": "US",
}],
},
{
@ -79,6 +87,8 @@ const TESTCASES = [
"address-line1": "2 Harrison St",
"address-line2": "line2 line3",
"address-line3": "line3",
"address-level1": "CA",
"country": "US",
}],
},
{
@ -96,6 +106,119 @@ const TESTCASES = [
"address-line1": "2 Harrison St",
"address-line2": "line2 line3",
"address-line3": "line3",
"address-level1": "CA",
"country": "US",
}],
},
{
description: "Form with exact matching options in select",
document: `<form>
<select autocomplete="address-level1">
<option id="option-address-level1-XX" value="XX">Dummy</option>
<option id="option-address-level1-CA" value="CA">California</option>
</select>
</form>`,
profileData: [Object.assign({}, DEFAULT_PROFILE)],
expectedResult: [{
"guid": "123",
"street-address": "2 Harrison St\nline2\nline3",
"-moz-street-address-one-line": "2 Harrison St line2 line3",
"address-line1": "2 Harrison St",
"address-line2": "line2",
"address-line3": "line3",
"address-level1": "CA",
"country": "US",
}],
expectedOptionElements: [{
"address-level1": "option-address-level1-CA",
}],
},
{
description: "Form with inexact matching options in select",
document: `<form>
<select autocomplete="address-level1">
<option id="option-address-level1-XX" value="XX">Dummy</option>
<option id="option-address-level1-OO" value="OO">California</option>
</select>
</form>`,
profileData: [Object.assign({}, DEFAULT_PROFILE)],
expectedResult: [{
"guid": "123",
"street-address": "2 Harrison St\nline2\nline3",
"-moz-street-address-one-line": "2 Harrison St line2 line3",
"address-line1": "2 Harrison St",
"address-line2": "line2",
"address-line3": "line3",
"address-level1": "CA",
"country": "US",
}],
expectedOptionElements: [{
"address-level1": "option-address-level1-OO",
}],
},
{
description: "Form with value-omitted options in select",
document: `<form>
<select autocomplete="address-level1">
<option id="option-address-level1-1" value="">Dummy</option>
<option id="option-address-level1-2" value="">California</option>
</select>
</form>`,
profileData: [Object.assign({}, DEFAULT_PROFILE)],
expectedResult: [{
"guid": "123",
"street-address": "2 Harrison St\nline2\nline3",
"-moz-street-address-one-line": "2 Harrison St line2 line3",
"address-line1": "2 Harrison St",
"address-line2": "line2",
"address-line3": "line3",
"address-level1": "CA",
"country": "US",
}],
expectedOptionElements: [{
"address-level1": "option-address-level1-2",
}],
},
{
description: "Form with options with the same value in select",
document: `<form>
<select autocomplete="address-level1">
<option id="option-address-level1-same1" value="same">Dummy</option>
<option id="option-address-level1-same2" value="same">California</option>
</select>
</form>`,
profileData: [Object.assign({}, DEFAULT_PROFILE)],
expectedResult: [{
"guid": "123",
"street-address": "2 Harrison St\nline2\nline3",
"-moz-street-address-one-line": "2 Harrison St line2 line3",
"address-line1": "2 Harrison St",
"address-line2": "line2",
"address-line3": "line3",
"address-level1": "CA",
"country": "US",
}],
expectedOptionElements: [{
"address-level1": "option-address-level1-same2",
}],
},
{
description: "Form without matching options in select",
document: `<form>
<select autocomplete="address-level1">
<option id="option-address-level1-dummy1" value="">Dummy</option>
<option id="option-address-level1-dummy2" value="">Dummy 2</option>
</select>
</form>`,
profileData: [Object.assign({}, DEFAULT_PROFILE)],
expectedResult: [{
"guid": "123",
"street-address": "2 Harrison St\nline2\nline3",
"-moz-street-address-one-line": "2 Harrison St line2 line3",
"address-line1": "2 Harrison St",
"address-line2": "line2",
"address-line3": "line3",
"country": "US",
}],
},
];
@ -113,6 +236,22 @@ for (let testcase of TESTCASES) {
handler.collectFormFields();
let adaptedAddresses = handler.getAdaptedProfiles(testcase.profileData);
Assert.deepEqual(adaptedAddresses, testcase.expectedResult);
if (testcase.expectedOptionElements) {
testcase.expectedOptionElements.forEach((expectedOptionElement, i) => {
for (let field in expectedOptionElement) {
let select = form.querySelector(`[autocomplete=${field}]`);
let expectedOption = doc.getElementById(expectedOptionElement[field]);
Assert.notEqual(expectedOption, null);
let value = testcase.profileData[i][field];
let cache = handler._cacheValue.matchingSelectOption.get(select);
let targetOption = cache[value] && cache[value].get();
Assert.notEqual(targetOption, null);
Assert.equal(targetOption, expectedOption);
}
});
}
});
}

Просмотреть файл

@ -5,6 +5,7 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
DIRS += [
'activity-stream',
'aushelper',
'clicktoplay-rollout',
'e10srollout',
@ -36,9 +37,3 @@ if CONFIG['MOZ_MORTAR']:
DIRS += [
'mortar',
]
# Nightly-only system add-ons
if CONFIG['NIGHTLY_BUILD']:
DIRS += [
'activity-stream',
]

Просмотреть файл

@ -9,7 +9,7 @@
<!ENTITY notificationsPolicy.label "Notifications">
<!ENTITY notificationsPolicyLearnMore.label "Learn more">
<!ENTITY notificationsPolicyDesc3.label "Choose which sites are allowed to send you notifications">
<!ENTITY notificationsPolicyDesc4.label "Choose which websites are allowed to send you notifications">
<!ENTITY notificationsPolicyButton.accesskey "h">
<!ENTITY notificationsPolicyButton.label "Choose…">
<!ENTITY notificationsDoNotDisturb.label "Do not disturb me">

Просмотреть файл

@ -19,20 +19,20 @@ acceptVeryLargeMinimumFont=Keep my changes anyway
#### Permissions Manager
trackingprotectionpermissionstext=You have disabled Tracking Protection on these sites.
trackingprotectionpermissionstext2=You have disabled Tracking Protection on these websites.
trackingprotectionpermissionstitle=Exceptions - Tracking Protection
cookiepermissionstext=You can specify which websites are always or never allowed to use cookies. Type the exact address of the site you want to manage and then click Block, Allow for Session, or Allow.
cookiepermissionstitle=Exceptions - Cookies
addonspermissionstext=You can specify which websites are allowed to install add-ons. Type the exact address of the site you want to allow and then click Allow.
addons_permissions_title=Allowed Sites - Add-ons Installation
addons_permissions_title2=Allowed Websites - Add-ons Installation
popuppermissionstext=You can specify which websites are allowed to open pop-up windows. Type the exact address of the site you want to allow and then click Allow.
popuppermissionstitle=Allowed Sites - Pop-ups
popuppermissionstitle2=Allowed Websites - Pop-ups
notificationspermissionstext4=Control which websites are always or never allowed to send you notifications. If you remove a site, it will need to request permission again.
notificationspermissionstitle=Notification Permissions
invalidURI=Please enter a valid hostname
invalidURITitle=Invalid Hostname Entered
savedLoginsExceptions_title=Exceptions - Saved Logins
savedLoginsExceptions_desc=Logins for the following sites will not be saved:
savedLoginsExceptions_desc2=Logins for the following websites will not be saved:
#### Block List Manager
@ -51,7 +51,7 @@ mozNameTemplate=%1$S %2$S
mozstdName=Disconnect.me basic protection (Recommended).
mozstdDesc=Allows some trackers so websites function properly.
mozfullName=Disconnect.me strict protection.
mozfullDesc=Blocks known trackers. Some sites may not function properly.
mozfullDesc2=Blocks known trackers. Some websites may not function properly.
# LOCALIZATION NOTE (blocklistChangeRequiresRestart): %S = brandShortName
blocklistChangeRequiresRestart=%S must restart to change block lists.
@ -191,8 +191,8 @@ clearSiteDataNow=Clear Now
persistent=Persistent
siteUsage=%1$S %2$S
acceptRemove=Remove
# LOCALIZATION NOTE (siteDataSettings.description): %S = brandShortName
siteDataSettings.description=The following websites store site data on your computer. %S keeps data from sites with persistent storage until you delete it, and deletes data from sites with non-persistent storage as space is needed.
# LOCALIZATION NOTE (siteDataSettings2.description): %S = brandShortName
siteDataSettings2.description=The following websites store site data on your computer. %S keeps data from websites with persistent storage until you delete it, and deletes data from websites with non-persistent storage as space is needed.
# LOCALIZATION NOTE (removeAllSiteData, removeAllSiteDataShown):
# removeAllSiteData and removeAllSiteDataShown are both used on the same one button,
# never displayed together and can share the same accesskey.

Просмотреть файл

@ -43,8 +43,8 @@
<!ENTITY suggestionSettings.label "Change preferences for search engine suggestions…">
<!ENTITY suggestionSettings.accesskey "g">
<!ENTITY acceptCookies.label "Accept cookies from sites">
<!ENTITY acceptCookies.accesskey "A">
<!ENTITY acceptCookies2.label "Accept cookies from websites">
<!ENTITY acceptCookies2.accesskey "A">
<!ENTITY acceptThirdParty.pre.label "Accept third-party cookies:">
<!ENTITY acceptThirdParty.pre.accesskey "y">

Просмотреть файл

@ -4,8 +4,8 @@
<!ENTITY general.label "General">
<!ENTITY warnOnAddonInstall.label "Warn you when sites try to install add-ons">
<!ENTITY warnOnAddonInstall.accesskey "W">
<!ENTITY warnOnAddonInstall2.label "Warn you when websites try to install add-ons">
<!ENTITY warnOnAddonInstall2.accesskey "W">
<!-- LOCALIZATION NOTE (enableSafeBrowsing.label, blockDownloads.label, blockUncommonUnwanted.label):
It is important that wording follows the guidelines outlined on this page:
@ -26,8 +26,8 @@
<!ENTITY logins.label "Logins">
<!ENTITY rememberLogins.label "Remember logins for sites">
<!ENTITY rememberLogins.accesskey "R">
<!ENTITY rememberLogins2.label "Remember logins for websites">
<!ENTITY rememberLogins2.accesskey "R">
<!ENTITY passwordExceptions.label "Exceptions…">
<!ENTITY passwordExceptions.accesskey "x">

Просмотреть файл

@ -8,7 +8,7 @@
<!ENTITY blockPopups.accesskey "B">
<!ENTITY notificationsPolicyLearnMore.label "Learn more">
<!ENTITY notificationsPolicyDesc3.label "Choose which sites are allowed to send you notifications">
<!ENTITY notificationsPolicyDesc4.label "Choose which websites are allowed to send you notifications">
<!ENTITY notificationsPolicyButton.accesskey "h">
<!ENTITY notificationsPolicyButton.label "Choose…">
<!ENTITY notificationsDoNotDisturb.label "Do not disturb me">

Просмотреть файл

@ -5,12 +5,12 @@
<!ENTITY window.title "Exceptions">
<!ENTITY window.width "45em">
<!ENTITY treehead.sitename.label "Site">
<!ENTITY treehead.sitename2.label "Website">
<!ENTITY treehead.status.label "Status">
<!ENTITY removepermission.label "Remove Site">
<!ENTITY removepermission.accesskey "R">
<!ENTITY removeallpermissions.label "Remove All Sites">
<!ENTITY removeallpermissions.accesskey "e">
<!ENTITY removepermission2.label "Remove Website">
<!ENTITY removepermission2.accesskey "R">
<!ENTITY removeallpermissions2.label "Remove All Websites">
<!ENTITY removeallpermissions2.accesskey "e">
<!ENTITY address.label "Address of website:">
<!ENTITY address.accesskey "d">
<!ENTITY block.label "Block">

Просмотреть файл

@ -19,20 +19,20 @@ acceptVeryLargeMinimumFont=Keep my changes anyway
#### Permissions Manager
trackingprotectionpermissionstext=You have disabled Tracking Protection on these sites.
trackingprotectionpermissionstext2=You have disabled Tracking Protection on these websites.
trackingprotectionpermissionstitle=Exceptions - Tracking Protection
cookiepermissionstext=You can specify which websites are always or never allowed to use cookies. Type the exact address of the site you want to manage and then click Block, Allow for Session, or Allow.
cookiepermissionstitle=Exceptions - Cookies
addonspermissionstext=You can specify which websites are allowed to install add-ons. Type the exact address of the site you want to allow and then click Allow.
addons_permissions_title=Allowed Sites - Add-ons Installation
addons_permissions_title2=Allowed Websites - Add-ons Installation
popuppermissionstext=You can specify which websites are allowed to open pop-up windows. Type the exact address of the site you want to allow and then click Allow.
popuppermissionstitle=Allowed Sites - Pop-ups
popuppermissionstitle2=Allowed Websites - Pop-ups
notificationspermissionstext4=Control which websites are always or never allowed to send you notifications. If you remove a site, it will need to request permission again.
notificationspermissionstitle=Notification Permissions
invalidURI=Please enter a valid hostname
invalidURITitle=Invalid Hostname Entered
savedLoginsExceptions_title=Exceptions - Saved Logins
savedLoginsExceptions_desc=Logins for the following sites will not be saved:
savedLoginsExceptions_desc2=Logins for the following websites will not be saved:
#### Block List Manager
@ -51,7 +51,7 @@ mozNameTemplate=%1$S %2$S
mozstdName=Disconnect.me basic protection (Recommended).
mozstdDesc=Allows some trackers so websites function properly.
mozfullName=Disconnect.me strict protection.
mozfullDesc=Blocks known trackers. Some sites may not function properly.
mozfullDesc2=Blocks known trackers. Some websites may not function properly.
# LOCALIZATION NOTE (blocklistChangeRequiresRestart): %S = brandShortName
blocklistChangeRequiresRestart=%S must restart to change block lists.
@ -191,8 +191,8 @@ clearSiteDataNow=Clear Now
persistent=Persistent
siteUsage=%1$S %2$S
acceptRemove=Remove
# LOCALIZATION NOTE (siteDataSettings.description): %S = brandShortName
siteDataSettings.description=The following websites store site data on your computer. %S keeps data from sites with persistent storage until you delete it, and deletes data from sites with non-persistent storage as space is needed.
# LOCALIZATION NOTE (siteDataSettings2.description): %S = brandShortName
siteDataSettings2.description=The following websites store site data on your computer. %S keeps data from websites with persistent storage until you delete it, and deletes data from websites with non-persistent storage as space is needed.
# LOCALIZATION NOTE (removeAllSiteData, removeAllSiteDataShown):
# removeAllSiteData and removeAllSiteDataShown are both used on the same one button,
# never displayed together and can share the same accesskey.

Просмотреть файл

@ -46,8 +46,8 @@
<!ENTITY suggestionSettings2.label "Change preferences for search engine suggestions">
<!ENTITY acceptCookies.label "Accept cookies from sites">
<!ENTITY acceptCookies.accesskey "A">
<!ENTITY acceptCookies2.label "Accept cookies from websites">
<!ENTITY acceptCookies2.accesskey "A">
<!ENTITY acceptThirdParty.pre.label "Accept third-party cookies:">
<!ENTITY acceptThirdParty.pre.accesskey "y">

Просмотреть файл

@ -5,8 +5,8 @@
<!ENTITY security.label "Security">
<!ENTITY phishingProtection.label "Phishing Protection">
<!ENTITY warnOnAddonInstall.label "Warn you when sites try to install add-ons">
<!ENTITY warnOnAddonInstall.accesskey "W">
<!ENTITY warnOnAddonInstall2.label "Warn you when websites try to install add-ons">
<!ENTITY warnOnAddonInstall2.accesskey "W">
<!-- LOCALIZATION NOTE (enableSafeBrowsing.label, blockDownloads.label, blockUncommonUnwanted.label):
It is important that wording follows the guidelines outlined on this page:
@ -27,8 +27,8 @@
<!ENTITY formsAndPasswords.label "Forms &amp; Passwords">
<!ENTITY rememberLogins1.label "Remember logins and passwords for sites">
<!ENTITY rememberLogins1.accesskey "R">
<!ENTITY rememberLogins2.label "Remember logins and passwords for websites">
<!ENTITY rememberLogins2.accesskey "R">
<!ENTITY passwordExceptions.label "Exceptions…">
<!ENTITY passwordExceptions.accesskey "x">

Просмотреть файл

@ -14,7 +14,7 @@
<!ENTITY removeAllLanguages.accesskey "e">
<!ENTITY noTranslationForSites.label "Translation will not be offered for the following sites:">
<!ENTITY treehead.siteName.label "Sites">
<!ENTITY treehead.siteName2.label "Websites">
<!ENTITY removeSite.label "Remove Site">
<!ENTITY removeSite.accesskey "S">
<!ENTITY removeAllSites.label "Remove All Sites">

Просмотреть файл

@ -700,17 +700,18 @@ groupbox {
menulist[indicator=true] > menupopup menuitem:not([image]) > .menu-iconic-left {
display: -moz-box;
width: 8px;
min-width: auto; /* Override the min-width defined in menu.css */
height: 10px;
margin-inline-end: 6px;
}
menulist[indicator=true] > menupopup menuitem:not([image]) > .menu-iconic-left > .menu-iconic-icon {
width: 8px;
height: 10px;
margin: 0;
}
menulist[indicator=true] > menupopup menuitem[indicator=true]:not([image]) > .menu-iconic-left > .menu-iconic-icon {
list-style-image: url(chrome://browser/skin/preferences/in-content-new/search-arrow-indicator.svg);
width: 8px;
height: 10px;
margin: 0;
}
menulist[indicator=true] > menupopup menuitem[indicator=true]:not([image]) > .menu-iconic-left > .menu-iconic-icon:-moz-locale-dir(rtl) {

Просмотреть файл

@ -1066,6 +1066,7 @@ Scanner.prototype = {
// aToken.mIdent may be "url" at this point; clear that out
aToken.mIdent.length = 0;
let hasString = false;
let ch = this.Peek();
// Do we have a string?
if (ch == QUOTATION_MARK || ch == APOSTROPHE) {
@ -1074,6 +1075,7 @@ Scanner.prototype = {
aToken.mType = eCSSToken_Bad_URL;
return;
}
hasString = true;
} else {
// Otherwise, this is the start of a non-quoted url (which may be empty).
aToken.mSymbol = 0;
@ -1092,6 +1094,25 @@ Scanner.prototype = {
}
} else {
aToken.mType = eCSSToken_Bad_URL;
if (!hasString) {
// Consume until before the next right parenthesis, which follows
// how <bad-url-token> is consumed in CSS Syntax 3 spec.
// Note that, we only do this when "url(" is not followed by a
// string, because in the spec, "url(" followed by a string is
// handled as a url function rather than a <url-token>, so the
// rest of content before ")" should be consumed in balance,
// which will be done by the parser.
// The closing ")" is not consumed here. It is left to the parser
// so that the parser can handle both cases.
do {
if (IsVertSpace(ch)) {
this.AdvanceLine();
} else {
this.Advance();
}
ch = this.Peek();
} while (ch >= 0 && ch != RIGHT_PARENTHESIS);
}
}
},

Просмотреть файл

@ -128,8 +128,7 @@ var LEX_TESTS = [
["url:http://example.com"]],
// In CSS Level 3, this is an ordinary URL, not a BAD_URL.
["url(http://example.com", ["url:http://example.com"]],
// See bug 1153981 to understand why this gets a SYMBOL token.
["url(http://example.com @", ["bad_url:http://example.com", "symbol:@"]],
["url(http://example.com @", ["bad_url:http://example.com"]],
["quo\\ting", ["ident:quoting"]],
["'bad string\n", ["bad_string:bad string", "whitespace"]],
["~=", ["includes"]],

Просмотреть файл

@ -0,0 +1,8 @@
[DEFAULT]
support-files =
file_CrossSiteXHR_server.sjs
file_CrossSiteXHR_inner.html
file_cors_logging_test.html
head.js
[browser_CORS-console-warnings.js]

Просмотреть файл

@ -0,0 +1,93 @@
/*
* Description of the test:
* Ensure that CORS warnings are printed to the web console.
*
* This test uses the same tests as the plain mochitest, but needs access to
* the console.
*/
'use strict';
function console_observer(subject, topic, data) {
var message = subject.wrappedJSObject.arguments[0];
ok(false, message);
};
var webconsole = null;
var messages_seen = 0;
var expected_messages = 50;
function on_new_message(event, new_messages) {
for (let message of new_messages) {
let elem = message.node;
let text = elem.textContent;
if (text.match('Cross-Origin Request Blocked:')) {
ok(true, "message is: " + text);
messages_seen++;
}
}
}
function do_cleanup() {
if (webconsole) {
webconsole.ui.off("new-messages", on_new_message);
}
yield unsetCookiePref();
}
/**
* Set e10s related preferences in the test environment.
* @return {Promise} promise that resolves when preferences are set.
*/
function setCookiePref() {
return new Promise(resolve =>
// accept all cookies so that the CORS requests will send the right cookies
SpecialPowers.pushPrefEnv({
set: [
["network.cookie.cookieBehavior", 0],
]
}, resolve));
}
/**
* Unset e10s related preferences in the test environment.
* @return {Promise} promise that resolves when preferences are unset.
*/
function unsetCookiePref() {
return new Promise(resolve => {
SpecialPowers.popPrefEnv(resolve);
});
}
//jscs:disable
add_task(function*() {
//jscs:enable
// A longer timeout is necessary for this test than the plain mochitests
// due to opening a new tab with the web console.
requestLongerTimeout(4);
registerCleanupFunction(do_cleanup);
yield setCookiePref();
let test_uri = "http://mochi.test:8888/browser/dom/security/test/cors/file_cors_logging_test.html";
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "about:blank");
let toolbox = yield openToolboxForTab(tab, "webconsole");
ok(toolbox, "Got toolbox");
let hud = toolbox.getCurrentPanel().hud;
ok(hud, "Got hud");
if (!webconsole) {
registerCleanupFunction(do_cleanup);
hud.ui.on("new-messages", on_new_message);
webconsole = hud;
}
BrowserTestUtils.loadURI(gBrowser, test_uri);
yield BrowserTestUtils.waitForLocationChange(gBrowser, test_uri+"#finished");
// Different OS combinations
ok(messages_seen > 0, "Saw " + messages_seen + " messages.");
yield BrowserTestUtils.removeTab(tab);
});

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

Просмотреть файл

@ -0,0 +1,69 @@
'use strict';
var { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
function scopedCuImport(path) {
const scope = {};
Cu.import(path, scope);
return scope;
}
const {loader, require} = scopedCuImport("resource://devtools/shared/Loader.jsm");
const {TargetFactory} = require("devtools/client/framework/target");
const {Utils: WebConsoleUtils} =
require("devtools/client/webconsole/utils");
let { gDevTools } = require("devtools/client/framework/devtools");
loader.lazyGetter(this, "HUDService", () => require("devtools/client/webconsole/webconsole"));
loader.lazyGetter(this, "HUDService", () => require("devtools/client/webconsole/hudservice"));
let promise = require("promise");
/**
* Open the toolbox in a given tab.
* @param {XULNode} tab The tab the toolbox should be opened in.
* @param {String} toolId Optional. The ID of the tool to be selected.
* @param {String} hostType Optional. The type of toolbox host to be used.
* @return {Promise} Resolves with the toolbox, when it has been opened.
*/
var openToolboxForTab = Task.async(function* (tab, toolId, hostType) {
info("Opening the toolbox");
let toolbox;
let target = TargetFactory.forTab(tab);
yield target.makeRemote();
// Check if the toolbox is already loaded.
toolbox = gDevTools.getToolbox(target);
if (toolbox) {
if (!toolId || (toolId && toolbox.getPanel(toolId))) {
info("Toolbox is already opened");
return toolbox;
}
}
// If not, load it now.
toolbox = yield gDevTools.showToolbox(target, toolId, hostType);
// Make sure that the toolbox frame is focused.
yield new Promise(resolve => waitForFocus(resolve, toolbox.win));
info("Toolbox opened and focused");
return toolbox;
});
/**
* Find multiple messages in the output.
*
* @param object hud
* The web console.
* @param string text
* A substring that can be found in the message.
* @param selector [optional]
* The selector to use in finding the message.
*/
function findMessages(hud, text, selector = ".message") {
const messages = hud.ui.experimentalOutputNode.querySelectorAll(selector);
const elements = Array.prototype.filter.call(
messages,
(el) => el.textContent.includes(text)
);
return elements;
}

Просмотреть файл

@ -28,6 +28,7 @@ MOCHITEST_CHROME_MANIFESTS += [
]
BROWSER_CHROME_MANIFESTS += [
'cors/browser.ini',
'csp/browser.ini',
'general/browser.ini',
'hsts/browser.ini',

Просмотреть файл

@ -1091,7 +1091,7 @@ PWebRenderBridgeChild*
CompositorBridgeChild::AllocPWebRenderBridgeChild(const wr::PipelineId& aPipelineId,
const LayoutDeviceIntSize&,
TextureFactoryIdentifier*,
uint32_t *aIdNamespace)
wr::IdNamespace *aIdNamespace)
{
WebRenderBridgeChild* child = new WebRenderBridgeChild(aPipelineId);
child->AddIPDLReference();

Просмотреть файл

@ -210,7 +210,7 @@ public:
PWebRenderBridgeChild* AllocPWebRenderBridgeChild(const wr::PipelineId& aPipelineId,
const LayoutDeviceIntSize&,
TextureFactoryIdentifier*,
uint32_t*) override;
wr::IdNamespace*) override;
bool DeallocPWebRenderBridgeChild(PWebRenderBridgeChild* aActor) override;
uint64_t DeviceResetSequenceNumber() const {

Просмотреть файл

@ -1678,7 +1678,7 @@ PWebRenderBridgeParent*
CompositorBridgeParent::AllocPWebRenderBridgeParent(const wr::PipelineId& aPipelineId,
const LayoutDeviceIntSize& aSize,
TextureFactoryIdentifier* aTextureFactoryIdentifier,
uint32_t* aIdNamespace)
wr::IdNamespace* aIdNamespace)
{
#ifndef MOZ_BUILD_WEBRENDER
// Extra guard since this in the parent process and we don't want a malicious
@ -1699,15 +1699,14 @@ CompositorBridgeParent::AllocPWebRenderBridgeParent(const wr::PipelineId& aPipel
new AsyncImagePipelineManager(WebRenderBridgeParent::AllocIdNameSpace());
if (!api) {
mWrBridge = WebRenderBridgeParent::CreateDestroyed();
*aIdNamespace = mWrBridge->GetIdNameSpace();
*aIdNamespace = mWrBridge->GetIdNamespace();
*aTextureFactoryIdentifier = TextureFactoryIdentifier(LayersBackend::LAYERS_NONE);
return mWrBridge;
}
MOZ_ASSERT(api); // TODO have a fallback
api->SetRootPipeline(aPipelineId);
RefPtr<CompositorAnimationStorage> animStorage = GetAnimationStorage();
mWrBridge = new WebRenderBridgeParent(this, aPipelineId, mWidget, nullptr, Move(api), Move(asyncMgr), Move(animStorage));
*aIdNamespace = mWrBridge->GetIdNameSpace();
*aIdNamespace = mWrBridge->GetIdNamespace();
mCompositorScheduler = mWrBridge->CompositorScheduler();
MOZ_ASSERT(mCompositorScheduler);

Просмотреть файл

@ -459,7 +459,7 @@ public:
PWebRenderBridgeParent* AllocPWebRenderBridgeParent(const wr::PipelineId& aPipelineId,
const LayoutDeviceIntSize& aSize,
TextureFactoryIdentifier* aTextureFactoryIdentifier,
uint32_t* aIdNamespace) override;
wr::IdNamespace* aIdNamespace) override;
bool DeallocPWebRenderBridgeParent(PWebRenderBridgeParent* aActor) override;
RefPtr<WebRenderBridgeParent> GetWebRenderBridgeParent() const;
Maybe<TimeStamp> GetTestingTimeStamp() const;

Просмотреть файл

@ -194,7 +194,7 @@ PWebRenderBridgeParent*
CrossProcessCompositorBridgeParent::AllocPWebRenderBridgeParent(const wr::PipelineId& aPipelineId,
const LayoutDeviceIntSize& aSize,
TextureFactoryIdentifier* aTextureFactoryIdentifier,
uint32_t *aIdNamespace)
wr::IdNamespace *aIdNamespace)
{
#ifndef MOZ_BUILD_WEBRENDER
// Extra guard since this in the parent process and we don't want a malicious
@ -218,7 +218,7 @@ CrossProcessCompositorBridgeParent::AllocPWebRenderBridgeParent(const wr::Pipeli
// This was observed during Tab move between different windows.
NS_WARNING("Created child without a matching parent?");
parent = WebRenderBridgeParent::CreateDestroyed();
*aIdNamespace = parent->GetIdNameSpace();
*aIdNamespace = parent->GetIdNamespace();
*aTextureFactoryIdentifier = TextureFactoryIdentifier(LayersBackend::LAYERS_NONE);
return parent;
}
@ -233,7 +233,7 @@ CrossProcessCompositorBridgeParent::AllocPWebRenderBridgeParent(const wr::Pipeli
sIndirectLayerTrees[layersId].mCrossProcessParent = this;
sIndirectLayerTrees[layersId].mWrBridge = parent;
*aTextureFactoryIdentifier = parent->GetTextureFactoryIdentifier();
*aIdNamespace = parent->GetIdNameSpace();
*aIdNamespace = parent->GetIdNamespace();
return parent;
}

Просмотреть файл

@ -148,7 +148,7 @@ public:
PWebRenderBridgeParent* AllocPWebRenderBridgeParent(const wr::PipelineId& aPipelineId,
const LayoutDeviceIntSize& aSize,
TextureFactoryIdentifier* aTextureFactoryIdentifier,
uint32_t* aIdNamespace) override;
wr::IdNamespace* aIdNamespace) override;
bool DeallocPWebRenderBridgeParent(PWebRenderBridgeParent* aActor) override;
void ObserveLayerUpdate(uint64_t aLayersId, uint64_t aEpoch, bool aActive) override;

Просмотреть файл

@ -39,6 +39,7 @@ using class mozilla::layers::FrameUniformityData from "mozilla/layers/FrameUnifo
using mozilla::layers::TextureFlags from "mozilla/layers/CompositorTypes.h";
using mozilla::layers::CompositorOptions from "mozilla/layers/CompositorOptions.h";
using mozilla::wr::PipelineId from "mozilla/webrender/WebRenderTypes.h";
using mozilla::wr::IdNamespace from "mozilla/webrender/WebRenderTypes.h";
using base::ProcessId from "base/process.h";
using mozilla::wr::MaybeExternalImageId from "mozilla/webrender/WebRenderTypes.h";
@ -250,7 +251,7 @@ parent:
// The pipelineId is the same as the layersId
sync PWebRenderBridge(PipelineId pipelineId, LayoutDeviceIntSize aSize)
returns (TextureFactoryIdentifier textureFactoryIdentifier, uint32_t idNamespace); //XXX: use the WrIdNamespace type
returns (TextureFactoryIdentifier textureFactoryIdentifier, IdNamespace idNamespace);
sync CheckContentOnlyTDR(uint32_t sequenceNum)
returns (bool isContentOnlyTDR);

Просмотреть файл

@ -24,6 +24,7 @@ using mozilla::wr::ImageKey from "mozilla/webrender/WebRenderTypes.h";
using mozilla::wr::FontKey from "mozilla/webrender/WebRenderTypes.h";
using mozilla::wr::PipelineId from "mozilla/webrender/WebRenderTypes.h";
using mozilla::wr::BuiltDisplayListDescriptor from "mozilla/webrender/webrender_ffi.h";
using mozilla::wr::IdNamespace from "mozilla/webrender/WebRenderTypes.h";
using mozilla::layers::WebRenderScrollData from "mozilla/layers/WebRenderScrollData.h";
namespace mozilla {
@ -56,10 +57,10 @@ parent:
async DPBegin(IntSize aSize);
async DPEnd(IntSize aSize, WebRenderParentCommand[] commands, OpDestroy[] toDestroy, uint64_t fwdTransactionId, uint64_t transactionId,
LayoutSize aContentSize, ByteBuffer aDL, BuiltDisplayListDescriptor aDLDesc,
WebRenderScrollData aScrollData, uint32_t idNameSpace, TimeStamp fwdTime);
WebRenderScrollData aScrollData, IdNamespace aIdNamespace, TimeStamp fwdTime);
sync DPSyncEnd(IntSize aSize, WebRenderParentCommand[] commands, OpDestroy[] toDestroy, uint64_t fwdTransactionId, uint64_t transactionId,
LayoutSize aContentSize, ByteBuffer aDL, BuiltDisplayListDescriptor aDLDesc,
WebRenderScrollData aScrollData, uint32_t idNameSpace, TimeStamp fwdTime);
WebRenderScrollData aScrollData, IdNamespace aIdNamespace, TimeStamp fwdTime);
async ParentCommands(WebRenderParentCommand[] commands);
sync DPGetSnapshot(PTexture texture);
async AddPipelineIdForAsyncCompositable(PipelineId aImageId, CompositableHandle aHandle);
@ -88,7 +89,7 @@ parent:
async Shutdown();
sync ShutdownSync();
child:
async WrUpdated(uint32_t newIdNameSpace);
async WrUpdated(IdNamespace aNewIdNamespace);
async __delete__();
};

Просмотреть файл

@ -23,7 +23,7 @@ AsyncImagePipelineManager::AsyncImagePipeline::AsyncImagePipeline()
, mMixBlendMode(wr::MixBlendMode::Normal)
{}
AsyncImagePipelineManager::AsyncImagePipelineManager(uint32_t aIdNamespace)
AsyncImagePipelineManager::AsyncImagePipelineManager(wr::IdNamespace aIdNamespace)
: mIdNamespace(aIdNamespace)
, mResourceId(0)
, mAsyncImageEpoch(0)

Просмотреть файл

@ -34,7 +34,7 @@ class AsyncImagePipelineManager final
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AsyncImagePipelineManager)
explicit AsyncImagePipelineManager(uint32_t aIdNamespace);
explicit AsyncImagePipelineManager(wr::IdNamespace aIdNamespace);
protected:
~AsyncImagePipelineManager();
@ -94,11 +94,11 @@ private:
void DeleteOldAsyncImages(wr::WebRenderAPI* aApi);
uint32_t GetNextResourceId() { return ++mResourceId; }
uint32_t GetNamespace() { return mIdNamespace; }
wr::IdNamespace GetNamespace() { return mIdNamespace; }
wr::ImageKey GenerateImageKey()
{
wr::ImageKey key;
key.mNamespace.mHandle = GetNamespace();
key.mNamespace = GetNamespace();
key.mHandle = GetNextResourceId();
return key;
}
@ -141,7 +141,7 @@ private:
nsTArray<wr::ImageKey>& aKeys,
nsTArray<wr::ImageKey>& aKeysToDelete);
uint32_t mIdNamespace;
wr::IdNamespace mIdNamespace;
uint32_t mResourceId;
nsClassHashtable<nsUint64HashKey, PipelineTexturesHolder> mPipelineTexturesHolders;

Просмотреть файл

@ -23,7 +23,7 @@ WebRenderBridgeChild::WebRenderBridgeChild(const wr::PipelineId& aPipelineId)
: mReadLockSequenceNumber(0)
, mIsInTransaction(false)
, mIsInClearCachedResources(false)
, mIdNamespace(0)
, mIdNamespace{0}
, mResourceId(0)
, mPipelineId(aPipelineId)
, mIPCOpen(false)
@ -119,7 +119,7 @@ WebRenderBridgeChild::DPEnd(wr::DisplayListBuilder &aBuilder,
if (aIsSync) {
this->SendDPSyncEnd(aSize, mParentCommands, mDestroyedActors, GetFwdTransactionId(), aTransactionId,
contentSize, dlData, dl.dl_desc, aScrollData, mIdNamespace,fwdTime);
contentSize, dlData, dl.dl_desc, aScrollData, mIdNamespace, fwdTime);
} else {
this->SendDPEnd(aSize, mParentCommands, mDestroyedActors, GetFwdTransactionId(), aTransactionId,
contentSize, dlData, dl.dl_desc, aScrollData, mIdNamespace, fwdTime);
@ -260,7 +260,7 @@ WebRenderBridgeChild::GetFontKeyForScaledFont(gfx::ScaledFont* aScaledFont)
return key;
}
key.mNamespace.mHandle = GetNamespace();
key.mNamespace = GetNamespace();
key.mHandle = GetNextResourceId();
SendAddRawFont(key, data.mFontBuffer, data.mFontIndex);
@ -452,11 +452,11 @@ WebRenderBridgeChild::InForwarderThread()
}
mozilla::ipc::IPCResult
WebRenderBridgeChild::RecvWrUpdated(const uint32_t& aNewIdNameSpace)
WebRenderBridgeChild::RecvWrUpdated(const wr::IdNamespace& aNewIdNamespace)
{
// Update mIdNamespace to identify obsolete keys and messages by WebRenderBridgeParent.
// Since usage of invalid keys could cause crash in webrender.
mIdNamespace = aNewIdNameSpace;
mIdNamespace = aNewIdNamespace;
// Remove all FontKeys since they are removed by WebRenderBridgeParent
for (auto iter = mFontKeys.Iter(); !iter.Done(); iter.Next()) {
SendDeleteFont(iter.Data());

Просмотреть файл

@ -90,15 +90,15 @@ public:
bool IsDestroyed() const { return mDestroyed; }
uint32_t GetNextResourceId() { return ++mResourceId; }
uint32_t GetNamespace() { return mIdNamespace; }
void SetNamespace(uint32_t aIdNamespace)
wr::IdNamespace GetNamespace() { return mIdNamespace; }
void SetNamespace(wr::IdNamespace aIdNamespace)
{
mIdNamespace = aIdNamespace;
}
wr::WrImageKey GetNextImageKey()
{
return wr::WrImageKey{ wr::WrIdNamespace { GetNamespace() }, GetNextResourceId() };
return wr::WrImageKey{ GetNamespace(), GetNextResourceId() };
}
void PushGlyphs(wr::DisplayListBuilder& aBuilder, const nsTArray<GlyphArray>& aGlyphs,
@ -144,7 +144,7 @@ private:
void ActorDestroy(ActorDestroyReason why) override;
virtual mozilla::ipc::IPCResult RecvWrUpdated(const uint32_t& aNewIdNameSpace) override;
virtual mozilla::ipc::IPCResult RecvWrUpdated(const wr::IdNamespace& aNewIdNamespace) override;
void AddIPDLReference() {
MOZ_ASSERT(mIPCOpen == false);
@ -166,7 +166,7 @@ private:
uint64_t mReadLockSequenceNumber;
bool mIsInTransaction;
bool mIsInClearCachedResources;
uint32_t mIdNamespace;
wr::IdNamespace mIdNamespace;
uint32_t mResourceId;
wr::PipelineId mPipelineId;

Просмотреть файл

@ -131,7 +131,7 @@ WebRenderBridgeParent::WebRenderBridgeParent(CompositorBridgeParentBase* aCompos
, mChildLayerObserverEpoch(0)
, mParentLayerObserverEpoch(0)
, mWrEpoch(0)
, mIdNameSpace(AllocIdNameSpace())
, mIdNamespace(AllocIdNameSpace())
, mPaused(false)
, mDestroyed(false)
, mForceRendering(false)
@ -150,7 +150,7 @@ WebRenderBridgeParent::WebRenderBridgeParent()
, mChildLayerObserverEpoch(0)
, mParentLayerObserverEpoch(0)
, mWrEpoch(0)
, mIdNameSpace(AllocIdNameSpace())
, mIdNamespace(AllocIdNameSpace())
, mPaused(false)
, mDestroyed(true)
, mForceRendering(false)
@ -234,7 +234,7 @@ WebRenderBridgeParent::RecvAddImage(const wr::ImageKey& aImageKey,
}
// Check if key is obsoleted.
if (aImageKey.mNamespace.mHandle != mIdNameSpace) {
if (aImageKey.mNamespace != mIdNamespace) {
return IPC_OK();
}
@ -261,7 +261,7 @@ WebRenderBridgeParent::RecvAddBlobImage(const wr::ImageKey& aImageKey,
}
// Check if key is obsoleted.
if (aImageKey.mNamespace.mHandle != mIdNameSpace) {
if (aImageKey.mNamespace != mIdNamespace) {
return IPC_OK();
}
@ -286,7 +286,7 @@ WebRenderBridgeParent::RecvAddRawFont(const wr::FontKey& aFontKey,
}
// Check if key is obsoleted.
if (aFontKey.mNamespace.mHandle != mIdNameSpace) {
if (aFontKey.mNamespace != mIdNamespace) {
return IPC_OK();
}
@ -309,7 +309,7 @@ WebRenderBridgeParent::RecvDeleteFont(const wr::FontKey& aFontKey)
MOZ_ASSERT(mApi);
// Check if key is obsoleted.
if (aFontKey.mNamespace.mHandle != mIdNameSpace) {
if (aFontKey.mNamespace != mIdNamespace) {
return IPC_OK();
}
@ -335,7 +335,7 @@ WebRenderBridgeParent::RecvUpdateImage(const wr::ImageKey& aImageKey,
MOZ_ASSERT(mApi);
// Check if key is obsoleted.
if (aImageKey.mNamespace.mHandle != mIdNameSpace) {
if (aImageKey.mNamespace != mIdNamespace) {
return IPC_OK();
}
@ -354,7 +354,7 @@ WebRenderBridgeParent::RecvDeleteImage(const wr::ImageKey& aImageKey)
MOZ_ASSERT(mApi);
// Check if key is obsoleted.
if (aImageKey.mNamespace.mHandle != mIdNameSpace) {
if (aImageKey.mNamespace != mIdNamespace) {
return IPC_OK();
}
@ -406,7 +406,7 @@ WebRenderBridgeParent::HandleDPEnd(const gfx::IntSize& aSize,
const wr::ByteBuffer& dl,
const wr::BuiltDisplayListDescriptor& dlDesc,
const WebRenderScrollData& aScrollData,
const uint32_t& aIdNameSpace,
const wr::IdNamespace& aIdNamespace,
const TimeStamp& aFwdTime)
{
AutoProfilerTracing tracing("Paint", "DPTransaction");
@ -425,13 +425,13 @@ WebRenderBridgeParent::HandleDPEnd(const gfx::IntSize& aSize,
uint32_t wrEpoch = GetNextWrEpoch();
ProcessWebRenderCommands(aSize, aCommands, wr::NewEpoch(wrEpoch),
aContentSize, dl, dlDesc, aIdNameSpace);
aContentSize, dl, dlDesc, aIdNamespace);
HoldPendingTransactionId(wrEpoch, aTransactionId, aFwdTime);
mScrollData = aScrollData;
UpdateAPZ();
if (mIdNameSpace != aIdNameSpace) {
if (mIdNamespace != aIdNamespace) {
// Pretend we composited since someone is wating for this event,
// though DisplayList was not pushed to webrender.
TimeStamp now = TimeStamp::Now();
@ -520,14 +520,14 @@ WebRenderBridgeParent::RecvDPEnd(const gfx::IntSize& aSize,
const wr::ByteBuffer& dl,
const wr::BuiltDisplayListDescriptor& dlDesc,
const WebRenderScrollData& aScrollData,
const uint32_t& aIdNameSpace,
const wr::IdNamespace& aIdNamespace,
const TimeStamp& aFwdTime)
{
if (mDestroyed) {
return IPC_OK();
}
HandleDPEnd(aSize, Move(aCommands), Move(aToDestroy), aFwdTransactionId, aTransactionId,
aContentSize, dl, dlDesc, aScrollData, aIdNameSpace, aFwdTime);
aContentSize, dl, dlDesc, aScrollData, aIdNamespace, aFwdTime);
return IPC_OK();
}
@ -541,14 +541,14 @@ WebRenderBridgeParent::RecvDPSyncEnd(const gfx::IntSize &aSize,
const wr::ByteBuffer& dl,
const wr::BuiltDisplayListDescriptor& dlDesc,
const WebRenderScrollData& aScrollData,
const uint32_t& aIdNameSpace,
const wr::IdNamespace& aIdNamespace,
const TimeStamp& aFwdTime)
{
if (mDestroyed) {
return IPC_OK();
}
HandleDPEnd(aSize, Move(aCommands), Move(aToDestroy), aFwdTransactionId, aTransactionId,
aContentSize, dl, dlDesc, aScrollData, aIdNameSpace, aFwdTime);
aContentSize, dl, dlDesc, aScrollData, aIdNamespace, aFwdTime);
return IPC_OK();
}
@ -572,7 +572,7 @@ WebRenderBridgeParent::ProcessWebRenderParentCommands(InfallibleTArray<WebRender
const OpAddExternalImage& op = cmd.get_OpAddExternalImage();
Range<const wr::ImageKey> keys(&op.key(), 1);
// Check if key is obsoleted.
if (keys[0].mNamespace.mHandle != mIdNameSpace) {
if (keys[0].mNamespace != mIdNamespace) {
break;
}
MOZ_ASSERT(mExternalImageIds.Get(wr::AsUint64(op.externalImageId())).get());
@ -663,14 +663,14 @@ WebRenderBridgeParent::ProcessWebRenderCommands(const gfx::IntSize &aSize,
InfallibleTArray<WebRenderParentCommand>& aCommands, const wr::Epoch& aEpoch,
const wr::LayoutSize& aContentSize, const wr::ByteBuffer& dl,
const wr::BuiltDisplayListDescriptor& dlDesc,
const uint32_t& aIdNameSpace)
const wr::IdNamespace& aIdNamespace)
{
mAsyncImageManager->SetCompositionTime(TimeStamp::Now());
ProcessWebRenderParentCommands(aCommands);
// The command is obsoleted.
// Do not set the command to webrender since it causes crash in webrender.
if (mIdNameSpace != aIdNameSpace) {
if (mIdNamespace != aIdNamespace) {
return;
}
@ -881,7 +881,7 @@ WebRenderBridgeParent::UpdateWebRender(CompositorVsyncScheduler* aScheduler,
// Update id name space to identify obsoleted keys.
// Since usage of invalid keys could cause crash in webrender.
mIdNameSpace = AllocIdNameSpace();
mIdNamespace = AllocIdNameSpace();
// XXX Remove it when webrender supports sharing/moving Keys between different webrender instances.
// XXX It requests client to update/reallocate webrender related resources,
// but parent side does not wait end of the update.
@ -890,7 +890,7 @@ WebRenderBridgeParent::UpdateWebRender(CompositorVsyncScheduler* aScheduler,
// after new layers/webrender keys allocation.
// Without client side's layout refactoring, we could not finish all old layers/webrender keys removals
// before new layer/webrender keys allocation. In future, we could address the problem.
Unused << SendWrUpdated(mIdNameSpace);
Unused << SendWrUpdated(mIdNamespace);
CompositorBridgeParentBase* cBridge = mCompositorBridge;
// XXX Stop to clear resources if webreder supports resources sharing between different webrender instances.
ClearResources();

Просмотреть файл

@ -102,7 +102,7 @@ public:
const wr::ByteBuffer& dl,
const wr::BuiltDisplayListDescriptor& dlDesc,
const WebRenderScrollData& aScrollData,
const uint32_t& aIdNameSpace,
const wr::IdNamespace& aIdNamespace,
const TimeStamp& aFwdTime) override;
mozilla::ipc::IPCResult RecvDPSyncEnd(const gfx::IntSize& aSize,
InfallibleTArray<WebRenderParentCommand>&& aCommands,
@ -113,7 +113,7 @@ public:
const wr::ByteBuffer& dl,
const wr::BuiltDisplayListDescriptor& dlDesc,
const WebRenderScrollData& aScrollData,
const uint32_t& aIdNameSpace,
const wr::IdNamespace& aIdNamespace,
const TimeStamp& aFwdTime) override;
mozilla::ipc::IPCResult RecvParentCommands(nsTArray<WebRenderParentCommand>&& commands) override;
mozilla::ipc::IPCResult RecvDPGetSnapshot(PTextureParent* aTexture) override;
@ -178,16 +178,16 @@ public:
void ExtractImageCompositeNotifications(nsTArray<ImageCompositeNotificationInfo>* aNotifications);
uint32_t GetIdNameSpace()
wr::IdNamespace GetIdNamespace()
{
return mIdNameSpace;
return mIdNamespace;
}
void UpdateAPZ();
const WebRenderScrollData& GetScrollData() const;
static uint32_t AllocIdNameSpace() {
return ++sIdNameSpace;
static wr::IdNamespace AllocIdNameSpace() {
return wr::IdNamespace { ++sIdNameSpace };
}
void FlushRendering(bool aIsSync);
@ -212,7 +212,7 @@ private:
const wr::LayoutSize& aContentSize,
const wr::ByteBuffer& dl,
const wr::BuiltDisplayListDescriptor& dlDesc,
const uint32_t& aIdNameSpace);
const wr::IdNamespace& aIdNamespace);
void ClearResources();
uint64_t GetChildLayerObserverEpoch() const { return mChildLayerObserverEpoch; }
bool ShouldParentObserveEpoch();
@ -225,7 +225,7 @@ private:
const wr::ByteBuffer& dl,
const wr::BuiltDisplayListDescriptor& dlDesc,
const WebRenderScrollData& aScrollData,
const uint32_t& aIdNameSpace,
const wr::IdNamespace& aIdNamespace,
const TimeStamp& aFwdTime);
mozilla::ipc::IPCResult HandleShutdown();
@ -287,7 +287,7 @@ private:
std::queue<PendingTransactionId> mPendingTransactionIds;
uint32_t mWrEpoch;
uint32_t mIdNameSpace;
wr::IdNamespace mIdNamespace;
bool mPaused;
bool mDestroyed;

Просмотреть файл

@ -35,7 +35,7 @@ wr::WrImageKey
WebRenderLayer::GenerateImageKey()
{
wr::WrImageKey key;
key.mNamespace.mHandle = WrBridge()->GetNamespace();
key.mNamespace = WrBridge()->GetNamespace();
key.mHandle = WrBridge()->GetNextResourceId();
return key;
}

Просмотреть файл

@ -57,7 +57,7 @@ WebRenderLayerManager::Initialize(PCompositorBridgeChild* aCBChild,
LayoutDeviceIntSize size = mWidget->GetClientSize();
TextureFactoryIdentifier textureFactoryIdentifier;
uint32_t id_namespace;
wr::IdNamespace id_namespace;
PWebRenderBridgeChild* bridge = aCBChild->SendPWebRenderBridgeConstructor(aLayersId,
size,
&textureFactoryIdentifier,

Просмотреть файл

@ -28,6 +28,7 @@ type WrEpoch = Epoch;
/// cbindgen:field-names=[mHandle]
/// cbindgen:derive-lt=true
/// cbindgen:derive-lte=true
/// cbindgen:derive-neq=true
type WrIdNamespace = IdNamespace;
/// cbindgen:field-names=[mNamespace, mHandle]

Просмотреть файл

@ -168,6 +168,9 @@ struct IdNamespace {
bool operator==(const IdNamespace& aOther) const {
return mHandle == aOther.mHandle;
}
bool operator!=(const IdNamespace& aOther) const {
return mHandle != aOther.mHandle;
}
bool operator<(const IdNamespace& aOther) const {
return mHandle < aOther.mHandle;
}

Просмотреть файл

@ -658,11 +658,13 @@ XPCJSRuntime::TraverseAdditionalNativeRoots(nsCycleCollectionNoteRootCallback& c
if (val.isObject() && !JS::ObjectIsMarkedGray(&val.toObject()))
continue;
}
cb.NoteXPCOMRoot(v);
cb.NoteXPCOMRoot(v,
XPCTraceableVariant::NS_CYCLE_COLLECTION_INNERCLASS::GetParticipant());
}
for (XPCRootSetElem* e = mWrappedJSRoots; e ; e = e->GetNextRoot()) {
cb.NoteXPCOMRoot(ToSupports(static_cast<nsXPCWrappedJS*>(e)));
cb.NoteXPCOMRoot(ToSupports(static_cast<nsXPCWrappedJS*>(e)),
nsXPCWrappedJS::NS_CYCLE_COLLECTION_INNERCLASS::GetParticipant());
}
}

Просмотреть файл

@ -22,17 +22,16 @@
#two { background-color: green; }
</style>
<style type="text/css">
/* not a URI token; the unterminated string ends at end of line, so
the brace never matches */
#three { background-color: green; }
/* not a URI token; bad-url token is consumed until the first closing ) */
#foo { background: url(foo"bar) }
#three { background-color: red; }
#three { background-color: green; }
</style>
<style type="text/css">
/* not a URI token; the unterminated string ends at end of line */
/* not a URI token; bad-url token is consumed until the first closing ) */
#four { background-color: green; }
#foo { background: url(foo"bar) }
) }
#four { background-color: green; }
#four { background-color: red; }
</style>
<style type="text/css">
/* not a URI token; the unterminated string ends at end of line, so
@ -68,18 +67,19 @@
#eleven { background: url([) green; }
</style>
<style type="text/css">
/* not a URI token; brace matching should work only after invalid URI token */
#twelve { background: url(}{""{)}); background-color: green; }
/* not a URI token; bad-url token is consumed until the first closing )
so the brace immediately after it closes the declaration block */
#twelve { background-color: green; }
#twelve { background: url(}{""{)}); background-color: red; }
</style>
<style type="text/css">
/* invalid URI token absorbs the [ */
#thirteen { background: url([""); background-color: green; }
</style>
<style type="text/css">
/* not a URI token; the opening ( is never matched */
#fourteen { background-color: green; }
/* not a URI token; bad-url token is consumed until the first closing ) */
#foo { background: url(() }
#fourteen { background-color: red; }
#fourteen { background-color: green; }
</style>
<!-- The next three tests test that invalid URI tokens absorb [ and { -->
<style type="text/css">

Просмотреть файл

@ -1,5 +1,5 @@
== at-rule-013.html at-rule-013-ref.html
fails-if(styloVsGecko||stylo) == invalid-url-handling.xhtml invalid-url-handling-ref.xhtml # bug 1383075
== invalid-url-handling.xhtml invalid-url-handling-ref.xhtml
== pseudo-elements-1.html pseudo-elements-1-ref.html
== invalid-attr-1.html invalid-attr-1-ref.html
== at-rule-error-handling-import-1.html at-rule-error-handling-ref.html

Просмотреть файл

@ -2730,20 +2730,32 @@ Gecko_ReportUnexpectedCSSError(ErrorReporter* reporter,
const char* message,
const char* param,
uint32_t paramLen,
const char* prefix,
const char* prefixParam,
uint32_t prefixParamLen,
const char* suffix,
const char* source,
uint32_t sourceLen,
uint32_t lineNumber,
uint32_t colNumber,
nsIURI* uri,
const char* followup)
uint32_t colNumber)
{
MOZ_ASSERT(NS_IsMainThread());
if (prefix) {
if (prefixParam) {
nsDependentCSubstring paramValue(prefixParam, prefixParamLen);
nsAutoString wideParam = NS_ConvertUTF8toUTF16(paramValue);
reporter->ReportUnexpectedUnescaped(prefix, wideParam);
} else {
reporter->ReportUnexpected(prefix);
}
}
nsDependentCSubstring paramValue(param, paramLen);
nsAutoString wideParam = NS_ConvertUTF8toUTF16(paramValue);
reporter->ReportUnexpectedUnescaped(message, wideParam);
if (followup) {
reporter->ReportUnexpected(followup);
if (suffix) {
reporter->ReportUnexpected(suffix);
}
nsDependentCSubstring sourceValue(source, sourceLen);
reporter->OutputError(lineNumber, colNumber, sourceValue);

Просмотреть файл

@ -680,12 +680,14 @@ void Gecko_ReportUnexpectedCSSError(mozilla::css::ErrorReporter* reporter,
const char* message,
const char* param,
uint32_t paramLen,
const char* prefix,
const char* prefixParam,
uint32_t prefixParamLen,
const char* suffix,
const char* source,
uint32_t sourceLen,
uint32_t lineNumber,
uint32_t colNumber,
nsIURI* aURI,
const char* followup);
uint32_t colNumber);
} // extern "C"

Просмотреть файл

@ -1165,6 +1165,7 @@ nsCSSScanner::NextURL(nsCSSToken& aToken)
// aToken.mIdent may be "url" at this point; clear that out
aToken.mIdent.Truncate();
bool hasString = false;
int32_t ch = Peek();
// Do we have a string?
if (ch == '"' || ch == '\'') {
@ -1174,7 +1175,7 @@ nsCSSScanner::NextURL(nsCSSToken& aToken)
return;
}
MOZ_ASSERT(aToken.mType == eCSSToken_String, "unexpected token type");
hasString = true;
} else {
// Otherwise, this is the start of a non-quoted url (which may be empty).
aToken.mSymbol = char16_t(0);
@ -1194,6 +1195,25 @@ nsCSSScanner::NextURL(nsCSSToken& aToken)
} else {
mSeenBadToken = true;
aToken.mType = eCSSToken_Bad_URL;
if (!hasString) {
// Consume until before the next right parenthesis, which follows
// how <bad-url-token> is consumed in CSS Syntax 3 spec.
// Note that, we only do this when "url(" is not followed by a
// string, because in the spec, "url(" followed by a string is
// handled as a url function rather than a <url-token>, so the
// rest of content before ")" should be consumed in balance,
// which will be done by the parser.
// The closing ")" is not consumed here. It is left to the parser
// so that the parser can handle both cases.
do {
if (IsVertSpace(ch)) {
AdvanceLine();
} else {
Advance();
}
ch = Peek();
} while (ch >= 0 && ch != ')');
}
}
}

Просмотреть файл

@ -55,8 +55,7 @@ var LEX_TESTS = [
["url:http://example.com"]],
// In CSS Level 3, this is an ordinary URL, not a BAD_URL.
["url(http://example.com", ["url:http://example.com"]],
// See bug 1153981 to understand why this gets a SYMBOL token.
["url(http://example.com @", ["bad_url:http://example.com", "symbol:@"]],
["url(http://example.com @", ["bad_url:http://example.com"]],
["quo\\ting", ["ident:quoting"]],
["'bad string\n", ["bad_string:bad string", "whitespace"]],
["~=", ["includes"]],

Просмотреть файл

@ -5414,7 +5414,7 @@ pref("browser.safebrowsing.provider.mozilla.nextupdatetime", "1");
pref("browser.safebrowsing.provider.mozilla.lists.base.name", "mozstdName");
pref("browser.safebrowsing.provider.mozilla.lists.base.description", "mozstdDesc");
pref("browser.safebrowsing.provider.mozilla.lists.content.name", "mozfullName");
pref("browser.safebrowsing.provider.mozilla.lists.content.description", "mozfullDesc");
pref("browser.safebrowsing.provider.mozilla.lists.content.description", "mozfullDesc2");
pref("urlclassifier.flashAllowTable", "allow-flashallow-digest256");
pref("urlclassifier.flashAllowExceptTable", "except-flashallow-digest256");

Просмотреть файл

@ -54,6 +54,7 @@
#include "nsSocketTransportService2.h"
#include "nsStreamUtils.h"
#include "nsThreadUtils.h"
#include "nsCORSListenerProxy.h"
#ifdef MOZ_TASK_TRACER
#include "GeckoTaskTracer.h"
@ -3598,5 +3599,22 @@ HttpChannelChild::ActorDestroy(ActorDestroyReason aWhy)
}
}
mozilla::ipc::IPCResult
HttpChannelChild::RecvLogBlockedCORSRequest(const nsString& aMessage)
{
Unused << LogBlockedCORSRequest(aMessage);
return IPC_OK();
}
NS_IMETHODIMP
HttpChannelChild::LogBlockedCORSRequest(const nsAString & aMessage)
{
if (mLoadInfo) {
uint64_t innerWindowID = mLoadInfo->GetInnerWindowID();
nsCORSListenerProxy::LogBlockedCORSRequest(innerWindowID, aMessage);
}
return NS_OK;
}
} // namespace net
} // namespace mozilla

Просмотреть файл

@ -179,6 +179,9 @@ protected:
// Get event target for processing network events.
already_AddRefed<nsIEventTarget> GetNeckoTarget() override;
virtual mozilla::ipc::IPCResult RecvLogBlockedCORSRequest(const nsString& aMessage) override;
NS_IMETHOD LogBlockedCORSRequest(const nsAString & aMessage) override;
private:
// this section is for main-thread-only object
// all the references need to be proxy released on main thread.

Просмотреть файл

@ -232,6 +232,12 @@ HttpChannelParent::CleanupBackgroundChannel()
return;
}
// The nsHttpChannel may have a reference to this parent, release it
// to avoid circular references.
if (mChannel) {
mChannel->SetWarningReporter(nullptr);
}
if (!mPromise.IsEmpty()) {
mRequest.DisconnectIfExists();
mPromise.Reject(NS_ERROR_FAILURE, __func__);
@ -805,6 +811,8 @@ HttpChannelParent::ConnectChannel(const uint32_t& registrarId, const bool& shoul
return true;
}
mChannel->SetWarningReporter(this);
nsCOMPtr<nsINetworkInterceptController> controller;
NS_QueryNotificationCallbacks(channel, controller);
RefPtr<HttpChannelParentListener> parentListener = do_QueryObject(controller);
@ -1544,6 +1552,8 @@ HttpChannelParent::OnStopRequest(nsIRequest *aRequest,
mChannel->GetCacheReadStart(&timing.cacheReadStart);
mChannel->GetCacheReadEnd(&timing.cacheReadEnd);
mChannel->SetWarningReporter(nullptr);
// Either IPC channel is closed or background channel
// is ready to send OnStopRequest.
MOZ_ASSERT(mIPCClosed || mBgParent);
@ -2227,5 +2237,15 @@ HttpChannelParent::DoSendSetPriority(int16_t aValue)
}
}
nsresult
HttpChannelParent::LogBlockedCORSRequest(const nsAString& aMessage)
{
if (mIPCClosed ||
NS_WARN_IF(!SendLogBlockedCORSRequest(nsString(aMessage)))) {
return NS_ERROR_UNEXPECTED;
}
return NS_OK;
}
} // namespace net
} // namespace mozilla

Просмотреть файл

@ -214,6 +214,7 @@ protected:
MOZ_MUST_USE nsresult
ReportSecurityMessage(const nsAString& aMessageTag,
const nsAString& aMessageCategory) override;
nsresult LogBlockedCORSRequest(const nsAString& aMessage) override;
// Calls SendDeleteSelf and sets mIPCClosed to true because we should not
// send any more messages after that. Bug 1274886

Просмотреть файл

@ -854,6 +854,12 @@ NullHttpChannel::SetIsMainDocumentChannel(bool aValue)
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
NullHttpChannel::LogBlockedCORSRequest(const nsAString& aMessage)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
#define IMPL_TIMING_ATTR(name) \
NS_IMETHODIMP \
NullHttpChannel::Get##name##Time(PRTime* _retval) { \

Просмотреть файл

@ -141,6 +141,11 @@ child:
// Tell the child to issue a deprecation warning.
async IssueDeprecationWarning(uint32_t warning, bool asError);
// When CORS blocks the request in the parent process, it doesn't have the
// correct window ID, so send the message to the child for logging to the web
// console.
async LogBlockedCORSRequest(nsString message);
both:
// After receiving this message, the parent also calls
// SendFinishInterceptedRedirect, and makes sure not to send any more messages

Просмотреть файл

@ -42,8 +42,10 @@
#include "NullPrincipal.h"
#include "nsICorsPreflightCallback.h"
#include "nsISupportsImpl.h"
#include "nsHttpChannel.h"
#include "mozilla/LoadInfo.h"
#include "nsIHttpHeaderVisitor.h"
#include "nsQueryObject.h"
#include <algorithm>
using namespace mozilla;
@ -56,24 +58,11 @@ static bool gDisableCORSPrivateData = false;
static void
LogBlockedRequest(nsIRequest* aRequest,
const char* aProperty,
const char16_t* aParam)
const char16_t* aParam,
nsIHttpChannel* aCreatingChannel)
{
nsresult rv = NS_OK;
// Build the error object and log it to the console
nsCOMPtr<nsIConsoleService> console(do_GetService(NS_CONSOLESERVICE_CONTRACTID, &rv));
if (NS_FAILED(rv)) {
NS_WARNING("Failed to log blocked cross-site request (no console)");
return;
}
nsCOMPtr<nsIScriptError> scriptError =
do_CreateInstance(NS_SCRIPTERROR_CONTRACTID, &rv);
if (NS_FAILED(rv)) {
NS_WARNING("Failed to log blocked cross-site request (no scriptError)");
return;
}
nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
nsCOMPtr<nsIURI> aUri;
channel->GetURI(getter_AddRefs(aUri));
@ -98,34 +87,19 @@ LogBlockedRequest(nsIRequest* aRequest,
nsAutoString msg(blockedMessage.get());
// query innerWindowID and log to web console, otherwise log to
// the error to the browser console.
uint64_t innerWindowID = nsContentUtils::GetInnerWindowID(aRequest);
if (XRE_IsParentProcess()) {
if (aCreatingChannel) {
rv = aCreatingChannel->LogBlockedCORSRequest(msg);
if (NS_SUCCEEDED(rv)) {
return;
}
}
NS_WARNING("Failed to log blocked cross-site request to web console from parent->child, falling back to browser console");
}
if (innerWindowID > 0) {
rv = scriptError->InitWithWindowID(msg,
EmptyString(), // sourceName
EmptyString(), // sourceLine
0, // lineNumber
0, // columnNumber
nsIScriptError::warningFlag,
"CORS",
innerWindowID);
}
else {
rv = scriptError->Init(msg,
EmptyString(), // sourceName
EmptyString(), // sourceLine
0, // lineNumber
0, // columnNumber
nsIScriptError::warningFlag,
"CORS");
}
if (NS_FAILED(rv)) {
NS_WARNING("Failed to log blocked cross-site request (scriptError init failed)");
return;
}
console->LogMessage(scriptError);
// log message ourselves
uint64_t innerWindowID = nsContentUtils::GetInnerWindowID(aRequest);
nsCORSListenerProxy::LogBlockedCORSRequest(innerWindowID, msg);
}
//////////////////////////////////////////////////////////////////////////
@ -451,6 +425,7 @@ nsCORSListenerProxy::Init(nsIChannel* aChannel, DataURIHandling aAllowDataURI)
mRequestingPrincipal = nullptr;
mOriginHeaderPrincipal = nullptr;
mOuterNotificationCallbacks = nullptr;
mHttpChannel = nullptr;
}
#ifdef DEBUG
mInited = true;
@ -540,9 +515,11 @@ nsCORSListenerProxy::CheckRequestApproved(nsIRequest* aRequest)
if (!mHasBeenCrossSite) {
return NS_OK;
}
nsCOMPtr<nsIHttpChannel> topChannel;
topChannel.swap(mHttpChannel);
if (gDisableCORS) {
LogBlockedRequest(aRequest, "CORSDisabled", nullptr);
LogBlockedRequest(aRequest, "CORSDisabled", nullptr, topChannel);
return NS_ERROR_DOM_BAD_URI;
}
@ -560,7 +537,7 @@ nsCORSListenerProxy::CheckRequestApproved(nsIRequest* aRequest)
// Test that things worked on a HTTP level
nsCOMPtr<nsIHttpChannel> http = do_QueryInterface(aRequest);
if (!http) {
LogBlockedRequest(aRequest, "CORSRequestNotHttp", nullptr);
LogBlockedRequest(aRequest, "CORSRequestNotHttp", nullptr, topChannel);
return NS_ERROR_DOM_BAD_URI;
}
@ -582,14 +559,14 @@ nsCORSListenerProxy::CheckRequestApproved(nsIRequest* aRequest)
// check for duplicate headers
rv = http->VisitOriginalResponseHeaders(visitor);
if (NS_FAILED(rv)) {
LogBlockedRequest(aRequest, "CORSAllowOriginNotMatchingOrigin", nullptr);
LogBlockedRequest(aRequest, "CORSAllowOriginNotMatchingOrigin", nullptr, topChannel);
return rv;
}
rv = http->GetResponseHeader(
NS_LITERAL_CSTRING("Access-Control-Allow-Origin"), allowedOriginHeader);
if (NS_FAILED(rv)) {
LogBlockedRequest(aRequest, "CORSMissingAllowOrigin", nullptr);
LogBlockedRequest(aRequest, "CORSMissingAllowOrigin", nullptr, topChannel);
return rv;
}
@ -602,7 +579,7 @@ nsCORSListenerProxy::CheckRequestApproved(nsIRequest* aRequest)
// below since "if (A && B)" is included in "if (A || !B)".
//
if (mWithCredentials && allowedOriginHeader.EqualsLiteral("*")) {
LogBlockedRequest(aRequest, "CORSNotSupportingCredentials", nullptr);
LogBlockedRequest(aRequest, "CORSNotSupportingCredentials", nullptr, topChannel);
return NS_ERROR_DOM_BAD_URI;
}
@ -613,7 +590,7 @@ nsCORSListenerProxy::CheckRequestApproved(nsIRequest* aRequest)
if (!allowedOriginHeader.Equals(origin)) {
LogBlockedRequest(aRequest, "CORSAllowOriginNotMatchingOrigin",
NS_ConvertUTF8toUTF16(allowedOriginHeader).get());
NS_ConvertUTF8toUTF16(allowedOriginHeader).get(), topChannel);
return NS_ERROR_DOM_BAD_URI;
}
}
@ -625,7 +602,7 @@ nsCORSListenerProxy::CheckRequestApproved(nsIRequest* aRequest)
NS_LITERAL_CSTRING("Access-Control-Allow-Credentials"), allowCredentialsHeader);
if (!allowCredentialsHeader.EqualsLiteral("true")) {
LogBlockedRequest(aRequest, "CORSMissingAllowCredentials", nullptr);
LogBlockedRequest(aRequest, "CORSMissingAllowCredentials", nullptr, topChannel);
return NS_ERROR_DOM_BAD_URI;
}
}
@ -642,6 +619,7 @@ nsCORSListenerProxy::OnStopRequest(nsIRequest* aRequest,
nsresult rv = mOuterListener->OnStopRequest(aRequest, aContext, aStatusCode);
mOuterListener = nullptr;
mOuterNotificationCallbacks = nullptr;
mHttpChannel = nullptr;
return rv;
}
@ -994,6 +972,8 @@ nsCORSListenerProxy::UpdateChannel(nsIChannel* aChannel,
NS_ENSURE_SUCCESS(rv, rv);
}
mHttpChannel = http;
return NS_OK;
}
@ -1310,11 +1290,12 @@ nsCORSPreflightListener::CheckPreflightRequestApproved(nsIRequest* aRequest)
nsCOMPtr<nsIHttpChannel> http = do_QueryInterface(aRequest);
nsCOMPtr<nsIHttpChannelInternal> internal = do_QueryInterface(aRequest);
NS_ENSURE_STATE(internal);
nsCOMPtr<nsIHttpChannel> parentHttpChannel = do_QueryInterface(mCallback);
bool succeedded;
rv = http->GetRequestSucceeded(&succeedded);
if (NS_FAILED(rv) || !succeedded) {
LogBlockedRequest(aRequest, "CORSPreflightDidNotSucceed", nullptr);
LogBlockedRequest(aRequest, "CORSPreflightDidNotSucceed", nullptr, parentHttpChannel);
return NS_ERROR_DOM_BAD_URI;
}
@ -1334,13 +1315,13 @@ nsCORSPreflightListener::CheckPreflightRequestApproved(nsIRequest* aRequest)
}
if (!NS_IsValidHTTPToken(method)) {
LogBlockedRequest(aRequest, "CORSInvalidAllowMethod",
NS_ConvertUTF8toUTF16(method).get());
NS_ConvertUTF8toUTF16(method).get(), parentHttpChannel);
return NS_ERROR_DOM_BAD_URI;
}
foundMethod |= mPreflightMethod.Equals(method);
}
if (!foundMethod) {
LogBlockedRequest(aRequest, "CORSMethodNotFound", nullptr);
LogBlockedRequest(aRequest, "CORSMethodNotFound", nullptr, parentHttpChannel);
return NS_ERROR_DOM_BAD_URI;
}
@ -1357,7 +1338,7 @@ nsCORSPreflightListener::CheckPreflightRequestApproved(nsIRequest* aRequest)
}
if (!NS_IsValidHTTPToken(header)) {
LogBlockedRequest(aRequest, "CORSInvalidAllowHeader",
NS_ConvertUTF8toUTF16(header).get());
NS_ConvertUTF8toUTF16(header).get(), parentHttpChannel);
return NS_ERROR_DOM_BAD_URI;
}
headers.AppendElement(header);
@ -1366,7 +1347,7 @@ nsCORSPreflightListener::CheckPreflightRequestApproved(nsIRequest* aRequest)
if (!headers.Contains(mPreflightHeaders[i],
nsCaseInsensitiveCStringArrayComparator())) {
LogBlockedRequest(aRequest, "CORSMissingAllowHeaderFromPreflight",
NS_ConvertUTF8toUTF16(mPreflightHeaders[i]).get());
NS_ConvertUTF8toUTF16(mPreflightHeaders[i]).get(), parentHttpChannel);
return NS_ERROR_DOM_BAD_URI;
}
}
@ -1396,6 +1377,7 @@ nsCORSListenerProxy::RemoveFromCorsPreflightCache(nsIURI* aURI,
}
}
// static
nsresult
nsCORSListenerProxy::StartCORSPreflight(nsIChannel* aRequestChannel,
nsICorsPreflightCallback* aCallback,
@ -1405,7 +1387,8 @@ nsCORSListenerProxy::StartCORSPreflight(nsIChannel* aRequestChannel,
*aPreflightChannel = nullptr;
if (gDisableCORS) {
LogBlockedRequest(aRequestChannel, "CORSDisabled", nullptr);
nsCOMPtr<nsIHttpChannel> http = do_QueryInterface(aRequestChannel);
LogBlockedRequest(aRequestChannel, "CORSDisabled", nullptr, http);
return NS_ERROR_DOM_BAD_URI;
}
@ -1501,6 +1484,13 @@ nsCORSListenerProxy::StartCORSPreflight(nsIChannel* aRequestChannel,
method, false);
NS_ENSURE_SUCCESS(rv, rv);
// Set the CORS preflight channel's warning reporter to be the same as the
// requesting channel so that all log messages are able to be reported through
// the warning reporter.
RefPtr<nsHttpChannel> reqCh = do_QueryObject(aRequestChannel);
RefPtr<nsHttpChannel> preCh = do_QueryObject(preHttp);
preCh->SetWarningReporter(reqCh->GetWarningReporter());
nsTArray<nsCString> preflightHeaders;
if (!aUnsafeHeaders.IsEmpty()) {
for (uint32_t i = 0; i < aUnsafeHeaders.Length(); ++i) {
@ -1538,3 +1528,52 @@ nsCORSListenerProxy::StartCORSPreflight(nsIChannel* aRequestChannel,
return NS_OK;
}
// static
void
nsCORSListenerProxy::LogBlockedCORSRequest(uint64_t aInnerWindowID,
const nsAString& aMessage)
{
nsresult rv = NS_OK;
// Build the error object and log it to the console
nsCOMPtr<nsIConsoleService> console(do_GetService(NS_CONSOLESERVICE_CONTRACTID, &rv));
if (NS_FAILED(rv)) {
NS_WARNING("Failed to log blocked cross-site request (no console)");
return;
}
nsCOMPtr<nsIScriptError> scriptError =
do_CreateInstance(NS_SCRIPTERROR_CONTRACTID, &rv);
if (NS_FAILED(rv)) {
NS_WARNING("Failed to log blocked cross-site request (no scriptError)");
return;
}
// query innerWindowID and log to web console, otherwise log to
// the error to the browser console.
if (aInnerWindowID > 0) {
rv = scriptError->InitWithWindowID(aMessage,
EmptyString(), // sourceName
EmptyString(), // sourceLine
0, // lineNumber
0, // columnNumber
nsIScriptError::warningFlag,
"CORS",
aInnerWindowID);
}
else {
rv = scriptError->Init(aMessage,
EmptyString(), // sourceName
EmptyString(), // sourceLine
0, // lineNumber
0, // columnNumber
nsIScriptError::warningFlag,
"CORS");
}
if (NS_FAILED(rv)) {
NS_WARNING("Failed to log blocked cross-site request (scriptError init failed)");
return;
}
console->LogMessage(scriptError);
}

Просмотреть файл

@ -70,6 +70,10 @@ public:
void SetInterceptController(nsINetworkInterceptController* aInterceptController);
// When CORS blocks a request, log the message to the web console, or the
// browser console if no valid inner window ID is found.
static void LogBlockedCORSRequest(uint64_t aInnerWindowID,
const nsAString& aMessage);
private:
// Only HttpChannelParent can call RemoveFromCorsPreflightCache
friend class mozilla::net::HttpChannelParent;
@ -108,6 +112,10 @@ private:
// an http: request to https: in nsHttpChannel::Connect() and hence
// a request might not be marked as cross site request based on that promise.
bool mHasBeenCrossSite;
// Under e10s, logging happens in the child process. Keep a reference to the
// creator nsIHttpChannel in order to find the way back to the child. Released
// in OnStopRequest().
nsCOMPtr<nsIHttpChannel> mHttpChannel;
#ifdef DEBUG
bool mInited;
#endif

Просмотреть файл

@ -416,6 +416,15 @@ nsHttpChannel::AddSecurityMessage(const nsAString& aMessageTag,
aMessageCategory);
}
NS_IMETHODIMP
nsHttpChannel::LogBlockedCORSRequest(const nsAString& aMessage)
{
if (mWarningReporter) {
return mWarningReporter->LogBlockedCORSRequest(aMessage);
}
return NS_ERROR_UNEXPECTED;
}
//-----------------------------------------------------------------------------
// nsHttpChannel <private>
//-----------------------------------------------------------------------------
@ -858,6 +867,7 @@ nsHttpChannel::ReleaseListeners()
{
HttpBaseChannel::ReleaseListeners();
mChannelClassifier = nullptr;
mWarningReporter = nullptr;
}
void
@ -5922,6 +5932,7 @@ nsHttpChannel::Cancel(nsresult status)
LOG((" ignoring; already canceled\n"));
return NS_OK;
}
if (mWaitingForRedirectCallback) {
LOG(("channel canceled during wait for redirect callback"));
}
@ -9250,5 +9261,19 @@ nsHttpChannel::Notify(nsITimer *aTimer)
return NS_OK;
}
void
nsHttpChannel::SetWarningReporter(HttpChannelSecurityWarningReporter *aReporter)
{
LOG(("nsHttpChannel [this=%p] SetWarningReporter [%p]", this, aReporter));
mWarningReporter = aReporter;
}
HttpChannelSecurityWarningReporter*
nsHttpChannel::GetWarningReporter()
{
LOG(("nsHttpChannel [this=%p] GetWarningReporter [%p]", this, mWarningReporter.get()));
return mWarningReporter.get();
}
} // namespace net
} // namespace mozilla

Просмотреть файл

@ -43,12 +43,13 @@ namespace mozilla { namespace net {
class nsChannelClassifier;
class Http2PushedStream;
class HttpChannelSecurityWarningReporter
class HttpChannelSecurityWarningReporter : public nsISupports
{
public:
virtual MOZ_MUST_USE nsresult
ReportSecurityMessage(const nsAString& aMessageTag,
const nsAString& aMessageCategory) = 0;
virtual nsresult LogBlockedCORSRequest(const nsAString& aMessage) = 0;
};
//-----------------------------------------------------------------------------
@ -190,10 +191,10 @@ public:
MOZ_MUST_USE nsresult
AddSecurityMessage(const nsAString& aMessageTag,
const nsAString& aMessageCategory) override;
NS_IMETHOD LogBlockedCORSRequest(const nsAString& aMessage) override;
void SetWarningReporter(HttpChannelSecurityWarningReporter* aReporter)
{ mWarningReporter = aReporter; }
void SetWarningReporter(HttpChannelSecurityWarningReporter *aReporter);
HttpChannelSecurityWarningReporter* GetWarningReporter();
public: /* internal necko use only */
using InitLocalBlockListCallback = std::function<void(bool)>;
@ -672,7 +673,7 @@ private:
nsCString mUsername;
// If non-null, warnings should be reported to this object.
HttpChannelSecurityWarningReporter* mWarningReporter;
RefPtr<HttpChannelSecurityWarningReporter> mWarningReporter;
RefPtr<ADivertableParentChannel> mParentChannel;

Просмотреть файл

@ -478,4 +478,14 @@ interface nsIHttpChannel : nsIChannel
* Don't alter it otherwise.
*/
[must_use] attribute uint64_t topLevelOuterContentWindowId;
/**
* In e10s, the information that the CORS response blocks the load is in the
* parent, which doesn't know the true window id of the request, so we may
* need to proxy the request to the child.
*
* @param aMessage
* The message to print in the console.
*/
void logBlockedCORSRequest(in AString aMessage);
};

Просмотреть файл

@ -1044,3 +1044,13 @@ nsViewSourceChannel::SetCorsPreflightParameters(const nsTArray<nsCString>& aUnsa
{
mHttpChannelInternal->SetCorsPreflightParameters(aUnsafeHeaders);
}
NS_IMETHODIMP
nsViewSourceChannel::LogBlockedCORSRequest(const nsAString& aMessage)
{
if (!mHttpChannel) {
NS_WARNING("nsViewSourceChannel::LogBlockedCORSRequest mHttpChannel is null");
return NS_ERROR_UNEXPECTED;
}
return mHttpChannel->LogBlockedCORSRequest(aMessage);
}

Просмотреть файл

@ -111,7 +111,10 @@ class BookmarkRepairRequestor extends CollectionRepairRequestor {
// that tests have a slightly easier time, hence the `|| []` in each loop.
// Missing children records when the parent exists but a child doesn't.
for (let { child } of validationInfo.problems.missingChildren || []) {
for (let { parent, child } of validationInfo.problems.missingChildren || []) {
// We can't be sure if the child is missing or our copy of the parent is
// wrong, so request both
ids.add(parent);
ids.add(child);
}
if (ids.size > MAX_REQUESTED_IDS) {
@ -130,18 +133,22 @@ class BookmarkRepairRequestor extends CollectionRepairRequestor {
return ids; // might as well give up here - we aren't going to repair.
}
// Entries where we have the parent but know for certain that the child was
// deleted.
for (let { parent } of validationInfo.problems.deletedChildren || []) {
// Entries where we have the parent but we have a record from the server that
// claims the child was deleted.
for (let { parent, child } of validationInfo.problems.deletedChildren || []) {
// Request both, since we don't know if it's a botched deletion or revival
ids.add(parent);
ids.add(child);
}
if (ids.size > MAX_REQUESTED_IDS) {
return ids; // might as well give up here - we aren't going to repair.
}
// Entries where the child references a parent that we don't have, but we
// know why: the parent was deleted.
for (let { child } of validationInfo.problems.deletedParents || []) {
// have a record from the server that claims the parent was deleted.
for (let { parent, child } of validationInfo.problems.deletedParents || []) {
// Request both, since we don't know if it's a botched deletion or revival
ids.add(parent);
ids.add(child);
}
if (ids.size > MAX_REQUESTED_IDS) {
@ -169,7 +176,6 @@ class BookmarkRepairRequestor extends CollectionRepairRequestor {
ids.add(child);
}
// XXX - any others we should consider?
return ids;
}

Просмотреть файл

@ -163,7 +163,7 @@ add_task(async function test_bookmark_repair_integration() {
value: undefined,
extra: {
flowID,
numIDs: "1",
numIDs: "2",
},
}, {
object: "sendcommand",
@ -180,7 +180,7 @@ add_task(async function test_bookmark_repair_integration() {
extra: {
deviceID: Service.identity.hashedDeviceID(remoteID),
flowID,
numIDs: "1",
numIDs: "2",
},
}], "Should record telemetry events for repair request");
@ -225,7 +225,7 @@ add_task(async function test_bookmark_repair_integration() {
value: undefined,
extra: {
flowID,
numIDs: "1",
numIDs: "2",
},
}, {
object: "sendcommand",
@ -241,7 +241,7 @@ add_task(async function test_bookmark_repair_integration() {
value: undefined,
extra: {
flowID,
numIDs: "1",
numIDs: "2",
}
}], "Should record telemetry events for repair response");
@ -290,7 +290,7 @@ add_task(async function test_bookmark_repair_integration() {
extra: {
flowID,
deviceID: Service.identity.hashedDeviceID(remoteID),
numIDs: "1",
numIDs: "2",
},
}, {
object: "repair",

Просмотреть файл

@ -105,12 +105,12 @@ add_task(async function test_requestor_no_clients() {
{ object: "repair",
method: "started",
value: undefined,
extra: { flowID, numIDs: 3 },
extra: { flowID, numIDs: 4 },
},
{ object: "repair",
method: "finished",
value: undefined,
extra: { flowID, numIDs: 3 },
extra: { flowID, numIDs: 4 },
}
]);
});
@ -156,22 +156,22 @@ add_task(async function test_requestor_one_client_no_response() {
{ object: "repair",
method: "started",
value: undefined,
extra: { flowID, numIDs: 3 },
extra: { flowID, numIDs: 4 },
},
{ object: "repair",
method: "request",
value: "upload",
extra: { flowID, numIDs: 3, deviceID: "client-a" },
extra: { flowID, numIDs: 4, deviceID: "client-a" },
},
{ object: "repair",
method: "request",
value: "upload",
extra: { flowID, numIDs: 3, deviceID: "client-a" },
extra: { flowID, numIDs: 4, deviceID: "client-a" },
},
{ object: "repair",
method: "finished",
value: undefined,
extra: { flowID, numIDs: 3 },
extra: { flowID, numIDs: 4 },
}
]);
});
@ -208,12 +208,12 @@ add_task(async function test_requestor_one_client_no_sync() {
{ object: "repair",
method: "started",
value: undefined,
extra: { flowID, numIDs: 3 },
extra: { flowID, numIDs: 4 },
},
{ object: "repair",
method: "request",
value: "upload",
extra: { flowID, numIDs: 3, deviceID: "client-a" },
extra: { flowID, numIDs: 4, deviceID: "client-a" },
},
{ object: "repair",
method: "abandon",
@ -223,7 +223,7 @@ add_task(async function test_requestor_one_client_no_sync() {
{ object: "repair",
method: "finished",
value: undefined,
extra: { flowID, numIDs: 3 },
extra: { flowID, numIDs: 4 },
}
]);
});
@ -288,7 +288,7 @@ add_task(async function test_requestor_client_vanishes() {
request: "upload",
flowID: requestor._flowID,
clientID: "client-b",
ids: ["a", "b", "c"],
ids: ["a", "b", "c", "x"],
}
await requestor.continueRepairs(response);
@ -298,12 +298,12 @@ add_task(async function test_requestor_client_vanishes() {
{ object: "repair",
method: "started",
value: undefined,
extra: { flowID, numIDs: 3 },
extra: { flowID, numIDs: 4 },
},
{ object: "repair",
method: "request",
value: "upload",
extra: { flowID, numIDs: 3, deviceID: "client-a" },
extra: { flowID, numIDs: 4, deviceID: "client-a" },
},
{ object: "repair",
method: "abandon",
@ -313,12 +313,12 @@ add_task(async function test_requestor_client_vanishes() {
{ object: "repair",
method: "request",
value: "upload",
extra: { flowID, numIDs: 3, deviceID: "client-b" },
extra: { flowID, numIDs: 4, deviceID: "client-b" },
},
{ object: "repair",
method: "response",
value: "upload",
extra: { flowID, deviceID: "client-b", numIDs: 3 },
extra: { flowID, deviceID: "client-b", numIDs: 4 },
},
{ object: "repair",
method: "finished",
@ -371,7 +371,7 @@ add_task(async function test_requestor_success_responses() {
request: "upload",
clientID: "client-b",
flowID: requestor._flowID,
ids: ["c"],
ids: ["c", "x"],
}
await requestor.continueRepairs(response);
@ -381,12 +381,12 @@ add_task(async function test_requestor_success_responses() {
{ object: "repair",
method: "started",
value: undefined,
extra: { flowID, numIDs: 3 },
extra: { flowID, numIDs: 4 },
},
{ object: "repair",
method: "request",
value: "upload",
extra: { flowID, numIDs: 3, deviceID: "client-a" },
extra: { flowID, numIDs: 4, deviceID: "client-a" },
},
{ object: "repair",
method: "response",
@ -396,12 +396,12 @@ add_task(async function test_requestor_success_responses() {
{ object: "repair",
method: "request",
value: "upload",
extra: { flowID, numIDs: 1, deviceID: "client-b" },
extra: { flowID, numIDs: 2, deviceID: "client-b" },
},
{ object: "repair",
method: "response",
value: "upload",
extra: { flowID, deviceID: "client-b", numIDs: 1 },
extra: { flowID, deviceID: "client-b", numIDs: 2 },
},
{ object: "repair",
method: "finished",
@ -496,17 +496,17 @@ add_task(async function test_requestor_already_repairing_continue() {
{ method: "started",
object: "repair",
value: undefined,
extra: { flowID, numIDs: "3" },
extra: { flowID, numIDs: "4" },
},
{ method: "request",
object: "repair",
value: "upload",
extra: { flowID, numIDs: "3", deviceID: "client-a" },
extra: { flowID, numIDs: "4", deviceID: "client-a" },
},
{ method: "aborted",
object: "repair",
value: undefined,
extra: { flowID, numIDs: "3", reason: "other clients repairing" },
extra: { flowID, numIDs: "4", reason: "other clients repairing" },
}
];

Просмотреть файл

@ -2881,10 +2881,15 @@ extern "C" {
param:
*const ::std::os::raw::c_char,
paramLen: u32,
prefix:
*const ::std::os::raw::c_char,
prefixParam:
*const ::std::os::raw::c_char,
prefixParamLen: u32,
suffix:
*const ::std::os::raw::c_char,
source:
*const ::std::os::raw::c_char,
sourceLen: u32, lineNumber: u32,
colNumber: u32, aURI: *mut nsIURI,
followup:
*const ::std::os::raw::c_char);
colNumber: u32);
}

Просмотреть файл

@ -38,7 +38,7 @@ use selectors::parser::SelectorParseError;
#[cfg(feature = "servo")] use servo_config::prefs::PREFS;
use shared_lock::StylesheetGuards;
use style_traits::{PARSING_MODE_DEFAULT, HasViewportPercentage, ToCss, ParseError};
use style_traits::{PropertyDeclarationParseError, StyleParseError};
use style_traits::{PropertyDeclarationParseError, StyleParseError, ValueParseError};
use stylesheets::{CssRuleType, MallocSizeOf, MallocSizeOfFn, Origin, UrlExtraData};
#[cfg(feature = "servo")] use values::Either;
use values::generics::text::LineHeight;
@ -1489,7 +1489,8 @@ impl PropertyDeclaration {
Ok(keyword) => DeclaredValueOwned::CSSWideKeyword(keyword),
Err(_) => match ::custom_properties::SpecifiedValue::parse(context, input) {
Ok(value) => DeclaredValueOwned::Value(value),
Err(_) => return Err(PropertyDeclarationParseError::InvalidValue(name.to_string().into())),
Err(e) => return Err(PropertyDeclarationParseError::InvalidValue(name.to_string().into(),
ValueParseError::from_parse_error(e))),
}
};
declarations.push(PropertyDeclaration::Custom(name, value));
@ -1502,13 +1503,14 @@ impl PropertyDeclaration {
input.look_for_var_functions();
let start = input.position();
input.parse_entirely(|input| id.parse_value(context, input))
.or_else(|_| {
.or_else(|err| {
while let Ok(_) = input.next() {} // Look for var() after the error.
if input.seen_var_functions() {
input.reset(start);
let (first_token_type, css) =
::custom_properties::parse_non_custom_with_var(input).map_err(|_| {
PropertyDeclarationParseError::InvalidValue(id.name().into())
::custom_properties::parse_non_custom_with_var(input).map_err(|e| {
PropertyDeclarationParseError::InvalidValue(id.name().into(),
ValueParseError::from_parse_error(e))
})?;
Ok(PropertyDeclaration::WithVariables(id, Arc::new(UnparsedValue {
css: css.into_owned(),
@ -1517,7 +1519,8 @@ impl PropertyDeclaration {
from_shorthand: None,
})))
} else {
Err(PropertyDeclarationParseError::InvalidValue(id.name().into()))
Err(PropertyDeclarationParseError::InvalidValue(id.name().into(),
ValueParseError::from_parse_error(err)))
}
})
}).map(|declaration| {
@ -1539,13 +1542,14 @@ impl PropertyDeclaration {
let start = input.position();
// Not using parse_entirely here: each ${shorthand.ident}::parse_into function
// needs to do so *before* pushing to `declarations`.
id.parse_into(declarations, context, input).or_else(|_| {
id.parse_into(declarations, context, input).or_else(|err| {
while let Ok(_) = input.next() {} // Look for var() after the error.
if input.seen_var_functions() {
input.reset(start);
let (first_token_type, css) =
::custom_properties::parse_non_custom_with_var(input).map_err(|_| {
PropertyDeclarationParseError::InvalidValue(id.name().into())
::custom_properties::parse_non_custom_with_var(input).map_err(|e| {
PropertyDeclarationParseError::InvalidValue(id.name().into(),
ValueParseError::from_parse_error(e))
})?;
let unparsed = Arc::new(UnparsedValue {
css: css.into_owned(),
@ -1564,7 +1568,8 @@ impl PropertyDeclaration {
}
Ok(())
} else {
Err(PropertyDeclarationParseError::InvalidValue(id.name().into()))
Err(PropertyDeclarationParseError::InvalidValue(id.name().into(),
ValueParseError::from_parse_error(err)))
}
})
}

Просмотреть файл

@ -13,7 +13,7 @@ use parser::{ParserContext, Parse};
use properties::longhands::color::SystemColor;
use std::fmt;
use std::io::Write;
use style_traits::{ToCss, ParseError, StyleParseError};
use style_traits::{ToCss, ParseError, StyleParseError, ValueParseError};
use super::AllowQuirks;
use values::computed::{Color as ComputedColor, Context, ToComputedValue};
@ -76,24 +76,28 @@ impl Parse for Color {
_ => None,
};
input.reset(start_position);
if let Ok(value) = input.try(CSSParserColor::parse) {
Ok(match value {
CSSParserColor::CurrentColor => Color::CurrentColor,
CSSParserColor::RGBA(rgba) => Color::Numeric {
parsed: rgba,
authored: authored,
},
})
} else {
#[cfg(feature = "gecko")] {
if let Ok(system) = input.try(SystemColor::parse) {
Ok(Color::System(system))
} else {
gecko::SpecialColorKeyword::parse(input).map(Color::Special)
match input.try(CSSParserColor::parse) {
Ok(value) =>
Ok(match value {
CSSParserColor::CurrentColor => Color::CurrentColor,
CSSParserColor::RGBA(rgba) => Color::Numeric {
parsed: rgba,
authored: authored,
},
}),
Err(e) => {
#[cfg(feature = "gecko")] {
if let Ok(system) = input.try(SystemColor::parse) {
return Ok(Color::System(system));
} else if let Ok(c) = gecko::SpecialColorKeyword::parse(input) {
return Ok(Color::Special(c));
}
}
match e {
BasicParseError::UnexpectedToken(t) =>
Err(StyleParseError::ValueError(ValueParseError::InvalidColor(t)).into()),
e => Err(e.into())
}
}
#[cfg(not(feature = "gecko"))] {
Err(StyleParseError::UnspecifiedError.into())
}
}
}
@ -161,11 +165,13 @@ impl Color {
input: &mut Parser<'i, 't>,
allow_quirks: AllowQuirks)
-> Result<Self, ParseError<'i>> {
input.try(|i| Self::parse(context, i)).or_else(|_| {
input.try(|i| Self::parse(context, i)).or_else(|e| {
if !allow_quirks.allowed(context.quirks_mode) {
return Err(StyleParseError::UnspecifiedError.into());
return Err(e);
}
Color::parse_quirky_color(input).map(|rgba| Color::rgba(rgba))
Color::parse_quirky_color(input)
.map(|rgba| Color::rgba(rgba))
.map_err(|_| e)
})
}

Просмотреть файл

@ -124,10 +124,31 @@ pub enum StyleParseError<'i> {
UnspecifiedError,
/// An unexpected token was found within a namespace rule.
UnexpectedTokenWithinNamespace(Token<'i>),
/// An error was encountered while parsing a property value.
ValueError(ValueParseError<'i>),
}
/// Specific errors that can be encountered while parsing property values.
#[derive(Clone, Debug, PartialEq)]
pub enum ValueParseError<'i> {
/// An invalid token was encountered while parsing a color value.
InvalidColor(Token<'i>),
}
impl<'i> ValueParseError<'i> {
/// Attempt to extract a ValueParseError value from a ParseError.
pub fn from_parse_error(this: ParseError<'i>) -> Option<ValueParseError<'i>> {
match this {
cssparser::ParseError::Custom(
SelectorParseError::Custom(
StyleParseError::ValueError(e))) => Some(e),
_ => None,
}
}
}
/// The result of parsing a property declaration.
#[derive(Eq, PartialEq, Clone, Debug)]
#[derive(PartialEq, Clone, Debug)]
pub enum PropertyDeclarationParseError<'i> {
/// The property declaration was for an unknown property.
UnknownProperty(CowRcStr<'i>),
@ -136,7 +157,7 @@ pub enum PropertyDeclarationParseError<'i> {
/// The property declaration was for a disabled experimental property.
ExperimentalProperty,
/// The property declaration contained an invalid value.
InvalidValue(CowRcStr<'i>),
InvalidValue(CowRcStr<'i>, Option<ValueParseError<'i>>),
/// The declaration contained an animation property, and we were parsing
/// this as a keyframe block (so that property should be ignored).
///

Просмотреть файл

@ -18,7 +18,7 @@ use style::gecko_bindings::structs::ErrorReporter as GeckoErrorReporter;
use style::gecko_bindings::structs::URLExtraData as RawUrlExtraData;
use style::gecko_bindings::sugar::refptr::RefPtr;
use style::stylesheets::UrlExtraData;
use style_traits::{ParseError, StyleParseError, PropertyDeclarationParseError};
use style_traits::{ParseError, StyleParseError, PropertyDeclarationParseError, ValueParseError};
/// Wrapper around an instance of Gecko's CSS error reporter.
pub struct ErrorReporter(*mut GeckoErrorReporter);
@ -194,8 +194,59 @@ enum Action {
trait ErrorHelpers<'a> {
fn error_data(self) -> (CowRcStr<'a>, ParseError<'a>);
fn error_param(self) -> ErrorString<'a>;
fn to_gecko_message(&self) -> (&'static [u8], Action);
fn error_params(self) -> (ErrorString<'a>, Option<ErrorString<'a>>);
fn to_gecko_message(&self) -> (Option<&'static [u8]>, &'static [u8], Action);
}
fn extract_error_param<'a>(err: ParseError<'a>) -> Option<ErrorString<'a>> {
Some(match err {
CssParseError::Basic(BasicParseError::UnexpectedToken(t)) =>
ErrorString::UnexpectedToken(t),
CssParseError::Basic(BasicParseError::AtRuleInvalid(i)) =>
ErrorString::Snippet(format!("@{}", escape_css_ident(&i)).into()),
CssParseError::Custom(SelectorParseError::Custom(
StyleParseError::PropertyDeclaration(
PropertyDeclarationParseError::InvalidValue(property, None)))) =>
ErrorString::Snippet(property),
CssParseError::Custom(SelectorParseError::UnexpectedIdent(ident)) =>
ErrorString::Ident(ident),
CssParseError::Custom(SelectorParseError::ExpectedNamespace(namespace)) =>
ErrorString::Ident(namespace),
CssParseError::Custom(SelectorParseError::Custom(
StyleParseError::PropertyDeclaration(
PropertyDeclarationParseError::UnknownProperty(property)))) =>
ErrorString::Ident(property),
CssParseError::Custom(SelectorParseError::Custom(
StyleParseError::UnexpectedTokenWithinNamespace(token))) =>
ErrorString::UnexpectedToken(token),
_ => return None,
})
}
fn extract_value_error_param<'a>(err: ValueParseError<'a>) -> ErrorString<'a> {
match err {
ValueParseError::InvalidColor(t) => ErrorString::UnexpectedToken(t),
}
}
/// If an error parameter is present in the given error, return it. Additionally return
/// a second parameter if it exists, for use in the prefix for the eventual error message.
fn extract_error_params<'a>(err: ParseError<'a>) -> Option<(ErrorString<'a>, Option<ErrorString<'a>>)> {
match err {
CssParseError::Custom(SelectorParseError::Custom(
StyleParseError::PropertyDeclaration(
PropertyDeclarationParseError::InvalidValue(property, Some(e))))) =>
Some((ErrorString::Snippet(property.into()), Some(extract_value_error_param(e)))),
err => extract_error_param(err).map(|e| (e, None)),
}
}
impl<'a> ErrorHelpers<'a> for ContextualParseError<'a> {
@ -222,40 +273,13 @@ impl<'a> ErrorHelpers<'a> for ContextualParseError<'a> {
}
}
fn error_param(self) -> ErrorString<'a> {
match self.error_data() {
(_, CssParseError::Basic(BasicParseError::UnexpectedToken(t))) =>
ErrorString::UnexpectedToken(t),
(_, CssParseError::Basic(BasicParseError::AtRuleInvalid(i))) =>
ErrorString::Snippet(format!("@{}", escape_css_ident(&i)).into()),
(_, CssParseError::Custom(SelectorParseError::Custom(
StyleParseError::PropertyDeclaration(
PropertyDeclarationParseError::InvalidValue(property))))) =>
ErrorString::Snippet(property),
(_, CssParseError::Custom(SelectorParseError::UnexpectedIdent(ident))) =>
ErrorString::Ident(ident),
(_, CssParseError::Custom(SelectorParseError::ExpectedNamespace(namespace))) =>
ErrorString::Ident(namespace),
(_, CssParseError::Custom(SelectorParseError::Custom(
StyleParseError::PropertyDeclaration(
PropertyDeclarationParseError::UnknownProperty(property))))) =>
ErrorString::Ident(property),
(_, CssParseError::Custom(SelectorParseError::Custom(
StyleParseError::UnexpectedTokenWithinNamespace(token)))) =>
ErrorString::UnexpectedToken(token),
(s, _) => ErrorString::Snippet(s)
}
fn error_params(self) -> (ErrorString<'a>, Option<ErrorString<'a>>) {
let (s, error) = self.error_data();
extract_error_params(error).unwrap_or((ErrorString::Snippet(s), None))
}
fn to_gecko_message(&self) -> (&'static [u8], Action) {
match *self {
fn to_gecko_message(&self) -> (Option<&'static [u8]>, &'static [u8], Action) {
let (msg, action): (&[u8], Action) = match *self {
ContextualParseError::UnsupportedPropertyDeclaration(
_, CssParseError::Basic(BasicParseError::UnexpectedToken(_))) |
ContextualParseError::UnsupportedPropertyDeclaration(
@ -264,8 +288,13 @@ impl<'a> ErrorHelpers<'a> for ContextualParseError<'a> {
ContextualParseError::UnsupportedPropertyDeclaration(
_, CssParseError::Custom(SelectorParseError::Custom(
StyleParseError::PropertyDeclaration(
PropertyDeclarationParseError::InvalidValue(_))))) =>
(b"PEValueParsingError\0", Action::Drop),
PropertyDeclarationParseError::InvalidValue(_, ref err))))) => {
let prefix = match *err {
Some(ValueParseError::InvalidColor(_)) => Some(&b"PEColorNotColor\0"[..]),
_ => None,
};
return (prefix, b"PEValueParsingError\0", Action::Drop);
}
ContextualParseError::UnsupportedPropertyDeclaration(..) =>
(b"PEUnknownProperty\0", Action::Drop),
ContextualParseError::UnsupportedFontFaceDescriptor(..) =>
@ -295,7 +324,8 @@ impl<'a> ErrorHelpers<'a> for ContextualParseError<'a> {
ContextualParseError::UnsupportedFontFeatureValuesDescriptor(..) |
ContextualParseError::InvalidFontFeatureValuesRule(..) =>
(b"PEUnknownAtRule\0", Action::Skip),
}
};
(None, msg, action)
}
}
@ -304,18 +334,21 @@ impl ParseErrorReporter for ErrorReporter {
input: &mut Parser,
position: SourcePosition,
error: ContextualParseError<'a>,
url: &UrlExtraData,
_url: &UrlExtraData,
line_number_offset: u64) {
let location = input.source_location(position);
let line_number = location.line + line_number_offset as u32;
let (name, action) = error.to_gecko_message();
let followup = match action {
let (pre, name, action) = error.to_gecko_message();
let suffix = match action {
Action::Nothing => ptr::null(),
Action::Skip => b"PEDeclSkipped\0".as_ptr(),
Action::Drop => b"PEDeclDropped\0".as_ptr(),
};
let param = error.error_param().into_str();
let (param, pre_param) = error.error_params();
let param = param.into_str();
let pre_param = pre_param.map(|p| p.into_str());
let pre_param_ptr = pre_param.as_ref().map_or(ptr::null(), |p| p.as_ptr());
// The CSS source text is unused and will be removed in bug 1381188.
let source = "";
unsafe {
@ -323,12 +356,14 @@ impl ParseErrorReporter for ErrorReporter {
name.as_ptr() as *const _,
param.as_ptr() as *const _,
param.len() as u32,
pre.map_or(ptr::null(), |p| p.as_ptr()) as *const _,
pre_param_ptr as *const _,
pre_param.as_ref().map_or(0, |p| p.len()) as u32,
suffix as *const _,
source.as_ptr() as *const _,
source.len() as u32,
line_number as u32,
location.column as u32,
url.mBaseURI.raw::<nsIURI>(),
followup as *const _);
location.column as u32);
}
}
}

Просмотреть файл

@ -378,7 +378,7 @@ fn test_report_error_stylesheet() {
let error = errors.pop().unwrap();
assert_eq!("Unsupported property declaration: 'display: invalid;', \
Custom(PropertyDeclaration(InvalidValue(\"display\")))", error.message);
Custom(PropertyDeclaration(InvalidValue(\"display\", None)))", error.message);
assert_eq!(8, error.line);
assert_eq!(8, error.column);

Просмотреть файл

@ -184,6 +184,9 @@ win32-devedition/opt:
config:
- builds/taskcluster_firefox_windows_32_opt.py
run-on-projects: ['mozilla-beta', ]
toolchains:
- win32-clang-cl
- win64-sccache
win64-devedition/opt:
description: "Win64 Dev Edition Opt"
@ -205,6 +208,9 @@ win64-devedition/opt:
config:
- builds/taskcluster_firefox_windows_64_opt.py
run-on-projects: ['mozilla-beta', ]
toolchains:
- win64-clang-cl
- win64-sccache
win32-nightly/opt:
description: "Win32 Nightly"
@ -430,6 +436,9 @@ win64-asan/opt:
config:
- builds/taskcluster_firefox_win64_asan_opt.py
run-on-projects: []
toolchains:
- win64-clang-cl
- win64-sccache
win32-devedition-nightly/opt:
description: "Win32 Dev Edition Nightly"
@ -457,6 +466,9 @@ win32-devedition-nightly/opt:
- taskcluster_nightly.py
custom-build-variant-cfg: devedition
run-on-projects: [ 'mozilla-beta', ]
toolchains:
- win32-clang-cl
- win64-sccache
win64-devedition-nightly/opt:
description: "Win64 Dev Edition Nightly"

Просмотреть файл

@ -41,7 +41,7 @@ class TestSelect(SelectTestCase):
options[1].click()
self.assertSelected(options[1])
def test_deselect(self):
def test_deselect_others(self):
self.marionette.navigate(inline("""
<select>
<option>first
@ -60,6 +60,22 @@ class TestSelect(SelectTestCase):
options[0].click()
self.assertSelected(options[0])
def test_select_self(self):
self.marionette.navigate(inline("""
<select>
<option>first
<option>second
</select>"""))
select = self.marionette.find_element(By.TAG_NAME, "select")
options = self.marionette.find_elements(By.TAG_NAME, "option")
self.assertSelected(options[0])
self.assertNotSelected(options[1])
options[1].click()
self.assertSelected(options[1])
options[1].click()
self.assertSelected(options[1])
def test_out_of_view(self):
self.marionette.navigate(inline("""
<select>

Просмотреть файл

@ -9,12 +9,13 @@ const {utils: Cu} = Components;
Cu.import("chrome://marionette/content/accessibility.js");
Cu.import("chrome://marionette/content/atom.js");
const {
ElementClickInterceptedError,
ElementNotInteractableError,
error,
InvalidArgument,
ElementNotInteractableError,
ElementClickInterceptedError,
InvalidElementStateError,
InvalidArgumentError,
InvalidElementStateError,
pprint,
} = Cu.import("chrome://marionette/content/error.js", {});
Cu.import("chrome://marionette/content/element.js");
Cu.import("chrome://marionette/content/event.js");
@ -281,10 +282,10 @@ function* seleniumClickElement(el, a11y) {
*/
interaction.selectOption = function(el) {
if (element.isXULElement(el)) {
throw new Error("XUL dropdowns not supported");
throw new TypeError("XUL dropdowns not supported");
}
if (el.localName != "option") {
throw new TypeError("Invalid elements");
throw new TypeError(pprint`Expected <option> element, got ${el}`);
}
let containerEl = element.getContainer(el);
@ -295,8 +296,14 @@ interaction.selectOption = function(el) {
event.focus(containerEl);
event.input(containerEl);
// toggle selectedness the way holding down control works
el.selected = !el.selected;
// Clicking <option> in <select> should not be deselected if selected.
// However, clicking one in a <select multiple> should toggle
// selectedness the way holding down Control works.
if (containerEl.multiple) {
el.selected = !el.selected;
} else if (!el.selected) {
el.selected = true;
}
event.change(containerEl);
event.mouseup(containerEl);

Просмотреть файл

@ -305535,6 +305535,11 @@
{}
]
],
"webdriver/tests/element_click/__init__.py": [
[
{}
]
],
"webdriver/tests/support/__init__.py": [
[
{}
@ -402871,6 +402876,12 @@
{}
]
],
"webdriver/tests/element_click/select.py": [
[
"/webdriver/tests/element_click/select.py",
{}
]
],
"webdriver/tests/navigation.py": [
[
"/webdriver/tests/navigation.py",
@ -621666,6 +621677,14 @@
"e31177e638269864031e44808945fa1e7c46031c",
"wdspec"
],
"webdriver/tests/element_click/__init__.py": [
"da39a3ee5e6b4b0d3255bfef95601890afd80709",
"support"
],
"webdriver/tests/element_click/select.py": [
"5ba51b660c7203bba3ada597c2f56fe094358e1f",
"wdspec"
],
"webdriver/tests/navigation.py": [
"cec2987258d9c807a247da9e0216b3af1f171484",
"wdspec"

Просмотреть файл

@ -1,4 +1,3 @@
[uri-013.xht]
type: reftest
expected:
if stylo: FAIL
expected: FAIL

Просмотреть файл

@ -637,10 +637,17 @@ class Element(object):
def rect(self):
return self.send_element_command("GET", "rect")
@property
@command
def property(self, name):
return self.send_element_command("GET", "property/%s" % name)
def selected(self):
return self.send_element_command("GET", "selected")
@command
def attribute(self, name):
return self.send_element_command("GET", "attribute/%s" % name)
# This MUST come last because otherwise @property decorators above
# will be overridden by this.
@command
def property(self, name):
return self.send_element_command("GET", "property/%s" % name)

Просмотреть файл

Просмотреть файл

@ -0,0 +1,213 @@
from tests.support.inline import inline
def test_click_option(session):
session.url = inline("""
<select>
<option>first
<option>second
</select>""")
options = session.find.css("option")
assert options[0].selected
assert not options[1].selected
options[1].click()
assert options[1].selected
assert not options[0].selected
def test_click_multiple_option(session):
session.url = inline("""
<select multiple>
<option>first
<option>second
</select>""")
options = session.find.css("option")
assert not options[0].selected
assert not options[1].selected
options[0].click()
assert options[0].selected
assert not options[1].selected
def test_click_preselected_option(session):
session.url = inline("""
<select>
<option>first
<option selected>second
</select>""")
options = session.find.css("option")
assert not options[0].selected
assert options[1].selected
options[1].click()
assert options[1].selected
assert not options[0].selected
options[0].click()
assert options[0].selected
assert not options[1].selected
def test_click_preselected_multiple_option(session):
session.url = inline("""
<select multiple>
<option>first
<option selected>second
</select>""")
options = session.find.css("option")
assert not options[0].selected
assert options[1].selected
options[1].click()
assert not options[1].selected
assert not options[0].selected
options[0].click()
assert options[0].selected
assert not options[1].selected
def test_click_deselects_others(session):
session.url = inline("""
<select>
<option>first
<option>second
<option>third
</select>""")
options = session.find.css("option")
options[0].click()
assert options[0].selected
options[1].click()
assert options[1].selected
options[2].click()
assert options[2].selected
options[0].click()
assert options[0].selected
def test_click_multiple_does_not_deselect_others(session):
session.url = inline("""
<select multiple>
<option>first
<option>second
<option>third
</select>""")
options = session.find.css("option")
options[0].click()
assert options[0].selected
options[1].click()
assert options[0].selected
assert options[1].selected
options[2].click()
assert options[0].selected
assert options[1].selected
assert options[2].selected
def test_click_selected_option(session):
session.url = inline("""
<select>
<option>first
<option>second
</select>""")
options = session.find.css("option")
# First <option> is selected in dropdown
assert options[0].selected
assert not options[1].selected
options[1].click()
assert options[1].selected
options[1].click()
assert options[1].selected
def test_click_selected_multiple_option(session):
session.url = inline("""
<select multiple>
<option>first
<option>second
</select>""")
options = session.find.css("option")
# No implicitly selected <option> in <select multiple>
assert not options[0].selected
assert not options[1].selected
options[0].click()
assert options[0].selected
assert not options[1].selected
# Second click in <select multiple> deselects
options[0].click()
assert not options[0].selected
assert not options[1].selected
def test_out_of_view_dropdown(session):
session.url = inline("""
<select>
<option>1
<option>2
<option>3
<option>4
<option>5
<option>6
<option>7
<option>8
<option>9
<option>10
<option>11
<option>12
<option>13
<option>14
<option>15
<option>16
<option>17
<option>18
<option>19
<option>20
</select>""")
options = session.find.css("option")
options[14].click()
assert options[14].selected
def test_out_of_view_multiple(session):
session.url = inline("""
<select multiple>
<option>1
<option>2
<option>3
<option>4
<option>5
<option>6
<option>7
<option>8
<option>9
<option>10
<option>11
<option>12
<option>13
<option>14
<option>15
<option>16
<option>17
<option>18
<option>19
<option>20
</select>""")
options = session.find.css("option")
last_option = options[-1]
last_option.click()
assert last_option.selected

Просмотреть файл

@ -640,7 +640,15 @@ class ProxyAPIImplementation extends SchemaAPIInterface {
this.childApiManager.callParentFunctionNoReturn(this.path, args);
}
callAsyncFunction(args, callback) {
callAsyncFunction(args, callback, requireUserInput) {
if (requireUserInput) {
let context = this.childApiManager.context;
let winUtils = context.contentWindow.getInterface(Ci.nsIDOMWindowUtils);
if (!winUtils.isHandlingUserInput) {
let err = new context.cloneScope.Error(`${this.path} may only be called from a user input handler`);
return context.wrapPromise(Promise.reject(err), callback);
}
}
return this.childApiManager.callParentAsyncFunction(this.path, args, callback);
}

Просмотреть файл

@ -450,10 +450,12 @@ class SchemaAPIInterface {
* @param {Array} args The parameters for the function.
* @param {function(*)} [callback] The callback to be called when the function
* completes.
* @param {boolean} [requireUserInput=false] If true, the function should
* fail if the browser is not currently handling user input.
* @returns {Promise|undefined} Must be void if `callback` is set, and a
* promise otherwise. The promise is resolved when the function completes.
*/
callAsyncFunction(args, callback) {
callAsyncFunction(args, callback, requireUserInput = false) {
throw new Error("Not implemented");
}
@ -559,9 +561,16 @@ class LocalAPIImplementation extends SchemaAPIInterface {
this.pathObj[this.name](...args);
}
callAsyncFunction(args, callback) {
callAsyncFunction(args, callback, requireUserInput) {
let promise;
try {
if (requireUserInput) {
let winUtils = this.context.contentWindow
.getInterface(Ci.nsIDOMWindowUtils);
if (!winUtils.isHandlingUserInput) {
throw new ExtensionError(`${this.name} may only be called from a user input handler`);
}
}
promise = this.pathObj[this.name](...args) || Promise.resolve();
} catch (e) {
promise = Promise.reject(e);

Просмотреть файл

@ -1836,7 +1836,8 @@ class ArrayType extends Type {
class FunctionType extends Type {
static get EXTRA_PROPERTIES() {
return ["parameters", "async", "returns", ...super.EXTRA_PROPERTIES];
return ["parameters", "async", "returns", "requireUserInput",
...super.EXTRA_PROPERTIES];
}
static parseSchema(schema, path, extraProperties = []) {
@ -1887,14 +1888,16 @@ class FunctionType extends Type {
}
return new this(schema, parameters, isAsync, hasAsyncCallback);
return new this(schema, parameters, isAsync, hasAsyncCallback,
!!schema.requireUserInput);
}
constructor(schema, parameters, isAsync, hasAsyncCallback) {
constructor(schema, parameters, isAsync, hasAsyncCallback, requireUserInput) {
super(schema);
this.parameters = parameters;
this.isAsync = isAsync;
this.hasAsyncCallback = hasAsyncCallback;
this.requireUserInput = requireUserInput;
}
normalize(value, context) {
@ -2167,6 +2170,7 @@ FunctionEntry = class FunctionEntry extends CallEntry {
this.isAsync = type.isAsync;
this.hasAsyncCallback = type.hasAsyncCallback;
this.requireUserInput = type.requireUserInput;
}
checkValue({type, optional, name}, value, context) {
@ -2216,7 +2220,7 @@ FunctionEntry = class FunctionEntry extends CallEntry {
original(...args);
};
}
let result = apiImpl.callAsyncFunction(actuals, callback);
let result = apiImpl.callAsyncFunction(actuals, callback, this.requireUserInput);
if (DEBUG && this.hasAsyncCallback && !callback) {
return result.then(result => {
this.checkCallback([result], context);

Просмотреть файл

@ -1,22 +0,0 @@
"use strict";
var {
ExtensionError,
} = ExtensionUtils;
this.downloads = class extends ExtensionAPI {
getAPI(context) {
return {
downloads: {
open(downloadId) {
let winUtils = context.contentWindow.getInterface(Ci.nsIDOMWindowUtils);
if (!winUtils.isHandlingUserInput) {
throw new ExtensionError("May only open downloads from a user input handler");
}
return context.childManager.callParentAsyncFunction("downloads.open_parent", [downloadId]);
},
},
};
}
};

Просмотреть файл

@ -1,22 +0,0 @@
"use strict";
var {
ExtensionError,
} = ExtensionUtils;
this.permissions = class extends ExtensionAPI {
getAPI(context) {
return {
permissions: {
async request(perms) {
let winUtils = context.contentWindow.getInterface(Ci.nsIDOMWindowUtils);
if (!winUtils.isHandlingUserInput) {
throw new ExtensionError("May only request permissions from a user input handler");
}
return context.childManager.callParentAsyncFunction("permissions.request_parent", [perms]);
},
},
};
}
};

Просмотреть файл

@ -41,13 +41,6 @@ extensions.registerModules({
["runtime", "getBackgroundPage"],
],
},
downloads: {
url: "chrome://extensions/content/ext-c-downloads.js",
scopes: ["addon_child"],
paths: [
["downloads"],
],
},
extension: {
url: "chrome://extensions/content/ext-c-extension.js",
scopes: ["addon_child", "content_child", "devtools_child", "proxy_script"],
@ -62,13 +55,6 @@ extensions.registerModules({
["i18n"],
],
},
permissions: {
url: "chrome://extensions/content/ext-c-permissions.js",
scopes: ["addon_child", "content_child", "devtools_child", "proxy_script"],
paths: [
["permissions"],
],
},
runtime: {
url: "chrome://extensions/content/ext-c-runtime.js",
scopes: ["addon_child", "content_child", "devtools_child", "proxy_script"],

Просмотреть файл

@ -645,7 +645,7 @@ this.downloads = class extends ExtensionAPI {
});
},
open_parent(downloadId) {
open(downloadId) {
return DownloadMap.lazyInit().then(() => {
let download = DownloadMap.fromId(downloadId).download;
if (download.succeeded) {

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше