Compare commits

...

2 Commits

Author SHA1 Message Date
Leonard Hecker
995c074734 Revert some more changes 2026-02-18 22:39:39 +01:00
Leonard Hecker
a865c8dc15 Implement dynamic 8-bit color palettes 2026-02-18 22:37:34 +01:00
47 changed files with 314 additions and 124 deletions

View File

@@ -213,6 +213,8 @@ xlocnum
xloctime
XMax
xmemory
XMVECTOR
XMVECTORF
XParse
xpath
xstddef

View File

@@ -198,6 +198,7 @@ codepages
coinit
colorizing
COLORONCOLOR
colorref
COLORREFs
colorschemes
colorspec

View File

@@ -1022,6 +1022,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
.scheme = renderSettings.GetColorTable(),
.foregroundAlias = renderSettings.GetColorAliasIndex(ColorAlias::DefaultForeground),
.backgroundAlias = renderSettings.GetColorAliasIndex(ColorAlias::DefaultBackground),
.generatePalette = renderSettings.GetRenderMode(Render::RenderSettings::Mode::Generate256Colors),
};
}
_terminal->UpdateColorScheme(scheme);
@@ -1041,6 +1042,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
}
renderSettings.SetColorAliasIndex(ColorAlias::DefaultForeground, stashedScheme.foregroundAlias);
renderSettings.SetColorAliasIndex(ColorAlias::DefaultBackground, stashedScheme.backgroundAlias);
renderSettings.SetRenderMode(Render::RenderSettings::Mode::Generate256Colors, stashedScheme.generatePalette);
_renderer->TriggerRedrawAll(true);
}
_stashedColorScheme.reset();

View File

@@ -428,6 +428,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
std::array<COLORREF, TextColor::TABLE_SIZE> scheme;
size_t foregroundAlias;
size_t backgroundAlias;
bool generatePalette;
};
std::unique_ptr<StashedColorScheme> _stashedColorScheme;

View File

@@ -101,6 +101,7 @@ namespace Microsoft.Terminal.Core
Boolean IntenseIsBold { get; };
Boolean IntenseIsBright { get; };
AdjustTextMode AdjustIndistinguishableColors { get; };
Boolean GeneratePalette { get; };
// NOTE! When adding something here, make sure to update ControlProperties.h too!
};

View File

@@ -141,6 +141,7 @@ void Terminal::UpdateAppearance(const ICoreAppearance& appearance)
{
auto& renderSettings = GetRenderSettings();
renderSettings.SetRenderMode(RenderSettings::Mode::Generate256Colors, appearance.GeneratePalette());
renderSettings.SetRenderMode(RenderSettings::Mode::IntenseIsBold, appearance.IntenseIsBold());
renderSettings.SetRenderMode(RenderSettings::Mode::IntenseIsBright, appearance.IntenseIsBright());
@@ -1230,7 +1231,7 @@ void Terminal::_clearPatternTree()
// Method Description:
// - Returns the tab color
// If the starting color exists, its value is preferred
const std::optional<til::color> Terminal::GetTabColor() const
const std::optional<til::color> Terminal::GetTabColor()
{
if (_startingTabColor.has_value())
{
@@ -1493,14 +1494,14 @@ std::vector<MarkExtents> Terminal::GetMarkExtents() const
return _inAltBuffer() ? std::vector<MarkExtents>{} : _activeBuffer().GetMarkExtents();
}
til::color Terminal::GetColorForMark(const ScrollbarData& markData) const
til::color Terminal::GetColorForMark(const ScrollbarData& markData)
{
if (markData.color.has_value())
{
return *markData.color;
}
const auto& renderSettings = GetRenderSettings();
auto& renderSettings = GetRenderSettings();
switch (markData.category)
{

View File

@@ -166,7 +166,7 @@ public:
void ClearMark();
void ClearAllMarks();
til::color GetColorForMark(const ScrollbarData& markData) const;
til::color GetColorForMark(const ScrollbarData& markData);
#pragma region ITerminalInput
// These methods are defined in Terminal.cpp
@@ -206,7 +206,7 @@ public:
std::wstring GetHyperlinkCustomId(uint16_t id) const override;
std::vector<size_t> GetPatternId(const til::point location) const override;
std::pair<COLORREF, COLORREF> GetAttributeColors(const TextAttribute& attr) const noexcept override;
std::pair<COLORREF, COLORREF> GetAttributeColors(const TextAttribute& attr) noexcept override;
std::span<const til::point_span> GetSelectionSpans() const noexcept override;
std::span<const til::point_span> GetSearchHighlights() const noexcept override;
const til::point_span* GetSearchHighlightFocused() const noexcept override;
@@ -238,7 +238,7 @@ public:
void UpdatePatternsUnderLock();
const std::optional<til::color> GetTabColor() const;
const std::optional<til::color> GetTabColor();
const size_t GetTaskbarState() const noexcept;
const size_t GetTaskbarProgress() const noexcept;
@@ -311,7 +311,7 @@ public:
til::point SelectionEndForRendering() const;
SelectionEndpoint SelectionEndpointTarget() const noexcept;
TextCopyData RetrieveSelectedTextFromBuffer(const bool singleLine, const bool withControlSequences = false, const bool html = false, const bool rtf = false) const;
TextCopyData RetrieveSelectedTextFromBuffer(const bool singleLine, const bool withControlSequences = false, const bool html = false, const bool rtf = false);
#pragma endregion
#ifndef NDEBUG

View File

@@ -959,7 +959,7 @@ void Terminal::ClearSelection()
// Return Value:
// - Plain and formatted selected text from buffer. Empty string represents no data for that format.
// - If extended to multiple lines, each line is separated by \r\n
Terminal::TextCopyData Terminal::RetrieveSelectedTextFromBuffer(const bool singleLine, const bool withControlSequences, const bool html, const bool rtf) const
Terminal::TextCopyData Terminal::RetrieveSelectedTextFromBuffer(const bool singleLine, const bool withControlSequences, const bool html, const bool rtf)
{
TextCopyData data;

View File

@@ -99,7 +99,7 @@ std::vector<size_t> Terminal::GetPatternId(const til::point location) const
return {};
}
std::pair<COLORREF, COLORREF> Terminal::GetAttributeColors(const TextAttribute& attr) const noexcept
std::pair<COLORREF, COLORREF> Terminal::GetAttributeColors(const TextAttribute& attr) noexcept
{
return GetRenderSettings().GetAttributeColors(attr);
}

View File

@@ -230,21 +230,21 @@ namespace winrt::Microsoft::Terminal::Settings
break;
}
if (appearance.Foreground())
if (const auto v = appearance.Foreground())
{
_DefaultForeground = til::color{ appearance.Foreground().Value() };
_DefaultForeground = til::color{ v.Value() };
}
if (appearance.Background())
if (const auto v = appearance.Background())
{
_DefaultBackground = til::color{ appearance.Background().Value() };
_DefaultBackground = til::color{ v.Value() };
}
if (appearance.SelectionBackground())
if (const auto v = appearance.SelectionBackground())
{
_SelectionBackground = til::color{ appearance.SelectionBackground().Value() };
_SelectionBackground = til::color{ v.Value() };
}
if (appearance.CursorColor())
if (const auto v = appearance.CursorColor())
{
_CursorColor = til::color{ appearance.CursorColor().Value() };
_CursorColor = til::color{ v.Value() };
}
if (const auto backgroundImage{ appearance.BackgroundImagePath() })
@@ -272,6 +272,7 @@ namespace winrt::Microsoft::Terminal::Settings
_IntenseIsBright = WI_IsFlagSet(appearance.IntenseTextStyle(), Microsoft::Terminal::Settings::Model::IntenseStyle::Bright);
_AdjustIndistinguishableColors = appearance.AdjustIndistinguishableColors();
_GeneratePalette = appearance.GeneratePalette();
_Opacity = appearance.Opacity();
_UseAcrylic = appearance.UseAcrylic();
}

View File

@@ -160,6 +160,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
OBSERVABLE_PROJECTED_SETTING(_appearance, BackgroundImageAlignment);
OBSERVABLE_PROJECTED_SETTING(_appearance, IntenseTextStyle);
OBSERVABLE_PROJECTED_SETTING(_appearance, AdjustIndistinguishableColors);
OBSERVABLE_PROJECTED_SETTING(_appearance, GeneratePalette);
OBSERVABLE_PROJECTED_SETTING(_appearance, Foreground);
OBSERVABLE_PROJECTED_SETTING(_appearance, Background);
OBSERVABLE_PROJECTED_SETTING(_appearance, SelectionBackground);

View File

@@ -86,6 +86,7 @@ namespace Microsoft.Terminal.Settings.Editor
OBSERVABLE_PROJECTED_APPEARANCE_SETTING(Microsoft.Terminal.Settings.Model.ConvergedAlignment, BackgroundImageAlignment);
OBSERVABLE_PROJECTED_APPEARANCE_SETTING(Microsoft.Terminal.Settings.Model.IntenseStyle, IntenseTextStyle);
OBSERVABLE_PROJECTED_APPEARANCE_SETTING(Microsoft.Terminal.Core.AdjustTextMode, AdjustIndistinguishableColors);
OBSERVABLE_PROJECTED_APPEARANCE_SETTING(Boolean, GeneratePalette);
OBSERVABLE_PROJECTED_APPEARANCE_SETTING(Windows.Foundation.IReference<Microsoft.Terminal.Core.Color>, Foreground);
OBSERVABLE_PROJECTED_APPEARANCE_SETTING(Windows.Foundation.IReference<Microsoft.Terminal.Core.Color>, Background);

View File

@@ -471,6 +471,15 @@
SelectedItem="{x:Bind CurrentAdjustIndistinguishableColors, Mode=TwoWay}"
Style="{StaticResource ComboBoxSettingStyle}" />
</local:SettingContainer>
<!-- Generate palette -->
<local:SettingContainer x:Uid="Profile_GeneratePalette"
ClearSettingValue="{x:Bind Appearance.ClearGeneratePalette}"
HasSettingValue="{x:Bind Appearance.HasGeneratePalette, Mode=OneWay}"
SettingOverrideSource="{x:Bind Appearance.GeneratePaletteOverrideSource, Mode=OneWay}">
<ToggleSwitch IsOn="{x:Bind Appearance.GeneratePalette, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
</StackPanel>
<!-- Grouping: Cursor -->

View File

@@ -943,6 +943,14 @@
<value>Automatic</value>
<comment>An option to choose from for the "adjust indistinguishable colors" setting. When selected, we will adjust the text colors for visibility only when the colors are part of this profile's color scheme's color table if and only if high contrast mode is enabled.</comment>
</data>
<data name="Profile_GeneratePalette.Header" xml:space="preserve">
<value>Generate palette</value>
<comment>A switch toggle that enables the use of an alternative color palette</comment>
</data>
<data name="Profile_GeneratePalette.HelpText" xml:space="preserve">
<value>When enabled, the extended 256-color palette is generated by interpolating between the basic theme colors instead of using the standard fixed palette.</value>
<comment>A description for a switch toggle that enables use of an alternative color palette</comment>
</data>
<data name="Profile_CursorShapeBar.Content" xml:space="preserve">
<value>Bar ( ┃ )</value>
<comment>{Locked="┃"} An option to choose from for the "cursor shape" setting. When selected, the cursor will look like a vertical bar. The character in the parentheses is used to show what it looks like.</comment>

View File

@@ -54,6 +54,7 @@ namespace Microsoft.Terminal.Settings.Model
INHERITABLE_APPEARANCE_SETTING(IMediaResource, PixelShaderImagePath);
INHERITABLE_APPEARANCE_SETTING(IntenseStyle, IntenseTextStyle);
INHERITABLE_APPEARANCE_SETTING(Microsoft.Terminal.Core.AdjustTextMode, AdjustIndistinguishableColors);
INHERITABLE_APPEARANCE_SETTING(Boolean, GeneratePalette);
INHERITABLE_APPEARANCE_SETTING(Single, Opacity);
INHERITABLE_APPEARANCE_SETTING(Boolean, UseAcrylic);
};

View File

@@ -141,6 +141,7 @@ Author(s):
X(IMediaResource, BackgroundImagePath, "backgroundImage", implementation::MediaResource::Empty()) \
X(Model::IntenseStyle, IntenseTextStyle, "intenseTextStyle", Model::IntenseStyle::Bright) \
X(Core::AdjustTextMode, AdjustIndistinguishableColors, "adjustIndistinguishableColors", Core::AdjustTextMode::Automatic) \
X(bool, GeneratePalette, "generatePalette", true) \
X(bool, UseAcrylic, "useAcrylic", false)
// Intentionally omitted Appearance settings:

View File

@@ -72,8 +72,8 @@ namespace SettingsModelUnitTests
VERIFY_ARE_EQUAL(til::color(0xFF, 0xFF, 0xFF, 255), til::color{ scheme->CursorColor() });
std::array<COLORREF, COLOR_TABLE_SIZE> expectedCampbellTable;
const auto campbellSpan = std::span{ expectedCampbellTable };
Utils::InitializeColorTable(campbellSpan);
Utils::InitializeANSIColorTable(expectedCampbellTable);
Utils::InitializeExtendedColorTable(expectedCampbellTable);
for (size_t i = 0; i < expectedCampbellTable.size(); i++)
{

View File

@@ -12,6 +12,7 @@
X(winrt::Microsoft::Terminal::Core::CursorStyle, CursorShape, winrt::Microsoft::Terminal::Core::CursorStyle::Vintage) \
X(uint32_t, CursorHeight, DEFAULT_CURSOR_HEIGHT) \
X(til::color, SelectionBackground, DEFAULT_FOREGROUND) \
X(bool, GeneratePalette, true) \
X(bool, IntenseIsBold) \
X(bool, IntenseIsBright, true) \
X(winrt::Microsoft::Terminal::Core::AdjustTextMode, AdjustIndistinguishableColors, winrt::Microsoft::Terminal::Core::AdjustTextMode::Automatic)

View File

@@ -129,7 +129,7 @@ public:
const bool isVisible) noexcept override;
//// driver will pare down for non-Ex method
void GetConsoleScreenBufferInfoExImpl(const SCREEN_INFORMATION& context,
void GetConsoleScreenBufferInfoExImpl(SCREEN_INFORMATION& context,
CONSOLE_SCREEN_BUFFER_INFOEX& data) noexcept override;
[[nodiscard]] HRESULT SetConsoleScreenBufferInfoExImpl(SCREEN_INFORMATION& context,

View File

@@ -99,7 +99,7 @@ void ApiRoutines::GetConsoleOutputModeImpl(SCREEN_INFORMATION& context, ULONG& m
// Arguments:
// - context - The output buffer concerned
// - data - Receives structure filled with metadata about the output buffer
void ApiRoutines::GetConsoleScreenBufferInfoExImpl(const SCREEN_INFORMATION& context,
void ApiRoutines::GetConsoleScreenBufferInfoExImpl(SCREEN_INFORMATION& context,
CONSOLE_SCREEN_BUFFER_INFOEX& data) noexcept
{
try

View File

@@ -197,9 +197,9 @@ std::vector<size_t> RenderData::GetPatternId(const til::point /*location*/) cons
// relevant table translation information and preferences.
// Return Value:
// - ARGB color values for the foreground and background
std::pair<COLORREF, COLORREF> RenderData::GetAttributeColors(const TextAttribute& attr) const noexcept
std::pair<COLORREF, COLORREF> RenderData::GetAttributeColors(const TextAttribute& attr) noexcept
{
const auto& renderSettings = ServiceLocator::LocateGlobals().getConsoleInformation().GetRenderSettings();
auto& renderSettings = ServiceLocator::LocateGlobals().getConsoleInformation().GetRenderSettings();
return renderSettings.GetAttributeColors(attr);
}

View File

@@ -33,7 +33,7 @@ public:
std::wstring GetHyperlinkCustomId(uint16_t id) const override;
std::vector<size_t> GetPatternId(const til::point location) const override;
std::pair<COLORREF, COLORREF> GetAttributeColors(const TextAttribute& attr) const noexcept override;
std::pair<COLORREF, COLORREF> GetAttributeColors(const TextAttribute& attr) noexcept override;
bool IsSelectionActive() const override;
bool IsBlockSelection() const override;
void ClearSelection() override;

View File

@@ -321,9 +321,9 @@ void SCREEN_INFORMATION::GetScreenBufferInformation(_Out_ til::size* pcoordSize,
_Out_ PWORD pwAttributes,
_Out_ til::size* pcoordMaximumWindowSize,
_Out_ PWORD pwPopupAttributes,
_Out_writes_(COLOR_TABLE_SIZE) LPCOLORREF lpColorTable) const
_Out_writes_(COLOR_TABLE_SIZE) LPCOLORREF lpColorTable)
{
const auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
*pcoordSize = GetBufferSize().Dimensions();
*pcoordCursorPosition = _textBuffer->GetCursor().GetPosition();

View File

@@ -147,7 +147,7 @@ public:
bool PostUpdateWindowSize() const;
// General Information
void GetScreenBufferInformation(til::size* size, til::point* cursorPosition, til::inclusive_rect* window, PWORD attributes, til::size* maximumWindowSize, PWORD popupAttributes, LPCOLORREF colorTable) const;
void GetScreenBufferInformation(til::size* size, til::point* cursorPosition, til::inclusive_rect* window, PWORD attributes, til::size* maximumWindowSize, PWORD popupAttributes, LPCOLORREF colorTable);
void GetRequiredConsoleSizeInPixels(til::size* requiredSize) const;
til::size GetMinWindowSizeInCharacters(til::size fontSize = { 1, 1 }) const;
til::size GetMaxWindowSizeInCharacters(til::size fontSize = { 1, 1 }) const;

View File

@@ -111,9 +111,6 @@ void Settings::ApplyDesktopSpecificDefaults()
_uHistoryBufferSize = 50;
_uNumberOfHistoryBuffers = 4;
_bHistoryNoDup = FALSE;
_renderSettings.ResetColorTable();
_fTrimLeadingZeros = false;
_fEnableColorSelection = false;
_uScrollScale = 1;
@@ -233,7 +230,7 @@ void Settings::InitFromStateInfo(_In_ PCONSOLE_STATE_INFO pStateInfo)
// - <none>
// Return Value:
// - a CONSOLE_STATE_INFO with the current state of this settings structure.
CONSOLE_STATE_INFO Settings::CreateConsoleStateInfo() const
CONSOLE_STATE_INFO Settings::CreateConsoleStateInfo()
{
CONSOLE_STATE_INFO csi = { 0 };
csi.ScreenAttributes = _wFillAttribute;
@@ -709,7 +706,7 @@ void Settings::SetColorTableEntry(const size_t index, const COLORREF color)
_renderSettings.SetColorTableEntry(index, color);
}
COLORREF Settings::GetColorTableEntry(const size_t index) const
COLORREF Settings::GetColorTableEntry(const size_t index)
{
return _renderSettings.GetColorTableEntry(index);
}
@@ -719,7 +716,7 @@ void Settings::SetLegacyColorTableEntry(const size_t index, const COLORREF color
SetColorTableEntry(TextColor::TransposeLegacyIndex(index), color);
}
COLORREF Settings::GetLegacyColorTableEntry(const size_t index) const
COLORREF Settings::GetLegacyColorTableEntry(const size_t index)
{
return GetColorTableEntry(TextColor::TransposeLegacyIndex(index));
}

View File

@@ -45,10 +45,9 @@ public:
void InitFromStateInfo(_In_ PCONSOLE_STATE_INFO pStateInfo);
void Validate();
CONSOLE_STATE_INFO CreateConsoleStateInfo() const;
CONSOLE_STATE_INFO CreateConsoleStateInfo();
RenderSettings& GetRenderSettings() noexcept { return _renderSettings; };
const RenderSettings& GetRenderSettings() const noexcept { return _renderSettings; };
RenderSettings& GetRenderSettings() noexcept { return _renderSettings; }
DWORD GetDefaultVirtTermLevel() const;
void SetDefaultVirtTermLevel(const DWORD dwVirtTermLevel);
@@ -161,9 +160,9 @@ public:
void SetHistoryNoDup(const bool fHistoryNoDup);
void SetColorTableEntry(const size_t index, const COLORREF color);
COLORREF GetColorTableEntry(const size_t index) const;
COLORREF GetColorTableEntry(const size_t index);
void SetLegacyColorTableEntry(const size_t index, const COLORREF color);
COLORREF GetLegacyColorTableEntry(const size_t index) const;
COLORREF GetLegacyColorTableEntry(const size_t index);
CursorType GetCursorType() const noexcept;
void SetCursorType(const CursorType cursorType) noexcept;

View File

@@ -167,7 +167,7 @@ try
CATCH_RETURN()
[[nodiscard]] HRESULT BgfxEngine::UpdateDrawingBrushes(const TextAttribute& textAttributes,
const RenderSettings& /*renderSettings*/,
RenderSettings& /*renderSettings*/,
const gsl::not_null<IRenderData*> /*pData*/,
const bool /*usingSoftFont*/,
const bool /*isSettingDefaultBrushes*/) noexcept

View File

@@ -54,7 +54,7 @@ namespace Microsoft::Console::Render
[[nodiscard]] HRESULT PaintCursor(const CursorOptions& options) noexcept override;
[[nodiscard]] HRESULT UpdateDrawingBrushes(const TextAttribute& textAttributes,
const RenderSettings& renderSettings,
RenderSettings& renderSettings,
const gsl::not_null<IRenderData*> pData,
const bool usingSoftFont,
const bool isSettingDefaultBrushes) noexcept override;

View File

@@ -342,9 +342,9 @@ void Clipboard::StoreSelectionToClipboard(const bool copyFormatting)
return;
}
const auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
const auto& buffer = gci.GetActiveOutputBuffer().GetTextBuffer();
const auto& renderSettings = gci.GetRenderSettings();
auto& renderSettings = gci.GetRenderSettings();
const auto GetAttributeColors = [&](const auto& attr) {
const auto [fg, bg] = renderSettings.GetAttributeColors(attr);

View File

@@ -295,7 +295,7 @@ void Menu::s_ShowPropertiesDialog(HWND const hwnd, BOOL const Defaults)
[[nodiscard]] HRESULT Menu::s_GetConsoleState(CONSOLE_STATE_INFO* const pStateInfo)
{
const auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
const auto& ScreenInfo = gci.GetActiveOutputBuffer();
LOG_IF_FAILED(til::unwrap_coord_size_hr(ScreenInfo.GetBufferSize().Dimensions(), pStateInfo->ScreenBufferSize));
LOG_IF_FAILED(til::unwrap_coord_size_hr(ScreenInfo.GetViewport().Dimensions(), pStateInfo->WindowSize));

View File

@@ -646,7 +646,7 @@ try
}
CATCH_RETURN()
[[nodiscard]] HRESULT AtlasEngine::UpdateDrawingBrushes(const TextAttribute& textAttributes, const RenderSettings& renderSettings, const gsl::not_null<IRenderData*> /*pData*/, const bool usingSoftFont, const bool isSettingDefaultBrushes) noexcept
[[nodiscard]] HRESULT AtlasEngine::UpdateDrawingBrushes(const TextAttribute& textAttributes, RenderSettings& renderSettings, const gsl::not_null<IRenderData*> /*pData*/, const bool usingSoftFont, const bool isSettingDefaultBrushes) noexcept
try
{
auto [fg, bg] = renderSettings.GetAttributeColorsWithAlpha(textAttributes);

View File

@@ -46,7 +46,7 @@ namespace Microsoft::Console::Render::Atlas
[[nodiscard]] HRESULT PaintImageSlice(const ImageSlice& imageSlice, til::CoordType targetRow, til::CoordType viewportLeft) noexcept override;
[[nodiscard]] HRESULT PaintSelection(const til::rect& rect) noexcept override;
[[nodiscard]] HRESULT PaintCursor(const CursorOptions& options) noexcept override;
[[nodiscard]] HRESULT UpdateDrawingBrushes(const TextAttribute& textAttributes, const RenderSettings& renderSettings, gsl::not_null<IRenderData*> pData, bool usingSoftFont, bool isSettingDefaultBrushes) noexcept override;
[[nodiscard]] HRESULT UpdateDrawingBrushes(const TextAttribute& textAttributes, RenderSettings& renderSettings, gsl::not_null<IRenderData*> pData, bool usingSoftFont, bool isSettingDefaultBrushes) noexcept override;
[[nodiscard]] HRESULT UpdateFont(const FontInfoDesired& FontInfoDesired, _Out_ FontInfo& FontInfo) noexcept override;
[[nodiscard]] HRESULT UpdateSoftFont(std::span<const uint16_t> bitPattern, til::size cellSize, size_t centeringHint) noexcept override;
[[nodiscard]] HRESULT UpdateDpi(int iDpi) noexcept override;

View File

@@ -8,12 +8,12 @@
#include "../../types/inc/ColorFix.hpp"
#include "../../types/inc/colorTable.hpp"
using namespace Microsoft::Console;
using namespace Microsoft::Console::Render;
using Microsoft::Console::Utils::InitializeColorTable;
RenderSettings::RenderSettings() noexcept
{
InitializeColorTable(_colorTable);
Utils::InitializeANSIColorTable(_colorTable);
SetColorTableEntry(TextColor::DEFAULT_FOREGROUND, INVALID_COLOR);
SetColorTableEntry(TextColor::DEFAULT_BACKGROUND, INVALID_COLOR);
@@ -30,12 +30,14 @@ RenderSettings::RenderSettings() noexcept
SaveDefaultSettings();
}
// Routine Description:
// - Saves the current color table and color aliases as the default values, so
// we can later restore them when a hard reset (RIS) is requested.
// Saves the current color table and color aliases as the default values,
// so we can later restore them when a hard reset (RIS) is requested.
//
// Since this is called after any color table modifications were made by
// the hosting terminal, it's a convenient time to handle Generate256Colors.
void RenderSettings::SaveDefaultSettings() noexcept
{
_defaultColorTable = _colorTable;
_defaultColorTable = _getColorTable();
_defaultColorAliasIndices = _colorAliasIndices;
}
@@ -49,6 +51,7 @@ void RenderSettings::RestoreDefaultSettings() noexcept
// DECSCNM and Synchronized Output are the only render mode we need to reset.
// The others are all user preferences that can't be changed programmatically.
_renderMode.reset(Mode::ScreenReversed, Mode::SynchronizedOutput);
_flagColorTableDirty();
}
// Routine Description:
@@ -58,6 +61,13 @@ void RenderSettings::RestoreDefaultSettings() noexcept
// - enabled - Set to true to enable the mode, false to disable it.
void RenderSettings::SetRenderMode(const Mode mode, const bool enabled) noexcept
{
// NOTE: This doesn't call _flagColorTableDirty(), because we want
// to *always* force a refresh if Mode::Generate256Colors gets flipped.
if (mode == Mode::Generate256Colors && _renderMode.test(mode) != enabled)
{
_colorTableDirty = true;
}
_renderMode.set(mode, enabled);
}
@@ -74,26 +84,48 @@ bool RenderSettings::GetRenderMode(const Mode mode) const noexcept
// Routine Description:
// - Returns a reference to the active color table array.
const std::array<COLORREF, TextColor::TABLE_SIZE>& RenderSettings::GetColorTable() const noexcept
const std::array<COLORREF, TextColor::TABLE_SIZE>& RenderSettings::GetColorTable() noexcept
{
return _getColorTable();
}
const std::array<COLORREF, TextColor::TABLE_SIZE>& RenderSettings::_getColorTable() noexcept
{
if (_colorTableDirty)
{
_generate256ColorTable();
}
return _colorTable;
}
// Routine Description:
// - Resets the first 16 color table entries with default values.
void RenderSettings::ResetColorTable() noexcept
void RenderSettings::_flagColorTableDirty() noexcept
{
InitializeColorTable({ _colorTable.data(), 16 });
_colorTableDirty |= _renderMode.test(Mode::Generate256Colors);
}
// Routine Description:
// - Updates the given index in the color table to a new value.
// Arguments:
// - tableIndex - The index of the color to update.
// - color - The new COLORREF to use as that color table value.
__declspec(noinline) void RenderSettings::_generate256ColorTable() noexcept
{
_colorTableDirty = false;
if (_renderMode.test(Mode::Generate256Colors))
{
const auto bg = _colorTable[GetColorAliasIndex(ColorAlias::DefaultBackground)];
const auto fg = _colorTable[GetColorAliasIndex(ColorAlias::DefaultForeground)];
Utils::InitializeExtendedColorTableDynamic(_colorTable, bg, fg);
}
else
{
Utils::InitializeExtendedColorTable(_colorTable);
}
}
// Updates the given index in the color table to a new value.
//
// NOTE: After calling SetColorTableEntry you MUST call NotifyColorTableChanged!
void RenderSettings::SetColorTableEntry(const size_t tableIndex, const COLORREF color)
{
_colorTable.at(tableIndex) = color;
_flagColorTableDirty();
}
// Routine Description:
@@ -102,9 +134,9 @@ void RenderSettings::SetColorTableEntry(const size_t tableIndex, const COLORREF
// - tableIndex - The index of the color to retrieve.
// Return Value:
// - The COLORREF value for the color at that index in the table.
COLORREF RenderSettings::GetColorTableEntry(const size_t tableIndex) const
COLORREF RenderSettings::GetColorTableEntry(const size_t tableIndex)
{
return _colorTable.at(tableIndex);
return _getColorTable().at(tableIndex);
}
// Routine Description:
@@ -112,6 +144,7 @@ COLORREF RenderSettings::GetColorTableEntry(const size_t tableIndex) const
void RenderSettings::RestoreDefaultIndexed256ColorTable()
{
std::copy_n(_defaultColorTable.begin(), 256, _colorTable.begin());
_flagColorTableDirty();
}
// Routine Description:
@@ -119,6 +152,7 @@ void RenderSettings::RestoreDefaultIndexed256ColorTable()
void RenderSettings::RestoreDefaultColorTableEntry(const size_t tableIndex)
{
_colorTable.at(tableIndex) = _defaultColorTable.at(tableIndex);
_flagColorTableDirty();
}
// Routine Description:
@@ -127,6 +161,8 @@ void RenderSettings::RestoreDefaultColorTableEntry(const size_t tableIndex)
// - alias - The color alias to update.
// - tableIndex - The new position of the alias in the color table.
// - color - The new COLORREF to assign to that alias.
//
// NOTE: After calling SetColorAlias you MUST call NotifyColorTableChanged!
void RenderSettings::SetColorAlias(const ColorAlias alias, const size_t tableIndex, const COLORREF color)
{
SetColorAliasIndex(alias, tableIndex);
@@ -139,7 +175,7 @@ void RenderSettings::SetColorAlias(const ColorAlias alias, const size_t tableInd
// - alias - The color alias to retrieve.
// Return Value:
// - The COLORREF value of the alias.
COLORREF RenderSettings::GetColorAlias(const ColorAlias alias) const
COLORREF RenderSettings::GetColorAlias(const ColorAlias alias)
{
return GetColorTableEntry(GetColorAliasIndex(alias));
}
@@ -154,6 +190,7 @@ void RenderSettings::SetColorAliasIndex(const ColorAlias alias, const size_t tab
if (tableIndex < TextColor::TABLE_SIZE)
{
gsl::at(_colorAliasIndices, static_cast<size_t>(alias)) = tableIndex;
_flagColorTableDirty();
}
}
@@ -163,7 +200,7 @@ void RenderSettings::SetColorAliasIndex(const ColorAlias alias, const size_t tab
// - alias - The color alias to retrieve.
// Return Value:
// - The position in the color table where the color is stored.
size_t RenderSettings::GetColorAliasIndex(const ColorAlias alias) const noexcept
size_t RenderSettings::GetColorAliasIndex(const ColorAlias alias) noexcept
{
return gsl::at(_colorAliasIndices, static_cast<size_t>(alias));
}
@@ -171,6 +208,7 @@ size_t RenderSettings::GetColorAliasIndex(const ColorAlias alias) const noexcept
void RenderSettings::RestoreDefaultColorAliasIndex(const ColorAlias alias) noexcept
{
gsl::at(_colorAliasIndices, static_cast<size_t>(alias)) = gsl::at(_defaultColorAliasIndices, static_cast<size_t>(alias));
_flagColorTableDirty();
}
// Routine Description:
@@ -180,7 +218,7 @@ void RenderSettings::RestoreDefaultColorAliasIndex(const ColorAlias alias) noexc
// - attr - The TextAttribute to retrieve the colors for.
// Return Value:
// - The color values of the attribute's foreground and background.
std::pair<COLORREF, COLORREF> RenderSettings::GetAttributeColors(const TextAttribute& attr) const noexcept
std::pair<COLORREF, COLORREF> RenderSettings::GetAttributeColors(const TextAttribute& attr) noexcept
{
const auto fgTextColor = attr.GetForeground();
const auto bgTextColor = attr.GetBackground();
@@ -192,8 +230,9 @@ std::pair<COLORREF, COLORREF> RenderSettings::GetAttributeColors(const TextAttri
const auto dimFg = attr.IsFaint() || (_blinkShouldBeFaint && attr.IsBlinking());
const auto swapFgAndBg = attr.IsReverseVideo() ^ GetRenderMode(Mode::ScreenReversed);
auto fg = fgTextColor.GetColor(_colorTable, defaultFgIndex, brightenFg);
auto bg = bgTextColor.GetColor(_colorTable, defaultBgIndex);
const auto& colorTable = _getColorTable();
auto fg = fgTextColor.GetColor(colorTable, defaultFgIndex, brightenFg);
auto bg = bgTextColor.GetColor(colorTable, defaultBgIndex);
if (dimFg)
{
@@ -233,7 +272,7 @@ std::pair<COLORREF, COLORREF> RenderSettings::GetAttributeColors(const TextAttri
// - attr - The TextAttribute to retrieve the colors for.
// Return Value:
// - The color values of the attribute's foreground and background.
std::pair<COLORREF, COLORREF> RenderSettings::GetAttributeColorsWithAlpha(const TextAttribute& attr) const noexcept
std::pair<COLORREF, COLORREF> RenderSettings::GetAttributeColorsWithAlpha(const TextAttribute& attr) noexcept
{
auto [fg, bg] = GetAttributeColors(attr);
@@ -256,7 +295,7 @@ std::pair<COLORREF, COLORREF> RenderSettings::GetAttributeColorsWithAlpha(const
// - attr - The TextAttribute to retrieve the underline color from.
// Return Value:
// - The color value of the attribute's underline.
COLORREF RenderSettings::GetAttributeUnderlineColor(const TextAttribute& attr) const noexcept
COLORREF RenderSettings::GetAttributeUnderlineColor(const TextAttribute& attr) noexcept
{
const auto [fg, bg] = GetAttributeColors(attr);
const auto ulTextColor = attr.GetUnderlineColor();
@@ -265,8 +304,9 @@ COLORREF RenderSettings::GetAttributeUnderlineColor(const TextAttribute& attr) c
return fg;
}
const auto& colorTable = _getColorTable();
const auto defaultUlIndex = GetColorAliasIndex(ColorAlias::DefaultForeground);
auto ul = ulTextColor.GetColor(_colorTable, defaultUlIndex, true);
auto ul = ulTextColor.GetColor(colorTable, defaultUlIndex, true);
if (attr.IsInvisible())
{
ul = bg;

View File

@@ -62,7 +62,7 @@ namespace Microsoft::Console::Render
[[nodiscard]] HRESULT PaintCursor(const CursorOptions& options) noexcept override;
[[nodiscard]] HRESULT UpdateDrawingBrushes(const TextAttribute& textAttributes,
const RenderSettings& renderSettings,
RenderSettings& renderSettings,
const gsl::not_null<IRenderData*> pData,
const bool usingSoftFont,
const bool isSettingDefaultBrushes) noexcept override;

View File

@@ -262,7 +262,7 @@ GdiEngine::~GdiEngine()
// Return Value:
// - S_OK if set successfully or relevant GDI error via HRESULT.
[[nodiscard]] HRESULT GdiEngine::UpdateDrawingBrushes(const TextAttribute& textAttributes,
const RenderSettings& renderSettings,
RenderSettings& renderSettings,
const gsl::not_null<IRenderData*> /*pData*/,
const bool usingSoftFont,
const bool isSettingDefaultBrushes) noexcept

View File

@@ -68,7 +68,7 @@ namespace Microsoft::Console::Render
virtual std::vector<size_t> GetPatternId(const til::point location) const = 0;
// This block used to be IUiaData.
virtual std::pair<COLORREF, COLORREF> GetAttributeColors(const TextAttribute& attr) const noexcept = 0;
virtual std::pair<COLORREF, COLORREF> GetAttributeColors(const TextAttribute& attr) noexcept = 0;
virtual bool IsSelectionActive() const = 0;
virtual bool IsBlockSelection() const = 0;
virtual void ClearSelection() = 0;

View File

@@ -83,7 +83,7 @@ namespace Microsoft::Console::Render
[[nodiscard]] virtual HRESULT PaintImageSlice(const ImageSlice& imageSlice, til::CoordType targetRow, til::CoordType viewportLeft) noexcept = 0;
[[nodiscard]] virtual HRESULT PaintSelection(const til::rect& rect) noexcept = 0;
[[nodiscard]] virtual HRESULT PaintCursor(const CursorOptions& options) noexcept = 0;
[[nodiscard]] virtual HRESULT UpdateDrawingBrushes(const TextAttribute& textAttributes, const RenderSettings& renderSettings, gsl::not_null<IRenderData*> pData, bool usingSoftFont, bool isSettingDefaultBrushes) noexcept = 0;
[[nodiscard]] virtual HRESULT UpdateDrawingBrushes(const TextAttribute& textAttributes, RenderSettings& renderSettings, gsl::not_null<IRenderData*> pData, bool usingSoftFont, bool isSettingDefaultBrushes) noexcept = 0;
[[nodiscard]] virtual HRESULT UpdateFont(const FontInfoDesired& FontInfoDesired, _Out_ FontInfo& FontInfo) noexcept = 0;
[[nodiscard]] virtual HRESULT UpdateSoftFont(std::span<const uint16_t> bitPattern, til::size cellSize, size_t centeringHint) noexcept = 0;
[[nodiscard]] virtual HRESULT UpdateDpi(int iDpi) noexcept = 0;

View File

@@ -20,6 +20,9 @@ namespace Microsoft::Console::Render
public:
enum class Mode : size_t
{
// Generate256Colors is first just to make test(Generate256Colors)
// ever so slightly cheaper. It's the most widely accessed one.
Generate256Colors,
IndexedDistinguishableColors,
AlwaysDistinguishableColors,
IntenseIsBold,
@@ -34,28 +37,36 @@ namespace Microsoft::Console::Render
void RestoreDefaultSettings() noexcept;
void SetRenderMode(const Mode mode, const bool enabled) noexcept;
bool GetRenderMode(const Mode mode) const noexcept;
const std::array<COLORREF, TextColor::TABLE_SIZE>& GetColorTable() const noexcept;
void ResetColorTable() noexcept;
const std::array<COLORREF, TextColor::TABLE_SIZE>& GetColorTable() noexcept;
void SetColorTableEntry(const size_t tableIndex, const COLORREF color);
COLORREF GetColorTableEntry(const size_t tableIndex) const;
COLORREF GetColorTableEntry(const size_t tableIndex);
void RestoreDefaultIndexed256ColorTable();
void RestoreDefaultColorTableEntry(const size_t tableIndex);
void SetColorAlias(const ColorAlias alias, const size_t tableIndex, const COLORREF color);
COLORREF GetColorAlias(const ColorAlias alias) const;
COLORREF GetColorAlias(const ColorAlias alias);
void SetColorAliasIndex(const ColorAlias alias, const size_t tableIndex) noexcept;
size_t GetColorAliasIndex(const ColorAlias alias) const noexcept;
size_t GetColorAliasIndex(const ColorAlias alias) noexcept;
void RestoreDefaultColorAliasIndex(const ColorAlias alias) noexcept;
std::pair<COLORREF, COLORREF> GetAttributeColors(const TextAttribute& attr) const noexcept;
std::pair<COLORREF, COLORREF> GetAttributeColorsWithAlpha(const TextAttribute& attr) const noexcept;
COLORREF GetAttributeUnderlineColor(const TextAttribute& attr) const noexcept;
std::pair<COLORREF, COLORREF> GetAttributeColors(const TextAttribute& attr) noexcept;
std::pair<COLORREF, COLORREF> GetAttributeColorsWithAlpha(const TextAttribute& attr) noexcept;
COLORREF GetAttributeUnderlineColor(const TextAttribute& attr) noexcept;
void ToggleBlinkRendition() noexcept;
private:
const std::array<COLORREF, TextColor::TABLE_SIZE>& _getColorTable() noexcept;
void _flagColorTableDirty() noexcept;
void _generate256ColorTable() noexcept;
// NOTE: Reads of _colorTable MUST occur through _getColorTable()!
// Writers to one of the following 3 MUST call _flagColorTableDirty()!
til::enumset<Mode> _renderMode{ Mode::IntenseIsBright };
std::array<COLORREF, TextColor::TABLE_SIZE> _colorTable;
std::array<size_t, static_cast<size_t>(ColorAlias::ENUM_COUNT)> _colorAliasIndices;
std::array<COLORREF, TextColor::TABLE_SIZE> _defaultColorTable;
std::array<size_t, static_cast<size_t>(ColorAlias::ENUM_COUNT)> _defaultColorAliasIndices;
bool _colorTableDirty = true;
bool _blinkShouldBeFaint = false;
};
}

View File

@@ -365,7 +365,7 @@ void UiaEngine::WaitUntilCanRender() noexcept
// Return Value:
// - S_FALSE since we do nothing
[[nodiscard]] HRESULT UiaEngine::UpdateDrawingBrushes(const TextAttribute& /*textAttributes*/,
const RenderSettings& /*renderSettings*/,
RenderSettings& /*renderSettings*/,
const gsl::not_null<IRenderData*> /*pData*/,
const bool /*usingSoftFont*/,
const bool /*isSettingDefaultBrushes*/) noexcept

View File

@@ -51,7 +51,7 @@ namespace Microsoft::Console::Render
[[nodiscard]] HRESULT PaintBufferGridLines(const GridLineSet lines, const COLORREF gridlineColor, const COLORREF underlineColor, const size_t cchLine, const til::point coordTarget) noexcept override;
[[nodiscard]] HRESULT PaintSelection(const til::rect& rect) noexcept override;
[[nodiscard]] HRESULT PaintCursor(const CursorOptions& options) noexcept override;
[[nodiscard]] HRESULT UpdateDrawingBrushes(const TextAttribute& textAttributes, const RenderSettings& renderSettings, const gsl::not_null<IRenderData*> pData, const bool usingSoftFont, const bool isSettingDefaultBrushes) noexcept override;
[[nodiscard]] HRESULT UpdateDrawingBrushes(const TextAttribute& textAttributes, RenderSettings& renderSettings, const gsl::not_null<IRenderData*> pData, const bool usingSoftFont, const bool isSettingDefaultBrushes) noexcept override;
[[nodiscard]] HRESULT UpdateFont(const FontInfoDesired& FontInfoDesired, _Out_ FontInfo& FontInfo) noexcept override;
[[nodiscard]] HRESULT UpdateDpi(const int iDpi) noexcept override;
[[nodiscard]] HRESULT UpdateViewport(const til::inclusive_rect& srNewViewport) noexcept override;

View File

@@ -292,7 +292,7 @@ CATCH_RETURN()
}
[[nodiscard]] HRESULT WddmConEngine::UpdateDrawingBrushes(const TextAttribute& textAttributes,
const RenderSettings& /*renderSettings*/,
RenderSettings& /*renderSettings*/,
const gsl::not_null<IRenderData*> /*pData*/,
const bool /*usingSoftFont*/,
const bool /*isSettingDefaultBrushes*/) noexcept

View File

@@ -47,7 +47,7 @@ namespace Microsoft::Console::Render
[[nodiscard]] HRESULT PaintCursor(const CursorOptions& options) noexcept override;
[[nodiscard]] HRESULT UpdateDrawingBrushes(const TextAttribute& textAttributes,
const RenderSettings& renderSettings,
RenderSettings& renderSettings,
const gsl::not_null<IRenderData*> pData,
const bool usingSoftFont,
const bool isSettingDefaultBrushes) noexcept override;

View File

@@ -135,7 +135,7 @@ public:
const bool isVisible) noexcept = 0;
// driver will pare down for non-Ex method
virtual void GetConsoleScreenBufferInfoExImpl(const IConsoleOutputObject& context,
virtual void GetConsoleScreenBufferInfoExImpl(IConsoleOutputObject& context,
CONSOLE_SCREEN_BUFFER_INFOEX& data) noexcept = 0;
[[nodiscard]] virtual HRESULT SetConsoleScreenBufferInfoExImpl(IConsoleOutputObject& OutContext,

View File

@@ -4,6 +4,8 @@
#include "precomp.h"
#include "inc/ColorFix.hpp"
using namespace ColorFix;
// This table contains a direct mapping from 8-bit sRGB to linear RGB.
// It was generated using the following code:
// #include <charconv>
@@ -87,20 +89,6 @@ __forceinline float cbrtf_est(float a) noexcept
// The only change I made is to replace cbrtf() with cbrtf_est() to cut the CPU cost by a third.
namespace oklab
{
struct Lab
{
float l;
float a;
float b;
};
struct RGB
{
float r;
float g;
float b;
};
__forceinline Lab linear_srgb_to_oklab(const RGB& c) noexcept
{
const auto l = 0.4122214708f * c.r + 0.5363325363f * c.g + 0.0514459929f * c.b;
@@ -115,6 +103,7 @@ namespace oklab
0.2104542553f * l_ + 0.7936177850f * m_ - 0.0040720468f * s_,
1.9779984951f * l_ - 2.4285922050f * m_ + 0.4505937099f * s_,
0.0259040371f * l_ + 0.7827717662f * m_ - 0.8086757660f * s_,
0,
};
}
@@ -132,6 +121,7 @@ namespace oklab
+4.0767416621f * l - 3.3077115913f * m + 0.2309699292f * s,
-1.2684380046f * l + 2.6097574011f * m - 0.3413193965f * s,
-0.0041960863f * l - 0.7034186147f * m + 1.7076147010f * s,
0,
};
}
}
@@ -140,17 +130,17 @@ namespace oklab
#pragma warning(disable : 26446) // Prefer to use gsl::at() instead of unchecked subscript operator (bounds.4).
#pragma warning(disable : 26482) // Only index into arrays using constant expressions (bounds.2).
__forceinline oklab::RGB colorrefToLinear(COLORREF c) noexcept
__forceinline RGB colorrefToLinear(COLORREF c) noexcept
{
const auto r = srgbToRgbLUT[(c >> 0) & 0xff];
const auto g = srgbToRgbLUT[(c >> 8) & 0xff];
const auto b = srgbToRgbLUT[(c >> 16) & 0xff];
return { r, g, b };
return { r, g, b, 0 };
}
#pragma warning(pop)
__forceinline COLORREF linearToColorref(const oklab::RGB& c) noexcept
__forceinline COLORREF linearToColorref(const RGB& c) noexcept
{
auto r = saturate(c.r);
auto g = saturate(c.g);
@@ -161,13 +151,23 @@ __forceinline COLORREF linearToColorref(const oklab::RGB& c) noexcept
return lrintf(r) | (lrintf(g) << 8) | (lrintf(b) << 16);
}
Lab ColorFix::ColorrefToOklab(COLORREF color) noexcept
{
return oklab::linear_srgb_to_oklab(colorrefToLinear(color));
}
COLORREF ColorFix::OklabToColorref(const Lab& color) noexcept
{
return linearToColorref(oklab::oklab_to_linear_srgb(color));
}
// This function changes `color` so that it is visually different
// enough from `reference` that it's (much more easily) readable.
// See /doc/color_nudging.html
COLORREF ColorFix::GetPerceivableColor(COLORREF color, COLORREF reference, float minSquaredDistance) noexcept
{
const auto referenceOklab = oklab::linear_srgb_to_oklab(colorrefToLinear(reference));
auto colorOklab = oklab::linear_srgb_to_oklab(colorrefToLinear(color));
const auto referenceOklab = ColorrefToOklab(reference);
auto colorOklab = ColorrefToOklab(color);
// To determine whether the two colors are too close to each other we use the ΔEOK metric
// based on the Oklab color space. It's defined as the simple euclidean distance between.
@@ -206,19 +206,19 @@ COLORREF ColorFix::GetPerceivableColor(COLORREF color, COLORREF reference, float
colorOklab.l = referenceOklab.l - deltaL;
}
return linearToColorref(oklab::oklab_to_linear_srgb(colorOklab)) | (color & 0xff000000);
return OklabToColorref(colorOklab) | (color & 0xff000000);
}
COLORREF ColorFix::AdjustLightness(COLORREF color, float delta) noexcept
{
auto lab = oklab::linear_srgb_to_oklab(colorrefToLinear(color));
auto lab = ColorrefToOklab(color);
lab.l = saturate(lab.l + delta);
return linearToColorref(oklab::oklab_to_linear_srgb(lab)) | (color & 0xff000000);
return OklabToColorref(lab) | (color & 0xff000000);
}
float ColorFix::GetLightness(COLORREF color) noexcept
{
return oklab::linear_srgb_to_oklab(colorrefToLinear(color)).l;
return ColorrefToOklab(color).l;
}
TIL_FAST_MATH_END

View File

@@ -3,6 +3,10 @@
#include "precomp.h"
#include "inc/colorTable.hpp"
#include <DirectXMath.h>
#include "inc/ColorFix.hpp"
#include "til/static_map.h"
using namespace Microsoft::Console;
@@ -219,18 +223,6 @@ std::span<const til::color> Utils::CampbellColorTable() noexcept
return std::span{ campbellColorTable };
}
// Function Description:
// - Fill up to 256 entries of a given color table with the default values
// Arguments:
// - table: a color table to be filled
// Return Value:
// - <none>
void Utils::InitializeColorTable(const std::span<COLORREF> table) noexcept
{
InitializeANSIColorTable(table);
InitializeExtendedColorTable(table);
}
void Utils::InitializeANSIColorTable(const std::span<COLORREF> table) noexcept
{
if (table.size() >= campbellColorTable.size())
@@ -282,6 +274,100 @@ void Utils::InitializeExtendedColorTable(const std::span<COLORREF> table, const
}
}
// Based on the proposal at:
// https://gist.github.com/jake-stewart/0a8ea46159a7da2c808e5be2177e1783
// this generates the 256 color LUT based on the indexed 16 colors.
void Utils::InitializeExtendedColorTableDynamic(const std::span<COLORREF> table, const COLORREF defaultBackground, const COLORREF defaultForeground) noexcept
{
using namespace DirectX;
static constexpr XMVECTORF32 g_02 = { { { 0.2f, 0.2f, 0.2f, 0.2f } } };
static constexpr XMVECTORF32 g_004 = { { { 0.04f, 0.04f, 0.04f, 0.04f } } };
if (table.size() < 256)
{
return;
}
// NOTE: The `lab` array is 4KiB large. Still fits comfortably on the stack.
XMVECTOR lab[256];
// Get the first 8 base colors which are used to generate the rest of the 256-indexed table.
{
COLORREF corners[8];
// As per the proposal we're using the default background/foreground colors,
// not the black/white colors, for the first/last corner.
corners[0] = defaultBackground;
std::copy_n(&table[1], 6, &corners[1]);
corners[7] = defaultForeground;
// Map to OkLab
for (size_t i = 0; i < 8; i++)
{
lab[i] = std::bit_cast<XMVECTOR>(ColorFix::ColorrefToOklab(corners[i]));
}
}
// Now we do the trilinear interpolation.
// But instead of doing a lerp(t, a, b), like in the original code,
// we precompute the step and accumulate with additions (forward differences).
// float precision is entirely sufficient for this.
size_t idx = 16;
// 6x6x6 color cube (indices 16-231)
const auto dc0 = (lab[1] - lab[0]) * g_02;
const auto dc1 = (lab[3] - lab[2]) * g_02;
const auto dc2 = (lab[5] - lab[4]) * g_02;
const auto dc3 = (lab[7] - lab[6]) * g_02;
auto c0 = lab[0];
auto c1 = lab[2];
auto c2 = lab[4];
auto c3 = lab[6];
for (int r = 0; r < 6; r++)
{
const auto dc4 = (c1 - c0) * g_02;
const auto dc5 = (c3 - c2) * g_02;
auto c4 = c0;
auto c5 = c2;
for (int g = 0; g < 6; g++)
{
const auto dc6 = (c5 - c4) * g_02;
auto c6 = c4;
for (int b = 0; b < 6; b++)
{
lab[idx++] = c6;
c6 += dc6;
}
c4 += dc4;
c5 += dc5;
}
c0 += dc0;
c1 += dc1;
c2 += dc2;
c3 += dc3;
}
// Grayscale ramp (indices 232-255)
const auto dg = (lab[7] - lab[0]) * g_004;
auto g = lab[0];
for (int i = 0; i < 24; i++)
{
g += dg;
lab[idx++] = g;
}
// Map back to COLORREF
for (size_t i = 16; i < 256; i++)
{
table[i] = ColorFix::OklabToColorref(std::bit_cast<ColorFix::Lab>(lab[i]));
}
}
#pragma warning(pop)
#pragma warning(push)

View File

@@ -9,6 +9,32 @@
namespace ColorFix
{
union RGB
{
struct
{
float r;
float g;
float b;
float _; // Padding, to align it to 16 bytes for vectorization
};
float data[4];
};
union Lab
{
struct
{
float l;
float a;
float b;
float _;
};
float data[4];
};
Lab ColorrefToOklab(COLORREF color) noexcept;
COLORREF OklabToColorref(const Lab& color) noexcept;
COLORREF GetPerceivableColor(COLORREF color, COLORREF reference, float minSquaredDistance) noexcept;
COLORREF AdjustLightness(COLORREF color, float delta) noexcept;
float GetLightness(COLORREF color) noexcept;

View File

@@ -12,10 +12,10 @@ Abstract:
namespace Microsoft::Console::Utils
{
void InitializeColorTable(const std::span<COLORREF> table) noexcept;
void InitializeANSIColorTable(const std::span<COLORREF> table) noexcept;
void InitializeVT340ColorTable(const std::span<COLORREF> table) noexcept;
void InitializeExtendedColorTable(const std::span<COLORREF> table, const bool monochrome = false) noexcept;
void InitializeExtendedColorTableDynamic(std::span<COLORREF> table, COLORREF defaultBackground, COLORREF defaultForeground) noexcept;
std::span<const til::color> CampbellColorTable() noexcept;
std::optional<til::color> ColorFromXOrgAppColorName(const std::wstring_view wstr) noexcept;