mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-30 00:01:50 +00:00
dc14cc8a35
This change brings the following improvements to RDM: * Page state is preserved when toggling in and out of RDM * Session history is no longer manipulated, so the tool UI won't end up in the tab's back-forward page list. Known issues to be fixed later: * The browser UI is not hooked up to the viewport browser * Restarting the browser with the tool open shows a confused, empty RDM MozReview-Commit-ID: Fb6QRv6LYow
195 lines
6.0 KiB
JavaScript
195 lines
6.0 KiB
JavaScript
/* 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";
|
|
|
|
/* global content, docShell, addEventListener, addMessageListener,
|
|
removeEventListener, removeMessageListener, sendAsyncMessage, Services */
|
|
|
|
var global = this;
|
|
|
|
// Guard against loading this frame script mutiple times
|
|
(function () {
|
|
if (global.responsiveFrameScriptLoaded) {
|
|
return;
|
|
}
|
|
|
|
var Ci = Components.interfaces;
|
|
const gDeviceSizeWasPageSize = docShell.deviceSizeIsPageSize;
|
|
const gFloatingScrollbarsStylesheet = Services.io.newURI("chrome://devtools/skin/floating-scrollbars-responsive-design.css", null, null);
|
|
var gRequiresFloatingScrollbars;
|
|
|
|
var active = false;
|
|
var resizeNotifications = false;
|
|
|
|
addMessageListener("ResponsiveMode:Start", startResponsiveMode);
|
|
addMessageListener("ResponsiveMode:Stop", stopResponsiveMode);
|
|
addMessageListener("ResponsiveMode:IsActive", isActive);
|
|
|
|
function debug(msg) {
|
|
// dump(`RDM CHILD: ${msg}\n`);
|
|
}
|
|
|
|
/**
|
|
* Used by tests to verify the state of responsive mode.
|
|
*/
|
|
function isActive() {
|
|
sendAsyncMessage("ResponsiveMode:IsActive:Done", { active });
|
|
}
|
|
|
|
function startResponsiveMode({data:data}) {
|
|
debug("START");
|
|
if (active) {
|
|
debug("ALREADY STARTED, ABORT");
|
|
return;
|
|
}
|
|
addMessageListener("ResponsiveMode:RequestScreenshot", screenshot);
|
|
let webProgress = docShell.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIWebProgress);
|
|
webProgress.addProgressListener(WebProgressListener, Ci.nsIWebProgress.NOTIFY_ALL);
|
|
docShell.deviceSizeIsPageSize = true;
|
|
gRequiresFloatingScrollbars = data.requiresFloatingScrollbars;
|
|
if (data.notifyOnResize) {
|
|
startOnResize();
|
|
}
|
|
|
|
// At this point, a content viewer might not be loaded for this
|
|
// docshell. makeScrollbarsFloating will be triggered by onLocationChange.
|
|
if (docShell.contentViewer) {
|
|
makeScrollbarsFloating();
|
|
}
|
|
active = true;
|
|
sendAsyncMessage("ResponsiveMode:Start:Done");
|
|
}
|
|
|
|
function onResize() {
|
|
let { width, height } = content.screen;
|
|
debug(`EMIT RESIZE: ${width} x ${height}`);
|
|
sendAsyncMessage("ResponsiveMode:OnContentResize", {
|
|
width,
|
|
height,
|
|
});
|
|
}
|
|
|
|
function bindOnResize() {
|
|
content.addEventListener("resize", onResize, false);
|
|
}
|
|
|
|
function startOnResize() {
|
|
debug("START ON RESIZE");
|
|
if (resizeNotifications) {
|
|
return;
|
|
}
|
|
resizeNotifications = true;
|
|
bindOnResize();
|
|
addEventListener("DOMWindowCreated", bindOnResize, false);
|
|
}
|
|
|
|
function stopOnResize() {
|
|
debug("STOP ON RESIZE");
|
|
if (!resizeNotifications) {
|
|
return;
|
|
}
|
|
resizeNotifications = false;
|
|
content.removeEventListener("resize", onResize, false);
|
|
removeEventListener("DOMWindowCreated", bindOnResize, false);
|
|
}
|
|
|
|
function stopResponsiveMode() {
|
|
debug("STOP");
|
|
if (!active) {
|
|
debug("ALREADY STOPPED, ABORT");
|
|
return;
|
|
}
|
|
active = false;
|
|
removeMessageListener("ResponsiveMode:RequestScreenshot", screenshot);
|
|
let webProgress = docShell.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIWebProgress);
|
|
webProgress.removeProgressListener(WebProgressListener);
|
|
docShell.deviceSizeIsPageSize = gDeviceSizeWasPageSize;
|
|
restoreScrollbars();
|
|
stopOnResize();
|
|
sendAsyncMessage("ResponsiveMode:Stop:Done");
|
|
}
|
|
|
|
function makeScrollbarsFloating() {
|
|
if (!gRequiresFloatingScrollbars) {
|
|
return;
|
|
}
|
|
|
|
let allDocShells = [docShell];
|
|
|
|
for (let i = 0; i < docShell.childCount; i++) {
|
|
let child = docShell.getChildAt(i).QueryInterface(Ci.nsIDocShell);
|
|
allDocShells.push(child);
|
|
}
|
|
|
|
for (let d of allDocShells) {
|
|
let win = d.contentViewer.DOMDocument.defaultView;
|
|
let winUtils = win.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
|
|
try {
|
|
winUtils.loadSheet(gFloatingScrollbarsStylesheet, win.AGENT_SHEET);
|
|
} catch (e) { }
|
|
}
|
|
|
|
flushStyle();
|
|
}
|
|
|
|
function restoreScrollbars() {
|
|
let allDocShells = [docShell];
|
|
for (let i = 0; i < docShell.childCount; i++) {
|
|
allDocShells.push(docShell.getChildAt(i).QueryInterface(Ci.nsIDocShell));
|
|
}
|
|
for (let d of allDocShells) {
|
|
let win = d.contentViewer.DOMDocument.defaultView;
|
|
let winUtils = win.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
|
|
try {
|
|
winUtils.removeSheet(gFloatingScrollbarsStylesheet, win.AGENT_SHEET);
|
|
} catch (e) { }
|
|
}
|
|
flushStyle();
|
|
}
|
|
|
|
function flushStyle() {
|
|
// Force presContext destruction
|
|
let isSticky = docShell.contentViewer.sticky;
|
|
docShell.contentViewer.sticky = false;
|
|
docShell.contentViewer.hide();
|
|
docShell.contentViewer.show();
|
|
docShell.contentViewer.sticky = isSticky;
|
|
}
|
|
|
|
function screenshot() {
|
|
let canvas = content.document.createElementNS("http://www.w3.org/1999/xhtml", "canvas");
|
|
let ratio = content.devicePixelRatio;
|
|
let width = content.innerWidth * ratio;
|
|
let height = content.innerHeight * ratio;
|
|
canvas.mozOpaque = true;
|
|
canvas.width = width;
|
|
canvas.height = height;
|
|
let ctx = canvas.getContext("2d");
|
|
ctx.scale(ratio, ratio);
|
|
ctx.drawWindow(content, content.scrollX, content.scrollY, width, height, "#fff");
|
|
sendAsyncMessage("ResponsiveMode:RequestScreenshot:Done", canvas.toDataURL());
|
|
}
|
|
|
|
var WebProgressListener = {
|
|
onLocationChange(webProgress, request, URI, flags) {
|
|
if (flags & Ci.nsIWebProgressListener.LOCATION_CHANGE_SAME_DOCUMENT) {
|
|
return;
|
|
}
|
|
makeScrollbarsFloating();
|
|
},
|
|
QueryInterface: function QueryInterface(aIID) {
|
|
if (aIID.equals(Ci.nsIWebProgressListener) ||
|
|
aIID.equals(Ci.nsISupportsWeakReference) ||
|
|
aIID.equals(Ci.nsISupports)) {
|
|
return this;
|
|
}
|
|
throw Components.results.NS_ERROR_NO_INTERFACE;
|
|
}
|
|
};
|
|
})();
|
|
|
|
global.responsiveFrameScriptLoaded = true;
|
|
sendAsyncMessage("ResponsiveMode:ChildScriptReady");
|