From 7620721be30ad8025162398093001e72c3d57e16 Mon Sep 17 00:00:00 2001 From: Tim Nguyen Date: Thu, 12 Apr 2018 16:48:23 -0400 Subject: [PATCH] Bug 1347204 - Implement the colors.ntp_background and colors.ntp_text properties. r=mconley MozReview-Commit-ID: En8HajryiJS --HG-- extra : rebase_source : b0b321418a68c134772616cc47ab883f8ffb9078 --- browser/base/content/contentTheme.js | 108 ++++++++++ browser/base/content/tab-content.js | 29 +++ .../performance/browser_startup_content.js | 1 + browser/base/jar.mn | 1 + browser/components/nsBrowserGlue.js | 2 + .../modules/LightweightThemeChildListener.jsm | 82 ++++++++ browser/modules/ThemeVariableMap.jsm | 7 +- browser/modules/moz.build | 4 + .../components/extensions/parent/ext-theme.js | 2 + .../components/extensions/schemas/theme.json | 8 + .../extensions/test/browser/browser.ini | 2 + .../browser/browser_ext_themes_ntp_colors.js | 103 ++++++++++ ...browser_ext_themes_ntp_colors_perwindow.js | 188 ++++++++++++++++++ toolkit/modules/LightweightThemeConsumer.jsm | 34 +++- 14 files changed, 568 insertions(+), 3 deletions(-) create mode 100644 browser/base/content/contentTheme.js create mode 100644 browser/modules/LightweightThemeChildListener.jsm create mode 100644 toolkit/components/extensions/test/browser/browser_ext_themes_ntp_colors.js create mode 100644 toolkit/components/extensions/test/browser/browser_ext_themes_ntp_colors_perwindow.js diff --git a/browser/base/content/contentTheme.js b/browser/base/content/contentTheme.js new file mode 100644 index 000000000000..d57f70b3b3b8 --- /dev/null +++ b/browser/base/content/contentTheme.js @@ -0,0 +1,108 @@ +/* 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/. */ + +"use strict"; + +{ + +function _isTextColorDark(r, g, b) { + return (0.2125 * r + 0.7154 * g + 0.0721 * b) <= 110; +} + +const inContentVariableMap = [ + ["--newtab-background-color", { + lwtProperty: "ntp_background" + }], + ["--newtab-text-primary-color", { + lwtProperty: "ntp_text", + processColor(rgbaChannels, element) { + if (!rgbaChannels) { + element.removeAttribute("lwt-newtab"); + element.removeAttribute("lwt-newtab-brighttext"); + return null; + } + + element.setAttribute("lwt-newtab", "true"); + const {r, g, b, a} = rgbaChannels; + if (!_isTextColorDark(r, g, b)) { + element.setAttribute("lwt-newtab-brighttext", "true"); + } + + return `rgba(${r}, ${g}, ${b}, ${a})`; + }, + }], +]; + +/** + * ContentThemeController handles theme updates sent by the frame script. + * To be able to use ContentThemeController, you must add your page to the whitelist + * in LightweightThemeChildListener.jsm + */ +const ContentThemeController = { + /** + * Tell the frame script that the page supports theming, and watch for updates + * from the frame script. + */ + init() { + addEventListener("LightweightTheme:Set", this); + + const event = new CustomEvent("LightweightTheme:Support", {bubbles: true}); + document.dispatchEvent(event); + }, + + /** + * Handle theme updates from the frame script. + * @param event object containing the theme update. + */ + handleEvent({ detail }) { + if (detail.type == "LightweightTheme:Update") { + let {data} = detail; + if (!data) { + data = {}; + } + this._setProperties(document.body, data); + } + }, + + /** + * Set a CSS variable to a given value + * @param elem The element where the CSS variable should be added. + * @param variableName The CSS variable to set. + * @param value The new value of the CSS variable. + */ + _setProperty(elem, variableName, value) { + if (value) { + elem.style.setProperty(variableName, value); + } else { + elem.style.removeProperty(variableName); + } + }, + + /** + * Apply theme data to an element + * @param root The element where the properties should be applied. + * @param themeData The theme data. + */ + _setProperties(elem, themeData) { + for (let [cssVarName, definition] of inContentVariableMap) { + const { + lwtProperty, + processColor, + } = definition; + let value = themeData[lwtProperty]; + + if (processColor) { + value = processColor(value, document.body); + } else if (value) { + const {r, g, b, a} = value; + value = `rgba(${r}, ${g}, ${b}, ${a})`; + } + + this._setProperty(elem, cssVarName, value); + } + }, +}; +ContentThemeController.init(); + +} diff --git a/browser/base/content/tab-content.js b/browser/base/content/tab-content.js index a2d8afa0767b..a43d4312a460 100644 --- a/browser/base/content/tab-content.js +++ b/browser/base/content/tab-content.js @@ -24,6 +24,8 @@ ChromeUtils.defineModuleGetter(this, "ReaderMode", "resource://gre/modules/ReaderMode.jsm"); ChromeUtils.defineModuleGetter(this, "PageStyleHandler", "resource:///modules/PageStyleHandler.jsm"); +ChromeUtils.defineModuleGetter(this, "LightweightThemeChildListener", + "resource:///modules/LightweightThemeChildListener.jsm"); // TabChildGlobal var global = this; @@ -79,6 +81,33 @@ addMessageListener("MixedContent:ReenableProtection", function() { docShell.mixedContentChannel = null; }); +var LightweightThemeChildListenerStub = { + _childListener: null, + get childListener() { + if (!this._childListener) { + this._childListener = new LightweightThemeChildListener(); + } + return this._childListener; + }, + + init() { + addEventListener("LightweightTheme:Support", this, false, true); + addMessageListener("LightweightTheme:Update", this); + sendAsyncMessage("LightweightTheme:Request"); + }, + + handleEvent(event) { + return this.childListener.handleEvent(event); + }, + + receiveMessage(msg) { + return this.childListener.receiveMessage(msg); + }, +}; + +LightweightThemeChildListenerStub.init(); + + var AboutReaderListener = { _articlePromise: null, diff --git a/browser/base/content/test/performance/browser_startup_content.js b/browser/base/content/test/performance/browser_startup_content.js index 12eb1c1dc9e9..5676af5042c0 100644 --- a/browser/base/content/test/performance/browser_startup_content.js +++ b/browser/base/content/test/performance/browser_startup_content.js @@ -56,6 +56,7 @@ const whitelist = { "resource:///modules/ContentLinkHandler.jsm", "resource:///modules/ContentMetaHandler.jsm", "resource:///modules/PageStyleHandler.jsm", + "resource:///modules/LightweightThemeChildListener.jsm", "resource://gre/modules/BrowserUtils.jsm", "resource://gre/modules/E10SUtils.jsm", "resource://gre/modules/PrivateBrowsingUtils.jsm", diff --git a/browser/base/jar.mn b/browser/base/jar.mn index 2c711aa3110f..e9d158ab5687 100644 --- a/browser/base/jar.mn +++ b/browser/base/jar.mn @@ -101,6 +101,7 @@ browser.jar: content/browser/webext-panels.js (content/webext-panels.js) * content/browser/webext-panels.xul (content/webext-panels.xul) content/browser/nsContextMenu.js (content/nsContextMenu.js) + content/browser/contentTheme.js (content/contentTheme.js) #ifdef XP_MACOSX # XXX: We should exclude this one as well (bug 71895) * content/browser/hiddenWindow.xul (content/hiddenWindow.xul) diff --git a/browser/components/nsBrowserGlue.js b/browser/components/nsBrowserGlue.js index 8cb47c4989dd..82f8b06cc697 100644 --- a/browser/components/nsBrowserGlue.js +++ b/browser/components/nsBrowserGlue.js @@ -760,6 +760,8 @@ BrowserGlue.prototype = { popup_border: "#27272b", toolbar_field_text: "rgb(249, 249, 250)", toolbar_field_border: "rgba(249, 249, 250, 0.2)", + ntp_background: "#2A2A2E", + ntp_text: "rgb(249, 249, 250)", author: vendorShortName, }, { useInDarkMode: true diff --git a/browser/modules/LightweightThemeChildListener.jsm b/browser/modules/LightweightThemeChildListener.jsm new file mode 100644 index 000000000000..06caa721210e --- /dev/null +++ b/browser/modules/LightweightThemeChildListener.jsm @@ -0,0 +1,82 @@ +/* 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/. */ + +"use strict"; + +/** + * LightweightThemeChildListener forwards theme updates from LightweightThemeConsumer to + * the whitelisted in-content pages + */ +class LightweightThemeChildListener { + constructor() { + /** + * The pages that will receive theme updates + */ + this.whitelist = new Set([ + "about:home", + "about:newtab", + "about:welcome", + ]); + + /** + * The last theme data received from LightweightThemeConsumer + */ + this._lastData = null; + } + + /** + * Handles theme updates from the parent process + * @param message from the parent process. + */ + receiveMessage({ name, data, target }) { + if (name == "LightweightTheme:Update") { + this._lastData = data; + this._update(data, target.content); + } + } + + /** + * Handles events from the content scope. + * @param event The received event. + */ + handleEvent(event) { + const content = event.originalTarget.defaultView; + if (content != content.top) { + return; + } + + if (event.type == "LightweightTheme:Support") { + this._update(this._lastData, content); + } + } + + /** + * Checks if a given global is allowed to receive theme updates + * @param content The global to check against. + * @returns true if the global is allowed to receive updates, false otherwise. + */ + _isContentWhitelisted(content) { + return this.whitelist.has(content.document.documentURI); + } + + /** + * Forward the theme data to the page. + * @param data The theme data to forward + * @param content The receiving global + */ + _update(data, content) { + if (this._isContentWhitelisted(content)) { + const event = Cu.cloneInto({ + detail: { + type: "LightweightTheme:Update", + data, + }, + }, content); + content.dispatchEvent(new content.CustomEvent("LightweightTheme:Set", + event)); + } + } +} + +var EXPORTED_SYMBOLS = ["LightweightThemeChildListener"]; diff --git a/browser/modules/ThemeVariableMap.jsm b/browser/modules/ThemeVariableMap.jsm index 2bbe9e8b6f7a..8e16f8248549 100644 --- a/browser/modules/ThemeVariableMap.jsm +++ b/browser/modules/ThemeVariableMap.jsm @@ -2,7 +2,7 @@ * 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 = ["ThemeVariableMap"]; +var EXPORTED_SYMBOLS = ["ThemeVariableMap", "ThemeContentPropertyList"]; const ThemeVariableMap = [ ["--lwt-accent-color-inactive", { @@ -80,3 +80,8 @@ const ThemeVariableMap = [ lwtProperty: "popup_highlight_text" }], ]; + +const ThemeContentPropertyList = [ + "ntp_background", + "ntp_text", +]; diff --git a/browser/modules/moz.build b/browser/modules/moz.build index 69eb3fe59003..66b1c07475fb 100644 --- a/browser/modules/moz.build +++ b/browser/modules/moz.build @@ -70,6 +70,9 @@ with Files("ExtensionsUI.jsm"): with Files("LaterRun.jsm"): BUG_COMPONENT = ("Firefox", "Tours") +with Files("LightweightThemeChildListener.jsm"): + BUG_COMPONENT = ("WebExtensions", "Themes") + with Files("LightWeightThemeWebInstallListener.jsm"): BUG_COMPONENT = ("Firefox", "Theme") @@ -155,6 +158,7 @@ EXTRA_JS_MODULES += [ 'FormSubmitObserver.jsm', 'FormValidationHandler.jsm', 'LaterRun.jsm', + 'LightweightThemeChildListener.jsm', 'LightWeightThemeWebInstallListener.jsm', 'NetErrorContent.jsm', 'OpenInTabsUtils.jsm', diff --git a/toolkit/components/extensions/parent/ext-theme.js b/toolkit/components/extensions/parent/ext-theme.js index 4c549d74e9e8..ff02ac72f943 100644 --- a/toolkit/components/extensions/parent/ext-theme.js +++ b/toolkit/components/extensions/parent/ext-theme.js @@ -170,6 +170,8 @@ class Theme { case "popup_border": case "popup_highlight": case "popup_highlight_text": + case "ntp_background": + case "ntp_text": this.lwtStyles[color] = cssColor; break; } diff --git a/toolkit/components/extensions/schemas/theme.json b/toolkit/components/extensions/schemas/theme.json index 96e87b1a4008..9bfbd699abb3 100644 --- a/toolkit/components/extensions/schemas/theme.json +++ b/toolkit/components/extensions/schemas/theme.json @@ -196,6 +196,14 @@ "popup_highlight_text": { "$ref": "ThemeColor", "optional": true + }, + "ntp_background": { + "$ref": "ThemeColor", + "optional": true + }, + "ntp_text": { + "$ref": "ThemeColor", + "optional": true } }, "additionalProperties": { "$ref": "UnrecognizedProperty" } diff --git a/toolkit/components/extensions/test/browser/browser.ini b/toolkit/components/extensions/test/browser/browser.ini index ce0d3c04f8f4..31d920e4d8f1 100644 --- a/toolkit/components/extensions/test/browser/browser.ini +++ b/toolkit/components/extensions/test/browser/browser.ini @@ -12,6 +12,8 @@ skip-if = verify [browser_ext_themes_getCurrent_differentExt.js] [browser_ext_themes_lwtsupport.js] [browser_ext_themes_multiple_backgrounds.js] +[browser_ext_themes_ntp_colors.js] +[browser_ext_themes_ntp_colors_perwindow.js] [browser_ext_themes_persistence.js] [browser_ext_themes_separators.js] [browser_ext_themes_static_onUpdated.js] diff --git a/toolkit/components/extensions/test/browser/browser_ext_themes_ntp_colors.js b/toolkit/components/extensions/test/browser/browser_ext_themes_ntp_colors.js new file mode 100644 index 000000000000..d2b6c12ed07f --- /dev/null +++ b/toolkit/components/extensions/test/browser/browser_ext_themes_ntp_colors.js @@ -0,0 +1,103 @@ +"use strict"; + +// This test checks whether the new tab page color properties work. + +/** + * Test whether the selected browser has the new tab page theme applied + * @param theme that is applied + * @param isBrightText whether the brighttext attribute should be set + */ +async function test_ntp_theme(theme, isBrightText) { + let extension = ExtensionTestUtils.loadExtension({ + manifest: { + theme, + }, + }); + + let browser = gBrowser.selectedBrowser; + + let { + originalBackground, + originalColor, + } = await ContentTask.spawn(browser, {}, function() { + let doc = content.document; + ok(!doc.body.hasAttribute("lwt-newtab"), + "New tab page should not have lwt-newtab attribute"); + ok(!doc.body.hasAttribute("lwt-newtab-brighttext"), + `New tab page should not have lwt-newtab-brighttext attribute`); + + return { + originalBackground: content.getComputedStyle(doc.body).backgroundColor, + originalColor: content.getComputedStyle(doc.querySelector(".outer-wrapper")).color, + }; + }); + + await extension.startup(); + + await ContentTask.spawn(browser, { + isBrightText, + background: hexToCSS(theme.colors.ntp_background), + color: hexToCSS(theme.colors.ntp_text), + }, function({isBrightText, background, color}) { + let doc = content.document; + ok(doc.body.hasAttribute("lwt-newtab"), + "New tab page should have lwt-newtab attribute"); + is(doc.body.hasAttribute("lwt-newtab-brighttext"), isBrightText, + `New tab page should${!isBrightText ? " not" : ""} have lwt-newtab-brighttext attribute`); + + is(content.getComputedStyle(doc.body).backgroundColor, background, + "New tab page background should be set."); + is(content.getComputedStyle(doc.querySelector(".outer-wrapper")).color, color, + "New tab page text color should be set."); + }); + + await extension.unload(); + + await ContentTask.spawn(browser, { + originalBackground, + originalColor, + }, function({originalBackground, originalColor}) { + let doc = content.document; + ok(!doc.body.hasAttribute("lwt-newtab"), + "New tab page should not have lwt-newtab attribute"); + ok(!doc.body.hasAttribute("lwt-newtab-brighttext"), + `New tab page should not have lwt-newtab-brighttext attribute`); + + is(content.getComputedStyle(doc.body).backgroundColor, originalBackground, + "New tab page background should be reset."); + is(content.getComputedStyle(doc.querySelector(".outer-wrapper")).color, originalColor, + "New tab page text color should be reset."); + }); +} + +add_task(async function test_support_ntp_colors() { + // BrowserTestUtils.withNewTab waits for about:newtab to load + // so we disable preloading before running the test. + SpecialPowers.setBoolPref("browser.newtab.preload", false); + registerCleanupFunction(() => { + SpecialPowers.clearUserPref("browser.newtab.preload"); + }); + gBrowser.removePreloadedBrowser(); + for (let url of ["about:newtab", "about:home", "about:welcome"]) { + info("Opening url: " + url); + await BrowserTestUtils.withNewTab({gBrowser, url}, async browser => { + await test_ntp_theme({ + colors: { + accentcolor: ACCENT_COLOR, + textcolor: TEXT_COLOR, + ntp_background: "#add8e6", + ntp_text: "#00008b", + }, + }, false, url); + + await test_ntp_theme({ + colors: { + accentcolor: ACCENT_COLOR, + textcolor: TEXT_COLOR, + ntp_background: "#00008b", + ntp_text: "#add8e6", + }, + }, true, url); + }); + } +}); diff --git a/toolkit/components/extensions/test/browser/browser_ext_themes_ntp_colors_perwindow.js b/toolkit/components/extensions/test/browser/browser_ext_themes_ntp_colors_perwindow.js new file mode 100644 index 000000000000..49bf09c41966 --- /dev/null +++ b/toolkit/components/extensions/test/browser/browser_ext_themes_ntp_colors_perwindow.js @@ -0,0 +1,188 @@ +"use strict"; + +// This test checks whether the new tab page color properties work per-window. + +/** + * Test whether a given browser has the new tab page theme applied + * @param browser to test against + * @param theme that is applied + * @param isBrightText whether the brighttext attribute should be set + */ +function test_ntp_theme(browser, theme, isBrightText) { + return ContentTask.spawn(browser, { + isBrightText, + background: hexToCSS(theme.colors.ntp_background), + color: hexToCSS(theme.colors.ntp_text), + }, function({isBrightText, background, color}) { + let doc = content.document; + ok(doc.body.hasAttribute("lwt-newtab"), + "New tab page should have lwt-newtab attribute"); + is(doc.body.hasAttribute("lwt-newtab-brighttext"), isBrightText, + `New tab page should${!isBrightText ? " not" : ""} have lwt-newtab-brighttext attribute`); + + is(content.getComputedStyle(doc.body).backgroundColor, background, + "New tab page background should be set."); + is(content.getComputedStyle(doc.querySelector(".outer-wrapper")).color, color, + "New tab page text color should be set."); + }); +} + +/** + * Test whether a given browser has the default theme applied + * @param browser to test against + */ +function test_ntp_default_theme(browser) { + return ContentTask.spawn(browser, { + background: hexToCSS("#F9F9FA"), + color: hexToCSS("#0C0C0D"), + }, function({background, color}) { + let doc = content.document; + ok(!doc.body.hasAttribute("lwt-newtab"), + "New tab page should not have lwt-newtab attribute"); + ok(!doc.body.hasAttribute("lwt-newtab-brighttext"), + `New tab page should not have lwt-newtab-brighttext attribute`); + + is(content.getComputedStyle(doc.body).backgroundColor, background, + "New tab page background should be reset."); + is(content.getComputedStyle(doc.querySelector(".outer-wrapper")).color, color, + "New tab page text color should be reset."); + }); +} + +add_task(async function test_per_window_ntp_theme() { + let extension = ExtensionTestUtils.loadExtension({ + manifest: { + permissions: ["theme"], + }, + async background() { + function promiseWindowChanged(winId) { + return new Promise(resolve => { + let listener = windowId => { + if (windowId === winId) { + browser.windows.onFocusChanged.removeListener(listener); + resolve(); + } + }; + browser.windows.onFocusChanged.addListener(listener); + }); + } + + function promiseWindowChecked() { + return new Promise(resolve => { + let listener = msg => { + if (msg == "checked-window") { + browser.test.onMessage.removeListener(listener); + resolve(); + } + }; + browser.test.onMessage.addListener(listener); + }); + } + + function createWindow() { + return new Promise(resolve => { + let listener = win => { + browser.windows.onCreated.removeListener(listener); + resolve(win); + }; + browser.windows.onCreated.addListener(listener); + browser.windows.create(); + }); + } + + function removeWindow(winId) { + return new Promise(resolve => { + let listener = removedWinId => { + if (removedWinId == winId) { + browser.windows.onRemoved.removeListener(listener); + resolve(); + } + }; + browser.windows.onRemoved.addListener(listener); + browser.windows.remove(winId); + }); + } + + async function checkWindow(theme, isBrightText, winId) { + // We query the window again to have the updated focus information + let win = await browser.windows.get(winId); + if (!win.focused) { + let focusChanged = promiseWindowChanged(win.id); + await browser.windows.update(win.id, {focused: true}); + await focusChanged; + } + + let windowChecked = promiseWindowChecked(); + browser.test.sendMessage("check-window", {theme, isBrightText}); + await windowChecked; + } + + const darkTextTheme = { + colors: { + accentcolor: "#add8e6", + textcolor: "#000", + ntp_background: "#add8e6", + ntp_text: "#000", + }, + }; + + const brightTextTheme = { + colors: { + accentcolor: "#00008b", + textcolor: "#add8e6", + ntp_background: "#00008b", + ntp_text: "#add8e6", + }, + }; + + let {id: winId} = await browser.windows.getCurrent(); + let {id: secondWinId} = await createWindow(); + + browser.test.log("Test that single window update works"); + await browser.theme.update(winId, darkTextTheme); + await checkWindow(darkTextTheme, false, winId); + await checkWindow(null, false, secondWinId); + + browser.test.log("Test that applying different themes on both windows"); + await browser.theme.update(secondWinId, brightTextTheme); + await checkWindow(darkTextTheme, false, winId); + await checkWindow(brightTextTheme, true, secondWinId); + + browser.test.log("Test resetting the theme on one window"); + await browser.theme.reset(winId); + await checkWindow(null, false, winId); + await checkWindow(brightTextTheme, true, secondWinId); + + await removeWindow(secondWinId); + await checkWindow(null, false, winId); + browser.test.notifyPass("perwindow-ntp-theme"); + }, + }); + + extension.onMessage("check-window", async ({theme, isBrightText}) => { + let win = Services.wm.getMostRecentWindow("navigator:browser"); + win.gBrowser.removePreloadedBrowser(); + for (let url of ["about:newtab", "about:home", "about:welcome"]) { + info("Opening url: " + url); + await BrowserTestUtils.withNewTab({gBrowser: win.gBrowser, url}, async browser => { + if (theme) { + await test_ntp_theme(browser, theme, isBrightText); + } else { + await test_ntp_default_theme(browser); + } + }); + } + extension.sendMessage("checked-window"); + }); + + // BrowserTestUtils.withNewTab waits for about:newtab to load + // so we disable preloading before running the test. + SpecialPowers.setBoolPref("browser.newtab.preload", false); + registerCleanupFunction(() => { + SpecialPowers.clearUserPref("browser.newtab.preload"); + }); + + await extension.startup(); + await extension.awaitFinish("perwindow-ntp-theme"); + await extension.unload(); +}); diff --git a/toolkit/modules/LightweightThemeConsumer.jsm b/toolkit/modules/LightweightThemeConsumer.jsm index b36ebf67b942..6a510805c8a1 100644 --- a/toolkit/modules/LightweightThemeConsumer.jsm +++ b/toolkit/modules/LightweightThemeConsumer.jsm @@ -99,8 +99,10 @@ const toolkitVariableMap = [ // Get the theme variables from the app resource directory. // This allows per-app variables. -ChromeUtils.import("resource:///modules/ThemeVariableMap.jsm"); - +ChromeUtils.defineModuleGetter(this, "ThemeContentPropertyList", + "resource:///modules/ThemeVariableMap.jsm"); +ChromeUtils.defineModuleGetter(this, "ThemeVariableMap", + "resource:///modules/ThemeVariableMap.jsm"); ChromeUtils.defineModuleGetter(this, "LightweightThemeImageOptimizer", "resource://gre/modules/addons/LightweightThemeImageOptimizer.jsm"); @@ -116,6 +118,7 @@ function LightweightThemeConsumer(aDocument) { this._win.addEventListener("resolutionchange", this); this._win.addEventListener("unload", this, { once: true }); + this._win.messageManager.addMessageListener("LightweightTheme:Request", this); let darkThemeMediaQuery = this._win.matchMedia("(-moz-system-dark-theme)"); darkThemeMediaQuery.addListener(temp.LightweightThemeManager); @@ -143,6 +146,13 @@ LightweightThemeConsumer.prototype = { this._update(parsedData); }, + receiveMessage({ name, target }) { + if (name == "LightweightTheme:Request") { + let contentThemeData = _getContentProperties(this._doc, this._active, this._lastData); + target.messageManager.sendAsyncMessage("LightweightTheme:Update", contentThemeData); + } + }, + handleEvent(aEvent) { switch (aEvent.type) { case "resolutionchange": @@ -204,9 +214,29 @@ LightweightThemeConsumer.prototype = { root.setAttribute("lwthemefooter", "true"); else root.removeAttribute("lwthemefooter"); + + let contentThemeData = _getContentProperties(this._doc, active, aData); + + let browserMessageManager = this._win.getGroupMessageManager("browsers"); + browserMessageManager.broadcastAsyncMessage( + "LightweightTheme:Update", contentThemeData + ); } }; +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; +} + function _setImage(aRoot, aActive, aVariableName, aURLs) { if (aURLs && !Array.isArray(aURLs)) { aURLs = [aURLs];