From bf453ef8ebbb25934cd0740bb4a0b19794510bc9 Mon Sep 17 00:00:00 2001 From: Emma Malysz Date: Thu, 12 Nov 2020 23:56:44 +0000 Subject: [PATCH] Bug 1665461: reflect the correct colors for default themes in the skeleton UI. r=dthayer This patch supports a skeleton UI for default, light, and dark themes. It is not enabled for apenglow or any custom themes. This also takes into account the system theme. If the user has the default theme selected and is in dark mode, we override the theme and present the dark theme skeleton UI. Differential Revision: https://phabricator.services.mozilla.com/D96230 --- .../browser_preXULSkeletonUIRegistry.js | 1 + mozglue/misc/PreXULSkeletonUI.cpp | 170 +++++++++++++++--- mozglue/misc/PreXULSkeletonUI.h | 13 ++ toolkit/xre/nsAppRunner.cpp | 12 +- 4 files changed, 166 insertions(+), 30 deletions(-) diff --git a/browser/base/content/test/startup/browser_preXULSkeletonUIRegistry.js b/browser/base/content/test/startup/browser_preXULSkeletonUIRegistry.js index 38c19d10deec..aa04e422befe 100644 --- a/browser/base/content/test/startup/browser_preXULSkeletonUIRegistry.js +++ b/browser/base/content/test/startup/browser_preXULSkeletonUIRegistry.js @@ -88,6 +88,7 @@ add_task(async function testWritesSizeValuesOnChange() { "CssToDevPixelScaling", "SpringsCSSSpan", "SearchbarCSSSpan", + "Theme", ]; // Remove all of the registry values to ensure old tests aren't giving us false diff --git a/mozglue/misc/PreXULSkeletonUI.cpp b/mozglue/misc/PreXULSkeletonUI.cpp index 987532474a2c..c81c01f1ca21 100644 --- a/mozglue/misc/PreXULSkeletonUI.cpp +++ b/mozglue/misc/PreXULSkeletonUI.cpp @@ -86,9 +86,11 @@ static int sNonClientHorizontalMargins = 0; static uint32_t sDpi = 0; // Color values needed by the animation loop -static uint32_t sBackgroundColor; +static uint32_t sAnimationColor; static uint32_t sToolbarForegroundColor; +static ThemeMode sTheme = ThemeMode::Invalid; + typedef BOOL(WINAPI* EnableNonClientDpiScalingProc)(HWND); static EnableNonClientDpiScalingProc sEnableNonClientDpiScaling = NULL; typedef int(WINAPI* GetSystemMetricsForDpiProc)(int, UINT); @@ -147,6 +149,7 @@ static const wchar_t* sUrlbarCSSRegSuffix = L"|UrlbarCSSSpan"; static const wchar_t* sCssToDevPixelScalingRegSuffix = L"|CssToDevPixelScaling"; static const wchar_t* sSearchbarRegSuffix = L"|SearchbarCSSSpan"; static const wchar_t* sSpringsCSSRegSuffix = L"|SpringsCSSSpan"; +static const wchar_t* sThemeRegSuffix = L"|Theme"; std::wstring GetRegValueName(const wchar_t* prefix, const wchar_t* suffix) { std::wstring result(prefix); @@ -201,7 +204,8 @@ int CSSToDevPixels(int cssPixels, double scaling) { void DrawSkeletonUI(HWND hWnd, CSSPixelSpan urlbarCSSSpan, CSSPixelSpan searchbarCSSSpan, - const Vector& springs) { + const Vector& springs, + const ThemeColors& currentTheme) { // NOTE: we opt here to paint a pixel buffer for the application chrome by // hand, without using native UI library methods. Why do we do this? // @@ -223,22 +227,8 @@ void DrawSkeletonUI(HWND hWnd, CSSPixelSpan urlbarCSSSpan, // manipulating raw pixels should not be *too* hard to maintain and // understand so long as it is only painting such simple shapes. - // NOTE: these could be constants, but eventually they won't be, and they will - // need to be set here. - // --toolbar-non-lwt-bgcolor in browser.css - sBackgroundColor = 0xf9f9fa; - // We define this, but it will need to differ based on theme - sToolbarForegroundColor = 0xe5e5e5; - - // found in browser-aero.css ":root[tabsintitlebar]:not(:-moz-lwtheme)" - // (set to "hsl(235,33%,19%)") - uint32_t tabBarColor = 0x202340; - // --chrome-content-separator-color in browser.css - uint32_t chromeContentDividerColor = 0xe2e1e3; - // controlled by css variable --tab-line-color - uint32_t tabLineColor = 0x0a75d3; - // controlled by css variable --toolbar-color - uint32_t urlbarColor = 0xffffff; + sAnimationColor = currentTheme.animationColor; + sToolbarForegroundColor = currentTheme.toolbarForegroundColor; int chromeHorMargin = CSSToDevPixels(2, sCSSToDevPixelScaling); int verticalOffset = sMaximized ? sNonClientVerticalMargins : 0; @@ -308,7 +298,7 @@ void DrawSkeletonUI(HWND hWnd, CSSPixelSpan urlbarCSSSpan, // The (traditionally dark blue on Windows) background of the tab bar. ColorRect tabBar = {}; - tabBar.color = tabBarColor; + tabBar.color = currentTheme.tabBarColor; tabBar.x = 0; tabBar.y = topBorder.height; tabBar.width = sWindowWidth; @@ -319,7 +309,7 @@ void DrawSkeletonUI(HWND hWnd, CSSPixelSpan urlbarCSSSpan, // The blue highlight at the top of the initial selected tab ColorRect tabLine = {}; - tabLine.color = tabLineColor; + tabLine.color = currentTheme.tabLineColor; tabLine.x = titlebarSpacerWidth; tabLine.y = topBorder.height; tabLine.width = selectedTabWidth; @@ -330,7 +320,7 @@ void DrawSkeletonUI(HWND hWnd, CSSPixelSpan urlbarCSSSpan, // The initial selected tab ColorRect selectedTab = {}; - selectedTab.color = sBackgroundColor; + selectedTab.color = currentTheme.backgroundColor; selectedTab.x = titlebarSpacerWidth; selectedTab.y = tabLine.y + tabLineHeight; selectedTab.width = selectedTabWidth; @@ -352,7 +342,7 @@ void DrawSkeletonUI(HWND hWnd, CSSPixelSpan urlbarCSSSpan, // The toolbar background ColorRect toolbar = {}; - toolbar.color = sBackgroundColor; + toolbar.color = currentTheme.backgroundColor; toolbar.x = 0; toolbar.y = tabBar.y + tabBarHeight; toolbar.width = sWindowWidth; @@ -363,7 +353,7 @@ void DrawSkeletonUI(HWND hWnd, CSSPixelSpan urlbarCSSSpan, // The single-pixel divider line below the toolbar ColorRect chromeContentDivider = {}; - chromeContentDivider.color = chromeContentDividerColor; + chromeContentDivider.color = currentTheme.chromeContentDividerColor; chromeContentDivider.x = 0; chromeContentDivider.y = toolbar.y + toolbar.height; chromeContentDivider.width = sWindowWidth; @@ -374,7 +364,7 @@ void DrawSkeletonUI(HWND hWnd, CSSPixelSpan urlbarCSSSpan, // The urlbar ColorRect urlbar = {}; - urlbar.color = urlbarColor; + urlbar.color = currentTheme.urlbarColor; urlbar.x = CSSToDevPixels(urlbarCSSSpan.start, sCSSToDevPixelScaling) + horizontalOffset; urlbar.y = tabBar.y + tabBarHeight + urlbarTopOffset; @@ -401,7 +391,7 @@ void DrawSkeletonUI(HWND hWnd, CSSPixelSpan urlbarCSSSpan, bool hasSearchbar = searchbarCSSSpan.start != 0 && searchbarCSSSpan.end != 0; ColorRect searchbarRect = {}; if (hasSearchbar == true) { - searchbarRect.color = urlbarColor; + searchbarRect.color = currentTheme.urlbarColor; searchbarRect.x = CSSToDevPixels(searchbarCSSSpan.start, sCSSToDevPixelScaling) + horizontalOffset; @@ -550,7 +540,7 @@ void DrawSkeletonUI(HWND hWnd, CSSPixelSpan urlbarCSSSpan, // Then, we just fill the rest with FillRect RECT rect = {0, sTotalChromeHeight, (LONG)sWindowWidth, (LONG)sWindowHeight}; - HBRUSH brush = sCreateSolidBrush(sBackgroundColor); + HBRUSH brush = sCreateSolidBrush(currentTheme.backgroundColor); sFillRect(hdc, &rect, brush); scopeExit.release(); @@ -584,7 +574,7 @@ DWORD WINAPI AnimateSkeletonUI(void* aUnused) { int animationWidth = CSSToDevPixels(80, sCSSToDevPixelScaling); UniquePtr animationLookup = MakeUnique(animationWidth); - uint32_t animationColor = sBackgroundColor; + uint32_t animationColor = sAnimationColor; NormalizedRGB rgbBlend = UintToRGB(animationColor); // Build the first half of the lookup table @@ -762,6 +752,86 @@ LRESULT WINAPI PreXULSkeletonUIProc(HWND hWnd, UINT msg, WPARAM wParam, return ::DefWindowProcW(hWnd, msg, wParam, lParam); } +bool IsSystemDarkThemeEnabled() { + DWORD result; + HKEY themeKey; + DWORD dataLen = sizeof(uint32_t); + LPCWSTR keyName = + L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize"; + + result = ::RegOpenKeyExW(HKEY_CURRENT_USER, keyName, 0, KEY_READ, &themeKey); + if (result != ERROR_SUCCESS) { + return false; + } + AutoCloseRegKey closeKey(themeKey); + + uint32_t lightThemeEnabled; + result = ::RegGetValueW( + themeKey, nullptr, L"AppsUseLightTheme", RRF_RT_REG_DWORD, nullptr, + reinterpret_cast(&lightThemeEnabled), &dataLen); + if (result != ERROR_SUCCESS) { + return false; + } + return !lightThemeEnabled; +} + +ThemeColors GetTheme(ThemeMode themeId) { + ThemeColors theme = {}; + switch (themeId) { + case ThemeMode::Dark: + // Dark theme or default theme when in dark mode + + // controlled by css variable --toolbar-bgcolor + theme.backgroundColor = 0x323234; + theme.toolbarForegroundColor = 0x6a6a6b; + // controlled by css variable --lwt-accent-color + theme.tabBarColor = 0x0c0c0d; + // controlled by --toolbar-non-lwt-textcolor in browser.css + theme.chromeContentDividerColor = 0x0c0c0d; + // controlled by css variable --tab-line-color + theme.tabLineColor = 0x0a84ff; + // controlled by css variable --lwt-toolbar-field-background-colo + theme.urlbarColor = 0x474749; + theme.animationColor = theme.urlbarColor; + return theme; + case ThemeMode::Light: + // Light theme + + // controlled by --toolbar-bgcolor + theme.backgroundColor = 0xf5f6f7; + theme.toolbarForegroundColor = 0xd9dadb; + // controlled by css variable --lwt-accent-color + theme.tabBarColor = 0xe3e4e6; + // --chrome-content-separator-color in browser.css + theme.chromeContentDividerColor = 0x9e9fa1; + // controlled by css variable --tab-line-color + theme.tabLineColor = 0x0a84ff; + // by css variable --lwt-toolbar-field-background-color + theme.urlbarColor = 0xffffff; + theme.animationColor = theme.backgroundColor; + return theme; + case ThemeMode::Default: + default: + // Default theme when not in dark mode + MOZ_ASSERT(themeId == ThemeMode::Default); + + // --toolbar-non-lwt-bgcolor in browser.css + theme.backgroundColor = 0xf9f9fa; + theme.toolbarForegroundColor = 0xe5e5e5; + // found in browser-aero.css ":root[tabsintitlebar]:not(:-moz-lwtheme)" + // (set to "hsl(235,33%,19%)") + theme.tabBarColor = 0x202340; + // --chrome-content-separator-color in browser.css + theme.chromeContentDividerColor = 0xe2e1e3; + // controlled by css variable --tab-line-color + theme.tabLineColor = 0x0a84ff; + // controlled by css variable --toolbar-color + theme.urlbarColor = 0xffffff; + theme.animationColor = theme.backgroundColor; + return theme; + } +} + bool OpenPreXULSkeletonUIRegKey(HKEY& key) { DWORD disposition; LSTATUS result = @@ -1221,6 +1291,23 @@ void CreateAndStorePreXULSkeletonUI(HINSTANCE hInstance, int argc, } } + dataLen = sizeof(uint32_t); + uint32_t theme; + result = ::RegGetValueW( + regKey, nullptr, GetRegValueName(binPath.get(), sThemeRegSuffix).c_str(), + RRF_RT_REG_DWORD, nullptr, reinterpret_cast(&theme), &dataLen); + if (result != ERROR_SUCCESS) { + printf_stderr("Error reading theme %lu\n", GetLastError()); + return; + } + ThemeMode themeMode = static_cast(theme); + if (themeMode == ThemeMode::Default) { + if (IsSystemDarkThemeEnabled() == true) { + themeMode = ThemeMode::Dark; + } + } + ThemeColors currentTheme = GetTheme(themeMode); + sPreXULSkeletonUIWindow = sCreateWindowExW(kPreXULSkeletonUIWindowStyleEx, L"MozillaWindowClass", L"", windowStyle, screenX, screenY, windowWidth, @@ -1261,8 +1348,8 @@ void CreateAndStorePreXULSkeletonUI(HINSTANCE hInstance, int argc, sSetWindowPos(sPreXULSkeletonUIWindow, 0, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOSIZE | SWP_NOZORDER); - DrawSkeletonUI(sPreXULSkeletonUIWindow, urlbar, searchbar, springs); - + DrawSkeletonUI(sPreXULSkeletonUIWindow, urlbar, searchbar, springs, + currentTheme); if (sAnimatedRects) { sPreXULSKeletonUIAnimationThread = ::CreateThread( nullptr, 256 * 1024, AnimateSkeletonUI, nullptr, 0, nullptr); @@ -1450,6 +1537,31 @@ MFBT_API void SetPreXULSkeletonUIEnabledIfAllowed(bool value) { sPreXULSkeletonUIEnabled = value; } +MFBT_API void SetPreXULSkeletonUIThemeId(ThemeMode theme) { + if (theme == sTheme) { + return; + } + + HKEY regKey; + if (!OpenPreXULSkeletonUIRegKey(regKey)) { + return; + } + AutoCloseRegKey closeKey(regKey); + + UniquePtr binPath = GetBinaryPath(); + uint32_t themeId = (uint32_t)theme; + LSTATUS result; + result = ::RegSetValueExW( + regKey, GetRegValueName(binPath.get(), sThemeRegSuffix).c_str(), 0, + REG_DWORD, reinterpret_cast(&themeId), sizeof(themeId)); + if (result != ERROR_SUCCESS) { + printf_stderr("Failed persisting theme to Windows registry\n"); + sTheme = ThemeMode::Invalid; + return; + } + sTheme = static_cast(themeId); +} + MFBT_API void PollPreXULSkeletonUIEvents() { if (sPreXULSkeletonUIEnabled && sPreXULSkeletonUIWindow) { MSG outMsg = {}; diff --git a/mozglue/misc/PreXULSkeletonUI.h b/mozglue/misc/PreXULSkeletonUI.h index 9fd548effb04..c94ba74701f6 100644 --- a/mozglue/misc/PreXULSkeletonUI.h +++ b/mozglue/misc/PreXULSkeletonUI.h @@ -32,6 +32,18 @@ struct DevPixelSpan { int end; }; +enum class ThemeMode : uint32_t { Invalid, Default, Dark, Light }; + +struct ThemeColors { + uint32_t backgroundColor; + uint32_t toolbarForegroundColor; + uint32_t tabBarColor; + uint32_t chromeContentDividerColor; + uint32_t tabLineColor; + uint32_t urlbarColor; + uint32_t animationColor; +}; + MFBT_API void CreateAndStorePreXULSkeletonUI(HINSTANCE hInstance, int argc, char** argv); MFBT_API HWND ConsumePreXULSkeletonUIHandle(); @@ -45,6 +57,7 @@ MFBT_API void PersistPreXULSkeletonUIValues(int screenX, int screenY, int width, MFBT_API bool GetPreXULSkeletonUIEnabled(); MFBT_API void SetPreXULSkeletonUIEnabledIfAllowed(bool value); MFBT_API void PollPreXULSkeletonUIEvents(); +MFBT_API void SetPreXULSkeletonUIThemeId(ThemeMode theme); } // namespace mozilla diff --git a/toolkit/xre/nsAppRunner.cpp b/toolkit/xre/nsAppRunner.cpp index 82b42b7b0834..40e4dae574dc 100644 --- a/toolkit/xre/nsAppRunner.cpp +++ b/toolkit/xre/nsAppRunner.cpp @@ -1958,7 +1958,17 @@ static void ReflectSkeletonUIPrefToRegistry(const char* aPref, void* aData) { if (shouldBeEnabled && Preferences::HasUserValue(kPrefThemeId)) { nsCString themeId; Preferences::GetCString(kPrefThemeId, themeId); - shouldBeEnabled = themeId.EqualsLiteral("default-theme@mozilla.org"); + if (themeId.EqualsLiteral("default-theme@mozilla.org")) { + SetPreXULSkeletonUIThemeId(ThemeMode::Default); + } else if (themeId.EqualsLiteral("firefox-compact-dark@mozilla.org")) { + SetPreXULSkeletonUIThemeId(ThemeMode::Dark); + } else if (themeId.EqualsLiteral("firefox-compact-light@mozilla.org")) { + SetPreXULSkeletonUIThemeId(ThemeMode::Light); + } else { + shouldBeEnabled = false; + } + } else if (shouldBeEnabled) { + SetPreXULSkeletonUIThemeId(ThemeMode::Default); } if (GetPreXULSkeletonUIEnabled() != shouldBeEnabled) {