Commit 2459f40c authored by Dave Townsend's avatar Dave Townsend
Browse files

Bug 1682593: Remove the site specific browser feature. r=Gijs

Differential Revision: https://phabricator.services.mozilla.com/D101860
parent 383977e4
......@@ -2030,9 +2030,6 @@ pref("app.normandy.onsync_skew_sec", 600);
pref("app.shield.optoutstudies.enabled", false);
#endif
// Web apps support
pref("browser.ssb.enabled", false);
// Multi-lingual preferences
#if defined(RELEASE_OR_BETA) && !defined(MOZ_DEV_EDITION)
pref("intl.multilingual.enabled", true);
......
......@@ -2,11 +2,6 @@
* 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/. */
ChromeUtils.defineModuleGetter(
this,
"SiteSpecificBrowser",
"resource:///modules/SiteSpecificBrowserService.jsm"
);
ChromeUtils.defineModuleGetter(
this,
"SearchUIUtils",
......@@ -1133,33 +1128,6 @@ BrowserPageActions.pinTab = {
},
};
// SiteSpecificBrowser
BrowserPageActions.launchSSB = {
updateState() {
let action = PageActions.actionForID("launchSSB");
let browser = gBrowser.selectedBrowser;
action.setDisabled(!browser.currentURI.schemeIs("https"), window);
},
async onCommand(event, buttonNode) {
if (!gBrowser.currentURI.schemeIs("https")) {
return;
}
let ssb = await SiteSpecificBrowser.createFromBrowser(
gBrowser.selectedBrowser
);
// Launching through the UI implies installing.
await ssb.install();
// The site's manifest may point to a different start page so explicitly
// open the SSB to the current page.
ssb.launch(gBrowser.selectedBrowser.currentURI);
gBrowser.removeTab(gBrowser.selectedTab, { closeWindowWithLastTab: false });
},
};
// copy URL
BrowserPageActions.copyURL = {
onCommand(event, buttonNode) {
......
......@@ -70,9 +70,6 @@ XPCOMUtils.defineLazyModuleGetters(this, {
SimpleServiceDiscovery: "resource://gre/modules/SimpleServiceDiscovery.jsm",
SiteDataManager: "resource:///modules/SiteDataManager.jsm",
SitePermissions: "resource:///modules/SitePermissions.jsm",
SiteSpecificBrowser: "resource:///modules/SiteSpecificBrowserService.jsm",
SiteSpecificBrowserService:
"resource:///modules/SiteSpecificBrowserService.jsm",
SubDialogManager: "resource://gre/modules/SubDialog.jsm",
TabModalPrompt: "chrome://global/content/tabprompts.jsm",
TabCrashHandler: "resource:///modules/ContentCrashHandlers.jsm",
......@@ -1930,8 +1927,6 @@ var gBrowserInit = {
FullZoom.init();
PanelUI.init();
SiteSpecificBrowserUI.init();
UpdateUrlbarSearchSplitterState();
BookmarkingUI.init();
......@@ -2567,130 +2562,6 @@ gBrowserInit.idleTasksFinishedPromise = new Promise(resolve => {
gBrowserInit.idleTaskPromiseResolve = resolve;
});
const SiteSpecificBrowserUI = {
menuInitialized: false,
init() {
if (!SiteSpecificBrowserService.isEnabled) {
return;
}
XPCOMUtils.defineLazyGetter(this, "panelBody", () => {
return PanelMultiView.getViewNode(
document,
"appMenu-SSBView .panel-subview-body"
);
});
let initializeMenu = async () => {
let list = await SiteSpecificBrowserService.list();
for (let ssb of list) {
this.addSSBToMenu(ssb);
}
if (!list.length) {
document.getElementById("appMenu-ssb-button").hidden = true;
}
this.menuInitialized = true;
Services.obs.addObserver(this, "site-specific-browser-install", true);
Services.obs.addObserver(this, "site-specific-browser-uninstall", true);
};
document.getElementById("appMenu-popup").addEventListener(
"popupshowing",
() => {
let blocker = initializeMenu();
PanelMultiView.getViewNode(
document,
"appMenu-SSBView"
).addEventListener(
"ViewShowing",
event => {
event.detail.addBlocker(blocker);
},
{ once: true }
);
},
{ once: true }
);
},
observe(subject, topic, id) {
let ssb = SiteSpecificBrowser.get(id);
switch (topic) {
case "site-specific-browser-install":
this.addSSBToMenu(ssb);
break;
case "site-specific-browser-uninstall":
this.removeSSBFromMenu(ssb);
break;
}
},
removeSSBFromMenu(ssb) {
let container = document.getElementById("ssb-button-" + ssb.id);
if (!container) {
return;
}
if (!container.nextElementSibling && !container.previousElementSibling) {
document.getElementById("appMenu-ssb-button").hidden = true;
}
let button = container.querySelector(".ssb-launch");
let uri = button.getAttribute("image");
if (uri) {
URL.revokeObjectURL(uri);
}
container.remove();
},
addSSBToMenu(ssb) {
let container = document.createXULElement("toolbaritem");
container.id = `ssb-button-${ssb.id}`;
container.className = "toolbaritem-menu-buttons";
let menu = document.createXULElement("toolbarbutton");
menu.className = "ssb-launch subviewbutton subviewbutton-iconic";
menu.setAttribute("label", ssb.name);
menu.setAttribute("flex", "1");
ssb.getScaledIcon(16 * devicePixelRatio).then(
icon => {
if (icon) {
menu.setAttribute("image", URL.createObjectURL(icon));
}
},
error => {
console.error(error);
}
);
menu.addEventListener("command", () => {
ssb.launch();
});
let uninstall = document.createXULElement("toolbarbutton");
uninstall.className = "ssb-uninstall subviewbutton subviewbutton-iconic";
// Hardcoded for now. Localization tracked in bug 1602528.
uninstall.setAttribute("tooltiptext", "Uninstall");
uninstall.addEventListener("command", () => {
ssb.uninstall();
});
container.append(menu);
container.append(uninstall);
this.panelBody.append(container);
document.getElementById("appMenu-ssb-button").hidden = false;
},
QueryInterface: ChromeUtils.generateQI(["nsISupportsWeakReference"]),
};
function HandleAppCommandEvent(evt) {
switch (evt.command) {
case "Back":
......
......@@ -868,12 +868,6 @@
key="key_openAddons"
command="Tools:Addons"
/>
<toolbarbutton id="appMenu-ssb-button"
class="subviewbutton subviewbutton-iconic subviewbutton-nav"
label="Sites in App Mode"
closemenu="none"
oncommand="PanelUI.showSubView('appMenu-SSBView', this)"
hidden="true" persist="hidden"/>
<toolbarbutton id="appMenu-preferences-button"
class="subviewbutton subviewbutton-iconic"
#ifdef XP_WIN
......@@ -1184,11 +1178,6 @@
</vbox>
</panelview>
<panelview id="appMenu-SSBView" class="PanelUI-subView">
<vbox class="panel-subview-body">
</vbox>
</panelview>
<panelview id="appMenu-moreView" title="&moreMenu.label;" class="PanelUI-subView">
<vbox class="panel-subview-body">
<toolbarbutton id="appMenu-taskmanager-button"
......
......@@ -691,17 +691,6 @@ let JSWINDOWACTORS = {
allFrames: true,
},
SiteSpecificBrowser: {
parent: {
moduleURI: "resource:///actors/SiteSpecificBrowserParent.jsm",
},
child: {
moduleURI: "resource:///actors/SiteSpecificBrowserChild.jsm",
},
allFrames: true,
},
Translation: {
parent: {
moduleURI: "resource:///modules/translation/TranslationParent.jsm",
......
......@@ -53,7 +53,6 @@ DIRS += [
"search",
"sessionstore",
"shell",
"ssb",
"syncedtabs",
"uitour",
"urlbar",
......
/* 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/. */
var EXPORTED_SYMBOLS = ["ImageTools"];
const { XPCOMUtils } = ChromeUtils.import(
"resource://gre/modules/XPCOMUtils.jsm"
);
XPCOMUtils.defineLazyModuleGetters(this, {
FileUtils: "resource://gre/modules/FileUtils.jsm",
NetUtil: "resource://gre/modules/NetUtil.jsm",
Services: "resource://gre/modules/Services.jsm",
});
XPCOMUtils.defineLazyServiceGetter(
this,
"ImgTools",
"@mozilla.org/image/tools;1",
Ci.imgITools
);
XPCOMUtils.defineLazyGlobalGetters(this, ["Blob"]);
const ImageTools = {
/**
* Given a data URI decodes the data into an object with "type" which is the
* found mimetype and "container" which is an imgIContainer.
*
* @param {nsIURI} dataURI the URI to load.
* @return {Promise<object>} the image info.
*/
loadImage(dataURI) {
return new Promise((resolve, reject) => {
if (!dataURI.schemeIs("data")) {
reject(new Error("Should only be loading data URIs."));
return;
}
let channel = NetUtil.newChannel({
uri: dataURI,
loadUsingSystemPrincipal: true,
});
ImgTools.decodeImageFromChannelAsync(
dataURI,
channel,
(container, status) => {
if (Components.isSuccessCode(status)) {
resolve({
type: channel.contentType,
container,
});
} else {
reject(Components.Exception("Failed to load image.", status));
}
},
null
);
});
},
scaleImage(container, width, height) {
return new Promise((resolve, reject) => {
let stream = ImgTools.encodeScaledImage(
container,
"image/png",
width,
height,
""
);
try {
stream.QueryInterface(Ci.nsIAsyncInputStream);
} catch (e) {
reject(
Components.Exception(
"imgIEncoder must implement nsIAsyncInputStream",
e
)
);
}
let binaryStream = Cc["@mozilla.org/binaryinputstream;1"].createInstance(
Ci.nsIBinaryInputStream
);
binaryStream.setInputStream(stream);
let buffers = [];
let callback = () => {
try {
let available = binaryStream.available();
if (available) {
let buffer = new ArrayBuffer(available);
binaryStream.readArrayBuffer(available, buffer);
buffers.push(buffer);
stream.asyncWait(callback, 0, 0, Services.tm.mainThread);
return;
}
// No data available, assume the encoding is done.
resolve(new Blob(buffers));
} catch (e) {
reject(e);
}
};
try {
stream.asyncWait(callback, 0, 0, Services.tm.mainThread);
} catch (e) {
reject(e);
}
});
},
saveIcon(container, width, height, target) {
return new Promise((resolve, reject) => {
let output = FileUtils.openFileOutputStream(target);
let stream = ImgTools.encodeScaledImage(
container,
"image/vnd.microsoft.icon",
width,
height,
""
);
NetUtil.asyncCopy(stream, output, status => {
if (Components.isSuccessCode(status)) {
resolve();
} else {
reject(Components.Exception("Failed to save icon.", status));
}
});
});
},
};
/* 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 EXPORTED_SYMBOLS = ["SiteSpecificBrowserChild"];
const { SiteSpecificBrowserBase } = ChromeUtils.import(
"resource:///modules/SiteSpecificBrowserService.jsm"
);
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
const { E10SUtils } = ChromeUtils.import(
"resource://gre/modules/E10SUtils.jsm"
);
/**
* Loads an icon URL into a data URI.
*
* @param {Window} window the DOM window providing the icon.
* @param {string} uri the href for the icon, may be relative to the source page.
* @return {Promise<string>} the data URI.
*/
async function loadIcon(window, uri) {
let iconURL = new window.URL(uri, window.location);
let request = new window.Request(iconURL, { mode: "cors" });
request.overrideContentPolicyType(Ci.nsIContentPolicy.TYPE_IMAGE);
let response = await window.fetch(request);
let blob = await response.blob();
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onloadend = () => resolve(reader.result);
reader.onerror = reject;
reader.readAsDataURL(blob);
});
}
class SiteSpecificBrowserChild extends JSWindowActorChild {
receiveMessage(message) {
switch (message.name) {
case "SetSSB":
// Note that this sets the webbrowserchrome for the top-level browser
// child in this page. This means that any inner-frames loading in
// different processes will not be handled correctly. Fixing this will
// happen in bug 1602849.
this.docShell.browserChild.webBrowserChrome = new WebBrowserChrome(
message.data
);
break;
case "LoadIcon":
return loadIcon(this.contentWindow, message.data);
}
return null;
}
}
function getActor(docShell) {
return docShell.domWindow.windowGlobalChild.getActor("SiteSpecificBrowser");
}
// JS actors can't generally be XPCOM objects so we must use a separate class.
class WebBrowserChrome {
constructor(id) {
this.id = id;
}
get ssb() {
return SiteSpecificBrowserBase.get(this.id);
}
// nsIWebBrowserChrome3
/**
* This gets called when a user clicks on a link or submits a form. We can use
* it to see where the resulting page load will occur and if needed redirect
* it to a different target.
*
* @param {string} originalTarget the target intended for the load.
* @param {nsIURI} linkURI the URI that will be loaded.
* @param {Node} linkNode the element causing the load.
* @param {boolean} isAppTab whether the source docshell is marked as an
* app tab.
* @return {string} the target to use for the load.
*/
onBeforeLinkTraversal(originalTarget, linkURI, linkNode, isAppTab) {
// Our actor is for the top-level frame in the page while this may be being
// called for a navigation in an inner frame. First we have to find the
// browsing context for the frame doing the load.
let docShell = linkNode.ownerGlobal.docShell;
let bc = docShell.browsingContext;
// Which browsing context is this link targetting?
let target = originalTarget ? bc.findWithName(originalTarget) : bc;
if (target) {
// If we found a target then it must be one of the frames within this
// frame tree since we don't support popup windows.
if (target.parent) {
// An inner frame, continue.
return originalTarget;
}
// A top-level load. If our SSB cannot load this URI then start the
// process of opening it into a new tab somewhere.
return this.ssb.canLoad(linkURI) ? originalTarget : "_blank";
}
// An attempt to open a new window/tab. If the new URI can be loaded by our
// SSB then load it at the top-level. Note that we override the requested
// target so that this page can't reach the new context.
return this.ssb.canLoad(linkURI) ? "_top" : "_blank";
}
/**
* A load is about to occur in a frame. This is an opportunity to stop it
* and redirect it somewhere.
*
* @param {nsIDocShell} docShell the current docshell.
* @param {nsIURI} uri the URI that will be loaded.
* @param {nsIReferrerInfo} referrerInfo the referrer info.
* @param {boolean} hasPostData whether there is POST data
* for the load.
* @param {nsIPrincipal} triggeringPrincipal the triggering principal.
* @param {nsIContentSecurityPolicy} csp the content security policy.
* @return {boolean} whether the load should proceed or not.
*/
shouldLoadURI(
docShell,
uri,
referrerInfo,
hasPostData,
triggeringPrincipal,
csp
) {
// As above, our actor is for the top-level frame in the page however we
// are passed the docshell potentially handling the load here so we can
// do the right thing.
// We only police loads at the top level.
if (docShell.browsingContext.parent) {
return true;
}
if (!this.ssb.canLoad(uri)) {
// Should only have got this far for a window.location manipulation.
getActor(docShell).sendAsyncMessage("RetargetOutOfScopeURIToBrowser", {
uri: uri.spec,
referrerInfo: E10SUtils.serializeReferrerInfo(referrerInfo),
triggeringPrincipal: E10SUtils.serializePrincipal(
triggeringPrincipal ||
Services.scriptSecurityManager.createNullPrincipal({})
),
csp: csp ? E10SUtils.serializeCSP(csp) : null,
});
return false;
}
return true;
}
/**
* A simple check for whether this is the correct process to load this URI.
*
* @param {nsIURI} uri the URI that will be loaded.
* @return {boolean} whether the load should proceed or not.
*/
shouldLoadURIInThisProcess(uri) {
return this.ssb.canLoad(uri);
}
}
/* vim: set ts=2 sw=2 sts=2 et tw=80: */
/* 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 = ["SiteSpecificBrowserParent"];
const { BrowserWindowTracker } = ChromeUtils.import(
"resource:///modules/BrowserWindowTracker.jsm"
);
const { E10SUtils } = ChromeUtils.import(
"resource://gre/modules/E10SUtils.jsm"
);
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
const { AppConstants } = ChromeUtils.import(
"resource://gre/modules/AppConstants.jsm"
);
class SiteSpecificBrowserParent extends JSWindowActorParent {
receiveMessage(message) {
switch (message.name) {
case "RetargetOutOfScopeURIToBrowser":
// The content process found a URI that needs to be loaded in the main
// browser.
let triggeringPrincipal = E10SUtils.deserializePrincipal(
message.data.triggeringPrincipal
);
let referrerInfo = E10SUtils.deserializeReferrerInfo(
message.data.referrerInfo
);
let csp = E10SUtils.deserializeCSP(message.data.csp);
// Attempt to find an existing window to open it in.
let win = BrowserWindowTracker.getTopWindow();
if (win) {
win.gBrowser.selectedTab = win.gBrowser.addTab(