2018-05-25 20:22:14 +03:00
|
|
|
/* 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/. */
|
2019-10-27 21:08:02 +03:00
|
|
|
"use strict";
|
2018-05-25 20:22:14 +03:00
|
|
|
|
2019-01-17 21:18:31 +03:00
|
|
|
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
2018-05-25 20:22:14 +03:00
|
|
|
|
2018-07-30 05:54:17 +03:00
|
|
|
var EXPORTED_SYMBOLS = ["PageStyleChild"];
|
2018-05-25 20:22:14 +03:00
|
|
|
|
2019-10-27 21:08:02 +03:00
|
|
|
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");
|
|
|
|
}
|
2019-10-24 23:51:59 +03:00
|
|
|
|
2019-10-27 21:08:02 +03:00
|
|
|
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);
|
|
|
|
|
|
|
|
this.sendAsyncMessage("PageStyle:Add", {
|
|
|
|
filteredStyleSheets,
|
|
|
|
authorStyleDisabled: this.docShell.contentViewer.authorStyleDisabled,
|
|
|
|
preferredStyleSheetSet: this.document.preferredStyleSheetSet,
|
|
|
|
});
|
2019-03-08 23:22:37 +03:00
|
|
|
});
|
2019-10-27 21:08:02 +03:00
|
|
|
}
|
2018-07-30 05:54:17 +03:00
|
|
|
}
|
2018-05-25 20:22:14 +03:00
|
|
|
|
|
|
|
receiveMessage(msg) {
|
|
|
|
switch (msg.name) {
|
2019-10-27 21:08:02 +03:00
|
|
|
// Sent when the page's enabled style sheet is changed.
|
2018-05-25 20:22:14 +03:00
|
|
|
case "PageStyle:Switch":
|
2019-10-27 21:08:02 +03:00
|
|
|
this.docShell.contentViewer.authorStyleDisabled = false;
|
|
|
|
this._switchStylesheet(msg.data.title);
|
2018-05-25 20:22:14 +03:00
|
|
|
break;
|
2019-10-27 21:08:02 +03:00
|
|
|
// Sent when "No Style" is chosen.
|
2018-05-25 20:22:14 +03:00
|
|
|
case "PageStyle:Disable":
|
2019-10-27 21:08:02 +03:00
|
|
|
this.docShell.contentViewer.authorStyleDisabled = true;
|
2018-05-25 20:22:14 +03:00
|
|
|
break;
|
|
|
|
}
|
2019-10-24 23:51:59 +03:00
|
|
|
}
|
|
|
|
|
2019-10-27 21:08:02 +03:00
|
|
|
/**
|
|
|
|
* 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;
|
|
|
|
}
|
2018-05-25 20:22:14 +03:00
|
|
|
}
|
|
|
|
|
2019-10-27 21:08:02 +03:00
|
|
|
for (let docStyleSheet of docStyleSheets) {
|
2018-05-25 20:22:14 +03:00
|
|
|
if (docStyleSheet.title) {
|
2019-10-27 21:08:02 +03:00
|
|
|
if (docContainsStyleSheet) {
|
|
|
|
docStyleSheet.disabled = docStyleSheet.title !== title;
|
|
|
|
}
|
2018-05-25 20:22:14 +03:00
|
|
|
} else if (docStyleSheet.disabled) {
|
|
|
|
docStyleSheet.disabled = false;
|
|
|
|
}
|
|
|
|
}
|
2018-07-30 05:54:17 +03:00
|
|
|
}
|
2018-05-25 20:22:14 +03:00
|
|
|
|
2019-10-27 21:08:02 +03:00
|
|
|
/**
|
|
|
|
* 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.
|
|
|
|
*/
|
2018-05-25 20:22:15 +03:00
|
|
|
_filterStyleSheets(styleSheets, content) {
|
2018-05-25 20:22:14 +03:00
|
|
|
let result = [];
|
|
|
|
|
2019-10-27 21:08:02 +03:00
|
|
|
// Only stylesheets with a title can act as an alternative stylesheet.
|
2018-05-25 20:22:14 +03:00
|
|
|
for (let currentStyleSheet of styleSheets) {
|
|
|
|
if (!currentStyleSheet.title) {
|
|
|
|
continue;
|
2019-07-05 10:46:28 +03:00
|
|
|
}
|
2018-05-25 20:22:14 +03:00
|
|
|
|
|
|
|
// Skip any stylesheets that don't match the screen media type.
|
2019-09-14 12:39:26 +03:00
|
|
|
if (currentStyleSheet.media.length) {
|
2018-05-25 20:22:14 +03:00
|
|
|
let mediaQueryList = currentStyleSheet.media.mediaText;
|
|
|
|
if (!content.matchMedia(mediaQueryList).matches) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let URI;
|
|
|
|
try {
|
|
|
|
if (
|
|
|
|
!currentStyleSheet.ownerNode ||
|
2019-10-27 21:08:02 +03:00
|
|
|
// Special-case style nodes, which have no href.
|
2018-05-25 20:22:14 +03:00
|
|
|
currentStyleSheet.ownerNode.nodeName.toLowerCase() != "style"
|
|
|
|
) {
|
|
|
|
URI = Services.io.newURI(currentStyleSheet.href);
|
|
|
|
}
|
|
|
|
} catch (e) {
|
|
|
|
if (e.result != Cr.NS_ERROR_MALFORMED_URI) {
|
|
|
|
throw e;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// We won't send data URIs all of the way up to the parent, as these
|
|
|
|
// can be arbitrarily large.
|
|
|
|
let sentURI = !URI || URI.scheme == "data" ? null : URI.spec;
|
|
|
|
|
|
|
|
result.push({
|
|
|
|
title: currentStyleSheet.title,
|
|
|
|
disabled: currentStyleSheet.disabled,
|
|
|
|
href: sentURI,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
2018-07-30 05:54:17 +03:00
|
|
|
}
|
|
|
|
}
|