217 lines
7.4 KiB
JavaScript
217 lines
7.4 KiB
JavaScript
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
import { AppConstants } from "resource://gre/modules/AppConstants.sys.mjs";
|
|
import { XPCOMUtils } from "resource://gre/modules/XPCOMUtils.sys.mjs";
|
|
|
|
let lazy = {};
|
|
|
|
ChromeUtils.defineESModuleGetters(lazy, {
|
|
FaviconUtils: "moz-src:///toolkit/modules/FaviconUtils.sys.mjs",
|
|
ShellService: "moz-src:///browser/components/shell/ShellService.sys.mjs",
|
|
});
|
|
|
|
XPCOMUtils.defineLazyServiceGetters(lazy, {
|
|
Favicons: ["@mozilla.org/browser/favicon-service;1", Ci.nsIFaviconService],
|
|
});
|
|
|
|
export const TaskbarTabsUtils = {
|
|
/**
|
|
* Checks if Taskbar Tabs has been enabled.
|
|
*
|
|
* @returns {bool} `true` if the Taskbar Tabs pref is enabled.
|
|
*/
|
|
isEnabled() {
|
|
const pref = "browser.taskbarTabs.enabled";
|
|
return Services.prefs.getBoolPref(pref, false);
|
|
},
|
|
|
|
isMSIX() {
|
|
return (
|
|
AppConstants.platform === "win" &&
|
|
Services.sysinfo.getProperty("hasWinPackageId", false)
|
|
);
|
|
},
|
|
|
|
/**
|
|
* Returns a folder to store profile-specific Taskbar Tabs files.
|
|
*
|
|
* @returns {nsIFile} Folder to store Taskbar Tabs files.
|
|
*/
|
|
getTaskbarTabsFolder() {
|
|
// Construct the path `[Profile]/taskbartabs/`.
|
|
let folder = Services.dirsvc.get("ProfD", Ci.nsIFile);
|
|
folder.append("taskbartabs");
|
|
return folder;
|
|
},
|
|
|
|
/**
|
|
* Checks if the window is a Taskbar Tabs window.
|
|
*
|
|
* @param {Window} aWin - The window to inspect.
|
|
* @returns {bool} true if the window is a Taskbar Tabs window.
|
|
*/
|
|
isTaskbarTabWindow(aWin) {
|
|
return aWin.document.documentElement.hasAttribute("taskbartab");
|
|
},
|
|
|
|
/**
|
|
* Retrieves the Taskbar Tabs ID for the window.
|
|
*
|
|
* @param {DOMWindow} aWin - The window to retrieve the Taskbar Tabs ID.
|
|
* @returns {string} The Taskbar Tabs ID for the window.
|
|
*/
|
|
getTaskbarTabIdFromWindow(aWin) {
|
|
return aWin.document.documentElement.getAttribute("taskbartab");
|
|
},
|
|
|
|
/**
|
|
* Retrieves an image container for the provided URI and decodes it remotely,
|
|
* e.g. in the content process of aBrowser.
|
|
*
|
|
* May throw if an error occurs while decoding.
|
|
*
|
|
* @param {nsIFile} aFile - The file to parse the image from.
|
|
* @param {number} aSize - The width/height of the image to decode.
|
|
* @param {Browser} aBrowser - The browser to decode the image in. Can be
|
|
* null if there isn't a specific content process to use.
|
|
* @param {string} aMimeType - The MIME type to use when decoding the image.
|
|
* @returns {Promise<imgIContainer>} An image container with the decoded
|
|
* image.
|
|
* @throws {Components.Exception} The image could not be decoded.
|
|
*/
|
|
async _remoteDecodeImageFromFile(aFile, aSize, aBrowser, aMimeType) {
|
|
// We can't use a file URI since the content process wouldn't be able to
|
|
// read it. Read the file now and create a data URI to read instead.
|
|
let content = await IOUtils.read(aFile.path);
|
|
let spec = `data:${aMimeType};base64,${content.toBase64()}`;
|
|
let uri = Services.io.newURI(spec);
|
|
|
|
return this._remoteDecodeImageFromURI(uri, aSize, aBrowser);
|
|
},
|
|
|
|
/**
|
|
* Retrieves an image container for the provided URI and decodes it remotely,
|
|
* e.g. in the content process of aBrowser.
|
|
*
|
|
* May throw if an error occurs while decoding.
|
|
*
|
|
* @param {nsIURI} aUri - The URI to parse the image from.
|
|
* @param {number} aSize - The width/height of the image to decode.
|
|
* @param {Browser?} [aBrowser] - The browser to decode the image in. Can be
|
|
* null if there isn't a specific content process to use.
|
|
* @returns {Promise<imgIContainer>} An image container with the decoded
|
|
* image.
|
|
* @throws {TypeError} aUri is not an nsIURI.
|
|
* @throws {Components.Exception} The image could not be decoded.
|
|
*/
|
|
async _remoteDecodeImageFromURI(aUri, aSize, aBrowser = null) {
|
|
if (!(aUri instanceof Ci.nsIURI)) {
|
|
throw new TypeError(
|
|
"Invalid argument, `aUri` should be instance of `nsIURI`"
|
|
);
|
|
}
|
|
|
|
let params = { size: aSize };
|
|
if (aBrowser) {
|
|
params.contentParentId =
|
|
aBrowser.browsingContext.currentWindowContext.contentParentId;
|
|
}
|
|
|
|
let newUri = Services.io.newURI(
|
|
lazy.FaviconUtils.getMozRemoteImageURL(aUri.spec, params)
|
|
);
|
|
return unsafeDecodeImageFromAnyURI(newUri);
|
|
},
|
|
|
|
/**
|
|
* Retrieves an image container for the provided URI. The URI must be a local
|
|
* URI, like chrome: or data:. (Note that being local _doesn't_ mean that it
|
|
* is trusted---this usually should be used from tests or for images bundled
|
|
* with the browser.)
|
|
*
|
|
* May throw if an error occurs while decoding.
|
|
*
|
|
* @param {nsIURI} aUri - The URI to parse the image from. Must be a local
|
|
* URI, like data:, chrome:, or file:.
|
|
* @returns {imgIContainer} A container of the icon retrieved, or the
|
|
* default favicon.
|
|
* @throws {TypeError} aUri is not an nsIURI.
|
|
* @throws {Error} aUri is not a local URI.
|
|
* @throws {Components.Exception} The image could not be decoded.
|
|
*/
|
|
async _imageFromLocalURI(aUri) {
|
|
if (!(aUri instanceof Ci.nsIURI)) {
|
|
throw new TypeError(
|
|
"Invalid argument, `aUri` should be instance of `nsIURI`"
|
|
);
|
|
}
|
|
|
|
const protocolFlags = Services.io.getProtocolFlags(aUri.scheme);
|
|
if (!(protocolFlags & Ci.nsIProtocolHandler.URI_IS_LOCAL_RESOURCE)) {
|
|
throw new Error("Attempting to create an image from a non-local URI");
|
|
}
|
|
|
|
return unsafeDecodeImageFromAnyURI(aUri);
|
|
},
|
|
|
|
/**
|
|
* Gets the favicon for aUri as a data URI.
|
|
*
|
|
* @param {nsIURI} aUri - The URI to look up the favicon for.
|
|
* @returns {nsIURI} The data URI of the favicon.
|
|
*/
|
|
async getFaviconUri(aUri) {
|
|
let favicon = await lazy.Favicons.getFaviconForPage(aUri);
|
|
return favicon?.dataURI;
|
|
},
|
|
|
|
/**
|
|
* Gets the default favicon as an imgIContainer. This icon is used if no
|
|
* other icons are available.
|
|
*
|
|
* @returns {imgIContainer} The default favicon.
|
|
*/
|
|
async getDefaultIcon() {
|
|
return await TaskbarTabsUtils._imageFromLocalURI(
|
|
lazy.Favicons.defaultFavicon
|
|
);
|
|
},
|
|
|
|
/**
|
|
* Gets the name that should be used for a new desktop entry on Linux. This
|
|
* avoids duplicating the logic between TaskbarTabsWindowManager, where we
|
|
* want the name before pinning, and TaskbarTabsPin, where it is actually
|
|
* pinned. As such, this should be constant within a single session.
|
|
*
|
|
* @param {string} aTaskbarTabId - The ID of the taskbar tab.
|
|
* @returns {string} The desktop entry name, excluding the '.desktop' suffix.
|
|
*/
|
|
_determineNewDesktopEntryName(aTaskbarTabId) {
|
|
return `${lazy.ShellService.getGlibPrgname()}.webapp-${aTaskbarTabId}`;
|
|
},
|
|
};
|
|
|
|
/**
|
|
* Shared helper function for _remoteDecodeImageFromURI and _imageFromLocalURI;
|
|
* fetches the given URI with the system principal and decodes it in the
|
|
* current process. Do not use with untrusted images.
|
|
*
|
|
* @param {nsIURI} aUri - The URI to fetch and decode.
|
|
* @returns {Promise<imgIContainer>} The parsed image container.
|
|
* @throws {Components.Exception} The image could not be decoded.
|
|
*/
|
|
async function unsafeDecodeImageFromAnyURI(aUri) {
|
|
const channel = Services.io.newChannelFromURI(
|
|
aUri,
|
|
null,
|
|
Services.scriptSecurityManager.getSystemPrincipal(),
|
|
null,
|
|
Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL,
|
|
Ci.nsIContentPolicy.TYPE_IMAGE
|
|
);
|
|
|
|
return ChromeUtils.fetchDecodedImage(aUri, channel);
|
|
}
|