aed6e4c2a6d60e1b6793ac723bab063c7d9e1afa
[WebKit-https.git] / Tools / WebKitTestRunner / InjectedBundle / TestRunner.cpp
1 /*
2  * Copyright (C) 2010-2017 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 "TestRunner.h"
28
29 #include "InjectedBundle.h"
30 #include "InjectedBundlePage.h"
31 #include "JSTestRunner.h"
32 #include "PlatformWebView.h"
33 #include "StringFunctions.h"
34 #include "TestController.h"
35 #include <JavaScriptCore/JSCTestRunnerUtils.h>
36 #include <WebCore/ResourceLoadObserver.h>
37 #include <WebKit/WKBundle.h>
38 #include <WebKit/WKBundleBackForwardList.h>
39 #include <WebKit/WKBundleFrame.h>
40 #include <WebKit/WKBundleFramePrivate.h>
41 #include <WebKit/WKBundleInspector.h>
42 #include <WebKit/WKBundleNodeHandlePrivate.h>
43 #include <WebKit/WKBundlePage.h>
44 #include <WebKit/WKBundlePagePrivate.h>
45 #include <WebKit/WKBundlePrivate.h>
46 #include <WebKit/WKBundleScriptWorld.h>
47 #include <WebKit/WKData.h>
48 #include <WebKit/WKPagePrivate.h>
49 #include <WebKit/WKRetainPtr.h>
50 #include <WebKit/WKSerializedScriptValue.h>
51 #include <WebKit/WebKit2_C.h>
52 #include <wtf/CurrentTime.h>
53 #include <wtf/HashMap.h>
54 #include <wtf/StdLibExtras.h>
55 #include <wtf/text/CString.h>
56 #include <wtf/text/StringBuilder.h>
57
58 namespace WTR {
59
60 Ref<TestRunner> TestRunner::create()
61 {
62     return adoptRef(*new TestRunner);
63 }
64
65 TestRunner::TestRunner()
66     : m_whatToDump(RenderTree)
67     , m_shouldDumpAllFrameScrollPositions(false)
68     , m_shouldDumpBackForwardListsForAllWindows(false)
69     , m_shouldAllowEditing(true)
70     , m_shouldCloseExtraWindows(false)
71     , m_dumpEditingCallbacks(false)
72     , m_dumpStatusCallbacks(false)
73     , m_dumpTitleChanges(false)
74     , m_dumpPixels(true)
75     , m_dumpSelectionRect(false)
76     , m_dumpFullScreenCallbacks(false)
77     , m_dumpFrameLoadCallbacks(false)
78     , m_dumpProgressFinishedCallback(false)
79     , m_dumpResourceLoadCallbacks(false)
80     , m_dumpResourceResponseMIMETypes(false)
81     , m_dumpWillCacheResponse(false)
82     , m_dumpApplicationCacheDelegateCallbacks(false)
83     , m_dumpDatabaseCallbacks(false)
84     , m_disallowIncreaseForApplicationCacheQuota(false)
85     , m_waitToDump(false)
86     , m_testRepaint(false)
87     , m_testRepaintSweepHorizontally(false)
88     , m_isPrinting(false)
89     , m_willSendRequestReturnsNull(false)
90     , m_willSendRequestReturnsNullOnRedirect(false)
91     , m_shouldStopProvisionalFrameLoads(false)
92     , m_policyDelegateEnabled(false)
93     , m_policyDelegatePermissive(false)
94     , m_globalFlag(false)
95     , m_customFullScreenBehavior(false)
96     , m_timeout(30000)
97     , m_databaseDefaultQuota(-1)
98     , m_databaseMaxQuota(-1)
99     , m_userStyleSheetEnabled(false)
100     , m_userStyleSheetLocation(adoptWK(WKStringCreateWithUTF8CString("")))
101 #if PLATFORM(GTK) || PLATFORM(WPE)
102     , m_waitToDumpWatchdogTimer(RunLoop::main(), this, &TestRunner::waitToDumpWatchdogTimerFired)
103 #endif
104 {
105     platformInitialize();
106 }
107
108 TestRunner::~TestRunner()
109 {
110 }
111
112 JSClassRef TestRunner::wrapperClass()
113 {
114     return JSTestRunner::testRunnerClass();
115 }
116
117 void TestRunner::display()
118 {
119     WKBundlePageRef page = InjectedBundle::singleton().page()->page();
120     WKBundlePageForceRepaint(page);
121 }
122
123 void TestRunner::displayAndTrackRepaints()
124 {
125     WKBundlePageRef page = InjectedBundle::singleton().page()->page();
126     WKBundlePageForceRepaint(page);
127     WKBundlePageSetTracksRepaints(page, true);
128     WKBundlePageResetTrackedRepaints(page);
129 }
130
131 void TestRunner::dumpAsText(bool dumpPixels)
132 {
133     if (m_whatToDump < MainFrameText)
134         m_whatToDump = MainFrameText;
135     m_dumpPixels = dumpPixels;
136 }
137
138 void TestRunner::setCustomPolicyDelegate(bool enabled, bool permissive)
139 {
140     m_policyDelegateEnabled = enabled;
141     m_policyDelegatePermissive = permissive;
142
143     InjectedBundle::singleton().setCustomPolicyDelegate(enabled, permissive);
144 }
145
146 void TestRunner::waitForPolicyDelegate()
147 {
148     setCustomPolicyDelegate(true);
149     waitUntilDone();
150 }
151
152 void TestRunner::waitUntilDownloadFinished()
153 {
154     m_shouldFinishAfterDownload = true;
155     waitUntilDone();
156 }
157
158 void TestRunner::waitUntilDone()
159 {
160     m_waitToDump = true;
161     if (InjectedBundle::singleton().useWaitToDumpWatchdogTimer())
162         initializeWaitToDumpWatchdogTimerIfNeeded();
163 }
164
165 void TestRunner::waitToDumpWatchdogTimerFired()
166 {
167     invalidateWaitToDumpWatchdogTimer();
168     auto& injectedBundle = InjectedBundle::singleton();
169 #if PLATFORM(COCOA)
170     char buffer[1024];
171     snprintf(buffer, sizeof(buffer), "#PID UNRESPONSIVE - %s (pid %d)\n", getprogname(), getpid());
172     injectedBundle.outputText(buffer);
173 #endif
174     injectedBundle.outputText("FAIL: Timed out waiting for notifyDone to be called\n\n");
175     injectedBundle.done();
176 }
177
178 void TestRunner::notifyDone()
179 {
180     auto& injectedBundle = InjectedBundle::singleton();
181     if (!injectedBundle.isTestRunning())
182         return;
183
184     if (m_waitToDump && !injectedBundle.topLoadingFrame())
185         injectedBundle.page()->dump();
186
187     // We don't call invalidateWaitToDumpWatchdogTimer() here, even if we continue to wait for a load to finish.
188     // The test is still subject to timeout checking - it is better to detect an async timeout inside WebKitTestRunner
189     // than to let webkitpy do that, because WebKitTestRunner will dump partial results.
190
191     m_waitToDump = false;
192 }
193
194 void TestRunner::forceImmediateCompletion()
195 {
196     auto& injectedBundle = InjectedBundle::singleton();
197     if (!injectedBundle.isTestRunning())
198         return;
199
200     if (m_waitToDump && injectedBundle.page())
201         injectedBundle.page()->dump();
202
203     m_waitToDump = false;
204 }
205
206 unsigned TestRunner::imageCountInGeneralPasteboard() const
207 {
208     return InjectedBundle::singleton().imageCountInGeneralPasteboard();
209 }
210
211 void TestRunner::addUserScript(JSStringRef source, bool runAtStart, bool allFrames)
212 {
213     WKRetainPtr<WKStringRef> sourceWK = toWK(source);
214
215     WKBundlePageAddUserScript(InjectedBundle::singleton().page()->page(), sourceWK.get(),
216         (runAtStart ? kWKInjectAtDocumentStart : kWKInjectAtDocumentEnd),
217         (allFrames ? kWKInjectInAllFrames : kWKInjectInTopFrameOnly));
218 }
219
220 void TestRunner::addUserStyleSheet(JSStringRef source, bool allFrames)
221 {
222     WKRetainPtr<WKStringRef> sourceWK = toWK(source);
223
224     WKBundlePageAddUserStyleSheet(InjectedBundle::singleton().page()->page(), sourceWK.get(),
225         (allFrames ? kWKInjectInAllFrames : kWKInjectInTopFrameOnly));
226 }
227
228 void TestRunner::keepWebHistory()
229 {
230     InjectedBundle::singleton().postSetAddsVisitedLinks(true);
231 }
232
233 void TestRunner::execCommand(JSStringRef name, JSStringRef argument)
234 {
235     WKBundlePageExecuteEditingCommand(InjectedBundle::singleton().page()->page(), toWK(name).get(), toWK(argument).get());
236 }
237
238 bool TestRunner::findString(JSStringRef target, JSValueRef optionsArrayAsValue)
239 {
240     WKFindOptions options = 0;
241
242     auto& injectedBundle = InjectedBundle::singleton();
243     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(injectedBundle.page()->page());
244     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
245     JSRetainPtr<JSStringRef> lengthPropertyName(Adopt, JSStringCreateWithUTF8CString("length"));
246     JSObjectRef optionsArray = JSValueToObject(context, optionsArrayAsValue, 0);
247     JSValueRef lengthValue = JSObjectGetProperty(context, optionsArray, lengthPropertyName.get(), 0);
248     if (!JSValueIsNumber(context, lengthValue))
249         return false;
250
251     size_t length = static_cast<size_t>(JSValueToNumber(context, lengthValue, 0));
252     for (size_t i = 0; i < length; ++i) {
253         JSValueRef value = JSObjectGetPropertyAtIndex(context, optionsArray, i, 0);
254         if (!JSValueIsString(context, value))
255             continue;
256
257         JSRetainPtr<JSStringRef> optionName(Adopt, JSValueToStringCopy(context, value, 0));
258
259         if (JSStringIsEqualToUTF8CString(optionName.get(), "CaseInsensitive"))
260             options |= kWKFindOptionsCaseInsensitive;
261         else if (JSStringIsEqualToUTF8CString(optionName.get(), "AtWordStarts"))
262             options |= kWKFindOptionsAtWordStarts;
263         else if (JSStringIsEqualToUTF8CString(optionName.get(), "TreatMedialCapitalAsWordStart"))
264             options |= kWKFindOptionsTreatMedialCapitalAsWordStart;
265         else if (JSStringIsEqualToUTF8CString(optionName.get(), "Backwards"))
266             options |= kWKFindOptionsBackwards;
267         else if (JSStringIsEqualToUTF8CString(optionName.get(), "WrapAround"))
268             options |= kWKFindOptionsWrapAround;
269         else if (JSStringIsEqualToUTF8CString(optionName.get(), "StartInSelection")) {
270             // FIXME: No kWKFindOptionsStartInSelection.
271         }
272     }
273
274     return WKBundlePageFindString(injectedBundle.page()->page(), toWK(target).get(), options);
275 }
276
277 void TestRunner::clearAllDatabases()
278 {
279     WKBundleClearAllDatabases(InjectedBundle::singleton().bundle());
280
281     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("DeleteAllIndexedDatabases"));
282     WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(true));
283
284     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
285 }
286
287 void TestRunner::setDatabaseQuota(uint64_t quota)
288 {
289     return WKBundleSetDatabaseQuota(InjectedBundle::singleton().bundle(), quota);
290 }
291
292 void TestRunner::clearAllApplicationCaches()
293 {
294     WKBundlePageClearApplicationCache(InjectedBundle::singleton().page()->page());
295 }
296
297 void TestRunner::clearApplicationCacheForOrigin(JSStringRef origin)
298 {
299     WKBundlePageClearApplicationCacheForOrigin(InjectedBundle::singleton().page()->page(), toWK(origin).get());
300 }
301
302 void TestRunner::setAppCacheMaximumSize(uint64_t size)
303 {
304     WKBundlePageSetAppCacheMaximumSize(InjectedBundle::singleton().page()->page(), size);
305 }
306
307 long long TestRunner::applicationCacheDiskUsageForOrigin(JSStringRef origin)
308 {
309     return WKBundlePageGetAppCacheUsageForOrigin(InjectedBundle::singleton().page()->page(), toWK(origin).get());
310 }
311
312 void TestRunner::disallowIncreaseForApplicationCacheQuota()
313 {
314     m_disallowIncreaseForApplicationCacheQuota = true;
315 }
316
317 static inline JSValueRef stringArrayToJS(JSContextRef context, WKArrayRef strings)
318 {
319     const size_t count = WKArrayGetSize(strings);
320
321     JSValueRef arrayResult = JSObjectMakeArray(context, 0, 0, 0);
322     JSObjectRef arrayObj = JSValueToObject(context, arrayResult, 0);
323     for (size_t i = 0; i < count; ++i) {
324         WKStringRef stringRef = static_cast<WKStringRef>(WKArrayGetItemAtIndex(strings, i));
325         JSRetainPtr<JSStringRef> stringJS = toJS(stringRef);
326         JSObjectSetPropertyAtIndex(context, arrayObj, i, JSValueMakeString(context, stringJS.get()), 0);
327     }
328
329     return arrayResult;
330 }
331
332 JSValueRef TestRunner::originsWithApplicationCache()
333 {
334     WKBundlePageRef page = InjectedBundle::singleton().page()->page();
335
336     WKRetainPtr<WKArrayRef> origins(AdoptWK, WKBundlePageCopyOriginsWithApplicationCache(page));
337
338     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(page);
339     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
340
341     return stringArrayToJS(context, origins.get());
342 }
343
344 bool TestRunner::isCommandEnabled(JSStringRef name)
345 {
346     return WKBundlePageIsEditingCommandEnabled(InjectedBundle::singleton().page()->page(), toWK(name).get());
347 }
348
349 void TestRunner::setCanOpenWindows(bool)
350 {
351     // The test plugins/get-url-with-blank-target.html requires that the embedding client forbid
352     // opening windows (by omitting a call to this function) so as to test that NPN_GetURL()
353     // with a blank target will return an error.
354     //
355     // It is not clear if we should implement this functionality or remove it and plugins/get-url-with-blank-target.html
356     // per the remark in <https://trac.webkit.org/changeset/64504/trunk/LayoutTests/platform/mac-wk2/Skipped>.
357     // For now, just ignore this setting.
358 }
359
360 void TestRunner::setXSSAuditorEnabled(bool enabled)
361 {
362     WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitXSSAuditorEnabled"));
363     auto& injectedBundle = InjectedBundle::singleton();
364     WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
365 }
366
367 void TestRunner::setMediaDevicesEnabled(bool enabled)
368 {
369     WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitMediaDevicesEnabled"));
370     auto& injectedBundle = InjectedBundle::singleton();
371     WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
372 }
373
374 void TestRunner::setWebRTCLegacyAPIEnabled(bool enabled)
375 {
376     WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitWebRTCLegacyAPIEnabled"));
377     auto& injectedBundle = InjectedBundle::singleton();
378     WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
379 }
380
381 void TestRunner::setModernMediaControlsEnabled(bool enabled)
382 {
383     WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitModernMediaControlsEnabled"));
384     auto& injectedBundle = InjectedBundle::singleton();
385     WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
386 }
387
388 void TestRunner::setWebGL2Enabled(bool enabled)
389 {
390     WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitWebGL2Enabled"));
391     auto& injectedBundle = InjectedBundle::singleton();
392     WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
393 }
394
395 void TestRunner::setWebGPUEnabled(bool enabled)
396 {
397     WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitWebGPUEnabled"));
398     auto& injectedBundle = InjectedBundle::singleton();
399     WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
400 }
401
402 void TestRunner::setWritableStreamAPIEnabled(bool enabled)
403 {
404     WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitWritableStreamAPIEnabled"));
405     auto& injectedBundle = InjectedBundle::singleton();
406     WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
407 }
408
409 void TestRunner::setReadableByteStreamAPIEnabled(bool enabled)
410 {
411     WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitReadableByteStreamAPIEnabled"));
412     auto& injectedBundle = InjectedBundle::singleton();
413     WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
414 }
415
416 void TestRunner::setEncryptedMediaAPIEnabled(bool enabled)
417 {
418     WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitEncryptedMediaAPIEnabled"));
419     auto& injectedBundle = InjectedBundle::singleton();
420     WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
421 }
422
423 void TestRunner::setAllowsAnySSLCertificate(bool enabled)
424 {
425     auto& injectedBundle = InjectedBundle::singleton();
426     injectedBundle.setAllowsAnySSLCertificate(enabled);
427
428     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetAllowsAnySSLCertificate"));
429     WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(enabled));
430     WKBundlePagePostSynchronousMessageForTesting(injectedBundle.page()->page(), messageName.get(), messageBody.get(), nullptr);
431 }
432
433 void TestRunner::setAllowUniversalAccessFromFileURLs(bool enabled)
434 {
435     auto& injectedBundle = InjectedBundle::singleton();
436     WKBundleSetAllowUniversalAccessFromFileURLs(injectedBundle.bundle(), injectedBundle.pageGroup(), enabled);
437 }
438
439 void TestRunner::setAllowFileAccessFromFileURLs(bool enabled)
440 {
441     auto& injectedBundle = InjectedBundle::singleton();
442     WKBundleSetAllowFileAccessFromFileURLs(injectedBundle.bundle(), injectedBundle.pageGroup(), enabled);
443 }
444
445 void TestRunner::setNeedsStorageAccessFromFileURLsQuirk(bool needsQuirk)
446 {
447     auto& injectedBundle = InjectedBundle::singleton();
448     WKBundleSetAllowStorageAccessFromFileURLS(injectedBundle.bundle(), injectedBundle.pageGroup(), needsQuirk);
449 }
450     
451 void TestRunner::setPluginsEnabled(bool enabled)
452 {
453     WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitPluginsEnabled"));
454     auto& injectedBundle = InjectedBundle::singleton();
455     WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
456 }
457
458 void TestRunner::setJavaScriptCanAccessClipboard(bool enabled)
459 {
460     auto& injectedBundle = InjectedBundle::singleton();
461     WKBundleSetJavaScriptCanAccessClipboard(injectedBundle.bundle(), injectedBundle.pageGroup(), enabled);
462 }
463
464 void TestRunner::setPrivateBrowsingEnabled(bool enabled)
465 {
466     auto& injectedBundle = InjectedBundle::singleton();
467     WKBundleSetPrivateBrowsingEnabled(injectedBundle.bundle(), injectedBundle.pageGroup(), enabled);
468 }
469
470 void TestRunner::setUseDashboardCompatibilityMode(bool enabled)
471 {
472 #if ENABLE(DASHBOARD_SUPPORT)
473     auto& injectedBundle = InjectedBundle::singleton();
474     WKBundleSetUseDashboardCompatibilityMode(injectedBundle.bundle(), injectedBundle.pageGroup(), enabled);
475 #else
476     UNUSED_PARAM(enabled);
477 #endif
478 }
479     
480 void TestRunner::setPopupBlockingEnabled(bool enabled)
481 {
482     auto& injectedBundle = InjectedBundle::singleton();
483     WKBundleSetPopupBlockingEnabled(injectedBundle.bundle(), injectedBundle.pageGroup(), enabled);
484 }
485
486 void TestRunner::setAuthorAndUserStylesEnabled(bool enabled)
487 {
488     auto& injectedBundle = InjectedBundle::singleton();
489     WKBundleSetAuthorAndUserStylesEnabled(injectedBundle.bundle(), injectedBundle.pageGroup(), enabled);
490 }
491
492 void TestRunner::addOriginAccessWhitelistEntry(JSStringRef sourceOrigin, JSStringRef destinationProtocol, JSStringRef destinationHost, bool allowDestinationSubdomains)
493 {
494     WKBundleAddOriginAccessWhitelistEntry(InjectedBundle::singleton().bundle(), toWK(sourceOrigin).get(), toWK(destinationProtocol).get(), toWK(destinationHost).get(), allowDestinationSubdomains);
495 }
496
497 void TestRunner::removeOriginAccessWhitelistEntry(JSStringRef sourceOrigin, JSStringRef destinationProtocol, JSStringRef destinationHost, bool allowDestinationSubdomains)
498 {
499     WKBundleRemoveOriginAccessWhitelistEntry(InjectedBundle::singleton().bundle(), toWK(sourceOrigin).get(), toWK(destinationProtocol).get(), toWK(destinationHost).get(), allowDestinationSubdomains);
500 }
501
502 bool TestRunner::isPageBoxVisible(int pageIndex)
503 {
504     auto& injectedBundle = InjectedBundle::singleton();
505     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(injectedBundle.page()->page());
506     return WKBundleIsPageBoxVisible(injectedBundle.bundle(), mainFrame, pageIndex);
507 }
508
509 void TestRunner::setValueForUser(JSContextRef context, JSValueRef element, JSStringRef value)
510 {
511     if (!element || !JSValueIsObject(context, element))
512         return;
513
514     WKRetainPtr<WKBundleNodeHandleRef> nodeHandle(AdoptWK, WKBundleNodeHandleCreate(context, const_cast<JSObjectRef>(element)));
515     WKBundleNodeHandleSetHTMLInputElementValueForUser(nodeHandle.get(), toWK(value).get());
516 }
517
518 void TestRunner::setAudioResult(JSContextRef context, JSValueRef data)
519 {
520     auto& injectedBundle = InjectedBundle::singleton();
521     // FIXME (123058): Use a JSC API to get buffer contents once such is exposed.
522     WKRetainPtr<WKDataRef> audioData(AdoptWK, WKBundleCreateWKDataFromUInt8Array(injectedBundle.bundle(), context, data));
523     injectedBundle.setAudioResult(audioData.get());
524     m_whatToDump = Audio;
525     m_dumpPixels = false;
526 }
527
528 unsigned TestRunner::windowCount()
529 {
530     return InjectedBundle::singleton().pageCount();
531 }
532
533 void TestRunner::clearBackForwardList()
534 {
535     WKBundleBackForwardListClear(WKBundlePageGetBackForwardList(InjectedBundle::singleton().page()->page()));
536 }
537
538 // Object Creation
539
540 void TestRunner::makeWindowObject(JSContextRef context, JSObjectRef windowObject, JSValueRef* exception)
541 {
542     setProperty(context, windowObject, "testRunner", this, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete, exception);
543 }
544
545 void TestRunner::showWebInspector()
546 {
547     WKBundleInspectorShow(WKBundlePageGetInspector(InjectedBundle::singleton().page()->page()));
548 }
549
550 void TestRunner::closeWebInspector()
551 {
552     WKBundleInspectorClose(WKBundlePageGetInspector(InjectedBundle::singleton().page()->page()));
553 }
554
555 void TestRunner::evaluateInWebInspector(JSStringRef script)
556 {
557     WKRetainPtr<WKStringRef> scriptWK = toWK(script);
558     WKBundleInspectorEvaluateScriptForTest(WKBundlePageGetInspector(InjectedBundle::singleton().page()->page()), scriptWK.get());
559 }
560
561 typedef WTF::HashMap<unsigned, WKRetainPtr<WKBundleScriptWorldRef> > WorldMap;
562 static WorldMap& worldMap()
563 {
564     static WorldMap& map = *new WorldMap;
565     return map;
566 }
567
568 unsigned TestRunner::worldIDForWorld(WKBundleScriptWorldRef world)
569 {
570     WorldMap::const_iterator end = worldMap().end();
571     for (WorldMap::const_iterator it = worldMap().begin(); it != end; ++it) {
572         if (it->value == world)
573             return it->key;
574     }
575
576     return 0;
577 }
578
579 void TestRunner::evaluateScriptInIsolatedWorld(JSContextRef context, unsigned worldID, JSStringRef script)
580 {
581     // A worldID of 0 always corresponds to a new world. Any other worldID corresponds to a world
582     // that is created once and cached forever.
583     WKRetainPtr<WKBundleScriptWorldRef> world;
584     if (!worldID)
585         world.adopt(WKBundleScriptWorldCreateWorld());
586     else {
587         WKRetainPtr<WKBundleScriptWorldRef>& worldSlot = worldMap().add(worldID, nullptr).iterator->value;
588         if (!worldSlot)
589             worldSlot.adopt(WKBundleScriptWorldCreateWorld());
590         world = worldSlot;
591     }
592
593     WKBundleFrameRef frame = WKBundleFrameForJavaScriptContext(context);
594     if (!frame)
595         frame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
596
597     JSGlobalContextRef jsContext = WKBundleFrameGetJavaScriptContextForWorld(frame, world.get());
598     JSEvaluateScript(jsContext, script, 0, 0, 0, 0); 
599 }
600
601 void TestRunner::setPOSIXLocale(JSStringRef locale)
602 {
603     char localeBuf[32];
604     JSStringGetUTF8CString(locale, localeBuf, sizeof(localeBuf));
605     setlocale(LC_ALL, localeBuf);
606 }
607
608 void TestRunner::setTextDirection(JSStringRef direction)
609 {
610     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
611     return WKBundleFrameSetTextDirection(mainFrame, toWK(direction).get());
612 }
613     
614 void TestRunner::setShouldStayOnPageAfterHandlingBeforeUnload(bool shouldStayOnPage)
615 {
616     InjectedBundle::singleton().postNewBeforeUnloadReturnValue(!shouldStayOnPage);
617 }
618
619 void TestRunner::setDefersLoading(bool shouldDeferLoading)
620 {
621     WKBundlePageSetDefersLoading(InjectedBundle::singleton().page()->page(), shouldDeferLoading);
622 }
623
624 void TestRunner::setPageVisibility(JSStringRef state)
625 {
626     InjectedBundle::singleton().setHidden(JSStringIsEqualToUTF8CString(state, "hidden") || JSStringIsEqualToUTF8CString(state, "prerender"));
627 }
628
629 void TestRunner::resetPageVisibility()
630 {
631     InjectedBundle::singleton().setHidden(false);
632 }
633
634 typedef WTF::HashMap<unsigned, JSValueRef> CallbackMap;
635 static CallbackMap& callbackMap()
636 {
637     static CallbackMap& map = *new CallbackMap;
638     return map;
639 }
640
641 enum {
642     AddChromeInputFieldCallbackID = 1,
643     RemoveChromeInputFieldCallbackID,
644     FocusWebViewCallbackID,
645     SetBackingScaleFactorCallbackID,
646     DidBeginSwipeCallbackID,
647     WillEndSwipeCallbackID,
648     DidEndSwipeCallbackID,
649     DidRemoveSwipeSnapshotCallbackID,
650     StatisticsDidModifyDataRecordsCallbackID,
651     StatisticsDidScanDataRecordsCallbackID,
652     StatisticsDidRunTelemetryCallbackID,
653     StatisticsDidClearThroughWebsiteDataRemovalCallbackID,
654     StatisticsDidSetPartitionOrBlockCookiesForHostCallbackID,
655     AllStorageAccessEntriesCallbackID,
656     DidRemoveAllSessionCredentialsCallbackID,
657     GetApplicationManifestCallbackID,
658     FirstUIScriptCallbackID = 100
659 };
660
661 static void cacheTestRunnerCallback(unsigned index, JSValueRef callback)
662 {
663     if (!callback)
664         return;
665
666     if (callbackMap().contains(index)) {
667         InjectedBundle::singleton().outputText(String::format("FAIL: Tried to install a second TestRunner callback for the same event (id %d)\n\n", index));
668         return;
669     }
670
671     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
672     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
673     JSValueProtect(context, callback);
674     callbackMap().add(index, callback);
675 }
676
677 static void callTestRunnerCallback(unsigned index, size_t argumentCount = 0, const JSValueRef arguments[] = nullptr)
678 {
679     if (!callbackMap().contains(index))
680         return;
681     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
682     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
683     JSObjectRef callback = JSValueToObject(context, callbackMap().take(index), 0);
684     JSObjectCallAsFunction(context, callback, JSContextGetGlobalObject(context), argumentCount, arguments, 0);
685     JSValueUnprotect(context, callback);
686 }
687
688 void TestRunner::clearTestRunnerCallbacks()
689 {
690     for (auto& iter : callbackMap()) {
691         WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
692         JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
693         JSObjectRef callback = JSValueToObject(context, iter.value, 0);
694         JSValueUnprotect(context, callback);
695     }
696
697     callbackMap().clear();
698 }
699
700 void TestRunner::accummulateLogsForChannel(JSStringRef)
701 {
702     // FIXME: Implement getting the call to all processes.
703 }
704
705 void TestRunner::addChromeInputField(JSValueRef callback)
706 {
707     cacheTestRunnerCallback(AddChromeInputFieldCallbackID, callback);
708     InjectedBundle::singleton().postAddChromeInputField();
709 }
710
711 void TestRunner::removeChromeInputField(JSValueRef callback)
712 {
713     cacheTestRunnerCallback(RemoveChromeInputFieldCallbackID, callback);
714     InjectedBundle::singleton().postRemoveChromeInputField();
715 }
716
717 void TestRunner::focusWebView(JSValueRef callback)
718 {
719     cacheTestRunnerCallback(FocusWebViewCallbackID, callback);
720     InjectedBundle::singleton().postFocusWebView();
721 }
722
723 void TestRunner::setBackingScaleFactor(double backingScaleFactor, JSValueRef callback)
724 {
725     cacheTestRunnerCallback(SetBackingScaleFactorCallbackID, callback);
726     InjectedBundle::singleton().postSetBackingScaleFactor(backingScaleFactor);
727 }
728
729 void TestRunner::setWindowIsKey(bool isKey)
730 {
731     InjectedBundle::singleton().postSetWindowIsKey(isKey);
732 }
733
734 void TestRunner::setViewSize(double width, double height)
735 {
736     InjectedBundle::singleton().postSetViewSize(width, height);
737 }
738
739 void TestRunner::callAddChromeInputFieldCallback()
740 {
741     callTestRunnerCallback(AddChromeInputFieldCallbackID);
742 }
743
744 void TestRunner::callRemoveChromeInputFieldCallback()
745 {
746     callTestRunnerCallback(RemoveChromeInputFieldCallbackID);
747 }
748
749 void TestRunner::callFocusWebViewCallback()
750 {
751     callTestRunnerCallback(FocusWebViewCallbackID);
752 }
753
754 void TestRunner::callSetBackingScaleFactorCallback()
755 {
756     callTestRunnerCallback(SetBackingScaleFactorCallbackID);
757 }
758
759 static inline bool toBool(JSStringRef value)
760 {
761     return JSStringIsEqualToUTF8CString(value, "true") || JSStringIsEqualToUTF8CString(value, "1");
762 }
763
764 void TestRunner::overridePreference(JSStringRef preference, JSStringRef value)
765 {
766     auto& injectedBundle = InjectedBundle::singleton();
767     // FIXME: handle non-boolean preferences.
768     WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), toWK(preference).get(), toBool(value));
769 }
770
771 void TestRunner::setAlwaysAcceptCookies(bool accept)
772 {
773     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetAlwaysAcceptCookies"));
774
775     WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(accept));
776
777     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
778 }
779
780 void TestRunner::setCookieStoragePartitioningEnabled(bool enabled)
781 {
782     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetCookieStoragePartitioningEnabled"));
783
784     WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(enabled));
785
786     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
787 }
788
789 double TestRunner::preciseTime()
790 {
791     return WallTime::now().secondsSinceEpoch().seconds();
792 }
793
794 void TestRunner::setUserStyleSheetEnabled(bool enabled)
795 {
796     m_userStyleSheetEnabled = enabled;
797
798     WKRetainPtr<WKStringRef> emptyUrl = adoptWK(WKStringCreateWithUTF8CString(""));
799     WKStringRef location = enabled ? m_userStyleSheetLocation.get() : emptyUrl.get();
800     auto& injectedBundle = InjectedBundle::singleton();
801     WKBundleSetUserStyleSheetLocation(injectedBundle.bundle(), injectedBundle.pageGroup(), location);
802 }
803
804 void TestRunner::setUserStyleSheetLocation(JSStringRef location)
805 {
806     m_userStyleSheetLocation = adoptWK(WKStringCreateWithJSString(location));
807
808     if (m_userStyleSheetEnabled)
809         setUserStyleSheetEnabled(true);
810 }
811
812 void TestRunner::setSpatialNavigationEnabled(bool enabled)
813 {
814     auto& injectedBundle = InjectedBundle::singleton();
815     WKBundleSetSpatialNavigationEnabled(injectedBundle.bundle(), injectedBundle.pageGroup(), enabled);
816 }
817
818 void TestRunner::setTabKeyCyclesThroughElements(bool enabled)
819 {
820     auto& injectedBundle = InjectedBundle::singleton();
821     WKBundleSetTabKeyCyclesThroughElements(injectedBundle.bundle(), injectedBundle.page()->page(), enabled);
822 }
823
824 void TestRunner::setSerializeHTTPLoads()
825 {
826     // WK2 doesn't reorder loads.
827 }
828
829 void TestRunner::dispatchPendingLoadRequests()
830 {
831     // WK2 doesn't keep pending requests.
832 }
833
834 void TestRunner::setCacheModel(int model)
835 {
836     InjectedBundle::singleton().setCacheModel(model);
837 }
838
839 void TestRunner::setAsynchronousSpellCheckingEnabled(bool enabled)
840 {
841     auto& injectedBundle = InjectedBundle::singleton();
842     WKBundleSetAsynchronousSpellCheckingEnabled(injectedBundle.bundle(), injectedBundle.pageGroup(), enabled);
843 }
844
845 void TestRunner::grantWebNotificationPermission(JSStringRef origin)
846 {
847     WKRetainPtr<WKStringRef> originWK = toWK(origin);
848     auto& injectedBundle = InjectedBundle::singleton();
849     WKBundleSetWebNotificationPermission(injectedBundle.bundle(), injectedBundle.page()->page(), originWK.get(), true);
850 }
851
852 void TestRunner::denyWebNotificationPermission(JSStringRef origin)
853 {
854     WKRetainPtr<WKStringRef> originWK = toWK(origin);
855     auto& injectedBundle = InjectedBundle::singleton();
856     WKBundleSetWebNotificationPermission(injectedBundle.bundle(), injectedBundle.page()->page(), originWK.get(), false);
857 }
858
859 void TestRunner::removeAllWebNotificationPermissions()
860 {
861     auto& injectedBundle = InjectedBundle::singleton();
862     WKBundleRemoveAllWebNotificationPermissions(injectedBundle.bundle(), injectedBundle.page()->page());
863 }
864
865 void TestRunner::simulateWebNotificationClick(JSValueRef notification)
866 {
867     auto& injectedBundle = InjectedBundle::singleton();
868     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(injectedBundle.page()->page());
869     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
870     uint64_t notificationID = WKBundleGetWebNotificationID(injectedBundle.bundle(), context, notification);
871     injectedBundle.postSimulateWebNotificationClick(notificationID);
872 }
873
874 void TestRunner::setGeolocationPermission(bool enabled)
875 {
876     // FIXME: this should be done by frame.
877     InjectedBundle::singleton().setGeolocationPermission(enabled);
878 }
879
880 bool TestRunner::isGeolocationProviderActive()
881 {
882     return InjectedBundle::singleton().isGeolocationProviderActive();
883 }
884
885 void TestRunner::setMockGeolocationPosition(double latitude, double longitude, double accuracy, JSValueRef jsAltitude, JSValueRef jsAltitudeAccuracy, JSValueRef jsHeading, JSValueRef jsSpeed, JSValueRef jsFloorLevel)
886 {
887     auto& injectedBundle = InjectedBundle::singleton();
888     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(injectedBundle.page()->page());
889     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
890
891     bool providesAltitude = false;
892     double altitude = 0.;
893     if (!JSValueIsUndefined(context, jsAltitude)) {
894         providesAltitude = true;
895         altitude = JSValueToNumber(context, jsAltitude, 0);
896     }
897
898     bool providesAltitudeAccuracy = false;
899     double altitudeAccuracy = 0.;
900     if (!JSValueIsUndefined(context, jsAltitudeAccuracy)) {
901         providesAltitudeAccuracy = true;
902         altitudeAccuracy = JSValueToNumber(context, jsAltitudeAccuracy, 0);
903     }
904
905     bool providesHeading = false;
906     double heading = 0.;
907     if (!JSValueIsUndefined(context, jsHeading)) {
908         providesHeading = true;
909         heading = JSValueToNumber(context, jsHeading, 0);
910     }
911
912     bool providesSpeed = false;
913     double speed = 0.;
914     if (!JSValueIsUndefined(context, jsSpeed)) {
915         providesSpeed = true;
916         speed = JSValueToNumber(context, jsSpeed, 0);
917     }
918
919     bool providesFloorLevel = false;
920     double floorLevel = 0.;
921     if (!JSValueIsUndefined(context, jsFloorLevel)) {
922         providesFloorLevel = true;
923         floorLevel = JSValueToNumber(context, jsFloorLevel, 0);
924     }
925
926     injectedBundle.setMockGeolocationPosition(latitude, longitude, accuracy, providesAltitude, altitude, providesAltitudeAccuracy, altitudeAccuracy, providesHeading, heading, providesSpeed, speed, providesFloorLevel, floorLevel);
927 }
928
929 void TestRunner::setMockGeolocationPositionUnavailableError(JSStringRef message)
930 {
931     WKRetainPtr<WKStringRef> messageWK = toWK(message);
932     InjectedBundle::singleton().setMockGeolocationPositionUnavailableError(messageWK.get());
933 }
934
935 void TestRunner::setUserMediaPermission(bool enabled)
936 {
937     // FIXME: this should be done by frame.
938     InjectedBundle::singleton().setUserMediaPermission(enabled);
939 }
940
941 void TestRunner::resetUserMediaPermission()
942 {
943     // FIXME: this should be done by frame.
944     InjectedBundle::singleton().resetUserMediaPermission();
945 }
946
947 void TestRunner::setUserMediaPersistentPermissionForOrigin(bool permission, JSStringRef origin, JSStringRef parentOrigin)
948 {
949     WKRetainPtr<WKStringRef> originWK = toWK(origin);
950     WKRetainPtr<WKStringRef> parentOriginWK = toWK(parentOrigin);
951     InjectedBundle::singleton().setUserMediaPersistentPermissionForOrigin(permission, originWK.get(), parentOriginWK.get());
952 }
953
954 unsigned TestRunner::userMediaPermissionRequestCountForOrigin(JSStringRef origin, JSStringRef parentOrigin) const
955 {
956     WKRetainPtr<WKStringRef> originWK = toWK(origin);
957     WKRetainPtr<WKStringRef> parentOriginWK = toWK(parentOrigin);
958     return InjectedBundle::singleton().userMediaPermissionRequestCountForOrigin(originWK.get(), parentOriginWK.get());
959 }
960
961 void TestRunner::resetUserMediaPermissionRequestCountForOrigin(JSStringRef origin, JSStringRef parentOrigin)
962 {
963     WKRetainPtr<WKStringRef> originWK = toWK(origin);
964     WKRetainPtr<WKStringRef> parentOriginWK = toWK(parentOrigin);
965     InjectedBundle::singleton().resetUserMediaPermissionRequestCountForOrigin(originWK.get(), parentOriginWK.get());
966 }
967
968 bool TestRunner::callShouldCloseOnWebView()
969 {
970     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
971     return WKBundleFrameCallShouldCloseOnWebView(mainFrame);
972 }
973
974 void TestRunner::queueBackNavigation(unsigned howFarBackward)
975 {
976     InjectedBundle::singleton().queueBackNavigation(howFarBackward);
977 }
978
979 void TestRunner::queueForwardNavigation(unsigned howFarForward)
980 {
981     InjectedBundle::singleton().queueForwardNavigation(howFarForward);
982 }
983
984 void TestRunner::queueLoad(JSStringRef url, JSStringRef target, bool shouldOpenExternalURLs)
985 {
986     auto& injectedBundle = InjectedBundle::singleton();
987     WKRetainPtr<WKURLRef> baseURLWK(AdoptWK, WKBundleFrameCopyURL(WKBundlePageGetMainFrame(injectedBundle.page()->page())));
988     WKRetainPtr<WKURLRef> urlWK(AdoptWK, WKURLCreateWithBaseURL(baseURLWK.get(), toWTFString(toWK(url)).utf8().data()));
989     WKRetainPtr<WKStringRef> urlStringWK(AdoptWK, WKURLCopyString(urlWK.get()));
990
991     injectedBundle.queueLoad(urlStringWK.get(), toWK(target).get(), shouldOpenExternalURLs);
992 }
993
994 void TestRunner::queueLoadHTMLString(JSStringRef content, JSStringRef baseURL, JSStringRef unreachableURL)
995 {
996     WKRetainPtr<WKStringRef> contentWK = toWK(content);
997     WKRetainPtr<WKStringRef> baseURLWK = baseURL ? toWK(baseURL) : WKRetainPtr<WKStringRef>();
998     WKRetainPtr<WKStringRef> unreachableURLWK = unreachableURL ? toWK(unreachableURL) : WKRetainPtr<WKStringRef>();
999
1000     InjectedBundle::singleton().queueLoadHTMLString(contentWK.get(), baseURLWK.get(), unreachableURLWK.get());
1001 }
1002
1003 void TestRunner::queueReload()
1004 {
1005     InjectedBundle::singleton().queueReload();
1006 }
1007
1008 void TestRunner::queueLoadingScript(JSStringRef script)
1009 {
1010     WKRetainPtr<WKStringRef> scriptWK = toWK(script);
1011     InjectedBundle::singleton().queueLoadingScript(scriptWK.get());
1012 }
1013
1014 void TestRunner::queueNonLoadingScript(JSStringRef script)
1015 {
1016     WKRetainPtr<WKStringRef> scriptWK = toWK(script);
1017     InjectedBundle::singleton().queueNonLoadingScript(scriptWK.get());
1018 }
1019
1020 void TestRunner::setRejectsProtectionSpaceAndContinueForAuthenticationChallenges(bool value)
1021 {
1022     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetRejectsProtectionSpaceAndContinueForAuthenticationChallenges"));
1023     WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(value));
1024     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
1025 }
1026     
1027 void TestRunner::setHandlesAuthenticationChallenges(bool handlesAuthenticationChallenges)
1028 {
1029     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetHandlesAuthenticationChallenges"));
1030     WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(handlesAuthenticationChallenges));
1031     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
1032 }
1033
1034 void TestRunner::setShouldLogCanAuthenticateAgainstProtectionSpace(bool value)
1035 {
1036     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetShouldLogCanAuthenticateAgainstProtectionSpace"));
1037     WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(value));
1038     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
1039 }
1040
1041 void TestRunner::setShouldLogDownloadCallbacks(bool value)
1042 {
1043     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetShouldLogDownloadCallbacks"));
1044     WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(value));
1045     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
1046 }
1047
1048 void TestRunner::setAuthenticationUsername(JSStringRef username)
1049 {
1050     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetAuthenticationUsername"));
1051     WKRetainPtr<WKStringRef> messageBody(AdoptWK, WKStringCreateWithJSString(username));
1052     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
1053 }
1054
1055 void TestRunner::setAuthenticationPassword(JSStringRef password)
1056 {
1057     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetAuthenticationPassword"));
1058     WKRetainPtr<WKStringRef> messageBody(AdoptWK, WKStringCreateWithJSString(password));
1059     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
1060 }
1061
1062 bool TestRunner::secureEventInputIsEnabled() const
1063 {
1064     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SecureEventInputIsEnabled"));
1065     WKTypeRef returnData = 0;
1066
1067     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), 0, &returnData);
1068     return WKBooleanGetValue(static_cast<WKBooleanRef>(returnData));
1069 }
1070
1071 void TestRunner::setBlockAllPlugins(bool shouldBlock)
1072 {
1073     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetBlockAllPlugins"));
1074     WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(shouldBlock));
1075     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
1076 }
1077
1078 void TestRunner::setPluginSupportedMode(JSStringRef mode)
1079 {
1080     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetPluginSupportedMode"));
1081     WKRetainPtr<WKStringRef> messageBody(AdoptWK, WKStringCreateWithJSString(mode));
1082     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
1083 }
1084
1085 JSValueRef TestRunner::failNextNewCodeBlock()
1086 {
1087     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
1088     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
1089     return JSC::failNextNewCodeBlock(context);
1090 }
1091
1092 JSValueRef TestRunner::numberOfDFGCompiles(JSValueRef theFunction)
1093 {
1094     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
1095     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
1096     return JSC::numberOfDFGCompiles(context, theFunction);
1097 }
1098
1099 JSValueRef TestRunner::neverInlineFunction(JSValueRef theFunction)
1100 {
1101     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
1102     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
1103     return JSC::setNeverInline(context, theFunction);
1104 }
1105
1106 void TestRunner::setShouldDecideNavigationPolicyAfterDelay(bool value)
1107 {
1108     m_shouldDecideNavigationPolicyAfterDelay = value;
1109     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetShouldDecideNavigationPolicyAfterDelay"));
1110     WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(value));
1111     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
1112 }
1113
1114 void TestRunner::setShouldDecideResponsePolicyAfterDelay(bool value)
1115 {
1116     m_shouldDecideResponsePolicyAfterDelay = value;
1117     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetShouldDecideResponsePolicyAfterDelay"));
1118     WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(value));
1119     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
1120 }
1121
1122 void TestRunner::setNavigationGesturesEnabled(bool value)
1123 {
1124     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetNavigationGesturesEnabled"));
1125     WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(value));
1126     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
1127 }
1128
1129 void TestRunner::setIgnoresViewportScaleLimits(bool value)
1130 {
1131     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetIgnoresViewportScaleLimits"));
1132     WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(value));
1133     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
1134 }
1135
1136 void TestRunner::setShouldDownloadUndisplayableMIMETypes(bool value)
1137 {
1138     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetShouldDownloadUndisplayableMIMETypes"));
1139     WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(value));
1140     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
1141 }
1142
1143 void TestRunner::terminateNetworkProcess()
1144 {
1145     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("TerminateNetworkProcess"));
1146     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), nullptr);
1147 }
1148
1149 void TestRunner::terminateServiceWorkerProcess()
1150 {
1151     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("TerminateServiceWorkerProcess"));
1152     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), nullptr);
1153 }
1154
1155 static unsigned nextUIScriptCallbackID()
1156 {
1157     static unsigned callbackID = FirstUIScriptCallbackID;
1158     return callbackID++;
1159 }
1160
1161 void TestRunner::runUIScript(JSStringRef script, JSValueRef callback)
1162 {
1163     unsigned callbackID = nextUIScriptCallbackID();
1164     cacheTestRunnerCallback(callbackID, callback);
1165
1166     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("RunUIProcessScript"));
1167
1168     WKRetainPtr<WKMutableDictionaryRef> testDictionary(AdoptWK, WKMutableDictionaryCreate());
1169
1170     WKRetainPtr<WKStringRef> scriptKey(AdoptWK, WKStringCreateWithUTF8CString("Script"));
1171     WKRetainPtr<WKStringRef> scriptValue(AdoptWK, WKStringCreateWithJSString(script));
1172
1173     WKRetainPtr<WKStringRef> callbackIDKey(AdoptWK, WKStringCreateWithUTF8CString("CallbackID"));
1174     WKRetainPtr<WKUInt64Ref> callbackIDValue = adoptWK(WKUInt64Create(callbackID));
1175
1176     WKDictionarySetItem(testDictionary.get(), scriptKey.get(), scriptValue.get());
1177     WKDictionarySetItem(testDictionary.get(), callbackIDKey.get(), callbackIDValue.get());
1178
1179     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), testDictionary.get());
1180 }
1181
1182 void TestRunner::runUIScriptCallback(unsigned callbackID, JSStringRef result)
1183 {
1184     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
1185     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
1186
1187     JSValueRef resultValue = JSValueMakeString(context, result);
1188     callTestRunnerCallback(callbackID, 1, &resultValue);
1189 }
1190
1191 void TestRunner::installDidBeginSwipeCallback(JSValueRef callback)
1192 {
1193     cacheTestRunnerCallback(DidBeginSwipeCallbackID, callback);
1194 }
1195
1196 void TestRunner::installWillEndSwipeCallback(JSValueRef callback)
1197 {
1198     cacheTestRunnerCallback(WillEndSwipeCallbackID, callback);
1199 }
1200
1201 void TestRunner::installDidEndSwipeCallback(JSValueRef callback)
1202 {
1203     cacheTestRunnerCallback(DidEndSwipeCallbackID, callback);
1204 }
1205
1206 void TestRunner::installDidRemoveSwipeSnapshotCallback(JSValueRef callback)
1207 {
1208     cacheTestRunnerCallback(DidRemoveSwipeSnapshotCallbackID, callback);
1209 }
1210
1211 void TestRunner::callDidBeginSwipeCallback()
1212 {
1213     callTestRunnerCallback(DidBeginSwipeCallbackID);
1214 }
1215
1216 void TestRunner::callWillEndSwipeCallback()
1217 {
1218     callTestRunnerCallback(WillEndSwipeCallbackID);
1219 }
1220
1221 void TestRunner::callDidEndSwipeCallback()
1222 {
1223     callTestRunnerCallback(DidEndSwipeCallbackID);
1224 }
1225
1226 void TestRunner::callDidRemoveSwipeSnapshotCallback()
1227 {
1228     callTestRunnerCallback(DidRemoveSwipeSnapshotCallbackID);
1229 }
1230
1231 void TestRunner::setStatisticsLastSeen(JSStringRef hostName, double seconds)
1232 {
1233     Vector<WKRetainPtr<WKStringRef>> keys;
1234     Vector<WKRetainPtr<WKTypeRef>> values;
1235     
1236     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("HostName") });
1237     values.append({ AdoptWK, WKStringCreateWithJSString(hostName) });
1238     
1239     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("Value") });
1240     values.append({ AdoptWK, WKDoubleCreate(seconds) });
1241     
1242     Vector<WKStringRef> rawKeys(keys.size());
1243     Vector<WKTypeRef> rawValues(values.size());
1244     
1245     for (size_t i = 0; i < keys.size(); ++i) {
1246         rawKeys[i] = keys[i].get();
1247         rawValues[i] = values[i].get();
1248     }
1249     
1250     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetStatisticsLastSeen"));
1251     WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1252     
1253     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1254 }
1255     
1256 void TestRunner::setStatisticsPrevalentResource(JSStringRef hostName, bool value)
1257 {
1258     Vector<WKRetainPtr<WKStringRef>> keys;
1259     Vector<WKRetainPtr<WKTypeRef>> values;
1260
1261     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("HostName") });
1262     values.append({ AdoptWK, WKStringCreateWithJSString(hostName) });
1263     
1264     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("Value") });
1265     values.append({ AdoptWK, WKBooleanCreate(value) });
1266     
1267     Vector<WKStringRef> rawKeys;
1268     Vector<WKTypeRef> rawValues;
1269     rawKeys.resize(keys.size());
1270     rawValues.resize(values.size());
1271     
1272     for (size_t i = 0; i < keys.size(); ++i) {
1273         rawKeys[i] = keys[i].get();
1274         rawValues[i] = values[i].get();
1275     }
1276     
1277     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetStatisticsPrevalentResource"));
1278     WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1279
1280     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1281 }
1282
1283 void TestRunner::setStatisticsVeryPrevalentResource(JSStringRef hostName, bool value)
1284 {
1285     Vector<WKRetainPtr<WKStringRef>> keys;
1286     Vector<WKRetainPtr<WKTypeRef>> values;
1287     
1288     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("HostName") });
1289     values.append({ AdoptWK, WKStringCreateWithJSString(hostName) });
1290     
1291     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("Value") });
1292     values.append({ AdoptWK, WKBooleanCreate(value) });
1293     
1294     Vector<WKStringRef> rawKeys;
1295     Vector<WKTypeRef> rawValues;
1296     rawKeys.resize(keys.size());
1297     rawValues.resize(values.size());
1298     
1299     for (size_t i = 0; i < keys.size(); ++i) {
1300         rawKeys[i] = keys[i].get();
1301         rawValues[i] = values[i].get();
1302     }
1303     
1304     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetStatisticsVeryPrevalentResource"));
1305     WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1306     
1307     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1308 }
1309
1310 bool TestRunner::isStatisticsPrevalentResource(JSStringRef hostName)
1311 {
1312     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("IsStatisticsPrevalentResource"));
1313     WKRetainPtr<WKStringRef> messageBody(AdoptWK, WKStringCreateWithJSString(hostName));
1314     WKTypeRef returnData = 0;
1315     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get(), &returnData);
1316     return WKBooleanGetValue(static_cast<WKBooleanRef>(returnData));
1317 }
1318
1319 bool TestRunner::isStatisticsVeryPrevalentResource(JSStringRef hostName)
1320 {
1321     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("IsStatisticsVeryPrevalentResource"));
1322     WKRetainPtr<WKStringRef> messageBody(AdoptWK, WKStringCreateWithJSString(hostName));
1323     WKTypeRef returnData = 0;
1324     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get(), &returnData);
1325     return WKBooleanGetValue(static_cast<WKBooleanRef>(returnData));
1326 }
1327
1328 bool TestRunner::isStatisticsRegisteredAsSubFrameUnder(JSStringRef subFrameHost, JSStringRef topFrameHost)
1329 {
1330     Vector<WKRetainPtr<WKStringRef>> keys;
1331     Vector<WKRetainPtr<WKTypeRef>> values;
1332
1333     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("SubFrameHost") });
1334     values.append({ AdoptWK, WKStringCreateWithJSString(subFrameHost) });
1335     
1336     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("TopFrameHost") });
1337     values.append({ AdoptWK, WKStringCreateWithJSString(topFrameHost) });
1338     
1339     Vector<WKStringRef> rawKeys(keys.size());
1340     Vector<WKTypeRef> rawValues(values.size());
1341
1342     for (size_t i = 0; i < keys.size(); ++i) {
1343         rawKeys[i] = keys[i].get();
1344         rawValues[i] = values[i].get();
1345     }
1346
1347     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("IsStatisticsRegisteredAsSubFrameUnder"));
1348     WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1349     WKTypeRef returnData = 0;
1350     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get(), &returnData);
1351     return WKBooleanGetValue(static_cast<WKBooleanRef>(returnData));
1352 }
1353
1354 bool TestRunner::isStatisticsRegisteredAsRedirectingTo(JSStringRef hostRedirectedFrom, JSStringRef hostRedirectedTo)
1355 {
1356     Vector<WKRetainPtr<WKStringRef>> keys;
1357     Vector<WKRetainPtr<WKTypeRef>> values;
1358     
1359     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("HostRedirectedFrom") });
1360     values.append({ AdoptWK, WKStringCreateWithJSString(hostRedirectedFrom) });
1361     
1362     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("HostRedirectedTo") });
1363     values.append({ AdoptWK, WKStringCreateWithJSString(hostRedirectedTo) });
1364     
1365     Vector<WKStringRef> rawKeys(keys.size());
1366     Vector<WKTypeRef> rawValues(values.size());
1367
1368     for (size_t i = 0; i < keys.size(); ++i) {
1369         rawKeys[i] = keys[i].get();
1370         rawValues[i] = values[i].get();
1371     }
1372     
1373     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("IsStatisticsRegisteredAsRedirectingTo"));
1374     WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1375     WKTypeRef returnData = 0;
1376     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get(), &returnData);
1377     return WKBooleanGetValue(static_cast<WKBooleanRef>(returnData));
1378 }
1379
1380 void TestRunner::setStatisticsHasHadUserInteraction(JSStringRef hostName, bool value)
1381 {
1382     Vector<WKRetainPtr<WKStringRef>> keys;
1383     Vector<WKRetainPtr<WKTypeRef>> values;
1384     
1385     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("HostName") });
1386     values.append({ AdoptWK, WKStringCreateWithJSString(hostName) });
1387     
1388     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("Value") });
1389     values.append({ AdoptWK, WKBooleanCreate(value) });
1390     
1391     Vector<WKStringRef> rawKeys;
1392     Vector<WKTypeRef> rawValues;
1393     rawKeys.resize(keys.size());
1394     rawValues.resize(values.size());
1395     
1396     for (size_t i = 0; i < keys.size(); ++i) {
1397         rawKeys[i] = keys[i].get();
1398         rawValues[i] = values[i].get();
1399     }
1400     
1401     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetStatisticsHasHadUserInteraction"));
1402     WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1403     
1404     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1405 }
1406
1407 void TestRunner::setStatisticsHasHadNonRecentUserInteraction(JSStringRef hostName)
1408 {
1409     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetStatisticsHasHadNonRecentUserInteraction"));
1410     WKRetainPtr<WKStringRef> messageBody(AdoptWK, WKStringCreateWithJSString(hostName));
1411     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1412 }
1413
1414 bool TestRunner::isStatisticsHasHadUserInteraction(JSStringRef hostName)
1415 {
1416     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("IsStatisticsHasHadUserInteraction"));
1417     WKRetainPtr<WKStringRef> messageBody(AdoptWK, WKStringCreateWithJSString(hostName));
1418     WKTypeRef returnData = 0;
1419     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get(), &returnData);
1420     return WKBooleanGetValue(static_cast<WKBooleanRef>(returnData));
1421 }
1422
1423 void TestRunner::setStatisticsGrandfathered(JSStringRef hostName, bool value)
1424 {
1425     Vector<WKRetainPtr<WKStringRef>> keys;
1426     Vector<WKRetainPtr<WKTypeRef>> values;
1427     
1428     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("HostName") });
1429     values.append({ AdoptWK, WKStringCreateWithJSString(hostName) });
1430     
1431     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("Value") });
1432     values.append({ AdoptWK, WKBooleanCreate(value) });
1433     
1434     Vector<WKStringRef> rawKeys;
1435     Vector<WKTypeRef> rawValues;
1436     rawKeys.resize(keys.size());
1437     rawValues.resize(values.size());
1438     
1439     for (size_t i = 0; i < keys.size(); ++i) {
1440         rawKeys[i] = keys[i].get();
1441         rawValues[i] = values[i].get();
1442     }
1443     
1444     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetStatisticsGrandfathered"));
1445     WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1446     
1447     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1448 }
1449     
1450 bool TestRunner::isStatisticsGrandfathered(JSStringRef hostName)
1451 {
1452     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("IsStatisticsGrandfathered"));
1453     WKRetainPtr<WKStringRef> messageBody(AdoptWK, WKStringCreateWithJSString(hostName));
1454     WKTypeRef returnData = 0;
1455     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get(), &returnData);
1456     return WKBooleanGetValue(static_cast<WKBooleanRef>(returnData));
1457 }
1458
1459 void TestRunner::setStatisticsSubframeUnderTopFrameOrigin(JSStringRef hostName, JSStringRef topFrameHostName)
1460 {
1461     Vector<WKRetainPtr<WKStringRef>> keys;
1462     Vector<WKRetainPtr<WKTypeRef>> values;
1463     
1464     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("HostName") });
1465     values.append({ AdoptWK, WKStringCreateWithJSString(hostName) });
1466     
1467     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("TopFrameHostName") });
1468     values.append({ AdoptWK, WKStringCreateWithJSString(topFrameHostName) });
1469     
1470     Vector<WKStringRef> rawKeys(keys.size());
1471     Vector<WKTypeRef> rawValues(values.size());
1472     
1473     for (size_t i = 0; i < keys.size(); ++i) {
1474         rawKeys[i] = keys[i].get();
1475         rawValues[i] = values[i].get();
1476     }
1477     
1478     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetStatisticsSubframeUnderTopFrameOrigin"));
1479     WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1480     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1481 }
1482
1483 void TestRunner::setStatisticsSubresourceUnderTopFrameOrigin(JSStringRef hostName, JSStringRef topFrameHostName)
1484 {
1485     Vector<WKRetainPtr<WKStringRef>> keys;
1486     Vector<WKRetainPtr<WKTypeRef>> values;
1487     
1488     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("HostName") });
1489     values.append({ AdoptWK, WKStringCreateWithJSString(hostName) });
1490     
1491     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("TopFrameHostName") });
1492     values.append({ AdoptWK, WKStringCreateWithJSString(topFrameHostName) });
1493     
1494     Vector<WKStringRef> rawKeys(keys.size());
1495     Vector<WKTypeRef> rawValues(values.size());
1496     
1497     for (size_t i = 0; i < keys.size(); ++i) {
1498         rawKeys[i] = keys[i].get();
1499         rawValues[i] = values[i].get();
1500     }
1501     
1502     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetStatisticsSubresourceUnderTopFrameOrigin"));
1503     WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1504     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1505 }
1506
1507 void TestRunner::setStatisticsSubresourceUniqueRedirectTo(JSStringRef hostName, JSStringRef hostNameRedirectedTo)
1508 {
1509     Vector<WKRetainPtr<WKStringRef>> keys;
1510     Vector<WKRetainPtr<WKTypeRef>> values;
1511     
1512     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("HostName") });
1513     values.append({ AdoptWK, WKStringCreateWithJSString(hostName) });
1514     
1515     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("HostNameRedirectedTo") });
1516     values.append({ AdoptWK, WKStringCreateWithJSString(hostNameRedirectedTo) });
1517     
1518     Vector<WKStringRef> rawKeys(keys.size());
1519     Vector<WKTypeRef> rawValues(values.size());
1520     
1521     for (size_t i = 0; i < keys.size(); ++i) {
1522         rawKeys[i] = keys[i].get();
1523         rawValues[i] = values[i].get();
1524     }
1525     
1526     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetStatisticsSubresourceUniqueRedirectTo"));
1527     WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1528     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1529 }
1530
1531
1532 void TestRunner::setStatisticsSubresourceUniqueRedirectFrom(JSStringRef hostName, JSStringRef hostNameRedirectedFrom)
1533 {
1534     Vector<WKRetainPtr<WKStringRef>> keys;
1535     Vector<WKRetainPtr<WKTypeRef>> values;
1536     
1537     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("HostName") });
1538     values.append({ AdoptWK, WKStringCreateWithJSString(hostName) });
1539     
1540     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("HostNameRedirectedFrom") });
1541     values.append({ AdoptWK, WKStringCreateWithJSString(hostNameRedirectedFrom) });
1542     
1543     Vector<WKStringRef> rawKeys(keys.size());
1544     Vector<WKTypeRef> rawValues(values.size());
1545     
1546     for (size_t i = 0; i < keys.size(); ++i) {
1547         rawKeys[i] = keys[i].get();
1548         rawValues[i] = values[i].get();
1549     }
1550     
1551     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetStatisticsSubresourceUniqueRedirectFrom"));
1552     WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1553     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1554 }
1555
1556 void TestRunner::setStatisticsTopFrameUniqueRedirectTo(JSStringRef hostName, JSStringRef hostNameRedirectedTo)
1557 {
1558     Vector<WKRetainPtr<WKStringRef>> keys;
1559     Vector<WKRetainPtr<WKTypeRef>> values;
1560     
1561     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("HostName") });
1562     values.append({ AdoptWK, WKStringCreateWithJSString(hostName) });
1563     
1564     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("HostNameRedirectedTo") });
1565     values.append({ AdoptWK, WKStringCreateWithJSString(hostNameRedirectedTo) });
1566     
1567     Vector<WKStringRef> rawKeys(keys.size());
1568     Vector<WKTypeRef> rawValues(values.size());
1569     
1570     for (size_t i = 0; i < keys.size(); ++i) {
1571         rawKeys[i] = keys[i].get();
1572         rawValues[i] = values[i].get();
1573     }
1574     
1575     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetStatisticsTopFrameUniqueRedirectTo"));
1576     WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1577     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1578 }
1579
1580 void TestRunner::setStatisticsTopFrameUniqueRedirectFrom(JSStringRef hostName, JSStringRef hostNameRedirectedFrom)
1581 {
1582     Vector<WKRetainPtr<WKStringRef>> keys;
1583     Vector<WKRetainPtr<WKTypeRef>> values;
1584     
1585     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("HostName") });
1586     values.append({ AdoptWK, WKStringCreateWithJSString(hostName) });
1587     
1588     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("HostNameRedirectedFrom") });
1589     values.append({ AdoptWK, WKStringCreateWithJSString(hostNameRedirectedFrom) });
1590     
1591     Vector<WKStringRef> rawKeys(keys.size());
1592     Vector<WKTypeRef> rawValues(values.size());
1593     
1594     for (size_t i = 0; i < keys.size(); ++i) {
1595         rawKeys[i] = keys[i].get();
1596         rawValues[i] = values[i].get();
1597     }
1598     
1599     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetStatisticsTopFrameUniqueRedirectFrom"));
1600     WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1601     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1602 }
1603
1604
1605 void TestRunner::setStatisticsTimeToLiveUserInteraction(double seconds)
1606 {
1607     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetStatisticsTimeToLiveUserInteraction"));
1608     WKRetainPtr<WKDoubleRef> messageBody(AdoptWK, WKDoubleCreate(seconds));
1609     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1610 }
1611
1612 void TestRunner::setStatisticsTimeToLiveCookiePartitionFree(double seconds)
1613 {
1614     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetStatisticsTimeToLiveCookiePartitionFree"));
1615     WKRetainPtr<WKDoubleRef> messageBody(AdoptWK, WKDoubleCreate(seconds));
1616     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1617 }
1618
1619 void TestRunner::installStatisticsDidModifyDataRecordsCallback(JSValueRef callback)
1620 {
1621     cacheTestRunnerCallback(StatisticsDidModifyDataRecordsCallbackID, callback);
1622 }
1623
1624 void TestRunner::statisticsDidModifyDataRecordsCallback()
1625 {
1626     callTestRunnerCallback(StatisticsDidModifyDataRecordsCallbackID);
1627 }
1628
1629 void TestRunner::installStatisticsDidScanDataRecordsCallback(JSValueRef callback)
1630 {
1631     cacheTestRunnerCallback(StatisticsDidScanDataRecordsCallbackID, callback);
1632 }
1633
1634 void TestRunner::statisticsDidScanDataRecordsCallback()
1635 {
1636     callTestRunnerCallback(StatisticsDidScanDataRecordsCallbackID);
1637 }
1638
1639 void TestRunner::installStatisticsDidRunTelemetryCallback(JSValueRef callback)
1640 {
1641     cacheTestRunnerCallback(StatisticsDidRunTelemetryCallbackID, callback);
1642 }
1643     
1644 void TestRunner::statisticsDidRunTelemetryCallback(unsigned totalPrevalentResources, unsigned totalPrevalentResourcesWithUserInteraction, unsigned top3SubframeUnderTopFrameOrigins)
1645 {
1646     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
1647     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
1648     
1649     StringBuilder stringBuilder;
1650     stringBuilder.appendLiteral("{ \"totalPrevalentResources\" : ");
1651     stringBuilder.appendNumber(totalPrevalentResources);
1652     stringBuilder.appendLiteral(", \"totalPrevalentResourcesWithUserInteraction\" : ");
1653     stringBuilder.appendNumber(totalPrevalentResourcesWithUserInteraction);
1654     stringBuilder.appendLiteral(", \"top3SubframeUnderTopFrameOrigins\" : ");
1655     stringBuilder.appendNumber(top3SubframeUnderTopFrameOrigins);
1656     stringBuilder.appendLiteral(" }");
1657     
1658     JSValueRef result = JSValueMakeFromJSONString(context, JSStringCreateWithUTF8CString(stringBuilder.toString().utf8().data()));
1659     
1660     callTestRunnerCallback(StatisticsDidRunTelemetryCallbackID, 1, &result);
1661 }
1662
1663 void TestRunner::statisticsNotifyObserver()
1664 {
1665     InjectedBundle::singleton().statisticsNotifyObserver();
1666 }
1667
1668 void TestRunner::statisticsProcessStatisticsAndDataRecords()
1669 {
1670     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("StatisticsProcessStatisticsAndDataRecords"));
1671     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), 0, nullptr);
1672 }
1673
1674 void TestRunner::statisticsUpdateCookiePartitioning(JSValueRef callback)
1675 {
1676     cacheTestRunnerCallback(StatisticsDidSetPartitionOrBlockCookiesForHostCallbackID, callback);
1677
1678     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("StatisticsUpdateCookiePartitioning"));
1679     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), 0, nullptr);
1680 }
1681
1682 void TestRunner::statisticsSetShouldPartitionCookiesForHost(JSStringRef hostName, bool value, JSValueRef callback)
1683 {
1684     cacheTestRunnerCallback(StatisticsDidSetPartitionOrBlockCookiesForHostCallbackID, callback);
1685
1686     Vector<WKRetainPtr<WKStringRef>> keys;
1687     Vector<WKRetainPtr<WKTypeRef>> values;
1688     
1689     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("HostName") });
1690     values.append({ AdoptWK, WKStringCreateWithJSString(hostName) });
1691     
1692     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("Value") });
1693     values.append({ AdoptWK, WKBooleanCreate(value) });
1694     
1695     Vector<WKStringRef> rawKeys(keys.size());
1696     Vector<WKTypeRef> rawValues(values.size());
1697     
1698     for (size_t i = 0; i < keys.size(); ++i) {
1699         rawKeys[i] = keys[i].get();
1700         rawValues[i] = values[i].get();
1701     }
1702     
1703     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("StatisticsSetShouldPartitionCookiesForHost"));
1704     WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1705     
1706     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1707 }
1708
1709 void TestRunner::statisticsCallDidSetPartitionOrBlockCookiesForHostCallback()
1710 {
1711     callTestRunnerCallback(StatisticsDidSetPartitionOrBlockCookiesForHostCallbackID);
1712 }
1713
1714 void TestRunner::statisticsSubmitTelemetry()
1715 {
1716     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("StatisticsSubmitTelemetry"));
1717     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), 0, nullptr);
1718 }
1719
1720 void TestRunner::setStatisticsNotifyPagesWhenDataRecordsWereScanned(bool value)
1721 {
1722     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("StatisticsNotifyPagesWhenDataRecordsWereScanned"));
1723     WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(value));
1724     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1725 }
1726
1727 void TestRunner::setStatisticsShouldClassifyResourcesBeforeDataRecordsRemoval(bool value)
1728 {
1729     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("StatisticsShouldClassifyResourcesBeforeDataRecordsRemoval"));
1730     WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(value));
1731     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1732 }
1733
1734 void TestRunner::setStatisticsNotifyPagesWhenTelemetryWasCaptured(bool value)
1735 {
1736     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("StatisticsNotifyPagesWhenTelemetryWasCaptured"));
1737     WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(value));
1738     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1739 }
1740
1741 void TestRunner::setStatisticsMinimumTimeBetweenDataRecordsRemoval(double seconds)
1742 {
1743     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetStatisticsMinimumTimeBetweenDataRecordsRemoval"));
1744     WKRetainPtr<WKDoubleRef> messageBody(AdoptWK, WKDoubleCreate(seconds));
1745     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1746 }
1747
1748 void TestRunner::setStatisticsGrandfatheringTime(double seconds)
1749 {
1750     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetStatisticsGrandfatheringTime"));
1751     WKRetainPtr<WKDoubleRef> messageBody(AdoptWK, WKDoubleCreate(seconds));
1752     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1753 }
1754
1755 void TestRunner::setStatisticsMaxStatisticsEntries(unsigned entries)
1756 {
1757     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetMaxStatisticsEntries"));
1758     WKRetainPtr<WKTypeRef> messageBody(AdoptWK, WKUInt64Create(entries));
1759     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1760 }
1761     
1762 void TestRunner::setStatisticsPruneEntriesDownTo(unsigned entries)
1763 {
1764     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetPruneEntriesDownTo"));
1765     WKRetainPtr<WKTypeRef> messageBody(AdoptWK, WKUInt64Create(entries));
1766     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1767 }
1768     
1769 void TestRunner::statisticsClearInMemoryAndPersistentStore(JSValueRef callback)
1770 {
1771     cacheTestRunnerCallback(StatisticsDidClearThroughWebsiteDataRemovalCallbackID, callback);
1772
1773     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("StatisticsClearInMemoryAndPersistentStore"));
1774     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), 0, nullptr);
1775 }
1776
1777 void TestRunner::statisticsClearInMemoryAndPersistentStoreModifiedSinceHours(unsigned hours, JSValueRef callback)
1778 {
1779     cacheTestRunnerCallback(StatisticsDidClearThroughWebsiteDataRemovalCallbackID, callback);
1780
1781     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("StatisticsClearInMemoryAndPersistentStoreModifiedSinceHours"));
1782     WKRetainPtr<WKTypeRef> messageBody(AdoptWK, WKUInt64Create(hours));
1783     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1784 }
1785
1786 void TestRunner::statisticsClearThroughWebsiteDataRemoval(JSValueRef callback)
1787 {
1788     cacheTestRunnerCallback(StatisticsDidClearThroughWebsiteDataRemovalCallbackID, callback);
1789     
1790     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("StatisticsClearThroughWebsiteDataRemoval"));
1791     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), 0, nullptr);
1792 }
1793
1794 void TestRunner::statisticsCallClearThroughWebsiteDataRemovalCallback()
1795 {
1796     callTestRunnerCallback(StatisticsDidClearThroughWebsiteDataRemovalCallbackID);
1797 }
1798
1799 void TestRunner::statisticsResetToConsistentState()
1800 {
1801     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("StatisticsResetToConsistentState"));
1802     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), 0, nullptr);
1803 }
1804
1805 void TestRunner::setStorageAccessAPIEnabled(bool enabled)
1806 {
1807     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetStorageAccessAPIEnabled"));
1808     
1809     WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(enabled));
1810     
1811     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1812 }
1813
1814 void TestRunner::getAllStorageAccessEntries(JSValueRef callback)
1815 {
1816     cacheTestRunnerCallback(AllStorageAccessEntriesCallbackID, callback);
1817     
1818     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("GetAllStorageAccessEntries"));
1819     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), 0, nullptr);
1820 }
1821
1822 void TestRunner::callDidReceiveAllStorageAccessEntriesCallback(Vector<String>& domains)
1823 {
1824     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
1825     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
1826     
1827     StringBuilder stringBuilder;
1828     stringBuilder.appendLiteral("[");
1829     bool firstDomain = true;
1830     for (auto& domain : domains) {
1831         if (firstDomain)
1832             firstDomain = false;
1833         else
1834             stringBuilder.appendLiteral(", ");
1835         stringBuilder.appendLiteral("\"");
1836         stringBuilder.append(domain);
1837         stringBuilder.appendLiteral("\"");
1838     }
1839     stringBuilder.appendLiteral("]");
1840     
1841     JSValueRef result = JSValueMakeFromJSONString(context, JSStringCreateWithUTF8CString(stringBuilder.toString().utf8().data()));
1842
1843     callTestRunnerCallback(AllStorageAccessEntriesCallbackID, 1, &result);
1844 }
1845
1846 #if PLATFORM(MAC)
1847 void TestRunner::connectMockGamepad(unsigned index)
1848 {
1849     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("ConnectMockGamepad"));
1850     WKRetainPtr<WKTypeRef> messageBody(AdoptWK, WKUInt64Create(index));
1851
1852     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1853 }
1854
1855 void TestRunner::disconnectMockGamepad(unsigned index)
1856 {
1857     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("DisconnectMockGamepad"));
1858     WKRetainPtr<WKTypeRef> messageBody(AdoptWK, WKUInt64Create(index));
1859
1860     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1861 }
1862
1863 void TestRunner::setMockGamepadDetails(unsigned index, JSStringRef gamepadID, unsigned axisCount, unsigned buttonCount)
1864 {
1865     Vector<WKRetainPtr<WKStringRef>> keys;
1866     Vector<WKRetainPtr<WKTypeRef>> values;
1867
1868     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("GamepadID") });
1869     values.append(toWK(gamepadID));
1870
1871     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("GamepadIndex") });
1872     values.append({ AdoptWK, WKUInt64Create(index) });
1873
1874     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("AxisCount") });
1875     values.append({ AdoptWK, WKUInt64Create(axisCount) });
1876
1877     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("ButtonCount") });
1878     values.append({ AdoptWK, WKUInt64Create(buttonCount) });
1879
1880     Vector<WKStringRef> rawKeys;
1881     Vector<WKTypeRef> rawValues;
1882     rawKeys.resize(keys.size());
1883     rawValues.resize(values.size());
1884
1885     for (size_t i = 0; i < keys.size(); ++i) {
1886         rawKeys[i] = keys[i].get();
1887         rawValues[i] = values[i].get();
1888     }
1889
1890     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetMockGamepadDetails"));
1891     WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1892
1893     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1894 }
1895
1896 void TestRunner::setMockGamepadAxisValue(unsigned index, unsigned axisIndex, double value)
1897 {
1898     Vector<WKRetainPtr<WKStringRef>> keys;
1899     Vector<WKRetainPtr<WKTypeRef>> values;
1900
1901     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("GamepadIndex") });
1902     values.append({ AdoptWK, WKUInt64Create(index) });
1903
1904     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("AxisIndex") });
1905     values.append({ AdoptWK, WKUInt64Create(axisIndex) });
1906
1907     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("Value") });
1908     values.append({ AdoptWK, WKDoubleCreate(value) });
1909
1910     Vector<WKStringRef> rawKeys;
1911     Vector<WKTypeRef> rawValues;
1912     rawKeys.resize(keys.size());
1913     rawValues.resize(values.size());
1914
1915     for (size_t i = 0; i < keys.size(); ++i) {
1916         rawKeys[i] = keys[i].get();
1917         rawValues[i] = values[i].get();
1918     }
1919
1920     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetMockGamepadAxisValue"));
1921     WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1922
1923     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1924 }
1925
1926 void TestRunner::setMockGamepadButtonValue(unsigned index, unsigned buttonIndex, double value)
1927 {
1928     Vector<WKRetainPtr<WKStringRef>> keys;
1929     Vector<WKRetainPtr<WKTypeRef>> values;
1930
1931     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("GamepadIndex") });
1932     values.append({ AdoptWK, WKUInt64Create(index) });
1933
1934     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("ButtonIndex") });
1935     values.append({ AdoptWK, WKUInt64Create(buttonIndex) });
1936
1937     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("Value") });
1938     values.append({ AdoptWK, WKDoubleCreate(value) });
1939
1940     Vector<WKStringRef> rawKeys;
1941     Vector<WKTypeRef> rawValues;
1942     rawKeys.resize(keys.size());
1943     rawValues.resize(values.size());
1944
1945     for (size_t i = 0; i < keys.size(); ++i) {
1946         rawKeys[i] = keys[i].get();
1947         rawValues[i] = values[i].get();
1948     }
1949
1950     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetMockGamepadButtonValue"));
1951     WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1952
1953     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1954 }
1955 #else
1956 void TestRunner::connectMockGamepad(unsigned)
1957 {
1958 }
1959
1960 void TestRunner::disconnectMockGamepad(unsigned)
1961 {
1962 }
1963
1964 void TestRunner::setMockGamepadDetails(unsigned, JSStringRef, unsigned, unsigned)
1965 {
1966 }
1967
1968 void TestRunner::setMockGamepadAxisValue(unsigned, unsigned, double)
1969 {
1970 }
1971
1972 void TestRunner::setMockGamepadButtonValue(unsigned, unsigned, double)
1973 {
1974 }
1975 #endif // PLATFORM(MAC)
1976
1977 void TestRunner::setOpenPanelFiles(JSValueRef filesValue)
1978 {
1979     WKBundlePageRef page = InjectedBundle::singleton().page()->page();
1980     JSContextRef context = WKBundleFrameGetJavaScriptContext(WKBundlePageGetMainFrame(page));
1981
1982     if (!JSValueIsArray(context, filesValue))
1983         return;
1984
1985     JSObjectRef files = JSValueToObject(context, filesValue, nullptr);
1986     static auto lengthProperty = JSRetainPtr<JSStringRef>(Adopt, JSStringCreateWithUTF8CString("length"));
1987     JSValueRef filesLengthValue = JSObjectGetProperty(context, files, lengthProperty.get(), nullptr);
1988     if (!JSValueIsNumber(context, filesLengthValue))
1989         return;
1990
1991     auto fileURLs = adoptWK(WKMutableArrayCreate());
1992     auto filesLength = static_cast<size_t>(JSValueToNumber(context, filesLengthValue, nullptr));
1993     for (size_t i = 0; i < filesLength; ++i) {
1994         JSValueRef fileValue = JSObjectGetPropertyAtIndex(context, files, i, nullptr);
1995         if (!JSValueIsString(context, fileValue))
1996             continue;
1997
1998         auto file = JSRetainPtr<JSStringRef>(Adopt, JSValueToStringCopy(context, fileValue, nullptr));
1999         size_t fileBufferSize = JSStringGetMaximumUTF8CStringSize(file.get()) + 1;
2000         auto fileBuffer = std::make_unique<char[]>(fileBufferSize);
2001         JSStringGetUTF8CString(file.get(), fileBuffer.get(), fileBufferSize);
2002
2003         WKArrayAppendItem(fileURLs.get(), adoptWK(WKURLCreateWithBaseURL(m_testURL.get(), fileBuffer.get())).get());
2004     }
2005
2006     static auto messageName = adoptWK(WKStringCreateWithUTF8CString("SetOpenPanelFileURLs"));
2007     WKBundlePagePostMessage(page, messageName.get(), fileURLs.get());
2008 }
2009
2010 void TestRunner::removeAllSessionCredentials(JSValueRef callback)
2011 {
2012     cacheTestRunnerCallback(DidRemoveAllSessionCredentialsCallbackID, callback);
2013     
2014     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("RemoveAllSessionCredentials"));
2015     WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(true));
2016     
2017     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
2018 }
2019
2020 void TestRunner::callDidRemoveAllSessionCredentialsCallback()
2021 {
2022     callTestRunnerCallback(DidRemoveAllSessionCredentialsCallbackID);
2023 }
2024
2025 void TestRunner::clearDOMCache(JSStringRef origin)
2026 {
2027     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("ClearDOMCache"));
2028     WKRetainPtr<WKStringRef> messageBody(AdoptWK, WKStringCreateWithJSString(origin));
2029     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
2030 }
2031
2032 void TestRunner::clearDOMCaches()
2033 {
2034     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("ClearDOMCaches"));
2035     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), nullptr, nullptr);
2036 }
2037
2038 bool TestRunner::hasDOMCache(JSStringRef origin)
2039 {
2040     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("HasDOMCache"));
2041     WKRetainPtr<WKStringRef> messageBody(AdoptWK, WKStringCreateWithJSString(origin));
2042     WKTypeRef returnData = 0;
2043     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get(), &returnData);
2044     return WKBooleanGetValue(static_cast<WKBooleanRef>(returnData));
2045 }
2046
2047 uint64_t TestRunner::domCacheSize(JSStringRef origin)
2048 {
2049     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("DOMCacheSize"));
2050     WKRetainPtr<WKStringRef> messageBody(AdoptWK, WKStringCreateWithJSString(origin));
2051     WKTypeRef returnData = 0;
2052     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get(), &returnData);
2053     return WKUInt64GetValue(static_cast<WKUInt64Ref>(returnData));
2054 }
2055
2056 void TestRunner::getApplicationManifestThen(JSValueRef callback)
2057 {
2058     cacheTestRunnerCallback(GetApplicationManifestCallbackID, callback);
2059     
2060     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("GetApplicationManifest"));
2061     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), nullptr, nullptr);
2062 }
2063
2064 void TestRunner::didGetApplicationManifest()
2065 {
2066     callTestRunnerCallback(GetApplicationManifestCallbackID);
2067 }
2068
2069 } // namespace WTR