Diff
Modified: trunk/Source/WebCore/ChangeLog (253949 => 253950)
--- trunk/Source/WebCore/ChangeLog 2019-12-30 20:16:54 UTC (rev 253949)
+++ trunk/Source/WebCore/ChangeLog 2019-12-30 20:23:20 UTC (rev 253950)
@@ -1,3 +1,36 @@
+2019-12-30 Brady Eidson <beid...@apple.com>
+
+ Add WKWebView SPI to evaluate a function with arguments
+ https://bugs.webkit.org/show_bug.cgi?id=205239
+
+ Reviewed by Alex Christensen.
+
+ Covered by new API tests.
+
+ * Headers.cmake:
+ * WebCore.xcodeproj/project.pbxproj:
+
+ * bindings/js/ExceptionDetails.h:
+
+ * bindings/js/RunJavaScriptParameters.h: Added.
+ (WebCore::RunJavaScriptParameters::RunJavaScriptParameters):
+ (WebCore::RunJavaScriptParameters::encode const):
+ (WebCore::RunJavaScriptParameters::decode):
+
+ * bindings/js/ScriptController.cpp:
+ (WebCore::ScriptController::executeScriptInWorldIgnoringException):
+ (WebCore::ScriptController::executeScriptInWorld):
+ (WebCore::ScriptController::callInWorld):
+ (WebCore::ScriptController::executeUserAgentScriptInWorld):
+ (WebCore::ScriptController::executeUserAgentScriptInWorldInternal):
+ (WebCore::ScriptController::executeAsynchronousUserAgentScriptInWorld):
+ * bindings/js/ScriptController.h:
+
+ XPathGrammar changes completely unrelated to the functionality of this patch,
+ but because of our poor #include hygiene these were necessary to keep linuxes building.
+ * xml/XPathGrammar.cpp:
+ * xml/XPathGrammar.y:
+
2019-12-30 Antti Koivisto <an...@apple.com>
Style invalidation cleanups
Modified: trunk/Source/WebCore/Headers.cmake (253949 => 253950)
--- trunk/Source/WebCore/Headers.cmake 2019-12-30 20:16:54 UTC (rev 253949)
+++ trunk/Source/WebCore/Headers.cmake 2019-12-30 20:23:20 UTC (rev 253950)
@@ -240,6 +240,7 @@
bindings/js/JSValueInWrappedObject.h
bindings/js/JSWindowProxy.h
bindings/js/ReadableStreamDefaultController.h
+ bindings/js/RunJavaScriptParameters.h
bindings/js/ScriptCachedFrameData.h
bindings/js/ScriptController.h
bindings/js/ScriptState.h
Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (253949 => 253950)
--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj 2019-12-30 20:16:54 UTC (rev 253949)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj 2019-12-30 20:23:20 UTC (rev 253950)
@@ -1533,6 +1533,7 @@
51BA4AC41BBB5CD800DF3D6D /* IDBDatabaseInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 51BA4AC21BBB5CBF00DF3D6D /* IDBDatabaseInfo.h */; settings = {ATTRIBUTES = (Private, ); }; };
51BA4ACB1BBC5BD900DF3D6D /* MemoryIDBBackingStore.h in Headers */ = {isa = PBXBuildFile; fileRef = 51BA4AC91BBC5B9E00DF3D6D /* MemoryIDBBackingStore.h */; };
51BA4ACC1BBC5BDD00DF3D6D /* IDBBackingStore.h in Headers */ = {isa = PBXBuildFile; fileRef = 51BA4AC71BBC5AD600DF3D6D /* IDBBackingStore.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ 51BA947123AC305300444846 /* RunJavaScriptParameters.h in Headers */ = {isa = PBXBuildFile; fileRef = 51BA946F23AC305000444846 /* RunJavaScriptParameters.h */; settings = {ATTRIBUTES = (Private, ); }; };
51BCCE301F8F179E006BA0ED /* ServiceWorkerThread.h in Headers */ = {isa = PBXBuildFile; fileRef = 517C87101F8EE72E00EB8076 /* ServiceWorkerThread.h */; settings = {ATTRIBUTES = (Private, ); }; };
51BE37E00DAEE00E001085FC /* StorageArea.h in Headers */ = {isa = PBXBuildFile; fileRef = 51BE37DE0DAEE00E001085FC /* StorageArea.h */; settings = {ATTRIBUTES = (Private, ); }; };
51C0AA390F2AA10A001648C2 /* CachedFrame.h in Headers */ = {isa = PBXBuildFile; fileRef = 51C0AA380F2AA10A001648C2 /* CachedFrame.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -8336,6 +8337,7 @@
51BA4AC71BBC5AD600DF3D6D /* IDBBackingStore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IDBBackingStore.h; sourceTree = "<group>"; };
51BA4AC81BBC5B9E00DF3D6D /* MemoryIDBBackingStore.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MemoryIDBBackingStore.cpp; sourceTree = "<group>"; };
51BA4AC91BBC5B9E00DF3D6D /* MemoryIDBBackingStore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MemoryIDBBackingStore.h; sourceTree = "<group>"; };
+ 51BA946F23AC305000444846 /* RunJavaScriptParameters.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RunJavaScriptParameters.h; sourceTree = "<group>"; };
51BE37DE0DAEE00E001085FC /* StorageArea.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StorageArea.h; sourceTree = "<group>"; };
51C0AA380F2AA10A001648C2 /* CachedFrame.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CachedFrame.h; sourceTree = "<group>"; };
51C0AA400F2AA15E001648C2 /* CachedFrame.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CachedFrame.cpp; sourceTree = "<group>"; };
@@ -25405,6 +25407,7 @@
41B459DA1F4CADB90000F6FD /* ReadableStream.h */,
418C395E1C8F0AAB0051C8A3 /* ReadableStreamDefaultController.cpp */,
418C395F1C8F0AAB0051C8A3 /* ReadableStreamDefaultController.h */,
+ 51BA946F23AC305000444846 /* RunJavaScriptParameters.h */,
41F1D21E0EF35C2A00DA8753 /* ScriptCachedFrameData.cpp */,
41F1D21D0EF35C2A00DA8753 /* ScriptCachedFrameData.h */,
93B70D5309EB0C7C009D8468 /* ScriptController.cpp */,
@@ -32131,6 +32134,7 @@
E4863CFE23842E9E00972158 /* RuleData.h in Headers */,
A79BADA2161E7F3F00C2E652 /* RuleFeature.h in Headers */,
A79BADA4161E7F3F00C2E652 /* RuleSet.h in Headers */,
+ 51BA947123AC305300444846 /* RunJavaScriptParameters.h in Headers */,
2D76BB821945632400CFD29A /* RunLoopObserver.h in Headers */,
1A569D1F0D7E2B82007C3983 /* runtime_array.h in Headers */,
1A569D210D7E2B82007C3983 /* runtime_method.h in Headers */,
Modified: trunk/Source/WebCore/bindings/js/ExceptionDetails.h (253949 => 253950)
--- trunk/Source/WebCore/bindings/js/ExceptionDetails.h 2019-12-30 20:16:54 UTC (rev 253949)
+++ trunk/Source/WebCore/bindings/js/ExceptionDetails.h 2019-12-30 20:23:20 UTC (rev 253950)
@@ -33,7 +33,10 @@
String message;
int lineNumber { 0 };
int columnNumber { 0 };
- String sourceURL;
+ // This bizarre explicit initialization of String is because older compilers (like on High Sierra)
+ // don't properly handle partial initialization lists unless every struct member has an explicit default value.
+ // Once we stop building on those platforms we can remove this.
+ String sourceURL { };
};
} // namespace WebCore
Added: trunk/Source/WebCore/bindings/js/RunJavaScriptParameters.h (0 => 253950)
--- trunk/Source/WebCore/bindings/js/RunJavaScriptParameters.h (rev 0)
+++ trunk/Source/WebCore/bindings/js/RunJavaScriptParameters.h 2019-12-30 20:23:20 UTC (rev 253950)
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2019 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 <wtf/HashMap.h>
+#include <wtf/Vector.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+enum class RunAsAsyncFunction : bool { No, Yes };
+enum class ForceUserGesture : bool { No, Yes };
+
+using ArgumentWireBytesMap = HashMap<String, Vector<uint8_t>>;
+
+struct RunJavaScriptParameters {
+ RunJavaScriptParameters(String&& source, RunAsAsyncFunction runAsAsyncFunction, Optional<ArgumentWireBytesMap>&& arguments, ForceUserGesture forceUserGesture)
+ : source(WTFMove(source))
+ , runAsAsyncFunction(runAsAsyncFunction)
+ , arguments(WTFMove(arguments))
+ , forceUserGesture(forceUserGesture)
+ {
+ }
+
+ RunJavaScriptParameters(const String& source, bool runAsAsyncFunction, Optional<ArgumentWireBytesMap>&& arguments, bool forceUserGesture)
+ : source(source)
+ , runAsAsyncFunction(runAsAsyncFunction ? RunAsAsyncFunction::Yes : RunAsAsyncFunction::No)
+ , arguments(WTFMove(arguments))
+ , forceUserGesture(forceUserGesture ? ForceUserGesture::Yes : ForceUserGesture::No)
+ {
+ }
+
+ RunJavaScriptParameters(String&& source, bool runAsAsyncFunction, Optional<ArgumentWireBytesMap>&& arguments, bool forceUserGesture)
+ : source(WTFMove(source))
+ , runAsAsyncFunction(runAsAsyncFunction ? RunAsAsyncFunction::Yes : RunAsAsyncFunction::No)
+ , arguments(WTFMove(arguments))
+ , forceUserGesture(forceUserGesture ? ForceUserGesture::Yes : ForceUserGesture::No)
+ {
+ }
+
+ String source;
+ RunAsAsyncFunction runAsAsyncFunction;
+ Optional<ArgumentWireBytesMap> arguments;
+ ForceUserGesture forceUserGesture;
+
+ template<typename Encoder> void encode(Encoder& encoder) const
+ {
+ encoder << source << runAsAsyncFunction << arguments << forceUserGesture;
+ }
+
+ template<typename Decoder> static Optional<RunJavaScriptParameters> decode(Decoder& decoder)
+ {
+ String source;
+ if (!decoder.decode(source))
+ return WTF::nullopt;
+
+ RunAsAsyncFunction runAsAsyncFunction;
+ if (!decoder.decode(runAsAsyncFunction))
+ return WTF::nullopt;
+
+ Optional<ArgumentWireBytesMap> arguments;
+ if (!decoder.decode(arguments))
+ return WTF::nullopt;
+
+ ForceUserGesture forceUserGesture;
+ if (!decoder.decode(forceUserGesture))
+ return WTF::nullopt;
+
+ return { RunJavaScriptParameters { WTFMove(source), runAsAsyncFunction, WTFMove(arguments), forceUserGesture } };
+ }
+};
+
+} // namespace WebCore
Modified: trunk/Source/WebCore/bindings/js/ScriptController.cpp (253949 => 253950)
--- trunk/Source/WebCore/bindings/js/ScriptController.cpp 2019-12-30 20:16:54 UTC (rev 253949)
+++ trunk/Source/WebCore/bindings/js/ScriptController.cpp 2019-12-30 20:23:20 UTC (rev 253950)
@@ -47,6 +47,7 @@
#include "PageGroup.h"
#include "PaymentCoordinator.h"
#include "PluginViewBase.h"
+#include "RunJavaScriptParameters.h"
#include "RuntimeApplicationChecks.h"
#include "ScriptDisallowedScope.h"
#include "ScriptSourceCode.h"
@@ -565,22 +566,118 @@
JSC::JSValue ScriptController::executeScriptInWorldIgnoringException(DOMWrapperWorld& world, const String& script, bool forceUserGesture)
{
- auto result = executeScriptInWorld(world, script, forceUserGesture);
+ auto result = executeScriptInWorld(world, RunJavaScriptParameters { script, false, WTF::nullopt, forceUserGesture });
return result ? result.value() : JSC::JSValue { };
}
-ValueOrException ScriptController::executeScriptInWorld(DOMWrapperWorld& world, const String& script, bool forceUserGesture)
+ValueOrException ScriptController::executeScriptInWorld(DOMWrapperWorld& world, RunJavaScriptParameters&& parameters)
{
- UserGestureIndicator gestureIndicator(forceUserGesture ? Optional<ProcessingUserGestureState>(ProcessingUserGesture) : WTF::nullopt);
- ScriptSourceCode sourceCode(script, URL(m_frame.document()->url()), TextPosition(), JSC::SourceProviderSourceType::Program, CachedScriptFetcher::create(m_frame.document()->charset()));
+ UserGestureIndicator gestureIndicator(parameters.forceUserGesture == ForceUserGesture::Yes ? Optional<ProcessingUserGestureState>(ProcessingUserGesture) : WTF::nullopt);
// FIXME: Instead of returning an empty JSValue, should return an ExceptionDetails.
if (!canExecuteScripts(AboutToExecuteScript) || isPaused())
return { };
- return evaluateInWorld(sourceCode, world);
+ switch (parameters.runAsAsyncFunction) {
+ case RunAsAsyncFunction::No: {
+ ScriptSourceCode sourceCode(parameters.source, URL(m_frame.document()->url()), TextPosition(), JSC::SourceProviderSourceType::Program, CachedScriptFetcher::create(m_frame.document()->charset()));
+ return evaluateInWorld(sourceCode, world);
+ }
+ case RunAsAsyncFunction::Yes:
+ return callInWorld(WTFMove(parameters), world);
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ }
}
+ValueOrException ScriptController::callInWorld(RunJavaScriptParameters&& parameters, DOMWrapperWorld& world)
+{
+ ASSERT(parameters.runAsAsyncFunction == RunAsAsyncFunction::Yes);
+ ASSERT(parameters.arguments);
+
+ auto& proxy = jsWindowProxy(world);
+ auto& globalObject = *proxy.window();
+ MarkedArgumentBuffer markedArguments;
+ StringBuilder functionStringBuilder;
+ String errorMessage;
+
+ // Build up a new script string that is an async function with arguments, and deserialize those arguments.
+ functionStringBuilder.append("(function(");
+ for (auto argument = parameters.arguments->begin(); argument != parameters.arguments->end();) {
+ functionStringBuilder.append(argument->key);
+ auto serializedArgument = SerializedScriptValue::createFromWireBytes(WTFMove(argument->value));
+
+ auto scope = DECLARE_CATCH_SCOPE(globalObject.vm());
+ auto jsArgument = serializedArgument->deserialize(globalObject, &globalObject);
+ if (UNLIKELY(scope.exception())) {
+ errorMessage = "Unable to deserialize argument to execute asynchronous _javascript_ function";
+ break;
+ }
+
+ markedArguments.append(jsArgument);
+
+ ++argument;
+ if (argument != parameters.arguments->end())
+ functionStringBuilder.append(',');
+ }
+
+ if (!errorMessage.isEmpty())
+ return makeUnexpected(ExceptionDetails { errorMessage });
+
+ functionStringBuilder.append("){", parameters.source, "})");
+
+ auto sourceCode = ScriptSourceCode { functionStringBuilder.toString(), URL(m_frame.document()->url()), TextPosition(), JSC::SourceProviderSourceType::Program, CachedScriptFetcher::create(m_frame.document()->charset()) };
+ const auto& jsSourceCode = sourceCode.jsSourceCode();
+
+ String sourceURL = jsSourceCode.provider()->url();
+ const String* savedSourceURL = m_sourceURL;
+ m_sourceURL = &sourceURL;
+
+ Ref<Frame> protector(m_frame);
+
+ InspectorInstrumentation::willEvaluateScript(m_frame, sourceURL, sourceCode.startLine(), sourceCode.startColumn());
+
+ NakedPtr<JSC::Exception> evaluationException;
+ Optional<ExceptionDetails> optionalDetails;
+ JSValue returnValue;
+ do {
+ JSValue functionObject = JSExecState::profiledEvaluate(&globalObject, JSC::ProfilingReason::Other, jsSourceCode, &proxy, evaluationException);
+
+ if (evaluationException)
+ break;
+
+ if (!functionObject || !functionObject.isFunction(world.vm())) {
+ optionalDetails = { { "Unable to create _javascript_ async function to call"_s } };
+ break;
+ }
+
+ // FIXME: https://bugs.webkit.org/show_bug.cgi?id=205562
+ // Getting CallData/CallType shouldn't be required to call into JS.
+ CallData callData;
+ CallType callType = getCallData(world.vm(), functionObject, callData);
+ if (callType == CallType::None) {
+ optionalDetails = { { "Unable to prepare _javascript_ async function to be called"_s } };
+ break;
+ }
+
+ returnValue = JSExecState::profiledCall(&globalObject, JSC::ProfilingReason::Other, functionObject, callType, callData, &proxy, markedArguments, evaluationException);
+ } while (false);
+
+ InspectorInstrumentation::didEvaluateScript(m_frame);
+
+ if (evaluationException && !optionalDetails) {
+ ExceptionDetails details;
+ reportException(&globalObject, evaluationException, sourceCode.cachedScript(), &details);
+ optionalDetails = WTFMove(details);
+ }
+
+ m_sourceURL = savedSourceURL;
+
+ if (optionalDetails)
+ return makeUnexpected(*optionalDetails);
+ return returnValue;
+}
+
JSC::JSValue ScriptController::executeUserAgentScriptInWorldIgnoringException(DOMWrapperWorld& world, const String& script, bool forceUserGesture)
{
auto result = executeUserAgentScriptInWorld(world, script, forceUserGesture);
@@ -588,14 +685,28 @@
}
ValueOrException ScriptController::executeUserAgentScriptInWorld(DOMWrapperWorld& world, const String& script, bool forceUserGesture)
{
+ return executeUserAgentScriptInWorldInternal(world, { script, false, WTF::nullopt, forceUserGesture });
+}
+
+ValueOrException ScriptController::executeUserAgentScriptInWorldInternal(DOMWrapperWorld& world, RunJavaScriptParameters&& parameters)
+{
auto& document = *m_frame.document();
if (!shouldAllowUserAgentScripts(document))
- return makeUnexpected(ExceptionDetails { "Unable to run user agent scripts in this document for security reasons"_s, 0, 0, { } });
+ return makeUnexpected(ExceptionDetails { "Unable to run user agent scripts in this document for security reasons"_s });
document.setHasEvaluatedUserAgentScripts();
- return executeScriptInWorld(world, script, forceUserGesture);
+ return executeScriptInWorld(world, WTFMove(parameters));
}
+void ScriptController::executeAsynchronousUserAgentScriptInWorld(DOMWrapperWorld& world, RunJavaScriptParameters&& parameters, ResolveFunction&& resolveFunction)
+{
+ auto result = executeUserAgentScriptInWorldInternal(world, WTFMove(parameters));
+
+ // FIXME: If the result is a thenable, install the fulfill/reject handlers instead of resolving now.
+
+ resolveFunction(result);
+}
+
bool ScriptController::shouldAllowUserAgentScripts(Document& document) const
{
#if ENABLE(APPLE_PAY)
Modified: trunk/Source/WebCore/bindings/js/ScriptController.h (253949 => 253950)
--- trunk/Source/WebCore/bindings/js/ScriptController.h 2019-12-30 20:16:54 UTC (rev 253949)
+++ trunk/Source/WebCore/bindings/js/ScriptController.h 2019-12-30 20:23:20 UTC (rev 253950)
@@ -23,6 +23,7 @@
#include "FrameLoaderTypes.h"
#include "JSWindowProxy.h"
+#include "SerializedScriptValue.h"
#include "WindowProxy.h"
#include <_javascript_Core/JSBase.h>
#include <_javascript_Core/Strong.h>
@@ -63,7 +64,11 @@
class ScriptSourceCode;
class SecurityOrigin;
class Widget;
+
+enum class RunAsAsyncFunction : bool;
+
struct ExceptionDetails;
+struct RunJavaScriptParameters;
enum ReasonForCallingCanExecuteScripts {
AboutToCreateEventListener,
@@ -91,11 +96,15 @@
static void getAllWorlds(Vector<Ref<DOMWrapperWorld>>&);
+ using ResolveFunction = CompletionHandler<void(ValueOrException)>;
+
WEBCORE_EXPORT JSC::JSValue executeScriptIgnoringException(const String& script, bool forceUserGesture = false);
JSC::JSValue executeScriptInWorldIgnoringException(DOMWrapperWorld&, const String& script, bool forceUserGesture = false);
- ValueOrException executeScriptInWorld(DOMWrapperWorld&, const String& script, bool forceUserGesture = false);
WEBCORE_EXPORT JSC::JSValue executeUserAgentScriptInWorldIgnoringException(DOMWrapperWorld&, const String& script, bool forceUserGesture);
WEBCORE_EXPORT ValueOrException executeUserAgentScriptInWorld(DOMWrapperWorld&, const String& script, bool forceUserGesture);
+ WEBCORE_EXPORT void executeAsynchronousUserAgentScriptInWorld(DOMWrapperWorld&, RunJavaScriptParameters&&, ResolveFunction&&);
+ JSC::JSValue evaluateIgnoringException(const ScriptSourceCode&);
+ JSC::JSValue evaluateInWorldIgnoringException(const ScriptSourceCode&, DOMWrapperWorld&);
bool shouldAllowUserAgentScripts(Document&) const;
@@ -106,10 +115,6 @@
// Darwin is an exception to this rule: it is OK to call this function from any thread, even reentrantly.
static void initializeThreading();
- JSC::JSValue evaluateIgnoringException(const ScriptSourceCode&);
- JSC::JSValue evaluateInWorldIgnoringException(const ScriptSourceCode&, DOMWrapperWorld&);
- ValueOrException evaluateInWorld(const ScriptSourceCode&, DOMWrapperWorld&);
-
void loadModuleScriptInWorld(LoadableModuleScript&, const String& moduleName, Ref<ModuleFetchParameters>&&, DOMWrapperWorld&);
void loadModuleScript(LoadableModuleScript&, const String& moduleName, Ref<ModuleFetchParameters>&&);
void loadModuleScriptInWorld(LoadableModuleScript&, const ScriptSourceCode&, DOMWrapperWorld&);
@@ -171,6 +176,11 @@
bool willReplaceWithResultOfExecutingJavascriptURL() const { return m_willReplaceWithResultOfExecutingJavascriptURL; }
private:
+ ValueOrException executeUserAgentScriptInWorldInternal(DOMWrapperWorld&, RunJavaScriptParameters&&);
+ ValueOrException executeScriptInWorld(DOMWrapperWorld&, RunJavaScriptParameters&&);
+ ValueOrException evaluateInWorld(const ScriptSourceCode&, DOMWrapperWorld&);
+ ValueOrException callInWorld(RunJavaScriptParameters&&, DOMWrapperWorld&);
+
void setupModuleScriptHandlers(LoadableModuleScript&, JSC::JSInternalPromise&, DOMWrapperWorld&);
void disconnectPlatformScriptObjects();
Modified: trunk/Source/WebCore/xml/XPathGrammar.cpp (253949 => 253950)
--- trunk/Source/WebCore/xml/XPathGrammar.cpp 2019-12-30 20:16:54 UTC (rev 253949)
+++ trunk/Source/WebCore/xml/XPathGrammar.cpp 2019-12-30 20:23:20 UTC (rev 253950)
@@ -1969,7 +1969,7 @@
#line 402 "WebCore/xml/XPathGrammar.y"
{
(yyvsp[(3) - (3)].locationPath)->setAbsolute();
- (yyval._expression_) = new Path(std::unique_ptr<_expression_>((yyvsp[(1) - (3)]._expression_)), std::unique_ptr<LocationPath>((yyvsp[(3) - (3)].locationPath)));
+ (yyval._expression_) = new XPath::Path(std::unique_ptr<_expression_>((yyvsp[(1) - (3)]._expression_)), std::unique_ptr<LocationPath>((yyvsp[(3) - (3)].locationPath)));
;}
break;
@@ -1978,7 +1978,7 @@
{
(yyvsp[(3) - (3)].locationPath)->prependStep(std::unique_ptr<Step>((yyvsp[(2) - (3)].step)));
(yyvsp[(3) - (3)].locationPath)->setAbsolute();
- (yyval._expression_) = new Path(std::unique_ptr<_expression_>((yyvsp[(1) - (3)]._expression_)), std::unique_ptr<LocationPath>((yyvsp[(3) - (3)].locationPath)));
+ (yyval._expression_) = new XPath::Path(std::unique_ptr<_expression_>((yyvsp[(1) - (3)]._expression_)), std::unique_ptr<LocationPath>((yyvsp[(3) - (3)].locationPath)));
;}
break;
Modified: trunk/Source/WebCore/xml/XPathGrammar.y (253949 => 253950)
--- trunk/Source/WebCore/xml/XPathGrammar.y 2019-12-30 20:16:54 UTC (rev 253949)
+++ trunk/Source/WebCore/xml/XPathGrammar.y 2019-12-30 20:23:20 UTC (rev 253950)
@@ -401,7 +401,7 @@
FilterExpr '/' RelativeLocationPath
{
$3->setAbsolute();
- $$ = new Path(std::unique_ptr<_expression_>($1), std::unique_ptr<LocationPath>($3));
+ $$ = new XPath::Path(std::unique_ptr<_expression_>($1), std::unique_ptr<LocationPath>($3));
}
|
FilterExpr DescendantOrSelf RelativeLocationPath
@@ -408,7 +408,7 @@
{
$3->prependStep(std::unique_ptr<Step>($2));
$3->setAbsolute();
- $$ = new Path(std::unique_ptr<_expression_>($1), std::unique_ptr<LocationPath>($3));
+ $$ = new XPath::Path(std::unique_ptr<_expression_>($1), std::unique_ptr<LocationPath>($3));
}
;
Modified: trunk/Source/WebKit/ChangeLog (253949 => 253950)
--- trunk/Source/WebKit/ChangeLog 2019-12-30 20:16:54 UTC (rev 253949)
+++ trunk/Source/WebKit/ChangeLog 2019-12-30 20:23:20 UTC (rev 253950)
@@ -1,3 +1,49 @@
+2019-12-30 Brady Eidson <beid...@apple.com>
+
+ Add WKWebView SPI to evaluate a function with arguments
+ https://bugs.webkit.org/show_bug.cgi?id=205239
+
+ Reviewed by Alex Christensen.
+
+ * Shared/API/APISerializedScriptValue.h:
+
+ * UIProcess/API/C/WKPage.cpp:
+ (WKPageRunJavaScriptInMainFrame):
+
+ * UIProcess/API/Cocoa/APISerializedScriptValueCocoa.mm:
+ (API::sharedContext):
+ (API::SerializedScriptValue::deserialize):
+ (API::SerializedScriptValue::wireBytesFromNSObject):
+
+ * UIProcess/API/Cocoa/WKWebView.mm:
+ (-[WKWebView evaluateJavaScript:completionHandler:]):
+ (validateArgument):
+ (-[WKWebView _evaluateJavaScript:asAsyncFunction:withArguments:forceUserGesture:completionHandler:]):
+ (-[WKWebView _callAsyncFunction:withArguments:completionHandler:]):
+ (-[WKWebView _evaluateJavaScriptWithoutUserGesture:completionHandler:]):
+ (-[WKWebView _evaluateJavaScript:forceUserGesture:completionHandler:]): Deleted.
+ * UIProcess/API/Cocoa/WKWebViewPrivate.h:
+
+ * UIProcess/API/glib/WebKitWebView.cpp:
+ (webkit_web_view_run_javascript):
+ (webkit_web_view_run_javascript_in_world):
+ (resourcesStreamReadCallback):
+
+ * UIProcess/WebPageProxy.cpp:
+ (WebKit::WebPageProxy::runJavaScriptInMainFrame):
+ (WebKit::WebPageProxy::runJavaScriptInMainFrameScriptWorld):
+ * UIProcess/WebPageProxy.h:
+
+ * UIProcess/socket/RemoteInspectorProtocolHandler.cpp:
+ (WebKit::RemoteInspectorProtocolHandler::runScript):
+
+ * WebProcess/WebPage/WebPage.cpp:
+ (WebKit::WebPage::runJavaScript):
+ (WebKit::WebPage::runJavaScriptInMainFrameScriptWorld):
+ (WebKit::WebPage::runJavaScriptInFrame):
+ * WebProcess/WebPage/WebPage.h:
+ * WebProcess/WebPage/WebPage.messages.in:
+
2019-12-29 Peng Liu <peng.l...@apple.com>
Tweak the format and comment in the code to support media in GPU process
Modified: trunk/Source/WebKit/Shared/API/APISerializedScriptValue.h (253949 => 253950)
--- trunk/Source/WebKit/Shared/API/APISerializedScriptValue.h 2019-12-30 20:16:54 UTC (rev 253949)
+++ trunk/Source/WebKit/Shared/API/APISerializedScriptValue.h 2019-12-30 20:23:20 UTC (rev 253950)
@@ -61,6 +61,7 @@
#if PLATFORM(COCOA) && defined(__OBJC__)
static id deserialize(WebCore::SerializedScriptValue&, JSValueRef* exception);
+ static Optional<Vector<uint8_t>> wireBytesFromNSObject(id);
#endif
IPC::DataReference dataReference() const { return m_serializedScriptValue->data(); }
Modified: trunk/Source/WebKit/UIProcess/API/C/WKPage.cpp (253949 => 253950)
--- trunk/Source/WebKit/UIProcess/API/C/WKPage.cpp 2019-12-30 20:16:54 UTC (rev 253949)
+++ trunk/Source/WebKit/UIProcess/API/C/WKPage.cpp 2019-12-30 20:23:20 UTC (rev 253950)
@@ -2472,7 +2472,7 @@
void WKPageRunJavaScriptInMainFrame(WKPageRef pageRef, WKStringRef scriptRef, void* context, WKPageRunJavaScriptFunction callback)
{
- toImpl(pageRef)->runJavaScriptInMainFrame(toImpl(scriptRef)->string(), true, [context, callback](API::SerializedScriptValue* returnValue, Optional<WebCore::ExceptionDetails>, CallbackBase::Error error) {
+ toImpl(pageRef)->runJavaScriptInMainFrame({ toImpl(scriptRef)->string(), false, WTF::nullopt, true }, [context, callback](API::SerializedScriptValue* returnValue, Optional<WebCore::ExceptionDetails>, CallbackBase::Error error) {
callback(toAPI(returnValue), (error != CallbackBase::Error::None) ? toAPI(API::Error::create().ptr()) : 0, context);
});
}
Modified: trunk/Source/WebKit/UIProcess/API/Cocoa/APISerializedScriptValueCocoa.mm (253949 => 253950)
--- trunk/Source/WebKit/UIProcess/API/Cocoa/APISerializedScriptValueCocoa.mm 2019-12-30 20:16:54 UTC (rev 253949)
+++ trunk/Source/WebKit/UIProcess/API/Cocoa/APISerializedScriptValueCocoa.mm 2019-12-30 20:23:20 UTC (rev 253950)
@@ -26,7 +26,9 @@
#include "config.h"
#include "APISerializedScriptValue.h"
+#import <_javascript_Core/APICast.h>
#import <_javascript_Core/JSContext.h>
+#import <_javascript_Core/JSGlobalObjectInlines.h>
#import <_javascript_Core/JSValue.h>
#import <wtf/NeverDestroyed.h>
#import <wtf/RunLoop.h>
@@ -59,11 +61,16 @@
RunLoop::Timer<SharedJSContext> m_timer;
};
+static SharedJSContext& sharedContext()
+{
+ static NeverDestroyed<SharedJSContext> sharedContext;
+ return sharedContext.get();
+}
+
id SerializedScriptValue::deserialize(WebCore::SerializedScriptValue& serializedScriptValue, JSValueRef* exception)
{
ASSERT(RunLoop::isMain());
- static NeverDestroyed<SharedJSContext> sharedContext;
- JSContext* context = sharedContext.get().ensureContext();
+ JSContext* context = sharedContext().ensureContext();
JSValueRef valueRef = serializedScriptValue.deserialize([context JSGlobalContextRef], exception);
if (!valueRef)
@@ -73,4 +80,20 @@
return value.toObject;
}
+Optional<Vector<uint8_t>> SerializedScriptValue::wireBytesFromNSObject(id object)
+{
+ ASSERT(RunLoop::isMain());
+ JSContext* context = sharedContext().ensureContext();
+ JSValue *value = [JSValue valueWithObject:object inContext:context];
+ if (!value)
+ return WTF::nullopt;
+
+ auto globalObject = toJS([context JSGlobalContextRef]);
+ ASSERT(globalObject);
+ JSC::JSLockHolder lock(globalObject);
+
+ auto coreValue = WebCore::SerializedScriptValue::create(*globalObject, toJS(globalObject, [value JSValueRef]));
+ return coreValue->toWireBytes();
+}
+
} // API
Modified: trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm (253949 => 253950)
--- trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm 2019-12-30 20:16:54 UTC (rev 253949)
+++ trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm 2019-12-30 20:23:20 UTC (rev 253950)
@@ -822,14 +822,81 @@
- (void)evaluateJavaScript:(NSString *)_javascript_String completionHandler:(void (^)(id, NSError *))completionHandler
{
- [self _evaluateJavaScript:_javascript_String forceUserGesture:YES completionHandler:completionHandler];
+ [self _evaluateJavaScript:_javascript_String asAsyncFunction:NO withArguments:nil forceUserGesture:YES completionHandler:completionHandler];
}
-- (void)_evaluateJavaScript:(NSString *)_javascript_String forceUserGesture:(BOOL)forceUserGesture completionHandler:(void (^)(id, NSError *))completionHandler
+static bool validateArgument(id argument)
{
+ if ([argument isKindOfClass:[NSString class]] || [argument isKindOfClass:[NSNumber class]] || [argument isKindOfClass:[NSDate class]] || [argument isKindOfClass:[NSNull class]])
+ return true;
+
+ if ([argument isKindOfClass:[NSArray class]]) {
+ __block BOOL valid = true;
+
+ [argument enumerateObjectsUsingBlock:^(id object, NSUInteger, BOOL *stop) {
+ if (!validateArgument(object)) {
+ valid = false;
+ *stop = YES;
+ }
+ }];
+
+ return valid;
+ }
+
+ if ([argument isKindOfClass:[NSDictionary class]]) {
+ __block bool valid = true;
+
+ [argument enumerateKeysAndObjectsUsingBlock:^(id key, id value, BOOL *stop) {
+ if (!validateArgument(key) || !validateArgument(value)) {
+ valid = false;
+ *stop = YES;
+ }
+ }];
+
+ return valid;
+ }
+
+ return false;
+}
+
+- (void)_evaluateJavaScript:(NSString *)_javascript_String asAsyncFunction:(BOOL)asAsyncFunction withArguments:(NSDictionary<NSString *, id> *)arguments forceUserGesture:(BOOL)forceUserGesture completionHandler:(void (^)(id, NSError *))completionHandler
+{
auto handler = adoptNS([completionHandler copy]);
- _page->runJavaScriptInMainFrame(_javascript_String, forceUserGesture, [handler](API::SerializedScriptValue* serializedScriptValue, Optional<WebCore::ExceptionDetails> details, WebKit::ScriptValueCallback::Error errorCode) {
+ Optional<WebCore::ArgumentWireBytesMap> argumentsMap;
+ if (asAsyncFunction)
+ argumentsMap = WebCore::ArgumentWireBytesMap { };
+ NSString *errorMessage = nil;
+
+ for (id key in arguments) {
+ id value = [arguments objectForKey:key];
+ if (!validateArgument(value)) {
+ errorMessage = @"Function argument values must be one of the following types, or contain only the following types: NSString, NSNumber, NSDate, NSArray, and NSDictionary";
+ break;
+ }
+
+ auto wireBytes = API::SerializedScriptValue::wireBytesFromNSObject(value);
+ // Since we've validated the input dictionary above, we should never fail to serialize it into wire bytes.
+ ASSERT(wireBytes);
+ argumentsMap->set(key, *wireBytes);
+ }
+
+ if (errorMessage) {
+ RetainPtr<NSMutableDictionary> userInfo = adoptNS([[NSMutableDictionary alloc] init]);
+
+ [userInfo setObject:localizedDescriptionForErrorCode(WKErrorJavaScriptExceptionOccurred) forKey:NSLocalizedDescriptionKey];
+ [userInfo setObject:errorMessage forKey:_WKJavaScriptExceptionMessageErrorKey];
+
+ auto error = adoptNS([[NSError alloc] initWithDomain:WKErrorDomain code:WKErrorJavaScriptExceptionOccurred userInfo:userInfo.get()]);
+ dispatch_async(dispatch_get_main_queue(), [handler, error] {
+ auto rawHandler = (void (^)(id, NSError *))handler.get();
+ rawHandler(nil, error.get());
+ });
+
+ return;
+ }
+
+ _page->runJavaScriptInMainFrame(WebCore::RunJavaScriptParameters { _javascript_String, !!asAsyncFunction, WTFMove(argumentsMap), !!forceUserGesture }, [handler](API::SerializedScriptValue* serializedScriptValue, Optional<WebCore::ExceptionDetails> details, WebKit::ScriptValueCallback::Error errorCode) {
if (!handler)
return;
@@ -1923,6 +1990,11 @@
[self createPDFWithConfiguration:pdfConfiguration completionHandler:completionHandler];
}
+- (void)_callAsyncFunction:(NSString *)_javascript_String withArguments:(NSDictionary<NSString *, id> *)arguments completionHandler:(void (^)(id, NSError *error))completionHandler
+{
+ [self _evaluateJavaScript:_javascript_String asAsyncFunction:YES withArguments:arguments forceUserGesture:YES completionHandler:completionHandler];
+}
+
- (NSData *)_sessionStateData
{
// FIXME: This should not use the legacy session state encoder.
@@ -2065,7 +2137,7 @@
- (void)_evaluateJavaScriptWithoutUserGesture:(NSString *)_javascript_String completionHandler:(void (^)(id, NSError *))completionHandler
{
- [self _evaluateJavaScript:_javascript_String forceUserGesture:NO completionHandler:completionHandler];
+ [self _evaluateJavaScript:_javascript_String asAsyncFunction:NO withArguments:nil forceUserGesture:NO completionHandler:completionHandler];
}
- (void)_updateWebsitePolicies:(_WKWebsitePolicies *)websitePolicies
Modified: trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebViewPrivate.h (253949 => 253950)
--- trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebViewPrivate.h 2019-12-30 20:16:54 UTC (rev 253949)
+++ trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebViewPrivate.h 2019-12-30 20:23:20 UTC (rev 253950)
@@ -315,6 +315,9 @@
- (void)_focusTextInputContext:(_WKTextInputContext *)textInputElement completionHandler:(void(^)(BOOL))completionHandler WK_API_AVAILABLE(macos(10.15), ios(13.0));
- (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 *)_javascript_String withArguments:(NSDictionary<NSString *, id> *)arguments completionHandler:(void (^)(id, NSError *error))completionHandler;
+
@end
#if TARGET_OS_IPHONE
Modified: trunk/Source/WebKit/UIProcess/API/glib/WebKitWebView.cpp (253949 => 253950)
--- trunk/Source/WebKit/UIProcess/API/glib/WebKitWebView.cpp 2019-12-30 20:16:54 UTC (rev 253949)
+++ trunk/Source/WebKit/UIProcess/API/glib/WebKitWebView.cpp 2019-12-30 20:23:20 UTC (rev 253950)
@@ -3636,7 +3636,7 @@
g_return_if_fail(script);
GRefPtr<GTask> task = adoptGRef(g_task_new(webView, cancellable, callback, userData));
- getPage(webView).runJavaScriptInMainFrame(String::fromUTF8(script), true, [task = WTFMove(task)](API::SerializedScriptValue* serializedScriptValue, Optional<ExceptionDetails> details, WebKit::CallbackBase::Error) {
+ getPage(webView).runJavaScriptInMainFrame({ String::fromUTF8(script), false, WTF::nullopt, true }, [task = WTFMove(task)](API::SerializedScriptValue* serializedScriptValue, Optional<ExceptionDetails> details, WebKit::CallbackBase::Error) {
ExceptionDetails exceptionDetails;
if (details)
exceptionDetails = *details;
@@ -3737,7 +3737,7 @@
g_return_if_fail(worldName);
GRefPtr<GTask> task = adoptGRef(g_task_new(webView, cancellable, callback, userData));
- getPage(webView).runJavaScriptInMainFrameScriptWorld(String::fromUTF8(script), true, String::fromUTF8(worldName), [task = WTFMove(task)](API::SerializedScriptValue* serializedScriptValue, Optional<ExceptionDetails> details, WebKit::CallbackBase::Error) {
+ 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) {
ExceptionDetails exceptionDetails;
if (details)
exceptionDetails = *details;
@@ -3779,7 +3779,7 @@
WebKitWebView* webView = WEBKIT_WEB_VIEW(g_task_get_source_object(task.get()));
gpointer outputStreamData = g_memory_output_stream_get_data(G_MEMORY_OUTPUT_STREAM(object));
- getPage(webView).runJavaScriptInMainFrame(String::fromUTF8(reinterpret_cast<const gchar*>(outputStreamData)), true,
+ getPage(webView).runJavaScriptInMainFrame({ String::fromUTF8(reinterpret_cast<const gchar*>(outputStreamData)), false, WTF::nullopt, true},
[task](API::SerializedScriptValue* serializedScriptValue, Optional<ExceptionDetails> details, WebKit::CallbackBase::Error) {
ExceptionDetails exceptionDetails;
if (details)
Modified: trunk/Source/WebKit/UIProcess/WebPageProxy.cpp (253949 => 253950)
--- trunk/Source/WebKit/UIProcess/WebPageProxy.cpp 2019-12-30 20:16:54 UTC (rev 253949)
+++ trunk/Source/WebKit/UIProcess/WebPageProxy.cpp 2019-12-30 20:23:20 UTC (rev 253950)
@@ -3849,12 +3849,12 @@
launchProcess({ }, ProcessLaunchReason::InitialProcess);
}
-void WebPageProxy::runJavaScriptInMainFrame(const String& script, bool forceUserGesture, WTF::Function<void (API::SerializedScriptValue*, Optional<WebCore::ExceptionDetails>, CallbackBase::Error)>&& callbackFunction)
+void WebPageProxy::runJavaScriptInMainFrame(RunJavaScriptParameters&& parameters, WTF::Function<void (API::SerializedScriptValue*, Optional<WebCore::ExceptionDetails>, CallbackBase::Error)>&& callbackFunction)
{
- runJavaScriptInMainFrameScriptWorld(script, forceUserGesture, WTF::nullopt, WTFMove(callbackFunction));
+ runJavaScriptInMainFrameScriptWorld(WTFMove(parameters), WTF::nullopt, WTFMove(callbackFunction));
}
-void WebPageProxy::runJavaScriptInMainFrameScriptWorld(const String& script, bool forceUserGesture, const Optional<String>& worldName, WTF::Function<void(API::SerializedScriptValue*, Optional<ExceptionDetails>, CallbackBase::Error)>&& callbackFunction)
+void WebPageProxy::runJavaScriptInMainFrameScriptWorld(RunJavaScriptParameters&& parameters, const Optional<String>& worldName, 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();
@@ -3865,7 +3865,7 @@
}
auto callbackID = m_callbacks.put(WTFMove(callbackFunction), m_process->throttler().backgroundActivity("WebPageProxy::runJavaScriptInMainFrameScriptWorld"_s));
- send(Messages::WebPage::RunJavaScriptInMainFrameScriptWorld(script, forceUserGesture, worldName, callbackID));
+ send(Messages::WebPage::RunJavaScriptInMainFrameScriptWorld(parameters, worldName, callbackID));
}
void WebPageProxy::runJavaScriptInFrame(FrameIdentifier frameID, const String& script, bool forceUserGesture, WTF::Function<void(API::SerializedScriptValue*, Optional<ExceptionDetails>, CallbackBase::Error)>&& callbackFunction)
Modified: trunk/Source/WebKit/UIProcess/WebPageProxy.h (253949 => 253950)
--- trunk/Source/WebKit/UIProcess/WebPageProxy.h 2019-12-30 20:16:54 UTC (rev 253949)
+++ trunk/Source/WebKit/UIProcess/WebPageProxy.h 2019-12-30 20:23:20 UTC (rev 253950)
@@ -92,6 +92,7 @@
#include <WebCore/PlatformSpeechSynthesizer.h>
#include <WebCore/PointerID.h>
#include <WebCore/RegistrableDomain.h>
+#include <WebCore/RunJavaScriptParameters.h>
#include <WebCore/ScrollTypes.h>
#include <WebCore/SearchPopupMenu.h>
#include <WebCore/TextChecking.h>
@@ -1062,8 +1063,8 @@
void getSelectionAsWebArchiveData(Function<void (API::Data*, CallbackBase::Error)>&&);
void getSourceForFrame(WebFrameProxy*, WTF::Function<void (const String&, CallbackBase::Error)>&&);
void getWebArchiveOfFrame(WebFrameProxy*, Function<void (API::Data*, CallbackBase::Error)>&&);
- void runJavaScriptInMainFrame(const String&, bool, WTF::Function<void (API::SerializedScriptValue*, Optional<WebCore::ExceptionDetails>, CallbackBase::Error)>&& callbackFunction);
- void runJavaScriptInMainFrameScriptWorld(const String&, bool, const Optional<String>& worldName, WTF::Function<void(API::SerializedScriptValue*, Optional<WebCore::ExceptionDetails>, CallbackBase::Error)>&& callbackFunction);
+ 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);
// 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>&&);
Modified: trunk/Source/WebKit/UIProcess/socket/RemoteInspectorProtocolHandler.cpp (253949 => 253950)
--- trunk/Source/WebKit/UIProcess/socket/RemoteInspectorProtocolHandler.cpp 2019-12-30 20:16:54 UTC (rev 253949)
+++ trunk/Source/WebKit/UIProcess/socket/RemoteInspectorProtocolHandler.cpp 2019-12-30 20:23:20 UTC (rev 253950)
@@ -126,7 +126,7 @@
void RemoteInspectorProtocolHandler::runScript(const String& script)
{
- m_page.runJavaScriptInMainFrame(script, false,
+ m_page.runJavaScriptInMainFrame({ script, false, WTF::nullopt, false },
[](API::SerializedScriptValue*, Optional<WebCore::ExceptionDetails> exceptionDetails, CallbackBase::Error) {
if (exceptionDetails)
LOG_ERROR("Exception running script \"%s\"", exceptionDetails->message.utf8().data());
Modified: trunk/Source/WebKit/WebProcess/WebPage/WebPage.cpp (253949 => 253950)
--- trunk/Source/WebKit/WebProcess/WebPage/WebPage.cpp 2019-12-30 20:16:54 UTC (rev 253949)
+++ trunk/Source/WebKit/WebProcess/WebPage/WebPage.cpp 2019-12-30 20:23:20 UTC (rev 253950)
@@ -214,6 +214,7 @@
#include <WebCore/ResourceLoadStatistics.h>
#include <WebCore/ResourceRequest.h>
#include <WebCore/ResourceResponse.h>
+#include <WebCore/RunJavaScriptParameters.h>
#include <WebCore/RuntimeEnabledFeatures.h>
#include <WebCore/SWClientConnection.h>
#include <WebCore/ScriptController.h>
@@ -3352,38 +3353,42 @@
return static_cast<KeyboardUIMode>((fullKeyboardAccessEnabled ? KeyboardAccessFull : KeyboardAccessDefault) | (m_tabToLinks ? KeyboardAccessTabsToLinks : 0));
}
-void WebPage::runJavaScript(WebFrame* frame, const String& script, bool forceUserGesture, const Optional<String>& worldName, CallbackID callbackID)
+void WebPage::runJavaScript(WebFrame* frame, RunJavaScriptParameters&& parameters, const Optional<String>& worldName, CallbackID callbackID)
{
// NOTE: We need to be careful when running scripts that the objects we depend on don't
// disappear during script execution.
- JSLockHolder lock(commonVM());
- ValueOrException result;
- RefPtr<SerializedScriptValue> serializedResultValue;
+ auto* world = worldName ? InjectedBundleScriptWorld::find(worldName.value()) : &InjectedBundleScriptWorld::normalWorld();
+ if (!frame || !frame->coreFrame() || !world) {
+ send(Messages::WebPageProxy::ScriptValueCallback({ }, ExceptionDetails { "Unable to execute _javascript_: Page is in invalid state"_s }, callbackID));
+ return;
+ }
- auto* world = worldName ? InjectedBundleScriptWorld::find(worldName.value()) : &InjectedBundleScriptWorld::normalWorld();
- if (frame && frame->coreFrame() && world) {
- result = frame->coreFrame()->script().executeUserAgentScriptInWorld(world->coreWorld(), script, forceUserGesture);
+ auto resolveFunction = [protectedThis = makeRef(*this), this, world = makeRef(*world), frame = makeRef(*frame), callbackID](ValueOrException result) {
+ RefPtr<SerializedScriptValue> serializedResultValue;
if (result) {
- serializedResultValue = SerializedScriptValue::create(frame->jsContextForWorld(world),
+ serializedResultValue = SerializedScriptValue::create(frame->jsContextForWorld(world.ptr()),
toRef(frame->coreFrame()->script().globalObject(world->coreWorld()), result.value()), nullptr);
}
- }
- IPC::DataReference dataReference;
- if (serializedResultValue)
- dataReference = serializedResultValue->data();
+ IPC::DataReference dataReference;
+ if (serializedResultValue)
+ dataReference = serializedResultValue->data();
- Optional<ExceptionDetails> details;
- if (!result)
- details = result.error();
+ Optional<ExceptionDetails> details;
+ if (!result)
+ details = result.error();
- send(Messages::WebPageProxy::ScriptValueCallback(dataReference, details, callbackID));
+ send(Messages::WebPageProxy::ScriptValueCallback(dataReference, details, callbackID));
+ };
+
+ JSLockHolder lock(commonVM());
+ frame->coreFrame()->script().executeAsynchronousUserAgentScriptInWorld(world->coreWorld(), WTFMove(parameters), WTFMove(resolveFunction));
}
-void WebPage::runJavaScriptInMainFrameScriptWorld(const String& script, bool forceUserGesture, const Optional<String>& worldName, CallbackID callbackID)
+void WebPage::runJavaScriptInMainFrameScriptWorld(RunJavaScriptParameters&& parameters, const Optional<String>& worldName, CallbackID callbackID)
{
- runJavaScript(mainWebFrame(), script, forceUserGesture, worldName, callbackID);
+ runJavaScript(mainWebFrame(), WTFMove(parameters), worldName, callbackID);
}
void WebPage::runJavaScriptInFrame(FrameIdentifier frameID, const String& script, bool forceUserGesture, CallbackID callbackID)
@@ -3390,7 +3395,7 @@
{
WebFrame* frame = WebProcess::singleton().webFrame(frameID);
ASSERT(mainWebFrame() != frame);
- runJavaScript(frame, script, forceUserGesture, WTF::nullopt, callbackID);
+ runJavaScript(frame, { script, false, WTF::nullopt, forceUserGesture }, WTF::nullopt, callbackID);
}
void WebPage::getContentsAsString(CallbackID callbackID)
Modified: trunk/Source/WebKit/WebProcess/WebPage/WebPage.h (253949 => 253950)
--- trunk/Source/WebKit/WebProcess/WebPage/WebPage.h 2019-12-30 20:16:54 UTC (rev 253949)
+++ trunk/Source/WebKit/WebProcess/WebPage/WebPage.h 2019-12-30 20:23:20 UTC (rev 253950)
@@ -197,6 +197,7 @@
struct Highlight;
struct KeypressCommand;
struct PromisedAttachmentInfo;
+struct RunJavaScriptParameters;
struct TextCheckingResult;
struct ViewportArguments;
@@ -1435,8 +1436,8 @@
void getSelectionAsWebArchiveData(CallbackID);
void getSourceForFrame(WebCore::FrameIdentifier, CallbackID);
void getWebArchiveOfFrame(WebCore::FrameIdentifier, CallbackID);
- void runJavaScript(WebFrame*, const String&, bool forceUserGesture, const Optional<String>& worldName, CallbackID);
- void runJavaScriptInMainFrameScriptWorld(const String&, bool forceUserGesture, const Optional<String>& worldName, CallbackID);
+ void runJavaScript(WebFrame*, WebCore::RunJavaScriptParameters&&, const Optional<String>& worldName, CallbackID);
+ void runJavaScriptInMainFrameScriptWorld(WebCore::RunJavaScriptParameters&&, const Optional<String>& worldName, 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);
Modified: trunk/Source/WebKit/WebProcess/WebPage/WebPage.messages.in (253949 => 253950)
--- trunk/Source/WebKit/WebProcess/WebPage/WebPage.messages.in 2019-12-30 20:16:54 UTC (rev 253949)
+++ trunk/Source/WebKit/WebProcess/WebPage/WebPage.messages.in 2019-12-30 20:23:20 UTC (rev 253950)
@@ -204,7 +204,7 @@
GetSelectionAsWebArchiveData(WebKit::CallbackID callbackID)
GetSourceForFrame(WebCore::FrameIdentifier frameID, WebKit::CallbackID callbackID)
GetWebArchiveOfFrame(WebCore::FrameIdentifier frameID, WebKit::CallbackID callbackID)
- RunJavaScriptInMainFrameScriptWorld(String script, bool forceUserGesture, Optional<String> worldName, WebKit::CallbackID callbackID)
+ RunJavaScriptInMainFrameScriptWorld(struct WebCore::RunJavaScriptParameters parameters, Optional<String> worldName, WebKit::CallbackID callbackID)
RunJavaScriptInFrame(WebCore::FrameIdentifier frameID, String script, bool forceUserGesture, WebKit::CallbackID callbackID)
ForceRepaint(WebKit::CallbackID callbackID)
Modified: trunk/Tools/ChangeLog (253949 => 253950)
--- trunk/Tools/ChangeLog 2019-12-30 20:16:54 UTC (rev 253949)
+++ trunk/Tools/ChangeLog 2019-12-30 20:23:20 UTC (rev 253950)
@@ -1,3 +1,17 @@
+2019-12-30 Brady Eidson <beid...@apple.com>
+
+ Add WKWebView SPI to evaluate a function with arguments
+ https://bugs.webkit.org/show_bug.cgi?id=205239
+
+ Reviewed by Alex Christensen.
+
+ * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+ * TestWebKitAPI/Tests/WebKitCocoa/AsyncFunction.mm: Added.
+ (TestWebKitAPI::TEST):
+ * TestWebKitAPI/cocoa/TestWKWebView.h:
+ * TestWebKitAPI/cocoa/TestWKWebView.mm:
+ (-[WKWebView objectByCallingAsyncFunction:withArguments:error:]):
+
2019-12-30 Carlos Alberto Lopez Perez <clo...@igalia.com>
[GTK][WPE] Report number of total tests run and failed in API test runner like run-api-tests does
Modified: trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj (253949 => 253950)
--- trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj 2019-12-30 20:16:54 UTC (rev 253949)
+++ trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj 2019-12-30 20:23:20 UTC (rev 253950)
@@ -290,6 +290,7 @@
51AF23DF1EF1A3730072F281 /* IconLoadingDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 51AF23DE1EF1A3720072F281 /* IconLoadingDelegate.mm */; };
51B1EE961C80FAEF0064FB98 /* IndexedDBPersistence-1.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 51B1EE941C80FADD0064FB98 /* IndexedDBPersistence-1.html */; };
51B1EE971C80FAEF0064FB98 /* IndexedDBPersistence-2.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 51B1EE951C80FADD0064FB98 /* IndexedDBPersistence-2.html */; };
+ 51B40D9E23AC962400E05241 /* AsyncFunction.mm in Sources */ = {isa = PBXBuildFile; fileRef = 51B40D9D23AC960E00E05241 /* AsyncFunction.mm */; };
51BCEE4E1C84F53B0042C82E /* IndexedDBMultiProcess-1.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 51BCEE4C1C84F52C0042C82E /* IndexedDBMultiProcess-1.html */; };
51BCEE4F1C84F53B0042C82E /* IndexedDBMultiProcess-2.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 51BCEE4D1C84F52C0042C82E /* IndexedDBMultiProcess-2.html */; };
51BE9E662376089F00B4E117 /* MediaType.mm in Sources */ = {isa = PBXBuildFile; fileRef = 51BE9E652376089500B4E117 /* MediaType.mm */; };
@@ -1841,6 +1842,7 @@
51B1EE8D1C80F5880064FB98 /* IndexedDBPersistence.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = IndexedDBPersistence.mm; sourceTree = "<group>"; };
51B1EE941C80FADD0064FB98 /* IndexedDBPersistence-1.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "IndexedDBPersistence-1.html"; sourceTree = "<group>"; };
51B1EE951C80FADD0064FB98 /* IndexedDBPersistence-2.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "IndexedDBPersistence-2.html"; sourceTree = "<group>"; };
+ 51B40D9D23AC960E00E05241 /* AsyncFunction.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = AsyncFunction.mm; sourceTree = "<group>"; };
51B454EB1B4E236B0085EAA6 /* WebViewCloseInsideDidFinishLoadForFrame.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WebViewCloseInsideDidFinishLoadForFrame.mm; sourceTree = "<group>"; };
51BCEE491C84F4AF0042C82E /* IndexedDBMultiProcess.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = IndexedDBMultiProcess.mm; sourceTree = "<group>"; };
51BCEE4C1C84F52C0042C82E /* IndexedDBMultiProcess-1.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "IndexedDBMultiProcess-1.html"; sourceTree = "<group>"; };
@@ -2829,6 +2831,7 @@
2DE71AFD1D49C0BD00904094 /* AnimatedResize.mm */,
A1798B8122431D65000764BD /* ApplePay.mm */,
63F668201F97C3AA0032EE51 /* ApplicationManifest.mm */,
+ 51B40D9D23AC960E00E05241 /* AsyncFunction.mm */,
834138C6203261B900F26960 /* AsyncPolicyForNavigationResponse.mm */,
3760C4F0211249AF00233ACC /* AttrStyle.mm */,
754CEC801F6722DC00D0039A /* AutoFillAvailable.mm */,
@@ -4536,6 +4539,7 @@
A1798B8222431D65000764BD /* ApplePay.mm in Sources */,
63F668221F97F7F90032EE51 /* ApplicationManifest.mm in Sources */,
6354F4D11F7C3AB500D89DF3 /* ApplicationManifestParser.cpp in Sources */,
+ 51B40D9E23AC962400E05241 /* AsyncFunction.mm in Sources */,
834138C7203261CA00F26960 /* AsyncPolicyForNavigationResponse.mm in Sources */,
7CCE7EB41A411A7E00447C4C /* AttributedString.mm in Sources */,
3760C4F1211249AF00233ACC /* AttrStyle.mm in Sources */,
Added: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/AsyncFunction.mm (0 => 253950)
--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/AsyncFunction.mm (rev 0)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/AsyncFunction.mm 2019-12-30 20:23:20 UTC (rev 253950)
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2019 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 "PlatformUtilities.h"
+#import "Test.h"
+#import "TestWKWebView.h"
+#import <WebKit/WKWebViewPrivate.h>
+
+namespace TestWebKitAPI {
+
+TEST(AsyncFunction, Basic)
+{
+ auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600)]);
+ NSError *error;
+
+ // Function with no return value.
+ // Returns _javascript_ undefined which translates to nil.
+ id result = [webView objectByCallingAsyncFunction:@"1" withArguments:nil error:&error];
+ EXPECT_NULL(error);
+ EXPECT_EQ(result, nil);
+
+ // Function returns explicit null.
+ // Returns _javascript_ null which translates to NSNull.
+ result = [webView objectByCallingAsyncFunction:@"return null" withArguments:nil error:&error];
+ EXPECT_NULL(error);
+ EXPECT_TRUE([result isKindOfClass:[NSNull class]]);
+
+ // Function returns a number.
+ result = [webView objectByCallingAsyncFunction:@"return 1" withArguments:nil error:&error];
+ EXPECT_NULL(error);
+ EXPECT_TRUE([result isKindOfClass:[NSNumber class]]);
+ EXPECT_TRUE([result isEqualToNumber:@1]);
+
+ // Function returns a string.
+ result = [webView objectByCallingAsyncFunction:@"return '1'" withArguments:nil error:&error];
+ EXPECT_NULL(error);
+ EXPECT_TRUE([result isKindOfClass:[NSString class]]);
+ EXPECT_TRUE([result isEqualToString:@"1"]);
+
+ // Takes multiple arguments.
+ result = [webView objectByCallingAsyncFunction:@"return a + b" withArguments:@{ @"a" : @40, @"b" : @2 } error:&error];
+ EXPECT_NULL(error);
+ EXPECT_TRUE([result isKindOfClass:[NSNumber class]]);
+ EXPECT_TRUE([result isEqualToNumber:@42]);
+
+ // Takes multiple arguments of different types, follows _javascript_s "type appending" rules.
+ result = [webView objectByCallingAsyncFunction:@"return foo + bar" withArguments:@{ @"foo" : @"foo", @"bar" : @42 } error:&error];
+ EXPECT_NULL(error);
+ EXPECT_TRUE([result isKindOfClass:[NSString class]]);
+ EXPECT_TRUE([result isEqualToString:@"foo42"]);
+
+ // Invalid _javascript_, should return an error.
+ result = [webView objectByCallingAsyncFunction:@"retunr null" withArguments:nil error:&error];
+ EXPECT_FALSE(error == nil);
+ EXPECT_NULL(result);
+}
+
+TEST(AsyncFunction, InvalidArguments)
+{
+ auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600)]);
+ NSError *error;
+
+ // Values can only be NSString, NSNumber, NSDate, NSNull, NS(Mutable)Array, NS(Mutable)Dictionary, NSNull, and may only contain those 6 types.
+ id result = [webView objectByCallingAsyncFunction:@"return 1" withArguments:@{ @"a" : [NSData data] } error:&error];
+ EXPECT_NULL(result);
+ EXPECT_FALSE(error == nil);
+
+ result = [webView objectByCallingAsyncFunction:@"return 1" withArguments:@{ @"a" : @[ @1, [NSData data] ] } error:&error];
+ EXPECT_NULL(result);
+ EXPECT_FALSE(error == nil);
+
+ // References an argument that was not provided.
+ result = [webView objectByCallingAsyncFunction:@"return a + b" withArguments:@{ @"a" : @40 } error:&error];
+ EXPECT_NULL(result);
+ EXPECT_FALSE(error == nil);
+}
+
+TEST(AsyncFunction, RoundTrip)
+{
+ auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600)]);
+ NSError *error;
+
+ // Tests round tripping a whole bunch of argument inputs and verifying the result.
+
+ id value = @42;
+ id arguments = @{ @"a" : value };
+ id result = [webView objectByCallingAsyncFunction:@"return a" withArguments:arguments error:&error];
+ EXPECT_NULL(error);
+ EXPECT_TRUE([value isEqual:result]);
+
+ value = [NSNull null];
+ arguments = @{ @"a" : value };
+ result = [webView objectByCallingAsyncFunction:@"return a" withArguments:arguments error:&error];
+ EXPECT_NULL(error);
+ EXPECT_TRUE([value isEqual:result]);
+
+ value = @"Foo";
+ arguments = @{ @"a" : value };
+ result = [webView objectByCallingAsyncFunction:@"return a" withArguments:arguments error:&error];
+ EXPECT_NULL(error);
+ EXPECT_TRUE([value isEqual:result]);
+
+ value = [NSDate dateWithTimeIntervalSinceReferenceDate:0];
+ arguments = @{ @"a" : value };
+ result = [webView objectByCallingAsyncFunction:@"return a" withArguments:arguments error:&error];
+ EXPECT_NULL(error);
+ EXPECT_TRUE([value isEqual:result]);
+
+ value = @[ @1, @2 ];
+ arguments = @{ @"a" : value };
+ result = [webView objectByCallingAsyncFunction:@"return a" withArguments:arguments error:&error];
+ EXPECT_NULL(error);
+ EXPECT_TRUE([value isEqual:result]);
+
+ NSMutableArray *mutableArray = [[NSMutableArray alloc] init];
+ [mutableArray addObject:value];
+ arguments = @{ @"a" : mutableArray };
+ result = [webView objectByCallingAsyncFunction:@"return a" withArguments:arguments error:&error];
+ EXPECT_NULL(error);
+ EXPECT_TRUE([mutableArray isEqual:result]);
+ [mutableArray release];
+
+ value = @[ @"foo", [NSDate dateWithTimeIntervalSinceReferenceDate:0] ];
+ arguments = @{ @"a" : value };
+ result = [webView objectByCallingAsyncFunction:@"return a" withArguments:arguments error:&error];
+ EXPECT_NULL(error);
+ EXPECT_TRUE([value isEqual:result]);
+
+ value = @{ @"a" : @1, @"b" : @2 };
+ arguments = @{ @"a" : value };
+ result = [webView objectByCallingAsyncFunction:@"return a" withArguments:arguments error:&error];
+ EXPECT_NULL(error);
+ EXPECT_TRUE([value isEqual:result]);
+
+ NSMutableDictionary<NSString *, id> *mutableDictionary = [[NSMutableDictionary alloc] init];
+ mutableDictionary[@"foo"] = value;
+ arguments = @{ @"a" : mutableDictionary };
+ result = [webView objectByCallingAsyncFunction:@"return a" withArguments:arguments error:&error];
+ EXPECT_NULL(error);
+ EXPECT_TRUE([mutableDictionary isEqual:result]);
+ [mutableDictionary release];
+
+ value = @{ @"a" : @"foo", @"b" : [NSDate dateWithTimeIntervalSinceReferenceDate:0] };
+ arguments = @{ @"a" : value };
+ result = [webView objectByCallingAsyncFunction:@"return a" withArguments:arguments error:&error];
+ EXPECT_NULL(error);
+ EXPECT_TRUE([value isEqual:result]);
+
+ value = @{ @"a" : @{ @"a" : @1 } };
+ arguments = @{ @"a" : value };
+ result = [webView objectByCallingAsyncFunction:@"return a" withArguments:arguments error:&error];
+ EXPECT_NULL(error);
+ EXPECT_TRUE([value isEqual:result]);
+}
+
+}
+
Modified: trunk/Tools/TestWebKitAPI/cocoa/TestWKWebView.h (253949 => 253950)
--- trunk/Tools/TestWebKitAPI/cocoa/TestWKWebView.h 2019-12-30 20:16:54 UTC (rev 253949)
+++ trunk/Tools/TestWebKitAPI/cocoa/TestWKWebView.h 2019-12-30 20:23:20 UTC (rev 253950)
@@ -63,6 +63,7 @@
- (NSString *)stringByEvaluatingJavaScript:(NSString *)script;
- (id)objectByEvaluatingJavaScriptWithUserGesture:(NSString *)script;
- (id)objectByEvaluatingJavaScript:(NSString *)script;
+- (id)objectByCallingAsyncFunction:(NSString *)script withArguments:(NSDictionary *)arguments error:(NSError **)errorOut;
- (unsigned)waitUntilClientWidthIs:(unsigned)expectedClientWidth;
@end
Modified: trunk/Tools/TestWebKitAPI/cocoa/TestWKWebView.mm (253949 => 253950)
--- trunk/Tools/TestWebKitAPI/cocoa/TestWKWebView.mm 2019-12-30 20:16:54 UTC (rev 253949)
+++ trunk/Tools/TestWebKitAPI/cocoa/TestWKWebView.mm 2019-12-30 20:23:20 UTC (rev 253950)
@@ -178,6 +178,27 @@
return evalResult.autorelease();
}
+- (id)objectByCallingAsyncFunction:(NSString *)script withArguments:(NSDictionary *)arguments error:(NSError **)errorOut
+{
+ bool isWaitingForJavaScript = false;
+ if (errorOut)
+ *errorOut = nil;
+
+ RetainPtr<id> evalResult;
+ [self _callAsyncFunction:script withArguments:arguments completionHandler:[&] (id result, NSError *error) {
+ evalResult = result;
+ if (errorOut)
+ *errorOut = [error retain];
+ isWaitingForJavaScript = true;
+ }];
+ TestWebKitAPI::Util::run(&isWaitingForJavaScript);
+
+ if (errorOut)
+ [*errorOut autorelease];
+
+ return evalResult.autorelease();
+}
+
- (NSString *)stringByEvaluatingJavaScript:(NSString *)script
{
return [NSString stringWithFormat:@"%@", [self objectByEvaluatingJavaScript:script]];