Expose more information about the exception in WKErrorJavaScriptExceptionOccurred...
authortimothy_horton@apple.com <timothy_horton@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 25 Oct 2015 05:37:09 +0000 (05:37 +0000)
committertimothy_horton@apple.com <timothy_horton@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 25 Oct 2015 05:37:09 +0000 (05:37 +0000)
https://bugs.webkit.org/show_bug.cgi?id=150525

Reviewed by Darin Adler.

Adjusted API test to cover this: WKWebView.EvaluateJavaScriptErrorCases.

* bindings/js/JSDOMBinding.cpp:
(WebCore::reportException):
* bindings/js/JSDOMBinding.h:
Fill in the given struct with computed exception data if it was given.

* bindings/js/ScriptController.cpp:
(WebCore::ScriptController::evaluateInWorld):
(WebCore::ScriptController::evaluate):
(WebCore::ScriptController::executeScript):
* bindings/js/ScriptController.h:
Plumb aforementioned struct through ScriptController.

* Scripts/webkit/messages.py:
(headers_for_type):
* Shared/WebCoreArgumentCoders.cpp:
(IPC::ArgumentCoder<ExceptionDetails>::encode):
(IPC::ArgumentCoder<ExceptionDetails>::decode):
* Shared/WebCoreArgumentCoders.h:
Learn how to en/decode ExceptionDetails.

* UIProcess/API/C/WKPage.cpp:
(WKPageRunJavaScriptInMainFrame):
* UIProcess/WebPageProxy.cpp:
(WebKit::WebPageProxy::runJavaScriptInMainFrame):
(WebKit::WebPageProxy::scriptValueCallback):
* UIProcess/WebPageProxy.h:
* UIProcess/WebPageProxy.messages.in:
* WebProcess/WebPage/WebPage.cpp:
(WebKit::WebPage::runJavaScriptInMainFrame):
Plumb ExceptionDetails back through runJavaScriptInMainFrame, across the
process boundary.

* UIProcess/API/Cocoa/WKError.mm:
(localizedDescriptionForErrorCode):
* UIProcess/API/Cocoa/WKErrorInternal.h:
* UIProcess/API/Cocoa/WKErrorPrivate.h:
Expose localizedDescriptionForErrorCode so that WKWebView can do special
things with its error.
Add new private userInfo keys for exception info.

* UIProcess/API/Cocoa/WKWebView.mm:
(-[WKWebView evaluateJavaScript:completionHandler:]):
Fill in the NSError userInfo with the exception info.

* TestWebKitAPI/Tests/WebKit2Cocoa/WKWebViewEvaluateJavaScript.mm:
(TEST):
Test the various new keys.

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

20 files changed:
Source/WebCore/ChangeLog
Source/WebCore/bindings/js/JSDOMBinding.cpp
Source/WebCore/bindings/js/JSDOMBinding.h
Source/WebCore/bindings/js/ScriptController.cpp
Source/WebCore/bindings/js/ScriptController.h
Source/WebKit2/ChangeLog
Source/WebKit2/Scripts/webkit/messages.py
Source/WebKit2/Shared/WebCoreArgumentCoders.cpp
Source/WebKit2/Shared/WebCoreArgumentCoders.h
Source/WebKit2/UIProcess/API/C/WKPage.cpp
Source/WebKit2/UIProcess/API/Cocoa/WKError.mm
Source/WebKit2/UIProcess/API/Cocoa/WKErrorInternal.h
Source/WebKit2/UIProcess/API/Cocoa/WKErrorPrivate.h
Source/WebKit2/UIProcess/API/Cocoa/WKWebView.mm
Source/WebKit2/UIProcess/WebPageProxy.cpp
Source/WebKit2/UIProcess/WebPageProxy.h
Source/WebKit2/UIProcess/WebPageProxy.messages.in
Source/WebKit2/WebProcess/WebPage/WebPage.cpp
Tools/ChangeLog
Tools/TestWebKitAPI/Tests/WebKit2Cocoa/WKWebViewEvaluateJavaScript.mm

index 9c39cb8..7c7b590 100644 (file)
@@ -1,3 +1,24 @@
+2015-10-24  Tim Horton  <timothy_horton@apple.com>
+
+        Expose more information about the exception in WKErrorJavaScriptExceptionOccurred errors
+        https://bugs.webkit.org/show_bug.cgi?id=150525
+
+        Reviewed by Darin Adler.
+
+        Adjusted API test to cover this: WKWebView.EvaluateJavaScriptErrorCases.
+
+        * bindings/js/JSDOMBinding.cpp:
+        (WebCore::reportException):
+        * bindings/js/JSDOMBinding.h:
+        Fill in the given struct with computed exception data if it was given.
+
+        * bindings/js/ScriptController.cpp:
+        (WebCore::ScriptController::evaluateInWorld):
+        (WebCore::ScriptController::evaluate):
+        (WebCore::ScriptController::executeScript):
+        * bindings/js/ScriptController.h:
+        Plumb aforementioned struct through ScriptController.
+
 2015-10-24  Gwang Yoon Hwang  <yoon@igalia.com>
 
         [TexMap] Clean up BitmapTexture and BitmapTextureGL.
index e1b0b5b..302c7a9 100644 (file)
@@ -159,7 +159,7 @@ void reportException(ExecState* exec, JSValue exceptionValue, CachedScript* cach
     reportException(exec, exception, cachedScript);
 }
 
-void reportException(ExecState* exec, Exception* exception, CachedScript* cachedScript)
+void reportException(ExecState* exec, Exception* exception, CachedScript* cachedScript, ExceptionDetails* exceptionDetails)
 {
     RELEASE_ASSERT(exec->vm().currentThreadIsHoldingAPILock());
     if (isTerminatedExecutionException(exception))
@@ -202,6 +202,13 @@ void reportException(ExecState* exec, Exception* exception, CachedScript* cached
 
     ScriptExecutionContext* scriptExecutionContext = globalObject->scriptExecutionContext();
     scriptExecutionContext->reportException(errorMessage, lineNumber, columnNumber, exceptionSourceURL, callStack->size() ? callStack : 0, cachedScript);
+
+    if (exceptionDetails) {
+        exceptionDetails->message = errorMessage;
+        exceptionDetails->lineNumber = lineNumber;
+        exceptionDetails->columnNumber = columnNumber;
+        exceptionDetails->sourceURL = exceptionSourceURL;
+    }
 }
 
 void reportCurrentException(ExecState* exec)
index c64a1e7..2f92322 100644 (file)
@@ -67,6 +67,13 @@ class Node;
 
 typedef int ExceptionCode;
 
+struct ExceptionDetails {
+    String message;
+    int lineNumber { 0 };
+    int columnNumber { 0 };
+    String sourceURL;
+};
+
 DOMWindow& activeDOMWindow(JSC::ExecState*);
 DOMWindow& firstDOMWindow(JSC::ExecState*);
 
@@ -272,7 +279,7 @@ void addImpureProperty(const AtomicString&);
 const JSC::HashTable& getHashTableForGlobalData(JSC::VM&, const JSC::HashTable& staticTable);
 
 WEBCORE_EXPORT void reportException(JSC::ExecState*, JSC::JSValue exception, CachedScript* = nullptr);
-WEBCORE_EXPORT void reportException(JSC::ExecState*, JSC::Exception*, CachedScript* = nullptr);
+WEBCORE_EXPORT void reportException(JSC::ExecState*, JSC::Exception*, CachedScript* = nullptr, ExceptionDetails* = nullptr);
 void reportCurrentException(JSC::ExecState*);
 
 JSC::JSValue createDOMException(JSC::ExecState*, ExceptionCode);
index e2cf092..b161e66 100644 (file)
@@ -137,7 +137,7 @@ JSDOMWindowShell* ScriptController::createWindowShell(DOMWrapperWorld& world)
     return windowShell.get();
 }
 
-Deprecated::ScriptValue ScriptController::evaluateInWorld(const ScriptSourceCode& sourceCode, DOMWrapperWorld& world)
+Deprecated::ScriptValue ScriptController::evaluateInWorld(const ScriptSourceCode& sourceCode, DOMWrapperWorld& world, ExceptionDetails* exceptionDetails)
 {
     JSLockHolder lock(world.vm());
 
@@ -166,7 +166,7 @@ Deprecated::ScriptValue ScriptController::evaluateInWorld(const ScriptSourceCode
     InspectorInstrumentation::didEvaluateScript(cookie, m_frame);
 
     if (evaluationException) {
-        reportException(exec, evaluationException, sourceCode.cachedScript());
+        reportException(exec, evaluationException, sourceCode.cachedScript(), exceptionDetails);
         m_sourceURL = savedSourceURL;
         return Deprecated::ScriptValue();
     }
@@ -175,9 +175,9 @@ Deprecated::ScriptValue ScriptController::evaluateInWorld(const ScriptSourceCode
     return Deprecated::ScriptValue(exec->vm(), returnValue);
 }
 
-Deprecated::ScriptValue ScriptController::evaluate(const ScriptSourceCode& sourceCode
+Deprecated::ScriptValue ScriptController::evaluate(const ScriptSourceCode& sourceCode, ExceptionDetails* exceptionDetails)
 {
-    return evaluateInWorld(sourceCode, mainThreadNormalWorld());
+    return evaluateInWorld(sourceCode, mainThreadNormalWorld(), exceptionDetails);
 }
 
 Ref<DOMWrapperWorld> ScriptController::createWorld()
@@ -545,20 +545,20 @@ bool ScriptController::canExecuteScripts(ReasonForCallingCanExecuteScripts reaso
     return m_frame.loader().client().allowScript(m_frame.settings().isScriptEnabled());
 }
 
-Deprecated::ScriptValue ScriptController::executeScript(const String& script, bool forceUserGesture)
+Deprecated::ScriptValue ScriptController::executeScript(const String& script, bool forceUserGesture, ExceptionDetails* exceptionDetails)
 {
     UserGestureIndicator gestureIndicator(forceUserGesture ? DefinitelyProcessingUserGesture : PossiblyProcessingUserGesture);
-    return executeScript(ScriptSourceCode(script, m_frame.document()->url()));
+    return executeScript(ScriptSourceCode(script, m_frame.document()->url()), exceptionDetails);
 }
 
-Deprecated::ScriptValue ScriptController::executeScript(const ScriptSourceCode& sourceCode)
+Deprecated::ScriptValue ScriptController::executeScript(const ScriptSourceCode& sourceCode, ExceptionDetails* exceptionDetails)
 {
     if (!canExecuteScripts(AboutToExecuteScript) || isPaused())
         return Deprecated::ScriptValue();
 
     Ref<Frame> protect(m_frame); // Script execution can destroy the frame, and thus the ScriptController.
 
-    return evaluate(sourceCode);
+    return evaluate(sourceCode, exceptionDetails);
 }
 
 bool ScriptController::executeIfJavaScriptURL(const URL& url, ShouldReplaceDocumentIfJavaScriptURL shouldReplaceDocumentIfJavaScriptURL)
index 07c53b7..2976fc3 100644 (file)
@@ -43,13 +43,13 @@ class ScriptValue;
 }
 
 namespace JSC {
-    class JSGlobalObject;
-    class ExecState;
+class JSGlobalObject;
+class ExecState;
 
-    namespace Bindings {
-        class Instance;
-        class RootObject;
-    }
+namespace Bindings {
+class Instance;
+class RootObject;
+}
 }
 
 namespace WebCore {
@@ -101,8 +101,8 @@ public:
 
     static void getAllWorlds(Vector<Ref<DOMWrapperWorld>>&);
 
-    Deprecated::ScriptValue executeScript(const ScriptSourceCode&);
-    WEBCORE_EXPORT Deprecated::ScriptValue executeScript(const String& script, bool forceUserGesture = false);
+    Deprecated::ScriptValue executeScript(const ScriptSourceCode&, ExceptionDetails* = nullptr);
+    WEBCORE_EXPORT Deprecated::ScriptValue executeScript(const String& script, bool forceUserGesture = false, ExceptionDetails* = nullptr);
     WEBCORE_EXPORT Deprecated::ScriptValue executeScriptInWorld(DOMWrapperWorld&, const String& script, bool forceUserGesture = false);
 
     // Returns true if argument is a JavaScript URL.
@@ -112,8 +112,8 @@ public:
     // Darwin is an exception to this rule: it is OK to call this function from any thread, even reentrantly.
     static void initializeThreading();
 
-    Deprecated::ScriptValue evaluate(const ScriptSourceCode&);
-    Deprecated::ScriptValue evaluateInWorld(const ScriptSourceCode&, DOMWrapperWorld&);
+    Deprecated::ScriptValue evaluate(const ScriptSourceCode&, ExceptionDetails* = nullptr);
+    Deprecated::ScriptValue evaluateInWorld(const ScriptSourceCode&, DOMWrapperWorld&, ExceptionDetails* = nullptr);
 
     WTF::TextPosition eventHandlerPosition() const;
 
index ef46dd2..4b4a70a 100644 (file)
@@ -1,3 +1,42 @@
+2015-10-24  Tim Horton  <timothy_horton@apple.com>
+
+        Expose more information about the exception in WKErrorJavaScriptExceptionOccurred errors
+        https://bugs.webkit.org/show_bug.cgi?id=150525
+
+        Reviewed by Darin Adler.
+
+        * Scripts/webkit/messages.py:
+        (headers_for_type):
+        * Shared/WebCoreArgumentCoders.cpp:
+        (IPC::ArgumentCoder<ExceptionDetails>::encode):
+        (IPC::ArgumentCoder<ExceptionDetails>::decode):
+        * Shared/WebCoreArgumentCoders.h:
+        Learn how to en/decode ExceptionDetails.
+
+        * UIProcess/API/C/WKPage.cpp:
+        (WKPageRunJavaScriptInMainFrame):
+        * UIProcess/WebPageProxy.cpp:
+        (WebKit::WebPageProxy::runJavaScriptInMainFrame):
+        (WebKit::WebPageProxy::scriptValueCallback):
+        * UIProcess/WebPageProxy.h:
+        * UIProcess/WebPageProxy.messages.in:
+        * WebProcess/WebPage/WebPage.cpp:
+        (WebKit::WebPage::runJavaScriptInMainFrame):
+        Plumb ExceptionDetails back through runJavaScriptInMainFrame, across the
+        process boundary.
+
+        * UIProcess/API/Cocoa/WKError.mm:
+        (localizedDescriptionForErrorCode):
+        * UIProcess/API/Cocoa/WKErrorInternal.h:
+        * UIProcess/API/Cocoa/WKErrorPrivate.h:
+        Expose localizedDescriptionForErrorCode so that WKWebView can do special
+        things with its error.
+        Add new private userInfo keys for exception info.
+
+        * UIProcess/API/Cocoa/WKWebView.mm:
+        (-[WKWebView evaluateJavaScript:completionHandler:]):
+        Fill in the NSError userInfo with the exception info.
+
 2015-10-24  Gyuyoung Kim  <gyuyoung.kim@webkit.org>
 
         [EFL] Fix a wrong enum variable use
index 89f56e1..614b5b8 100644 (file)
@@ -352,6 +352,7 @@ def headers_for_type(type):
     special_cases = {
         'String': ['<wtf/text/WTFString.h>'],
         'WebCore::CompositionUnderline': ['<WebCore/Editor.h>'],
+        'WebCore::ExceptionDetails': ['<WebCore/JSDOMBinding.h>'],
         'WebCore::GrammarDetail': ['<WebCore/TextCheckerClient.h>'],
         'WebCore::TextureMapperAnimations': ['<WebCore/TextureMapperAnimation.h>'],
         'WebCore::KeyframeValueList': ['<WebCore/GraphicsLayer.h>'],
index 6c9c263..f0e2636 100644 (file)
@@ -45,6 +45,7 @@
 #include <WebCore/GraphicsLayer.h>
 #include <WebCore/IDBGetResult.h>
 #include <WebCore/Image.h>
+#include <WebCore/JSDOMBinding.h>
 #include <WebCore/Length.h>
 #include <WebCore/Path.h>
 #include <WebCore/PluginData.h>
@@ -2037,4 +2038,29 @@ bool ArgumentCoder<DictionaryPopupInfo>::decode(IPC::ArgumentDecoder& decoder, D
     return true;
 }
 
+void ArgumentCoder<ExceptionDetails>::encode(IPC::ArgumentEncoder& encoder, const ExceptionDetails& info)
+{
+    encoder << info.message;
+    encoder << info.lineNumber;
+    encoder << info.columnNumber;
+    encoder << info.sourceURL;
+}
+
+bool ArgumentCoder<ExceptionDetails>::decode(IPC::ArgumentDecoder& decoder, ExceptionDetails& result)
+{
+    if (!decoder.decode(result.message))
+        return false;
+
+    if (!decoder.decode(result.lineNumber))
+        return false;
+
+    if (!decoder.decode(result.columnNumber))
+        return false;
+
+    if (!decoder.decode(result.sourceURL))
+        return false;
+
+    return true;
+}
+
 } // namespace IPC
index c83e998..46e7c12 100644 (file)
@@ -71,6 +71,7 @@ struct CompositionUnderline;
 struct Cookie;
 struct DictationAlternative;
 struct DictionaryPopupInfo;
+struct ExceptionDetails;
 struct FileChooserSettings;
 struct Length;
 struct GrammarDetail;
@@ -457,6 +458,11 @@ template<> struct ArgumentCoder<WebCore::RecentSearch> {
     static bool decode(ArgumentDecoder&, WebCore::RecentSearch&);
 };
 
+template<> struct ArgumentCoder<WebCore::ExceptionDetails> {
+    static void encode(ArgumentEncoder&, const WebCore::ExceptionDetails&);
+    static bool decode(ArgumentDecoder&, WebCore::ExceptionDetails&);
+};
+
 } // namespace IPC
 
 #endif // WebCoreArgumentCoders_h
index 3b7c816..646776c 100644 (file)
@@ -2183,7 +2183,7 @@ void WKPageSetSession(WKPageRef pageRef, WKSessionRef session)
 
 void WKPageRunJavaScriptInMainFrame(WKPageRef pageRef, WKStringRef scriptRef, void* context, WKPageRunJavaScriptFunction callback)
 {
-    toImpl(pageRef)->runJavaScriptInMainFrame(toImpl(scriptRef)->string(), [context, callback](API::SerializedScriptValue* returnValue, bool, CallbackBase::Error error) {
+    toImpl(pageRef)->runJavaScriptInMainFrame(toImpl(scriptRef)->string(), [context, callback](API::SerializedScriptValue* returnValue, bool, const WebCore::ExceptionDetails&, CallbackBase::Error error) {
         callback(toAPI(returnValue), (error != CallbackBase::Error::None) ? toAPI(API::Error::create().ptr()) : 0, context);
     });
 }
index 34f6245..cab6eb9 100644 (file)
 NSString * const WKErrorDomain = @"WKErrorDomain";
 NSString * const _WKLegacyErrorDomain = @"WebKitErrorDomain";
 
-static NSString *localizedDescriptionForErrorCode(WKErrorCode errorCode)
+NSString * const _WKJavaScriptExceptionMessageErrorKey = @"WKJavaScriptExceptionMessage";
+NSString * const _WKJavaScriptExceptionLineNumberErrorKey = @"WKJavaScriptExceptionLineNumber";
+NSString * const _WKJavaScriptExceptionColumnNumberErrorKey = @"WKJavaScriptExceptionColumnNumber";
+NSString * const _WKJavaScriptExceptionSourceURLErrorKey = @"WKJavaScriptExceptionSourceURL";
+
+NSString *localizedDescriptionForErrorCode(WKErrorCode errorCode)
 {
     switch (errorCode) {
     case WKErrorUnknown:
index 711b949..33237d5 100644 (file)
@@ -31,5 +31,6 @@
 #import "GenericCallback.h"
 
 RetainPtr<NSError> createNSError(WKErrorCode);
+NSString *localizedDescriptionForErrorCode(WKErrorCode);
 
 #endif
index a037190..c99d1df 100644 (file)
@@ -34,4 +34,20 @@ typedef NS_ENUM(NSInteger, _WKLegacyErrorCode) {
     _WKLegacyErrorPlugInWillHandleLoad = 204,
 } WK_ENUM_AVAILABLE(10_11, 8_3);
 
+/*! @constant _WKJavaScriptExceptionMessageErrorKey Key in userInfo representing
+ the exception message (as an NSString) for WKErrorJavaScriptExceptionOccurred errors. */
+WK_EXTERN NSString * const _WKJavaScriptExceptionMessageErrorKey WK_AVAILABLE(WK_MAC_TBA, WK_IOS_TBA);
+
+/*! @constant _WKJavaScriptExceptionLineNumberErrorKey Key in userInfo representing
+ the exception line number (as an NSNumber) for WKErrorJavaScriptExceptionOccurred errors. */
+WK_EXTERN NSString * const _WKJavaScriptExceptionLineNumberErrorKey WK_AVAILABLE(WK_MAC_TBA, WK_IOS_TBA);
+
+/*! @constant _WKJavaScriptExceptionColumnNumberErrorKey Key in userInfo representing
+ the exception column number (as an NSNumber) for WKErrorJavaScriptExceptionOccurred errors. */
+WK_EXTERN NSString * const _WKJavaScriptExceptionColumnNumberErrorKey WK_AVAILABLE(WK_MAC_TBA, WK_IOS_TBA);
+
+/*! @constant _WKJavaScriptExceptionSourceURLErrorKey Key in userInfo representing
+ the exception source URL (as an NSURL) for WKErrorJavaScriptExceptionOccurred errors. */
+WK_EXTERN NSString * const _WKJavaScriptExceptionSourceURLErrorKey WK_AVAILABLE(WK_MAC_TBA, WK_IOS_TBA);
+
 #endif
index ef31efb..cd7eb8c 100644 (file)
@@ -80,6 +80,7 @@
 #import "_WKSessionStateInternal.h"
 #import "_WKVisitedLinkStoreInternal.h"
 #import <WebCore/IOSurface.h>
+#import <WebCore/JSDOMBinding.h>
 #import <wtf/HashMap.h>
 #import <wtf/MathExtras.h>
 #import <wtf/NeverDestroyed.h>
@@ -612,7 +613,7 @@ static WKErrorCode callbackErrorCode(WebKit::CallbackBase::Error error)
 {
     auto handler = adoptNS([completionHandler copy]);
 
-    _page->runJavaScriptInMainFrame(javaScriptString, [handler](API::SerializedScriptValue* serializedScriptValue, bool hadException, WebKit::ScriptValueCallback::Error errorCode) {
+    _page->runJavaScriptInMainFrame(javaScriptString, [handler](API::SerializedScriptValue* serializedScriptValue, bool hadException, const WebCore::ExceptionDetails& details, WebKit::ScriptValueCallback::Error errorCode) {
         if (!handler)
             return;
 
@@ -637,7 +638,18 @@ static WKErrorCode callbackErrorCode(WebKit::CallbackBase::Error error)
         auto rawHandler = (void (^)(id, NSError *))handler.get();
         if (hadException) {
             ASSERT(!serializedScriptValue);
-            rawHandler(nil, createNSError(WKErrorJavaScriptExceptionOccurred).get());
+
+            RetainPtr<NSMutableDictionary> userInfo = adoptNS([[NSMutableDictionary alloc] init]);
+
+            [userInfo setObject:localizedDescriptionForErrorCode(WKErrorJavaScriptExceptionOccurred) forKey:NSLocalizedDescriptionKey];
+            [userInfo setObject:static_cast<NSString *>(details.message) forKey:_WKJavaScriptExceptionMessageErrorKey];
+            [userInfo setObject:@(details.lineNumber) forKey:_WKJavaScriptExceptionLineNumberErrorKey];
+            [userInfo setObject:@(details.columnNumber) forKey:_WKJavaScriptExceptionColumnNumberErrorKey];
+
+            if (!details.sourceURL.isEmpty())
+                [userInfo setObject:[NSURL _web_URLWithWTFString:details.sourceURL] forKey:_WKJavaScriptExceptionSourceURLErrorKey];
+
+            rawHandler(nil, adoptNS([[NSError alloc] initWithDomain:WKErrorDomain code:WKErrorJavaScriptExceptionOccurred userInfo:userInfo.get()]).get());
             return;
         }
 
index a6ac35e..e777662 100644 (file)
 #include <WebCore/DragData.h>
 #include <WebCore/FloatRect.h>
 #include <WebCore/FocusDirection.h>
+#include <WebCore/JSDOMBinding.h>
 #include <WebCore/MIMETypeRegistry.h>
 #include <WebCore/RenderEmbeddedObject.h>
 #include <WebCore/SerializedCryptoKeyWrap.h>
@@ -2587,10 +2588,10 @@ void WebPageProxy::countStringMatches(const String& string, FindOptions options,
     m_process->send(Messages::WebPage::CountStringMatches(string, options, maxMatchCount), m_pageID);
 }
 
-void WebPageProxy::runJavaScriptInMainFrame(const String& script, std::function<void (API::SerializedScriptValue*, bool hadException, CallbackBase::Error)> callbackFunction)
+void WebPageProxy::runJavaScriptInMainFrame(const String& script, std::function<void (API::SerializedScriptValue*, bool hadException, const ExceptionDetails&, CallbackBase::Error)> callbackFunction)
 {
     if (!isValid()) {
-        callbackFunction(nullptr, false, CallbackBase::Error::Unknown);
+        callbackFunction(nullptr, false, { }, CallbackBase::Error::Unknown);
         return;
     }
 
@@ -4681,7 +4682,7 @@ void WebPageProxy::stringCallback(const String& resultString, uint64_t callbackI
     callback->performCallbackWithReturnValue(resultString.impl());
 }
 
-void WebPageProxy::scriptValueCallback(const IPC::DataReference& dataReference, bool hadException, uint64_t callbackID)
+void WebPageProxy::scriptValueCallback(const IPC::DataReference& dataReference, bool hadException, const ExceptionDetails& details, uint64_t callbackID)
 {
     auto callback = m_callbacks.take<ScriptValueCallback>(callbackID);
     if (!callback) {
@@ -4693,7 +4694,7 @@ void WebPageProxy::scriptValueCallback(const IPC::DataReference& dataReference,
     data.reserveInitialCapacity(dataReference.size());
     data.append(dataReference.data(), dataReference.size());
 
-    callback->performCallbackWithReturnValue(data.size() ? API::SerializedScriptValue::adopt(data).ptr() : nullptr, hadException);
+    callback->performCallbackWithReturnValue(data.size() ? API::SerializedScriptValue::adopt(data).ptr() : nullptr, hadException, details);
 }
 
 void WebPageProxy::computedPagesCallback(const Vector<IntRect>& pageRects, double totalScaleFactorForPrinting, uint64_t callbackID)
index d200283..6baa32d 100644 (file)
@@ -157,6 +157,7 @@ class RunLoopObserver;
 class SharedBuffer;
 class TextIndicator;
 struct DictionaryPopupInfo;
+struct ExceptionDetails;
 struct FileChooserSettings;
 struct SecurityOriginData;
 struct TextAlternativeWithRange;
@@ -222,7 +223,7 @@ class QuickLookDocumentData;
 typedef GenericCallback<uint64_t> UnsignedCallback;
 typedef GenericCallback<EditingRange> EditingRangeCallback;
 typedef GenericCallback<const String&> StringCallback;
-typedef GenericCallback<API::SerializedScriptValue*, bool> ScriptValueCallback;
+typedef GenericCallback<API::SerializedScriptValue*, bool, const WebCore::ExceptionDetails&> ScriptValueCallback;
 
 #if PLATFORM(GTK)
 typedef GenericCallback<API::Error*> PrintFinishedCallback;
@@ -762,7 +763,7 @@ public:
     void getSelectionAsWebArchiveData(std::function<void (API::Data*, CallbackBase::Error)>);
     void getSourceForFrame(WebFrameProxy*, std::function<void (const String&, CallbackBase::Error)>);
     void getWebArchiveOfFrame(WebFrameProxy*, std::function<void (API::Data*, CallbackBase::Error)>);
-    void runJavaScriptInMainFrame(const String&, std::function<void (API::SerializedScriptValue*, bool hadException, CallbackBase::Error)> callbackFunction);
+    void runJavaScriptInMainFrame(const String&, std::function<void (API::SerializedScriptValue*, bool hadException, const WebCore::ExceptionDetails&, CallbackBase::Error)> callbackFunction);
     void forceRepaint(PassRefPtr<VoidCallback>);
 
     float headerHeight(WebFrameProxy*);
@@ -1323,7 +1324,7 @@ private:
     void dataCallback(const IPC::DataReference&, uint64_t);
     void imageCallback(const ShareableBitmap::Handle&, uint64_t);
     void stringCallback(const String&, uint64_t);
-    void scriptValueCallback(const IPC::DataReference&, bool hadException, uint64_t);
+    void scriptValueCallback(const IPC::DataReference&, bool hadException, const WebCore::ExceptionDetails&, uint64_t);
     void computedPagesCallback(const Vector<WebCore::IntRect>&, double totalScaleFactorForPrinting, uint64_t);
     void validateCommandCallback(const String&, bool, int, uint64_t);
     void unsignedCallback(uint64_t, uint64_t);
index 5f6b5e3..e2b2c7d 100644 (file)
@@ -159,7 +159,7 @@ messages -> WebPageProxy {
     DataCallback(IPC::DataReference resultData, uint64_t callbackID)
     ImageCallback(WebKit::ShareableBitmap::Handle bitmapHandle, uint64_t callbackID)
     StringCallback(String resultString, uint64_t callbackID)
-    ScriptValueCallback(IPC::DataReference resultData, bool hadException, uint64_t callbackID)
+    ScriptValueCallback(IPC::DataReference resultData, bool hadException, struct WebCore::ExceptionDetails details, uint64_t callbackID)
     ComputedPagesCallback(Vector<WebCore::IntRect> pageRects, double totalScaleFactorForPrinting, uint64_t callbackID)
     ValidateCommandCallback(String command, bool isEnabled, int32_t state, uint64_t callbackID)
     EditingRangeCallback(struct WebKit::EditingRange range, uint64_t callbackID)
index 15de61d..ce9fc82 100644 (file)
@@ -2505,7 +2505,8 @@ void WebPage::runJavaScriptInMainFrame(const String& script, uint64_t callbackID
     RefPtr<SerializedScriptValue> serializedResultValue;
     JSLockHolder lock(JSDOMWindow::commonVM());
     bool hadException = true;
-    if (JSValue resultValue = m_mainFrame->coreFrame()->script().executeScript(script, true).jsValue()) {
+    ExceptionDetails details;
+    if (JSValue resultValue = m_mainFrame->coreFrame()->script().executeScript(script, true, &details).jsValue()) {
         hadException = false;
         serializedResultValue = SerializedScriptValue::create(m_mainFrame->jsContext(),
             toRef(m_mainFrame->coreFrame()->script().globalObject(mainThreadNormalWorld())->globalExec(), resultValue), nullptr);
@@ -2514,7 +2515,7 @@ void WebPage::runJavaScriptInMainFrame(const String& script, uint64_t callbackID
     IPC::DataReference dataReference;
     if (serializedResultValue)
         dataReference = serializedResultValue->data();
-    send(Messages::WebPageProxy::ScriptValueCallback(dataReference, hadException, callbackID));
+    send(Messages::WebPageProxy::ScriptValueCallback(dataReference, hadException, details, callbackID));
 }
 
 void WebPage::getContentsAsString(uint64_t callbackID)
index a18e548..82e2dc9 100644 (file)
@@ -1,3 +1,14 @@
+2015-10-24  Tim Horton  <timothy_horton@apple.com>
+
+        Expose more information about the exception in WKErrorJavaScriptExceptionOccurred errors
+        https://bugs.webkit.org/show_bug.cgi?id=150525
+
+        Reviewed by Darin Adler.
+
+        * TestWebKitAPI/Tests/WebKit2Cocoa/WKWebViewEvaluateJavaScript.mm:
+        (TEST):
+        Test the various new keys.
+
 2015-10-24  Frederic Wang  <fred.wang@free.fr>
 
         check-webkit-style complains about missing operator whitespace inside character literal
index 20b2977..997fa8e 100644 (file)
 #import "PlatformUtilities.h"
 #import "Test.h"
 #import <WebKit/WKWebView.h>
+#import <WebKit/WKErrorPrivate.h>
 #import <wtf/RetainPtr.h>
 
 static bool isDone;
 
+@interface EvaluateJavaScriptNavigationDelegate : NSObject <WKNavigationDelegate>
+@end
+
+@implementation EvaluateJavaScriptNavigationDelegate
+
+- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation
+{
+    isDone = true;
+}
+
+@end
+
 TEST(WKWebView, EvaluateJavaScriptBlockCrash)
 {
     RetainPtr<WKWebView> webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600)]);
@@ -63,14 +76,17 @@ TEST(WKWebView, EvaluateJavaScriptBlockCrash)
 TEST(WKWebView, EvaluateJavaScriptErrorCases)
 {
     RetainPtr<WKWebView> webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600)]);
+    RetainPtr<EvaluateJavaScriptNavigationDelegate> delegate = adoptNS([[EvaluateJavaScriptNavigationDelegate alloc] init]);
+    [webView setNavigationDelegate:delegate.get()];
 
     NSURLRequest *request = [NSURLRequest requestWithURL:[[NSBundle mainBundle] URLForResource:@"simple" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]];
     [webView loadRequest:request];
+    TestWebKitAPI::Util::run(&isDone);
 
     [webView evaluateJavaScript:@"document.body" completionHandler:^(id result, NSError *error) {
         EXPECT_NULL(result);
         EXPECT_WK_STREQ(@"WKErrorDomain", [error domain]);
-        EXPECT_EQ(5, [error code]);
+        EXPECT_EQ(WKErrorJavaScriptResultTypeIsUnsupported, [error code]);
 
         isDone = true;
     }];
@@ -81,7 +97,26 @@ TEST(WKWebView, EvaluateJavaScriptErrorCases)
     [webView evaluateJavaScript:@"document.body.insertBefore(document, document)" completionHandler:^(id result, NSError *error) {
         EXPECT_NULL(result);
         EXPECT_WK_STREQ(@"WKErrorDomain", [error domain]);
-        EXPECT_EQ(4, [error code]);
+        EXPECT_EQ(WKErrorJavaScriptExceptionOccurred, [error code]);
+        EXPECT_NOT_NULL([error.userInfo objectForKey:_WKJavaScriptExceptionMessageErrorKey]);
+        EXPECT_GT([[error.userInfo objectForKey:_WKJavaScriptExceptionMessageErrorKey] length], (unsigned long)0);
+        EXPECT_EQ(1, [[error.userInfo objectForKey:_WKJavaScriptExceptionLineNumberErrorKey] intValue]);
+        EXPECT_EQ(27, [[error.userInfo objectForKey:_WKJavaScriptExceptionColumnNumberErrorKey] intValue]);
+
+        isDone = true;
+    }];
+
+    isDone = false;
+    TestWebKitAPI::Util::run(&isDone);
+
+    [webView evaluateJavaScript:@"\n\nthrow 'something bad'" completionHandler:^(id result, NSError *error) {
+        EXPECT_NULL(result);
+        EXPECT_WK_STREQ(@"WKErrorDomain", [error domain]);
+        EXPECT_EQ(WKErrorJavaScriptExceptionOccurred, [error code]);
+        EXPECT_WK_STREQ(@"something bad", [error.userInfo objectForKey:_WKJavaScriptExceptionMessageErrorKey]);
+        EXPECT_EQ(3, [[error.userInfo objectForKey:_WKJavaScriptExceptionLineNumberErrorKey] intValue]);
+        EXPECT_EQ(22, [[error.userInfo objectForKey:_WKJavaScriptExceptionColumnNumberErrorKey] intValue]);
+        EXPECT_NOT_NULL([error.userInfo objectForKey:_WKJavaScriptExceptionSourceURLErrorKey]);
 
         isDone = true;
     }];