2011-06-04 Dominic Cooney <dominicc@chromium.org>
[WebKit-https.git] / Tools / DumpRenderTree / win / FrameLoadDelegate.cpp
1 /*
2  * Copyright (C) 2005, 2006, 2007, 2009 Apple Inc. All rights reserved.
3  * Copyright (C) 2010 Torch Mobile (Beijing) Co. Ltd. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1.  Redistributions of source code must retain the above copyright
10  *     notice, this list of conditions and the following disclaimer. 
11  * 2.  Redistributions in binary form must reproduce the above copyright
12  *     notice, this list of conditions and the following disclaimer in the
13  *     documentation and/or other materials provided with the distribution. 
14  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
15  *     its contributors may be used to endorse or promote products derived
16  *     from this software without specific prior written permission. 
17  *
18  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
19  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
22  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 #include "config.h"
31 #include "FrameLoadDelegate.h"
32
33 #include "AccessibilityController.h"
34 #include "DumpRenderTree.h"
35 #include "EventSender.h"
36 #include "GCController.h"
37 #include "LayoutTestController.h"
38 #include "WebCoreTestSupport.h"
39 #include "WorkQueueItem.h"
40 #include "WorkQueue.h"
41 #include <WebCore/COMPtr.h>
42 #include <JavaScriptCore/Assertions.h>
43 #include <JavaScriptCore/JavaScriptCore.h>
44 #include <WebKit/WebKit.h>
45 #include <stdio.h>
46 #include <string>
47 #include <wtf/PassOwnPtr.h>
48 #include <wtf/Vector.h>
49
50 using std::string;
51
52 static FrameLoadDelegate* g_delegateWaitingOnTimer;
53
54 string descriptionSuitableForTestResult(IWebFrame* webFrame)
55 {
56     COMPtr<IWebView> webView;
57     if (FAILED(webFrame->webView(&webView)))
58         return string();
59
60     COMPtr<IWebFrame> mainFrame;
61     if (FAILED(webView->mainFrame(&mainFrame)))
62         return string();
63
64     BSTR frameNameBSTR;
65     if (FAILED(webFrame->name(&frameNameBSTR)) || toUTF8(frameNameBSTR).empty())
66         return (webFrame == mainFrame) ? "main frame" : string();
67
68     string frameName = (webFrame == mainFrame) ? "main frame" : "frame";
69     frameName += " \"" + toUTF8(frameNameBSTR) + "\""; 
70
71     SysFreeString(frameNameBSTR); 
72     return frameName;
73 }
74
75 FrameLoadDelegate::FrameLoadDelegate()
76     : m_refCount(1)
77     , m_gcController(adoptPtr(new GCController))
78     , m_accessibilityController(adoptPtr(new AccessibilityController))
79 {
80 }
81
82 FrameLoadDelegate::~FrameLoadDelegate()
83 {
84 }
85
86 HRESULT STDMETHODCALLTYPE FrameLoadDelegate::QueryInterface(REFIID riid, void** ppvObject)
87 {
88     *ppvObject = 0;
89     if (IsEqualGUID(riid, IID_IUnknown))
90         *ppvObject = static_cast<IWebFrameLoadDelegate*>(this);
91     else if (IsEqualGUID(riid, IID_IWebFrameLoadDelegate))
92         *ppvObject = static_cast<IWebFrameLoadDelegate*>(this);
93     else if (IsEqualGUID(riid, IID_IWebFrameLoadDelegatePrivate))
94         *ppvObject = static_cast<IWebFrameLoadDelegatePrivate*>(this);
95     else if (IsEqualGUID(riid, IID_IWebFrameLoadDelegatePrivate2))
96         *ppvObject = static_cast<IWebFrameLoadDelegatePrivate2*>(this);
97     else
98         return E_NOINTERFACE;
99
100     AddRef();
101     return S_OK;
102 }
103
104 ULONG STDMETHODCALLTYPE FrameLoadDelegate::AddRef(void)
105 {
106     return ++m_refCount;
107 }
108
109 ULONG STDMETHODCALLTYPE FrameLoadDelegate::Release(void)
110 {
111     ULONG newRef = --m_refCount;
112     if (!newRef)
113         delete(this);
114
115     return newRef;
116 }
117
118
119 HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didStartProvisionalLoadForFrame( 
120     /* [in] */ IWebView* webView,
121     /* [in] */ IWebFrame* frame) 
122 {
123     if (!done && gLayoutTestController->dumpFrameLoadCallbacks())
124         printf("%s - didStartProvisionalLoadForFrame\n", descriptionSuitableForTestResult(frame).c_str());
125
126     // Make sure we only set this once per test.  If it gets cleared, and then set again, we might
127     // end up doing two dumps for one test.
128     if (!topLoadingFrame && !done)
129         topLoadingFrame = frame;
130
131     return S_OK; 
132 }
133
134 HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didReceiveServerRedirectForProvisionalLoadForFrame( 
135     /* [in] */ IWebView *webView,
136     /* [in] */ IWebFrame *frame)
137
138     if (!done && gLayoutTestController->dumpFrameLoadCallbacks())
139         printf("%s - didReceiveServerRedirectForProvisionalLoadForFrame\n", descriptionSuitableForTestResult(frame).c_str());
140
141     return S_OK;
142 }
143
144 HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didFailProvisionalLoadWithError( 
145     /* [in] */ IWebView *webView,
146     /* [in] */ IWebError *error,
147     /* [in] */ IWebFrame *frame)
148 {
149     if (!done && gLayoutTestController->dumpFrameLoadCallbacks())
150         printf("%s - didFailProvisionalLoadWithError\n", descriptionSuitableForTestResult(frame).c_str());
151
152     locationChangeDone(error, frame);
153     return S_OK;
154 }
155
156 HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didCommitLoadForFrame( 
157     /* [in] */ IWebView *webView,
158     /* [in] */ IWebFrame *frame)
159 {
160     if (!done && gLayoutTestController->dumpFrameLoadCallbacks())
161         printf("%s - didCommitLoadForFrame\n", descriptionSuitableForTestResult(frame).c_str());
162
163     COMPtr<IWebViewPrivate> webViewPrivate;
164     HRESULT hr = webView->QueryInterface(&webViewPrivate);
165     if (FAILED(hr))
166         return hr;
167     webViewPrivate->updateFocusedAndActiveState();
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 (!done && gLayoutTestController->dumpFrameLoadCallbacks())
178         printf("%s - didReceiveTitle: %S\n", descriptionSuitableForTestResult(frame).c_str(), title);
179
180     if (::gLayoutTestController->dumpTitleChanges() && !done)
181         printf("TITLE CHANGED: %S\n", title ? title : L"");
182     return S_OK;
183 }
184
185 HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didChangeIcons(
186     /* [in] */ IWebView* webView,
187     /* [in] */ IWebFrame* frame)
188 {
189     if (!done && gLayoutTestController->dumpIconChanges())
190         printf("%s - didChangeIcons\n", descriptionSuitableForTestResult(frame).c_str());
191
192     return S_OK;
193 }
194
195 void FrameLoadDelegate::processWork()
196 {
197     // if another load started, then wait for it to complete.
198     if (topLoadingFrame)
199         return;
200
201     // if we finish all the commands, we're ready to dump state
202     if (WorkQueue::shared()->processWork() && !::gLayoutTestController->waitToDump())
203         dump();
204 }
205
206 void FrameLoadDelegate::resetToConsistentState()
207 {
208     m_accessibilityController->resetToConsistentState();
209 }
210
211 typedef Vector<COMPtr<FrameLoadDelegate> > DelegateVector;
212 static DelegateVector& delegatesWithDelayedWork()
213 {
214     DEFINE_STATIC_LOCAL(DelegateVector, delegates, ());
215     return delegates;
216 }
217
218 static UINT_PTR processWorkTimerID;
219
220 static void CALLBACK processWorkTimer(HWND hwnd, UINT, UINT_PTR id, DWORD)
221 {
222     ASSERT_ARG(id, id == processWorkTimerID);
223     ::KillTimer(hwnd, id);
224     processWorkTimerID = 0;
225
226     DelegateVector delegates;
227     delegates.swap(delegatesWithDelayedWork());
228
229     for (size_t i = 0; i < delegates.size(); ++i)
230         delegates[i]->processWork();
231 }
232
233 void FrameLoadDelegate::locationChangeDone(IWebError*, IWebFrame* frame)
234 {
235     if (frame != topLoadingFrame)
236         return;
237
238     topLoadingFrame = 0;
239     WorkQueue::shared()->setFrozen(true);
240
241     if (::gLayoutTestController->waitToDump())
242         return;
243
244     if (WorkQueue::shared()->count()) {
245         if (!processWorkTimerID)
246             processWorkTimerID = ::SetTimer(0, 0, 0, processWorkTimer);
247         delegatesWithDelayedWork().append(this);
248         return;
249     }
250
251     dump();
252 }
253
254 HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didFinishLoadForFrame( 
255     /* [in] */ IWebView* webView,
256     /* [in] */ IWebFrame* frame)
257 {
258     if (!done && gLayoutTestController->dumpFrameLoadCallbacks())
259         printf("%s - didFinishLoadForFrame\n", descriptionSuitableForTestResult(frame).c_str());
260
261     locationChangeDone(0, frame);
262     return S_OK;
263 }
264
265 HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didFailLoadWithError( 
266     /* [in] */ IWebView* webView,
267     /* [in] */ IWebError* error,
268     /* [in] */ IWebFrame* frame)
269 {
270     if (!done && gLayoutTestController->dumpFrameLoadCallbacks())
271         printf("%s - didFailLoadWithError\n", descriptionSuitableForTestResult(frame).c_str());
272
273     locationChangeDone(error, frame);
274     return S_OK;
275 }
276
277 HRESULT STDMETHODCALLTYPE FrameLoadDelegate::willPerformClientRedirectToURL( 
278     /* [in] */ IWebView *webView,
279     /* [in] */ BSTR url,  
280     /* [in] */ double delaySeconds,
281     /* [in] */ DATE fireDate,
282     /* [in] */ IWebFrame *frame)
283 {
284     if (!done && gLayoutTestController->dumpFrameLoadCallbacks())
285         printf("%s - willPerformClientRedirectToURL: %S \n", descriptionSuitableForTestResult(frame).c_str(),
286                 urlSuitableForTestResult(std::wstring(url, ::SysStringLen(url))).c_str());
287
288     return S_OK;
289 }
290
291 HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didCancelClientRedirectForFrame( 
292     /* [in] */ IWebView *webView,
293     /* [in] */ IWebFrame *frame)
294 {
295     if (!done && gLayoutTestController->dumpFrameLoadCallbacks())
296         printf("%s - didCancelClientRedirectForFrame\n", descriptionSuitableForTestResult(frame).c_str());
297
298     return S_OK;
299 }
300
301
302 HRESULT STDMETHODCALLTYPE FrameLoadDelegate::willCloseFrame( 
303     /* [in] */ IWebView *webView,
304     /* [in] */ IWebFrame *frame)
305 {
306     return E_NOTIMPL;
307 }
308
309 HRESULT FrameLoadDelegate::didClearWindowObject(IWebView*, JSContextRef, JSObjectRef, IWebFrame*)
310 {
311     return E_NOTIMPL;
312 }
313
314 HRESULT FrameLoadDelegate::didClearWindowObjectForFrameInScriptWorld(IWebView* webView, IWebFrame* frame, IWebScriptWorld* world)
315 {
316     ASSERT_ARG(webView, webView);
317     ASSERT_ARG(frame, frame);
318     ASSERT_ARG(world, world);
319     if (!webView || !frame || !world)
320         return E_POINTER;
321
322     COMPtr<IWebScriptWorld> standardWorld;
323     if (FAILED(world->standardWorld(&standardWorld)))
324         return S_OK;
325
326     if (world == standardWorld)
327         didClearWindowObjectForFrameInStandardWorld(frame);
328     else
329         didClearWindowObjectForFrameInIsolatedWorld(frame, world);
330     return S_OK;
331 }
332
333 void FrameLoadDelegate::didClearWindowObjectForFrameInIsolatedWorld(IWebFrame* frame, IWebScriptWorld* world)
334 {
335     COMPtr<IWebFramePrivate> framePrivate(Query, frame);
336     if (!framePrivate)
337         return;
338
339     JSGlobalContextRef ctx = framePrivate->globalContextForScriptWorld(world);
340     if (!ctx)
341         return;
342
343     JSObjectRef globalObject = JSContextGetGlobalObject(ctx);
344     if (!globalObject)
345         return;
346
347     JSObjectSetProperty(ctx, globalObject, JSRetainPtr<JSStringRef>(Adopt, JSStringCreateWithUTF8CString("__worldID")).get(), JSValueMakeNumber(ctx, worldIDForWorld(world)), kJSPropertyAttributeReadOnly, 0);
348     return;
349 }
350
351 void FrameLoadDelegate::didClearWindowObjectForFrameInStandardWorld(IWebFrame* frame)
352 {
353     JSGlobalContextRef context = frame->globalContext();
354     JSObjectRef windowObject = JSContextGetGlobalObject(context);
355
356     IWebFrame* parentFrame = 0;
357     frame->parentFrame(&parentFrame);
358
359     JSValueRef exception = 0;
360
361     ::gLayoutTestController->makeWindowObject(context, windowObject, &exception);
362     ASSERT(!exception);
363
364     m_gcController->makeWindowObject(context, windowObject, &exception);
365     ASSERT(!exception);
366
367     m_accessibilityController->makeWindowObject(context, windowObject, &exception);
368     ASSERT(!exception);
369
370     JSStringRef eventSenderStr = JSStringCreateWithUTF8CString("eventSender");
371     JSValueRef eventSender = makeEventSender(context, !parentFrame);
372     JSObjectSetProperty(context, windowObject, eventSenderStr, eventSender, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete, 0);
373     JSStringRelease(eventSenderStr);
374
375     WebCoreTestSupport::injectInternalsObject(context);
376 }
377
378 HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didFinishDocumentLoadForFrame( 
379     /* [in] */ IWebView *sender,
380     /* [in] */ IWebFrame *frame)
381 {
382     if (!done && gLayoutTestController->dumpFrameLoadCallbacks())
383         printf("%s - didFinishDocumentLoadForFrame\n",
384                 descriptionSuitableForTestResult(frame).c_str());
385     if (!done) {
386         COMPtr<IWebFramePrivate> webFramePrivate;
387         HRESULT hr = frame->QueryInterface(&webFramePrivate);
388         if (FAILED(hr))
389             return hr;
390         unsigned pendingFrameUnloadEvents;
391         hr = webFramePrivate->pendingFrameUnloadEventCount(&pendingFrameUnloadEvents);
392         if (FAILED(hr))
393             return hr;
394         if (pendingFrameUnloadEvents)
395             printf("%s - has %u onunload handler(s)\n",
396                     descriptionSuitableForTestResult(frame).c_str(), pendingFrameUnloadEvents);
397     }
398
399     return S_OK;
400 }
401
402 HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didHandleOnloadEventsForFrame( 
403     /* [in] */ IWebView *sender,
404     /* [in] */ IWebFrame *frame)
405 {
406     if (!done && gLayoutTestController->dumpFrameLoadCallbacks())
407         printf("%s - didHandleOnloadEventsForFrame\n",
408                 descriptionSuitableForTestResult(frame).c_str());
409
410     return S_OK;
411 }
412
413 HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didFirstVisuallyNonEmptyLayoutInFrame( 
414     /* [in] */ IWebView *sender,
415     /* [in] */ IWebFrame *frame)
416 {
417     return S_OK;
418 }
419
420 HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didDisplayInsecureContent( 
421     /* [in] */ IWebView *sender)
422 {
423     if (!done && gLayoutTestController->dumpFrameLoadCallbacks())
424         printf("didDisplayInsecureContent\n");
425
426     return S_OK;
427 }
428
429 HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didRunInsecureContent( 
430     /* [in] */ IWebView *sender,
431     /* [in] */ IWebSecurityOrigin *origin)
432 {
433     if (!done && gLayoutTestController->dumpFrameLoadCallbacks())
434         printf("didRunInsecureContent\n");
435
436     return S_OK;
437 }
438