author | Dave Townsend <dtownsend@oxymoronical.com> |
Fri, 15 Jan 2021 11:11:19 +0000 (2021-01-15) | |
changeset 563284 | 634e8801b8b6538dc9bdc43555185d68aa3f1886 |
parent 563283 | c92dc02122c7e7b87d630ac15d51e6d772216096 |
child 563285 | d5f4f4a54b905b2c5a56539579ace4f1f21cfb2c |
push id | 134268 |
push user | dtownsend@mozilla.com |
push date | Fri, 15 Jan 2021 14:03:11 +0000 (2021-01-15) |
treeherder | autoland@634e8801b8b6 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | Gijs |
bugs | 1682593 |
milestone | 86.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/browser/app/profile/firefox.js +++ b/browser/app/profile/firefox.js @@ -2025,19 +2025,16 @@ pref("app.normandy.shieldLearnMoreUrl", pref("app.normandy.last_seen_buildid", ""); pref("app.normandy.onsync_skew_sec", 600); #ifdef MOZ_DATA_REPORTING pref("app.shield.optoutstudies.enabled", true); #else 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); pref("intl.multilingual.downloadEnabled", true); #else pref("intl.multilingual.enabled", false); // AMO only serves language packs for release and beta versions. pref("intl.multilingual.downloadEnabled", false);
--- a/browser/base/content/browser-pageActions.js +++ b/browser/base/content/browser-pageActions.js @@ -1,19 +1,14 @@ /* 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/. */ ChromeUtils.defineModuleGetter( this, - "SiteSpecificBrowser", - "resource:///modules/SiteSpecificBrowserService.jsm" -); -ChromeUtils.defineModuleGetter( - this, "SearchUIUtils", "resource:///modules/SearchUIUtils.jsm" ); var BrowserPageActions = { _panelNode: null, /** * The main page action button in the urlbar (DOM node) @@ -1128,43 +1123,16 @@ BrowserPageActions.pinTab = { if (gBrowser.selectedTab.pinned) { gBrowser.unpinTab(gBrowser.selectedTab); } else { gBrowser.pinTab(gBrowser.selectedTab); } }, }; -// 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) { PanelMultiView.hidePopup(BrowserPageActions.panelNode); Cc["@mozilla.org/widget/clipboardhelper;1"] .getService(Ci.nsIClipboardHelper) .copyString( gURLBar.makeURIReadable(gBrowser.selectedBrowser.currentURI).displaySpec
--- a/browser/base/content/browser.js +++ b/browser/base/content/browser.js @@ -65,19 +65,16 @@ XPCOMUtils.defineLazyModuleGetters(this, SafeBrowsing: "resource://gre/modules/SafeBrowsing.jsm", Sanitizer: "resource:///modules/Sanitizer.jsm", SessionStartup: "resource:///modules/sessionstore/SessionStartup.jsm", SessionStore: "resource:///modules/sessionstore/SessionStore.jsm", ShortcutUtils: "resource://gre/modules/ShortcutUtils.jsm", 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", TelemetryEnvironment: "resource://gre/modules/TelemetryEnvironment.jsm", Translation: "resource:///modules/translation/TranslationParent.jsm", UITour: "resource:///modules/UITour.jsm", UpdateUtils: "resource://gre/modules/UpdateUtils.jsm", UrlbarInput: "resource:///modules/UrlbarInput.jsm", @@ -1925,18 +1922,16 @@ var gBrowserInit = { WebAuthnPromptHelper.init(); // Initialize the full zoom setting. // We do this before the session restore service gets initialized so we can // apply full zoom settings to tabs restored by the session restore service. FullZoom.init(); PanelUI.init(); - SiteSpecificBrowserUI.init(); - UpdateUrlbarSearchSplitterState(); BookmarkingUI.init(); BrowserSearch.delayedStartupInit(); gProtectionsHandler.init(); HomePage.delayedStartup().catch(Cu.reportError); let safeMode = document.getElementById("helpSafeMode"); @@ -2562,140 +2557,16 @@ XPCOMUtils.defineLazyGetter( "_firstContentWindowPaintDeferred", () => PromiseUtils.defer() ); 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": BrowserBack(); break; case "Forward": BrowserForward(); break;
--- a/browser/base/content/browser.xhtml +++ b/browser/base/content/browser.xhtml @@ -863,22 +863,16 @@ oncommand="LoginHelper.openPasswordManager(window, { entryPoint: 'mainmenu' })" /> <toolbarbutton id="appMenu-addons-button" class="subviewbutton subviewbutton-iconic" label="&addons.label;" 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 label="&preferencesCmd2.label;" #else label="&preferencesCmdUnix.label;" #ifdef XP_MACOSX key="key_preferencesCmdMac" @@ -1179,21 +1173,16 @@ <label id="PanelUI-panic-warning" data-l10n-id="panic-button-undo-warning"></label> </vbox> <button id="PanelUI-panic-view-button" data-l10n-id="panic-button-forget-button"/> </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" class="subviewbutton subviewbutton-iconic" label="&taskManagerCmd.label;" oncommand="switchToTabHavingURI('about:performance', true)"/> <toolbarbutton id="appMenu-characterencoding-button" class="subviewbutton subviewbutton-nav"
--- a/browser/components/BrowserGlue.jsm +++ b/browser/components/BrowserGlue.jsm @@ -686,27 +686,16 @@ let JSWINDOWACTORS = { SwitchDocumentDirection: { child: { moduleURI: "resource:///actors/SwitchDocumentDirectionChild.jsm", }, 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", }, child: { moduleURI: "resource:///modules/translation/TranslationChild.jsm", events: { pageshow: {},
--- a/browser/components/moz.build +++ b/browser/components/moz.build @@ -48,17 +48,16 @@ DIRS += [ "privatebrowsing", "prompts", "protections", "protocolhandler", "resistfingerprinting", "search", "sessionstore", "shell", - "ssb", "syncedtabs", "uitour", "urlbar", "translation", ] DIRS += ["build"]
deleted file mode 100644 --- a/browser/components/ssb/ImageTools.jsm +++ /dev/null @@ -1,137 +0,0 @@ -/* 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)); - } - }); - }); - }, -};
deleted file mode 100644 --- a/browser/components/ssb/SiteSpecificBrowserChild.jsm +++ /dev/null @@ -1,177 +0,0 @@ -/* 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); - } -}
deleted file mode 100644 --- a/browser/components/ssb/SiteSpecificBrowserParent.jsm +++ /dev/null @@ -1,75 +0,0 @@ -/* 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(message.data.uri, { - triggeringPrincipal, - csp, - referrerInfo, - }); - } else { - let sa = Cc["@mozilla.org/array;1"].createInstance( - Ci.nsIMutableArray - ); - - let wuri = Cc["@mozilla.org/supports-string;1"].createInstance( - Ci.nsISupportsString - ); - wuri.data = message.data.uri; - - sa.appendElement(wuri); - sa.appendElement(null); // unused (bug 871161) - sa.appendElement(referrerInfo); - sa.appendElement(null); // postData - sa.appendElement(null); // allowThirdPartyFixup - sa.appendElement(null); // userContextId - sa.appendElement(null); // originPrincipal - sa.appendElement(null); // originStoragePrincipal - sa.appendElement(triggeringPrincipal); - sa.appendElement(null); // allowInheritPrincipal - sa.appendElement(csp); - - Services.ww.openWindow( - null, - AppConstants.BROWSER_CHROME_URL, - null, - "chrome,dialog=no,all", - sa - ); - } - break; - } - } -}
deleted file mode 100644 --- a/browser/components/ssb/SiteSpecificBrowserService.jsm +++ /dev/null @@ -1,908 +0,0 @@ -/* 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/. */ - -/** - * A Site Specific Browser intends to allow the user to navigate through the - * chosen site in the SSB UI. Any attempt to load something outside the site - * should be loaded in a normal browser. In order to achieve this we have to use - * various APIs to listen for attempts to load new content and take appropriate - * action. Often this requires returning synchronous responses to method calls - * in content processes and will require data about the SSB in order to respond - * correctly. Here we implement an architecture to support that: - * - * In the main process the SiteSpecificBrowser class implements all the - * functionality involved with managing an SSB. All content processes can - * synchronously retrieve a matching SiteSpecificBrowserBase that has enough - * data about the SSB in order to be able to respond to load requests - * synchronously. To support this we give every SSB a unique ID (UUID based) - * and the appropriate data is shared via sharedData. Once created the ID can be - * used to retrieve the SiteSpecificBrowser instance in the main process or - * SiteSpecificBrowserBase instance in any content process. - */ - -var EXPORTED_SYMBOLS = [ - "SiteSpecificBrowserService", - "SiteSpecificBrowserBase", - "SiteSpecificBrowser", - "SSBCommandLineHandler", -]; - -const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm"); -const { XPCOMUtils } = ChromeUtils.import( - "resource://gre/modules/XPCOMUtils.jsm" -); - -XPCOMUtils.defineLazyModuleGetters(this, { - ManifestObtainer: "resource://gre/modules/ManifestObtainer.jsm", - ManifestProcessor: "resource://gre/modules/ManifestProcessor.jsm", - KeyValueService: "resource://gre/modules/kvstore.jsm", - OS: "resource://gre/modules/osfile.jsm", - ImageTools: "resource:///modules/ssb/ImageTools.jsm", - AppConstants: "resource://gre/modules/AppConstants.jsm", -}); - -if (AppConstants.platform == "win") { - ChromeUtils.defineModuleGetter( - this, - "WindowsSupport", - "resource:///modules/ssb/WindowsSupport.jsm" - ); -} - -/** - * A schema version for the SSB data stored in the kvstore. - * - * Version 1 has the `manifest` and `config` properties. - */ -const DATA_VERSION = 1; - -/** - * The prefix used for SSB ids in the store. - */ -const SSB_STORE_PREFIX = "ssb:"; - -/** - * A prefix that will sort immediately after any SSB ids in the store. - */ -const SSB_STORE_LAST = "ssb;"; - -function uuid() { - return Cc["@mozilla.org/uuid-generator;1"] - .getService(Ci.nsIUUIDGenerator) - .generateUUID() - .toString(); -} - -const sharedDataKey = id => `SiteSpecificBrowserBase:${id}`; -const storeKey = id => SSB_STORE_PREFIX + id; - -/** - * Builds a lookup table for all the icons in order of size. - */ -function buildIconList(icons) { - let iconList = []; - - for (let icon of icons) { - for (let sizeSpec of icon.sizes) { - let size = - sizeSpec == "any" ? Number.MAX_SAFE_INTEGER : parseInt(sizeSpec); - - iconList.push({ - icon, - size, - }); - } - } - - iconList.sort((a, b) => { - // Given that we're using MAX_SAFE_INTEGER adding a value to that would - // overflow and give odd behaviour. And we're using numbers supplied by a - // website so just compare for safety. - if (a.size < b.size) { - return -1; - } - - if (a.size > b.size) { - return 1; - } - - return 0; - }); - return iconList; -} - -const IS_MAIN_PROCESS = - Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_DEFAULT; - -/** - * Tests whether an app manifest's scope includes the given URI. - * - * @param {nsIURI} scope the manifest's scope. - * @param {nsIURI} uri the URI to test. - * @returns {boolean} true if the uri is included in the scope. - */ -function scopeIncludes(scope, uri) { - // https://w3c.github.io/manifest/#dfn-within-scope - if (scope.prePath != uri.prePath) { - return false; - } - - return uri.filePath.startsWith(scope.filePath); -} - -/** - * Generates a basic app manifest for a URI. - * - * @param {nsIURI} uri the start URI for the site. - * @return {Manifest} an app manifest. - */ -function manifestForURI(uri) { - try { - let manifestURI = Services.io.newURI("/manifest.json", null, uri); - return ManifestProcessor.process({ - jsonText: "{}", - manifestURL: manifestURI.spec, - docURL: uri.spec, - }); - } catch (e) { - console.error(`Failed to generate a SSB manifest for ${uri.spec}.`, e); - throw e; - } -} - -/** - * Creates an IconResource from the LinkHandler data. - * - * @param {object} iconData the data from the LinkHandler actor. - * @return {Promise<IconResource>} an icon resource. - */ -async function getIconResource(iconData) { - // This should be a data url so no network traffic. - let imageData = await ImageTools.loadImage( - Services.io.newURI(iconData.iconURL) - ); - if (imageData.container.type == Ci.imgIContainer.TYPE_VECTOR) { - return { - src: iconData.iconURL, - purpose: ["any"], - type: imageData.type, - sizes: ["any"], - }; - } - - // TODO: For ico files we should find all the available sizes: Bug 1604285. - - return { - src: iconData.iconURL, - purpose: ["any"], - type: imageData.type, - sizes: [`${imageData.container.width}x${imageData.container.height}`], - }; -} - -/** - * Generates an app manifest for a site loaded in a browser element. - * - * @param {Element} browser the browser element the site is loaded in. - * @return {Promise<Manifest>} an app manifest. - */ -async function buildManifestForBrowser(browser) { - let manifest = null; - try { - manifest = await ManifestObtainer.browserObtainManifest(browser); - } catch (e) { - // We can function without a valid manifest. - console.error(e); - } - - // Reject the manifest if its scope doesn't include the current document. - if ( - !manifest || - !scopeIncludes(Services.io.newURI(manifest.scope), browser.currentURI) - ) { - manifest = manifestForURI(browser.currentURI); - } - - // Cache all the icons as data URIs since we can need access to them when - // the website is not loaded. - manifest.icons = ( - await Promise.all( - manifest.icons.map(async icon => { - if (icon.src.startsWith("data:")) { - return icon; - } - - let actor = browser.browsingContext.currentWindowGlobal.getActor( - "SiteSpecificBrowser" - ); - try { - icon.src = await actor.sendQuery("LoadIcon", icon.src); - } catch (e) { - // Bad icon, drop it from the list. - return null; - } - - return icon; - }) - ) - ).filter(icon => icon); - - // If the site provided no icons then try to use the normal page icons. - if (!manifest.icons.length) { - let linkHandler = browser.browsingContext.currentWindowGlobal.getActor( - "LinkHandler" - ); - - for (let icon of [linkHandler.icon, linkHandler.richIcon]) { - if (!icon) { - continue; - } - - try { - manifest.icons.push(await getIconResource(icon)); - } catch (e) { - console.warn(`Failed to load icon resource ${icon.originalURL}`, e); - } - } - } - - return manifest; -} - -/** - * Maintains an ID -> SSB mapping in the main process. Content processes should - * use sharedData to get a SiteSpecificBrowserBase. - * - * We do not currently expire data from here so once created an SSB instance - * lives for the lifetime of the application. The expectation is that the - * numbers of different SSBs used will be low and the memory use will also - * be low. - */ -const SSBMap = new Map(); - -/** - * The base contains the data about an SSB instance needed in content processes. - * - * The only data needed currently is site's `scope` which is just a URI. - */ -class SiteSpecificBrowserBase { - /** - * Creates a new SiteSpecificBrowserBase. Generally should only be called by - * code within this module. - * - * @param {nsIURI} scope the scope for the SSB. - */ - constructor(scope) { - this._scope = scope; - } - - /** - * Gets the SiteSpecifcBrowserBase for an ID. If this is the main process this - * will instead return the SiteSpecificBrowser instance itself but generally - * don't call this from the main process. - * - * The returned object is not "live" and will not be updated with any - * configuration changes from the main process so do not cache this, get it - * when needed and then discard. - * - * @param {string} id the SSB ID. - * @return {SiteSpecificBrowserBase|null} the instance if it exists. - */ - static get(id) { - if (IS_MAIN_PROCESS) { - return SiteSpecificBrowser.get(id); - } - - let key = sharedDataKey(id); - if (!Services.cpmm.sharedData.has(key)) { - return null; - } - - let scope = Services.io.newURI(Services.cpmm.sharedData.get(key)); - return new SiteSpecificBrowserBase(scope); - } - - /** - * Checks whether the given URI is considered to be a part of this SSB or not. - * Any URIs that return false should be loaded in a normal browser. - * - * @param {nsIURI} uri the URI to check. - * @return {boolean} whether this SSB can load the URI. - */ - canLoad(uri) { - // Always allow loading about:blank as it is the initial page for iframes. - if (uri.spec == "about:blank") { - return true; - } - - return scopeIncludes(this._scope, uri); - } -} - -/** - * The SSB instance used in the main process. - * - * We maintain three pieces of data for an SSB: - * - * First is the string UUID for identification purposes. - * - * Second is an app manifest (https://w3c.github.io/manifest/). If the site does - * not provide one a basic one will be automatically generated. The intent is to - * never modify this such that it can be updated from the site when needed - * without blowing away any configuration changes a user might want to make to - * the SSB itself. - * - * Thirdly there is the SSB configuration. This includes internal data, user - * overrides for the app manifest and custom SSB extensions to the app manifest. - * - * We pass data based on these down to the SiteSpecificBrowserBase in this and - * other processes (via `_updateSharedData`). - */ -class SiteSpecificBrowser extends SiteSpecificBrowserBase { - /** - * Creates a new SiteSpecificBrowser. Generally should only be called by - * code within this module. - * - * @param {string} id the SSB's unique ID. - * @param {Manifest} manifest the app manifest for the SSB. - * @param {object?} config the SSB configuration settings. - */ - constructor(id, manifest, config = {}) { - if (!IS_MAIN_PROCESS) { - throw new Error( - "SiteSpecificBrowser instances are only available in the main process." - ); - } - - super(Services.io.newURI(manifest.scope)); - this._id = id; - this._manifest = manifest; - this._config = Object.assign( - { - needsUpdate: true, - persisted: false, - }, - config - ); - - // Cache the SSB for retrieval. - SSBMap.set(id, this); - - this._updateSharedData(); - } - - /** - * Loads the SiteSpecificBrowser for the given ID. - * - * @param {string} id the SSB's unique ID. - * @param {object?} data the data to deserialize from. Do not use externally. - * @return {Promise<SiteSpecificBrowser?>} the instance if it exists. - */ - static async load(id, data = null) { - if (!IS_MAIN_PROCESS) { - throw new Error( - "SiteSpecificBrowser instances are only available in the main process." - ); - } - - if (SSBMap.has(id)) { - return SSBMap.get(id); - } - - if (!data) { - let kvstore = await SiteSpecificBrowserService.getKVStore(); - data = await kvstore.get(storeKey(id), null); - } - - if (!data) { - return null; - } - - try { - let parsed = JSON.parse(data); - parsed.config.persisted = true; - return new SiteSpecificBrowser(id, parsed.manifest, parsed.config); - } catch (e) { - console.error(e); - } - - return null; - } - - /** - * Gets the SiteSpecifcBrowser for an ID. Can only be called from the main - * process. - * - * @param {string} id the SSB ID. - * @return {SiteSpecificBrowser|null} the instance if it exists. - */ - static get(id) { - if (!IS_MAIN_PROCESS) { - throw new Error( - "SiteSpecificBrowser instances are only available in the main process." - ); - } - - return SSBMap.get(id); - } - - /** - * Creates an SSB from a parsed app manifest. - * - * @param {Manifest} manifest the app manifest for the site. - * @return {Promise<SiteSpecificBrowser>} the generated SSB. - */ - static async createFromManifest(manifest) { - if (!SiteSpecificBrowserService.isEnabled) { - throw new Error("Site specific browsing is disabled."); - } - - if (!manifest.scope.startsWith("https:")) { - throw new Error( - "Site specific browsers can only be opened for secure sites." - ); - } - - return new SiteSpecificBrowser(uuid(), manifest, { needsUpdate: false }); - } - - /** - * Creates an SSB from a site loaded in a browser element. - * - * @param {Element} browser the browser element the site is loaded in. - * @return {Promise<SiteSpecificBrowser>} the generated SSB. - */ - static async createFromBrowser(browser) { - if (!SiteSpecificBrowserService.isEnabled) { - throw new Error("Site specific browsing is disabled."); - } - - if (!browser.currentURI.schemeIs("https")) { - throw new Error( - "Site specific browsers can only be opened for secure sites." - ); - } - - let manifest = await buildManifestForBrowser(browser); - let ssb = await SiteSpecificBrowser.createFromManifest(manifest); - - if (!manifest.name) { - ssb.name = browser.contentTitle; - } - return ssb; - } - - /** - * Creates an SSB from a sURI. - * - * @param {nsIURI} uri the uri to generate from. - * @return {SiteSpecificBrowser} the generated SSB. - */ - static createFromURI(uri) { - if (!SiteSpecificBrowserService.isEnabled) { - throw new Error("Site specific browsing is disabled."); - } - - if (!uri.schemeIs("https")) { - throw new Error( - "Site specific browsers can only be opened for secure sites." - ); - } - - return new SiteSpecificBrowser(uuid(), manifestForURI(uri)); - } - - /** - * Caches the data needed by content processes. - */ - _updateSharedData() { - Services.ppmm.sharedData.set(sharedDataKey(this.id), this._scope.spec); - Services.ppmm.sharedData.flush(); - } - - /** - * Persists the data to the store if needed. When a change in configuration - * has occured call this. - */ - async _maybeSave() { - // If this SSB is persisted then update it in the data store. - if (this._config.persisted) { - let data = { - manifest: this._manifest, - config: this._config, - }; - - let kvstore = await SiteSpecificBrowserService.getKVStore(); - await kvstore.put(storeKey(this.id), JSON.stringify(data)); - } - } - - /** - * Installs this SiteSpecificBrowser such that it exists for future instances - * of the application and will appear in lists of installed SSBs. - */ - async install() { - if (this._config.persisted) { - return; - } - - this._config.persisted = true; - await this._maybeSave(); - - if (AppConstants.platform == "win") { - await WindowsSupport.install(this); - } - - Services.obs.notifyObservers( - null, - "site-specific-browser-install", - this.id - ); - } - - /** - * Uninstalls this SiteSpecificBrowser. Undoes eveerything above. The SSB is - * still usable afterwards. - */ - async uninstall() { - if (!this._config.persisted) { - return; - } - - if (AppConstants.platform == "win") { - await WindowsSupport.uninstall(this); - } - - this._config.persisted = false; - let kvstore = await SiteSpecificBrowserService.getKVStore(); - await kvstore.delete(storeKey(this.id)); - - Services.obs.notifyObservers( - null, - "site-specific-browser-uninstall", - this.id - ); - } - - /** - * The SSB's ID. - */ - get id() { - return this._id; - } - - get name() { - if (this._config.name) { - return this._config.name; - } - - if (this._manifest.name) { - return this._manifest.name; - } - - return this.startURI.host; - } - - set name(val) { - this._config.name = val; - this._maybeSave(); - } - - /** - * The default URI to load. - */ - get startURI() { - return Services.io.newURI(this._manifest.start_url); - } - - /** - * Whether this SSB needs to be checked for an updated manifest. - */ - get needsUpdate() { - return this._config.needsUpdate; - } - - /** - * Gets the best icon for the requested size. It may not be the exact size - * requested. - * - * Finds the smallest icon that is larger than the requested size. If no such - * icon exists returns the largest icon available. Returns null only if there - * are no icons at all. - * - * @param {Number} size the size of the desired icon in pixels. - * @return {IconResource} the icon resource for the icon. - */ - getIcon(size) { - if (!this._iconSizes) { - this._iconSizes = buildIconList(this._manifest.icons); - } - - if (!this._iconSizes.length) { - return null; - } - - let i = 0; - while (i < this._iconSizes.length && this._iconSizes[i].size < size) { - i++; - } - - return i < this._iconSizes.length - ? this._iconSizes[i].icon - : this._iconSizes[this._iconSizes.length - 1].icon; - } - - /** - * Gets the best icon for the requested size. If there isn't a perfect match - * the closest match will be scaled. - * - * @param {Number} size the size of the desired icon in pixels. - * @return {string|null} a data URI for the icon. - */ - async getScaledIcon(size) { - let icon = this.getIcon(size); - if (!icon) { - return null; - } - - let { container } = await ImageTools.loadImage( - Services.io.newURI(icon.src) - ); - return ImageTools.scaleImage(container, size, size); - } - - /** - * Updates this SSB from a new app manifest. - * - * @param {Manifest} manifest the new app manifest. - */ - async updateFromManifest(manifest) { - this._manifest = manifest; - this._iconSizes = null; - this._scope = Services.io.newURI(this._manifest.scope); - this._config.needsUpdate = false; - - this._updateSharedData(); - await this._maybeSave(); - } - - /** - * Updates this SSB from the site loaded in the browser element. - * - * @param {Element} browser the browser element. - */ - async updateFromBrowser(browser) { - let manifest = await buildManifestForBrowser(browser); - await this.updateFromManifest(manifest); - } - - /** - * Launches a SSB by opening the necessary UI. - * - * @param {nsIURI?} the initial URI to load. If not provided uses the default. - */ - launch(uri = null) { - let sa = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray); - - let idstr = Cc["@mozilla.org/supports-string;1"].createInstance( - Ci.nsISupportsString - ); - idstr.data = this.id; - sa.appendElement(idstr); - - if (uri) { - let uristr = Cc["@mozilla.org/supports-string;1"].createInstance( - Ci.nsISupportsString - ); - uristr.data = uri.spec; - sa.appendElement(uristr); - } - - let win = Services.ww.openWindow( - null, - "chrome://browser/content/ssb/ssb.html", - "_blank", - "chrome,dialog=no,all", - sa - ); - - if (Services.appinfo.OS == "WINNT") { - WindowsSupport.applyOSIntegration(this, win); - } - } -} - -/** - * Loads the KV store for SSBs. Should always resolve with a store even if that - * means wiping whatever is currently on disk because it was unreadable. - */ -async function loadKVStore() { - let dir = OS.Path.join(OS.Constants.Path.profileDir, "ssb"); - - /** - * Creates an empty store. Called when we know there is an empty directory. - */ - async function createStore() { - await OS.File.makeDir(dir); - let kvstore = await KeyValueService.getOrCreate(dir, "ssb"); - await kvstore.put( - "_meta", - JSON.stringify({ - version: DATA_VERSION, - }) - ); - - return kvstore; - } - - // First see if anything exists. - try { - let info = await OS.File.stat(dir); - - if (!info.isDir) { - await OS.File.remove(dir, { ignoreAbsent: true }); - return createStore(); - } - } catch (e) { - if (e.becauseNoSuchFile) { - return createStore(); - } - throw e; - } - - // Something exists, try to load it. - try { - let kvstore = await KeyValueService.getOrCreate(dir, "ssb"); - - let meta = await kvstore.get("_meta", null); - if (meta) { - let data = JSON.parse(meta); - if (data.version == DATA_VERSION) { - return kvstore; - } - console.error(`SSB store is an unexpected version ${data.version}`); - } else { - console.error("SSB store was missing meta data."); - } - - // We don't know how to handle this database, re-initialize it. - await kvstore.clear(); - await kvstore.put( - "_meta", - JSON.stringify({ - version: DATA_VERSION, - }) - ); - - return kvstore; - } catch (e) { - console.error(e); - - // Something is very wrong. Wipe all our data and start again. - await OS.File.removeDir(dir); - return createStore(); - } -} - -const SiteSpecificBrowserService = { - kvstore: null, - - /** - * Returns a promise that resolves to the KV store for SSBs. - */ - getKVStore() { - if (!this.kvstore) { - this.kvstore = loadKVStore(); - } - - return this.kvstore; - }, - - /** - * Checks if OS integration is enabled. This will affect whether installs and - * uninstalls have effects on the OS itself amongst other things. Generally - * only disabled for testing. - */ - get useOSIntegration() { - if (Services.appinfo.OS != "WINNT") { - return false; - } - - return Services.prefs.getBoolPref("browser.ssb.osintegration", true); - }, - - /** - * Returns a promise that resolves to an array of all of the installed SSBs. - */ - async list() { - let kvstore = await this.getKVStore(); - let list = await kvstore.enumerate(SSB_STORE_PREFIX, SSB_STORE_LAST); - return Promise.all( - Array.from(list).map(({ key: id, value: data }) => - SiteSpecificBrowser.load(id.substring(SSB_STORE_PREFIX.length), data) - ) - ); - }, -}; - -XPCOMUtils.defineLazyPreferenceGetter( - SiteSpecificBrowserService, - "isEnabled", - "browser.ssb.enabled", - false -); - -async function startSSB(id) { - // Loading the SSB is async. Until that completes and launches we will - // be without an open window and the platform will not continue startup - // in that case. Flag that a window is coming. - Services.startup.enterLastWindowClosingSurvivalArea(); - - // Whatever happens we must exitLastWindowClosingSurvivalArea when done. - try { - let ssb = await SiteSpecificBrowser.load(id); - if (ssb) { - ssb.launch(); - } else { - dump(`No SSB installed as ID ${id}\n`); - } - } finally { - Services.startup.exitLastWindowClosingSurvivalArea(); - } -} - -class SSBCommandLineHandler { - /* nsICommandLineHandler */ - handle(cmdLine) { - if (!SiteSpecificBrowserService.isEnabled) { - return; - } - - let site = cmdLine.handleFlagWithParam("ssb", false); - if (site) { - cmdLine.preventDefault = true; - - try { - let fixupInfo = Services.uriFixup.getFixupURIInfo( - site, - Services.uriFixup.FIXUP_FLAG_FIX_SCHEME_TYPOS - ); - - let uri = fixupInfo.preferredURI; - if (!uri) { - dump(`Unable to parse '${site}' as a URI.\n`); - return; - } - - if (fixupInfo.fixupChangedProtocol && uri.schemeIs("http")) { - uri = uri - .mutate() - .setScheme("https") - .finalize(); - } - let ssb = SiteSpecificBrowser.createFromURI(uri); - ssb.launch(); - } catch (e) { - dump(`Unable to parse '${site}' as a URI: ${e}\n`); - } - - return; - } - - let id = cmdLine.handleFlagWithParam("start-ssb", false); - if (id) { - cmdLine.preventDefault = true; - - startSSB(id); - } - } - - get helpInfo() { - return " --ssb <uri> Open a site specific browser for <uri>.\n"; - } -} - -SSBCommandLineHandler.prototype.QueryInterface = ChromeUtils.generateQI([ - "nsICommandLineHandler", -]);
deleted file mode 100644 --- a/browser/components/ssb/WindowsSupport.jsm +++ /dev/null @@ -1,160 +0,0 @@ -/* 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 = ["WindowsSupport"]; - -const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm"); -const { XPCOMUtils } = ChromeUtils.import( - "resource://gre/modules/XPCOMUtils.jsm" -); -const { SiteSpecificBrowserService } = ChromeUtils.import( - "resource:///modules/SiteSpecificBrowserService.jsm" -); - -XPCOMUtils.defineLazyModuleGetters(this, { - OS: "resource://gre/modules/osfile.jsm", - ImageTools: "resource:///modules/ssb/ImageTools.jsm", -}); - -const shellService = Cc["@mozilla.org/browser/shell-service;1"].getService( - Ci.nsIWindowsShellService -); - -const uiUtils = Cc["@mozilla.org/windows-ui-utils;1"].getService( - Ci.nsIWindowsUIUtils -); - -const taskbar = Cc["@mozilla.org/windows-taskbar;1"].getService( - Ci.nsIWinTaskbar -); - -const File = Components.Constructor( - "@mozilla.org/file/local;1", - Ci.nsIFile, - "initWithPath" -); - -function buildGroupId(id) { - try { - return `${taskbar.defaultGroupId}.ssb.${id}`; - } catch (e) { - return `Firefox.ssb.${id}`; - } -} - -const WindowsSupport = { - /** - * Installs an SSB by creating a shortcut to launch it on the user's desktop. - * - * @param {SiteSpecificBrowser} ssb the SSB to install. - */ - async install(ssb) { - if (!SiteSpecificBrowserService.useOSIntegration) { - return; - } - - let dir = OS.Path.join(OS.Constants.Path.profileDir, "ssb", ssb.id); - await OS.File.makeDir(dir, { - from: OS.Constants.Path.profileDir, - ignoreExisting: true, - }); - - let iconFile = new File(OS.Path.join(dir, "icon.ico")); - - // We should be embedding multiple icon sizes, but the current icon encoder - // does not support this. For now just embed a sensible size. - let icon = ssb.getIcon(128); - if (icon) { - let { container } = await ImageTools.loadImage( - Services.io.newURI(icon.src) - ); - ImageTools.saveIcon(container, 128, 128, iconFile); - } else { - // TODO use a default icon file. - iconFile = null; - } - - let desktop = Services.dirsvc.get("Desk", Ci.nsIFile); - let link = OS.Path.join(desktop.path, `${ssb.name}.lnk`); - - shellService.createShortcut( - Services.dirsvc.get("XREExeF", Ci.nsIFile), - ["-profile", OS.Constants.Path.profileDir, "-start-ssb", ssb.id], - ssb.name, - iconFile, - buildGroupId(ssb.id), - new File(link) - ); - }, - - /** - * Uninstalls an SSB by deleting its shortcut from the user's desktop. - * - * @param {SiteSpecificBrowser} ssb the SSB to uninstall. - */ - async uninstall(ssb) { - if (!SiteSpecificBrowserService.useOSIntegration) { - return; - } - - let desktop = Services.dirsvc.get("Desk", Ci.nsIFile); - let link = OS.Path.join(desktop.path, `${ssb.name}.lnk`); - - try { - await OS.File.remove(link); - } catch (e) { - console.error(e); - } - - let dir = OS.Path.join(OS.Constants.Path.profileDir, "ssb", ssb.id); - try { - await OS.File.removeDir(dir, { - ignoreAbsent: true, - ignorePermissions: true, - }); - } catch (e) { - console.error(e); - } - }, - - /** - * Applies the necessary OS integration to an open SSB. - * - * Sets the window icon based on the available icons. - * - * @param {SiteSpecificBrowser} ssb the SSB. - * @param {DOMWindow} window the window showing the SSB. - */ - async applyOSIntegration(ssb, window) { - const getIcon = async size => { - let icon = ssb.getIcon(size); - if (!icon) { - return null; - } - - try { - let image = await ImageTools.loadImage(Services.io.newURI(icon.src)); - return image.container; - } catch (e) { - console.error(e); - return null; - } - }; - - if (!SiteSpecificBrowserService.useOSIntegration) { - return; - } - - let icons = await Promise.all([ - getIcon(uiUtils.systemSmallIconSize), - getIcon(uiUtils.systemLargeIconSize), - ]); - - if (icons[0] || icons[1]) { - uiUtils.setWindowIcon(window, icons[0], icons[1]); - } - - taskbar.setGroupIdForWindow(window, buildGroupId(ssb.id)); - }, -};
deleted file mode 100644 --- a/browser/components/ssb/components.conf +++ /dev/null @@ -1,19 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# 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/. - -Classes = [ - { - 'cid': '{6344f783-c893-4db8-91ec-7d43a46bd6f4}', - 'contract_ids': [ - '@mozilla.org/browser/ssb/clh;1', - ], - 'jsm': 'resource:///modules/SiteSpecificBrowserService.jsm', - 'constructor': 'SSBCommandLineHandler', - 'categories': { - 'command-line-handler': 'e-ssb', - }, - }, -]
deleted file mode 100644 --- a/browser/components/ssb/content/jar.mn +++ /dev/null @@ -1,8 +0,0 @@ -# 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/. - -browser.jar: - content/browser/ssb/ssb.html - content/browser/ssb/ssb.js - content/browser/ssb/ssb.css
deleted file mode 100644 --- a/browser/components/ssb/content/ssb.css +++ /dev/null @@ -1,14 +0,0 @@ -/* 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/. */ - -html, -body, -#browser-container, -#browser { - width: 100%; - height: 100%; - margin: 0; - padding: 0; - overflow: hidden; -}
deleted file mode 100644 --- a/browser/components/ssb/content/ssb.html +++ /dev/null @@ -1,17 +0,0 @@ -<!-- 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/. --> - -<!DOCTYPE html> - -<html width="800" height="600"> -<head> -<link rel="stylesheet" href="chrome://global/skin/global.css"> -<link rel="stylesheet" href="ssb.css"> -<title id="title"></title> -</head> -<body> - <div id="browser-container"></div> - <script type="text/javascript" src="ssb.js"></script> -</body> -</html>
deleted file mode 100644 --- a/browser/components/ssb/content/ssb.js +++ /dev/null @@ -1,269 +0,0 @@ -/* 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/. */ - -const { XPCOMUtils } = ChromeUtils.import( - "resource://gre/modules/XPCOMUtils.jsm" -); - -XPCOMUtils.defineLazyModuleGetters(this, { - BrowserUtils: "resource://gre/modules/BrowserUtils.jsm", - Services: "resource://gre/modules/Services.jsm", - SiteSpecificBrowser: "resource:///modules/SiteSpecificBrowserService.jsm", - BrowserWindowTracker: "resource:///modules/BrowserWindowTracker.jsm", - WindowsSupport: "resource:///modules/ssb/WindowsSupport.jsm", -}); - -XPCOMUtils.defineLazyScriptGetter( - this, - "PrintUtils", - "chrome://global/content/printUtils.js" -); - -let gSSBBrowser = null; -var gSSB = null; - -function init() { - gSSB = SiteSpecificBrowser.get(window.arguments[0]); - - let uri = gSSB.startURI; - if (window.arguments.length > 1) { - uri = Services.io.newURI(window.arguments[1]); - } - - window.browserDOMWindow = new BrowserDOMWindow(); - - gSSBBrowser = document.createXULElement("browser"); - gSSBBrowser.setAttribute("id", "browser"); - gSSBBrowser.setAttribute("type", "content"); - gSSBBrowser.setAttribute("remote", "true"); - gSSBBrowser.setAttribute("nodefaultsrc", "true"); - document.getElementById("browser-container").appendChild(gSSBBrowser); - - // Give our actor the SSB's ID. - let actor = gSSBBrowser.browsingContext.currentWindowGlobal.getActor( - "SiteSpecificBrowser" - ); - actor.sendAsyncMessage("SetSSB", gSSB.id); - - gSSBBrowser.addProgressListener( - new ProgressListener(), - Ci.nsIWebProgress.NOTIFY_STATE_ALL - ); - gSSBBrowser.src = uri.spec; - - document.getElementById("title").textContent = gSSB.name; -} - -class ProgressListener { - constructor() { - this.isInitial = true; - } - - /** - * Called when the load state changes - * - * @param {nsIWebProgress} webProgress - * @param {nsIRequest} request - * @param {Number} state - * @param {Number} status - */ - async onStateChange(webProgress, request, state, status) { - if (!webProgress.isTopLevel) { - return; - } - - let final = - Ci.nsIWebProgressListener.STATE_IS_WINDOW + - Ci.nsIWebProgressListener.STATE_STOP; - if ((state & final) != final) { - return; - } - - // Load complete. Does the SSB need an update? - let { isInitial } = this; - this.isInitial = false; - if (isInitial && gSSB.needsUpdate) { - await gSSB.updateFromBrowser(gSSBBrowser); - if (Services.appinfo.OS == "WINNT") { - WindowsSupport.applyOSIntegration(gSSB, window); - } - } - - // So the testing harness knows when the ssb is properly initialized. - let event = new CustomEvent("SSBLoad"); - gSSBBrowser.dispatchEvent(event); - } -} - -ProgressListener.prototype.QueryInterface = ChromeUtils.generateQI([ - "nsIWebProgressListener", - "nsISupportsWeakReference", -]); - -class BrowserDOMWindow { - /** - * Called when a page in the main process needs a new window to display a new - * page in. - * - * @param {nsIURI?} uri - * @param {nsIOpenWindowInfo} openWindowInfo - * @param {Number} where - * @param {Number} flags - * @param {nsIPrincipal} triggeringPrincipal - * @param {nsIContentSecurityPolicy?} csp - * @return {BrowsingContext} the BrowsingContext the URI should be loaded in. - */ - createContentWindow( - uri, - openWindowInfo, - where, - flags, - triggeringPrincipal, - csp - ) { - console.error( - "createContentWindow should never be called from a remote browser" - ); - throw Components.Exception("", Cr.NS_ERROR_FAILURE); - } - - /** - * Called from a page in the main process to open a new URI. - * - * @param {nsIURI} uri - * @param {nsIOpenWindowInfo} openWindowInfo - * @param {Number} where - * @param {Number} flags - * @param {nsIPrincipal} triggeringPrincipal - * @param {nsIContentSecurityPolicy?} csp - * @return {BrowsingContext} the BrowsingContext the URI should be loaded in. - */ - openURI(uri, openWindowInfo, where, flags, triggeringPrincipal, csp) { - console.error("openURI should never be called from a remote browser"); - throw Components.Exception("", Cr.NS_ERROR_FAILURE); - } - - /** - * Finds a new frame to load some content in. - * - * @param {nsIURI?} uri - * @param {nsIOpenURIInFrameParams} params - * @param {Number} where - * @param {Number} flags - * @param {string} name - * @param {boolean} shouldOpen should the load start or not. - * @return {Element} the frame element the URI should be loaded in. - */ - getContentWindowOrOpenURIInFrame( - uri, - params, - where, - flags, - name, - shouldOpen - ) { - // It's been determined that this load needs to happen in a new frame. - // Either onBeforeLinkTraversal set this correctly or this is the result - // of a window.open call. - if (where == Ci.nsIBrowserDOMWindow.OPEN_PRINT_BROWSER) { - return PrintUtils.startPrintWindow( - "window_print", - params.openWindowInfo.parent, - { openWindowInfo: params.openWindowInfo } - ); - } - - // If this ssb can load the url then just load it internally. - if (gSSB.canLoad(uri)) { - return gSSBBrowser; - } - - // Try and find a browser window to open in. - let win = BrowserWindowTracker.getTopWindow({ - private: params.isPrivate, - allowPopups: false, - }); - - if (win) { - // Just hand off to the window's handler - win.focus(); - return win.browserDOMWindow.openURIInFrame( - shouldOpen ? uri : null, - params, - where, - flags, - name - ); - } - - // We need to open a new browser window and a tab in it. That's an - // asychronous operation but luckily if we return null here the platform - // handles doing that for us. - return null; - } - - /** - * Gets an nsFrameLoaderOwner to load some new content in. - * - * @param {nsIURI?} uri - * @param {nsIOpenURIInFrameParams} params - * @param {Number} where - * @param {Number} flags - * @param {string} name - * @return {Element} the frame element the URI should be loaded in. - */ - createContentWindowInFrame(uri, params, where, flags, name) { - return this.getContentWindowOrOpenURIInFrame( - uri, - params, - where, - flags, - name, - false - ); - } - - /** - * Create a new nsFrameLoaderOwner and load some content into it. - * - * @param {nsIURI} uri - * @param {nsIOpenURIInFrameParams} params - * @param {Number} where - * @param {Number} flags - * @param {string} name - * @return {Element} the frame element the URI is loading in. - */ - openURIInFrame(uri, params, where, flags, name) { - return this.getContentWindowOrOpenURIInFrame( - uri, - params, - where, - flags, - name, - true - ); - } - - canClose() { - /* globals docShell */ - for (let i = 0; i < docShell.childCount; i++) { - let childShell = docShell.getChildAt(i).QueryInterface(Ci.nsIDocShell); - let { contentViewer } = childShell; - if (contentViewer && !contentViewer.permitUnload()) { - return false; - } - } - return true; - } - - get tabCount() { - return 1; - } -} - -BrowserDOMWindow.prototype.QueryInterface = ChromeUtils.generateQI([ - "nsIBrowserDOMWindow", -]); - -window.addEventListener("DOMContentLoaded", init, true);
deleted file mode 100644 --- a/browser/components/ssb/moz.build +++ /dev/null @@ -1,31 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# 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/. - -JAR_MANIFESTS += ["content/jar.mn"] -BROWSER_CHROME_MANIFESTS += ["tests/browser/browser.ini"] -XPCSHELL_TESTS_MANIFESTS += ["tests/xpcshell/xpcshell.ini"] - -XPCOM_MANIFESTS += [ - "components.conf", -] - -EXTRA_JS_MODULES += [ - "SiteSpecificBrowserService.jsm", -] - -EXTRA_JS_MODULES.ssb += [ - "ImageTools.jsm", -] - -FINAL_TARGET_FILES.actors += [ - "SiteSpecificBrowserChild.jsm", - "SiteSpecificBrowserParent.jsm", -] - -if CONFIG["MOZ_WIDGET_TOOLKIT"] == "windows": - EXTRA_JS_MODULES.ssb += [ - "WindowsSupport.jsm", - ]
deleted file mode 100644 --- a/browser/components/ssb/tests/browser/browser.ini +++ /dev/null @@ -1,24 +0,0 @@ -[DEFAULT] -support-files = - head.js - test_page.html - empty_page.html -prefs = - dom.manfiest.enabled=true - browser.ssb.enabled=true - browser.ssb.osintegration=false - -[browser_ssb_direct.js] -[browser_ssb_lasttab.js] -[browser_ssb_list_menu.js] -[browser_ssb_manifest_scope.js] -support-files = - site1/* - site2/* -[browser_ssb_menu.js] -[browser_ssb_newtab.js] -[browser_ssb_newwindow.js] -[browser_ssb_open.js] -[browser_ssb_windowlocation.js] -[browser_ssb_windowopen.js] -skip-if = true # It is unclear what we want to do here.
deleted file mode 100644 --- a/browser/components/ssb/tests/browser/browser_ssb_direct.js +++ /dev/null @@ -1,66 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -async function testDirectLoad(target, checker) { - let ssb = await openSSB(gHttpsTestRoot + "test_page.html#" + target); - - let promise = checker(ssb); - await BrowserTestUtils.synthesizeMouseAtCenter( - "#direct", - {}, - getBrowser(ssb) - ); - - await promise; - await BrowserTestUtils.closeWindow(ssb); -} - -// A link that should load inside the ssb -add_task(async function local() { - await testDirectLoad(gHttpsTestRoot + "empty_page.html", async ssb => { - try { - await expectSSBLoad(ssb); - Assert.equal( - getBrowser(ssb).currentURI.spec, - gHttpsTestRoot + "empty_page.html", - "Should have loaded the right uri." - ); - } catch (e) { - // Any error will already have logged a failure. - } - }); -}); - -// A link to an insecure site should load outside the ssb -add_task(async function insecure() { - await testDirectLoad(gHttpTestRoot + "empty_page.html", async ssb => { - try { - let tab = await expectTabLoad(ssb); - Assert.equal( - tab.linkedBrowser.currentURI.spec, - gHttpTestRoot + "empty_page.html", - "Should have loaded the right uri." - ); - BrowserTestUtils.removeTab(tab); - } catch (e) { - // Any error will already have logged a failure. - } - }); -}); - -// A link to a different host should load outside the ssb -add_task(async function external() { - await testDirectLoad(gHttpsOtherRoot + "empty_page.html", async ssb => { - try { - let tab = await expectTabLoad(ssb); - Assert.equal( - tab.linkedBrowser.currentURI.spec, - gHttpsOtherRoot + "empty_page.html", - "Should have loaded the right uri." - ); - BrowserTestUtils.removeTab(tab); - } catch (e) { - // Any error will already have logged a failure. - } - }); -});
deleted file mode 100644 --- a/browser/components/ssb/tests/browser/browser_ssb_lasttab.js +++ /dev/null @@ -1,39 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -// Opening from the last browser tab should not close the window. -add_task(async () => { - let win = await BrowserTestUtils.openNewBrowserWindow(); - - let windowClosed = false; - BrowserTestUtils.windowClosed(win).then(() => { - windowClosed = true; - }); - - Assert.equal(win.gBrowser.tabs.length, 1, "Should be only one tab."); - let tab = win.gBrowser.selectedTab; - - BrowserTestUtils.loadURI( - win.gBrowser.selectedBrowser, - gHttpsTestRoot + "test_page.html" - ); - await BrowserTestUtils.browserLoaded( - win.gBrowser.selectedBrowser, - true, - gHttpsTestRoot + "test_page.html" - ); - - let ssbwin = await openSSBFromBrowserWindow(win); - Assert.equal(win.gBrowser.tabs.length, 1, "Should still be only one tab."); - Assert.notEqual(tab, win.gBrowser.selectedTab, "Should be a new tab."); - Assert.equal( - getBrowser(ssbwin).currentURI.spec, - gHttpsTestRoot + "test_page.html" - ); - - await getSSB(ssbwin).uninstall(); - - Assert.ok(!windowClosed, "Should not have seen the window close."); - await BrowserTestUtils.closeWindow(ssbwin); - await BrowserTestUtils.closeWindow(win); -});
deleted file mode 100644 --- a/browser/components/ssb/tests/browser/browser_ssb_list_menu.js +++ /dev/null @@ -1,98 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -// Check that the menu is updated correctly and can be used to launch an ssb. -add_task(async () => { - let win = await BrowserTestUtils.openNewBrowserWindow(); - - let button = win.document.getElementById("appMenu-ssb-button"); - - Assert.equal(button, null, "Button should be not be available."); - Assert.equal( - win.document.querySelector("#appMenu-SSBView .panel-subview-body"), - null, - "Panel should not be available" - ); - - let ssb = await SiteSpecificBrowser.createFromURI( - Services.io.newURI(gHttpsTestRoot) - ); - - button = win.document.getElementById("appMenu-ssb-button"); - Assert.equal(button, null, "Button should be not be available."); - Assert.equal( - win.document.querySelector("#appMenu-SSBView .panel-subview-body"), - null, - "Panel should not be available" - ); - - await ssb.install(); - - button = win.document.getElementById("appMenu-ssb-button"); - // Button should still be unavailable, we don't populate the list until it is - // first opened. - Assert.equal(button, null, "Button should be not be available."); - Assert.equal( - win.document.querySelector("#appMenu-SSBView .panel-subview-body"), - null, - "Panel should not be available" - ); - - let appMenuOpened = BrowserTestUtils.waitForEvent( - win.document.getElementById("appMenu-popup"), - "popupshown" - ); - - EventUtils.synthesizeMouseAtCenter( - win.document.getElementById("PanelUI-menu-button"), - {}, - win - ); - await appMenuOpened; - - button = win.document.getElementById("appMenu-ssb-button"); - await BrowserTestUtils.waitForAttributeRemoval("hidden", button); - - Assert.ok(!button.hidden, "Button should be visible."); - - EventUtils.synthesizeMouseAtCenter( - win.document.getElementById("appMenu-ssb-button"), - {}, - win - ); - - let panelShown = BrowserTestUtils.waitForEvent( - win.document.getElementById("appMenu-SSBView"), - "ViewShown" - ); - let panel = win.document.querySelector( - "#appMenu-SSBView .panel-subview-body" - ); - await panelShown; - - Assert.notEqual( - panel.firstElementChild, - null, - "Should be something in the list." - ); - Assert.equal( - panel.firstElementChild.id, - "ssb-button-" + ssb.id, - "Should have the right ID." - ); - - let ssbOpened = waitForSSB(); - EventUtils.synthesizeMouseAtCenter(panel.firstElementChild, {}, win); - let ssbWin = await ssbOpened; - - Assert.equal(getBrowser(ssbWin).currentURI.spec, gHttpsTestRoot); - await BrowserTestUtils.closeWindow(ssbWin); - - await ssb.uninstall(); - - // Menu will be dynamically updating at this point. - Assert.ok(button.hidden, "Should be no installs."); - Assert.equal(panel.firstElementChild, null, "Should be nothing in the list."); - - await BrowserTestUtils.closeWindow(win); -});
deleted file mode 100644 --- a/browser/components/ssb/tests/browser/browser_ssb_manifest_scope.js +++ /dev/null @@ -1,83 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -// Enable web manifest processing. -Services.prefs.setBoolPref("dom.manifest.enabled", true); - -// Check that a site's manifest affects the scope of a ssb. - -function build_task(page, linkId, external, preload) { - let expectedTarget = linkId + "/final.html"; - - add_task(async () => { - let ssbwin; - - info(`Loading ${page} (${preload})`); - if (preload) { - // Loading via a browser will initialize the SSB with the correct manifest. - await BrowserTestUtils.openNewForegroundTab({ - gBrowser, - url: gHttpsTestRoot + page, - }); - - ssbwin = await openSSBFromBrowserWindow(); - } else { - // The manifest will be loaded once the initial page loads. - ssbwin = await openSSB(gHttpsTestRoot + page); - } - - let promise; - if (external) { - promise = expectTabLoad(ssbwin).then(tab => { - Assert.equal( - tab.linkedBrowser.currentURI.spec, - gHttpsTestRoot + expectedTarget, - "Should have loaded the right uri." - ); - BrowserTestUtils.removeTab(tab); - }); - } else { - promise = expectSSBLoad(ssbwin).then(() => { - Assert.equal( - getBrowser(ssbwin).currentURI.spec, - gHttpsTestRoot + expectedTarget, - "Should have loaded the right uri." - ); - }); - } - - info(`Clicking #${linkId}`); - await BrowserTestUtils.synthesizeMouseAtCenter( - `#${linkId}`, - {}, - getBrowser(ssbwin) - ); - - await promise; - await getSSB(ssbwin).uninstall(); - await BrowserTestUtils.closeWindow(ssbwin); - }); -} - -function make_all_tasks(preload) { - /** - * Arguments are: - * - * * Page to load. - * * Link ID to click in the page. - * * Is that link expected to point to an external site (i.e. should be retargeted). - * * true to create the SSB from a loaded browser, false to create it from a URL. - * The latter implies that the manifest won't initially be available. - */ - build_task("site1/simple.html", "site1", false, preload); - build_task("site1/simple.html", "site2", true, preload); - build_task("site1/empty.html", "site1", false, preload); - build_task("site1/empty.html", "site2", true, preload); - build_task("site1/allhost.html", "site1", false, preload); - build_task("site1/allhost.html", "site2", false, preload); - build_task("site1/bad.html", "site1", false, preload); - build_task("site1/bad.html", "site2", true, preload); -} - -make_all_tasks(true); -make_all_tasks(false);
deleted file mode 100644 --- a/browser/components/ssb/tests/browser/browser_ssb_menu.js +++ /dev/null @@ -1,38 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -// Check that it is correctly enabled/disabled based on the displaying page. -add_task(async () => { - let tab = await BrowserTestUtils.openNewForegroundTab({ - gBrowser, - url: gHttpTestRoot + "test_page.html", - }); - - // Must open the panel before the item gets added. - let pageActionButton = document.getElementById("pageActionButton"); - let panel = document.getElementById("pageActionPanel"); - let popupShown = BrowserTestUtils.waitForEvent(panel, "popupshown"); - - EventUtils.synthesizeMouseAtCenter(pageActionButton, {}, window); - await popupShown; - - let popupHidden = BrowserTestUtils.waitForEvent(panel, "popuphidden"); - panel.hidePopup(); - await popupHidden; - - Assert.ok( - document.getElementById("pageAction-panel-launchSSB").disabled, - "Menu should be disabled for a http: page." - ); - - let uri = gHttpsTestRoot + "test_page.html"; - BrowserTestUtils.loadURI(tab.linkedBrowser, uri); - await BrowserTestUtils.browserLoaded(tab.linkedBrowser, true, uri); - - Assert.ok( - !document.getElementById("pageAction-panel-launchSSB").disabled, - "Menu should not be disabled for a https: page." - ); - - BrowserTestUtils.removeTab(tab); -});
deleted file mode 100644 --- a/browser/components/ssb/tests/browser/browser_ssb_newtab.js +++ /dev/null @@ -1,66 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -async function testNewTabLoad(target, checker) { - let ssb = await openSSB(gHttpsTestRoot + "test_page.html#" + target); - - let promise = checker(ssb); - await BrowserTestUtils.synthesizeMouseAtCenter( - "#new-tab", - {}, - getBrowser(ssb) - ); - - await promise; - await BrowserTestUtils.closeWindow(ssb); -} - -// A link that should load inside the ssb -add_task(async function local() { - await testNewTabLoad(gHttpsTestRoot + "empty_page.html", async ssb => { - try { - await expectSSBLoad(ssb); - Assert.equal( - getBrowser(ssb).currentURI.spec, - gHttpsTestRoot + "empty_page.html", - "Should have loaded the right uri." - ); - } catch (e) { - // Any error will already have logged a failure. - } - }); -}); - -// A link to an insecure site should load outside the ssb -add_task(async function insecure() { - await testNewTabLoad(gHttpTestRoot + "empty_page.html", async ssb => { - try { - let tab = await expectTabLoad(ssb); - Assert.equal( - tab.linkedBrowser.currentURI.spec, - gHttpTestRoot + "empty_page.html", - "Should have loaded the right uri." - ); - BrowserTestUtils.removeTab(tab); - } catch (e) { - // Any error will already have logged a failure. - } - }); -}); - -// A link to a different host should load outside the ssb -add_task(async function external() { - await testNewTabLoad(gHttpsOtherRoot + "empty_page.html", async ssb => { - try { - let tab = await expectTabLoad(ssb); - Assert.equal( - tab.linkedBrowser.currentURI.spec, - gHttpsOtherRoot + "empty_page.html", - "Should have loaded the right uri." - ); - BrowserTestUtils.removeTab(tab); - } catch (e) { - // Any error will already have logged a failure. - } - }); -});
deleted file mode 100644 --- a/browser/components/ssb/tests/browser/browser_ssb_newwindow.js +++ /dev/null @@ -1,66 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -async function testNewWindowLoad(target, checker) { - let ssb = await openSSB(gHttpsTestRoot + "test_page.html#" + target); - - let promise = checker(ssb); - await BrowserTestUtils.synthesizeMouseAtCenter( - "#new-window", - {}, - getBrowser(ssb) - ); - - await promise; - await BrowserTestUtils.closeWindow(ssb); -} - -// A link that should load inside the ssb -add_task(async function local() { - await testNewWindowLoad(gHttpsTestRoot + "empty_page.html", async ssb => { - try { - await expectSSBLoad(ssb); - Assert.equal( - getBrowser(ssb).currentURI.spec, - gHttpsTestRoot + "empty_page.html", - "Should have loaded the right uri." - ); - } catch (e) { - // Any error will already have logged a failure. - } - }); -}); - -// A link to an insecure site should load outside the ssb -add_task(async function insecure() { - await testNewWindowLoad(gHttpTestRoot + "empty_page.html", async ssb => { - try { - let tab = await expectTabLoad(ssb); - Assert.equal( - tab.linkedBrowser.currentURI.spec, - gHttpTestRoot + "empty_page.html", - "Should have loaded the right uri." - ); - BrowserTestUtils.removeTab(tab); - } catch (e) { - // Any error will already have logged a failure. - } - }); -}); - -// A link to a different host should load outside the ssb -add_task(async function external() { - await testNewWindowLoad(gHttpsOtherRoot + "empty_page.html", async ssb => { - try { - let tab = await expectTabLoad(ssb); - Assert.equal( - tab.linkedBrowser.currentURI.spec, - gHttpsOtherRoot + "empty_page.html", - "Should have loaded the right uri." - ); - BrowserTestUtils.removeTab(tab); - } catch (e) { - // Any error will already have logged a failure. - } - }); -});
deleted file mode 100644 --- a/browser/components/ssb/tests/browser/browser_ssb_open.js +++ /dev/null @@ -1,25 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -// Verify that clicking the menu button opens an ssb. -add_task(async () => { - let tab = await BrowserTestUtils.openNewForegroundTab({ - gBrowser, - url: gHttpsTestRoot + "test_page.html", - }); - - let ssbwin = await openSSBFromBrowserWindow(); - Assert.equal( - getBrowser(ssbwin).currentURI.spec, - gHttpsTestRoot + "test_page.html" - ); - - Assert.equal(tab.parentNode, null, "The tab should have been closed"); - let ssb = getSSB(ssbwin); - - // This title comes from the test_page.html title tag as there is no manifest. - Assert.equal(ssb.name, "Test site", "The name should be correct."); - - await ssb.uninstall(); - await BrowserTestUtils.closeWindow(ssbwin); -});
deleted file mode 100644 --- a/browser/components/ssb/tests/browser/browser_ssb_windowlocation.js +++ /dev/null @@ -1,72 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -async function testWindowLocationLoad(target, checker) { - let ssb = await openSSB(gHttpsTestRoot + "test_page.html#" + target); - - let promise = checker(ssb); - await BrowserTestUtils.synthesizeMouseAtCenter( - "#window-location", - {}, - getBrowser(ssb) - ); - - await promise; - await BrowserTestUtils.closeWindow(ssb); -} - -// A link that should load inside the ssb -add_task(async function local() { - await testWindowLocationLoad( - gHttpsTestRoot + "empty_page.html", - async ssb => { - try { - await expectSSBLoad(ssb); - Assert.equal( - getBrowser(ssb).currentURI.spec, - gHttpsTestRoot + "empty_page.html", - "Should have loaded the right uri." - ); - } catch (e) { - // Any error will already have logged a failure. - } - } - ); -}); - -// A link to an insecure site should load outside the ssb -add_task(async function insecure() { - await testWindowLocationLoad(gHttpTestRoot + "empty_page.html", async ssb => { - try { - let tab = await expectTabLoad(ssb); - Assert.equal( - tab.linkedBrowser.currentURI.spec, - gHttpTestRoot + "empty_page.html", - "Should have loaded the right uri." - ); - BrowserTestUtils.removeTab(tab); - } catch (e) { - // Any error will already have logged a failure. - } - }); -}); - -// A link to a different host should load outside the ssb -add_task(async function external() { - await testWindowLocationLoad( - gHttpsOtherRoot + "empty_page.html", - async ssb => { - try { - let tab = await expectTabLoad(ssb); - Assert.equal( - tab.linkedBrowser.currentURI.spec, - gHttpsOtherRoot + "empty_page.html", - "Should have loaded the right uri." - ); - BrowserTestUtils.removeTab(tab); - } catch (e) { - // Any error will already have logged a failure. - } - } - ); -});
deleted file mode 100644 --- a/browser/components/ssb/tests/browser/browser_ssb_windowopen.js +++ /dev/null @@ -1,66 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -async function testWindowOpenLoad(target, checker) { - let ssb = await openSSB(gHttpsTestRoot + "test_page.html#" + target); - - let promise = checker(ssb); - await BrowserTestUtils.synthesizeMouseAtCenter( - "#window-open", - {}, - getBrowser(ssb) - ); - - await promise; - await BrowserTestUtils.closeWindow(ssb); -} - -// A link that should load inside the ssb -add_task(async function local() { - await testWindowOpenLoad(gHttpsTestRoot + "empty_page.html", async ssb => { - try { - await expectSSBLoad(ssb); - Assert.equal( - getBrowser(ssb).currentURI.spec, - gHttpsTestRoot + "empty_page.html", - "Should have loaded the right uri." - ); - } catch (e) { - // Any error will already have logged a failure. - } - }); -}); - -// A link to an insecure site should load outside the ssb -add_task(async function insecure() { - await testWindowOpenLoad(gHttpTestRoot + "empty_page.html", async ssb => { - try { - let tab = await expectTabLoad(ssb); - Assert.equal( - tab.linkedBrowser.currentURI.spec, - gHttpTestRoot + "empty_page.html", - "Should have loaded the right uri." - ); - BrowserTestUtils.removeTab(tab); - } catch (e) { - // Any error will already have logged a failure. - } - }); -}); - -// A link to a different host should load outside the ssb -add_task(async function external() { - await testWindowOpenLoad(gHttpsOtherRoot + "empty_page.html", async ssb => { - try { - let tab = await expectTabLoad(ssb); - Assert.equal( - tab.linkedBrowser.currentURI.spec, - gHttpsOtherRoot + "empty_page.html", - "Should have loaded the right uri." - ); - BrowserTestUtils.removeTab(tab); - } catch (e) { - // Any error will already have logged a failure. - } - }); -});
deleted file mode 100644 --- a/browser/components/ssb/tests/browser/empty_page.html +++ /dev/null @@ -1,9 +0,0 @@ -<!DOCTYPE html> - -<html> -<head> -<meta charset="utf-8"> -</head> -<body> -</body> -</html>
deleted file mode 100644 --- a/browser/components/ssb/tests/browser/head.js +++ /dev/null @@ -1,225 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -const { SiteSpecificBrowser } = ChromeUtils.import( - "resource:///modules/SiteSpecificBrowserService.jsm" -); - -// An insecure site to use. SSBs cannot be insecure. -const gHttpTestRoot = getRootDirectory(gTestPath).replace( - "chrome://mochitests/content/", - "http://example.com/" -); - -// A secure site to use. -const gHttpsTestRoot = getRootDirectory(gTestPath).replace( - "chrome://mochitests/content/", - "https://example.com/" -); - -// A different secure site to use. -const gHttpsOtherRoot = getRootDirectory(gTestPath).replace( - "chrome://mochitests/content/", - "https://example.org/" -); - -// The chrome url for the SSB UI. -const SSB_WINDOW = "chrome://browser/content/ssb/ssb.html"; - -// Waits for an SSB window to open. -async function waitForSSB() { - let ssbwin = await BrowserTestUtils.domWindowOpened(null, async domwin => { - await BrowserTestUtils.waitForEvent(domwin, "load"); - return domwin.location.toString() == SSB_WINDOW; - }); - - await BrowserTestUtils.waitForEvent(getBrowser(ssbwin), "SSBLoad"); - return ssbwin; -} - -// Directly opens an SSB for the given URI. Resolves to the SSB DOM window after -// the SSB content has loaded. -async function openSSB(uri) { - if (!(uri instanceof Ci.nsIURI)) { - uri = Services.io.newURI(uri); - } - - let openPromise = waitForSSB(); - let ssb = SiteSpecificBrowser.createFromURI(uri); - ssb.launch(); - return openPromise; -} - -// Simulates opening a SSB from the main browser window. Resolves to the SSB -// DOM window after the SSB content has loaded. -async function openSSBFromBrowserWindow(win = window) { - let doc = win.document; - let pageActionButton = doc.getElementById("pageActionButton"); - EventUtils.synthesizeMouseAtCenter(pageActionButton, {}, win); - let panel = doc.getElementById("pageActionPanel"); - let popupShown = BrowserTestUtils.waitForEvent(panel, "popupshown"); - - await popupShown; - - let openItem = doc.getElementById("pageAction-panel-launchSSB"); - Assert.ok(!openItem.disabled, "Open menu item should not be disabled"); - Assert.ok(!openItem.hidden, "Open menu item should not be hidden"); - - let openPromise = waitForSSB(); - EventUtils.synthesizeMouseAtCenter(openItem, {}, win); - return openPromise; -} - -// Given the SSB UI DOM window gets the browser element showing the content. -function getBrowser(ssbwin) { - return ssbwin.document.getElementById("browser"); -} - -// Given the SSB UI DOM window gets the ssb instance showing the content. -function getSSB(ssbwin) { - return ssbwin.gSSB; -} - -/** - * Waits for a load in response to an attempt to navigate from the SSB. It - * listens for new tab opens in the main window, new window opens and loads in - * the SSB itself. It returns a promise. - * - * The `where` argument is a string saying where the load is expected to - * happen, "ssb", "tab" or "window". The promise rejects if the load happens - * somewhere else and the offending new item (tab or window) get closed. When - * the load is seen in the correct location different things are returned - * depending on `where`. For "tab" the new tab is returned (it will have - * finished loading), for "window" the new window is returned (it will have - * finished loading). The "ssb" case doesn't return anything. - * - * Generally use the methods below this as they look more obvious. - */ -function expectLoadSomewhere(ssb, where, win = window) { - return new Promise((resolve, reject) => { - // Listens for a new tab opening in the main window. - const tabListener = async ({ target: tab }) => { - cleanup(); - - await BrowserTestUtils.browserLoaded( - tab.linkedBrowser, - true, - uri => uri != "about:blank" - ); - - if (where != "tab") { - Assert.ok( - false, - `Did not expect ${tab.linkedBrowser.currentURI.spec} to load in a new tab.` - ); - BrowserTestUtils.removeTab(tab); - reject(new Error("Page unexpectedly loaded in a new tab.")); - return; - } - Assert.ok( - true, - `${tab.linkedBrowser.currentURI.spec} loaded in a new tab as expected.` - ); - resolve(tab); - }; - win.gBrowser.tabContainer.addEventListener("TabOpen", tabListener); - - // Listens for new top-level windows. - const winObserver = async (domwin, topic) => { - if (topic != "domwindowopened") { - return; - } - - cleanup(); - - await BrowserTestUtils.waitForEvent( - domwin, - "load", - uri => uri != "about:blank" - ); - - if (where != "window") { - Assert.ok(false, `Did not expect a new ${domwin.location} to open.`); - await BrowserTestUtils.closeWindow(domwin); - reject(new Error("New window unexpectedly opened.")); - return; - } - Assert.ok(true, `${domwin.location} opened as expected.`); - resolve(domwin); - }; - Services.ww.registerNotification(winObserver); - - const ssbListener = () => { - cleanup(); - - if (where != "ssb") { - Assert.ok( - false, - `Did not expect ${ - getBrowser(ssb).currentURI.spec - } to load in the ssb window.` - ); - reject(new Error("Page unexpectedly loaded in the ssb window.")); - return; - } - Assert.ok( - true, - `${ - getBrowser(ssb).currentURI.spec - } loaded in the ssb window as expected.` - ); - resolve(); - }; - getBrowser(ssb).addEventListener("SSBLoad", ssbListener); - - // Makes sure that no notifications fire after the test is done. - const cleanup = () => { - win.gBrowser.tabContainer.removeEventListener("TabOpen", tabListener); - Services.ww.unregisterNotification(winObserver); - getBrowser(ssb).removeEventListener("SSBLoad", ssbListener); - }; - }); -} - -/** - * Waits for a load to occur in the ssb window but rejects if a new tab or - * window get opened. - */ -function expectSSBLoad(ssb, win = window) { - return expectLoadSomewhere(ssb, "ssb", win); -} - -/** - * Waits for a new tab to be opened and loaded. Rejects if a new window is - * opened or the ssb loads something before. Resolves with the new loaded tab. - */ -function expectTabLoad(ssb, win = window) { - return expectLoadSomewhere(ssb, "tab", win); -} - -/** - * Waits for a new window to be opened and loaded. Rejects if a new tab is - * opened or the ssb loads something before. Resolves with the new loaded - * window. - */ -function expectWindowOpen(ssb, win = window) { - return expectLoadSomewhere(ssb, "window", win); -} - -add_task(async () => { - let list = await SiteSpecificBrowserService.list(); - Assert.equal( - list.length, - 0, - "Should be no installed SSBs at the start of a test." - ); -}); - -registerCleanupFunction(async () => { - let list = await SiteSpecificBrowserService.list(); - Assert.equal( - list.length, - 0, - "Should be no installed SSBs at the end of a test." - ); -});
deleted file mode 100644 --- a/browser/components/ssb/tests/browser/site1/allhost.html +++ /dev/null @@ -1,13 +0,0 @@ -<!DOCTYPE html> - -<html> -<head> -<meta charset="utf-8"> -<!-- This page links to a manifest that sets the scope to the entire host. --> -<link rel="manifest" href="allhost.json"> -</head> -<body> -<p><a id="site1" href="../site1/final.html">Site 1</a></p> -<p><a id="site2" href="../site2/final.html">Site 2</a></p> -</body> -</html>
deleted file mode 100644 --- a/browser/components/ssb/tests/browser/site1/allhost.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "scope": "/" -} \ No newline at end of file
deleted file mode 100644 --- a/browser/components/ssb/tests/browser/site1/bad.html +++ /dev/null @@ -1,14 +0,0 @@ -<!DOCTYPE html> - -<html> -<head> -<meta charset="utf-8"> -<!-- This page links to a manifest with an invalid scope. The manifest will - just be ignored in this case. --> -<link rel="manifest" href="bad.json"> -</head> -<body> -<p><a id="site1" href="../site1/final.html">Site 1</a></p> -<p><a id="site2" href="../site2/final.html">Site 2</a></p> -</body> -</html>
deleted file mode 100644 --- a/browser/components/ssb/tests/browser/site1/bad.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "scope": "/foo/bar" -} \ No newline at end of file
deleted file mode 100644 --- a/browser/components/ssb/tests/browser/site1/empty.html +++ /dev/null @@ -1,14 +0,0 @@ -<!DOCTYPE html> - -<html> -<head> -<meta charset="utf-8"> -<!-- This page links to an empty manifest. The default scope is the current - directory --> -<link rel="manifest" href="empty.json"> -</head> -<body> -<p><a id="site1" href="../site1/final.html">Site 1</a></p> -<p><a id="site2" href="../site2/final.html">Site 2</a></p> -</body> -</html>
deleted file mode 100644 --- a/browser/components/ssb/tests/browser/site1/empty.json +++ /dev/null @@ -1,1 +0,0 @@ -{} \ No newline at end of file
deleted file mode 100644 --- a/browser/components/ssb/tests/browser/site1/final.html +++ /dev/null @@ -1,10 +0,0 @@ -<!DOCTYPE html> - -<html> -<head> -<meta charset="utf-8"> -</head> -<body> -<p>Landing page</p> -</body> -</html>
deleted file mode 100644 --- a/browser/components/ssb/tests/browser/site1/simple.html +++ /dev/null @@ -1,13 +0,0 @@ -<!DOCTYPE html> - -<html> -<head> -<meta charset="utf-8"> -<!-- This page has no linked manifest. A missing manifest is treated as the same - as an empty manifest where the default scope is the current directory --> -</head> -<body> -<p><a id="site1" href="../site1/final.html">Site 1</a></p> -<p><a id="site2" href="../site2/final.html">Site 2</a></p> -</body> -</html>
deleted file mode 100644 --- a/browser/components/ssb/tests/browser/site2/final.html +++ /dev/null @@ -1,10 +0,0 @@ -<!DOCTYPE html> - -<html> -<head> -<meta charset="utf-8"> -</head> -<body> -<p>Landing page</p> -</body> -</html>
deleted file mode 100644 --- a/browser/components/ssb/tests/browser/test_page.html +++ /dev/null @@ -1,47 +0,0 @@ -<!DOCTYPE html> - -<html> -<head> -<title>Test site</title> -<meta charset="utf-8"> -<script type="text/javascript"> -function initialize() { - let target = window.location.hash; - if (target.length < 2) { - return; - } - target = target.substring(1); - - let anchor = document.getElementById("direct"); - anchor.href = target; - - anchor = document.getElementById("new-tab"); - anchor.href = target; - - anchor = document.getElementById("new-window"); - anchor.href = target; - - anchor = document.getElementById("window-open"); - anchor.onclick = (e) => { - window.open(target, "foo", "height=300,width=400"); - e.preventDefault(); - }; - - anchor = document.getElementById("window-location"); - anchor.onclick = (e) => { - window.location = target; - e.preventDefault(); - }; -} - -window.addEventListener("load", initialize, true); -</script> -</head> -<body> -<p><a id="direct">Direct link</a></p> -<p><a id="new-tab" target="_blank">New tab link</a></p> -<p><a id="new-window" target="foo">New window link</a></p> -<p><a id="window-open" href="#">window.open call</a></p> -<p><a id="window-location" href="#">window.location manipulation</a></p> -</body> -</html>
deleted file mode 100644 --- a/browser/components/ssb/tests/xpcshell/head.js +++ /dev/null @@ -1,69 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm"); -const { SiteSpecificBrowser, SiteSpecificBrowserService } = ChromeUtils.import( - "resource:///modules/SiteSpecificBrowserService.jsm" -); -const { XPCOMUtils } = ChromeUtils.import( - "resource://gre/modules/XPCOMUtils.jsm" -); - -const ICON16 = - "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAADUExURUdwTIL60tIAAAABdFJOUwBA5thmAAAAC0lEQVQIHWMgEQAAADAAAQrnSBQAAAAASUVORK5CYII="; -const ICON32 = - "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgAQMAAABJtOi3AAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAADUExURUdwTIL60tIAAAABdFJOUwBA5thmAAAAC0lEQVQIHWMY5AAAAKAAAZearVIAAAAASUVORK5CYII="; -const ICON48 = - "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwAQMAAABtzGvEAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAADUExURUdwTIL60tIAAAABdFJOUwBA5thmAAAADElEQVQYGWMYBVQFAAFQAAHUa/NpAAAAAElFTkSuQmCC"; -const ICON96 = - "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgAQMAAADYVuV7AAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAADUExURUdwTIL60tIAAAABdFJOUwBA5thmAAAAEUlEQVQYGWMYBaNgFIyCYQoABOAAAZ11NUsAAAAASUVORK5CYII="; -const ICON128 = - "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACAAQMAAAD58POIAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAADUExURUdwTIL60tIAAAABdFJOUwBA5thmAAAAGElEQVQYGWMYBaNgFIyCUTAKRsEooDMAAAiAAAE2cKqmAAAAAElFTkSuQmCC"; -const ICON256 = - "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQAAAAEAAQMAAABmvDolAAAAA1BMVEVHcEyC+tLSAAAAAXRSTlMAQObYZgAAAB9JREFUGBntwQENAAAAwiD7p34ON2AAAAAAAAAAAOcCIQAAAfWivQQAAAAASUVORK5CYII="; - -XPCOMUtils.defineLazyModuleGetters(this, { - ManifestProcessor: "resource://gre/modules/ManifestProcessor.jsm", - KeyValueService: "resource://gre/modules/kvstore.jsm", - OS: "resource://gre/modules/osfile.jsm", - AppConstants: "resource://gre/modules/AppConstants.jsm", -}); - -let xreDirProvider = Cc["@mozilla.org/xre/directory-provider;1"].getService( - Ci.nsIXREDirProvider -); - -const SSB_STORE_PREFIX = "ssb:"; - -const uri = spec => Services.io.newURI(spec); -const storeKey = id => SSB_STORE_PREFIX + id; - -let gProfD = do_get_profile(); -let gSSBData = gProfD.clone(); -gSSBData.append("ssb"); - -Services.prefs.setBoolPref("browser.ssb.enabled", true); -Services.prefs.setBoolPref("browser.ssb.osintegration", false); - -async function getKVStore() { - await OS.File.makeDir(gSSBData.path); - return KeyValueService.getOrCreate(gSSBData.path, "ssb"); -} - -function parseManifest(doc, manifest = {}) { - return ManifestProcessor.process({ - jsonText: JSON.stringify(manifest), - manifestURL: new URL("/manifest.json", doc), - docURL: doc, - }); -} - -async function storeSSB(store, id, manifest, config = {}) { - return store.put( - storeKey(id), - JSON.stringify({ - manifest, - config, - }) - ); -}
deleted file mode 100644 --- a/browser/components/ssb/tests/xpcshell/test_empty.js +++ /dev/null @@ -1,8 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -// Basic check. There should be no SSBs in an empty profile. -add_task(async () => { - let ssbs = await SiteSpecificBrowserService.list(); - Assert.equal(ssbs.length, 0); -});
deleted file mode 100644 --- a/browser/components/ssb/tests/xpcshell/test_icons.js +++ /dev/null @@ -1,42 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -add_task(async function icons() { - let ssb = await SiteSpecificBrowser.createFromManifest( - parseManifest("https://www.mozilla.org/", { - icons: [ - { - src: "data:b", - sizes: "24x24", - }, - { - src: "data:a", - sizes: "16x16 32x32", - }, - { - src: "data:c", - sizes: "any", - }, - { - src: "data:d", - sizes: "128x128", - }, - ], - }) - ); - - Assert.equal(ssb.getIcon(1).src, "data:a"); - Assert.equal(ssb.getIcon(15).src, "data:a"); - Assert.equal(ssb.getIcon(16).src, "data:a"); - Assert.equal(ssb.getIcon(17).src, "data:b"); - Assert.equal(ssb.getIcon(23).src, "data:b"); - Assert.equal(ssb.getIcon(24).src, "data:b"); - Assert.equal(ssb.getIcon(25).src, "data:a"); - Assert.equal(ssb.getIcon(31).src, "data:a"); - Assert.equal(ssb.getIcon(32).src, "data:a"); - Assert.equal(ssb.getIcon(33).src, "data:d"); - Assert.equal(ssb.getIcon(127).src, "data:d"); - Assert.equal(ssb.getIcon(128).src, "data:d"); - Assert.equal(ssb.getIcon(129).src, "data:c"); - Assert.equal(ssb.getIcon(5000).src, "data:c"); -});
deleted file mode 100644 --- a/browser/components/ssb/tests/xpcshell/test_install.js +++ /dev/null @@ -1,59 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -// Tests that installing adds it to the store. -add_task(async () => { - Services.prefs.setBoolPref("browser.ssb.osintegration", true); - - let ssb = await SiteSpecificBrowser.createFromManifest( - parseManifest("https://www.mozilla.org/", { - icons: [ - { - src: ICON32, - sizes: "32x32", - }, - { - src: ICON48, - sizes: "48x48", - }, - { - src: ICON128, - sizes: "128x128", - }, - ], - }) - ); - await ssb.install(); - - let ssbs = await SiteSpecificBrowserService.list(); - Assert.equal(ssbs.length, 1); - Assert.equal(ssbs[0], ssb); - - let kvstore = await getKVStore(); - Assert.ok(await kvstore.has(storeKey(ssb.id))); - - // Don't want to rely on the structure too much, just make sure it looks sane. - let data = JSON.parse(await kvstore.get(`ssb:${ssb.id}`)); - Assert.ok("manifest" in data); - Assert.ok("config" in data); - - if (AppConstants.platform == "win") { - // Check that the shortcut is made and destroyed. - let link = Services.dirsvc.get("Desk", Ci.nsIFile); - link.append("www.mozilla.org.lnk"); - - Assert.ok(link.isFile()); - - let icon = gSSBData.clone(); - icon.append(ssb.id); - icon.append("icon.ico"); - - Assert.ok(icon.isFile()); - - await ssb.uninstall(); - Assert.ok(!link.exists()); - let dir = gSSBData.clone(); - dir.append(ssb.id); - Assert.ok(!dir.exists()); - } -});
deleted file mode 100644 --- a/browser/components/ssb/tests/xpcshell/test_manifest.js +++ /dev/null @@ -1,88 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -add_task(async function empty_manifest() { - let ssb = await SiteSpecificBrowser.createFromManifest( - parseManifest("https://www.mozilla.org/") - ); - - Assert.equal(ssb.startURI.spec, "https://www.mozilla.org/"); - - Assert.ok(ssb.canLoad(uri("https://www.mozilla.org/"))); - Assert.ok(ssb.canLoad(uri("https://www.mozilla.org/foo"))); - Assert.ok(ssb.canLoad(uri("https://www.mozilla.org/bar"))); - Assert.ok(!ssb.canLoad(uri("http://www.mozilla.org/"))); - Assert.ok(!ssb.canLoad(uri("https://test.mozilla.org/"))); -}); - -add_task(async function manifest_with_scope() { - let ssb = await SiteSpecificBrowser.createFromManifest( - parseManifest("https://www.mozilla.org/foo/bar", { - scope: "https://www.mozilla.org/foo", - }) - ); - - Assert.equal(ssb.startURI.spec, "https://www.mozilla.org/foo/bar"); - - Assert.ok(ssb.canLoad(uri("https://www.mozilla.org/foo"))); - Assert.ok(ssb.canLoad(uri("https://www.mozilla.org/foo/bar"))); - Assert.ok(ssb.canLoad(uri("https://www.mozilla.org/foo/baz"))); - - // Note: scopes are simple path prefixes. - Assert.ok(ssb.canLoad(uri("https://www.mozilla.org/food"))); - - Assert.ok(!ssb.canLoad(uri("https://www.mozilla.org/"))); - Assert.ok(!ssb.canLoad(uri("https://www.mozilla.org/bar"))); - Assert.ok(!ssb.canLoad(uri("http://www.mozilla.org/"))); - Assert.ok(!ssb.canLoad(uri("https://test.mozilla.org/"))); -}); - -add_task(async function manifest_with_start_url() { - let ssb = await SiteSpecificBrowser.createFromManifest( - parseManifest("https://www.mozilla.org/foo/bar", { - start_url: "https://www.mozilla.org/foo/", - }) - ); - - Assert.equal(ssb.startURI.spec, "https://www.mozilla.org/foo/"); - - // scope should be "https://www.mozilla.org/foo/" - Assert.ok(ssb.canLoad(uri("https://www.mozilla.org/foo/bar"))); - Assert.ok(ssb.canLoad(uri("https://www.mozilla.org/foo/baz"))); - - Assert.ok(!ssb.canLoad(uri("https://www.mozilla.org/foo"))); - Assert.ok(!ssb.canLoad(uri("https://www.mozilla.org/"))); - Assert.ok(!ssb.canLoad(uri("https://www.mozilla.org/bar"))); - Assert.ok(!ssb.canLoad(uri("http://www.mozilla.org/"))); - Assert.ok(!ssb.canLoad(uri("https://test.mozilla.org/"))); -}); - -add_task(async function update_manifest() { - let ssb = await SiteSpecificBrowser.createFromManifest( - parseManifest("https://www.mozilla.org/foo/bar/bas", { - start_url: "https://www.mozilla.org/foo/bar/bas", - scope: "https://www.mozilla.org/foo/bar/", - }) - ); - - Assert.equal(ssb.startURI.spec, "https://www.mozilla.org/foo/bar/bas"); - - Assert.ok(ssb.canLoad(uri("https://www.mozilla.org/foo/bar/"))); - Assert.ok(ssb.canLoad(uri("https://www.mozilla.org/foo/bar/foo"))); - - Assert.ok(!ssb.canLoad(uri("https://www.mozilla.org/foo"))); - Assert.ok(!ssb.canLoad(uri("https://www.mozilla.org/foo/bar"))); - - await ssb.updateFromManifest( - parseManifest("https://www.mozilla.org/foo/bar/bas", { - start_url: "https://www.mozilla.org/foo/bar/bas", - scope: "https://www.mozilla.org/foo/", - }) - ); - - Assert.ok(ssb.canLoad(uri("https://www.mozilla.org/foo/bar/"))); - Assert.ok(ssb.canLoad(uri("https://www.mozilla.org/foo/bar/foo"))); - - Assert.ok(!ssb.canLoad(uri("https://www.mozilla.org/foo"))); - Assert.ok(ssb.canLoad(uri("https://www.mozilla.org/foo/bar"))); -});
deleted file mode 100644 --- a/browser/components/ssb/tests/xpcshell/test_too_new.js +++ /dev/null @@ -1,22 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -// A database that is too new should be wiped. -add_task(async () => { - let kvstore = await getKVStore(); - kvstore.put( - "_meta", - JSON.stringify({ - version: 1000, - }) - ); - - storeSSB(kvstore, "a", parseManifest("https://www.mozilla.org/"), {}); - storeSSB(kvstore, "b", parseManifest("https://www.microsoft.com/"), {}); - - let ssbs = await SiteSpecificBrowserService.list(); - Assert.equal(ssbs.length, 0); - - let meta = JSON.parse(await kvstore.get("_meta")); - Assert.equal(meta.version, 1); -});
deleted file mode 100644 --- a/browser/components/ssb/tests/xpcshell/test_uninstall.js +++ /dev/null @@ -1,31 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -// Tests that uninstalling removes from the store. -add_task(async () => { - let kvstore = await getKVStore(); - kvstore.put( - "_meta", - JSON.stringify({ - version: 1, - }) - ); - - storeSSB(kvstore, "a", parseManifest("https://www.mozilla.org/"), {}); - - let ssb = await SiteSpecificBrowser.load("a"); - - let ssbs = await SiteSpecificBrowserService.list(); - Assert.equal(ssbs.length, 1); - Assert.equal(ssbs[0], ssb); - - Assert.ok(ssb.canLoad(uri("https://www.mozilla.org/test/"))); - Assert.ok(!ssb.canLoad(uri("https://www.microsoft.com/test/"))); - - await ssb.uninstall(); - - ssbs = await SiteSpecificBrowserService.list(); - Assert.equal(ssbs.length, 0); - - Assert.ok(!(await kvstore.has(storeKey("a")))); -});
deleted file mode 100644 --- a/browser/components/ssb/tests/xpcshell/xpcshell.ini +++ /dev/null @@ -1,12 +0,0 @@ -[DEFAULT] -head = head.js -firefox-appdir = browser - -[test_empty.js] -[test_icons.js] -[test_install.js] -[test_manifest.js] -[test_too_new.js] -skip-if = tsan # Times out, bug 1674773 -[test_uninstall.js] -skip-if = tsan # Times out, bug 1674773
--- a/browser/modules/PageActions.jsm +++ b/browser/modules/PageActions.jsm @@ -31,21 +31,16 @@ ChromeUtils.defineModuleGetter( "BinarySearch", "resource://gre/modules/BinarySearch.jsm" ); ChromeUtils.defineModuleGetter( this, "PrivateBrowsingUtils", "resource://gre/modules/PrivateBrowsingUtils.jsm" ); -ChromeUtils.defineModuleGetter( - this, - "SiteSpecificBrowserService", - "resource:///modules/SiteSpecificBrowserService.jsm" -); const ACTION_ID_BOOKMARK = "bookmark"; const ACTION_ID_PIN_TAB = "pinTab"; const ACTION_ID_BOOKMARK_SEPARATOR = "bookmarkSeparator"; const ACTION_ID_BUILT_IN_SEPARATOR = "builtInSeparator"; const ACTION_ID_TRANSIENT_SEPARATOR = "transientSeparator"; const PREF_PERSISTED_ACTIONS = "browser.pageActions.persistedActions"; @@ -1287,30 +1282,16 @@ if (Services.prefs.getBoolPref("identity onSubviewShowing(panelViewNode) { browserPageActions(panelViewNode).sendToDevice.onShowingSubview( panelViewNode ); }, }); } -if (SiteSpecificBrowserService.isEnabled) { - gBuiltInActions.push({ - id: "launchSSB", - // Hardcoded for now. Localization tracked in bug 1602528. - title: "Use This Site in App Mode", - onLocationChange(browserWindow) { - browserPageActions(browserWindow).launchSSB.updateState(); - }, - onCommand(event, buttonNode) { - browserPageActions(buttonNode).launchSSB.onCommand(event, buttonNode); - }, - }); -} - // share URL if (AppConstants.platform == "macosx") { gBuiltInActions.push({ id: "shareURL", panelFluentID: "page-action-share-url-panel", urlbarFluentID: "page-action-share-url-urlbar", onShowingInPanel(buttonNode) { browserPageActions(buttonNode).shareURL.onShowingInPanel(buttonNode);
deleted file mode 100644 --- a/browser/themes/shared/install-ssb.svg +++ /dev/null @@ -1,7 +0,0 @@ -<!-- 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/. --> -<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"> - <path fill="context-fill" fill-opacity="context-fill-opacity" d="M15 2h-1V1a1 1 0 0 0-2 0v1h-1a1 1 0 0 0 0 2h1v1a1 1 0 0 0 2 0V4h1a1 1 0 0 0 0-2z"/> - <path fill="context-fill" fill-opacity="context-fill-opacity" d="M13 7a1 1 0 0 0-1 1v5H3V4h5a1 1 0 0 0 0-2H2a1 1 0 0 0-1 1v11a1 1 0 0 0 1 1h11a1 1 0 0 0 1-1V8a1 1 0 0 0-1-1z"/> -</svg>
--- a/browser/themes/shared/jar.inc.mn +++ b/browser/themes/shared/jar.inc.mn @@ -287,10 +287,9 @@ skin/classic/browser/places/folder.svg (../shared/places/folder.svg) skin/classic/browser/places/folder-smart.svg (../shared/places/folder-smart.svg) skin/classic/browser/places/history.svg (../shared/places/history.svg) skin/classic/browser/places/tag.svg (../shared/places/tag.svg) skin/classic/browser/places/tree-icons.css (../shared/places/tree-icons.css) skin/classic/browser/privatebrowsing/aboutPrivateBrowsing.css (../shared/privatebrowsing/aboutPrivateBrowsing.css) skin/classic/browser/privatebrowsing/favicon.svg (../shared/privatebrowsing/favicon.svg) skin/classic/browser/privatebrowsing/private-browsing.svg (../shared/privatebrowsing/private-browsing.svg) - skin/classic/browser/install-ssb.svg (../shared/install-ssb.svg) skin/classic/browser/critical.svg (../shared/icons/critical.svg)
--- a/browser/themes/shared/menupanel.inc.css +++ b/browser/themes/shared/menupanel.inc.css @@ -172,14 +172,8 @@ toolbarpaletteitem[place="palette"] > #b #appMenu-library-downloads-button { list-style-image: url("chrome://browser/skin/downloads/download-icons.svg#arrow-with-bar"); } #appMenu-library-downloads-show-button { list-style-image: url("chrome://browser/skin/folder.svg"); } - -.panel-subview-body .ssb-uninstall > .toolbarbutton-icon { - list-style-image: url("chrome://global/skin/icons/close.svg"); - -moz-context-properties: fill, fill-opacity; - fill-opacity: 0; -}
--- a/browser/themes/shared/urlbar-searchbar.inc.css +++ b/browser/themes/shared/urlbar-searchbar.inc.css @@ -468,21 +468,16 @@ min-width: 11px; min-height: 11px; } #pageActionActivatedActionPanel[actionID="pocket"] { --arrowpanel-background: #fbfbfb; } -#pageAction-panel-launchSSB, -#pageAction-urlbar-launchSSB { - list-style-image: url("chrome://browser/skin/install-ssb.svg"); -} - /* URL bar and page action buttons */ #page-action-buttons { -moz-box-align: center; } #pageActionSeparator { /* This draws the separator the same way that #urlbar-label-box draws its