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/SourceProvider.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.characters()) length:s.length()];
     58 }
     59 
     60 static NSString *toNSString(SourceProvider* 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, ustringToString(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->globalData(), 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, SourceProvider* sourceProvider, int errorLine, const UString& errorMsg)
    108 {
    109     if (m_callingDelegate)
    110         return;
    111 
    112     m_callingDelegate = true;
    113 
    114     NSString *nsSource = toNSString(sourceProvider);
    115     NSURL *nsURL = toNSURL(sourceProvider->url());
    116     int firstLine = sourceProvider->startPosition().m_line.oneBasedInt();
    117 
    118     WebFrame *webFrame = toWebFrame(exec->dynamicGlobalObject());
    119     WebView *webView = [webFrame webView];
    120     WebScriptDebugDelegateImplementationCache* implementations = WebViewGetScriptDebugDelegateImplementations(webView);
    121 
    122     if (errorLine == -1) {
    123         if (implementations->didParseSourceFunc) {
    124             if (implementations->didParseSourceExpectsBaseLineNumber)
    125                 CallScriptDebugDelegate(implementations->didParseSourceFunc, webView, @selector(webView:didParseSource:baseLineNumber:fromURL:sourceId:forWebFrame:), nsSource, firstLine, nsURL, sourceProvider->asID(), webFrame);
    126             else
    127                 CallScriptDebugDelegate(implementations->didParseSourceFunc, webView, @selector(webView:didParseSource:fromURL:sourceId:forWebFrame:), nsSource, [nsURL absoluteString], sourceProvider->asID(), webFrame);
    128         }
    129     } else {
    130         NSString* nsErrorMessage = toNSString(errorMsg);
    131         NSDictionary *info = [[NSDictionary alloc] initWithObjectsAndKeys:nsErrorMessage, WebScriptErrorDescriptionKey, [NSNumber numberWithUnsignedInt:errorLine], WebScriptErrorLineNumberKey, nil];
    132         NSError *error = [[NSError alloc] initWithDomain:WebScriptErrorDomain code:WebScriptGeneralErrorCode userInfo:info];
    133 
    134         if (implementations->failedToParseSourceFunc)
    135             CallScriptDebugDelegate(implementations->failedToParseSourceFunc, webView, @selector(webView:failedToParseSource:baseLineNumber:fromURL:withError:forWebFrame:), nsSource, firstLine, nsURL, error, webFrame);
    136 
    137         [error release];
    138         [info release];
    139     }
    140 
    141     m_callingDelegate = false;
    142 }
    143 
    144 void WebScriptDebugger::callEvent(const DebuggerCallFrame& debuggerCallFrame, intptr_t sourceID, int lineNumber)
    145 {
    146     if (m_callingDelegate)
    147         return;
    148 
    149     m_callingDelegate = true;
    150 
    151     WebFrame *webFrame = toWebFrame(debuggerCallFrame.dynamicGlobalObject());
    152 
    153     m_topCallFrame.adoptNS([[WebScriptCallFrame alloc] _initWithGlobalObject:core(webFrame)->script()->windowScriptObject() debugger:this caller:m_topCallFrame.get() debuggerCallFrame:debuggerCallFrame]);
    154 
    155     WebView *webView = [webFrame webView];
    156     WebScriptDebugDelegateImplementationCache* implementations = WebViewGetScriptDebugDelegateImplementations(webView);
    157     if (implementations->didEnterCallFrameFunc)
    158         CallScriptDebugDelegate(implementations->didEnterCallFrameFunc, webView, @selector(webView:didEnterCallFrame:sourceId:line:forWebFrame:), m_topCallFrame.get(), sourceID, lineNumber, webFrame);
    159 
    160     m_callingDelegate = false;
    161 }
    162 
    163 void WebScriptDebugger::atStatement(const DebuggerCallFrame& debuggerCallFrame, intptr_t sourceID, int lineNumber)
    164 {
    165     if (m_callingDelegate)
    166         return;
    167 
    168     m_callingDelegate = true;
    169 
    170     WebFrame *webFrame = toWebFrame(debuggerCallFrame.dynamicGlobalObject());
    171     WebView *webView = [webFrame webView];
    172 
    173     [m_topCallFrame.get() _setDebuggerCallFrame:debuggerCallFrame];
    174 
    175     WebScriptDebugDelegateImplementationCache* implementations = WebViewGetScriptDebugDelegateImplementations(webView);
    176     if (implementations->willExecuteStatementFunc)
    177         CallScriptDebugDelegate(implementations->willExecuteStatementFunc, webView, @selector(webView:willExecuteStatement:sourceId:line:forWebFrame:), m_topCallFrame.get(), sourceID, lineNumber, webFrame);
    178 
    179     m_callingDelegate = false;
    180 }
    181 
    182 void WebScriptDebugger::returnEvent(const DebuggerCallFrame& debuggerCallFrame, intptr_t sourceID, int lineNumber)
    183 {
    184     if (m_callingDelegate)
    185         return;
    186 
    187     m_callingDelegate = true;
    188 
    189     WebFrame *webFrame = toWebFrame(debuggerCallFrame.dynamicGlobalObject());
    190     WebView *webView = [webFrame webView];
    191 
    192     [m_topCallFrame.get() _setDebuggerCallFrame:debuggerCallFrame];
    193 
    194     WebScriptDebugDelegateImplementationCache* implementations = WebViewGetScriptDebugDelegateImplementations(webView);
    195     if (implementations->willLeaveCallFrameFunc)
    196         CallScriptDebugDelegate(implementations->willLeaveCallFrameFunc, webView, @selector(webView:willLeaveCallFrame:sourceId:line:forWebFrame:), m_topCallFrame.get(), sourceID, lineNumber, webFrame);
    197 
    198     [m_topCallFrame.get() _clearDebuggerCallFrame];
    199     m_topCallFrame = [m_topCallFrame.get() caller];
    200 
    201     m_callingDelegate = false;
    202 }
    203 
    204 void WebScriptDebugger::exception(const DebuggerCallFrame& debuggerCallFrame, intptr_t sourceID, int lineNumber, bool hasHandler)
    205 {
    206     if (m_callingDelegate)
    207         return;
    208 
    209     m_callingDelegate = true;
    210 
    211     WebFrame *webFrame = toWebFrame(debuggerCallFrame.dynamicGlobalObject());
    212     WebView *webView = [webFrame webView];
    213     [m_topCallFrame.get() _setDebuggerCallFrame:debuggerCallFrame];
    214 
    215     WebScriptDebugDelegateImplementationCache* cache = WebViewGetScriptDebugDelegateImplementations(webView);
    216     if (cache->exceptionWasRaisedFunc) {
    217         if (cache->exceptionWasRaisedExpectsHasHandlerFlag)
    218             CallScriptDebugDelegate(cache->exceptionWasRaisedFunc, webView, @selector(webView:exceptionWasRaised:hasHandler:sourceId:line:forWebFrame:), m_topCallFrame.get(), hasHandler, sourceID, lineNumber, webFrame);
    219         else
    220             CallScriptDebugDelegate(cache->exceptionWasRaisedFunc, webView, @selector(webView:exceptionWasRaised:sourceId:line:forWebFrame:), m_topCallFrame.get(), sourceID, lineNumber, webFrame);
    221     }
    222 
    223     m_callingDelegate = false;
    224 }
    225 
    226 void WebScriptDebugger::willExecuteProgram(const DebuggerCallFrame& debuggerCallFrame, intptr_t sourceID, int lineno)
    227 {
    228     callEvent(debuggerCallFrame, sourceID, lineno);
    229 }
    230 
    231 void WebScriptDebugger::didExecuteProgram(const DebuggerCallFrame& debuggerCallFrame, intptr_t sourceID, int lineno)
    232 {
    233     returnEvent(debuggerCallFrame, sourceID, lineno);
    234 }
    235 
    236 void WebScriptDebugger::didReachBreakpoint(const DebuggerCallFrame&, intptr_t, int)
    237 {
    238     return;
    239 }
    240