Bug 950132 - Fix pageStyle data collection r=yoric

From af5873fe7e4f55dd72f0e62d5c22285c2c94e40d Mon Sep 17 00:00:00 2001
This commit is contained in:
Tim Taubert 2013-12-19 12:21:51 +01:00
parent c186d04972
commit ca97bda553
5 changed files with 98 additions and 47 deletions

View File

@ -244,20 +244,34 @@ let ScrollPositionListener = {
* currently applied style to the chrome process.
*
* Causes a SessionStore:update message to be sent that contains the currently
* selected pageStyle, if any. The pageStyle is represented by a string.
* selected pageStyle for all reachable frames.
*
* Example:
* {pageStyle: "Dusk", children: [null, {pageStyle: "Mozilla"}]}
*/
let PageStyleListener = {
init: function () {
Services.obs.addObserver(this, "author-style-disabled-changed", true);
Services.obs.addObserver(this, "style-sheet-applicable-state-changed", true);
gFrameTree.addObserver(this);
},
observe: function (subject, topic) {
if (subject.defaultView && subject.defaultView.top == content) {
MessageQueue.push("pageStyle", () => PageStyle.collect(docShell) || null);
let frame = subject.defaultView;
if (frame && gFrameTree.contains(frame)) {
MessageQueue.push("pageStyle", () => this.collect());
}
},
collect: function () {
return PageStyle.collect(docShell, gFrameTree);
},
onFrameTreeReset: function () {
MessageQueue.push("pageStyle", () => null);
},
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
Ci.nsISupportsWeakReference])
};

View File

@ -12,13 +12,17 @@ const Ci = Components.interfaces;
* The external API exported by this module.
*/
this.PageStyle = Object.freeze({
collect: function (docShell) {
return PageStyleInternal.collect(docShell);
collect: function (docShell, frameTree) {
return PageStyleInternal.collect(docShell, frameTree);
},
restore: function (docShell, frameList, pageStyle) {
PageStyleInternal.restore(docShell, frameList, pageStyle);
},
restoreTree: function (docShell, data) {
PageStyleInternal.restoreTree(docShell, data);
}
});
// Signifies that author style level is disabled for the page.
@ -26,47 +30,29 @@ const NO_STYLE = "_nostyle";
let PageStyleInternal = {
/**
* Find out the title of the style sheet selected for the given
* docshell. Recurse into frames if needed.
* Collects the selected style sheet sets for all reachable frames.
*/
collect: function (docShell) {
collect: function (docShell, frameTree) {
let result = frameTree.map(({document: doc}) => {
let style;
if (doc) {
// http://dev.w3.org/csswg/cssom/#persisting-the-selected-css-style-sheet-set
style = doc.selectedStyleSheetSet || doc.lastStyleSheetSet;
}
return style ? {pageStyle: style} : null;
});
let markupDocumentViewer =
docShell.contentViewer.QueryInterface(Ci.nsIMarkupDocumentViewer);
if (markupDocumentViewer.authorStyleDisabled) {
return NO_STYLE;
result = result || {};
result.disabled = true;
}
let content = docShell.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindow);
return this.collectFrame(content);
},
/**
* Determine the title of the currently enabled style sheet (if any);
* recurse through the frameset if necessary.
* @param content is a frame reference
* @returns the title style sheet determined to be enabled (empty string if none)
*/
collectFrame: function (content) {
const forScreen = /(?:^|,)\s*(?:all|screen)\s*(?:,|$)/i;
let sheets = content.document.styleSheets;
for (let i = 0; i < sheets.length; i++) {
let ss = sheets[i];
let media = ss.media.mediaText;
if (!ss.disabled && ss.title && (!media || forScreen.test(media))) {
return ss.title;
}
}
for (let i = 0; i < content.frames.length; i++) {
let selectedPageStyle = this.collectFrame(content.frames[i]);
if (selectedPageStyle) {
return selectedPageStyle;
}
}
return "";
return result && Object.keys(result).length ? result : null;
},
/**
@ -91,4 +77,51 @@ let PageStyleInternal = {
});
}
},
/**
* Restores pageStyle data for the current frame hierarchy starting at the
* |docShell's| current DOMWindow using the given pageStyle |data|.
*
* Warning: If the current frame hierarchy doesn't match that of the given
* |data| object we will silently discard data for unreachable frames. We may
* as well assign page styles to the wrong frames if some were reordered or
* removed.
*
* @param docShell (nsIDocShell)
* @param data (object)
* {
* disabled: true, // when true, author styles will be disabled
* pageStyle: "Dusk",
* children: [
* null,
* {pageStyle: "Mozilla", children: [ ... ]}
* ]
* }
*/
restoreTree: function (docShell, data) {
let disabled = data.disabled || false;
let markupDocumentViewer =
docShell.contentViewer.QueryInterface(Ci.nsIMarkupDocumentViewer);
markupDocumentViewer.authorStyleDisabled = disabled;
function restoreFrame(root, data) {
if (data.hasOwnProperty("pageStyle")) {
root.document.selectedStyleSheetSet = data.pageStyle;
}
if (!data.hasOwnProperty("children")) {
return;
}
let frames = root.frames;
data.children.forEach((child, index) => {
if (child && index < frames.length) {
restoreFrame(frames[index], child);
}
});
}
let ifreq = docShell.QueryInterface(Ci.nsIInterfaceRequestor);
restoreFrame(ifreq.getInterface(Ci.nsIDOMWindow), data);
}
};

View File

@ -2976,11 +2976,17 @@ let SessionStoreInternal = {
}
let frameList = this.getFramesToRestore(aBrowser);
let pageStyle = RestoreData.get(aBrowser, "pageStyle") || "";
let pageStyle = RestoreData.get(aBrowser, "pageStyle") || {};
let scrollPositions = RestoreData.get(aBrowser, "scroll") || {};
PageStyle.restore(aBrowser.docShell, frameList, pageStyle);
ScrollPosition.restoreTree(aBrowser.contentWindow, scrollPositions);
// Support the old pageStyle format.
if (typeof(pageStyle) === "string") {
PageStyle.restore(aBrowser.docShell, frameList, pageStyle);
} else {
ScrollPosition.restoreTree(aBrowser.contentWindow, scrollPositions);
}
PageStyle.restoreTree(aBrowser.docShell, pageStyle);
TextAndScrollData.restore(frameList);
let tab = aBrowser.__SS_restore_tab;

View File

@ -61,7 +61,8 @@ add_task(function nested_page_style() {
gBrowser.removeTab(tab);
let [{state: {pageStyle}}] = JSON.parse(ss.getClosedTabData(window));
is(pageStyle, "alternate", "correct pageStyle persisted");
let expected = JSON.stringify({children: [{pageStyle: "alternate"}]});
is(JSON.stringify(pageStyle), expected, "correct pageStyle persisted");
});
function getStyleSheets(browser) {

View File

@ -11,9 +11,6 @@
<link href="404.css" title="media_ALL" rel="alternate stylesheet" media=" ALL ">
<link href="404.css" title="media_screen" rel="alternate stylesheet" media="screen">
<link href="404.css" title="media_print_screen" rel="alternate stylesheet" media="print,screen">
<link href="404.css" title="fail_media_print" rel="alternate stylesheet" media="print">
<link href="404.css" title="fail_media_projection" rel="stylesheet" media="projection">
<link href="404.css" title="fail_media_invalid" rel="alternate stylesheet" media="hallo">
</head>
<body></body>
</html>