Title: [291985] branches/safari-614.1.8-branch
Revision
291985
Author
repst...@apple.com
Date
2022-03-28 13:29:35 -0700 (Mon, 28 Mar 2022)

Log Message

Cherry-pick r291979. rdar://problem/90616651

    Support ServiceWorkerClients.openWindow.
    <rdar://90616651> and https://bugs.webkit.org/show_bug.cgi?id=238400

    Reviewed by Youenn Fablet.
    Source/WebCore:

    Test: http/tests/workers/service/openwindow-from-notification-click.html

    * dom/Document.cpp:
    (WebCore::Document::pageID const):

    * page/ClientOrigin.h:
    (WebCore::ClientOrigin::loggingString const):

    * workers/service/ServiceWorkerClientData.cpp:
    (WebCore::ServiceWorkerClientData::isolatedCopy const):
    (WebCore::ServiceWorkerClientData::isolatedCopy):
    (WebCore::ServiceWorkerClientData::from):

    * workers/service/ServiceWorkerClientData.h:
    (WebCore::ServiceWorkerClientData::encode const):
    (WebCore::ServiceWorkerClientData::decode):

    * workers/service/ServiceWorkerClients.cpp:
    (WebCore::matchWindowWithPageIdentifier):
    (WebCore::ServiceWorkerClients::openWindow):

    * workers/service/context/SWContextManager.h:
    * workers/service/server/SWServerToContextConnection.h:
    * workers/service/server/SWServerWorker.h:

    Source/WebKit:

    This API asks the browser to asynchronously open a new tab to a URL then resolve
    a promise with the new WindowClient representing that tab.

    From a WebCore/WebKit standpoint, implementing this was mostly straightforward.
    1 - A plumbing exercise (thread hopping and IPC'ing the message and its reply around)
    2 - Implmenting a new delegate method for the hosting app to create the requested WKWebView

    The delegate method was interesting. Normally this is the type of thing that'd go to the
    WKUIDelegate but that requires there to be a WKWebView, and service workers can be running
    without any web views.

    Fortunately we already had a WKWebsiteDataStore delegate SPI, and service workers *do* always
    have an associated website data store they're running under.

    Once the app gives the new web view back to WebKit, we record its PageIdentifier in the reply.

    Once the reply makes its way all the way back to the ServiceWorker process and on the
    ServiceWorker thread, we do a client match and cross check with that PageIdentifier to make
    sure we're resolving the promise with the correct WindowClient.

    If there's no matched clients, then the view is either already gone or it has navigated away
    to a non-applicable URL.

    Same if there are matched clients, but they don't match the specified PageIdentifier.

    A straight forward layouttest completes the task.

    * NetworkProcess/ServiceWorker/WebSWServerConnection.cpp:
    (WebKit::WebSWServerConnection::controlClient):

    * NetworkProcess/ServiceWorker/WebSWServerToContextConnection.cpp:
    (WebKit::WebSWServerToContextConnection::openWindow):
    * NetworkProcess/ServiceWorker/WebSWServerToContextConnection.h:
    * NetworkProcess/ServiceWorker/WebSWServerToContextConnection.messages.in:

    * UIProcess/API/Cocoa/WKWebsiteDataStore.mm:
    (-[WKWebsiteDataStore set_delegate:]):
    * UIProcess/API/Cocoa/_WKWebsiteDataStoreDelegate.h:

    * UIProcess/Network/NetworkProcessProxy.cpp:
    (WebKit::NetworkProcessProxy::openWindowFromServiceWorker):
    * UIProcess/Network/NetworkProcessProxy.h:
    * UIProcess/Network/NetworkProcessProxy.messages.in:

    * UIProcess/WebPageProxy.cpp:
    (WebKit::WebPageProxy::didFailProvisionalLoadForFrameShared):
    (WebKit::WebPageProxy::callLoadCompletionHandlersIfNecessary):
    (WebKit::WebPageProxy::didFinishLoadForFrame):
    (WebKit::WebPageProxy::didFailLoadForFrame):
    (WebKit::WebPageProxy::resetState):
    (WebKit::WebPageProxy::callServiceWorkerLaunchCompletionHandlerIfNecessary): Deleted.
    * UIProcess/WebPageProxy.h:

    * UIProcess/WebsiteData/WebsiteDataStore.cpp:
    (WebKit::WebsiteDataStore::openWindowFromServiceWorker):
    * UIProcess/WebsiteData/WebsiteDataStore.h:

    * UIProcess/WebsiteData/WebsiteDataStoreClient.h:
    (WebKit::WebsiteDataStoreClient::openWindowFromServiceWorker):

    * WebProcess/Notifications/WebNotificationManager.cpp:
    (WebKit::WebNotificationManager::show):
    (WebKit::WebNotificationManager::didShowNotification):
    (WebKit::WebNotificationManager::didClickNotification):

    * WebProcess/Storage/WebSWContextManagerConnection.cpp:
    (WebKit::WebSWContextManagerConnection::openWindow):
    * WebProcess/Storage/WebSWContextManagerConnection.h:

    Source/WTF:

    * wtf/HashTable.h:
    (WTF::KeyTraits>::inlineLookup): Relax this value size requirement for now.
    The required refactoring is best left as a seperate task with a seperate patch.

    Tools:

    Implement the new delegate to create the new view.

    * WebKitTestRunner/TestController.cpp:
    (WTR::TestController::createOtherPage):
    (WTR::TestController::createOtherPlatformWebView):
    * WebKitTestRunner/TestController.h:

    * WebKitTestRunner/cocoa/TestControllerCocoa.mm:
    (WTR::TestController::platformCreateOtherPage):
    * WebKitTestRunner/cocoa/TestWebsiteDataStoreDelegate.mm:
    (-[TestWebsiteDataStoreDelegate websiteDataStore:openWindow:fromServiceWorkerOrigin:completionHandler:]):

    LayoutTests:

    WKTR knows how to openWindow() now.

    So test:
    - The success case
    - Failure due to a disallowed URL
    - Failure due to a lack of a related user gesture.

    * http/tests/workers/service/openwindow-from-notification-click-expected.txt: Added.
    * http/tests/workers/service/openwindow-from-notification-click.html: Added.
    * http/tests/workers/service/resources/openwindow-client.html: Added.
    * http/tests/workers/service/resources/shownotification-openwindow-worker.js: Added.
    (async const):
    (let.messageClients):
    (clients.openWindow.string_appeared_here.then.async client):
    (catch.async error):
    (async event):
    (async tryShow):
    (async getNotes):
    * platform/gtk/TestExpectations:

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

Modified Paths

Added Paths

Diff

Modified: branches/safari-614.1.8-branch/LayoutTests/ChangeLog (291984 => 291985)


--- branches/safari-614.1.8-branch/LayoutTests/ChangeLog	2022-03-28 20:17:35 UTC (rev 291984)
+++ branches/safari-614.1.8-branch/LayoutTests/ChangeLog	2022-03-28 20:29:35 UTC (rev 291985)
@@ -1,3 +1,181 @@
+2022-03-28  Russell Epstein  <repst...@apple.com>
+
+        Cherry-pick r291979. rdar://problem/90616651
+
+    Support ServiceWorkerClients.openWindow.
+    <rdar://90616651> and https://bugs.webkit.org/show_bug.cgi?id=238400
+    
+    Reviewed by Youenn Fablet.
+    Source/WebCore:
+    
+    Test: http/tests/workers/service/openwindow-from-notification-click.html
+    
+    * dom/Document.cpp:
+    (WebCore::Document::pageID const):
+    
+    * page/ClientOrigin.h:
+    (WebCore::ClientOrigin::loggingString const):
+    
+    * workers/service/ServiceWorkerClientData.cpp:
+    (WebCore::ServiceWorkerClientData::isolatedCopy const):
+    (WebCore::ServiceWorkerClientData::isolatedCopy):
+    (WebCore::ServiceWorkerClientData::from):
+    
+    * workers/service/ServiceWorkerClientData.h:
+    (WebCore::ServiceWorkerClientData::encode const):
+    (WebCore::ServiceWorkerClientData::decode):
+    
+    * workers/service/ServiceWorkerClients.cpp:
+    (WebCore::matchWindowWithPageIdentifier):
+    (WebCore::ServiceWorkerClients::openWindow):
+    
+    * workers/service/context/SWContextManager.h:
+    * workers/service/server/SWServerToContextConnection.h:
+    * workers/service/server/SWServerWorker.h:
+    
+    Source/WebKit:
+    
+    This API asks the browser to asynchronously open a new tab to a URL then resolve
+    a promise with the new WindowClient representing that tab.
+    
+    From a WebCore/WebKit standpoint, implementing this was mostly straightforward.
+    1 - A plumbing exercise (thread hopping and IPC'ing the message and its reply around)
+    2 - Implmenting a new delegate method for the hosting app to create the requested WKWebView
+    
+    The delegate method was interesting. Normally this is the type of thing that'd go to the
+    WKUIDelegate but that requires there to be a WKWebView, and service workers can be running
+    without any web views.
+    
+    Fortunately we already had a WKWebsiteDataStore delegate SPI, and service workers *do* always
+    have an associated website data store they're running under.
+    
+    Once the app gives the new web view back to WebKit, we record its PageIdentifier in the reply.
+    
+    Once the reply makes its way all the way back to the ServiceWorker process and on the
+    ServiceWorker thread, we do a client match and cross check with that PageIdentifier to make
+    sure we're resolving the promise with the correct WindowClient.
+    
+    If there's no matched clients, then the view is either already gone or it has navigated away
+    to a non-applicable URL.
+    
+    Same if there are matched clients, but they don't match the specified PageIdentifier.
+    
+    A straight forward layouttest completes the task.
+    
+    * NetworkProcess/ServiceWorker/WebSWServerConnection.cpp:
+    (WebKit::WebSWServerConnection::controlClient):
+    
+    * NetworkProcess/ServiceWorker/WebSWServerToContextConnection.cpp:
+    (WebKit::WebSWServerToContextConnection::openWindow):
+    * NetworkProcess/ServiceWorker/WebSWServerToContextConnection.h:
+    * NetworkProcess/ServiceWorker/WebSWServerToContextConnection.messages.in:
+    
+    * UIProcess/API/Cocoa/WKWebsiteDataStore.mm:
+    (-[WKWebsiteDataStore set_delegate:]):
+    * UIProcess/API/Cocoa/_WKWebsiteDataStoreDelegate.h:
+    
+    * UIProcess/Network/NetworkProcessProxy.cpp:
+    (WebKit::NetworkProcessProxy::openWindowFromServiceWorker):
+    * UIProcess/Network/NetworkProcessProxy.h:
+    * UIProcess/Network/NetworkProcessProxy.messages.in:
+    
+    * UIProcess/WebPageProxy.cpp:
+    (WebKit::WebPageProxy::didFailProvisionalLoadForFrameShared):
+    (WebKit::WebPageProxy::callLoadCompletionHandlersIfNecessary):
+    (WebKit::WebPageProxy::didFinishLoadForFrame):
+    (WebKit::WebPageProxy::didFailLoadForFrame):
+    (WebKit::WebPageProxy::resetState):
+    (WebKit::WebPageProxy::callServiceWorkerLaunchCompletionHandlerIfNecessary): Deleted.
+    * UIProcess/WebPageProxy.h:
+    
+    * UIProcess/WebsiteData/WebsiteDataStore.cpp:
+    (WebKit::WebsiteDataStore::openWindowFromServiceWorker):
+    * UIProcess/WebsiteData/WebsiteDataStore.h:
+    
+    * UIProcess/WebsiteData/WebsiteDataStoreClient.h:
+    (WebKit::WebsiteDataStoreClient::openWindowFromServiceWorker):
+    
+    * WebProcess/Notifications/WebNotificationManager.cpp:
+    (WebKit::WebNotificationManager::show):
+    (WebKit::WebNotificationManager::didShowNotification):
+    (WebKit::WebNotificationManager::didClickNotification):
+    
+    * WebProcess/Storage/WebSWContextManagerConnection.cpp:
+    (WebKit::WebSWContextManagerConnection::openWindow):
+    * WebProcess/Storage/WebSWContextManagerConnection.h:
+    
+    Source/WTF:
+    
+    * wtf/HashTable.h:
+    (WTF::KeyTraits>::inlineLookup): Relax this value size requirement for now.
+    The required refactoring is best left as a seperate task with a seperate patch.
+    
+    Tools:
+    
+    Implement the new delegate to create the new view.
+    
+    * WebKitTestRunner/TestController.cpp:
+    (WTR::TestController::createOtherPage):
+    (WTR::TestController::createOtherPlatformWebView):
+    * WebKitTestRunner/TestController.h:
+    
+    * WebKitTestRunner/cocoa/TestControllerCocoa.mm:
+    (WTR::TestController::platformCreateOtherPage):
+    * WebKitTestRunner/cocoa/TestWebsiteDataStoreDelegate.mm:
+    (-[TestWebsiteDataStoreDelegate websiteDataStore:openWindow:fromServiceWorkerOrigin:completionHandler:]):
+    
+    LayoutTests:
+    
+    WKTR knows how to openWindow() now.
+    
+    So test:
+    - The success case
+    - Failure due to a disallowed URL
+    - Failure due to a lack of a related user gesture.
+    
+    * http/tests/workers/service/openwindow-from-notification-click-expected.txt: Added.
+    * http/tests/workers/service/openwindow-from-notification-click.html: Added.
+    * http/tests/workers/service/resources/openwindow-client.html: Added.
+    * http/tests/workers/service/resources/shownotification-openwindow-worker.js: Added.
+    (async const):
+    (let.messageClients):
+    (clients.openWindow.string_appeared_here.then.async client):
+    (catch.async error):
+    (async event):
+    (async tryShow):
+    (async getNotes):
+    * platform/gtk/TestExpectations:
+    
+    
+    git-svn-id: https://svn.webkit.org/repository/webkit/trunk@291979 268f45cc-cd09-0410-ab3c-d52691b4dbfc
+
+    2022-03-28  Brady Eidson  <beid...@apple.com>
+
+            Support ServiceWorkerClients.openWindow.
+            <rdar://90616651> and https://bugs.webkit.org/show_bug.cgi?id=238400
+
+            Reviewed by Youenn Fablet.
+
+            WKTR knows how to openWindow() now.
+
+            So test:
+            - The success case
+            - Failure due to a disallowed URL
+            - Failure due to a lack of a related user gesture.
+
+            * http/tests/workers/service/openwindow-from-notification-click-expected.txt: Added.
+            * http/tests/workers/service/openwindow-from-notification-click.html: Added.
+            * http/tests/workers/service/resources/openwindow-client.html: Added.
+            * http/tests/workers/service/resources/shownotification-openwindow-worker.js: Added.
+            (async const):
+            (let.messageClients):
+            (clients.openWindow.string_appeared_here.then.async client):
+            (catch.async error):
+            (async event):
+            (async tryShow):
+            (async getNotes):
+            * platform/gtk/TestExpectations:
+
 2022-03-27  Matt Woodrow  <mattwood...@apple.com>
 
         Use the sizing algorithm's available size to compute grid gap.

Added: branches/safari-614.1.8-branch/LayoutTests/http/tests/workers/service/openwindow-from-notification-click-expected.txt (0 => 291985)


--- branches/safari-614.1.8-branch/LayoutTests/http/tests/workers/service/openwindow-from-notification-click-expected.txt	                        (rev 0)
+++ branches/safari-614.1.8-branch/LayoutTests/http/tests/workers/service/openwindow-from-notification-click-expected.txt	2022-03-28 20:29:35 UTC (rev 291985)
@@ -0,0 +1,15 @@
+This tests that a notificationclick handler can open a window
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS Notification.permission is "granted"
+PASS gotClicked is false
+PASS gotClosed is false
+PASS gotClicked is true
+PASS gotClosed is false
+PASS gotAboutBlankFail is true
+PASS gotUserGestureFail is true
+PASS gotSuccessfulNullClient is true
+PASS New client has been observed
+

Added: branches/safari-614.1.8-branch/LayoutTests/http/tests/workers/service/openwindow-from-notification-click.html (0 => 291985)


--- branches/safari-614.1.8-branch/LayoutTests/http/tests/workers/service/openwindow-from-notification-click.html	                        (rev 0)
+++ branches/safari-614.1.8-branch/LayoutTests/http/tests/workers/service/openwindow-from-notification-click.html	2022-03-28 20:29:35 UTC (rev 291985)
@@ -0,0 +1,91 @@
+<head>
+<script src=""
+<script src=""
+<script>
+
+function failTheTest(msg)
+{
+    testFailed(msg);
+    if (testRunner)
+        testRunner.notifyDone();
+}
+
+if (window.testRunner) {
+    testRunner.waitUntilDone();
+    testRunner.grantWebNotificationPermission(testURL);
+    setTimeout("failTheTest('timed out')", 15000);
+}
+
+description("This tests that a notificationclick handler can open a window");
+
+shouldBeEqualToString("Notification.permission", "granted");
+
+async function registerServiceWorker() {
+    var registration = await navigator.serviceWorker.register('resources/shownotification-openwindow-worker.js');
+    
+    if (!registration)
+        return testFailed("No registration");
+    
+    if (registration.active) {
+        registration.active.postMessage("Start");
+        return;
+    }
+
+    var installingWorker = registration.installing;
+    if (!installingWorker)
+        failTheTest("No active *or* installing worker");
+
+    installingWorker.addEventListener("statechange", () => {
+        if (installingWorker.state === "activated") {
+            installingWorker.postMessage("tryshow");
+        }
+    });
+}
+
+var gotClicked = false;
+var gotClosed = false;
+var gotNewClient = false;
+var gotAboutBlankFail = false;
+var gotUserGestureFail = false;
+var gotSuccessfulNullClient = false;
+
+navigator.serviceWorker.addEventListener('message', event => {
+    if (event.data == "showFailed") {
+        failTheTest("Unexpectedly received the failed-to-show message");
+    } else if (event.data == "shown") {
+        if (testRunner)
+            testRunner.simulateWebNotificationClickForServiceWorkerNotifications();
+    } else if (event.data == "clicked") {
+        shouldBeFalse("gotClicked");
+        shouldBeFalse("gotClosed");
+        gotClicked = true;
+    } else if (event.data == "closed") {
+        shouldBeTrue("gotClicked")
+        shouldBeFalse("gotClosed")
+        gotClosed = true;
+    } else if (event.data == "gotNewClient") {
+        gotNewClient = true;
+    } else if (event.data == "gotAboutBlankFail") {
+        gotAboutBlankFail = true;
+    } else if (event.data == "gotUserGestureFail") {
+        gotUserGestureFail = true;
+    } else if (event.data = "" {
+        gotSuccessfulNullClient = true;
+    } else {
+        testFailed("Message received: " + event.data);
+    }
+    
+    if (gotNewClient) {
+        shouldBeTrue("gotAboutBlankFail");
+        shouldBeTrue("gotUserGestureFail");
+        shouldBeTrue("gotSuccessfulNullClient");
+        testPassed("New client has been observed");
+        if (window.testRunner)
+            testRunner.notifyDone();
+    }
+});
+
+</script>
+</head>
+<body _onload_="registerServiceWorker()">
+</body>

Added: branches/safari-614.1.8-branch/LayoutTests/http/tests/workers/service/resources/openwindow-client.html (0 => 291985)


--- branches/safari-614.1.8-branch/LayoutTests/http/tests/workers/service/resources/openwindow-client.html	                        (rev 0)
+++ branches/safari-614.1.8-branch/LayoutTests/http/tests/workers/service/resources/openwindow-client.html	2022-03-28 20:29:35 UTC (rev 291985)
@@ -0,0 +1,16 @@
+<head>
+<script>
+    
+navigator.serviceWorker.addEventListener('message', event => {
+    if (event.data != "echo")
+        return;
+
+    navigator.serviceWorker.getRegistration().then(function(registration) {
+        registration.active.postMessage("echo back");
+    });
+});
+
+</script>
+</head>
+<body>
+</body>

Added: branches/safari-614.1.8-branch/LayoutTests/http/tests/workers/service/resources/shownotification-openwindow-worker.js (0 => 291985)


--- branches/safari-614.1.8-branch/LayoutTests/http/tests/workers/service/resources/shownotification-openwindow-worker.js	                        (rev 0)
+++ branches/safari-614.1.8-branch/LayoutTests/http/tests/workers/service/resources/shownotification-openwindow-worker.js	2022-03-28 20:29:35 UTC (rev 291985)
@@ -0,0 +1,108 @@
+
+let messageClients = async function(msg) { 
+    const allClients = await clients.matchAll({
+        includeUncontrolled: true
+    });
+
+    for (const client of allClients)
+        client.postMessage(msg);
+}
+
+// Try to open a new window now.
+// It should fail due to lack of user gesture
+clients.openWindow('http://127.0.0.1:8000/workers/service/resources/openwindow-client.html').then(async function(client) {
+    await messageClients("Opening a window client without a user gesture SUCCEEDED. It should've failed.");
+}).catch(async function(error) {
+    await messageClients("gotUserGestureFail");
+});
+
+self.addEventListener('notificationclick', async function(event) {
+    await messageClients("clicked");
+    event.notification.close();
+
+    // Should fail because about:blank is not an allowable URL
+    clients.openWindow('about:blank').then(async function(client) {
+        await messageClients("Opening a window client to about:blank SUCCEEDED. It should've failed.");
+    }).catch(async function(error) {
+        await messageClients("gotAboutBlankFail");
+    });
+
+    // This successfully loads the openwindow-client.html resource, but the origin is different, therefore the serviceworker
+    // should NOT get a WindowClient
+    clients.openWindow('http://localhost:8000/workers/service/resources/openwindow-client.html').then(async function(client) {
+        if (client == null)
+            await messageClients("gotSuccessfulNullClient")
+        else
+            await messageClients("Got a WindowClient when we were *not* expecting to");
+    }).catch(async function(error) {
+        await messageClients("Expected a resolved promise with a null window client. Promise rejected instead");
+    });
+
+    clients.openWindow('http://127.0.0.1:8000/workers/service/resources/openwindow-client.html').then(function(client) {
+        client.postMessage("echo");
+    });
+});
+
+self.addEventListener('notificationclose', async function(event) {
+    await messageClients("closed");
+});
+
+async function tryShow(message)
+{
+    var title, body, tag;
+    var components = message.split('|');
+
+    if (components.length == 1) {
+        title = "This is a notification";        
+    } else {
+        title = components[1];
+        body = components[2];
+        tag = components[3];
+    }
+    
+    try {
+        await registration.showNotification(title, {
+            body: body,
+            tag: tag
+        });
+    } catch(error) {
+        await messageClients("showFailed");
+        return;
+    }
+    
+    await messageClients("shown");
+}
+
+var seenNotes = new Set();
+
+async function getNotes(message)
+{
+    var tag = undefined;
+    var components = message.split('|');
+    if (components.length == 2)
+        tag = components[1];
+
+    var notifications = await registration.getNotifications({ tag: tag });
+    var reply = "gotnotes|There are " + notifications.length + " notifications|";
+
+    for (notification of notifications) {
+        if (seenNotes.has(notification))
+            messageClients("Saw the same notifcation twice through getNotifications(), this should not happen");
+        seenNotes.add(notification)
+        
+        reply += "Title: " + notification.title + "|";
+        reply += "Body: " + notification.body + "|";
+        reply += "Tag: " + notification.tag + "|";
+    }
+    await messageClients(reply);
+}
+
+self.addEventListener('message', async function(event) {
+    var messageName = event.data.split('|')[0];
+    if (messageName == "tryshow")
+        await tryShow(event.data);
+    if (messageName == "getnotes")
+        await getNotes(event.data);
+    if (messageName == "echo back")
+        await messageClients("gotNewClient");
+});

Modified: branches/safari-614.1.8-branch/LayoutTests/platform/gtk/TestExpectations (291984 => 291985)


--- branches/safari-614.1.8-branch/LayoutTests/platform/gtk/TestExpectations	2022-03-28 20:17:35 UTC (rev 291984)
+++ branches/safari-614.1.8-branch/LayoutTests/platform/gtk/TestExpectations	2022-03-28 20:29:35 UTC (rev 291985)
@@ -717,6 +717,7 @@
 webkit.org/b/175419 imported/w3c/web-platform-tests/service-workers/cache-storage/serviceworker/cache-storage-match.https.html [ Skip ]
 webkit.org/b/175419 imported/w3c/web-platform-tests/service-workers/cache-storage/serviceworker/credentials.https.html [ Skip ]
 webkit.org/b/175419 [ Release ] http/tests/workers/service/postmessage-after-terminate.https.html [ Pass Failure Timeout ]
+webkit.org/b/175419 http/tests/workers/service/openwindow-from-notification-click.html [ Skip ]
 
 # FIXME: This can't be the right bug number.
 webkit.org/b/175419 imported/w3c/web-platform-tests/fetch/api/abort/serviceworker-intercepted.https.html [ Failure ]

Modified: branches/safari-614.1.8-branch/Source/WTF/ChangeLog (291984 => 291985)


--- branches/safari-614.1.8-branch/Source/WTF/ChangeLog	2022-03-28 20:17:35 UTC (rev 291984)
+++ branches/safari-614.1.8-branch/Source/WTF/ChangeLog	2022-03-28 20:29:35 UTC (rev 291985)
@@ -1,3 +1,165 @@
+2022-03-28  Russell Epstein  <repst...@apple.com>
+
+        Cherry-pick r291979. rdar://problem/90616651
+
+    Support ServiceWorkerClients.openWindow.
+    <rdar://90616651> and https://bugs.webkit.org/show_bug.cgi?id=238400
+    
+    Reviewed by Youenn Fablet.
+    Source/WebCore:
+    
+    Test: http/tests/workers/service/openwindow-from-notification-click.html
+    
+    * dom/Document.cpp:
+    (WebCore::Document::pageID const):
+    
+    * page/ClientOrigin.h:
+    (WebCore::ClientOrigin::loggingString const):
+    
+    * workers/service/ServiceWorkerClientData.cpp:
+    (WebCore::ServiceWorkerClientData::isolatedCopy const):
+    (WebCore::ServiceWorkerClientData::isolatedCopy):
+    (WebCore::ServiceWorkerClientData::from):
+    
+    * workers/service/ServiceWorkerClientData.h:
+    (WebCore::ServiceWorkerClientData::encode const):
+    (WebCore::ServiceWorkerClientData::decode):
+    
+    * workers/service/ServiceWorkerClients.cpp:
+    (WebCore::matchWindowWithPageIdentifier):
+    (WebCore::ServiceWorkerClients::openWindow):
+    
+    * workers/service/context/SWContextManager.h:
+    * workers/service/server/SWServerToContextConnection.h:
+    * workers/service/server/SWServerWorker.h:
+    
+    Source/WebKit:
+    
+    This API asks the browser to asynchronously open a new tab to a URL then resolve
+    a promise with the new WindowClient representing that tab.
+    
+    From a WebCore/WebKit standpoint, implementing this was mostly straightforward.
+    1 - A plumbing exercise (thread hopping and IPC'ing the message and its reply around)
+    2 - Implmenting a new delegate method for the hosting app to create the requested WKWebView
+    
+    The delegate method was interesting. Normally this is the type of thing that'd go to the
+    WKUIDelegate but that requires there to be a WKWebView, and service workers can be running
+    without any web views.
+    
+    Fortunately we already had a WKWebsiteDataStore delegate SPI, and service workers *do* always
+    have an associated website data store they're running under.
+    
+    Once the app gives the new web view back to WebKit, we record its PageIdentifier in the reply.
+    
+    Once the reply makes its way all the way back to the ServiceWorker process and on the
+    ServiceWorker thread, we do a client match and cross check with that PageIdentifier to make
+    sure we're resolving the promise with the correct WindowClient.
+    
+    If there's no matched clients, then the view is either already gone or it has navigated away
+    to a non-applicable URL.
+    
+    Same if there are matched clients, but they don't match the specified PageIdentifier.
+    
+    A straight forward layouttest completes the task.
+    
+    * NetworkProcess/ServiceWorker/WebSWServerConnection.cpp:
+    (WebKit::WebSWServerConnection::controlClient):
+    
+    * NetworkProcess/ServiceWorker/WebSWServerToContextConnection.cpp:
+    (WebKit::WebSWServerToContextConnection::openWindow):
+    * NetworkProcess/ServiceWorker/WebSWServerToContextConnection.h:
+    * NetworkProcess/ServiceWorker/WebSWServerToContextConnection.messages.in:
+    
+    * UIProcess/API/Cocoa/WKWebsiteDataStore.mm:
+    (-[WKWebsiteDataStore set_delegate:]):
+    * UIProcess/API/Cocoa/_WKWebsiteDataStoreDelegate.h:
+    
+    * UIProcess/Network/NetworkProcessProxy.cpp:
+    (WebKit::NetworkProcessProxy::openWindowFromServiceWorker):
+    * UIProcess/Network/NetworkProcessProxy.h:
+    * UIProcess/Network/NetworkProcessProxy.messages.in:
+    
+    * UIProcess/WebPageProxy.cpp:
+    (WebKit::WebPageProxy::didFailProvisionalLoadForFrameShared):
+    (WebKit::WebPageProxy::callLoadCompletionHandlersIfNecessary):
+    (WebKit::WebPageProxy::didFinishLoadForFrame):
+    (WebKit::WebPageProxy::didFailLoadForFrame):
+    (WebKit::WebPageProxy::resetState):
+    (WebKit::WebPageProxy::callServiceWorkerLaunchCompletionHandlerIfNecessary): Deleted.
+    * UIProcess/WebPageProxy.h:
+    
+    * UIProcess/WebsiteData/WebsiteDataStore.cpp:
+    (WebKit::WebsiteDataStore::openWindowFromServiceWorker):
+    * UIProcess/WebsiteData/WebsiteDataStore.h:
+    
+    * UIProcess/WebsiteData/WebsiteDataStoreClient.h:
+    (WebKit::WebsiteDataStoreClient::openWindowFromServiceWorker):
+    
+    * WebProcess/Notifications/WebNotificationManager.cpp:
+    (WebKit::WebNotificationManager::show):
+    (WebKit::WebNotificationManager::didShowNotification):
+    (WebKit::WebNotificationManager::didClickNotification):
+    
+    * WebProcess/Storage/WebSWContextManagerConnection.cpp:
+    (WebKit::WebSWContextManagerConnection::openWindow):
+    * WebProcess/Storage/WebSWContextManagerConnection.h:
+    
+    Source/WTF:
+    
+    * wtf/HashTable.h:
+    (WTF::KeyTraits>::inlineLookup): Relax this value size requirement for now.
+    The required refactoring is best left as a seperate task with a seperate patch.
+    
+    Tools:
+    
+    Implement the new delegate to create the new view.
+    
+    * WebKitTestRunner/TestController.cpp:
+    (WTR::TestController::createOtherPage):
+    (WTR::TestController::createOtherPlatformWebView):
+    * WebKitTestRunner/TestController.h:
+    
+    * WebKitTestRunner/cocoa/TestControllerCocoa.mm:
+    (WTR::TestController::platformCreateOtherPage):
+    * WebKitTestRunner/cocoa/TestWebsiteDataStoreDelegate.mm:
+    (-[TestWebsiteDataStoreDelegate websiteDataStore:openWindow:fromServiceWorkerOrigin:completionHandler:]):
+    
+    LayoutTests:
+    
+    WKTR knows how to openWindow() now.
+    
+    So test:
+    - The success case
+    - Failure due to a disallowed URL
+    - Failure due to a lack of a related user gesture.
+    
+    * http/tests/workers/service/openwindow-from-notification-click-expected.txt: Added.
+    * http/tests/workers/service/openwindow-from-notification-click.html: Added.
+    * http/tests/workers/service/resources/openwindow-client.html: Added.
+    * http/tests/workers/service/resources/shownotification-openwindow-worker.js: Added.
+    (async const):
+    (let.messageClients):
+    (clients.openWindow.string_appeared_here.then.async client):
+    (catch.async error):
+    (async event):
+    (async tryShow):
+    (async getNotes):
+    * platform/gtk/TestExpectations:
+    
+    
+    git-svn-id: https://svn.webkit.org/repository/webkit/trunk@291979 268f45cc-cd09-0410-ab3c-d52691b4dbfc
+
+    2022-03-28  Brady Eidson  <beid...@apple.com>
+
+            Support ServiceWorkerClients.openWindow.
+            <rdar://90616651> and https://bugs.webkit.org/show_bug.cgi?id=238400
+
+            Reviewed by Youenn Fablet.
+
+            * wtf/HashTable.h:
+            (WTF::KeyTraits>::inlineLookup): Relax this value size requirement for now.
+            The required refactoring is best left as a seperate task with a seperate patch.
+
 2022-03-27  Alexander Mikhaylenko  <al...@gnome.org>
 
         [GTK][WPE] Support CSS accent-color

Modified: branches/safari-614.1.8-branch/Source/WTF/wtf/HashTable.h (291984 => 291985)


--- branches/safari-614.1.8-branch/Source/WTF/wtf/HashTable.h	2022-03-28 20:17:35 UTC (rev 291984)
+++ branches/safari-614.1.8-branch/Source/WTF/wtf/HashTable.h	2022-03-28 20:29:35 UTC (rev 291985)
@@ -681,7 +681,7 @@
     template<typename HashTranslator, typename T>
     ALWAYS_INLINE auto HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::inlineLookup(const T& key) -> ValueType*
     {
-        static_assert(sizeof(Value) <= 128, "Your HashTable types are too big to efficiently move when rehashing.  Consider using UniqueRef instead");
+        static_assert(sizeof(Value) <= 150, "Your HashTable types are too big to efficiently move when rehashing.  Consider using UniqueRef instead");
         checkKey<HashTranslator>(key);
 
         unsigned k = 0;

Modified: branches/safari-614.1.8-branch/Source/WebCore/ChangeLog (291984 => 291985)


--- branches/safari-614.1.8-branch/Source/WebCore/ChangeLog	2022-03-28 20:17:35 UTC (rev 291984)
+++ branches/safari-614.1.8-branch/Source/WebCore/ChangeLog	2022-03-28 20:29:35 UTC (rev 291985)
@@ -1,3 +1,186 @@
+2022-03-28  Russell Epstein  <repst...@apple.com>
+
+        Cherry-pick r291979. rdar://problem/90616651
+
+    Support ServiceWorkerClients.openWindow.
+    <rdar://90616651> and https://bugs.webkit.org/show_bug.cgi?id=238400
+    
+    Reviewed by Youenn Fablet.
+    Source/WebCore:
+    
+    Test: http/tests/workers/service/openwindow-from-notification-click.html
+    
+    * dom/Document.cpp:
+    (WebCore::Document::pageID const):
+    
+    * page/ClientOrigin.h:
+    (WebCore::ClientOrigin::loggingString const):
+    
+    * workers/service/ServiceWorkerClientData.cpp:
+    (WebCore::ServiceWorkerClientData::isolatedCopy const):
+    (WebCore::ServiceWorkerClientData::isolatedCopy):
+    (WebCore::ServiceWorkerClientData::from):
+    
+    * workers/service/ServiceWorkerClientData.h:
+    (WebCore::ServiceWorkerClientData::encode const):
+    (WebCore::ServiceWorkerClientData::decode):
+    
+    * workers/service/ServiceWorkerClients.cpp:
+    (WebCore::matchWindowWithPageIdentifier):
+    (WebCore::ServiceWorkerClients::openWindow):
+    
+    * workers/service/context/SWContextManager.h:
+    * workers/service/server/SWServerToContextConnection.h:
+    * workers/service/server/SWServerWorker.h:
+    
+    Source/WebKit:
+    
+    This API asks the browser to asynchronously open a new tab to a URL then resolve
+    a promise with the new WindowClient representing that tab.
+    
+    From a WebCore/WebKit standpoint, implementing this was mostly straightforward.
+    1 - A plumbing exercise (thread hopping and IPC'ing the message and its reply around)
+    2 - Implmenting a new delegate method for the hosting app to create the requested WKWebView
+    
+    The delegate method was interesting. Normally this is the type of thing that'd go to the
+    WKUIDelegate but that requires there to be a WKWebView, and service workers can be running
+    without any web views.
+    
+    Fortunately we already had a WKWebsiteDataStore delegate SPI, and service workers *do* always
+    have an associated website data store they're running under.
+    
+    Once the app gives the new web view back to WebKit, we record its PageIdentifier in the reply.
+    
+    Once the reply makes its way all the way back to the ServiceWorker process and on the
+    ServiceWorker thread, we do a client match and cross check with that PageIdentifier to make
+    sure we're resolving the promise with the correct WindowClient.
+    
+    If there's no matched clients, then the view is either already gone or it has navigated away
+    to a non-applicable URL.
+    
+    Same if there are matched clients, but they don't match the specified PageIdentifier.
+    
+    A straight forward layouttest completes the task.
+    
+    * NetworkProcess/ServiceWorker/WebSWServerConnection.cpp:
+    (WebKit::WebSWServerConnection::controlClient):
+    
+    * NetworkProcess/ServiceWorker/WebSWServerToContextConnection.cpp:
+    (WebKit::WebSWServerToContextConnection::openWindow):
+    * NetworkProcess/ServiceWorker/WebSWServerToContextConnection.h:
+    * NetworkProcess/ServiceWorker/WebSWServerToContextConnection.messages.in:
+    
+    * UIProcess/API/Cocoa/WKWebsiteDataStore.mm:
+    (-[WKWebsiteDataStore set_delegate:]):
+    * UIProcess/API/Cocoa/_WKWebsiteDataStoreDelegate.h:
+    
+    * UIProcess/Network/NetworkProcessProxy.cpp:
+    (WebKit::NetworkProcessProxy::openWindowFromServiceWorker):
+    * UIProcess/Network/NetworkProcessProxy.h:
+    * UIProcess/Network/NetworkProcessProxy.messages.in:
+    
+    * UIProcess/WebPageProxy.cpp:
+    (WebKit::WebPageProxy::didFailProvisionalLoadForFrameShared):
+    (WebKit::WebPageProxy::callLoadCompletionHandlersIfNecessary):
+    (WebKit::WebPageProxy::didFinishLoadForFrame):
+    (WebKit::WebPageProxy::didFailLoadForFrame):
+    (WebKit::WebPageProxy::resetState):
+    (WebKit::WebPageProxy::callServiceWorkerLaunchCompletionHandlerIfNecessary): Deleted.
+    * UIProcess/WebPageProxy.h:
+    
+    * UIProcess/WebsiteData/WebsiteDataStore.cpp:
+    (WebKit::WebsiteDataStore::openWindowFromServiceWorker):
+    * UIProcess/WebsiteData/WebsiteDataStore.h:
+    
+    * UIProcess/WebsiteData/WebsiteDataStoreClient.h:
+    (WebKit::WebsiteDataStoreClient::openWindowFromServiceWorker):
+    
+    * WebProcess/Notifications/WebNotificationManager.cpp:
+    (WebKit::WebNotificationManager::show):
+    (WebKit::WebNotificationManager::didShowNotification):
+    (WebKit::WebNotificationManager::didClickNotification):
+    
+    * WebProcess/Storage/WebSWContextManagerConnection.cpp:
+    (WebKit::WebSWContextManagerConnection::openWindow):
+    * WebProcess/Storage/WebSWContextManagerConnection.h:
+    
+    Source/WTF:
+    
+    * wtf/HashTable.h:
+    (WTF::KeyTraits>::inlineLookup): Relax this value size requirement for now.
+    The required refactoring is best left as a seperate task with a seperate patch.
+    
+    Tools:
+    
+    Implement the new delegate to create the new view.
+    
+    * WebKitTestRunner/TestController.cpp:
+    (WTR::TestController::createOtherPage):
+    (WTR::TestController::createOtherPlatformWebView):
+    * WebKitTestRunner/TestController.h:
+    
+    * WebKitTestRunner/cocoa/TestControllerCocoa.mm:
+    (WTR::TestController::platformCreateOtherPage):
+    * WebKitTestRunner/cocoa/TestWebsiteDataStoreDelegate.mm:
+    (-[TestWebsiteDataStoreDelegate websiteDataStore:openWindow:fromServiceWorkerOrigin:completionHandler:]):
+    
+    LayoutTests:
+    
+    WKTR knows how to openWindow() now.
+    
+    So test:
+    - The success case
+    - Failure due to a disallowed URL
+    - Failure due to a lack of a related user gesture.
+    
+    * http/tests/workers/service/openwindow-from-notification-click-expected.txt: Added.
+    * http/tests/workers/service/openwindow-from-notification-click.html: Added.
+    * http/tests/workers/service/resources/openwindow-client.html: Added.
+    * http/tests/workers/service/resources/shownotification-openwindow-worker.js: Added.
+    (async const):
+    (let.messageClients):
+    (clients.openWindow.string_appeared_here.then.async client):
+    (catch.async error):
+    (async event):
+    (async tryShow):
+    (async getNotes):
+    * platform/gtk/TestExpectations:
+    
+    
+    git-svn-id: https://svn.webkit.org/repository/webkit/trunk@291979 268f45cc-cd09-0410-ab3c-d52691b4dbfc
+
+    2022-03-28  Brady Eidson  <beid...@apple.com>
+
+            Support ServiceWorkerClients.openWindow.
+            <rdar://90616651> and https://bugs.webkit.org/show_bug.cgi?id=238400
+
+            Reviewed by Youenn Fablet.
+
+            Test: http/tests/workers/service/openwindow-from-notification-click.html
+
+            * dom/Document.cpp:
+            (WebCore::Document::pageID const):
+
+            * page/ClientOrigin.h:
+            (WebCore::ClientOrigin::loggingString const):
+
+            * workers/service/ServiceWorkerClientData.cpp:
+            (WebCore::ServiceWorkerClientData::isolatedCopy const):
+            (WebCore::ServiceWorkerClientData::isolatedCopy):
+            (WebCore::ServiceWorkerClientData::from):
+
+            * workers/service/ServiceWorkerClientData.h:
+            (WebCore::ServiceWorkerClientData::encode const):
+            (WebCore::ServiceWorkerClientData::decode):
+
+            * workers/service/ServiceWorkerClients.cpp:
+            (WebCore::matchWindowWithPageIdentifier):
+            (WebCore::ServiceWorkerClients::openWindow):
+
+            * workers/service/context/SWContextManager.h:
+            * workers/service/server/SWServerToContextConnection.h:
+            * workers/service/server/SWServerWorker.h:
+
 2022-03-27  Matt Woodrow  <mattwood...@apple.com>
 
         Use the sizing algorithm's available size to compute grid gap.

Modified: branches/safari-614.1.8-branch/Source/WebCore/dom/Document.cpp (291984 => 291985)


--- branches/safari-614.1.8-branch/Source/WebCore/dom/Document.cpp	2022-03-28 20:17:35 UTC (rev 291984)
+++ branches/safari-614.1.8-branch/Source/WebCore/dom/Document.cpp	2022-03-28 20:29:35 UTC (rev 291985)
@@ -8408,7 +8408,7 @@
     
 std::optional<PageIdentifier> Document::pageID() const
 {
-    return m_frame->loader().pageID();
+    return m_frame ? m_frame->loader().pageID() : std::nullopt;
 }
 
 std::optional<FrameIdentifier> Document::frameID() const

Modified: branches/safari-614.1.8-branch/Source/WebCore/page/ClientOrigin.h (291984 => 291985)


--- branches/safari-614.1.8-branch/Source/WebCore/page/ClientOrigin.h	2022-03-28 20:17:35 UTC (rev 291984)
+++ branches/safari-614.1.8-branch/Source/WebCore/page/ClientOrigin.h	2022-03-28 20:29:35 UTC (rev 291985)
@@ -50,6 +50,8 @@
 
     SecurityOriginData topOrigin;
     SecurityOriginData clientOrigin;
+
+    String loggingString() const { return makeString(topOrigin.toString(), "-", clientOrigin.toString()); }
 };
 
 inline void add(Hasher& hasher, const ClientOrigin& origin)

Modified: branches/safari-614.1.8-branch/Source/WebCore/workers/service/ServiceWorkerClientData.cpp (291984 => 291985)


--- branches/safari-614.1.8-branch/Source/WebCore/workers/service/ServiceWorkerClientData.cpp	2022-03-28 20:17:35 UTC (rev 291984)
+++ branches/safari-614.1.8-branch/Source/WebCore/workers/service/ServiceWorkerClientData.cpp	2022-03-28 20:29:35 UTC (rev 291985)
@@ -58,12 +58,12 @@
 
 ServiceWorkerClientData ServiceWorkerClientData::isolatedCopy() const &
 {
-    return { identifier, type, frameType, url.isolatedCopy(), lastNavigationWasAppInitiated, isVisible, isFocused, focusOrder };
+    return { identifier, type, frameType, url.isolatedCopy(), pageIdentifier, lastNavigationWasAppInitiated, isVisible, isFocused, focusOrder };
 }
 
 ServiceWorkerClientData ServiceWorkerClientData::isolatedCopy() &&
 {
-    return { identifier, type, frameType, WTFMove(url).isolatedCopy(), lastNavigationWasAppInitiated, isVisible, isFocused, focusOrder };
+    return { identifier, type, frameType, WTFMove(url).isolatedCopy(), pageIdentifier, lastNavigationWasAppInitiated, isVisible, isFocused, focusOrder };
 }
 
 ServiceWorkerClientData ServiceWorkerClientData::from(ScriptExecutionContext& context)
@@ -78,7 +78,9 @@
         context.identifier(),
         isDocument ? ServiceWorkerClientType::Window : ServiceWorkerClientType::Worker,
         toServiceWorkerClientFrameType(context),
-        document.creationURL(), lastNavigationWasAppInitiated,
+        document.creationURL(),
+        document.pageID(),
+        lastNavigationWasAppInitiated,
         !document.hidden(),
         document.hasFocus(),
         0

Modified: branches/safari-614.1.8-branch/Source/WebCore/workers/service/ServiceWorkerClientData.h (291984 => 291985)


--- branches/safari-614.1.8-branch/Source/WebCore/workers/service/ServiceWorkerClientData.h	2022-03-28 20:17:35 UTC (rev 291984)
+++ branches/safari-614.1.8-branch/Source/WebCore/workers/service/ServiceWorkerClientData.h	2022-03-28 20:29:35 UTC (rev 291985)
@@ -27,6 +27,7 @@
 
 #if ENABLE(SERVICE_WORKER)
 
+#include "PageIdentifier.h"
 #include "ProcessQualified.h"
 #include "ScriptExecutionContextIdentifier.h"
 #include "ServiceWorkerClientType.h"
@@ -45,6 +46,7 @@
     ServiceWorkerClientType type;
     ServiceWorkerClientFrameType frameType;
     URL url;
+    std::optional<PageIdentifier> pageIdentifier;
     LastNavigationWasAppInitiated lastNavigationWasAppInitiated;
     bool isVisible { false };
     bool isFocused { false };
@@ -62,7 +64,7 @@
 template<class Encoder>
 void ServiceWorkerClientData::encode(Encoder& encoder) const
 {
-    encoder << identifier << type << frameType << url << lastNavigationWasAppInitiated << isVisible << isFocused << focusOrder;
+    encoder << identifier << type << frameType << url << pageIdentifier << lastNavigationWasAppInitiated << isVisible << isFocused << focusOrder;
 }
 
 template<class Decoder>
@@ -88,6 +90,11 @@
     if (!url)
         return std::nullopt;
 
+    std::optional<std::optional<PageIdentifier>> pageIdentifier;
+    decoder >> pageIdentifier;
+    if (!pageIdentifier)
+        return std::nullopt;
+
     std::optional<LastNavigationWasAppInitiated> lastNavigationWasAppInitiated;
     decoder >> lastNavigationWasAppInitiated;
     if (!lastNavigationWasAppInitiated)
@@ -108,7 +115,7 @@
     if (!focusOrder)
         return std::nullopt;
 
-    return { { WTFMove(*identifier), WTFMove(*type), WTFMove(*frameType), WTFMove(*url), WTFMove(*lastNavigationWasAppInitiated), WTFMove(*isVisible), WTFMove(*isFocused), WTFMove(*focusOrder) } };
+    return { { WTFMove(*identifier), WTFMove(*type), WTFMove(*frameType), WTFMove(*url), WTFMove(*pageIdentifier), WTFMove(*lastNavigationWasAppInitiated), WTFMove(*isVisible), WTFMove(*isFocused), WTFMove(*focusOrder) } };
 }
 
 using ServiceWorkerClientsMatchAllCallback = CompletionHandler<void(Vector<ServiceWorkerClientData>&&)>;

Modified: branches/safari-614.1.8-branch/Source/WebCore/workers/service/ServiceWorkerClients.cpp (291984 => 291985)


--- branches/safari-614.1.8-branch/Source/WebCore/workers/service/ServiceWorkerClients.cpp	2022-03-28 20:17:35 UTC (rev 291984)
+++ branches/safari-614.1.8-branch/Source/WebCore/workers/service/ServiceWorkerClients.cpp	2022-03-28 20:29:35 UTC (rev 291985)
@@ -90,12 +90,78 @@
     });
 }
 
-void ServiceWorkerClients::openWindow(ScriptExecutionContext&, const String& url, Ref<DeferredPromise>&& promise)
+static void matchWindowWithPageIdentifier(ServiceWorkerIdentifier serviceWorkerIdentifier, PageIdentifier pageIdentifier, CompletionHandler<void(ServiceWorkerGlobalScope&, std::optional<ServiceWorkerClientData>)>&& callback)
 {
-    UNUSED_PARAM(url);
-    promise->reject(Exception { NotSupportedError, "clients.openWindow() is not yet supported"_s });
+    callOnMainThread([serviceWorkerIdentifier, pageIdentifier, callback = WTFMove(callback)] () mutable {
+        auto connection = SWContextManager::singleton().connection();
+        auto options = ServiceWorkerClientQueryOptions { true, ServiceWorkerClientType::Window };
+        connection->matchAll(serviceWorkerIdentifier, options, [serviceWorkerIdentifier, pageIdentifier, callback = WTFMove(callback)] (Vector<ServiceWorkerClientData>&& clientsData) mutable {
+            SWContextManager::singleton().postTaskToServiceWorker(serviceWorkerIdentifier, [pageIdentifier, callback = WTFMove(callback), clientsData = crossThreadCopy(WTFMove(clientsData))] (auto& scope) mutable {
+                for (auto& data : clientsData) {
+                    if (data.pageIdentifier == pageIdentifier) {
+                        callback(scope, data);
+                        return;
+                    }
+                }
+
+                callback(scope, std::nullopt);
+            });
+        });
+    });
 }
 
+void ServiceWorkerClients::openWindow(ScriptExecutionContext& context, const String& urlString, Ref<DeferredPromise>&& promise)
+{
+    LOG(ServiceWorker, "WebProcess %i service worker calling openWindow to URL %s", getpid(), urlString.utf8().data());
+
+    auto serviceWorkerIdentifier = downcast<ServiceWorkerGlobalScope>(context).thread().identifier();
+    auto url = ""
+
+    if (context.settingsValues().serviceWorkersUserGestureEnabled && !downcast<ServiceWorkerGlobalScope>(context).isProcessingUserGesture()) {
+        promise->reject(Exception { InvalidAccessError, "ServiceWorkerClients.openWindow() requires a user gesture"_s });
+        return;
+    }
+
+    if (!url.isValid()) {
+        promise->reject(Exception { TypeError, makeString("URL string ", urlString, " cannot successfully be parsed"_s) });
+        return;
+    }
+
+    if (url.protocolIsAbout()) {
+        promise->reject(Exception { TypeError, makeString("ServiceWorkerClients.openWindow() cannot be called with URL "_s, url.string()) });
+        return;
+    }
+
+    callOnMainThread([promiseIdentifier = addPendingPromise(WTFMove(promise)), serviceWorkerIdentifier, url = "" () mutable {
+        auto connection = SWContextManager::singleton().connection();
+        connection->openWindow(serviceWorkerIdentifier, url.string(), [promiseIdentifier, serviceWorkerIdentifier] (std::optional<PageIdentifier>&& pageIdentifier) mutable {
+            SWContextManager::singleton().postTaskToServiceWorker(serviceWorkerIdentifier, [promiseIdentifier, pageIdentifier = WTFMove(pageIdentifier), serviceWorkerIdentifier] (ServiceWorkerGlobalScope& scope) mutable {
+                LOG(ServiceWorker, "WebProcess %i finished ServiceWorkerClients::openWindow call. Resulting page identifier is %s", getpid(), pageIdentifier ? pageIdentifier->loggingString().utf8().data() : "<NONE>");
+
+                if (!pageIdentifier) {
+                    if (auto promise = scope.clients().takePendingPromise(promiseIdentifier))
+                        promise->resolveWithJSValue(JSC::jsNull());
+                    return;
+                }
+
+                matchWindowWithPageIdentifier(serviceWorkerIdentifier, *pageIdentifier, [promiseIdentifier] (auto& scope, std::optional<ServiceWorkerClientData> clientData) mutable {
+                    auto promise = scope.clients().takePendingPromise(promiseIdentifier);
+                    if (!promise)
+                        return;
+
+                    if (!clientData) {
+                        promise->resolveWithJSValue(JSC::jsNull());
+                        return;
+                    }
+
+                    auto client = ServiceWorkerClient::create(scope, WTFMove(*clientData));
+                    promise->template resolve<IDLInterface<ServiceWorkerClient>>(WTFMove(client));
+                });
+            });
+        });
+    });
+}
+
 void ServiceWorkerClients::claim(ScriptExecutionContext& context, Ref<DeferredPromise>&& promise)
 {
     auto serviceWorkerIdentifier = downcast<ServiceWorkerGlobalScope>(context).thread().identifier();

Modified: branches/safari-614.1.8-branch/Source/WebCore/workers/service/context/SWContextManager.h (291984 => 291985)


--- branches/safari-614.1.8-branch/Source/WebCore/workers/service/context/SWContextManager.h	2022-03-28 20:17:35 UTC (rev 291984)
+++ branches/safari-614.1.8-branch/Source/WebCore/workers/service/context/SWContextManager.h	2022-03-28 20:29:35 UTC (rev 291985)
@@ -67,8 +67,8 @@
         virtual void findClientByVisibleIdentifier(ServiceWorkerIdentifier, const String&, FindClientByIdentifierCallback&&) = 0;
         virtual void matchAll(ServiceWorkerIdentifier, const ServiceWorkerClientQueryOptions&, ServiceWorkerClientsMatchAllCallback&&) = 0;
         virtual void claim(ServiceWorkerIdentifier, CompletionHandler<void(ExceptionOr<void>&&)>&&) = 0;
-
         virtual void focus(ScriptExecutionContextIdentifier, CompletionHandler<void(std::optional<WebCore::ServiceWorkerClientData>&&)>&&) = 0;
+        virtual void openWindow(ServiceWorkerIdentifier, const String& url, CompletionHandler<void(std::optional<PageIdentifier>&&)>&&) = 0;
 
         virtual void didFailHeartBeatCheck(ServiceWorkerIdentifier) = 0;
         virtual void setAsInspected(ServiceWorkerIdentifier, bool) = 0;

Modified: branches/safari-614.1.8-branch/Source/WebCore/workers/service/server/SWServerToContextConnection.h (291984 => 291985)


--- branches/safari-614.1.8-branch/Source/WebCore/workers/service/server/SWServerToContextConnection.h	2022-03-28 20:17:35 UTC (rev 291984)
+++ branches/safari-614.1.8-branch/Source/WebCore/workers/service/server/SWServerToContextConnection.h	2022-03-28 20:29:35 UTC (rev 291985)
@@ -82,6 +82,8 @@
     WEBCORE_EXPORT void setAsInspected(ServiceWorkerIdentifier, bool);
     WEBCORE_EXPORT void findClientByVisibleIdentifier(ServiceWorkerIdentifier, const String& clientIdentifier, CompletionHandler<void(std::optional<WebCore::ServiceWorkerClientData>&&)>&&);
 
+    virtual void openWindow(ServiceWorkerIdentifier, const String& urlString, CompletionHandler<void(std::optional<WebCore::PageIdentifier>&&)>&&) = 0;
+
     const RegistrableDomain& registrableDomain() const { return m_registrableDomain; }
     std::optional<ScriptExecutionContextIdentifier> serviceWorkerPageIdentifier() const { return m_serviceWorkerPageIdentifier; }
 

Modified: branches/safari-614.1.8-branch/Source/WebCore/workers/service/server/SWServerWorker.h (291984 => 291985)


--- branches/safari-614.1.8-branch/Source/WebCore/workers/service/server/SWServerWorker.h	2022-03-28 20:17:35 UTC (rev 291984)
+++ branches/safari-614.1.8-branch/Source/WebCore/workers/service/server/SWServerWorker.h	2022-03-28 20:29:35 UTC (rev 291985)
@@ -117,7 +117,7 @@
     const ServiceWorkerData& data() const { return m_data; }
     ServiceWorkerContextData contextData() const;
 
-    const ClientOrigin& origin() const;
+    WEBCORE_EXPORT const ClientOrigin& origin() const;
     const RegistrableDomain& registrableDomain() const { return m_registrableDomain; }
     WEBCORE_EXPORT std::optional<ScriptExecutionContextIdentifier> serviceWorkerPageIdentifier() const;
 

Modified: branches/safari-614.1.8-branch/Source/WebKit/ChangeLog (291984 => 291985)


--- branches/safari-614.1.8-branch/Source/WebKit/ChangeLog	2022-03-28 20:17:35 UTC (rev 291984)
+++ branches/safari-614.1.8-branch/Source/WebKit/ChangeLog	2022-03-28 20:29:35 UTC (rev 291985)
@@ -1,3 +1,230 @@
+2022-03-28  Russell Epstein  <repst...@apple.com>
+
+        Cherry-pick r291979. rdar://problem/90616651
+
+    Support ServiceWorkerClients.openWindow.
+    <rdar://90616651> and https://bugs.webkit.org/show_bug.cgi?id=238400
+    
+    Reviewed by Youenn Fablet.
+    Source/WebCore:
+    
+    Test: http/tests/workers/service/openwindow-from-notification-click.html
+    
+    * dom/Document.cpp:
+    (WebCore::Document::pageID const):
+    
+    * page/ClientOrigin.h:
+    (WebCore::ClientOrigin::loggingString const):
+    
+    * workers/service/ServiceWorkerClientData.cpp:
+    (WebCore::ServiceWorkerClientData::isolatedCopy const):
+    (WebCore::ServiceWorkerClientData::isolatedCopy):
+    (WebCore::ServiceWorkerClientData::from):
+    
+    * workers/service/ServiceWorkerClientData.h:
+    (WebCore::ServiceWorkerClientData::encode const):
+    (WebCore::ServiceWorkerClientData::decode):
+    
+    * workers/service/ServiceWorkerClients.cpp:
+    (WebCore::matchWindowWithPageIdentifier):
+    (WebCore::ServiceWorkerClients::openWindow):
+    
+    * workers/service/context/SWContextManager.h:
+    * workers/service/server/SWServerToContextConnection.h:
+    * workers/service/server/SWServerWorker.h:
+    
+    Source/WebKit:
+    
+    This API asks the browser to asynchronously open a new tab to a URL then resolve
+    a promise with the new WindowClient representing that tab.
+    
+    From a WebCore/WebKit standpoint, implementing this was mostly straightforward.
+    1 - A plumbing exercise (thread hopping and IPC'ing the message and its reply around)
+    2 - Implmenting a new delegate method for the hosting app to create the requested WKWebView
+    
+    The delegate method was interesting. Normally this is the type of thing that'd go to the
+    WKUIDelegate but that requires there to be a WKWebView, and service workers can be running
+    without any web views.
+    
+    Fortunately we already had a WKWebsiteDataStore delegate SPI, and service workers *do* always
+    have an associated website data store they're running under.
+    
+    Once the app gives the new web view back to WebKit, we record its PageIdentifier in the reply.
+    
+    Once the reply makes its way all the way back to the ServiceWorker process and on the
+    ServiceWorker thread, we do a client match and cross check with that PageIdentifier to make
+    sure we're resolving the promise with the correct WindowClient.
+    
+    If there's no matched clients, then the view is either already gone or it has navigated away
+    to a non-applicable URL.
+    
+    Same if there are matched clients, but they don't match the specified PageIdentifier.
+    
+    A straight forward layouttest completes the task.
+    
+    * NetworkProcess/ServiceWorker/WebSWServerConnection.cpp:
+    (WebKit::WebSWServerConnection::controlClient):
+    
+    * NetworkProcess/ServiceWorker/WebSWServerToContextConnection.cpp:
+    (WebKit::WebSWServerToContextConnection::openWindow):
+    * NetworkProcess/ServiceWorker/WebSWServerToContextConnection.h:
+    * NetworkProcess/ServiceWorker/WebSWServerToContextConnection.messages.in:
+    
+    * UIProcess/API/Cocoa/WKWebsiteDataStore.mm:
+    (-[WKWebsiteDataStore set_delegate:]):
+    * UIProcess/API/Cocoa/_WKWebsiteDataStoreDelegate.h:
+    
+    * UIProcess/Network/NetworkProcessProxy.cpp:
+    (WebKit::NetworkProcessProxy::openWindowFromServiceWorker):
+    * UIProcess/Network/NetworkProcessProxy.h:
+    * UIProcess/Network/NetworkProcessProxy.messages.in:
+    
+    * UIProcess/WebPageProxy.cpp:
+    (WebKit::WebPageProxy::didFailProvisionalLoadForFrameShared):
+    (WebKit::WebPageProxy::callLoadCompletionHandlersIfNecessary):
+    (WebKit::WebPageProxy::didFinishLoadForFrame):
+    (WebKit::WebPageProxy::didFailLoadForFrame):
+    (WebKit::WebPageProxy::resetState):
+    (WebKit::WebPageProxy::callServiceWorkerLaunchCompletionHandlerIfNecessary): Deleted.
+    * UIProcess/WebPageProxy.h:
+    
+    * UIProcess/WebsiteData/WebsiteDataStore.cpp:
+    (WebKit::WebsiteDataStore::openWindowFromServiceWorker):
+    * UIProcess/WebsiteData/WebsiteDataStore.h:
+    
+    * UIProcess/WebsiteData/WebsiteDataStoreClient.h:
+    (WebKit::WebsiteDataStoreClient::openWindowFromServiceWorker):
+    
+    * WebProcess/Notifications/WebNotificationManager.cpp:
+    (WebKit::WebNotificationManager::show):
+    (WebKit::WebNotificationManager::didShowNotification):
+    (WebKit::WebNotificationManager::didClickNotification):
+    
+    * WebProcess/Storage/WebSWContextManagerConnection.cpp:
+    (WebKit::WebSWContextManagerConnection::openWindow):
+    * WebProcess/Storage/WebSWContextManagerConnection.h:
+    
+    Source/WTF:
+    
+    * wtf/HashTable.h:
+    (WTF::KeyTraits>::inlineLookup): Relax this value size requirement for now.
+    The required refactoring is best left as a seperate task with a seperate patch.
+    
+    Tools:
+    
+    Implement the new delegate to create the new view.
+    
+    * WebKitTestRunner/TestController.cpp:
+    (WTR::TestController::createOtherPage):
+    (WTR::TestController::createOtherPlatformWebView):
+    * WebKitTestRunner/TestController.h:
+    
+    * WebKitTestRunner/cocoa/TestControllerCocoa.mm:
+    (WTR::TestController::platformCreateOtherPage):
+    * WebKitTestRunner/cocoa/TestWebsiteDataStoreDelegate.mm:
+    (-[TestWebsiteDataStoreDelegate websiteDataStore:openWindow:fromServiceWorkerOrigin:completionHandler:]):
+    
+    LayoutTests:
+    
+    WKTR knows how to openWindow() now.
+    
+    So test:
+    - The success case
+    - Failure due to a disallowed URL
+    - Failure due to a lack of a related user gesture.
+    
+    * http/tests/workers/service/openwindow-from-notification-click-expected.txt: Added.
+    * http/tests/workers/service/openwindow-from-notification-click.html: Added.
+    * http/tests/workers/service/resources/openwindow-client.html: Added.
+    * http/tests/workers/service/resources/shownotification-openwindow-worker.js: Added.
+    (async const):
+    (let.messageClients):
+    (clients.openWindow.string_appeared_here.then.async client):
+    (catch.async error):
+    (async event):
+    (async tryShow):
+    (async getNotes):
+    * platform/gtk/TestExpectations:
+    
+    
+    git-svn-id: https://svn.webkit.org/repository/webkit/trunk@291979 268f45cc-cd09-0410-ab3c-d52691b4dbfc
+
+    2022-03-28  Brady Eidson  <beid...@apple.com>
+
+            Support ServiceWorkerClients.openWindow.
+            <rdar://90616651> and https://bugs.webkit.org/show_bug.cgi?id=238400
+
+            Reviewed by Youenn Fablet.
+
+            This API asks the browser to asynchronously open a new tab to a URL then resolve
+            a promise with the new WindowClient representing that tab.
+
+            From a WebCore/WebKit standpoint, implementing this was mostly straightforward.
+            1 - A plumbing exercise (thread hopping and IPC'ing the message and its reply around)
+            2 - Implmenting a new delegate method for the hosting app to create the requested WKWebView
+
+            The delegate method was interesting. Normally this is the type of thing that'd go to the
+            WKUIDelegate but that requires there to be a WKWebView, and service workers can be running
+            without any web views.
+
+            Fortunately we already had a WKWebsiteDataStore delegate SPI, and service workers *do* always
+            have an associated website data store they're running under.
+
+            Once the app gives the new web view back to WebKit, we record its PageIdentifier in the reply.
+
+            Once the reply makes its way all the way back to the ServiceWorker process and on the
+            ServiceWorker thread, we do a client match and cross check with that PageIdentifier to make
+            sure we're resolving the promise with the correct WindowClient.
+
+            If there's no matched clients, then the view is either already gone or it has navigated away
+            to a non-applicable URL.
+
+            Same if there are matched clients, but they don't match the specified PageIdentifier.
+
+            A straight forward layouttest completes the task.
+
+            * NetworkProcess/ServiceWorker/WebSWServerConnection.cpp:
+            (WebKit::WebSWServerConnection::controlClient):
+
+            * NetworkProcess/ServiceWorker/WebSWServerToContextConnection.cpp:
+            (WebKit::WebSWServerToContextConnection::openWindow):
+            * NetworkProcess/ServiceWorker/WebSWServerToContextConnection.h:
+            * NetworkProcess/ServiceWorker/WebSWServerToContextConnection.messages.in:
+
+            * UIProcess/API/Cocoa/WKWebsiteDataStore.mm:
+            (-[WKWebsiteDataStore set_delegate:]):
+            * UIProcess/API/Cocoa/_WKWebsiteDataStoreDelegate.h:
+
+            * UIProcess/Network/NetworkProcessProxy.cpp:
+            (WebKit::NetworkProcessProxy::openWindowFromServiceWorker):
+            * UIProcess/Network/NetworkProcessProxy.h:
+            * UIProcess/Network/NetworkProcessProxy.messages.in:
+
+            * UIProcess/WebPageProxy.cpp:
+            (WebKit::WebPageProxy::didFailProvisionalLoadForFrameShared):
+            (WebKit::WebPageProxy::callLoadCompletionHandlersIfNecessary):
+            (WebKit::WebPageProxy::didFinishLoadForFrame):
+            (WebKit::WebPageProxy::didFailLoadForFrame):
+            (WebKit::WebPageProxy::resetState):
+            (WebKit::WebPageProxy::callServiceWorkerLaunchCompletionHandlerIfNecessary): Deleted.
+            * UIProcess/WebPageProxy.h:
+
+            * UIProcess/WebsiteData/WebsiteDataStore.cpp:
+            (WebKit::WebsiteDataStore::openWindowFromServiceWorker):
+            * UIProcess/WebsiteData/WebsiteDataStore.h:
+
+            * UIProcess/WebsiteData/WebsiteDataStoreClient.h:
+            (WebKit::WebsiteDataStoreClient::openWindowFromServiceWorker):
+
+            * WebProcess/Notifications/WebNotificationManager.cpp:
+            (WebKit::WebNotificationManager::show):
+            (WebKit::WebNotificationManager::didShowNotification):
+            (WebKit::WebNotificationManager::didClickNotification):
+
+            * WebProcess/Storage/WebSWContextManagerConnection.cpp:
+            (WebKit::WebSWContextManagerConnection::openWindow):
+            * WebProcess/Storage/WebSWContextManagerConnection.h:
+
 2022-03-26  Yusuke Suzuki  <ysuz...@apple.com>
 
         Use static_assert instead of COMPILE_ASSERT

Modified: branches/safari-614.1.8-branch/Source/WebKit/NetworkProcess/ServiceWorker/WebSWServerConnection.cpp (291984 => 291985)


--- branches/safari-614.1.8-branch/Source/WebKit/NetworkProcess/ServiceWorker/WebSWServerConnection.cpp	2022-03-28 20:17:35 UTC (rev 291984)
+++ branches/safari-614.1.8-branch/Source/WebKit/NetworkProcess/ServiceWorker/WebSWServerConnection.cpp	2022-03-28 20:29:35 UTC (rev 291985)
@@ -175,7 +175,7 @@
         unregisterServiceWorkerClient(clientIdentifier);
     });
 
-    ServiceWorkerClientData data { clientIdentifier, ServiceWorkerClientType::Window, ServiceWorkerClientFrameType::None, request.url(), request.isAppInitiated() ? WebCore::LastNavigationWasAppInitiated::Yes : WebCore::LastNavigationWasAppInitiated::No };
+    ServiceWorkerClientData data { clientIdentifier, ServiceWorkerClientType::Window, ServiceWorkerClientFrameType::None, request.url(), { }, request.isAppInitiated() ? WebCore::LastNavigationWasAppInitiated::Yes : WebCore::LastNavigationWasAppInitiated::No };
     registerServiceWorkerClient(SecurityOriginData { registration.key().topOrigin() }, WTFMove(data), registration.identifier(), request.httpUserAgent());
 }
 

Modified: branches/safari-614.1.8-branch/Source/WebKit/NetworkProcess/ServiceWorker/WebSWServerToContextConnection.cpp (291984 => 291985)


--- branches/safari-614.1.8-branch/Source/WebKit/NetworkProcess/ServiceWorker/WebSWServerToContextConnection.cpp	2022-03-28 20:17:35 UTC (rev 291984)
+++ branches/safari-614.1.8-branch/Source/WebKit/NetworkProcess/ServiceWorker/WebSWServerToContextConnection.cpp	2022-03-28 20:29:35 UTC (rev 291985)
@@ -157,6 +157,27 @@
     m_connection.networkProcess().parentProcessConnection()->send(Messages::NetworkProcessProxy::TerminateUnresponsiveServiceWorkerProcesses { webProcessIdentifier() }, 0);
 }
 
+void WebSWServerToContextConnection::openWindow(WebCore::ServiceWorkerIdentifier identifier, const String& urlString, CompletionHandler<void(std::optional<WebCore::PageIdentifier>&&)>&& callback)
+{
+    auto* server = this->server();
+    if (!server) {
+        callback(std::nullopt);
+        return;
+    }
+
+    auto* worker = server->workerByID(identifier);
+    if (!worker) {
+        callback(std::nullopt);
+        return;
+    }
+
+    auto innerCallback = [callback = WTFMove(callback)](std::optional<WebCore::PageIdentifier>&& pageIdentifier) mutable {
+        callback(WTFMove(pageIdentifier));
+    };
+
+    m_connection.networkProcess().parentProcessConnection()->sendWithAsyncReply(Messages::NetworkProcessProxy::OpenWindowFromServiceWorker { server->sessionID(), urlString, worker->origin().clientOrigin }, WTFMove(innerCallback));
+}
+
 void WebSWServerToContextConnection::matchAllCompleted(uint64_t requestIdentifier, const Vector<ServiceWorkerClientData>& clientsData)
 {
     send(Messages::WebSWContextManagerConnection::MatchAllCompleted { requestIdentifier, clientsData });

Modified: branches/safari-614.1.8-branch/Source/WebKit/NetworkProcess/ServiceWorker/WebSWServerToContextConnection.h (291984 => 291985)


--- branches/safari-614.1.8-branch/Source/WebKit/NetworkProcess/ServiceWorker/WebSWServerToContextConnection.h	2022-03-28 20:17:35 UTC (rev 291984)
+++ branches/safari-614.1.8-branch/Source/WebKit/NetworkProcess/ServiceWorker/WebSWServerToContextConnection.h	2022-03-28 20:29:35 UTC (rev 291985)
@@ -102,6 +102,7 @@
 
     void connectionIsNoLongerNeeded() final;
     void terminateDueToUnresponsiveness() final;
+    void openWindow(WebCore::ServiceWorkerIdentifier, const String& urlString, CompletionHandler<void(std::optional<WebCore::PageIdentifier>&&)>&&) final;
 
     void connectionClosed();
 

Modified: branches/safari-614.1.8-branch/Source/WebKit/NetworkProcess/ServiceWorker/WebSWServerToContextConnection.messages.in (291984 => 291985)


--- branches/safari-614.1.8-branch/Source/WebKit/NetworkProcess/ServiceWorker/WebSWServerToContextConnection.messages.in	2022-03-28 20:17:35 UTC (rev 291984)
+++ branches/safari-614.1.8-branch/Source/WebKit/NetworkProcess/ServiceWorker/WebSWServerToContextConnection.messages.in	2022-03-28 20:29:35 UTC (rev 291985)
@@ -40,6 +40,8 @@
     PostMessageToServiceWorkerClient(WebCore::ScriptExecutionContextIdentifier destination, struct WebCore::MessageWithMessagePorts message, WebCore::ServiceWorkerIdentifier source, String sourceOrigin)
     DidFailHeartBeatCheck(WebCore::ServiceWorkerIdentifier identifier)
     SetAsInspected(WebCore::ServiceWorkerIdentifier identifier, bool isInspected)
+
+    OpenWindow(WebCore::ServiceWorkerIdentifier identifier, String urlString) -> (std::optional<WebCore::PageIdentifier> newClientData)
 }
 
 #endif // ENABLE(SERVICE_WORKER)

Modified: branches/safari-614.1.8-branch/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStore.mm (291984 => 291985)


--- branches/safari-614.1.8-branch/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStore.mm	2022-03-28 20:17:35 UTC (rev 291984)
+++ branches/safari-614.1.8-branch/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStore.mm	2022-03-28 20:29:35 UTC (rev 291985)
@@ -48,6 +48,7 @@
 #import "_WKWebsiteDataStoreDelegate.h"
 #import <WebCore/Credential.h>
 #import <WebCore/RegistrationDatabase.h>
+#import <WebCore/ServiceWorkerClientData.h>
 #import <WebCore/WebCoreObjCExtras.h>
 #import <wtf/BlockPtr.h>
 #import <wtf/URL.h>
@@ -56,10 +57,12 @@
 
 class WebsiteDataStoreClient final : public WebKit::WebsiteDataStoreClient {
 public:
-    explicit WebsiteDataStoreClient(id <_WKWebsiteDataStoreDelegate> delegate)
-        : m_delegate(delegate)
+    explicit WebsiteDataStoreClient(WKWebsiteDataStore *dataStore, id<_WKWebsiteDataStoreDelegate> delegate)
+        : m_dataStore(dataStore)
+        , m_delegate(delegate)
         , m_hasRequestStorageSpaceSelector([m_delegate.get() respondsToSelector:@selector(requestStorageSpace: frameOrigin: quota: currentSize: spaceRequired: decisionHandler:)])
         , m_hasAuthenticationChallengeSelector([m_delegate.get() respondsToSelector:@selector(didReceiveAuthenticationChallenge: completionHandler:)])
+        , m_hasOpenWindowSelector([m_delegate.get() respondsToSelector:@selector(websiteDataStore:openWindow:fromServiceWorkerOrigin:completionHandler:)])
     {
     }
 
@@ -104,9 +107,32 @@
         [m_delegate.getAutoreleased() didReceiveAuthenticationChallenge:nsURLChallenge completionHandler:completionHandler.get()];
     }
 
+    void openWindowFromServiceWorker(const String& url, const WebCore::SecurityOriginData& serviceWorkerOrigin, CompletionHandler<void(WebKit::WebPageProxy*)>&& callback)
+    {
+        if (!m_hasOpenWindowSelector || !m_delegate || !m_dataStore) {
+            callback({ });
+            return;
+        }
+
+        auto checker = WebKit::CompletionHandlerCallChecker::create(m_delegate.getAutoreleased(), @selector(websiteDataStore:openWindow:fromServiceWorkerOrigin:completionHandler:));
+        auto completionHandler = makeBlockPtr([callback = WTFMove(callback), checker = WTFMove(checker)](WKWebView *newWebView) mutable {
+            if (checker->completionHandlerHasBeenCalled())
+                return;
+            checker->didCallCompletionHandler();
+
+            callback(newWebView._page.get());
+        });
+
+        auto nsURL = (NSURL *)URL { url };
+        auto apiOrigin = API::SecurityOrigin::create(serviceWorkerOrigin);
+        [m_delegate.getAutoreleased() websiteDataStore:m_dataStore.getAutoreleased() openWindow:nsURL fromServiceWorkerOrigin:wrapper(apiOrigin.get()) completionHandler:completionHandler.get()];
+    }
+
+    WeakObjCPtr<WKWebsiteDataStore> m_dataStore;
     WeakObjCPtr<id <_WKWebsiteDataStoreDelegate> > m_delegate;
     bool m_hasRequestStorageSpaceSelector { false };
     bool m_hasAuthenticationChallengeSelector { false };
+    bool m_hasOpenWindowSelector { false };
 };
 
 @implementation WKWebsiteDataStore
@@ -652,7 +678,7 @@
 - (void)set_delegate:(id <_WKWebsiteDataStoreDelegate>)delegate
 {
     _delegate = delegate;
-    _websiteDataStore->setClient(makeUniqueRef<WebsiteDataStoreClient>(delegate));
+    _websiteDataStore->setClient(makeUniqueRef<WebsiteDataStoreClient>(self, delegate));
 }
 
 - (_WKWebsiteDataStoreConfiguration *)_configuration

Modified: branches/safari-614.1.8-branch/Source/WebKit/UIProcess/API/Cocoa/_WKWebsiteDataStoreDelegate.h (291984 => 291985)


--- branches/safari-614.1.8-branch/Source/WebKit/UIProcess/API/Cocoa/_WKWebsiteDataStoreDelegate.h	2022-03-28 20:17:35 UTC (rev 291984)
+++ branches/safari-614.1.8-branch/Source/WebKit/UIProcess/API/Cocoa/_WKWebsiteDataStoreDelegate.h	2022-03-28 20:29:35 UTC (rev 291985)
@@ -26,6 +26,10 @@
 #import <Foundation/Foundation.h>
 #import <WebKit/WKFoundation.h>
 
+@class WKSecurityOrigin;
+@class WKWebsiteDataStore;
+@class WKWebView;
+
 WK_API_AVAILABLE(macos(10.15), ios(13.0))
 @protocol _WKWebsiteDataStoreDelegate <NSObject>
 
@@ -32,5 +36,5 @@
 @optional
 - (void)requestStorageSpace:(NSURL *)mainFrameURL frameOrigin:(NSURL *)frameURL quota:(NSUInteger)quota currentSize:(NSUInteger)currentSize spaceRequired:(NSUInteger)spaceRequired decisionHandler:(void (^)(unsigned long long quota))decisionHandler;
 - (void)didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler;
-
+- (void)websiteDataStore:(WKWebsiteDataStore *)dataStore openWindow:(NSURL *)url fromServiceWorkerOrigin:(WKSecurityOrigin *)serviceWorkerOrigin completionHandler:(void (^)(WKWebView *newWebView))completionHandler;
 @end

Modified: branches/safari-614.1.8-branch/Source/WebKit/UIProcess/Network/NetworkProcessProxy.cpp (291984 => 291985)


--- branches/safari-614.1.8-branch/Source/WebKit/UIProcess/Network/NetworkProcessProxy.cpp	2022-03-28 20:17:35 UTC (rev 291984)
+++ branches/safari-614.1.8-branch/Source/WebKit/UIProcess/Network/NetworkProcessProxy.cpp	2022-03-28 20:29:35 UTC (rev 291985)
@@ -1798,6 +1798,16 @@
     send(Messages::NetworkProcess::TerminateRemoteWorkerContextConnectionWhenPossible(workerType, sessionID, registrableDomain, processIdentifier), 0);
 }
 
+void NetworkProcessProxy::openWindowFromServiceWorker(PAL::SessionID sessionID, const String& urlString, const WebCore::SecurityOriginData& serviceWorkerOrigin, CompletionHandler<void(std::optional<WebCore::PageIdentifier>&&)>&& callback)
+{
+    if (auto* store = websiteDataStoreFromSessionID(sessionID)) {
+        store->openWindowFromServiceWorker(urlString, serviceWorkerOrigin, WTFMove(callback));
+        return;
+    }
+
+    callback(std::nullopt);
+}
+
 } // namespace WebKit
 
 #undef MESSAGE_CHECK

Modified: branches/safari-614.1.8-branch/Source/WebKit/UIProcess/Network/NetworkProcessProxy.h (291984 => 291985)


--- branches/safari-614.1.8-branch/Source/WebKit/UIProcess/Network/NetworkProcessProxy.h	2022-03-28 20:17:35 UTC (rev 291984)
+++ branches/safari-614.1.8-branch/Source/WebKit/UIProcess/Network/NetworkProcessProxy.h	2022-03-28 20:29:35 UTC (rev 291985)
@@ -299,6 +299,8 @@
 
     void terminateRemoteWorkerContextConnectionWhenPossible(RemoteWorkerType, PAL::SessionID, const WebCore::RegistrableDomain&, WebCore::ProcessIdentifier);
 
+    void openWindowFromServiceWorker(PAL::SessionID, const String& urlString, const WebCore::SecurityOriginData& serviceWorkerOrigin, CompletionHandler<void(std::optional<WebCore::PageIdentifier>&&)>&&);
+
 private:
     explicit NetworkProcessProxy();
 

Modified: branches/safari-614.1.8-branch/Source/WebKit/UIProcess/Network/NetworkProcessProxy.messages.in (291984 => 291985)


--- branches/safari-614.1.8-branch/Source/WebKit/UIProcess/Network/NetworkProcessProxy.messages.in	2022-03-28 20:17:35 UTC (rev 291984)
+++ branches/safari-614.1.8-branch/Source/WebKit/UIProcess/Network/NetworkProcessProxy.messages.in	2022-03-28 20:29:35 UTC (rev 291985)
@@ -91,6 +91,8 @@
     DataTaskDidReceiveResponse(WebKit::DataTaskIdentifier identifier, WebCore::ResourceResponse response) -> (bool allowed)
     DataTaskDidReceiveData(WebKit::DataTaskIdentifier identifier, IPC::DataReference data)
     DataTaskDidCompleteWithError(WebKit::DataTaskIdentifier identifier, WebCore::ResourceError error)
+
+    OpenWindowFromServiceWorker(PAL::SessionID sessionID, String urlString, struct WebCore::SecurityOriginData serviceWorkerOrigin) -> (std::optional<WebCore::PageIdentifier> newPage)
 }
 
 }

Modified: branches/safari-614.1.8-branch/Source/WebKit/UIProcess/WebPageProxy.cpp (291984 => 291985)


--- branches/safari-614.1.8-branch/Source/WebKit/UIProcess/WebPageProxy.cpp	2022-03-28 20:17:35 UTC (rev 291984)
+++ branches/safari-614.1.8-branch/Source/WebKit/UIProcess/WebPageProxy.cpp	2022-03-28 20:29:35 UTC (rev 291985)
@@ -4870,7 +4870,7 @@
         if (navigation)
             navigation->setClientNavigationActivity(nullptr);
 
-        callServiceWorkerLaunchCompletionHandlerIfNecessary();
+        callLoadCompletionHandlersIfNecessary(false);
     }
 
     frame.didFailProvisionalLoad();
@@ -4905,12 +4905,15 @@
 }
 #endif
 
-void WebPageProxy::callServiceWorkerLaunchCompletionHandlerIfNecessary()
+void WebPageProxy::callLoadCompletionHandlersIfNecessary(bool success)
 {
 #if ENABLE(SERVICE_WORKER)
-    if (m_isServiceWorkerPage && m_serviceWorkerLaunchCompletionHandler)
+    if (m_isServiceWorkerPage && m_serviceWorkerLaunchCompletionHandler && !success)
         m_serviceWorkerLaunchCompletionHandler(false);
 #endif
+
+    if (m_serviceWorkerOpenWindowCompletionCallback)
+        m_serviceWorkerOpenWindowCompletionCallback(success);
 }
 
 #if ENABLE(INTELLIGENT_TRACKING_PREVENTION)
@@ -5134,6 +5137,8 @@
         resetRecentCrashCountSoon();
 
         notifyProcessPoolToPrewarm();
+
+        callLoadCompletionHandlersIfNecessary(true);
     }
 
     m_isLoadingAlternateHTMLStringForFailingProvisionalLoad = false;
@@ -5182,7 +5187,7 @@
         if (navigation)
             navigation->setClientNavigationActivity(nullptr);
 
-        callServiceWorkerLaunchCompletionHandlerIfNecessary();
+        callLoadCompletionHandlersIfNecessary(false);
     }
 }
 
@@ -8018,7 +8023,7 @@
 #endif
 
     if (resetStateReason != ResetStateReason::NavigationSwap)
-        callServiceWorkerLaunchCompletionHandlerIfNecessary();
+        callLoadCompletionHandlersIfNecessary(false);
 
     if (m_openPanelResultListener) {
         m_openPanelResultListener->invalidate();

Modified: branches/safari-614.1.8-branch/Source/WebKit/UIProcess/WebPageProxy.h (291984 => 291985)


--- branches/safari-614.1.8-branch/Source/WebKit/UIProcess/WebPageProxy.h	2022-03-28 20:17:35 UTC (rev 291984)
+++ branches/safari-614.1.8-branch/Source/WebKit/UIProcess/WebPageProxy.h	2022-03-28 20:29:35 UTC (rev 291985)
@@ -2081,6 +2081,14 @@
 
     void interactableRegionsInRootViewCoordinates(WebCore::FloatRect, CompletionHandler<void(Vector<WebCore::FloatRect>)>&&);
 
+#if ENABLE(SERVICE_WORKER)
+    void setServiceWorkerOpenWindowCompletionCallback(CompletionHandler<void(bool)>&& completionCallback)
+    {
+        ASSERT(!m_serviceWorkerOpenWindowCompletionCallback);
+        m_serviceWorkerOpenWindowCompletionCallback = WTFMove(completionCallback);
+    }
+#endif
+
 private:
     WebPageProxy(PageClient&, WebProcessProxy&, Ref<API::PageConfiguration>&&);
     void platformInitialize();
@@ -2607,7 +2615,7 @@
 #if ENABLE(SERVICE_WORKER)
     void didFinishServiceWorkerPageRegistration(bool success);
 #endif
-    void callServiceWorkerLaunchCompletionHandlerIfNecessary();
+    void callLoadCompletionHandlersIfNecessary(bool success);
 
 #if PLATFORM(IOS_FAMILY)
     static bool isInHardwareKeyboardMode();
@@ -3119,6 +3127,7 @@
 #if ENABLE(SERVICE_WORKER)
     bool m_isServiceWorkerPage { false };
     CompletionHandler<void(bool)> m_serviceWorkerLaunchCompletionHandler;
+    CompletionHandler<void(bool)> m_serviceWorkerOpenWindowCompletionCallback;
 #endif
 
     RunLoop::Timer<WebPageProxy> m_tryCloseTimeoutTimer;

Modified: branches/safari-614.1.8-branch/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.cpp (291984 => 291985)


--- branches/safari-614.1.8-branch/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.cpp	2022-03-28 20:17:35 UTC (rev 291984)
+++ branches/safari-614.1.8-branch/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.cpp	2022-03-28 20:29:35 UTC (rev 291985)
@@ -2087,4 +2087,34 @@
     WebNotificationManagerProxy::sharedServiceWorkerManager().didDestroyNotification(nullptr, notificationID);
 }
 
+void WebsiteDataStore::openWindowFromServiceWorker(const String& urlString, const WebCore::SecurityOriginData& serviceWorkerOrigin, CompletionHandler<void(std::optional<WebCore::PageIdentifier>)>&& callback)
+{
+    auto innerCallback = [callback = WTFMove(callback)] (WebPageProxy* newPage) mutable {
+        if (!newPage) {
+            callback(std::nullopt);
+            return;
+        }
+
+        if (!newPage->pageLoadState().isLoading()) {
+            RELEASE_LOG(Loading, "The WKWebView provided in response to a ServiceWorker openWindow request was not in the loading state");
+            callback(std::nullopt);
+            return;
+        }
+
+        auto innerCallback = [pageID = newPage->identifier(), callback = WTFMove(callback)] (bool success) mutable {
+            auto* newPage = WebProcessProxy::webPage(pageID);
+            if (!newPage || !success) {
+                callback(std::nullopt);
+                return;
+            }
+
+            callback(newPage->webPageID());
+        };
+
+        newPage->setServiceWorkerOpenWindowCompletionCallback(WTFMove(innerCallback));
+    };
+
+    m_client->openWindowFromServiceWorker(urlString, serviceWorkerOrigin, WTFMove(innerCallback));
 }
+
+}

Modified: branches/safari-614.1.8-branch/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.h (291984 => 291985)


--- branches/safari-614.1.8-branch/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.h	2022-03-28 20:17:35 UTC (rev 291984)
+++ branches/safari-614.1.8-branch/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.h	2022-03-28 20:29:35 UTC (rev 291985)
@@ -379,6 +379,8 @@
     void clearServiceWorkerNotification(const UUID& notificationID);
     void didDestroyServiceWorkerNotification(const UUID& notificationID);
 
+    void openWindowFromServiceWorker(const String& urlString, const WebCore::SecurityOriginData& serviceWorkerOrigin, CompletionHandler<void(std::optional<WebCore::PageIdentifier>)>&&);
+
 private:
     enum class ForceReinitialization : bool { No, Yes };
 #if ENABLE(APP_BOUND_DOMAINS)

Modified: branches/safari-614.1.8-branch/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStoreClient.h (291984 => 291985)


--- branches/safari-614.1.8-branch/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStoreClient.h	2022-03-28 20:17:35 UTC (rev 291984)
+++ branches/safari-614.1.8-branch/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStoreClient.h	2022-03-28 20:29:35 UTC (rev 291985)
@@ -36,6 +36,8 @@
 
 namespace WebKit {
 
+class WebPageProxy;
+
 class WebsiteDataStoreClient {
     WTF_MAKE_FAST_ALLOCATED;
 public:
@@ -50,6 +52,11 @@
     {
         challenge->listener().completeChallenge(AuthenticationChallengeDisposition::PerformDefaultHandling);
     }
+
+    virtual void openWindowFromServiceWorker(const String&, const WebCore::SecurityOriginData&, CompletionHandler<void(WebPageProxy*)>&& completionHandler)
+    {
+        completionHandler(nullptr);
+    }
 };
 
 } // namespace WebKit

Modified: branches/safari-614.1.8-branch/Source/WebKit/WebProcess/Notifications/WebNotificationManager.cpp (291984 => 291985)


--- branches/safari-614.1.8-branch/Source/WebKit/WebProcess/Notifications/WebNotificationManager.cpp	2022-03-28 20:17:35 UTC (rev 291984)
+++ branches/safari-614.1.8-branch/Source/WebKit/WebProcess/Notifications/WebNotificationManager.cpp	2022-03-28 20:29:35 UTC (rev 291985)
@@ -150,6 +150,8 @@
 
 bool WebNotificationManager::show(Notification& notification, WebPage* page)
 {
+    LOG(Notifications, "WebProcess %i going to show notification %s", getpid(), notification.identifier().toString().utf8().data());
+
     ASSERT(isMainRunLoop());
 #if ENABLE(NOTIFICATIONS)
     if (page && !page->corePage()->settings().notificationsEnabled())
@@ -208,6 +210,8 @@
 {
     ASSERT(isMainRunLoop());
 
+    LOG(Notifications, "WebProcess %i DID SHOW notification %s", getpid(), notificationID.toString().utf8().data());
+
 #if ENABLE(NOTIFICATIONS)
     RefPtr<Notification> notification = m_notificationIDMap.get(notificationID);
     if (!notification)
@@ -223,11 +227,15 @@
 {
     ASSERT(isMainRunLoop());
 
+    LOG(Notifications, "WebProcess %i DID CLICK notification %s", getpid(), notificationID.toString().utf8().data());
+
 #if ENABLE(NOTIFICATIONS)
     RefPtr<Notification> notification = m_notificationIDMap.get(notificationID);
     if (!notification)
         return;
 
+    LOG(Notifications, "WebProcess %i handling click event for notification %s", getpid(), notificationID.toString().utf8().data());
+
     // Indicate that this event is being dispatched in reaction to a user's interaction with a platform notification.
     UserGestureIndicator indicator(ProcessingUserGesture);
     notification->dispatchClickEvent();

Modified: branches/safari-614.1.8-branch/Source/WebKit/WebProcess/Storage/WebSWContextManagerConnection.cpp (291984 => 291985)


--- branches/safari-614.1.8-branch/Source/WebKit/WebProcess/Storage/WebSWContextManagerConnection.cpp	2022-03-28 20:17:35 UTC (rev 291984)
+++ branches/safari-614.1.8-branch/Source/WebKit/WebProcess/Storage/WebSWContextManagerConnection.cpp	2022-03-28 20:29:35 UTC (rev 291985)
@@ -332,6 +332,11 @@
         callback(WTFMove(clientsData));
 }
 
+void WebSWContextManagerConnection::openWindow(WebCore::ServiceWorkerIdentifier serviceWorkerIdentifier, const String& url, CompletionHandler<void(std::optional<WebCore::PageIdentifier>&&)>&& callback)
+{
+    m_connectionToNetworkProcess->sendWithAsyncReply(Messages::WebSWServerToContextConnection::OpenWindow { serviceWorkerIdentifier, url }, WTFMove(callback));
+}
+
 void WebSWContextManagerConnection::claim(ServiceWorkerIdentifier serviceWorkerIdentifier, CompletionHandler<void(ExceptionOr<void>&&)>&& callback)
 {
     m_connectionToNetworkProcess->sendWithAsyncReply(Messages::WebSWServerToContextConnection::Claim { serviceWorkerIdentifier }, [callback = WTFMove(callback)](auto&& result) mutable {

Modified: branches/safari-614.1.8-branch/Source/WebKit/WebProcess/Storage/WebSWContextManagerConnection.h (291984 => 291985)


--- branches/safari-614.1.8-branch/Source/WebKit/WebProcess/Storage/WebSWContextManagerConnection.h	2022-03-28 20:17:35 UTC (rev 291984)
+++ branches/safari-614.1.8-branch/Source/WebKit/WebProcess/Storage/WebSWContextManagerConnection.h	2022-03-28 20:29:35 UTC (rev 291985)
@@ -87,6 +87,7 @@
     bool isThrottleable() const final;
     void didFailHeartBeatCheck(WebCore::ServiceWorkerIdentifier) final;
     void setAsInspected(WebCore::ServiceWorkerIdentifier, bool) final;
+    void openWindow(WebCore::ServiceWorkerIdentifier, const String& url, CompletionHandler<void(std::optional<WebCore::PageIdentifier>&&)>&&) final;
 
     // IPC messages.
     void serviceWorkerStarted(std::optional<WebCore::ServiceWorkerJobDataIdentifier>, WebCore::ServiceWorkerIdentifier, bool doesHandleFetch) final;

Modified: branches/safari-614.1.8-branch/Tools/ChangeLog (291984 => 291985)


--- branches/safari-614.1.8-branch/Tools/ChangeLog	2022-03-28 20:17:35 UTC (rev 291984)
+++ branches/safari-614.1.8-branch/Tools/ChangeLog	2022-03-28 20:29:35 UTC (rev 291985)
@@ -1,3 +1,173 @@
+2022-03-28  Russell Epstein  <repst...@apple.com>
+
+        Cherry-pick r291979. rdar://problem/90616651
+
+    Support ServiceWorkerClients.openWindow.
+    <rdar://90616651> and https://bugs.webkit.org/show_bug.cgi?id=238400
+    
+    Reviewed by Youenn Fablet.
+    Source/WebCore:
+    
+    Test: http/tests/workers/service/openwindow-from-notification-click.html
+    
+    * dom/Document.cpp:
+    (WebCore::Document::pageID const):
+    
+    * page/ClientOrigin.h:
+    (WebCore::ClientOrigin::loggingString const):
+    
+    * workers/service/ServiceWorkerClientData.cpp:
+    (WebCore::ServiceWorkerClientData::isolatedCopy const):
+    (WebCore::ServiceWorkerClientData::isolatedCopy):
+    (WebCore::ServiceWorkerClientData::from):
+    
+    * workers/service/ServiceWorkerClientData.h:
+    (WebCore::ServiceWorkerClientData::encode const):
+    (WebCore::ServiceWorkerClientData::decode):
+    
+    * workers/service/ServiceWorkerClients.cpp:
+    (WebCore::matchWindowWithPageIdentifier):
+    (WebCore::ServiceWorkerClients::openWindow):
+    
+    * workers/service/context/SWContextManager.h:
+    * workers/service/server/SWServerToContextConnection.h:
+    * workers/service/server/SWServerWorker.h:
+    
+    Source/WebKit:
+    
+    This API asks the browser to asynchronously open a new tab to a URL then resolve
+    a promise with the new WindowClient representing that tab.
+    
+    From a WebCore/WebKit standpoint, implementing this was mostly straightforward.
+    1 - A plumbing exercise (thread hopping and IPC'ing the message and its reply around)
+    2 - Implmenting a new delegate method for the hosting app to create the requested WKWebView
+    
+    The delegate method was interesting. Normally this is the type of thing that'd go to the
+    WKUIDelegate but that requires there to be a WKWebView, and service workers can be running
+    without any web views.
+    
+    Fortunately we already had a WKWebsiteDataStore delegate SPI, and service workers *do* always
+    have an associated website data store they're running under.
+    
+    Once the app gives the new web view back to WebKit, we record its PageIdentifier in the reply.
+    
+    Once the reply makes its way all the way back to the ServiceWorker process and on the
+    ServiceWorker thread, we do a client match and cross check with that PageIdentifier to make
+    sure we're resolving the promise with the correct WindowClient.
+    
+    If there's no matched clients, then the view is either already gone or it has navigated away
+    to a non-applicable URL.
+    
+    Same if there are matched clients, but they don't match the specified PageIdentifier.
+    
+    A straight forward layouttest completes the task.
+    
+    * NetworkProcess/ServiceWorker/WebSWServerConnection.cpp:
+    (WebKit::WebSWServerConnection::controlClient):
+    
+    * NetworkProcess/ServiceWorker/WebSWServerToContextConnection.cpp:
+    (WebKit::WebSWServerToContextConnection::openWindow):
+    * NetworkProcess/ServiceWorker/WebSWServerToContextConnection.h:
+    * NetworkProcess/ServiceWorker/WebSWServerToContextConnection.messages.in:
+    
+    * UIProcess/API/Cocoa/WKWebsiteDataStore.mm:
+    (-[WKWebsiteDataStore set_delegate:]):
+    * UIProcess/API/Cocoa/_WKWebsiteDataStoreDelegate.h:
+    
+    * UIProcess/Network/NetworkProcessProxy.cpp:
+    (WebKit::NetworkProcessProxy::openWindowFromServiceWorker):
+    * UIProcess/Network/NetworkProcessProxy.h:
+    * UIProcess/Network/NetworkProcessProxy.messages.in:
+    
+    * UIProcess/WebPageProxy.cpp:
+    (WebKit::WebPageProxy::didFailProvisionalLoadForFrameShared):
+    (WebKit::WebPageProxy::callLoadCompletionHandlersIfNecessary):
+    (WebKit::WebPageProxy::didFinishLoadForFrame):
+    (WebKit::WebPageProxy::didFailLoadForFrame):
+    (WebKit::WebPageProxy::resetState):
+    (WebKit::WebPageProxy::callServiceWorkerLaunchCompletionHandlerIfNecessary): Deleted.
+    * UIProcess/WebPageProxy.h:
+    
+    * UIProcess/WebsiteData/WebsiteDataStore.cpp:
+    (WebKit::WebsiteDataStore::openWindowFromServiceWorker):
+    * UIProcess/WebsiteData/WebsiteDataStore.h:
+    
+    * UIProcess/WebsiteData/WebsiteDataStoreClient.h:
+    (WebKit::WebsiteDataStoreClient::openWindowFromServiceWorker):
+    
+    * WebProcess/Notifications/WebNotificationManager.cpp:
+    (WebKit::WebNotificationManager::show):
+    (WebKit::WebNotificationManager::didShowNotification):
+    (WebKit::WebNotificationManager::didClickNotification):
+    
+    * WebProcess/Storage/WebSWContextManagerConnection.cpp:
+    (WebKit::WebSWContextManagerConnection::openWindow):
+    * WebProcess/Storage/WebSWContextManagerConnection.h:
+    
+    Source/WTF:
+    
+    * wtf/HashTable.h:
+    (WTF::KeyTraits>::inlineLookup): Relax this value size requirement for now.
+    The required refactoring is best left as a seperate task with a seperate patch.
+    
+    Tools:
+    
+    Implement the new delegate to create the new view.
+    
+    * WebKitTestRunner/TestController.cpp:
+    (WTR::TestController::createOtherPage):
+    (WTR::TestController::createOtherPlatformWebView):
+    * WebKitTestRunner/TestController.h:
+    
+    * WebKitTestRunner/cocoa/TestControllerCocoa.mm:
+    (WTR::TestController::platformCreateOtherPage):
+    * WebKitTestRunner/cocoa/TestWebsiteDataStoreDelegate.mm:
+    (-[TestWebsiteDataStoreDelegate websiteDataStore:openWindow:fromServiceWorkerOrigin:completionHandler:]):
+    
+    LayoutTests:
+    
+    WKTR knows how to openWindow() now.
+    
+    So test:
+    - The success case
+    - Failure due to a disallowed URL
+    - Failure due to a lack of a related user gesture.
+    
+    * http/tests/workers/service/openwindow-from-notification-click-expected.txt: Added.
+    * http/tests/workers/service/openwindow-from-notification-click.html: Added.
+    * http/tests/workers/service/resources/openwindow-client.html: Added.
+    * http/tests/workers/service/resources/shownotification-openwindow-worker.js: Added.
+    (async const):
+    (let.messageClients):
+    (clients.openWindow.string_appeared_here.then.async client):
+    (catch.async error):
+    (async event):
+    (async tryShow):
+    (async getNotes):
+    * platform/gtk/TestExpectations:
+    
+    
+    git-svn-id: https://svn.webkit.org/repository/webkit/trunk@291979 268f45cc-cd09-0410-ab3c-d52691b4dbfc
+
+    2022-03-28  Brady Eidson  <beid...@apple.com>
+
+            Support ServiceWorkerClients.openWindow.
+            <rdar://90616651> and https://bugs.webkit.org/show_bug.cgi?id=238400
+
+            Reviewed by Youenn Fablet.
+
+            Implement the new delegate to create the new view.
+
+            * WebKitTestRunner/TestController.cpp:
+            (WTR::TestController::createOtherPage):
+            (WTR::TestController::createOtherPlatformWebView):
+            * WebKitTestRunner/TestController.h:
+
+            * WebKitTestRunner/cocoa/TestControllerCocoa.mm:
+            (WTR::TestController::platformCreateOtherPage):
+            * WebKitTestRunner/cocoa/TestWebsiteDataStoreDelegate.mm:
+            (-[TestWebsiteDataStoreDelegate websiteDataStore:openWindow:fromServiceWorkerOrigin:completionHandler:]):
+
 2022-03-26  Myles C. Maxfield  <mmaxfi...@apple.com>
 
         [WebGPU] Import WebGPU Conformance Test Suite

Modified: branches/safari-614.1.8-branch/Tools/WebKitTestRunner/TestController.cpp (291984 => 291985)


--- branches/safari-614.1.8-branch/Tools/WebKitTestRunner/TestController.cpp	2022-03-28 20:17:35 UTC (rev 291984)
+++ branches/safari-614.1.8-branch/Tools/WebKitTestRunner/TestController.cpp	2022-03-28 20:29:35 UTC (rev 291985)
@@ -381,6 +381,17 @@
 
 WKPageRef TestController::createOtherPage(PlatformWebView* parentView, WKPageConfigurationRef configuration, WKNavigationActionRef navigationAction, WKWindowFeaturesRef windowFeatures)
 {
+    auto* platformWebView = createOtherPlatformWebView(parentView, configuration, navigationAction, windowFeatures);
+    if (!platformWebView)
+        return nullptr;
+
+    auto* page = platformWebView->page();
+    WKRetain(page);
+    return page;
+}
+
+PlatformWebView* TestController::createOtherPlatformWebView(PlatformWebView* parentView, WKPageConfigurationRef configuration, WKNavigationActionRef, WKWindowFeaturesRef)
+{
     m_currentInvocation->willCreateNewPage();
 
     // The test called testRunner.preventPopupWindows() to prevent opening new windows.
@@ -389,7 +400,8 @@
 
     m_createdOtherPage = true;
 
-    auto view = platformCreateOtherPage(parentView, configuration, parentView->options());
+    auto options = parentView ? parentView->options() : m_mainWebView->options();
+    auto view = platformCreateOtherPage(parentView, configuration, options);
     WKPageRef newPage = view->page();
 
     view->resizeTo(800, 600);
@@ -509,9 +521,9 @@
 
     TestController::singleton().updateWindowScaleForTest(view.ptr(), *TestController::singleton().m_currentInvocation);
 
+    PlatformWebView* viewToReturn = view.ptr();
     m_auxiliaryWebViews.append(WTFMove(view));
-    WKRetain(newPage);
-    return newPage;
+    return viewToReturn;
 }
 
 const char* TestController::libraryPathForTesting()

Modified: branches/safari-614.1.8-branch/Tools/WebKitTestRunner/TestController.h (291984 => 291985)


--- branches/safari-614.1.8-branch/Tools/WebKitTestRunner/TestController.h	2022-03-28 20:17:35 UTC (rev 291984)
+++ branches/safari-614.1.8-branch/Tools/WebKitTestRunner/TestController.h	2022-03-28 20:29:35 UTC (rev 291985)
@@ -378,6 +378,8 @@
     bool denyNotificationPermission(WKStringRef origin);
     bool denyNotificationPermissionOnPrompt(WKStringRef origin);
 
+    PlatformWebView* createOtherPlatformWebView(PlatformWebView* parentView, WKPageConfigurationRef, WKNavigationActionRef, WKWindowFeaturesRef);
+
 private:
     WKRetainPtr<WKPageConfigurationRef> generatePageConfiguration(const TestOptions&);
     WKRetainPtr<WKContextConfigurationRef> generateContextConfiguration(const TestOptions&) const;

Modified: branches/safari-614.1.8-branch/Tools/WebKitTestRunner/cocoa/TestControllerCocoa.mm (291984 => 291985)


--- branches/safari-614.1.8-branch/Tools/WebKitTestRunner/cocoa/TestControllerCocoa.mm	2022-03-28 20:17:35 UTC (rev 291984)
+++ branches/safari-614.1.8-branch/Tools/WebKitTestRunner/cocoa/TestControllerCocoa.mm	2022-03-28 20:29:35 UTC (rev 291985)
@@ -214,7 +214,8 @@
 UniqueRef<PlatformWebView> TestController::platformCreateOtherPage(PlatformWebView* parentView, WKPageConfigurationRef, const TestOptions& options)
 {
     auto newConfiguration = adoptNS([globalWebViewConfiguration() copy]);
-    [newConfiguration _setRelatedWebView:static_cast<WKWebView*>(parentView->platformView())];
+    if (parentView)
+        [newConfiguration _setRelatedWebView:static_cast<WKWebView*>(parentView->platformView())];
     if ([newConfiguration _relatedWebView])
         [newConfiguration setWebsiteDataStore:[newConfiguration _relatedWebView].configuration.websiteDataStore];
     auto view = makeUniqueRef<PlatformWebView>(newConfiguration.get(), options);

Modified: branches/safari-614.1.8-branch/Tools/WebKitTestRunner/cocoa/TestWebsiteDataStoreDelegate.mm (291984 => 291985)


--- branches/safari-614.1.8-branch/Tools/WebKitTestRunner/cocoa/TestWebsiteDataStoreDelegate.mm	2022-03-28 20:17:35 UTC (rev 291984)
+++ branches/safari-614.1.8-branch/Tools/WebKitTestRunner/cocoa/TestWebsiteDataStoreDelegate.mm	2022-03-28 20:29:35 UTC (rev 291985)
@@ -26,6 +26,12 @@
 #import "config.h"
 #import "TestWebsiteDataStoreDelegate.h"
 
+#import "PlatformWebView.h"
+#import "TestController.h"
+#import "TestRunnerWKWebView.h"
+#import <WebKit/WKWebView.h>
+#import <wtf/UniqueRef.h>
+
 @implementation TestWebsiteDataStoreDelegate { }
 - (instancetype)init
 {
@@ -61,4 +67,15 @@
     _shouldAllowAnySSLCertificate = shouldAllowAnySSLCertificate;
 }
 
+- (void)websiteDataStore:(WKWebsiteDataStore *)dataStore openWindow:(NSURL *)url fromServiceWorkerOrigin:(WKSecurityOrigin *)serviceWorkerOrigin completionHandler:(void (^)(WKWebView *newWebView))completionHandler
+{
+    auto* newView = WTR::TestController::singleton().createOtherPlatformWebView(nullptr, nullptr, nullptr, nullptr);
+    WKWebView *webView = newView->platformView();
+
+    ASSERT(webView.configuration.websiteDataStore == dataStore);
+
+    [webView loadRequest:[NSURLRequest requestWithURL:url]];
+    completionHandler(webView);
+}
+
 @end
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to