Bug 1602189: If the app manifest provides no icons use those provided by the page where available. r=Gijs

Makes the LinkHandler cache its most recent seen icons so that we can retrieve
them when the app manifest doesn't provide any (generally only when there is
no manifest at all).

Differential Revision: https://phabricator.services.mozilla.com/D56291

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Dave Townsend 2019-12-16 19:57:00 +00:00
parent 117107b7d4
commit ecb4d2fcb7
4 changed files with 137 additions and 3 deletions

View File

@ -39,12 +39,13 @@ class LinkHandlerParent extends JSWindowActorParent {
let win = browser.ownerGlobal;
let gBrowser = win.gBrowser;
if (!gBrowser) {
return;
}
switch (aMsg.name) {
case "Link:LoadingIcon":
if (!gBrowser) {
return;
}
if (aMsg.data.canUseForTab) {
let tab = gBrowser.getTabForBrowser(browser);
if (tab.hasAttribute("busy")) {
@ -56,12 +57,27 @@ class LinkHandlerParent extends JSWindowActorParent {
break;
case "Link:SetIcon":
// Cache the most recent icon and rich icon locally.
if (aMsg.data.canUseForTab) {
this.icon = aMsg.data;
} else {
this.richIcon = aMsg.data;
}
if (!gBrowser) {
return;
}
this.setIconFromLink(gBrowser, browser, aMsg.data);
this.notifyTestListeners("SetIcon", aMsg.data);
break;
case "Link:SetFailedIcon":
if (!gBrowser) {
return;
}
if (aMsg.data.canUseForTab) {
this.clearPendingIcon(gBrowser, browser);
}
@ -70,6 +86,10 @@ class LinkHandlerParent extends JSWindowActorParent {
break;
case "Link:AddSearch":
if (!gBrowser) {
return;
}
let tab = gBrowser.getTabForBrowser(browser);
if (!tab) {
break;

View File

@ -0,0 +1,60 @@
/* 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/. */
var EXPORTED_SYMBOLS = ["ImageTools"];
const { XPCOMUtils } = ChromeUtils.import(
"resource://gre/modules/XPCOMUtils.jsm"
);
ChromeUtils.defineModuleGetter(
this,
"NetUtil",
"resource://gre/modules/NetUtil.jsm"
);
XPCOMUtils.defineLazyServiceGetter(
this,
"ImgTools",
"@mozilla.org/image/tools;1",
Ci.imgITools
);
const ImageTools = {
/**
* Given a data URI decodes the data into an object with "type" which is the
* found mimetype and "container" which is an imgIContainer.
*
* @param {nsIURI} dataURI the URI to load.
* @return {Promise<object>} the image info.
*/
loadImage(dataURI) {
return new Promise((resolve, reject) => {
if (!dataURI.schemeIs("data")) {
reject(new Error("Should only be loading data URIs."));
return;
}
let channel = NetUtil.newChannel({
uri: dataURI,
loadUsingSystemPrincipal: true,
});
ImgTools.decodeImageFromChannelAsync(
dataURI,
channel,
(container, status) => {
if (Components.isSuccessCode(status)) {
resolve({
type: channel.contentType,
container,
});
} else {
reject(Components.Exception("Failed to load image.", status));
}
},
null
);
});
},
};

View File

@ -38,6 +38,7 @@ XPCOMUtils.defineLazyModuleGetters(this, {
ManifestProcessor: "resource://gre/modules/ManifestProcessor.jsm",
KeyValueService: "resource://gre/modules/kvstore.jsm",
OS: "resource://gre/modules/osfile.jsm",
ImageTools: "resource:///modules/ssb/ImageTools.jsm",
});
/**
@ -106,6 +107,36 @@ function manifestForURI(uri) {
}
}
/**
* Creates an IconResource from the LinkHandler data.
*
* @param {object} iconData the data from the LinkHandler actor.
* @return {Promise<IconResource>} an icon resource.
*/
async function getIconResource(iconData) {
// This should be a data url so no network traffic.
let imageData = await ImageTools.loadImage(
Services.io.newURI(iconData.iconURL)
);
if (imageData.container.type == Ci.imgIContainer.TYPE_VECTOR) {
return {
src: iconData.iconURL,
purpose: ["any"],
type: imageData.type,
sizes: ["any"],
};
}
// TODO: For ico files we should find all the available sizes: Bug 1604285.
return {
src: iconData.iconURL,
purpose: ["any"],
type: imageData.type,
sizes: [`${imageData.container.width}x${imageData.container.height}`],
};
}
/**
* Generates an app manifest for a site loaded in a browser element.
*
@ -151,6 +182,25 @@ async function buildManifestForBrowser(browser) {
})
)).filter(icon => icon);
// If the site provided no icons then try to use the normal page icons.
if (!manifest.icons.length) {
let linkHandler = browser.browsingContext.currentWindowGlobal.getActor(
"LinkHandler"
);
for (let icon of [linkHandler.icon, linkHandler.richIcon]) {
if (!icon) {
continue;
}
try {
manifest.icons.push(await getIconResource(icon));
} catch (e) {
console.warn(`Failed to load icon resource ${icon.originalURL}`, e);
}
}
}
return manifest;
}

View File

@ -16,6 +16,10 @@ EXTRA_JS_MODULES += [
'SiteSpecificBrowserService.jsm',
]
EXTRA_JS_MODULES.ssb += [
'ImageTools.jsm',
]
FINAL_TARGET_FILES.actors += [
'SiteSpecificBrowserChild.jsm',
'SiteSpecificBrowserParent.jsm',