1 /* 2 * Copyright (C) 2008 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of 14 * its contributors may be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #import "WebScriptDebugger.h" 30 31 #import "WebDelegateImplementationCaching.h" 32 #import "WebFrameInternal.h" 33 #import "WebScriptDebugDelegate.h" 34 #import "WebViewInternal.h" 35 #import <JavaScriptCore/DebuggerCallFrame.h> 36 #import <JavaScriptCore/JSGlobalObject.h> 37 #import <JavaScriptCore/SourceCode.h> 38 #import <WebCore/DOMWindow.h> 39 #import <WebCore/Frame.h> 40 #import <WebCore/JSDOMWindow.h> 41 #import <WebCore/KURL.h> 42 #import <WebCore/ScriptController.h> 43 44 using namespace JSC; 45 using namespace WebCore; 46 47 @interface WebScriptCallFrame (WebScriptDebugDelegateInternal) 48 - (WebScriptCallFrame *)_initWithGlobalObject:(WebScriptObject *)globalObj debugger:(WebScriptDebugger *)debugger caller:(WebScriptCallFrame *)caller debuggerCallFrame:(const DebuggerCallFrame&)debuggerCallFrame; 49 - (void)_setDebuggerCallFrame:(const DebuggerCallFrame&)debuggerCallFrame; 50 - (void)_clearDebuggerCallFrame; 51 @end 52 53 NSString *toNSString(const UString& s) 54 { 55 if (s.isEmpty()) 56 return nil; 57 return [NSString stringWithCharacters:reinterpret_cast<const unichar*>(s.data()) length:s.size()]; 58 } 59 60 static NSString *toNSString(const SourceCode& s) 61 { 62 if (!s.length()) 63 return nil; 64 return [NSString stringWithCharacters:reinterpret_cast<const unichar*>(s.data()) length:s.length()]; 65 } 66 67 // convert UString to NSURL 68 static NSURL *toNSURL(const UString& s) 69 { 70 if (s.isEmpty()) 71 return nil; 72 return KURL(ParsedURLString, s); 73 } 74 75 static WebFrame *toWebFrame(JSGlobalObject* globalObject) 76 { 77 JSDOMWindow* window = static_cast<JSDOMWindow*>(globalObject); 78 return kit(window->impl()->frame()); 79 } 80 81 WebScriptDebugger::WebScriptDebugger(JSGlobalObject* globalObject) 82 : m_callingDelegate(false) 83 , m_globalObject(globalObject) 84 { 85 attach(globalObject); 86 initGlobalCallFrame(globalObject->globalExec()); 87 } 88 89 void WebScriptDebugger::initGlobalCallFrame(const DebuggerCallFrame& debuggerCallFrame) 90 { 91 m_callingDelegate = true; 92 93 WebFrame *webFrame = toWebFrame(debuggerCallFrame.dynamicGlobalObject()); 94 95 m_topCallFrame.adoptNS([[WebScriptCallFrame alloc] _initWithGlobalObject:core(webFrame)->script()->windowScriptObject() debugger:this caller:m_topCallFrame.get() debuggerCallFrame:debuggerCallFrame]); 96 m_globalCallFrame = m_topCallFrame; 97 98 WebView *webView = [webFrame webView]; 99 WebScriptDebugDelegateImplementationCache* implementations = WebViewGetScriptDebugDelegateImplementations(webView); 100 if (implementations->didEnterCallFrameFunc) 101 CallScriptDebugDelegate(implementations->didEnterCallFrameFunc, webView, @selector(webView:didEnterCallFrame:sourceId:line:forWebFrame:), m_topCallFrame.get(), static_cast<NSInteger>(0), -1, webFrame); 102 103 m_callingDelegate = false; 104 } 105 106 // callbacks - relay to delegate 107 void WebScriptDebugger::sourceParsed(ExecState* exec, const SourceCode& source, int errorLine, const UString& errorMsg) 108 { 109 if (m_callingDelegate) 110 return; 111 112 m_callingDelegate = true; 113 114 NSString *nsSource = toNSString(source); 115 NSURL *nsURL = toNSURL(source.provider()->url()); 116 117 WebFrame *webFrame = toWebFrame(exec->dynamicGlobalObject()); 118 WebView *webView = [webFrame webView]; 119 WebScriptDebugDelegateImplementationCache* implementations = WebViewGetScriptDebugDelegateImplementations(webView); 120 121 if (errorLine == -1) { 122 if (implementations->didParseSourceFunc) { 123 if (implementations->didParseSourceExpectsBaseLineNumber) 124 CallScriptDebugDelegate(implementations->didParseSourceFunc, webView, @selector(webView:didParseSource:baseLineNumber:fromURL:sourceId:forWebFrame:), nsSource, source.firstLine(), nsURL, source.provider()->asID(), webFrame); 125 else 126 CallScriptDebugDelegate(implementations->didParseSourceFunc, webView, @selector(webView:didParseSource:fromURL:sourceId:forWebFrame:), nsSource, [nsURL absoluteString], source.provider()->asID(), webFrame); 127 } 128 } else { 129 NSString* nsErrorMessage = toNSString(errorMsg); 130 NSDictionary *info = [[NSDictionary alloc] initWithObjectsAndKeys:nsErrorMessage, WebScriptErrorDescriptionKey, [NSNumber numberWithUnsignedInt:errorLine], WebScriptErrorLineNumberKey, nil]; 131 NSError *error = [[NSError alloc] initWithDomain:WebScriptErrorDomain code:WebScriptGeneralErrorCode userInfo:info]; 132 133 if (implementations->failedToParseSourceFunc) 134 CallScriptDebugDelegate(implementations->failedToParseSourceFunc, webView, @selector(webView:failedToParseSource:baseLineNumber:fromURL:withError:forWebFrame:), nsSource, source.firstLine(), nsURL, error, webFrame); 135 136 [error release]; 137 [info release]; 138 } 139 140 m_callingDelegate = false; 141 } 142 143 void WebScriptDebugger::callEvent(const DebuggerCallFrame& debuggerCallFrame, intptr_t sourceID, int lineNumber) 144 { 145 if (m_callingDelegate) 146 return; 147 148 m_callingDelegate = true; 149 150 WebFrame *webFrame = toWebFrame(debuggerCallFrame.dynamicGlobalObject()); 151 152 m_topCallFrame.adoptNS([[WebScriptCallFrame alloc] _initWithGlobalObject:core(webFrame)->script()->windowScriptObject() debugger:this caller:m_topCallFrame.get() debuggerCallFrame:debuggerCallFrame]); 153 154 WebView *webView = [webFrame webView]; 155 WebScriptDebugDelegateImplementationCache* implementations = WebViewGetScriptDebugDelegateImplementations(webView); 156 if (implementations->didEnterCallFrameFunc) 157 CallScriptDebugDelegate(implementations->didEnterCallFrameFunc, webView, @selector(webView:didEnterCallFrame:sourceId:line:forWebFrame:), m_topCallFrame.get(), sourceID, lineNumber, webFrame); 158 159 m_callingDelegate = false; 160 } 161 162 void WebScriptDebugger::atStatement(const DebuggerCallFrame& debuggerCallFrame, intptr_t sourceID, int lineNumber) 163 { 164 if (m_callingDelegate) 165 return; 166 167 m_callingDelegate = true; 168 169 WebFrame *webFrame = toWebFrame(debuggerCallFrame.dynamicGlobalObject()); 170 WebView *webView = [webFrame webView]; 171 172 [m_topCallFrame.get() _setDebuggerCallFrame:debuggerCallFrame]; 173 174 WebScriptDebugDelegateImplementationCache* implementations = WebViewGetScriptDebugDelegateImplementations(webView); 175 if (implementations->willExecuteStatementFunc) 176 CallScriptDebugDelegate(implementations->willExecuteStatementFunc, webView, @selector(webView:willExecuteStatement:sourceId:line:forWebFrame:), m_topCallFrame.get(), sourceID, lineNumber, webFrame); 177 178 m_callingDelegate = false; 179 } 180 181 void WebScriptDebugger::returnEvent(const DebuggerCallFrame& debuggerCallFrame, intptr_t sourceID, int lineNumber) 182 { 183 if (m_callingDelegate) 184 return; 185 186 m_callingDelegate = true; 187 188 WebFrame *webFrame = toWebFrame(debuggerCallFrame.dynamicGlobalObject()); 189 WebView *webView = [webFrame webView]; 190 191 [m_topCallFrame.get() _setDebuggerCallFrame:debuggerCallFrame]; 192 193 WebScriptDebugDelegateImplementationCache* implementations = WebViewGetScriptDebugDelegateImplementations(webView); 194 if (implementations->willLeaveCallFrameFunc) 195 CallScriptDebugDelegate(implementations->willLeaveCallFrameFunc, webView, @selector(webView:willLeaveCallFrame:sourceId:line:forWebFrame:), m_topCallFrame.get(), sourceID, lineNumber, webFrame); 196 197 [m_topCallFrame.get() _clearDebuggerCallFrame]; 198 m_topCallFrame = [m_topCallFrame.get() caller]; 199 200 m_callingDelegate = false; 201 } 202 203 void WebScriptDebugger::exception(const DebuggerCallFrame& debuggerCallFrame, intptr_t sourceID, int lineNumber, bool hasHandler) 204 { 205 if (m_callingDelegate) 206 return; 207 208 m_callingDelegate = true; 209 210 WebFrame *webFrame = toWebFrame(debuggerCallFrame.dynamicGlobalObject()); 211 WebView *webView = [webFrame webView]; 212 [m_topCallFrame.get() _setDebuggerCallFrame:debuggerCallFrame]; 213 214 WebScriptDebugDelegateImplementationCache* implementations = WebViewGetScriptDebugDelegateImplementations(webView); 215 if (implementations->exceptionWasRaisedFunc) 216 CallScriptDebugDelegate(implementations->exceptionWasRaisedFunc, webView, @selector(webView:exceptionWasRaised:sourceId:line:forWebFrame:), m_topCallFrame.get(), sourceID, lineNumber, webFrame); 217 218 m_callingDelegate = false; 219 } 220 221 void WebScriptDebugger::willExecuteProgram(const DebuggerCallFrame& debuggerCallFrame, intptr_t sourceID, int lineno) 222 { 223 } 224 225 void WebScriptDebugger::didExecuteProgram(const DebuggerCallFrame& debuggerCallFrame, intptr_t sourceID, int lineno) 226 { 227 } 228 229 void WebScriptDebugger::didReachBreakpoint(const DebuggerCallFrame&, intptr_t, int) 230 { 231 return; 232 } 233