diff --git a/src/buffer/out/textBuffer.cpp b/src/buffer/out/textBuffer.cpp index 7a098a78c28..36266710a86 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 7ce785831bd..72422675694 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 7ec3056a6ab..0e5f2916f09 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 38088a838d2..7c9a668c3a5 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 70876af7a42..70c34674a8f 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)) }; - - const auto fontSizeInDips{ _core->FontSizeInDips() }; - if (distance >= (std::min(fontSizeInDips.width(), fontSizeInDips.height()) / 4.f)) + // 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 + + 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 6039bc8da96..59de34ae96b 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 570cfd67ec6..d2247311d1e 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 bd95c54047b..57c3a85fc8d 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 fb5c0280c25..22b0738a508 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 53206b16ed1..aa6f3567e80 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 4eaa385e2d4..4c9d38227b2 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 367a8365a56..f45d18f821d 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 def44aeb15b..3e19898b1a4 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 9f885a94f9f..0da22765c15 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 ae063f1939b..4be7a402f9b 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 @@ class TerminalCoreUnitTests::ConptyRoundtripTests final 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 6c275b1e268..0083662a39b 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 c8ffa8320ee..9a345e18b57 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 87a4d345371..cbd2509385c 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 ed620925106..53c00121d15 100644 --- a/src/cascadia/WindowsTerminal/IslandWindow.h +++ b/src/cascadia/WindowsTerminal/IslandWindow.h @@ -134,7 +134,7 @@ class IslandWindow : 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 50c68fd860c..7327656970f 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 879da45f600..7f5cfb36b35 100644 --- a/src/cascadia/WindowsTerminal/NonClientIslandWindow.h +++ b/src/cascadia/WindowsTerminal/NonClientIslandWindow.h @@ -72,7 +72,7 @@ class NonClientIslandWindow : public IslandWindow 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 08782076989..dadc320a14d 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 24ee0337382..cc71a88b41f 100644 --- a/src/cascadia/WindowsTerminal/NotificationIcon.h +++ b/src/cascadia/WindowsTerminal/NotificationIcon.h @@ -23,7 +23,7 @@ class NotificationIcon 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 0d46d59d932..dce1c3e1fee 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 d58343d3d69..529f2c38f4b 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 3d9a5b8aa1b..85612eebc0f 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 a3b9b39aebc..04986dc63fa 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 59e07cb8e41..ae46c8778cf 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/color.h" +#include "til/enumset.h" +#include "til/pmr.h" #include "til/replace.h" +#include "til/rle.h" #include "til/string.h" -#include "til/pmr.h" -#include "til/enumset.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 f4bef68b62c..f3527914bf2 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 92afa100c09..59f80c2cc6e 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,30 +59,16 @@ 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); - } - } - }; - - 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 gsl::narrow(val); } - return ::base::saturated_cast(val); } }; } @@ -80,6 +76,5 @@ namespace til 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 7e18e33498a..3ee186ad6ba 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 5d47588255e..4741a67c8d8 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 - { - public: - constexpr point() noexcept : - point(0, 0) - { - } + using CoordType = int32_t; - // 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 - - 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) + namespace details + { + template + constexpr U extract(const ::base::CheckedNumeric& num) { - THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(x).AssignIfValid(&_x)); - THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(y).AssignIfValid(&_y)); + U val; + if (!num.AssignIfValid(&val)) + { + throw gsl::narrowing_error{}; + } + return val; } + } - constexpr point(ptrdiff_t x, ptrdiff_t y) noexcept : - _x(x), - _y(y) - { - } + struct point + { + CoordType x = 0; + CoordType y = 0; - // 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)) - { - } + constexpr point() noexcept = default; - // 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 - { - 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); - } - - point operator/(const point& other) const + constexpr 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 }; + return point{ + details::extract(::base::CheckDiv(x, other.x)), + details::extract(::base::CheckDiv(y, other.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)); - - ptrdiff_t y; - THROW_HR_IF(E_ABORT, !base::CheckMul(_y, scale).AssignIfValid(&y)); - - return point{ x, y }; + return point{ + details::extract(::base::CheckMul(x, scale)), + details::extract(::base::CheckMul(y, scale)), + }; } - 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::CheckDiv(_x, scale).AssignIfValid(&x)); - - ptrdiff_t y; - THROW_HR_IF(E_ABORT, !base::CheckDiv(_y, scale).AssignIfValid(&y)); - - return point{ x, y }; + return point{ + details::extract(::base::CheckDiv(x, scale)), + details::extract(::base::CheckDiv(y, scale)), + }; } - constexpr ptrdiff_t x() const noexcept + template + constexpr T narrow_x() const { - 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; + return gsl::narrow(y); } - constexpr ptrdiff_t y() const noexcept +#ifdef _WINCONTYPES_ + explicit constexpr point(const COORD other) noexcept : + x{ other.X }, y{ other.Y } { - return _y; } - template - T y() const + constexpr COORD to_win32_coord() const { - T ret; - THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(y()).AssignIfValid(&ret)); - return ret; + return { narrow_x(), narrow_y() }; } +#endif -#ifdef _WINCONTYPES_ - operator COORD() const +#ifdef _WINDEF_ + explicit constexpr point(const POINT 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; } -#endif -#ifdef _WINDEF_ - operator POINT() const + constexpr POINT to_win32_point() const noexcept { - 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; + 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) } + { + } + + constexpr D2D1_POINT_2F to_d2d_point() const noexcept { - return D2D1_POINT_2F{ gsl::narrow_cast(_x), gsl::narrow_cast(_y) }; + 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 00000000000..f5116da1978 --- /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 43bae773f0b..00000000000 --- 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 907089ef690..22422bccf7d 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) - { - } - - // 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 - - 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)); - } + CoordType width = 0; + CoordType height = 0; - 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)) - { - } + constexpr size() noexcept = default; - // 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; + return gsl::narrow(static_cast(width) * static_cast(height)); } - template - T height() const +#ifdef _WINCONTYPES_ + explicit constexpr size(const COORD other) noexcept : + width{ other.X }, height{ other.Y } { - T ret; - THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(height()).AssignIfValid(&ret)); - return ret; } - ptrdiff_t area() const + constexpr COORD to_win32_coord() const { - ptrdiff_t result; - THROW_HR_IF(E_ABORT, !base::CheckMul(_width, _height).AssignIfValid(&result)); - return result; + return { gsl::narrow(width), gsl::narrow(height) }; } +#endif - template - T area() const +#ifdef _WINDEF_ + explicit constexpr size(const SIZE other) noexcept : + width{ other.cx }, height{ other.cy } { - T ret; - THROW_HR_IF(E_ABORT, !base::CheckMul(_width, _height).AssignIfValid(&ret)); - return ret; } -#ifdef _WINCONTYPES_ - operator COORD() const + constexpr SIZE to_win32_size() const noexcept { - 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; + return { width, height }; } #endif -#ifdef _WINDEF_ - operator SIZE() const +#ifdef DCOMMON_H_INCLUDED + template + constexpr size(TilMath, const D2D1_SIZE_F other) : + width{ TilMath::template cast(other.width) }, + height{ TilMath::template cast(other.height) } { - 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; } -#endif -#ifdef DCOMMON_H_INCLUDED - constexpr operator D2D1_SIZE_F() const noexcept + constexpr D2D1_SIZE_F to_d2d_size() const noexcept { - return D2D1_SIZE_F{ gsl::narrow_cast(_width), gsl::narrow_cast(_height) }; + return { static_cast(width), static_cast(height) }; } #endif - std::wstring to_string() const +#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) } { - return wil::str_printf(L"[W:%td, H:%td]", width(), height()); } - protected: - ptrdiff_t _width; - ptrdiff_t _height; - -#ifdef UNIT_TESTING - friend class ::SizeTests; + 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); + } }; }; @@ -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 96d523c486b..d21a3cdca54 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 ef9e951129b..1f05709f0b5 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 4a01837d936..adb3b930a11 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 a1339bb8c69..535d7822971 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 cba9aa951b9..323f2788685 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 95c6a9a5ffd..ca78fd75e08 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 ac187dadc70..e294c614517 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 8bae3743620..8247e4c8cff 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 38263033a2e..465317e9ff0 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 26ba9c3aa10..95dd7e8ae18 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 a0c0804c42b..0f75c46b1fd 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 a75f14bc2fa..b4b9fad108d 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 96c44ccb699..cb1acf34577 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 aae67a7bef9..aeb23fde44d 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 000cb23f749..527f7776f13 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 2e09f374dd1..33ed8352129 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 a127021ef14..58a014fa021 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 722577c8ec0..954d55c9dd8 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 ecf9daecfd3..c3aa8000fbc 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 8349d710acb..9424501538c 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 3b187f64652..d660fe7138e 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 9d5a74665cd..e78812db026 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 1856ac4cdd4..5132f8bec0b 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 54834399310..8521764eaee 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 adb0c90d156..1f015520ea2 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 2d60910ab24..bfea737bb12 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 c28220f6503..6e76efed8d5 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 3a7675a7906..f3aa7fbb005 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 96da01ca2f7..9cba89e3f14 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 1ee11d74182..ae99e9e6c15 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 de564c0017c..3d7d3ccb134 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 688325b27ec..5e6ffb963ef 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 bdd6fff7204..08115f1b552 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 18d81fd56f7..af1f4d62822 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 2f45b32a7b4..bd330088c1c 100644 --- a/src/terminal/adapter/ut_adapter/adapterTest.cpp +++ b/src/terminal/adapter/ut_adapter/adapterTest.cpp @@ -1794,7 +1794,7 @@ class AdapterTest 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 b06bfa84e82..ca469663849 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 2fc1e9f26b5..39847cafdf4 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 6e031fb44d6..9bad6a12437 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 a98531bd158..7dce7b739cc 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 c79d2c8cd4f..364fd046f48 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 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; }); - } + const auto l = 5; + const auto t = 10; + const auto r = 15; + const auto b = 20; - 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 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 auto l = 5; + const auto t = 10; + const auto r = 15; + const auto b = 20; + + 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)); - } - - Log::Comment(L"1.) Out of bounds too low."); - { - 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; }); + VERIFY_ARE_EQUAL(expected, rc.point_at(72)); } - Log::Comment(L"2.) Out of bounds too high."); + Log::Comment(L"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"); - { - { - til::rectangle converted{ til::math::ceiling, lowerFloatIntegral }; - VERIFY_ARE_EQUAL((til::rectangle{ 1, 2, 3, 4 }), converted); - } - { - til::rectangle converted{ til::math::ceiling, lowerFloat }; - VERIFY_ARE_EQUAL((til::rectangle{ 2, 3, 4, 5 }), converted); - } - { - til::rectangle converted{ til::math::ceiling, capitalDoubleIntegral }; - VERIFY_ARE_EQUAL((til::rectangle{ 3, 4, 5, 6 }), converted); - } - { - til::rectangle converted{ til::math::ceiling, capitalDouble }; - VERIFY_ARE_EQUAL((til::rectangle{ 4, 5, 6, 7 }), converted); - } - } - - Log::Comment(L"1.) Flooring"); + Log::Comment(L"Ceiling"); { { - til::rectangle converted{ til::math::flooring, 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::flooring, lowerFloat }; - VERIFY_ARE_EQUAL((til::rectangle{ 1, 2, 3, 4 }), 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::flooring, 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::flooring, capitalDouble }; - VERIFY_ARE_EQUAL((til::rectangle{ 3, 4, 5, 6 }), 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"2.) Rounding"); + Log::Comment(L"Flooring"); { { - til::rectangle converted{ til::math::rounding, 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::rounding, lowerFloat }; - VERIFY_ARE_EQUAL((til::rectangle{ 2, 2, 3, 5 }), 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::rounding, 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::rounding, capitalDouble }; - VERIFY_ARE_EQUAL((til::rectangle{ 4, 4, 6, 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"3.) Truncating"); + Log::Comment(L"Rounding"); { { - til::rectangle converted{ til::math::truncating, 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::truncating, lowerFloat }; - VERIFY_ARE_EQUAL((til::rectangle{ 1, 2, 3, 4 }), 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::truncating, 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::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 ad1d64243ae..1f9483ca787 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 880e186cecd..bca24d3cbca 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 2bc7411d9dd..58a6f4f982f 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 c9089438d1b..0f6a843fd8e 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 ac4461d7a6a..13b69909996 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 51c2d8019bb..3f3d05e1b76 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";