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 <WebCore/DOMWindow.h> 36#import <WebCore/Frame.h> 37#import <WebCore/JSDOMWindow.h> 38#import <WebCore/KURL.h> 39#import <WebCore/ScriptController.h> 40#import <debugger/DebuggerCallFrame.h> 41#import <runtime/JSGlobalObject.h> 42 43using namespace JSC; 44using namespace WebCore; 45 46@interface WebScriptCallFrame (WebScriptDebugDelegateInternal) 47- (WebScriptCallFrame *)_initWithGlobalObject:(WebScriptObject *)globalObj debugger:(WebScriptDebugger *)debugger caller:(WebScriptCallFrame *)caller debuggerCallFrame:(const DebuggerCallFrame&)debuggerCallFrame; 48- (void)_setDebuggerCallFrame:(const DebuggerCallFrame&)debuggerCallFrame; 49- (void)_clearDebuggerCallFrame; 50@end 51 52NSString *toNSString(const UString& s) 53{ 54 if (s.isEmpty()) 55 return nil; 56 return [NSString stringWithCharacters:reinterpret_cast<const unichar*>(s.data()) length:s.size()]; 57} 58 59static NSString *toNSString(const SourceCode& s) 60{ 61 if (!s.length()) 62 return nil; 63 return [NSString stringWithCharacters:reinterpret_cast<const unichar*>(s.data()) length:s.length()]; 64} 65 66// convert UString to NSURL 67static NSURL *toNSURL(const UString& s) 68{ 69 if (s.isEmpty()) 70 return nil; 71 return KURL(s); 72} 73 74static WebFrame *toWebFrame(JSGlobalObject* globalObject) 75{ 76 JSDOMWindow* window = static_cast<JSDOMWindow*>(globalObject); 77 return kit(window->impl()->frame()); 78} 79 80WebScriptDebugger::WebScriptDebugger(JSGlobalObject* globalObject) 81 : m_callingDelegate(false) 82 , m_globalObject(globalObject) 83{ 84 attach(globalObject); 85 initGlobalCallFrame(globalObject->globalExec()); 86} 87 88void WebScriptDebugger::initGlobalCallFrame(const DebuggerCallFrame& debuggerCallFrame) 89{ 90 m_callingDelegate = true; 91 92 WebFrame *webFrame = toWebFrame(debuggerCallFrame.dynamicGlobalObject()); 93 94 m_topCallFrame.adoptNS([[WebScriptCallFrame alloc] _initWithGlobalObject:core(webFrame)->script()->windowScriptObject() debugger:this caller:m_topCallFrame.get() debuggerCallFrame:debuggerCallFrame]); 95 m_globalCallFrame = m_topCallFrame; 96 97 WebView *webView = [webFrame webView]; 98 WebScriptDebugDelegateImplementationCache* implementations = WebViewGetScriptDebugDelegateImplementations(webView); 99 if (implementations->didEnterCallFrameFunc) 100 CallScriptDebugDelegate(implementations->didEnterCallFrameFunc, webView, @selector(webView:didEnterCallFrame:sourceId:line:forWebFrame:), m_topCallFrame.get(), static_cast<NSInteger>(0), -1, webFrame); 101 102 m_callingDelegate = false; 103} 104 105// callbacks - relay to delegate 106void WebScriptDebugger::sourceParsed(ExecState* exec, const SourceCode& source, int errorLine, const UString& errorMsg) 107{ 108 if (m_callingDelegate) 109 return; 110 111 m_callingDelegate = true; 112 113 NSString *nsSource = toNSString(source); 114 NSURL *nsURL = toNSURL(source.provider()->url()); 115 116 WebFrame *webFrame = toWebFrame(exec->dynamicGlobalObject()); 117 WebView *webView = [webFrame webView]; 118 WebScriptDebugDelegateImplementationCache* implementations = WebViewGetScriptDebugDelegateImplementations(webView); 119 120 if (errorLine == -1) { 121 if (implementations->didParseSourceFunc) { 122 if (implementations->didParseSourceExpectsBaseLineNumber) 123 CallScriptDebugDelegate(implementations->didParseSourceFunc, webView, @selector(webView:didParseSource:baseLineNumber:fromURL:sourceId:forWebFrame:), nsSource, source.firstLine(), nsURL, source.provider()->asID(), webFrame); 124 else 125 CallScriptDebugDelegate(implementations->didParseSourceFunc, webView, @selector(webView:didParseSource:fromURL:sourceId:forWebFrame:), nsSource, [nsURL absoluteString], source.provider()->asID(), webFrame); 126 } 127 } else { 128 NSString* nsErrorMessage = toNSString(errorMsg); 129 NSDictionary *info = [[NSDictionary alloc] initWithObjectsAndKeys:nsErrorMessage, WebScriptErrorDescriptionKey, [NSNumber numberWithUnsignedInt:errorLine], WebScriptErrorLineNumberKey, nil]; 130 NSError *error = [[NSError alloc] initWithDomain:WebScriptErrorDomain code:WebScriptGeneralErrorCode userInfo:info]; 131 132 if (implementations->failedToParseSourceFunc) 133 CallScriptDebugDelegate(implementations->failedToParseSourceFunc, webView, @selector(webView:failedToParseSource:baseLineNumber:fromURL:withError:forWebFrame:), nsSource, source.firstLine(), nsURL, error, webFrame); 134 135 [error release]; 136 [info release]; 137 } 138 139 m_callingDelegate = false; 140} 141 142void WebScriptDebugger::callEvent(const DebuggerCallFrame& debuggerCallFrame, intptr_t sourceID, int lineNumber) 143{ 144 if (m_callingDelegate) 145 return; 146 147 m_callingDelegate = true; 148 149 WebFrame *webFrame = toWebFrame(debuggerCallFrame.dynamicGlobalObject()); 150 151 m_topCallFrame.adoptNS([[WebScriptCallFrame alloc] _initWithGlobalObject:core(webFrame)->script()->windowScriptObject() debugger:this caller:m_topCallFrame.get() debuggerCallFrame:debuggerCallFrame]); 152 153 WebView *webView = [webFrame webView]; 154 WebScriptDebugDelegateImplementationCache* implementations = WebViewGetScriptDebugDelegateImplementations(webView); 155 if (implementations->didEnterCallFrameFunc) 156 CallScriptDebugDelegate(implementations->didEnterCallFrameFunc, webView, @selector(webView:didEnterCallFrame:sourceId:line:forWebFrame:), m_topCallFrame.get(), sourceID, lineNumber, webFrame); 157 158 m_callingDelegate = false; 159} 160 161void WebScriptDebugger::atStatement(const DebuggerCallFrame& debuggerCallFrame, intptr_t sourceID, int lineNumber) 162{ 163 if (m_callingDelegate) 164 return; 165 166 m_callingDelegate = true; 167 168 WebFrame *webFrame = toWebFrame(debuggerCallFrame.dynamicGlobalObject()); 169 WebView *webView = [webFrame webView]; 170 171 [m_topCallFrame.get() _setDebuggerCallFrame:debuggerCallFrame]; 172 173 WebScriptDebugDelegateImplementationCache* implementations = WebViewGetScriptDebugDelegateImplementations(webView); 174 if (implementations->willExecuteStatementFunc) 175 CallScriptDebugDelegate(implementations->willExecuteStatementFunc, webView, @selector(webView:willExecuteStatement:sourceId:line:forWebFrame:), m_topCallFrame.get(), sourceID, lineNumber, webFrame); 176 177 m_callingDelegate = false; 178} 179 180void WebScriptDebugger::returnEvent(const DebuggerCallFrame& debuggerCallFrame, intptr_t sourceID, int lineNumber) 181{ 182 if (m_callingDelegate) 183 return; 184 185 m_callingDelegate = true; 186 187 WebFrame *webFrame = toWebFrame(debuggerCallFrame.dynamicGlobalObject()); 188 WebView *webView = [webFrame webView]; 189 190 [m_topCallFrame.get() _setDebuggerCallFrame:debuggerCallFrame]; 191 192 WebScriptDebugDelegateImplementationCache* implementations = WebViewGetScriptDebugDelegateImplementations(webView); 193 if (implementations->willLeaveCallFrameFunc) 194 CallScriptDebugDelegate(implementations->willLeaveCallFrameFunc, webView, @selector(webView:willLeaveCallFrame:sourceId:line:forWebFrame:), m_topCallFrame.get(), sourceID, lineNumber, webFrame); 195 196 [m_topCallFrame.get() _clearDebuggerCallFrame]; 197 m_topCallFrame = [m_topCallFrame.get() caller]; 198 199 m_callingDelegate = false; 200} 201 202void WebScriptDebugger::exception(const DebuggerCallFrame& debuggerCallFrame, intptr_t sourceID, int lineNumber) 203{ 204 if (m_callingDelegate) 205 return; 206 207 m_callingDelegate = true; 208 209 WebFrame *webFrame = toWebFrame(debuggerCallFrame.dynamicGlobalObject()); 210 WebView *webView = [webFrame webView]; 211 [m_topCallFrame.get() _setDebuggerCallFrame:debuggerCallFrame]; 212 213 WebScriptDebugDelegateImplementationCache* implementations = WebViewGetScriptDebugDelegateImplementations(webView); 214 if (implementations->exceptionWasRaisedFunc) 215 CallScriptDebugDelegate(implementations->exceptionWasRaisedFunc, webView, @selector(webView:exceptionWasRaised:sourceId:line:forWebFrame:), m_topCallFrame.get(), sourceID, lineNumber, webFrame); 216 217 m_callingDelegate = false; 218} 219 220void WebScriptDebugger::willExecuteProgram(const DebuggerCallFrame& debuggerCallFrame, intptr_t sourceID, int lineno) 221{ 222} 223 224void WebScriptDebugger::didExecuteProgram(const DebuggerCallFrame& debuggerCallFrame, intptr_t sourceID, int lineno) 225{ 226} 227 228void WebScriptDebugger::didReachBreakpoint(const DebuggerCallFrame&, intptr_t, int) 229{ 230 return; 231} 232