Title: [295105] trunk
Revision
295105
Author
wenson_hs...@apple.com
Date
2022-06-01 14:42:09 -0700 (Wed, 01 Jun 2022)

Log Message

[macOS] Only allow the active, visible tab to trigger `-_focusWebView:`
https://bugs.webkit.org/show_bug.cgi?id=241108
rdar://93973632

Reviewed by Chris Dumez.

To address <https://webkit.org/b/233686>, Safari removed their implementation of the UI delegate
method `-_focusWebView:`, which is invoked when a webpage uses `window.open()` with a target, and
which Safari previously handled by making the web view the active tab. However, this breaks a valid
use case in which a webpage uses `window.open()` to open itself in a new tab, and later use it again
to return to the original tab. To address this, we'll restore Safari's implementation of the
`WKWebView` focus delegate method, but will change WebKit to only allow this method call to bubble
up into the client layer in the case where the page that's calling `window.open()` is already active
and visible.

* Source/WebCore/loader/FrameLoader.cpp:
(WebCore::isInVisibleAndActivePage):
(WebCore::FrameLoader::loadFrameRequest):
(WebCore::createWindow):
* Source/WebCore/page/DOMWindow.cpp:
(WebCore::DOMWindow::focus):

Check that the opener (or source) frame that's triggering the call to `open()` is in a page that's
visible and active.

* Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
* Tools/TestWebKitAPI/Tests/mac/FocusWebView.mm: Added.
(TestWebKitAPI::TEST):

Add an API test to verify that `-_focusWebView:` is not called when opening a window once the web
page containing the frame that's calling `window.open()` is unparented from its window.

* Tools/TestWebKitAPI/Tests/mac/open-in-new-tab.html: Added.
* Tools/TestWebKitAPI/cocoa/TestUIDelegate.h:
* Tools/TestWebKitAPI/cocoa/TestUIDelegate.mm:
(-[TestUIDelegate _focusWebView:]):

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

Modified Paths

Added Paths

Diff

Modified: trunk/Source/WebCore/loader/FrameLoader.cpp (295104 => 295105)


--- trunk/Source/WebCore/loader/FrameLoader.cpp	2022-06-01 20:36:56 UTC (rev 295104)
+++ trunk/Source/WebCore/loader/FrameLoader.cpp	2022-06-01 21:42:09 UTC (rev 295105)
@@ -214,6 +214,12 @@
     return frame.document() && frame.document()->isSandboxed(mask);
 }
 
+static bool isInVisibleAndActivePage(const Frame& frame)
+{
+    auto* page = frame.page();
+    return page && page->isVisibleAndActive();
+}
+
 class PageLevelForbidScope {
 protected:
     explicit PageLevelForbidScope(Page* page)
@@ -1277,7 +1283,7 @@
             sourceFrame = &m_frame;
         Frame* targetFrame = sourceFrame->loader().findFrameForNavigation(frameName);
         if (targetFrame && targetFrame != sourceFrame) {
-            if (Page* page = targetFrame->page())
+            if (auto* page = targetFrame->page(); page && isInVisibleAndActivePage(*sourceFrame))
                 page->chrome().focus();
         }
     };
@@ -4127,7 +4133,7 @@
     if (!request.frameName().isEmpty() && !isBlankTargetFrameName(request.frameName())) {
         if (RefPtr<Frame> frame = lookupFrame.loader().findFrameForNavigation(request.frameName(), openerFrame.document())) {
             if (!isSelfTargetFrameName(request.frameName())) {
-                if (Page* page = frame->page())
+                if (auto* page = frame->page(); page && isInVisibleAndActivePage(openerFrame))
                     page->chrome().focus();
             }
             return frame;

Modified: trunk/Source/WebCore/page/DOMWindow.cpp (295104 => 295105)


--- trunk/Source/WebCore/page/DOMWindow.cpp	2022-06-01 20:36:56 UTC (rev 295104)
+++ trunk/Source/WebCore/page/DOMWindow.cpp	2022-06-01 21:42:09 UTC (rev 295105)
@@ -998,7 +998,13 @@
 {
     RefPtr frame = this->frame();
     RefPtr openerFrame = frame ? frame->loader().opener() : nullptr;
-    focus(openerFrame && openerFrame != frame && incumbentWindow.frame() == openerFrame);
+    focus([&] {
+        if (!openerFrame || openerFrame == frame || incumbentWindow.frame() != openerFrame)
+            return false;
+
+        auto* page = openerFrame->page();
+        return page && page->isVisibleAndActive();
+    }());
 }
 
 void DOMWindow::focus(bool allowFocus)

Modified: trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj (295104 => 295105)


--- trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj	2022-06-01 20:36:56 UTC (rev 295104)
+++ trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj	2022-06-01 21:42:09 UTC (rev 295105)
@@ -1111,6 +1111,8 @@
 		F491DBAE281DE0E80081705F /* image-controls.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F491DBAD281DE0980081705F /* image-controls.html */; };
 		F494B36A263120780060A310 /* TextServicesTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = F494B369263120780060A310 /* TextServicesTests.mm */; };
 		F49992C6248DABFD00034167 /* overflow-hidden.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F49992C5248DABE400034167 /* overflow-hidden.html */; };
+		F4A2E64D284541BA0001FEEF /* FocusWebView.mm in Sources */ = {isa = PBXBuildFile; fileRef = F4A2E64C284541BA0001FEEF /* FocusWebView.mm */; };
+		F4A2E64F28455D3A0001FEEF /* open-in-new-tab.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F4A2E64E28455D230001FEEF /* open-in-new-tab.html */; };
 		F4A32EC41F05F3850047C544 /* dragstart-change-selection-offscreen.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F4A32EC31F05F3780047C544 /* dragstart-change-selection-offscreen.html */; };
 		F4A32ECB1F0643370047C544 /* contenteditable-in-iframe.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F4A32ECA1F0642F40047C544 /* contenteditable-in-iframe.html */; };
 		F4A7CE782662D6E800228685 /* TouchEventTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = F4A7CE772662D6E800228685 /* TouchEventTests.mm */; };
@@ -1239,7 +1241,6 @@
 			dstPath = TestWebKitAPI.resources;
 			dstSubfolderSpec = 7;
 			files = (
-				49C64FD728349C38005BF0C2 /* test.pages in Copy Resources */,
 				55A817FF2181021A0004A39A /* 100x100-red.tga in Copy Resources */,
 				1A9E52C913E65EF4006917F5 /* 18-characters.html in Copy Resources */,
 				55A81800218102210004A39A /* 400x400-green.png in Copy Resources */,
@@ -1551,6 +1552,7 @@
 				074994421EA5034B000DA44F /* ondevicechange.html in Copy Resources */,
 				1DAA52CC243BE805001A3159 /* one-video.html in Copy Resources */,
 				CEA6CF2819CCF69D0064F5A7 /* open-and-close-window.html in Copy Resources */,
+				F4A2E64F28455D3A0001FEEF /* open-in-new-tab.html in Copy Resources */,
 				7CCB99231D3B4A46003922F6 /* open-multiple-external-url.html in Copy Resources */,
 				468BC45522653A1000A36C96 /* open-window-then-write-to-it.html in Copy Resources */,
 				41848F4424891879000E2588 /* open-window-with-file-url-with-host.html in Copy Resources */,
@@ -1622,6 +1624,7 @@
 				C95984F71E36BCEF002C0D45 /* test-without-audio-track.mp4 in Copy Resources */,
 				F46D43AB26D7092800969E5E /* test.jpg in Copy Resources */,
 				524BBCA119E30C77002F1AF1 /* test.mp4 in Copy Resources */,
+				49C64FD728349C38005BF0C2 /* test.pages in Copy Resources */,
 				7AE9E5091AE5AE8B00CF874B /* test.pdf in Copy Resources */,
 				5C7101C725DD98B600686200 /* test_print.pdf in Copy Resources */,
 				F45EB60427739F34003571AE /* TestModalContainerControls.mlmodelc in Copy Resources */,
@@ -3162,6 +3165,8 @@
 		F493247C1F44DF8D006F4336 /* UIKitSPI.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = UIKitSPI.h; sourceTree = "<group>"; };
 		F494B369263120780060A310 /* TextServicesTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = TextServicesTests.mm; sourceTree = "<group>"; };
 		F49992C5248DABE400034167 /* overflow-hidden.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "overflow-hidden.html"; sourceTree = "<group>"; };
+		F4A2E64C284541BA0001FEEF /* FocusWebView.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = FocusWebView.mm; sourceTree = "<group>"; };
+		F4A2E64E28455D230001FEEF /* open-in-new-tab.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "open-in-new-tab.html"; sourceTree = "<group>"; };
 		F4A32EC31F05F3780047C544 /* dragstart-change-selection-offscreen.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = "dragstart-change-selection-offscreen.html"; sourceTree = "<group>"; };
 		F4A32ECA1F0642F40047C544 /* contenteditable-in-iframe.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = "contenteditable-in-iframe.html"; sourceTree = "<group>"; };
 		F4A7CE772662D6E800228685 /* TouchEventTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = TouchEventTests.mm; sourceTree = "<group>"; };
@@ -4324,7 +4329,6 @@
 				CEBCA1351E3A803400C73293 /* page-with-csp.html */,
 				CEBCA1361E3A803400C73293 /* page-without-csp-iframe.html */,
 				CEBCA1371E3A803400C73293 /* page-without-csp.html */,
-				49C64FD628349C19005BF0C2 /* test.pages */,
 				F4B86D4E20BCD5970099A7E6 /* paint-significant-area-milestone.html */,
 				A1409AD81E7254AC004949D9 /* password-protected.pages */,
 				9BD6D3A61F7B21CC00BD4962 /* paste-image.html */,
@@ -4359,6 +4363,7 @@
 				31B76E4423299BA3007FED2C /* system-preview-trigger.html */,
 				313C3A0121E5677A00DBA86E /* SystemPreviewBlobNaming.html */,
 				F46D43AA26D7090300969E5E /* test.jpg */,
+				49C64FD628349C19005BF0C2 /* test.pages */,
 				F45EB60327739F2B003571AE /* TestModalContainerControls.mlmodelc */,
 				2E9896141D8F092B00739892 /* text-and-password-inputs.html */,
 				F4CD74C520FDACF500DE3794 /* text-with-async-script.html */,
@@ -4652,6 +4657,7 @@
 				E3C21A7821B25C82003B31A3 /* cocoa */,
 				7CBBA07519BB8A0900BBF025 /* darwin */,
 				BC029B1A1486B23800817DA9 /* ns */,
+				FF25942A2834B7A7006892D6 /* AlignedRefLogger.h */,
 				26F1B44215CA434F00D1E4BF /* AtomString.cpp */,
 				FE2D9473245EB2DF00E48135 /* Bitmap.cpp */,
 				E40019301ACE9B5C001B0A2A /* BloomFilter.cpp */,
@@ -4669,7 +4675,6 @@
 				278DE64B22B8D611004E0E7A /* CrossThreadCopier.cpp */,
 				51714EB91D087416004723C4 /* CrossThreadTask.cpp */,
 				26A2C72E15E2E73C005B1A14 /* CString.cpp */,
-				FF25942A2834B7A7006892D6 /* AlignedRefLogger.h */,
 				7AA021BA1AB09EA70052953F /* DateMath.cpp */,
 				1A3524A91D627BD40031729B /* DeletedAddressOfOperator.h */,
 				E4A757D3178AEA5B00B5D7A4 /* Deque.cpp */,
@@ -4967,6 +4972,7 @@
 				4BB4160316815F9100824238 /* ElementAtPointInWebFrame.mm */,
 				9B79164F1BD89D0D00D50B8F /* FirstResponderScrollingPosition.mm */,
 				C9E6DD311EA972D800DD78AA /* FirstResponderSuppression.mm */,
+				F4A2E64C284541BA0001FEEF /* FocusWebView.mm */,
 				F456AB1B213EDBA300CB2CEF /* FontManagerTests.mm */,
 				1A7E8B33181208DE00AEB74A /* FragmentNavigation.mm */,
 				CDB213BC24EF522800FDE301 /* FullscreenFocus.mm */,
@@ -5058,6 +5064,7 @@
 				CDA315991ED540A5009F60D3 /* MediaPlaybackSleepAssertion.html */,
 				E1220DC9155B287D0013E2FC /* MemoryCacheDisableWithinResourceLoadDelegate.html */,
 				517E7E031511187500D0B008 /* MemoryCachePruneWithinResourceLoadDelegate.html */,
+				F4A2E64E28455D230001FEEF /* open-in-new-tab.html */,
 				290A9BB81735F42300D71BBC /* OpenNewWindow.html */,
 				A57A34F116AF69E200C2501F /* PageVisibilityStateWithWindowChanges.html */,
 				52B8CF9415868CF000281053 /* SetDocumentURI.html */,
@@ -5703,6 +5710,7 @@
 				7A909A7F1D877480007E10F8 /* FloatRectTests.cpp in Sources */,
 				7A909A801D877480007E10F8 /* FloatSizeTests.cpp in Sources */,
 				F4BC0B142146C849002A0478 /* FocusPreservationTests.mm in Sources */,
+				F4A2E64D284541BA0001FEEF /* FocusWebView.mm in Sources */,
 				F456AB1C213EDBA300CB2CEF /* FontManagerTests.mm in Sources */,
 				1C81802725FB09E200608B3E /* FontRegistrySandboxCheck.mm in Sources */,
 				95C52729275F35E100DA7E40 /* FontShadowTests.cpp in Sources */,

Added: trunk/Tools/TestWebKitAPI/Tests/mac/FocusWebView.mm (0 => 295105)


--- trunk/Tools/TestWebKitAPI/Tests/mac/FocusWebView.mm	                        (rev 0)
+++ trunk/Tools/TestWebKitAPI/Tests/mac/FocusWebView.mm	2022-06-01 21:42:09 UTC (rev 295105)
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2022 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import "config.h"
+
+#if PLATFORM(MAC)
+
+#import "PlatformUtilities.h"
+#import "TestNavigationDelegate.h"
+#import "TestProtocol.h"
+#import "TestUIDelegate.h"
+#import "TestWKWebView.h"
+#import "WKWebViewConfigurationExtras.h"
+#import <QuartzCore/QuartzCore.h>
+#import <wtf/RetainPtr.h>
+
+namespace TestWebKitAPI {
+
+TEST(FocusWebView, DoNotFocusWebViewWhenUnparented)
+{
+    auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
+    auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 400, 400) configuration:configuration]);
+    [webView synchronouslyLoadTestPageNamed:@"open-in-new-tab"];
+
+    auto uiDelegate = adoptNS([TestUIDelegate new]);
+    [webView setUIDelegate:uiDelegate.get()];
+
+    __block bool calledFocusWebView = false;
+    [uiDelegate setFocusWebView:^(WKWebView *viewToFocus) {
+        EXPECT_EQ(viewToFocus, webView.get());
+        calledFocusWebView = true;
+    }];
+
+    [webView objectByEvaluatingJavaScript:@"openNewTab()"];
+    EXPECT_TRUE(calledFocusWebView);
+
+    [webView removeFromSuperview];
+    [CATransaction flush];
+    __block bool doneUnparenting = false;
+    dispatch_async(dispatch_get_main_queue(), ^{
+        doneUnparenting = true;
+    });
+    Util::run(&doneUnparenting);
+
+    calledFocusWebView = false;
+    [webView objectByEvaluatingJavaScript:@"openNewTab()"];
+    EXPECT_FALSE(calledFocusWebView);
+}
+
+} // namespace TestWebKitAPI
+
+#endif // PLATFORM(MAC)

Added: trunk/Tools/TestWebKitAPI/Tests/mac/open-in-new-tab.html (0 => 295105)


--- trunk/Tools/TestWebKitAPI/Tests/mac/open-in-new-tab.html	                        (rev 0)
+++ trunk/Tools/TestWebKitAPI/Tests/mac/open-in-new-tab.html	2022-06-01 21:42:09 UTC (rev 295105)
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+<body>
+<iframe name="subframe"></iframe>
+<script>
+function openNewTab()
+{
+    let callOpen = () => open("https://webkit.org", "subframe");
+    if (window.internals)
+        internals.withUserGesture(callOpen);
+    else
+        callOpen();
+}
+</script>
+</body>
+</html>

Modified: trunk/Tools/TestWebKitAPI/cocoa/TestUIDelegate.h (295104 => 295105)


--- trunk/Tools/TestWebKitAPI/cocoa/TestUIDelegate.h	2022-06-01 20:36:56 UTC (rev 295104)
+++ trunk/Tools/TestWebKitAPI/cocoa/TestUIDelegate.h	2022-06-01 21:42:09 UTC (rev 295105)
@@ -33,6 +33,7 @@
 @property (nonatomic, copy) void (^getContextMenuFromProposedMenu)(NSMenu *, _WKContextMenuElementInfo *, id <NSSecureCoding>, void (^)(NSMenu *));
 #endif
 @property (nonatomic, copy) void (^saveDataToFile)(WKWebView *, NSData *, NSString *, NSString *, NSURL *);
+@property (nonatomic, copy) void (^focusWebView)(WKWebView *);
 
 - (NSString *)waitForAlert;
 

Modified: trunk/Tools/TestWebKitAPI/cocoa/TestUIDelegate.mm (295104 => 295105)


--- trunk/Tools/TestWebKitAPI/cocoa/TestUIDelegate.mm	2022-06-01 20:36:56 UTC (rev 295104)
+++ trunk/Tools/TestWebKitAPI/cocoa/TestUIDelegate.mm	2022-06-01 21:42:09 UTC (rev 295105)
@@ -57,6 +57,12 @@
     else
         completionHandler(menu);
 }
+
+- (void)_focusWebView:(WKWebView *)webView
+{
+    if (_focusWebView)
+        _focusWebView(webView);
+}
 #endif // PLATFORM(MAC)
 
 - (void)_webView:(WKWebView *)webView saveDataToFile:(NSData *)data suggestedFilename:(NSString *)suggestedFilename mimeType:(NSString *)mimeType originatingURL:(NSURL *)url
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to