зеркало из https://github.com/mozilla/gecko-dev.git
Merge autoland to central, a=merge
MozReview-Commit-ID: BptG5xWc5Ax
This commit is contained in:
Коммит
ccf6649c52
|
@ -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 user’s 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
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче