blob: e59c4fce375db567ff0f11786dff6c78ed7f2860 [file] [log] [blame]
/*
* 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 <JavaScriptCore/JSContextRef.h>
#include <JavaScriptCore/JSRetainPtr.h>
#include <JavaScriptCore/JSStringRefBSTR.h>
#include <JavaScriptCore/RetainPtr.h>
#include <WebKit/ForEachCoClass.h>
#include <WebKit/IWebScriptCallFrame.h>
#include <WebKit/IWebScriptDebugServer.h>
#include <WebKit/WebKit.h>
#include <iostream>
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<IWebScriptDebugServer> tempServer;
CLSID clsid = CLSID_NULL;
if (FAILED(CLSIDFromProgID(PROGID(WebScriptDebugServer), &clsid)))
return;
if (FAILED(CoCreateInstance(clsid, 0, CLSCTX_LOCAL_SERVER, IID_IWebScriptDebugServer, (void**)&tempServer)))
return;
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<IWebScriptDebugListener*>(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<IWebDocumentRepresentation> 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<JSStringRef> documentSourceJS(Adopt, JSStringCreateWithBSTR(documentSource));
SysFreeString(documentSource);
// Get URL
COMPtr<IWebURLResponse> response;
ret = dataSource->response(&response);
if (FAILED(ret))
return ret;
BSTR url = 0;
ret = response->URL(&url);
if (FAILED(ret))
return ret;
JSRetainPtr<JSStringRef> 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<IWebDataSource> dataSource;
ret = webFrame->dataSource(&dataSource);
if (FAILED(ret))
return ret;
COMPtr<IWebURLResponse> 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<IWebDocumentRepresentation> 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<JSStringRef> sourceJS(Adopt, JSStringCreateWithBSTR(sourceCode));
JSRetainPtr<JSStringRef> documentSourceJS(Adopt, JSStringCreateWithBSTR(documentSource));
SysFreeString(documentSource);
JSRetainPtr<JSStringRef> 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<IWebScriptCallFrame> ServerConnection::getCallerFrame(int callFrame) const
{
COMPtr<IWebScriptCallFrame> cframe = currentFrame();
for (int count = 0; count < callFrame; count++) {
COMPtr<IWebScriptCallFrame> callerFrame;
if (FAILED(cframe->caller(&callerFrame)))
return 0;
cframe = callerFrame;
}
return cframe;
}