Mac build fix. Add new symbol to exports file.
[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 "WebKit.h"
28 #include "WebKitDLL.h"
29 #include "WebScriptDebugServer.h"
30
31 #include "WebScriptDebugger.h"
32 #pragma warning(push, 0)
33 #include <WebCore/Page.h>
34 #pragma warning(pop)
35 #include <wtf/Assertions.h>
36 #include <wtf/Vector.h>
37
38 using namespace WebCore;
39
40 typedef HashSet<COMPtr<IWebScriptDebugListener> > ListenerSet;
41
42 static ListenerSet s_Listeners;
43 static unsigned s_ListenerCount = 0;
44 static OwnPtr<WebScriptDebugServer> s_SharedWebScriptDebugServer;
45 static bool s_dying = false;
46
47 unsigned WebScriptDebugServer::listenerCount() { return s_ListenerCount; };
48
49 // WebScriptDebugServer ------------------------------------------------------------
50
51 WebScriptDebugServer::WebScriptDebugServer()
52     : m_refCount(0)
53     , m_paused(false)
54     , m_step(false)
55 {
56     gClassCount++;
57 }
58
59 WebScriptDebugServer::~WebScriptDebugServer()
60 {
61     gClassCount--;
62 }
63
64 WebScriptDebugServer* WebScriptDebugServer::createInstance()
65 {
66     WebScriptDebugServer* instance = new WebScriptDebugServer;
67     instance->AddRef();
68     return instance;
69 }
70
71 WebScriptDebugServer* WebScriptDebugServer::sharedWebScriptDebugServer()
72 {
73     if (!s_SharedWebScriptDebugServer) {
74         s_dying = false;
75         s_SharedWebScriptDebugServer.set(WebScriptDebugServer::createInstance());
76     }
77
78     return s_SharedWebScriptDebugServer.get();
79 }
80
81 void WebScriptDebugServer::pageCreated(Page* page)
82 {
83     ASSERT_ARG(page, page);
84
85     if (s_ListenerCount > 0)
86         page->setDebugger(&WebScriptDebugger::shared());
87 }
88
89 // IUnknown -------------------------------------------------------------------
90
91 HRESULT STDMETHODCALLTYPE WebScriptDebugServer::QueryInterface(REFIID riid, void** ppvObject)
92 {
93     *ppvObject = 0;
94     if (IsEqualGUID(riid, IID_IUnknown))
95         *ppvObject = static_cast<WebScriptDebugServer*>(this);
96     else if (IsEqualGUID(riid, IID_IWebScriptDebugServer))
97         *ppvObject = static_cast<WebScriptDebugServer*>(this);
98     else
99         return E_NOINTERFACE;
100
101     AddRef();
102     return S_OK;
103 }
104
105 ULONG STDMETHODCALLTYPE WebScriptDebugServer::AddRef()
106 {
107     return ++m_refCount;
108 }
109
110 ULONG STDMETHODCALLTYPE WebScriptDebugServer::Release()
111 {
112     ULONG newRef = --m_refCount;
113     if (!newRef)
114         delete(this);
115
116     return newRef;
117 }
118
119 // IWebScriptDebugServer -----------------------------------------------------------
120
121 HRESULT STDMETHODCALLTYPE WebScriptDebugServer::sharedWebScriptDebugServer( 
122     /* [retval][out] */ IWebScriptDebugServer** server)
123 {
124     if (!server)
125         return E_POINTER;
126
127     *server = WebScriptDebugServer::sharedWebScriptDebugServer();
128     (*server)->AddRef();
129
130     return S_OK;
131 }
132
133 HRESULT STDMETHODCALLTYPE WebScriptDebugServer::addListener(
134     /* [in] */ IWebScriptDebugListener* listener)
135 {
136     if (s_dying)
137         return E_FAIL;
138
139     if (!listener)
140         return E_POINTER;
141
142     if (!s_ListenerCount)
143         Page::setDebuggerForAllPages(&WebScriptDebugger::shared());
144
145     ++s_ListenerCount;
146     s_Listeners.add(listener);
147
148     return S_OK;
149 }
150
151 HRESULT STDMETHODCALLTYPE WebScriptDebugServer::removeListener(
152     /* [in] */ IWebScriptDebugListener* listener)
153 {
154     if (s_dying)
155         return S_OK;
156
157     if (!listener)
158         return E_POINTER;
159
160     if (!s_Listeners.contains(listener))
161         return S_OK;
162
163     s_Listeners.remove(listener);
164
165     ASSERT(s_ListenerCount >= 1);
166     if (--s_ListenerCount == 0) {
167         Page::setDebuggerForAllPages(0);
168         resume();
169     }
170
171     return S_OK;
172 }
173
174 HRESULT STDMETHODCALLTYPE WebScriptDebugServer::step()
175 {
176     m_step = true;
177     m_paused = false;
178
179     return S_OK;
180 }
181
182 HRESULT STDMETHODCALLTYPE WebScriptDebugServer::pause()
183 {
184     m_paused = true;
185     m_step = false;
186
187     return S_OK;
188 }
189
190 HRESULT STDMETHODCALLTYPE WebScriptDebugServer::resume()
191 {
192     m_paused = false;
193     m_step = false;
194
195     return S_OK;
196 }
197
198 HRESULT STDMETHODCALLTYPE WebScriptDebugServer::isPaused(
199     /* [out, retval] */ BOOL* isPaused)
200 {
201     if (!isPaused)
202         return E_POINTER;
203
204     *isPaused = m_paused;
205     return S_OK;
206 }
207
208 static HWND comMessageWindow()
209 {
210     static bool initialized;
211     static HWND window;
212
213     if (initialized)
214         return window;
215     initialized = true;
216
217     static LPCTSTR windowClass = TEXT("OleMainThreadWndClass");
218     static LPCTSTR windowText = TEXT("OleMainThreadWndName");
219     static const DWORD currentProcess = GetCurrentProcessId();
220
221     window = 0;
222     DWORD windowProcess = 0;
223     do {
224         window = FindWindowEx(HWND_MESSAGE, window, windowClass, windowText);
225         GetWindowThreadProcessId(window, &windowProcess);
226     } while (window && windowProcess != currentProcess);
227
228     return window;
229 }
230
231 void WebScriptDebugServer::suspendProcessIfPaused()
232 {
233     static bool alreadyHere = false;
234
235     if (alreadyHere)
236         return;
237
238     alreadyHere = true;
239
240     // We only deliver messages to COM's message window to pause the process while still allowing RPC to work.
241     // FIXME: It would be nice if we could keep delivering WM_[NC]PAINT messages to all windows to keep them painting on XP.
242
243     HWND messageWindow = comMessageWindow();
244
245     MSG msg;
246     while (m_paused && GetMessage(&msg, messageWindow, 0, 0)) {
247         TranslateMessage(&msg);
248         DispatchMessage(&msg);
249     }
250
251     if (m_step) {
252         m_step = false;
253         m_paused = true;
254     }
255
256     alreadyHere = false;
257 }
258
259 // IWebScriptDebugListener
260 HRESULT STDMETHODCALLTYPE WebScriptDebugServer::didLoadMainResourceForDataSource(
261     /* [in] */ IWebView* webView,
262     /* [in] */ IWebDataSource* dataSource)
263 {
264     if (!webView || !dataSource)
265         return E_FAIL;
266
267     ListenerSet listenersCopy = s_Listeners;
268     ListenerSet::iterator end = listenersCopy.end();
269     for (ListenerSet::iterator it = listenersCopy.begin(); it != end; ++it)
270         (**it).didLoadMainResourceForDataSource(webView, dataSource);
271
272     return S_OK;
273 }
274
275 HRESULT STDMETHODCALLTYPE WebScriptDebugServer::didParseSource(
276     /* [in] */ IWebView* webView,
277     /* [in] */ BSTR sourceCode,
278     /* [in] */ UINT baseLineNumber,
279     /* [in] */ BSTR url,
280     /* [in] */ int sourceID,
281     /* [in] */ IWebFrame* webFrame)
282 {
283     if (!webView || !sourceCode || !url || !webFrame)
284         return E_FAIL;
285
286     ListenerSet listenersCopy = s_Listeners;
287     ListenerSet::iterator end = listenersCopy.end();
288     for (ListenerSet::iterator it = listenersCopy.begin(); it != end; ++it)
289         (**it).didParseSource(webView, sourceCode, baseLineNumber, url, sourceID, webFrame);
290
291     return S_OK;
292 }
293
294 HRESULT STDMETHODCALLTYPE WebScriptDebugServer::failedToParseSource(
295     /* [in] */ IWebView* webView,
296     /* [in] */ BSTR sourceCode,
297     /* [in] */ UINT baseLineNumber,
298     /* [in] */ BSTR url,
299     /* [in] */ BSTR error,
300     /* [in] */ IWebFrame* webFrame)
301 {
302     if (!webView || !sourceCode || !url || !error || !webFrame)
303         return E_FAIL;
304
305     ListenerSet listenersCopy = s_Listeners;
306     ListenerSet::iterator end = listenersCopy.end();
307     for (ListenerSet::iterator it = listenersCopy.begin(); it != end; ++it)
308         (**it).failedToParseSource(webView, sourceCode, baseLineNumber, url, error, webFrame);
309
310     return S_OK;
311 }
312
313 HRESULT STDMETHODCALLTYPE WebScriptDebugServer::didEnterCallFrame(
314     /* [in] */ IWebView* webView,
315     /* [in] */ IWebScriptCallFrame* frame,
316     /* [in] */ int sourceID,
317     /* [in] */ int lineNumber,
318     /* [in] */ IWebFrame* webFrame)
319 {
320     if (!webView || !frame || !webFrame)
321         return E_FAIL;
322
323     ListenerSet listenersCopy = s_Listeners;
324     ListenerSet::iterator end = listenersCopy.end();
325     for (ListenerSet::iterator it = listenersCopy.begin(); it != end; ++it)
326         (**it).didEnterCallFrame(webView, frame, sourceID, lineNumber, webFrame);
327
328     suspendProcessIfPaused();
329
330     return S_OK;
331 }
332
333 HRESULT STDMETHODCALLTYPE WebScriptDebugServer::willExecuteStatement(
334     /* [in] */ IWebView* webView,
335     /* [in] */ IWebScriptCallFrame* frame,
336     /* [in] */ int sourceID,
337     /* [in] */ int lineNumber,
338     /* [in] */ IWebFrame* webFrame)
339 {
340     if (!webView || !frame || !webFrame)
341         return E_FAIL;
342
343     ListenerSet listenersCopy = s_Listeners;
344     ListenerSet::iterator end = listenersCopy.end();
345     for (ListenerSet::iterator it = listenersCopy.begin(); it != end; ++it)
346         (**it).willExecuteStatement(webView, frame, sourceID, lineNumber, webFrame);
347
348     suspendProcessIfPaused();
349
350     return S_OK;
351 }
352
353 HRESULT STDMETHODCALLTYPE WebScriptDebugServer::willLeaveCallFrame(
354     /* [in] */ IWebView* webView,
355     /* [in] */ IWebScriptCallFrame* frame,
356     /* [in] */ int sourceID,
357     /* [in] */ int lineNumber,
358     /* [in] */ IWebFrame* webFrame)
359 {
360     if (!webView || !frame || !webFrame)
361         return E_FAIL;
362
363     ListenerSet listenersCopy = s_Listeners;
364     ListenerSet::iterator end = listenersCopy.end();
365     for (ListenerSet::iterator it = listenersCopy.begin(); it != end; ++it)
366         (**it).willLeaveCallFrame(webView, frame, sourceID, lineNumber, webFrame);
367
368     suspendProcessIfPaused();
369
370     return S_OK;
371 }
372
373 HRESULT STDMETHODCALLTYPE WebScriptDebugServer::exceptionWasRaised(
374     /* [in] */ IWebView* webView,
375     /* [in] */ IWebScriptCallFrame* frame,
376     /* [in] */ int sourceID,
377     /* [in] */ int lineNumber,
378     /* [in] */ IWebFrame* webFrame)
379 {
380     if (!webView || !frame || !webFrame)
381         return E_FAIL;
382
383     ListenerSet listenersCopy = s_Listeners;
384     ListenerSet::iterator end = listenersCopy.end();
385     for (ListenerSet::iterator it = listenersCopy.begin(); it != end; ++it)
386         (**it).exceptionWasRaised(webView, frame, sourceID, lineNumber, webFrame);
387
388     suspendProcessIfPaused();
389
390     return S_OK;
391 }
392
393 HRESULT STDMETHODCALLTYPE WebScriptDebugServer::serverDidDie()
394 {
395     s_dying = true;
396
397     ListenerSet listenersCopy = s_Listeners;
398     ListenerSet::iterator end = listenersCopy.end();
399     for (ListenerSet::iterator it = listenersCopy.begin(); it != end; ++it) {
400         (**it).serverDidDie();
401         s_Listeners.remove((*it).get());
402     }
403
404     return S_OK;
405 }