Add SPI for immediate injection of user scripts
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 14 Jun 2017 19:51:00 +0000 (19:51 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 14 Jun 2017 19:51:00 +0000 (19:51 +0000)
https://bugs.webkit.org/show_bug.cgi?id=173342
<rdar://problem/29202285>

Patch by Alex Christensen <achristensen@webkit.org> on 2017-06-14
Reviewed by Brady Eidson.

Source/WebCore:

The new SPI is WKUserContentController._addUserScriptImmediately.
It is covered by new API tests.

* page/Frame.cpp:
(WebCore::Frame::injectUserScripts):
(WebCore::Frame::injectUserScriptImmediately):
Move injection functionality to allow us to call it directly from the new SPI.
* page/Frame.h:
* page/Page.cpp:
(WebCore::Page::forEachPage):
* page/Page.h:

Source/WebKit2:

* UIProcess/API/C/WKPageGroup.cpp:
(WKPageGroupAddUserScript):
* UIProcess/API/C/WKUserContentControllerRef.cpp:
(WKUserContentControllerAddUserScript):
* UIProcess/API/Cocoa/WKUserContentController.mm:
(-[WKUserContentController addUserScript:]):
(-[WKUserContentController _addUserScriptImmediately:]):
* UIProcess/API/Cocoa/WKUserContentControllerPrivate.h:
* UIProcess/UserContent/WebUserContentControllerProxy.cpp:
(WebKit::WebUserContentControllerProxy::addUserScript):
* UIProcess/UserContent/WebUserContentControllerProxy.h:
* WebProcess/UserContent/WebUserContentController.cpp:
(WebKit::WebUserContentController::addUserScripts):
(WebKit::WebUserContentController::addUserScriptInternal):
If we are to inject the script internally, inject it into the appropriate pages.
If we're injecting into the top frame only, there's no need to traverse the frame tree.
(WebKit::WebUserContentController::addUserScript):
* WebProcess/UserContent/WebUserContentController.h:
* WebProcess/UserContent/WebUserContentController.messages.in:
* WebProcess/WebPage/WebPage.cpp:
(WebKit::m_cpuLimit):

Tools:

* TestWebKitAPI/Tests/WebKit2Cocoa/UserContentController.mm:
(waitForMessage):
(TEST):

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

22 files changed:
Source/WebCore/ChangeLog
Source/WebCore/page/Frame.cpp
Source/WebCore/page/Frame.h
Source/WebCore/page/Page.cpp
Source/WebCore/page/Page.h
Source/WebKit2/ChangeLog
Source/WebKit2/Shared/WebUserContentControllerDataTypes.h
Source/WebKit2/UIProcess/API/C/WKPageGroup.cpp
Source/WebKit2/UIProcess/API/C/WKUserContentControllerRef.cpp
Source/WebKit2/UIProcess/API/Cocoa/WKUserContentController.mm
Source/WebKit2/UIProcess/API/Cocoa/WKUserContentControllerPrivate.h
Source/WebKit2/UIProcess/API/gtk/WebKitUserContentManager.cpp
Source/WebKit2/UIProcess/UserContent/WebUserContentControllerProxy.cpp
Source/WebKit2/UIProcess/UserContent/WebUserContentControllerProxy.h
Source/WebKit2/WebKit2.xcodeproj/project.pbxproj
Source/WebKit2/WebProcess/UserContent/AddUserScriptImmediately.h [new file with mode: 0644]
Source/WebKit2/WebProcess/UserContent/WebUserContentController.cpp
Source/WebKit2/WebProcess/UserContent/WebUserContentController.h
Source/WebKit2/WebProcess/UserContent/WebUserContentController.messages.in
Source/WebKit2/WebProcess/WebPage/WebPage.cpp
Tools/ChangeLog
Tools/TestWebKitAPI/Tests/WebKit2Cocoa/UserContentController.mm

index 746eb0d..fde5afc 100644 (file)
@@ -1,3 +1,23 @@
+2017-06-14  Alex Christensen  <achristensen@webkit.org>
+
+        Add SPI for immediate injection of user scripts
+        https://bugs.webkit.org/show_bug.cgi?id=173342
+        <rdar://problem/29202285>
+
+        Reviewed by Brady Eidson.
+
+        The new SPI is WKUserContentController._addUserScriptImmediately.
+        It is covered by new API tests.
+
+        * page/Frame.cpp:
+        (WebCore::Frame::injectUserScripts):
+        (WebCore::Frame::injectUserScriptImmediately):
+        Move injection functionality to allow us to call it directly from the new SPI.
+        * page/Frame.h:
+        * page/Page.cpp:
+        (WebCore::Page::forEachPage):
+        * page/Page.h:
+
 2017-06-14  Zalan Bujtas  <zalan@apple.com>
 
         Crash in WebCore::RenderStyle::colorIncludingFallback.
index 96ac904..de08f13 100644 (file)
@@ -707,20 +707,25 @@ void Frame::injectUserScripts(UserScriptInjectionTime injectionTime)
         return;
 
     m_page->userContentProvider().forEachUserScript([this, protectedThis = makeRef(*this), injectionTime](DOMWrapperWorld& world, const UserScript& script) {
-        auto* document = this->document();
-        if (!document)
-            return;
-        if (script.injectedFrames() == InjectInTopFrameOnly && ownerElement())
-            return;
-
-        if (script.injectionTime() == injectionTime && UserContentURLPattern::matchesPatterns(document->url(), script.whitelist(), script.blacklist())) {
-            if (m_page)
-                m_page->setAsRunningUserScripts();
-            m_script->evaluateInWorld(ScriptSourceCode(script.source(), script.url()), world);
-        }
+        if (script.injectionTime() == injectionTime)
+            injectUserScriptImmediately(world, script);
     });
 }
 
+void Frame::injectUserScriptImmediately(DOMWrapperWorld& world, const UserScript& script)
+{
+    auto* document = this->document();
+    if (!document)
+        return;
+    if (script.injectedFrames() == InjectInTopFrameOnly && !isMainFrame())
+        return;
+    if (!UserContentURLPattern::matchesPatterns(document->url(), script.whitelist(), script.blacklist()))
+        return;
+    if (m_page)
+        m_page->setAsRunningUserScripts();
+    m_script->evaluateInWorld(ScriptSourceCode(script.source(), script.url()), world);
+}
+
 RenderView* Frame::contentRenderer() const
 {
     return document() ? document()->renderView() : nullptr;
index 65999c3..1d94da8 100644 (file)
@@ -165,7 +165,8 @@ public:
 
 // ======== All public functions below this point are candidates to move out of Frame into another class. ========
 
-    void injectUserScripts(UserScriptInjectionTime);
+    WEBCORE_EXPORT void injectUserScripts(UserScriptInjectionTime);
+    WEBCORE_EXPORT void injectUserScriptImmediately(DOMWrapperWorld&, const UserScript&);
     
     WEBCORE_EXPORT String layerTreeAsText(LayerTreeFlags = 0) const;
     WEBCORE_EXPORT String trackedRepaintRectsAsText() const;
index 1f90c6a..c793aed 100644 (file)
@@ -150,7 +150,7 @@ static inline bool isUtilityPageChromeClient(ChromeClient& chromeClient)
 
 DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, pageCounter, ("Page"));
 
-void Page::forEachPage(std::function<void(Page&)> function)
+void Page::forEachPage(Function<void(Page&)>&& function)
 {
     if (!allPages)
         return;
index 514f0a2..fdc0744 100644 (file)
@@ -193,7 +193,7 @@ public:
 
     PageGroup& group();
 
-    static void forEachPage(std::function<void(Page&)>);
+    WEBCORE_EXPORT static void forEachPage(WTF::Function<void(Page&)>&&);
 
     void incrementSubframeCount() { ++m_subframeCount; }
     void decrementSubframeCount() { ASSERT(m_subframeCount); --m_subframeCount; }
@@ -515,7 +515,7 @@ public:
 
     PluginInfoProvider& pluginInfoProvider();
 
-    UserContentProvider& userContentProvider();
+    WEBCORE_EXPORT UserContentProvider& userContentProvider();
     WEBCORE_EXPORT void setUserContentProvider(Ref<UserContentProvider>&&);
 
     VisitedLinkStore& visitedLinkStore();
index b7910c7..0d59e03 100644 (file)
@@ -1,3 +1,33 @@
+2017-06-14  Alex Christensen  <achristensen@webkit.org>
+
+        Add SPI for immediate injection of user scripts
+        https://bugs.webkit.org/show_bug.cgi?id=173342
+        <rdar://problem/29202285>
+
+        Reviewed by Brady Eidson.
+
+        * UIProcess/API/C/WKPageGroup.cpp:
+        (WKPageGroupAddUserScript):
+        * UIProcess/API/C/WKUserContentControllerRef.cpp:
+        (WKUserContentControllerAddUserScript):
+        * UIProcess/API/Cocoa/WKUserContentController.mm:
+        (-[WKUserContentController addUserScript:]):
+        (-[WKUserContentController _addUserScriptImmediately:]):
+        * UIProcess/API/Cocoa/WKUserContentControllerPrivate.h:
+        * UIProcess/UserContent/WebUserContentControllerProxy.cpp:
+        (WebKit::WebUserContentControllerProxy::addUserScript):
+        * UIProcess/UserContent/WebUserContentControllerProxy.h:
+        * WebProcess/UserContent/WebUserContentController.cpp:
+        (WebKit::WebUserContentController::addUserScripts):
+        (WebKit::WebUserContentController::addUserScriptInternal):
+        If we are to inject the script internally, inject it into the appropriate pages.
+        If we're injecting into the top frame only, there's no need to traverse the frame tree.
+        (WebKit::WebUserContentController::addUserScript):
+        * WebProcess/UserContent/WebUserContentController.h:
+        * WebProcess/UserContent/WebUserContentController.messages.in:
+        * WebProcess/WebPage/WebPage.cpp:
+        (WebKit::m_cpuLimit):
+
 2017-06-14  Jonathan Bedard  <jbedard@apple.com>
 
         Configure screen scale for running layout tests on plus devices
index e29593b..0cc1f5b 100644 (file)
@@ -23,8 +23,7 @@
  * THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#ifndef WebUserContentControllerDataTypes_h
-#define WebUserContentControllerDataTypes_h
+#pragma once
 
 #include <WebCore/UserScript.h>
 #include <WebCore/UserStyleSheet.h>
@@ -64,5 +63,3 @@ struct WebScriptMessageHandlerData {
 };
 
 } // namespace WebKit
-
-#endif // WebUserContentControllerDataTypes_h
index 107834a..dec0d07 100644 (file)
 #include "APIUserContentWorld.h"
 #include "APIUserScript.h"
 #include "APIUserStyleSheet.h"
+#include "AddUserScriptImmediately.h"
 #include "WKAPICast.h"
 #include "WebPageGroup.h"
 #include "WebPreferences.h"
+#include "WebUserContentController.h"
 #include "WebUserContentControllerProxy.h"
 
 using namespace WebKit;
@@ -98,7 +100,7 @@ void WKPageGroupAddUserScript(WKPageGroupRef pageGroupRef, WKStringRef sourceRef
     
     auto url = baseURLString.isEmpty() ? WebCore::blankURL() : WebCore::URL(WebCore::URL(), baseURLString);
     Ref<API::UserScript> userScript = API::UserScript::create(WebCore::UserScript { WTFMove(source), WTFMove(url), whitelist ? whitelist->toStringVector() : Vector<String>(), blacklist ? blacklist->toStringVector() : Vector<String>(), toUserScriptInjectionTime(injectionTime), toUserContentInjectedFrames(injectedFrames) }, API::UserContentWorld::normalWorld());
-    toImpl(pageGroupRef)->userContentController().addUserScript(userScript.get());
+    toImpl(pageGroupRef)->userContentController().addUserScript(userScript.get(), AddUserScriptImmediately::No);
 }
 
 void WKPageGroupRemoveAllUserScripts(WKPageGroupRef pageGroupRef)
index b468774..aa539fa 100644 (file)
@@ -29,6 +29,7 @@
 #include "APIArray.h"
 #include "APIContentRuleList.h"
 #include "APIUserScript.h"
+#include "AddUserScriptImmediately.h"
 #include "WKAPICast.h"
 #include "WebUserContentControllerProxy.h"
 
@@ -52,7 +53,7 @@ WKArrayRef WKUserContentControllerCopyUserScripts(WKUserContentControllerRef use
 
 void WKUserContentControllerAddUserScript(WKUserContentControllerRef userContentControllerRef, WKUserScriptRef userScriptRef)
 {
-    toImpl(userContentControllerRef)->addUserScript(*toImpl(userScriptRef));
+    toImpl(userContentControllerRef)->addUserScript(*toImpl(userScriptRef), AddUserScriptImmediately::No);
 }
 
 void WKUserContentControllerRemoveAllUserScripts(WKUserContentControllerRef userContentControllerRef)
index 38f8c12..8affb97 100644 (file)
@@ -30,6 +30,7 @@
 
 #import "APISerializedScriptValue.h"
 #import "APIUserContentWorld.h"
+#import "AddUserScriptImmediately.h"
 #import "WKContentRuleListInternal.h"
 #import "WKFrameInfoInternal.h"
 #import "WKNSArray.h"
@@ -84,7 +85,7 @@
 
 - (void)addUserScript:(WKUserScript *)userScript
 {
-    _userContentControllerProxy->addUserScript(*userScript->_userScript);
+    _userContentControllerProxy->addUserScript(*userScript->_userScript, WebKit::AddUserScriptImmediately::No);
 }
 
 - (void)removeAllUserScripts
@@ -172,6 +173,11 @@ private:
     _userContentControllerProxy->removeAllUserScripts(*userContentWorld->_userContentWorld);
 }
 
+- (void)_addUserScriptImmediately:(WKUserScript *)userScript
+{
+    _userContentControllerProxy->addUserScript(*userScript->_userScript, WebKit::AddUserScriptImmediately::Yes);
+}
+
 - (void)_addUserContentFilter:(_WKUserContentFilter *)userContentFilter
 {
 #if ENABLE(CONTENT_EXTENSIONS)
index 4668d98..38c1ab9 100644 (file)
@@ -36,6 +36,7 @@
 
 - (void)_removeUserScript:(WKUserScript *)userScript WK_API_AVAILABLE(macosx(10.12), ios(10.0));
 - (void)_removeAllUserScriptsAssociatedWithUserContentWorld:(_WKUserContentWorld *)userContentWorld WK_API_AVAILABLE(macosx(10.12), ios(10.0));
+- (void)_addUserScriptImmediately:(WKUserScript *)userScript WK_API_AVAILABLE(macosx(WK_MAC_TBA), ios(WK_IOS_TBA));
 
 - (void)_addUserContentFilter:(_WKUserContentFilter *)userContentFilter WK_API_AVAILABLE(macosx(10.11), ios(9.0));
 - (void)_removeUserContentFilter:(NSString *)userContentFilterName WK_API_AVAILABLE(macosx(10.11), ios(9.0));
index 5c7d7af..b7fe837 100644 (file)
@@ -21,6 +21,7 @@
 #include "WebKitUserContentManager.h"
 
 #include "APISerializedScriptValue.h"
+#include "AddUserScriptImmediately.h"
 #include "WebKitJavascriptResultPrivate.h"
 #include "WebKitPrivate.h"
 #include "WebKitUserContentManagerPrivate.h"
@@ -159,7 +160,7 @@ void webkit_user_content_manager_add_script(WebKitUserContentManager* manager, W
 {
     g_return_if_fail(WEBKIT_IS_USER_CONTENT_MANAGER(manager));
     g_return_if_fail(script);
-    manager->priv->userContentController->addUserScript(webkitUserScriptGetUserScript(script));
+    manager->priv->userContentController->addUserScript(webkitUserScriptGetUserScript(script), AddUserScriptImmediately::No);
 }
 
 /**
index 7f86943..01df830 100644 (file)
@@ -30,6 +30,7 @@
 #include "APIUserContentWorld.h"
 #include "APIUserScript.h"
 #include "APIUserStyleSheet.h"
+#include "AddUserScriptImmediately.h"
 #include "DataReference.h"
 #include "WebPageCreationParameters.h"
 #include "WebProcessProxy.h"
@@ -154,7 +155,7 @@ void WebUserContentControllerProxy::removeUserContentWorldUses(HashCountedSet<Re
         process->send(Messages::WebUserContentController::RemoveUserContentWorlds(worldsToRemove), m_identifier);
 }
 
-void WebUserContentControllerProxy::addUserScript(API::UserScript& userScript)
+void WebUserContentControllerProxy::addUserScript(API::UserScript& userScript, AddUserScriptImmediately immediately)
 {
     Ref<API::UserContentWorld> world = userScript.userContentWorld();
 
@@ -163,7 +164,7 @@ void WebUserContentControllerProxy::addUserScript(API::UserScript& userScript)
     m_userScripts->elements().append(&userScript);
 
     for (WebProcessProxy* process : m_processes)
-        process->send(Messages::WebUserContentController::AddUserScripts({ { userScript.identifier(), world->identifier(), userScript.userScript() } }), m_identifier);
+        process->send(Messages::WebUserContentController::AddUserScripts({ { userScript.identifier(), world->identifier(), userScript.userScript() } }, immediately), m_identifier);
 }
 
 void WebUserContentControllerProxy::removeUserScript(API::UserScript& userScript)
index 469306a..fec9ffb 100644 (file)
@@ -57,6 +57,7 @@ class WebProcessProxy;
 class WebScriptMessageHandler;
 struct FrameInfoData;
 struct WebPageCreationParameters;
+enum class AddUserScriptImmediately;
 
 class WebUserContentControllerProxy : public API::ObjectImpl<API::Object::Type::UserContentController>, private IPC::MessageReceiver {
 public:
@@ -73,7 +74,7 @@ public:
     void removeProcess(WebProcessProxy&);
 
     API::Array& userScripts() { return m_userScripts.get(); }
-    void addUserScript(API::UserScript&);
+    void addUserScript(API::UserScript&, AddUserScriptImmediately);
     void removeUserScript(API::UserScript&);
     void removeAllUserScripts(API::UserContentWorld&);
     void removeAllUserScripts();
index d3f137a..486d3b1 100644 (file)
                5C7706731D111D8B0012700F /* WebSocketProvider.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = WebSocketProvider.cpp; path = Network/WebSocketProvider.cpp; sourceTree = "<group>"; };
                5C7C88DC1D0F41A0009D2F6D /* WebSocketProvider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WebSocketProvider.h; path = Network/WebSocketProvider.h; sourceTree = "<group>"; };
                5C85C7861C3F23C50061A4FA /* PendingDownload.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PendingDownload.cpp; path = NetworkProcess/Downloads/PendingDownload.cpp; sourceTree = "<group>"; };
+               5C92412D1EF1A67A005AF897 /* AddUserScriptImmediately.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AddUserScriptImmediately.h; sourceTree = "<group>"; };
                5C9E567F1DF7930900C9EE33 /* WebsitePolicies.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebsitePolicies.h; sourceTree = "<group>"; };
                5C9E56801DF7F05500C9EE33 /* WKWebsitePolicies.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WKWebsitePolicies.cpp; sourceTree = "<group>"; };
                5C9E56811DF7F05500C9EE33 /* WKWebsitePolicies.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WKWebsitePolicies.h; sourceTree = "<group>"; };
                1AAF08AA1926930B00B6390C /* UserContent */ = {
                        isa = PBXGroup;
                        children = (
+                               5C92412D1EF1A67A005AF897 /* AddUserScriptImmediately.h */,
                                1AAF08AB1926936700B6390C /* WebUserContentController.cpp */,
                                1AAF08AC1926936700B6390C /* WebUserContentController.h */,
                                1AAF08B419269E2400B6390C /* WebUserContentController.messages.in */,
diff --git a/Source/WebKit2/WebProcess/UserContent/AddUserScriptImmediately.h b/Source/WebKit2/WebProcess/UserContent/AddUserScriptImmediately.h
new file mode 100644 (file)
index 0000000..832fa41
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <wtf/EnumTraits.h>
+
+namespace WebKit {
+    
+enum class AddUserScriptImmediately { No, Yes };
+    
+}
+
+namespace WTF {
+
+template<> struct EnumTraits<WebKit::AddUserScriptImmediately> {
+    using values = EnumValues<
+    WebKit::AddUserScriptImmediately,
+    WebKit::AddUserScriptImmediately::No,
+    WebKit::AddUserScriptImmediately::Yes
+    >;
+};
+
+}
index a83158f..25b4919 100644 (file)
@@ -26,6 +26,7 @@
 #include "config.h"
 #include "WebUserContentController.h"
 
+#include "AddUserScriptImmediately.h"
 #include "DataReference.h"
 #include "FrameInfoData.h"
 #include "InjectedBundleScriptWorld.h"
@@ -36,6 +37,7 @@
 #include "WebUserContentControllerMessages.h"
 #include "WebUserContentControllerProxyMessages.h"
 #include <WebCore/DOMWrapperWorld.h>
+#include <WebCore/MainFrame.h>
 #include <WebCore/SecurityOriginData.h>
 #include <WebCore/SerializedScriptValue.h>
 #include <WebCore/UserStyleSheet.h>
@@ -122,7 +124,7 @@ void WebUserContentController::removeUserContentWorlds(const Vector<uint64_t>& w
     }
 }
 
-void WebUserContentController::addUserScripts(const Vector<WebUserScriptData>& userScripts)
+void WebUserContentController::addUserScripts(Vector<WebUserScriptData>&& userScripts, AddUserScriptImmediately immediately)
 {
     for (const auto& userScriptData : userScripts) {
         auto it = worldMap().find(userScriptData.worldIdentifier);
@@ -132,7 +134,7 @@ void WebUserContentController::addUserScripts(const Vector<WebUserScriptData>& u
         }
 
         UserScript script = userScriptData.userScript;
-        addUserScriptInternal(*it->value.first, userScriptData.identifier, WTFMove(script));
+        addUserScriptInternal(*it->value.first, userScriptData.identifier, WTFMove(script), immediately);
     }
 }
 
@@ -360,15 +362,31 @@ void WebUserContentController::removeAllContentRuleLists()
 }
 #endif
 
-void WebUserContentController::addUserScriptInternal(InjectedBundleScriptWorld& world, uint64_t userScriptIdentifier, UserScript&& userScript)
-{
+void WebUserContentController::addUserScriptInternal(InjectedBundleScriptWorld& world, uint64_t userScriptIdentifier, UserScript&& userScript, AddUserScriptImmediately immediately)
+{
+    if (immediately == AddUserScriptImmediately::Yes) {
+        Page::forEachPage([&] (Page& page) {
+            if (&page.userContentProvider() != this)
+                return;
+            
+            auto& mainFrame = page.mainFrame();
+            if (userScript.injectedFrames() == InjectInTopFrameOnly) {
+                mainFrame.injectUserScriptImmediately(world.coreWorld(), userScript);
+                return;
+            }
+
+            for (Frame* frame = &mainFrame; frame; frame = frame->tree().traverseNext(&mainFrame))
+                frame->injectUserScriptImmediately(world.coreWorld(), userScript);
+        });
+    }
+
     auto& scriptsInWorld = m_userScripts.ensure(&world, [] { return Vector<std::pair<uint64_t, WebCore::UserScript>>(); }).iterator->value;
     scriptsInWorld.append(std::make_pair(userScriptIdentifier, WTFMove(userScript)));
 }
 
 void WebUserContentController::addUserScript(InjectedBundleScriptWorld& world, UserScript&& userScript)
 {
-    addUserScriptInternal(world, 0, WTFMove(userScript));
+    addUserScriptInternal(world, 0, WTFMove(userScript), AddUserScriptImmediately::No);
 }
 
 void WebUserContentController::removeUserScriptWithURL(InjectedBundleScriptWorld& world, const URL& url)
index 9b72d96..2963aa4 100644 (file)
@@ -46,6 +46,7 @@ namespace WebKit {
 class InjectedBundleScriptWorld;
 class WebCompiledContentRuleListData;
 class WebUserMessageHandlerDescriptorProxy;
+enum class AddUserScriptImmediately;
 
 class WebUserContentController final : public WebCore::UserContentProvider, private IPC::MessageReceiver {
 public:
@@ -63,7 +64,7 @@ public:
     void removeAllUserContent();
 
     void addUserContentWorlds(const Vector<std::pair<uint64_t, String>>&);
-    void addUserScripts(const Vector<WebUserScriptData>&);
+    void addUserScripts(Vector<WebUserScriptData>&&, AddUserScriptImmediately);
     void addUserStyleSheets(const Vector<WebUserStyleSheetData>&);
     void addUserScriptMessageHandlers(const Vector<WebScriptMessageHandlerData>&);
 #if ENABLE(CONTENT_EXTENSIONS)
@@ -102,7 +103,7 @@ private:
     void removeAllContentRuleLists();
 #endif
 
-    void addUserScriptInternal(InjectedBundleScriptWorld&, uint64_t userScriptIdentifier, WebCore::UserScript&&);
+    void addUserScriptInternal(InjectedBundleScriptWorld&, uint64_t userScriptIdentifier, WebCore::UserScript&&, AddUserScriptImmediately);
     void removeUserScriptInternal(InjectedBundleScriptWorld&, uint64_t userScriptIdentifier);
     void addUserStyleSheetInternal(InjectedBundleScriptWorld&, uint64_t userStyleSheetIdentifier, WebCore::UserStyleSheet&&);
     void removeUserStyleSheetInternal(InjectedBundleScriptWorld&, uint64_t userStyleSheetIdentifier);
index 9ac7514..b5d4ca0 100644 (file)
@@ -27,7 +27,7 @@ messages -> WebUserContentController {
     AddUserContentWorlds(Vector<std::pair<uint64_t, String>> worlds);
     RemoveUserContentWorlds(Vector<uint64_t> worldIdentifiers);
 
-    AddUserScripts(Vector<struct WebKit::WebUserScriptData> userScripts);
+    AddUserScripts(Vector<struct WebKit::WebUserScriptData> userScripts, enum WebKit::AddUserScriptImmediately immediately);
     RemoveUserScript(uint64_t worldIdentifier, uint64_t identifier);
     RemoveAllUserScripts(Vector<uint64_t> worldIdentifiers);
 
index f52da8e..874fb48 100644 (file)
@@ -31,6 +31,7 @@
 #include "APIArray.h"
 #include "APIGeometry.h"
 #include "APIWebsitePolicies.h"
+#include "AddUserScriptImmediately.h"
 #include "AssistedNodeInformation.h"
 #include "DataReference.h"
 #include "DragControllerAction.h"
@@ -573,7 +574,7 @@ WebPage::WebPage(uint64_t pageID, WebPageCreationParameters&& parameters)
         registerURLSchemeHandler(iterator.value, iterator.key);
 
     m_userContentController->addUserContentWorlds(parameters.userContentWorlds);
-    m_userContentController->addUserScripts(parameters.userScripts);
+    m_userContentController->addUserScripts(WTFMove(parameters.userScripts), AddUserScriptImmediately::No);
     m_userContentController->addUserStyleSheets(parameters.userStyleSheets);
     m_userContentController->addUserScriptMessageHandlers(parameters.messageHandlers);
 #if ENABLE(CONTENT_EXTENSIONS)
index ef70370..32bc95c 100644 (file)
@@ -1,3 +1,15 @@
+2017-06-14  Alex Christensen  <achristensen@webkit.org>
+
+        Add SPI for immediate injection of user scripts
+        https://bugs.webkit.org/show_bug.cgi?id=173342
+        <rdar://problem/29202285>
+
+        Reviewed by Brady Eidson.
+
+        * TestWebKitAPI/Tests/WebKit2Cocoa/UserContentController.mm:
+        (waitForMessage):
+        (TEST):
+
 2017-06-14  Claudio Saavedra  <csaavedra@igalia.com>
 
         Add WPE to the flakiness dashboard
index 87d1d44..424cdd6 100644 (file)
@@ -140,6 +140,47 @@ TEST(WKUserContentController, ScriptMessageHandlerBasicPostIsolatedWorld)
     EXPECT_WK_STREQ(@"PASS", resultValue);
 }
 
+static void waitForMessage(const char* expectedMessage)
+{
+    TestWebKitAPI::Util::run(&receivedScriptMessage);
+    receivedScriptMessage = false;
+    EXPECT_STREQ(expectedMessage, [(NSString *)[lastScriptMessage body] UTF8String]);
+}
+
+TEST(WKUserContentController, AddUserScriptImmediately)
+{
+    RetainPtr<ScriptMessageHandler> handler = adoptNS([[ScriptMessageHandler alloc] init]);
+    RetainPtr<WKUserScript> startAllFrames = adoptNS([[WKUserScript alloc] initWithSource:@"window.webkit.messageHandlers.testHandler.postMessage('start all')" injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:NO]);
+    RetainPtr<WKUserScript> endMainFrameOnly = adoptNS([[WKUserScript alloc] initWithSource:@"window.webkit.messageHandlers.testHandler.postMessage('end main')" injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:YES]);
+    
+    RetainPtr<WKWebViewConfiguration> configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
+    [[configuration userContentController] addScriptMessageHandler:handler.get() name:@"testHandler"];
+    
+    RetainPtr<WKWebView> webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]);
+    
+    RetainPtr<SimpleNavigationDelegate> delegate = adoptNS([[SimpleNavigationDelegate alloc] init]);
+    [webView setNavigationDelegate:delegate.get()];
+    
+    NSURLRequest *request = [NSURLRequest requestWithURL:[[NSBundle mainBundle] URLForResource:@"simple-iframe" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]];
+    
+    isDoneWithNavigation = false;
+    [webView loadRequest:request];
+    TestWebKitAPI::Util::run(&isDoneWithNavigation);
+    
+    receivedScriptMessage = false;
+    [[configuration userContentController] _addUserScriptImmediately:startAllFrames.get()];
+    // simple-iframe.html has a main frame and one iframe.
+    waitForMessage("start all");
+    waitForMessage("start all");
+    [[configuration userContentController] _addUserScriptImmediately:endMainFrameOnly.get()];
+    waitForMessage("end main");
+    [webView reload];
+    waitForMessage("start all");
+    waitForMessage("end main");
+    // When reloading, an iframe doesn't exist before the document has started to load.
+    waitForMessage("start all");
+}
+
 TEST(WKUserContentController, ScriptMessageHandlerBasicRemove)
 {
     RetainPtr<ScriptMessageHandler> handler = adoptNS([[ScriptMessageHandler alloc] init]);