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/. */
5 export var ManifestIcons = {
6 async browserFetchIcon(aBrowser, manifest, iconSize) {
7 const msgKey = "DOM:WebManifest:fetchIcon";
10 aBrowser.browsingContext.currentWindowGlobal.getActor("ManifestMessages");
11 const reply = await actor.sendQuery(msgKey, { manifest, iconSize });
18 async contentFetchIcon(aWindow, manifest, iconSize) {
19 return getIcon(aWindow, toIconArray(manifest.icons), iconSize);
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;
29 // 100x100 will parse as 100
30 return parseInt(size, 10);
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) });
42 return iconBySize.sort((a, b) => a.size - b.size);
45 async function getIcon(aWindow, icons, expectedSize) {
47 throw new Error("Could not find valid icon");
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);
54 index = icons.length - 1;
57 return fetchIcon(aWindow, icons[index].src).catch(err => {
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);
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:") {
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);