tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

TaskbarTabsUtils.sys.mjs (5382B)


      1 /* vim: se cin sw=2 ts=2 et filetype=javascript :
      2 * This Source Code Form is subject to the terms of the Mozilla Public
      3 * License, v. 2.0. If a copy of the MPL was not distributed with this
      4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      5 
      6 import { XPCOMUtils } from "resource://gre/modules/XPCOMUtils.sys.mjs";
      7 
      8 let lazy = {};
      9 
     10 XPCOMUtils.defineLazyServiceGetters(lazy, {
     11  Favicons: ["@mozilla.org/browser/favicon-service;1", Ci.nsIFaviconService],
     12  imgTools: ["@mozilla.org/image/tools;1", Ci.imgITools],
     13 });
     14 
     15 ChromeUtils.defineLazyGetter(lazy, "logConsole", () => {
     16  return console.createInstance({
     17    prefix: "TaskbarTabs",
     18    maxLogLevel: "Warn",
     19  });
     20 });
     21 
     22 export const TaskbarTabsUtils = {
     23  /**
     24   * Checks if Taskbar Tabs has been enabled.
     25   *
     26   * @returns {bool} `true` if the Taskbar Tabs pref is enabled.
     27   */
     28  isEnabled() {
     29    const pref = "browser.taskbarTabs.enabled";
     30    return Services.prefs.getBoolPref(pref, false);
     31  },
     32 
     33  /**
     34   * Returns a folder to store profile-specific Taskbar Tabs files.
     35   *
     36   * @returns {nsIFile} Folder to store Taskbar Tabs files.
     37   */
     38  getTaskbarTabsFolder() {
     39    // Construct the path `[Profile]/taskbartabs/`.
     40    let folder = Services.dirsvc.get("ProfD", Ci.nsIFile);
     41    folder.append("taskbartabs");
     42    return folder;
     43  },
     44 
     45  /**
     46   * Checks if the window is a Taskbar Tabs window.
     47   *
     48   * @param {Window} aWin - The window to inspect.
     49   * @returns {bool} true if the window is a Taskbar Tabs window.
     50   */
     51  isTaskbarTabWindow(aWin) {
     52    return aWin.document.documentElement.hasAttribute("taskbartab");
     53  },
     54 
     55  /**
     56   * Retrieves the Taskbar Tabs ID for the window.
     57   *
     58   * @param {DOMWindow} aWin - The window to retrieve the Taskbar Tabs ID.
     59   * @returns {string} The Taskbar Tabs ID for the window.
     60   */
     61  getTaskbarTabIdFromWindow(aWin) {
     62    return aWin.document.documentElement.getAttribute("taskbartab");
     63  },
     64 
     65  /**
     66   * Retrieves a favicon image container for the provided URL.
     67   *
     68   * @param {nsIURI} aUri - The URI to retrieve a favicon for.
     69   * @returns {imgIContainer} A container of the favicon retrieved, or the
     70   * default favicon.
     71   */
     72  async getFavicon(aUri) {
     73    let favicon = await lazy.Favicons.getFaviconForPage(aUri);
     74 
     75    let imgContainer;
     76    if (favicon) {
     77      try {
     78        if (favicon.mimeType !== "image/svg+xml") {
     79          // Image containers retrieved via `getImageFromUri` error when
     80          // attempting to scale via `scaleImage`. Since we have the raw image
     81          // data from the favicon service and the image container decoded from
     82          // it scales without error, use it instead.
     83          let img = lazy.imgTools.decodeImageFromArrayBuffer(
     84            new Uint8Array(favicon.rawData).buffer,
     85            favicon.mimeType
     86          );
     87          imgContainer = scaleImage(img);
     88        } else {
     89          // `imgITools::decodeImage*` APIs don't work with SVG images.
     90          imgContainer = getImageFromUri(favicon.dataURI);
     91        }
     92      } catch (e) {
     93        lazy.logConsole.error(
     94          `${e.message}, falling through to default favicon.`
     95        );
     96      }
     97    }
     98 
     99    if (!imgContainer) {
    100      lazy.logConsole.debug(
    101        `Unable to retrieve icon for ${aUri.spec}, using default favicon at ${lazy.Favicons.defaultFavicon.spec}.`
    102      );
    103      imgContainer = await getImageFromUri(lazy.Favicons.defaultFavicon);
    104    }
    105 
    106    return imgContainer;
    107  },
    108 };
    109 
    110 /**
    111 * Attempts to scale the provided image container to a 256x256 image.
    112 *
    113 * @param {imgIContainer} aImgContainer - The image container to scale from.
    114 * @returns {imgIContainer} The scaled image container on success, or the
    115 * provided image container on failure.
    116 */
    117 function scaleImage(aImgContainer) {
    118  try {
    119    const istream = lazy.imgTools.encodeScaledImage(
    120      aImgContainer,
    121      "image/png",
    122      256,
    123      256
    124    );
    125    const size = istream.available();
    126 
    127    // Use a binary input stream to grab the bytes.
    128    const bis = Cc["@mozilla.org/binaryinputstream;1"].createInstance(
    129      Ci.nsIBinaryInputStream
    130    );
    131    bis.setInputStream(istream);
    132 
    133    const bytes = bis.readBytes(size);
    134    if (size != bytes.length) {
    135      throw new Error("Didn't read expected number of bytes");
    136    }
    137    aImgContainer = lazy.imgTools.decodeImageFromBuffer(
    138      bytes,
    139      bytes.length,
    140      "image/png"
    141    );
    142  } catch (e) {
    143    lazy.logConsole.error(
    144      "Failed to scale the favicon image, continuing with the unscaled image container."
    145    );
    146  }
    147 
    148  return aImgContainer;
    149 }
    150 
    151 /**
    152 * Retrieves an image given a URI.
    153 *
    154 * @param {nsIURI} aUri - The URI to retrieve an image from.
    155 * @returns {Promise<imgIContainer>} Resolves to an image container.
    156 */
    157 async function getImageFromUri(aUri) {
    158  // Creating the Taskbar Tabs icon should not result in a network request.
    159  const protocolFlags = Services.io.getProtocolFlags(aUri.scheme);
    160  if (!(protocolFlags & Ci.nsIProtocolHandler.URI_IS_LOCAL_RESOURCE)) {
    161    throw new Error(
    162      `Scheme "${aUri.scheme}" is not supported for creating a Taskbar Tab icon, URI should be local`
    163    );
    164  }
    165 
    166  const channel = Services.io.newChannelFromURI(
    167    aUri,
    168    null,
    169    Services.scriptSecurityManager.getSystemPrincipal(),
    170    null,
    171    Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL,
    172    Ci.nsIContentPolicy.TYPE_IMAGE
    173  );
    174 
    175  return ChromeUtils.fetchDecodedImage(aUri, channel);
    176 }