terminal/src/cascadia/TerminalCore/terminalrenderdata.cpp
James Holderness 3388a486dc
Refactor the renderer color calculations (#6853)
This is a refactoring of the renderer color calculations to simplify the
implementation, and to make it easier to support additional
color-altering rendition attributes in the future (e.g. _faint_ and
_conceal_).

## References

* This is a followup to PRs #3817 and #6809, which introduced additional
  complexity in the color calculations, and which suggested the need for
  refactoring. 

## Detailed Description of the Pull Request / Additional comments

When we added support for `DECSCNM`, that required the foreground and
background color lookup methods to be able to return the opposite of
what was requested when the reversed mode was set. That made those
methods unnecessarily complicated, and I thought we could simplify them
considerably just by combining the calculations into a single method
that derived both colors at the same time.

And since both conhost and Windows Terminal needed to perform the same
calculations, it also made sense to move that functionality into the
`TextAttribute` class, where it could easily be shared.

In general this way of doing things is a bit more efficient. However, it
does result in some unnecessary work when only one of the colors is
required, as is the case for the gridline painter. So to make that less
of an issue, I've reordered the gridline code a bit so it at least
avoids looking up the colors when no gridlines are needed.

## Validation Steps Performed

Because of the API changes, quite a lot of the unit tests had to be
updated. For example instead of verifying colors with two separate calls
to `LookupForegroundColor` and `LookupBackgroundColor`, that's now
achieved with a single `LookupAttributeColors` call, comparing against a
pair of values. The specifics of the tests haven't changed though, and
they're all still working as expected.

I've also manually confirmed that the various color sequences and
rendition attributes are rendering correctly with the new refactoring.
2020-07-10 22:26:34 +00:00

221 lines
6.3 KiB
C++

// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include "Terminal.hpp"
#include <DefaultSettings.h>
using namespace Microsoft::Terminal::Core;
using namespace Microsoft::Console::Types;
using namespace Microsoft::Console::Render;
Viewport Terminal::GetViewport() noexcept
{
return _GetVisibleViewport();
}
COORD Terminal::GetTextBufferEndPosition() const noexcept
{
// We use the end line of mutableViewport as the end
// of the text buffer, it always moves with the written
// text
COORD endPosition{ _GetMutableViewport().Width() - 1, gsl::narrow<short>(ViewEndIndex()) };
return endPosition;
}
const TextBuffer& Terminal::GetTextBuffer() noexcept
{
return *_buffer;
}
// Creating a FontInfo can technically throw (on string allocation) and this is noexcept.
// That means this will std::terminate. We could come back and make there be a default constructor
// backup to FontInfo that throws no exceptions and allocates a default FontInfo structure.
#pragma warning(push)
#pragma warning(disable : 26447)
const FontInfo& Terminal::GetFontInfo() noexcept
{
// TODO: This font value is only used to check if the font is a raster font.
// Otherwise, the font is changed with the renderer via TriggerFontChange.
// The renderer never uses any of the other members from the value returned
// by this method.
// We could very likely replace this with just an IsRasterFont method
// (which would return false)
static const FontInfo _fakeFontInfo(DEFAULT_FONT_FACE, TMPF_TRUETYPE, 10, { 0, DEFAULT_FONT_SIZE }, CP_UTF8, false);
return _fakeFontInfo;
}
#pragma warning(pop)
const TextAttribute Terminal::GetDefaultBrushColors() noexcept
{
return TextAttribute{};
}
std::pair<COLORREF, COLORREF> Terminal::GetAttributeColors(const TextAttribute& attr) const noexcept
{
auto colors = attr.CalculateRgbColors({ _colorTable.data(), _colorTable.size() },
_defaultFg,
_defaultBg,
_screenReversed);
colors.first |= 0xff000000;
// We only care about alpha for the default BG (which enables acrylic)
// If the bg isn't the default bg color, or reverse video is enabled, make it fully opaque.
if (!attr.BackgroundIsDefault() || (attr.IsReverseVideo() ^ _screenReversed))
{
colors.second |= 0xff000000;
}
return colors;
}
COORD Terminal::GetCursorPosition() const noexcept
{
const auto& cursor = _buffer->GetCursor();
return cursor.GetPosition();
}
bool Terminal::IsCursorVisible() const noexcept
{
const auto& cursor = _buffer->GetCursor();
return cursor.IsVisible() && !cursor.IsPopupShown();
}
bool Terminal::IsCursorOn() const noexcept
{
const auto& cursor = _buffer->GetCursor();
return cursor.IsOn();
}
ULONG Terminal::GetCursorPixelWidth() const noexcept
{
return 1;
}
ULONG Terminal::GetCursorHeight() const noexcept
{
return _buffer->GetCursor().GetSize();
}
CursorType Terminal::GetCursorStyle() const noexcept
{
return _buffer->GetCursor().GetType();
}
COLORREF Terminal::GetCursorColor() const noexcept
{
return _buffer->GetCursor().GetColor();
}
bool Terminal::IsCursorDoubleWidth() const
{
const auto position = _buffer->GetCursor().GetPosition();
TextBufferTextIterator it(TextBufferCellIterator(*_buffer, position));
return IsGlyphFullWidth(*it);
}
const std::vector<RenderOverlay> Terminal::GetOverlays() const noexcept
{
return {};
}
const bool Terminal::IsGridLineDrawingAllowed() noexcept
{
return true;
}
std::vector<Microsoft::Console::Types::Viewport> Terminal::GetSelectionRects() noexcept
try
{
std::vector<Viewport> result;
for (const auto& lineRect : _GetSelectionRects())
{
result.emplace_back(Viewport::FromInclusive(lineRect));
}
return result;
}
catch (...)
{
LOG_CAUGHT_EXCEPTION();
return {};
}
void Terminal::SelectNewRegion(const COORD coordStart, const COORD coordEnd)
{
#pragma warning(push)
#pragma warning(disable : 26496) // cpp core checks wants these const, but they're decremented below.
COORD realCoordStart = coordStart;
COORD realCoordEnd = coordEnd;
#pragma warning(pop)
bool notifyScrollChange = false;
if (coordStart.Y < _VisibleStartIndex())
{
// recalculate the scrollOffset
_scrollOffset = ViewStartIndex() - coordStart.Y;
notifyScrollChange = true;
}
else if (coordEnd.Y > _VisibleEndIndex())
{
// recalculate the scrollOffset, note that if the found text is
// beneath the current visible viewport, it may be within the
// current mutableViewport and the scrollOffset will be smaller
// than 0
_scrollOffset = std::max(0, ViewStartIndex() - coordStart.Y);
notifyScrollChange = true;
}
if (notifyScrollChange)
{
_buffer->GetRenderTarget().TriggerScroll();
_NotifyScrollEvent();
}
realCoordStart.Y -= gsl::narrow<short>(_VisibleStartIndex());
realCoordEnd.Y -= gsl::narrow<short>(_VisibleStartIndex());
SetSelectionAnchor(realCoordStart);
SetSelectionEnd(realCoordEnd, SelectionExpansionMode::Cell);
}
const std::wstring Terminal::GetConsoleTitle() const noexcept
try
{
if (_title.has_value())
{
return _title.value();
}
return _startingTitle;
}
catch (...)
{
LOG_CAUGHT_EXCEPTION();
return {};
}
// Method Description:
// - Lock the terminal for reading the contents of the buffer. Ensures that the
// contents of the terminal won't be changed in the middle of a paint
// operation.
// Callers should make sure to also call Terminal::UnlockConsole once
// they're done with any querying they need to do.
void Terminal::LockConsole() noexcept
{
_readWriteLock.lock_shared();
}
// Method Description:
// - Unlocks the terminal after a call to Terminal::LockConsole.
void Terminal::UnlockConsole() noexcept
{
_readWriteLock.unlock_shared();
}
// Method Description:
// - Returns whether the screen is inverted;
// Return Value:
// - false.
bool Terminal::IsScreenReversed() const noexcept
{
return _screenReversed;
}