Repository: microsoft/terminal (language: cpp)

Issue:
RangeFromPoint and ExpandToEnclosingUnit freezes terminal
### Windows Terminal version

1.20.11781.0

### Windows build number

10.0.22631.0

### Other Software

https://github.com/yinkaisheng/Python-UIAutomation-for-Windows 2.0.19

### Steps to reproduce

```python
import uiautomation as auto
import time
import typing
time.sleep(5)
[x,y] = auto.GetCursorPos()
c = auto.ControlFromPoint(x,y)
if text_pattern := typing.cast(auto.TextPattern | None, c.GetPattern(auto.PatternId.TextPattern)):
    if r := text_pattern.RangeFromPoint(x,y):
        r.ExpandToEnclosingUnit(auto.TextUnit.Word)
        print(r.GetText())
```
Put the cursor over a terminal window

### Expected Behavior

I get the word under the cursor.

### Actual Behavior

Windows terminals freezes. This program works fine with other software so I don't think the bug is in UIAutomation.


Discussion / hints:

Fix patch:
diff --git a/src/interactivity/win32/uiaTextRange.cpp b/src/interactivity/win32/uiaTextRange.cpp
index eb78d090cfc..028e181b383 100644
--- a/src/interactivity/win32/uiaTextRange.cpp
+++ b/src/interactivity/win32/uiaTextRange.cpp
@@ -69,14 +69,14 @@ IFACEMETHODIMP UiaTextRange::Clone(_Outptr_result_maybenull_ ITextRangeProvider*
     return S_OK;
 }
 
-void UiaTextRange::_TranslatePointToScreen(til::point* clientPoint) const
+void UiaTextRange::_TranslatePointToScreen(til::point& clientPoint) const
 {
-    ClientToScreen(_getWindowHandle(), clientPoint->as_win32_point());
+    ClientToScreen(_getWindowHandle(), clientPoint.as_win32_point());
 }
 
-void UiaTextRange::_TranslatePointFromScreen(til::point* screenPoint) const
+void UiaTextRange::_TranslatePointFromScreen(til::point& screenPoint) const
 {
-    ScreenToClient(_getWindowHandle(), screenPoint->as_win32_point());
+    ScreenToClient(_getWindowHandle(), screenPoint.as_win32_point());
 }
 
 HWND UiaTextRange::_getWindowHandle() const
diff --git a/src/interactivity/win32/uiaTextRange.hpp b/src/interactivity/win32/uiaTextRange.hpp
index 7ea79364d5d..84f8b5a5392 100644
--- a/src/interactivity/win32/uiaTextRange.hpp
+++ b/src/interactivity/win32/uiaTextRange.hpp
@@ -56,8 +56,8 @@ namespace Microsoft::Console::Interactivity::Win32
         IFACEMETHODIMP Clone(_Outptr_result_maybenull_ ITextRangeProvider** ppRetVal) override;
 
     protected:
-        void _TranslatePointToScreen(til::point* clientPoint) const override;
-        void _TranslatePointFromScreen(til::point* screenPoint) const override;
+        void _TranslatePointToScreen(til::point& clientPoint) const override;
+        void _TranslatePointFromScreen(til::point& screenPoint) const override;
 
     private:
         HWND _getWindowHandle() const;
diff --git a/src/types/TermControlUiaTextRange.cpp b/src/types/TermControlUiaTextRange.cpp
index 6f3c82e8180..5b26dd5189d 100644
--- a/src/types/TermControlUiaTextRange.cpp
+++ b/src/types/TermControlUiaTextRange.cpp
@@ -73,7 +73,7 @@ IFACEMETHODIMP TermControlUiaTextRange::Clone(_Outptr_result_maybenull_ ITextRan
 //                (0,0) is the top-left of the app window
 // Return Value:
 // - <none>
-void TermControlUiaTextRange::_TranslatePointToScreen(til::point* clientPoint) const
+void TermControlUiaTextRange::_TranslatePointToScreen(til::point& clientPoint) const
 {
     const gsl::not_null<TermControlUiaProvider*> provider = static_cast<TermControlUiaProvider*>(_pProvider);
 
@@ -96,8 +96,8 @@ void TermControlUiaTextRange::_TranslatePointToScreen(til::point* clientPoint) c
     // Get scale factor for display
     const auto scaleFactor = provider->GetScaleFactor();
 
-    clientPoint->x = includeOffsets(clientPoint->x, boundingRect.left, padding.left, scaleFactor);
-    clientPoint->y = includeOffsets(clientPoint->y, boundingRect.top, padding.top, scaleFactor);
+    clientPoint.x = includeOffsets(clientPoint.x, boundingRect.left, padding.left, scaleFactor);
+    clientPoint.y = includeOffsets(clientPoint.y, boundingRect.top, padding.top, scaleFactor);
 }
 
 // Method Description:
@@ -107,15 +107,13 @@ void TermControlUiaTextRange::_TranslatePointToScreen(til::point* clientPoint) c
 //                (0,0) is the top-left of the screen
 // Return Value:
 // - <none>
-void TermControlUiaTextRange::_TranslatePointFromScreen(til::point* screenPoint) const
+void TermControlUiaTextRange::_TranslatePointFromScreen(til::point& screenPoint) const
 {
     const gsl::not_null<TermControlUiaProvider*> provider = static_cast<TermControlUiaProvider*>(_pProvider);
 
     const auto includeOffsets = [](long screenPos, double termControlPos, double padding, double scaleFactor) {
-        auto result = base::ClampedNumeric<double>(padding);
-        // only the padding is in DIPs now
-        result /= scaleFactor;
-        result -= screenPos;
+        auto result = base::ClampedNumeric<til::CoordType>(screenPos);
+        result -= padding / scaleFactor;
         result -= termControlPos;
         return result;
     };
@@ -130,8 +128,8 @@ void TermControlUiaTextRange::_TranslatePointFromScreen(til::point* screenPoint)
     // Get scale factor for display
     const auto scaleFactor = provider->GetScaleFactor();
 
-    screenPoint->x = includeOffsets(screenPoint->x, boundingRect.left, padding.left, scaleFactor);
-    screenPoint->y = includeOffsets(screenPoint->y, boundingRect.top, padding.top, scaleFactor);
+    screenPoint.x = includeOffsets(screenPoint.x, boundingRect.left, padding.left, scaleFactor);
+    screenPoint.y = includeOffsets(screenPoint.y, boundingRect.top, padding.top, scaleFactor);
 }
 
 til::size TermControlUiaTextRange::_getScreenFontSize() const noexcept
diff --git a/src/types/TermControlUiaTextRange.hpp b/src/types/TermControlUiaTextRange.hpp
index 70ba9cac979..e619583a9e9 100644
--- a/src/types/TermControlUiaTextRange.hpp
+++ b/src/types/TermControlUiaTextRange.hpp
@@ -56,8 +56,8 @@ namespace Microsoft::Terminal
         IFACEMETHODIMP Clone(_Outptr_result_maybenull_ ITextRangeProvider** ppRetVal) override;
 
     protected:
-        void _TranslatePointToScreen(til::point* clientPoint) const override;
-        void _TranslatePointFromScreen(til::point* screenPoint) const override;
+        void _TranslatePointToScreen(til::point& clientPoint) const override;
+        void _TranslatePointFromScreen(til::point& screenPoint) const override;
         til::size _getScreenFontSize() const noexcept override;
     };
 }
diff --git a/src/types/UiaTextRangeBase.cpp b/src/types/UiaTextRangeBase.cpp
index 8e83ef47aa0..0ce958e6985 100644
--- a/src/types/UiaTextRangeBase.cpp
+++ b/src/types/UiaTextRangeBase.cpp
@@ -97,30 +97,24 @@ CATCH_RETURN();
 
 void UiaTextRangeBase::Initialize(_In_ const UiaPoint point)
 {
-    til::point clientPoint;
-    clientPoint.x = static_cast<LONG>(point.x);
-    clientPoint.y = static_cast<LONG>(point.y);
-    // get row that point resides in
+    til::point clientPoint{ static_cast<til::CoordType>(point.x), static_cast<til::CoordType>(point.y) };
+
+    // clamp the point to be within the client area
     const auto windowRect = _getTerminalRect();
+    clientPoint.x = std::clamp(clientPoint.x, windowRect.left, windowRect.right);
+    clientPoint.y = std::clamp(clientPoint.y, windowRect.top, windowRect.bottom);
+
+    // convert point to be relative to client area
+    _TranslatePointFromScreen(clientPoint);
+
+    // convert the point to screen buffer coordinates
+    _pData->LockConsole();
+    const auto currentFontSize = _getScreenFontSize();
     const auto viewport = _pData->GetViewport().ToInclusive();
-    til::CoordType row = 0;
-    if (clientPoint.y <= windowRect.top)
-    {
-        row = viewport.top;
-    }
-    else if (clientPoint.y >= windowRect.bottom)
-    {
-        row = viewport.bottom;
-    }
-    else
-    {
-        // change point coords to pixels relative to window
-        _TranslatePointFromScreen(&clientPoint);
+    _pData->UnlockConsole();
 
-        const auto currentFontSize = _getScreenFontSize();
-        row = clientPoint.y / currentFontSize.height + viewport.top;
-    }
-    _start = { 0, row };
+    _start = { clientPoint.x / currentFontSize.width + viewport.left,
+               clientPoint.y / currentFontSize.height + viewport.top };
     _end = _start;
 }
 
@@ -1381,8 +1375,8 @@ void UiaTextRangeBase::_getBoundingRect(const til::rect& textRect, _Inout_ std::
 
     // convert the coords to be relative to the screen instead of
     // the client window
-    _TranslatePointToScreen(&topLeft);
-    _TranslatePointToScreen(&bottomRight);
+    _TranslatePointToScreen(topLeft);
+    _TranslatePointToScreen(bottomRight);
 
     const long width = bottomRight.x - topLeft.x;
     const long height = bottomRight.y - topLeft.y;
diff --git a/src/types/UiaTextRangeBase.hpp b/src/types/UiaTextRangeBase.hpp
index eec30a3dcbd..2b36ccc0efa 100644
--- a/src/types/UiaTextRangeBase.hpp
+++ b/src/types/UiaTextRangeBase.hpp
@@ -123,8 +123,8 @@ namespace Microsoft::Console::Types
         std::wstring _wordDelimiters{};
         ::Search _searcher;
 
-        virtual void _TranslatePointToScreen(til::point* clientPoint) const = 0;
-        virtual void _TranslatePointFromScreen(til::point* screenPoint) const = 0;
+        virtual void _TranslatePointToScreen(til::point& clientPoint) const = 0;
+        virtual void _TranslatePointFromScreen(til::point& screenPoint) const = 0;
 
         void Initialize(_In_ const UiaPoint point);
 


Test patch: