Merge autoland to mozilla-central r=merge a=merge

This commit is contained in:
Gurzau Raul 2017-12-06 11:52:20 +02:00
commit c2096f8bee
223 changed files with 3858 additions and 2824 deletions

View File

@ -1480,7 +1480,10 @@ AccessibleWrap::GetIAccessibleFor(const VARIANT& aVarChild, bool* aIsDefunct)
// accessible is part of the chrome process and is part of the xul browser
// window and the child id points in the content documents. Thus we need to
// make sure that it is never called on proxies.
if (XRE_IsParentProcess() && !IsProxy() && !sIDGen.IsChromeID(varChild.lVal)) {
// Bug 1422674: We must only handle remote ids here (< 0), not child indices.
// Child indices (> 0) are handled below for both local and remote children.
if (XRE_IsParentProcess() && !IsProxy() &&
varChild.lVal < 0 && !sIDGen.IsChromeID(varChild.lVal)) {
if (!IsRoot()) {
// Bug 1422201: accChild with a remote id is only valid on the root accessible.
// Otherwise, we might return remote accessibles which aren't descendants

View File

@ -224,7 +224,6 @@ pref("browser.uitour.surveyDuration", 7200);
pref("keyword.enabled", true);
pref("browser.fixup.domainwhitelist.localhost", true);
pref("general.useragent.locale", "@AB_CD@");
pref("general.skins.selectedSkin", "classic/1.0");
pref("general.smoothScroll", true);
@ -521,6 +520,8 @@ pref("javascript.options.showInConsole", true);
pref("general.warnOnAboutConfig", false);
#endif
pref("intl.locale.requested", "@AB_CD@");
// This is the pref to control the location bar, change this to true to
// force this - this makes the origin of popup windows more obvious to avoid
// spoofing. We would rather not do it by default because it affects UE for web

View File

@ -441,10 +441,19 @@ var gXPInstallObserver = {
});
let secondaryActions = null;
let numAddons = installInfo.installs.length;
if (needsRestart) {
notificationID = "addon-install-restart";
messageString = gNavigatorBundle.getString("addonsInstalledNeedsRestart");
if (numAddons == 1) {
messageString = gNavigatorBundle.getFormattedString("addonInstalledNeedsRestart",
[installInfo.installs[0].name, brandShortName]);
} else {
messageString = gNavigatorBundle.getString("addonsGenericInstalledNeedsRestart");
messageString = PluralForm.get(numAddons, messageString);
messageString = messageString.replace("#1", numAddons);
messageString = messageString.replace("#2", brandShortName);
}
action = {
label: gNavigatorBundle.getString("addonInstallRestartButton"),
accessKey: gNavigatorBundle.getString("addonInstallRestartButton.accesskey"),
@ -458,15 +467,17 @@ var gXPInstallObserver = {
callback: () => {},
}];
} else {
messageString = gNavigatorBundle.getString("addonsInstalled");
if (numAddons == 1) {
messageString = gNavigatorBundle.getFormattedString("addonInstalled",
[installInfo.installs[0].name]);
} else {
messageString = gNavigatorBundle.getString("addonsGenericInstalled");
messageString = PluralForm.get(numAddons, messageString);
messageString = messageString.replace("#1", numAddons);
}
action = null;
}
messageString = PluralForm.get(installInfo.installs.length, messageString);
messageString = messageString.replace("#1", installInfo.installs[0].name);
messageString = messageString.replace("#2", installInfo.installs.length);
messageString = messageString.replace("#3", brandShortName);
// Remove notification on dismissal, since it's possible to cancel the
// install through the addons manager UI, making the "restart" prompt
// irrelevant.

View File

@ -40,8 +40,15 @@ this.pageAction = class extends ExtensionAPI {
this.tabManager = extension.tabManager;
// If <all_urls> is present, the default is to show the page action.
let show = options.show_matches && options.show_matches.includes("<all_urls>");
let showMatches = new MatchPatternSet(options.show_matches || []);
let hideMatches = new MatchPatternSet(options.hide_matches || []);
this.defaults = {
show: false,
show,
showMatches,
hideMatches,
title: options.default_title || extension.name,
popup: options.default_popup || "",
};
@ -70,7 +77,7 @@ this.pageAction = class extends ExtensionAPI {
title: this.defaults.title,
iconURL: this.getIconData(this.defaults.icon),
pinnedToUrlbar: true,
disabled: true,
disabled: !this.defaults.show,
onCommand: (event, buttonNode) => {
this.handleClick(event.target.ownerGlobal);
},
@ -226,6 +233,12 @@ this.pageAction = class extends ExtensionAPI {
if (fromBrowse) {
this.tabContext.clear(tab);
}
// Set show via pattern matching.
let context = this.tabContext.get(tab);
let uri = tab.linkedBrowser.currentURI;
context.show = (context.show || context.showMatches.matches(uri)) && !context.hideMatches.matches(uri);
this.updateButton(tab.ownerGlobal);
}

View File

@ -31,6 +31,18 @@
"browser_style": {
"type": "boolean",
"optional": true
},
"show_matches": {
"type": "array",
"optional": true,
"minItems": 1,
"items": { "$ref": "MatchPattern" }
},
"hide_matches": {
"type": "array",
"optional": true,
"minItems": 1,
"items": { "$ref": "MatchPattern" }
}
},
"optional": true

View File

@ -102,6 +102,7 @@ skip-if = (os == 'win' && !debug) # bug 1352668
[browser_ext_pageAction_contextMenu.js]
[browser_ext_pageAction_popup.js]
[browser_ext_pageAction_popup_resize.js]
[browser_ext_pageAction_show_matches.js]
[browser_ext_pageAction_simple.js]
[browser_ext_pageAction_telemetry.js]
[browser_ext_pageAction_title.js]

View File

@ -0,0 +1,68 @@
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";
function getExtension(page_action) {
return ExtensionTestUtils.loadExtension({
manifest: {
page_action,
},
});
}
add_task(async function test_pageAction_default_show() {
let tests = [
{
"name": "Test shown for all_urls",
"page_action": {
"show_matches": ["<all_urls>"],
},
"shown": [true, true, false],
},
{
"name": "Test hide_matches overrides all_urls.",
"page_action": {
"show_matches": ["<all_urls>"],
"hide_matches": ["*://mochi.test/*"],
},
"shown": [true, false, false],
},
{
"name": "Test shown only for show_matches.",
"page_action": {
"show_matches": ["*://mochi.test/*"],
},
"shown": [false, true, false],
},
];
let tabs = [
await BrowserTestUtils.openNewForegroundTab(gBrowser, "http://example.com/", true, true),
await BrowserTestUtils.openNewForegroundTab(gBrowser, "http://mochi.test:8888/", true, true),
await BrowserTestUtils.openNewForegroundTab(gBrowser, "about:rights", true, true),
];
for (let [i, test] of tests.entries()) {
info(`test ${i}: ${test.name}`);
let extension = getExtension(test.page_action);
await extension.startup();
let widgetId = makeWidgetId(extension.id);
let pageActionId = BrowserPageActions.urlbarButtonNodeIDForActionID(widgetId);
for (let [t, tab] of tabs.entries()) {
await BrowserTestUtils.switchTab(gBrowser, tab);
is(gBrowser.selectedTab, tab, `tab ${t} selected`);
let button = document.getElementById(pageActionId);
// Sometimes we're hidden, sometimes a parent is hidden via css (e.g. about pages)
let hidden = button === null || button.hidden ||
window.getComputedStyle(button).display == "none";
is(!hidden, test.shown[t], `test ${i} tab ${t}: page action is ${test.shown[t] ? "shown" : "hidden"} for ${tab.linkedBrowser.currentURI.spec}`);
}
await extension.unload();
}
for (let tab of tabs) {
await BrowserTestUtils.removeTab(tab);
}
});

View File

@ -2,7 +2,7 @@
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";
add_task(async function() {
add_task(async function test_pageAction_basic() {
let extension = ExtensionTestUtils.loadExtension({
manifest: {
"page_action": {

View File

@ -1,12 +1,11 @@
const LOCALE_PREF = "general.useragent.locale";
Components.utils.import("resource://gre/modules/Services.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "aboutNewTabService",
"@mozilla.org/browser/aboutnewtab-service;1",
"nsIAboutNewTabService");
const DEFAULT_URL = "resource://activity-stream/prerendered/en-US/activity-stream-prerendered.html";
async function getUrlForLocale(locale) {
await SpecialPowers.pushPrefEnv({set: [[LOCALE_PREF, locale]]});
Services.locale.setRequestedLocales([locale]);
return aboutNewTabService.defaultURL;
}
@ -14,7 +13,7 @@ async function getUrlForLocale(locale) {
* Test that an unknown locale defaults to en-US
*/
add_task(async function test_unknown_locale() {
const url = await getUrlForLocale("foo-BAR");
const url = await getUrlForLocale("und");
Assert.equal(url, DEFAULT_URL);
});

View File

@ -2208,6 +2208,27 @@ BrowserGlue.prototype = {
Services.prefs.setCharPref("browser.search.reset.status", "silent");
}
});
// Migrate the old requested locales prefs to use the new model
const SELECTED_LOCALE_PREF = "general.useragent.locale";
const MATCHOS_LOCALE_PREF = "intl.locale.matchOS";
if (Services.prefs.prefHasUserValue(MATCHOS_LOCALE_PREF) ||
Services.prefs.prefHasUserValue(SELECTED_LOCALE_PREF)) {
if (Services.prefs.getBoolPref(MATCHOS_LOCALE_PREF, false)) {
Services.locale.setRequestedLocales([]);
} else {
let locale = Services.prefs.getComplexValue(SELECTED_LOCALE_PREF,
Ci.nsIPrefLocalizedString);
if (locale) {
try {
Services.locale.setRequestedLocales([locale.data]);
} catch (e) { /* Don't panic if the value is not a valid locale code. */ }
}
}
Services.prefs.clearUserPref(SELECTED_LOCALE_PREF);
Services.prefs.clearUserPref(MATCHOS_LOCALE_PREF);
}
}
// Update the migration version.

View File

@ -14,6 +14,9 @@ XPCOMUtils.defineLazyGetter(this, "FxAccountsCommon", function() {
XPCOMUtils.defineLazyModuleGetter(this, "fxAccounts",
"resource://gre/modules/FxAccounts.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "UIState",
"resource://services-sync/UIState.jsm");
const FXA_PAGE_LOGGED_OUT = 0;
const FXA_PAGE_LOGGED_IN = 1;
@ -112,27 +115,13 @@ var gSyncPane = {
},
_init() {
let topics = ["weave:service:login:error",
"weave:service:login:finish",
"weave:service:start-over:finish",
"weave:service:setup-complete",
"weave:service:logout:finish",
FxAccountsCommon.ONVERIFIED_NOTIFICATION,
FxAccountsCommon.ONLOGIN_NOTIFICATION,
FxAccountsCommon.ON_ACCOUNT_STATE_CHANGE_NOTIFICATION,
FxAccountsCommon.ON_PROFILE_CHANGE_NOTIFICATION,
];
// Add the observers now and remove them on unload
// XXXzpao This should use Services.obs.* but Weave's Obs does nice handling
// of `this`. Fix in a followup. (bug 583347)
topics.forEach(function(topic) {
Weave.Svc.Obs.add(topic, this.updateWeavePrefs, this);
}, this);
Weave.Svc.Obs.add(UIState.ON_UPDATE, this.updateWeavePrefs, this);
window.addEventListener("unload", function() {
topics.forEach(function(topic) {
Weave.Svc.Obs.remove(topic, this.updateWeavePrefs, this);
}, gSyncPane);
window.addEventListener("unload", () => {
Weave.Svc.Obs.remove(UIState.ON_UPDATE, this.updateWeavePrefs, this);
});
XPCOMUtils.defineLazyGetter(this, "_accountsStringBundle", () => {
@ -149,10 +138,6 @@ var gSyncPane = {
document.getElementById("tosPP-small-ToS").setAttribute("href", Weave.Svc.Prefs.get("fxa.termsURL"));
document.getElementById("tosPP-small-PP").setAttribute("href", Weave.Svc.Prefs.get("fxa.privacyURL"));
fxAccounts.promiseAccountsManageURI(this._getEntryPoint()).then(accountsManageURI => {
document.getElementById("verifiedManage").setAttribute("href", accountsManageURI);
});
fxAccounts.promiseAccountsSignUpURI(this._getEntryPoint()).then(signUpURI => {
document.getElementById("noFxaSignUp").setAttribute("href", signUpURI);
});
@ -263,94 +248,67 @@ var gSyncPane = {
// determine the fxa status...
this._showLoadPage(service);
fxAccounts.getSignedInUser().then(data => {
return fxAccounts.hasLocalSession().then(hasLocalSession => {
return [data, hasLocalSession];
});
}).then(([data, hasLocalSession]) => {
if (!data) {
this.page = FXA_PAGE_LOGGED_OUT;
return false;
}
this.page = FXA_PAGE_LOGGED_IN;
// We are logged in locally, but maybe we are in a state where the
// server rejected our credentials (eg, password changed on the server)
let fxaLoginStatus = document.getElementById("fxaLoginStatus");
let syncReady;
// We need to check error states that need a re-authenticate to resolve
// themselves first.
if (!hasLocalSession || Weave.Status.login == Weave.LOGIN_FAILED_LOGIN_REJECTED) {
fxaLoginStatus.selectedIndex = FXA_LOGIN_FAILED;
syncReady = false;
} else if (!data.verified) {
fxaLoginStatus.selectedIndex = FXA_LOGIN_UNVERIFIED;
syncReady = false;
// So we think we are logged in, so login problems are next.
// (Although if the Sync identity manager is still initializing, we
// ignore login errors and assume all will eventually be good.)
// LOGIN_FAILED_LOGIN_REJECTED explicitly means "you must log back in".
// All other login failures are assumed to be transient and should go
// away by themselves, so aren't reflected here.
} else {
// We must be golden (or in an error state we expect to magically
// resolve itself)
fxaLoginStatus.selectedIndex = FXA_LOGIN_VERIFIED;
syncReady = true;
}
fxaEmailAddressLabels.forEach((label) => {
label.value = data.email;
});
this._populateComputerName(Weave.Service.clientsEngine.localName);
let engines = document.getElementById("fxaSyncEngines");
for (let checkbox of engines.querySelectorAll("checkbox")) {
checkbox.disabled = !syncReady;
}
document.getElementById("fxaChangeDeviceName").disabled = !syncReady;
let state = UIState.get();
if (state.status == UIState.STATUS_NOT_CONFIGURED) {
this.page = FXA_PAGE_LOGGED_OUT;
return;
}
this.page = FXA_PAGE_LOGGED_IN;
// We are logged in locally, but maybe we are in a state where the
// server rejected our credentials (eg, password changed on the server)
let fxaLoginStatus = document.getElementById("fxaLoginStatus");
let syncReady = false; // Is sync able to actually sync?
// We need to check error states that need a re-authenticate to resolve
// themselves first.
if (state.status == UIState.STATUS_LOGIN_FAILED) {
fxaLoginStatus.selectedIndex = FXA_LOGIN_FAILED;
} else if (state.status == UIState.STATUS_NOT_VERIFIED) {
fxaLoginStatus.selectedIndex = FXA_LOGIN_UNVERIFIED;
} else {
// We must be golden (or in an error state we expect to magically
// resolve itself)
fxaLoginStatus.selectedIndex = FXA_LOGIN_VERIFIED;
syncReady = true;
}
fxaEmailAddressLabels.forEach((label) => {
label.value = state.email;
});
this._populateComputerName(Weave.Service.clientsEngine.localName);
let engines = document.getElementById("fxaSyncEngines");
for (let checkbox of engines.querySelectorAll("checkbox")) {
checkbox.disabled = !syncReady;
}
document.getElementById("fxaChangeDeviceName").disabled = !syncReady;
// Clear the profile image (if any) of the previously logged in account.
document.querySelector("#fxaLoginVerified > .fxaProfileImage").style.removeProperty("list-style-image");
// Clear the profile image (if any) of the previously logged in account.
document.querySelector("#fxaLoginVerified > .fxaProfileImage").style.removeProperty("list-style-image");
// If the account is verified the next promise in the chain will
// fetch profile data.
return data.verified;
}).then(isVerified => {
if (isVerified) {
return fxAccounts.getSignedInUserProfile();
}
return null;
}).then(data => {
let fxaLoginStatus = document.getElementById("fxaLoginStatus");
if (data) {
if (data.displayName) {
fxaLoginStatus.setAttribute("hasName", true);
displayNameLabel.hidden = false;
displayNameLabel.textContent = data.displayName;
} else {
fxaLoginStatus.removeAttribute("hasName");
if (state.displayName) {
fxaLoginStatus.setAttribute("hasName", true);
displayNameLabel.hidden = false;
displayNameLabel.textContent = state.displayName;
} else {
fxaLoginStatus.removeAttribute("hasName");
}
if (state.avatarURL) {
let bgImage = "url(\"" + state.avatarURL + "\")";
let profileImageElement = document.querySelector("#fxaLoginVerified > .fxaProfileImage");
profileImageElement.style.listStyleImage = bgImage;
let img = new Image();
img.onerror = () => {
// Clear the image if it has trouble loading. Since this callback is asynchronous
// we check to make sure the image is still the same before we clear it.
if (profileImageElement.style.listStyleImage === bgImage) {
profileImageElement.style.removeProperty("list-style-image");
}
if (data.avatar) {
let bgImage = "url(\"" + data.avatar + "\")";
let profileImageElement = document.querySelector("#fxaLoginVerified > .fxaProfileImage");
profileImageElement.style.listStyleImage = bgImage;
let img = new Image();
img.onerror = () => {
// Clear the image if it has trouble loading. Since this callback is asynchronous
// we check to make sure the image is still the same before we clear it.
if (profileImageElement.style.listStyleImage === bgImage) {
profileImageElement.style.removeProperty("list-style-image");
}
};
img.src = data.avatar;
}
} else {
fxaLoginStatus.removeAttribute("hasName");
}
}, err => {
FxAccountsCommon.log.error(err);
}).catch(err => {
// If we get here something's really busted
Cu.reportError(String(err));
};
img.src = state.avatarURL;
}
// The "manage account" link embeds the uid, so we need to update this
// if the account state changes.
fxAccounts.promiseAccountsManageURI(this._getEntryPoint()).then(accountsManageURI => {
document.getElementById("verifiedManage").setAttribute("href", accountsManageURI);
});
},
@ -385,7 +343,13 @@ var gSyncPane = {
},
async reSignIn() {
const url = await fxAccounts.promiseAccountsForceSigninURI(this._getEntryPoint());
// There's a bit of an edge-case here - we might be forcing reauth when we've
// lost the FxA account data - in which case we'll not get a URL as the re-auth
// URL embeds account info and the server endpoint complains if we don't
// supply it - So we just use the regular "sign in" URL in that case.
let entryPoint = this._getEntryPoint();
const url = (await fxAccounts.promiseAccountsForceSigninURI(entryPoint)) ||
(await fxAccounts.promiseAccountsSignInURI(entryPoint));
this.replaceTabWithUrl(url);
},

View File

@ -657,6 +657,7 @@ this.FormAutofillUtils = {
* {
* {string} addressLevel1Label
* {string} postalCodeLabel
* {object} fieldsOrder
* }
*/
getFormFormat(country) {
@ -664,6 +665,7 @@ this.FormAutofillUtils = {
return {
"addressLevel1Label": dataset.state_name_type || "province",
"postalCodeLabel": dataset.zip_name_type || "postalCode",
"fieldsOrder": this.parseAddressFormat(dataset.fmt || "%N%n%O%n%A%n%C, %S %Z"),
};
},

View File

@ -13,38 +13,42 @@
</head>
<body>
<form id="form" autocomplete="off">
<label id="given-name-container">
<span data-localization="givenName"/>
<input id="given-name" type="text"/>
</label>
<label id="additional-name-container">
<span data-localization="additionalName"/>
<input id="additional-name" type="text"/>
</label>
<label id="family-name-container">
<span data-localization="familyName"/>
<input id="family-name" type="text"/>
</label>
<label id="organization-container">
<span data-localization="organization2"/>
<input id="organization" type="text"/>
</label>
<label id="street-address-container">
<span data-localization="streetAddress"/>
<textarea id="street-address" rows="3"/>
</label>
<label id="address-level2-container">
<span data-localization="city"/>
<input id="address-level2" type="text"/>
</label>
<label id="address-level1-container">
<span/>
<input id="address-level1" type="text"/>
</label>
<label id="postal-code-container">
<span/>
<input id="postal-code" type="text"/>
</label>
<div>
<div id="name-container">
<label id="given-name-container">
<span data-localization="givenName"/>
<input id="given-name" type="text"/>
</label>
<label id="additional-name-container">
<span data-localization="additionalName"/>
<input id="additional-name" type="text"/>
</label>
<label id="family-name-container">
<span data-localization="familyName"/>
<input id="family-name" type="text"/>
</label>
</div>
<label id="organization-container">
<span data-localization="organization2"/>
<input id="organization" type="text"/>
</label>
<label id="street-address-container">
<span data-localization="streetAddress"/>
<textarea id="street-address" rows="3"/>
</label>
<label id="address-level2-container">
<span data-localization="city"/>
<input id="address-level2" type="text"/>
</label>
<label id="address-level1-container">
<span/>
<input id="address-level1" type="text"/>
</label>
<label id="postal-code-container">
<span/>
<input id="postal-code" type="text"/>
</label>
</div>
<label id="country-container">
<span data-localization="country"/>
<select id="country">

View File

@ -120,6 +120,10 @@ class EditDialog {
this.handleKeyPress(event);
break;
}
case "change": {
this.handleChange(event);
break;
}
}
}
@ -180,6 +184,15 @@ class EditDialog {
this._elements.controlsContainer.removeEventListener("click", this);
document.removeEventListener("input", this);
}
// An interface to be inherited.
localizeDocument() {}
// An interface to be inherited.
handleSubmit(event) {}
// An interface to be inherited.
handleChange(event) {}
}
class EditAddress extends EditDialog {
@ -194,11 +207,42 @@ class EditAddress extends EditDialog {
* @param {string} country
*/
formatForm(country) {
// TODO: Use fmt to show/hide and order fields (Bug 1383687)
const {addressLevel1Label, postalCodeLabel} = FormAutofillUtils.getFormFormat(country);
const {addressLevel1Label, postalCodeLabel, fieldsOrder} = FormAutofillUtils.getFormFormat(country);
this._elements.addressLevel1Label.dataset.localization = addressLevel1Label;
this._elements.postalCodeLabel.dataset.localization = postalCodeLabel;
FormAutofillUtils.localizeMarkup(AUTOFILL_BUNDLE_URI, document);
this.arrangeFields(fieldsOrder);
}
arrangeFields(fieldsOrder) {
let fields = [
"name",
"organization",
"street-address",
"address-level2",
"address-level1",
"postal-code",
];
let inputs = [];
for (let i = 0; i < fieldsOrder.length; i++) {
let {fieldId, newLine} = fieldsOrder[i];
let container = document.getElementById(`${fieldId}-container`);
inputs.push(...container.querySelectorAll("input, textarea, select"));
container.style.display = "flex";
container.style.order = i;
container.style.pageBreakAfter = newLine ? "always" : "auto";
// Remove the field from the list of fields
fields.splice(fields.indexOf(fieldId), 1);
}
for (let i = 0; i < inputs.length; i++) {
// Assign tabIndex starting from 1
inputs[i].tabIndex = i + 1;
}
// Hide the remaining fields
for (let field of fields) {
let container = document.getElementById(`${field}-container`);
container.style.display = "none";
}
}
localizeDocument() {
@ -220,6 +264,20 @@ class EditAddress extends EditDialog {
await this.saveRecord(this.buildFormObject(), this._record ? this._record.guid : null);
window.close();
}
handleChange(event) {
this.formatForm(event.target.value);
}
attachEventListeners() {
this._elements.country.addEventListener("change", this);
super.attachEventListeners();
}
detachEventListeners() {
this._elements.country.removeEventListener("change", this);
super.detachEventListeners();
}
}
class EditCreditCard extends EditDialog {

View File

@ -26,13 +26,11 @@ select {
flex: 0 1 50%;
}
#family-name-container,
#organization-container,
#address-level2-container,
#tel-container {
padding-inline-end: 50%;
}
#name-container,
#street-address-container,
#email-container {
flex: 0 1 100%;

View File

@ -9,13 +9,17 @@ p {
display: flex;
}
form {
form,
div {
flex-wrap: wrap;
}
form {
/* Add extra space to ensure invalid input box is displayed properly */
padding: 2px;
}
form > label,
form label,
form > p {
margin: 0 0 0.5em !important;
}

View File

@ -34,32 +34,41 @@ add_task(async function test_saveAddress() {
ok(true, "Edit address dialog is closed");
resolve();
}, {once: true});
EventUtils.synthesizeKey("VK_TAB", {}, win);
EventUtils.synthesizeKey(TEST_ADDRESS_1["given-name"], {}, win);
EventUtils.synthesizeKey("VK_TAB", {}, win);
EventUtils.synthesizeKey(TEST_ADDRESS_1["additional-name"], {}, win);
EventUtils.synthesizeKey("VK_TAB", {}, win);
EventUtils.synthesizeKey(TEST_ADDRESS_1["family-name"], {}, win);
EventUtils.synthesizeKey("VK_TAB", {}, win);
EventUtils.synthesizeKey(TEST_ADDRESS_1.organization, {}, win);
EventUtils.synthesizeKey("VK_TAB", {}, win);
EventUtils.synthesizeKey(TEST_ADDRESS_1["street-address"], {}, win);
EventUtils.synthesizeKey("VK_TAB", {}, win);
EventUtils.synthesizeKey(TEST_ADDRESS_1["address-level2"], {}, win);
EventUtils.synthesizeKey("VK_TAB", {}, win);
EventUtils.synthesizeKey(TEST_ADDRESS_1["address-level1"], {}, win);
EventUtils.synthesizeKey("VK_TAB", {}, win);
EventUtils.synthesizeKey(TEST_ADDRESS_1["postal-code"], {}, win);
EventUtils.synthesizeKey("VK_TAB", {}, win);
EventUtils.synthesizeKey(TEST_ADDRESS_1.country, {}, win);
EventUtils.synthesizeKey("VK_TAB", {}, win);
EventUtils.synthesizeKey(TEST_ADDRESS_1.email, {}, win);
EventUtils.synthesizeKey("VK_TAB", {}, win);
EventUtils.synthesizeKey(TEST_ADDRESS_1.tel, {}, win);
EventUtils.synthesizeKey("VK_TAB", {}, win);
EventUtils.synthesizeKey("VK_TAB", {}, win);
info("saving address");
EventUtils.synthesizeKey("VK_RETURN", {}, win);
let doc = win.document;
// Verify labels
is(doc.querySelector("#address-level1-container > span").textContent, "State",
"US address-level1 label should be 'State'");
is(doc.querySelector("#postal-code-container > span").textContent, "Zip Code",
"US postal-code label should be 'Zip Code'");
// Input address info and verify move through form with tab keys
const keyInputs = [
"VK_TAB",
TEST_ADDRESS_1["given-name"],
"VK_TAB",
TEST_ADDRESS_1["additional-name"],
"VK_TAB",
TEST_ADDRESS_1["family-name"],
"VK_TAB",
TEST_ADDRESS_1.organization,
"VK_TAB",
TEST_ADDRESS_1["street-address"],
"VK_TAB",
TEST_ADDRESS_1["address-level2"],
"VK_TAB",
TEST_ADDRESS_1["address-level1"],
"VK_TAB",
TEST_ADDRESS_1["postal-code"],
"VK_TAB",
TEST_ADDRESS_1.country,
"VK_TAB",
TEST_ADDRESS_1.email,
"VK_TAB",
TEST_ADDRESS_1.tel,
"VK_TAB",
"VK_TAB",
"VK_RETURN",
];
keyInputs.forEach(input => EventUtils.synthesizeKey(input, {}, win));
}, {once: true});
});
let addresses = await getAddresses();
@ -95,3 +104,109 @@ add_task(async function test_editAddress() {
addresses = await getAddresses();
is(addresses.length, 0, "Address storage is empty");
});
add_task(async function test_saveAddressCA() {
await new Promise(resolve => {
let win = window.openDialog(EDIT_ADDRESS_DIALOG_URL);
win.addEventListener("load", () => {
win.addEventListener("unload", () => {
ok(true, "Edit address dialog is closed");
resolve();
}, {once: true});
let doc = win.document;
// Change country to verify labels
doc.querySelector("#country").focus();
EventUtils.synthesizeKey("Canada", {}, win);
is(doc.querySelector("#address-level1-container > span").textContent, "Province",
"CA address-level1 label should be 'Province'");
is(doc.querySelector("#postal-code-container > span").textContent, "Postal Code",
"CA postal-code label should be 'Postal Code'");
// Input address info and verify move through form with tab keys
doc.querySelector("#given-name").focus();
const keyInputs = [
TEST_ADDRESS_CA_1["given-name"],
"VK_TAB",
TEST_ADDRESS_CA_1["additional-name"],
"VK_TAB",
TEST_ADDRESS_CA_1["family-name"],
"VK_TAB",
TEST_ADDRESS_CA_1.organization,
"VK_TAB",
TEST_ADDRESS_CA_1["street-address"],
"VK_TAB",
TEST_ADDRESS_CA_1["address-level2"],
"VK_TAB",
TEST_ADDRESS_CA_1["address-level1"],
"VK_TAB",
TEST_ADDRESS_CA_1["postal-code"],
"VK_TAB",
TEST_ADDRESS_CA_1.country,
"VK_TAB",
TEST_ADDRESS_CA_1.email,
"VK_TAB",
TEST_ADDRESS_CA_1.tel,
"VK_TAB",
"VK_TAB",
"VK_RETURN",
];
keyInputs.forEach(input => EventUtils.synthesizeKey(input, {}, win));
}, {once: true});
});
let addresses = await getAddresses();
for (let [fieldName, fieldValue] of Object.entries(TEST_ADDRESS_CA_1)) {
is(addresses[0][fieldName], fieldValue, "check " + fieldName);
}
await removeAllRecords();
});
add_task(async function test_saveAddressDE() {
await new Promise(resolve => {
let win = window.openDialog(EDIT_ADDRESS_DIALOG_URL);
win.addEventListener("load", () => {
win.addEventListener("unload", () => {
ok(true, "Edit address dialog is closed");
resolve();
}, {once: true});
let doc = win.document;
// Change country to verify labels
doc.querySelector("#country").focus();
EventUtils.synthesizeKey("Germany", {}, win);
is(doc.querySelector("#postal-code-container > span").textContent, "Postal Code",
"DE postal-code label should be 'Postal Code'");
is(doc.querySelector("#address-level1-container").style.display, "none",
"DE address-level1 should be hidden");
// Input address info and verify move through form with tab keys
doc.querySelector("#given-name").focus();
const keyInputs = [
TEST_ADDRESS_DE_1["given-name"],
"VK_TAB",
TEST_ADDRESS_DE_1["additional-name"],
"VK_TAB",
TEST_ADDRESS_DE_1["family-name"],
"VK_TAB",
TEST_ADDRESS_DE_1.organization,
"VK_TAB",
TEST_ADDRESS_DE_1["street-address"],
"VK_TAB",
TEST_ADDRESS_DE_1["postal-code"],
"VK_TAB",
TEST_ADDRESS_DE_1["address-level2"],
"VK_TAB",
TEST_ADDRESS_DE_1.country,
"VK_TAB",
TEST_ADDRESS_DE_1.email,
"VK_TAB",
TEST_ADDRESS_DE_1.tel,
"VK_TAB",
"VK_TAB",
"VK_RETURN",
];
keyInputs.forEach(input => EventUtils.synthesizeKey(input, {}, win));
}, {once: true});
});
let addresses = await getAddresses();
for (let [fieldName, fieldValue] of Object.entries(TEST_ADDRESS_DE_1)) {
is(addresses[0][fieldName], fieldValue, "check " + fieldName);
}
await removeAllRecords();
});

View File

@ -1,5 +1,5 @@
/* exported MANAGE_ADDRESSES_DIALOG_URL, MANAGE_CREDIT_CARDS_DIALOG_URL, EDIT_ADDRESS_DIALOG_URL, EDIT_CREDIT_CARD_DIALOG_URL,
BASE_URL, TEST_ADDRESS_1, TEST_ADDRESS_2, TEST_ADDRESS_3, TEST_ADDRESS_4, TEST_ADDRESS_5,
BASE_URL, TEST_ADDRESS_1, TEST_ADDRESS_2, TEST_ADDRESS_3, TEST_ADDRESS_4, TEST_ADDRESS_5, TEST_ADDRESS_CA_1, TEST_ADDRESS_DE_1,
TEST_CREDIT_CARD_1, TEST_CREDIT_CARD_2, TEST_CREDIT_CARD_3, FORM_URL, CREDITCARD_FORM_URL,
FTU_PREF, ENABLED_AUTOFILL_ADDRESSES_PREF, AUTOFILL_CREDITCARDS_AVAILABLE_PREF, ENABLED_AUTOFILL_CREDITCARDS_PREF,
SYNC_USERNAME_PREF, SYNC_ADDRESSES_PREF, SYNC_CREDITCARDS_PREF, SYNC_CREDITCARDS_AVAILABLE_PREF, CREDITCARDS_USED_STATUS_PREF,
@ -67,6 +67,33 @@ const TEST_ADDRESS_5 = {
tel: "+16172535702",
};
const TEST_ADDRESS_CA_1 = {
"given-name": "John",
"additional-name": "R.",
"family-name": "Smith",
organization: "Mozilla",
"street-address": "163 W Hastings\nSuite 209",
"address-level2": "Vancouver",
"address-level1": "BC",
"postal-code": "V6B 1H5",
country: "CA",
tel: "+17787851540",
email: "timbl@w3.org",
};
const TEST_ADDRESS_DE_1 = {
"given-name": "John",
"additional-name": "R.",
"family-name": "Smith",
organization: "Mozilla",
"street-address": "Geb\u00E4ude 3, 4. Obergeschoss\nSchlesische Stra\u00DFe 27",
"address-level2": "Berlin",
"postal-code": "10997",
country: "DE",
tel: "+4930983333000",
email: "timbl@w3.org",
};
const TEST_CREDIT_CARD_1 = {
"cc-name": "John Doe",
"cc-number": "1234567812345678",

View File

@ -198,12 +198,22 @@ addonConfirmInstallUnsigned.message=Caution: This site would like to install an
# #2 is the total number of add-ons being installed (at least 2)
addonConfirmInstallSomeUnsigned.message=;Caution: This site would like to install #2 add-ons in #1, some of which are unverified. Proceed at your own risk.
# LOCALIZATION NOTE (addonsInstalled, addonsInstalledNeedsRestart):
# LOCALIZATION NOTE (addonInstalled):
# %S is the name of the add-on
addonInstalled=%S has been installed successfully.
# LOCALIZATION NOTE (addonsGenericInstalled):
# Semicolon-separated list of plural forms. See:
# http://developer.mozilla.org/en/docs/Localization_and_Plurals
# #1 first add-on's name, #2 number of add-ons, #3 application name
addonsInstalled=#1 has been installed successfully.;#2 add-ons have been installed successfully.
addonsInstalledNeedsRestart=#1 will be installed after you restart #3.;#2 add-ons will be installed after you restart #3.
# #1 number of add-ons
addonsGenericInstalled=#1 add-on has been installed successfully.;#1 add-ons have been installed successfully.
# LOCALIZATION NOTE (addonInstalledNeedsRestart):
# %1$S is the name of the add-on, %2$S is the application's name
addonInstalledNeedsRestart=%1$S will be installed after you restart %2$S.
# LOCALIZATION NOTE (addonsGenericInstalledNeedsRestart):
# Semicolon-separated list of plural forms. See:
# http://developer.mozilla.org/en/docs/Localization_and_Plurals
# #1 number of add-ons. #2 application's name
addonsGenericInstalledNeedsRestart=#1 add-on will be installed after you restart #2.;#1 add-ons will be installed after you restart #2.
addonInstallRestartButton=Restart Now
addonInstallRestartButton.accesskey=R
addonInstallRestartIgnoreButton=Not Now

View File

@ -7,5 +7,3 @@
# LOCALIZATION NOTE: this preference is set to true for en-US specifically,
# locales without this line have the setting set to false by default.
pref("browser.search.geoSpecificDefaults", true);
pref("general.useragent.locale", "@AB_CD@");

View File

@ -465,7 +465,7 @@ tabbrowser {
}
.tabbrowser-tab[visuallyselected=true]:-moz-lwtheme {
color: var(--theme-tab-text, var(--toolbar-color, inherit));
color: var(--lwt-tab-text, var(--toolbar-color, inherit));
}
.tab-line {

View File

@ -4,6 +4,9 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
%endif
%define fieldBorderColor hsla(240,5%,5%,.25)
%define fieldHoverBorderColor hsla(240,5%,5%,.35)
:root {
/* 28x28 box - 16x16 image = 12x12 padding, 6 on each side */
--urlbar-icon-padding: 6px;
@ -23,7 +26,7 @@
.searchbar-textbox {
-moz-appearance: none;
background-clip: content-box;
border: 1px solid hsla(240,5%,5%,.25);
border: 1px solid @fieldBorderColor@;
border-radius: var(--toolbarbutton-border-radius);
box-shadow: 0 1px 4px rgba(0,0,0,.05);
padding: 0;
@ -35,7 +38,7 @@
#urlbar:hover,
.searchbar-textbox:hover {
border-color: hsla(240,5%,5%,.35);
border-color: @fieldHoverBorderColor@;
box-shadow: 0 1px 6px rgba(0,0,0,.1);
}
@ -47,7 +50,12 @@
#urlbar:not([focused="true"]):-moz-lwtheme,
#navigator-toolbox .searchbar-textbox:not([focused="true"]):-moz-lwtheme {
border-color: var(--url-and-searchbar-border-color, hsla(240,5%,5%,.25));
border-color: var(--lwt-toolbar-field-border-color, @fieldBorderColor@);
}
#urlbar:not([focused="true"]):-moz-lwtheme:hover,
#navigator-toolbox .searchbar-textbox:not([focused="true"]):-moz-lwtheme:hover {
border-color: var(--lwt-toolbar-field-border-color, @fieldHoverBorderColor@);
}
#urlbar:-moz-lwtheme:hover,

View File

@ -5,7 +5,7 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
@template
def GeckoBinary(linkage='dependent', msvcrt='dynamic', mozglue=None):
def GeckoBinary(linkage='dependent', mozglue=None):
'''Template for Gecko-related binaries.
This template is meant to be used in other templates.
@ -17,28 +17,11 @@ def GeckoBinary(linkage='dependent', msvcrt='dynamic', mozglue=None):
uses the standalone XPCOM glue to load libxul. None means no XPCOM glue
or libxul linkage at all.
`msvcrt` indicates which Microsoft Visual Studio CRT, for Windows build,
ought to be linked: 'static' or 'dynamic'.
`mozglue` indicates whether to link against the mozglue library, and if
so, what linkage to apply. Valid values are None (mozglue not linked),
'program' (mozglue linked to an executable program), or 'library' (mozglue
linked to a shared library).
'''
if msvcrt == 'dynamic' or CONFIG['OS_ARCH'] != 'WINNT' or CONFIG['MOZ_ASAN']:
xpcomglue = 'xpcomglue'
elif msvcrt == 'static':
USE_STATIC_LIBS = True
xpcomglue = 'xpcomglue_staticruntime'
if not CONFIG['GNU_CC']:
mozglue = None
if linkage == 'dependent':
USE_LIBS += [
'mozalloc_staticruntime',
]
else:
error('msvcrt must be "dynamic" or "static"')
if linkage == 'dependent':
USE_LIBS += [
'nspr',
@ -48,7 +31,7 @@ def GeckoBinary(linkage='dependent', msvcrt='dynamic', mozglue=None):
DEFINES['XPCOM_GLUE'] = True
USE_LIBS += [
xpcomglue,
'xpcomglue',
]
elif linkage != None:
error('`linkage` must be "dependent", "standalone" or None')

View File

@ -2,6 +2,7 @@ mozilla.pth:python/mach
mozilla.pth:python/mozboot
mozilla.pth:python/mozbuild
mozilla.pth:python/mozlint
mozilla.pth:python/mozterm
mozilla.pth:python/mozversioncontrol
mozilla.pth:third_party/python/blessings
mozilla.pth:third_party/python/compare-locales

View File

@ -58,7 +58,7 @@ public:
, public BaseURIMutator<NullPrincipalURI>
{
NS_DECL_ISUPPORTS
NS_FORWARD_SAFE_NSIURISETTERS(mURI)
NS_FORWARD_SAFE_NSIURISETTERS_RET(mURI)
NS_IMETHOD Deserialize(const mozilla::ipc::URIParams& aParams) override
{
@ -76,8 +76,9 @@ public:
return NS_OK;
}
NS_IMETHOD SetSpec(const nsACString & aSpec) override
NS_IMETHOD SetSpec(const nsACString & aSpec, nsIURIMutator** aMutator) override
{
NS_ADDREF(*aMutator = this);
return NS_ERROR_NOT_IMPLEMENTED;
}

View File

@ -3053,7 +3053,8 @@ exports.CSS_PROPERTIES = {
"-moz-outline-radius-topright",
"outline-style",
"outline-width",
"overflow-clip-box",
"overflow-clip-box-block",
"overflow-clip-box-inline",
"overflow-x",
"overflow-y",
"padding-block-end",
@ -9954,6 +9955,14 @@ exports.PREFERENCES = [
"overflow-clip-box",
"layout.css.overflow-clip-box.enabled"
],
[
"overflow-clip-box-block",
"layout.css.overflow-clip-box.enabled"
],
[
"overflow-clip-box-inline",
"layout.css.overflow-clip-box.enabled"
],
[
"paint-order",
"svg.paint-order.enabled"

View File

@ -24,9 +24,9 @@ promise_test(function(t) {
'Initial value of margin-left is zero');
animation.play();
return animation.ready.then(waitForFrame).then(function() {
assert_true(getMarginLeft(cs) > 0,
'Playing value of margin-left is greater than zero');
return animation.ready.then(waitForNextFrame).then(function() {
assert_greater_than(getMarginLeft(cs), 0,
'Playing value of margin-left is greater than zero');
});
}, 'play() overrides animation-play-state');
@ -41,7 +41,7 @@ promise_test(function(t) {
animation.pause();
div.style.animationPlayState = 'running';
return animation.ready.then(waitForFrame).then(function() {
return animation.ready.then(waitForNextFrame).then(function() {
assert_equals(cs.animationPlayState, 'running',
'animation-play-state is running');
assert_equals(getMarginLeft(cs), 0,
@ -62,7 +62,7 @@ promise_test(function(t) {
return animation.ready.then(function() {
div.style.animationPlayState = 'running';
cs.animationPlayState; // Trigger style resolution
return waitForFrame();
return waitForNextFrame();
}).then(function() {
assert_equals(cs.animationPlayState, 'running',
'animation-play-state is running');
@ -72,7 +72,7 @@ promise_test(function(t) {
assert_equals(cs.animationPlayState, 'paused',
'animation-play-state is paused');
previousAnimVal = getMarginLeft(cs);
return waitForFrame();
return waitForNextFrame();
}).then(function() {
assert_equals(getMarginLeft(cs), previousAnimVal,
'Animated value of margin-left does not change when'
@ -95,11 +95,11 @@ promise_test(function(t) {
animation.play();
var previousAnimVal = getMarginLeft(cs);
return animation.ready.then(waitForFrame).then(function() {
return animation.ready.then(waitForNextFrame).then(function() {
assert_equals(cs.animationPlayState, 'paused',
'animation-play-state is paused');
assert_true(getMarginLeft(cs) > previousAnimVal,
'Playing value of margin-left is increasing');
assert_greater_than(getMarginLeft(cs), previousAnimVal,
'Playing value of margin-left is increasing');
});
}, 'play() flushes pending changes to animation-play-state first');
@ -125,7 +125,7 @@ promise_test(function(t) {
animation.pause();
var previousAnimVal = getMarginLeft(cs);
return animation.ready.then(waitForFrame).then(function() {
return animation.ready.then(waitForNextFrame).then(function() {
assert_equals(cs.animationPlayState, 'running',
'animation-play-state is running');
assert_equals(getMarginLeft(cs), previousAnimVal,

View File

@ -24,14 +24,14 @@ async_test(function(t) {
'Initial value of margin-left is zero');
var previousAnimVal = getMarginLeft(cs);
animation.ready.then(waitForFrame).then(t.step_func(function() {
assert_true(getMarginLeft(cs) > previousAnimVal,
'margin-left is initially increasing');
animation.ready.then(waitForNextFrame).then(t.step_func(function() {
assert_greater_than(getMarginLeft(cs), previousAnimVal,
'margin-left is initially increasing');
animation.pause();
return animation.ready;
})).then(t.step_func(function() {
previousAnimVal = getMarginLeft(cs);
return waitForFrame();
return waitForNextFrame();
})).then(t.step_func(function() {
assert_equals(getMarginLeft(cs), previousAnimVal,
'margin-left does not increase after calling pause()');
@ -39,8 +39,8 @@ async_test(function(t) {
animation.play();
return animation.ready.then(waitForFrame);
})).then(t.step_func(function() {
assert_true(getMarginLeft(cs) > previousAnimVal,
'margin-left increases after calling play()');
assert_greater_than(getMarginLeft(cs), previousAnimVal,
'margin-left increases after calling play()');
t.done();
}));
}, 'pause() and play() a transition');

View File

@ -83,7 +83,7 @@ public:
, public BaseURIMutator<nsHostObjectURI>
{
NS_DECL_ISUPPORTS
NS_FORWARD_SAFE_NSIURISETTERS(mURI)
NS_FORWARD_SAFE_NSIURISETTERS_RET(mURI)
NS_DEFINE_NSIMUTATOR_COMMON
explicit Mutator() { }

View File

@ -70,17 +70,25 @@ GridLine::Number() const
return mNumber;
}
int32_t
GridLine::NegativeNumber() const
{
return mNegativeNumber;
}
void
GridLine::SetLineValues(const nsTArray<nsString>& aNames,
double aStart,
double aBreadth,
uint32_t aNumber,
int32_t aNegativeNumber,
GridDeclaration aType)
{
mNames = aNames;
mStart = aStart;
mBreadth = aBreadth;
mNumber = aNumber;
mNegativeNumber = aNegativeNumber;
mType = aType;
}

View File

@ -42,11 +42,13 @@ public:
double Breadth() const;
GridDeclaration Type() const;
uint32_t Number() const;
int32_t NegativeNumber() const;
void SetLineValues(const nsTArray<nsString>& aNames,
double aStart,
double aBreadth,
uint32_t aNumber,
int32_t aNegativeNumber,
GridDeclaration aType);
protected:
@ -56,6 +58,7 @@ protected:
double mBreadth;
GridDeclaration mType;
uint32_t mNumber;
int32_t mNegativeNumber;
};
} // namespace dom

View File

@ -75,18 +75,34 @@ GridLines::SetLineInfo(const ComputedGridTrackInfo* aTrackInfo,
return;
}
uint32_t trackCount = aTrackInfo->mEndFragmentTrack -
aTrackInfo->mStartFragmentTrack;
uint32_t lineCount = aTrackInfo->mEndFragmentTrack -
aTrackInfo->mStartFragmentTrack +
1;
// If there is at least one track, line count is one more
// than the number of tracks.
if (trackCount > 0) {
if (lineCount > 0) {
nscoord lastTrackEdge = 0;
nscoord startOfNextTrack;
uint32_t repeatIndex = 0;
uint32_t numRepeatTracks = aTrackInfo->mRemovedRepeatTracks.Length();
uint32_t numAddedLines = 0;
// For the calculation of negative line numbers, we need to know
// the total number of leading implicit and explicit tracks.
// This might be different from the number of tracks sizes in
// aTrackInfo, because some of those tracks may be auto-fits that
// have been removed.
uint32_t leadingTrackCount = aTrackInfo->mNumLeadingImplicitTracks +
aTrackInfo->mNumExplicitTracks;
if (numRepeatTracks > 0) {
for (auto& removedTrack : aTrackInfo->mRemovedRepeatTracks) {
if (removedTrack) {
++leadingTrackCount;
}
}
}
for (uint32_t i = aTrackInfo->mStartFragmentTrack;
i < aTrackInfo->mEndFragmentTrack + 1;
i++) {
@ -137,6 +153,7 @@ GridLines::SetLineInfo(const ComputedGridTrackInfo* aTrackInfo,
lastTrackEdge,
repeatIndex,
numRepeatTracks,
leadingTrackCount,
lineNames);
}
@ -145,6 +162,7 @@ GridLines::SetLineInfo(const ComputedGridTrackInfo* aTrackInfo,
MOZ_ASSERT(line1Index > 0, "line1Index must be positive.");
bool isBeforeFirstExplicit =
(line1Index <= aTrackInfo->mNumLeadingImplicitTracks);
bool isAfterLastExplicit = line1Index > (leadingTrackCount + 1);
// Calculate an actionable line number for this line, that could be used
// in a css grid property to align a grid item or area at that line.
// For implicit lines that appear before line 1, report a number of 0.
@ -152,11 +170,13 @@ GridLines::SetLineInfo(const ComputedGridTrackInfo* aTrackInfo,
// meaning in the css grid spec (negative indexes are negative-1-based
// from the end of the grid decreasing towards the front).
uint32_t lineNumber = isBeforeFirstExplicit ? 0 :
(line1Index - aTrackInfo->mNumLeadingImplicitTracks + numAddedLines);
(line1Index + numAddedLines - aTrackInfo->mNumLeadingImplicitTracks);
// The negativeNumber is counted back from the leadingTrackCount.
int32_t lineNegativeNumber = isAfterLastExplicit ? 0 :
(line1Index + numAddedLines - (leadingTrackCount + 2));
GridDeclaration lineType =
(isBeforeFirstExplicit ||
line1Index > (aTrackInfo->mNumLeadingImplicitTracks +
aTrackInfo->mNumExplicitTracks + 1))
(isBeforeFirstExplicit || isAfterLastExplicit)
? GridDeclaration::Implicit
: GridDeclaration::Explicit;
line->SetLineValues(
@ -165,6 +185,7 @@ GridLines::SetLineInfo(const ComputedGridTrackInfo* aTrackInfo,
nsPresContext::AppUnitsToDoubleCSSPixels(startOfNextTrack -
lastTrackEdge),
lineNumber,
lineNegativeNumber,
lineType
);
@ -181,6 +202,7 @@ GridLines::AppendRemovedAutoFits(const ComputedGridTrackInfo* aTrackInfo,
nscoord aLastTrackEdge,
uint32_t& aRepeatIndex,
uint32_t aNumRepeatTracks,
uint32_t aNumLeadingTracks,
nsTArray<nsString>& aLineNames)
{
// Check to see if lineNames contains ALL of the before line names.
@ -225,13 +247,29 @@ GridLines::AppendRemovedAutoFits(const ComputedGridTrackInfo* aTrackInfo,
RefPtr<GridLine> line = new GridLine(this);
mLines.AppendElement(line);
// Time to calculate the line numbers. For the positive numbers
// we count with a 1-based index from mRepeatFirstTrack. Although
// this number is the index of the first repeat track AFTER all
// the leading implicit tracks, that's still what we want since
// all those leading implicit tracks have line number 0.
uint32_t lineNumber = aTrackInfo->mRepeatFirstTrack +
aRepeatIndex + 1;
// The negative number does have to account for the leading
// implicit tracks. We've been passed aNumLeadingTracks which is
// the total of the leading implicit tracks plus the explicit
// tracks. So all we have to do is subtract that number plus one
// from the 0-based index of this track.
int32_t lineNegativeNumber = (aTrackInfo->mNumLeadingImplicitTracks +
aTrackInfo->mRepeatFirstTrack +
aRepeatIndex) - (aNumLeadingTracks + 1);
line->SetLineValues(
aLineNames,
nsPresContext::AppUnitsToDoubleCSSPixels(aLastTrackEdge),
nsPresContext::AppUnitsToDoubleCSSPixels(0),
lineNumber,
lineNegativeNumber,
GridDeclaration::Explicit
);

View File

@ -50,6 +50,7 @@ protected:
nscoord aLastTrackEdge,
uint32_t& aRepeatIndex,
uint32_t aNumRepeatTracks,
uint32_t aNumLeadingTracks,
nsTArray<nsString>& aLineNames);
RefPtr<GridDimension> mParent;

View File

@ -267,11 +267,22 @@ function runTests() {
4,
5,
];
let expectedNegativeNumber = [
-7,
-6,
-5,
-4,
-3,
-2,
-1,
0,
];
for (let i = 0; i < grid.cols.lines.length; i++) {
let line = grid.cols.lines[i];
is(line.type, expectedType[i], "Line index " + i + " has expected type.");
is(line.number, expectedNumber[i], "Line index " + i + " has expected number.");
is(line.negativeNumber, expectedNegativeNumber[i], "Line index " + i + " has expected negative number.");
}
}

View File

@ -18,12 +18,12 @@ body {
color: #fff;
}
.repeatColumns {
width: 600px;
width: 400px;
grid-auto-columns: 50px;
grid-template-columns: repeat(auto-fit, 100px);
}
.repeatRows {
height: 600px;
height: 400px;
grid-auto-rows: 50px;
grid-template-rows: repeat(auto-fit, 100px);
}
@ -38,6 +38,7 @@ function testLines(elementName, lines, expectedValues) {
is(lines.count, expectedValues.count, elementName + " has expected number of lines.");
for (let i = 0; i < lines.length; i++) {
is(lines[i].number, expectedValues[i].number, elementName + " line index " + i + " has expected number.");
is(lines[i].negativeNumber, expectedValues[i].negativeNumber, elementName + " line index " + i + " has expected negativeNumber.");
}
}
@ -49,32 +50,53 @@ function runTests() {
grid = document.getElementById("gridWithColumns").getGridFragments()[0];
lines = grid.cols.lines;
expectedValues = [
{ "number": 0 },
{ "number": 0 },
{ "number": 1 },
{ "number": 2 },
{ "number": 3 },
{ "number": 4 },
{ "number": 5 },
{ "number": 6 },
{ "number": 7 },
{ "number": 8 },
{ "number": 0,
"negativeNumber": -9 },
{ "number": 0,
"negativeNumber": -8 },
{ "number": 0,
"negativeNumber": -7 },
{ "number": 0,
"negativeNumber": -6 },
{ "number": 1,
"negativeNumber": -5 },
{ "number": 2,
"negativeNumber": -4 },
{ "number": 3,
"negativeNumber": -3 },
{ "number": 4,
"negativeNumber": -2 },
{ "number": 5,
"negativeNumber": -1 },
{ "number": 6,
"negativeNumber": 0 },
];
testLines("gridWithColumns", lines, expectedValues);
grid = document.getElementById("gridWithRows").getGridFragments()[0];
lines = grid.rows.lines;
expectedValues = [
{ "number": 0 },
{ "number": 0 },
{ "number": 1 },
{ "number": 2 },
{ "number": 3 },
{ "number": 4 },
{ "number": 5 },
{ "number": 6 },
{ "number": 7 },
{ "number": 8 },
{ "number": 0,
"negativeNumber": -9 },
{ "number": 0,
"negativeNumber": -8 },
{ "number": 0,
"negativeNumber": -7 },
{ "number": 0,
"negativeNumber": -6 },
{ "number": 1,
"negativeNumber": -5 },
{ "number": 2,
"negativeNumber": -4 },
{ "number": 3,
"negativeNumber": -3 },
{ "number": 4,
"negativeNumber": -2 },
{ "number": 5,
"negativeNumber": -1 },
{ "number": 6,
"negativeNumber": 0 },
];
testLines("gridWithRows", lines, expectedValues);
@ -86,15 +108,14 @@ function runTests() {
<div id="gridWithColumns" class="wrapper repeatColumns">
<div style="grid-column: -9">A</div>
<div style="grid-column: 4">B</div>
<div style="grid-column: 7">C</div>
<div style="grid-column: 2">B</div>
<div style="grid-column: 5">C</div>
</div>
<div id="gridWithRows" class="wrapper repeatRows">
<div style="grid-row: span 3 / 2">A</div>
<div style="grid-row: 4">B</div>
<div style="grid-row: 5">C</div>
<div style="grid-row: span 2 / 8">D</div>
<div style="grid-row: span 4 / 1">A</div>
<div style="grid-row: 3">B</div>
<div style="grid-row: 4 / span 2">C</div>
</div>
</body>

View File

@ -47,8 +47,9 @@ function runTests() {
// test column line width
is(grid.cols.lines[1].breadth, 10, "Grid column line 2 width is as expected.");
// test column line number
is(grid.cols.lines[3].number, 4, "Grid column line 4 number is as expected.");
// test column line numbers, positive and negative
is(grid.cols.lines[3].number, 4, "Grid column line 4 positive number is as expected.");
is(grid.cols.lines[3].negativeNumber, -2, "Grid column line 4 negative number is as expected.");
// test column line names
is(grid.cols.lines[0].names.length, 0, "Grid column line 1 has no names.");

View File

@ -12,6 +12,7 @@ body {
display: grid;
width: 600px;
grid-gap: 0px;
grid-auto-column: 50px;
background-color: #f00;
}
.grid1 {
@ -44,6 +45,10 @@ body {
.grid10 {
grid-template-columns: [real-before] repeat(auto-fit, [before] 100px) [real-after];
}
.grid11 {
grid-template-columns: repeat(auto-fit, 100px);
}
.box {
background-color: #444;
color: #fff;
@ -63,6 +68,9 @@ body {
.e {
grid-column: 5;
}
.f {
grid-column: -9;
}
</style>
@ -72,17 +80,52 @@ body {
SimpleTest.waitForExplicitFinish();
function testLines(elementName, grid, expectedValues) {
is(grid.cols.lines.length, expectedValues.length, elementName + " has expected number of lines.");
for (let i = 0; i < grid.cols.lines.length; i++) {
is(grid.cols.lines[i].number, (i + 1), elementName + " line " + (i + 1) + " has expected number.");
is(grid.cols.lines[i].start, expectedValues[i].start, elementName + " line " + (i + 1) + " has expected start.");
is(grid.cols.lines[i].breadth, 0, elementName + " line " + (i + 1) + " has zero breadth.");
is(grid.cols.lines[i].names + "", expectedValues[i].names, elementName + " line " + (i + 1) + " has expected names.");
// 'number' is optional.
if (typeof(expectedValues[i].number) != "undefined") {
is(grid.cols.lines[i].number, expectedValues[i].number, elementName + " line " + (i + 1) + " has expected number.");
} else {
// If 'number' is omitted, assume that first line is line 1 and increase from there.
is(grid.cols.lines[i].number, (i + 1), elementName + " line " + (i + 1) + " has expected number.");
}
// 'negativeNumber' is optional.
if (typeof(expectedValues[i].negativeNumber) != "undefined") {
// Check for the supplied number.
is(grid.cols.lines[i].negativeNumber, expectedValues[i].negativeNumber, elementName + " line " + (i + 1) + " has expected negativeNumber.");
}
// 'start' is optional.
if (typeof(expectedValues[i].start) != "undefined") {
is(grid.cols.lines[i].start, expectedValues[i].start, elementName + " line " + (i + 1) + " has expected start.");
}
// 'breadth' is optional.
if (typeof(expectedValues[i].breadth) != "undefined") {
is(grid.cols.lines[i].breadth, 0, elementName + " line " + (i + 1) + " has zero breadth.");
}
// 'names' is optional.
if (typeof(expectedValues[i].names) != "undefined") {
is(grid.cols.lines[i].names + "", expectedValues[i].names, elementName + " line " + (i + 1) + " has expected names.");
}
// 'todo_names' is optional.
if (typeof(expectedValues[i].todo_names) != "undefined") {
todo_is(grid.cols.lines[i].names + "", expectedValues[i].todo_names, elementName + " line " + (i + 1) + " has expected names.");
}
}
}
function runTests() {
let wrapper = document.getElementById("wrapper1");
let grid = wrapper.getGridFragments()[0];
let wrapper;
let grid;
let expectedValues;
wrapper = document.getElementById("wrapper1");
grid = wrapper.getGridFragments()[0];
// test auto-fit count
is(grid.cols.tracks.length, 7, "Grid column track array reports removed auto-fit columns.");
@ -93,7 +136,7 @@ function runTests() {
"Resolved value of grid-template-columns reports removed auto-fits as '0px'.");
// test starts, breadths, and states
let expectedValues = [
expectedValues = [
{ "start": 0,
"breadth": 50,
"state": "static" },
@ -244,9 +287,9 @@ function runTests() {
// test starts and names
expectedValues = [
{ "start": 0,
"names": "real-before,before" },
"todo_names": "real-before,before" },
{ "start": 0,
"names": "after,real-after" },
"todo_names": "after,real-after" },
];
testLines("wrapper8", grid, expectedValues);

View File

@ -110,7 +110,7 @@ public:
, public BaseURIMutator<nsJSURI>
{
NS_DECL_ISUPPORTS
NS_FORWARD_SAFE_NSIURISETTERS(mURI)
NS_FORWARD_SAFE_NSIURISETTERS_RET(mURI)
NS_DEFINE_NSIMUTATOR_COMMON
explicit Mutator() { }

View File

@ -0,0 +1,198 @@
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "BackgroundVideoDecodingPermissionObserver.h"
#include "mozilla/AsyncEventDispatcher.h"
#include "MediaDecoder.h"
#include "MediaPrefs.h"
#include "nsContentUtils.h"
#include "nsIDocument.h"
namespace mozilla {
BackgroundVideoDecodingPermissionObserver::
BackgroundVideoDecodingPermissionObserver(MediaDecoder* aDecoder)
: mDecoder(aDecoder)
, mIsRegisteredForEvent(false)
{
MOZ_ASSERT(mDecoder);
}
NS_IMETHODIMP
BackgroundVideoDecodingPermissionObserver::Observe(nsISupports* aSubject,
const char* aTopic,
const char16_t* aData)
{
if (!MediaPrefs::ResumeVideoDecodingOnTabHover()) {
return NS_OK;
}
if (!IsValidEventSender(aSubject)) {
return NS_OK;
}
if (strcmp(aTopic, "unselected-tab-hover") == 0) {
bool allowed = !NS_strcmp(aData, u"true");
mDecoder->SetIsBackgroundVideoDecodingAllowed(allowed);
}
return NS_OK;
}
void
BackgroundVideoDecodingPermissionObserver::RegisterEvent()
{
MOZ_ASSERT(!mIsRegisteredForEvent);
nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
if (observerService) {
observerService->AddObserver(this, "unselected-tab-hover", false);
mIsRegisteredForEvent = true;
if (nsContentUtils::IsInStableOrMetaStableState()) {
// Events shall not be fired synchronously to prevent anything visible
// from the scripts while we are in stable state.
if (nsCOMPtr<nsIDocument> doc = GetOwnerDoc()) {
doc->Dispatch(
TaskCategory::Other,
NewRunnableMethod(
"BackgroundVideoDecodingPermissionObserver::"
"EnableEvent",
this,
&BackgroundVideoDecodingPermissionObserver::
EnableEvent));
}
} else {
EnableEvent();
}
}
}
void
BackgroundVideoDecodingPermissionObserver::UnregisterEvent()
{
MOZ_ASSERT(mIsRegisteredForEvent);
nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
if (observerService) {
observerService->RemoveObserver(this, "unselected-tab-hover");
mIsRegisteredForEvent = false;
mDecoder->SetIsBackgroundVideoDecodingAllowed(false);
if (nsContentUtils::IsInStableOrMetaStableState()) {
// Events shall not be fired synchronously to prevent anything visible
// from the scripts while we are in stable state.
if (nsCOMPtr<nsIDocument> doc = GetOwnerDoc()) {
doc->Dispatch(
TaskCategory::Other,
NewRunnableMethod(
"BackgroundVideoDecodingPermissionObserver::"
"DisableEvent",
this,
&BackgroundVideoDecodingPermissionObserver::
DisableEvent));
}
} else {
DisableEvent();
}
}
}
BackgroundVideoDecodingPermissionObserver::
~BackgroundVideoDecodingPermissionObserver()
{
MOZ_ASSERT(!mIsRegisteredForEvent);
}
void
BackgroundVideoDecodingPermissionObserver::EnableEvent() const
{
nsIDocument* doc = GetOwnerDoc();
if (!doc) {
return;
}
RefPtr<AsyncEventDispatcher> asyncDispatcher =
new AsyncEventDispatcher(doc,
NS_LITERAL_STRING("UnselectedTabHover:Enable"),
/* Bubbles */ true,
/* OnlyChromeDispatch */ true);
asyncDispatcher->PostDOMEvent();
}
void
BackgroundVideoDecodingPermissionObserver::DisableEvent() const
{
nsIDocument* doc = GetOwnerDoc();
if (!doc) {
return;
}
RefPtr<AsyncEventDispatcher> asyncDispatcher =
new AsyncEventDispatcher(doc,
NS_LITERAL_STRING("UnselectedTabHover:Disable"),
/* Bubbles */ true,
/* OnlyChromeDispatch */ true);
asyncDispatcher->PostDOMEvent();
}
already_AddRefed<nsPIDOMWindowOuter>
BackgroundVideoDecodingPermissionObserver::GetOwnerWindow() const
{
nsIDocument* doc = GetOwnerDoc();
if (!doc) {
return nullptr;
}
nsCOMPtr<nsPIDOMWindowInner> innerWin = doc->GetInnerWindow();
if (!innerWin) {
return nullptr;
}
nsCOMPtr<nsPIDOMWindowOuter> outerWin = innerWin->GetOuterWindow();
if (!outerWin) {
return nullptr;
}
nsCOMPtr<nsPIDOMWindowOuter> topWin = outerWin->GetTop();
return topWin.forget();
}
nsIDocument*
BackgroundVideoDecodingPermissionObserver::GetOwnerDoc() const
{
if (!mDecoder->GetOwner()) {
return nullptr;
}
return mDecoder->GetOwner()->GetDocument();
}
bool
BackgroundVideoDecodingPermissionObserver::IsValidEventSender(
nsISupports* aSubject) const
{
nsCOMPtr<nsPIDOMWindowInner> senderInner(do_QueryInterface(aSubject));
if (!senderInner) {
return false;
}
nsCOMPtr<nsPIDOMWindowOuter> senderOuter = senderInner->GetOuterWindow();
if (!senderOuter) {
return false;
}
nsCOMPtr<nsPIDOMWindowOuter> senderTop = senderOuter->GetTop();
if (!senderTop) {
return false;
}
nsCOMPtr<nsPIDOMWindowOuter> ownerTop = GetOwnerWindow();
if (!ownerTop) {
return false;
}
return ownerTop == senderTop;
}
NS_IMPL_ISUPPORTS(BackgroundVideoDecodingPermissionObserver, nsIObserver)
} // namespace mozilla

View File

@ -0,0 +1,48 @@
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#if !defined(BackgroundVideoDecodingPermissionObserver_h_)
#define BackgroundVideoDecodingPermissionObserver_h_
#include "nsIObserver.h"
#include "nsISupportsImpl.h"
class nsIDocument;
class nsISupports;
class nsPIDOMWindowOuter;
namespace mozilla {
class MediaDecoder;
class BackgroundVideoDecodingPermissionObserver final
: public nsIObserver
{
public:
NS_DECL_ISUPPORTS
explicit BackgroundVideoDecodingPermissionObserver(MediaDecoder* aDecoder);
NS_IMETHOD Observe(nsISupports* aSubject, const char* aTopic,
const char16_t* aData) override;
void RegisterEvent();
void UnregisterEvent();
private:
~BackgroundVideoDecodingPermissionObserver();
void EnableEvent() const;
void DisableEvent() const;
already_AddRefed<nsPIDOMWindowOuter> GetOwnerWindow() const;
nsIDocument* GetOwnerDoc() const;
bool IsValidEventSender(nsISupports* aSubject) const;
// The life cycle of observer would always be shorter than decoder, so we
// use raw pointer here.
MediaDecoder* mDecoder;
bool mIsRegisteredForEvent;
};
} // namespace mozilla
#endif // BackgroundVideoDecodingPermissionObserver_h_

View File

@ -159,4 +159,13 @@ BaseMediaResource::ModifyLoadFlags(nsLoadFlags aFlags)
}
}
void
BaseMediaResource::DispatchBytesConsumed(int64_t aNumBytes, int64_t aOffset)
{
if (aNumBytes <= 0) {
return;
}
mCallback->NotifyBytesConsumed(aNumBytes, aOffset);
}
} // namespace mozilla

View File

@ -129,6 +129,10 @@ protected:
// then the request is added back to the load group.
void ModifyLoadFlags(nsLoadFlags aFlags);
// Dispatches an event to call MediaDecoder::NotifyBytesConsumed(aNumBytes, aOffset)
// on the main thread. This is called automatically after every read.
void DispatchBytesConsumed(int64_t aNumBytes, int64_t aOffset);
RefPtr<MediaResourceCallback> mCallback;
// Channel used to download the media data. Must be accessed

View File

@ -131,11 +131,30 @@ ChannelMediaDecoder::ResourceCallback::NotifySuspendedStatusChanged(
}
}
void
ChannelMediaDecoder::ResourceCallback::NotifyBytesConsumed(int64_t aBytes,
int64_t aOffset)
{
RefPtr<ResourceCallback> self = this;
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(
"ChannelMediaDecoder::ResourceCallback::NotifyBytesConsumed",
[=]() {
if (self->mDecoder) {
self->mDecoder->NotifyBytesConsumed(aBytes, aOffset);
}
});
mAbstractMainThread->Dispatch(r.forget());
}
ChannelMediaDecoder::ChannelMediaDecoder(MediaDecoderInit& aInit)
: MediaDecoder(aInit)
, mResourceCallback(new ResourceCallback(aInit.mOwner->AbstractMainThread()))
, mWatchManager(this, aInit.mOwner->AbstractMainThread())
{
mResourceCallback->Connect(this);
// mIgnoreProgressData
mWatchManager.Watch(mLogicallySeeking, &ChannelMediaDecoder::SeekingChanged);
}
/* static */
@ -202,6 +221,7 @@ MediaDecoderStateMachine* ChannelMediaDecoder::CreateStateMachine()
void
ChannelMediaDecoder::Shutdown()
{
mWatchManager.Shutdown();
mResourceCallback->Disconnect();
MediaDecoder::Shutdown();
@ -288,6 +308,30 @@ ChannelMediaDecoder::NotifyDownloadEnded(nsresult aStatus)
}
}
void
ChannelMediaDecoder::NotifyBytesConsumed(int64_t aBytes, int64_t aOffset)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
AbstractThread::AutoEnter context(AbstractMainThread());
if (mIgnoreProgressData) {
return;
}
MOZ_ASSERT(GetStateMachine());
mDecoderPosition = aOffset + aBytes;
}
void
ChannelMediaDecoder::SeekingChanged()
{
// Stop updating the bytes downloaded for progress notifications when
// seeking to prevent wild changes to the progress notification.
MOZ_ASSERT(NS_IsMainThread());
mIgnoreProgressData = mLogicallySeeking;
}
bool
ChannelMediaDecoder::CanPlayThroughImpl()
{
@ -400,7 +444,7 @@ ChannelMediaDecoder::GetStatistics(const PlaybackRateInfo& aInfo)
MediaStatistics result;
result.mDownloadRate =
mResource->GetDownloadRate(&result.mDownloadRateReliable);
result.mDownloadPosition = mResource->GetCachedDataEnd(mPlaybackPosition);
result.mDownloadPosition = mResource->GetCachedDataEnd(mDecoderPosition);
result.mTotalBytes = mResource->GetLength();
result.mPlaybackRate = aInfo.mRate;
result.mPlaybackRateReliable = aInfo.mReliable;

View File

@ -44,6 +44,7 @@ class ChannelMediaDecoder : public MediaDecoder
void NotifyDataEnded(nsresult aStatus) override;
void NotifyPrincipalChanged() override;
void NotifySuspendedStatusChanged(bool aSuspendedByCache) override;
void NotifyBytesConsumed(int64_t aBytes, int64_t aOffset) override;
static void TimerCallback(nsITimer* aTimer, void* aClosure);
@ -114,6 +115,8 @@ private:
// by the MediaResource read functions.
void NotifyBytesConsumed(int64_t aBytes, int64_t aOffset);
void SeekingChanged();
bool CanPlayThroughImpl() override final;
bool IsLiveStream() override final;
@ -138,6 +141,14 @@ private:
bool ShouldThrottleDownload(const MediaStatistics& aStats);
WatchManager<ChannelMediaDecoder> mWatchManager;
// True when seeking or otherwise moving the play position around in
// such a manner that progress event data is inaccurate. This is set
// during seek and duration operations to prevent the progress indicator
// from jumping around. Read/Write on the main thread only.
bool mIgnoreProgressData = false;
// Data needed to estimate playback data rate. The timeline used for
// this estimate is "decode time" (where the "current time" is the
// time of the last decoded video frame).

View File

@ -621,7 +621,12 @@ nsresult ChannelMediaResource::ReadAt(int64_t aOffset,
uint32_t* aBytes)
{
NS_ASSERTION(!NS_IsMainThread(), "Don't call on main thread");
return mCacheStream.ReadAt(aOffset, aBuffer, aCount, aBytes);
nsresult rv = mCacheStream.ReadAt(aOffset, aBuffer, aCount, aBytes);
if (NS_SUCCEEDED(rv)) {
DispatchBytesConsumed(*aBytes, aOffset);
}
return rv;
}
void

View File

@ -171,6 +171,9 @@ FileMediaResource::ReadAt(int64_t aOffset, char* aBuffer, uint32_t aCount,
if (NS_FAILED(rv)) return rv;
rv = UnsafeRead(aBuffer, aCount, aBytes);
}
if (NS_SUCCEEDED(rv)) {
DispatchBytesConsumed(*aBytes, aOffset);
}
return rv;
}

View File

@ -6,6 +6,8 @@
#if !defined(MediaChannelStatistics_h_)
#define MediaChannelStatistics_h_
#include "mozilla/TimeStamp.h"
namespace mozilla {
// Number of bytes we have accumulated before we assume the connection download

View File

@ -15,17 +15,12 @@
#include "VideoFrameContainer.h"
#include "VideoUtils.h"
#include "mozilla/AbstractThread.h"
#include "mozilla/AsyncEventDispatcher.h"
#include "mozilla/FloatingPoint.h"
#include "mozilla/MathAlgorithms.h"
#include "mozilla/Preferences.h"
#include "mozilla/StaticPtr.h"
#include "mozilla/Telemetry.h"
#include "mozilla/dom/AudioTrack.h"
#include "mozilla/dom/AudioTrackList.h"
#include "mozilla/dom/VideoTrack.h"
#include "mozilla/dom/VideoTrackList.h"
#include "mozilla/layers/ShadowLayers.h"
#include "Visibility.h"
#include "mozilla/Unused.h"
#include "nsComponentManagerUtils.h"
#include "nsContentUtils.h"
@ -123,177 +118,6 @@ public:
}
};
class MediaDecoder::BackgroundVideoDecodingPermissionObserver final :
public nsIObserver
{
public:
NS_DECL_ISUPPORTS
explicit BackgroundVideoDecodingPermissionObserver(MediaDecoder* aDecoder)
: mDecoder(aDecoder)
, mIsRegisteredForEvent(false)
{
MOZ_ASSERT(mDecoder);
}
NS_IMETHOD Observe(nsISupports* aSubject, const char* aTopic,
const char16_t* aData) override
{
if (!MediaPrefs::ResumeVideoDecodingOnTabHover()) {
return NS_OK;
}
if (!IsValidEventSender(aSubject)) {
return NS_OK;
}
if (strcmp(aTopic, "unselected-tab-hover") == 0) {
mDecoder->mIsBackgroundVideoDecodingAllowed = !NS_strcmp(aData, u"true");
mDecoder->UpdateVideoDecodeMode();
}
return NS_OK;
}
void RegisterEvent() {
MOZ_ASSERT(!mIsRegisteredForEvent);
nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
if (observerService) {
observerService->AddObserver(this, "unselected-tab-hover", false);
mIsRegisteredForEvent = true;
if (nsContentUtils::IsInStableOrMetaStableState()) {
// Events shall not be fired synchronously to prevent anything visible
// from the scripts while we are in stable state.
if (nsCOMPtr<nsIDocument> doc = GetOwnerDoc()) {
doc->Dispatch(TaskCategory::Other,
NewRunnableMethod(
"MediaDecoder::BackgroundVideoDecodingPermissionObserver::EnableEvent",
this, &MediaDecoder::BackgroundVideoDecodingPermissionObserver::EnableEvent));
}
} else {
EnableEvent();
}
}
}
void UnregisterEvent() {
MOZ_ASSERT(mIsRegisteredForEvent);
nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
if (observerService) {
observerService->RemoveObserver(this, "unselected-tab-hover");
mIsRegisteredForEvent = false;
mDecoder->mIsBackgroundVideoDecodingAllowed = false;
mDecoder->UpdateVideoDecodeMode();
if (nsContentUtils::IsInStableOrMetaStableState()) {
// Events shall not be fired synchronously to prevent anything visible
// from the scripts while we are in stable state.
if (nsCOMPtr<nsIDocument> doc = GetOwnerDoc()) {
doc->Dispatch(TaskCategory::Other,
NewRunnableMethod(
"MediaDecoder::BackgroundVideoDecodingPermissionObserver::DisableEvent",
this, &MediaDecoder::BackgroundVideoDecodingPermissionObserver::DisableEvent));
}
} else {
DisableEvent();
}
}
}
private:
~BackgroundVideoDecodingPermissionObserver() {
MOZ_ASSERT(!mIsRegisteredForEvent);
}
void EnableEvent() const
{
nsIDocument* doc = GetOwnerDoc();
if (!doc) {
return;
}
RefPtr<AsyncEventDispatcher> asyncDispatcher =
new AsyncEventDispatcher(doc,
NS_LITERAL_STRING("UnselectedTabHover:Enable"),
/* Bubbles */ true,
/* OnlyChromeDispatch */ true);
asyncDispatcher->PostDOMEvent();
}
void DisableEvent() const
{
nsIDocument* doc = GetOwnerDoc();
if (!doc) {
return;
}
RefPtr<AsyncEventDispatcher> asyncDispatcher =
new AsyncEventDispatcher(doc,
NS_LITERAL_STRING("UnselectedTabHover:Disable"),
/* Bubbles */ true,
/* OnlyChromeDispatch */ true);
asyncDispatcher->PostDOMEvent();
}
already_AddRefed<nsPIDOMWindowOuter> GetOwnerWindow() const
{
nsIDocument* doc = GetOwnerDoc();
if (!doc) {
return nullptr;
}
nsCOMPtr<nsPIDOMWindowInner> innerWin = doc->GetInnerWindow();
if (!innerWin) {
return nullptr;
}
nsCOMPtr<nsPIDOMWindowOuter> outerWin = innerWin->GetOuterWindow();
if (!outerWin) {
return nullptr;
}
nsCOMPtr<nsPIDOMWindowOuter> topWin = outerWin->GetTop();
return topWin.forget();
}
nsIDocument* GetOwnerDoc() const
{
if (!mDecoder->mOwner) {
return nullptr;
}
return mDecoder->mOwner->GetDocument();
}
bool IsValidEventSender(nsISupports* aSubject) const
{
nsCOMPtr<nsPIDOMWindowInner> senderInner(do_QueryInterface(aSubject));
if (!senderInner) {
return false;
}
nsCOMPtr<nsPIDOMWindowOuter> senderOuter = senderInner->GetOuterWindow();
if (!senderOuter) {
return false;
}
nsCOMPtr<nsPIDOMWindowOuter> senderTop = senderOuter->GetTop();
if (!senderTop) {
return false;
}
nsCOMPtr<nsPIDOMWindowOuter> ownerTop = GetOwnerWindow();
if (!ownerTop) {
return false;
}
return ownerTop == senderTop;
}
// The life cycle of observer would always be shorter than decoder, so we
// use raw pointer here.
MediaDecoder* mDecoder;
bool mIsRegisteredForEvent;
};
NS_IMPL_ISUPPORTS(MediaDecoder::BackgroundVideoDecodingPermissionObserver, nsIObserver)
StaticRefPtr<MediaMemoryTracker> MediaMemoryTracker::sUniqueInstance;
LazyLogModule gMediaTimerLog("MediaTimer");
@ -1200,6 +1024,13 @@ MediaDecoder::UpdateVideoDecodeMode()
}
}
void
MediaDecoder::SetIsBackgroundVideoDecodingAllowed(bool aAllowed)
{
mIsBackgroundVideoDecodingAllowed = aAllowed;
UpdateVideoDecodeMode();
}
bool
MediaDecoder::HasSuspendTaint() const
{

View File

@ -7,6 +7,7 @@
#if !defined(MediaDecoder_h_)
#define MediaDecoder_h_
#include "BackgroundVideoDecodingPermissionObserver.h"
#include "DecoderDoctorDiagnostics.h"
#include "MediaContainerType.h"
#include "MediaDecoderOwner.h"
@ -306,6 +307,8 @@ private:
void UpdateVideoDecodeMode();
void SetIsBackgroundVideoDecodingAllowed(bool aAllowed);
/******
* The following methods must only be called on the main
* thread.
@ -641,13 +644,18 @@ protected:
// We can allow video decoding in background when we match some special
// conditions, eg. when the cursor is hovering over the tab. This observer is
// used to listen the related events.
class BackgroundVideoDecodingPermissionObserver;
RefPtr<BackgroundVideoDecodingPermissionObserver> mVideoDecodingOberver;
// True if we want to resume video decoding even the media element is in the
// background.
bool mIsBackgroundVideoDecodingAllowed;
// Current decoding position in the stream. This is where the decoder
// is up to consuming the stream. This is not adjusted during decoder
// seek operations, but it's updated at the end when we start playing
// back again.
int64_t mDecoderPosition = 0;
public:
AbstractCanonical<double>* CanonicalVolume() { return &mVolume; }
AbstractCanonical<bool>* CanonicalPreservesPitch()

View File

@ -13,36 +13,24 @@
#include <algorithm>
#include <stdint.h>
#include "gfx2DGlue.h"
#include "mediasink/AudioSink.h"
#include "mediasink/AudioSinkWrapper.h"
#include "mediasink/DecodedStream.h"
#include "mediasink/OutputStreamManager.h"
#include "mediasink/VideoSink.h"
#include "mozilla/DebugOnly.h"
#include "mozilla/IndexSequence.h"
#include "mozilla/Logging.h"
#include "mozilla/mozalloc.h"
#include "mozilla/MathAlgorithms.h"
#include "mozilla/NotNull.h"
#include "mozilla/Preferences.h"
#include "mozilla/SharedThreadPool.h"
#include "mozilla/Sprintf.h"
#include "mozilla/Telemetry.h"
#include "mozilla/TaskQueue.h"
#include "mozilla/Tuple.h"
#include "nsComponentManagerUtils.h"
#include "nsContentUtils.h"
#include "nsIEventTarget.h"
#include "nsIMemoryReporter.h"
#include "nsITimer.h"
#include "nsPrintfCString.h"
#include "nsTArray.h"
#include "nsDeque.h"
#include "prenv.h"
#include "AudioSegment.h"
#include "DOMMediaStream.h"
#include "ImageContainer.h"
#include "MediaDecoder.h"
#include "MediaDecoderStateMachine.h"
@ -51,14 +39,10 @@
#include "MediaTimer.h"
#include "ReaderProxy.h"
#include "TimeUnits.h"
#include "VideoSegment.h"
#include "VideoUtils.h"
#include "gfxPrefs.h"
namespace mozilla {
using namespace mozilla::dom;
using namespace mozilla::layers;
using namespace mozilla::media;
#define NS_DispatchToMainThread(...) CompileError_UseAbstractThreadDispatchInstead

View File

@ -7,19 +7,16 @@
#include "MediaFormatReader.h"
#include "AutoTaskQueue.h"
#include "Layers.h"
#include "MediaData.h"
#include "MediaDecoderOwner.h"
#include "MediaInfo.h"
#include "MediaResource.h"
#include "VideoFrameContainer.h"
#include "VideoUtils.h"
#include "mozilla/AbstractThread.h"
#include "mozilla/CDMProxy.h"
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/NotNull.h"
#include "mozilla/Preferences.h"
#include "mozilla/SharedThreadPool.h"
#include "mozilla/SyncRunnable.h"
#include "mozilla/Telemetry.h"
#include "mozilla/Unused.h"
#include "nsContentUtils.h"
@ -31,10 +28,6 @@
using namespace mozilla::media;
using mozilla::layers::Image;
using mozilla::layers::LayerManager;
using mozilla::layers::LayersBackend;
static mozilla::LazyLogModule sFormatDecoderLog("MediaFormatReader");
mozilla::LazyLogModule gMediaDemuxerLog("MediaDemuxer");

View File

@ -53,6 +53,9 @@ public:
// Notify that the "cache suspended" status of MediaResource changes.
virtual void NotifySuspendedStatusChanged(bool aSuspendedByCache) {}
// Notify the number of bytes read from the resource.
virtual void NotifyBytesConsumed(int64_t aBytes, int64_t aOffset) {}
protected:
virtual ~MediaResourceCallback() {}
};

View File

@ -975,12 +975,10 @@ GeckoMediaPluginServiceParent::PluginTerminated(const RefPtr<GMPParent>& aPlugin
MOZ_ASSERT(mGMPThread->EventTarget()->IsOnCurrentThread());
if (aPlugin->IsMarkedForDeletion()) {
nsCString path8;
nsString path;
RefPtr<nsIFile> dir = aPlugin->GetDirectory();
nsresult rv = dir->GetNativePath(path8);
nsresult rv = dir->GetPath(path);
NS_ENSURE_SUCCESS_VOID(rv);
nsString path = NS_ConvertUTF8toUTF16(path8);
if (mPluginsWaitingForDeletion.Contains(path)) {
RemoveOnGMPThread(path, true /* delete */, true /* can defer */);
}

View File

@ -99,6 +99,7 @@ EXPORTS += [
'AudioSegment.h',
'AudioStream.h',
'AutoplayPolicy.h',
'BackgroundVideoDecodingPermissionObserver.h',
'Benchmark.h',
'BitReader.h',
'BufferMediaResource.h',
@ -215,6 +216,7 @@ UNIFIED_SOURCES += [
'AudioTrack.cpp',
'AudioTrackList.cpp',
'AutoplayPolicy.cpp',
'BackgroundVideoDecodingPermissionObserver.cpp',
'BaseMediaResource.cpp',
'Benchmark.cpp',
'BitReader.cpp',

View File

@ -71,9 +71,23 @@ interface GridLine
readonly attribute GridDeclaration type;
/**
* Number is the 1-indexed index of the line in flow order.
* Number is the 1-indexed index of the line in flow order. The
* first explicit line has number 1, and numbers increment by 1 for
* each line after that. Lines before the first explicit line
* have number 0, which is not a valid addressable line number, and
* should be filtered out by callers.
*/
readonly attribute unsigned long number;
/**
* NegativeNumber is the 1-indexed index of the line in reverse
* flow order. The last explicit line has negativeNumber -1, and
* negativeNumbers decrement by 1 for each line before that.
* Lines after the last explicit line have negativeNumber 0, which
* is not a valid addressable line number, and should be filtered
* out by callers.
*/
readonly attribute long negativeNumber;
};
[ChromeOnly]

View File

@ -164,13 +164,18 @@ NS_IMETHODIMP mozHunspell::SetDictionary(const char16_t *aDictionary)
nsAutoCString dictFileName, affFileName;
// XXX This isn't really good. nsIFile->NativePath isn't safe for all
// character sets on Windows.
// A better way would be to QI to nsIFile, and get a filehandle
// from there. Only problem is that hunspell wants a path
#ifdef XP_WIN
nsAutoString affFileNameU;
nsresult rv = affFile->GetPath(affFileNameU);
NS_ENSURE_SUCCESS(rv, rv);
// Hunspell 1.5+ supports UTF-8 file paths on Windows
// by prefixing "\\\\?\\".
affFileName.AssignLiteral("\\\\?\\");
AppendUTF16toUTF8(affFileNameU, affFileName);
#else
nsresult rv = affFile->GetNativePath(affFileName);
NS_ENSURE_SUCCESS(rv, rv);
#endif
if (mAffixFileName.Equals(affFileName.get()))
return NS_OK;

View File

@ -46,6 +46,7 @@ RefPtr<ID2D1Factory1> D2DFactory()
DrawTargetD2D1::DrawTargetD2D1()
: mPushedLayers(1)
, mSnapshotLock(make_shared<Mutex>("DrawTargetD2D1::mSnapshotLock"))
, mUsedCommandListsSincePurge(0)
, mComplexBlendsWithListInList(0)
, mDeviceSeq(0)
@ -91,9 +92,7 @@ DrawTargetD2D1::~DrawTargetD2D1()
already_AddRefed<SourceSurface>
DrawTargetD2D1::Snapshot()
{
if (!mSnapshotLock) {
mSnapshotLock = make_shared<Mutex>("DrawTargetD2D1::mSnapshotLock");
}
MutexAutoLock lock(*mSnapshotLock);
if (mSnapshot) {
RefPtr<SourceSurface> snapshot(mSnapshot);
return snapshot.forget();

View File

@ -260,7 +260,7 @@ RenderDXGIYCbCrTextureHostOGL::RenderDXGIYCbCrTextureHostOGL(WindowsHandle (&aHa
RenderDXGIYCbCrTextureHostOGL::~RenderDXGIYCbCrTextureHostOGL()
{
MOZ_COUNT_CTOR_INHERITED(RenderDXGIYCbCrTextureHostOGL, RenderTextureHostOGL);
MOZ_COUNT_DTOR_INHERITED(RenderDXGIYCbCrTextureHostOGL, RenderTextureHostOGL);
DeleteTextureHandle();
}

View File

@ -51,7 +51,7 @@ public:
, public BaseURIMutator<nsMozIconURI>
{
NS_DECL_ISUPPORTS
NS_FORWARD_SAFE_NSIURISETTERS(mURI)
NS_FORWARD_SAFE_NSIURISETTERS_RET(mURI)
NS_IMETHOD Deserialize(const mozilla::ipc::URIParams& aParams) override
{
@ -69,7 +69,8 @@ public:
return NS_OK;
}
NS_IMETHOD SetSpec(const nsACString & aSpec) override {
NS_IMETHOD SetSpec(const nsACString & aSpec, nsIURIMutator** aMutator) override {
NS_ADDREF(*aMutator = this);
return InitFromSpec(aSpec);
}

View File

@ -21,12 +21,10 @@
#define INTL_SYSTEM_LOCALES_CHANGED "intl:system-locales-changed"
#define MATCH_OS_LOCALE_PREF "intl.locale.matchOS"
#define SELECTED_LOCALE_PREF "general.useragent.locale"
#define REQUESTED_LOCALES_PREF "intl.locale.requested"
static const char* kObservedPrefs[] = {
MATCH_OS_LOCALE_PREF,
SELECTED_LOCALE_PREF,
REQUESTED_LOCALES_PREF,
nullptr
};
@ -47,8 +45,8 @@ mozilla::StaticRefPtr<LocaleService> LocaleService::sInstance;
* The BCP47 form should be used for all calls to ICU/Intl APIs.
* The canonical form is used for all internal operations.
*/
static void
SanitizeForBCP47(nsACString& aLocale)
static bool
SanitizeForBCP47(nsACString& aLocale, bool strict)
{
// Currently, the only locale code we use that's not BCP47-conformant is
// "ja-JP-mac" on OS X, but let's try to be more general than just
@ -56,50 +54,65 @@ SanitizeForBCP47(nsACString& aLocale)
const int32_t LANG_TAG_CAPACITY = 128;
char langTag[LANG_TAG_CAPACITY];
nsAutoCString locale(aLocale);
locale.Trim(" ");
UErrorCode err = U_ZERO_ERROR;
// This is a fail-safe method that will set langTag to "und" if it cannot
// match any part of the input locale code.
int32_t len = uloc_toLanguageTag(locale.get(), langTag, LANG_TAG_CAPACITY,
false, &err);
strict, &err);
if (U_SUCCESS(err) && len > 0) {
aLocale.Assign(langTag, len);
}
return U_SUCCESS(err);
}
static bool
ReadRequestedLocales(nsTArray<nsCString>& aRetVal)
{
nsAutoCString locale;
nsAutoCString str;
nsresult rv = Preferences::GetCString(REQUESTED_LOCALES_PREF, str);
// First, we'll try to check if the user has `matchOS` pref selected
bool matchOSLocale = Preferences::GetBool(MATCH_OS_LOCALE_PREF);
if (matchOSLocale) {
// If he has, we'll pick the locale from the system
if (OSPreferences::GetInstance()->GetSystemLocales(aRetVal)) {
// If we succeeded, return.
return true;
// We handle three scenarios here:
//
// 1) The pref is not set - use default locale
// 2) The pref is set to "" - use OS locales
// 3) The pref is set to a value - parse the locale list and use it
if (NS_SUCCEEDED(rv)) {
if (str.Length() > 0) {
for (const nsACString& part : str.Split(',')) {
nsAutoCString locale(part);
if (SanitizeForBCP47(locale, true)) {
// This is a hack required for us to handle the special Mozilla `ja-JP-mac`
// locales. We sanitize the input to normalize the case etc. but in result
// the `ja-JP-mac` will get turned into a BCP47 tag. Here we're turning it
// back into the form expected by Gecko resources.
if (locale.EqualsLiteral("ja-JP-x-lvariant-mac")) {
locale.Assign("ja-JP-mac");
}
if (!aRetVal.Contains(locale)) {
aRetVal.AppendElement(locale);
}
}
}
} else {
// If the pref string is empty, we'll take requested locales
// from the OS.
OSPreferences::GetInstance()->GetSystemLocales(aRetVal);
}
} else {
nsAutoCString defaultLocale;
LocaleService::GetInstance()->GetDefaultLocale(defaultLocale);
aRetVal.AppendElement(defaultLocale);
}
// Otherwise, we'll try to get the requested locale from the prefs.
if (!NS_SUCCEEDED(Preferences::GetCString(SELECTED_LOCALE_PREF, locale))) {
return false;
}
// At the moment we just take a single locale, but in the future
// we'll want to allow user to specify a list of requested locales.
aRetVal.AppendElement(locale);
// Last fallback locale is a locale for the requested locale chain.
// In the future we'll want to make the fallback chain differ per-locale.
// For now, it'll always fallback on en-US.
//
// Notice: This is not the same as DefaultLocale,
// which follows the default locale the build is in.
LocaleService::GetInstance()->GetLastFallbackLocale(locale);
if (!aRetVal.Contains(locale)) {
aRetVal.AppendElement(locale);
LocaleService::GetInstance()->GetLastFallbackLocale(str);
if (!aRetVal.Contains(str)) {
aRetVal.AppendElement(str);
}
return true;
}
@ -223,7 +236,7 @@ LocaleService::GetAppLocalesAsBCP47(nsTArray<nsCString>& aRetVal)
}
for (uint32_t i = 0; i < mAppLocales.Length(); i++) {
nsAutoCString locale(mAppLocales[i]);
SanitizeForBCP47(locale);
SanitizeForBCP47(locale, false);
aRetVal.AppendElement(locale);
}
}
@ -298,7 +311,6 @@ LocaleService::GetRequestedLocales(nsTArray<nsCString>& aRetVal)
{
if (mRequestedLocales.IsEmpty()) {
ReadRequestedLocales(mRequestedLocales);
}
aRetVal = mRequestedLocales;
@ -572,8 +584,7 @@ LocaleService::Observe(nsISupports *aSubject, const char *aTopic,
NS_ConvertUTF16toUTF8 pref(aData);
// At the moment the only thing we're observing are settings indicating
// user requested locales.
if (pref.EqualsLiteral(MATCH_OS_LOCALE_PREF) ||
pref.EqualsLiteral(SELECTED_LOCALE_PREF)) {
if (pref.EqualsLiteral(REQUESTED_LOCALES_PREF)) {
RequestedLocalesChanged();
}
}
@ -693,7 +704,7 @@ LocaleService::GetAppLocaleAsBCP47(nsACString& aRetVal)
}
aRetVal = mAppLocales[0];
SanitizeForBCP47(aRetVal);
SanitizeForBCP47(aRetVal, false);
return NS_OK;
}
@ -977,19 +988,26 @@ NS_IMETHODIMP
LocaleService::SetRequestedLocales(const char** aRequested,
uint32_t aRequestedCount)
{
nsAutoCString lastFallbackLocale;
GetLastFallbackLocale(lastFallbackLocale);
MOZ_ASSERT(aRequestedCount < 2 ||
(aRequestedCount == 2 && lastFallbackLocale.Equals(aRequested[1])),
"We can only handle one requested locale (optionally with last fallback)");
nsAutoCString str;
if (aRequestedCount == 0) {
Preferences::ClearUser(SELECTED_LOCALE_PREF);
} else {
Preferences::SetCString(SELECTED_LOCALE_PREF, aRequested[0]);
for (uint32_t i = 0; i < aRequestedCount; i++) {
nsAutoCString locale(aRequested[i]);
if (!SanitizeForBCP47(locale, true)) {
NS_ERROR("Invalid language tag provided to SetRequestedLocales!");
return NS_ERROR_INVALID_ARG;
}
if (locale.EqualsLiteral("ja-JP-x-lvariant-mac")) {
// This is a hack for our code to handle `ja-JP-mac` special case.
locale.Assign("ja-JP-mac");
}
if (i > 0) {
str.AppendLiteral(",");
}
str.Append(locale);
}
Preferences::SetCString(REQUESTED_LOCALES_PREF, str);
Preferences::SetBool(MATCH_OS_LOCALE_PREF, aRequestedCount == 0);
return NS_OK;
}

View File

@ -49,9 +49,7 @@ add_test(function test_getAppLocalesAsLangTags() {
run_next_test();
});
const PREF_MATCH_OS_LOCALE = "intl.locale.matchOS";
const PREF_SELECTED_LOCALE = "general.useragent.locale";
const PREF_OS_LOCALE = "intl.locale.os";
const PREF_REQUESTED_LOCALES = "intl.locale.requested";
const REQ_LOC_CHANGE_EVENT = "intl:requested-locales-changed";
add_test(function test_getRequestedLocales() {
@ -72,9 +70,7 @@ add_test(function test_getRequestedLocales() {
add_test(function test_getRequestedLocales_matchOS() {
do_test_pending();
Services.prefs.setBoolPref(PREF_MATCH_OS_LOCALE, false);
Services.prefs.setCharPref(PREF_SELECTED_LOCALE, "ar-IR");
Services.prefs.setCharPref(PREF_OS_LOCALE, "en-US");
Services.prefs.setCharPref(PREF_REQUESTED_LOCALES, "ar-IR");
const observer = {
observe: function (aSubject, aTopic, aData) {
@ -89,7 +85,7 @@ add_test(function test_getRequestedLocales_matchOS() {
};
Services.obs.addObserver(observer, REQ_LOC_CHANGE_EVENT);
Services.prefs.setBoolPref(PREF_MATCH_OS_LOCALE, true);
Services.prefs.setCharPref(PREF_REQUESTED_LOCALES, "");
run_next_test();
});
@ -99,11 +95,10 @@ add_test(function test_getRequestedLocales_matchOS() {
* event for requested locales change, it will be fired when the
* pref for browser UI locale changes.
*/
add_test(function test_getRequestedLocales_matchOS() {
add_test(function test_getRequestedLocales_onChange() {
do_test_pending();
Services.prefs.setBoolPref(PREF_MATCH_OS_LOCALE, false);
Services.prefs.setCharPref(PREF_SELECTED_LOCALE, "ar-IR");
Services.prefs.setCharPref(PREF_REQUESTED_LOCALES, "ar-IR");
const observer = {
observe: function (aSubject, aTopic, aData) {
@ -118,25 +113,18 @@ add_test(function test_getRequestedLocales_matchOS() {
};
Services.obs.addObserver(observer, REQ_LOC_CHANGE_EVENT);
Services.prefs.setCharPref(PREF_SELECTED_LOCALE, "sr-RU");
Services.prefs.setCharPref(PREF_REQUESTED_LOCALES, "sr-RU");
run_next_test();
});
add_test(function test_getRequestedLocale() {
Services.prefs.setBoolPref(PREF_MATCH_OS_LOCALE, false);
Services.prefs.setCharPref(PREF_SELECTED_LOCALE, "tlh");
Services.prefs.setCharPref(PREF_REQUESTED_LOCALES, "tlh");
let requestedLocale = localeService.getRequestedLocale();
do_check_true(requestedLocale === "tlh", "requestedLocale returns the right value");
Services.prefs.setCharPref(PREF_SELECTED_LOCALE, "");
requestedLocale = localeService.getRequestedLocale();
do_check_true(requestedLocale === "", "requestedLocale returns empty value value");
Services.prefs.clearUserPref(PREF_MATCH_OS_LOCALE);
Services.prefs.clearUserPref(PREF_SELECTED_LOCALE);
Services.prefs.clearUserPref(PREF_REQUESTED_LOCALES);
run_next_test();
});
@ -144,15 +132,12 @@ add_test(function test_getRequestedLocale() {
add_test(function test_setRequestedLocales() {
localeService.setRequestedLocales([]);
let matchOS = Services.prefs.getBoolPref(PREF_MATCH_OS_LOCALE);
do_check_true(matchOS === true);
localeService.setRequestedLocales(['de-AT', 'de-DE', 'de-CH']);
localeService.setRequestedLocales(['de-AT']);
matchOS = Services.prefs.getBoolPref(PREF_MATCH_OS_LOCALE);
do_check_true(matchOS === false);
let locales = localeService.getRequestedLocales();;
do_check_true(locales[0] === 'de-AT');
do_check_true(locales[1] === 'de-DE');
do_check_true(locales[2] === 'de-CH');
run_next_test();
});
@ -163,8 +148,25 @@ add_test(function test_isAppLocaleRTL() {
run_next_test();
});
do_register_cleanup(() => {
Services.prefs.clearUserPref(PREF_SELECTED_LOCALE);
Services.prefs.clearUserPref(PREF_MATCH_OS_LOCALE);
Services.prefs.clearUserPref(PREF_OS_LOCALE, "en-US");
/**
* This test verifies that all values coming from the pref are sanitized.
*/
add_test(function test_getRequestedLocales_sanitize() {
Services.prefs.setCharPref(PREF_REQUESTED_LOCALES, "de,2,#$@#,pl,!a2,DE-at,,;");
let locales = localeService.getRequestedLocales();
do_check_eq(locales[0], "de");
do_check_eq(locales[1], "pl");
do_check_eq(locales[2], "de-AT");
do_check_eq(locales[3], "und");
do_check_eq(locales[4], localeService.lastFallbackLocale);
do_check_eq(locales.length, 5);
Services.prefs.clearUserPref(PREF_REQUESTED_LOCALES);
run_next_test();
});
do_register_cleanup(() => {
Services.prefs.clearUserPref(PREF_REQUESTED_LOCALES);
});

View File

@ -3627,9 +3627,27 @@ PresShell::ScrollFrameRectIntoView(nsIFrame* aFrame,
if (sf) {
nsPoint oldPosition = sf->GetScrollPosition();
nsRect targetRect = rect;
if (container->StyleDisplay()->mOverflowClipBox ==
// Inflate the scrolled rect by the container's padding in each dimension,
// unless we have 'overflow-clip-box-*: content-box' in that dimension.
auto* disp = container->StyleDisplay();
if (disp->mOverflowClipBoxBlock ==
NS_STYLE_OVERFLOW_CLIP_BOX_CONTENT_BOX ||
disp->mOverflowClipBoxInline ==
NS_STYLE_OVERFLOW_CLIP_BOX_CONTENT_BOX) {
WritingMode wm = container->GetWritingMode();
bool cbH = (wm.IsVertical() ? disp->mOverflowClipBoxBlock
: disp->mOverflowClipBoxInline) ==
NS_STYLE_OVERFLOW_CLIP_BOX_CONTENT_BOX;
bool cbV = (wm.IsVertical() ? disp->mOverflowClipBoxInline
: disp->mOverflowClipBoxBlock) ==
NS_STYLE_OVERFLOW_CLIP_BOX_CONTENT_BOX;
nsMargin padding = container->GetUsedPadding();
if (!cbH) {
padding.left = padding.right = nscoord(0);
}
if (!cbV) {
padding.top = padding.bottom = nscoord(0);
}
targetRect.Inflate(padding);
}
ScrollToShowRect(sf, targetRect - sf->GetScrolledFrame()->GetPosition(),

View File

@ -161,7 +161,6 @@ using namespace mozilla::layout;
using namespace mozilla::gfx;
#define GRID_ENABLED_PREF_NAME "layout.css.grid.enabled"
#define GRID_TEMPLATE_SUBGRID_ENABLED_PREF_NAME "layout.css.grid-template-subgrid-value.enabled"
#define WEBKIT_PREFIXES_ENABLED_PREF_NAME "layout.css.prefixes.webkit"
#define TEXT_ALIGN_UNSAFE_ENABLED_PREF_NAME "layout.css.text-align-unsafe-value.enabled"
#define FLOAT_LOGICAL_VALUES_ENABLED_PREF_NAME "layout.css.float-logical-values.enabled"
@ -745,22 +744,6 @@ nsLayoutUtils::UnsetValueEnabled()
return sUnsetValueEnabled;
}
bool
nsLayoutUtils::IsGridTemplateSubgridValueEnabled()
{
static bool sGridTemplateSubgridValueEnabled;
static bool sGridTemplateSubgridValueEnabledPrefCached = false;
if (!sGridTemplateSubgridValueEnabledPrefCached) {
sGridTemplateSubgridValueEnabledPrefCached = true;
Preferences::AddBoolVarCache(&sGridTemplateSubgridValueEnabled,
GRID_TEMPLATE_SUBGRID_ENABLED_PREF_NAME,
false);
}
return sGridTemplateSubgridValueEnabled;
}
bool
nsLayoutUtils::IsTextAlignUnsafeValueEnabled()
{

View File

@ -2372,12 +2372,6 @@ public:
*/
static bool UnsetValueEnabled();
/**
* Checks whether support for the CSS grid-template-{columns,rows} 'subgrid X'
* value is enabled.
*/
static bool IsGridTemplateSubgridValueEnabled();
/**
* Checks whether support for the CSS text-align (and text-align-last)
* 'true' value is enabled.

View File

@ -2436,14 +2436,34 @@ ApplyOverflowClipping(nsDisplayListBuilder* aBuilder,
nsRect clipRect;
bool haveRadii = false;
nscoord radii[8];
if (aFrame->StyleDisplay()->mOverflowClipBox ==
NS_STYLE_OVERFLOW_CLIP_BOX_PADDING_BOX) {
auto* disp = aFrame->StyleDisplay();
if (disp->mOverflowClipBoxBlock == NS_STYLE_OVERFLOW_CLIP_BOX_PADDING_BOX &&
disp->mOverflowClipBoxInline == NS_STYLE_OVERFLOW_CLIP_BOX_PADDING_BOX) {
clipRect = aFrame->GetPaddingRectRelativeToSelf() +
aBuilder->ToReferenceFrame(aFrame);
haveRadii = aFrame->GetPaddingBoxBorderRadii(radii);
} else {
clipRect = aFrame->GetContentRectRelativeToSelf() +
aBuilder->ToReferenceFrame(aFrame);
// Only deflate the padding if we clip to the content-box in that axis.
auto wm = aFrame->GetWritingMode();
bool cbH = (wm.IsVertical() ? disp->mOverflowClipBoxBlock
: disp->mOverflowClipBoxInline) ==
NS_STYLE_OVERFLOW_CLIP_BOX_CONTENT_BOX;
bool cbV = (wm.IsVertical() ? disp->mOverflowClipBoxInline
: disp->mOverflowClipBoxBlock) ==
NS_STYLE_OVERFLOW_CLIP_BOX_CONTENT_BOX;
nsMargin bp = aFrame->GetUsedPadding();
if (!cbH) {
bp.left = bp.right = nscoord(0);
}
if (!cbV) {
bp.top = bp.bottom = nscoord(0);
}
bp += aFrame->GetUsedBorder();
bp.ApplySkipSides(aFrame->GetSkipSides());
nsRect rect(nsPoint(0, 0), aFrame->GetSize());
rect.Deflate(bp);
clipRect = rect + aBuilder->ToReferenceFrame(aFrame);
// XXX border-radius
}
aClipState.ClipContainingBlockDescendantsExtra(clipRect, haveRadii ? radii : nullptr);

View File

@ -575,11 +575,22 @@ nsHTMLScrollFrame::ReflowScrolledFrame(ScrollReflowInput* aState,
// overflow area doesn't include the frame bounds.
aMetrics->UnionOverflowAreasWithDesiredBounds();
if (MOZ_UNLIKELY(StyleDisplay()->mOverflowClipBox ==
auto* disp = StyleDisplay();
if (MOZ_UNLIKELY(disp->mOverflowClipBoxBlock ==
NS_STYLE_OVERFLOW_CLIP_BOX_CONTENT_BOX ||
disp->mOverflowClipBoxInline ==
NS_STYLE_OVERFLOW_CLIP_BOX_CONTENT_BOX)) {
nsOverflowAreas childOverflow;
nsLayoutUtils::UnionChildOverflow(mHelper.mScrolledFrame, childOverflow);
nsRect childScrollableOverflow = childOverflow.ScrollableOverflow();
if (disp->mOverflowClipBoxBlock == NS_STYLE_OVERFLOW_CLIP_BOX_PADDING_BOX) {
padding.BStart(wm) = nscoord(0);
padding.BEnd(wm) = nscoord(0);
}
if (disp->mOverflowClipBoxInline == NS_STYLE_OVERFLOW_CLIP_BOX_PADDING_BOX) {
padding.IStart(wm) = nscoord(0);
padding.IEnd(wm) = nscoord(0);
}
childScrollableOverflow.Inflate(padding.GetPhysicalMargin(wm));
nsRect contentArea =
wm.IsVertical() ? nsRect(0, 0, computedBSize, availISize)
@ -3458,15 +3469,31 @@ ScrollFrameHelper::BuildDisplayList(nsDisplayListBuilder* aBuilder,
Maybe<nsRect> contentBoxClip;
Maybe<const DisplayItemClipChain*> extraContentBoxClipForNonCaretContent;
if (MOZ_UNLIKELY(mOuter->StyleDisplay()->mOverflowClipBox ==
NS_STYLE_OVERFLOW_CLIP_BOX_CONTENT_BOX)) {
if (MOZ_UNLIKELY(disp->mOverflowClipBoxBlock ==
NS_STYLE_OVERFLOW_CLIP_BOX_CONTENT_BOX ||
disp->mOverflowClipBoxInline ==
NS_STYLE_OVERFLOW_CLIP_BOX_CONTENT_BOX)) {
WritingMode wm = mScrolledFrame->GetWritingMode();
bool cbH = (wm.IsVertical() ? disp->mOverflowClipBoxBlock
: disp->mOverflowClipBoxInline) ==
NS_STYLE_OVERFLOW_CLIP_BOX_CONTENT_BOX;
bool cbV = (wm.IsVertical() ? disp->mOverflowClipBoxInline
: disp->mOverflowClipBoxBlock) ==
NS_STYLE_OVERFLOW_CLIP_BOX_CONTENT_BOX;
// We only clip if there is *scrollable* overflow, to avoid clipping
// *visual* overflow unnecessarily.
nsRect clipRect = mScrollPort + aBuilder->ToReferenceFrame(mOuter);
nsRect so = mScrolledFrame->GetScrollableOverflowRect();
if (clipRect.width != so.width || clipRect.height != so.height ||
so.x < 0 || so.y < 0) {
clipRect.Deflate(mOuter->GetUsedPadding());
if ((cbH && (clipRect.width != so.width || so.x < 0)) ||
(cbV && (clipRect.height != so.height || so.y < 0))) {
nsMargin padding = mOuter->GetUsedPadding();
if (!cbH) {
padding.left = padding.right = nscoord(0);
}
if (!cbV) {
padding.top = padding.bottom = nscoord(0);
}
clipRect.Deflate(padding);
// The non-inflated clip needs to be set on all non-caret items.
// We prepare an extra DisplayItemClipChain here that will be intersected

View File

@ -0,0 +1,99 @@
<!DOCTYPE HTML>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<html><head>
<meta charset="utf-8">
<title>Reference: Testcase for bug 1422839</title>
<style type="text/css">
html,body {
color:black; background-color:white; font:16px/1 monospace; line-height:1; padding:0; margin:0;
}
div {
width: 0;
height: 0;
white-space: pre;
overflow: hidden;
border: 1px solid;
width: 100px;
height: 100px;
}
.h > div { height: 120px; }
.w > div { width: 120px; }
c {
display: block;
width: 100px;
height: 40px;
border: 1px solid black;
}
.float { float: left; }
x {
display: block;
overflow: hidden;
padding-left: 50px;
padding-top: 50px;
width: 50px;
height: 50px;
}
.w x { width: 20px; }
.h x { height: 20px; }
.w.h x {
background-color: lime;
background-clip: content-box;
overflow: visible;
}
y {
display: block;
overflow: hidden;
width: 20px;
height: 20px;
}
</style>
</head>
<body>
<span class="float">
<div><x><c></c></x></div>
<div></div>
<div></div>
<div></div>
<div><x><c></c></x></div>
<div></div>
</span>
<span class="float h">
<div><x style="height:70px"><c></c></x></div>
<div></div>
<div></div>
<div><x><c></c></x></div>
<div><x style="height:70px"><c></c></x></div>
<div></div>
</span>
<span class="float w">
<div><x style="width:70px"><c></c></x></div>
<div></div>
<div><x><c></c></x></div>
<div></div>
<div><x style="width:70px"><c></c></x></div>
<div></div>
</span>
<span class="float w h">
<div><x><y style="height:70px; width:70px"><c></c></y></x></div>
<div><x><y><c></c></y></x></div>
<div><x><y style="height:70px"><c></c></y></x></div>
<div><x><y style="width:70px"><c></c></y></x></div>
<div><x><y style="height:70px; width:70px"><c></c></y></x></div>
<div><x><y><c></c></y></x></div>
</span>
</body>
</html>

View File

@ -0,0 +1,76 @@
<!DOCTYPE HTML>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<html><head>
<meta charset="utf-8">
<title>Testcase for bug 1422839</title>
<style type="text/css">
html,body {
color:black; background-color:white; font:16px/1 monospace; line-height:1; padding:0; margin:0;
}
div {
width: 0;
height: 0;
padding: 50px;
white-space: pre;
overflow: hidden;
background-color: lime;
background-clip: content-box;
border: 1px solid;
}
.float { float: left; }
.w > div { width: 20px; }
.h > div { height: 20px; }
c {
display: block;
width: 100px;
height: 40px;
border: 1px solid black;
}
</style>
</head>
<body>
<span class="float">
<div style="overflow-clip-box: padding-box"><c></c></div>
<div style="overflow-clip-box: content-box"><c></c></div>
<div style="overflow-clip-box: padding-box content-box"><c></c></div>
<div style="overflow-clip-box: content-box padding-box"><c></c></div>
<div style="overflow-clip-box: padding-box padding-box"><c></c></div>
<div style="overflow-clip-box: content-box content-box"><c></c></div>
</span>
<span class="float h">
<div style="overflow-clip-box: padding-box"><c></c></div>
<div style="overflow-clip-box: content-box"><c></c></div>
<div style="overflow-clip-box: padding-box content-box"><c></c></div>
<div style="overflow-clip-box: content-box padding-box"><c></c></div>
<div style="overflow-clip-box: padding-box padding-box"><c></c></div>
<div style="overflow-clip-box: content-box content-box"><c></c></div>
</span>
<span class="float w">
<div style="overflow-clip-box: padding-box"><c></c></div>
<div style="overflow-clip-box: content-box"><c></c></div>
<div style="overflow-clip-box: padding-box content-box"><c></c></div>
<div style="overflow-clip-box: content-box padding-box"><c></c></div>
<div style="overflow-clip-box: padding-box padding-box"><c></c></div>
<div style="overflow-clip-box: content-box content-box"><c></c></div>
</span>
<span class="float w h">
<div style="overflow-clip-box: padding-box"><c></c></div>
<div style="overflow-clip-box: content-box"><c></c></div>
<div style="overflow-clip-box: padding-box content-box"><c></c></div>
<div style="overflow-clip-box: content-box padding-box"><c></c></div>
<div style="overflow-clip-box: padding-box padding-box"><c></c></div>
<div style="overflow-clip-box: content-box content-box"><c></c></div>
</span>
</body>
</html>

View File

@ -0,0 +1,101 @@
<!DOCTYPE HTML>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<html><head>
<meta charset="utf-8">
<title>Reference: Testcase for bug 1422839</title>
<style type="text/css">
html,body {
color:black; background-color:white; font:16px/1 monospace; line-height:1; padding:0; margin:0;
}
div {
width: 0;
height: 0;
white-space: pre;
overflow: hidden;
border: 1px solid;
width: 100px;
height: 100px;
direction: rtl;
}
.h > div { height: 120px; }
.w > div { width: 120px; }
c {
display: block;
width: 100px;
height: 40px;
border: 1px solid black;
margin-top: -10px;
}
.float { float: left; }
x {
display: block;
overflow: hidden;
padding-right: 50px;
padding-top: 50px;
width: 50px;
height: 50px;
}
.w x { width: 20px; }
.h x { height: 20px; }
.w.h x {
background-color: lime;
background-clip: content-box;
overflow: visible;
}
y {
display: block;
overflow: hidden;
width: 20px;
height: 20px;
}
</style>
</head>
<body>
<span class="float">
<div><x><c></c></x></div>
<div></div>
<div></div>
<div></div>
<div><x><c></c></x></div>
<div></div>
</span>
<span class="float h">
<div><x style="height:70px"><c></c></x></div>
<div></div>
<div></div>
<div><x style="height:20px"><c style="margin:0; border-top-width:0"></c></x></div>
<div><x style="height:70px"><c></c></x></div>
<div></div>
</span>
<span class="float w">
<div><x style="width:70px"><c></c></x></div>
<div></div>
<div><x><c></c></x></div>
<div></div>
<div><x style="width:70px"><c></c></x></div>
<div></div>
</span>
<span class="float w h">
<div><x><y style="height:70px; width:70px; margin-top:-10px"><c style="margin-top:0px"></c></y></x></div>
<div><x><y><c></c></y></x></div>
<div><x><y style="height:70px; margin-top:-10px"><c style="margin-top:0px"></c></y></x></div>
<div><x><y style="width:70px"><c></c></y></x></div>
<div><x><y style="height:70px; width:70px; margin-top:-10px"><c style="margin-top:0px"></c></y></x></div>
<div><x><y><c></c></y></x></div>
</span>
</body>
</html>

View File

@ -0,0 +1,78 @@
<!DOCTYPE HTML>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<html><head>
<meta charset="utf-8">
<title>Testcase for bug 1422839</title>
<style type="text/css">
html,body {
color:black; background-color:white; font:16px/1 monospace; line-height:1; padding:0; margin:0;
}
div {
width: 0;
height: 0;
padding: 50px;
white-space: pre;
overflow: hidden;
background-color: lime;
background-clip: content-box;
border: 1px solid;
direction: rtl;
}
.float { float: left; }
.w > div { width: 20px; }
.h > div { height: 20px; }
c {
display: block;
width: 100px;
height: 40px;
border: 1px solid black;
margin-top: -10px;
}
</style>
</head>
<body>
<span class="float">
<div style="overflow-clip-box: padding-box"><c></c></div>
<div style="overflow-clip-box: content-box"><c></c></div>
<div style="overflow-clip-box: padding-box content-box"><c></c></div>
<div style="overflow-clip-box: content-box padding-box"><c></c></div>
<div style="overflow-clip-box: padding-box padding-box"><c></c></div>
<div style="overflow-clip-box: content-box content-box"><c></c></div>
</span>
<span class="float h">
<div style="overflow-clip-box: padding-box"><c></c></div>
<div style="overflow-clip-box: content-box"><c></c></div>
<div style="overflow-clip-box: padding-box content-box"><c></c></div>
<div style="overflow-clip-box: content-box padding-box"><c></c></div>
<div style="overflow-clip-box: padding-box padding-box"><c></c></div>
<div style="overflow-clip-box: content-box content-box"><c></c></div>
</span>
<span class="float w">
<div style="overflow-clip-box: padding-box"><c></c></div>
<div style="overflow-clip-box: content-box"><c></c></div>
<div style="overflow-clip-box: padding-box content-box"><c></c></div>
<div style="overflow-clip-box: content-box padding-box"><c></c></div>
<div style="overflow-clip-box: padding-box padding-box"><c></c></div>
<div style="overflow-clip-box: content-box content-box"><c></c></div>
</span>
<span class="float w h">
<div style="overflow-clip-box: padding-box"><c></c></div>
<div style="overflow-clip-box: content-box"><c></c></div>
<div style="overflow-clip-box: padding-box content-box"><c></c></div>
<div style="overflow-clip-box: content-box padding-box"><c></c></div>
<div style="overflow-clip-box: padding-box padding-box"><c></c></div>
<div style="overflow-clip-box: content-box content-box"><c></c></div>
</span>
</body>
</html>

View File

@ -28,3 +28,5 @@
== clip-auto.html clip-auto-ref.html
== clip-rect-auto.html clip-rect-auto-ref.html
== width-rounding.html width-rounding-ref.html
pref(layout.css.overflow-clip-box.enabled,true) == overflow-clip-box-1.html overflow-clip-box-1-ref.html
pref(layout.css.overflow-clip-box.enabled,true) == overflow-clip-box-2.html overflow-clip-box-2-ref.html

View File

@ -1414,6 +1414,7 @@ Declaration::GetPropertyValueInternal(
}
MOZ_FALLTHROUGH;
}
case eCSSProperty_overflow_clip_box:
case eCSSProperty_grid_gap: {
const nsCSSPropertyID* subprops =
nsCSSProps::SubpropertyEntryFor(aProperty);

View File

@ -20,6 +20,7 @@ bool StylePrefs::sFramesTimingFunctionEnabled;
bool StylePrefs::sUnprefixedFullscreenApiEnabled;
bool StylePrefs::sVisitedLinksEnabled;
bool StylePrefs::sMozDocumentEnabledInContent;
bool StylePrefs::sGridTemplateSubgridValueEnabled;
/* static */ void
StylePrefs::Init()
@ -44,6 +45,8 @@ StylePrefs::Init()
"layout.css.visited_links_enabled");
Preferences::AddBoolVarCache(&sMozDocumentEnabledInContent,
"layout.css.moz-document.content.enabled");
Preferences::AddBoolVarCache(&sGridTemplateSubgridValueEnabled,
"layout.css.grid-template-subgrid-value.enabled");
}
} // namespace mozilla

View File

@ -23,6 +23,7 @@ struct StylePrefs
static bool sUnprefixedFullscreenApiEnabled;
static bool sVisitedLinksEnabled;
static bool sMozDocumentEnabledInContent;
static bool sGridTemplateSubgridValueEnabled;
static void Init();
};

View File

@ -937,6 +937,7 @@ protected:
bool ParseObjectPosition();
bool ParseOutline();
bool ParseOverflow();
bool ParseOverflowClipBox();
bool ParsePadding();
bool ParseQuotes();
bool ParseTextAlign(nsCSSValue& aValue,
@ -9121,7 +9122,7 @@ CSSParserImpl::ParseGridTemplateColumnsRows(nsCSSPropertyID aPropID)
nsAString* ident = NextIdent();
if (ident) {
if (ident->LowerCaseEqualsLiteral("subgrid")) {
if (!nsLayoutUtils::IsGridTemplateSubgridValueEnabled()) {
if (!StylePrefs::sGridTemplateSubgridValueEnabled) {
REPORT_UNEXPECTED(PESubgridNotSupported);
return false;
}
@ -9309,7 +9310,7 @@ CSSParserImpl::ParseGridTemplate(bool aForGridShorthand)
nsAString* ident = NextIdent();
if (ident) {
if (ident->LowerCaseEqualsLiteral("subgrid")) {
if (!nsLayoutUtils::IsGridTemplateSubgridValueEnabled()) {
if (!StylePrefs::sGridTemplateSubgridValueEnabled) {
REPORT_UNEXPECTED(PESubgridNotSupported);
return false;
}
@ -11774,6 +11775,8 @@ CSSParserImpl::ParsePropertyByFunction(nsCSSPropertyID aPropID)
return ParseOutline();
case eCSSProperty_overflow:
return ParseOverflow();
case eCSSProperty_overflow_clip_box:
return ParseOverflowClipBox();
case eCSSProperty_padding:
return ParsePadding();
case eCSSProperty_quotes:
@ -15344,6 +15347,31 @@ CSSParserImpl::ParseOverflow()
return true;
}
bool
CSSParserImpl::ParseOverflowClipBox()
{
nsCSSValue first;
if (ParseSingleTokenVariant(first, VARIANT_INHERIT, nullptr)) {
AppendValue(eCSSProperty_overflow_clip_box_block, first);
AppendValue(eCSSProperty_overflow_clip_box_inline, first);
return true;
}
const auto& kTable = nsCSSProps::kOverflowClipBoxKTable;
auto result = ParseVariant(first, VARIANT_KEYWORD, kTable);
if (result != CSSParseResult::Ok) {
return false;
}
nsCSSValue second;
result = ParseVariant(second, VARIANT_KEYWORD, kTable);
if (result == CSSParseResult::Error) {
return false;
}
AppendValue(eCSSProperty_overflow_clip_box_block, first);
AppendValue(eCSSProperty_overflow_clip_box_inline,
result == CSSParseResult::NotFound ? first : second);
return true;
}
bool
CSSParserImpl::ParsePadding()
{

View File

@ -3264,10 +3264,30 @@ CSS_PROP_SHORTHAND(
Overflow,
CSS_PROPERTY_PARSE_FUNCTION,
"")
CSS_PROP_DISPLAY(
CSS_PROP_SHORTHAND(
overflow-clip-box,
overflow_clip_box,
OverflowClipBox,
CSS_PROPERTY_PARSE_FUNCTION |
CSS_PROPERTY_ENABLED_IN_UA_SHEETS |
CSS_PROPERTY_APPLIES_TO_PLACEHOLDER,
"layout.css.overflow-clip-box.enabled")
CSS_PROP_DISPLAY(
overflow-clip-box-block,
overflow_clip_box_block,
OverflowClipBoxBlock,
CSS_PROPERTY_PARSE_VALUE |
CSS_PROPERTY_ENABLED_IN_UA_SHEETS |
CSS_PROPERTY_APPLIES_TO_PLACEHOLDER,
"layout.css.overflow-clip-box.enabled",
VARIANT_HK,
kOverflowClipBoxKTable,
CSS_PROP_NO_OFFSET,
eStyleAnimType_Discrete)
CSS_PROP_DISPLAY(
overflow-clip-box-inline,
overflow_clip_box_inline,
OverflowClipBoxInline,
CSS_PROPERTY_PARSE_VALUE |
CSS_PROPERTY_ENABLED_IN_UA_SHEETS |
CSS_PROPERTY_APPLIES_TO_PLACEHOLDER,

View File

@ -2930,6 +2930,12 @@ static const nsCSSPropertyID gOverflowSubpropTable[] = {
eCSSProperty_UNKNOWN
};
static const nsCSSPropertyID gOverflowClipBoxSubpropTable[] = {
eCSSProperty_overflow_clip_box_block,
eCSSProperty_overflow_clip_box_inline,
eCSSProperty_UNKNOWN
};
static const nsCSSPropertyID gPaddingSubpropTable[] = {
// Code relies on these being in top-right-bottom-left order.
eCSSProperty_padding_top,

View File

@ -5137,11 +5137,21 @@ nsComputedDOMStyle::DoGetOverflowY()
}
already_AddRefed<CSSValue>
nsComputedDOMStyle::DoGetOverflowClipBox()
nsComputedDOMStyle::DoGetOverflowClipBoxBlock()
{
RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
val->SetIdent(
nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mOverflowClipBox,
nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mOverflowClipBoxBlock,
nsCSSProps::kOverflowClipBoxKTable));
return val.forget();
}
already_AddRefed<CSSValue>
nsComputedDOMStyle::DoGetOverflowClipBoxInline()
{
RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
val->SetIdent(
nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mOverflowClipBoxInline,
nsCSSProps::kOverflowClipBoxKTable));
return val.forget();
}

View File

@ -501,7 +501,8 @@ private:
already_AddRefed<CSSValue> DoGetOverflow();
already_AddRefed<CSSValue> DoGetOverflowX();
already_AddRefed<CSSValue> DoGetOverflowY();
already_AddRefed<CSSValue> DoGetOverflowClipBox();
already_AddRefed<CSSValue> DoGetOverflowClipBoxBlock();
already_AddRefed<CSSValue> DoGetOverflowClipBoxInline();
already_AddRefed<CSSValue> DoGetResize();
already_AddRefed<CSSValue> DoGetPageBreakAfter();
already_AddRefed<CSSValue> DoGetPageBreakBefore();

View File

@ -199,7 +199,8 @@ COMPUTED_STYLE_PROP(outline_offset, OutlineOffset)
COMPUTED_STYLE_PROP(outline_style, OutlineStyle)
COMPUTED_STYLE_PROP(outline_width, OutlineWidth)
COMPUTED_STYLE_PROP(overflow, Overflow)
COMPUTED_STYLE_PROP(overflow_clip_box, OverflowClipBox)
COMPUTED_STYLE_PROP(overflow_clip_box_block, OverflowClipBoxBlock)
COMPUTED_STYLE_PROP(overflow_clip_box_inline, OverflowClipBoxInline)
COMPUTED_STYLE_PROP(overflow_wrap, OverflowWrap)
COMPUTED_STYLE_PROP(overflow_x, OverflowX)
COMPUTED_STYLE_PROP(overflow_y, OverflowY)

View File

@ -6143,10 +6143,17 @@ nsRuleNode::ComputeDisplayData(void* aStartStruct,
}
}
SetValue(*aRuleData->ValueForOverflowClipBox(), display->mOverflowClipBox,
SetValue(*aRuleData->ValueForOverflowClipBoxBlock(),
display->mOverflowClipBoxBlock,
conditions,
SETVAL_ENUMERATED | SETVAL_UNSET_INITIAL,
parentDisplay->mOverflowClipBox,
parentDisplay->mOverflowClipBoxBlock,
NS_STYLE_OVERFLOW_CLIP_BOX_PADDING_BOX);
SetValue(*aRuleData->ValueForOverflowClipBoxInline(),
display->mOverflowClipBoxInline,
conditions,
SETVAL_ENUMERATED | SETVAL_UNSET_INITIAL,
parentDisplay->mOverflowClipBoxInline,
NS_STYLE_OVERFLOW_CLIP_BOX_PADDING_BOX);
SetValue(*aRuleData->ValueForResize(), display->mResize, conditions,

View File

@ -3578,7 +3578,8 @@ nsStyleDisplay::nsStyleDisplay(const nsPresContext* aContext)
, mBreakAfter(false)
, mOverflowX(NS_STYLE_OVERFLOW_VISIBLE)
, mOverflowY(NS_STYLE_OVERFLOW_VISIBLE)
, mOverflowClipBox(NS_STYLE_OVERFLOW_CLIP_BOX_PADDING_BOX)
, mOverflowClipBoxBlock(NS_STYLE_OVERFLOW_CLIP_BOX_PADDING_BOX)
, mOverflowClipBoxInline(NS_STYLE_OVERFLOW_CLIP_BOX_PADDING_BOX)
, mResize(NS_STYLE_RESIZE_NONE)
, mOrient(StyleOrient::Inline)
, mIsolation(NS_STYLE_ISOLATION_AUTO)
@ -3642,7 +3643,8 @@ nsStyleDisplay::nsStyleDisplay(const nsStyleDisplay& aSource)
, mBreakAfter(aSource.mBreakAfter)
, mOverflowX(aSource.mOverflowX)
, mOverflowY(aSource.mOverflowY)
, mOverflowClipBox(aSource.mOverflowClipBox)
, mOverflowClipBoxBlock(aSource.mOverflowClipBoxBlock)
, mOverflowClipBoxInline(aSource.mOverflowClipBoxInline)
, mResize(aSource.mResize)
, mOrient(aSource.mOrient)
, mIsolation(aSource.mIsolation)
@ -3825,7 +3827,8 @@ nsStyleDisplay::CalcDifference(const nsStyleDisplay& aNewData) const
|| mBreakAfter != aNewData.mBreakAfter
|| mAppearance != aNewData.mAppearance
|| mOrient != aNewData.mOrient
|| mOverflowClipBox != aNewData.mOverflowClipBox) {
|| mOverflowClipBoxBlock != aNewData.mOverflowClipBoxBlock
|| mOverflowClipBoxInline != aNewData.mOverflowClipBoxInline) {
hint |= nsChangeHint_AllReflowHints |
nsChangeHint_RepaintFrame;
}

View File

@ -2562,7 +2562,8 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleDisplay
bool mBreakAfter; // [reset]
uint8_t mOverflowX; // [reset] see nsStyleConsts.h
uint8_t mOverflowY; // [reset] see nsStyleConsts.h
uint8_t mOverflowClipBox; // [reset] see nsStyleConsts.h
uint8_t mOverflowClipBoxBlock; // [reset] see nsStyleConsts.h
uint8_t mOverflowClipBoxInline; // [reset] see nsStyleConsts.h
uint8_t mResize; // [reset] see nsStyleConsts.h
mozilla::StyleOrient mOrient; // [reset] see nsStyleConsts.h
uint8_t mIsolation; // [reset] see nsStyleConsts.h

View File

@ -7410,14 +7410,34 @@ if (IsCSSPropertyPrefEnabled("layout.css.background-blend-mode.enabled")) {
}
if (IsCSSPropertyPrefEnabled("layout.css.overflow-clip-box.enabled")) {
gCSSProperties["overflow-clip-box"] = {
domProp: "overflowClipBox",
gCSSProperties["overflow-clip-box-block"] = {
domProp: "overflowClipBoxBlock",
inherited: false,
type: CSS_TYPE_LONGHAND,
applies_to_placeholder: true,
initial_values: [ "padding-box" ],
other_values: [ "content-box" ],
invalid_values: [ "none", "auto", "border-box", "0" ]
invalid_values: [ "auto", "border-box", "0", "padding-box padding-box" ]
};
gCSSProperties["overflow-clip-box-inline"] = {
domProp: "overflowClipBoxInline",
inherited: false,
type: CSS_TYPE_LONGHAND,
applies_to_placeholder: true,
initial_values: [ "padding-box" ],
other_values: [ "content-box" ],
invalid_values: [ "none", "border-box", "0", "content-box content-box" ]
};
gCSSProperties["overflow-clip-box"] = {
domProp: "overflowClipBox",
inherited: false,
type: CSS_TYPE_TRUE_SHORTHAND,
subproperties: [ "overflow-clip-box-block", "overflow-clip-box-inline" ],
initial_values: [ "padding-box" ],
other_values: [ "content-box", "padding-box content-box", "content-box padding-box",
"content-box content-box" ],
invalid_values: [ "none", "auto", "content-box none", "border-box", "0",
"content-box, content-box" ]
};
}

View File

@ -9,9 +9,7 @@
#include <stdlib.h>
#ifndef HAVE_MEMALIGN
namespace {
inline void*
MOZ_MEMORY_API void*
memalign(size_t aAlignment, size_t aSize)
{
#ifdef XP_WIN
@ -24,7 +22,6 @@ memalign(size_t aAlignment, size_t aSize)
return ret;
#endif
}
}
#endif
struct SystemMalloc

View File

@ -48,9 +48,6 @@ DisableStlWrapping()
DEFINES['IMPL_MFBT'] = True
if CONFIG['_MSC_VER']:
DIRS += ['staticruntime']
LOCAL_INCLUDES += [
'!/xpcom',
'/memory/build',

View File

@ -7,13 +7,7 @@
#include <stddef.h> // for size_t
// Building with USE_STATIC_LIBS = True sets -MT instead of -MD. -MT sets _MT,
// while -MD sets _MT and _DLL.
#if defined(_MT) && !defined(_DLL)
#define MOZ_STATIC_RUNTIME
#endif
#if defined(MOZ_MEMORY) && !defined(MOZ_STATIC_RUNTIME)
#if defined(MOZ_MEMORY)
// mozalloc.cpp is part of the same library as mozmemory, thus MOZ_MEMORY_IMPL
// is needed.
#define MOZ_MEMORY_IMPL
@ -40,20 +34,18 @@ MOZ_MEMORY_API char *strndup_impl(const char *, size_t);
// we need not to use the suffixes.
#if defined(MALLOC_H)
# include MALLOC_H // for memalign, valloc, malloc_size, malloc_us
# include MALLOC_H // for memalign, malloc_size, malloc_us
#endif // if defined(MALLOC_H)
#include <stdlib.h> // for malloc, free
#if defined(XP_UNIX)
# include <unistd.h> // for valloc on *BSD
# include <unistd.h>
#endif //if defined(XP_UNIX)
#define malloc_impl malloc
#define posix_memalign_impl posix_memalign
#define calloc_impl calloc
#define realloc_impl realloc
#define free_impl free
#define memalign_impl memalign
#define valloc_impl valloc
#define malloc_usable_size_impl malloc_usable_size
#define strdup_impl strdup
#define strndup_impl strndup
@ -135,21 +127,12 @@ moz_xstrndup(const char* str, size_t strsize)
}
#endif // if defined(HAVE_STRNDUP)
#if defined(HAVE_POSIX_MEMALIGN)
int
moz_xposix_memalign(void **ptr, size_t alignment, size_t size)
{
int err = posix_memalign_impl(ptr, alignment, size);
if (UNLIKELY(err && ENOMEM == err)) {
mozalloc_handle_oom(size);
return moz_xposix_memalign(ptr, alignment, size);
}
// else: (0 == err) or (EINVAL == err)
return err;
}
#endif // if defined(HAVE_POSIX_MEMALIGN)
#ifndef HAVE_MEMALIGN
// We always have a definition of memalign, but system headers don't
// necessarily come with a declaration.
extern "C" void* memalign(size_t, size_t);
#endif
#if defined(HAVE_MEMALIGN)
void*
moz_xmemalign(size_t boundary, size_t size)
{
@ -161,22 +144,7 @@ moz_xmemalign(size_t boundary, size_t size)
// non-NULL ptr or errno == EINVAL
return ptr;
}
#endif // if defined(HAVE_MEMALIGN)
#if defined(HAVE_VALLOC)
void*
moz_xvalloc(size_t size)
{
void* ptr = valloc_impl(size);
if (UNLIKELY(!ptr)) {
mozalloc_handle_oom(size);
return moz_xvalloc(size);
}
return ptr;
}
#endif // if defined(HAVE_VALLOC)
#ifndef MOZ_STATIC_RUNTIME
size_t
moz_malloc_usable_size(void *ptr)
{
@ -220,4 +188,3 @@ moz_malloc_enclosing_size_of(const void *ptr)
return 0;
#endif
}
#endif

View File

@ -33,8 +33,6 @@
#include "mozilla/Attributes.h"
#include "mozilla/Types.h"
#define MOZALLOC_HAVE_XMALLOC
#if defined(MOZ_ALWAYS_INLINE_EVEN_DEBUG)
# define MOZALLOC_INLINE MOZ_ALWAYS_INLINE_EVEN_DEBUG
#elif defined(HAVE_FORCEINLINE)
@ -99,24 +97,8 @@ MFBT_API char* moz_xstrndup(const char* str, size_t strsize)
MOZ_ALLOCATOR;
#endif /* if defined(HAVE_STRNDUP) */
#if defined(HAVE_POSIX_MEMALIGN)
MFBT_API MOZ_MUST_USE
int moz_xposix_memalign(void **ptr, size_t alignment, size_t size);
#endif /* if defined(HAVE_POSIX_MEMALIGN) */
#if defined(HAVE_MEMALIGN)
MFBT_API void* moz_xmemalign(size_t boundary, size_t size)
MOZ_ALLOCATOR;
#endif /* if defined(HAVE_MEMALIGN) */
#if defined(HAVE_VALLOC)
MFBT_API void* moz_xvalloc(size_t size)
MOZ_ALLOCATOR;
#endif /* if defined(HAVE_VALLOC) */
MOZ_END_EXTERN_C

View File

@ -1,35 +0,0 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
NoVisibilityFlags()
if CONFIG['WRAP_STL_INCLUDES']:
DEFINES['_HAS_EXCEPTIONS'] = 0
if CONFIG['MOZ_MSVC_STL_WRAP_RAISE']:
SOURCES += [
'../msvc_raise_wrappers.cpp',
]
UNIFIED_SOURCES += [
'../mozalloc.cpp',
'../mozalloc_abort.cpp',
'../mozalloc_oom.cpp',
]
# Keep this file separate to avoid #include'ing windows.h everywhere.
SOURCES += [
'../winheap.cpp',
]
LOCAL_INCLUDES += ['!/xpcom']
DisableStlWrapping()
DEFINES['IMPL_MFBT'] = True
USE_STATIC_LIBS = True
Library('mozalloc_staticruntime')

View File

@ -8,13 +8,7 @@
#include "mozilla/Types.h"
#include <windows.h>
// Building with USE_STATIC_LIBS = True sets -MT instead of -MD. -MT sets _MT,
// while -MD sets _MT and _DLL.
#if defined(_MT) && !defined(_DLL)
#define MOZ_STATIC_RUNTIME
#endif
#if defined(MOZ_MEMORY) && !defined(MOZ_STATIC_RUNTIME)
#if defined(MOZ_MEMORY)
// mozalloc.cpp is part of the same library as mozmemory, thus MOZ_MEMORY_IMPL
// is needed.
#define MOZ_MEMORY_IMPL

View File

@ -34,7 +34,7 @@ allocatorFns = [
'calloc',
# Matches realloc, replace_realloc, moz_xrealloc, vpx_realloc, js_realloc, pod_realloc, pod_reallocCanGC.
'realloc',
# Matches memalign, posix_memalign, replace_memalign, replace_posix_memalign, moz_xmemalign, moz_xposix_memalign, vpx_memalign, malloc_zone_memalign.
# Matches memalign, posix_memalign, replace_memalign, replace_posix_memalign, moz_xmemalign, vpx_memalign, malloc_zone_memalign.
'memalign',
'operator new(',
'operator new[](',

View File

@ -3,4 +3,4 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// Inherit locale from the OS, used for multi-locale builds
pref("intl.locale.matchOS", true);
pref("intl.locale.requested", "");

View File

@ -3,5 +3,3 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
#filter substitution
pref("general.useragent.locale", "@AB_CD@");

View File

@ -104,7 +104,7 @@ public:
, public BaseURIMutator<nsJARURI>
{
NS_DECL_ISUPPORTS
NS_FORWARD_SAFE_NSIURISETTERS(mURI)
NS_FORWARD_SAFE_NSIURISETTERS_RET(mURI)
NS_DEFINE_NSIMUTATOR_COMMON
explicit Mutator() { }

View File

@ -22,7 +22,6 @@
pref("preferences.allow.omt-write", true);
pref("keyword.enabled", false);
pref("general.useragent.locale", "chrome://global/locale/intl.properties");
pref("general.useragent.compatMode.firefox", false);
// This pref exists only for testing purposes. In order to disable all
@ -2295,7 +2294,6 @@ pref("intl.charset.fallback.override", "");
pref("intl.charset.fallback.tld", true);
pref("intl.charset.fallback.utf8_for_file", false);
pref("intl.ellipsis", "chrome://global-platform/locale/intl.properties");
pref("intl.locale.matchOS", false);
// this pref allows user to request that all internationalization formatters
// like date/time formatting, unit formatting, calendars etc. should use
// OS locale set instead of the app locale set.

View File

@ -212,6 +212,7 @@ UNIFIED_SOURCES += [
'nsInputStreamChannel.cpp',
'nsInputStreamPump.cpp',
'nsIOService.cpp',
'nsIURIMutatorUtils.cpp',
'nsLoadGroup.cpp',
'nsMediaFragmentURIParser.cpp',
'nsMIMEInputStream.cpp',

View File

@ -6,9 +6,11 @@
#include "nsISupports.idl"
interface nsIURI;
interface nsIObjectInputStream;
interface nsIURIMutator;
%{C++
#include "nsStringGlue.h"
#include "nsCOMPtr.h"
#undef SetPort // XXX Windows!
@ -16,7 +18,6 @@ namespace mozilla {
class Encoding;
}
namespace mozilla {
namespace ipc {
class URIParams;
@ -87,9 +88,8 @@ protected:
{ return InitFromInputStream(aStream); } \
NS_IMETHOD Finalize(nsIURI** aURI) override \
{ mURI.forget(aURI); return NS_OK; } \
NS_IMETHOD SetSpec(const nsACString & aSpec) override \
{ return InitFromSpec(aSpec); }
NS_IMETHOD SetSpec(const nsACString & aSpec, nsIURIMutator** aMutator) override \
{ if (aMutator) NS_ADDREF(*aMutator = this); return InitFromSpec(aSpec); }
%}
[ptr] native Encoding(const mozilla::Encoding);
@ -104,27 +104,70 @@ interface nsIURISetSpec : nsISupports
* to define it separately, while the rest of the setters may be simply
* forwarded to the mutable URI.
*/
void setSpec(in AUTF8String aSpec);
nsIURIMutator setSpec(in AUTF8String aSpec);
};
/**
* These methods allow the mutator to change various parts of the URI.
* They return the same nsIURIMutator so that we may chain setter operations:
* Example:
* let newURI = uri.mutate()
* .setSpec("http://example.com")
* .setQuery("hello")
* .finalize();
*/
[scriptable, builtinclass, uuid(5403a6ec-99d7-405e-8b45-9f805bbdfcef)]
interface nsIURISetters : nsIURISetSpec
{
void setScheme(in AUTF8String aScheme);
void setUserPass(in AUTF8String aUserPass);
void setUsername(in AUTF8String aUsername);
void setPassword(in AUTF8String aPassword);
void setHostPort(in AUTF8String aHostPort);
void setHostAndPort(in AUTF8String aHostAndPort);
void setHost(in AUTF8String aHost);
void setPort(in long aPort);
void setPathQueryRef(in AUTF8String aPathQueryRef);
void setRef(in AUTF8String aRef);
void setFilePath(in AUTF8String aFilePath);
void setQuery(in AUTF8String aQuery);
[noscript] void setQueryWithEncoding(in AUTF8String query, in Encoding encoding);
nsIURIMutator setScheme(in AUTF8String aScheme);
nsIURIMutator setUserPass(in AUTF8String aUserPass);
nsIURIMutator setUsername(in AUTF8String aUsername);
nsIURIMutator setPassword(in AUTF8String aPassword);
nsIURIMutator setHostPort(in AUTF8String aHostPort);
nsIURIMutator setHostAndPort(in AUTF8String aHostAndPort);
nsIURIMutator setHost(in AUTF8String aHost);
nsIURIMutator setPort(in long aPort);
nsIURIMutator setPathQueryRef(in AUTF8String aPathQueryRef);
nsIURIMutator setRef(in AUTF8String aRef);
nsIURIMutator setFilePath(in AUTF8String aFilePath);
nsIURIMutator setQuery(in AUTF8String aQuery);
[noscript] nsIURIMutator setQueryWithEncoding(in AUTF8String query, in Encoding encoding);
};
%{C++
// Using this macro instead of NS_FORWARD_SAFE_NSIURISETTERS makes chaining
// setter operations possible.
#define NS_FORWARD_SAFE_NSIURISETTERS_RET(_to) \
NS_IMETHOD SetScheme(const nsACString & aScheme, nsIURIMutator** aMutator) override \
{ if (aMutator) NS_ADDREF(*aMutator = this); return !_to ? NS_ERROR_NULL_POINTER : _to->SetScheme(aScheme); } \
NS_IMETHOD SetUserPass(const nsACString & aUserPass, nsIURIMutator** aMutator) override \
{ if (aMutator) NS_ADDREF(*aMutator = this); return !_to ? NS_ERROR_NULL_POINTER : _to->SetUserPass(aUserPass); } \
NS_IMETHOD SetUsername(const nsACString & aUsername, nsIURIMutator** aMutator) override \
{ if (aMutator) NS_ADDREF(*aMutator = this); return !_to ? NS_ERROR_NULL_POINTER : _to->SetUsername(aUsername); } \
NS_IMETHOD SetPassword(const nsACString & aPassword, nsIURIMutator** aMutator) override \
{ if (aMutator) NS_ADDREF(*aMutator = this); return !_to ? NS_ERROR_NULL_POINTER : _to->SetPassword(aPassword); } \
NS_IMETHOD SetHostPort(const nsACString & aHostPort, nsIURIMutator** aMutator) override \
{ if (aMutator) NS_ADDREF(*aMutator = this); return !_to ? NS_ERROR_NULL_POINTER : _to->SetHostPort(aHostPort); } \
NS_IMETHOD SetHostAndPort(const nsACString & aHostAndPort, nsIURIMutator** aMutator) override \
{ if (aMutator) NS_ADDREF(*aMutator = this); return !_to ? NS_ERROR_NULL_POINTER : _to->SetHostAndPort(aHostAndPort); } \
NS_IMETHOD SetHost(const nsACString & aHost, nsIURIMutator** aMutator) override \
{ if (aMutator) NS_ADDREF(*aMutator = this); return !_to ? NS_ERROR_NULL_POINTER : _to->SetHost(aHost); } \
NS_IMETHOD SetPort(int32_t aPort, nsIURIMutator** aMutator) override \
{ if (aMutator) NS_ADDREF(*aMutator = this); return !_to ? NS_ERROR_NULL_POINTER : _to->SetPort(aPort); } \
NS_IMETHOD SetPathQueryRef(const nsACString & aPathQueryRef, nsIURIMutator** aMutator) override \
{ if (aMutator) NS_ADDREF(*aMutator = this); return !_to ? NS_ERROR_NULL_POINTER : _to->SetPathQueryRef(aPathQueryRef); } \
NS_IMETHOD SetRef(const nsACString & aRef, nsIURIMutator** aMutator) override \
{ if (aMutator) NS_ADDREF(*aMutator = this); return !_to ? NS_ERROR_NULL_POINTER : _to->SetRef(aRef); } \
NS_IMETHOD SetFilePath(const nsACString & aFilePath, nsIURIMutator** aMutator) override \
{ if (aMutator) NS_ADDREF(*aMutator = this); return !_to ? NS_ERROR_NULL_POINTER : _to->SetFilePath(aFilePath); } \
NS_IMETHOD SetQuery(const nsACString & aQuery, nsIURIMutator** aMutator) override \
{ if (aMutator) NS_ADDREF(*aMutator = this); return !_to ? NS_ERROR_NULL_POINTER : _to->SetQuery(aQuery); } \
NS_IMETHOD SetQueryWithEncoding(const nsACString & query, const mozilla::Encoding *encoding, nsIURIMutator** aMutator) override \
{ if (aMutator) NS_ADDREF(*aMutator = this); return !_to ? NS_ERROR_NULL_POINTER : _to->SetQueryWithEncoding(query, encoding); }
%}
[scriptable, builtinclass, uuid(4d1f3103-1c44-4dcd-b717-5d22a697a7d9)]
interface nsIURIMutator : nsIURISetters
{
@ -148,3 +191,109 @@ interface nsIURIMutator : nsIURISetters
nsIURI finalize();
};
%{C++
// This class provides a useful helper that allows chaining of setter operations
class MOZ_STACK_CLASS NS_MutateURI
{
public:
explicit NS_MutateURI(nsIURI* aURI);
explicit NS_MutateURI(const char * aContractID);
NS_MutateURI& SetSpec(const nsACString& aSpec)
{
NS_ENSURE_SUCCESS(mStatus, *this);
mStatus = mMutator->SetSpec(aSpec, nullptr);
return *this;
}
NS_MutateURI& SetScheme(const nsACString& aScheme)
{
NS_ENSURE_SUCCESS(mStatus, *this);
mStatus = mMutator->SetScheme(aScheme, nullptr);
return *this;
}
NS_MutateURI& SetUserPass(const nsACString& aUserPass)
{
NS_ENSURE_SUCCESS(mStatus, *this);
mStatus = mMutator->SetUserPass(aUserPass, nullptr);
return *this;
}
NS_MutateURI& SetUsername(const nsACString& aUsername)
{
NS_ENSURE_SUCCESS(mStatus, *this);
mStatus = mMutator->SetUsername(aUsername, nullptr);
return *this;
}
NS_MutateURI& SetPassword(const nsACString& aPassword)
{
NS_ENSURE_SUCCESS(mStatus, *this);
mStatus = mMutator->SetPassword(aPassword, nullptr);
return *this;
}
NS_MutateURI& SetHostPort(const nsACString& aHostPort)
{
NS_ENSURE_SUCCESS(mStatus, *this);
mStatus = mMutator->SetHostPort(aHostPort, nullptr);
return *this;
}
NS_MutateURI& SetHostAndPort(const nsACString& aHostAndPort)
{
NS_ENSURE_SUCCESS(mStatus, *this);
mStatus = mMutator->SetHostAndPort(aHostAndPort, nullptr);
return *this;
}
NS_MutateURI& SetHost(const nsACString& aHost)
{
NS_ENSURE_SUCCESS(mStatus, *this);
mStatus = mMutator->SetHost(aHost, nullptr);
return *this;
}
NS_MutateURI& SetPort(int32_t aPort)
{
NS_ENSURE_SUCCESS(mStatus, *this);
mStatus = mMutator->SetPort(aPort, nullptr);
return *this;
}
NS_MutateURI& SetPathQueryRef(const nsACString& aPathQueryRef)
{
NS_ENSURE_SUCCESS(mStatus, *this);
mStatus = mMutator->SetPathQueryRef(aPathQueryRef, nullptr);
return *this;
}
NS_MutateURI& SetRef(const nsACString& aRef)
{
NS_ENSURE_SUCCESS(mStatus, *this);
mStatus = mMutator->SetRef(aRef, nullptr);
return *this;
}
NS_MutateURI& SetFilePath(const nsACString& aFilePath)
{
NS_ENSURE_SUCCESS(mStatus, *this);
mStatus = mMutator->SetFilePath(aFilePath, nullptr);
return *this;
}
NS_MutateURI& SetQuery(const nsACString& aQuery)
{
NS_ENSURE_SUCCESS(mStatus, *this);
mStatus = mMutator->SetQuery(aQuery, nullptr);
return *this;
}
NS_MutateURI& SetQueryWithEncoding(const nsACString& query, const mozilla::Encoding *encoding)
{
NS_ENSURE_SUCCESS(mStatus, *this);
mStatus = mMutator->SetQueryWithEncoding(query, encoding, nullptr);
return *this;
}
nsresult Finalize(nsIURI** aURI)
{
NS_ENSURE_SUCCESS(mStatus, mStatus);
mStatus = mMutator->Finalize(aURI);
return mStatus;
}
nsresult GetStatus() { return mStatus; }
private:
nsresult mStatus;
RefPtr<nsIURIMutator> mMutator;
};
%}

View File

@ -0,0 +1,22 @@
#include "nsIURIMutator.h"
#include "nsIURI.h"
#include "nsComponentManagerUtils.h"
static nsresult
GetURIMutator(nsIURI* aURI, nsIURIMutator** aMutator)
{
if (NS_WARN_IF(!aURI)) {
return NS_ERROR_INVALID_ARG;
}
return aURI->Mutate(aMutator);
}
NS_MutateURI::NS_MutateURI(nsIURI* aURI)
{
mStatus = GetURIMutator(aURI, getter_AddRefs(mMutator));
}
NS_MutateURI::NS_MutateURI(const char * aContractID)
{
mMutator = do_CreateInstance(aContractID, &mStatus);
}

View File

@ -77,8 +77,8 @@ public:
, public BaseURIMutator<nsSimpleNestedURI>
{
NS_DECL_ISUPPORTS
NS_FORWARD_SAFE_NSIURISETTERS(mURI)
NS_DEFINE_NSIMUTATOR_COMMON
NS_FORWARD_SAFE_NSIURISETTERS_RET(mURI)
explicit Mutator() { }
private:

View File

@ -118,7 +118,7 @@ public:
, public BaseURIMutator<nsSimpleURI>
{
NS_DECL_ISUPPORTS
NS_FORWARD_SAFE_NSIURISETTERS(mURI)
NS_FORWARD_SAFE_NSIURISETTERS_RET(mURI)
NS_DEFINE_NSIMUTATOR_COMMON
explicit Mutator() { }

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