diff --git a/dev/WebView2/InteractionTests/WebView2Tests.cs b/dev/WebView2/InteractionTests/WebView2Tests.cs
index 6f98836ae6..e4944ade48 100644
--- a/dev/WebView2/InteractionTests/WebView2Tests.cs
+++ b/dev/WebView2/InteractionTests/WebView2Tests.cs
@@ -880,7 +880,7 @@ public void MultipleWebviews_FocusTest()
Log.Comment("Focus on tabstop1");
x1.SetFocus();
Wait.ForIdle();
- Verify.IsTrue(x1.HasKeyboardFocus);
+ Verify.IsTrue(x1.HasKeyboardFocus, "TabStopButton1 has keyboard focus");
Log.Comment("Tab tabstop1 -> MyWebView2");
KeyboardHelper.PressKey(Key.Tab);
@@ -1167,13 +1167,11 @@ public void MouseCaptureTest()
PointerInput.Press(PointerButtons.Primary);
PointerInput.Move(outsidePoint);
PointerInput.Release(PointerButtons.Primary);
- Wait.ForIdle();
// Move mouse back across text
// If the WebView did not correctly handle captured mouse input then the text will be deselected
// due to the WebView still thinking that the mouse's left-button is pressed.
PointerInput.Move(startPoint);
- Wait.ForIdle();
using (var pasteTestWaiter = new ValueChangedEventWaiter(CopyPasteTextBox2, "MouseCaptureResult"))
{
@@ -1338,7 +1336,6 @@ public void ResizeTest()
[TestMethod]
[TestProperty("Ignore", "True")] // Task 31708332: WebView2 Touch Tests still failing on Helix
- [TestProperty("Ignore", "True")] //Task 31704068: Unreliable tests: WebView2 BasicTapTouchTest, BasicFlingTouchTest, BasicLongPressTouchTest
[TestProperty("TestSuite", "B")]
public void BasicTapTouchTest()
{
@@ -1366,7 +1363,6 @@ public void BasicTapTouchTest()
[TestMethod]
[TestProperty("Ignore", "True")] // Task 31708332: WebView2 Touch Tests still failing on Helix
- [TestProperty("Ignore", "True")] //Task 31704068: Unreliable tests: WebView2 BasicTapTouchTest, BasicFlingTouchTest, BasicLongPressTouchTest
[TestProperty("TestSuite", "B")]
public void BasicFlingTouchTest()
{
@@ -1553,7 +1549,6 @@ public void ReparentElementTest()
CompleteTestAndWaitForResult("ReparentElementTest");
// Ensure that the moved WebView is still visible
- Log.Comment("ReparentElementTest Test App Result ignored due to RTB issues with the test. Verifying from the test runner.");
WebView2Temporary.WebView2RenderingVerifier.VerifyInstances("ReparentElementTest");
}
}
@@ -2013,7 +2008,7 @@ public void CloseThenDPIChangeTest()
[TestMethod] // Test fails because .NET UWP doesn't support Object -> VARIANT marshalling.
[TestProperty("TestSuite", "D")]
- [TestProperty("Ignore", "True")] // 32510465
+ [TestProperty("Ignore", "True")]
public void AddHostObjectToScriptTest()
{
if (!PlatformConfiguration.IsOsVersionGreaterThanOrEqual(OSVersion.Redstone5))
@@ -2149,10 +2144,68 @@ public void HtmlDropdownTest()
}
}
+ [TestMethod]
+ [TestProperty("TestSuite", "D")]
+ public void HiddenThenVisibleTest()
+ {
+ using (var setup = new WebView2TestSetupHelper(new[] { "WebView2 Tests", "navigateToBasicWebView2" }))
+ {
+ ChooseTest("HiddenThenVisibleTest");
+ CompleteTestAndWaitForResult("HiddenThenVisibleTest");
+
+ // Clear the cache so we can find the new webview
+ ElementCache.Clear();
+ var webview = FindElement.ById("MyWebView2");
+ Verify.IsTrue(webview.IsOffscreen == false);
+
+ // Click in the webview to ensure we can interact with it
+ Rectangle bounds = webview.BoundingRectangle;
+ Log.Comment("Bounds = X:{0}, Y:{1}, Width:{2}, Height:{3}", bounds.X, bounds.Y, bounds.Width, bounds.Height);
+ var point = new Point(bounds.X + 20, bounds.Y + 20);
+ Log.Comment("Move mouse to ({0}, {1})", bounds.X + 20, bounds.Y + 20);
+ PointerInput.Move(point);
+
+ PointerInput.Press(PointerButtons.Primary);
+ PointerInput.Release(PointerButtons.Primary);
+ Wait.ForIdle();
+
+ WaitForWebMessageResult("HiddenThenVisibleTest");
+ }
+ }
+
+ [TestMethod]
+ [TestProperty("TestSuite", "D")]
+ public void ParentHiddenThenVisibleTest()
+ {
+ using (var setup = new WebView2TestSetupHelper(new[] { "WebView2 Tests", "navigateToBasicWebView2" }))
+ {
+ ChooseTest("ParentHiddenThenVisibleTest");
+ CompleteTestAndWaitForResult("ParentHiddenThenVisibleTest");
+
+ // Clear the cache so we can find the new webview
+ ElementCache.Clear();
+ var webview = FindElement.ById("MyWebView2");
+ Verify.IsTrue(webview.IsOffscreen == false);
+
+ // Click in the webview to ensure we can interact with it
+ Rectangle bounds = webview.BoundingRectangle;
+ Log.Comment("Bounds = X:{0}, Y:{1}, Width:{2}, Height:{3}", bounds.X, bounds.Y, bounds.Width, bounds.Height);
+ var point = new Point(bounds.X + 20, bounds.Y + 20);
+ Log.Comment("Move mouse to ({0}, {1})", bounds.X + 20, bounds.Y + 20);
+ PointerInput.Move(point);
+
+ PointerInput.Press(PointerButtons.Primary);
+ PointerInput.Release(PointerButtons.Primary);
+ Wait.ForIdle();
+
+ WaitForWebMessageResult("ParentHiddenThenVisibleTest");
+ }
+ }
+
private static void BeginSubTest(string testName, string testDescription)
{
Log.Comment(Environment.NewLine + testName + ": " + testDescription);
-
+
Log.Comment("Resetting event and exception counts...");
Button resetCounts_Button = new Button(FindElement.ById("ResetCounts_Button"));
resetCounts_Button.Invoke();
diff --git a/dev/WebView2/TestUI/WebView2BasicPage.xaml b/dev/WebView2/TestUI/WebView2BasicPage.xaml
index fe01d5005d..b2e7fc2cd7 100644
--- a/dev/WebView2/TestUI/WebView2BasicPage.xaml
+++ b/dev/WebView2/TestUI/WebView2BasicPage.xaml
@@ -42,6 +42,7 @@
Focus_MouseActivateTest
Focus_ReverseTabTest
GoBackAndForwardTest
+ HiddenThenVisibleTest
HostNameToFolderMappingTest
HtmlDropdownTest
MouseCaptureTest
@@ -63,6 +64,7 @@
NavigationStartingTest
NonAsciiUriTest
OffTreeWebViewInputTest
+ ParentHiddenThenVisibleTest
ParentVisibilityHiddenTest
ParentVisibilityTurnedOnTest
PointerReleaseWithoutPressTest
@@ -175,7 +177,7 @@
-
+
diff --git a/dev/WebView2/TestUI/WebView2BasicPage.xaml.cs b/dev/WebView2/TestUI/WebView2BasicPage.xaml.cs
index 472772b557..c84cd9f8d1 100644
--- a/dev/WebView2/TestUI/WebView2BasicPage.xaml.cs
+++ b/dev/WebView2/TestUI/WebView2BasicPage.xaml.cs
@@ -197,6 +197,8 @@ enum TestList
NonAsciiUriTest,
OffTreeWebViewInputTest,
HtmlDropdownTest,
+ HiddenThenVisibleTest,
+ ParentHiddenThenVisibleTest
};
// Map of TestList entry to its webpage (index in TestPageNames[])
@@ -260,6 +262,8 @@ enum TestList
{ TestList.NonAsciiUriTest, 7 },
{ TestList.OffTreeWebViewInputTest, 1 },
{ TestList.HtmlDropdownTest, 5 },
+ { TestList.HiddenThenVisibleTest, 1 },
+ { TestList.ParentHiddenThenVisibleTest, 1 },
};
readonly string[] TestPageNames =
@@ -537,7 +541,7 @@ private void TestNameComboBox_SelectionChanged(object sender, SelectionChangedEv
{
AddWebViewControl("MyWebView2B");
AddWebViewControl("MyWebView2C");
- WebView2Common.LoadWebPage(MyWebView2, TestPageNames[0]);
+ WebView2Common.LoadWebPage(MyWebView2, TestPageNames[TestInfoDictionary[test]]);
}
break;
case TestList.MultipleWebviews_FocusTest:
@@ -565,9 +569,7 @@ private void TestNameComboBox_SelectionChanged(object sender, SelectionChangedEv
case TestList.SourceBeforeLoadTest:
{
// Remove existing WebView, we're going to replace it
- RemoveWebViewEventHandlers(MyWebView2);
- Border parentBorder = MyWebView2.Parent as Border;
- parentBorder.Child = null;
+ Border parentBorder = RemoveExistingWebViewControl(MyWebView2);
Uri uri = WebView2Common.GetTestPageUri("SimplePageWithButton.html");
var newWebView2 = new WebView2() {
@@ -612,9 +614,7 @@ private void TestNameComboBox_SelectionChanged(object sender, SelectionChangedEv
case TestList.WindowlessPopupTest:
{
// Remove existing WebView so it doesn't get confused with the one in the popup
- RemoveWebViewEventHandlers(MyWebView2);
- Border parentBorder = MyWebView2.Parent as Border;
- parentBorder.Child = null;
+ _ = RemoveExistingWebViewControl(MyWebView2);
// Create popup contents: a new webview
var webviewInPopup = new WebView2() {
@@ -662,9 +662,7 @@ private void TestNameComboBox_SelectionChanged(object sender, SelectionChangedEv
case TestList.CursorUpdateTest:
{
// Remove existing WebView, we're going to replace it
- RemoveWebViewEventHandlers(MyWebView2);
- Border parentBorder = MyWebView2.Parent as Border;
- parentBorder.Child = null;
+ Border parentBorder = RemoveExistingWebViewControl(MyWebView2);
// Insert webview with public ProtectedCursor
var newWebView2 = new WebView2WithCursor() {
@@ -691,12 +689,69 @@ private void TestNameComboBox_SelectionChanged(object sender, SelectionChangedEv
case TestList.OffTreeWebViewInputTest:
{
// Remove existing webview
- RemoveWebViewEventHandlers(MyWebView2);
- Border parentBorder = MyWebView2.Parent as Border;
- parentBorder.Child = null;
+ Border parentBorder = RemoveExistingWebViewControl(MyWebView2);
parentBorder.BorderBrush = new SolidColorBrush(Colors.Pink);
}
break;
+ case TestList.HiddenThenVisibleTest:
+ {
+ // Remove existing WebView, we're going to replace it with a hidden one
+ Border parentBorder = RemoveExistingWebViewControl(MyWebView2);
+ var parentStackPanel = parentBorder.Parent as StackPanel;
+ parentStackPanel.Children.Remove(parentBorder);
+
+ // Create a new border that gets its size from the webview
+ var newBorder = new Border() {
+ BorderBrush = new SolidColorBrush(Colors.Red),
+ BorderThickness = new Thickness(5)
+ };
+
+ // Add a new, collapsed WebView2 into the tree
+ var uri = WebView2Common.GetTestPageUri(TestPageNames[TestInfoDictionary[test]]);
+ var newWebView2 = new WebView2() {
+ Name = "MyWebView2",
+ Margin = new Thickness(8, 8, 8, 8),
+ Width = 670,
+ Height = 370,
+ Source = uri,
+ Visibility = Visibility.Collapsed,
+ };
+ AutomationProperties.SetName(newWebView2, "MyWebView2");
+ newBorder.Child = newWebView2;
+ parentStackPanel.Children.Add(newBorder);
+ AddWebViewEventHandlers(newWebView2);
+ }
+ break;
+ case TestList.ParentHiddenThenVisibleTest:
+ {
+ // Remove existing WebView, we're going to replace it with a hidden one
+ Border parentBorder = RemoveExistingWebViewControl(MyWebView2);
+ var parentStackPanel = parentBorder.Parent as StackPanel;
+ parentStackPanel.Children.Remove(parentBorder);
+
+ // Create a new, collapsed border that gets its size from the webview
+ var newBorder = new Border() {
+ BorderBrush = new SolidColorBrush(Colors.Red),
+ BorderThickness = new Thickness(5),
+ Visibility = Visibility.Collapsed
+ };
+
+ // Add a new WebView2 into the tree
+ var uri = WebView2Common.GetTestPageUri(TestPageNames[TestInfoDictionary[test]]);
+ var newWebView2 = new WebView2() {
+ Name = "MyWebView2",
+ Margin = new Thickness(8, 8, 8, 8),
+ Width = 670,
+ Height = 370,
+ Source = uri,
+ Visibility = Visibility.Visible,
+ };
+ AutomationProperties.SetName(newWebView2, "MyWebView2");
+ newBorder.Child = newWebView2;
+ parentStackPanel.Children.Add(newBorder);
+ AddWebViewEventHandlers(newWebView2);
+ }
+ break;
default:
WebView2Common.LoadWebPage(MyWebView2, TestPageNames[TestInfoDictionary[test]]);
break;
@@ -903,6 +958,14 @@ void MoveWebViewControl(string webviewName, WebView2 webView2)
WebView2Collection.Children.Add(stackPanel);
}
+ Border RemoveExistingWebViewControl(WebView2 webview)
+ {
+ RemoveWebViewEventHandlers(webview);
+ Border parentBorder = webview.Parent as Border;
+ parentBorder.Child = null;
+ return parentBorder;
+ }
+
void AddWebViewEventHandlers(WebView2 webview)
{
webview.NavigationStarting += OnNavigationStarting;
@@ -1119,6 +1182,11 @@ public void VerifyWebMessageBasedTest(string stringResult, string jsonResult)
expectedStringResult = "Left mouse button clicked.";
break;
+ case TestList.HiddenThenVisibleTest:
+ case TestList.ParentHiddenThenVisibleTest:
+ expectedStringResult = "Left mouse button clicked.";
+ break;
+
default:
{
logger.LogError("Unexpected test type in VerifyWebMessageBasedTest(), got message: " + stringResult);
@@ -1807,6 +1875,36 @@ async public void CompleteCurrentTest(object sender, RoutedEventArgs args)
selectedTest, selctedOption));;
}
break;
+ case TestList.HiddenThenVisibleTest:
+ {
+ logger.Verify(MyWebView2.Visibility == Visibility.Collapsed,
+ string.Format("Test {0}: Incorrect setup, Expected MyWebView2.Visibility to be Collapsed, was {1}",
+ selectedTest, MyWebView2.Visibility));
+
+ // Make WebView2 visible
+ MyWebView2.Visibility = Visibility.Visible;
+
+ logger.Verify(MyWebView2.IsHitTestVisible,
+ string.Format("Test {0}: Failed, Expected MyWebView2.IsHitTestVisible to be true, was {1}",
+ selectedTest, MyWebView2.IsHitTestVisible));
+ }
+ break;
+ case TestList.ParentHiddenThenVisibleTest:
+ {
+ var parentBorder = MyWebView2.Parent as Border;
+
+ logger.Verify(parentBorder.Visibility == Visibility.Collapsed,
+ string.Format("Test {0}: Incorrect setup, Expected MyWebView2.Visibility to be Collapsed, was {1}",
+ selectedTest, parentBorder.Visibility));
+
+ // Make WebView2's parent Border visible
+ parentBorder.Visibility = Visibility.Visible;
+
+ logger.Verify(MyWebView2.IsHitTestVisible,
+ string.Format("Test {0}: Failed, Expected MyWebView2.IsHitTestVisible to be true, was {1}",
+ selectedTest, MyWebView2.IsHitTestVisible));
+ }
+ break;
default:
break;
diff --git a/dev/WebView2/WebView2.cpp b/dev/WebView2/WebView2.cpp
index 2d97376b23..d1c8cba750 100644
--- a/dev/WebView2/WebView2.cpp
+++ b/dev/WebView2/WebView2.cpp
@@ -833,24 +833,28 @@ void WebView2::CreateMissingAnaheimWarning()
Content(warning);
}
-// We could have a child TextBlock (see CreateMissingAnaheimWarning), make sure it is visited by Measure pass.
+// We could have a child Grid (see AddChildPanel) or a child TextBlock (see CreateMissingAnaheimWarning).
+// Make sure it is visited by the Measure pass.
winrt::Size WebView2::MeasureOverride(winrt::Size const& availableSize)
{
//if (auto child = Content().try_as())
//{
- // Content().Measure(availableSize);
+ // child.Measure(availableSize);
+ // return child.DesiredSize;
//}
return __super::MeasureOverride(availableSize);
}
-// We could have a child TextBlock (see CreateMissingAnaheimWarning), make sure it is visited by Arrange pass.
+// We could have a child Grid (see AddChildPanel) or a child TextBlock (see CreateMissingAnaheimWarning).
+// Make sure it is visited by the Arrange pass.
winrt::Size WebView2::ArrangeOverride(winrt::Size const& finalSize)
{
- //if (auto child = Content().try_as())
- //{
- // Content().Arrange(winrt::Rect{ winrt::Point{0,0}, finalSize });
- //}
+ if (auto child = Content().try_as())
+ {
+ child.Arrange(winrt::Rect{ winrt::Point{0,0}, finalSize });
+ return finalSize;
+ }
return __super::ArrangeOverride(finalSize);
}
@@ -1505,6 +1509,28 @@ void WebView2::TryCompleteInitialization()
[this](auto&&, auto&&) { UpdateDefaultBackgroundColor(); });
}
+ // WebView2 in WinUI 2 is a ContentControl that either renders its web content to a SpriteVisual, or in the case that
+ // the WebView2 Runtime is not installed, renders a message to that effect as its Content. In the case where the
+ // WebView2 starts with Visibility.Collapsed, hit testing code has trouble seeing the WebView2 if it does not have
+ // Content. To work around this, give the WebView2 a transparent Grid as Content that hit testing can find. The size
+ // of this Grid must be kept in sync with the size of the WebView2 (see ResizeChildPanel()).
+ AddChildPanel();
+
+ CreateAndSetVisual();
+
+ // If we were recreating the webview after a core process failure, indicate that we have now recovered
+ m_isCoreFailure_BrowserExited_State = false;
+}
+
+void WebView2::AddChildPanel()
+{
+ auto panelContent = winrt::Grid();
+ panelContent.Background(winrt::SolidColorBrush(winrt::Colors::Transparent()));
+ Content(panelContent);
+}
+
+void WebView2::CreateAndSetVisual()
+{
#ifdef WINUI3
if (!m_systemVisualBridge)
{
@@ -1534,10 +1560,6 @@ void WebView2::TryCompleteInitialization()
auto coreWebView2CompositionControllerInterop = m_coreWebViewCompositionController.as();
winrt::check_hresult(coreWebView2CompositionControllerInterop->put_RootVisualTarget(m_visual.as<::IUnknown>().get()));
#endif
-
-
- // If we were recreating the webview after a core process failure, indicate that we have now recovered
- m_isCoreFailure_BrowserExited_State = false;
}
winrt::IAsyncOperation WebView2::ExecuteScriptAsync(winrt::hstring javascriptCode)
@@ -1763,7 +1785,8 @@ void WebView2::CheckAndUpdateWebViewPosition()
return;
}
- // Check if the position of the WebView within the window has changed
+ // Check if the position of the WebView2 within the window has changed
+ bool changed = false;
auto transform = TransformToVisual(nullptr);
auto topLeft = transform.TransformPoint(winrt::Point(0, 0));
@@ -1774,13 +1797,32 @@ void WebView2::CheckAndUpdateWebViewPosition()
{
m_webViewScaledPosition.X = scaledTopLeftX;
m_webViewScaledPosition.Y = scaledTopLeftY;
+ changed = true;
}
- m_webViewScaledSize.X = ceil(static_cast(ActualWidth()) * m_rasterizationScale);
- m_webViewScaledSize.Y = ceil(static_cast(ActualHeight()) * m_rasterizationScale);
+ auto scaledSizeX = ceil(static_cast(ActualWidth()) * m_rasterizationScale);
+ auto scaledSizeY = ceil(static_cast(ActualHeight()) * m_rasterizationScale);
+ if (scaledSizeX != m_webViewScaledSize.X || scaledSizeY != m_webViewScaledSize.Y)
+ {
+ m_webViewScaledSize.X = scaledSizeX;
+ m_webViewScaledSize.Y = scaledSizeY;
+ changed = true;
+ }
+
+ if (changed)
+ {
+ // We create the Bounds using X, Y, width, and height
+ m_coreWebViewController.Bounds({
+ (m_webViewScaledPosition.X),
+ (m_webViewScaledPosition.Y),
+ (m_webViewScaledSize.X),
+ (m_webViewScaledSize.Y) });
+ }
+}
- // We create the Bounds using X, Y, width, and height
- m_coreWebViewController.Bounds({
+winrt::Rect WebView2::GetBoundingRectangle()
+{
+ return winrt::Rect({
(m_webViewScaledPosition.X),
(m_webViewScaledPosition.Y),
(m_webViewScaledSize.X),
diff --git a/dev/WebView2/WebView2.h b/dev/WebView2/WebView2.h
index dfa4a69d21..d485fb5404 100644
--- a/dev/WebView2/WebView2.h
+++ b/dev/WebView2/WebView2.h
@@ -99,6 +99,8 @@ class WebView2 :
winrt::CoreWebView2 CoreWebView2(); // Getter for CoreWebView2 property (read-only)
+ winrt::Rect GetBoundingRectangle();
+
private:
bool ShouldNavigate(const winrt::Uri& uri);
winrt::IAsyncAction OnSourceChanged(winrt::Uri providedUri);
@@ -155,6 +157,8 @@ class WebView2 :
void XamlRootChangedHelper(bool forceUpdate);
void TryCompleteInitialization();
void DisconnectFromRootVisualTarget();
+ void CreateAndSetVisual();
+ void AddChildPanel();
void CheckAndUpdateWebViewPosition();
void CheckAndUpdateWindowPosition();
diff --git a/dev/WebView2/WebView2AutomationPeer.cpp b/dev/WebView2/WebView2AutomationPeer.cpp
index fe53510c38..8e81b06f40 100644
--- a/dev/WebView2/WebView2AutomationPeer.cpp
+++ b/dev/WebView2/WebView2AutomationPeer.cpp
@@ -36,6 +36,12 @@ winrt::AutomationControlType WebView2AutomationPeer::GetAutomationControlTypeCor
return winrt::AutomationControlType::Pane;
}
+winrt::Rect WebView2AutomationPeer::GetBoundingRectangleCore()
+{
+ winrt::Rect boundingRect = GetImpl()->GetBoundingRectangle();
+ return boundingRect;
+}
+
#if WINUI3
HRESULT WebView2AutomationPeer::GetRawElementProviderSimple(_Outptr_opt_ IRawElementProviderSimple** value)
{
diff --git a/dev/WebView2/WebView2AutomationPeer.h b/dev/WebView2/WebView2AutomationPeer.h
index 93383b302f..51aa2e5bfb 100644
--- a/dev/WebView2/WebView2AutomationPeer.h
+++ b/dev/WebView2/WebView2AutomationPeer.h
@@ -20,6 +20,7 @@ class WebView2AutomationPeer :
// IAutomationPeerOverrides
winrt::hstring GetClassNameCore();
winrt::AutomationControlType GetAutomationControlTypeCore();
+ winrt::Rect GetBoundingRectangleCore();
winrt::IInspectable GetFocusedElementCore();
winrt::IInspectable NavigateCore(winrt::AutomationNavigationDirection direction);