[WK2] Add runBeforeUnloadConfirmPanel WKUIDelegate SPI; support onbeforeunload confir...
authordbates@webkit.org <dbates@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 30 May 2017 21:01:59 +0000 (21:01 +0000)
committerdbates@webkit.org <dbates@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 30 May 2017 21:01:59 +0000 (21:01 +0000)
https://bugs.webkit.org/show_bug.cgi?id=172603
<rdar://problem/32471306>

Reviewed by Brady Eidson.

Source/WebKit2:

A page loaded in MiniBrowser using WebKit2 cannot show a beforeunload confirm panel (by registering
an onbeforeunload event handler) when it is unloaded. The same page loaded in MiniBrowser using
WebKit1 can show such a confirm panel. We need to add WKUIDelegate SPI so that an embedding client,
such as MiniBrowser, can register to receive a callback to show a beforeunload confirm panel.

* UIProcess/API/APIUIClient.h:
(API::UIClient::runBeforeUnloadConfirmPanel): Modified to take a SecurityOriginData object. This
makes the API consistent with the existing JavaScript dialog callbacks.
* UIProcess/API/C/WKPage.cpp:
(WKPageSetPageUIClient):
* UIProcess/API/Cocoa/WKUIDelegatePrivate.h: Add SPI -_webView:runBeforeUnloadConfirmPanelWithMessage:initiatedByFrame:completionHandler:.
* UIProcess/API/Cocoa/WKWebView.mm:
(-[WKWebView setUIDelegate:]): Set the delegate of WebKit::UIDelegate to the specified WKUIDelegate
before we set the UI client on the page so as to ensure that API::UIClient callbacks that depend
-respondsToSelector: checks (e.g. API::UIClient::canRunBeforeUnloadConfirmPanel()) return the correct
result. To elaborate further, a API::UIClient client must override both canRunBeforeUnloadConfirmPanel()
and runBeforeUnloadConfirmPanel() to support running a beforeunload confirm dialog. When mapping
the Cocoa SPI, WKUIDelegatePrivate, to API::UIClient we implement API::UIClient::canRunBeforeUnloadConfirmPanel()
in terms of whether the Cocoa delegate responds at runtime to the selector -_webView:runBeforeUnloadConfirmPanelWithMessage:initiatedByFrame:completionHandler:.
We need to do such runtime checks before we pass the API::UIClient to the page. Otherwise, querying
API::UIClient::canRunBeforeUnloadConfirmPanel() will return the wrong result.
* UIProcess/API/gtk/WebKitUIClient.cpp: Modified runBeforeUnloadConfirmPanel() to take a SecurityOriginData object.
* UIProcess/Cocoa/UIDelegate.h: Add declarations for API::UIClient overrides: canRunBeforeUnloadConfirmPanel()
and runBeforeUnloadConfirmPanel(). Add a bit to m_delegateMethods as to whether the Cocoa delegate
responds to selector -_webView:runBeforeUnloadConfirmPanelWithMessage:initiatedByFrame:completionHandler:.
* UIProcess/Cocoa/UIDelegate.mm:
(WebKit::UIDelegate::setDelegate): Set the above m_delegateMethods bit if the Cocoa delegate responds
to selector -_webView:runBeforeUnloadConfirmPanelWithMessage:initiatedByFrame:completionHandler:.
(WebKit::UIDelegate::UIClient::canRunBeforeUnloadConfirmPanel): Return whether the above m_delegateMethods
bit was set.
(WebKit::UIDelegate::UIClient::runBeforeUnloadConfirmPanel): Turn around and call -_webView:runBeforeUnloadConfirmPanelWithMessage:initiatedByFrame:completionHandler: (if applicable).
* UIProcess/WebPageProxy.cpp:
(WebKit::WebPageProxy::runBeforeUnloadConfirmPanel): Modified to take a SecurityOriginData object
and pass it to API::UIClient::runBeforeUnloadConfirmPanel().
* UIProcess/WebPageProxy.h:
* UIProcess/WebPageProxy.messages.in: Add SecurityOriginData argument to message RunBeforeUnloadConfirmPanel.
Also pass the message for the panel as the last argument so as to make the order of arguments to message
RunBeforeUnloadConfirmPanel more closely match the order of arguments passed to other JavaScript dialog
messages (e.g. RunJavaScriptAlert) for consistency.
* WebProcess/WebCoreSupport/WebChromeClient.cpp:
(WebKit::WebChromeClient::runBeforeUnloadConfirmPanel): Include the SecurityOriginData object for the
frame in message RunBeforeUnloadConfirmPanel.

Tools:

Implement the -_webView:runBeforeUnloadConfirmPanelWithMessage:initiatedByFrame:completionHandler: delegate
method in MiniBrowser to show a confirm panel as to whether to allow the unloading of the page when
unloading is initiated for a page that registered a onbeforeunload handler.

Modify TestWebKitAPI/Tests/WebKit2Cocoa/ModalAlerts.mm to test that the -_webView:runBeforeUnloadConfirmPanelWithMessage:initiatedByFrame:completionHandler:
is called. Also fix style nit; pass YES instead of true to avoid implicit conversion from bool to BOOL
when invoking the completion handler in -_webView:runJavaScriptAlertPanelWithMessage:initiatedByFrame:completionHandler:.

Until we fix <https://bugs.webkit.org/show_bug.cgi?id=172614> the unit test in TestWebKitAPI/Tests/WebKit2Cocoa/ModalAlerts.mm
for -_webView:runBeforeUnloadConfirmPanelWithMessage:initiatedByFrame:completionHandler: is only run on Mac
as we do not have the infrastructure to simulate a click/tap on iOS and a click/tap on the page that
registered an onbeforeunload handler is required to show a confirm panel when the page will be unloaded.

* MiniBrowser/mac/WK2BrowserWindowController.m:
(-[WK2BrowserWindowController _webView:runBeforeUnloadConfirmPanelWithMessage:initiatedByFrame:completionHandler:]):
* TestWebKitAPI/Tests/WebKit2/modal-alerts-in-new-about-blank-window.html:
* TestWebKitAPI/Tests/WebKit2Cocoa/ModalAlerts.mm:
(sawDialog):
(-[ModalAlertsUIDelegate webView:createWebViewWithConfiguration:forNavigationAction:windowFeatures:]):
(-[ModalAlertsUIDelegate webView:runJavaScriptConfirmPanelWithMessage:initiatedByFrame:completionHandler:]):
(-[ModalAlertsUIDelegate _webView:runBeforeUnloadConfirmPanelWithMessage:initiatedByFrame:completionHandler:]):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@217571 268f45cc-cd09-0410-ab3c-d52691b4dbfc

16 files changed:
Source/WebKit2/ChangeLog
Source/WebKit2/UIProcess/API/APIUIClient.h
Source/WebKit2/UIProcess/API/C/WKPage.cpp
Source/WebKit2/UIProcess/API/Cocoa/WKUIDelegatePrivate.h
Source/WebKit2/UIProcess/API/Cocoa/WKWebView.mm
Source/WebKit2/UIProcess/API/gtk/WebKitUIClient.cpp
Source/WebKit2/UIProcess/Cocoa/UIDelegate.h
Source/WebKit2/UIProcess/Cocoa/UIDelegate.mm
Source/WebKit2/UIProcess/WebPageProxy.cpp
Source/WebKit2/UIProcess/WebPageProxy.h
Source/WebKit2/UIProcess/WebPageProxy.messages.in
Source/WebKit2/WebProcess/WebCoreSupport/WebChromeClient.cpp
Tools/ChangeLog
Tools/MiniBrowser/mac/WK2BrowserWindowController.m
Tools/TestWebKitAPI/Tests/WebKit2/modal-alerts-in-new-about-blank-window.html
Tools/TestWebKitAPI/Tests/WebKit2Cocoa/ModalAlerts.mm

index 332ddb7..c35a0a2 100644 (file)
@@ -1,3 +1,54 @@
+2017-05-30  Daniel Bates  <dabates@apple.com>
+
+        [WK2] Add runBeforeUnloadConfirmPanel WKUIDelegate SPI; support onbeforeunload confirm panel in MiniBrowser
+        https://bugs.webkit.org/show_bug.cgi?id=172603
+        <rdar://problem/32471306>
+
+        Reviewed by Brady Eidson.
+
+        A page loaded in MiniBrowser using WebKit2 cannot show a beforeunload confirm panel (by registering
+        an onbeforeunload event handler) when it is unloaded. The same page loaded in MiniBrowser using
+        WebKit1 can show such a confirm panel. We need to add WKUIDelegate SPI so that an embedding client,
+        such as MiniBrowser, can register to receive a callback to show a beforeunload confirm panel.
+
+        * UIProcess/API/APIUIClient.h:
+        (API::UIClient::runBeforeUnloadConfirmPanel): Modified to take a SecurityOriginData object. This
+        makes the API consistent with the existing JavaScript dialog callbacks.
+        * UIProcess/API/C/WKPage.cpp:
+        (WKPageSetPageUIClient):
+        * UIProcess/API/Cocoa/WKUIDelegatePrivate.h: Add SPI -_webView:runBeforeUnloadConfirmPanelWithMessage:initiatedByFrame:completionHandler:.
+        * UIProcess/API/Cocoa/WKWebView.mm:
+        (-[WKWebView setUIDelegate:]): Set the delegate of WebKit::UIDelegate to the specified WKUIDelegate
+        before we set the UI client on the page so as to ensure that API::UIClient callbacks that depend
+        -respondsToSelector: checks (e.g. API::UIClient::canRunBeforeUnloadConfirmPanel()) return the correct
+        result. To elaborate further, a API::UIClient client must override both canRunBeforeUnloadConfirmPanel()
+        and runBeforeUnloadConfirmPanel() to support running a beforeunload confirm dialog. When mapping
+        the Cocoa SPI, WKUIDelegatePrivate, to API::UIClient we implement API::UIClient::canRunBeforeUnloadConfirmPanel()
+        in terms of whether the Cocoa delegate responds at runtime to the selector -_webView:runBeforeUnloadConfirmPanelWithMessage:initiatedByFrame:completionHandler:.
+        We need to do such runtime checks before we pass the API::UIClient to the page. Otherwise, querying
+        API::UIClient::canRunBeforeUnloadConfirmPanel() will return the wrong result.
+        * UIProcess/API/gtk/WebKitUIClient.cpp: Modified runBeforeUnloadConfirmPanel() to take a SecurityOriginData object.
+        * UIProcess/Cocoa/UIDelegate.h: Add declarations for API::UIClient overrides: canRunBeforeUnloadConfirmPanel()
+        and runBeforeUnloadConfirmPanel(). Add a bit to m_delegateMethods as to whether the Cocoa delegate
+        responds to selector -_webView:runBeforeUnloadConfirmPanelWithMessage:initiatedByFrame:completionHandler:.
+        * UIProcess/Cocoa/UIDelegate.mm:
+        (WebKit::UIDelegate::setDelegate): Set the above m_delegateMethods bit if the Cocoa delegate responds
+        to selector -_webView:runBeforeUnloadConfirmPanelWithMessage:initiatedByFrame:completionHandler:.
+        (WebKit::UIDelegate::UIClient::canRunBeforeUnloadConfirmPanel): Return whether the above m_delegateMethods
+        bit was set.
+        (WebKit::UIDelegate::UIClient::runBeforeUnloadConfirmPanel): Turn around and call -_webView:runBeforeUnloadConfirmPanelWithMessage:initiatedByFrame:completionHandler: (if applicable).
+        * UIProcess/WebPageProxy.cpp:
+        (WebKit::WebPageProxy::runBeforeUnloadConfirmPanel): Modified to take a SecurityOriginData object
+        and pass it to API::UIClient::runBeforeUnloadConfirmPanel().
+        * UIProcess/WebPageProxy.h:
+        * UIProcess/WebPageProxy.messages.in: Add SecurityOriginData argument to message RunBeforeUnloadConfirmPanel.
+        Also pass the message for the panel as the last argument so as to make the order of arguments to message
+        RunBeforeUnloadConfirmPanel more closely match the order of arguments passed to other JavaScript dialog
+        messages (e.g. RunJavaScriptAlert) for consistency.
+        * WebProcess/WebCoreSupport/WebChromeClient.cpp:
+        (WebKit::WebChromeClient::runBeforeUnloadConfirmPanel): Include the SecurityOriginData object for the
+        frame in message RunBeforeUnloadConfirmPanel.
+
 2017-05-30  Alex Christensen  <achristensen@webkit.org>
 
         Update libwebrtc configuration
index 0a2709a..a55cf59 100644 (file)
@@ -115,7 +115,7 @@ public:
     virtual WebCore::FloatRect windowFrame(WebKit::WebPageProxy*) { return WebCore::FloatRect(); }
 
     virtual bool canRunBeforeUnloadConfirmPanel() const { return false; }
-    virtual void runBeforeUnloadConfirmPanel(WebKit::WebPageProxy*, const WTF::String&, WebKit::WebFrameProxy*, Function<void (bool)>&& completionHandler) { completionHandler(true); }
+    virtual void runBeforeUnloadConfirmPanel(WebKit::WebPageProxy*, const WTF::String&, WebKit::WebFrameProxy*, const WebCore::SecurityOriginData&, Function<void (bool)>&& completionHandler) { completionHandler(true); }
 
     virtual void pageDidScroll(WebKit::WebPageProxy*) { }
 
index c576e6a..3332f23 100644 (file)
@@ -2060,7 +2060,7 @@ void WKPageSetPageUIClient(WKPageRef pageRef, const WKPageUIClientBase* wkClient
             return m_client.runBeforeUnloadConfirmPanel_deprecatedForUseWithV6 || m_client.runBeforeUnloadConfirmPanel;
         }
 
-        void runBeforeUnloadConfirmPanel(WebKit::WebPageProxy* page, const WTF::String& message, WebKit::WebFrameProxy* frame, Function<void (bool)>&& completionHandler) override
+        void runBeforeUnloadConfirmPanel(WebKit::WebPageProxy* page, const WTF::String& message, WebKit::WebFrameProxy* frame, const SecurityOriginData&, Function<void (bool)>&& completionHandler) override
         {
             if (m_client.runBeforeUnloadConfirmPanel) {
                 RefPtr<RunBeforeUnloadConfirmPanelResultListener> listener = RunBeforeUnloadConfirmPanelResultListener::create(WTFMove(completionHandler));
index 2c2d626..1b2e73b 100644 (file)
@@ -70,6 +70,8 @@ struct UIEdgeInsets;
 - (WKDragDestinationAction)_webView:(WKWebView *)webView dragDestinationActionMaskForDraggingInfo:(id)draggingInfo WK_API_AVAILABLE(macosx(WK_MAC_TBA), ios(WK_IOS_TBA));
 - (void)_webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures completionHandler:(void (^)(WKWebView *webView))completionHandler WK_API_AVAILABLE(macosx(WK_MAC_TBA), ios(WK_IOS_TBA));
 
+- (void)_webView:(WKWebView *)webView runBeforeUnloadConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL result))completionHandler WK_API_AVAILABLE(macosx(WK_MAC_TBA), ios(WK_IOS_TBA));
+
 #if TARGET_OS_IPHONE
 - (BOOL)_webView:(WKWebView *)webView shouldIncludeAppLinkActionsForElement:(_WKActivatedElementInfo *)element WK_API_AVAILABLE(ios(9.0));
 - (NSArray *)_webView:(WKWebView *)webView actionsForElement:(_WKActivatedElementInfo *)element defaultActions:(NSArray<_WKElementAction *> *)defaultActions;
index fab32da..e0bedab 100644 (file)
@@ -707,11 +707,11 @@ static uint32_t convertSystemLayoutDirection(NSUserInterfaceLayoutDirection dire
 
 - (void)setUIDelegate:(id<WKUIDelegate>)UIDelegate
 {
+    _uiDelegate->setDelegate(UIDelegate);
 #if ENABLE(CONTEXT_MENUS)
     _page->setContextMenuClient(_uiDelegate->createContextMenuClient());
 #endif
     _page->setUIClient(_uiDelegate->createUIClient());
-    _uiDelegate->setDelegate(UIDelegate);
 }
 
 - (id <_WKIconLoadingDelegate>)_iconLoadingDelegate
index ec71d45..5f42c5c 100644 (file)
@@ -86,7 +86,7 @@ private:
 
     bool canRunBeforeUnloadConfirmPanel() const override { return true; }
 
-    void runBeforeUnloadConfirmPanel(WebPageProxy*, const String& message, WebFrameProxy*, Function<void (bool)>&& completionHandler) override
+    void runBeforeUnloadConfirmPanel(WebPageProxy*, const String& message, WebFrameProxy*, const WebCore::SecurityOriginData&, Function<void (bool)>&& completionHandler) override
     {
         completionHandler(webkitWebViewRunJavaScriptBeforeUnloadConfirm(m_webView, message.utf8()));
     }
index f3ef33a..30f90f5 100644 (file)
@@ -86,6 +86,8 @@ private:
         void runJavaScriptAlert(WebKit::WebPageProxy*, const WTF::String&, WebKit::WebFrameProxy*, const WebCore::SecurityOriginData&, Function<void ()>&& completionHandler) override;
         void runJavaScriptConfirm(WebKit::WebPageProxy*, const WTF::String&, WebKit::WebFrameProxy*, const WebCore::SecurityOriginData&, Function<void (bool)>&& completionHandler) override;
         void runJavaScriptPrompt(WebKit::WebPageProxy*, const WTF::String&, const WTF::String&, WebKit::WebFrameProxy*, const WebCore::SecurityOriginData&, Function<void (const WTF::String&)>&& completionHandler) override;
+        bool canRunBeforeUnloadConfirmPanel() const final;
+        void runBeforeUnloadConfirmPanel(WebKit::WebPageProxy*, const WTF::String&, WebKit::WebFrameProxy*, const WebCore::SecurityOriginData&, Function<void (bool)>&& completionHandler) final;
         void exceededDatabaseQuota(WebPageProxy*, WebFrameProxy*, API::SecurityOrigin*, const WTF::String& databaseName, const WTF::String& displayName, unsigned long long currentQuota, unsigned long long currentOriginUsage, unsigned long long currentUsage, unsigned long long expectedUsage, Function<void (unsigned long long)>&& completionHandler) override;
         void reachedApplicationCacheOriginQuota(WebPageProxy*, const WebCore::SecurityOrigin&, uint64_t currentQuota, uint64_t totalBytesNeeded, Function<void (unsigned long long)>&& completionHandler) override;
 #if PLATFORM(MAC)
@@ -127,6 +129,7 @@ private:
         bool webViewRunJavaScriptAlertPanelWithMessageInitiatedByFrameCompletionHandler : 1;
         bool webViewRunJavaScriptConfirmPanelWithMessageInitiatedByFrameCompletionHandler : 1;
         bool webViewRunJavaScriptTextInputPanelWithPromptDefaultTextInitiatedByFrameCompletionHandler : 1;
+        bool webViewRunBeforeUnloadConfirmPanelWithMessageInitiatedByFrameCompletionHandler : 1;
 #if PLATFORM(MAC)
         bool webViewRunOpenPanelWithParametersInitiatedByFrameCompletionHandler : 1;
 #endif
index 44830d1..c8ecab5 100644 (file)
@@ -96,6 +96,7 @@ void UIDelegate::setDelegate(id <WKUIDelegate> delegate)
     m_delegateMethods.webViewRunJavaScriptAlertPanelWithMessageInitiatedByFrameCompletionHandler = [delegate respondsToSelector:@selector(webView:runJavaScriptAlertPanelWithMessage:initiatedByFrame:completionHandler:)];
     m_delegateMethods.webViewRunJavaScriptConfirmPanelWithMessageInitiatedByFrameCompletionHandler = [delegate respondsToSelector:@selector(webView:runJavaScriptConfirmPanelWithMessage:initiatedByFrame:completionHandler:)];
     m_delegateMethods.webViewRunJavaScriptTextInputPanelWithPromptDefaultTextInitiatedByFrameCompletionHandler = [delegate respondsToSelector:@selector(webView:runJavaScriptTextInputPanelWithPrompt:defaultText:initiatedByFrame:completionHandler:)];
+    m_delegateMethods.webViewRunBeforeUnloadConfirmPanelWithMessageInitiatedByFrameCompletionHandler = [delegate respondsToSelector:@selector(_webView:runBeforeUnloadConfirmPanelWithMessage:initiatedByFrame:completionHandler:)];
 
 #if PLATFORM(MAC)
     m_delegateMethods.webViewRunOpenPanelWithParametersInitiatedByFrameCompletionHandler = [delegate respondsToSelector:@selector(webView:runOpenPanelWithParameters:initiatedByFrame:completionHandler:)];
@@ -313,6 +314,33 @@ void UIDelegate::UIClient::runJavaScriptPrompt(WebKit::WebPageProxy*, const WTF:
     }).get()];
 }
 
+bool UIDelegate::UIClient::canRunBeforeUnloadConfirmPanel() const
+{
+    return m_uiDelegate.m_delegateMethods.webViewRunBeforeUnloadConfirmPanelWithMessageInitiatedByFrameCompletionHandler;
+}
+
+void UIDelegate::UIClient::runBeforeUnloadConfirmPanel(WebKit::WebPageProxy*, const WTF::String& message, WebKit::WebFrameProxy* webFrameProxy, const WebCore::SecurityOriginData& securityOriginData, Function<void (bool)>&& completionHandler)
+{
+    if (!m_uiDelegate.m_delegateMethods.webViewRunBeforeUnloadConfirmPanelWithMessageInitiatedByFrameCompletionHandler) {
+        completionHandler(false);
+        return;
+    }
+
+    auto delegate = m_uiDelegate.m_delegate.get();
+    if (!delegate) {
+        completionHandler(false);
+        return;
+    }
+
+    RefPtr<CompletionHandlerCallChecker> checker = CompletionHandlerCallChecker::create(delegate.get(), @selector(_webView:runBeforeUnloadConfirmPanelWithMessage:initiatedByFrame:completionHandler:));
+    [(id <WKUIDelegatePrivate>)delegate _webView:m_uiDelegate.m_webView runBeforeUnloadConfirmPanelWithMessage:message initiatedByFrame:wrapper(API::FrameInfo::create(*webFrameProxy, securityOriginData.securityOrigin())) completionHandler:BlockPtr<void (BOOL)>::fromCallable([completionHandler = WTFMove(completionHandler), checker = WTFMove(checker)](BOOL result) {
+        if (checker->completionHandlerHasBeenCalled())
+            return;
+        completionHandler(result);
+        checker->didCallCompletionHandler();
+    }).get()];
+}
+
 void UIDelegate::UIClient::exceededDatabaseQuota(WebPageProxy*, WebFrameProxy*, API::SecurityOrigin* securityOrigin, const WTF::String& databaseName, const WTF::String& displayName, unsigned long long currentQuota, unsigned long long currentOriginUsage, unsigned long long currentUsage, unsigned long long expectedUsage, Function<void (unsigned long long)>&& completionHandler)
 {
     if (!m_uiDelegate.m_delegateMethods.webViewDecideDatabaseQuotaForSecurityOriginCurrentQuotaCurrentOriginUsageCurrentDatabaseUsageExpectedUsageDecisionHandler) {
index 9e17c5e..bd7864d 100644 (file)
@@ -4091,7 +4091,7 @@ void WebPageProxy::rootViewToAccessibilityScreen(const IntRect& viewRect, IntRec
 }
 #endif
 
-void WebPageProxy::runBeforeUnloadConfirmPanel(const String& message, uint64_t frameID, RefPtr<Messages::WebPageProxy::RunBeforeUnloadConfirmPanel::DelayedReply> reply)
+void WebPageProxy::runBeforeUnloadConfirmPanel(uint64_t frameID, const SecurityOriginData& securityOrigin, const String& message, RefPtr<Messages::WebPageProxy::RunBeforeUnloadConfirmPanel::DelayedReply> reply)
 {
     WebFrameProxy* frame = m_process->webFrame(frameID);
     MESSAGE_CHECK(frame);
@@ -4099,7 +4099,7 @@ void WebPageProxy::runBeforeUnloadConfirmPanel(const String& message, uint64_t f
     // Since runBeforeUnloadConfirmPanel() can spin a nested run loop we need to turn off the responsiveness timer.
     m_process->responsivenessTimer().stop();
 
-    m_uiClient->runBeforeUnloadConfirmPanel(this, message, frame, [reply](bool result) { reply->send(result); });
+    m_uiClient->runBeforeUnloadConfirmPanel(this, message, frame, securityOrigin, [reply](bool result) { reply->send(result); });
 }
 
 void WebPageProxy::didChangeViewportProperties(const ViewportAttributes& attr)
index a8ee3ae..823017f 100644 (file)
@@ -1297,7 +1297,7 @@ private:
     void accessibilityScreenToRootView(const WebCore::IntPoint& screenPoint, WebCore::IntPoint& windowPoint);
     void rootViewToAccessibilityScreen(const WebCore::IntRect& viewRect, WebCore::IntRect& result);
 #endif
-    void runBeforeUnloadConfirmPanel(const String& message, uint64_t frameID, RefPtr<Messages::WebPageProxy::RunBeforeUnloadConfirmPanel::DelayedReply>);
+    void runBeforeUnloadConfirmPanel(uint64_t frameID, const WebCore::SecurityOriginData&, const String& message, RefPtr<Messages::WebPageProxy::RunBeforeUnloadConfirmPanel::DelayedReply>);
     void didChangeViewportProperties(const WebCore::ViewportAttributes&);
     void pageDidScroll();
     void runOpenPanel(uint64_t frameID, const WebCore::SecurityOriginData&, const WebCore::FileChooserSettings&);
index 5ccc30f..7b9a0e2 100644 (file)
@@ -74,7 +74,7 @@ messages -> WebPageProxy {
     RootViewToAccessibilityScreen(WebCore::IntRect rect) -> (WebCore::IntRect screenFrame)
 #endif
 
-    RunBeforeUnloadConfirmPanel(String message, uint64_t frameID) -> (bool shouldClose) Delayed
+    RunBeforeUnloadConfirmPanel(uint64_t frameID, struct WebCore::SecurityOriginData frameSecurityOrigin, String message) -> (bool shouldClose) Delayed
     PageDidScroll()
     RunOpenPanel(uint64_t frameID, struct WebCore::SecurityOriginData frameSecurityOrigin, struct WebCore::FileChooserSettings parameters)
     PrintFrame(uint64_t frameID) -> ()
index dd0d4bc..1f5a94b 100644 (file)
@@ -367,7 +367,7 @@ bool WebChromeClient::runBeforeUnloadConfirmPanel(const String& message, Frame&
 
     HangDetectionDisabler hangDetectionDisabler;
 
-    if (!WebProcess::singleton().parentProcessConnection()->sendSync(Messages::WebPageProxy::RunBeforeUnloadConfirmPanel(message, webFrame->frameID()), Messages::WebPageProxy::RunBeforeUnloadConfirmPanel::Reply(shouldClose), m_page.pageID(), Seconds::infinity(), IPC::SendSyncOption::InformPlatformProcessWillSuspend))
+    if (!WebProcess::singleton().parentProcessConnection()->sendSync(Messages::WebPageProxy::RunBeforeUnloadConfirmPanel(webFrame->frameID(), SecurityOriginData::fromFrame(&frame), message), Messages::WebPageProxy::RunBeforeUnloadConfirmPanel::Reply(shouldClose), m_page.pageID(), Seconds::infinity(), IPC::SendSyncOption::InformPlatformProcessWillSuspend))
         return false;
 
     return shouldClose;
index e0159ac..68b9af5 100644 (file)
@@ -1,3 +1,33 @@
+2017-05-30  Daniel Bates  <dabates@apple.com>
+
+        [WK2] Add runBeforeUnloadConfirmPanel WKUIDelegate SPI; support onbeforeunload confirm panel in MiniBrowser
+        https://bugs.webkit.org/show_bug.cgi?id=172603
+        <rdar://problem/32471306>
+
+        Reviewed by Brady Eidson.
+
+        Implement the -_webView:runBeforeUnloadConfirmPanelWithMessage:initiatedByFrame:completionHandler: delegate
+        method in MiniBrowser to show a confirm panel as to whether to allow the unloading of the page when
+        unloading is initiated for a page that registered a onbeforeunload handler.
+
+        Modify TestWebKitAPI/Tests/WebKit2Cocoa/ModalAlerts.mm to test that the -_webView:runBeforeUnloadConfirmPanelWithMessage:initiatedByFrame:completionHandler:
+        is called. Also fix style nit; pass YES instead of true to avoid implicit conversion from bool to BOOL
+        when invoking the completion handler in -_webView:runJavaScriptAlertPanelWithMessage:initiatedByFrame:completionHandler:.
+
+        Until we fix <https://bugs.webkit.org/show_bug.cgi?id=172614> the unit test in TestWebKitAPI/Tests/WebKit2Cocoa/ModalAlerts.mm
+        for -_webView:runBeforeUnloadConfirmPanelWithMessage:initiatedByFrame:completionHandler: is only run on Mac
+        as we do not have the infrastructure to simulate a click/tap on iOS and a click/tap on the page that
+        registered an onbeforeunload handler is required to show a confirm panel when the page will be unloaded.
+
+        * MiniBrowser/mac/WK2BrowserWindowController.m:
+        (-[WK2BrowserWindowController _webView:runBeforeUnloadConfirmPanelWithMessage:initiatedByFrame:completionHandler:]):
+        * TestWebKitAPI/Tests/WebKit2/modal-alerts-in-new-about-blank-window.html:
+        * TestWebKitAPI/Tests/WebKit2Cocoa/ModalAlerts.mm:
+        (sawDialog):
+        (-[ModalAlertsUIDelegate webView:createWebViewWithConfiguration:forNavigationAction:windowFeatures:]):
+        (-[ModalAlertsUIDelegate webView:runJavaScriptConfirmPanelWithMessage:initiatedByFrame:completionHandler:]):
+        (-[ModalAlertsUIDelegate _webView:runBeforeUnloadConfirmPanelWithMessage:initiatedByFrame:completionHandler:]):
+
 2017-05-30  Alex Christensen  <achristensen@webkit.org>
 
         Update libwebrtc configuration
index d01d0cd..d0921ef 100644 (file)
@@ -515,6 +515,22 @@ static BOOL areEssentiallyEqual(double a, double b)
     }];
 }
 
+- (void)_webView:(WebView *)sender runBeforeUnloadConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL result))completionHandler
+{
+    NSAlert *alert = [[NSAlert alloc] init];
+
+    alert.messageText = [NSString stringWithFormat:@"JavaScript before unload dialog from %@.", [frame.request.URL absoluteString]];
+    alert.informativeText = message;
+
+    [alert addButtonWithTitle:@"Leave Page"];
+    [alert addButtonWithTitle:@"Stay On Page"];
+
+    [alert beginSheetModalForWindow:self.window completionHandler:^void (NSModalResponse response) {
+        completionHandler(response == NSAlertFirstButtonReturn);
+        [alert release];
+    }];
+}
+
 - (WKDragDestinationAction)_webView:(WKWebView *)webView dragDestinationActionMaskForDraggingInfo:(id)draggingInfo
 {
     return WKDragDestinationActionAny;
index f76cb65..19bf39d 100644 (file)
@@ -7,6 +7,7 @@ var newWindow = window.open("about:blank");
 newWindow.alert("Testing alert");
 newWindow.confirm("Testing confirm");
 newWindow.prompt("Testing prompt", "Default text");
+newWindow.onbeforeunload = () => "Default text";
 
 </script>
 </head>
index aa386a9..a446ee7 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 Apple Inc. All rights reserved.
+ * Copyright (C) 2014-2017 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -26,6 +26,7 @@
 #include "config.h"
 
 #import "PlatformUtilities.h"
+#import "TestWKWebView.h"
 #import <WebKit/WKPreferences.h>
 #import <WebKit/WKUIDelegatePrivate.h>
 #import <WebKit/WKWebView.h>
 @class ModalAlertsUIDelegate;
 
 static bool isDone;
-static RetainPtr<WKWebView> openedWebView;
+static RetainPtr<TestWKWebView> openedWebView;
 static RetainPtr<ModalAlertsUIDelegate> sharedUIDelegate;
 
 static unsigned dialogsSeen;
+
+// FIXME: Remove this guard once we fix <https://bugs.webkit.org/show_bug.cgi?id=172614>.
+#if PLATFORM(MAC)
+static const unsigned dialogsExpected = 4;
+static const unsigned dialogsBeforeUnloadConfirmPanel = dialogsExpected - 1;
+#else
 static const unsigned dialogsExpected = 3;
+#endif
 
 static void sawDialog()
 {
-    if (++dialogsSeen == dialogsExpected)
+    ++dialogsSeen;
+
+    // FIXME: Remove this guard once we fix <https://bugs.webkit.org/show_bug.cgi?id=172614>.
+#if PLATFORM(MAC)
+    if (dialogsSeen == dialogsBeforeUnloadConfirmPanel) {
+        [openedWebView sendClicksAtPoint:NSMakePoint(5, 5) numberOfClicks:1];
+        [openedWebView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"data:text/html"]]];
+        return;
+    }
+#endif
+
+    if (dialogsSeen == dialogsExpected)
         isDone = true;
 }
 
@@ -56,7 +75,7 @@ static void sawDialog()
 
 - (WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures
 {
-    openedWebView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration]);
+    openedWebView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration]);
     [openedWebView setUIDelegate:sharedUIDelegate.get()];
     return openedWebView.get();
 }
@@ -79,7 +98,7 @@ static void sawDialog()
     EXPECT_STREQ([[[frame securityOrigin] host] UTF8String], "");
     EXPECT_EQ([[frame securityOrigin] port], 0);
 
-    completionHandler(true);
+    completionHandler(YES);
     sawDialog();
 }
 
@@ -94,6 +113,20 @@ static void sawDialog()
     sawDialog();
 }
 
+// FIXME: Remove this guard once we fix <https://bugs.webkit.org/show_bug.cgi?id=172614>.
+#if PLATFORM(MAC)
+- (void)_webView:(WKWebView *)webView runBeforeUnloadConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL result))completionHandler
+{
+    EXPECT_STREQ([[[[frame request] URL] absoluteString] UTF8String], "about:blank");
+    EXPECT_STREQ([[[frame securityOrigin] protocol] UTF8String], "file");
+    EXPECT_STREQ([[[frame securityOrigin] host] UTF8String], "");
+    EXPECT_EQ([[frame securityOrigin] port], 0);
+
+    completionHandler(NO);
+    sawDialog();
+}
+#endif
+
 @end
 
 TEST(WebKit2, ModalAlerts)