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