Bug 1506770: Extract data url from icon of addon. r=jdescottes,ochameau

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

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Daisuke Akatsuka 2018-12-20 02:11:56 +00:00
parent 78f66f50f9
commit f379e6739b
5 changed files with 79 additions and 17 deletions

View File

@ -78,6 +78,8 @@ const WebExtensionActor = protocol.ActorClassWithSpec(webExtensionSpec, {
id: this.addonId,
name: this.addon.name,
url: this.addon.sourceURI ? this.addon.sourceURI.spec : undefined,
// iconDataURL is available after calling loadIconDataURL
iconDataURL: this._iconDataURL,
iconURL: this.addon.iconURL,
isSystem: this.addon.isSystem,
debuggable: this.addon.isDebuggable,
@ -112,6 +114,45 @@ const WebExtensionActor = protocol.ActorClassWithSpec(webExtensionSpec, {
return this._childFormPromise;
},
// This function will be called from RootActor in case that the debugger client
// retrieves list of addons with `iconDataURL` option.
async loadIconDataURL() {
this._iconDataURL = await this.getIconDataURL();
},
async getIconDataURL() {
if (!this.addon.iconURL) {
return null;
}
const xhr = new XMLHttpRequest();
xhr.responseType = "blob";
xhr.open("GET", this.addon.iconURL, true);
if (this.addon.iconURL.toLowerCase().endsWith(".svg")) {
// Maybe SVG, thus force to change mime type.
xhr.overrideMimeType("image/svg+xml");
}
try {
const blob = await new Promise((resolve, reject) => {
xhr.onload = () => resolve(xhr.response);
xhr.onerror = reject;
xhr.send();
});
const reader = new FileReader();
return await new Promise((resolve, reject) => {
reader.onloadend = () => resolve(reader.result);
reader.onerror = reject;
reader.readAsDataURL(blob);
});
} catch (_) {
console.warn(`Failed to create data url from [${ this.addon.iconURL }]`);
return null;
}
},
// WebExtensionTargetActorProxy callbacks.
onProxyDestroy() {

View File

@ -400,7 +400,17 @@ RootActor.prototype = {
this._parameters.tabList.onListChanged = null;
},
onListAddons: function() {
/**
* This function can receive the following option from debugger client.
*
* @param {Object} option
* - iconDataURL: {boolean}
* When true, make data url from the icon of addon, then make possible to
* access by iconDataURL in the actor. The iconDataURL is useful when
* retrieving addons from a remote device, because the raw iconURL might not
* be accessible on the client.
*/
onListAddons: async function(option) {
const addonList = this._parameters.addonList;
if (!addonList) {
return { from: this.actorID, error: "noAddons",
@ -410,22 +420,25 @@ RootActor.prototype = {
// Reattach the onListChanged listener now that a client requested the list.
addonList.onListChanged = this._onAddonListChanged;
return addonList.getList().then((addonTargetActors) => {
const addonTargetActorPool = new Pool(this.conn);
for (const addonTargetActor of addonTargetActors) {
addonTargetActorPool.manage(addonTargetActor);
const addonTargetActors = await addonList.getList();
const addonTargetActorPool = new Pool(this.conn);
for (const addonTargetActor of addonTargetActors) {
if (option.iconDataURL) {
await addonTargetActor.loadIconDataURL();
}
if (this._addonTargetActorPool) {
this._addonTargetActorPool.destroy();
}
this._addonTargetActorPool = addonTargetActorPool;
addonTargetActorPool.manage(addonTargetActor);
}
return {
"from": this.actorID,
"addons": addonTargetActors.map(addonTargetActor => addonTargetActor.form()),
};
});
if (this._addonTargetActorPool) {
this._addonTargetActorPool.destroy();
}
this._addonTargetActorPool = addonTargetActorPool;
return {
"from": this.actorID,
"addons": addonTargetActors.map(addonTargetActor => addonTargetActor.form()),
};
},
onAddonListChanged: function() {

View File

@ -183,6 +183,10 @@ AddonTargetActor.prototype = {
});
},
// A no-op function to enable this actor to be handled as same as WebExtensionActor.
loadIconDataURL() {
},
preNest: function() {
for (const {windowUtils} of Services.wm.getEnumerator(null)) {
windowUtils.suppressEventHandling(true);
@ -248,4 +252,3 @@ AddonTargetActor.prototype.requestTypes = {
"detach": AddonTargetActor.prototype.onDetach,
"reload": AddonTargetActor.prototype.onReload,
};

View File

@ -33,6 +33,7 @@ const {
const {
atob,
btoa,
Blob,
ChromeUtils,
CSS,
CSSRule,
@ -52,6 +53,7 @@ const {
wantGlobalProperties: [
"atob",
"btoa",
"Blob",
"ChromeUtils",
"CSS",
"CSSRule",
@ -213,7 +215,6 @@ function lazyRequireGetter(obj, property, module, destructure) {
// List of pseudo modules exposed to all devtools modules.
exports.modules = {
ChromeUtils,
FileReader,
HeapSnapshot,
InspectorUtils,
promise,
@ -265,6 +266,7 @@ defineLazyGetter(exports.modules, "xpcInspector", () => {
// Changes here should be mirrored to devtools/.eslintrc.
exports.globals = {
atob,
Blob,
btoa,
console,
CSS,
@ -291,6 +293,7 @@ exports.globals = {
DOMRect,
Element,
Event,
FileReader,
FormData,
isWorker: false,
loader: {

View File

@ -55,7 +55,9 @@ const rootSpecPrototype = {
},
listAddons: {
request: {},
request: {
iconDataURL: Option(0, "boolean"),
},
response: {
addons: RetVal("array:addonTarget"),
},