Add WKContentWorld SPI, and use it in JavaScript execution.
authorbeidson@apple.com <beidson@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 16 Jan 2020 05:41:03 +0000 (05:41 +0000)
committerbeidson@apple.com <beidson@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 16 Jan 2020 05:41:03 +0000 (05:41 +0000)
https://bugs.webkit.org/show_bug.cgi?id=206310

Reviewed by Alex Christensen.
Source/WebKit:

Covered by API tests.

_WKContentWorld is a UI Process wrapper for an InjectedBundleScriptWorld.
Much like _WKUserContentWorld is. But different in that:
- Its APIs are named different things
- Only one unique instance per string name
- It is used with evaluateJavascript: and callAsyncJavaScriptFunction: instead of WKUserContentController.

But _WKContentWorld and _WKUserContentWorld do have to work together a little bit to avoid conflicts in the WebProcess.

The new versions of evaluateJavascript: and callAsyncJavaScriptFunction: are also included, as well as API tests for all the new stuff.

* Shared/API/APIObject.h:
* Shared/Cocoa/APIObject.mm:
(API::Object::newObject):

* UIProcess/API/APIContentWorld.cpp: Copied from Source/WebKit/UIProcess/API/APIUserContentWorld.cpp.
(API::ContentWorld::sharedWorldWithName):
(API::ContentWorld::pageContentWorld):
(API::ContentWorld::defaultClientWorld):
(API::ContentWorld::ContentWorld):
(API::ContentWorld::~ContentWorld):
* UIProcess/API/APIContentWorld.h: Copied from Source/WebKit/UIProcess/API/APIUserContentWorld.h.

* UIProcess/API/APIUserContentWorld.cpp:
(API::UserContentWorld::generateIdentifier):
(API::UserContentWorld::UserContentWorld):
(API::generateIdentifier): Deleted.
* UIProcess/API/APIUserContentWorld.h:

* UIProcess/API/Cocoa/WKWebView.mm:
(-[WKWebView evaluateJavaScript:completionHandler:]):
(-[WKWebView _evaluateJavaScript:asAsyncFunction:withArguments:forceUserGesture:completionHandler:inWorld:]):
(-[WKWebView _callAsyncJavaScriptFunction:withArguments:inWorld:completionHandler:]):
(-[WKWebView _evaluateJavaScript:inWorld:completionHandler:]):
(-[WKWebView _evaluateJavaScriptWithoutUserGesture:completionHandler:]):
(-[WKWebView _evaluateJavaScript:asAsyncFunction:withArguments:forceUserGesture:completionHandler:]): Deleted.
(-[WKWebView _callAsyncFunction:withArguments:completionHandler:]): Deleted.
* UIProcess/API/Cocoa/WKWebViewPrivate.h:

* UIProcess/API/Cocoa/_WKContentWorld.h: Added.
* UIProcess/API/Cocoa/_WKContentWorld.mm: Copied from Source/WebKit/UIProcess/API/APIUserContentWorld.h.
(+[_WKContentWorld pageContentWorld]):
(+[_WKContentWorld defaultClientWorld]):
(+[_WKContentWorld worldWithName:]):
(-[_WKContentWorld dealloc]):
(-[_WKContentWorld name]):
(-[_WKContentWorld _apiObject]):
* UIProcess/API/Cocoa/_WKContentWorldInternal.h: Copied from Source/WebKit/UIProcess/API/APIUserContentWorld.h.

* UIProcess/UserContent/WebUserContentControllerProxy.cpp:
* UIProcess/UserContent/WebUserContentControllerProxy.h:

* UIProcess/WebPageProxy.cpp:
(WebKit::WebPageProxy::runJavaScriptInMainFrame):
(WebKit::WebPageProxy::runJavaScriptInMainFrameScriptWorld):
* UIProcess/WebPageProxy.h:

* WebProcess/UserContent/WebUserContentController.cpp:
(WebKit::worldMap):
(WebKit::WebUserContentController::worldForIdentifier):
(WebKit::WebUserContentController::addUserContentWorld):
(WebKit::WebUserContentController::addUserContentWorlds):
* WebProcess/UserContent/WebUserContentController.h:

* WebProcess/WebPage/WebPage.cpp:
(WebKit::WebPage::runJavaScript):
(WebKit::WebPage::runJavaScriptInMainFrameScriptWorld):
(WebKit::WebPage::runJavaScriptInFrame):
* WebProcess/WebPage/WebPage.h:
* WebProcess/WebPage/WebPage.messages.in:

* Sources.txt:
* WebKit.xcodeproj/project.pbxproj:

Tools:

Update previous callAsyncFunction calls with the new signature.
Add tests for new _WKContentWorld class and its behavior with regard to executing JavaScript.

* TestWebKitAPI/Tests/WebKitCocoa/AsyncFunction.mm:
(TestWebKitAPI::tryGCPromise):
(TestWebKitAPI::TEST):
* TestWebKitAPI/Tests/WebKitCocoa/WKWebViewEvaluateJavaScript.mm:
(TEST):
* TestWebKitAPI/cocoa/TestWKWebView.mm:
(-[WKWebView objectByCallingAsyncFunction:withArguments:error:]):

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

28 files changed:
Source/WebKit/ChangeLog
Source/WebKit/Shared/API/APIObject.h
Source/WebKit/Shared/Cocoa/APIObject.mm
Source/WebKit/Sources.txt
Source/WebKit/UIProcess/API/APIContentWorld.cpp [new file with mode: 0644]
Source/WebKit/UIProcess/API/APIContentWorld.h [new file with mode: 0644]
Source/WebKit/UIProcess/API/APIUserContentWorld.cpp
Source/WebKit/UIProcess/API/APIUserContentWorld.h
Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm
Source/WebKit/UIProcess/API/Cocoa/WKWebViewPrivate.h
Source/WebKit/UIProcess/API/Cocoa/_WKContentWorld.h [new file with mode: 0644]
Source/WebKit/UIProcess/API/Cocoa/_WKContentWorld.mm [new file with mode: 0644]
Source/WebKit/UIProcess/API/Cocoa/_WKContentWorldInternal.h [new file with mode: 0644]
Source/WebKit/UIProcess/API/glib/WebKitWebView.cpp
Source/WebKit/UIProcess/UserContent/WebUserContentControllerProxy.cpp
Source/WebKit/UIProcess/UserContent/WebUserContentControllerProxy.h
Source/WebKit/UIProcess/WebPageProxy.cpp
Source/WebKit/UIProcess/WebPageProxy.h
Source/WebKit/WebKit.xcodeproj/project.pbxproj
Source/WebKit/WebProcess/UserContent/WebUserContentController.cpp
Source/WebKit/WebProcess/UserContent/WebUserContentController.h
Source/WebKit/WebProcess/WebPage/WebPage.cpp
Source/WebKit/WebProcess/WebPage/WebPage.h
Source/WebKit/WebProcess/WebPage/WebPage.messages.in
Tools/ChangeLog
Tools/TestWebKitAPI/Tests/WebKitCocoa/AsyncFunction.mm
Tools/TestWebKitAPI/Tests/WebKitCocoa/WKWebViewEvaluateJavaScript.mm
Tools/TestWebKitAPI/cocoa/TestWKWebView.mm

index ed3f812..46e980a 100644 (file)
@@ -1,3 +1,85 @@
+2020-01-15  Brady Eidson  <beidson@apple.com>
+
+        Add WKContentWorld SPI, and use it in JavaScript execution.
+        https://bugs.webkit.org/show_bug.cgi?id=206310
+
+        Reviewed by Alex Christensen.
+
+        Covered by API tests.
+        
+        _WKContentWorld is a UI Process wrapper for an InjectedBundleScriptWorld.
+        Much like _WKUserContentWorld is. But different in that:
+        - Its APIs are named different things
+        - Only one unique instance per string name
+        - It is used with evaluateJavascript: and callAsyncJavaScriptFunction: instead of WKUserContentController.
+        
+        But _WKContentWorld and _WKUserContentWorld do have to work together a little bit to avoid conflicts in the WebProcess.
+        
+        The new versions of evaluateJavascript: and callAsyncJavaScriptFunction: are also included, as well as API tests for all the new stuff.
+
+        * Shared/API/APIObject.h:
+        * Shared/Cocoa/APIObject.mm:
+        (API::Object::newObject):
+
+        * UIProcess/API/APIContentWorld.cpp: Copied from Source/WebKit/UIProcess/API/APIUserContentWorld.cpp.
+        (API::ContentWorld::sharedWorldWithName):
+        (API::ContentWorld::pageContentWorld):
+        (API::ContentWorld::defaultClientWorld):
+        (API::ContentWorld::ContentWorld):
+        (API::ContentWorld::~ContentWorld):
+        * UIProcess/API/APIContentWorld.h: Copied from Source/WebKit/UIProcess/API/APIUserContentWorld.h.
+
+        * UIProcess/API/APIUserContentWorld.cpp:
+        (API::UserContentWorld::generateIdentifier):
+        (API::UserContentWorld::UserContentWorld):
+        (API::generateIdentifier): Deleted.
+        * UIProcess/API/APIUserContentWorld.h:
+
+        * UIProcess/API/Cocoa/WKWebView.mm:
+        (-[WKWebView evaluateJavaScript:completionHandler:]):
+        (-[WKWebView _evaluateJavaScript:asAsyncFunction:withArguments:forceUserGesture:completionHandler:inWorld:]):
+        (-[WKWebView _callAsyncJavaScriptFunction:withArguments:inWorld:completionHandler:]):
+        (-[WKWebView _evaluateJavaScript:inWorld:completionHandler:]):
+        (-[WKWebView _evaluateJavaScriptWithoutUserGesture:completionHandler:]):
+        (-[WKWebView _evaluateJavaScript:asAsyncFunction:withArguments:forceUserGesture:completionHandler:]): Deleted.
+        (-[WKWebView _callAsyncFunction:withArguments:completionHandler:]): Deleted.
+        * UIProcess/API/Cocoa/WKWebViewPrivate.h:
+
+        * UIProcess/API/Cocoa/_WKContentWorld.h: Added.
+        * UIProcess/API/Cocoa/_WKContentWorld.mm: Copied from Source/WebKit/UIProcess/API/APIUserContentWorld.h.
+        (+[_WKContentWorld pageContentWorld]):
+        (+[_WKContentWorld defaultClientWorld]):
+        (+[_WKContentWorld worldWithName:]):
+        (-[_WKContentWorld dealloc]):
+        (-[_WKContentWorld name]):
+        (-[_WKContentWorld _apiObject]):
+        * UIProcess/API/Cocoa/_WKContentWorldInternal.h: Copied from Source/WebKit/UIProcess/API/APIUserContentWorld.h.
+
+        * UIProcess/UserContent/WebUserContentControllerProxy.cpp:
+        * UIProcess/UserContent/WebUserContentControllerProxy.h:
+
+        * UIProcess/WebPageProxy.cpp:
+        (WebKit::WebPageProxy::runJavaScriptInMainFrame):
+        (WebKit::WebPageProxy::runJavaScriptInMainFrameScriptWorld):
+        * UIProcess/WebPageProxy.h:
+
+        * WebProcess/UserContent/WebUserContentController.cpp:
+        (WebKit::worldMap):
+        (WebKit::WebUserContentController::worldForIdentifier):
+        (WebKit::WebUserContentController::addUserContentWorld):
+        (WebKit::WebUserContentController::addUserContentWorlds):
+        * WebProcess/UserContent/WebUserContentController.h:
+
+        * WebProcess/WebPage/WebPage.cpp:
+        (WebKit::WebPage::runJavaScript):
+        (WebKit::WebPage::runJavaScriptInMainFrameScriptWorld):
+        (WebKit::WebPage::runJavaScriptInFrame):
+        * WebProcess/WebPage/WebPage.h:
+        * WebProcess/WebPage/WebPage.messages.in:
+
+        * Sources.txt:
+        * WebKit.xcodeproj/project.pbxproj:
+
 2020-01-15  Ross Kirsling  <ross.kirsling@sony.com>
 
         [PlayStation] Add stubs for WebContextMenuClient
index 8da13c4..9056ac8 100644 (file)
@@ -110,6 +110,7 @@ public:
         ContentRuleList,
         ContentRuleListAction,
         ContentRuleListStore,
+        ContentWorld,
 #if PLATFORM(IOS_FAMILY)
         ContextMenuElementInfo,
 #endif
index bf24db6..44bd491 100644 (file)
@@ -71,6 +71,7 @@
 #import "_WKAttachmentInternal.h"
 #import "_WKAutomationSessionInternal.h"
 #import "_WKContentRuleListActionInternal.h"
+#import "_WKContentWorldInternal.h"
 #import "_WKCustomHeaderFieldsInternal.h"
 #import "_WKDownloadInternal.h"
 #import "_WKExperimentalFeatureInternal.h"
@@ -346,6 +347,10 @@ void* Object::newObject(size_t size, Type type)
         wrapper = [_WKResourceLoadStatisticsThirdParty alloc];
         break;
 
+    case Type::ContentWorld:
+        wrapper = [_WKContentWorld alloc];
+        break;
+
     case Type::UserContentWorld:
         wrapper = [_WKUserContentWorld alloc];
         break;
index 472e4e0..979fa65 100644 (file)
@@ -326,6 +326,7 @@ UIProcess/API/APIAttachment.cpp
 UIProcess/API/APIContentRuleList.cpp
 UIProcess/API/APIContentRuleListAction.cpp
 UIProcess/API/APIContentRuleListStore.cpp
+UIProcess/API/APIContentWorld.cpp
 UIProcess/API/APIContextMenuElementInfo.cpp
 UIProcess/API/APIDebuggableInfo.cpp
 UIProcess/API/APIExperimentalFeature.cpp
diff --git a/Source/WebKit/UIProcess/API/APIContentWorld.cpp b/Source/WebKit/UIProcess/API/APIContentWorld.cpp
new file mode 100644 (file)
index 0000000..6345476
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2020 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. AND ITS CONTRIBUTORS ``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 ITS 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.
+ */
+
+#include "config.h"
+#include "APIContentWorld.h"
+
+#include "APIUserContentWorld.h"
+
+namespace API {
+
+static HashMap<WTF::String, ContentWorld*>& sharedWorldMap()
+{
+    static HashMap<WTF::String, ContentWorld*>* sharedMap = new HashMap<WTF::String, ContentWorld*>;
+    return *sharedMap;
+}
+
+Ref<ContentWorld> ContentWorld::sharedWorldWithName(const WTF::String& name)
+{
+    auto result = sharedWorldMap().add(name, nullptr);
+    if (result.isNewEntry) {
+        result.iterator->value = new ContentWorld(name);
+        return adoptRef(*result.iterator->value);
+    }
+
+    return makeRef(*result.iterator->value);
+}
+
+ContentWorld& ContentWorld::pageContentWorld()
+{
+    static NeverDestroyed<RefPtr<ContentWorld>> world(adoptRef(new ContentWorld(API::UserContentWorld::normalWorldIdentifer())));
+    return *world.get();
+}
+
+ContentWorld& ContentWorld::defaultClientWorld()
+{
+    static NeverDestroyed<RefPtr<ContentWorld>> world(adoptRef(new ContentWorld(API::UserContentWorld::generateIdentifier())));
+    return *world.get();
+}
+
+ContentWorld::ContentWorld(const WTF::String& name)
+    : m_identifier(API::UserContentWorld::generateIdentifier())
+    , m_name(name)
+{
+}
+
+ContentWorld::ContentWorld(uint64_t identifier)
+    : m_identifier(identifier)
+{
+}
+
+ContentWorld::~ContentWorld()
+{
+    if (m_name.isNull())
+        return;
+
+    auto taken = sharedWorldMap().take(m_name);
+    ASSERT_UNUSED(taken, taken == this);
+}
+
+} // namespace API
diff --git a/Source/WebKit/UIProcess/API/APIContentWorld.h b/Source/WebKit/UIProcess/API/APIContentWorld.h
new file mode 100644 (file)
index 0000000..93e90ac
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2020 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. AND ITS CONTRIBUTORS ``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 ITS 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 "APIObject.h"
+#include <wtf/text/WTFString.h>
+
+namespace API {
+
+class ContentWorld final : public API::ObjectImpl<API::Object::Type::ContentWorld> {
+public:
+    static Ref<ContentWorld> sharedWorldWithName(const WTF::String&);
+    static ContentWorld& pageContentWorld();
+    static ContentWorld& defaultClientWorld();
+
+    virtual ~ContentWorld();
+
+    const WTF::String& name() const { return m_name; }
+    uint64_t identifier() const { return m_identifier; }
+
+    std::pair<uint64_t, WTF::String> worldData() { return { m_identifier, m_name }; }
+
+private:
+    ContentWorld(const WTF::String&);
+    ContentWorld(uint64_t identifier);
+
+    // FIXME: This should be an ObjectIdentifier once we can get all ScriptWorld related classes to use ObjectIdentifier.
+    uint64_t m_identifier;
+    WTF::String m_name;
+};
+
+} // namespace API
index 4dadfbf..a85a15b 100644 (file)
 
 namespace API {
 
-static const uint64_t normalWorldIdentifer = 1;
-
-static uint64_t generateIdentifier()
+uint64_t UserContentWorld::generateIdentifier()
 {
-    static uint64_t identifier = normalWorldIdentifer;
+    static uint64_t identifier = normalWorldIdentifer();
 
     return ++identifier;
 }
@@ -55,7 +53,7 @@ UserContentWorld::UserContentWorld(const WTF::String& name)
 }
 
 UserContentWorld::UserContentWorld(ForNormalWorldOnly)
-    : m_identifier(normalWorldIdentifer)
+    : m_identifier(normalWorldIdentifer())
 {
 }
 
index 840fe1c..fe9fc54 100644 (file)
@@ -31,6 +31,8 @@
 
 namespace API {
 
+class ContentWorld;
+
 class UserContentWorld final : public API::ObjectImpl<API::Object::Type::UserContentWorld> {
 public:
     static Ref<UserContentWorld> worldWithName(const WTF::String&);
@@ -41,12 +43,18 @@ public:
     const WTF::String& name() const { return m_name; }
     uint64_t identifier() const { return m_identifier; }
 
+    static uint64_t normalWorldIdentifer() { return 1; };
+
 private:
+    friend class ContentWorld;
+
     UserContentWorld(const WTF::String&);
 
     enum class ForNormalWorldOnly { NormalWorld };
     UserContentWorld(ForNormalWorldOnly);
 
+    static uint64_t generateIdentifier();
+
     uint64_t m_identifier;
     WTF::String m_name;
 };
index 83933e0..74564db 100644 (file)
@@ -91,6 +91,7 @@
 #import "WebURLSchemeHandlerCocoa.h"
 #import "WebViewImpl.h"
 #import "_WKActivatedElementInfoInternal.h"
+#import "_WKContentWorldInternal.h"
 #import "_WKDiagnosticLoggingDelegate.h"
 #import "_WKFindDelegate.h"
 #import "_WKFrameHandleInternal.h"
@@ -814,7 +815,7 @@ static WKErrorCode callbackErrorCode(WebKit::CallbackBase::Error error)
 
 - (void)evaluateJavaScript:(NSString *)javaScriptString completionHandler:(void (^)(id, NSError *))completionHandler
 {
-    [self _evaluateJavaScript:javaScriptString asAsyncFunction:NO withArguments:nil forceUserGesture:YES completionHandler:completionHandler];
+    [self _evaluateJavaScript:javaScriptString asAsyncFunction:NO withArguments:nil forceUserGesture:YES completionHandler:completionHandler inWorld:_WKContentWorld.pageContentWorld];
 }
 
 static bool validateArgument(id argument)
@@ -851,7 +852,7 @@ static bool validateArgument(id argument)
     return false;
 }
 
-- (void)_evaluateJavaScript:(NSString *)javaScriptString asAsyncFunction:(BOOL)asAsyncFunction withArguments:(NSDictionary<NSString *, id> *)arguments forceUserGesture:(BOOL)forceUserGesture completionHandler:(void (^)(id, NSError *))completionHandler
+- (void)_evaluateJavaScript:(NSString *)javaScriptString asAsyncFunction:(BOOL)asAsyncFunction withArguments:(NSDictionary<NSString *, id> *)arguments forceUserGesture:(BOOL)forceUserGesture completionHandler:(void (^)(id, NSError *))completionHandler inWorld:(_WKContentWorld *)world
 {
     auto handler = adoptNS([completionHandler copy]);
 
@@ -888,7 +889,7 @@ static bool validateArgument(id argument)
         return;
     }
 
-    _page->runJavaScriptInMainFrame(WebCore::RunJavaScriptParameters { javaScriptString, !!asAsyncFunction, WTFMove(argumentsMap), !!forceUserGesture }, [handler](API::SerializedScriptValue* serializedScriptValue, Optional<WebCore::ExceptionDetails> details, WebKit::ScriptValueCallback::Error errorCode) {
+    _page->runJavaScriptInMainFrameScriptWorld(WebCore::RunJavaScriptParameters { javaScriptString, !!asAsyncFunction, WTFMove(argumentsMap), !!forceUserGesture }, *world->_contentWorld.get(), [handler](API::SerializedScriptValue* serializedScriptValue, Optional<WebCore::ExceptionDetails> details, WebKit::ScriptValueCallback::Error errorCode) {
         if (!handler)
             return;
 
@@ -1504,6 +1505,16 @@ FOR_EACH_PRIVATE_WKCONTENTVIEW_ACTION(FORWARD_ACTION_TO_WKCONTENTVIEW)
 
 #pragma mark - macOS/iOS WKPrivate
 
+- (void)_callAsyncJavaScriptFunction:(NSString *)javaScriptString withArguments:(NSDictionary<NSString *, id> *)arguments inWorld:(_WKContentWorld *)contentWorld completionHandler:(void (^)(id, NSError *error))completionHandler
+{
+    [self _evaluateJavaScript:javaScriptString asAsyncFunction:YES withArguments:arguments forceUserGesture:YES completionHandler:completionHandler inWorld:contentWorld];
+}
+
+- (void)_evaluateJavaScript:(NSString *)javaScriptString inWorld:(_WKContentWorld *)contentWorld completionHandler:(void (^)(id, NSError *))completionHandler
+{
+    [self _evaluateJavaScript:javaScriptString asAsyncFunction:NO withArguments:nil forceUserGesture:YES completionHandler:completionHandler inWorld:contentWorld];
+}
+
 - (_WKSelectionAttributes)_selectionAttributes
 {
     return _selectionAttributes;
@@ -1987,11 +1998,6 @@ FOR_EACH_PRIVATE_WKCONTENTVIEW_ACTION(FORWARD_ACTION_TO_WKCONTENTVIEW)
     [self createPDFWithConfiguration:pdfConfiguration completionHandler:completionHandler];
 }
 
-- (void)_callAsyncFunction:(NSString *)javaScriptString withArguments:(NSDictionary<NSString *, id> *)arguments completionHandler:(void (^)(id, NSError *error))completionHandler
-{
-    [self _evaluateJavaScript:javaScriptString asAsyncFunction:YES withArguments:arguments forceUserGesture:YES completionHandler:completionHandler];
-}
-
 - (NSData *)_sessionStateData
 {
     // FIXME: This should not use the legacy session state encoder.
@@ -2134,7 +2140,7 @@ FOR_EACH_PRIVATE_WKCONTENTVIEW_ACTION(FORWARD_ACTION_TO_WKCONTENTVIEW)
 
 - (void)_evaluateJavaScriptWithoutUserGesture:(NSString *)javaScriptString completionHandler:(void (^)(id, NSError *))completionHandler
 {
-    [self _evaluateJavaScript:javaScriptString asAsyncFunction:NO withArguments:nil forceUserGesture:NO completionHandler:completionHandler];
+    [self _evaluateJavaScript:javaScriptString asAsyncFunction:NO withArguments:nil forceUserGesture:NO completionHandler:completionHandler inWorld:_WKContentWorld.pageContentWorld];
 }
 
 - (void)_updateWebsitePolicies:(_WKWebsitePolicies *)websitePolicies
index d3fe707..6ae61cc 100644 (file)
@@ -106,6 +106,7 @@ typedef NS_OPTIONS(NSUInteger, _WKRectEdge) {
 @class WKBrowsingContextHandle;
 @class WKWebpagePreferences;
 @class _WKApplicationManifest;
+@class _WKContentWorld;
 @class _WKFrameHandle;
 @class _WKHitTestResult;
 @class _WKInspector;
@@ -318,7 +319,58 @@ typedef NS_OPTIONS(NSUInteger, _WKRectEdge) {
 
 - (void)_takePDFSnapshotWithConfiguration:(WKSnapshotConfiguration *)snapshotConfiguration completionHandler:(void (^)(NSData *pdfSnapshotData, NSError *error))completionHandler WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA));
 
-- (void)_callAsyncFunction:(NSString *)javaScriptString withArguments:(NSDictionary<NSString *, id> *)arguments completionHandler:(void (^)(id, NSError *error))completionHandler;
+/* @abstract Calls the given JavaScript string as a function, passing the given named arguments to that function.
+ @param javaScriptString The JavaScript string to call as a function.
+ @param arguments A dictionary representing the arguments to be passed to the function call.
+ @param contentWorld The WKContentWorld in which to call the JavaScript function.
+ @param completionHandler A block to invoke with the return value of the function call, or with the asynchronous resolution of the function's return value.
+ @discussion The JavaScript string is treated as an anonymous JavaScript function that can be called with named arguments.
+ Pass in JavaScript string formatted for evaluation, not as one of the variants of function call available in JavaScript.
+ For example:
+     return x ? y : z;
+
+ The arguments dictionary supplies the values for those arguments which are serialized into JavaScript equivalents.
+ For example:
+     @{ @"x" : @YES, @"y" : @1, @"z" : @2 };
+
+ Combining the above arguments dictionary with the above JavaScript string, a function with the arguments "x", "y", and "z" is called with values YES, 1, and 2 respectively.
+
+ Allowed argument types are:
+ NSNumber, NSString, NSDate, NSArray, NSDictionary, and NSNull.
+ Any NSArray or NSDictionary containers can only contain objects of those types.
+
+ No matter which WKContentWorld you use to call your JavaScript function, you can make changes to the underlying web content. (e.g. the Document and its DOM structure)
+ Such changes will be visible to script executing in all WKContentWorlds.
+ Calling your JavaScript function can leave behind other changes to global state visibile to JavaScript. (e.g. `window.myVariable = 1;`)
+ Those changes will only be visibile to scripts executed in the same WKContentWorld.
+
+ Your completion handler will be called with the return value of your JavaScript function.
+ If your JavaScript does not explicitly return any value, that undefined result manifests as nil being passed to your completion handler.
+ If your JavaScript returns null, that result manifests as NSNull being passed to your completion handler.
+
+ JavaScript has the concept of a "thenable" object, which is any JavaScript object that has a callable "then" property.
+ The most well known example of a "thenable" object is a JavaScript promise.
+ If your JavaScript returns a "thenable" object WebKit will call "then" on the resulting object and wait for it to be resolved.
+
+ If the object calls "fulfill", your completion handler will be called with the result.
+ If the object calls "reject", your completion handler will be called with a WKErrorJavaScriptAsyncFunctionResultRejected error containing the reject reason in the userInfo dictionary.
+ If the object is garbage collected before it is resolved, your completion handler will be called with an error indicating that it will never be resolved.
+*/
+- (void)_callAsyncJavaScriptFunction:(NSString *)javaScriptString withArguments:(NSDictionary<NSString *, id> *)arguments inWorld:(_WKContentWorld *)contentWorld completionHandler:(void (^)(id, NSError *error))completionHandler;
+
+/* @abstract Evaluates the given JavaScript string.
+ @param javaScriptString The JavaScript string to evaluate.
+ @param contentWorld The WKContentWorld in which to evaluate the JavaScript string.
+ @param completionHandler A block to invoke when script evaluation completes or fails.
+ @discussion The completionHandler is passed the result of the script evaluation or an error.
+ No matter which WKContentWorld you use to evaluate your JavaScript string, you can make changes to the underlying web content. (e.g. the Document and its DOM structure)
+ Such changes will be visible to script executing in all WKContentWorlds.
+ Evaluating your JavaScript string can leave behind other changes to global state visibile to JavaScript. (e.g. `window.myVariable = 1;`)
+ Those changes will only be visibile to scripts executed in the same WKContentWorld.
+ evaluateJavaScript: is the best way to set up global state for future JavaScript execution in a given world. (e.g. Importing libraries/utilities that future JavaScript execution will rely on)
+ Once your global state is set up, consider using callAsyncJavaScriptFunction: for more flexible interaction with the JavaScript programming model.
+*/
+- (void)_evaluateJavaScript:(NSString *)javaScriptString inWorld:(_WKContentWorld *)contentWorld completionHandler:(void (^)(id, NSError *error))completionHandler;
 
 @end
 
diff --git a/Source/WebKit/UIProcess/API/Cocoa/_WKContentWorld.h b/Source/WebKit/UIProcess/API/Cocoa/_WKContentWorld.h
new file mode 100644 (file)
index 0000000..6d25ad6
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2020 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. AND ITS CONTRIBUTORS ``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 ITS 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.
+ */
+
+#import <WebKit/WKFoundation.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+/*!
+A WKContentWorld object allows you to seperate your application's interaction with content displayed in a WKWebView into different roles that cannot interfere with one another.
+*/
+WK_CLASS_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA))
+@interface _WKContentWorld : NSObject
+
++ (instancetype)new NS_UNAVAILABLE;
+- (instancetype)init NS_UNAVAILABLE;
+
+/*! @abstract Retrieve the main world that page content itself uses.
+ @discussion When interacting with page content in a WKWebView using the page content world you can disrupt the operation of page content (e.g. by conflicting with variable names in JavaScript set by the web page content itself).
+*/
+@property (class, nonatomic, readonly) _WKContentWorld *pageContentWorld;
+
+/*! @abstract Retrieve the default non-page content world for API clients.
+ @discussion Interacting with page content in a WKWebView using a content world different from the page content world enables using DOM and built-in DOM APIs
+ without conflicting with other aspects of the page content (e.g. JavaScript from the web page content itself)
+*/
+@property (class, nonatomic, readonly) _WKContentWorld *defaultClientWorld;
+
+/*! @abstract Retrieves a named content world for API users.
+ @param name The name of the WKContentWorld to retrieve.
+ @discussion By interacting with page content in a WKWebView using a non-main content world you can interact with the DOM and built-in DOM APIs
+ without conflicting with other aspects of the page content (e.g. JavaScript from the web content itself)
+ Repeated calls with the same name will retrieve the same WKContentWorld instance.
+ Each named content world is distinct from all other named content worlds, the defaultClientWorld, and the pageContentWorld.
+ The name can be used to keep distinct worlds identifiable anywhere a world might be surfaced in a user interface.
+ For example, the different worlds used in your application will be surfaced by name in the WebKit Web Inspector.
+*/
++ (_WKContentWorld *)worldWithName:(NSString *)name NS_REFINED_FOR_SWIFT;
+
+/*! @abstract The name of the WKContentWorld
+ @discussion The pageContentWorld and defaultClientWorld instances will have a nil name.
+ All other instances will have the non-nil name they were accessed by.
+*/
+@property (nullable, nonatomic, readonly, copy) NSString *name;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Source/WebKit/UIProcess/API/Cocoa/_WKContentWorld.mm b/Source/WebKit/UIProcess/API/Cocoa/_WKContentWorld.mm
new file mode 100644 (file)
index 0000000..ea365f2
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2020 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. AND ITS CONTRIBUTORS ``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 ITS 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.
+ */
+
+#import "config.h"
+#import "_WKContentWorldInternal.h"
+
+@implementation _WKContentWorld
+
++ (_WKContentWorld *)pageContentWorld
+{
+    return wrapper(API::ContentWorld::pageContentWorld());
+}
+
++ (_WKContentWorld *)defaultClientWorld
+{
+    return wrapper(API::ContentWorld::defaultClientWorld());
+}
+
++ (_WKContentWorld *)worldWithName:(NSString *)name
+{
+    return wrapper(API::ContentWorld::sharedWorldWithName(name));
+}
+
+- (void)dealloc
+{
+    _contentWorld->~ContentWorld();
+
+    [super dealloc];
+}
+
+- (NSString *)name
+{
+    if (_contentWorld->name().isNull())
+        return nil;
+
+    return _contentWorld->name();
+}
+
+#pragma mark WKObject protocol implementation
+
+- (API::Object&)_apiObject
+{
+    return *_contentWorld;
+}
+
+@end
diff --git a/Source/WebKit/UIProcess/API/Cocoa/_WKContentWorldInternal.h b/Source/WebKit/UIProcess/API/Cocoa/_WKContentWorldInternal.h
new file mode 100644 (file)
index 0000000..4800c12
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2020 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. AND ITS CONTRIBUTORS ``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 ITS 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.
+ */
+
+#import "_WKContentWorld.h"
+
+#import "APIContentWorld.h"
+#import "WKObject.h"
+#import <wtf/text/WTFString.h>
+
+namespace WebKit {
+
+template<> struct WrapperTraits<API::ContentWorld> {
+    using WrapperClass = _WKContentWorld;
+};
+
+}
+
+@interface _WKContentWorld () <WKObject> {
+@package
+    API::ObjectStorage<API::ContentWorld> _contentWorld;
+}
+@end
index f9da1bb..ff86ecf 100644 (file)
@@ -23,6 +23,7 @@
 #include "config.h"
 #include "WebKitWebView.h"
 
+#include "APIContentWorld.h"
 #include "APIData.h"
 #include "APINavigation.h"
 #include "APISerializedScriptValue.h"
@@ -3742,7 +3743,8 @@ void webkit_web_view_run_javascript_in_world(WebKitWebView* webView, const gchar
     g_return_if_fail(worldName);
 
     GRefPtr<GTask> task = adoptGRef(g_task_new(webView, cancellable, callback, userData));
-    getPage(webView).runJavaScriptInMainFrameScriptWorld({ String::fromUTF8(script), false, WTF::nullopt, true }, String::fromUTF8(worldName), [task = WTFMove(task)](API::SerializedScriptValue* serializedScriptValue, Optional<ExceptionDetails> details, WebKit::CallbackBase::Error) {
+    auto world = API::ContentWorld::sharedWorldWithName(String::fromUTF8(worldName));
+    getPage(webView).runJavaScriptInMainFrameScriptWorld({ String::fromUTF8(script), false, WTF::nullopt, true }, world.get(), [task = WTFMove(task)](API::SerializedScriptValue* serializedScriptValue, Optional<ExceptionDetails> details, WebKit::CallbackBase::Error) {
         ExceptionDetails exceptionDetails;
         if (details)
             exceptionDetails = *details;
index d10e7b5..d01413d 100644 (file)
@@ -27,6 +27,7 @@
 #include "WebUserContentControllerProxy.h"
 
 #include "APIArray.h"
+#include "APIContentWorld.h"
 #include "APIUserContentWorld.h"
 #include "APIUserScript.h"
 #include "APIUserStyleSheet.h"
index 671fb29..676d237 100644 (file)
@@ -41,6 +41,7 @@
 namespace API {
 class Array;
 class ContentRuleList;
+class ContentWorld;
 class UserContentWorld;
 class UserScript;
 class UserStyleSheet;
index b39a6fe..7bb955f 100644 (file)
@@ -29,6 +29,7 @@
 
 #include "APIArray.h"
 #include "APIAttachment.h"
+#include "APIContentWorld.h"
 #include "APIContextMenuClient.h"
 #include "APIFindClient.h"
 #include "APIFindMatchesClient.h"
@@ -3874,10 +3875,10 @@ void WebPageProxy::launchInitialProcessIfNecessary()
 
 void WebPageProxy::runJavaScriptInMainFrame(RunJavaScriptParameters&& parameters, WTF::Function<void (API::SerializedScriptValue*, Optional<WebCore::ExceptionDetails>, CallbackBase::Error)>&& callbackFunction)
 {
-    runJavaScriptInMainFrameScriptWorld(WTFMove(parameters), WTF::nullopt, WTFMove(callbackFunction));
+    runJavaScriptInMainFrameScriptWorld(WTFMove(parameters), API::ContentWorld::pageContentWorld(), WTFMove(callbackFunction));
 }
 
-void WebPageProxy::runJavaScriptInMainFrameScriptWorld(RunJavaScriptParameters&& parameters, const Optional<String>& worldName, WTF::Function<void(API::SerializedScriptValue*, Optional<ExceptionDetails>, CallbackBase::Error)>&& callbackFunction)
+void WebPageProxy::runJavaScriptInMainFrameScriptWorld(RunJavaScriptParameters&& parameters, API::ContentWorld& world, WTF::Function<void(API::SerializedScriptValue*, Optional<ExceptionDetails>, CallbackBase::Error)>&& callbackFunction)
 {
     // For backward-compatibility support running script in a WebView which has not done any loads yets.
     launchInitialProcessIfNecessary();
@@ -3888,7 +3889,7 @@ void WebPageProxy::runJavaScriptInMainFrameScriptWorld(RunJavaScriptParameters&&
     }
 
     auto callbackID = m_callbacks.put(WTFMove(callbackFunction), m_process->throttler().backgroundActivity("WebPageProxy::runJavaScriptInMainFrameScriptWorld"_s));
-    send(Messages::WebPage::RunJavaScriptInMainFrameScriptWorld(parameters, worldName, callbackID));
+    send(Messages::WebPage::RunJavaScriptInMainFrameScriptWorld(parameters, world.worldData(), callbackID));
 }
 
 void WebPageProxy::runJavaScriptInFrame(FrameIdentifier frameID, const String& script, bool forceUserGesture, WTF::Function<void(API::SerializedScriptValue*, Optional<ExceptionDetails>, CallbackBase::Error)>&& callbackFunction)
index 7fecfcd..bca0b84 100644 (file)
@@ -166,6 +166,7 @@ interface ID3D11Device1;
 
 namespace API {
 class Attachment;
+class ContentWorld;
 class ContextMenuClient;
 class FindClient;
 class FindMatchesClient;
@@ -1083,7 +1084,7 @@ public:
     void getSourceForFrame(WebFrameProxy*, WTF::Function<void (const String&, CallbackBase::Error)>&&);
     void getWebArchiveOfFrame(WebFrameProxy*, Function<void (API::Data*, CallbackBase::Error)>&&);
     void runJavaScriptInMainFrame(WebCore::RunJavaScriptParameters&&, WTF::Function<void (API::SerializedScriptValue*, Optional<WebCore::ExceptionDetails>, CallbackBase::Error)>&& callbackFunction);
-    void runJavaScriptInMainFrameScriptWorld(WebCore::RunJavaScriptParameters&&, const Optional<String>& worldName, WTF::Function<void(API::SerializedScriptValue*, Optional<WebCore::ExceptionDetails>, CallbackBase::Error)>&& callbackFunction);
+    void runJavaScriptInMainFrameScriptWorld(WebCore::RunJavaScriptParameters&&, API::ContentWorld&, WTF::Function<void(API::SerializedScriptValue*, Optional<WebCore::ExceptionDetails>, CallbackBase::Error)>&& callbackFunction);
     // For sub frames.
     void runJavaScriptInFrame(WebCore::FrameIdentifier, const String& script, bool forceUserGesture, WTF::Function<void(API::SerializedScriptValue*, Optional<WebCore::ExceptionDetails>, CallbackBase::Error)>&& callbackFunction);
     void forceRepaint(RefPtr<VoidCallback>&&);
index 1c70e64..5c06117 100644 (file)
                517CF0E3163A486C00C2950E /* NetworkProcessConnectionMessageReceiver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 517CF0E1163A486C00C2950E /* NetworkProcessConnectionMessageReceiver.cpp */; };
                517CF0E3163A486C00C2950F /* CacheStorageEngineConnectionMessageReceiver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 517CF0E1163A486C00C2950F /* CacheStorageEngineConnectionMessageReceiver.cpp */; };
                517CF0E4163A486C00C2950E /* NetworkProcessConnectionMessages.h in Headers */ = {isa = PBXBuildFile; fileRef = 517CF0E2163A486C00C2950E /* NetworkProcessConnectionMessages.h */; };
+               5183721D23CE85F60003CF83 /* _WKContentWorld.h in Headers */ = {isa = PBXBuildFile; fileRef = 5183721A23CD49B20003CF83 /* _WKContentWorld.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               5183721E23CE85FB0003CF83 /* _WKContentWorldInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 5183721C23CD4A740003CF83 /* _WKContentWorldInternal.h */; };
+               5183721F23CE95210003CF83 /* _WKContentWorld.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5183721B23CD49B20003CF83 /* _WKContentWorld.mm */; };
+               5183722223CE97410003CF83 /* APIContentWorld.h in Headers */ = {isa = PBXBuildFile; fileRef = 5183722023CE973A0003CF83 /* APIContentWorld.h */; };
                51871B5C127CB89D00F76232 /* WebContextMenu.h in Headers */ = {isa = PBXBuildFile; fileRef = 51871B5A127CB89D00F76232 /* WebContextMenu.h */; };
                518ACAEA12AEE6BB00B04B83 /* WKProtectionSpaceTypes.h in Headers */ = {isa = PBXBuildFile; fileRef = 518ACAE912AEE6BB00B04B83 /* WKProtectionSpaceTypes.h */; settings = {ATTRIBUTES = (Private, ); }; };
                518ACF1112B015F800B04B83 /* WKCredentialTypes.h in Headers */ = {isa = PBXBuildFile; fileRef = 518ACF1012B015F800B04B83 /* WKCredentialTypes.h */; settings = {ATTRIBUTES = (Private, ); }; };
                517CF0E1163A486C00C2950E /* NetworkProcessConnectionMessageReceiver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = NetworkProcessConnectionMessageReceiver.cpp; path = DerivedSources/WebKit2/NetworkProcessConnectionMessageReceiver.cpp; sourceTree = BUILT_PRODUCTS_DIR; };
                517CF0E1163A486C00C2950F /* CacheStorageEngineConnectionMessageReceiver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CacheStorageEngineConnectionMessageReceiver.cpp; path = DerivedSources/WebKit2/CacheStorageEngineConnectionMessageReceiver.cpp; sourceTree = BUILT_PRODUCTS_DIR; };
                517CF0E2163A486C00C2950E /* NetworkProcessConnectionMessages.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NetworkProcessConnectionMessages.h; path = DerivedSources/WebKit2/NetworkProcessConnectionMessages.h; sourceTree = BUILT_PRODUCTS_DIR; };
+               5183721A23CD49B20003CF83 /* _WKContentWorld.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = _WKContentWorld.h; sourceTree = "<group>"; };
+               5183721B23CD49B20003CF83 /* _WKContentWorld.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = _WKContentWorld.mm; sourceTree = "<group>"; };
+               5183721C23CD4A740003CF83 /* _WKContentWorldInternal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = _WKContentWorldInternal.h; sourceTree = "<group>"; };
+               5183722023CE973A0003CF83 /* APIContentWorld.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = APIContentWorld.h; sourceTree = "<group>"; };
+               5183722123CE973A0003CF83 /* APIContentWorld.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = APIContentWorld.cpp; sourceTree = "<group>"; };
                5183B3931379F85C00E8754E /* Shim.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Shim.xcconfig; sourceTree = "<group>"; };
                51871B59127CB89D00F76232 /* WebContextMenu.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WebContextMenu.cpp; sourceTree = "<group>"; };
                51871B5A127CB89D00F76232 /* WebContextMenu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebContextMenu.h; sourceTree = "<group>"; };
                                5C4609E222430E4C009943C2 /* _WKContentRuleListAction.h */,
                                5C4609E322430E4D009943C2 /* _WKContentRuleListAction.mm */,
                                5C4609E422430E4D009943C2 /* _WKContentRuleListActionInternal.h */,
+                               5183721A23CD49B20003CF83 /* _WKContentWorld.h */,
+                               5183721B23CD49B20003CF83 /* _WKContentWorld.mm */,
+                               5183721C23CD4A740003CF83 /* _WKContentWorldInternal.h */,
                                1A5704F61BE01FF400874AF1 /* _WKContextMenuElementInfo.h */,
                                1A5704F51BE01FF400874AF1 /* _WKContextMenuElementInfo.mm */,
                                5C5D2389227A1892000B9BDA /* _WKCustomHeaderFields.h */,
                                5C4609E622430FA7009943C2 /* APIContentRuleListAction.h */,
                                7C3A06A51AAB903E009D74BA /* APIContentRuleListStore.cpp */,
                                7C3A06A61AAB903E009D74BA /* APIContentRuleListStore.h */,
+                               5183722123CE973A0003CF83 /* APIContentWorld.cpp */,
+                               5183722023CE973A0003CF83 /* APIContentWorld.h */,
                                076E884D1A13CADF005E90FC /* APIContextMenuClient.h */,
                                5CE0C366229F2D3D003695F0 /* APIContextMenuElementInfo.cpp */,
                                5CE0C367229F2D3E003695F0 /* APIContextMenuElementInfo.h */,
                                990D28B11C65208D00986977 /* _WKAutomationSessionInternal.h in Headers */,
                                5C4609E7224317B4009943C2 /* _WKContentRuleListAction.h in Headers */,
                                5C4609E8224317BB009943C2 /* _WKContentRuleListActionInternal.h in Headers */,
+                               5183721D23CE85F60003CF83 /* _WKContentWorld.h in Headers */,
+                               5183721E23CE85FB0003CF83 /* _WKContentWorldInternal.h in Headers */,
                                1A5704F81BE01FF400874AF1 /* _WKContextMenuElementInfo.h in Headers */,
                                5C5D238C227A2CDA000B9BDA /* _WKCustomHeaderFields.h in Headers */,
                                83891B691A68BEBC0030F386 /* _WKDiagnosticLoggingDelegate.h in Headers */,
                                1A3DD206125E5A2F004515E6 /* APIClient.h in Headers */,
                                7C89D2B41A6B068C003A5FDE /* APIContentRuleList.h in Headers */,
                                7C3A06A81AAB903E009D74BA /* APIContentRuleListStore.h in Headers */,
+                               5183722223CE97410003CF83 /* APIContentWorld.h in Headers */,
                                076E884E1A13CADF005E90FC /* APIContextMenuClient.h in Headers */,
                                7A821F501E2F7A7500604577 /* APICustomProtocolManagerClient.h in Headers */,
                                51578B831209ECEF00A37C4A /* APIData.h in Headers */,
                        isa = PBXSourcesBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
+                               5183721F23CE95210003CF83 /* _WKContentWorld.mm in Sources */,
                                5CBD595C2280EDF4002B22AA /* _WKCustomHeaderFields.mm in Sources */,
                                49FBEFFD239B011D00BD032F /* _WKResourceLoadStatisticsFirstParty.mm in Sources */,
                                49FBEFFF239B012F00BD032F /* _WKResourceLoadStatisticsThirdParty.mm in Sources */,
index c44adb2..6ec6721 100644 (file)
@@ -62,7 +62,7 @@ typedef HashMap<uint64_t, std::pair<RefPtr<InjectedBundleScriptWorld>, unsigned>
 
 static WorldMap& worldMap()
 {
-    static NeverDestroyed<WorldMap> map(std::initializer_list<WorldMap::KeyValuePairType> { { 1, std::make_pair(&InjectedBundleScriptWorld::normalWorld(), 1) } });
+    static NeverDestroyed<WorldMap> map(std::initializer_list<WorldMap::KeyValuePairType> { { WebUserContentController::identifierForNormalWorld(), std::make_pair(&InjectedBundleScriptWorld::normalWorld(), 1) } });
 
     return map;
 }
@@ -94,23 +94,33 @@ WebUserContentController::~WebUserContentController()
     userContentControllers().remove(m_identifier);
 }
 
-void WebUserContentController::addUserContentWorlds(const Vector<std::pair<uint64_t, String>>& worlds)
+InjectedBundleScriptWorld* WebUserContentController::worldForIdentifier(uint64_t identifier)
+{
+    auto iterator = worldMap().find(identifier);
+    return iterator == worldMap().end() ? nullptr : iterator->value.first.get();
+}
+
+void WebUserContentController::addUserContentWorld(const std::pair<uint64_t, String>& world)
 {
-    for (auto& world : worlds) {
-        ASSERT(world.first);
-        ASSERT(world.first != 1);
+    ASSERT(world.first);
+    ASSERT(world.first != 1);
 
-        worldMap().ensure(world.first, [&] {
+    worldMap().ensure(world.first, [&] {
 #if PLATFORM(GTK) || PLATFORM(WPE)
-            // The GLib API doesn't allow to create script worlds from the UI process. We need to
-            // use the existing world created by the web extension if any. The world name is used
-            // as the identifier.
-            if (auto* existingWorld = InjectedBundleScriptWorld::find(world.second))
-                return std::make_pair(Ref<InjectedBundleScriptWorld>(*existingWorld), 1);
+        // The GLib API doesn't allow to create script worlds from the UI process. We need to
+        // use the existing world created by the web extension if any. The world name is used
+        // as the identifier.
+        if (auto* existingWorld = InjectedBundleScriptWorld::find(world.second))
+            return std::make_pair(Ref<InjectedBundleScriptWorld>(*existingWorld), 1);
 #endif
-            return std::make_pair(InjectedBundleScriptWorld::create(world.second), 1);
-        });
-    }
+        return std::make_pair(InjectedBundleScriptWorld::create(world.second), 1);
+    });
+}
+
+void WebUserContentController::addUserContentWorlds(const Vector<std::pair<uint64_t, String>>& worlds)
+{
+    for (auto& world : worlds)
+        addUserContentWorld(world);
 }
 
 void WebUserContentController::removeUserContentWorlds(const Vector<uint64_t>& worldIdentifiers)
index d6f8c1c..48e7d6a 100644 (file)
@@ -64,7 +64,11 @@ public:
     void removeUserStyleSheets(InjectedBundleScriptWorld&);
     void removeAllUserContent();
 
+    static uint64_t identifierForNormalWorld() { return 1; }
+    InjectedBundleScriptWorld* worldForIdentifier(uint64_t);
+
     void addUserContentWorlds(const Vector<std::pair<uint64_t, String>>&);
+    void addUserContentWorld(const std::pair<uint64_t, String>&);
     void addUserScripts(Vector<WebUserScriptData>&&, InjectUserScriptImmediately);
     void addUserStyleSheets(const Vector<WebUserStyleSheetData>&);
     void addUserScriptMessageHandlers(const Vector<WebScriptMessageHandlerData>&);
index d804273..8ccbc85 100644 (file)
@@ -3380,17 +3380,23 @@ KeyboardUIMode WebPage::keyboardUIMode()
     return static_cast<KeyboardUIMode>((fullKeyboardAccessEnabled ? KeyboardAccessFull : KeyboardAccessDefault) | (m_tabToLinks ? KeyboardAccessTabsToLinks : 0));
 }
 
-void WebPage::runJavaScript(WebFrame* frame, RunJavaScriptParameters&& parameters, const Optional<String>& worldName, CallbackID callbackID)
+void WebPage::runJavaScript(WebFrame* frame, RunJavaScriptParameters&& parameters, uint64_t worldIdentifier, CallbackID callbackID)
 {
     // NOTE: We need to be careful when running scripts that the objects we depend on don't
     // disappear during script execution.
 
-    auto* world = worldName ? InjectedBundleScriptWorld::find(worldName.value()) : &InjectedBundleScriptWorld::normalWorld();
-    if (!frame || !frame->coreFrame() || !world) {
+    if (!frame || !frame->coreFrame()) {
         send(Messages::WebPageProxy::ScriptValueCallback({ }, ExceptionDetails { "Unable to execute JavaScript: Page is in invalid state"_s }, callbackID));
         return;
     }
 
+    ASSERT(worldIdentifier);
+    auto* world = m_userContentController->worldForIdentifier(worldIdentifier);
+    if (!world) {
+        send(Messages::WebPageProxy::ScriptValueCallback({ }, ExceptionDetails { "Unable to execute JavaScript: Cannot find specified content world"_s }, callbackID));
+        return;
+    }
+
     auto resolveFunction = [protectedThis = makeRef(*this), this, world = makeRef(*world), frame = makeRef(*frame), callbackID](ValueOrException result) {
         RefPtr<SerializedScriptValue> serializedResultValue;
         if (result) {
@@ -3413,16 +3419,17 @@ void WebPage::runJavaScript(WebFrame* frame, RunJavaScriptParameters&& parameter
     frame->coreFrame()->script().executeAsynchronousUserAgentScriptInWorld(world->coreWorld(), WTFMove(parameters), WTFMove(resolveFunction));
 }
 
-void WebPage::runJavaScriptInMainFrameScriptWorld(RunJavaScriptParameters&& parameters, const Optional<String>& worldName, CallbackID callbackID)
+void WebPage::runJavaScriptInMainFrameScriptWorld(RunJavaScriptParameters&& parameters, const std::pair<uint64_t, String>& worldData, CallbackID callbackID)
 {
-    runJavaScript(mainWebFrame(), WTFMove(parameters), worldName, callbackID);
+    m_userContentController->addUserContentWorld(worldData);
+    runJavaScript(mainWebFrame(), WTFMove(parameters), worldData.first, callbackID);
 }
 
 void WebPage::runJavaScriptInFrame(FrameIdentifier frameID, const String& script, bool forceUserGesture, CallbackID callbackID)
 {
     WebFrame* frame = WebProcess::singleton().webFrame(frameID);
     ASSERT(mainWebFrame() != frame);
-    runJavaScript(frame, { script, false, WTF::nullopt, forceUserGesture }, WTF::nullopt, callbackID);
+    runJavaScript(frame, { script, false, WTF::nullopt, forceUserGesture }, WebUserContentController::identifierForNormalWorld(), callbackID);
 }
 
 void WebPage::getContentsAsString(CallbackID callbackID)
index 896e7f0..d48817c 100644 (file)
@@ -1461,8 +1461,8 @@ private:
     void getSelectionAsWebArchiveData(CallbackID);
     void getSourceForFrame(WebCore::FrameIdentifier, CallbackID);
     void getWebArchiveOfFrame(WebCore::FrameIdentifier, CallbackID);
-    void runJavaScript(WebFrame*, WebCore::RunJavaScriptParameters&&, const Optional<String>& worldName, CallbackID);
-    void runJavaScriptInMainFrameScriptWorld(WebCore::RunJavaScriptParameters&&, const Optional<String>& worldName, CallbackID);
+    void runJavaScript(WebFrame*, WebCore::RunJavaScriptParameters&&, uint64_t worldIdentifier, CallbackID);
+    void runJavaScriptInMainFrameScriptWorld(WebCore::RunJavaScriptParameters&&, const std::pair<uint64_t, String>& worldData, CallbackID);
     void runJavaScriptInFrame(WebCore::FrameIdentifier, const String&, bool forceUserGesture, CallbackID);
     void forceRepaint(CallbackID);
     void takeSnapshot(WebCore::IntRect snapshotRect, WebCore::IntSize bitmapSize, uint32_t options, CallbackID);
index 0940f6c..211b093 100644 (file)
@@ -206,10 +206,12 @@ GenerateSyntheticEditingCommand(enum:uint8_t WebKit::SyntheticEditingCommandType
     GetSelectionAsWebArchiveData(WebKit::CallbackID callbackID)
     GetSourceForFrame(WebCore::FrameIdentifier frameID, WebKit::CallbackID callbackID)
     GetWebArchiveOfFrame(WebCore::FrameIdentifier frameID, WebKit::CallbackID callbackID)
-    RunJavaScriptInMainFrameScriptWorld(struct WebCore::RunJavaScriptParameters parameters, Optional<String> worldName, WebKit::CallbackID callbackID)
+
+    // FIXME: These should use sendWithAsyncReply instead of callbackIDs
+    RunJavaScriptInMainFrameScriptWorld(struct WebCore::RunJavaScriptParameters parameters, std::pair<uint64_t, String> world, WebKit::CallbackID callbackID)
     RunJavaScriptInFrame(WebCore::FrameIdentifier frameID, String script, bool forceUserGesture, WebKit::CallbackID callbackID)
-    ForceRepaint(WebKit::CallbackID callbackID)
 
+    ForceRepaint(WebKit::CallbackID callbackID)
     SelectAll()
     ScheduleFullEditorStateUpdate()
 
index 81cf410..6e865de 100644 (file)
@@ -1,3 +1,21 @@
+2020-01-15  Brady Eidson  <beidson@apple.com>
+
+        Add WKContentWorld SPI, and use it in JavaScript execution.
+        https://bugs.webkit.org/show_bug.cgi?id=206310
+
+        Reviewed by Alex Christensen.
+        
+        Update previous callAsyncFunction calls with the new signature.
+        Add tests for new _WKContentWorld class and its behavior with regard to executing JavaScript.
+
+        * TestWebKitAPI/Tests/WebKitCocoa/AsyncFunction.mm:
+        (TestWebKitAPI::tryGCPromise):
+        (TestWebKitAPI::TEST):
+        * TestWebKitAPI/Tests/WebKitCocoa/WKWebViewEvaluateJavaScript.mm:
+        (TEST):
+        * TestWebKitAPI/cocoa/TestWKWebView.mm:
+        (-[WKWebView objectByCallingAsyncFunction:withArguments:error:]):
+
 2020-01-15  Jonathan Bedard  <jbedard@apple.com>
 
         run-api-tests no longer supports wildcards in test names
index 09cafe4..78cdd77 100644 (file)
@@ -29,6 +29,7 @@
 #import "Test.h"
 #import "TestWKWebView.h"
 #import <WebKit/WKWebViewPrivate.h>
+#import <WebKit/_WKContentWorld.h>
 
 namespace TestWebKitAPI {
 
@@ -183,7 +184,7 @@ static void tryGCPromise(WKWebView *webView, bool& done)
         return;
 
     NSString *functionBody = @"return new Promise(function(resolve, reject) { })";
-    [webView _callAsyncFunction:functionBody withArguments:nil completionHandler:[&] (id result, NSError *error) {
+    [webView _callAsyncJavaScriptFunction:functionBody withArguments:nil inWorld:_WKContentWorld.pageContentWorld completionHandler:[&] (id result, NSError *error) {
         EXPECT_NULL(result);
         EXPECT_TRUE(error != nil);
         EXPECT_TRUE([[error description] containsString:@"no longer reachable"]);
@@ -200,7 +201,7 @@ TEST(AsyncFunction, Promise)
     NSString *functionBody = @"return new Promise(function(resolve, reject) { setTimeout(function(){ resolve(42) }, 0); })";
 
     bool done = false;
-    [webView _callAsyncFunction:functionBody withArguments:nil completionHandler:[&] (id result, NSError *error) {
+    [webView _callAsyncJavaScriptFunction:functionBody withArguments:nil inWorld:_WKContentWorld.pageContentWorld completionHandler:[&] (id result, NSError *error) {
         EXPECT_NULL(error);
         EXPECT_TRUE([result isKindOfClass:[NSNumber class]]);
         EXPECT_TRUE([result isEqualToNumber:@42]);
@@ -212,7 +213,7 @@ TEST(AsyncFunction, Promise)
     functionBody = @"return new Promise(function(resolve, reject) { setTimeout(function(){ reject('Rejected!') }, 0); })";
 
     done = false;
-    [webView _callAsyncFunction:functionBody withArguments:nil completionHandler:[&] (id result, NSError *error) {
+    [webView _callAsyncJavaScriptFunction:functionBody withArguments:nil inWorld:_WKContentWorld.pageContentWorld completionHandler:[&] (id result, NSError *error) {
         EXPECT_NULL(result);
         EXPECT_TRUE(error != nil);
         EXPECT_TRUE([[error description] containsString:@"Rejected!"]);
@@ -223,7 +224,7 @@ TEST(AsyncFunction, Promise)
     functionBody = @"let p = new Proxy(function(resolve, reject) { setTimeout(function() { resolve(42); }, 0); }, { }); return { then: p };";
 
     done = false;
-    [webView _callAsyncFunction:functionBody withArguments:nil completionHandler:[&] (id result, NSError *error) {
+    [webView _callAsyncJavaScriptFunction:functionBody withArguments:nil inWorld:_WKContentWorld.pageContentWorld completionHandler:[&] (id result, NSError *error) {
         EXPECT_NULL(error);
         EXPECT_TRUE([result isKindOfClass:[NSNumber class]]);
         EXPECT_TRUE([result isEqualToNumber:@42]);
@@ -234,7 +235,7 @@ TEST(AsyncFunction, Promise)
     functionBody = @"let p = new Proxy(function(resolve, reject) { setTimeout(function() { reject('Rejected!'); }, 0); }, { }); return { then: p };";
 
     done = false;
-    [webView _callAsyncFunction:functionBody withArguments:nil completionHandler:[&] (id result, NSError *error) {
+    [webView _callAsyncJavaScriptFunction:functionBody withArguments:nil inWorld:_WKContentWorld.pageContentWorld completionHandler:[&] (id result, NSError *error) {
         EXPECT_NULL(result);
         EXPECT_TRUE(error != nil);
         EXPECT_TRUE([[error description] containsString:@"Rejected!"]);
index 984bc36..8c70c24 100644 (file)
 #import "PlatformUtilities.h"
 #import "Test.h"
 #import "TestNavigationDelegate.h"
-#import <WebKit/WKWebView.h>
+#import "TestWKWebView.h"
 #import <WebKit/WKErrorPrivate.h>
+#import <WebKit/WKWebViewPrivate.h>
+#import <WebKit/_WKContentWorld.h>
 #import <wtf/RetainPtr.h>
 
 static bool isDone;
@@ -111,3 +113,114 @@ TEST(WKWebView, EvaluateJavaScriptErrorCases)
     isDone = false;
     TestWebKitAPI::Util::run(&isDone);
 }
+
+TEST(WKWebView, WKContentWorld)
+{
+    EXPECT_NULL(_WKContentWorld.pageContentWorld.name);
+    EXPECT_NULL(_WKContentWorld.defaultClientWorld.name);
+    EXPECT_FALSE(_WKContentWorld.pageContentWorld == _WKContentWorld.defaultClientWorld);
+
+    _WKContentWorld *namedWorld = [_WKContentWorld worldWithName:@"Name"];
+    EXPECT_TRUE([namedWorld.name isEqualToString:@"Name"]);
+    EXPECT_EQ(namedWorld, [_WKContentWorld worldWithName:@"Name"]);
+}
+
+TEST(WKWebView, EvaluateJavaScriptInWorlds)
+{
+    RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600)]);
+    [webView synchronouslyLoadHTMLString:@"<html></html>"];
+
+    // Set a variable in the main world via "normal" evaluateJavaScript
+    isDone = false;
+    [webView evaluateJavaScript:@"var foo = 'bar'" completionHandler:^(id result, NSError *error) {
+        isDone = true;
+    }];
+    isDone = false;
+
+    // Verify that value is visible when evaluating in the pageContentWorld
+    [webView _evaluateJavaScript:@"foo" inWorld:_WKContentWorld.pageContentWorld completionHandler:^(id result, NSError *error) {
+        EXPECT_TRUE([result isKindOfClass:[NSString class]]);
+        EXPECT_TRUE([result isEqualToString:@"bar"]);
+        isDone = true;
+    }];
+    isDone = false;
+
+    // Verify that value is not visible when evaluating in the defaultClientWorld
+    [webView _evaluateJavaScript:@"foo" inWorld:_WKContentWorld.defaultClientWorld completionHandler:^(id result, NSError *error) {
+        EXPECT_NULL(result);
+        isDone = true;
+    }];
+    isDone = false;
+
+    // Verify that value is visible when calling a function in the pageContentWorld
+    [webView _callAsyncJavaScriptFunction:@"return foo" withArguments:nil inWorld:_WKContentWorld.pageContentWorld completionHandler:[&] (id result, NSError *error) {
+        EXPECT_TRUE([result isKindOfClass:[NSString class]]);
+        EXPECT_TRUE([result isEqualToString:@"bar"]);
+        isDone = true;
+    }];
+    isDone = false;
+
+    // Verify that value is not visible when calling a function in the defaultClientWorld
+    [webView _callAsyncJavaScriptFunction:@"return foo" withArguments:nil inWorld:_WKContentWorld.defaultClientWorld completionHandler:[&] (id result, NSError *error) {
+        EXPECT_NULL(result);
+        isDone = true;
+    }];
+    isDone = false;
+
+    // Set a varibale value in a named world.
+    RetainPtr<_WKContentWorld> namedWorld = [_WKContentWorld worldWithName:@"NamedWorld"];
+    [webView _evaluateJavaScript:@"var bar = baz" inWorld:namedWorld.get() completionHandler:^(id result, NSError *error) {
+        EXPECT_NULL(result);
+        isDone = true;
+    }];
+    isDone = false;
+
+    // Set a global varibale value in a named world via a function call.
+    [webView _callAsyncJavaScriptFunction:@"window.baz = bat" withArguments:nil inWorld:namedWorld.get() completionHandler:^(id result, NSError *error) {
+        EXPECT_NULL(result);
+        EXPECT_NULL(error);
+        isDone = true;
+    }];
+    isDone = false;
+
+    // Verify they are there in that named world.
+    [webView _evaluateJavaScript:@"bar" inWorld:namedWorld.get() completionHandler:^(id result, NSError *error) {
+        EXPECT_TRUE([result isKindOfClass:[NSString class]]);
+        EXPECT_TRUE([result isEqualToString:@"baz"]);
+        isDone = true;
+    }];
+    isDone = false;
+
+    [webView _evaluateJavaScript:@"window.baz" inWorld:namedWorld.get() completionHandler:^(id result, NSError *error) {
+        EXPECT_TRUE([result isKindOfClass:[NSString class]]);
+        EXPECT_TRUE([result isEqualToString:@"bat"]);
+        isDone = true;
+    }];
+    isDone = false;
+
+    // Verify they aren't there in the defaultClientWorld.
+    [webView _evaluateJavaScript:@"bar" inWorld:_WKContentWorld.defaultClientWorld completionHandler:^(id result, NSError *error) {
+        EXPECT_NULL(result);
+        isDone = true;
+    }];
+    isDone = false;
+
+    [webView _evaluateJavaScript:@"window.baz" inWorld:_WKContentWorld.defaultClientWorld completionHandler:^(id result, NSError *error) {
+        EXPECT_NULL(result);
+        isDone = true;
+    }];
+    isDone = false;
+
+    // Verify they aren't there in the pageContentWorld.
+    [webView _evaluateJavaScript:@"bar" inWorld:_WKContentWorld.pageContentWorld completionHandler:^(id result, NSError *error) {
+        EXPECT_NULL(result);
+        isDone = true;
+    }];
+    isDone = false;
+
+    [webView _evaluateJavaScript:@"window.baz" inWorld:_WKContentWorld.pageContentWorld completionHandler:^(id result, NSError *error) {
+        EXPECT_NULL(result);
+        isDone = true;
+    }];
+    isDone = false;
+}
index f873a66..ef61adb 100644 (file)
@@ -33,6 +33,7 @@
 #import <WebKit/WKWebViewConfigurationPrivate.h>
 #import <WebKit/WebKitPrivate.h>
 #import <WebKit/_WKActivatedElementInfo.h>
+#import <WebKit/_WKContentWorld.h>
 #import <WebKit/_WKProcessPoolConfiguration.h>
 #import <objc/runtime.h>
 #import <wtf/RetainPtr.h>
@@ -185,7 +186,7 @@ SOFT_LINK_CLASS(UIKit, UIWindow)
         *errorOut = nil;
 
     RetainPtr<id> evalResult;
-    [self _callAsyncFunction:script withArguments:arguments completionHandler:[&] (id result, NSError *error) {
+    [self _callAsyncJavaScriptFunction:script withArguments:arguments inWorld:_WKContentWorld.pageContentWorld completionHandler:[&] (id result, NSError *error) {
         evalResult = result;
         if (errorOut)
             *errorOut = [error retain];