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

Fix the ConPTY extended attributes optimization #13661

Merged
10 commits merged into from
Aug 5, 2022
5 changes: 0 additions & 5 deletions src/buffer/out/TextAttribute.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -357,11 +357,6 @@ void TextAttribute::SetReverseVideo(bool isReversed) noexcept
WI_UpdateFlag(_wAttrLegacy, COMMON_LVB_REVERSE_VIDEO, isReversed);
}

ExtendedAttributes TextAttribute::GetExtendedAttributes() const noexcept
{
return _extendedAttrs;
}

// Routine Description:
// - swaps foreground and background color
void TextAttribute::Invert() noexcept
Expand Down
12 changes: 11 additions & 1 deletion src/buffer/out/TextAttribute.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,10 @@ class TextAttribute final
void SetOverlined(bool isOverlined) noexcept;
void SetReverseVideo(bool isReversed) noexcept;

ExtendedAttributes GetExtendedAttributes() const noexcept;
constexpr ExtendedAttributes GetExtendedAttributes() const noexcept
{
return _extendedAttrs;
}

bool IsHyperlink() const noexcept;

Expand Down Expand Up @@ -161,6 +164,13 @@ class TextAttribute final
{
return WI_IsAnyFlagSet(_wAttrLegacy, COMMON_LVB_GRID_HORIZONTAL | COMMON_LVB_GRID_LVERTICAL | COMMON_LVB_GRID_RVERTICAL | COMMON_LVB_UNDERSCORE);
}
constexpr bool HasAnyExtendedAttributes() const noexcept
{
return GetExtendedAttributes() != ExtendedAttributes::Normal ||
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(fwiw: since GetExtendedAttributes doesn't do any translation or synthesis on its own, why should we use it instead of just using _extendedAttrs directly?)

IsAnyGridLineEnabled() ||
GetHyperlinkId() != 0 ||
IsReverseVideo();
}

private:
static std::array<TextColor, 16> s_legacyForegroundColorMap;
Expand Down
56 changes: 56 additions & 0 deletions src/cascadia/UnitTests_TerminalCore/ConptyRoundtripTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,8 @@ class TerminalCoreUnitTests::ConptyRoundtripTests final

TEST_METHOD(AltBufferResizeCrash);

TEST_METHOD(TestNoExtendedAttrsOptimization);

private:
bool _writeCallback(const char* const pch, const size_t cch);
void _flushFirstFrame();
Expand Down Expand Up @@ -4114,6 +4116,11 @@ void ConptyRoundtripTests::AltBufferResizeCrash()
L"particular combination of resizing could crash the terminal."
L" This test makes sure we don't.");

// Anything that resizes the buffer needs IsolationLevel:Method
BEGIN_TEST_METHOD_PROPERTIES()
TEST_METHOD_PROPERTY(L"IsolationLevel", L"Method")
END_TEST_METHOD_PROPERTIES()

auto& g = ServiceLocator::LocateGlobals();
auto& renderer = *g.pRender;
auto& gci = g.getConsoleInformation();
Expand Down Expand Up @@ -4154,3 +4161,52 @@ void ConptyRoundtripTests::AltBufferResizeCrash()
Log::Comment(L"Painting the frame");
VERIFY_SUCCEEDED(renderer.PaintFrame());
}

void ConptyRoundtripTests::TestNoExtendedAttrsOptimization()
{
Log::Comment(L"We don't want conpty to optimize out runs of spaces that DO "
L"have extended attrs, because EL / ECH don't fill space with "
L"those attributes");

auto& g = ServiceLocator::LocateGlobals();
auto& renderer = *g.pRender;
auto& gci = g.getConsoleInformation();
auto& si = gci.GetActiveOutputBuffer();
auto& sm = si.GetStateMachine();

auto* hostTb = &si.GetTextBuffer();
auto* termTb = term->_mainBuffer.get();

gci.LockConsole(); // Lock must be taken to manipulate alt/main buffer state.
auto unlock = wil::scope_exit([&] { gci.UnlockConsole(); });

_flushFirstFrame();

_checkConptyOutput = false;

TextAttribute reverseAttrs{};
reverseAttrs.SetReverseVideo(true);

auto verifyBuffer = [&](const TextBuffer& tb) {
auto iter0 = TestUtils::VerifyLineContains(tb, { 0, 0 }, L' ', reverseAttrs, 9u);
TestUtils::VerifyExpectedString(L"test", iter0);
TestUtils::VerifyLineContains(iter0, L' ', reverseAttrs, 9u);

TestUtils::VerifyLineContains(tb, { 0, 1 }, L' ', reverseAttrs, static_cast<uint32_t>(TerminalViewWidth));
};

Log::Comment(L"========== Fill test content ==========");
sm.ProcessString(L"\x1b[7m test \x1b[m\n");
sm.ProcessString(L"\x1b[7m");
sm.ProcessString(std::wstring(TerminalViewWidth, L' '));
sm.ProcessString(L"\x1b[m\n");

Log::Comment(L"========== Check host buffer ==========");
verifyBuffer(*hostTb);

Log::Comment(L"Painting the frame");
VERIFY_SUCCEEDED(renderer.PaintFrame());

Log::Comment(L"========== Check terminal buffer ==========");
verifyBuffer(*termTb);
}
7 changes: 6 additions & 1 deletion src/renderer/vt/paint.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -424,10 +424,15 @@ using namespace Microsoft::Console::Types;
// the inbox telnet client doesn't understand the Erase Character sequence,
// and it uses xterm-ascii. This ensures that xterm and -256color consumers
// get the enhancements, and telnet isn't broken.
//
// GH#13229: ECH and EL don't fill the space with "meta" attributes like
Copy link
Member

@DHowett DHowett Aug 4, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean, don't we still have the "background" version of this problem? \e[40m x theres a lot of spaces here, github deleted them \e[m doesn't require any extended attributes.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

more tests you got it

// underline, reverse video, hyperlinks, etc. If these spaces had those
// attrs, then don't try and optimize them out.
const auto optimalToUseECH = numSpaces > ERASE_CHARACTER_STRING_LENGTH;
const auto useEraseChar = (optimalToUseECH) &&
(!_newBottomLine) &&
(!_clearedAllThisFrame);
(!_clearedAllThisFrame) &&
(!_lastTextAttributes.HasAnyExtendedAttributes());
const auto printingBottomLine = coord.Y == _lastViewport.BottomInclusive();

// GH#5502 - If the background color of the "new bottom line" is different
Expand Down