--- a/browser/themes/shared/browser.inc.css
+++ b/browser/themes/shared/browser.inc.css
@@ -1,44 +1,53 @@
/* 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/. */
%include downloads/indicator.inc.css
%filter substitution
%define navbarTabsShadowSize 1px
+%define themeTransition background-color 0.1s cubic-bezier(.17,.67,.83,.67)
:root {
/* Note: Setting this to 0 (without px) breaks CSS calculations for OSX. */
--space-above-tabbar: 0px;
}
:root[extradragspace][tabsintitlebar]:not([inFullscreen]) {
--space-above-tabbar: 8px;
}
+:root:-moz-lwtheme {
+ transition: @themeTransition@;
+}
+
/* Toolbar / content area border */
#navigator-toolbox::after {
content: "";
display: -moz-box;
border-bottom: 1px solid var(--toolbox-border-bottom-color);
}
:root[customizing] #navigator-toolbox::after {
border-bottom-style: none;
}
+ #nav-bar:-moz-lwtheme {
+ transition: @themeTransition@;
+}
+
/* Bookmark toolbar */
#navigator-toolbox > toolbar:not(#toolbar-menubar):not(#TabsToolbar):not(#nav-bar) {
overflow: -moz-hidden-unscrollable;
max-height: 4em;
- transition: min-height 170ms ease-out, max-height 170ms ease-out;
+ transition: min-height 170ms ease-out, max-height 170ms ease-out, @themeTransition@;
padding: 0 6px 2px;
}
#navigator-toolbox > toolbar:not(#toolbar-menubar):not(#TabsToolbar):not(#nav-bar)[collapsed=true] {
min-height: 0.1px;
max-height: 0;
transition: min-height 170ms ease-out, max-height 170ms ease-out, visibility 170ms linear;
}
--- a/toolkit/components/extensions/test/browser/browser.ini
+++ b/toolkit/components/extensions/test/browser/browser.ini
@@ -18,8 +18,9 @@ support-files =
[browser_ext_themes_tab_loading.js]
[browser_ext_themes_tab_text.js]
[browser_ext_themes_toolbar_fields.js]
[browser_ext_themes_toolbars.js]
[browser_ext_themes_toolbarbutton_icons.js]
[browser_ext_themes_toolbarbutton_colors.js]
[browser_ext_themes_arrowpanels.js]
[browser_ext_themes_tab_selected.js]
+[browser_ext_themes_theme_transition.js]
--- a/toolkit/components/extensions/test/browser/browser_ext_themes_alpha_accentcolor.js
+++ b/toolkit/components/extensions/test/browser/browser_ext_themes_alpha_accentcolor.js
@@ -18,13 +18,15 @@ add_task(async function test_alpha_accen
},
});
await extension.startup();
let docEl = window.document.documentElement;
let style = window.getComputedStyle(docEl);
+ await new Promise(resolve => setTimeout(resolve, 100));
+
Assert.equal(style.backgroundColor, "rgb(230, 128, 0)",
"Window background color should be opaque");
await extension.unload();
});
--- a/toolkit/components/extensions/test/browser/browser_ext_themes_chromeparity.js
+++ b/toolkit/components/extensions/test/browser/browser_ext_themes_chromeparity.js
@@ -25,25 +25,30 @@ add_task(async function test_support_the
"face.png": imageBufferFromDataURI(ENCODED_IMAGE_DATA),
},
});
await extension.startup();
let docEl = window.document.documentElement;
+ // wait for theme transition to end
+ await waitForTransition(docEl, "background-color");
+
Assert.ok(docEl.hasAttribute("lwtheme"), "LWT attribute should be set");
Assert.equal(docEl.getAttribute("lwthemetextcolor"), "bright",
"LWT text color attribute should be set");
let style = window.getComputedStyle(docEl);
Assert.ok(style.backgroundImage.includes("face.png"),
`The backgroundImage should use face.png. Actual value is: ${style.backgroundImage}`);
+
Assert.equal(style.backgroundColor, "rgb(" + FRAME_COLOR.join(", ") + ")",
"Expected correct background color");
+
Assert.equal(style.color, "rgba(" + TAB_TEXT_COLOR.join(", ") + ")",
"Expected correct text color");
await extension.unload();
Assert.ok(!docEl.hasAttribute("lwtheme"), "LWT attribute should not be set");
});
@@ -69,22 +74,27 @@ add_task(async function test_support_the
},
});
await extension.startup();
let docEl = window.document.documentElement;
let style = window.getComputedStyle(docEl);
+ // wait for theme transition to end
+ await waitForTransition(docEl, "background-color");
+
Assert.equal(style.backgroundColor, "rgb(" + FRAME_COLOR.join(", ") + ")",
"Window background is set to the colors.frame property");
// Now we'll open a new window to see if the inactive browser accent color changed
let window2 = await BrowserTestUtils.openNewBrowserWindow();
+ await waitForTransition(docEl, "background-color");
+
Assert.equal(style.backgroundColor, "rgb(" + FRAME_COLOR_INACTIVE.join(", ") + ")",
`Inactive window background color should be ${FRAME_COLOR_INACTIVE}`);
await BrowserTestUtils.closeWindow(window2);
await extension.unload();
Assert.ok(!docEl.hasAttribute("lwtheme"), "LWT attribute should not be set");
});
@@ -109,16 +119,19 @@ add_task(async function test_lack_of_the
},
});
await extension.startup();
let docEl = window.document.documentElement;
let style = window.getComputedStyle(docEl);
+ // wait for theme transition to end
+ await waitForTransition(docEl, "background-color");
+
Assert.equal(style.backgroundColor, "rgb(" + FRAME_COLOR.join(", ") + ")",
"Window background is set to the colors.frame property");
// Now we'll open a new window to make sure the inactive browser accent color stayed the same
let window2 = await BrowserTestUtils.openNewBrowserWindow();
Assert.equal(style.backgroundColor, "rgb(" + FRAME_COLOR.join(", ") + ")",
"Inactive window background should not change if colors.frame_inactive isn't set");
--- a/toolkit/components/extensions/test/browser/browser_ext_themes_dynamic_updates.js
+++ b/toolkit/components/extensions/test/browser/browser_ext_themes_dynamic_updates.js
@@ -10,33 +10,37 @@ const BACKGROUND_2 = "data:image/png;bas
const ACCENT_COLOR_2 = "#03fe03";
const TEXT_COLOR_2 = "#0ef325";
function hexToRGB(hex) {
hex = parseInt((hex.indexOf("#") > -1 ? hex.substring(1) : hex), 16);
return "rgb(" + [hex >> 16, (hex & 0x00FF00) >> 8, (hex & 0x0000FF)].join(", ") + ")";
}
-function validateTheme(backgroundImage, accentColor, textColor, isLWT) {
+// Themes are expected to still be in transition when function is called
+async function validateTheme(backgroundImage, accentColor, textColor, isLWT) {
let docEl = window.document.documentElement;
let style = window.getComputedStyle(docEl);
if (isLWT) {
+ // wait for theme transition to end
+ await waitForTransition(docEl, "background-color");
Assert.ok(docEl.hasAttribute("lwtheme"), "LWT attribute should be set");
Assert.equal(docEl.getAttribute("lwthemetextcolor"), "bright",
"LWT text color attribute should be set");
}
Assert.ok(style.backgroundImage.includes(backgroundImage), "Expected correct background image");
if (accentColor.startsWith("#")) {
accentColor = hexToRGB(accentColor);
}
if (textColor.startsWith("#")) {
textColor = hexToRGB(textColor);
}
+
Assert.equal(style.backgroundColor, accentColor, "Expected correct accent color");
Assert.equal(style.color, textColor, "Expected correct text color");
}
add_task(async function setup() {
await SpecialPowers.pushPrefEnv({
set: [["extensions.webextensions.themes.enabled", true]],
});
@@ -76,38 +80,38 @@ add_task(async function test_dynamic_the
"colors": {
"accentcolor": ACCENT_COLOR_1,
"textcolor": TEXT_COLOR_1,
},
});
await extension.awaitMessage("theme-updated");
- validateTheme("image1.png", ACCENT_COLOR_1, TEXT_COLOR_1, true);
+ await validateTheme("image1.png", ACCENT_COLOR_1, TEXT_COLOR_1, true);
extension.sendMessage("update-theme", {
"images": {
"headerURL": "image2.png",
},
"colors": {
"accentcolor": ACCENT_COLOR_2,
"textcolor": TEXT_COLOR_2,
},
});
await extension.awaitMessage("theme-updated");
- validateTheme("image2.png", ACCENT_COLOR_2, TEXT_COLOR_2, true);
+ await validateTheme("image2.png", ACCENT_COLOR_2, TEXT_COLOR_2, true);
extension.sendMessage("reset-theme");
await extension.awaitMessage("theme-reset");
let {backgroundImage, backgroundColor, color} = defaultStyle;
- validateTheme(backgroundImage, backgroundColor, color, false);
+ await validateTheme(backgroundImage, backgroundColor, color, false);
await extension.unload();
let docEl = window.document.documentElement;
Assert.ok(!docEl.hasAttribute("lwtheme"), "LWT attribute should not be set");
});
add_task(async function test_dynamic_theme_updates_with_data_url() {
@@ -140,36 +144,36 @@ add_task(async function test_dynamic_the
"colors": {
"accentcolor": ACCENT_COLOR_1,
"textcolor": TEXT_COLOR_1,
},
});
await extension.awaitMessage("theme-updated");
- validateTheme(BACKGROUND_1, ACCENT_COLOR_1, TEXT_COLOR_1, true);
+ await validateTheme(BACKGROUND_1, ACCENT_COLOR_1, TEXT_COLOR_1, true);
extension.sendMessage("update-theme", {
"images": {
"headerURL": BACKGROUND_2,
},
"colors": {
"accentcolor": ACCENT_COLOR_2,
"textcolor": TEXT_COLOR_2,
},
});
await extension.awaitMessage("theme-updated");
- validateTheme(BACKGROUND_2, ACCENT_COLOR_2, TEXT_COLOR_2, true);
+ await validateTheme(BACKGROUND_2, ACCENT_COLOR_2, TEXT_COLOR_2, true);
extension.sendMessage("reset-theme");
await extension.awaitMessage("theme-reset");
let {backgroundImage, backgroundColor, color} = defaultStyle;
- validateTheme(backgroundImage, backgroundColor, color, false);
+ await validateTheme(backgroundImage, backgroundColor, color, false);
await extension.unload();
let docEl = window.document.documentElement;
Assert.ok(!docEl.hasAttribute("lwtheme"), "LWT attribute should not be set");
});
--- a/toolkit/components/extensions/test/browser/browser_ext_themes_lwtsupport.js
+++ b/toolkit/components/extensions/test/browser/browser_ext_themes_lwtsupport.js
@@ -30,18 +30,23 @@ add_task(async function test_support_LWT
let style = window.getComputedStyle(docEl);
Assert.ok(docEl.hasAttribute("lwtheme"), "LWT attribute should be set");
Assert.ok(docEl.hasAttribute("lwtheme-image"), "LWT image attribute should be set");
Assert.equal(docEl.getAttribute("lwthemetextcolor"), "bright",
"LWT text color attribute should be set");
Assert.ok(style.backgroundImage.includes("image1.png"), "Expected background image");
+
+ // wait for theme transition to end
+ await waitForTransition(docEl, "background-color");
+
Assert.equal(style.backgroundColor, "rgb(" + hexToRGB(ACCENT_COLOR).join(", ") + ")",
"Expected correct background color");
+
Assert.equal(style.color, "rgb(" + hexToRGB(TEXT_COLOR).join(", ") + ")",
"Expected correct text color");
await extension.unload();
Assert.ok(!docEl.hasAttribute("lwtheme"), "LWT attribute should not be set");
Assert.ok(!docEl.hasAttribute("lwtheme-image"), "LWT image attribute should not be set");
});
new file mode 100644
--- /dev/null
+++ b/toolkit/components/extensions/test/browser/browser_ext_themes_theme_transition.js
@@ -0,0 +1,66 @@
+"use strict";
+
+// This test checks whether the applied theme transition effects are applied
+// correctly.
+
+add_task(async function test_theme_transition_effects() {
+ const ACCENT_COLOR = "#aaf442";
+ const TOOLBAR = "#f27489";
+ const TEXT_COLOR = "#000000";
+ const TRANSITION_PROPERTY = "background-color";
+
+ let extension = ExtensionTestUtils.loadExtension({
+ manifest: {
+ "theme": {
+ "images": {
+ "headerURL": "image1.png",
+ },
+ "colors": {
+ "accentcolor": ACCENT_COLOR,
+ "textcolor": TEXT_COLOR,
+ "toolbar": TOOLBAR,
+ "toolbar_text": TEXT_COLOR,
+ },
+ },
+ },
+ files: {
+ "image1.png": BACKGROUND,
+ },
+
+ });
+
+ await extension.startup();
+
+ // check if transition effect is set for root, which affects transition for
+ // accent color
+ let docEl = window.document.documentElement;
+ let rootCS = window.getComputedStyle(docEl);
+
+ Assert.equal(
+ rootCS.getPropertyValue("transition-property"),
+ TRANSITION_PROPERTY,
+ "Transition property set for root"
+ );
+
+ // now check transition effect for toolbars
+ let navbar = document.querySelector("#nav-bar");
+ let navbarCS = window.getComputedStyle(navbar);
+
+ Assert.equal(
+ navbarCS.getPropertyValue("transition-property").includes(TRANSITION_PROPERTY),
+ true,
+ "Transition property set for #nav-bar"
+ );
+
+ let bookmarksBar = document.querySelector("#PersonalToolbar");
+ bookmarksBar.setAttribute("collapsed", "false");
+ let bookmarksBarCS = window.getComputedStyle(bookmarksBar);
+
+ Assert.equal(
+ bookmarksBarCS.getPropertyValue("transition-property").includes(TRANSITION_PROPERTY),
+ true,
+ "Transition property set for #PersonalToolbar"
+ );
+
+ await extension.unload();
+});
--- a/toolkit/components/extensions/test/browser/browser_ext_themes_toolbars.js
+++ b/toolkit/components/extensions/test/browser/browser_ext_themes_toolbars.js
@@ -28,22 +28,27 @@ add_task(async function test_support_too
await extension.startup();
let toolbox = document.querySelector("#navigator-toolbox");
let toolbars = [...toolbox.querySelectorAll("toolbar:not(#TabsToolbar)")].filter(toolbar => {
let bounds = toolbar.getBoundingClientRect();
return bounds.width > 0 && bounds.height > 0;
});
+ // Wait for theme transition to end for one of the toolbars
+ await waitForTransition(toolbars[toolbars.length - 1], "background-color");
+
info(`Checking toolbar colors for ${toolbars.length} toolbars.`);
for (let toolbar of toolbars) {
info(`Testing ${toolbar.id}`);
+
Assert.equal(window.getComputedStyle(toolbar).backgroundColor,
hexToCSS(TOOLBAR_COLOR),
"Toolbar background color should be set.");
+
Assert.equal(window.getComputedStyle(toolbar).color,
hexToCSS(TOOLBAR_TEXT_COLOR),
"Toolbar text color should be set.");
}
info("Checking selected tab colors");
let selectedTab = document.querySelector(".tabbrowser-tab[selected]");
Assert.equal(window.getComputedStyle(selectedTab).color,
--- a/toolkit/components/extensions/test/browser/head.js
+++ b/toolkit/components/extensions/test/browser/head.js
@@ -1,10 +1,11 @@
/* exported ACCENT_COLOR, BACKGROUND, ENCODED_IMAGE_DATA, FRAME_COLOR, TAB_TEXT_COLOR,
- TEXT_COLOR, TAB_BACKGROUND_TEXT_COLOR, imageBufferFromDataURI, hexToCSS, hexToRGB, testBorderColor */
+ TEXT_COLOR, TAB_BACKGROUND_TEXT_COLOR, imageBufferFromDataURI, hexToCSS, hexToRGB, testBorderColor
+ TEXT_COLOR, BACKGROUND_TAB_TEXT_COLOR, imageBufferFromDataURI, hexToCSS, hexToRGB, waitForTransition */
"use strict";
const BACKGROUND = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0" +
"DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==";
const ENCODED_IMAGE_DATA = "iVBORw0KGgoAAAANSUhEUgAAABkAAAAZCAYAAADE6YVjAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAgY0h" +
"STQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAAdhwAAHYcBj+XxZQAAB5dJREFUSMd" +
"91vmTlEcZB/Bvd7/vO+/ce83O3gfLDUsC4VgIghBUEo2GM9GCFTaQBEISA1qIEVNQ4aggJDGIgAGTlFUKKcqKQpVHaQyny7FrCMiywp4ze+/Mzs67M/P" +
@@ -64,8 +65,19 @@ function testBorderColor(element, expect
"Element right border color should be set.");
Assert.equal(computedStyle.borderTopColor,
hexToCSS(expected),
"Element top border color should be set.");
Assert.equal(computedStyle.borderBottomColor,
hexToCSS(expected),
"Element bottom border color should be set.");
}
+
+function waitForTransition(doc, property) {
+ return new Promise(resolve => {
+ let listener = doc.addEventListener("transitionend", e => {
+ if (e.target == doc && e.propertyName == property) {
+ doc.removeEventListener("transitionend", listener);
+ resolve();
+ }
+ });
+ });
+}