Eliminate more transient allocations: Titles and invalid rectangles and bitmap runs and utf8 conversions (#8621)

## References
* See also #8617 

## PR Checklist
* [x] Supports #3075
* [x] I work here.
* [x] Manual test.

## Detailed Description of the Pull Request / Additional comments

### Window Title Generation
Every time the renderer checks the title, it's doing two bad things that
I've fixed:
1. It's assembling the prefix to the full title doing a concatenation.
   No one ever gets just the prefix ever after it is set besides the
   concat. So instead of storing prefix and the title, I store the
   assembled prefix + title and the bare title.
2. A copy must be made because it was returning `std::wstring` instead
   of `std::wstring&`. Now it returns the ref.

### Dirty Area Return
Every time the renderer checks the dirty area, which is sometimes
multiple times per pass (regular text printing, again for selection,
etc.), a vector is created off the heap to return the rectangles. The
consumers only ever iterate this data. Now we return a span over a
rectangle or rectangles that the engine must store itself.
1. For some renderers, it's always a constant 1 element. They update
   that 1 element when dirty is queried and return it in the span with a
   span size of 1.
2. For other renderers with more complex behavior, they're already
   holding a cached vector of rectangles. Now it's effectively giving
   out the ref to those in the span for iteration.

### Bitmap Runs
The `til::bitmap` used a `std::optional<std::vector<til::rectangle>>`
inside itself to cache its runs and would clear the optional when the
runs became invalidated. Unfortunately doing `.reset()` to clear the
optional will destroy the underlying vector and have it release its
memory. We know it's about to get reallocated again, so we're just going
to make it a `std::pmr::vector` and give it a memory pool. 

The alternative solution here was to use a `bool` and
`std::vector<til::rectangle>` and just flag when the vector was invalid,
but that was honestly more code changes and I love excuses to try out
PMR now.

Also, instead of returning the ref to the vector... I'm just returning a
span now. Everyone just iterates it anyway, may as well not share the
implementation detail.

### UTF-8 conversions
When testing with Terminal and looking at the `conhost.exe`'s PTY
renderer, it spends a TON of allocation time on converting all the
UTF-16 stuff inside to UTF-8 before it sends it out the PTY. This was
because `ConvertToA` was allocating a string inside itself and returning
it just to have it freed after printing and looping back around again...
as a PTY does.

The change here is to use `til::u16u8` that accepts a buffer out
parameter so the caller can just hold onto it.

## Validation Steps Performed
- [x] `big.txt` in conhost.exe (GDI renderer)
- [x] `big.txt` in Terminal (DX, PTY renderer)
- [x] Ensure WDDM and BGFX build under Razzle with this change.
This commit is contained in:
Michael Niksa 2021-02-16 12:52:33 -08:00 committed by GitHub
parent ca226d62e2
commit 525be22bd8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
36 changed files with 187 additions and 135 deletions

View file

@ -182,7 +182,7 @@ public:
void SelectNewRegion(const COORD coordStart, const COORD coordEnd) override; void SelectNewRegion(const COORD coordStart, const COORD coordEnd) override;
const COORD GetSelectionAnchor() const noexcept override; const COORD GetSelectionAnchor() const noexcept override;
const COORD GetSelectionEnd() const noexcept override; const COORD GetSelectionEnd() const noexcept override;
const std::wstring GetConsoleTitle() const noexcept override; const std::wstring_view GetConsoleTitle() const noexcept override;
void ColorSelection(const COORD coordSelectionStart, const COORD coordSelectionEnd, const TextAttribute) override; void ColorSelection(const COORD coordSelectionStart, const COORD coordSelectionEnd, const TextAttribute) override;
#pragma endregion #pragma endregion

View file

@ -215,7 +215,7 @@ void Terminal::SelectNewRegion(const COORD coordStart, const COORD coordEnd)
SetSelectionEnd(realCoordEnd, SelectionExpansionMode::Cell); SetSelectionEnd(realCoordEnd, SelectionExpansionMode::Cell);
} }
const std::wstring Terminal::GetConsoleTitle() const noexcept const std::wstring_view Terminal::GetConsoleTitle() const noexcept
try try
{ {
if (_title.has_value()) if (_title.has_value())

View file

@ -24,6 +24,8 @@ CONSOLE_INFORMATION::CONSOLE_INFORMATION() :
// ExeAliasList initialized below // ExeAliasList initialized below
_OriginalTitle(), _OriginalTitle(),
_Title(), _Title(),
_Prefix(),
_TitleAndPrefix(),
_LinkTitle(), _LinkTitle(),
Flags(0), Flags(0),
PopupCount(0), PopupCount(0),
@ -115,7 +117,12 @@ ULONG CONSOLE_INFORMATION::GetCSRecursionCount()
try try
{ {
gci.SetTitle(title); gci.SetTitle(title);
gci.SetOriginalTitle(std::wstring(TranslateConsoleTitle(gci.GetTitle().c_str(), TRUE, FALSE)));
// TranslateConsoleTitle must have a null terminated string.
// This should only happen once on startup so the copy shouldn't be costly
// but could be eliminated by rewriting TranslateConsoleTitle.
const std::wstring nullTerminatedTitle{ gci.GetTitle() };
gci.SetOriginalTitle(std::wstring(TranslateConsoleTitle(nullTerminatedTitle.c_str(), TRUE, FALSE)));
} }
catch (...) catch (...)
{ {
@ -269,6 +276,7 @@ std::pair<COLORREF, COLORREF> CONSOLE_INFORMATION::LookupAttributeColors(const T
void CONSOLE_INFORMATION::SetTitle(const std::wstring_view newTitle) void CONSOLE_INFORMATION::SetTitle(const std::wstring_view newTitle)
{ {
_Title = std::wstring{ newTitle.begin(), newTitle.end() }; _Title = std::wstring{ newTitle.begin(), newTitle.end() };
_TitleAndPrefix = _Prefix + _Title;
auto* const pRender = ServiceLocator::LocateGlobals().pRender; auto* const pRender = ServiceLocator::LocateGlobals().pRender;
if (pRender) if (pRender)
@ -284,9 +292,10 @@ void CONSOLE_INFORMATION::SetTitle(const std::wstring_view newTitle)
// - newTitlePrefix: The new value to use for the title prefix // - newTitlePrefix: The new value to use for the title prefix
// Return Value: // Return Value:
// - <none> // - <none>
void CONSOLE_INFORMATION::SetTitlePrefix(const std::wstring& newTitlePrefix) void CONSOLE_INFORMATION::SetTitlePrefix(const std::wstring_view newTitlePrefix)
{ {
_TitlePrefix = newTitlePrefix; _Prefix = newTitlePrefix;
_TitleAndPrefix = _Prefix + _Title;
auto* const pRender = ServiceLocator::LocateGlobals().pRender; auto* const pRender = ServiceLocator::LocateGlobals().pRender;
if (pRender) if (pRender)
@ -302,7 +311,7 @@ void CONSOLE_INFORMATION::SetTitlePrefix(const std::wstring& newTitlePrefix)
// - originalTitle: The new value to use for the console's original title // - originalTitle: The new value to use for the console's original title
// Return Value: // Return Value:
// - <none> // - <none>
void CONSOLE_INFORMATION::SetOriginalTitle(const std::wstring& originalTitle) void CONSOLE_INFORMATION::SetOriginalTitle(const std::wstring_view originalTitle)
{ {
_OriginalTitle = originalTitle; _OriginalTitle = originalTitle;
} }
@ -314,7 +323,7 @@ void CONSOLE_INFORMATION::SetOriginalTitle(const std::wstring& originalTitle)
// - linkTitle: The new value to use for the console's link title // - linkTitle: The new value to use for the console's link title
// Return Value: // Return Value:
// - <none> // - <none>
void CONSOLE_INFORMATION::SetLinkTitle(const std::wstring& linkTitle) void CONSOLE_INFORMATION::SetLinkTitle(const std::wstring_view linkTitle)
{ {
_LinkTitle = linkTitle; _LinkTitle = linkTitle;
} }
@ -324,8 +333,8 @@ void CONSOLE_INFORMATION::SetLinkTitle(const std::wstring& linkTitle)
// Arguments: // Arguments:
// - <none> // - <none>
// Return Value: // Return Value:
// - a reference to the console's title. // - the console's title.
const std::wstring& CONSOLE_INFORMATION::GetTitle() const noexcept const std::wstring_view CONSOLE_INFORMATION::GetTitle() const noexcept
{ {
return _Title; return _Title;
} }
@ -336,10 +345,10 @@ const std::wstring& CONSOLE_INFORMATION::GetTitle() const noexcept
// Arguments: // Arguments:
// - <none> // - <none>
// Return Value: // Return Value:
// - a new wstring containing the combined prefix and title. // - the combined prefix and title.
const std::wstring CONSOLE_INFORMATION::GetTitleAndPrefix() const const std::wstring_view CONSOLE_INFORMATION::GetTitleAndPrefix() const
{ {
return _TitlePrefix + _Title; return _TitleAndPrefix;
} }
// Method Description: // Method Description:
@ -347,8 +356,8 @@ const std::wstring CONSOLE_INFORMATION::GetTitleAndPrefix() const
// Arguments: // Arguments:
// - <none> // - <none>
// Return Value: // Return Value:
// - a reference to the console's original title. // - the console's original title.
const std::wstring& CONSOLE_INFORMATION::GetOriginalTitle() const noexcept const std::wstring_view CONSOLE_INFORMATION::GetOriginalTitle() const noexcept
{ {
return _OriginalTitle; return _OriginalTitle;
} }
@ -358,8 +367,8 @@ const std::wstring& CONSOLE_INFORMATION::GetOriginalTitle() const noexcept
// Arguments: // Arguments:
// - <none> // - <none>
// Return Value: // Return Value:
// - a reference to the console's link title. // - the console's link title.
const std::wstring& CONSOLE_INFORMATION::GetLinkTitle() const noexcept const std::wstring_view CONSOLE_INFORMATION::GetLinkTitle() const noexcept
{ {
return _LinkTitle; return _LinkTitle;
} }

View file

@ -1660,33 +1660,21 @@ void DoSrvPrivateRefreshWindow(_In_ const SCREEN_INFORMATION& screenInfo)
} }
// Get the appropriate title and length depending on the mode. // Get the appropriate title and length depending on the mode.
const wchar_t* pwszTitle; const std::wstring_view storedTitle = isOriginal ? gci.GetOriginalTitle() : gci.GetTitle();
size_t cchTitleLength;
if (isOriginal)
{
pwszTitle = gci.GetOriginalTitle().c_str();
cchTitleLength = gci.GetOriginalTitle().length();
}
else
{
pwszTitle = gci.GetTitle().c_str();
cchTitleLength = gci.GetTitle().length();
}
// Always report how much space we would need. // Always report how much space we would need.
needed = cchTitleLength; needed = storedTitle.size();
// If we have a pointer to receive the data, then copy it out. // If we have a pointer to receive the data, then copy it out.
if (title.has_value()) if (title.has_value())
{ {
HRESULT const hr = StringCchCopyNW(title->data(), title->size(), pwszTitle, cchTitleLength); HRESULT const hr = StringCchCopyNW(title->data(), title->size(), storedTitle.data(), storedTitle.size());
// Insufficient buffer is allowed. If we return a partial string, that's still OK by historical/compat standards. // Insufficient buffer is allowed. If we return a partial string, that's still OK by historical/compat standards.
// Just say how much we managed to return. // Just say how much we managed to return.
if (SUCCEEDED(hr) || STRSAFE_E_INSUFFICIENT_BUFFER == hr) if (SUCCEEDED(hr) || STRSAFE_E_INSUFFICIENT_BUFFER == hr)
{ {
written = std::min(title->size(), cchTitleLength); written = std::min(title->size(), storedTitle.size());
} }
} }
return S_OK; return S_OK;

View file

@ -318,7 +318,7 @@ const bool RenderData::IsGridLineDrawingAllowed() noexcept
// - Retrieves the title information to be displayed in the frame/edge of the window // - Retrieves the title information to be displayed in the frame/edge of the window
// Return Value: // Return Value:
// - String with title information // - String with title information
const std::wstring RenderData::GetConsoleTitle() const noexcept const std::wstring_view RenderData::GetConsoleTitle() const noexcept
{ {
const CONSOLE_INFORMATION& gci = ServiceLocator::LocateGlobals().getConsoleInformation(); const CONSOLE_INFORMATION& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
return gci.GetTitleAndPrefix(); return gci.GetTitleAndPrefix();

View file

@ -54,7 +54,7 @@ public:
const bool IsGridLineDrawingAllowed() noexcept override; const bool IsGridLineDrawingAllowed() noexcept override;
const std::wstring GetConsoleTitle() const noexcept override; const std::wstring_view GetConsoleTitle() const noexcept override;
const std::wstring GetHyperlinkUri(uint16_t id) const noexcept override; const std::wstring GetHyperlinkUri(uint16_t id) const noexcept override;
const std::wstring GetHyperlinkCustomId(uint16_t id) const noexcept override; const std::wstring GetHyperlinkCustomId(uint16_t id) const noexcept override;

View file

@ -129,13 +129,13 @@ public:
std::pair<COLORREF, COLORREF> LookupAttributeColors(const TextAttribute& attr) const noexcept; std::pair<COLORREF, COLORREF> LookupAttributeColors(const TextAttribute& attr) const noexcept;
void SetTitle(const std::wstring_view newTitle); void SetTitle(const std::wstring_view newTitle);
void SetTitlePrefix(const std::wstring& newTitlePrefix); void SetTitlePrefix(const std::wstring_view newTitlePrefix);
void SetOriginalTitle(const std::wstring& originalTitle); void SetOriginalTitle(const std::wstring_view originalTitle);
void SetLinkTitle(const std::wstring& linkTitle); void SetLinkTitle(const std::wstring_view linkTitle);
const std::wstring& GetTitle() const noexcept; const std::wstring_view GetTitle() const noexcept;
const std::wstring& GetOriginalTitle() const noexcept; const std::wstring_view GetOriginalTitle() const noexcept;
const std::wstring& GetLinkTitle() const noexcept; const std::wstring_view GetLinkTitle() const noexcept;
const std::wstring GetTitleAndPrefix() const; const std::wstring_view GetTitleAndPrefix() const;
[[nodiscard]] static NTSTATUS AllocateConsole(const std::wstring_view title); [[nodiscard]] static NTSTATUS AllocateConsole(const std::wstring_view title);
// MSFT:16886775 : get rid of friends // MSFT:16886775 : get rid of friends
@ -152,7 +152,8 @@ public:
private: private:
CRITICAL_SECTION _csConsoleLock; // serialize input and output using this CRITICAL_SECTION _csConsoleLock; // serialize input and output using this
std::wstring _Title; std::wstring _Title;
std::wstring _TitlePrefix; // Eg Select, Mark - things that we manually prepend to the title. std::wstring _Prefix; // Eg Select, Mark - things that we manually prepend to the title.
std::wstring _TitleAndPrefix;
std::wstring _OriginalTitle; std::wstring _OriginalTitle;
std::wstring _LinkTitle; // Path to .lnk file std::wstring _LinkTitle; // Path to .lnk file
SCREEN_INFORMATION* pCurrentScreenBuffer; SCREEN_INFORMATION* pCurrentScreenBuffer;

View file

@ -207,10 +207,12 @@ class ApiRoutinesTests
CONSOLE_INFORMATION& gci = ServiceLocator::LocateGlobals().getConsoleInformation(); CONSOLE_INFORMATION& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
gci.SetTitle(L"Test window title."); gci.SetTitle(L"Test window title.");
const auto title = gci.GetTitle();
int const iBytesNeeded = WideCharToMultiByte(gci.OutputCP, int const iBytesNeeded = WideCharToMultiByte(gci.OutputCP,
0, 0,
gci.GetTitle().c_str(), title.data(),
-1, gsl::narrow_cast<int>(title.size()),
nullptr, nullptr,
0, 0,
nullptr, nullptr,
@ -221,8 +223,8 @@ class ApiRoutinesTests
VERIFY_WIN32_BOOL_SUCCEEDED(WideCharToMultiByte(gci.OutputCP, VERIFY_WIN32_BOOL_SUCCEEDED(WideCharToMultiByte(gci.OutputCP,
0, 0,
gci.GetTitle().c_str(), title.data(),
-1, gsl::narrow_cast<int>(title.size()),
pszExpected.get(), pszExpected.get(),
iBytesNeeded, iBytesNeeded,
nullptr, nullptr,
@ -251,10 +253,13 @@ class ApiRoutinesTests
VERIFY_SUCCEEDED(_pApiRoutines->GetConsoleTitleWImpl(gsl::span<wchar_t>(pwszTitle, ARRAYSIZE(pwszTitle)), cchWritten, cchNeeded)); VERIFY_SUCCEEDED(_pApiRoutines->GetConsoleTitleWImpl(gsl::span<wchar_t>(pwszTitle, ARRAYSIZE(pwszTitle)), cchWritten, cchNeeded));
VERIFY_ARE_NOT_EQUAL(0u, cchWritten); VERIFY_ARE_NOT_EQUAL(0u, cchWritten);
const auto title = gci.GetTitle();
// NOTE: W version of API returns string length. A version of API returns buffer length (string + null). // NOTE: W version of API returns string length. A version of API returns buffer length (string + null).
VERIFY_ARE_EQUAL(gci.GetTitle().length(), cchWritten); VERIFY_ARE_EQUAL(title.length(), cchWritten);
VERIFY_ARE_EQUAL(gci.GetTitle().length(), cchNeeded); VERIFY_ARE_EQUAL(title.length(), cchNeeded);
VERIFY_ARE_EQUAL(WEX::Common::String(gci.GetTitle().c_str()), WEX::Common::String(pwszTitle)); VERIFY_ARE_EQUAL(WEX::Common::String(title.data(), gsl::narrow_cast<int>(title.size())), WEX::Common::String(pwszTitle));
} }
TEST_METHOD(ApiGetConsoleOriginalTitleA) TEST_METHOD(ApiGetConsoleOriginalTitleA)
@ -262,10 +267,12 @@ class ApiRoutinesTests
CONSOLE_INFORMATION& gci = ServiceLocator::LocateGlobals().getConsoleInformation(); CONSOLE_INFORMATION& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
gci.SetOriginalTitle(L"Test original window title."); gci.SetOriginalTitle(L"Test original window title.");
const auto originalTitle = gci.GetOriginalTitle();
int const iBytesNeeded = WideCharToMultiByte(gci.OutputCP, int const iBytesNeeded = WideCharToMultiByte(gci.OutputCP,
0, 0,
gci.GetOriginalTitle().c_str(), originalTitle.data(),
-1, gsl::narrow_cast<int>(originalTitle.size()),
nullptr, nullptr,
0, 0,
nullptr, nullptr,
@ -276,8 +283,8 @@ class ApiRoutinesTests
VERIFY_WIN32_BOOL_SUCCEEDED(WideCharToMultiByte(gci.OutputCP, VERIFY_WIN32_BOOL_SUCCEEDED(WideCharToMultiByte(gci.OutputCP,
0, 0,
gci.GetOriginalTitle().c_str(), originalTitle.data(),
-1, gsl::narrow_cast<int>(originalTitle.size()),
pszExpected.get(), pszExpected.get(),
iBytesNeeded, iBytesNeeded,
nullptr, nullptr,
@ -306,10 +313,12 @@ class ApiRoutinesTests
VERIFY_SUCCEEDED(_pApiRoutines->GetConsoleOriginalTitleWImpl(gsl::span<wchar_t>(pwszTitle, ARRAYSIZE(pwszTitle)), cchWritten, cchNeeded)); VERIFY_SUCCEEDED(_pApiRoutines->GetConsoleOriginalTitleWImpl(gsl::span<wchar_t>(pwszTitle, ARRAYSIZE(pwszTitle)), cchWritten, cchNeeded));
VERIFY_ARE_NOT_EQUAL(0u, cchWritten); VERIFY_ARE_NOT_EQUAL(0u, cchWritten);
const auto originalTitle = gci.GetOriginalTitle();
// NOTE: W version of API returns string length. A version of API returns buffer length (string + null). // NOTE: W version of API returns string length. A version of API returns buffer length (string + null).
VERIFY_ARE_EQUAL(gci.GetOriginalTitle().length(), cchWritten); VERIFY_ARE_EQUAL(originalTitle.length(), cchWritten);
VERIFY_ARE_EQUAL(gci.GetOriginalTitle().length(), cchNeeded); VERIFY_ARE_EQUAL(originalTitle.length(), cchNeeded);
VERIFY_ARE_EQUAL(WEX::Common::String(gci.GetOriginalTitle().c_str()), WEX::Common::String(pwszTitle)); VERIFY_ARE_EQUAL(WEX::Common::String(originalTitle.data(), gsl::narrow_cast<int>(originalTitle.size())), WEX::Common::String(pwszTitle));
} }
static void s_AdjustOutputWait(const bool fShouldBlock) static void s_AdjustOutputWait(const bool fShouldBlock)

View file

@ -355,9 +355,9 @@ public:
return false; return false;
} }
const std::wstring GetConsoleTitle() const noexcept override const std::wstring_view GetConsoleTitle() const noexcept override
{ {
return std::wstring{}; return std::wstring_view{};
} }
const bool IsSelectionActive() const override const bool IsSelectionActive() const override

View file

@ -263,7 +263,7 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned"
return const_iterator(_bits, _sz, _sz.area()); return const_iterator(_bits, _sz, _sz.area());
} }
const std::vector<til::rectangle, run_allocator_type>& runs() const const gsl::span<const til::rectangle> runs() const
{ {
// If we don't have cached runs, rebuild. // If we don't have cached runs, rebuild.
if (!_runs.has_value()) if (!_runs.has_value())
@ -271,7 +271,7 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned"
_runs.emplace(begin(), end()); _runs.emplace(begin(), end());
} }
// Return a reference to the runs. // Return the runs.
return _runs.value(); return _runs.value();
} }

View file

@ -230,7 +230,7 @@ BgfxEngine::BgfxEngine(PVOID SharedViewBase, LONG DisplayHeight, LONG DisplayWid
return S_OK; return S_OK;
} }
std::vector<til::rectangle> BgfxEngine::GetDirtyArea() [[nodiscard]] HRESULT BgfxEngine::GetDirtyArea(gsl::span<const til::rectangle>& area) noexcept
{ {
SMALL_RECT r; SMALL_RECT r;
r.Bottom = _displayHeight > 0 ? (SHORT)(_displayHeight - 1) : 0; r.Bottom = _displayHeight > 0 ? (SHORT)(_displayHeight - 1) : 0;
@ -238,7 +238,12 @@ std::vector<til::rectangle> BgfxEngine::GetDirtyArea()
r.Left = 0; r.Left = 0;
r.Right = _displayWidth > 0 ? (SHORT)(_displayWidth - 1) : 0; r.Right = _displayWidth > 0 ? (SHORT)(_displayWidth - 1) : 0;
return { r }; _dirtyArea = r;
area = { &_dirtyArea,
1 };
return S_OK;
} }
[[nodiscard]] HRESULT BgfxEngine::GetFontSize(_Out_ COORD* const pFontSize) noexcept [[nodiscard]] HRESULT BgfxEngine::GetFontSize(_Out_ COORD* const pFontSize) noexcept
@ -260,7 +265,7 @@ std::vector<til::rectangle> BgfxEngine::GetDirtyArea()
// - newTitle: the new string to use for the title of the window // - newTitle: the new string to use for the title of the window
// Return Value: // Return Value:
// - S_OK // - S_OK
[[nodiscard]] HRESULT BgfxEngine::_DoUpdateTitle(_In_ const std::wstring& /*newTitle*/) noexcept [[nodiscard]] HRESULT BgfxEngine::_DoUpdateTitle(_In_ const std::wstring_view /*newTitle*/) noexcept
{ {
return S_OK; return S_OK;
} }

View file

@ -67,12 +67,12 @@ namespace Microsoft::Console::Render
[[nodiscard]] HRESULT GetProposedFont(const FontInfoDesired& fiFontInfoDesired, FontInfo& fiFontInfo, int const iDpi) noexcept override; [[nodiscard]] HRESULT GetProposedFont(const FontInfoDesired& fiFontInfoDesired, FontInfo& fiFontInfo, int const iDpi) noexcept override;
std::vector<til::rectangle> GetDirtyArea() override; [[nodiscard]] HRESULT GetDirtyArea(gsl::span<const til::rectangle>& area) noexcept override;
[[nodiscard]] HRESULT GetFontSize(_Out_ COORD* const pFontSize) noexcept override; [[nodiscard]] HRESULT GetFontSize(_Out_ COORD* const pFontSize) noexcept override;
[[nodiscard]] HRESULT IsGlyphWideByFont(const std::wstring_view glyph, _Out_ bool* const pResult) noexcept override; [[nodiscard]] HRESULT IsGlyphWideByFont(const std::wstring_view glyph, _Out_ bool* const pResult) noexcept override;
protected: protected:
[[nodiscard]] HRESULT _DoUpdateTitle(_In_ const std::wstring& newTitle) noexcept override; [[nodiscard]] HRESULT _DoUpdateTitle(_In_ const std::wstring_view newTitle) noexcept override;
private: private:
ULONG_PTR _sharedViewBase; ULONG_PTR _sharedViewBase;
@ -80,6 +80,7 @@ namespace Microsoft::Console::Render
LONG _displayHeight; LONG _displayHeight;
LONG _displayWidth; LONG _displayWidth;
til::rectangle _dirtyArea;
COORD _fontSize; COORD _fontSize;

View file

@ -289,11 +289,17 @@ void Window::_UpdateSystemMetrics() const
} }
} }
// CreateWindowExW needs a null terminated string, so ensure
// title is null terminated in a std::wstring here.
// We don't mind the string copy here because making the window
// should be infrequent.
const std::wstring title{ gci.GetTitle() };
// Attempt to create window // Attempt to create window
HWND hWnd = CreateWindowExW( HWND hWnd = CreateWindowExW(
CONSOLE_WINDOW_EX_FLAGS, CONSOLE_WINDOW_EX_FLAGS,
CONSOLE_WINDOW_CLASS, CONSOLE_WINDOW_CLASS,
gci.GetTitle().c_str(), title.c_str(),
CONSOLE_WINDOW_FLAGS, CONSOLE_WINDOW_FLAGS,
WI_IsFlagSet(gci.Flags, CONSOLE_AUTO_POSITION) ? CW_USEDEFAULT : rectProposed.left, WI_IsFlagSet(gci.Flags, CONSOLE_AUTO_POSITION) ? CW_USEDEFAULT : rectProposed.left,
rectProposed.top, // field is ignored if CW_USEDEFAULT was chosen above rectProposed.top, // field is ignored if CW_USEDEFAULT was chosen above

View file

@ -687,7 +687,10 @@ using namespace Microsoft::Console::Types;
case CM_UPDATE_TITLE: case CM_UPDATE_TITLE:
{ {
SetWindowTextW(hWnd, gci.GetTitleAndPrefix().c_str()); // SetWindowTextW needs null terminated string so assign view to string.
const std::wstring titleAndPrefix{ gci.GetTitleAndPrefix() };
SetWindowTextW(hWnd, titleAndPrefix.c_str());
break; break;
} }

View file

@ -13,7 +13,7 @@ RenderEngineBase::RenderEngineBase() :
{ {
} }
HRESULT RenderEngineBase::InvalidateTitle(const std::wstring& proposedTitle) noexcept HRESULT RenderEngineBase::InvalidateTitle(const std::wstring_view proposedTitle) noexcept
{ {
if (proposedTitle != _lastFrameTitle) if (proposedTitle != _lastFrameTitle)
{ {
@ -23,7 +23,7 @@ HRESULT RenderEngineBase::InvalidateTitle(const std::wstring& proposedTitle) noe
return S_OK; return S_OK;
} }
HRESULT RenderEngineBase::UpdateTitle(const std::wstring& newTitle) noexcept HRESULT RenderEngineBase::UpdateTitle(const std::wstring_view newTitle) noexcept
{ {
HRESULT hr = S_FALSE; HRESULT hr = S_FALSE;
if (newTitle != _lastFrameTitle) if (newTitle != _lastFrameTitle)

View file

@ -467,7 +467,7 @@ void Renderer::TriggerCircling()
// - <none> // - <none>
void Renderer::TriggerTitleChange() void Renderer::TriggerTitleChange()
{ {
const std::wstring newTitle = _pData->GetConsoleTitle(); const auto newTitle = _pData->GetConsoleTitle();
for (IRenderEngine* const pEngine : _rgpEngines) for (IRenderEngine* const pEngine : _rgpEngines)
{ {
LOG_IF_FAILED(pEngine->InvalidateTitle(newTitle)); LOG_IF_FAILED(pEngine->InvalidateTitle(newTitle));
@ -483,7 +483,7 @@ void Renderer::TriggerTitleChange()
// - the HRESULT of the underlying engine's UpdateTitle call. // - the HRESULT of the underlying engine's UpdateTitle call.
HRESULT Renderer::_PaintTitle(IRenderEngine* const pEngine) HRESULT Renderer::_PaintTitle(IRenderEngine* const pEngine)
{ {
const std::wstring newTitle = _pData->GetConsoleTitle(); const auto newTitle = _pData->GetConsoleTitle();
return pEngine->UpdateTitle(newTitle); return pEngine->UpdateTitle(newTitle);
} }
@ -627,9 +627,10 @@ void Renderer::_PaintBufferOutput(_In_ IRenderEngine* const pEngine)
// This is effectively the number of cells on the visible screen that need to be redrawn. // This is effectively the number of cells on the visible screen that need to be redrawn.
// The origin is always 0, 0 because it represents the screen itself, not the underlying buffer. // The origin is always 0, 0 because it represents the screen itself, not the underlying buffer.
const auto dirtyAreas = pEngine->GetDirtyArea(); gsl::span<const til::rectangle> dirtyAreas;
LOG_IF_FAILED(pEngine->GetDirtyArea(dirtyAreas));
for (const auto dirtyRect : dirtyAreas) for (const auto& dirtyRect : dirtyAreas)
{ {
auto dirty = Viewport::FromInclusive(dirtyRect); auto dirty = Viewport::FromInclusive(dirtyRect);
@ -1044,7 +1045,10 @@ void Renderer::_PaintOverlay(IRenderEngine& engine,
// Set it up in a Viewport helper structure and trim it the IME viewport to be within the full console viewport. // Set it up in a Viewport helper structure and trim it the IME viewport to be within the full console viewport.
Viewport viewConv = Viewport::FromInclusive(srCaView); Viewport viewConv = Viewport::FromInclusive(srCaView);
for (SMALL_RECT srDirty : engine.GetDirtyArea()) gsl::span<const til::rectangle> dirtyAreas;
LOG_IF_FAILED(engine.GetDirtyArea(dirtyAreas));
for (SMALL_RECT srDirty : dirtyAreas)
{ {
// Dirty is an inclusive rectangle, but oddly enough the IME was an exclusive one, so correct it. // Dirty is an inclusive rectangle, but oddly enough the IME was an exclusive one, so correct it.
srDirty.Bottom++; srDirty.Bottom++;
@ -1101,13 +1105,14 @@ void Renderer::_PaintSelection(_In_ IRenderEngine* const pEngine)
{ {
try try
{ {
auto dirtyAreas = pEngine->GetDirtyArea(); gsl::span<const til::rectangle> dirtyAreas;
LOG_IF_FAILED(pEngine->GetDirtyArea(dirtyAreas));
// Get selection rectangles // Get selection rectangles
const auto rectangles = _GetSelectionRects(); const auto rectangles = _GetSelectionRects();
for (auto rect : rectangles) for (auto rect : rectangles)
{ {
for (auto dirtyRect : dirtyAreas) for (auto& dirtyRect : dirtyAreas)
{ {
// Make a copy as `TrimToViewport` will manipulate it and // Make a copy as `TrimToViewport` will manipulate it and
// can destroy it for the next dirtyRect to test against. // can destroy it for the next dirtyRect to test against.

View file

@ -66,7 +66,8 @@ using namespace Microsoft::Console::Types;
DxEngine::DxEngine() : DxEngine::DxEngine() :
RenderEngineBase(), RenderEngineBase(),
_invalidateFullRows{ true }, _invalidateFullRows{ true },
_invalidMap{}, _pool{ til::pmr::get_default_resource() },
_invalidMap{ &_pool },
_invalidScroll{}, _invalidScroll{},
_allInvalid{ false }, _allInvalid{ false },
_firstFrame{ true }, _firstFrame{ true },
@ -2087,13 +2088,16 @@ float DxEngine::GetScaling() const noexcept
// Routine Description: // Routine Description:
// - Gets the area that we currently believe is dirty within the character cell grid // - Gets the area that we currently believe is dirty within the character cell grid
// Arguments: // Arguments:
// - <none> // - area - Rectangle describing dirty area in characters.
// Return Value: // Return Value:
// - Rectangle describing dirty area in characters. // - S_OK
[[nodiscard]] std::vector<til::rectangle> DxEngine::GetDirtyArea() [[nodiscard]] HRESULT DxEngine::GetDirtyArea(gsl::span<const til::rectangle>& area) noexcept
try
{ {
return _invalidMap.runs(); area = _invalidMap.runs();
return S_OK;
} }
CATCH_RETURN();
// Routine Description: // Routine Description:
// - Gets the current font size // - Gets the current font size
@ -2141,7 +2145,7 @@ CATCH_RETURN();
// - newTitle: the new string to use for the title of the window // - newTitle: the new string to use for the title of the window
// Return Value: // Return Value:
// - S_OK // - S_OK
[[nodiscard]] HRESULT DxEngine::_DoUpdateTitle(_In_ const std::wstring& /*newTitle*/) noexcept [[nodiscard]] HRESULT DxEngine::_DoUpdateTitle(_In_ const std::wstring_view /*newTitle*/) noexcept
{ {
if (_hwndTarget != INVALID_HANDLE_VALUE) if (_hwndTarget != INVALID_HANDLE_VALUE)
{ {

View file

@ -113,7 +113,7 @@ namespace Microsoft::Console::Render
[[nodiscard]] HRESULT GetProposedFont(const FontInfoDesired& fiFontInfoDesired, FontInfo& fiFontInfo, int const iDpi) noexcept override; [[nodiscard]] HRESULT GetProposedFont(const FontInfoDesired& fiFontInfoDesired, FontInfo& fiFontInfo, int const iDpi) noexcept override;
[[nodiscard]] std::vector<til::rectangle> GetDirtyArea() override; [[nodiscard]] HRESULT GetDirtyArea(gsl::span<const til::rectangle>& area) noexcept override;
[[nodiscard]] HRESULT GetFontSize(_Out_ COORD* const pFontSize) noexcept override; [[nodiscard]] HRESULT GetFontSize(_Out_ COORD* const pFontSize) noexcept override;
[[nodiscard]] HRESULT IsGlyphWideByFont(const std::wstring_view glyph, _Out_ bool* const pResult) noexcept override; [[nodiscard]] HRESULT IsGlyphWideByFont(const std::wstring_view glyph, _Out_ bool* const pResult) noexcept override;
@ -130,7 +130,7 @@ namespace Microsoft::Console::Render
void UpdateHyperlinkHoveredId(const uint16_t hoveredId) noexcept; void UpdateHyperlinkHoveredId(const uint16_t hoveredId) noexcept;
protected: protected:
[[nodiscard]] HRESULT _DoUpdateTitle(_In_ const std::wstring& newTitle) noexcept override; [[nodiscard]] HRESULT _DoUpdateTitle(_In_ const std::wstring_view newTitle) noexcept override;
[[nodiscard]] HRESULT _PaintTerminalEffects() noexcept; [[nodiscard]] HRESULT _PaintTerminalEffects() noexcept;
[[nodiscard]] bool _FullRepaintNeeded() const noexcept; [[nodiscard]] bool _FullRepaintNeeded() const noexcept;
@ -181,7 +181,8 @@ namespace Microsoft::Console::Render
bool _firstFrame; bool _firstFrame;
bool _invalidateFullRows; bool _invalidateFullRows;
til::bitmap _invalidMap; std::pmr::unsynchronized_pool_resource _pool;
til::pmr::bitmap _invalidMap;
til::point _invalidScroll; til::point _invalidScroll;
bool _allInvalid; bool _allInvalid;

View file

@ -66,12 +66,12 @@ namespace Microsoft::Console::Render
_Out_ FontInfo& Font, _Out_ FontInfo& Font,
const int iDpi) noexcept override; const int iDpi) noexcept override;
[[nodiscard]] std::vector<til::rectangle> GetDirtyArea() override; [[nodiscard]] HRESULT GetDirtyArea(gsl::span<const til::rectangle>& area) noexcept override;
[[nodiscard]] HRESULT GetFontSize(_Out_ COORD* const pFontSize) noexcept override; [[nodiscard]] HRESULT GetFontSize(_Out_ COORD* const pFontSize) noexcept override;
[[nodiscard]] HRESULT IsGlyphWideByFont(const std::wstring_view glyph, _Out_ bool* const pResult) noexcept override; [[nodiscard]] HRESULT IsGlyphWideByFont(const std::wstring_view glyph, _Out_ bool* const pResult) noexcept override;
protected: protected:
[[nodiscard]] HRESULT _DoUpdateTitle(_In_ const std::wstring& newTitle) noexcept override; [[nodiscard]] HRESULT _DoUpdateTitle(_In_ const std::wstring_view newTitle) noexcept override;
private: private:
HWND _hwndTargetWindow; HWND _hwndTargetWindow;
@ -82,6 +82,7 @@ namespace Microsoft::Console::Render
bool _fPaintStarted; bool _fPaintStarted;
til::rectangle _invalidCharacters;
PAINTSTRUCT _psInvalidData; PAINTSTRUCT _psInvalidData;
HDC _hdcMemoryContext; HDC _hdcMemoryContext;
bool _isTrueTypeFont; bool _isTrueTypeFont;

View file

@ -12,18 +12,22 @@ using namespace Microsoft::Console::Render;
// Routine Description: // Routine Description:
// - Gets the size in characters of the current dirty portion of the frame. // - Gets the size in characters of the current dirty portion of the frame.
// Arguments: // Arguments:
// - <none> // - area - The character dimensions of the current dirty area of the frame.
// Return Value:
// - The character dimensions of the current dirty area of the frame.
// This is an Inclusive rect. // This is an Inclusive rect.
std::vector<til::rectangle> GdiEngine::GetDirtyArea() // Return Value:
// - S_OK or math failure
[[nodiscard]] HRESULT GdiEngine::GetDirtyArea(gsl::span<const til::rectangle>& area) noexcept
{ {
RECT rc = _psInvalidData.rcPaint; RECT rc = _psInvalidData.rcPaint;
SMALL_RECT sr = { 0 }; SMALL_RECT sr = { 0 };
LOG_IF_FAILED(_ScaleByFont(&rc, &sr)); RETURN_IF_FAILED(_ScaleByFont(&rc, &sr));
return { sr }; _invalidCharacters = sr;
area = { &_invalidCharacters, 1 };
return S_OK;
} }
// Routine Description: // Routine Description:

View file

@ -31,6 +31,7 @@ GdiEngine::GdiEngine() :
_lastBg(INVALID_COLOR), _lastBg(INVALID_COLOR),
_lastFontItalic(false), _lastFontItalic(false),
_fPaintStarted(false), _fPaintStarted(false),
_invalidCharacters{},
_hfont(nullptr), _hfont(nullptr),
_hfontItalic(nullptr), _hfontItalic(nullptr),
_pool{ til::pmr::get_default_resource() }, // It's important the pool is first so it can be given to the others on construction. _pool{ til::pmr::get_default_resource() }, // It's important the pool is first so it can be given to the others on construction.
@ -392,7 +393,7 @@ GdiEngine::~GdiEngine()
// - newTitle: the new string to use for the title of the window // - newTitle: the new string to use for the title of the window
// Return Value: // Return Value:
// - S_OK if PostMessageW succeeded, otherwise E_FAIL // - S_OK if PostMessageW succeeded, otherwise E_FAIL
[[nodiscard]] HRESULT GdiEngine::_DoUpdateTitle(_In_ const std::wstring& /*newTitle*/) noexcept [[nodiscard]] HRESULT GdiEngine::_DoUpdateTitle(_In_ const std::wstring_view /*newTitle*/) noexcept
{ {
// the CM_UPDATE_TITLE handler in windowproc will query the updated title. // the CM_UPDATE_TITLE handler in windowproc will query the updated title.
return PostMessageW(_hwndTargetWindow, CM_UPDATE_TITLE, 0, (LPARAM) nullptr) ? S_OK : E_FAIL; return PostMessageW(_hwndTargetWindow, CM_UPDATE_TITLE, 0, (LPARAM) nullptr) ? S_OK : E_FAIL;

View file

@ -64,7 +64,7 @@ namespace Microsoft::Console::Render
virtual const std::vector<RenderOverlay> GetOverlays() const noexcept = 0; virtual const std::vector<RenderOverlay> GetOverlays() const noexcept = 0;
virtual const bool IsGridLineDrawingAllowed() noexcept = 0; virtual const bool IsGridLineDrawingAllowed() noexcept = 0;
virtual const std::wstring GetConsoleTitle() const noexcept = 0; virtual const std::wstring_view GetConsoleTitle() const noexcept = 0;
virtual const std::wstring GetHyperlinkUri(uint16_t id) const noexcept = 0; virtual const std::wstring GetHyperlinkUri(uint16_t id) const noexcept = 0;
virtual const std::wstring GetHyperlinkCustomId(uint16_t id) const noexcept = 0; virtual const std::wstring GetHyperlinkCustomId(uint16_t id) const noexcept = 0;

View file

@ -71,7 +71,7 @@ namespace Microsoft::Console::Render
[[nodiscard]] virtual HRESULT InvalidateAll() noexcept = 0; [[nodiscard]] virtual HRESULT InvalidateAll() noexcept = 0;
[[nodiscard]] virtual HRESULT InvalidateCircling(_Out_ bool* const pForcePaint) noexcept = 0; [[nodiscard]] virtual HRESULT InvalidateCircling(_Out_ bool* const pForcePaint) noexcept = 0;
[[nodiscard]] virtual HRESULT InvalidateTitle(const std::wstring& proposedTitle) noexcept = 0; [[nodiscard]] virtual HRESULT InvalidateTitle(const std::wstring_view proposedTitle) noexcept = 0;
[[nodiscard]] virtual HRESULT PrepareRenderInfo(const RenderFrameInfo& info) noexcept = 0; [[nodiscard]] virtual HRESULT PrepareRenderInfo(const RenderFrameInfo& info) noexcept = 0;
@ -100,10 +100,10 @@ namespace Microsoft::Console::Render
_Out_ FontInfo& FontInfo, _Out_ FontInfo& FontInfo,
const int iDpi) noexcept = 0; const int iDpi) noexcept = 0;
virtual std::vector<til::rectangle> GetDirtyArea() = 0; [[nodiscard]] virtual HRESULT GetDirtyArea(gsl::span<const til::rectangle>& area) noexcept = 0;
[[nodiscard]] virtual HRESULT GetFontSize(_Out_ COORD* const pFontSize) noexcept = 0; [[nodiscard]] virtual HRESULT GetFontSize(_Out_ COORD* const pFontSize) noexcept = 0;
[[nodiscard]] virtual HRESULT IsGlyphWideByFont(const std::wstring_view glyph, _Out_ bool* const pResult) noexcept = 0; [[nodiscard]] virtual HRESULT IsGlyphWideByFont(const std::wstring_view glyph, _Out_ bool* const pResult) noexcept = 0;
[[nodiscard]] virtual HRESULT UpdateTitle(const std::wstring& newTitle) noexcept = 0; [[nodiscard]] virtual HRESULT UpdateTitle(const std::wstring_view newTitle) noexcept = 0;
}; };
inline Microsoft::Console::Render::IRenderEngine::~IRenderEngine() {} inline Microsoft::Console::Render::IRenderEngine::~IRenderEngine() {}

View file

@ -34,9 +34,9 @@ namespace Microsoft::Console::Render
RenderEngineBase& operator=(RenderEngineBase&&) = default; RenderEngineBase& operator=(RenderEngineBase&&) = default;
public: public:
[[nodiscard]] HRESULT InvalidateTitle(const std::wstring& proposedTitle) noexcept override; [[nodiscard]] HRESULT InvalidateTitle(const std::wstring_view proposedTitle) noexcept override;
[[nodiscard]] HRESULT UpdateTitle(const std::wstring& newTitle) noexcept override; [[nodiscard]] HRESULT UpdateTitle(const std::wstring_view newTitle) noexcept override;
[[nodiscard]] HRESULT PrepareRenderInfo(const RenderFrameInfo& info) noexcept override; [[nodiscard]] HRESULT PrepareRenderInfo(const RenderFrameInfo& info) noexcept override;
@ -45,7 +45,7 @@ namespace Microsoft::Console::Render
void WaitUntilCanRender() noexcept override; void WaitUntilCanRender() noexcept override;
protected: protected:
[[nodiscard]] virtual HRESULT _DoUpdateTitle(const std::wstring& newTitle) noexcept = 0; [[nodiscard]] virtual HRESULT _DoUpdateTitle(const std::wstring_view newTitle) noexcept = 0;
bool _titleChanged; bool _titleChanged;
std::wstring _lastFrameTitle; std::wstring _lastFrameTitle;

View file

@ -427,12 +427,16 @@ CATCH_RETURN();
// - Gets the area that we currently believe is dirty within the character cell grid // - Gets the area that we currently believe is dirty within the character cell grid
// - Not currently used by UiaEngine. // - Not currently used by UiaEngine.
// Arguments: // Arguments:
// - <none> // - area - Rectangle describing dirty area in characters.
// Return Value: // Return Value:
// - Rectangle describing dirty area in characters. // - S_OK.
[[nodiscard]] std::vector<til::rectangle> UiaEngine::GetDirtyArea() [[nodiscard]] HRESULT UiaEngine::GetDirtyArea(gsl::span<const til::rectangle>& area) noexcept
{ {
return { Viewport::Empty().ToInclusive() }; // Magic static is only valid because any instance of this object has the same behavior.
// Use member variable instead if this ever changes.
const static til::rectangle empty;
area = { &empty, 1 };
return S_OK;
} }
// Routine Description: // Routine Description:
@ -465,7 +469,7 @@ CATCH_RETURN();
// - newTitle: the new string to use for the title of the window // - newTitle: the new string to use for the title of the window
// Return Value: // Return Value:
// - S_FALSE // - S_FALSE
[[nodiscard]] HRESULT UiaEngine::_DoUpdateTitle(_In_ const std::wstring& /*newTitle*/) noexcept [[nodiscard]] HRESULT UiaEngine::_DoUpdateTitle(_In_ const std::wstring_view /*newTitle*/) noexcept
{ {
return S_FALSE; return S_FALSE;
} }

View file

@ -69,12 +69,12 @@ namespace Microsoft::Console::Render
[[nodiscard]] HRESULT GetProposedFont(const FontInfoDesired& fiFontInfoDesired, FontInfo& fiFontInfo, int const iDpi) noexcept override; [[nodiscard]] HRESULT GetProposedFont(const FontInfoDesired& fiFontInfoDesired, FontInfo& fiFontInfo, int const iDpi) noexcept override;
[[nodiscard]] std::vector<til::rectangle> GetDirtyArea() override; [[nodiscard]] HRESULT GetDirtyArea(gsl::span<const til::rectangle>& area) noexcept override;
[[nodiscard]] HRESULT GetFontSize(_Out_ COORD* const pFontSize) noexcept override; [[nodiscard]] HRESULT GetFontSize(_Out_ COORD* const pFontSize) noexcept override;
[[nodiscard]] HRESULT IsGlyphWideByFont(const std::wstring_view glyph, _Out_ bool* const pResult) noexcept override; [[nodiscard]] HRESULT IsGlyphWideByFont(const std::wstring_view glyph, _Out_ bool* const pResult) noexcept override;
protected: protected:
[[nodiscard]] HRESULT _DoUpdateTitle(const std::wstring& newTitle) noexcept override; [[nodiscard]] HRESULT _DoUpdateTitle(const std::wstring_view newTitle) noexcept override;
private: private:
bool _isEnabled; bool _isEnabled;

View file

@ -57,7 +57,8 @@ XtermEngine::XtermEngine(_In_ wil::unique_hfile hPipe,
} }
else else
{ {
const auto dirty = GetDirtyArea(); gsl::span<const til::rectangle> dirty;
RETURN_IF_FAILED(GetDirtyArea(dirty));
// If we have 0 or 1 dirty pieces in the area, set as appropriate. // If we have 0 or 1 dirty pieces in the area, set as appropriate.
Viewport dirtyView = dirty.empty() ? Viewport::Empty() : Viewport::FromInclusive(til::at(dirty, 0)); Viewport dirtyView = dirty.empty() ? Viewport::Empty() : Viewport::FromInclusive(til::at(dirty, 0));
@ -540,7 +541,7 @@ CATCH_RETURN();
// - newTitle: the new string to use for the title of the window // - newTitle: the new string to use for the title of the window
// Return Value: // Return Value:
// - S_OK // - S_OK
[[nodiscard]] HRESULT XtermEngine::_DoUpdateTitle(const std::wstring& newTitle) noexcept [[nodiscard]] HRESULT XtermEngine::_DoUpdateTitle(const std::wstring_view newTitle) noexcept
{ {
// inbox telnet uses xterm-ascii as its mode. If we're in ascii mode, don't // inbox telnet uses xterm-ascii as its mode. If we're in ascii mode, don't
// do anything, to maintain compatibility. // do anything, to maintain compatibility.

View file

@ -59,7 +59,7 @@ namespace Microsoft::Console::Render
[[nodiscard]] HRESULT _MoveCursor(const COORD coord) noexcept override; [[nodiscard]] HRESULT _MoveCursor(const COORD coord) noexcept override;
[[nodiscard]] HRESULT _DoUpdateTitle(const std::wstring& newTitle) noexcept override; [[nodiscard]] HRESULT _DoUpdateTitle(const std::wstring_view newTitle) noexcept override;
#ifdef UNIT_TESTING #ifdef UNIT_TESTING
friend class VtRendererTest; friend class VtRendererTest;

View file

@ -13,13 +13,14 @@ using namespace Microsoft::Console::Types;
// Routine Description: // Routine Description:
// - Gets the size in characters of the current dirty portion of the frame. // - Gets the size in characters of the current dirty portion of the frame.
// Arguments: // Arguments:
// - <none> // - area - The character dimensions of the current dirty area of the frame.
// This is an Inclusive rect.
// Return Value: // Return Value:
// - The character dimensions of the current dirty area of the frame. // - S_OK.
// This is an Inclusive rect. [[nodiscard]] HRESULT VtEngine::GetDirtyArea(gsl::span<const til::rectangle>& area) noexcept
std::vector<til::rectangle> VtEngine::GetDirtyArea()
{ {
return _invalidMap.runs(); area = _invalidMap.runs();
return S_OK;
} }
// Routine Description: // Routine Description:

View file

@ -598,7 +598,7 @@ using namespace Microsoft::Console::Types;
// - newTitle: the new string to use for the title of the window // - newTitle: the new string to use for the title of the window
// Return Value: // Return Value:
// - S_OK // - S_OK
[[nodiscard]] HRESULT VtEngine::_DoUpdateTitle(const std::wstring& /*newTitle*/) noexcept [[nodiscard]] HRESULT VtEngine::_DoUpdateTitle(const std::wstring_view /*newTitle*/) noexcept
{ {
return S_OK; return S_OK;
} }

View file

@ -31,7 +31,8 @@ VtEngine::VtEngine(_In_ wil::unique_hfile pipe,
_hFile(std::move(pipe)), _hFile(std::move(pipe)),
_lastTextAttributes(INVALID_COLOR, INVALID_COLOR), _lastTextAttributes(INVALID_COLOR, INVALID_COLOR),
_lastViewport(initialViewport), _lastViewport(initialViewport),
_invalidMap(initialViewport.Dimensions()), _pool(til::pmr::get_default_resource()),
_invalidMap(initialViewport.Dimensions(), false, &_pool),
_lastText({ 0 }), _lastText({ 0 }),
_scrollDelta({ 0, 0 }), _scrollDelta({ 0, 0 }),
_quickReturn(false), _quickReturn(false),
@ -50,7 +51,10 @@ VtEngine::VtEngine(_In_ wil::unique_hfile pipe,
_deferredCursorPos{ INVALID_COORDS }, _deferredCursorPos{ INVALID_COORDS },
_inResizeRequest{ false }, _inResizeRequest{ false },
_trace{}, _trace{},
_bufferLine{} _bufferLine{},
_buffer{},
_formatBuffer{},
_conversionBuffer{}
{ {
#ifndef UNIT_TESTING #ifndef UNIT_TESTING
// When unit testing, we can instantiate a VtEngine without a pipe. // When unit testing, we can instantiate a VtEngine without a pipe.
@ -144,12 +148,8 @@ VtEngine::VtEngine(_In_ wil::unique_hfile pipe,
// - S_OK or suitable HRESULT error from either conversion or writing pipe. // - S_OK or suitable HRESULT error from either conversion or writing pipe.
[[nodiscard]] HRESULT VtEngine::_WriteTerminalUtf8(const std::wstring_view wstr) noexcept [[nodiscard]] HRESULT VtEngine::_WriteTerminalUtf8(const std::wstring_view wstr) noexcept
{ {
try RETURN_IF_FAILED(til::u16u8(wstr, _conversionBuffer));
{ return _Write(_conversionBuffer);
const auto converted = ConvertToA(CP_UTF8, wstr);
return _Write(converted);
}
CATCH_RETURN();
} }
// Method Description: // Method Description:

View file

@ -145,7 +145,7 @@ void RenderTracing::TraceInvalidateScroll(const til::point scroll) const
} }
void RenderTracing::TraceStartPaint(const bool quickReturn, void RenderTracing::TraceStartPaint(const bool quickReturn,
const til::bitmap& invalidMap, const til::pmr::bitmap& invalidMap,
const til::rectangle lastViewport, const til::rectangle lastViewport,
const til::point scrollDelt, const til::point scrollDelt,
const bool cursorMoved, const bool cursorMoved,

View file

@ -39,7 +39,7 @@ namespace Microsoft::Console::VirtualTerminal
void TraceTriggerCircling(const bool newFrame) const; void TraceTriggerCircling(const bool newFrame) const;
void TraceInvalidateScroll(const til::point scroll) const; void TraceInvalidateScroll(const til::point scroll) const;
void TraceStartPaint(const bool quickReturn, void TraceStartPaint(const bool quickReturn,
const til::bitmap& invalidMap, const til::pmr::bitmap& invalidMap,
const til::rectangle lastViewport, const til::rectangle lastViewport,
const til::point scrollDelta, const til::point scrollDelta,
const bool cursorMoved, const bool cursorMoved,

View file

@ -85,7 +85,7 @@ namespace Microsoft::Console::Render
_Out_ FontInfo& Font, _Out_ FontInfo& Font,
const int iDpi) noexcept override; const int iDpi) noexcept override;
std::vector<til::rectangle> GetDirtyArea() override; [[nodiscard]] HRESULT GetDirtyArea(gsl::span<const til::rectangle>& area) noexcept override;
[[nodiscard]] HRESULT GetFontSize(_Out_ COORD* const pFontSize) noexcept override; [[nodiscard]] HRESULT GetFontSize(_Out_ COORD* const pFontSize) noexcept override;
[[nodiscard]] HRESULT IsGlyphWideByFont(const std::wstring_view glyph, _Out_ bool* const pResult) noexcept override; [[nodiscard]] HRESULT IsGlyphWideByFont(const std::wstring_view glyph, _Out_ bool* const pResult) noexcept override;
@ -113,12 +113,14 @@ namespace Microsoft::Console::Render
std::string _buffer; std::string _buffer;
std::string _formatBuffer; std::string _formatBuffer;
std::string _conversionBuffer;
TextAttribute _lastTextAttributes; TextAttribute _lastTextAttributes;
Microsoft::Console::Types::Viewport _lastViewport; Microsoft::Console::Types::Viewport _lastViewport;
til::bitmap _invalidMap; std::pmr::unsynchronized_pool_resource _pool;
til::pmr::bitmap _invalidMap;
COORD _lastText; COORD _lastText;
til::point _scrollDelta; til::point _scrollDelta;
@ -222,7 +224,7 @@ namespace Microsoft::Console::Render
[[nodiscard]] HRESULT _WriteTerminalUtf8(const std::wstring_view str) noexcept; [[nodiscard]] HRESULT _WriteTerminalUtf8(const std::wstring_view str) noexcept;
[[nodiscard]] HRESULT _WriteTerminalAscii(const std::wstring_view str) noexcept; [[nodiscard]] HRESULT _WriteTerminalAscii(const std::wstring_view str) noexcept;
[[nodiscard]] virtual HRESULT _DoUpdateTitle(const std::wstring& newTitle) noexcept override; [[nodiscard]] virtual HRESULT _DoUpdateTitle(const std::wstring_view newTitle) noexcept override;
/////////////////////////// Unit Testing Helpers /////////////////////////// /////////////////////////// Unit Testing Helpers ///////////////////////////
#ifdef UNIT_TESTING #ifdef UNIT_TESTING

View file

@ -353,7 +353,7 @@ bool WddmConEngine::IsInitialized()
return S_OK; return S_OK;
} }
std::vector<til::rectangle> WddmConEngine::GetDirtyArea() [[nodiscard]] HRESULT WddmConEngine::GetDirtyArea(gsl::span<const til::rectangle>& area) noexcept
{ {
SMALL_RECT r; SMALL_RECT r;
r.Bottom = _displayHeight > 0 ? (SHORT)(_displayHeight - 1) : 0; r.Bottom = _displayHeight > 0 ? (SHORT)(_displayHeight - 1) : 0;
@ -361,7 +361,12 @@ std::vector<til::rectangle> WddmConEngine::GetDirtyArea()
r.Left = 0; r.Left = 0;
r.Right = _displayWidth > 0 ? (SHORT)(_displayWidth - 1) : 0; r.Right = _displayWidth > 0 ? (SHORT)(_displayWidth - 1) : 0;
return { r }; _dirtyArea = r;
area = { &_dirtyArea,
1 };
return S_OK;
} }
RECT WddmConEngine::GetDisplaySize() RECT WddmConEngine::GetDisplaySize()
@ -409,7 +414,7 @@ RECT WddmConEngine::GetDisplaySize()
// - newTitle: the new string to use for the title of the window // - newTitle: the new string to use for the title of the window
// Return Value: // Return Value:
// - S_OK // - S_OK
[[nodiscard]] HRESULT WddmConEngine::_DoUpdateTitle(_In_ const std::wstring& /*newTitle*/) noexcept [[nodiscard]] HRESULT WddmConEngine::_DoUpdateTitle(_In_ const std::wstring_view /*newTitle*/) noexcept
{ {
return S_OK; return S_OK;
} }

View file

@ -59,12 +59,12 @@ namespace Microsoft::Console::Render
[[nodiscard]] HRESULT GetProposedFont(const FontInfoDesired& fiFontInfoDesired, FontInfo& fiFontInfo, int const iDpi) noexcept override; [[nodiscard]] HRESULT GetProposedFont(const FontInfoDesired& fiFontInfoDesired, FontInfo& fiFontInfo, int const iDpi) noexcept override;
std::vector<til::rectangle> GetDirtyArea() override; [[nodiscard]] HRESULT GetDirtyArea(gsl::span<const til::rectangle>& area) noexcept override;
[[nodiscard]] HRESULT GetFontSize(_Out_ COORD* const pFontSize) noexcept override; [[nodiscard]] HRESULT GetFontSize(_Out_ COORD* const pFontSize) noexcept override;
[[nodiscard]] HRESULT IsGlyphWideByFont(const std::wstring_view glyph, _Out_ bool* const pResult) noexcept override; [[nodiscard]] HRESULT IsGlyphWideByFont(const std::wstring_view glyph, _Out_ bool* const pResult) noexcept override;
protected: protected:
[[nodiscard]] HRESULT _DoUpdateTitle(_In_ const std::wstring& newTitle) noexcept override; [[nodiscard]] HRESULT _DoUpdateTitle(_In_ const std::wstring_view newTitle) noexcept override;
private: private:
HANDLE _hWddmConCtx; HANDLE _hWddmConCtx;
@ -75,6 +75,7 @@ namespace Microsoft::Console::Render
// Variables // Variables
LONG _displayHeight; LONG _displayHeight;
LONG _displayWidth; LONG _displayWidth;
til::rectangle _dirtyArea;
PCD_IO_ROW_INFORMATION* _displayState; PCD_IO_ROW_INFORMATION* _displayState;