зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1576918 - Port PageStyle actor, which handles alternative stylesheets, to JSWindowActors for Fission compatibility. r=mconley,Gijs
Differential Revision: https://phabricator.services.mozilla.com/D46861 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
d5a1276fec
Коммит
cb5acc50ed
|
@ -1,103 +1,90 @@
|
||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
/* 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
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
"use strict";
|
||||||
|
|
||||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||||
|
|
||||||
var EXPORTED_SYMBOLS = ["PageStyleChild"];
|
var EXPORTED_SYMBOLS = ["PageStyleChild"];
|
||||||
|
|
||||||
const { ActorChild } = ChromeUtils.import(
|
class PageStyleChild extends JSWindowActorChild {
|
||||||
"resource://gre/modules/ActorChild.jsm"
|
handleEvent(event) {
|
||||||
);
|
// On page show, tell the parent all of the stylesheets this document has.
|
||||||
|
if (event.type == "pageshow") {
|
||||||
|
// If we are in the topmost browsing context,
|
||||||
|
// delete the stylesheets from the previous page.
|
||||||
|
if (this.browsingContext.top === this.browsingContext) {
|
||||||
|
this.sendAsyncMessage("PageStyle:Clear");
|
||||||
|
}
|
||||||
|
|
||||||
class PageStyleChild extends ActorChild {
|
let window = event.target.ownerGlobal;
|
||||||
getViewer(content) {
|
window.requestIdleCallback(() => {
|
||||||
return content.docShell.contentViewer;
|
if (!window || window.closed) {
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
|
let styleSheets = Array.from(this.document.styleSheets);
|
||||||
|
let filteredStyleSheets = this._filterStyleSheets(styleSheets, window);
|
||||||
|
|
||||||
sendStyleSheetInfo(mm) {
|
this.sendAsyncMessage("PageStyle:Add", {
|
||||||
let content = mm.content;
|
filteredStyleSheets,
|
||||||
content.requestIdleCallback(() => {
|
authorStyleDisabled: this.docShell.contentViewer.authorStyleDisabled,
|
||||||
let filteredStyleSheets = this._filterStyleSheets(
|
preferredStyleSheetSet: this.document.preferredStyleSheetSet,
|
||||||
this.getAllStyleSheets(content),
|
});
|
||||||
content
|
|
||||||
);
|
|
||||||
|
|
||||||
mm.sendAsyncMessage("PageStyle:StyleSheets", {
|
|
||||||
filteredStyleSheets,
|
|
||||||
authorStyleDisabled: this.getViewer(content).authorStyleDisabled,
|
|
||||||
preferredStyleSheetSet: content.document.preferredStyleSheetSet,
|
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
}
|
|
||||||
|
|
||||||
getAllStyleSheets(frameset) {
|
|
||||||
let selfSheets = Array.from(frameset.document.styleSheets);
|
|
||||||
let subSheets = Array.from(frameset.frames, frame =>
|
|
||||||
this.getAllStyleSheets(frame)
|
|
||||||
);
|
|
||||||
return selfSheets.concat(...subSheets);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
receiveMessage(msg) {
|
receiveMessage(msg) {
|
||||||
let content = msg.target.content;
|
|
||||||
switch (msg.name) {
|
switch (msg.name) {
|
||||||
|
// Sent when the page's enabled style sheet is changed.
|
||||||
case "PageStyle:Switch":
|
case "PageStyle:Switch":
|
||||||
this.getViewer(content).authorStyleDisabled = false;
|
this.docShell.contentViewer.authorStyleDisabled = false;
|
||||||
this._stylesheetSwitchAll(content, msg.data.title);
|
this._switchStylesheet(msg.data.title);
|
||||||
break;
|
break;
|
||||||
|
// Sent when "No Style" is chosen.
|
||||||
case "PageStyle:Disable":
|
case "PageStyle:Disable":
|
||||||
this.getViewer(content).authorStyleDisabled = true;
|
this.docShell.contentViewer.authorStyleDisabled = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.sendStyleSheetInfo(msg.target);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
handleEvent(event) {
|
/**
|
||||||
let win = event.target.ownerGlobal;
|
* Switch the stylesheet so that only the sheet with the given title is enabled.
|
||||||
if (win != win.top) {
|
*/
|
||||||
return;
|
_switchStylesheet(title) {
|
||||||
|
let docStyleSheets = this.document.styleSheets;
|
||||||
|
|
||||||
|
// Does this doc contain a stylesheet with this title?
|
||||||
|
// If not, it's a subframe's stylesheet that's being changed,
|
||||||
|
// so no need to disable stylesheets here.
|
||||||
|
let docContainsStyleSheet = false;
|
||||||
|
for (let docStyleSheet of docStyleSheets) {
|
||||||
|
if (docStyleSheet.title === title) {
|
||||||
|
docContainsStyleSheet = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mm = win.docShell.messageManager;
|
for (let docStyleSheet of docStyleSheets) {
|
||||||
this.sendStyleSheetInfo(mm);
|
|
||||||
}
|
|
||||||
|
|
||||||
_stylesheetSwitchAll(frameset, title) {
|
|
||||||
if (!title || this._stylesheetInFrame(frameset, title)) {
|
|
||||||
this._stylesheetSwitchFrame(frameset, title);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let i = 0; i < frameset.frames.length; i++) {
|
|
||||||
// Recurse into sub-frames.
|
|
||||||
this._stylesheetSwitchAll(frameset.frames[i], title);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_stylesheetSwitchFrame(frame, title) {
|
|
||||||
var docStyleSheets = frame.document.styleSheets;
|
|
||||||
|
|
||||||
for (let i = 0; i < docStyleSheets.length; ++i) {
|
|
||||||
let docStyleSheet = docStyleSheets[i];
|
|
||||||
if (docStyleSheet.title) {
|
if (docStyleSheet.title) {
|
||||||
docStyleSheet.disabled = docStyleSheet.title != title;
|
if (docContainsStyleSheet) {
|
||||||
|
docStyleSheet.disabled = docStyleSheet.title !== title;
|
||||||
|
}
|
||||||
} else if (docStyleSheet.disabled) {
|
} else if (docStyleSheet.disabled) {
|
||||||
docStyleSheet.disabled = false;
|
docStyleSheet.disabled = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_stylesheetInFrame(frame, title) {
|
/**
|
||||||
return Array.from(frame.document.styleSheets).some(
|
* Filter the stylesheets that actually apply to this webpage.
|
||||||
styleSheet => styleSheet.title == title
|
* @param styleSheets The list of stylesheets from the document.
|
||||||
);
|
* @param content The window object that the webpage lives in.
|
||||||
}
|
*/
|
||||||
|
|
||||||
_filterStyleSheets(styleSheets, content) {
|
_filterStyleSheets(styleSheets, content) {
|
||||||
let result = [];
|
let result = [];
|
||||||
|
|
||||||
|
// Only stylesheets with a title can act as an alternative stylesheet.
|
||||||
for (let currentStyleSheet of styleSheets) {
|
for (let currentStyleSheet of styleSheets) {
|
||||||
if (!currentStyleSheet.title) {
|
if (!currentStyleSheet.title) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -115,7 +102,7 @@ class PageStyleChild extends ActorChild {
|
||||||
try {
|
try {
|
||||||
if (
|
if (
|
||||||
!currentStyleSheet.ownerNode ||
|
!currentStyleSheet.ownerNode ||
|
||||||
// special-case style nodes, which have no href
|
// Special-case style nodes, which have no href.
|
||||||
currentStyleSheet.ownerNode.nodeName.toLowerCase() != "style"
|
currentStyleSheet.ownerNode.nodeName.toLowerCase() != "style"
|
||||||
) {
|
) {
|
||||||
URI = Services.io.newURI(currentStyleSheet.href);
|
URI = Services.io.newURI(currentStyleSheet.href);
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
/* 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";
|
||||||
|
|
||||||
|
var EXPORTED_SYMBOLS = ["PageStyleParent"];
|
||||||
|
|
||||||
|
class PageStyleParent extends JSWindowActorParent {
|
||||||
|
receiveMessage(msg) {
|
||||||
|
// The top browser.
|
||||||
|
let browser = this.browsingContext.top.embedderElement;
|
||||||
|
let permanentKey = browser.permanentKey;
|
||||||
|
let window = browser.ownerGlobal;
|
||||||
|
if (window.closed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let styleMenu = window.gPageStyleMenu;
|
||||||
|
|
||||||
|
switch (msg.name) {
|
||||||
|
case "PageStyle:Add":
|
||||||
|
if (browser.outerBrowser) {
|
||||||
|
// We are in RDM mode and we probably
|
||||||
|
// want to work with the outer browser.
|
||||||
|
browser = browser.outerBrowser;
|
||||||
|
}
|
||||||
|
styleMenu.addBrowserStyleSheets(msg.data, permanentKey);
|
||||||
|
break;
|
||||||
|
case "PageStyle:Clear":
|
||||||
|
styleMenu.clearBrowserStyleSheets(permanentKey);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -41,6 +41,7 @@ FINAL_TARGET_FILES.actors += [
|
||||||
'OfflineAppsChild.jsm',
|
'OfflineAppsChild.jsm',
|
||||||
'PageInfoChild.jsm',
|
'PageInfoChild.jsm',
|
||||||
'PageStyleChild.jsm',
|
'PageStyleChild.jsm',
|
||||||
|
'PageStyleParent.jsm',
|
||||||
'PluginChild.jsm',
|
'PluginChild.jsm',
|
||||||
'PluginParent.jsm',
|
'PluginParent.jsm',
|
||||||
'PromptParent.jsm',
|
'PromptParent.jsm',
|
||||||
|
|
|
@ -1808,7 +1808,6 @@ var gBrowserInit = {
|
||||||
// message sent between when the frame script is loaded and when
|
// message sent between when the frame script is loaded and when
|
||||||
// the listener is registered.
|
// the listener is registered.
|
||||||
DOMEventHandler.init();
|
DOMEventHandler.init();
|
||||||
gPageStyleMenu.init();
|
|
||||||
LanguageDetectionListener.init();
|
LanguageDetectionListener.init();
|
||||||
BrowserOnClick.init();
|
BrowserOnClick.init();
|
||||||
CaptivePortalWatcher.init();
|
CaptivePortalWatcher.init();
|
||||||
|
@ -7730,17 +7729,28 @@ var gPageStyleMenu = {
|
||||||
//
|
//
|
||||||
_pageStyleSheets: new WeakMap(),
|
_pageStyleSheets: new WeakMap(),
|
||||||
|
|
||||||
init() {
|
/**
|
||||||
let mm = window.messageManager;
|
* Add/append styleSheets to the _pageStyleSheets weakmap.
|
||||||
mm.addMessageListener("PageStyle:StyleSheets", msg => {
|
* @param styleSheets
|
||||||
if (msg.target.permanentKey) {
|
* The stylesheets to add, including the preferred
|
||||||
this._pageStyleSheets.set(msg.target.permanentKey, msg.data);
|
* stylesheet set for this document.
|
||||||
}
|
* @param permanentKey
|
||||||
});
|
* The permanent key of the browser that
|
||||||
|
* these stylesheets come from.
|
||||||
|
*/
|
||||||
|
addBrowserStyleSheets(styleSheets, permanentKey) {
|
||||||
|
let sheetData = this._pageStyleSheets.get(permanentKey);
|
||||||
|
if (!sheetData) {
|
||||||
|
this._pageStyleSheets.set(permanentKey, styleSheets);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sheetData.filteredStyleSheets.push(...styleSheets.filteredStyleSheets);
|
||||||
|
sheetData.preferredStyleSheetSet =
|
||||||
|
sheetData.preferredStyleSheetSet || styleSheets.preferredStyleSheetSet;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an array of Objects representing stylesheets in a
|
* Return an array of Objects representing stylesheets in a
|
||||||
* browser. Note that the pageshow event needs to fire in content
|
* browser. Note that the pageshow event needs to fire in content
|
||||||
* before this information will be available.
|
* before this information will be available.
|
||||||
*
|
*
|
||||||
|
@ -7764,6 +7774,10 @@ var gPageStyleMenu = {
|
||||||
return data.filteredStyleSheets;
|
return data.filteredStyleSheets;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
clearBrowserStyleSheets(permanentKey) {
|
||||||
|
this._pageStyleSheets.delete(permanentKey);
|
||||||
|
},
|
||||||
|
|
||||||
_getStyleSheetInfo(browser) {
|
_getStyleSheetInfo(browser) {
|
||||||
let data = this._pageStyleSheets.get(browser.permanentKey);
|
let data = this._pageStyleSheets.get(browser.permanentKey);
|
||||||
if (!data) {
|
if (!data) {
|
||||||
|
@ -7832,14 +7846,56 @@ var gPageStyleMenu = {
|
||||||
sep.hidden = (noStyle.hidden && persistentOnly.hidden) || !haveAltSheets;
|
sep.hidden = (noStyle.hidden && persistentOnly.hidden) || !haveAltSheets;
|
||||||
},
|
},
|
||||||
|
|
||||||
switchStyleSheet(title) {
|
/**
|
||||||
let mm = gBrowser.selectedBrowser.messageManager;
|
* Send a message to all PageStyleParents by walking the BrowsingContext tree.
|
||||||
mm.sendAsyncMessage("PageStyle:Switch", { title });
|
* @param message
|
||||||
|
* The string message to send to each PageStyleChild.
|
||||||
|
* @param data
|
||||||
|
* The data to send to each PageStyleChild within the message.
|
||||||
|
*/
|
||||||
|
_sendMessageToAll(message, data) {
|
||||||
|
let contextsToVisit = [gBrowser.selectedBrowser.browsingContext];
|
||||||
|
while (contextsToVisit.length) {
|
||||||
|
let currentContext = contextsToVisit.pop();
|
||||||
|
let global = currentContext.currentWindowGlobal;
|
||||||
|
|
||||||
|
if (!global) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let actor = global.getActor("PageStyle");
|
||||||
|
actor.sendAsyncMessage(message, data);
|
||||||
|
|
||||||
|
contextsToVisit.push(...currentContext.getChildren());
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Switch the stylesheet of all documents in the current browser.
|
||||||
|
* @param title The title of the stylesheet to switch to.
|
||||||
|
*/
|
||||||
|
switchStyleSheet(title) {
|
||||||
|
let { permanentKey } = gBrowser.selectedBrowser;
|
||||||
|
let sheetData = this._pageStyleSheets.get(permanentKey);
|
||||||
|
if (sheetData && sheetData.filteredStyleSheets) {
|
||||||
|
sheetData.authorStyleDisabled = false;
|
||||||
|
for (let sheet of sheetData.filteredStyleSheets) {
|
||||||
|
sheet.disabled = sheet.title !== title;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this._sendMessageToAll("PageStyle:Switch", { title });
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disable all stylesheets. Called with View > Page Style > No Style.
|
||||||
|
*/
|
||||||
disableStyle() {
|
disableStyle() {
|
||||||
let mm = gBrowser.selectedBrowser.messageManager;
|
let { permanentKey } = gBrowser.selectedBrowser;
|
||||||
mm.sendAsyncMessage("PageStyle:Disable");
|
let sheetData = this._pageStyleSheets.get(permanentKey);
|
||||||
|
if (sheetData) {
|
||||||
|
sheetData.authorStyleDisabled = true;
|
||||||
|
}
|
||||||
|
this._sendMessageToAll("PageStyle:Disable", {});
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ add_task(async function() {
|
||||||
);
|
);
|
||||||
let browser = tab.linkedBrowser;
|
let browser = tab.linkedBrowser;
|
||||||
await BrowserTestUtils.loadURI(browser, PAGE);
|
await BrowserTestUtils.loadURI(browser, PAGE);
|
||||||
await promiseStylesheetsUpdated(browser);
|
await promiseStylesheetsLoaded(tab, 17);
|
||||||
|
|
||||||
let menupopup = document.getElementById("pageStyleMenu").menupopup;
|
let menupopup = document.getElementById("pageStyleMenu").menupopup;
|
||||||
gPageStyleMenu.fillPopup(menupopup);
|
gPageStyleMenu.fillPopup(menupopup);
|
||||||
|
|
|
@ -14,9 +14,8 @@ add_task(async function() {
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
let browser = tab.linkedBrowser;
|
let browser = tab.linkedBrowser;
|
||||||
|
|
||||||
await BrowserTestUtils.loadURI(browser, PAGE);
|
await BrowserTestUtils.loadURI(browser, PAGE);
|
||||||
await promiseStylesheetsUpdated(browser);
|
await promiseStylesheetsLoaded(tab, 17);
|
||||||
|
|
||||||
let menupopup = document.getElementById("pageStyleMenu").menupopup;
|
let menupopup = document.getElementById("pageStyleMenu").menupopup;
|
||||||
gPageStyleMenu.fillPopup(menupopup);
|
gPageStyleMenu.fillPopup(menupopup);
|
||||||
|
@ -34,10 +33,6 @@ add_task(async function() {
|
||||||
let target = menupopup.querySelector("menuitem[label='1']");
|
let target = menupopup.querySelector("menuitem[label='1']");
|
||||||
target.click();
|
target.click();
|
||||||
|
|
||||||
// Now we need to wait for the content process to send its stylesheet
|
|
||||||
// update for the selected tab to the parent.
|
|
||||||
await promiseStylesheetsUpdated(browser);
|
|
||||||
|
|
||||||
gPageStyleMenu.fillPopup(menupopup);
|
gPageStyleMenu.fillPopup(menupopup);
|
||||||
// gPageStyleMenu empties out the menu between opens, so we need
|
// gPageStyleMenu empties out the menu between opens, so we need
|
||||||
// to get a new reference to the selected menuitem
|
// to get a new reference to the selected menuitem
|
||||||
|
|
|
@ -530,18 +530,20 @@ async function loadBadCertPage(url) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Waits for the message from content to update the Page Style menu.
|
* Waits for the stylesheets to be loaded into the browser menu.
|
||||||
*
|
*
|
||||||
* @param browser
|
* @param tab
|
||||||
* The <xul:browser> to wait for.
|
* The tab that contains the webpage we're testing.
|
||||||
|
* @param styleSheetCount
|
||||||
|
* How many stylesheets we expect to be loaded.
|
||||||
* @return Promise
|
* @return Promise
|
||||||
*/
|
*/
|
||||||
async function promiseStylesheetsUpdated(browser) {
|
async function promiseStylesheetsLoaded(tab, styleSheetCount) {
|
||||||
await BrowserTestUtils.waitForMessage(
|
let styleMenu = tab.ownerGlobal.gPageStyleMenu;
|
||||||
browser.messageManager,
|
let permanentKey = tab.permanentKey;
|
||||||
"PageStyle:StyleSheets"
|
|
||||||
);
|
await TestUtils.waitForCondition(() => {
|
||||||
// Resolve on the next tick of the event loop to give the Page Style
|
let menu = styleMenu._pageStyleSheets.get(permanentKey);
|
||||||
// menu code an opportunity to update.
|
return menu && menu.filteredStyleSheets.length >= styleSheetCount;
|
||||||
await new Promise(resolve => Services.tm.dispatchToMainThread(resolve));
|
}, "waiting for style sheets to load");
|
||||||
}
|
}
|
||||||
|
|
|
@ -104,6 +104,23 @@ let ACTORS = {
|
||||||
allFrames: true,
|
allFrames: true,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
PageStyle: {
|
||||||
|
parent: {
|
||||||
|
moduleURI: "resource:///actors/PageStyleParent.jsm",
|
||||||
|
},
|
||||||
|
child: {
|
||||||
|
moduleURI: "resource:///actors/PageStyleChild.jsm",
|
||||||
|
events: {
|
||||||
|
pageshow: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// Only matching web pages, as opposed to internal about:, chrome: or
|
||||||
|
// resource: pages. See https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Match_patterns
|
||||||
|
matches: ["*://*/*"],
|
||||||
|
allFrames: true,
|
||||||
|
},
|
||||||
|
|
||||||
Plugin: {
|
Plugin: {
|
||||||
parent: {
|
parent: {
|
||||||
moduleURI: "resource:///actors/PluginParent.jsm",
|
moduleURI: "resource:///actors/PluginParent.jsm",
|
||||||
|
@ -313,20 +330,6 @@ let LEGACY_ACTORS = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
PageStyle: {
|
|
||||||
child: {
|
|
||||||
module: "resource:///actors/PageStyleChild.jsm",
|
|
||||||
group: "browsers",
|
|
||||||
events: {
|
|
||||||
pageshow: {},
|
|
||||||
},
|
|
||||||
messages: ["PageStyle:Switch", "PageStyle:Disable"],
|
|
||||||
// Only matching web pages, as opposed to internal about:, chrome: or
|
|
||||||
// resource: pages. See https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Match_patterns
|
|
||||||
matches: ["*://*/*"],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
SearchTelemetry: {
|
SearchTelemetry: {
|
||||||
child: {
|
child: {
|
||||||
module: "resource:///actors/SearchTelemetryChild.jsm",
|
module: "resource:///actors/SearchTelemetryChild.jsm",
|
||||||
|
|
Загрузка…
Ссылка в новой задаче