Skip to content

Commit

Permalink
PRE-MERGE #15795 Add support for underline style and color in VT
Browse files Browse the repository at this point in the history
  • Loading branch information
zadjii-msft committed Aug 29, 2023
2 parents 364e9c8 + 31455cd commit 0630132
Show file tree
Hide file tree
Showing 22 changed files with 780 additions and 241 deletions.
2 changes: 1 addition & 1 deletion src/buffer/out/OutputCellIterator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
#include "../../types/inc/GlyphWidth.hpp"
#include "../../inc/conattrs.hpp"

static constexpr TextAttribute InvalidTextAttribute{ INVALID_COLOR, INVALID_COLOR };
static constexpr TextAttribute InvalidTextAttribute{ INVALID_COLOR, INVALID_COLOR, INVALID_COLOR };

// Routine Description:
// - This is a fill-mode iterator for one particular wchar. It will repeat forever if fillLimit is 0.
Expand Down
49 changes: 35 additions & 14 deletions src/buffer/out/TextAttribute.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

// Keeping TextColor compact helps us keeping TextAttribute compact,
// which in turn ensures that our buffer memory usage is low.
static_assert(sizeof(TextAttribute) == 12);
static_assert(sizeof(TextAttribute) == 16);
static_assert(alignof(TextAttribute) == 2);
// Ensure that we can memcpy() and memmove() the struct for performance.
static_assert(std::is_trivially_copyable_v<TextAttribute>);
Expand Down Expand Up @@ -156,6 +156,17 @@ uint16_t TextAttribute::GetHyperlinkId() const noexcept
return _hyperlinkId;
}

TextColor TextAttribute::GetUnderlineColor() const noexcept
{
return _underlineColor;
}

UnderlineStyle TextAttribute::GetUnderlineStyle() const noexcept
{
const auto styleAttr = WI_EnumValue(_attrs & CharacterAttributes::UnderlineStyle);
return static_cast<UnderlineStyle>(styleAttr >> UNDERLINE_STYLE_SHIFT);
}

void TextAttribute::SetForeground(const TextColor foreground) noexcept
{
_foreground = foreground;
Expand All @@ -166,6 +177,13 @@ void TextAttribute::SetBackground(const TextColor background) noexcept
_background = background;
}

void TextAttribute::SetUnderlineColor(const TextColor color) noexcept
{
// Index16 colors are not supported for underline colors.
assert(!color.IsIndex16());
_underlineColor = color;
}

void TextAttribute::SetForeground(const COLORREF rgbForeground) noexcept
{
_foreground = TextColor(rgbForeground);
Expand Down Expand Up @@ -277,14 +295,12 @@ bool TextAttribute::IsCrossedOut() const noexcept
return WI_IsFlagSet(_attrs, CharacterAttributes::CrossedOut);
}

// Method description:
// - Returns true if the text is underlined with any underline style.
bool TextAttribute::IsUnderlined() const noexcept
{
return WI_IsFlagSet(_attrs, CharacterAttributes::Underlined);
}

bool TextAttribute::IsDoublyUnderlined() const noexcept
{
return WI_IsFlagSet(_attrs, CharacterAttributes::DoublyUnderlined);
const auto style = GetUnderlineStyle();
return (style != UnderlineStyle::NoUnderline);
}

bool TextAttribute::IsOverlined() const noexcept
Expand Down Expand Up @@ -332,14 +348,14 @@ void TextAttribute::SetCrossedOut(bool isCrossedOut) noexcept
WI_UpdateFlag(_attrs, CharacterAttributes::CrossedOut, isCrossedOut);
}

void TextAttribute::SetUnderlined(bool isUnderlined) noexcept
{
WI_UpdateFlag(_attrs, CharacterAttributes::Underlined, isUnderlined);
}

void TextAttribute::SetDoublyUnderlined(bool isDoublyUnderlined) noexcept
// Method description:
// - Sets underline style to singly, doubly, or one of the extended styles.
// Arguments:
// - style - underline style to set.
void TextAttribute::SetUnderlineStyle(const UnderlineStyle style) noexcept
{
WI_UpdateFlag(_attrs, CharacterAttributes::DoublyUnderlined, isDoublyUnderlined);
const auto shiftedStyle = WI_EnumValue(style) << UNDERLINE_STYLE_SHIFT;
_attrs = (_attrs & ~CharacterAttributes::UnderlineStyle) | static_cast<CharacterAttributes>(shiftedStyle);
}

void TextAttribute::SetOverlined(bool isOverlined) noexcept
Expand Down Expand Up @@ -374,6 +390,11 @@ void TextAttribute::SetDefaultBackground() noexcept
_background = TextColor();
}

void TextAttribute::SetDefaultUnderlineColor() noexcept
{
_underlineColor = TextColor{};
}

// Method description:
// - Resets only the rendition character attributes, which includes everything
// except the Protected attribute.
Expand Down
45 changes: 36 additions & 9 deletions src/buffer/out/TextAttribute.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,31 +27,55 @@ Revision History:
#include "WexTestClass.h"
#endif

enum class UnderlineStyle
{
NoUnderline = 0U,
SinglyUnderlined = 1U,
DoublyUnderlined = 2U,
CurlyUnderlined = 3U,
DottedUnderlined = 4U,
DashedUnderlined = 5U,
Max = DashedUnderlined
};

class TextAttribute final
{
public:
constexpr TextAttribute() noexcept :
_attrs{ CharacterAttributes::Normal },
_foreground{},
_background{},
_hyperlinkId{ 0 }
_hyperlinkId{ 0 },
_underlineColor{}
{
}

explicit constexpr TextAttribute(const WORD wLegacyAttr) noexcept :
_attrs{ gsl::narrow_cast<WORD>(wLegacyAttr & USED_META_ATTRS) },
_foreground{ gsl::at(s_legacyForegroundColorMap, wLegacyAttr & FG_ATTRS) },
_background{ gsl::at(s_legacyBackgroundColorMap, (wLegacyAttr & BG_ATTRS) >> 4) },
_hyperlinkId{ 0 }
_hyperlinkId{ 0 },
_underlineColor{}
{
}

constexpr TextAttribute(const COLORREF rgbForeground,
const COLORREF rgbBackground) noexcept :
const COLORREF rgbBackground,
const COLORREF rgbUnderline = INVALID_COLOR) noexcept :
_attrs{ CharacterAttributes::Normal },
_foreground{ rgbForeground },
_background{ rgbBackground },
_hyperlinkId{ 0 }
_hyperlinkId{ 0 },
_underlineColor{ rgbUnderline }
{
}

constexpr TextAttribute(const CharacterAttributes attrs, const TextColor foreground, const TextColor background, const uint16_t hyperlinkId, const TextColor underlineColor) noexcept :
_attrs{ attrs },
_foreground{ foreground },
_background{ background },
_hyperlinkId{ hyperlinkId },
_underlineColor{ underlineColor }
{
}

Expand Down Expand Up @@ -87,7 +111,6 @@ class TextAttribute final
bool IsInvisible() const noexcept;
bool IsCrossedOut() const noexcept;
bool IsUnderlined() const noexcept;
bool IsDoublyUnderlined() const noexcept;
bool IsOverlined() const noexcept;
bool IsReverseVideo() const noexcept;
bool IsProtected() const noexcept;
Expand All @@ -98,8 +121,7 @@ class TextAttribute final
void SetBlinking(bool isBlinking) noexcept;
void SetInvisible(bool isInvisible) noexcept;
void SetCrossedOut(bool isCrossedOut) noexcept;
void SetUnderlined(bool isUnderlined) noexcept;
void SetDoublyUnderlined(bool isDoublyUnderlined) noexcept;
void SetUnderlineStyle(const UnderlineStyle underlineStyle) noexcept;
void SetOverlined(bool isOverlined) noexcept;
void SetReverseVideo(bool isReversed) noexcept;
void SetProtected(bool isProtected) noexcept;
Expand All @@ -118,8 +140,11 @@ class TextAttribute final
TextColor GetForeground() const noexcept;
TextColor GetBackground() const noexcept;
uint16_t GetHyperlinkId() const noexcept;
TextColor GetUnderlineColor() const noexcept;
UnderlineStyle GetUnderlineStyle() const noexcept;
void SetForeground(const TextColor foreground) noexcept;
void SetBackground(const TextColor background) noexcept;
void SetUnderlineColor(const TextColor color) noexcept;
void SetForeground(const COLORREF rgbForeground) noexcept;
void SetBackground(const COLORREF rgbBackground) noexcept;
void SetIndexedForeground(const BYTE fgIndex) noexcept;
Expand All @@ -131,6 +156,7 @@ class TextAttribute final

void SetDefaultForeground() noexcept;
void SetDefaultBackground() noexcept;
void SetDefaultUnderlineColor() noexcept;
void SetDefaultRenditionAttributes() noexcept;

bool BackgroundIsDefault() const noexcept;
Expand All @@ -147,8 +173,8 @@ class TextAttribute final
// global ^ local == false: the foreground attribute is the visible foreground, so we care about the backgrounds being identical
const auto checkForeground = (inverted != IsReverseVideo());
return !IsAnyGridLineEnabled() && // grid lines have a visual representation
// crossed out, doubly and singly underlined have a visual representation
WI_AreAllFlagsClear(_attrs, CharacterAttributes::CrossedOut | CharacterAttributes::DoublyUnderlined | CharacterAttributes::Underlined) &&
// styled underline and crossed out have a visual representation
!IsUnderlined() && WI_IsFlagClear(_attrs, CharacterAttributes::CrossedOut) &&
// hyperlinks have a visual representation
!IsHyperlink() &&
// all other attributes do not have a visual representation
Expand All @@ -175,6 +201,7 @@ class TextAttribute final
uint16_t _hyperlinkId; // sizeof: 2, alignof: 2
TextColor _foreground; // sizeof: 4, alignof: 1
TextColor _background; // sizeof: 4, alignof: 1
TextColor _underlineColor; // sizeof: 4, alignof: 1

#ifdef UNIT_TESTING
friend class TextBufferTests;
Expand Down
2 changes: 1 addition & 1 deletion src/host/ut_host/OutputCellIteratorTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ using namespace WEX::Common;
using namespace WEX::Logging;
using namespace WEX::TestExecution;

static constexpr TextAttribute InvalidTextAttribute{ INVALID_COLOR, INVALID_COLOR };
static constexpr TextAttribute InvalidTextAttribute{ INVALID_COLOR, INVALID_COLOR, INVALID_COLOR };

class OutputCellIteratorTests
{
Expand Down
Loading

0 comments on commit 0630132

Please sign in to comment.