b21d34e6746655485f8e2c22f3c14c736251a9aa
[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/WebKit.h>
41 #include <wtf/Vector.h>
42 #include <stdio.h>
43 #include <string>
44
45 using std::string;
46
47 static FrameLoadDelegate* g_delegateWaitingOnTimer;
48
49 string BSTRtoString(BSTR bstr)
50 {
51     int result = WideCharToMultiByte(CP_UTF8, 0, bstr, SysStringLen(bstr) + 1, 0, 0, 0, 0);
52     Vector<char> utf8Vector(result);
53     result = WideCharToMultiByte(CP_UTF8, 0, bstr, SysStringLen(bstr) + 1, utf8Vector.data(), result, 0, 0);
54     if (!result)
55         return string();
56
57     return string(utf8Vector.data(), utf8Vector.size() - 1);
58 }
59
60 string descriptionSuitableForTestResult(IWebFrame* webFrame)
61 {
62     COMPtr<IWebView> webView;
63     if (FAILED(webFrame->webView(&webView)))
64         return string();
65
66     COMPtr<IWebFrame> mainFrame;
67     if (FAILED(webView->mainFrame(&mainFrame)))
68         return string();
69
70     if (webFrame == mainFrame)
71         return "main frame";
72
73     BSTR frameNameBSTR;
74     if (FAILED(webFrame->name(&frameNameBSTR)))
75         return string();
76
77     string frameName = "frame \"" + BSTRtoString(frameNameBSTR) + "\"";
78     SysFreeString(frameNameBSTR);
79
80     return frameName;
81 }
82
83 FrameLoadDelegate::FrameLoadDelegate()
84     : m_refCount(1)
85     , m_gcController(new GCController)
86 {
87 }
88
89 FrameLoadDelegate::~FrameLoadDelegate()
90 {
91 }
92
93 HRESULT STDMETHODCALLTYPE FrameLoadDelegate::QueryInterface(REFIID riid, void** ppvObject)
94 {
95     *ppvObject = 0;
96     if (IsEqualGUID(riid, IID_IUnknown))
97         *ppvObject = static_cast<IWebFrameLoadDelegate*>(this);
98     else if (IsEqualGUID(riid, IID_IWebFrameLoadDelegate))
99         *ppvObject = static_cast<IWebFrameLoadDelegate*>(this);
100     else if (IsEqualGUID(riid, IID_IWebFrameLoadDelegate2))
101         *ppvObject = static_cast<IWebFrameLoadDelegate*>(this);
102     else if (IsEqualGUID(riid, IID_IWebFrameLoadDelegatePrivate))
103         *ppvObject = static_cast<IWebFrameLoadDelegatePrivate*>(this);
104     else
105         return E_NOINTERFACE;
106
107     AddRef();
108     return S_OK;
109 }
110
111 ULONG STDMETHODCALLTYPE FrameLoadDelegate::AddRef(void)
112 {
113     return ++m_refCount;
114 }
115
116 ULONG STDMETHODCALLTYPE FrameLoadDelegate::Release(void)
117 {
118     ULONG newRef = --m_refCount;
119     if (!newRef)
120         delete(this);
121
122     return newRef;
123 }
124
125
126 HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didStartProvisionalLoadForFrame( 
127         /* [in] */ IWebView* webView,
128         /* [in] */ IWebFrame* frame) 
129 {
130     if (!done && layoutTestController->dumpFrameLoadCallbacks())
131         printf("%s - didStartProvisionalLoadForFrame\n",
132                 descriptionSuitableForTestResult(frame).c_str());
133
134     // Make sure we only set this once per test.  If it gets cleared, and then set again, we might
135     // end up doing two dumps for one test.
136     if (!topLoadingFrame && !done)
137         topLoadingFrame = frame;
138
139     return S_OK; 
140 }
141
142 HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didFailProvisionalLoadWithError( 
143     /* [in] */ IWebView *webView,
144     /* [in] */ IWebError *error,
145     /* [in] */ IWebFrame *frame)
146 {
147     if (!done && layoutTestController->dumpFrameLoadCallbacks())
148         printf("%s - didFailProvisionalLoadWithError\n",
149                 descriptionSuitableForTestResult(frame).c_str());
150
151     return S_OK;
152 }
153
154 HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didCommitLoadForFrame( 
155     /* [in] */ IWebView *webView,
156     /* [in] */ IWebFrame *frame)
157 {
158     COMPtr<IWebViewPrivate> webViewPrivate;
159     HRESULT hr = webView->QueryInterface(&webViewPrivate);
160     if (FAILED(hr))
161         return hr;
162     webViewPrivate->updateFocusedAndActiveState();
163
164     if (!done && layoutTestController->dumpFrameLoadCallbacks())
165         printf("%s - didCommitLoadForFrame\n",
166                 descriptionSuitableForTestResult(frame).c_str());
167
168
169     return S_OK;
170 }
171
172 HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didReceiveTitle( 
173         /* [in] */ IWebView *webView,
174         /* [in] */ BSTR title,
175         /* [in] */ IWebFrame *frame)
176 {
177     if (::layoutTestController->dumpTitleChanges() && !done)
178         printf("TITLE CHANGED: %S\n", title ? title : L"");
179     return S_OK;
180 }
181
182 void FrameLoadDelegate::processWork()
183 {
184     // quit doing work once a load is in progress
185     while (!topLoadingFrame && WorkQueue::shared()->count()) {
186         WorkQueueItem* item = WorkQueue::shared()->dequeue();
187         ASSERT(item);
188         item->invoke();
189     }
190
191     // if we didn't start a new load, then we finished all the commands, so we're ready to dump state
192     if (!topLoadingFrame && !::layoutTestController->waitToDump())
193         dump();
194 }
195
196 static void CALLBACK processWorkTimer(HWND, UINT, UINT_PTR id, DWORD)
197 {
198     ::KillTimer(0, id);
199     FrameLoadDelegate* d = g_delegateWaitingOnTimer;
200     g_delegateWaitingOnTimer = 0;
201     d->processWork();
202 }
203
204 void FrameLoadDelegate::locationChangeDone(IWebError*, IWebFrame* frame)
205 {
206     if (frame != topLoadingFrame)
207         return;
208
209     topLoadingFrame = 0;
210     WorkQueue::shared()->setFrozen(true);
211
212     if (::layoutTestController->waitToDump())
213         return;
214
215     if (WorkQueue::shared()->count()) {
216         ASSERT(!g_delegateWaitingOnTimer);
217         g_delegateWaitingOnTimer = this;
218         ::SetTimer(0, 0, 0, processWorkTimer);
219         return;
220     }
221
222     dump();
223 }
224
225 HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didFinishLoadForFrame( 
226         /* [in] */ IWebView* webView,
227         /* [in] */ IWebFrame* frame)
228 {
229     if (!done && layoutTestController->dumpFrameLoadCallbacks())
230         printf("%s - didFinishLoadForFrame\n",
231                 descriptionSuitableForTestResult(frame).c_str());
232
233     locationChangeDone(0, frame);
234     return S_OK;
235 }
236
237 HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didFailLoadWithError( 
238     /* [in] */ IWebView* webView,
239     /* [in] */ IWebError* error,
240     /* [in] */ IWebFrame* forFrame)
241 {
242     locationChangeDone(error, forFrame);
243     return S_OK;
244 }
245
246 HRESULT STDMETHODCALLTYPE FrameLoadDelegate::willCloseFrame( 
247         /* [in] */ IWebView *webView,
248         /* [in] */ IWebFrame *frame)
249 {
250     return E_NOTIMPL;
251 }
252
253 HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didClearWindowObject( 
254         /* [in] */ IWebView*webView,
255         /* [in] */ JSContextRef context,
256         /* [in] */ JSObjectRef windowObject,
257         /* [in] */ IWebFrame* frame)
258 {
259     JSValueRef exception = 0;
260
261     ::layoutTestController->makeWindowObject(context, windowObject, &exception);
262     ASSERT(!exception);
263
264     m_gcController->makeWindowObject(context, windowObject, &exception);
265     ASSERT(!exception);
266
267     JSStringRef eventSenderStr = JSStringCreateWithUTF8CString("eventSender");
268     JSValueRef eventSender = makeEventSender(context);
269     JSObjectSetProperty(context, windowObject, eventSenderStr, eventSender, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete, 0);
270     JSStringRelease(eventSenderStr);
271
272     return S_OK;
273 }
274
275 HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didFinishDocumentLoadForFrame( 
276     /* [in] */ IWebView *sender,
277     /* [in] */ IWebFrame *frame)
278 {
279     if (!done && layoutTestController->dumpFrameLoadCallbacks())
280         printf("%s - didFinishDocumentLoadForFrame\n",
281                 descriptionSuitableForTestResult(frame).c_str());
282
283     return S_OK;
284 }
285
286 HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didHandleOnloadEventsForFrame( 
287     /* [in] */ IWebView *sender,
288     /* [in] */ IWebFrame *frame)
289 {
290     if (!done && layoutTestController->dumpFrameLoadCallbacks())
291         printf("%s - didHandleOnloadEventsForFrame\n",
292                 descriptionSuitableForTestResult(frame).c_str());
293
294     return S_OK;
295 }
296