Source code

Revision control

Other Tools

1
/* This Source Code Form is subject to the terms of the Mozilla Public
2
* License, v. 2.0. If a copy of the MPL was not distributed with this
3
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
6
7
var EXPORTED_SYMBOLS = ["PageStyleChild"];
8
9
const { ActorChild } = ChromeUtils.import(
11
);
12
13
class PageStyleChild extends ActorChild {
14
getViewer(content) {
15
return content.docShell.contentViewer;
16
}
17
18
sendStyleSheetInfo(mm) {
19
let content = mm.content;
20
content.requestIdleCallback(() => {
21
let filteredStyleSheets = this._filterStyleSheets(
22
this.getAllStyleSheets(content),
23
content
24
);
25
26
mm.sendAsyncMessage("PageStyle:StyleSheets", {
27
filteredStyleSheets,
28
authorStyleDisabled: this.getViewer(content).authorStyleDisabled,
29
preferredStyleSheetSet: content.document.preferredStyleSheetSet,
30
});
31
});
32
}
33
34
getAllStyleSheets(frameset) {
35
let selfSheets = Array.from(frameset.document.styleSheets);
36
let subSheets = Array.from(frameset.frames, frame =>
37
this.getAllStyleSheets(frame)
38
);
39
return selfSheets.concat(...subSheets);
40
}
41
42
receiveMessage(msg) {
43
let content = msg.target.content;
44
switch (msg.name) {
45
case "PageStyle:Switch":
46
this.getViewer(content).authorStyleDisabled = false;
47
this._stylesheetSwitchAll(content, msg.data.title);
48
break;
49
50
case "PageStyle:Disable":
51
this.getViewer(content).authorStyleDisabled = true;
52
break;
53
}
54
55
this.sendStyleSheetInfo(msg.target);
56
}
57
58
handleEvent(event) {
59
let win = event.target.ownerGlobal;
60
if (win != win.top) {
61
return;
62
}
63
64
let mm = win.docShell.messageManager;
65
this.sendStyleSheetInfo(mm);
66
}
67
68
_stylesheetSwitchAll(frameset, title) {
69
if (!title || this._stylesheetInFrame(frameset, title)) {
70
this._stylesheetSwitchFrame(frameset, title);
71
}
72
73
for (let i = 0; i < frameset.frames.length; i++) {
74
// Recurse into sub-frames.
75
this._stylesheetSwitchAll(frameset.frames[i], title);
76
}
77
}
78
79
_stylesheetSwitchFrame(frame, title) {
80
var docStyleSheets = frame.document.styleSheets;
81
82
for (let i = 0; i < docStyleSheets.length; ++i) {
83
let docStyleSheet = docStyleSheets[i];
84
if (docStyleSheet.title) {
85
docStyleSheet.disabled = docStyleSheet.title != title;
86
} else if (docStyleSheet.disabled) {
87
docStyleSheet.disabled = false;
88
}
89
}
90
}
91
92
_stylesheetInFrame(frame, title) {
93
return Array.from(frame.document.styleSheets).some(
94
styleSheet => styleSheet.title == title
95
);
96
}
97
98
_filterStyleSheets(styleSheets, content) {
99
let result = [];
100
101
for (let currentStyleSheet of styleSheets) {
102
if (!currentStyleSheet.title) {
103
continue;
104
}
105
106
// Skip any stylesheets that don't match the screen media type.
107
if (currentStyleSheet.media.length > 0) {
108
let mediaQueryList = currentStyleSheet.media.mediaText;
109
if (!content.matchMedia(mediaQueryList).matches) {
110
continue;
111
}
112
}
113
114
let URI;
115
try {
116
if (
117
!currentStyleSheet.ownerNode ||
118
// special-case style nodes, which have no href
119
currentStyleSheet.ownerNode.nodeName.toLowerCase() != "style"
120
) {
121
URI = Services.io.newURI(currentStyleSheet.href);
122
}
123
} catch (e) {
124
if (e.result != Cr.NS_ERROR_MALFORMED_URI) {
125
throw e;
126
}
127
continue;
128
}
129
130
// We won't send data URIs all of the way up to the parent, as these
131
// can be arbitrarily large.
132
let sentURI = !URI || URI.scheme == "data" ? null : URI.spec;
133
134
result.push({
135
title: currentStyleSheet.title,
136
disabled: currentStyleSheet.disabled,
137
href: sentURI,
138
});
139
}
140
141
return result;
142
}
143
}