[Win] Various DumpRenderTree Fixes.
[WebKit-https.git] / Tools / DumpRenderTree / win / FrameLoadDelegate.cpp
1 /*
2  * Copyright (C) 2005, 2006, 2007, 2009, 2014 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 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 <comutil.h>
35 #include "DumpRenderTree.h"
36 #include "EventSender.h"
37 #include "GCController.h"
38 #include "TestRunner.h"
39 #include "TextInputController.h"
40 #include "WebCoreTestSupport.h"
41 #include "WorkQueueItem.h"
42 #include "WorkQueue.h"
43 #include <WebCore/COMPtr.h>
44 #include <JavaScriptCore/JavaScriptCore.h>
45 #include <WebKit/WebKit.h>
46 #include <stdio.h>
47 #include <string>
48 #include <wtf/Assertions.h>
49 #include <wtf/NeverDestroyed.h>
50 #include <wtf/Vector.h>
51
52 using std::string;
53
54 static FrameLoadDelegate* g_delegateWaitingOnTimer;
55
56 string descriptionSuitableForTestResult(IWebFrame* webFrame)
57 {
58     COMPtr<IWebView> webView;
59     if (FAILED(webFrame->webView(&webView)))
60         return string();
61
62     COMPtr<IWebFrame> mainFrame;
63     if (FAILED(webView->mainFrame(&mainFrame)))
64         return string();
65
66     _bstr_t frameNameBSTR;
67     if (FAILED(webFrame->name(&frameNameBSTR.GetBSTR())) || !frameNameBSTR.length())
68         return (webFrame == mainFrame) ? "main frame" : string();
69
70     string frameName = (webFrame == mainFrame) ? "main frame" : "frame";
71     frameName += " \"" + toUTF8(frameNameBSTR) + "\""; 
72
73     return frameName;
74 }
75
76 FrameLoadDelegate::FrameLoadDelegate()
77     : m_refCount(1)
78     , m_gcController(std::make_unique<GCController>())
79     , m_accessibilityController(std::make_unique<AccessibilityController>())
80     , m_textInputController(std::make_unique<TextInputController>())
81 {
82 }
83
84 FrameLoadDelegate::~FrameLoadDelegate()
85 {
86 }
87
88 HRESULT FrameLoadDelegate::QueryInterface(REFIID riid, void** ppvObject)
89 {
90     *ppvObject = 0;
91     if (IsEqualGUID(riid, IID_IUnknown))
92         *ppvObject = static_cast<IWebFrameLoadDelegate*>(this);
93     else if (IsEqualGUID(riid, IID_IWebFrameLoadDelegate))
94         *ppvObject = static_cast<IWebFrameLoadDelegate*>(this);
95     else if (IsEqualGUID(riid, IID_IWebFrameLoadDelegatePrivate))
96         *ppvObject = static_cast<IWebFrameLoadDelegatePrivate*>(this);
97     else if (IsEqualGUID(riid, IID_IWebFrameLoadDelegatePrivate2))
98         *ppvObject = static_cast<IWebFrameLoadDelegatePrivate2*>(this);
99     else
100         return E_NOINTERFACE;
101
102     AddRef();
103     return S_OK;
104 }
105
106 ULONG FrameLoadDelegate::AddRef(void)
107 {
108     return ++m_refCount;
109 }
110
111 ULONG FrameLoadDelegate::Release(void)
112 {
113     ULONG newRef = --m_refCount;
114     if (!newRef)
115         delete(this);
116
117     return newRef;
118 }
119
120
121 HRESULT FrameLoadDelegate::didStartProvisionalLoadForFrame(IWebView* /*webView*/, IWebFrame* frame)
122 {
123     if (!done && gTestRunner->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 FrameLoadDelegate::didReceiveServerRedirectForProvisionalLoadForFrame(IWebView* /*webView*/, IWebFrame* frame)
135
136     if (!done && gTestRunner->dumpFrameLoadCallbacks())
137         printf("%s - didReceiveServerRedirectForProvisionalLoadForFrame\n", descriptionSuitableForTestResult(frame).c_str());
138
139     return S_OK;
140 }
141
142 HRESULT FrameLoadDelegate::didFailProvisionalLoadWithError(IWebView* /*webView*/, IWebError* error, IWebFrame* frame)
143 {
144     if (!done && gTestRunner->dumpFrameLoadCallbacks())
145         printf("%s - didFailProvisionalLoadWithError\n", descriptionSuitableForTestResult(frame).c_str());
146
147     locationChangeDone(error, frame);
148     return S_OK;
149 }
150
151 HRESULT FrameLoadDelegate::didCommitLoadForFrame(IWebView* webView, IWebFrame* frame)
152 {
153     if (!done && gTestRunner->dumpFrameLoadCallbacks())
154         printf("%s - didCommitLoadForFrame\n", descriptionSuitableForTestResult(frame).c_str());
155
156     COMPtr<IWebViewPrivate> webViewPrivate;
157     HRESULT hr = webView->QueryInterface(&webViewPrivate);
158     if (FAILED(hr))
159         return hr;
160     webViewPrivate->updateFocusedAndActiveState();
161
162     return S_OK;
163 }
164
165 HRESULT FrameLoadDelegate::didReceiveTitle(IWebView* /*webView*/, BSTR title, IWebFrame* frame)
166 {
167     if (!done && gTestRunner->dumpFrameLoadCallbacks())
168         printf("%s - didReceiveTitle: %S\n", descriptionSuitableForTestResult(frame).c_str(), title);
169
170     if (::gTestRunner->dumpTitleChanges() && !done)
171         printf("TITLE CHANGED: '%S'\n", title ? title : L"");
172     return S_OK;
173 }
174
175 HRESULT FrameLoadDelegate::didChangeIcons(
176     /* [in] */ IWebView* webView,
177     /* [in] */ IWebFrame* frame)
178 {
179     if (!done && gTestRunner->dumpIconChanges())
180         printf("%s - didChangeIcons\n", descriptionSuitableForTestResult(frame).c_str());
181
182     return S_OK;
183 }
184
185 void FrameLoadDelegate::processWork()
186 {
187     // if another load started, then wait for it to complete.
188     if (topLoadingFrame)
189         return;
190
191     // if we finish all the commands, we're ready to dump state
192     if (WorkQueue::shared()->processWork() && !::gTestRunner->waitToDump())
193         dump();
194 }
195
196 void FrameLoadDelegate::resetToConsistentState()
197 {
198     m_accessibilityController->resetToConsistentState();
199 }
200
201 typedef Vector<COMPtr<FrameLoadDelegate> > DelegateVector;
202 static DelegateVector& delegatesWithDelayedWork()
203 {
204     static NeverDestroyed<DelegateVector> delegates;
205     return delegates;
206 }
207
208 static UINT_PTR processWorkTimerID;
209
210 static void CALLBACK processWorkTimer(HWND hwnd, UINT, UINT_PTR id, DWORD)
211 {
212     ASSERT_ARG(id, id == processWorkTimerID);
213     ::KillTimer(hwnd, id);
214     processWorkTimerID = 0;
215
216     DelegateVector delegates;
217     delegates.swap(delegatesWithDelayedWork());
218
219     for (size_t i = 0; i < delegates.size(); ++i)
220         delegates[i]->processWork();
221 }
222
223 void FrameLoadDelegate::locationChangeDone(IWebError*, IWebFrame* frame)
224 {
225     if (frame != topLoadingFrame)
226         return;
227
228     topLoadingFrame = 0;
229     WorkQueue::shared()->setFrozen(true);
230
231     if (::gTestRunner->waitToDump())
232         return;
233
234     if (WorkQueue::shared()->count()) {
235         if (!processWorkTimerID)
236             processWorkTimerID = ::SetTimer(0, 0, 0, processWorkTimer);
237         delegatesWithDelayedWork().append(this);
238         return;
239     }
240
241     dump();
242 }
243
244 HRESULT FrameLoadDelegate::didFinishLoadForFrame(IWebView* /*webView*/, IWebFrame* frame)
245 {
246     if (!done && gTestRunner->dumpFrameLoadCallbacks())
247         printf("%s - didFinishLoadForFrame\n", descriptionSuitableForTestResult(frame).c_str());
248
249     locationChangeDone(0, frame);
250     return S_OK;
251 }
252
253 HRESULT FrameLoadDelegate::didFailLoadWithError(IWebView* /*webView*/, IWebError* error, IWebFrame* frame)
254 {
255     if (!done && gTestRunner->dumpFrameLoadCallbacks())
256         printf("%s - didFailLoadWithError\n", descriptionSuitableForTestResult(frame).c_str());
257
258     locationChangeDone(error, frame);
259     return S_OK;
260 }
261
262 HRESULT FrameLoadDelegate::willPerformClientRedirectToURL(IWebView* /*webView*/, BSTR url, double /*delaySeconds*/, DATE /*fireDate*/, IWebFrame* frame)
263 {
264     if (!done && gTestRunner->dumpFrameLoadCallbacks())
265         printf("%s - willPerformClientRedirectToURL: %S \n", descriptionSuitableForTestResult(frame).c_str(),
266                 urlSuitableForTestResult(std::wstring(url, ::SysStringLen(url))).c_str());
267
268     return S_OK;
269 }
270
271 HRESULT FrameLoadDelegate::didCancelClientRedirectForFrame(IWebView* /*webView*/, IWebFrame* frame)
272 {
273     if (!done && gTestRunner->dumpFrameLoadCallbacks())
274         printf("%s - didCancelClientRedirectForFrame\n", descriptionSuitableForTestResult(frame).c_str());
275
276     return S_OK;
277 }
278
279
280 HRESULT FrameLoadDelegate::willCloseFrame(IWebView* /*webView*/, IWebFrame* /*frame*/)
281 {
282     return E_NOTIMPL;
283 }
284
285 HRESULT FrameLoadDelegate::didClearWindowObject(IWebView*, JSContextRef, JSObjectRef, IWebFrame*)
286 {
287     return E_NOTIMPL;
288 }
289
290 HRESULT FrameLoadDelegate::didClearWindowObjectForFrameInScriptWorld(IWebView* webView, IWebFrame* frame, IWebScriptWorld* world)
291 {
292     ASSERT_ARG(webView, webView);
293     ASSERT_ARG(frame, frame);
294     ASSERT_ARG(world, world);
295     if (!webView || !frame || !world)
296         return E_POINTER;
297
298     COMPtr<IWebScriptWorld> standardWorld;
299     if (FAILED(world->standardWorld(&standardWorld)))
300         return S_OK;
301
302     if (world == standardWorld)
303         didClearWindowObjectForFrameInStandardWorld(frame);
304     else
305         didClearWindowObjectForFrameInIsolatedWorld(frame, world);
306     return S_OK;
307 }
308
309 void FrameLoadDelegate::didClearWindowObjectForFrameInIsolatedWorld(IWebFrame* frame, IWebScriptWorld* world)
310 {
311     COMPtr<IWebFramePrivate> framePrivate(Query, frame);
312     if (!framePrivate)
313         return;
314
315     JSGlobalContextRef ctx = framePrivate->globalContextForScriptWorld(world);
316     if (!ctx)
317         return;
318
319     JSObjectRef globalObject = JSContextGetGlobalObject(ctx);
320     if (!globalObject)
321         return;
322
323     JSObjectSetProperty(ctx, globalObject, JSRetainPtr<JSStringRef>(Adopt, JSStringCreateWithUTF8CString("__worldID")).get(), JSValueMakeNumber(ctx, worldIDForWorld(world)), kJSPropertyAttributeReadOnly, 0);
324     return;
325 }
326
327 void FrameLoadDelegate::didClearWindowObjectForFrameInStandardWorld(IWebFrame* frame)
328 {
329     JSGlobalContextRef context = frame->globalContext();
330     JSObjectRef windowObject = JSContextGetGlobalObject(context);
331
332     IWebFrame* parentFrame = 0;
333     frame->parentFrame(&parentFrame);
334
335     JSValueRef exception = 0;
336
337     ::gTestRunner->makeWindowObject(context, windowObject, &exception);
338     ASSERT(!exception);
339
340     m_gcController->makeWindowObject(context, windowObject, &exception);
341     ASSERT(!exception);
342
343     m_accessibilityController->makeWindowObject(context, windowObject, &exception);
344     ASSERT(!exception);
345
346     m_textInputController->makeWindowObject(context, windowObject, &exception);
347     ASSERT(!exception);
348
349     JSStringRef eventSenderStr = JSStringCreateWithUTF8CString("eventSender");
350     JSValueRef eventSender = makeEventSender(context, !parentFrame);
351     JSObjectSetProperty(context, windowObject, eventSenderStr, eventSender, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete, 0);
352     JSStringRelease(eventSenderStr);
353
354     WebCoreTestSupport::injectInternalsObject(context);
355 }
356
357 HRESULT FrameLoadDelegate::didFinishDocumentLoadForFrame(IWebView* /*sender*/, IWebFrame* frame)
358 {
359     if (!done && gTestRunner->dumpFrameLoadCallbacks())
360         printf("%s - didFinishDocumentLoadForFrame\n",
361                 descriptionSuitableForTestResult(frame).c_str());
362     if (!done) {
363         COMPtr<IWebFramePrivate> webFramePrivate;
364         HRESULT hr = frame->QueryInterface(&webFramePrivate);
365         if (FAILED(hr))
366             return hr;
367         unsigned pendingFrameUnloadEvents;
368         hr = webFramePrivate->pendingFrameUnloadEventCount(&pendingFrameUnloadEvents);
369         if (FAILED(hr))
370             return hr;
371         if (pendingFrameUnloadEvents)
372             printf("%s - has %u onunload handler(s)\n",
373                     descriptionSuitableForTestResult(frame).c_str(), pendingFrameUnloadEvents);
374     }
375
376     return S_OK;
377 }
378
379 HRESULT FrameLoadDelegate::didHandleOnloadEventsForFrame(IWebView* /*sender*/, IWebFrame* frame)
380 {
381     if (!done && gTestRunner->dumpFrameLoadCallbacks())
382         printf("%s - didHandleOnloadEventsForFrame\n",
383                 descriptionSuitableForTestResult(frame).c_str());
384
385     return S_OK;
386 }
387
388 HRESULT FrameLoadDelegate::didFirstVisuallyNonEmptyLayoutInFrame(IWebView* /*sender*/, IWebFrame* /*frame*/)
389 {
390     return S_OK;
391 }
392
393 HRESULT FrameLoadDelegate::didDisplayInsecureContent(IWebView* /*sender*/)
394 {
395     if (!done && gTestRunner->dumpFrameLoadCallbacks())
396         printf("didDisplayInsecureContent\n");
397
398     return S_OK;
399 }
400
401 HRESULT FrameLoadDelegate::didRunInsecureContent(IWebView* /*sender*/, IWebSecurityOrigin* /*origin*/)
402 {
403     if (!done && gTestRunner->dumpFrameLoadCallbacks())
404         printf("didRunInsecureContent\n");
405
406     return S_OK;
407 }