Add asynchronous equivalent of -[<WKUIDelegate> webView:createWebViewWithConfiguratio...
authorbeidson@apple.com <beidson@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 20 Apr 2017 00:43:59 +0000 (00:43 +0000)
committerbeidson@apple.com <beidson@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 20 Apr 2017 00:43:59 +0000 (00:43 +0000)
<rdar://problem/30699851> and https://bugs.webkit.org/show_bug.cgi?id=171018

Reviewed by Tim Horton.

Source/WebKit2:

* UIProcess/API/APIUIClient.h:
(API::UIClient::createNewPageAsync):

* UIProcess/API/Cocoa/WKUIDelegatePrivate.h:

* UIProcess/Cocoa/UIDelegate.h:
* UIProcess/Cocoa/UIDelegate.mm:
(WebKit::UIDelegate::setDelegate):
(WebKit::UIDelegate::UIClient::createNewPageCommon):
(WebKit::UIDelegate::UIClient::createNewPage):
(WebKit::UIDelegate::UIClient::createNewPageAsync):

* UIProcess/WebPageProxy.cpp:
(WebKit::WebPageProxy::createNewPage):
* UIProcess/WebPageProxy.h:
* UIProcess/WebPageProxy.messages.in:

Tools:

* TestWebKitAPI/Tests/WebKit2Cocoa/OpenAndCloseWindow.mm:
(TEST):
(-[OpenAndCloseWindowUIDelegateAsync webView:createWebViewWithConfiguration:forNavigationAction:windowFeatures:]):
(-[OpenAndCloseWindowUIDelegateAsync _webView:createWebViewWithConfiguration:forNavigationAction:windowFeatures:completionHandler:]):

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

Source/WebKit2/ChangeLog
Source/WebKit2/UIProcess/API/APIUIClient.h
Source/WebKit2/UIProcess/API/Cocoa/WKUIDelegatePrivate.h
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
Tools/ChangeLog
Tools/TestWebKitAPI/Tests/WebKit2Cocoa/OpenAndCloseWindow.mm

index 8284b7c..5a1e3f0 100644 (file)
@@ -1,3 +1,27 @@
+2017-04-19  Brady Eidson  <beidson@apple.com>
+
+        Add asynchronous equivalent of -[<WKUIDelegate> webView:createWebViewWithConfiguration:...].
+        <rdar://problem/30699851> and https://bugs.webkit.org/show_bug.cgi?id=171018
+
+        Reviewed by Tim Horton.
+
+        * UIProcess/API/APIUIClient.h:
+        (API::UIClient::createNewPageAsync):
+
+        * UIProcess/API/Cocoa/WKUIDelegatePrivate.h:
+
+        * UIProcess/Cocoa/UIDelegate.h:
+        * UIProcess/Cocoa/UIDelegate.mm:
+        (WebKit::UIDelegate::setDelegate):
+        (WebKit::UIDelegate::UIClient::createNewPageCommon):
+        (WebKit::UIDelegate::UIClient::createNewPage):
+        (WebKit::UIDelegate::UIClient::createNewPageAsync):
+
+        * UIProcess/WebPageProxy.cpp:
+        (WebKit::WebPageProxy::createNewPage):
+        * UIProcess/WebPageProxy.h:
+        * UIProcess/WebPageProxy.messages.in:
+
 2017-04-19  Anders Carlsson  <andersca@apple.com>
 
         Stop using deprecated APIs, part 3
index 07aebe1..27d6690 100644 (file)
@@ -74,6 +74,7 @@ public:
     virtual ~UIClient() { }
 
     virtual RefPtr<WebKit::WebPageProxy> createNewPage(WebKit::WebPageProxy*, WebKit::WebFrameProxy*, const WebCore::SecurityOriginData&, const WebCore::ResourceRequest&, const WebCore::WindowFeatures&, const WebKit::NavigationActionData&) { return nullptr; }
+    virtual bool createNewPageAsync(WebKit::WebPageProxy*, WebKit::WebFrameProxy*, const WebCore::SecurityOriginData&, const WebCore::ResourceRequest&, const WebCore::WindowFeatures&, const WebKit::NavigationActionData&, std::function<void (RefPtr<WebKit::WebPageProxy>)> completionHandler) { return false; }
     virtual void showPage(WebKit::WebPageProxy*) { }
     virtual void fullscreenMayReturnToInline(WebKit::WebPageProxy*) { }
     virtual void didEnterFullscreen(WebKit::WebPageProxy*) { }
index 4e3614e..d629805 100644 (file)
@@ -68,6 +68,8 @@ struct UIEdgeInsets;
 - (void)_webView:(WKWebView *)webView checkUserMediaPermissionForURL:(NSURL *)url mainFrameURL:(NSURL *)mainFrameURL frameIdentifier:(NSUInteger)frameIdentifier decisionHandler:(void (^)(NSString *salt, BOOL authorized))decisionHandler WK_API_AVAILABLE(macosx(WK_MAC_TBA), ios(WK_IOS_TBA));
 - (void)_webView:(WKWebView *)webView mediaCaptureStateDidChange:(_WKMediaCaptureState)state WK_API_AVAILABLE(macosx(WK_MAC_TBA), ios(WK_IOS_TBA));
 - (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));
+
 #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 e06c1fc..6a7bea9 100644 (file)
@@ -76,6 +76,9 @@ private:
     private:
         // API::UIClient
         RefPtr<WebKit::WebPageProxy> createNewPage(WebKit::WebPageProxy*, WebKit::WebFrameProxy*, const WebCore::SecurityOriginData&, const WebCore::ResourceRequest&, const WebCore::WindowFeatures&, const WebKit::NavigationActionData&) override;
+        bool createNewPageAsync(WebKit::WebPageProxy*, WebKit::WebFrameProxy*, const WebCore::SecurityOriginData&, const WebCore::ResourceRequest&, const WebCore::WindowFeatures&, const WebKit::NavigationActionData&, std::function<void (RefPtr<WebKit::WebPageProxy>)> completionHandler) override;
+        RefPtr<WebKit::WebPageProxy> createNewPageCommon(WebKit::WebPageProxy*, WebKit::WebFrameProxy*, const WebCore::SecurityOriginData&, const WebCore::ResourceRequest&, const WebCore::WindowFeatures&, const WebKit::NavigationActionData&, std::function<void (RefPtr<WebKit::WebPageProxy>)>* completionHandler);
+
         void close(WebKit::WebPageProxy*) override;
         void fullscreenMayReturnToInline(WebKit::WebPageProxy*) override;
         void didEnterFullscreen(WebKit::WebPageProxy*) override;
@@ -118,6 +121,7 @@ private:
 
     struct {
         bool webViewCreateWebViewWithConfigurationForNavigationActionWindowFeatures : 1;
+        bool webViewCreateWebViewWithConfigurationForNavigationActionWindowFeaturesAsync : 1;
         bool webViewRunJavaScriptAlertPanelWithMessageInitiatedByFrameCompletionHandler : 1;
         bool webViewRunJavaScriptConfirmPanelWithMessageInitiatedByFrameCompletionHandler : 1;
         bool webViewRunJavaScriptTextInputPanelWithPromptDefaultTextInitiatedByFrameCompletionHandler : 1;
index 89b8ecc..4ef5542 100644 (file)
@@ -92,6 +92,7 @@ void UIDelegate::setDelegate(id <WKUIDelegate> delegate)
     m_delegate = delegate;
 
     m_delegateMethods.webViewCreateWebViewWithConfigurationForNavigationActionWindowFeatures = [delegate respondsToSelector:@selector(webView:createWebViewWithConfiguration:forNavigationAction:windowFeatures:)];
+    m_delegateMethods.webViewCreateWebViewWithConfigurationForNavigationActionWindowFeaturesAsync = [delegate respondsToSelector:@selector(_webView:createWebViewWithConfiguration:forNavigationAction:windowFeatures:completionHandler:)];
     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:)];
@@ -169,14 +170,10 @@ UIDelegate::UIClient::~UIClient()
 {
 }
 
-RefPtr<WebKit::WebPageProxy> UIDelegate::UIClient::createNewPage(WebKit::WebPageProxy* page, WebKit::WebFrameProxy* initiatingFrame, const WebCore::SecurityOriginData& securityOriginData, const WebCore::ResourceRequest& request, const WebCore::WindowFeatures& windowFeatures, const WebKit::NavigationActionData& navigationActionData)
+RefPtr<WebKit::WebPageProxy> UIDelegate::UIClient::createNewPageCommon(WebKit::WebPageProxy* page, WebKit::WebFrameProxy* initiatingFrame, const WebCore::SecurityOriginData& securityOriginData, const WebCore::ResourceRequest& request, const WebCore::WindowFeatures& windowFeatures, const WebKit::NavigationActionData& navigationActionData, std::function<void (RefPtr<WebKit::WebPageProxy>)>* completionHandler)
 {
-    if (!m_uiDelegate.m_delegateMethods.webViewCreateWebViewWithConfigurationForNavigationActionWindowFeatures)
-        return nullptr;
-
     auto delegate = m_uiDelegate.m_delegate.get();
-    if (!delegate)
-        return nullptr;
+    ASSERT(delegate);
 
     auto configuration = adoptNS([m_uiDelegate.m_webView->_configuration copy]);
     [configuration _setRelatedWebView:m_uiDelegate.m_webView];
@@ -189,6 +186,22 @@ RefPtr<WebKit::WebPageProxy> UIDelegate::UIClient::createNewPage(WebKit::WebPage
 
     auto apiWindowFeatures = API::WindowFeatures::create(windowFeatures);
 
+    if (completionHandler) {
+        auto completionHandlerCopy = *completionHandler;
+
+        [(id <WKUIDelegatePrivate>)delegate _webView:m_uiDelegate.m_webView createWebViewWithConfiguration:configuration.get() forNavigationAction:wrapper(apiNavigationAction) windowFeatures:wrapper(apiWindowFeatures) completionHandler:^void(WKWebView *webView) {
+            if (!webView)
+                return;
+
+            if ([webView->_configuration _relatedWebView] != m_uiDelegate.m_webView)
+                [NSException raise:NSInternalInconsistencyException format:@"Returned WKWebView was not created with the given configuration."];
+
+            completionHandlerCopy(webView->_page.get());
+        }];
+
+        return nullptr;
+    }
+
     RetainPtr<WKWebView> webView = [delegate webView:m_uiDelegate.m_webView createWebViewWithConfiguration:configuration.get() forNavigationAction:wrapper(apiNavigationAction) windowFeatures:wrapper(apiWindowFeatures)];
 
     if (!webView)
@@ -200,6 +213,32 @@ RefPtr<WebKit::WebPageProxy> UIDelegate::UIClient::createNewPage(WebKit::WebPage
     return webView->_page.get();
 }
 
+RefPtr<WebKit::WebPageProxy> UIDelegate::UIClient::createNewPage(WebKit::WebPageProxy* page, WebKit::WebFrameProxy* initiatingFrame, const WebCore::SecurityOriginData& securityOriginData, const WebCore::ResourceRequest& request, const WebCore::WindowFeatures& windowFeatures, const WebKit::NavigationActionData& navigationActionData)
+{
+    if (!m_uiDelegate.m_delegateMethods.webViewCreateWebViewWithConfigurationForNavigationActionWindowFeatures)
+        return nullptr;
+
+    auto delegate = m_uiDelegate.m_delegate.get();
+    if (!delegate)
+        return nullptr;
+
+    return createNewPageCommon(page, initiatingFrame, securityOriginData, request, windowFeatures, navigationActionData, nullptr);
+}
+
+bool UIDelegate::UIClient::createNewPageAsync(WebKit::WebPageProxy* page, WebKit::WebFrameProxy* initiatingFrame, const WebCore::SecurityOriginData& securityOriginData, const WebCore::ResourceRequest& request, const WebCore::WindowFeatures& windowFeatures, const WebKit::NavigationActionData& navigationActionData, std::function<void (RefPtr<WebKit::WebPageProxy>)> completionHandler)
+{
+    if (!m_uiDelegate.m_delegateMethods.webViewCreateWebViewWithConfigurationForNavigationActionWindowFeaturesAsync)
+        return false;
+
+    auto delegate = m_uiDelegate.m_delegate.get();
+    if (!delegate)
+        return false;
+
+    createNewPageCommon(page, initiatingFrame, securityOriginData, request, windowFeatures, navigationActionData, &completionHandler);
+
+    return true;
+}
+
 void UIDelegate::UIClient::runJavaScriptAlert(WebKit::WebPageProxy*, const WTF::String& message, WebKit::WebFrameProxy* webFrameProxy, const WebCore::SecurityOriginData& securityOriginData, Function<void ()>&& completionHandler)
 {
     if (!m_uiDelegate.m_delegateMethods.webViewRunJavaScriptAlertPanelWithMessageInitiatedByFrameCompletionHandler) {
index 604146f..aaf20bc 100644 (file)
@@ -3867,24 +3867,31 @@ void WebPageProxy::didUpdateHistoryTitle(const String& title, const String& url,
 
 // UIClient
 
-void WebPageProxy::createNewPage(uint64_t frameID, const SecurityOriginData& securityOriginData, const ResourceRequest& request, const WindowFeatures& windowFeatures, const NavigationActionData& navigationActionData, uint64_t& newPageID, WebPageCreationParameters& newPageParameters)
+void WebPageProxy::createNewPage(uint64_t frameID, const SecurityOriginData& securityOriginData, const ResourceRequest& request, const WindowFeatures& windowFeatures, const NavigationActionData& navigationActionData, RefPtr<Messages::WebPageProxy::CreateNewPage::DelayedReply> reply)
 {
     WebFrameProxy* frame = m_process->webFrame(frameID);
     MESSAGE_CHECK(frame);
 
     auto mainFrameURL = m_mainFrame->url();
 
-    RefPtr<WebPageProxy> newPage = m_uiClient->createNewPage(this, frame, securityOriginData, request, windowFeatures, navigationActionData);
-    if (!newPage) {
-        newPageID = 0;
-        return;
-    }
+    auto completionHandler = [this, protectedThis = RefPtr<WebPageProxy>(this), mainFrameURL, request, reply = WTFMove(reply)](RefPtr<WebPageProxy> newPage) {
+        if (!newPage) {
+            reply->send(0, { });
+            return;
+        }
+
+        reply->send(newPage->pageID(), newPage->creationParameters());
 
-    newPageID = newPage->pageID();
-    newPageParameters = newPage->creationParameters();
+        WebsiteDataStore::cloneSessionData(*this, *newPage);
+        newPage->m_shouldSuppressAppLinksInNextNavigationPolicyDecision = hostsAreEqual(URL(ParsedURLString, mainFrameURL), request.url());
 
-    WebsiteDataStore::cloneSessionData(*this, *newPage);
-    newPage->m_shouldSuppressAppLinksInNextNavigationPolicyDecision = hostsAreEqual(URL(ParsedURLString, mainFrameURL), request.url());
+    };
+
+    if (m_uiClient->createNewPageAsync(this, frame, securityOriginData, request, windowFeatures, navigationActionData, completionHandler))
+        return;
+
+    RefPtr<WebPageProxy> newPage = m_uiClient->createNewPage(this, frame, securityOriginData, request, windowFeatures, navigationActionData);
+    completionHandler(WTFMove(newPage));
 }
     
 void WebPageProxy::showPage()
index b9205f4..d351688 100644 (file)
@@ -1286,7 +1286,7 @@ private:
     void didUpdateHistoryTitle(const String& title, const String& url, uint64_t frameID);
 
     // UI client
-    void createNewPage(uint64_t frameID, const WebCore::SecurityOriginData&, const WebCore::ResourceRequest&, const WebCore::WindowFeatures&, const NavigationActionData&, uint64_t& newPageID, WebPageCreationParameters&);
+    void createNewPage(uint64_t frameID, const WebCore::SecurityOriginData&, const WebCore::ResourceRequest&, const WebCore::WindowFeatures&, const NavigationActionData&, RefPtr<Messages::WebPageProxy::CreateNewPage::DelayedReply>);
     void showPage();
     void runJavaScriptAlert(uint64_t frameID, const WebCore::SecurityOriginData&, const String&, Ref<Messages::WebPageProxy::RunJavaScriptAlert::DelayedReply>&&);
     void runJavaScriptConfirm(uint64_t frameID, const WebCore::SecurityOriginData&, const String&, Ref<Messages::WebPageProxy::RunJavaScriptConfirm::DelayedReply>&&);
index 14a57f9..be695af 100644 (file)
@@ -22,7 +22,7 @@
 
 messages -> WebPageProxy {
     # UI messages
-    CreateNewPage(uint64_t frameID, struct WebCore::SecurityOriginData frameSecurityOrigin, WebCore::ResourceRequest request, struct WebCore::WindowFeatures windowFeatures, struct WebKit::NavigationActionData navigationActionData) -> (uint64_t newPageID, struct WebKit::WebPageCreationParameters newPageParameters)
+    CreateNewPage(uint64_t frameID, struct WebCore::SecurityOriginData frameSecurityOrigin, WebCore::ResourceRequest request, struct WebCore::WindowFeatures windowFeatures, struct WebKit::NavigationActionData navigationActionData) -> (uint64_t newPageID, struct WebKit::WebPageCreationParameters newPageParameters) Delayed
     ShowPage()
     ClosePage(bool stopResponsivenessTimer)
     RunJavaScriptAlert(uint64_t frameID, struct WebCore::SecurityOriginData frameSecurityOrigin, String message) -> () Delayed
index 425dfe5..c965049 100644 (file)
@@ -1,5 +1,17 @@
 2017-04-19  Brady Eidson  <beidson@apple.com>
 
+        Add asynchronous equivalent of -[<WKUIDelegate> webView:createWebViewWithConfiguration:...].
+        <rdar://problem/30699851> and https://bugs.webkit.org/show_bug.cgi?id=171018
+
+        Reviewed by Tim Horton.
+
+        * TestWebKitAPI/Tests/WebKit2Cocoa/OpenAndCloseWindow.mm:
+        (TEST):
+        (-[OpenAndCloseWindowUIDelegateAsync webView:createWebViewWithConfiguration:forNavigationAction:windowFeatures:]):
+        (-[OpenAndCloseWindowUIDelegateAsync _webView:createWebViewWithConfiguration:forNavigationAction:windowFeatures:completionHandler:]):
+
+2017-04-19  Brady Eidson  <beidson@apple.com>
+
         REGRESSION (r213168): An extra Web Content process is spun up on launch and is never closed.
         <rdar://problem/30774839> and https://bugs.webkit.org/show_bug.cgi?id=171002
 
index b8f5211..6c6794a 100644 (file)
 #if WK_API_ENABLED
 
 @class OpenAndCloseWindowUIDelegate;
+@class OpenAndCloseWindowUIDelegateAsync;
 
 static bool isDone;
 static RetainPtr<WKWebView> openedWebView;
 static RetainPtr<OpenAndCloseWindowUIDelegate> sharedUIDelegate;
+static RetainPtr<OpenAndCloseWindowUIDelegateAsync> sharedUIDelegateAsync;
 
 @interface OpenAndCloseWindowUIDelegate : NSObject <WKUIDelegate>
 @end
@@ -62,6 +64,8 @@ static RetainPtr<OpenAndCloseWindowUIDelegate> sharedUIDelegate;
 
 TEST(WebKit2, OpenAndCloseWindow)
 {
+    openedWebView = nullptr;
+
     RetainPtr<WKWebView> webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600)]);
 
     sharedUIDelegate = adoptNS([[OpenAndCloseWindowUIDelegate alloc] init]);
@@ -75,4 +79,43 @@ TEST(WebKit2, OpenAndCloseWindow)
     TestWebKitAPI::Util::run(&isDone);
 }
 
+@interface OpenAndCloseWindowUIDelegateAsync : OpenAndCloseWindowUIDelegate
+@end
+
+@implementation OpenAndCloseWindowUIDelegateAsync
+
+- (WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures
+{
+    ASSERT_NOT_REACHED();
+    return nil;
+}
+
+- (void)_webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures completionHandler:(void (^)(WKWebView *webView))completionHandler
+{
+    dispatch_async(dispatch_get_main_queue(), ^ {
+        openedWebView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration]);
+        [openedWebView setUIDelegate:sharedUIDelegateAsync.get()];
+        completionHandler(openedWebView.get());
+    });
+}
+
+@end
+
+TEST(WebKit2, OpenAndCloseWindowAsync)
+{
+    openedWebView = nullptr;
+
+    RetainPtr<WKWebView> webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600)]);
+
+    sharedUIDelegateAsync = adoptNS([[OpenAndCloseWindowUIDelegateAsync alloc] init]);
+    [webView setUIDelegate:sharedUIDelegateAsync.get()];
+
+    [webView configuration].preferences.javaScriptCanOpenWindowsAutomatically = YES;
+
+    NSURLRequest *request = [NSURLRequest requestWithURL:[[NSBundle mainBundle] URLForResource:@"open-and-close-window" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]];
+    [webView loadRequest:request];
+
+    TestWebKitAPI::Util::run(&isDone);
+}
+
 #endif