blob: 463da5d35ff4c569dffa5303f7f2ab172229cbea [file] [log] [blame]
/*
* Copyright (C) 2007 Apple Inc. All rights reserved.
*
* 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.
*
* THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 COMPUTER, INC. OR
* 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 "IWebScriptDebugListener.h"
#include "WebKitDLL.h"
#include "WebScriptDebugServer.h"
#include "WebView.h"
#include <wtf/Assertions.h>
#include <wtf/Vector.h>
typedef HashSet<COMPtr<IWebScriptDebugListener> > ListenerSet;
static ListenerSet s_Listeners;
static unsigned s_ListenerCount = 0;
static OwnPtr<WebScriptDebugServer> s_SharedWebScriptDebugServer;
static bool s_dying = false;
unsigned WebScriptDebugServer::listenerCount() { return s_ListenerCount; };
// WebScriptDebugServer ------------------------------------------------------------
WebScriptDebugServer::WebScriptDebugServer()
: m_refCount(0)
, m_paused(false)
, m_step(false)
{
gClassCount++;
}
WebScriptDebugServer::~WebScriptDebugServer()
{
gClassCount--;
}
WebScriptDebugServer* WebScriptDebugServer::createInstance()
{
WebScriptDebugServer* instance = new WebScriptDebugServer;
instance->AddRef();
return instance;
}
WebScriptDebugServer* WebScriptDebugServer::sharedWebScriptDebugServer()
{
if (!s_SharedWebScriptDebugServer) {
s_dying = false;
s_SharedWebScriptDebugServer.set(WebScriptDebugServer::createInstance());
}
return s_SharedWebScriptDebugServer.get();
}
// IUnknown -------------------------------------------------------------------
HRESULT STDMETHODCALLTYPE WebScriptDebugServer::QueryInterface(REFIID riid, void** ppvObject)
{
*ppvObject = 0;
if (IsEqualGUID(riid, IID_IUnknown))
*ppvObject = static_cast<WebScriptDebugServer*>(this);
else if (IsEqualGUID(riid, IID_IWebScriptDebugServer))
*ppvObject = static_cast<WebScriptDebugServer*>(this);
else
return E_NOINTERFACE;
AddRef();
return S_OK;
}
ULONG STDMETHODCALLTYPE WebScriptDebugServer::AddRef()
{
return ++m_refCount;
}
ULONG STDMETHODCALLTYPE WebScriptDebugServer::Release()
{
ULONG newRef = --m_refCount;
if (!newRef)
delete(this);
return newRef;
}
// IWebScriptDebugServer -----------------------------------------------------------
HRESULT STDMETHODCALLTYPE WebScriptDebugServer::sharedWebScriptDebugServer(
/* [retval][out] */ IWebScriptDebugServer** server)
{
if (!server)
return E_POINTER;
*server = WebScriptDebugServer::sharedWebScriptDebugServer();
(*server)->AddRef();
return S_OK;
}
HRESULT STDMETHODCALLTYPE WebScriptDebugServer::addListener(
/* [in] */ IWebScriptDebugListener* listener)
{
if (s_dying)
return E_FAIL;
if (!listener)
return E_POINTER;
++s_ListenerCount;
s_Listeners.add(listener);
return S_OK;
}
HRESULT STDMETHODCALLTYPE WebScriptDebugServer::removeListener(
/* [in] */ IWebScriptDebugListener* listener)
{
if (s_dying)
return S_OK;
if (!listener)
return E_POINTER;
if (!s_Listeners.contains(listener))
return S_OK;
s_Listeners.remove(listener);
ASSERT(s_ListenerCount >= 1);
if (--s_ListenerCount == 0)
resume();
return S_OK;
}
HRESULT STDMETHODCALLTYPE WebScriptDebugServer::step()
{
m_step = true;
m_paused = false;
return S_OK;
}
HRESULT STDMETHODCALLTYPE WebScriptDebugServer::pause()
{
m_paused = true;
m_step = false;
return S_OK;
}
HRESULT STDMETHODCALLTYPE WebScriptDebugServer::resume()
{
m_paused = false;
m_step = false;
return S_OK;
}
HRESULT STDMETHODCALLTYPE WebScriptDebugServer::isPaused(
/* [out, retval] */ BOOL* isPaused)
{
if (!isPaused)
return E_POINTER;
*isPaused = m_paused;
return S_OK;
}
void WebScriptDebugServer::suspendProcessIfPaused()
{
static bool alreadyHere = false;
if (alreadyHere)
return;
alreadyHere = true;
MSG msg;
while (m_paused && GetMessage(&msg, 0, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
if (m_step) {
m_step = false;
m_paused = true;
}
alreadyHere = false;
}
// IWebScriptDebugListener
HRESULT STDMETHODCALLTYPE WebScriptDebugServer::didLoadMainResourceForDataSource(
/* [in] */ IWebView* webView,
/* [in] */ IWebDataSource* dataSource)
{
if (!webView || !dataSource)
return E_FAIL;
ListenerSet listenersCopy = s_Listeners;
ListenerSet::iterator end = listenersCopy.end();
for (ListenerSet::iterator it = listenersCopy.begin(); it != end; ++it)
(**it).didLoadMainResourceForDataSource(webView, dataSource);
return S_OK;
}
HRESULT STDMETHODCALLTYPE WebScriptDebugServer::didParseSource(
/* [in] */ IWebView* webView,
/* [in] */ BSTR sourceCode,
/* [in] */ UINT baseLineNumber,
/* [in] */ BSTR url,
/* [in] */ int sourceID,
/* [in] */ IWebFrame* webFrame)
{
if (!webView || !sourceCode || !url || !webFrame)
return E_FAIL;
ListenerSet listenersCopy = s_Listeners;
ListenerSet::iterator end = listenersCopy.end();
for (ListenerSet::iterator it = listenersCopy.begin(); it != end; ++it)
(**it).didParseSource(webView, sourceCode, baseLineNumber, url, sourceID, webFrame);
return S_OK;
}
HRESULT STDMETHODCALLTYPE WebScriptDebugServer::failedToParseSource(
/* [in] */ IWebView* webView,
/* [in] */ BSTR sourceCode,
/* [in] */ UINT baseLineNumber,
/* [in] */ BSTR url,
/* [in] */ BSTR error,
/* [in] */ IWebFrame* webFrame)
{
if (!webView || !sourceCode || !url || !error || !webFrame)
return E_FAIL;
ListenerSet listenersCopy = s_Listeners;
ListenerSet::iterator end = listenersCopy.end();
for (ListenerSet::iterator it = listenersCopy.begin(); it != end; ++it)
(**it).failedToParseSource(webView, sourceCode, baseLineNumber, url, error, webFrame);
return S_OK;
}
HRESULT STDMETHODCALLTYPE WebScriptDebugServer::didEnterCallFrame(
/* [in] */ IWebView* webView,
/* [in] */ IWebScriptCallFrame* frame,
/* [in] */ int sourceID,
/* [in] */ int lineNumber,
/* [in] */ IWebFrame* webFrame)
{
if (!webView || !frame || !webFrame)
return E_FAIL;
ListenerSet listenersCopy = s_Listeners;
ListenerSet::iterator end = listenersCopy.end();
for (ListenerSet::iterator it = listenersCopy.begin(); it != end; ++it)
(**it).didEnterCallFrame(webView, frame, sourceID, lineNumber, webFrame);
suspendProcessIfPaused();
return S_OK;
}
HRESULT STDMETHODCALLTYPE WebScriptDebugServer::willExecuteStatement(
/* [in] */ IWebView* webView,
/* [in] */ IWebScriptCallFrame* frame,
/* [in] */ int sourceID,
/* [in] */ int lineNumber,
/* [in] */ IWebFrame* webFrame)
{
if (!webView || !frame || !webFrame)
return E_FAIL;
ListenerSet listenersCopy = s_Listeners;
ListenerSet::iterator end = listenersCopy.end();
for (ListenerSet::iterator it = listenersCopy.begin(); it != end; ++it)
(**it).willExecuteStatement(webView, frame, sourceID, lineNumber, webFrame);
suspendProcessIfPaused();
return S_OK;
}
HRESULT STDMETHODCALLTYPE WebScriptDebugServer::willLeaveCallFrame(
/* [in] */ IWebView* webView,
/* [in] */ IWebScriptCallFrame* frame,
/* [in] */ int sourceID,
/* [in] */ int lineNumber,
/* [in] */ IWebFrame* webFrame)
{
if (!webView || !frame || !webFrame)
return E_FAIL;
ListenerSet listenersCopy = s_Listeners;
ListenerSet::iterator end = listenersCopy.end();
for (ListenerSet::iterator it = listenersCopy.begin(); it != end; ++it)
(**it).willLeaveCallFrame(webView, frame, sourceID, lineNumber, webFrame);
suspendProcessIfPaused();
return S_OK;
}
HRESULT STDMETHODCALLTYPE WebScriptDebugServer::exceptionWasRaised(
/* [in] */ IWebView* webView,
/* [in] */ IWebScriptCallFrame* frame,
/* [in] */ int sourceID,
/* [in] */ int lineNumber,
/* [in] */ IWebFrame* webFrame)
{
if (!webView || !frame || !webFrame)
return E_FAIL;
ListenerSet listenersCopy = s_Listeners;
ListenerSet::iterator end = listenersCopy.end();
for (ListenerSet::iterator it = listenersCopy.begin(); it != end; ++it)
(**it).exceptionWasRaised(webView, frame, sourceID, lineNumber, webFrame);
suspendProcessIfPaused();
return S_OK;
}
HRESULT STDMETHODCALLTYPE WebScriptDebugServer::serverDidDie()
{
s_dying = true;
ListenerSet listenersCopy = s_Listeners;
ListenerSet::iterator end = listenersCopy.end();
for (ListenerSet::iterator it = listenersCopy.begin(); it != end; ++it) {
(**it).serverDidDie();
s_Listeners.remove((*it).get());
}
return S_OK;
}