From 6373bae6c327f46c7c2eb9724ff4ba58848b665d Mon Sep 17 00:00:00 2001 From: Pankaj Bhojwani Date: Tue, 31 Aug 2021 13:42:10 -0700 Subject: [PATCH 01/25] transfer --- src/cascadia/TerminalCore/ColorFix.cpp | 496 ++++++++++++++++++ src/cascadia/TerminalCore/ColorFix.hpp | 67 +++ .../TerminalCore/terminalcore-common.vcxitems | 2 + 3 files changed, 565 insertions(+) create mode 100644 src/cascadia/TerminalCore/ColorFix.cpp create mode 100644 src/cascadia/TerminalCore/ColorFix.hpp diff --git a/src/cascadia/TerminalCore/ColorFix.cpp b/src/cascadia/TerminalCore/ColorFix.cpp new file mode 100644 index 00000000000..0fcac3d1600 --- /dev/null +++ b/src/cascadia/TerminalCore/ColorFix.cpp @@ -0,0 +1,496 @@ +#include "pch.h" + +#define _USE_MATH_DEFINES +#include +#include +#include "ColorFix.hpp" + +const double g_min_thrashold = 12.0; +const double g_exp_thrashold = 20.0; +const double g_L_step = 5.0; + +// DeltaE 2000 +// Source: https://github.com/zschuessler/DeltaE +dE00::dE00(ColorFix ax1, ColorFix ax2, double weight_lightness, double weight_chroma, double weight_hue) +{ + _x1 = ax1; + _x2 = ax2; + + _kSubL = weight_lightness; + _kSubC = weight_chroma; + _kSubH = weight_hue; + + // Delta L Prime + _deltaLPrime = _x2.L - _x1.L; + + // L Bar + _lBar = (_x1.L + _x2.L) / 2; + + // _c1 & _c2 + _c1 = sqrt(pow(_x1.A, 2) + pow(_x1.B, 2)); + _c2 = sqrt(pow(_x2.A, 2) + pow(_x2.B, 2)); + + // C Bar + _cBar = (_c1 + _c2) / 2; + + // A Prime 1 + _aPrime1 = _x1.A + + (_x1.A / 2) * + (1 - sqrt( + pow(_cBar, 7) / + (pow(_cBar, 7) + pow((double)25, 7)))); + + // A Prime 2 + _aPrime2 = _x2.A + + (_x2.A / 2) * + (1 - sqrt( + pow(_cBar, 7) / + (pow(_cBar, 7) + pow((double)25, 7)))); + + // C Prime 1 + _cPrime1 = sqrt( + pow(_aPrime1, 2) + + pow(_x1.B, 2)); + + // C Prime 2 + _cPrime2 = sqrt( + pow(_aPrime2, 2) + + pow(_x2.B, 2)); + + // C Bar Prime + _cBarPrime = (_cPrime1 + _cPrime2) / 2; + + // Delta C Prime + _deltaCPrime = _cPrime2 - _cPrime1; + + // S sub L + _sSubL = 1 + ((0.015 * pow(_lBar - 50, 2)) / + sqrt(20 + pow(_lBar - 50, 2))); + + // S sub C + _sSubC = 1 + 0.045 * _cBarPrime; + + // Properties set in GetDeltaE method, for access to convenience functions + // h Prime 1 + _hPrime1 = 0; + + // h Prime 2 + _hPrime2 = 0; + + // Delta H Prime + _deltaHPrime = 0; + + // H Bar Prime + _hBarPrime = 0; + + // T + _t = 0; + + // S sub H + _sSubH = 0; + + // R sub T + _rSubT = 0; +} + +/** + * Returns the deltaE value. + * @method + * @returns {number} + */ +double dE00::GetDeltaE() +{ + // h Prime 1 + _hPrime1 = _GetHPrime1(); + + // h Prime 2 + _hPrime2 = _GetHPrime2(); + + // Delta H Prime + _deltaHPrime = 2 * sqrt(_cPrime1 * _cPrime2) * sin(_DegreesToRadians(_GetDeltaHPrime()) / 2); + + // H Bar Prime + _hBarPrime = _GetHBarPrime(); + + // T + _t = _GetT(); + + // S sub H + _sSubH = 1 + 0.015 * _cBarPrime * _t; + + // R sub T + _rSubT = _GetRSubT(); + + // Put it all together! + double lightness = _deltaLPrime / (_kSubL * _sSubL); + double chroma = _deltaCPrime / (_kSubC * _sSubC); + double hue = _deltaHPrime / (_kSubH * _sSubH); + + return sqrt( + pow(lightness, 2) + + pow(chroma, 2) + + pow(hue, 2) + + _rSubT * chroma * hue); +}; + +/** + * Returns the RT variable calculation. + * @method + * @returns {number} + */ +double dE00::_GetRSubT() +{ + return -2 * + sqrt( + pow(_cBarPrime, 7) / + (pow(_cBarPrime, 7) + pow((double)25, 7))) * + sin(_DegreesToRadians( + 60 * + exp( + -( + pow( + (_hBarPrime - 275) / 25, 2))))); +}; + +/** + * Returns the T variable calculation. + * @method + * @returns {number} + */ +double dE00::_GetT() +{ + return 1 - + 0.17 * cos(_DegreesToRadians(_hBarPrime - 30)) + + 0.24 * cos(_DegreesToRadians(2 * _hBarPrime)) + + 0.32 * cos(_DegreesToRadians(3 * _hBarPrime + 6)) - + 0.20 * cos(_DegreesToRadians(4 * _hBarPrime - 63)); +}; + +/** + * Returns the H Bar Prime variable calculation. + * @method + * @returns {number} + */ +double dE00::_GetHBarPrime() +{ + if (abs(_hPrime1 - _hPrime2) > 180) + { + return (_hPrime1 + _hPrime2 + 360) / 2; + } + + return (_hPrime1 + _hPrime2) / 2; +}; + +/** + * Returns the Delta h Prime variable calculation. + * @method + * @returns {number} + */ +double dE00::_GetDeltaHPrime() +{ + // When either _c1 prime or _c2 prime is zero, then deltaH prime is irrelevant and may be set to + // zero. + if (0 == _c1 || 0 == _c2) + { + return 0; + } + + if (abs(_hPrime1 - _hPrime2) <= 180) + { + return _hPrime2 - _hPrime1; + } + + if (_hPrime2 <= _hPrime1) + { + return _hPrime2 - _hPrime1 + 360; + } + else + { + return _hPrime2 - _hPrime1 - 360; + } +}; + +/** + * Returns the h Prime 1 variable calculation. + * @method + * @returns {number} + */ +double dE00::_GetHPrime1() +{ + return _GetHPrimeFn(_x1.B, _aPrime1); +} + +/** + * Returns the h Prime 2 variable calculation. + * @method + * @returns {number} + */ +double dE00::_GetHPrime2() +{ + return _GetHPrimeFn(_x2.B, _aPrime2); +}; + +/** + * A helper function to calculate the h Prime 1 and h Prime 2 values. + * @method + * @private + * @returns {number} + */ +double dE00::_GetHPrimeFn(double x, double y) +{ + double hueAngle; + + if (x == 0 && y == 0) + { + return 0; + } + + hueAngle = _RadiansToDegrees(atan2(x, y)); + + if (hueAngle >= 0) + { + return hueAngle; + } + else + { + return hueAngle + 360; + } +}; + +/** + * Gives the radian equivalent of a specified degree angle. + * @method + * @returns {number} + */ +double dE00::_RadiansToDegrees(double radians) +{ + return radians * (180 / M_PI); +}; + +/** + * Gives the degree equivalent of a specified radian. + * @method + * @returns {number} + */ +double dE00::_DegreesToRadians(double degrees) +{ + return degrees * (M_PI / 180); +}; + +// RGB <--> Lab +// http://stackoverflow.com/a/8433985/1405560 +// http://www.easyrgb.com/index.php?X=MATH&H=08#text8 +namespace ColorSpace +{ + // using http://www.easyrgb.com/index.php?X=MATH&H=01#text1 + void rgb2lab(double R, double G, double B, double& l_s, double& a_s, double& b_s) + { + double var_R = R / 255.0; + double var_G = G / 255.0; + double var_B = B / 255.0; + + if (var_R > 0.04045) + var_R = pow(((var_R + 0.055) / 1.055), 2.4); + else + var_R = var_R / 12.92; + if (var_G > 0.04045) + var_G = pow(((var_G + 0.055) / 1.055), 2.4); + else + var_G = var_G / 12.92; + if (var_B > 0.04045) + var_B = pow(((var_B + 0.055) / 1.055), 2.4); + else + var_B = var_B / 12.92; + + var_R = var_R * 100.; + var_G = var_G * 100.; + var_B = var_B * 100.; + + //Observer. = 2 degrees, Illuminant = D65 + double X = var_R * 0.4124 + var_G * 0.3576 + var_B * 0.1805; + double Y = var_R * 0.2126 + var_G * 0.7152 + var_B * 0.0722; + double Z = var_R * 0.0193 + var_G * 0.1192 + var_B * 0.9505; + + double var_X = X / 95.047; //ref_X = 95.047 (Observer= 2 degrees, Illuminant= D65) + double var_Y = Y / 100.000; //ref_Y = 100.000 + double var_Z = Z / 108.883; //ref_Z = 108.883 + + if (var_X > 0.008856) + var_X = pow(var_X, (1. / 3.)); + else + var_X = (7.787 * var_X) + (16. / 116.); + if (var_Y > 0.008856) + var_Y = pow(var_Y, (1. / 3.)); + else + var_Y = (7.787 * var_Y) + (16. / 116.); + if (var_Z > 0.008856) + var_Z = pow(var_Z, (1. / 3.)); + else + var_Z = (7.787 * var_Z) + (16. / 116.); + + l_s = (116. * var_Y) - 16.; + a_s = 500. * (var_X - var_Y); + b_s = 200. * (var_Y - var_Z); + }; + + // http://www.easyrgb.com/index.php?X=MATH&H=01#text1 + void lab2rgb(double l_s, double a_s, double b_s, double& R, double& G, double& B) + { + double var_Y = (l_s + 16.) / 116.; + double var_X = a_s / 500. + var_Y; + double var_Z = var_Y - b_s / 200.; + + if (pow(var_Y, 3) > 0.008856) + var_Y = pow(var_Y, 3); + else + var_Y = (var_Y - 16. / 116.) / 7.787; + if (pow(var_X, 3) > 0.008856) + var_X = pow(var_X, 3); + else + var_X = (var_X - 16. / 116.) / 7.787; + if (pow(var_Z, 3) > 0.008856) + var_Z = pow(var_Z, 3); + else + var_Z = (var_Z - 16. / 116.) / 7.787; + + double X = 95.047 * var_X; //ref_X = 95.047 (Observer= 2 degrees, Illuminant= D65) + double Y = 100.000 * var_Y; //ref_Y = 100.000 + double Z = 108.883 * var_Z; //ref_Z = 108.883 + + var_X = X / 100.; //X from 0 to 95.047 (Observer = 2 degrees, Illuminant = D65) + var_Y = Y / 100.; //Y from 0 to 100.000 + var_Z = Z / 100.; //Z from 0 to 108.883 + + double var_R = var_X * 3.2406 + var_Y * -1.5372 + var_Z * -0.4986; + double var_G = var_X * -0.9689 + var_Y * 1.8758 + var_Z * 0.0415; + double var_B = var_X * 0.0557 + var_Y * -0.2040 + var_Z * 1.0570; + + if (var_R > 0.0031308) + var_R = 1.055 * pow(var_R, (1 / 2.4)) - 0.055; + else + var_R = 12.92 * var_R; + if (var_G > 0.0031308) + var_G = 1.055 * pow(var_G, (1 / 2.4)) - 0.055; + else + var_G = 12.92 * var_G; + if (var_B > 0.0031308) + var_B = 1.055 * pow(var_B, (1 / 2.4)) - 0.055; + else + var_B = 12.92 * var_B; + + R = var_R * 255.; + G = var_G * 255.; + B = var_B * 255.; + }; + + double DeltaE(ColorFix lab1, ColorFix lab2) + { + dE00 delta(lab1, lab2); + double de = delta.GetDeltaE(); + return de; + }; + + BYTE min_max(double v) + { + if (v <= 0) + return 0; + else if (v >= 255) + return 255; + else + return (BYTE)v; + } + + void lab2rgb(double l_s, double a_s, double b_s, COLORREF& rgb) + { + double _r = 0, _g = 0, _b = 0; + lab2rgb(l_s, a_s, b_s, _r, _g, _b); + rgb = RGB(min_max(_r), min_max(_g), min_max(_b)); + }; +}; + +// The ColorFix implementation + +ColorFix::ColorFix() +{ + rgb = 0; + L = 0; + A = 0; + B = 0; +} + +ColorFix::ColorFix(COLORREF a_rgb) +{ + rgb = a_rgb; + ToLab(); +} + +ColorFix::ColorFix(double a_L, double a_a, double a_b) +{ + L = a_L; + A = a_a; + B = a_b; + ToRGB(); +} + +ColorFix::ColorFix(const ColorFix& clr) +{ + L = clr.L; + A = clr.A; + B = clr.B; + rgb = clr.rgb; +} + +void ColorFix::ToLab() +{ + ColorSpace::rgb2lab(r, g, b, L, A, B); +} + +void ColorFix::ToRGB() +{ + ColorSpace::lab2rgb(L, A, B, rgb); +} + +double ColorFix::DeltaE(ColorFix color) +{ + return ColorSpace::DeltaE(*this, color); +} + +bool ColorFix::PerceivableColor(COLORREF back /*, COLORREF alt*/, ColorFix& pColor, double* oldDE /*= NULL*/, double* newDE /*= NULL*/) +{ + bool bChanged = false; + ColorFix backLab(back); + double de1 = DeltaE(backLab); + if (oldDE) + *oldDE = de1; + if (newDE) + *newDE = de1; + if (de1 < g_min_thrashold) + { + for (int i = 0; i <= 1; i++) + { + double step = (i == 0) ? g_L_step : -g_L_step; + pColor.L = L + step; + pColor.A = A; + pColor.B = B; + + while (((i == 0) && (pColor.L <= 100)) || ((i == 1) && (pColor.L >= 0))) + { + double de2 = pColor.DeltaE(backLab); + if (de2 >= g_exp_thrashold) + { + if (newDE) + *newDE = de2; + bChanged = true; + goto wrap; + } + pColor.L += step; + } + } + } +wrap: + if (bChanged) + pColor.ToRGB(); + else + pColor = *this; + return bChanged; +} diff --git a/src/cascadia/TerminalCore/ColorFix.hpp b/src/cascadia/TerminalCore/ColorFix.hpp new file mode 100644 index 00000000000..07e5f1c8248 --- /dev/null +++ b/src/cascadia/TerminalCore/ColorFix.hpp @@ -0,0 +1,67 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +#pragma once + +// We probably want to include something else here, whatever gives us COLORREF and BYTE +#include "../../terminal/input/terminalInput.hpp" + +struct ColorFix +{ + ColorFix(); + ColorFix(COLORREF a_rgb); + ColorFix(double a_L, double a_a, double a_b); + ColorFix(const ColorFix& clr); + + void ToLab(); + void ToRGB(); + + double DeltaE(ColorFix color); + + bool PerceivableColor(COLORREF back /*, COLORREF alt*/, ColorFix& pColor, double* oldDE = NULL, double* newDE = NULL); + + // RGB + union + { + struct + { + BYTE r, g, b, dummy; + }; + COLORREF rgb; + }; + + // Lab + struct + { + double L, A, B; + }; +}; + +struct dE00 +{ +public: + dE00(ColorFix ax1, ColorFix ax2, double weight_lightness = 1, double weight_chroma = 1, double weight_hue = 1); + double GetDeltaE(); + +private: + double _GetRSubT(); + double _GetT(); + double _GetHBarPrime(); + double _GetDeltaHPrime(); + double _GetHPrime1(); + double _GetHPrime2(); + double _GetHPrimeFn(double x, double y); + double _RadiansToDegrees(double radians); + double _DegreesToRadians(double degrees); + + ColorFix _x1, _x2; + double _kSubL, _kSubC, _kSubH; + double _deltaLPrime, _lBar; + double _c1, _c2, _cBar; + double _aPrime1, _aPrime2; + double _cPrime1, _cPrime2; + double _cBarPrime, _deltaCPrime; + double _sSubL, _sSubC; + double _hPrime1, _hPrime2, _deltaHPrime; + double _hBarPrime, _t, _sSubH, _rSubT; +}; diff --git a/src/cascadia/TerminalCore/terminalcore-common.vcxitems b/src/cascadia/TerminalCore/terminalcore-common.vcxitems index 5b777af15c0..f74187ac696 100644 --- a/src/cascadia/TerminalCore/terminalcore-common.vcxitems +++ b/src/cascadia/TerminalCore/terminalcore-common.vcxitems @@ -8,6 +8,7 @@ + Create @@ -19,6 +20,7 @@ + From da2cad83a61788421aa2df1aad95a546fc039e21 Mon Sep 17 00:00:00 2001 From: Pankaj Bhojwani Date: Tue, 31 Aug 2021 14:13:03 -0700 Subject: [PATCH 02/25] works --- src/cascadia/TerminalCore/ColorFix.cpp | 50 +++++++++---------- src/cascadia/TerminalCore/ColorFix.hpp | 10 ++-- .../TerminalCore/terminalrenderdata.cpp | 7 ++- 3 files changed, 36 insertions(+), 31 deletions(-) diff --git a/src/cascadia/TerminalCore/ColorFix.cpp b/src/cascadia/TerminalCore/ColorFix.cpp index 0fcac3d1600..7cd2c30a0a7 100644 --- a/src/cascadia/TerminalCore/ColorFix.cpp +++ b/src/cascadia/TerminalCore/ColorFix.cpp @@ -5,20 +5,20 @@ #include #include "ColorFix.hpp" -const double g_min_thrashold = 12.0; -const double g_exp_thrashold = 20.0; -const double g_L_step = 5.0; +const double gMinThreshold = 12.0; +const double gExpThreshold = 20.0; +const double gLStep = 5.0; // DeltaE 2000 // Source: https://github.com/zschuessler/DeltaE -dE00::dE00(ColorFix ax1, ColorFix ax2, double weight_lightness, double weight_chroma, double weight_hue) +dE00::dE00(ColorFix x1, ColorFix x2, double weightLightness, double weightChroma, double weightHue) { - _x1 = ax1; - _x2 = ax2; + _x1 = x1; + _x2 = x2; - _kSubL = weight_lightness; - _kSubC = weight_chroma; - _kSubH = weight_hue; + _kSubL = weightLightness; + _kSubC = weightChroma; + _kSubH = weightHue; // Delta L Prime _deltaLPrime = _x2.L - _x1.L; @@ -26,7 +26,7 @@ dE00::dE00(ColorFix ax1, ColorFix ax2, double weight_lightness, double weight_ch // L Bar _lBar = (_x1.L + _x2.L) / 2; - // _c1 & _c2 + // C1 & C2 _c1 = sqrt(pow(_x1.A, 2) + pow(_x1.B, 2)); _c2 = sqrt(pow(_x2.A, 2) + pow(_x2.B, 2)); @@ -418,26 +418,26 @@ ColorFix::ColorFix() B = 0; } -ColorFix::ColorFix(COLORREF a_rgb) +ColorFix::ColorFix(COLORREF color) { - rgb = a_rgb; + rgb = color; ToLab(); } -ColorFix::ColorFix(double a_L, double a_a, double a_b) +ColorFix::ColorFix(double l, double a, double b) { - L = a_L; - A = a_a; - B = a_b; + L = l; + A = a; + B = b; ToRGB(); } -ColorFix::ColorFix(const ColorFix& clr) +ColorFix::ColorFix(const ColorFix& color) { - L = clr.L; - A = clr.A; - B = clr.B; - rgb = clr.rgb; + L = color.L; + A = color.A; + B = color.B; + rgb = color.rgb; } void ColorFix::ToLab() @@ -455,7 +455,7 @@ double ColorFix::DeltaE(ColorFix color) return ColorSpace::DeltaE(*this, color); } -bool ColorFix::PerceivableColor(COLORREF back /*, COLORREF alt*/, ColorFix& pColor, double* oldDE /*= NULL*/, double* newDE /*= NULL*/) +bool ColorFix::PerceivableColor(COLORREF back, ColorFix& pColor, double* oldDE, double* newDE) { bool bChanged = false; ColorFix backLab(back); @@ -464,11 +464,11 @@ bool ColorFix::PerceivableColor(COLORREF back /*, COLORREF alt*/, ColorFix& pCol *oldDE = de1; if (newDE) *newDE = de1; - if (de1 < g_min_thrashold) + if (de1 < gMinThreshold) { for (int i = 0; i <= 1; i++) { - double step = (i == 0) ? g_L_step : -g_L_step; + double step = (i == 0) ? gLStep : -gLStep; pColor.L = L + step; pColor.A = A; pColor.B = B; @@ -476,7 +476,7 @@ bool ColorFix::PerceivableColor(COLORREF back /*, COLORREF alt*/, ColorFix& pCol while (((i == 0) && (pColor.L <= 100)) || ((i == 1) && (pColor.L >= 0))) { double de2 = pColor.DeltaE(backLab); - if (de2 >= g_exp_thrashold) + if (de2 >= gExpThreshold) { if (newDE) *newDE = de2; diff --git a/src/cascadia/TerminalCore/ColorFix.hpp b/src/cascadia/TerminalCore/ColorFix.hpp index 07e5f1c8248..b0ab58ee6f7 100644 --- a/src/cascadia/TerminalCore/ColorFix.hpp +++ b/src/cascadia/TerminalCore/ColorFix.hpp @@ -9,16 +9,16 @@ struct ColorFix { ColorFix(); - ColorFix(COLORREF a_rgb); - ColorFix(double a_L, double a_a, double a_b); - ColorFix(const ColorFix& clr); + ColorFix(COLORREF color); + ColorFix(double l, double a, double b); + ColorFix(const ColorFix& color); void ToLab(); void ToRGB(); double DeltaE(ColorFix color); - bool PerceivableColor(COLORREF back /*, COLORREF alt*/, ColorFix& pColor, double* oldDE = NULL, double* newDE = NULL); + bool PerceivableColor(COLORREF back, ColorFix& pColor, double* oldDE = NULL, double* newDE = NULL); // RGB union @@ -40,7 +40,7 @@ struct ColorFix struct dE00 { public: - dE00(ColorFix ax1, ColorFix ax2, double weight_lightness = 1, double weight_chroma = 1, double weight_hue = 1); + dE00(ColorFix x1, ColorFix x2, double weightLightness = 1, double weightChroma = 1, double weightHue = 1); double GetDeltaE(); private: diff --git a/src/cascadia/TerminalCore/terminalrenderdata.cpp b/src/cascadia/TerminalCore/terminalrenderdata.cpp index 84b00eadfeb..c256694fb05 100644 --- a/src/cascadia/TerminalCore/terminalrenderdata.cpp +++ b/src/cascadia/TerminalCore/terminalrenderdata.cpp @@ -4,6 +4,8 @@ #include "pch.h" #include "Terminal.hpp" #include +#include "ColorFix.hpp" + using namespace Microsoft::Terminal::Core; using namespace Microsoft::Console::Types; using namespace Microsoft::Console::Render; @@ -59,7 +61,10 @@ std::pair Terminal::GetAttributeColors(const TextAttribute& { colors.second |= 0xff000000; } - return colors; + ColorFix colorFix{ colors.first }; + ColorFix result{}; + colorFix.PerceivableColor(colors.second, result); + return std::pair(result.rgb, colors.second); } COORD Terminal::GetCursorPosition() const noexcept From d1c974830b26ca23a43e40e4d933d870738ab600 Mon Sep 17 00:00:00 2001 From: Pankaj Bhojwani Date: Wed, 1 Sep 2021 09:06:44 -0700 Subject: [PATCH 03/25] remove --- src/cascadia/TerminalCore/ColorFix.cpp | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/src/cascadia/TerminalCore/ColorFix.cpp b/src/cascadia/TerminalCore/ColorFix.cpp index 7cd2c30a0a7..3103f8ba002 100644 --- a/src/cascadia/TerminalCore/ColorFix.cpp +++ b/src/cascadia/TerminalCore/ColorFix.cpp @@ -69,28 +69,6 @@ dE00::dE00(ColorFix x1, ColorFix x2, double weightLightness, double weightChroma // S sub C _sSubC = 1 + 0.045 * _cBarPrime; - - // Properties set in GetDeltaE method, for access to convenience functions - // h Prime 1 - _hPrime1 = 0; - - // h Prime 2 - _hPrime2 = 0; - - // Delta H Prime - _deltaHPrime = 0; - - // H Bar Prime - _hBarPrime = 0; - - // T - _t = 0; - - // S sub H - _sSubH = 0; - - // R sub T - _rSubT = 0; } /** From 0c8168be92c5e264dc322c8b4e156faed43a5dee Mon Sep 17 00:00:00 2001 From: Pankaj Bhojwani Date: Wed, 1 Sep 2021 11:16:47 -0700 Subject: [PATCH 04/25] method descriptions --- src/cascadia/TerminalCore/ColorFix.cpp | 162 +++++++++++++++---------- 1 file changed, 99 insertions(+), 63 deletions(-) diff --git a/src/cascadia/TerminalCore/ColorFix.cpp b/src/cascadia/TerminalCore/ColorFix.cpp index 3103f8ba002..47cf4272756 100644 --- a/src/cascadia/TerminalCore/ColorFix.cpp +++ b/src/cascadia/TerminalCore/ColorFix.cpp @@ -71,11 +71,10 @@ dE00::dE00(ColorFix x1, ColorFix x2, double weightLightness, double weightChroma _sSubC = 1 + 0.045 * _cBarPrime; } -/** - * Returns the deltaE value. - * @method - * @returns {number} - */ +// Method Description: +// - Calculates and returns the deltaE value. +// Return Value: +// - The deltaE value double dE00::GetDeltaE() { // h Prime 1 @@ -111,11 +110,10 @@ double dE00::GetDeltaE() _rSubT * chroma * hue); }; -/** - * Returns the RT variable calculation. - * @method - * @returns {number} - */ +// Method Description: +// - Calculates and returns the RT variable +// Return Value: +// - The RT variable double dE00::_GetRSubT() { return -2 * @@ -130,11 +128,10 @@ double dE00::_GetRSubT() (_hBarPrime - 275) / 25, 2))))); }; -/** - * Returns the T variable calculation. - * @method - * @returns {number} - */ +// Method Description: +// - Calculates and returns the T variable +// Return Value: +// - The T variable double dE00::_GetT() { return 1 - @@ -144,11 +141,10 @@ double dE00::_GetT() 0.20 * cos(_DegreesToRadians(4 * _hBarPrime - 63)); }; -/** - * Returns the H Bar Prime variable calculation. - * @method - * @returns {number} - */ +// Method Description: +// - Calculates and returns the HBarPrime variable +// Return Value: +// - The HBarPrime variable double dE00::_GetHBarPrime() { if (abs(_hPrime1 - _hPrime2) > 180) @@ -159,11 +155,10 @@ double dE00::_GetHBarPrime() return (_hPrime1 + _hPrime2) / 2; }; -/** - * Returns the Delta h Prime variable calculation. - * @method - * @returns {number} - */ +// Method Description: +// - Calculates and returns the Delta h prime variable +// Return Value: +// - The Delta h prime variable double dE00::_GetDeltaHPrime() { // When either _c1 prime or _c2 prime is zero, then deltaH prime is irrelevant and may be set to @@ -188,32 +183,28 @@ double dE00::_GetDeltaHPrime() } }; -/** - * Returns the h Prime 1 variable calculation. - * @method - * @returns {number} - */ +// Method Description: +// - Calculates and returns the h Prime 1 variable +// Return Value: +// - The h Prime 1 variable double dE00::_GetHPrime1() { return _GetHPrimeFn(_x1.B, _aPrime1); } -/** - * Returns the h Prime 2 variable calculation. - * @method - * @returns {number} - */ +// Method Description: +// - Calculates and returns the h Prime 2 variable +// Return Value: +// - The h Prime 2 variable double dE00::_GetHPrime2() { return _GetHPrimeFn(_x2.B, _aPrime2); }; -/** - * A helper function to calculate the h Prime 1 and h Prime 2 values. - * @method - * @private - * @returns {number} - */ +// Method Description: +// - Helper function to calculate the h Prime values +// Return Value: +// - The h Prime value double dE00::_GetHPrimeFn(double x, double y) { double hueAngle; @@ -235,32 +226,38 @@ double dE00::_GetHPrimeFn(double x, double y) } }; -/** - * Gives the radian equivalent of a specified degree angle. - * @method - * @returns {number} - */ +// Method Description: +// - Converts radians to degrees +// Arguments: +// - radians: the angle in radians +// Return Value: +// - the given angle, converted to degrees double dE00::_RadiansToDegrees(double radians) { return radians * (180 / M_PI); }; -/** - * Gives the degree equivalent of a specified radian. - * @method - * @returns {number} - */ +// Method Description: +// - Converts degrees to radians +// Arguments: +// - degrees: the angle in degrees +// Return Value: +// - the given angle, converted to radians double dE00::_DegreesToRadians(double degrees) { return degrees * (M_PI / 180); }; -// RGB <--> Lab // http://stackoverflow.com/a/8433985/1405560 // http://www.easyrgb.com/index.php?X=MATH&H=08#text8 namespace ColorSpace { - // using http://www.easyrgb.com/index.php?X=MATH&H=01#text1 + // Method Description: + // - Converts a color in rgb format to a color in lab format + // - Reference: http://www.easyrgb.com/index.php?X=MATH&H=01#text1 + // Arguments: + // R, G, B: the rgb values of the input color + // l_s, a_s, b_s: where the output lab format should be stored void rgb2lab(double R, double G, double B, double& l_s, double& a_s, double& b_s) { double var_R = R / 255.0; @@ -311,7 +308,12 @@ namespace ColorSpace b_s = 200. * (var_Y - var_Z); }; - // http://www.easyrgb.com/index.php?X=MATH&H=01#text1 + // Method Description: + // - Converts a color in lab format to a color in rgb format + // - Reference: http://www.easyrgb.com/index.php?X=MATH&H=01#text1 + // Arguments: + // l_s, a_s, b_s: the lab values of the input color + // R, G, B: where the output rgb format should be stored void lab2rgb(double l_s, double a_s, double b_s, double& R, double& G, double& B) { double var_Y = (l_s + 16.) / 116.; @@ -361,6 +363,26 @@ namespace ColorSpace B = var_B * 255.; }; + // Method Description: + // - Converts a color in lab format to a color in rgb format + // - Reference: http://www.easyrgb.com/index.php?X=MATH&H=01#text1 + // Arguments: + // l_s, a_s, b_s: the lab values of the input color + // rgb: where the output rgb format should be stored + void lab2rgb(double l_s, double a_s, double b_s, COLORREF& rgb) + { + double _r = 0, _g = 0, _b = 0; + lab2rgb(l_s, a_s, b_s, _r, _g, _b); + rgb = RGB(min_max(_r), min_max(_g), min_max(_b)); + }; + + // Method Description: + // - Given 2 colors, computes the DeltaE value between them + // Arguments: + // - lab1: the foreground color + // - lab2: the background color + // Return Value: + // - the DeltaE value double DeltaE(ColorFix lab1, ColorFix lab2) { dE00 delta(lab1, lab2); @@ -368,6 +390,12 @@ namespace ColorSpace return de; }; + // Method Description: + // - Clamps the given value to be between 0-255 inclusive + // Arguments: + // - v: the value to clamp + // Return Value: + // - The clamped value BYTE min_max(double v) { if (v <= 0) @@ -377,17 +405,8 @@ namespace ColorSpace else return (BYTE)v; } - - void lab2rgb(double l_s, double a_s, double b_s, COLORREF& rgb) - { - double _r = 0, _g = 0, _b = 0; - lab2rgb(l_s, a_s, b_s, _r, _g, _b); - rgb = RGB(min_max(_r), min_max(_g), min_max(_b)); - }; }; -// The ColorFix implementation - ColorFix::ColorFix() { rgb = 0; @@ -418,21 +437,38 @@ ColorFix::ColorFix(const ColorFix& color) rgb = color.rgb; } +// Method Description: +// - Populates our L, A, B values, based on our r, g, b values void ColorFix::ToLab() { ColorSpace::rgb2lab(r, g, b, L, A, B); } +// Method Description: +// - Populates our r, g, b values, based on our L, A, B values void ColorFix::ToRGB() { ColorSpace::lab2rgb(L, A, B, rgb); } +// Method Description: +// - Given a color, computes the DeltaE between us and that color +// - Arguments: +// - color: the color to compare against +// - Return Value: +// - The DeltaE value between us and that color double ColorFix::DeltaE(ColorFix color) { return ColorSpace::DeltaE(*this, color); } +// Method Description: +// - Given a background color, change our own color to make it more perceivable if necessary +// - Arguments: +// - back: the color to compare against +// - pColor: where to store the resulting color +// - Return Value: +// - True if we changed our color, false otherwise bool ColorFix::PerceivableColor(COLORREF back, ColorFix& pColor, double* oldDE, double* newDE) { bool bChanged = false; From 7b1eefe50a9945e7134f5833149766e943022c8b Mon Sep 17 00:00:00 2001 From: Pankaj Bhojwani Date: Wed, 1 Sep 2021 13:17:05 -0700 Subject: [PATCH 05/25] spell, format --- .github/actions/spelling/allow/math.txt | 7 ++++ .github/actions/spelling/expect/web.txt | 2 ++ src/cascadia/TerminalCore/ColorFix.cpp | 46 ++++++++++++------------- 3 files changed, 32 insertions(+), 23 deletions(-) diff --git a/.github/actions/spelling/allow/math.txt b/.github/actions/spelling/allow/math.txt index 1482aedaba0..096fc197473 100644 --- a/.github/actions/spelling/allow/math.txt +++ b/.github/actions/spelling/allow/math.txt @@ -1,3 +1,10 @@ +atan +CPrime +HBar +HPrime isnan +LPrime +LStep powf +RSub sqrtf diff --git a/.github/actions/spelling/expect/web.txt b/.github/actions/spelling/expect/web.txt index 3072b0075b4..826edf1af8e 100644 --- a/.github/actions/spelling/expect/web.txt +++ b/.github/actions/spelling/expect/web.txt @@ -1,5 +1,7 @@ http www +easyrgb +php ecma rapidtables WCAG diff --git a/src/cascadia/TerminalCore/ColorFix.cpp b/src/cascadia/TerminalCore/ColorFix.cpp index 47cf4272756..268e9070cc8 100644 --- a/src/cascadia/TerminalCore/ColorFix.cpp +++ b/src/cascadia/TerminalCore/ColorFix.cpp @@ -35,17 +35,17 @@ dE00::dE00(ColorFix x1, ColorFix x2, double weightLightness, double weightChroma // A Prime 1 _aPrime1 = _x1.A + - (_x1.A / 2) * - (1 - sqrt( - pow(_cBar, 7) / - (pow(_cBar, 7) + pow((double)25, 7)))); + (_x1.A / 2) * + (1 - sqrt( + pow(_cBar, 7) / + (pow(_cBar, 7) + pow((double)25, 7)))); // A Prime 2 _aPrime2 = _x2.A + - (_x2.A / 2) * - (1 - sqrt( - pow(_cBar, 7) / - (pow(_cBar, 7) + pow((double)25, 7)))); + (_x2.A / 2) * + (1 - sqrt( + pow(_cBar, 7) / + (pow(_cBar, 7) + pow((double)25, 7)))); // C Prime 1 _cPrime1 = sqrt( @@ -65,7 +65,7 @@ dE00::dE00(ColorFix x1, ColorFix x2, double weightLightness, double weightChroma // S sub L _sSubL = 1 + ((0.015 * pow(_lBar - 50, 2)) / - sqrt(20 + pow(_lBar - 50, 2))); + sqrt(20 + pow(_lBar - 50, 2))); // S sub C _sSubC = 1 + 0.045 * _cBarPrime; @@ -117,15 +117,15 @@ double dE00::GetDeltaE() double dE00::_GetRSubT() { return -2 * - sqrt( - pow(_cBarPrime, 7) / - (pow(_cBarPrime, 7) + pow((double)25, 7))) * - sin(_DegreesToRadians( - 60 * - exp( - -( - pow( - (_hBarPrime - 275) / 25, 2))))); + sqrt( + pow(_cBarPrime, 7) / + (pow(_cBarPrime, 7) + pow((double)25, 7))) * + sin(_DegreesToRadians( + 60 * + exp( + -( + pow( + (_hBarPrime - 275) / 25, 2))))); }; // Method Description: @@ -135,10 +135,10 @@ double dE00::_GetRSubT() double dE00::_GetT() { return 1 - - 0.17 * cos(_DegreesToRadians(_hBarPrime - 30)) + - 0.24 * cos(_DegreesToRadians(2 * _hBarPrime)) + - 0.32 * cos(_DegreesToRadians(3 * _hBarPrime + 6)) - - 0.20 * cos(_DegreesToRadians(4 * _hBarPrime - 63)); + 0.17 * cos(_DegreesToRadians(_hBarPrime - 30)) + + 0.24 * cos(_DegreesToRadians(2 * _hBarPrime)) + + 0.32 * cos(_DegreesToRadians(3 * _hBarPrime + 6)) - + 0.20 * cos(_DegreesToRadians(4 * _hBarPrime - 63)); }; // Method Description: @@ -167,7 +167,7 @@ double dE00::_GetDeltaHPrime() { return 0; } - + if (abs(_hPrime1 - _hPrime2) <= 180) { return _hPrime2 - _hPrime1; From f8003d32c4da5d3022d0ab9e2dbefa231d9ee464 Mon Sep 17 00:00:00 2001 From: Pankaj Bhojwani Date: Wed, 1 Sep 2021 13:45:14 -0700 Subject: [PATCH 06/25] order --- src/cascadia/TerminalCore/ColorFix.cpp | 32 +++++++++++++------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/cascadia/TerminalCore/ColorFix.cpp b/src/cascadia/TerminalCore/ColorFix.cpp index 268e9070cc8..229700e2cf9 100644 --- a/src/cascadia/TerminalCore/ColorFix.cpp +++ b/src/cascadia/TerminalCore/ColorFix.cpp @@ -252,6 +252,22 @@ double dE00::_DegreesToRadians(double degrees) // http://www.easyrgb.com/index.php?X=MATH&H=08#text8 namespace ColorSpace { + // Method Description: + // - Clamps the given value to be between 0-255 inclusive + // Arguments: + // - v: the value to clamp + // Return Value: + // - The clamped value + BYTE min_max(double v) + { + if (v <= 0) + return 0; + else if (v >= 255) + return 255; + else + return (BYTE)v; + } + // Method Description: // - Converts a color in rgb format to a color in lab format // - Reference: http://www.easyrgb.com/index.php?X=MATH&H=01#text1 @@ -389,22 +405,6 @@ namespace ColorSpace double de = delta.GetDeltaE(); return de; }; - - // Method Description: - // - Clamps the given value to be between 0-255 inclusive - // Arguments: - // - v: the value to clamp - // Return Value: - // - The clamped value - BYTE min_max(double v) - { - if (v <= 0) - return 0; - else if (v >= 255) - return 255; - else - return (BYTE)v; - } }; ColorFix::ColorFix() From e4fced6810685604b26139dfb1ab901942bb4db6 Mon Sep 17 00:00:00 2001 From: Pankaj Bhojwani Date: Wed, 1 Sep 2021 15:58:49 -0700 Subject: [PATCH 07/25] default on setting --- doc/cascadia/profiles.schema.json | 8 ++++++++ src/cascadia/TerminalCore/ICoreAppearance.idl | 1 + src/cascadia/TerminalCore/Terminal.cpp | 4 +++- src/cascadia/TerminalCore/Terminal.hpp | 1 + .../TerminalCore/terminalrenderdata.cpp | 17 +++++++++++++---- .../TerminalSettingsEditor/Appearances.h | 1 + .../TerminalSettingsEditor/Appearances.idl | 1 + .../TerminalSettingsEditor/Appearances.xaml | 8 ++++++++ .../Resources/en-US/Resources.resw | 8 ++++++++ .../TerminalSettingsModel/AppearanceConfig.cpp | 4 ++++ .../TerminalSettingsModel/AppearanceConfig.h | 2 ++ .../TerminalSettingsModel/CascadiaSettings.cpp | 1 + .../TerminalSettingsModel/IAppearanceConfig.idl | 2 ++ .../TerminalSettingsModel/TerminalSettings.cpp | 2 ++ .../TerminalSettingsModel/TerminalSettings.h | 2 ++ .../UnitTests_Control/MockControlSettings.h | 1 + .../UnitTests_TerminalCore/MockTermSettings.h | 1 + 17 files changed, 59 insertions(+), 5 deletions(-) diff --git a/doc/cascadia/profiles.schema.json b/doc/cascadia/profiles.schema.json index b2e293c761d..b8aeb933d46 100644 --- a/doc/cascadia/profiles.schema.json +++ b/doc/cascadia/profiles.schema.json @@ -165,6 +165,10 @@ ], "type": "string" }, + "perceptualColorNudging": { + "description": "When set to true, we will (when necessary) 'nudge' the foreground color to make it more visible, based on the background color.", + "type": "boolean" + }, "experimental.retroTerminalEffect": { "description": "When set to true, enable retro terminal effects when unfocused. This is an experimental feature, and its continued existence is not guaranteed.", "type": "boolean" @@ -1590,6 +1594,10 @@ } ] }, + "perceptualColorNudging": { + "description": "When set to true, we will (when necessary) 'nudge' the foreground color to make it more visible, based on the background color.", + "type": "boolean" + }, "scrollbarState": { "default": "visible", "description": "Defines the visibility of the scrollbar.", diff --git a/src/cascadia/TerminalCore/ICoreAppearance.idl b/src/cascadia/TerminalCore/ICoreAppearance.idl index 5300ec6748f..00a41c9e508 100644 --- a/src/cascadia/TerminalCore/ICoreAppearance.idl +++ b/src/cascadia/TerminalCore/ICoreAppearance.idl @@ -67,5 +67,6 @@ namespace Microsoft.Terminal.Core CursorStyle CursorShape; UInt32 CursorHeight; Boolean IntenseIsBright; + Boolean PerceptualColorNudging; }; } diff --git a/src/cascadia/TerminalCore/Terminal.cpp b/src/cascadia/TerminalCore/Terminal.cpp index aba4d68de66..0291f254abb 100644 --- a/src/cascadia/TerminalCore/Terminal.cpp +++ b/src/cascadia/TerminalCore/Terminal.cpp @@ -53,7 +53,8 @@ Terminal::Terminal() : _taskbarState{ 0 }, _taskbarProgress{ 0 }, _trimBlockSelection{ false }, - _intenseIsBright{ true } + _intenseIsBright{ true }, + _perceptualColorNudging{ true } { auto dispatch = std::make_unique(*this); auto engine = std::make_unique(std::move(dispatch)); @@ -175,6 +176,7 @@ void Terminal::UpdateAppearance(const ICoreAppearance& appearance) _defaultBg = newBackgroundColor.with_alpha(0); _defaultFg = appearance.DefaultForeground(); _intenseIsBright = appearance.IntenseIsBright(); + _perceptualColorNudging = appearance.PerceptualColorNudging(); for (int i = 0; i < 16; i++) { diff --git a/src/cascadia/TerminalCore/Terminal.hpp b/src/cascadia/TerminalCore/Terminal.hpp index 27e26b7f280..c2ff2e131fc 100644 --- a/src/cascadia/TerminalCore/Terminal.hpp +++ b/src/cascadia/TerminalCore/Terminal.hpp @@ -283,6 +283,7 @@ class Microsoft::Terminal::Core::Terminal final : bool _bracketedPasteMode; bool _trimBlockSelection; bool _intenseIsBright; + bool _perceptualColorNudging; size_t _taskbarState; size_t _taskbarProgress; diff --git a/src/cascadia/TerminalCore/terminalrenderdata.cpp b/src/cascadia/TerminalCore/terminalrenderdata.cpp index c256694fb05..253e8d541ff 100644 --- a/src/cascadia/TerminalCore/terminalrenderdata.cpp +++ b/src/cascadia/TerminalCore/terminalrenderdata.cpp @@ -61,10 +61,19 @@ std::pair Terminal::GetAttributeColors(const TextAttribute& { colors.second |= 0xff000000; } - ColorFix colorFix{ colors.first }; - ColorFix result{}; - colorFix.PerceivableColor(colors.second, result); - return std::pair(result.rgb, colors.second); + std::pair result; + if (_perceptualColorNudging) + { + ColorFix colorFix{ colors.first }; + ColorFix fixResult{}; + colorFix.PerceivableColor(colors.second, fixResult); + result = std::pair(fixResult.rgb, colors.second); + } + else + { + result = colors; + } + return result; } COORD Terminal::GetCursorPosition() const noexcept diff --git a/src/cascadia/TerminalSettingsEditor/Appearances.h b/src/cascadia/TerminalSettingsEditor/Appearances.h index f6fa4b3d644..c1c3815f6ae 100644 --- a/src/cascadia/TerminalSettingsEditor/Appearances.h +++ b/src/cascadia/TerminalSettingsEditor/Appearances.h @@ -93,6 +93,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation OBSERVABLE_PROJECTED_SETTING(_appearance, BackgroundImageStretchMode); OBSERVABLE_PROJECTED_SETTING(_appearance, BackgroundImageAlignment); OBSERVABLE_PROJECTED_SETTING(_appearance, IntenseTextStyle); + OBSERVABLE_PROJECTED_SETTING(_appearance, PerceptualColorNudging); private: Model::AppearanceConfig _appearance; diff --git a/src/cascadia/TerminalSettingsEditor/Appearances.idl b/src/cascadia/TerminalSettingsEditor/Appearances.idl index fe2450b6d3c..a803984d8c6 100644 --- a/src/cascadia/TerminalSettingsEditor/Appearances.idl +++ b/src/cascadia/TerminalSettingsEditor/Appearances.idl @@ -46,6 +46,7 @@ namespace Microsoft.Terminal.Settings.Editor OBSERVABLE_PROJECTED_APPEARANCE_SETTING(Windows.UI.Xaml.Media.Stretch, BackgroundImageStretchMode); OBSERVABLE_PROJECTED_APPEARANCE_SETTING(Microsoft.Terminal.Settings.Model.ConvergedAlignment, BackgroundImageAlignment); OBSERVABLE_PROJECTED_APPEARANCE_SETTING(Microsoft.Terminal.Settings.Model.IntenseStyle, IntenseTextStyle); + OBSERVABLE_PROJECTED_APPEARANCE_SETTING(Boolean, PerceptualColorNudging); } [default_interface] runtimeclass Appearances : Windows.UI.Xaml.Controls.UserControl, Windows.UI.Xaml.Data.INotifyPropertyChanged diff --git a/src/cascadia/TerminalSettingsEditor/Appearances.xaml b/src/cascadia/TerminalSettingsEditor/Appearances.xaml index a2f715fd27e..c8d869377a9 100644 --- a/src/cascadia/TerminalSettingsEditor/Appearances.xaml +++ b/src/cascadia/TerminalSettingsEditor/Appearances.xaml @@ -150,6 +150,14 @@ SettingOverrideSource="{x:Bind Appearance.RetroTerminalEffectOverrideSource, Mode=OneWay}"> + + + + + diff --git a/src/cascadia/TerminalSettingsEditor/Resources/en-US/Resources.resw b/src/cascadia/TerminalSettingsEditor/Resources/en-US/Resources.resw index 5edf5c577fe..4d5c49a344f 100644 --- a/src/cascadia/TerminalSettingsEditor/Resources/en-US/Resources.resw +++ b/src/cascadia/TerminalSettingsEditor/Resources/en-US/Resources.resw @@ -747,6 +747,14 @@ When enabled, enables retro terminal effects such as glowing text and scan lines. A description for what the "retro terminal effects" setting does. Presented near "Profile_RetroTerminalEffect". + + Perceptual color nudging + Header for a control to toggle if we should 'nudge' the foreground color to make it more visible when necessary, based on the background color. + + + When enabled, enables perceptual color nudging, which will, only when necessary, 'nudge' the foreground color to make it more visible (based on the background color). + A description for what the "perceptual color nudging" setting does. Presented near "Profile_PerceptualColorNudging". + Scrollbar visibility Header for a control to select the visibility of the scrollbar in a session. diff --git a/src/cascadia/TerminalSettingsModel/AppearanceConfig.cpp b/src/cascadia/TerminalSettingsModel/AppearanceConfig.cpp index 67eb279eaa6..255ff3e0007 100644 --- a/src/cascadia/TerminalSettingsModel/AppearanceConfig.cpp +++ b/src/cascadia/TerminalSettingsModel/AppearanceConfig.cpp @@ -26,6 +26,7 @@ static constexpr std::string_view BackgroundImageAlignmentKey{ "backgroundImageA static constexpr std::string_view RetroTerminalEffectKey{ "experimental.retroTerminalEffect" }; static constexpr std::string_view PixelShaderPathKey{ "experimental.pixelShaderPath" }; static constexpr std::string_view IntenseTextStyleKey{ "intenseTextStyle" }; +static constexpr std::string_view PerceptualColorNudgingKey{ "perceptualColorNudging" }; winrt::Microsoft::Terminal::Settings::Model::implementation::AppearanceConfig::AppearanceConfig(const winrt::weak_ref sourceProfile) : _sourceProfile(sourceProfile) @@ -50,6 +51,7 @@ winrt::com_ptr AppearanceConfig::CopyAppearance(const winrt::c appearance->_RetroTerminalEffect = sourceAppearance->_RetroTerminalEffect; appearance->_PixelShaderPath = sourceAppearance->_PixelShaderPath; appearance->_IntenseTextStyle = sourceAppearance->_IntenseTextStyle; + appearance->_PerceptualColorNudging = sourceAppearance->_PerceptualColorNudging; return appearance; } @@ -71,6 +73,7 @@ Json::Value AppearanceConfig::ToJson() const JsonUtils::SetValueForKey(json, RetroTerminalEffectKey, _RetroTerminalEffect); JsonUtils::SetValueForKey(json, PixelShaderPathKey, _PixelShaderPath); JsonUtils::SetValueForKey(json, IntenseTextStyleKey, _IntenseTextStyle); + JsonUtils::SetValueForKey(json, PerceptualColorNudgingKey, _PerceptualColorNudging); return json; } @@ -102,6 +105,7 @@ void AppearanceConfig::LayerJson(const Json::Value& json) JsonUtils::GetValueForKey(json, RetroTerminalEffectKey, _RetroTerminalEffect); JsonUtils::GetValueForKey(json, PixelShaderPathKey, _PixelShaderPath); JsonUtils::GetValueForKey(json, IntenseTextStyleKey, _IntenseTextStyle); + JsonUtils::GetValueForKey(json, PerceptualColorNudgingKey, _PerceptualColorNudging); } winrt::Microsoft::Terminal::Settings::Model::Profile AppearanceConfig::SourceProfile() diff --git a/src/cascadia/TerminalSettingsModel/AppearanceConfig.h b/src/cascadia/TerminalSettingsModel/AppearanceConfig.h index 7a0c47985d0..412ba033501 100644 --- a/src/cascadia/TerminalSettingsModel/AppearanceConfig.h +++ b/src/cascadia/TerminalSettingsModel/AppearanceConfig.h @@ -54,6 +54,8 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation INHERITABLE_SETTING(Model::IAppearanceConfig, hstring, PixelShaderPath, L""); INHERITABLE_SETTING(Model::IAppearanceConfig, Model::IntenseStyle, IntenseTextStyle, Model::IntenseStyle::Bright); + INHERITABLE_SETTING(Model::IAppearanceConfig, bool, PerceptualColorNudging, true); + private: winrt::weak_ref _sourceProfile; }; diff --git a/src/cascadia/TerminalSettingsModel/CascadiaSettings.cpp b/src/cascadia/TerminalSettingsModel/CascadiaSettings.cpp index aff7cba52cf..0cdfb319896 100644 --- a/src/cascadia/TerminalSettingsModel/CascadiaSettings.cpp +++ b/src/cascadia/TerminalSettingsModel/CascadiaSettings.cpp @@ -343,6 +343,7 @@ winrt::Microsoft::Terminal::Settings::Model::Profile CascadiaSettings::Duplicate DUPLICATE_SETTING_MACRO_SUB(appearance, target, RetroTerminalEffect); DUPLICATE_SETTING_MACRO_SUB(appearance, target, CursorShape); DUPLICATE_SETTING_MACRO_SUB(appearance, target, CursorHeight); + DUPLICATE_SETTING_MACRO_SUB(appearance, target, PerceptualColorNudging); } // UnfocusedAppearance is treated as a single setting, diff --git a/src/cascadia/TerminalSettingsModel/IAppearanceConfig.idl b/src/cascadia/TerminalSettingsModel/IAppearanceConfig.idl index b33cf23e7dc..9ca590197ad 100644 --- a/src/cascadia/TerminalSettingsModel/IAppearanceConfig.idl +++ b/src/cascadia/TerminalSettingsModel/IAppearanceConfig.idl @@ -51,5 +51,7 @@ namespace Microsoft.Terminal.Settings.Model INHERITABLE_APPEARANCE_SETTING(Boolean, RetroTerminalEffect); INHERITABLE_APPEARANCE_SETTING(String, PixelShaderPath); INHERITABLE_APPEARANCE_SETTING(IntenseStyle, IntenseTextStyle); + + INHERITABLE_APPEARANCE_SETTING(Boolean, PerceptualColorNudging); }; } diff --git a/src/cascadia/TerminalSettingsModel/TerminalSettings.cpp b/src/cascadia/TerminalSettingsModel/TerminalSettings.cpp index de6b013472c..0246c936f65 100644 --- a/src/cascadia/TerminalSettingsModel/TerminalSettings.cpp +++ b/src/cascadia/TerminalSettingsModel/TerminalSettings.cpp @@ -201,6 +201,8 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation _IntenseIsBold = WI_IsFlagSet(appearance.IntenseTextStyle(), Microsoft::Terminal::Settings::Model::IntenseStyle::Bold); _IntenseIsBright = WI_IsFlagSet(appearance.IntenseTextStyle(), Microsoft::Terminal::Settings::Model::IntenseStyle::Bright); + + _PerceptualColorNudging = appearance.PerceptualColorNudging(); } // Method Description: diff --git a/src/cascadia/TerminalSettingsModel/TerminalSettings.h b/src/cascadia/TerminalSettingsModel/TerminalSettings.h index 3744c10573a..1880afef06f 100644 --- a/src/cascadia/TerminalSettingsModel/TerminalSettings.h +++ b/src/cascadia/TerminalSettingsModel/TerminalSettings.h @@ -114,6 +114,8 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation INHERITABLE_SETTING(Model::TerminalSettings, bool, IntenseIsBright); + INHERITABLE_SETTING(Model::TerminalSettings, bool, PerceptualColorNudging); + // ------------------------ End of Core Settings ----------------------- INHERITABLE_SETTING(Model::TerminalSettings, hstring, ProfileName); diff --git a/src/cascadia/UnitTests_Control/MockControlSettings.h b/src/cascadia/UnitTests_Control/MockControlSettings.h index d8400658988..25c51b9bf1e 100644 --- a/src/cascadia/UnitTests_Control/MockControlSettings.h +++ b/src/cascadia/UnitTests_Control/MockControlSettings.h @@ -47,6 +47,7 @@ namespace ControlUnitTests WINRT_PROPERTY(bool, TrimBlockSelection, false); WINRT_PROPERTY(bool, DetectURLs, true); WINRT_PROPERTY(bool, IntenseIsBright, true); + WINRT_PROPERTY(bool, PerceptualColorNudging, true); // ------------------------ End of Core Settings ----------------------- WINRT_PROPERTY(winrt::hstring, ProfileName); diff --git a/src/cascadia/UnitTests_TerminalCore/MockTermSettings.h b/src/cascadia/UnitTests_TerminalCore/MockTermSettings.h index 2c23d221712..043a57446e9 100644 --- a/src/cascadia/UnitTests_TerminalCore/MockTermSettings.h +++ b/src/cascadia/UnitTests_TerminalCore/MockTermSettings.h @@ -74,6 +74,7 @@ namespace TerminalCoreUnitTests void DetectURLs(bool) {} WINRT_PROPERTY(bool, IntenseIsBright, true); + WINRT_PROPERTY(bool, PerceptualColorNudging, true); private: int32_t _historySize; From 041e5ce3aeca2ade2970b061089039f6afb93d1e Mon Sep 17 00:00:00 2001 From: Pankaj Bhojwani Date: Thu, 2 Sep 2021 14:45:36 -0700 Subject: [PATCH 08/25] remove colorspace --- src/cascadia/TerminalCore/ColorFix.cpp | 298 ++++++++++++------------- src/cascadia/TerminalCore/ColorFix.hpp | 5 + 2 files changed, 145 insertions(+), 158 deletions(-) diff --git a/src/cascadia/TerminalCore/ColorFix.cpp b/src/cascadia/TerminalCore/ColorFix.cpp index 229700e2cf9..f67d011c08a 100644 --- a/src/cascadia/TerminalCore/ColorFix.cpp +++ b/src/cascadia/TerminalCore/ColorFix.cpp @@ -248,163 +248,144 @@ double dE00::_DegreesToRadians(double degrees) return degrees * (M_PI / 180); }; -// http://stackoverflow.com/a/8433985/1405560 -// http://www.easyrgb.com/index.php?X=MATH&H=08#text8 -namespace ColorSpace +// Method Description: +// - Clamps the given value to be between 0-255 inclusive +// Arguments: +// - v: the value to clamp +// Return Value: +// - The clamped value +BYTE dE00::Clamp(double v) { - // Method Description: - // - Clamps the given value to be between 0-255 inclusive - // Arguments: - // - v: the value to clamp - // Return Value: - // - The clamped value - BYTE min_max(double v) - { - if (v <= 0) - return 0; - else if (v >= 255) - return 255; - else - return (BYTE)v; - } + if (v <= 0) + return 0; + else if (v >= 255) + return 255; + else + return (BYTE)v; +} - // Method Description: - // - Converts a color in rgb format to a color in lab format - // - Reference: http://www.easyrgb.com/index.php?X=MATH&H=01#text1 - // Arguments: - // R, G, B: the rgb values of the input color - // l_s, a_s, b_s: where the output lab format should be stored - void rgb2lab(double R, double G, double B, double& l_s, double& a_s, double& b_s) - { - double var_R = R / 255.0; - double var_G = G / 255.0; - double var_B = B / 255.0; - - if (var_R > 0.04045) - var_R = pow(((var_R + 0.055) / 1.055), 2.4); - else - var_R = var_R / 12.92; - if (var_G > 0.04045) - var_G = pow(((var_G + 0.055) / 1.055), 2.4); - else - var_G = var_G / 12.92; - if (var_B > 0.04045) - var_B = pow(((var_B + 0.055) / 1.055), 2.4); - else - var_B = var_B / 12.92; - - var_R = var_R * 100.; - var_G = var_G * 100.; - var_B = var_B * 100.; - - //Observer. = 2 degrees, Illuminant = D65 - double X = var_R * 0.4124 + var_G * 0.3576 + var_B * 0.1805; - double Y = var_R * 0.2126 + var_G * 0.7152 + var_B * 0.0722; - double Z = var_R * 0.0193 + var_G * 0.1192 + var_B * 0.9505; - - double var_X = X / 95.047; //ref_X = 95.047 (Observer= 2 degrees, Illuminant= D65) - double var_Y = Y / 100.000; //ref_Y = 100.000 - double var_Z = Z / 108.883; //ref_Z = 108.883 - - if (var_X > 0.008856) - var_X = pow(var_X, (1. / 3.)); - else - var_X = (7.787 * var_X) + (16. / 116.); - if (var_Y > 0.008856) - var_Y = pow(var_Y, (1. / 3.)); - else - var_Y = (7.787 * var_Y) + (16. / 116.); - if (var_Z > 0.008856) - var_Z = pow(var_Z, (1. / 3.)); - else - var_Z = (7.787 * var_Z) + (16. / 116.); - - l_s = (116. * var_Y) - 16.; - a_s = 500. * (var_X - var_Y); - b_s = 200. * (var_Y - var_Z); - }; - - // Method Description: - // - Converts a color in lab format to a color in rgb format - // - Reference: http://www.easyrgb.com/index.php?X=MATH&H=01#text1 - // Arguments: - // l_s, a_s, b_s: the lab values of the input color - // R, G, B: where the output rgb format should be stored - void lab2rgb(double l_s, double a_s, double b_s, double& R, double& G, double& B) - { - double var_Y = (l_s + 16.) / 116.; - double var_X = a_s / 500. + var_Y; - double var_Z = var_Y - b_s / 200.; - - if (pow(var_Y, 3) > 0.008856) - var_Y = pow(var_Y, 3); - else - var_Y = (var_Y - 16. / 116.) / 7.787; - if (pow(var_X, 3) > 0.008856) - var_X = pow(var_X, 3); - else - var_X = (var_X - 16. / 116.) / 7.787; - if (pow(var_Z, 3) > 0.008856) - var_Z = pow(var_Z, 3); - else - var_Z = (var_Z - 16. / 116.) / 7.787; - - double X = 95.047 * var_X; //ref_X = 95.047 (Observer= 2 degrees, Illuminant= D65) - double Y = 100.000 * var_Y; //ref_Y = 100.000 - double Z = 108.883 * var_Z; //ref_Z = 108.883 - - var_X = X / 100.; //X from 0 to 95.047 (Observer = 2 degrees, Illuminant = D65) - var_Y = Y / 100.; //Y from 0 to 100.000 - var_Z = Z / 100.; //Z from 0 to 108.883 - - double var_R = var_X * 3.2406 + var_Y * -1.5372 + var_Z * -0.4986; - double var_G = var_X * -0.9689 + var_Y * 1.8758 + var_Z * 0.0415; - double var_B = var_X * 0.0557 + var_Y * -0.2040 + var_Z * 1.0570; - - if (var_R > 0.0031308) - var_R = 1.055 * pow(var_R, (1 / 2.4)) - 0.055; - else - var_R = 12.92 * var_R; - if (var_G > 0.0031308) - var_G = 1.055 * pow(var_G, (1 / 2.4)) - 0.055; - else - var_G = 12.92 * var_G; - if (var_B > 0.0031308) - var_B = 1.055 * pow(var_B, (1 / 2.4)) - 0.055; - else - var_B = 12.92 * var_B; - - R = var_R * 255.; - G = var_G * 255.; - B = var_B * 255.; - }; - - // Method Description: - // - Converts a color in lab format to a color in rgb format - // - Reference: http://www.easyrgb.com/index.php?X=MATH&H=01#text1 - // Arguments: - // l_s, a_s, b_s: the lab values of the input color - // rgb: where the output rgb format should be stored - void lab2rgb(double l_s, double a_s, double b_s, COLORREF& rgb) - { - double _r = 0, _g = 0, _b = 0; - lab2rgb(l_s, a_s, b_s, _r, _g, _b); - rgb = RGB(min_max(_r), min_max(_g), min_max(_b)); - }; - - // Method Description: - // - Given 2 colors, computes the DeltaE value between them - // Arguments: - // - lab1: the foreground color - // - lab2: the background color - // Return Value: - // - the DeltaE value - double DeltaE(ColorFix lab1, ColorFix lab2) - { - dE00 delta(lab1, lab2); - double de = delta.GetDeltaE(); - return de; - }; +// Method Description: +// - Converts a color in rgb format to a color in lab format +// - Reference: http://www.easyrgb.com/index.php?X=MATH&H=01#text1 +// Arguments: +// R, G, B: the rgb values of the input color +// l_s, a_s, b_s: where the output lab format should be stored +void dE00::RGBToLAB(double R, double G, double B, double& l_s, double& a_s, double& b_s) +{ + double var_R = R / 255.0; + double var_G = G / 255.0; + double var_B = B / 255.0; + + if (var_R > 0.04045) + var_R = pow(((var_R + 0.055) / 1.055), 2.4); + else + var_R = var_R / 12.92; + if (var_G > 0.04045) + var_G = pow(((var_G + 0.055) / 1.055), 2.4); + else + var_G = var_G / 12.92; + if (var_B > 0.04045) + var_B = pow(((var_B + 0.055) / 1.055), 2.4); + else + var_B = var_B / 12.92; + + var_R = var_R * 100.; + var_G = var_G * 100.; + var_B = var_B * 100.; + + //Observer. = 2 degrees, Illuminant = D65 + double X = var_R * 0.4124 + var_G * 0.3576 + var_B * 0.1805; + double Y = var_R * 0.2126 + var_G * 0.7152 + var_B * 0.0722; + double Z = var_R * 0.0193 + var_G * 0.1192 + var_B * 0.9505; + + double var_X = X / 95.047; //ref_X = 95.047 (Observer= 2 degrees, Illuminant= D65) + double var_Y = Y / 100.000; //ref_Y = 100.000 + double var_Z = Z / 108.883; //ref_Z = 108.883 + + if (var_X > 0.008856) + var_X = pow(var_X, (1. / 3.)); + else + var_X = (7.787 * var_X) + (16. / 116.); + if (var_Y > 0.008856) + var_Y = pow(var_Y, (1. / 3.)); + else + var_Y = (7.787 * var_Y) + (16. / 116.); + if (var_Z > 0.008856) + var_Z = pow(var_Z, (1. / 3.)); + else + var_Z = (7.787 * var_Z) + (16. / 116.); + + l_s = (116. * var_Y) - 16.; + a_s = 500. * (var_X - var_Y); + b_s = 200. * (var_Y - var_Z); +}; + +// Method Description: +// - Converts a color in lab format to a color in rgb format +// - Reference: http://www.easyrgb.com/index.php?X=MATH&H=01#text1 +// Arguments: +// l_s, a_s, b_s: the lab values of the input color +// R, G, B: where the output rgb format should be stored +void dE00::LABToRGB(double l_s, double a_s, double b_s, double& R, double& G, double& B) +{ + double var_Y = (l_s + 16.) / 116.; + double var_X = a_s / 500. + var_Y; + double var_Z = var_Y - b_s / 200.; + + if (pow(var_Y, 3) > 0.008856) + var_Y = pow(var_Y, 3); + else + var_Y = (var_Y - 16. / 116.) / 7.787; + if (pow(var_X, 3) > 0.008856) + var_X = pow(var_X, 3); + else + var_X = (var_X - 16. / 116.) / 7.787; + if (pow(var_Z, 3) > 0.008856) + var_Z = pow(var_Z, 3); + else + var_Z = (var_Z - 16. / 116.) / 7.787; + + double X = 95.047 * var_X; //ref_X = 95.047 (Observer= 2 degrees, Illuminant= D65) + double Y = 100.000 * var_Y; //ref_Y = 100.000 + double Z = 108.883 * var_Z; //ref_Z = 108.883 + + var_X = X / 100.; //X from 0 to 95.047 (Observer = 2 degrees, Illuminant = D65) + var_Y = Y / 100.; //Y from 0 to 100.000 + var_Z = Z / 100.; //Z from 0 to 108.883 + + double var_R = var_X * 3.2406 + var_Y * -1.5372 + var_Z * -0.4986; + double var_G = var_X * -0.9689 + var_Y * 1.8758 + var_Z * 0.0415; + double var_B = var_X * 0.0557 + var_Y * -0.2040 + var_Z * 1.0570; + + if (var_R > 0.0031308) + var_R = 1.055 * pow(var_R, (1 / 2.4)) - 0.055; + else + var_R = 12.92 * var_R; + if (var_G > 0.0031308) + var_G = 1.055 * pow(var_G, (1 / 2.4)) - 0.055; + else + var_G = 12.92 * var_G; + if (var_B > 0.0031308) + var_B = 1.055 * pow(var_B, (1 / 2.4)) - 0.055; + else + var_B = 12.92 * var_B; + + R = var_R * 255.; + G = var_G * 255.; + B = var_B * 255.; +}; + +// Method Description: +// - Converts a color in lab format to a color in rgb format +// - Reference: http://www.easyrgb.com/index.php?X=MATH&H=01#text1 +// Arguments: +// - l_s, a_s, b_s: the lab values of the input color +// - rgb: where the output rgb format should be stored +void dE00::LABToRGB(double l_s, double a_s, double b_s, COLORREF& rgb) +{ + double _r = 0, _g = 0, _b = 0; + LABToRGB(l_s, a_s, b_s, _r, _g, _b); + rgb = RGB(Clamp(_r), Clamp(_g), Clamp(_b)); }; ColorFix::ColorFix() @@ -441,14 +422,14 @@ ColorFix::ColorFix(const ColorFix& color) // - Populates our L, A, B values, based on our r, g, b values void ColorFix::ToLab() { - ColorSpace::rgb2lab(r, g, b, L, A, B); + dE00::RGBToLAB(r, g, b, L, A, B); } // Method Description: // - Populates our r, g, b values, based on our L, A, B values void ColorFix::ToRGB() { - ColorSpace::lab2rgb(L, A, B, rgb); + dE00::LABToRGB(L, A, B, rgb); } // Method Description: @@ -459,7 +440,8 @@ void ColorFix::ToRGB() // - The DeltaE value between us and that color double ColorFix::DeltaE(ColorFix color) { - return ColorSpace::DeltaE(*this, color); + dE00 delta{ *this, color }; + return delta.GetDeltaE(); } // Method Description: diff --git a/src/cascadia/TerminalCore/ColorFix.hpp b/src/cascadia/TerminalCore/ColorFix.hpp index b0ab58ee6f7..c3146dd460f 100644 --- a/src/cascadia/TerminalCore/ColorFix.hpp +++ b/src/cascadia/TerminalCore/ColorFix.hpp @@ -43,6 +43,11 @@ struct dE00 dE00(ColorFix x1, ColorFix x2, double weightLightness = 1, double weightChroma = 1, double weightHue = 1); double GetDeltaE(); + static void RGBToLAB(double R, double G, double B, double& l_s, double& a_s, double& b_s); + static void LABToRGB(double R, double G, double B, double& l_s, double& a_s, double& b_s); + static void LABToRGB(double l_s, double a_s, double b_s, COLORREF& rgb); + static BYTE Clamp(double v); + private: double _GetRSubT(); double _GetT(); From 12e8d6c95801b0151d149574bc76bfde3f9b4224 Mon Sep 17 00:00:00 2001 From: Pankaj Bhojwani Date: Thu, 2 Sep 2021 15:59:23 -0700 Subject: [PATCH 09/25] neater --- src/cascadia/TerminalCore/ColorFix.cpp | 153 ++++++++++--------------- src/cascadia/TerminalCore/ColorFix.hpp | 9 +- 2 files changed, 66 insertions(+), 96 deletions(-) diff --git a/src/cascadia/TerminalCore/ColorFix.cpp b/src/cascadia/TerminalCore/ColorFix.cpp index f67d011c08a..44a1ecb312e 100644 --- a/src/cascadia/TerminalCore/ColorFix.cpp +++ b/src/cascadia/TerminalCore/ColorFix.cpp @@ -248,33 +248,46 @@ double dE00::_DegreesToRadians(double degrees) return degrees * (M_PI / 180); }; -// Method Description: -// - Clamps the given value to be between 0-255 inclusive -// Arguments: -// - v: the value to clamp -// Return Value: -// - The clamped value -BYTE dE00::Clamp(double v) +ColorFix::ColorFix() { - if (v <= 0) - return 0; - else if (v >= 255) - return 255; - else - return (BYTE)v; + rgb = 0; + L = 0; + A = 0; + B = 0; +} + +ColorFix::ColorFix(COLORREF color) +{ + rgb = color; + ToLab(); +} + +ColorFix::ColorFix(double l, double a, double b) +{ + L = l; + A = a; + B = b; + ToRGB(); +} + +ColorFix::ColorFix(const ColorFix& color) +{ + L = color.L; + A = color.A; + B = color.B; + rgb = color.rgb; } // Method Description: +// - Populates our L, A, B values, based on our r, g, b values // - Converts a color in rgb format to a color in lab format // - Reference: http://www.easyrgb.com/index.php?X=MATH&H=01#text1 -// Arguments: -// R, G, B: the rgb values of the input color -// l_s, a_s, b_s: where the output lab format should be stored -void dE00::RGBToLAB(double R, double G, double B, double& l_s, double& a_s, double& b_s) +void ColorFix::ToLab() { - double var_R = R / 255.0; - double var_G = G / 255.0; - double var_B = B / 255.0; + //dE00::RGBToLAB(r, g, b, L, A, B); + double var_R = r / 255.0; + double var_G = g / 255.0; + double var_B = b / 255.0; if (var_R > 0.04045) var_R = pow(((var_R + 0.055) / 1.055), 2.4); @@ -315,22 +328,20 @@ void dE00::RGBToLAB(double R, double G, double B, double& l_s, double& a_s, doub else var_Z = (7.787 * var_Z) + (16. / 116.); - l_s = (116. * var_Y) - 16.; - a_s = 500. * (var_X - var_Y); - b_s = 200. * (var_Y - var_Z); -}; + L = (116. * var_Y) - 16.; + A = 500. * (var_X - var_Y); + B = 200. * (var_Y - var_Z); +} // Method Description: +// - Populates our r, g, b values, based on our L, A, B values // - Converts a color in lab format to a color in rgb format // - Reference: http://www.easyrgb.com/index.php?X=MATH&H=01#text1 -// Arguments: -// l_s, a_s, b_s: the lab values of the input color -// R, G, B: where the output rgb format should be stored -void dE00::LABToRGB(double l_s, double a_s, double b_s, double& R, double& G, double& B) +void ColorFix::ToRGB() { - double var_Y = (l_s + 16.) / 116.; - double var_X = a_s / 500. + var_Y; - double var_Z = var_Y - b_s / 200.; + double var_Y = (L + 16.) / 116.; + double var_X = A / 500. + var_Y; + double var_Z = var_Y - B / 200.; if (pow(var_Y, 3) > 0.008856) var_Y = pow(var_Y, 3); @@ -370,66 +381,9 @@ void dE00::LABToRGB(double l_s, double a_s, double b_s, double& R, double& G, do else var_B = 12.92 * var_B; - R = var_R * 255.; - G = var_G * 255.; - B = var_B * 255.; -}; - -// Method Description: -// - Converts a color in lab format to a color in rgb format -// - Reference: http://www.easyrgb.com/index.php?X=MATH&H=01#text1 -// Arguments: -// - l_s, a_s, b_s: the lab values of the input color -// - rgb: where the output rgb format should be stored -void dE00::LABToRGB(double l_s, double a_s, double b_s, COLORREF& rgb) -{ - double _r = 0, _g = 0, _b = 0; - LABToRGB(l_s, a_s, b_s, _r, _g, _b); - rgb = RGB(Clamp(_r), Clamp(_g), Clamp(_b)); -}; - -ColorFix::ColorFix() -{ - rgb = 0; - L = 0; - A = 0; - B = 0; -} - -ColorFix::ColorFix(COLORREF color) -{ - rgb = color; - ToLab(); -} - -ColorFix::ColorFix(double l, double a, double b) -{ - L = l; - A = a; - B = b; - ToRGB(); -} - -ColorFix::ColorFix(const ColorFix& color) -{ - L = color.L; - A = color.A; - B = color.B; - rgb = color.rgb; -} - -// Method Description: -// - Populates our L, A, B values, based on our r, g, b values -void ColorFix::ToLab() -{ - dE00::RGBToLAB(r, g, b, L, A, B); -} - -// Method Description: -// - Populates our r, g, b values, based on our L, A, B values -void ColorFix::ToRGB() -{ - dE00::LABToRGB(L, A, B, rgb); + r = _Clamp(var_R * 255.); + g = _Clamp(var_G * 255.); + b = _Clamp(var_B * 255.); } // Method Description: @@ -490,3 +444,20 @@ bool ColorFix::PerceivableColor(COLORREF back, ColorFix& pColor, double* oldDE, pColor = *this; return bChanged; } + +// Method Description: +// - Clamps the given value to be between 0-255 inclusive +// - Converts the result to BYTE +// Arguments: +// - v: the value to clamp +// Return Value: +// - The clamped value +BYTE ColorFix::_Clamp(double v) +{ + if (v <= 0) + return 0; + else if (v >= 255) + return 255; + else + return (BYTE)v; +} diff --git a/src/cascadia/TerminalCore/ColorFix.hpp b/src/cascadia/TerminalCore/ColorFix.hpp index c3146dd460f..80194cee438 100644 --- a/src/cascadia/TerminalCore/ColorFix.hpp +++ b/src/cascadia/TerminalCore/ColorFix.hpp @@ -8,6 +8,7 @@ struct ColorFix { +public: ColorFix(); ColorFix(COLORREF color); ColorFix(double l, double a, double b); @@ -35,6 +36,9 @@ struct ColorFix { double L, A, B; }; + +private: + BYTE _Clamp(double v); }; struct dE00 @@ -43,11 +47,6 @@ struct dE00 dE00(ColorFix x1, ColorFix x2, double weightLightness = 1, double weightChroma = 1, double weightHue = 1); double GetDeltaE(); - static void RGBToLAB(double R, double G, double B, double& l_s, double& a_s, double& b_s); - static void LABToRGB(double R, double G, double B, double& l_s, double& a_s, double& b_s); - static void LABToRGB(double l_s, double a_s, double b_s, COLORREF& rgb); - static BYTE Clamp(double v); - private: double _GetRSubT(); double _GetT(); From 384bf498f1c178bf4c4e032e7511e2731cc0c6cd Mon Sep 17 00:00:00 2001 From: Pankaj Bhojwani Date: Thu, 2 Sep 2021 16:04:35 -0700 Subject: [PATCH 10/25] private --- src/cascadia/TerminalCore/ColorFix.cpp | 12 ++++++------ src/cascadia/TerminalCore/ColorFix.hpp | 5 ++--- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/cascadia/TerminalCore/ColorFix.cpp b/src/cascadia/TerminalCore/ColorFix.cpp index 44a1ecb312e..ee5d23656bd 100644 --- a/src/cascadia/TerminalCore/ColorFix.cpp +++ b/src/cascadia/TerminalCore/ColorFix.cpp @@ -259,7 +259,7 @@ ColorFix::ColorFix() ColorFix::ColorFix(COLORREF color) { rgb = color; - ToLab(); + _ToLab(); } ColorFix::ColorFix(double l, double a, double b) @@ -267,7 +267,7 @@ ColorFix::ColorFix(double l, double a, double b) L = l; A = a; B = b; - ToRGB(); + _ToRGB(); } ColorFix::ColorFix(const ColorFix& color) @@ -282,7 +282,7 @@ ColorFix::ColorFix(const ColorFix& color) // - Populates our L, A, B values, based on our r, g, b values // - Converts a color in rgb format to a color in lab format // - Reference: http://www.easyrgb.com/index.php?X=MATH&H=01#text1 -void ColorFix::ToLab() +void ColorFix::_ToLab() { //dE00::RGBToLAB(r, g, b, L, A, B); double var_R = r / 255.0; @@ -337,7 +337,7 @@ void ColorFix::ToLab() // - Populates our r, g, b values, based on our L, A, B values // - Converts a color in lab format to a color in rgb format // - Reference: http://www.easyrgb.com/index.php?X=MATH&H=01#text1 -void ColorFix::ToRGB() +void ColorFix::_ToRGB() { double var_Y = (L + 16.) / 116.; double var_X = A / 500. + var_Y; @@ -399,7 +399,7 @@ double ColorFix::DeltaE(ColorFix color) } // Method Description: -// - Given a background color, change our own color to make it more perceivable if necessary +// - Given a background color, change the foreground color to make it more perceivable if necessary // - Arguments: // - back: the color to compare against // - pColor: where to store the resulting color @@ -439,7 +439,7 @@ bool ColorFix::PerceivableColor(COLORREF back, ColorFix& pColor, double* oldDE, } wrap: if (bChanged) - pColor.ToRGB(); + pColor._ToRGB(); else pColor = *this; return bChanged; diff --git a/src/cascadia/TerminalCore/ColorFix.hpp b/src/cascadia/TerminalCore/ColorFix.hpp index 80194cee438..b6a99225cf8 100644 --- a/src/cascadia/TerminalCore/ColorFix.hpp +++ b/src/cascadia/TerminalCore/ColorFix.hpp @@ -14,9 +14,6 @@ struct ColorFix ColorFix(double l, double a, double b); ColorFix(const ColorFix& color); - void ToLab(); - void ToRGB(); - double DeltaE(ColorFix color); bool PerceivableColor(COLORREF back, ColorFix& pColor, double* oldDE = NULL, double* newDE = NULL); @@ -38,6 +35,8 @@ struct ColorFix }; private: + void _ToLab(); + void _ToRGB(); BYTE _Clamp(double v); }; From 9f9af2eb94230899dfce6b8f63cb66a778ad6226 Mon Sep 17 00:00:00 2001 From: Pankaj Bhojwani Date: Fri, 3 Sep 2021 09:35:43 -0700 Subject: [PATCH 11/25] dedcode --- src/cascadia/TerminalCore/ColorFix.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/cascadia/TerminalCore/ColorFix.cpp b/src/cascadia/TerminalCore/ColorFix.cpp index ee5d23656bd..1b6478d1d22 100644 --- a/src/cascadia/TerminalCore/ColorFix.cpp +++ b/src/cascadia/TerminalCore/ColorFix.cpp @@ -284,7 +284,6 @@ ColorFix::ColorFix(const ColorFix& color) // - Reference: http://www.easyrgb.com/index.php?X=MATH&H=01#text1 void ColorFix::_ToLab() { - //dE00::RGBToLAB(r, g, b, L, A, B); double var_R = r / 255.0; double var_G = g / 255.0; double var_B = b / 255.0; From 326decb0e9626d093024a0e29f853f9e48ef4533 Mon Sep 17 00:00:00 2001 From: Pankaj Bhojwani Date: Wed, 8 Sep 2021 14:52:09 -0700 Subject: [PATCH 12/25] delete a bunch, static functions --- src/cascadia/TerminalCore/ColorFix.cpp | 305 ++++-------------- src/cascadia/TerminalCore/ColorFix.hpp | 36 +-- .../TerminalCore/terminalrenderdata.cpp | 5 +- 3 files changed, 62 insertions(+), 284 deletions(-) diff --git a/src/cascadia/TerminalCore/ColorFix.cpp b/src/cascadia/TerminalCore/ColorFix.cpp index 1b6478d1d22..43d8fcc7761 100644 --- a/src/cascadia/TerminalCore/ColorFix.cpp +++ b/src/cascadia/TerminalCore/ColorFix.cpp @@ -1,6 +1,5 @@ #include "pch.h" -#define _USE_MATH_DEFINES #include #include #include "ColorFix.hpp" @@ -9,245 +8,100 @@ const double gMinThreshold = 12.0; const double gExpThreshold = 20.0; const double gLStep = 5.0; +constexpr double rad006 = 0.104719755119659774; +constexpr double rad025 = 0.436332312998582394; +constexpr double rad030 = 0.523598775598298873; +constexpr double rad060 = 1.047197551196597746; +constexpr double rad063 = 1.099557428756427633; +constexpr double rad180 = 3.141592653589793238; +constexpr double rad275 = 4.799655442984406336; +constexpr double rad360 = 6.283185307179586476; + +double GetHPrimeFn(double x, double y) +{ + if (x == 0 && y == 0) + { + return 0; + } + + const auto hueAngle = atan2(x, y); + return hueAngle >= 0 ? hueAngle : hueAngle + rad360; +} + // DeltaE 2000 // Source: https://github.com/zschuessler/DeltaE -dE00::dE00(ColorFix x1, ColorFix x2, double weightLightness, double weightChroma, double weightHue) +double ColorFix::GetDeltaE(ColorFix x1, ColorFix x2) { - _x1 = x1; - _x2 = x2; - - _kSubL = weightLightness; - _kSubC = weightChroma; - _kSubH = weightHue; + constexpr double kSubL = 1; + constexpr double kSubC = 1; + constexpr double kSubH = 1; // Delta L Prime - _deltaLPrime = _x2.L - _x1.L; + const double deltaLPrime = x2.L - x1.L; // L Bar - _lBar = (_x1.L + _x2.L) / 2; + const double lBar = (x1.L + x2.L) / 2; // C1 & C2 - _c1 = sqrt(pow(_x1.A, 2) + pow(_x1.B, 2)); - _c2 = sqrt(pow(_x2.A, 2) + pow(_x2.B, 2)); + const double c1 = sqrt(pow(x1.A, 2) + pow(x1.B, 2)); + const double c2 = sqrt(pow(x2.A, 2) + pow(x2.B, 2)); // C Bar - _cBar = (_c1 + _c2) / 2; + const double cBar = (c1 + c2) / 2; // A Prime 1 - _aPrime1 = _x1.A + - (_x1.A / 2) * - (1 - sqrt( - pow(_cBar, 7) / - (pow(_cBar, 7) + pow((double)25, 7)))); + const double aPrime1 = x1.A + (x1.A / 2) * (1 - sqrt(pow(cBar, 7) / (pow(cBar, 7) + pow(25.0, 7)))); // A Prime 2 - _aPrime2 = _x2.A + - (_x2.A / 2) * - (1 - sqrt( - pow(_cBar, 7) / - (pow(_cBar, 7) + pow((double)25, 7)))); + const double aPrime2 = x2.A + (x2.A / 2) * (1 - sqrt(pow(cBar, 7) / (pow(cBar, 7) + pow(25.0, 7)))); // C Prime 1 - _cPrime1 = sqrt( - pow(_aPrime1, 2) + - pow(_x1.B, 2)); + const double cPrime1 = sqrt(pow(aPrime1, 2) + pow(x1.B, 2)); // C Prime 2 - _cPrime2 = sqrt( - pow(_aPrime2, 2) + - pow(_x2.B, 2)); + const double cPrime2 = sqrt(pow(aPrime2, 2) + pow(x2.B, 2)); // C Bar Prime - _cBarPrime = (_cPrime1 + _cPrime2) / 2; + const double cBarPrime = (cPrime1 + cPrime2) / 2; // Delta C Prime - _deltaCPrime = _cPrime2 - _cPrime1; + const double deltaCPrime = cPrime2 - cPrime1; // S sub L - _sSubL = 1 + ((0.015 * pow(_lBar - 50, 2)) / - sqrt(20 + pow(_lBar - 50, 2))); + const double sSubL = 1 + ((0.015 * pow(lBar - 50, 2)) / sqrt(20 + pow(lBar - 50, 2))); // S sub C - _sSubC = 1 + 0.045 * _cBarPrime; -} + const double sSubC = 1 + 0.045 * cBarPrime; -// Method Description: -// - Calculates and returns the deltaE value. -// Return Value: -// - The deltaE value -double dE00::GetDeltaE() -{ // h Prime 1 - _hPrime1 = _GetHPrime1(); + const double hPrime1 = GetHPrimeFn(x1.B, aPrime1); // h Prime 2 - _hPrime2 = _GetHPrime2(); + const double hPrime2 = GetHPrimeFn(x2.B, aPrime2); // Delta H Prime - _deltaHPrime = 2 * sqrt(_cPrime1 * _cPrime2) * sin(_DegreesToRadians(_GetDeltaHPrime()) / 2); + const double deltaHPrime = 0 == c1 || 0 == c2 ? 0 : 2 * sqrt(cPrime1 * cPrime2) * sin(abs(hPrime1 - hPrime2) <= rad180 ? hPrime2 - hPrime1 : (hPrime2 <= hPrime1 ? hPrime2 - hPrime1 + rad360 : hPrime2 - hPrime1 - rad360) / 2); // H Bar Prime - _hBarPrime = _GetHBarPrime(); + const double hBarPrime = (abs(hPrime1 - hPrime2) > rad180) ? (hPrime1 + hPrime2 + rad360) / 2 : (hPrime1 + hPrime2) / 2; // T - _t = _GetT(); + const double t = 1 - 0.17 * cos(hBarPrime - rad030) + 0.24 * cos(2 * hBarPrime) + 0.32 * cos(3 * hBarPrime + rad006) - 0.20 * cos(4 * hBarPrime - rad063); // S sub H - _sSubH = 1 + 0.015 * _cBarPrime * _t; + const double sSubH = 1 + 0.015 * cBarPrime * t; // R sub T - _rSubT = _GetRSubT(); + const double rSubT = -2 * sqrt(pow(cBarPrime, 7) / (pow(cBarPrime, 7) + pow(25.0, 7))) * sin(rad060 * exp(-pow((hBarPrime - rad275) / rad025, 2))); // Put it all together! - double lightness = _deltaLPrime / (_kSubL * _sSubL); - double chroma = _deltaCPrime / (_kSubC * _sSubC); - double hue = _deltaHPrime / (_kSubH * _sSubH); - - return sqrt( - pow(lightness, 2) + - pow(chroma, 2) + - pow(hue, 2) + - _rSubT * chroma * hue); -}; - -// Method Description: -// - Calculates and returns the RT variable -// Return Value: -// - The RT variable -double dE00::_GetRSubT() -{ - return -2 * - sqrt( - pow(_cBarPrime, 7) / - (pow(_cBarPrime, 7) + pow((double)25, 7))) * - sin(_DegreesToRadians( - 60 * - exp( - -( - pow( - (_hBarPrime - 275) / 25, 2))))); -}; - -// Method Description: -// - Calculates and returns the T variable -// Return Value: -// - The T variable -double dE00::_GetT() -{ - return 1 - - 0.17 * cos(_DegreesToRadians(_hBarPrime - 30)) + - 0.24 * cos(_DegreesToRadians(2 * _hBarPrime)) + - 0.32 * cos(_DegreesToRadians(3 * _hBarPrime + 6)) - - 0.20 * cos(_DegreesToRadians(4 * _hBarPrime - 63)); -}; - -// Method Description: -// - Calculates and returns the HBarPrime variable -// Return Value: -// - The HBarPrime variable -double dE00::_GetHBarPrime() -{ - if (abs(_hPrime1 - _hPrime2) > 180) - { - return (_hPrime1 + _hPrime2 + 360) / 2; - } - - return (_hPrime1 + _hPrime2) / 2; -}; - -// Method Description: -// - Calculates and returns the Delta h prime variable -// Return Value: -// - The Delta h prime variable -double dE00::_GetDeltaHPrime() -{ - // When either _c1 prime or _c2 prime is zero, then deltaH prime is irrelevant and may be set to - // zero. - if (0 == _c1 || 0 == _c2) - { - return 0; - } - - if (abs(_hPrime1 - _hPrime2) <= 180) - { - return _hPrime2 - _hPrime1; - } - - if (_hPrime2 <= _hPrime1) - { - return _hPrime2 - _hPrime1 + 360; - } - else - { - return _hPrime2 - _hPrime1 - 360; - } -}; + const double lightness = deltaLPrime / (kSubL * sSubL); + const double chroma = deltaCPrime / (kSubC * sSubC); + const double hue = deltaHPrime / (kSubH * sSubH); -// Method Description: -// - Calculates and returns the h Prime 1 variable -// Return Value: -// - The h Prime 1 variable -double dE00::_GetHPrime1() -{ - return _GetHPrimeFn(_x1.B, _aPrime1); + return sqrt(pow(lightness, 2) + pow(chroma, 2) + pow(hue, 2) + rSubT * chroma * hue); } -// Method Description: -// - Calculates and returns the h Prime 2 variable -// Return Value: -// - The h Prime 2 variable -double dE00::_GetHPrime2() -{ - return _GetHPrimeFn(_x2.B, _aPrime2); -}; - -// Method Description: -// - Helper function to calculate the h Prime values -// Return Value: -// - The h Prime value -double dE00::_GetHPrimeFn(double x, double y) -{ - double hueAngle; - - if (x == 0 && y == 0) - { - return 0; - } - - hueAngle = _RadiansToDegrees(atan2(x, y)); - - if (hueAngle >= 0) - { - return hueAngle; - } - else - { - return hueAngle + 360; - } -}; - -// Method Description: -// - Converts radians to degrees -// Arguments: -// - radians: the angle in radians -// Return Value: -// - the given angle, converted to degrees -double dE00::_RadiansToDegrees(double radians) -{ - return radians * (180 / M_PI); -}; - -// Method Description: -// - Converts degrees to radians -// Arguments: -// - degrees: the angle in degrees -// Return Value: -// - the given angle, converted to radians -double dE00::_DegreesToRadians(double degrees) -{ - return degrees * (M_PI / 180); -}; - ColorFix::ColorFix() { rgb = 0; @@ -262,22 +116,6 @@ ColorFix::ColorFix(COLORREF color) _ToLab(); } -ColorFix::ColorFix(double l, double a, double b) -{ - L = l; - A = a; - B = b; - _ToRGB(); -} - -ColorFix::ColorFix(const ColorFix& color) -{ - L = color.L; - A = color.A; - B = color.B; - rgb = color.rgb; -} - // Method Description: // - Populates our L, A, B values, based on our r, g, b values // - Converts a color in rgb format to a color in lab format @@ -385,18 +223,6 @@ void ColorFix::_ToRGB() b = _Clamp(var_B * 255.); } -// Method Description: -// - Given a color, computes the DeltaE between us and that color -// - Arguments: -// - color: the color to compare against -// - Return Value: -// - The DeltaE value between us and that color -double ColorFix::DeltaE(ColorFix color) -{ - dE00 delta{ *this, color }; - return delta.GetDeltaE(); -} - // Method Description: // - Given a background color, change the foreground color to make it more perceivable if necessary // - Arguments: @@ -404,44 +230,31 @@ double ColorFix::DeltaE(ColorFix color) // - pColor: where to store the resulting color // - Return Value: // - True if we changed our color, false otherwise -bool ColorFix::PerceivableColor(COLORREF back, ColorFix& pColor, double* oldDE, double* newDE) +COLORREF ColorFix::GetPerceivableColor(COLORREF fg, COLORREF bg) { - bool bChanged = false; - ColorFix backLab(back); - double de1 = DeltaE(backLab); - if (oldDE) - *oldDE = de1; - if (newDE) - *newDE = de1; + ColorFix backLab(bg); + ColorFix frontLab(fg); + double de1 = GetDeltaE(frontLab, backLab); if (de1 < gMinThreshold) { for (int i = 0; i <= 1; i++) { double step = (i == 0) ? gLStep : -gLStep; - pColor.L = L + step; - pColor.A = A; - pColor.B = B; + frontLab.L += step; - while (((i == 0) && (pColor.L <= 100)) || ((i == 1) && (pColor.L >= 0))) + while (((i == 0) && (frontLab.L <= 100)) || ((i == 1) && (frontLab.L >= 0))) { - double de2 = pColor.DeltaE(backLab); + double de2 = GetDeltaE(frontLab, backLab); if (de2 >= gExpThreshold) { - if (newDE) - *newDE = de2; - bChanged = true; - goto wrap; + frontLab._ToRGB(); + return frontLab.rgb; } - pColor.L += step; + frontLab.L += step; } } } -wrap: - if (bChanged) - pColor._ToRGB(); - else - pColor = *this; - return bChanged; + return frontLab.rgb; } // Method Description: diff --git a/src/cascadia/TerminalCore/ColorFix.hpp b/src/cascadia/TerminalCore/ColorFix.hpp index b6a99225cf8..f270bc9f430 100644 --- a/src/cascadia/TerminalCore/ColorFix.hpp +++ b/src/cascadia/TerminalCore/ColorFix.hpp @@ -11,12 +11,9 @@ struct ColorFix public: ColorFix(); ColorFix(COLORREF color); - ColorFix(double l, double a, double b); - ColorFix(const ColorFix& color); - double DeltaE(ColorFix color); - - bool PerceivableColor(COLORREF back, ColorFix& pColor, double* oldDE = NULL, double* newDE = NULL); + static double GetDeltaE(ColorFix x1, ColorFix x2); + static COLORREF GetPerceivableColor(COLORREF fg, COLORREF bg); // RGB union @@ -39,32 +36,3 @@ struct ColorFix void _ToRGB(); BYTE _Clamp(double v); }; - -struct dE00 -{ -public: - dE00(ColorFix x1, ColorFix x2, double weightLightness = 1, double weightChroma = 1, double weightHue = 1); - double GetDeltaE(); - -private: - double _GetRSubT(); - double _GetT(); - double _GetHBarPrime(); - double _GetDeltaHPrime(); - double _GetHPrime1(); - double _GetHPrime2(); - double _GetHPrimeFn(double x, double y); - double _RadiansToDegrees(double radians); - double _DegreesToRadians(double degrees); - - ColorFix _x1, _x2; - double _kSubL, _kSubC, _kSubH; - double _deltaLPrime, _lBar; - double _c1, _c2, _cBar; - double _aPrime1, _aPrime2; - double _cPrime1, _cPrime2; - double _cBarPrime, _deltaCPrime; - double _sSubL, _sSubC; - double _hPrime1, _hPrime2, _deltaHPrime; - double _hBarPrime, _t, _sSubH, _rSubT; -}; diff --git a/src/cascadia/TerminalCore/terminalrenderdata.cpp b/src/cascadia/TerminalCore/terminalrenderdata.cpp index 253e8d541ff..5b17772fbfe 100644 --- a/src/cascadia/TerminalCore/terminalrenderdata.cpp +++ b/src/cascadia/TerminalCore/terminalrenderdata.cpp @@ -64,10 +64,7 @@ std::pair Terminal::GetAttributeColors(const TextAttribute& std::pair result; if (_perceptualColorNudging) { - ColorFix colorFix{ colors.first }; - ColorFix fixResult{}; - colorFix.PerceivableColor(colors.second, fixResult); - result = std::pair(fixResult.rgb, colors.second); + result = std::pair(ColorFix::GetPerceivableColor(colors.first, colors.second), colors.second); } else { From 5bcbde25a483d2b24869efc1a079cf72e75a7f32 Mon Sep 17 00:00:00 2001 From: Pankaj Bhojwani Date: Wed, 8 Sep 2021 15:00:14 -0700 Subject: [PATCH 13/25] update comments --- src/cascadia/TerminalCore/ColorFix.cpp | 46 +++++++++++++------------- src/cascadia/TerminalCore/ColorFix.hpp | 2 +- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/cascadia/TerminalCore/ColorFix.cpp b/src/cascadia/TerminalCore/ColorFix.cpp index 43d8fcc7761..01470ab018b 100644 --- a/src/cascadia/TerminalCore/ColorFix.cpp +++ b/src/cascadia/TerminalCore/ColorFix.cpp @@ -17,7 +17,15 @@ constexpr double rad180 = 3.141592653589793238; constexpr double rad275 = 4.799655442984406336; constexpr double rad360 = 6.283185307179586476; -double GetHPrimeFn(double x, double y) +ColorFix::ColorFix(COLORREF color) +{ + rgb = color; + _ToLab(); +} + +// Method Description: +// - Helper function to calculate HPrime +double ColorFix::_GetHPrimeFn(double x, double y) { if (x == 0 && y == 0) { @@ -28,8 +36,13 @@ double GetHPrimeFn(double x, double y) return hueAngle >= 0 ? hueAngle : hueAngle + rad360; } -// DeltaE 2000 -// Source: https://github.com/zschuessler/DeltaE +// Method Description: +// - Given 2 colors, computes the DeltaE value between them +// Arguments: +// - x1: the first color +// - x2: the second color +// Return Value: +// - The DeltaE value between x1 and x2 double ColorFix::GetDeltaE(ColorFix x1, ColorFix x2) { constexpr double kSubL = 1; @@ -74,10 +87,10 @@ double ColorFix::GetDeltaE(ColorFix x1, ColorFix x2) const double sSubC = 1 + 0.045 * cBarPrime; // h Prime 1 - const double hPrime1 = GetHPrimeFn(x1.B, aPrime1); + const double hPrime1 = _GetHPrimeFn(x1.B, aPrime1); // h Prime 2 - const double hPrime2 = GetHPrimeFn(x2.B, aPrime2); + const double hPrime2 = _GetHPrimeFn(x2.B, aPrime2); // Delta H Prime const double deltaHPrime = 0 == c1 || 0 == c2 ? 0 : 2 * sqrt(cPrime1 * cPrime2) * sin(abs(hPrime1 - hPrime2) <= rad180 ? hPrime2 - hPrime1 : (hPrime2 <= hPrime1 ? hPrime2 - hPrime1 + rad360 : hPrime2 - hPrime1 - rad360) / 2); @@ -102,20 +115,6 @@ double ColorFix::GetDeltaE(ColorFix x1, ColorFix x2) return sqrt(pow(lightness, 2) + pow(chroma, 2) + pow(hue, 2) + rSubT * chroma * hue); } -ColorFix::ColorFix() -{ - rgb = 0; - L = 0; - A = 0; - B = 0; -} - -ColorFix::ColorFix(COLORREF color) -{ - rgb = color; - _ToLab(); -} - // Method Description: // - Populates our L, A, B values, based on our r, g, b values // - Converts a color in rgb format to a color in lab format @@ -224,12 +223,13 @@ void ColorFix::_ToRGB() } // Method Description: -// - Given a background color, change the foreground color to make it more perceivable if necessary +// - Given foreground and background colors, change the foreground color to +// make it more perceivable if necessary // - Arguments: -// - back: the color to compare against -// - pColor: where to store the resulting color +// - fg: the foreground color +// - bg: the background color // - Return Value: -// - True if we changed our color, false otherwise +// - The foreground color after performing any necessary changes to make it more perceivable COLORREF ColorFix::GetPerceivableColor(COLORREF fg, COLORREF bg) { ColorFix backLab(bg); diff --git a/src/cascadia/TerminalCore/ColorFix.hpp b/src/cascadia/TerminalCore/ColorFix.hpp index f270bc9f430..66e8caf4295 100644 --- a/src/cascadia/TerminalCore/ColorFix.hpp +++ b/src/cascadia/TerminalCore/ColorFix.hpp @@ -9,7 +9,6 @@ struct ColorFix { public: - ColorFix(); ColorFix(COLORREF color); static double GetDeltaE(ColorFix x1, ColorFix x2); @@ -32,6 +31,7 @@ struct ColorFix }; private: + static double _GetHPrimeFn(double x, double y); void _ToLab(); void _ToRGB(); BYTE _Clamp(double v); From 48f619992c93843b5e711420186d9e4d5e44cdf8 Mon Sep 17 00:00:00 2001 From: Pankaj Bhojwani Date: Thu, 9 Sep 2021 09:51:56 -0700 Subject: [PATCH 14/25] precalculate --- src/cascadia/TerminalCore/ColorFix.cpp | 5 +++++ src/cascadia/TerminalCore/Terminal.cpp | 14 ++++++++++++++ src/cascadia/TerminalCore/Terminal.hpp | 3 +++ src/cascadia/TerminalCore/terminalrenderdata.cpp | 16 +++++----------- 4 files changed, 27 insertions(+), 11 deletions(-) diff --git a/src/cascadia/TerminalCore/ColorFix.cpp b/src/cascadia/TerminalCore/ColorFix.cpp index 01470ab018b..c98fb5dc921 100644 --- a/src/cascadia/TerminalCore/ColorFix.cpp +++ b/src/cascadia/TerminalCore/ColorFix.cpp @@ -232,6 +232,11 @@ void ColorFix::_ToRGB() // - The foreground color after performing any necessary changes to make it more perceivable COLORREF ColorFix::GetPerceivableColor(COLORREF fg, COLORREF bg) { + // If the colors are the same, don't do any adjusting + if (fg == bg) + { + return fg; + } ColorFix backLab(bg); ColorFix frontLab(fg); double de1 = GetDeltaE(frontLab, backLab); diff --git a/src/cascadia/TerminalCore/Terminal.cpp b/src/cascadia/TerminalCore/Terminal.cpp index 0291f254abb..d97403879c0 100644 --- a/src/cascadia/TerminalCore/Terminal.cpp +++ b/src/cascadia/TerminalCore/Terminal.cpp @@ -9,6 +9,7 @@ #include "../../inc/argb.h" #include "../../types/inc/utils.hpp" #include "../../types/inc/colorTable.hpp" +#include "ColorFix.hpp" #include @@ -182,6 +183,7 @@ void Terminal::UpdateAppearance(const ICoreAppearance& appearance) { _colorTable.at(i) = til::color{ appearance.GetColorTableEntry(i) }; } + _MakeAdjustedColorMap(); CursorType cursorShape = CursorType::VerticalBar; switch (appearance.CursorShape()) @@ -1276,3 +1278,15 @@ const size_t Microsoft::Terminal::Core::Terminal::GetTaskbarProgress() const noe { return _taskbarProgress; } + +void Terminal::_MakeAdjustedColorMap() +{ + // for each pair of , map it to the adjusted fg + for (const auto fg : _colorTable) + { + for (const auto bg : _colorTable) + { + _adjustedColorMap[std::pair(fg, bg)] = ColorFix::GetPerceivableColor(fg, bg); + } + } +} diff --git a/src/cascadia/TerminalCore/Terminal.hpp b/src/cascadia/TerminalCore/Terminal.hpp index c2ff2e131fc..79e2ee1ae63 100644 --- a/src/cascadia/TerminalCore/Terminal.hpp +++ b/src/cascadia/TerminalCore/Terminal.hpp @@ -370,6 +370,9 @@ class Microsoft::Terminal::Core::Terminal final : void _NotifyTerminalCursorPositionChanged() noexcept; + std::map, COLORREF> _adjustedColorMap; + void _MakeAdjustedColorMap(); + #pragma region TextSelection // These methods are defined in TerminalSelection.cpp std::vector _GetSelectionRects() const noexcept; diff --git a/src/cascadia/TerminalCore/terminalrenderdata.cpp b/src/cascadia/TerminalCore/terminalrenderdata.cpp index 5b17772fbfe..d5aeb1ed91b 100644 --- a/src/cascadia/TerminalCore/terminalrenderdata.cpp +++ b/src/cascadia/TerminalCore/terminalrenderdata.cpp @@ -4,7 +4,6 @@ #include "pch.h" #include "Terminal.hpp" #include -#include "ColorFix.hpp" using namespace Microsoft::Terminal::Core; using namespace Microsoft::Console::Types; @@ -54,6 +53,10 @@ std::pair Terminal::GetAttributeColors(const TextAttribute& _screenReversed, _blinkingState.IsBlinkingFaint(), _intenseIsBright); + if (_perceptualColorNudging && _adjustedColorMap.find(colors) != _adjustedColorMap.end()) + { + colors.first = _adjustedColorMap.at(colors); + } colors.first |= 0xff000000; // We only care about alpha for the default BG (which enables acrylic) // If the bg isn't the default bg color, or reverse video is enabled, make it fully opaque. @@ -61,16 +64,7 @@ std::pair Terminal::GetAttributeColors(const TextAttribute& { colors.second |= 0xff000000; } - std::pair result; - if (_perceptualColorNudging) - { - result = std::pair(ColorFix::GetPerceivableColor(colors.first, colors.second), colors.second); - } - else - { - result = colors; - } - return result; + return colors; } COORD Terminal::GetCursorPosition() const noexcept From fe40978f86dbc2b0e20152d76a2509f25fae9af9 Mon Sep 17 00:00:00 2001 From: Pankaj Bhojwani Date: Fri, 10 Sep 2021 09:59:15 -0700 Subject: [PATCH 15/25] array --- src/buffer/out/TextAttribute.cpp | 25 +++++++++++++++--- src/buffer/out/TextAttribute.hpp | 3 ++- src/cascadia/TerminalCore/Terminal.cpp | 23 +++++++++++----- src/cascadia/TerminalCore/Terminal.hpp | 4 +-- .../TerminalCore/terminalrenderdata.cpp | 26 +++++++++++-------- 5 files changed, 58 insertions(+), 23 deletions(-) diff --git a/src/buffer/out/TextAttribute.cpp b/src/buffer/out/TextAttribute.cpp index c4472484603..854f2407ab0 100644 --- a/src/buffer/out/TextAttribute.cpp +++ b/src/buffer/out/TextAttribute.cpp @@ -104,15 +104,34 @@ std::pair TextAttribute::CalculateRgbColors(const std::array const COLORREF defaultBgColor, const bool reverseScreenMode, const bool blinkingIsFaint, - const bool boldIsBright) const noexcept + const bool boldIsBright, + const std::optional, 18>>& adjustedForegroundColors) const noexcept { - auto fg = _foreground.GetColor(colorTable, defaultFgColor, boldIsBright && IsBold()); + COLORREF fg; auto bg = _background.GetColor(colorTable, defaultBgColor); + bool reversed{ false }; + if (adjustedForegroundColors.has_value() && + (_background.IsDefault() || _background.IsLegacy()) && + (_foreground.IsDefault() || _foreground.IsLegacy())) + { + auto bgIndex = _background.IsDefault() ? 16 : _background.GetIndex(); + auto fgIndex = _foreground.IsDefault() ? 17 : _foreground.GetIndex(); + fg = adjustedForegroundColors.value()[bgIndex][fgIndex]; + if (IsReverseVideo() ^ reverseScreenMode) + { + std::swap(fg, bg); + reversed = true; + } + } + else + { + fg = _foreground.GetColor(colorTable, defaultFgColor, boldIsBright && IsBold()); + } if (IsFaint() || (IsBlinking() && blinkingIsFaint)) { fg = (fg >> 1) & 0x7F7F7F; // Divide foreground color components by two. } - if (IsReverseVideo() ^ reverseScreenMode) + if (IsReverseVideo() ^ reverseScreenMode && !reversed) { std::swap(fg, bg); } diff --git a/src/buffer/out/TextAttribute.hpp b/src/buffer/out/TextAttribute.hpp index 00f8a22665f..12093fbaeb0 100644 --- a/src/buffer/out/TextAttribute.hpp +++ b/src/buffer/out/TextAttribute.hpp @@ -69,7 +69,8 @@ class TextAttribute final const COLORREF defaultBgColor, const bool reverseScreenMode = false, const bool blinkingIsFaint = false, - const bool boldIsBright = true) const noexcept; + const bool boldIsBright = true, + const std::optional, 18>>& adjustedForegroundColors = std::nullopt) const noexcept; bool IsLeadingByte() const noexcept; bool IsTrailingByte() const noexcept; diff --git a/src/cascadia/TerminalCore/Terminal.cpp b/src/cascadia/TerminalCore/Terminal.cpp index d97403879c0..f3c4e5e9f53 100644 --- a/src/cascadia/TerminalCore/Terminal.cpp +++ b/src/cascadia/TerminalCore/Terminal.cpp @@ -183,7 +183,10 @@ void Terminal::UpdateAppearance(const ICoreAppearance& appearance) { _colorTable.at(i) = til::color{ appearance.GetColorTableEntry(i) }; } - _MakeAdjustedColorMap(); + if (_perceptualColorNudging) + { + _MakeAdjustedColorArray(); + } CursorType cursorShape = CursorType::VerticalBar; switch (appearance.CursorShape()) @@ -1279,14 +1282,22 @@ const size_t Microsoft::Terminal::Core::Terminal::GetTaskbarProgress() const noe return _taskbarProgress; } -void Terminal::_MakeAdjustedColorMap() +void Terminal::_MakeAdjustedColorArray() { - // for each pair of , map it to the adjusted fg - for (const auto fg : _colorTable) + std::array colorTableWithDefaults; + for (auto index = 0; index < 16; ++index) + { + colorTableWithDefaults[index] = _colorTable.at(index); + } + colorTableWithDefaults[16] = _defaultBg; + colorTableWithDefaults[17] = _defaultFg; + for (auto fgIndex = 0; fgIndex < 18; ++fgIndex) { - for (const auto bg : _colorTable) + auto fg = colorTableWithDefaults.at(fgIndex); + for (auto bgIndex = 0; bgIndex < 18; ++bgIndex) { - _adjustedColorMap[std::pair(fg, bg)] = ColorFix::GetPerceivableColor(fg, bg); + auto bg = colorTableWithDefaults.at(bgIndex); + _adjustedForegroundColors[bgIndex][fgIndex] = ColorFix::GetPerceivableColor(fg, bg); } } } diff --git a/src/cascadia/TerminalCore/Terminal.hpp b/src/cascadia/TerminalCore/Terminal.hpp index 79e2ee1ae63..96608d27013 100644 --- a/src/cascadia/TerminalCore/Terminal.hpp +++ b/src/cascadia/TerminalCore/Terminal.hpp @@ -370,8 +370,8 @@ class Microsoft::Terminal::Core::Terminal final : void _NotifyTerminalCursorPositionChanged() noexcept; - std::map, COLORREF> _adjustedColorMap; - void _MakeAdjustedColorMap(); + std::array, 18> _adjustedForegroundColors; + void _MakeAdjustedColorArray(); #pragma region TextSelection // These methods are defined in TerminalSelection.cpp diff --git a/src/cascadia/TerminalCore/terminalrenderdata.cpp b/src/cascadia/TerminalCore/terminalrenderdata.cpp index d5aeb1ed91b..6b37e768d8a 100644 --- a/src/cascadia/TerminalCore/terminalrenderdata.cpp +++ b/src/cascadia/TerminalCore/terminalrenderdata.cpp @@ -46,17 +46,21 @@ const TextAttribute Terminal::GetDefaultBrushColors() noexcept std::pair Terminal::GetAttributeColors(const TextAttribute& attr) const noexcept { _blinkingState.RecordBlinkingUsage(attr); - auto colors = attr.CalculateRgbColors( - _colorTable, - _defaultFg, - _defaultBg, - _screenReversed, - _blinkingState.IsBlinkingFaint(), - _intenseIsBright); - if (_perceptualColorNudging && _adjustedColorMap.find(colors) != _adjustedColorMap.end()) - { - colors.first = _adjustedColorMap.at(colors); - } + auto colors = _perceptualColorNudging ? attr.CalculateRgbColors( + _colorTable, + _defaultFg, + _defaultBg, + _screenReversed, + _blinkingState.IsBlinkingFaint(), + _intenseIsBright, + _adjustedForegroundColors) : + attr.CalculateRgbColors( + _colorTable, + _defaultFg, + _defaultBg, + _screenReversed, + _blinkingState.IsBlinkingFaint(), + _intenseIsBright); colors.first |= 0xff000000; // We only care about alpha for the default BG (which enables acrylic) // If the bg isn't the default bg color, or reverse video is enabled, make it fully opaque. From 7551212f26d99b9a4d6e227be921a188c962766c Mon Sep 17 00:00:00 2001 From: Pankaj Bhojwani Date: Fri, 10 Sep 2021 10:04:44 -0700 Subject: [PATCH 16/25] format --- .../TerminalCore/terminalrenderdata.cpp | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/cascadia/TerminalCore/terminalrenderdata.cpp b/src/cascadia/TerminalCore/terminalrenderdata.cpp index 6b37e768d8a..e771b428ed0 100644 --- a/src/cascadia/TerminalCore/terminalrenderdata.cpp +++ b/src/cascadia/TerminalCore/terminalrenderdata.cpp @@ -47,20 +47,20 @@ std::pair Terminal::GetAttributeColors(const TextAttribute& { _blinkingState.RecordBlinkingUsage(attr); auto colors = _perceptualColorNudging ? attr.CalculateRgbColors( - _colorTable, - _defaultFg, - _defaultBg, - _screenReversed, - _blinkingState.IsBlinkingFaint(), - _intenseIsBright, - _adjustedForegroundColors) : + _colorTable, + _defaultFg, + _defaultBg, + _screenReversed, + _blinkingState.IsBlinkingFaint(), + _intenseIsBright, + _adjustedForegroundColors) : attr.CalculateRgbColors( - _colorTable, - _defaultFg, - _defaultBg, - _screenReversed, - _blinkingState.IsBlinkingFaint(), - _intenseIsBright); + _colorTable, + _defaultFg, + _defaultBg, + _screenReversed, + _blinkingState.IsBlinkingFaint(), + _intenseIsBright); colors.first |= 0xff000000; // We only care about alpha for the default BG (which enables acrylic) // If the bg isn't the default bg color, or reverse video is enabled, make it fully opaque. From fdd80177ba5c08e93ff819f5b65ef88507e3765b Mon Sep 17 00:00:00 2001 From: Pankaj Bhojwani Date: Fri, 10 Sep 2021 10:15:44 -0700 Subject: [PATCH 17/25] fix swap --- src/buffer/out/TextAttribute.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/buffer/out/TextAttribute.cpp b/src/buffer/out/TextAttribute.cpp index 854f2407ab0..a49a3f416f4 100644 --- a/src/buffer/out/TextAttribute.cpp +++ b/src/buffer/out/TextAttribute.cpp @@ -116,12 +116,16 @@ std::pair TextAttribute::CalculateRgbColors(const std::array { auto bgIndex = _background.IsDefault() ? 16 : _background.GetIndex(); auto fgIndex = _foreground.IsDefault() ? 17 : _foreground.GetIndex(); - fg = adjustedForegroundColors.value()[bgIndex][fgIndex]; if (IsReverseVideo() ^ reverseScreenMode) { - std::swap(fg, bg); + bg = _foreground.GetColor(colorTable, defaultFgColor); + fg = adjustedForegroundColors.value()[fgIndex][bgIndex]; reversed = true; } + else + { + fg = adjustedForegroundColors.value()[bgIndex][fgIndex]; + } } else { From 23445c7407895922474aaedf83c6b34e313e6d5d Mon Sep 17 00:00:00 2001 From: Pankaj Bhojwani Date: Mon, 13 Sep 2021 11:20:35 -0700 Subject: [PATCH 18/25] move out of text attribute --- src/buffer/out/TextAttribute.cpp | 29 +--------- src/buffer/out/TextAttribute.hpp | 3 +- .../TerminalCore/terminalrenderdata.cpp | 55 ++++++++++++++----- 3 files changed, 44 insertions(+), 43 deletions(-) diff --git a/src/buffer/out/TextAttribute.cpp b/src/buffer/out/TextAttribute.cpp index a49a3f416f4..c4472484603 100644 --- a/src/buffer/out/TextAttribute.cpp +++ b/src/buffer/out/TextAttribute.cpp @@ -104,38 +104,15 @@ std::pair TextAttribute::CalculateRgbColors(const std::array const COLORREF defaultBgColor, const bool reverseScreenMode, const bool blinkingIsFaint, - const bool boldIsBright, - const std::optional, 18>>& adjustedForegroundColors) const noexcept + const bool boldIsBright) const noexcept { - COLORREF fg; + auto fg = _foreground.GetColor(colorTable, defaultFgColor, boldIsBright && IsBold()); auto bg = _background.GetColor(colorTable, defaultBgColor); - bool reversed{ false }; - if (adjustedForegroundColors.has_value() && - (_background.IsDefault() || _background.IsLegacy()) && - (_foreground.IsDefault() || _foreground.IsLegacy())) - { - auto bgIndex = _background.IsDefault() ? 16 : _background.GetIndex(); - auto fgIndex = _foreground.IsDefault() ? 17 : _foreground.GetIndex(); - if (IsReverseVideo() ^ reverseScreenMode) - { - bg = _foreground.GetColor(colorTable, defaultFgColor); - fg = adjustedForegroundColors.value()[fgIndex][bgIndex]; - reversed = true; - } - else - { - fg = adjustedForegroundColors.value()[bgIndex][fgIndex]; - } - } - else - { - fg = _foreground.GetColor(colorTable, defaultFgColor, boldIsBright && IsBold()); - } if (IsFaint() || (IsBlinking() && blinkingIsFaint)) { fg = (fg >> 1) & 0x7F7F7F; // Divide foreground color components by two. } - if (IsReverseVideo() ^ reverseScreenMode && !reversed) + if (IsReverseVideo() ^ reverseScreenMode) { std::swap(fg, bg); } diff --git a/src/buffer/out/TextAttribute.hpp b/src/buffer/out/TextAttribute.hpp index 12093fbaeb0..00f8a22665f 100644 --- a/src/buffer/out/TextAttribute.hpp +++ b/src/buffer/out/TextAttribute.hpp @@ -69,8 +69,7 @@ class TextAttribute final const COLORREF defaultBgColor, const bool reverseScreenMode = false, const bool blinkingIsFaint = false, - const bool boldIsBright = true, - const std::optional, 18>>& adjustedForegroundColors = std::nullopt) const noexcept; + const bool boldIsBright = true) const noexcept; bool IsLeadingByte() const noexcept; bool IsTrailingByte() const noexcept; diff --git a/src/cascadia/TerminalCore/terminalrenderdata.cpp b/src/cascadia/TerminalCore/terminalrenderdata.cpp index e771b428ed0..42cfdc54cc1 100644 --- a/src/cascadia/TerminalCore/terminalrenderdata.cpp +++ b/src/cascadia/TerminalCore/terminalrenderdata.cpp @@ -45,22 +45,47 @@ const TextAttribute Terminal::GetDefaultBrushColors() noexcept std::pair Terminal::GetAttributeColors(const TextAttribute& attr) const noexcept { + std::pair colors; _blinkingState.RecordBlinkingUsage(attr); - auto colors = _perceptualColorNudging ? attr.CalculateRgbColors( - _colorTable, - _defaultFg, - _defaultBg, - _screenReversed, - _blinkingState.IsBlinkingFaint(), - _intenseIsBright, - _adjustedForegroundColors) : - attr.CalculateRgbColors( - _colorTable, - _defaultFg, - _defaultBg, - _screenReversed, - _blinkingState.IsBlinkingFaint(), - _intenseIsBright); + const auto fgTextColor = attr.GetForeground(); + const auto bgTextColor = attr.GetBackground(); + + // We want to nudge the foreground color to make it more perceivable only for the + // default color pairs within the color table + if (_perceptualColorNudging && + !(attr.IsFaint() || (attr.IsBlinking() && _blinkingState.IsBlinkingFaint())) && + (fgTextColor.IsDefault() || fgTextColor.IsLegacy()) && + (bgTextColor.IsDefault() || bgTextColor.IsLegacy())) + { + auto bgIndex = bgTextColor.IsDefault() ? 16 : bgTextColor.GetIndex(); + auto fgIndex = fgTextColor.IsDefault() ? 17 : fgTextColor.GetIndex(); + + if (fgTextColor.IsIndex16() && (fgIndex < 8) && attr.IsBold() && _intenseIsBright) + { + // There is a special case for bold here - we need to get the bright version of the foreground color + fgIndex += 8; + } + + if (attr.IsReverseVideo() ^ _screenReversed) + { + colors.first = _adjustedForegroundColors[fgIndex][bgIndex]; + colors.second = fgTextColor.GetColor(_colorTable, _defaultFg); + } + else + { + colors.first = _adjustedForegroundColors[bgIndex][fgIndex]; + colors.second = bgTextColor.GetColor(_colorTable, _defaultBg); + } + } + else + { + colors = attr.CalculateRgbColors(_colorTable, + _defaultFg, + _defaultBg, + _screenReversed, + _blinkingState.IsBlinkingFaint(), + _intenseIsBright); + } colors.first |= 0xff000000; // We only care about alpha for the default BG (which enables acrylic) // If the bg isn't the default bg color, or reverse video is enabled, make it fully opaque. From 8b21babbb7b353eb519ff31737b5e783c9d37a74 Mon Sep 17 00:00:00 2001 From: Pankaj Bhojwani Date: Mon, 13 Sep 2021 11:46:14 -0700 Subject: [PATCH 19/25] mtd description --- src/cascadia/TerminalCore/Terminal.cpp | 12 ++++++++++-- src/cascadia/TerminalCore/Terminal.hpp | 2 ++ src/cascadia/TerminalCore/terminalrenderdata.cpp | 4 ++-- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/cascadia/TerminalCore/Terminal.cpp b/src/cascadia/TerminalCore/Terminal.cpp index f3c4e5e9f53..8655298ff0b 100644 --- a/src/cascadia/TerminalCore/Terminal.cpp +++ b/src/cascadia/TerminalCore/Terminal.cpp @@ -1282,15 +1282,23 @@ const size_t Microsoft::Terminal::Core::Terminal::GetTaskbarProgress() const noe return _taskbarProgress; } +// Method Description: +// - Creates the adjusted color array, which contains the possible foreground colors, +// adjusted for perceivability +// - The adjusted color array is 2-d, and effectively maps a background and foreground +// color pair to the adjusted foreground for that color pair void Terminal::_MakeAdjustedColorArray() { + // The color table has 16 colors, but the adjusted color table needs to be 18 + // to include the default background and default foreground colors std::array colorTableWithDefaults; for (auto index = 0; index < 16; ++index) { colorTableWithDefaults[index] = _colorTable.at(index); } - colorTableWithDefaults[16] = _defaultBg; - colorTableWithDefaults[17] = _defaultFg; + + colorTableWithDefaults[DefaultBgIndex] = _defaultBg; + colorTableWithDefaults[DefaultFgIndex] = _defaultFg; for (auto fgIndex = 0; fgIndex < 18; ++fgIndex) { auto fg = colorTableWithDefaults.at(fgIndex); diff --git a/src/cascadia/TerminalCore/Terminal.hpp b/src/cascadia/TerminalCore/Terminal.hpp index 96608d27013..01d8a07d066 100644 --- a/src/cascadia/TerminalCore/Terminal.hpp +++ b/src/cascadia/TerminalCore/Terminal.hpp @@ -22,6 +22,8 @@ static constexpr std::wstring_view linkPattern{ LR"(\b(https?|ftp|file)://[-A-Za-z0-9+&@#/%?=~_|$!:,.;]*[A-Za-z0-9+&@#/%=~_|$])" }; static constexpr size_t TaskbarMinProgress{ 10 }; +static constexpr size_t DefaultBgIndex{ 16 }; +static constexpr size_t DefaultFgIndex{ 17 }; // You have to forward decl the ICoreSettings here, instead of including the header. // If you include the header, there will be compilation errors with other diff --git a/src/cascadia/TerminalCore/terminalrenderdata.cpp b/src/cascadia/TerminalCore/terminalrenderdata.cpp index 42cfdc54cc1..f9acaf4490b 100644 --- a/src/cascadia/TerminalCore/terminalrenderdata.cpp +++ b/src/cascadia/TerminalCore/terminalrenderdata.cpp @@ -57,8 +57,8 @@ std::pair Terminal::GetAttributeColors(const TextAttribute& (fgTextColor.IsDefault() || fgTextColor.IsLegacy()) && (bgTextColor.IsDefault() || bgTextColor.IsLegacy())) { - auto bgIndex = bgTextColor.IsDefault() ? 16 : bgTextColor.GetIndex(); - auto fgIndex = fgTextColor.IsDefault() ? 17 : fgTextColor.GetIndex(); + auto bgIndex = bgTextColor.IsDefault() ? DefaultBgIndex : bgTextColor.GetIndex(); + auto fgIndex = fgTextColor.IsDefault() ? DefaultFgIndex : fgTextColor.GetIndex(); if (fgTextColor.IsIndex16() && (fgIndex < 8) && attr.IsBold() && _intenseIsBright) { From 0a7d3a974413a2c9c929a9bd3ffd7537c542b187 Mon Sep 17 00:00:00 2001 From: Pankaj Bhojwani Date: Mon, 13 Sep 2021 14:23:06 -0700 Subject: [PATCH 20/25] conemu license --- NOTICE.md | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/NOTICE.md b/NOTICE.md index 44e0f66629c..8fc966f8aee 100644 --- a/NOTICE.md +++ b/NOTICE.md @@ -252,6 +252,43 @@ DEALINGS IN THE SOFTWARE. ``` +## ConEmu +**Source**: [https://github.com/Maximus5/ConEmu](https://github.com/Maximus5/ConEmu) + +### License + +``` +BSD 3-Clause License + +Copyright (c) 2009-2017, Maximus5 +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +``` + # Microsoft Open Source This product also incorporates source code from other Microsoft open source projects, all licensed under the MIT license. From 36917917519a993fcc8e3798d2013d86fd747483 Mon Sep 17 00:00:00 2001 From: Pankaj Bhojwani Date: Wed, 29 Sep 2021 14:46:21 -0700 Subject: [PATCH 21/25] pr comments --- src/cascadia/TerminalCore/ColorFix.cpp | 129 ++++++------------ src/cascadia/TerminalCore/ColorFix.hpp | 25 +++- src/cascadia/TerminalCore/Terminal.cpp | 11 +- .../TerminalCore/terminalrenderdata.cpp | 2 +- 4 files changed, 64 insertions(+), 103 deletions(-) diff --git a/src/cascadia/TerminalCore/ColorFix.cpp b/src/cascadia/TerminalCore/ColorFix.cpp index c98fb5dc921..6af76d919e5 100644 --- a/src/cascadia/TerminalCore/ColorFix.cpp +++ b/src/cascadia/TerminalCore/ColorFix.cpp @@ -1,21 +1,27 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +// A lot of code was taken from +// https://github.com/Maximus5/ConEmu/blob/master/src/ConEmu/ColorFix.cpp +// and then adjusted to fit our style guidelines + #include "pch.h" #include -#include #include "ColorFix.hpp" -const double gMinThreshold = 12.0; -const double gExpThreshold = 20.0; -const double gLStep = 5.0; +static constexpr double gMinThreshold = 12.0; +static constexpr double gExpThreshold = 20.0; +static constexpr double gLStep = 5.0; -constexpr double rad006 = 0.104719755119659774; -constexpr double rad025 = 0.436332312998582394; -constexpr double rad030 = 0.523598775598298873; -constexpr double rad060 = 1.047197551196597746; -constexpr double rad063 = 1.099557428756427633; -constexpr double rad180 = 3.141592653589793238; -constexpr double rad275 = 4.799655442984406336; -constexpr double rad360 = 6.283185307179586476; +static constexpr double rad006 = 0.104719755119659774; +static constexpr double rad025 = 0.436332312998582394; +static constexpr double rad030 = 0.523598775598298873; +static constexpr double rad060 = 1.047197551196597746; +static constexpr double rad063 = 1.099557428756427633; +static constexpr double rad180 = 3.141592653589793238; +static constexpr double rad275 = 4.799655442984406336; +static constexpr double rad360 = 6.283185307179586476; ColorFix::ColorFix(COLORREF color) { @@ -43,7 +49,7 @@ double ColorFix::_GetHPrimeFn(double x, double y) // - x2: the second color // Return Value: // - The DeltaE value between x1 and x2 -double ColorFix::GetDeltaE(ColorFix x1, ColorFix x2) +double ColorFix::_GetDeltaE(ColorFix x1, ColorFix x2) { constexpr double kSubL = 1; constexpr double kSubC = 1; @@ -125,44 +131,26 @@ void ColorFix::_ToLab() double var_G = g / 255.0; double var_B = b / 255.0; - if (var_R > 0.04045) - var_R = pow(((var_R + 0.055) / 1.055), 2.4); - else - var_R = var_R / 12.92; - if (var_G > 0.04045) - var_G = pow(((var_G + 0.055) / 1.055), 2.4); - else - var_G = var_G / 12.92; - if (var_B > 0.04045) - var_B = pow(((var_B + 0.055) / 1.055), 2.4); - else - var_B = var_B / 12.92; + var_R = var_R > 0.04045 ? pow(((var_R + 0.055) / 1.055), 2.4) : var_R / 12.92; + var_G = var_G > 0.04045 ? pow(((var_G + 0.055) / 1.055), 2.4) : var_G / 12.92; + var_B = var_B > 0.04045 ? pow(((var_B + 0.055) / 1.055), 2.4) : var_B / 12.92; var_R = var_R * 100.; var_G = var_G * 100.; var_B = var_B * 100.; //Observer. = 2 degrees, Illuminant = D65 - double X = var_R * 0.4124 + var_G * 0.3576 + var_B * 0.1805; - double Y = var_R * 0.2126 + var_G * 0.7152 + var_B * 0.0722; - double Z = var_R * 0.0193 + var_G * 0.1192 + var_B * 0.9505; + const double X = var_R * 0.4124 + var_G * 0.3576 + var_B * 0.1805; + const double Y = var_R * 0.2126 + var_G * 0.7152 + var_B * 0.0722; + const double Z = var_R * 0.0193 + var_G * 0.1192 + var_B * 0.9505; double var_X = X / 95.047; //ref_X = 95.047 (Observer= 2 degrees, Illuminant= D65) double var_Y = Y / 100.000; //ref_Y = 100.000 double var_Z = Z / 108.883; //ref_Z = 108.883 - if (var_X > 0.008856) - var_X = pow(var_X, (1. / 3.)); - else - var_X = (7.787 * var_X) + (16. / 116.); - if (var_Y > 0.008856) - var_Y = pow(var_Y, (1. / 3.)); - else - var_Y = (7.787 * var_Y) + (16. / 116.); - if (var_Z > 0.008856) - var_Z = pow(var_Z, (1. / 3.)); - else - var_Z = (7.787 * var_Z) + (16. / 116.); + var_X = var_X > 0.008856 ? pow(var_X, (1. / 3.)) : (7.787 * var_X) + (16. / 116.); + var_Y = var_Y > 0.008856 ? pow(var_Y, (1. / 3.)) : (7.787 * var_Y) + (16. / 116.); + var_Z = var_Z > 0.008856 ? pow(var_Z, (1. / 3.)) : (7.787 * var_Z) + (16. / 116.); L = (116. * var_Y) - 16.; A = 500. * (var_X - var_Y); @@ -179,18 +167,9 @@ void ColorFix::_ToRGB() double var_X = A / 500. + var_Y; double var_Z = var_Y - B / 200.; - if (pow(var_Y, 3) > 0.008856) - var_Y = pow(var_Y, 3); - else - var_Y = (var_Y - 16. / 116.) / 7.787; - if (pow(var_X, 3) > 0.008856) - var_X = pow(var_X, 3); - else - var_X = (var_X - 16. / 116.) / 7.787; - if (pow(var_Z, 3) > 0.008856) - var_Z = pow(var_Z, 3); - else - var_Z = (var_Z - 16. / 116.) / 7.787; + var_Y = (pow(var_Y, 3) > 0.008856) ? pow(var_Y, 3) : (var_Y - 16. / 116.) / 7.787; + var_X = (pow(var_X, 3) > 0.008856) ? pow(var_X, 3) : (var_X - 16. / 116.) / 7.787; + var_Z = (pow(var_Z, 3) > 0.008856) ? pow(var_Z, 3) : (var_Z - 16. / 116.) / 7.787; double X = 95.047 * var_X; //ref_X = 95.047 (Observer= 2 degrees, Illuminant= D65) double Y = 100.000 * var_Y; //ref_Y = 100.000 @@ -204,22 +183,13 @@ void ColorFix::_ToRGB() double var_G = var_X * -0.9689 + var_Y * 1.8758 + var_Z * 0.0415; double var_B = var_X * 0.0557 + var_Y * -0.2040 + var_Z * 1.0570; - if (var_R > 0.0031308) - var_R = 1.055 * pow(var_R, (1 / 2.4)) - 0.055; - else - var_R = 12.92 * var_R; - if (var_G > 0.0031308) - var_G = 1.055 * pow(var_G, (1 / 2.4)) - 0.055; - else - var_G = 12.92 * var_G; - if (var_B > 0.0031308) - var_B = 1.055 * pow(var_B, (1 / 2.4)) - 0.055; - else - var_B = 12.92 * var_B; - - r = _Clamp(var_R * 255.); - g = _Clamp(var_G * 255.); - b = _Clamp(var_B * 255.); + var_R = var_R > 0.0031308 ? 1.055 * pow(var_R, (1 / 2.4)) - 0.055 : var_R = 12.92 * var_R; + var_G = var_G > 0.0031308 ? 1.055 * pow(var_G, (1 / 2.4)) - 0.055 : var_G = 12.92 * var_G; + var_B = var_B > 0.0031308 ? 1.055 * pow(var_B, (1 / 2.4)) - 0.055 : var_B = 12.92 * var_B; + + r = (BYTE)std::clamp(var_R * 255., 0., 255.); + g = (BYTE)std::clamp(var_G * 255., 0., 255.); + b = (BYTE)std::clamp(var_B * 255., 0., 255.); } // Method Description: @@ -239,17 +209,17 @@ COLORREF ColorFix::GetPerceivableColor(COLORREF fg, COLORREF bg) } ColorFix backLab(bg); ColorFix frontLab(fg); - double de1 = GetDeltaE(frontLab, backLab); + const double de1 = _GetDeltaE(frontLab, backLab); if (de1 < gMinThreshold) { for (int i = 0; i <= 1; i++) { - double step = (i == 0) ? gLStep : -gLStep; + const double step = (i == 0) ? gLStep : -gLStep; frontLab.L += step; while (((i == 0) && (frontLab.L <= 100)) || ((i == 1) && (frontLab.L >= 0))) { - double de2 = GetDeltaE(frontLab, backLab); + const double de2 = _GetDeltaE(frontLab, backLab); if (de2 >= gExpThreshold) { frontLab._ToRGB(); @@ -261,20 +231,3 @@ COLORREF ColorFix::GetPerceivableColor(COLORREF fg, COLORREF bg) } return frontLab.rgb; } - -// Method Description: -// - Clamps the given value to be between 0-255 inclusive -// - Converts the result to BYTE -// Arguments: -// - v: the value to clamp -// Return Value: -// - The clamped value -BYTE ColorFix::_Clamp(double v) -{ - if (v <= 0) - return 0; - else if (v >= 255) - return 255; - else - return (BYTE)v; -} diff --git a/src/cascadia/TerminalCore/ColorFix.hpp b/src/cascadia/TerminalCore/ColorFix.hpp index 66e8caf4295..935c5a953f4 100644 --- a/src/cascadia/TerminalCore/ColorFix.hpp +++ b/src/cascadia/TerminalCore/ColorFix.hpp @@ -1,17 +1,28 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. +/*++ +Copyright (c) Microsoft Corporation +Licensed under the MIT license. -#pragma once +Module Name: +- ColorFix + +Abstract: +- Implementation of perceptual color nudging, which allows the Terminal + to slightly shift the foreground color to make it more perceivable on + the current background (for cases where the foreground is very close + to being inperceivable on the background). + +Author(s): +- Pankaj Bhojwani - Sep 2021 -// We probably want to include something else here, whatever gives us COLORREF and BYTE -#include "../../terminal/input/terminalInput.hpp" +--*/ + +#pragma once struct ColorFix { public: ColorFix(COLORREF color); - static double GetDeltaE(ColorFix x1, ColorFix x2); static COLORREF GetPerceivableColor(COLORREF fg, COLORREF bg); // RGB @@ -32,7 +43,7 @@ struct ColorFix private: static double _GetHPrimeFn(double x, double y); + static double _GetDeltaE(ColorFix x1, ColorFix x2); void _ToLab(); void _ToRGB(); - BYTE _Clamp(double v); }; diff --git a/src/cascadia/TerminalCore/Terminal.cpp b/src/cascadia/TerminalCore/Terminal.cpp index 8655298ff0b..911ec2236f1 100644 --- a/src/cascadia/TerminalCore/Terminal.cpp +++ b/src/cascadia/TerminalCore/Terminal.cpp @@ -1292,19 +1292,16 @@ void Terminal::_MakeAdjustedColorArray() // The color table has 16 colors, but the adjusted color table needs to be 18 // to include the default background and default foreground colors std::array colorTableWithDefaults; - for (auto index = 0; index < 16; ++index) - { - colorTableWithDefaults[index] = _colorTable.at(index); - } - + std::copy_n(std::begin(_colorTable), 16, std::begin(colorTableWithDefaults)); colorTableWithDefaults[DefaultBgIndex] = _defaultBg; colorTableWithDefaults[DefaultFgIndex] = _defaultFg; for (auto fgIndex = 0; fgIndex < 18; ++fgIndex) { - auto fg = colorTableWithDefaults.at(fgIndex); + //auto fg = colorTableWithDefaults.at(fgIndex); + const auto fg = til::at(colorTableWithDefaults, fgIndex); for (auto bgIndex = 0; bgIndex < 18; ++bgIndex) { - auto bg = colorTableWithDefaults.at(bgIndex); + const auto bg = til::at(colorTableWithDefaults, bgIndex); _adjustedForegroundColors[bgIndex][fgIndex] = ColorFix::GetPerceivableColor(fg, bg); } } diff --git a/src/cascadia/TerminalCore/terminalrenderdata.cpp b/src/cascadia/TerminalCore/terminalrenderdata.cpp index f2e7d8f25c9..c51a729e121 100644 --- a/src/cascadia/TerminalCore/terminalrenderdata.cpp +++ b/src/cascadia/TerminalCore/terminalrenderdata.cpp @@ -57,7 +57,7 @@ std::pair Terminal::GetAttributeColors(const TextAttribute& (fgTextColor.IsDefault() || fgTextColor.IsLegacy()) && (bgTextColor.IsDefault() || bgTextColor.IsLegacy())) { - auto bgIndex = bgTextColor.IsDefault() ? DefaultBgIndex : bgTextColor.GetIndex(); + const auto bgIndex = bgTextColor.IsDefault() ? DefaultBgIndex : bgTextColor.GetIndex(); auto fgIndex = fgTextColor.IsDefault() ? DefaultFgIndex : fgTextColor.GetIndex(); if (fgTextColor.IsIndex16() && (fgIndex < 8) && attr.IsBold() && _intenseIsBright) From daf815f38e9a4abad527bd0913348ec34eb48c44 Mon Sep 17 00:00:00 2001 From: Pankaj Bhojwani Date: Wed, 29 Sep 2021 15:01:43 -0700 Subject: [PATCH 22/25] spell --- src/cascadia/TerminalCore/ColorFix.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cascadia/TerminalCore/ColorFix.hpp b/src/cascadia/TerminalCore/ColorFix.hpp index 935c5a953f4..aa32ecebd6b 100644 --- a/src/cascadia/TerminalCore/ColorFix.hpp +++ b/src/cascadia/TerminalCore/ColorFix.hpp @@ -9,7 +9,7 @@ Module Name: - Implementation of perceptual color nudging, which allows the Terminal to slightly shift the foreground color to make it more perceivable on the current background (for cases where the foreground is very close - to being inperceivable on the background). + to being imperceivable on the background). Author(s): - Pankaj Bhojwani - Sep 2021 From a95fb4247d61da66695f846bc6a1c99fa8098036 Mon Sep 17 00:00:00 2001 From: Pankaj Bhojwani Date: Tue, 5 Oct 2021 15:30:29 -0700 Subject: [PATCH 23/25] rename setting, only ignore same index --- doc/cascadia/profiles.schema.json | 8 ++++---- src/cascadia/TerminalCore/ColorFix.cpp | 5 ----- src/cascadia/TerminalCore/ICoreAppearance.idl | 2 +- src/cascadia/TerminalCore/Terminal.cpp | 18 ++++++++++++------ src/cascadia/TerminalCore/Terminal.hpp | 2 +- .../TerminalCore/terminalrenderdata.cpp | 2 +- .../TerminalSettingsEditor/Appearances.h | 4 ++-- .../TerminalSettingsEditor/Appearances.idl | 2 +- .../TerminalSettingsEditor/Appearances.xaml | 12 ++++++------ .../Resources/en-US/Resources.resw | 12 ++++++------ .../TerminalSettingsModel/AppearanceConfig.cpp | 8 ++++---- .../TerminalSettingsModel/AppearanceConfig.h | 2 +- .../TerminalSettingsModel/CascadiaSettings.cpp | 2 +- .../IAppearanceConfig.idl | 2 +- .../TerminalSettingsModel/TerminalSettings.cpp | 2 +- .../TerminalSettingsModel/TerminalSettings.h | 2 +- .../UnitTests_Control/MockControlSettings.h | 2 +- .../UnitTests_TerminalCore/MockTermSettings.h | 2 +- 18 files changed, 45 insertions(+), 44 deletions(-) diff --git a/doc/cascadia/profiles.schema.json b/doc/cascadia/profiles.schema.json index e1c32037376..49dc9693e48 100644 --- a/doc/cascadia/profiles.schema.json +++ b/doc/cascadia/profiles.schema.json @@ -188,8 +188,8 @@ ], "type": "string" }, - "perceptualColorNudging": { - "description": "When set to true, we will (when necessary) 'nudge' the foreground color to make it more visible, based on the background color.", + "adjustIndistinguishableColors": { + "description": "When set to true, we will (when necessary) adjust the foreground color to make it more visible, based on the background color.", "type": "boolean" }, "experimental.retroTerminalEffect": { @@ -1976,8 +1976,8 @@ } ] }, - "perceptualColorNudging": { - "description": "When set to true, we will (when necessary) 'nudge' the foreground color to make it more visible, based on the background color.", + "adjustIndistinguishableColors": { + "description": "When set to true, we will (when necessary) adjust the foreground color to make it more visible, based on the background color.", "type": "boolean" }, "scrollbarState": { diff --git a/src/cascadia/TerminalCore/ColorFix.cpp b/src/cascadia/TerminalCore/ColorFix.cpp index 6af76d919e5..577cfe41871 100644 --- a/src/cascadia/TerminalCore/ColorFix.cpp +++ b/src/cascadia/TerminalCore/ColorFix.cpp @@ -202,11 +202,6 @@ void ColorFix::_ToRGB() // - The foreground color after performing any necessary changes to make it more perceivable COLORREF ColorFix::GetPerceivableColor(COLORREF fg, COLORREF bg) { - // If the colors are the same, don't do any adjusting - if (fg == bg) - { - return fg; - } ColorFix backLab(bg); ColorFix frontLab(fg); const double de1 = _GetDeltaE(frontLab, backLab); diff --git a/src/cascadia/TerminalCore/ICoreAppearance.idl b/src/cascadia/TerminalCore/ICoreAppearance.idl index 00a41c9e508..ddeb5b83825 100644 --- a/src/cascadia/TerminalCore/ICoreAppearance.idl +++ b/src/cascadia/TerminalCore/ICoreAppearance.idl @@ -67,6 +67,6 @@ namespace Microsoft.Terminal.Core CursorStyle CursorShape; UInt32 CursorHeight; Boolean IntenseIsBright; - Boolean PerceptualColorNudging; + Boolean AdjustIndistinguishableColors; }; } diff --git a/src/cascadia/TerminalCore/Terminal.cpp b/src/cascadia/TerminalCore/Terminal.cpp index 911ec2236f1..320650790d0 100644 --- a/src/cascadia/TerminalCore/Terminal.cpp +++ b/src/cascadia/TerminalCore/Terminal.cpp @@ -55,7 +55,7 @@ Terminal::Terminal() : _taskbarProgress{ 0 }, _trimBlockSelection{ false }, _intenseIsBright{ true }, - _perceptualColorNudging{ true } + _adjustIndistinguishableColors{ true } { auto dispatch = std::make_unique(*this); auto engine = std::make_unique(std::move(dispatch)); @@ -177,13 +177,13 @@ void Terminal::UpdateAppearance(const ICoreAppearance& appearance) _defaultBg = newBackgroundColor.with_alpha(0); _defaultFg = appearance.DefaultForeground(); _intenseIsBright = appearance.IntenseIsBright(); - _perceptualColorNudging = appearance.PerceptualColorNudging(); + _adjustIndistinguishableColors = appearance.AdjustIndistinguishableColors(); for (int i = 0; i < 16; i++) { _colorTable.at(i) = til::color{ appearance.GetColorTableEntry(i) }; } - if (_perceptualColorNudging) + if (_adjustIndistinguishableColors) { _MakeAdjustedColorArray(); } @@ -1297,12 +1297,18 @@ void Terminal::_MakeAdjustedColorArray() colorTableWithDefaults[DefaultFgIndex] = _defaultFg; for (auto fgIndex = 0; fgIndex < 18; ++fgIndex) { - //auto fg = colorTableWithDefaults.at(fgIndex); const auto fg = til::at(colorTableWithDefaults, fgIndex); for (auto bgIndex = 0; bgIndex < 18; ++bgIndex) { - const auto bg = til::at(colorTableWithDefaults, bgIndex); - _adjustedForegroundColors[bgIndex][fgIndex] = ColorFix::GetPerceivableColor(fg, bg); + if (fgIndex == bgIndex) + { + _adjustedForegroundColors[bgIndex][fgIndex] = fg; + } + else + { + const auto bg = til::at(colorTableWithDefaults, bgIndex); + _adjustedForegroundColors[bgIndex][fgIndex] = ColorFix::GetPerceivableColor(fg, bg); + } } } } diff --git a/src/cascadia/TerminalCore/Terminal.hpp b/src/cascadia/TerminalCore/Terminal.hpp index 0f0b29b87a2..15bb15db608 100644 --- a/src/cascadia/TerminalCore/Terminal.hpp +++ b/src/cascadia/TerminalCore/Terminal.hpp @@ -300,7 +300,7 @@ class Microsoft::Terminal::Core::Terminal final : bool _bracketedPasteMode; bool _trimBlockSelection; bool _intenseIsBright; - bool _perceptualColorNudging; + bool _adjustIndistinguishableColors; size_t _taskbarState; size_t _taskbarProgress; diff --git a/src/cascadia/TerminalCore/terminalrenderdata.cpp b/src/cascadia/TerminalCore/terminalrenderdata.cpp index c51a729e121..1ef9620b352 100644 --- a/src/cascadia/TerminalCore/terminalrenderdata.cpp +++ b/src/cascadia/TerminalCore/terminalrenderdata.cpp @@ -52,7 +52,7 @@ std::pair Terminal::GetAttributeColors(const TextAttribute& // We want to nudge the foreground color to make it more perceivable only for the // default color pairs within the color table - if (_perceptualColorNudging && + if (_adjustIndistinguishableColors && !(attr.IsFaint() || (attr.IsBlinking() && _blinkingState.IsBlinkingFaint())) && (fgTextColor.IsDefault() || fgTextColor.IsLegacy()) && (bgTextColor.IsDefault() || bgTextColor.IsLegacy())) diff --git a/src/cascadia/TerminalSettingsEditor/Appearances.h b/src/cascadia/TerminalSettingsEditor/Appearances.h index c1c3815f6ae..980d16d167a 100644 --- a/src/cascadia/TerminalSettingsEditor/Appearances.h +++ b/src/cascadia/TerminalSettingsEditor/Appearances.h @@ -1,4 +1,4 @@ -/*++ +/*++ Copyright (c) Microsoft Corporation Licensed under the MIT license. @@ -93,7 +93,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation OBSERVABLE_PROJECTED_SETTING(_appearance, BackgroundImageStretchMode); OBSERVABLE_PROJECTED_SETTING(_appearance, BackgroundImageAlignment); OBSERVABLE_PROJECTED_SETTING(_appearance, IntenseTextStyle); - OBSERVABLE_PROJECTED_SETTING(_appearance, PerceptualColorNudging); + OBSERVABLE_PROJECTED_SETTING(_appearance, AdjustIndistinguishableColors); private: Model::AppearanceConfig _appearance; diff --git a/src/cascadia/TerminalSettingsEditor/Appearances.idl b/src/cascadia/TerminalSettingsEditor/Appearances.idl index a803984d8c6..33e4567fda2 100644 --- a/src/cascadia/TerminalSettingsEditor/Appearances.idl +++ b/src/cascadia/TerminalSettingsEditor/Appearances.idl @@ -46,7 +46,7 @@ namespace Microsoft.Terminal.Settings.Editor OBSERVABLE_PROJECTED_APPEARANCE_SETTING(Windows.UI.Xaml.Media.Stretch, BackgroundImageStretchMode); OBSERVABLE_PROJECTED_APPEARANCE_SETTING(Microsoft.Terminal.Settings.Model.ConvergedAlignment, BackgroundImageAlignment); OBSERVABLE_PROJECTED_APPEARANCE_SETTING(Microsoft.Terminal.Settings.Model.IntenseStyle, IntenseTextStyle); - OBSERVABLE_PROJECTED_APPEARANCE_SETTING(Boolean, PerceptualColorNudging); + OBSERVABLE_PROJECTED_APPEARANCE_SETTING(Boolean, AdjustIndistinguishableColors); } [default_interface] runtimeclass Appearances : Windows.UI.Xaml.Controls.UserControl, Windows.UI.Xaml.Data.INotifyPropertyChanged diff --git a/src/cascadia/TerminalSettingsEditor/Appearances.xaml b/src/cascadia/TerminalSettingsEditor/Appearances.xaml index 7af0fbc2a47..978443ce64d 100644 --- a/src/cascadia/TerminalSettingsEditor/Appearances.xaml +++ b/src/cascadia/TerminalSettingsEditor/Appearances.xaml @@ -151,12 +151,12 @@ - - - + + + diff --git a/src/cascadia/TerminalSettingsEditor/Resources/en-US/Resources.resw b/src/cascadia/TerminalSettingsEditor/Resources/en-US/Resources.resw index 9b6b38b7a1b..317a37dd944 100644 --- a/src/cascadia/TerminalSettingsEditor/Resources/en-US/Resources.resw +++ b/src/cascadia/TerminalSettingsEditor/Resources/en-US/Resources.resw @@ -771,13 +771,13 @@ When enabled, enables retro terminal effects such as glowing text and scan lines. A description for what the "retro terminal effects" setting does. Presented near "Profile_RetroTerminalEffect". - - Perceptual color nudging - Header for a control to toggle if we should 'nudge' the foreground color to make it more visible when necessary, based on the background color. + + Automatically adjust lightness of indistinguishable text + Header for a control to toggle if we should adjust the foreground color's lightness to make it more visible when necessary, based on the background color. - - When enabled, enables perceptual color nudging, which will, only when necessary, 'nudge' the foreground color to make it more visible (based on the background color). - A description for what the "perceptual color nudging" setting does. Presented near "Profile_PerceptualColorNudging". + + When enabled, enables automatic adjustment of indistinguishable colors, which will, only when necessary, adjust the foreground color's lightness to make it more visible (based on the background color). + A description for what the "adjust indistinguishable colors" setting does. Presented near "Profile_AdjustIndistinguishableColors". Scrollbar visibility diff --git a/src/cascadia/TerminalSettingsModel/AppearanceConfig.cpp b/src/cascadia/TerminalSettingsModel/AppearanceConfig.cpp index aee5c0daa4f..dcc1677e6ca 100644 --- a/src/cascadia/TerminalSettingsModel/AppearanceConfig.cpp +++ b/src/cascadia/TerminalSettingsModel/AppearanceConfig.cpp @@ -26,7 +26,7 @@ static constexpr std::string_view BackgroundImageAlignmentKey{ "backgroundImageA static constexpr std::string_view RetroTerminalEffectKey{ "experimental.retroTerminalEffect" }; static constexpr std::string_view PixelShaderPathKey{ "experimental.pixelShaderPath" }; static constexpr std::string_view IntenseTextStyleKey{ "intenseTextStyle" }; -static constexpr std::string_view PerceptualColorNudgingKey{ "perceptualColorNudging" }; +static constexpr std::string_view AdjustIndistinguishableColorsKey{ "adjustIndistinguishableColors" }; static constexpr std::string_view LegacyAcrylicTransparencyKey{ "acrylicOpacity" }; static constexpr std::string_view OpacityKey{ "opacity" }; @@ -53,7 +53,7 @@ winrt::com_ptr AppearanceConfig::CopyAppearance(const Appearan appearance->_PixelShaderPath = source->_PixelShaderPath; appearance->_IntenseTextStyle = source->_IntenseTextStyle; appearance->_Opacity = source->_Opacity; - appearance->_PerceptualColorNudging = source->_PerceptualColorNudging; + appearance->_AdjustIndistinguishableColors = source->_AdjustIndistinguishableColors; return appearance; } @@ -75,7 +75,7 @@ Json::Value AppearanceConfig::ToJson() const JsonUtils::SetValueForKey(json, RetroTerminalEffectKey, _RetroTerminalEffect); JsonUtils::SetValueForKey(json, PixelShaderPathKey, _PixelShaderPath); JsonUtils::SetValueForKey(json, IntenseTextStyleKey, _IntenseTextStyle); - JsonUtils::SetValueForKey(json, PerceptualColorNudgingKey, _PerceptualColorNudging); + JsonUtils::SetValueForKey(json, AdjustIndistinguishableColorsKey, _AdjustIndistinguishableColors); JsonUtils::SetValueForKey(json, OpacityKey, _Opacity, JsonUtils::OptionalConverter{}); return json; @@ -108,7 +108,7 @@ void AppearanceConfig::LayerJson(const Json::Value& json) JsonUtils::GetValueForKey(json, RetroTerminalEffectKey, _RetroTerminalEffect); JsonUtils::GetValueForKey(json, PixelShaderPathKey, _PixelShaderPath); JsonUtils::GetValueForKey(json, IntenseTextStyleKey, _IntenseTextStyle); - JsonUtils::GetValueForKey(json, PerceptualColorNudgingKey, _PerceptualColorNudging); + JsonUtils::GetValueForKey(json, AdjustIndistinguishableColorsKey, _AdjustIndistinguishableColors); JsonUtils::GetValueForKey(json, LegacyAcrylicTransparencyKey, _Opacity); JsonUtils::GetValueForKey(json, OpacityKey, _Opacity, JsonUtils::OptionalConverter{}); } diff --git a/src/cascadia/TerminalSettingsModel/AppearanceConfig.h b/src/cascadia/TerminalSettingsModel/AppearanceConfig.h index 8f9b0230daa..6cf9a5f2d36 100644 --- a/src/cascadia/TerminalSettingsModel/AppearanceConfig.h +++ b/src/cascadia/TerminalSettingsModel/AppearanceConfig.h @@ -54,7 +54,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation INHERITABLE_SETTING(Model::IAppearanceConfig, Model::IntenseStyle, IntenseTextStyle, Model::IntenseStyle::Bright); INHERITABLE_SETTING(Model::IAppearanceConfig, double, Opacity, 1.0); - INHERITABLE_SETTING(Model::IAppearanceConfig, bool, PerceptualColorNudging, true); + INHERITABLE_SETTING(Model::IAppearanceConfig, bool, AdjustIndistinguishableColors, true); private: winrt::weak_ref _sourceProfile; diff --git a/src/cascadia/TerminalSettingsModel/CascadiaSettings.cpp b/src/cascadia/TerminalSettingsModel/CascadiaSettings.cpp index 833f236764d..d614c6e28a5 100644 --- a/src/cascadia/TerminalSettingsModel/CascadiaSettings.cpp +++ b/src/cascadia/TerminalSettingsModel/CascadiaSettings.cpp @@ -307,7 +307,7 @@ Model::Profile CascadiaSettings::DuplicateProfile(const Model::Profile& source) DUPLICATE_SETTING_MACRO_SUB(appearance, target, RetroTerminalEffect); DUPLICATE_SETTING_MACRO_SUB(appearance, target, CursorShape); DUPLICATE_SETTING_MACRO_SUB(appearance, target, CursorHeight); - DUPLICATE_SETTING_MACRO_SUB(appearance, target, PerceptualColorNudging); + DUPLICATE_SETTING_MACRO_SUB(appearance, target, AdjustIndistinguishableColors); DUPLICATE_SETTING_MACRO_SUB(appearance, target, Opacity); } diff --git a/src/cascadia/TerminalSettingsModel/IAppearanceConfig.idl b/src/cascadia/TerminalSettingsModel/IAppearanceConfig.idl index 787a5374a2a..01df05fedd2 100644 --- a/src/cascadia/TerminalSettingsModel/IAppearanceConfig.idl +++ b/src/cascadia/TerminalSettingsModel/IAppearanceConfig.idl @@ -51,7 +51,7 @@ namespace Microsoft.Terminal.Settings.Model INHERITABLE_APPEARANCE_SETTING(Boolean, RetroTerminalEffect); INHERITABLE_APPEARANCE_SETTING(String, PixelShaderPath); INHERITABLE_APPEARANCE_SETTING(IntenseStyle, IntenseTextStyle); - INHERITABLE_APPEARANCE_SETTING(Boolean, PerceptualColorNudging); + INHERITABLE_APPEARANCE_SETTING(Boolean, AdjustIndistinguishableColors); INHERITABLE_APPEARANCE_SETTING(Double, Opacity); }; } diff --git a/src/cascadia/TerminalSettingsModel/TerminalSettings.cpp b/src/cascadia/TerminalSettingsModel/TerminalSettings.cpp index fc90d4172cd..5e4d1eeea8a 100644 --- a/src/cascadia/TerminalSettingsModel/TerminalSettings.cpp +++ b/src/cascadia/TerminalSettingsModel/TerminalSettings.cpp @@ -202,7 +202,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation _IntenseIsBold = WI_IsFlagSet(appearance.IntenseTextStyle(), Microsoft::Terminal::Settings::Model::IntenseStyle::Bold); _IntenseIsBright = WI_IsFlagSet(appearance.IntenseTextStyle(), Microsoft::Terminal::Settings::Model::IntenseStyle::Bright); - _PerceptualColorNudging = appearance.PerceptualColorNudging(); + _AdjustIndistinguishableColors = appearance.AdjustIndistinguishableColors(); _Opacity = appearance.Opacity(); } diff --git a/src/cascadia/TerminalSettingsModel/TerminalSettings.h b/src/cascadia/TerminalSettingsModel/TerminalSettings.h index d3ef2f6f403..90b7b60fef7 100644 --- a/src/cascadia/TerminalSettingsModel/TerminalSettings.h +++ b/src/cascadia/TerminalSettingsModel/TerminalSettings.h @@ -114,7 +114,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation INHERITABLE_SETTING(Model::TerminalSettings, bool, IntenseIsBright); - INHERITABLE_SETTING(Model::TerminalSettings, bool, PerceptualColorNudging); + INHERITABLE_SETTING(Model::TerminalSettings, bool, AdjustIndistinguishableColors); // ------------------------ End of Core Settings ----------------------- diff --git a/src/cascadia/UnitTests_Control/MockControlSettings.h b/src/cascadia/UnitTests_Control/MockControlSettings.h index f1b72fccaeb..485f9b146b8 100644 --- a/src/cascadia/UnitTests_Control/MockControlSettings.h +++ b/src/cascadia/UnitTests_Control/MockControlSettings.h @@ -47,7 +47,7 @@ namespace ControlUnitTests WINRT_PROPERTY(bool, TrimBlockSelection, false); WINRT_PROPERTY(bool, DetectURLs, true); WINRT_PROPERTY(bool, IntenseIsBright, true); - WINRT_PROPERTY(bool, PerceptualColorNudging, true); + WINRT_PROPERTY(bool, AdjustIndistinguishableColors, true); // ------------------------ End of Core Settings ----------------------- WINRT_PROPERTY(winrt::hstring, ProfileName); diff --git a/src/cascadia/UnitTests_TerminalCore/MockTermSettings.h b/src/cascadia/UnitTests_TerminalCore/MockTermSettings.h index 043a57446e9..d3ce6a403de 100644 --- a/src/cascadia/UnitTests_TerminalCore/MockTermSettings.h +++ b/src/cascadia/UnitTests_TerminalCore/MockTermSettings.h @@ -74,7 +74,7 @@ namespace TerminalCoreUnitTests void DetectURLs(bool) {} WINRT_PROPERTY(bool, IntenseIsBright, true); - WINRT_PROPERTY(bool, PerceptualColorNudging, true); + WINRT_PROPERTY(bool, AdjustIndistinguishableColors, true); private: int32_t _historySize; From 7277f9dd7909c7c1fb45332d9366135d2f757b87 Mon Sep 17 00:00:00 2001 From: Pankaj Bhojwani Date: Thu, 7 Oct 2021 13:46:58 -0700 Subject: [PATCH 24/25] Constants only in cpp file --- src/cascadia/TerminalCore/Terminal.cpp | 32 ----------------- src/cascadia/TerminalCore/Terminal.hpp | 2 -- .../TerminalCore/terminalrenderdata.cpp | 35 +++++++++++++++++++ 3 files changed, 35 insertions(+), 34 deletions(-) diff --git a/src/cascadia/TerminalCore/Terminal.cpp b/src/cascadia/TerminalCore/Terminal.cpp index 320650790d0..bb6e26ba947 100644 --- a/src/cascadia/TerminalCore/Terminal.cpp +++ b/src/cascadia/TerminalCore/Terminal.cpp @@ -9,7 +9,6 @@ #include "../../inc/argb.h" #include "../../types/inc/utils.hpp" #include "../../types/inc/colorTable.hpp" -#include "ColorFix.hpp" #include @@ -1281,34 +1280,3 @@ const size_t Microsoft::Terminal::Core::Terminal::GetTaskbarProgress() const noe { return _taskbarProgress; } - -// Method Description: -// - Creates the adjusted color array, which contains the possible foreground colors, -// adjusted for perceivability -// - The adjusted color array is 2-d, and effectively maps a background and foreground -// color pair to the adjusted foreground for that color pair -void Terminal::_MakeAdjustedColorArray() -{ - // The color table has 16 colors, but the adjusted color table needs to be 18 - // to include the default background and default foreground colors - std::array colorTableWithDefaults; - std::copy_n(std::begin(_colorTable), 16, std::begin(colorTableWithDefaults)); - colorTableWithDefaults[DefaultBgIndex] = _defaultBg; - colorTableWithDefaults[DefaultFgIndex] = _defaultFg; - for (auto fgIndex = 0; fgIndex < 18; ++fgIndex) - { - const auto fg = til::at(colorTableWithDefaults, fgIndex); - for (auto bgIndex = 0; bgIndex < 18; ++bgIndex) - { - if (fgIndex == bgIndex) - { - _adjustedForegroundColors[bgIndex][fgIndex] = fg; - } - else - { - const auto bg = til::at(colorTableWithDefaults, bgIndex); - _adjustedForegroundColors[bgIndex][fgIndex] = ColorFix::GetPerceivableColor(fg, bg); - } - } - } -} diff --git a/src/cascadia/TerminalCore/Terminal.hpp b/src/cascadia/TerminalCore/Terminal.hpp index 15bb15db608..3fc69d8ad94 100644 --- a/src/cascadia/TerminalCore/Terminal.hpp +++ b/src/cascadia/TerminalCore/Terminal.hpp @@ -22,8 +22,6 @@ static constexpr std::wstring_view linkPattern{ LR"(\b(https?|ftp|file)://[-A-Za-z0-9+&@#/%?=~_|$!:,.;]*[A-Za-z0-9+&@#/%=~_|$])" }; static constexpr size_t TaskbarMinProgress{ 10 }; -static constexpr size_t DefaultBgIndex{ 16 }; -static constexpr size_t DefaultFgIndex{ 17 }; // You have to forward decl the ICoreSettings here, instead of including the header. // If you include the header, there will be compilation errors with other diff --git a/src/cascadia/TerminalCore/terminalrenderdata.cpp b/src/cascadia/TerminalCore/terminalrenderdata.cpp index 1ef9620b352..91e96c3bfe3 100644 --- a/src/cascadia/TerminalCore/terminalrenderdata.cpp +++ b/src/cascadia/TerminalCore/terminalrenderdata.cpp @@ -3,12 +3,16 @@ #include "pch.h" #include "Terminal.hpp" +#include "ColorFix.hpp" #include using namespace Microsoft::Terminal::Core; using namespace Microsoft::Console::Types; using namespace Microsoft::Console::Render; +static constexpr size_t DefaultBgIndex{ 16 }; +static constexpr size_t DefaultFgIndex{ 17 }; + Viewport Terminal::GetViewport() noexcept { return _GetVisibleViewport(); @@ -293,3 +297,34 @@ const bool Terminal::IsUiaDataInitialized() const noexcept // UiaData are not yet initialized. return !!_buffer; } + +// Method Description: +// - Creates the adjusted color array, which contains the possible foreground colors, +// adjusted for perceivability +// - The adjusted color array is 2-d, and effectively maps a background and foreground +// color pair to the adjusted foreground for that color pair +void Terminal::_MakeAdjustedColorArray() +{ + // The color table has 16 colors, but the adjusted color table needs to be 18 + // to include the default background and default foreground colors + std::array colorTableWithDefaults; + std::copy_n(std::begin(_colorTable), 16, std::begin(colorTableWithDefaults)); + colorTableWithDefaults[DefaultBgIndex] = _defaultBg; + colorTableWithDefaults[DefaultFgIndex] = _defaultFg; + for (auto fgIndex = 0; fgIndex < 18; ++fgIndex) + { + const auto fg = til::at(colorTableWithDefaults, fgIndex); + for (auto bgIndex = 0; bgIndex < 18; ++bgIndex) + { + if (fgIndex == bgIndex) + { + _adjustedForegroundColors[bgIndex][fgIndex] = fg; + } + else + { + const auto bg = til::at(colorTableWithDefaults, bgIndex); + _adjustedForegroundColors[bgIndex][fgIndex] = ColorFix::GetPerceivableColor(fg, bg); + } + } + } +} From acb2fb422a1252add15926dcd5ec416a67219b62 Mon Sep 17 00:00:00 2001 From: Pankaj Bhojwani Date: Thu, 7 Oct 2021 13:53:45 -0700 Subject: [PATCH 25/25] move member --- src/cascadia/TerminalCore/Terminal.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cascadia/TerminalCore/Terminal.hpp b/src/cascadia/TerminalCore/Terminal.hpp index 3fc69d8ad94..e5f407d642b 100644 --- a/src/cascadia/TerminalCore/Terminal.hpp +++ b/src/cascadia/TerminalCore/Terminal.hpp @@ -385,9 +385,6 @@ class Microsoft::Terminal::Core::Terminal final : void _NotifyTerminalCursorPositionChanged() noexcept; - std::array, 18> _adjustedForegroundColors; - void _MakeAdjustedColorArray(); - #pragma region TextSelection // These methods are defined in TerminalSelection.cpp std::vector _GetSelectionRects() const noexcept; @@ -402,6 +399,9 @@ class Microsoft::Terminal::Core::Terminal final : Microsoft::Console::VirtualTerminal::SgrStack _sgrStack; + void _MakeAdjustedColorArray(); + std::array, 18> _adjustedForegroundColors; + #ifdef UNIT_TESTING friend class TerminalCoreUnitTests::TerminalBufferTests; friend class TerminalCoreUnitTests::TerminalApiTest;