Remove ColorHelper (#19187)

Most of `ColorHelper` was unused and one of them had UB.

Related to #19183

## Validation Steps Performed
* Set a custom tabRow theme color
  Split button looks similar to before 
* White/black FG color decision for colored
  tabs is similar to before 
This commit is contained in:
Leonard Hecker 2025-07-29 18:35:48 +02:00 committed by GitHub
parent 7d6e0c8b8e
commit 0c3002c1b9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 43 additions and 493 deletions

View File

@ -1,267 +0,0 @@
#include "ColorHelper.h"
using namespace winrt::TerminalApp;
// Method Description:
// Determines whether or not a given color is light
// Arguments:
// - color: this color is going to be examined whether it
// is light or not
// Return Value:
// - true if light, false if dark
bool ColorHelper::IsBrightColor(const winrt::Windows::UI::Color& color)
{
// https://www.w3.org/TR/AERT#color-contrast
auto brightness = (color.R * 299 + color.G * 587 + color.B * 114) / 1000.f;
return brightness > 128.f;
}
// Method Description:
// Converts a rgb color to an hsl one
// Arguments:
// - color: the rgb color, which is going to be converted
// Return Value:
// - a hsl color with the following ranges
// - H: [0.f -360.f]
// - L: [0.f - 1.f] (rounded to the third decimal place)
// - S: [0.f - 1.f] (rounded to the third decimal place)
HSL ColorHelper::RgbToHsl(const winrt::Windows::UI::Color& color)
{
// https://www.rapidtables.com/convert/color/rgb-to-hsl.html
auto epsilon = std::numeric_limits<float>::epsilon();
auto r = color.R / 255.f;
auto g = color.G / 255.f;
auto b = color.B / 255.f;
auto max = std::max(r, std::max(g, b));
auto min = std::min(r, std::min(g, b));
auto delta = max - min;
auto h = 0.f;
auto s = 0.f;
auto l = (max + min) / 2;
if (delta < epsilon || max < epsilon) /* delta == 0 || max == 0*/
{
l = std::roundf(l * 1000) / 1000;
return HSL{ h, s, l };
}
s = l > 0.5 ? delta / (2 - max - min) : delta / (max + min);
if (max - r < epsilon) // max == r
{
h = (g - b) / delta + (g < b ? 6 : 0);
}
else if (max - g < epsilon) // max == g
{
h = (b - r) / delta + 2;
}
else if (max - b < epsilon) // max == b
{
h = (r - g) / delta + 4;
}
// three decimal places after the comma ought
// to be enough for everybody - Bill Gates, 1981
auto finalH = std::roundf(h * 60);
auto finalS = std::roundf(s * 1000) / 1000;
auto finalL = std::roundf(l * 1000) / 1000;
return HSL{ finalH, finalS, finalL };
}
// Method Description:
// Converts a hsl color to rgb one
// Arguments:
// - color: the hsl color, which is going to be converted
// Return Value:
// - the rgb color (r,g,b - [0, 255] range)
winrt::Windows::UI::Color ColorHelper::HslToRgb(const HSL& color)
{
auto epsilon = std::numeric_limits<float>::epsilon();
auto h = (color.H - 1.f > epsilon) ? color.H / 360.f : color.H;
auto s = (color.S - 1.f > epsilon) ? color.S / 100.f : color.S;
auto l = (color.L - 1.f > epsilon) ? color.L / 100.f : color.L;
auto r = l;
auto g = l;
auto b = l;
if (s > epsilon)
{
auto q = l < 0.5 ? l * (1 + s) : l + s - l * s;
auto p = 2 * l - q;
r = HueToRgb(p, q, h + 1.f / 3.f);
g = HueToRgb(p, q, h);
b = HueToRgb(p, q, h - 1.f / 3.f);
}
auto finalR = static_cast<uint8_t>(std::roundf(r * 255));
auto finalG = static_cast<uint8_t>(std::roundf(g * 255));
auto finalB = static_cast<uint8_t>(std::roundf(b * 255));
uint8_t finalA = 255; //opaque
return winrt::Windows::UI::ColorHelper::FromArgb(finalA, finalR, finalG, finalB);
}
float ColorHelper::HueToRgb(float p, float q, float t)
{
auto epsilon = std::numeric_limits<float>::epsilon();
if (t < 0)
t += 1;
if (t > 1)
t -= 1;
if (t - (1.f / 6.f) < epsilon)
return p + (q - p) * 6 * t;
if (t - .5f < epsilon)
return q;
if (t - 2.f / 3.f < epsilon)
return p + (q - p) * (2.f / 3.f - t) * 6;
return p;
}
// Method Description:
// Lightens a color by a given amount
// Arguments:
// - color: the color which is going to be lightened
// - amount: the lighten amount (0-100)
// Return Value:
// - the lightened color in RGB format
winrt::Windows::UI::Color ColorHelper::Lighten(const winrt::Windows::UI::Color& color, float amount /* = 10.f*/)
{
auto hsl = RgbToHsl(color);
hsl.L += amount / 100;
hsl.L = std::clamp(hsl.L, 0.f, 1.f);
return HslToRgb(hsl);
}
// Method Description:
// Darkens a color by a given amount
// Arguments:
// - color: the color which is going to be darkened
// - amount: the darken amount (0-100)
// Return Value:
// - the darkened color in RGB format
winrt::Windows::UI::Color ColorHelper::Darken(const winrt::Windows::UI::Color& color, float amount /* = 10.f*/)
{
auto hsl = RgbToHsl(color);
hsl.L -= amount / 100;
hsl.L = std::clamp(hsl.L, 0.f, 1.f);
return HslToRgb(hsl);
}
// Method Description:
// Gets an accent color to a given color. Basically, generates
// 16 shades of the color and finds the first which has a good
// contrast according to https://www.w3.org/TR/2008/REC-WCAG20-20081211/#contrast-ratiodef (WCAG Version 2)
// Readability ratio of 3.5 seems to look quite nicely
// Arguments:
// - color: the color for which we need an accent
// Return Value:
// - the accent color in RGB format
winrt::Windows::UI::Color ColorHelper::GetAccentColor(const winrt::Windows::UI::Color& color)
{
auto accentColor = RgbToHsl(color);
if (accentColor.S < 0.15)
{
accentColor.S = 0.15f;
}
constexpr auto shadeCount = 16;
constexpr auto shadeStep = 1.f / shadeCount;
auto shades = std::map<float, HSL>();
for (auto i = 0; i < 15; i++)
{
auto shade = HSL{ accentColor.H, accentColor.S, i * shadeStep };
auto contrast = GetReadability(shade, accentColor);
shades.insert(std::make_pair(contrast, shade));
}
// 3f is quite nice if the whole non-client area is painted
constexpr auto readability = 1.75f;
for (auto shade : shades)
{
if (shade.first >= readability)
{
return HslToRgb(shade.second);
}
}
return HslToRgb(shades.end()->second);
}
// Method Description:
// Gets the readability of two colors according to
// https://www.w3.org/TR/2008/REC-WCAG20-20081211/#contrast-ratiodef (WCAG Version 2)
// Arguments:
// - firstColor: the first color for the readability check (hsl)
// - secondColor: the second color for the readability check (hsl)
// Return Value:
// - the readability of the colors according to (WCAG Version 2)
float ColorHelper::GetReadability(const HSL& first, const HSL& second)
{
return GetReadability(HslToRgb(first), HslToRgb(second));
}
// Method Description:
// Gets the readability of two colors according to
// https://www.w3.org/TR/2008/REC-WCAG20-20081211/#contrast-ratiodef (WCAG Version 2)
// Arguments:
// - firstColor: the first color for the readability check (rgb)
// - secondColor: the second color for the readability check (rgb)
// Return Value:
// - the readability of the colors according to (WCAG Version 2)
float ColorHelper::GetReadability(const winrt::Windows::UI::Color& first, const winrt::Windows::UI::Color& second)
{
auto l1 = GetLuminance(first);
auto l2 = GetLuminance(second);
return (std::max(l1, l2) + 0.05f) / std::min(l1, l2) + 0.05f;
}
// Method Description:
// Calculates the luminance of a given color according to
// https://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef
// Arguments:
// - color: its luminance is going to be calculated
// Return Value:
// - the luminance of the color
float ColorHelper::GetLuminance(const winrt::Windows::UI::Color& color)
{
auto epsilon = std::numeric_limits<float>::epsilon();
float R, G, B;
auto RsRGB = color.R / 255.f;
auto GsRGB = color.G / 255.f;
auto BsRGB = color.B / 255.f;
if (RsRGB - 0.03928f <= epsilon)
{
R = RsRGB / 12.92f;
}
else
{
R = std::pow(((RsRGB + 0.055f) / 1.055f), 2.4f);
}
if (GsRGB - 0.03928f <= epsilon)
{
G = GsRGB / 12.92f;
}
else
{
G = std::pow(((GsRGB + 0.055f) / 1.055f), 2.4f);
}
if (BsRGB - 0.03928f <= epsilon)
{
B = BsRGB / 12.92f;
}
else
{
B = std::pow(((BsRGB + 0.055f) / 1.055f), 2.4f);
}
auto luminance = (0.2126f * R) + (0.7152f * G) + (0.0722f * B);
return std::roundf(luminance * 10000) / 10000.f;
}

View File

@ -1,31 +0,0 @@
#pragma once
#include <winrt/Windows.UI.h>
namespace winrt::TerminalApp
{
class HSL
{
public:
float H;
float S;
float L;
};
class ColorHelper
{
public:
static bool IsBrightColor(const Windows::UI::Color& color);
static HSL RgbToHsl(const Windows::UI::Color& color);
static Windows::UI::Color HslToRgb(const HSL& color);
static Windows::UI::Color Lighten(const Windows::UI::Color& color, float amount = 10.f);
static Windows::UI::Color Darken(const Windows::UI::Color& color, float amount = 10.f);
static Windows::UI::Color GetAccentColor(const Windows::UI::Color& color);
static float GetLuminance(const Windows::UI::Color& color);
static float GetReadability(const Windows::UI::Color& first, const Windows::UI::Color& second);
static float GetReadability(const HSL& first, const HSL& second);
private:
static float HueToRgb(float p, float q, float t);
};
}

View File

@ -8,8 +8,8 @@
#include "SettingsPaneContent.h"
#include "Tab.g.cpp"
#include "Utils.h"
#include "ColorHelper.h"
#include "AppLogic.h"
#include "../../types/inc/ColorFix.hpp"
using namespace winrt;
using namespace winrt::Windows::UI::Xaml;
@ -2275,11 +2275,13 @@ namespace winrt::TerminalApp::implementation
// the background color
// - This method should only be called on the UI thread.
// Arguments:
// - color: the color the user picked for their tab
// - uiColor: the color the user picked for their tab
// Return Value:
// - <none>
void Tab::_ApplyTabColorOnUIThread(const winrt::Windows::UI::Color& color)
void Tab::_ApplyTabColorOnUIThread(const winrt::Windows::UI::Color& uiColor)
{
constexpr auto lightnessThreshold = 0.6f;
const til::color color{ uiColor };
Media::SolidColorBrush selectedTabBrush{};
Media::SolidColorBrush deselectedTabBrush{};
Media::SolidColorBrush fontBrush{};
@ -2292,7 +2294,7 @@ namespace winrt::TerminalApp::implementation
// calculate the luminance of the current color and select a font
// color based on that
// see https://www.w3.org/TR/WCAG20/#relativeluminancedef
if (TerminalApp::ColorHelper::IsBrightColor(color))
if (ColorFix::GetLightness(color) >= lightnessThreshold)
{
auto subtleFillColorSecondary = winrt::Windows::UI::Colors::Black();
subtleFillColorSecondary.A = 0x09;
@ -2312,8 +2314,8 @@ namespace winrt::TerminalApp::implementation
}
// The tab font should be based on the evaluated appearance of the tab color layered on tab row.
const auto layeredTabColor = til::color{ color }.layer_over(_tabRowColor);
if (TerminalApp::ColorHelper::IsBrightColor(layeredTabColor))
const auto layeredTabColor = color.layer_over(_tabRowColor);
if (ColorFix::GetLightness(layeredTabColor) >= lightnessThreshold)
{
fontBrush.Color(winrt::Windows::UI::Colors::Black());
auto secondaryFontColor = winrt::Windows::UI::Colors::Black();
@ -2333,8 +2335,7 @@ namespace winrt::TerminalApp::implementation
selectedTabBrush.Color(color);
// Start with the current tab color, set to Opacity=.3
til::color deselectedTabColor{ color };
deselectedTabColor = deselectedTabColor.with_alpha(77); // 255 * .3 = 77
auto deselectedTabColor = color.with_alpha(77); // 255 * .3 = 77
// If we DON'T have a color set from the color picker, or the profile's
// tabColor, but we do have a unfocused color in the theme, use the
@ -2376,7 +2377,7 @@ namespace winrt::TerminalApp::implementation
// We don't want that to result in white text on a white tab row for
// inactive tabs.
const auto deselectedActualColor = deselectedTabColor.layer_over(_tabRowColor);
if (TerminalApp::ColorHelper::IsBrightColor(deselectedActualColor))
if (ColorFix::GetLightness(deselectedActualColor) >= lightnessThreshold)
{
deselectedFontBrush.Color(winrt::Windows::UI::Colors::Black());
}

View File

@ -18,7 +18,6 @@
#include <LibraryResources.h>
#include "TabRowControl.h"
#include "ColorHelper.h"
#include "DebugTapConnection.h"
#include "..\TerminalSettingsModel\FileUtils.h"

View File

@ -134,7 +134,6 @@
<ClInclude Include="FilteredCommand.h" />
<ClInclude Include="Pane.h" />
<ClInclude Include="fzf/fzf.h" />
<ClInclude Include="ColorHelper.h" />
<ClInclude Include="pch.h" />
<ClInclude Include="ShortcutActionDispatch.h">
<DependentUpon>ShortcutActionDispatch.idl</DependentUpon>
@ -247,9 +246,6 @@
<ClCompile Include="FilteredCommand.cpp" />
<ClCompile Include="Pane.cpp" />
<ClCompile Include="Pane.LayoutSizeNode.cpp" />
<ClCompile Include="ColorHelper.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="DebugTapConnection.cpp" />
<ClCompile Include="pch.cpp">
<PrecompiledHeader>Create</PrecompiledHeader>

View File

@ -20,7 +20,6 @@
</ClCompile>
<ClCompile Include="AppCommandlineArgs.cpp" />
<ClCompile Include="Commandline.cpp" />
<ClCompile Include="ColorHelper.cpp" />
<ClCompile Include="DebugTapConnection.cpp" />
<ClCompile Include="Jumplist.cpp" />
<ClCompile Include="FilteredCommand.cpp">
@ -48,7 +47,6 @@
<ClInclude Include="AppCommandlineArgs.h" />
<ClInclude Include="Commandline.h" />
<ClInclude Include="DebugTapConnection.h" />
<ClInclude Include="ColorHelper.h" />
<ClInclude Include="Jumplist.h" />
<ClInclude Include="FilteredCommand.h">
<Filter>commandPalette</Filter>

View File

@ -6,24 +6,24 @@
#include "TerminalPage.h"
#include <LibraryResources.h>
#include <TerminalCore/ControlKeyStates.hpp>
#include <Utils.h>
#include <TerminalCore/ControlKeyStates.hpp>
#include "../../types/inc/utils.hpp"
#include "App.h"
#include "ColorHelper.h"
#include "DebugTapConnection.h"
#include "SettingsPaneContent.h"
#include "ScratchpadContent.h"
#include "SnippetsPaneContent.h"
#include "MarkdownPaneContent.h"
#include "TabRowControl.h"
#include "Remoting.h"
#include "ScratchpadContent.h"
#include "SettingsPaneContent.h"
#include "SnippetsPaneContent.h"
#include "TabRowControl.h"
#include "../../types/inc/ColorFix.hpp"
#include "../../types/inc/utils.hpp"
#include "TerminalPage.g.cpp"
#include "LaunchPositionRequest.g.cpp"
#include "RenameWindowRequestedArgs.g.cpp"
#include "RequestMoveContentArgs.g.cpp"
#include "LaunchPositionRequest.g.cpp"
#include "TerminalPage.g.cpp"
using namespace winrt;
using namespace winrt::Microsoft::Management::Deployment;
@ -3904,36 +3904,18 @@ namespace winrt::TerminalApp::implementation
// and the non-client are behind it
// Return Value:
// - <none>
void TerminalPage::_SetNewTabButtonColor(const Windows::UI::Color& color, const Windows::UI::Color& accentColor)
void TerminalPage::_SetNewTabButtonColor(const til::color color, const til::color accentColor)
{
constexpr auto lightnessThreshold = 0.6f;
// TODO GH#3327: Look at what to do with the tab button when we have XAML theming
auto IsBrightColor = ColorHelper::IsBrightColor(color);
auto isLightAccentColor = ColorHelper::IsBrightColor(accentColor);
winrt::Windows::UI::Color pressedColor{};
winrt::Windows::UI::Color hoverColor{};
winrt::Windows::UI::Color foregroundColor{};
const auto hoverColorAdjustment = 5.f;
const auto pressedColorAdjustment = 7.f;
const auto IsBrightColor = ColorFix::GetLightness(color) >= lightnessThreshold;
const auto isLightAccentColor = ColorFix::GetLightness(accentColor) >= lightnessThreshold;
const auto hoverColorAdjustment = isLightAccentColor ? -0.05f : 0.05f;
const auto pressedColorAdjustment = isLightAccentColor ? -0.1f : 0.1f;
if (IsBrightColor)
{
foregroundColor = winrt::Windows::UI::Colors::Black();
}
else
{
foregroundColor = winrt::Windows::UI::Colors::White();
}
if (isLightAccentColor)
{
hoverColor = ColorHelper::Darken(accentColor, hoverColorAdjustment);
pressedColor = ColorHelper::Darken(accentColor, pressedColorAdjustment);
}
else
{
hoverColor = ColorHelper::Lighten(accentColor, hoverColorAdjustment);
pressedColor = ColorHelper::Lighten(accentColor, pressedColorAdjustment);
}
const auto foregroundColor = IsBrightColor ? Colors::Black() : Colors::White();
const auto hoverColor = til::color{ ColorFix::AdjustLightness(accentColor, hoverColorAdjustment) };
const auto pressedColor = til::color{ ColorFix::AdjustLightness(accentColor, pressedColorAdjustment) };
Media::SolidColorBrush backgroundBrush{ accentColor };
Media::SolidColorBrush backgroundHoverBrush{ hoverColor };

View File

@ -463,7 +463,7 @@ namespace winrt::TerminalApp::implementation
void _RefreshUIForSettingsReload();
void _SetNewTabButtonColor(const Windows::UI::Color& color, const Windows::UI::Color& accentColor);
void _SetNewTabButtonColor(til::color color, til::color accentColor);
void _ClearNewTabButtonColor();
safe_void_coroutine _CompleteInitialization();

View File

@ -7,8 +7,7 @@
#include "pch.h"
#include "TitlebarControl.h"
#include "ColorHelper.h"
#include "../../types/inc/ColorFix.hpp"
#include "TitlebarControl.g.cpp"
@ -189,7 +188,8 @@ namespace winrt::TerminalApp::implementation
return;
}
const auto isBrightColor = ColorHelper::IsBrightColor(c);
constexpr auto lightnessThreshold = 0.6f;
const auto isBrightColor = ColorFix::GetLightness(c) >= lightnessThreshold;
MinMaxCloseControl().RequestedTheme(isBrightColor ? winrt::Windows::UI::Xaml::ElementTheme::Light :
winrt::Windows::UI::Xaml::ElementTheme::Dark);
}

View File

@ -1,130 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "precomp.h"
#include "../TerminalSettingsModel/Profile.h"
#include "../TerminalApp/ColorHelper.h"
// Import some templates to compare floats using approximate matching.
#include <consoletaeftemplates.hpp>
using namespace Microsoft::Console;
using namespace winrt::TerminalApp;
using namespace WEX::Logging;
using namespace WEX::TestExecution;
using namespace WEX::Common;
namespace TerminalAppUnitTests
{
class ColorHelperTests
{
BEGIN_TEST_CLASS(ColorHelperTests)
TEST_CLASS_PROPERTY(L"ActivationContext", L"TerminalApp.Unit.Tests.manifest")
END_TEST_CLASS()
TEST_METHOD(ConvertRgbToHsl);
TEST_METHOD(ConvertHslToRgb);
TEST_METHOD(LuminanceTests);
};
void ColorHelperTests::ConvertHslToRgb()
{
auto red = winrt::Windows::UI::Colors::Red();
auto redHsl = ColorHelper::RgbToHsl(red);
VERIFY_ARE_EQUAL(0.f, redHsl.H);
VERIFY_ARE_EQUAL(1.f, redHsl.S);
VERIFY_ARE_EQUAL(0.5f, redHsl.L);
auto green = winrt::Windows::UI::Colors::Lime();
auto greenHsl = ColorHelper::RgbToHsl(green);
VERIFY_ARE_EQUAL(120.f, greenHsl.H);
VERIFY_ARE_EQUAL(1.f, greenHsl.S);
VERIFY_ARE_EQUAL(0.5f, greenHsl.L);
auto blue = winrt::Windows::UI::Colors::Blue();
auto blueHsl = ColorHelper::RgbToHsl(blue);
VERIFY_ARE_EQUAL(240.f, blueHsl.H);
VERIFY_ARE_EQUAL(1.f, blueHsl.S);
VERIFY_ARE_EQUAL(0.5f, blueHsl.L);
auto darkTurquoise = winrt::Windows::UI::Colors::DarkTurquoise();
auto darkTurquoiseHsl = ColorHelper::RgbToHsl(darkTurquoise);
VERIFY_ARE_EQUAL(181.f, darkTurquoiseHsl.H);
VERIFY_ARE_EQUAL(1.f, darkTurquoiseHsl.S);
VERIFY_ARE_EQUAL(0.41f, darkTurquoiseHsl.L);
auto darkViolet = winrt::Windows::UI::Colors::DarkViolet();
auto darkVioletHsl = ColorHelper::RgbToHsl(darkViolet);
VERIFY_ARE_EQUAL(282.f, darkVioletHsl.H);
VERIFY_ARE_EQUAL(1.f, darkVioletHsl.S);
VERIFY_ARE_EQUAL(0.414f, darkVioletHsl.L);
auto white = winrt::Windows::UI::Colors::White();
auto whiteHsl = ColorHelper::RgbToHsl(white);
VERIFY_ARE_EQUAL(0.f, whiteHsl.H);
VERIFY_ARE_EQUAL(0.f, whiteHsl.S);
VERIFY_ARE_EQUAL(1.f, whiteHsl.L);
auto black = winrt::Windows::UI::Colors::Black();
auto blackHsl = ColorHelper::RgbToHsl(black);
VERIFY_ARE_EQUAL(0.f, blackHsl.H);
VERIFY_ARE_EQUAL(0.f, blackHsl.S);
VERIFY_ARE_EQUAL(0.f, blackHsl.L);
}
void ColorHelperTests::ConvertRgbToHsl()
{
auto redHsl = HSL{ 0.f, 100.f, 50.f };
auto red = ColorHelper::HslToRgb(redHsl);
VERIFY_ARE_EQUAL(255, red.R);
VERIFY_ARE_EQUAL(0, red.G);
VERIFY_ARE_EQUAL(0, red.B);
auto greenHsl = HSL{ 120.f, 100.f, 50.f };
auto green = ColorHelper::HslToRgb(greenHsl);
VERIFY_ARE_EQUAL(0, green.R);
VERIFY_ARE_EQUAL(255, green.G);
VERIFY_ARE_EQUAL(0, green.B);
auto blueHsl = HSL{ 240.f, 100.f, 50.f };
auto blue = ColorHelper::HslToRgb(blueHsl);
VERIFY_ARE_EQUAL(0, blue.R);
VERIFY_ARE_EQUAL(0, blue.G);
VERIFY_ARE_EQUAL(255, blue.B);
auto darkTurquoiseHsl = HSL{ 181.f, 100.f, 41.f };
auto darkTurquoise = ColorHelper::HslToRgb(darkTurquoiseHsl);
VERIFY_ARE_EQUAL(0, darkTurquoise.R);
VERIFY_ARE_EQUAL(206, darkTurquoise.G);
VERIFY_ARE_EQUAL(209, darkTurquoise.B);
auto darkVioletHsl = HSL{ 282.f, 100.f, 41.4f };
auto darkViolet = ColorHelper::HslToRgb(darkVioletHsl);
VERIFY_ARE_EQUAL(148, darkViolet.R);
VERIFY_ARE_EQUAL(0, darkViolet.G);
VERIFY_ARE_EQUAL(211, darkViolet.B);
auto whiteHsl = HSL{ 360.f, 100.f, 100.f };
auto white = ColorHelper::HslToRgb(whiteHsl);
VERIFY_ARE_EQUAL(255, white.R);
VERIFY_ARE_EQUAL(255, white.G);
VERIFY_ARE_EQUAL(255, white.B);
auto blackHsl = HSL{ 0.f, 0.f, 0.f };
auto black = ColorHelper::HslToRgb(blackHsl);
VERIFY_ARE_EQUAL(0, black.R);
VERIFY_ARE_EQUAL(0, black.G);
VERIFY_ARE_EQUAL(0, black.B);
}
void ColorHelperTests::LuminanceTests()
{
auto darkTurquoiseLuminance = ColorHelper::GetLuminance(winrt::Windows::UI::Colors::DarkTurquoise());
VERIFY_ARE_EQUAL(48.75f, darkTurquoiseLuminance * 100);
auto darkVioletLuminance = ColorHelper::GetLuminance(winrt::Windows::UI::Colors::DarkViolet());
VERIFY_ARE_EQUAL(11.f, darkVioletLuminance * 100);
auto magentaLuminance = ColorHelper::GetLuminance(winrt::Windows::UI::Colors::Magenta());
VERIFY_ARE_EQUAL(28.48f, magentaLuminance * 100);
}
}

View File

@ -21,17 +21,11 @@
<!-- ========================= Cpp Files ======================== -->
<ItemGroup>
<ClCompile Include="ColorHelperTests.cpp" />
<ClCompile Include="JsonUtilsTests.cpp" />
<ClCompile Include="FzfTests.cpp" />
<ClCompile Include="precomp.cpp">
<PrecompiledHeader>Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="..\TerminalApp\ColorHelper.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
</ItemGroup>
<!-- ========================= Project References ======================== -->

View File

@ -322,7 +322,7 @@ CATCH_RETURN()
auto misc = _api.s.write()->misc.write();
misc->selectionColor = newSelectionColor;
// Select a black or white foreground based on the perceptual lightness of the background.
misc->selectionForeground = ColorFix::GetLuminosity(newSelectionColor) < 0.5f ? 0xffffffff : 0xff000000;
misc->selectionForeground = ColorFix::GetLightness(newSelectionColor) < 0.5f ? 0xffffffff : 0xff000000;
// We copied the selection colors into _p during StartPaint, which happened just before PrepareRenderInfo
// This keeps their generations in sync.

View File

@ -209,7 +209,14 @@ COLORREF ColorFix::GetPerceivableColor(COLORREF color, COLORREF reference, float
return linearToColorref(oklab::oklab_to_linear_srgb(colorOklab)) | (color & 0xff000000);
}
float ColorFix::GetLuminosity(COLORREF color) noexcept
COLORREF ColorFix::AdjustLightness(COLORREF color, float delta) noexcept
{
auto lab = oklab::linear_srgb_to_oklab(colorrefToLinear(color));
lab.l = saturate(lab.l + delta);
return linearToColorref(oklab::oklab_to_linear_srgb(lab)) | (color & 0xff000000);
}
float ColorFix::GetLightness(COLORREF color) noexcept
{
return oklab::linear_srgb_to_oklab(colorrefToLinear(color)).l;
}

View File

@ -10,5 +10,6 @@
namespace ColorFix
{
COLORREF GetPerceivableColor(COLORREF color, COLORREF reference, float minSquaredDistance) noexcept;
float GetLuminosity(COLORREF color) noexcept;
COLORREF AdjustLightness(COLORREF color, float delta) noexcept;
float GetLightness(COLORREF color) noexcept;
}