/* * Copyright (C) 2007 Apple Inc. All rights reserved. * Copyright (C) 2006, 2007 Vladimir Olexa (vladimir.olexa@gmail.com) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" #include "ServerConnection.h" #include "DebuggerDocument.h" #include #include #include #include #include #include #include #include ServerConnection::ServerConnection() : m_globalContext(0) , m_serverConnected(false) { OleInitialize(0); attemptToCreateServerConnection(); } ServerConnection::~ServerConnection() { if (m_server) m_server->removeListener(this); if (m_globalContext) JSGlobalContextRelease(m_globalContext); } void ServerConnection::attemptToCreateServerConnection(JSGlobalContextRef globalContextRef) { COMPtr tempServer; if (SUCCEEDED(CoCreateInstance(CLSID_WebScriptDebugServer, 0, CLSCTX_LOCAL_SERVER, IID_IWebScriptDebugServer, (void**)&tempServer))) { if (FAILED(tempServer->sharedWebScriptDebugServer(&m_server))) return; if (FAILED(m_server->addListener(this))) { m_server = 0; return; } m_serverConnected = true; if (globalContextRef) m_globalContext = JSGlobalContextRetain(globalContextRef); } } void ServerConnection::setGlobalContext(JSGlobalContextRef globalContextRef) { m_globalContext = JSGlobalContextRetain(globalContextRef); } // Pause & Step void ServerConnection::pause() { if (m_server) m_server->pause(); } void ServerConnection::resume() { if (m_server) m_server->resume(); } void ServerConnection::stepInto() { if (m_server) m_server->step(); } // IUnknown -------------------------------------------------- HRESULT STDMETHODCALLTYPE ServerConnection::QueryInterface(REFIID riid, void** ppvObject) { *ppvObject = 0; if (IsEqualGUID(riid, IID_IUnknown)) *ppvObject = this; else if (IsEqualGUID(riid, IID_IWebScriptDebugListener)) *ppvObject = static_cast(this); else return E_NOINTERFACE; AddRef(); return S_OK; } ULONG STDMETHODCALLTYPE ServerConnection::AddRef(void) { // COM ref-counting isn't useful to us because we're in charge of the lifetime of the WebView. return 1; } ULONG STDMETHODCALLTYPE ServerConnection::Release(void) { // COM ref-counting isn't useful to us because we're in charge of the lifetime of the WebView. return 1; } // IWebScriptDebugListener ----------------------------------- HRESULT STDMETHODCALLTYPE ServerConnection::didLoadMainResourceForDataSource( /* [in] */ IWebView*, /* [in] */ IWebDataSource* dataSource) { HRESULT ret = S_OK; if (!m_globalContext || !dataSource) return ret; // Get document source COMPtr rep; ret = dataSource->representation(&rep); if (FAILED(ret)) return ret; BOOL canProvideDocumentSource = FALSE; ret = rep->canProvideDocumentSource(&canProvideDocumentSource); if (FAILED(ret)) return ret; BSTR documentSource = 0; if (canProvideDocumentSource) ret = rep->documentSource(&documentSource); if (FAILED(ret) || !documentSource) return ret; JSRetainPtr documentSourceJS(Adopt, JSStringCreateWithBSTR(documentSource)); SysFreeString(documentSource); // Get URL COMPtr response; ret = dataSource->response(&response); if (FAILED(ret)) return ret; BSTR url = 0; ret = response->URL(&url); if (FAILED(ret)) return ret; JSRetainPtr urlJS(Adopt, JSStringCreateWithBSTR(url)); SysFreeString(url); DebuggerDocument::updateFileSource(m_globalContext, documentSourceJS.get(), urlJS.get()); return S_OK; } HRESULT STDMETHODCALLTYPE ServerConnection::didParseSource( /* [in] */ IWebView*, /* [in] */ BSTR sourceCode, /* [in] */ UINT baseLineNumber, /* [in] */ BSTR url, /* [in] */ int sourceID, /* [in] */ IWebFrame* webFrame) { HRESULT ret = S_OK; if (!m_globalContext || !sourceCode) return ret; COMPtr dataSource; ret = webFrame->dataSource(&dataSource); if (FAILED(ret)) return ret; COMPtr response; ret = dataSource->response(&response); if (FAILED(ret)) return ret; BSTR responseURL; ret = response->URL(&responseURL); if (FAILED(ret)) return ret; BSTR documentSource = 0; if (!url || !wcscmp(responseURL, url)) { COMPtr rep; ret = dataSource->representation(&rep); if (FAILED(ret)) return ret; BOOL canProvideDocumentSource; rep->canProvideDocumentSource(&canProvideDocumentSource); if (FAILED(ret)) return ret; if (canProvideDocumentSource) { ret = rep->documentSource(&documentSource); if (FAILED(ret)) return ret; } if (!url) { ret = response->URL(&url); if (FAILED(ret)) return ret; } } SysFreeString(responseURL); JSRetainPtr sourceJS(Adopt, JSStringCreateWithBSTR(sourceCode)); JSRetainPtr documentSourceJS(Adopt, JSStringCreateWithBSTR(documentSource)); SysFreeString(documentSource); JSRetainPtr urlJS(Adopt, JSStringCreateWithBSTR(url)); JSValueRef sidJS = JSValueMakeNumber(m_globalContext, sourceID); JSValueRef baseLineJS = JSValueMakeNumber(m_globalContext, baseLineNumber); DebuggerDocument::didParseScript(m_globalContext, sourceJS.get(), documentSourceJS.get(), urlJS.get(), sidJS, baseLineJS); return S_OK; } HRESULT STDMETHODCALLTYPE ServerConnection::failedToParseSource( /* [in] */ IWebView*, /* [in] */ BSTR, /* [in] */ UINT, /* [in] */ BSTR, /* [in] */ BSTR, /* [in] */ IWebFrame*) { return S_OK; } HRESULT STDMETHODCALLTYPE ServerConnection::didEnterCallFrame( /* [in] */ IWebView*, /* [in] */ IWebScriptCallFrame* frame, /* [in] */ int sourceID, /* [in] */ int lineNumber, /* [in] */ IWebFrame*) { HRESULT ret = S_OK; if (!m_globalContext) return ret; m_currentFrame = frame; JSValueRef sidJS = JSValueMakeNumber(m_globalContext, sourceID); JSValueRef linenoJS = JSValueMakeNumber(m_globalContext, lineNumber); DebuggerDocument::didEnterCallFrame(m_globalContext, sidJS, linenoJS); return ret; } HRESULT STDMETHODCALLTYPE ServerConnection::willExecuteStatement( /* [in] */ IWebView*, /* [in] */ IWebScriptCallFrame*, /* [in] */ int sourceID, /* [in] */ int lineNumber, /* [in] */ IWebFrame*) { HRESULT ret = S_OK; if (!m_globalContext) return ret; JSValueRef sidJS = JSValueMakeNumber(m_globalContext, sourceID); JSValueRef linenoJS = JSValueMakeNumber(m_globalContext, lineNumber); DebuggerDocument::willExecuteStatement(m_globalContext, sidJS, linenoJS); return ret; } HRESULT STDMETHODCALLTYPE ServerConnection::willLeaveCallFrame( /* [in] */ IWebView*, /* [in] */ IWebScriptCallFrame* frame, /* [in] */ int sourceID, /* [in] */ int lineNumber, /* [in] */ IWebFrame*) { HRESULT ret = S_OK; if (!m_globalContext) return ret; JSValueRef sidJS = JSValueMakeNumber(m_globalContext, sourceID); JSValueRef linenoJS = JSValueMakeNumber(m_globalContext, lineNumber); DebuggerDocument::willLeaveCallFrame(m_globalContext, sidJS, linenoJS); m_currentFrame = frame; return S_OK; } HRESULT STDMETHODCALLTYPE ServerConnection::exceptionWasRaised( /* [in] */ IWebView*, /* [in] */ IWebScriptCallFrame*, /* [in] */ int sourceID, /* [in] */ int lineNumber, /* [in] */ IWebFrame*) { HRESULT ret = S_OK; if (!m_globalContext) return ret; JSValueRef sidJS = JSValueMakeNumber(m_globalContext, sourceID); JSValueRef linenoJS = JSValueMakeNumber(m_globalContext, lineNumber); DebuggerDocument::exceptionWasRaised(m_globalContext, sidJS, linenoJS); return ret; } HRESULT STDMETHODCALLTYPE ServerConnection::serverDidDie() { m_server = 0; m_currentFrame = 0; m_serverConnected = false; return S_OK; } // Stack & Variables IWebScriptCallFrame* ServerConnection::currentFrame() const { return m_currentFrame.get(); } COMPtr ServerConnection::getCallerFrame(int callFrame) const { COMPtr cframe = currentFrame(); for (int count = 0; count < callFrame; count++) { COMPtr callerFrame; if (FAILED(cframe->caller(&callerFrame))) return 0; cframe = callerFrame; } return cframe; }