Merge autoland to central, a=merge

MozReview-Commit-ID: BptG5xWc5Ax
This commit is contained in:
Wes Kocher 2017-09-13 23:17:32 -07:00
Родитель 184f059e3b d80f1e578d
Коммит ccf6649c52
172 изменённых файлов: 3768 добавлений и 1567 удалений

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

@ -583,7 +583,7 @@ pref("browser.gesture.pinch.threshold", 150);
pref("browser.gesture.pinch.latched", false);
pref("browser.gesture.pinch.threshold", 25);
#endif
#ifdef XP_WIN
#if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
// Enabled for touch input display zoom.
pref("browser.gesture.pinch.out", "cmd_fullZoomEnlarge");
pref("browser.gesture.pinch.in", "cmd_fullZoomReduce");
@ -1275,7 +1275,7 @@ pref("browser.newtabpage.directory.source", "https://tiles.services.mozilla.com/
// activates Activity Stream
pref("browser.newtabpage.activity-stream.enabled", true);
pref("browser.newtabpage.activity-stream.prerender", true);
pref("browser.newtabpage.activity-stream.aboutHome.enabled", false);
pref("browser.newtabpage.activity-stream.aboutHome.enabled", true);
// Enable the DOM fullscreen API.
pref("full-screen-api.enabled", true);

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

@ -285,6 +285,9 @@
<key key="&reloadCmd.commandkey;" command="Browser:Reload" modifiers="accel" id="key_reload"/>
<key key="&reloadCmd.commandkey;" command="Browser:ReloadSkipCache" modifiers="accel,shift"/>
<key id="key_viewSource" key="&pageSourceCmd.commandkey;" command="View:PageSource" modifiers="accel"/>
#ifdef XP_MACOSX
<key id="key_viewSourceSafari" key="&pageSourceCmd.SafariCommandKey;" command="View:PageSource" modifiers="accel,alt"/>
#endif
#ifndef XP_WIN
<key id="key_viewInfo" key="&pageInfoCmd.commandkey;" command="View:PageInfo" modifiers="accel"/>
#endif

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

@ -184,6 +184,7 @@ tabbrowser {
transition: transform 200ms var(--animation-easing-function);
}
#TabsToolbar[movingtab] > .chromeclass-toolbar-additional,
#TabsToolbar[movingtab] > .tabbrowser-tabs {
padding-bottom: 15px;
}
@ -455,9 +456,12 @@ toolbarpaletteitem[place="palette"] > #personal-bookmarks > #bookmarks-toolbar-b
display: -moz-box;
}
#personal-bookmarks {
position: relative;
}
#PlacesToolbarDropIndicatorHolder {
position: absolute;
top: 25%;
}
#nav-bar-customization-target > #personal-bookmarks,

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

@ -301,6 +301,10 @@ var gInitialPages = [
"about:sessionrestore"
];
function isInitialPage(url) {
return gInitialPages.includes(url) || url == BROWSER_NEW_TAB_URL;
}
function* browserWindows() {
let windows = Services.wm.getEnumerator("navigator:browser");
while (windows.hasMoreElements())
@ -2751,7 +2755,7 @@ function URLBarSetURI(aURI) {
// Replace initial page URIs with an empty string
// only if there's no opener (bug 370555).
if (gInitialPages.includes(uri.spec) &&
if (isInitialPage(uri.spec) &&
checkEmptyPageOrigin(gBrowser.selectedBrowser, uri)) {
value = "";
} else {
@ -2764,6 +2768,10 @@ function URLBarSetURI(aURI) {
}
valid = !isBlankPageURL(uri.spec) || uri.schemeIs("moz-extension");
} else if (isInitialPage(value) &&
checkEmptyPageOrigin(gBrowser.selectedBrowser)) {
value = "";
valid = true;
}
let isDifferentValidValue = valid && value != gURLBar.value;

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

@ -246,7 +246,8 @@ ContentSearchUIController.prototype = {
let searchText = this.input;
let searchTerms;
if (this._table.hidden ||
aEvent.originalTarget.id == "contentSearchDefaultEngineHeader" ||
(aEvent.originalTarget &&
aEvent.originalTarget.id == "contentSearchDefaultEngineHeader") ||
aEvent instanceof KeyboardEvent) {
searchTerms = searchText.value;
} else {

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

@ -27,8 +27,9 @@ add_task(async function() {
// The onboarding tour's notification would affect tests
// and it isn't out test target so make sure disabling it
// before any tests start.
await promiseDisableOnboardingTours();
await promiseDisableOnboardingToursAndActivityStream();
is(false, Services.prefs.getBoolPref("browser.onboarding.enabled"), "Should disable the onboarding tours");
is(false, Services.prefs.getBoolPref("browser.newtabpage.activity-stream.aboutHome.enabled"), "Should disable activity stream on about:home");
});
add_task(async function() {

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

@ -150,6 +150,9 @@ function waitForDocLoadAndStopIt(aExpectedURL, aBrowser = gBrowser.selectedBrows
});
}
function promiseDisableOnboardingTours() {
return SpecialPowers.pushPrefEnv({set: [["browser.onboarding.enabled", false]]});
function promiseDisableOnboardingToursAndActivityStream() {
return SpecialPowers.pushPrefEnv({set: [
["browser.onboarding.enabled", false],
["browser.newtabpage.activity-stream.aboutHome.enabled", false]
]});
}

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

@ -4339,7 +4339,7 @@ OverflowableToolbar.prototype = {
if (this._chevron.open) {
this._panel.hidePopup();
this._chevron.open = false;
} else if (this._panel.state != "hiding") {
} else if (this._panel.state != "hiding" && !this._chevron.disabled) {
this.show();
}
},

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

@ -105,6 +105,7 @@ this.browserAction = class extends ExtensionAPI {
extension, ["browserAction", "default_icon"],
() => IconDetails.normalize({
path: options.default_icon,
iconType: "browserAction",
themeIcons: options.theme_icons,
}, extension));
@ -622,6 +623,8 @@ this.browserAction = class extends ExtensionAPI {
setIcon: function(details) {
let tab = getTab(details.tabId);
details.iconType = "browserAction";
let icon = IconDetails.normalize(details, extension, context);
browserAction.setProperty(tab, "icon", icon);
},

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

@ -60,12 +60,6 @@ class ChildDevToolsPanel extends ExtensionUtils.EventEmitter {
}
receiveMessage({name, data}) {
// Filter out any message received while the panel context do not yet
// exist.
if (!this.panelContext || !this.panelContext.contentWindow) {
return;
}
// Filter out any message that is not related to the id of this
// toolbox panel.
if (!data || data.toolboxPanelId !== this.id) {
@ -74,6 +68,11 @@ class ChildDevToolsPanel extends ExtensionUtils.EventEmitter {
switch (name) {
case "Extension:DevToolsPanelShown":
// Filter out *Shown message received while the panel context do not yet
// exist.
if (!this.panelContext || !this.panelContext.contentWindow) {
return;
}
this.onParentPanelShown();
break;
case "Extension:DevToolsPanelHidden":

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

@ -61,13 +61,21 @@ class ParentDevToolsPanel {
this.id = this.panelOptions.id;
this.onToolboxPanelSelect = this.onToolboxPanelSelect.bind(this);
this.onToolboxHostWillChange = this.onToolboxHostWillChange.bind(this);
this.onToolboxHostChanged = this.onToolboxHostChanged.bind(this);
this.panelAdded = false;
this.addPanel();
this.unwatchExtensionProxyContextLoad = null;
this.waitTopLevelContext = new Promise(resolve => {
this._resolveTopLevelContext = resolve;
});
// References to the panel browser XUL element and the toolbox window global which
// contains the devtools panel UI.
this.browser = null;
this.browserContainerWindow = null;
this.panelAdded = false;
this.addPanel();
}
addPanel() {
@ -88,7 +96,7 @@ class ParentDevToolsPanel {
throw new Error("Unexpected toolbox received on addAdditionalTool build property");
}
const destroy = this.buildPanel(window, toolbox);
const destroy = this.buildPanel(window);
return {toolbox, destroy};
},
@ -97,7 +105,114 @@ class ParentDevToolsPanel {
this.panelAdded = true;
}
buildPanel(window, toolbox) {
buildPanel(window) {
const {toolbox} = this;
this.createBrowserElement(window);
// Store the last panel's container element (used to restore it when the toolbox
// host is switched between docked and undocked).
this.browserContainerWindow = window;
toolbox.on("select", this.onToolboxPanelSelect);
toolbox.on("host-will-change", this.onToolboxHostWillChange);
toolbox.on("host-changed", this.onToolboxHostChanged);
// Return a cleanup method that is when the panel is destroyed, e.g.
// - when addon devtool panel has been disabled by the user from the toolbox preferences,
// its ParentDevToolsPanel instance is still valid, but the built devtools panel is removed from
// the toolbox (and re-built again if the user re-enables it from the toolbox preferences panel)
// - when the creator context has been destroyed, the ParentDevToolsPanel close method is called,
// it removes the tool definition from the toolbox, which will call this destroy method.
return () => {
this.destroyBrowserElement();
this.browserContainerWindow = null;
toolbox.off("select", this.onToolboxPanelSelect);
toolbox.off("host-will-change", this.onToolboxHostWillChange);
toolbox.off("host-changed", this.onToolboxHostChanged);
};
}
onToolboxHostWillChange() {
// NOTE: Using a content iframe here breaks the devtools panel
// switching between docked and undocked mode,
// because of a swapFrameLoader exception (see bug 1075490),
// destroy the browser and recreate it after the toolbox host has been
// switched is a reasonable workaround to fix the issue on release and beta
// Firefox versions (at least until the underlying bug can be fixed).
if (this.browser) {
// Fires a panel.onHidden event before destroying the browser element because
// the toolbox hosts is changing.
if (this.visible) {
this.context.parentMessageManager.sendAsyncMessage("Extension:DevToolsPanelHidden", {
toolboxPanelId: this.id,
});
}
this.destroyBrowserElement();
}
}
async onToolboxHostChanged() {
if (this.browserContainerWindow) {
this.createBrowserElement(this.browserContainerWindow);
// Fires a panel.onShown event once the browser element has been recreated
// after the toolbox hosts has been changed (needed to provide the new window
// object to the extension page that has created the devtools panel).
if (this.visible) {
await this.waitTopLevelContext;
this.context.parentMessageManager.sendAsyncMessage("Extension:DevToolsPanelShown", {
toolboxPanelId: this.id,
});
}
}
}
async onToolboxPanelSelect(what, id) {
if (!this.waitTopLevelContext || !this.panelAdded) {
return;
}
// Wait that the panel is fully loaded and emit show.
await this.waitTopLevelContext;
if (!this.visible && id === this.id) {
this.visible = true;
} else if (this.visible && id !== this.id) {
this.visible = false;
}
const extensionMessage = `Extension:DevToolsPanel${this.visible ? "Shown" : "Hidden"}`;
this.context.parentMessageManager.sendAsyncMessage(extensionMessage, {
toolboxPanelId: this.id,
});
}
close() {
const {toolbox} = this;
if (!toolbox) {
throw new Error("Unable to destroy a closed devtools panel");
}
// Explicitly remove the panel if it is registered and the toolbox is not
// closing itself.
if (this.panelAdded && toolbox.isToolRegistered(this.id)) {
toolbox.removeAdditionalTool(this.id);
}
this.waitTopLevelContext = null;
this._resolveTopLevelContext = null;
this.context = null;
this.toolbox = null;
this.browser = null;
this.browserContainerWindow = null;
}
createBrowserElement(window) {
const {toolbox} = this;
const {url} = this.panelOptions;
const {document} = window;
@ -119,18 +234,12 @@ class ParentDevToolsPanel {
browser.setAttribute("remote", "true");
browser.setAttribute("remoteType", E10SUtils.EXTENSION_REMOTE_TYPE);
awaitFrameLoader = promiseEvent(browser, "XULFrameLoaderCreated");
} else if (!AppConstants.RELEASE_OR_BETA) {
// NOTE: Using a content iframe here breaks the devtools panel
// switching between docked and undocked mode,
// because of a swapFrameLoader exception (see bug 1075490).
browser.setAttribute("type", "chrome");
browser.setAttribute("forcemessagemanager", true);
}
let hasTopLevelContext = false;
// Listening to new proxy contexts.
const unwatchExtensionProxyContextLoad = watchExtensionProxyContextLoad(this, context => {
this.unwatchExtensionProxyContextLoad = watchExtensionProxyContextLoad(this, context => {
// Keep track of the toolbox and target associated to the context, which is
// needed by the API methods implementation.
context.devToolsToolbox = toolbox;
@ -154,65 +263,26 @@ class ParentDevToolsPanel {
});
browser.loadURI(url);
}
toolbox.on("select", this.onToolboxPanelSelect);
// Return a cleanup method that is when the panel is destroyed, e.g.
// - when addon devtool panel has been disabled by the user from the toolbox preferences,
// its ParentDevToolsPanel instance is still valid, but the built devtools panel is removed from
// the toolbox (and re-built again if the user re-enable it from the toolbox preferences panel)
// - when the creator context has been destroyed, the ParentDevToolsPanel close method is called,
// it remove the tool definition from the toolbox, which will call this destroy method.
return () => {
destroyBrowserElement() {
const {browser, unwatchExtensionProxyContextLoad} = this;
if (unwatchExtensionProxyContextLoad) {
this.unwatchExtensionProxyContextLoad = null;
unwatchExtensionProxyContextLoad();
}
if (browser) {
browser.remove();
toolbox.off("select", this.onToolboxPanelSelect);
// If the panel has been disabled from the toolbox preferences,
// we need to re-initialize the waitTopLevelContext Promise.
this.waitTopLevelContext = new Promise(resolve => {
this._resolveTopLevelContext = resolve;
});
};
}
onToolboxPanelSelect(what, id) {
if (!this.waitTopLevelContext || !this.panelAdded) {
return;
}
if (!this.visible && id === this.id) {
// Wait that the panel is fully loaded and emit show.
this.waitTopLevelContext.then(() => {
this.visible = true;
this.context.parentMessageManager.sendAsyncMessage("Extension:DevToolsPanelShown", {
toolboxPanelId: this.id,
});
});
} else if (this.visible && id !== this.id) {
this.visible = false;
this.context.parentMessageManager.sendAsyncMessage("Extension:DevToolsPanelHidden", {
toolboxPanelId: this.id,
});
}
}
close() {
const {toolbox} = this;
if (!toolbox) {
throw new Error("Unable to destroy a closed devtools panel");
this.browser = null;
}
// Explicitly remove the panel if it is registered and the toolbox is not
// closing itself.
if (this.panelAdded && toolbox.isToolRegistered(this.id) && !toolbox._destroyer) {
toolbox.removeAdditionalTool(this.id);
}
this.context = null;
this.toolbox = null;
this.waitTopLevelContext = null;
this._resolveTopLevelContext = null;
// If the panel has been removed or disabled (e.g. from the toolbox preferences
// or during the toolbox switching between docked and undocked),
// we need to re-initialize the waitTopLevelContext Promise.
this.waitTopLevelContext = new Promise(resolve => {
this._resolveTopLevelContext = resolve;
});
}
}

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

@ -148,12 +148,11 @@ this.pageAction = class extends ExtensionAPI {
}
getIconData(icons) {
// These URLs should already be properly escaped, but make doubly sure CSS
// string escape characters are escaped here, since they could lead to a
// sandbox break.
let escape = str => str.replace(/[\\\s"]/g, encodeURIComponent);
let getIcon = size => escape(IconDetails.getPreferredIcon(icons, this.extension, size).icon);
let getIcon = size => {
let {icon} = IconDetails.getPreferredIcon(icons, this.extension, size);
// TODO: implement theme based icon for pageAction (Bug 1398156)
return IconDetails.escapeUrl(icon);
};
let style = `
--webextension-urlbar-image: url("${getIcon(16)}");

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

@ -297,3 +297,75 @@ add_task(async function testDetailsObjects() {
await extension.unload();
});
// NOTE: The current goal of this test is ensuring that Bug 1397196 has been fixed,
// and so this test extension manifest has a browser action which specify
// a theme based icon and a pageAction, both the pageAction and the browserAction
// have a common default_icon.
//
// Once Bug 1398156 will be fixed, this test should be converted into testing that
// the browserAction and pageAction themed icons (as well as any other cached icon,
// e.g. the sidebar and devtools panel icons) can be specified in the same extension
// and do not conflict with each other.
//
// This test currently fails without the related fix, but only if the browserAction
// API has been already loaded before the pageAction, otherwise the icons will be cached
// in the opposite order and the test is not able to reproduce the issue anymore.
add_task(async function testPageActionIconLoadingOnBrowserActionThemedIcon() {
async function background() {
const tabs = await browser.tabs.query({active: true});
await browser.pageAction.show(tabs[0].id);
browser.test.sendMessage("ready");
}
const extension = ExtensionTestUtils.loadExtension({
background,
manifest: {
"name": "Foo Extension",
"browser_action": {
"default_icon": "common_cached_icon.png",
"default_popup": "default_popup.html",
"default_title": "BrowserAction title",
"theme_icons": [
{
"dark": "1.png",
"light": "2.png",
"size": 16
}
],
},
"page_action": {
"default_icon": "common_cached_icon.png",
"default_popup": "default_popup.html",
"default_title": "PageAction title",
},
"permissions": ["tabs"],
},
"files": {
"common_cached_icon.png": imageBuffer,
"1.png": imageBuffer,
"2.png": imageBuffer,
"default_popup.html": "<!DOCTYPE html><html><body>popup</body></html>",
},
});
await extension.startup();
await extension.awaitMessage("ready");
await promiseAnimationFrame();
let pageActionId = `${makeWidgetId(extension.id)}-page-action`;
let pageActionImage = document.getElementById(pageActionId);
const iconURL = new URL(getListStyleImage(pageActionImage));
is(iconURL.pathname, "/common_cached_icon.png", "Got the expected pageAction icon url");
await extension.unload();
});

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

@ -309,3 +309,127 @@ add_task(async function test_devtools_page_panels_create() {
await BrowserTestUtils.removeTab(tab);
});
add_task(async function test_devtools_page_panels_switch_toolbox_host() {
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, "http://mochi.test:8888/");
function devtools_panel() {
const hasDevToolsAPINamespace = "devtools" in browser;
browser.test.sendMessage("devtools_panel_loaded", {
hasDevToolsAPINamespace,
panelLoadedURL: window.location.href,
});
}
async function devtools_page() {
const panel = await browser.devtools.panels.create(
"Test Panel", "fake-icon.png", "devtools_panel.html"
);
panel.onShown.addListener(panelWindow => {
browser.test.sendMessage("devtools_panel_shown", panelWindow.location.href);
});
panel.onHidden.addListener(() => {
browser.test.sendMessage("devtools_panel_hidden");
});
browser.test.sendMessage("devtools_panel_created");
}
let extension = ExtensionTestUtils.loadExtension({
manifest: {
devtools_page: "devtools_page.html",
},
files: {
"devtools_page.html": `<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<script src="devtools_page.js"></script>
</body>
</html>`,
"devtools_page.js": devtools_page,
"devtools_panel.html": `<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
DEVTOOLS PANEL
<script src="devtools_panel.js"></script>
</body>
</html>`,
"devtools_panel.js": devtools_panel,
},
});
await extension.startup();
let target = gDevTools.getTargetForTab(tab);
const toolbox = await gDevTools.showToolbox(target, "webconsole");
info("developer toolbox opened");
await extension.awaitMessage("devtools_panel_created");
const toolboxAdditionalTools = toolbox.getAdditionalTools();
is(toolboxAdditionalTools.length, 1,
"Got the expected number of toolbox specific panel registered.");
const panelDef = toolboxAdditionalTools[0];
const panelId = panelDef.id;
info("Selecting the addon devtools panel");
await gDevTools.showToolbox(target, panelId);
info("Wait for the panel to show and load for the first time");
const panelShownURL = await extension.awaitMessage("devtools_panel_shown");
const {
panelLoadedURL,
hasDevToolsAPINamespace,
} = await extension.awaitMessage("devtools_panel_loaded");
is(panelShownURL, panelLoadedURL, "Got the expected panel URL on the first load");
ok(hasDevToolsAPINamespace, "The devtools panel has the devtools API on the first load");
const originalToolboxHostType = toolbox.hostType;
info("Switch the toolbox from docked on bottom to docked on side");
toolbox.switchHost("side");
info("Wait for the panel to emit hide, show and load messages once docked on side");
await extension.awaitMessage("devtools_panel_hidden");
const dockedOnSideShownURL = await extension.awaitMessage("devtools_panel_shown");
is(dockedOnSideShownURL, panelShownURL,
"Got the expected panel url once the panel shown event has been emitted on toolbox host changed");
const dockedOnSideLoaded = await extension.awaitMessage("devtools_panel_loaded");
is(dockedOnSideLoaded.panelLoadedURL, panelShownURL,
"Got the expected panel url once the panel has been reloaded on toolbox host changed");
ok(dockedOnSideLoaded.hasDevToolsAPINamespace,
"The devtools panel has the devtools API once the toolbox host has been changed");
info("Switch the toolbox from docked on bottom to the original dock mode");
toolbox.switchHost(originalToolboxHostType);
info("Wait for the panel test messages once toolbox dock mode has been restored");
await extension.awaitMessage("devtools_panel_hidden");
await extension.awaitMessage("devtools_panel_shown");
await extension.awaitMessage("devtools_panel_loaded");
await gDevTools.closeToolbox(target);
await target.destroy();
await extension.unload();
await BrowserTestUtils.removeTab(tab);
});

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

@ -89,6 +89,7 @@ add_task(async function testIdentityIndicationNewTab() {
let url = await extension.awaitMessage("url");
await BrowserTestUtils.withNewTab({gBrowser, url}, async function() {
confirmExtensionPage();
is(gURLBar.value, "", "The URL bar is blank");
});
await extension.unload();

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

@ -45,3 +45,52 @@ add_task(async function test_sending_message_from_newtab_page() {
await BrowserTestUtils.removeTab(gBrowser.selectedTab);
await extension.unload();
});
/**
* Ensure we don't show the extension URL in the URL bar temporarily in new tabs
* while we're switching remoteness (when the URL we're loading and the
* default content principal are different).
*/
add_task(async function dontTemporarilyShowAboutExtensionPath() {
let extension = ExtensionTestUtils.loadExtension({
manifest: {
name: "Test Extension",
applications: {
gecko: {
id: "newtab@mochi.test",
},
},
chrome_url_overrides: {
newtab: "newtab.html",
},
},
background() {
browser.test.sendMessage("url", browser.runtime.getURL("newtab.html"));
},
files: {
"newtab.html": "<h1>New tab!</h1>",
},
useAddonManager: "temporary",
});
await extension.startup();
let url = await extension.awaitMessage("url");
let wpl = {
onLocationChange() {
is(gURLBar.value, "", "URL bar value should stay empty.");
},
};
gBrowser.addProgressListener(wpl);
let tab = await BrowserTestUtils.openNewForegroundTab({gBrowser, url});
gBrowser.removeProgressListener(wpl);
is(gURLBar.value, "", "URL bar value should be empty.");
ContentTask.spawn(tab.linkedBrowser, null, function() {
is(content.document.body.textContent, "New tab!", "New tab page is loaded.");
});
await BrowserTestUtils.removeTab(tab);
await extension.unload();
});

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

@ -6,6 +6,8 @@ Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
Components.utils.import("resource://gre/modules/Services.jsm");
Components.utils.import("resource://gre/modules/AppConstants.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "HeadlessShell",
"resource:///modules/HeadlessShell.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "LaterRun",
"resource:///modules/LaterRun.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils",
@ -466,6 +468,10 @@ nsBrowserContentHandler.prototype = {
} else {
info += " --preferences Open Preferences dialog.\n";
}
if (AppConstants.platform == "win" || AppConstants.MOZ_WIDGET_GTK) {
info += " --screenshot [<path>] Save screenshot to <path> or in working directory.\n";
info += " --window-size width[,height] Width and optionally height of screenshot.\n";
}
info += " --search <term> Search <term> with your default search engine.\n";
return info;
},
@ -741,6 +747,11 @@ nsDefaultCommandLineHandler.prototype = {
Components.utils.reportError(e);
}
if (cmdLine.findFlag("screenshot", true) != -1) {
HeadlessShell.handleCmdLineArgs(cmdLine, urilist.filter(shouldLoadURI).map(u => u.spec));
return;
}
for (let i = 0; i < cmdLine.length; ++i) {
var curarg = cmdLine.getArgument(i);
if (curarg.match(/^-/)) {

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

@ -85,8 +85,8 @@
#else
<vbox>
#endif
<label accesskey="&overrideDefaultPageColors.accesskey;"
control="useDocumentColors">&overrideDefaultPageColors.label;</label>
<label accesskey="&overrideDefaultPageColors2.accesskey;"
control="useDocumentColors">&overrideDefaultPageColors2.label;</label>
<hbox>
<menulist id="useDocumentColors" preference="browser.display.document_color_use" flex="1">
<menupopup>

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

@ -6,6 +6,11 @@
/* import-globals-from ../../../../toolkit/mozapps/preferences/fontbuilder.js */
/* import-globals-from ../../../base/content/aboutDialog-appUpdater.js */
XPCOMUtils.defineLazyModuleGetter(this, "ExtensionPreferencesManager",
"resource://gre/modules/ExtensionPreferencesManager.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "AddonManager",
"resource://gre/modules/AddonManager.jsm");
Components.utils.import("resource://gre/modules/Services.jsm");
Components.utils.import("resource://gre/modules/Downloads.jsm");
Components.utils.import("resource://gre/modules/FileUtils.jsm");
@ -236,6 +241,8 @@ var gMainPane = {
gMainPane.setHomePageToBookmark);
setEventListener("restoreDefaultHomePage", "command",
gMainPane.restoreDefaultHomePage);
setEventListener("disableHomePageExtension", "command",
gMainPane.makeDisableControllingExtension("homepage_override"));
setEventListener("chooseLanguage", "command",
gMainPane.showLanguages);
setEventListener("translationAttributionImage", "click",
@ -620,6 +627,19 @@ var gMainPane = {
syncFromHomePref() {
let homePref = document.getElementById("browser.startup.homepage");
// Set the "Use Current Page(s)" button's text and enabled state.
this._updateUseCurrentButton();
// This is an async task.
handleControllingExtension("homepage_override")
.then((isControlled) => {
// Disable or enable the inputs based on if this is controlled by an extension.
document.querySelectorAll("#browserHomePage, .homepage-button")
.forEach((button) => {
button.disabled = isControlled;
});
});
// If the pref is set to about:home or about:newtab, set the value to ""
// to show the placeholder text (about:home title) rather than
// exposing those URLs to users.
@ -695,10 +715,8 @@ var gMainPane = {
* Switches the "Use Current Page" button between its singular and plural
* forms.
*/
_updateUseCurrentButton() {
async _updateUseCurrentButton() {
let useCurrent = document.getElementById("useCurrent");
let tabs = this._getTabsForHomePage();
if (tabs.length > 1)
@ -706,6 +724,12 @@ var gMainPane = {
else
useCurrent.label = useCurrent.getAttribute("label1");
// If the homepage is controlled by an extension then you can't use this.
if (await getControllingExtensionId("homepage_override")) {
useCurrent.disabled = true;
return;
}
// In this case, the button's disabled state is set by preferences.xml.
let prefName = "pref.browser.homepage.disable_button.current_page";
if (document.getElementById(prefName).locked)
@ -749,6 +773,14 @@ var gMainPane = {
homePage.value = homePage.defaultValue;
},
makeDisableControllingExtension(pref) {
return async function disableExtension() {
let id = await getControllingExtensionId(pref);
let addon = await AddonManager.getAddonByID(id);
addon.userDisabled = true;
};
},
/**
* Utility function to enable/disable the button specified by aButtonID based
* on the value of the Boolean preference specified by aPreferenceID.
@ -2571,6 +2603,66 @@ function getLocalHandlerApp(aFile) {
return localHandlerApp;
}
let extensionControlledContentIds = {
"homepage_override": "browserHomePageExtensionContent",
};
/**
* Check if a pref is being managed by an extension.
*/
function getControllingExtensionId(settingName) {
return ExtensionPreferencesManager.getControllingExtensionId(settingName);
}
function getControllingExtensionEl(settingName) {
return document.getElementById(extensionControlledContentIds[settingName]);
}
async function handleControllingExtension(prefName) {
let controllingExtensionId = await getControllingExtensionId(prefName);
if (controllingExtensionId) {
showControllingExtension(prefName, controllingExtensionId);
} else {
hideControllingExtension(prefName);
}
return !!controllingExtensionId;
}
async function showControllingExtension(settingName, extensionId) {
let extensionControlledContent = getControllingExtensionEl(settingName);
// Tell the user what extension is controlling the homepage.
let addon = await AddonManager.getAddonByID(extensionId);
const defaultIcon = "chrome://mozapps/skin/extensions/extensionGeneric.svg";
let stringParts = document
.getElementById("bundlePreferences")
.getString(`extensionControlled.${settingName}`)
.split("%S");
let description = extensionControlledContent.querySelector("description");
// Remove the old content from the description.
while (description.firstChild) {
description.firstChild.remove();
}
// Populate the description.
description.appendChild(document.createTextNode(stringParts[0]));
let image = document.createElement("image");
image.setAttribute("src", addon.iconURL || defaultIcon);
image.classList.add("extension-controlled-icon");
description.appendChild(image);
description.appendChild(document.createTextNode(` ${addon.name}`));
description.appendChild(document.createTextNode(stringParts[1]));
// Show the controlling extension row and hide the old label.
extensionControlledContent.hidden = false;
}
function hideControllingExtension(settingName) {
getControllingExtensionEl(settingName).hidden = true;
}
/**
* An enumeration of items in a JS array.
*

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

@ -348,6 +348,13 @@
hidden="true">
<caption><label>&homepage2.label;</label></caption>
<hbox id="browserHomePageExtensionContent" align="center">
<description control="disableHomePageExtension" flex="1" />
<button id="disableHomePageExtension"
class="extension-controlled-button accessory-button"
label="&disableExtension.label;" />
</hbox>
<vbox>
<textbox id="browserHomePage"
class="uri-element"
@ -572,7 +579,7 @@
icon="select-color"
label="&colors.label;"
accesskey="&colors.accesskey;"
searchkeywords="&overrideDefaultPageColors.label;
searchkeywords="&overrideDefaultPageColors2.label;
&overrideDefaultPageColors.always.label;
&overrideDefaultPageColors.auto.label;
&overrideDefaultPageColors.never.label;

Двоичный файл не отображается.

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

@ -3,6 +3,7 @@ support-files =
head.js
privacypane_tests_perwindow.js
site_data_test.html
addons/set_homepage.xpi
offline/offline.html
offline/manifest.appcache

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

@ -1,4 +1,4 @@
add_task(async function() {
add_task(async function testSetHomepageUseCurrent() {
is(gBrowser.currentURI.spec, "about:blank", "Test starts with about:blank open");
await BrowserTestUtils.openNewForegroundTab(gBrowser, "about:home");
await openPreferencesViaOpenPreferencesAPI("paneGeneral", {leaveOpen: true});
@ -18,3 +18,94 @@ add_task(async function() {
await BrowserTestUtils.removeTab(gBrowser.selectedTab);
await BrowserTestUtils.removeTab(gBrowser.selectedTab);
});
const TEST_DIR = gTestPath.substr(0, gTestPath.lastIndexOf("/"));
const CHROME_URL_ROOT = TEST_DIR + "/";
function getSupportsFile(path) {
let cr = Cc["@mozilla.org/chrome/chrome-registry;1"]
.getService(Ci.nsIChromeRegistry);
let uri = Services.io.newURI(CHROME_URL_ROOT + path);
let fileurl = cr.convertChromeURL(uri);
return fileurl.QueryInterface(Ci.nsIFileURL);
}
function installAddon() {
let filePath = getSupportsFile("addons/set_homepage.xpi").file;
return new Promise((resolve, reject) => {
AddonManager.getInstallForFile(filePath, install => {
if (!install) {
throw new Error(`An install was not created for ${filePath}`);
}
install.addListener({
onDownloadFailed: reject,
onDownloadCancelled: reject,
onInstallFailed: reject,
onInstallCancelled: reject,
onInstallEnded: resolve
});
install.install();
});
});
}
function waitForMessageChange(cb) {
return new Promise((resolve) => {
let target = gBrowser.contentDocument.getElementById("browserHomePageExtensionContent");
let observer = new MutationObserver(() => {
if (cb(target)) {
observer.disconnect();
resolve();
}
});
observer.observe(target, { attributes: true, attributeFilter: ["hidden"] });
});
}
function waitForMessageHidden() {
return waitForMessageChange(target => target.hidden);
}
function waitForMessageShown() {
return waitForMessageChange(target => !target.hidden);
}
add_task(async function testExtensionControlledHomepage() {
await openPreferencesViaOpenPreferencesAPI("paneGeneral", {leaveOpen: true});
let doc = gBrowser.contentDocument;
is(gBrowser.currentURI.spec, "about:preferences#general",
"#general should be in the URI for about:preferences");
let homepagePref = () => Services.prefs.getCharPref("browser.startup.homepage");
let originalHomepagePref = homepagePref();
let extensionHomepage = "https://developer.mozilla.org/";
let controlledContent = doc.getElementById("browserHomePageExtensionContent");
// The homepage is set to the default and editable.
ok(originalHomepagePref != extensionHomepage, "homepage is empty by default");
is(doc.getElementById("browserHomePage").disabled, false, "The homepage input is enabled");
is(controlledContent.hidden, true, "The extension controlled row is hidden");
// Install an extension that will set the homepage.
await installAddon();
await waitForMessageShown();
// The homepage has been set by the extension, the user is notified and it isn't editable.
let controlledLabel = controlledContent.querySelector("description");
is(homepagePref(), extensionHomepage, "homepage is set by extension");
// There are two spaces before "set_homepage" because it's " <image /> set_homepage".
is(controlledLabel.textContent, "An extension, set_homepage, controls your home page.",
"The user is notified that an extension is controlling the homepage");
is(controlledContent.hidden, false, "The extension controlled row is hidden");
is(doc.getElementById("browserHomePage").disabled, true, "The homepage input is disabled");
// Disable the extension.
doc.getElementById("disableHomePageExtension").click();
await waitForMessageHidden();
is(homepagePref(), originalHomepagePref, "homepage is set back to default");
is(doc.getElementById("browserHomePage").disabled, false, "The homepage input is enabled");
is(controlledContent.hidden, true, "The extension controlled row is hidden");
await BrowserTestUtils.removeTab(gBrowser.selectedTab);
});

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

@ -0,0 +1,161 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
let EXPORTED_SYMBOLS = ["HeadlessShell"];
Components.utils.import("resource://gre/modules/Services.jsm");
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
Components.utils.import("resource://gre/modules/osfile.jsm");
const Ci = Components.interfaces;
function loadContentWindow(webNavigation, uri) {
return new Promise((resolve, reject) => {
webNavigation.loadURI(uri, Ci.nsIWebNavigation.LOAD_FLAGS_NONE, null, null, null);
let docShell = webNavigation.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDocShell);
let webProgress = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebProgress);
let progressListener = {
onLocationChange(progress, request, location, flags) {
// Ignore inner-frame events
if (progress != webProgress) {
return;
}
// Ignore events that don't change the document
if (flags & Ci.nsIWebProgressListener.LOCATION_CHANGE_SAME_DOCUMENT) {
return;
}
let contentWindow = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindow);
webProgress.removeProgressListener(progressListener);
contentWindow.addEventListener("load", (event) => {
resolve(contentWindow);
}, { once: true });
},
QueryInterface: XPCOMUtils.generateQI(["nsIWebProgressListener",
"nsISupportsWeakReference"])
};
webProgress.addProgressListener(progressListener,
Ci.nsIWebProgress.NOTIFY_LOCATION);
});
}
async function takeScreenshot(fullWidth, fullHeight, contentWidth, contentHeight, path, url) {
try {
let windowlessBrowser = Services.appShell.createWindowlessBrowser(false);
var webNavigation = windowlessBrowser.QueryInterface(Ci.nsIWebNavigation);
let contentWindow = await loadContentWindow(webNavigation, url);
contentWindow.resizeTo(contentWidth, contentHeight);
let canvas = contentWindow.document.createElementNS("http://www.w3.org/1999/xhtml", "html:canvas");
let context = canvas.getContext("2d");
let width = fullWidth ? contentWindow.innerWidth + contentWindow.scrollMaxX - contentWindow.scrollMinX
: contentWindow.innerWidth;
let height = fullHeight ? contentWindow.innerHeight + contentWindow.scrollMaxY - contentWindow.scrollMinY
: contentWindow.innerHeight;
canvas.width = width;
canvas.height = height;
context.drawWindow(contentWindow, 0, 0, width, height, "rgb(255, 255, 255)");
function getBlob() {
return new Promise(resolve => canvas.toBlob(resolve));
}
function readBlob(blob) {
return new Promise(resolve => {
let reader = new FileReader();
reader.onloadend = () => resolve(reader);
reader.readAsArrayBuffer(blob);
});
}
let blob = await getBlob();
let reader = await readBlob(blob);
await OS.File.writeAtomic(path, new Uint8Array(reader.result), {flush: true});
dump("Screenshot saved to: " + path + "\n");
} catch (e) {
dump("Failure taking screenshot: " + e + "\n");
} finally {
if (webNavigation) {
webNavigation.close();
}
}
}
let HeadlessShell = {
async handleCmdLineArgs(cmdLine, URLlist) {
try {
// Don't quit even though we don't create a window
Services.startup.enterLastWindowClosingSurvivalArea();
// Default options
let fullWidth = true;
let fullHeight = true;
// Most common screen resolution of Firefox users
let contentWidth = 1366;
let contentHeight = 768;
// Parse `window-size`
try {
var dimensionsStr = cmdLine.handleFlagWithParam("window-size", true);
} catch (e) {
dump("expected format: --window-size width[,height]\n");
return;
}
if (dimensionsStr) {
let success;
let dimensions = dimensionsStr.split(",", 2);
if (dimensions.length == 1) {
success = dimensions[0] > 0;
if (success) {
fullWidth = false;
fullHeight = true;
contentWidth = dimensions[0];
}
} else {
success = dimensions[0] > 0 && dimensions[1] > 0;
if (success) {
fullWidth = false;
fullHeight = false;
contentWidth = dimensions[0];
contentHeight = dimensions[1];
}
}
if (!success) {
dump("expected format: --window-size width[,height]\n");
return;
}
}
// Only command line argument left should be `screenshot`
// There could still be URLs however
try {
var path = cmdLine.handleFlagWithParam("screenshot", true);
if (!cmdLine.length && !URLlist.length) {
URLlist.push(path); // Assume the user wanted to specify a URL
path = OS.Path.join(cmdLine.workingDirectory.path, "screenshot.png");
}
} catch (e) {
path = OS.Path.join(cmdLine.workingDirectory.path, "screenshot.png");
cmdLine.handleFlag("screenshot", true); // Remove `screenshot`
}
for (let i = 0; i < cmdLine.length; ++i) {
URLlist.push(cmdLine.getArgument(i)); // Assume that all remaining arguments are URLs
}
if (URLlist.length == 1) {
await takeScreenshot(fullWidth, fullHeight, contentWidth, contentHeight, path, URLlist[0]);
} else {
dump("expected exactly one URL when using `screenshot`\n");
}
} finally {
Services.startup.exitLastWindowClosingSurvivalArea();
}
}
};

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

@ -11,6 +11,7 @@ LOCAL_INCLUDES += [
XPCSHELL_TESTS_MANIFESTS += ['test/unit/xpcshell.ini']
BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
MOCHITEST_CHROME_MANIFESTS += ['test/chrome.ini']
JAR_MANIFESTS += ['jar.mn']
@ -54,6 +55,7 @@ EXTRA_COMPONENTS += [
]
EXTRA_JS_MODULES += [
'HeadlessShell.jsm',
'ShellService.jsm',
]

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

@ -0,0 +1,5 @@
[DEFAULT]
support-files = headless.html
[test_headless_screenshot.html]
skip-if = (os != 'win' && os != 'linux')

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

@ -0,0 +1,6 @@
<html>
<head><meta content="text/html; charset=utf-8" http-equiv="Content-Type"></head>
<body style="background-color: rgb(0, 255, 0); color: rgb(0, 0, 255)">
Hi
</body>
</html>

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

@ -0,0 +1,124 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1378010
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 1378010</title>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
<script type="application/javascript">
Components.utils.import("resource://gre/modules/Services.jsm");
Components.utils.import("resource://gre/modules/Subprocess.jsm");
Components.utils.import("resource://gre/modules/osfile.jsm");
const screenshotPath = OS.Path.join(OS.Constants.Path.tmpDir, "headless_test_screenshot.png");
async function runFirefox(args) {
const Ci = Components.interfaces;
const XRE_EXECUTABLE_FILE = "XREExeF";
const firefoxExe = Services.dirsvc.get(XRE_EXECUTABLE_FILE, Ci.nsIFile).path;
const NS_APP_PREFS_50_FILE = "PrefF";
const mochiPrefsFile = Services.dirsvc.get(NS_APP_PREFS_50_FILE, Ci.nsIFile);
const mochiPrefsPath = mochiPrefsFile.path;
const mochiPrefsName = mochiPrefsFile.leafName;
const profilePath = OS.Path.join(OS.Constants.Path.tmpDir, "headless_test_screenshot_profile");
const prefsPath = OS.Path.join(profilePath, mochiPrefsName);
const firefoxArgs = ["-profile", profilePath, "-no-remote"];
await OS.File.makeDir(profilePath);
await OS.File.copy(mochiPrefsPath, prefsPath);
let proc = await Subprocess.call({
command: firefoxExe,
arguments: firefoxArgs.concat(args),
});
let stdout;
while ((stdout = await proc.stdout.readString())) {
dump(">>> " + stdout + "\n");
}
let {exitCode} = await proc.wait();
is(exitCode, 0, "Firefox process should exit with code 0");
await OS.File.removeDir(profilePath);
}
async function testFileCreationPositive(args, path) {
await runFirefox(args);
let saved = await OS.File.exists(path);
ok(saved, "A screenshot should be saved as " + path);
if (!saved) {
return;
}
let info = await OS.File.stat(path);
ok(info.size > 0, "Screenshot should not be an empty file");
await OS.File.remove(path);
}
async function testFileCreationNegative(args, path) {
await runFirefox(args);
let saved = await OS.File.exists(path);
ok(!saved, "A screenshot should not be saved");
await OS.File.remove(path, { ignoreAbsent: true });
}
async function testWindowSizePositive(width, height) {
let size = width + "";
if (height) {
size += "," + height;
}
await runFirefox(["-url", "http://mochi.test:8888/headless.html", "-screenshot", screenshotPath, "-window-size", size]);
let saved = await OS.File.exists(screenshotPath);
ok(saved, "A screenshot should be saved in the tmp directory");
if (!saved) {
return;
}
let data = await OS.File.read(screenshotPath);
await new Promise((resolve, reject) => {
let blob = new Blob([data], { type: "image/png" });
let reader = new FileReader();
reader.onloadend = function() {
let screenshot = new Image();
screenshot.onloadend = function() {
is(screenshot.width, width, "Screenshot should be " + width + " pixels wide");
if (height) {
is(screenshot.height, height, "Screenshot should be " + height + " pixels tall");
}
resolve();
};
screenshot.src = reader.result;
};
reader.readAsDataURL(blob);
});
await OS.File.remove(screenshotPath);
}
(async function() {
SimpleTest.waitForExplicitFinish();
await testFileCreationPositive(["-url", "http://mochi.test:8888/headless.html", "-screenshot", screenshotPath], screenshotPath);
await testFileCreationPositive(["-screenshot", "http://mochi.test:8888/headless.html"], "screenshot.png");
await testFileCreationPositive(["http://mochi.test:8888/headless.html", "-screenshot"], "screenshot.png");
await testFileCreationNegative(["-screenshot"], "screenshot.png");
await testFileCreationNegative(["http://mochi.test:8888/headless.html", "http://mochi.test:8888/headless.html", "-screenshot"], "screenshot.png");
await testWindowSizePositive(800, 600);
await testWindowSizePositive(1234);
await testFileCreationNegative(["-url", "http://mochi.test:8888/headless.html", "-screenshot", screenshotPath, "-window-size", "hello"], screenshotPath);
await testFileCreationNegative(["-url", "http://mochi.test:8888/headless.html", "-screenshot", screenshotPath, "-window-size", "800,"], screenshotPath);
SimpleTest.finish();
})();
</script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1378010">Mozilla Bug 1378010</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
</pre>
</body>
</html>

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

@ -100,6 +100,13 @@ when there are no windows but Firefox is still running. -->
<!ENTITY pageSourceCmd.label "Page Source">
<!ENTITY pageSourceCmd.accesskey "o">
<!ENTITY pageSourceCmd.commandkey "u">
<!-- LOCALIZATION NOTE (pageSourceCmd.SafariCommandKey should match the
Option+Command keyboard shortcut letter that Safari and Chrome use for "View
Source" on macOS. pageSourceCmd.commandkey above is Firefox's official keyboard
shortcut shown in the GUI. SafariCommandKey is an alias provided for the
convenience of Safari and Chrome users on macOS. See bug 1398988. -->
<!ENTITY pageSourceCmd.SafariCommandKey "u">
<!ENTITY pageInfoCmd.label "Page Info">
<!ENTITY pageInfoCmd.accesskey "I">
<!ENTITY pageInfoCmd.commandkey "i">

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

@ -6,8 +6,8 @@
<!ENTITY window.width "38em">
<!ENTITY window.macWidth "41em">
<!ENTITY overrideDefaultPageColors.label "Override the colors specified by the page with your selections above:">
<!ENTITY overrideDefaultPageColors.accesskey "O">
<!ENTITY overrideDefaultPageColors2.label "Override the colors specified by the page with your selections above">
<!ENTITY overrideDefaultPageColors2.accesskey "O">
<!ENTITY overrideDefaultPageColors.always.label "Always">
<!ENTITY overrideDefaultPageColors.auto.label "Only with High Contrast themes">

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

@ -20,6 +20,8 @@
<!ENTITY restoreDefault.label "Restore to Default">
<!ENTITY restoreDefault.accesskey "R">
<!ENTITY disableExtension.label "Disable Extension">
<!ENTITY downloads.label "Downloads">
<!ENTITY saveTo.label "Save files to">

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

@ -277,3 +277,7 @@ searchResults.needHelp2=Need help? Visit <html:a id="need-help-link" target="_bl
# LOCALIZATION NOTE %S is the default value of the `dom.ipc.processCount` pref.
defaultContentProcessCount=%S (default)
# LOCALIZATION NOTE (extensionControlled.homepage_override):
# This string is shown to notify the user that their home page is being controlled by an extension.
extensionControlled.homepage_override = An extension, %S, controls your home page.

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

@ -30,7 +30,7 @@
}
#customization-header {
font-weight: 600;
font-weight: 500;
font-size: 1.2em;
margin: 20px 20px 15px;
}
@ -419,11 +419,16 @@ toolbarpaletteitem[place=toolbar] > toolbarspring {
color: var(--arrowpanel-color);
background: var(--arrowpanel-background);
background-clip: padding-box;
border: 1px solid var(--arrowpanel-border-color);
box-shadow: 0 0 10px hsla(0,0%,0%,.2);
%ifdef XP_MACOSX
/* Native styling adds more 'oompf' to the popup box-shadow, so simulate that
* as best as we can here: */
border: 1px solid var(--arrowpanel-dimmed-even-further);
box-shadow: 0 4px 10px hsla(0,0%,0%,.3);
-moz-appearance: none;
border-radius: var(--arrowpanel-border-radius);
%else
border: 1px solid var(--arrowpanel-border-color);
box-shadow: 0 0 4px hsla(0,0%,0%,.2);
%endif
}
@ -433,6 +438,17 @@ toolbarpaletteitem[place=toolbar] > toolbarspring {
margin-bottom: -1px;
}
/* The overflow button icon _looks_ disabled, but is also shown as [open]. */
#nav-bar[customizing] > .overflow-button {
/* This color is the hard-coded #4c4c4c at 40% opacity as found in toolbarbutton-icons.inc.css */
fill: hsla(0,0%,30%,.4);
}
#nav-bar[customizing] > .overflow-button > .toolbarbutton-icon {
background-color: var(--toolbarbutton-active-background);
opacity: 1;
}
#customization-panelWrapper > .panel-arrowbox > .panel-arrow[side="top"] {
%ifdef XP_MACOSX
list-style-image: var(--panel-arrow-image-vertical,
@ -454,14 +470,14 @@ toolbarpaletteitem[place=toolbar] > toolbarspring {
* + 2 * toolbarbutton-inner-padding)
* hamburger button border + margin: 1px + 2px
* The total desired offset from the right edge of the window is thus:
* 10px + toolbarbutton-inner-padding (center of overflow button) +
* 10px + 1 * toolbarbutton-inner-padding (center of overflow button) +
* 29px + 2 * toolbarbutton-inner-padding
* The #customization-panel-container has a 25px margin, so that leaves:
* 14px + 3 * toolbarbutton-inner-padding
* The #customization-panel-container has a 20px margin, so that leaves:
* 19px + 3 * toolbarbutton-inner-padding
* Finally, we need to center the arrow, which is 20px wide, so subtract
* 10px.
*/
margin-inline-end: calc(4px + 3 * var(--toolbarbutton-inner-padding));
margin-inline-end: calc(9px + 3 * var(--toolbarbutton-inner-padding));
vertical-align: top;
}

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

@ -159,6 +159,13 @@ separator.thin:not([orient="vertical"]) {
margin-inline-end: 0;
}
.extension-controlled-icon {
height: 20px;
margin-bottom: 6px;
vertical-align: bottom;
width: 20px;
}
#getStarted {
font-size: 90%;
}

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

@ -52,7 +52,7 @@ exports.testBasic = function (options) {
current: "hello",
status: "ERROR",
predictions: [
"Shalom", "Namasté", "Hallo", "Dydd-da", "Chào", "Hej",
"Shalom", "Namast\u{00E9}", "Hallo", "Dydd-da", "Ch\u{00E0}o", "Hej",
"Saluton", "Sawubona"
],
unassigned: [ ],
@ -74,7 +74,7 @@ exports.testBasic = function (options) {
cursor: 8,
current: "hello",
status: "ERROR",
predictions: [ "Shalom", "Saluton", "Sawubona", "Namasté" ],
predictions: [ "Shalom", "Saluton", "Sawubona", "Namast\u{00E9}" ],
unassigned: [ ],
args: {
command: { name: "tsslow" },

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

@ -17,7 +17,7 @@ var flags = require("devtools/shared/flags");
// Import the GCLI test helper
var testDir = gTestPath.substr(0, gTestPath.lastIndexOf("/"));
Services.scriptloader.loadSubScript(testDir + "/helpers.js", this);
Services.scriptloader.loadSubScript(testDir + "/mockCommands.js", this);
Services.scriptloader.loadSubScript(testDir + "/mockCommands.js", this, "UTF-8");
flags.testing = true;
SimpleTest.registerCleanupFunction(() => {

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

@ -1547,6 +1547,11 @@ Toolbox.prototype = {
* the id of the additional tool to unregister and remove.
*/
removeAdditionalTool(toolId) {
// Early exit if the toolbox is already destroying itself.
if (this._destroyer) {
return;
}
if (!this.hasAdditionalTool(toolId)) {
throw new Error("Tool definition not registered to this toolbox: " +
toolId);

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

@ -117,7 +117,11 @@ GridInspector.prototype = {
this.inspector.reflowTracker.untrackReflows(this, this.onReflow);
this.swatchColorPickerTooltip.destroy();
// The color picker may not be ready as `init` function is async,
// and we do not wait for its completion before calling destroy in tests
if (this.swatchColorPickerTooltip) {
this.swatchColorPickerTooltip.destroy();
}
this.document = null;
this.highlighters = null;

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

@ -23,7 +23,6 @@ const Store = require("devtools/client/inspector/store");
loader.lazyRequireGetter(this, "initCssProperties", "devtools/shared/fronts/css-properties", true);
loader.lazyRequireGetter(this, "HTMLBreadcrumbs", "devtools/client/inspector/breadcrumbs", true);
loader.lazyRequireGetter(this, "KeyShortcuts", "devtools/client/shared/key-shortcuts");
loader.lazyRequireGetter(this, "GridInspector", "devtools/client/inspector/grids/grid-inspector");
loader.lazyRequireGetter(this, "InspectorSearch", "devtools/client/inspector/inspector-search", true);
loader.lazyRequireGetter(this, "ToolSidebar", "devtools/client/inspector/toolsidebar", true);
loader.lazyRequireGetter(this, "MarkupView", "devtools/client/inspector/markup/markup");
@ -627,12 +626,28 @@ Inspector.prototype = {
INSPECTOR_L10N.getStr("inspector.sidebar.computedViewTitle"),
defaultTab == "computedview");
// Grid and layout panels aren't lazy-loaded as their module end up
// calling inspector.addSidebarTab
this.gridInspector = new GridInspector(this, this.panelWin);
const LayoutView = this.browserRequire("devtools/client/inspector/layout/layout");
this.layoutview = new LayoutView(this, this.panelWin);
// Inject a lazy loaded react tab by exposing a fake React object
// with a lazy defined Tab thanks to `panel` being a function
let layoutId = "layoutview";
let layoutTitle = INSPECTOR_L10N.getStr("inspector.sidebar.layoutViewTitle2");
this.sidebar.addTab(
layoutId,
layoutTitle,
{
props: {
id: layoutId,
title: layoutTitle
},
panel: () => {
if (!this.layoutview) {
const LayoutView =
this.browserRequire("devtools/client/inspector/layout/layout");
this.layoutview = new LayoutView(this, this.panelWin);
}
return this.layoutview.provider;
}
},
defaultTab == layoutId);
if (this.target.form.animationsActor) {
this.sidebar.addFrameTab(
@ -1053,10 +1068,6 @@ Inspector.prototype = {
}
this._panels.clear();
if (this.gridInspector) {
this.gridInspector.destroy();
}
if (this.layoutview) {
this.layoutview.destroy();
}

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

@ -21,6 +21,8 @@ const PROMOTE_COUNT_PREF = "devtools.promote.layoutview";
// @remove after release 56 (See Bug 1355747)
const GRID_LINK = "https://www.mozilla.org/en-US/developer/css-grid/?utm_source=gridtooltip&utm_medium=devtools&utm_campaign=cssgrid_layout";
loader.lazyRequireGetter(this, "GridInspector", "devtools/client/inspector/grids/grid-inspector");
function LayoutView(inspector, window) {
this.document = window.document;
this.inspector = inspector;
@ -50,6 +52,7 @@ LayoutView.prototype = {
onToggleGeometryEditor,
} = this.inspector.getPanel("boxmodel").getComponentProps();
this.gridInspector = new GridInspector(this.inspector, this.inspector.panelWin);
let {
getSwatchColorPickerTooltip,
onSetGridOverlayColor,
@ -60,7 +63,7 @@ LayoutView.prototype = {
onToggleShowGridAreas,
onToggleShowGridLineNumbers,
onToggleShowInfiniteLines,
} = this.inspector.gridInspector.getComponentProps();
} = this.gridInspector.getComponentProps();
let {
onPromoteLearnMoreClick,
@ -101,20 +104,16 @@ LayoutView.prototype = {
showBadge: () => Services.prefs.getIntPref(PROMOTE_COUNT_PREF) > 0,
}, app);
let defaultTab = Services.prefs.getCharPref("devtools.inspector.activeSidebar");
this.inspector.addSidebarTab(
"layoutview",
INSPECTOR_L10N.getStr("inspector.sidebar.layoutViewTitle2"),
provider,
defaultTab == "layoutview"
);
// Expose the provider to let inspector.js use it in setupSidebar.
this.provider = provider;
},
/**
* Destruction function called when the inspector is destroyed. Cleans up references.
*/
destroy() {
this.gridInspector.destroy();
this.document = null;
this.inspector = null;
this.store = null;

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

@ -53,6 +53,7 @@ var openInspectorSidebarTab = Task.async(function* (id) {
info("Selecting the " + id + " sidebar");
let onSidebarSelect = inspector.sidebar.once("select");
if (id === "computedview" || id === "layoutview") {
// The layout and computed views should wait until the box-model widget is ready.
let onBoxModelViewReady = inspector.once("boxmodel-view-updated");
@ -61,6 +62,7 @@ var openInspectorSidebarTab = Task.async(function* (id) {
} else {
inspector.sidebar.select(id);
}
yield onSidebarSelect;
return {
toolbox,
@ -134,7 +136,7 @@ function openLayoutView() {
toolbox: data.toolbox,
inspector: data.inspector,
boxmodel: data.inspector.getPanel("boxmodel"),
gridInspector: data.inspector.gridInspector,
gridInspector: data.inspector.layoutview.gridInspector,
testActor: data.testActor
};
});

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

@ -334,6 +334,13 @@ define(function (require, exports, module) {
width: selected ? "100%" : "0",
};
// Allows lazy loading panels by creating them only if they are selected,
// then store a copy of the lazy created panel in `tab.panel`.
if (typeof tab.panel == "function" && selected) {
tab.panel = tab.panel(tab);
}
let panel = tab.panel || tab;
return (
DOM.div({
id: id ? id + "-panel" : "panel-" + index,
@ -343,7 +350,7 @@ define(function (require, exports, module) {
role: "tabpanel",
"aria-labelledby": id ? id + "-tab" : "tab-" + index,
},
(selected || this.state.created[index]) ? tab : null
(selected || this.state.created[index]) ? panel : null
)
);
});

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

@ -982,6 +982,16 @@ EffectCompositor::PreTraverseInSubtree(ServoTraversalFlags aFlags,
"Traversal root, if provided, should be bound to a display "
"document");
// Convert the root element to the parent element if the root element is
// pseudo since we check each element in mElementsToRestyle is in the subtree
// of the root element later in this function, but for pseudo elements the
// element in mElementsToRestyle is the parent of the pseudo.
if (aRoot &&
(aRoot->IsGeneratedContentContainerForBefore() ||
aRoot->IsGeneratedContentContainerForAfter())) {
aRoot = aRoot->GetParentElement();
}
AutoRestore<bool> guard(mIsInPreTraverse);
mIsInPreTraverse = true;

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

@ -34,7 +34,6 @@ DEPRECATED_OPERATION(UseOfReleaseEvents)
DEPRECATED_OPERATION(UseOfDOM3LoadMethod)
DEPRECATED_OPERATION(ChromeUseOfDOM3LoadMethod)
DEPRECATED_OPERATION(ShowModalDialog)
DEPRECATED_OPERATION(Window_Content)
DEPRECATED_OPERATION(SyncXMLHttpRequest)
DEPRECATED_OPERATION(Window_Cc_ontrollers)
DEPRECATED_OPERATION(ImportXULIntoContent)

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

@ -1234,17 +1234,6 @@ public:
return win.forget();
}
void Get_content(JSContext* aCx,
JS::MutableHandle<JSObject*> aRetval,
mozilla::dom::SystemCallerGuarantee aCallerType,
mozilla::ErrorResult& aError)
{
if (mDoc) {
mDoc->WarnOnceAbout(nsIDocument::eWindow_Content);
}
GetContent(aCx, aRetval, aCallerType, aError);
}
already_AddRefed<mozilla::dom::Promise>
CreateImageBitmap(JSContext* aCx,
const mozilla::dom::ImageBitmapSource& aImage,

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

@ -2458,6 +2458,7 @@ WebGLContext::ValidateArrayBufferView(const char* funcName,
void
WebGLContext::UpdateMaxDrawBuffers()
{
gl->MakeCurrent();
mGLMaxColorAttachments = gl->GetIntAs<uint32_t>(LOCAL_GL_MAX_COLOR_ATTACHMENTS);
mGLMaxDrawBuffers = gl->GetIntAs<uint32_t>(LOCAL_GL_MAX_DRAW_BUFFERS);

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

@ -181,8 +181,6 @@ UseOfReleaseEventsWarning=Use of releaseEvents() is deprecated. To upgrade your
UseOfDOM3LoadMethodWarning=Use of document.load() is deprecated. To upgrade your code, use the DOM XMLHttpRequest object. For more help https://developer.mozilla.org/en/XMLHttpRequest
# LOCALIZATION NOTE: Do not translate "window.showModalDialog()" or "window.open()"
ShowModalDialogWarning=Use of window.showModalDialog() is deprecated. Use window.open() instead. For more help https://developer.mozilla.org/en-US/docs/Web/API/Window.open
# LOCALIZATION NOTE: Do not translate "window._content" or "window.content"
Window_ContentWarning=window._content is deprecated. Please use window.content instead.
# LOCALIZATION NOTE: Do not translate "XMLHttpRequest"
SyncXMLHttpRequestWarning=Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end users experience. For more help http://xhr.spec.whatwg.org/
ImplicitMetaViewportTagFallback=No meta-viewport tag found. Please explicitly specify one to prevent unexpected behavioural changes in future versions. For more help https://developer.mozilla.org/en/docs/Mozilla/Mobile/Viewport_meta_tag

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

@ -55,7 +55,6 @@ skip-if = !e10s || (os == "win" && processor == "x86") # Large-Allocation requir
[browser_localStorage_e10s.js]
skip-if = !e10s # This is a test of e10s functionality.
[browser_localStorage_privatestorageevent.js]
[browser_test__content.js]
[browser_test_focus_after_modal_state.js]
support-files =
focus_after_prompt.html

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

@ -1,4 +0,0 @@
function test() {
is(window._content, window.content,
"_content needs to work, since extensions use it");
}

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

@ -1,8 +1,10 @@
# WebVR Reftests
default-preferences pref(dom.vr.puppet.enabled,true) pref(dom.vr.test.enabled,true) pref(dom.vr.require-gesture,false) pref(dom.vr.puppet.submitframe,1)
# VR SubmitFrame is only implemented for D3D11 now.
# VR SubmitFrame is only implemented for D3D11 and MacOSX now.
# We need to continue to investigate why these reftests can be run well in local,
# but will be suspended until terminating on reftest debug build.
skip-if(!winWidget||!layersGPUAccelerated||isDebugBuild) == draw_rect.html wrapper.html?draw_rect.png
skip-if(!winWidget||!layersGPUAccelerated||isDebugBuild) == change_size.html wrapper.html?change_size.png
# but will be suspended until terminating on reftest D3D11 debug build.
skip-if(Android||gtkWidget||(winWidget&&isDebugBuild)||!layersGPUAccelerated) == draw_rect.html wrapper.html?draw_rect.png
# On MacOSX platform, getting different color interpolation result.
# For lower resolution Mac hardware, we need to adjust it to fuzzy-if(cocoaWidget,1,1200).
fuzzy-if(cocoaWidget,1,600) skip-if(Android||gtkWidget||(winWidget&&isDebugBuild)||!layersGPUAccelerated) == change_size.html wrapper.html?change_size.png

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

@ -338,8 +338,6 @@ partial interface Window {
[Replaceable, Throws, NeedsCallerType] readonly attribute object? content;
[ChromeOnly, Throws, NeedsCallerType] readonly attribute object? __content;
[Throws, ChromeOnly] any getInterface(IID iid);
/**

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

@ -229,16 +229,22 @@ WebRenderLayerManager::CreateWebRenderCommandsFromDisplayList(nsDisplayList* aDi
// Peek ahead to the next item and try merging with it or swapping with it
// if necessary.
nsDisplayItem* aboveItem;
while ((aboveItem = aDisplayList->GetBottom()) != nullptr) {
if (aboveItem->TryMerge(item)) {
aDisplayList->RemoveBottom();
item->Destroy(aDisplayListBuilder);
item = aboveItem;
itemType = item->GetType();
} else {
AutoTArray<nsDisplayItem*, 1> mergedItems;
mergedItems.AppendElement(item);
for (nsDisplayItem* peek = item->GetAbove(); peek; peek = peek->GetAbove()) {
if (!item->CanMerge(peek)) {
break;
}
mergedItems.AppendElement(peek);
// Move the iterator forward since we will merge this item.
item = peek;
}
if (mergedItems.Length() > 1) {
item = aDisplayListBuilder->MergeItems(mergedItems);
MOZ_ASSERT(item && itemType == item->GetType());
}
nsDisplayList* itemSameCoordinateSystemChildren

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

@ -2006,6 +2006,7 @@ gfxFont::DrawEmphasisMarks(const gfxTextRun* aShapedText, gfxPoint* aPt,
gfxFloat& inlineCoord = aParams.isVertical ? aPt->y : aPt->x;
gfxTextRun::Range markRange(aParams.mark);
gfxTextRun::DrawParams params(aParams.context);
params.textDrawer = aParams.textDrawer;
gfxFloat clusterStart = -std::numeric_limits<gfxFloat>::infinity();
bool shouldDrawEmphasisMark = false;

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

@ -75,6 +75,9 @@ class SVGContextPaint;
namespace gfx {
class GlyphRenderingOptions;
} // namespace gfx
namespace layout {
class TextDrawTarget;
} // namespace layout
} // namespace mozilla
struct gfxFontStyle {
@ -2310,6 +2313,7 @@ struct MOZ_STACK_CLASS FontDrawParams {
struct MOZ_STACK_CLASS EmphasisMarkDrawParams {
gfxContext* context;
mozilla::layout::TextDrawTarget* textDrawer = nullptr;
gfxFont::Spacing* spacing;
gfxTextRun* mark;
gfxFloat advance;

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

@ -607,7 +607,7 @@ gfxTextRun::Draw(Range aRange, gfxPoint aPt, const DrawParams& aParams) const
if (aParams.drawMode & DrawMode::GLYPH_FILL) {
Color currentColor;
if (aParams.context->GetDeviceColor(currentColor) &&
currentColor.a == 0) {
currentColor.a == 0 && !aParams.textDrawer) {
skipDrawing = true;
}
}
@ -724,7 +724,9 @@ gfxTextRun::Draw(Range aRange, gfxPoint aPt, const DrawParams& aParams) const
// This method is mostly parallel to Draw().
void
gfxTextRun::DrawEmphasisMarks(gfxContext *aContext, gfxTextRun* aMark,
gfxTextRun::DrawEmphasisMarks(gfxContext *aContext,
mozilla::layout::TextDrawTarget* aTextDrawer,
gfxTextRun* aMark,
gfxFloat aMarkAdvance, gfxPoint aPt,
Range aRange, PropertyProvider* aProvider) const
{
@ -732,6 +734,7 @@ gfxTextRun::DrawEmphasisMarks(gfxContext *aContext, gfxTextRun* aMark,
EmphasisMarkDrawParams params;
params.context = aContext;
params.textDrawer = aTextDrawer;
params.mark = aMark;
params.advance = aMarkAdvance;
params.direction = GetDirection();

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

@ -42,6 +42,9 @@ class gfxMissingFontRecorder;
namespace mozilla {
class SVGContextPaint;
enum class StyleHyphens : uint8_t;
namespace layout {
class TextDrawTarget;
};
};
/**
@ -244,6 +247,7 @@ public:
struct MOZ_STACK_CLASS DrawParams
{
gfxContext* context;
mozilla::layout::TextDrawTarget* textDrawer = nullptr;
DrawMode drawMode = DrawMode::GLYPH_FILL;
nscolor textStrokeColor = 0;
gfxPattern* textStrokePattern = nullptr;
@ -284,7 +288,9 @@ public:
* from aProvider. The provided point is the baseline origin of the
* line of emphasis marks.
*/
void DrawEmphasisMarks(gfxContext* aContext, gfxTextRun* aMark,
void DrawEmphasisMarks(gfxContext* aContext,
mozilla::layout::TextDrawTarget* aTextDrawer,
gfxTextRun* aMark,
gfxFloat aMarkAdvance, gfxPoint aPt,
Range aRange, PropertyProvider* aProvider) const;

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

@ -7,12 +7,16 @@
#include "CompositorD3D11.h"
#include "TextureD3D11.h"
#include "mozilla/gfx/DeviceManagerDx.h"
#endif // XP_WIN
#elif defined(XP_MACOSX)
#include "mozilla/gfx/MacIOSurface.h"
#endif
#include "mozilla/Base64.h"
#include "mozilla/gfx/DataSurfaceHelpers.h"
#include "gfxPrefs.h"
#include "gfxUtils.h"
#include "gfxVRPuppet.h"
#include "VRManager.h"
#include "mozilla/dom/GamepadEventTypes.h"
#include "mozilla/dom/GamepadBinding.h"
@ -38,19 +42,9 @@ static const uint64_t kPuppetButtonMask[] = {
4,
8
};
static const uint32_t kNumPuppetButtonMask = sizeof(kPuppetButtonMask) /
sizeof(uint64_t);
static const uint32_t kPuppetAxes[] = {
0,
1,
2
};
static const uint32_t kNumPuppetAxis = sizeof(kPuppetAxes) /
sizeof(uint32_t);
static const uint32_t kNumPuppetAxis = 3;
static const uint32_t kNumPuppetHaptcs = 1;
VRDisplayPuppet::VRDisplayPuppet()
@ -378,7 +372,7 @@ VRDisplayPuppet::SubmitFrame(TextureSourceD3D11* aSource,
result.mWidth = mapInfo.RowPitch / 4;
result.mHeight = desc.Height;
result.mFrameNum = mDisplayInfo.mFrameId;
nsCString rawString(Substring((char*)srcData, mapInfo.RowPitch * desc.Height));
nsCString rawString(Substring(srcData, mapInfo.RowPitch * desc.Height));
if (Base64Encode(rawString, result.mBase64Image) != NS_OK) {
MOZ_ASSERT(false, "Failed to encode base64 images.");
@ -474,12 +468,66 @@ VRDisplayPuppet::SubmitFrame(MacIOSurface* aMacIOSurface,
const gfx::Rect& aLeftEyeRect,
const gfx::Rect& aRightEyeRect)
{
if (!mIsPresenting) {
if (!mIsPresenting || !aMacIOSurface) {
return false;
}
// TODO: Bug 1343730, Need to block until the next simulated
// vblank interval and capture frames for use in reftests.
VRManager* vm = VRManager::Get();
MOZ_ASSERT(vm);
switch (gfxPrefs::VRPuppetSubmitFrame()) {
case 0:
// The VR frame is not displayed.
break;
case 1:
{
// The frames are submitted to VR compositor are decoded
// into a base64Image and dispatched to the DOM side.
RefPtr<SourceSurface> surf = aMacIOSurface->GetAsSurface();
RefPtr<DataSourceSurface> dataSurf = surf ? surf->GetDataSurface() :
nullptr;
if (dataSurf) {
// Ideally, we should convert the srcData to a PNG image and decode it
// to a Base64 string here, but the GPU process does not have the privilege to
// access the image library. So, we have to convert the RAW image data
// to a base64 string and forward it to let the content process to
// do the image conversion.
DataSourceSurface::MappedSurface map;
if (!dataSurf->Map(gfx::DataSourceSurface::MapType::READ, &map)) {
MOZ_ASSERT(false, "Read DataSourceSurface fail.");
return false;
}
const uint8_t* srcData = map.mData;
const auto& surfSize = dataSurf->GetSize();
VRSubmitFrameResultInfo result;
result.mFormat = SurfaceFormat::B8G8R8A8;
result.mWidth = surfSize.width;
result.mHeight = surfSize.height;
result.mFrameNum = mDisplayInfo.mFrameId;
// If the original texture size is not pow of 2, the data will not be tightly strided.
// We have to copy the pixels by rows.
nsCString rawString;
for (int32_t i = 0; i < surfSize.height; i++) {
rawString += Substring((const char*)(srcData) + i * map.mStride,
surfSize.width * 4);
}
dataSurf->Unmap();
if (Base64Encode(rawString, result.mBase64Image) != NS_OK) {
MOZ_ASSERT(false, "Failed to encode base64 images.");
}
// Dispatch the base64 encoded string to the DOM side. Then, it will be decoded
// and convert to a PNG image there.
vm->DispatchSubmitFrameResult(mDisplayInfo.mDisplayID, result);
}
break;
}
case 2:
{
MOZ_ASSERT(false, "No support for showing VR frames on MacOSX yet.");
break;
}
}
return false;
}
@ -707,7 +755,7 @@ VRSystemManagerPuppet::HandleAxisMove(uint32_t aControllerIdx, uint32_t aAxis,
void
VRSystemManagerPuppet::HandlePoseTracking(uint32_t aControllerIdx,
const GamepadPoseState& aPose,
const dom::GamepadPoseState& aPose,
VRControllerHost* aController)
{
MOZ_ASSERT(aController);

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

@ -24,7 +24,6 @@ LOCAL_INCLUDES += [
UNIFIED_SOURCES += [
'gfxVR.cpp',
'gfxVROSVR.cpp',
'gfxVRPuppet.cpp',
'ipc/VRLayerChild.cpp',
'ipc/VRLayerParent.cpp',
'ipc/VRManagerChild.cpp',
@ -38,6 +37,7 @@ UNIFIED_SOURCES += [
# which define Size and Points types in the root namespace that
# often conflict with our own types.
SOURCES += [
'gfxVRPuppet.cpp',
'VRDisplayHost.cpp',
]

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

@ -445,19 +445,14 @@ js::IsAnyBuiltinEval(JSFunction* fun)
}
static bool
ExecuteInNonSyntacticGlobalInternal(JSContext* cx, HandleObject global, HandleScript scriptArg,
HandleObject varEnv, HandleObject lexEnv)
ExecuteInExtensibleLexicalEnvironment(JSContext* cx, HandleScript scriptArg, HandleObject env)
{
CHECK_REQUEST(cx);
assertSameCompartment(cx, global, varEnv, lexEnv);
MOZ_ASSERT(global->is<GlobalObject>());
MOZ_ASSERT(varEnv->is<NonSyntacticVariablesObject>());
MOZ_ASSERT(IsExtensibleLexicalEnvironment(lexEnv));
MOZ_ASSERT(lexEnv->enclosingEnvironment() == varEnv);
assertSameCompartment(cx, env);
MOZ_ASSERT(IsExtensibleLexicalEnvironment(env));
MOZ_RELEASE_ASSERT(scriptArg->hasNonSyntacticScope());
RootedScript script(cx, scriptArg);
Rooted<GlobalObject*> globalRoot(cx, &global->as<GlobalObject>());
if (script->compartment() != cx->compartment()) {
script = CloneGlobalScript(cx, ScopeKind::NonSyntactic, script);
if (!script)
@ -467,7 +462,7 @@ ExecuteInNonSyntacticGlobalInternal(JSContext* cx, HandleObject global, HandleSc
}
RootedValue rval(cx);
return ExecuteKernel(cx, script, *lexEnv, UndefinedValue(),
return ExecuteKernel(cx, script, *env, UndefinedValue(),
NullFramePtr() /* evalInFrame */, rval.address());
}
@ -485,7 +480,7 @@ js::ExecuteInGlobalAndReturnScope(JSContext* cx, HandleObject global, HandleScri
if (!lexEnv)
return false;
if (!ExecuteInNonSyntacticGlobalInternal(cx, global, scriptArg, varEnv, lexEnv))
if (!ExecuteInExtensibleLexicalEnvironment(cx, scriptArg, lexEnv))
return false;
envArg.set(lexEnv);
@ -509,14 +504,51 @@ js::NewJSMEnvironment(JSContext* cx)
JS_FRIEND_API(bool)
js::ExecuteInJSMEnvironment(JSContext* cx, HandleScript scriptArg, HandleObject varEnv)
{
AutoObjectVector emptyChain(cx);
return ExecuteInJSMEnvironment(cx, scriptArg, varEnv, emptyChain);
}
JS_FRIEND_API(bool)
js::ExecuteInJSMEnvironment(JSContext* cx, HandleScript scriptArg, HandleObject varEnv,
AutoObjectVector& targetObj)
{
assertSameCompartment(cx, varEnv);
MOZ_ASSERT(cx->compartment()->getNonSyntacticLexicalEnvironment(varEnv));
MOZ_DIAGNOSTIC_ASSERT(scriptArg->noScriptRval());
RootedObject global(cx, &varEnv->global());
RootedObject lexEnv(cx, JS_ExtensibleLexicalEnvironment(varEnv));
RootedObject env(cx, JS_ExtensibleLexicalEnvironment(varEnv));
return ExecuteInNonSyntacticGlobalInternal(cx, global, scriptArg, varEnv, lexEnv);
// If the Gecko subscript loader specifies target objects, we need to add
// them to the environment. These are added after the NSVO environment.
if (!targetObj.empty()) {
// The environment chain will be as follows:
// GlobalObject / BackstagePass
// LexicalEnvironmentObject[this=global]
// NonSyntacticVariablesObject (the JSMEnvironment)
// LexicalEnvironmentObject[this=nsvo]
// WithEnvironmentObject[target=targetObj]
// LexicalEnvironmentObject[this=targetObj] (*)
//
// (*) This environment intentionally intercepts JSOP_GLOBALTHIS, but
// not JSOP_FUNCTIONTHIS (which instead will fallback to the NSVO). I
// don't make the rules, I just record them.
// Wrap the target objects in WithEnvironments.
if (!js::CreateObjectsForEnvironmentChain(cx, targetObj, env, &env))
return false;
// See CreateNonSyntacticEnvironmentChain
if (!JSObject::setQualifiedVarObj(cx, env))
return false;
// Create an extensible LexicalEnvironmentObject for target object
env = cx->compartment()->getOrCreateNonSyntacticLexicalEnvironment(cx, env);
if (!env)
return false;
}
return ExecuteInExtensibleLexicalEnvironment(cx, scriptArg, env);
}
JS_FRIEND_API(JSObject*)
@ -536,3 +568,11 @@ js::GetJSMEnvironmentOfScriptedCaller(JSContext* cx)
return env;
}
JS_FRIEND_API(bool)
js::IsJSMEnvironment(JSObject* obj)
{
// NOTE: This also returns true if the NonSyntacticVariablesObject was
// created for reasons other than the JSM loader.
return obj->is<NonSyntacticVariablesObject>();
}

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

@ -24,6 +24,7 @@ BEGIN_TEST(testExecuteInJSMEnvironment_Basic)
JS::CompileOptions options(cx);
options.setFileAndLine(__FILE__, __LINE__);
options.setNoScriptRval(true);
JS::RootedScript script(cx);
CHECK(JS::CompileForNonSyntacticScope(cx, options, src, sizeof(src)-1, &script));
@ -82,6 +83,7 @@ BEGIN_TEST(testExecuteInJSMEnvironment_Callback)
JS::CompileOptions options(cx);
options.setFileAndLine(__FILE__, __LINE__);
options.setNoScriptRval(true);
JS::RootedScript script(cx);
CHECK(JS::CompileForNonSyntacticScope(cx, options, src, sizeof(src)-1, &script));

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

@ -2888,16 +2888,69 @@ extern JS_FRIEND_API(bool)
ExecuteInGlobalAndReturnScope(JSContext* cx, JS::HandleObject obj, JS::HandleScript script,
JS::MutableHandleObject scope);
// These functions are only for JSM component loader, please don't use this for anything else!
// These functions are provided for the JSM component loader in Gecko.
//
// A 'JSMEnvironment' refers to an environment chain constructed for JSM loading
// in a shared global. Internally it is a NonSyntacticVariablesObject with a
// corresponding extensible LexicalEnvironmentObject that is accessible by
// JS_ExtensibleLexicalEnvironment. The |this| value of that lexical environment
// is the NSVO itself.
//
// Normal global environment (ES6): JSM "global" environment:
//
// * - extensible lexical environment
// | (code runs in this environment;
// | `let/const` bindings go here)
// |
// * - JSMEnvironment (=== `this`)
// | (`var` bindings go here)
// |
// * - extensible lexical environment * - extensible lexical environment
// | (code runs in this environment; | (empty)
// | `let/const` bindings go here) |
// | |
// * - actual global (=== `this`) * - shared JSM global
// (var bindings go here; and (Object, Math, etc. live here)
// Object, Math, etc. live here)
// Allocate a new environment in current compartment that is compatible with JSM
// shared loading.
extern JS_FRIEND_API(JSObject*)
NewJSMEnvironment(JSContext* cx);
// Execute the given script (copied into compartment if necessary) in the given
// JSMEnvironment. The script must have been compiled for hasNonSyntacticScope.
// The |jsmEnv| must have been previously allocated by NewJSMEnvironment.
//
// NOTE: The associated extensible lexical environment is reused.
extern JS_FRIEND_API(bool)
ExecuteInJSMEnvironment(JSContext* cx, JS::HandleScript script, JS::HandleObject nsvo);
ExecuteInJSMEnvironment(JSContext* cx, JS::HandleScript script, JS::HandleObject jsmEnv);
// Additionally, target objects may be specified as required by the Gecko
// subscript loader. These are wrapped in non-syntactic WithEnvironments and
// temporarily placed on environment chain.
//
// See also: JS::CloneAndExecuteScript(...)
extern JS_FRIEND_API(bool)
ExecuteInJSMEnvironment(JSContext* cx, JS::HandleScript script, JS::HandleObject jsmEnv,
JS::AutoObjectVector& targetObj);
// Used by native methods to determine the JSMEnvironment of caller if possible
// by looking at stack frames. Returns nullptr if top frame isn't a scripted
// caller in a JSM.
//
// NOTE: This may find NonSyntacticVariablesObject generated by other embedding
// such as a Gecko FrameScript. Caller can check the compartment if needed.
extern JS_FRIEND_API(JSObject*)
GetJSMEnvironmentOfScriptedCaller(JSContext* cx);
// Determine if obj is a JSMEnvironment
//
// NOTE: This may return true for an NonSyntacticVariablesObject generated by
// other embedding such as a Gecko FrameScript. Caller can check compartment.
extern JS_FRIEND_API(bool)
IsJSMEnvironment(JSObject* obj);
#if defined(XP_WIN) && defined(_WIN64)
// Parameters use void* types to avoid #including windows.h. The return value of

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

@ -3187,7 +3187,8 @@ js::CreateObjectsForEnvironmentChain(JSContext* cx, AutoObjectVector& chain,
#ifdef DEBUG
for (size_t i = 0; i < chain.length(); ++i) {
assertSameCompartment(cx, chain[i]);
MOZ_ASSERT(!chain[i]->is<GlobalObject>());
MOZ_ASSERT(!chain[i]->is<GlobalObject>() &&
!chain[i]->is<NonSyntacticVariablesObject>());
}
#endif

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

@ -446,9 +446,14 @@ mozJSComponentLoader::FindTargetObject(JSContext* aCx,
{
aTargetObject.set(js::GetJSMEnvironmentOfScriptedCaller(aCx));
// The above could fail if the scripted caller is not a
// component/JSM (it could be a DOM scope, for instance).
if (!aTargetObject) {
// The above could fail if the scripted caller is not a component/JSM (it
// could be a DOM scope, for instance).
//
// If the target object was not in the JSM shared global, return the global
// instead. This is needed when calling the subscript loader within a frame
// script, since it the FrameScript NSVO will have been found.
if (!aTargetObject ||
!IsLoaderGlobal(js::GetGlobalForObjectCrossCompartment(aTargetObject))) {
aTargetObject.set(CurrentGlobalOrNull(aCx));
}
}

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

@ -89,6 +89,21 @@ mozJSSubScriptLoader::~mozJSSubScriptLoader()
NS_IMPL_ISUPPORTS(mozJSSubScriptLoader, mozIJSSubScriptLoader)
#define JSSUB_CACHE_PREFIX(aType) "jssubloader/" aType
static void
SubscriptCachePath(JSContext* cx, nsIURI* uri, JS::HandleObject targetObj, nsACString& cachePath)
{
// StartupCache must distinguish between non-syntactic vs global, as well as
// javascript version when computing the cache key.
bool hasNonSyntacticScope = !JS_IsGlobalObject(targetObj);
JSVersion version = JS_GetVersion(cx);
cachePath.Assign(hasNonSyntacticScope ? JSSUB_CACHE_PREFIX("non-syntactic")
: JSSUB_CACHE_PREFIX("global"));
cachePath.AppendPrintf("/%d", version);
PathifyURI(uri, cachePath);
}
static void
ReportError(JSContext* cx, const nsACString& msg)
{
@ -178,24 +193,40 @@ EvalScript(JSContext* cx,
if (!JS::CloneAndExecuteScript(cx, script, retval)) {
return false;
}
} else if (js::IsJSMEnvironment(targetObj)) {
if (!ExecuteInJSMEnvironment(cx, script, targetObj)) {
return false;
}
retval.setUndefined();
} else {
JS::AutoObjectVector envChain(cx);
if (!envChain.append(targetObj)) {
return false;
}
if (loadScope != targetObj &&
loadScope &&
!JS_IsGlobalObject(loadScope))
{
MOZ_DIAGNOSTIC_ASSERT(js::GetObjectCompartment(loadScope) ==
js::GetObjectCompartment(targetObj));
if (!envChain.append(loadScope)) {
if (!loadScope) {
// A null loadScope means we are cross-compartment. In this case, we
// should check the target isn't in the JSM loader shared-global or
// we will contaiminate all JSMs in the compartment.
//
// NOTE: If loadScope is already a shared-global JSM, we can't
// determine which JSM the target belongs to and have to assume it
// is in our JSM.
JSObject* targetGlobal = js::GetGlobalForObjectCrossCompartment(targetObj);
MOZ_DIAGNOSTIC_ASSERT(!mozJSComponentLoader::Get()->IsLoaderGlobal(targetGlobal),
"Don't load subscript into target in a shared-global JSM");
if (!JS::CloneAndExecuteScript(cx, envChain, script, retval)) {
return false;
}
}
if (!JS::CloneAndExecuteScript(cx, envChain, script, retval)) {
return false;
} else if (JS_IsGlobalObject(loadScope)) {
if (!JS::CloneAndExecuteScript(cx, envChain, script, retval)) {
return false;
}
} else {
MOZ_ASSERT(js::IsJSMEnvironment(loadScope));
if (!js::ExecuteInJSMEnvironment(cx, script, loadScope, envChain)) {
return false;
}
retval.setUndefined();
}
}
@ -206,9 +237,7 @@ EvalScript(JSContext* cx,
if (script && (startupCache || preloadCache)) {
nsAutoCString cachePath;
JSVersion version = JS_GetVersion(cx);
cachePath.AppendPrintf("jssubloader/%d", version);
PathifyURI(uri, cachePath);
SubscriptCachePath(cx, uri, targetObj, cachePath);
nsCString uriStr;
if (preloadCache && NS_SUCCEEDED(uri->GetSpec(uriStr))) {
@ -661,10 +690,8 @@ mozJSSubScriptLoader::DoLoadSubScriptWithOptions(const nsAString& url,
|| scheme.EqualsLiteral("blob");
StartupCache* cache = ignoreCache ? nullptr : StartupCache::GetSingleton();
JSVersion version = JS_GetVersion(cx);
nsAutoCString cachePath;
cachePath.AppendPrintf("jssubloader/%d", version);
PathifyURI(uri, cachePath);
SubscriptCachePath(cx, uri, targetObj, cachePath);
RootedScript script(cx);
if (!options.ignoreCache) {

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

@ -0,0 +1,18 @@
Components.utils.import("resource://gre/modules/Services.jsm");
var EXPORTED_SYMBOLS = ["target", "bound"];
var bound = "";
var target = {};
Services.scriptloader.loadSubScript("resource://test/environment_script.js", target);
// Check global bindings
try { void vu; bound += "vu,"; } catch (e) {}
try { void vq; bound += "vq,"; } catch (e) {}
try { void vl; bound += "vl,"; } catch (e) {}
try { void gt; bound += "gt,"; } catch (e) {}
try { void ed; bound += "ed,"; } catch (e) {}
try { void ei; bound += "ei,"; } catch (e) {}
try { void fo; bound += "fo,"; } catch (e) {}
try { void fi; bound += "fi,"; } catch (e) {}
try { void fd; bound += "fd,"; } catch (e) {}

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

@ -0,0 +1,23 @@
let tgt_load = {};
let tgt_check = {};
Components.utils.import("resource://test/environment_loadscript.jsm", tgt_load);
Components.utils.import("resource://test/environment_checkscript.jsm", tgt_check);
// Check target bindings
var tgt_subscript_bound = "";
for (var name of ["vu", "vq", "vl", "gt", "ed", "ei", "fo", "fi", "fd"])
if (tgt_load.target.hasOwnProperty(name))
tgt_subscript_bound += name + ",";
// Expected subscript loader behavior is as follows:
// - Qualified vars and |this| access occur on target object
// - Lexical vars occur on ExtensibleLexicalEnvironment of target object
// - Bareword assignments and global |this| access occur on caller's global
if (tgt_load.bound != "vu,ei,fo,fi,")
throw new Error("Unexpected global binding set - " + tgt_load.bound);
if (tgt_subscript_bound != "vq,gt,ed,fd,")
throw new Error("Unexpected target binding set - " + tgt_subscript_bound);
// Components should not share namespace
if (tgt_check.bound != "")
throw new Error("Unexpected shared binding set - " + tgt_check.bound);

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

@ -12,6 +12,7 @@ support-files =
component_import.js
component_import.manifest
environment_script.js
environment_loadscript.jsm
environment_checkscript.jsm
file_simple_script.js
importer.jsm
@ -142,4 +143,5 @@ head = head_watchdog.js
[test_FrameScriptEnvironment.js]
[test_SubscriptLoaderEnvironment.js]
[test_SubscriptLoaderSandboxEnvironment.js]
[test_SubscriptLoaderJSMEnvironment.js]
[test_ComponentEnvironment.js]

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

@ -2484,12 +2484,19 @@ public:
// to disable it dynamically in stylo-enabled builds via a pref.
static bool StyloEnabled() {
#ifdef MOZ_STYLO
return sStyloEnabled;
return sStyloEnabled && StyloSupportedInCurrentProcess();
#else
return false;
#endif
}
// Whether Stylo should be allowed to be enabled in this process. This
// returns true for content processes and the non-e10s parent process.
static bool StyloSupportedInCurrentProcess() {
return XRE_IsContentProcess() ||
(XRE_IsParentProcess() && !XRE_IsE10sParentProcess());
}
static bool StyleAttrWithXMLBaseDisabled() {
return sStyleAttrWithXMLBaseDisabled;
}

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

@ -258,9 +258,11 @@ nsStyleSheetService::LoadAndRegisterSheetInternal(nsIURI *aSheetURI,
MOZ_ASSERT(geckoSheet);
#ifdef MOZ_STYLO
rv = LoadSheet(aSheetURI, parsingMode, StyleBackendType::Servo, &servoSheet);
NS_ENSURE_SUCCESS(rv, rv);
MOZ_ASSERT(servoSheet);
if (nsLayoutUtils::StyloSupportedInCurrentProcess()) {
rv = LoadSheet(aSheetURI, parsingMode, StyleBackendType::Servo, &servoSheet);
NS_ENSURE_SUCCESS(rv, rv);
MOZ_ASSERT(servoSheet);
}
#endif
mGeckoSheets[aSheetType].AppendElement(geckoSheet);

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

@ -301,7 +301,9 @@ nsLayoutStatics::Initialize()
mozilla::dom::WebCryptoThreadPool::Initialize();
#ifdef MOZ_STYLO
InitializeServo();
if (XRE_IsParentProcess() || XRE_IsContentProcess()) {
InitializeServo();
}
#endif
#ifndef MOZ_WIDGET_ANDROID
@ -323,8 +325,10 @@ nsLayoutStatics::Shutdown()
// memory reporter manager.
#ifdef MOZ_STYLO
ShutdownServo();
URLExtraData::ReleaseDummy();
if (XRE_IsParentProcess() || XRE_IsContentProcess()) {
ShutdownServo();
URLExtraData::ReleaseDummy();
}
#endif
nsMessageManagerScriptExecutor::Shutdown();

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

@ -110,12 +110,14 @@ public:
virtual void Paint(nsDisplayListBuilder* aBuilder,
gfxContext* aCtx) override;
virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder,
bool* aSnap) override;
bool* aSnap) const override;
NS_DISPLAY_DECL_NAME("ButtonBoxShadowOuter", TYPE_BUTTON_BOX_SHADOW_OUTER)
};
nsRect
nsDisplayButtonBoxShadowOuter::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) {
nsDisplayButtonBoxShadowOuter::GetBounds(nsDisplayListBuilder* aBuilder,
bool* aSnap) const
{
*aSnap = false;
return mFrame->GetVisualOverflowRectRelativeToSelf() + ToReferenceFrame();
}
@ -282,11 +284,11 @@ public:
virtual void Paint(nsDisplayListBuilder* aBuilder,
gfxContext* aCtx) override;
virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder,
bool* aSnap) override;
bool* aSnap) const override;
virtual nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder) override;
virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
const nsDisplayItemGeometry* aGeometry,
nsRegion *aInvalidRegion) override;
nsRegion *aInvalidRegion) const override;
virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
LayerManager* aManager,
const ContainerLayerParameters& aParameters) override;
@ -391,10 +393,9 @@ nsDisplayButtonBorder::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder&
}
void
nsDisplayButtonBorder::ComputeInvalidationRegion(
nsDisplayListBuilder* aBuilder,
const nsDisplayItemGeometry* aGeometry,
nsRegion *aInvalidRegion)
nsDisplayButtonBorder::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
const nsDisplayItemGeometry* aGeometry,
nsRegion *aInvalidRegion) const
{
auto geometry =
static_cast<const nsDisplayItemGenericImageGeometry*>(aGeometry);
@ -424,7 +425,9 @@ nsDisplayButtonBorder::Paint(nsDisplayListBuilder* aBuilder,
}
nsRect
nsDisplayButtonBorder::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) {
nsDisplayButtonBorder::GetBounds(nsDisplayListBuilder* aBuilder,
bool* aSnap) const
{
*aSnap = false;
return aBuilder->IsForEventDelivery() ? nsRect(ToReferenceFrame(), mFrame->GetSize())
: mFrame->GetVisualOverflowRectRelativeToSelf() + ToReferenceFrame();
@ -446,7 +449,7 @@ public:
nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder) override;
void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
const nsDisplayItemGeometry* aGeometry,
nsRegion *aInvalidRegion) override;
nsRegion *aInvalidRegion) const override;
virtual void Paint(nsDisplayListBuilder* aBuilder,
gfxContext* aCtx) override;
virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
@ -473,10 +476,9 @@ nsDisplayButtonForeground::AllocateGeometry(nsDisplayListBuilder* aBuilder)
}
void
nsDisplayButtonForeground::ComputeInvalidationRegion(
nsDisplayListBuilder* aBuilder,
const nsDisplayItemGeometry* aGeometry,
nsRegion* aInvalidRegion)
nsDisplayButtonForeground::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
const nsDisplayItemGeometry* aGeometry,
nsRegion* aInvalidRegion) const
{
auto geometry =
static_cast<const nsDisplayItemGenericImageGeometry*>(aGeometry);

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

@ -95,8 +95,9 @@ public:
virtual nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder) override;
virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
const nsDisplayItemGeometry* aGeometry,
nsRegion *aInvalidRegion) override;
virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) override;
nsRegion *aInvalidRegion) const override;
virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder,
bool* aSnap) const override;
NS_DISPLAY_DECL_NAME("FieldSetBorder", TYPE_FIELDSET_BORDER_BACKGROUND)
};
@ -119,7 +120,7 @@ nsDisplayFieldSetBorder::AllocateGeometry(nsDisplayListBuilder* aBuilder)
void
nsDisplayFieldSetBorder::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
const nsDisplayItemGeometry* aGeometry,
nsRegion *aInvalidRegion)
nsRegion *aInvalidRegion) const
{
auto geometry =
static_cast<const nsDisplayItemGenericImageGeometry*>(aGeometry);
@ -135,7 +136,7 @@ nsDisplayFieldSetBorder::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilde
nsRect
nsDisplayFieldSetBorder::GetBounds(nsDisplayListBuilder* aBuilder,
bool* aSnap)
bool* aSnap) const
{
// Just go ahead and claim our frame's overflow rect as the bounds, because we
// may have border-image-outset or other features that cause borders to extend

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

@ -185,8 +185,9 @@ public:
nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder) override;
void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
const nsDisplayItemGeometry* aGeometry,
nsRegion *aInvalidRegion) override;
virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) override;
nsRegion *aInvalidRegion) const override;
virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder,
bool* aSnap) const override;
virtual void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) override;
NS_DISPLAY_DECL_NAME("RangeFocusRing", TYPE_RANGE_FOCUS_RING)
};
@ -198,10 +199,9 @@ nsDisplayRangeFocusRing::AllocateGeometry(nsDisplayListBuilder* aBuilder)
}
void
nsDisplayRangeFocusRing::ComputeInvalidationRegion(
nsDisplayListBuilder* aBuilder,
const nsDisplayItemGeometry* aGeometry,
nsRegion* aInvalidRegion)
nsDisplayRangeFocusRing::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
const nsDisplayItemGeometry* aGeometry,
nsRegion* aInvalidRegion) const
{
auto geometry =
static_cast<const nsDisplayItemGenericImageGeometry*>(aGeometry);
@ -216,7 +216,8 @@ nsDisplayRangeFocusRing::ComputeInvalidationRegion(
}
nsRect
nsDisplayRangeFocusRing::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap)
nsDisplayRangeFocusRing::GetBounds(nsDisplayListBuilder* aBuilder,
bool* aSnap) const
{
*aSnap = false;
nsRect rect(ToReferenceFrame(), Frame()->GetSize());

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

@ -106,7 +106,9 @@ public:
}
#endif
virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) override {
virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder,
bool* aSnap) const override
{
*aSnap = false;
// override bounds because the list item focus ring may extend outside
// the nsSelectsAreaFrame

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

@ -26,6 +26,31 @@ struct SelectionFragment {
wr::LayoutRect rect;
};
// Selections are used in nsTextFrame to hack in sub-frame style changes.
// Most notably text-shadows can be changed by selections, and so we need to
// group all the glyphs and decorations attached to a shadow. We do this by
// having shadows apply to an entire SelectedTextRunFragment, and creating
// one for each "piece" of selection.
//
// For instance, this text:
//
// Hello [there] my name [is Mega]man
// ^ ^
// normal selection Ctrl+F highlight selection (yeah it's very overloaded)
//
// Would be broken up into 5 SelectedTextRunFragments
//
// ["Hello ", "there", " my name ", "is Mega", "man"]
//
// For almost all nsTextFrames, there will be only one SelectedTextRunFragment.
struct SelectedTextRunFragment {
Maybe<SelectionFragment> selection;
nsTArray<wr::TextShadow> shadows;
nsTArray<TextRunFragment> text;
nsTArray<wr::Line> beforeDecorations;
nsTArray<wr::Line> afterDecorations;
};
// This class is fake DrawTarget, used to intercept text draw calls, while
// also collecting up the other aspects of text natively.
//
@ -66,6 +91,7 @@ public:
: mCurrentlyDrawing(Phase::eSelection)
{
mCurrentTarget = gfx::Factory::CreateDrawTarget(gfx::BackendType::SKIA, IntSize(1, 1), gfx::SurfaceFormat::B8G8R8A8);
SetSelectionIndex(0);
}
// Prevent this from being copied
@ -75,6 +101,17 @@ public:
// Change the phase of text we're drawing.
void StartDrawing(Phase aPhase) { mCurrentlyDrawing = aPhase; }
void SetSelectionIndex(size_t i) {
// i should only be accessed if i-1 has already been
MOZ_ASSERT(mParts.Length() <= i);
if (mParts.Length() == i){
mParts.AppendElement();
}
mCurrentPart = &mParts[i];
}
// This overload just stores the glyphs/font/color.
void
FillGlyphs(ScaledFont* aFont,
@ -104,14 +141,14 @@ public:
// We need to push a new TextRunFragment whenever the font/color changes
// (usually this implies some font fallback from mixing languages/emoji)
TextRunFragment* fragment;
if (mText.IsEmpty() ||
mText.LastElement().font != aFont ||
mText.LastElement().color != colorPat->mColor) {
fragment = mText.AppendElement();
if (mCurrentPart->text.IsEmpty() ||
mCurrentPart->text.LastElement().font != aFont ||
mCurrentPart->text.LastElement().color != colorPat->mColor) {
fragment = mCurrentPart->text.AppendElement();
fragment->font = aFont;
fragment->color = colorPat->mColor;
} else {
fragment = &mText.LastElement();
fragment = &mCurrentPart->text.LastElement();
}
nsTArray<Glyph>& glyphs = fragment->glyphs;
@ -134,15 +171,18 @@ public:
}
}
void AppendShadow(const wr::TextShadow& aShadow) { mShadows.AppendElement(aShadow); }
void
AppendShadow(const wr::TextShadow& aShadow) {
mCurrentPart->shadows.AppendElement(aShadow);
}
void
AppendSelection(const LayoutDeviceRect& aRect, const Color& aColor)
SetSelectionRect(const LayoutDeviceRect& aRect, const Color& aColor)
{
SelectionFragment frag;
frag.rect = wr::ToLayoutRect(aRect);
frag.color = wr::ToColorF(aColor);
mSelections.AppendElement(frag);
mCurrentPart->selection = Some(frag);
}
void
@ -158,10 +198,10 @@ public:
switch (mCurrentlyDrawing) {
case Phase::eUnderline:
case Phase::eOverline:
decoration = mBeforeDecorations.AppendElement();
decoration = mCurrentPart->beforeDecorations.AppendElement();
break;
case Phase::eLineThrough:
decoration = mAfterDecorations.AppendElement();
decoration = mCurrentPart->afterDecorations.AppendElement();
break;
default:
MOZ_CRASH("TextDrawTarget received Decoration in wrong phase");
@ -208,34 +248,67 @@ public:
}
const nsTArray<wr::TextShadow>& GetShadows() { return mShadows; }
const nsTArray<TextRunFragment>& GetText() { return mText; }
const nsTArray<SelectionFragment>& GetSelections() { return mSelections; }
const nsTArray<wr::Line>& GetBeforeDecorations() { return mBeforeDecorations; }
const nsTArray<wr::Line>& GetAfterDecorations() { return mAfterDecorations; }
const nsTArray<SelectedTextRunFragment>& GetParts() { return mParts; }
bool
CanSerializeFonts()
{
for (const TextRunFragment& frag : GetText()) {
if (!frag.font->CanSerialize()) {
return false;
for (const SelectedTextRunFragment& part : GetParts()) {
for (const TextRunFragment& frag : part.text) {
if (!frag.font->CanSerialize()) {
return false;
}
}
}
return true;
}
// TextLayers don't support very complicated text right now. This checks
// if any of the problem cases exist.
bool
ContentsAreSimple()
{
ScaledFont* font = nullptr;
for (const SelectedTextRunFragment& part : GetParts()) {
// Can't handle shadows, selections, or decorations
if (part.shadows.Length() > 0 ||
part.beforeDecorations.Length() > 0 ||
part.afterDecorations.Length() > 0 ||
part.selection.isSome()) {
return false;
}
// Must only have one font (multiple colors is fine)
for (const mozilla::layout::TextRunFragment& text : part.text) {
if (!font) {
font = text.font;
}
if (font != text.font) {
return false;
}
}
}
// Must have an actual font (i.e. actual text)
if (!font) {
return false;
}
return true;
}
private:
// The part of the text we're currently drawing (glyphs, underlines, etc.)
Phase mCurrentlyDrawing;
// Properties of the whole text
nsTArray<wr::TextShadow> mShadows;
nsTArray<TextRunFragment> mText;
nsTArray<SelectionFragment> mSelections;
nsTArray<wr::Line> mBeforeDecorations;
nsTArray<wr::Line> mAfterDecorations;
// Which chunk of mParts is actively being populated
SelectedTextRunFragment* mCurrentPart;
// Chunks of the text, grouped by selection
nsTArray<SelectedTextRunFragment> mParts;
// A dummy to handle parts of the DrawTarget impl we don't care for
RefPtr<DrawTarget> mCurrentTarget;

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

@ -177,14 +177,15 @@ public:
}
#endif
virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder,
bool* aSnap) override {
bool* aSnap) const override
{
*aSnap = false;
nsRect shadowRect =
nsLayoutUtils::GetTextShadowRectsUnion(mRect, mFrame);
return mRect.Union(shadowRect);
}
virtual nsRect GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder) override
virtual nsRect GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder) const override
{
if (gfxPlatform::GetPlatform()->RespectsFontStyleSmoothing()) {
// On OS X, web authors can turn off subpixel text rendering using the
@ -201,7 +202,7 @@ public:
virtual void Paint(nsDisplayListBuilder* aBuilder,
gfxContext* aCtx) override;
virtual uint32_t GetPerFrameKey() override {
virtual uint32_t GetPerFrameKey() const override {
return (mIndex << TYPE_BITS) | nsDisplayItem::GetPerFrameKey();
}
void PaintTextToContext(gfxContext* aCtx,

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

@ -530,7 +530,6 @@ class nsDisplayBullet final : public nsDisplayItem {
public:
nsDisplayBullet(nsDisplayListBuilder* aBuilder, nsBulletFrame* aFrame)
: nsDisplayItem(aBuilder, aFrame)
, mDisableSubpixelAA(false)
{
MOZ_COUNT_CTOR(nsDisplayBullet);
}
@ -541,7 +540,7 @@ public:
#endif
virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder,
bool* aSnap) override
bool* aSnap) const override
{
*aSnap = false;
return mFrame->GetVisualOverflowRectRelativeToSelf() + ToReferenceFrame();
@ -570,16 +569,12 @@ public:
gfxContext* aCtx) override;
NS_DISPLAY_DECL_NAME("Bullet", TYPE_BULLET)
virtual nsRect GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder) override
virtual nsRect GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder) const override
{
bool snap;
return GetBounds(aBuilder, &snap);
}
virtual void DisableComponentAlpha() override {
mDisableSubpixelAA = true;
}
virtual nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder) override
{
return new nsDisplayBulletGeometry(this, aBuilder);
@ -587,7 +582,7 @@ public:
virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
const nsDisplayItemGeometry* aGeometry,
nsRegion *aInvalidRegion) override
nsRegion *aInvalidRegion) const override
{
const nsDisplayBulletGeometry* geometry = static_cast<const nsDisplayBulletGeometry*>(aGeometry);
nsBulletFrame* f = static_cast<nsBulletFrame*>(mFrame);
@ -609,7 +604,6 @@ public:
}
protected:
bool mDisableSubpixelAA;
Maybe<BulletRenderer> mBulletRenderer;
};

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

@ -464,7 +464,7 @@ public:
}
virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder,
bool* aSnap) override
bool* aSnap) const override
{
*aSnap = false;
// This is an overestimate, but that's not a problem.

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

@ -142,7 +142,8 @@ public:
{
return NS_GET_A(mColor) > 0;
}
virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) override
virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder,
bool* aSnap) const override
{
nsCanvasFrame* frame = static_cast<nsCanvasFrame*>(mFrame);
*aSnap = true;
@ -195,14 +196,14 @@ public:
virtual void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) override;
virtual void NotifyRenderingChanged() override
virtual void NotifyRenderingChanged() const override
{
mFrame->DeleteProperty(nsIFrame::CachedBackgroundImageDT());
}
// We still need to paint a background color as well as an image for this item,
// so we can't support this yet.
virtual bool SupportsOptimizingToImage() override { return false; }
virtual bool SupportsOptimizingToImage() const override { return false; }
bool IsSingleFixedPositionImage(nsDisplayListBuilder* aBuilder,
const nsRect& aClipRect,

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

@ -31,7 +31,7 @@ public:
* Returns the frame's visual overflow rect instead of the frame's bounds.
*/
virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder,
bool* aSnap) override
bool* aSnap) const override
{
*aSnap = false;
return static_cast<nsColumnSetFrame*>(mFrame)->CalculateBounds(ToReferenceFrame());

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

@ -79,7 +79,8 @@ public:
NS_DISPLAY_DECL_NAME("nsDisplayCanvas", TYPE_CANVAS)
virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
bool* aSnap) override {
bool* aSnap) const override
{
*aSnap = false;
nsHTMLCanvasFrame* f = static_cast<nsHTMLCanvasFrame*>(Frame());
HTMLCanvasElement* canvas =
@ -108,7 +109,8 @@ public:
}
virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder,
bool* aSnap) override {
bool* aSnap) const override
{
*aSnap = true;
nsHTMLCanvasFrame* f = static_cast<nsHTMLCanvasFrame*>(Frame());
return f->GetInnerArea() + ToReferenceFrame();

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

@ -1314,7 +1314,7 @@ public:
virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
const nsDisplayItemGeometry* aGeometry,
nsRegion* aInvalidRegion) override
nsRegion* aInvalidRegion) const override
{
auto geometry =
static_cast<const nsDisplayItemGenericImageGeometry*>(aGeometry);
@ -1329,7 +1329,7 @@ public:
}
virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder,
bool* aSnap) override
bool* aSnap) const override
{
*aSnap = false;
return mFrame->GetVisualOverflowRectRelativeToSelf() + ToReferenceFrame();
@ -1566,7 +1566,7 @@ nsDisplayImage::AllocateGeometry(nsDisplayListBuilder* aBuilder)
void
nsDisplayImage::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
const nsDisplayItemGeometry* aGeometry,
nsRegion* aInvalidRegion)
nsRegion* aInvalidRegion) const
{
auto geometry =
static_cast<const nsDisplayItemGenericImageGeometry*>(aGeometry);
@ -1588,7 +1588,7 @@ nsDisplayImage::GetImage()
}
nsRect
nsDisplayImage::GetDestRect()
nsDisplayImage::GetDestRect() const
{
bool snap = true;
const nsRect frameContentBox = GetBounds(&snap);
@ -1661,7 +1661,7 @@ nsDisplayImage::GetLayerState(nsDisplayListBuilder* aBuilder,
/* virtual */ nsRegion
nsDisplayImage::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
bool* aSnap)
bool* aSnap) const
{
*aSnap = false;
if (mImage && mImage->WillDrawOpaqueNow()) {

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

@ -424,7 +424,7 @@ public:
virtual nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder) override;
virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
const nsDisplayItemGeometry* aGeometry,
nsRegion* aInvalidRegion) override;
nsRegion* aInvalidRegion) const override;
virtual void Paint(nsDisplayListBuilder* aBuilder,
gfxContext* aCtx) override;
@ -434,12 +434,12 @@ public:
* @return The dest rect we'll use when drawing this image, in app units.
* Not necessarily contained in this item's bounds.
*/
virtual nsRect GetDestRect() override;
virtual nsRect GetDestRect() const override;
virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
LayerManager* aManager,
const ContainerLayerParameters& aParameters) override;
nsRect GetBounds(bool* aSnap)
nsRect GetBounds(bool* aSnap) const
{
*aSnap = true;
@ -448,13 +448,13 @@ public:
}
virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder,
bool* aSnap) override
bool* aSnap) const override
{
return GetBounds(aSnap);
}
virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
bool* aSnap) override;
bool* aSnap) const override;
virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
LayerManager* aManager,

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

@ -477,7 +477,6 @@ class nsDisplayHeaderFooter : public nsDisplayItem {
public:
nsDisplayHeaderFooter(nsDisplayListBuilder* aBuilder, nsPageFrame *aFrame)
: nsDisplayItem(aBuilder, aFrame)
, mDisableSubpixelAA(false)
{
MOZ_COUNT_CTOR(nsDisplayHeaderFooter);
}
@ -498,16 +497,11 @@ public:
}
NS_DISPLAY_DECL_NAME("HeaderFooter", TYPE_HEADER_FOOTER)
virtual nsRect GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder) override {
virtual nsRect GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder) const override
{
bool snap;
return GetBounds(aBuilder, &snap);
}
virtual void DisableComponentAlpha() override {
mDisableSubpixelAA = true;
}
protected:
bool mDisableSubpixelAA;
};
//------------------------------------------------------------------------------

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

@ -901,7 +901,7 @@ public:
#endif
nsRect GetBounds(nsDisplayListBuilder* aBuilder,
bool* aSnap) override;
bool* aSnap) const override;
NS_DISPLAY_DECL_NAME("PluginReadback", TYPE_PLUGIN_READBACK)
@ -921,21 +921,24 @@ public:
};
static nsRect
GetDisplayItemBounds(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem, nsIFrame* aFrame)
GetDisplayItemBounds(nsDisplayListBuilder* aBuilder,
const nsDisplayItem* aItem,
nsIFrame* aFrame)
{
// XXX For slightly more accurate region computations we should pixel-snap this
return aFrame->GetContentRectRelativeToSelf() + aItem->ToReferenceFrame();
}
nsRect
nsDisplayPluginReadback::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap)
nsDisplayPluginReadback::GetBounds(nsDisplayListBuilder* aBuilder,
bool* aSnap) const
{
*aSnap = false;
return GetDisplayItemBounds(aBuilder, this, mFrame);
}
nsRect
nsDisplayPlugin::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap)
nsDisplayPlugin::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) const
{
*aSnap = true;
return GetDisplayItemBounds(aBuilder, this, mFrame);
@ -1011,7 +1014,7 @@ nsDisplayPlugin::ComputeVisibility(nsDisplayListBuilder* aBuilder,
nsRegion
nsDisplayPlugin::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
bool* aSnap)
bool* aSnap) const
{
*aSnap = false;
nsRegion result;
@ -1314,7 +1317,7 @@ nsPluginFrame::PrintPlugin(gfxContext& aRenderingContext,
}
nsRect
nsPluginFrame::GetPaintedRect(nsDisplayPlugin* aItem)
nsPluginFrame::GetPaintedRect(const nsDisplayPlugin* aItem) const
{
if (!mInstanceOwner)
return nsRect();

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

@ -178,7 +178,7 @@ public:
* the frame's content-box but may be smaller if the plugin is rendering
* asynchronously and has a different-sized image temporarily.
*/
nsRect GetPaintedRect(nsDisplayPlugin* aItem);
nsRect GetPaintedRect(const nsDisplayPlugin* aItem) const;
/**
* If aSupports has a nsPluginFrame, then prepare it for a DocShell swap.
@ -361,9 +361,10 @@ public:
}
#endif
virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) override;
virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder,
bool* aSnap) const override;
virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
bool* aSnap) override;
bool* aSnap) const override;
virtual void Paint(nsDisplayListBuilder* aBuilder,
gfxContext* aCtx) override;
virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder,

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

@ -4955,7 +4955,8 @@ public:
#endif
virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder,
bool* aSnap) override {
bool* aSnap) const override
{
*aSnap = false;
return mBounds;
}
@ -4981,7 +4982,7 @@ public:
gfxContext* aCtx) override;
NS_DISPLAY_DECL_NAME("Text", TYPE_TEXT)
virtual nsRect GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder) override
virtual nsRect GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder) const override
{
if (gfxPlatform::GetPlatform()->RespectsFontStyleSmoothing()) {
// On OS X, web authors can turn off subpixel text rendering using the
@ -4999,11 +5000,7 @@ public:
virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
const nsDisplayItemGeometry* aGeometry,
nsRegion *aInvalidRegion) override;
virtual void DisableComponentAlpha() override {
mDisableSubpixelAA = true;
}
nsRegion *aInvalidRegion) const override;
void RenderToContext(gfxContext* aCtx, TextDrawTarget* aTextDrawer, nsDisplayListBuilder* aBuilder, bool aIsRecording = false);
@ -5052,11 +5049,8 @@ public:
}
RefPtr<TextDrawTarget> mTextDrawer;
nsRect mBounds;
float mOpacity;
bool mDisableSubpixelAA;
};
class nsDisplayTextGeometry : public nsCharClipGeometry
@ -5088,7 +5082,7 @@ nsDisplayText::AllocateGeometry(nsDisplayListBuilder* aBuilder)
void
nsDisplayText::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
const nsDisplayItemGeometry* aGeometry,
nsRegion *aInvalidRegion)
nsRegion *aInvalidRegion) const
{
const nsDisplayTextGeometry* geometry = static_cast<const nsDisplayTextGeometry*>(aGeometry);
nsTextFrame* f = static_cast<nsTextFrame*>(mFrame);
@ -5122,7 +5116,6 @@ nsDisplayText::nsDisplayText(nsDisplayListBuilder* aBuilder, nsTextFrame* aFrame
const Maybe<bool>& aIsSelected)
: nsCharClipDisplayItem(aBuilder, aFrame)
, mOpacity(1.0f)
, mDisableSubpixelAA(false)
{
MOZ_COUNT_CTOR(nsDisplayText);
mIsFrameSelected = aIsSelected;
@ -5161,29 +5154,7 @@ nsDisplayText::GetLayerState(nsDisplayListBuilder* aBuilder,
// If we're using the TextLayer backend, then we need to make sure
// the input is plain enough for it to handle
// Can't handle shadows, selections, or decorations
if (mTextDrawer->GetShadows().Length() > 0 ||
mTextDrawer->GetSelections().Length() > 0 ||
mTextDrawer->GetBeforeDecorations().Length() > 0 ||
mTextDrawer->GetAfterDecorations().Length() > 0) {
return mozilla::LAYER_NONE;
}
// Must only have one font (multiple colors is fine)
ScaledFont* font = nullptr;
for (const mozilla::layout::TextRunFragment& text : mTextDrawer->GetText()) {
if (!font) {
font = text.font;
}
if (font != text.font) {
return mozilla::LAYER_NONE;
}
}
// Must have an actual font (i.e. actual text)
if (!font) {
if (!mTextDrawer->ContentsAreSimple()) {
return mozilla::LAYER_NONE;
}
@ -5237,38 +5208,42 @@ nsDisplayText::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder
// text, emphasisText, [grouped in one array]
// lineThrough
for (const mozilla::layout::SelectionFragment& selection:
mTextDrawer->GetSelections()) {
aBuilder.PushRect(selection.rect, wrClipRect, selection.color);
for (auto& part : mTextDrawer->GetParts()) {
if (part.selection) {
auto selection = part.selection.value();
aBuilder.PushRect(selection.rect, wrClipRect, selection.color);
}
}
// WR takes the shadows in CSS-order (reverse of rendering order),
// because the drawing of a shadow actually occurs when it's popped.
for (const wr::TextShadow& shadow : mTextDrawer->GetShadows()) {
aBuilder.PushTextShadow(wrBoundsRect, wrClipRect, shadow);
}
for (auto& part : mTextDrawer->GetParts()) {
// WR takes the shadows in CSS-order (reverse of rendering order),
// because the drawing of a shadow actually occurs when it's popped.
for (const wr::TextShadow& shadow : part.shadows) {
aBuilder.PushTextShadow(wrBoundsRect, wrClipRect, shadow);
}
for (const wr::Line& decoration: mTextDrawer->GetBeforeDecorations()) {
aBuilder.PushLine(wrClipRect, decoration);
}
for (const wr::Line& decoration : part.beforeDecorations) {
aBuilder.PushLine(wrClipRect, decoration);
}
for (const mozilla::layout::TextRunFragment& text: mTextDrawer->GetText()) {
// mOpacity is set after we do our analysis, so we need to apply it here.
// mOpacity is only non-trivial when we have "pure" text, so we don't
// ever need to apply it to shadows or decorations.
auto color = text.color;
color.a *= mOpacity;
for (const mozilla::layout::TextRunFragment& text : part.text) {
// mOpacity is set after we do our analysis, so we need to apply it here.
// mOpacity is only non-trivial when we have "pure" text, so we don't
// ever need to apply it to shadows or decorations.
auto color = text.color;
color.a *= mOpacity;
aManager->WrBridge()->PushGlyphs(aBuilder, text.glyphs, text.font,
color, aSc, boundsRect, clipRect);
}
aManager->WrBridge()->PushGlyphs(aBuilder, text.glyphs, text.font,
color, aSc, boundsRect, clipRect);
}
for (const wr::Line& decoration: mTextDrawer->GetAfterDecorations()) {
aBuilder.PushLine(wrClipRect, decoration);
}
for (const wr::Line& decoration : part.afterDecorations) {
aBuilder.PushLine(wrClipRect, decoration);
}
for (size_t i = 0; i < mTextDrawer->GetShadows().Length(); ++i) {
aBuilder.PopTextShadow();
for (size_t i = 0; i < part.shadows.Length(); ++i) {
aBuilder.PopTextShadow();
}
}
return true;
@ -5298,19 +5273,26 @@ nsDisplayText::BuildLayer(nsDisplayListBuilder* aBuilder,
ScaledFont* font = nullptr;
nsTArray<GlyphArray> allGlyphs;
allGlyphs.SetCapacity(mTextDrawer->GetText().Length());
for (const mozilla::layout::TextRunFragment& text : mTextDrawer->GetText()) {
if (!font) {
font = text.font;
size_t totalLength = 0;
for (auto& part : mTextDrawer->GetParts()) {
totalLength += part.text.Length();
}
allGlyphs.SetCapacity(totalLength);
for (auto& part : mTextDrawer->GetParts()) {
for (const mozilla::layout::TextRunFragment& text : part.text) {
if (!font) {
font = text.font;
}
GlyphArray* glyphs = allGlyphs.AppendElement();
glyphs->glyphs() = text.glyphs;
// Apply folded alpha (only applies to glyphs)
auto color = text.color;
color.a *= mOpacity;
glyphs->color() = color;
}
GlyphArray* glyphs = allGlyphs.AppendElement();
glyphs->glyphs() = text.glyphs;
// Apply folded alpha (only applies to glyphs)
auto color = text.color;
color.a *= mOpacity;
glyphs->color() = color;
}
MOZ_ASSERT(font);
@ -6613,8 +6595,13 @@ nsTextFrame::PaintTextWithSelectionColors(
SelectionIterator iterator(prevailingSelections, contentRange,
*aParams.provider, mTextRun, startIOffset);
SelectionType selectionType;
size_t selectionIndex = 0;
while (iterator.GetNextSegment(&iOffset, &range, &hyphenWidth,
&selectionType, &rangeStyle)) {
if (aParams.textDrawer) {
aParams.textDrawer->SetSelectionIndex(selectionIndex);
}
nscolor foreground, background;
GetSelectionTextColors(selectionType, *aParams.textPaintStyle,
rangeStyle, &foreground, &background);
@ -6636,8 +6623,8 @@ nsTextFrame::PaintTextWithSelectionColors(
LayoutDeviceRect::FromAppUnits(bgRect, appUnitsPerDevPixel);
if (aParams.textDrawer) {
aParams.textDrawer->AppendSelection(selectionRect,
ToDeviceColor(background));
aParams.textDrawer->SetSelectionRect(selectionRect,
ToDeviceColor(background));
} else {
PaintSelectionBackground(
*aParams.context->GetDrawTarget(), background, aParams.dirtyRect,
@ -6645,6 +6632,7 @@ nsTextFrame::PaintTextWithSelectionColors(
}
}
iterator.UpdateWithAdvance(advance);
++selectionIndex;
}
}
@ -6672,8 +6660,14 @@ nsTextFrame::PaintTextWithSelectionColors(
SelectionIterator iterator(prevailingSelections, contentRange,
*aParams.provider, mTextRun, startIOffset);
SelectionType selectionType;
size_t selectionIndex = 0;
while (iterator.GetNextSegment(&iOffset, &range, &hyphenWidth,
&selectionType, &rangeStyle)) {
if (aParams.textDrawer) {
aParams.textDrawer->SetSelectionIndex(selectionIndex);
}
nscolor foreground, background;
if (aParams.IsGenerateTextMask()) {
foreground = NS_RGBA(0, 0, 0, 255);
@ -6712,6 +6706,7 @@ nsTextFrame::PaintTextWithSelectionColors(
DrawText(range, textBaselinePt, params);
advance += hyphenWidth;
iterator.UpdateWithAdvance(advance);
++selectionIndex;
}
return true;
}
@ -6787,8 +6782,12 @@ nsTextFrame::PaintTextSelectionDecorations(
gfxFloat decorationOffsetDir = mTextRun->IsSidewaysLeft() ? -1.0 : 1.0;
SelectionType nextSelectionType;
TextRangeStyle selectedStyle;
size_t selectionIndex = 0;
while (iterator.GetNextSegment(&iOffset, &range, &hyphenWidth,
&nextSelectionType, &selectedStyle)) {
if (aParams.textDrawer) {
aParams.textDrawer->SetSelectionIndex(selectionIndex);
}
gfxFloat advance = hyphenWidth +
mTextRun->GetAdvanceWidth(range, aParams.provider);
if (nextSelectionType == aSelectionType) {
@ -6808,6 +6807,7 @@ nsTextFrame::PaintTextSelectionDecorations(
verticalRun, decorationOffsetDir, kDecoration);
}
iterator.UpdateWithAdvance(advance);
++selectionIndex;
}
}
@ -6850,7 +6850,9 @@ nsTextFrame::PaintTextWithSelection(
}
void
nsTextFrame::DrawEmphasisMarks(gfxContext* aContext, WritingMode aWM,
nsTextFrame::DrawEmphasisMarks(gfxContext* aContext,
TextDrawTarget* aTextDrawer,
WritingMode aWM,
const gfxPoint& aTextBaselinePt,
const gfxPoint& aFramePt, Range aRange,
const nscolor* aDecorationOverrideColor,
@ -6887,12 +6889,14 @@ nsTextFrame::DrawEmphasisMarks(gfxContext* aContext, WritingMode aWM,
}
}
if (!isTextCombined) {
mTextRun->DrawEmphasisMarks(aContext, info->textRun.get(), info->advance,
pt, aRange, aProvider);
mTextRun->DrawEmphasisMarks(aContext, aTextDrawer, info->textRun.get(),
info->advance, pt, aRange, aProvider);
} else {
pt.y += (GetSize().height - info->advance) / 2;
gfxTextRun::DrawParams params(aContext);
params.textDrawer = aTextDrawer;
info->textRun->Draw(Range(info->textRun.get()), pt,
gfxTextRun::DrawParams(aContext));
params);
}
}
@ -7286,6 +7290,7 @@ DrawTextRun(const gfxTextRun* aTextRun,
const nsTextFrame::DrawTextRunParams& aParams)
{
gfxTextRun::DrawParams params(aParams.context);
params.textDrawer = aParams.textDrawer;
params.provider = aParams.provider;
params.advanceWidth = aParams.advanceWidth;
params.contextPaint = aParams.contextPaint;
@ -7296,13 +7301,13 @@ DrawTextRun(const gfxTextRun* aTextRun,
aTextRun->Draw(aRange, aTextBaselinePt, params);
aParams.callbacks->NotifyAfterText();
} else {
if (NS_GET_A(aParams.textColor) != 0) {
if (NS_GET_A(aParams.textColor) != 0 || aParams.textDrawer) {
aParams.context->SetColor(Color::FromABGR(aParams.textColor));
} else {
params.drawMode = DrawMode::GLYPH_STROKE;
}
if (NS_GET_A(aParams.textStrokeColor) != 0 &&
if ((NS_GET_A(aParams.textStrokeColor) != 0 || aParams.textDrawer) &&
aParams.textStrokeWidth != 0.0f) {
StrokeOptions strokeOpts;
params.drawMode |= DrawMode::GLYPH_STROKE;
@ -7493,7 +7498,7 @@ nsTextFrame::DrawTextRunAndDecorations(Range aRange,
if (aParams.textDrawer) {
aParams.textDrawer->StartDrawing(TextDrawTarget::Phase::eEmphasisMarks);
}
DrawEmphasisMarks(aParams.context, wm,
DrawEmphasisMarks(aParams.context, aParams.textDrawer, wm,
aTextBaselinePt, aParams.framePt, aRange,
aParams.decorationOverrideColor, aParams.provider);

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

@ -538,6 +538,7 @@ public:
SelectionType aSelectionType);
void DrawEmphasisMarks(gfxContext* aContext,
TextDrawTarget* aTextDrawer,
mozilla::WritingMode aWM,
const gfxPoint& aTextBaselinePt,
const gfxPoint& aFramePt,

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

@ -498,7 +498,8 @@ public:
// away completely (e.g. because of a decoder error). The problem would
// be especially acute if we have off-main-thread rendering.
virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) override
virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder,
bool* aSnap) const override
{
*aSnap = true;
nsIFrame* f = Frame();

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

@ -1867,7 +1867,9 @@ public:
}
#endif
virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) override {
virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder,
bool* aSnap) const override
{
*aSnap = false;
nsRect rect;
mChar->GetRect(rect);
@ -1889,13 +1891,13 @@ public:
NS_DISPLAY_DECL_NAME("MathMLCharForeground", TYPE_MATHML_CHAR_FOREGROUND)
virtual nsRect GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder) override
virtual nsRect GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder) const override
{
bool snap;
return GetBounds(aBuilder, &snap);
}
virtual uint32_t GetPerFrameKey() override {
virtual uint32_t GetPerFrameKey() const override {
return (mIndex << TYPE_BITS) | nsDisplayItem::GetPerFrameKey();
}

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

@ -338,7 +338,7 @@ public:
}
#endif
virtual uint32_t GetPerFrameKey() override {
virtual uint32_t GetPerFrameKey() const override {
return (mIndex << TYPE_BITS) | nsDisplayItem::GetPerFrameKey();
}

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

@ -761,7 +761,7 @@ public:
}
#endif
virtual uint32_t GetPerFrameKey() override {
virtual uint32_t GetPerFrameKey() const override {
return (mType << TYPE_BITS) | nsDisplayItem::GetPerFrameKey();
}

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

@ -280,7 +280,7 @@ public:
void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
const nsDisplayItemGeometry* aGeometry,
nsRegion* aInvalidRegion) override
nsRegion* aInvalidRegion) const override
{
auto geometry =
static_cast<const nsDisplayItemGenericImageGeometry*>(aGeometry);
@ -294,7 +294,8 @@ public:
nsDisplayItem::ComputeInvalidationRegion(aBuilder, aGeometry, aInvalidRegion);
}
virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) override
virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder,
bool* aSnap) const override
{
*aSnap = true;
nsStyleBorder styleBorder = *mFrame->StyleBorder();

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

@ -1106,6 +1106,13 @@ public:
* the child layers.
*/
void ProcessDisplayItems(nsDisplayList* aList);
void ProcessDisplayItems(nsDisplayList* aList,
AnimatedGeometryRoot* aLastAnimatedGeometryRoot,
const ActiveScrolledRoot* aLastASR,
const nsPoint& aLastAGRTopLeft,
nsPoint& aTopLeft,
int32_t aMaxLayers,
int& aLayerCount);
/**
* This finalizes all the open PaintedLayers by popping every element off
* mPaintedLayerDataStack, then sets the children of the container layer
@ -3994,9 +4001,23 @@ ContainerState::ProcessDisplayItems(nsDisplayList* aList)
int32_t maxLayers = gfxPrefs::MaxActiveLayers();
int layerCount = 0;
nsDisplayList savedItems;
nsDisplayItem* item;
while ((item = aList->RemoveBottom()) != nullptr) {
ProcessDisplayItems(aList, lastAnimatedGeometryRoot, lastASR,
lastAGRTopLeft, topLeft, maxLayers, layerCount);
}
void
ContainerState::ProcessDisplayItems(nsDisplayList* aList,
AnimatedGeometryRoot* aLastAnimatedGeometryRoot,
const ActiveScrolledRoot* aLastASR,
const nsPoint& aLastAGRTopLeft,
nsPoint& aTopLeft,
int32_t aMaxLayers,
int& aLayerCount)
{
for (nsDisplayItem* i = aList->GetBottom(); i; i = i->GetAbove()) {
nsDisplayItem* item = i;
MOZ_ASSERT(item);
DisplayItemType itemType = item->GetType();
// If the item is a event regions item, but is empty (has no regions in it)
@ -4004,35 +4025,44 @@ ContainerState::ProcessDisplayItems(nsDisplayList* aList)
if (itemType == DisplayItemType::TYPE_LAYER_EVENT_REGIONS) {
nsDisplayLayerEventRegions* eventRegions =
static_cast<nsDisplayLayerEventRegions*>(item);
if (eventRegions->IsEmpty()) {
item->Destroy(mBuilder);
continue;
}
}
// Peek ahead to the next item and try merging with it or swapping with it
// if necessary.
nsDisplayItem* aboveItem;
while ((aboveItem = aList->GetBottom()) != nullptr) {
if (aboveItem->TryMerge(item)) {
aList->RemoveBottom();
item->Destroy(mBuilder);
item = aboveItem;
itemType = item->GetType();
} else {
// Peek ahead to the next item and see if it can be merged with the current
// item. We create a list of consecutive items that can be merged together.
AutoTArray<nsDisplayItem*, 1> mergedItems;
mergedItems.AppendElement(item);
for (nsDisplayItem* peek = item->GetAbove(); peek; peek = peek->GetAbove()) {
if (!item->CanMerge(peek)) {
break;
}
mergedItems.AppendElement(peek);
// Move the iterator forward since we will merge this item.
i = peek;
}
nsDisplayList* itemSameCoordinateSystemChildren
= item->GetSameCoordinateSystemChildren();
if (mergedItems.Length() > 1) {
// We have items that can be merged together. Merge them into a temporary
// item and process that item immediately.
item = mBuilder->MergeItems(mergedItems);
MOZ_ASSERT(item && itemType == item->GetType());
}
nsDisplayList* childItems = item->GetSameCoordinateSystemChildren();
if (item->ShouldFlattenAway(mBuilder)) {
aList->AppendToBottom(itemSameCoordinateSystemChildren);
item->Destroy(mBuilder);
MOZ_ASSERT(childItems);
ProcessDisplayItems(childItems, aLastAnimatedGeometryRoot, aLastASR,
aLastAGRTopLeft, aTopLeft, aMaxLayers, aLayerCount);
continue;
}
savedItems.AppendToTop(item);
MOZ_ASSERT(item->GetType() != DisplayItemType::TYPE_WRAP_LIST);
NS_ASSERTION(mAppUnitsPerDevPixel == AppUnitsPerDevPixel(item),
"items in a container layer should all have the same app units per dev pixel");
@ -4059,9 +4089,9 @@ ContainerState::ProcessDisplayItems(nsDisplayList* aList)
const DisplayItemClipChain* layerClipChain = nullptr;
if (mFlattenToSingleLayer && layerState != LAYER_ACTIVE_FORCE) {
forceInactive = true;
animatedGeometryRoot = lastAnimatedGeometryRoot;
itemASR = lastASR;
topLeft = lastAGRTopLeft;
animatedGeometryRoot = aLastAnimatedGeometryRoot;
itemASR = aLastASR;
aTopLeft = aLastAGRTopLeft;
item->FuseClipChainUpTo(mBuilder, mContainerASR);
} else {
forceInactive = false;
@ -4083,7 +4113,7 @@ ContainerState::ProcessDisplayItems(nsDisplayList* aList)
itemASR = mContainerASR;
item->FuseClipChainUpTo(mBuilder, mContainerASR);
}
topLeft = (*animatedGeometryRoot)->GetOffsetToCrossDoc(mContainerReferenceFrame);
aTopLeft = (*animatedGeometryRoot)->GetOffsetToCrossDoc(mContainerReferenceFrame);
}
const ActiveScrolledRoot* scrollMetadataASR =
@ -4140,7 +4170,7 @@ ContainerState::ProcessDisplayItems(nsDisplayList* aList)
ScaleToOutsidePixels(item->GetVisibleRect(), false));
}
if (maxLayers != -1 && layerCount >= maxLayers) {
if (aMaxLayers != -1 && aLayerCount >= aMaxLayers) {
forceInactive = true;
}
@ -4151,7 +4181,7 @@ ContainerState::ProcessDisplayItems(nsDisplayList* aList)
(layerState == LAYER_ACTIVE_EMPTY ||
layerState == LAYER_ACTIVE))) {
layerCount++;
aLayerCount++;
// LAYER_ACTIVE_EMPTY means the layer is created just for its metadata.
// We should never see an empty layer with any visible content!
@ -4356,12 +4386,11 @@ ContainerState::ProcessDisplayItems(nsDisplayList* aList)
nsDisplayMask* maskItem = static_cast<nsDisplayMask*>(item);
SetupMaskLayerForCSSMask(ownLayer, maskItem);
nsDisplayItem* next = aList->GetBottom();
if (next && next->GetType() == DisplayItemType::TYPE_SCROLL_INFO_LAYER) {
if (i->GetAbove() &&
i->GetAbove()->GetType() == DisplayItemType::TYPE_SCROLL_INFO_LAYER) {
// Since we do build a layer for mask, there is no need for this
// scroll info layer anymore.
aList->RemoveBottom();
next->Destroy(mBuilder);
i = i->GetAbove();
}
}
@ -4470,7 +4499,7 @@ ContainerState::ProcessDisplayItems(nsDisplayList* aList)
item->Frame()->In3DContextAndBackfaceIsHidden(),
[&]() {
return NewPaintedLayerData(item, animatedGeometryRoot, itemASR, layerClipChain, scrollMetadataASR,
topLeft);
aTopLeft);
});
if (itemType == DisplayItemType::TYPE_LAYER_EVENT_REGIONS) {
@ -4488,7 +4517,7 @@ ContainerState::ProcessDisplayItems(nsDisplayList* aList)
if (!paintedLayerData->mLayer) {
// Try to recycle the old layer of this display item.
RefPtr<PaintedLayer> layer =
AttemptToRecyclePaintedLayer(animatedGeometryRoot, item, topLeft);
AttemptToRecyclePaintedLayer(animatedGeometryRoot, item, aTopLeft);
if (layer) {
paintedLayerData->mLayer = layer;
@ -4500,13 +4529,10 @@ ContainerState::ProcessDisplayItems(nsDisplayList* aList)
}
}
if (itemSameCoordinateSystemChildren &&
itemSameCoordinateSystemChildren->NeedsTransparentSurface()) {
if (childItems && childItems->NeedsTransparentSurface()) {
aList->SetNeedsTransparentSurface();
}
}
aList->AppendToTop(&savedItems);
}
void

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

@ -856,6 +856,39 @@ nsDisplayListBuilder::AddAnimationsAndTransitionsToLayer(Layer* aLayer,
animationInfo.TransferMutatedFlagToLayer(aLayer);
}
nsDisplayItem*
nsDisplayListBuilder::MergeItems(nsTArray<nsDisplayItem*>& aMergedItems)
{
// For merging, we create a temporary item by cloning the last item of the
// mergeable items list. This ensures that the temporary item will have the
// correct frame and bounds.
nsDisplayItem* merged = nullptr;
for (nsDisplayItem* item : Reversed(aMergedItems)) {
MOZ_ASSERT(item);
if (!merged) {
// Create the temporary item.
merged = item->Clone(this);
MOZ_ASSERT(merged);
AddTemporaryItem(merged);
} else {
// Merge the item properties (frame/bounds/etc) with the previously
// created temporary item.
MOZ_ASSERT(merged->CanMerge(item));
merged->Merge(item);
}
// Create nsDisplayWrapList that points to the internal display list of the
// item we are merging. This nsDisplayWrapList is added to the display list
// of the temporary item.
merged->MergeDisplayListFromItem(this, item);
}
return merged;
}
void
nsDisplayListBuilder::AutoCurrentActiveScrolledRootSetter::InsertScrollFrame(nsIScrollableFrame* aScrollableFrame)
{
@ -1129,6 +1162,9 @@ nsDisplayListBuilder::~nsDisplayListBuilder() {
for (ActiveScrolledRoot* asr : mActiveScrolledRoots) {
asr->ActiveScrolledRoot::~ActiveScrolledRoot();
}
for (nsDisplayItem* i : mTemporaryItems) {
i->Destroy(this);
}
for (DisplayItemClipChain* c : mClipChainsToDestroy) {
c->DisplayItemClipChain::~DisplayItemClipChain();
}
@ -2619,6 +2655,7 @@ nsDisplayItem::nsDisplayItem(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
, mActiveScrolledRoot(aActiveScrolledRoot)
, mAnimatedGeometryRoot(nullptr)
, mForceNotVisible(aBuilder->IsBuildingInvisibleItems())
, mDisableSubpixelAA(false)
#ifdef MOZ_DUMP_PAINTING
, mPainted(false)
#endif
@ -2796,7 +2833,7 @@ nsDisplayItem::IntersectClip(nsDisplayListBuilder* aBuilder,
}
nsRect
nsDisplayItem::GetClippedBounds(nsDisplayListBuilder* aBuilder)
nsDisplayItem::GetClippedBounds(nsDisplayListBuilder* aBuilder) const
{
bool snap;
nsRect r = GetBounds(aBuilder, &snap);
@ -2827,7 +2864,8 @@ nsDisplayItem::BuildDisplayItemLayer(nsDisplayListBuilder* aBuilder,
}
nsRect
nsDisplaySolidColor::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap)
nsDisplaySolidColor::GetBounds(nsDisplayListBuilder* aBuilder,
bool* aSnap) const
{
*aSnap = true;
return mBounds;
@ -2914,7 +2952,8 @@ nsDisplaySolidColor::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aB
}
nsRect
nsDisplaySolidColorRegion::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap)
nsDisplaySolidColorRegion::GetBounds(nsDisplayListBuilder* aBuilder,
bool* aSnap) const
{
*aSnap = true;
return mRegion.GetBounds();
@ -3427,7 +3466,7 @@ nsDisplayBackgroundImage::CanOptimizeToImageLayer(LayerManager* aManager,
}
nsRect
nsDisplayBackgroundImage::GetDestRect()
nsDisplayBackgroundImage::GetDestRect() const
{
return mDestRect;
}
@ -3636,7 +3675,7 @@ nsDisplayBackgroundImage::ComputeVisibility(nsDisplayListBuilder* aBuilder,
}
/* static */ nsRegion
nsDisplayBackgroundImage::GetInsideClipRegion(nsDisplayItem* aItem,
nsDisplayBackgroundImage::GetInsideClipRegion(const nsDisplayItem* aItem,
StyleGeometryBox aClip,
const nsRect& aRect,
const nsRect& aBackgroundRect)
@ -3666,7 +3705,8 @@ nsDisplayBackgroundImage::GetInsideClipRegion(nsDisplayItem* aItem,
nsRegion
nsDisplayBackgroundImage::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
bool* aSnap) {
bool* aSnap) const
{
nsRegion result;
*aSnap = false;
@ -3696,7 +3736,8 @@ nsDisplayBackgroundImage::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
}
Maybe<nscolor>
nsDisplayBackgroundImage::IsUniform(nsDisplayListBuilder* aBuilder) {
nsDisplayBackgroundImage::IsUniform(nsDisplayListBuilder* aBuilder) const
{
if (!mBackgroundStyle) {
return Some(NS_RGBA(0,0,0,0));
}
@ -3704,7 +3745,7 @@ nsDisplayBackgroundImage::IsUniform(nsDisplayListBuilder* aBuilder) {
}
nsRect
nsDisplayBackgroundImage::GetPositioningArea()
nsDisplayBackgroundImage::GetPositioningArea() const
{
if (!mBackgroundStyle) {
return nsRect();
@ -3720,7 +3761,7 @@ nsDisplayBackgroundImage::GetPositioningArea()
}
bool
nsDisplayBackgroundImage::RenderingMightDependOnPositioningAreaSizeChange()
nsDisplayBackgroundImage::RenderingMightDependOnPositioningAreaSizeChange() const
{
if (!mBackgroundStyle)
return false;
@ -3773,9 +3814,10 @@ nsDisplayBackgroundImage::PaintInternal(nsDisplayListBuilder* aBuilder,
nsDisplayBackgroundGeometry::UpdateDrawResult(this, result);
}
void nsDisplayBackgroundImage::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
const nsDisplayItemGeometry* aGeometry,
nsRegion* aInvalidRegion)
void
nsDisplayBackgroundImage::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
const nsDisplayItemGeometry* aGeometry,
nsRegion* aInvalidRegion) const
{
if (!mBackgroundStyle) {
return;
@ -3824,7 +3866,9 @@ void nsDisplayBackgroundImage::ComputeInvalidationRegion(nsDisplayListBuilder* a
}
nsRect
nsDisplayBackgroundImage::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) {
nsDisplayBackgroundImage::GetBounds(nsDisplayListBuilder* aBuilder,
bool* aSnap) const
{
*aSnap = true;
return mBounds;
}
@ -3848,12 +3892,6 @@ nsDisplayBackgroundImage::GetBoundsInternal(nsDisplayListBuilder* aBuilder) {
aBuilder->GetBackgroundPaintFlags());
}
uint32_t
nsDisplayBackgroundImage::GetPerFrameKey()
{
return (mLayer << TYPE_BITS) | nsDisplayItem::GetPerFrameKey();
}
nsDisplayTableBackgroundImage::nsDisplayTableBackgroundImage(const InitData& aData,
nsIFrame* aCellFrame)
: nsDisplayBackgroundImage(aData)
@ -3864,7 +3902,7 @@ nsDisplayTableBackgroundImage::nsDisplayTableBackgroundImage(const InitData& aDa
}
bool
nsDisplayTableBackgroundImage::IsInvalid(nsRect& aRect)
nsDisplayTableBackgroundImage::IsInvalid(nsRect& aRect) const
{
bool result = mStyleFrame ? mStyleFrame->IsInvalid(aRect) : false;
aRect += ToReferenceFrame();
@ -3926,7 +3964,8 @@ nsDisplayThemedBackground::HitTest(nsDisplayListBuilder* aBuilder,
nsRegion
nsDisplayThemedBackground::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
bool* aSnap) {
bool* aSnap) const
{
nsRegion result;
*aSnap = false;
@ -3937,7 +3976,8 @@ nsDisplayThemedBackground::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
}
Maybe<nscolor>
nsDisplayThemedBackground::IsUniform(nsDisplayListBuilder* aBuilder) {
nsDisplayThemedBackground::IsUniform(nsDisplayListBuilder* aBuilder) const
{
if (mAppearance == NS_THEME_WIN_BORDERLESS_GLASS ||
mAppearance == NS_THEME_WIN_GLASS) {
return Some(NS_RGBA(0,0,0,0));
@ -3946,14 +3986,14 @@ nsDisplayThemedBackground::IsUniform(nsDisplayListBuilder* aBuilder) {
}
bool
nsDisplayThemedBackground::ProvidesFontSmoothingBackgroundColor(nscolor* aColor)
nsDisplayThemedBackground::ProvidesFontSmoothingBackgroundColor(nscolor* aColor) const
{
nsITheme* theme = mFrame->PresContext()->GetTheme();
return theme->WidgetProvidesFontSmoothingBackgroundColor(mFrame, mAppearance, aColor);
}
nsRect
nsDisplayThemedBackground::GetPositioningArea()
nsDisplayThemedBackground::GetPositioningArea() const
{
return mBackgroundRect;
}
@ -3981,15 +4021,17 @@ nsDisplayThemedBackground::PaintInternal(nsDisplayListBuilder* aBuilder,
theme->DrawWidgetBackground(aCtx, mFrame, mAppearance, mBackgroundRect, drawing);
}
bool nsDisplayThemedBackground::IsWindowActive()
bool
nsDisplayThemedBackground::IsWindowActive() const
{
EventStates docState = mFrame->GetContent()->OwnerDoc()->GetDocumentState();
return !docState.HasState(NS_DOCUMENT_STATE_WINDOW_INACTIVE);
}
void nsDisplayThemedBackground::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
const nsDisplayItemGeometry* aGeometry,
nsRegion* aInvalidRegion)
void
nsDisplayThemedBackground::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
const nsDisplayItemGeometry* aGeometry,
nsRegion* aInvalidRegion) const
{
const nsDisplayThemedBackgroundGeometry* geometry = static_cast<const nsDisplayThemedBackgroundGeometry*>(aGeometry);
@ -4014,7 +4056,9 @@ void nsDisplayThemedBackground::ComputeInvalidationRegion(nsDisplayListBuilder*
}
nsRect
nsDisplayThemedBackground::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) {
nsDisplayThemedBackground::GetBounds(nsDisplayListBuilder* aBuilder,
bool* aSnap) const
{
*aSnap = true;
return mBounds;
}
@ -4288,7 +4332,7 @@ nsDisplayBackgroundColor::Paint(nsDisplayListBuilder* aBuilder,
nsRegion
nsDisplayBackgroundColor::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
bool* aSnap)
bool* aSnap) const
{
*aSnap = false;
@ -4311,7 +4355,7 @@ nsDisplayBackgroundColor::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
}
Maybe<nscolor>
nsDisplayBackgroundColor::IsUniform(nsDisplayListBuilder* aBuilder)
nsDisplayBackgroundColor::IsUniform(nsDisplayListBuilder* aBuilder) const
{
return Some(mColor.ToABGR());
}
@ -4361,7 +4405,9 @@ nsDisplayClearBackground::BuildLayer(nsDisplayListBuilder* aBuilder,
}
nsRect
nsDisplayOutline::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) {
nsDisplayOutline::GetBounds(nsDisplayListBuilder* aBuilder,
bool* aSnap) const
{
*aSnap = false;
return mFrame->GetVisualOverflowRectRelativeToSelf() + ToReferenceFrame();
}
@ -4442,7 +4488,7 @@ nsDisplayOutline::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuil
}
bool
nsDisplayOutline::IsInvisibleInRect(const nsRect& aRect)
nsDisplayOutline::IsInvisibleInRect(const nsRect& aRect) const
{
const nsStyleOutline* outline = mFrame->StyleOutline();
nsRect borderBox(ToReferenceFrame(), mFrame->GetSize());
@ -4690,7 +4736,8 @@ nsDisplayCaret::~nsDisplayCaret()
#endif
nsRect
nsDisplayCaret::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap)
nsDisplayCaret::GetBounds(nsDisplayListBuilder* aBuilder,
bool* aSnap) const
{
*aSnap = true;
// The caret returns a rect in the coordinates of mFrame.
@ -4784,7 +4831,7 @@ nsDisplayBorder::nsDisplayBorder(nsDisplayListBuilder* aBuilder, nsIFrame* aFram
}
bool
nsDisplayBorder::IsInvisibleInRect(const nsRect& aRect)
nsDisplayBorder::IsInvisibleInRect(const nsRect& aRect) const
{
nsRect paddingRect = mFrame->GetPaddingRect() - mFrame->GetPosition() +
ToReferenceFrame();
@ -4813,7 +4860,7 @@ nsDisplayBorder::AllocateGeometry(nsDisplayListBuilder* aBuilder)
void
nsDisplayBorder::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
const nsDisplayItemGeometry* aGeometry,
nsRegion* aInvalidRegion)
nsRegion* aInvalidRegion) const
{
const nsDisplayBorderGeometry* geometry = static_cast<const nsDisplayBorderGeometry*>(aGeometry);
bool snap;
@ -5125,14 +5172,15 @@ nsDisplayBorder::Paint(nsDisplayListBuilder* aBuilder,
}
nsRect
nsDisplayBorder::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap)
nsDisplayBorder::GetBounds(nsDisplayListBuilder* aBuilder,
bool* aSnap) const
{
*aSnap = true;
return mBounds;
}
nsRegion
nsDisplayBorder::CalculateBounds(const nsStyleBorder& aStyleBorder)
nsDisplayBorder::CalculateBounds(const nsStyleBorder& aStyleBorder) const
{
nsRect borderBounds(ToReferenceFrame(), mFrame->GetSize());
if (aStyleBorder.IsBorderImageLoaded()) {
@ -5228,7 +5276,9 @@ nsDisplayBoxShadowOuter::Paint(nsDisplayListBuilder* aBuilder,
}
nsRect
nsDisplayBoxShadowOuter::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) {
nsDisplayBoxShadowOuter::GetBounds(nsDisplayListBuilder* aBuilder,
bool* aSnap) const
{
*aSnap = false;
return mBounds;
}
@ -5240,7 +5290,7 @@ nsDisplayBoxShadowOuter::GetBoundsInternal() {
}
bool
nsDisplayBoxShadowOuter::IsInvisibleInRect(const nsRect& aRect)
nsDisplayBoxShadowOuter::IsInvisibleInRect(const nsRect& aRect) const
{
nsPoint origin = ToReferenceFrame();
nsRect frameRect(origin, mFrame->GetSize());
@ -5425,7 +5475,7 @@ nsDisplayBoxShadowOuter::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder
void
nsDisplayBoxShadowOuter::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
const nsDisplayItemGeometry* aGeometry,
nsRegion* aInvalidRegion)
nsRegion* aInvalidRegion) const
{
const nsDisplayBoxShadowOuterGeometry* geometry =
static_cast<const nsDisplayBoxShadowOuterGeometry*>(aGeometry);
@ -5632,7 +5682,8 @@ nsDisplayWrapList::nsDisplayWrapList(nsDisplayListBuilder* aBuilder,
mBaseVisibleRect = mVisibleRect;
mList.AppendToTop(aList);
mListPtr = &mList;
mListPtr->AppendToTop(aList);
UpdateBounds(aBuilder);
if (!aFrame || !aFrame->IsTransformed()) {
@ -5649,7 +5700,7 @@ nsDisplayWrapList::nsDisplayWrapList(nsDisplayListBuilder* aBuilder,
// (since nsDisplayTransform wraps all actual content), and that child
// will have the correct reference frame set (since nsDisplayTransform
// handles this explictly).
nsDisplayItem *i = mList.GetBottom();
nsDisplayItem *i = mListPtr->GetBottom();
if (i && (!i->GetAbove() || i->GetType() == DisplayItemType::TYPE_TRANSFORM) &&
i->Frame() == mFrame) {
mReferenceFrame = i->ReferenceFrame();
@ -5669,7 +5720,8 @@ nsDisplayWrapList::nsDisplayWrapList(nsDisplayListBuilder* aBuilder,
mBaseVisibleRect = mVisibleRect;
mList.AppendToTop(aItem);
mListPtr = &mList;
mListPtr->AppendToTop(aItem);
UpdateBounds(aBuilder);
if (!aFrame || !aFrame->IsTransformed()) {
@ -5689,14 +5741,34 @@ nsDisplayWrapList::~nsDisplayWrapList() {
MOZ_COUNT_DTOR(nsDisplayWrapList);
}
void
nsDisplayWrapList::MergeDisplayListFromItem(nsDisplayListBuilder* aBuilder,
const nsDisplayItem* aItem)
{
const nsDisplayWrapList* wrappedItem = aItem->AsDisplayWrapList();
MOZ_ASSERT(wrappedItem);
// Create a new nsDisplayWrapList using a copy-constructor. This is done
// to preserve the information about bounds.
nsDisplayWrapList* wrapper = new (aBuilder) nsDisplayWrapList(*wrappedItem);
// Set the display list pointer of the new wrapper item to the display list
// of the wrapped item.
wrapper->mListPtr = wrappedItem->mListPtr;
mListPtr->AppendToBottom(wrapper);
}
void
nsDisplayWrapList::HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames) {
mList.HitTest(aBuilder, aRect, aState, aOutFrames);
mListPtr->HitTest(aBuilder, aRect, aState, aOutFrames);
}
nsRect
nsDisplayWrapList::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) {
nsDisplayWrapList::GetBounds(nsDisplayListBuilder* aBuilder,
bool* aSnap) const
{
*aSnap = false;
return mBounds;
}
@ -5711,8 +5783,9 @@ nsDisplayWrapList::ComputeVisibility(nsDisplayListBuilder* aBuilder,
nsRegion originalVisibleRegion = visibleRegion;
bool retval =
mList.ComputeVisibilityForSublist(aBuilder, &visibleRegion, mVisibleRect);
mListPtr->ComputeVisibilityForSublist(aBuilder,
&visibleRegion,
mVisibleRect);
nsRegion removed;
// removed = originalVisibleRegion - visibleRegion
removed.Sub(originalVisibleRegion, visibleRegion);
@ -5725,10 +5798,11 @@ nsDisplayWrapList::ComputeVisibility(nsDisplayListBuilder* aBuilder,
nsRegion
nsDisplayWrapList::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
bool* aSnap) {
bool* aSnap) const
{
*aSnap = false;
nsRegion result;
if (mList.IsOpaque()) {
if (mListPtr->IsOpaque()) {
// Everything within GetBounds that's visible is opaque.
result = GetBounds(aBuilder, aSnap);
}
@ -5736,7 +5810,8 @@ nsDisplayWrapList::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
}
Maybe<nscolor>
nsDisplayWrapList::IsUniform(nsDisplayListBuilder* aBuilder) {
nsDisplayWrapList::IsUniform(nsDisplayListBuilder* aBuilder) const
{
// We could try to do something but let's conservatively just return Nothing.
return Nothing();
}
@ -5797,10 +5872,10 @@ RequiredLayerStateForChildren(nsDisplayListBuilder* aBuilder,
return result;
}
nsRect nsDisplayWrapList::GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder)
nsRect nsDisplayWrapList::GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder) const
{
nsRect bounds;
for (nsDisplayItem* i = mList.GetBottom(); i; i = i->GetAbove()) {
for (nsDisplayItem* i = mListPtr->GetBottom(); i; i = i->GetAbove()) {
bounds.UnionRect(bounds, i->GetComponentAlphaBounds(aBuilder));
}
return bounds;
@ -5928,7 +6003,8 @@ nsDisplayOpacity::~nsDisplayOpacity() {
#endif
nsRegion nsDisplayOpacity::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
bool* aSnap) {
bool* aSnap) const
{
*aSnap = false;
// The only time where mOpacity == 1.0 should be when we have will-change.
// We could report this as opaque then but when the will-change value starts
@ -6001,6 +6077,52 @@ nsDisplayOpacity::CanApplyOpacity() const
return true;
}
/**
* Recursively iterates through |aList| and collects at most |aMaxChildCount|
* display item pointers to items that return true for CanApplyOpacity().
* The item pointers are added to |aArray|.
*
* LayerEventRegions and WrapList items are ignored.
*
* We need to do this recursively, because the child display items might contain
* nested nsDisplayWrapLists.
*
* Returns false if there are more than |aMaxChildCount| items, or if an item
* that returns false for CanApplyOpacity() is encountered.
* Otherwise returns true.
*/
static bool
CollectItemsWithOpacity(nsDisplayList* aList,
nsTArray<nsDisplayItem*>& aArray,
const size_t aMaxChildCount)
{
for (nsDisplayItem* i = aList->GetBottom(); i; i = i->GetAbove()) {
DisplayItemType type = i->GetType();
nsDisplayList* children = i->GetChildren();
// Descend only into wraplists.
if (type == DisplayItemType::TYPE_WRAP_LIST && children) {
// The current display item has children, process them first.
if (!CollectItemsWithOpacity(children, aArray, aMaxChildCount)) {
return false;
}
}
if (type == DisplayItemType::TYPE_LAYER_EVENT_REGIONS ||
type == DisplayItemType::TYPE_WRAP_LIST) {
continue;
}
if (!i->CanApplyOpacity() || aArray.Length() == aMaxChildCount) {
return false;
}
aArray.AppendElement(i);
}
return true;
}
bool
nsDisplayOpacity::ShouldFlattenAway(nsDisplayListBuilder* aBuilder)
{
@ -6012,36 +6134,36 @@ nsDisplayOpacity::ShouldFlattenAway(nsDisplayListBuilder* aBuilder)
return false;
}
nsDisplayItem* child = mList.GetBottom();
// Only try folding our opacity down if we have at most three children
// that don't overlap and can all apply the opacity to themselves.
if (!child) {
return false;
}
struct {
nsDisplayItem* item;
nsRect bounds;
} children[3];
bool snap;
uint32_t numChildren = 0;
for (; numChildren < ArrayLength(children) && child; numChildren++, child = child->GetAbove()) {
if (child->GetType() == DisplayItemType::TYPE_LAYER_EVENT_REGIONS) {
numChildren--;
continue;
}
if (!child->CanApplyOpacity()) {
return false;
}
children[numChildren].item = child;
children[numChildren].bounds = child->GetBounds(aBuilder, &snap);
}
if (child) {
// we have a fourth (or more) child
if (mList.IsEmpty()) {
return false;
}
for (uint32_t i = 0; i < numChildren; i++) {
for (uint32_t j = i+1; j < numChildren; j++) {
// Only try folding our opacity down if we have at most kMaxChildCount
// children that don't overlap and can all apply the opacity to themselves.
static const size_t kMaxChildCount = 3;
// Iterate through the child display list and copy at most kMaxChildCount
// child display item pointers to a temporary list.
AutoTArray<nsDisplayItem*, kMaxChildCount> items;
if (!CollectItemsWithOpacity(&mList, items, kMaxChildCount)) {
return false;
}
struct {
nsDisplayItem* item;
nsRect bounds;
} children[kMaxChildCount];
bool snap;
size_t childCount = 0;
for (nsDisplayItem* item : items) {
children[childCount].item = item;
children[childCount].bounds = item->GetBounds(aBuilder, &snap);
childCount++;
}
for (size_t i = 0; i < childCount; i++) {
for (size_t j = i+1; j < childCount; j++) {
if (children[i].bounds.Intersects(children[j].bounds)) {
return false;
}
@ -6054,11 +6176,12 @@ nsDisplayOpacity::ShouldFlattenAway(nsDisplayListBuilder* aBuilder)
// usually never have their own clip because during display item creation
// time we propagated the clip to our contents, so maybe we should just
// remove the clip parameter from ApplyOpacity completely.
DisplayItemClipChain clip = { GetClip(), mActiveScrolledRoot, nullptr };
DisplayItemClipChain clip { GetClip(), mActiveScrolledRoot, nullptr };
for (uint32_t i = 0; i < numChildren; i++) {
for (uint32_t i = 0; i < childCount; i++) {
children[i].item->ApplyOpacity(aBuilder, mOpacity, mClip ? &clip : nullptr);
}
return true;
}
@ -6098,20 +6221,6 @@ nsDisplayOpacity::ComputeVisibility(nsDisplayListBuilder* aBuilder,
nsDisplayWrapList::ComputeVisibility(aBuilder, &visibleUnderChildren);
}
bool nsDisplayOpacity::TryMerge(nsDisplayItem* aItem) {
if (aItem->GetType() != DisplayItemType::TYPE_OPACITY)
return false;
// items for the same content element should be merged into a single
// compositing group
// aItem->GetUnderlyingFrame() returns non-null because it's nsDisplayOpacity
if (aItem->Frame()->GetContent() != mFrame->GetContent())
return false;
if (aItem->GetClipChain() != GetClipChain())
return false;
MergeFromTrackingMergedFrames(static_cast<nsDisplayOpacity*>(aItem));
return true;
}
void
nsDisplayOpacity::WriteDebugInfo(std::stringstream& aStream)
{
@ -6185,7 +6294,8 @@ nsDisplayBlendMode::~nsDisplayBlendMode() {
#endif
nsRegion nsDisplayBlendMode::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
bool* aSnap) {
bool* aSnap) const
{
*aSnap = false;
// We are never considered opaque
return nsRegion();
@ -6235,7 +6345,8 @@ nsDisplayBlendMode::BuildLayer(nsDisplayListBuilder* aBuilder,
return container.forget();
}
bool nsDisplayBlendMode::ComputeVisibility(nsDisplayListBuilder* aBuilder,
bool
nsDisplayBlendMode::ComputeVisibility(nsDisplayListBuilder* aBuilder,
nsRegion* aVisibleRegion) {
// Our children are need their backdrop so we should not allow them to subtract
// area from aVisibleRegion. We do need to find out what is visible under
@ -6248,19 +6359,23 @@ bool nsDisplayBlendMode::ComputeVisibility(nsDisplayListBuilder* aBuilder,
return nsDisplayWrapList::ComputeVisibility(aBuilder, &visibleUnderChildren);
}
bool nsDisplayBlendMode::TryMerge(nsDisplayItem* aItem) {
if (aItem->GetType() != DisplayItemType::TYPE_BLEND_MODE)
bool
nsDisplayBlendMode::CanMerge(const nsDisplayItem* aItem) const
{
// Items for the same content element should be merged into a single
// compositing group.
if (!HasSameTypeAndClip(aItem) || !HasSameContent(aItem)) {
return false;
nsDisplayBlendMode* item = static_cast<nsDisplayBlendMode*>(aItem);
// items for the same content element should be merged into a single
// compositing group
if (item->Frame()->GetContent() != mFrame->GetContent())
}
const nsDisplayBlendMode* item =
static_cast<const nsDisplayBlendMode*>(aItem);
if (item->mIndex != 0 || mIndex != 0) {
// Don't merge background-blend-mode items
return false;
if (item->mIndex != 0 || mIndex != 0)
return false; // don't merge background-blend-mode items
if (item->GetClipChain() != GetClipChain())
return false;
MergeFromTrackingMergedFrames(item);
}
return true;
}
@ -6339,20 +6454,6 @@ nsDisplayBlendContainer::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder
aManager, aDisplayListBuilder);
}
bool nsDisplayBlendContainer::TryMerge(nsDisplayItem* aItem) {
if (aItem->GetType() != DisplayItemType::TYPE_BLEND_CONTAINER)
return false;
// items for the same content element should be merged into a single
// compositing group
// aItem->GetUnderlyingFrame() returns non-null because it's nsDisplayOpacity
if (aItem->Frame()->GetContent() != mFrame->GetContent())
return false;
if (aItem->GetClipChain() != GetClipChain())
return false;
MergeFromTrackingMergedFrames(static_cast<nsDisplayBlendContainer*>(aItem));
return true;
}
nsDisplayOwnLayer::nsDisplayOwnLayer(nsDisplayListBuilder* aBuilder,
nsIFrame* aFrame, nsDisplayList* aList,
const ActiveScrolledRoot* aActiveScrolledRoot,
@ -6402,7 +6503,7 @@ nsDisplayOwnLayer::IsScrollThumbLayer() const
}
bool
nsDisplayOwnLayer::ShouldBuildLayerEvenIfInvisible(nsDisplayListBuilder* aBuilder)
nsDisplayOwnLayer::ShouldBuildLayerEvenIfInvisible(nsDisplayListBuilder* aBuilder) const
{
// Render scroll thumb layers even if they are invisible, because async
// scrolling might bring them into view.
@ -6556,7 +6657,8 @@ UseDisplayPortForViewport(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
}
nsRect
nsDisplaySubDocument::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap)
nsDisplaySubDocument::GetBounds(nsDisplayListBuilder* aBuilder,
bool* aSnap) const
{
bool usingDisplayPort = UseDisplayPortForViewport(aBuilder, mFrame);
@ -6612,7 +6714,7 @@ nsDisplaySubDocument::ComputeVisibility(nsDisplayListBuilder* aBuilder,
}
bool
nsDisplaySubDocument::ShouldBuildLayerEvenIfInvisible(nsDisplayListBuilder* aBuilder)
nsDisplaySubDocument::ShouldBuildLayerEvenIfInvisible(nsDisplayListBuilder* aBuilder) const
{
bool usingDisplayPort = UseDisplayPortForViewport(aBuilder, mFrame);
@ -6624,7 +6726,8 @@ nsDisplaySubDocument::ShouldBuildLayerEvenIfInvisible(nsDisplayListBuilder* aBui
}
nsRegion
nsDisplaySubDocument::GetOpaqueRegion(nsDisplayListBuilder* aBuilder, bool* aSnap)
nsDisplaySubDocument::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
bool* aSnap) const
{
bool usingDisplayPort = UseDisplayPortForViewport(aBuilder, mFrame);
@ -6769,19 +6872,6 @@ nsDisplayFixedPosition::BuildLayer(nsDisplayListBuilder* aBuilder,
return layer.forget();
}
bool nsDisplayFixedPosition::TryMerge(nsDisplayItem* aItem) {
if (aItem->GetType() != DisplayItemType::TYPE_FIXED_POSITION)
return false;
// Items with the same fixed position frame can be merged.
nsDisplayFixedPosition* other = static_cast<nsDisplayFixedPosition*>(aItem);
if (other->mFrame != mFrame)
return false;
if (aItem->GetClipChain() != GetClipChain())
return false;
MergeFromTrackingMergedFrames(other);
return true;
}
bool
nsDisplayFixedPosition::UpdateScrollData(mozilla::layers::WebRenderScrollData* aData,
mozilla::layers::WebRenderLayerScrollData* aLayerData)
@ -6928,19 +7018,6 @@ nsDisplayStickyPosition::BuildLayer(nsDisplayListBuilder* aBuilder,
return layer.forget();
}
bool nsDisplayStickyPosition::TryMerge(nsDisplayItem* aItem) {
if (aItem->GetType() != DisplayItemType::TYPE_STICKY_POSITION)
return false;
// Items with the same fixed position frame can be merged.
nsDisplayStickyPosition* other = static_cast<nsDisplayStickyPosition*>(aItem);
if (other->mFrame != mFrame)
return false;
if (aItem->GetClipChain() != GetClipChain())
return false;
MergeFromTrackingMergedFrames(other);
return true;
}
nsDisplayScrollInfoLayer::nsDisplayScrollInfoLayer(
nsDisplayListBuilder* aBuilder,
nsIFrame* aScrolledFrame,
@ -7039,7 +7116,8 @@ nsDisplayZoom::~nsDisplayZoom() {
}
#endif
nsRect nsDisplayZoom::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap)
nsRect nsDisplayZoom::GetBounds(nsDisplayListBuilder* aBuilder,
bool* aSnap) const
{
nsRect bounds = nsDisplaySubDocument::GetBounds(aBuilder, aSnap);
*aSnap = false;
@ -7719,7 +7797,7 @@ static bool IsFrameVisible(nsIFrame* aFrame, const Matrix4x4& aMatrix)
}
const Matrix4x4&
nsDisplayTransform::GetTransform()
nsDisplayTransform::GetTransform() const
{
if (mTransform.IsIdentity()) {
float scale = mFrame->PresContext()->AppUnitsPerDevPixel();
@ -7787,7 +7865,7 @@ nsDisplayTransform::GetAccumulatedPreserved3DTransform(nsDisplayListBuilder* aBu
}
bool
nsDisplayTransform::ShouldBuildLayerEvenIfInvisible(nsDisplayListBuilder* aBuilder)
nsDisplayTransform::ShouldBuildLayerEvenIfInvisible(nsDisplayListBuilder* aBuilder) const
{
// The visible rect of a Preserves-3D frame is just an intermediate
// result. It should always build a layer to make sure it is
@ -7934,7 +8012,7 @@ already_AddRefed<Layer> nsDisplayTransform::BuildLayer(nsDisplayListBuilder *aBu
}
bool
nsDisplayTransform::MayBeAnimated(nsDisplayListBuilder* aBuilder)
nsDisplayTransform::MayBeAnimated(nsDisplayListBuilder* aBuilder) const
{
// If EffectCompositor::HasAnimationsForCompositor() is true then we can
// completely bypass the main thread for this animation, so it is always
@ -8123,7 +8201,8 @@ nsDisplayTransform::GetHitDepthAtPoint(nsDisplayListBuilder* aBuilder, const nsP
* by the reference point.
*/
nsRect
nsDisplayTransform::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap)
nsDisplayTransform::GetBounds(nsDisplayListBuilder* aBuilder,
bool* aSnap) const
{
*aSnap = false;
@ -8199,8 +8278,9 @@ nsDisplayTransform::ComputeBounds(nsDisplayListBuilder* aBuilder)
* mStoredList.GetVisibleRect().Contains(untransformedVisible), then it
* certainly contains the actual (non-axis-aligned) untransformed rect.
*/
nsRegion nsDisplayTransform::GetOpaqueRegion(nsDisplayListBuilder *aBuilder,
bool* aSnap)
nsRegion
nsDisplayTransform::GetOpaqueRegion(nsDisplayListBuilder *aBuilder,
bool* aSnap) const
{
*aSnap = false;
nsRect untransformedVisible;
@ -8226,7 +8306,7 @@ nsRegion nsDisplayTransform::GetOpaqueRegion(nsDisplayListBuilder *aBuilder,
* works.
*/
Maybe<nscolor>
nsDisplayTransform::IsUniform(nsDisplayListBuilder *aBuilder)
nsDisplayTransform::IsUniform(nsDisplayListBuilder *aBuilder) const
{
nsRect untransformedVisible;
if (!UntransformVisibleRect(aBuilder, &untransformedVisible)) {
@ -8244,45 +8324,6 @@ nsDisplayTransform::IsUniform(nsDisplayListBuilder *aBuilder)
return Nothing();
}
/* If UNIFIED_CONTINUATIONS is defined, we can merge two display lists that
* share the same underlying content. Otherwise, doing so results in graphical
* glitches.
*/
#ifndef UNIFIED_CONTINUATIONS
bool
nsDisplayTransform::TryMerge(nsDisplayItem *aItem)
{
return false;
}
#else
bool
nsDisplayTransform::TryMerge(nsDisplayItem *aItem)
{
NS_PRECONDITION(aItem, "Why did you try merging with a null item?");
/* Make sure that we're dealing with two transforms. */
if (aItem->GetType() != TYPE_TRANSFORM)
return false;
/* Check to see that both frames are part of the same content. */
if (aItem->Frame()->GetContent() != mFrame->GetContent())
return false;
if (aItem->GetClipChain() != GetClipChain())
return false;
/* Now, move everything over to this frame and signal that
* we merged things!
*/
mStoredList.MergeFromTrackingMergedFrames(&static_cast<nsDisplayTransform*>(aItem)->mStoredList);
return true;
}
#endif
/* TransformRect takes in as parameters a rectangle (in app space) and returns
* the smallest rectangle (in app space) containing the transformed image of
* that rectangle. That is, it takes the four corners of the rectangle,
@ -8344,7 +8385,7 @@ bool nsDisplayTransform::UntransformRect(const nsRect &aTransformedBounds,
}
bool nsDisplayTransform::UntransformVisibleRect(nsDisplayListBuilder* aBuilder,
nsRect *aOutRect)
nsRect *aOutRect) const
{
const Matrix4x4& matrix = GetTransform();
if (matrix.IsSingular())
@ -8535,7 +8576,7 @@ nsCharClipDisplayItem::AllocateGeometry(nsDisplayListBuilder* aBuilder)
void
nsCharClipDisplayItem::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
const nsDisplayItemGeometry* aGeometry,
nsRegion* aInvalidRegion)
nsRegion* aInvalidRegion) const
{
const nsCharClipGeometry* geometry = static_cast<const nsCharClipGeometry*>(aGeometry);
@ -8577,7 +8618,7 @@ nsDisplaySVGEffects::~nsDisplaySVGEffects()
#endif
nsRegion nsDisplaySVGEffects::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
bool* aSnap)
bool* aSnap) const
{
*aSnap = false;
return nsRegion();
@ -8609,7 +8650,7 @@ nsDisplaySVGEffects::UserSpaceOffset() const
void
nsDisplaySVGEffects::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
const nsDisplayItemGeometry* aGeometry,
nsRegion* aInvalidRegion)
nsRegion* aInvalidRegion) const
{
const nsDisplaySVGEffectGeometry* geometry =
static_cast<const nsDisplaySVGEffectGeometry*>(aGeometry);
@ -8798,36 +8839,17 @@ nsDisplayMask::~nsDisplayMask()
}
#endif
bool nsDisplayMask::TryMerge(nsDisplayItem* aItem)
bool
nsDisplayMask::CanMerge(const nsDisplayItem* aItem) const
{
if (aItem->GetType() != DisplayItemType::TYPE_MASK)
return false;
// Do not merge items for box-decoration-break:clone elements,
// since each box should have its own mask in that case.
if (mFrame->StyleBorder()->mBoxDecorationBreak == StyleBoxDecorationBreak::Clone) {
return false;
}
// items for the same content element should be merged into a single
// compositing group
// aItem->GetUnderlyingFrame() returns non-null because it's nsDisplaySVGEffects
if (aItem->Frame()->GetContent() != mFrame->GetContent()) {
return false;
}
if (aItem->GetClipChain() != GetClipChain()) {
return false;
}
// Items for the same content element should be merged into a single
// compositing group.
// Do not merge if mFrame has mask. Continuation frames should apply mask
// independently(just like nsDisplayBackgroundImage).
if (mFrame->StyleSVGReset()->HasMask()) {
return false;
}
MergeFromTrackingMergedFrames(static_cast<nsDisplayMask*>(aItem));
return true;
// independently (just like nsDisplayBackgroundImage).
return HasSameTypeAndClip(aItem) && HasSameContent(aItem) &&
!mFrame->StyleSVGReset()->HasMask() &&
(mFrame->StyleBorder()->mBoxDecorationBreak !=
mozilla::StyleBoxDecorationBreak::Clone);
}
already_AddRefed<Layer>
@ -8928,7 +8950,7 @@ bool nsDisplayMask::ComputeVisibility(nsDisplayListBuilder* aBuilder,
void
nsDisplayMask::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
const nsDisplayItemGeometry* aGeometry,
nsRegion* aInvalidRegion)
nsRegion* aInvalidRegion) const
{
nsDisplaySVGEffects::ComputeInvalidationRegion(aBuilder, aGeometry,
aInvalidRegion);
@ -9133,30 +9155,6 @@ nsDisplayFilter::BuildLayer(nsDisplayListBuilder* aBuilder,
return container.forget();
}
bool nsDisplayFilter::TryMerge(nsDisplayItem* aItem)
{
if (aItem->GetType() != DisplayItemType::TYPE_FILTER) {
return false;
}
// items for the same content element should be merged into a single
// compositing group.
// aItem->Frame() returns non-null because it's nsDisplayFilter
if (aItem->Frame()->GetContent() != mFrame->GetContent()) {
return false;
}
if (aItem->GetClipChain() != GetClipChain()) {
return false;
}
nsDisplayFilter* other = static_cast<nsDisplayFilter*>(aItem);
MergeFromTrackingMergedFrames(other);
mEffectsBounds.UnionRect(mEffectsBounds,
other->mEffectsBounds + other->mFrame->GetOffsetTo(mFrame));
return true;
}
LayerState
nsDisplayFilter::GetLayerState(nsDisplayListBuilder* aBuilder,
LayerManager* aManager,
@ -9190,8 +9188,9 @@ nsDisplayFilter::GetLayerState(nsDisplayListBuilder* aBuilder,
return LAYER_ACTIVE;
}
bool nsDisplayFilter::ComputeVisibility(nsDisplayListBuilder* aBuilder,
nsRegion* aVisibleRegion)
bool
nsDisplayFilter::ComputeVisibility(nsDisplayListBuilder* aBuilder,
nsRegion* aVisibleRegion)
{
nsPoint offset = ToReferenceFrame();
nsRect dirtyRect =
@ -9211,7 +9210,7 @@ bool nsDisplayFilter::ComputeVisibility(nsDisplayListBuilder* aBuilder,
void
nsDisplayFilter::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
const nsDisplayItemGeometry* aGeometry,
nsRegion* aInvalidRegion)
nsRegion* aInvalidRegion) const
{
nsDisplaySVGEffects::ComputeInvalidationRegion(aBuilder, aGeometry,
aInvalidRegion);

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

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

@ -87,7 +87,7 @@ public:
void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
const nsDisplayItemGeometry* aGeometry,
nsRegion *aInvalidRegion) override;
nsRegion *aInvalidRegion) const override;
};
void
@ -134,10 +134,9 @@ nsDisplaySVGGeometry::Paint(nsDisplayListBuilder* aBuilder,
}
void
nsDisplaySVGGeometry::ComputeInvalidationRegion(
nsDisplayListBuilder* aBuilder,
const nsDisplayItemGeometry* aGeometry,
nsRegion* aInvalidRegion)
nsDisplaySVGGeometry::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
const nsDisplayItemGeometry* aGeometry,
nsRegion* aInvalidRegion) const
{
auto geometry =
static_cast<const nsDisplayItemGenericImageGeometry*>(aGeometry);

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

@ -3067,10 +3067,8 @@ SVGTextDrawPathCallbacks::StrokeGeometry()
class nsDisplaySVGText : public nsDisplayItem {
public:
nsDisplaySVGText(nsDisplayListBuilder* aBuilder,
SVGTextFrame* aFrame)
: nsDisplayItem(aBuilder, aFrame),
mDisableSubpixelAA(false)
nsDisplaySVGText(nsDisplayListBuilder* aBuilder, SVGTextFrame* aFrame)
: nsDisplayItem(aBuilder, aFrame)
{
MOZ_COUNT_CTOR(nsDisplaySVGText);
MOZ_ASSERT(aFrame, "Must have a frame!");
@ -3083,9 +3081,6 @@ public:
NS_DISPLAY_DECL_NAME("nsDisplaySVGText", TYPE_SVG_TEXT)
virtual void DisableComponentAlpha() override {
mDisableSubpixelAA = true;
}
virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
HitTestState* aState,
nsTArray<nsIFrame*> *aOutFrames) override;
@ -3095,12 +3090,12 @@ public:
{
return new nsDisplayItemGenericImageGeometry(this, aBuilder);
}
virtual nsRect GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder) override {
virtual nsRect GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder) const override
{
bool snap;
return GetBounds(aBuilder, &snap);
}
private:
bool mDisableSubpixelAA;
};
void

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

@ -561,7 +561,7 @@ public:
virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
const nsDisplayItemGeometry* aGeometry,
nsRegion* aInvalidRegion) override;
nsRegion* aInvalidRegion) const override;
nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder) override
{
@ -662,7 +662,7 @@ nsSVGOuterSVGFrame::FindInvalidatedForeignObjectFrameChildren(nsIFrame* aFrame)
void
nsDisplayOuterSVG::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
const nsDisplayItemGeometry* aGeometry,
nsRegion* aInvalidRegion)
nsRegion* aInvalidRegion) const
{
nsSVGOuterSVGFrame *frame = static_cast<nsSVGOuterSVGFrame*>(mFrame);
frame->InvalidateSVG(frame->FindInvalidatedForeignObjectFrameChildren(frame));

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

@ -428,7 +428,7 @@ public:
virtual void Paint(nsDisplayListBuilder* aBuilder,
gfxContext* aCtx) override;
virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder,
bool* aSnap) override;
bool* aSnap) const override;
NS_DISPLAY_DECL_NAME("TableCellBackground", TYPE_TABLE_CELL_BACKGROUND)
};
@ -444,7 +444,7 @@ void nsDisplayTableCellBackground::Paint(nsDisplayListBuilder* aBuilder,
nsRect
nsDisplayTableCellBackground::GetBounds(nsDisplayListBuilder* aBuilder,
bool* aSnap)
bool* aSnap) const
{
// revert from nsDisplayTableItem's implementation ... cell backgrounds
// don't overflow the cell

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