Title: [295098] trunk
Revision
295098
Author
akeer...@apple.com
Date
2022-06-01 11:32:53 -0700 (Wed, 01 Jun 2022)

Log Message

[iOS] WKWebViews can get into a state with multiple find overlays
https://bugs.webkit.org/show_bug.cgi?id=241163
rdar://93904570

Reviewed by Devin Rousso.

When `-[WKWebView didEndTextSearchOperation]` and `-[WKWebView didBeginTextSearchOperation]`
are called in quick succession, the web view can get into a state with multiple
find overlays. This state occurs because `didBeginTextSearchOperation` nulls out
the find overlay before the fade out animation has finished.
`didBeginTextSearchOperation` then observes that there is no find overlay, and
adds another overlay.

To fix, the page overlay member should be nulled out at the right time.

* Source/WebKit/WebProcess/WebPage/WebFoundTextRangeController.cpp:
(WebKit::WebFoundTextRangeController::didBeginTextSearchOperation):

If there is already a find overlay, cancel its removal if it is being
uninstalled. This ensures that calling end/begin in quick succession will preserve
the overlay.

(WebKit::WebFoundTextRangeController::didEndTextSearchOperation):

Do not null out the page overlay immediately when uninstalling. Nulling out
the member is handled in `willMoveToPage`, which is called after the animation
is finished.

* Tools/TestWebKitAPI/Tests/WebKitCocoa/FindInPage.mm:
(traverseLayerTree):
(overlayCount):
(TestWebKitAPI::TEST):

Added an API test to ensure at most one find overlay is in the layer tree at
any time.

Canonical link: https://commits.webkit.org/251193@main

Modified Paths

Diff

Modified: trunk/Source/WebKit/WebProcess/WebPage/WebFoundTextRangeController.cpp (295097 => 295098)


--- trunk/Source/WebKit/WebProcess/WebPage/WebFoundTextRangeController.cpp	2022-06-01 17:50:03 UTC (rev 295097)
+++ trunk/Source/WebKit/WebProcess/WebPage/WebFoundTextRangeController.cpp	2022-06-01 18:32:53 UTC (rev 295098)
@@ -177,7 +177,9 @@
 
 void WebFoundTextRangeController::didBeginTextSearchOperation()
 {
-    if (!m_findPageOverlay) {
+    if (m_findPageOverlay)
+        m_findPageOverlay->stopFadeOutAnimation();
+    else {
         m_findPageOverlay = WebCore::PageOverlay::create(*this, WebCore::PageOverlay::OverlayType::Document);
         m_webPage->corePage()->pageOverlayController().installPageOverlay(*m_findPageOverlay, WebCore::PageOverlay::FadeMode::Fade);
     }
@@ -189,8 +191,6 @@
 {
     if (m_findPageOverlay)
         m_webPage->corePage()->pageOverlayController().uninstallPageOverlay(*m_findPageOverlay, WebCore::PageOverlay::FadeMode::Fade);
-
-    m_findPageOverlay = nullptr;
 }
 
 void WebFoundTextRangeController::requestRectForFoundTextRange(const WebFoundTextRange& range, CompletionHandler<void(WebCore::FloatRect)>&& completionHandler)

Modified: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/FindInPage.mm (295097 => 295098)


--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/FindInPage.mm	2022-06-01 17:50:03 UTC (rev 295097)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/FindInPage.mm	2022-06-01 18:32:53 UTC (rev 295098)
@@ -421,6 +421,23 @@
 
 @end
 
+static void traverseLayerTree(CALayer *layer, void(^block)(CALayer *))
+{
+    for (CALayer *child in layer.sublayers)
+        traverseLayerTree(child, block);
+    block(layer);
+}
+
+static size_t overlayCount(WKWebView *webView)
+{
+    __block size_t count = 0;
+    traverseLayerTree([webView layer], ^(CALayer *layer) {
+        if ([layer.name containsString:@"Overlay content"])
+            count++;
+    });
+    return count;
+}
+
 static void testPerformTextSearchWithQueryStringInWebView(WKWebView *webView, NSString *query, TestTextSearchOptions *searchOptions, NSUInteger expectedMatches)
 {
     __block bool finishedSearching = false;
@@ -645,4 +662,32 @@
     TestWebKitAPI::Util::run(&scrollViewDelegate->_finishedScrolling);
 }
 
+TEST(WebKit, CannotHaveMultipleFindOverlays)
+{
+    auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 200, 200)]);
+
+    NSURLRequest *request = [NSURLRequest requestWithURL:[[NSBundle mainBundle] URLForResource:@"lots-of-text" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]];
+    [webView loadRequest:request];
+    [webView _test_waitForDidFinishNavigation];
+
+    EXPECT_EQ(overlayCount(webView.get()), 0U);
+
+    [webView didBeginTextSearchOperation];
+
+    // Wait for two presentation updates, as the document overlay root layer is
+    // created lazily.
+    [webView waitForNextPresentationUpdate];
+    [webView waitForNextPresentationUpdate];
+
+    EXPECT_EQ(overlayCount(webView.get()), 1U);
+
+    [webView didEndTextSearchOperation];
+    [webView didBeginTextSearchOperation];
+
+    [webView waitForNextPresentationUpdate];
+    [webView waitForNextPresentationUpdate];
+
+    EXPECT_EQ(overlayCount(webView.get()), 1U);
+}
+
 #endif // HAVE(UIFINDINTERACTION)
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to