2012-05-21 15:12:37 +04:00
|
|
|
/* 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/. */
|
2009-09-04 14:58:18 +04:00
|
|
|
|
2018-02-23 22:50:01 +03:00
|
|
|
var EXPORTED_SYMBOLS = ["LightweightThemeConsumer"];
|
2009-09-04 14:58:18 +04:00
|
|
|
|
2019-01-17 21:18:31 +03:00
|
|
|
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
2012-09-22 23:24:26 +04:00
|
|
|
|
2018-07-10 15:27:55 +03:00
|
|
|
const DEFAULT_THEME_ID = "default-theme@mozilla.org";
|
|
|
|
const ICONS = Services.prefs.getStringPref("extensions.webextensions.themes.icons.buttons", "").split(",");
|
|
|
|
|
2019-02-25 13:02:50 +03:00
|
|
|
ChromeUtils.defineModuleGetter(this, "AppConstants",
|
|
|
|
"resource://gre/modules/AppConstants.jsm");
|
|
|
|
ChromeUtils.defineModuleGetter(this, "LightweightThemeImageOptimizer",
|
|
|
|
"resource://gre/modules/addons/LightweightThemeImageOptimizer.jsm");
|
|
|
|
// Get the theme variables from the app resource directory.
|
|
|
|
// This allows per-app variables.
|
|
|
|
ChromeUtils.defineModuleGetter(this, "ThemeContentPropertyList",
|
|
|
|
"resource:///modules/ThemeVariableMap.jsm");
|
|
|
|
ChromeUtils.defineModuleGetter(this, "ThemeVariableMap",
|
|
|
|
"resource:///modules/ThemeVariableMap.jsm");
|
|
|
|
|
2018-02-07 08:22:22 +03:00
|
|
|
const toolkitVariableMap = [
|
2018-03-27 14:40:06 +03:00
|
|
|
["--lwt-accent-color", {
|
|
|
|
lwtProperty: "accentcolor",
|
|
|
|
processColor(rgbaChannels, element) {
|
2018-04-11 22:05:13 +03:00
|
|
|
if (!rgbaChannels || rgbaChannels.a == 0) {
|
2018-03-27 14:40:06 +03:00
|
|
|
return "white";
|
|
|
|
}
|
|
|
|
// Remove the alpha channel
|
|
|
|
const {r, g, b} = rgbaChannels;
|
|
|
|
return `rgb(${r}, ${g}, ${b})`;
|
2018-08-31 08:59:17 +03:00
|
|
|
},
|
2018-03-27 14:40:06 +03:00
|
|
|
}],
|
|
|
|
["--lwt-text-color", {
|
|
|
|
lwtProperty: "textcolor",
|
|
|
|
processColor(rgbaChannels, element) {
|
|
|
|
if (!rgbaChannels) {
|
2018-05-11 20:48:53 +03:00
|
|
|
rgbaChannels = {r: 0, g: 0, b: 0};
|
2018-03-27 14:40:06 +03:00
|
|
|
}
|
2018-05-11 20:48:53 +03:00
|
|
|
// Remove the alpha channel
|
|
|
|
const {r, g, b} = rgbaChannels;
|
2018-05-26 19:45:06 +03:00
|
|
|
element.setAttribute("lwthemetextcolor", _isTextColorDark(r, g, b) ? "dark" : "bright");
|
2018-05-11 20:48:53 +03:00
|
|
|
return `rgba(${r}, ${g}, ${b})`;
|
2018-08-31 08:59:17 +03:00
|
|
|
},
|
2018-03-27 14:40:06 +03:00
|
|
|
}],
|
2018-04-18 18:54:38 +03:00
|
|
|
["--arrowpanel-background", {
|
2018-08-31 08:59:17 +03:00
|
|
|
lwtProperty: "popup",
|
2018-03-27 14:40:06 +03:00
|
|
|
}],
|
2018-04-18 18:54:38 +03:00
|
|
|
["--arrowpanel-color", {
|
2018-05-26 19:45:06 +03:00
|
|
|
lwtProperty: "popup_text",
|
|
|
|
processColor(rgbaChannels, element) {
|
|
|
|
const disabledColorVariable = "--panel-disabled-color";
|
|
|
|
|
|
|
|
if (!rgbaChannels) {
|
|
|
|
element.removeAttribute("lwt-popup-brighttext");
|
|
|
|
element.removeAttribute("lwt-popup-darktext");
|
|
|
|
element.style.removeProperty(disabledColorVariable);
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
let {r, g, b, a} = rgbaChannels;
|
|
|
|
|
|
|
|
if (_isTextColorDark(r, g, b)) {
|
|
|
|
element.removeAttribute("lwt-popup-brighttext");
|
|
|
|
element.setAttribute("lwt-popup-darktext", "true");
|
|
|
|
} else {
|
|
|
|
element.removeAttribute("lwt-popup-darktext");
|
|
|
|
element.setAttribute("lwt-popup-brighttext", "true");
|
|
|
|
}
|
|
|
|
|
|
|
|
element.style.setProperty(disabledColorVariable, `rgba(${r}, ${g}, ${b}, 0.5)`);
|
|
|
|
return `rgba(${r}, ${g}, ${b}, ${a})`;
|
2018-08-31 08:59:17 +03:00
|
|
|
},
|
2018-03-27 14:40:06 +03:00
|
|
|
}],
|
2018-04-18 18:54:38 +03:00
|
|
|
["--arrowpanel-border-color", {
|
2018-08-31 08:59:17 +03:00
|
|
|
lwtProperty: "popup_border",
|
2018-03-27 14:40:06 +03:00
|
|
|
}],
|
2018-02-11 01:24:50 +03:00
|
|
|
["--lwt-toolbar-field-background-color", {
|
2018-08-31 08:59:17 +03:00
|
|
|
lwtProperty: "toolbar_field",
|
2018-02-11 01:24:50 +03:00
|
|
|
}],
|
|
|
|
["--lwt-toolbar-field-color", {
|
2018-04-26 12:48:22 +03:00
|
|
|
lwtProperty: "toolbar_field_text",
|
|
|
|
processColor(rgbaChannels, element) {
|
|
|
|
if (!rgbaChannels) {
|
|
|
|
element.removeAttribute("lwt-toolbar-field-brighttext");
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
const {r, g, b, a} = rgbaChannels;
|
2018-05-26 19:45:06 +03:00
|
|
|
if (_isTextColorDark(r, g, b)) {
|
2018-04-26 12:48:22 +03:00
|
|
|
element.removeAttribute("lwt-toolbar-field-brighttext");
|
|
|
|
} else {
|
|
|
|
element.setAttribute("lwt-toolbar-field-brighttext", "true");
|
|
|
|
}
|
|
|
|
return `rgba(${r}, ${g}, ${b}, ${a})`;
|
2018-08-31 08:59:17 +03:00
|
|
|
},
|
2018-02-11 01:24:50 +03:00
|
|
|
}],
|
2018-06-19 17:25:49 +03:00
|
|
|
["--lwt-toolbar-field-border-color", {
|
2018-08-31 08:59:17 +03:00
|
|
|
lwtProperty: "toolbar_field_border",
|
2018-06-19 17:25:49 +03:00
|
|
|
}],
|
|
|
|
["--lwt-toolbar-field-focus", {
|
2018-08-31 08:59:17 +03:00
|
|
|
lwtProperty: "toolbar_field_focus",
|
2018-06-19 17:25:49 +03:00
|
|
|
}],
|
|
|
|
["--lwt-toolbar-field-focus-color", {
|
2018-08-31 08:59:17 +03:00
|
|
|
lwtProperty: "toolbar_field_text_focus",
|
2018-06-19 17:25:49 +03:00
|
|
|
}],
|
|
|
|
["--toolbar-field-focus-border-color", {
|
2018-08-31 08:59:17 +03:00
|
|
|
lwtProperty: "toolbar_field_border_focus",
|
2018-06-19 17:25:49 +03:00
|
|
|
}],
|
2019-01-31 16:28:30 +03:00
|
|
|
["--lwt-toolbar-field-highlight", {
|
|
|
|
lwtProperty: "toolbar_field_highlight",
|
|
|
|
processColor(rgbaChannels, element) {
|
|
|
|
if (!rgbaChannels) {
|
|
|
|
element.removeAttribute("lwt-selection");
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
element.setAttribute("lwt-selection", "true");
|
|
|
|
const {r, g, b, a} = rgbaChannels;
|
|
|
|
return `rgba(${r}, ${g}, ${b}, ${a})`;
|
|
|
|
},
|
|
|
|
}],
|
|
|
|
["--lwt-toolbar-field-highlight-text", {
|
|
|
|
lwtProperty: "toolbar_field_highlight_text",
|
|
|
|
}],
|
2018-02-07 08:22:22 +03:00
|
|
|
];
|
2018-03-27 14:40:06 +03:00
|
|
|
|
2018-02-23 22:50:01 +03:00
|
|
|
function LightweightThemeConsumer(aDocument) {
|
2009-09-04 14:58:18 +04:00
|
|
|
this._doc = aDocument;
|
2012-09-22 23:24:26 +04:00
|
|
|
this._win = aDocument.defaultView;
|
2018-07-13 18:21:34 +03:00
|
|
|
this._winId = this._win.windowUtils.outerWindowID;
|
2009-09-04 14:58:18 +04:00
|
|
|
|
2017-04-14 22:51:38 +03:00
|
|
|
Services.obs.addObserver(this, "lightweight-theme-styling-update");
|
2009-09-04 14:58:18 +04:00
|
|
|
|
2019-02-20 10:20:52 +03:00
|
|
|
ChromeUtils.import("resource://gre/modules/LightweightThemeManager.jsm", this);
|
|
|
|
|
2019-02-25 13:02:50 +03:00
|
|
|
// We're responsible for notifying LightweightThemeManager when the OS is in
|
|
|
|
// dark mode so it can activate the dark theme. We don't want this on Linux
|
2019-02-26 18:37:29 +03:00
|
|
|
// as the default theme picks up the right colors from dark GTK themes.
|
2019-02-25 13:02:50 +03:00
|
|
|
if (AppConstants.platform != "linux") {
|
|
|
|
this._darkThemeMediaQuery = this._win.matchMedia("(-moz-system-dark-theme)");
|
|
|
|
this._darkThemeMediaQuery.addListener(this.LightweightThemeManager);
|
|
|
|
this.LightweightThemeManager.systemThemeChanged(this._darkThemeMediaQuery);
|
|
|
|
}
|
2019-02-20 10:20:52 +03:00
|
|
|
|
|
|
|
this._update(this.LightweightThemeManager.currentThemeWithPersistedData);
|
2018-04-20 15:21:00 +03:00
|
|
|
|
|
|
|
this._win.addEventListener("resolutionchange", this);
|
2018-02-15 20:03:25 +03:00
|
|
|
this._win.addEventListener("unload", this, { once: true });
|
2018-02-23 22:50:01 +03:00
|
|
|
}
|
2009-09-04 14:58:18 +04:00
|
|
|
|
|
|
|
LightweightThemeConsumer.prototype = {
|
2012-09-22 23:24:26 +04:00
|
|
|
_lastData: null,
|
2014-03-21 00:55:49 +04:00
|
|
|
// Whether a lightweight theme is enabled.
|
2014-02-05 01:17:00 +04:00
|
|
|
_active: false,
|
2012-09-22 23:24:26 +04:00
|
|
|
|
2016-12-30 02:34:54 +03:00
|
|
|
observe(aSubject, aTopic, aData) {
|
2009-11-24 18:59:53 +03:00
|
|
|
if (aTopic != "lightweight-theme-styling-update")
|
2009-09-04 14:58:18 +04:00
|
|
|
return;
|
|
|
|
|
2018-07-10 15:27:55 +03:00
|
|
|
let parsedData = JSON.parse(aData);
|
|
|
|
if (!parsedData) {
|
2018-07-23 20:46:40 +03:00
|
|
|
parsedData = { theme: null, experiment: null };
|
2018-07-10 15:27:55 +03:00
|
|
|
}
|
|
|
|
|
2018-07-13 18:21:34 +03:00
|
|
|
if (parsedData.window && parsedData.window !== this._winId) {
|
2017-08-04 23:08:57 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-07-23 20:46:40 +03:00
|
|
|
this._update(parsedData.theme, parsedData.experiment);
|
2009-09-04 14:58:18 +04:00
|
|
|
},
|
|
|
|
|
2016-12-30 02:34:54 +03:00
|
|
|
handleEvent(aEvent) {
|
2018-02-15 20:03:25 +03:00
|
|
|
switch (aEvent.type) {
|
2018-04-20 15:21:00 +03:00
|
|
|
case "resolutionchange":
|
|
|
|
if (this._active) {
|
|
|
|
this._update(this._lastData);
|
|
|
|
}
|
|
|
|
break;
|
2018-02-15 20:03:25 +03:00
|
|
|
case "unload":
|
|
|
|
Services.obs.removeObserver(this, "lightweight-theme-styling-update");
|
2018-07-13 18:21:34 +03:00
|
|
|
Services.ppmm.sharedData.delete(`theme/${this._winId}`);
|
2018-04-20 15:21:00 +03:00
|
|
|
this._win.removeEventListener("resolutionchange", this);
|
2019-02-25 13:02:50 +03:00
|
|
|
this._win = this._doc = null;
|
|
|
|
if (this._darkThemeMediaQuery) {
|
|
|
|
this._darkThemeMediaQuery.removeListener(this.LightweightThemeManager);
|
|
|
|
this._darkThemeMediaQuery = null;
|
|
|
|
}
|
2018-02-15 20:03:25 +03:00
|
|
|
break;
|
2012-09-22 23:24:26 +04:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2018-07-23 20:46:40 +03:00
|
|
|
_update(theme, experiment) {
|
|
|
|
this._lastData = theme;
|
|
|
|
if (theme) {
|
|
|
|
theme = LightweightThemeImageOptimizer.optimize(theme, this._win.screen);
|
2013-07-01 19:12:23 +04:00
|
|
|
}
|
2018-07-23 20:46:40 +03:00
|
|
|
if (!theme) {
|
2019-02-20 10:20:52 +03:00
|
|
|
theme = { id: DEFAULT_THEME_ID };
|
2018-07-10 15:27:55 +03:00
|
|
|
}
|
|
|
|
|
2019-02-20 10:20:52 +03:00
|
|
|
let active = this._active = (theme.id != DEFAULT_THEME_ID);
|
|
|
|
|
|
|
|
// The theme we're switching to can be different from the user-selected
|
|
|
|
// theme. E.g. if the default theme is selected and the OS is in dark mode,
|
|
|
|
// we'd silently activate the dark theme if available. We set an attribute
|
|
|
|
// in that case so stylesheets can differentiate this from the dark theme
|
|
|
|
// being selected explicitly by the user.
|
|
|
|
let isDefaultThemeInDarkMode =
|
|
|
|
theme.id == this.LightweightThemeManager.defaultDarkThemeID &&
|
|
|
|
this.LightweightThemeManager.selectedThemeID == DEFAULT_THEME_ID &&
|
2019-02-25 13:02:50 +03:00
|
|
|
this._darkThemeMediaQuery &&
|
2019-02-20 10:20:52 +03:00
|
|
|
this._darkThemeMediaQuery.matches;
|
|
|
|
|
2014-02-05 01:17:00 +04:00
|
|
|
let root = this._doc.documentElement;
|
2009-09-04 14:58:18 +04:00
|
|
|
|
2018-07-23 20:46:40 +03:00
|
|
|
if (active && theme.headerURL) {
|
2018-02-15 16:37:30 +03:00
|
|
|
root.setAttribute("lwtheme-image", "true");
|
|
|
|
} else {
|
|
|
|
root.removeAttribute("lwtheme-image");
|
|
|
|
}
|
|
|
|
|
2018-07-23 20:46:40 +03:00
|
|
|
if (active && theme.icons) {
|
|
|
|
let activeIcons = Object.keys(theme.icons).join(" ");
|
2017-03-07 02:10:39 +03:00
|
|
|
root.setAttribute("lwthemeicons", activeIcons);
|
|
|
|
} else {
|
|
|
|
root.removeAttribute("lwthemeicons");
|
|
|
|
}
|
|
|
|
|
2018-07-10 15:27:55 +03:00
|
|
|
for (let icon of ICONS) {
|
2018-07-23 20:46:40 +03:00
|
|
|
let value = theme.icons ? theme.icons[`--${icon}-icon`] : null;
|
2018-07-10 15:27:55 +03:00
|
|
|
_setImage(root, active, `--${icon}-icon`, value);
|
|
|
|
}
|
|
|
|
|
2018-07-23 20:46:40 +03:00
|
|
|
this._setExperiment(active, experiment, theme.experimental);
|
|
|
|
_setImage(root, active, "--lwt-header-image", theme.headerURL);
|
|
|
|
_setImage(root, active, "--lwt-additional-images", theme.additionalBackgrounds);
|
|
|
|
_setProperties(root, active, theme);
|
2017-03-07 02:10:39 +03:00
|
|
|
|
2018-05-11 20:48:53 +03:00
|
|
|
if (active) {
|
|
|
|
root.setAttribute("lwtheme", "true");
|
|
|
|
} else {
|
|
|
|
root.removeAttribute("lwtheme");
|
|
|
|
root.removeAttribute("lwthemetextcolor");
|
|
|
|
}
|
2019-02-20 10:20:52 +03:00
|
|
|
if (isDefaultThemeInDarkMode) {
|
|
|
|
root.setAttribute("lwt-default-theme-in-dark-mode", "true");
|
|
|
|
} else {
|
|
|
|
root.removeAttribute("lwt-default-theme-in-dark-mode");
|
|
|
|
}
|
2018-05-11 20:48:53 +03:00
|
|
|
|
2018-07-23 20:46:40 +03:00
|
|
|
let contentThemeData = _getContentProperties(this._doc, active, theme);
|
2018-07-13 18:21:34 +03:00
|
|
|
Services.ppmm.sharedData.set(`theme/${this._winId}`, contentThemeData);
|
2018-07-23 20:46:40 +03:00
|
|
|
},
|
|
|
|
|
|
|
|
_setExperiment(active, experiment, properties) {
|
|
|
|
const root = this._doc.documentElement;
|
|
|
|
if (this._lastExperimentData) {
|
|
|
|
const { stylesheet, usedVariables } = this._lastExperimentData;
|
|
|
|
if (stylesheet) {
|
|
|
|
stylesheet.remove();
|
|
|
|
}
|
|
|
|
if (usedVariables) {
|
Bug 1511138 - Improve performance of LightweightThemeConsumer when setting properties, and also avoid _sanitizeCSSColor from getting fooled. r=jaws
This probably deserves a comment as of why it belongs to this bug.
This patch series caused a single, reproducible timeout on
browser_ext_themes_toolbars.js, where the transitionend event it awaits for
stops triggering.
I got fascinated by it and I decided to poke around it in rr instead of just
removing the await line, and here's what's going on.
In the previous implementation of _sanitizeCSSColor, we were not flushing style
because of the optimization bug 1363805 introduced (which wasn't supposed to
deal with out-of-document elements, but it accidentally did so).
In any case, the fact that we were not flushing style in _sanitizeCSSColor
caused us to flush style sometime later when the lwtheme attribute was already
set up, and thus the selector in here matched:
https://searchfox.org/mozilla-central/rev/cfaa5a1d48d6bc6552199e73004ecb05d0a9c921/browser/themes/shared/browser.inc.css#40
And thus caused the transition rule to apply at a time where the
background-color change happened.
Now we were flushing on getComputedStyle on every call, and in the most
inefficient way possible (changing a custom property on the root before each
property change, which causes us to restyle the whole document to propagate it
down to all descendants).
Furthermore, we were flushing style at a time where the lwtheme attribute
change had not yet happened, and thus when the background-color changed, there
was no transition rule applicable, and the transition didn't fire.
This patch changes LightweightThemeConsumer to avoid restyling the whole
document over and over.
Also, while at it I realized that you could fool the sanitizer with !important
in an experiment stylesheet or with other !important rule in the page really.
It's not clear why you'd do that, but it may be worth to just making that
function completely sound, so I did that and added a test for it.
Differential Revision: https://phabricator.services.mozilla.com/D13716
2018-12-04 05:06:44 +03:00
|
|
|
for (const [variable] of usedVariables) {
|
2018-07-23 20:46:40 +03:00
|
|
|
_setProperty(root, false, variable);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
Bug 1511138 - Improve performance of LightweightThemeConsumer when setting properties, and also avoid _sanitizeCSSColor from getting fooled. r=jaws
This probably deserves a comment as of why it belongs to this bug.
This patch series caused a single, reproducible timeout on
browser_ext_themes_toolbars.js, where the transitionend event it awaits for
stops triggering.
I got fascinated by it and I decided to poke around it in rr instead of just
removing the await line, and here's what's going on.
In the previous implementation of _sanitizeCSSColor, we were not flushing style
because of the optimization bug 1363805 introduced (which wasn't supposed to
deal with out-of-document elements, but it accidentally did so).
In any case, the fact that we were not flushing style in _sanitizeCSSColor
caused us to flush style sometime later when the lwtheme attribute was already
set up, and thus the selector in here matched:
https://searchfox.org/mozilla-central/rev/cfaa5a1d48d6bc6552199e73004ecb05d0a9c921/browser/themes/shared/browser.inc.css#40
And thus caused the transition rule to apply at a time where the
background-color change happened.
Now we were flushing on getComputedStyle on every call, and in the most
inefficient way possible (changing a custom property on the root before each
property change, which causes us to restyle the whole document to propagate it
down to all descendants).
Furthermore, we were flushing style at a time where the lwtheme attribute
change had not yet happened, and thus when the background-color changed, there
was no transition rule applicable, and the transition didn't fire.
This patch changes LightweightThemeConsumer to avoid restyling the whole
document over and over.
Also, while at it I realized that you could fool the sanitizer with !important
in an experiment stylesheet or with other !important rule in the page really.
It's not clear why you'd do that, but it may be worth to just making that
function completely sound, so I did that and added a test for it.
Differential Revision: https://phabricator.services.mozilla.com/D13716
2018-12-04 05:06:44 +03:00
|
|
|
|
|
|
|
this._lastExperimentData = {};
|
|
|
|
|
|
|
|
if (!active || !experiment) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
let usedVariables = [];
|
|
|
|
if (properties.colors) {
|
|
|
|
for (const property in properties.colors) {
|
|
|
|
const cssVariable = experiment.colors[property];
|
|
|
|
const value = _sanitizeCSSColor(root.ownerDocument, properties.colors[property]);
|
|
|
|
usedVariables.push([cssVariable, value]);
|
2018-07-23 20:46:40 +03:00
|
|
|
}
|
Bug 1511138 - Improve performance of LightweightThemeConsumer when setting properties, and also avoid _sanitizeCSSColor from getting fooled. r=jaws
This probably deserves a comment as of why it belongs to this bug.
This patch series caused a single, reproducible timeout on
browser_ext_themes_toolbars.js, where the transitionend event it awaits for
stops triggering.
I got fascinated by it and I decided to poke around it in rr instead of just
removing the await line, and here's what's going on.
In the previous implementation of _sanitizeCSSColor, we were not flushing style
because of the optimization bug 1363805 introduced (which wasn't supposed to
deal with out-of-document elements, but it accidentally did so).
In any case, the fact that we were not flushing style in _sanitizeCSSColor
caused us to flush style sometime later when the lwtheme attribute was already
set up, and thus the selector in here matched:
https://searchfox.org/mozilla-central/rev/cfaa5a1d48d6bc6552199e73004ecb05d0a9c921/browser/themes/shared/browser.inc.css#40
And thus caused the transition rule to apply at a time where the
background-color change happened.
Now we were flushing on getComputedStyle on every call, and in the most
inefficient way possible (changing a custom property on the root before each
property change, which causes us to restyle the whole document to propagate it
down to all descendants).
Furthermore, we were flushing style at a time where the lwtheme attribute
change had not yet happened, and thus when the background-color changed, there
was no transition rule applicable, and the transition didn't fire.
This patch changes LightweightThemeConsumer to avoid restyling the whole
document over and over.
Also, while at it I realized that you could fool the sanitizer with !important
in an experiment stylesheet or with other !important rule in the page really.
It's not clear why you'd do that, but it may be worth to just making that
function completely sound, so I did that and added a test for it.
Differential Revision: https://phabricator.services.mozilla.com/D13716
2018-12-04 05:06:44 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if (properties.images) {
|
|
|
|
for (const property in properties.images) {
|
|
|
|
const cssVariable = experiment.images[property];
|
|
|
|
usedVariables.push([cssVariable, `url(${properties.images[property]})`]);
|
2018-07-23 20:46:40 +03:00
|
|
|
}
|
Bug 1511138 - Improve performance of LightweightThemeConsumer when setting properties, and also avoid _sanitizeCSSColor from getting fooled. r=jaws
This probably deserves a comment as of why it belongs to this bug.
This patch series caused a single, reproducible timeout on
browser_ext_themes_toolbars.js, where the transitionend event it awaits for
stops triggering.
I got fascinated by it and I decided to poke around it in rr instead of just
removing the await line, and here's what's going on.
In the previous implementation of _sanitizeCSSColor, we were not flushing style
because of the optimization bug 1363805 introduced (which wasn't supposed to
deal with out-of-document elements, but it accidentally did so).
In any case, the fact that we were not flushing style in _sanitizeCSSColor
caused us to flush style sometime later when the lwtheme attribute was already
set up, and thus the selector in here matched:
https://searchfox.org/mozilla-central/rev/cfaa5a1d48d6bc6552199e73004ecb05d0a9c921/browser/themes/shared/browser.inc.css#40
And thus caused the transition rule to apply at a time where the
background-color change happened.
Now we were flushing on getComputedStyle on every call, and in the most
inefficient way possible (changing a custom property on the root before each
property change, which causes us to restyle the whole document to propagate it
down to all descendants).
Furthermore, we were flushing style at a time where the lwtheme attribute
change had not yet happened, and thus when the background-color changed, there
was no transition rule applicable, and the transition didn't fire.
This patch changes LightweightThemeConsumer to avoid restyling the whole
document over and over.
Also, while at it I realized that you could fool the sanitizer with !important
in an experiment stylesheet or with other !important rule in the page really.
It's not clear why you'd do that, but it may be worth to just making that
function completely sound, so I did that and added a test for it.
Differential Revision: https://phabricator.services.mozilla.com/D13716
2018-12-04 05:06:44 +03:00
|
|
|
}
|
|
|
|
if (properties.properties) {
|
|
|
|
for (const property in properties.properties) {
|
|
|
|
const cssVariable = experiment.properties[property];
|
|
|
|
usedVariables.push([cssVariable, properties.properties[property]]);
|
2018-12-07 21:55:24 +03:00
|
|
|
}
|
Bug 1511138 - Improve performance of LightweightThemeConsumer when setting properties, and also avoid _sanitizeCSSColor from getting fooled. r=jaws
This probably deserves a comment as of why it belongs to this bug.
This patch series caused a single, reproducible timeout on
browser_ext_themes_toolbars.js, where the transitionend event it awaits for
stops triggering.
I got fascinated by it and I decided to poke around it in rr instead of just
removing the await line, and here's what's going on.
In the previous implementation of _sanitizeCSSColor, we were not flushing style
because of the optimization bug 1363805 introduced (which wasn't supposed to
deal with out-of-document elements, but it accidentally did so).
In any case, the fact that we were not flushing style in _sanitizeCSSColor
caused us to flush style sometime later when the lwtheme attribute was already
set up, and thus the selector in here matched:
https://searchfox.org/mozilla-central/rev/cfaa5a1d48d6bc6552199e73004ecb05d0a9c921/browser/themes/shared/browser.inc.css#40
And thus caused the transition rule to apply at a time where the
background-color change happened.
Now we were flushing on getComputedStyle on every call, and in the most
inefficient way possible (changing a custom property on the root before each
property change, which causes us to restyle the whole document to propagate it
down to all descendants).
Furthermore, we were flushing style at a time where the lwtheme attribute
change had not yet happened, and thus when the background-color changed, there
was no transition rule applicable, and the transition didn't fire.
This patch changes LightweightThemeConsumer to avoid restyling the whole
document over and over.
Also, while at it I realized that you could fool the sanitizer with !important
in an experiment stylesheet or with other !important rule in the page really.
It's not clear why you'd do that, but it may be worth to just making that
function completely sound, so I did that and added a test for it.
Differential Revision: https://phabricator.services.mozilla.com/D13716
2018-12-04 05:06:44 +03:00
|
|
|
}
|
|
|
|
for (const [variable, value] of usedVariables) {
|
|
|
|
_setProperty(root, true, variable, value);
|
|
|
|
}
|
|
|
|
this._lastExperimentData.usedVariables = usedVariables;
|
|
|
|
|
|
|
|
if (experiment.stylesheet) {
|
|
|
|
/* Stylesheet URLs are validated using WebExtension schemas */
|
|
|
|
let stylesheetAttr = `href="${experiment.stylesheet}" type="text/css"`;
|
|
|
|
let stylesheet = this._doc.createProcessingInstruction("xml-stylesheet",
|
|
|
|
stylesheetAttr);
|
|
|
|
this._doc.insertBefore(stylesheet, root);
|
|
|
|
this._lastExperimentData.stylesheet = stylesheet;
|
2018-07-23 20:46:40 +03:00
|
|
|
}
|
2018-08-31 08:59:17 +03:00
|
|
|
},
|
2017-10-15 21:50:30 +03:00
|
|
|
};
|
2009-09-04 14:58:18 +04:00
|
|
|
|
2018-04-12 23:48:23 +03:00
|
|
|
function _getContentProperties(doc, active, data) {
|
|
|
|
if (!active) {
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
let properties = {};
|
|
|
|
for (let property in data) {
|
|
|
|
if (ThemeContentPropertyList.includes(property)) {
|
|
|
|
properties[property] = _parseRGBA(_sanitizeCSSColor(doc, data[property]));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return properties;
|
|
|
|
}
|
|
|
|
|
2017-03-31 15:48:44 +03:00
|
|
|
function _setImage(aRoot, aActive, aVariableName, aURLs) {
|
|
|
|
if (aURLs && !Array.isArray(aURLs)) {
|
|
|
|
aURLs = [aURLs];
|
|
|
|
}
|
|
|
|
_setProperty(aRoot, aActive, aVariableName, aURLs && aURLs.map(v => `url("${v.replace(/"/g, '\\"')}")`).join(","));
|
|
|
|
}
|
|
|
|
|
2018-02-02 17:54:52 +03:00
|
|
|
function _setProperty(elem, active, variableName, value) {
|
2017-03-31 15:48:44 +03:00
|
|
|
if (active && value) {
|
2018-02-02 17:54:52 +03:00
|
|
|
elem.style.setProperty(variableName, value);
|
2017-02-22 22:13:09 +03:00
|
|
|
} else {
|
2018-02-02 17:54:52 +03:00
|
|
|
elem.style.removeProperty(variableName);
|
2017-02-22 22:13:09 +03:00
|
|
|
}
|
2009-09-04 14:58:18 +04:00
|
|
|
}
|
|
|
|
|
2018-03-27 14:40:06 +03:00
|
|
|
function _setProperties(root, active, themeData) {
|
Bug 1511138 - Improve performance of LightweightThemeConsumer when setting properties, and also avoid _sanitizeCSSColor from getting fooled. r=jaws
This probably deserves a comment as of why it belongs to this bug.
This patch series caused a single, reproducible timeout on
browser_ext_themes_toolbars.js, where the transitionend event it awaits for
stops triggering.
I got fascinated by it and I decided to poke around it in rr instead of just
removing the await line, and here's what's going on.
In the previous implementation of _sanitizeCSSColor, we were not flushing style
because of the optimization bug 1363805 introduced (which wasn't supposed to
deal with out-of-document elements, but it accidentally did so).
In any case, the fact that we were not flushing style in _sanitizeCSSColor
caused us to flush style sometime later when the lwtheme attribute was already
set up, and thus the selector in here matched:
https://searchfox.org/mozilla-central/rev/cfaa5a1d48d6bc6552199e73004ecb05d0a9c921/browser/themes/shared/browser.inc.css#40
And thus caused the transition rule to apply at a time where the
background-color change happened.
Now we were flushing on getComputedStyle on every call, and in the most
inefficient way possible (changing a custom property on the root before each
property change, which causes us to restyle the whole document to propagate it
down to all descendants).
Furthermore, we were flushing style at a time where the lwtheme attribute
change had not yet happened, and thus when the background-color changed, there
was no transition rule applicable, and the transition didn't fire.
This patch changes LightweightThemeConsumer to avoid restyling the whole
document over and over.
Also, while at it I realized that you could fool the sanitizer with !important
in an experiment stylesheet or with other !important rule in the page really.
It's not clear why you'd do that, but it may be worth to just making that
function completely sound, so I did that and added a test for it.
Differential Revision: https://phabricator.services.mozilla.com/D13716
2018-12-04 05:06:44 +03:00
|
|
|
let properties = [];
|
|
|
|
|
2018-02-07 08:22:22 +03:00
|
|
|
for (let map of [toolkitVariableMap, ThemeVariableMap]) {
|
2018-03-27 14:40:06 +03:00
|
|
|
for (let [cssVarName, definition] of map) {
|
|
|
|
const {
|
|
|
|
lwtProperty,
|
|
|
|
optionalElementID,
|
|
|
|
processColor,
|
2018-08-31 08:59:17 +03:00
|
|
|
isColor = true,
|
2018-03-27 14:40:06 +03:00
|
|
|
} = definition;
|
2018-02-07 08:22:22 +03:00
|
|
|
let elem = optionalElementID ? root.ownerDocument.getElementById(optionalElementID)
|
|
|
|
: root;
|
2018-03-27 14:40:06 +03:00
|
|
|
let val = themeData[lwtProperty];
|
|
|
|
if (isColor) {
|
|
|
|
val = _sanitizeCSSColor(root.ownerDocument, val);
|
|
|
|
if (processColor) {
|
|
|
|
val = processColor(_parseRGBA(val), elem);
|
|
|
|
}
|
|
|
|
}
|
Bug 1511138 - Improve performance of LightweightThemeConsumer when setting properties, and also avoid _sanitizeCSSColor from getting fooled. r=jaws
This probably deserves a comment as of why it belongs to this bug.
This patch series caused a single, reproducible timeout on
browser_ext_themes_toolbars.js, where the transitionend event it awaits for
stops triggering.
I got fascinated by it and I decided to poke around it in rr instead of just
removing the await line, and here's what's going on.
In the previous implementation of _sanitizeCSSColor, we were not flushing style
because of the optimization bug 1363805 introduced (which wasn't supposed to
deal with out-of-document elements, but it accidentally did so).
In any case, the fact that we were not flushing style in _sanitizeCSSColor
caused us to flush style sometime later when the lwtheme attribute was already
set up, and thus the selector in here matched:
https://searchfox.org/mozilla-central/rev/cfaa5a1d48d6bc6552199e73004ecb05d0a9c921/browser/themes/shared/browser.inc.css#40
And thus caused the transition rule to apply at a time where the
background-color change happened.
Now we were flushing on getComputedStyle on every call, and in the most
inefficient way possible (changing a custom property on the root before each
property change, which causes us to restyle the whole document to propagate it
down to all descendants).
Furthermore, we were flushing style at a time where the lwtheme attribute
change had not yet happened, and thus when the background-color changed, there
was no transition rule applicable, and the transition didn't fire.
This patch changes LightweightThemeConsumer to avoid restyling the whole
document over and over.
Also, while at it I realized that you could fool the sanitizer with !important
in an experiment stylesheet or with other !important rule in the page really.
It's not clear why you'd do that, but it may be worth to just making that
function completely sound, so I did that and added a test for it.
Differential Revision: https://phabricator.services.mozilla.com/D13716
2018-12-04 05:06:44 +03:00
|
|
|
properties.push([elem, cssVarName, val]);
|
2018-02-07 08:22:22 +03:00
|
|
|
}
|
2017-06-15 20:20:26 +03:00
|
|
|
}
|
Bug 1511138 - Improve performance of LightweightThemeConsumer when setting properties, and also avoid _sanitizeCSSColor from getting fooled. r=jaws
This probably deserves a comment as of why it belongs to this bug.
This patch series caused a single, reproducible timeout on
browser_ext_themes_toolbars.js, where the transitionend event it awaits for
stops triggering.
I got fascinated by it and I decided to poke around it in rr instead of just
removing the await line, and here's what's going on.
In the previous implementation of _sanitizeCSSColor, we were not flushing style
because of the optimization bug 1363805 introduced (which wasn't supposed to
deal with out-of-document elements, but it accidentally did so).
In any case, the fact that we were not flushing style in _sanitizeCSSColor
caused us to flush style sometime later when the lwtheme attribute was already
set up, and thus the selector in here matched:
https://searchfox.org/mozilla-central/rev/cfaa5a1d48d6bc6552199e73004ecb05d0a9c921/browser/themes/shared/browser.inc.css#40
And thus caused the transition rule to apply at a time where the
background-color change happened.
Now we were flushing on getComputedStyle on every call, and in the most
inefficient way possible (changing a custom property on the root before each
property change, which causes us to restyle the whole document to propagate it
down to all descendants).
Furthermore, we were flushing style at a time where the lwtheme attribute
change had not yet happened, and thus when the background-color changed, there
was no transition rule applicable, and the transition didn't fire.
This patch changes LightweightThemeConsumer to avoid restyling the whole
document over and over.
Also, while at it I realized that you could fool the sanitizer with !important
in an experiment stylesheet or with other !important rule in the page really.
It's not clear why you'd do that, but it may be worth to just making that
function completely sound, so I did that and added a test for it.
Differential Revision: https://phabricator.services.mozilla.com/D13716
2018-12-04 05:06:44 +03:00
|
|
|
|
|
|
|
// Set all the properties together, since _sanitizeCSSColor flushes.
|
|
|
|
for (const [elem, cssVarName, val] of properties) {
|
|
|
|
_setProperty(elem, active, cssVarName, val);
|
|
|
|
}
|
2017-06-15 20:20:26 +03:00
|
|
|
}
|
|
|
|
|
2018-03-27 14:40:06 +03:00
|
|
|
function _sanitizeCSSColor(doc, cssColor) {
|
|
|
|
if (!cssColor) {
|
|
|
|
return null;
|
2018-02-11 20:32:33 +03:00
|
|
|
}
|
2018-04-11 22:05:13 +03:00
|
|
|
const HTML_NS = "http://www.w3.org/1999/xhtml";
|
|
|
|
// style.color normalizes color values and makes invalid ones black, so a
|
2018-03-27 14:40:06 +03:00
|
|
|
// simple round trip gets us a sanitized color value.
|
Bug 1511138 - Improve performance of LightweightThemeConsumer when setting properties, and also avoid _sanitizeCSSColor from getting fooled. r=jaws
This probably deserves a comment as of why it belongs to this bug.
This patch series caused a single, reproducible timeout on
browser_ext_themes_toolbars.js, where the transitionend event it awaits for
stops triggering.
I got fascinated by it and I decided to poke around it in rr instead of just
removing the await line, and here's what's going on.
In the previous implementation of _sanitizeCSSColor, we were not flushing style
because of the optimization bug 1363805 introduced (which wasn't supposed to
deal with out-of-document elements, but it accidentally did so).
In any case, the fact that we were not flushing style in _sanitizeCSSColor
caused us to flush style sometime later when the lwtheme attribute was already
set up, and thus the selector in here matched:
https://searchfox.org/mozilla-central/rev/cfaa5a1d48d6bc6552199e73004ecb05d0a9c921/browser/themes/shared/browser.inc.css#40
And thus caused the transition rule to apply at a time where the
background-color change happened.
Now we were flushing on getComputedStyle on every call, and in the most
inefficient way possible (changing a custom property on the root before each
property change, which causes us to restyle the whole document to propagate it
down to all descendants).
Furthermore, we were flushing style at a time where the lwtheme attribute
change had not yet happened, and thus when the background-color changed, there
was no transition rule applicable, and the transition didn't fire.
This patch changes LightweightThemeConsumer to avoid restyling the whole
document over and over.
Also, while at it I realized that you could fool the sanitizer with !important
in an experiment stylesheet or with other !important rule in the page really.
It's not clear why you'd do that, but it may be worth to just making that
function completely sound, so I did that and added a test for it.
Differential Revision: https://phabricator.services.mozilla.com/D13716
2018-12-04 05:06:44 +03:00
|
|
|
// Use !important so that the theme's stylesheets cannot override us.
|
2018-04-11 22:05:13 +03:00
|
|
|
let div = doc.createElementNS(HTML_NS, "div");
|
Bug 1511138 - Improve performance of LightweightThemeConsumer when setting properties, and also avoid _sanitizeCSSColor from getting fooled. r=jaws
This probably deserves a comment as of why it belongs to this bug.
This patch series caused a single, reproducible timeout on
browser_ext_themes_toolbars.js, where the transitionend event it awaits for
stops triggering.
I got fascinated by it and I decided to poke around it in rr instead of just
removing the await line, and here's what's going on.
In the previous implementation of _sanitizeCSSColor, we were not flushing style
because of the optimization bug 1363805 introduced (which wasn't supposed to
deal with out-of-document elements, but it accidentally did so).
In any case, the fact that we were not flushing style in _sanitizeCSSColor
caused us to flush style sometime later when the lwtheme attribute was already
set up, and thus the selector in here matched:
https://searchfox.org/mozilla-central/rev/cfaa5a1d48d6bc6552199e73004ecb05d0a9c921/browser/themes/shared/browser.inc.css#40
And thus caused the transition rule to apply at a time where the
background-color change happened.
Now we were flushing on getComputedStyle on every call, and in the most
inefficient way possible (changing a custom property on the root before each
property change, which causes us to restyle the whole document to propagate it
down to all descendants).
Furthermore, we were flushing style at a time where the lwtheme attribute
change had not yet happened, and thus when the background-color changed, there
was no transition rule applicable, and the transition didn't fire.
This patch changes LightweightThemeConsumer to avoid restyling the whole
document over and over.
Also, while at it I realized that you could fool the sanitizer with !important
in an experiment stylesheet or with other !important rule in the page really.
It's not clear why you'd do that, but it may be worth to just making that
function completely sound, so I did that and added a test for it.
Differential Revision: https://phabricator.services.mozilla.com/D13716
2018-12-04 05:06:44 +03:00
|
|
|
div.style.setProperty("color", "black", "important");
|
|
|
|
div.style.setProperty("display", "none", "important");
|
2018-04-11 22:05:13 +03:00
|
|
|
let span = doc.createElementNS(HTML_NS, "span");
|
Bug 1511138 - Improve performance of LightweightThemeConsumer when setting properties, and also avoid _sanitizeCSSColor from getting fooled. r=jaws
This probably deserves a comment as of why it belongs to this bug.
This patch series caused a single, reproducible timeout on
browser_ext_themes_toolbars.js, where the transitionend event it awaits for
stops triggering.
I got fascinated by it and I decided to poke around it in rr instead of just
removing the await line, and here's what's going on.
In the previous implementation of _sanitizeCSSColor, we were not flushing style
because of the optimization bug 1363805 introduced (which wasn't supposed to
deal with out-of-document elements, but it accidentally did so).
In any case, the fact that we were not flushing style in _sanitizeCSSColor
caused us to flush style sometime later when the lwtheme attribute was already
set up, and thus the selector in here matched:
https://searchfox.org/mozilla-central/rev/cfaa5a1d48d6bc6552199e73004ecb05d0a9c921/browser/themes/shared/browser.inc.css#40
And thus caused the transition rule to apply at a time where the
background-color change happened.
Now we were flushing on getComputedStyle on every call, and in the most
inefficient way possible (changing a custom property on the root before each
property change, which causes us to restyle the whole document to propagate it
down to all descendants).
Furthermore, we were flushing style at a time where the lwtheme attribute
change had not yet happened, and thus when the background-color changed, there
was no transition rule applicable, and the transition didn't fire.
This patch changes LightweightThemeConsumer to avoid restyling the whole
document over and over.
Also, while at it I realized that you could fool the sanitizer with !important
in an experiment stylesheet or with other !important rule in the page really.
It's not clear why you'd do that, but it may be worth to just making that
function completely sound, so I did that and added a test for it.
Differential Revision: https://phabricator.services.mozilla.com/D13716
2018-12-04 05:06:44 +03:00
|
|
|
span.style.setProperty("color", cssColor, "important");
|
2018-11-30 14:40:25 +03:00
|
|
|
|
|
|
|
// CSS variables are not allowed and should compute to black.
|
Bug 1511138 - Improve performance of LightweightThemeConsumer when setting properties, and also avoid _sanitizeCSSColor from getting fooled. r=jaws
This probably deserves a comment as of why it belongs to this bug.
This patch series caused a single, reproducible timeout on
browser_ext_themes_toolbars.js, where the transitionend event it awaits for
stops triggering.
I got fascinated by it and I decided to poke around it in rr instead of just
removing the await line, and here's what's going on.
In the previous implementation of _sanitizeCSSColor, we were not flushing style
because of the optimization bug 1363805 introduced (which wasn't supposed to
deal with out-of-document elements, but it accidentally did so).
In any case, the fact that we were not flushing style in _sanitizeCSSColor
caused us to flush style sometime later when the lwtheme attribute was already
set up, and thus the selector in here matched:
https://searchfox.org/mozilla-central/rev/cfaa5a1d48d6bc6552199e73004ecb05d0a9c921/browser/themes/shared/browser.inc.css#40
And thus caused the transition rule to apply at a time where the
background-color change happened.
Now we were flushing on getComputedStyle on every call, and in the most
inefficient way possible (changing a custom property on the root before each
property change, which causes us to restyle the whole document to propagate it
down to all descendants).
Furthermore, we were flushing style at a time where the lwtheme attribute
change had not yet happened, and thus when the background-color changed, there
was no transition rule applicable, and the transition didn't fire.
This patch changes LightweightThemeConsumer to avoid restyling the whole
document over and over.
Also, while at it I realized that you could fool the sanitizer with !important
in an experiment stylesheet or with other !important rule in the page really.
It's not clear why you'd do that, but it may be worth to just making that
function completely sound, so I did that and added a test for it.
Differential Revision: https://phabricator.services.mozilla.com/D13716
2018-12-04 05:06:44 +03:00
|
|
|
if (span.style.color.includes("var(")) {
|
2018-11-30 14:40:25 +03:00
|
|
|
span.style.color = "";
|
|
|
|
}
|
|
|
|
|
2018-04-11 22:05:13 +03:00
|
|
|
div.appendChild(span);
|
2018-11-30 14:40:25 +03:00
|
|
|
doc.documentElement.appendChild(div);
|
2018-03-27 14:40:06 +03:00
|
|
|
cssColor = doc.defaultView.getComputedStyle(span).color;
|
2018-11-30 14:40:25 +03:00
|
|
|
div.remove();
|
2018-03-27 14:40:06 +03:00
|
|
|
return cssColor;
|
|
|
|
}
|
2018-02-11 20:32:33 +03:00
|
|
|
|
2018-03-27 14:40:06 +03:00
|
|
|
function _parseRGBA(aColorString) {
|
|
|
|
if (!aColorString) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
var rgba = aColorString.replace(/(rgba?\()|(\)$)/g, "").split(",");
|
|
|
|
rgba = rgba.map(x => parseFloat(x));
|
|
|
|
return {
|
|
|
|
r: rgba[0],
|
|
|
|
g: rgba[1],
|
|
|
|
b: rgba[2],
|
2018-04-11 22:05:13 +03:00
|
|
|
a: 3 in rgba ? rgba[3] : 1,
|
2018-03-27 14:40:06 +03:00
|
|
|
};
|
2018-02-11 20:32:33 +03:00
|
|
|
}
|
2018-04-26 12:48:22 +03:00
|
|
|
|
2018-05-26 19:45:06 +03:00
|
|
|
function _isTextColorDark(r, g, b) {
|
|
|
|
return (0.2125 * r + 0.7154 * g + 0.0721 * b) <= 110;
|
2018-04-26 12:48:22 +03:00
|
|
|
}
|