Home | History | Annotate | Download | only in WebView
      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