diff --git a/src/types/UiaTextRangeBase.cpp b/src/types/UiaTextRangeBase.cpp index 804d4758540..9326809b8fc 100644 --- a/src/types/UiaTextRangeBase.cpp +++ b/src/types/UiaTextRangeBase.cpp @@ -181,9 +181,9 @@ const COORD UiaTextRangeBase::GetEndpoint(TextPatternRangeEndpoint endpoint) con // - val - the value that it will be set to // Return Value: // - true if range is degenerate, false otherwise. -bool UiaTextRangeBase::SetEndpoint(TextPatternRangeEndpoint endpoint, const COORD val) +bool UiaTextRangeBase::SetEndpoint(TextPatternRangeEndpoint endpoint, const COORD val) noexcept { - const auto bufferSize = _pData->GetTextBuffer().GetSize(); + const auto bufferSize = _getBufferSize(); switch (endpoint) { case TextPatternRangeEndpoint::TextPatternRangeEndpoint_End: @@ -301,7 +301,7 @@ IFACEMETHODIMP UiaTextRangeBase::ExpandToEnclosingUnit(_In_ TextUnit unit) noexc try { const auto& buffer = _pData->GetTextBuffer(); - const auto bufferSize = buffer.GetSize(); + const auto bufferSize = _getBufferSize(); const auto bufferEnd = bufferSize.EndExclusive(); if (unit == TextUnit::TextUnit_Character) @@ -314,6 +314,13 @@ IFACEMETHODIMP UiaTextRangeBase::ExpandToEnclosingUnit(_In_ TextUnit unit) noexc // expand to word _start = buffer.GetWordStart(_start, _wordDelimiters, true); _end = buffer.GetWordEnd(_start, _wordDelimiters, true); + + // GetWordEnd may return the actual end of the TextBuffer. + // If so, just set it to this value of bufferEnd + if (!bufferSize.IsInBounds(_end)) + { + _end = bufferEnd; + } } else if (unit <= TextUnit::TextUnit_Line) { @@ -359,7 +366,7 @@ try *ppRetVal = nullptr; const std::wstring queryText{ text, SysStringLen(text) }; - const auto bufferSize = _pData->GetTextBuffer().GetSize(); + const auto bufferSize = _getBufferSize(); const auto sensitivity = ignoreCase ? Search::Sensitivity::CaseInsensitive : Search::Sensitivity::CaseSensitive; auto searchDirection = Search::Direction::Forward; @@ -436,7 +443,7 @@ IFACEMETHODIMP UiaTextRangeBase::GetBoundingRectangles(_Outptr_result_maybenull_ // set of coords. std::vector coords; - const auto bufferSize = _pData->GetTextBuffer().GetSize(); + const auto bufferSize = _getBufferSize(); // these viewport vars are converted to the buffer coordinate space const auto viewport = bufferSize.ConvertToOrigin(_pData->GetViewport()); @@ -970,6 +977,25 @@ const unsigned int UiaTextRangeBase::_getViewportHeight(const SMALL_RECT viewpor return viewport.Bottom - viewport.Top + 1; } +// Routine Description: +// - Gets a viewport representing where valid text may be in the TextBuffer +// - Use this instead of `textBuffer.GetSize()`. This improves performance +// because it's a smaller space to have to search through +// Arguments: +// - +// Return Value: +// - A viewport representing the portion of the TextBuffer that has valid text +const Viewport UiaTextRangeBase::_getBufferSize() const noexcept +{ + // we need to add 1 to the X/Y of textBufferEnd + // because we want the returned viewport to include this COORD + const auto textBufferEnd = _pData->GetTextBufferEndPosition(); + const auto width = base::ClampAdd(1, textBufferEnd.X); + const auto height = base::ClampAdd(1, textBufferEnd.Y); + + return Viewport::FromDimensions({ 0, 0 }, width, height); +} + // Routine Description: // - adds the relevant coordinate points from the row to coords. // - it is assumed that startAnchor and endAnchor are within the same row @@ -1038,7 +1064,7 @@ void UiaTextRangeBase::_getBoundingRect(_In_ const COORD startAnchor, _In_ const void UiaTextRangeBase::_moveEndpointByUnitCharacter(_In_ const int moveCount, _In_ const TextPatternRangeEndpoint endpoint, _Out_ gsl::not_null const pAmountMoved, - _In_ const bool preventBufferEnd) + _In_ const bool preventBufferEnd) noexcept { *pAmountMoved = 0; @@ -1049,7 +1075,7 @@ void UiaTextRangeBase::_moveEndpointByUnitCharacter(_In_ const int moveCount, const bool allowBottomExclusive = !preventBufferEnd; const MovementDirection moveDirection = (moveCount > 0) ? MovementDirection::Forward : MovementDirection::Backward; - const auto bufferSize = _pData->GetTextBuffer().GetSize(); + const auto bufferSize = _getBufferSize(); bool success = true; auto target = GetEndpoint(endpoint); @@ -1106,10 +1132,10 @@ void UiaTextRangeBase::_moveEndpointByUnitWord(_In_ const int moveCount, const bool allowBottomExclusive = !preventBufferEnd; const MovementDirection moveDirection = (moveCount > 0) ? MovementDirection::Forward : MovementDirection::Backward; const auto& buffer = _pData->GetTextBuffer(); - const auto bufferSize = buffer.GetSize(); + const auto bufferSize = _getBufferSize(); const auto bufferOrigin = bufferSize.Origin(); const auto bufferEnd = bufferSize.EndExclusive(); - const auto lastCharPos = buffer.GetLastNonSpaceCharacter(); + const auto lastCharPos = buffer.GetLastNonSpaceCharacter(bufferSize); auto resultPos = GetEndpoint(endpoint); auto nextPos = resultPos; @@ -1180,7 +1206,7 @@ void UiaTextRangeBase::_moveEndpointByUnitWord(_In_ const int moveCount, void UiaTextRangeBase::_moveEndpointByUnitLine(_In_ const int moveCount, _In_ const TextPatternRangeEndpoint endpoint, _Out_ gsl::not_null const pAmountMoved, - _In_ const bool preventBufferEnd) + _In_ const bool preventBufferEnd) noexcept { *pAmountMoved = 0; @@ -1191,7 +1217,7 @@ void UiaTextRangeBase::_moveEndpointByUnitLine(_In_ const int moveCount, const bool allowBottomExclusive = !preventBufferEnd; const MovementDirection moveDirection = (moveCount > 0) ? MovementDirection::Forward : MovementDirection::Backward; - const auto bufferSize = _pData->GetTextBuffer().GetSize(); + const auto bufferSize = _getBufferSize(); bool success = true; auto resultPos = GetEndpoint(endpoint); @@ -1264,7 +1290,7 @@ void UiaTextRangeBase::_moveEndpointByUnitLine(_In_ const int moveCount, void UiaTextRangeBase::_moveEndpointByUnitDocument(_In_ const int moveCount, _In_ const TextPatternRangeEndpoint endpoint, _Out_ gsl::not_null const pAmountMoved, - _In_ const bool preventBufferEnd) + _In_ const bool preventBufferEnd) noexcept { *pAmountMoved = 0; @@ -1274,7 +1300,7 @@ void UiaTextRangeBase::_moveEndpointByUnitDocument(_In_ const int moveCount, } const MovementDirection moveDirection = (moveCount > 0) ? MovementDirection::Forward : MovementDirection::Backward; - const auto bufferSize = _pData->GetTextBuffer().GetSize(); + const auto bufferSize = _getBufferSize(); const auto target = GetEndpoint(endpoint); switch (moveDirection) diff --git a/src/types/UiaTextRangeBase.hpp b/src/types/UiaTextRangeBase.hpp index 389807b0d31..aa56a3c4261 100644 --- a/src/types/UiaTextRangeBase.hpp +++ b/src/types/UiaTextRangeBase.hpp @@ -87,7 +87,7 @@ namespace Microsoft::Console::Types const IdType GetId() const noexcept; const COORD GetEndpoint(TextPatternRangeEndpoint endpoint) const noexcept; - bool SetEndpoint(TextPatternRangeEndpoint endpoint, const COORD val); + bool SetEndpoint(TextPatternRangeEndpoint endpoint, const COORD val) noexcept; const bool IsDegenerate() const noexcept; // ITextRangeProvider methods @@ -159,6 +159,7 @@ namespace Microsoft::Console::Types virtual const COORD _getScreenFontSize() const; const unsigned int _getViewportHeight(const SMALL_RECT viewport) const noexcept; + const Viewport _getBufferSize() const noexcept; void _getBoundingRect(_In_ const COORD startAnchor, _In_ const COORD endAnchor, _Inout_ std::vector& coords) const; @@ -166,7 +167,7 @@ namespace Microsoft::Console::Types _moveEndpointByUnitCharacter(_In_ const int moveCount, _In_ const TextPatternRangeEndpoint endpoint, _Out_ gsl::not_null const pAmountMoved, - _In_ const bool preventBufferEnd = false); + _In_ const bool preventBufferEnd = false) noexcept; void _moveEndpointByUnitWord(_In_ const int moveCount, @@ -178,13 +179,13 @@ namespace Microsoft::Console::Types _moveEndpointByUnitLine(_In_ const int moveCount, _In_ const TextPatternRangeEndpoint endpoint, _Out_ gsl::not_null const pAmountMoved, - _In_ const bool preventBufferEnd = false); + _In_ const bool preventBufferEnd = false) noexcept; void _moveEndpointByUnitDocument(_In_ const int moveCount, _In_ const TextPatternRangeEndpoint endpoint, _Out_ gsl::not_null const pAmountMoved, - _In_ const bool preventBufferEnd = false); + _In_ const bool preventBufferEnd = false) noexcept; #ifdef UNIT_TESTING friend class ::UiaTextRangeTests;