9d232ee16d48f2acae00869095d0949f85835b67
[WebKit-https.git] / Tools / WebKitTestRunner / InjectedBundle / InjectedBundlePage.cpp
1 /*
2  * Copyright (C) 2010, 2011, 2012 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  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "InjectedBundlePage.h"
28
29 #include "InjectedBundle.h"
30 #include "StringFunctions.h"
31 #include "WebCoreTestSupport.h"
32 #include <cmath>
33 #include <JavaScriptCore/JSRetainPtr.h>
34 #include <WebKit/WKArray.h>
35 #include <WebKit/WKBundle.h>
36 #include <WebKit/WKBundleBackForwardList.h>
37 #include <WebKit/WKBundleBackForwardListItem.h>
38 #include <WebKit/WKBundleFrame.h>
39 #include <WebKit/WKBundleFramePrivate.h>
40 #include <WebKit/WKBundleHitTestResult.h>
41 #include <WebKit/WKBundleNavigationAction.h>
42 #include <WebKit/WKBundleNavigationActionPrivate.h>
43 #include <WebKit/WKBundleNodeHandlePrivate.h>
44 #include <WebKit/WKBundlePagePrivate.h>
45 #include <WebKit/WKBundlePrivate.h>
46 #include <WebKit/WKSecurityOriginRef.h>
47 #include <WebKit/WKURLRequest.h>
48 #include <wtf/HashMap.h>
49 #include <wtf/text/CString.h>
50 #include <wtf/text/StringBuilder.h>
51
52 #if USE(CF)
53 #include "WebArchiveDumpSupport.h"
54 #endif
55
56 using namespace std;
57
58 namespace WTR {
59
60 static bool hasPrefix(const WTF::String& searchString, const WTF::String& prefix)
61 {
62     return searchString.length() >= prefix.length() && searchString.substring(0, prefix.length()) == prefix;
63 }
64
65 static JSValueRef propertyValue(JSContextRef context, JSObjectRef object, const char* propertyName)
66 {
67     if (!object)
68         return 0;
69     JSRetainPtr<JSStringRef> propertyNameString(Adopt, JSStringCreateWithUTF8CString(propertyName));
70     return JSObjectGetProperty(context, object, propertyNameString.get(), 0);
71 }
72
73 static double propertyValueDouble(JSContextRef context, JSObjectRef object, const char* propertyName)
74 {
75     JSValueRef value = propertyValue(context, object, propertyName);
76     if (!value)
77         return 0;
78     return JSValueToNumber(context, value, 0);    
79 }
80
81 static int propertyValueInt(JSContextRef context, JSObjectRef object, const char* propertyName)
82 {
83     return static_cast<int>(propertyValueDouble(context, object, propertyName));    
84 }
85
86 static double numericWindowPropertyValue(WKBundleFrameRef frame, const char* propertyName)
87 {
88     JSGlobalContextRef context = WKBundleFrameGetJavaScriptContext(frame);
89     return propertyValueDouble(context, JSContextGetGlobalObject(context), propertyName);
90 }
91
92 static WTF::String dumpPath(JSGlobalContextRef context, JSObjectRef nodeValue)
93 {
94     JSValueRef nodeNameValue = propertyValue(context, nodeValue, "nodeName");
95     JSRetainPtr<JSStringRef> jsStringNodeName(Adopt, JSValueToStringCopy(context, nodeNameValue, 0));
96     WKRetainPtr<WKStringRef> nodeName = toWK(jsStringNodeName);
97
98     JSValueRef parentNode = propertyValue(context, nodeValue, "parentNode");
99
100     StringBuilder stringBuilder;
101     stringBuilder.append(toWTFString(nodeName));
102
103     if (parentNode && JSValueIsObject(context, parentNode)) {
104         stringBuilder.appendLiteral(" > ");
105         stringBuilder.append(dumpPath(context, (JSObjectRef)parentNode));
106     }
107
108     return stringBuilder.toString();
109 }
110
111 static WTF::String dumpPath(WKBundlePageRef page, WKBundleScriptWorldRef world, WKBundleNodeHandleRef node)
112 {
113     if (!node)
114         return "(null)";
115
116     WKBundleFrameRef frame = WKBundlePageGetMainFrame(page);
117
118     JSGlobalContextRef context = WKBundleFrameGetJavaScriptContextForWorld(frame, world);
119     JSValueRef nodeValue = WKBundleFrameGetJavaScriptWrapperForNodeForWorld(frame, node, world);
120     ASSERT(JSValueIsObject(context, nodeValue));
121     JSObjectRef nodeObject = (JSObjectRef)nodeValue;
122
123     return dumpPath(context, nodeObject);
124 }
125
126 static WTF::String rangeToStr(WKBundlePageRef page, WKBundleScriptWorldRef world, WKBundleRangeHandleRef rangeRef)
127 {
128     if (!rangeRef)
129         return "(null)";
130  
131     WKBundleFrameRef frame = WKBundlePageGetMainFrame(page);
132
133     JSGlobalContextRef context = WKBundleFrameGetJavaScriptContextForWorld(frame, world);
134     JSValueRef rangeValue = WKBundleFrameGetJavaScriptWrapperForRangeForWorld(frame, rangeRef, world);
135     ASSERT(JSValueIsObject(context, rangeValue));
136     JSObjectRef rangeObject = (JSObjectRef)rangeValue;
137
138     JSValueRef startNodeValue = propertyValue(context, rangeObject, "startContainer");
139     ASSERT(JSValueIsObject(context, startNodeValue));
140     JSObjectRef startNodeObject = (JSObjectRef)startNodeValue;
141
142     JSValueRef endNodeValue = propertyValue(context, rangeObject, "endContainer");
143     ASSERT(JSValueIsObject(context, endNodeValue));
144     JSObjectRef endNodeObject = (JSObjectRef)endNodeValue;
145
146     int startOffset = propertyValueInt(context, rangeObject, "startOffset");
147     int endOffset = propertyValueInt(context, rangeObject, "endOffset");
148
149     StringBuilder stringBuilder;
150     stringBuilder.appendLiteral("range from ");
151     stringBuilder.appendNumber(startOffset);
152     stringBuilder.appendLiteral(" of ");
153     stringBuilder.append(dumpPath(context, startNodeObject));
154     stringBuilder.appendLiteral(" to ");
155     stringBuilder.appendNumber(endOffset);
156     stringBuilder.appendLiteral(" of ");
157     stringBuilder.append(dumpPath(context, endNodeObject));
158     return stringBuilder.toString();
159 }
160
161 static WKRetainPtr<WKStringRef> NavigationTypeToString(WKFrameNavigationType type)
162 {
163     switch (type) {
164     case kWKFrameNavigationTypeLinkClicked:
165         return adoptWK(WKStringCreateWithUTF8CString("link clicked"));
166     case kWKFrameNavigationTypeFormSubmitted:
167         return adoptWK(WKStringCreateWithUTF8CString("form submitted"));
168     case kWKFrameNavigationTypeBackForward:
169         return adoptWK(WKStringCreateWithUTF8CString("back/forward"));
170     case kWKFrameNavigationTypeReload:
171         return adoptWK(WKStringCreateWithUTF8CString("reload"));
172     case kWKFrameNavigationTypeFormResubmitted:
173         return adoptWK(WKStringCreateWithUTF8CString("form resubmitted"));
174     case kWKFrameNavigationTypeOther:
175         return adoptWK(WKStringCreateWithUTF8CString("other"));
176     }
177     return adoptWK(WKStringCreateWithUTF8CString("illegal value"));
178 }
179
180 static WTF::String styleDecToStr(WKBundleCSSStyleDeclarationRef style)
181 {
182     // DumpRenderTree calls -[DOMCSSStyleDeclaration description], which just dumps class name and object address.
183     // No existing tests actually hit this code path at the time of this writing, because WebCore doesn't call
184     // the editing client if the styling operation source is CommandFromDOM or CommandFromDOMWithUserInterface.
185     StringBuilder stringBuilder;
186     stringBuilder.appendLiteral("<DOMCSSStyleDeclaration ADDRESS>");
187     return stringBuilder.toString();
188 }
189
190 static WTF::String securityOriginToStr(WKSecurityOriginRef origin)
191 {
192     StringBuilder stringBuilder;
193     stringBuilder.append('{');
194     stringBuilder.append(toWTFString(adoptWK(WKSecurityOriginCopyProtocol(origin))));
195     stringBuilder.appendLiteral(", ");
196     stringBuilder.append(toWTFString(adoptWK(WKSecurityOriginCopyHost(origin))));
197     stringBuilder.appendLiteral(", ");
198     stringBuilder.appendNumber(WKSecurityOriginGetPort(origin));
199     stringBuilder.append('}');
200
201     return stringBuilder.toString();
202 }
203
204 static WTF::String frameToStr(WKBundleFrameRef frame)
205 {
206     WKRetainPtr<WKStringRef> name(AdoptWK, WKBundleFrameCopyName(frame));
207     StringBuilder stringBuilder;
208     if (WKBundleFrameIsMainFrame(frame)) {
209         if (!WKStringIsEmpty(name.get())) {
210             stringBuilder.appendLiteral("main frame \"");
211             stringBuilder.append(toWTFString(name));
212             stringBuilder.append('"');
213         } else
214             stringBuilder.appendLiteral("main frame");
215     } else {
216         if (!WKStringIsEmpty(name.get())) {
217             stringBuilder.appendLiteral("frame \"");
218             stringBuilder.append(toWTFString(name));
219             stringBuilder.append('"');
220         }
221         else
222             stringBuilder.appendLiteral("frame (anonymous)");
223     }
224     
225     return stringBuilder.toString();
226 }
227
228 static inline bool isLocalFileScheme(WKStringRef scheme)
229 {
230     return WKStringIsEqualToUTF8CStringIgnoringCase(scheme, "file");
231 }
232
233 static const char divider = '/';
234
235 static inline WTF::String pathSuitableForTestResult(WKURLRef fileUrl)
236 {
237     if (!fileUrl)
238         return "(null)";
239
240     WKRetainPtr<WKStringRef> schemeString = adoptWK(WKURLCopyScheme(fileUrl));
241     if (!isLocalFileScheme(schemeString.get()))
242         return toWTFString(adoptWK(WKURLCopyString(fileUrl)));
243
244     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
245     WKRetainPtr<WKURLRef> mainFrameURL = adoptWK(WKBundleFrameCopyURL(mainFrame));
246     if (!mainFrameURL)
247         mainFrameURL = adoptWK(WKBundleFrameCopyProvisionalURL(mainFrame));
248
249     String pathString = toWTFString(adoptWK(WKURLCopyPath(fileUrl)));
250     String mainFrameURLPathString = toWTFString(adoptWK(WKURLCopyPath(mainFrameURL.get())));
251     String basePath = mainFrameURLPathString.substring(0, mainFrameURLPathString.reverseFind(divider) + 1);
252     
253     if (!basePath.isEmpty() && pathString.startsWith(basePath))
254         return pathString.substring(basePath.length());
255     return toWTFString(adoptWK(WKURLCopyLastPathComponent(fileUrl))); // We lose some information here, but it's better than exposing a full path, which is always machine specific.
256 }
257
258 static HashMap<uint64_t, String> assignedUrlsCache;
259
260 static inline void dumpResourceURL(uint64_t identifier, StringBuilder& stringBuilder)
261 {
262     if (assignedUrlsCache.contains(identifier))
263         stringBuilder.append(assignedUrlsCache.get(identifier));
264     else
265         stringBuilder.appendLiteral("<unknown>");
266 }
267
268 InjectedBundlePage::InjectedBundlePage(WKBundlePageRef page)
269     : m_page(page)
270     , m_world(AdoptWK, WKBundleScriptWorldCreateWorld())
271 {
272     WKBundlePageLoaderClientV8 loaderClient = {
273         { 8, this },
274         didStartProvisionalLoadForFrame,
275         didReceiveServerRedirectForProvisionalLoadForFrame,
276         didFailProvisionalLoadWithErrorForFrame,
277         didCommitLoadForFrame,
278         didFinishDocumentLoadForFrame,
279         didFinishLoadForFrame,
280         didFailLoadWithErrorForFrame,
281         didSameDocumentNavigationForFrame,
282         didReceiveTitleForFrame,
283         0, // didFirstLayoutForFrame
284         0, // didFirstVisuallyNonEmptyLayoutForFrame
285         0, // didRemoveFrameFromHierarchy
286         didDisplayInsecureContentForFrame,
287         didRunInsecureContentForFrame,
288         didClearWindowForFrame,
289         didCancelClientRedirectForFrame,
290         willPerformClientRedirectForFrame,
291         didHandleOnloadEventsForFrame,
292         0, // didLayoutForFrame
293         0, // didNewFirstVisuallyNonEmptyLayout_unavailable
294         didDetectXSSForFrame,
295         0, // shouldGoToBackForwardListItem
296         0, // didCreateGlobalObjectForFrame
297         0, // willDisconnectDOMWindowExtensionFromGlobalObject
298         0, // didReconnectDOMWindowExtensionToGlobalObject
299         0, // willDestroyGlobalObjectForDOMWindowExtension
300         didFinishProgress, // didFinishProgress
301         0, // shouldForceUniversalAccessFromLocalURL
302         0, // didReceiveIntentForFrame
303         0, // registerIntentServiceForFrame
304         0, // didLayout
305         0, // featuresUsedInPage
306         0, // willLoadURLRequest
307         0, // willLoadDataRequest
308         0, // willDestroyFrame_unavailable
309         0, // userAgentForURL
310     };
311     WKBundlePageSetPageLoaderClient(m_page, &loaderClient.base);
312
313     WKBundlePageResourceLoadClientV1 resourceLoadClient = {
314         { 1, this },
315         didInitiateLoadForResource,
316         willSendRequestForFrame,
317         didReceiveResponseForResource,
318         didReceiveContentLengthForResource,
319         didFinishLoadForResource,
320         didFailLoadForResource,
321         shouldCacheResponse,
322         0 // shouldUseCredentialStorage
323     };
324     WKBundlePageSetResourceLoadClient(m_page, &resourceLoadClient.base);
325
326     WKBundlePagePolicyClientV0 policyClient = {
327         { 0, this },
328         decidePolicyForNavigationAction,
329         decidePolicyForNewWindowAction,
330         decidePolicyForResponse,
331         unableToImplementPolicy
332     };
333     WKBundlePageSetPolicyClient(m_page, &policyClient.base);
334
335     WKBundlePageUIClientV2 uiClient = {
336         { 2, this },
337         willAddMessageToConsole,
338         willSetStatusbarText,
339         willRunJavaScriptAlert,
340         willRunJavaScriptConfirm,
341         willRunJavaScriptPrompt,
342         0, /*mouseDidMoveOverElement*/
343         0, /*pageDidScroll*/
344         0, /*paintCustomOverhangArea*/
345         0, /*shouldGenerateFileForUpload*/
346         0, /*generateFileForUpload*/
347         0, /*shouldRubberBandInDirection*/
348         0, /*statusBarIsVisible*/
349         0, /*menuBarIsVisible*/
350         0, /*toolbarsAreVisible*/
351         didReachApplicationCacheOriginQuota,
352         didExceedDatabaseQuota,
353         0, /*plugInStartLabelTitle*/
354         0, /*plugInStartLabelSubtitle*/
355         0, /*plugInExtraStyleSheet*/
356         0, /*plugInExtraScript*/
357     };
358     WKBundlePageSetUIClient(m_page, &uiClient.base);
359
360     WKBundlePageEditorClientV1 editorClient = {
361         { 1, this },
362         shouldBeginEditing,
363         shouldEndEditing,
364         shouldInsertNode,
365         shouldInsertText,
366         shouldDeleteRange,
367         shouldChangeSelectedRange,
368         shouldApplyStyle,
369         didBeginEditing,
370         didEndEditing,
371         didChange,
372         didChangeSelection,
373         0, /* willWriteToPasteboard */
374         0, /* getPasteboardDataForRange */
375         0  /* didWriteToPasteboard */
376     };
377     WKBundlePageSetEditorClient(m_page, &editorClient.base);
378
379 #if ENABLE(FULLSCREEN_API)
380     WKBundlePageFullScreenClientV1 fullScreenClient = {
381         { 1, this },
382         supportsFullScreen,
383         enterFullScreenForElement,
384         exitFullScreenForElement,
385         beganEnterFullScreen,
386         beganExitFullScreen,
387         closeFullScreen,
388     };
389     WKBundlePageSetFullScreenClient(m_page, &fullScreenClient.base);
390 #endif
391 }
392
393 InjectedBundlePage::~InjectedBundlePage()
394 {
395 }
396
397 void InjectedBundlePage::stopLoading()
398 {
399     WKBundlePageStopLoading(m_page);
400 }
401
402 void InjectedBundlePage::prepare()
403 {
404     WKBundlePageClearMainFrameName(m_page);
405
406     WKBundlePageSetPageZoomFactor(m_page, 1);
407     WKBundlePageSetTextZoomFactor(m_page, 1);
408
409     WKPoint origin = { 0, 0 };
410     WKBundlePageSetScaleAtOrigin(m_page, 1, origin);
411
412     m_previousTestBackForwardListItem = adoptWK(WKBundleBackForwardListCopyItemAtIndex(WKBundlePageGetBackForwardList(m_page), 0));
413
414     WKBundleFrameClearOpener(WKBundlePageGetMainFrame(m_page));
415     
416     WKBundlePageSetTracksRepaints(m_page, false);
417 }
418
419 void InjectedBundlePage::resetAfterTest()
420 {
421     WKBundleFrameRef frame = WKBundlePageGetMainFrame(m_page);
422
423     // WebKit currently doesn't reset focus even when navigating to a new page. This may or may not be a bug
424     // (see <https://bugs.webkit.org/show_bug.cgi?id=138334>), however for tests, we want to start each one with a clean state.
425     WKBundleFrameFocus(frame);
426
427     JSGlobalContextRef context = WKBundleFrameGetJavaScriptContext(frame);
428     WebCoreTestSupport::resetInternalsObject(context);
429     assignedUrlsCache.clear();
430 }
431
432 // Loader Client Callbacks
433
434 // String output must be identical to -[WebFrame _drt_descriptionSuitableForTestResult].
435 static void dumpFrameDescriptionSuitableForTestResult(WKBundleFrameRef frame, StringBuilder& stringBuilder)
436 {
437     WKRetainPtr<WKStringRef> name(AdoptWK, WKBundleFrameCopyName(frame));
438     if (WKBundleFrameIsMainFrame(frame)) {
439         if (WKStringIsEmpty(name.get())) {
440             stringBuilder.appendLiteral("main frame");
441             return;
442         }
443
444         stringBuilder.appendLiteral("main frame \"");
445         stringBuilder.append(toWTFString(name));
446         stringBuilder.append('"');
447         return;
448     }
449
450     if (WKStringIsEmpty(name.get())) {
451         stringBuilder.appendLiteral("frame (anonymous)");
452         return;
453     }
454
455     stringBuilder.appendLiteral("frame \"");
456     stringBuilder.append(toWTFString(name));
457     stringBuilder.append('"');
458 }
459
460 static void dumpLoadEvent(WKBundleFrameRef frame, const char* eventName)
461 {
462     StringBuilder stringBuilder;
463     dumpFrameDescriptionSuitableForTestResult(frame, stringBuilder);
464     stringBuilder.appendLiteral(" - ");
465     stringBuilder.append(eventName);
466     stringBuilder.append('\n');
467     InjectedBundle::singleton().outputText(stringBuilder.toString());
468 }
469
470 static inline void dumpRequestDescriptionSuitableForTestResult(WKURLRequestRef request, StringBuilder& stringBuilder)
471 {
472     WKRetainPtr<WKURLRef> url = adoptWK(WKURLRequestCopyURL(request));
473     WKRetainPtr<WKURLRef> firstParty = adoptWK(WKURLRequestCopyFirstPartyForCookies(request));
474     WKRetainPtr<WKStringRef> httpMethod = adoptWK(WKURLRequestCopyHTTPMethod(request));
475
476     stringBuilder.appendLiteral("<NSURLRequest URL ");
477     stringBuilder.append(pathSuitableForTestResult(url.get()));
478     stringBuilder.appendLiteral(", main document URL ");
479     stringBuilder.append(pathSuitableForTestResult(firstParty.get()));
480     stringBuilder.appendLiteral(", http method ");
481
482     if (WKStringIsEmpty(httpMethod.get()))
483         stringBuilder.appendLiteral("(none)");
484     else
485         stringBuilder.append(toWTFString(httpMethod));
486
487     stringBuilder.append('>');
488 }
489
490 static inline void dumpResponseDescriptionSuitableForTestResult(WKURLResponseRef response, StringBuilder& stringBuilder)
491 {
492     WKRetainPtr<WKURLRef> url = adoptWK(WKURLResponseCopyURL(response));
493     if (!url) {
494         stringBuilder.appendLiteral("(null)");
495         return;
496     }
497     stringBuilder.appendLiteral("<NSURLResponse ");
498     stringBuilder.append(pathSuitableForTestResult(url.get()));
499     stringBuilder.appendLiteral(", http status code ");
500     stringBuilder.appendNumber(WKURLResponseHTTPStatusCode(response));
501     stringBuilder.append('>');
502 }
503
504 static inline void dumpErrorDescriptionSuitableForTestResult(WKErrorRef error, StringBuilder& stringBuilder)
505 {
506     WKRetainPtr<WKStringRef> errorDomain = adoptWK(WKErrorCopyDomain(error));
507     int errorCode = WKErrorGetErrorCode(error);
508
509     // We need to do some error mapping here to match the test expectations (Mac error names are expected).
510     if (WKStringIsEqualToUTF8CString(errorDomain.get(), "WebKitNetworkError")) {
511         errorDomain = adoptWK(WKStringCreateWithUTF8CString("NSURLErrorDomain"));
512         errorCode = -999;
513     }
514
515     if (WKStringIsEqualToUTF8CString(errorDomain.get(), "WebKitPolicyError"))
516         errorDomain = adoptWK(WKStringCreateWithUTF8CString("WebKitErrorDomain"));
517
518     stringBuilder.appendLiteral("<NSError domain ");
519     stringBuilder.append(toWTFString(errorDomain));
520     stringBuilder.appendLiteral(", code ");
521     stringBuilder.appendNumber(errorCode);
522
523     WKRetainPtr<WKURLRef> url = adoptWK(WKErrorCopyFailingURL(error));
524     if (url.get()) {
525         WKRetainPtr<WKStringRef> urlString = adoptWK(WKURLCopyString(url.get()));
526         stringBuilder.appendLiteral(", failing URL \"");
527         stringBuilder.append(toWTFString(urlString));
528         stringBuilder.append('"');
529     }
530
531     stringBuilder.append('>');
532 }
533
534 void InjectedBundlePage::didStartProvisionalLoadForFrame(WKBundlePageRef page, WKBundleFrameRef frame, WKTypeRef*, const void *clientInfo)
535 {
536     static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didStartProvisionalLoadForFrame(frame);
537 }
538
539 void InjectedBundlePage::didReceiveServerRedirectForProvisionalLoadForFrame(WKBundlePageRef page, WKBundleFrameRef frame, WKTypeRef*, const void *clientInfo)
540 {
541     static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didReceiveServerRedirectForProvisionalLoadForFrame(frame);
542 }
543
544 void InjectedBundlePage::didFailProvisionalLoadWithErrorForFrame(WKBundlePageRef page, WKBundleFrameRef frame, WKErrorRef error, WKTypeRef*, const void *clientInfo)
545 {
546     static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didFailProvisionalLoadWithErrorForFrame(frame, error);
547 }
548
549 void InjectedBundlePage::didCommitLoadForFrame(WKBundlePageRef page, WKBundleFrameRef frame, WKTypeRef*, const void *clientInfo)
550 {
551     static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didCommitLoadForFrame(frame);
552 }
553
554 void InjectedBundlePage::didFinishLoadForFrame(WKBundlePageRef page, WKBundleFrameRef frame, WKTypeRef*, const void *clientInfo)
555 {
556     static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didFinishLoadForFrame(frame);
557 }
558
559 void InjectedBundlePage::didFinishProgress(WKBundlePageRef, const void *clientInfo)
560 {
561     static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didFinishProgress();
562 }
563
564 void InjectedBundlePage::didFinishDocumentLoadForFrame(WKBundlePageRef page, WKBundleFrameRef frame, WKTypeRef*, const void* clientInfo)
565 {
566     static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didFinishDocumentLoadForFrame(frame);
567 }
568
569 void InjectedBundlePage::didFailLoadWithErrorForFrame(WKBundlePageRef page, WKBundleFrameRef frame, WKErrorRef error, WKTypeRef*, const void *clientInfo)
570 {
571     static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didFailLoadWithErrorForFrame(frame, error);
572 }
573
574 void InjectedBundlePage::didReceiveTitleForFrame(WKBundlePageRef page, WKStringRef title, WKBundleFrameRef frame, WKTypeRef*, const void *clientInfo)
575 {
576     static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didReceiveTitleForFrame(title, frame);
577 }
578
579 void InjectedBundlePage::didClearWindowForFrame(WKBundlePageRef page, WKBundleFrameRef frame, WKBundleScriptWorldRef world, const void *clientInfo)
580 {
581     static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didClearWindowForFrame(frame, world);
582 }
583
584 void InjectedBundlePage::didCancelClientRedirectForFrame(WKBundlePageRef page, WKBundleFrameRef frame, const void* clientInfo)
585 {
586     static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didCancelClientRedirectForFrame(frame);
587 }
588
589 void InjectedBundlePage::willPerformClientRedirectForFrame(WKBundlePageRef page, WKBundleFrameRef frame, WKURLRef url, double delay, double date, const void* clientInfo)
590 {
591     static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->willPerformClientRedirectForFrame(page, frame, url, delay, date);
592 }
593
594 void InjectedBundlePage::didSameDocumentNavigationForFrame(WKBundlePageRef page, WKBundleFrameRef frame, WKSameDocumentNavigationType type, WKTypeRef*, const void* clientInfo)
595 {
596     static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didSameDocumentNavigationForFrame(frame, type);
597 }
598
599 void InjectedBundlePage::didHandleOnloadEventsForFrame(WKBundlePageRef page, WKBundleFrameRef frame, const void* clientInfo)
600 {
601     static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didHandleOnloadEventsForFrame(frame);
602 }
603
604 void InjectedBundlePage::didDisplayInsecureContentForFrame(WKBundlePageRef page, WKBundleFrameRef frame, WKTypeRef*, const void* clientInfo)
605 {
606     static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didDisplayInsecureContentForFrame(frame);
607 }
608
609 void InjectedBundlePage::didDetectXSSForFrame(WKBundlePageRef page, WKBundleFrameRef frame, WKTypeRef*, const void* clientInfo)
610 {
611     static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didDetectXSSForFrame(frame);
612 }
613
614 void InjectedBundlePage::didRunInsecureContentForFrame(WKBundlePageRef page, WKBundleFrameRef frame, WKTypeRef*, const void* clientInfo)
615 {
616     static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didRunInsecureContentForFrame(frame);
617 }
618
619 void InjectedBundlePage::didInitiateLoadForResource(WKBundlePageRef page, WKBundleFrameRef frame, uint64_t identifier, WKURLRequestRef request, bool pageLoadIsProvisional, const void* clientInfo)
620 {
621     static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didInitiateLoadForResource(page, frame, identifier, request, pageLoadIsProvisional);
622 }
623
624 WKURLRequestRef InjectedBundlePage::willSendRequestForFrame(WKBundlePageRef page, WKBundleFrameRef frame, uint64_t identifier, WKURLRequestRef request, WKURLResponseRef redirectResponse, const void* clientInfo)
625 {
626     return static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->willSendRequestForFrame(page, frame, identifier, request, redirectResponse);
627 }
628
629 void InjectedBundlePage::didReceiveResponseForResource(WKBundlePageRef page, WKBundleFrameRef frame, uint64_t identifier, WKURLResponseRef response, const void* clientInfo)
630 {
631     static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didReceiveResponseForResource(page, frame, identifier, response);
632 }
633
634 void InjectedBundlePage::didReceiveContentLengthForResource(WKBundlePageRef page, WKBundleFrameRef frame, uint64_t identifier, uint64_t length, const void* clientInfo)
635 {
636     static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didReceiveContentLengthForResource(page, frame, identifier, length);
637 }
638
639 void InjectedBundlePage::didFinishLoadForResource(WKBundlePageRef page, WKBundleFrameRef frame, uint64_t identifier, const void* clientInfo)
640 {
641     static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didFinishLoadForResource(page, frame, identifier);
642 }
643
644 void InjectedBundlePage::didFailLoadForResource(WKBundlePageRef page, WKBundleFrameRef frame, uint64_t identifier, WKErrorRef error, const void* clientInfo)
645 {
646     static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didFailLoadForResource(page, frame, identifier, error);
647 }
648
649 bool InjectedBundlePage::shouldCacheResponse(WKBundlePageRef page, WKBundleFrameRef frame, uint64_t identifier, const void* clientInfo)
650 {
651     return static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->shouldCacheResponse(page, frame, identifier);
652 }
653
654 void InjectedBundlePage::didStartProvisionalLoadForFrame(WKBundleFrameRef frame)
655 {
656     auto& injectedBundle = InjectedBundle::singleton();
657     if (!injectedBundle.isTestRunning())
658         return;
659
660     if (!injectedBundle.testRunner()->testURL()) {
661         WKRetainPtr<WKURLRef> testURL = adoptWK(WKBundleFrameCopyProvisionalURL(frame));
662         injectedBundle.testRunner()->setTestURL(testURL.get());
663     }
664
665     platformDidStartProvisionalLoadForFrame(frame);
666
667     if (injectedBundle.testRunner()->shouldDumpFrameLoadCallbacks())
668         dumpLoadEvent(frame, "didStartProvisionalLoadForFrame");
669
670     if (!injectedBundle.topLoadingFrame())
671         injectedBundle.setTopLoadingFrame(frame);
672
673     if (injectedBundle.testRunner()->shouldStopProvisionalFrameLoads())
674         dumpLoadEvent(frame, "stopping load in didStartProvisionalLoadForFrame callback");
675 }
676
677 void InjectedBundlePage::didReceiveServerRedirectForProvisionalLoadForFrame(WKBundleFrameRef frame)
678 {
679     auto& injectedBundle = InjectedBundle::singleton();
680     if (!injectedBundle.isTestRunning())
681         return;
682
683     if (!injectedBundle.testRunner()->shouldDumpFrameLoadCallbacks())
684         return;
685
686     dumpLoadEvent(frame, "didReceiveServerRedirectForProvisionalLoadForFrame");
687 }
688
689 void InjectedBundlePage::didFailProvisionalLoadWithErrorForFrame(WKBundleFrameRef frame, WKErrorRef error)
690 {
691     auto& injectedBundle = InjectedBundle::singleton();
692     if (!injectedBundle.isTestRunning())
693         return;
694
695     if (injectedBundle.testRunner()->shouldDumpFrameLoadCallbacks()) {
696         dumpLoadEvent(frame, "didFailProvisionalLoadWithError");
697         if (WKErrorGetErrorCode(error) == kWKErrorCodeCannotShowURL)
698             dumpLoadEvent(frame, "(kWKErrorCodeCannotShowURL)");
699     }
700
701     frameDidChangeLocation(frame);
702 }
703
704 void InjectedBundlePage::didCommitLoadForFrame(WKBundleFrameRef frame)
705 {
706     auto& injectedBundle = InjectedBundle::singleton();
707     if (!injectedBundle.isTestRunning())
708         return;
709
710     if (!injectedBundle.testRunner()->shouldDumpFrameLoadCallbacks())
711         return;
712
713     dumpLoadEvent(frame, "didCommitLoadForFrame");
714 }
715
716 void InjectedBundlePage::didFinishProgress()
717 {
718     auto& injectedBundle = InjectedBundle::singleton();
719     if (!injectedBundle.isTestRunning())
720         return;
721
722     if (!injectedBundle.testRunner()->shouldDumpProgressFinishedCallback())
723         return;
724
725     injectedBundle.outputText("postProgressFinishedNotification\n");
726 }
727
728 enum FrameNamePolicy { ShouldNotIncludeFrameName, ShouldIncludeFrameName };
729
730 static void dumpFrameScrollPosition(WKBundleFrameRef frame, StringBuilder& stringBuilder, FrameNamePolicy shouldIncludeFrameName = ShouldNotIncludeFrameName)
731 {
732     double x = numericWindowPropertyValue(frame, "pageXOffset");
733     double y = numericWindowPropertyValue(frame, "pageYOffset");
734     if (fabs(x) <= 0.00000001 && fabs(y) <= 0.00000001)
735         return;
736
737     if (shouldIncludeFrameName) {
738         WKRetainPtr<WKStringRef> name(AdoptWK, WKBundleFrameCopyName(frame));
739         stringBuilder.appendLiteral("frame '");
740         stringBuilder.append(toWTFString(name));
741         stringBuilder.appendLiteral("' ");
742     }
743     stringBuilder.appendLiteral("scrolled to ");
744     stringBuilder.append(WTF::String::number(x));
745     stringBuilder.append(',');
746     stringBuilder.append(WTF::String::number(y));
747     stringBuilder.append('\n');
748 }
749
750 static void dumpDescendantFrameScrollPositions(WKBundleFrameRef frame, StringBuilder& stringBuilder)
751 {
752     WKRetainPtr<WKArrayRef> childFrames(AdoptWK, WKBundleFrameCopyChildFrames(frame));
753     size_t size = WKArrayGetSize(childFrames.get());
754     for (size_t i = 0; i < size; ++i) {
755         WKBundleFrameRef subframe = static_cast<WKBundleFrameRef>(WKArrayGetItemAtIndex(childFrames.get(), i));
756         dumpFrameScrollPosition(subframe, stringBuilder, ShouldIncludeFrameName);
757         dumpDescendantFrameScrollPositions(subframe, stringBuilder);
758     }
759 }
760
761 void InjectedBundlePage::dumpAllFrameScrollPositions(StringBuilder& stringBuilder)
762 {
763     WKBundleFrameRef frame = WKBundlePageGetMainFrame(m_page);
764     dumpFrameScrollPosition(frame, stringBuilder);
765     dumpDescendantFrameScrollPositions(frame, stringBuilder);
766 }
767
768 static JSRetainPtr<JSStringRef> toJS(const char* string)
769 {
770     return JSRetainPtr<JSStringRef>(Adopt, JSStringCreateWithUTF8CString(string));
771 }
772
773 static bool hasDocumentElement(WKBundleFrameRef frame)
774 {
775     JSGlobalContextRef context = WKBundleFrameGetJavaScriptContext(frame);
776     JSObjectRef globalObject = JSContextGetGlobalObject(context);
777
778     JSValueRef documentValue = JSObjectGetProperty(context, globalObject, toJS("document").get(), 0);
779     if (!documentValue)
780         return false;
781
782     ASSERT(JSValueIsObject(context, documentValue));
783     JSObjectRef document = JSValueToObject(context, documentValue, 0);
784
785     JSValueRef documentElementValue = JSObjectGetProperty(context, document, toJS("documentElement").get(), 0);
786     if (!documentElementValue)
787         return false;
788
789     return JSValueToBoolean(context, documentElementValue);
790 }
791
792 static void dumpFrameText(WKBundleFrameRef frame, StringBuilder& stringBuilder)
793 {
794     // If the frame doesn't have a document element, its inner text will be an empty string, so
795     // we'll end up just appending a single newline below. But DumpRenderTree doesn't append
796     // anything in this case, so we shouldn't either.
797     if (!hasDocumentElement(frame))
798         return;
799
800     WKRetainPtr<WKStringRef> text(AdoptWK, WKBundleFrameCopyInnerText(frame));
801     stringBuilder.append(toWTFString(text));
802     stringBuilder.append('\n');
803 }
804
805 static void dumpDescendantFramesText(WKBundleFrameRef frame, StringBuilder& stringBuilder)
806 {
807     WKRetainPtr<WKArrayRef> childFrames(AdoptWK, WKBundleFrameCopyChildFrames(frame));
808     size_t size = WKArrayGetSize(childFrames.get());
809     for (size_t i = 0; i < size; ++i) {
810         WKBundleFrameRef subframe = static_cast<WKBundleFrameRef>(WKArrayGetItemAtIndex(childFrames.get(), i));
811         WKRetainPtr<WKStringRef> subframeName(AdoptWK, WKBundleFrameCopyName(subframe));
812
813         // DumpRenderTree ignores empty frames, so do the same thing here.
814         if (!hasDocumentElement(subframe))
815             continue;
816
817         stringBuilder.appendLiteral("\n--------\nFrame: '");
818         stringBuilder.append(toWTFString(subframeName));
819         stringBuilder.appendLiteral("'\n--------\n");
820
821         dumpFrameText(subframe, stringBuilder);
822         dumpDescendantFramesText(subframe, stringBuilder);
823     }
824 }
825
826 void InjectedBundlePage::dumpAllFramesText(StringBuilder& stringBuilder)
827 {
828     WKBundleFrameRef frame = WKBundlePageGetMainFrame(m_page);
829     dumpFrameText(frame, stringBuilder);
830     dumpDescendantFramesText(frame, stringBuilder);
831 }
832
833
834 void InjectedBundlePage::dumpDOMAsWebArchive(WKBundleFrameRef frame, StringBuilder& stringBuilder)
835 {
836 #if USE(CF)
837     WKRetainPtr<WKDataRef> wkData = adoptWK(WKBundleFrameCopyWebArchive(frame));
838     RetainPtr<CFDataRef> cfData = adoptCF(CFDataCreate(0, WKDataGetBytes(wkData.get()), WKDataGetSize(wkData.get())));
839     RetainPtr<CFStringRef> cfString = adoptCF(createXMLStringFromWebArchiveData(cfData.get()));
840     stringBuilder.append(cfString.get());
841 #endif
842 }
843
844 void InjectedBundlePage::dump()
845 {
846     auto& injectedBundle = InjectedBundle::singleton();
847     ASSERT(injectedBundle.isTestRunning());
848
849     // Force a paint before dumping. This matches DumpRenderTree on Windows. (DumpRenderTree on Mac
850     // does this at a slightly different time.) See <http://webkit.org/b/55469> for details.
851     WKBundlePageForceRepaint(m_page);
852
853     WKBundleFrameRef frame = WKBundlePageGetMainFrame(m_page);
854     WKRetainPtr<WKURLRef> urlRef = adoptWK(WKBundleFrameCopyURL(frame));
855     String url = toWTFString(adoptWK(WKURLCopyString(urlRef.get())));
856     WKRetainPtr<WKStringRef> mimeType = adoptWK(WKBundleFrameCopyMIMETypeForResourceWithURL(frame, urlRef.get()));
857     if (url.find("dumpAsText/") != notFound || WKStringIsEqualToUTF8CString(mimeType.get(), "text/plain"))
858         injectedBundle.testRunner()->dumpAsText(false);
859
860     StringBuilder stringBuilder;
861
862     switch (injectedBundle.testRunner()->whatToDump()) {
863     case TestRunner::RenderTree: {
864         if (injectedBundle.testRunner()->isPrinting())
865             stringBuilder.append(toWTFString(adoptWK(WKBundlePageCopyRenderTreeExternalRepresentationForPrinting(m_page)).get()));
866         else
867             stringBuilder.append(toWTFString(adoptWK(WKBundlePageCopyRenderTreeExternalRepresentation(m_page)).get()));
868         break;
869     }
870     case TestRunner::MainFrameText:
871         dumpFrameText(WKBundlePageGetMainFrame(m_page), stringBuilder);
872         break;
873     case TestRunner::AllFramesText:
874         dumpAllFramesText(stringBuilder);
875         break;
876     case TestRunner::Audio:
877         break;
878     case TestRunner::DOMAsWebArchive:
879         dumpDOMAsWebArchive(frame, stringBuilder);
880         break;
881     }
882
883     if (injectedBundle.testRunner()->shouldDumpAllFrameScrollPositions())
884         dumpAllFrameScrollPositions(stringBuilder);
885     else if (injectedBundle.testRunner()->shouldDumpMainFrameScrollPosition())
886         dumpFrameScrollPosition(WKBundlePageGetMainFrame(m_page), stringBuilder);
887
888     if (injectedBundle.testRunner()->shouldDumpBackForwardListsForAllWindows())
889         injectedBundle.dumpBackForwardListsForAllPages(stringBuilder);
890
891     if (injectedBundle.shouldDumpPixels() && injectedBundle.testRunner()->shouldDumpPixels()) {
892         WKSnapshotOptions options = kWKSnapshotOptionsShareable | kWKSnapshotOptionsInViewCoordinates;
893         if (injectedBundle.testRunner()->shouldDumpSelectionRect())
894             options |= kWKSnapshotOptionsPaintSelectionRectangle;
895
896         injectedBundle.setPixelResult(adoptWK(WKBundlePageCreateSnapshotWithOptions(m_page, WKBundleFrameGetVisibleContentBounds(WKBundlePageGetMainFrame(m_page)), options)).get());
897         if (WKBundlePageIsTrackingRepaints(m_page))
898             injectedBundle.setRepaintRects(adoptWK(WKBundlePageCopyTrackedRepaintRects(m_page)).get());
899     }
900
901     injectedBundle.outputText(stringBuilder.toString());
902     injectedBundle.done();
903 }
904
905 void InjectedBundlePage::didFinishLoadForFrame(WKBundleFrameRef frame)
906 {
907     auto& injectedBundle = InjectedBundle::singleton();
908     if (!injectedBundle.isTestRunning())
909         return;
910
911     if (injectedBundle.testRunner()->shouldDumpFrameLoadCallbacks())
912         dumpLoadEvent(frame, "didFinishLoadForFrame");
913
914     frameDidChangeLocation(frame, /*shouldDump*/ true);
915 }
916
917 void InjectedBundlePage::didFailLoadWithErrorForFrame(WKBundleFrameRef frame, WKErrorRef)
918 {
919     auto& injectedBundle = InjectedBundle::singleton();
920     if (!injectedBundle.isTestRunning())
921         return;
922
923     if (injectedBundle.testRunner()->shouldDumpFrameLoadCallbacks())
924         dumpLoadEvent(frame, "didFailLoadWithError");
925
926     frameDidChangeLocation(frame);
927 }
928
929 void InjectedBundlePage::didReceiveTitleForFrame(WKStringRef title, WKBundleFrameRef frame)
930 {
931     auto& injectedBundle = InjectedBundle::singleton();
932     if (!injectedBundle.isTestRunning())
933         return;
934
935     StringBuilder stringBuilder;
936     if (injectedBundle.testRunner()->shouldDumpFrameLoadCallbacks()) {
937         dumpFrameDescriptionSuitableForTestResult(frame, stringBuilder);
938         stringBuilder.appendLiteral(" - didReceiveTitle: ");
939         stringBuilder.append(toWTFString(title));
940         stringBuilder.append('\n');
941     }
942
943     if (injectedBundle.testRunner()->shouldDumpTitleChanges()) {
944         stringBuilder.appendLiteral("TITLE CHANGED: '");
945         stringBuilder.append(toWTFString(title));
946         stringBuilder.appendLiteral("'\n");
947     }
948
949     injectedBundle.outputText(stringBuilder.toString());
950 }
951
952 void InjectedBundlePage::didClearWindowForFrame(WKBundleFrameRef frame, WKBundleScriptWorldRef world)
953 {
954     auto& injectedBundle = InjectedBundle::singleton();
955     if (!injectedBundle.isTestRunning())
956         return;
957
958     JSGlobalContextRef context = WKBundleFrameGetJavaScriptContextForWorld(frame, world);
959     JSObjectRef window = JSContextGetGlobalObject(context);
960
961     if (WKBundleScriptWorldNormalWorld() != world) {
962         JSObjectSetProperty(context, window, toJS("__worldID").get(), JSValueMakeNumber(context, TestRunner::worldIDForWorld(world)), kJSPropertyAttributeReadOnly, 0);
963         return;
964     }
965
966     JSValueRef exception = nullptr;
967     injectedBundle.testRunner()->makeWindowObject(context, window, &exception);
968     injectedBundle.gcController()->makeWindowObject(context, window, &exception);
969     injectedBundle.eventSendingController()->makeWindowObject(context, window, &exception);
970     injectedBundle.textInputController()->makeWindowObject(context, window, &exception);
971     injectedBundle.accessibilityController()->makeWindowObject(context, window, &exception);
972
973     WebCoreTestSupport::injectInternalsObject(context);
974 }
975
976 void InjectedBundlePage::didCancelClientRedirectForFrame(WKBundleFrameRef frame)
977 {
978     auto& injectedBundle = InjectedBundle::singleton();
979     if (!injectedBundle.isTestRunning())
980         return;
981
982     if (!injectedBundle.testRunner()->shouldDumpFrameLoadCallbacks())
983         return;
984
985     dumpLoadEvent(frame, "didCancelClientRedirectForFrame");
986 }
987
988 void InjectedBundlePage::willPerformClientRedirectForFrame(WKBundlePageRef, WKBundleFrameRef frame, WKURLRef url, double delay, double date)
989 {
990     auto& injectedBundle = InjectedBundle::singleton();
991     if (!injectedBundle.isTestRunning())
992         return;
993
994     if (!injectedBundle.testRunner()->shouldDumpFrameLoadCallbacks())
995         return;
996
997     StringBuilder stringBuilder;
998     dumpFrameDescriptionSuitableForTestResult(frame, stringBuilder);
999     stringBuilder.appendLiteral(" - willPerformClientRedirectToURL: ");
1000     stringBuilder.append(pathSuitableForTestResult(url));
1001     stringBuilder.appendLiteral(" \n");
1002     injectedBundle.outputText(stringBuilder.toString());
1003 }
1004
1005 void InjectedBundlePage::didSameDocumentNavigationForFrame(WKBundleFrameRef frame, WKSameDocumentNavigationType type)
1006 {
1007     auto& injectedBundle = InjectedBundle::singleton();
1008     if (!injectedBundle.isTestRunning())
1009         return;
1010
1011     if (!injectedBundle.testRunner()->shouldDumpFrameLoadCallbacks())
1012         return;
1013
1014     if (type != kWKSameDocumentNavigationAnchorNavigation)
1015         return;
1016
1017     dumpLoadEvent(frame, "didChangeLocationWithinPageForFrame");
1018 }
1019
1020 void InjectedBundlePage::didFinishDocumentLoadForFrame(WKBundleFrameRef frame)
1021 {
1022     auto& injectedBundle = InjectedBundle::singleton();
1023     if (!injectedBundle.isTestRunning())
1024         return;
1025
1026     if (injectedBundle.testRunner()->shouldDumpFrameLoadCallbacks())
1027         dumpLoadEvent(frame, "didFinishDocumentLoadForFrame");
1028
1029     unsigned pendingFrameUnloadEvents = WKBundleFrameGetPendingUnloadCount(frame);
1030     if (pendingFrameUnloadEvents) {
1031         StringBuilder stringBuilder;
1032         stringBuilder.append(frameToStr(frame));
1033         stringBuilder.appendLiteral(" - has ");
1034         stringBuilder.appendNumber(pendingFrameUnloadEvents);
1035         stringBuilder.appendLiteral(" onunload handler(s)\n");
1036         injectedBundle.outputText(stringBuilder.toString());
1037     }
1038 }
1039
1040 void InjectedBundlePage::didHandleOnloadEventsForFrame(WKBundleFrameRef frame)
1041 {
1042     auto& injectedBundle = InjectedBundle::singleton();
1043     if (!injectedBundle.isTestRunning())
1044         return;
1045
1046     if (injectedBundle.testRunner()->shouldDumpFrameLoadCallbacks())
1047         dumpLoadEvent(frame, "didHandleOnloadEventsForFrame");
1048 }
1049
1050 void InjectedBundlePage::didDisplayInsecureContentForFrame(WKBundleFrameRef)
1051 {
1052     auto& injectedBundle = InjectedBundle::singleton();
1053     if (injectedBundle.testRunner()->shouldDumpFrameLoadCallbacks())
1054         injectedBundle.outputText("didDisplayInsecureContent\n");
1055 }
1056
1057 void InjectedBundlePage::didRunInsecureContentForFrame(WKBundleFrameRef)
1058 {
1059     auto& injectedBundle = InjectedBundle::singleton();
1060     if (injectedBundle.testRunner()->shouldDumpFrameLoadCallbacks())
1061         injectedBundle.outputText("didRunInsecureContent\n");
1062 }
1063
1064 void InjectedBundlePage::didDetectXSSForFrame(WKBundleFrameRef)
1065 {
1066     auto& injectedBundle = InjectedBundle::singleton();
1067     if (injectedBundle.testRunner()->shouldDumpFrameLoadCallbacks())
1068         injectedBundle.outputText("didDetectXSS\n");
1069 }
1070
1071 void InjectedBundlePage::didInitiateLoadForResource(WKBundlePageRef page, WKBundleFrameRef, uint64_t identifier, WKURLRequestRef request, bool)
1072 {
1073     if (!InjectedBundle::singleton().isTestRunning())
1074         return;
1075
1076     WKRetainPtr<WKURLRef> url = adoptWK(WKURLRequestCopyURL(request));
1077     assignedUrlsCache.add(identifier, pathSuitableForTestResult(url.get()));
1078 }
1079
1080 // Resource Load Client Callbacks
1081
1082 static inline bool isLocalHost(WKStringRef host)
1083 {
1084     return WKStringIsEqualToUTF8CString(host, "127.0.0.1") || WKStringIsEqualToUTF8CString(host, "localhost");
1085 }
1086
1087 static inline bool isHTTPOrHTTPSScheme(WKStringRef scheme)
1088 {
1089     return WKStringIsEqualToUTF8CStringIgnoringCase(scheme, "http") || WKStringIsEqualToUTF8CStringIgnoringCase(scheme, "https");
1090 }
1091
1092 static inline bool isAllowedHost(WKStringRef host)
1093 {
1094     return InjectedBundle::singleton().isAllowedHost(host);
1095 }
1096
1097 WKURLRequestRef InjectedBundlePage::willSendRequestForFrame(WKBundlePageRef page, WKBundleFrameRef frame, uint64_t identifier, WKURLRequestRef request, WKURLResponseRef response)
1098 {
1099     auto& injectedBundle = InjectedBundle::singleton();
1100     if (injectedBundle.isTestRunning()
1101         && injectedBundle.testRunner()->shouldDumpResourceLoadCallbacks()) {
1102         StringBuilder stringBuilder;
1103         dumpResourceURL(identifier, stringBuilder);
1104         stringBuilder.appendLiteral(" - willSendRequest ");
1105         dumpRequestDescriptionSuitableForTestResult(request, stringBuilder);
1106         stringBuilder.appendLiteral(" redirectResponse ");
1107         dumpResponseDescriptionSuitableForTestResult(response, stringBuilder);
1108         stringBuilder.append('\n');
1109         injectedBundle.outputText(stringBuilder.toString());
1110     }
1111
1112     if (injectedBundle.isTestRunning() && injectedBundle.testRunner()->willSendRequestReturnsNull())
1113         return nullptr;
1114
1115     WKRetainPtr<WKURLRef> redirectURL = adoptWK(WKURLResponseCopyURL(response));
1116     if (injectedBundle.isTestRunning() && injectedBundle.testRunner()->willSendRequestReturnsNullOnRedirect() && redirectURL) {
1117         injectedBundle.outputText("Returning null for this redirect\n");
1118         return nullptr;
1119     }
1120
1121     WKRetainPtr<WKURLRef> url = adoptWK(WKURLRequestCopyURL(request));
1122     WKRetainPtr<WKStringRef> host = adoptWK(WKURLCopyHostName(url.get()));
1123     WKRetainPtr<WKStringRef> scheme = adoptWK(WKURLCopyScheme(url.get()));
1124     WKRetainPtr<WKStringRef> urlString = adoptWK(WKURLCopyString(url.get()));
1125     if (host && !WKStringIsEmpty(host.get())
1126         && isHTTPOrHTTPSScheme(scheme.get())
1127         && !WKStringIsEqualToUTF8CString(host.get(), "255.255.255.255") // Used in some tests that expect to get back an error.
1128         && !isLocalHost(host.get())) {
1129         bool mainFrameIsExternal = false;
1130         if (injectedBundle.isTestRunning()) {
1131             WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(m_page);
1132             WKRetainPtr<WKURLRef> mainFrameURL = adoptWK(WKBundleFrameCopyURL(mainFrame));
1133             if (!mainFrameURL || WKStringIsEqualToUTF8CString(adoptWK(WKURLCopyString(mainFrameURL.get())).get(), "about:blank"))
1134                 mainFrameURL = adoptWK(WKBundleFrameCopyProvisionalURL(mainFrame));
1135
1136             WKRetainPtr<WKStringRef> mainFrameHost = adoptWK(WKURLCopyHostName(mainFrameURL.get()));
1137             WKRetainPtr<WKStringRef> mainFrameScheme = adoptWK(WKURLCopyScheme(mainFrameURL.get()));
1138             mainFrameIsExternal = isHTTPOrHTTPSScheme(mainFrameScheme.get()) && !isLocalHost(mainFrameHost.get());
1139         }
1140         if (!mainFrameIsExternal && !isAllowedHost(host.get())) {
1141             StringBuilder stringBuilder;
1142             stringBuilder.appendLiteral("Blocked access to external URL ");
1143             stringBuilder.append(toWTFString(urlString));
1144             stringBuilder.append('\n');
1145             injectedBundle.outputText(stringBuilder.toString());
1146             return nullptr;
1147         }
1148     }
1149
1150     WKRetain(request);
1151     return request;
1152 }
1153
1154 void InjectedBundlePage::didReceiveResponseForResource(WKBundlePageRef page, WKBundleFrameRef, uint64_t identifier, WKURLResponseRef response)
1155 {
1156     auto& injectedBundle = InjectedBundle::singleton();
1157     if (!injectedBundle.isTestRunning())
1158         return;
1159
1160     if (injectedBundle.testRunner()->shouldDumpResourceLoadCallbacks()) {
1161         StringBuilder stringBuilder;
1162         dumpResourceURL(identifier, stringBuilder);
1163         stringBuilder.appendLiteral(" - didReceiveResponse ");
1164         dumpResponseDescriptionSuitableForTestResult(response, stringBuilder);
1165         stringBuilder.append('\n');
1166         injectedBundle.outputText(stringBuilder.toString());
1167     }
1168
1169
1170     if (!injectedBundle.testRunner()->shouldDumpResourceResponseMIMETypes())
1171         return;
1172
1173     WKRetainPtr<WKURLRef> url = adoptWK(WKURLResponseCopyURL(response));
1174     WKRetainPtr<WKStringRef> urlString = adoptWK(WKURLCopyLastPathComponent(url.get()));
1175     WKRetainPtr<WKStringRef> mimeTypeString = adoptWK(WKURLResponseCopyMIMEType(response));
1176
1177     StringBuilder stringBuilder;
1178     stringBuilder.append(toWTFString(urlString));
1179     stringBuilder.appendLiteral(" has MIME type ");
1180     stringBuilder.append(toWTFString(mimeTypeString));
1181
1182     String platformMimeType = platformResponseMimeType(response);
1183     if (!platformMimeType.isEmpty() && platformMimeType != toWTFString(mimeTypeString)) {
1184         stringBuilder.appendLiteral(" but platform response has ");
1185         stringBuilder.append(platformMimeType);
1186     }
1187
1188     stringBuilder.append('\n');
1189
1190     injectedBundle.outputText(stringBuilder.toString());
1191 }
1192
1193 void InjectedBundlePage::didReceiveContentLengthForResource(WKBundlePageRef, WKBundleFrameRef, uint64_t, uint64_t)
1194 {
1195 }
1196
1197 void InjectedBundlePage::didFinishLoadForResource(WKBundlePageRef, WKBundleFrameRef, uint64_t identifier)
1198 {
1199     auto& injectedBundle = InjectedBundle::singleton();
1200     if (!injectedBundle.isTestRunning())
1201         return;
1202
1203     if (!injectedBundle.testRunner()->shouldDumpResourceLoadCallbacks())
1204         return;
1205
1206     StringBuilder stringBuilder;
1207     dumpResourceURL(identifier, stringBuilder);
1208     stringBuilder.appendLiteral(" - didFinishLoading\n");
1209     injectedBundle.outputText(stringBuilder.toString());
1210 }
1211
1212 void InjectedBundlePage::didFailLoadForResource(WKBundlePageRef, WKBundleFrameRef, uint64_t identifier, WKErrorRef error)
1213 {
1214     auto& injectedBundle = InjectedBundle::singleton();
1215     if (!injectedBundle.isTestRunning())
1216         return;
1217
1218     if (!injectedBundle.testRunner()->shouldDumpResourceLoadCallbacks())
1219         return;
1220
1221     StringBuilder stringBuilder;
1222     dumpResourceURL(identifier, stringBuilder);
1223     stringBuilder.appendLiteral(" - didFailLoadingWithError: ");
1224
1225     dumpErrorDescriptionSuitableForTestResult(error, stringBuilder);
1226     stringBuilder.append('\n');
1227     injectedBundle.outputText(stringBuilder.toString());
1228 }
1229
1230 bool InjectedBundlePage::shouldCacheResponse(WKBundlePageRef, WKBundleFrameRef, uint64_t identifier)
1231 {
1232     auto& injectedBundle = InjectedBundle::singleton();
1233     if (!injectedBundle.isTestRunning())
1234         return true;
1235
1236     if (!injectedBundle.testRunner()->shouldDumpWillCacheResponse())
1237         return true;
1238
1239     StringBuilder stringBuilder;
1240     stringBuilder.appendNumber(identifier);
1241     stringBuilder.appendLiteral(" - willCacheResponse: called\n");
1242     injectedBundle.outputText(stringBuilder.toString());
1243
1244     // The default behavior is the cache the response.
1245     return true;
1246 }
1247
1248
1249 // Policy Client Callbacks
1250
1251 WKBundlePagePolicyAction InjectedBundlePage::decidePolicyForNavigationAction(WKBundlePageRef page, WKBundleFrameRef frame, WKBundleNavigationActionRef navigationAction, WKURLRequestRef request, WKTypeRef* userData, const void* clientInfo)
1252 {
1253     return static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->decidePolicyForNavigationAction(page, frame, navigationAction, request, userData);
1254 }
1255
1256 WKBundlePagePolicyAction InjectedBundlePage::decidePolicyForNewWindowAction(WKBundlePageRef page, WKBundleFrameRef frame, WKBundleNavigationActionRef navigationAction, WKURLRequestRef request, WKStringRef frameName, WKTypeRef* userData, const void* clientInfo)
1257 {
1258     return static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->decidePolicyForNewWindowAction(page, frame, navigationAction, request, frameName, userData);
1259 }
1260
1261 WKBundlePagePolicyAction InjectedBundlePage::decidePolicyForResponse(WKBundlePageRef page, WKBundleFrameRef frame, WKURLResponseRef response, WKURLRequestRef request, WKTypeRef* userData, const void* clientInfo)
1262 {
1263     return static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->decidePolicyForResponse(page, frame, response, request, userData);
1264 }
1265
1266 void InjectedBundlePage::unableToImplementPolicy(WKBundlePageRef page, WKBundleFrameRef frame, WKErrorRef error, WKTypeRef* userData, const void* clientInfo)
1267 {
1268     static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->unableToImplementPolicy(page, frame, error, userData);
1269 }
1270
1271 WKBundlePagePolicyAction InjectedBundlePage::decidePolicyForNavigationAction(WKBundlePageRef page, WKBundleFrameRef frame, WKBundleNavigationActionRef navigationAction, WKURLRequestRef request, WKTypeRef* userData)
1272 {
1273     auto& injectedBundle = InjectedBundle::singleton();
1274     if (!injectedBundle.isTestRunning())
1275         return WKBundlePagePolicyActionUse;
1276
1277     if (injectedBundle.testRunner()->shouldDumpPolicyCallbacks()) {
1278         StringBuilder stringBuilder;
1279         stringBuilder.appendLiteral(" - decidePolicyForNavigationAction \n");
1280         dumpRequestDescriptionSuitableForTestResult(request, stringBuilder);
1281         stringBuilder.appendLiteral(" is main frame - ");
1282         stringBuilder.append(WKBundleFrameIsMainFrame(frame) ? "yes" : "no");
1283         stringBuilder.appendLiteral(" should open URLs externally - ");
1284         stringBuilder.append(WKBundleNavigationActionGetShouldOpenExternalURLs(navigationAction) ? "yes" : "no");
1285         stringBuilder.append('\n');
1286         injectedBundle.outputText(stringBuilder.toString());
1287     }
1288
1289     if (!injectedBundle.testRunner()->isPolicyDelegateEnabled())
1290         return WKBundlePagePolicyActionUse;
1291
1292     WKRetainPtr<WKURLRef> url = adoptWK(WKURLRequestCopyURL(request));
1293     WKRetainPtr<WKStringRef> urlScheme = adoptWK(WKURLCopyScheme(url.get()));
1294
1295     StringBuilder stringBuilder;
1296     stringBuilder.appendLiteral("Policy delegate: attempt to load ");
1297     if (isLocalFileScheme(urlScheme.get())) {
1298         WKRetainPtr<WKStringRef> filename = adoptWK(WKURLCopyLastPathComponent(url.get()));
1299         stringBuilder.append(toWTFString(filename));
1300     } else {
1301         WKRetainPtr<WKStringRef> urlString = adoptWK(WKURLCopyString(url.get()));
1302         stringBuilder.append(toWTFString(urlString));
1303     }
1304     stringBuilder.appendLiteral(" with navigation type \'");
1305     stringBuilder.append(toWTFString(NavigationTypeToString(WKBundleNavigationActionGetNavigationType(navigationAction))));
1306     stringBuilder.appendLiteral("\'");
1307     WKBundleHitTestResultRef hitTestResultRef = WKBundleNavigationActionCopyHitTestResult(navigationAction);
1308     if (hitTestResultRef) {
1309         stringBuilder.appendLiteral(" originating from ");
1310         stringBuilder.append(dumpPath(m_page, m_world.get(), WKBundleHitTestResultCopyNodeHandle(hitTestResultRef)));
1311     }
1312
1313     stringBuilder.append('\n');
1314     injectedBundle.outputText(stringBuilder.toString());
1315     injectedBundle.testRunner()->notifyDone();
1316
1317     if (injectedBundle.testRunner()->isPolicyDelegatePermissive())
1318         return WKBundlePagePolicyActionUse;
1319     return WKBundlePagePolicyActionPassThrough;
1320 }
1321
1322 WKBundlePagePolicyAction InjectedBundlePage::decidePolicyForNewWindowAction(WKBundlePageRef, WKBundleFrameRef, WKBundleNavigationActionRef, WKURLRequestRef, WKStringRef, WKTypeRef*)
1323 {
1324     return WKBundlePagePolicyActionUse;
1325 }
1326
1327 WKBundlePagePolicyAction InjectedBundlePage::decidePolicyForResponse(WKBundlePageRef page, WKBundleFrameRef, WKURLResponseRef response, WKURLRequestRef, WKTypeRef*)
1328 {
1329     if (InjectedBundle::singleton().testRunner()->isPolicyDelegateEnabled() && WKURLResponseIsAttachment(response)) {
1330         StringBuilder stringBuilder;
1331         WKRetainPtr<WKStringRef> filename = adoptWK(WKURLResponseCopySuggestedFilename(response));
1332         stringBuilder.appendLiteral("Policy delegate: resource is an attachment, suggested file name \'");
1333         stringBuilder.append(toWTFString(filename));
1334         stringBuilder.appendLiteral("\'\n");
1335         InjectedBundle::singleton().outputText(stringBuilder.toString());
1336     }
1337
1338     WKRetainPtr<WKStringRef> mimeType = adoptWK(WKURLResponseCopyMIMEType(response));
1339     return WKBundlePageCanShowMIMEType(page, mimeType.get()) ? WKBundlePagePolicyActionUse : WKBundlePagePolicyActionPassThrough;
1340 }
1341
1342 void InjectedBundlePage::unableToImplementPolicy(WKBundlePageRef, WKBundleFrameRef, WKErrorRef, WKTypeRef*)
1343 {
1344 }
1345
1346 // UI Client Callbacks
1347
1348 void InjectedBundlePage::willAddMessageToConsole(WKBundlePageRef page, WKStringRef message, uint32_t lineNumber, const void *clientInfo)
1349 {
1350     static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->willAddMessageToConsole(message, lineNumber);
1351 }
1352
1353 void InjectedBundlePage::willSetStatusbarText(WKBundlePageRef page, WKStringRef statusbarText, const void *clientInfo)
1354 {
1355     static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->willSetStatusbarText(statusbarText);
1356 }
1357
1358 void InjectedBundlePage::willRunJavaScriptAlert(WKBundlePageRef page, WKStringRef message, WKBundleFrameRef frame, const void *clientInfo)
1359 {
1360     static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->willRunJavaScriptAlert(message, frame);
1361 }
1362
1363 void InjectedBundlePage::willRunJavaScriptConfirm(WKBundlePageRef page, WKStringRef message, WKBundleFrameRef frame, const void *clientInfo)
1364 {
1365     return static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->willRunJavaScriptConfirm(message, frame);
1366 }
1367
1368 void InjectedBundlePage::willRunJavaScriptPrompt(WKBundlePageRef page, WKStringRef message, WKStringRef defaultValue, WKBundleFrameRef frame, const void *clientInfo)
1369 {
1370     static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->willRunJavaScriptPrompt(message, defaultValue, frame);
1371 }
1372
1373 void InjectedBundlePage::didReachApplicationCacheOriginQuota(WKBundlePageRef page, WKSecurityOriginRef origin, int64_t totalBytesNeeded, const void* clientInfo)
1374 {
1375     static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didReachApplicationCacheOriginQuota(origin, totalBytesNeeded);
1376 }
1377
1378 uint64_t InjectedBundlePage::didExceedDatabaseQuota(WKBundlePageRef page, WKSecurityOriginRef origin, WKStringRef databaseName, WKStringRef databaseDisplayName, uint64_t currentQuotaBytes, uint64_t currentOriginUsageBytes, uint64_t currentDatabaseUsageBytes, uint64_t expectedUsageBytes, const void* clientInfo)
1379 {
1380     return static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didExceedDatabaseQuota(origin, databaseName, databaseDisplayName, currentQuotaBytes, currentOriginUsageBytes, currentDatabaseUsageBytes, expectedUsageBytes);
1381 }
1382
1383 static WTF::String lastFileURLPathComponent(const WTF::String& path)
1384 {
1385     size_t pos = path.find("file://");
1386     ASSERT(WTF::notFound != pos);
1387
1388     WTF::String tmpPath = path.substring(pos + 7);
1389     if (tmpPath.length() < 2) // Keep the lone slash to avoid empty output.
1390         return tmpPath;
1391
1392     // Remove the trailing delimiter
1393     if (tmpPath[tmpPath.length() - 1] == '/')
1394         tmpPath.remove(tmpPath.length() - 1);
1395
1396     pos = tmpPath.reverseFind('/');
1397     if (WTF::notFound != pos)
1398         return tmpPath.substring(pos + 1);
1399
1400     return tmpPath;
1401 }
1402
1403 void InjectedBundlePage::willAddMessageToConsole(WKStringRef message, uint32_t lineNumber)
1404 {
1405     auto& injectedBundle = InjectedBundle::singleton();
1406     if (!injectedBundle.isTestRunning())
1407         return;
1408
1409     WTF::String messageString = toWTFString(message);
1410     size_t nullCharPos = messageString.find(UChar(0));
1411     if (nullCharPos != WTF::notFound)
1412         messageString.truncate(nullCharPos);
1413
1414     size_t fileProtocolStart = messageString.find("file://");
1415     if (fileProtocolStart != WTF::notFound)
1416         // FIXME: The code below does not handle additional text after url nor multiple urls. This matches DumpRenderTree implementation.
1417         messageString = messageString.substring(0, fileProtocolStart) + lastFileURLPathComponent(messageString.substring(fileProtocolStart));
1418
1419     StringBuilder stringBuilder;
1420     stringBuilder.appendLiteral("CONSOLE MESSAGE: ");
1421     if (lineNumber) {
1422         stringBuilder.appendLiteral("line ");
1423         stringBuilder.appendNumber(lineNumber);
1424         stringBuilder.appendLiteral(": ");
1425     }
1426     stringBuilder.append(messageString);
1427     stringBuilder.append('\n');
1428     injectedBundle.outputText(stringBuilder.toString());
1429 }
1430
1431 void InjectedBundlePage::willSetStatusbarText(WKStringRef statusbarText)
1432 {
1433     auto& injectedBundle = InjectedBundle::singleton();
1434     if (!injectedBundle.isTestRunning())
1435         return;
1436
1437     if (!injectedBundle.testRunner()->shouldDumpStatusCallbacks())
1438         return;
1439
1440     StringBuilder stringBuilder;
1441     stringBuilder.appendLiteral("UI DELEGATE STATUS CALLBACK: setStatusText:");
1442     stringBuilder.append(toWTFString(statusbarText));
1443     stringBuilder.append('\n');
1444     injectedBundle.outputText(stringBuilder.toString());
1445 }
1446
1447 void InjectedBundlePage::willRunJavaScriptAlert(WKStringRef message, WKBundleFrameRef)
1448 {
1449     auto& injectedBundle = InjectedBundle::singleton();
1450     if (!injectedBundle.isTestRunning())
1451         return;
1452
1453     StringBuilder stringBuilder;
1454     stringBuilder.appendLiteral("ALERT: ");
1455     stringBuilder.append(toWTFString(message));
1456     stringBuilder.append('\n');
1457     injectedBundle.outputText(stringBuilder.toString());
1458 }
1459
1460 void InjectedBundlePage::willRunJavaScriptConfirm(WKStringRef message, WKBundleFrameRef)
1461 {
1462     auto& injectedBundle = InjectedBundle::singleton();
1463     if (!injectedBundle.isTestRunning())
1464         return;
1465
1466     StringBuilder stringBuilder;
1467     stringBuilder.appendLiteral("CONFIRM: ");
1468     stringBuilder.append(toWTFString(message));
1469     stringBuilder.append('\n');
1470     injectedBundle.outputText(stringBuilder.toString());
1471 }
1472
1473 void InjectedBundlePage::willRunJavaScriptPrompt(WKStringRef message, WKStringRef defaultValue, WKBundleFrameRef)
1474 {
1475     StringBuilder stringBuilder;
1476     stringBuilder.appendLiteral("PROMPT: ");
1477     stringBuilder.append(toWTFString(message));
1478     stringBuilder.appendLiteral(", default text: ");
1479     stringBuilder.append(toWTFString(defaultValue));
1480     stringBuilder.append('\n');
1481     InjectedBundle::singleton().outputText(stringBuilder.toString());
1482 }
1483
1484 void InjectedBundlePage::didReachApplicationCacheOriginQuota(WKSecurityOriginRef origin, int64_t totalBytesNeeded)
1485 {
1486     auto& injectedBundle = InjectedBundle::singleton();
1487     if (injectedBundle.testRunner()->shouldDumpApplicationCacheDelegateCallbacks()) {
1488         // For example, numbers from 30000 - 39999 will output as 30000.
1489         // Rounding up or down does not really matter for these tests. It's
1490         // sufficient to just get a range of 10000 to determine if we were
1491         // above or below a threshold.
1492         int64_t truncatedSpaceNeeded = (totalBytesNeeded / 10000) * 10000;
1493
1494         StringBuilder stringBuilder;
1495         stringBuilder.appendLiteral("UI DELEGATE APPLICATION CACHE CALLBACK: exceededApplicationCacheOriginQuotaForSecurityOrigin:");
1496         stringBuilder.append(securityOriginToStr(origin));
1497         stringBuilder.appendLiteral(" totalSpaceNeeded:~");
1498         stringBuilder.appendNumber(truncatedSpaceNeeded);
1499         stringBuilder.append('\n');
1500         injectedBundle.outputText(stringBuilder.toString());
1501     }
1502
1503     if (injectedBundle.testRunner()->shouldDisallowIncreaseForApplicationCacheQuota())
1504         return;
1505
1506     // Reset default application cache quota.
1507     WKBundleResetApplicationCacheOriginQuota(injectedBundle.bundle(), adoptWK(WKSecurityOriginCopyToString(origin)).get());
1508 }
1509
1510 uint64_t InjectedBundlePage::didExceedDatabaseQuota(WKSecurityOriginRef origin, WKStringRef databaseName, WKStringRef databaseDisplayName, uint64_t currentQuotaBytes, uint64_t currentOriginUsageBytes, uint64_t currentDatabaseUsageBytes, uint64_t expectedUsageBytes)
1511 {
1512     auto& injectedBundle = InjectedBundle::singleton();
1513     if (injectedBundle.testRunner()->shouldDumpDatabaseCallbacks()) {
1514         StringBuilder stringBuilder;
1515         stringBuilder.appendLiteral("UI DELEGATE DATABASE CALLBACK: exceededDatabaseQuotaForSecurityOrigin:");
1516         stringBuilder.append(securityOriginToStr(origin));
1517         stringBuilder.appendLiteral(" database:");
1518         stringBuilder.append(toWTFString(databaseName));
1519         stringBuilder.append('\n');
1520         injectedBundle.outputText(stringBuilder.toString());
1521     }
1522
1523     uint64_t defaultQuota = 5 * 1024 * 1024;
1524     double testDefaultQuota = injectedBundle.testRunner()->databaseDefaultQuota();
1525     if (testDefaultQuota >= 0)
1526         defaultQuota = testDefaultQuota;
1527
1528     unsigned long long newQuota = defaultQuota;
1529
1530     double maxQuota = injectedBundle.testRunner()->databaseMaxQuota();
1531     if (maxQuota >= 0) {
1532         if (defaultQuota < expectedUsageBytes && expectedUsageBytes <= maxQuota) {
1533             newQuota = expectedUsageBytes;
1534
1535             StringBuilder stringBuilder;
1536             stringBuilder.appendLiteral("UI DELEGATE DATABASE CALLBACK: increased quota to ");
1537             stringBuilder.appendNumber(newQuota);
1538             stringBuilder.append('\n');
1539             injectedBundle.outputText(stringBuilder.toString());
1540         }
1541     }
1542     return newQuota;
1543 }
1544
1545 // Editor Client Callbacks
1546
1547 bool InjectedBundlePage::shouldBeginEditing(WKBundlePageRef page, WKBundleRangeHandleRef range, const void* clientInfo)
1548 {
1549     return static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->shouldBeginEditing(range);
1550 }
1551
1552 bool InjectedBundlePage::shouldEndEditing(WKBundlePageRef page, WKBundleRangeHandleRef range, const void* clientInfo)
1553 {
1554     return static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->shouldEndEditing(range);
1555 }
1556
1557 bool InjectedBundlePage::shouldInsertNode(WKBundlePageRef page, WKBundleNodeHandleRef node, WKBundleRangeHandleRef rangeToReplace, WKInsertActionType action, const void* clientInfo)
1558 {
1559     return static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->shouldInsertNode(node, rangeToReplace, action);
1560 }
1561
1562 bool InjectedBundlePage::shouldInsertText(WKBundlePageRef page, WKStringRef text, WKBundleRangeHandleRef rangeToReplace, WKInsertActionType action, const void* clientInfo)
1563 {
1564     return static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->shouldInsertText(text, rangeToReplace, action);
1565 }
1566
1567 bool InjectedBundlePage::shouldDeleteRange(WKBundlePageRef page, WKBundleRangeHandleRef range, const void* clientInfo)
1568 {
1569     return static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->shouldDeleteRange(range);
1570 }
1571
1572 bool InjectedBundlePage::shouldChangeSelectedRange(WKBundlePageRef page, WKBundleRangeHandleRef fromRange, WKBundleRangeHandleRef toRange, WKAffinityType affinity, bool stillSelecting, const void* clientInfo)
1573 {
1574     return static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->shouldChangeSelectedRange(fromRange, toRange, affinity, stillSelecting);
1575 }
1576
1577 bool InjectedBundlePage::shouldApplyStyle(WKBundlePageRef page, WKBundleCSSStyleDeclarationRef style, WKBundleRangeHandleRef range, const void* clientInfo)
1578 {
1579     return static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->shouldApplyStyle(style, range);
1580 }
1581
1582 void InjectedBundlePage::didBeginEditing(WKBundlePageRef page, WKStringRef notificationName, const void* clientInfo)
1583 {
1584     static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didBeginEditing(notificationName);
1585 }
1586
1587 void InjectedBundlePage::didEndEditing(WKBundlePageRef page, WKStringRef notificationName, const void* clientInfo)
1588 {
1589     static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didEndEditing(notificationName);
1590 }
1591
1592 void InjectedBundlePage::didChange(WKBundlePageRef page, WKStringRef notificationName, const void* clientInfo)
1593 {
1594     static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didChange(notificationName);
1595 }
1596
1597 void InjectedBundlePage::didChangeSelection(WKBundlePageRef page, WKStringRef notificationName, const void* clientInfo)
1598 {
1599     static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didChangeSelection(notificationName);
1600 }
1601
1602 bool InjectedBundlePage::shouldBeginEditing(WKBundleRangeHandleRef range)
1603 {
1604     auto& injectedBundle = InjectedBundle::singleton();
1605     if (!injectedBundle.isTestRunning())
1606         return true;
1607
1608     if (injectedBundle.testRunner()->shouldDumpEditingCallbacks()) {
1609         StringBuilder stringBuilder;
1610         stringBuilder.appendLiteral("EDITING DELEGATE: shouldBeginEditingInDOMRange:");
1611         stringBuilder.append(rangeToStr(m_page, m_world.get(), range));
1612         stringBuilder.append('\n');
1613         injectedBundle.outputText(stringBuilder.toString());
1614     }
1615     return injectedBundle.testRunner()->shouldAllowEditing();
1616 }
1617
1618 bool InjectedBundlePage::shouldEndEditing(WKBundleRangeHandleRef range)
1619 {
1620     auto& injectedBundle = InjectedBundle::singleton();
1621     if (!injectedBundle.isTestRunning())
1622         return true;
1623
1624     if (injectedBundle.testRunner()->shouldDumpEditingCallbacks()) {
1625         StringBuilder stringBuilder;
1626         stringBuilder.appendLiteral("EDITING DELEGATE: shouldEndEditingInDOMRange:");
1627         stringBuilder.append(rangeToStr(m_page, m_world.get(), range));
1628         stringBuilder.append('\n');
1629         injectedBundle.outputText(stringBuilder.toString());
1630     }
1631     return injectedBundle.testRunner()->shouldAllowEditing();
1632 }
1633
1634 bool InjectedBundlePage::shouldInsertNode(WKBundleNodeHandleRef node, WKBundleRangeHandleRef rangeToReplace, WKInsertActionType action)
1635 {
1636     auto& injectedBundle = InjectedBundle::singleton();
1637     if (!injectedBundle.isTestRunning())
1638         return true;
1639
1640     static const char* insertactionstring[] = {
1641         "WebViewInsertActionTyped",
1642         "WebViewInsertActionPasted",
1643         "WebViewInsertActionDropped",
1644     };
1645
1646     if (injectedBundle.testRunner()->shouldDumpEditingCallbacks()) {
1647         StringBuilder stringBuilder;
1648         stringBuilder.appendLiteral("EDITING DELEGATE: shouldInsertNode:");
1649         stringBuilder.append(dumpPath(m_page, m_world.get(), node));
1650         stringBuilder.appendLiteral(" replacingDOMRange:");
1651         stringBuilder.append(rangeToStr(m_page, m_world.get(), rangeToReplace));
1652         stringBuilder.appendLiteral(" givenAction:");
1653         stringBuilder.append(insertactionstring[action]);
1654         stringBuilder.append('\n');
1655         injectedBundle.outputText(stringBuilder.toString());
1656     }
1657     return injectedBundle.testRunner()->shouldAllowEditing();
1658 }
1659
1660 bool InjectedBundlePage::shouldInsertText(WKStringRef text, WKBundleRangeHandleRef rangeToReplace, WKInsertActionType action)
1661 {
1662     auto& injectedBundle = InjectedBundle::singleton();
1663     if (!injectedBundle.isTestRunning())
1664         return true;
1665
1666     static const char *insertactionstring[] = {
1667         "WebViewInsertActionTyped",
1668         "WebViewInsertActionPasted",
1669         "WebViewInsertActionDropped",
1670     };
1671
1672     if (injectedBundle.testRunner()->shouldDumpEditingCallbacks()) {
1673         StringBuilder stringBuilder;
1674         stringBuilder.appendLiteral("EDITING DELEGATE: shouldInsertText:");
1675         stringBuilder.append(toWTFString(text));
1676         stringBuilder.appendLiteral(" replacingDOMRange:");
1677         stringBuilder.append(rangeToStr(m_page, m_world.get(), rangeToReplace));
1678         stringBuilder.appendLiteral(" givenAction:");
1679         stringBuilder.append(insertactionstring[action]);
1680         stringBuilder.append('\n');
1681         injectedBundle.outputText(stringBuilder.toString());
1682     }
1683     return injectedBundle.testRunner()->shouldAllowEditing();
1684 }
1685
1686 bool InjectedBundlePage::shouldDeleteRange(WKBundleRangeHandleRef range)
1687 {
1688     auto& injectedBundle = InjectedBundle::singleton();
1689     if (!injectedBundle.isTestRunning())
1690         return true;
1691
1692     if (injectedBundle.testRunner()->shouldDumpEditingCallbacks()) {
1693         StringBuilder stringBuilder;
1694         stringBuilder.appendLiteral("EDITING DELEGATE: shouldDeleteDOMRange:");
1695         stringBuilder.append(rangeToStr(m_page, m_world.get(), range));
1696         stringBuilder.append('\n');
1697         injectedBundle.outputText(stringBuilder.toString());
1698     }
1699     return injectedBundle.testRunner()->shouldAllowEditing();
1700 }
1701
1702 bool InjectedBundlePage::shouldChangeSelectedRange(WKBundleRangeHandleRef fromRange, WKBundleRangeHandleRef toRange, WKAffinityType affinity, bool stillSelecting)
1703 {
1704     auto& injectedBundle = InjectedBundle::singleton();
1705     if (!injectedBundle.isTestRunning())
1706         return true;
1707
1708     static const char *affinitystring[] = {
1709         "NSSelectionAffinityUpstream",
1710         "NSSelectionAffinityDownstream"
1711     };
1712     static const char *boolstring[] = {
1713         "FALSE",
1714         "TRUE"
1715     };
1716
1717     if (injectedBundle.testRunner()->shouldDumpEditingCallbacks()) {
1718         StringBuilder stringBuilder;
1719         stringBuilder.appendLiteral("EDITING DELEGATE: shouldChangeSelectedDOMRange:");
1720         stringBuilder.append(rangeToStr(m_page, m_world.get(), fromRange));
1721         stringBuilder.appendLiteral(" toDOMRange:");
1722         stringBuilder.append(rangeToStr(m_page, m_world.get(), toRange));
1723         stringBuilder.appendLiteral(" affinity:");
1724         stringBuilder.append(affinitystring[affinity]); 
1725         stringBuilder.appendLiteral(" stillSelecting:");
1726         stringBuilder.append(boolstring[stillSelecting]); 
1727         stringBuilder.append('\n');
1728         injectedBundle.outputText(stringBuilder.toString());
1729     }
1730     return injectedBundle.testRunner()->shouldAllowEditing();
1731 }
1732
1733 bool InjectedBundlePage::shouldApplyStyle(WKBundleCSSStyleDeclarationRef style, WKBundleRangeHandleRef range)
1734 {
1735     auto& injectedBundle = InjectedBundle::singleton();
1736     if (!injectedBundle.isTestRunning())
1737         return true;
1738
1739     if (injectedBundle.testRunner()->shouldDumpEditingCallbacks()) {
1740         StringBuilder stringBuilder;
1741         stringBuilder.appendLiteral("EDITING DELEGATE: shouldApplyStyle:");
1742         stringBuilder.append(styleDecToStr(style));
1743         stringBuilder.appendLiteral(" toElementsInDOMRange:");
1744         stringBuilder.append(rangeToStr(m_page, m_world.get(), range));
1745         stringBuilder.append('\n');
1746         injectedBundle.outputText(stringBuilder.toString());
1747     }
1748     return injectedBundle.testRunner()->shouldAllowEditing();
1749 }
1750
1751 void InjectedBundlePage::didBeginEditing(WKStringRef notificationName)
1752 {
1753     auto& injectedBundle = InjectedBundle::singleton();
1754     if (!injectedBundle.isTestRunning())
1755         return;
1756     if (!injectedBundle.testRunner()->shouldDumpEditingCallbacks())
1757         return;
1758
1759     StringBuilder stringBuilder;
1760     stringBuilder.appendLiteral("EDITING DELEGATE: webViewDidBeginEditing:");
1761     stringBuilder.append(toWTFString(notificationName));
1762     stringBuilder.append('\n');
1763     injectedBundle.outputText(stringBuilder.toString());
1764 }
1765
1766 void InjectedBundlePage::didEndEditing(WKStringRef notificationName)
1767 {
1768     auto& injectedBundle = InjectedBundle::singleton();
1769     if (!injectedBundle.isTestRunning())
1770         return;
1771     if (!injectedBundle.testRunner()->shouldDumpEditingCallbacks())
1772         return;
1773
1774     StringBuilder stringBuilder;
1775     stringBuilder.appendLiteral("EDITING DELEGATE: webViewDidEndEditing:");
1776     stringBuilder.append(toWTFString(notificationName));
1777     stringBuilder.append('\n');
1778     injectedBundle.outputText(stringBuilder.toString());
1779 }
1780
1781 void InjectedBundlePage::didChange(WKStringRef notificationName)
1782 {
1783     auto& injectedBundle = InjectedBundle::singleton();
1784     if (!injectedBundle.isTestRunning())
1785         return;
1786     if (!injectedBundle.testRunner()->shouldDumpEditingCallbacks())
1787         return;
1788
1789     StringBuilder stringBuilder;
1790     stringBuilder.appendLiteral("EDITING DELEGATE: webViewDidChange:");
1791     stringBuilder.append(toWTFString(notificationName));
1792     stringBuilder.append('\n');
1793     injectedBundle.outputText(stringBuilder.toString());
1794 }
1795
1796 void InjectedBundlePage::didChangeSelection(WKStringRef notificationName)
1797 {
1798     auto& injectedBundle = InjectedBundle::singleton();
1799     if (!injectedBundle.isTestRunning())
1800         return;
1801     if (!injectedBundle.testRunner()->shouldDumpEditingCallbacks())
1802         return;
1803
1804     StringBuilder stringBuilder;
1805     stringBuilder.appendLiteral("EDITING DELEGATE: webViewDidChangeSelection:");
1806     stringBuilder.append(toWTFString(notificationName));
1807     stringBuilder.append('\n');
1808     injectedBundle.outputText(stringBuilder.toString());
1809 }
1810
1811 #if ENABLE(FULLSCREEN_API)
1812 bool InjectedBundlePage::supportsFullScreen(WKBundlePageRef pageRef, WKFullScreenKeyboardRequestType requestType)
1813 {
1814     auto& injectedBundle = InjectedBundle::singleton();
1815     if (injectedBundle.testRunner()->shouldDumpFullScreenCallbacks())
1816         injectedBundle.outputText("supportsFullScreen() == true\n");
1817     return true;
1818 }
1819
1820 void InjectedBundlePage::enterFullScreenForElement(WKBundlePageRef pageRef, WKBundleNodeHandleRef elementRef)
1821 {
1822     auto& injectedBundle = InjectedBundle::singleton();
1823     if (injectedBundle.testRunner()->shouldDumpFullScreenCallbacks())
1824         injectedBundle.outputText("enterFullScreenForElement()\n");
1825
1826     if (!injectedBundle.testRunner()->hasCustomFullScreenBehavior()) {
1827         WKBundlePageWillEnterFullScreen(pageRef);
1828         WKBundlePageDidEnterFullScreen(pageRef);
1829     }
1830 }
1831
1832 void InjectedBundlePage::exitFullScreenForElement(WKBundlePageRef pageRef, WKBundleNodeHandleRef elementRef)
1833 {
1834     auto& injectedBundle = InjectedBundle::singleton();
1835     if (injectedBundle.testRunner()->shouldDumpFullScreenCallbacks())
1836         injectedBundle.outputText("exitFullScreenForElement()\n");
1837
1838     if (!injectedBundle.testRunner()->hasCustomFullScreenBehavior()) {
1839         WKBundlePageWillExitFullScreen(pageRef);
1840         WKBundlePageDidExitFullScreen(pageRef);
1841     }
1842 }
1843
1844 void InjectedBundlePage::beganEnterFullScreen(WKBundlePageRef, WKRect, WKRect)
1845 {
1846     auto& injectedBundle = InjectedBundle::singleton();
1847     if (injectedBundle.testRunner()->shouldDumpFullScreenCallbacks())
1848         injectedBundle.outputText("beganEnterFullScreen()\n");
1849 }
1850
1851 void InjectedBundlePage::beganExitFullScreen(WKBundlePageRef, WKRect, WKRect)
1852 {
1853     auto& injectedBundle = InjectedBundle::singleton();
1854     if (injectedBundle.testRunner()->shouldDumpFullScreenCallbacks())
1855         injectedBundle.outputText("beganExitFullScreen()\n");
1856 }
1857
1858 void InjectedBundlePage::closeFullScreen(WKBundlePageRef pageRef)
1859 {
1860     auto& injectedBundle = InjectedBundle::singleton();
1861     if (injectedBundle.testRunner()->shouldDumpFullScreenCallbacks())
1862         injectedBundle.outputText("closeFullScreen()\n");
1863
1864     if (!injectedBundle.testRunner()->hasCustomFullScreenBehavior()) {
1865         WKBundlePageWillExitFullScreen(pageRef);
1866         WKBundlePageDidExitFullScreen(pageRef);
1867     }
1868 }
1869 #endif
1870
1871 static bool compareByTargetName(WKBundleBackForwardListItemRef item1, WKBundleBackForwardListItemRef item2)
1872 {
1873     return toSTD(adoptWK(WKBundleBackForwardListItemCopyTarget(item1))) < toSTD(adoptWK(WKBundleBackForwardListItemCopyTarget(item2)));
1874 }
1875
1876 static void dumpBackForwardListItem(WKBundleBackForwardListItemRef item, unsigned indent, bool isCurrentItem, StringBuilder& stringBuilder)
1877 {
1878     unsigned column = 0;
1879     if (isCurrentItem) {
1880         stringBuilder.appendLiteral("curr->");
1881         column = 6;
1882     }
1883     for (unsigned i = column; i < indent; i++)
1884         stringBuilder.append(' ');
1885
1886     WTF::String url = toWTFString(adoptWK(WKURLCopyString(adoptWK(WKBundleBackForwardListItemCopyURL(item)).get())));
1887     if (hasPrefix(url, "file:")) {
1888         WTF::String directoryName = "/LayoutTests/";
1889         size_t start = url.find(directoryName);
1890         if (start == WTF::notFound)
1891             start = 0;
1892         else
1893             start += directoryName.length();
1894         stringBuilder.appendLiteral("(file test):");
1895         stringBuilder.append(url.substring(start));
1896     } else
1897         stringBuilder.append(url);
1898
1899     WTF::String target = toWTFString(adoptWK(WKBundleBackForwardListItemCopyTarget(item)));
1900     if (target.length()) {
1901         stringBuilder.appendLiteral(" (in frame \"");
1902         stringBuilder.append(target);
1903         stringBuilder.appendLiteral("\")");
1904     }
1905
1906     // FIXME: Need WKBackForwardListItemIsTargetItem.
1907     if (WKBundleBackForwardListItemIsTargetItem(item))
1908         stringBuilder.appendLiteral("  **nav target**");
1909
1910     stringBuilder.append('\n');
1911
1912     if (WKRetainPtr<WKArrayRef> kids = adoptWK(WKBundleBackForwardListItemCopyChildren(item))) {
1913         // Sort to eliminate arbitrary result ordering which defeats reproducible testing.
1914         size_t size = WKArrayGetSize(kids.get());
1915         Vector<WKBundleBackForwardListItemRef> sortedKids(size);
1916         for (size_t i = 0; i < size; ++i)
1917             sortedKids[i] = static_cast<WKBundleBackForwardListItemRef>(WKArrayGetItemAtIndex(kids.get(), i));
1918         stable_sort(sortedKids.begin(), sortedKids.end(), compareByTargetName);
1919         for (size_t i = 0; i < size; ++i)
1920             dumpBackForwardListItem(sortedKids[i], indent + 4, false, stringBuilder);
1921     }
1922 }
1923
1924 void InjectedBundlePage::dumpBackForwardList(StringBuilder& stringBuilder)
1925 {
1926     stringBuilder.appendLiteral("\n============== Back Forward List ==============\n");
1927
1928     WKBundleBackForwardListRef list = WKBundlePageGetBackForwardList(m_page);
1929
1930     // Print out all items in the list after m_previousTestBackForwardListItem.
1931     // Gather items from the end of the list, then print them out from oldest to newest.
1932     Vector<WKRetainPtr<WKBundleBackForwardListItemRef> > itemsToPrint;
1933     for (unsigned i = WKBundleBackForwardListGetForwardListCount(list); i; --i) {
1934         WKRetainPtr<WKBundleBackForwardListItemRef> item = adoptWK(WKBundleBackForwardListCopyItemAtIndex(list, i));
1935         // Something is wrong if the item from the last test is in the forward part of the list.
1936         ASSERT(!WKBundleBackForwardListItemIsSame(item.get(), m_previousTestBackForwardListItem.get()));
1937         itemsToPrint.append(item);
1938     }
1939
1940     ASSERT(!WKBundleBackForwardListItemIsSame(adoptWK(WKBundleBackForwardListCopyItemAtIndex(list, 0)).get(), m_previousTestBackForwardListItem.get()));
1941
1942     itemsToPrint.append(adoptWK(WKBundleBackForwardListCopyItemAtIndex(list, 0)));
1943
1944     int currentItemIndex = itemsToPrint.size() - 1;
1945
1946     int backListCount = WKBundleBackForwardListGetBackListCount(list);
1947     for (int i = -1; i >= -backListCount; --i) {
1948         WKRetainPtr<WKBundleBackForwardListItemRef> item = adoptWK(WKBundleBackForwardListCopyItemAtIndex(list, i));
1949         if (WKBundleBackForwardListItemIsSame(item.get(), m_previousTestBackForwardListItem.get()))
1950             break;
1951         itemsToPrint.append(item);
1952     }
1953
1954     for (int i = itemsToPrint.size() - 1; i >= 0; i--)
1955         dumpBackForwardListItem(itemsToPrint[i].get(), 8, i == currentItemIndex, stringBuilder);
1956
1957     stringBuilder.appendLiteral("===============================================\n");
1958 }
1959
1960 #if !PLATFORM(COCOA)
1961 void InjectedBundlePage::platformDidStartProvisionalLoadForFrame(WKBundleFrameRef)
1962 {
1963 }
1964
1965 String InjectedBundlePage::platformResponseMimeType(WKURLResponseRef)
1966 {
1967     return String();
1968 }
1969 #endif
1970
1971 void InjectedBundlePage::frameDidChangeLocation(WKBundleFrameRef frame, bool shouldDump)
1972 {
1973     auto& injectedBundle = InjectedBundle::singleton();
1974     if (frame != injectedBundle.topLoadingFrame())
1975         return;
1976
1977     injectedBundle.setTopLoadingFrame(nullptr);
1978
1979     if (injectedBundle.testRunner()->waitToDump())
1980         return;
1981
1982     if (injectedBundle.shouldProcessWorkQueue()) {
1983         injectedBundle.processWorkQueue();
1984         return;
1985     }
1986
1987     if (shouldDump)
1988         injectedBundle.page()->dump();
1989     else
1990         injectedBundle.done();
1991 }
1992
1993 } // namespace WTR