Fix SGR indexed colors to distinguish Indexed256 color (and more) (#5834)

This PR introduces a new `ColorType` to allow us to distinguish between
`SGR` indexed colors from the 16 color table, the lower half of which
can be brightened, and the ISO/ITU indexed colors from the 256 color
table, which have a fixed brightness. Retaining the distinction between
these two types will enable us to forward the correct `SGR` sequences to
conpty when addressing issue #2661. 

The other benefit of retaining the color index (which we didn't
previously do for ISO/ITU colors) is that it ensures that the colors are
updated correctly when the color scheme is changed.

## References

* This is another step towards fixing the conpty narrowing bugs in issue
  #2661.
* This is technically a fix for issue #5384, but that won't be apparent
  until #2661 is complete.

## PR Checklist
* [x] Closes #1223
* [x] CLA signed. 
* [x] Tests added/passed
* [ ] Requires documentation to be updated
* [x] I've discussed this with core contributors already.

## Detailed Description of the Pull Request / Additional comments

The first part of this PR was the introduction of a new `ColorType` in
the `TextColor` class. Instead of just the one `IsIndex` type, there is
now an `IsIndex16` and an `IsIndex256`. `IsIndex16` covers the eight
original ANSI colors set with `SGR 3x` and `SGR 4x`, as well as the
brighter aixterm variants set with `SGR 9x` and `SGR 10x`. `IsIndex256`
covers the 256 ISO/ITU indexed colors set with `SGR 38;5` and `SGR
48;5`.

There are two reasons for this distinction. The first is that the ANSI
colors have the potential to be brightened by the `SGR 1` bold
attribute, while the ISO/ITO color do not. The second reason is that
when forwarding an attributes through conpty, we want to try and
preserve the original SGR sequence that generated each color (to the
extent that that is possible). By having the two separate types, we can
map the `IsIndex16` colors back to ANSI/aixterm values, and `IsIndex256`
to the ISO/ITU sequences.

In addition to the VT colors, we also have to deal with the legacy
colors set by the Windows console APIs, but we don't really need a
separate type for those. It seemed most appropriate to me to store them
as `IsIndex256` colors, since it doesn't make sense to have them
brightened by the `SGR 1` attribute (which is what would happen if they
were stored as `IsIndex16`). If a console app wanted a bright color it
would have selected one, so we shouldn't be messing with that choice.

The second part of the PR was the unification of the two color tables.
Originally we had a 16 color table for the legacy colors, and a separate
table for the 256 ISO/ITU colors. These have now been merged into one,
so color table lookups no longer need to decide which of the two tables
they should be referencing. I've also updated all the methods that took
a color table as a parameter to use a `basic_string_view` instead of
separate pointer and length variables, which I think makes them a lot
easier and safer to work with. 

With this new architecture in place, I could now update the
`AdaptDispatch` SGR implementation to store the ISO/ITU indexed colors
as `IsIndex256` values, where before they were mapped to RGB values
(which prevented them reflecting any color scheme changes). I could also
update the `TerminalDispatch` implementation to differentiate between
the two index types, so that the `SGR 1` brightening would only be
applied to the ANSI colors.

I've also done a bit of code refactoring to try and minimise any direct
access to the color tables, getting rid of a lot of places that were
copying tables with `memmove` operations. I'm hoping this will make it
easier for us to update the code in the future if we want to reorder the
table entries (which is likely a requirement for unifying the
`AdaptDispatch` and `TerminalDispatch` implementations). 

## Validation Steps Performed

For testing, I've just updated the existing unit tests to account for
the API changes. The `TextColorTests` required an extra parameter
specifying the index type when setting an index. And the `AdapterTest`
and `ScreenBufferTests` required the use of the new `SetIndexedXXX`
methods in order to be explicit about the index type, instead of relying
on the `TextAttribute` constructor and the old `SetForeground` and
`SetBackground` methods which didn't have a way to differentiate index
types.

I've manually tested the various console APIs
(`SetConsoleTextAttribute`, `ReadConsoleOutputAttribute`, and
`ReadConsoleOutput`), to make sure they are still setting and reading
the attributes as well as they used to. And I've tested the
`SetConsoleScreenBufferInfoEx` and `GetConsoleScreenBufferInfoEx` APIs
to make sure they can read and write the color table correctly. I've
also tested the color table in the properties dialog, made sure it was
saved and restored from the registry correctly, and similarly saved and
restored from a shortcut link.

Note that there are still a bunch of issues with the color table APIs,
but no new problems have been introduced by the changes in this PR, as
far as I could tell.

I've also done a bunch of manual tests of `OSC 4` to make sure it's
updating all the colors correctly (at least in conhost), and confirmed
that the test case in issue #1223 now works as expected.
This commit is contained in:
James Holderness 2020-05-27 23:34:45 +01:00 committed by GitHub
parent e7c22fbadb
commit fa7c1abdf8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
36 changed files with 327 additions and 375 deletions

View file

@ -10,6 +10,11 @@ bool TextAttribute::IsLegacy() const noexcept
return _foreground.IsLegacy() && _background.IsLegacy();
}
bool TextAttribute::IsHighColor() const noexcept
{
return _foreground.IsHighColor() || _background.IsHighColor();
}
// Arguments:
// - None
// Return Value:
@ -72,12 +77,22 @@ void TextAttribute::SetBackground(const COLORREF rgbBackground) noexcept
void TextAttribute::SetIndexedForeground(const BYTE fgIndex) noexcept
{
_foreground = TextColor(fgIndex);
_foreground = TextColor(fgIndex, false);
}
void TextAttribute::SetIndexedBackground(const BYTE bgIndex) noexcept
{
_background = TextColor(bgIndex);
_background = TextColor(bgIndex, false);
}
void TextAttribute::SetIndexedForeground256(const BYTE fgIndex) noexcept
{
_foreground = TextColor(fgIndex, true);
}
void TextAttribute::SetIndexedBackground256(const BYTE bgIndex) noexcept
{
_background = TextColor(bgIndex, true);
}
void TextAttribute::SetColor(const COLORREF rgbColor, const bool fIsForeground) noexcept

View file

@ -42,8 +42,8 @@ public:
constexpr TextAttribute(const WORD wLegacyAttr) noexcept :
_wAttrLegacy{ gsl::narrow_cast<WORD>(wLegacyAttr & META_ATTRS) },
_foreground{ gsl::narrow_cast<BYTE>(wLegacyAttr & FG_ATTRS) },
_background{ gsl::narrow_cast<BYTE>((wLegacyAttr & BG_ATTRS) >> 4) },
_foreground{ gsl::narrow_cast<BYTE>(wLegacyAttr & FG_ATTRS), true },
_background{ gsl::narrow_cast<BYTE>((wLegacyAttr & BG_ATTRS) >> 4), true },
_extendedAttrs{ ExtendedAttributes::Normal }
{
// If we're given lead/trailing byte information with the legacy color, strip it.
@ -59,12 +59,13 @@ public:
{
}
constexpr WORD GetLegacyAttributes() const noexcept
WORD GetLegacyAttributes() const noexcept
{
const BYTE fg = (_foreground.GetIndex() & FG_ATTRS);
const BYTE bg = (_background.GetIndex() << 4) & BG_ATTRS;
const WORD meta = (_wAttrLegacy & META_ATTRS);
return (fg | bg | meta) | (IsBold() ? FOREGROUND_INTENSITY : 0);
const bool brighten = _foreground.IsIndex16() && IsBold();
return (fg | bg | meta) | (brighten ? FOREGROUND_INTENSITY : 0);
}
// Method Description:
@ -79,15 +80,16 @@ public:
// the background not be a legacy style attribute.
// Return Value:
// - a WORD with legacy-style attributes for this textattribute.
constexpr WORD GetLegacyAttributes(const BYTE defaultFgIndex,
const BYTE defaultBgIndex) const noexcept
WORD GetLegacyAttributes(const BYTE defaultFgIndex,
const BYTE defaultBgIndex) const noexcept
{
const BYTE fgIndex = _foreground.IsLegacy() ? _foreground.GetIndex() : defaultFgIndex;
const BYTE bgIndex = _background.IsLegacy() ? _background.GetIndex() : defaultBgIndex;
const BYTE fg = (fgIndex & FG_ATTRS);
const BYTE bg = (bgIndex << 4) & BG_ATTRS;
const WORD meta = (_wAttrLegacy & META_ATTRS);
return (fg | bg | meta) | (IsBold() ? FOREGROUND_INTENSITY : 0);
const bool brighten = _foreground.IsIndex16() && IsBold();
return (fg | bg | meta) | (brighten ? FOREGROUND_INTENSITY : 0);
}
COLORREF CalculateRgbForeground(std::basic_string_view<COLORREF> colorTable,
@ -117,6 +119,7 @@ public:
friend constexpr bool operator!=(const WORD& legacyAttr, const TextAttribute& attr) noexcept;
bool IsLegacy() const noexcept;
bool IsHighColor() const noexcept;
bool IsBold() const noexcept;
bool IsItalic() const noexcept;
bool IsBlinking() const noexcept;
@ -139,6 +142,8 @@ public:
void SetBackground(const COLORREF rgbBackground) noexcept;
void SetIndexedForeground(const BYTE fgIndex) noexcept;
void SetIndexedBackground(const BYTE bgIndex) noexcept;
void SetIndexedForeground256(const BYTE fgIndex) noexcept;
void SetIndexedBackground256(const BYTE bgIndex) noexcept;
void SetColor(const COLORREF rgbColor, const bool fIsForeground) noexcept;
void SetDefaultForeground() noexcept;
@ -149,11 +154,6 @@ public:
void SetStandardErase() noexcept;
constexpr bool IsRgb() const noexcept
{
return _foreground.IsRgb() || _background.IsRgb();
}
// This returns whether this attribute, if printed directly next to another attribute, for the space
// character, would look identical to the other one.
bool HasIdenticalVisualRepresentationForBlankSpace(const TextAttribute& other, const bool inverted = false) const noexcept
@ -224,26 +224,6 @@ constexpr bool operator!=(const TextAttribute& a, const TextAttribute& b) noexce
return !(a == b);
}
constexpr bool operator==(const TextAttribute& attr, const WORD& legacyAttr) noexcept
{
return attr.GetLegacyAttributes() == legacyAttr;
}
constexpr bool operator!=(const TextAttribute& attr, const WORD& legacyAttr) noexcept
{
return !(attr == legacyAttr);
}
constexpr bool operator==(const WORD& legacyAttr, const TextAttribute& attr) noexcept
{
return attr == legacyAttr;
}
constexpr bool operator!=(const WORD& legacyAttr, const TextAttribute& attr) noexcept
{
return !(attr == legacyAttr);
}
#ifdef UNIT_TESTING
#define LOG_ATTR(attr) (Log::Comment(NoThrowString().Format( \

View file

@ -4,6 +4,36 @@
#include "precomp.h"
#include "TextColor.h"
bool TextColor::IsLegacy() const noexcept
{
return IsIndex16() || (IsIndex256() && _index < 16);
}
bool TextColor::IsHighColor() const noexcept
{
return IsRgb() || (IsIndex256() && _index >= 16);
}
bool TextColor::IsIndex16() const noexcept
{
return _meta == ColorType::IsIndex16;
}
bool TextColor::IsIndex256() const noexcept
{
return _meta == ColorType::IsIndex256;
}
bool TextColor::IsDefault() const noexcept
{
return _meta == ColorType::IsDefault;
}
bool TextColor::IsRgb() const noexcept
{
return _meta == ColorType::IsRgb;
}
// Method Description:
// - Sets the color value of this attribute, and sets this color to be an RGB
// attribute.
@ -23,11 +53,12 @@ void TextColor::SetColor(const COLORREF rgbColor) noexcept
// - Sets this TextColor to be a legacy-style index into the color table.
// Arguments:
// - index: the index of the colortable we should use for this TextColor.
// - isIndex256: is this a 256 color index (true) or a 16 color index (false).
// Return Value:
// - <none>
void TextColor::SetIndex(const BYTE index) noexcept
void TextColor::SetIndex(const BYTE index, const bool isIndex256) noexcept
{
_meta = ColorType::IsIndex;
_meta = isIndex256 ? ColorType::IsIndex256 : ColorType::IsIndex16;
_index = index;
}
@ -48,15 +79,15 @@ void TextColor::SetDefault() noexcept
// * If we're an RGB color, we'll use that value.
// * If we're an indexed color table value, we'll use that index to look up
// our value in the provided color table.
// - If brighten is true, and the index is in the "dark" portion of the
// color table (indices [0,7]), then we'll look up the bright version of
// this color (from indices [8,15]). This should be true for
// TextAttributes that are "Bold" and we're treating bold as bright
// (which is the default behavior of most terminals.)
// - If brighten is true, and we've got a 16 color index in the "dark"
// portion of the color table (indices [0,7]), then we'll look up the
// bright version of this color (from indices [8,15]). This should be
// true for TextAttributes that are "Bold" and we're treating bold as
// bright (which is the default behavior of most terminals.)
// * If we're a default color, we'll return the default color provided.
// Arguments:
// - colorTable: The table of colors we should use to look up the value of a
// legacy attribute from
// - colorTable: The table of colors we should use to look up the value of
// an indexed attribute from.
// - defaultColor: The color value to use if we're a default attribute.
// - brighten: if true, we'll brighten a dark color table index.
// Return Value:
@ -94,21 +125,13 @@ COLORREF TextColor::GetColor(std::basic_string_view<COLORREF> colorTable,
{
return _GetRGB();
}
else if (IsIndex16() && brighten)
{
return colorTable.at(_index | 8);
}
else
{
FAIL_FAST_IF(colorTable.size() < _index);
// If the color is already bright (it's in index [8,15] or it's a
// 256color value [16,255], then boldness does nothing.
if (brighten && _index < 8)
{
FAIL_FAST_IF(colorTable.size() < 16);
FAIL_FAST_IF(gsl::narrow_cast<size_t>(_index) + 8 > colorTable.size());
return colorTable.at(gsl::narrow_cast<size_t>(_index) + 8);
}
else
{
return colorTable.at(_index);
}
return colorTable.at(_index);
}
}

View file

@ -41,9 +41,10 @@ Revision History:
enum class ColorType : BYTE
{
IsIndex = 0x0,
IsDefault = 0x1,
IsRgb = 0x2
IsIndex256 = 0x0,
IsIndex16 = 0x1,
IsDefault = 0x2,
IsRgb = 0x3
};
struct TextColor
@ -57,9 +58,9 @@ public:
{
}
constexpr TextColor(const BYTE wLegacyAttr) noexcept :
_meta{ ColorType::IsIndex },
_index{ wLegacyAttr },
constexpr TextColor(const BYTE index, const bool isIndex256) noexcept :
_meta{ isIndex256 ? ColorType::IsIndex256 : ColorType::IsIndex16 },
_index{ index },
_green{ 0 },
_blue{ 0 }
{
@ -76,23 +77,15 @@ public:
friend constexpr bool operator==(const TextColor& a, const TextColor& b) noexcept;
friend constexpr bool operator!=(const TextColor& a, const TextColor& b) noexcept;
constexpr bool IsLegacy() const noexcept
{
return !(IsDefault() || IsRgb());
}
constexpr bool IsDefault() const noexcept
{
return _meta == ColorType::IsDefault;
}
constexpr bool IsRgb() const noexcept
{
return _meta == ColorType::IsRgb;
}
bool IsLegacy() const noexcept;
bool IsHighColor() const noexcept;
bool IsIndex16() const noexcept;
bool IsIndex256() const noexcept;
bool IsDefault() const noexcept;
bool IsRgb() const noexcept;
void SetColor(const COLORREF rgbColor) noexcept;
void SetIndex(const BYTE index) noexcept;
void SetIndex(const BYTE index, const bool isIndex256) noexcept;
void SetDefault() noexcept;
COLORREF GetColor(std::basic_string_view<COLORREF> colorTable,

View file

@ -81,7 +81,7 @@ void TextColorTests::TestDefaultColor()
void TextColorTests::TestDarkIndexColor()
{
TextColor indexColor((BYTE)(7));
TextColor indexColor((BYTE)(7), false);
VERIFY_IS_FALSE(indexColor.IsDefault());
VERIFY_IS_TRUE(indexColor.IsLegacy());
@ -104,7 +104,7 @@ void TextColorTests::TestDarkIndexColor()
void TextColorTests::TestBrightIndexColor()
{
TextColor indexColor((BYTE)(15));
TextColor indexColor((BYTE)(15), false);
VERIFY_IS_FALSE(indexColor.IsDefault());
VERIFY_IS_TRUE(indexColor.IsLegacy());
@ -186,7 +186,7 @@ void TextColorTests::TestChangeColor()
color = rgbColor.GetColor(view, _defaultBg, true);
VERIFY_ARE_EQUAL(_defaultBg, color);
rgbColor.SetIndex(7);
rgbColor.SetIndex(7, false);
color = rgbColor.GetColor(view, _defaultFg, false);
VERIFY_ARE_EQUAL(_colorTable[7], color);
@ -199,7 +199,7 @@ void TextColorTests::TestChangeColor()
color = rgbColor.GetColor(view, _defaultBg, true);
VERIFY_ARE_EQUAL(_colorTable[15], color);
rgbColor.SetIndex(15);
rgbColor.SetIndex(15, false);
color = rgbColor.GetColor(view, _defaultFg, false);
VERIFY_ARE_EQUAL(_colorTable[15], color);

View file

@ -21,6 +21,8 @@ namespace Microsoft::Terminal::Core
virtual bool SetTextToDefaults(bool foreground, bool background) noexcept = 0;
virtual bool SetTextForegroundIndex(BYTE colorIndex) noexcept = 0;
virtual bool SetTextBackgroundIndex(BYTE colorIndex) noexcept = 0;
virtual bool SetTextForegroundIndex256(BYTE colorIndex) noexcept = 0;
virtual bool SetTextBackgroundIndex256(BYTE colorIndex) noexcept = 0;
virtual bool SetTextRgbColor(COLORREF color, bool foreground) noexcept = 0;
virtual bool BoldText(bool boldOn) noexcept = 0;
virtual bool UnderlineText(bool underlineOn) noexcept = 0;

View file

@ -81,6 +81,8 @@ public:
bool SetTextToDefaults(bool foreground, bool background) noexcept override;
bool SetTextForegroundIndex(BYTE colorIndex) noexcept override;
bool SetTextBackgroundIndex(BYTE colorIndex) noexcept override;
bool SetTextForegroundIndex256(BYTE colorIndex) noexcept override;
bool SetTextBackgroundIndex256(BYTE colorIndex) noexcept override;
bool SetTextRgbColor(COLORREF color, bool foreground) noexcept override;
bool BoldText(bool boldOn) noexcept override;
bool UnderlineText(bool underlineOn) noexcept override;

View file

@ -57,6 +57,22 @@ bool Terminal::SetTextBackgroundIndex(BYTE colorIndex) noexcept
return true;
}
bool Terminal::SetTextForegroundIndex256(BYTE colorIndex) noexcept
{
TextAttribute attrs = _buffer->GetCurrentAttributes();
attrs.SetIndexedForeground256(colorIndex);
_buffer->SetCurrentAttributes(attrs);
return true;
}
bool Terminal::SetTextBackgroundIndex256(BYTE colorIndex) noexcept
{
TextAttribute attrs = _buffer->GetCurrentAttributes();
attrs.SetIndexedBackground256(colorIndex);
_buffer->SetCurrentAttributes(attrs);
return true;
}
bool Terminal::SetTextRgbColor(COLORREF color, bool foreground) noexcept
{
TextAttribute attrs = _buffer->GetCurrentAttributes();

View file

@ -121,8 +121,8 @@ bool TerminalDispatch::_SetRgbColorsHelper(const std::basic_string_view<Dispatch
{
const auto tableIndex = til::at(options, 2);
success = isForeground ?
_terminalApi.SetTextForegroundIndex(gsl::narrow_cast<BYTE>(tableIndex)) :
_terminalApi.SetTextBackgroundIndex(gsl::narrow_cast<BYTE>(tableIndex));
_terminalApi.SetTextForegroundIndex256(gsl::narrow_cast<BYTE>(tableIndex)) :
_terminalApi.SetTextBackgroundIndex256(gsl::narrow_cast<BYTE>(tableIndex));
}
}
}

View file

@ -119,8 +119,7 @@ class TerminalCoreUnitTests::ConptyRoundtripTests final
auto vtRenderEngine = std::make_unique<Xterm256Engine>(std::move(hFile),
gci,
initialViewport,
gci.GetColorTable(),
static_cast<WORD>(gci.GetColorTableSize()));
gci.Get16ColorTable());
auto pfn = std::bind(&ConptyRoundtripTests::_writeCallback, this, std::placeholders::_1, std::placeholders::_2);
vtRenderEngine->SetTestCallback(pfn);

View file

@ -161,31 +161,27 @@ VtIo::VtIo() :
_pVtRenderEngine = std::make_unique<Xterm256Engine>(std::move(_hOutput),
gci,
initialViewport,
gci.GetColorTable(),
static_cast<WORD>(gci.GetColorTableSize()));
gci.Get16ColorTable());
break;
case VtIoMode::XTERM:
_pVtRenderEngine = std::make_unique<XtermEngine>(std::move(_hOutput),
gci,
initialViewport,
gci.GetColorTable(),
static_cast<WORD>(gci.GetColorTableSize()),
gci.Get16ColorTable(),
false);
break;
case VtIoMode::XTERM_ASCII:
_pVtRenderEngine = std::make_unique<XtermEngine>(std::move(_hOutput),
gci,
initialViewport,
gci.GetColorTable(),
static_cast<WORD>(gci.GetColorTableSize()),
gci.Get16ColorTable(),
true);
break;
case VtIoMode::WIN_TELNET:
_pVtRenderEngine = std::make_unique<WinTelnetEngine>(std::move(_hOutput),
gci,
initialViewport,
gci.GetColorTable(),
static_cast<WORD>(gci.GetColorTableSize()));
gci.Get16ColorTable());
break;
default:
return E_FAIL;

View file

@ -81,13 +81,12 @@ static double _FindDifference(const _HSL* const phslColorA, const COLORREF rgbCo
//Arguments:
// - Color - The RGB color to fine the nearest color to.
// - ColorTable - The array of colors to find a nearest color from.
// - cColorTable - The number of elements in ColorTable
// Return value:
// The index in ColorTable of the nearest match to Color.
WORD FindNearestTableIndex(const COLORREF Color, _In_reads_(cColorTable) const COLORREF* const ColorTable, const WORD cColorTable)
WORD FindNearestTableIndex(const COLORREF Color, const std::basic_string_view<COLORREF> ColorTable)
{
// Quick check for an exact match in the color table:
for (WORD i = 0; i < cColorTable; i++)
for (WORD i = 0; i < ColorTable.size(); i++)
{
if (Color == ColorTable[i])
{
@ -100,7 +99,7 @@ WORD FindNearestTableIndex(const COLORREF Color, _In_reads_(cColorTable) const C
const _HSL hslColor = _HSL(Color);
WORD closest = 0;
double minDiff = _FindDifference(&hslColor, ColorTable[0]);
for (WORD i = 1; i < cColorTable; i++)
for (WORD i = 1; i < ColorTable.size(); i++)
{
double diff = _FindDifference(&hslColor, ColorTable[i]);
if (diff < minDiff)
@ -146,36 +145,19 @@ WORD Xterm256ToWindowsIndex(const size_t xtermTableEntry) noexcept
static_cast<WORD>(xtermTableEntry);
}
// Function Description:
// - Converts the value of a pair of xterm color table indices to the legacy attr equivalent.
// Arguments:
// - xtermForeground: the xterm color table foreground index
// - xtermBackground: the xterm color table background index
// Return Value:
// - The legacy windows attribute equivalent.
WORD XtermToLegacy(const size_t xtermForeground, const size_t xtermBackground)
{
const WORD fgAttr = XtermToWindowsIndex(xtermForeground);
const WORD bgAttr = XtermToWindowsIndex(xtermBackground);
return (bgAttr << 4) | fgAttr;
}
//Routine Description:
// Returns the exact entry from the color table, if it's in there.
//Arguments:
// - Color - The RGB color to fine the nearest color to.
// - ColorTable - The array of colors to find a nearest color from.
// - cColorTable - The number of elements in ColorTable
// Return value:
// The index in ColorTable of the nearest match to Color.
bool FindTableIndex(const COLORREF Color,
_In_reads_(cColorTable) const COLORREF* const ColorTable,
const WORD cColorTable,
const std::basic_string_view<COLORREF> ColorTable,
_Out_ WORD* const pFoundIndex)
{
*pFoundIndex = 0;
for (WORD i = 0; i < cColorTable; i++)
for (WORD i = 0; i < ColorTable.size(); i++)
{
if (ColorTable[i] == Color)
{
@ -185,41 +167,3 @@ bool FindTableIndex(const COLORREF Color,
}
return false;
}
// Method Description:
// - Get a COLORREF for the foreground component of the given legacy attributes.
// Arguments:
// - wLegacyAttrs - The legacy attributes to get the foreground color from.
// - ColorTable - The array of colors to get the color from.
// - cColorTable - The number of elements in ColorTable
// Return Value:
// - the COLORREF for the foreground component
COLORREF ForegroundColor(const WORD wLegacyAttrs,
_In_reads_(cColorTable) const COLORREF* const ColorTable,
const size_t cColorTable)
{
const byte iColorTableIndex = LOBYTE(wLegacyAttrs) & FG_ATTRS;
return (iColorTableIndex < cColorTable && iColorTableIndex >= 0) ?
ColorTable[iColorTableIndex] :
INVALID_COLOR;
}
// Method Description:
// - Get a COLORREF for the background component of the given legacy attributes.
// Arguments:
// - wLegacyAttrs - The legacy attributes to get the background color from.
// - ColorTable - The array of colors to get the color from.
// - cColorTable - The number of elements in ColorTable
// Return Value:
// - the COLORREF for the background component
COLORREF BackgroundColor(const WORD wLegacyAttrs,
_In_reads_(cColorTable) const COLORREF* const ColorTable,
const size_t cColorTable)
{
const byte iColorTableIndex = (LOBYTE(wLegacyAttrs) & BG_ATTRS) >> 4;
return (iColorTableIndex < cColorTable && iColorTableIndex >= 0) ?
ColorTable[iColorTableIndex] :
INVALID_COLOR;
}

View file

@ -572,7 +572,10 @@ void ApiRoutines::GetLargestConsoleWindowSizeImpl(const SCREEN_INFORMATION& cont
}
const COORD newBufferSize = context.GetBufferSize().Dimensions();
gci.SetColorTable(data.ColorTable, ARRAYSIZE(data.ColorTable));
for (size_t i = 0; i < std::size(data.ColorTable); i++)
{
gci.SetColorTableEntry(i, data.ColorTable[i]);
}
context.SetDefaultAttributes({ data.wAttributes }, { data.wPopupAttributes });

View file

@ -360,7 +360,10 @@ void SCREEN_INFORMATION::GetScreenBufferInformation(_Out_ PCOORD pcoordSize,
*pwPopupAttributes = gci.GenerateLegacyAttributes(_PopupAttributes);
// the copy length must be constant for now to keep OACR happy with buffer overruns.
memmove(lpColorTable, gci.GetColorTable(), COLOR_TABLE_SIZE * sizeof(COLORREF));
for (size_t i = 0; i < COLOR_TABLE_SIZE; i++)
{
lpColorTable[i] = gci.GetColorTableEntry(i);
}
*pcoordMaximumWindowSize = GetMaxWindowSizeInCharacters();
}

View file

@ -81,9 +81,8 @@ Settings::Settings() :
_CursorColor = Cursor::s_InvertCursorColor;
_CursorType = CursorType::Legacy;
gsl::span<COLORREF> tableView = { _ColorTable, gsl::narrow<ptrdiff_t>(COLOR_TABLE_SIZE) };
gsl::span<COLORREF> xtermTableView = { _XtermColorTable, gsl::narrow<ptrdiff_t>(XTERM_COLOR_TABLE_SIZE) };
::Microsoft::Console::Utils::Initialize256ColorTable(xtermTableView);
gsl::span<COLORREF> tableView = { _colorTable.data(), gsl::narrow<ptrdiff_t>(_colorTable.size()) };
::Microsoft::Console::Utils::Initialize256ColorTable(tableView);
::Microsoft::Console::Utils::InitializeCampbellColorTableForConhost(tableView);
}
@ -123,7 +122,7 @@ void Settings::ApplyDesktopSpecificDefaults()
_uNumberOfHistoryBuffers = 4;
_bHistoryNoDup = FALSE;
gsl::span<COLORREF> tableView = { _ColorTable, gsl::narrow<ptrdiff_t>(COLOR_TABLE_SIZE) };
gsl::span<COLORREF> tableView = { _colorTable.data(), gsl::narrow<ptrdiff_t>(_colorTable.size()) };
::Microsoft::Console::Utils::InitializeCampbellColorTableForConhost(tableView);
_fTrimLeadingZeros = false;
@ -221,7 +220,10 @@ void Settings::InitFromStateInfo(_In_ PCONSOLE_STATE_INFO pStateInfo)
_bHistoryNoDup = pStateInfo->HistoryNoDup;
_uHistoryBufferSize = pStateInfo->HistoryBufferSize;
_uNumberOfHistoryBuffers = pStateInfo->NumberOfHistoryBuffers;
memmove(_ColorTable, pStateInfo->ColorTable, sizeof(_ColorTable));
for (size_t i = 0; i < std::size(pStateInfo->ColorTable); i++)
{
SetColorTableEntry(i, pStateInfo->ColorTable[i]);
}
_uCodePage = pStateInfo->CodePage;
_bWrapText = !!pStateInfo->fWrapText;
_fFilterOnPaste = pStateInfo->fFilterOnPaste;
@ -263,7 +265,10 @@ CONSOLE_STATE_INFO Settings::CreateConsoleStateInfo() const
csi.HistoryNoDup = _bHistoryNoDup;
csi.HistoryBufferSize = _uHistoryBufferSize;
csi.NumberOfHistoryBuffers = _uNumberOfHistoryBuffers;
memmove(csi.ColorTable, _ColorTable, sizeof(_ColorTable));
for (size_t i = 0; i < std::size(csi.ColorTable); i++)
{
csi.ColorTable[i] = GetColorTableEntry(i);
}
csi.CodePage = _uCodePage;
csi.fWrapText = !!_bWrapText;
csi.fFilterOnPaste = _fFilterOnPaste;
@ -717,26 +722,19 @@ void Settings::SetHistoryNoDup(const bool bHistoryNoDup)
_bHistoryNoDup = bHistoryNoDup;
}
const COLORREF* const Settings::GetColorTable() const
std::basic_string_view<COLORREF> Settings::Get16ColorTable() const
{
return _ColorTable;
return Get256ColorTable().substr(0, 16);
}
void Settings::SetColorTable(_In_reads_(cSize) const COLORREF* const pColorTable, const size_t cSize)
{
size_t cSizeWritten = std::min(cSize, static_cast<size_t>(COLOR_TABLE_SIZE));
memmove(_ColorTable, pColorTable, cSizeWritten * sizeof(COLORREF));
std::basic_string_view<COLORREF> Settings::Get256ColorTable() const
{
return { _colorTable.data(), _colorTable.size() };
}
void Settings::SetColorTableEntry(const size_t index, const COLORREF ColorValue)
{
if (index < ARRAYSIZE(_ColorTable))
{
_ColorTable[index] = ColorValue;
}
else
{
_XtermColorTable[index] = ColorValue;
}
_colorTable.at(index) = ColorValue;
}
bool Settings::IsStartupTitleIsLinkNameSet() const
@ -754,21 +752,9 @@ void Settings::UnsetStartupFlag(const DWORD dwFlagToUnset)
_dwStartupFlags &= ~dwFlagToUnset;
}
const size_t Settings::GetColorTableSize() const
{
return ARRAYSIZE(_ColorTable);
}
COLORREF Settings::GetColorTableEntry(const size_t index) const
{
if (index < ARRAYSIZE(_ColorTable))
{
return _ColorTable[index];
}
else
{
return _XtermColorTable[index];
}
return _colorTable.at(index);
}
// Routine Description:
@ -792,19 +778,21 @@ WORD Settings::GenerateLegacyAttributes(const TextAttribute attributes) const
BYTE bgIndex = static_cast<BYTE>((_wFillAttribute & BG_ATTRS) >> 4);
// If the attributes have any RGB components, we need to match that RGB
// color to a color table value.
if (attributes.IsRgb())
if (attributes.IsHighColor())
{
// If the attribute doesn't have a "default" colored *ground, look up
// the nearest color table value for its *ground.
const COLORREF rgbForeground = LookupForegroundColor(attributes);
fgIndex = attributes.ForegroundIsDefault() ?
fgIndex :
static_cast<BYTE>(FindNearestTableIndex(rgbForeground));
if (!attributes.ForegroundIsDefault())
{
const COLORREF rgbForeground = LookupForegroundColor(attributes);
fgIndex = static_cast<BYTE>(::FindNearestTableIndex(rgbForeground, Get16ColorTable()));
}
const COLORREF rgbBackground = LookupBackgroundColor(attributes);
bgIndex = attributes.BackgroundIsDefault() ?
bgIndex :
static_cast<BYTE>(FindNearestTableIndex(rgbBackground));
if (!attributes.BackgroundIsDefault())
{
const COLORREF rgbBackground = LookupBackgroundColor(attributes);
bgIndex = static_cast<BYTE>(::FindNearestTableIndex(rgbBackground, Get16ColorTable()));
}
}
// TextAttribute::GetLegacyAttributes(BYTE, BYTE) will use the legacy value
@ -815,19 +803,6 @@ WORD Settings::GenerateLegacyAttributes(const TextAttribute attributes) const
return wCompleteAttr;
}
//Routine Description:
// For a given RGB color Color, finds the nearest color from the array ColorTable, and returns the index of that match.
//Arguments:
// - Color - The RGB color to fine the nearest color to.
// - ColorTable - The array of colors to find a nearest color from.
// - cColorTable - The number of elements in ColorTable
// Return value:
// The index in ColorTable of the nearest match to Color.
WORD Settings::FindNearestTableIndex(const COLORREF Color) const
{
return ::FindNearestTableIndex(Color, _ColorTable, ARRAYSIZE(_ColorTable));
}
COLORREF Settings::GetCursorColor() const noexcept
{
return _CursorColor;
@ -924,7 +899,7 @@ bool Settings::GetUseDx() const noexcept
COLORREF Settings::CalculateDefaultForeground() const noexcept
{
const auto fg = GetDefaultForegroundColor();
return fg != INVALID_COLOR ? fg : ForegroundColor(GetFillAttribute(), GetColorTable(), GetColorTableSize());
return fg != INVALID_COLOR ? fg : GetColorTableEntry(LOBYTE(_wFillAttribute) & FG_ATTRS);
}
// Method Description:
@ -939,7 +914,7 @@ COLORREF Settings::CalculateDefaultForeground() const noexcept
COLORREF Settings::CalculateDefaultBackground() const noexcept
{
const auto bg = GetDefaultBackgroundColor();
return bg != INVALID_COLOR ? bg : BackgroundColor(GetFillAttribute(), GetColorTable(), GetColorTableSize());
return bg != INVALID_COLOR ? bg : GetColorTableEntry((LOBYTE(_wFillAttribute) & BG_ATTRS) >> 4);
}
// Method Description:
@ -951,7 +926,7 @@ COLORREF Settings::CalculateDefaultBackground() const noexcept
// - The color value of the attribute's foreground TextColor.
COLORREF Settings::LookupForegroundColor(const TextAttribute& attr) const noexcept
{
const auto tableView = std::basic_string_view<COLORREF>(&GetColorTable()[0], GetColorTableSize());
const auto tableView = Get256ColorTable();
if (_fScreenReversed)
{
return attr.CalculateRgbBackground(tableView, CalculateDefaultForeground(), CalculateDefaultBackground());
@ -971,7 +946,7 @@ COLORREF Settings::LookupForegroundColor(const TextAttribute& attr) const noexce
// - The color value of the attribute's background TextColor.
COLORREF Settings::LookupBackgroundColor(const TextAttribute& attr) const noexcept
{
const auto tableView = std::basic_string_view<COLORREF>(&GetColorTable()[0], GetColorTableSize());
const auto tableView = Get256ColorTable();
if (_fScreenReversed)
{
return attr.CalculateRgbForeground(tableView, CalculateDefaultForeground(), CalculateDefaultBackground());

View file

@ -159,9 +159,8 @@ public:
bool GetHistoryNoDup() const;
void SetHistoryNoDup(const bool fHistoryNoDup);
const COLORREF* const GetColorTable() const;
const size_t GetColorTableSize() const;
void SetColorTable(_In_reads_(cSize) const COLORREF* const pColorTable, const size_t cSize);
std::basic_string_view<COLORREF> Get16ColorTable() const;
std::basic_string_view<COLORREF> Get256ColorTable() const;
void SetColorTableEntry(const size_t index, const COLORREF ColorValue);
COLORREF GetColorTableEntry(const size_t index) const;
@ -217,7 +216,6 @@ private:
UINT _uHistoryBufferSize;
UINT _uNumberOfHistoryBuffers;
BOOL _bHistoryNoDup;
COLORREF _ColorTable[COLOR_TABLE_SIZE];
// END - memcpy
UINT _uCodePage;
UINT _uScrollScale;
@ -238,7 +236,7 @@ private:
bool _fUseDx;
bool _fCopyColor;
COLORREF _XtermColorTable[XTERM_COLOR_TABLE_SIZE];
std::array<COLORREF, XTERM_COLOR_TABLE_SIZE> _colorTable;
// this is used for the special STARTF_USESIZE mode.
bool _fUseWindowSizePixels;
@ -257,5 +255,4 @@ private:
public:
WORD GenerateLegacyAttributes(const TextAttribute attributes) const;
WORD FindNearestTableIndex(const COLORREF Color) const;
};

View file

@ -419,7 +419,7 @@ void Telemetry::WriteFinalTraceLog()
TraceLoggingBool(gci.GetQuickEdit(), "QuickEdit"),
TraceLoggingValue(gci.GetWindowAlpha(), "WindowAlpha"),
TraceLoggingBool(gci.GetWrapText(), "WrapText"),
TraceLoggingUInt32Array((UINT32 const*)gci.GetColorTable(), (UINT16)gci.GetColorTableSize(), "ColorTable"),
TraceLoggingUInt32Array((UINT32 const*)gci.Get16ColorTable().data(), (UINT16)gci.Get16ColorTable().size(), "ColorTable"),
TraceLoggingValue(gci.CP, "CodePageInput"),
TraceLoggingValue(gci.OutputCP, "CodePageOutput"),
TraceLoggingValue(gci.GetFontSize().X, "FontSizeX"),
@ -453,7 +453,7 @@ void Telemetry::WriteFinalTraceLog()
TraceLoggingValue(gci.GetShowWindow(), "ShowWindow"),
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
static_assert(sizeof(UINT32) == sizeof(*gci.GetColorTable()), "gci.GetColorTable()");
static_assert(sizeof(UINT32) == sizeof(gci.Get16ColorTable()[0]), "gci.Get16ColorTable()");
// I could use the TraceLoggingUIntArray, but then we would have to know the order of the enums on the backend.
// So just log each enum count separately with its string representation which makes it more human readable.

View file

@ -88,8 +88,7 @@ class ConptyOutputTests
auto vtRenderEngine = std::make_unique<Xterm256Engine>(std::move(hFile),
gci,
initialViewport,
gci.GetColorTable(),
static_cast<WORD>(gci.GetColorTableSize()));
gci.Get16ColorTable());
auto pfn = std::bind(&ConptyOutputTests::_writeCallback, this, std::placeholders::_1, std::placeholders::_2);
vtRenderEngine->SetTestCallback(pfn);

View file

@ -1844,7 +1844,9 @@ void ScreenBufferTests::VtEraseAllPersistCursorFillColor()
L"Change the colors to dark_red on bright_blue, then execute a Erase All.\n"
L"The viewport should be full of dark_red on bright_blue"));
auto expectedAttr = TextAttribute(XtermToLegacy(1, 12));
auto expectedAttr = TextAttribute{};
expectedAttr.SetIndexedForeground((BYTE)XtermToWindowsIndex(1));
expectedAttr.SetIndexedBackground((BYTE)XtermToWindowsIndex(12));
stateMachine.ProcessString(L"\x1b[31;104m");
VERIFY_ARE_EQUAL(expectedAttr, si.GetAttributes());
@ -2222,12 +2224,14 @@ void ScreenBufferTests::SetDefaultsIndividuallyBothDefault()
// See the log comment above for description of these values.
TextAttribute expectedDefaults{};
TextAttribute expectedTwo{ FOREGROUND_GREEN | FOREGROUND_INTENSITY | BACKGROUND_BLUE };
TextAttribute expectedThree{ FOREGROUND_GREEN | FOREGROUND_INTENSITY | BACKGROUND_BLUE };
TextAttribute expectedTwo;
expectedTwo.SetIndexedForeground((BYTE)XtermToWindowsIndex(10));
expectedTwo.SetIndexedBackground((BYTE)XtermToWindowsIndex(4));
TextAttribute expectedThree = expectedTwo;
expectedThree.SetDefaultForeground();
// Four is the same as Defaults
// Five is the same as two
TextAttribute expectedSix{ FOREGROUND_GREEN | FOREGROUND_INTENSITY | BACKGROUND_BLUE };
TextAttribute expectedSix = expectedTwo;
expectedSix.SetDefaultBackground();
COORD expectedCursor{ 6, 0 };
@ -2324,7 +2328,7 @@ void ScreenBufferTests::SetDefaultsTogether()
// See the log comment above for description of these values.
TextAttribute expectedDefaults{};
TextAttribute expectedTwo{};
expectedTwo.SetBackground(color250);
expectedTwo.SetIndexedBackground256(250);
COORD expectedCursor{ 3, 0 };
VERIFY_ARE_EQUAL(expectedCursor, cursor.GetPosition());
@ -4503,14 +4507,14 @@ void ScreenBufferTests::ScrollLines256Colors()
auto& cursor = si.GetTextBuffer().GetCursor();
TextAttribute expectedAttr{ si.GetAttributes() };
std::wstring_view sgrSeq = L"\x1b[48;5;2m";
std::wstring_view sgrSeq = L"\x1b[42m";
if (colorStyle == Use16Color)
{
expectedAttr.SetBackground(gci.GetColorTableEntry(2));
expectedAttr.SetIndexedBackground(2);
}
else if (colorStyle == Use256Color)
{
expectedAttr.SetBackground(gci.GetColorTableEntry(20));
expectedAttr.SetIndexedBackground256(20);
sgrSeq = L"\x1b[48;5;20m";
}
else if (colorStyle == UseRGBColor)
@ -5237,7 +5241,7 @@ void ScreenBufferTests::TestExtendedTextAttributesWithColors()
}
else if (setForegroundType == Use256Color)
{
expectedAttr.SetForeground(gci.GetColorTableEntry(20));
expectedAttr.SetIndexedForeground256(20);
vtSeq += L"\x1b[38;5;20m";
}
else if (setForegroundType == UseRGBColor)
@ -5259,7 +5263,7 @@ void ScreenBufferTests::TestExtendedTextAttributesWithColors()
}
else if (setBackgroundType == Use256Color)
{
expectedAttr.SetBackground(gci.GetColorTableEntry(20));
expectedAttr.SetIndexedBackground256(20);
vtSeq += L"\x1b[48;5;20m";
}
else if (setBackgroundType == UseRGBColor)

View file

@ -498,7 +498,7 @@ void TextBufferIteratorTests::DereferenceOperatorCell()
const auto textExpected = (std::wstring_view)row.GetCharRow().GlyphAt(it._pos.X);
const auto dbcsExpected = row.GetCharRow().DbcsAttrAt(it._pos.X);
const auto attrExpected = row.GetAttrRow().GetAttrByColumn(it._pos.X).GetLegacyAttributes();
const auto attrExpected = row.GetAttrRow().GetAttrByColumn(it._pos.X);
const auto cellActual = *it;
const auto textActual = cellActual.Chars();

View file

@ -124,28 +124,28 @@ void VtIoTests::DtorTestJustEngine()
wil::unique_hfile hOutputFile;
hOutputFile.reset(INVALID_HANDLE_VALUE);
auto pRenderer256 = new Xterm256Engine(std::move(hOutputFile), p, SetUpViewport(), colorTable, colorTableSize);
auto pRenderer256 = new Xterm256Engine(std::move(hOutputFile), p, SetUpViewport(), colorTable);
Log::Comment(NoThrowString().Format(L"Made Xterm256Engine"));
delete pRenderer256;
Log::Comment(NoThrowString().Format(L"Deleted."));
hOutputFile.reset(INVALID_HANDLE_VALUE);
auto pRenderEngineXterm = new XtermEngine(std::move(hOutputFile), p, SetUpViewport(), colorTable, colorTableSize, false);
auto pRenderEngineXterm = new XtermEngine(std::move(hOutputFile), p, SetUpViewport(), colorTable, false);
Log::Comment(NoThrowString().Format(L"Made XtermEngine"));
delete pRenderEngineXterm;
Log::Comment(NoThrowString().Format(L"Deleted."));
hOutputFile.reset(INVALID_HANDLE_VALUE);
auto pRenderEngineXtermAscii = new XtermEngine(std::move(hOutputFile), p, SetUpViewport(), colorTable, colorTableSize, true);
auto pRenderEngineXtermAscii = new XtermEngine(std::move(hOutputFile), p, SetUpViewport(), colorTable, true);
Log::Comment(NoThrowString().Format(L"Made XtermEngine"));
delete pRenderEngineXtermAscii;
Log::Comment(NoThrowString().Format(L"Deleted."));
hOutputFile.reset(INVALID_HANDLE_VALUE);
auto pRenderEngineWinTelnet = new WinTelnetEngine(std::move(hOutputFile), p, SetUpViewport(), colorTable, colorTableSize);
auto pRenderEngineWinTelnet = new WinTelnetEngine(std::move(hOutputFile), p, SetUpViewport(), colorTable);
Log::Comment(NoThrowString().Format(L"Made WinTelnetEngine"));
delete pRenderEngineWinTelnet;
Log::Comment(NoThrowString().Format(L"Deleted."));
@ -180,8 +180,7 @@ void VtIoTests::DtorTestDeleteVtio()
vtio->_pVtRenderEngine = std::make_unique<Xterm256Engine>(std::move(hOutputFile),
p,
SetUpViewport(),
colorTable,
colorTableSize);
colorTable);
Log::Comment(NoThrowString().Format(L"Made Xterm256Engine"));
delete vtio;
Log::Comment(NoThrowString().Format(L"Deleted."));
@ -193,7 +192,6 @@ void VtIoTests::DtorTestDeleteVtio()
p,
SetUpViewport(),
colorTable,
colorTableSize,
false);
Log::Comment(NoThrowString().Format(L"Made XtermEngine"));
delete vtio;
@ -206,7 +204,6 @@ void VtIoTests::DtorTestDeleteVtio()
p,
SetUpViewport(),
colorTable,
colorTableSize,
true);
Log::Comment(NoThrowString().Format(L"Made XtermEngine"));
delete vtio;
@ -218,8 +215,7 @@ void VtIoTests::DtorTestDeleteVtio()
vtio->_pVtRenderEngine = std::make_unique<WinTelnetEngine>(std::move(hOutputFile),
p,
SetUpViewport(),
colorTable,
colorTableSize);
colorTable);
Log::Comment(NoThrowString().Format(L"Made WinTelnetEngine"));
delete vtio;
Log::Comment(NoThrowString().Format(L"Deleted."));
@ -253,8 +249,7 @@ void VtIoTests::DtorTestStackAlloc()
vtio._pVtRenderEngine = std::make_unique<Xterm256Engine>(std::move(hOutputFile),
p,
SetUpViewport(),
colorTable,
colorTableSize);
colorTable);
}
hOutputFile.reset(INVALID_HANDLE_VALUE);
@ -264,7 +259,6 @@ void VtIoTests::DtorTestStackAlloc()
p,
SetUpViewport(),
colorTable,
colorTableSize,
false);
}
@ -275,7 +269,6 @@ void VtIoTests::DtorTestStackAlloc()
p,
SetUpViewport(),
colorTable,
colorTableSize,
true);
}
@ -285,8 +278,7 @@ void VtIoTests::DtorTestStackAlloc()
vtio._pVtRenderEngine = std::make_unique<WinTelnetEngine>(std::move(hOutputFile),
p,
SetUpViewport(),
colorTable,
colorTableSize);
colorTable);
}
}
}
@ -317,8 +309,7 @@ void VtIoTests::DtorTestStackAllocMany()
vtio1._pVtRenderEngine = std::make_unique<Xterm256Engine>(std::move(hOutputFile),
p,
SetUpViewport(),
colorTable,
colorTableSize);
colorTable);
hOutputFile.reset(INVALID_HANDLE_VALUE);
VtIo vtio2;
@ -326,7 +317,6 @@ void VtIoTests::DtorTestStackAllocMany()
p,
SetUpViewport(),
colorTable,
colorTableSize,
false);
hOutputFile.reset(INVALID_HANDLE_VALUE);
@ -335,7 +325,6 @@ void VtIoTests::DtorTestStackAllocMany()
p,
SetUpViewport(),
colorTable,
colorTableSize,
true);
hOutputFile.reset(INVALID_HANDLE_VALUE);
@ -343,8 +332,7 @@ void VtIoTests::DtorTestStackAllocMany()
vtio4._pVtRenderEngine = std::make_unique<WinTelnetEngine>(std::move(hOutputFile),
p,
SetUpViewport(),
colorTable,
colorTableSize);
colorTable);
}
}
}

View file

@ -189,7 +189,7 @@ void VtRendererTest::TestPaint(VtEngine& engine, std::function<void()> pfn)
void VtRendererTest::VtSequenceHelperTests()
{
wil::unique_hfile hFile = wil::unique_hfile(INVALID_HANDLE_VALUE);
std::unique_ptr<Xterm256Engine> engine = std::make_unique<Xterm256Engine>(std::move(hFile), p, SetUpViewport(), g_ColorTable, static_cast<WORD>(COLOR_TABLE_SIZE));
std::unique_ptr<Xterm256Engine> engine = std::make_unique<Xterm256Engine>(std::move(hFile), p, SetUpViewport(), g_ColorTable);
auto pfn = std::bind(&VtRendererTest::WriteCallback, this, std::placeholders::_1, std::placeholders::_2);
engine->SetTestCallback(pfn);
@ -246,7 +246,7 @@ void VtRendererTest::VtSequenceHelperTests()
void VtRendererTest::Xterm256TestInvalidate()
{
wil::unique_hfile hFile = wil::unique_hfile(INVALID_HANDLE_VALUE);
std::unique_ptr<Xterm256Engine> engine = std::make_unique<Xterm256Engine>(std::move(hFile), p, SetUpViewport(), g_ColorTable, static_cast<WORD>(COLOR_TABLE_SIZE));
std::unique_ptr<Xterm256Engine> engine = std::make_unique<Xterm256Engine>(std::move(hFile), p, SetUpViewport(), g_ColorTable);
auto pfn = std::bind(&VtRendererTest::WriteCallback, this, std::placeholders::_1, std::placeholders::_2);
engine->SetTestCallback(pfn);
@ -434,7 +434,7 @@ void VtRendererTest::Xterm256TestInvalidate()
void VtRendererTest::Xterm256TestColors()
{
wil::unique_hfile hFile = wil::unique_hfile(INVALID_HANDLE_VALUE);
std::unique_ptr<Xterm256Engine> engine = std::make_unique<Xterm256Engine>(std::move(hFile), p, SetUpViewport(), g_ColorTable, static_cast<WORD>(COLOR_TABLE_SIZE));
std::unique_ptr<Xterm256Engine> engine = std::make_unique<Xterm256Engine>(std::move(hFile), p, SetUpViewport(), g_ColorTable);
auto pfn = std::bind(&VtRendererTest::WriteCallback, this, std::placeholders::_1, std::placeholders::_2);
engine->SetTestCallback(pfn);
@ -571,7 +571,7 @@ void VtRendererTest::Xterm256TestColors()
void VtRendererTest::Xterm256TestCursor()
{
wil::unique_hfile hFile = wil::unique_hfile(INVALID_HANDLE_VALUE);
std::unique_ptr<Xterm256Engine> engine = std::make_unique<Xterm256Engine>(std::move(hFile), p, SetUpViewport(), g_ColorTable, static_cast<WORD>(COLOR_TABLE_SIZE));
std::unique_ptr<Xterm256Engine> engine = std::make_unique<Xterm256Engine>(std::move(hFile), p, SetUpViewport(), g_ColorTable);
auto pfn = std::bind(&VtRendererTest::WriteCallback, this, std::placeholders::_1, std::placeholders::_2);
engine->SetTestCallback(pfn);
@ -723,7 +723,7 @@ void VtRendererTest::Xterm256TestExtendedAttributes()
}
wil::unique_hfile hFile = wil::unique_hfile(INVALID_HANDLE_VALUE);
std::unique_ptr<Xterm256Engine> engine = std::make_unique<Xterm256Engine>(std::move(hFile), p, SetUpViewport(), g_ColorTable, static_cast<WORD>(COLOR_TABLE_SIZE));
std::unique_ptr<Xterm256Engine> engine = std::make_unique<Xterm256Engine>(std::move(hFile), p, SetUpViewport(), g_ColorTable);
auto pfn = std::bind(&VtRendererTest::WriteCallback, this, std::placeholders::_1, std::placeholders::_2);
engine->SetTestCallback(pfn);
@ -767,7 +767,7 @@ void VtRendererTest::Xterm256TestExtendedAttributes()
void VtRendererTest::XtermTestInvalidate()
{
wil::unique_hfile hFile = wil::unique_hfile(INVALID_HANDLE_VALUE);
std::unique_ptr<XtermEngine> engine = std::make_unique<XtermEngine>(std::move(hFile), p, SetUpViewport(), g_ColorTable, static_cast<WORD>(COLOR_TABLE_SIZE), false);
std::unique_ptr<XtermEngine> engine = std::make_unique<XtermEngine>(std::move(hFile), p, SetUpViewport(), g_ColorTable, false);
auto pfn = std::bind(&VtRendererTest::WriteCallback, this, std::placeholders::_1, std::placeholders::_2);
engine->SetTestCallback(pfn);
@ -954,7 +954,7 @@ void VtRendererTest::XtermTestInvalidate()
void VtRendererTest::XtermTestColors()
{
wil::unique_hfile hFile = wil::unique_hfile(INVALID_HANDLE_VALUE);
std::unique_ptr<XtermEngine> engine = std::make_unique<XtermEngine>(std::move(hFile), p, SetUpViewport(), g_ColorTable, static_cast<WORD>(COLOR_TABLE_SIZE), false);
std::unique_ptr<XtermEngine> engine = std::make_unique<XtermEngine>(std::move(hFile), p, SetUpViewport(), g_ColorTable, false);
auto pfn = std::bind(&VtRendererTest::WriteCallback, this, std::placeholders::_1, std::placeholders::_2);
engine->SetTestCallback(pfn);
@ -1040,7 +1040,7 @@ void VtRendererTest::XtermTestColors()
void VtRendererTest::XtermTestCursor()
{
wil::unique_hfile hFile = wil::unique_hfile(INVALID_HANDLE_VALUE);
std::unique_ptr<XtermEngine> engine = std::make_unique<XtermEngine>(std::move(hFile), p, SetUpViewport(), g_ColorTable, static_cast<WORD>(COLOR_TABLE_SIZE), false);
std::unique_ptr<XtermEngine> engine = std::make_unique<XtermEngine>(std::move(hFile), p, SetUpViewport(), g_ColorTable, false);
auto pfn = std::bind(&VtRendererTest::WriteCallback, this, std::placeholders::_1, std::placeholders::_2);
engine->SetTestCallback(pfn);
@ -1149,7 +1149,7 @@ void VtRendererTest::XtermTestCursor()
void VtRendererTest::WinTelnetTestInvalidate()
{
wil::unique_hfile hFile = wil::unique_hfile(INVALID_HANDLE_VALUE);
std::unique_ptr<WinTelnetEngine> engine = std::make_unique<WinTelnetEngine>(std::move(hFile), p, SetUpViewport(), g_ColorTable, static_cast<WORD>(COLOR_TABLE_SIZE));
std::unique_ptr<WinTelnetEngine> engine = std::make_unique<WinTelnetEngine>(std::move(hFile), p, SetUpViewport(), g_ColorTable);
auto pfn = std::bind(&VtRendererTest::WriteCallback, this, std::placeholders::_1, std::placeholders::_2);
engine->SetTestCallback(pfn);
@ -1221,7 +1221,7 @@ void VtRendererTest::WinTelnetTestInvalidate()
void VtRendererTest::WinTelnetTestColors()
{
wil::unique_hfile hFile = wil::unique_hfile(INVALID_HANDLE_VALUE);
std::unique_ptr<WinTelnetEngine> engine = std::make_unique<WinTelnetEngine>(std::move(hFile), p, SetUpViewport(), g_ColorTable, static_cast<WORD>(COLOR_TABLE_SIZE));
std::unique_ptr<WinTelnetEngine> engine = std::make_unique<WinTelnetEngine>(std::move(hFile), p, SetUpViewport(), g_ColorTable);
auto pfn = std::bind(&VtRendererTest::WriteCallback, this, std::placeholders::_1, std::placeholders::_2);
engine->SetTestCallback(pfn);
@ -1299,7 +1299,7 @@ void VtRendererTest::WinTelnetTestColors()
void VtRendererTest::WinTelnetTestCursor()
{
wil::unique_hfile hFile = wil::unique_hfile(INVALID_HANDLE_VALUE);
std::unique_ptr<WinTelnetEngine> engine = std::make_unique<WinTelnetEngine>(std::move(hFile), p, SetUpViewport(), g_ColorTable, static_cast<WORD>(COLOR_TABLE_SIZE));
std::unique_ptr<WinTelnetEngine> engine = std::make_unique<WinTelnetEngine>(std::move(hFile), p, SetUpViewport(), g_ColorTable);
auto pfn = std::bind(&VtRendererTest::WriteCallback, this, std::placeholders::_1, std::placeholders::_2);
engine->SetTestCallback(pfn);
@ -1379,7 +1379,7 @@ void VtRendererTest::WinTelnetTestCursor()
void VtRendererTest::TestWrapping()
{
wil::unique_hfile hFile = wil::unique_hfile(INVALID_HANDLE_VALUE);
std::unique_ptr<Xterm256Engine> engine = std::make_unique<Xterm256Engine>(std::move(hFile), p, SetUpViewport(), g_ColorTable, static_cast<WORD>(COLOR_TABLE_SIZE));
std::unique_ptr<Xterm256Engine> engine = std::make_unique<Xterm256Engine>(std::move(hFile), p, SetUpViewport(), g_ColorTable);
auto pfn = std::bind(&VtRendererTest::WriteCallback, this, std::placeholders::_1, std::placeholders::_2);
engine->SetTestCallback(pfn);
@ -1432,7 +1432,7 @@ void VtRendererTest::TestResize()
{
Viewport view = SetUpViewport();
wil::unique_hfile hFile = wil::unique_hfile(INVALID_HANDLE_VALUE);
auto engine = std::make_unique<Xterm256Engine>(std::move(hFile), p, view, g_ColorTable, static_cast<WORD>(COLOR_TABLE_SIZE));
auto engine = std::make_unique<Xterm256Engine>(std::move(hFile), p, view, g_ColorTable);
auto pfn = std::bind(&VtRendererTest::WriteCallback, this, std::placeholders::_1, std::placeholders::_2);
engine->SetTestCallback(pfn);
@ -1469,7 +1469,7 @@ void VtRendererTest::TestCursorVisibility()
{
Viewport view = SetUpViewport();
wil::unique_hfile hFile = wil::unique_hfile(INVALID_HANDLE_VALUE);
auto engine = std::make_unique<Xterm256Engine>(std::move(hFile), p, view, g_ColorTable, static_cast<WORD>(COLOR_TABLE_SIZE));
auto engine = std::make_unique<Xterm256Engine>(std::move(hFile), p, view, g_ColorTable);
auto pfn = std::bind(&VtRendererTest::WriteCallback, this, std::placeholders::_1, std::placeholders::_2);
engine->SetTestCallback(pfn);
@ -1594,7 +1594,7 @@ void VtRendererTest::FormattedString()
Viewport view = SetUpViewport();
wil::unique_hfile hFile = wil::unique_hfile(INVALID_HANDLE_VALUE);
auto engine = std::make_unique<Xterm256Engine>(std::move(hFile), p, view, g_ColorTable, static_cast<WORD>(COLOR_TABLE_SIZE));
auto engine = std::make_unique<Xterm256Engine>(std::move(hFile), p, view, g_ColorTable);
auto pfn = std::bind(&VtRendererTest::WriteCallback, this, std::placeholders::_1, std::placeholders::_2);
engine->SetTestCallback(pfn);

View file

@ -24,26 +24,16 @@ enum class ExtendedAttributes : BYTE
DEFINE_ENUM_FLAG_OPERATORS(ExtendedAttributes);
WORD FindNearestTableIndex(const COLORREF Color,
_In_reads_(cColorTable) const COLORREF* const ColorTable,
const WORD cColorTable);
const std::basic_string_view<COLORREF> ColorTable);
bool FindTableIndex(const COLORREF Color,
_In_reads_(cColorTable) const COLORREF* const ColorTable,
const WORD cColorTable,
const std::basic_string_view<COLORREF> ColorTable,
_Out_ WORD* const pFoundIndex);
WORD XtermToWindowsIndex(const size_t index) noexcept;
WORD Xterm256ToWindowsIndex(const size_t index) noexcept;
WORD XtermToLegacy(const size_t xtermForeground, const size_t xtermBackground);
COLORREF ForegroundColor(const WORD wLegacyAttrs,
_In_reads_(cColorTable) const COLORREF* const ColorTable,
const size_t cColorTable);
COLORREF BackgroundColor(const WORD wLegacyAttrs,
_In_reads_(cColorTable) const COLORREF* const ColorTable,
const size_t cColorTable);
const WORD WINDOWS_RED_ATTR = FOREGROUND_RED;
const WORD WINDOWS_GREEN_ATTR = FOREGROUND_GREEN;
const WORD WINDOWS_BLUE_ATTR = FOREGROUND_BLUE;

View file

@ -335,7 +335,10 @@ void Menu::s_ShowPropertiesDialog(HWND const hwnd, BOOL const Defaults)
pStateInfo->NumberOfHistoryBuffers = gci.GetNumberOfHistoryBuffers();
pStateInfo->HistoryNoDup = !!(gci.Flags & CONSOLE_HISTORY_NODUP);
memmove(pStateInfo->ColorTable, gci.GetColorTable(), gci.GetColorTableSize() * sizeof(COLORREF));
for (size_t i = 0; i < std::size(pStateInfo->ColorTable); i++)
{
pStateInfo->ColorTable[i] = gci.GetColorTableEntry(i);
}
// Create mutable copies of the titles so the propsheet can do something with them.
if (gci.GetOriginalTitle().length() > 0)
@ -562,7 +565,10 @@ void Menu::s_PropertiesUpdate(PCONSOLE_STATE_INFO pStateInfo)
}
}
gci.SetColorTable(pStateInfo->ColorTable, gci.GetColorTableSize());
for (size_t i = 0; i < std::size(pStateInfo->ColorTable); i++)
{
gci.SetColorTableEntry(i, pStateInfo->ColorTable[i]);
}
// Ensure that attributes only contain color specification.
WI_ClearAllFlags(pStateInfo->ScreenAttributes, ~(FG_ATTRS | BG_ATTRS));

View file

@ -12,11 +12,9 @@ using namespace Microsoft::Console::Types;
WinTelnetEngine::WinTelnetEngine(_In_ wil::unique_hfile hPipe,
const IDefaultColorProvider& colorProvider,
const Viewport initialViewport,
_In_reads_(cColorTable) const COLORREF* const ColorTable,
const WORD cColorTable) :
const std::basic_string_view<COLORREF> colorTable) :
VtEngine(std::move(hPipe), colorProvider, initialViewport),
_ColorTable(ColorTable),
_cColorTable(cColorTable)
_colorTable(colorTable)
{
}
@ -42,8 +40,7 @@ WinTelnetEngine::WinTelnetEngine(_In_ wil::unique_hfile hPipe,
return VtEngine::_16ColorUpdateDrawingBrushes(colorForeground,
colorBackground,
WI_IsFlagSet(extendedAttrs, ExtendedAttributes::Bold),
_ColorTable,
_cColorTable);
_colorTable);
}
// Routine Description:

View file

@ -26,8 +26,7 @@ namespace Microsoft::Console::Render
WinTelnetEngine(_In_ wil::unique_hfile hPipe,
const Microsoft::Console::IDefaultColorProvider& colorProvider,
const Microsoft::Console::Types::Viewport initialViewport,
_In_reads_(cColorTable) const COLORREF* const ColorTable,
const WORD cColorTable);
const std::basic_string_view<COLORREF> colorTable);
virtual ~WinTelnetEngine() override = default;
[[nodiscard]] HRESULT UpdateDrawingBrushes(const COLORREF colorForeground,
@ -45,8 +44,7 @@ namespace Microsoft::Console::Render
[[nodiscard]] HRESULT _MoveCursor(const COORD coord) noexcept;
private:
const COLORREF* const _ColorTable;
const WORD _cColorTable;
const std::basic_string_view<COLORREF> _colorTable;
#ifdef UNIT_TESTING
friend class VtRendererTest;

View file

@ -11,9 +11,8 @@ using namespace Microsoft::Console::Types;
Xterm256Engine::Xterm256Engine(_In_ wil::unique_hfile hPipe,
const IDefaultColorProvider& colorProvider,
const Viewport initialViewport,
_In_reads_(cColorTable) const COLORREF* const ColorTable,
const WORD cColorTable) :
XtermEngine(std::move(hPipe), colorProvider, initialViewport, ColorTable, cColorTable, false),
const std::basic_string_view<COLORREF> colorTable) :
XtermEngine(std::move(hPipe), colorProvider, initialViewport, colorTable, false),
_lastExtendedAttrsState{ ExtendedAttributes::Normal }
{
}
@ -52,8 +51,7 @@ Xterm256Engine::Xterm256Engine(_In_ wil::unique_hfile hPipe,
return VtEngine::_RgbUpdateDrawingBrushes(colorForeground,
colorBackground,
WI_IsFlagSet(extendedAttrs, ExtendedAttributes::Bold),
_ColorTable,
_cColorTable);
_colorTable);
}
// Routine Description:

View file

@ -26,8 +26,7 @@ namespace Microsoft::Console::Render
Xterm256Engine(_In_ wil::unique_hfile hPipe,
const Microsoft::Console::IDefaultColorProvider& colorProvider,
const Microsoft::Console::Types::Viewport initialViewport,
_In_reads_(cColorTable) const COLORREF* const ColorTable,
const WORD cColorTable);
const std::basic_string_view<COLORREF> colorTable);
virtual ~Xterm256Engine() override = default;

View file

@ -12,12 +12,10 @@ using namespace Microsoft::Console::Types;
XtermEngine::XtermEngine(_In_ wil::unique_hfile hPipe,
const IDefaultColorProvider& colorProvider,
const Viewport initialViewport,
_In_reads_(cColorTable) const COLORREF* const ColorTable,
const WORD cColorTable,
const std::basic_string_view<COLORREF> colorTable,
const bool fUseAsciiOnly) :
VtEngine(std::move(hPipe), colorProvider, initialViewport),
_ColorTable(ColorTable),
_cColorTable(cColorTable),
_colorTable(colorTable),
_fUseAsciiOnly(fUseAsciiOnly),
_usingUnderLine(false),
_needToDisableCursor(false),
@ -192,8 +190,7 @@ XtermEngine::XtermEngine(_In_ wil::unique_hfile hPipe,
return VtEngine::_16ColorUpdateDrawingBrushes(colorForeground,
colorBackground,
WI_IsFlagSet(extendedAttrs, ExtendedAttributes::Bold),
_ColorTable,
_cColorTable);
_colorTable);
}
// Routine Description:

View file

@ -30,8 +30,7 @@ namespace Microsoft::Console::Render
XtermEngine(_In_ wil::unique_hfile hPipe,
const Microsoft::Console::IDefaultColorProvider& colorProvider,
const Microsoft::Console::Types::Viewport initialViewport,
_In_reads_(cColorTable) const COLORREF* const ColorTable,
const WORD cColorTable,
const std::basic_string_view<COLORREF> colorTable,
const bool fUseAsciiOnly);
virtual ~XtermEngine() override = default;
@ -57,8 +56,7 @@ namespace Microsoft::Console::Render
[[nodiscard]] HRESULT WriteTerminalW(const std::wstring_view str) noexcept override;
protected:
const COLORREF* const _ColorTable;
const WORD _cColorTable;
const std::basic_string_view<COLORREF> _colorTable;
const bool _fUseAsciiOnly;
bool _usingUnderLine;
bool _needToDisableCursor;

View file

@ -192,8 +192,7 @@ using namespace Microsoft::Console::Types;
[[nodiscard]] HRESULT VtEngine::_RgbUpdateDrawingBrushes(const COLORREF colorForeground,
const COLORREF colorBackground,
const bool isBold,
_In_reads_(cColorTable) const COLORREF* const ColorTable,
const WORD cColorTable) noexcept
const std::basic_string_view<COLORREF> colorTable) noexcept
{
const bool fgChanged = colorForeground != _LastFG;
const bool bgChanged = colorBackground != _LastBG;
@ -232,7 +231,7 @@ using namespace Microsoft::Console::Types;
{
RETURN_IF_FAILED(_SetGraphicsRenditionDefaultColor(true));
}
else if (::FindTableIndex(colorForeground, ColorTable, cColorTable, &wFoundColor))
else if (::FindTableIndex(colorForeground, colorTable, &wFoundColor))
{
RETURN_IF_FAILED(_SetGraphicsRendition16Color(wFoundColor, true));
}
@ -249,7 +248,7 @@ using namespace Microsoft::Console::Types;
{
RETURN_IF_FAILED(_SetGraphicsRenditionDefaultColor(false));
}
else if (::FindTableIndex(colorBackground, ColorTable, cColorTable, &wFoundColor))
else if (::FindTableIndex(colorBackground, colorTable, &wFoundColor))
{
RETURN_IF_FAILED(_SetGraphicsRendition16Color(wFoundColor, false));
}
@ -278,8 +277,7 @@ using namespace Microsoft::Console::Types;
[[nodiscard]] HRESULT VtEngine::_16ColorUpdateDrawingBrushes(const COLORREF colorForeground,
const COLORREF colorBackground,
const bool isBold,
_In_reads_(cColorTable) const COLORREF* const ColorTable,
const WORD cColorTable) noexcept
const std::basic_string_view<COLORREF> colorTable) noexcept
{
const bool fgChanged = colorForeground != _LastFG;
const bool bgChanged = colorBackground != _LastBG;
@ -312,7 +310,7 @@ using namespace Microsoft::Console::Types;
if (fgChanged)
{
const WORD wNearestFg = ::FindNearestTableIndex(colorForeground, ColorTable, cColorTable);
const WORD wNearestFg = ::FindNearestTableIndex(colorForeground, colorTable);
RETURN_IF_FAILED(_SetGraphicsRendition16Color(wNearestFg, true));
_LastFG = colorForeground;
@ -320,7 +318,7 @@ using namespace Microsoft::Console::Types;
if (bgChanged)
{
const WORD wNearestBg = ::FindNearestTableIndex(colorBackground, ColorTable, cColorTable);
const WORD wNearestBg = ::FindNearestTableIndex(colorBackground, colorTable);
RETURN_IF_FAILED(_SetGraphicsRendition16Color(wNearestBg, false));
_LastBG = colorBackground;

View file

@ -212,13 +212,11 @@ namespace Microsoft::Console::Render
[[nodiscard]] HRESULT _RgbUpdateDrawingBrushes(const COLORREF colorForeground,
const COLORREF colorBackground,
const bool isBold,
_In_reads_(cColorTable) const COLORREF* const ColorTable,
const WORD cColorTable) noexcept;
const std::basic_string_view<COLORREF> colorTable) noexcept;
[[nodiscard]] HRESULT _16ColorUpdateDrawingBrushes(const COLORREF colorForeground,
const COLORREF colorBackground,
const bool isBold,
_In_reads_(cColorTable) const COLORREF* const ColorTable,
const WORD cColorTable) noexcept;
const std::basic_string_view<COLORREF> colorTable) noexcept;
bool _WillWriteSingleChar() const;

View file

@ -178,6 +178,6 @@ namespace Microsoft::Console::VirtualTerminal
size_t _SetRgbColorsHelper(const std::basic_string_view<DispatchTypes::GraphicsOptions> options,
TextAttribute& attr,
const bool isForeground);
const bool isForeground) noexcept;
};
}

View file

@ -49,7 +49,7 @@ const BYTE BRIGHT_WHITE = BRIGHT_ATTR | RED_ATTR | GREEN_ATTR | BLUE_ATTR;
// - The number of options consumed, not including the initial 38/48.
size_t AdaptDispatch::_SetRgbColorsHelper(const std::basic_string_view<DispatchTypes::GraphicsOptions> options,
TextAttribute& attr,
const bool isForeground)
const bool isForeground) noexcept
{
size_t optionsConsumed = 0;
if (options.size() >= 1)
@ -73,11 +73,17 @@ size_t AdaptDispatch::_SetRgbColorsHelper(const std::basic_string_view<DispatchT
{
optionsConsumed = 2;
const size_t tableIndex = til::at(options, 1);
COLORREF rgbColor;
if (_pConApi->PrivateGetColorTableEntry(tableIndex, rgbColor))
if (tableIndex <= 255)
{
// TODO GH#1223: Decouple xterm-256color indexed storage from RGB storage
attr.SetColor(rgbColor, isForeground);
const auto adjustedIndex = gsl::narrow_cast<BYTE>(::Xterm256ToWindowsIndex(tableIndex));
if (isForeground)
{
attr.SetIndexedForeground256(adjustedIndex);
}
else
{
attr.SetIndexedBackground256(adjustedIndex);
}
}
}
}

View file

@ -1286,42 +1286,50 @@ public:
case DispatchTypes::GraphicsOptions::ForegroundBlack:
Log::Comment(L"Testing graphics 'Foreground Color Black'");
_testGetSet->_attribute = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY;
_testGetSet->_expectedAttribute = 0;
_testGetSet->_expectedAttribute = _testGetSet->_attribute;
_testGetSet->_expectedAttribute.SetIndexedForeground(0);
break;
case DispatchTypes::GraphicsOptions::ForegroundBlue:
Log::Comment(L"Testing graphics 'Foreground Color Blue'");
_testGetSet->_attribute = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY;
_testGetSet->_expectedAttribute = FOREGROUND_BLUE;
_testGetSet->_expectedAttribute = _testGetSet->_attribute;
_testGetSet->_expectedAttribute.SetIndexedForeground(FOREGROUND_BLUE);
break;
case DispatchTypes::GraphicsOptions::ForegroundGreen:
Log::Comment(L"Testing graphics 'Foreground Color Green'");
_testGetSet->_attribute = FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY;
_testGetSet->_expectedAttribute = FOREGROUND_GREEN;
_testGetSet->_expectedAttribute = _testGetSet->_attribute;
_testGetSet->_expectedAttribute.SetIndexedForeground(FOREGROUND_GREEN);
break;
case DispatchTypes::GraphicsOptions::ForegroundCyan:
Log::Comment(L"Testing graphics 'Foreground Color Cyan'");
_testGetSet->_attribute = FOREGROUND_RED | FOREGROUND_INTENSITY;
_testGetSet->_expectedAttribute = FOREGROUND_BLUE | FOREGROUND_GREEN;
_testGetSet->_expectedAttribute = _testGetSet->_attribute;
_testGetSet->_expectedAttribute.SetIndexedForeground(FOREGROUND_BLUE | FOREGROUND_GREEN);
break;
case DispatchTypes::GraphicsOptions::ForegroundRed:
Log::Comment(L"Testing graphics 'Foreground Color Red'");
_testGetSet->_attribute = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_INTENSITY;
_testGetSet->_expectedAttribute = FOREGROUND_RED;
_testGetSet->_expectedAttribute = _testGetSet->_attribute;
_testGetSet->_expectedAttribute.SetIndexedForeground(FOREGROUND_RED);
break;
case DispatchTypes::GraphicsOptions::ForegroundMagenta:
Log::Comment(L"Testing graphics 'Foreground Color Magenta'");
_testGetSet->_attribute = FOREGROUND_GREEN | FOREGROUND_INTENSITY;
_testGetSet->_expectedAttribute = FOREGROUND_BLUE | FOREGROUND_RED;
_testGetSet->_expectedAttribute = _testGetSet->_attribute;
_testGetSet->_expectedAttribute.SetIndexedForeground(FOREGROUND_BLUE | FOREGROUND_RED);
break;
case DispatchTypes::GraphicsOptions::ForegroundYellow:
Log::Comment(L"Testing graphics 'Foreground Color Yellow'");
_testGetSet->_attribute = FOREGROUND_BLUE | FOREGROUND_INTENSITY;
_testGetSet->_expectedAttribute = FOREGROUND_GREEN | FOREGROUND_RED;
_testGetSet->_expectedAttribute = _testGetSet->_attribute;
_testGetSet->_expectedAttribute.SetIndexedForeground(FOREGROUND_GREEN | FOREGROUND_RED);
break;
case DispatchTypes::GraphicsOptions::ForegroundWhite:
Log::Comment(L"Testing graphics 'Foreground Color White'");
_testGetSet->_attribute = FOREGROUND_INTENSITY;
_testGetSet->_expectedAttribute = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED;
_testGetSet->_expectedAttribute = _testGetSet->_attribute;
_testGetSet->_expectedAttribute.SetIndexedForeground(FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED);
break;
case DispatchTypes::GraphicsOptions::ForegroundDefault:
Log::Comment(L"Testing graphics 'Foreground Color Default'");
@ -1333,42 +1341,50 @@ public:
case DispatchTypes::GraphicsOptions::BackgroundBlack:
Log::Comment(L"Testing graphics 'Background Color Black'");
_testGetSet->_attribute = BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_INTENSITY;
_testGetSet->_expectedAttribute = 0;
_testGetSet->_expectedAttribute = _testGetSet->_attribute;
_testGetSet->_expectedAttribute.SetIndexedBackground(0);
break;
case DispatchTypes::GraphicsOptions::BackgroundBlue:
Log::Comment(L"Testing graphics 'Background Color Blue'");
_testGetSet->_attribute = BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_INTENSITY;
_testGetSet->_expectedAttribute = BACKGROUND_BLUE;
_testGetSet->_expectedAttribute = _testGetSet->_attribute;
_testGetSet->_expectedAttribute.SetIndexedBackground(BACKGROUND_BLUE >> 4);
break;
case DispatchTypes::GraphicsOptions::BackgroundGreen:
Log::Comment(L"Testing graphics 'Background Color Green'");
_testGetSet->_attribute = BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_INTENSITY;
_testGetSet->_expectedAttribute = BACKGROUND_GREEN;
_testGetSet->_expectedAttribute = _testGetSet->_attribute;
_testGetSet->_expectedAttribute.SetIndexedBackground(BACKGROUND_GREEN >> 4);
break;
case DispatchTypes::GraphicsOptions::BackgroundCyan:
Log::Comment(L"Testing graphics 'Background Color Cyan'");
_testGetSet->_attribute = BACKGROUND_RED | BACKGROUND_INTENSITY;
_testGetSet->_expectedAttribute = BACKGROUND_BLUE | BACKGROUND_GREEN;
_testGetSet->_expectedAttribute = _testGetSet->_attribute;
_testGetSet->_expectedAttribute.SetIndexedBackground((BACKGROUND_BLUE | BACKGROUND_GREEN) >> 4);
break;
case DispatchTypes::GraphicsOptions::BackgroundRed:
Log::Comment(L"Testing graphics 'Background Color Red'");
_testGetSet->_attribute = BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_INTENSITY;
_testGetSet->_expectedAttribute = BACKGROUND_RED;
_testGetSet->_expectedAttribute = _testGetSet->_attribute;
_testGetSet->_expectedAttribute.SetIndexedBackground(BACKGROUND_RED >> 4);
break;
case DispatchTypes::GraphicsOptions::BackgroundMagenta:
Log::Comment(L"Testing graphics 'Background Color Magenta'");
_testGetSet->_attribute = BACKGROUND_GREEN | BACKGROUND_INTENSITY;
_testGetSet->_expectedAttribute = BACKGROUND_BLUE | BACKGROUND_RED;
_testGetSet->_expectedAttribute = _testGetSet->_attribute;
_testGetSet->_expectedAttribute.SetIndexedBackground((BACKGROUND_BLUE | BACKGROUND_RED) >> 4);
break;
case DispatchTypes::GraphicsOptions::BackgroundYellow:
Log::Comment(L"Testing graphics 'Background Color Yellow'");
_testGetSet->_attribute = BACKGROUND_BLUE | BACKGROUND_INTENSITY;
_testGetSet->_expectedAttribute = BACKGROUND_GREEN | BACKGROUND_RED;
_testGetSet->_expectedAttribute = _testGetSet->_attribute;
_testGetSet->_expectedAttribute.SetIndexedBackground((BACKGROUND_GREEN | BACKGROUND_RED) >> 4);
break;
case DispatchTypes::GraphicsOptions::BackgroundWhite:
Log::Comment(L"Testing graphics 'Background Color White'");
_testGetSet->_attribute = BACKGROUND_INTENSITY;
_testGetSet->_expectedAttribute = BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED;
_testGetSet->_expectedAttribute = _testGetSet->_attribute;
_testGetSet->_expectedAttribute.SetIndexedBackground((BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED) >> 4);
break;
case DispatchTypes::GraphicsOptions::BackgroundDefault:
Log::Comment(L"Testing graphics 'Background Color Default'");
@ -1380,82 +1396,98 @@ public:
case DispatchTypes::GraphicsOptions::BrightForegroundBlack:
Log::Comment(L"Testing graphics 'Bright Foreground Color Black'");
_testGetSet->_attribute = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
_testGetSet->_expectedAttribute = FOREGROUND_INTENSITY;
_testGetSet->_expectedAttribute = _testGetSet->_attribute;
_testGetSet->_expectedAttribute.SetIndexedForeground(FOREGROUND_INTENSITY);
break;
case DispatchTypes::GraphicsOptions::BrightForegroundBlue:
Log::Comment(L"Testing graphics 'Bright Foreground Color Blue'");
_testGetSet->_attribute = FOREGROUND_RED | FOREGROUND_GREEN;
_testGetSet->_expectedAttribute = FOREGROUND_INTENSITY | FOREGROUND_BLUE;
_testGetSet->_expectedAttribute = _testGetSet->_attribute;
_testGetSet->_expectedAttribute.SetIndexedForeground(FOREGROUND_INTENSITY | FOREGROUND_BLUE);
break;
case DispatchTypes::GraphicsOptions::BrightForegroundGreen:
Log::Comment(L"Testing graphics 'Bright Foreground Color Green'");
_testGetSet->_attribute = FOREGROUND_RED | FOREGROUND_BLUE;
_testGetSet->_expectedAttribute = FOREGROUND_INTENSITY | FOREGROUND_GREEN;
_testGetSet->_expectedAttribute = _testGetSet->_attribute;
_testGetSet->_expectedAttribute.SetIndexedForeground(FOREGROUND_INTENSITY | FOREGROUND_GREEN);
break;
case DispatchTypes::GraphicsOptions::BrightForegroundCyan:
Log::Comment(L"Testing graphics 'Bright Foreground Color Cyan'");
_testGetSet->_attribute = FOREGROUND_RED;
_testGetSet->_expectedAttribute = FOREGROUND_INTENSITY | FOREGROUND_BLUE | FOREGROUND_GREEN;
_testGetSet->_expectedAttribute = _testGetSet->_attribute;
_testGetSet->_expectedAttribute.SetIndexedForeground(FOREGROUND_INTENSITY | FOREGROUND_BLUE | FOREGROUND_GREEN);
break;
case DispatchTypes::GraphicsOptions::BrightForegroundRed:
Log::Comment(L"Testing graphics 'Bright Foreground Color Red'");
_testGetSet->_attribute = FOREGROUND_BLUE | FOREGROUND_GREEN;
_testGetSet->_expectedAttribute = FOREGROUND_INTENSITY | FOREGROUND_RED;
_testGetSet->_expectedAttribute = _testGetSet->_attribute;
_testGetSet->_expectedAttribute.SetIndexedForeground(FOREGROUND_INTENSITY | FOREGROUND_RED);
break;
case DispatchTypes::GraphicsOptions::BrightForegroundMagenta:
Log::Comment(L"Testing graphics 'Bright Foreground Color Magenta'");
_testGetSet->_attribute = FOREGROUND_GREEN;
_testGetSet->_expectedAttribute = FOREGROUND_INTENSITY | FOREGROUND_BLUE | FOREGROUND_RED;
_testGetSet->_expectedAttribute = _testGetSet->_attribute;
_testGetSet->_expectedAttribute.SetIndexedForeground(FOREGROUND_INTENSITY | FOREGROUND_BLUE | FOREGROUND_RED);
break;
case DispatchTypes::GraphicsOptions::BrightForegroundYellow:
Log::Comment(L"Testing graphics 'Bright Foreground Color Yellow'");
_testGetSet->_attribute = FOREGROUND_BLUE;
_testGetSet->_expectedAttribute = FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED;
_testGetSet->_expectedAttribute = _testGetSet->_attribute;
_testGetSet->_expectedAttribute.SetIndexedForeground(FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED);
break;
case DispatchTypes::GraphicsOptions::BrightForegroundWhite:
Log::Comment(L"Testing graphics 'Bright Foreground Color White'");
_testGetSet->_attribute = 0;
_testGetSet->_expectedAttribute = FOREGROUND_INTENSITY | FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED;
_testGetSet->_expectedAttribute = _testGetSet->_attribute;
_testGetSet->_expectedAttribute.SetIndexedForeground(FOREGROUND_INTENSITY | FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED);
break;
case DispatchTypes::GraphicsOptions::BrightBackgroundBlack:
Log::Comment(L"Testing graphics 'Bright Background Color Black'");
_testGetSet->_attribute = BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE;
_testGetSet->_expectedAttribute = BACKGROUND_INTENSITY;
_testGetSet->_expectedAttribute = _testGetSet->_attribute;
_testGetSet->_expectedAttribute.SetIndexedBackground(BACKGROUND_INTENSITY >> 4);
break;
case DispatchTypes::GraphicsOptions::BrightBackgroundBlue:
Log::Comment(L"Testing graphics 'Bright Background Color Blue'");
_testGetSet->_attribute = BACKGROUND_RED | BACKGROUND_GREEN;
_testGetSet->_expectedAttribute = BACKGROUND_INTENSITY | BACKGROUND_BLUE;
_testGetSet->_expectedAttribute = _testGetSet->_attribute;
_testGetSet->_expectedAttribute.SetIndexedBackground((BACKGROUND_INTENSITY | BACKGROUND_BLUE) >> 4);
break;
case DispatchTypes::GraphicsOptions::BrightBackgroundGreen:
Log::Comment(L"Testing graphics 'Bright Background Color Green'");
_testGetSet->_attribute = BACKGROUND_RED | BACKGROUND_BLUE;
_testGetSet->_expectedAttribute = BACKGROUND_INTENSITY | BACKGROUND_GREEN;
_testGetSet->_expectedAttribute = _testGetSet->_attribute;
_testGetSet->_expectedAttribute.SetIndexedBackground((BACKGROUND_INTENSITY | BACKGROUND_GREEN) >> 4);
break;
case DispatchTypes::GraphicsOptions::BrightBackgroundCyan:
Log::Comment(L"Testing graphics 'Bright Background Color Cyan'");
_testGetSet->_attribute = BACKGROUND_RED;
_testGetSet->_expectedAttribute = BACKGROUND_INTENSITY | BACKGROUND_BLUE | BACKGROUND_GREEN;
_testGetSet->_expectedAttribute = _testGetSet->_attribute;
_testGetSet->_expectedAttribute.SetIndexedBackground((BACKGROUND_INTENSITY | BACKGROUND_BLUE | BACKGROUND_GREEN) >> 4);
break;
case DispatchTypes::GraphicsOptions::BrightBackgroundRed:
Log::Comment(L"Testing graphics 'Bright Background Color Red'");
_testGetSet->_attribute = BACKGROUND_BLUE | BACKGROUND_GREEN;
_testGetSet->_expectedAttribute = BACKGROUND_INTENSITY | BACKGROUND_RED;
_testGetSet->_expectedAttribute = _testGetSet->_attribute;
_testGetSet->_expectedAttribute.SetIndexedBackground((BACKGROUND_INTENSITY | BACKGROUND_RED) >> 4);
break;
case DispatchTypes::GraphicsOptions::BrightBackgroundMagenta:
Log::Comment(L"Testing graphics 'Bright Background Color Magenta'");
_testGetSet->_attribute = BACKGROUND_GREEN;
_testGetSet->_expectedAttribute = BACKGROUND_INTENSITY | BACKGROUND_BLUE | BACKGROUND_RED;
_testGetSet->_expectedAttribute = _testGetSet->_attribute;
_testGetSet->_expectedAttribute.SetIndexedBackground((BACKGROUND_INTENSITY | BACKGROUND_BLUE | BACKGROUND_RED) >> 4);
break;
case DispatchTypes::GraphicsOptions::BrightBackgroundYellow:
Log::Comment(L"Testing graphics 'Bright Background Color Yellow'");
_testGetSet->_attribute = BACKGROUND_BLUE;
_testGetSet->_expectedAttribute = BACKGROUND_INTENSITY | BACKGROUND_GREEN | BACKGROUND_RED;
_testGetSet->_expectedAttribute = _testGetSet->_attribute;
_testGetSet->_expectedAttribute.SetIndexedBackground((BACKGROUND_INTENSITY | BACKGROUND_GREEN | BACKGROUND_RED) >> 4);
break;
case DispatchTypes::GraphicsOptions::BrightBackgroundWhite:
Log::Comment(L"Testing graphics 'Bright Background Color White'");
_testGetSet->_attribute = 0;
_testGetSet->_expectedAttribute = BACKGROUND_INTENSITY | BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED;
_testGetSet->_expectedAttribute = _testGetSet->_attribute;
_testGetSet->_expectedAttribute.SetIndexedBackground((BACKGROUND_INTENSITY | BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED) >> 4);
break;
default:
VERIFY_FAIL(L"Test not implemented yet!");
@ -1880,32 +1912,28 @@ public:
rgOptions[0] = DispatchTypes::GraphicsOptions::ForegroundExtended;
rgOptions[1] = DispatchTypes::GraphicsOptions::BlinkOrXterm256Index;
rgOptions[2] = (DispatchTypes::GraphicsOptions)2; // Green
_testGetSet->_expectedAttribute.SetForeground(2);
_testGetSet->_expectedColorTableIndex = 2;
_testGetSet->_expectedAttribute.SetIndexedForeground256((BYTE)::XtermToWindowsIndex(2));
VERIFY_IS_TRUE(_pDispatch.get()->SetGraphicsRendition({ rgOptions, cOptions }));
Log::Comment(L"Test 2: Change Background");
rgOptions[0] = DispatchTypes::GraphicsOptions::BackgroundExtended;
rgOptions[1] = DispatchTypes::GraphicsOptions::BlinkOrXterm256Index;
rgOptions[2] = (DispatchTypes::GraphicsOptions)9; // Bright Red
_testGetSet->_expectedAttribute.SetBackground(9);
_testGetSet->_expectedColorTableIndex = 9;
_testGetSet->_expectedAttribute.SetIndexedBackground256((BYTE)::XtermToWindowsIndex(9));
VERIFY_IS_TRUE(_pDispatch.get()->SetGraphicsRendition({ rgOptions, cOptions }));
Log::Comment(L"Test 3: Change Foreground to RGB color");
rgOptions[0] = DispatchTypes::GraphicsOptions::ForegroundExtended;
rgOptions[1] = DispatchTypes::GraphicsOptions::BlinkOrXterm256Index;
rgOptions[2] = (DispatchTypes::GraphicsOptions)42; // Arbitrary Color
_testGetSet->_expectedColorTableIndex = 42;
_testGetSet->_expectedAttribute.SetForeground(42);
_testGetSet->_expectedAttribute.SetIndexedForeground256(42);
VERIFY_IS_TRUE(_pDispatch.get()->SetGraphicsRendition({ rgOptions, cOptions }));
Log::Comment(L"Test 4: Change Background to RGB color");
rgOptions[0] = DispatchTypes::GraphicsOptions::BackgroundExtended;
rgOptions[1] = DispatchTypes::GraphicsOptions::BlinkOrXterm256Index;
rgOptions[2] = (DispatchTypes::GraphicsOptions)142; // Arbitrary Color
_testGetSet->_expectedColorTableIndex = 142;
_testGetSet->_expectedAttribute.SetBackground(142);
_testGetSet->_expectedAttribute.SetIndexedBackground256(142);
VERIFY_IS_TRUE(_pDispatch.get()->SetGraphicsRendition({ rgOptions, cOptions }));
Log::Comment(L"Test 5: Change Foreground to Legacy Attr while BG is RGB color");
@ -1915,8 +1943,7 @@ public:
rgOptions[0] = DispatchTypes::GraphicsOptions::ForegroundExtended;
rgOptions[1] = DispatchTypes::GraphicsOptions::BlinkOrXterm256Index;
rgOptions[2] = (DispatchTypes::GraphicsOptions)9; // Bright Red
_testGetSet->_expectedAttribute.SetForeground(9);
_testGetSet->_expectedColorTableIndex = 9;
_testGetSet->_expectedAttribute.SetIndexedForeground256((BYTE)::XtermToWindowsIndex(9));
VERIFY_IS_TRUE(_pDispatch.get()->SetGraphicsRendition({ rgOptions, cOptions }));
}

View file

@ -2,7 +2,8 @@
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
<!-- See https://docs.microsoft.com/en-us/visualstudio/debugger/create-custom-views-of-native-objects?view=vs-2017#BKMK_Syntax_reference for documentation -->
<Type Name="TextColor">
<DisplayString Condition="_meta==ColorType::IsIndex">{{Index:{_index}}}</DisplayString>
<DisplayString Condition="_meta==ColorType::IsIndex256">{{Index256:{_index}}}</DisplayString>
<DisplayString Condition="_meta==ColorType::IsIndex16">{{Index16:{_index}}}</DisplayString>
<DisplayString Condition="_meta==ColorType::IsDefault">{{Default}}</DisplayString>
<DisplayString Condition="_meta==ColorType::IsRgb">{{RGB:{_red},{_green},{_blue}}}</DisplayString>
<Expand></Expand>