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