mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-04 13:07:52 +00:00
Bug 1576918 - Port PageStyle actor to JSWindowActors for Fission compatibility. r=mconley,Gijs
These actors handle implementation of alternative stylesheets functionality. r=mconley,Gijs Differential Revision: https://phabricator.services.mozilla.com/D46861 --HG-- extra : moz-landing-system : lando
This commit is contained in:
parent
1534e5d150
commit
8a6c8f36ef
@ -1,103 +1,90 @@
|
||||
/* 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";
|
||||
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
var EXPORTED_SYMBOLS = ["PageStyleChild"];
|
||||
|
||||
const { ActorChild } = ChromeUtils.import(
|
||||
"resource://gre/modules/ActorChild.jsm"
|
||||
);
|
||||
class PageStyleChild extends JSWindowActorChild {
|
||||
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 {
|
||||
getViewer(content) {
|
||||
return content.docShell.contentViewer;
|
||||
}
|
||||
let window = event.target.ownerGlobal;
|
||||
window.requestIdleCallback(() => {
|
||||
if (!window || window.closed) {
|
||||
return;
|
||||
}
|
||||
let styleSheets = Array.from(this.document.styleSheets);
|
||||
let filteredStyleSheets = this._filterStyleSheets(styleSheets, window);
|
||||
|
||||
sendStyleSheetInfo(mm) {
|
||||
let content = mm.content;
|
||||
content.requestIdleCallback(() => {
|
||||
let filteredStyleSheets = this._filterStyleSheets(
|
||||
this.getAllStyleSheets(content),
|
||||
content
|
||||
);
|
||||
|
||||
mm.sendAsyncMessage("PageStyle:StyleSheets", {
|
||||
filteredStyleSheets,
|
||||
authorStyleDisabled: this.getViewer(content).authorStyleDisabled,
|
||||
preferredStyleSheetSet: content.document.preferredStyleSheetSet,
|
||||
this.sendAsyncMessage("PageStyle:Add", {
|
||||
filteredStyleSheets,
|
||||
authorStyleDisabled: this.docShell.contentViewer.authorStyleDisabled,
|
||||
preferredStyleSheetSet: this.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) {
|
||||
let content = msg.target.content;
|
||||
switch (msg.name) {
|
||||
// Sent when the page's enabled style sheet is changed.
|
||||
case "PageStyle:Switch":
|
||||
this.getViewer(content).authorStyleDisabled = false;
|
||||
this._stylesheetSwitchAll(content, msg.data.title);
|
||||
this.docShell.contentViewer.authorStyleDisabled = false;
|
||||
this._switchStylesheet(msg.data.title);
|
||||
break;
|
||||
|
||||
// Sent when "No Style" is chosen.
|
||||
case "PageStyle:Disable":
|
||||
this.getViewer(content).authorStyleDisabled = true;
|
||||
this.docShell.contentViewer.authorStyleDisabled = true;
|
||||
break;
|
||||
}
|
||||
|
||||
this.sendStyleSheetInfo(msg.target);
|
||||
}
|
||||
|
||||
handleEvent(event) {
|
||||
let win = event.target.ownerGlobal;
|
||||
if (win != win.top) {
|
||||
return;
|
||||
/**
|
||||
* Switch the stylesheet so that only the sheet with the given title is enabled.
|
||||
*/
|
||||
_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;
|
||||
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];
|
||||
for (let docStyleSheet of docStyleSheets) {
|
||||
if (docStyleSheet.title) {
|
||||
docStyleSheet.disabled = docStyleSheet.title != title;
|
||||
if (docContainsStyleSheet) {
|
||||
docStyleSheet.disabled = docStyleSheet.title !== title;
|
||||
}
|
||||
} else if (docStyleSheet.disabled) {
|
||||
docStyleSheet.disabled = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_stylesheetInFrame(frame, title) {
|
||||
return Array.from(frame.document.styleSheets).some(
|
||||
styleSheet => styleSheet.title == title
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter the stylesheets that actually apply to this webpage.
|
||||
* @param styleSheets The list of stylesheets from the document.
|
||||
* @param content The window object that the webpage lives in.
|
||||
*/
|
||||
_filterStyleSheets(styleSheets, content) {
|
||||
let result = [];
|
||||
|
||||
// Only stylesheets with a title can act as an alternative stylesheet.
|
||||
for (let currentStyleSheet of styleSheets) {
|
||||
if (!currentStyleSheet.title) {
|
||||
continue;
|
||||
@ -115,7 +102,7 @@ class PageStyleChild extends ActorChild {
|
||||
try {
|
||||
if (
|
||||
!currentStyleSheet.ownerNode ||
|
||||
// special-case style nodes, which have no href
|
||||
// Special-case style nodes, which have no href.
|
||||
currentStyleSheet.ownerNode.nodeName.toLowerCase() != "style"
|
||||
) {
|
||||
URI = Services.io.newURI(currentStyleSheet.href);
|
||||
|
37
browser/actors/PageStyleParent.jsm
Normal file
37
browser/actors/PageStyleParent.jsm
Normal file
@ -0,0 +1,37 @@
|
||||
/* 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;
|
||||
if (!browser) {
|
||||
return;
|
||||
}
|
||||
|
||||
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',
|
||||
'PageInfoChild.jsm',
|
||||
'PageStyleChild.jsm',
|
||||
'PageStyleParent.jsm',
|
||||
'PluginChild.jsm',
|
||||
'PluginParent.jsm',
|
||||
'PromptParent.jsm',
|
||||
|
@ -1808,7 +1808,6 @@ var gBrowserInit = {
|
||||
// message sent between when the frame script is loaded and when
|
||||
// the listener is registered.
|
||||
DOMEventHandler.init();
|
||||
gPageStyleMenu.init();
|
||||
LanguageDetectionListener.init();
|
||||
BrowserOnClick.init();
|
||||
CaptivePortalWatcher.init();
|
||||
@ -7730,17 +7729,28 @@ var gPageStyleMenu = {
|
||||
//
|
||||
_pageStyleSheets: new WeakMap(),
|
||||
|
||||
init() {
|
||||
let mm = window.messageManager;
|
||||
mm.addMessageListener("PageStyle:StyleSheets", msg => {
|
||||
if (msg.target.permanentKey) {
|
||||
this._pageStyleSheets.set(msg.target.permanentKey, msg.data);
|
||||
}
|
||||
});
|
||||
/**
|
||||
* Add/append styleSheets to the _pageStyleSheets weakmap.
|
||||
* @param styleSheets
|
||||
* The stylesheets to add, including the preferred
|
||||
* 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
|
||||
* before this information will be available.
|
||||
*
|
||||
@ -7764,6 +7774,10 @@ var gPageStyleMenu = {
|
||||
return data.filteredStyleSheets;
|
||||
},
|
||||
|
||||
clearBrowserStyleSheets(permanentKey) {
|
||||
this._pageStyleSheets.delete(permanentKey);
|
||||
},
|
||||
|
||||
_getStyleSheetInfo(browser) {
|
||||
let data = this._pageStyleSheets.get(browser.permanentKey);
|
||||
if (!data) {
|
||||
@ -7832,14 +7846,56 @@ var gPageStyleMenu = {
|
||||
sep.hidden = (noStyle.hidden && persistentOnly.hidden) || !haveAltSheets;
|
||||
},
|
||||
|
||||
switchStyleSheet(title) {
|
||||
let mm = gBrowser.selectedBrowser.messageManager;
|
||||
mm.sendAsyncMessage("PageStyle:Switch", { title });
|
||||
/**
|
||||
* Send a message to all PageStyleParents by walking the BrowsingContext tree.
|
||||
* @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() {
|
||||
let mm = gBrowser.selectedBrowser.messageManager;
|
||||
mm.sendAsyncMessage("PageStyle:Disable");
|
||||
let { permanentKey } = gBrowser.selectedBrowser;
|
||||
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;
|
||||
await BrowserTestUtils.loadURI(browser, PAGE);
|
||||
await promiseStylesheetsUpdated(browser);
|
||||
await promiseStylesheetsLoaded(tab, 17);
|
||||
|
||||
let menupopup = document.getElementById("pageStyleMenu").menupopup;
|
||||
gPageStyleMenu.fillPopup(menupopup);
|
||||
|
@ -14,9 +14,8 @@ add_task(async function() {
|
||||
false
|
||||
);
|
||||
let browser = tab.linkedBrowser;
|
||||
|
||||
await BrowserTestUtils.loadURI(browser, PAGE);
|
||||
await promiseStylesheetsUpdated(browser);
|
||||
await promiseStylesheetsLoaded(tab, 17);
|
||||
|
||||
let menupopup = document.getElementById("pageStyleMenu").menupopup;
|
||||
gPageStyleMenu.fillPopup(menupopup);
|
||||
@ -34,10 +33,6 @@ add_task(async function() {
|
||||
let target = menupopup.querySelector("menuitem[label='1']");
|
||||
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 empties out the menu between opens, so we need
|
||||
// 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
|
||||
* The <xul:browser> to wait for.
|
||||
* @param tab
|
||||
* The tab that contains the webpage we're testing.
|
||||
* @param styleSheetCount
|
||||
* How many stylesheets we expect to be loaded.
|
||||
* @return Promise
|
||||
*/
|
||||
async function promiseStylesheetsUpdated(browser) {
|
||||
await BrowserTestUtils.waitForMessage(
|
||||
browser.messageManager,
|
||||
"PageStyle:StyleSheets"
|
||||
);
|
||||
// Resolve on the next tick of the event loop to give the Page Style
|
||||
// menu code an opportunity to update.
|
||||
await new Promise(resolve => Services.tm.dispatchToMainThread(resolve));
|
||||
async function promiseStylesheetsLoaded(tab, styleSheetCount) {
|
||||
let styleMenu = tab.ownerGlobal.gPageStyleMenu;
|
||||
let permanentKey = tab.permanentKey;
|
||||
|
||||
await TestUtils.waitForCondition(() => {
|
||||
let menu = styleMenu._pageStyleSheets.get(permanentKey);
|
||||
return menu && menu.filteredStyleSheets.length >= styleSheetCount;
|
||||
}, "waiting for style sheets to load");
|
||||
}
|
||||
|
@ -104,6 +104,23 @@ let ACTORS = {
|
||||
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: {
|
||||
parent: {
|
||||
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: {
|
||||
child: {
|
||||
module: "resource:///actors/SearchTelemetryChild.jsm",
|
||||
|
Loading…
x
Reference in New Issue
Block a user