2 * Copyright (C) 2005, 2006, 2007, 2009 Apple Inc. All rights reserved.
3 * Copyright (C) 2010 Torch Mobile (Beijing) Co. Ltd. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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.
31 #include "FrameLoadDelegate.h"
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>
47 #include <wtf/PassOwnPtr.h>
48 #include <wtf/Vector.h>
52 static FrameLoadDelegate* g_delegateWaitingOnTimer;
54 string descriptionSuitableForTestResult(IWebFrame* webFrame)
56 COMPtr<IWebView> webView;
57 if (FAILED(webFrame->webView(&webView)))
60 COMPtr<IWebFrame> mainFrame;
61 if (FAILED(webView->mainFrame(&mainFrame)))
65 if (FAILED(webFrame->name(&frameNameBSTR)) || toUTF8(frameNameBSTR).empty())
66 return (webFrame == mainFrame) ? "main frame" : string();
68 string frameName = (webFrame == mainFrame) ? "main frame" : "frame";
69 frameName += " \"" + toUTF8(frameNameBSTR) + "\"";
71 SysFreeString(frameNameBSTR);
75 FrameLoadDelegate::FrameLoadDelegate()
77 , m_gcController(adoptPtr(new GCController))
78 , m_accessibilityController(adoptPtr(new AccessibilityController))
82 FrameLoadDelegate::~FrameLoadDelegate()
86 HRESULT STDMETHODCALLTYPE FrameLoadDelegate::QueryInterface(REFIID riid, void** ppvObject)
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);
104 ULONG STDMETHODCALLTYPE FrameLoadDelegate::AddRef(void)
109 ULONG STDMETHODCALLTYPE FrameLoadDelegate::Release(void)
111 ULONG newRef = --m_refCount;
119 HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didStartProvisionalLoadForFrame(
120 /* [in] */ IWebView* webView,
121 /* [in] */ IWebFrame* frame)
123 if (!done && gLayoutTestController->dumpFrameLoadCallbacks())
124 printf("%s - didStartProvisionalLoadForFrame\n", descriptionSuitableForTestResult(frame).c_str());
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;
134 HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didReceiveServerRedirectForProvisionalLoadForFrame(
135 /* [in] */ IWebView *webView,
136 /* [in] */ IWebFrame *frame)
138 if (!done && gLayoutTestController->dumpFrameLoadCallbacks())
139 printf("%s - didReceiveServerRedirectForProvisionalLoadForFrame\n", descriptionSuitableForTestResult(frame).c_str());
144 HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didFailProvisionalLoadWithError(
145 /* [in] */ IWebView *webView,
146 /* [in] */ IWebError *error,
147 /* [in] */ IWebFrame *frame)
149 if (!done && gLayoutTestController->dumpFrameLoadCallbacks())
150 printf("%s - didFailProvisionalLoadWithError\n", descriptionSuitableForTestResult(frame).c_str());
152 locationChangeDone(error, frame);
156 HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didCommitLoadForFrame(
157 /* [in] */ IWebView *webView,
158 /* [in] */ IWebFrame *frame)
160 if (!done && gLayoutTestController->dumpFrameLoadCallbacks())
161 printf("%s - didCommitLoadForFrame\n", descriptionSuitableForTestResult(frame).c_str());
163 COMPtr<IWebViewPrivate> webViewPrivate;
164 HRESULT hr = webView->QueryInterface(&webViewPrivate);
167 webViewPrivate->updateFocusedAndActiveState();
172 HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didReceiveTitle(
173 /* [in] */ IWebView *webView,
174 /* [in] */ BSTR title,
175 /* [in] */ IWebFrame *frame)
177 if (!done && gLayoutTestController->dumpFrameLoadCallbacks())
178 printf("%s - didReceiveTitle: %S\n", descriptionSuitableForTestResult(frame).c_str(), title);
180 if (::gLayoutTestController->dumpTitleChanges() && !done)
181 printf("TITLE CHANGED: %S\n", title ? title : L"");
185 HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didChangeIcons(
186 /* [in] */ IWebView* webView,
187 /* [in] */ IWebFrame* frame)
189 if (!done && gLayoutTestController->dumpIconChanges())
190 printf("%s - didChangeIcons\n", descriptionSuitableForTestResult(frame).c_str());
195 void FrameLoadDelegate::processWork()
197 // if another load started, then wait for it to complete.
201 // if we finish all the commands, we're ready to dump state
202 if (WorkQueue::shared()->processWork() && !::gLayoutTestController->waitToDump())
206 void FrameLoadDelegate::resetToConsistentState()
208 m_accessibilityController->resetToConsistentState();
211 typedef Vector<COMPtr<FrameLoadDelegate> > DelegateVector;
212 static DelegateVector& delegatesWithDelayedWork()
214 DEFINE_STATIC_LOCAL(DelegateVector, delegates, ());
218 static UINT_PTR processWorkTimerID;
220 static void CALLBACK processWorkTimer(HWND hwnd, UINT, UINT_PTR id, DWORD)
222 ASSERT_ARG(id, id == processWorkTimerID);
223 ::KillTimer(hwnd, id);
224 processWorkTimerID = 0;
226 DelegateVector delegates;
227 delegates.swap(delegatesWithDelayedWork());
229 for (size_t i = 0; i < delegates.size(); ++i)
230 delegates[i]->processWork();
233 void FrameLoadDelegate::locationChangeDone(IWebError*, IWebFrame* frame)
235 if (frame != topLoadingFrame)
239 WorkQueue::shared()->setFrozen(true);
241 if (::gLayoutTestController->waitToDump())
244 if (WorkQueue::shared()->count()) {
245 if (!processWorkTimerID)
246 processWorkTimerID = ::SetTimer(0, 0, 0, processWorkTimer);
247 delegatesWithDelayedWork().append(this);
254 HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didFinishLoadForFrame(
255 /* [in] */ IWebView* webView,
256 /* [in] */ IWebFrame* frame)
258 if (!done && gLayoutTestController->dumpFrameLoadCallbacks())
259 printf("%s - didFinishLoadForFrame\n", descriptionSuitableForTestResult(frame).c_str());
261 locationChangeDone(0, frame);
265 HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didFailLoadWithError(
266 /* [in] */ IWebView* webView,
267 /* [in] */ IWebError* error,
268 /* [in] */ IWebFrame* frame)
270 if (!done && gLayoutTestController->dumpFrameLoadCallbacks())
271 printf("%s - didFailLoadWithError\n", descriptionSuitableForTestResult(frame).c_str());
273 locationChangeDone(error, frame);
277 HRESULT STDMETHODCALLTYPE FrameLoadDelegate::willPerformClientRedirectToURL(
278 /* [in] */ IWebView *webView,
280 /* [in] */ double delaySeconds,
281 /* [in] */ DATE fireDate,
282 /* [in] */ IWebFrame *frame)
284 if (!done && gLayoutTestController->dumpFrameLoadCallbacks())
285 printf("%s - willPerformClientRedirectToURL: %S \n", descriptionSuitableForTestResult(frame).c_str(),
286 urlSuitableForTestResult(std::wstring(url, ::SysStringLen(url))).c_str());
291 HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didCancelClientRedirectForFrame(
292 /* [in] */ IWebView *webView,
293 /* [in] */ IWebFrame *frame)
295 if (!done && gLayoutTestController->dumpFrameLoadCallbacks())
296 printf("%s - didCancelClientRedirectForFrame\n", descriptionSuitableForTestResult(frame).c_str());
302 HRESULT STDMETHODCALLTYPE FrameLoadDelegate::willCloseFrame(
303 /* [in] */ IWebView *webView,
304 /* [in] */ IWebFrame *frame)
309 HRESULT FrameLoadDelegate::didClearWindowObject(IWebView*, JSContextRef, JSObjectRef, IWebFrame*)
314 HRESULT FrameLoadDelegate::didClearWindowObjectForFrameInScriptWorld(IWebView* webView, IWebFrame* frame, IWebScriptWorld* world)
316 ASSERT_ARG(webView, webView);
317 ASSERT_ARG(frame, frame);
318 ASSERT_ARG(world, world);
319 if (!webView || !frame || !world)
322 COMPtr<IWebScriptWorld> standardWorld;
323 if (FAILED(world->standardWorld(&standardWorld)))
326 if (world == standardWorld)
327 didClearWindowObjectForFrameInStandardWorld(frame);
329 didClearWindowObjectForFrameInIsolatedWorld(frame, world);
333 void FrameLoadDelegate::didClearWindowObjectForFrameInIsolatedWorld(IWebFrame* frame, IWebScriptWorld* world)
335 COMPtr<IWebFramePrivate> framePrivate(Query, frame);
339 JSGlobalContextRef ctx = framePrivate->globalContextForScriptWorld(world);
343 JSObjectRef globalObject = JSContextGetGlobalObject(ctx);
347 JSObjectSetProperty(ctx, globalObject, JSRetainPtr<JSStringRef>(Adopt, JSStringCreateWithUTF8CString("__worldID")).get(), JSValueMakeNumber(ctx, worldIDForWorld(world)), kJSPropertyAttributeReadOnly, 0);
351 void FrameLoadDelegate::didClearWindowObjectForFrameInStandardWorld(IWebFrame* frame)
353 JSGlobalContextRef context = frame->globalContext();
354 JSObjectRef windowObject = JSContextGetGlobalObject(context);
356 IWebFrame* parentFrame = 0;
357 frame->parentFrame(&parentFrame);
359 JSValueRef exception = 0;
361 ::gLayoutTestController->makeWindowObject(context, windowObject, &exception);
364 m_gcController->makeWindowObject(context, windowObject, &exception);
367 m_accessibilityController->makeWindowObject(context, windowObject, &exception);
370 JSStringRef eventSenderStr = JSStringCreateWithUTF8CString("eventSender");
371 JSValueRef eventSender = makeEventSender(context, !parentFrame);
372 JSObjectSetProperty(context, windowObject, eventSenderStr, eventSender, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete, 0);
373 JSStringRelease(eventSenderStr);
375 WebCoreTestSupport::injectInternalsObject(context);
378 HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didFinishDocumentLoadForFrame(
379 /* [in] */ IWebView *sender,
380 /* [in] */ IWebFrame *frame)
382 if (!done && gLayoutTestController->dumpFrameLoadCallbacks())
383 printf("%s - didFinishDocumentLoadForFrame\n",
384 descriptionSuitableForTestResult(frame).c_str());
386 COMPtr<IWebFramePrivate> webFramePrivate;
387 HRESULT hr = frame->QueryInterface(&webFramePrivate);
390 unsigned pendingFrameUnloadEvents;
391 hr = webFramePrivate->pendingFrameUnloadEventCount(&pendingFrameUnloadEvents);
394 if (pendingFrameUnloadEvents)
395 printf("%s - has %u onunload handler(s)\n",
396 descriptionSuitableForTestResult(frame).c_str(), pendingFrameUnloadEvents);
402 HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didHandleOnloadEventsForFrame(
403 /* [in] */ IWebView *sender,
404 /* [in] */ IWebFrame *frame)
406 if (!done && gLayoutTestController->dumpFrameLoadCallbacks())
407 printf("%s - didHandleOnloadEventsForFrame\n",
408 descriptionSuitableForTestResult(frame).c_str());
413 HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didFirstVisuallyNonEmptyLayoutInFrame(
414 /* [in] */ IWebView *sender,
415 /* [in] */ IWebFrame *frame)
420 HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didDisplayInsecureContent(
421 /* [in] */ IWebView *sender)
423 if (!done && gLayoutTestController->dumpFrameLoadCallbacks())
424 printf("didDisplayInsecureContent\n");
429 HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didRunInsecureContent(
430 /* [in] */ IWebView *sender,
431 /* [in] */ IWebSecurityOrigin *origin)
433 if (!done && gLayoutTestController->dumpFrameLoadCallbacks())
434 printf("didRunInsecureContent\n");