mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 21:31:04 +00:00
Merge autoland to mozilla-central r=merge a=merge
This commit is contained in:
commit
c2096f8bee
@ -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
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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]
|
||||
|
@ -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);
|
||||
}
|
||||
});
|
@ -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": {
|
||||
|
@ -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);
|
||||
});
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
},
|
||||
|
||||
|
@ -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"),
|
||||
};
|
||||
},
|
||||
|
||||
|
@ -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">
|
||||
|
@ -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 {
|
||||
|
@ -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%;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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();
|
||||
});
|
||||
|
@ -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",
|
||||
|
@ -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
|
||||
|
@ -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@");
|
||||
|
@ -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 {
|
||||
|
@ -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,
|
||||
|
@ -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')
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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"
|
||||
|
@ -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,
|
||||
|
@ -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');
|
||||
|
@ -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() { }
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
);
|
||||
|
||||
|
@ -50,6 +50,7 @@ protected:
|
||||
nscoord aLastTrackEdge,
|
||||
uint32_t& aRepeatIndex,
|
||||
uint32_t aNumRepeatTracks,
|
||||
uint32_t aNumLeadingTracks,
|
||||
nsTArray<nsString>& aLineNames);
|
||||
|
||||
RefPtr<GridDimension> mParent;
|
||||
|
@ -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.");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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.");
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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() { }
|
||||
|
198
dom/media/BackgroundVideoDecodingPermissionObserver.cpp
Normal file
198
dom/media/BackgroundVideoDecodingPermissionObserver.cpp
Normal 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
|
48
dom/media/BackgroundVideoDecodingPermissionObserver.h
Normal file
48
dom/media/BackgroundVideoDecodingPermissionObserver.h
Normal 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_
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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).
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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()
|
||||
|
@ -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
|
||||
|
@ -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");
|
||||
|
||||
|
@ -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() {}
|
||||
};
|
||||
|
@ -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 */);
|
||||
}
|
||||
|
@ -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',
|
||||
|
@ -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]
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -260,7 +260,7 @@ RenderDXGIYCbCrTextureHostOGL::RenderDXGIYCbCrTextureHostOGL(WindowsHandle (&aHa
|
||||
|
||||
RenderDXGIYCbCrTextureHostOGL::~RenderDXGIYCbCrTextureHostOGL()
|
||||
{
|
||||
MOZ_COUNT_CTOR_INHERITED(RenderDXGIYCbCrTextureHostOGL, RenderTextureHostOGL);
|
||||
MOZ_COUNT_DTOR_INHERITED(RenderDXGIYCbCrTextureHostOGL, RenderTextureHostOGL);
|
||||
DeleteTextureHandle();
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
});
|
||||
|
@ -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(),
|
||||
|
@ -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()
|
||||
{
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
99
layout/reftests/box-properties/overflow-clip-box-1-ref.html
Normal file
99
layout/reftests/box-properties/overflow-clip-box-1-ref.html
Normal 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>
|
76
layout/reftests/box-properties/overflow-clip-box-1.html
Normal file
76
layout/reftests/box-properties/overflow-clip-box-1.html
Normal 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>
|
101
layout/reftests/box-properties/overflow-clip-box-2-ref.html
Normal file
101
layout/reftests/box-properties/overflow-clip-box-2-ref.html
Normal 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>
|
78
layout/reftests/box-properties/overflow-clip-box-2.html
Normal file
78
layout/reftests/box-properties/overflow-clip-box-2.html
Normal 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>
|
@ -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
|
||||
|
@ -1414,6 +1414,7 @@ Declaration::GetPropertyValueInternal(
|
||||
}
|
||||
MOZ_FALLTHROUGH;
|
||||
}
|
||||
case eCSSProperty_overflow_clip_box:
|
||||
case eCSSProperty_grid_gap: {
|
||||
const nsCSSPropertyID* subprops =
|
||||
nsCSSProps::SubpropertyEntryFor(aProperty);
|
||||
|
@ -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
|
||||
|
@ -23,6 +23,7 @@ struct StylePrefs
|
||||
static bool sUnprefixedFullscreenApiEnabled;
|
||||
static bool sVisitedLinksEnabled;
|
||||
static bool sMozDocumentEnabledInContent;
|
||||
static bool sGridTemplateSubgridValueEnabled;
|
||||
|
||||
static void Init();
|
||||
};
|
||||
|
@ -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()
|
||||
{
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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)
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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" ]
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -48,9 +48,6 @@ DisableStlWrapping()
|
||||
|
||||
DEFINES['IMPL_MFBT'] = True
|
||||
|
||||
if CONFIG['_MSC_VER']:
|
||||
DIRS += ['staticruntime']
|
||||
|
||||
LOCAL_INCLUDES += [
|
||||
'!/xpcom',
|
||||
'/memory/build',
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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')
|
@ -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
|
||||
|
@ -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[](',
|
||||
|
@ -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", "");
|
||||
|
@ -3,5 +3,3 @@
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#filter substitution
|
||||
|
||||
pref("general.useragent.locale", "@AB_CD@");
|
||||
|
@ -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() { }
|
||||
|
@ -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.
|
||||
|
@ -212,6 +212,7 @@ UNIFIED_SOURCES += [
|
||||
'nsInputStreamChannel.cpp',
|
||||
'nsInputStreamPump.cpp',
|
||||
'nsIOService.cpp',
|
||||
'nsIURIMutatorUtils.cpp',
|
||||
'nsLoadGroup.cpp',
|
||||
'nsMediaFragmentURIParser.cpp',
|
||||
'nsMIMEInputStream.cpp',
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
%}
|
||||
|
22
netwerk/base/nsIURIMutatorUtils.cpp
Normal file
22
netwerk/base/nsIURIMutatorUtils.cpp
Normal 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);
|
||||
}
|
@ -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:
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user