Add a FrameLoaderClient willInjectUserScriptForFrame callback
authoryouenn@apple.com <youenn@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 12 Jul 2018 21:34:35 +0000 (21:34 +0000)
committeryouenn@apple.com <youenn@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 12 Jul 2018 21:34:35 +0000 (21:34 +0000)
https://bugs.webkit.org/show_bug.cgi?id=187565

Reviewed by Alex Christensen.

Source/WebCore:

Test: http/tests/contentextensions/injected-script-callback.html.

* loader/FrameLoaderClient.h:
* page/Frame.cpp:
(WebCore::Frame::injectUserScriptImmediately):
Calling the new callback whenever being about to inject a new script.

Source/WebKit:

Introduce a new WKBundlePageLoaderClient callback that is called everytime a user script is injected.
Implement WebFrameLoaderClient::willInjectUserScript by calling this new callback.

* WebProcess/InjectedBundle/API/APIInjectedBundlePageLoaderClient.h:
(API::InjectedBundle::PageLoaderClient::willInjectUserScriptForFrame):
* WebProcess/InjectedBundle/API/c/WKBundlePageLoaderClient.h:
* WebProcess/InjectedBundle/API/mac/WKWebProcessPlugInBrowserContextController.mm:
(setUpPageLoaderClient):
* WebProcess/InjectedBundle/InjectedBundlePageLoaderClient.cpp:
(WebKit::InjectedBundlePageLoaderClient::globalObjectIsAvailableForFrame):
(WebKit::InjectedBundlePageLoaderClient::willInjectUserScriptForFrame):
* WebProcess/InjectedBundle/InjectedBundlePageLoaderClient.h:
* WebProcess/WebCoreSupport/WebFrameLoaderClient.cpp:
(WebKit::WebFrameLoaderClient::willInjectUserScript):
* WebProcess/WebCoreSupport/WebFrameLoaderClient.h:

Tools:

Added new test runner API to check for willInjectUserScriptForFrame callback.

* WebKitTestRunner/InjectedBundle/Bindings/TestRunner.idl:
* WebKitTestRunner/InjectedBundle/InjectedBundle.h:
(WTR::InjectedBundle::resetUserScriptInjectedCount):
(WTR::InjectedBundle::increaseUserScriptInjectedCount):
(WTR::InjectedBundle::userScriptInjectedCount const):
* WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp:
(WTR::InjectedBundlePage::InjectedBundlePage):
(WTR::InjectedBundlePage::resetAfterTest):
(WTR::InjectedBundlePage::willInjectUserScriptForFrame):
* WebKitTestRunner/InjectedBundle/InjectedBundlePage.h:
* WebKitTestRunner/InjectedBundle/TestRunner.cpp:
(WTR::TestRunner::userScriptInjectedCount const):
(WTR::TestRunner::injectUserScript):
* WebKitTestRunner/InjectedBundle/TestRunner.h:
* WebKitTestRunner/TestController.cpp:
(WTR::TestController::injectUserScript):
* WebKitTestRunner/TestController.h:
* WebKitTestRunner/TestInvocation.cpp:
(WTR::TestInvocation::didReceiveSynchronousMessageFromInjectedBundle):
* WebKitTestRunner/cocoa/TestControllerCocoa.mm:
(WTR::TestController::injectUserScript):

LayoutTests:

* http/tests/contentextensions/injected-script-callback-expected.txt: Added.
* http/tests/contentextensions/injected-script-callback.html: Added.

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

25 files changed:
LayoutTests/ChangeLog
LayoutTests/http/tests/contentextensions/injected-script-callback-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/contentextensions/injected-script-callback.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/loader/FrameLoaderClient.h
Source/WebCore/page/Frame.cpp
Source/WebKit/ChangeLog
Source/WebKit/WebProcess/InjectedBundle/API/APIInjectedBundlePageLoaderClient.h
Source/WebKit/WebProcess/InjectedBundle/API/c/WKBundlePageLoaderClient.h
Source/WebKit/WebProcess/InjectedBundle/API/mac/WKWebProcessPlugInBrowserContextController.mm
Source/WebKit/WebProcess/InjectedBundle/InjectedBundlePageLoaderClient.cpp
Source/WebKit/WebProcess/InjectedBundle/InjectedBundlePageLoaderClient.h
Source/WebKit/WebProcess/WebCoreSupport/WebFrameLoaderClient.cpp
Source/WebKit/WebProcess/WebCoreSupport/WebFrameLoaderClient.h
Tools/ChangeLog
Tools/WebKitTestRunner/InjectedBundle/Bindings/TestRunner.idl
Tools/WebKitTestRunner/InjectedBundle/InjectedBundle.h
Tools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp
Tools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.h
Tools/WebKitTestRunner/InjectedBundle/TestRunner.cpp
Tools/WebKitTestRunner/InjectedBundle/TestRunner.h
Tools/WebKitTestRunner/TestController.cpp
Tools/WebKitTestRunner/TestController.h
Tools/WebKitTestRunner/TestInvocation.cpp
Tools/WebKitTestRunner/cocoa/TestControllerCocoa.mm

index 4e9537a..1d21286 100644 (file)
@@ -1,3 +1,13 @@
+2018-07-12  Youenn Fablet  <youenn@apple.com>
+
+        Add a FrameLoaderClient willInjectUserScriptForFrame callback
+        https://bugs.webkit.org/show_bug.cgi?id=187565
+
+        Reviewed by Alex Christensen.
+
+        * http/tests/contentextensions/injected-script-callback-expected.txt: Added.
+        * http/tests/contentextensions/injected-script-callback.html: Added.
+
 2018-07-11  Ross Kirsling  <ross.kirsling@sony.com>
 
         UTF-16 XHTML files need svn:mime-type to be handled correctly by Windows SVN
diff --git a/LayoutTests/http/tests/contentextensions/injected-script-callback-expected.txt b/LayoutTests/http/tests/contentextensions/injected-script-callback-expected.txt
new file mode 100644 (file)
index 0000000..48a0e78
--- /dev/null
@@ -0,0 +1,4 @@
+  
+
+PASS Test willInjectUserScript callback being called 
+
diff --git a/LayoutTests/http/tests/contentextensions/injected-script-callback.html b/LayoutTests/http/tests/contentextensions/injected-script-callback.html
new file mode 100644 (file)
index 0000000..db6435c
--- /dev/null
@@ -0,0 +1,53 @@
+<!doctype html>
+<html>
+    <head>
+        <meta charset="utf-8">
+        <title>Testing new callback</title>
+        <script src="/resources/testharness.js"></script>
+        <script src="/resources/testharnessreport.js"></script>
+    </head>
+    <body>
+        <script>
+function waitFor(duration)
+{
+    return new Promise((resolve) => setTimeout(resolve, duration));
+}
+
+function withFrame(url)
+{
+    return new Promise((resolve) => {
+        let frame = document.createElement('iframe');
+        frame.src = url;
+        frame.onload = function() { resolve(frame); };
+        document.body.appendChild(frame);
+    });
+}
+
+async function verifyUserScriptInjectedCount(expected)
+{
+    let counter = 0;
+    while (++counter < 100) {
+        if (testRunner.userScriptInjectedCount === expected)
+            return;
+        await waitFor(10);
+    }
+    return Promise.reject("Did not get expected value " + expected + " but " + testRunner.userScriptInjectedCount);
+}
+
+promise_test(async () => {
+    if (!window.testRunner) {
+        reject("Test requires internals API");
+        return;
+    }
+    assert_equals(testRunner.userScriptInjectedCount, 0);
+    testRunner.injectUserScript("function a() { }");
+
+    await withFrame(".");
+    await verifyUserScriptInjectedCount(1);
+
+    await withFrame(".");
+    await verifyUserScriptInjectedCount(2);
+}, 'Test willInjectUserScript callback being called');
+        </script>
+    </body>
+</html>
index 237493b..a401082 100644 (file)
@@ -1,3 +1,17 @@
+2018-07-12  Youenn Fablet  <youenn@apple.com>
+
+        Add a FrameLoaderClient willInjectUserScriptForFrame callback
+        https://bugs.webkit.org/show_bug.cgi?id=187565
+
+        Reviewed by Alex Christensen.
+
+        Test: http/tests/contentextensions/injected-script-callback.html.
+
+        * loader/FrameLoaderClient.h:
+        * page/Frame.cpp:
+        (WebCore::Frame::injectUserScriptImmediately):
+        Calling the new callback whenever being about to inject a new script.
+
 2018-07-12  Megan Gardner  <megan_gardner@apple.com>
 
         Keep Selections within Shadow DOM boundaries
index f722618..5e7a29e 100644 (file)
@@ -332,6 +332,8 @@ public:
     virtual void dispatchDidReconnectDOMWindowExtensionToGlobalObject(DOMWindowExtension*) { }
     virtual void dispatchWillDestroyGlobalObjectForDOMWindowExtension(DOMWindowExtension*) { }
 
+    virtual void willInjectUserScript(DOMWrapperWorld&) { }
+
 #if ENABLE(WEB_RTC)
     virtual void dispatchWillStartUsingPeerConnectionHandler(RTCPeerConnectionHandler*) { }
 #endif
index d230930..2b87d60 100644 (file)
@@ -751,6 +751,7 @@ void Frame::injectUserScriptImmediately(DOMWrapperWorld& world, const UserScript
         return;
     if (m_page)
         m_page->setAsRunningUserScripts();
+    loader().client().willInjectUserScript(world);
     m_script->evaluateInWorld(ScriptSourceCode(script.source(), script.url()), world);
 }
 
index f7f7b02..1a4fac4 100644 (file)
@@ -1,3 +1,26 @@
+2018-07-12  Youenn Fablet  <youenn@apple.com>
+
+        Add a FrameLoaderClient willInjectUserScriptForFrame callback
+        https://bugs.webkit.org/show_bug.cgi?id=187565
+
+        Reviewed by Alex Christensen.
+
+        Introduce a new WKBundlePageLoaderClient callback that is called everytime a user script is injected.
+        Implement WebFrameLoaderClient::willInjectUserScript by calling this new callback.
+
+        * WebProcess/InjectedBundle/API/APIInjectedBundlePageLoaderClient.h:
+        (API::InjectedBundle::PageLoaderClient::willInjectUserScriptForFrame):
+        * WebProcess/InjectedBundle/API/c/WKBundlePageLoaderClient.h:
+        * WebProcess/InjectedBundle/API/mac/WKWebProcessPlugInBrowserContextController.mm:
+        (setUpPageLoaderClient):
+        * WebProcess/InjectedBundle/InjectedBundlePageLoaderClient.cpp:
+        (WebKit::InjectedBundlePageLoaderClient::globalObjectIsAvailableForFrame):
+        (WebKit::InjectedBundlePageLoaderClient::willInjectUserScriptForFrame):
+        * WebProcess/InjectedBundle/InjectedBundlePageLoaderClient.h:
+        * WebProcess/WebCoreSupport/WebFrameLoaderClient.cpp:
+        (WebKit::WebFrameLoaderClient::willInjectUserScript):
+        * WebProcess/WebCoreSupport/WebFrameLoaderClient.h:
+
 2018-07-12  Said Abou-Hallawa  <sabouhallawa@apple.com>
 
         [iOS] When bringing MobileSafari to the foreground, images are drawn asynchronously after removing a snapshot that included them
index 58c64d2..08ddbbe 100644 (file)
@@ -89,6 +89,8 @@ public:
     virtual void didReconnectDOMWindowExtensionToGlobalObject(WebKit::WebPage&, WebCore::DOMWindowExtension*) { }
     virtual void willDestroyGlobalObjectForDOMWindowExtension(WebKit::WebPage&, WebCore::DOMWindowExtension*) { }
 
+    virtual void willInjectUserScriptForFrame(WebKit::WebPage&, WebKit::WebFrame&, WebCore::DOMWrapperWorld&) { }
+
     virtual bool shouldForceUniversalAccessFromLocalURL(WebKit::WebPage&, const WTF::String&) { return false; }
 
     virtual void featuresUsedInPage(WebKit::WebPage&, const Vector<WTF::String>&) { }
index ee142de..040f591 100644 (file)
@@ -53,6 +53,7 @@ typedef void (*WKBundlePageWillPerformClientRedirectForFrameCallback)(WKBundlePa
 typedef void (*WKBundlePageDidHandleOnloadEventsForFrameCallback)(WKBundlePageRef page, WKBundleFrameRef frame, const void *clientInfo);
 typedef bool (*WKBundlePageShouldGoToBackForwardListItemCallback)(WKBundlePageRef page, WKBundleBackForwardListItemRef item, WKTypeRef* userData, const void *clientInfo);
 typedef void (*WKBundlePageGlobalObjectIsAvailableForFrameCallback)(WKBundlePageRef page, WKBundleFrameRef, WKBundleScriptWorldRef, const void* clientInfo);
+typedef void (*WKBundlePageWillInjectUserScriptForFrameCallback)(WKBundlePageRef page, WKBundleFrameRef, WKBundleScriptWorldRef, const void* clientInfo);
 typedef void (*WKBundlePageWillDisconnectDOMWindowExtensionFromGlobalObjectCallback)(WKBundlePageRef page, WKBundleDOMWindowExtensionRef, const void* clientInfo);
 typedef void (*WKBundlePageDidReconnectDOMWindowExtensionToGlobalObjectCallback)(WKBundlePageRef page, WKBundleDOMWindowExtensionRef, const void* clientInfo);
 typedef void (*WKBundlePageWillDestroyGlobalObjectForDOMWindowExtensionCallback)(WKBundlePageRef page, WKBundleDOMWindowExtensionRef, const void* clientInfo);
@@ -464,4 +465,65 @@ typedef struct WKBundlePageLoaderClientV8 {
     WKBundlePageUserAgentForURLCallback                                     userAgentForURL;
 } WKBundlePageLoaderClientV8;
 
+typedef struct WKBundlePageLoaderClientV9 {
+    WKBundlePageLoaderClientBase                                            base;
+
+    // Version 0.
+    WKBundlePageDidStartProvisionalLoadForFrameCallback                     didStartProvisionalLoadForFrame;
+    WKBundlePageDidReceiveServerRedirectForProvisionalLoadForFrameCallback  didReceiveServerRedirectForProvisionalLoadForFrame;
+    WKBundlePageDidFailProvisionalLoadWithErrorForFrameCallback             didFailProvisionalLoadWithErrorForFrame;
+    WKBundlePageDidCommitLoadForFrameCallback                               didCommitLoadForFrame;
+    WKBundlePageDidFinishDocumentLoadForFrameCallback                       didFinishDocumentLoadForFrame;
+    WKBundlePageDidFinishLoadForFrameCallback                               didFinishLoadForFrame;
+    WKBundlePageDidFailLoadWithErrorForFrameCallback                        didFailLoadWithErrorForFrame;
+    WKBundlePageDidSameDocumentNavigationForFrameCallback                   didSameDocumentNavigationForFrame;
+    WKBundlePageDidReceiveTitleForFrameCallback                             didReceiveTitleForFrame;
+    WKBundlePageDidFirstLayoutForFrameCallback                              didFirstLayoutForFrame;
+    WKBundlePageDidFirstVisuallyNonEmptyLayoutForFrameCallback              didFirstVisuallyNonEmptyLayoutForFrame;
+    WKBundlePageDidRemoveFrameFromHierarchyCallback                         didRemoveFrameFromHierarchy;
+    WKBundlePageDidDisplayInsecureContentForFrameCallback                   didDisplayInsecureContentForFrame;
+    WKBundlePageDidRunInsecureContentForFrameCallback                       didRunInsecureContentForFrame;
+    WKBundlePageDidClearWindowObjectForFrameCallback                        didClearWindowObjectForFrame;
+    WKBundlePageDidCancelClientRedirectForFrameCallback                     didCancelClientRedirectForFrame;
+    WKBundlePageWillPerformClientRedirectForFrameCallback                   willPerformClientRedirectForFrame;
+    WKBundlePageDidHandleOnloadEventsForFrameCallback                       didHandleOnloadEventsForFrame;
+
+    // Version 1.
+    WKBundlePageDidLayoutForFrameCallback                                   didLayoutForFrame;
+    void *                                                                  didNewFirstVisuallyNonEmptyLayout_unavailable;
+    WKBundlePageDidDetectXSSForFrameCallback                                didDetectXSSForFrame;
+    WKBundlePageShouldGoToBackForwardListItemCallback                       shouldGoToBackForwardListItem;
+    WKBundlePageGlobalObjectIsAvailableForFrameCallback                     globalObjectIsAvailableForFrame;
+    WKBundlePageWillDisconnectDOMWindowExtensionFromGlobalObjectCallback    willDisconnectDOMWindowExtensionFromGlobalObject;
+    WKBundlePageDidReconnectDOMWindowExtensionToGlobalObjectCallback        didReconnectDOMWindowExtensionToGlobalObject;
+    WKBundlePageWillDestroyGlobalObjectForDOMWindowExtensionCallback        willDestroyGlobalObjectForDOMWindowExtension;
+
+    // Version 2
+    WKBundlePageDidFinishProgressCallback                                   didFinishProgress;
+    WKBundlePageShouldForceUniversalAccessFromLocalURLCallback              shouldForceUniversalAccessFromLocalURL;
+
+    // Version 3
+    void *                                                                  didReceiveIntentForFrame_unavailable;
+    void *                                                                  registerIntentServiceForFrame_unavailable;
+
+    // Version 4
+    WKBundlePageDidLayoutCallback                                           didLayout;
+
+    // Version 5
+    WKBundlePageFeaturesUsedInPageCallback                                  featuresUsedInPage;
+
+    // Version 6
+    WKBundlePageWillLoadURLRequestCallback                                  willLoadURLRequest;
+    WKBundlePageWillLoadDataRequestCallback                                 willLoadDataRequest;
+
+    // Version 7
+    void *                                                                  willDestroyFrame_unavailable;
+
+    // Version 8
+    WKBundlePageUserAgentForURLCallback                                     userAgentForURL;
+
+    // Version 9
+    WKBundlePageWillInjectUserScriptForFrameCallback                        willInjectUserScriptForFrame;
+} WKBundlePageLoaderClientV9;
+
 #endif // WKBundlePageLoaderClient_h
index 577398a..1935322 100644 (file)
@@ -232,7 +232,7 @@ static WKStringRef userAgentForURL(WKBundleFrameRef frame, WKURLRef url, const v
 
 static void setUpPageLoaderClient(WKWebProcessPlugInBrowserContextController *contextController, WebPage& page)
 {
-    WKBundlePageLoaderClientV8 client;
+    WKBundlePageLoaderClientV9 client;
     memset(&client, 0, sizeof(client));
 
     client.base.version = 8;
index e41e831..b6f3800 100644 (file)
@@ -303,11 +303,20 @@ void InjectedBundlePageLoaderClient::globalObjectIsAvailableForFrame(WebPage& pa
 {
     if (!m_client.globalObjectIsAvailableForFrame)
         return;
-    
+
     RefPtr<InjectedBundleScriptWorld> injectedWorld = InjectedBundleScriptWorld::getOrCreate(world);
     m_client.globalObjectIsAvailableForFrame(toAPI(&page), toAPI(&frame), toAPI(injectedWorld.get()), m_client.base.clientInfo);
 }
 
+void InjectedBundlePageLoaderClient::willInjectUserScriptForFrame(WebPage& page, WebFrame& frame, DOMWrapperWorld& world)
+{
+    if (!m_client.willInjectUserScriptForFrame)
+        return;
+
+    RefPtr<InjectedBundleScriptWorld> injectedWorld = InjectedBundleScriptWorld::getOrCreate(world);
+    m_client.willInjectUserScriptForFrame(toAPI(&page), toAPI(&frame), toAPI(injectedWorld.get()), m_client.base.clientInfo);
+}
+
 void InjectedBundlePageLoaderClient::willDisconnectDOMWindowExtensionFromGlobalObject(WebPage& page, DOMWindowExtension* coreExtension)
 {
     if (!m_client.willDisconnectDOMWindowExtensionFromGlobalObject)
index a90ed60..4935661 100644 (file)
@@ -37,7 +37,7 @@ class String;
 class URL;
 
 template<> struct ClientTraits<WKBundlePageLoaderClientBase> {
-    typedef std::tuple<WKBundlePageLoaderClientV0, WKBundlePageLoaderClientV1, WKBundlePageLoaderClientV2, WKBundlePageLoaderClientV3, WKBundlePageLoaderClientV4, WKBundlePageLoaderClientV5, WKBundlePageLoaderClientV6, WKBundlePageLoaderClientV7, WKBundlePageLoaderClientV8> Versions;
+    typedef std::tuple<WKBundlePageLoaderClientV0, WKBundlePageLoaderClientV1, WKBundlePageLoaderClientV2, WKBundlePageLoaderClientV3, WKBundlePageLoaderClientV4, WKBundlePageLoaderClientV5, WKBundlePageLoaderClientV6, WKBundlePageLoaderClientV7, WKBundlePageLoaderClientV8, WKBundlePageLoaderClientV9> Versions;
 };
 }
 
@@ -81,6 +81,8 @@ public:
     void didReconnectDOMWindowExtensionToGlobalObject(WebPage&, WebCore::DOMWindowExtension*) override;
     void willDestroyGlobalObjectForDOMWindowExtension(WebPage&, WebCore::DOMWindowExtension*) override;
 
+    void willInjectUserScriptForFrame(WebKit::WebPage&, WebKit::WebFrame&, WebCore::DOMWrapperWorld&) final;
+
     bool shouldForceUniversalAccessFromLocalURL(WebPage&, const WTF::String&) override;
 
     void featuresUsedInPage(WebPage&, const Vector<WTF::String>&) override;
index 8430fb6..5777c2b 100644 (file)
@@ -1691,7 +1691,6 @@ void WebFrameLoaderClient::dispatchDidClearWindowObjectInWorld(DOMWrapperWorld&
 #endif
 }
 
-
 void WebFrameLoaderClient::dispatchGlobalObjectAvailable(DOMWrapperWorld& world)
 {
     WebPage* webPage = m_frame->page();
@@ -1701,6 +1700,15 @@ void WebFrameLoaderClient::dispatchGlobalObjectAvailable(DOMWrapperWorld& world)
     webPage->injectedBundleLoaderClient().globalObjectIsAvailableForFrame(*webPage, *m_frame, world);
 }
 
+void WebFrameLoaderClient::willInjectUserScript(DOMWrapperWorld& world)
+{
+    WebPage* webPage = m_frame->page();
+    if (!webPage)
+        return;
+
+    webPage->injectedBundleLoaderClient().willInjectUserScriptForFrame(*webPage, *m_frame, world);
+}
+
 void WebFrameLoaderClient::dispatchWillDisconnectDOMWindowExtensionFromGlobalObject(WebCore::DOMWindowExtension* extension)
 {
     WebPage* webPage = m_frame->page();
index 63cbb12..c80afc2 100644 (file)
@@ -232,7 +232,9 @@ private:
     void dispatchWillDisconnectDOMWindowExtensionFromGlobalObject(WebCore::DOMWindowExtension*) final;
     void dispatchDidReconnectDOMWindowExtensionToGlobalObject(WebCore::DOMWindowExtension*) final;
     void dispatchWillDestroyGlobalObjectForDOMWindowExtension(WebCore::DOMWindowExtension*) final;
-    
+
+    void willInjectUserScript(WebCore::DOMWrapperWorld&) final;
+
 #if PLATFORM(COCOA)
     RemoteAXObjectRef accessibilityRemoteObject() final;
     
index 3f6908f..845d258 100644 (file)
@@ -1,3 +1,34 @@
+2018-07-12  Youenn Fablet  <youenn@apple.com>
+
+        Add a FrameLoaderClient willInjectUserScriptForFrame callback
+        https://bugs.webkit.org/show_bug.cgi?id=187565
+
+        Reviewed by Alex Christensen.
+
+        Added new test runner API to check for willInjectUserScriptForFrame callback.
+
+        * WebKitTestRunner/InjectedBundle/Bindings/TestRunner.idl:
+        * WebKitTestRunner/InjectedBundle/InjectedBundle.h:
+        (WTR::InjectedBundle::resetUserScriptInjectedCount):
+        (WTR::InjectedBundle::increaseUserScriptInjectedCount):
+        (WTR::InjectedBundle::userScriptInjectedCount const):
+        * WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp:
+        (WTR::InjectedBundlePage::InjectedBundlePage):
+        (WTR::InjectedBundlePage::resetAfterTest):
+        (WTR::InjectedBundlePage::willInjectUserScriptForFrame):
+        * WebKitTestRunner/InjectedBundle/InjectedBundlePage.h:
+        * WebKitTestRunner/InjectedBundle/TestRunner.cpp:
+        (WTR::TestRunner::userScriptInjectedCount const):
+        (WTR::TestRunner::injectUserScript):
+        * WebKitTestRunner/InjectedBundle/TestRunner.h:
+        * WebKitTestRunner/TestController.cpp:
+        (WTR::TestController::injectUserScript):
+        * WebKitTestRunner/TestController.h:
+        * WebKitTestRunner/TestInvocation.cpp:
+        (WTR::TestInvocation::didReceiveSynchronousMessageFromInjectedBundle):
+        * WebKitTestRunner/cocoa/TestControllerCocoa.mm:
+        (WTR::TestController::injectUserScript):
+
 2018-07-12  Sihui Liu  <sihui_liu@apple.com>
 
         IndexedDB: database file of subframe cannot be removed
index e6aa49e..6c4b989 100644 (file)
@@ -343,4 +343,7 @@ interface TestRunner {
     void clearMockMediaDevices();
     void removeMockMediaDevice(DOMString persistentId);
     void resetMockMediaDevices();
+
+    void injectUserScript(DOMString string);
+    readonly attribute unsigned long userScriptInjectedCount;
 };
index 7307b6c..6d4ded8 100644 (file)
@@ -140,6 +140,10 @@ public:
     void textFieldDidBeginEditing();
     void textFieldDidEndEditing();
 
+    void resetUserScriptInjectedCount() { m_userScriptInjectedCount = 0; }
+    void increaseUserScriptInjectedCount() { ++m_userScriptInjectedCount; }
+    size_t userScriptInjectedCount() const { return m_userScriptInjectedCount; }
+
 private:
     InjectedBundle();
     ~InjectedBundle();
@@ -199,6 +203,8 @@ private:
     WKRetainPtr<WKArrayRef> m_repaintRects;
 
     Vector<String> m_allowedHosts;
+
+    size_t m_userScriptInjectedCount { 0 };
 };
 
 } // namespace WTR
index 6427fda..0f5865f 100644 (file)
@@ -274,8 +274,8 @@ InjectedBundlePage::InjectedBundlePage(WKBundlePageRef page)
     : m_page(page)
     , m_world(AdoptWK, WKBundleScriptWorldCreateWorld())
 {
-    WKBundlePageLoaderClientV8 loaderClient = {
-        { 8, this },
+    WKBundlePageLoaderClientV9 loaderClient = {
+        { 9, this },
         didStartProvisionalLoadForFrame,
         didReceiveServerRedirectForProvisionalLoadForFrame,
         didFailProvisionalLoadWithErrorForFrame,
@@ -312,6 +312,7 @@ InjectedBundlePage::InjectedBundlePage(WKBundlePageRef page)
         0, // willLoadDataRequest
         0, // willDestroyFrame_unavailable
         0, // userAgentForURL
+        willInjectUserScriptForFrame
     };
     WKBundlePageSetPageLoaderClient(m_page, &loaderClient.base);
 
@@ -443,6 +444,8 @@ void InjectedBundlePage::resetAfterTest()
     WKBundlePageRemoveAllUserContent(m_page);
 
     uninstallFakeHelvetica();
+
+    InjectedBundle::singleton().resetUserScriptInjectedCount();
 }
 
 // Loader Client Callbacks
@@ -592,6 +595,11 @@ void InjectedBundlePage::didFinishProgress(WKBundlePageRef, const void *clientIn
     static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didFinishProgress();
 }
 
+void InjectedBundlePage::willInjectUserScriptForFrame(WKBundlePageRef, WKBundleFrameRef, WKBundleScriptWorldRef, const void* clientInfo)
+{
+    static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->willInjectUserScriptForFrame();
+}
+
 void InjectedBundlePage::didFinishDocumentLoadForFrame(WKBundlePageRef page, WKBundleFrameRef frame, WKTypeRef*, const void* clientInfo)
 {
     static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didFinishDocumentLoadForFrame(frame);
@@ -759,6 +767,11 @@ void InjectedBundlePage::didFinishProgress()
     injectedBundle.outputText("postProgressFinishedNotification\n");
 }
 
+void InjectedBundlePage::willInjectUserScriptForFrame()
+{
+    InjectedBundle::singleton().increaseUserScriptInjectedCount();
+}
+
 enum FrameNamePolicy { ShouldNotIncludeFrameName, ShouldIncludeFrameName };
 
 static void dumpFrameScrollPosition(WKBundleFrameRef frame, StringBuilder& stringBuilder, FrameNamePolicy shouldIncludeFrameName = ShouldNotIncludeFrameName)
index 30e375c..1c153d4 100644 (file)
@@ -77,6 +77,7 @@ private:
     static void didFinishLoadForResource(WKBundlePageRef, WKBundleFrameRef, uint64_t identifier, const void*);
     static void didFailLoadForResource(WKBundlePageRef, WKBundleFrameRef, uint64_t identifier, WKErrorRef, const void*);
     static bool shouldCacheResponse(WKBundlePageRef, WKBundleFrameRef, uint64_t identifier, const void*);
+    static void willInjectUserScriptForFrame(WKBundlePageRef, WKBundleFrameRef, WKBundleScriptWorldRef, const void*);
 
     void didStartProvisionalLoadForFrame(WKBundleFrameRef);
     void didReceiveServerRedirectForProvisionalLoadForFrame(WKBundleFrameRef);
@@ -95,6 +96,7 @@ private:
     void didDisplayInsecureContentForFrame(WKBundleFrameRef);
     void didRunInsecureContentForFrame(WKBundleFrameRef);
     void didDetectXSSForFrame(WKBundleFrameRef);
+    void willInjectUserScriptForFrame();
 
     // Resource Load Client
     void didInitiateLoadForResource(WKBundlePageRef, WKBundleFrameRef, uint64_t identifier, WKURLRequestRef, bool pageLoadIsProvisional);
index 4dfa758..b3af72a 100644 (file)
@@ -2267,4 +2267,17 @@ void TestRunner::didGetApplicationManifest()
     callTestRunnerCallback(GetApplicationManifestCallbackID);
 }
 
+size_t TestRunner::userScriptInjectedCount() const
+{
+    return InjectedBundle::singleton().userScriptInjectedCount();
+}
+
+void TestRunner::injectUserScript(JSStringRef script)
+{
+    WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("InjectUserScript"));
+    WKRetainPtr<WKStringRef> messageBody(AdoptWK, WKStringCreateWithJSString(script));
+    WKTypeRef returnData = 0;
+    WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get(), &returnData);
+}
+
 } // namespace WTR
index 371e1df..2639b4e 100644 (file)
@@ -454,6 +454,9 @@ public:
     void removeMockMediaDevice(JSStringRef persistentId);
     void resetMockMediaDevices();
 
+    size_t userScriptInjectedCount() const;
+    void injectUserScript(JSStringRef);
+
 private:
     TestRunner();
 
index c16df4e..e772aeb 100644 (file)
@@ -2912,6 +2912,11 @@ void TestController::resetMockMediaDevices()
 void TestController::platformAddTestOptions(TestOptions&) const
 {
 }
+
+void TestController::injectUserScript(WKStringRef)
+{
+}
+
 #endif
 
 } // namespace WTR
index 4adebd6..519bfb7 100644 (file)
@@ -218,6 +218,8 @@ public:
     void removeMockMediaDevice(WKStringRef persistentID);
     void resetMockMediaDevices();
 
+    void injectUserScript(WKStringRef);
+
 private:
     WKRetainPtr<WKPageConfigurationRef> generatePageConfiguration(WKContextConfigurationRef);
     WKRetainPtr<WKContextConfigurationRef> generateContextConfiguration() const;
index fe24a01..9eadd2c 100644 (file)
@@ -1414,6 +1414,13 @@ WKRetainPtr<WKTypeRef> TestInvocation::didReceiveSynchronousMessageFromInjectedB
         return result;
     }
 
+    if (WKStringIsEqualToUTF8CString(messageName, "InjectUserScript")) {
+        ASSERT(WKGetTypeID(messageBody) == WKStringGetTypeID());
+        WKStringRef script = static_cast<WKStringRef>(messageBody);
+
+        TestController::singleton().injectUserScript(script);
+    }
+
     if (WKStringIsEqualToUTF8CString(messageName, "GetApplicationManifest")) {
 #ifdef __BLOCKS__
         WKPageGetApplicationManifest_b(TestController::singleton().mainWebView()->page(), ^{
index c7b7adc..a4d511c 100644 (file)
@@ -280,4 +280,13 @@ void TestController::getAllStorageAccessEntries()
 #endif
 }
 
+void TestController::injectUserScript(WKStringRef script)
+{
+#if WK_API_ENABLED
+    auto userScript = adoptNS([[WKUserScript alloc] initWithSource: toWTFString(script) injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:NO]);
+
+    [[globalWebViewConfiguration userContentController] addUserScript: userScript.get()];
+#endif
+}
+
 } // namespace WTR