Rubber stamped by Niko.
[WebKit-https.git] / WebKitTools / DumpRenderTree / win / FrameLoadDelegate.cpp
1 /*
2  * Copyright (C) 2005, 2006, 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  *
8  * 1.  Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer. 
10  * 2.  Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution. 
13  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14  *     its contributors may be used to endorse or promote products derived
15  *     from this software without specific prior written permission. 
16  *
17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #include "DumpRenderTree.h"
30 #include "FrameLoadDelegate.h"
31
32 #include "EventSender.h"
33 #include "GCController.h"
34 #include "LayoutTestController.h"
35 #include "WorkQueueItem.h"
36 #include "WorkQueue.h"
37 #include <WebCore/COMPtr.h>
38 #include <JavaScriptCore/Assertions.h>
39 #include <JavaScriptCore/JavaScriptCore.h>
40 #include <WebKit/IWebFramePrivate.h>
41 #include <WebKit/IWebViewPrivate.h>
42 #include <wtf/Vector.h>
43 #include <stdio.h>
44 #include <string>
45
46 using std::string;
47
48 static FrameLoadDelegate* g_delegateWaitingOnTimer;
49
50 string BSTRtoString(BSTR bstr)
51 {
52     int result = WideCharToMultiByte(CP_UTF8, 0, bstr, SysStringLen(bstr) + 1, 0, 0, 0, 0);
53     Vector<char> utf8Vector(result);
54     result = WideCharToMultiByte(CP_UTF8, 0, bstr, SysStringLen(bstr) + 1, utf8Vector.data(), result, 0, 0);
55     if (!result)
56         return string();
57
58     return string(utf8Vector.data(), utf8Vector.size() - 1);
59 }
60
61 string descriptionSuitableForTestResult(IWebFrame* webFrame)
62 {
63     COMPtr<IWebView> webView;
64     if (FAILED(webFrame->webView(&webView)))
65         return string();
66
67     COMPtr<IWebFrame> mainFrame;
68     if (FAILED(webView->mainFrame(&mainFrame)))
69         return string();
70
71     if (webFrame == mainFrame)
72         return "main frame";
73
74     BSTR frameNameBSTR;
75     if (FAILED(webFrame->name(&frameNameBSTR)))
76         return string();
77
78     string frameName = "frame \"" + BSTRtoString(frameNameBSTR) + "\"";
79     SysFreeString(frameNameBSTR);
80
81     return frameName;
82 }
83
84 FrameLoadDelegate::FrameLoadDelegate()
85     : m_refCount(1)
86     , m_gcController(new GCController)
87 {
88 }
89
90 FrameLoadDelegate::~FrameLoadDelegate()
91 {
92 }
93
94 HRESULT STDMETHODCALLTYPE FrameLoadDelegate::QueryInterface(REFIID riid, void** ppvObject)
95 {
96     *ppvObject = 0;
97     if (IsEqualGUID(riid, IID_IUnknown))
98         *ppvObject = static_cast<IWebFrameLoadDelegate*>(this);
99     else if (IsEqualGUID(riid, IID_IWebFrameLoadDelegate))
100         *ppvObject = static_cast<IWebFrameLoadDelegate*>(this);
101     else if (IsEqualGUID(riid, IID_IWebFrameLoadDelegate2))
102         *ppvObject = static_cast<IWebFrameLoadDelegate*>(this);
103     else if (IsEqualGUID(riid, IID_IWebFrameLoadDelegatePrivate))
104         *ppvObject = static_cast<IWebFrameLoadDelegatePrivate*>(this);
105     else
106         return E_NOINTERFACE;
107
108     AddRef();
109     return S_OK;
110 }
111
112 ULONG STDMETHODCALLTYPE FrameLoadDelegate::AddRef(void)
113 {
114     return ++m_refCount;
115 }
116
117 ULONG STDMETHODCALLTYPE FrameLoadDelegate::Release(void)
118 {
119     ULONG newRef = --m_refCount;
120     if (!newRef)
121         delete(this);
122
123     return newRef;
124 }
125
126
127 HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didStartProvisionalLoadForFrame( 
128         /* [in] */ IWebView* webView,
129         /* [in] */ IWebFrame* frame) 
130 {
131     if (!done && layoutTestController->dumpFrameLoadCallbacks())
132         printf("%s - didStartProvisionalLoadForFrame\n",
133                 descriptionSuitableForTestResult(frame).c_str());
134
135     // Make sure we only set this once per test.  If it gets cleared, and then set again, we might
136     // end up doing two dumps for one test.
137     if (!topLoadingFrame && !done)
138         topLoadingFrame = frame;
139
140     return S_OK; 
141 }
142
143 HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didFailProvisionalLoadWithError( 
144     /* [in] */ IWebView *webView,
145     /* [in] */ IWebError *error,
146     /* [in] */ IWebFrame *frame)
147 {
148     if (!done && layoutTestController->dumpFrameLoadCallbacks())
149         printf("%s - didFailProvisionalLoadWithError\n",
150                 descriptionSuitableForTestResult(frame).c_str());
151
152     return S_OK;
153 }
154
155 HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didCommitLoadForFrame( 
156     /* [in] */ IWebView *webView,
157     /* [in] */ IWebFrame *frame)
158 {
159     COMPtr<IWebViewPrivate> webViewPrivate;
160     HRESULT hr = webView->QueryInterface(&webViewPrivate);
161     if (FAILED(hr))
162         return hr;
163     webViewPrivate->updateActiveState();
164
165     if (!done && layoutTestController->dumpFrameLoadCallbacks())
166         printf("%s - didCommitLoadForFrame\n",
167                 descriptionSuitableForTestResult(frame).c_str());
168
169
170     return S_OK;
171 }
172
173 HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didReceiveTitle( 
174         /* [in] */ IWebView *webView,
175         /* [in] */ BSTR title,
176         /* [in] */ IWebFrame *frame)
177 {
178     if (::layoutTestController->dumpTitleChanges() && !done)
179         printf("TITLE CHANGED: %S\n", title ? title : L"");
180     return S_OK;
181 }
182
183 void FrameLoadDelegate::processWork()
184 {
185     // quit doing work once a load is in progress
186     while (!topLoadingFrame && WorkQueue::shared()->count()) {
187         WorkQueueItem* item = WorkQueue::shared()->dequeue();
188         ASSERT(item);
189         item->invoke();
190     }
191
192     // if we didn't start a new load, then we finished all the commands, so we're ready to dump state
193     if (!topLoadingFrame && !::layoutTestController->waitToDump())
194         dump();
195 }
196
197 static void CALLBACK processWorkTimer(HWND, UINT, UINT_PTR id, DWORD)
198 {
199     ::KillTimer(0, id);
200     FrameLoadDelegate* d = g_delegateWaitingOnTimer;
201     g_delegateWaitingOnTimer = 0;
202     d->processWork();
203 }
204
205 void FrameLoadDelegate::locationChangeDone(IWebError*, IWebFrame* frame)
206 {
207     if (frame != topLoadingFrame)
208         return;
209
210     topLoadingFrame = 0;
211     WorkQueue::shared()->setFrozen(true);
212
213     if (::layoutTestController->waitToDump())
214         return;
215
216     if (WorkQueue::shared()->count()) {
217         ASSERT(!g_delegateWaitingOnTimer);
218         g_delegateWaitingOnTimer = this;
219         ::SetTimer(0, 0, 0, processWorkTimer);
220         return;
221     }
222
223     dump();
224 }
225
226 HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didFinishLoadForFrame( 
227         /* [in] */ IWebView* webView,
228         /* [in] */ IWebFrame* frame)
229 {
230     if (!done && layoutTestController->dumpFrameLoadCallbacks())
231         printf("%s - didFinishLoadForFrame\n",
232                 descriptionSuitableForTestResult(frame).c_str());
233
234     locationChangeDone(0, frame);
235     return S_OK;
236 }
237
238 HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didFailLoadWithError( 
239     /* [in] */ IWebView* webView,
240     /* [in] */ IWebError* error,
241     /* [in] */ IWebFrame* forFrame)
242 {
243     locationChangeDone(error, forFrame);
244     return S_OK;
245 }
246
247 HRESULT STDMETHODCALLTYPE FrameLoadDelegate::willCloseFrame( 
248         /* [in] */ IWebView *webView,
249         /* [in] */ IWebFrame *frame)
250 {
251     if (!done && layoutTestController->dumpFrameLoadCallbacks())
252         printf("%s - willCloseFrame\n",
253                 descriptionSuitableForTestResult(frame).c_str());
254
255     return S_OK;
256 }
257
258 HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didClearWindowObject( 
259         /* [in] */ IWebView*webView,
260         /* [in] */ JSContextRef context,
261         /* [in] */ JSObjectRef windowObject,
262         /* [in] */ IWebFrame* frame)
263 {
264     if (!done && layoutTestController->dumpFrameLoadCallbacks())
265         printf("%s - didClearWindowObjectForFrame\n",
266                 descriptionSuitableForTestResult(frame).c_str());
267
268     JSValueRef exception = 0;
269
270     ::layoutTestController->makeWindowObject(context, windowObject, &exception);
271     ASSERT(!exception);
272
273     m_gcController->makeWindowObject(context, windowObject, &exception);
274     ASSERT(!exception);
275
276     JSStringRef eventSenderStr = JSStringCreateWithUTF8CString("eventSender");
277     JSValueRef eventSender = makeEventSender(context);
278     JSObjectSetProperty(context, windowObject, eventSenderStr, eventSender, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete, 0);
279     JSStringRelease(eventSenderStr);
280
281     return S_OK;
282 }
283
284 HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didFinishDocumentLoadForFrame( 
285     /* [in] */ IWebView *sender,
286     /* [in] */ IWebFrame *frame)
287 {
288     if (!done && layoutTestController->dumpFrameLoadCallbacks())
289         printf("%s - didFinishDocumentLoadForFrame\n",
290                 descriptionSuitableForTestResult(frame).c_str());
291
292     return S_OK;
293 }
294
295 HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didHandleOnloadEventsForFrame( 
296     /* [in] */ IWebView *sender,
297     /* [in] */ IWebFrame *frame)
298 {
299     if (!done && layoutTestController->dumpFrameLoadCallbacks())
300         printf("%s - didHandleOnloadEventsForFrame\n",
301                 descriptionSuitableForTestResult(frame).c_str());
302
303     return S_OK;
304 }
305