WebCore:
[WebKit-https.git] / WebKit / win / WebScriptDebugServer.cpp
1 /*
2  * Copyright (C) 2007 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  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #include "config.h"
27 #include "IWebScriptDebugListener.h"
28 #include "WebKitDLL.h"
29 #include "WebScriptDebugServer.h"
30
31 #include "WebView.h"
32 #include <wtf/Assertions.h>
33 #include <wtf/Vector.h>
34
35 static Vector<IWebView*> sViews;
36 static WebScriptDebugServer* sSharedWebScriptDebugServer;
37 static unsigned sListenerCount = 0;
38
39 unsigned WebScriptDebugServer::listenerCount() { return sListenerCount; };
40
41 // EnumViews ------------------------------------------------------------------
42
43 class EnumViews : public IEnumVARIANT
44 {
45 public:
46     EnumViews() : m_refCount(1), m_current(sViews.begin()) { }
47
48     virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject);
49     virtual ULONG STDMETHODCALLTYPE AddRef();
50     virtual ULONG STDMETHODCALLTYPE Release();
51
52     virtual HRESULT STDMETHODCALLTYPE Next(ULONG celt, VARIANT *rgVar, ULONG *pCeltFetched);
53     virtual HRESULT STDMETHODCALLTYPE Skip(ULONG celt);
54     virtual HRESULT STDMETHODCALLTYPE Reset(void);
55     virtual HRESULT STDMETHODCALLTYPE Clone(IEnumVARIANT**);
56
57 private:
58     ULONG m_refCount;
59     Vector<IWebView*>::iterator m_current;
60 };
61
62 HRESULT STDMETHODCALLTYPE EnumViews::QueryInterface(REFIID riid, void** ppvObject)
63 {
64     *ppvObject = 0;
65     if (IsEqualGUID(riid, IID_IUnknown) || IsEqualGUID(riid, IID_IEnumVARIANT))
66         *ppvObject = this;
67     else
68         return E_NOINTERFACE;
69
70     AddRef();
71     return S_OK;
72 }
73
74 ULONG STDMETHODCALLTYPE EnumViews::AddRef()
75 {
76     return ++m_refCount;
77 }
78
79 ULONG STDMETHODCALLTYPE EnumViews::Release()
80 {
81     ULONG newRef = --m_refCount;
82     if (!newRef)
83         delete(this);
84     return newRef;
85 }
86
87 HRESULT STDMETHODCALLTYPE EnumViews::Next(ULONG celt, VARIANT *rgVar, ULONG *pCeltFetched)
88 {
89     if (pCeltFetched)
90         *pCeltFetched = 0;
91     if (!rgVar)
92         return E_POINTER;
93     VariantInit(rgVar);
94     if (!celt || celt > 1)
95         return S_FALSE;
96     if (m_current == sViews.end())
97         return S_FALSE;
98
99     IUnknown* unknown;
100     HRESULT hr = (*m_current++)->QueryInterface(IID_IUnknown, (void**)&unknown);
101     if (FAILED(hr))
102         return hr;
103
104     V_VT(rgVar) = VT_UNKNOWN;
105     V_UNKNOWN(rgVar) = unknown;
106
107     if (pCeltFetched)
108         *pCeltFetched = 1;
109     return S_OK;
110 }
111
112 HRESULT STDMETHODCALLTYPE EnumViews::Skip(ULONG celt)
113 {
114     m_current += celt;
115     return (m_current != sViews.end()) ? S_OK : S_FALSE;
116 }
117
118 HRESULT STDMETHODCALLTYPE EnumViews::Reset(void)
119 {
120     m_current = sViews.begin();
121     return S_OK;
122 }
123
124 HRESULT STDMETHODCALLTYPE EnumViews::Clone(IEnumVARIANT**)
125 {
126     return E_NOTIMPL;
127 }
128
129 // WebScriptDebugServer ------------------------------------------------------------
130
131 WebScriptDebugServer::WebScriptDebugServer()
132     : m_refCount(0)
133     , m_paused(false)
134     , m_step(false)
135 {
136     gClassCount++;
137 }
138
139 WebScriptDebugServer::~WebScriptDebugServer()
140 {
141     gClassCount--;
142 }
143
144 WebScriptDebugServer* WebScriptDebugServer::createInstance()
145 {
146     WebScriptDebugServer* instance = new WebScriptDebugServer;
147     instance->AddRef();
148     return instance;
149 }
150
151 WebScriptDebugServer* WebScriptDebugServer::sharedWebScriptDebugServer()
152 {
153     if (!sSharedWebScriptDebugServer)
154         sSharedWebScriptDebugServer = WebScriptDebugServer::createInstance();
155
156     return sSharedWebScriptDebugServer;
157 }
158
159
160 // IUnknown -------------------------------------------------------------------
161
162 HRESULT STDMETHODCALLTYPE WebScriptDebugServer::QueryInterface(REFIID riid, void** ppvObject)
163 {
164     *ppvObject = 0;
165     if (IsEqualGUID(riid, IID_IUnknown))
166         *ppvObject = static_cast<WebScriptDebugServer*>(this);
167     else if (IsEqualGUID(riid, IID_IWebScriptDebugServer))
168         *ppvObject = static_cast<WebScriptDebugServer*>(this);
169     else
170         return E_NOINTERFACE;
171
172     AddRef();
173     return S_OK;
174 }
175
176 ULONG STDMETHODCALLTYPE WebScriptDebugServer::AddRef()
177 {
178     return ++m_refCount;
179 }
180
181 ULONG STDMETHODCALLTYPE WebScriptDebugServer::Release()
182 {
183     ULONG newRef = --m_refCount;
184     if (!newRef)
185         delete(this);
186
187     return newRef;
188 }
189
190 void WebScriptDebugServer::viewAdded(IWebView* view)
191 {
192     sViews.append(view);
193 }
194
195 void WebScriptDebugServer::viewRemoved(IWebView* view)
196 {
197     Vector<IWebView*>::iterator end = sViews.end();
198     int i=0;
199     for (Vector<IWebView*>::iterator it = sViews.begin(); it != end; ++it, ++i) {
200         if (*it == view) {
201             sViews.remove(i);
202             break;
203         }
204     }
205 }
206
207 // IWebScriptDebugServer -----------------------------------------------------------
208
209 HRESULT STDMETHODCALLTYPE WebScriptDebugServer::sharedWebScriptDebugServer( 
210     /* [retval][out] */ IWebScriptDebugServer** server)
211 {
212     if (!server)
213         return E_POINTER;
214
215     *server = WebScriptDebugServer::sharedWebScriptDebugServer();
216     (*server)->AddRef();
217
218     return S_OK;
219 }
220
221 HRESULT STDMETHODCALLTYPE WebScriptDebugServer::addListener(
222     /* [in] */ IWebScriptDebugListener* listener)
223 {
224     if (!listener)
225         return E_POINTER;
226
227     sListenerCount++;
228     m_listeners.add(listener);
229
230     return S_OK;
231 }
232
233 HRESULT STDMETHODCALLTYPE WebScriptDebugServer::removeListener(
234     /* [in] */ IWebScriptDebugListener* listener)
235 {
236     if (!listener)
237         return E_POINTER;
238
239     if (!m_listeners.contains(listener))
240         return S_OK;
241
242     ASSERT(sListenerCount >= 1);
243     sListenerCount--;
244     m_listeners.remove(listener);
245
246     return S_OK;
247 }
248
249 HRESULT STDMETHODCALLTYPE WebScriptDebugServer::step()
250 {
251     m_step = true;
252     m_paused = false;
253
254     return S_OK;
255 }
256
257 HRESULT STDMETHODCALLTYPE WebScriptDebugServer::pause()
258 {
259     m_paused = true;
260     m_step = false;
261
262     return S_OK;
263 }
264
265 HRESULT STDMETHODCALLTYPE WebScriptDebugServer::resume()
266 {
267     m_paused = false;
268     m_step = false;
269
270     return S_OK;
271 }
272
273 HRESULT STDMETHODCALLTYPE WebScriptDebugServer::isPaused(
274     /* [out, retval] */ BOOL* isPaused)
275 {
276     if (!isPaused)
277         return E_POINTER;
278
279     *isPaused = m_paused;
280     return S_OK;
281 }
282
283
284 void WebScriptDebugServer::suspendProcessIfPaused()
285 {
286     // FIXME: There needs to be some sort of busy wait here.
287
288     if (m_step) {
289         m_step = false;
290         m_paused = true;
291     }
292 }
293
294 // IWebScriptDebugListener
295 HRESULT STDMETHODCALLTYPE WebScriptDebugServer::didLoadMainResourceForDataSource(
296     /* [in] */ IWebView* webView,
297     /* [in] */ IWebDataSource* dataSource)
298 {
299     if (!webView || !dataSource)
300         return E_FAIL;
301
302     ListenerSet listenersCopy = m_listeners;
303     for (ListenerSet::iterator it = listenersCopy.begin(); it != listenersCopy.end(); ++it)
304         (**it).didLoadMainResourceForDataSource(webView, dataSource);
305
306     return S_OK;
307 }
308
309 HRESULT STDMETHODCALLTYPE WebScriptDebugServer::didParseSource(
310     /* [in] */ IWebView* webView,
311     /* [in] */ BSTR sourceCode,
312     /* [in] */ UINT baseLineNumber,
313     /* [in] */ BSTR url,
314     /* [in] */ int sourceID,
315     /* [in] */ IWebFrame* webFrame)
316 {
317     if (!webView || !sourceCode || !url || !webFrame)
318         return E_FAIL;
319
320     ListenerSet listenersCopy = m_listeners;
321     for (ListenerSet::iterator it = listenersCopy.begin(); it != listenersCopy.end(); ++it)
322         (**it).didParseSource(webView, sourceCode, baseLineNumber, url, sourceID, webFrame);
323
324     return S_OK;
325 }
326
327 HRESULT STDMETHODCALLTYPE WebScriptDebugServer::failedToParseSource(
328     /* [in] */ IWebView* webView,
329     /* [in] */ BSTR sourceCode,
330     /* [in] */ UINT baseLineNumber,
331     /* [in] */ BSTR url,
332     /* [in] */ BSTR error,
333     /* [in] */ IWebFrame* webFrame)
334 {
335     if (!webView || !sourceCode || !url || !error || !webFrame)
336         return E_FAIL;
337
338     ListenerSet listenersCopy = m_listeners;
339     for (ListenerSet::iterator it = listenersCopy.begin(); it != listenersCopy.end(); ++it)
340         (**it).failedToParseSource(webView, sourceCode, baseLineNumber, url, error, webFrame);
341
342     return S_OK;
343 }
344
345 HRESULT STDMETHODCALLTYPE WebScriptDebugServer::didEnterCallFrame(
346     /* [in] */ IWebView* webView,
347     /* [in] */ IWebScriptCallFrame* frame,
348     /* [in] */ int sourceID,
349     /* [in] */ int lineNumber,
350     /* [in] */ IWebFrame* webFrame)
351 {
352     if (!webView || !frame || !webFrame)
353         return E_FAIL;
354
355     ListenerSet listenersCopy = m_listeners;
356     for (ListenerSet::iterator it = listenersCopy.begin(); it != listenersCopy.end(); ++it)
357         (**it).didEnterCallFrame(webView, frame, sourceID, lineNumber, webFrame);
358
359     return S_OK;
360 }
361
362 HRESULT STDMETHODCALLTYPE WebScriptDebugServer::willExecuteStatement(
363     /* [in] */ IWebView* webView,
364     /* [in] */ IWebScriptCallFrame* frame,
365     /* [in] */ int sourceID,
366     /* [in] */ int lineNumber,
367     /* [in] */ IWebFrame* webFrame)
368 {
369     if (!webView || !frame || !webFrame)
370         return E_FAIL;
371
372     ListenerSet listenersCopy = m_listeners;
373     for (ListenerSet::iterator it = listenersCopy.begin(); it != listenersCopy.end(); ++it)
374         (**it).willExecuteStatement(webView, frame, sourceID, lineNumber, webFrame);
375
376     return S_OK;
377 }
378
379 HRESULT STDMETHODCALLTYPE WebScriptDebugServer::willLeaveCallFrame(
380     /* [in] */ IWebView* webView,
381     /* [in] */ IWebScriptCallFrame* frame,
382     /* [in] */ int sourceID,
383     /* [in] */ int lineNumber,
384     /* [in] */ IWebFrame* webFrame)
385 {
386     if (!webView || !frame || !webFrame)
387         return E_FAIL;
388
389     ListenerSet listenersCopy = m_listeners;
390     for (ListenerSet::iterator it = listenersCopy.begin(); it != listenersCopy.end(); ++it)
391         (**it).willLeaveCallFrame(webView, frame, sourceID, lineNumber, webFrame);
392
393     return S_OK;
394 }
395
396 HRESULT STDMETHODCALLTYPE WebScriptDebugServer::exceptionWasRaised(
397     /* [in] */ IWebView* webView,
398     /* [in] */ IWebScriptCallFrame* frame,
399     /* [in] */ int sourceID,
400     /* [in] */ int lineNumber,
401     /* [in] */ IWebFrame* webFrame)
402 {
403     if (!webView || !frame || !webFrame)
404         return E_FAIL;
405
406     ListenerSet listenersCopy = m_listeners;
407     for (ListenerSet::iterator it = listenersCopy.begin(); it != listenersCopy.end(); ++it)
408         (**it).exceptionWasRaised(webView, frame, sourceID, lineNumber, webFrame);
409
410     return S_OK;
411 }
412
413