From b3fab518f8e887f64c360eb3ae6acc8db9a877a1 Mon Sep 17 00:00:00 2001 From: Leonard Hecker Date: Thu, 13 Jan 2022 22:09:29 +0100 Subject: [PATCH] Prepare til wrappers for migrating off of SMALL_RECT (#11902) This commit makes the following changes to `til::point/size/rectangle` for the following reasons: * Rename `rectangle` into `rect` This will make the naming consistent with a later `small_rect` struct as well as the existing Win32 POINT/SIZE/RECT structs. * Standardizes til wrappers on `int32_t` instead of `ptrdiff_t` Provides a consistent behavior between x86 and x64, preventing accidental errors on x86, as it's less rigorously tested than x64. Additionally it improves interop with MIDL3 which only supports fixed width integer types. * Standardizes til wrappers on throwing `gsl::narrow_error` Makes the behavior of our code more consistent. * Makes all eligible functions `constexpr` Because why not. * Removes implicit constructors and conversion operators This is a complex and controversial topic. My reasons are: You can't Ctrl+F for an implicit conversion. This breaks most non-IDE engines, like the one on GitHub or those we have internally at MS. This is important for me as these implicit conversion operators aren't cost free. Narrowing integers itself, as well as the boundary checks that need to be done have a certain, fixed overhead each time. Additionally the lack of noexcept prevents many advanced compiler optimizations. Removing their use entirely drops conhost's code segment size by around ~6.5%. ## References Preliminary work for #4015. ## PR Checklist * [x] I work here * [x] Tests added/passed ## Validation Steps Performed I'm mostly relying on our unit tests here. Both OpenConsole and WT appear to work fine. --- src/buffer/out/textBuffer.cpp | 58 +- .../PublicTerminalCore/HwndTerminal.cpp | 28 +- src/cascadia/TerminalControl/ControlCore.cpp | 35 +- src/cascadia/TerminalControl/ControlCore.h | 4 +- .../TerminalControl/ControlInteractivity.cpp | 68 +- .../TerminalControl/ControlInteractivity.h | 28 +- .../InteractivityAutomationPeer.cpp | 10 +- .../InteractivityAutomationPeer.h | 4 +- .../TerminalControl/TSFInputControl.cpp | 32 +- src/cascadia/TerminalControl/TermControl.cpp | 45 +- src/cascadia/TerminalCore/Terminal.cpp | 18 +- .../TerminalCore/TerminalSelection.cpp | 4 +- .../TerminalCore/terminalrenderdata.cpp | 2 +- .../ControlInteractivityTests.cpp | 74 +- .../ConptyRoundtripTests.cpp | 249 ++-- src/cascadia/WinRTUtils/inc/Utils.h | 17 - src/cascadia/WindowsTerminal/AppHost.cpp | 36 +- src/cascadia/WindowsTerminal/IslandWindow.cpp | 87 +- src/cascadia/WindowsTerminal/IslandWindow.h | 2 +- .../WindowsTerminal/NonClientIslandWindow.cpp | 34 +- .../WindowsTerminal/NonClientIslandWindow.h | 2 +- .../WindowsTerminal/NotificationIcon.cpp | 4 +- .../WindowsTerminal/NotificationIcon.h | 2 +- src/host/readData.hpp | 2 + src/host/ut_host/TextBufferTests.cpp | 4 +- src/host/ut_host/VtRendererTests.cpp | 28 +- src/inc/consoletaeftemplates.hpp | 56 +- src/inc/til.h | 19 +- src/inc/til/bitmap.h | 65 +- src/inc/til/math.h | 47 +- src/inc/til/operators.h | 32 +- src/inc/til/point.h | 383 ++---- src/inc/til/rect.h | 860 ++++++++++++++ src/inc/til/rectangle.h | 955 --------------- src/inc/til/size.h | 306 ++--- src/inc/til/some.h | 18 +- src/interactivity/onecore/BgfxEngine.cpp | 11 +- src/interactivity/onecore/BgfxEngine.hpp | 4 +- .../GeneratedUiaTextRangeMovementTests.g.cpp | 54 +- .../UiaTextRangeTests.cpp | 176 +-- src/renderer/atlas/AtlasEngine.api.cpp | 2 +- src/renderer/atlas/AtlasEngine.cpp | 10 +- src/renderer/atlas/AtlasEngine.h | 4 +- src/renderer/base/FontResource.cpp | 14 +- src/renderer/base/renderer.cpp | 33 +- src/renderer/dx/CustomTextLayout.cpp | 2 +- src/renderer/dx/CustomTextRenderer.cpp | 15 +- src/renderer/dx/DxFontRenderData.cpp | 6 +- src/renderer/dx/DxRenderer.cpp | 83 +- src/renderer/dx/DxRenderer.hpp | 6 +- src/renderer/gdi/gdirenderer.hpp | 4 +- src/renderer/gdi/math.cpp | 4 +- src/renderer/gdi/state.cpp | 4 +- src/renderer/inc/IRenderEngine.hpp | 2 +- src/renderer/uia/UiaRenderer.cpp | 4 +- src/renderer/uia/UiaRenderer.hpp | 2 +- src/renderer/vt/XtermEngine.cpp | 20 +- src/renderer/vt/invalidate.cpp | 4 +- src/renderer/vt/math.cpp | 2 +- src/renderer/vt/paint.cpp | 4 +- src/renderer/vt/state.cpp | 8 +- src/renderer/vt/tracing.cpp | 6 +- src/renderer/vt/tracing.hpp | 6 +- src/renderer/vt/vtrenderer.hpp | 2 +- src/renderer/wddmcon/WddmConRenderer.cpp | 11 +- src/renderer/wddmcon/WddmConRenderer.hpp | 4 +- src/terminal/adapter/FontBuffer.cpp | 4 +- src/terminal/adapter/FontBuffer.hpp | 2 +- src/terminal/adapter/adaptDispatch.cpp | 2 +- .../adapter/ut_adapter/adapterTest.cpp | 2 +- .../parser/InputStateMachineEngine.cpp | 4 +- src/til/ut_til/BitmapTests.cpp | 168 ++- src/til/ut_til/MathTests.cpp | 146 +-- src/til/ut_til/PointTests.cpp | 503 +++----- src/til/ut_til/RectangleTests.cpp | 1024 +++++++---------- src/til/ut_til/SPSCTests.cpp | 2 + src/til/ut_til/SizeTests.cpp | 311 ++--- src/types/UiaTextRangeBase.cpp | 48 +- src/types/UiaTextRangeBase.hpp | 2 +- tools/ConsoleTypes.natvis | 2 +- tools/TestTableWriter/GenerateTests.ps1 | 10 +- 81 files changed, 2704 insertions(+), 3651 deletions(-) create mode 100644 src/inc/til/rect.h delete mode 100644 src/inc/til/rectangle.h diff --git a/src/buffer/out/textBuffer.cpp b/src/buffer/out/textBuffer.cpp index 7a098a78c2..36266710a8 100644 --- a/src/buffer/out/textBuffer.cpp +++ b/src/buffer/out/textBuffer.cpp @@ -1076,7 +1076,7 @@ const COORD TextBuffer::GetWordStart(const COORD target, const std::wstring_view #pragma warning(suppress : 26496) auto copy{ target }; const auto bufferSize{ GetSize() }; - const auto limit{ limitOptional.value_or(bufferSize.EndExclusive()) }; + const auto limit{ limitOptional.value_or(til::point{ bufferSize.EndExclusive() }) }; if (target == bufferSize.Origin()) { // can't expand left @@ -1088,10 +1088,10 @@ const COORD TextBuffer::GetWordStart(const COORD target, const std::wstring_view // that it actually points to a space in the buffer copy = { bufferSize.RightInclusive(), bufferSize.BottomInclusive() }; } - else if (bufferSize.CompareInBounds(target, limit, true) >= 0) + else if (bufferSize.CompareInBounds(target, limit.to_win32_coord(), true) >= 0) { // if at/past the limit --> clamp to limit - copy = *limitOptional; + copy = limitOptional->to_win32_coord(); } if (accessibilityMode) @@ -1203,15 +1203,15 @@ const COORD TextBuffer::GetWordEnd(const COORD target, const std::wstring_view w // Already at/past the limit. Can't move forward. const auto bufferSize{ GetSize() }; - const auto limit{ limitOptional.value_or(bufferSize.EndExclusive()) }; - if (bufferSize.CompareInBounds(target, limit, true) >= 0) + const auto limit{ limitOptional.value_or(til::point{ bufferSize.EndExclusive() }) }; + if (bufferSize.CompareInBounds(target, limit.to_win32_coord(), true) >= 0) { return target; } if (accessibilityMode) { - return _GetWordEndForAccessibility(target, wordDelimiters, limit); + return _GetWordEndForAccessibility(target, wordDelimiters, limit.to_win32_coord()); } else { @@ -1366,10 +1366,10 @@ bool TextBuffer::MoveToNextWord(COORD& pos, const std::wstring_view wordDelimite // NOTE: _GetWordEnd...() returns the exclusive position of the "end of the word" // This is also the inclusive start of the next word. const auto bufferSize{ GetSize() }; - const auto limit{ limitOptional.value_or(bufferSize.EndExclusive()) }; - const auto copy{ _GetWordEndForAccessibility(pos, wordDelimiters, limit) }; + const auto limit{ limitOptional.value_or(til::point{ bufferSize.EndExclusive() }) }; + const auto copy{ _GetWordEndForAccessibility(pos, wordDelimiters, limit.to_win32_coord()) }; - if (bufferSize.CompareInBounds(copy, limit, true) >= 0) + if (bufferSize.CompareInBounds(copy, limit.to_win32_coord(), true) >= 0) { return false; } @@ -1411,23 +1411,23 @@ bool TextBuffer::MoveToPreviousWord(COORD& pos, std::wstring_view wordDelimiters // - pos - The COORD for the first cell of the current glyph (inclusive) const til::point TextBuffer::GetGlyphStart(const til::point pos, std::optional limitOptional) const { - COORD resultPos = pos; + COORD resultPos = pos.to_win32_coord(); const auto bufferSize = GetSize(); - const auto limit{ limitOptional.value_or(bufferSize.EndExclusive()) }; + const auto limit{ limitOptional.value_or(til::point{ bufferSize.EndExclusive() }) }; // Clamp pos to limit - if (bufferSize.CompareInBounds(resultPos, limit, true) > 0) + if (bufferSize.CompareInBounds(resultPos, limit.to_win32_coord(), true) > 0) { - resultPos = limit; + resultPos = limit.to_win32_coord(); } // limit is exclusive, so we need to move back to be within valid bounds - if (resultPos != limit && GetCellDataAt(resultPos)->DbcsAttr().IsTrailing()) + if (resultPos != limit.to_win32_coord() && GetCellDataAt(resultPos)->DbcsAttr().IsTrailing()) { bufferSize.DecrementInBounds(resultPos, true); } - return resultPos; + return til::point{ resultPos }; } // Method Description: @@ -1439,17 +1439,17 @@ const til::point TextBuffer::GetGlyphStart(const til::point pos, std::optional limitOptional) const { - COORD resultPos = pos; + COORD resultPos = pos.to_win32_coord(); const auto bufferSize = GetSize(); - const auto limit{ limitOptional.value_or(bufferSize.EndExclusive()) }; + const auto limit{ limitOptional.value_or(til::point{ bufferSize.EndExclusive() }) }; // Clamp pos to limit - if (bufferSize.CompareInBounds(resultPos, limit, true) > 0) + if (bufferSize.CompareInBounds(resultPos, limit.to_win32_coord(), true) > 0) { - resultPos = limit; + resultPos = limit.to_win32_coord(); } - if (resultPos != limit && GetCellDataAt(resultPos)->DbcsAttr().IsLeading()) + if (resultPos != limit.to_win32_coord() && GetCellDataAt(resultPos)->DbcsAttr().IsLeading()) { bufferSize.IncrementInBounds(resultPos, true); } @@ -1459,7 +1459,7 @@ const til::point TextBuffer::GetGlyphEnd(const til::point pos, bool accessibilit { bufferSize.IncrementInBounds(resultPos, true); } - return resultPos; + return til::point{ resultPos }; } // Method Description: @@ -1474,9 +1474,9 @@ const til::point TextBuffer::GetGlyphEnd(const til::point pos, bool accessibilit bool TextBuffer::MoveToNextGlyph(til::point& pos, bool allowExclusiveEnd, std::optional limitOptional) const { const auto bufferSize = GetSize(); - const auto limit{ limitOptional.value_or(bufferSize.EndExclusive()) }; + const auto limit{ limitOptional.value_or(til::point{ bufferSize.EndExclusive() }) }; - const auto distanceToLimit{ bufferSize.CompareInBounds(pos, limit, true) }; + const auto distanceToLimit{ bufferSize.CompareInBounds(pos.to_win32_coord(), limit.to_win32_coord(), true) }; if (distanceToLimit >= 0) { // Corner Case: we're on/past the limit @@ -1493,7 +1493,7 @@ bool TextBuffer::MoveToNextGlyph(til::point& pos, bool allowExclusiveEnd, std::o } // Try to move forward, but if we hit the buffer boundary, we fail to move. - auto iter{ GetCellDataAt(pos, bufferSize) }; + auto iter{ GetCellDataAt(pos.to_win32_coord(), bufferSize) }; const bool success{ ++iter }; // Move again if we're on a wide glyph @@ -1502,7 +1502,7 @@ bool TextBuffer::MoveToNextGlyph(til::point& pos, bool allowExclusiveEnd, std::o ++iter; } - pos = iter.Pos(); + pos = til::point{ iter.Pos() }; return success; } @@ -1515,11 +1515,11 @@ bool TextBuffer::MoveToNextGlyph(til::point& pos, bool allowExclusiveEnd, std::o // - pos - The COORD for the first cell of the previous glyph (inclusive) bool TextBuffer::MoveToPreviousGlyph(til::point& pos, std::optional limitOptional) const { - COORD resultPos = pos; + COORD resultPos = pos.to_win32_coord(); const auto bufferSize = GetSize(); - const auto limit{ limitOptional.value_or(bufferSize.EndExclusive()) }; + const auto limit{ limitOptional.value_or(til::point{ bufferSize.EndExclusive() }) }; - if (bufferSize.CompareInBounds(pos, limit, true) > 0) + if (bufferSize.CompareInBounds(pos.to_win32_coord(), limit.to_win32_coord(), true) > 0) { // we're past the end // clamp us to the limit @@ -1534,7 +1534,7 @@ bool TextBuffer::MoveToPreviousGlyph(til::point& pos, std::optional bufferSize.DecrementInBounds(resultPos, true); } - pos = resultPos; + pos = til::point{ resultPos }; return success; } diff --git a/src/cascadia/PublicTerminalCore/HwndTerminal.cpp b/src/cascadia/PublicTerminalCore/HwndTerminal.cpp index 7ce785831b..7242267569 100644 --- a/src/cascadia/PublicTerminalCore/HwndTerminal.cpp +++ b/src/cascadia/PublicTerminalCore/HwndTerminal.cpp @@ -549,11 +549,11 @@ try if (multiClickMapper == 3) { - _terminal->MultiClickSelection(cursorPosition / fontSize, ::Terminal::SelectionExpansion::Line); + _terminal->MultiClickSelection((cursorPosition / fontSize).to_win32_coord(), ::Terminal::SelectionExpansion::Line); } else if (multiClickMapper == 2) { - _terminal->MultiClickSelection(cursorPosition / fontSize, ::Terminal::SelectionExpansion::Word); + _terminal->MultiClickSelection((cursorPosition / fontSize).to_win32_coord(), ::Terminal::SelectionExpansion::Word); } else { @@ -582,19 +582,25 @@ try RETURN_HR_IF(E_NOT_VALID_STATE, fontSize.area() == 0); // either dimension = 0, area == 0 - if (this->_singleClickTouchdownPos) + // This is a copy of ControlInteractivity::PointerMoved + if (_singleClickTouchdownPos) { - const auto& touchdownPoint{ *this->_singleClickTouchdownPos }; - const auto distance{ std::sqrtf(std::powf(cursorPosition.x() - touchdownPoint.x(), 2) + std::powf(cursorPosition.y() - touchdownPoint.y(), 2)) }; - if (distance >= (std::min(fontSize.width(), fontSize.height()) / 4.f)) + const auto touchdownPoint = *_singleClickTouchdownPos; + const auto dx = cursorPosition.x - touchdownPoint.x; + const auto dy = cursorPosition.y - touchdownPoint.y; + const auto w = fontSize.width; + const auto distanceSquared = dx * dx + dy * dy; + const auto maxDistanceSquared = w * w / 16; // (w / 4)^2 + + if (distanceSquared >= maxDistanceSquared) { - _terminal->SetSelectionAnchor(touchdownPoint / fontSize); + _terminal->SetSelectionAnchor((touchdownPoint / fontSize).to_win32_coord()); // stop tracking the touchdown point _singleClickTouchdownPos = std::nullopt; } } - this->_terminal->SetSelectionEnd(cursorPosition / fontSize); + this->_terminal->SetSelectionEnd((cursorPosition / fontSize).to_win32_coord()); this->_renderer->TriggerSelection(); return S_OK; @@ -696,9 +702,9 @@ try wheelDelta = HIWORD(wParam); // If it's a *WHEEL event, it's in screen coordinates, not window (?!) - POINT coordsToTransform = cursorPosition; + POINT coordsToTransform = cursorPosition.to_win32_point(); ScreenToClient(_hwnd.get(), &coordsToTransform); - cursorPosition = coordsToTransform; + cursorPosition = til::point{ coordsToTransform }; } const TerminalInput::MouseButtonState state{ @@ -707,7 +713,7 @@ try WI_IsFlagSet(GetKeyState(VK_RBUTTON), KeyPressed) }; - return _terminal->SendMouseEvent(cursorPosition / fontSize, uMsg, getControlKeyState(), wheelDelta, state); + return _terminal->SendMouseEvent((cursorPosition / fontSize).to_win32_coord(), uMsg, getControlKeyState(), wheelDelta, state); } catch (...) { diff --git a/src/cascadia/TerminalControl/ControlCore.cpp b/src/cascadia/TerminalControl/ControlCore.cpp index 7ec3056a6a..0e5f2916f0 100644 --- a/src/cascadia/TerminalControl/ControlCore.cpp +++ b/src/cascadia/TerminalControl/ControlCore.cpp @@ -423,7 +423,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation const short wheelDelta, const TerminalInput::MouseButtonState state) { - return _terminal->SendMouseEvent(viewportPos, uiButton, states, wheelDelta, state); + return _terminal->SendMouseEvent(viewportPos.to_win32_coord(), uiButton, states, wheelDelta, state); } void ControlCore::UserScrollViewport(const int viewTop) @@ -546,12 +546,12 @@ namespace winrt::Microsoft::Terminal::Control::implementation _lastHoveredCell = terminalPosition; uint16_t newId{ 0u }; // we can't use auto here because we're pre-declaring newInterval. - decltype(_terminal->GetHyperlinkIntervalFromPosition(til::point{})) newInterval{ std::nullopt }; + decltype(_terminal->GetHyperlinkIntervalFromPosition(COORD{})) newInterval{ std::nullopt }; if (terminalPosition.has_value()) { auto lock = _terminal->LockForReading(); // Lock for the duration of our reads. - newId = _terminal->GetHyperlinkIdAtPosition(*terminalPosition); - newInterval = _terminal->GetHyperlinkIntervalFromPosition(*terminalPosition); + newId = _terminal->GetHyperlinkIdAtPosition(terminalPosition->to_win32_coord()); + newInterval = _terminal->GetHyperlinkIntervalFromPosition(terminalPosition->to_win32_coord()); } // If the hyperlink ID changed or the interval changed, trigger a redraw all @@ -577,11 +577,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation } } - winrt::hstring ControlCore::GetHyperlink(const til::point pos) const + winrt::hstring ControlCore::GetHyperlink(const Core::Point pos) const { // Lock for the duration of our reads. auto lock = _terminal->LockForReading(); - return winrt::hstring{ _terminal->GetHyperlinkAtPosition(pos) }; + return winrt::hstring{ _terminal->GetHyperlinkAtPosition(til::point{ pos }.to_win32_coord()) }; } winrt::hstring ControlCore::HoveredUriText() const @@ -589,14 +589,14 @@ namespace winrt::Microsoft::Terminal::Control::implementation auto lock = _terminal->LockForReading(); // Lock for the duration of our reads. if (_lastHoveredCell.has_value()) { - return winrt::hstring{ _terminal->GetHyperlinkAtPosition(*_lastHoveredCell) }; + return winrt::hstring{ _terminal->GetHyperlinkAtPosition(_lastHoveredCell->to_win32_coord()) }; } return {}; } Windows::Foundation::IReference ControlCore::HoveredCell() const { - return _lastHoveredCell.has_value() ? Windows::Foundation::IReference{ _lastHoveredCell.value() } : nullptr; + return _lastHoveredCell.has_value() ? Windows::Foundation::IReference{ _lastHoveredCell.value().to_core_point() } : nullptr; } // Method Description: @@ -938,7 +938,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation void ControlCore::SetSelectionAnchor(til::point const& position) { auto lock = _terminal->LockForWriting(); - _terminal->SetSelectionAnchor(position); + _terminal->SetSelectionAnchor(position.to_win32_coord()); } // Method Description: @@ -956,16 +956,13 @@ namespace winrt::Microsoft::Terminal::Control::implementation // you move its endpoints while it is generating a frame. auto lock = _terminal->LockForWriting(); - const short lastVisibleRow = std::max(_terminal->GetViewport().Height() - 1, 0); - const short lastVisibleCol = std::max(_terminal->GetViewport().Width() - 1, 0); - til::point terminalPosition{ - std::clamp(position.x(), 0, lastVisibleCol), - std::clamp(position.y(), 0, lastVisibleRow) + std::clamp(position.x, 0, _terminal->GetViewport().Width() - 1), + std::clamp(position.y, 0, _terminal->GetViewport().Height() - 1) }; // save location (for rendering) + render - _terminal->SetSelectionEnd(terminalPosition); + _terminal->SetSelectionEnd(terminalPosition.to_win32_coord()); _renderer->TriggerSelection(); } @@ -1433,7 +1430,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation return _terminal != nullptr && _terminal->IsTrackingMouseInput(); } - til::point ControlCore::CursorPosition() const + Core::Point ControlCore::CursorPosition() const { // If we haven't been initialized yet, then fake it. if (!_initializedTerminal) @@ -1442,7 +1439,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation } auto lock = _terminal->LockForReading(); - return _terminal->GetCursorPosition(); + return til::point{ _terminal->GetCursorPosition() }.to_core_point(); } // This one's really pushing the boundary of what counts as "encapsulation". @@ -1494,7 +1491,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation { // If shift is pressed and there is a selection we extend it using // the selection mode (expand the "end" selection point) - _terminal->SetSelectionEnd(terminalPosition, mode); + _terminal->SetSelectionEnd(terminalPosition.to_win32_coord(), mode); selectionNeedsToBeCopied = true; } else if (mode != ::Terminal::SelectionExpansion::Char || shiftEnabled) @@ -1502,7 +1499,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation // If we are handling a double / triple-click or shift+single click // we establish selection using the selected mode // (expand both "start" and "end" selection points) - _terminal->MultiClickSelection(terminalPosition, mode); + _terminal->MultiClickSelection(terminalPosition.to_win32_coord(), mode); selectionNeedsToBeCopied = true; } diff --git a/src/cascadia/TerminalControl/ControlCore.h b/src/cascadia/TerminalControl/ControlCore.h index 38088a838d..7c9a668c3a 100644 --- a/src/cascadia/TerminalControl/ControlCore.h +++ b/src/cascadia/TerminalControl/ControlCore.h @@ -88,7 +88,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation void UpdatePatternLocations(); void SetHoveredCell(Core::Point terminalPosition); void ClearHoveredCell(); - winrt::hstring GetHyperlink(const til::point position) const; + winrt::hstring GetHyperlink(const Core::Point position) const; winrt::hstring HoveredUriText() const; Windows::Foundation::IReference HoveredCell() const; @@ -138,7 +138,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation void CursorOn(const bool isCursorOn); bool IsVtMouseModeEnabled() const; - til::point CursorPosition() const; + Core::Point CursorPosition() const; bool HasSelection() const; bool CopyOnSelect() const; diff --git a/src/cascadia/TerminalControl/ControlInteractivity.cpp b/src/cascadia/TerminalControl/ControlInteractivity.cpp index 70876af7a4..70c34674a8 100644 --- a/src/cascadia/TerminalControl/ControlInteractivity.cpp +++ b/src/cascadia/TerminalControl/ControlInteractivity.cpp @@ -84,7 +84,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation // Return Value: // - if the click is in the same position as the last click and within the timeout, the number of clicks within that time window // - otherwise, 1 - unsigned int ControlInteractivity::_numberOfClicks(til::point clickPos, + unsigned int ControlInteractivity::_numberOfClicks(Core::Point clickPos, Timestamp clickTime) { // if click occurred at a different location or past the multiClickTimer... @@ -192,16 +192,16 @@ namespace winrt::Microsoft::Terminal::Control::implementation const unsigned int pointerUpdateKind, const uint64_t timestamp, const ::Microsoft::Terminal::Core::ControlKeyStates modifiers, - const til::point pixelPosition) + const Core::Point pixelPosition) { - const til::point terminalPosition = _getTerminalPosition(pixelPosition); + const til::point terminalPosition = _getTerminalPosition(til::point{ pixelPosition }); const auto altEnabled = modifiers.IsAltPressed(); const auto shiftEnabled = modifiers.IsShiftPressed(); const auto ctrlEnabled = modifiers.IsCtrlPressed(); // GH#9396: we prioritize hyper-link over VT mouse events - auto hyperlink = _core->GetHyperlink(terminalPosition); + auto hyperlink = _core->GetHyperlink(terminalPosition.to_core_point()); if (WI_IsFlagSet(buttonState, MouseButtonState::IsLeftButtonDown) && ctrlEnabled && !hyperlink.empty()) { @@ -265,7 +265,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation } } - void ControlInteractivity::TouchPressed(const til::point contactPoint) + void ControlInteractivity::TouchPressed(const Core::Point contactPoint) { _touchAnchor = contactPoint; } @@ -274,10 +274,10 @@ namespace winrt::Microsoft::Terminal::Control::implementation const unsigned int pointerUpdateKind, const ::Microsoft::Terminal::Core::ControlKeyStates modifiers, const bool focused, - const til::point pixelPosition, + const Core::Point pixelPosition, const bool pointerPressedInBounds) { - const til::point terminalPosition = _getTerminalPosition(pixelPosition); + const til::point terminalPosition = _getTerminalPosition(til::point{ pixelPosition }); // Short-circuit isReadOnly check to avoid warning dialog if (focused && !_core->IsInReadOnlyMode() && _canSendVTMouseInput(modifiers)) @@ -292,21 +292,23 @@ namespace winrt::Microsoft::Terminal::Control::implementation { if (_singleClickTouchdownPos) { - // Figure out if the user's moved a quarter of a cell's smaller axis away from the clickdown point - auto& touchdownPoint{ *_singleClickTouchdownPos }; - float dx = ::base::saturated_cast(pixelPosition.x() - touchdownPoint.x()); - float dy = ::base::saturated_cast(pixelPosition.y() - touchdownPoint.y()); - auto distance{ std::sqrtf(std::powf(dx, 2) + - std::powf(dy, 2)) }; + // Figure out if the user's moved a 1/4th of a cell's smaller axis + // (practically always the width) away from the clickdown point. + const auto fontSizeInDips = _core->FontSizeInDips(); + const auto touchdownPoint = *_singleClickTouchdownPos; + const auto dx = pixelPosition.X - touchdownPoint.X; + const auto dy = pixelPosition.Y - touchdownPoint.Y; + const auto w = fontSizeInDips.width; + const auto distanceSquared = dx * dx + dy * dy; + const auto maxDistanceSquared = w * w / 16; // (w / 4)^2 - const auto fontSizeInDips{ _core->FontSizeInDips() }; - if (distance >= (std::min(fontSizeInDips.width(), fontSizeInDips.height()) / 4.f)) + if (distanceSquared >= maxDistanceSquared) { // GH#9955.c: Make sure to use the terminal location of the // _touchdown_ point here. We want to start the selection // from where the user initially clicked, not where they are // now. - _core->SetSelectionAnchor(_getTerminalPosition(touchdownPoint)); + _core->SetSelectionAnchor(_getTerminalPosition(til::point{ touchdownPoint })); // stop tracking the touchdown point _singleClickTouchdownPos = std::nullopt; @@ -316,10 +318,10 @@ namespace winrt::Microsoft::Terminal::Control::implementation SetEndSelectionPoint(pixelPosition); } - _core->SetHoveredCell(terminalPosition); + _core->SetHoveredCell(terminalPosition.to_core_point()); } - void ControlInteractivity::TouchMoved(const til::point newTouchPoint, + void ControlInteractivity::TouchMoved(const Core::Point newTouchPoint, const bool focused) { if (focused && @@ -332,19 +334,19 @@ namespace winrt::Microsoft::Terminal::Control::implementation const auto fontSizeInDips{ _core->FontSizeInDips() }; // Get the difference between the point we've dragged to and the start of the touch. - const float dy = ::base::saturated_cast(newTouchPoint.y() - anchor.y()); + const auto dy = static_cast(newTouchPoint.Y - anchor.Y); // Start viewport scroll after we've moved more than a half row of text - if (std::abs(dy) > (fontSizeInDips.height() / 2.0f)) + if (std::abs(dy) > (fontSizeInDips.height / 2.0)) { // Multiply by -1, because moving the touch point down will // create a positive delta, but we want the viewport to move up, // so we'll need a negative scroll amount (and the inverse for // panning down) - const float numRows = -1.0f * (dy / fontSizeInDips.height()); + const auto numRows = dy / -fontSizeInDips.height; - const double currentOffset = ::base::ClampedNumeric(_core->ScrollOffset()); - const double newValue = numRows + currentOffset; + const auto currentOffset = _core->ScrollOffset(); + const auto newValue = numRows + currentOffset; // Update the Core's viewport position, and raise a // ScrollPositionChanged event to update the scrollbar @@ -359,9 +361,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation void ControlInteractivity::PointerReleased(Control::MouseButtonState buttonState, const unsigned int pointerUpdateKind, const ::Microsoft::Terminal::Core::ControlKeyStates modifiers, - const til::point pixelPosition) + const Core::Point pixelPosition) { - const til::point terminalPosition = _getTerminalPosition(pixelPosition); + const til::point terminalPosition = _getTerminalPosition(til::point{ pixelPosition }); // Short-circuit isReadOnly check to avoid warning dialog if (!_core->IsInReadOnlyMode() && _canSendVTMouseInput(modifiers)) { @@ -402,10 +404,10 @@ namespace winrt::Microsoft::Terminal::Control::implementation // - delta: the mouse wheel delta that triggered this event. bool ControlInteractivity::MouseWheel(const ::Microsoft::Terminal::Core::ControlKeyStates modifiers, const int32_t delta, - const til::point pixelPosition, + const Core::Point pixelPosition, const Control::MouseButtonState buttonState) { - const til::point terminalPosition = _getTerminalPosition(pixelPosition); + const til::point terminalPosition = _getTerminalPosition(til::point{ pixelPosition }); // Short-circuit isReadOnly check to avoid warning dialog if (!_core->IsInReadOnlyMode() && _canSendVTMouseInput(modifiers)) @@ -470,7 +472,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation // - pixelPosition: the location of the mouse during this event // - isLeftButtonPressed: true iff the left mouse button was pressed during this event. void ControlInteractivity::_mouseScrollHandler(const double mouseDelta, - const til::point pixelPosition, + const Core::Point pixelPosition, const bool isLeftButtonPressed) { // GH#9955.b: Start scrolling from our internal scrollbar position. This @@ -573,9 +575,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation // - Sets selection's end position to match supplied cursor position, e.g. while mouse dragging. // Arguments: // - cursorPosition: in pixels, relative to the origin of the control - void ControlInteractivity::SetEndSelectionPoint(const til::point pixelPosition) + void ControlInteractivity::SetEndSelectionPoint(const Core::Point pixelPosition) { - _core->SetEndSelectionPoint(_getTerminalPosition(pixelPosition)); + _core->SetEndSelectionPoint(_getTerminalPosition(til::point{ pixelPosition })); _selectionNeedsToBeCopied = true; } @@ -587,7 +589,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation // NOTE: origin (0,0) is top-left. // Return Value: // - the corresponding viewport terminal position for the given Point parameter - til::point ControlInteractivity::_getTerminalPosition(const til::point& pixelPosition) + til::point ControlInteractivity::_getTerminalPosition(const til::point pixelPosition) { // Get the size of the font, which is in pixels const til::size fontSize{ _core->GetFont().GetSize() }; @@ -603,9 +605,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation { const auto adjustment = _core->ScrollOffset() > 0 ? _core->BufferHeight() - _core->ScrollOffset() - _core->ViewHeight() : 0; // If the click happened outside the active region, just don't send any mouse event - if (const auto adjustedY = terminalPosition.y() - adjustment; adjustedY >= 0) + if (const auto adjustedY = terminalPosition.y - adjustment; adjustedY >= 0) { - return _core->SendMouseEvent({ terminalPosition.x(), adjustedY }, pointerUpdateKind, modifiers, wheelDelta, toInternalMouseState(buttonState)); + return _core->SendMouseEvent({ terminalPosition.x, adjustedY }, pointerUpdateKind, modifiers, wheelDelta, toInternalMouseState(buttonState)); } return false; } diff --git a/src/cascadia/TerminalControl/ControlInteractivity.h b/src/cascadia/TerminalControl/ControlInteractivity.h index 6039bc8da9..59de34ae96 100644 --- a/src/cascadia/TerminalControl/ControlInteractivity.h +++ b/src/cascadia/TerminalControl/ControlInteractivity.h @@ -52,27 +52,27 @@ namespace winrt::Microsoft::Terminal::Control::implementation const unsigned int pointerUpdateKind, const uint64_t timestamp, const ::Microsoft::Terminal::Core::ControlKeyStates modifiers, - const til::point pixelPosition); - void TouchPressed(const til::point contactPoint); + const Core::Point pixelPosition); + void TouchPressed(const Core::Point contactPoint); void PointerMoved(Control::MouseButtonState buttonState, const unsigned int pointerUpdateKind, const ::Microsoft::Terminal::Core::ControlKeyStates modifiers, const bool focused, - const til::point pixelPosition, + const Core::Point pixelPosition, const bool pointerPressedInBounds); - void TouchMoved(const til::point newTouchPoint, + void TouchMoved(const Core::Point newTouchPoint, const bool focused); void PointerReleased(Control::MouseButtonState buttonState, const unsigned int pointerUpdateKind, const ::Microsoft::Terminal::Core::ControlKeyStates modifiers, - const til::point pixelPosition); + const Core::Point pixelPosition); void TouchReleased(); bool MouseWheel(const ::Microsoft::Terminal::Core::ControlKeyStates modifiers, const int32_t delta, - const til::point pixelPosition, + const Core::Point pixelPosition, const Control::MouseButtonState state); void UpdateScrollbar(const double newValue); @@ -82,7 +82,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation bool CopySelectionToClipboard(bool singleLine, const Windows::Foundation::IReference& formats); void RequestPasteTextFromClipboard(); - void SetEndSelectionPoint(const til::point pixelPosition); + void SetEndSelectionPoint(const Core::Point pixelPosition); bool ManglePathsForWsl(); TYPED_EVENT(OpenHyperlink, IInspectable, Control::OpenHyperlinkEventArgs); @@ -105,7 +105,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation // If this is set, then we assume we are in the middle of panning the // viewport via touch input. - std::optional _touchAnchor; + std::optional _touchAnchor; using Timestamp = uint64_t; @@ -114,9 +114,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation Timestamp _multiClickTimer; unsigned int _multiClickCounter; Timestamp _lastMouseClickTimestamp; - std::optional _lastMouseClickPos; - std::optional _singleClickTouchdownPos; - std::optional _lastMouseClickPosNoSelection; + std::optional _lastMouseClickPos; + std::optional _singleClickTouchdownPos; + std::optional _lastMouseClickPosNoSelection; // This field tracks whether the selection has changed meaningfully // since it was last copied. It's generally used to prevent copyOnSelect // from firing when the pointer _just happens_ to be released over the @@ -129,20 +129,20 @@ namespace winrt::Microsoft::Terminal::Control::implementation std::optional::interval> _lastHoveredInterval{ std::nullopt }; - unsigned int _numberOfClicks(til::point clickPos, Timestamp clickTime); + unsigned int _numberOfClicks(Core::Point clickPos, Timestamp clickTime); void _updateSystemParameterSettings() noexcept; void _mouseTransparencyHandler(const double mouseDelta); void _mouseZoomHandler(const double mouseDelta); void _mouseScrollHandler(const double mouseDelta, - const til::point terminalPosition, + const Core::Point terminalPosition, const bool isLeftButtonPressed); void _hyperlinkHandler(const std::wstring_view uri); bool _canSendVTMouseInput(const ::Microsoft::Terminal::Core::ControlKeyStates modifiers); void _sendPastedTextToConnection(std::wstring_view wstr); - til::point _getTerminalPosition(const til::point& pixelPosition); + til::point _getTerminalPosition(const til::point pixelPosition); bool _sendMouseEventHelper(const til::point terminalPosition, const unsigned int pointerUpdateKind, diff --git a/src/cascadia/TerminalControl/InteractivityAutomationPeer.cpp b/src/cascadia/TerminalControl/InteractivityAutomationPeer.cpp index 570cfd67ec..d2247311d1 100644 --- a/src/cascadia/TerminalControl/InteractivityAutomationPeer.cpp +++ b/src/cascadia/TerminalControl/InteractivityAutomationPeer.cpp @@ -37,11 +37,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation void InteractivityAutomationPeer::SetControlBounds(const Windows::Foundation::Rect bounds) { - _controlBounds = til::rectangle{ til::math::rounding, bounds }; + _controlBounds = til::rect{ til::math::rounding, bounds }; } void InteractivityAutomationPeer::SetControlPadding(const Core::Padding padding) { - _controlPadding = padding; + _controlPadding = til::rect{ til::math::rounding, padding }; } void InteractivityAutomationPeer::ParentProvider(AutomationPeer parentProvider) { @@ -143,12 +143,12 @@ namespace winrt::Microsoft::Terminal::Control::implementation #pragma region IControlAccessibilityInfo COORD InteractivityAutomationPeer::GetFontSize() const noexcept { - return til::size{ til::math::rounding, _interactivity->Core().FontSize() }; + return til::size{ til::math::rounding, _interactivity->Core().FontSize() }.to_win32_coord(); } RECT InteractivityAutomationPeer::GetBounds() const noexcept { - return _controlBounds; + return _controlBounds.to_win32_rect(); } HRESULT InteractivityAutomationPeer::GetHostUiaProvider(IRawElementProviderSimple** provider) @@ -161,7 +161,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation RECT InteractivityAutomationPeer::GetPadding() const noexcept { - return _controlPadding; + return _controlPadding.to_win32_rect(); } double InteractivityAutomationPeer::GetScaleFactor() const noexcept diff --git a/src/cascadia/TerminalControl/InteractivityAutomationPeer.h b/src/cascadia/TerminalControl/InteractivityAutomationPeer.h index bd95c54047..57c3a85fc8 100644 --- a/src/cascadia/TerminalControl/InteractivityAutomationPeer.h +++ b/src/cascadia/TerminalControl/InteractivityAutomationPeer.h @@ -81,8 +81,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation winrt::Microsoft::Terminal::Control::implementation::ControlInteractivity* _interactivity; weak_ref _parentProvider; - til::rectangle _controlBounds{}; - til::rectangle _controlPadding{}; + til::rect _controlBounds{}; + til::rect _controlPadding{}; winrt::com_array WrapArrayOfTextRangeProviders(SAFEARRAY* textRanges); }; diff --git a/src/cascadia/TerminalControl/TSFInputControl.cpp b/src/cascadia/TerminalControl/TSFInputControl.cpp index fb5c0280c2..22b0738a50 100644 --- a/src/cascadia/TerminalControl/TSFInputControl.cpp +++ b/src/cascadia/TerminalControl/TSFInputControl.cpp @@ -144,7 +144,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation // Get the cursor position in text buffer position auto cursorArgs = winrt::make_self(); _CurrentCursorPositionHandlers(*this, *cursorArgs); - const til::point cursorPos{ gsl::narrow_cast(cursorArgs->CurrentPosition().X), gsl::narrow_cast(cursorArgs->CurrentPosition().Y) }; + const til::point cursorPos{ til::math::flooring, cursorArgs->CurrentPosition() }; const double actualCanvasWidth{ Canvas().ActualWidth() }; const double actualTextBlockHeight{ TextBlock().ActualHeight() }; @@ -189,14 +189,14 @@ namespace winrt::Microsoft::Terminal::Control::implementation // Get scale factor for view const double scaleFactor = DisplayInformation::GetForCurrentView().RawPixelsPerViewPixel(); - const til::point clientCursorInDips{ clientCursorPos / scaleFactor }; + const til::point clientCursorInDips{ til::math::flooring, clientCursorPos.x / scaleFactor, clientCursorPos.y / scaleFactor }; // Position our TextBlock at the cursor position - Canvas().SetLeft(TextBlock(), clientCursorInDips.x()); - Canvas().SetTop(TextBlock(), clientCursorInDips.y()); + Canvas().SetLeft(TextBlock(), clientCursorInDips.x); + Canvas().SetTop(TextBlock(), clientCursorInDips.y); // calculate FontSize in pixels from Points - const double fontSizePx = (fontSize.height() * 72) / USER_DEFAULT_SCREEN_DPI; + const double fontSizePx = (fontSize.height * 72) / USER_DEFAULT_SCREEN_DPI; const double unscaledFontSizePx = fontSizePx / scaleFactor; // Make sure to unscale the font size to correct for DPI! XAML needs @@ -212,7 +212,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation TextBlock().MinHeight(unscaledFontSizePx); _currentTextBlockHeight = std::max(unscaledFontSizePx, _currentTextBlockHeight); - const auto widthToTerminalEnd = _currentCanvasWidth - clientCursorInDips.x(); + const auto widthToTerminalEnd = _currentCanvasWidth - clientCursorInDips.x; // Make sure that we're setting the MaxWidth to a positive number - a // negative number here will crash us in mysterious ways with a useless // stack trace @@ -221,7 +221,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation // Get window in screen coordinates, this is the entire window including // tabs. THIS IS IN DIPs - const til::point windowOrigin{ til::math::flooring, _currentWindowBounds }; + const til::point windowOrigin{ til::math::flooring, _currentWindowBounds.X, _currentWindowBounds.Y }; // Get the offset (margin + tabs, etc..) of the control within the window const til::point controlOrigin{ til::math::flooring, @@ -232,25 +232,25 @@ namespace winrt::Microsoft::Terminal::Control::implementation const til::point controlAbsoluteOrigin{ windowOrigin + controlOrigin }; // Convert the control origin to pixels - const til::point scaledFrameOrigin = controlAbsoluteOrigin * scaleFactor; + const til::point scaledFrameOrigin = til::point{ til::math::flooring, controlAbsoluteOrigin.x * scaleFactor, controlAbsoluteOrigin.y * scaleFactor }; // Get the location of the cursor in the display, in pixels. til::point screenCursorPos{ scaledFrameOrigin + clientCursorPos }; // GH #5007 - make sure to account for wrapping the IME composition at // the right side of the viewport. - const ptrdiff_t textBlockHeight = ::base::ClampMul(_currentTextBlockHeight, scaleFactor); + const auto textBlockHeight = ::base::ClampMul(_currentTextBlockHeight, scaleFactor); // Get the bounds of the composition text, in pixels. - const til::rectangle textBounds{ til::point{ screenCursorPos.x(), screenCursorPos.y() }, - til::size{ 0, textBlockHeight } }; + const til::rect textBounds{ til::point{ screenCursorPos.x, screenCursorPos.y }, + til::size{ 0, textBlockHeight } }; - _currentTextBounds = textBounds; + _currentTextBounds = textBounds.to_winrt_rect(); - _currentControlBounds = Rect(screenCursorPos.x(), - screenCursorPos.y(), - 0, - fontSize.height()); + _currentControlBounds = Rect(static_cast(screenCursorPos.x), + static_cast(screenCursorPos.y), + 0.0f, + static_cast(fontSize.height)); } // Method Description: diff --git a/src/cascadia/TerminalControl/TermControl.cpp b/src/cascadia/TerminalControl/TermControl.cpp index 53206b16ed..aa6f3567e8 100644 --- a/src/cascadia/TerminalControl/TermControl.cpp +++ b/src/cascadia/TerminalControl/TermControl.cpp @@ -1137,7 +1137,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation { const auto contactRect = point.Properties().ContactRect(); auto anchor = til::point{ til::math::rounding, contactRect.X, contactRect.Y }; - _interactivity.TouchPressed(anchor); + _interactivity.TouchPressed(anchor.to_core_point()); } else { @@ -1146,7 +1146,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation TermControl::GetPointerUpdateKind(point), point.Timestamp(), ControlKeyStates{ args.KeyModifiers() }, - _toTerminalOrigin(cursorPosition)); + _toTerminalOrigin(cursorPosition).to_core_point()); } args.Handled(true); @@ -1185,7 +1185,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation TermControl::GetPointerUpdateKind(point), ControlKeyStates(args.KeyModifiers()), _focused, - pixelPosition, + pixelPosition.to_core_point(), _pointerPressedInBounds); // GH#9109 - Only start an auto-scroll when the drag actually @@ -1227,7 +1227,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation const auto contactRect = point.Properties().ContactRect(); til::point newTouchPoint{ til::math::rounding, contactRect.X, contactRect.Y }; - _interactivity.TouchMoved(newTouchPoint, _focused); + _interactivity.TouchMoved(newTouchPoint.to_core_point(), _focused); } args.Handled(true); @@ -1263,7 +1263,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation _interactivity.PointerReleased(TermControl::GetPressedMouseButtons(point), TermControl::GetPointerUpdateKind(point), ControlKeyStates(args.KeyModifiers()), - pixelPosition); + pixelPosition.to_core_point()); } else if (type == Windows::Devices::Input::PointerDeviceType::Touch) { @@ -1303,7 +1303,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation auto result = _interactivity.MouseWheel(ControlKeyStates{ args.KeyModifiers() }, point.Properties().MouseWheelDelta(), - _toTerminalOrigin(point.Position()), + _toTerminalOrigin(point.Position()).to_core_point(), TermControl::GetPressedMouseButtons(point)); if (result) { @@ -1334,7 +1334,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation WI_SetFlagIf(state, Control::MouseButtonState::IsMiddleButtonDown, midButtonDown); WI_SetFlagIf(state, Control::MouseButtonState::IsRightButtonDown, rightButtonDown); - return _interactivity.MouseWheel(modifiers, delta, _toTerminalOrigin(location), state); + return _interactivity.MouseWheel(modifiers, delta, _toTerminalOrigin(location).to_core_point(), state); } // Method Description: @@ -1704,7 +1704,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation // - cursorPosition: in pixels, relative to the origin of the control void TermControl::_SetEndSelectionPointAtCursor(Windows::Foundation::Point const& cursorPosition) { - _interactivity.SetEndSelectionPoint(_toTerminalOrigin(cursorPosition)); + _interactivity.SetEndSelectionPoint(_toTerminalOrigin(cursorPosition).to_core_point()); } // Method Description: @@ -2157,7 +2157,12 @@ namespace winrt::Microsoft::Terminal::Control::implementation const til::point relativeToMarginInDIPs = cursorPosInDIPs - marginsInDips; // Convert it to pixels - const til::point relativeToMarginInPixels{ relativeToMarginInDIPs * SwapChainPanel().CompositionScaleX() }; + const auto scale = SwapChainPanel().CompositionScaleX(); + const til::point relativeToMarginInPixels{ + til::math::flooring, + relativeToMarginInDIPs.x * scale, + relativeToMarginInDIPs.y * scale, + }; return relativeToMarginInPixels; } @@ -2196,10 +2201,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation return; } - const til::point cursorPos = _core.CursorPosition(); - Windows::Foundation::Point p = { ::base::ClampedNumeric(cursorPos.x()), - ::base::ClampedNumeric(cursorPos.y()) }; - eventArgs.CurrentPosition(p); + const auto cursorPos = _core.CursorPosition(); + eventArgs.CurrentPosition({ static_cast(cursorPos.X), static_cast(cursorPos.Y) }); } // Method Description: @@ -2597,13 +2600,17 @@ namespace winrt::Microsoft::Terminal::Control::implementation const auto uriText = _core.HoveredUriText(); if (!uriText.empty()) { + const auto panel = SwapChainPanel(); + const auto scale = panel.CompositionScaleX(); + const auto offset = panel.ActualOffset(); + // Update the tooltip with the URI HoveredUri().Text(uriText); // Set the border thickness so it covers the entire cell const auto charSizeInPixels = CharacterDimensions(); - const auto htInDips = charSizeInPixels.Height / SwapChainPanel().CompositionScaleY(); - const auto wtInDips = charSizeInPixels.Width / SwapChainPanel().CompositionScaleX(); + const auto htInDips = charSizeInPixels.Height / scale; + const auto wtInDips = charSizeInPixels.Width / scale; const Thickness newThickness{ wtInDips, htInDips, 0, 0 }; HyperlinkTooltipBorder().BorderThickness(newThickness); @@ -2612,14 +2619,12 @@ namespace winrt::Microsoft::Terminal::Control::implementation const til::point startPos{ lastHoveredCell.Value() }; const til::size fontSize{ til::math::rounding, _core.FontSize() }; const til::point posInPixels{ startPos * fontSize }; - const til::point posInDIPs{ posInPixels / SwapChainPanel().CompositionScaleX() }; + const til::point posInDIPs{ til::math::flooring, posInPixels.x / scale, posInPixels.y / scale }; const til::point locationInDIPs{ posInDIPs + marginsInDips }; // Move the border to the top left corner of the cell - OverlayCanvas().SetLeft(HyperlinkTooltipBorder(), - (locationInDIPs.x() - SwapChainPanel().ActualOffset().x)); - OverlayCanvas().SetTop(HyperlinkTooltipBorder(), - (locationInDIPs.y() - SwapChainPanel().ActualOffset().y)); + OverlayCanvas().SetLeft(HyperlinkTooltipBorder(), locationInDIPs.x - offset.x); + OverlayCanvas().SetTop(HyperlinkTooltipBorder(), locationInDIPs.y - offset.y); } } } diff --git a/src/cascadia/TerminalCore/Terminal.cpp b/src/cascadia/TerminalCore/Terminal.cpp index 4eaa385e2d..4c9d38227b 100644 --- a/src/cascadia/TerminalCore/Terminal.cpp +++ b/src/cascadia/TerminalCore/Terminal.cpp @@ -515,8 +515,8 @@ std::wstring Terminal::GetHyperlinkAtPosition(const COORD position) const auto end = result->stop; std::wstring uri; - const auto startIter = _buffer->GetCellDataAt(_ConvertToBufferCell(start)); - const auto endIter = _buffer->GetCellDataAt(_ConvertToBufferCell(end)); + const auto startIter = _buffer->GetCellDataAt(_ConvertToBufferCell(start.to_win32_coord())); + const auto endIter = _buffer->GetCellDataAt(_ConvertToBufferCell(end.to_win32_coord())); for (auto iter = startIter; iter != endIter; ++iter) { uri += iter->Chars(); @@ -545,7 +545,7 @@ uint16_t Terminal::GetHyperlinkIdAtPosition(const COORD position) // - The interval representing the start and end coordinates std::optional Terminal::GetHyperlinkIntervalFromPosition(const COORD position) { - const auto results = _patternIntervalTree.findOverlapping(COORD{ position.X + 1, position.Y }, position); + const auto results = _patternIntervalTree.findOverlapping(til::point{ position.X + 1, position.Y }, til::point{ position }); if (results.size() > 0) { for (const auto& result : results) @@ -715,8 +715,8 @@ void Terminal::_InvalidatePatternTree(interval_tree::IntervalTree(interval.start.x()), gsl::narrow(interval.start.y() + vis) }; - COORD endCoord{ gsl::narrow(interval.stop.x()), gsl::narrow(interval.stop.y() + vis) }; + COORD startCoord{ gsl::narrow(interval.start.x), gsl::narrow(interval.start.y + vis) }; + COORD endCoord{ gsl::narrow(interval.stop.x), gsl::narrow(interval.stop.y + vis) }; _InvalidateFromCoords(startCoord, endCoord); }; tree.visit_all(invalidate); @@ -738,18 +738,18 @@ void Terminal::_InvalidateFromCoords(const COORD start, const COORD end) const auto rowSize = gsl::narrow(_buffer->GetRowByOffset(0).size()); // invalidate the first line - SMALL_RECT region{ start.X, start.Y, rowSize - 1, start.Y }; + SMALL_RECT region{ start.X, start.Y, gsl::narrow(rowSize - 1), gsl::narrow(start.Y) }; _buffer->GetRenderTarget().TriggerRedraw(Viewport::FromInclusive(region)); if ((end.Y - start.Y) > 1) { // invalidate the lines in between the first and last line - region = til::rectangle(0, start.Y + 1, rowSize - 1, end.Y - 1); + region = SMALL_RECT{ 0, start.Y + 1, gsl::narrow(rowSize - 1), gsl::narrow(end.Y - 1) }; _buffer->GetRenderTarget().TriggerRedraw(Viewport::FromInclusive(region)); } // invalidate the last line - region = til::rectangle(0, end.Y, end.X, end.Y); + region = SMALL_RECT{ 0, end.Y, end.X, end.Y }; _buffer->GetRenderTarget().TriggerRedraw(Viewport::FromInclusive(region)); } } @@ -1104,7 +1104,7 @@ void Terminal::_AdjustCursorPosition(const COORD proposedPosition) // We have to report the delta here because we might have circled the text buffer. // That didn't change the viewport and therefore the TriggerScroll(void) // method can't detect the delta on its own. - COORD delta{ 0, -rowsPushedOffTopOfBuffer }; + COORD delta{ 0, gsl::narrow_cast(-rowsPushedOffTopOfBuffer) }; _buffer->GetRenderTarget().TriggerScroll(&delta); } diff --git a/src/cascadia/TerminalCore/TerminalSelection.cpp b/src/cascadia/TerminalCore/TerminalSelection.cpp index 367a8365a5..f45d18f821 100644 --- a/src/cascadia/TerminalCore/TerminalSelection.cpp +++ b/src/cascadia/TerminalCore/TerminalSelection.cpp @@ -335,11 +335,11 @@ void Terminal::_MoveByChar(SelectionDirection direction, COORD& pos) { case SelectionDirection::Left: _buffer->GetSize().DecrementInBounds(pos); - pos = _buffer->GetGlyphStart(pos); + pos = _buffer->GetGlyphStart(til::point{ pos }).to_win32_coord(); break; case SelectionDirection::Right: _buffer->GetSize().IncrementInBounds(pos); - pos = _buffer->GetGlyphEnd(pos); + pos = _buffer->GetGlyphEnd(til::point{ pos }).to_win32_coord(); break; case SelectionDirection::Up: { diff --git a/src/cascadia/TerminalCore/terminalrenderdata.cpp b/src/cascadia/TerminalCore/terminalrenderdata.cpp index def44aeb15..3e19898b1a 100644 --- a/src/cascadia/TerminalCore/terminalrenderdata.cpp +++ b/src/cascadia/TerminalCore/terminalrenderdata.cpp @@ -169,7 +169,7 @@ const std::wstring Microsoft::Terminal::Core::Terminal::GetHyperlinkCustomId(uin const std::vector Terminal::GetPatternId(const COORD location) const noexcept { // Look through our interval tree for this location - const auto intervals = _patternIntervalTree.findOverlapping(COORD{ location.X + 1, location.Y }, location); + const auto intervals = _patternIntervalTree.findOverlapping(til::point{ location.X + 1, location.Y }, til::point{ location }); if (intervals.size() == 0) { return {}; diff --git a/src/cascadia/UnitTests_Control/ControlInteractivityTests.cpp b/src/cascadia/UnitTests_Control/ControlInteractivityTests.cpp index 9f885a94f9..0da22765c1 100644 --- a/src/cascadia/UnitTests_Control/ControlInteractivityTests.cpp +++ b/src/cascadia/UnitTests_Control/ControlInteractivityTests.cpp @@ -144,7 +144,7 @@ namespace ControlUnitTests // The mouse location and buttons don't matter here. interactivity->MouseWheel(modifiers, 30, - til::point{ 0, 0 }, + Core::Point{ 0, 0 }, buttonState); } @@ -162,7 +162,7 @@ namespace ControlUnitTests // The mouse location and buttons don't matter here. interactivity->MouseWheel(modifiers, -30, - til::point{ 0, 0 }, + Core::Point{ 0, 0 }, buttonState); } } @@ -219,7 +219,7 @@ namespace ControlUnitTests interactivity->MouseWheel(modifiers, WHEEL_DELTA, - til::point{ 0, 0 }, + Core::Point{ 0, 0 }, buttonState); Log::Comment(L"Scroll up 19 more times, to the top"); @@ -228,18 +228,18 @@ namespace ControlUnitTests expectedTop--; interactivity->MouseWheel(modifiers, WHEEL_DELTA, - til::point{ 0, 0 }, + Core::Point{ 0, 0 }, buttonState); } Log::Comment(L"Scrolling up more should do nothing"); expectedTop = 0; interactivity->MouseWheel(modifiers, WHEEL_DELTA, - til::point{ 0, 0 }, + Core::Point{ 0, 0 }, buttonState); interactivity->MouseWheel(modifiers, WHEEL_DELTA, - til::point{ 0, 0 }, + Core::Point{ 0, 0 }, buttonState); Log::Comment(L"Scroll down 21 more times, to the bottom"); @@ -249,7 +249,7 @@ namespace ControlUnitTests expectedTop++; interactivity->MouseWheel(modifiers, -WHEEL_DELTA, - til::point{ 0, 0 }, + Core::Point{ 0, 0 }, buttonState); Log::Comment(NoThrowString().Format(L"internal scrollbar pos:%f", interactivity->_internalScrollbarPosition)); } @@ -257,11 +257,11 @@ namespace ControlUnitTests expectedTop = 21; interactivity->MouseWheel(modifiers, -WHEEL_DELTA, - til::point{ 0, 0 }, + Core::Point{ 0, 0 }, buttonState); interactivity->MouseWheel(modifiers, -WHEEL_DELTA, - til::point{ 0, 0 }, + Core::Point{ 0, 0 }, buttonState); } @@ -292,7 +292,7 @@ namespace ControlUnitTests WM_LBUTTONDOWN, //pointerUpdateKind 0, // timestamp modifiers, - cursorPosition0); + cursorPosition0.to_core_point()); Log::Comment(L"Verify that there's not yet a selection"); VERIFY_IS_FALSE(core->HasSelection()); @@ -305,7 +305,7 @@ namespace ControlUnitTests WM_LBUTTONDOWN, //pointerUpdateKind modifiers, true, // focused, - cursorPosition1, + cursorPosition1.to_core_point(), true); Log::Comment(L"Verify that there's one selection"); VERIFY_IS_TRUE(core->HasSelection()); @@ -318,7 +318,7 @@ namespace ControlUnitTests WM_LBUTTONDOWN, //pointerUpdateKind modifiers, true, // focused, - cursorPosition2, + cursorPosition2.to_core_point(), true); Log::Comment(L"Verify that there's now two selections (one on each row)"); VERIFY_IS_TRUE(core->HasSelection()); @@ -328,7 +328,7 @@ namespace ControlUnitTests interactivity->PointerReleased(noMouseDown, WM_LBUTTONUP, //pointerUpdateKind modifiers, - cursorPosition2); + cursorPosition2.to_core_point()); Log::Comment(L"Verify that there's still two selections"); VERIFY_IS_TRUE(core->HasSelection()); VERIFY_ARE_EQUAL(2u, core->_terminal->GetSelectionRects().size()); @@ -340,7 +340,7 @@ namespace ControlUnitTests WM_LBUTTONDOWN, //pointerUpdateKind 0, // timestamp modifiers, - cursorPosition3); + cursorPosition3.to_core_point()); Log::Comment(L"Verify that there's now no selection"); VERIFY_IS_FALSE(core->HasSelection()); VERIFY_ARE_EQUAL(0u, core->_terminal->GetSelectionRects().size()); @@ -352,7 +352,7 @@ namespace ControlUnitTests WM_LBUTTONDOWN, //pointerUpdateKind modifiers, true, // focused, - cursorPosition4, + cursorPosition4.to_core_point(), true); Log::Comment(L"Verify that there's now one selection"); VERIFY_IS_TRUE(core->HasSelection()); @@ -392,13 +392,13 @@ namespace ControlUnitTests WM_LBUTTONDOWN, //pointerUpdateKind 0, // timestamp modifiers, - cursorPosition0); + cursorPosition0.to_core_point()); Log::Comment(L"Verify that there's not yet a selection"); VERIFY_IS_FALSE(core->HasSelection()); VERIFY_IS_TRUE(interactivity->_singleClickTouchdownPos.has_value()); - VERIFY_ARE_EQUAL(cursorPosition0, interactivity->_singleClickTouchdownPos.value()); + VERIFY_ARE_EQUAL(cursorPosition0.to_core_point(), interactivity->_singleClickTouchdownPos.value()); Log::Comment(L"Drag the mouse just a little"); // move not quite a whole cell, but enough to start a selection @@ -407,7 +407,7 @@ namespace ControlUnitTests WM_LBUTTONDOWN, //pointerUpdateKind modifiers, true, // focused, - cursorPosition1, + cursorPosition1.to_core_point(), true); Log::Comment(L"Verify that there's one selection"); VERIFY_IS_TRUE(core->HasSelection()); @@ -423,7 +423,7 @@ namespace ControlUnitTests Log::Comment(L"Scroll up a line, with the left mouse button selected"); interactivity->MouseWheel(modifiers, WHEEL_DELTA, - cursorPosition1, + cursorPosition1.to_core_point(), leftMouseDown); Log::Comment(L"Verify the location of the selection"); @@ -466,7 +466,7 @@ namespace ControlUnitTests // WHEEL_DELTA is 120, so we'll use 24 for now as the delta, just so the tests don't take forever. const int delta = WHEEL_DELTA / 5; - const til::point mousePos{ 0, 0 }; + const Core::Point mousePos{ 0, 0 }; Control::MouseButtonState state{}; interactivity->MouseWheel(modifiers, delta, mousePos, state); // 1/5 @@ -541,21 +541,21 @@ namespace ControlUnitTests WM_LBUTTONDOWN, //pointerUpdateKind 0, // timestamp modifiers, - cursorPosition0); + cursorPosition0.to_core_point()); Log::Comment(L"Verify that there's not yet a selection"); VERIFY_IS_FALSE(core->HasSelection()); VERIFY_IS_TRUE(interactivity->_singleClickTouchdownPos.has_value()); - VERIFY_ARE_EQUAL(cursorPosition0, interactivity->_singleClickTouchdownPos.value()); + VERIFY_ARE_EQUAL(cursorPosition0.to_core_point(), interactivity->_singleClickTouchdownPos.value()); Log::Comment(L"Drag the mouse a lot. This simulates dragging the mouse real fast."); - const til::point cursorPosition1{ 6 + fontSize.width() * 2, 0 }; + const til::point cursorPosition1{ 6 + fontSize.width * 2, 0 }; interactivity->PointerMoved(leftMouseDown, WM_LBUTTONDOWN, //pointerUpdateKind modifiers, true, // focused, - cursorPosition1, + cursorPosition1.to_core_point(), true); Log::Comment(L"Verify that there's one selection"); VERIFY_IS_TRUE(core->HasSelection()); @@ -586,21 +586,21 @@ namespace ControlUnitTests WM_LBUTTONDOWN, //pointerUpdateKind 0, // timestamp modifiers, - cursorPosition0); + cursorPosition0.to_core_point()); Log::Comment(L"Verify that there's not yet a selection"); VERIFY_IS_FALSE(core->HasSelection()); VERIFY_IS_TRUE(interactivity->_singleClickTouchdownPos.has_value()); - VERIFY_ARE_EQUAL(cursorPosition0, interactivity->_singleClickTouchdownPos.value()); + VERIFY_ARE_EQUAL(cursorPosition0.to_core_point(), interactivity->_singleClickTouchdownPos.value()); Log::Comment(L"Drag the mouse a lot. This simulates dragging the mouse real fast."); - const til::point cursorPosition1{ 6 + fontSize.width() * 2, 0 }; + const til::point cursorPosition1{ 6 + fontSize.width * 2, 0 }; interactivity->PointerMoved(leftMouseDown, WM_LBUTTONDOWN, //pointerUpdateKind modifiers, true, // focused, - cursorPosition1, + cursorPosition1.to_core_point(), true); Log::Comment(L"Verify that there's one selection"); VERIFY_IS_TRUE(core->HasSelection()); @@ -615,18 +615,18 @@ namespace ControlUnitTests interactivity->PointerReleased(noMouseDown, WM_LBUTTONUP, modifiers, - cursorPosition1); + cursorPosition1.to_core_point()); VERIFY_ARE_EQUAL(expectedAnchor, core->_terminal->GetSelectionAnchor()); VERIFY_ARE_EQUAL(expectedEnd, core->_terminal->GetSelectionEnd()); Log::Comment(L"Simulate dragging the mouse into the control, without first clicking into the control"); - const til::point cursorPosition2{ fontSize.width() * 10, 0 }; + const til::point cursorPosition2{ fontSize.width * 10, 0 }; interactivity->PointerMoved(leftMouseDown, WM_LBUTTONDOWN, //pointerUpdateKind modifiers, true, // focused, - cursorPosition2, + cursorPosition2.to_core_point(), false); Log::Comment(L"The selection should be unchanged."); @@ -689,7 +689,7 @@ namespace ControlUnitTests expectedTop--; interactivity->MouseWheel(modifiers, WHEEL_DELTA, - til::point{ 0, 0 }, + Core::Point{ 0, 0 }, noMouseDown); } @@ -704,7 +704,7 @@ namespace ControlUnitTests WM_LBUTTONDOWN, //pointerUpdateKind 0, // timestamp modifiers, - cursorPosition0); + cursorPosition0.to_core_point()); Log::Comment(L"Verify that there's not yet a selection"); VERIFY_IS_FALSE(core->HasSelection()); @@ -717,7 +717,7 @@ namespace ControlUnitTests WM_LBUTTONDOWN, //pointerUpdateKind modifiers, true, // focused, - cursorPosition1, + cursorPosition1.to_core_point(), true); Log::Comment(L"Verify that there's still no selection"); VERIFY_IS_FALSE(core->HasSelection()); @@ -753,13 +753,13 @@ namespace ControlUnitTests WM_LBUTTONDOWN, //pointerUpdateKind 0, // timestamp modifiers, - cursorPosition0); + cursorPosition0.to_core_point()); Log::Comment(L"Verify that there's not yet a selection"); VERIFY_IS_FALSE(core->HasSelection()); VERIFY_IS_TRUE(interactivity->_singleClickTouchdownPos.has_value()); - VERIFY_ARE_EQUAL(cursorPosition0, interactivity->_singleClickTouchdownPos.value()); + VERIFY_ARE_EQUAL(cursorPosition0.to_core_point(), interactivity->_singleClickTouchdownPos.value()); Log::Comment(L"Drag the mouse just a little"); // move not quite a whole cell, but enough to start a selection @@ -768,7 +768,7 @@ namespace ControlUnitTests WM_LBUTTONDOWN, //pointerUpdateKind modifiers, true, // focused, - cursorPosition1, + cursorPosition1.to_core_point(), true); Log::Comment(L"Verify that there's one selection"); VERIFY_IS_TRUE(core->HasSelection()); diff --git a/src/cascadia/UnitTests_TerminalCore/ConptyRoundtripTests.cpp b/src/cascadia/UnitTests_TerminalCore/ConptyRoundtripTests.cpp index ae063f1939..4be7a402f9 100644 --- a/src/cascadia/UnitTests_TerminalCore/ConptyRoundtripTests.cpp +++ b/src/cascadia/UnitTests_TerminalCore/ConptyRoundtripTests.cpp @@ -17,7 +17,6 @@ #include "../../renderer/vt/Xterm256Engine.hpp" #include "../../renderer/vt/XtermEngine.hpp" -class InputBuffer; // This for some reason needs to be fwd-decl'd #include "../host/inputBuffer.hpp" #include "../host/readDataCooked.hpp" #include "../host/output.h" @@ -227,7 +226,7 @@ private: void _resizeConpty(const unsigned short sx, const unsigned short sy); void _clearConpty(); - [[nodiscard]] std::tuple _performResize(const til::size& newSize); + [[nodiscard]] std::tuple _performResize(const til::size newSize); std::deque expectedOutput; @@ -307,7 +306,7 @@ void ConptyRoundtripTests::_clearConpty() _pConApi->PrivateClearBuffer(); } -[[nodiscard]] std::tuple ConptyRoundtripTests::_performResize(const til::size& newSize) +[[nodiscard]] std::tuple ConptyRoundtripTests::_performResize(const til::size newSize) { // IMPORTANT! Anyone calling this should make sure that the test is running // in IsolationLevel: Method. If you don't add that, then it might secretly @@ -315,9 +314,9 @@ void ConptyRoundtripTests::_clearConpty() Log::Comment(L"========== Resize the Terminal and conpty =========="); - auto resizeResult = term->UserResize(newSize); + auto resizeResult = term->UserResize(newSize.to_win32_coord()); VERIFY_SUCCEEDED(resizeResult); - _resizeConpty(newSize.width(), newSize.height()); + _resizeConpty(newSize.narrow_width(), newSize.narrow_height()); // After we resize, make sure to get the new textBuffers return { &ServiceLocator::LocateGlobals().getConsoleInformation().GetActiveOutputBuffer().GetTextBuffer(), @@ -900,7 +899,7 @@ void ConptyRoundtripTests::TestResizeHeight() // Conpty's doesn't have a scrollback, it's view's origin is always 0,0 const auto thirdHostView = si.GetViewport(); VERIFY_ARE_EQUAL(0, thirdHostView.Top()); - VERIFY_ARE_EQUAL(newViewportSize.height(), thirdHostView.BottomExclusive()); + VERIFY_ARE_EQUAL(newViewportSize.height, thirdHostView.BottomExclusive()); // The Terminal should be stuck to the top of the viewport, unless dy<0, // rows=50. In that set of cases, we _didn't_ pin the top of the Terminal to @@ -928,7 +927,7 @@ void ConptyRoundtripTests::TestResizeHeight() // Conpty's doesn't have a scrollback, it's view's origin is always 0,0 const auto fourthHostView = si.GetViewport(); VERIFY_ARE_EQUAL(0, fourthHostView.Top()); - VERIFY_ARE_EQUAL(newViewportSize.height(), fourthHostView.BottomExclusive()); + VERIFY_ARE_EQUAL(newViewportSize.height, fourthHostView.BottomExclusive()); // The Terminal should be stuck to the top of the viewport, unless dy<0, // rows=50. In that set of cases, we _didn't_ pin the top of the Terminal to @@ -1086,16 +1085,16 @@ void ConptyRoundtripTests::PassthroughClearAll() sm.ProcessString(L"~"); } - auto verifyBuffer = [&](const TextBuffer& tb, const til::rectangle viewport, const bool afterClear = false) { - const auto width = viewport.width(); + auto verifyBuffer = [&](const TextBuffer& tb, const til::rect& viewport, const bool afterClear = false) { + const auto width = viewport.narrow_width(); // "~" rows - for (short row = 0; row < viewport.bottom(); row++) + for (short row = 0; row < viewport.narrow_bottom(); row++) { Log::Comment(NoThrowString().Format(L"Checking row %d", row)); VERIFY_IS_FALSE(tb.GetRowByOffset(row).WasWrapForced()); auto iter = tb.GetCellDataAt({ 0, row }); - if (afterClear && row >= viewport.top()) + if (afterClear && row >= viewport.narrow_top()) { TestUtils::VerifySpanOfText(L" ", iter, 0, width); } @@ -1108,15 +1107,15 @@ void ConptyRoundtripTests::PassthroughClearAll() }; Log::Comment(L"========== Checking the host buffer state (before) =========="); - verifyBuffer(*hostTb, si.GetViewport().ToInclusive()); + verifyBuffer(*hostTb, til::rect{ si.GetViewport().ToInclusive() }); Log::Comment(L"Painting the frame"); VERIFY_SUCCEEDED(renderer.PaintFrame()); Log::Comment(L"========== Checking the terminal buffer state (before) =========="); - verifyBuffer(*termTb, term->_mutableViewport.ToInclusive()); + verifyBuffer(*termTb, til::rect{ term->_mutableViewport.ToInclusive() }); - const til::rectangle originalTerminalView{ term->_mutableViewport.ToInclusive() }; + const til::rect originalTerminalView{ term->_mutableViewport.ToInclusive() }; // Here, we'll emit the 2J to EraseAll, and move the viewport contents into // the scrollback. @@ -1127,12 +1126,12 @@ void ConptyRoundtripTests::PassthroughClearAll() // Make sure that the terminal's new viewport is actually just lower than it // used to be. - const til::rectangle newTerminalView{ term->_mutableViewport.ToInclusive() }; - VERIFY_ARE_EQUAL(end, newTerminalView.top()); - VERIFY_IS_GREATER_THAN(newTerminalView.top(), originalTerminalView.top()); + const til::rect newTerminalView{ term->_mutableViewport.ToInclusive() }; + VERIFY_ARE_EQUAL(end, newTerminalView.narrow_top()); + VERIFY_IS_GREATER_THAN(newTerminalView.top, originalTerminalView.top); Log::Comment(L"========== Checking the host buffer state (after) =========="); - verifyBuffer(*hostTb, si.GetViewport().ToInclusive(), true); + verifyBuffer(*hostTb, til::rect{ si.GetViewport().ToInclusive() }, true); Log::Comment(L"Painting the frame"); VERIFY_SUCCEEDED(renderer.PaintFrame()); @@ -1370,9 +1369,9 @@ void ConptyRoundtripTests::OutputWrappedLinesAtBottomOfBuffer() auto iter0 = tb.GetCellDataAt({ 0, wrappedRow }); TestUtils::VerifySpanOfText(L"A", iter0, 0, TerminalViewWidth); - auto iter1 = tb.GetCellDataAt({ 0, wrappedRow + 1 }); + auto iter1 = tb.GetCellDataAt({ 0, gsl::narrow(wrappedRow + 1) }); TestUtils::VerifySpanOfText(L"A", iter1, 0, 20); - auto iter2 = tb.GetCellDataAt({ 20, wrappedRow + 1 }); + auto iter2 = tb.GetCellDataAt({ 20, gsl::narrow(wrappedRow + 1) }); TestUtils::VerifySpanOfText(L" ", iter2, 0, TerminalViewWidth - 20); }; @@ -1457,9 +1456,9 @@ void ConptyRoundtripTests::ScrollWithChangesInMiddle() L"8"); // Restore hostSm.ProcessString(std::wstring(wrappedLineLength, L'A')); // Print 100 'A's - auto verifyBuffer = [](const TextBuffer& tb, const til::rectangle viewport) { - const short wrappedRow = viewport.bottom() - 2; - const short start = viewport.top(); + auto verifyBuffer = [](const TextBuffer& tb, const til::rect& viewport) { + const auto wrappedRow = gsl::narrow(viewport.bottom - 2); + const short start = viewport.narrow_top(); for (short i = start; i < wrappedRow; i++) { Log::Comment(NoThrowString().Format(L"Checking row %d", i)); @@ -1472,20 +1471,20 @@ void ConptyRoundtripTests::ScrollWithChangesInMiddle() auto iter0 = tb.GetCellDataAt({ 0, wrappedRow }); TestUtils::VerifySpanOfText(L"A", iter0, 0, TerminalViewWidth); - auto iter1 = tb.GetCellDataAt({ 0, wrappedRow + 1 }); + auto iter1 = tb.GetCellDataAt({ 0, gsl::narrow(wrappedRow + 1) }); TestUtils::VerifySpanOfText(L"A", iter1, 0, 20); - auto iter2 = tb.GetCellDataAt({ 20, wrappedRow + 1 }); + auto iter2 = tb.GetCellDataAt({ 20, gsl::narrow(wrappedRow + 1) }); TestUtils::VerifySpanOfText(L" ", iter2, 0, TerminalViewWidth - 20); }; Log::Comment(NoThrowString().Format(L"Checking the host buffer...")); - verifyBuffer(hostTb, hostView.ToInclusive()); + verifyBuffer(hostTb, til::rect{ hostView.ToInclusive() }); Log::Comment(NoThrowString().Format(L"... Done")); VERIFY_SUCCEEDED(renderer.PaintFrame()); Log::Comment(NoThrowString().Format(L"Checking the terminal buffer...")); - verifyBuffer(termTb, term->_mutableViewport.ToInclusive()); + verifyBuffer(termTb, til::rect{ term->_mutableViewport.ToInclusive() }); Log::Comment(NoThrowString().Format(L"... Done")); } @@ -1840,11 +1839,11 @@ void ConptyRoundtripTests::ClearHostTrickeryTest() _flushFirstFrame(); auto verifyBuffer = [&cursorOnNextLine, &useLongSpaces, &printTextAfterSpaces](const TextBuffer& tb, - const til::rectangle viewport) { + const til::rect viewport) { // We _would_ expect the Terminal's cursor to be on { 8, 0 }, but this // is currently broken due to #381/#4676. So we'll use the viewport // provided to find the actual Y position of the cursor. - const short viewTop = viewport.origin().y(); + const short viewTop = viewport.origin().narrow_y(); const short cursorRow = viewTop + (cursorOnNextLine ? 1 : 0); const short cursorCol = (cursorOnNextLine ? 5 : (10 + (useLongSpaces ? 5 : 0) + (printTextAfterSpaces ? 5 : 0))); @@ -1921,13 +1920,13 @@ void ConptyRoundtripTests::ClearHostTrickeryTest() hostSm.ProcessString(L"\x1b[?1049l"); Log::Comment(L"Checking the host buffer state"); - verifyBuffer(hostTb, si.GetViewport().ToInclusive()); + verifyBuffer(hostTb, til::rect{ si.GetViewport().ToInclusive() }); Log::Comment(L"Painting the frame"); VERIFY_SUCCEEDED(renderer.PaintFrame()); Log::Comment(L"Checking the terminal buffer state"); - verifyBuffer(termTb, term->_mutableViewport.ToInclusive()); + verifyBuffer(termTb, til::rect{ term->_mutableViewport.ToInclusive() }); } void ConptyRoundtripTests::OverstrikeAtBottomOfBuffer() @@ -1948,15 +1947,15 @@ void ConptyRoundtripTests::OverstrikeAtBottomOfBuffer() _flushFirstFrame(); auto verifyBuffer = [](const TextBuffer& tb, - const til::rectangle viewport) { - const auto lastRow = viewport.bottom() - 1; + const til::rect viewport) { + const auto lastRow = viewport.bottom - 1; const til::point expectedCursor{ 0, lastRow - 1 }; VERIFY_ARE_EQUAL(expectedCursor, til::point{ tb.GetCursor().GetPosition() }); VERIFY_IS_TRUE(tb.GetCursor().IsVisible()); - TestUtils::VerifyExpectedString(tb, L"AAAAAAAAAA DDDDDDDDDD", til::point{ 0, lastRow - 2 }); - TestUtils::VerifyExpectedString(tb, L"BBBBBBBBBB", til::point{ 0, lastRow - 1 }); - TestUtils::VerifyExpectedString(tb, L"FFFFFFFFFE", til::point{ 0, lastRow }); + TestUtils::VerifyExpectedString(tb, L"AAAAAAAAAA DDDDDDDDDD", COORD{ 0, gsl::narrow(lastRow - 2) }); + TestUtils::VerifyExpectedString(tb, L"BBBBBBBBBB", COORD{ 0, gsl::narrow(lastRow - 1) }); + TestUtils::VerifyExpectedString(tb, L"FFFFFFFFFE", COORD{ 0, gsl::narrow(lastRow) }); }; _logConpty = true; @@ -1993,14 +1992,14 @@ void ConptyRoundtripTests::OverstrikeAtBottomOfBuffer() hostSm.ProcessString(L"\n"); Log::Comment(L"========== Checking the host buffer state =========="); - verifyBuffer(hostTb, si.GetViewport().ToInclusive()); + verifyBuffer(hostTb, til::rect{ si.GetViewport().ToInclusive() }); Log::Comment(L"Painting the frame"); VERIFY_SUCCEEDED(renderer.PaintFrame()); Log::Comment(L"========== Checking the terminal buffer state =========="); - verifyBuffer(termTb, term->_mutableViewport.ToInclusive()); + verifyBuffer(termTb, til::rect{ term->_mutableViewport.ToInclusive() }); } void ConptyRoundtripTests::MarginsWithStatusLine() @@ -2026,17 +2025,17 @@ void ConptyRoundtripTests::MarginsWithStatusLine() _flushFirstFrame(); auto verifyBuffer = [](const TextBuffer& tb, - const til::rectangle viewport) { - const auto lastRow = viewport.bottom() - 1; + const til::rect viewport) { + const auto lastRow = gsl::narrow(viewport.bottom - 1); const til::point expectedCursor{ 1, lastRow }; VERIFY_ARE_EQUAL(expectedCursor, til::point{ tb.GetCursor().GetPosition() }); VERIFY_IS_TRUE(tb.GetCursor().IsVisible()); - TestUtils::VerifyExpectedString(tb, L"EEEEEEEEEE", til::point{ 0, lastRow - 4 }); - TestUtils::VerifyExpectedString(tb, L"AAAAAAAAAA", til::point{ 0, lastRow - 3 }); - TestUtils::VerifyExpectedString(tb, L" ", til::point{ 0, lastRow - 2 }); - TestUtils::VerifyExpectedString(tb, L"XBBBBBBBBB", til::point{ 0, lastRow - 1 }); - TestUtils::VerifyExpectedString(tb, L"YCCCCCCCCC", til::point{ 0, lastRow }); + TestUtils::VerifyExpectedString(tb, L"EEEEEEEEEE", COORD{ 0, gsl::narrow(lastRow - 4) }); + TestUtils::VerifyExpectedString(tb, L"AAAAAAAAAA", COORD{ 0, gsl::narrow(lastRow - 3) }); + TestUtils::VerifyExpectedString(tb, L" ", COORD{ 0, gsl::narrow(lastRow - 2) }); + TestUtils::VerifyExpectedString(tb, L"XBBBBBBBBB", COORD{ 0, gsl::narrow(lastRow - 1) }); + TestUtils::VerifyExpectedString(tb, L"YCCCCCCCCC", COORD{ 0, lastRow }); }; // We're _not_ checking the conpty output during this test, only the side effects. @@ -2076,7 +2075,7 @@ void ConptyRoundtripTests::MarginsWithStatusLine() src.Left = 0; src.Right = si.GetViewport().Width(); src.Bottom = originalBottom; - COORD tgt = { 0, newBottom - 1 }; + COORD tgt{ 0, gsl::narrow(newBottom - 1) }; TextAttribute useThisAttr(0x07); // We don't terribly care about the attributes so this is arbitrary ScrollRegion(si, src, std::nullopt, tgt, L' ', useThisAttr); } @@ -2090,14 +2089,14 @@ void ConptyRoundtripTests::MarginsWithStatusLine() hostSm.ProcessString(L"Y"); Log::Comment(L"========== Checking the host buffer state =========="); - verifyBuffer(hostTb, si.GetViewport().ToInclusive()); + verifyBuffer(hostTb, til::rect{ si.GetViewport().ToInclusive() }); Log::Comment(L"Painting the frame"); VERIFY_SUCCEEDED(renderer.PaintFrame()); Log::Comment(L"========== Checking the terminal buffer state =========="); - verifyBuffer(termTb, term->_mutableViewport.ToInclusive()); + verifyBuffer(termTb, til::rect{ term->_mutableViewport.ToInclusive() }); } void ConptyRoundtripTests::OutputWrappedLineWithSpace() @@ -2273,7 +2272,7 @@ void ConptyRoundtripTests::OutputWrappedLineWithSpaceAtBottomOfBuffer() sm.ProcessString(std::wstring(spacesLength, L' ')); sm.ProcessString(std::wstring(secondTextLength, L'B')); - auto verifyBuffer = [&](const TextBuffer& tb, const til::rectangle viewport) { + auto verifyBuffer = [&](const TextBuffer& tb, const til::rect& viewport) { // Buffer contents should look like the following: (80 wide) // (w) means we hard wrapped the line // (b) means the line is _not_ wrapped (it's broken, the default state.) @@ -2282,7 +2281,7 @@ void ConptyRoundtripTests::OutputWrappedLineWithSpaceAtBottomOfBuffer() // | B_ ... | (b) (cursor is on the '_') // | ... | (b) - const short wrappedRow = viewport.bottom() - 2; + const auto wrappedRow = gsl::narrow(viewport.bottom - 2); VERIFY_IS_TRUE(tb.GetRowByOffset(wrappedRow).WasWrapForced()); VERIFY_IS_FALSE(tb.GetRowByOffset(wrappedRow + 1).WasWrapForced()); @@ -2292,20 +2291,20 @@ void ConptyRoundtripTests::OutputWrappedLineWithSpaceAtBottomOfBuffer() TestUtils::VerifySpanOfText(L" ", iter0, 0, 2); // Second row - auto iter1 = tb.GetCellDataAt({ 0, wrappedRow + 1 }); + auto iter1 = tb.GetCellDataAt({ 0, gsl::narrow(wrappedRow + 1) }); TestUtils::VerifySpanOfText(L" ", iter1, 0, 1); - auto iter2 = tb.GetCellDataAt({ 1, wrappedRow + 1 }); + auto iter2 = tb.GetCellDataAt({ 1, gsl::narrow(wrappedRow + 1) }); TestUtils::VerifySpanOfText(L"B", iter2, 0, secondTextLength); }; Log::Comment(L"========== Checking the host buffer state =========="); - verifyBuffer(hostTb, hostView.ToInclusive()); + verifyBuffer(hostTb, til::rect{ hostView.ToInclusive() }); Log::Comment(L"Painting the frame"); VERIFY_SUCCEEDED(renderer.PaintFrame()); Log::Comment(L"========== Checking the terminal buffer state =========="); - verifyBuffer(termTb, term->_mutableViewport.ToInclusive()); + verifyBuffer(termTb, til::rect{ term->_mutableViewport.ToInclusive() }); } void ConptyRoundtripTests::BreakLinesOnCursorMovement() @@ -2344,22 +2343,22 @@ void ConptyRoundtripTests::BreakLinesOnCursorMovement() (cursorMovementMode == MoveCursorWithCUB_LF); auto verifyBuffer = [&](const TextBuffer& tb, - const til::rectangle viewport) { - const auto lastRow = viewport.bottom() - 1; + const til::rect viewport) { + const auto lastRow = gsl::narrow(viewport.bottom - 1); const til::point expectedCursor{ 5, lastRow }; VERIFY_ARE_EQUAL(expectedCursor, til::point{ tb.GetCursor().GetPosition() }); VERIFY_IS_TRUE(tb.GetCursor().IsVisible()); - for (auto y = viewport.top(); y < lastRow; y++) + for (auto y = viewport.narrow_top(); y < lastRow; y++) { // We're using CUP to move onto the status line _always_, so the // second-last row will always be marked as wrapped. const auto rowWrapped = (!expectHardBreak) || (y == lastRow - 1); VERIFY_ARE_EQUAL(rowWrapped, tb.GetRowByOffset(y).WasWrapForced()); - TestUtils::VerifyExpectedString(tb, L"~ ", til::point{ 0, y }); + TestUtils::VerifyExpectedString(tb, L"~ ", COORD{ 0, y }); } - TestUtils::VerifyExpectedString(tb, L"AAAAA", til::point{ 0, lastRow }); + TestUtils::VerifyExpectedString(tb, L"AAAAA", COORD{ 0, lastRow }); }; // We're _not_ checking the conpty output during this test, only the side effects. @@ -2468,14 +2467,14 @@ void ConptyRoundtripTests::BreakLinesOnCursorMovement() hostSm.ProcessString(L"AAAAA"); Log::Comment(L"========== Checking the host buffer state =========="); - verifyBuffer(altTextBuffer, altBuffer.GetViewport().ToInclusive()); + verifyBuffer(altTextBuffer, til::rect{ altBuffer.GetViewport().ToInclusive() }); Log::Comment(L"Painting the frame"); VERIFY_SUCCEEDED(renderer.PaintFrame()); Log::Comment(L"========== Checking the terminal buffer state =========="); - verifyBuffer(termTb, term->_mutableViewport.ToInclusive()); + verifyBuffer(termTb, til::rect{ term->_mutableViewport.ToInclusive() }); } void ConptyRoundtripTests::TestCursorInDeferredEOLPositionOnNewLineWithSpaces() @@ -2519,7 +2518,7 @@ void ConptyRoundtripTests::TestCursorInDeferredEOLPositionOnNewLineWithSpaces() VERIFY_IS_FALSE(lastRow.WasWrapForced()); auto expectedStringSecondToLastRow{ std::wstring(gsl::narrow_cast(tb.GetSize().Width()) - 1, L'A') + L" " }; - TestUtils::VerifyExpectedString(tb, expectedStringSecondToLastRow, { 0, bottomRow - 1 }); + TestUtils::VerifyExpectedString(tb, expectedStringSecondToLastRow, { 0, gsl::narrow(bottomRow - 1) }); TestUtils::VerifyExpectedString(tb, L"B", { 0, bottomRow }); }; @@ -2588,9 +2587,9 @@ void ConptyRoundtripTests::ResizeRepaintVimExeBuffer() drawVim(); - auto verifyBuffer = [&](const TextBuffer& tb, const til::rectangle viewport) { - const auto firstRow = viewport.top(); - const auto width = viewport.width(); + auto verifyBuffer = [&](const TextBuffer& tb, const til::rect& viewport) { + const auto firstRow = viewport.narrow_top(); + const auto width = viewport.narrow_width(); // First row VERIFY_IS_FALSE(tb.GetRowByOffset(firstRow).WasWrapForced()); @@ -2600,12 +2599,12 @@ void ConptyRoundtripTests::ResizeRepaintVimExeBuffer() // Second row VERIFY_IS_FALSE(tb.GetRowByOffset(firstRow + 1).WasWrapForced()); - auto iter1 = tb.GetCellDataAt({ 0, firstRow + 1 }); + auto iter1 = tb.GetCellDataAt({ 0, gsl::narrow(firstRow + 1) }); TestUtils::VerifySpanOfText(L"B", iter1, 0, 3); TestUtils::VerifySpanOfText(L" ", iter1, 0, width - 3); // "~" rows - for (short row = firstRow + 2; row < viewport.bottom() - 1; row++) + for (short row = firstRow + 2; row < viewport.bottom - 1; row++) { Log::Comment(NoThrowString().Format(L"Checking row %d", row)); VERIFY_IS_TRUE(tb.GetRowByOffset(row).WasWrapForced()); @@ -2616,7 +2615,7 @@ void ConptyRoundtripTests::ResizeRepaintVimExeBuffer() // Last row { - short row = viewport.bottom() - 1; + const auto row = gsl::narrow(viewport.bottom - 1); Log::Comment(NoThrowString().Format(L"Checking row %d", row)); VERIFY_IS_TRUE(tb.GetRowByOffset(row).WasWrapForced()); auto iter = tb.GetCellDataAt({ 0, row }); @@ -2626,13 +2625,13 @@ void ConptyRoundtripTests::ResizeRepaintVimExeBuffer() }; Log::Comment(L"========== Checking the host buffer state (before) =========="); - verifyBuffer(*hostTb, si.GetViewport().ToInclusive()); + verifyBuffer(*hostTb, til::rect{ si.GetViewport().ToInclusive() }); Log::Comment(L"Painting the frame"); VERIFY_SUCCEEDED(renderer.PaintFrame()); Log::Comment(L"========== Checking the terminal buffer state (before) =========="); - verifyBuffer(*termTb, term->_mutableViewport.ToInclusive()); + verifyBuffer(*termTb, til::rect{ term->_mutableViewport.ToInclusive() }); // After we resize, make sure to get the new textBuffers std::tie(hostTb, termTb) = _performResize({ TerminalViewWidth - 1, @@ -2646,13 +2645,13 @@ void ConptyRoundtripTests::ResizeRepaintVimExeBuffer() drawVim(); Log::Comment(L"========== Checking the host buffer state (after) =========="); - verifyBuffer(*hostTb, si.GetViewport().ToInclusive()); + verifyBuffer(*hostTb, til::rect{ si.GetViewport().ToInclusive() }); Log::Comment(L"Painting the frame"); VERIFY_SUCCEEDED(renderer.PaintFrame()); Log::Comment(L"========== Checking the terminal buffer state (after) =========="); - verifyBuffer(*termTb, term->_mutableViewport.ToInclusive()); + verifyBuffer(*termTb, til::rect{ term->_mutableViewport.ToInclusive() }); } void ConptyRoundtripTests::ClsAndClearHostClearsScrollbackTest() @@ -2698,11 +2697,11 @@ void ConptyRoundtripTests::ClsAndClearHostClearsScrollbackTest() sm.ProcessString(L"~"); } - auto verifyBuffer = [&](const TextBuffer& tb, const til::rectangle viewport, const bool afterClear = false) { - const auto width = viewport.width(); + auto verifyBuffer = [&](const TextBuffer& tb, const til::rect& viewport, const bool afterClear = false) { + const auto width = viewport.narrow_width(); // "~" rows - for (short row = 0; row < viewport.bottom(); row++) + for (short row = 0; row < viewport.narrow_bottom(); row++) { Log::Comment(NoThrowString().Format(L"Checking row %d", row)); VERIFY_IS_FALSE(tb.GetRowByOffset(row).WasWrapForced()); @@ -2720,13 +2719,13 @@ void ConptyRoundtripTests::ClsAndClearHostClearsScrollbackTest() }; Log::Comment(L"========== Checking the host buffer state (before) =========="); - verifyBuffer(*hostTb, si.GetViewport().ToInclusive()); + verifyBuffer(*hostTb, til::rect{ si.GetViewport().ToInclusive() }); Log::Comment(L"Painting the frame"); VERIFY_SUCCEEDED(renderer.PaintFrame()); Log::Comment(L"========== Checking the terminal buffer state (before) =========="); - verifyBuffer(*termTb, term->_mutableViewport.ToInclusive()); + verifyBuffer(*termTb, til::rect{ term->_mutableViewport.ToInclusive() }); VERIFY_ARE_EQUAL(si.GetViewport().Dimensions(), si.GetBufferSize().Dimensions()); VERIFY_ARE_EQUAL(si.GetViewport(), si.GetBufferSize()); @@ -2790,12 +2789,12 @@ void ConptyRoundtripTests::ClsAndClearHostClearsScrollbackTest() VERIFY_SUCCEEDED(renderer.PaintFrame()); Log::Comment(L"========== Checking the host buffer state (after) =========="); - verifyBuffer(*hostTb, si.GetViewport().ToInclusive(), true); + verifyBuffer(*hostTb, til::rect{ si.GetViewport().ToInclusive() }, true); Log::Comment(L"Painting the frame"); VERIFY_SUCCEEDED(renderer.PaintFrame()); Log::Comment(L"========== Checking the terminal buffer state (after) =========="); - verifyBuffer(*termTb, term->_mutableViewport.ToInclusive(), true); + verifyBuffer(*termTb, til::rect{ term->_mutableViewport.ToInclusive() }, true); } void ConptyRoundtripTests::TestResizeWithCookedRead() @@ -2934,8 +2933,8 @@ void ConptyRoundtripTests::ResizeInitializeBufferWithDefaultAttrs() sm.ProcessString(L"#"); } - auto verifyBuffer = [&](const TextBuffer& tb, const til::rectangle viewport, const bool isTerminal, const bool afterResize) { - const auto width = viewport.width(); + auto verifyBuffer = [&](const TextBuffer& tb, const til::rect& viewport, const bool isTerminal, const bool afterResize) { + const auto width = viewport.narrow_width(); // Conhost and Terminal attributes are potentially different. const auto greenAttrs = isTerminal ? terminalGreenAttrs : conhostGreenAttrs; @@ -2967,19 +2966,19 @@ void ConptyRoundtripTests::ResizeInitializeBufferWithDefaultAttrs() } else { - TestUtils::VerifyLineContains(tb, { 0, row }, L' ', actualDefaultAttrs, viewport.width()); + TestUtils::VerifyLineContains(tb, { 0, row }, L' ', actualDefaultAttrs, viewport.narrow_width()); } } }; Log::Comment(L"========== Checking the host buffer state (before) =========="); - verifyBuffer(*hostTb, si.GetViewport().ToInclusive(), false, false); + verifyBuffer(*hostTb, til::rect{ si.GetViewport().ToInclusive() }, false, false); Log::Comment(L"Painting the frame"); VERIFY_SUCCEEDED(renderer.PaintFrame()); Log::Comment(L"========== Checking the terminal buffer state (before) =========="); - verifyBuffer(*termTb, term->_mutableViewport.ToInclusive(), true, false); + verifyBuffer(*termTb, til::rect{ term->_mutableViewport.ToInclusive() }, true, false); // After we resize, make sure to get the new textBuffers std::tie(hostTb, termTb) = _performResize({ TerminalViewWidth + dx, @@ -2989,13 +2988,13 @@ void ConptyRoundtripTests::ResizeInitializeBufferWithDefaultAttrs() VERIFY_SUCCEEDED(renderer.PaintFrame()); Log::Comment(L"========== Checking the host buffer state (after) =========="); - verifyBuffer(*hostTb, si.GetViewport().ToInclusive(), false, true); + verifyBuffer(*hostTb, til::rect{ si.GetViewport().ToInclusive() }, false, true); Log::Comment(L"Painting the frame"); VERIFY_SUCCEEDED(renderer.PaintFrame()); Log::Comment(L"========== Checking the terminal buffer state (after) =========="); - verifyBuffer(*termTb, term->_mutableViewport.ToInclusive(), true, true); + verifyBuffer(*termTb, til::rect{ term->_mutableViewport.ToInclusive() }, true, true); } void ConptyRoundtripTests::NewLinesAtBottomWithBackground() @@ -3072,20 +3071,20 @@ void ConptyRoundtripTests::NewLinesAtBottomWithBackground() } } - auto verifyBuffer = [&](const TextBuffer& tb, const til::rectangle viewport) { - const auto width = viewport.width(); - const auto isTerminal = viewport.top() != 0; + auto verifyBuffer = [&](const TextBuffer& tb, const til::rect& viewport) { + const auto width = viewport.narrow_width(); + const auto isTerminal = viewport.top != 0; // Conhost and Terminal attributes are potentially different. const auto blueAttrs = isTerminal ? terminalBlueAttrs : conhostBlueAttrs; - for (short row = 0; row < viewport.bottom() - 2; row++) + for (short row = 0; row < viewport.bottom - 2; row++) { Log::Comment(NoThrowString().Format(L"Checking row %d", row)); VERIFY_IS_FALSE(tb.GetRowByOffset(row).WasWrapForced()); const auto isBlank = (row % 2) == 0; - const auto rowCircled = row > (viewport.bottom() - 1 - circledRows); + const auto rowCircled = row > (viewport.bottom - 1 - circledRows); // When the buffer circles, new lines will be initialized using the // current text attributes. Those will be the default-on-default // attributes. All of the Terminal's buffer will use @@ -3095,7 +3094,7 @@ void ConptyRoundtripTests::NewLinesAtBottomWithBackground() if (isBlank) { - TestUtils::VerifyLineContains(tb, { 0, row }, L' ', actualDefaultAttrs, viewport.width()); + TestUtils::VerifyLineContains(tb, { 0, row }, L' ', actualDefaultAttrs, viewport.narrow_width()); } else { @@ -3109,13 +3108,13 @@ void ConptyRoundtripTests::NewLinesAtBottomWithBackground() }; Log::Comment(L"========== Checking the host buffer state =========="); - verifyBuffer(*hostTb, si.GetViewport().ToInclusive()); + verifyBuffer(*hostTb, til::rect{ si.GetViewport().ToInclusive() }); Log::Comment(L"Painting the frame"); VERIFY_SUCCEEDED(renderer.PaintFrame()); Log::Comment(L"========== Checking the terminal buffer state =========="); - verifyBuffer(*termTb, term->_mutableViewport.ToInclusive()); + verifyBuffer(*termTb, til::rect{ term->_mutableViewport.ToInclusive() }); } void doWriteCharsLegacy(SCREEN_INFORMATION& screenInfo, const std::wstring_view string, DWORD flags = 0) @@ -3272,17 +3271,17 @@ void ConptyRoundtripTests::WrapNewLineAtBottom() // row[4]: |~~~~~~~~~~~~~~~~~~~| // row[5]: |~~~~~~ | - auto verifyBuffer = [&](const TextBuffer& tb, const til::rectangle viewport) { - const auto width = viewport.width(); - const auto isTerminal = viewport.top() != 0; + auto verifyBuffer = [&](const TextBuffer& tb, const til::rect& viewport) { + const auto width = viewport.narrow_width(); + const auto isTerminal = viewport.top != 0; - for (short row = 0; row < viewport.bottom(); row++) + for (short row = 0; row < viewport.narrow_bottom(); row++) { Log::Comment(NoThrowString().Format(L"Checking row %d", row)); // The first line wrapped, the second didn't, so on and so forth const auto isWrapped = (row % 2) == 0; - const auto rowCircled = row >= (viewport.bottom() - circledRows); + const auto rowCircled = row >= (viewport.bottom - circledRows); const auto actualNonSpacesAttrs = defaultAttrs; const auto actualSpacesAttrs = rowCircled || isTerminal ? defaultAttrs : conhostDefaultAttrs; @@ -3290,25 +3289,25 @@ void ConptyRoundtripTests::WrapNewLineAtBottom() VERIFY_ARE_EQUAL(isWrapped, tb.GetRowByOffset(row).WasWrapForced()); if (isWrapped) { - TestUtils::VerifyExpectedString(tb, std::wstring(charsInFirstLine, L'~'), til::point{ 0, row }); + TestUtils::VerifyExpectedString(tb, std::wstring(charsInFirstLine, L'~'), COORD{ 0, row }); } else { - auto iter = TestUtils::VerifyExpectedString(tb, std::wstring(charsInSecondLine, L'~'), til::point{ 0, row }); + auto iter = TestUtils::VerifyExpectedString(tb, std::wstring(charsInSecondLine, L'~'), COORD{ 0, row }); TestUtils::VerifyExpectedString(std::wstring(width - charsInSecondLine, L' '), iter); } } }; Log::Comment(L"========== Checking the host buffer state =========="); - verifyBuffer(*hostTb, si.GetViewport().ToInclusive()); + verifyBuffer(*hostTb, til::rect{ si.GetViewport().ToInclusive() }); Log::Comment(L"Painting the frame"); VERIFY_SUCCEEDED(renderer.PaintFrame()); Log::Comment(L"========== Checking the terminal buffer state =========="); VERIFY_ARE_EQUAL(circledRows, term->_mutableViewport.Top()); - verifyBuffer(*termTb, term->_mutableViewport.ToInclusive()); + verifyBuffer(*termTb, til::rect{ term->_mutableViewport.ToInclusive() }); } void ConptyRoundtripTests::WrapNewLineAtBottomLikeMSYS() @@ -3474,10 +3473,10 @@ void ConptyRoundtripTests::WrapNewLineAtBottomLikeMSYS() } } - auto verifyBuffer = [&](const TextBuffer& tb, const til::rectangle viewport) { - const auto width = viewport.width(); - const auto isTerminal = viewport.top() != 0; - auto lastRow = viewport.bottom() - 1; + auto verifyBuffer = [&](const TextBuffer& tb, const til::rect& viewport) { + const auto width = viewport.narrow_width(); + const auto isTerminal = viewport.top != 0; + auto lastRow = gsl::narrow(viewport.bottom - 1); for (short row = 0; row < lastRow; row++) { Log::Comment(NoThrowString().Format(L"Checking row %d", row)); @@ -3489,7 +3488,7 @@ void ConptyRoundtripTests::WrapNewLineAtBottomLikeMSYS() // buffer, then the top line of the conpty will _not_ be wrapped, // when the 0th line of the terminal buffer _is_. const auto isWrapped = (row % 2) == (isTerminal ? 0 : 1); - const auto rowCircled = row >= (viewport.bottom() - circledRows); + const auto rowCircled = row >= (viewport.bottom - circledRows); const auto actualNonSpacesAttrs = defaultAttrs; const auto actualSpacesAttrs = rowCircled || isTerminal ? defaultAttrs : conhostDefaultAttrs; @@ -3497,28 +3496,28 @@ void ConptyRoundtripTests::WrapNewLineAtBottomLikeMSYS() VERIFY_ARE_EQUAL(isWrapped, tb.GetRowByOffset(row).WasWrapForced()); if (isWrapped) { - TestUtils::VerifyExpectedString(tb, std::wstring(charsInFirstLine, L'~'), til::point{ 0, row }); + TestUtils::VerifyExpectedString(tb, std::wstring(charsInFirstLine, L'~'), COORD{ 0, row }); } else { - auto iter = TestUtils::VerifyExpectedString(tb, std::wstring(charsInSecondLine, L'~'), til::point{ 0, row }); + auto iter = TestUtils::VerifyExpectedString(tb, std::wstring(charsInSecondLine, L'~'), COORD{ 0, row }); TestUtils::VerifyExpectedString(std::wstring(width - charsInSecondLine, L' '), iter); } } VERIFY_IS_FALSE(tb.GetRowByOffset(lastRow).WasWrapForced()); - auto iter = TestUtils::VerifyExpectedString(tb, std::wstring(1, L':'), til::point{ 0, lastRow }); + auto iter = TestUtils::VerifyExpectedString(tb, std::wstring(1, L':'), COORD{ 0, lastRow }); TestUtils::VerifyExpectedString(std::wstring(width - 1, L' '), iter); }; Log::Comment(L"========== Checking the host buffer state =========="); - verifyBuffer(*hostTb, si.GetViewport().ToInclusive()); + verifyBuffer(*hostTb, til::rect{ si.GetViewport().ToInclusive() }); Log::Comment(L"Painting the frame"); VERIFY_SUCCEEDED(renderer.PaintFrame()); Log::Comment(L"========== Checking the terminal buffer state =========="); VERIFY_ARE_EQUAL(circledRows + 1, term->_mutableViewport.Top()); - verifyBuffer(*termTb, term->_mutableViewport.ToInclusive()); + verifyBuffer(*termTb, til::rect{ term->_mutableViewport.ToInclusive() }); } void ConptyRoundtripTests::DeleteWrappedWord() @@ -3550,8 +3549,8 @@ void ConptyRoundtripTests::DeleteWrappedWord() sm.ProcessString(std::wstring(50, L'B')); sm.ProcessString(L"\x1b[?25h"); - auto verifyBuffer = [&](const TextBuffer& tb, const til::rectangle viewport, const bool after) { - const auto width = viewport.width(); + auto verifyBuffer = [&](const TextBuffer& tb, const til::rect& viewport, const bool after) { + const auto width = viewport.narrow_width(); auto iter1 = tb.GetCellDataAt({ 0, 0 }); TestUtils::VerifySpanOfText(L"A", iter1, 0, 50); @@ -3574,12 +3573,12 @@ void ConptyRoundtripTests::DeleteWrappedWord() }; Log::Comment(L"========== Checking the host buffer state (before) =========="); - verifyBuffer(*hostTb, si.GetViewport().ToInclusive(), false); + verifyBuffer(*hostTb, til::rect{ si.GetViewport().ToInclusive() }, false); Log::Comment(L"Painting the frame"); VERIFY_SUCCEEDED(renderer.PaintFrame()); Log::Comment(L"========== Checking the terminal buffer state (before) =========="); - verifyBuffer(*termTb, term->_mutableViewport.ToInclusive(), false); + verifyBuffer(*termTb, til::rect{ term->_mutableViewport.ToInclusive() }, false); // Now, go back and erase all the 'B's, as if the user executed a // backward-kill-word in PowerShell. Afterwards, the buffer will look like: @@ -3603,12 +3602,12 @@ void ConptyRoundtripTests::DeleteWrappedWord() sm.ProcessString(L"\x1b[?25h"); Log::Comment(L"========== Checking the host buffer state (after) =========="); - verifyBuffer(*hostTb, si.GetViewport().ToInclusive(), true); + verifyBuffer(*hostTb, til::rect{ si.GetViewport().ToInclusive() }, true); Log::Comment(L"Painting the frame"); VERIFY_SUCCEEDED(renderer.PaintFrame()); Log::Comment(L"========== Checking the terminal buffer state (after) =========="); - verifyBuffer(*termTb, term->_mutableViewport.ToInclusive(), true); + verifyBuffer(*termTb, til::rect{ term->_mutableViewport.ToInclusive() }, true); } // This test checks that upon conpty rendering again, terminal still maintains @@ -3712,8 +3711,8 @@ void ConptyRoundtripTests::ClearBufferSignal() sm.ProcessString(L"\x1b[?m"); sm.ProcessString(L"\x1b[?25h"); - auto verifyBuffer = [&](const TextBuffer& tb, const til::rectangle viewport, const bool before) { - const short width = viewport.width(); + auto verifyBuffer = [&](const TextBuffer& tb, const til::rect& viewport, const bool before) { + const short width = viewport.narrow_width(); const short numCharsOnSecondLine = 50 - (width - 51); auto iter1 = tb.GetCellDataAt({ 0, 0 }); if (before) @@ -3733,21 +3732,21 @@ void ConptyRoundtripTests::ClearBufferSignal() }; Log::Comment(L"========== Checking the host buffer state (before) =========="); - verifyBuffer(*hostTb, si.GetViewport().ToInclusive(), true); + verifyBuffer(*hostTb, til::rect{ si.GetViewport().ToInclusive() }, true); Log::Comment(L"Painting the frame"); VERIFY_SUCCEEDED(renderer.PaintFrame()); Log::Comment(L"========== Checking the terminal buffer state (before) =========="); - verifyBuffer(*termTb, term->_mutableViewport.ToInclusive(), true); + verifyBuffer(*termTb, til::rect{ term->_mutableViewport.ToInclusive() }, true); Log::Comment(L"========== Clear the ConPTY buffer with the signal =========="); _clearConpty(); Log::Comment(L"========== Checking the host buffer state (after) =========="); - verifyBuffer(*hostTb, si.GetViewport().ToInclusive(), false); + verifyBuffer(*hostTb, til::rect{ si.GetViewport().ToInclusive() }, false); Log::Comment(L"Painting the frame"); VERIFY_SUCCEEDED(renderer.PaintFrame()); Log::Comment(L"========== Checking the terminal buffer state (after) =========="); - verifyBuffer(*termTb, term->_mutableViewport.ToInclusive(), false); + verifyBuffer(*termTb, til::rect{ term->_mutableViewport.ToInclusive() }, false); } diff --git a/src/cascadia/WinRTUtils/inc/Utils.h b/src/cascadia/WinRTUtils/inc/Utils.h index 6c275b1e26..0083662a39 100644 --- a/src/cascadia/WinRTUtils/inc/Utils.h +++ b/src/cascadia/WinRTUtils/inc/Utils.h @@ -3,23 +3,6 @@ #pragma once -// Method Description: -// - Scales a Rect based on a scale factor -// Arguments: -// - rect: Rect to scale by scale -// - scale: amount to scale rect by -// Return Value: -// - Rect scaled by scale -inline winrt::Windows::Foundation::Rect ScaleRect(winrt::Windows::Foundation::Rect rect, double scale) -{ - const auto scaleLocal = base::ClampedNumeric(scale); - rect.X = base::ClampMul(rect.X, scaleLocal); - rect.Y = base::ClampMul(rect.Y, scaleLocal); - rect.Width = base::ClampMul(rect.Width, scaleLocal); - rect.Height = base::ClampMul(rect.Height, scaleLocal); - return rect; -} - // Function Description: // - This function presents a File Open "common dialog" and returns its selected file asynchronously. // Parameters: diff --git a/src/cascadia/WindowsTerminal/AppHost.cpp b/src/cascadia/WindowsTerminal/AppHost.cpp index c8ffa8320e..9a345e18b5 100644 --- a/src/cascadia/WindowsTerminal/AppHost.cpp +++ b/src/cascadia/WindowsTerminal/AppHost.cpp @@ -532,10 +532,10 @@ void AppHost::_HandleCreateWindow(const HWND hwnd, RECT proposedRect, LaunchMode // Get the size of a window we'd need to host that client rect. This will // add the titlebar space. - const til::size nonClientSize = _window->GetTotalNonClientExclusiveSize(dpix); - const til::rectangle nonClientFrame = _window->GetNonClientFrame(dpix); - adjustedWidth = islandWidth + nonClientSize.width(); - adjustedHeight = islandHeight + nonClientSize.height(); + const til::size nonClientSize{ _window->GetTotalNonClientExclusiveSize(dpix) }; + const til::rect nonClientFrame{ _window->GetNonClientFrame(dpix) }; + adjustedWidth = islandWidth + nonClientSize.width; + adjustedHeight = islandHeight + nonClientSize.height; til::size dimensions{ Utils::ClampToShortMax(adjustedWidth, 1), Utils::ClampToShortMax(adjustedHeight, 1) }; @@ -554,7 +554,7 @@ void AppHost::_HandleCreateWindow(const HWND hwnd, RECT proposedRect, LaunchMode // for the top here - the IslandWindow includes the titlebar in // nonClientFrame.top, so adjusting for that would actually place the // titlebar _off_ the monitor. - til::point origin{ (proposedRect.left + nonClientFrame.left()), + til::point origin{ (proposedRect.left + nonClientFrame.left), (proposedRect.top) }; if (_logic.IsQuakeWindow()) @@ -564,12 +564,12 @@ void AppHost::_HandleCreateWindow(const HWND hwnd, RECT proposedRect, LaunchMode const til::size availableSpace = desktopDimensions + nonClientSize; origin = til::point{ - ::base::ClampSub(nearestMonitorInfo.rcWork.left, (nonClientSize.width() / 2)), + ::base::ClampSub(nearestMonitorInfo.rcWork.left, (nonClientSize.width / 2)), (nearestMonitorInfo.rcWork.top) }; dimensions = til::size{ - availableSpace.width(), - availableSpace.height() / 2 + availableSpace.width, + availableSpace.height / 2 }; launchMode = LaunchMode::FocusMode; } @@ -577,18 +577,18 @@ void AppHost::_HandleCreateWindow(const HWND hwnd, RECT proposedRect, LaunchMode { // Move our proposed location into the center of that specific monitor. origin = til::point{ - (nearestMonitorInfo.rcWork.left + ((desktopDimensions.width() / 2) - (dimensions.width() / 2))), - (nearestMonitorInfo.rcWork.top + ((desktopDimensions.height() / 2) - (dimensions.height() / 2))) + (nearestMonitorInfo.rcWork.left + ((desktopDimensions.width / 2) - (dimensions.width / 2))), + (nearestMonitorInfo.rcWork.top + ((desktopDimensions.height / 2) - (dimensions.height / 2))) }; } - const til::rectangle newRect{ origin, dimensions }; + const til::rect newRect{ origin, dimensions }; bool succeeded = SetWindowPos(hwnd, nullptr, - newRect.left(), - newRect.top(), - newRect.width(), - newRect.height(), + newRect.left, + newRect.top, + newRect.width(), + newRect.height(), SWP_NOACTIVATE | SWP_NOZORDER); // Refresh the dpi of HWND because the dpi where the window will launch may be different @@ -705,7 +705,7 @@ void AppHost::_WindowMouseWheeled(const til::point coord, const int32_t delta) if (_logic) { // Find all the elements that are underneath the mouse - auto elems = winrt::Windows::UI::Xaml::Media::VisualTreeHelper::FindElementsInHostCoordinates(coord, _logic.GetRoot()); + auto elems = winrt::Windows::UI::Xaml::Media::VisualTreeHelper::FindElementsInHostCoordinates(coord.to_winrt_point(), _logic.GetRoot()); for (const auto& e : elems) { // If that element has implemented IMouseWheelListener, call OnMouseWheel on that element. @@ -716,7 +716,7 @@ void AppHost::_WindowMouseWheeled(const til::point coord, const int32_t delta) // Translate the event to the coordinate space of the control // we're attempting to dispatch it to const auto transform = e.TransformToVisual(nullptr); - const til::point controlOrigin{ til::math::flooring, transform.TransformPoint(til::point{ 0, 0 }) }; + const til::point controlOrigin{ til::math::flooring, transform.TransformPoint({}) }; const til::point offsetPoint = coord - controlOrigin; @@ -724,7 +724,7 @@ void AppHost::_WindowMouseWheeled(const til::point coord, const int32_t delta) const auto mButtonDown = WI_IsFlagSet(GetKeyState(VK_MBUTTON), KeyPressed); const auto rButtonDown = WI_IsFlagSet(GetKeyState(VK_RBUTTON), KeyPressed); - if (control.OnMouseWheel(offsetPoint, delta, lButtonDown, mButtonDown, rButtonDown)) + if (control.OnMouseWheel(offsetPoint.to_winrt_point(), delta, lButtonDown, mButtonDown, rButtonDown)) { // If the element handled the mouse wheel event, don't // continue to iterate over the remaining controls. diff --git a/src/cascadia/WindowsTerminal/IslandWindow.cpp b/src/cascadia/WindowsTerminal/IslandWindow.cpp index 87a4d34537..cbd2509385 100644 --- a/src/cascadia/WindowsTerminal/IslandWindow.cpp +++ b/src/cascadia/WindowsTerminal/IslandWindow.cpp @@ -202,8 +202,7 @@ LRESULT IslandWindow::_OnSizing(const WPARAM wParam, const LPARAM lParam) // bad parameters, which we won't have, so no big deal. LOG_IF_FAILED(GetDpiForMonitor(hmon, MDT_EFFECTIVE_DPI, &dpix, &dpiy)); - const auto widthScale = base::ClampedNumeric(dpix) / USER_DEFAULT_SCREEN_DPI; - const long minWidthScaled = minimumWidth * widthScale; + const long minWidthScaled = minimumWidth * dpix / USER_DEFAULT_SCREEN_DPI; const auto nonClientSize = GetTotalNonClientExclusiveSize(dpix); @@ -383,11 +382,10 @@ void IslandWindow::_OnGetMinMaxInfo(const WPARAM /*wParam*/, const LPARAM lParam // From now we use dpix for all computations (same as in _OnSizing). const auto nonClientSizeScaled = GetTotalNonClientExclusiveSize(dpix); - const auto scale = base::ClampedNumeric(dpix) / USER_DEFAULT_SCREEN_DPI; auto lpMinMaxInfo = reinterpret_cast(lParam); - lpMinMaxInfo->ptMinTrackSize.x = _calculateTotalSize(true, minimumWidth * scale, nonClientSizeScaled.cx); - lpMinMaxInfo->ptMinTrackSize.y = _calculateTotalSize(false, minimumHeight * scale, nonClientSizeScaled.cy); + lpMinMaxInfo->ptMinTrackSize.x = _calculateTotalSize(true, minimumWidth * dpix / USER_DEFAULT_SCREEN_DPI, nonClientSizeScaled.cx); + lpMinMaxInfo->ptMinTrackSize.y = _calculateTotalSize(false, minimumHeight * dpiy / USER_DEFAULT_SCREEN_DPI, nonClientSizeScaled.cy); } // Method Description: @@ -521,11 +519,12 @@ long IslandWindow::_calculateTotalSize(const bool isWidth, const long clientSize // and HIWORD treat the coordinates as unsigned quantities. const til::point eventPoint{ GET_X_LPARAM(lparam), GET_Y_LPARAM(lparam) }; // This mouse event is relative to the display origin, not the window. Convert here. - const til::rectangle windowRect{ GetWindowRect() }; + const til::rect windowRect{ GetWindowRect() }; const auto origin = windowRect.origin(); const auto relative = eventPoint - origin; // Convert to logical scaling before raising the event. - const auto real = relative / GetCurrentDpiScale(); + const auto scale = GetCurrentDpiScale(); + const til::point real{ til::math::flooring, relative.x / scale, relative.y / scale }; const short wheelDelta = static_cast(HIWORD(wparam)); @@ -574,8 +573,8 @@ long IslandWindow::_calculateTotalSize(const bool isWidth, const long clientSize GetMonitorInfo(proposed, &proposedInfo); // If the monitor changed... - if (til::rectangle{ proposedInfo.rcMonitor } != - til::rectangle{ currentInfo.rcMonitor }) + if (til::rect{ proposedInfo.rcMonitor } != + til::rect{ currentInfo.rcMonitor }) { const auto newWindowRect{ _getQuakeModeSize(proposed) }; @@ -583,10 +582,10 @@ long IslandWindow::_calculateTotalSize(const bool isWidth, const long clientSize // and dimensions that _getQuakeModeSize returned. When we // snap across monitor boundaries, this will re-evaluate our // size for the new monitor. - lpwpos->x = newWindowRect.left(); - lpwpos->y = newWindowRect.top(); - lpwpos->cx = newWindowRect.width(); - lpwpos->cy = newWindowRect.height(); + lpwpos->x = newWindowRect.left; + lpwpos->y = newWindowRect.top; + lpwpos->cx = newWindowRect.width(); + lpwpos->cy = newWindowRect.height(); return 0; } @@ -973,14 +972,14 @@ void IslandWindow::_SetIsBorderless(const bool borderlessEnabled) // Resize the window, with SWP_FRAMECHANGED, to trigger user32 to // recalculate the non/client areas - const til::rectangle windowPos{ GetWindowRect() }; + const til::rect windowPos{ GetWindowRect() }; SetWindowPos(GetHandle(), HWND_TOP, - windowPos.left(), - windowPos.top(), - windowPos.width(), - windowPos.height(), + windowPos.left, + windowPos.top, + windowPos.width(), + windowPos.height(), SWP_SHOWWINDOW | SWP_FRAMECHANGED | SWP_NOACTIVATE); } @@ -1048,8 +1047,8 @@ void IslandWindow::_RestoreFullscreenPosition(const RECT rcWork) // We want to make sure the window is restored within the bounds of the // monitor we're on, but it's totally fine if the invisible borders are // outside the monitor. - const auto halfWidth{ ncSize.width() / 2 }; - const auto halfHeight{ ncSize.height() / 2 }; + const auto halfWidth{ ncSize.width / 2 }; + const auto halfHeight{ ncSize.height / 2 }; rcWorkAdjusted.left -= halfWidth; rcWorkAdjusted.right += halfWidth; @@ -1254,8 +1253,8 @@ void IslandWindow::_summonWindowRoutineBody(Remoting::SummonWindowBehavior args) // mouse, then we should move to that monitor instead of dismissing. if (args.ToMonitor() == Remoting::MonitorBehavior::ToMouse) { - const til::rectangle cursorMonitorRect{ _getMonitorForCursor().rcMonitor }; - const til::rectangle currentMonitorRect{ _getMonitorForWindow(GetHandle()).rcMonitor }; + const til::rect cursorMonitorRect{ _getMonitorForCursor().rcMonitor }; + const til::rect currentMonitorRect{ _getMonitorForWindow(GetHandle()).rcMonitor }; if (cursorMonitorRect != currentMonitorRect) { // We're not on the same monitor as the mouse. Go to that monitor. @@ -1292,8 +1291,8 @@ void IslandWindow::_summonWindowRoutineBody(Remoting::SummonWindowBehavior args) // - void IslandWindow::_doSlideAnimation(const uint32_t dropdownDuration, const bool down) { - til::rectangle fullWindowSize{ GetWindowRect() }; - const double fullHeight = fullWindowSize.height(); + til::rect fullWindowSize{ GetWindowRect() }; + const auto fullHeight = fullWindowSize.height(); const double animationDuration = dropdownDuration; // use floating-point math throughout const auto start = std::chrono::system_clock::now(); @@ -1312,15 +1311,11 @@ void IslandWindow::_doSlideAnimation(const uint32_t dropdownDuration, const bool } // If going down, increase the height over time. If going up, decrease the height. - const double currentHeight = ::base::saturated_cast( + const auto currentHeight = ::base::saturated_cast( down ? ((dt / animationDuration) * fullHeight) : ((1.0 - (dt / animationDuration)) * fullHeight)); - wil::unique_hrgn rgn{ CreateRectRgn(0, - 0, - fullWindowSize.width(), - ::base::saturated_cast(currentHeight)) }; - + wil::unique_hrgn rgn{ CreateRectRgn(0, 0, fullWindowSize.width(), currentHeight) }; SetWindowRgn(_interopWindowHandle, rgn.get(), true); // Go immediately into another frame. This prevents the window from @@ -1562,20 +1557,20 @@ void IslandWindow::_moveToMonitor(const MONITORINFO activeMonitor) // Get the monitor info for the window's current monitor. const auto currentMonitor = _getMonitorForWindow(GetHandle()); - const til::rectangle currentRect{ currentMonitor.rcMonitor }; - const til::rectangle activeRect{ activeMonitor.rcMonitor }; + const til::rect currentRect{ currentMonitor.rcMonitor }; + const til::rect activeRect{ activeMonitor.rcMonitor }; if (currentRect != activeRect) { - const til::rectangle currentWindowRect{ GetWindowRect() }; + const til::rect currentWindowRect{ GetWindowRect() }; const til::point offset{ currentWindowRect.origin() - currentRect.origin() }; const til::point newOrigin{ activeRect.origin() + offset }; SetWindowPos(GetHandle(), 0, - newOrigin.x(), - newOrigin.y(), - currentWindowRect.width(), - currentWindowRect.height(), + newOrigin.x, + newOrigin.y, + currentWindowRect.width(), + currentWindowRect.height(), SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE); // GH#10274, GH#10182: Re-evaluate the size of the quake window when we @@ -1627,10 +1622,10 @@ void IslandWindow::_enterQuakeMode() SetWindowPos(GetHandle(), HWND_TOP, - newRect.left(), - newRect.top(), - newRect.width(), - newRect.height(), + newRect.left, + newRect.top, + newRect.width(), + newRect.height(), SWP_SHOWWINDOW | SWP_FRAMECHANGED | SWP_NOACTIVATE); } @@ -1642,7 +1637,7 @@ void IslandWindow::_enterQuakeMode() // - // Return Value: // - -til::rectangle IslandWindow::_getQuakeModeSize(HMONITOR hmon) +til::rect IslandWindow::_getQuakeModeSize(HMONITOR hmon) { MONITORINFO nearestMonitorInfo; @@ -1667,15 +1662,15 @@ til::rectangle IslandWindow::_getQuakeModeSize(HMONITOR hmon) // smaller on either side to account for that, so they don't hang onto // adjacent monitors. const til::point origin{ - ::base::ClampSub(nearestMonitorInfo.rcWork.left, (ncSize.width() / 2)) + 1, + ::base::ClampSub(nearestMonitorInfo.rcWork.left, (ncSize.width / 2)) + 1, (nearestMonitorInfo.rcWork.top) }; const til::size dimensions{ - availableSpace.width() - 2, - availableSpace.height() / 2 + availableSpace.width - 2, + availableSpace.height / 2 }; - return til::rectangle{ origin, dimensions }; + return til::rect{ origin, dimensions }; } void IslandWindow::HideWindow() diff --git a/src/cascadia/WindowsTerminal/IslandWindow.h b/src/cascadia/WindowsTerminal/IslandWindow.h index ed62092510..53c00121d1 100644 --- a/src/cascadia/WindowsTerminal/IslandWindow.h +++ b/src/cascadia/WindowsTerminal/IslandWindow.h @@ -134,7 +134,7 @@ protected: bool _isQuakeWindow{ false }; void _enterQuakeMode(); - til::rectangle _getQuakeModeSize(HMONITOR hmon); + til::rect _getQuakeModeSize(HMONITOR hmon); void _summonWindowRoutineBody(winrt::Microsoft::Terminal::Remoting::SummonWindowBehavior args); diff --git a/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp b/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp index 50c68fd860..7327656970 100644 --- a/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp +++ b/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp @@ -87,7 +87,7 @@ void NonClientIslandWindow::MakeWindow() noexcept THROW_HR_IF_NULL(E_UNEXPECTED, _dragBarWindow); } -LRESULT NonClientIslandWindow::_dragBarNcHitTest(const til::point& pointer) +LRESULT NonClientIslandWindow::_dragBarNcHitTest(const til::point pointer) { RECT rcParent = GetWindowRect(); // The size of the buttons doesn't change over the life of the application. @@ -97,23 +97,23 @@ LRESULT NonClientIslandWindow::_dragBarNcHitTest(const til::point& pointer) const auto buttonWidthInPixels{ buttonWidthInDips * GetCurrentDpiScale() }; // make sure to account for the width of the window frame! - const til::rectangle nonClientFrame{ GetNonClientFrame(_currentDpi) }; - const auto rightBorder{ rcParent.right - nonClientFrame.right() }; + const til::rect nonClientFrame{ GetNonClientFrame(_currentDpi) }; + const auto rightBorder{ rcParent.right - nonClientFrame.right }; // From the right to the left, // * are we in the close button? // * the maximize button? // * the minimize button? // If we're not, then we're in either the top resize border, or just // generally in the titlebar. - if ((rightBorder - pointer.x()) < (buttonWidthInPixels)) + if ((rightBorder - pointer.x) < (buttonWidthInPixels)) { return HTCLOSE; } - else if ((rightBorder - pointer.x()) < (buttonWidthInPixels * 2)) + else if ((rightBorder - pointer.x) < (buttonWidthInPixels * 2)) { return HTMAXBUTTON; } - else if ((rightBorder - pointer.x()) < (buttonWidthInPixels * 3)) + else if ((rightBorder - pointer.x) < (buttonWidthInPixels * 3)) { return HTMINBUTTON; } @@ -123,7 +123,7 @@ LRESULT NonClientIslandWindow::_dragBarNcHitTest(const til::point& pointer) // border. If we're not on the top border, then we're just generally in // the caption area. const auto resizeBorderHeight = _GetResizeHandleHeight(); - const auto isOnResizeBorder = pointer.y() < rcParent.top + resizeBorderHeight; + const auto isOnResizeBorder = pointer.y < rcParent.top + resizeBorderHeight; return isOnResizeBorder ? HTTOP : HTCAPTION; } @@ -294,15 +294,15 @@ LRESULT NonClientIslandWindow::_InputSinkMessageHandler(UINT const message, // This window is used to capture clicks on the non-client area. void NonClientIslandWindow::_ResizeDragBarWindow() noexcept { - const til::rectangle rect{ _GetDragAreaRect() }; + const til::rect rect{ _GetDragAreaRect() }; if (_IsTitlebarVisible() && rect.size().area() > 0) { SetWindowPos(_dragBarWindow.get(), HWND_TOP, - rect.left(), - rect.top() + _GetTopBorderHeight(), - rect.width(), - rect.height(), + rect.left, + rect.top + _GetTopBorderHeight(), + rect.width(), + rect.height(), SWP_NOACTIVATE | SWP_SHOWWINDOW); SetLayeredWindowAttributes(_dragBarWindow.get(), 0, 255, LWA_ALPHA); } @@ -1087,13 +1087,13 @@ void NonClientIslandWindow::_SetIsBorderless(const bool borderlessEnabled) // Resize the window, with SWP_FRAMECHANGED, to trigger user32 to // recalculate the non/client areas - const til::rectangle windowPos{ GetWindowRect() }; + const til::rect windowPos{ GetWindowRect() }; SetWindowPos(GetHandle(), HWND_TOP, - windowPos.left(), - windowPos.top(), - windowPos.width(), - windowPos.height(), + windowPos.left, + windowPos.top, + windowPos.width(), + windowPos.height(), SWP_SHOWWINDOW | SWP_FRAMECHANGED | SWP_NOACTIVATE); } diff --git a/src/cascadia/WindowsTerminal/NonClientIslandWindow.h b/src/cascadia/WindowsTerminal/NonClientIslandWindow.h index 879da45f60..7f5cfb36b3 100644 --- a/src/cascadia/WindowsTerminal/NonClientIslandWindow.h +++ b/src/cascadia/WindowsTerminal/NonClientIslandWindow.h @@ -72,7 +72,7 @@ private: int _GetResizeHandleHeight() const noexcept; RECT _GetDragAreaRect() const noexcept; int _GetTopBorderHeight() const noexcept; - LRESULT _dragBarNcHitTest(const til::point& pointer); + LRESULT _dragBarNcHitTest(const til::point pointer); [[nodiscard]] LRESULT _OnNcCreate(WPARAM wParam, LPARAM lParam) noexcept override; [[nodiscard]] LRESULT _OnNcCalcSize(const WPARAM wParam, const LPARAM lParam) noexcept; diff --git a/src/cascadia/WindowsTerminal/NotificationIcon.cpp b/src/cascadia/WindowsTerminal/NotificationIcon.cpp index 0878207698..dadc320a14 100644 --- a/src/cascadia/WindowsTerminal/NotificationIcon.cpp +++ b/src/cascadia/WindowsTerminal/NotificationIcon.cpp @@ -109,7 +109,7 @@ void NotificationIcon::CreateNotificationIcon() // - peasants: The map of all peasants that should be available in the context menu. // Return Value: // - -void NotificationIcon::ShowContextMenu(const til::point& coord, +void NotificationIcon::ShowContextMenu(const til::point coord, const IVectorView& peasants) { if (const auto hMenu = _CreateContextMenu(peasants)) @@ -132,7 +132,7 @@ void NotificationIcon::ShowContextMenu(const til::point& coord, uFlags |= TPM_LEFTALIGN; } - TrackPopupMenuEx(hMenu, uFlags, gsl::narrow_cast(coord.x()), gsl::narrow_cast(coord.y()), _owningHwnd, NULL); + TrackPopupMenuEx(hMenu, uFlags, coord.x, coord.y, _owningHwnd, NULL); } } diff --git a/src/cascadia/WindowsTerminal/NotificationIcon.h b/src/cascadia/WindowsTerminal/NotificationIcon.h index 24ee033738..cc71a88b41 100644 --- a/src/cascadia/WindowsTerminal/NotificationIcon.h +++ b/src/cascadia/WindowsTerminal/NotificationIcon.h @@ -23,7 +23,7 @@ public: void ReAddNotificationIcon(); void NotificationIconPressed(); - void ShowContextMenu(const til::point& coord, const winrt::Windows::Foundation::Collections::IVectorView& peasants); + void ShowContextMenu(const til::point coord, const winrt::Windows::Foundation::Collections::IVectorView& peasants); void MenuItemSelected(const HMENU menu, const UINT menuItemIndex); WINRT_CALLBACK(SummonWindowRequested, winrt::delegate); diff --git a/src/host/readData.hpp b/src/host/readData.hpp index 0d46d59d93..dce1c3e1fe 100644 --- a/src/host/readData.hpp +++ b/src/host/readData.hpp @@ -24,6 +24,8 @@ Revision History: #include "../server/IWaitRoutine.h" #include "../server/WaitTerminationReason.h" +class InputBuffer; + class ReadData : public IWaitRoutine { public: diff --git a/src/host/ut_host/TextBufferTests.cpp b/src/host/ut_host/TextBufferTests.cpp index d58343d3d6..529f2c38f4 100644 --- a/src/host/ut_host/TextBufferTests.cpp +++ b/src/host/ut_host/TextBufferTests.cpp @@ -2196,7 +2196,7 @@ void TextBufferTests::MoveByWord() Log::Comment(NoThrowString().Format(L"COORD (%hd, %hd)", test.startPos.X, test.startPos.Y)); auto pos{ test.startPos }; const auto result = movingForwards ? - _buffer->MoveToNextWord(pos, delimiters, lastCharPos) : + _buffer->MoveToNextWord(pos, delimiters, til::point{ lastCharPos }) : _buffer->MoveToPreviousWord(pos, delimiters); const auto expected = movingForwards ? test.expected.moveForwards : test.expected.moveBackwards; VERIFY_ARE_EQUAL(expected, pos); @@ -2250,7 +2250,7 @@ void TextBufferTests::GetGlyphBoundaries() { Log::Comment(test.name.c_str()); auto target = test.start; - _buffer->Write(iter, target); + _buffer->Write(iter, target.to_win32_coord()); auto start = _buffer->GetGlyphStart(target); auto end = _buffer->GetGlyphEnd(target, true); diff --git a/src/host/ut_host/VtRendererTests.cpp b/src/host/ut_host/VtRendererTests.cpp index 3d9a5b8aa1..85612eebc0 100644 --- a/src/host/ut_host/VtRendererTests.cpp +++ b/src/host/ut_host/VtRendererTests.cpp @@ -234,7 +234,7 @@ void VtRendererTest::Xterm256TestInvalidate() VERIFY_SUCCEEDED(engine->Invalidate(&invalid)); TestPaint(*engine, [&]() { VERIFY_IS_TRUE(engine->_invalidMap.one()); - VERIFY_ARE_EQUAL(til::rectangle{ Viewport::FromExclusive(invalid).ToInclusive() }, *(engine->_invalidMap.begin())); + VERIFY_ARE_EQUAL(til::rect{ Viewport::FromExclusive(invalid).ToInclusive() }, *(engine->_invalidMap.begin())); }); Log::Comment(NoThrowString().Format( @@ -249,7 +249,7 @@ void VtRendererTest::Xterm256TestInvalidate() const auto runs = engine->_invalidMap.runs(); VERIFY_ARE_EQUAL(1u, runs.size()); - VERIFY_ARE_EQUAL(til::rectangle{ Viewport::FromExclusive(invalid).ToInclusive() }, runs.front()); + VERIFY_ARE_EQUAL(til::rect{ Viewport::FromExclusive(invalid).ToInclusive() }, runs.front()); qExpectedInput.push_back("\x1b[H"); // Go Home qExpectedInput.push_back("\x1b[L"); // insert a line @@ -275,7 +275,7 @@ void VtRendererTest::Xterm256TestInvalidate() } // verify the rect matches the invalid one. - VERIFY_ARE_EQUAL(til::rectangle{ Viewport::FromExclusive(invalid).ToInclusive() }, invalidRect); + VERIFY_ARE_EQUAL(til::rect{ Viewport::FromExclusive(invalid).ToInclusive() }, invalidRect); // We would expect a CUP here, but the cursor is already at the home position qExpectedInput.push_back("\x1b[3L"); // insert 3 lines VERIFY_SUCCEEDED(engine->ScrollFrame()); @@ -291,7 +291,7 @@ void VtRendererTest::Xterm256TestInvalidate() const auto runs = engine->_invalidMap.runs(); VERIFY_ARE_EQUAL(1u, runs.size()); - VERIFY_ARE_EQUAL(til::rectangle{ Viewport::FromExclusive(invalid).ToInclusive() }, runs.front()); + VERIFY_ARE_EQUAL(til::rect{ Viewport::FromExclusive(invalid).ToInclusive() }, runs.front()); qExpectedInput.push_back("\x1b[32;1H"); // Bottom of buffer qExpectedInput.push_back("\n"); // Scroll down once @@ -316,7 +316,7 @@ void VtRendererTest::Xterm256TestInvalidate() } // verify the rect matches the invalid one. - VERIFY_ARE_EQUAL(til::rectangle{ Viewport::FromExclusive(invalid).ToInclusive() }, invalidRect); + VERIFY_ARE_EQUAL(til::rect{ Viewport::FromExclusive(invalid).ToInclusive() }, invalidRect); // We would expect a CUP here, but we're already at the bottom from the last call. qExpectedInput.push_back("\n\n\n"); // Scroll down three times @@ -346,7 +346,7 @@ void VtRendererTest::Xterm256TestInvalidate() } // verify the rect matches the invalid one. - VERIFY_ARE_EQUAL(til::rectangle{ Viewport::FromExclusive(invalid).ToInclusive() }, invalidRect); + VERIFY_ARE_EQUAL(til::rect{ Viewport::FromExclusive(invalid).ToInclusive() }, invalidRect); qExpectedInput.push_back("\x1b[H"); // Go to home qExpectedInput.push_back("\x1b[3L"); // insert 3 lines @@ -386,7 +386,7 @@ void VtRendererTest::Xterm256TestInvalidate() // 0000 // 0000 // 1111 - const til::rectangle expected{ til::point{ view.Left(), view.BottomInclusive() }, til::size{ view.Width(), 1 } }; + const til::rect expected{ til::point{ view.Left(), view.BottomInclusive() }, til::size{ view.Width(), 1 } }; VERIFY_ARE_EQUAL(expected, invalidRect); VERIFY_SUCCEEDED(engine->ScrollFrame()); @@ -912,7 +912,7 @@ void VtRendererTest::XtermTestInvalidate() VERIFY_SUCCEEDED(engine->Invalidate(&invalid)); TestPaint(*engine, [&]() { VERIFY_IS_TRUE(engine->_invalidMap.one()); - VERIFY_ARE_EQUAL(til::rectangle{ Viewport::FromExclusive(invalid).ToInclusive() }, *(engine->_invalidMap.begin())); + VERIFY_ARE_EQUAL(til::rect{ Viewport::FromExclusive(invalid).ToInclusive() }, *(engine->_invalidMap.begin())); }); Log::Comment(NoThrowString().Format( @@ -927,7 +927,7 @@ void VtRendererTest::XtermTestInvalidate() const auto runs = engine->_invalidMap.runs(); VERIFY_ARE_EQUAL(1u, runs.size()); - VERIFY_ARE_EQUAL(til::rectangle{ Viewport::FromExclusive(invalid).ToInclusive() }, runs.front()); + VERIFY_ARE_EQUAL(til::rect{ Viewport::FromExclusive(invalid).ToInclusive() }, runs.front()); qExpectedInput.push_back("\x1b[H"); // Go Home qExpectedInput.push_back("\x1b[L"); // insert a line @@ -952,7 +952,7 @@ void VtRendererTest::XtermTestInvalidate() } // verify the rect matches the invalid one. - VERIFY_ARE_EQUAL(til::rectangle{ Viewport::FromExclusive(invalid).ToInclusive() }, invalidRect); + VERIFY_ARE_EQUAL(til::rect{ Viewport::FromExclusive(invalid).ToInclusive() }, invalidRect); // We would expect a CUP here, but the cursor is already at the home position qExpectedInput.push_back("\x1b[3L"); // insert 3 lines VERIFY_SUCCEEDED(engine->ScrollFrame()); @@ -968,7 +968,7 @@ void VtRendererTest::XtermTestInvalidate() const auto runs = engine->_invalidMap.runs(); VERIFY_ARE_EQUAL(1u, runs.size()); - VERIFY_ARE_EQUAL(til::rectangle{ Viewport::FromExclusive(invalid).ToInclusive() }, runs.front()); + VERIFY_ARE_EQUAL(til::rect{ Viewport::FromExclusive(invalid).ToInclusive() }, runs.front()); qExpectedInput.push_back("\x1b[32;1H"); // Bottom of buffer qExpectedInput.push_back("\n"); // Scroll down once @@ -993,7 +993,7 @@ void VtRendererTest::XtermTestInvalidate() } // verify the rect matches the invalid one. - VERIFY_ARE_EQUAL(til::rectangle{ Viewport::FromExclusive(invalid).ToInclusive() }, invalidRect); + VERIFY_ARE_EQUAL(til::rect{ Viewport::FromExclusive(invalid).ToInclusive() }, invalidRect); // We would expect a CUP here, but we're already at the bottom from the last call. qExpectedInput.push_back("\n\n\n"); // Scroll down three times @@ -1023,7 +1023,7 @@ void VtRendererTest::XtermTestInvalidate() } // verify the rect matches the invalid one. - VERIFY_ARE_EQUAL(til::rectangle{ Viewport::FromExclusive(invalid).ToInclusive() }, invalidRect); + VERIFY_ARE_EQUAL(til::rect{ Viewport::FromExclusive(invalid).ToInclusive() }, invalidRect); qExpectedInput.push_back("\x1b[H"); // Go to home qExpectedInput.push_back("\x1b[3L"); // insert 3 lines @@ -1063,7 +1063,7 @@ void VtRendererTest::XtermTestInvalidate() // 0000 // 0000 // 1111 - const til::rectangle expected{ til::point{ view.Left(), view.BottomInclusive() }, til::size{ view.Width(), 1 } }; + const til::rect expected{ til::point{ view.Left(), view.BottomInclusive() }, til::size{ view.Width(), 1 } }; VERIFY_ARE_EQUAL(expected, invalidRect); VERIFY_SUCCEEDED(engine->ScrollFrame()); diff --git a/src/inc/consoletaeftemplates.hpp b/src/inc/consoletaeftemplates.hpp index a3b9b39aeb..04986dc63f 100644 --- a/src/inc/consoletaeftemplates.hpp +++ b/src/inc/consoletaeftemplates.hpp @@ -242,66 +242,14 @@ namespace WEX::TestExecution public: static bool AreEqual(const CONSOLE_SCREEN_BUFFER_INFOEX& expected, const CONSOLE_SCREEN_BUFFER_INFOEX& actual) { - return expected.bFullscreenSupported == actual.bFullscreenSupported && - expected.wAttributes == actual.wAttributes && - expected.wPopupAttributes == actual.wPopupAttributes && - VerifyCompareTraits::AreEqual(expected.dwCursorPosition, actual.dwCursorPosition) && - VerifyCompareTraits::AreEqual(expected.dwSize, actual.dwSize) && - VerifyCompareTraits::AreEqual(expected.dwMaximumWindowSize, actual.dwMaximumWindowSize) && - VerifyCompareTraits::AreEqual(expected.srWindow, actual.srWindow) && - expected.ColorTable[0] == actual.ColorTable[0] && - expected.ColorTable[1] == actual.ColorTable[1] && - expected.ColorTable[2] == actual.ColorTable[2] && - expected.ColorTable[3] == actual.ColorTable[3] && - expected.ColorTable[4] == actual.ColorTable[4] && - expected.ColorTable[5] == actual.ColorTable[5] && - expected.ColorTable[6] == actual.ColorTable[6] && - expected.ColorTable[7] == actual.ColorTable[7] && - expected.ColorTable[8] == actual.ColorTable[8] && - expected.ColorTable[9] == actual.ColorTable[9] && - expected.ColorTable[10] == actual.ColorTable[10] && - expected.ColorTable[11] == actual.ColorTable[11] && - expected.ColorTable[12] == actual.ColorTable[12] && - expected.ColorTable[13] == actual.ColorTable[13] && - expected.ColorTable[14] == actual.ColorTable[14] && - expected.ColorTable[15] == actual.ColorTable[15]; + static_assert(std::has_unique_object_representations_v); + return memcmp(&expected, &actual, sizeof(CONSOLE_SCREEN_BUFFER_INFOEX)) == 0; } static bool AreSame(const CONSOLE_SCREEN_BUFFER_INFOEX& expected, const CONSOLE_SCREEN_BUFFER_INFOEX& actual) { return &expected == &actual; } - - static bool IsLessThan(const CONSOLE_SCREEN_BUFFER_INFOEX& expectedLess, const CONSOLE_SCREEN_BUFFER_INFOEX& expectedGreater) = delete; - - static bool IsGreaterThan(const CONSOLE_SCREEN_BUFFER_INFOEX& expectedGreater, const CONSOLE_SCREEN_BUFFER_INFOEX& expectedLess) = delete; - - static bool IsNull(const CONSOLE_SCREEN_BUFFER_INFOEX& object) - { - return object.bFullscreenSupported == 0 && - object.wAttributes == 0 && - object.wPopupAttributes == 0 && - VerifyCompareTraits::IsNull(object.dwCursorPosition) && - VerifyCompareTraits::IsNull(object.dwSize) && - VerifyCompareTraits::IsNull(object.dwMaximumWindowSize) && - VerifyCompareTraits::IsNull(object.srWindow) && - object.ColorTable[0] == 0x0 && - object.ColorTable[1] == 0x0 && - object.ColorTable[2] == 0x0 && - object.ColorTable[3] == 0x0 && - object.ColorTable[4] == 0x0 && - object.ColorTable[5] == 0x0 && - object.ColorTable[6] == 0x0 && - object.ColorTable[7] == 0x0 && - object.ColorTable[8] == 0x0 && - object.ColorTable[9] == 0x0 && - object.ColorTable[10] == 0x0 && - object.ColorTable[11] == 0x0 && - object.ColorTable[12] == 0x0 && - object.ColorTable[13] == 0x0 && - object.ColorTable[14] == 0x0 && - object.ColorTable[15] == 0x0; - } }; template<> diff --git a/src/inc/til.h b/src/inc/til.h index 59e07cb8e4..ae46c8778c 100644 --- a/src/inc/til.h +++ b/src/inc/til.h @@ -6,22 +6,15 @@ #define _TIL_INLINEPREFIX __declspec(noinline) inline #include "til/at.h" -#include "til/color.h" -#include "til/math.h" -#include "til/some.h" -#include "til/size.h" -#include "til/point.h" -#include "til/operators.h" -#include "til/rectangle.h" -#include "til/rle.h" #include "til/bitmap.h" -#include "til/u8u16convert.h" -#include "til/spsc.h" #include "til/coalesce.h" -#include "til/replace.h" -#include "til/string.h" -#include "til/pmr.h" +#include "til/color.h" #include "til/enumset.h" +#include "til/pmr.h" +#include "til/replace.h" +#include "til/rle.h" +#include "til/string.h" +#include "til/u8u16convert.h" // Use keywords on TraceLogging providers to specify the category // of event that we are emitting for filtering purposes. diff --git a/src/inc/til/bitmap.h b/src/inc/til/bitmap.h index f4bef68b62..f3527914bf 100644 --- a/src/inc/til/bitmap.h +++ b/src/inc/til/bitmap.h @@ -3,6 +3,8 @@ #pragma once +#include "rect.h" + #ifdef UNIT_TESTING class BitmapTests; #endif @@ -15,13 +17,13 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned" class _bitmap_const_iterator { public: - using iterator_category = typename std::input_iterator_tag; - using value_type = typename const til::rectangle; - using difference_type = typename ptrdiff_t; - using pointer = typename const til::rectangle*; - using reference = typename const til::rectangle&; + using iterator_category = std::input_iterator_tag; + using value_type = const til::rect; + using difference_type = ptrdiff_t; + using pointer = const til::rect*; + using reference = const til::rect&; - _bitmap_const_iterator(const dynamic_bitset& values, til::rectangle rc, ptrdiff_t pos) : + _bitmap_const_iterator(const dynamic_bitset& values, til::rect rc, ptrdiff_t pos) : _values(values), _rc(rc), _pos(pos), @@ -76,11 +78,11 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned" private: const dynamic_bitset& _values; - const til::rectangle _rc; - ptrdiff_t _pos; - ptrdiff_t _nextPos; - const ptrdiff_t _end; - til::rectangle _run; + const til::rect _rc; + size_t _pos; + size_t _nextPos; + const size_t _end; + til::rect _run; // Update _run to contain the next rectangle of consecutively set bits within this bitmap. // _calculateArea may be called repeatedly to yield all those rectangles. @@ -92,23 +94,22 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned" // dynamic_bitset allows you to quickly find the next set bit using find_next(prev), // where "prev" is the position _past_ which should be searched (i.e. excluding position "prev"). // If _pos is still 0, we thus need to use the counterpart find_first(). - const auto nextPos = _pos == 0 ? _values.find_first() : _values.find_next(_pos - 1); - // If no next set bit can be found, npos is returned, which is SIZE_T_MAX. - // saturated_cast can ensure that this will be converted to PTRDIFF_T_MAX (which is greater than _end). - _nextPos = base::saturated_cast(nextPos); + _nextPos = _pos == 0 ? _values.find_first() : _values.find_next(_pos - 1); // If we haven't reached the end yet... if (_nextPos < _end) { // pos is now at the first on bit. - const auto runStart = _rc.point_at(_nextPos); + // If no next set bit can be found, npos is returned, which is SIZE_T_MAX. + // saturated_cast can ensure that this will be converted to CoordType's max (which is greater than _end). + const auto runStart = _rc.point_at(base::saturated_cast(_nextPos)); // We'll only count up until the end of this row. // a run can be a max of one row tall. - const ptrdiff_t rowEndIndex = _rc.index_of(til::point(_rc.right() - 1, runStart.y())) + 1; + const size_t rowEndIndex = _rc.index_of(til::point(_rc.right - 1, runStart.y)) + 1; // Find the length for the rectangle. - ptrdiff_t runLength = 0; + size_t runLength = 0; // We have at least 1 so start with a do/while. do @@ -119,7 +120,7 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned" // Keep going until we reach end of row, end of the buffer, or the next bit is off. // Assemble and store that run. - _run = til::rectangle{ runStart, til::size{ runLength, static_cast(1) } }; + _run = til::rect{ runStart, til::size{ base::saturated_cast(runLength), 1 } }; } else { @@ -127,7 +128,7 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned" // ---> Mark the end of the iterator by updating the state with _end. _pos = _end; _nextPos = _end; - _run = til::rectangle{}; + _run = til::rect{}; } } }; @@ -140,7 +141,7 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned" using const_iterator = details::_bitmap_const_iterator; private: - using run_allocator_type = typename std::allocator_traits::template rebind_alloc; + using run_allocator_type = typename std::allocator_traits::template rebind_alloc; public: explicit bitmap(const allocator_type& allocator) noexcept : @@ -255,15 +256,15 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned" const_iterator begin() const { - return const_iterator(_bits, _sz, 0); + return const_iterator(_bits, til::rect{ _sz }, 0); } const_iterator end() const { - return const_iterator(_bits, _sz, _sz.area()); + return const_iterator(_bits, til::rect{ _sz }, _sz.area()); } - const gsl::span runs() const + const gsl::span runs() const { // If we don't have cached runs, rebuild. if (!_runs.has_value()) @@ -278,10 +279,10 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned" // optional fill the uncovered area with bits. void translate(const til::point delta, bool fill = false) { - if (delta.x() == 0) + if (delta.x == 0) { // fast path by using bit shifting - translate_y(delta.y(), fill); + translate_y(delta.y, fill); return; } @@ -356,14 +357,14 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned" _bits.set(_rc.index_of(pt)); } - void set(const til::rectangle rc) + void set(const til::rect& rc) { THROW_HR_IF(E_INVALIDARG, !_rc.contains(rc)); _runs.reset(); // reset cached runs on any non-const method - for (auto row = rc.top(); row < rc.bottom(); ++row) + for (auto row = rc.top; row < rc.bottom; ++row) { - _bits.set(_rc.index_of(til::point{ rc.left(), row }), rc.width(), true); + _bits.set(_rc.index_of(til::point{ rc.left, row }), rc.width(), true); } } @@ -480,7 +481,7 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned" return; } - const auto bitShift = delta_y * _sz.width(); + const auto bitShift = delta_y * _sz.width; #pragma warning(push) // we can't depend on GSL here, so we use static_cast for explicit narrowing @@ -530,10 +531,10 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned" allocator_type _alloc; til::size _sz; - til::rectangle _rc; + til::rect _rc; dynamic_bitset _bits; - mutable std::optional> _runs; + mutable std::optional> _runs; #ifdef UNIT_TESTING friend class ::BitmapTests; diff --git a/src/inc/til/math.h b/src/inc/til/math.h index 92afa100c0..59f80c2cc6 100644 --- a/src/inc/til/math.h +++ b/src/inc/til/math.h @@ -12,19 +12,30 @@ namespace til { namespace details { + // Just like gsl::narrow, but also checks for NAN. + template + constexpr O narrow_float(T val) + { + const auto o = gsl::narrow_cast(val); + if (std::isnan(val) || static_cast(o) != val) + { + throw gsl::narrowing_error{}; + } + return o; + } + struct ceiling_t { template - static O cast(T val) + static constexpr O cast(T val) { if constexpr (std::is_floating_point_v) { - THROW_HR_IF(E_ABORT, ::std::isnan(val)); - return ::base::saturated_cast(::std::ceil(val)); + return narrow_float(std::ceil(val)); } else { - return ::base::saturated_cast(val); + return gsl::narrow(val); } } }; @@ -32,16 +43,15 @@ namespace til struct flooring_t { template - static O cast(T val) + static constexpr O cast(T val) { if constexpr (std::is_floating_point_v) { - THROW_HR_IF(E_ABORT, ::std::isnan(val)); - return ::base::saturated_cast(::std::floor(val)); + return narrow_float(std::floor(val)); } else { - return ::base::saturated_cast(val); + return gsl::narrow(val); } } }; @@ -49,37 +59,22 @@ namespace til struct rounding_t { template - static O cast(T val) + static constexpr O cast(T val) { if constexpr (std::is_floating_point_v) { - THROW_HR_IF(E_ABORT, ::std::isnan(val)); - return ::base::saturated_cast(::std::round(val)); + return narrow_float(std::round(val)); } else { - return ::base::saturated_cast(val); + return gsl::narrow(val); } } }; - - struct truncating_t - { - template - static O cast(T val) - { - if constexpr (std::is_floating_point_v) - { - THROW_HR_IF(E_ABORT, ::std::isnan(val)); - } - return ::base::saturated_cast(val); - } - }; } static constexpr details::ceiling_t ceiling; // positives become more positive, negatives become less negative static constexpr details::flooring_t flooring; // positives become less positive, negatives become more negative static constexpr details::rounding_t rounding; // it's rounding, from math class - static constexpr details::truncating_t truncating; // drop the decimal point, regardless of how close it is to the next value } } diff --git a/src/inc/til/operators.h b/src/inc/til/operators.h index 7e18e33498..3ee186ad6b 100644 --- a/src/inc/til/operators.h +++ b/src/inc/til/operators.h @@ -9,47 +9,47 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned" #pragma region POINT VS SIZE // This is a convenience and will take X vs WIDTH and Y vs HEIGHT. - _TIL_INLINEPREFIX point operator+(const point& lhs, const size& rhs) + constexpr point operator+(const point lhs, const size rhs) { - return lhs + til::point{ rhs.width(), rhs.height() }; + return lhs + til::point{ rhs.width, rhs.height }; } - _TIL_INLINEPREFIX point operator-(const point& lhs, const size& rhs) + constexpr point operator-(const point lhs, const size rhs) { - return lhs - til::point{ rhs.width(), rhs.height() }; + return lhs - til::point{ rhs.width, rhs.height }; } - _TIL_INLINEPREFIX point operator*(const point& lhs, const size& rhs) + constexpr point operator*(const point lhs, const size rhs) { - return lhs * til::point{ rhs.width(), rhs.height() }; + return lhs * til::point{ rhs.width, rhs.height }; } - _TIL_INLINEPREFIX point operator/(const point& lhs, const size& rhs) + constexpr point operator/(const point lhs, const size rhs) { - return lhs / til::point{ rhs.width(), rhs.height() }; + return lhs / til::point{ rhs.width, rhs.height }; } #pragma endregion #pragma region SIZE VS POINT // This is a convenience and will take WIDTH vs X and HEIGHT vs Y. - _TIL_INLINEPREFIX size operator+(const size& lhs, const point& rhs) + constexpr size operator+(const size lhs, const point rhs) { - return lhs + til::size(rhs.x(), rhs.y()); + return lhs + til::size(rhs.x, rhs.y); } - _TIL_INLINEPREFIX size operator-(const size& lhs, const point& rhs) + constexpr size operator-(const size lhs, const point rhs) { - return lhs - til::size(rhs.x(), rhs.y()); + return lhs - til::size(rhs.x, rhs.y); } - _TIL_INLINEPREFIX size operator*(const size& lhs, const point& rhs) + constexpr size operator*(const size lhs, const point rhs) { - return lhs * til::size(rhs.x(), rhs.y()); + return lhs * til::size(rhs.x, rhs.y); } - _TIL_INLINEPREFIX size operator/(const size& lhs, const point& rhs) + constexpr size operator/(const size lhs, const point rhs) { - return lhs / til::size(rhs.x(), rhs.y()); + return lhs / til::size(rhs.x, rhs.y); } #pragma endregion } diff --git a/src/inc/til/point.h b/src/inc/til/point.h index 5d47588255..4741a67c8d 100644 --- a/src/inc/til/point.h +++ b/src/inc/til/point.h @@ -3,368 +3,231 @@ #pragma once -#ifdef UNIT_TESTING -class PointTests; -#endif - namespace til // Terminal Implementation Library. Also: "Today I Learned" { - class point + using CoordType = int32_t; + + namespace details { - public: - constexpr point() noexcept : - point(0, 0) + template + constexpr U extract(const ::base::CheckedNumeric& num) { + U val; + if (!num.AssignIfValid(&val)) + { + throw gsl::narrowing_error{}; + } + return val; } + } - // On 64-bit processors, int and ptrdiff_t are different fundamental types. - // On 32-bit processors, they're the same which makes this a double-definition - // with the `ptrdiff_t` one below. -#if defined(_M_AMD64) || defined(_M_ARM64) - constexpr point(int x, int y) noexcept : - point(static_cast(x), static_cast(y)) - { - } - constexpr point(ptrdiff_t width, int height) noexcept : - point(width, static_cast(height)) - { - } - constexpr point(int width, ptrdiff_t height) noexcept : - point(static_cast(width), height) - { - } -#endif + struct point + { + CoordType x = 0; + CoordType y = 0; - point(size_t x, size_t y) - { - THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(x).AssignIfValid(&_x)); - THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(y).AssignIfValid(&_y)); - } - point(long x, long y) - { - THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(x).AssignIfValid(&_x)); - THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(y).AssignIfValid(&_y)); - } + constexpr point() noexcept = default; - constexpr point(ptrdiff_t x, ptrdiff_t y) noexcept : - _x(x), - _y(y) - { - } - - // This template will convert to size from anything that has an X and a Y field that appear convertible to an integer value - template - constexpr point(const TOther& other, std::enable_if_t().X)> && std::is_integral_v().Y)>, int> /*sentinel*/ = 0) : - point(static_cast(other.X), static_cast(other.Y)) - { - } - - // This template will convert to size from anything that has a x and a y field that appear convertible to an integer value - template - constexpr point(const TOther& other, std::enable_if_t().x)> && std::is_integral_v().y)>, int> /*sentinel*/ = 0) : - point(static_cast(other.x), static_cast(other.y)) + constexpr point(CoordType x, CoordType y) noexcept : + x{ x }, y{ y } { } // This template will convert to point from floating-point args; // a math type is required. If you _don't_ provide one, you're going to // get a compile-time error about "cannot convert from initializer-list to til::point" - template - constexpr point(TilMath, const TOther& x, const TOther& y, std::enable_if_t, int> /*sentinel*/ = 0) : - point(TilMath::template cast(x), TilMath::template cast(y)) + template + constexpr point(TilMath, const T x, const T y) : + x{ TilMath::template cast(x) }, y{ TilMath::template cast(y) } { } - // This template will convert to size from anything that has a X and a Y field that are floating-point; - // a math type is required. If you _don't_ provide one, you're going to - // get a compile-time error about "cannot convert from initializer-list to til::point" - template - constexpr point(TilMath, const TOther& other, std::enable_if_t().X)> && std::is_floating_point_v().Y)>, int> /*sentinel*/ = 0) : - point(TilMath::template cast(other.X), TilMath::template cast(other.Y)) + constexpr bool operator==(const point rhs) const noexcept { + // `__builtin_memcmp` isn't an official standard, but it's the + // only way at the time of writing to get a constexpr `memcmp`. + return __builtin_memcmp(this, &rhs, sizeof(rhs)) == 0; } - // This template will convert to size from anything that has a x and a y field that are floating-point; - // a math type is required. If you _don't_ provide one, you're going to - // get a compile-time error about "cannot convert from initializer-list to til::point" - template - constexpr point(TilMath, const TOther& other, std::enable_if_t().x)> && std::is_floating_point_v().y)>, int> /*sentinel*/ = 0) : - point(TilMath::template cast(other.x), TilMath::template cast(other.y)) + constexpr bool operator!=(const point rhs) const noexcept { + return __builtin_memcmp(this, &rhs, sizeof(rhs)) != 0; } - constexpr bool operator==(const point& other) const noexcept + constexpr bool operator<(const point other) const noexcept { - return _x == other._x && - _y == other._y; + return y < other.y || (y == other.y && x < other.x); } - constexpr bool operator!=(const point& other) const noexcept + constexpr bool operator<=(const point other) const noexcept { - return !(*this == other); + return y < other.y || (y == other.y && x <= other.x); } - constexpr bool operator<(const point& other) const noexcept + constexpr bool operator>(const point other) const noexcept { - if (_y < other._y) - { - return true; - } - else if (_y > other._y) - { - return false; - } - else - { - return _x < other._x; - } + return y > other.y || (y == other.y && x > other.x); } - constexpr bool operator>(const point& other) const noexcept + constexpr bool operator>=(const point other) const noexcept { - if (_y > other._y) - { - return true; - } - else if (_y < other._y) - { - return false; - } - else - { - return _x > other._x; - } + return y > other.y || (y == other.y && x >= other.x); } - constexpr bool operator<=(const point& other) const noexcept + constexpr point operator+(const point other) const { - if (_y < other._y) - { - return true; - } - else if (_y > other._y) - { - return false; - } - else - { - return _x <= other._x; - } + return point{ + details::extract(::base::CheckAdd(x, other.x)), + details::extract(::base::CheckAdd(y, other.y)), + }; } - constexpr bool operator>=(const point& other) const noexcept - { - if (_y > other._y) - { - return true; - } - else if (_y < other._y) - { - return false; - } - else - { - return _x >= other._x; - } - } - - point operator+(const point& other) const - { - ptrdiff_t x; - THROW_HR_IF(E_ABORT, !base::CheckAdd(_x, other._x).AssignIfValid(&x)); - - ptrdiff_t y; - THROW_HR_IF(E_ABORT, !base::CheckAdd(_y, other._y).AssignIfValid(&y)); - - return point{ x, y }; - } - - point& operator+=(const point& other) + constexpr point& operator+=(const point other) { *this = *this + other; return *this; } - point operator-(const point& other) const + constexpr point operator-(const point other) const { - ptrdiff_t x; - THROW_HR_IF(E_ABORT, !base::CheckSub(_x, other._x).AssignIfValid(&x)); - - ptrdiff_t y; - THROW_HR_IF(E_ABORT, !base::CheckSub(_y, other._y).AssignIfValid(&y)); - - return point{ x, y }; + return point{ + details::extract(::base::CheckSub(x, other.x)), + details::extract(::base::CheckSub(y, other.y)), + }; } - point& operator-=(const point& other) + constexpr point& operator-=(const point other) { *this = *this - other; return *this; } - point operator*(const point& other) const + constexpr point operator*(const point other) const { - ptrdiff_t x; - THROW_HR_IF(E_ABORT, !base::CheckMul(_x, other._x).AssignIfValid(&x)); - - ptrdiff_t y; - THROW_HR_IF(E_ABORT, !base::CheckMul(_y, other._y).AssignIfValid(&y)); - - return point{ x, y }; + return point{ + details::extract(::base::CheckMul(x, other.x)), + details::extract(::base::CheckMul(y, other.y)), + }; } - point& operator*=(const point& other) + constexpr point& operator*=(const point other) { *this = *this * other; return *this; } - template - point scale(TilMath, const float scale) const + constexpr point operator/(const point other) const { - struct - { - float x, y; - } pt; - THROW_HR_IF(E_ABORT, !base::CheckMul(scale, _x).AssignIfValid(&pt.x)); - THROW_HR_IF(E_ABORT, !base::CheckMul(scale, _y).AssignIfValid(&pt.y)); - - return til::point(TilMath(), pt); + return point{ + details::extract(::base::CheckDiv(x, other.x)), + details::extract(::base::CheckDiv(y, other.y)), + }; } - point operator/(const point& other) const - { - ptrdiff_t x; - THROW_HR_IF(E_ABORT, !base::CheckDiv(_x, other._x).AssignIfValid(&x)); - - ptrdiff_t y; - THROW_HR_IF(E_ABORT, !base::CheckDiv(_y, other._y).AssignIfValid(&y)); - - return point{ x, y }; - } - - point& operator/=(const point& other) + constexpr point& operator/=(const point other) { *this = *this / other; return *this; } - template - point operator*(const T& scale) const + template>> + constexpr point operator*(const T scale) const { - static_assert(std::is_arithmetic::value, "Type must be arithmetic"); - ptrdiff_t x; - THROW_HR_IF(E_ABORT, !base::CheckMul(_x, scale).AssignIfValid(&x)); + return point{ + details::extract(::base::CheckMul(x, scale)), + details::extract(::base::CheckMul(y, scale)), + }; + } - ptrdiff_t y; - THROW_HR_IF(E_ABORT, !base::CheckMul(_y, scale).AssignIfValid(&y)); - - return point{ x, y }; + template>> + constexpr point operator/(const T scale) const + { + return point{ + details::extract(::base::CheckDiv(x, scale)), + details::extract(::base::CheckDiv(y, scale)), + }; } template - point operator/(const T& scale) const + constexpr T narrow_x() const { - static_assert(std::is_arithmetic::value, "Type must be arithmetic"); - ptrdiff_t x; - THROW_HR_IF(E_ABORT, !base::CheckDiv(_x, scale).AssignIfValid(&x)); - - ptrdiff_t y; - THROW_HR_IF(E_ABORT, !base::CheckDiv(_y, scale).AssignIfValid(&y)); - - return point{ x, y }; - } - - constexpr ptrdiff_t x() const noexcept - { - return _x; + return gsl::narrow(x); } template - T x() const + constexpr T narrow_y() const { - T ret; - THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(x()).AssignIfValid(&ret)); - return ret; - } - - constexpr ptrdiff_t y() const noexcept - { - return _y; - } - - template - T y() const - { - T ret; - THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(y()).AssignIfValid(&ret)); - return ret; + return gsl::narrow(y); } #ifdef _WINCONTYPES_ - operator COORD() const + explicit constexpr point(const COORD other) noexcept : + x{ other.X }, y{ other.Y } { - COORD ret; - THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(_x).AssignIfValid(&ret.X)); - THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(_y).AssignIfValid(&ret.Y)); - return ret; + } + + constexpr COORD to_win32_coord() const + { + return { narrow_x(), narrow_y() }; } #endif #ifdef _WINDEF_ - operator POINT() const + explicit constexpr point(const POINT other) noexcept : + x{ other.x }, y{ other.y } { - POINT ret; - THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(_x).AssignIfValid(&ret.x)); - THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(_y).AssignIfValid(&ret.y)); - return ret; + } + + constexpr POINT to_win32_point() const noexcept + { + return { x, y }; } #endif #ifdef DCOMMON_H_INCLUDED - constexpr operator D2D1_POINT_2F() const noexcept + template + constexpr point(TilMath, const D2D1_POINT_2F other) : + x{ TilMath::template cast(other.x) }, + y{ TilMath::template cast(other.y) } { - return D2D1_POINT_2F{ gsl::narrow_cast(_x), gsl::narrow_cast(_y) }; + } + + constexpr D2D1_POINT_2F to_d2d_point() const noexcept + { + return { static_cast(x), static_cast(y) }; } #endif #ifdef WINRT_Windows_Foundation_H - operator winrt::Windows::Foundation::Point() const + template + constexpr point(TilMath, const winrt::Windows::Foundation::Point other) : + x{ TilMath::template cast(other.X) }, + y{ TilMath::template cast(other.Y) } { - winrt::Windows::Foundation::Point ret; - THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(_x).AssignIfValid(&ret.X)); - THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(_y).AssignIfValid(&ret.Y)); - return ret; + } + + winrt::Windows::Foundation::Point to_winrt_point() const noexcept + { + return { static_cast(x), static_cast(y) }; } #endif #ifdef WINRT_Microsoft_Terminal_Core_H - constexpr point(const winrt::Microsoft::Terminal::Core::Point& corePoint) : - point(corePoint.X, corePoint.Y) + explicit constexpr point(const winrt::Microsoft::Terminal::Core::Point other) : + x{ other.X }, y{ other.Y } { } - operator winrt::Microsoft::Terminal::Core::Point() const + winrt::Microsoft::Terminal::Core::Point to_core_point() const noexcept { - winrt::Microsoft::Terminal::Core::Point ret; - ret.X = x(); - ret.Y = y(); - return ret; + return { x, y }; } #endif std::wstring to_string() const { - return wil::str_printf(L"(X:%td, Y:%td)", x(), y()); + return wil::str_printf(L"(X:%td, Y:%td)", x, y); } - - protected: - ptrdiff_t _x; - ptrdiff_t _y; - -#ifdef UNIT_TESTING - friend class ::PointTests; -#endif }; } @@ -372,34 +235,34 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned" namespace WEX::TestExecution { template<> - class VerifyOutputTraits<::til::point> + class VerifyOutputTraits { public: - static WEX::Common::NoThrowString ToString(const ::til::point& point) + static WEX::Common::NoThrowString ToString(const til::point point) { return WEX::Common::NoThrowString(point.to_string().c_str()); } }; template<> - class VerifyCompareTraits<::til::point, ::til::point> + class VerifyCompareTraits { public: - static bool AreEqual(const ::til::point& expected, const ::til::point& actual) noexcept + static constexpr bool AreEqual(const til::point expected, const til::point actual) noexcept { return expected == actual; } - static bool AreSame(const ::til::point& expected, const ::til::point& actual) noexcept + static constexpr bool AreSame(const til::point expected, const til::point actual) noexcept { return &expected == &actual; } - static bool IsLessThan(const ::til::point& expectedLess, const ::til::point& expectedGreater) = delete; + static constexpr bool IsLessThan(const til::point expectedLess, const til::point expectedGreater) = delete; - static bool IsGreaterThan(const ::til::point& expectedGreater, const ::til::point& expectedLess) = delete; + static constexpr bool IsGreaterThan(const til::point expectedGreater, const til::point expectedLess) = delete; - static bool IsNull(const ::til::point& object) noexcept + static constexpr bool IsNull(const til::point object) noexcept { return object == til::point{}; } diff --git a/src/inc/til/rect.h b/src/inc/til/rect.h new file mode 100644 index 0000000000..f5116da197 --- /dev/null +++ b/src/inc/til/rect.h @@ -0,0 +1,860 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +#pragma once + +#include "bit.h" +#include "some.h" +#include "math.h" +#include "size.h" +#include "point.h" +#include "operators.h" + +namespace til // Terminal Implementation Library. Also: "Today I Learned" +{ + namespace details + { + class _rectangle_const_iterator + { + public: + constexpr _rectangle_const_iterator(point topLeft, point bottomRight) : + _topLeft{ topLeft }, + _bottomRight{ bottomRight }, + _current{ topLeft } + { + } + + constexpr _rectangle_const_iterator(point topLeft, point bottomRight, point start) : + _topLeft{ topLeft }, + _bottomRight{ bottomRight }, + _current{ start } + { + } + + _rectangle_const_iterator& operator++() + { + const auto nextX = details::extract(::base::CheckAdd(_current.x, 1)); + + if (nextX >= _bottomRight.x) + { + const auto nextY = details::extract(::base::CheckAdd(_current.y, 1)); + // Note for the standard Left-to-Right, Top-to-Bottom walk, + // the end position is one cell below the bottom left. + // (or more accurately, on the exclusive bottom line in the inclusive left column.) + _current = { _topLeft.x, nextY }; + } + else + { + _current = { nextX, _current.y }; + } + + return (*this); + } + + constexpr bool operator==(const _rectangle_const_iterator& rhs) const noexcept + { + // `__builtin_memcmp` isn't an official standard, but it's the + // only way at the time of writing to get a constexpr `memcmp`. + return __builtin_memcmp(this, &rhs, sizeof(rhs)) == 0; + } + + constexpr bool operator!=(const _rectangle_const_iterator& rhs) const noexcept + { + return __builtin_memcmp(this, &rhs, sizeof(rhs)) != 0; + } + + constexpr bool operator<(const _rectangle_const_iterator& other) const + { + return _current < other._current; + } + + constexpr bool operator>(const _rectangle_const_iterator& other) const + { + return _current > other._current; + } + + constexpr point operator*() const + { + return _current; + } + + protected: + point _current; + const point _topLeft; + const point _bottomRight; + }; + } + + struct rect + { + using const_iterator = details::_rectangle_const_iterator; + + CoordType left = 0; + CoordType top = 0; + CoordType right = 0; + CoordType bottom = 0; + + constexpr rect() noexcept = default; + + constexpr rect(CoordType left, CoordType top, CoordType right, CoordType bottom) noexcept : + left{ left }, top{ top }, right{ right }, bottom{ bottom } + { + } + + // This template will convert to point from floating-point args; + // a math type is required. If you _don't_ provide one, you're going to + // get a compile-time error about "cannot convert from initializer-list to til::point" + template + constexpr rect(TilMath, T left, T top, T right, T bottom) : + left{ TilMath::template cast(left) }, + top{ TilMath::template cast(top) }, + right{ TilMath::template cast(right) }, + bottom{ TilMath::template cast(bottom) } + { + } + + // Creates a rect where you specify the top-left corner (included) + // and the bottom-right corner (excluded) + constexpr rect(point topLeft, point bottomRight) noexcept : + left{ topLeft.x }, top{ topLeft.y }, right{ bottomRight.x }, bottom{ bottomRight.y } + { + } + + // Creates a rect with the given size where the top-left corner + // is set to 0,0. + explicit constexpr rect(size size) noexcept : + right{ size.width }, bottom{ size.height } + { + } + + // Creates a rect at the given top-left corner point X,Y that extends + // down (+Y direction) and right (+X direction) for the given size. + constexpr rect(point topLeft, size size) : + rect{ topLeft, topLeft + size } + { + } + + constexpr bool operator==(const rect& rhs) const noexcept + { + // `__builtin_memcmp` isn't an official standard, but it's the + // only way at the time of writing to get a constexpr `memcmp`. + return __builtin_memcmp(this, &rhs, sizeof(rhs)) == 0; + } + + constexpr bool operator!=(const rect& rhs) const noexcept + { + return __builtin_memcmp(this, &rhs, sizeof(rhs)) != 0; + } + + explicit constexpr operator bool() const noexcept + { + return (left >= 0) & (top >= 0) & + (right > left) & (bottom > top); + } + + constexpr const_iterator begin() const + { + return const_iterator({ left, top }, { right, bottom }); + } + + constexpr const_iterator end() const + { + // For the standard walk: Left-To-Right then Top-To-Bottom + // the end box is one cell below the left most column. + // |----| 5x2 square. Remember bottom & right are exclusive + // | | while top & left are inclusive. + // X----- X is the end position. + + return const_iterator({ left, top }, { right, bottom }, { left, bottom }); + } + +#pragma region RECTANGLE OPERATORS + // OR = union + constexpr rect operator|(const rect& other) const noexcept + { + const auto thisEmpty = empty(); + const auto otherEmpty = other.empty(); + + // If both are empty, return empty rect. + if (thisEmpty && otherEmpty) + { + return rect{}; + } + + // If this is empty but not the other one, then give the other. + if (thisEmpty) + { + return other; + } + + // If the other is empty but not this, give this. + if (otherEmpty) + { + return *this; + } + + // If we get here, they're both not empty. Do math. + const auto l = std::min(left, other.left); + const auto t = std::min(top, other.top); + const auto r = std::max(right, other.right); + const auto b = std::max(bottom, other.bottom); + return rect{ l, t, r, b }; + } + + constexpr rect& operator|=(const rect& other) noexcept + { + *this = *this | other; + return *this; + } + + // AND = intersect + constexpr rect operator&(const rect& other) const noexcept + { + const auto l = std::max(left, other.left); + const auto r = std::min(right, other.right); + + // If the width dimension would be empty, give back empty rect. + if (l >= r) + { + return rect{}; + } + + const auto t = std::max(top, other.top); + const auto b = std::min(bottom, other.bottom); + + // If the height dimension would be empty, give back empty rect. + if (t >= b) + { + return rect{}; + } + + return rect{ l, t, r, b }; + } + + constexpr rect& operator&=(const rect& other) noexcept + { + *this = *this & other; + return *this; + } + + // - = subtract + constexpr some operator-(const rect& other) const + { + some result; + + // We could have up to four rectangles describing the area resulting when you take removeMe out of main. + // Find the intersection of the two so we know which bits of removeMe are actually applicable + // to the original rect for subtraction purposes. + const auto intersect = *this & other; + + // If there's no intersect, there's nothing to remove. + if (intersect.empty()) + { + // Just put the original rect into the results and return early. + result.push_back(*this); + } + // If the original rect matches the intersect, there is nothing to return. + else if (*this != intersect) + { + // Generate our potential four viewports that represent the region of the original that falls outside of the remove area. + // We will bias toward generating wide rectangles over tall rectangles (if possible) so that optimizations that apply + // to manipulating an entire row at once can be realized by other parts of the console code. (i.e. Run Length Encoding) + // In the following examples, the found remaining regions are represented by: + // T = Top B = Bottom L = Left R = Right + // + // 4 Sides but Identical: + // |-----------this-----------| |-----------this-----------| + // | | | | + // | | | | + // | | | | + // | | ======> | intersect | ======> early return of nothing + // | | | | + // | | | | + // | | | | + // |-----------other----------| |--------------------------| + // + // 4 Sides: + // |-----------this-----------| |-----------this-----------| |--------------------------| + // | | | | |TTTTTTTTTTTTTTTTTTTTTTTTTT| + // | | | | |TTTTTTTTTTTTTTTTTTTTTTTTTT| + // | |---------| | | |---------| | |LLLLLLLL|---------|RRRRRRR| + // | |other | | ======> | |intersect| | ======> |LLLLLLLL| |RRRRRRR| + // | |---------| | | |---------| | |LLLLLLLL|---------|RRRRRRR| + // | | | | |BBBBBBBBBBBBBBBBBBBBBBBBBB| + // | | | | |BBBBBBBBBBBBBBBBBBBBBBBBBB| + // |--------------------------| |--------------------------| |--------------------------| + // + // 3 Sides: + // |-----------this-----------| |-----------this-----------| |--------------------------| + // | | | | |TTTTTTTTTTTTTTTTTTTTTTTTTT| + // | | | | |TTTTTTTTTTTTTTTTTTTTTTTTTT| + // | |--------------------| | |-----------------| |LLLLLLLL|-----------------| + // | |other | ======> | |intersect | ======> |LLLLLLLL| | + // | |--------------------| | |-----------------| |LLLLLLLL|-----------------| + // | | | | |BBBBBBBBBBBBBBBBBBBBBBBBBB| + // | | | | |BBBBBBBBBBBBBBBBBBBBBBBBBB| + // |--------------------------| |--------------------------| |--------------------------| + // + // 2 Sides: + // |-----------this-----------| |-----------this-----------| |--------------------------| + // | | | | |TTTTTTTTTTTTTTTTTTTTTTTTTT| + // | | | | |TTTTTTTTTTTTTTTTTTTTTTTTTT| + // | |--------------------| | |-----------------| |LLLLLLLL|-----------------| + // | |other | ======> | |intersect | ======> |LLLLLLLL| | + // | | | | | | |LLLLLLLL| | + // | | | | | | |LLLLLLLL| | + // | | | | | | |LLLLLLLL| | + // |--------| | |--------------------------| |--------------------------| + // | | + // |--------------------| + // + // 1 Side: + // |-----------this-----------| |-----------this-----------| |--------------------------| + // | | | | |TTTTTTTTTTTTTTTTTTTTTTTTTT| + // | | | | |TTTTTTTTTTTTTTTTTTTTTTTTTT| + // |-----------------------------| |--------------------------| |--------------------------| + // | other | ======> | intersect | ======> | | + // | | | | | | + // | | | | | | + // | | | | | | + // | | |--------------------------| |--------------------------| + // | | + // |-----------------------------| + // + // 0 Sides: + // |-----------this-----------| |-----------this-----------| + // | | | | + // | | | | + // | | | | + // | | ======> | | ======> early return of this + // | | | | + // | | | | + // | | | | + // |--------------------------| |--------------------------| + // + // + // |---------------| + // | other | + // |---------------| + + // We generate these rectangles by the original and intersect points, but some of them might be empty when the intersect + // lines up with the edge of the original. That's OK. That just means that the subtraction didn't leave anything behind. + // We will filter those out below when adding them to the result. + const rect t{ left, top, right, intersect.top }; + const rect b{ left, intersect.bottom, right, bottom }; + const rect l{ left, intersect.top, intersect.left, intersect.bottom }; + const rect r{ intersect.right, intersect.top, right, intersect.bottom }; + + if (!t.empty()) + { + result.push_back(t); + } + + if (!b.empty()) + { + result.push_back(b); + } + + if (!l.empty()) + { + result.push_back(l); + } + + if (!r.empty()) + { + result.push_back(r); + } + } + + return result; + } +#pragma endregion + +#pragma region RECTANGLE VS POINT + // ADD will translate (offset) the rect by the point. + constexpr rect operator+(const point point) const + { + const auto l = details::extract(::base::CheckAdd(left, point.x)); + const auto t = details::extract(::base::CheckAdd(top, point.y)); + const auto r = details::extract(::base::CheckAdd(right, point.x)); + const auto b = details::extract(::base::CheckAdd(bottom, point.y)); + return { l, t, r, b }; + } + + constexpr rect& operator+=(const point point) + { + *this = *this + point; + return *this; + } + + // SUB will translate (offset) the rect by the point. + constexpr rect operator-(const point point) const + { + const auto l = details::extract(::base::CheckSub(left, point.x)); + const auto t = details::extract(::base::CheckSub(top, point.y)); + const auto r = details::extract(::base::CheckSub(right, point.x)); + const auto b = details::extract(::base::CheckSub(bottom, point.y)); + return { l, t, r, b }; + } + + constexpr rect& operator-=(const point point) + { + *this = *this - point; + return *this; + } + +#pragma endregion + +#pragma region RECTANGLE VS SIZE + // ADD will grow the total area of the rect. The sign is the direction to grow. + constexpr rect operator+(const size size) const + { + // Fetch the pieces of the rect. + auto l = left; + auto r = right; + auto t = top; + auto b = bottom; + + // Fetch the scale factors we're using. + const auto width = size.width; + const auto height = size.height; + + // Since this is the add operation versus a size, the result + // should grow the total rect area. + // The sign determines which edge of the rect moves. + // We use the magnitude as how far to move. + if (width > 0) + { + // Adding the positive makes the rect "grow" + // because right stretches outward (to the right). + // + // Example with adding width 3... + // |-- x = origin + // V + // x---------| x------------| + // | | | | + // | | | | + // |---------| |------------| + // BEFORE AFTER + r = details::extract(::base::CheckAdd(r, width)); + } + else + { + // Adding the negative makes the rect "grow" + // because left stretches outward (to the left). + // + // Example with adding width -3... + // |-- x = origin + // V + // x---------| |--x---------| + // | | | | + // | | | | + // |---------| |------------| + // BEFORE AFTER + l = details::extract(::base::CheckAdd(l, width)); + } + + if (height > 0) + { + // Adding the positive makes the rect "grow" + // because bottom stretches outward (to the down). + // + // Example with adding height 2... + // |-- x = origin + // V + // x---------| x---------| + // | | | | + // | | | | + // |---------| | | + // | | + // |---------| + // BEFORE AFTER + b = details::extract(::base::CheckAdd(b, height)); + } + else + { + // Adding the negative makes the rect "grow" + // because top stretches outward (to the up). + // + // Example with adding height -2... + // |-- x = origin + // | + // | |---------| + // V | | + // x---------| x | + // | | | | + // | | | | + // |---------| |---------| + // BEFORE AFTER + t = details::extract(::base::CheckAdd(t, height)); + } + + return rect{ point{ l, t }, point{ r, b } }; + } + + constexpr rect& operator+=(const size size) + { + *this = *this + size; + return *this; + } + + // SUB will shrink the total area of the rect. The sign is the direction to shrink. + constexpr rect operator-(const size size) const + { + // Fetch the pieces of the rect. + auto l = left; + auto r = right; + auto t = top; + auto b = bottom; + + // Fetch the scale factors we're using. + const auto width = size.width; + const auto height = size.height; + + // Since this is the subtract operation versus a size, the result + // should shrink the total rect area. + // The sign determines which edge of the rect moves. + // We use the magnitude as how far to move. + if (width > 0) + { + // Subtracting the positive makes the rect "shrink" + // because right pulls inward (to the left). + // + // Example with subtracting width 3... + // |-- x = origin + // V + // x---------| x------| + // | | | | + // | | | | + // |---------| |------| + // BEFORE AFTER + r = details::extract(::base::CheckSub(r, width)); + } + else + { + // Subtracting the negative makes the rect "shrink" + // because left pulls inward (to the right). + // + // Example with subtracting width -3... + // |-- x = origin + // V + // x---------| x |------| + // | | | | + // | | | | + // |---------| |------| + // BEFORE AFTER + l = details::extract(::base::CheckSub(l, width)); + } + + if (height > 0) + { + // Subtracting the positive makes the rect "shrink" + // because bottom pulls inward (to the up). + // + // Example with subtracting height 2... + // |-- x = origin + // V + // x---------| x---------| + // | | |---------| + // | | + // |---------| + // BEFORE AFTER + b = details::extract(::base::CheckSub(b, height)); + } + else + { + // Subtracting the positive makes the rect "shrink" + // because top pulls inward (to the down). + // + // Example with subtracting height -2... + // |-- x = origin + // V + // x---------| x + // | | + // | | |---------| + // |---------| |---------| + // BEFORE AFTER + t = details::extract(::base::CheckSub(t, height)); + } + + return rect{ point{ l, t }, point{ r, b } }; + } + + constexpr rect& operator-=(const size size) + { + *this = *this - size; + return *this; + } + + // scale_up will scale the entire rect up by the size factor + // This includes moving the origin. + constexpr rect scale_up(const size size) const + { + const auto topLeft = point{ left, top } * size; + const auto bottomRight = point{ right, bottom } * size; + return rect{ topLeft, bottomRight }; + } + + // scale_down will scale the entire rect down by the size factor, + // but rounds the bottom-right corner out. + // This includes moving the origin. + constexpr rect scale_down(const size size) const + { + auto topLeft = point{ left, top }; + auto bottomRight = point{ right, bottom }; + topLeft = topLeft / size; + + // Move bottom right point into a size + // Use size specialization of divide_ceil to round up against the size given. + // Add leading addition to point to convert it back into a point. + bottomRight = point{} + til::size{ right, bottom }.divide_ceil(size); + + return rect{ topLeft, bottomRight }; + } + +#pragma endregion + + template + constexpr T narrow_left() const + { + return gsl::narrow(left); + } + + template + constexpr T narrow_top() const + { + return gsl::narrow(top); + } + + template + constexpr T narrow_right() const + { + return gsl::narrow(right); + } + + template + constexpr T narrow_bottom() const + { + return gsl::narrow(bottom); + } + + constexpr CoordType width() const + { + return details::extract(::base::CheckSub(right, left)); + } + + template + constexpr T narrow_width() const + { + return details::extract(::base::CheckSub(right, left)); + } + + constexpr CoordType height() const + { + return details::extract(::base::CheckSub(bottom, top)); + } + + template + constexpr T narrow_height() const + { + return details::extract(::base::CheckSub(bottom, top)); + } + + constexpr point origin() const noexcept + { + return { left, top }; + } + + constexpr size size() const noexcept + { + return til::size{ width(), height() }; + } + + constexpr bool empty() const noexcept + { + return !operator bool(); + } + + constexpr bool contains(point pt) const noexcept + { + return (pt.x >= left) & (pt.x < right) & + (pt.y >= top) & (pt.y < bottom); + } + + constexpr bool contains(const rect& rc) const noexcept + { + return (rc.left >= left) & (rc.top >= top) & + (rc.right <= right) & (rc.bottom <= bottom); + } + + template + constexpr T index_of(point pt) const + { + THROW_HR_IF(E_INVALIDARG, !contains(pt)); + + // Take Y away from the top to find how many rows down + auto check = ::base::CheckSub(pt.y, top); + + // Multiply by the width because we've passed that many + // widths-worth of indices. + check *= width(); + + // Then add in the last few indices in the x position this row + // and subtract left to find the offset from left edge. + check = check + pt.x - left; + + return details::extract(check); + } + + point point_at(size_t index) const + { + const auto width = details::extract(::base::CheckSub(right, left)); + const auto area = details::extract(::base::CheckSub(bottom, top) * width); + + THROW_HR_IF(E_INVALIDARG, index >= area); + + // Not checking math on these because we're presuming + // that the point can't be in bounds of a rect where + // this would overflow on addition after the division. + const auto quot = gsl::narrow_cast(index / width); + const auto rem = gsl::narrow_cast(index % width); + return point{ left + rem, top + quot }; + } + +#ifdef _WINCONTYPES_ + // NOTE: This will convert from INCLUSIVE on the way in because + // that is generally how SMALL_RECTs are handled in console code and via the APIs. + explicit constexpr rect(const SMALL_RECT other) noexcept : + rect{ other.Left, other.Top, other.Right + 1, other.Bottom + 1 } + { + } + + // NOTE: This will convert back to INCLUSIVE on the way out because + // that is generally how SMALL_RECTs are handled in console code and via the APIs. + constexpr SMALL_RECT to_small_rect() const + { + // The two -1 operations below are technically UB if they underflow. + // But practically speaking no hardware without two's complement for + // signed integers is supported by Windows. If they do underflow, they'll + // result in INT_MAX which will throw in gsl::narrow just like INT_MAX does. + return { + gsl::narrow(left), + gsl::narrow(top), + gsl::narrow(right - 1), + gsl::narrow(bottom - 1), + }; + } +#endif + +#ifdef _WINDEF_ + explicit constexpr rect(const RECT& other) noexcept : + rect{ other.left, other.top, other.right, other.bottom } + { + } + + constexpr RECT to_win32_rect() const noexcept + { + return { left, top, right, bottom }; + } +#endif + +#ifdef DCOMMON_H_INCLUDED + template + constexpr rect(TilMath&& math, const D2D1_RECT_F& other) : + rect{ std::forward(math), other.left, other.top, other.right, other.bottom } + { + } + + constexpr D2D1_RECT_F to_d2d_rect() const noexcept + { + return { + static_cast(left), + static_cast(top), + static_cast(right), + static_cast(bottom), + }; + } +#endif + +#ifdef WINRT_Windows_Foundation_H + template + constexpr rect(TilMath&& math, const winrt::Windows::Foundation::Rect& other) : + rect{ std::forward(math), other.X, other.Y, other.X + other.Width, other.Y + other.Height } + { + } + + winrt::Windows::Foundation::Rect to_winrt_rect() const noexcept + { + return { + static_cast(left), + static_cast(top), + static_cast(width()), + static_cast(height()), + }; + } +#endif + +#ifdef WINRT_Microsoft_Terminal_Core_H + template + constexpr rect(TilMath&& math, const winrt::Microsoft::Terminal::Core::Padding& other) : + rect{ std::forward(math), other.Left, other.Top, other.Right, other.Bottom } + { + } + + winrt::Microsoft::Terminal::Core::Padding to_core_padding() const noexcept + { + return { + static_cast(left), + static_cast(top), + static_cast(right), + static_cast(bottom), + }; + } +#endif + + std::wstring to_string() const + { + return wil::str_printf(L"(L:%d, T:%d, R:%d, B:%d) [W:%d, H:%d]", left, top, right, bottom, width(), height()); + } + }; +} + +#ifdef __WEX_COMMON_H__ +namespace WEX::TestExecution +{ + template<> + class VerifyOutputTraits + { + public: + static WEX::Common::NoThrowString ToString(const til::rect& rect) + { + return WEX::Common::NoThrowString(rect.to_string().c_str()); + } + }; + + template<> + class VerifyCompareTraits + { + public: + static bool AreEqual(const til::rect& expected, const til::rect& actual) noexcept + { + return expected == actual; + } + + static bool AreSame(const til::rect& expected, const til::rect& actual) noexcept + { + return &expected == &actual; + } + + static bool IsLessThan(const til::rect& expectedLess, const til::rect& expectedGreater) = delete; + + static bool IsGreaterThan(const til::rect& expectedGreater, const til::rect& expectedLess) = delete; + + static bool IsNull(const til::rect& object) noexcept + { + return object == til::rect{}; + } + }; + +}; +#endif diff --git a/src/inc/til/rectangle.h b/src/inc/til/rectangle.h deleted file mode 100644 index 43bae773f0..0000000000 --- a/src/inc/til/rectangle.h +++ /dev/null @@ -1,955 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -#pragma once - -#ifdef UNIT_TESTING -class RectangleTests; -#endif - -namespace til // Terminal Implementation Library. Also: "Today I Learned" -{ - namespace details - { - class _rectangle_const_iterator - { - public: - constexpr _rectangle_const_iterator(point topLeft, point bottomRight) : - _topLeft(topLeft), - _bottomRight(bottomRight), - _current(topLeft) - { - } - - constexpr _rectangle_const_iterator(point topLeft, point bottomRight, point start) : - _topLeft(topLeft), - _bottomRight(bottomRight), - _current(start) - { - } - - _rectangle_const_iterator& operator++() - { - ptrdiff_t nextX; - THROW_HR_IF(E_ABORT, !::base::CheckAdd(_current.x(), 1).AssignIfValid(&nextX)); - - if (nextX >= _bottomRight.x()) - { - ptrdiff_t nextY; - THROW_HR_IF(E_ABORT, !::base::CheckAdd(_current.y(), 1).AssignIfValid(&nextY)); - // Note for the standard Left-to-Right, Top-to-Bottom walk, - // the end position is one cell below the bottom left. - // (or more accurately, on the exclusive bottom line in the inclusive left column.) - _current = { _topLeft.x(), nextY }; - } - else - { - _current = { nextX, _current.y() }; - } - - return (*this); - } - - constexpr bool operator==(const _rectangle_const_iterator& other) const - { - return _current == other._current && - _topLeft == other._topLeft && - _bottomRight == other._bottomRight; - } - - constexpr bool operator!=(const _rectangle_const_iterator& other) const - { - return !(*this == other); - } - - constexpr bool operator<(const _rectangle_const_iterator& other) const - { - return _current < other._current; - } - - constexpr bool operator>(const _rectangle_const_iterator& other) const - { - return _current > other._current; - } - - constexpr point operator*() const - { - return _current; - } - - protected: - point _current; - const point _topLeft; - const point _bottomRight; - -#ifdef UNIT_TESTING - friend class ::RectangleTests; -#endif - }; - } - - class rectangle - { - public: - using const_iterator = details::_rectangle_const_iterator; - - constexpr rectangle() noexcept : - rectangle(til::point{ 0, 0 }, til::point{ 0, 0 }) - { - } - - // On 64-bit processors, int and ptrdiff_t are different fundamental types. - // On 32-bit processors, they're the same which makes this a double-definition - // with the `ptrdiff_t` one below. -#if defined(_M_AMD64) || defined(_M_ARM64) - constexpr rectangle(int left, int top, int right, int bottom) noexcept : - rectangle(til::point{ left, top }, til::point{ right, bottom }) - { - } -#endif - - rectangle(size_t left, size_t top, size_t right, size_t bottom) : - rectangle(til::point{ left, top }, til::point{ right, bottom }) - { - } - - constexpr rectangle(ptrdiff_t left, ptrdiff_t top, ptrdiff_t right, ptrdiff_t bottom) noexcept : - rectangle(til::point{ left, top }, til::point{ right, bottom }) - { - } - - // Creates a 1x1 rectangle with the given top-left corner. - rectangle(til::point topLeft) : - _topLeft(topLeft) - { - _bottomRight = _topLeft + til::point{ 1, 1 }; - } - - // Creates a rectangle where you specify the top-left corner (included) - // and the bottom-right corner (excluded) - constexpr rectangle(til::point topLeft, til::point bottomRight) noexcept : - _topLeft(topLeft), - _bottomRight(bottomRight) - { - } - - // Creates a rectangle with the given size where the top-left corner - // is set to 0,0. - constexpr rectangle(til::size size) noexcept : - _topLeft(til::point{ 0, 0 }), - _bottomRight(til::point{ size.width(), size.height() }) - { - } - - // Creates a rectangle at the given top-left corner point X,Y that extends - // down (+Y direction) and right (+X direction) for the given size. - rectangle(til::point topLeft, til::size size) : - _topLeft(topLeft), - _bottomRight(topLeft + til::point{ size.width(), size.height() }) - { - } - -#ifdef _WINCONTYPES_ - // This extra specialization exists for SMALL_RECT because it's the only rectangle in the world that we know of - // with the bottom and right fields INCLUSIVE to the rectangle itself. - // It will perform math on the way in to ensure that it is represented as EXCLUSIVE. - rectangle(SMALL_RECT sr) - { - _topLeft = til::point{ static_cast(sr.Left), static_cast(sr.Top) }; - - _bottomRight = til::point{ static_cast(sr.Right), static_cast(sr.Bottom) } + til::point{ 1, 1 }; - } -#endif - - // This template will convert to rectangle from anything that has a Left, Top, Right, and Bottom field that appear convertible to an integer value - template - constexpr rectangle(const TOther& other, std::enable_if_t().Top)> && std::is_integral_v().Left)> && std::is_integral_v().Bottom)> && std::is_integral_v().Right)>, int> /*sentinel*/ = 0) : - rectangle(til::point{ static_cast(other.Left), static_cast(other.Top) }, til::point{ static_cast(other.Right), static_cast(other.Bottom) }) - { - } - - // This template will convert to rectangle from anything that has a left, top, right, and bottom field that appear convertible to an integer value - template - constexpr rectangle(const TOther& other, std::enable_if_t().top)> && std::is_integral_v().left)> && std::is_integral_v().bottom)> && std::is_integral_v().right)>, int> /*sentinel*/ = 0) : - rectangle(til::point{ static_cast(other.left), static_cast(other.top) }, til::point{ static_cast(other.right), static_cast(other.bottom) }) - { - } - - // This template will convert to rectangle from anything that has a Left, Top, Right, and Bottom field that are floating-point; - // a math type is required. - template - constexpr rectangle(TilMath, const TOther& other, std::enable_if_t().Left)> && std::is_floating_point_v().Top)> && std::is_floating_point_v().Right)> && std::is_floating_point_v().Bottom)>, int> /*sentinel*/ = 0) : - rectangle(til::point{ TilMath::template cast(other.Left), TilMath::template cast(other.Top) }, til::point{ TilMath::template cast(other.Right), TilMath::template cast(other.Bottom) }) - { - } - - // This template will convert to rectangle from anything that has a X, Y, Width, and Height field that are floating-point; - // a math type is required. - template - constexpr rectangle(TilMath, const TOther& other, std::enable_if_t().X)> && std::is_floating_point_v().Y)> && std::is_floating_point_v().Width)> && std::is_floating_point_v().Height)>, int> /*sentinel*/ = 0) : - rectangle(til::point{ TilMath::template cast(other.X), TilMath::template cast(other.Y) }, til::size{ TilMath::template cast(other.Width), TilMath::template cast(other.Height) }) - { - } - - // This template will convert to rectangle from anything that has a left, top, right, and bottom field that are floating-point; - // a math type is required. - template - constexpr rectangle(TilMath, const TOther& other, std::enable_if_t().left)> && std::is_floating_point_v().top)> && std::is_floating_point_v().right)> && std::is_floating_point_v().bottom)>, int> /*sentinel*/ = 0) : - rectangle(til::point{ TilMath::template cast(other.left), TilMath::template cast(other.top) }, til::point{ TilMath::template cast(other.right), TilMath::template cast(other.bottom) }) - { - } - - constexpr bool operator==(const rectangle& other) const noexcept - { - return _topLeft == other._topLeft && - _bottomRight == other._bottomRight; - } - - constexpr bool operator!=(const rectangle& other) const noexcept - { - return !(*this == other); - } - - explicit constexpr operator bool() const noexcept - { - return _topLeft.x() < _bottomRight.x() && - _topLeft.y() < _bottomRight.y(); - } - - constexpr const_iterator begin() const - { - return const_iterator(_topLeft, _bottomRight); - } - - constexpr const_iterator end() const - { - // For the standard walk: Left-To-Right then Top-To-Bottom - // the end box is one cell below the left most column. - // |----| 5x2 square. Remember bottom & right are exclusive - // | | while top & left are inclusive. - // X----- X is the end position. - - return const_iterator(_topLeft, _bottomRight, { _topLeft.x(), _bottomRight.y() }); - } - -#pragma region RECTANGLE OPERATORS - // OR = union - constexpr rectangle operator|(const rectangle& other) const noexcept - { - const auto thisEmpty = empty(); - const auto otherEmpty = other.empty(); - - // If both are empty, return empty rect. - if (thisEmpty && otherEmpty) - { - return rectangle{}; - } - - // If this is empty but not the other one, then give the other. - if (thisEmpty) - { - return other; - } - - // If the other is empty but not this, give this. - if (otherEmpty) - { - return *this; - } - - // If we get here, they're both not empty. Do math. - const auto l = std::min(left(), other.left()); - const auto t = std::min(top(), other.top()); - const auto r = std::max(right(), other.right()); - const auto b = std::max(bottom(), other.bottom()); - return rectangle{ l, t, r, b }; - } - - constexpr rectangle& operator|=(const rectangle& other) noexcept - { - *this = *this | other; - return *this; - } - - // AND = intersect - constexpr rectangle operator&(const rectangle& other) const noexcept - { - const auto l = std::max(left(), other.left()); - const auto r = std::min(right(), other.right()); - - // If the width dimension would be empty, give back empty rectangle. - if (l >= r) - { - return rectangle{}; - } - - const auto t = std::max(top(), other.top()); - const auto b = std::min(bottom(), other.bottom()); - - // If the height dimension would be empty, give back empty rectangle. - if (t >= b) - { - return rectangle{}; - } - - return rectangle{ l, t, r, b }; - } - - constexpr rectangle& operator&=(const rectangle& other) noexcept - { - *this = *this & other; - return *this; - } - - // - = subtract - some operator-(const rectangle& other) const - { - some result; - - // We could have up to four rectangles describing the area resulting when you take removeMe out of main. - // Find the intersection of the two so we know which bits of removeMe are actually applicable - // to the original rectangle for subtraction purposes. - const auto intersect = *this & other; - - // If there's no intersect, there's nothing to remove. - if (intersect.empty()) - { - // Just put the original rectangle into the results and return early. - result.push_back(*this); - } - // If the original rectangle matches the intersect, there is nothing to return. - else if (*this != intersect) - { - // Generate our potential four viewports that represent the region of the original that falls outside of the remove area. - // We will bias toward generating wide rectangles over tall rectangles (if possible) so that optimizations that apply - // to manipulating an entire row at once can be realized by other parts of the console code. (i.e. Run Length Encoding) - // In the following examples, the found remaining regions are represented by: - // T = Top B = Bottom L = Left R = Right - // - // 4 Sides but Identical: - // |-----------this-----------| |-----------this-----------| - // | | | | - // | | | | - // | | | | - // | | ======> | intersect | ======> early return of nothing - // | | | | - // | | | | - // | | | | - // |-----------other----------| |--------------------------| - // - // 4 Sides: - // |-----------this-----------| |-----------this-----------| |--------------------------| - // | | | | |TTTTTTTTTTTTTTTTTTTTTTTTTT| - // | | | | |TTTTTTTTTTTTTTTTTTTTTTTTTT| - // | |---------| | | |---------| | |LLLLLLLL|---------|RRRRRRR| - // | |other | | ======> | |intersect| | ======> |LLLLLLLL| |RRRRRRR| - // | |---------| | | |---------| | |LLLLLLLL|---------|RRRRRRR| - // | | | | |BBBBBBBBBBBBBBBBBBBBBBBBBB| - // | | | | |BBBBBBBBBBBBBBBBBBBBBBBBBB| - // |--------------------------| |--------------------------| |--------------------------| - // - // 3 Sides: - // |-----------this-----------| |-----------this-----------| |--------------------------| - // | | | | |TTTTTTTTTTTTTTTTTTTTTTTTTT| - // | | | | |TTTTTTTTTTTTTTTTTTTTTTTTTT| - // | |--------------------| | |-----------------| |LLLLLLLL|-----------------| - // | |other | ======> | |intersect | ======> |LLLLLLLL| | - // | |--------------------| | |-----------------| |LLLLLLLL|-----------------| - // | | | | |BBBBBBBBBBBBBBBBBBBBBBBBBB| - // | | | | |BBBBBBBBBBBBBBBBBBBBBBBBBB| - // |--------------------------| |--------------------------| |--------------------------| - // - // 2 Sides: - // |-----------this-----------| |-----------this-----------| |--------------------------| - // | | | | |TTTTTTTTTTTTTTTTTTTTTTTTTT| - // | | | | |TTTTTTTTTTTTTTTTTTTTTTTTTT| - // | |--------------------| | |-----------------| |LLLLLLLL|-----------------| - // | |other | ======> | |intersect | ======> |LLLLLLLL| | - // | | | | | | |LLLLLLLL| | - // | | | | | | |LLLLLLLL| | - // | | | | | | |LLLLLLLL| | - // |--------| | |--------------------------| |--------------------------| - // | | - // |--------------------| - // - // 1 Side: - // |-----------this-----------| |-----------this-----------| |--------------------------| - // | | | | |TTTTTTTTTTTTTTTTTTTTTTTTTT| - // | | | | |TTTTTTTTTTTTTTTTTTTTTTTTTT| - // |-----------------------------| |--------------------------| |--------------------------| - // | other | ======> | intersect | ======> | | - // | | | | | | - // | | | | | | - // | | | | | | - // | | |--------------------------| |--------------------------| - // | | - // |-----------------------------| - // - // 0 Sides: - // |-----------this-----------| |-----------this-----------| - // | | | | - // | | | | - // | | | | - // | | ======> | | ======> early return of this - // | | | | - // | | | | - // | | | | - // |--------------------------| |--------------------------| - // - // - // |---------------| - // | other | - // |---------------| - - // We generate these rectangles by the original and intersect points, but some of them might be empty when the intersect - // lines up with the edge of the original. That's OK. That just means that the subtraction didn't leave anything behind. - // We will filter those out below when adding them to the result. - const til::rectangle t{ left(), top(), right(), intersect.top() }; - const til::rectangle b{ left(), intersect.bottom(), right(), bottom() }; - const til::rectangle l{ left(), intersect.top(), intersect.left(), intersect.bottom() }; - const til::rectangle r{ intersect.right(), intersect.top(), right(), intersect.bottom() }; - - if (!t.empty()) - { - result.push_back(t); - } - - if (!b.empty()) - { - result.push_back(b); - } - - if (!l.empty()) - { - result.push_back(l); - } - - if (!r.empty()) - { - result.push_back(r); - } - } - - return result; - } -#pragma endregion - -#pragma region RECTANGLE VS POINT - // ADD will translate (offset) the rectangle by the point. - rectangle operator+(const point& point) const - { - ptrdiff_t l, t, r, b; - - THROW_HR_IF(E_ABORT, !::base::CheckAdd(left(), point.x()).AssignIfValid(&l)); - THROW_HR_IF(E_ABORT, !::base::CheckAdd(top(), point.y()).AssignIfValid(&t)); - THROW_HR_IF(E_ABORT, !::base::CheckAdd(right(), point.x()).AssignIfValid(&r)); - THROW_HR_IF(E_ABORT, !::base::CheckAdd(bottom(), point.y()).AssignIfValid(&b)); - - return til::rectangle{ til::point{ l, t }, til::point{ r, b } }; - } - - rectangle& operator+=(const point& point) - { - *this = *this + point; - return *this; - } - - // SUB will translate (offset) the rectangle by the point. - rectangle operator-(const point& point) const - { - ptrdiff_t l, t, r, b; - - THROW_HR_IF(E_ABORT, !::base::CheckSub(left(), point.x()).AssignIfValid(&l)); - THROW_HR_IF(E_ABORT, !::base::CheckSub(top(), point.y()).AssignIfValid(&t)); - THROW_HR_IF(E_ABORT, !::base::CheckSub(right(), point.x()).AssignIfValid(&r)); - THROW_HR_IF(E_ABORT, !::base::CheckSub(bottom(), point.y()).AssignIfValid(&b)); - - return til::rectangle{ til::point{ l, t }, til::point{ r, b } }; - } - - rectangle& operator-=(const point& point) - { - *this = *this - point; - return *this; - } - -#pragma endregion - -#pragma region RECTANGLE VS SIZE - // ADD will grow the total area of the rectangle. The sign is the direction to grow. - rectangle operator+(const size& size) const - { - // Fetch the pieces of the rectangle. - auto l = left(); - auto r = right(); - auto t = top(); - auto b = bottom(); - - // Fetch the scale factors we're using. - const auto width = size.width(); - const auto height = size.height(); - - // Since this is the add operation versus a size, the result - // should grow the total rectangle area. - // The sign determines which edge of the rectangle moves. - // We use the magnitude as how far to move. - if (width > 0) - { - // Adding the positive makes the rectangle "grow" - // because right stretches outward (to the right). - // - // Example with adding width 3... - // |-- x = origin - // V - // x---------| x------------| - // | | | | - // | | | | - // |---------| |------------| - // BEFORE AFTER - THROW_HR_IF(E_ABORT, !base::CheckAdd(r, width).AssignIfValid(&r)); - } - else - { - // Adding the negative makes the rectangle "grow" - // because left stretches outward (to the left). - // - // Example with adding width -3... - // |-- x = origin - // V - // x---------| |--x---------| - // | | | | - // | | | | - // |---------| |------------| - // BEFORE AFTER - THROW_HR_IF(E_ABORT, !base::CheckAdd(l, width).AssignIfValid(&l)); - } - - if (height > 0) - { - // Adding the positive makes the rectangle "grow" - // because bottom stretches outward (to the down). - // - // Example with adding height 2... - // |-- x = origin - // V - // x---------| x---------| - // | | | | - // | | | | - // |---------| | | - // | | - // |---------| - // BEFORE AFTER - THROW_HR_IF(E_ABORT, !base::CheckAdd(b, height).AssignIfValid(&b)); - } - else - { - // Adding the negative makes the rectangle "grow" - // because top stretches outward (to the up). - // - // Example with adding height -2... - // |-- x = origin - // | - // | |---------| - // V | | - // x---------| x | - // | | | | - // | | | | - // |---------| |---------| - // BEFORE AFTER - THROW_HR_IF(E_ABORT, !base::CheckAdd(t, height).AssignIfValid(&t)); - } - - return rectangle{ til::point{ l, t }, til::point{ r, b } }; - } - - rectangle& operator+=(const size& size) - { - *this = *this + size; - return *this; - } - - // SUB will shrink the total area of the rectangle. The sign is the direction to shrink. - rectangle operator-(const size& size) const - { - // Fetch the pieces of the rectangle. - auto l = left(); - auto r = right(); - auto t = top(); - auto b = bottom(); - - // Fetch the scale factors we're using. - const auto width = size.width(); - const auto height = size.height(); - - // Since this is the subtract operation versus a size, the result - // should shrink the total rectangle area. - // The sign determines which edge of the rectangle moves. - // We use the magnitude as how far to move. - if (width > 0) - { - // Subtracting the positive makes the rectangle "shrink" - // because right pulls inward (to the left). - // - // Example with subtracting width 3... - // |-- x = origin - // V - // x---------| x------| - // | | | | - // | | | | - // |---------| |------| - // BEFORE AFTER - THROW_HR_IF(E_ABORT, !base::CheckSub(r, width).AssignIfValid(&r)); - } - else - { - // Subtracting the negative makes the rectangle "shrink" - // because left pulls inward (to the right). - // - // Example with subtracting width -3... - // |-- x = origin - // V - // x---------| x |------| - // | | | | - // | | | | - // |---------| |------| - // BEFORE AFTER - THROW_HR_IF(E_ABORT, !base::CheckSub(l, width).AssignIfValid(&l)); - } - - if (height > 0) - { - // Subtracting the positive makes the rectangle "shrink" - // because bottom pulls inward (to the up). - // - // Example with subtracting height 2... - // |-- x = origin - // V - // x---------| x---------| - // | | |---------| - // | | - // |---------| - // BEFORE AFTER - THROW_HR_IF(E_ABORT, !base::CheckSub(b, height).AssignIfValid(&b)); - } - else - { - // Subtracting the positive makes the rectangle "shrink" - // because top pulls inward (to the down). - // - // Example with subtracting height -2... - // |-- x = origin - // V - // x---------| x - // | | - // | | |---------| - // |---------| |---------| - // BEFORE AFTER - THROW_HR_IF(E_ABORT, !base::CheckSub(t, height).AssignIfValid(&t)); - } - - return rectangle{ til::point{ l, t }, til::point{ r, b } }; - } - - rectangle& operator-=(const size& size) - { - *this = *this - size; - return *this; - } - - // scale_up will scale the entire rectangle up by the size factor - // This includes moving the origin. - rectangle scale_up(const size& size) const - { - const auto topLeft = _topLeft * size; - const auto bottomRight = _bottomRight * size; - return til::rectangle{ topLeft, bottomRight }; - } - - // scale_down will scale the entire rectangle down by the size factor, - // but rounds the bottom-right corner out. - // This includes moving the origin. - rectangle scale_down(const size& size) const - { - auto topLeft = _topLeft; - auto bottomRight = _bottomRight; - topLeft = topLeft / size; - - // Move bottom right point into a size - // Use size specialization of divide_ceil to round up against the size given. - // Add leading addition to point to convert it back into a point. - bottomRight = til::point{} + til::size{ right(), bottom() }.divide_ceil(size); - - return til::rectangle{ topLeft, bottomRight }; - } - - template - rectangle scale(TilMath, const float scale) const - { - return til::rectangle{ _topLeft.scale(TilMath{}, scale), _bottomRight.scale(TilMath{}, scale) }; - } - -#pragma endregion - - constexpr ptrdiff_t top() const noexcept - { - return _topLeft.y(); - } - - template - T top() const - { - T ret; - THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(top()).AssignIfValid(&ret)); - return ret; - } - - constexpr ptrdiff_t bottom() const noexcept - { - return _bottomRight.y(); - } - - template - T bottom() const - { - T ret; - THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(bottom()).AssignIfValid(&ret)); - return ret; - } - - constexpr ptrdiff_t left() const noexcept - { - return _topLeft.x(); - } - - template - T left() const - { - T ret; - THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(left()).AssignIfValid(&ret)); - return ret; - } - - constexpr ptrdiff_t right() const noexcept - { - return _bottomRight.x(); - } - - template - T right() const - { - T ret; - THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(right()).AssignIfValid(&ret)); - return ret; - } - - ptrdiff_t width() const - { - ptrdiff_t ret; - THROW_HR_IF(E_ABORT, !::base::CheckSub(right(), left()).AssignIfValid(&ret)); - return ret; - } - - template - T width() const - { - T ret; - THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(width()).AssignIfValid(&ret)); - return ret; - } - - ptrdiff_t height() const - { - ptrdiff_t ret; - THROW_HR_IF(E_ABORT, !::base::CheckSub(bottom(), top()).AssignIfValid(&ret)); - return ret; - } - - template - T height() const - { - T ret; - THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(height()).AssignIfValid(&ret)); - return ret; - } - - constexpr point origin() const noexcept - { - return _topLeft; - } - - size size() const - { - return til::size{ width(), height() }; - } - - constexpr bool empty() const noexcept - { - return !operator bool(); - } - - constexpr bool contains(til::point pt) const - { - return pt.x() >= _topLeft.x() && pt.x() < _bottomRight.x() && - pt.y() >= _topLeft.y() && pt.y() < _bottomRight.y(); - } - - bool contains(ptrdiff_t index) const - { - return index >= 0 && index < size().area(); - } - - constexpr bool contains(til::rectangle rc) const - { - // Union the other rectangle and ourselves. - // If the result of that didn't grow at all, then we already - // fully contained the rectangle we were given. - return (*this | rc) == *this; - } - - ptrdiff_t index_of(til::point pt) const - { - THROW_HR_IF(E_INVALIDARG, !contains(pt)); - - // Take Y away from the top to find how many rows down - auto check = base::CheckSub(pt.y(), top()); - - // Multiply by the width because we've passed that many - // widths-worth of indices. - check *= width(); - - // Then add in the last few indices in the x position this row - // and subtract left to find the offset from left edge. - check = check + pt.x() - left(); - - ptrdiff_t result; - THROW_HR_IF(E_ABORT, !check.AssignIfValid(&result)); - return result; - } - - til::point point_at(ptrdiff_t index) const - { - THROW_HR_IF(E_INVALIDARG, !contains(index)); - - const auto div = std::div(index, width()); - - // Not checking math on these because we're presuming - // that the point can't be in bounds of a rectangle where - // this would overflow on addition after the division. - return til::point{ div.rem + left(), div.quot + top() }; - } - -#ifdef _WINCONTYPES_ - // NOTE: This will convert back to INCLUSIVE on the way out because - // that is generally how SMALL_RECTs are handled in console code and via the APIs. - operator SMALL_RECT() const - { - SMALL_RECT ret; - THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(left()).AssignIfValid(&ret.Left)); - THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(top()).AssignIfValid(&ret.Top)); - THROW_HR_IF(E_ABORT, !base::CheckSub(right(), 1).AssignIfValid(&ret.Right)); - THROW_HR_IF(E_ABORT, !base::CheckSub(bottom(), 1).AssignIfValid(&ret.Bottom)); - return ret; - } -#endif - -#ifdef _WINDEF_ - operator RECT() const - { - RECT ret; - THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(left()).AssignIfValid(&ret.left)); - THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(top()).AssignIfValid(&ret.top)); - THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(right()).AssignIfValid(&ret.right)); - THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(bottom()).AssignIfValid(&ret.bottom)); - return ret; - } -#endif - -#ifdef DCOMMON_H_INCLUDED - constexpr operator D2D1_RECT_F() const noexcept - { - return D2D1_RECT_F{ gsl::narrow_cast(left()), gsl::narrow_cast(top()), gsl::narrow_cast(right()), gsl::narrow_cast(bottom()) }; - } -#endif - -#ifdef WINRT_Windows_Foundation_H - operator winrt::Windows::Foundation::Rect() const - { - winrt::Windows::Foundation::Rect ret; - THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(left()).AssignIfValid(&ret.X)); - THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(top()).AssignIfValid(&ret.Y)); - THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(width()).AssignIfValid(&ret.Width)); - THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(height()).AssignIfValid(&ret.Height)); - return ret; - } -#endif - -#ifdef WINRT_Microsoft_Terminal_Core_H - operator winrt::Microsoft::Terminal::Core::Padding() const - { - winrt::Microsoft::Terminal::Core::Padding ret; - THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(left()).AssignIfValid(&ret.Left)); - THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(top()).AssignIfValid(&ret.Top)); - THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(right()).AssignIfValid(&ret.Right)); - THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(bottom()).AssignIfValid(&ret.Bottom)); - return ret; - } - constexpr rectangle(const winrt::Microsoft::Terminal::Core::Padding& padding) : - rectangle(til::math::rounding, padding) - { - } -#endif - - std::wstring to_string() const - { - return wil::str_printf(L"(L:%td, T:%td, R:%td, B:%td) [W:%td, H:%td]", left(), top(), right(), bottom(), width(), height()); - } - - protected: - til::point _topLeft; - til::point _bottomRight; - -#ifdef UNIT_TESTING - friend class ::RectangleTests; -#endif - }; -} - -#ifdef __WEX_COMMON_H__ -namespace WEX::TestExecution -{ - template<> - class VerifyOutputTraits<::til::rectangle> - { - public: - static WEX::Common::NoThrowString ToString(const ::til::rectangle& rect) - { - return WEX::Common::NoThrowString(rect.to_string().c_str()); - } - }; - - template<> - class VerifyCompareTraits<::til::rectangle, ::til::rectangle> - { - public: - static bool AreEqual(const ::til::rectangle& expected, const ::til::rectangle& actual) noexcept - { - return expected == actual; - } - - static bool AreSame(const ::til::rectangle& expected, const ::til::rectangle& actual) noexcept - { - return &expected == &actual; - } - - static bool IsLessThan(const ::til::rectangle& expectedLess, const ::til::rectangle& expectedGreater) = delete; - - static bool IsGreaterThan(const ::til::rectangle& expectedGreater, const ::til::rectangle& expectedLess) = delete; - - static bool IsNull(const ::til::rectangle& object) noexcept - { - return object == til::rectangle{}; - } - }; - -}; -#endif diff --git a/src/inc/til/size.h b/src/inc/til/size.h index 907089ef69..22422bccf7 100644 --- a/src/inc/til/size.h +++ b/src/inc/til/size.h @@ -3,195 +3,107 @@ #pragma once -#ifdef UNIT_TESTING -class SizeTests; -#endif +#include "point.h" namespace til // Terminal Implementation Library. Also: "Today I Learned" { - class size + struct size { - public: - constexpr size() noexcept : - size(0, 0) - { - } + CoordType width = 0; + CoordType height = 0; - // On 64-bit processors, int and ptrdiff_t are different fundamental types. - // On 32-bit processors, they're the same which makes this a double-definition - // with the `ptrdiff_t` one below. -#if defined(_M_AMD64) || defined(_M_ARM64) - constexpr size(int width, int height) noexcept : - size(static_cast(width), static_cast(height)) - { - } - constexpr size(ptrdiff_t width, int height) noexcept : - size(width, static_cast(height)) - { - } - constexpr size(int width, ptrdiff_t height) noexcept : - size(static_cast(width), height) - { - } -#endif + constexpr size() noexcept = default; - size(size_t width, size_t height) - { - THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(width).AssignIfValid(&_width)); - THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(height).AssignIfValid(&_height)); - } - size(long width, long height) - { - THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(width).AssignIfValid(&_width)); - THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(height).AssignIfValid(&_height)); - } - - constexpr size(ptrdiff_t width, ptrdiff_t height) noexcept : - _width(width), - _height(height) - { - } - - // This template will convert to size from anything that has an X and a Y field that appear convertible to an integer value - template - constexpr size(const TOther& other, std::enable_if_t().X)> && std::is_integral_v().Y)>, int> /*sentinel*/ = 0) : - size(static_cast(other.X), static_cast(other.Y)) - { - } - - // This template will convert to size from anything that has a cx and a cy field that appear convertible to an integer value - template - constexpr size(const TOther& other, std::enable_if_t().cx)> && std::is_integral_v().cy)>, int> /*sentinel*/ = 0) : - size(static_cast(other.cx), static_cast(other.cy)) - { - } - - // This template will convert to size from anything that has a X and a Y field that are floating-point; - // a math type is required. If you _don't_ provide one, you're going to - // get a compile-time error about "cannot convert from initializer-list to til::size" - template - constexpr size(TilMath, const TOther& other, std::enable_if_t().X)> && std::is_floating_point_v().Y)>, int> /*sentinel*/ = 0) : - size(TilMath::template cast(other.X), TilMath::template cast(other.Y)) - { - } - - // This template will convert to size from anything that has a cx and a cy field that are floating-point; - // a math type is required. If you _don't_ provide one, you're going to - // get a compile-time error about "cannot convert from initializer-list to til::size" - template - constexpr size(TilMath, const TOther& other, std::enable_if_t().cx)> && std::is_floating_point_v().cy)>, int> /*sentinel*/ = 0) : - size(TilMath::template cast(other.cx), TilMath::template cast(other.cy)) - { - } - - // This template will convert to size from anything that has a Width and a Height field that are floating-point; - // a math type is required. If you _don't_ provide one, you're going to - // get a compile-time error about "cannot convert from initializer-list to til::size" - template - constexpr size(TilMath, const TOther& other, std::enable_if_t().Width)> && std::is_floating_point_v().Height)>, int> /*sentinel*/ = 0) : - size(TilMath::template cast(other.Width), TilMath::template cast(other.Height)) + constexpr size(CoordType width, CoordType height) noexcept : + width{ width }, height{ height } { } // This template will convert to size from floating-point args; // a math type is required. If you _don't_ provide one, you're going to // get a compile-time error about "cannot convert from initializer-list to til::size" - template - constexpr size(TilMath, const TOther& width, const TOther& height, std::enable_if_t, int> /*sentinel*/ = 0) : - size(TilMath::template cast(width), TilMath::template cast(height)) + template + constexpr size(TilMath, const T width, const T height) : + width{ TilMath::template cast(width) }, height{ TilMath::template cast(height) } { } - constexpr bool operator==(const size& other) const noexcept + constexpr bool operator==(const size rhs) const noexcept { - return _width == other._width && - _height == other._height; + // `__builtin_memcmp` isn't an official standard, but it's the + // only way at the time of writing to get a constexpr `memcmp`. + return __builtin_memcmp(this, &rhs, sizeof(rhs)) == 0; } - constexpr bool operator!=(const size& other) const noexcept + constexpr bool operator!=(const size rhs) const noexcept { - return !(*this == other); + return __builtin_memcmp(this, &rhs, sizeof(rhs)) != 0; } constexpr explicit operator bool() const noexcept { - return _width > 0 && _height > 0; + return width > 0 && height > 0; } - size operator+(const size& other) const + constexpr size operator+(const size other) const { - ptrdiff_t width; - THROW_HR_IF(E_ABORT, !base::CheckAdd(_width, other._width).AssignIfValid(&width)); - - ptrdiff_t height; - THROW_HR_IF(E_ABORT, !base::CheckAdd(_height, other._height).AssignIfValid(&height)); - - return size{ width, height }; + return size{ + details::extract(::base::CheckAdd(width, other.width)), + details::extract(::base::CheckAdd(height, other.height)), + }; } - size operator-(const size& other) const + constexpr size operator-(const size other) const { - ptrdiff_t width; - THROW_HR_IF(E_ABORT, !base::CheckSub(_width, other._width).AssignIfValid(&width)); - - ptrdiff_t height; - THROW_HR_IF(E_ABORT, !base::CheckSub(_height, other._height).AssignIfValid(&height)); - - return size{ width, height }; + return size{ + details::extract(::base::CheckSub(width, other.width)), + details::extract(::base::CheckSub(height, other.height)), + }; } - size operator*(const size& other) const + constexpr size operator*(const size other) const { - ptrdiff_t width; - THROW_HR_IF(E_ABORT, !base::CheckMul(_width, other._width).AssignIfValid(&width)); - - ptrdiff_t height; - THROW_HR_IF(E_ABORT, !base::CheckMul(_height, other._height).AssignIfValid(&height)); - - return size{ width, height }; + return size{ + details::extract(::base::CheckMul(width, other.width)), + details::extract(::base::CheckMul(height, other.height)), + }; } - template - size scale(TilMath, const float scale) const + constexpr size operator/(const size other) const { - struct - { - float Width, Height; - } sz; - THROW_HR_IF(E_ABORT, !base::CheckMul(scale, _width).AssignIfValid(&sz.Width)); - THROW_HR_IF(E_ABORT, !base::CheckMul(scale, _height).AssignIfValid(&sz.Height)); - - return til::size(TilMath(), sz); + return size{ + details::extract(::base::CheckDiv(width, other.width)), + details::extract(::base::CheckDiv(height, other.height)), + }; } - size operator/(const size& other) const + template>> + constexpr size scale(TilMath math, const T scale) const { - ptrdiff_t width; - THROW_HR_IF(E_ABORT, !base::CheckDiv(_width, other._width).AssignIfValid(&width)); - - ptrdiff_t height; - THROW_HR_IF(E_ABORT, !base::CheckDiv(_height, other._height).AssignIfValid(&height)); - - return size{ width, height }; + return til::size{ + math, + width * scale, + height * scale, + }; } - size divide_ceil(const size& other) const + constexpr size divide_ceil(const size other) const { // Divide normally to get the floor. const size floor = *this / other; - ptrdiff_t adjWidth = 0; - ptrdiff_t adjHeight = 0; + CoordType adjWidth = 0; + CoordType adjHeight = 0; // Check for width remainder, anything not 0. // If we multiply the floored number with the other, it will equal // the old width if there was no remainder. - if (other._width * floor._width != _width) + if (other.width * floor.width != width) { // If there was any remainder, // Grow the magnitude by 1 in the // direction of the sign. - if (floor.width() >= 0) + if (floor.width >= 0) { ++adjWidth; } @@ -204,12 +116,12 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned" // Check for height remainder, anything not 0. // If we multiply the floored number with the other, it will equal // the old width if there was no remainder. - if (other._height * floor._height != _height) + if (other.height * floor.height != height) { // If there was any remainder, // Grow the magnitude by 1 in the // direction of the sign. - if (_height >= 0) + if (height >= 0) { ++adjHeight; } @@ -222,86 +134,80 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned" return floor + size{ adjWidth, adjHeight }; } - constexpr ptrdiff_t width() const noexcept + template + constexpr T narrow_width() const { - return _width; + return gsl::narrow(width); } - template - T width() const + template + constexpr T narrow_height() const { - T ret; - THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(width()).AssignIfValid(&ret)); - return ret; + return gsl::narrow(height); } - constexpr ptrdiff_t height() const noexcept + template + constexpr T area() const { - return _height; - } - - template - T height() const - { - T ret; - THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(height()).AssignIfValid(&ret)); - return ret; - } - - ptrdiff_t area() const - { - ptrdiff_t result; - THROW_HR_IF(E_ABORT, !base::CheckMul(_width, _height).AssignIfValid(&result)); - return result; - } - - template - T area() const - { - T ret; - THROW_HR_IF(E_ABORT, !base::CheckMul(_width, _height).AssignIfValid(&ret)); - return ret; + return gsl::narrow(static_cast(width) * static_cast(height)); } #ifdef _WINCONTYPES_ - operator COORD() const + explicit constexpr size(const COORD other) noexcept : + width{ other.X }, height{ other.Y } { - COORD ret; - THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(_width).AssignIfValid(&ret.X)); - THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(_height).AssignIfValid(&ret.Y)); - return ret; + } + + constexpr COORD to_win32_coord() const + { + return { gsl::narrow(width), gsl::narrow(height) }; } #endif #ifdef _WINDEF_ - operator SIZE() const + explicit constexpr size(const SIZE other) noexcept : + width{ other.cx }, height{ other.cy } { - SIZE ret; - THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(_width).AssignIfValid(&ret.cx)); - THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(_height).AssignIfValid(&ret.cy)); - return ret; + } + + constexpr SIZE to_win32_size() const noexcept + { + return { width, height }; } #endif #ifdef DCOMMON_H_INCLUDED - constexpr operator D2D1_SIZE_F() const noexcept + template + constexpr size(TilMath, const D2D1_SIZE_F other) : + width{ TilMath::template cast(other.width) }, + height{ TilMath::template cast(other.height) } { - return D2D1_SIZE_F{ gsl::narrow_cast(_width), gsl::narrow_cast(_height) }; + } + + constexpr D2D1_SIZE_F to_d2d_size() const noexcept + { + return { static_cast(width), static_cast(height) }; + } +#endif + +#ifdef WINRT_Windows_Foundation_H + template + constexpr size(TilMath, const winrt::Windows::Foundation::Size other) : + width{ TilMath::template cast(other.Width) }, + height{ TilMath::template cast(other.Height) } + { + } + + winrt::Windows::Foundation::Size to_winrt_size() const noexcept + { + return { static_cast(width), static_cast(height) }; } #endif std::wstring to_string() const { - return wil::str_printf(L"[W:%td, H:%td]", width(), height()); + return wil::str_printf(L"[W:%td, H:%td]", width, height); } - - protected: - ptrdiff_t _width; - ptrdiff_t _height; - -#ifdef UNIT_TESTING - friend class ::SizeTests; -#endif }; }; @@ -309,34 +215,34 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned" namespace WEX::TestExecution { template<> - class VerifyOutputTraits<::til::size> + class VerifyOutputTraits { public: - static WEX::Common::NoThrowString ToString(const ::til::size& size) + static WEX::Common::NoThrowString ToString(const til::size size) { return WEX::Common::NoThrowString(size.to_string().c_str()); } }; template<> - class VerifyCompareTraits<::til::size, ::til::size> + class VerifyCompareTraits { public: - static bool AreEqual(const ::til::size& expected, const ::til::size& actual) noexcept + static bool AreEqual(const til::size expected, const til::size actual) noexcept { return expected == actual; } - static bool AreSame(const ::til::size& expected, const ::til::size& actual) noexcept + static bool AreSame(const til::size expected, const til::size actual) noexcept { return &expected == &actual; } - static bool IsLessThan(const ::til::size& expectedLess, const ::til::size& expectedGreater) = delete; + static bool IsLessThan(const til::size expectedLess, const til::size expectedGreater) = delete; - static bool IsGreaterThan(const ::til::size& expectedGreater, const ::til::size& expectedLess) = delete; + static bool IsGreaterThan(const til::size expectedGreater, const til::size expectedLess) = delete; - static bool IsNull(const ::til::size& object) noexcept + static bool IsNull(const til::size object) noexcept { return object == til::size{}; } diff --git a/src/inc/til/some.h b/src/inc/til/some.h index 96d523c486..d21a3cdca5 100644 --- a/src/inc/til/some.h +++ b/src/inc/til/some.h @@ -33,13 +33,13 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned" using reverse_iterator = typename decltype(_array)::reverse_iterator; using const_reverse_iterator = typename decltype(_array)::const_reverse_iterator; - some() noexcept : + constexpr some() noexcept : _array{}, _used{ 0 } { } - some(std::initializer_list init) + constexpr some(std::initializer_list init) { if (init.size() > N) { @@ -60,13 +60,13 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned" return !(*this == other); } - void fill(const T& _Value) + constexpr void fill(const T& _Value) { _array.fill(_Value); _used = N; } - void swap(some& _Other) noexcept(std::is_nothrow_swappable::value) + constexpr void swap(some& _Other) noexcept(std::is_nothrow_swappable::value) { _array.swap(_Other._array); std::swap(_used, _Other._used); @@ -163,7 +163,7 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned" return _array.data(); } - void push_back(const T& val) + constexpr void push_back(const T& val) { if (_used >= N) { @@ -175,7 +175,7 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned" ++_used; } - void push_back(T&& val) + constexpr void push_back(T&& val) { if (_used >= N) { @@ -187,7 +187,7 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned" ++_used; } - void pop_back() + constexpr void pop_back() { if (_used <= 0) { @@ -199,12 +199,12 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned" til::at(_array, _used) = 0; } - [[noreturn]] void _invalidArg() const + [[noreturn]] constexpr void _invalidArg() const { throw std::invalid_argument("invalid argument"); } - [[noreturn]] void _outOfRange() const + [[noreturn]] constexpr void _outOfRange() const { throw std::out_of_range("invalid some subscript"); } diff --git a/src/interactivity/onecore/BgfxEngine.cpp b/src/interactivity/onecore/BgfxEngine.cpp index ef9e951129..1f05709f0b 100644 --- a/src/interactivity/onecore/BgfxEngine.cpp +++ b/src/interactivity/onecore/BgfxEngine.cpp @@ -231,15 +231,10 @@ BgfxEngine::BgfxEngine(PVOID SharedViewBase, LONG DisplayHeight, LONG DisplayWid return S_OK; } -[[nodiscard]] HRESULT BgfxEngine::GetDirtyArea(gsl::span& area) noexcept +[[nodiscard]] HRESULT BgfxEngine::GetDirtyArea(gsl::span& area) noexcept { - SMALL_RECT r; - r.Bottom = _displayHeight > 0 ? (SHORT)(_displayHeight - 1) : 0; - r.Top = 0; - r.Left = 0; - r.Right = _displayWidth > 0 ? (SHORT)(_displayWidth - 1) : 0; - - _dirtyArea = r; + _dirtyArea.bottom = std::max(0, _displayHeight); + _dirtyArea.right = std::max(0, _displayWidth); area = { &_dirtyArea, 1 }; diff --git a/src/interactivity/onecore/BgfxEngine.hpp b/src/interactivity/onecore/BgfxEngine.hpp index 4a01837d93..adb3b930a1 100644 --- a/src/interactivity/onecore/BgfxEngine.hpp +++ b/src/interactivity/onecore/BgfxEngine.hpp @@ -68,7 +68,7 @@ namespace Microsoft::Console::Render [[nodiscard]] HRESULT GetProposedFont(const FontInfoDesired& fiFontInfoDesired, FontInfo& fiFontInfo, int const iDpi) noexcept override; - [[nodiscard]] HRESULT GetDirtyArea(gsl::span& area) noexcept override; + [[nodiscard]] HRESULT GetDirtyArea(gsl::span& area) 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; @@ -81,7 +81,7 @@ namespace Microsoft::Console::Render LONG _displayHeight; LONG _displayWidth; - til::rectangle _dirtyArea; + til::rect _dirtyArea; COORD _fontSize; diff --git a/src/interactivity/win32/ut_interactivity_win32/GeneratedUiaTextRangeMovementTests.g.cpp b/src/interactivity/win32/ut_interactivity_win32/GeneratedUiaTextRangeMovementTests.g.cpp index a1339bb8c6..535d782297 100644 --- a/src/interactivity/win32/ut_interactivity_win32/GeneratedUiaTextRangeMovementTests.g.cpp +++ b/src/interactivity/win32/ut_interactivity_win32/GeneratedUiaTextRangeMovementTests.g.cpp @@ -5,7 +5,7 @@ // These were generated by tools\TestTableWriter\GenerateTests.ps1 // Read tools\TestTableWriter\README.md for more details // Define a few helpful variables -constexpr til::rectangle bufferSize{ 0, 0, 80, 300 }; +constexpr til::rect bufferSize{ 0, 0, 80, 300 }; constexpr short midX{ 40 }; constexpr short midY{ 150 }; constexpr short midPopulatedY{ 75 }; @@ -28,7 +28,7 @@ constexpr auto docEndM1L{ point_offset_by_line(docEnd, bufferSize, -1) }; constexpr auto docEndM5C{ point_offset_by_char(docEnd, bufferSize, -5) }; constexpr auto docEndM5L{ point_offset_by_line(docEnd, bufferSize, -5) }; constexpr auto docEndP1C{ point_offset_by_char(docEnd, bufferSize, 1) }; -constexpr til::point lastCharPosLeft{ bufferSize.left(), lastCharPos.y() }; +constexpr til::point lastCharPosLeft{ bufferSize.left, lastCharPos.y }; constexpr auto lastCharPosM1C{ point_offset_by_char(lastCharPos, bufferSize, -1) }; constexpr auto lastCharPosM1L{ point_offset_by_line(lastCharPos, bufferSize, -1) }; constexpr auto lastCharPosM4C{ point_offset_by_char(lastCharPos, bufferSize, -4) }; @@ -39,7 +39,7 @@ constexpr auto lastCharPosP1C{ point_offset_by_char(lastCharPos, bufferSize, 1) constexpr auto lastCharPosP2C{ point_offset_by_char(lastCharPos, bufferSize, 2) }; constexpr auto lastCharPosP5C{ point_offset_by_char(lastCharPos, bufferSize, 5) }; constexpr auto lastCharPosP6C{ point_offset_by_char(lastCharPos, bufferSize, 6) }; -constexpr til::point midDocEndLeft{ bufferSize.left(), midDocEnd.y() }; +constexpr til::point midDocEndLeft{ bufferSize.left, midDocEnd.y }; constexpr auto midDocEndM1C{ point_offset_by_char(midDocEnd, bufferSize, -1) }; constexpr auto midDocEndM1L{ point_offset_by_line(midDocEnd, bufferSize, -1) }; constexpr auto midDocEndM4C{ point_offset_by_char(midDocEnd, bufferSize, -4) }; @@ -51,7 +51,7 @@ constexpr auto midDocEndP2C{ point_offset_by_char(midDocEnd, bufferSize, 2) }; constexpr auto midDocEndP5C{ point_offset_by_char(midDocEnd, bufferSize, 5) }; constexpr auto midDocEndP6C{ point_offset_by_char(midDocEnd, bufferSize, 6) }; constexpr auto midEmptySpaceP1C{ point_offset_by_char(midEmptySpace, bufferSize, 1) }; -constexpr til::point midHistoryLeft{ bufferSize.left(), midHistory.y() }; +constexpr til::point midHistoryLeft{ bufferSize.left, midHistory.y }; constexpr auto midHistoryM1C{ point_offset_by_char(midHistory, bufferSize, -1) }; constexpr auto midHistoryM1L{ point_offset_by_line(midHistory, bufferSize, -1) }; constexpr auto midHistoryM4C{ point_offset_by_char(midHistory, bufferSize, -4) }; @@ -83,29 +83,29 @@ constexpr auto originP5C{ point_offset_by_char(origin, bufferSize, 5) }; constexpr auto originP5L{ point_offset_by_line(origin, bufferSize, 5) }; constexpr auto originP6C{ point_offset_by_char(origin, bufferSize, 6) }; constexpr auto originP6L{ point_offset_by_line(origin, bufferSize, 6) }; -constexpr til::point segment0LmidTopP1L{ segment0, midTopP1L.y() }; -constexpr til::point segment1LmidDocEnd{ segment1, midDocEnd.y() }; -constexpr til::point segment1LmidHistory{ segment1, midHistory.y() }; -constexpr til::point segment1LmidTop{ segment1, midTop.y() }; -constexpr til::point segment1LmidTopP1L{ segment1, midTopP1L.y() }; -constexpr til::point segment2LmidDocEnd{ segment2, midDocEnd.y() }; -constexpr til::point segment2LmidDocEndM1L{ segment2, midDocEndM1L.y() }; -constexpr til::point segment2LmidHistory{ segment2, midHistory.y() }; -constexpr til::point segment2LmidHistoryM1L{ segment2, midHistoryM1L.y() }; -constexpr til::point segment2LmidHistoryP1L{ segment2, midHistoryP1L.y() }; -constexpr til::point segment2LmidTop{ segment2, midTop.y() }; -constexpr til::point segment2LmidTopP1L{ segment2, midTopP1L.y() }; -constexpr til::point segment3LmidDocEnd{ segment3, midDocEnd.y() }; -constexpr til::point segment3LmidDocEndM1L{ segment3, midDocEndM1L.y() }; -constexpr til::point segment3LmidHistory{ segment3, midHistory.y() }; -constexpr til::point segment3LmidHistoryM1L{ segment3, midHistoryM1L.y() }; -constexpr til::point segment3LmidHistoryP1L{ segment3, midHistoryP1L.y() }; -constexpr til::point segment3LmidTop{ segment3, midTop.y() }; -constexpr til::point segment3LmidTopP1L{ segment3, midTopP1L.y() }; -constexpr til::point segment4LlastCharPosM1L{ segment4, lastCharPosM1L.y() }; -constexpr til::point segment4LmidDocEnd{ segment4, midDocEnd.y() }; -constexpr til::point segment4LmidHistory{ segment4, midHistory.y() }; -constexpr til::point segment4LmidTop{ segment4, midTop.y() }; +constexpr til::point segment0LmidTopP1L{ segment0, midTopP1L.y }; +constexpr til::point segment1LmidDocEnd{ segment1, midDocEnd.y }; +constexpr til::point segment1LmidHistory{ segment1, midHistory.y }; +constexpr til::point segment1LmidTop{ segment1, midTop.y }; +constexpr til::point segment1LmidTopP1L{ segment1, midTopP1L.y }; +constexpr til::point segment2LmidDocEnd{ segment2, midDocEnd.y }; +constexpr til::point segment2LmidDocEndM1L{ segment2, midDocEndM1L.y }; +constexpr til::point segment2LmidHistory{ segment2, midHistory.y }; +constexpr til::point segment2LmidHistoryM1L{ segment2, midHistoryM1L.y }; +constexpr til::point segment2LmidHistoryP1L{ segment2, midHistoryP1L.y }; +constexpr til::point segment2LmidTop{ segment2, midTop.y }; +constexpr til::point segment2LmidTopP1L{ segment2, midTopP1L.y }; +constexpr til::point segment3LmidDocEnd{ segment3, midDocEnd.y }; +constexpr til::point segment3LmidDocEndM1L{ segment3, midDocEndM1L.y }; +constexpr til::point segment3LmidHistory{ segment3, midHistory.y }; +constexpr til::point segment3LmidHistoryM1L{ segment3, midHistoryM1L.y }; +constexpr til::point segment3LmidHistoryP1L{ segment3, midHistoryP1L.y }; +constexpr til::point segment3LmidTop{ segment3, midTop.y }; +constexpr til::point segment3LmidTopP1L{ segment3, midTopP1L.y }; +constexpr til::point segment4LlastCharPosM1L{ segment4, lastCharPosM1L.y }; +constexpr til::point segment4LmidDocEnd{ segment4, midDocEnd.y }; +constexpr til::point segment4LmidHistory{ segment4, midHistory.y }; +constexpr til::point segment4LmidTop{ segment4, midTop.y }; struct GeneratedMovementTestInput { TextUnit unit; diff --git a/src/interactivity/win32/ut_interactivity_win32/UiaTextRangeTests.cpp b/src/interactivity/win32/ut_interactivity_win32/UiaTextRangeTests.cpp index cba9aa951b..323f278868 100644 --- a/src/interactivity/win32/ut_interactivity_win32/UiaTextRangeTests.cpp +++ b/src/interactivity/win32/ut_interactivity_win32/UiaTextRangeTests.cpp @@ -21,23 +21,23 @@ using namespace Microsoft::WRL; using namespace Microsoft::Console::Interactivity::Win32; -static constexpr til::point point_offset_by_char(const til::point start, const til::rectangle bounds, ptrdiff_t amt) +static constexpr til::point point_offset_by_char(const til::point start, const til::rect& bounds, til::CoordType amt) { - ptrdiff_t pos_x = start.x(); - ptrdiff_t pos_y = start.y(); + auto pos_x = start.x; + auto pos_y = start.y; while (amt != 0) { if (amt > 0) { - if (pos_x == bounds.left() && pos_y == bounds.bottom()) + if (pos_x == bounds.left && pos_y == bounds.bottom) { // end exclusive --> can't move any more break; } - else if (pos_x == bounds.right() - 1) + else if (pos_x == bounds.right - 1) { // right boundary --> wrap - pos_x = bounds.left(); + pos_x = bounds.left; ++pos_y; } else @@ -49,15 +49,15 @@ static constexpr til::point point_offset_by_char(const til::point start, const t } else { - if (pos_x == bounds.left() && pos_y == bounds.top()) + if (pos_x == bounds.left && pos_y == bounds.top) { // origin --> can't move any more break; } - else if (pos_x == bounds.left()) + else if (pos_x == bounds.left) { // left boundary --> wrap - pos_x = bounds.right() - 1; + pos_x = bounds.right - 1; --pos_y; } else @@ -71,16 +71,16 @@ static constexpr til::point point_offset_by_char(const til::point start, const t return { pos_x, pos_y }; } -static constexpr til::point point_offset_by_line(const til::point start, const til::rectangle bounds, ptrdiff_t amt) +static constexpr til::point point_offset_by_line(const til::point start, const til::rect& bounds, til::CoordType amt) { // X = left boundary for UIA - ptrdiff_t pos_x = bounds.left(); - ptrdiff_t pos_y = start.y(); + auto pos_x = bounds.left; + auto pos_y = start.y; while (amt != 0) { if (amt > 0) { - if (pos_y == bounds.bottom() + 1) + if (pos_y == bounds.bottom + 1) { break; } @@ -92,7 +92,7 @@ static constexpr til::point point_offset_by_line(const til::point start, const t } else { - if (pos_y == bounds.top()) + if (pos_y == bounds.top) { break; } @@ -399,8 +399,8 @@ class UiaTextRangeTests THROW_IF_FAILED(Microsoft::WRL::MakeAndInitialize(°enerate, _pUiaData, &_dummyProvider, - origin, - origin)); + origin.to_win32_coord(), + origin.to_win32_coord())); VERIFY_IS_TRUE(degenerate->IsDegenerate()); VERIFY_ARE_EQUAL(degenerate->_start, degenerate->_end); @@ -410,8 +410,8 @@ class UiaTextRangeTests THROW_IF_FAILED(Microsoft::WRL::MakeAndInitialize(¬Degenerate, _pUiaData, &_dummyProvider, - origin, - end)); + origin.to_win32_coord(), + end.to_win32_coord())); VERIFY_IS_FALSE(notDegenerate->IsDegenerate()); VERIFY_ARE_NOT_EQUAL(notDegenerate->_start, notDegenerate->_end); } @@ -422,8 +422,8 @@ class UiaTextRangeTests THROW_IF_FAILED(Microsoft::WRL::MakeAndInitialize(&utr1, _pUiaData, &_dummyProvider, - origin, - origin)); + origin.to_win32_coord(), + origin.to_win32_coord())); // utr2 initialized to have the same start/end as utr1 Microsoft::WRL::ComPtr utr2; @@ -439,8 +439,8 @@ class UiaTextRangeTests THROW_IF_FAILED(Microsoft::WRL::MakeAndInitialize(&utr2, _pUiaData, &_dummyProvider, - origin, - end)); + origin.to_win32_coord(), + end.to_win32_coord())); Log::Comment(L"_end is different"); THROW_IF_FAILED(utr1->Compare(utr2.Get(), &comparison)); @@ -453,8 +453,8 @@ class UiaTextRangeTests THROW_IF_FAILED(Microsoft::WRL::MakeAndInitialize(&utr1, _pUiaData, &_dummyProvider, - origin, - origin)); + origin.to_win32_coord(), + origin.to_win32_coord())); Microsoft::WRL::ComPtr utr2; THROW_IF_FAILED(utr1->Clone(&utr2)); @@ -475,8 +475,8 @@ class UiaTextRangeTests THROW_IF_FAILED(Microsoft::WRL::MakeAndInitialize(&utr2, _pUiaData, &_dummyProvider, - origin, - end)); + origin.to_win32_coord(), + end.to_win32_coord())); Log::Comment(L"_start should match"); THROW_IF_FAILED(utr1->CompareEndpoints(TextPatternRangeEndpoint_Start, utr2.Get(), TextPatternRangeEndpoint_Start, &comparison)); @@ -659,8 +659,8 @@ class UiaTextRangeTests THROW_IF_FAILED(Microsoft::WRL::MakeAndInitialize(&target, _pUiaData, &_dummyProvider, - origin, - origin)); + origin.to_win32_coord(), + origin.to_win32_coord())); }; Log::Comment(L"Move target's end to utr1's start"); @@ -669,7 +669,7 @@ class UiaTextRangeTests THROW_IF_FAILED(target->MoveEndpointByRange(TextPatternRangeEndpoint_End, utr.Get(), TextPatternRangeEndpoint_Start)); - VERIFY_ARE_EQUAL(target->GetEndpoint(TextPatternRangeEndpoint_Start), origin); + VERIFY_ARE_EQUAL(target->GetEndpoint(TextPatternRangeEndpoint_Start), origin.to_win32_coord()); VERIFY_ARE_EQUAL(target->GetEndpoint(TextPatternRangeEndpoint_End), utr->GetEndpoint(TextPatternRangeEndpoint_Start)); } @@ -679,7 +679,7 @@ class UiaTextRangeTests THROW_IF_FAILED(target->MoveEndpointByRange(TextPatternRangeEndpoint_End, utr.Get(), TextPatternRangeEndpoint_End)); - VERIFY_ARE_EQUAL(target->GetEndpoint(TextPatternRangeEndpoint_Start), origin); + VERIFY_ARE_EQUAL(target->GetEndpoint(TextPatternRangeEndpoint_Start), origin.to_win32_coord()); VERIFY_ARE_EQUAL(target->GetEndpoint(TextPatternRangeEndpoint_End), utr->GetEndpoint(TextPatternRangeEndpoint_End)); THROW_IF_FAILED(target->MoveEndpointByRange(TextPatternRangeEndpoint_Start, @@ -738,7 +738,7 @@ class UiaTextRangeTests // GH#6986: This is used as the "end of the buffer" to help screen readers run faster // instead of parsing through thousands of empty lines of text. - const COORD documentEnd{ _pTextBuffer->GetSize().Left(), _pTextBuffer->GetLastNonSpaceCharacter().Y + 1 }; + const COORD documentEnd{ _pTextBuffer->GetSize().Left(), gsl::narrow(_pTextBuffer->GetLastNonSpaceCharacter().Y + 1) }; // clang-format off const std::vector testData @@ -798,8 +798,8 @@ class UiaTextRangeTests -5, { -5, - {lastColumnIndex - 4, 0}, - {lastColumnIndex - 3, 0} + {gsl::narrow(lastColumnIndex - 4), 0}, + {gsl::narrow(lastColumnIndex - 3), 0} } } }; @@ -826,7 +826,7 @@ class UiaTextRangeTests // GH#6986: This is used as the "end of the buffer" to help screen readers run faster // instead of parsing through thousands of empty lines of text. - const COORD documentEnd{ _pTextBuffer->GetSize().Left(), _pTextBuffer->GetLastNonSpaceCharacter().Y + 1 }; + const COORD documentEnd{ _pTextBuffer->GetSize().Left(), gsl::narrow(_pTextBuffer->GetLastNonSpaceCharacter().Y + 1) }; // clang-format off const std::vector testData @@ -1060,7 +1060,7 @@ class UiaTextRangeTests // GH#6986: This is used as the "end of the buffer" to help screen readers run faster // instead of parsing through thousands of empty lines of text. - const COORD documentEnd{ _pTextBuffer->GetSize().Left(), _pTextBuffer->GetLastNonSpaceCharacter().Y + 1 }; + const COORD documentEnd{ _pTextBuffer->GetSize().Left(), gsl::narrow(_pTextBuffer->GetLastNonSpaceCharacter().Y + 1) }; // clang-format off const std::vector testData @@ -1134,7 +1134,7 @@ class UiaTextRangeTests MoveEndpointTest{ L"can't move _end forwards when it's on the bottom row (past doc end)", {0, 0}, - {lastColumnIndex - 3, bottomRow}, + {gsl::narrow(lastColumnIndex - 3), bottomRow}, 1, TextPatternRangeEndpoint_End, 0, @@ -1145,7 +1145,7 @@ class UiaTextRangeTests MoveEndpointTest{ L"can't move _end forwards when it's at the end of the buffer already (past doc end)", {0, 0}, - {0, bottomRow+1}, + {0, gsl::narrow(bottomRow + 1)}, 1, TextPatternRangeEndpoint_End, 0, @@ -1167,7 +1167,7 @@ class UiaTextRangeTests MoveEndpointTest{ L"moving _end backward when it's already on the top row creates a degenerate range at the document start", {4, 0}, - {lastColumnIndex - 5, 0}, + {gsl::narrow(lastColumnIndex - 5), 0}, -1, TextPatternRangeEndpoint_End, -1, @@ -1198,7 +1198,7 @@ class UiaTextRangeTests // GH#6986: This is used as the "end of the buffer" to help screen readers run faster // instead of parsing through thousands of empty lines of text. - const COORD documentEnd{ _pTextBuffer->GetSize().Left(), _pTextBuffer->GetLastNonSpaceCharacter().Y + 1 }; + const COORD documentEnd{ _pTextBuffer->GetSize().Left(), gsl::narrow(_pTextBuffer->GetLastNonSpaceCharacter().Y + 1) }; // clang-format off const std::vector testData = @@ -1232,7 +1232,7 @@ class UiaTextRangeTests MoveEndpointTest{ L"can't move _end forward when it's already at the end of the buffer (past doc end)", {3, 2}, - {0, bottomRow+1}, + {0, gsl::narrow(bottomRow + 1)}, 1, TextPatternRangeEndpoint_End, { @@ -1320,10 +1320,10 @@ class UiaTextRangeTests Log::Comment(NoThrowString().Format(L"%s", toString(static_cast(textUnit)))); // Create a degenerate UTR at EndExclusive - THROW_IF_FAILED(Microsoft::WRL::MakeAndInitialize(&utr, _pUiaData, &_dummyProvider, bufferEnd, endExclusive)); + THROW_IF_FAILED(Microsoft::WRL::MakeAndInitialize(&utr, _pUiaData, &_dummyProvider, bufferEnd.to_win32_coord(), endExclusive.to_win32_coord())); THROW_IF_FAILED(utr->ExpandToEnclosingUnit(static_cast(textUnit))); - VERIFY_ARE_EQUAL(documentEnd, til::point{ utr->_end }); + VERIFY_ARE_EQUAL(documentEnd, utr->_end); } TEST_METHOD(MovementAtExclusiveEnd) @@ -1335,16 +1335,16 @@ class UiaTextRangeTests // write "temp" at (2,2) _pTextBuffer->Reset(); const til::point writeTarget{ 2, 2 }; - _pTextBuffer->Write({ L"temp" }, writeTarget); + _pTextBuffer->Write({ L"temp" }, writeTarget.to_win32_coord()); // GH#6986: This is used as the "end of the buffer" to help screen readers run faster // instead of parsing through thousands of empty lines of text. - const COORD documentEndInclusive{ base::ClampSub(static_cast(bufferSize.right()), 1), _pTextBuffer->GetLastNonSpaceCharacter().Y }; - const COORD documentEndExclusive{ static_cast(bufferSize.left()), base::ClampAdd(documentEndInclusive.Y, 1) }; + const til::point documentEndInclusive{ base::ClampSub(static_cast(bufferSize.right), 1), _pTextBuffer->GetLastNonSpaceCharacter().Y }; + const til::point documentEndExclusive{ static_cast(bufferSize.left), base::ClampAdd(documentEndInclusive.y, 1) }; - const COORD lastLineStart{ static_cast(bufferSize.left()), documentEndInclusive.Y }; - const auto secondToLastLinePos{ point_offset_by_line(lastLineStart, bufferSize, -1) }; - const COORD secondToLastCharacterPos{ documentEndInclusive.X - 1, documentEndInclusive.Y }; + const til::point lastLineStart{ static_cast(bufferSize.left), documentEndInclusive.y }; + const til::point secondToLastLinePos{ point_offset_by_line(til::point{ lastLineStart }, bufferSize, -1) }; + const til::point secondToLastCharacterPos{ documentEndInclusive.x - 1, documentEndInclusive.y }; // Iterate over each TextUnit. If we don't support // the given TextUnit, we're supposed to fallback @@ -1368,22 +1368,22 @@ class UiaTextRangeTests Log::Comment(NoThrowString().Format(L"Forward by %s", toString(textUnit))); // Create an UTR at EndExclusive - const auto utrEnd{ atDocumentEnd ? documentEndExclusive : static_cast(endExclusive) }; + const auto utrEnd{ atDocumentEnd ? documentEndExclusive : til::point{ endExclusive } }; if (degenerate) { // UTR: (exclusive, exclusive) range - const auto utrStart{ atDocumentEnd ? documentEndExclusive : static_cast(endExclusive) }; - THROW_IF_FAILED(Microsoft::WRL::MakeAndInitialize(&utr, _pUiaData, &_dummyProvider, utrStart, utrEnd)); + const auto utrStart{ atDocumentEnd ? documentEndExclusive : endExclusive }; + THROW_IF_FAILED(Microsoft::WRL::MakeAndInitialize(&utr, _pUiaData, &_dummyProvider, utrStart.to_win32_coord(), utrEnd.to_win32_coord())); } else { // UTR: (inclusive, exclusive) range - const auto utrStart{ atDocumentEnd ? documentEndInclusive : static_cast(endInclusive) }; - THROW_IF_FAILED(Microsoft::WRL::MakeAndInitialize(&utr, _pUiaData, &_dummyProvider, utrStart, utrEnd)); + const auto utrStart{ atDocumentEnd ? documentEndInclusive : endInclusive }; + THROW_IF_FAILED(Microsoft::WRL::MakeAndInitialize(&utr, _pUiaData, &_dummyProvider, utrStart.to_win32_coord(), utrEnd.to_win32_coord())); } THROW_IF_FAILED(utr->Move(textUnit, 1, &moveAmt)); - VERIFY_ARE_EQUAL(documentEndExclusive, utr->_end); + VERIFY_ARE_EQUAL(documentEndExclusive.to_win32_coord(), utr->_end); VERIFY_ARE_EQUAL(0, moveAmt); // Verify expansion works properly @@ -1391,37 +1391,37 @@ class UiaTextRangeTests THROW_IF_FAILED(utr->ExpandToEnclosingUnit(textUnit)); if (textUnit <= TextUnit::TextUnit_Character) { - VERIFY_ARE_EQUAL(documentEndInclusive, utr->_start); - VERIFY_ARE_EQUAL(documentEndExclusive, utr->_end); + VERIFY_ARE_EQUAL(documentEndInclusive.to_win32_coord(), utr->_start); + VERIFY_ARE_EQUAL(documentEndExclusive.to_win32_coord(), utr->_end); } else if (textUnit <= TextUnit::TextUnit_Word) { - VERIFY_ARE_EQUAL(writeTarget, til::point{ utr->_start }); - VERIFY_ARE_EQUAL(documentEndExclusive, utr->_end); + VERIFY_ARE_EQUAL(writeTarget.to_win32_coord(), utr->_start); + VERIFY_ARE_EQUAL(documentEndExclusive.to_win32_coord(), utr->_end); } else if (textUnit <= TextUnit::TextUnit_Line) { - VERIFY_ARE_EQUAL(lastLineStart, utr->_start); - VERIFY_ARE_EQUAL(documentEndExclusive, utr->_end); + VERIFY_ARE_EQUAL(lastLineStart.to_win32_coord(), utr->_start); + VERIFY_ARE_EQUAL(documentEndExclusive.to_win32_coord(), utr->_end); } else // textUnit <= TextUnit::TextUnit_Document: { - VERIFY_ARE_EQUAL(origin, til::point{ utr->_start }); - VERIFY_ARE_EQUAL(documentEndExclusive, utr->_end); + VERIFY_ARE_EQUAL(origin.to_win32_coord(), utr->_start); + VERIFY_ARE_EQUAL(documentEndExclusive.to_win32_coord(), utr->_end); } // reset the UTR if (degenerate) { // UTR: (exclusive, exclusive) range - const auto utrStart{ atDocumentEnd ? documentEndExclusive : static_cast(endExclusive) }; - THROW_IF_FAILED(Microsoft::WRL::MakeAndInitialize(&utr, _pUiaData, &_dummyProvider, utrStart, utrEnd)); + const auto utrStart{ atDocumentEnd ? documentEndExclusive : endExclusive }; + THROW_IF_FAILED(Microsoft::WRL::MakeAndInitialize(&utr, _pUiaData, &_dummyProvider, utrStart.to_win32_coord(), utrEnd.to_win32_coord())); } else { // UTR: (inclusive, exclusive) range - const auto utrStart{ atDocumentEnd ? documentEndInclusive : static_cast(endInclusive) }; - THROW_IF_FAILED(Microsoft::WRL::MakeAndInitialize(&utr, _pUiaData, &_dummyProvider, utrStart, utrEnd)); + const auto utrStart{ atDocumentEnd ? documentEndInclusive : endInclusive }; + THROW_IF_FAILED(Microsoft::WRL::MakeAndInitialize(&utr, _pUiaData, &_dummyProvider, utrStart.to_win32_coord(), utrEnd.to_win32_coord())); } // Verify that moving backwards still works properly @@ -1435,8 +1435,8 @@ class UiaTextRangeTests // - degenerate --> it moves with _start to stay degenerate // - !degenerate --> it excludes the last char, to select the second to last char VERIFY_ARE_EQUAL(-1, moveAmt); - VERIFY_ARE_EQUAL(degenerate || !atDocumentEnd ? documentEndInclusive : secondToLastCharacterPos, utr->_start); - VERIFY_ARE_EQUAL(documentEndInclusive, utr->_end); + VERIFY_ARE_EQUAL(degenerate || !atDocumentEnd ? documentEndInclusive : secondToLastCharacterPos, til::point{ utr->_start }); + VERIFY_ARE_EQUAL(documentEndInclusive, til::point{ utr->_end }); } else if (textUnit <= TextUnit::TextUnit_Word) { @@ -1448,7 +1448,7 @@ class UiaTextRangeTests { VERIFY_ARE_EQUAL(-1, moveAmt); VERIFY_ARE_EQUAL(degenerate || !atDocumentEnd ? til::point{ lastLineStart } : secondToLastLinePos, til::point{ utr->_start }); - VERIFY_ARE_EQUAL(lastLineStart, utr->_end); + VERIFY_ARE_EQUAL(lastLineStart, til::point{ utr->_end }); } else // textUnit <= TextUnit::TextUnit_Document: { @@ -1464,11 +1464,11 @@ class UiaTextRangeTests const auto originExclusive{ point_offset_by_char(origin, bufferSize, 1) }; - _pTextBuffer->Write({ L"My name is Carlos" }, origin); + _pTextBuffer->Write({ L"My name is Carlos" }, origin.to_win32_coord()); // Create degenerate UTR at origin Microsoft::WRL::ComPtr utr; - THROW_IF_FAILED(Microsoft::WRL::MakeAndInitialize(&utr, _pUiaData, &_dummyProvider, origin, origin)); + THROW_IF_FAILED(Microsoft::WRL::MakeAndInitialize(&utr, _pUiaData, &_dummyProvider, origin.to_win32_coord(), origin.to_win32_coord())); // move forward by a word int moveAmt; @@ -1503,17 +1503,17 @@ class UiaTextRangeTests const auto viewportSize{ _pUiaData->GetViewport() }; const std::vector testData{ - { L"Origin", gsl::narrow(bufferSize.top()) }, - { L"ViewportHeight From Top - 1", base::ClampedNumeric(bufferSize.top()) + viewportSize.Height() - 1 }, - { L"ViewportHeight From Top", base::ClampedNumeric(bufferSize.top()) + viewportSize.Height() }, - { L"ViewportHeight From Top + 1", base::ClampedNumeric(bufferSize.top()) + viewportSize.Height() + 1 }, - { L"ViewportHeight From Bottom - 1", base::ClampedNumeric(bufferSize.bottom()) - viewportSize.Height() - 2 }, - { L"ViewportHeight From Bottom", base::ClampedNumeric(bufferSize.bottom()) - viewportSize.Height() - 1 }, - { L"ViewportHeight From Bottom + 1", base::ClampedNumeric(bufferSize.bottom()) - viewportSize.Height() + 1 }, + { L"Origin", gsl::narrow(bufferSize.top) }, + { L"ViewportHeight From Top - 1", base::ClampedNumeric(bufferSize.top) + viewportSize.Height() - 1 }, + { L"ViewportHeight From Top", base::ClampedNumeric(bufferSize.top) + viewportSize.Height() }, + { L"ViewportHeight From Top + 1", base::ClampedNumeric(bufferSize.top) + viewportSize.Height() + 1 }, + { L"ViewportHeight From Bottom - 1", base::ClampedNumeric(bufferSize.bottom) - viewportSize.Height() - 2 }, + { L"ViewportHeight From Bottom", base::ClampedNumeric(bufferSize.bottom) - viewportSize.Height() - 1 }, + { L"ViewportHeight From Bottom + 1", base::ClampedNumeric(bufferSize.bottom) - viewportSize.Height() + 1 }, // GH#7839: ExclusiveEnd is a non-existent space, // so scrolling to it when !alignToTop used to crash - { L"Exclusive End", gsl::narrow(bufferSize.bottom()) } + { L"Exclusive End", gsl::narrow(bufferSize.bottom) } }; BEGIN_TEST_METHOD_PROPERTIES() @@ -1527,8 +1527,8 @@ class UiaTextRangeTests for (const auto test : testData) { Log::Comment(test.comment.c_str()); - const til::point pos{ bufferSize.left(), test.yPos }; - THROW_IF_FAILED(Microsoft::WRL::MakeAndInitialize(&utr, _pUiaData, &_dummyProvider, pos, pos)); + const til::point pos{ bufferSize.left, test.yPos }; + THROW_IF_FAILED(Microsoft::WRL::MakeAndInitialize(&utr, _pUiaData, &_dummyProvider, pos.to_win32_coord(), pos.to_win32_coord())); VERIFY_SUCCEEDED(utr->ScrollIntoView(alignToTop)); } } @@ -1856,7 +1856,7 @@ class UiaTextRangeTests const auto secondChar{ point_offset_by_char(origin, bufferSize, 2) }; const auto fifthChar{ point_offset_by_char(origin, bufferSize, 5) }; const auto sixthChar{ point_offset_by_char(origin, bufferSize, 6) }; - const til::point documentEnd{ bufferSize.left(), (bufferSize.height() / 2) + 1 }; + const til::point documentEnd{ bufferSize.left, (bufferSize.height() / 2) + 1 }; // Populate buffer // Split the line into 5 segments alternating between "X" and whitespace @@ -1868,9 +1868,9 @@ class UiaTextRangeTests // |_______________| { short i = 0; - auto iter{ _pTextBuffer->GetCellDataAt(origin) }; + auto iter{ _pTextBuffer->GetCellDataAt(origin.to_win32_coord()) }; const auto segment{ bufferSize.width() / 5 }; - while (iter.Pos() != documentEnd) + while (iter.Pos() != documentEnd.to_win32_coord()) { bool fill{ true }; if (i % segment == 0) @@ -1936,12 +1936,12 @@ class UiaTextRangeTests // +------------------------------+ { short i = 0; - auto iter{ _pTextBuffer->GetCellDataAt(bufferSize.origin()) }; + auto iter{ _pTextBuffer->GetCellDataAt(bufferSize.origin().to_win32_coord()) }; const auto segment{ bufferSize.width() / 10 }; bool fill{ true }; - while (iter.Pos() != docEnd) + while (iter.Pos() != docEnd.to_win32_coord()) { - if (iter.Pos().X == bufferSize.left()) + if (iter.Pos().X == bufferSize.left) { fill = true; } @@ -1977,7 +1977,7 @@ class UiaTextRangeTests { Microsoft::WRL::ComPtr utr; int amountMoved; - THROW_IF_FAILED(Microsoft::WRL::MakeAndInitialize(&utr, _pUiaData, &_dummyProvider, testCase.input.start, testCase.input.end)); + THROW_IF_FAILED(Microsoft::WRL::MakeAndInitialize(&utr, _pUiaData, &_dummyProvider, testCase.input.start.to_win32_coord(), testCase.input.end.to_win32_coord())); THROW_IF_FAILED(utr->Move(testCase.input.unit, testCase.input.moveAmount, &amountMoved)); VERIFY_ARE_EQUAL(testCase.expected.moveAmount, amountMoved); diff --git a/src/renderer/atlas/AtlasEngine.api.cpp b/src/renderer/atlas/AtlasEngine.api.cpp index 95c6a9a5ff..ca78fd75e0 100644 --- a/src/renderer/atlas/AtlasEngine.api.cpp +++ b/src/renderer/atlas/AtlasEngine.api.cpp @@ -232,7 +232,7 @@ try } CATCH_RETURN() -[[nodiscard]] HRESULT AtlasEngine::GetDirtyArea(gsl::span& area) noexcept +[[nodiscard]] HRESULT AtlasEngine::GetDirtyArea(gsl::span& area) noexcept { area = gsl::span{ &_api.dirtyRect, 1 }; return S_OK; diff --git a/src/renderer/atlas/AtlasEngine.cpp b/src/renderer/atlas/AtlasEngine.cpp index ac187dadc7..e294c61451 100644 --- a/src/renderer/atlas/AtlasEngine.cpp +++ b/src/renderer/atlas/AtlasEngine.cpp @@ -377,11 +377,11 @@ try } } - _api.dirtyRect = til::rectangle{ - static_cast(0), - static_cast(_api.invalidatedRows.x), - static_cast(_api.cellCount.x), - static_cast(_api.invalidatedRows.y), + _api.dirtyRect = til::rect{ + 0, + _api.invalidatedRows.x, + _api.cellCount.x, + _api.invalidatedRows.y, }; return S_OK; diff --git a/src/renderer/atlas/AtlasEngine.h b/src/renderer/atlas/AtlasEngine.h index 8bae374362..8247e4c8cf 100644 --- a/src/renderer/atlas/AtlasEngine.h +++ b/src/renderer/atlas/AtlasEngine.h @@ -49,7 +49,7 @@ namespace Microsoft::Console::Render [[nodiscard]] HRESULT UpdateDpi(int iDpi) noexcept override; [[nodiscard]] HRESULT UpdateViewport(SMALL_RECT srNewViewport) noexcept override; [[nodiscard]] HRESULT GetProposedFont(const FontInfoDesired& FontInfoDesired, _Out_ FontInfo& FontInfo, int iDpi) noexcept override; - [[nodiscard]] HRESULT GetDirtyArea(gsl::span& area) noexcept override; + [[nodiscard]] HRESULT GetDirtyArea(gsl::span& area) noexcept override; [[nodiscard]] HRESULT GetFontSize(_Out_ COORD* pFontSize) noexcept override; [[nodiscard]] HRESULT IsGlyphWideByFont(std::wstring_view glyph, _Out_ bool* pResult) noexcept override; [[nodiscard]] HRESULT UpdateTitle(std::wstring_view newTitle) noexcept override; @@ -741,7 +741,7 @@ namespace Microsoft::Console::Render u32 selectionColor = 0x7fffffff; // dirtyRect is a computed value based on invalidatedRows. - til::rectangle dirtyRect; + til::rect dirtyRect; // These "invalidation" fields are reset in EndPaint() u16r invalidatedCursorArea = invalidatedAreaNone; u16x2 invalidatedRows = invalidatedRowsNone; // x is treated as "top" and y as "bottom" diff --git a/src/renderer/base/FontResource.cpp b/src/renderer/base/FontResource.cpp index 38263033a2..465317e9ff 100644 --- a/src/renderer/base/FontResource.cpp +++ b/src/renderer/base/FontResource.cpp @@ -107,8 +107,8 @@ FontResource::operator HFONT() void FontResource::_regenerateFont() { - const auto targetWidth = _targetSize.width(); - const auto targetHeight = _targetSize.height(); + const auto targetWidth = _targetSize.narrow_width(); + const auto targetHeight = _targetSize.narrow_height(); const auto charSizeInBytes = (targetWidth + 7) / 8 * targetHeight; const DWORD fontBitmapSize = charSizeInBytes * CHAR_COUNT; @@ -171,10 +171,10 @@ void FontResource::_regenerateFont() void FontResource::_resizeBitPattern(gsl::span targetBuffer) { - auto sourceWidth = _sourceSize.width(); - auto targetWidth = _targetSize.width(); - const auto sourceHeight = _sourceSize.height(); - const auto targetHeight = _targetSize.height(); + auto sourceWidth = _sourceSize.width; + auto targetWidth = _targetSize.width; + const auto sourceHeight = _sourceSize.height; + const auto targetHeight = _targetSize.height; // If the text in the font is not perfectly centered, the _centeringHint // gives us the offset needed to correct that misalignment. So to ensure @@ -214,7 +214,7 @@ void FontResource::_resizeBitPattern(gsl::span targetBuffer) // Once we've calculated the scaling increments, taking the centering hint // into account, we reset the target width back to its original value. - targetWidth = _targetSize.width(); + targetWidth = _targetSize.width; auto targetBufferPointer = targetBuffer.begin(); for (auto ch = 0; ch < CHAR_COUNT; ch++) diff --git a/src/renderer/base/renderer.cpp b/src/renderer/base/renderer.cpp index 26ba9c3aa1..95dd7e8ae1 100644 --- a/src/renderer/base/renderer.cpp +++ b/src/renderer/base/renderer.cpp @@ -354,17 +354,17 @@ void Renderer::TriggerSelection() // Restrict all previous selection rectangles to inside the current viewport bounds for (auto& sr : _previousSelection) { - // Make the exclusive SMALL_RECT into a til::rectangle. - til::rectangle rc{ Viewport::FromExclusive(sr).ToInclusive() }; + // Make the exclusive SMALL_RECT into a til::rect. + til::rect rc{ Viewport::FromExclusive(sr).ToInclusive() }; // Make a viewport representing the coordinates that are currently presentable. - const til::rectangle viewport{ til::size{ _pData->GetViewport().Dimensions() } }; + const til::rect viewport{ til::size{ _pData->GetViewport().Dimensions() } }; // Intersect them so we only invalidate things that are still visible. rc &= viewport; // Convert back into the exclusive SMALL_RECT and store in the vector. - sr = Viewport::FromInclusive(rc).ToExclusive(); + sr = Viewport::FromInclusive(rc.to_small_rect()).ToExclusive(); } FOREACH_ENGINE(pEngine) @@ -408,7 +408,7 @@ bool Renderer::_CheckViewportAndScroll() LOG_IF_FAILED(engine->InvalidateScroll(&coordDelta)); } - _ScrollPreviousSelection(coordDelta); + _ScrollPreviousSelection(til::point{ coordDelta }); return true; } @@ -443,7 +443,7 @@ void Renderer::TriggerScroll(const COORD* const pcoordDelta) LOG_IF_FAILED(pEngine->InvalidateScroll(pcoordDelta)); } - _ScrollPreviousSelection(*pcoordDelta); + _ScrollPreviousSelection(til::point{ *pcoordDelta }); _NotifyPaintFrame(); } @@ -665,7 +665,7 @@ void Renderer::_PaintBufferOutput(_In_ IRenderEngine* const pEngine) // 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. - gsl::span dirtyAreas; + gsl::span dirtyAreas; LOG_IF_FAILED(pEngine->GetDirtyArea(dirtyAreas)); // This is to make sure any transforms are reset when this paint is finished. @@ -676,12 +676,12 @@ void Renderer::_PaintBufferOutput(_In_ IRenderEngine* const pEngine) for (const auto& dirtyRect : dirtyAreas) { // Shortcut: don't bother redrawing if the width is 0. - if (dirtyRect.left() == dirtyRect.right()) + if (dirtyRect.left == dirtyRect.right) { continue; } - auto dirty = Viewport::FromInclusive(dirtyRect); + auto dirty = Viewport::FromInclusive(dirtyRect.to_small_rect()); // Shift the origin of the dirty region to match the underlying buffer so we can // compare the two regions directly for intersection. @@ -805,7 +805,7 @@ void Renderer::_PaintBufferOutputHelper(_In_ IRenderEngine* const pEngine, // We also accumulate clusters according to regex patterns do { - COORD thisPoint{ screenPoint.X + gsl::narrow(cols), screenPoint.Y }; + COORD thisPoint{ gsl::narrow(screenPoint.X + cols), screenPoint.Y }; const auto thisPointPatterns = _pData->GetPatternId(thisPoint); const auto thisUsingSoftFont = s_IsSoftFontChar(it->Chars(), _firstSoftFontChar, _lastSoftFontChar); const auto changedPatternOrFont = patternIds != thisPointPatterns || usingSoftFont != thisUsingSoftFont; @@ -1113,12 +1113,13 @@ 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. Viewport viewConv = Viewport::FromInclusive(srCaView); - gsl::span dirtyAreas; + gsl::span dirtyAreas; LOG_IF_FAILED(engine.GetDirtyArea(dirtyAreas)); - for (SMALL_RECT srDirty : dirtyAreas) + for (const auto& rect : dirtyAreas) { // Dirty is an inclusive rectangle, but oddly enough the IME was an exclusive one, so correct it. + auto srDirty = rect.to_small_rect(); srDirty.Bottom++; srDirty.Right++; @@ -1173,7 +1174,7 @@ void Renderer::_PaintSelection(_In_ IRenderEngine* const pEngine) { try { - gsl::span dirtyAreas; + gsl::span dirtyAreas; LOG_IF_FAILED(pEngine->GetDirtyArea(dirtyAreas)); // Get selection rectangles @@ -1185,7 +1186,7 @@ void Renderer::_PaintSelection(_In_ IRenderEngine* const pEngine) // Make a copy as `TrimToViewport` will manipulate it and // can destroy it for the next dirtyRect to test against. auto rectCopy = rect; - Viewport dirtyView = Viewport::FromInclusive(dirtyRect); + Viewport dirtyView = Viewport::FromInclusive(dirtyRect.to_small_rect()); if (dirtyView.TrimToViewport(&rectCopy)) { LOG_IF_FAILED(pEngine->PaintSelection(rectCopy)); @@ -1280,13 +1281,13 @@ void Renderer::_ScrollPreviousSelection(const til::point delta) for (auto& sr : _previousSelection) { // Get a rectangle representing this piece of the selection. - til::rectangle rc = Viewport::FromExclusive(sr).ToInclusive(); + til::rect rc{ Viewport::FromExclusive(sr).ToInclusive() }; // Offset the entire existing rectangle by the delta. rc += delta; // Store it back into the vector. - sr = Viewport::FromInclusive(rc).ToExclusive(); + sr = Viewport::FromInclusive(rc.to_small_rect()).ToExclusive(); } } } diff --git a/src/renderer/dx/CustomTextLayout.cpp b/src/renderer/dx/CustomTextLayout.cpp index a0c0804c42..0f75c46b1f 100644 --- a/src/renderer/dx/CustomTextLayout.cpp +++ b/src/renderer/dx/CustomTextLayout.cpp @@ -27,7 +27,7 @@ CustomTextLayout::CustomTextLayout(gsl::not_null const fontRe _runs{}, _breakpoints{}, _runIndex{ 0 }, - _width{ gsl::narrow_cast(fontRenderData->GlyphCell().width()) }, + _width{ gsl::narrow_cast(fontRenderData->GlyphCell().width) }, _isEntireTextSimple{ false } { _localeName.resize(gsl::narrow_cast(fontRenderData->DefaultTextFormat()->GetLocaleNameLength()) + 1); // +1 for null diff --git a/src/renderer/dx/CustomTextRenderer.cpp b/src/renderer/dx/CustomTextRenderer.cpp index a75f14bc2f..b4b9fad108 100644 --- a/src/renderer/dx/CustomTextRenderer.cpp +++ b/src/renderer/dx/CustomTextRenderer.cpp @@ -273,18 +273,17 @@ try // TODO GH#6338: Add support for `"cursorTextColor": null` for letting the // cursor draw on top again. - // **MATH** PHASE - const til::size glyphSize{ til::math::flooring, - drawingContext.cellSize.width, - drawingContext.cellSize.height }; - // Create rectangular block representing where the cursor can fill. - D2D1_RECT_F rect = til::rectangle{ til::point{ options.coordCursor } }.scale_up(glyphSize); + D2D1_RECT_F rect; + rect.left = options.coordCursor.X * drawingContext.cellSize.width; + rect.top = options.coordCursor.Y * drawingContext.cellSize.height; + rect.right = rect.left + drawingContext.cellSize.width; + rect.bottom = rect.top + drawingContext.cellSize.height; // If we're double-width, make it one extra glyph wider if (options.fIsDoubleWidth) { - rect.right += glyphSize.width(); + rect.right += drawingContext.cellSize.width; } // If the cursor isn't within the bounds of this current run of text, do nothing. @@ -303,7 +302,7 @@ try { // Enforce min/max cursor height ULONG ulHeight = std::clamp(options.ulCursorHeightPercent, MinCursorHeightPercent, MaxCursorHeightPercent); - ulHeight = (glyphSize.height() * ulHeight) / 100; + ulHeight = gsl::narrow_cast(drawingContext.cellSize.height * ulHeight) / 100; ulHeight = std::max(ulHeight, MinCursorHeightPixels); // No smaller than 1px rect.top = rect.bottom - ulHeight; diff --git a/src/renderer/dx/DxFontRenderData.cpp b/src/renderer/dx/DxFontRenderData.cpp index 96c44ccb69..cb1acf3457 100644 --- a/src/renderer/dx/DxFontRenderData.cpp +++ b/src/renderer/dx/DxFontRenderData.cpp @@ -114,7 +114,7 @@ DxFontRenderData::DxFontRenderData(::Microsoft::WRL::ComPtr dwr if (!_boxDrawingEffect) { // Calculate and cache the box effect for the base font. Scale is 1.0f because the base font is exactly the scale we want already. - THROW_IF_FAILED(s_CalculateBoxEffect(DefaultTextFormat().Get(), _glyphCell.width(), DefaultFontFace().Get(), 1.0f, &_boxDrawingEffect)); + THROW_IF_FAILED(s_CalculateBoxEffect(DefaultTextFormat().Get(), _glyphCell.width, DefaultFontFace().Get(), 1.0f, &_boxDrawingEffect)); } return _boxDrawingEffect; @@ -738,7 +738,7 @@ void DxFontRenderData::_BuildFontRenderData(const FontInfoDesired& desired, Font // - 12 ppi font * (96 dpi / 96 dpi) * (96 dpi / 72 points per inch) = 16 pixels tall font for 100% display (96 dpi is 100%) // - 12 ppi font * (144 dpi / 96 dpi) * (96 dpi / 72 points per inch) = 24 pixels tall font for 150% display (144 dpi is 150%) // - 12 ppi font * (192 dpi / 96 dpi) * (96 dpi / 72 points per inch) = 32 pixels tall font for 200% display (192 dpi is 200%) - float heightDesired = static_cast(desired.GetEngineSize().Y) * static_cast(USER_DEFAULT_SCREEN_DPI) / POINTS_PER_INCH; + float heightDesired = desired.GetEngineSize().Y * USER_DEFAULT_SCREEN_DPI / POINTS_PER_INCH; // The advance is the number of pixels left-to-right (X dimension) for the given font. // We're finding a proportional factor here with the design units in "ems", not an actual pixel measurement. @@ -891,7 +891,7 @@ void DxFontRenderData::_BuildFontRenderData(const FontInfoDesired& desired, Font _lineMetrics = lineMetrics; - _glyphCell = actual.GetSize(); + _glyphCell = til::size{ actual.GetSize() }; } Microsoft::WRL::ComPtr DxFontRenderData::_BuildTextFormat(const DxFontInfo& fontInfo, const std::wstring_view localeName) diff --git a/src/renderer/dx/DxRenderer.cpp b/src/renderer/dx/DxRenderer.cpp index aae67a7bef..aeb23fde44 100644 --- a/src/renderer/dx/DxRenderer.cpp +++ b/src/renderer/dx/DxRenderer.cpp @@ -344,8 +344,8 @@ HRESULT DxEngine::_SetupTerminalEffects() // Setup the viewport. D3D11_VIEWPORT vp; - vp.Width = _displaySizePixels.width(); - vp.Height = _displaySizePixels.height(); + vp.Width = static_cast(_displaySizePixels.width); + vp.Height = static_cast(_displaySizePixels.height); vp.MinDepth = 0.0f; vp.MaxDepth = 1.0f; vp.TopLeftX = 0; @@ -463,8 +463,8 @@ void DxEngine::_ComputePixelShaderSettings() noexcept _pixelShaderSettings.Scale = _scale; // Set the display resolution - const float w = 1.0f * _displaySizePixels.width(); - const float h = 1.0f * _displaySizePixels.height(); + const float w = static_cast(_displaySizePixels.width); + const float h = static_cast(_displaySizePixels.height); _pixelShaderSettings.Resolution = XMFLOAT2{ w, h }; // Set the background @@ -653,8 +653,8 @@ try RETURN_IF_FAILED(_dxgiFactory2.As(&_dxgiFactoryMedia)); // Use the given target size for compositions. - _swapChainDesc.Width = _displaySizePixels.width(); - _swapChainDesc.Height = _displaySizePixels.height(); + _swapChainDesc.Width = _displaySizePixels.narrow_width(); + _swapChainDesc.Height = _displaySizePixels.narrow_height(); // We're doing advanced composition pretty much for the purpose of pretty alpha, so turn it on. _swapChainDesc.AlphaMode = DXGI_ALPHA_MODE_PREMULTIPLIED; @@ -942,8 +942,8 @@ try return _dwriteFactory->CreateTextLayout(string, gsl::narrow(stringLength), _fontRenderData->DefaultTextFormat().Get(), - _displaySizePixels.width(), - _fontRenderData->GlyphCell().height() != 0 ? _fontRenderData->GlyphCell().height() : _displaySizePixels.height(), + static_cast(_displaySizePixels.width), + _fontRenderData->GlyphCell().height != 0 ? _fontRenderData->GlyphCell().narrow_height() : _displaySizePixels.narrow_height(), ppTextLayout); } CATCH_RETURN() @@ -965,7 +965,7 @@ CATCH_RETURN() [[nodiscard]] HRESULT DxEngine::SetWindowSize(const SIZE Pixels) noexcept try { - _sizeTarget = Pixels; + _sizeTarget = til::size{ Pixels }; return S_OK; } CATCH_RETURN(); @@ -1006,7 +1006,7 @@ try { // Enable shader effects if the path isn't empty. Otherwise leave it untouched. _terminalEffectsEnabled = value.empty() ? _terminalEffectsEnabled : true; - _pixelShaderPath = { value }; + _pixelShaderPath = std::wstring{ value }; _recreateDeviceRequested = true; LOG_IF_FAILED(InvalidateAll()); } @@ -1058,17 +1058,17 @@ HANDLE DxEngine::GetSwapChainHandle() noexcept return _swapChainHandle.get(); } -void DxEngine::_InvalidateRectangle(const til::rectangle& rc) +void DxEngine::_InvalidateRectangle(const til::rect& rc) { const auto size = _invalidMap.size(); - const auto topLeft = til::point{ 0, std::min(size.height(), rc.top()) }; - const auto bottomRight = til::point{ size.width(), std::min(size.height(), rc.bottom()) }; - _invalidMap.set({ topLeft, bottomRight }); + const auto topLeft = til::point{ 0, std::min(size.height, rc.top) }; + const auto bottomRight = til::point{ size.width, std::min(size.height, rc.bottom) }; + _invalidMap.set(til::rect{ topLeft, bottomRight }); } bool DxEngine::_IsAllInvalid() const noexcept { - return std::llabs(_invalidScroll.y()) >= _invalidMap.size().height(); + return std::abs(_invalidScroll.y) >= _invalidMap.size().height; } // Routine Description: @@ -1084,7 +1084,7 @@ try if (!_allInvalid) { - _InvalidateRectangle(Viewport::FromExclusive(*psrRegion).ToInclusive()); + _InvalidateRectangle(til::rect{ Viewport::FromExclusive(*psrRegion).ToInclusive() }); } return S_OK; @@ -1117,7 +1117,7 @@ try { // Dirty client is in pixels. Use divide specialization against glyph factor to make conversion // to cells. - _InvalidateRectangle(til::rectangle{ *prcDirtyClient }.scale_down(_fontRenderData->GlyphCell())); + _InvalidateRectangle(til::rect{ *prcDirtyClient }.scale_down(_fontRenderData->GlyphCell())); } return S_OK; @@ -1159,7 +1159,7 @@ try if (!_allInvalid) { - if (deltaCells != til::point{ 0, 0 }) + if (deltaCells != til::point{}) { // Shift the contents of the map and fill in revealed area. _invalidMap.translate(deltaCells, true); @@ -1226,7 +1226,7 @@ CATCH_RETURN(); RECT clientRect = { 0 }; LOG_IF_WIN32_BOOL_FALSE(GetClientRect(_hwndTarget, &clientRect)); - return til::rectangle{ clientRect }.size(); + return til::rect{ clientRect }.size(); } case SwapChainMode::ForComposition: { @@ -1323,7 +1323,7 @@ try _d2dBitmap.Reset(); // Change the buffer size and recreate the render target (and surface) - RETURN_IF_FAILED(_dxgiSwapChain->ResizeBuffers(2, clientSize.width(), clientSize.height(), _swapChainDesc.Format, _swapChainDesc.Flags)); + RETURN_IF_FAILED(_dxgiSwapChain->ResizeBuffers(2, clientSize.narrow_width(), clientSize.narrow_height(), _swapChainDesc.Format, _swapChainDesc.Flags)); RETURN_IF_FAILED(_PrepareRenderTarget()); // OK we made it past the parts that can cause errors. We can release our failure handler. @@ -1354,7 +1354,7 @@ try _ShouldForceGrayscaleAA(), _dwriteFactory.Get(), spacing, - glyphCellSize, + glyphCellSize.to_d2d_size(), _d2dDeviceContext->GetSize(), std::nullopt, D2D1_DRAW_TEXT_OPTIONS_ENABLE_COLOR_FONT); @@ -1391,11 +1391,11 @@ try { if (_invalidScroll != til::point{ 0, 0 }) { - // Copy `til::rectangles` into RECT map. + // Copy `til::rects` into RECT map. _presentDirty.assign(_invalidMap.begin(), _invalidMap.end()); // Scale all dirty rectangles into pixels - std::transform(_presentDirty.begin(), _presentDirty.end(), _presentDirty.begin(), [&](til::rectangle rc) { + std::transform(_presentDirty.begin(), _presentDirty.end(), _presentDirty.begin(), [&](const til::rect& rc) { return rc.scale_up(_fontRenderData->GlyphCell()); }); @@ -1403,20 +1403,25 @@ try const auto scrollPixels = (_invalidScroll * _fontRenderData->GlyphCell()); // The scroll rect is the entire field of cells, but in pixels. - til::rectangle scrollArea{ _invalidMap.size() * _fontRenderData->GlyphCell() }; + til::rect scrollArea{ _invalidMap.size() * _fontRenderData->GlyphCell() }; // Reduce the size of the rectangle by the scroll. scrollArea -= til::size{} - scrollPixels; // Assign the area to the present storage - _presentScroll = scrollArea; + _presentScroll = scrollArea.to_win32_rect(); // Pass the offset. - _presentOffset = scrollPixels; + _presentOffset = scrollPixels.to_win32_point(); // Now fill up the parameters structure from the member variables. _presentParams.DirtyRectsCount = gsl::narrow(_presentDirty.size()); - _presentParams.pDirtyRects = _presentDirty.data(); + + // It's not nice to use reinterpret_cast between til::rect and RECT, + // but to be honest... it does save a ton of type juggling. + static_assert(sizeof(decltype(_presentDirty)::value_type) == sizeof(RECT)); +#pragma warning(suppress : 26490) // Don't use reinterpret_cast (type.1). + _presentParams.pDirtyRects = reinterpret_cast(_presentDirty.data()); _presentParams.pScrollOffset = &_presentOffset; _presentParams.pScrollRect = &_presentScroll; @@ -1646,7 +1651,7 @@ try // Runs are counts of cells. // Use a transform by the size of one cell to convert cells-to-pixels // as we clear. - _d2dDeviceContext->SetTransform(D2D1::Matrix3x2F::Scale(_fontRenderData->GlyphCell())); + _d2dDeviceContext->SetTransform(D2D1::Matrix3x2F::Scale(_fontRenderData->GlyphCell().to_d2d_size())); for (const auto& rect : _invalidMap.runs()) { // Use aliased. @@ -1654,7 +1659,7 @@ try // the edges are cut nice and sharp (not blended by anti-aliasing). // For performance reasons, it takes a lot less work to not // do anti-alias blending. - _d2dDeviceContext->PushAxisAlignedClip(rect, D2D1_ANTIALIAS_MODE_ALIASED); + _d2dDeviceContext->PushAxisAlignedClip(rect.to_d2d_rect(), D2D1_ANTIALIAS_MODE_ALIASED); _d2dDeviceContext->Clear(nothing); _d2dDeviceContext->PopAxisAlignedClip(); } @@ -1680,7 +1685,7 @@ CATCH_RETURN() try { // Calculate positioning of our origin. - const D2D1_POINT_2F origin = til::point{ coord } * _fontRenderData->GlyphCell(); + const D2D1_POINT_2F origin = (til::point{ coord } * _fontRenderData->GlyphCell()).to_d2d_point(); // Create the text layout RETURN_IF_FAILED(_customLayout->Reset()); @@ -1714,7 +1719,7 @@ try _d2dBrushForeground->SetColor(_ColorFFromColorRef(color)); - const D2D1_SIZE_F font = _fontRenderData->GlyphCell(); + const D2D1_SIZE_F font = _fontRenderData->GlyphCell().to_d2d_size(); const D2D_POINT_2F target = { coordTarget.X * font.width, coordTarget.Y * font.height }; const auto fullRunWidth = font.width * gsl::narrow_cast(cchLine); @@ -1833,7 +1838,7 @@ try _d2dBrushForeground->SetColor(_selectionBackground); const auto resetColorOnExit = wil::scope_exit([&]() noexcept { _d2dBrushForeground->SetColor(existingColor); }); - const D2D1_RECT_F draw = til::rectangle{ Viewport::FromExclusive(rect).ToInclusive() }.scale_up(_fontRenderData->GlyphCell()); + const D2D1_RECT_F draw = til::rect{ Viewport::FromExclusive(rect).ToInclusive() }.scale_up(_fontRenderData->GlyphCell()).to_d2d_rect(); _d2dDeviceContext->FillRectangle(draw, _d2dBrushForeground.Get()); @@ -2018,16 +2023,16 @@ CATCH_RETURN(); [[nodiscard]] Viewport DxEngine::GetViewportInCharacters(const Viewport& viewInPixels) const noexcept { - const short widthInChars = base::saturated_cast(viewInPixels.Width() / _fontRenderData->GlyphCell().width()); - const short heightInChars = base::saturated_cast(viewInPixels.Height() / _fontRenderData->GlyphCell().height()); + const short widthInChars = base::saturated_cast(viewInPixels.Width() / _fontRenderData->GlyphCell().width); + const short heightInChars = base::saturated_cast(viewInPixels.Height() / _fontRenderData->GlyphCell().height); return Viewport::FromDimensions(viewInPixels.Origin(), { widthInChars, heightInChars }); } [[nodiscard]] Viewport DxEngine::GetViewportInPixels(const Viewport& viewInCharacters) const noexcept { - const short widthInPixels = base::saturated_cast(viewInCharacters.Width() * _fontRenderData->GlyphCell().width()); - const short heightInPixels = base::saturated_cast(viewInCharacters.Height() * _fontRenderData->GlyphCell().height()); + const short widthInPixels = base::saturated_cast(viewInCharacters.Width() * _fontRenderData->GlyphCell().width); + const short heightInPixels = base::saturated_cast(viewInCharacters.Height() * _fontRenderData->GlyphCell().height); return Viewport::FromDimensions(viewInCharacters.Origin(), { widthInPixels, heightInPixels }); } @@ -2099,7 +2104,7 @@ float DxEngine::GetScaling() const noexcept // - area - Rectangle describing dirty area in characters. // Return Value: // - S_OK -[[nodiscard]] HRESULT DxEngine::GetDirtyArea(gsl::span& area) noexcept +[[nodiscard]] HRESULT DxEngine::GetDirtyArea(gsl::span& area) noexcept try { area = _invalidMap.runs(); @@ -2116,7 +2121,9 @@ CATCH_RETURN(); [[nodiscard]] HRESULT DxEngine::GetFontSize(_Out_ COORD* const pFontSize) noexcept try { - *pFontSize = _fontRenderData->GlyphCell(); + const auto size = _fontRenderData->GlyphCell(); + pFontSize->X = size.narrow_width(); + pFontSize->Y = size.narrow_height(); return S_OK; } CATCH_RETURN(); diff --git a/src/renderer/dx/DxRenderer.hpp b/src/renderer/dx/DxRenderer.hpp index 000cb23f74..527f7776f1 100644 --- a/src/renderer/dx/DxRenderer.hpp +++ b/src/renderer/dx/DxRenderer.hpp @@ -116,7 +116,7 @@ namespace Microsoft::Console::Render [[nodiscard]] HRESULT GetProposedFont(const FontInfoDesired& fiFontInfoDesired, FontInfo& fiFontInfo, int const iDpi) noexcept override; - [[nodiscard]] HRESULT GetDirtyArea(gsl::span& area) noexcept override; + [[nodiscard]] HRESULT GetDirtyArea(gsl::span& area) 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; @@ -177,7 +177,7 @@ namespace Microsoft::Console::Render bool _allInvalid; bool _presentReady; - std::vector _presentDirty; + std::vector _presentDirty; RECT _presentScroll; POINT _presentOffset; DXGI_PRESENT_PARAMETERS _presentParams; @@ -298,7 +298,7 @@ namespace Microsoft::Console::Render [[nodiscard]] til::size _GetClientSize() const; - void _InvalidateRectangle(const til::rectangle& rc); + void _InvalidateRectangle(const til::rect& rc); bool _IsAllInvalid() const noexcept; [[nodiscard]] D2D1_COLOR_F _ColorFFromColorRef(const COLORREF color) noexcept; diff --git a/src/renderer/gdi/gdirenderer.hpp b/src/renderer/gdi/gdirenderer.hpp index 2e09f374dd..33ed835212 100644 --- a/src/renderer/gdi/gdirenderer.hpp +++ b/src/renderer/gdi/gdirenderer.hpp @@ -76,7 +76,7 @@ namespace Microsoft::Console::Render _Out_ FontInfo& Font, const int iDpi) noexcept override; - [[nodiscard]] HRESULT GetDirtyArea(gsl::span& area) noexcept override; + [[nodiscard]] HRESULT GetDirtyArea(gsl::span& area) 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; @@ -92,7 +92,7 @@ namespace Microsoft::Console::Render bool _fPaintStarted; - til::rectangle _invalidCharacters; + til::rect _invalidCharacters; PAINTSTRUCT _psInvalidData; HDC _hdcMemoryContext; bool _isTrueTypeFont; diff --git a/src/renderer/gdi/math.cpp b/src/renderer/gdi/math.cpp index a127021ef1..58a014fa02 100644 --- a/src/renderer/gdi/math.cpp +++ b/src/renderer/gdi/math.cpp @@ -16,14 +16,14 @@ using namespace Microsoft::Console::Render; // This is an Inclusive rect. // Return Value: // - S_OK or math failure -[[nodiscard]] HRESULT GdiEngine::GetDirtyArea(gsl::span& area) noexcept +[[nodiscard]] HRESULT GdiEngine::GetDirtyArea(gsl::span& area) noexcept { RECT rc = _psInvalidData.rcPaint; SMALL_RECT sr = { 0 }; RETURN_IF_FAILED(_ScaleByFont(&rc, &sr)); - _invalidCharacters = sr; + _invalidCharacters = til::rect{ sr }; area = { &_invalidCharacters, 1 }; diff --git a/src/renderer/gdi/state.cpp b/src/renderer/gdi/state.cpp index 722577c8ec..954d55c9dd 100644 --- a/src/renderer/gdi/state.cpp +++ b/src/renderer/gdi/state.cpp @@ -435,7 +435,7 @@ GdiEngine::~GdiEngine() _fontCodepage = Font.GetCodePage(); // Inform the soft font of the change in size. - _softFont.SetTargetSize(_GetFontSize()); + _softFont.SetTargetSize(til::size{ _GetFontSize() }); LOG_IF_FAILED(InvalidateAll()); @@ -462,7 +462,7 @@ GdiEngine::~GdiEngine() } // Create a new font resource with the updated pattern, or delete if empty. - _softFont = { bitPattern, cellSize, _GetFontSize(), centeringHint }; + _softFont = FontResource{ bitPattern, til::size{ cellSize }, til::size{ _GetFontSize() }, centeringHint }; return S_OK; } diff --git a/src/renderer/inc/IRenderEngine.hpp b/src/renderer/inc/IRenderEngine.hpp index ecf9daecfd..c3aa8000fb 100644 --- a/src/renderer/inc/IRenderEngine.hpp +++ b/src/renderer/inc/IRenderEngine.hpp @@ -82,7 +82,7 @@ namespace Microsoft::Console::Render [[nodiscard]] virtual HRESULT UpdateDpi(int iDpi) noexcept = 0; [[nodiscard]] virtual HRESULT UpdateViewport(SMALL_RECT srNewViewport) noexcept = 0; [[nodiscard]] virtual HRESULT GetProposedFont(const FontInfoDesired& FontInfoDesired, _Out_ FontInfo& FontInfo, int iDpi) noexcept = 0; - [[nodiscard]] virtual HRESULT GetDirtyArea(gsl::span& area) noexcept = 0; + [[nodiscard]] virtual HRESULT GetDirtyArea(gsl::span& area) noexcept = 0; [[nodiscard]] virtual HRESULT GetFontSize(_Out_ COORD* pFontSize) noexcept = 0; [[nodiscard]] virtual HRESULT IsGlyphWideByFont(std::wstring_view glyph, _Out_ bool* pResult) noexcept = 0; [[nodiscard]] virtual HRESULT UpdateTitle(std::wstring_view newTitle) noexcept = 0; diff --git a/src/renderer/uia/UiaRenderer.cpp b/src/renderer/uia/UiaRenderer.cpp index 8349d710ac..9424501538 100644 --- a/src/renderer/uia/UiaRenderer.cpp +++ b/src/renderer/uia/UiaRenderer.cpp @@ -440,11 +440,11 @@ void UiaEngine::WaitUntilCanRender() noexcept // - area - Rectangle describing dirty area in characters. // Return Value: // - S_OK. -[[nodiscard]] HRESULT UiaEngine::GetDirtyArea(gsl::span& area) noexcept +[[nodiscard]] HRESULT UiaEngine::GetDirtyArea(gsl::span& area) noexcept { // 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; + static constexpr til::rect empty; area = { &empty, 1 }; return S_OK; } diff --git a/src/renderer/uia/UiaRenderer.hpp b/src/renderer/uia/UiaRenderer.hpp index 3b187f6465..d660fe7138 100644 --- a/src/renderer/uia/UiaRenderer.hpp +++ b/src/renderer/uia/UiaRenderer.hpp @@ -57,7 +57,7 @@ namespace Microsoft::Console::Render [[nodiscard]] HRESULT UpdateDpi(const int iDpi) noexcept override; [[nodiscard]] HRESULT UpdateViewport(const SMALL_RECT srNewViewport) noexcept override; [[nodiscard]] HRESULT GetProposedFont(const FontInfoDesired& FontInfoDesired, _Out_ FontInfo& FontInfo, const int iDpi) noexcept override; - [[nodiscard]] HRESULT GetDirtyArea(gsl::span& area) noexcept override; + [[nodiscard]] HRESULT GetDirtyArea(gsl::span& area) 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; diff --git a/src/renderer/vt/XtermEngine.cpp b/src/renderer/vt/XtermEngine.cpp index 9d5a74665c..e78812db02 100644 --- a/src/renderer/vt/XtermEngine.cpp +++ b/src/renderer/vt/XtermEngine.cpp @@ -37,7 +37,7 @@ XtermEngine::XtermEngine(_In_ wil::unique_hfile hPipe, { RETURN_IF_FAILED(VtEngine::StartPaint()); - _trace.TraceLastText(_lastText); + _trace.TraceLastText(til::point{ _lastText }); // Prep us to think that the cursor is not visible this frame. If it _is_ // visible, then PaintCursor will be called, and we'll set this to true @@ -57,16 +57,16 @@ XtermEngine::XtermEngine(_In_ wil::unique_hfile hPipe, } else { - gsl::span dirty; + gsl::span dirty; RETURN_IF_FAILED(GetDirtyArea(dirty)); // 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).to_small_rect()); // If there's more than 1, union them all up with the 1 we already have. for (size_t i = 1; i < dirty.size(); ++i) { - dirtyView = Viewport::Union(dirtyView, Viewport::FromInclusive(til::at(dirty, i))); + dirtyView = Viewport::Union(dirtyView, Viewport::FromInclusive(til::at(dirty, i).to_small_rect())); } } @@ -237,7 +237,7 @@ XtermEngine::XtermEngine(_In_ wil::unique_hfile hPipe, { HRESULT hr = S_OK; const auto originalPos = _lastText; - _trace.TraceMoveCursor(_lastText, coord); + _trace.TraceMoveCursor(til::point{ _lastText }, til::point{ coord }); bool performedSoftWrap = false; if (coord.X != _lastText.X || coord.Y != _lastText.Y) { @@ -348,18 +348,18 @@ try { _trace.TraceScrollFrame(_scrollDelta); - if (_scrollDelta.x() != 0) + if (_scrollDelta.x != 0) { // No easy way to shift left-right. Everything needs repainting. return InvalidateAll(); } - if (_scrollDelta.y() == 0) + if (_scrollDelta.y == 0) { // There's nothing to do here. Do nothing. return S_OK; } - const short dy = _scrollDelta.y(); + const short dy = _scrollDelta.narrow_y(); const short absDy = static_cast(abs(dy)); // Save the old wrap state here. We're going to clear it so that @@ -411,7 +411,7 @@ try // position we think we left the cursor. // // See GH#5113 - _trace.TraceLastText(_lastText); + _trace.TraceLastText(til::point{ _lastText }); if (_wrappedRow.has_value()) { _wrappedRow.value() += dy; @@ -430,7 +430,7 @@ try // one frame, and the second line in another frame that included other // changes _above_ the wrapped line, that we maintain the wrap state in // the Terminal. - const til::rectangle lastCellOfWrappedRow{ + const til::rect lastCellOfWrappedRow{ til::point{ _lastViewport.RightInclusive(), _wrappedRow.value() }, til::size{ 1, 1 } }; diff --git a/src/renderer/vt/invalidate.cpp b/src/renderer/vt/invalidate.cpp index 1856ac4cdd..5132f8bec0 100644 --- a/src/renderer/vt/invalidate.cpp +++ b/src/renderer/vt/invalidate.cpp @@ -49,7 +49,7 @@ using namespace Microsoft::Console::Render; [[nodiscard]] HRESULT VtEngine::Invalidate(const SMALL_RECT* const psrRegion) noexcept try { - const til::rectangle rect{ Viewport::FromExclusive(*psrRegion).ToInclusive() }; + const til::rect rect{ Viewport::FromExclusive(*psrRegion).ToInclusive() }; _trace.TraceInvalidate(rect); _invalidMap.set(rect); return S_OK; @@ -91,7 +91,7 @@ CATCH_RETURN(); [[nodiscard]] HRESULT VtEngine::InvalidateAll() noexcept try { - _trace.TraceInvalidateAll(_lastViewport.ToOrigin().ToInclusive()); + _trace.TraceInvalidateAll(til::rect{ _lastViewport.ToOrigin().ToInclusive() }); _invalidMap.set_all(); return S_OK; } diff --git a/src/renderer/vt/math.cpp b/src/renderer/vt/math.cpp index 5483439931..8521764eae 100644 --- a/src/renderer/vt/math.cpp +++ b/src/renderer/vt/math.cpp @@ -17,7 +17,7 @@ using namespace Microsoft::Console::Types; // This is an Inclusive rect. // Return Value: // - S_OK. -[[nodiscard]] HRESULT VtEngine::GetDirtyArea(gsl::span& area) noexcept +[[nodiscard]] HRESULT VtEngine::GetDirtyArea(gsl::span& area) noexcept { area = _invalidMap.runs(); return S_OK; diff --git a/src/renderer/vt/paint.cpp b/src/renderer/vt/paint.cpp index adb0c90d15..1f015520ea 100644 --- a/src/renderer/vt/paint.cpp +++ b/src/renderer/vt/paint.cpp @@ -34,7 +34,7 @@ using namespace Microsoft::Console::Types; _quickReturn = !somethingToDo; _trace.TraceStartPaint(_quickReturn, _invalidMap, - _lastViewport.ToInclusive(), + til::rect{ _lastViewport.ToInclusive() }, _scrollDelta, _cursorMoved, _wrappedRow); @@ -158,7 +158,7 @@ using namespace Microsoft::Console::Types; // - S_OK or suitable HRESULT error from writing pipe. [[nodiscard]] HRESULT VtEngine::PaintCursor(const CursorOptions& options) noexcept { - _trace.TracePaintCursor(options.coordCursor); + _trace.TracePaintCursor(til::point{ options.coordCursor }); // MSFT:15933349 - Send the terminal the updated cursor information, if it's changed. LOG_IF_FAILED(_MoveCursor(options.coordCursor)); diff --git a/src/renderer/vt/state.cpp b/src/renderer/vt/state.cpp index 2d60910ab2..bfea737bb1 100644 --- a/src/renderer/vt/state.cpp +++ b/src/renderer/vt/state.cpp @@ -32,9 +32,9 @@ VtEngine::VtEngine(_In_ wil::unique_hfile pipe, _lastTextAttributes(INVALID_COLOR, INVALID_COLOR), _lastViewport(initialViewport), _pool(til::pmr::get_default_resource()), - _invalidMap(initialViewport.Dimensions(), false, &_pool), + _invalidMap(til::size{ initialViewport.Dimensions() }, false, &_pool), _lastText({ 0 }), - _scrollDelta({ 0, 0 }), + _scrollDelta(0, 0), _quickReturn(false), _clearedAllThisFrame(false), _cursorMoved(false), @@ -245,13 +245,13 @@ VtEngine::VtEngine(_In_ wil::unique_hfile pipe, // buffer will have triggered it's own invalidations for what it knows is // invalid. Previously, we'd invalidate everything if the width changed, // because we couldn't be sure if lines were reflowed. - _invalidMap.resize(newView.Dimensions()); + _invalidMap.resize(til::size{ newView.Dimensions() }); } else { if (SUCCEEDED(hr)) { - _invalidMap.resize(newView.Dimensions(), true); // resize while filling in new space with repaint requests. + _invalidMap.resize(til::size{ newView.Dimensions() }, true); // resize while filling in new space with repaint requests. // Viewport is smaller now - just update it all. if (oldView.Height() > newView.Height() || oldView.Width() > newView.Width()) diff --git a/src/renderer/vt/tracing.cpp b/src/renderer/vt/tracing.cpp index c28220f650..6e76efed8d 100644 --- a/src/renderer/vt/tracing.cpp +++ b/src/renderer/vt/tracing.cpp @@ -82,7 +82,7 @@ void RenderTracing::TraceString(const std::string_view& instr) const #endif UNIT_TESTING } -void RenderTracing::TraceInvalidate(const til::rectangle invalidRect) const +void RenderTracing::TraceInvalidate(const til::rect& invalidRect) const { #ifndef UNIT_TESTING if (TraceLoggingProviderEnabled(g_hConsoleVtRendererTraceProvider, WINEVENT_LEVEL_VERBOSE, TIL_KEYWORD_TRACE)) @@ -100,7 +100,7 @@ void RenderTracing::TraceInvalidate(const til::rectangle invalidRect) const #endif UNIT_TESTING } -void RenderTracing::TraceInvalidateAll(const til::rectangle viewport) const +void RenderTracing::TraceInvalidateAll(const til::rect& viewport) const { #ifndef UNIT_TESTING if (TraceLoggingProviderEnabled(g_hConsoleVtRendererTraceProvider, WINEVENT_LEVEL_VERBOSE, TIL_KEYWORD_TRACE)) @@ -151,7 +151,7 @@ void RenderTracing::TraceInvalidateScroll(const til::point scroll) const void RenderTracing::TraceStartPaint(const bool quickReturn, const til::pmr::bitmap& invalidMap, - const til::rectangle lastViewport, + const til::rect& lastViewport, const til::point scrollDelt, const bool cursorMoved, const std::optional& wrappedRow) const diff --git a/src/renderer/vt/tracing.hpp b/src/renderer/vt/tracing.hpp index 3a7675a790..f3aa7fbb00 100644 --- a/src/renderer/vt/tracing.hpp +++ b/src/renderer/vt/tracing.hpp @@ -27,7 +27,7 @@ namespace Microsoft::Console::VirtualTerminal RenderTracing(); ~RenderTracing(); void TraceString(const std::string_view& str) const; - void TraceInvalidate(const til::rectangle view) const; + void TraceInvalidate(const til::rect& view) const; void TraceLastText(const til::point lastText) const; void TraceScrollFrame(const til::point scrollDelta) const; void TraceMoveCursor(const til::point lastText, const til::point cursor) const; @@ -35,12 +35,12 @@ namespace Microsoft::Console::VirtualTerminal void TraceClearWrapped() const; void TraceWrapped() const; void TracePaintCursor(const til::point coordCursor) const; - void TraceInvalidateAll(const til::rectangle view) const; + void TraceInvalidateAll(const til::rect& view) const; void TraceTriggerCircling(const bool newFrame) const; void TraceInvalidateScroll(const til::point scroll) const; void TraceStartPaint(const bool quickReturn, const til::pmr::bitmap& invalidMap, - const til::rectangle lastViewport, + const til::rect& lastViewport, const til::point scrollDelta, const bool cursorMoved, const std::optional& wrappedRow) const; diff --git a/src/renderer/vt/vtrenderer.hpp b/src/renderer/vt/vtrenderer.hpp index 96da01ca2f..9cba89e3f1 100644 --- a/src/renderer/vt/vtrenderer.hpp +++ b/src/renderer/vt/vtrenderer.hpp @@ -66,7 +66,7 @@ namespace Microsoft::Console::Render [[nodiscard]] HRESULT UpdateDpi(int iDpi) noexcept override; [[nodiscard]] HRESULT UpdateViewport(SMALL_RECT srNewViewport) noexcept override; [[nodiscard]] HRESULT GetProposedFont(const FontInfoDesired& FontInfoDesired, _Out_ FontInfo& FontInfo, int iDpi) noexcept override; - [[nodiscard]] HRESULT GetDirtyArea(gsl::span& area) noexcept override; + [[nodiscard]] HRESULT GetDirtyArea(gsl::span& area) noexcept override; [[nodiscard]] HRESULT GetFontSize(_Out_ COORD* pFontSize) noexcept override; [[nodiscard]] HRESULT IsGlyphWideByFont(std::wstring_view glyph, _Out_ bool* pResult) noexcept override; diff --git a/src/renderer/wddmcon/WddmConRenderer.cpp b/src/renderer/wddmcon/WddmConRenderer.cpp index 1ee11d7418..ae99e9e6c1 100644 --- a/src/renderer/wddmcon/WddmConRenderer.cpp +++ b/src/renderer/wddmcon/WddmConRenderer.cpp @@ -354,15 +354,10 @@ bool WddmConEngine::IsInitialized() return S_OK; } -[[nodiscard]] HRESULT WddmConEngine::GetDirtyArea(gsl::span& area) noexcept +[[nodiscard]] HRESULT WddmConEngine::GetDirtyArea(gsl::span& area) noexcept { - SMALL_RECT r; - r.Bottom = _displayHeight > 0 ? (SHORT)(_displayHeight - 1) : 0; - r.Top = 0; - r.Left = 0; - r.Right = _displayWidth > 0 ? (SHORT)(_displayWidth - 1) : 0; - - _dirtyArea = r; + _dirtyArea.bottom = std::max(0, _displayHeight); + _dirtyArea.right = std::max(0, _displayWidth); area = { &_dirtyArea, 1 }; diff --git a/src/renderer/wddmcon/WddmConRenderer.hpp b/src/renderer/wddmcon/WddmConRenderer.hpp index de564c0017..3d7d3ccb13 100644 --- a/src/renderer/wddmcon/WddmConRenderer.hpp +++ b/src/renderer/wddmcon/WddmConRenderer.hpp @@ -60,7 +60,7 @@ namespace Microsoft::Console::Render [[nodiscard]] HRESULT GetProposedFont(const FontInfoDesired& fiFontInfoDesired, FontInfo& fiFontInfo, int const iDpi) noexcept override; - [[nodiscard]] HRESULT GetDirtyArea(gsl::span& area) noexcept override; + [[nodiscard]] HRESULT GetDirtyArea(gsl::span& area) 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; @@ -76,7 +76,7 @@ namespace Microsoft::Console::Render // Variables LONG _displayHeight; LONG _displayWidth; - til::rectangle _dirtyArea; + til::rect _dirtyArea; PCD_IO_ROW_INFORMATION* _displayState; diff --git a/src/terminal/adapter/FontBuffer.cpp b/src/terminal/adapter/FontBuffer.cpp index 688325b27e..5e6ffb963e 100644 --- a/src/terminal/adapter/FontBuffer.cpp +++ b/src/terminal/adapter/FontBuffer.cpp @@ -222,9 +222,9 @@ gsl::span FontBuffer::GetBitPattern() const noexcept return { _buffer.data(), MAX_CHARS * _fullHeight }; } -til::size FontBuffer::GetCellSize() const +til::size FontBuffer::GetCellSize() const noexcept { - return { _fullWidth, _fullHeight }; + return { gsl::narrow_cast(_fullWidth), gsl::narrow_cast(_fullHeight) }; } size_t FontBuffer::GetTextCenteringHint() const noexcept diff --git a/src/terminal/adapter/FontBuffer.hpp b/src/terminal/adapter/FontBuffer.hpp index bdd6fff720..08115f1b55 100644 --- a/src/terminal/adapter/FontBuffer.hpp +++ b/src/terminal/adapter/FontBuffer.hpp @@ -31,7 +31,7 @@ namespace Microsoft::Console::VirtualTerminal bool FinalizeSixelData(); gsl::span GetBitPattern() const noexcept; - til::size GetCellSize() const; + til::size GetCellSize() const noexcept; size_t GetTextCenteringHint() const noexcept; VTID GetDesignation() const noexcept; diff --git a/src/terminal/adapter/adaptDispatch.cpp b/src/terminal/adapter/adaptDispatch.cpp index 18d81fd56f..af1f4d6282 100644 --- a/src/terminal/adapter/adaptDispatch.cpp +++ b/src/terminal/adapter/adaptDispatch.cpp @@ -2474,7 +2474,7 @@ ITermDispatch::StringHandler AdaptDispatch::DownloadDRCS(const size_t fontNumber const auto bitPattern = _fontBuffer->GetBitPattern(); const auto cellSize = _fontBuffer->GetCellSize(); const auto centeringHint = _fontBuffer->GetTextCenteringHint(); - _pConApi->PrivateUpdateSoftFont(bitPattern, cellSize, centeringHint); + _pConApi->PrivateUpdateSoftFont(bitPattern, cellSize.to_win32_size(), centeringHint); } return true; }; diff --git a/src/terminal/adapter/ut_adapter/adapterTest.cpp b/src/terminal/adapter/ut_adapter/adapterTest.cpp index 2f45b32a7b..bd330088c1 100644 --- a/src/terminal/adapter/ut_adapter/adapterTest.cpp +++ b/src/terminal/adapter/ut_adapter/adapterTest.cpp @@ -1794,7 +1794,7 @@ public: wchar_t pwszBuffer[50]; - swprintf_s(pwszBuffer, ARRAYSIZE(pwszBuffer), L"\x1b[%d;%dR\x1b[%d;%dR", coordCursorExpectedFirst.y(), coordCursorExpectedFirst.x(), coordCursorExpectedSecond.y(), coordCursorExpectedSecond.x()); + swprintf_s(pwszBuffer, ARRAYSIZE(pwszBuffer), L"\x1b[%d;%dR\x1b[%d;%dR", coordCursorExpectedFirst.y, coordCursorExpectedFirst.x, coordCursorExpectedSecond.y, coordCursorExpectedSecond.x); _testGetSet->ValidateInputEvent(pwszBuffer); } } diff --git a/src/terminal/parser/InputStateMachineEngine.cpp b/src/terminal/parser/InputStateMachineEngine.cpp index b06bfa84e8..ca46966384 100644 --- a/src/terminal/parser/InputStateMachineEngine.cpp +++ b/src/terminal/parser/InputStateMachineEngine.cpp @@ -387,7 +387,7 @@ bool InputStateMachineEngine::ActionCsiDispatch(const VTID id, const VTParameter DWORD buttonState = 0; DWORD eventFlags = 0; const size_t firstParameter = parameters.at(0).value_or(0); - const til::point uiPos{ parameters.at(1) - 1, parameters.at(2) - 1 }; + const til::point uiPos{ gsl::narrow_cast(parameters.at(1) - 1), gsl::narrow_cast(parameters.at(2) - 1) }; modifierState = _GetSGRMouseModifierState(firstParameter); success = _UpdateSGRMouseButtonState(id, firstParameter, buttonState, eventFlags, uiPos); @@ -730,7 +730,7 @@ bool InputStateMachineEngine::_WriteMouseEvent(const til::point uiPos, const DWO { INPUT_RECORD rgInput; rgInput.EventType = MOUSE_EVENT; - rgInput.Event.MouseEvent.dwMousePosition = uiPos; + rgInput.Event.MouseEvent.dwMousePosition = uiPos.to_win32_coord(); rgInput.Event.MouseEvent.dwButtonState = buttonState; rgInput.Event.MouseEvent.dwControlKeyState = controlKeyState; rgInput.Event.MouseEvent.dwEventFlags = eventFlags; diff --git a/src/til/ut_til/BitmapTests.cpp b/src/til/ut_til/BitmapTests.cpp index 2fc1e9f26b..39847cafdf 100644 --- a/src/til/ut_til/BitmapTests.cpp +++ b/src/til/ut_til/BitmapTests.cpp @@ -14,14 +14,14 @@ class BitmapTests TEST_CLASS(BitmapTests); template - void _checkBits(const til::rectangle& bitsOn, + void _checkBits(const til::rect& bitsOn, const til::details::bitmap& map) { - _checkBits(std::vector{ bitsOn }, map); + _checkBits(std::vector{ bitsOn }, map); } template - void _checkBits(const std::vector& bitsOn, + void _checkBits(const std::vector& bitsOn, const til::details::bitmap& map) { Log::Comment(L"Check all bits in map."); @@ -50,7 +50,7 @@ class BitmapTests { const til::bitmap bitmap; const til::size expectedSize{ 0, 0 }; - const til::rectangle expectedRect{ 0, 0, 0, 0 }; + const til::rect expectedRect{ 0, 0, 0, 0 }; VERIFY_ARE_EQUAL(expectedSize, bitmap._sz); VERIFY_ARE_EQUAL(expectedRect, bitmap._rc); VERIFY_ARE_EQUAL(0u, bitmap._bits.size()); @@ -63,7 +63,7 @@ class BitmapTests TEST_METHOD(SizeConstruct) { const til::size expectedSize{ 5, 10 }; - const til::rectangle expectedRect{ 0, 0, 5, 10 }; + const til::rect expectedRect{ 0, 0, 5, 10 }; const til::bitmap bitmap{ expectedSize }; VERIFY_ARE_EQUAL(expectedSize, bitmap._sz); VERIFY_ARE_EQUAL(expectedRect, bitmap._rc); @@ -84,7 +84,7 @@ class BitmapTests VERIFY_SUCCEEDED_RETURN(TestData::TryGetValue(L"fill", fill)); const til::size expectedSize{ 5, 10 }; - const til::rectangle expectedRect{ 0, 0, 5, 10 }; + const til::rect expectedRect{ 0, 0, 5, 10 }; const til::bitmap bitmap{ expectedSize, fill }; VERIFY_ARE_EQUAL(expectedSize, bitmap._sz); VERIFY_ARE_EQUAL(expectedRect, bitmap._rc); @@ -184,7 +184,7 @@ class BitmapTests // 0 1 1 0 // 0 1 1 0 // 0 0 0 0 - map.set(til::rectangle{ til::point{ 1, 1 }, til::size{ 2, 2 } }); + map.set(til::rect{ til::point{ 1, 1 }, til::size{ 2, 2 } }); Log::Comment(L"1.) Move down and right"); { @@ -226,7 +226,7 @@ class BitmapTests // 0 1 1 0 0 0 0 0 // 0 1 1 0 v --> 0 0 0 0 // 0 0 0 0 v 0 1 1 0 - expected.set(til::rectangle{ til::point{ 1, 3 }, til::size{ 2, 1 } }); + expected.set(til::rect{ til::point{ 1, 3 }, til::size{ 2, 1 } }); actual.translate(delta); @@ -271,7 +271,7 @@ class BitmapTests // 0 1 1 0 --> 1 0 0 0 // 0 0 0 0 0 0 0 0 // <--<-- - expected.set(til::rectangle{ til::point{ 0, 1 }, til::size{ 1, 2 } }); + expected.set(til::rect{ til::point{ 0, 1 }, til::size{ 1, 2 } }); actual.translate(delta); @@ -318,7 +318,7 @@ class BitmapTests // 0 1 1 0 ^ 0 0 0 0 // 0 1 1 0 --> 0 0 0 0 // 0 0 0 0 0 0 0 0 - expected.set(til::rectangle{ til::point{ 1, 0 }, til::size{ 2, 1 } }); + expected.set(til::rect{ til::point{ 1, 0 }, til::size{ 2, 1 } }); actual.translate(delta); @@ -363,7 +363,7 @@ class BitmapTests // 0 1 1 0 --> 0 0 0 1 // 0 0 0 0 0 0 0 0 // ->-> - expected.set(til::rectangle{ til::point{ 3, 1 }, til::size{ 1, 2 } }); + expected.set(til::rect{ til::point{ 3, 1 }, til::size{ 1, 2 } }); actual.translate(delta); @@ -381,7 +381,7 @@ class BitmapTests // 0 1 1 0 // 0 1 1 0 // 0 0 0 0 - map.set(til::rectangle{ til::point{ 1, 1 }, til::size{ 2, 2 } }); + map.set(til::rect{ til::point{ 1, 1 }, til::size{ 2, 2 } }); Log::Comment(L"1.) Move down and right"); { @@ -400,8 +400,8 @@ class BitmapTests // 0 1 1 0 v --> 0 0 0 0 --> F F 0 0 // 0 0 0 0 v 0 1 1 0 F F 0 1 // ->-> - expected.set(til::rectangle{ til::point{ 0, 0 }, til::size{ 4, 2 } }); - expected.set(til::rectangle{ til::point{ 0, 2 }, til::size{ 2, 2 } }); + expected.set(til::rect{ til::point{ 0, 0 }, til::size{ 4, 2 } }); + expected.set(til::rect{ til::point{ 0, 2 }, til::size{ 2, 2 } }); expected.set(til::point{ 3, 3 }); actual.translate(delta, true); @@ -425,8 +425,8 @@ class BitmapTests // 0 1 1 0 F F F F // 0 1 1 0 v --> 0 0 0 0 // 0 0 0 0 v 0 1 1 0 - expected.set(til::rectangle{ til::point{ 0, 0 }, til::size{ 4, 2 } }); - expected.set(til::rectangle{ til::point{ 1, 3 }, til::size{ 2, 1 } }); + expected.set(til::rect{ til::point{ 0, 0 }, til::size{ 4, 2 } }); + expected.set(til::rect{ til::point{ 1, 3 }, til::size{ 2, 1 } }); actual.translate(delta, true); @@ -450,8 +450,8 @@ class BitmapTests // 0 1 1 0 v --> 0 0 0 0 --> 0 0 F F // 0 0 0 0 v 0 1 1 0 1 0 F F // <-<- - expected.set(til::rectangle{ til::point{ 0, 0 }, til::size{ 4, 2 } }); - expected.set(til::rectangle{ til::point{ 2, 2 }, til::size{ 2, 2 } }); + expected.set(til::rect{ til::point{ 0, 0 }, til::size{ 4, 2 } }); + expected.set(til::rect{ til::point{ 2, 2 }, til::size{ 2, 2 } }); expected.set(til::point{ 0, 3 }); actual.translate(delta, true); @@ -473,8 +473,8 @@ class BitmapTests // 0 1 1 0 --> 1 0 F F // 0 0 0 0 0 0 F F // <--<-- - expected.set(til::rectangle{ til::point{ 2, 0 }, til::size{ 2, 4 } }); - expected.set(til::rectangle{ til::point{ 0, 1 }, til::size{ 1, 2 } }); + expected.set(til::rect{ til::point{ 2, 0 }, til::size{ 2, 4 } }); + expected.set(til::rect{ til::point{ 0, 1 }, til::size{ 1, 2 } }); actual.translate(delta, true); @@ -498,8 +498,8 @@ class BitmapTests // 0 1 1 0 --> F F F F --> F F F F // 0 0 0 0 F F F F F F F F // <-<- - expected.set(til::rectangle{ til::point{ 2, 0 }, til::size{ 2, 2 } }); - expected.set(til::rectangle{ til::point{ 0, 2 }, til::size{ 4, 2 } }); + expected.set(til::rect{ til::point{ 2, 0 }, til::size{ 2, 2 } }); + expected.set(til::rect{ til::point{ 0, 2 }, til::size{ 4, 2 } }); expected.set(til::point{ 0, 0 }); actual.translate(delta, true); @@ -523,8 +523,8 @@ class BitmapTests // 0 1 1 0 ^ 0 0 0 0 // 0 1 1 0 --> F F F F // 0 0 0 0 F F F F - expected.set(til::rectangle{ til::point{ 1, 0 }, til::size{ 2, 1 } }); - expected.set(til::rectangle{ til::point{ 0, 2 }, til::size{ 4, 2 } }); + expected.set(til::rect{ til::point{ 1, 0 }, til::size{ 2, 1 } }); + expected.set(til::rect{ til::point{ 0, 2 }, til::size{ 4, 2 } }); actual.translate(delta, true); @@ -549,8 +549,8 @@ class BitmapTests // 0 0 0 0 F F F F F F F F // ->-> expected.set(til::point{ 3, 0 }); - expected.set(til::rectangle{ til::point{ 0, 2 }, til::size{ 4, 2 } }); - expected.set(til::rectangle{ til::point{ 0, 0 }, til::size{ 2, 2 } }); + expected.set(til::rect{ til::point{ 0, 2 }, til::size{ 4, 2 } }); + expected.set(til::rect{ til::point{ 0, 0 }, til::size{ 2, 2 } }); actual.translate(delta, true); @@ -571,8 +571,8 @@ class BitmapTests // 0 1 1 0 --> F F 0 1 // 0 0 0 0 F F 0 0 // ->-> - expected.set(til::rectangle{ til::point{ 3, 1 }, til::size{ 1, 2 } }); - expected.set(til::rectangle{ til::point{ 0, 0 }, til::size{ 2, 4 } }); + expected.set(til::rect{ til::point{ 3, 1 }, til::size{ 1, 2 } }); + expected.set(til::rect{ til::point{ 0, 0 }, til::size{ 2, 4 } }); actual.translate(delta, true); @@ -592,8 +592,8 @@ class BitmapTests const til::point point{ 2, 2 }; bitmap.set(point); - std::vector expectedSet; - expectedSet.emplace_back(til::rectangle{ point }); + std::vector expectedSet; + expectedSet.emplace_back(til::rect{ 2, 2, 3, 3 }); // Run through every bit. Only the one we set should be true. Log::Comment(L"Only the bit we set should be true."); @@ -603,7 +603,7 @@ class BitmapTests bitmap.set_all(); expectedSet.clear(); - expectedSet.emplace_back(til::rectangle{ bitmap._rc }); + expectedSet.emplace_back(til::rect{ bitmap._rc }); _checkBits(expectedSet, bitmap); Log::Comment(L"Now reset them all."); @@ -612,13 +612,13 @@ class BitmapTests expectedSet.clear(); _checkBits(expectedSet, bitmap); - til::rectangle totalZone{ sz }; + til::rect totalZone{ sz }; Log::Comment(L"Set a rectangle of bits and test they went on."); // 0 0 0 0 |1 1|0 0 // 0 0 0 0 --\ |1 1|0 0 // 0 0 0 0 --/ |1 1|0 0 // 0 0 0 0 0 0 0 0 - til::rectangle setZone{ til::point{ 0, 0 }, til::size{ 2, 3 } }; + til::rect setZone{ til::point{ 0, 0 }, til::size{ 2, 3 } }; bitmap.set(setZone); expectedSet.clear(); @@ -647,11 +647,7 @@ class BitmapTests Log::Comment(L"2.) SetRectangle out of bounds."); { auto fn = [&]() { - map.set(til::rectangle{ til::point{ - 2, - 2, - }, - til::size{ 10, 10 } }); + map.set(til::rect{ til::point{ 2, 2 }, til::size{ 10, 10 } }); }; VERIFY_THROWS_SPECIFIC(fn(), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_INVALIDARG; }); @@ -664,11 +660,11 @@ class BitmapTests const til::size originalSize{ 2, 2 }; til::bitmap bitmap{ originalSize, true }; - std::vector expectedFillRects; + std::vector expectedFillRects; // 1 1 // 1 1 - expectedFillRects.emplace_back(til::rectangle{ originalSize }); + expectedFillRects.emplace_back(til::rect{ originalSize }); _checkBits(expectedFillRects, bitmap); Log::Comment(L"Attempt resize to the same size."); @@ -688,7 +684,7 @@ class BitmapTests Log::Comment(L"Set a bit out in the new space and check it."); const til::point spaceBit{ 1, 2 }; - expectedFillRects.emplace_back(til::rectangle{ spaceBit }); + expectedFillRects.emplace_back(til::rect{ 1, 2, 2, 3 }); bitmap.set(spaceBit); // 1 1 0 @@ -697,7 +693,7 @@ class BitmapTests _checkBits(expectedFillRects, bitmap); Log::Comment(L"Grow vertically and shrink horizontally at the same time. Fill any new space."); - expectedFillRects.emplace_back(til::rectangle{ til::point{ 0, 3 }, til::size{ 2, 1 } }); + expectedFillRects.emplace_back(til::rect{ til::point{ 0, 3 }, til::size{ 2, 1 } }); bitmap.resize(til::size{ 2, 4 }, true); // 1 1 @@ -846,19 +842,19 @@ class BitmapTests // 0 0 0 0 0 0 0 0 // 0 0 0 0 --> 0 0 0 0 // 0 0 0 0 0 0 0 0 - map.set(til::rectangle{ til::point{ 0, 0 }, til::size{ 2, 1 } }); + map.set(til::rect{ til::point{ 0, 0 }, til::size{ 2, 1 } }); // 1 1 0 0 1 1 0 0 // 0 0 0 0 0 0|1|0 // 0 0 0 0 --> 0 0|1|0 // 0 0 0 0 0 0|1|0 - map.set(til::rectangle{ til::point{ 2, 1 }, til::size{ 1, 3 } }); + map.set(til::rect{ til::point{ 2, 1 }, til::size{ 1, 3 } }); // 1 1 0 0 1 1 0|1| // 0 0 1 0 0 0 1|1| // 0 0 1 0 --> 0 0 1 0 // 0 0 1 0 0 0 1 0 - map.set(til::rectangle{ til::point{ 3, 0 }, til::size{ 1, 2 } }); + map.set(til::rect{ til::point{ 3, 0 }, til::size{ 1, 2 } }); // 1 1 0 1 1 1 0 1 // 0 0 1 1 |1|0 1 1 @@ -879,16 +875,16 @@ class BitmapTests // C _ D D // _ _ E _ // _ F F _ - til::some expected; - expected.push_back(til::rectangle{ til::point{ 0, 0 }, til::size{ 2, 1 } }); - expected.push_back(til::rectangle{ til::point{ 3, 0 }, til::size{ 1, 1 } }); - expected.push_back(til::rectangle{ til::point{ 0, 1 }, til::size{ 1, 1 } }); - expected.push_back(til::rectangle{ til::point{ 2, 1 }, til::size{ 2, 1 } }); - expected.push_back(til::rectangle{ til::point{ 2, 2 }, til::size{ 1, 1 } }); - expected.push_back(til::rectangle{ til::point{ 1, 3 }, til::size{ 2, 1 } }); + til::some expected; + expected.push_back(til::rect{ til::point{ 0, 0 }, til::size{ 2, 1 } }); + expected.push_back(til::rect{ til::point{ 3, 0 }, til::size{ 1, 1 } }); + expected.push_back(til::rect{ til::point{ 0, 1 }, til::size{ 1, 1 } }); + expected.push_back(til::rect{ til::point{ 2, 1 }, til::size{ 2, 1 } }); + expected.push_back(til::rect{ til::point{ 2, 2 }, til::size{ 1, 1 } }); + expected.push_back(til::rect{ til::point{ 1, 3 }, til::size{ 2, 1 } }); Log::Comment(L"Run the iterator and collect the runs."); - til::some actual; + til::some actual; for (auto run : map.runs()) { actual.push_back(run); @@ -912,7 +908,7 @@ class BitmapTests Log::Comment(L"Set point and validate runs updated."); const til::point setPoint{ 2, 2 }; - expected.push_back(til::rectangle{ setPoint }); + expected.push_back(til::rect{ 2, 2, 3, 3 }); map.set(setPoint); for (auto run : map.runs()) @@ -922,10 +918,10 @@ class BitmapTests VERIFY_ARE_EQUAL(expected, actual); Log::Comment(L"Set rectangle and validate runs updated."); - const til::rectangle setRect{ setPoint, til::size{ 2, 2 } }; + const til::rect setRect{ setPoint, til::size{ 2, 2 } }; expected.clear(); - expected.push_back(til::rectangle{ til::point{ 2, 2 }, til::size{ 2, 1 } }); - expected.push_back(til::rectangle{ til::point{ 2, 3 }, til::size{ 2, 1 } }); + expected.push_back(til::rect{ til::point{ 2, 2 }, til::size{ 2, 1 } }); + expected.push_back(til::rect{ til::point{ 2, 3 }, til::size{ 2, 1 } }); map.set(setRect); actual.clear(); @@ -937,10 +933,10 @@ class BitmapTests Log::Comment(L"Set all and validate runs updated."); expected.clear(); - expected.push_back(til::rectangle{ til::point{ 0, 0 }, til::size{ 4, 1 } }); - expected.push_back(til::rectangle{ til::point{ 0, 1 }, til::size{ 4, 1 } }); - expected.push_back(til::rectangle{ til::point{ 0, 2 }, til::size{ 4, 1 } }); - expected.push_back(til::rectangle{ til::point{ 0, 3 }, til::size{ 4, 1 } }); + expected.push_back(til::rect{ til::point{ 0, 0 }, til::size{ 4, 1 } }); + expected.push_back(til::rect{ til::point{ 0, 1 }, til::size{ 4, 1 } }); + expected.push_back(til::rect{ til::point{ 0, 2 }, til::size{ 4, 1 } }); + expected.push_back(til::rect{ til::point{ 0, 3 }, til::size{ 4, 1 } }); map.set_all(); actual.clear(); @@ -953,9 +949,9 @@ class BitmapTests Log::Comment(L"Resize and validate runs updated."); const til::size newSize{ 3, 3 }; expected.clear(); - expected.push_back(til::rectangle{ til::point{ 0, 0 }, til::size{ 3, 1 } }); - expected.push_back(til::rectangle{ til::point{ 0, 1 }, til::size{ 3, 1 } }); - expected.push_back(til::rectangle{ til::point{ 0, 2 }, til::size{ 3, 1 } }); + expected.push_back(til::rect{ til::point{ 0, 0 }, til::size{ 3, 1 } }); + expected.push_back(til::rect{ til::point{ 0, 1 }, til::size{ 3, 1 } }); + expected.push_back(til::rect{ til::point{ 0, 2 }, til::size{ 3, 1 } }); map.resize(newSize); actual.clear(); @@ -984,19 +980,19 @@ class BitmapTests // 0 0 0 0 0 0 0 0 // 0 0 0 0 --> 0 0 0 0 // 0 0 0 0 0 0 0 0 - map.set(til::rectangle{ til::point{ 0, 0 }, til::size{ 2, 1 } }); + map.set(til::rect{ til::point{ 0, 0 }, til::size{ 2, 1 } }); // 1 1 0 0 1 1 0 0 // 0 0 0 0 0 0|1|0 // 0 0 0 0 --> 0 0|1|0 // 0 0 0 0 0 0|1|0 - map.set(til::rectangle{ til::point{ 2, 1 }, til::size{ 1, 3 } }); + map.set(til::rect{ til::point{ 2, 1 }, til::size{ 1, 3 } }); // 1 1 0 0 1 1 0|1| // 0 0 1 0 0 0 1|1| // 0 0 1 0 --> 0 0 1 0 // 0 0 1 0 0 0 1 0 - map.set(til::rectangle{ til::point{ 3, 0 }, til::size{ 1, 2 } }); + map.set(til::rect{ til::point{ 3, 0 }, til::size{ 1, 2 } }); // 1 1 0 1 1 1 0 1 // 0 0 1 1 |1|0 1 1 @@ -1017,16 +1013,16 @@ class BitmapTests // C _ D D // _ _ E _ // _ F F _ - til::some expected; - expected.push_back(til::rectangle{ til::point{ 0, 0 }, til::size{ 2, 1 } }); - expected.push_back(til::rectangle{ til::point{ 3, 0 }, til::size{ 1, 1 } }); - expected.push_back(til::rectangle{ til::point{ 0, 1 }, til::size{ 1, 1 } }); - expected.push_back(til::rectangle{ til::point{ 2, 1 }, til::size{ 2, 1 } }); - expected.push_back(til::rectangle{ til::point{ 2, 2 }, til::size{ 1, 1 } }); - expected.push_back(til::rectangle{ til::point{ 1, 3 }, til::size{ 2, 1 } }); + til::some expected; + expected.push_back(til::rect{ til::point{ 0, 0 }, til::size{ 2, 1 } }); + expected.push_back(til::rect{ til::point{ 3, 0 }, til::size{ 1, 1 } }); + expected.push_back(til::rect{ til::point{ 0, 1 }, til::size{ 1, 1 } }); + expected.push_back(til::rect{ til::point{ 2, 1 }, til::size{ 2, 1 } }); + expected.push_back(til::rect{ til::point{ 2, 2 }, til::size{ 1, 1 } }); + expected.push_back(til::rect{ til::point{ 1, 3 }, til::size{ 2, 1 } }); Log::Comment(L"Run the iterator and collect the runs."); - til::some actual; + til::some actual; for (auto run : map.runs()) { actual.push_back(run); @@ -1050,7 +1046,7 @@ class BitmapTests Log::Comment(L"Set point and validate runs updated."); const til::point setPoint{ 2, 2 }; - expected.push_back(til::rectangle{ setPoint }); + expected.push_back(til::rect{ 2, 2, 3, 3 }); map.set(setPoint); for (auto run : map.runs()) @@ -1060,10 +1056,10 @@ class BitmapTests VERIFY_ARE_EQUAL(expected, actual); Log::Comment(L"Set rectangle and validate runs updated."); - const til::rectangle setRect{ setPoint, til::size{ 2, 2 } }; + const til::rect setRect{ setPoint, til::size{ 2, 2 } }; expected.clear(); - expected.push_back(til::rectangle{ til::point{ 2, 2 }, til::size{ 2, 1 } }); - expected.push_back(til::rectangle{ til::point{ 2, 3 }, til::size{ 2, 1 } }); + expected.push_back(til::rect{ til::point{ 2, 2 }, til::size{ 2, 1 } }); + expected.push_back(til::rect{ til::point{ 2, 3 }, til::size{ 2, 1 } }); map.set(setRect); actual.clear(); @@ -1075,10 +1071,10 @@ class BitmapTests Log::Comment(L"Set all and validate runs updated."); expected.clear(); - expected.push_back(til::rectangle{ til::point{ 0, 0 }, til::size{ 4, 1 } }); - expected.push_back(til::rectangle{ til::point{ 0, 1 }, til::size{ 4, 1 } }); - expected.push_back(til::rectangle{ til::point{ 0, 2 }, til::size{ 4, 1 } }); - expected.push_back(til::rectangle{ til::point{ 0, 3 }, til::size{ 4, 1 } }); + expected.push_back(til::rect{ til::point{ 0, 0 }, til::size{ 4, 1 } }); + expected.push_back(til::rect{ til::point{ 0, 1 }, til::size{ 4, 1 } }); + expected.push_back(til::rect{ til::point{ 0, 2 }, til::size{ 4, 1 } }); + expected.push_back(til::rect{ til::point{ 0, 3 }, til::size{ 4, 1 } }); map.set_all(); actual.clear(); @@ -1091,9 +1087,9 @@ class BitmapTests Log::Comment(L"Resize and validate runs updated."); const til::size newSize{ 3, 3 }; expected.clear(); - expected.push_back(til::rectangle{ til::point{ 0, 0 }, til::size{ 3, 1 } }); - expected.push_back(til::rectangle{ til::point{ 0, 1 }, til::size{ 3, 1 } }); - expected.push_back(til::rectangle{ til::point{ 0, 2 }, til::size{ 3, 1 } }); + expected.push_back(til::rect{ til::point{ 0, 0 }, til::size{ 3, 1 } }); + expected.push_back(til::rect{ til::point{ 0, 1 }, til::size{ 3, 1 } }); + expected.push_back(til::rect{ til::point{ 0, 2 }, til::size{ 3, 1 } }); map.resize(newSize); actual.clear(); diff --git a/src/til/ut_til/MathTests.cpp b/src/til/ut_til/MathTests.cpp index 6e031fb44d..9bad6a1243 100644 --- a/src/til/ut_til/MathTests.cpp +++ b/src/til/ut_til/MathTests.cpp @@ -13,103 +13,103 @@ class MathTests { TEST_CLASS(MathTests); - template + using FloatType = double; + using IntegralType = int; + using TargetType = int; + + static constexpr auto nan = std::numeric_limits::quiet_NaN(); + static constexpr auto infinity = std::numeric_limits::infinity(); + + template struct TestCase { TG given; - TX expected; + TargetType expected; + bool throws = false; }; - template - static void _RunCases(TilMath, const std::array, N>& cases) + template + static void _RunCases(TilMath, const std::initializer_list>& cases) { for (const auto& tc : cases) { - VERIFY_ARE_EQUAL(tc.expected, TilMath::template cast(tc.given)); + if (tc.throws) + { + VERIFY_THROWS(TilMath::template cast(tc.given), gsl::narrowing_error); + } + else + { + VERIFY_ARE_EQUAL(tc.expected, TilMath::template cast(tc.given)); + } } } - TEST_METHOD(Truncating) - { - std::array, 8> cases{ - TestCase{ 1., 1 }, - { 1.9, 1 }, - { -7.1, -7 }, - { -8.5, -8 }, - { PTRDIFF_MAX + 0.5, PTRDIFF_MAX }, - { PTRDIFF_MIN - 0.5, PTRDIFF_MIN }, - { INFINITY, PTRDIFF_MAX }, - { -INFINITY, PTRDIFF_MIN }, - }; - - _RunCases(til::math::truncating, cases); - - VERIFY_THROWS_SPECIFIC(til::math::details::truncating_t::cast(NAN), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_ABORT; }); - } - TEST_METHOD(Ceiling) { - std::array, 8> cases{ - TestCase{ 1., 1 }, - { 1.9, 2 }, - { -7.1, -7 }, - { -8.5, -8 }, - { PTRDIFF_MAX + 0.5, PTRDIFF_MAX }, - { PTRDIFF_MIN - 0.5, PTRDIFF_MIN }, - { INFINITY, PTRDIFF_MAX }, - { -INFINITY, PTRDIFF_MIN }, - }; - - _RunCases(til::math::ceiling, cases); - - VERIFY_THROWS_SPECIFIC(til::math::details::ceiling_t::cast(NAN), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_ABORT; }); + _RunCases( + til::math::ceiling, + { + { 1., 1 }, + { 1.9, 2 }, + { -7.1, -7 }, + { -8.5, -8 }, + { INT_MAX - 0.1, INT_MAX }, + { INT_MIN - 0.1, INT_MIN }, + { INT_MAX + 1.1, 0, true }, + { INT_MIN - 1.1, 0, true }, + { infinity, 0, true }, + { -infinity, 0, true }, + { nan, 0, true }, + }); } TEST_METHOD(Flooring) { - std::array, 8> cases{ - TestCase{ 1., 1 }, - { 1.9, 1 }, - { -7.1, -8 }, - { -8.5, -9 }, - { PTRDIFF_MAX + 0.5, PTRDIFF_MAX }, - { PTRDIFF_MIN - 0.5, PTRDIFF_MIN }, - { INFINITY, PTRDIFF_MAX }, - { -INFINITY, PTRDIFF_MIN }, - }; - - _RunCases(til::math::flooring, cases); - - VERIFY_THROWS_SPECIFIC(til::math::details::flooring_t::cast(NAN), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_ABORT; }); + _RunCases( + til::math::flooring, + { + { 1., 1 }, + { 1.9, 1 }, + { -7.1, -8 }, + { -8.5, -9 }, + { INT_MAX + 0.1, INT_MAX }, + { INT_MIN + 0.1, INT_MIN }, + { INT_MAX + 1.1, 0, true }, + { INT_MIN - 1.1, 0, true }, + { infinity, 0, true }, + { -infinity, 0, true }, + { nan, 0, true }, + }); } TEST_METHOD(Rounding) { - std::array, 8> cases{ - TestCase{ 1., 1 }, - { 1.9, 2 }, - { -7.1, -7 }, - { -8.5, -9 }, - { PTRDIFF_MAX + 0.5, PTRDIFF_MAX }, - { PTRDIFF_MIN - 0.5, PTRDIFF_MIN }, - { INFINITY, PTRDIFF_MAX }, - { -INFINITY, PTRDIFF_MIN }, - }; - - _RunCases(til::math::rounding, cases); - - VERIFY_THROWS_SPECIFIC(til::math::details::rounding_t::cast(NAN), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_ABORT; }); + _RunCases( + til::math::rounding, + { + { 1., 1 }, + { 1.9, 2 }, + { -7.1, -7 }, + { -8.5, -9 }, + { INT_MAX + 0.1, INT_MAX }, + { INT_MIN - 0.1, INT_MIN }, + { INT_MAX + 1.1, 0, true }, + { INT_MIN - 1.1, 0, true }, + { infinity, 0, true }, + { -infinity, 0, true }, + { nan, 0, true }, + }); } TEST_METHOD(NormalIntegers) { - std::array, 4> cases{ - TestCase{ 1, 1 }, - { -1, -1 }, - { PTRDIFF_MAX, INT_MAX }, - { PTRDIFF_MIN, INT_MIN }, - }; - - _RunCases(til::math::rounding, cases); + _RunCases( + til::math::rounding, + { + { 1, 1 }, + { -1, -1 }, + { INT_MAX, INT_MAX }, + { INT_MIN, INT_MIN }, + }); } }; diff --git a/src/til/ut_til/PointTests.cpp b/src/til/ut_til/PointTests.cpp index a98531bd15..7dce7b739c 100644 --- a/src/til/ut_til/PointTests.cpp +++ b/src/til/ut_til/PointTests.cpp @@ -16,69 +16,32 @@ class PointTests TEST_METHOD(DefaultConstruct) { const til::point pt; - VERIFY_ARE_EQUAL(0, pt._x); - VERIFY_ARE_EQUAL(0, pt._y); + VERIFY_ARE_EQUAL(0, pt.x); + VERIFY_ARE_EQUAL(0, pt.y); } TEST_METHOD(RawConstruct) { const til::point pt{ 5, 10 }; - VERIFY_ARE_EQUAL(5, pt._x); - VERIFY_ARE_EQUAL(10, pt._y); + VERIFY_ARE_EQUAL(5, pt.x); + VERIFY_ARE_EQUAL(10, pt.y); } TEST_METHOD(RawFloatingConstruct) { const til::point pt{ til::math::rounding, 3.2f, 7.6f }; - VERIFY_ARE_EQUAL(3, pt._x); - VERIFY_ARE_EQUAL(8, pt._y); - } - - TEST_METHOD(UnsignedConstruct) - { - Log::Comment(L"0.) Normal unsigned construct."); - { - const size_t x = 5; - const size_t y = 10; - - const til::point pt{ x, y }; - VERIFY_ARE_EQUAL(5, pt._x); - VERIFY_ARE_EQUAL(10, pt._y); - } - - Log::Comment(L"1.) Unsigned construct overflow on x."); - { - constexpr size_t x = std::numeric_limits().max(); - const size_t y = 10; - - auto fn = [&]() { - til::point pt{ x, y }; - }; - - VERIFY_THROWS_SPECIFIC(fn(), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_ABORT; }); - } - - Log::Comment(L"2.) Unsigned construct overflow on y."); - { - constexpr size_t y = std::numeric_limits().max(); - const size_t x = 10; - - auto fn = [&]() { - til::point pt{ x, y }; - }; - - VERIFY_THROWS_SPECIFIC(fn(), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_ABORT; }); - } + VERIFY_ARE_EQUAL(3, pt.x); + VERIFY_ARE_EQUAL(8, pt.y); } TEST_METHOD(SignedConstruct) { - const ptrdiff_t x = -5; - const ptrdiff_t y = -10; + const til::CoordType x = -5; + const til::CoordType y = -10; const til::point pt{ x, y }; - VERIFY_ARE_EQUAL(x, pt._x); - VERIFY_ARE_EQUAL(y, pt._y); + VERIFY_ARE_EQUAL(x, pt.x); + VERIFY_ARE_EQUAL(y, pt.y); } TEST_METHOD(CoordConstruct) @@ -86,8 +49,8 @@ class PointTests COORD coord{ -5, 10 }; const til::point pt{ coord }; - VERIFY_ARE_EQUAL(coord.X, pt._x); - VERIFY_ARE_EQUAL(coord.Y, pt._y); + VERIFY_ARE_EQUAL(coord.X, pt.x); + VERIFY_ARE_EQUAL(coord.Y, pt.y); } TEST_METHOD(PointConstruct) @@ -95,41 +58,41 @@ class PointTests POINT point{ 5, -10 }; const til::point pt{ point }; - VERIFY_ARE_EQUAL(point.x, pt._x); - VERIFY_ARE_EQUAL(point.y, pt._y); + VERIFY_ARE_EQUAL(point.x, pt.x); + VERIFY_ARE_EQUAL(point.y, pt.y); } TEST_METHOD(Equality) { - Log::Comment(L"0.) Equal."); + Log::Comment(L"Equal."); { const til::point s1{ 5, 10 }; const til::point s2{ 5, 10 }; VERIFY_IS_TRUE(s1 == s2); } - Log::Comment(L"1.) Left Width changed."); + Log::Comment(L"Left Width changed."); { const til::point s1{ 4, 10 }; const til::point s2{ 5, 10 }; VERIFY_IS_FALSE(s1 == s2); } - Log::Comment(L"2.) Right Width changed."); + Log::Comment(L"Right Width changed."); { const til::point s1{ 5, 10 }; const til::point s2{ 6, 10 }; VERIFY_IS_FALSE(s1 == s2); } - Log::Comment(L"3.) Left Height changed."); + Log::Comment(L"Left Height changed."); { const til::point s1{ 5, 9 }; const til::point s2{ 5, 10 }; VERIFY_IS_FALSE(s1 == s2); } - Log::Comment(L"4.) Right Height changed."); + Log::Comment(L"Right Height changed."); { const til::point s1{ 5, 10 }; const til::point s2{ 5, 11 }; @@ -139,35 +102,35 @@ class PointTests TEST_METHOD(Inequality) { - Log::Comment(L"0.) Equal."); + Log::Comment(L"Equal."); { const til::point s1{ 5, 10 }; const til::point s2{ 5, 10 }; VERIFY_IS_FALSE(s1 != s2); } - Log::Comment(L"1.) Left Width changed."); + Log::Comment(L"Left Width changed."); { const til::point s1{ 4, 10 }; const til::point s2{ 5, 10 }; VERIFY_IS_TRUE(s1 != s2); } - Log::Comment(L"2.) Right Width changed."); + Log::Comment(L"Right Width changed."); { const til::point s1{ 5, 10 }; const til::point s2{ 6, 10 }; VERIFY_IS_TRUE(s1 != s2); } - Log::Comment(L"3.) Left Height changed."); + Log::Comment(L"Left Height changed."); { const til::point s1{ 5, 9 }; const til::point s2{ 5, 10 }; VERIFY_IS_TRUE(s1 != s2); } - Log::Comment(L"4.) Right Height changed."); + Log::Comment(L"Right Height changed."); { const til::point s1{ 5, 10 }; const til::point s2{ 5, 11 }; @@ -177,35 +140,35 @@ class PointTests TEST_METHOD(LessThanOrEqual) { - Log::Comment(L"0.) Equal."); + Log::Comment(L"Equal."); { const til::point s1{ 5, 10 }; const til::point s2{ 5, 10 }; VERIFY_IS_TRUE(s1 <= s2); } - Log::Comment(L"1.) Left Width changed."); + Log::Comment(L"Left Width changed."); { const til::point s1{ 4, 10 }; const til::point s2{ 5, 10 }; VERIFY_IS_TRUE(s1 <= s2); } - Log::Comment(L"2.) Right Width changed."); + Log::Comment(L"Right Width changed."); { const til::point s1{ 5, 10 }; const til::point s2{ 6, 10 }; VERIFY_IS_TRUE(s1 <= s2); } - Log::Comment(L"3.) Left Height changed."); + Log::Comment(L"Left Height changed."); { const til::point s1{ 5, 9 }; const til::point s2{ 5, 10 }; VERIFY_IS_TRUE(s1 <= s2); } - Log::Comment(L"4.) Right Height changed."); + Log::Comment(L"Right Height changed."); { const til::point s1{ 5, 10 }; const til::point s2{ 5, 11 }; @@ -215,35 +178,35 @@ class PointTests TEST_METHOD(GreaterThanOrEqual) { - Log::Comment(L"0.) Equal."); + Log::Comment(L"Equal."); { const til::point s1{ 5, 10 }; const til::point s2{ 5, 10 }; VERIFY_IS_TRUE(s1 >= s2); } - Log::Comment(L"1.) Left Width changed."); + Log::Comment(L"Left Width changed."); { const til::point s1{ 4, 10 }; const til::point s2{ 5, 10 }; VERIFY_IS_FALSE(s1 >= s2); } - Log::Comment(L"2.) Right Width changed."); + Log::Comment(L"Right Width changed."); { const til::point s1{ 5, 10 }; const til::point s2{ 6, 10 }; VERIFY_IS_FALSE(s1 >= s2); } - Log::Comment(L"3.) Left Height changed."); + Log::Comment(L"Left Height changed."); { const til::point s1{ 5, 9 }; const til::point s2{ 5, 10 }; VERIFY_IS_FALSE(s1 >= s2); } - Log::Comment(L"4.) Right Height changed."); + Log::Comment(L"Right Height changed."); { const til::point s1{ 5, 10 }; const til::point s2{ 5, 11 }; @@ -253,51 +216,51 @@ class PointTests TEST_METHOD(Addition) { - Log::Comment(L"0.) Addition of two things that should be in bounds."); + Log::Comment(L"Addition of two things that should be in bounds."); { const til::point pt{ 5, 10 }; const til::point pt2{ 23, 47 }; - const til::point expected{ pt.x() + pt2.x(), pt.y() + pt2.y() }; + const til::point expected{ pt.x + pt2.x, pt.y + pt2.y }; VERIFY_ARE_EQUAL(expected, pt + pt2); } - Log::Comment(L"1.) Addition results in value that is too large (x)."); + Log::Comment(L"Addition results in value that is too large (x)."); { - constexpr ptrdiff_t bigSize = std::numeric_limits().max(); - const til::point pt{ bigSize, static_cast(0) }; + constexpr auto bigSize = std::numeric_limits().max(); + const til::point pt{ bigSize, static_cast(0) }; const til::point pt2{ 1, 1 }; auto fn = [&]() { pt + pt2; }; - VERIFY_THROWS_SPECIFIC(fn(), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_ABORT; }); + VERIFY_THROWS(fn(), gsl::narrowing_error); } - Log::Comment(L"2.) Addition results in value that is too large (y)."); + Log::Comment(L"Addition results in value that is too large (y)."); { - constexpr ptrdiff_t bigSize = std::numeric_limits().max(); - const til::point pt{ static_cast(0), bigSize }; + constexpr auto bigSize = std::numeric_limits().max(); + const til::point pt{ static_cast(0), bigSize }; const til::point pt2{ 1, 1 }; auto fn = [&]() { pt + pt2; }; - VERIFY_THROWS_SPECIFIC(fn(), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_ABORT; }); + VERIFY_THROWS(fn(), gsl::narrowing_error); } } TEST_METHOD(AdditionInplace) { - Log::Comment(L"0.) Addition of two things that should be in bounds."); + Log::Comment(L"Addition of two things that should be in bounds."); { const til::point pt{ 5, 10 }; const til::point pt2{ 23, 47 }; - const til::point expected{ pt.x() + pt2.x(), pt.y() + pt2.y() }; + const til::point expected{ pt.x + pt2.x, pt.y + pt2.y }; auto actual = pt; actual += pt2; @@ -305,10 +268,10 @@ class PointTests VERIFY_ARE_EQUAL(expected, actual); } - Log::Comment(L"1.) Addition results in value that is too large (x)."); + Log::Comment(L"Addition results in value that is too large (x)."); { - constexpr ptrdiff_t bigSize = std::numeric_limits().max(); - const til::point pt{ bigSize, static_cast(0) }; + constexpr auto bigSize = std::numeric_limits().max(); + const til::point pt{ bigSize, static_cast(0) }; const til::point pt2{ 1, 1 }; auto fn = [&]() { @@ -316,13 +279,13 @@ class PointTests actual += pt2; }; - VERIFY_THROWS_SPECIFIC(fn(), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_ABORT; }); + VERIFY_THROWS(fn(), gsl::narrowing_error); } - Log::Comment(L"2.) Addition results in value that is too large (y)."); + Log::Comment(L"Addition results in value that is too large (y)."); { - constexpr ptrdiff_t bigSize = std::numeric_limits().max(); - const til::point pt{ static_cast(0), bigSize }; + constexpr auto bigSize = std::numeric_limits().max(); + const til::point pt{ static_cast(0), bigSize }; const til::point pt2{ 1, 1 }; auto fn = [&]() { @@ -330,57 +293,57 @@ class PointTests actual += pt2; }; - VERIFY_THROWS_SPECIFIC(fn(), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_ABORT; }); + VERIFY_THROWS(fn(), gsl::narrowing_error); } } TEST_METHOD(Subtraction) { - Log::Comment(L"0.) Subtraction of two things that should be in bounds."); + Log::Comment(L"Subtraction of two things that should be in bounds."); { const til::point pt{ 5, 10 }; const til::point pt2{ 23, 47 }; - const til::point expected{ pt.x() - pt2.x(), pt.y() - pt2.y() }; + const til::point expected{ pt.x - pt2.x, pt.y - pt2.y }; VERIFY_ARE_EQUAL(expected, pt - pt2); } - Log::Comment(L"1.) Subtraction results in value that is too small (x)."); + Log::Comment(L"Subtraction results in value that is too small (x)."); { - constexpr ptrdiff_t bigSize = std::numeric_limits().max(); - const til::point pt{ bigSize, static_cast(0) }; + constexpr auto bigSize = std::numeric_limits().max(); + const til::point pt{ bigSize, static_cast(0) }; const til::point pt2{ -2, -2 }; auto fn = [&]() { pt2 - pt; }; - VERIFY_THROWS_SPECIFIC(fn(), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_ABORT; }); + VERIFY_THROWS(fn(), gsl::narrowing_error); } - Log::Comment(L"2.) Subtraction results in value that is too small (y)."); + Log::Comment(L"Subtraction results in value that is too small (y)."); { - constexpr ptrdiff_t bigSize = std::numeric_limits().max(); - const til::point pt{ static_cast(0), bigSize }; + constexpr auto bigSize = std::numeric_limits().max(); + const til::point pt{ static_cast(0), bigSize }; const til::point pt2{ -2, -2 }; auto fn = [&]() { pt2 - pt; }; - VERIFY_THROWS_SPECIFIC(fn(), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_ABORT; }); + VERIFY_THROWS(fn(), gsl::narrowing_error); } } TEST_METHOD(SubtractionInplace) { - Log::Comment(L"0.) Subtraction of two things that should be in bounds."); + Log::Comment(L"Subtraction of two things that should be in bounds."); { const til::point pt{ 5, 10 }; const til::point pt2{ 23, 47 }; - const til::point expected{ pt.x() - pt2.x(), pt.y() - pt2.y() }; + const til::point expected{ pt.x - pt2.x, pt.y - pt2.y }; auto actual = pt; actual -= pt2; @@ -388,10 +351,10 @@ class PointTests VERIFY_ARE_EQUAL(expected, actual); } - Log::Comment(L"1.) Subtraction results in value that is too small (x)."); + Log::Comment(L"Subtraction results in value that is too small (x)."); { - constexpr ptrdiff_t bigSize = std::numeric_limits().max(); - const til::point pt{ bigSize, static_cast(0) }; + constexpr auto bigSize = std::numeric_limits().max(); + const til::point pt{ bigSize, static_cast(0) }; const til::point pt2{ -2, -2 }; auto fn = [&]() { @@ -399,13 +362,13 @@ class PointTests actual -= pt; }; - VERIFY_THROWS_SPECIFIC(fn(), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_ABORT; }); + VERIFY_THROWS(fn(), gsl::narrowing_error); } - Log::Comment(L"2.) Subtraction results in value that is too small (y)."); + Log::Comment(L"Subtraction results in value that is too small (y)."); { - constexpr ptrdiff_t bigSize = std::numeric_limits().max(); - const til::point pt{ static_cast(0), bigSize }; + constexpr auto bigSize = std::numeric_limits().max(); + const til::point pt{ static_cast(0), bigSize }; const til::point pt2{ -2, -2 }; auto fn = [&]() { @@ -413,57 +376,57 @@ class PointTests actual -= pt; }; - VERIFY_THROWS_SPECIFIC(fn(), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_ABORT; }); + VERIFY_THROWS(fn(), gsl::narrowing_error); } } TEST_METHOD(Multiplication) { - Log::Comment(L"0.) Multiplication of two things that should be in bounds."); + Log::Comment(L"Multiplication of two things that should be in bounds."); { const til::point pt{ 5, 10 }; const til::point pt2{ 23, 47 }; - const til::point expected{ pt.x() * pt2.x(), pt.y() * pt2.y() }; + const til::point expected{ pt.x * pt2.x, pt.y * pt2.y }; VERIFY_ARE_EQUAL(expected, pt * pt2); } - Log::Comment(L"1.) Multiplication results in value that is too large (x)."); + Log::Comment(L"Multiplication results in value that is too large (x)."); { - constexpr ptrdiff_t bigSize = std::numeric_limits().max(); - const til::point pt{ bigSize, static_cast(0) }; + constexpr auto bigSize = std::numeric_limits().max(); + const til::point pt{ bigSize, static_cast(0) }; const til::point pt2{ 10, 10 }; auto fn = [&]() { pt* pt2; }; - VERIFY_THROWS_SPECIFIC(fn(), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_ABORT; }); + VERIFY_THROWS(fn(), gsl::narrowing_error); } - Log::Comment(L"2.) Multiplication results in value that is too large (y)."); + Log::Comment(L"Multiplication results in value that is too large (y)."); { - constexpr ptrdiff_t bigSize = std::numeric_limits().max(); - const til::point pt{ static_cast(0), bigSize }; + constexpr auto bigSize = std::numeric_limits().max(); + const til::point pt{ static_cast(0), bigSize }; const til::point pt2{ 10, 10 }; auto fn = [&]() { pt* pt2; }; - VERIFY_THROWS_SPECIFIC(fn(), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_ABORT; }); + VERIFY_THROWS(fn(), gsl::narrowing_error); } } TEST_METHOD(MultiplicationInplace) { - Log::Comment(L"0.) Multiplication of two things that should be in bounds."); + Log::Comment(L"Multiplication of two things that should be in bounds."); { const til::point pt{ 5, 10 }; const til::point pt2{ 23, 47 }; - const til::point expected{ pt.x() * pt2.x(), pt.y() * pt2.y() }; + const til::point expected{ pt.x * pt2.x, pt.y * pt2.y }; auto actual = pt; actual *= pt2; @@ -471,10 +434,10 @@ class PointTests VERIFY_ARE_EQUAL(expected, actual); } - Log::Comment(L"1.) Multiplication results in value that is too large (x)."); + Log::Comment(L"Multiplication results in value that is too large (x)."); { - constexpr ptrdiff_t bigSize = std::numeric_limits().max(); - const til::point pt{ bigSize, static_cast(0) }; + constexpr auto bigSize = std::numeric_limits().max(); + const til::point pt{ bigSize, static_cast(0) }; const til::point pt2{ 10, 10 }; auto fn = [&]() { @@ -482,13 +445,13 @@ class PointTests actual *= pt2; }; - VERIFY_THROWS_SPECIFIC(fn(), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_ABORT; }); + VERIFY_THROWS(fn(), gsl::narrowing_error); } - Log::Comment(L"2.) Multiplication results in value that is too large (y)."); + Log::Comment(L"Multiplication results in value that is too large (y)."); { - constexpr ptrdiff_t bigSize = std::numeric_limits().max(); - const til::point pt{ static_cast(0), bigSize }; + constexpr auto bigSize = std::numeric_limits().max(); + const til::point pt{ static_cast(0), bigSize }; const til::point pt2{ 10, 10 }; auto fn = [&]() { @@ -496,81 +459,54 @@ class PointTests actual *= pt2; }; - VERIFY_THROWS_SPECIFIC(fn(), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_ABORT; }); - } - } - - TEST_METHOD(ScaleByFloat) - { - Log::Comment(L"0.) Scale that should be in bounds."); - { - const til::point pt{ 5, 10 }; - const float scale = 1.783f; - - const til::point expected{ static_cast(ceil(5 * scale)), static_cast(ceil(10 * scale)) }; - - const auto actual = pt.scale(til::math::ceiling, scale); - - VERIFY_ARE_EQUAL(expected, actual); - } - - Log::Comment(L"1.) Scale results in value that is too large."); - { - const til::point pt{ 5, 10 }; - constexpr float scale = std::numeric_limits().max(); - - auto fn = [&]() { - pt.scale(til::math::ceiling, scale); - }; - - VERIFY_THROWS_SPECIFIC(fn(), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_ABORT; }); + VERIFY_THROWS(fn(), gsl::narrowing_error); } } TEST_METHOD(Division) { - Log::Comment(L"0.) Division of two things that should be in bounds."); + Log::Comment(L"Division of two things that should be in bounds."); { const til::point pt{ 555, 510 }; const til::point pt2{ 23, 47 }; - const til::point expected{ pt.x() / pt2.x(), pt.y() / pt2.y() }; + const til::point expected{ pt.x / pt2.x, pt.y / pt2.y }; VERIFY_ARE_EQUAL(expected, pt / pt2); } - Log::Comment(L"1.) Division by zero"); + Log::Comment(L"Division by zero"); { - constexpr ptrdiff_t bigSize = std::numeric_limits().max(); - const til::point pt{ bigSize, static_cast(0) }; + constexpr auto bigSize = std::numeric_limits().max(); + const til::point pt{ bigSize, static_cast(0) }; const til::point pt2{ 1, 1 }; auto fn = [&]() { pt2 / pt; }; - VERIFY_THROWS_SPECIFIC(fn(), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_ABORT; }); + VERIFY_THROWS(fn(), gsl::narrowing_error); } } TEST_METHOD(DivisionInplace) { - Log::Comment(L"0.) Division of two things that should be in bounds."); + Log::Comment(L"Division of two things that should be in bounds."); { const til::point pt{ 555, 510 }; const til::point pt2{ 23, 47 }; - const til::point expected{ pt.x() / pt2.x(), pt.y() / pt2.y() }; + const til::point expected{ pt.x / pt2.x, pt.y / pt2.y }; auto actual = pt; actual /= pt2; VERIFY_ARE_EQUAL(expected, actual); } - Log::Comment(L"1.) Division by zero"); + Log::Comment(L"Division by zero"); { - constexpr ptrdiff_t bigSize = std::numeric_limits().max(); - const til::point pt{ bigSize, static_cast(0) }; + constexpr auto bigSize = std::numeric_limits().max(); + const til::point pt{ bigSize, static_cast(0) }; const til::point pt2{ 1, 1 }; auto fn = [&]() { @@ -578,125 +514,76 @@ class PointTests actual /= pt; }; - VERIFY_THROWS_SPECIFIC(fn(), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_ABORT; }); + VERIFY_THROWS(fn(), gsl::narrowing_error); } } - TEST_METHOD(X) - { - const til::point pt{ 5, 10 }; - VERIFY_ARE_EQUAL(pt._x, pt.x()); - } - TEST_METHOD(XCast) { const til::point pt{ 5, 10 }; - VERIFY_ARE_EQUAL(static_cast(pt._x), pt.x()); - } - - TEST_METHOD(Y) - { - const til::point pt{ 5, 10 }; - VERIFY_ARE_EQUAL(pt._y, pt.y()); + VERIFY_ARE_EQUAL(static_cast(pt.x), pt.narrow_x()); } TEST_METHOD(YCast) { const til::point pt{ 5, 10 }; - VERIFY_ARE_EQUAL(static_cast(pt._x), pt.x()); - } - - TEST_METHOD(CastToCoord) - { - Log::Comment(L"0.) Typical situation."); - { - const til::point pt{ 5, 10 }; - COORD val = pt; - VERIFY_ARE_EQUAL(5, val.X); - VERIFY_ARE_EQUAL(10, val.Y); - } - - Log::Comment(L"1.) Overflow on x."); - { - constexpr ptrdiff_t x = std::numeric_limits().max(); - const ptrdiff_t y = 10; - const til::point pt{ x, y }; - - auto fn = [&]() { - COORD val = pt; - }; - - VERIFY_THROWS_SPECIFIC(fn(), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_ABORT; }); - } - - Log::Comment(L"2.) Overflow on y."); - { - constexpr ptrdiff_t y = std::numeric_limits().max(); - const ptrdiff_t x = 10; - const til::point pt{ x, y }; - - auto fn = [&]() { - COORD val = pt; - }; - - VERIFY_THROWS_SPECIFIC(fn(), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_ABORT; }); - } + VERIFY_ARE_EQUAL(static_cast(pt.x), pt.narrow_x()); } TEST_METHOD(CastToPoint) { - Log::Comment(L"0.) Typical situation."); + Log::Comment(L"Typical situation."); { const til::point pt{ 5, 10 }; - POINT val = pt; + POINT val = pt.to_win32_point(); VERIFY_ARE_EQUAL(5, val.x); VERIFY_ARE_EQUAL(10, val.y); } - Log::Comment(L"1.) Fit max x into POINT (may overflow)."); + Log::Comment(L"Fit max x into POINT (may overflow)."); { - constexpr ptrdiff_t x = std::numeric_limits().max(); - const ptrdiff_t y = 10; + constexpr auto x = std::numeric_limits().max(); + const til::CoordType y = 10; const til::point pt{ x, y }; - // On some platforms, ptrdiff_t will fit inside x/y + // On some platforms, til::CoordType will fit inside x/y const bool overflowExpected = x > std::numeric_limits().max(); if (overflowExpected) { auto fn = [&]() { - POINT val = pt; + POINT val = pt.to_win32_point(); }; - VERIFY_THROWS_SPECIFIC(fn(), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_ABORT; }); + VERIFY_THROWS(fn(), gsl::narrowing_error); } else { - POINT val = pt; + POINT val = pt.to_win32_point(); VERIFY_ARE_EQUAL(x, val.x); } } - Log::Comment(L"2.) Fit max y into POINT (may overflow)."); + Log::Comment(L"Fit max y into POINT (may overflow)."); { - constexpr ptrdiff_t y = std::numeric_limits().max(); - const ptrdiff_t x = 10; + constexpr auto y = std::numeric_limits().max(); + const til::CoordType x = 10; const til::point pt{ x, y }; - // On some platforms, ptrdiff_t will fit inside x/y + // On some platforms, til::CoordType will fit inside x/y const bool overflowExpected = y > std::numeric_limits().max(); if (overflowExpected) { auto fn = [&]() { - POINT val = pt; + POINT val = pt.to_win32_point(); }; - VERIFY_THROWS_SPECIFIC(fn(), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_ABORT; }); + VERIFY_THROWS(fn(), gsl::narrowing_error); } else { - POINT val = pt; + POINT val = pt.to_win32_point(); VERIFY_ARE_EQUAL(y, val.y); } } @@ -704,66 +591,66 @@ class PointTests TEST_METHOD(CastToD2D1Point2F) { - Log::Comment(L"0.) Typical situation."); + Log::Comment(L"Typical situation."); { const til::point pt{ 5, 10 }; - D2D1_POINT_2F val = pt; + D2D1_POINT_2F val = pt.to_d2d_point(); VERIFY_ARE_EQUAL(5, val.x); VERIFY_ARE_EQUAL(10, val.y); } - // All ptrdiff_ts fit into a float, so there's no exception tests. + // All til::CoordTypes fit into a float, so there's no exception tests. } TEST_METHOD(Scaling) { - Log::Comment(L"0.) Multiplication of two things that should be in bounds."); + Log::Comment(L"Multiplication of two things that should be in bounds."); { const til::point pt{ 5, 10 }; const int scale = 23; - const til::point expected{ pt.x() * scale, pt.y() * scale }; + const til::point expected{ pt.x * scale, pt.y * scale }; VERIFY_ARE_EQUAL(expected, pt * scale); } - Log::Comment(L"1.) Multiplication results in value that is too large (x)."); + Log::Comment(L"Multiplication results in value that is too large (x)."); { - constexpr ptrdiff_t bigSize = std::numeric_limits().max(); - const til::point pt{ bigSize, static_cast(0) }; + constexpr auto bigSize = std::numeric_limits().max(); + const til::point pt{ bigSize, static_cast(0) }; const int scale = 10; auto fn = [&]() { pt* scale; }; - VERIFY_THROWS_SPECIFIC(fn(), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_ABORT; }); + VERIFY_THROWS(fn(), gsl::narrowing_error); } - Log::Comment(L"2.) Multiplication results in value that is too large (y)."); + Log::Comment(L"Multiplication results in value that is too large (y)."); { - constexpr ptrdiff_t bigSize = std::numeric_limits().max(); - const til::point pt{ static_cast(0), bigSize }; + constexpr auto bigSize = std::numeric_limits().max(); + const til::point pt{ static_cast(0), bigSize }; const int scale = 10; auto fn = [&]() { pt* scale; }; - VERIFY_THROWS_SPECIFIC(fn(), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_ABORT; }); + VERIFY_THROWS(fn(), gsl::narrowing_error); } - Log::Comment(L"3.) Division of two things that should be in bounds."); + Log::Comment(L"Division of two things that should be in bounds."); { const til::point pt{ 555, 510 }; const int scale = 23; - const til::point expected{ pt.x() / scale, pt.y() / scale }; + const til::point expected{ pt.x / scale, pt.y / scale }; VERIFY_ARE_EQUAL(expected, pt / scale); } - Log::Comment(L"4.) Division by zero"); + Log::Comment(L"Division by zero"); { const til::point pt{ 1, 1 }; const int scale = 0; @@ -772,148 +659,70 @@ class PointTests pt / scale; }; - VERIFY_THROWS_SPECIFIC(fn(), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_ABORT; }); - } - - Log::Comment(L"5.) Multiplication of floats that should be in bounds."); - { - const til::point pt{ 3, 10 }; - const float scale = 5.5f; - - // 3 * 5.5 = 15.5, which we'll round to 15 - const til::point expected{ 16, 55 }; - - VERIFY_ARE_EQUAL(expected, pt * scale); - } - - Log::Comment(L"6.) Multiplication of doubles that should be in bounds."); - { - const til::point pt{ 3, 10 }; - const double scale = 5.5f; - - // 3 * 5.5 = 15.5, which we'll round to 15 - const til::point expected{ 16, 55 }; - - VERIFY_ARE_EQUAL(expected, pt * scale); - } - - Log::Comment(L"5.) Division of floats that should be in bounds."); - { - const til::point pt{ 15, 10 }; - const float scale = 2.0f; - - // 15 / 2 = 7.5, which we'll floor to 7 - const til::point expected{ 7, 5 }; - - VERIFY_ARE_EQUAL(expected, pt / scale); - } - - Log::Comment(L"6.) Division of doubles that should be in bounds."); - { - const til::point pt{ 15, 10 }; - const double scale = 2.0; - - // 15 / 2 = 7.5, which we'll floor to 7 - const til::point expected{ 7, 5 }; - - VERIFY_ARE_EQUAL(expected, pt / scale); + VERIFY_THROWS(fn(), gsl::narrowing_error); } } - template - struct PointTypeWith_xy - { - T x, y; - }; - template - struct PointTypeWith_XY - { - T X, Y; - }; TEST_METHOD(CastFromFloatWithMathTypes) { - PointTypeWith_xy xyFloatIntegral{ 1.f, 2.f }; - PointTypeWith_xy xyFloat{ 1.6f, 2.4f }; - PointTypeWith_XY XYDoubleIntegral{ 3., 4. }; - PointTypeWith_XY XYDouble{ 3.6, 4.4 }; - Log::Comment(L"0.) Ceiling"); + Log::Comment(L"Ceiling"); { { - til::point converted{ til::math::ceiling, xyFloatIntegral }; + til::point converted{ til::math::ceiling, 1.f, 2.f }; VERIFY_ARE_EQUAL((til::point{ 1, 2 }), converted); } { - til::point converted{ til::math::ceiling, xyFloat }; + til::point converted{ til::math::ceiling, 1.6f, 2.4f }; VERIFY_ARE_EQUAL((til::point{ 2, 3 }), converted); } { - til::point converted{ til::math::ceiling, XYDoubleIntegral }; + til::point converted{ til::math::ceiling, 3., 4. }; VERIFY_ARE_EQUAL((til::point{ 3, 4 }), converted); } { - til::point converted{ til::math::ceiling, XYDouble }; + til::point converted{ til::math::ceiling, 3.6, 4.4 }; VERIFY_ARE_EQUAL((til::point{ 4, 5 }), converted); } } - Log::Comment(L"1.) Flooring"); + Log::Comment(L"Flooring"); { { - til::point converted{ til::math::flooring, xyFloatIntegral }; + til::point converted{ til::math::flooring, 1.f, 2.f }; VERIFY_ARE_EQUAL((til::point{ 1, 2 }), converted); } { - til::point converted{ til::math::flooring, xyFloat }; + til::point converted{ til::math::flooring, 1.6f, 2.4f }; VERIFY_ARE_EQUAL((til::point{ 1, 2 }), converted); } { - til::point converted{ til::math::flooring, XYDoubleIntegral }; + til::point converted{ til::math::flooring, 3., 4. }; VERIFY_ARE_EQUAL((til::point{ 3, 4 }), converted); } { - til::point converted{ til::math::flooring, XYDouble }; + til::point converted{ til::math::flooring, 3.6, 4.4 }; VERIFY_ARE_EQUAL((til::point{ 3, 4 }), converted); } } - Log::Comment(L"2.) Rounding"); + Log::Comment(L"Rounding"); { { - til::point converted{ til::math::rounding, xyFloatIntegral }; + til::point converted{ til::math::rounding, 1.f, 2.f }; VERIFY_ARE_EQUAL((til::point{ 1, 2 }), converted); } { - til::point converted{ til::math::rounding, xyFloat }; + til::point converted{ til::math::rounding, 1.6f, 2.4f }; VERIFY_ARE_EQUAL((til::point{ 2, 2 }), converted); } { - til::point converted{ til::math::rounding, XYDoubleIntegral }; + til::point converted{ til::math::rounding, 3., 4. }; VERIFY_ARE_EQUAL((til::point{ 3, 4 }), converted); } { - til::point converted{ til::math::rounding, XYDouble }; + til::point converted{ til::math::rounding, 3.6, 4.4 }; VERIFY_ARE_EQUAL((til::point{ 4, 4 }), converted); } } - - Log::Comment(L"3.) Truncating"); - { - { - til::point converted{ til::math::truncating, xyFloatIntegral }; - VERIFY_ARE_EQUAL((til::point{ 1, 2 }), converted); - } - { - til::point converted{ til::math::truncating, xyFloat }; - VERIFY_ARE_EQUAL((til::point{ 1, 2 }), converted); - } - { - til::point converted{ til::math::truncating, XYDoubleIntegral }; - VERIFY_ARE_EQUAL((til::point{ 3, 4 }), converted); - } - { - til::point converted{ til::math::truncating, XYDouble }; - VERIFY_ARE_EQUAL((til::point{ 3, 4 }), converted); - } - } } }; diff --git a/src/til/ut_til/RectangleTests.cpp b/src/til/ut_til/RectangleTests.cpp index c79d2c8cd4..364fd046f4 100644 --- a/src/til/ut_til/RectangleTests.cpp +++ b/src/til/ut_til/RectangleTests.cpp @@ -3,8 +3,6 @@ #include "precomp.h" -#include "til/rectangle.h" - using namespace WEX::Common; using namespace WEX::Logging; using namespace WEX::TestExecution; @@ -15,202 +13,95 @@ class RectangleTests TEST_METHOD(DefaultConstruct) { - const til::rectangle rc; - VERIFY_ARE_EQUAL(0, rc._topLeft.x()); - VERIFY_ARE_EQUAL(0, rc._topLeft.y()); - VERIFY_ARE_EQUAL(0, rc._bottomRight.x()); - VERIFY_ARE_EQUAL(0, rc._bottomRight.y()); + const til::rect rc; + VERIFY_ARE_EQUAL(0, rc.left); + VERIFY_ARE_EQUAL(0, rc.top); + VERIFY_ARE_EQUAL(0, rc.right); + VERIFY_ARE_EQUAL(0, rc.bottom); } TEST_METHOD(RawConstruct) { - const til::rectangle rc{ 5, 10, 15, 20 }; - VERIFY_ARE_EQUAL(5, rc._topLeft.x()); - VERIFY_ARE_EQUAL(10, rc._topLeft.y()); - VERIFY_ARE_EQUAL(15, rc._bottomRight.x()); - VERIFY_ARE_EQUAL(20, rc._bottomRight.y()); - } - - TEST_METHOD(UnsignedConstruct) - { - Log::Comment(L"0.) Normal unsigned construct."); - { - const size_t l = 5; - const size_t t = 10; - const size_t r = 15; - const size_t b = 20; - - const til::rectangle rc{ l, t, r, b }; - VERIFY_ARE_EQUAL(5, rc._topLeft.x()); - VERIFY_ARE_EQUAL(10, rc._topLeft.y()); - VERIFY_ARE_EQUAL(15, rc._bottomRight.x()); - VERIFY_ARE_EQUAL(20, rc._bottomRight.y()); - } - - Log::Comment(L"1.) Unsigned construct overflow on left."); - { - constexpr size_t l = std::numeric_limits().max(); - const size_t t = 10; - const size_t r = 15; - const size_t b = 20; - - auto fn = [&]() { - const til::rectangle rc{ l, t, r, b }; - }; - - VERIFY_THROWS_SPECIFIC(fn(), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_ABORT; }); - } - - Log::Comment(L"2.) Unsigned construct overflow on top."); - { - const size_t l = 5; - constexpr size_t t = std::numeric_limits().max(); - const size_t r = 15; - const size_t b = 20; - - auto fn = [&]() { - const til::rectangle rc{ l, t, r, b }; - }; - - VERIFY_THROWS_SPECIFIC(fn(), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_ABORT; }); - } - - Log::Comment(L"3.) Unsigned construct overflow on right."); - { - const size_t l = 5; - const size_t t = 10; - constexpr size_t r = std::numeric_limits().max(); - const size_t b = 20; - - auto fn = [&]() { - const til::rectangle rc{ l, t, r, b }; - }; - - VERIFY_THROWS_SPECIFIC(fn(), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_ABORT; }); - } - - Log::Comment(L"4.) Unsigned construct overflow on bottom."); - { - const size_t l = 5; - const size_t t = 10; - const size_t r = 15; - constexpr size_t b = std::numeric_limits().max(); - - auto fn = [&]() { - const til::rectangle rc{ l, t, r, b }; - }; - - VERIFY_THROWS_SPECIFIC(fn(), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_ABORT; }); - } + const til::rect rc{ 5, 10, 15, 20 }; + VERIFY_ARE_EQUAL(5, rc.left); + VERIFY_ARE_EQUAL(10, rc.top); + VERIFY_ARE_EQUAL(15, rc.right); + VERIFY_ARE_EQUAL(20, rc.bottom); } TEST_METHOD(SignedConstruct) { - const ptrdiff_t l = 5; - const ptrdiff_t t = 10; - const ptrdiff_t r = 15; - const ptrdiff_t b = 20; + const auto l = 5; + const auto t = 10; + const auto r = 15; + const auto b = 20; - const til::rectangle rc{ l, t, r, b }; - VERIFY_ARE_EQUAL(5, rc._topLeft.x()); - VERIFY_ARE_EQUAL(10, rc._topLeft.y()); - VERIFY_ARE_EQUAL(15, rc._bottomRight.x()); - VERIFY_ARE_EQUAL(20, rc._bottomRight.y()); - } - - TEST_METHOD(SinglePointConstruct) - { - Log::Comment(L"0.) Normal Case"); - { - const til::rectangle rc{ til::point{ 4, 8 } }; - VERIFY_ARE_EQUAL(4, rc._topLeft.x()); - VERIFY_ARE_EQUAL(8, rc._topLeft.y()); - VERIFY_ARE_EQUAL(5, rc._bottomRight.x()); - VERIFY_ARE_EQUAL(9, rc._bottomRight.y()); - } - - Log::Comment(L"1.) Overflow x-dimension case."); - { - auto fn = [&]() { - constexpr ptrdiff_t x = std::numeric_limits().max(); - const ptrdiff_t y = 0; - const til::rectangle rc{ til::point{ x, y } }; - }; - - VERIFY_THROWS_SPECIFIC(fn(), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_ABORT; }); - } - - Log::Comment(L"1.) Overflow y-dimension case."); - { - auto fn = [&]() { - const ptrdiff_t x = 0; - constexpr ptrdiff_t y = std::numeric_limits().max(); - const til::rectangle rc{ til::point{ x, y } }; - }; - - VERIFY_THROWS_SPECIFIC(fn(), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_ABORT; }); - } + const til::rect rc{ l, t, r, b }; + VERIFY_ARE_EQUAL(5, rc.left); + VERIFY_ARE_EQUAL(10, rc.top); + VERIFY_ARE_EQUAL(15, rc.right); + VERIFY_ARE_EQUAL(20, rc.bottom); } TEST_METHOD(TwoPointsConstruct) { - const ptrdiff_t l = 5; - const ptrdiff_t t = 10; - const ptrdiff_t r = 15; - const ptrdiff_t b = 20; + const auto l = 5; + const auto t = 10; + const auto r = 15; + const auto b = 20; - const til::rectangle rc{ til::point{ l, t }, til::point{ r, b } }; - VERIFY_ARE_EQUAL(5, rc._topLeft.x()); - VERIFY_ARE_EQUAL(10, rc._topLeft.y()); - VERIFY_ARE_EQUAL(15, rc._bottomRight.x()); - VERIFY_ARE_EQUAL(20, rc._bottomRight.y()); + const til::rect rc{ til::point{ l, t }, til::point{ r, b } }; + VERIFY_ARE_EQUAL(5, rc.left); + VERIFY_ARE_EQUAL(10, rc.top); + VERIFY_ARE_EQUAL(15, rc.right); + VERIFY_ARE_EQUAL(20, rc.bottom); } TEST_METHOD(SizeOnlyConstruct) { // Size will match bottom right point because - // til::rectangle is exclusive. + // til::rect is exclusive. const auto sz = til::size{ 5, 10 }; - const til::rectangle rc{ sz }; - VERIFY_ARE_EQUAL(0, rc._topLeft.x()); - VERIFY_ARE_EQUAL(0, rc._topLeft.y()); - VERIFY_ARE_EQUAL(sz.width(), rc._bottomRight.x()); - VERIFY_ARE_EQUAL(sz.height(), rc._bottomRight.y()); + const til::rect rc{ sz }; + VERIFY_ARE_EQUAL(0, rc.left); + VERIFY_ARE_EQUAL(0, rc.top); + VERIFY_ARE_EQUAL(sz.width, rc.right); + VERIFY_ARE_EQUAL(sz.height, rc.bottom); } TEST_METHOD(PointAndSizeConstruct) { const til::point pt{ 4, 8 }; - Log::Comment(L"0.) Normal Case"); + Log::Comment(L"Normal Case"); { - const til::rectangle rc{ pt, til::size{ 2, 10 } }; - VERIFY_ARE_EQUAL(4, rc._topLeft.x()); - VERIFY_ARE_EQUAL(8, rc._topLeft.y()); - VERIFY_ARE_EQUAL(6, rc._bottomRight.x()); - VERIFY_ARE_EQUAL(18, rc._bottomRight.y()); + const til::rect rc{ pt, til::size{ 2, 10 } }; + VERIFY_ARE_EQUAL(4, rc.left); + VERIFY_ARE_EQUAL(8, rc.top); + VERIFY_ARE_EQUAL(6, rc.right); + VERIFY_ARE_EQUAL(18, rc.bottom); } - Log::Comment(L"1.) Overflow x-dimension case."); + Log::Comment(L"Overflow x-dimension case."); { auto fn = [&]() { - constexpr ptrdiff_t x = std::numeric_limits().max(); - const ptrdiff_t y = 0; - const til::rectangle rc{ pt, til::size{ x, y } }; + constexpr til::CoordType x = std::numeric_limits().max(); + const auto y = 0; + const til::rect rc{ pt, til::size{ x, y } }; }; - VERIFY_THROWS_SPECIFIC(fn(), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_ABORT; }); + VERIFY_THROWS(fn(), gsl::narrowing_error); } - Log::Comment(L"1.) Overflow y-dimension case."); + Log::Comment(L"Overflow y-dimension case."); { auto fn = [&]() { - const ptrdiff_t x = 0; - constexpr ptrdiff_t y = std::numeric_limits().max(); - const til::rectangle rc{ pt, til::size{ x, y } }; + const auto x = 0; + constexpr til::CoordType y = std::numeric_limits().max(); + const til::rect rc{ pt, til::size{ x, y } }; }; - VERIFY_THROWS_SPECIFIC(fn(), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_ABORT; }); + VERIFY_THROWS(fn(), gsl::narrowing_error); } } @@ -222,190 +113,170 @@ class RectangleTests sr.Right = 14; sr.Bottom = 19; - const til::rectangle rc{ sr }; - VERIFY_ARE_EQUAL(5, rc._topLeft.x()); - VERIFY_ARE_EQUAL(10, rc._topLeft.y()); - VERIFY_ARE_EQUAL(15, rc._bottomRight.x()); - VERIFY_ARE_EQUAL(20, rc._bottomRight.y()); - } - - TEST_METHOD(ExclusiveCapitalStructConstruct) - { - struct TestStruct - { - char Left; - char Top; - char Right; - char Bottom; - }; - - const TestStruct ts{ 1, 2, 3, 4 }; - - const til::rectangle rc{ ts }; - - VERIFY_ARE_EQUAL(1, rc._topLeft.x()); - VERIFY_ARE_EQUAL(2, rc._topLeft.y()); - VERIFY_ARE_EQUAL(3, rc._bottomRight.x()); - VERIFY_ARE_EQUAL(4, rc._bottomRight.y()); + const til::rect rc{ sr }; + VERIFY_ARE_EQUAL(5, rc.left); + VERIFY_ARE_EQUAL(10, rc.top); + VERIFY_ARE_EQUAL(15, rc.right); + VERIFY_ARE_EQUAL(20, rc.bottom); } TEST_METHOD(Win32RectConstruct) { const RECT win32rc{ 5, 10, 15, 20 }; - const til::rectangle rc{ win32rc }; + const til::rect rc{ win32rc }; - VERIFY_ARE_EQUAL(5, rc._topLeft.x()); - VERIFY_ARE_EQUAL(10, rc._topLeft.y()); - VERIFY_ARE_EQUAL(15, rc._bottomRight.x()); - VERIFY_ARE_EQUAL(20, rc._bottomRight.y()); + VERIFY_ARE_EQUAL(5, rc.left); + VERIFY_ARE_EQUAL(10, rc.top); + VERIFY_ARE_EQUAL(15, rc.right); + VERIFY_ARE_EQUAL(20, rc.bottom); } TEST_METHOD(Assignment) { - til::rectangle a{ 1, 2, 3, 4 }; - const til::rectangle b{ 5, 6, 7, 8 }; + til::rect a{ 1, 2, 3, 4 }; + const til::rect b{ 5, 6, 7, 8 }; - VERIFY_ARE_EQUAL(1, a._topLeft.x()); - VERIFY_ARE_EQUAL(2, a._topLeft.y()); - VERIFY_ARE_EQUAL(3, a._bottomRight.x()); - VERIFY_ARE_EQUAL(4, a._bottomRight.y()); + VERIFY_ARE_EQUAL(1, a.left); + VERIFY_ARE_EQUAL(2, a.top); + VERIFY_ARE_EQUAL(3, a.right); + VERIFY_ARE_EQUAL(4, a.bottom); a = b; - VERIFY_ARE_EQUAL(5, a._topLeft.x()); - VERIFY_ARE_EQUAL(6, a._topLeft.y()); - VERIFY_ARE_EQUAL(7, a._bottomRight.x()); - VERIFY_ARE_EQUAL(8, a._bottomRight.y()); + VERIFY_ARE_EQUAL(5, a.left); + VERIFY_ARE_EQUAL(6, a.top); + VERIFY_ARE_EQUAL(7, a.right); + VERIFY_ARE_EQUAL(8, a.bottom); } TEST_METHOD(Equality) { - Log::Comment(L"0.) Equal."); + Log::Comment(L"Equal."); { - const til::rectangle a{ 1, 2, 3, 4 }; - const til::rectangle b{ 1, 2, 3, 4 }; + const til::rect a{ 1, 2, 3, 4 }; + const til::rect b{ 1, 2, 3, 4 }; VERIFY_IS_TRUE(a == b); } - Log::Comment(L"1.) Left A changed."); + Log::Comment(L"Left A changed."); { - const til::rectangle a{ 9, 2, 3, 4 }; - const til::rectangle b{ 1, 2, 3, 4 }; + const til::rect a{ 9, 2, 3, 4 }; + const til::rect b{ 1, 2, 3, 4 }; VERIFY_IS_FALSE(a == b); } - Log::Comment(L"2.) Top A changed."); + Log::Comment(L"Top A changed."); { - const til::rectangle a{ 1, 9, 3, 4 }; - const til::rectangle b{ 1, 2, 3, 4 }; + const til::rect a{ 1, 9, 3, 4 }; + const til::rect b{ 1, 2, 3, 4 }; VERIFY_IS_FALSE(a == b); } - Log::Comment(L"3.) Right A changed."); + Log::Comment(L"Right A changed."); { - const til::rectangle a{ 1, 2, 9, 4 }; - const til::rectangle b{ 1, 2, 3, 4 }; + const til::rect a{ 1, 2, 9, 4 }; + const til::rect b{ 1, 2, 3, 4 }; VERIFY_IS_FALSE(a == b); } - Log::Comment(L"4.) Bottom A changed."); + Log::Comment(L"Bottom A changed."); { - const til::rectangle a{ 1, 2, 3, 9 }; - const til::rectangle b{ 1, 2, 3, 4 }; + const til::rect a{ 1, 2, 3, 9 }; + const til::rect b{ 1, 2, 3, 4 }; VERIFY_IS_FALSE(a == b); } - Log::Comment(L"5.) Left B changed."); + Log::Comment(L"Left B changed."); { - const til::rectangle a{ 1, 2, 3, 4 }; - const til::rectangle b{ 9, 2, 3, 4 }; + const til::rect a{ 1, 2, 3, 4 }; + const til::rect b{ 9, 2, 3, 4 }; VERIFY_IS_FALSE(a == b); } - Log::Comment(L"6.) Top B changed."); + Log::Comment(L"Top B changed."); { - const til::rectangle a{ 1, 2, 3, 4 }; - const til::rectangle b{ 1, 9, 3, 4 }; + const til::rect a{ 1, 2, 3, 4 }; + const til::rect b{ 1, 9, 3, 4 }; VERIFY_IS_FALSE(a == b); } - Log::Comment(L"7.) Right B changed."); + Log::Comment(L"Right B changed."); { - const til::rectangle a{ 1, 2, 3, 4 }; - const til::rectangle b{ 1, 2, 9, 4 }; + const til::rect a{ 1, 2, 3, 4 }; + const til::rect b{ 1, 2, 9, 4 }; VERIFY_IS_FALSE(a == b); } - Log::Comment(L"8.) Bottom B changed."); + Log::Comment(L"Bottom B changed."); { - const til::rectangle a{ 1, 2, 3, 4 }; - const til::rectangle b{ 1, 2, 3, 9 }; + const til::rect a{ 1, 2, 3, 4 }; + const til::rect b{ 1, 2, 3, 9 }; VERIFY_IS_FALSE(a == b); } } TEST_METHOD(Inequality) { - Log::Comment(L"0.) Equal."); + Log::Comment(L"Equal."); { - const til::rectangle a{ 1, 2, 3, 4 }; - const til::rectangle b{ 1, 2, 3, 4 }; + const til::rect a{ 1, 2, 3, 4 }; + const til::rect b{ 1, 2, 3, 4 }; VERIFY_IS_FALSE(a != b); } - Log::Comment(L"1.) Left A changed."); + Log::Comment(L"Left A changed."); { - const til::rectangle a{ 9, 2, 3, 4 }; - const til::rectangle b{ 1, 2, 3, 4 }; + const til::rect a{ 9, 2, 3, 4 }; + const til::rect b{ 1, 2, 3, 4 }; VERIFY_IS_TRUE(a != b); } - Log::Comment(L"2.) Top A changed."); + Log::Comment(L"Top A changed."); { - const til::rectangle a{ 1, 9, 3, 4 }; - const til::rectangle b{ 1, 2, 3, 4 }; + const til::rect a{ 1, 9, 3, 4 }; + const til::rect b{ 1, 2, 3, 4 }; VERIFY_IS_TRUE(a != b); } - Log::Comment(L"3.) Right A changed."); + Log::Comment(L"Right A changed."); { - const til::rectangle a{ 1, 2, 9, 4 }; - const til::rectangle b{ 1, 2, 3, 4 }; + const til::rect a{ 1, 2, 9, 4 }; + const til::rect b{ 1, 2, 3, 4 }; VERIFY_IS_TRUE(a != b); } - Log::Comment(L"4.) Bottom A changed."); + Log::Comment(L"Bottom A changed."); { - const til::rectangle a{ 1, 2, 3, 9 }; - const til::rectangle b{ 1, 2, 3, 4 }; + const til::rect a{ 1, 2, 3, 9 }; + const til::rect b{ 1, 2, 3, 4 }; VERIFY_IS_TRUE(a != b); } - Log::Comment(L"5.) Left B changed."); + Log::Comment(L"Left B changed."); { - const til::rectangle a{ 1, 2, 3, 4 }; - const til::rectangle b{ 9, 2, 3, 4 }; + const til::rect a{ 1, 2, 3, 4 }; + const til::rect b{ 9, 2, 3, 4 }; VERIFY_IS_TRUE(a != b); } - Log::Comment(L"6.) Top B changed."); + Log::Comment(L"Top B changed."); { - const til::rectangle a{ 1, 2, 3, 4 }; - const til::rectangle b{ 1, 9, 3, 4 }; + const til::rect a{ 1, 2, 3, 4 }; + const til::rect b{ 1, 9, 3, 4 }; VERIFY_IS_TRUE(a != b); } - Log::Comment(L"7.) Right B changed."); + Log::Comment(L"Right B changed."); { - const til::rectangle a{ 1, 2, 3, 4 }; - const til::rectangle b{ 1, 2, 9, 4 }; + const til::rect a{ 1, 2, 3, 4 }; + const til::rect b{ 1, 2, 9, 4 }; VERIFY_IS_TRUE(a != b); } - Log::Comment(L"8.) Bottom B changed."); + Log::Comment(L"Bottom B changed."); { - const til::rectangle a{ 1, 2, 3, 4 }; - const til::rectangle b{ 1, 2, 3, 9 }; + const til::rect a{ 1, 2, 3, 4 }; + const til::rect b{ 1, 2, 3, 9 }; VERIFY_IS_TRUE(a != b); } } @@ -419,75 +290,75 @@ class RectangleTests TEST_METHOD_PROPERTY(L"Data:bottom", L"{0,10}") END_TEST_METHOD_PROPERTIES() - ptrdiff_t left, top, right, bottom; + til::CoordType left, top, right, bottom; VERIFY_SUCCEEDED_RETURN(TestData::TryGetValue(L"left", left)); VERIFY_SUCCEEDED_RETURN(TestData::TryGetValue(L"top", top)); VERIFY_SUCCEEDED_RETURN(TestData::TryGetValue(L"right", right)); VERIFY_SUCCEEDED_RETURN(TestData::TryGetValue(L"bottom", bottom)); const bool expected = left < right && top < bottom; - const til::rectangle actual{ left, top, right, bottom }; + const til::rect actual{ left, top, right, bottom }; VERIFY_ARE_EQUAL(expected, (bool)actual); } TEST_METHOD(OrUnion) { - const til::rectangle one{ 4, 6, 10, 14 }; - const til::rectangle two{ 5, 2, 13, 10 }; + const til::rect one{ 4, 6, 10, 14 }; + const til::rect two{ 5, 2, 13, 10 }; - const til::rectangle expected{ 4, 2, 13, 14 }; + const til::rect expected{ 4, 2, 13, 14 }; const auto actual = one | two; VERIFY_ARE_EQUAL(expected, actual); } TEST_METHOD(OrUnionInplace) { - til::rectangle one{ 4, 6, 10, 14 }; - const til::rectangle two{ 5, 2, 13, 10 }; + til::rect one{ 4, 6, 10, 14 }; + const til::rect two{ 5, 2, 13, 10 }; - const til::rectangle expected{ 4, 2, 13, 14 }; + const til::rect expected{ 4, 2, 13, 14 }; one |= two; VERIFY_ARE_EQUAL(expected, one); } TEST_METHOD(AndIntersect) { - const til::rectangle one{ 4, 6, 10, 14 }; - const til::rectangle two{ 5, 2, 13, 10 }; + const til::rect one{ 4, 6, 10, 14 }; + const til::rect two{ 5, 2, 13, 10 }; - const til::rectangle expected{ 5, 6, 10, 10 }; + const til::rect expected{ 5, 6, 10, 10 }; const auto actual = one & two; VERIFY_ARE_EQUAL(expected, actual); } TEST_METHOD(AndIntersectInplace) { - til::rectangle one{ 4, 6, 10, 14 }; - const til::rectangle two{ 5, 2, 13, 10 }; + til::rect one{ 4, 6, 10, 14 }; + const til::rect two{ 5, 2, 13, 10 }; - const til::rectangle expected{ 5, 6, 10, 10 }; + const til::rect expected{ 5, 6, 10, 10 }; one &= two; VERIFY_ARE_EQUAL(expected, one); } TEST_METHOD(MinusSubtractSame) { - const til::rectangle original{ 0, 0, 10, 10 }; + const til::rect original{ 0, 0, 10, 10 }; const auto removal = original; // Since it's the same rectangle, nothing's left. We should get no results. - const til::some expected; + const til::some expected; const auto actual = original - removal; VERIFY_ARE_EQUAL(expected, actual); } TEST_METHOD(MinusSubtractNoOverlap) { - const til::rectangle original{ 0, 0, 10, 10 }; - const til::rectangle removal{ 12, 12, 15, 15 }; + const til::rect original{ 0, 0, 10, 10 }; + const til::rect removal{ 12, 12, 15, 15 }; // Since they don't overlap, we expect the original to be given back. - const til::some expected{ original }; + const til::some expected{ original }; const auto actual = original - removal; VERIFY_ARE_EQUAL(expected, actual); } @@ -510,11 +381,11 @@ class RectangleTests // | | // +-------------------------------------+ - const til::rectangle original{ 0, 0, 10, 10 }; - const til::rectangle removal{ -12, 3, 15, 15 }; + const til::rect original{ 0, 0, 10, 10 }; + const til::rect removal{ -12, 3, 15, 15 }; - const til::some expected{ - til::rectangle{ original.left(), original.top(), original.right(), removal.top() } + const til::some expected{ + til::rect{ original.left, original.top, original.right, removal.top } }; const auto actual = original - removal; VERIFY_ARE_EQUAL(expected, actual); @@ -537,12 +408,12 @@ class RectangleTests // | removal | // +-----------------+ - const til::rectangle original{ 0, 0, 10, 10 }; - const til::rectangle removal{ 3, 3, 15, 15 }; + const til::rect original{ 0, 0, 10, 10 }; + const til::rect removal{ 3, 3, 15, 15 }; - const til::some expected{ - til::rectangle{ original.left(), original.top(), original.right(), removal.top() }, - til::rectangle{ original.left(), removal.top(), removal.left(), original.bottom() } + const til::some expected{ + til::rect{ original.left, original.top, original.right, removal.top }, + til::rect{ original.left, removal.top, removal.left, original.bottom } }; const auto actual = original - removal; VERIFY_ARE_EQUAL(expected, actual); @@ -561,13 +432,13 @@ class RectangleTests // | | // +--------+ - const til::rectangle original{ 0, 0, 10, 10 }; - const til::rectangle removal{ 3, 3, 15, 6 }; + const til::rect original{ 0, 0, 10, 10 }; + const til::rect removal{ 3, 3, 15, 6 }; - const til::some expected{ - til::rectangle{ original.left(), original.top(), original.right(), removal.top() }, - til::rectangle{ original.left(), removal.bottom(), original.right(), original.bottom() }, - til::rectangle{ original.left(), removal.top(), removal.left(), removal.bottom() } + const til::some expected{ + til::rect{ original.left, original.top, original.right, removal.top }, + til::rect{ original.left, removal.bottom, original.right, original.bottom }, + til::rect{ original.left, removal.top, removal.left, removal.bottom } }; const auto actual = original - removal; VERIFY_ARE_EQUAL(expected, actual); @@ -592,14 +463,14 @@ class RectangleTests // | | // +---------------------------+ - const til::rectangle original{ 0, 0, 10, 10 }; - const til::rectangle removal{ 3, 3, 6, 6 }; + const til::rect original{ 0, 0, 10, 10 }; + const til::rect removal{ 3, 3, 6, 6 }; - const til::some expected{ - til::rectangle{ original.left(), original.top(), original.right(), removal.top() }, - til::rectangle{ original.left(), removal.bottom(), original.right(), original.bottom() }, - til::rectangle{ original.left(), removal.top(), removal.left(), removal.bottom() }, - til::rectangle{ removal.right(), removal.top(), original.right(), removal.bottom() } + const til::some expected{ + til::rect{ original.left, original.top, original.right, removal.top }, + til::rect{ original.left, removal.bottom, original.right, original.bottom }, + til::rect{ original.left, removal.top, removal.left, removal.bottom }, + til::rect{ removal.right, removal.top, original.right, removal.bottom } }; const auto actual = original - removal; VERIFY_ARE_EQUAL(expected, actual); @@ -607,72 +478,72 @@ class RectangleTests TEST_METHOD(AdditionPoint) { - const til::rectangle start{ 10, 20, 30, 40 }; + const til::rect start{ 10, 20, 30, 40 }; const til::point pt{ 3, 7 }; - const til::rectangle expected{ 10 + 3, 20 + 7, 30 + 3, 40 + 7 }; + const til::rect expected{ 10 + 3, 20 + 7, 30 + 3, 40 + 7 }; const auto actual = start + pt; VERIFY_ARE_EQUAL(expected, actual); } TEST_METHOD(AdditionPointInplace) { - til::rectangle start{ 10, 20, 30, 40 }; + til::rect start{ 10, 20, 30, 40 }; const til::point pt{ 3, 7 }; - const til::rectangle expected{ 10 + 3, 20 + 7, 30 + 3, 40 + 7 }; + const til::rect expected{ 10 + 3, 20 + 7, 30 + 3, 40 + 7 }; start += pt; VERIFY_ARE_EQUAL(expected, start); } TEST_METHOD(SubtractionPoint) { - const til::rectangle start{ 10, 20, 30, 40 }; + const til::rect start{ 10, 20, 30, 40 }; const til::point pt{ 3, 7 }; - const til::rectangle expected{ 10 - 3, 20 - 7, 30 - 3, 40 - 7 }; + const til::rect expected{ 10 - 3, 20 - 7, 30 - 3, 40 - 7 }; const auto actual = start - pt; VERIFY_ARE_EQUAL(expected, actual); } TEST_METHOD(SubtractionPointInplace) { - til::rectangle start{ 10, 20, 30, 40 }; + til::rect start{ 10, 20, 30, 40 }; const til::point pt{ 3, 7 }; - const til::rectangle expected{ 10 - 3, 20 - 7, 30 - 3, 40 - 7 }; + const til::rect expected{ 10 - 3, 20 - 7, 30 - 3, 40 - 7 }; start -= pt; VERIFY_ARE_EQUAL(expected, start); } TEST_METHOD(AdditionSize) { - const til::rectangle start{ 10, 20, 30, 40 }; + const til::rect start{ 10, 20, 30, 40 }; - Log::Comment(L"1.) Add size to bottom and right"); + Log::Comment(L"Add size to bottom and right"); { const til::size scale{ 3, 7 }; - const til::rectangle expected{ 10, 20, 33, 47 }; + const til::rect expected{ 10, 20, 33, 47 }; const auto actual = start + scale; VERIFY_ARE_EQUAL(expected, actual); } - Log::Comment(L"2.) Add size to top and left"); + Log::Comment(L"Add size to top and left"); { const til::size scale{ -3, -7 }; - const til::rectangle expected{ 7, 13, 30, 40 }; + const til::rect expected{ 7, 13, 30, 40 }; const auto actual = start + scale; VERIFY_ARE_EQUAL(expected, actual); } - Log::Comment(L"3.) Add size to bottom and left"); + Log::Comment(L"Add size to bottom and left"); { const til::size scale{ -3, 7 }; - const til::rectangle expected{ 7, 20, 30, 47 }; + const til::rect expected{ 7, 20, 30, 47 }; const auto actual = start + scale; VERIFY_ARE_EQUAL(expected, actual); } - Log::Comment(L"4.) Add size to top and right"); + Log::Comment(L"Add size to top and right"); { const til::size scale{ 3, -7 }; - const til::rectangle expected{ 10, 13, 33, 40 }; + const til::rect expected{ 10, 13, 33, 40 }; const auto actual = start + scale; VERIFY_ARE_EQUAL(expected, actual); } @@ -680,40 +551,40 @@ class RectangleTests TEST_METHOD(AdditionSizeInplace) { - const til::rectangle start{ 10, 20, 30, 40 }; + const til::rect start{ 10, 20, 30, 40 }; - Log::Comment(L"1.) Add size to bottom and right"); + Log::Comment(L"Add size to bottom and right"); { auto actual = start; const til::size scale{ 3, 7 }; - const til::rectangle expected{ 10, 20, 33, 47 }; + const til::rect expected{ 10, 20, 33, 47 }; actual += scale; VERIFY_ARE_EQUAL(expected, actual); } - Log::Comment(L"2.) Add size to top and left"); + Log::Comment(L"Add size to top and left"); { auto actual = start; const til::size scale{ -3, -7 }; - const til::rectangle expected{ 7, 13, 30, 40 }; + const til::rect expected{ 7, 13, 30, 40 }; actual += scale; VERIFY_ARE_EQUAL(expected, actual); } - Log::Comment(L"3.) Add size to bottom and left"); + Log::Comment(L"Add size to bottom and left"); { auto actual = start; const til::size scale{ -3, 7 }; - const til::rectangle expected{ 7, 20, 30, 47 }; + const til::rect expected{ 7, 20, 30, 47 }; actual += scale; VERIFY_ARE_EQUAL(expected, actual); } - Log::Comment(L"4.) Add size to top and right"); + Log::Comment(L"Add size to top and right"); { auto actual = start; const til::size scale{ 3, -7 }; - const til::rectangle expected{ 10, 13, 33, 40 }; + const til::rect expected{ 10, 13, 33, 40 }; actual += scale; VERIFY_ARE_EQUAL(expected, actual); } @@ -721,36 +592,36 @@ class RectangleTests TEST_METHOD(SubtractionSize) { - const til::rectangle start{ 10, 20, 30, 40 }; + const til::rect start{ 10, 20, 30, 40 }; - Log::Comment(L"1.) Subtract size from bottom and right"); + Log::Comment(L"Subtract size from bottom and right"); { const til::size scale{ 3, 7 }; - const til::rectangle expected{ 10, 20, 27, 33 }; + const til::rect expected{ 10, 20, 27, 33 }; const auto actual = start - scale; VERIFY_ARE_EQUAL(expected, actual); } - Log::Comment(L"2.) Subtract size from top and left"); + Log::Comment(L"Subtract size from top and left"); { const til::size scale{ -3, -7 }; - const til::rectangle expected{ 13, 27, 30, 40 }; + const til::rect expected{ 13, 27, 30, 40 }; const auto actual = start - scale; VERIFY_ARE_EQUAL(expected, actual); } - Log::Comment(L"3.) Subtract size from bottom and left"); + Log::Comment(L"Subtract size from bottom and left"); { const til::size scale{ -3, 7 }; - const til::rectangle expected{ 13, 20, 30, 33 }; + const til::rect expected{ 13, 20, 30, 33 }; const auto actual = start - scale; VERIFY_ARE_EQUAL(expected, actual); } - Log::Comment(L"4.) Subtract size from top and right"); + Log::Comment(L"Subtract size from top and right"); { const til::size scale{ 3, -6 }; - const til::rectangle expected{ 10, 26, 27, 40 }; + const til::rect expected{ 10, 26, 27, 40 }; const auto actual = start - scale; VERIFY_ARE_EQUAL(expected, actual); } @@ -758,40 +629,40 @@ class RectangleTests TEST_METHOD(SubtractionSizeInplace) { - const til::rectangle start{ 10, 20, 30, 40 }; + const til::rect start{ 10, 20, 30, 40 }; - Log::Comment(L"1.) Subtract size from bottom and right"); + Log::Comment(L"Subtract size from bottom and right"); { auto actual = start; const til::size scale{ 3, 7 }; - const til::rectangle expected{ 10, 20, 27, 33 }; + const til::rect expected{ 10, 20, 27, 33 }; actual -= scale; VERIFY_ARE_EQUAL(expected, actual); } - Log::Comment(L"2.) Subtract size from top and left"); + Log::Comment(L"Subtract size from top and left"); { auto actual = start; const til::size scale{ -3, -7 }; - const til::rectangle expected{ 13, 27, 30, 40 }; + const til::rect expected{ 13, 27, 30, 40 }; actual -= scale; VERIFY_ARE_EQUAL(expected, actual); } - Log::Comment(L"3.) Subtract size from bottom and left"); + Log::Comment(L"Subtract size from bottom and left"); { auto actual = start; const til::size scale{ -3, 7 }; - const til::rectangle expected{ 13, 20, 30, 33 }; + const til::rect expected{ 13, 20, 30, 33 }; actual -= scale; VERIFY_ARE_EQUAL(expected, actual); } - Log::Comment(L"4.) Subtract size from top and right"); + Log::Comment(L"Subtract size from top and right"); { auto actual = start; const til::size scale{ 3, -6 }; - const til::rectangle expected{ 10, 26, 27, 40 }; + const til::rect expected{ 10, 26, 27, 40 }; actual -= scale; VERIFY_ARE_EQUAL(expected, actual); } @@ -799,44 +670,44 @@ class RectangleTests TEST_METHOD(ScaleUpSize) { - const til::rectangle start{ 10, 20, 30, 40 }; + const til::rect start{ 10, 20, 30, 40 }; - Log::Comment(L"1.) Multiply by size to scale from cells to pixels"); + Log::Comment(L"Multiply by size to scale from cells to pixels"); { const til::size scale{ 3, 7 }; - const til::rectangle expected{ 10 * 3, 20 * 7, 30 * 3, 40 * 7 }; + const til::rect expected{ 10 * 3, 20 * 7, 30 * 3, 40 * 7 }; const auto actual = start.scale_up(scale); VERIFY_ARE_EQUAL(expected, actual); } - Log::Comment(L"2.) Multiply by size with width way too big."); + Log::Comment(L"Multiply by size with width way too big."); { - const til::size scale{ std::numeric_limits().max(), static_cast(7) }; + const til::size scale{ std::numeric_limits().max(), static_cast(7) }; auto fn = [&]() { const auto actual = start.scale_up(scale); }; - VERIFY_THROWS_SPECIFIC(fn(), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_ABORT; }); + VERIFY_THROWS(fn(), gsl::narrowing_error); } - Log::Comment(L"3.) Multiply by size with height way too big."); + Log::Comment(L"Multiply by size with height way too big."); { - const til::size scale{ static_cast(3), std::numeric_limits().max() }; + const til::size scale{ static_cast(3), std::numeric_limits().max() }; auto fn = [&]() { const auto actual = start.scale_up(scale); }; - VERIFY_THROWS_SPECIFIC(fn(), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_ABORT; }); + VERIFY_THROWS(fn(), gsl::narrowing_error); } } TEST_METHOD(ScaleDownSize) { - const til::rectangle start{ 10, 20, 29, 40 }; + const til::rect start{ 10, 20, 29, 40 }; - Log::Comment(L"0.) Division by size to scale from pixels to cells"); + Log::Comment(L"Division by size to scale from pixels to cells"); { const til::size scale{ 3, 7 }; @@ -848,144 +719,128 @@ class RectangleTests // T: 20 / 7 = 2.857 --> round down --> 2 // R: 29 / 3 = 9.667 --> round up ----> 10 // B: 40 / 7 = 5.714 --> round up ----> 6 - const til::rectangle expected{ 3, 2, 10, 6 }; + const til::rect expected{ 3, 2, 10, 6 }; const auto actual = start.scale_down(scale); VERIFY_ARE_EQUAL(expected, actual); } } - TEST_METHOD(ScaleByFloat) - { - const til::rectangle start{ 10, 20, 30, 40 }; - - const float scale = 1.45f; - - // This is not a test of the various TilMath rounding methods - // so we're only checking one here. - // Expected here is written based on the "ceiling" outcome. - const til::rectangle expected{ 15, 29, 44, 58 }; - - const auto actual = start.scale(til::math::ceiling, scale); - - VERIFY_ARE_EQUAL(actual, expected); - } - TEST_METHOD(Top) { - const til::rectangle rc{ 5, 10, 15, 20 }; - VERIFY_ARE_EQUAL(rc._topLeft.y(), rc.top()); + const til::rect rc{ 5, 10, 15, 20 }; + VERIFY_ARE_EQUAL(rc.top, rc.top); } TEST_METHOD(TopCast) { - const til::rectangle rc{ 5, 10, 15, 20 }; - VERIFY_ARE_EQUAL(static_cast(rc._topLeft.y()), rc.top()); + const til::rect rc{ 5, 10, 15, 20 }; + VERIFY_ARE_EQUAL(static_cast(rc.top), rc.narrow_top()); } TEST_METHOD(Bottom) { - const til::rectangle rc{ 5, 10, 15, 20 }; - VERIFY_ARE_EQUAL(rc._bottomRight.y(), rc.bottom()); + const til::rect rc{ 5, 10, 15, 20 }; + VERIFY_ARE_EQUAL(rc.bottom, rc.bottom); } TEST_METHOD(BottomCast) { - const til::rectangle rc{ 5, 10, 15, 20 }; - VERIFY_ARE_EQUAL(static_cast(rc._bottomRight.y()), rc.bottom()); + const til::rect rc{ 5, 10, 15, 20 }; + VERIFY_ARE_EQUAL(static_cast(rc.bottom), rc.narrow_bottom()); } TEST_METHOD(Left) { - const til::rectangle rc{ 5, 10, 15, 20 }; - VERIFY_ARE_EQUAL(rc._topLeft.x(), rc.left()); + const til::rect rc{ 5, 10, 15, 20 }; + VERIFY_ARE_EQUAL(rc.left, rc.left); } TEST_METHOD(LeftCast) { - const til::rectangle rc{ 5, 10, 15, 20 }; - VERIFY_ARE_EQUAL(static_cast(rc._topLeft.x()), rc.left()); + const til::rect rc{ 5, 10, 15, 20 }; + VERIFY_ARE_EQUAL(static_cast(rc.left), rc.narrow_left()); } TEST_METHOD(Right) { - const til::rectangle rc{ 5, 10, 15, 20 }; - VERIFY_ARE_EQUAL(rc._bottomRight.x(), rc.right()); + const til::rect rc{ 5, 10, 15, 20 }; + VERIFY_ARE_EQUAL(rc.right, rc.right); } TEST_METHOD(RightCast) { - const til::rectangle rc{ 5, 10, 15, 20 }; - VERIFY_ARE_EQUAL(static_cast(rc._bottomRight.x()), rc.right()); + const til::rect rc{ 5, 10, 15, 20 }; + VERIFY_ARE_EQUAL(static_cast(rc.right), rc.narrow_right()); } TEST_METHOD(Width) { - Log::Comment(L"0.) Width that should be in bounds."); + Log::Comment(L"Width that should be in bounds."); { - const til::rectangle rc{ 5, 10, 15, 20 }; + const til::rect rc{ 5, 10, 15, 20 }; VERIFY_ARE_EQUAL(15 - 5, rc.width()); } - Log::Comment(L"1.) Width that should go out of bounds on subtraction."); + Log::Comment(L"Width that should go out of bounds on subtraction."); { - constexpr ptrdiff_t bigVal = std::numeric_limits().min(); - const ptrdiff_t normalVal = 5; - const til::rectangle rc{ normalVal, normalVal, bigVal, normalVal }; + constexpr til::CoordType bigVal = std::numeric_limits().min(); + const auto normalVal = 5; + const til::rect rc{ normalVal, normalVal, bigVal, normalVal }; auto fn = [&]() { rc.width(); }; - VERIFY_THROWS_SPECIFIC(fn(), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_ABORT; }); + VERIFY_THROWS(fn(), gsl::narrowing_error); } } TEST_METHOD(WidthCast) { - const SHORT expected = 15 - 5; - const til::rectangle rc{ 5, 10, 15, 20 }; - VERIFY_ARE_EQUAL(expected, rc.width()); + const auto expected = 15 - 5; + const til::rect rc{ 5, 10, 15, 20 }; + VERIFY_ARE_EQUAL(expected, rc.narrow_width()); } TEST_METHOD(Height) { - Log::Comment(L"0.) Height that should be in bounds."); + Log::Comment(L"Height that should be in bounds."); { - const til::rectangle rc{ 5, 10, 15, 20 }; + const til::rect rc{ 5, 10, 15, 20 }; VERIFY_ARE_EQUAL(20 - 10, rc.height()); } - Log::Comment(L"1.) Height that should go out of bounds on subtraction."); + Log::Comment(L"Height that should go out of bounds on subtraction."); { - constexpr ptrdiff_t bigVal = std::numeric_limits().min(); - const ptrdiff_t normalVal = 5; - const til::rectangle rc{ normalVal, normalVal, normalVal, bigVal }; + constexpr til::CoordType bigVal = std::numeric_limits().min(); + const auto normalVal = 5; + const til::rect rc{ normalVal, normalVal, normalVal, bigVal }; auto fn = [&]() { rc.height(); }; - VERIFY_THROWS_SPECIFIC(fn(), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_ABORT; }); + VERIFY_THROWS(fn(), gsl::narrowing_error); } } TEST_METHOD(HeightCast) { - const SHORT expected = 20 - 10; - const til::rectangle rc{ 5, 10, 15, 20 }; - VERIFY_ARE_EQUAL(expected, rc.height()); + const auto expected = 20 - 10; + const til::rect rc{ 5, 10, 15, 20 }; + VERIFY_ARE_EQUAL(expected, rc.narrow_height()); } TEST_METHOD(Origin) { - const til::rectangle rc{ 5, 10, 15, 20 }; - const til::point expected{ rc._topLeft }; + const til::rect rc{ 5, 10, 15, 20 }; + const til::point expected{ 5, 10 }; VERIFY_ARE_EQUAL(expected, rc.origin()); } TEST_METHOD(Size) { - const til::rectangle rc{ 5, 10, 15, 20 }; + const til::rect rc{ 5, 10, 15, 20 }; const til::size expected{ 10, 10 }; VERIFY_ARE_EQUAL(expected, rc.size()); } @@ -999,14 +854,14 @@ class RectangleTests TEST_METHOD_PROPERTY(L"Data:bottom", L"{0,10}") END_TEST_METHOD_PROPERTIES() - ptrdiff_t left, top, right, bottom; + til::CoordType left, top, right, bottom; VERIFY_SUCCEEDED_RETURN(TestData::TryGetValue(L"left", left)); VERIFY_SUCCEEDED_RETURN(TestData::TryGetValue(L"top", top)); VERIFY_SUCCEEDED_RETURN(TestData::TryGetValue(L"right", right)); VERIFY_SUCCEEDED_RETURN(TestData::TryGetValue(L"bottom", bottom)); const bool expected = !(left < right && top < bottom); - const til::rectangle actual{ left, top, right, bottom }; + const til::rect actual{ left, top, right, bottom }; VERIFY_ARE_EQUAL(expected, actual.empty()); } @@ -1017,11 +872,11 @@ class RectangleTests TEST_METHOD_PROPERTY(L"Data:y", L"{-1000,0,9,10,11,19,20,21,1000}") END_TEST_METHOD_PROPERTIES() - ptrdiff_t x, y; + til::CoordType x, y; VERIFY_SUCCEEDED_RETURN(TestData::TryGetValue(L"x", x)); VERIFY_SUCCEEDED_RETURN(TestData::TryGetValue(L"y", y)); - const til::rectangle rc{ 5, 10, 15, 20 }; + const til::rect rc{ 5, 10, 15, 20 }; const til::point pt{ x, y }; const bool xInBounds = x >= 5 && x < 15; @@ -1039,37 +894,13 @@ class RectangleTests VERIFY_ARE_EQUAL(expected, rc.contains(pt)); } - TEST_METHOD(ContainsIndex) - { - BEGIN_TEST_METHOD_PROPERTIES() - TEST_METHOD_PROPERTY(L"Data:idx", L"{-1000,-1,0, 1,50,99,100,101, 1000}") - END_TEST_METHOD_PROPERTIES() - - ptrdiff_t idx; - VERIFY_SUCCEEDED_RETURN(TestData::TryGetValue(L"idx", idx)); - - const til::rectangle rc{ 5, 10, 15, 20 }; // 10x10 rectangle. - const ptrdiff_t area = (15 - 5) * (20 - 10); - const bool expected = idx >= 0 && idx < area; - if (expected) - { - Log::Comment(L"Expected in bounds."); - } - else - { - Log::Comment(L"Expected OUT of bounds."); - } - - VERIFY_ARE_EQUAL(expected, rc.contains(idx)); - } - TEST_METHOD(ContainsRectangle) { - const til::rectangle rc{ 5, 10, 15, 20 }; // 10x10 rectangle. + const til::rect rc{ 5, 10, 15, 20 }; // 10x10 rectangle. - const til::rectangle fitsInside{ 8, 12, 10, 18 }; - const til::rectangle spillsOut{ 0, 0, 50, 50 }; - const til::rectangle sticksOut{ 14, 12, 30, 13 }; + const til::rect fitsInside{ 8, 12, 10, 18 }; + const til::rect spillsOut{ 0, 0, 50, 50 }; + const til::rect sticksOut{ 14, 12, 30, 13 }; VERIFY_IS_TRUE(rc.contains(rc), L"We contain ourself."); VERIFY_IS_TRUE(rc.contains(fitsInside), L"We fully contain a smaller rectangle."); @@ -1079,16 +910,16 @@ class RectangleTests TEST_METHOD(IndexOfPoint) { - const til::rectangle rc{ 5, 10, 15, 20 }; + const til::rect rc{ 5, 10, 15, 20 }; - Log::Comment(L"0.) Normal in bounds."); + Log::Comment(L"Normal in bounds."); { const til::point pt{ 7, 17 }; - const ptrdiff_t expected = 72; + const auto expected = 72; VERIFY_ARE_EQUAL(expected, rc.index_of(pt)); } - Log::Comment(L"1.) Out of bounds."); + Log::Comment(L"Out of bounds."); { auto fn = [&]() { const til::point pt{ 1, 1 }; @@ -1098,47 +929,34 @@ class RectangleTests VERIFY_THROWS_SPECIFIC(fn(), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_INVALIDARG; }); } - Log::Comment(L"2.) Overflow."); + Log::Comment(L"Overflow."); { auto fn = [&]() { - constexpr const ptrdiff_t min = static_cast(0); - constexpr const ptrdiff_t max = std::numeric_limits().max(); - const til::rectangle bigRc{ min, min, max, max }; + constexpr const auto min = static_cast(0); + constexpr const auto max = std::numeric_limits().max(); + const til::rect bigRc{ min, min, max, max }; const til::point pt{ max - 1, max - 1 }; bigRc.index_of(pt); }; - VERIFY_THROWS_SPECIFIC(fn(), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_ABORT; }); + VERIFY_THROWS(fn(), gsl::narrowing_error); } } TEST_METHOD(PointAtIndex) { - const til::rectangle rc{ 5, 10, 15, 20 }; + const til::rect rc{ 5, 10, 15, 20 }; - Log::Comment(L"0.) Normal in bounds."); + Log::Comment(L"Normal in bounds."); { - const ptrdiff_t index = 72; const til::point expected{ 7, 17 }; - - VERIFY_ARE_EQUAL(expected, rc.point_at(index)); + VERIFY_ARE_EQUAL(expected, rc.point_at(72)); } - Log::Comment(L"1.) Out of bounds too low."); + Log::Comment(L"Out of bounds too high."); { auto fn = [&]() { - const ptrdiff_t index = -1; - rc.point_at(index); - }; - - VERIFY_THROWS_SPECIFIC(fn(), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_INVALIDARG; }); - } - - Log::Comment(L"2.) Out of bounds too high."); - { - auto fn = [&]() { - const ptrdiff_t index = 1000; - rc.point_at(index); + rc.point_at(1000); }; VERIFY_THROWS_SPECIFIC(fn(), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_INVALIDARG; }); @@ -1147,189 +965,189 @@ class RectangleTests TEST_METHOD(CastToSmallRect) { - Log::Comment(L"0.) Typical situation."); + Log::Comment(L"Typical situation."); { - const til::rectangle rc{ 5, 10, 15, 20 }; - SMALL_RECT val = rc; + const til::rect rc{ 5, 10, 15, 20 }; + const auto val = rc.to_small_rect(); VERIFY_ARE_EQUAL(5, val.Left); VERIFY_ARE_EQUAL(10, val.Top); VERIFY_ARE_EQUAL(14, val.Right); VERIFY_ARE_EQUAL(19, val.Bottom); } - Log::Comment(L"1.) Overflow on left."); + Log::Comment(L"Overflow on left."); { - constexpr ptrdiff_t l = std::numeric_limits().max(); - const ptrdiff_t t = 10; - const ptrdiff_t r = 15; - const ptrdiff_t b = 20; - const til::rectangle rc{ l, t, r, b }; + constexpr til::CoordType l = std::numeric_limits().max(); + const til::CoordType t = 10; + const til::CoordType r = 15; + const til::CoordType b = 20; + const til::rect rc{ l, t, r, b }; auto fn = [&]() { - SMALL_RECT val = rc; + const auto val = rc.to_small_rect(); }; - VERIFY_THROWS_SPECIFIC(fn(), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_ABORT; }); + VERIFY_THROWS(fn(), gsl::narrowing_error); } - Log::Comment(L"2.) Overflow on top."); + Log::Comment(L"Overflow on top."); { - const ptrdiff_t l = 5; - constexpr ptrdiff_t t = std::numeric_limits().max(); - const ptrdiff_t r = 15; - const ptrdiff_t b = 20; - const til::rectangle rc{ l, t, r, b }; + const til::CoordType l = 5; + constexpr til::CoordType t = std::numeric_limits().max(); + const til::CoordType r = 15; + const til::CoordType b = 20; + const til::rect rc{ l, t, r, b }; auto fn = [&]() { - SMALL_RECT val = rc; + const auto val = rc.to_small_rect(); }; - VERIFY_THROWS_SPECIFIC(fn(), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_ABORT; }); + VERIFY_THROWS(fn(), gsl::narrowing_error); } - Log::Comment(L"3.) Overflow on right."); + Log::Comment(L"Overflow on right."); { - const ptrdiff_t l = 5; - const ptrdiff_t t = 10; - constexpr ptrdiff_t r = std::numeric_limits().max(); - const ptrdiff_t b = 20; - const til::rectangle rc{ l, t, r, b }; + const til::CoordType l = 5; + const til::CoordType t = 10; + constexpr til::CoordType r = std::numeric_limits().max(); + const til::CoordType b = 20; + const til::rect rc{ l, t, r, b }; auto fn = [&]() { - SMALL_RECT val = rc; + const auto val = rc.to_small_rect(); }; - VERIFY_THROWS_SPECIFIC(fn(), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_ABORT; }); + VERIFY_THROWS(fn(), gsl::narrowing_error); } - Log::Comment(L"4.) Overflow on bottom."); + Log::Comment(L"Overflow on bottom."); { - const ptrdiff_t l = 5; - const ptrdiff_t t = 10; - const ptrdiff_t r = 15; - constexpr ptrdiff_t b = std::numeric_limits().max(); - const til::rectangle rc{ l, t, r, b }; + const til::CoordType l = 5; + const til::CoordType t = 10; + const til::CoordType r = 15; + constexpr til::CoordType b = std::numeric_limits().max(); + const til::rect rc{ l, t, r, b }; auto fn = [&]() { - SMALL_RECT val = rc; + const auto val = rc.to_small_rect(); }; - VERIFY_THROWS_SPECIFIC(fn(), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_ABORT; }); + VERIFY_THROWS(fn(), gsl::narrowing_error); } } TEST_METHOD(CastToRect) { - Log::Comment(L"0.) Typical situation."); + Log::Comment(L"Typical situation."); { - const til::rectangle rc{ 5, 10, 15, 20 }; - RECT val = rc; + const til::rect rc{ 5, 10, 15, 20 }; + RECT val = rc.to_win32_rect(); VERIFY_ARE_EQUAL(5, val.left); VERIFY_ARE_EQUAL(10, val.top); VERIFY_ARE_EQUAL(15, val.right); VERIFY_ARE_EQUAL(20, val.bottom); } - Log::Comment(L"1.) Fit max left into RECT (may overflow)."); + Log::Comment(L"Fit max left into RECT (may overflow)."); { - constexpr ptrdiff_t l = std::numeric_limits().max(); - const ptrdiff_t t = 10; - const ptrdiff_t r = 15; - const ptrdiff_t b = 20; - const til::rectangle rc{ l, t, r, b }; + constexpr til::CoordType l = std::numeric_limits().max(); + const auto t = 10; + const auto r = 15; + const auto b = 20; + const til::rect rc{ l, t, r, b }; - // On some platforms, ptrdiff_t will fit inside l/t/r/b + // On some platforms, til::CoordType will fit inside l/t/r/b const bool overflowExpected = l > std::numeric_limits().max(); if (overflowExpected) { auto fn = [&]() { - RECT val = rc; + RECT val = rc.to_win32_rect(); }; - VERIFY_THROWS_SPECIFIC(fn(), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_ABORT; }); + VERIFY_THROWS(fn(), gsl::narrowing_error); } else { - RECT val = rc; + RECT val = rc.to_win32_rect(); VERIFY_ARE_EQUAL(l, val.left); } } - Log::Comment(L"2.) Fit max top into RECT (may overflow)."); + Log::Comment(L"Fit max top into RECT (may overflow)."); { - const ptrdiff_t l = 5; - constexpr ptrdiff_t t = std::numeric_limits().max(); - const ptrdiff_t r = 15; - const ptrdiff_t b = 20; - const til::rectangle rc{ l, t, r, b }; + const auto l = 5; + constexpr til::CoordType t = std::numeric_limits().max(); + const auto r = 15; + const auto b = 20; + const til::rect rc{ l, t, r, b }; - // On some platforms, ptrdiff_t will fit inside l/t/r/b + // On some platforms, til::CoordType will fit inside l/t/r/b const bool overflowExpected = t > std::numeric_limits().max(); if (overflowExpected) { auto fn = [&]() { - RECT val = rc; + RECT val = rc.to_win32_rect(); }; - VERIFY_THROWS_SPECIFIC(fn(), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_ABORT; }); + VERIFY_THROWS(fn(), gsl::narrowing_error); } else { - RECT val = rc; + RECT val = rc.to_win32_rect(); VERIFY_ARE_EQUAL(t, val.top); } } - Log::Comment(L"3.) Fit max right into RECT (may overflow)."); + Log::Comment(L"Fit max right into RECT (may overflow)."); { - const ptrdiff_t l = 5; - const ptrdiff_t t = 10; - constexpr ptrdiff_t r = std::numeric_limits().max(); - const ptrdiff_t b = 20; - const til::rectangle rc{ l, t, r, b }; + const auto l = 5; + const auto t = 10; + constexpr til::CoordType r = std::numeric_limits().max(); + const auto b = 20; + const til::rect rc{ l, t, r, b }; - // On some platforms, ptrdiff_t will fit inside l/t/r/b + // On some platforms, til::CoordType will fit inside l/t/r/b const bool overflowExpected = r > std::numeric_limits().max(); if (overflowExpected) { auto fn = [&]() { - RECT val = rc; + RECT val = rc.to_win32_rect(); }; - VERIFY_THROWS_SPECIFIC(fn(), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_ABORT; }); + VERIFY_THROWS(fn(), gsl::narrowing_error); } else { - RECT val = rc; + RECT val = rc.to_win32_rect(); VERIFY_ARE_EQUAL(r, val.right); } } - Log::Comment(L"4.) Fit max bottom into RECT (may overflow)."); + Log::Comment(L"Fit max bottom into RECT (may overflow)."); { - const ptrdiff_t l = 5; - const ptrdiff_t t = 10; - const ptrdiff_t r = 15; - constexpr ptrdiff_t b = std::numeric_limits().max(); - const til::rectangle rc{ l, t, r, b }; + const auto l = 5; + const auto t = 10; + const auto r = 15; + constexpr til::CoordType b = std::numeric_limits().max(); + const til::rect rc{ l, t, r, b }; - // On some platforms, ptrdiff_t will fit inside l/t/r/b + // On some platforms, til::CoordType will fit inside l/t/r/b const bool overflowExpected = b > std::numeric_limits().max(); if (overflowExpected) { auto fn = [&]() { - RECT val = rc; + RECT val = rc.to_win32_rect(); }; - VERIFY_THROWS_SPECIFIC(fn(), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_ABORT; }); + VERIFY_THROWS(fn(), gsl::narrowing_error); } else { - RECT val = rc; + RECT val = rc.to_win32_rect(); VERIFY_ARE_EQUAL(b, val.bottom); } } @@ -1337,32 +1155,32 @@ class RectangleTests TEST_METHOD(CastToD2D1RectF) { - Log::Comment(L"0.) Typical situation."); + Log::Comment(L"Typical situation."); { - const til::rectangle rc{ 5, 10, 15, 20 }; - D2D1_RECT_F val = rc; + const til::rect rc{ 5, 10, 15, 20 }; + D2D1_RECT_F val = rc.to_d2d_rect(); VERIFY_ARE_EQUAL(5, val.left); VERIFY_ARE_EQUAL(10, val.top); VERIFY_ARE_EQUAL(15, val.right); VERIFY_ARE_EQUAL(20, val.bottom); } - // All ptrdiff_ts fit into a float, so there's no exception tests. + // All til::CoordTypes fit into a float, so there's no exception tests. } TEST_METHOD(CastToWindowsFoundationRect) { - Log::Comment(L"0.) Typical situation."); + Log::Comment(L"Typical situation."); { - const til::rectangle rc{ 5, 10, 15, 20 }; - winrt::Windows::Foundation::Rect val = rc; + const til::rect rc{ 5, 10, 15, 20 }; + winrt::Windows::Foundation::Rect val = rc.to_winrt_rect(); VERIFY_ARE_EQUAL(5.f, val.X); VERIFY_ARE_EQUAL(10.f, val.Y); VERIFY_ARE_EQUAL(10.f, val.Width); VERIFY_ARE_EQUAL(10.f, val.Height); } - // All ptrdiff_ts fit into a float, so there's no exception tests. + // All til::CoordTypes fit into a float, so there's no exception tests. // The only other exceptions come from things that don't fit into width() or height() // and those have explicit tests elsewhere in this file. } @@ -1370,8 +1188,8 @@ class RectangleTests #pragma region iterator TEST_METHOD(Begin) { - const til::rectangle rc{ 5, 10, 15, 20 }; - const til::point expected{ rc.left(), rc.top() }; + const til::rect rc{ 5, 10, 15, 20 }; + const til::point expected{ rc.left, rc.top }; const auto it = rc.begin(); VERIFY_ARE_EQUAL(expected, *it); @@ -1379,8 +1197,8 @@ class RectangleTests TEST_METHOD(End) { - const til::rectangle rc{ 5, 10, 15, 20 }; - const til::point expected{ rc.left(), rc.bottom() }; + const til::rect rc{ 5, 10, 15, 20 }; + const til::point expected{ rc.left, rc.bottom }; const auto it = rc.end(); VERIFY_ARE_EQUAL(expected, *it); @@ -1388,7 +1206,7 @@ class RectangleTests TEST_METHOD(ConstIteratorIncrement) { - const til::rectangle rc{ til::size{ 2, 2 } }; + const til::rect rc{ til::size{ 2, 2 } }; auto it = rc.begin(); auto expected = til::point{ 0, 0 }; @@ -1420,7 +1238,7 @@ class RectangleTests TEST_METHOD(ConstIteratorEquality) { - const til::rectangle rc{ 5, 10, 15, 20 }; + const til::rect rc{ 5, 10, 15, 20 }; VERIFY_IS_TRUE(rc.begin() == rc.begin()); VERIFY_IS_FALSE(rc.begin() == rc.end()); @@ -1428,7 +1246,7 @@ class RectangleTests TEST_METHOD(ConstIteratorInequality) { - const til::rectangle rc{ 5, 10, 15, 20 }; + const til::rect rc{ 5, 10, 15, 20 }; VERIFY_IS_FALSE(rc.begin() != rc.begin()); VERIFY_IS_TRUE(rc.begin() != rc.end()); @@ -1436,7 +1254,7 @@ class RectangleTests TEST_METHOD(ConstIteratorLessThan) { - const til::rectangle rc{ 5, 10, 15, 20 }; + const til::rect rc{ 5, 10, 15, 20 }; VERIFY_IS_TRUE(rc.begin() < rc.end()); VERIFY_IS_FALSE(rc.end() < rc.begin()); @@ -1444,7 +1262,7 @@ class RectangleTests TEST_METHOD(ConstIteratorGreaterThan) { - const til::rectangle rc{ 5, 10, 15, 20 }; + const til::rect rc{ 5, 10, 15, 20 }; VERIFY_IS_TRUE(rc.end() > rc.begin()); VERIFY_IS_FALSE(rc.begin() > rc.end()); @@ -1452,99 +1270,65 @@ class RectangleTests #pragma endregion - template - struct RectangleTypeWithLowercase - { - T left, top, right, bottom; - }; - template - struct RectangleTypeWithCapitalization - { - T Left, Top, Right, Bottom; - }; TEST_METHOD(CastFromFloatWithMathTypes) { - RectangleTypeWithLowercase lowerFloatIntegral{ 1.f, 2.f, 3.f, 4.f }; - RectangleTypeWithLowercase lowerFloat{ 1.6f, 2.4f, 3.2f, 4.8f }; - RectangleTypeWithCapitalization capitalDoubleIntegral{ 3., 4., 5., 6. }; - RectangleTypeWithCapitalization capitalDouble{ 3.6, 4.4, 5.7, 6.3 }; - Log::Comment(L"0.) Ceiling"); + Log::Comment(L"Ceiling"); { { - til::rectangle converted{ til::math::ceiling, lowerFloatIntegral }; - VERIFY_ARE_EQUAL((til::rectangle{ 1, 2, 3, 4 }), converted); + til::rect converted{ til::math::ceiling, 1.f, 2.f, 3.f, 4.f }; + VERIFY_ARE_EQUAL((til::rect{ 1, 2, 3, 4 }), converted); } { - til::rectangle converted{ til::math::ceiling, lowerFloat }; - VERIFY_ARE_EQUAL((til::rectangle{ 2, 3, 4, 5 }), converted); + til::rect converted{ til::math::ceiling, 1.6f, 2.4f, 3.2f, 4.8f }; + VERIFY_ARE_EQUAL((til::rect{ 2, 3, 4, 5 }), converted); } { - til::rectangle converted{ til::math::ceiling, capitalDoubleIntegral }; - VERIFY_ARE_EQUAL((til::rectangle{ 3, 4, 5, 6 }), converted); + til::rect converted{ til::math::ceiling, 3., 4., 5., 6. }; + VERIFY_ARE_EQUAL((til::rect{ 3, 4, 5, 6 }), converted); } { - til::rectangle converted{ til::math::ceiling, capitalDouble }; - VERIFY_ARE_EQUAL((til::rectangle{ 4, 5, 6, 7 }), converted); + til::rect converted{ til::math::ceiling, 3.6, 4.4, 5.7, 6.3 }; + VERIFY_ARE_EQUAL((til::rect{ 4, 5, 6, 7 }), converted); } } - Log::Comment(L"1.) Flooring"); + Log::Comment(L"Flooring"); { { - til::rectangle converted{ til::math::flooring, lowerFloatIntegral }; - VERIFY_ARE_EQUAL((til::rectangle{ 1, 2, 3, 4 }), converted); + til::rect converted{ til::math::flooring, 1.f, 2.f, 3.f, 4.f }; + VERIFY_ARE_EQUAL((til::rect{ 1, 2, 3, 4 }), converted); } { - til::rectangle converted{ til::math::flooring, lowerFloat }; - VERIFY_ARE_EQUAL((til::rectangle{ 1, 2, 3, 4 }), converted); + til::rect converted{ til::math::flooring, 1.6f, 2.4f, 3.2f, 4.8f }; + VERIFY_ARE_EQUAL((til::rect{ 1, 2, 3, 4 }), converted); } { - til::rectangle converted{ til::math::flooring, capitalDoubleIntegral }; - VERIFY_ARE_EQUAL((til::rectangle{ 3, 4, 5, 6 }), converted); + til::rect converted{ til::math::flooring, 3., 4., 5., 6. }; + VERIFY_ARE_EQUAL((til::rect{ 3, 4, 5, 6 }), converted); } { - til::rectangle converted{ til::math::flooring, capitalDouble }; - VERIFY_ARE_EQUAL((til::rectangle{ 3, 4, 5, 6 }), converted); + til::rect converted{ til::math::flooring, 3.6, 4.4, 5.7, 6.3 }; + VERIFY_ARE_EQUAL((til::rect{ 3, 4, 5, 6 }), converted); } } - Log::Comment(L"2.) Rounding"); + Log::Comment(L"Rounding"); { { - til::rectangle converted{ til::math::rounding, lowerFloatIntegral }; - VERIFY_ARE_EQUAL((til::rectangle{ 1, 2, 3, 4 }), converted); + til::rect converted{ til::math::rounding, 1.f, 2.f, 3.f, 4.f }; + VERIFY_ARE_EQUAL((til::rect{ 1, 2, 3, 4 }), converted); } { - til::rectangle converted{ til::math::rounding, lowerFloat }; - VERIFY_ARE_EQUAL((til::rectangle{ 2, 2, 3, 5 }), converted); + til::rect converted{ til::math::rounding, 1.6f, 2.4f, 3.2f, 4.8f }; + VERIFY_ARE_EQUAL((til::rect{ 2, 2, 3, 5 }), converted); } { - til::rectangle converted{ til::math::rounding, capitalDoubleIntegral }; - VERIFY_ARE_EQUAL((til::rectangle{ 3, 4, 5, 6 }), converted); + til::rect converted{ til::math::rounding, 3., 4., 5., 6. }; + VERIFY_ARE_EQUAL((til::rect{ 3, 4, 5, 6 }), converted); } { - til::rectangle converted{ til::math::rounding, capitalDouble }; - VERIFY_ARE_EQUAL((til::rectangle{ 4, 4, 6, 6 }), converted); - } - } - - Log::Comment(L"3.) Truncating"); - { - { - til::rectangle converted{ til::math::truncating, lowerFloatIntegral }; - VERIFY_ARE_EQUAL((til::rectangle{ 1, 2, 3, 4 }), converted); - } - { - til::rectangle converted{ til::math::truncating, lowerFloat }; - VERIFY_ARE_EQUAL((til::rectangle{ 1, 2, 3, 4 }), converted); - } - { - til::rectangle converted{ til::math::truncating, capitalDoubleIntegral }; - VERIFY_ARE_EQUAL((til::rectangle{ 3, 4, 5, 6 }), converted); - } - { - til::rectangle converted{ til::math::truncating, capitalDouble }; - VERIFY_ARE_EQUAL((til::rectangle{ 3, 4, 5, 6 }), converted); + til::rect converted{ til::math::rounding, 3.6, 4.4, 5.7, 6.3 }; + VERIFY_ARE_EQUAL((til::rect{ 4, 4, 6, 6 }), converted); } } } diff --git a/src/til/ut_til/SPSCTests.cpp b/src/til/ut_til/SPSCTests.cpp index ad1d64243a..1f9483ca78 100644 --- a/src/til/ut_til/SPSCTests.cpp +++ b/src/til/ut_til/SPSCTests.cpp @@ -4,6 +4,8 @@ #include "precomp.h" #include "WexTestClass.h" +#include + using namespace WEX::Common; using namespace WEX::Logging; using namespace WEX::TestExecution; diff --git a/src/til/ut_til/SizeTests.cpp b/src/til/ut_til/SizeTests.cpp index 880e186cec..bca24d3cbc 100644 --- a/src/til/ut_til/SizeTests.cpp +++ b/src/til/ut_til/SizeTests.cpp @@ -16,88 +16,51 @@ class SizeTests TEST_METHOD(DefaultConstruct) { const til::size sz; - VERIFY_ARE_EQUAL(0, sz._width); - VERIFY_ARE_EQUAL(0, sz._height); + VERIFY_ARE_EQUAL(0, sz.width); + VERIFY_ARE_EQUAL(0, sz.height); } TEST_METHOD(RawConstruct) { const til::size sz{ 5, 10 }; - VERIFY_ARE_EQUAL(5, sz._width); - VERIFY_ARE_EQUAL(10, sz._height); + VERIFY_ARE_EQUAL(5, sz.width); + VERIFY_ARE_EQUAL(10, sz.height); } TEST_METHOD(RawFloatingConstruct) { const til::size sz{ til::math::rounding, 3.2f, 7.8f }; - VERIFY_ARE_EQUAL(3, sz._width); - VERIFY_ARE_EQUAL(8, sz._height); - } - - TEST_METHOD(UnsignedConstruct) - { - Log::Comment(L"0.) Normal unsigned construct."); - { - const size_t width = 5; - const size_t height = 10; - - const til::size sz{ width, height }; - VERIFY_ARE_EQUAL(5, sz._width); - VERIFY_ARE_EQUAL(10, sz._height); - } - - Log::Comment(L"1.) Unsigned construct overflow on width."); - { - constexpr size_t width = std::numeric_limits().max(); - const size_t height = 10; - - auto fn = [&]() { - til::size sz{ width, height }; - }; - - VERIFY_THROWS_SPECIFIC(fn(), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_ABORT; }); - } - - Log::Comment(L"2.) Unsigned construct overflow on height."); - { - constexpr size_t height = std::numeric_limits().max(); - const size_t width = 10; - - auto fn = [&]() { - til::size sz{ width, height }; - }; - - VERIFY_THROWS_SPECIFIC(fn(), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_ABORT; }); - } + VERIFY_ARE_EQUAL(3, sz.width); + VERIFY_ARE_EQUAL(8, sz.height); } TEST_METHOD(SignedConstruct) { - const ptrdiff_t width = -5; - const ptrdiff_t height = -10; + const auto width = -5; + const auto height = -10; const til::size sz{ width, height }; - VERIFY_ARE_EQUAL(width, sz._width); - VERIFY_ARE_EQUAL(height, sz._height); + VERIFY_ARE_EQUAL(width, sz.width); + VERIFY_ARE_EQUAL(height, sz.height); } TEST_METHOD(MixedRawTypeConstruct) { - const ptrdiff_t a = -5; + const auto a = -5; const int b = -10; - Log::Comment(L"Case 1: ptrdiff_t/int"); + Log::Comment(L"Case 1: til::CoordType/int"); { const til::size sz{ a, b }; - VERIFY_ARE_EQUAL(a, sz._width); - VERIFY_ARE_EQUAL(b, sz._height); + VERIFY_ARE_EQUAL(a, sz.width); + VERIFY_ARE_EQUAL(b, sz.height); } - Log::Comment(L"Case 2: int/ptrdiff_t"); + Log::Comment(L"Case 2: int/til::CoordType"); { const til::size sz{ b, a }; - VERIFY_ARE_EQUAL(b, sz._width); - VERIFY_ARE_EQUAL(a, sz._height); + VERIFY_ARE_EQUAL(b, sz.width); + VERIFY_ARE_EQUAL(a, sz.height); } } @@ -106,8 +69,8 @@ class SizeTests COORD coord{ -5, 10 }; const til::size sz{ coord }; - VERIFY_ARE_EQUAL(coord.X, sz._width); - VERIFY_ARE_EQUAL(coord.Y, sz._height); + VERIFY_ARE_EQUAL(coord.X, sz.width); + VERIFY_ARE_EQUAL(coord.Y, sz.height); } TEST_METHOD(SizeConstruct) @@ -115,8 +78,8 @@ class SizeTests SIZE size{ 5, -10 }; const til::size sz{ size }; - VERIFY_ARE_EQUAL(size.cx, sz._width); - VERIFY_ARE_EQUAL(size.cy, sz._height); + VERIFY_ARE_EQUAL(size.cx, sz.width); + VERIFY_ARE_EQUAL(size.cy, sz.height); } TEST_METHOD(Equality) @@ -226,35 +189,35 @@ class SizeTests const til::size sz{ 5, 10 }; const til::size sz2{ 23, 47 }; - const til::size expected{ sz.width() + sz2.width(), sz.height() + sz2.height() }; + const til::size expected{ sz.width + sz2.width, sz.height + sz2.height }; VERIFY_ARE_EQUAL(expected, sz + sz2); } Log::Comment(L"1.) Addition results in value that is too large (width)."); { - constexpr ptrdiff_t bigSize = std::numeric_limits().max(); - const til::size sz{ bigSize, static_cast(0) }; + constexpr til::CoordType bigSize = std::numeric_limits().max(); + const til::size sz{ bigSize, static_cast(0) }; const til::size sz2{ 1, 1 }; auto fn = [&]() { sz + sz2; }; - VERIFY_THROWS_SPECIFIC(fn(), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_ABORT; }); + VERIFY_THROWS(fn(), gsl::narrowing_error); } Log::Comment(L"2.) Addition results in value that is too large (height)."); { - constexpr ptrdiff_t bigSize = std::numeric_limits().max(); - const til::size sz{ static_cast(0), bigSize }; + constexpr til::CoordType bigSize = std::numeric_limits().max(); + const til::size sz{ static_cast(0), bigSize }; const til::size sz2{ 1, 1 }; auto fn = [&]() { sz + sz2; }; - VERIFY_THROWS_SPECIFIC(fn(), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_ABORT; }); + VERIFY_THROWS(fn(), gsl::narrowing_error); } } @@ -265,35 +228,35 @@ class SizeTests const til::size sz{ 5, 10 }; const til::size sz2{ 23, 47 }; - const til::size expected{ sz.width() - sz2.width(), sz.height() - sz2.height() }; + const til::size expected{ sz.width - sz2.width, sz.height - sz2.height }; VERIFY_ARE_EQUAL(expected, sz - sz2); } Log::Comment(L"1.) Subtraction results in value that is too small (width)."); { - constexpr ptrdiff_t bigSize = std::numeric_limits().max(); - const til::size sz{ bigSize, static_cast(0) }; + constexpr til::CoordType bigSize = std::numeric_limits().max(); + const til::size sz{ bigSize, static_cast(0) }; const til::size sz2{ -2, -2 }; auto fn = [&]() { sz2 - sz; }; - VERIFY_THROWS_SPECIFIC(fn(), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_ABORT; }); + VERIFY_THROWS(fn(), gsl::narrowing_error); } Log::Comment(L"2.) Subtraction results in value that is too small (height)."); { - constexpr ptrdiff_t bigSize = std::numeric_limits().max(); - const til::size sz{ static_cast(0), bigSize }; + constexpr til::CoordType bigSize = std::numeric_limits().max(); + const til::size sz{ static_cast(0), bigSize }; const til::size sz2{ -2, -2 }; auto fn = [&]() { sz2 - sz; }; - VERIFY_THROWS_SPECIFIC(fn(), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_ABORT; }); + VERIFY_THROWS(fn(), gsl::narrowing_error); } } @@ -304,35 +267,35 @@ class SizeTests const til::size sz{ 5, 10 }; const til::size sz2{ 23, 47 }; - const til::size expected{ sz.width() * sz2.width(), sz.height() * sz2.height() }; + const til::size expected{ sz.width * sz2.width, sz.height * sz2.height }; VERIFY_ARE_EQUAL(expected, sz * sz2); } Log::Comment(L"1.) Multiplication results in value that is too large (width)."); { - constexpr ptrdiff_t bigSize = std::numeric_limits().max(); - const til::size sz{ bigSize, static_cast(0) }; + constexpr til::CoordType bigSize = std::numeric_limits().max(); + const til::size sz{ bigSize, static_cast(0) }; const til::size sz2{ 10, 10 }; auto fn = [&]() { sz* sz2; }; - VERIFY_THROWS_SPECIFIC(fn(), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_ABORT; }); + VERIFY_THROWS(fn(), gsl::narrowing_error); } Log::Comment(L"2.) Multiplication results in value that is too large (height)."); { - constexpr ptrdiff_t bigSize = std::numeric_limits().max(); - const til::size sz{ static_cast(0), bigSize }; + constexpr til::CoordType bigSize = std::numeric_limits().max(); + const til::size sz{ static_cast(0), bigSize }; const til::size sz2{ 10, 10 }; auto fn = [&]() { sz* sz2; }; - VERIFY_THROWS_SPECIFIC(fn(), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_ABORT; }); + VERIFY_THROWS(fn(), gsl::narrowing_error); } } @@ -343,7 +306,7 @@ class SizeTests const til::size sz{ 5, 10 }; const float scale = 1.783f; - const til::size expected{ static_cast(ceil(5 * scale)), static_cast(ceil(10 * scale)) }; + const til::size expected{ static_cast(ceil(5 * scale)), static_cast(ceil(10 * scale)) }; const auto actual = sz.scale(til::math::ceiling, scale); @@ -359,7 +322,7 @@ class SizeTests sz.scale(til::math::ceiling, scale); }; - VERIFY_THROWS_SPECIFIC(fn(), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_ABORT; }); + VERIFY_THROWS(fn(), gsl::narrowing_error); } } @@ -370,22 +333,22 @@ class SizeTests const til::size sz{ 555, 510 }; const til::size sz2{ 23, 47 }; - const til::size expected{ sz.width() / sz2.width(), sz.height() / sz2.height() }; + const til::size expected{ sz.width / sz2.width, sz.height / sz2.height }; VERIFY_ARE_EQUAL(expected, sz / sz2); } Log::Comment(L"1.) Division by zero"); { - constexpr ptrdiff_t bigSize = std::numeric_limits().max(); - const til::size sz{ bigSize, static_cast(0) }; + constexpr til::CoordType bigSize = std::numeric_limits().max(); + const til::size sz{ bigSize, static_cast(0) }; const til::size sz2{ 1, 1 }; auto fn = [&]() { sz2 / sz; }; - VERIFY_THROWS_SPECIFIC(fn(), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_ABORT; }); + VERIFY_THROWS(fn(), gsl::narrowing_error); } } @@ -416,28 +379,16 @@ class SizeTests } } - TEST_METHOD(Width) - { - const til::size sz{ 5, 10 }; - VERIFY_ARE_EQUAL(sz._width, sz.width()); - } - TEST_METHOD(WidthCast) { const til::size sz{ 5, 10 }; - VERIFY_ARE_EQUAL(static_cast(sz._width), sz.width()); - } - - TEST_METHOD(Height) - { - const til::size sz{ 5, 10 }; - VERIFY_ARE_EQUAL(sz._height, sz.height()); + VERIFY_ARE_EQUAL(static_cast(sz.width), sz.narrow_width()); } TEST_METHOD(HeightCast) { const til::size sz{ 5, 10 }; - VERIFY_ARE_EQUAL(static_cast(sz._height), sz.height()); + VERIFY_ARE_EQUAL(static_cast(sz.height), sz.narrow_height()); } TEST_METHOD(Area) @@ -445,19 +396,19 @@ class SizeTests Log::Comment(L"0.) Area of two things that should be in bounds."); { const til::size sz{ 5, 10 }; - VERIFY_ARE_EQUAL(sz._width * sz._height, sz.area()); + VERIFY_ARE_EQUAL(sz.width * sz.height, sz.area()); } Log::Comment(L"1.) Area is out of bounds on multiplication."); { - constexpr ptrdiff_t bigSize = std::numeric_limits().max(); + constexpr til::CoordType bigSize = std::numeric_limits().max(); const til::size sz{ bigSize, bigSize }; auto fn = [&]() { sz.area(); }; - VERIFY_THROWS_SPECIFIC(fn(), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_ABORT; }); + VERIFY_THROWS(fn(), gsl::narrowing_error); } } TEST_METHOD(AreaCast) @@ -470,51 +421,14 @@ class SizeTests Log::Comment(L"1.) Area is out of bounds on multiplication."); { - constexpr ptrdiff_t bigSize = std::numeric_limits().max(); + constexpr til::CoordType bigSize = std::numeric_limits().max(); const til::size sz{ bigSize, bigSize }; auto fn = [&]() { sz.area(); }; - VERIFY_THROWS_SPECIFIC(fn(), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_ABORT; }); - } - } - - TEST_METHOD(CastToCoord) - { - Log::Comment(L"0.) Typical situation."); - { - const til::size sz{ 5, 10 }; - COORD val = sz; - VERIFY_ARE_EQUAL(5, val.X); - VERIFY_ARE_EQUAL(10, val.Y); - } - - Log::Comment(L"1.) Overflow on width."); - { - constexpr ptrdiff_t width = std::numeric_limits().max(); - const ptrdiff_t height = 10; - const til::size sz{ width, height }; - - auto fn = [&]() { - COORD val = sz; - }; - - VERIFY_THROWS_SPECIFIC(fn(), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_ABORT; }); - } - - Log::Comment(L"2.) Overflow on height."); - { - constexpr ptrdiff_t height = std::numeric_limits().max(); - const ptrdiff_t width = 10; - const til::size sz{ width, height }; - - auto fn = [&]() { - COORD val = sz; - }; - - VERIFY_THROWS_SPECIFIC(fn(), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_ABORT; }); + VERIFY_THROWS(fn(), gsl::narrowing_error); } } @@ -523,55 +437,55 @@ class SizeTests Log::Comment(L"0.) Typical situation."); { const til::size sz{ 5, 10 }; - SIZE val = sz; + SIZE val = sz.to_win32_size(); VERIFY_ARE_EQUAL(5, val.cx); VERIFY_ARE_EQUAL(10, val.cy); } Log::Comment(L"1.) Fit max width into SIZE (may overflow)."); { - constexpr ptrdiff_t width = std::numeric_limits().max(); - const ptrdiff_t height = 10; + constexpr til::CoordType width = std::numeric_limits().max(); + const auto height = 10; const til::size sz{ width, height }; - // On some platforms, ptrdiff_t will fit inside cx/cy + // On some platforms, til::CoordType will fit inside cx/cy const bool overflowExpected = width > std::numeric_limits().max(); if (overflowExpected) { auto fn = [&]() { - SIZE val = sz; + SIZE val = sz.to_win32_size(); }; - VERIFY_THROWS_SPECIFIC(fn(), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_ABORT; }); + VERIFY_THROWS(fn(), gsl::narrowing_error); } else { - SIZE val = sz; + SIZE val = sz.to_win32_size(); VERIFY_ARE_EQUAL(width, val.cx); } } Log::Comment(L"2.) Fit max height into SIZE (may overflow)."); { - constexpr ptrdiff_t height = std::numeric_limits().max(); - const ptrdiff_t width = 10; + constexpr til::CoordType height = std::numeric_limits().max(); + const auto width = 10; const til::size sz{ width, height }; - // On some platforms, ptrdiff_t will fit inside cx/cy + // On some platforms, til::CoordType will fit inside cx/cy const bool overflowExpected = height > std::numeric_limits().max(); if (overflowExpected) { auto fn = [&]() { - SIZE val = sz; + SIZE val = sz.to_win32_size(); }; - VERIFY_THROWS_SPECIFIC(fn(), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_ABORT; }); + VERIFY_THROWS(fn(), gsl::narrowing_error); } else { - SIZE val = sz; + SIZE val = sz.to_win32_size(); VERIFY_ARE_EQUAL(height, val.cy); } } @@ -582,61 +496,40 @@ class SizeTests Log::Comment(L"0.) Typical situation."); { const til::size sz{ 5, 10 }; - D2D1_SIZE_F val = sz; + D2D1_SIZE_F val = sz.to_d2d_size(); VERIFY_ARE_EQUAL(5, val.width); VERIFY_ARE_EQUAL(10, val.height); } - // All ptrdiff_ts fit into a float, so there's no exception tests. + // All til::CoordTypes fit into a float, so there's no exception tests. } - template - struct SizeTypeWith_XY - { - T X, Y; - }; - template - struct SizeTypeWith_cxcy - { - T cx, cy; - }; - template - struct SizeTypeWith_WidthHeight - { - T Width, Height; - }; TEST_METHOD(CastFromFloatWithMathTypes) { - SizeTypeWith_XY XYFloatIntegral{ 1.f, 2.f }; - SizeTypeWith_XY XYFloat{ 1.6f, 2.4f }; - SizeTypeWith_cxcy cxcyDoubleIntegral{ 3., 4. }; - SizeTypeWith_cxcy cxcyDouble{ 3.6, 4.4 }; - SizeTypeWith_WidthHeight WHDoubleIntegral{ 5., 6. }; - SizeTypeWith_WidthHeight WHDouble{ 5.6, 6.4 }; Log::Comment(L"0.) Ceiling"); { { - til::size converted{ til::math::ceiling, XYFloatIntegral }; + til::size converted{ til::math::ceiling, 1.f, 2.f }; VERIFY_ARE_EQUAL((til::size{ 1, 2 }), converted); } { - til::size converted{ til::math::ceiling, XYFloat }; + til::size converted{ til::math::ceiling, 1.6f, 2.4f }; VERIFY_ARE_EQUAL((til::size{ 2, 3 }), converted); } { - til::size converted{ til::math::ceiling, cxcyDoubleIntegral }; + til::size converted{ til::math::ceiling, 3., 4. }; VERIFY_ARE_EQUAL((til::size{ 3, 4 }), converted); } { - til::size converted{ til::math::ceiling, cxcyDouble }; + til::size converted{ til::math::ceiling, 3.6, 4.4 }; VERIFY_ARE_EQUAL((til::size{ 4, 5 }), converted); } { - til::size converted{ til::math::ceiling, WHDoubleIntegral }; + til::size converted{ til::math::ceiling, 5., 6. }; VERIFY_ARE_EQUAL((til::size{ 5, 6 }), converted); } { - til::size converted{ til::math::ceiling, WHDouble }; + til::size converted{ til::math::ceiling, 5.6, 6.4 }; VERIFY_ARE_EQUAL((til::size{ 6, 7 }), converted); } } @@ -644,27 +537,27 @@ class SizeTests Log::Comment(L"1.) Flooring"); { { - til::size converted{ til::math::flooring, XYFloatIntegral }; + til::size converted{ til::math::flooring, 1.f, 2.f }; VERIFY_ARE_EQUAL((til::size{ 1, 2 }), converted); } { - til::size converted{ til::math::flooring, XYFloat }; + til::size converted{ til::math::flooring, 1.6f, 2.4f }; VERIFY_ARE_EQUAL((til::size{ 1, 2 }), converted); } { - til::size converted{ til::math::flooring, cxcyDoubleIntegral }; + til::size converted{ til::math::flooring, 3., 4. }; VERIFY_ARE_EQUAL((til::size{ 3, 4 }), converted); } { - til::size converted{ til::math::flooring, cxcyDouble }; + til::size converted{ til::math::flooring, 3.6, 4.4 }; VERIFY_ARE_EQUAL((til::size{ 3, 4 }), converted); } { - til::size converted{ til::math::flooring, WHDoubleIntegral }; + til::size converted{ til::math::flooring, 5., 6. }; VERIFY_ARE_EQUAL((til::size{ 5, 6 }), converted); } { - til::size converted{ til::math::flooring, WHDouble }; + til::size converted{ til::math::flooring, 5.6, 6.4 }; VERIFY_ARE_EQUAL((til::size{ 5, 6 }), converted); } } @@ -672,57 +565,29 @@ class SizeTests Log::Comment(L"2.) Rounding"); { { - til::size converted{ til::math::rounding, XYFloatIntegral }; + til::size converted{ til::math::rounding, 1.f, 2.f }; VERIFY_ARE_EQUAL((til::size{ 1, 2 }), converted); } { - til::size converted{ til::math::rounding, XYFloat }; + til::size converted{ til::math::rounding, 1.6f, 2.4f }; VERIFY_ARE_EQUAL((til::size{ 2, 2 }), converted); } { - til::size converted{ til::math::rounding, cxcyDoubleIntegral }; + til::size converted{ til::math::rounding, 3., 4. }; VERIFY_ARE_EQUAL((til::size{ 3, 4 }), converted); } { - til::size converted{ til::math::rounding, cxcyDouble }; + til::size converted{ til::math::rounding, 3.6, 4.4 }; VERIFY_ARE_EQUAL((til::size{ 4, 4 }), converted); } { - til::size converted{ til::math::rounding, WHDoubleIntegral }; + til::size converted{ til::math::rounding, 5., 6. }; VERIFY_ARE_EQUAL((til::size{ 5, 6 }), converted); } { - til::size converted{ til::math::rounding, WHDouble }; + til::size converted{ til::math::rounding, 5.6, 6.4 }; VERIFY_ARE_EQUAL((til::size{ 6, 6 }), converted); } } - - Log::Comment(L"3.) Truncating"); - { - { - til::size converted{ til::math::truncating, XYFloatIntegral }; - VERIFY_ARE_EQUAL((til::size{ 1, 2 }), converted); - } - { - til::size converted{ til::math::truncating, XYFloat }; - VERIFY_ARE_EQUAL((til::size{ 1, 2 }), converted); - } - { - til::size converted{ til::math::truncating, cxcyDoubleIntegral }; - VERIFY_ARE_EQUAL((til::size{ 3, 4 }), converted); - } - { - til::size converted{ til::math::truncating, cxcyDouble }; - VERIFY_ARE_EQUAL((til::size{ 3, 4 }), converted); - } - { - til::size converted{ til::math::truncating, WHDoubleIntegral }; - VERIFY_ARE_EQUAL((til::size{ 5, 6 }), converted); - } - { - til::size converted{ til::math::truncating, WHDouble }; - VERIFY_ARE_EQUAL((til::size{ 5, 6 }), converted); - } - } } }; diff --git a/src/types/UiaTextRangeBase.cpp b/src/types/UiaTextRangeBase.cpp index 2bc7411d9d..58a6f4f982 100644 --- a/src/types/UiaTextRangeBase.cpp +++ b/src/types/UiaTextRangeBase.cpp @@ -287,16 +287,16 @@ void UiaTextRangeBase::_expandToEnclosingUnit(TextUnit unit) // If we're past document end, // set us to ONE BEFORE the document end. // This allows us to expand properly. - if (bufferSize.CompareInBounds(_start, documentEnd, true) >= 0) + if (bufferSize.CompareInBounds(_start, documentEnd.to_win32_coord(), true) >= 0) { - _start = documentEnd; + _start = documentEnd.to_win32_coord(); bufferSize.DecrementInBounds(_start, true); } if (unit == TextUnit_Character) { - _start = buffer.GetGlyphStart(_start, documentEnd); - _end = buffer.GetGlyphEnd(_start, true, documentEnd); + _start = buffer.GetGlyphStart(til::point{ _start }, documentEnd).to_win32_coord(); + _end = buffer.GetGlyphEnd(til::point{ _start }, true, documentEnd).to_win32_coord(); } else if (unit <= TextUnit_Word) { @@ -308,10 +308,10 @@ void UiaTextRangeBase::_expandToEnclosingUnit(TextUnit unit) { // expand to line _start.X = 0; - if (_start.Y == documentEnd.y()) + if (_start.Y == documentEnd.y) { // we're on the last line - _end = documentEnd; + _end = documentEnd.to_win32_coord(); bufferSize.IncrementInBounds(_end, true); } else @@ -324,7 +324,7 @@ void UiaTextRangeBase::_expandToEnclosingUnit(TextUnit unit) { // expand to document _start = bufferSize.Origin(); - _end = documentEnd; + _end = documentEnd.to_win32_coord(); } } @@ -859,7 +859,7 @@ IFACEMETHODIMP UiaTextRangeBase::GetBoundingRectangles(_Outptr_result_maybenull_ // these viewport vars are converted to the buffer coordinate space const auto viewport = bufferSize.ConvertToOrigin(_pData->GetViewport()); - const til::point viewportOrigin = viewport.Origin(); + const auto viewportOrigin = viewport.Origin(); const auto viewportEnd = viewport.EndExclusive(); // startAnchor: the earliest COORD we will get a bounding rect for @@ -900,8 +900,8 @@ IFACEMETHODIMP UiaTextRangeBase::GetBoundingRectangles(_Outptr_result_maybenull_ // Convert the buffer coordinates to an equivalent range of // screen cells, taking line rendition into account. const auto lineRendition = buffer.GetLineRendition(rect.Top); - til::rectangle r{ BufferToScreenLine(rect, lineRendition) }; - r -= viewportOrigin; + til::rect r{ BufferToScreenLine(rect, lineRendition) }; + r -= til::point{ viewportOrigin }; _getBoundingRect(r, coords); } } @@ -1038,7 +1038,7 @@ try // If so, clamp each endpoint to the end of the document. constexpr auto endpoint = TextPatternRangeEndpoint::TextPatternRangeEndpoint_Start; const auto bufferSize{ _pData->GetTextBuffer().GetSize() }; - const COORD documentEnd = _getDocumentEnd(); + const COORD documentEnd = _getDocumentEnd().to_win32_coord(); if (bufferSize.CompareInBounds(_start, documentEnd, true) > 0) { _start = documentEnd; @@ -1109,7 +1109,7 @@ IFACEMETHODIMP UiaTextRangeBase::MoveEndpointByUnit(_In_ TextPatternRangeEndpoin auto documentEnd = bufferSize.EndExclusive(); try { - documentEnd = _getDocumentEnd(); + documentEnd = _getDocumentEnd().to_win32_coord(); } CATCH_LOG(); @@ -1381,20 +1381,20 @@ const til::point UiaTextRangeBase::_getDocumentEnd() const // - coords - vector to add the calculated coords to // Return Value: // - -void UiaTextRangeBase::_getBoundingRect(const til::rectangle textRect, _Inout_ std::vector& coords) const +void UiaTextRangeBase::_getBoundingRect(const til::rect& textRect, _Inout_ std::vector& coords) const { - const til::size currentFontSize = _getScreenFontSize(); + const til::size currentFontSize{ _getScreenFontSize() }; POINT topLeft{ 0 }; POINT bottomRight{ 0 }; // we want to clamp to a long (output type), not a short (input type) // so we need to explicitly say - topLeft.x = base::ClampMul(textRect.left(), currentFontSize.width()); - topLeft.y = base::ClampMul(textRect.top(), currentFontSize.height()); + topLeft.x = base::ClampMul(textRect.left, currentFontSize.width); + topLeft.y = base::ClampMul(textRect.top, currentFontSize.height); - bottomRight.x = base::ClampMul(textRect.right(), currentFontSize.width()); - bottomRight.y = base::ClampMul(textRect.bottom(), currentFontSize.height()); + bottomRight.x = base::ClampMul(textRect.right, currentFontSize.width); + bottomRight.y = base::ClampMul(textRect.bottom, currentFontSize.height); // convert the coords to be relative to the screen instead of // the client window @@ -1440,7 +1440,7 @@ void UiaTextRangeBase::_moveEndpointByUnitCharacter(_In_ const int moveCount, const auto& buffer = _pData->GetTextBuffer(); bool success = true; - til::point target = GetEndpoint(endpoint); + til::point target{ GetEndpoint(endpoint) }; const auto documentEnd{ _getDocumentEnd() }; while (std::abs(*pAmountMoved) < std::abs(moveCount) && success) { @@ -1465,7 +1465,7 @@ void UiaTextRangeBase::_moveEndpointByUnitCharacter(_In_ const int moveCount, } } - SetEndpoint(endpoint, target); + SetEndpoint(endpoint, target.to_win32_coord()); } // Routine Description: @@ -1510,7 +1510,7 @@ void UiaTextRangeBase::_moveEndpointByUnitWord(_In_ const int moveCount, { case MovementDirection::Forward: { - if (bufferSize.CompareInBounds(nextPos, documentEnd, true) >= 0) + if (bufferSize.CompareInBounds(nextPos, documentEnd.to_win32_coord(), true) >= 0) { success = false; } @@ -1521,7 +1521,7 @@ void UiaTextRangeBase::_moveEndpointByUnitWord(_In_ const int moveCount, } else if (allowBottomExclusive) { - resultPos = documentEnd; + resultPos = documentEnd.to_win32_coord(); (*pAmountMoved)++; } else @@ -1615,7 +1615,7 @@ void UiaTextRangeBase::_moveEndpointByUnitLine(_In_ const int moveCount, auto documentEnd{ bufferSize.EndExclusive() }; try { - documentEnd = _getDocumentEnd(); + documentEnd = _getDocumentEnd().to_win32_coord(); } CATCH_LOG(); @@ -1727,7 +1727,7 @@ void UiaTextRangeBase::_moveEndpointByUnitDocument(_In_ const int moveCount, auto documentEnd{ bufferSize.EndExclusive() }; try { - documentEnd = _getDocumentEnd(); + documentEnd = _getDocumentEnd().to_win32_coord(); } CATCH_LOG(); diff --git a/src/types/UiaTextRangeBase.hpp b/src/types/UiaTextRangeBase.hpp index c9089438d1..0f6a843fd8 100644 --- a/src/types/UiaTextRangeBase.hpp +++ b/src/types/UiaTextRangeBase.hpp @@ -152,7 +152,7 @@ namespace Microsoft::Console::Types const Viewport _getOptimizedBufferSize() const noexcept; const til::point _getDocumentEnd() const; - void _getBoundingRect(const til::rectangle textRect, _Inout_ std::vector& coords) const; + void _getBoundingRect(const til::rect& textRect, _Inout_ std::vector& coords) const; void _expandToEnclosingUnit(TextUnit unit); diff --git a/tools/ConsoleTypes.natvis b/tools/ConsoleTypes.natvis index ac4461d7a6..13b6990999 100644 --- a/tools/ConsoleTypes.natvis +++ b/tools/ConsoleTypes.natvis @@ -85,7 +85,7 @@ {{X: {_x,d}, Y: {_y,d}}} - + {{L: {_topLeft._x}, T: {_topLeft._y}, R: {_bottomRight._x} B: {_bottomRight._y} [W: {_bottomRight._x - _topLeft._x} x H: {_bottomRight._y - _topLeft._y} -> A: {(_bottomRight._x - _topLeft._x) * (_bottomRight._y - _topLeft._y)}]}} diff --git a/tools/TestTableWriter/GenerateTests.ps1 b/tools/TestTableWriter/GenerateTests.ps1 index 51c2d8019b..3f3d05e1b7 100644 --- a/tools/TestTableWriter/GenerateTests.ps1 +++ b/tools/TestTableWriter/GenerateTests.ps1 @@ -10,7 +10,7 @@ [CmdletBinding()] Param( [Parameter(Position=0, ValueFromPipeline=$true)] - [string]$TestPath = "UiaTests.csv" + [string]$TestPath = "$PSScriptRoot/../../tools/TestTableWriter/UiaTests.csv" ) # 0. Generate a comment telling people to not modify these tests in the .cpp @@ -24,7 +24,7 @@ $result = "// Copyright (c) Microsoft Corporation. # 1. Define a few helpful variables to make life easier. $result += " // Define a few helpful variables -constexpr til::rectangle bufferSize{ 0, 0, 80, 300 }; +constexpr til::rect bufferSize{ 0, 0, 80, 300 }; constexpr short midX{ 40 }; constexpr short midY{ 150 }; constexpr short midPopulatedY{ 75 }; @@ -77,7 +77,7 @@ foreach ($var in $vars) # i. Contains "segment" --> define point at the beginning of a text segment if ($segmentHeuristic) { - $result += "constexpr til::point {0}{{ {1}, {2}.y() }};" -f $var, $var.Substring(0, 8), $var.Substring(9, $var.Length - $var.IndexOf("L") - 1); + $result += "constexpr til::point {0}{{ {1}, {2}.y }};" -f $var, $var.Substring(0, 8), $var.Substring(9, $var.Length - $var.IndexOf("L") - 1); } # ii. Contains number --> requires movement elseif ($movementHeuristic) @@ -125,7 +125,7 @@ foreach ($var in $vars) elseif ($leftHeuristic) { $standardVar = $var.Split("Left")[0] - $result += "constexpr til::point {0}{{ bufferSize.left(), {1}.y() }};" -f $var, $standardVar; + $result += "constexpr til::point {0}{{ bufferSize.left, {1}.y }};" -f $var, $standardVar; } $result += "`n"; } @@ -182,4 +182,4 @@ foreach ($test in $tests) } $result += "};`n`n" -$result > "..\..\src\interactivity\win32\ut_interactivity_win32\GeneratedUiaTextRangeMovementTests.g.cpp"; +$result > "$PSScriptRoot/../../src/interactivity/win32/ut_interactivity_win32/GeneratedUiaTextRangeMovementTests.g.cpp";