Domain relationships in the ITP Database should be inserted in a single query and...
[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/WKNumber.h>
49 #include <WebKit/WKPagePrivate.h>
50 #include <WebKit/WKRetainPtr.h>
51 #include <WebKit/WKSerializedScriptValue.h>
52 #include <WebKit/WebKit2_C.h>
53 #include <wtf/HashMap.h>
54 #include <wtf/Optional.h>
55 #include <wtf/StdLibExtras.h>
56 #include <wtf/UniqueArray.h>
57 #include <wtf/text/CString.h>
58 #include <wtf/text/StringBuilder.h>
59 #include <wtf/text/StringConcatenateNumbers.h>
60
61 namespace WTR {
62
63 Ref<TestRunner> TestRunner::create()
64 {
65     return adoptRef(*new TestRunner);
66 }
67
68 TestRunner::TestRunner()
69     : m_userStyleSheetLocation(adoptWK(WKStringCreateWithUTF8CString("")))
70 {
71     platformInitialize();
72 }
73
74 TestRunner::~TestRunner()
75 {
76 }
77
78 JSClassRef TestRunner::wrapperClass()
79 {
80     return JSTestRunner::testRunnerClass();
81 }
82
83 void TestRunner::display()
84 {
85     WKBundlePageRef page = InjectedBundle::singleton().page()->page();
86     WKBundlePageForceRepaint(page);
87 }
88
89 void TestRunner::displayAndTrackRepaints()
90 {
91     WKBundlePageRef page = InjectedBundle::singleton().page()->page();
92     WKBundlePageForceRepaint(page);
93     WKBundlePageSetTracksRepaints(page, true);
94     WKBundlePageResetTrackedRepaints(page);
95 }
96
97 bool TestRunner::shouldDumpPixels() const
98 {
99     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("GetDumpPixels"));
100     WKTypeRef returnData = nullptr;
101     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), nullptr, &returnData);
102     ASSERT(WKGetTypeID(returnData) == WKBooleanGetTypeID());
103     return WKBooleanGetValue(adoptWK(static_cast<WKBooleanRef>(returnData)).get());
104 }
105
106 void TestRunner::setDumpPixels(bool dumpPixels)
107 {
108     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetDumpPixels"));
109     WKRetainPtr<WKBooleanRef> messageBody = adoptWK(WKBooleanCreate(dumpPixels));
110     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
111 }
112
113 void TestRunner::dumpAsText(bool dumpPixels)
114 {
115     if (whatToDump() < WhatToDump::MainFrameText)
116         setWhatToDump(WhatToDump::MainFrameText);
117     setDumpPixels(dumpPixels);
118 }
119     
120 WhatToDump TestRunner::whatToDump() const
121 {
122     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("GetWhatToDump"));
123     WKTypeRef returnData = nullptr;
124     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), nullptr, &returnData);
125     ASSERT(WKGetTypeID(returnData) == WKUInt64GetTypeID());
126     return static_cast<WhatToDump>(WKUInt64GetValue(adoptWK(static_cast<WKUInt64Ref>(returnData)).get()));
127 }
128
129 void TestRunner::setWhatToDump(WhatToDump whatToDump)
130 {
131     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetWhatToDump"));
132     WKRetainPtr<WKUInt64Ref> messageBody = adoptWK(WKUInt64Create(static_cast<uint64_t>(whatToDump)));
133     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
134 }
135
136 void TestRunner::setCustomPolicyDelegate(bool enabled, bool permissive)
137 {
138     m_policyDelegateEnabled = enabled;
139     m_policyDelegatePermissive = permissive;
140
141     InjectedBundle::singleton().setCustomPolicyDelegate(enabled, permissive);
142 }
143
144 void TestRunner::waitForPolicyDelegate()
145 {
146     setCustomPolicyDelegate(true);
147     waitUntilDone();
148 }
149
150 void TestRunner::waitUntilDownloadFinished()
151 {
152     m_shouldFinishAfterDownload = true;
153     waitUntilDone();
154 }
155
156 void TestRunner::waitUntilDone()
157 {
158     auto& injectedBundle = InjectedBundle::singleton();
159     RELEASE_ASSERT(injectedBundle.isTestRunning());
160
161     setWaitUntilDone(true);
162 }
163
164 void TestRunner::setWaitUntilDone(bool value)
165 {
166     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetWaitUntilDone"));
167     WKRetainPtr<WKBooleanRef> messageBody = adoptWK(WKBooleanCreate(value));
168     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
169 }
170
171 bool TestRunner::shouldWaitUntilDone() const
172 {
173     WKRetainPtr<WKStringRef> messsageName = adoptWK(WKStringCreateWithUTF8CString("GetWaitUntilDone"));
174     WKTypeRef returnData = nullptr;
175     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messsageName.get(), nullptr, &returnData);
176     ASSERT(WKGetTypeID(returnData) == WKBooleanGetTypeID());
177     return WKBooleanGetValue(adoptWK(static_cast<WKBooleanRef>(returnData)).get());
178 }
179
180 void TestRunner::notifyDone()
181 {
182     auto& injectedBundle = InjectedBundle::singleton();
183     if (!injectedBundle.isTestRunning())
184         return;
185
186     if (shouldWaitUntilDone() && !injectedBundle.topLoadingFrame())
187         injectedBundle.page()->dump();
188
189     // We don't call invalidateWaitToDumpWatchdogTimer() here, even if we continue to wait for a load to finish.
190     // The test is still subject to timeout checking - it is better to detect an async timeout inside WebKitTestRunner
191     // than to let webkitpy do that, because WebKitTestRunner will dump partial results.
192
193     setWaitUntilDone(false);
194 }
195
196 void TestRunner::forceImmediateCompletion()
197 {
198     auto& injectedBundle = InjectedBundle::singleton();
199     if (!injectedBundle.isTestRunning())
200         return;
201
202     if (shouldWaitUntilDone() && injectedBundle.page())
203         injectedBundle.page()->dump();
204
205     setWaitUntilDone(false);
206 }
207
208 void TestRunner::setShouldDumpFrameLoadCallbacks(bool value)
209 {
210     WKRetainPtr<WKStringRef> messsageName = adoptWK(WKStringCreateWithUTF8CString("SetDumpFrameLoadCallbacks"));
211     WKRetainPtr<WKBooleanRef> messageBody = adoptWK(WKBooleanCreate(value));
212     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messsageName.get(), messageBody.get(), nullptr);
213 }
214
215 bool TestRunner::shouldDumpFrameLoadCallbacks()
216 {
217     WKRetainPtr<WKStringRef> messsageName = adoptWK(WKStringCreateWithUTF8CString("GetDumpFrameLoadCallbacks"));
218     WKTypeRef returnData = nullptr;
219     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messsageName.get(), nullptr, &returnData);
220     ASSERT(WKGetTypeID(returnData) == WKBooleanGetTypeID());
221     return WKBooleanGetValue(adoptWK(static_cast<WKBooleanRef>(returnData)).get());
222 }
223
224 unsigned TestRunner::imageCountInGeneralPasteboard() const
225 {
226     return InjectedBundle::singleton().imageCountInGeneralPasteboard();
227 }
228
229 void TestRunner::addUserScript(JSStringRef source, bool runAtStart, bool allFrames)
230 {
231     WKRetainPtr<WKStringRef> sourceWK = toWK(source);
232
233     WKBundlePageAddUserScript(InjectedBundle::singleton().page()->page(), sourceWK.get(),
234         (runAtStart ? kWKInjectAtDocumentStart : kWKInjectAtDocumentEnd),
235         (allFrames ? kWKInjectInAllFrames : kWKInjectInTopFrameOnly));
236 }
237
238 void TestRunner::addUserStyleSheet(JSStringRef source, bool allFrames)
239 {
240     WKRetainPtr<WKStringRef> sourceWK = toWK(source);
241
242     WKBundlePageAddUserStyleSheet(InjectedBundle::singleton().page()->page(), sourceWK.get(),
243         (allFrames ? kWKInjectInAllFrames : kWKInjectInTopFrameOnly));
244 }
245
246 void TestRunner::keepWebHistory()
247 {
248     InjectedBundle::singleton().postSetAddsVisitedLinks(true);
249 }
250
251 void TestRunner::execCommand(JSStringRef name, JSStringRef showUI, JSStringRef value)
252 {
253     WKBundlePageExecuteEditingCommand(InjectedBundle::singleton().page()->page(), toWK(name).get(), toWK(value).get());
254 }
255
256 static Optional<WKFindOptions> findOptionsFromArray(JSValueRef optionsArrayAsValue)
257 {
258     auto& injectedBundle = InjectedBundle::singleton();
259     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(injectedBundle.page()->page());
260     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
261     auto lengthPropertyName = adopt(JSStringCreateWithUTF8CString("length"));
262     JSObjectRef optionsArray = JSValueToObject(context, optionsArrayAsValue, 0);
263     JSValueRef lengthValue = JSObjectGetProperty(context, optionsArray, lengthPropertyName.get(), 0);
264     if (!JSValueIsNumber(context, lengthValue))
265         return WTF::nullopt;
266
267     WKFindOptions options = 0;
268     size_t length = static_cast<size_t>(JSValueToNumber(context, lengthValue, 0));
269     for (size_t i = 0; i < length; ++i) {
270         JSValueRef value = JSObjectGetPropertyAtIndex(context, optionsArray, i, 0);
271         if (!JSValueIsString(context, value))
272             continue;
273
274         auto optionName = adopt(JSValueToStringCopy(context, value, 0));
275
276         if (JSStringIsEqualToUTF8CString(optionName.get(), "CaseInsensitive"))
277             options |= kWKFindOptionsCaseInsensitive;
278         else if (JSStringIsEqualToUTF8CString(optionName.get(), "AtWordStarts"))
279             options |= kWKFindOptionsAtWordStarts;
280         else if (JSStringIsEqualToUTF8CString(optionName.get(), "TreatMedialCapitalAsWordStart"))
281             options |= kWKFindOptionsTreatMedialCapitalAsWordStart;
282         else if (JSStringIsEqualToUTF8CString(optionName.get(), "Backwards"))
283             options |= kWKFindOptionsBackwards;
284         else if (JSStringIsEqualToUTF8CString(optionName.get(), "WrapAround"))
285             options |= kWKFindOptionsWrapAround;
286         else if (JSStringIsEqualToUTF8CString(optionName.get(), "StartInSelection")) {
287             // FIXME: No kWKFindOptionsStartInSelection.
288         }
289     }
290     return options;
291 }
292
293 bool TestRunner::findString(JSStringRef target, JSValueRef optionsArrayAsValue)
294 {
295     if (auto options = findOptionsFromArray(optionsArrayAsValue))
296         return WKBundlePageFindString(InjectedBundle::singleton().page()->page(), toWK(target).get(), *options);
297
298     return false;
299 }
300
301 void TestRunner::findStringMatchesInPage(JSStringRef target, JSValueRef optionsArrayAsValue)
302 {
303     if (auto options = findOptionsFromArray(optionsArrayAsValue))
304         return WKBundlePageFindStringMatches(InjectedBundle::singleton().page()->page(), toWK(target).get(), *options);
305 }
306
307 void TestRunner::replaceFindMatchesAtIndices(JSValueRef matchIndicesAsValue, JSStringRef replacementText, bool selectionOnly)
308 {
309     auto& bundle = InjectedBundle::singleton();
310     auto mainFrame = WKBundlePageGetMainFrame(bundle.page()->page());
311     auto context = WKBundleFrameGetJavaScriptContext(mainFrame);
312     auto lengthPropertyName = adopt(JSStringCreateWithUTF8CString("length"));
313     auto matchIndicesObject = JSValueToObject(context, matchIndicesAsValue, 0);
314     auto lengthValue = JSObjectGetProperty(context, matchIndicesObject, lengthPropertyName.get(), 0);
315     if (!JSValueIsNumber(context, lengthValue))
316         return;
317
318     auto indices = adoptWK(WKMutableArrayCreate());
319     auto length = static_cast<size_t>(JSValueToNumber(context, lengthValue, 0));
320     for (size_t i = 0; i < length; ++i) {
321         auto value = JSObjectGetPropertyAtIndex(context, matchIndicesObject, i, 0);
322         if (!JSValueIsNumber(context, value))
323             continue;
324
325         auto index = adoptWK(WKUInt64Create(std::round(JSValueToNumber(context, value, nullptr))));
326         WKArrayAppendItem(indices.get(), index.get());
327     }
328     WKBundlePageReplaceStringMatches(bundle.page()->page(), indices.get(), toWK(replacementText).get(), selectionOnly);
329 }
330
331 void TestRunner::clearAllDatabases()
332 {
333     WKBundleClearAllDatabases(InjectedBundle::singleton().bundle());
334
335     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("DeleteAllIndexedDatabases"));
336     WKRetainPtr<WKBooleanRef> messageBody = adoptWK(WKBooleanCreate(true));
337
338     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
339 }
340
341 void TestRunner::setDatabaseQuota(uint64_t quota)
342 {
343     return WKBundleSetDatabaseQuota(InjectedBundle::singleton().bundle(), quota);
344 }
345
346 void TestRunner::syncLocalStorage()
347 {
348     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SyncLocalStorage"));
349     WKRetainPtr<WKBooleanRef> messageBody = adoptWK(WKBooleanCreate(true));
350     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
351 }
352
353 void TestRunner::clearAllApplicationCaches()
354 {
355     WKBundlePageClearApplicationCache(InjectedBundle::singleton().page()->page());
356 }
357
358 void TestRunner::clearApplicationCacheForOrigin(JSStringRef origin)
359 {
360     WKBundlePageClearApplicationCacheForOrigin(InjectedBundle::singleton().page()->page(), toWK(origin).get());
361 }
362
363 void TestRunner::setAppCacheMaximumSize(uint64_t size)
364 {
365     WKBundlePageSetAppCacheMaximumSize(InjectedBundle::singleton().page()->page(), size);
366 }
367
368 long long TestRunner::applicationCacheDiskUsageForOrigin(JSStringRef origin)
369 {
370     return WKBundlePageGetAppCacheUsageForOrigin(InjectedBundle::singleton().page()->page(), toWK(origin).get());
371 }
372
373 void TestRunner::disallowIncreaseForApplicationCacheQuota()
374 {
375     m_disallowIncreaseForApplicationCacheQuota = true;
376 }
377
378 static inline JSValueRef stringArrayToJS(JSContextRef context, WKArrayRef strings)
379 {
380     const size_t count = WKArrayGetSize(strings);
381
382     JSValueRef arrayResult = JSObjectMakeArray(context, 0, 0, 0);
383     JSObjectRef arrayObj = JSValueToObject(context, arrayResult, 0);
384     for (size_t i = 0; i < count; ++i) {
385         WKStringRef stringRef = static_cast<WKStringRef>(WKArrayGetItemAtIndex(strings, i));
386         JSRetainPtr<JSStringRef> stringJS = toJS(stringRef);
387         JSObjectSetPropertyAtIndex(context, arrayObj, i, JSValueMakeString(context, stringJS.get()), 0);
388     }
389
390     return arrayResult;
391 }
392
393 JSValueRef TestRunner::originsWithApplicationCache()
394 {
395     WKBundlePageRef page = InjectedBundle::singleton().page()->page();
396
397     WKRetainPtr<WKArrayRef> origins = adoptWK(WKBundlePageCopyOriginsWithApplicationCache(page));
398
399     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(page);
400     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
401
402     return stringArrayToJS(context, origins.get());
403 }
404
405 bool TestRunner::isCommandEnabled(JSStringRef name)
406 {
407     return WKBundlePageIsEditingCommandEnabled(InjectedBundle::singleton().page()->page(), toWK(name).get());
408 }
409
410 void TestRunner::setCanOpenWindows()
411 {
412     WKRetainPtr<WKStringRef> messsageName = adoptWK(WKStringCreateWithUTF8CString("SetCanOpenWindows"));
413     WKRetainPtr<WKBooleanRef> messageBody = adoptWK(WKBooleanCreate(true));
414     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messsageName.get(), messageBody.get(), nullptr);
415 }
416
417 void TestRunner::setXSSAuditorEnabled(bool enabled)
418 {
419     WKRetainPtr<WKStringRef> key = adoptWK(WKStringCreateWithUTF8CString("WebKitXSSAuditorEnabled"));
420     auto& injectedBundle = InjectedBundle::singleton();
421     WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
422 }
423
424 void TestRunner::setMediaDevicesEnabled(bool enabled)
425 {
426     WKRetainPtr<WKStringRef> key = adoptWK(WKStringCreateWithUTF8CString("WebKitMediaDevicesEnabled"));
427     auto& injectedBundle = InjectedBundle::singleton();
428     WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
429 }
430
431 void TestRunner::setWebRTCMDNSICECandidatesEnabled(bool enabled)
432 {
433     WKRetainPtr<WKStringRef> key = adoptWK(WKStringCreateWithUTF8CString("WebKitWebRTCMDNSICECandidatesEnabled"));
434     auto& injectedBundle = InjectedBundle::singleton();
435     WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
436 }
437
438 void TestRunner::setWebRTCUnifiedPlanEnabled(bool enabled)
439 {
440     WKRetainPtr<WKStringRef> key = adoptWK(WKStringCreateWithUTF8CString("WebKitWebRTCUnifiedPlanEnabled"));
441     auto& injectedBundle = InjectedBundle::singleton();
442     WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
443 }
444
445 void TestRunner::setCustomUserAgent(JSStringRef userAgent)
446 {
447     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetCustomUserAgent"));
448     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), toWK(userAgent).get(), nullptr);
449 }
450
451 void TestRunner::setWebAPIStatisticsEnabled(bool enabled)
452 {
453     WKRetainPtr<WKStringRef> key = adoptWK(WKStringCreateWithUTF8CString("WebKitWebAPIStatisticsEnabled"));
454     auto& injectedBundle = InjectedBundle::singleton();
455     WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
456 }
457
458 void TestRunner::setModernMediaControlsEnabled(bool enabled)
459 {
460     WKRetainPtr<WKStringRef> key = adoptWK(WKStringCreateWithUTF8CString("WebKitModernMediaControlsEnabled"));
461     auto& injectedBundle = InjectedBundle::singleton();
462     WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
463 }
464
465 void TestRunner::setWebGL2Enabled(bool enabled)
466 {
467     WKRetainPtr<WKStringRef> key = adoptWK(WKStringCreateWithUTF8CString("WebKitWebGL2Enabled"));
468     auto& injectedBundle = InjectedBundle::singleton();
469     WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
470 }
471
472 void TestRunner::setWritableStreamAPIEnabled(bool enabled)
473 {
474     WKRetainPtr<WKStringRef> key = adoptWK(WKStringCreateWithUTF8CString("WebKitWritableStreamAPIEnabled"));
475     auto& injectedBundle = InjectedBundle::singleton();
476     WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
477 }
478
479 void TestRunner::setReadableByteStreamAPIEnabled(bool enabled)
480 {
481     WKRetainPtr<WKStringRef> key = adoptWK(WKStringCreateWithUTF8CString("WebKitReadableByteStreamAPIEnabled"));
482     auto& injectedBundle = InjectedBundle::singleton();
483     WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
484 }
485
486 void TestRunner::setEncryptedMediaAPIEnabled(bool enabled)
487 {
488     WKRetainPtr<WKStringRef> key = adoptWK(WKStringCreateWithUTF8CString("WebKitEncryptedMediaAPIEnabled"));
489     auto& injectedBundle = InjectedBundle::singleton();
490     WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
491 }
492
493 void TestRunner::setAllowsAnySSLCertificate(bool enabled)
494 {
495     auto& injectedBundle = InjectedBundle::singleton();
496     injectedBundle.setAllowsAnySSLCertificate(enabled);
497
498     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetAllowsAnySSLCertificate"));
499     WKRetainPtr<WKBooleanRef> messageBody = adoptWK(WKBooleanCreate(enabled));
500     WKBundlePagePostSynchronousMessageForTesting(injectedBundle.page()->page(), messageName.get(), messageBody.get(), nullptr);
501 }
502
503 void TestRunner::setShouldSwapToEphemeralSessionOnNextNavigation(bool shouldSwap)
504 {
505     auto& injectedBundle = InjectedBundle::singleton();
506
507     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetShouldSwapToEphemeralSessionOnNextNavigation"));
508     WKRetainPtr<WKBooleanRef> messageBody = adoptWK(WKBooleanCreate(shouldSwap));
509     WKBundlePagePostSynchronousMessageForTesting(injectedBundle.page()->page(), messageName.get(), messageBody.get(), nullptr);
510 }
511
512 void TestRunner::setShouldSwapToDefaultSessionOnNextNavigation(bool shouldSwap)
513 {
514     auto& injectedBundle = InjectedBundle::singleton();
515
516     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetShouldSwapToDefaultSessionOnNextNavigation"));
517     WKRetainPtr<WKBooleanRef> messageBody = adoptWK(WKBooleanCreate(shouldSwap));
518     WKBundlePagePostSynchronousMessageForTesting(injectedBundle.page()->page(), messageName.get(), messageBody.get(), nullptr);
519 }
520
521 void TestRunner::setAllowUniversalAccessFromFileURLs(bool enabled)
522 {
523     auto& injectedBundle = InjectedBundle::singleton();
524     WKBundleSetAllowUniversalAccessFromFileURLs(injectedBundle.bundle(), injectedBundle.pageGroup(), enabled);
525 }
526
527 void TestRunner::setAllowFileAccessFromFileURLs(bool enabled)
528 {
529     auto& injectedBundle = InjectedBundle::singleton();
530     WKBundleSetAllowFileAccessFromFileURLs(injectedBundle.bundle(), injectedBundle.pageGroup(), enabled);
531 }
532
533 void TestRunner::setNeedsStorageAccessFromFileURLsQuirk(bool needsQuirk)
534 {
535     auto& injectedBundle = InjectedBundle::singleton();
536     WKBundleSetAllowStorageAccessFromFileURLS(injectedBundle.bundle(), injectedBundle.pageGroup(), needsQuirk);
537 }
538     
539 void TestRunner::setPluginsEnabled(bool enabled)
540 {
541     WKRetainPtr<WKStringRef> key = adoptWK(WKStringCreateWithUTF8CString("WebKitPluginsEnabled"));
542     auto& injectedBundle = InjectedBundle::singleton();
543     WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
544 }
545
546 void TestRunner::setJavaScriptCanAccessClipboard(bool enabled)
547 {
548     auto& injectedBundle = InjectedBundle::singleton();
549     WKBundleSetJavaScriptCanAccessClipboard(injectedBundle.bundle(), injectedBundle.pageGroup(), enabled);
550 }
551
552 void TestRunner::setPopupBlockingEnabled(bool enabled)
553 {
554     auto& injectedBundle = InjectedBundle::singleton();
555     WKBundleSetPopupBlockingEnabled(injectedBundle.bundle(), injectedBundle.pageGroup(), enabled);
556 }
557
558 void TestRunner::setAuthorAndUserStylesEnabled(bool enabled)
559 {
560     auto& injectedBundle = InjectedBundle::singleton();
561     WKBundleSetAuthorAndUserStylesEnabled(injectedBundle.bundle(), injectedBundle.pageGroup(), enabled);
562 }
563
564 void TestRunner::addOriginAccessWhitelistEntry(JSStringRef sourceOrigin, JSStringRef destinationProtocol, JSStringRef destinationHost, bool allowDestinationSubdomains)
565 {
566     WKBundleAddOriginAccessWhitelistEntry(InjectedBundle::singleton().bundle(), toWK(sourceOrigin).get(), toWK(destinationProtocol).get(), toWK(destinationHost).get(), allowDestinationSubdomains);
567 }
568
569 void TestRunner::removeOriginAccessWhitelistEntry(JSStringRef sourceOrigin, JSStringRef destinationProtocol, JSStringRef destinationHost, bool allowDestinationSubdomains)
570 {
571     WKBundleRemoveOriginAccessWhitelistEntry(InjectedBundle::singleton().bundle(), toWK(sourceOrigin).get(), toWK(destinationProtocol).get(), toWK(destinationHost).get(), allowDestinationSubdomains);
572 }
573
574 bool TestRunner::isPageBoxVisible(int pageIndex)
575 {
576     auto& injectedBundle = InjectedBundle::singleton();
577     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(injectedBundle.page()->page());
578     return WKBundleIsPageBoxVisible(injectedBundle.bundle(), mainFrame, pageIndex);
579 }
580
581 void TestRunner::setValueForUser(JSContextRef context, JSValueRef element, JSStringRef value)
582 {
583     if (!element || !JSValueIsObject(context, element))
584         return;
585
586     WKRetainPtr<WKBundleNodeHandleRef> nodeHandle = adoptWK(WKBundleNodeHandleCreate(context, const_cast<JSObjectRef>(element)));
587     WKBundleNodeHandleSetHTMLInputElementValueForUser(nodeHandle.get(), toWK(value).get());
588 }
589
590 void TestRunner::setAudioResult(JSContextRef context, JSValueRef data)
591 {
592     auto& injectedBundle = InjectedBundle::singleton();
593     // FIXME (123058): Use a JSC API to get buffer contents once such is exposed.
594     WKRetainPtr<WKDataRef> audioData = adoptWK(WKBundleCreateWKDataFromUInt8Array(injectedBundle.bundle(), context, data));
595     injectedBundle.setAudioResult(audioData.get());
596     setWhatToDump(WhatToDump::Audio);
597     setDumpPixels(false);
598 }
599
600 unsigned TestRunner::windowCount()
601 {
602     return InjectedBundle::singleton().pageCount();
603 }
604
605 void TestRunner::clearBackForwardList()
606 {
607     WKBundleClearHistoryForTesting(InjectedBundle::singleton().page()->page());
608 }
609
610 // Object Creation
611
612 void TestRunner::makeWindowObject(JSContextRef context, JSObjectRef windowObject, JSValueRef* exception)
613 {
614     setProperty(context, windowObject, "testRunner", this, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete, exception);
615 }
616
617 void TestRunner::showWebInspector()
618 {
619     WKBundleInspectorShow(WKBundlePageGetInspector(InjectedBundle::singleton().page()->page()));
620 }
621
622 void TestRunner::closeWebInspector()
623 {
624     WKBundleInspectorClose(WKBundlePageGetInspector(InjectedBundle::singleton().page()->page()));
625 }
626
627 void TestRunner::evaluateInWebInspector(JSStringRef script)
628 {
629     WKRetainPtr<WKStringRef> scriptWK = toWK(script);
630     WKBundleInspectorEvaluateScriptForTest(WKBundlePageGetInspector(InjectedBundle::singleton().page()->page()), scriptWK.get());
631 }
632
633 typedef WTF::HashMap<unsigned, WKRetainPtr<WKBundleScriptWorldRef> > WorldMap;
634 static WorldMap& worldMap()
635 {
636     static WorldMap& map = *new WorldMap;
637     return map;
638 }
639
640 unsigned TestRunner::worldIDForWorld(WKBundleScriptWorldRef world)
641 {
642     WorldMap::const_iterator end = worldMap().end();
643     for (WorldMap::const_iterator it = worldMap().begin(); it != end; ++it) {
644         if (it->value == world)
645             return it->key;
646     }
647
648     return 0;
649 }
650
651 void TestRunner::evaluateScriptInIsolatedWorld(JSContextRef context, unsigned worldID, JSStringRef script)
652 {
653     // A worldID of 0 always corresponds to a new world. Any other worldID corresponds to a world
654     // that is created once and cached forever.
655     WKRetainPtr<WKBundleScriptWorldRef> world;
656     if (!worldID)
657         world.adopt(WKBundleScriptWorldCreateWorld());
658     else {
659         WKRetainPtr<WKBundleScriptWorldRef>& worldSlot = worldMap().add(worldID, nullptr).iterator->value;
660         if (!worldSlot)
661             worldSlot.adopt(WKBundleScriptWorldCreateWorld());
662         world = worldSlot;
663     }
664
665     WKBundleFrameRef frame = WKBundleFrameForJavaScriptContext(context);
666     if (!frame)
667         frame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
668
669     JSGlobalContextRef jsContext = WKBundleFrameGetJavaScriptContextForWorld(frame, world.get());
670     JSEvaluateScript(jsContext, script, 0, 0, 0, 0); 
671 }
672
673 void TestRunner::setPOSIXLocale(JSStringRef locale)
674 {
675     char localeBuf[32];
676     JSStringGetUTF8CString(locale, localeBuf, sizeof(localeBuf));
677     setlocale(LC_ALL, localeBuf);
678 }
679
680 void TestRunner::setTextDirection(JSStringRef direction)
681 {
682     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
683     return WKBundleFrameSetTextDirection(mainFrame, toWK(direction).get());
684 }
685     
686 void TestRunner::setShouldStayOnPageAfterHandlingBeforeUnload(bool shouldStayOnPage)
687 {
688     InjectedBundle::singleton().postNewBeforeUnloadReturnValue(!shouldStayOnPage);
689 }
690
691 bool TestRunner::didReceiveServerRedirectForProvisionalNavigation() const
692 {
693     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("DidReceiveServerRedirectForProvisionalNavigation"));
694     WKTypeRef returnData = nullptr;
695     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), nullptr, &returnData);
696     ASSERT(WKGetTypeID(returnData) == WKBooleanGetTypeID());
697     return WKBooleanGetValue(adoptWK(static_cast<WKBooleanRef>(returnData)).get());
698 }
699
700 void TestRunner::clearDidReceiveServerRedirectForProvisionalNavigation()
701 {
702     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("ClearDidReceiveServerRedirectForProvisionalNavigation"));
703     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), nullptr, nullptr);
704 }
705
706 void TestRunner::setPageVisibility(JSStringRef state)
707 {
708     InjectedBundle::singleton().setHidden(JSStringIsEqualToUTF8CString(state, "hidden") || JSStringIsEqualToUTF8CString(state, "prerender"));
709 }
710
711 void TestRunner::resetPageVisibility()
712 {
713     InjectedBundle::singleton().setHidden(false);
714 }
715
716 typedef WTF::HashMap<unsigned, JSValueRef> CallbackMap;
717 static CallbackMap& callbackMap()
718 {
719     static CallbackMap& map = *new CallbackMap;
720     return map;
721 }
722
723 enum {
724     AddChromeInputFieldCallbackID = 1,
725     RemoveChromeInputFieldCallbackID,
726     FocusWebViewCallbackID,
727     SetBackingScaleFactorCallbackID,
728     DidBeginSwipeCallbackID,
729     WillEndSwipeCallbackID,
730     DidEndSwipeCallbackID,
731     DidRemoveSwipeSnapshotCallbackID,
732     SetStatisticsDebugModeCallbackID,
733     SetStatisticsPrevalentResourceForDebugModeCallbackID,
734     SetStatisticsLastSeenCallbackID,
735     SetStatisticsMergeStatisticCallbackID,
736     SetStatisticsPrevalentResourceCallbackID,
737     SetStatisticsVeryPrevalentResourceCallbackID,
738     SetStatisticsHasHadUserInteractionCallbackID,
739     StatisticsDidModifyDataRecordsCallbackID,
740     StatisticsDidScanDataRecordsCallbackID,
741     StatisticsDidRunTelemetryCallbackID,
742     StatisticsDidClearThroughWebsiteDataRemovalCallbackID,
743     StatisticsDidResetToConsistentStateCallbackID,
744     StatisticsDidSetBlockCookiesForHostCallbackID,
745     StatisticsDidSetShouldDowngradeReferrerCallbackID,
746     AllStorageAccessEntriesCallbackID,
747     DidRemoveAllSessionCredentialsCallbackID,
748     GetApplicationManifestCallbackID,
749     TextDidChangeInTextFieldCallbackID,
750     TextFieldDidBeginEditingCallbackID,
751     TextFieldDidEndEditingCallbackID,
752     CustomMenuActionCallbackID,
753     FirstUIScriptCallbackID = 100
754 };
755
756 static void cacheTestRunnerCallback(unsigned index, JSValueRef callback)
757 {
758     if (!callback)
759         return;
760
761     if (callbackMap().contains(index)) {
762         InjectedBundle::singleton().outputText(makeString("FAIL: Tried to install a second TestRunner callback for the same event (id ", index, ")\n\n"));
763         return;
764     }
765
766     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
767     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
768     JSValueProtect(context, callback);
769     callbackMap().add(index, callback);
770 }
771
772 static void callTestRunnerCallback(unsigned index, size_t argumentCount = 0, const JSValueRef arguments[] = nullptr)
773 {
774     if (!callbackMap().contains(index))
775         return;
776     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
777     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
778     JSObjectRef callback = JSValueToObject(context, callbackMap().take(index), 0);
779     JSObjectCallAsFunction(context, callback, JSContextGetGlobalObject(context), argumentCount, arguments, 0);
780     JSValueUnprotect(context, callback);
781 }
782
783 void TestRunner::clearTestRunnerCallbacks()
784 {
785     for (auto& iter : callbackMap()) {
786         WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
787         JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
788         JSObjectRef callback = JSValueToObject(context, iter.value, 0);
789         JSValueUnprotect(context, callback);
790     }
791
792     callbackMap().clear();
793 }
794
795 void TestRunner::accummulateLogsForChannel(JSStringRef)
796 {
797     // FIXME: Implement getting the call to all processes.
798 }
799
800 void TestRunner::addChromeInputField(JSValueRef callback)
801 {
802     cacheTestRunnerCallback(AddChromeInputFieldCallbackID, callback);
803     InjectedBundle::singleton().postAddChromeInputField();
804 }
805
806 void TestRunner::removeChromeInputField(JSValueRef callback)
807 {
808     cacheTestRunnerCallback(RemoveChromeInputFieldCallbackID, callback);
809     InjectedBundle::singleton().postRemoveChromeInputField();
810 }
811
812 void TestRunner::focusWebView(JSValueRef callback)
813 {
814     cacheTestRunnerCallback(FocusWebViewCallbackID, callback);
815     InjectedBundle::singleton().postFocusWebView();
816 }
817
818 void TestRunner::setBackingScaleFactor(double backingScaleFactor, JSValueRef callback)
819 {
820     cacheTestRunnerCallback(SetBackingScaleFactorCallbackID, callback);
821     InjectedBundle::singleton().postSetBackingScaleFactor(backingScaleFactor);
822 }
823
824 void TestRunner::setWindowIsKey(bool isKey)
825 {
826     InjectedBundle::singleton().postSetWindowIsKey(isKey);
827 }
828
829 void TestRunner::setViewSize(double width, double height)
830 {
831     InjectedBundle::singleton().postSetViewSize(width, height);
832 }
833
834 void TestRunner::callAddChromeInputFieldCallback()
835 {
836     callTestRunnerCallback(AddChromeInputFieldCallbackID);
837 }
838
839 void TestRunner::callRemoveChromeInputFieldCallback()
840 {
841     callTestRunnerCallback(RemoveChromeInputFieldCallbackID);
842 }
843
844 void TestRunner::callFocusWebViewCallback()
845 {
846     callTestRunnerCallback(FocusWebViewCallbackID);
847 }
848
849 void TestRunner::callSetBackingScaleFactorCallback()
850 {
851     callTestRunnerCallback(SetBackingScaleFactorCallbackID);
852 }
853
854 static inline bool toBool(JSStringRef value)
855 {
856     return JSStringIsEqualToUTF8CString(value, "true") || JSStringIsEqualToUTF8CString(value, "1");
857 }
858
859 void TestRunner::overridePreference(JSStringRef preference, JSStringRef value)
860 {
861     auto& injectedBundle = InjectedBundle::singleton();
862     // Should use `<!-- webkit-test-runner [ enablePageCache=true ] -->` instead.
863     RELEASE_ASSERT(!JSStringIsEqualToUTF8CString(preference, "WebKitUsesPageCachePreferenceKey"));
864
865     // FIXME: handle non-boolean preferences.
866     WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), toWK(preference).get(), toBool(value));
867 }
868
869 void TestRunner::setAlwaysAcceptCookies(bool accept)
870 {
871     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetAlwaysAcceptCookies"));
872
873     WKRetainPtr<WKBooleanRef> messageBody = adoptWK(WKBooleanCreate(accept));
874
875     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
876 }
877
878 void TestRunner::setOnlyAcceptFirstPartyCookies(bool accept)
879 {
880     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetOnlyAcceptFirstPartyCookies"));
881     
882     WKRetainPtr<WKBooleanRef> messageBody = adoptWK(WKBooleanCreate(accept));
883     
884     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
885 }
886
887 double TestRunner::preciseTime()
888 {
889     return WallTime::now().secondsSinceEpoch().seconds();
890 }
891
892 void TestRunner::setRenderTreeDumpOptions(unsigned short options)
893 {
894     m_renderTreeDumpOptions = options;
895 }
896
897 void TestRunner::setUserStyleSheetEnabled(bool enabled)
898 {
899     m_userStyleSheetEnabled = enabled;
900
901     WKRetainPtr<WKStringRef> emptyUrl = adoptWK(WKStringCreateWithUTF8CString(""));
902     WKStringRef location = enabled ? m_userStyleSheetLocation.get() : emptyUrl.get();
903     auto& injectedBundle = InjectedBundle::singleton();
904     WKBundleSetUserStyleSheetLocation(injectedBundle.bundle(), injectedBundle.pageGroup(), location);
905 }
906
907 void TestRunner::setUserStyleSheetLocation(JSStringRef location)
908 {
909     m_userStyleSheetLocation = adoptWK(WKStringCreateWithJSString(location));
910
911     if (m_userStyleSheetEnabled)
912         setUserStyleSheetEnabled(true);
913 }
914
915 void TestRunner::setSpatialNavigationEnabled(bool enabled)
916 {
917     auto& injectedBundle = InjectedBundle::singleton();
918     WKBundleSetSpatialNavigationEnabled(injectedBundle.bundle(), injectedBundle.pageGroup(), enabled);
919 }
920
921 void TestRunner::setTabKeyCyclesThroughElements(bool enabled)
922 {
923     auto& injectedBundle = InjectedBundle::singleton();
924     WKBundleSetTabKeyCyclesThroughElements(injectedBundle.bundle(), injectedBundle.page()->page(), enabled);
925 }
926
927 void TestRunner::setSerializeHTTPLoads()
928 {
929     // WK2 doesn't reorder loads.
930 }
931
932 void TestRunner::dispatchPendingLoadRequests()
933 {
934     // WK2 doesn't keep pending requests.
935 }
936
937 void TestRunner::setCacheModel(int model)
938 {
939     InjectedBundle::singleton().setCacheModel(model);
940 }
941
942 void TestRunner::setAsynchronousSpellCheckingEnabled(bool enabled)
943 {
944     auto& injectedBundle = InjectedBundle::singleton();
945     WKBundleSetAsynchronousSpellCheckingEnabled(injectedBundle.bundle(), injectedBundle.pageGroup(), enabled);
946 }
947
948 void TestRunner::grantWebNotificationPermission(JSStringRef origin)
949 {
950     WKRetainPtr<WKStringRef> originWK = toWK(origin);
951     auto& injectedBundle = InjectedBundle::singleton();
952     WKBundleSetWebNotificationPermission(injectedBundle.bundle(), injectedBundle.page()->page(), originWK.get(), true);
953 }
954
955 void TestRunner::denyWebNotificationPermission(JSStringRef origin)
956 {
957     WKRetainPtr<WKStringRef> originWK = toWK(origin);
958     auto& injectedBundle = InjectedBundle::singleton();
959     WKBundleSetWebNotificationPermission(injectedBundle.bundle(), injectedBundle.page()->page(), originWK.get(), false);
960 }
961
962 void TestRunner::removeAllWebNotificationPermissions()
963 {
964     auto& injectedBundle = InjectedBundle::singleton();
965     WKBundleRemoveAllWebNotificationPermissions(injectedBundle.bundle(), injectedBundle.page()->page());
966 }
967
968 void TestRunner::simulateWebNotificationClick(JSValueRef notification)
969 {
970     auto& injectedBundle = InjectedBundle::singleton();
971     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(injectedBundle.page()->page());
972     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
973     uint64_t notificationID = WKBundleGetWebNotificationID(injectedBundle.bundle(), context, notification);
974     injectedBundle.postSimulateWebNotificationClick(notificationID);
975 }
976
977 void TestRunner::setGeolocationPermission(bool enabled)
978 {
979     // FIXME: this should be done by frame.
980     InjectedBundle::singleton().setGeolocationPermission(enabled);
981 }
982
983 bool TestRunner::isGeolocationProviderActive()
984 {
985     return InjectedBundle::singleton().isGeolocationProviderActive();
986 }
987
988 void TestRunner::setMockGeolocationPosition(double latitude, double longitude, double accuracy, JSValueRef jsAltitude, JSValueRef jsAltitudeAccuracy, JSValueRef jsHeading, JSValueRef jsSpeed, JSValueRef jsFloorLevel)
989 {
990     auto& injectedBundle = InjectedBundle::singleton();
991     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(injectedBundle.page()->page());
992     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
993
994     bool providesAltitude = false;
995     double altitude = 0.;
996     if (!JSValueIsUndefined(context, jsAltitude)) {
997         providesAltitude = true;
998         altitude = JSValueToNumber(context, jsAltitude, 0);
999     }
1000
1001     bool providesAltitudeAccuracy = false;
1002     double altitudeAccuracy = 0.;
1003     if (!JSValueIsUndefined(context, jsAltitudeAccuracy)) {
1004         providesAltitudeAccuracy = true;
1005         altitudeAccuracy = JSValueToNumber(context, jsAltitudeAccuracy, 0);
1006     }
1007
1008     bool providesHeading = false;
1009     double heading = 0.;
1010     if (!JSValueIsUndefined(context, jsHeading)) {
1011         providesHeading = true;
1012         heading = JSValueToNumber(context, jsHeading, 0);
1013     }
1014
1015     bool providesSpeed = false;
1016     double speed = 0.;
1017     if (!JSValueIsUndefined(context, jsSpeed)) {
1018         providesSpeed = true;
1019         speed = JSValueToNumber(context, jsSpeed, 0);
1020     }
1021
1022     bool providesFloorLevel = false;
1023     double floorLevel = 0.;
1024     if (!JSValueIsUndefined(context, jsFloorLevel)) {
1025         providesFloorLevel = true;
1026         floorLevel = JSValueToNumber(context, jsFloorLevel, 0);
1027     }
1028
1029     injectedBundle.setMockGeolocationPosition(latitude, longitude, accuracy, providesAltitude, altitude, providesAltitudeAccuracy, altitudeAccuracy, providesHeading, heading, providesSpeed, speed, providesFloorLevel, floorLevel);
1030 }
1031
1032 void TestRunner::setMockGeolocationPositionUnavailableError(JSStringRef message)
1033 {
1034     WKRetainPtr<WKStringRef> messageWK = toWK(message);
1035     InjectedBundle::singleton().setMockGeolocationPositionUnavailableError(messageWK.get());
1036 }
1037
1038 void TestRunner::setUserMediaPermission(bool enabled)
1039 {
1040     // FIXME: this should be done by frame.
1041     InjectedBundle::singleton().setUserMediaPermission(enabled);
1042 }
1043
1044 void TestRunner::resetUserMediaPermission()
1045 {
1046     // FIXME: this should be done by frame.
1047     InjectedBundle::singleton().resetUserMediaPermission();
1048 }
1049
1050 bool TestRunner::isDoingMediaCapture() const
1051 {
1052     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("IsDoingMediaCapture"));
1053     WKTypeRef returnData = nullptr;
1054     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), nullptr, &returnData);
1055     ASSERT(WKGetTypeID(returnData) == WKBooleanGetTypeID());
1056     return WKBooleanGetValue(adoptWK(static_cast<WKBooleanRef>(returnData)).get());
1057 }
1058
1059 void TestRunner::setUserMediaPersistentPermissionForOrigin(bool permission, JSStringRef origin, JSStringRef parentOrigin)
1060 {
1061     WKRetainPtr<WKStringRef> originWK = toWK(origin);
1062     WKRetainPtr<WKStringRef> parentOriginWK = toWK(parentOrigin);
1063     InjectedBundle::singleton().setUserMediaPersistentPermissionForOrigin(permission, originWK.get(), parentOriginWK.get());
1064 }
1065
1066 unsigned TestRunner::userMediaPermissionRequestCountForOrigin(JSStringRef origin, JSStringRef parentOrigin) const
1067 {
1068     WKRetainPtr<WKStringRef> originWK = toWK(origin);
1069     WKRetainPtr<WKStringRef> parentOriginWK = toWK(parentOrigin);
1070     return InjectedBundle::singleton().userMediaPermissionRequestCountForOrigin(originWK.get(), parentOriginWK.get());
1071 }
1072
1073 void TestRunner::resetUserMediaPermissionRequestCountForOrigin(JSStringRef origin, JSStringRef parentOrigin)
1074 {
1075     WKRetainPtr<WKStringRef> originWK = toWK(origin);
1076     WKRetainPtr<WKStringRef> parentOriginWK = toWK(parentOrigin);
1077     InjectedBundle::singleton().resetUserMediaPermissionRequestCountForOrigin(originWK.get(), parentOriginWK.get());
1078 }
1079
1080 bool TestRunner::callShouldCloseOnWebView()
1081 {
1082     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
1083     return WKBundleFrameCallShouldCloseOnWebView(mainFrame);
1084 }
1085
1086 void TestRunner::queueBackNavigation(unsigned howFarBackward)
1087 {
1088     InjectedBundle::singleton().queueBackNavigation(howFarBackward);
1089 }
1090
1091 void TestRunner::queueForwardNavigation(unsigned howFarForward)
1092 {
1093     InjectedBundle::singleton().queueForwardNavigation(howFarForward);
1094 }
1095
1096 void TestRunner::queueLoad(JSStringRef url, JSStringRef target, bool shouldOpenExternalURLs)
1097 {
1098     auto& injectedBundle = InjectedBundle::singleton();
1099     WKRetainPtr<WKURLRef> baseURLWK = adoptWK(WKBundleFrameCopyURL(WKBundlePageGetMainFrame(injectedBundle.page()->page())));
1100     WKRetainPtr<WKURLRef> urlWK = adoptWK(WKURLCreateWithBaseURL(baseURLWK.get(), toWTFString(toWK(url)).utf8().data()));
1101     WKRetainPtr<WKStringRef> urlStringWK = adoptWK(WKURLCopyString(urlWK.get()));
1102
1103     injectedBundle.queueLoad(urlStringWK.get(), toWK(target).get(), shouldOpenExternalURLs);
1104 }
1105
1106 void TestRunner::queueLoadHTMLString(JSStringRef content, JSStringRef baseURL, JSStringRef unreachableURL)
1107 {
1108     WKRetainPtr<WKStringRef> contentWK = toWK(content);
1109     WKRetainPtr<WKStringRef> baseURLWK = baseURL ? toWK(baseURL) : WKRetainPtr<WKStringRef>();
1110     WKRetainPtr<WKStringRef> unreachableURLWK = unreachableURL ? toWK(unreachableURL) : WKRetainPtr<WKStringRef>();
1111
1112     InjectedBundle::singleton().queueLoadHTMLString(contentWK.get(), baseURLWK.get(), unreachableURLWK.get());
1113 }
1114
1115 void TestRunner::queueReload()
1116 {
1117     InjectedBundle::singleton().queueReload();
1118 }
1119
1120 void TestRunner::queueLoadingScript(JSStringRef script)
1121 {
1122     WKRetainPtr<WKStringRef> scriptWK = toWK(script);
1123     InjectedBundle::singleton().queueLoadingScript(scriptWK.get());
1124 }
1125
1126 void TestRunner::queueNonLoadingScript(JSStringRef script)
1127 {
1128     WKRetainPtr<WKStringRef> scriptWK = toWK(script);
1129     InjectedBundle::singleton().queueNonLoadingScript(scriptWK.get());
1130 }
1131
1132 void TestRunner::setRejectsProtectionSpaceAndContinueForAuthenticationChallenges(bool value)
1133 {
1134     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetRejectsProtectionSpaceAndContinueForAuthenticationChallenges"));
1135     WKRetainPtr<WKBooleanRef> messageBody = adoptWK(WKBooleanCreate(value));
1136     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
1137 }
1138     
1139 void TestRunner::setHandlesAuthenticationChallenges(bool handlesAuthenticationChallenges)
1140 {
1141     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetHandlesAuthenticationChallenges"));
1142     WKRetainPtr<WKBooleanRef> messageBody = adoptWK(WKBooleanCreate(handlesAuthenticationChallenges));
1143     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
1144 }
1145
1146 void TestRunner::setShouldLogCanAuthenticateAgainstProtectionSpace(bool value)
1147 {
1148     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetShouldLogCanAuthenticateAgainstProtectionSpace"));
1149     WKRetainPtr<WKBooleanRef> messageBody = adoptWK(WKBooleanCreate(value));
1150     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
1151 }
1152
1153 void TestRunner::setShouldLogDownloadCallbacks(bool value)
1154 {
1155     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetShouldLogDownloadCallbacks"));
1156     WKRetainPtr<WKBooleanRef> messageBody = adoptWK(WKBooleanCreate(value));
1157     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
1158 }
1159
1160 void TestRunner::setAuthenticationUsername(JSStringRef username)
1161 {
1162     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetAuthenticationUsername"));
1163     WKRetainPtr<WKStringRef> messageBody = adoptWK(WKStringCreateWithJSString(username));
1164     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
1165 }
1166
1167 void TestRunner::setAuthenticationPassword(JSStringRef password)
1168 {
1169     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetAuthenticationPassword"));
1170     WKRetainPtr<WKStringRef> messageBody = adoptWK(WKStringCreateWithJSString(password));
1171     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
1172 }
1173
1174 bool TestRunner::secureEventInputIsEnabled() const
1175 {
1176     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SecureEventInputIsEnabled"));
1177     WKTypeRef returnData = nullptr;
1178     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), nullptr, &returnData);
1179     ASSERT(WKGetTypeID(returnData) == WKBooleanGetTypeID());
1180     return WKBooleanGetValue(adoptWK(static_cast<WKBooleanRef>(returnData)).get());
1181 }
1182
1183 void TestRunner::setBlockAllPlugins(bool shouldBlock)
1184 {
1185     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetBlockAllPlugins"));
1186     WKRetainPtr<WKBooleanRef> messageBody = adoptWK(WKBooleanCreate(shouldBlock));
1187     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
1188 }
1189
1190 void TestRunner::setPluginSupportedMode(JSStringRef mode)
1191 {
1192     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetPluginSupportedMode"));
1193     WKRetainPtr<WKStringRef> messageBody = adoptWK(WKStringCreateWithJSString(mode));
1194     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
1195 }
1196
1197 JSValueRef TestRunner::failNextNewCodeBlock()
1198 {
1199     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
1200     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
1201     return JSC::failNextNewCodeBlock(context);
1202 }
1203
1204 JSValueRef TestRunner::numberOfDFGCompiles(JSValueRef theFunction)
1205 {
1206     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
1207     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
1208     return JSC::numberOfDFGCompiles(context, theFunction);
1209 }
1210
1211 JSValueRef TestRunner::neverInlineFunction(JSValueRef theFunction)
1212 {
1213     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
1214     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
1215     return JSC::setNeverInline(context, theFunction);
1216 }
1217
1218 void TestRunner::setShouldDecideNavigationPolicyAfterDelay(bool value)
1219 {
1220     m_shouldDecideNavigationPolicyAfterDelay = value;
1221     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetShouldDecideNavigationPolicyAfterDelay"));
1222     WKRetainPtr<WKBooleanRef> messageBody = adoptWK(WKBooleanCreate(value));
1223     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
1224 }
1225
1226 void TestRunner::setShouldDecideResponsePolicyAfterDelay(bool value)
1227 {
1228     m_shouldDecideResponsePolicyAfterDelay = value;
1229     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetShouldDecideResponsePolicyAfterDelay"));
1230     WKRetainPtr<WKBooleanRef> messageBody = adoptWK(WKBooleanCreate(value));
1231     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
1232 }
1233
1234 void TestRunner::setNavigationGesturesEnabled(bool value)
1235 {
1236     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetNavigationGesturesEnabled"));
1237     WKRetainPtr<WKBooleanRef> messageBody = adoptWK(WKBooleanCreate(value));
1238     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
1239 }
1240
1241 void TestRunner::setIgnoresViewportScaleLimits(bool value)
1242 {
1243     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetIgnoresViewportScaleLimits"));
1244     WKRetainPtr<WKBooleanRef> messageBody = adoptWK(WKBooleanCreate(value));
1245     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
1246 }
1247
1248 void TestRunner::setShouldDownloadUndisplayableMIMETypes(bool value)
1249 {
1250     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetShouldDownloadUndisplayableMIMETypes"));
1251     WKRetainPtr<WKBooleanRef> messageBody = adoptWK(WKBooleanCreate(value));
1252     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
1253 }
1254
1255 void TestRunner::setShouldAllowDeviceOrientationAndMotionAccess(bool value)
1256 {
1257     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetShouldAllowDeviceOrientationAndMotionAccess"));
1258     WKRetainPtr<WKBooleanRef> messageBody = adoptWK(WKBooleanCreate(value));
1259     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
1260 }
1261
1262 void TestRunner::terminateNetworkProcess()
1263 {
1264     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("TerminateNetworkProcess"));
1265     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), nullptr, nullptr);
1266 }
1267
1268 void TestRunner::terminateServiceWorkerProcess()
1269 {
1270     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("TerminateServiceWorkerProcess"));
1271     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), nullptr, nullptr);
1272 }
1273
1274 static unsigned nextUIScriptCallbackID()
1275 {
1276     static unsigned callbackID = FirstUIScriptCallbackID;
1277     return callbackID++;
1278 }
1279
1280 void TestRunner::runUIScript(JSStringRef script, JSValueRef callback)
1281 {
1282     unsigned callbackID = nextUIScriptCallbackID();
1283     cacheTestRunnerCallback(callbackID, callback);
1284
1285     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("RunUIProcessScript"));
1286
1287     WKRetainPtr<WKMutableDictionaryRef> testDictionary = adoptWK(WKMutableDictionaryCreate());
1288
1289     WKRetainPtr<WKStringRef> scriptKey = adoptWK(WKStringCreateWithUTF8CString("Script"));
1290     WKRetainPtr<WKStringRef> scriptValue = adoptWK(WKStringCreateWithJSString(script));
1291
1292     WKRetainPtr<WKStringRef> callbackIDKey = adoptWK(WKStringCreateWithUTF8CString("CallbackID"));
1293     WKRetainPtr<WKUInt64Ref> callbackIDValue = adoptWK(WKUInt64Create(callbackID));
1294
1295     WKDictionarySetItem(testDictionary.get(), scriptKey.get(), scriptValue.get());
1296     WKDictionarySetItem(testDictionary.get(), callbackIDKey.get(), callbackIDValue.get());
1297
1298     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), testDictionary.get());
1299 }
1300
1301 void TestRunner::runUIScriptCallback(unsigned callbackID, JSStringRef result)
1302 {
1303     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
1304     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
1305
1306     JSValueRef resultValue = JSValueMakeString(context, result);
1307     callTestRunnerCallback(callbackID, 1, &resultValue);
1308 }
1309
1310 void TestRunner::setAllowedMenuActions(JSValueRef actions)
1311 {
1312     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetAllowedMenuActions"));
1313     WKRetainPtr<WKMutableArrayRef> messageBody = adoptWK(WKMutableArrayCreate());
1314
1315     auto page = InjectedBundle::singleton().page()->page();
1316     auto mainFrame = WKBundlePageGetMainFrame(page);
1317     auto context = WKBundleFrameGetJavaScriptContext(mainFrame);
1318     auto lengthPropertyName = adopt(JSStringCreateWithUTF8CString("length"));
1319     auto actionsArray = JSValueToObject(context, actions, nullptr);
1320     auto lengthValue = JSObjectGetProperty(context, actionsArray, lengthPropertyName.get(), nullptr);
1321     if (!JSValueIsNumber(context, lengthValue))
1322         return;
1323
1324     auto length = static_cast<size_t>(JSValueToNumber(context, lengthValue, 0));
1325     for (size_t i = 0; i < length; ++i) {
1326         auto value = JSObjectGetPropertyAtIndex(context, actionsArray, i, 0);
1327         if (!JSValueIsString(context, value))
1328             continue;
1329
1330         auto actionName = adopt(JSValueToStringCopy(context, value, 0));
1331         WKRetainPtr<WKStringRef> action = adoptWK(WKStringCreateWithJSString(actionName.get()));
1332         WKArrayAppendItem(messageBody.get(), action.get());
1333     }
1334
1335     WKBundlePagePostMessage(page, messageName.get(), messageBody.get());
1336 }
1337
1338 void TestRunner::installCustomMenuAction(JSStringRef name, bool dismissesAutomatically, JSValueRef callback)
1339 {
1340     cacheTestRunnerCallback(CustomMenuActionCallbackID, callback);
1341
1342     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("InstallCustomMenuAction"));
1343     WKRetainPtr<WKMutableDictionaryRef> messageBody = adoptWK(WKMutableDictionaryCreate());
1344
1345     WKRetainPtr<WKStringRef> nameKey = adoptWK(WKStringCreateWithUTF8CString("name"));
1346     WKRetainPtr<WKStringRef> nameValue = adoptWK(WKStringCreateWithJSString(name));
1347     WKDictionarySetItem(messageBody.get(), nameKey.get(), nameValue.get());
1348
1349     WKRetainPtr<WKStringRef> dismissesAutomaticallyKey = adoptWK(WKStringCreateWithUTF8CString("dismissesAutomatically"));
1350     WKRetainPtr<WKBooleanRef> dismissesAutomaticallyValue = adoptWK(WKBooleanCreate(dismissesAutomatically));
1351     WKDictionarySetItem(messageBody.get(), dismissesAutomaticallyKey.get(), dismissesAutomaticallyValue.get());
1352
1353     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
1354 }
1355
1356 void TestRunner::installDidBeginSwipeCallback(JSValueRef callback)
1357 {
1358     cacheTestRunnerCallback(DidBeginSwipeCallbackID, callback);
1359 }
1360
1361 void TestRunner::installWillEndSwipeCallback(JSValueRef callback)
1362 {
1363     cacheTestRunnerCallback(WillEndSwipeCallbackID, callback);
1364 }
1365
1366 void TestRunner::installDidEndSwipeCallback(JSValueRef callback)
1367 {
1368     cacheTestRunnerCallback(DidEndSwipeCallbackID, callback);
1369 }
1370
1371 void TestRunner::installDidRemoveSwipeSnapshotCallback(JSValueRef callback)
1372 {
1373     cacheTestRunnerCallback(DidRemoveSwipeSnapshotCallbackID, callback);
1374 }
1375
1376 void TestRunner::callDidBeginSwipeCallback()
1377 {
1378     callTestRunnerCallback(DidBeginSwipeCallbackID);
1379 }
1380
1381 void TestRunner::callWillEndSwipeCallback()
1382 {
1383     callTestRunnerCallback(WillEndSwipeCallbackID);
1384 }
1385
1386 void TestRunner::callDidEndSwipeCallback()
1387 {
1388     callTestRunnerCallback(DidEndSwipeCallbackID);
1389 }
1390
1391 void TestRunner::callDidRemoveSwipeSnapshotCallback()
1392 {
1393     callTestRunnerCallback(DidRemoveSwipeSnapshotCallbackID);
1394 }
1395
1396 void TestRunner::setStatisticsDebugMode(bool value, JSValueRef completionHandler)
1397 {
1398     cacheTestRunnerCallback(SetStatisticsDebugModeCallbackID, completionHandler);
1399
1400     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetStatisticsDebugMode"));
1401     WKRetainPtr<WKBooleanRef> messageBody = adoptWK(WKBooleanCreate(value));
1402     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1403
1404 }
1405
1406 void TestRunner::statisticsCallDidSetDebugModeCallback()
1407 {
1408     callTestRunnerCallback(SetStatisticsDebugModeCallbackID);
1409 }
1410
1411 void TestRunner::setStatisticsPrevalentResourceForDebugMode(JSStringRef hostName, JSValueRef completionHandler)
1412 {
1413     cacheTestRunnerCallback(SetStatisticsPrevalentResourceForDebugModeCallbackID, completionHandler);
1414     
1415     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetStatisticsPrevalentResourceForDebugMode"));
1416     WKRetainPtr<WKStringRef> messageBody = adoptWK(WKStringCreateWithJSString(hostName));
1417     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1418 }
1419
1420 void TestRunner::statisticsCallDidSetPrevalentResourceForDebugModeCallback()
1421 {
1422     callTestRunnerCallback(SetStatisticsPrevalentResourceForDebugModeCallbackID);
1423 }
1424
1425 void TestRunner::setStatisticsLastSeen(JSStringRef hostName, double seconds, JSValueRef completionHandler)
1426 {
1427     cacheTestRunnerCallback(SetStatisticsLastSeenCallbackID, completionHandler);
1428
1429     Vector<WKRetainPtr<WKStringRef>> keys;
1430     Vector<WKRetainPtr<WKTypeRef>> values;
1431     
1432     keys.append(adoptWK(WKStringCreateWithUTF8CString("HostName")));
1433     values.append(adoptWK(WKStringCreateWithJSString(hostName)));
1434     
1435     keys.append(adoptWK(WKStringCreateWithUTF8CString("Value")));
1436     values.append(adoptWK(WKDoubleCreate(seconds)));
1437     
1438     Vector<WKStringRef> rawKeys(keys.size());
1439     Vector<WKTypeRef> rawValues(values.size());
1440     
1441     for (size_t i = 0; i < keys.size(); ++i) {
1442         rawKeys[i] = keys[i].get();
1443         rawValues[i] = values[i].get();
1444     }
1445     
1446     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetStatisticsLastSeen"));
1447     WKRetainPtr<WKDictionaryRef> messageBody = adoptWK(WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1448     
1449     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1450 }
1451
1452 void TestRunner::statisticsCallDidSetLastSeenCallback()
1453 {
1454     callTestRunnerCallback(SetStatisticsLastSeenCallbackID);
1455 }
1456
1457 void TestRunner::setStatisticsMergeStatistic(JSStringRef hostName, JSStringRef topFrameDomain1, JSStringRef topFrameDomain2, double lastSeen, bool hadUserInteraction, double mostRecentUserInteraction, bool isGrandfathered, bool isPrevalent, bool isVeryPrevalent, unsigned dataRecordsRemoved, JSValueRef completionHandler)
1458 {
1459     cacheTestRunnerCallback(SetStatisticsMergeStatisticCallbackID, completionHandler);
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("TopFrameDomain1")));
1468     values.append(adoptWK(WKStringCreateWithJSString(topFrameDomain1)));
1469     
1470     keys.append(adoptWK(WKStringCreateWithUTF8CString("TopFrameDomain2")));
1471     values.append(adoptWK(WKStringCreateWithJSString(topFrameDomain2)));
1472
1473     keys.append(adoptWK(WKStringCreateWithUTF8CString("LastSeen")));
1474     values.append(adoptWK(WKDoubleCreate(lastSeen)));
1475
1476     keys.append(adoptWK(WKStringCreateWithUTF8CString("HadUserInteraction")));
1477     values.append(adoptWK(WKBooleanCreate(hadUserInteraction)));
1478
1479     keys.append(adoptWK(WKStringCreateWithUTF8CString("MostRecentUserInteraction")));
1480     values.append(adoptWK(WKDoubleCreate(mostRecentUserInteraction)));
1481
1482     keys.append(adoptWK(WKStringCreateWithUTF8CString("IsGrandfathered")));
1483     values.append(adoptWK(WKBooleanCreate(isGrandfathered)));
1484
1485     keys.append(adoptWK(WKStringCreateWithUTF8CString("IsPrevalent")));
1486     values.append(adoptWK(WKBooleanCreate(isPrevalent)));
1487
1488     keys.append(adoptWK(WKStringCreateWithUTF8CString("IsVeryPrevalent")));
1489     values.append(adoptWK(WKBooleanCreate(isVeryPrevalent)));
1490
1491     keys.append(adoptWK(WKStringCreateWithUTF8CString("DataRecordsRemoved")));
1492     values.append(adoptWK(WKUInt64Create(dataRecordsRemoved)));
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     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetStatisticsMergeStatistic"));
1502     WKRetainPtr<WKDictionaryRef> messageBody = adoptWK(WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1503     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1504 }
1505
1506 void TestRunner::statisticsCallDidSetMergeStatisticCallback()
1507 {
1508     callTestRunnerCallback(SetStatisticsMergeStatisticCallbackID);
1509 }
1510
1511 void TestRunner::setStatisticsPrevalentResource(JSStringRef hostName, bool value, JSValueRef completionHandler)
1512 {
1513     cacheTestRunnerCallback(SetStatisticsPrevalentResourceCallbackID, completionHandler);
1514
1515     Vector<WKRetainPtr<WKStringRef>> keys;
1516     Vector<WKRetainPtr<WKTypeRef>> values;
1517
1518     keys.append(adoptWK(WKStringCreateWithUTF8CString("HostName")));
1519     values.append(adoptWK(WKStringCreateWithJSString(hostName)));
1520     
1521     keys.append(adoptWK(WKStringCreateWithUTF8CString("Value")));
1522     values.append(adoptWK(WKBooleanCreate(value)));
1523     
1524     Vector<WKStringRef> rawKeys;
1525     Vector<WKTypeRef> rawValues;
1526     rawKeys.resize(keys.size());
1527     rawValues.resize(values.size());
1528     
1529     for (size_t i = 0; i < keys.size(); ++i) {
1530         rawKeys[i] = keys[i].get();
1531         rawValues[i] = values[i].get();
1532     }
1533     
1534     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetStatisticsPrevalentResource"));
1535     WKRetainPtr<WKDictionaryRef> messageBody = adoptWK(WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1536
1537     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1538 }
1539
1540 void TestRunner::statisticsCallDidSetPrevalentResourceCallback()
1541 {
1542     callTestRunnerCallback(SetStatisticsPrevalentResourceCallbackID);
1543 }
1544
1545 void TestRunner::setStatisticsVeryPrevalentResource(JSStringRef hostName, bool value, JSValueRef completionHandler)
1546 {
1547     cacheTestRunnerCallback(SetStatisticsVeryPrevalentResourceCallbackID, completionHandler);
1548
1549     Vector<WKRetainPtr<WKStringRef>> keys;
1550     Vector<WKRetainPtr<WKTypeRef>> values;
1551     
1552     keys.append(adoptWK(WKStringCreateWithUTF8CString("HostName")));
1553     values.append(adoptWK(WKStringCreateWithJSString(hostName)));
1554     
1555     keys.append(adoptWK(WKStringCreateWithUTF8CString("Value")));
1556     values.append(adoptWK(WKBooleanCreate(value)));
1557     
1558     Vector<WKStringRef> rawKeys;
1559     Vector<WKTypeRef> rawValues;
1560     rawKeys.resize(keys.size());
1561     rawValues.resize(values.size());
1562     
1563     for (size_t i = 0; i < keys.size(); ++i) {
1564         rawKeys[i] = keys[i].get();
1565         rawValues[i] = values[i].get();
1566     }
1567     
1568     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetStatisticsVeryPrevalentResource"));
1569     WKRetainPtr<WKDictionaryRef> messageBody = adoptWK(WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1570     
1571     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1572 }
1573
1574 void TestRunner::statisticsCallDidSetVeryPrevalentResourceCallback()
1575 {
1576     callTestRunnerCallback(SetStatisticsVeryPrevalentResourceCallbackID);
1577 }
1578     
1579 void TestRunner::dumpResourceLoadStatistics()
1580 {
1581     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("dumpResourceLoadStatistics"));
1582     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), nullptr, nullptr);
1583 }
1584
1585 bool TestRunner::isStatisticsPrevalentResource(JSStringRef hostName)
1586 {
1587     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("IsStatisticsPrevalentResource"));
1588     WKRetainPtr<WKStringRef> messageBody = adoptWK(WKStringCreateWithJSString(hostName));
1589     WKTypeRef returnData = nullptr;
1590     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get(), &returnData);
1591     ASSERT(WKGetTypeID(returnData) == WKBooleanGetTypeID());
1592     return WKBooleanGetValue(adoptWK(static_cast<WKBooleanRef>(returnData)).get());
1593 }
1594
1595 bool TestRunner::isStatisticsVeryPrevalentResource(JSStringRef hostName)
1596 {
1597     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("IsStatisticsVeryPrevalentResource"));
1598     WKRetainPtr<WKStringRef> messageBody = adoptWK(WKStringCreateWithJSString(hostName));
1599     WKTypeRef returnData = nullptr;
1600     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get(), &returnData);
1601     ASSERT(WKGetTypeID(returnData) == WKBooleanGetTypeID());
1602     return WKBooleanGetValue(adoptWK(static_cast<WKBooleanRef>(returnData)).get());
1603 }
1604
1605 bool TestRunner::isStatisticsRegisteredAsSubresourceUnder(JSStringRef subresourceHost, JSStringRef topFrameHost)
1606 {
1607     Vector<WKRetainPtr<WKStringRef>> keys;
1608     Vector<WKRetainPtr<WKTypeRef>> values;
1609     
1610     keys.append(adoptWK(WKStringCreateWithUTF8CString("SubresourceHost")));
1611     values.append(adoptWK(WKStringCreateWithJSString(subresourceHost)));
1612     
1613     keys.append(adoptWK(WKStringCreateWithUTF8CString("TopFrameHost")));
1614     values.append(adoptWK(WKStringCreateWithJSString(topFrameHost)));
1615     
1616     Vector<WKStringRef> rawKeys(keys.size());
1617     Vector<WKTypeRef> rawValues(values.size());
1618     
1619     for (size_t i = 0; i < keys.size(); ++i) {
1620         rawKeys[i] = keys[i].get();
1621         rawValues[i] = values[i].get();
1622     }
1623     
1624     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("IsStatisticsRegisteredAsSubresourceUnder"));
1625     WKRetainPtr<WKDictionaryRef> messageBody = adoptWK(WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1626     WKTypeRef returnData = nullptr;
1627     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get(), &returnData);
1628     ASSERT(WKGetTypeID(returnData) == WKBooleanGetTypeID());
1629     return WKBooleanGetValue(adoptWK(static_cast<WKBooleanRef>(returnData)).get());
1630 }
1631
1632 bool TestRunner::isStatisticsRegisteredAsSubFrameUnder(JSStringRef subFrameHost, JSStringRef topFrameHost)
1633 {
1634     Vector<WKRetainPtr<WKStringRef>> keys;
1635     Vector<WKRetainPtr<WKTypeRef>> values;
1636
1637     keys.append(adoptWK(WKStringCreateWithUTF8CString("SubFrameHost")));
1638     values.append(adoptWK(WKStringCreateWithJSString(subFrameHost)));
1639     
1640     keys.append(adoptWK(WKStringCreateWithUTF8CString("TopFrameHost")));
1641     values.append(adoptWK(WKStringCreateWithJSString(topFrameHost)));
1642     
1643     Vector<WKStringRef> rawKeys(keys.size());
1644     Vector<WKTypeRef> rawValues(values.size());
1645
1646     for (size_t i = 0; i < keys.size(); ++i) {
1647         rawKeys[i] = keys[i].get();
1648         rawValues[i] = values[i].get();
1649     }
1650
1651     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("IsStatisticsRegisteredAsSubFrameUnder"));
1652     WKRetainPtr<WKDictionaryRef> messageBody = adoptWK(WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1653     WKTypeRef returnData = nullptr;
1654     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get(), &returnData);
1655     ASSERT(WKGetTypeID(returnData) == WKBooleanGetTypeID());
1656     return WKBooleanGetValue(adoptWK(static_cast<WKBooleanRef>(returnData)).get());
1657 }
1658
1659 bool TestRunner::isStatisticsRegisteredAsRedirectingTo(JSStringRef hostRedirectedFrom, JSStringRef hostRedirectedTo)
1660 {
1661     Vector<WKRetainPtr<WKStringRef>> keys;
1662     Vector<WKRetainPtr<WKTypeRef>> values;
1663     
1664     keys.append(adoptWK(WKStringCreateWithUTF8CString("HostRedirectedFrom")));
1665     values.append(adoptWK(WKStringCreateWithJSString(hostRedirectedFrom)));
1666     
1667     keys.append(adoptWK(WKStringCreateWithUTF8CString("HostRedirectedTo")));
1668     values.append(adoptWK(WKStringCreateWithJSString(hostRedirectedTo)));
1669     
1670     Vector<WKStringRef> rawKeys(keys.size());
1671     Vector<WKTypeRef> rawValues(values.size());
1672
1673     for (size_t i = 0; i < keys.size(); ++i) {
1674         rawKeys[i] = keys[i].get();
1675         rawValues[i] = values[i].get();
1676     }
1677     
1678     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("IsStatisticsRegisteredAsRedirectingTo"));
1679     WKRetainPtr<WKDictionaryRef> messageBody = adoptWK(WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1680     WKTypeRef returnData = nullptr;
1681     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get(), &returnData);
1682     ASSERT(WKGetTypeID(returnData) == WKBooleanGetTypeID());
1683     return WKBooleanGetValue(adoptWK(static_cast<WKBooleanRef>(returnData)).get());
1684 }
1685
1686 void TestRunner::setStatisticsHasHadUserInteraction(JSStringRef hostName, bool value, JSValueRef completionHandler)
1687 {
1688     cacheTestRunnerCallback(SetStatisticsHasHadUserInteractionCallbackID, completionHandler);
1689
1690     Vector<WKRetainPtr<WKStringRef>> keys;
1691     Vector<WKRetainPtr<WKTypeRef>> values;
1692     
1693     keys.append(adoptWK(WKStringCreateWithUTF8CString("HostName")));
1694     values.append(adoptWK(WKStringCreateWithJSString(hostName)));
1695     
1696     keys.append(adoptWK(WKStringCreateWithUTF8CString("Value")));
1697     values.append(adoptWK(WKBooleanCreate(value)));
1698     
1699     Vector<WKStringRef> rawKeys;
1700     Vector<WKTypeRef> rawValues;
1701     rawKeys.resize(keys.size());
1702     rawValues.resize(values.size());
1703     
1704     for (size_t i = 0; i < keys.size(); ++i) {
1705         rawKeys[i] = keys[i].get();
1706         rawValues[i] = values[i].get();
1707     }
1708     
1709     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetStatisticsHasHadUserInteraction"));
1710     WKRetainPtr<WKDictionaryRef> messageBody = adoptWK(WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1711     
1712     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1713 }
1714
1715 void TestRunner::statisticsCallDidSetHasHadUserInteractionCallback()
1716 {
1717     callTestRunnerCallback(SetStatisticsHasHadUserInteractionCallbackID);
1718 }
1719
1720 bool TestRunner::isStatisticsHasHadUserInteraction(JSStringRef hostName)
1721 {
1722     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("IsStatisticsHasHadUserInteraction"));
1723     WKRetainPtr<WKStringRef> messageBody = adoptWK(WKStringCreateWithJSString(hostName));
1724     WKTypeRef returnData = nullptr;
1725     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get(), &returnData);
1726     ASSERT(WKGetTypeID(returnData) == WKBooleanGetTypeID());
1727     return WKBooleanGetValue(adoptWK(static_cast<WKBooleanRef>(returnData)).get());
1728 }
1729
1730 bool TestRunner::isStatisticsOnlyInDatabaseOnce(JSStringRef subHost, JSStringRef topHost)
1731 {
1732     
1733     Vector<WKRetainPtr<WKStringRef>> keys;
1734     Vector<WKRetainPtr<WKTypeRef>> values;
1735
1736     keys.append(adoptWK(WKStringCreateWithUTF8CString("SubHost")));
1737     values.append(adoptWK(WKStringCreateWithJSString(subHost)));
1738     
1739     keys.append(adoptWK(WKStringCreateWithUTF8CString("TopHost")));
1740     values.append(adoptWK(WKStringCreateWithJSString(topHost)));
1741     
1742     Vector<WKStringRef> rawKeys(keys.size());
1743     Vector<WKTypeRef> rawValues(values.size());
1744
1745     for (size_t i = 0; i < keys.size(); ++i) {
1746         rawKeys[i] = keys[i].get();
1747         rawValues[i] = values[i].get();
1748     }
1749
1750     auto messageName = adoptWK(WKStringCreateWithUTF8CString("IsStatisticsOnlyInDatabaseOnce"));
1751     auto messageBody = adoptWK(WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1752     WKTypeRef returnData = nullptr;
1753     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get(), &returnData);
1754     ASSERT(WKGetTypeID(returnData) == WKBooleanGetTypeID());
1755     return WKBooleanGetValue(adoptWK(static_cast<WKBooleanRef>(returnData)).get());
1756 }
1757
1758 void TestRunner::setStatisticsGrandfathered(JSStringRef hostName, bool value)
1759 {
1760     Vector<WKRetainPtr<WKStringRef>> keys;
1761     Vector<WKRetainPtr<WKTypeRef>> values;
1762     
1763     keys.append(adoptWK(WKStringCreateWithUTF8CString("HostName")));
1764     values.append(adoptWK(WKStringCreateWithJSString(hostName)));
1765     
1766     keys.append(adoptWK(WKStringCreateWithUTF8CString("Value")));
1767     values.append(adoptWK(WKBooleanCreate(value)));
1768     
1769     Vector<WKStringRef> rawKeys;
1770     Vector<WKTypeRef> rawValues;
1771     rawKeys.resize(keys.size());
1772     rawValues.resize(values.size());
1773     
1774     for (size_t i = 0; i < keys.size(); ++i) {
1775         rawKeys[i] = keys[i].get();
1776         rawValues[i] = values[i].get();
1777     }
1778     
1779     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetStatisticsGrandfathered"));
1780     WKRetainPtr<WKDictionaryRef> messageBody = adoptWK(WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1781     
1782     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1783 }
1784
1785 void TestRunner::setUseITPDatabase(bool value)
1786 {
1787     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetUseITPDatabase"));
1788     WKRetainPtr<WKBooleanRef> messageBody = adoptWK(WKBooleanCreate(value));
1789     
1790     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1791 }
1792
1793 bool TestRunner::isStatisticsGrandfathered(JSStringRef hostName)
1794 {
1795     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("IsStatisticsGrandfathered"));
1796     WKRetainPtr<WKStringRef> messageBody = adoptWK(WKStringCreateWithJSString(hostName));
1797     WKTypeRef returnData = nullptr;
1798     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get(), &returnData);
1799     ASSERT(WKGetTypeID(returnData) == WKBooleanGetTypeID());
1800     return WKBooleanGetValue(adoptWK(static_cast<WKBooleanRef>(returnData)).get());
1801 }
1802
1803 void TestRunner::setStatisticsSubframeUnderTopFrameOrigin(JSStringRef hostName, JSStringRef topFrameHostName)
1804 {
1805     Vector<WKRetainPtr<WKStringRef>> keys;
1806     Vector<WKRetainPtr<WKTypeRef>> values;
1807     
1808     keys.append(adoptWK(WKStringCreateWithUTF8CString("HostName")));
1809     values.append(adoptWK(WKStringCreateWithJSString(hostName)));
1810     
1811     keys.append(adoptWK(WKStringCreateWithUTF8CString("TopFrameHostName")));
1812     values.append(adoptWK(WKStringCreateWithJSString(topFrameHostName)));
1813     
1814     Vector<WKStringRef> rawKeys(keys.size());
1815     Vector<WKTypeRef> rawValues(values.size());
1816     
1817     for (size_t i = 0; i < keys.size(); ++i) {
1818         rawKeys[i] = keys[i].get();
1819         rawValues[i] = values[i].get();
1820     }
1821     
1822     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetStatisticsSubframeUnderTopFrameOrigin"));
1823     WKRetainPtr<WKDictionaryRef> messageBody = adoptWK(WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1824     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1825 }
1826
1827 void TestRunner::setStatisticsSubresourceUnderTopFrameOrigin(JSStringRef hostName, JSStringRef topFrameHostName)
1828 {
1829     Vector<WKRetainPtr<WKStringRef>> keys;
1830     Vector<WKRetainPtr<WKTypeRef>> values;
1831     
1832     keys.append(adoptWK(WKStringCreateWithUTF8CString("HostName")));
1833     values.append(adoptWK(WKStringCreateWithJSString(hostName)));
1834     
1835     keys.append(adoptWK(WKStringCreateWithUTF8CString("TopFrameHostName")));
1836     values.append(adoptWK(WKStringCreateWithJSString(topFrameHostName)));
1837     
1838     Vector<WKStringRef> rawKeys(keys.size());
1839     Vector<WKTypeRef> rawValues(values.size());
1840     
1841     for (size_t i = 0; i < keys.size(); ++i) {
1842         rawKeys[i] = keys[i].get();
1843         rawValues[i] = values[i].get();
1844     }
1845     
1846     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetStatisticsSubresourceUnderTopFrameOrigin"));
1847     WKRetainPtr<WKDictionaryRef> messageBody = adoptWK(WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1848     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1849 }
1850
1851 void TestRunner::setStatisticsSubresourceUniqueRedirectTo(JSStringRef hostName, JSStringRef hostNameRedirectedTo)
1852 {
1853     Vector<WKRetainPtr<WKStringRef>> keys;
1854     Vector<WKRetainPtr<WKTypeRef>> values;
1855     
1856     keys.append(adoptWK(WKStringCreateWithUTF8CString("HostName")));
1857     values.append(adoptWK(WKStringCreateWithJSString(hostName)));
1858     
1859     keys.append(adoptWK(WKStringCreateWithUTF8CString("HostNameRedirectedTo")));
1860     values.append(adoptWK(WKStringCreateWithJSString(hostNameRedirectedTo)));
1861     
1862     Vector<WKStringRef> rawKeys(keys.size());
1863     Vector<WKTypeRef> rawValues(values.size());
1864     
1865     for (size_t i = 0; i < keys.size(); ++i) {
1866         rawKeys[i] = keys[i].get();
1867         rawValues[i] = values[i].get();
1868     }
1869     
1870     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetStatisticsSubresourceUniqueRedirectTo"));
1871     WKRetainPtr<WKDictionaryRef> messageBody = adoptWK(WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1872     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1873 }
1874
1875
1876 void TestRunner::setStatisticsSubresourceUniqueRedirectFrom(JSStringRef hostName, JSStringRef hostNameRedirectedFrom)
1877 {
1878     Vector<WKRetainPtr<WKStringRef>> keys;
1879     Vector<WKRetainPtr<WKTypeRef>> values;
1880     
1881     keys.append(adoptWK(WKStringCreateWithUTF8CString("HostName")));
1882     values.append(adoptWK(WKStringCreateWithJSString(hostName)));
1883     
1884     keys.append(adoptWK(WKStringCreateWithUTF8CString("HostNameRedirectedFrom")));
1885     values.append(adoptWK(WKStringCreateWithJSString(hostNameRedirectedFrom)));
1886     
1887     Vector<WKStringRef> rawKeys(keys.size());
1888     Vector<WKTypeRef> rawValues(values.size());
1889     
1890     for (size_t i = 0; i < keys.size(); ++i) {
1891         rawKeys[i] = keys[i].get();
1892         rawValues[i] = values[i].get();
1893     }
1894     
1895     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetStatisticsSubresourceUniqueRedirectFrom"));
1896     WKRetainPtr<WKDictionaryRef> messageBody = adoptWK(WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1897     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1898 }
1899
1900 void TestRunner::setStatisticsTopFrameUniqueRedirectTo(JSStringRef hostName, JSStringRef hostNameRedirectedTo)
1901 {
1902     Vector<WKRetainPtr<WKStringRef>> keys;
1903     Vector<WKRetainPtr<WKTypeRef>> values;
1904     
1905     keys.append(adoptWK(WKStringCreateWithUTF8CString("HostName")));
1906     values.append(adoptWK(WKStringCreateWithJSString(hostName)));
1907     
1908     keys.append(adoptWK(WKStringCreateWithUTF8CString("HostNameRedirectedTo")));
1909     values.append(adoptWK(WKStringCreateWithJSString(hostNameRedirectedTo)));
1910     
1911     Vector<WKStringRef> rawKeys(keys.size());
1912     Vector<WKTypeRef> rawValues(values.size());
1913     
1914     for (size_t i = 0; i < keys.size(); ++i) {
1915         rawKeys[i] = keys[i].get();
1916         rawValues[i] = values[i].get();
1917     }
1918     
1919     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetStatisticsTopFrameUniqueRedirectTo"));
1920     WKRetainPtr<WKDictionaryRef> messageBody = adoptWK(WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1921     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1922 }
1923
1924 void TestRunner::setStatisticsTopFrameUniqueRedirectFrom(JSStringRef hostName, JSStringRef hostNameRedirectedFrom)
1925 {
1926     Vector<WKRetainPtr<WKStringRef>> keys;
1927     Vector<WKRetainPtr<WKTypeRef>> values;
1928     
1929     keys.append(adoptWK(WKStringCreateWithUTF8CString("HostName")));
1930     values.append(adoptWK(WKStringCreateWithJSString(hostName)));
1931     
1932     keys.append(adoptWK(WKStringCreateWithUTF8CString("HostNameRedirectedFrom")));
1933     values.append(adoptWK(WKStringCreateWithJSString(hostNameRedirectedFrom)));
1934     
1935     Vector<WKStringRef> rawKeys(keys.size());
1936     Vector<WKTypeRef> rawValues(values.size());
1937     
1938     for (size_t i = 0; i < keys.size(); ++i) {
1939         rawKeys[i] = keys[i].get();
1940         rawValues[i] = values[i].get();
1941     }
1942     
1943     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetStatisticsTopFrameUniqueRedirectFrom"));
1944     WKRetainPtr<WKDictionaryRef> messageBody = adoptWK(WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1945     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1946 }
1947
1948 void TestRunner::setStatisticsCrossSiteLoadWithLinkDecoration(JSStringRef fromHost, JSStringRef toHost)
1949 {
1950     Vector<WKRetainPtr<WKStringRef>> keys;
1951     Vector<WKRetainPtr<WKTypeRef>> values;
1952     
1953     keys.append(adoptWK(WKStringCreateWithUTF8CString("FromHost")));
1954     values.append(adoptWK(WKStringCreateWithJSString(fromHost)));
1955     
1956     keys.append(adoptWK(WKStringCreateWithUTF8CString("ToHost")));
1957     values.append(adoptWK(WKStringCreateWithJSString(toHost)));
1958     
1959     Vector<WKStringRef> rawKeys(keys.size());
1960     Vector<WKTypeRef> rawValues(values.size());
1961     
1962     for (size_t i = 0; i < keys.size(); ++i) {
1963         rawKeys[i] = keys[i].get();
1964         rawValues[i] = values[i].get();
1965     }
1966     
1967     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetStatisticsCrossSiteLoadWithLinkDecoration"));
1968     WKRetainPtr<WKDictionaryRef> messageBody = adoptWK(WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1969     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1970 }
1971
1972 void TestRunner::setStatisticsTimeToLiveUserInteraction(double seconds)
1973 {
1974     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetStatisticsTimeToLiveUserInteraction"));
1975     WKRetainPtr<WKDoubleRef> messageBody = adoptWK(WKDoubleCreate(seconds));
1976     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1977 }
1978
1979 void TestRunner::installStatisticsDidModifyDataRecordsCallback(JSValueRef callback)
1980 {
1981     cacheTestRunnerCallback(StatisticsDidModifyDataRecordsCallbackID, callback);
1982 }
1983
1984 void TestRunner::statisticsDidModifyDataRecordsCallback()
1985 {
1986     callTestRunnerCallback(StatisticsDidModifyDataRecordsCallbackID);
1987 }
1988
1989 void TestRunner::installStatisticsDidScanDataRecordsCallback(JSValueRef callback)
1990 {
1991     cacheTestRunnerCallback(StatisticsDidScanDataRecordsCallbackID, callback);
1992
1993     bool notifyPagesWhenDataRecordsWereScanned = !!callback;
1994
1995     // Setting a callback implies we expect to receive callbacks. So register for them.
1996     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("StatisticsNotifyPagesWhenDataRecordsWereScanned"));
1997     WKRetainPtr<WKBooleanRef> messageBody = adoptWK(WKBooleanCreate(notifyPagesWhenDataRecordsWereScanned));
1998     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1999 }
2000
2001 void TestRunner::statisticsDidScanDataRecordsCallback()
2002 {
2003     callTestRunnerCallback(StatisticsDidScanDataRecordsCallbackID);
2004 }
2005
2006 void TestRunner::installStatisticsDidRunTelemetryCallback(JSValueRef callback)
2007 {
2008     cacheTestRunnerCallback(StatisticsDidRunTelemetryCallbackID, callback);
2009 }
2010     
2011 void TestRunner::statisticsDidRunTelemetryCallback(unsigned totalPrevalentResources, unsigned totalPrevalentResourcesWithUserInteraction, unsigned top3SubframeUnderTopFrameOrigins)
2012 {
2013     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
2014     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
2015     
2016     String string = makeString("{ \"totalPrevalentResources\" : ", totalPrevalentResources, ", \"totalPrevalentResourcesWithUserInteraction\" : ", totalPrevalentResourcesWithUserInteraction, ", \"top3SubframeUnderTopFrameOrigins\" : ", top3SubframeUnderTopFrameOrigins, " }");
2017     
2018     JSValueRef result = JSValueMakeFromJSONString(context, adopt(JSStringCreateWithUTF8CString(string.utf8().data())).get());
2019
2020     callTestRunnerCallback(StatisticsDidRunTelemetryCallbackID, 1, &result);
2021 }
2022
2023 bool TestRunner::statisticsNotifyObserver()
2024 {
2025     return InjectedBundle::singleton().statisticsNotifyObserver();
2026 }
2027
2028 void TestRunner::statisticsProcessStatisticsAndDataRecords()
2029 {
2030     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("StatisticsProcessStatisticsAndDataRecords"));
2031     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), nullptr, nullptr);
2032 }
2033
2034 void TestRunner::statisticsUpdateCookieBlocking(JSValueRef completionHandler)
2035 {
2036     cacheTestRunnerCallback(StatisticsDidSetBlockCookiesForHostCallbackID, completionHandler);
2037
2038     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("StatisticsUpdateCookieBlocking"));
2039     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), nullptr, nullptr);
2040 }
2041
2042 void TestRunner::statisticsCallDidSetBlockCookiesForHostCallback()
2043 {
2044     callTestRunnerCallback(StatisticsDidSetBlockCookiesForHostCallbackID);
2045 }
2046
2047 void TestRunner::statisticsSubmitTelemetry()
2048 {
2049     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("StatisticsSubmitTelemetry"));
2050     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), nullptr, nullptr);
2051 }
2052
2053 void TestRunner::setStatisticsNotifyPagesWhenDataRecordsWereScanned(bool value)
2054 {
2055     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("StatisticsNotifyPagesWhenDataRecordsWereScanned"));
2056     WKRetainPtr<WKBooleanRef> messageBody = adoptWK(WKBooleanCreate(value));
2057     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
2058 }
2059
2060 void TestRunner::setStatisticsIsRunningTest(bool value)
2061 {
2062     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("StatisticsSetIsRunningTest"));
2063     WKRetainPtr<WKBooleanRef> messageBody = adoptWK(WKBooleanCreate(value));
2064     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
2065 }
2066
2067 void TestRunner::setStatisticsShouldClassifyResourcesBeforeDataRecordsRemoval(bool value)
2068 {
2069     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("StatisticsShouldClassifyResourcesBeforeDataRecordsRemoval"));
2070     WKRetainPtr<WKBooleanRef> messageBody = adoptWK(WKBooleanCreate(value));
2071     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
2072 }
2073
2074 void TestRunner::setStatisticsNotifyPagesWhenTelemetryWasCaptured(bool value)
2075 {
2076     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("StatisticsNotifyPagesWhenTelemetryWasCaptured"));
2077     WKRetainPtr<WKBooleanRef> messageBody = adoptWK(WKBooleanCreate(value));
2078     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
2079 }
2080
2081 void TestRunner::setStatisticsMinimumTimeBetweenDataRecordsRemoval(double seconds)
2082 {
2083     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetStatisticsMinimumTimeBetweenDataRecordsRemoval"));
2084     WKRetainPtr<WKDoubleRef> messageBody = adoptWK(WKDoubleCreate(seconds));
2085     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
2086 }
2087
2088 void TestRunner::setStatisticsGrandfatheringTime(double seconds)
2089 {
2090     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetStatisticsGrandfatheringTime"));
2091     WKRetainPtr<WKDoubleRef> messageBody = adoptWK(WKDoubleCreate(seconds));
2092     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
2093 }
2094
2095 void TestRunner::setStatisticsMaxStatisticsEntries(unsigned entries)
2096 {
2097     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetMaxStatisticsEntries"));
2098     WKRetainPtr<WKTypeRef> messageBody = adoptWK(WKUInt64Create(entries));
2099     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
2100 }
2101     
2102 void TestRunner::setStatisticsPruneEntriesDownTo(unsigned entries)
2103 {
2104     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetPruneEntriesDownTo"));
2105     WKRetainPtr<WKTypeRef> messageBody = adoptWK(WKUInt64Create(entries));
2106     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
2107 }
2108     
2109 void TestRunner::statisticsClearInMemoryAndPersistentStore(JSValueRef callback)
2110 {
2111     cacheTestRunnerCallback(StatisticsDidClearThroughWebsiteDataRemovalCallbackID, callback);
2112
2113     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("StatisticsClearInMemoryAndPersistentStore"));
2114     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), nullptr, nullptr);
2115 }
2116
2117 void TestRunner::statisticsClearInMemoryAndPersistentStoreModifiedSinceHours(unsigned hours, JSValueRef callback)
2118 {
2119     cacheTestRunnerCallback(StatisticsDidClearThroughWebsiteDataRemovalCallbackID, callback);
2120
2121     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("StatisticsClearInMemoryAndPersistentStoreModifiedSinceHours"));
2122     WKRetainPtr<WKTypeRef> messageBody = adoptWK(WKUInt64Create(hours));
2123     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
2124 }
2125
2126 void TestRunner::statisticsClearThroughWebsiteDataRemoval(JSValueRef callback)
2127 {
2128     cacheTestRunnerCallback(StatisticsDidClearThroughWebsiteDataRemovalCallbackID, callback);
2129     
2130     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("StatisticsClearThroughWebsiteDataRemoval"));
2131     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), nullptr, nullptr);
2132 }
2133
2134 void TestRunner::statisticsDeleteCookiesForHost(JSStringRef hostName, bool includeHttpOnlyCookies)
2135 {
2136     Vector<WKRetainPtr<WKStringRef>> keys;
2137     Vector<WKRetainPtr<WKTypeRef>> values;
2138
2139     keys.append(adoptWK(WKStringCreateWithUTF8CString("HostName")));
2140     values.append(adoptWK(WKStringCreateWithJSString(hostName)));
2141
2142     keys.append(adoptWK(WKStringCreateWithUTF8CString("IncludeHttpOnlyCookies")));
2143     values.append(adoptWK(WKBooleanCreate(includeHttpOnlyCookies)));
2144
2145     Vector<WKStringRef> rawKeys;
2146     Vector<WKTypeRef> rawValues;
2147     rawKeys.resize(keys.size());
2148     rawValues.resize(values.size());
2149
2150     for (size_t i = 0; i < keys.size(); ++i) {
2151         rawKeys[i] = keys[i].get();
2152         rawValues[i] = values[i].get();
2153     }
2154
2155     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("StatisticsDeleteCookiesForHost"));
2156     WKRetainPtr<WKDictionaryRef> messageBody = adoptWK(WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
2157     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
2158 }
2159
2160 bool TestRunner::isStatisticsHasLocalStorage(JSStringRef hostName)
2161 {
2162     auto messageName = adoptWK(WKStringCreateWithUTF8CString("IsStatisticsHasLocalStorage"));
2163     auto messageBody = adoptWK(WKStringCreateWithJSString(hostName));
2164     WKTypeRef returnData = nullptr;
2165     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get(), &returnData);
2166     ASSERT(WKGetTypeID(returnData) == WKBooleanGetTypeID());
2167     return WKBooleanGetValue(adoptWK(static_cast<WKBooleanRef>(returnData)).get());
2168 }
2169
2170 void TestRunner::setStatisticsCacheMaxAgeCap(double seconds)
2171 {
2172     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetStatisticsCacheMaxAgeCap"));
2173     WKRetainPtr<WKDoubleRef> messageBody = adoptWK(WKDoubleCreate(seconds));
2174     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
2175 }
2176
2177 bool TestRunner::hasStatisticsIsolatedSession(JSStringRef hostName)
2178 {
2179     auto messageName = adoptWK(WKStringCreateWithUTF8CString("HasStatisticsIsolatedSession"));
2180     auto messageBody = adoptWK(WKStringCreateWithJSString(hostName));
2181     WKTypeRef returnData = nullptr;
2182     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get(), &returnData);
2183     ASSERT(WKGetTypeID(returnData) == WKBooleanGetTypeID());
2184     return WKBooleanGetValue(adoptWK(static_cast<WKBooleanRef>(returnData)).get());
2185 }
2186
2187 void TestRunner::setStatisticsShouldDowngradeReferrer(bool value, JSValueRef completionHandler)
2188 {
2189     if (m_hasSetDowngradeReferrerCallback)
2190         return;
2191     
2192     cacheTestRunnerCallback(StatisticsDidSetShouldDowngradeReferrerCallbackID, completionHandler);
2193     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetStatisticsShouldDowngradeReferrer"));
2194     WKRetainPtr<WKBooleanRef> messageBody = adoptWK(WKBooleanCreate(value));
2195     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
2196     m_hasSetDowngradeReferrerCallback = true;
2197 }
2198
2199 void TestRunner::statisticsCallDidSetShouldDowngradeReferrerCallback()
2200 {
2201     callTestRunnerCallback(StatisticsDidSetShouldDowngradeReferrerCallbackID);
2202 }
2203
2204 void TestRunner::statisticsCallClearThroughWebsiteDataRemovalCallback()
2205 {
2206     callTestRunnerCallback(StatisticsDidClearThroughWebsiteDataRemovalCallbackID);
2207 }
2208
2209 void TestRunner::statisticsResetToConsistentState(JSValueRef completionHandler)
2210 {
2211     cacheTestRunnerCallback(StatisticsDidResetToConsistentStateCallbackID, completionHandler);
2212     
2213     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("StatisticsResetToConsistentState"));
2214     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), nullptr, nullptr);
2215 }
2216
2217 void TestRunner::statisticsCallDidResetToConsistentStateCallback()
2218 {
2219     callTestRunnerCallback(StatisticsDidResetToConsistentStateCallbackID);
2220 }
2221
2222 void TestRunner::installTextDidChangeInTextFieldCallback(JSValueRef callback)
2223 {
2224     cacheTestRunnerCallback(TextDidChangeInTextFieldCallbackID, callback);
2225 }
2226
2227 void TestRunner::textDidChangeInTextFieldCallback()
2228 {
2229     callTestRunnerCallback(TextDidChangeInTextFieldCallbackID);
2230 }
2231
2232 void TestRunner::installTextFieldDidBeginEditingCallback(JSValueRef callback)
2233 {
2234     cacheTestRunnerCallback(TextFieldDidBeginEditingCallbackID, callback);
2235 }
2236
2237 void TestRunner::textFieldDidBeginEditingCallback()
2238 {
2239     callTestRunnerCallback(TextFieldDidBeginEditingCallbackID);
2240 }
2241
2242 void TestRunner::installTextFieldDidEndEditingCallback(JSValueRef callback)
2243 {
2244     cacheTestRunnerCallback(TextFieldDidEndEditingCallbackID, callback);
2245 }
2246
2247 void TestRunner::textFieldDidEndEditingCallback()
2248 {
2249     callTestRunnerCallback(TextFieldDidEndEditingCallbackID);
2250 }
2251
2252 void TestRunner::setStorageAccessAPIEnabled(bool enabled)
2253 {
2254     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetStorageAccessAPIEnabled"));
2255     
2256     WKRetainPtr<WKBooleanRef> messageBody = adoptWK(WKBooleanCreate(enabled));
2257     
2258     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
2259 }
2260
2261 void TestRunner::getAllStorageAccessEntries(JSValueRef callback)
2262 {
2263     cacheTestRunnerCallback(AllStorageAccessEntriesCallbackID, callback);
2264     
2265     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("GetAllStorageAccessEntries"));
2266     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), nullptr, nullptr);
2267 }
2268
2269 void TestRunner::callDidReceiveAllStorageAccessEntriesCallback(Vector<String>& domains)
2270 {
2271     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
2272     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
2273     
2274     StringBuilder stringBuilder;
2275     stringBuilder.appendLiteral("[");
2276     bool firstDomain = true;
2277     for (auto& domain : domains) {
2278         if (firstDomain)
2279             firstDomain = false;
2280         else
2281             stringBuilder.appendLiteral(", ");
2282         stringBuilder.appendLiteral("\"");
2283         stringBuilder.append(domain);
2284         stringBuilder.appendLiteral("\"");
2285     }
2286     stringBuilder.appendLiteral("]");
2287     
2288     JSValueRef result = JSValueMakeFromJSONString(context, adopt(JSStringCreateWithUTF8CString(stringBuilder.toString().utf8().data())).get());
2289
2290     callTestRunnerCallback(AllStorageAccessEntriesCallbackID, 1, &result);
2291 }
2292
2293 void TestRunner::addMockMediaDevice(JSStringRef persistentId, JSStringRef label, const char* type)
2294 {
2295     Vector<WKRetainPtr<WKStringRef>> keys;
2296     Vector<WKRetainPtr<WKTypeRef>> values;
2297
2298     keys.append(adoptWK(WKStringCreateWithUTF8CString("PersistentID")));
2299     values.append(toWK(persistentId));
2300
2301     keys.append(adoptWK(WKStringCreateWithUTF8CString("Label")));
2302     values.append(toWK(label));
2303
2304     keys.append(adoptWK(WKStringCreateWithUTF8CString("Type")));
2305     values.append(adoptWK(WKStringCreateWithUTF8CString(type)));
2306
2307     Vector<WKStringRef> rawKeys;
2308     Vector<WKTypeRef> rawValues;
2309     rawKeys.resize(keys.size());
2310     rawValues.resize(values.size());
2311
2312     for (size_t i = 0; i < keys.size(); ++i) {
2313         rawKeys[i] = keys[i].get();
2314         rawValues[i] = values[i].get();
2315     }
2316
2317     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("AddMockMediaDevice"));
2318     WKRetainPtr<WKDictionaryRef> messageBody = adoptWK(WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
2319
2320     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
2321 }
2322
2323 void TestRunner::addMockCameraDevice(JSStringRef persistentId, JSStringRef label)
2324 {
2325     addMockMediaDevice(persistentId, label, "camera");
2326 }
2327
2328 void TestRunner::addMockMicrophoneDevice(JSStringRef persistentId, JSStringRef label)
2329 {
2330     addMockMediaDevice(persistentId, label, "microphone");
2331 }
2332
2333 void TestRunner::addMockScreenDevice(JSStringRef persistentId, JSStringRef label)
2334 {
2335     addMockMediaDevice(persistentId, label, "screen");
2336 }
2337
2338 void TestRunner::clearMockMediaDevices()
2339 {
2340     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("ClearMockMediaDevices"));
2341     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), nullptr, nullptr);
2342 }
2343
2344 void TestRunner::removeMockMediaDevice(JSStringRef persistentId)
2345 {
2346     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("RemoveMockMediaDevice"));
2347     WKRetainPtr<WKTypeRef> messageBody(toWK(persistentId));
2348
2349     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
2350 }
2351
2352 void TestRunner::resetMockMediaDevices()
2353 {
2354     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("ResetMockMediaDevices"));
2355     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), nullptr, nullptr);
2356 }
2357
2358 #if PLATFORM(MAC)
2359 void TestRunner::connectMockGamepad(unsigned index)
2360 {
2361     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("ConnectMockGamepad"));
2362     WKRetainPtr<WKTypeRef> messageBody = adoptWK(WKUInt64Create(index));
2363
2364     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
2365 }
2366
2367 void TestRunner::disconnectMockGamepad(unsigned index)
2368 {
2369     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("DisconnectMockGamepad"));
2370     WKRetainPtr<WKTypeRef> messageBody = adoptWK(WKUInt64Create(index));
2371
2372     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
2373 }
2374
2375 void TestRunner::setMockGamepadDetails(unsigned index, JSStringRef gamepadID, unsigned axisCount, unsigned buttonCount)
2376 {
2377     Vector<WKRetainPtr<WKStringRef>> keys;
2378     Vector<WKRetainPtr<WKTypeRef>> values;
2379
2380     keys.append(adoptWK(WKStringCreateWithUTF8CString("GamepadID")));
2381     values.append(toWK(gamepadID));
2382
2383     keys.append(adoptWK(WKStringCreateWithUTF8CString("GamepadIndex")));
2384     values.append(adoptWK(WKUInt64Create(index)));
2385
2386     keys.append(adoptWK(WKStringCreateWithUTF8CString("AxisCount")));
2387     values.append(adoptWK(WKUInt64Create(axisCount)));
2388
2389     keys.append(adoptWK(WKStringCreateWithUTF8CString("ButtonCount")));
2390     values.append(adoptWK(WKUInt64Create(buttonCount)));
2391
2392     Vector<WKStringRef> rawKeys;
2393     Vector<WKTypeRef> rawValues;
2394     rawKeys.resize(keys.size());
2395     rawValues.resize(values.size());
2396
2397     for (size_t i = 0; i < keys.size(); ++i) {
2398         rawKeys[i] = keys[i].get();
2399         rawValues[i] = values[i].get();
2400     }
2401
2402     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetMockGamepadDetails"));
2403     WKRetainPtr<WKDictionaryRef> messageBody = adoptWK(WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
2404
2405     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
2406 }
2407
2408 void TestRunner::setMockGamepadAxisValue(unsigned index, unsigned axisIndex, double value)
2409 {
2410     Vector<WKRetainPtr<WKStringRef>> keys;
2411     Vector<WKRetainPtr<WKTypeRef>> values;
2412
2413     keys.append(adoptWK(WKStringCreateWithUTF8CString("GamepadIndex")));
2414     values.append(adoptWK(WKUInt64Create(index)));
2415
2416     keys.append(adoptWK(WKStringCreateWithUTF8CString("AxisIndex")));
2417     values.append(adoptWK(WKUInt64Create(axisIndex)));
2418
2419     keys.append(adoptWK(WKStringCreateWithUTF8CString("Value")));
2420     values.append(adoptWK(WKDoubleCreate(value)));
2421
2422     Vector<WKStringRef> rawKeys;
2423     Vector<WKTypeRef> rawValues;
2424     rawKeys.resize(keys.size());
2425     rawValues.resize(values.size());
2426
2427     for (size_t i = 0; i < keys.size(); ++i) {
2428         rawKeys[i] = keys[i].get();
2429         rawValues[i] = values[i].get();
2430     }
2431
2432     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetMockGamepadAxisValue"));
2433     WKRetainPtr<WKDictionaryRef> messageBody = adoptWK(WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
2434
2435     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
2436 }
2437
2438 void TestRunner::setMockGamepadButtonValue(unsigned index, unsigned buttonIndex, double value)
2439 {
2440     Vector<WKRetainPtr<WKStringRef>> keys;
2441     Vector<WKRetainPtr<WKTypeRef>> values;
2442
2443     keys.append(adoptWK(WKStringCreateWithUTF8CString("GamepadIndex")));
2444     values.append(adoptWK(WKUInt64Create(index)));
2445
2446     keys.append(adoptWK(WKStringCreateWithUTF8CString("ButtonIndex")));
2447     values.append(adoptWK(WKUInt64Create(buttonIndex)));
2448
2449     keys.append(adoptWK(WKStringCreateWithUTF8CString("Value")));
2450     values.append(adoptWK(WKDoubleCreate(value)));
2451
2452     Vector<WKStringRef> rawKeys;
2453     Vector<WKTypeRef> rawValues;
2454     rawKeys.resize(keys.size());
2455     rawValues.resize(values.size());
2456
2457     for (size_t i = 0; i < keys.size(); ++i) {
2458         rawKeys[i] = keys[i].get();
2459         rawValues[i] = values[i].get();
2460     }
2461
2462     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetMockGamepadButtonValue"));
2463     WKRetainPtr<WKDictionaryRef> messageBody = adoptWK(WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
2464
2465     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
2466 }
2467 #else
2468 void TestRunner::connectMockGamepad(unsigned)
2469 {
2470 }
2471
2472 void TestRunner::disconnectMockGamepad(unsigned)
2473 {
2474 }
2475
2476 void TestRunner::setMockGamepadDetails(unsigned, JSStringRef, unsigned, unsigned)
2477 {
2478 }
2479
2480 void TestRunner::setMockGamepadAxisValue(unsigned, unsigned, double)
2481 {
2482 }
2483
2484 void TestRunner::setMockGamepadButtonValue(unsigned, unsigned, double)
2485 {
2486 }
2487 #endif // PLATFORM(MAC)
2488
2489 void TestRunner::setOpenPanelFiles(JSValueRef filesValue)
2490 {
2491     WKBundlePageRef page = InjectedBundle::singleton().page()->page();
2492     JSContextRef context = WKBundleFrameGetJavaScriptContext(WKBundlePageGetMainFrame(page));
2493
2494     if (!JSValueIsArray(context, filesValue))
2495         return;
2496
2497     JSObjectRef files = JSValueToObject(context, filesValue, nullptr);
2498     static auto lengthProperty = adopt(JSStringCreateWithUTF8CString("length"));
2499     JSValueRef filesLengthValue = JSObjectGetProperty(context, files, lengthProperty.get(), nullptr);
2500     if (!JSValueIsNumber(context, filesLengthValue))
2501         return;
2502
2503     auto fileURLs = adoptWK(WKMutableArrayCreate());
2504     auto filesLength = static_cast<size_t>(JSValueToNumber(context, filesLengthValue, nullptr));
2505     for (size_t i = 0; i < filesLength; ++i) {
2506         JSValueRef fileValue = JSObjectGetPropertyAtIndex(context, files, i, nullptr);
2507         if (!JSValueIsString(context, fileValue))
2508             continue;
2509
2510         auto file = adopt(JSValueToStringCopy(context, fileValue, nullptr));
2511         size_t fileBufferSize = JSStringGetMaximumUTF8CStringSize(file.get()) + 1;
2512         auto fileBuffer = makeUniqueArray<char>(fileBufferSize);
2513         JSStringGetUTF8CString(file.get(), fileBuffer.get(), fileBufferSize);
2514
2515         WKArrayAppendItem(fileURLs.get(), adoptWK(WKURLCreateWithBaseURL(m_testURL.get(), fileBuffer.get())).get());
2516     }
2517
2518     static auto messageName = adoptWK(WKStringCreateWithUTF8CString("SetOpenPanelFileURLs"));
2519     WKBundlePagePostMessage(page, messageName.get(), fileURLs.get());
2520 }
2521
2522 #if PLATFORM(IOS_FAMILY)
2523 void TestRunner::setOpenPanelFilesMediaIcon(JSValueRef data)
2524 {
2525     WKBundlePageRef page = InjectedBundle::singleton().page()->page();
2526     JSContextRef context = WKBundleFrameGetJavaScriptContext(WKBundlePageGetMainFrame(page));
2527
2528     auto& injectedBundle = InjectedBundle::singleton();
2529     // FIXME (123058): Use a JSC API to get buffer contents once such is exposed.
2530     WKRetainPtr<WKDataRef> iconData = adoptWK(WKBundleCreateWKDataFromUInt8Array(injectedBundle.bundle(), context, data));
2531
2532     static auto messageName = adoptWK(WKStringCreateWithUTF8CString("SetOpenPanelFileURLsMediaIcon"));
2533     WKBundlePagePostMessage(page, messageName.get(), iconData.get());
2534 }
2535 #else
2536 void TestRunner::setOpenPanelFilesMediaIcon(JSValueRef)
2537 {
2538 }
2539 #endif // PLATFORM(IOS_FAMILY)
2540
2541 void TestRunner::removeAllSessionCredentials(JSValueRef callback)
2542 {
2543     cacheTestRunnerCallback(DidRemoveAllSessionCredentialsCallbackID, callback);
2544     
2545     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("RemoveAllSessionCredentials"));
2546     WKRetainPtr<WKBooleanRef> messageBody = adoptWK(WKBooleanCreate(true));
2547     
2548     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
2549 }
2550
2551 void TestRunner::callDidRemoveAllSessionCredentialsCallback()
2552 {
2553     callTestRunnerCallback(DidRemoveAllSessionCredentialsCallbackID);
2554 }
2555
2556 void TestRunner::clearDOMCache(JSStringRef origin)
2557 {
2558     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("ClearDOMCache"));
2559     WKRetainPtr<WKStringRef> messageBody = adoptWK(WKStringCreateWithJSString(origin));
2560     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
2561 }
2562
2563 void TestRunner::clearDOMCaches()
2564 {
2565     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("ClearDOMCaches"));
2566     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), nullptr, nullptr);
2567 }
2568
2569 bool TestRunner::hasDOMCache(JSStringRef origin)
2570 {
2571     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("HasDOMCache"));
2572     WKRetainPtr<WKStringRef> messageBody = adoptWK(WKStringCreateWithJSString(origin));
2573     WKTypeRef returnData = nullptr;
2574     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get(), &returnData);
2575     ASSERT(WKGetTypeID(returnData) == WKBooleanGetTypeID());
2576     return WKBooleanGetValue(adoptWK(static_cast<WKBooleanRef>(returnData)).get());
2577 }
2578
2579 uint64_t TestRunner::domCacheSize(JSStringRef origin)
2580 {
2581     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("DOMCacheSize"));
2582     WKRetainPtr<WKStringRef> messageBody = adoptWK(WKStringCreateWithJSString(origin));
2583     WKTypeRef returnData = nullptr;
2584     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get(), &returnData);
2585     return WKUInt64GetValue(static_cast<WKUInt64Ref>(returnData));
2586 }
2587
2588 void TestRunner::setAllowStorageQuotaIncrease(bool willIncrease)
2589 {
2590     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetAllowStorageQuotaIncrease"));
2591     WKRetainPtr<WKBooleanRef> messageBody = adoptWK(WKBooleanCreate(willIncrease));
2592     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
2593 }
2594
2595 void TestRunner::getApplicationManifestThen(JSValueRef callback)
2596 {
2597     cacheTestRunnerCallback(GetApplicationManifestCallbackID, callback);
2598     
2599     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("GetApplicationManifest"));
2600     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), nullptr, nullptr);
2601 }
2602
2603 void TestRunner::didGetApplicationManifest()
2604 {
2605     callTestRunnerCallback(GetApplicationManifestCallbackID);
2606 }
2607
2608 void TestRunner::performCustomMenuAction()
2609 {
2610     callTestRunnerCallback(CustomMenuActionCallbackID);
2611 }
2612
2613 size_t TestRunner::userScriptInjectedCount() const
2614 {
2615     return InjectedBundle::singleton().userScriptInjectedCount();
2616 }
2617
2618 void TestRunner::injectUserScript(JSStringRef script)
2619 {
2620     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("InjectUserScript"));
2621     WKRetainPtr<WKStringRef> messageBody = adoptWK(WKStringCreateWithJSString(script));
2622     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get(), nullptr);
2623 }
2624
2625 void TestRunner::sendDisplayConfigurationChangedMessageForTesting()
2626 {
2627     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SendDisplayConfigurationChangedMessageForTesting"));
2628     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), nullptr, nullptr);
2629 }
2630
2631 // WebAuthN
2632 void TestRunner::setWebAuthenticationMockConfiguration(JSValueRef configurationValue)
2633 {
2634     auto& injectedBundle = InjectedBundle::singleton();
2635     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(injectedBundle.page()->page());
2636     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
2637     if (!JSValueIsObject(context, configurationValue))
2638         return;
2639     JSObjectRef configuration = JSValueToObject(context, configurationValue, 0);
2640
2641     Vector<WKRetainPtr<WKStringRef>> configurationKeys;
2642     Vector<WKRetainPtr<WKTypeRef>> configurationValues;
2643
2644     JSRetainPtr<JSStringRef> silentFailurePropertyName(Adopt, JSStringCreateWithUTF8CString("silentFailure"));
2645     JSValueRef silentFailureValue = JSObjectGetProperty(context, configuration, silentFailurePropertyName.get(), 0);
2646     if (!JSValueIsUndefined(context, silentFailureValue)) {
2647         if (!JSValueIsBoolean(context, silentFailureValue))
2648             return;
2649         bool silentFailure = JSValueToBoolean(context, silentFailureValue);
2650         configurationKeys.append(adoptWK(WKStringCreateWithUTF8CString("SilentFailure")));
2651         configurationValues.append(adoptWK(WKBooleanCreate(silentFailure)).get());
2652     }
2653
2654     JSRetainPtr<JSStringRef> localPropertyName(Adopt, JSStringCreateWithUTF8CString("local"));
2655     JSValueRef localValue = JSObjectGetProperty(context, configuration, localPropertyName.get(), 0);
2656     if (!JSValueIsUndefined(context, localValue) && !JSValueIsNull(context, localValue)) {
2657         if (!JSValueIsObject(context, localValue))
2658             return;
2659         JSObjectRef local = JSValueToObject(context, localValue, 0);
2660
2661         JSRetainPtr<JSStringRef> acceptAuthenticationPropertyName(Adopt, JSStringCreateWithUTF8CString("acceptAuthentication"));
2662         JSValueRef acceptAuthenticationValue = JSObjectGetProperty(context, local, acceptAuthenticationPropertyName.get(), 0);
2663         if (!JSValueIsBoolean(context, acceptAuthenticationValue))
2664             return;
2665         bool acceptAuthentication = JSValueToBoolean(context, acceptAuthenticationValue);
2666
2667         JSRetainPtr<JSStringRef> acceptAttestationPropertyName(Adopt, JSStringCreateWithUTF8CString("acceptAttestation"));
2668         JSValueRef acceptAttestationValue = JSObjectGetProperty(context, local, acceptAttestationPropertyName.get(), 0);
2669         if (!JSValueIsBoolean(context, acceptAttestationValue))
2670             return;
2671         bool acceptAttestation = JSValueToBoolean(context, acceptAttestationValue);
2672
2673         Vector<WKRetainPtr<WKStringRef>> localKeys;
2674         Vector<WKRetainPtr<WKTypeRef>> localValues;
2675         localKeys.append(adoptWK(WKStringCreateWithUTF8CString("AcceptAuthentication")));
2676         localValues.append(adoptWK(WKBooleanCreate(acceptAuthentication)).get());
2677         localKeys.append(adoptWK(WKStringCreateWithUTF8CString("AcceptAttestation")));
2678         localValues.append(adoptWK(WKBooleanCreate(acceptAttestation)).get());
2679
2680         if (acceptAttestation) {
2681             JSRetainPtr<JSStringRef> privateKeyBase64PropertyName(Adopt, JSStringCreateWithUTF8CString("privateKeyBase64"));
2682             JSValueRef privateKeyBase64Value = JSObjectGetProperty(context, local, privateKeyBase64PropertyName.get(), 0);
2683             if (!JSValueIsString(context, privateKeyBase64Value))
2684                 return;
2685
2686             JSRetainPtr<JSStringRef> userCertificateBase64PropertyName(Adopt, JSStringCreateWithUTF8CString("userCertificateBase64"));
2687             JSValueRef userCertificateBase64Value = JSObjectGetProperty(context, local, userCertificateBase64PropertyName.get(), 0);
2688             if (!JSValueIsString(context, userCertificateBase64Value))
2689                 return;
2690
2691             JSRetainPtr<JSStringRef> intermediateCACertificateBase64PropertyName(Adopt, JSStringCreateWithUTF8CString("intermediateCACertificateBase64"));
2692             JSValueRef intermediateCACertificateBase64Value = JSObjectGetProperty(context, local, intermediateCACertificateBase64PropertyName.get(), 0);
2693             if (!JSValueIsString(context, intermediateCACertificateBase64Value))
2694                 return;
2695
2696             localKeys.append(adoptWK(WKStringCreateWithUTF8CString("PrivateKeyBase64")));
2697             localValues.append(toWK(adopt(JSValueToStringCopy(context, privateKeyBase64Value, 0)).get()));
2698             localKeys.append(adoptWK(WKStringCreateWithUTF8CString("UserCertificateBase64")));
2699             localValues.append(toWK(adopt(JSValueToStringCopy(context, userCertificateBase64Value, 0)).get()));
2700             localKeys.append(adoptWK(WKStringCreateWithUTF8CString("IntermediateCACertificateBase64")));
2701             localValues.append(toWK(adopt(JSValueToStringCopy(context, intermediateCACertificateBase64Value, 0)).get()));
2702         }
2703
2704         JSRetainPtr<JSStringRef> preferredUserhandleBase64PropertyName(Adopt, JSStringCreateWithUTF8CString("preferredUserhandleBase64"));
2705         JSValueRef preferredUserhandleBase64Value = JSObjectGetProperty(context, local, preferredUserhandleBase64PropertyName.get(), 0);
2706         if (!JSValueIsUndefined(context, preferredUserhandleBase64Value) && !JSValueIsNull(context, preferredUserhandleBase64Value)) {
2707             if (!JSValueIsString(context, preferredUserhandleBase64Value))
2708                 return;
2709
2710             localKeys.append(adoptWK(WKStringCreateWithUTF8CString("PreferredUserhandleBase64")));
2711             localValues.append(toWK(adopt(JSValueToStringCopy(context, preferredUserhandleBase64Value, 0)).get()));
2712         }
2713
2714         Vector<WKStringRef> rawLocalKeys;
2715         Vector<WKTypeRef> rawLocalValues;
2716         rawLocalKeys.resize(localKeys.size());
2717         rawLocalValues.resize(localValues.size());
2718         for (size_t i = 0; i < localKeys.size(); ++i) {
2719             rawLocalKeys[i] = localKeys[i].get();
2720             rawLocalValues[i] = localValues[i].get();
2721         }
2722
2723         configurationKeys.append(adoptWK(WKStringCreateWithUTF8CString("Local")));
2724         configurationValues.append(adoptWK(WKDictionaryCreate(rawLocalKeys.data(), rawLocalValues.data(), rawLocalKeys.size())));
2725     }
2726
2727     JSRetainPtr<JSStringRef> hidPropertyName(Adopt, JSStringCreateWithUTF8CString("hid"));
2728     JSValueRef hidValue = JSObjectGetProperty(context, configuration, hidPropertyName.get(), 0);
2729     if (!JSValueIsUndefined(context, hidValue) && !JSValueIsNull(context, hidValue)) {
2730         if (!JSValueIsObject(context, hidValue))
2731             return;
2732         JSObjectRef hid = JSValueToObject(context, hidValue, 0);
2733
2734         JSRetainPtr<JSStringRef> stagePropertyName(Adopt, JSStringCreateWithUTF8CString("stage"));
2735         JSValueRef stageValue = JSObjectGetProperty(context, hid, stagePropertyName.get(), 0);
2736         if (!JSValueIsString(context, stageValue))
2737             return;
2738
2739         JSRetainPtr<JSStringRef> subStagePropertyName(Adopt, JSStringCreateWithUTF8CString("subStage"));
2740         JSValueRef subStageValue = JSObjectGetProperty(context, hid, subStagePropertyName.get(), 0);
2741         if (!JSValueIsString(context, subStageValue))
2742             return;
2743
2744         JSRetainPtr<JSStringRef> errorPropertyName(Adopt, JSStringCreateWithUTF8CString("error"));
2745         JSValueRef errorValue = JSObjectGetProperty(context, hid, errorPropertyName.get(), 0);
2746         if (!JSValueIsString(context, errorValue))
2747             return;
2748
2749         Vector<WKRetainPtr<WKStringRef>> hidKeys;
2750         Vector<WKRetainPtr<WKTypeRef>> hidValues;
2751         hidKeys.append(adoptWK(WKStringCreateWithUTF8CString("Stage")));
2752         hidValues.append(toWK(adopt(JSValueToStringCopy(context, stageValue, 0)).get()));
2753         hidKeys.append(adoptWK(WKStringCreateWithUTF8CString("SubStage")));
2754         hidValues.append(toWK(adopt(JSValueToStringCopy(context, subStageValue, 0)).get()));
2755         hidKeys.append(adoptWK(WKStringCreateWithUTF8CString("Error")));
2756         hidValues.append(toWK(adopt(JSValueToStringCopy(context, errorValue, 0)).get()));
2757
2758         JSRetainPtr<JSStringRef> payloadBase64PropertyName(Adopt, JSStringCreateWithUTF8CString("payloadBase64"));
2759         JSValueRef payloadBase64Value = JSObjectGetProperty(context, hid, payloadBase64PropertyName.get(), 0);
2760         if (!JSValueIsUndefined(context, payloadBase64Value) && !JSValueIsNull(context, payloadBase64Value)) {
2761             if (!JSValueIsArray(context, payloadBase64Value))
2762                 return;
2763
2764             JSObjectRef payloadBase64 = JSValueToObject(context, payloadBase64Value, nullptr);
2765             static auto lengthProperty = adopt(JSStringCreateWithUTF8CString("length"));
2766             JSValueRef payloadBase64LengthValue = JSObjectGetProperty(context, payloadBase64, lengthProperty.get(), nullptr);
2767             if (!JSValueIsNumber(context, payloadBase64LengthValue))
2768                 return;
2769
2770             auto payloadBase64s = adoptWK(WKMutableArrayCreate());
2771             auto payloadBase64Length = static_cast<size_t>(JSValueToNumber(context, payloadBase64LengthValue, nullptr));
2772             for (size_t i = 0; i < payloadBase64Length; ++i) {
2773                 JSValueRef payloadBase64Value = JSObjectGetPropertyAtIndex(context, payloadBase64, i, nullptr);
2774                 if (!JSValueIsString(context, payloadBase64Value))
2775                     continue;
2776                 WKArrayAppendItem(payloadBase64s.get(), toWK(adopt(JSValueToStringCopy(context, payloadBase64Value, 0)).get()).get());
2777             }
2778
2779             hidKeys.append(adoptWK(WKStringCreateWithUTF8CString("PayloadBase64")));
2780             hidValues.append(payloadBase64s);
2781         }
2782
2783         JSRetainPtr<JSStringRef> isU2fPropertyName(Adopt, JSStringCreateWithUTF8CString("isU2f"));
2784         JSValueRef isU2fValue = JSObjectGetProperty(context, hid, isU2fPropertyName.get(), 0);
2785         if (!JSValueIsUndefined(context, isU2fValue) && !JSValueIsNull(context, isU2fValue)) {
2786             if (!JSValueIsBoolean(context, isU2fValue))
2787                 return;
2788             bool isU2f = JSValueToBoolean(context, isU2fValue);
2789             hidKeys.append(adoptWK(WKStringCreateWithUTF8CString("IsU2f")));
2790             hidValues.append(adoptWK(WKBooleanCreate(isU2f)).get());
2791         }
2792
2793         JSRetainPtr<JSStringRef> keepAlivePropertyName(Adopt, JSStringCreateWithUTF8CString("keepAlive"));
2794         JSValueRef keepAliveValue = JSObjectGetProperty(context, hid, keepAlivePropertyName.get(), 0);
2795         if (!JSValueIsUndefined(context, keepAliveValue) && !JSValueIsNull(context, keepAliveValue)) {
2796             if (!JSValueIsBoolean(context, keepAliveValue))
2797                 return;
2798             bool keepAlive = JSValueToBoolean(context, keepAliveValue);
2799             hidKeys.append(adoptWK(WKStringCreateWithUTF8CString("KeepAlive")));
2800             hidValues.append(adoptWK(WKBooleanCreate(keepAlive)).get());
2801         }
2802
2803         JSRetainPtr<JSStringRef> fastDataArrivalPropertyName(Adopt, JSStringCreateWithUTF8CString("fastDataArrival"));
2804         JSValueRef fastDataArrivalValue = JSObjectGetProperty(context, hid, fastDataArrivalPropertyName.get(), 0);
2805         if (!JSValueIsUndefined(context, fastDataArrivalValue) && !JSValueIsNull(context, fastDataArrivalValue)) {
2806             if (!JSValueIsBoolean(context, fastDataArrivalValue))
2807                 return;
2808             bool fastDataArrival = JSValueToBoolean(context, fastDataArrivalValue);
2809             hidKeys.append(adoptWK(WKStringCreateWithUTF8CString("FastDataArrival")));
2810             hidValues.append(adoptWK(WKBooleanCreate(fastDataArrival)).get());
2811         }
2812
2813         JSRetainPtr<JSStringRef> continueAfterErrorDataPropertyName(Adopt, JSStringCreateWithUTF8CString("continueAfterErrorData"));
2814         JSValueRef continueAfterErrorDataValue = JSObjectGetProperty(context, hid, continueAfterErrorDataPropertyName.get(), 0);
2815         if (!JSValueIsUndefined(context, continueAfterErrorDataValue) && !JSValueIsNull(context, continueAfterErrorDataValue)) {
2816             if (!JSValueIsBoolean(context, continueAfterErrorDataValue))
2817                 return;
2818             bool continueAfterErrorData = JSValueToBoolean(context, continueAfterErrorDataValue);
2819             hidKeys.append(adoptWK(WKStringCreateWithUTF8CString("ContinueAfterErrorData")));
2820             hidValues.append(adoptWK(WKBooleanCreate(continueAfterErrorData)).get());
2821         }
2822
2823         JSRetainPtr<JSStringRef> canDowngradePropertyName(Adopt, JSStringCreateWithUTF8CString("canDowngrade"));
2824         JSValueRef canDowngradeValue = JSObjectGetProperty(context, hid, canDowngradePropertyName.get(), 0);
2825         if (!JSValueIsUndefined(context, canDowngradeValue) && !JSValueIsNull(context, canDowngradeValue)) {
2826             if (!JSValueIsBoolean(context, canDowngradeValue))
2827                 return;
2828             bool canDowngrade = JSValueToBoolean(context, canDowngradeValue);
2829             hidKeys.append(adoptWK(WKStringCreateWithUTF8CString("CanDowngrade")));
2830             hidValues.append(adoptWK(WKBooleanCreate(canDowngrade)).get());
2831         }
2832
2833         Vector<WKStringRef> rawHidKeys;
2834         Vector<WKTypeRef> rawHidValues;
2835         rawHidKeys.resize(hidKeys.size());
2836         rawHidValues.resize(hidValues.size());
2837         for (size_t i = 0; i < hidKeys.size(); ++i) {
2838             rawHidKeys[i] = hidKeys[i].get();
2839             rawHidValues[i] = hidValues[i].get();
2840         }
2841
2842         configurationKeys.append(adoptWK(WKStringCreateWithUTF8CString("Hid")));
2843         configurationValues.append(adoptWK(WKDictionaryCreate(rawHidKeys.data(), rawHidValues.data(), rawHidKeys.size())));
2844     }
2845
2846     JSRetainPtr<JSStringRef> nfcPropertyName(Adopt, JSStringCreateWithUTF8CString("nfc"));
2847     JSValueRef nfcValue = JSObjectGetProperty(context, configuration, nfcPropertyName.get(), 0);
2848     if (!JSValueIsUndefined(context, nfcValue) && !JSValueIsNull(context, nfcValue)) {
2849         if (!JSValueIsObject(context, nfcValue))
2850             return;
2851         JSObjectRef nfc = JSValueToObject(context, nfcValue, 0);
2852
2853         JSRetainPtr<JSStringRef> errorPropertyName(Adopt, JSStringCreateWithUTF8CString("error"));
2854         JSValueRef errorValue = JSObjectGetProperty(context, nfc, errorPropertyName.get(), 0);
2855         if (!JSValueIsString(context, errorValue))
2856             return;
2857
2858         Vector<WKRetainPtr<WKStringRef>> nfcKeys;
2859         Vector<WKRetainPtr<WKTypeRef>> nfcValues;
2860         nfcKeys.append(adoptWK(WKStringCreateWithUTF8CString("Error")));
2861         nfcValues.append(toWK(adopt(JSValueToStringCopy(context, errorValue, 0)).get()));
2862
2863         JSRetainPtr<JSStringRef> payloadBase64PropertyName(Adopt, JSStringCreateWithUTF8CString("payloadBase64"));
2864         JSValueRef payloadBase64Value = JSObjectGetProperty(context, nfc, payloadBase64PropertyName.get(), 0);
2865         if (!JSValueIsUndefined(context, payloadBase64Value) && !JSValueIsNull(context, payloadBase64Value)) {
2866             if (!JSValueIsArray(context, payloadBase64Value))
2867                 return;
2868
2869             JSObjectRef payloadBase64 = JSValueToObject(context, payloadBase64Value, nullptr);
2870             static auto lengthProperty = adopt(JSStringCreateWithUTF8CString("length"));
2871             JSValueRef payloadBase64LengthValue = JSObjectGetProperty(context, payloadBase64, lengthProperty.get(), nullptr);
2872             if (!JSValueIsNumber(context, payloadBase64LengthValue))
2873                 return;
2874
2875             auto payloadBase64s = adoptWK(WKMutableArrayCreate());
2876             auto payloadBase64Length = static_cast<size_t>(JSValueToNumber(context, payloadBase64LengthValue, nullptr));
2877             for (size_t i = 0; i < payloadBase64Length; ++i) {
2878                 JSValueRef payloadBase64Value = JSObjectGetPropertyAtIndex(context, payloadBase64, i, nullptr);
2879                 if (!JSValueIsString(context, payloadBase64Value))
2880                     continue;
2881                 WKArrayAppendItem(payloadBase64s.get(), toWK(adopt(JSValueToStringCopy(context, payloadBase64Value, 0)).get()).get());
2882             }
2883
2884             nfcKeys.append(adoptWK(WKStringCreateWithUTF8CString("PayloadBase64")));
2885             nfcValues.append(payloadBase64s);
2886         }
2887
2888         JSRetainPtr<JSStringRef> multipleTagsPropertyName(Adopt, JSStringCreateWithUTF8CString("multipleTags"));
2889         JSValueRef multipleTagsValue = JSObjectGetProperty(context, nfc, multipleTagsPropertyName.get(), 0);
2890         if (!JSValueIsUndefined(context, multipleTagsValue) && !JSValueIsNull(context, multipleTagsValue)) {
2891             if (!JSValueIsBoolean(context, multipleTagsValue))
2892                 return;
2893             bool multipleTags = JSValueToBoolean(context, multipleTagsValue);
2894             nfcKeys.append(adoptWK(WKStringCreateWithUTF8CString("MultipleTags")));
2895             nfcValues.append(adoptWK(WKBooleanCreate(multipleTags)).get());
2896         }
2897
2898         Vector<WKStringRef> rawNfcKeys;
2899         Vector<WKTypeRef> rawNfcValues;
2900         rawNfcKeys.resize(nfcKeys.size());
2901         rawNfcValues.resize(nfcValues.size());
2902         for (size_t i = 0; i < nfcKeys.size(); ++i) {
2903             rawNfcKeys[i] = nfcKeys[i].get();
2904             rawNfcValues[i] = nfcValues[i].get();
2905         }
2906
2907         configurationKeys.append(adoptWK(WKStringCreateWithUTF8CString("Nfc")));
2908         configurationValues.append(adoptWK(WKDictionaryCreate(rawNfcKeys.data(), rawNfcValues.data(), rawNfcKeys.size())));
2909     }
2910
2911     Vector<WKStringRef> rawConfigurationKeys;
2912     Vector<WKTypeRef> rawConfigurationValues;
2913     rawConfigurationKeys.resize(configurationKeys.size());
2914     rawConfigurationValues.resize(configurationValues.size());
2915     for (size_t i = 0; i < configurationKeys.size(); ++i) {
2916         rawConfigurationKeys[i] = configurationKeys[i].get();
2917         rawConfigurationValues[i] = configurationValues[i].get();
2918     }
2919
2920     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetWebAuthenticationMockConfiguration"));
2921     WKRetainPtr<WKDictionaryRef> messageBody = adoptWK(WKDictionaryCreate(rawConfigurationKeys.data(), rawConfigurationValues.data(), rawConfigurationKeys.size()));
2922     
2923     WKBundlePostSynchronousMessage(injectedBundle.bundle(), messageName.get(), messageBody.get(), nullptr);
2924 }
2925
2926 void TestRunner::addTestKeyToKeychain(JSStringRef privateKeyBase64, JSStringRef attrLabel, JSStringRef applicationTagBase64)
2927 {
2928     Vector<WKRetainPtr<WKStringRef>> keys;
2929     Vector<WKRetainPtr<WKTypeRef>> values;
2930
2931     keys.append(adoptWK(WKStringCreateWithUTF8CString("PrivateKey")));
2932     values.append(toWK(privateKeyBase64));
2933
2934     keys.append(adoptWK(WKStringCreateWithUTF8CString("AttrLabel")));
2935     values.append(toWK(attrLabel));
2936
2937     keys.append(adoptWK(WKStringCreateWithUTF8CString("ApplicationTag")));
2938     values.append(toWK(applicationTagBase64));
2939
2940     Vector<WKStringRef> rawKeys;
2941     Vector<WKTypeRef> rawValues;
2942     rawKeys.resize(keys.size());
2943     rawValues.resize(values.size());
2944
2945     for (size_t i = 0; i < keys.size(); ++i) {
2946         rawKeys[i] = keys[i].get();
2947         rawValues[i] = values[i].get();
2948     }
2949
2950     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("AddTestKeyToKeychain"));
2951     WKRetainPtr<WKDictionaryRef> messageBody = adoptWK(WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
2952
2953     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
2954 }
2955
2956 void TestRunner::cleanUpKeychain(JSStringRef attrLabel, JSStringRef applicationTagBase64)
2957 {
2958     Vector<WKRetainPtr<WKStringRef>> keys;
2959     Vector<WKRetainPtr<WKTypeRef>> values;
2960
2961     keys.append(adoptWK(WKStringCreateWithUTF8CString("AttrLabel")));
2962     values.append(toWK(attrLabel));
2963
2964     if (applicationTagBase64) {
2965         keys.append(adoptWK(WKStringCreateWithUTF8CString("ApplicationTag")));
2966         values.append(toWK(applicationTagBase64));
2967     }
2968
2969     Vector<WKStringRef> rawKeys;
2970     Vector<WKTypeRef> rawValues;
2971     rawKeys.resize(keys.size());
2972     rawValues.resize(values.size());
2973
2974     for (size_t i = 0; i < keys.size(); ++i) {
2975         rawKeys[i] = keys[i].get();
2976         rawValues[i] = values[i].get();
2977     }
2978
2979     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("CleanUpKeychain"));
2980     WKRetainPtr<WKDictionaryRef> messageBody = adoptWK(WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
2981
2982     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
2983 }
2984
2985 bool TestRunner::keyExistsInKeychain(JSStringRef attrLabel, JSStringRef applicationTagBase64)
2986 {
2987     Vector<WKRetainPtr<WKStringRef>> keys;
2988     Vector<WKRetainPtr<WKTypeRef>> values;
2989
2990     keys.append(adoptWK(WKStringCreateWithUTF8CString("AttrLabel")));
2991     values.append(toWK(attrLabel));
2992
2993     keys.append(adoptWK(WKStringCreateWithUTF8CString("ApplicationTag")));
2994     values.append(toWK(applicationTagBase64));
2995
2996     Vector<WKStringRef> rawKeys;
2997     Vector<WKTypeRef> rawValues;
2998     rawKeys.resize(keys.size());
2999     rawValues.resize(values.size());
3000
3001     for (size_t i = 0; i < keys.size(); ++i) {
3002         rawKeys[i] = keys[i].get();
3003         rawValues[i] = values[i].get();
3004     }
3005
3006     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("KeyExistsInKeychain"));
3007     WKRetainPtr<WKDictionaryRef> messageBody = adoptWK(WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
3008
3009     WKTypeRef returnData = nullptr;
3010     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), &returnData);
3011     ASSERT(WKGetTypeID(returnData) == WKBooleanGetTypeID());
3012     return WKBooleanGetValue(adoptWK(static_cast<WKBooleanRef>(returnData)).get());
3013 }
3014
3015 unsigned long TestRunner::serverTrustEvaluationCallbackCallsCount()
3016 {
3017     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("ServerTrustEvaluationCallbackCallsCount"));
3018     WKTypeRef returnData = nullptr;
3019     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), nullptr, &returnData);
3020     ASSERT(WKGetTypeID(returnData) == WKUInt64GetTypeID());
3021     return WKUInt64GetValue(adoptWK(static_cast<WKUInt64Ref>(returnData)).get());
3022 }
3023
3024 void TestRunner::setShouldDismissJavaScriptAlertsAsynchronously(bool shouldDismissAsynchronously)
3025 {
3026     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("ShouldDismissJavaScriptAlertsAsynchronously"));
3027     WKRetainPtr<WKBooleanRef> messageBody = adoptWK(WKBooleanCreate(shouldDismissAsynchronously));
3028     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
3029 }
3030
3031 void TestRunner::abortModal()
3032 {
3033     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("AbortModal"));
3034     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), nullptr, nullptr);
3035 }
3036
3037 void TestRunner::dumpAdClickAttribution()
3038 {
3039     auto messageName = adoptWK(WKStringCreateWithUTF8CString("DumpAdClickAttribution"));
3040     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), nullptr, nullptr);
3041 }
3042
3043 void TestRunner::clearAdClickAttribution()
3044 {
3045     auto messageName = adoptWK(WKStringCreateWithUTF8CString("ClearAdClickAttribution"));
3046     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), nullptr, nullptr);
3047 }
3048
3049 void TestRunner::clearAdClickAttributionsThroughWebsiteDataRemoval()
3050 {
3051     auto messageName = adoptWK(WKStringCreateWithUTF8CString("ClearAdClickAttributionsThroughWebsiteDataRemoval"));
3052     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), nullptr, nullptr);
3053 }
3054
3055 void TestRunner::setAdClickAttributionOverrideTimerForTesting(bool value)
3056 {
3057     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetAdClickAttributionOverrideTimerForTesting"));
3058     WKRetainPtr<WKBooleanRef> messageBody = adoptWK(WKBooleanCreate(value));
3059     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get(), nullptr);
3060 }
3061
3062 void TestRunner::setAdClickAttributionConversionURLForTesting(JSStringRef urlString)
3063 {
3064     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetAdClickAttributionConversionURLForTesting"));
3065     auto wtfURLString = toWTFString(WKStringCreateWithJSString(urlString));
3066     WKRetainPtr<WKURLRef> messageBody = adoptWK(WKURLCreateWithUTF8CString(wtfURLString.utf8().data()));
3067     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get(), nullptr);
3068 }
3069
3070 void TestRunner::markAdClickAttributionsAsExpiredForTesting()
3071 {
3072     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("MarkAdClickAttributionsAsExpiredForTesting"));
3073     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), nullptr, nullptr);
3074 }
3075
3076 } // namespace WTR