Blame dom/manifest/ManifestIcons.jsm

Packit f0b94e
"use strict";
Packit f0b94e
Packit f0b94e
const {
Packit f0b94e
  utils: Cu,
Packit f0b94e
  classes: Cc,
Packit f0b94e
  interfaces: Ci
Packit f0b94e
} = Components;
Packit f0b94e
Packit f0b94e
ChromeUtils.import("resource://gre/modules/PromiseMessage.jsm");
Packit f0b94e
Packit f0b94e
var ManifestIcons = {
Packit f0b94e
Packit f0b94e
  async browserFetchIcon(aBrowser, manifest, iconSize) {
Packit f0b94e
    const msgKey = "DOM:WebManifest:fetchIcon";
Packit f0b94e
    const mm = aBrowser.messageManager;
Packit f0b94e
    const {data: {success, result}} =
Packit f0b94e
      await PromiseMessage.send(mm, msgKey, {manifest, iconSize});
Packit f0b94e
    if (!success) {
Packit f0b94e
      throw result;
Packit f0b94e
    }
Packit f0b94e
    return result;
Packit f0b94e
  },
Packit f0b94e
Packit f0b94e
  async contentFetchIcon(aWindow, manifest, iconSize) {
Packit f0b94e
    return await getIcon(aWindow, toIconArray(manifest.icons), iconSize);
Packit f0b94e
  }
Packit f0b94e
};
Packit f0b94e
Packit f0b94e
function parseIconSize(size) {
Packit f0b94e
  if (size === "any" || size === "") {
Packit f0b94e
    // We want icons without size specified to sorted
Packit f0b94e
    // as the largest available icons
Packit f0b94e
    return Number.MAX_SAFE_INTEGER;
Packit f0b94e
  }
Packit f0b94e
  // 100x100 will parse as 100
Packit f0b94e
  return parseInt(size, 10);
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
// Create an array of icons sorted by their size
Packit f0b94e
function toIconArray(icons) {
Packit f0b94e
  const iconBySize = [];
Packit f0b94e
  icons.forEach(icon => {
Packit f0b94e
    const sizes = ("sizes" in icon) ? icon.sizes : "";
Packit f0b94e
    sizes.split(" ").forEach(size => {
Packit f0b94e
      iconBySize.push({src: icon.src, size: parseIconSize(size)});
Packit f0b94e
    });
Packit f0b94e
  });
Packit f0b94e
  return iconBySize.sort((a, b) => a.size - b.size);
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
async function getIcon(aWindow, icons, expectedSize) {
Packit f0b94e
  if (!icons.length) {
Packit f0b94e
    throw new Error("Could not find valid icon");
Packit f0b94e
  }
Packit f0b94e
  // We start trying the smallest icon that is larger than the requested
Packit f0b94e
  // size and go up to the largest icon if they fail, if all those fail
Packit f0b94e
  // go back down to the smallest
Packit f0b94e
  let index = icons.findIndex(icon => icon.size >= expectedSize);
Packit f0b94e
  if (index === -1) {
Packit f0b94e
    index = icons.length - 1;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  return fetchIcon(aWindow, icons[index].src).catch(err => {
Packit f0b94e
    // Remove all icons with the failed source, the same source
Packit f0b94e
    // may have been used for multiple sizes
Packit f0b94e
    icons = icons.filter(x => x.src !== icons[index].src);
Packit f0b94e
    return getIcon(aWindow, icons, expectedSize);
Packit f0b94e
  });
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
async function fetchIcon(aWindow, src) {
Packit f0b94e
  const iconURL = new aWindow.URL(src, aWindow.location);
Packit f0b94e
  const request = new aWindow.Request(iconURL, {mode: "cors"});
Packit f0b94e
  request.overrideContentPolicyType(Ci.nsIContentPolicy.TYPE_IMAGE);
Packit f0b94e
  return aWindow.fetch(request)
Packit f0b94e
    .then(response => response.blob())
Packit f0b94e
    .then(blob => new Promise((resolve, reject) => {
Packit f0b94e
      var reader = new FileReader();
Packit f0b94e
      reader.onloadend = () => resolve(reader.result);
Packit f0b94e
      reader.onerror = reject;
Packit f0b94e
      reader.readAsDataURL(blob);
Packit f0b94e
    }));
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
var EXPORTED_SYMBOLS = ["ManifestIcons"]; // jshint ignore:line