tor-browser

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

ManifestIcons.sys.mjs (2729B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 export var ManifestIcons = {
      6  async browserFetchIcon(aBrowser, manifest, iconSize) {
      7    const msgKey = "DOM:WebManifest:fetchIcon";
      8 
      9    const actor =
     10      aBrowser.browsingContext.currentWindowGlobal.getActor("ManifestMessages");
     11    const reply = await actor.sendQuery(msgKey, { manifest, iconSize });
     12    if (!reply.success) {
     13      throw reply.result;
     14    }
     15    return reply.result;
     16  },
     17 
     18  async contentFetchIcon(aWindow, manifest, iconSize) {
     19    return getIcon(aWindow, toIconArray(manifest.icons), iconSize);
     20  },
     21 };
     22 
     23 function parseIconSize(size) {
     24  if (size === "any" || size === "") {
     25    // We want icons without size specified to sorted
     26    // as the largest available icons
     27    return Number.MAX_SAFE_INTEGER;
     28  }
     29  // 100x100 will parse as 100
     30  return parseInt(size, 10);
     31 }
     32 
     33 // Create an array of icons sorted by their size
     34 function toIconArray(icons) {
     35  const iconBySize = [];
     36  icons.forEach(icon => {
     37    const sizes = "sizes" in icon ? icon.sizes : "";
     38    sizes.forEach(size => {
     39      iconBySize.push({ src: icon.src, size: parseIconSize(size) });
     40    });
     41  });
     42  return iconBySize.sort((a, b) => a.size - b.size);
     43 }
     44 
     45 async function getIcon(aWindow, icons, expectedSize) {
     46  if (!icons.length) {
     47    throw new Error("Could not find valid icon");
     48  }
     49  // We start trying the smallest icon that is larger than the requested
     50  // size and go up to the largest icon if they fail, if all those fail
     51  // go back down to the smallest
     52  let index = icons.findIndex(icon => icon.size >= expectedSize);
     53  if (index === -1) {
     54    index = icons.length - 1;
     55  }
     56 
     57  return fetchIcon(aWindow, icons[index].src).catch(() => {
     58    // Remove all icons with the failed source, the same source
     59    // may have been used for multiple sizes
     60    icons = icons.filter(x => x.src !== icons[index].src);
     61    return getIcon(aWindow, icons, expectedSize);
     62  });
     63 }
     64 
     65 async function fetchIcon(aWindow, src) {
     66  const iconURL = new aWindow.URL(src, aWindow.location);
     67  // If this is already a data URL then no need to load it again.
     68  if (iconURL.protocol === "data:") {
     69    return iconURL.href;
     70  }
     71 
     72  const request = new aWindow.Request(iconURL, { mode: "cors" });
     73  request.overrideContentPolicyType(Ci.nsIContentPolicy.TYPE_IMAGE);
     74  const response = await aWindow.fetch(request);
     75  const blob = await response.blob();
     76  return new Promise((resolve, reject) => {
     77    const reader = new FileReader();
     78    reader.onloadend = () => resolve(reader.result);
     79    reader.onerror = reject;
     80    reader.readAsDataURL(blob);
     81  });
     82 }