Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for underline style and color in VT #15795

Merged
merged 42 commits into from
Sep 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
07cb660
add support for underline color & style in VT parser
tusharsnx Aug 5, 2023
c26b688
add underline color and style support to VT renderer
tusharsnx Aug 6, 2023
0093d93
use const& when reading TextAttribute without mutation
tusharsnx Aug 6, 2023
ac2b786
more attributes read to const& refactoring
tusharsnx Aug 6, 2023
87a43c0
respect underline style and color in DECRARA and DECCARA
tusharsnx Aug 6, 2023
3dcb214
remaining refactor for const& for reading TextAttribute
tusharsnx Aug 6, 2023
1027e1b
refactor _SetRgbColorsHelperFromSubParams
tusharsnx Aug 7, 2023
1673c6e
let DECCARA apply underline color
tusharsnx Aug 8, 2023
a8bede3
store underline style within CharacterAttribute
tusharsnx Aug 10, 2023
00833f9
use public apis to manipulate flags in CharacterAttributes
tusharsnx Aug 10, 2023
87b3fa7
Merge remote-tracking branch 'upstream/main' into temp
tusharsnx Aug 12, 2023
0b38f07
update DECCIR to use styles instead of boolean when setting the under…
tusharsnx Aug 11, 2023
7d12a21
let's bid adieu to CharacterAttribute::DoublyUnderlined
tusharsnx Aug 12, 2023
1163542
update routines for XTPUSHSGR / XTPOPSGR
tusharsnx Aug 12, 2023
a7d2437
update routines for DECRQSS
tusharsnx Aug 12, 2023
d18f4d7
check underline color is not Index16 based
tusharsnx Aug 12, 2023
42f6066
update routines for DECCIR
tusharsnx Aug 12, 2023
9660e2a
update the tests
tusharsnx Aug 12, 2023
fd165f2
format
tusharsnx Aug 12, 2023
0a3e9ae
fix little things
tusharsnx Aug 12, 2023
5350ac4
fix a wrong default'ing for drawing underlines
tusharsnx Aug 12, 2023
6d4ac54
fix wordings
tusharsnx Aug 12, 2023
eeff6a5
write seq for doubly underlined directly
tusharsnx Aug 12, 2023
21309d5
report singly and doubly underlined with sgr 4 and 21 in DECRQSS resp…
tusharsnx Aug 12, 2023
a117f30
update test and add ITU color test for the underline
tusharsnx Aug 12, 2023
ac62677
renderer: merge NoUnderline into the default case
tusharsnx Aug 13, 2023
5bb3531
adaptDispatch: maintain rendition attrs' numeric order while sending …
tusharsnx Aug 13, 2023
da50289
revert the comment added to SetDefaultRenditionAttributes
tusharsnx Aug 13, 2023
e33130c
initialize underline color to INVALID_COLOR where it make sense to do so
tusharsnx Aug 14, 2023
32bd78a
avoid false errors due to missing headers within editor
tusharsnx Aug 14, 2023
820cbc0
update test to use CurlyUnderlined instead of SinglyUnderlined
tusharsnx Aug 14, 2023
f5ab09a
reset doubly underlined before sending the new style
tusharsnx Aug 15, 2023
be681de
pass a separate boolean reverseUnderline in ChangeOps to reverse unde…
tusharsnx Aug 15, 2023
7fd1129
update restore logic for XTPUSHSGR/XTPOPSGR
tusharsnx Aug 16, 2023
432d4df
Merge remote-tracking branch 'upstream/main' into feat-underline-styl…
tusharsnx Aug 18, 2023
20755f3
inline mapping functions for mapping underline style to/from characte…
tusharsnx Aug 20, 2023
2935818
Merge remote-tracking branch 'upstream/main' into feat-underline-styl…
tusharsnx Aug 22, 2023
8812867
use util to generate subparams and ranges
tusharsnx Aug 22, 2023
31455cd
test underline color and style in GraphicsSingleWithSubParamTests
tusharsnx Aug 22, 2023
ea7dcfe
revert changes to DECRARA
tusharsnx Sep 1, 2023
a67a1ab
update the DECRARA testcase to test for intense attr instead of under…
tusharsnx Sep 1, 2023
dc1b95f
treat invalid style values as singly underlined
tusharsnx Sep 7, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
57 changes: 43 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,25 @@ uint16_t TextAttribute::GetHyperlinkId() const noexcept
return _hyperlinkId;
}

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

// Method description:
// - Retrieves the underline style of the text.
// - If the attribute is not the **current** attribute of the text buffer,
// (eg. reading an attribute from another part of the text buffer, which
// was modified using DECRARA), this might return an invalid style. In this
// case, treat the style as singly underlined.
// Return value:
// - The underline style.
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 +185,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 +303,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 +356,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 +398,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/cascadia/TerminalCore/Terminal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ std::wstring_view Terminal::GetWorkingDirectory() noexcept
// but after the resize, we'll want to make sure that the new buffer's
// current attributes (the ones used for printing new text) match the
// old buffer's.
const auto oldBufferAttributes = _mainBuffer->GetCurrentAttributes();
const auto& oldBufferAttributes = _mainBuffer->GetCurrentAttributes();
newTextBuffer = std::make_unique<TextBuffer>(bufferSize,
TextAttribute{},
0, // temporarily set size to 0 so it won't render.
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
Loading