Bug 1362224: Cache per-tab icon data for browserAction/pageAction. r?aswan
MozReview-Commit-ID: JifAtY36gKA
--- a/browser/components/extensions/ext-browserAction.js
+++ b/browser/components/extensions/ext-browserAction.js
@@ -14,16 +14,17 @@ XPCOMUtils.defineLazyModuleGetter(this,
XPCOMUtils.defineLazyServiceGetter(this, "DOMUtils",
"@mozilla.org/inspector/dom-utils;1",
"inIDOMUtils");
Cu.import("resource://gre/modules/EventEmitter.jsm");
Cu.import("resource://gre/modules/Task.jsm");
var {
+ DefaultWeakMap,
IconDetails,
} = ExtensionUtils;
const POPUP_PRELOAD_TIMEOUT_MS = 200;
var XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
function isAncestorOrSelf(target, node) {
@@ -52,16 +53,18 @@ this.browserAction = class extends Exten
return browserActionMap.get(extension);
}
onManifestEntry(entryName) {
let {extension} = this;
let options = extension.manifest.browser_action;
+ this.iconData = new DefaultWeakMap(icons => this.getIconData(icons));
+
let widgetId = makeWidgetId(extension.id);
this.id = `${widgetId}-browser-action`;
this.viewId = `PanelUI-webext-${widgetId}-browser-action-view`;
this.widget = null;
this.pendingPopup = null;
this.pendingPopupTimeout = null;
@@ -387,43 +390,56 @@ this.browserAction = class extends Exten
if (badgeNode) {
let color = tabData.badgeBackgroundColor;
if (color) {
color = `rgba(${color[0]}, ${color[1]}, ${color[2]}, ${color[3] / 255})`;
}
badgeNode.style.backgroundColor = color || "";
}
+ let {style, legacy} = this.iconData.get(tabData.icon);
const LEGACY_CLASS = "toolbarbutton-legacy-addon";
- node.classList.remove(LEGACY_CLASS);
+ if (legacy) {
+ node.classList.add(LEGACY_CLASS);
+ } else {
+ node.classList.remove(LEGACY_CLASS);
+ }
+ node.setAttribute("style", style);
+ }
+
+ getIconData(icons) {
let baseSize = 16;
- let {icon, size} = IconDetails.getPreferredIcon(tabData.icon, this.extension, baseSize);
+ let {icon, size} = IconDetails.getPreferredIcon(icons, this.extension, baseSize);
+
+ let legacy = false;
// If the best available icon size is not divisible by 16, check if we have
// an 18px icon to fall back to, and trim off the padding instead.
if (size % 16 && !icon.endsWith(".svg")) {
- let result = IconDetails.getPreferredIcon(tabData.icon, this.extension, 18);
+ let result = IconDetails.getPreferredIcon(icons, this.extension, 18);
if (result.size % 18 == 0) {
baseSize = 18;
icon = result.icon;
- node.classList.add(LEGACY_CLASS);
+ legacy = true;
}
}
let getIcon = size => IconDetails.escapeUrl(
- IconDetails.getPreferredIcon(tabData.icon, this.extension, size).icon);
+ IconDetails.getPreferredIcon(icons, this.extension, size).icon);
- node.setAttribute("style", `
+ let style = `
--webextension-menupanel-image: url("${getIcon(32)}");
--webextension-menupanel-image-2x: url("${getIcon(64)}");
--webextension-toolbar-image: url("${IconDetails.escapeUrl(icon)}");
--webextension-toolbar-image-2x: url("${getIcon(baseSize * 2)}");
- `);
+ `;
+
+ return {style, legacy};
}
// Update the toolbar button for a given window.
updateWindow(window) {
let widget = this.widget.forWindow(window);
if (widget) {
let tab = window.gBrowser.selectedTab;
this.updateButton(widget.node, this.tabContext.get(tab));
--- a/browser/components/extensions/ext-pageAction.js
+++ b/browser/components/extensions/ext-pageAction.js
@@ -3,31 +3,34 @@
"use strict";
XPCOMUtils.defineLazyModuleGetter(this, "PanelPopup",
"resource:///modules/ExtensionPopups.jsm");
Cu.import("resource://gre/modules/Task.jsm");
var {
+ DefaultWeakMap,
IconDetails,
} = ExtensionUtils;
// WeakMap[Extension -> PageAction]
let pageActionMap = new WeakMap();
this.pageAction = class extends ExtensionAPI {
static for(extension) {
return pageActionMap.get(extension);
}
onManifestEntry(entryName) {
let {extension} = this;
let options = extension.manifest.page_action;
+ this.iconData = new DefaultWeakMap(icons => this.getIconData(icons));
+
this.id = makeWidgetId(extension.id) + "-page-action";
this.tabManager = extension.tabManager;
this.defaults = {
show: false,
title: options.default_title || extension.name,
icon: IconDetails.normalize({path: options.default_icon}, extension),
@@ -107,35 +110,42 @@ this.pageAction = class extends Extensio
let button = this.getButton(window);
if (tabData.show) {
// Update the title and icon only if the button is visible.
let title = tabData.title || this.extension.name;
button.setAttribute("tooltiptext", title);
button.setAttribute("aria-label", title);
-
- // These URLs should already be properly escaped, but make doubly sure CSS
- // string escape characters are escaped here, since they could lead to a
- // sandbox break.
- let escape = str => str.replace(/[\\\s"]/g, encodeURIComponent);
+ button.classList.add("webextension-page-action");
- let getIcon = size => escape(IconDetails.getPreferredIcon(tabData.icon, this.extension, size).icon);
+ let {style} = this.iconData.get(tabData.icon);
- button.setAttribute("style", `
- --webextension-urlbar-image: url("${getIcon(16)}");
- --webextension-urlbar-image-2x: url("${getIcon(32)}");
- `);
-
- button.classList.add("webextension-page-action");
+ button.setAttribute("style", style);
}
button.hidden = !tabData.show;
}
+ getIconData(icons) {
+ // These URLs should already be properly escaped, but make doubly sure CSS
+ // string escape characters are escaped here, since they could lead to a
+ // sandbox break.
+ let escape = str => str.replace(/[\\\s"]/g, encodeURIComponent);
+
+ let getIcon = size => escape(IconDetails.getPreferredIcon(icons, this.extension, size).icon);
+
+ let style = `
+ --webextension-urlbar-image: url("${getIcon(16)}");
+ --webextension-urlbar-image-2x: url("${getIcon(32)}");
+ `;
+
+ return style;
+ }
+
// Create an |image| node and add it to the |urlbar-icons|
// container in the given window.
addButton(window) {
let document = window.document;
let button = document.createElement("image");
button.id = this.id;
button.setAttribute("class", "urlbar-icon");