Source/WebCore:
[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     SetStatisticsPrevalentResourceCallbackID,
736     SetStatisticsVeryPrevalentResourceCallbackID,
737     SetStatisticsHasHadUserInteractionCallbackID,
738     StatisticsDidModifyDataRecordsCallbackID,
739     StatisticsDidScanDataRecordsCallbackID,
740     StatisticsDidRunTelemetryCallbackID,
741     StatisticsDidClearThroughWebsiteDataRemovalCallbackID,
742     StatisticsDidResetToConsistentStateCallbackID,
743     StatisticsDidSetBlockCookiesForHostCallbackID,
744     AllStorageAccessEntriesCallbackID,
745     DidRemoveAllSessionCredentialsCallbackID,
746     GetApplicationManifestCallbackID,
747     TextDidChangeInTextFieldCallbackID,
748     TextFieldDidBeginEditingCallbackID,
749     TextFieldDidEndEditingCallbackID,
750     CustomMenuActionCallbackID,
751     FirstUIScriptCallbackID = 100
752 };
753
754 static void cacheTestRunnerCallback(unsigned index, JSValueRef callback)
755 {
756     if (!callback)
757         return;
758
759     if (callbackMap().contains(index)) {
760         InjectedBundle::singleton().outputText(makeString("FAIL: Tried to install a second TestRunner callback for the same event (id ", index, ")\n\n"));
761         return;
762     }
763
764     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
765     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
766     JSValueProtect(context, callback);
767     callbackMap().add(index, callback);
768 }
769
770 static void callTestRunnerCallback(unsigned index, size_t argumentCount = 0, const JSValueRef arguments[] = nullptr)
771 {
772     if (!callbackMap().contains(index))
773         return;
774     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
775     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
776     JSObjectRef callback = JSValueToObject(context, callbackMap().take(index), 0);
777     JSObjectCallAsFunction(context, callback, JSContextGetGlobalObject(context), argumentCount, arguments, 0);
778     JSValueUnprotect(context, callback);
779 }
780
781 void TestRunner::clearTestRunnerCallbacks()
782 {
783     for (auto& iter : callbackMap()) {
784         WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
785         JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
786         JSObjectRef callback = JSValueToObject(context, iter.value, 0);
787         JSValueUnprotect(context, callback);
788     }
789
790     callbackMap().clear();
791 }
792
793 void TestRunner::accummulateLogsForChannel(JSStringRef)
794 {
795     // FIXME: Implement getting the call to all processes.
796 }
797
798 void TestRunner::addChromeInputField(JSValueRef callback)
799 {
800     cacheTestRunnerCallback(AddChromeInputFieldCallbackID, callback);
801     InjectedBundle::singleton().postAddChromeInputField();
802 }
803
804 void TestRunner::removeChromeInputField(JSValueRef callback)
805 {
806     cacheTestRunnerCallback(RemoveChromeInputFieldCallbackID, callback);
807     InjectedBundle::singleton().postRemoveChromeInputField();
808 }
809
810 void TestRunner::focusWebView(JSValueRef callback)
811 {
812     cacheTestRunnerCallback(FocusWebViewCallbackID, callback);
813     InjectedBundle::singleton().postFocusWebView();
814 }
815
816 void TestRunner::setBackingScaleFactor(double backingScaleFactor, JSValueRef callback)
817 {
818     cacheTestRunnerCallback(SetBackingScaleFactorCallbackID, callback);
819     InjectedBundle::singleton().postSetBackingScaleFactor(backingScaleFactor);
820 }
821
822 void TestRunner::setWindowIsKey(bool isKey)
823 {
824     InjectedBundle::singleton().postSetWindowIsKey(isKey);
825 }
826
827 void TestRunner::setViewSize(double width, double height)
828 {
829     InjectedBundle::singleton().postSetViewSize(width, height);
830 }
831
832 void TestRunner::callAddChromeInputFieldCallback()
833 {
834     callTestRunnerCallback(AddChromeInputFieldCallbackID);
835 }
836
837 void TestRunner::callRemoveChromeInputFieldCallback()
838 {
839     callTestRunnerCallback(RemoveChromeInputFieldCallbackID);
840 }
841
842 void TestRunner::callFocusWebViewCallback()
843 {
844     callTestRunnerCallback(FocusWebViewCallbackID);
845 }
846
847 void TestRunner::callSetBackingScaleFactorCallback()
848 {
849     callTestRunnerCallback(SetBackingScaleFactorCallbackID);
850 }
851
852 static inline bool toBool(JSStringRef value)
853 {
854     return JSStringIsEqualToUTF8CString(value, "true") || JSStringIsEqualToUTF8CString(value, "1");
855 }
856
857 void TestRunner::overridePreference(JSStringRef preference, JSStringRef value)
858 {
859     auto& injectedBundle = InjectedBundle::singleton();
860     // FIXME: handle non-boolean preferences.
861     WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), toWK(preference).get(), toBool(value));
862 }
863
864 void TestRunner::setAlwaysAcceptCookies(bool accept)
865 {
866     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetAlwaysAcceptCookies"));
867
868     WKRetainPtr<WKBooleanRef> messageBody = adoptWK(WKBooleanCreate(accept));
869
870     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
871 }
872
873 void TestRunner::setOnlyAcceptFirstPartyCookies(bool accept)
874 {
875     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetOnlyAcceptFirstPartyCookies"));
876     
877     WKRetainPtr<WKBooleanRef> messageBody = adoptWK(WKBooleanCreate(accept));
878     
879     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
880 }
881
882 double TestRunner::preciseTime()
883 {
884     return WallTime::now().secondsSinceEpoch().seconds();
885 }
886
887 void TestRunner::setRenderTreeDumpOptions(unsigned short options)
888 {
889     m_renderTreeDumpOptions = options;
890 }
891
892 void TestRunner::setUserStyleSheetEnabled(bool enabled)
893 {
894     m_userStyleSheetEnabled = enabled;
895
896     WKRetainPtr<WKStringRef> emptyUrl = adoptWK(WKStringCreateWithUTF8CString(""));
897     WKStringRef location = enabled ? m_userStyleSheetLocation.get() : emptyUrl.get();
898     auto& injectedBundle = InjectedBundle::singleton();
899     WKBundleSetUserStyleSheetLocation(injectedBundle.bundle(), injectedBundle.pageGroup(), location);
900 }
901
902 void TestRunner::setUserStyleSheetLocation(JSStringRef location)
903 {
904     m_userStyleSheetLocation = adoptWK(WKStringCreateWithJSString(location));
905
906     if (m_userStyleSheetEnabled)
907         setUserStyleSheetEnabled(true);
908 }
909
910 void TestRunner::setSpatialNavigationEnabled(bool enabled)
911 {
912     auto& injectedBundle = InjectedBundle::singleton();
913     WKBundleSetSpatialNavigationEnabled(injectedBundle.bundle(), injectedBundle.pageGroup(), enabled);
914 }
915
916 void TestRunner::setTabKeyCyclesThroughElements(bool enabled)
917 {
918     auto& injectedBundle = InjectedBundle::singleton();
919     WKBundleSetTabKeyCyclesThroughElements(injectedBundle.bundle(), injectedBundle.page()->page(), enabled);
920 }
921
922 void TestRunner::setSerializeHTTPLoads()
923 {
924     // WK2 doesn't reorder loads.
925 }
926
927 void TestRunner::dispatchPendingLoadRequests()
928 {
929     // WK2 doesn't keep pending requests.
930 }
931
932 void TestRunner::setCacheModel(int model)
933 {
934     InjectedBundle::singleton().setCacheModel(model);
935 }
936
937 void TestRunner::setAsynchronousSpellCheckingEnabled(bool enabled)
938 {
939     auto& injectedBundle = InjectedBundle::singleton();
940     WKBundleSetAsynchronousSpellCheckingEnabled(injectedBundle.bundle(), injectedBundle.pageGroup(), enabled);
941 }
942
943 void TestRunner::grantWebNotificationPermission(JSStringRef origin)
944 {
945     WKRetainPtr<WKStringRef> originWK = toWK(origin);
946     auto& injectedBundle = InjectedBundle::singleton();
947     WKBundleSetWebNotificationPermission(injectedBundle.bundle(), injectedBundle.page()->page(), originWK.get(), true);
948 }
949
950 void TestRunner::denyWebNotificationPermission(JSStringRef origin)
951 {
952     WKRetainPtr<WKStringRef> originWK = toWK(origin);
953     auto& injectedBundle = InjectedBundle::singleton();
954     WKBundleSetWebNotificationPermission(injectedBundle.bundle(), injectedBundle.page()->page(), originWK.get(), false);
955 }
956
957 void TestRunner::removeAllWebNotificationPermissions()
958 {
959     auto& injectedBundle = InjectedBundle::singleton();
960     WKBundleRemoveAllWebNotificationPermissions(injectedBundle.bundle(), injectedBundle.page()->page());
961 }
962
963 void TestRunner::simulateWebNotificationClick(JSValueRef notification)
964 {
965     auto& injectedBundle = InjectedBundle::singleton();
966     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(injectedBundle.page()->page());
967     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
968     uint64_t notificationID = WKBundleGetWebNotificationID(injectedBundle.bundle(), context, notification);
969     injectedBundle.postSimulateWebNotificationClick(notificationID);
970 }
971
972 void TestRunner::setGeolocationPermission(bool enabled)
973 {
974     // FIXME: this should be done by frame.
975     InjectedBundle::singleton().setGeolocationPermission(enabled);
976 }
977
978 bool TestRunner::isGeolocationProviderActive()
979 {
980     return InjectedBundle::singleton().isGeolocationProviderActive();
981 }
982
983 void TestRunner::setMockGeolocationPosition(double latitude, double longitude, double accuracy, JSValueRef jsAltitude, JSValueRef jsAltitudeAccuracy, JSValueRef jsHeading, JSValueRef jsSpeed, JSValueRef jsFloorLevel)
984 {
985     auto& injectedBundle = InjectedBundle::singleton();
986     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(injectedBundle.page()->page());
987     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
988
989     bool providesAltitude = false;
990     double altitude = 0.;
991     if (!JSValueIsUndefined(context, jsAltitude)) {
992         providesAltitude = true;
993         altitude = JSValueToNumber(context, jsAltitude, 0);
994     }
995
996     bool providesAltitudeAccuracy = false;
997     double altitudeAccuracy = 0.;
998     if (!JSValueIsUndefined(context, jsAltitudeAccuracy)) {
999         providesAltitudeAccuracy = true;
1000         altitudeAccuracy = JSValueToNumber(context, jsAltitudeAccuracy, 0);
1001     }
1002
1003     bool providesHeading = false;
1004     double heading = 0.;
1005     if (!JSValueIsUndefined(context, jsHeading)) {
1006         providesHeading = true;
1007         heading = JSValueToNumber(context, jsHeading, 0);
1008     }
1009
1010     bool providesSpeed = false;
1011     double speed = 0.;
1012     if (!JSValueIsUndefined(context, jsSpeed)) {
1013         providesSpeed = true;
1014         speed = JSValueToNumber(context, jsSpeed, 0);
1015     }
1016
1017     bool providesFloorLevel = false;
1018     double floorLevel = 0.;
1019     if (!JSValueIsUndefined(context, jsFloorLevel)) {
1020         providesFloorLevel = true;
1021         floorLevel = JSValueToNumber(context, jsFloorLevel, 0);
1022     }
1023
1024     injectedBundle.setMockGeolocationPosition(latitude, longitude, accuracy, providesAltitude, altitude, providesAltitudeAccuracy, altitudeAccuracy, providesHeading, heading, providesSpeed, speed, providesFloorLevel, floorLevel);
1025 }
1026
1027 void TestRunner::setMockGeolocationPositionUnavailableError(JSStringRef message)
1028 {
1029     WKRetainPtr<WKStringRef> messageWK = toWK(message);
1030     InjectedBundle::singleton().setMockGeolocationPositionUnavailableError(messageWK.get());
1031 }
1032
1033 void TestRunner::setUserMediaPermission(bool enabled)
1034 {
1035     // FIXME: this should be done by frame.
1036     InjectedBundle::singleton().setUserMediaPermission(enabled);
1037 }
1038
1039 void TestRunner::resetUserMediaPermission()
1040 {
1041     // FIXME: this should be done by frame.
1042     InjectedBundle::singleton().resetUserMediaPermission();
1043 }
1044
1045 bool TestRunner::isDoingMediaCapture() const
1046 {
1047     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("IsDoingMediaCapture"));
1048     WKTypeRef returnData = nullptr;
1049     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), nullptr, &returnData);
1050     ASSERT(WKGetTypeID(returnData) == WKBooleanGetTypeID());
1051     return WKBooleanGetValue(adoptWK(static_cast<WKBooleanRef>(returnData)).get());
1052 }
1053
1054 void TestRunner::setUserMediaPersistentPermissionForOrigin(bool permission, JSStringRef origin, JSStringRef parentOrigin)
1055 {
1056     WKRetainPtr<WKStringRef> originWK = toWK(origin);
1057     WKRetainPtr<WKStringRef> parentOriginWK = toWK(parentOrigin);
1058     InjectedBundle::singleton().setUserMediaPersistentPermissionForOrigin(permission, originWK.get(), parentOriginWK.get());
1059 }
1060
1061 unsigned TestRunner::userMediaPermissionRequestCountForOrigin(JSStringRef origin, JSStringRef parentOrigin) const
1062 {
1063     WKRetainPtr<WKStringRef> originWK = toWK(origin);
1064     WKRetainPtr<WKStringRef> parentOriginWK = toWK(parentOrigin);
1065     return InjectedBundle::singleton().userMediaPermissionRequestCountForOrigin(originWK.get(), parentOriginWK.get());
1066 }
1067
1068 void TestRunner::resetUserMediaPermissionRequestCountForOrigin(JSStringRef origin, JSStringRef parentOrigin)
1069 {
1070     WKRetainPtr<WKStringRef> originWK = toWK(origin);
1071     WKRetainPtr<WKStringRef> parentOriginWK = toWK(parentOrigin);
1072     InjectedBundle::singleton().resetUserMediaPermissionRequestCountForOrigin(originWK.get(), parentOriginWK.get());
1073 }
1074
1075 bool TestRunner::callShouldCloseOnWebView()
1076 {
1077     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
1078     return WKBundleFrameCallShouldCloseOnWebView(mainFrame);
1079 }
1080
1081 void TestRunner::queueBackNavigation(unsigned howFarBackward)
1082 {
1083     InjectedBundle::singleton().queueBackNavigation(howFarBackward);
1084 }
1085
1086 void TestRunner::queueForwardNavigation(unsigned howFarForward)
1087 {
1088     InjectedBundle::singleton().queueForwardNavigation(howFarForward);
1089 }
1090
1091 void TestRunner::queueLoad(JSStringRef url, JSStringRef target, bool shouldOpenExternalURLs)
1092 {
1093     auto& injectedBundle = InjectedBundle::singleton();
1094     WKRetainPtr<WKURLRef> baseURLWK = adoptWK(WKBundleFrameCopyURL(WKBundlePageGetMainFrame(injectedBundle.page()->page())));
1095     WKRetainPtr<WKURLRef> urlWK = adoptWK(WKURLCreateWithBaseURL(baseURLWK.get(), toWTFString(toWK(url)).utf8().data()));
1096     WKRetainPtr<WKStringRef> urlStringWK = adoptWK(WKURLCopyString(urlWK.get()));
1097
1098     injectedBundle.queueLoad(urlStringWK.get(), toWK(target).get(), shouldOpenExternalURLs);
1099 }
1100
1101 void TestRunner::queueLoadHTMLString(JSStringRef content, JSStringRef baseURL, JSStringRef unreachableURL)
1102 {
1103     WKRetainPtr<WKStringRef> contentWK = toWK(content);
1104     WKRetainPtr<WKStringRef> baseURLWK = baseURL ? toWK(baseURL) : WKRetainPtr<WKStringRef>();
1105     WKRetainPtr<WKStringRef> unreachableURLWK = unreachableURL ? toWK(unreachableURL) : WKRetainPtr<WKStringRef>();
1106
1107     InjectedBundle::singleton().queueLoadHTMLString(contentWK.get(), baseURLWK.get(), unreachableURLWK.get());
1108 }
1109
1110 void TestRunner::queueReload()
1111 {
1112     InjectedBundle::singleton().queueReload();
1113 }
1114
1115 void TestRunner::queueLoadingScript(JSStringRef script)
1116 {
1117     WKRetainPtr<WKStringRef> scriptWK = toWK(script);
1118     InjectedBundle::singleton().queueLoadingScript(scriptWK.get());
1119 }
1120
1121 void TestRunner::queueNonLoadingScript(JSStringRef script)
1122 {
1123     WKRetainPtr<WKStringRef> scriptWK = toWK(script);
1124     InjectedBundle::singleton().queueNonLoadingScript(scriptWK.get());
1125 }
1126
1127 void TestRunner::setRejectsProtectionSpaceAndContinueForAuthenticationChallenges(bool value)
1128 {
1129     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetRejectsProtectionSpaceAndContinueForAuthenticationChallenges"));
1130     WKRetainPtr<WKBooleanRef> messageBody = adoptWK(WKBooleanCreate(value));
1131     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
1132 }
1133     
1134 void TestRunner::setHandlesAuthenticationChallenges(bool handlesAuthenticationChallenges)
1135 {
1136     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetHandlesAuthenticationChallenges"));
1137     WKRetainPtr<WKBooleanRef> messageBody = adoptWK(WKBooleanCreate(handlesAuthenticationChallenges));
1138     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
1139 }
1140
1141 void TestRunner::setShouldLogCanAuthenticateAgainstProtectionSpace(bool value)
1142 {
1143     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetShouldLogCanAuthenticateAgainstProtectionSpace"));
1144     WKRetainPtr<WKBooleanRef> messageBody = adoptWK(WKBooleanCreate(value));
1145     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
1146 }
1147
1148 void TestRunner::setShouldLogDownloadCallbacks(bool value)
1149 {
1150     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetShouldLogDownloadCallbacks"));
1151     WKRetainPtr<WKBooleanRef> messageBody = adoptWK(WKBooleanCreate(value));
1152     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
1153 }
1154
1155 void TestRunner::setAuthenticationUsername(JSStringRef username)
1156 {
1157     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetAuthenticationUsername"));
1158     WKRetainPtr<WKStringRef> messageBody = adoptWK(WKStringCreateWithJSString(username));
1159     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
1160 }
1161
1162 void TestRunner::setAuthenticationPassword(JSStringRef password)
1163 {
1164     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetAuthenticationPassword"));
1165     WKRetainPtr<WKStringRef> messageBody = adoptWK(WKStringCreateWithJSString(password));
1166     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
1167 }
1168
1169 bool TestRunner::secureEventInputIsEnabled() const
1170 {
1171     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SecureEventInputIsEnabled"));
1172     WKTypeRef returnData = nullptr;
1173     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), nullptr, &returnData);
1174     ASSERT(WKGetTypeID(returnData) == WKBooleanGetTypeID());
1175     return WKBooleanGetValue(adoptWK(static_cast<WKBooleanRef>(returnData)).get());
1176 }
1177
1178 void TestRunner::setBlockAllPlugins(bool shouldBlock)
1179 {
1180     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetBlockAllPlugins"));
1181     WKRetainPtr<WKBooleanRef> messageBody = adoptWK(WKBooleanCreate(shouldBlock));
1182     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
1183 }
1184
1185 void TestRunner::setPluginSupportedMode(JSStringRef mode)
1186 {
1187     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetPluginSupportedMode"));
1188     WKRetainPtr<WKStringRef> messageBody = adoptWK(WKStringCreateWithJSString(mode));
1189     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
1190 }
1191
1192 JSValueRef TestRunner::failNextNewCodeBlock()
1193 {
1194     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
1195     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
1196     return JSC::failNextNewCodeBlock(context);
1197 }
1198
1199 JSValueRef TestRunner::numberOfDFGCompiles(JSValueRef theFunction)
1200 {
1201     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
1202     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
1203     return JSC::numberOfDFGCompiles(context, theFunction);
1204 }
1205
1206 JSValueRef TestRunner::neverInlineFunction(JSValueRef theFunction)
1207 {
1208     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
1209     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
1210     return JSC::setNeverInline(context, theFunction);
1211 }
1212
1213 void TestRunner::setShouldDecideNavigationPolicyAfterDelay(bool value)
1214 {
1215     m_shouldDecideNavigationPolicyAfterDelay = value;
1216     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetShouldDecideNavigationPolicyAfterDelay"));
1217     WKRetainPtr<WKBooleanRef> messageBody = adoptWK(WKBooleanCreate(value));
1218     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
1219 }
1220
1221 void TestRunner::setShouldDecideResponsePolicyAfterDelay(bool value)
1222 {
1223     m_shouldDecideResponsePolicyAfterDelay = value;
1224     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetShouldDecideResponsePolicyAfterDelay"));
1225     WKRetainPtr<WKBooleanRef> messageBody = adoptWK(WKBooleanCreate(value));
1226     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
1227 }
1228
1229 void TestRunner::setNavigationGesturesEnabled(bool value)
1230 {
1231     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetNavigationGesturesEnabled"));
1232     WKRetainPtr<WKBooleanRef> messageBody = adoptWK(WKBooleanCreate(value));
1233     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
1234 }
1235
1236 void TestRunner::setIgnoresViewportScaleLimits(bool value)
1237 {
1238     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetIgnoresViewportScaleLimits"));
1239     WKRetainPtr<WKBooleanRef> messageBody = adoptWK(WKBooleanCreate(value));
1240     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
1241 }
1242
1243 void TestRunner::setShouldDownloadUndisplayableMIMETypes(bool value)
1244 {
1245     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetShouldDownloadUndisplayableMIMETypes"));
1246     WKRetainPtr<WKBooleanRef> messageBody = adoptWK(WKBooleanCreate(value));
1247     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
1248 }
1249
1250 void TestRunner::setShouldAllowDeviceOrientationAndMotionAccess(bool value)
1251 {
1252     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetShouldAllowDeviceOrientationAndMotionAccess"));
1253     WKRetainPtr<WKBooleanRef> messageBody = adoptWK(WKBooleanCreate(value));
1254     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
1255 }
1256
1257 void TestRunner::terminateNetworkProcess()
1258 {
1259     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("TerminateNetworkProcess"));
1260     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), nullptr, nullptr);
1261 }
1262
1263 void TestRunner::terminateServiceWorkerProcess()
1264 {
1265     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("TerminateServiceWorkerProcess"));
1266     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), nullptr, nullptr);
1267 }
1268
1269 static unsigned nextUIScriptCallbackID()
1270 {
1271     static unsigned callbackID = FirstUIScriptCallbackID;
1272     return callbackID++;
1273 }
1274
1275 void TestRunner::runUIScript(JSStringRef script, JSValueRef callback)
1276 {
1277     unsigned callbackID = nextUIScriptCallbackID();
1278     cacheTestRunnerCallback(callbackID, callback);
1279
1280     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("RunUIProcessScript"));
1281
1282     WKRetainPtr<WKMutableDictionaryRef> testDictionary = adoptWK(WKMutableDictionaryCreate());
1283
1284     WKRetainPtr<WKStringRef> scriptKey = adoptWK(WKStringCreateWithUTF8CString("Script"));
1285     WKRetainPtr<WKStringRef> scriptValue = adoptWK(WKStringCreateWithJSString(script));
1286
1287     WKRetainPtr<WKStringRef> callbackIDKey = adoptWK(WKStringCreateWithUTF8CString("CallbackID"));
1288     WKRetainPtr<WKUInt64Ref> callbackIDValue = adoptWK(WKUInt64Create(callbackID));
1289
1290     WKDictionarySetItem(testDictionary.get(), scriptKey.get(), scriptValue.get());
1291     WKDictionarySetItem(testDictionary.get(), callbackIDKey.get(), callbackIDValue.get());
1292
1293     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), testDictionary.get());
1294 }
1295
1296 void TestRunner::runUIScriptCallback(unsigned callbackID, JSStringRef result)
1297 {
1298     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
1299     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
1300
1301     JSValueRef resultValue = JSValueMakeString(context, result);
1302     callTestRunnerCallback(callbackID, 1, &resultValue);
1303 }
1304
1305 void TestRunner::setAllowedMenuActions(JSValueRef actions)
1306 {
1307     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetAllowedMenuActions"));
1308     WKRetainPtr<WKMutableArrayRef> messageBody = adoptWK(WKMutableArrayCreate());
1309
1310     auto page = InjectedBundle::singleton().page()->page();
1311     auto mainFrame = WKBundlePageGetMainFrame(page);
1312     auto context = WKBundleFrameGetJavaScriptContext(mainFrame);
1313     auto lengthPropertyName = adopt(JSStringCreateWithUTF8CString("length"));
1314     auto actionsArray = JSValueToObject(context, actions, nullptr);
1315     auto lengthValue = JSObjectGetProperty(context, actionsArray, lengthPropertyName.get(), nullptr);
1316     if (!JSValueIsNumber(context, lengthValue))
1317         return;
1318
1319     auto length = static_cast<size_t>(JSValueToNumber(context, lengthValue, 0));
1320     for (size_t i = 0; i < length; ++i) {
1321         auto value = JSObjectGetPropertyAtIndex(context, actionsArray, i, 0);
1322         if (!JSValueIsString(context, value))
1323             continue;
1324
1325         auto actionName = adopt(JSValueToStringCopy(context, value, 0));
1326         WKRetainPtr<WKStringRef> action = adoptWK(WKStringCreateWithJSString(actionName.get()));
1327         WKArrayAppendItem(messageBody.get(), action.get());
1328     }
1329
1330     WKBundlePagePostMessage(page, messageName.get(), messageBody.get());
1331 }
1332
1333 void TestRunner::installCustomMenuAction(JSStringRef name, bool dismissesAutomatically, JSValueRef callback)
1334 {
1335     cacheTestRunnerCallback(CustomMenuActionCallbackID, callback);
1336
1337     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("InstallCustomMenuAction"));
1338     WKRetainPtr<WKMutableDictionaryRef> messageBody = adoptWK(WKMutableDictionaryCreate());
1339
1340     WKRetainPtr<WKStringRef> nameKey = adoptWK(WKStringCreateWithUTF8CString("name"));
1341     WKRetainPtr<WKStringRef> nameValue = adoptWK(WKStringCreateWithJSString(name));
1342     WKDictionarySetItem(messageBody.get(), nameKey.get(), nameValue.get());
1343
1344     WKRetainPtr<WKStringRef> dismissesAutomaticallyKey = adoptWK(WKStringCreateWithUTF8CString("dismissesAutomatically"));
1345     WKRetainPtr<WKBooleanRef> dismissesAutomaticallyValue = adoptWK(WKBooleanCreate(dismissesAutomatically));
1346     WKDictionarySetItem(messageBody.get(), dismissesAutomaticallyKey.get(), dismissesAutomaticallyValue.get());
1347
1348     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
1349 }
1350
1351 void TestRunner::installDidBeginSwipeCallback(JSValueRef callback)
1352 {
1353     cacheTestRunnerCallback(DidBeginSwipeCallbackID, callback);
1354 }
1355
1356 void TestRunner::installWillEndSwipeCallback(JSValueRef callback)
1357 {
1358     cacheTestRunnerCallback(WillEndSwipeCallbackID, callback);
1359 }
1360
1361 void TestRunner::installDidEndSwipeCallback(JSValueRef callback)
1362 {
1363     cacheTestRunnerCallback(DidEndSwipeCallbackID, callback);
1364 }
1365
1366 void TestRunner::installDidRemoveSwipeSnapshotCallback(JSValueRef callback)
1367 {
1368     cacheTestRunnerCallback(DidRemoveSwipeSnapshotCallbackID, callback);
1369 }
1370
1371 void TestRunner::callDidBeginSwipeCallback()
1372 {
1373     callTestRunnerCallback(DidBeginSwipeCallbackID);
1374 }
1375
1376 void TestRunner::callWillEndSwipeCallback()
1377 {
1378     callTestRunnerCallback(WillEndSwipeCallbackID);
1379 }
1380
1381 void TestRunner::callDidEndSwipeCallback()
1382 {
1383     callTestRunnerCallback(DidEndSwipeCallbackID);
1384 }
1385
1386 void TestRunner::callDidRemoveSwipeSnapshotCallback()
1387 {
1388     callTestRunnerCallback(DidRemoveSwipeSnapshotCallbackID);
1389 }
1390
1391 void TestRunner::setStatisticsDebugMode(bool value, JSValueRef completionHandler)
1392 {
1393     cacheTestRunnerCallback(SetStatisticsDebugModeCallbackID, completionHandler);
1394
1395     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetStatisticsDebugMode"));
1396     WKRetainPtr<WKBooleanRef> messageBody = adoptWK(WKBooleanCreate(value));
1397     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1398
1399 }
1400
1401 void TestRunner::statisticsCallDidSetDebugModeCallback()
1402 {
1403     callTestRunnerCallback(SetStatisticsDebugModeCallbackID);
1404 }
1405
1406 void TestRunner::setStatisticsPrevalentResourceForDebugMode(JSStringRef hostName, JSValueRef completionHandler)
1407 {
1408     cacheTestRunnerCallback(SetStatisticsPrevalentResourceForDebugModeCallbackID, completionHandler);
1409     
1410     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetStatisticsPrevalentResourceForDebugMode"));
1411     WKRetainPtr<WKStringRef> messageBody = adoptWK(WKStringCreateWithJSString(hostName));
1412     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1413 }
1414
1415 void TestRunner::statisticsCallDidSetPrevalentResourceForDebugModeCallback()
1416 {
1417     callTestRunnerCallback(SetStatisticsPrevalentResourceForDebugModeCallbackID);
1418 }
1419
1420 void TestRunner::setStatisticsLastSeen(JSStringRef hostName, double seconds, JSValueRef completionHandler)
1421 {
1422     cacheTestRunnerCallback(SetStatisticsLastSeenCallbackID, completionHandler);
1423
1424     Vector<WKRetainPtr<WKStringRef>> keys;
1425     Vector<WKRetainPtr<WKTypeRef>> values;
1426     
1427     keys.append(adoptWK(WKStringCreateWithUTF8CString("HostName")));
1428     values.append(adoptWK(WKStringCreateWithJSString(hostName)));
1429     
1430     keys.append(adoptWK(WKStringCreateWithUTF8CString("Value")));
1431     values.append(adoptWK(WKDoubleCreate(seconds)));
1432     
1433     Vector<WKStringRef> rawKeys(keys.size());
1434     Vector<WKTypeRef> rawValues(values.size());
1435     
1436     for (size_t i = 0; i < keys.size(); ++i) {
1437         rawKeys[i] = keys[i].get();
1438         rawValues[i] = values[i].get();
1439     }
1440     
1441     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetStatisticsLastSeen"));
1442     WKRetainPtr<WKDictionaryRef> messageBody = adoptWK(WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1443     
1444     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1445 }
1446
1447 void TestRunner::statisticsCallDidSetLastSeenCallback()
1448 {
1449     callTestRunnerCallback(SetStatisticsLastSeenCallbackID);
1450 }
1451
1452 void TestRunner::setStatisticsPrevalentResource(JSStringRef hostName, bool value, JSValueRef completionHandler)
1453 {
1454     cacheTestRunnerCallback(SetStatisticsPrevalentResourceCallbackID, completionHandler);
1455
1456     Vector<WKRetainPtr<WKStringRef>> keys;
1457     Vector<WKRetainPtr<WKTypeRef>> values;
1458
1459     keys.append(adoptWK(WKStringCreateWithUTF8CString("HostName")));
1460     values.append(adoptWK(WKStringCreateWithJSString(hostName)));
1461     
1462     keys.append(adoptWK(WKStringCreateWithUTF8CString("Value")));
1463     values.append(adoptWK(WKBooleanCreate(value)));
1464     
1465     Vector<WKStringRef> rawKeys;
1466     Vector<WKTypeRef> rawValues;
1467     rawKeys.resize(keys.size());
1468     rawValues.resize(values.size());
1469     
1470     for (size_t i = 0; i < keys.size(); ++i) {
1471         rawKeys[i] = keys[i].get();
1472         rawValues[i] = values[i].get();
1473     }
1474     
1475     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetStatisticsPrevalentResource"));
1476     WKRetainPtr<WKDictionaryRef> messageBody = adoptWK(WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1477
1478     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1479 }
1480
1481 void TestRunner::statisticsCallDidSetPrevalentResourceCallback()
1482 {
1483     callTestRunnerCallback(SetStatisticsPrevalentResourceCallbackID);
1484 }
1485
1486 void TestRunner::setStatisticsVeryPrevalentResource(JSStringRef hostName, bool value, JSValueRef completionHandler)
1487 {
1488     cacheTestRunnerCallback(SetStatisticsVeryPrevalentResourceCallbackID, completionHandler);
1489
1490     Vector<WKRetainPtr<WKStringRef>> keys;
1491     Vector<WKRetainPtr<WKTypeRef>> values;
1492     
1493     keys.append(adoptWK(WKStringCreateWithUTF8CString("HostName")));
1494     values.append(adoptWK(WKStringCreateWithJSString(hostName)));
1495     
1496     keys.append(adoptWK(WKStringCreateWithUTF8CString("Value")));
1497     values.append(adoptWK(WKBooleanCreate(value)));
1498     
1499     Vector<WKStringRef> rawKeys;
1500     Vector<WKTypeRef> rawValues;
1501     rawKeys.resize(keys.size());
1502     rawValues.resize(values.size());
1503     
1504     for (size_t i = 0; i < keys.size(); ++i) {
1505         rawKeys[i] = keys[i].get();
1506         rawValues[i] = values[i].get();
1507     }
1508     
1509     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetStatisticsVeryPrevalentResource"));
1510     WKRetainPtr<WKDictionaryRef> messageBody = adoptWK(WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1511     
1512     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1513 }
1514
1515 void TestRunner::statisticsCallDidSetVeryPrevalentResourceCallback()
1516 {
1517     callTestRunnerCallback(SetStatisticsVeryPrevalentResourceCallbackID);
1518 }
1519     
1520 void TestRunner::dumpResourceLoadStatistics()
1521 {
1522     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("dumpResourceLoadStatistics"));
1523     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), nullptr, nullptr);
1524 }
1525
1526 bool TestRunner::isStatisticsPrevalentResource(JSStringRef hostName)
1527 {
1528     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("IsStatisticsPrevalentResource"));
1529     WKRetainPtr<WKStringRef> messageBody = adoptWK(WKStringCreateWithJSString(hostName));
1530     WKTypeRef returnData = nullptr;
1531     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get(), &returnData);
1532     ASSERT(WKGetTypeID(returnData) == WKBooleanGetTypeID());
1533     return WKBooleanGetValue(adoptWK(static_cast<WKBooleanRef>(returnData)).get());
1534 }
1535
1536 bool TestRunner::isStatisticsVeryPrevalentResource(JSStringRef hostName)
1537 {
1538     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("IsStatisticsVeryPrevalentResource"));
1539     WKRetainPtr<WKStringRef> messageBody = adoptWK(WKStringCreateWithJSString(hostName));
1540     WKTypeRef returnData = nullptr;
1541     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get(), &returnData);
1542     ASSERT(WKGetTypeID(returnData) == WKBooleanGetTypeID());
1543     return WKBooleanGetValue(adoptWK(static_cast<WKBooleanRef>(returnData)).get());
1544 }
1545
1546 bool TestRunner::isStatisticsRegisteredAsSubresourceUnder(JSStringRef subresourceHost, JSStringRef topFrameHost)
1547 {
1548     Vector<WKRetainPtr<WKStringRef>> keys;
1549     Vector<WKRetainPtr<WKTypeRef>> values;
1550     
1551     keys.append(adoptWK(WKStringCreateWithUTF8CString("SubresourceHost")));
1552     values.append(adoptWK(WKStringCreateWithJSString(subresourceHost)));
1553     
1554     keys.append(adoptWK(WKStringCreateWithUTF8CString("TopFrameHost")));
1555     values.append(adoptWK(WKStringCreateWithJSString(topFrameHost)));
1556     
1557     Vector<WKStringRef> rawKeys(keys.size());
1558     Vector<WKTypeRef> rawValues(values.size());
1559     
1560     for (size_t i = 0; i < keys.size(); ++i) {
1561         rawKeys[i] = keys[i].get();
1562         rawValues[i] = values[i].get();
1563     }
1564     
1565     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("IsStatisticsRegisteredAsSubresourceUnder"));
1566     WKRetainPtr<WKDictionaryRef> messageBody = adoptWK(WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1567     WKTypeRef returnData = nullptr;
1568     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get(), &returnData);
1569     ASSERT(WKGetTypeID(returnData) == WKBooleanGetTypeID());
1570     return WKBooleanGetValue(adoptWK(static_cast<WKBooleanRef>(returnData)).get());
1571 }
1572
1573 bool TestRunner::isStatisticsRegisteredAsSubFrameUnder(JSStringRef subFrameHost, JSStringRef topFrameHost)
1574 {
1575     Vector<WKRetainPtr<WKStringRef>> keys;
1576     Vector<WKRetainPtr<WKTypeRef>> values;
1577
1578     keys.append(adoptWK(WKStringCreateWithUTF8CString("SubFrameHost")));
1579     values.append(adoptWK(WKStringCreateWithJSString(subFrameHost)));
1580     
1581     keys.append(adoptWK(WKStringCreateWithUTF8CString("TopFrameHost")));
1582     values.append(adoptWK(WKStringCreateWithJSString(topFrameHost)));
1583     
1584     Vector<WKStringRef> rawKeys(keys.size());
1585     Vector<WKTypeRef> rawValues(values.size());
1586
1587     for (size_t i = 0; i < keys.size(); ++i) {
1588         rawKeys[i] = keys[i].get();
1589         rawValues[i] = values[i].get();
1590     }
1591
1592     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("IsStatisticsRegisteredAsSubFrameUnder"));
1593     WKRetainPtr<WKDictionaryRef> messageBody = adoptWK(WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1594     WKTypeRef returnData = nullptr;
1595     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get(), &returnData);
1596     ASSERT(WKGetTypeID(returnData) == WKBooleanGetTypeID());
1597     return WKBooleanGetValue(adoptWK(static_cast<WKBooleanRef>(returnData)).get());
1598 }
1599
1600 bool TestRunner::isStatisticsRegisteredAsRedirectingTo(JSStringRef hostRedirectedFrom, JSStringRef hostRedirectedTo)
1601 {
1602     Vector<WKRetainPtr<WKStringRef>> keys;
1603     Vector<WKRetainPtr<WKTypeRef>> values;
1604     
1605     keys.append(adoptWK(WKStringCreateWithUTF8CString("HostRedirectedFrom")));
1606     values.append(adoptWK(WKStringCreateWithJSString(hostRedirectedFrom)));
1607     
1608     keys.append(adoptWK(WKStringCreateWithUTF8CString("HostRedirectedTo")));
1609     values.append(adoptWK(WKStringCreateWithJSString(hostRedirectedTo)));
1610     
1611     Vector<WKStringRef> rawKeys(keys.size());
1612     Vector<WKTypeRef> rawValues(values.size());
1613
1614     for (size_t i = 0; i < keys.size(); ++i) {
1615         rawKeys[i] = keys[i].get();
1616         rawValues[i] = values[i].get();
1617     }
1618     
1619     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("IsStatisticsRegisteredAsRedirectingTo"));
1620     WKRetainPtr<WKDictionaryRef> messageBody = adoptWK(WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1621     WKTypeRef returnData = nullptr;
1622     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get(), &returnData);
1623     ASSERT(WKGetTypeID(returnData) == WKBooleanGetTypeID());
1624     return WKBooleanGetValue(adoptWK(static_cast<WKBooleanRef>(returnData)).get());
1625 }
1626
1627 void TestRunner::setStatisticsHasHadUserInteraction(JSStringRef hostName, bool value, JSValueRef completionHandler)
1628 {
1629     cacheTestRunnerCallback(SetStatisticsHasHadUserInteractionCallbackID, completionHandler);
1630
1631     Vector<WKRetainPtr<WKStringRef>> keys;
1632     Vector<WKRetainPtr<WKTypeRef>> values;
1633     
1634     keys.append(adoptWK(WKStringCreateWithUTF8CString("HostName")));
1635     values.append(adoptWK(WKStringCreateWithJSString(hostName)));
1636     
1637     keys.append(adoptWK(WKStringCreateWithUTF8CString("Value")));
1638     values.append(adoptWK(WKBooleanCreate(value)));
1639     
1640     Vector<WKStringRef> rawKeys;
1641     Vector<WKTypeRef> rawValues;
1642     rawKeys.resize(keys.size());
1643     rawValues.resize(values.size());
1644     
1645     for (size_t i = 0; i < keys.size(); ++i) {
1646         rawKeys[i] = keys[i].get();
1647         rawValues[i] = values[i].get();
1648     }
1649     
1650     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetStatisticsHasHadUserInteraction"));
1651     WKRetainPtr<WKDictionaryRef> messageBody = adoptWK(WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1652     
1653     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1654 }
1655
1656 void TestRunner::statisticsCallDidSetHasHadUserInteractionCallback()
1657 {
1658     callTestRunnerCallback(SetStatisticsHasHadUserInteractionCallbackID);
1659 }
1660
1661 bool TestRunner::isStatisticsHasHadUserInteraction(JSStringRef hostName)
1662 {
1663     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("IsStatisticsHasHadUserInteraction"));
1664     WKRetainPtr<WKStringRef> messageBody = adoptWK(WKStringCreateWithJSString(hostName));
1665     WKTypeRef returnData = nullptr;
1666     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get(), &returnData);
1667     ASSERT(WKGetTypeID(returnData) == WKBooleanGetTypeID());
1668     return WKBooleanGetValue(adoptWK(static_cast<WKBooleanRef>(returnData)).get());
1669 }
1670
1671 void TestRunner::setStatisticsGrandfathered(JSStringRef hostName, bool value)
1672 {
1673     Vector<WKRetainPtr<WKStringRef>> keys;
1674     Vector<WKRetainPtr<WKTypeRef>> values;
1675     
1676     keys.append(adoptWK(WKStringCreateWithUTF8CString("HostName")));
1677     values.append(adoptWK(WKStringCreateWithJSString(hostName)));
1678     
1679     keys.append(adoptWK(WKStringCreateWithUTF8CString("Value")));
1680     values.append(adoptWK(WKBooleanCreate(value)));
1681     
1682     Vector<WKStringRef> rawKeys;
1683     Vector<WKTypeRef> rawValues;
1684     rawKeys.resize(keys.size());
1685     rawValues.resize(values.size());
1686     
1687     for (size_t i = 0; i < keys.size(); ++i) {
1688         rawKeys[i] = keys[i].get();
1689         rawValues[i] = values[i].get();
1690     }
1691     
1692     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetStatisticsGrandfathered"));
1693     WKRetainPtr<WKDictionaryRef> messageBody = adoptWK(WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1694     
1695     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1696 }
1697
1698 void TestRunner::setUseITPDatabase(bool value)
1699 {
1700     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetUseITPDatabase"));
1701     WKRetainPtr<WKBooleanRef> messageBody = adoptWK(WKBooleanCreate(value));
1702     
1703     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1704 }
1705
1706 bool TestRunner::isStatisticsGrandfathered(JSStringRef hostName)
1707 {
1708     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("IsStatisticsGrandfathered"));
1709     WKRetainPtr<WKStringRef> messageBody = adoptWK(WKStringCreateWithJSString(hostName));
1710     WKTypeRef returnData = nullptr;
1711     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get(), &returnData);
1712     ASSERT(WKGetTypeID(returnData) == WKBooleanGetTypeID());
1713     return WKBooleanGetValue(adoptWK(static_cast<WKBooleanRef>(returnData)).get());
1714 }
1715
1716 void TestRunner::setStatisticsSubframeUnderTopFrameOrigin(JSStringRef hostName, JSStringRef topFrameHostName)
1717 {
1718     Vector<WKRetainPtr<WKStringRef>> keys;
1719     Vector<WKRetainPtr<WKTypeRef>> values;
1720     
1721     keys.append(adoptWK(WKStringCreateWithUTF8CString("HostName")));
1722     values.append(adoptWK(WKStringCreateWithJSString(hostName)));
1723     
1724     keys.append(adoptWK(WKStringCreateWithUTF8CString("TopFrameHostName")));
1725     values.append(adoptWK(WKStringCreateWithJSString(topFrameHostName)));
1726     
1727     Vector<WKStringRef> rawKeys(keys.size());
1728     Vector<WKTypeRef> rawValues(values.size());
1729     
1730     for (size_t i = 0; i < keys.size(); ++i) {
1731         rawKeys[i] = keys[i].get();
1732         rawValues[i] = values[i].get();
1733     }
1734     
1735     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetStatisticsSubframeUnderTopFrameOrigin"));
1736     WKRetainPtr<WKDictionaryRef> messageBody = adoptWK(WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1737     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1738 }
1739
1740 void TestRunner::setStatisticsSubresourceUnderTopFrameOrigin(JSStringRef hostName, JSStringRef topFrameHostName)
1741 {
1742     Vector<WKRetainPtr<WKStringRef>> keys;
1743     Vector<WKRetainPtr<WKTypeRef>> values;
1744     
1745     keys.append(adoptWK(WKStringCreateWithUTF8CString("HostName")));
1746     values.append(adoptWK(WKStringCreateWithJSString(hostName)));
1747     
1748     keys.append(adoptWK(WKStringCreateWithUTF8CString("TopFrameHostName")));
1749     values.append(adoptWK(WKStringCreateWithJSString(topFrameHostName)));
1750     
1751     Vector<WKStringRef> rawKeys(keys.size());
1752     Vector<WKTypeRef> rawValues(values.size());
1753     
1754     for (size_t i = 0; i < keys.size(); ++i) {
1755         rawKeys[i] = keys[i].get();
1756         rawValues[i] = values[i].get();
1757     }
1758     
1759     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetStatisticsSubresourceUnderTopFrameOrigin"));
1760     WKRetainPtr<WKDictionaryRef> messageBody = adoptWK(WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1761     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1762 }
1763
1764 void TestRunner::setStatisticsSubresourceUniqueRedirectTo(JSStringRef hostName, JSStringRef hostNameRedirectedTo)
1765 {
1766     Vector<WKRetainPtr<WKStringRef>> keys;
1767     Vector<WKRetainPtr<WKTypeRef>> values;
1768     
1769     keys.append(adoptWK(WKStringCreateWithUTF8CString("HostName")));
1770     values.append(adoptWK(WKStringCreateWithJSString(hostName)));
1771     
1772     keys.append(adoptWK(WKStringCreateWithUTF8CString("HostNameRedirectedTo")));
1773     values.append(adoptWK(WKStringCreateWithJSString(hostNameRedirectedTo)));
1774     
1775     Vector<WKStringRef> rawKeys(keys.size());
1776     Vector<WKTypeRef> rawValues(values.size());
1777     
1778     for (size_t i = 0; i < keys.size(); ++i) {
1779         rawKeys[i] = keys[i].get();
1780         rawValues[i] = values[i].get();
1781     }
1782     
1783     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetStatisticsSubresourceUniqueRedirectTo"));
1784     WKRetainPtr<WKDictionaryRef> messageBody = adoptWK(WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1785     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1786 }
1787
1788
1789 void TestRunner::setStatisticsSubresourceUniqueRedirectFrom(JSStringRef hostName, JSStringRef hostNameRedirectedFrom)
1790 {
1791     Vector<WKRetainPtr<WKStringRef>> keys;
1792     Vector<WKRetainPtr<WKTypeRef>> values;
1793     
1794     keys.append(adoptWK(WKStringCreateWithUTF8CString("HostName")));
1795     values.append(adoptWK(WKStringCreateWithJSString(hostName)));
1796     
1797     keys.append(adoptWK(WKStringCreateWithUTF8CString("HostNameRedirectedFrom")));
1798     values.append(adoptWK(WKStringCreateWithJSString(hostNameRedirectedFrom)));
1799     
1800     Vector<WKStringRef> rawKeys(keys.size());
1801     Vector<WKTypeRef> rawValues(values.size());
1802     
1803     for (size_t i = 0; i < keys.size(); ++i) {
1804         rawKeys[i] = keys[i].get();
1805         rawValues[i] = values[i].get();
1806     }
1807     
1808     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetStatisticsSubresourceUniqueRedirectFrom"));
1809     WKRetainPtr<WKDictionaryRef> messageBody = adoptWK(WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1810     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1811 }
1812
1813 void TestRunner::setStatisticsTopFrameUniqueRedirectTo(JSStringRef hostName, JSStringRef hostNameRedirectedTo)
1814 {
1815     Vector<WKRetainPtr<WKStringRef>> keys;
1816     Vector<WKRetainPtr<WKTypeRef>> values;
1817     
1818     keys.append(adoptWK(WKStringCreateWithUTF8CString("HostName")));
1819     values.append(adoptWK(WKStringCreateWithJSString(hostName)));
1820     
1821     keys.append(adoptWK(WKStringCreateWithUTF8CString("HostNameRedirectedTo")));
1822     values.append(adoptWK(WKStringCreateWithJSString(hostNameRedirectedTo)));
1823     
1824     Vector<WKStringRef> rawKeys(keys.size());
1825     Vector<WKTypeRef> rawValues(values.size());
1826     
1827     for (size_t i = 0; i < keys.size(); ++i) {
1828         rawKeys[i] = keys[i].get();
1829         rawValues[i] = values[i].get();
1830     }
1831     
1832     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetStatisticsTopFrameUniqueRedirectTo"));
1833     WKRetainPtr<WKDictionaryRef> messageBody = adoptWK(WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1834     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1835 }
1836
1837 void TestRunner::setStatisticsTopFrameUniqueRedirectFrom(JSStringRef hostName, JSStringRef hostNameRedirectedFrom)
1838 {
1839     Vector<WKRetainPtr<WKStringRef>> keys;
1840     Vector<WKRetainPtr<WKTypeRef>> values;
1841     
1842     keys.append(adoptWK(WKStringCreateWithUTF8CString("HostName")));
1843     values.append(adoptWK(WKStringCreateWithJSString(hostName)));
1844     
1845     keys.append(adoptWK(WKStringCreateWithUTF8CString("HostNameRedirectedFrom")));
1846     values.append(adoptWK(WKStringCreateWithJSString(hostNameRedirectedFrom)));
1847     
1848     Vector<WKStringRef> rawKeys(keys.size());
1849     Vector<WKTypeRef> rawValues(values.size());
1850     
1851     for (size_t i = 0; i < keys.size(); ++i) {
1852         rawKeys[i] = keys[i].get();
1853         rawValues[i] = values[i].get();
1854     }
1855     
1856     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetStatisticsTopFrameUniqueRedirectFrom"));
1857     WKRetainPtr<WKDictionaryRef> messageBody = adoptWK(WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1858     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1859 }
1860
1861 void TestRunner::setStatisticsCrossSiteLoadWithLinkDecoration(JSStringRef fromHost, JSStringRef toHost)
1862 {
1863     Vector<WKRetainPtr<WKStringRef>> keys;
1864     Vector<WKRetainPtr<WKTypeRef>> values;
1865     
1866     keys.append(adoptWK(WKStringCreateWithUTF8CString("FromHost")));
1867     values.append(adoptWK(WKStringCreateWithJSString(fromHost)));
1868     
1869     keys.append(adoptWK(WKStringCreateWithUTF8CString("ToHost")));
1870     values.append(adoptWK(WKStringCreateWithJSString(toHost)));
1871     
1872     Vector<WKStringRef> rawKeys(keys.size());
1873     Vector<WKTypeRef> rawValues(values.size());
1874     
1875     for (size_t i = 0; i < keys.size(); ++i) {
1876         rawKeys[i] = keys[i].get();
1877         rawValues[i] = values[i].get();
1878     }
1879     
1880     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetStatisticsCrossSiteLoadWithLinkDecoration"));
1881     WKRetainPtr<WKDictionaryRef> messageBody = adoptWK(WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1882     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1883 }
1884
1885 void TestRunner::setStatisticsTimeToLiveUserInteraction(double seconds)
1886 {
1887     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetStatisticsTimeToLiveUserInteraction"));
1888     WKRetainPtr<WKDoubleRef> messageBody = adoptWK(WKDoubleCreate(seconds));
1889     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1890 }
1891
1892 void TestRunner::installStatisticsDidModifyDataRecordsCallback(JSValueRef callback)
1893 {
1894     cacheTestRunnerCallback(StatisticsDidModifyDataRecordsCallbackID, callback);
1895 }
1896
1897 void TestRunner::statisticsDidModifyDataRecordsCallback()
1898 {
1899     callTestRunnerCallback(StatisticsDidModifyDataRecordsCallbackID);
1900 }
1901
1902 void TestRunner::installStatisticsDidScanDataRecordsCallback(JSValueRef callback)
1903 {
1904     cacheTestRunnerCallback(StatisticsDidScanDataRecordsCallbackID, callback);
1905
1906     bool notifyPagesWhenDataRecordsWereScanned = !!callback;
1907
1908     // Setting a callback implies we expect to receive callbacks. So register for them.
1909     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("StatisticsNotifyPagesWhenDataRecordsWereScanned"));
1910     WKRetainPtr<WKBooleanRef> messageBody = adoptWK(WKBooleanCreate(notifyPagesWhenDataRecordsWereScanned));
1911     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1912 }
1913
1914 void TestRunner::statisticsDidScanDataRecordsCallback()
1915 {
1916     callTestRunnerCallback(StatisticsDidScanDataRecordsCallbackID);
1917 }
1918
1919 void TestRunner::installStatisticsDidRunTelemetryCallback(JSValueRef callback)
1920 {
1921     cacheTestRunnerCallback(StatisticsDidRunTelemetryCallbackID, callback);
1922 }
1923     
1924 void TestRunner::statisticsDidRunTelemetryCallback(unsigned totalPrevalentResources, unsigned totalPrevalentResourcesWithUserInteraction, unsigned top3SubframeUnderTopFrameOrigins)
1925 {
1926     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
1927     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
1928     
1929     String string = makeString("{ \"totalPrevalentResources\" : ", totalPrevalentResources, ", \"totalPrevalentResourcesWithUserInteraction\" : ", totalPrevalentResourcesWithUserInteraction, ", \"top3SubframeUnderTopFrameOrigins\" : ", top3SubframeUnderTopFrameOrigins, " }");
1930     
1931     JSValueRef result = JSValueMakeFromJSONString(context, adopt(JSStringCreateWithUTF8CString(string.utf8().data())).get());
1932
1933     callTestRunnerCallback(StatisticsDidRunTelemetryCallbackID, 1, &result);
1934 }
1935
1936 bool TestRunner::statisticsNotifyObserver()
1937 {
1938     return InjectedBundle::singleton().statisticsNotifyObserver();
1939 }
1940
1941 void TestRunner::statisticsProcessStatisticsAndDataRecords()
1942 {
1943     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("StatisticsProcessStatisticsAndDataRecords"));
1944     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), nullptr, nullptr);
1945 }
1946
1947 void TestRunner::statisticsUpdateCookieBlocking(JSValueRef completionHandler)
1948 {
1949     cacheTestRunnerCallback(StatisticsDidSetBlockCookiesForHostCallbackID, completionHandler);
1950
1951     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("StatisticsUpdateCookieBlocking"));
1952     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), nullptr, nullptr);
1953 }
1954
1955 void TestRunner::statisticsCallDidSetBlockCookiesForHostCallback()
1956 {
1957     callTestRunnerCallback(StatisticsDidSetBlockCookiesForHostCallbackID);
1958 }
1959
1960 void TestRunner::statisticsSubmitTelemetry()
1961 {
1962     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("StatisticsSubmitTelemetry"));
1963     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), nullptr, nullptr);
1964 }
1965
1966 void TestRunner::setStatisticsNotifyPagesWhenDataRecordsWereScanned(bool value)
1967 {
1968     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("StatisticsNotifyPagesWhenDataRecordsWereScanned"));
1969     WKRetainPtr<WKBooleanRef> messageBody = adoptWK(WKBooleanCreate(value));
1970     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1971 }
1972
1973 void TestRunner::setStatisticsIsRunningTest(bool value)
1974 {
1975     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("StatisticsSetIsRunningTest"));
1976     WKRetainPtr<WKBooleanRef> messageBody = adoptWK(WKBooleanCreate(value));
1977     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1978 }
1979
1980 void TestRunner::setStatisticsShouldClassifyResourcesBeforeDataRecordsRemoval(bool value)
1981 {
1982     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("StatisticsShouldClassifyResourcesBeforeDataRecordsRemoval"));
1983     WKRetainPtr<WKBooleanRef> messageBody = adoptWK(WKBooleanCreate(value));
1984     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1985 }
1986
1987 void TestRunner::setStatisticsNotifyPagesWhenTelemetryWasCaptured(bool value)
1988 {
1989     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("StatisticsNotifyPagesWhenTelemetryWasCaptured"));
1990     WKRetainPtr<WKBooleanRef> messageBody = adoptWK(WKBooleanCreate(value));
1991     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1992 }
1993
1994 void TestRunner::setStatisticsMinimumTimeBetweenDataRecordsRemoval(double seconds)
1995 {
1996     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetStatisticsMinimumTimeBetweenDataRecordsRemoval"));
1997     WKRetainPtr<WKDoubleRef> messageBody = adoptWK(WKDoubleCreate(seconds));
1998     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1999 }
2000
2001 void TestRunner::setStatisticsGrandfatheringTime(double seconds)
2002 {
2003     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetStatisticsGrandfatheringTime"));
2004     WKRetainPtr<WKDoubleRef> messageBody = adoptWK(WKDoubleCreate(seconds));
2005     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
2006 }
2007
2008 void TestRunner::setStatisticsMaxStatisticsEntries(unsigned entries)
2009 {
2010     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetMaxStatisticsEntries"));
2011     WKRetainPtr<WKTypeRef> messageBody = adoptWK(WKUInt64Create(entries));
2012     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
2013 }
2014     
2015 void TestRunner::setStatisticsPruneEntriesDownTo(unsigned entries)
2016 {
2017     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetPruneEntriesDownTo"));
2018     WKRetainPtr<WKTypeRef> messageBody = adoptWK(WKUInt64Create(entries));
2019     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
2020 }
2021     
2022 void TestRunner::statisticsClearInMemoryAndPersistentStore(JSValueRef callback)
2023 {
2024     cacheTestRunnerCallback(StatisticsDidClearThroughWebsiteDataRemovalCallbackID, callback);
2025
2026     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("StatisticsClearInMemoryAndPersistentStore"));
2027     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), nullptr, nullptr);
2028 }
2029
2030 void TestRunner::statisticsClearInMemoryAndPersistentStoreModifiedSinceHours(unsigned hours, JSValueRef callback)
2031 {
2032     cacheTestRunnerCallback(StatisticsDidClearThroughWebsiteDataRemovalCallbackID, callback);
2033
2034     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("StatisticsClearInMemoryAndPersistentStoreModifiedSinceHours"));
2035     WKRetainPtr<WKTypeRef> messageBody = adoptWK(WKUInt64Create(hours));
2036     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
2037 }
2038
2039 void TestRunner::statisticsClearThroughWebsiteDataRemoval(JSValueRef callback)
2040 {
2041     cacheTestRunnerCallback(StatisticsDidClearThroughWebsiteDataRemovalCallbackID, callback);
2042     
2043     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("StatisticsClearThroughWebsiteDataRemoval"));
2044     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), nullptr, nullptr);
2045 }
2046
2047 void TestRunner::statisticsDeleteCookiesForHost(JSStringRef hostName, bool includeHttpOnlyCookies)
2048 {
2049     Vector<WKRetainPtr<WKStringRef>> keys;
2050     Vector<WKRetainPtr<WKTypeRef>> values;
2051
2052     keys.append(adoptWK(WKStringCreateWithUTF8CString("HostName")));
2053     values.append(adoptWK(WKStringCreateWithJSString(hostName)));
2054
2055     keys.append(adoptWK(WKStringCreateWithUTF8CString("IncludeHttpOnlyCookies")));
2056     values.append(adoptWK(WKBooleanCreate(includeHttpOnlyCookies)));
2057
2058     Vector<WKStringRef> rawKeys;
2059     Vector<WKTypeRef> rawValues;
2060     rawKeys.resize(keys.size());
2061     rawValues.resize(values.size());
2062
2063     for (size_t i = 0; i < keys.size(); ++i) {
2064         rawKeys[i] = keys[i].get();
2065         rawValues[i] = values[i].get();
2066     }
2067
2068     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("StatisticsDeleteCookiesForHost"));
2069     WKRetainPtr<WKDictionaryRef> messageBody = adoptWK(WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
2070     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
2071 }
2072
2073 bool TestRunner::isStatisticsHasLocalStorage(JSStringRef hostName)
2074 {
2075     auto messageName = adoptWK(WKStringCreateWithUTF8CString("IsStatisticsHasLocalStorage"));
2076     auto messageBody = adoptWK(WKStringCreateWithJSString(hostName));
2077     WKTypeRef returnData = nullptr;
2078     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get(), &returnData);
2079     ASSERT(WKGetTypeID(returnData) == WKBooleanGetTypeID());
2080     return WKBooleanGetValue(adoptWK(static_cast<WKBooleanRef>(returnData)).get());
2081 }
2082
2083 void TestRunner::setStatisticsCacheMaxAgeCap(double seconds)
2084 {
2085     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetStatisticsCacheMaxAgeCap"));
2086     WKRetainPtr<WKDoubleRef> messageBody = adoptWK(WKDoubleCreate(seconds));
2087     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
2088 }
2089
2090 bool TestRunner::hasStatisticsIsolatedSession(JSStringRef hostName)
2091 {
2092     auto messageName = adoptWK(WKStringCreateWithUTF8CString("HasStatisticsIsolatedSession"));
2093     auto messageBody = adoptWK(WKStringCreateWithJSString(hostName));
2094     WKTypeRef returnData = nullptr;
2095     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get(), &returnData);
2096     ASSERT(WKGetTypeID(returnData) == WKBooleanGetTypeID());
2097     return WKBooleanGetValue(adoptWK(static_cast<WKBooleanRef>(returnData)).get());
2098 }
2099
2100 void TestRunner::statisticsCallClearThroughWebsiteDataRemovalCallback()
2101 {
2102     callTestRunnerCallback(StatisticsDidClearThroughWebsiteDataRemovalCallbackID);
2103 }
2104
2105 void TestRunner::statisticsResetToConsistentState(JSValueRef completionHandler)
2106 {
2107     cacheTestRunnerCallback(StatisticsDidResetToConsistentStateCallbackID, completionHandler);
2108     
2109     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("StatisticsResetToConsistentState"));
2110     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), nullptr, nullptr);
2111 }
2112
2113 void TestRunner::statisticsCallDidResetToConsistentStateCallback()
2114 {
2115     callTestRunnerCallback(StatisticsDidResetToConsistentStateCallbackID);
2116 }
2117
2118 void TestRunner::installTextDidChangeInTextFieldCallback(JSValueRef callback)
2119 {
2120     cacheTestRunnerCallback(TextDidChangeInTextFieldCallbackID, callback);
2121 }
2122
2123 void TestRunner::textDidChangeInTextFieldCallback()
2124 {
2125     callTestRunnerCallback(TextDidChangeInTextFieldCallbackID);
2126 }
2127
2128 void TestRunner::installTextFieldDidBeginEditingCallback(JSValueRef callback)
2129 {
2130     cacheTestRunnerCallback(TextFieldDidBeginEditingCallbackID, callback);
2131 }
2132
2133 void TestRunner::textFieldDidBeginEditingCallback()
2134 {
2135     callTestRunnerCallback(TextFieldDidBeginEditingCallbackID);
2136 }
2137
2138 void TestRunner::installTextFieldDidEndEditingCallback(JSValueRef callback)
2139 {
2140     cacheTestRunnerCallback(TextFieldDidEndEditingCallbackID, callback);
2141 }
2142
2143 void TestRunner::textFieldDidEndEditingCallback()
2144 {
2145     callTestRunnerCallback(TextFieldDidEndEditingCallbackID);
2146 }
2147
2148 void TestRunner::setStorageAccessAPIEnabled(bool enabled)
2149 {
2150     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetStorageAccessAPIEnabled"));
2151     
2152     WKRetainPtr<WKBooleanRef> messageBody = adoptWK(WKBooleanCreate(enabled));
2153     
2154     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
2155 }
2156
2157 void TestRunner::getAllStorageAccessEntries(JSValueRef callback)
2158 {
2159     cacheTestRunnerCallback(AllStorageAccessEntriesCallbackID, callback);
2160     
2161     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("GetAllStorageAccessEntries"));
2162     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), nullptr, nullptr);
2163 }
2164
2165 void TestRunner::callDidReceiveAllStorageAccessEntriesCallback(Vector<String>& domains)
2166 {
2167     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
2168     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
2169     
2170     StringBuilder stringBuilder;
2171     stringBuilder.appendLiteral("[");
2172     bool firstDomain = true;
2173     for (auto& domain : domains) {
2174         if (firstDomain)
2175             firstDomain = false;
2176         else
2177             stringBuilder.appendLiteral(", ");
2178         stringBuilder.appendLiteral("\"");
2179         stringBuilder.append(domain);
2180         stringBuilder.appendLiteral("\"");
2181     }
2182     stringBuilder.appendLiteral("]");
2183     
2184     JSValueRef result = JSValueMakeFromJSONString(context, adopt(JSStringCreateWithUTF8CString(stringBuilder.toString().utf8().data())).get());
2185
2186     callTestRunnerCallback(AllStorageAccessEntriesCallbackID, 1, &result);
2187 }
2188
2189 void TestRunner::addMockMediaDevice(JSStringRef persistentId, JSStringRef label, const char* type)
2190 {
2191     Vector<WKRetainPtr<WKStringRef>> keys;
2192     Vector<WKRetainPtr<WKTypeRef>> values;
2193
2194     keys.append(adoptWK(WKStringCreateWithUTF8CString("PersistentID")));
2195     values.append(toWK(persistentId));
2196
2197     keys.append(adoptWK(WKStringCreateWithUTF8CString("Label")));
2198     values.append(toWK(label));
2199
2200     keys.append(adoptWK(WKStringCreateWithUTF8CString("Type")));
2201     values.append(adoptWK(WKStringCreateWithUTF8CString(type)));
2202
2203     Vector<WKStringRef> rawKeys;
2204     Vector<WKTypeRef> rawValues;
2205     rawKeys.resize(keys.size());
2206     rawValues.resize(values.size());
2207
2208     for (size_t i = 0; i < keys.size(); ++i) {
2209         rawKeys[i] = keys[i].get();
2210         rawValues[i] = values[i].get();
2211     }
2212
2213     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("AddMockMediaDevice"));
2214     WKRetainPtr<WKDictionaryRef> messageBody = adoptWK(WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
2215
2216     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
2217 }
2218
2219 void TestRunner::addMockCameraDevice(JSStringRef persistentId, JSStringRef label)
2220 {
2221     addMockMediaDevice(persistentId, label, "camera");
2222 }
2223
2224 void TestRunner::addMockMicrophoneDevice(JSStringRef persistentId, JSStringRef label)
2225 {
2226     addMockMediaDevice(persistentId, label, "microphone");
2227 }
2228
2229 void TestRunner::addMockScreenDevice(JSStringRef persistentId, JSStringRef label)
2230 {
2231     addMockMediaDevice(persistentId, label, "screen");
2232 }
2233
2234 void TestRunner::clearMockMediaDevices()
2235 {
2236     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("ClearMockMediaDevices"));
2237     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), nullptr, nullptr);
2238 }
2239
2240 void TestRunner::removeMockMediaDevice(JSStringRef persistentId)
2241 {
2242     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("RemoveMockMediaDevice"));
2243     WKRetainPtr<WKTypeRef> messageBody(toWK(persistentId));
2244
2245     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
2246 }
2247
2248 void TestRunner::resetMockMediaDevices()
2249 {
2250     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("ResetMockMediaDevices"));
2251     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), nullptr, nullptr);
2252 }
2253
2254 #if PLATFORM(MAC)
2255 void TestRunner::connectMockGamepad(unsigned index)
2256 {
2257     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("ConnectMockGamepad"));
2258     WKRetainPtr<WKTypeRef> messageBody = adoptWK(WKUInt64Create(index));
2259
2260     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
2261 }
2262
2263 void TestRunner::disconnectMockGamepad(unsigned index)
2264 {
2265     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("DisconnectMockGamepad"));
2266     WKRetainPtr<WKTypeRef> messageBody = adoptWK(WKUInt64Create(index));
2267
2268     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
2269 }
2270
2271 void TestRunner::setMockGamepadDetails(unsigned index, JSStringRef gamepadID, unsigned axisCount, unsigned buttonCount)
2272 {
2273     Vector<WKRetainPtr<WKStringRef>> keys;
2274     Vector<WKRetainPtr<WKTypeRef>> values;
2275
2276     keys.append(adoptWK(WKStringCreateWithUTF8CString("GamepadID")));
2277     values.append(toWK(gamepadID));
2278
2279     keys.append(adoptWK(WKStringCreateWithUTF8CString("GamepadIndex")));
2280     values.append(adoptWK(WKUInt64Create(index)));
2281
2282     keys.append(adoptWK(WKStringCreateWithUTF8CString("AxisCount")));
2283     values.append(adoptWK(WKUInt64Create(axisCount)));
2284
2285     keys.append(adoptWK(WKStringCreateWithUTF8CString("ButtonCount")));
2286     values.append(adoptWK(WKUInt64Create(buttonCount)));
2287
2288     Vector<WKStringRef> rawKeys;
2289     Vector<WKTypeRef> rawValues;
2290     rawKeys.resize(keys.size());
2291     rawValues.resize(values.size());
2292
2293     for (size_t i = 0; i < keys.size(); ++i) {
2294         rawKeys[i] = keys[i].get();
2295         rawValues[i] = values[i].get();
2296     }
2297
2298     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetMockGamepadDetails"));
2299     WKRetainPtr<WKDictionaryRef> messageBody = adoptWK(WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
2300
2301     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
2302 }
2303
2304 void TestRunner::setMockGamepadAxisValue(unsigned index, unsigned axisIndex, double value)
2305 {
2306     Vector<WKRetainPtr<WKStringRef>> keys;
2307     Vector<WKRetainPtr<WKTypeRef>> values;
2308
2309     keys.append(adoptWK(WKStringCreateWithUTF8CString("GamepadIndex")));
2310     values.append(adoptWK(WKUInt64Create(index)));
2311
2312     keys.append(adoptWK(WKStringCreateWithUTF8CString("AxisIndex")));
2313     values.append(adoptWK(WKUInt64Create(axisIndex)));
2314
2315     keys.append(adoptWK(WKStringCreateWithUTF8CString("Value")));
2316     values.append(adoptWK(WKDoubleCreate(value)));
2317
2318     Vector<WKStringRef> rawKeys;
2319     Vector<WKTypeRef> rawValues;
2320     rawKeys.resize(keys.size());
2321     rawValues.resize(values.size());
2322
2323     for (size_t i = 0; i < keys.size(); ++i) {
2324         rawKeys[i] = keys[i].get();
2325         rawValues[i] = values[i].get();
2326     }
2327
2328     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetMockGamepadAxisValue"));
2329     WKRetainPtr<WKDictionaryRef> messageBody = adoptWK(WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
2330
2331     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
2332 }
2333
2334 void TestRunner::setMockGamepadButtonValue(unsigned index, unsigned buttonIndex, double value)
2335 {
2336     Vector<WKRetainPtr<WKStringRef>> keys;
2337     Vector<WKRetainPtr<WKTypeRef>> values;
2338
2339     keys.append(adoptWK(WKStringCreateWithUTF8CString("GamepadIndex")));
2340     values.append(adoptWK(WKUInt64Create(index)));
2341
2342     keys.append(adoptWK(WKStringCreateWithUTF8CString("ButtonIndex")));
2343     values.append(adoptWK(WKUInt64Create(buttonIndex)));
2344
2345     keys.append(adoptWK(WKStringCreateWithUTF8CString("Value")));
2346     values.append(adoptWK(WKDoubleCreate(value)));
2347
2348     Vector<WKStringRef> rawKeys;
2349     Vector<WKTypeRef> rawValues;
2350     rawKeys.resize(keys.size());
2351     rawValues.resize(values.size());
2352
2353     for (size_t i = 0; i < keys.size(); ++i) {
2354         rawKeys[i] = keys[i].get();
2355         rawValues[i] = values[i].get();
2356     }
2357
2358     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetMockGamepadButtonValue"));
2359     WKRetainPtr<WKDictionaryRef> messageBody = adoptWK(WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
2360
2361     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
2362 }
2363 #else
2364 void TestRunner::connectMockGamepad(unsigned)
2365 {
2366 }
2367
2368 void TestRunner::disconnectMockGamepad(unsigned)
2369 {
2370 }
2371
2372 void TestRunner::setMockGamepadDetails(unsigned, JSStringRef, unsigned, unsigned)
2373 {
2374 }
2375
2376 void TestRunner::setMockGamepadAxisValue(unsigned, unsigned, double)
2377 {
2378 }
2379
2380 void TestRunner::setMockGamepadButtonValue(unsigned, unsigned, double)
2381 {
2382 }
2383 #endif // PLATFORM(MAC)
2384
2385 void TestRunner::setOpenPanelFiles(JSValueRef filesValue)
2386 {
2387     WKBundlePageRef page = InjectedBundle::singleton().page()->page();
2388     JSContextRef context = WKBundleFrameGetJavaScriptContext(WKBundlePageGetMainFrame(page));
2389
2390     if (!JSValueIsArray(context, filesValue))
2391         return;
2392
2393     JSObjectRef files = JSValueToObject(context, filesValue, nullptr);
2394     static auto lengthProperty = adopt(JSStringCreateWithUTF8CString("length"));
2395     JSValueRef filesLengthValue = JSObjectGetProperty(context, files, lengthProperty.get(), nullptr);
2396     if (!JSValueIsNumber(context, filesLengthValue))
2397         return;
2398
2399     auto fileURLs = adoptWK(WKMutableArrayCreate());
2400     auto filesLength = static_cast<size_t>(JSValueToNumber(context, filesLengthValue, nullptr));
2401     for (size_t i = 0; i < filesLength; ++i) {
2402         JSValueRef fileValue = JSObjectGetPropertyAtIndex(context, files, i, nullptr);
2403         if (!JSValueIsString(context, fileValue))
2404             continue;
2405
2406         auto file = adopt(JSValueToStringCopy(context, fileValue, nullptr));
2407         size_t fileBufferSize = JSStringGetMaximumUTF8CStringSize(file.get()) + 1;
2408         auto fileBuffer = makeUniqueArray<char>(fileBufferSize);
2409         JSStringGetUTF8CString(file.get(), fileBuffer.get(), fileBufferSize);
2410
2411         WKArrayAppendItem(fileURLs.get(), adoptWK(WKURLCreateWithBaseURL(m_testURL.get(), fileBuffer.get())).get());
2412     }
2413
2414     static auto messageName = adoptWK(WKStringCreateWithUTF8CString("SetOpenPanelFileURLs"));
2415     WKBundlePagePostMessage(page, messageName.get(), fileURLs.get());
2416 }
2417
2418 #if PLATFORM(IOS_FAMILY)
2419 void TestRunner::setOpenPanelFilesMediaIcon(JSValueRef data)
2420 {
2421     WKBundlePageRef page = InjectedBundle::singleton().page()->page();
2422     JSContextRef context = WKBundleFrameGetJavaScriptContext(WKBundlePageGetMainFrame(page));
2423
2424     auto& injectedBundle = InjectedBundle::singleton();
2425     // FIXME (123058): Use a JSC API to get buffer contents once such is exposed.
2426     WKRetainPtr<WKDataRef> iconData = adoptWK(WKBundleCreateWKDataFromUInt8Array(injectedBundle.bundle(), context, data));
2427
2428     static auto messageName = adoptWK(WKStringCreateWithUTF8CString("SetOpenPanelFileURLsMediaIcon"));
2429     WKBundlePagePostMessage(page, messageName.get(), iconData.get());
2430 }
2431 #else
2432 void TestRunner::setOpenPanelFilesMediaIcon(JSValueRef)
2433 {
2434 }
2435 #endif // PLATFORM(IOS_FAMILY)
2436
2437 void TestRunner::removeAllSessionCredentials(JSValueRef callback)
2438 {
2439     cacheTestRunnerCallback(DidRemoveAllSessionCredentialsCallbackID, callback);
2440     
2441     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("RemoveAllSessionCredentials"));
2442     WKRetainPtr<WKBooleanRef> messageBody = adoptWK(WKBooleanCreate(true));
2443     
2444     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
2445 }
2446
2447 void TestRunner::callDidRemoveAllSessionCredentialsCallback()
2448 {
2449     callTestRunnerCallback(DidRemoveAllSessionCredentialsCallbackID);
2450 }
2451
2452 void TestRunner::clearDOMCache(JSStringRef origin)
2453 {
2454     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("ClearDOMCache"));
2455     WKRetainPtr<WKStringRef> messageBody = adoptWK(WKStringCreateWithJSString(origin));
2456     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
2457 }
2458
2459 void TestRunner::clearDOMCaches()
2460 {
2461     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("ClearDOMCaches"));
2462     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), nullptr, nullptr);
2463 }
2464
2465 bool TestRunner::hasDOMCache(JSStringRef origin)
2466 {
2467     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("HasDOMCache"));
2468     WKRetainPtr<WKStringRef> messageBody = adoptWK(WKStringCreateWithJSString(origin));
2469     WKTypeRef returnData = nullptr;
2470     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get(), &returnData);
2471     ASSERT(WKGetTypeID(returnData) == WKBooleanGetTypeID());
2472     return WKBooleanGetValue(adoptWK(static_cast<WKBooleanRef>(returnData)).get());
2473 }
2474
2475 uint64_t TestRunner::domCacheSize(JSStringRef origin)
2476 {
2477     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("DOMCacheSize"));
2478     WKRetainPtr<WKStringRef> messageBody = adoptWK(WKStringCreateWithJSString(origin));
2479     WKTypeRef returnData = nullptr;
2480     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get(), &returnData);
2481     return WKUInt64GetValue(static_cast<WKUInt64Ref>(returnData));
2482 }
2483
2484 void TestRunner::setAllowStorageQuotaIncrease(bool willIncrease)
2485 {
2486     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetAllowStorageQuotaIncrease"));
2487     WKRetainPtr<WKBooleanRef> messageBody = adoptWK(WKBooleanCreate(willIncrease));
2488     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
2489 }
2490
2491 void TestRunner::getApplicationManifestThen(JSValueRef callback)
2492 {
2493     cacheTestRunnerCallback(GetApplicationManifestCallbackID, callback);
2494     
2495     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("GetApplicationManifest"));
2496     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), nullptr, nullptr);
2497 }
2498
2499 void TestRunner::didGetApplicationManifest()
2500 {
2501     callTestRunnerCallback(GetApplicationManifestCallbackID);
2502 }
2503
2504 void TestRunner::performCustomMenuAction()
2505 {
2506     callTestRunnerCallback(CustomMenuActionCallbackID);
2507 }
2508
2509 size_t TestRunner::userScriptInjectedCount() const
2510 {
2511     return InjectedBundle::singleton().userScriptInjectedCount();
2512 }
2513
2514 void TestRunner::injectUserScript(JSStringRef script)
2515 {
2516     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("InjectUserScript"));
2517     WKRetainPtr<WKStringRef> messageBody = adoptWK(WKStringCreateWithJSString(script));
2518     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get(), nullptr);
2519 }
2520
2521 void TestRunner::sendDisplayConfigurationChangedMessageForTesting()
2522 {
2523     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SendDisplayConfigurationChangedMessageForTesting"));
2524     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), nullptr, nullptr);
2525 }
2526
2527 // WebAuthN
2528 void TestRunner::setWebAuthenticationMockConfiguration(JSValueRef configurationValue)
2529 {
2530     auto& injectedBundle = InjectedBundle::singleton();
2531     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(injectedBundle.page()->page());
2532     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
2533     if (!JSValueIsObject(context, configurationValue))
2534         return;
2535     JSObjectRef configuration = JSValueToObject(context, configurationValue, 0);
2536
2537     Vector<WKRetainPtr<WKStringRef>> configurationKeys;
2538     Vector<WKRetainPtr<WKTypeRef>> configurationValues;
2539
2540     JSRetainPtr<JSStringRef> silentFailurePropertyName(Adopt, JSStringCreateWithUTF8CString("silentFailure"));
2541     JSValueRef silentFailureValue = JSObjectGetProperty(context, configuration, silentFailurePropertyName.get(), 0);
2542     if (!JSValueIsUndefined(context, silentFailureValue)) {
2543         if (!JSValueIsBoolean(context, silentFailureValue))
2544             return;
2545         bool silentFailure = JSValueToBoolean(context, silentFailureValue);
2546         configurationKeys.append(adoptWK(WKStringCreateWithUTF8CString("SilentFailure")));
2547         configurationValues.append(adoptWK(WKBooleanCreate(silentFailure)).get());
2548     }
2549
2550     JSRetainPtr<JSStringRef> localPropertyName(Adopt, JSStringCreateWithUTF8CString("local"));
2551     JSValueRef localValue = JSObjectGetProperty(context, configuration, localPropertyName.get(), 0);
2552     if (!JSValueIsUndefined(context, localValue) && !JSValueIsNull(context, localValue)) {
2553         if (!JSValueIsObject(context, localValue))
2554             return;
2555         JSObjectRef local = JSValueToObject(context, localValue, 0);
2556
2557         JSRetainPtr<JSStringRef> acceptAuthenticationPropertyName(Adopt, JSStringCreateWithUTF8CString("acceptAuthentication"));
2558         JSValueRef acceptAuthenticationValue = JSObjectGetProperty(context, local, acceptAuthenticationPropertyName.get(), 0);
2559         if (!JSValueIsBoolean(context, acceptAuthenticationValue))
2560             return;
2561         bool acceptAuthentication = JSValueToBoolean(context, acceptAuthenticationValue);
2562
2563         JSRetainPtr<JSStringRef> acceptAttestationPropertyName(Adopt, JSStringCreateWithUTF8CString("acceptAttestation"));
2564         JSValueRef acceptAttestationValue = JSObjectGetProperty(context, local, acceptAttestationPropertyName.get(), 0);
2565         if (!JSValueIsBoolean(context, acceptAttestationValue))
2566             return;
2567         bool acceptAttestation = JSValueToBoolean(context, acceptAttestationValue);
2568
2569         Vector<WKRetainPtr<WKStringRef>> localKeys;
2570         Vector<WKRetainPtr<WKTypeRef>> localValues;
2571         localKeys.append(adoptWK(WKStringCreateWithUTF8CString("AcceptAuthentication")));
2572         localValues.append(adoptWK(WKBooleanCreate(acceptAuthentication)).get());
2573         localKeys.append(adoptWK(WKStringCreateWithUTF8CString("AcceptAttestation")));
2574         localValues.append(adoptWK(WKBooleanCreate(acceptAttestation)).get());
2575
2576         if (acceptAttestation) {
2577             JSRetainPtr<JSStringRef> privateKeyBase64PropertyName(Adopt, JSStringCreateWithUTF8CString("privateKeyBase64"));
2578             JSValueRef privateKeyBase64Value = JSObjectGetProperty(context, local, privateKeyBase64PropertyName.get(), 0);
2579             if (!JSValueIsString(context, privateKeyBase64Value))
2580                 return;
2581
2582             JSRetainPtr<JSStringRef> userCertificateBase64PropertyName(Adopt, JSStringCreateWithUTF8CString("userCertificateBase64"));
2583             JSValueRef userCertificateBase64Value = JSObjectGetProperty(context, local, userCertificateBase64PropertyName.get(), 0);
2584             if (!JSValueIsString(context, userCertificateBase64Value))
2585                 return;
2586
2587             JSRetainPtr<JSStringRef> intermediateCACertificateBase64PropertyName(Adopt, JSStringCreateWithUTF8CString("intermediateCACertificateBase64"));
2588             JSValueRef intermediateCACertificateBase64Value = JSObjectGetProperty(context, local, intermediateCACertificateBase64PropertyName.get(), 0);
2589             if (!JSValueIsString(context, intermediateCACertificateBase64Value))
2590                 return;
2591
2592             localKeys.append(adoptWK(WKStringCreateWithUTF8CString("PrivateKeyBase64")));
2593             localValues.append(toWK(adopt(JSValueToStringCopy(context, privateKeyBase64Value, 0)).get()));
2594             localKeys.append(adoptWK(WKStringCreateWithUTF8CString("UserCertificateBase64")));
2595             localValues.append(toWK(adopt(JSValueToStringCopy(context, userCertificateBase64Value, 0)).get()));
2596             localKeys.append(adoptWK(WKStringCreateWithUTF8CString("IntermediateCACertificateBase64")));
2597             localValues.append(toWK(adopt(JSValueToStringCopy(context, intermediateCACertificateBase64Value, 0)).get()));
2598         }
2599
2600         JSRetainPtr<JSStringRef> preferredUserhandleBase64PropertyName(Adopt, JSStringCreateWithUTF8CString("preferredUserhandleBase64"));
2601         JSValueRef preferredUserhandleBase64Value = JSObjectGetProperty(context, local, preferredUserhandleBase64PropertyName.get(), 0);
2602         if (!JSValueIsUndefined(context, preferredUserhandleBase64Value) && !JSValueIsNull(context, preferredUserhandleBase64Value)) {
2603             if (!JSValueIsString(context, preferredUserhandleBase64Value))
2604                 return;
2605
2606             localKeys.append(adoptWK(WKStringCreateWithUTF8CString("PreferredUserhandleBase64")));
2607             localValues.append(toWK(adopt(JSValueToStringCopy(context, preferredUserhandleBase64Value, 0)).get()));
2608         }
2609
2610         Vector<WKStringRef> rawLocalKeys;
2611         Vector<WKTypeRef> rawLocalValues;
2612         rawLocalKeys.resize(localKeys.size());
2613         rawLocalValues.resize(localValues.size());
2614         for (size_t i = 0; i < localKeys.size(); ++i) {
2615             rawLocalKeys[i] = localKeys[i].get();
2616             rawLocalValues[i] = localValues[i].get();
2617         }
2618
2619         configurationKeys.append(adoptWK(WKStringCreateWithUTF8CString("Local")));
2620         configurationValues.append(adoptWK(WKDictionaryCreate(rawLocalKeys.data(), rawLocalValues.data(), rawLocalKeys.size())));
2621     }
2622
2623     JSRetainPtr<JSStringRef> hidPropertyName(Adopt, JSStringCreateWithUTF8CString("hid"));
2624     JSValueRef hidValue = JSObjectGetProperty(context, configuration, hidPropertyName.get(), 0);
2625     if (!JSValueIsUndefined(context, hidValue) && !JSValueIsNull(context, hidValue)) {
2626         if (!JSValueIsObject(context, hidValue))
2627             return;
2628         JSObjectRef hid = JSValueToObject(context, hidValue, 0);
2629
2630         JSRetainPtr<JSStringRef> stagePropertyName(Adopt, JSStringCreateWithUTF8CString("stage"));
2631         JSValueRef stageValue = JSObjectGetProperty(context, hid, stagePropertyName.get(), 0);
2632         if (!JSValueIsString(context, stageValue))
2633             return;
2634
2635         JSRetainPtr<JSStringRef> subStagePropertyName(Adopt, JSStringCreateWithUTF8CString("subStage"));
2636         JSValueRef subStageValue = JSObjectGetProperty(context, hid, subStagePropertyName.get(), 0);
2637         if (!JSValueIsString(context, subStageValue))
2638             return;
2639
2640         JSRetainPtr<JSStringRef> errorPropertyName(Adopt, JSStringCreateWithUTF8CString("error"));
2641         JSValueRef errorValue = JSObjectGetProperty(context, hid, errorPropertyName.get(), 0);
2642         if (!JSValueIsString(context, errorValue))
2643             return;
2644
2645         Vector<WKRetainPtr<WKStringRef>> hidKeys;
2646         Vector<WKRetainPtr<WKTypeRef>> hidValues;
2647         hidKeys.append(adoptWK(WKStringCreateWithUTF8CString("Stage")));
2648         hidValues.append(toWK(adopt(JSValueToStringCopy(context, stageValue, 0)).get()));
2649         hidKeys.append(adoptWK(WKStringCreateWithUTF8CString("SubStage")));
2650         hidValues.append(toWK(adopt(JSValueToStringCopy(context, subStageValue, 0)).get()));
2651         hidKeys.append(adoptWK(WKStringCreateWithUTF8CString("Error")));
2652         hidValues.append(toWK(adopt(JSValueToStringCopy(context, errorValue, 0)).get()));
2653
2654         JSRetainPtr<JSStringRef> payloadBase64PropertyName(Adopt, JSStringCreateWithUTF8CString("payloadBase64"));
2655         JSValueRef payloadBase64Value = JSObjectGetProperty(context, hid, payloadBase64PropertyName.get(), 0);
2656         if (!JSValueIsUndefined(context, payloadBase64Value) && !JSValueIsNull(context, payloadBase64Value)) {
2657             if (!JSValueIsArray(context, payloadBase64Value))
2658                 return;
2659
2660             JSObjectRef payloadBase64 = JSValueToObject(context, payloadBase64Value, nullptr);
2661             static auto lengthProperty = adopt(JSStringCreateWithUTF8CString("length"));
2662             JSValueRef payloadBase64LengthValue = JSObjectGetProperty(context, payloadBase64, lengthProperty.get(), nullptr);
2663             if (!JSValueIsNumber(context, payloadBase64LengthValue))
2664                 return;
2665
2666             auto payloadBase64s = adoptWK(WKMutableArrayCreate());
2667             auto payloadBase64Length = static_cast<size_t>(JSValueToNumber(context, payloadBase64LengthValue, nullptr));
2668             for (size_t i = 0; i < payloadBase64Length; ++i) {
2669                 JSValueRef payloadBase64Value = JSObjectGetPropertyAtIndex(context, payloadBase64, i, nullptr);
2670                 if (!JSValueIsString(context, payloadBase64Value))
2671                     continue;
2672                 WKArrayAppendItem(payloadBase64s.get(), toWK(adopt(JSValueToStringCopy(context, payloadBase64Value, 0)).get()).get());
2673             }
2674
2675             hidKeys.append(adoptWK(WKStringCreateWithUTF8CString("PayloadBase64")));
2676             hidValues.append(payloadBase64s);
2677         }
2678
2679         JSRetainPtr<JSStringRef> isU2fPropertyName(Adopt, JSStringCreateWithUTF8CString("isU2f"));
2680         JSValueRef isU2fValue = JSObjectGetProperty(context, hid, isU2fPropertyName.get(), 0);
2681         if (!JSValueIsUndefined(context, isU2fValue) && !JSValueIsNull(context, isU2fValue)) {
2682             if (!JSValueIsBoolean(context, isU2fValue))
2683                 return;
2684             bool isU2f = JSValueToBoolean(context, isU2fValue);
2685             hidKeys.append(adoptWK(WKStringCreateWithUTF8CString("IsU2f")));
2686             hidValues.append(adoptWK(WKBooleanCreate(isU2f)).get());
2687         }
2688
2689         JSRetainPtr<JSStringRef> keepAlivePropertyName(Adopt, JSStringCreateWithUTF8CString("keepAlive"));
2690         JSValueRef keepAliveValue = JSObjectGetProperty(context, hid, keepAlivePropertyName.get(), 0);
2691         if (!JSValueIsUndefined(context, keepAliveValue) && !JSValueIsNull(context, keepAliveValue)) {
2692             if (!JSValueIsBoolean(context, keepAliveValue))
2693                 return;
2694             bool keepAlive = JSValueToBoolean(context, keepAliveValue);
2695             hidKeys.append(adoptWK(WKStringCreateWithUTF8CString("KeepAlive")));
2696             hidValues.append(adoptWK(WKBooleanCreate(keepAlive)).get());
2697         }
2698
2699         JSRetainPtr<JSStringRef> fastDataArrivalPropertyName(Adopt, JSStringCreateWithUTF8CString("fastDataArrival"));
2700         JSValueRef fastDataArrivalValue = JSObjectGetProperty(context, hid, fastDataArrivalPropertyName.get(), 0);
2701         if (!JSValueIsUndefined(context, fastDataArrivalValue) && !JSValueIsNull(context, fastDataArrivalValue)) {
2702             if (!JSValueIsBoolean(context, fastDataArrivalValue))
2703                 return;
2704             bool fastDataArrival = JSValueToBoolean(context, fastDataArrivalValue);
2705             hidKeys.append(adoptWK(WKStringCreateWithUTF8CString("FastDataArrival")));
2706             hidValues.append(adoptWK(WKBooleanCreate(fastDataArrival)).get());
2707         }
2708
2709         JSRetainPtr<JSStringRef> continueAfterErrorDataPropertyName(Adopt, JSStringCreateWithUTF8CString("continueAfterErrorData"));
2710         JSValueRef continueAfterErrorDataValue = JSObjectGetProperty(context, hid, continueAfterErrorDataPropertyName.get(), 0);
2711         if (!JSValueIsUndefined(context, continueAfterErrorDataValue) && !JSValueIsNull(context, continueAfterErrorDataValue)) {
2712             if (!JSValueIsBoolean(context, continueAfterErrorDataValue))
2713                 return;
2714             bool continueAfterErrorData = JSValueToBoolean(context, continueAfterErrorDataValue);
2715             hidKeys.append(adoptWK(WKStringCreateWithUTF8CString("ContinueAfterErrorData")));
2716             hidValues.append(adoptWK(WKBooleanCreate(continueAfterErrorData)).get());
2717         }
2718
2719         JSRetainPtr<JSStringRef> canDowngradePropertyName(Adopt, JSStringCreateWithUTF8CString("canDowngrade"));
2720         JSValueRef canDowngradeValue = JSObjectGetProperty(context, hid, canDowngradePropertyName.get(), 0);
2721         if (!JSValueIsUndefined(context, canDowngradeValue) && !JSValueIsNull(context, canDowngradeValue)) {
2722             if (!JSValueIsBoolean(context, canDowngradeValue))
2723                 return;
2724             bool canDowngrade = JSValueToBoolean(context, canDowngradeValue);
2725             hidKeys.append(adoptWK(WKStringCreateWithUTF8CString("CanDowngrade")));
2726             hidValues.append(adoptWK(WKBooleanCreate(canDowngrade)).get());
2727         }
2728
2729         Vector<WKStringRef> rawHidKeys;
2730         Vector<WKTypeRef> rawHidValues;
2731         rawHidKeys.resize(hidKeys.size());
2732         rawHidValues.resize(hidValues.size());
2733         for (size_t i = 0; i < hidKeys.size(); ++i) {
2734             rawHidKeys[i] = hidKeys[i].get();
2735             rawHidValues[i] = hidValues[i].get();
2736         }
2737
2738         configurationKeys.append(adoptWK(WKStringCreateWithUTF8CString("Hid")));
2739         configurationValues.append(adoptWK(WKDictionaryCreate(rawHidKeys.data(), rawHidValues.data(), rawHidKeys.size())));
2740     }
2741
2742     JSRetainPtr<JSStringRef> nfcPropertyName(Adopt, JSStringCreateWithUTF8CString("nfc"));
2743     JSValueRef nfcValue = JSObjectGetProperty(context, configuration, nfcPropertyName.get(), 0);
2744     if (!JSValueIsUndefined(context, nfcValue) && !JSValueIsNull(context, nfcValue)) {
2745         if (!JSValueIsObject(context, nfcValue))
2746             return;
2747         JSObjectRef nfc = JSValueToObject(context, nfcValue, 0);
2748
2749         JSRetainPtr<JSStringRef> errorPropertyName(Adopt, JSStringCreateWithUTF8CString("error"));
2750         JSValueRef errorValue = JSObjectGetProperty(context, nfc, errorPropertyName.get(), 0);
2751         if (!JSValueIsString(context, errorValue))
2752             return;
2753
2754         Vector<WKRetainPtr<WKStringRef>> nfcKeys;
2755         Vector<WKRetainPtr<WKTypeRef>> nfcValues;
2756         nfcKeys.append(adoptWK(WKStringCreateWithUTF8CString("Error")));
2757         nfcValues.append(toWK(adopt(JSValueToStringCopy(context, errorValue, 0)).get()));
2758
2759         JSRetainPtr<JSStringRef> payloadBase64PropertyName(Adopt, JSStringCreateWithUTF8CString("payloadBase64"));
2760         JSValueRef payloadBase64Value = JSObjectGetProperty(context, nfc, payloadBase64PropertyName.get(), 0);
2761         if (!JSValueIsUndefined(context, payloadBase64Value) && !JSValueIsNull(context, payloadBase64Value)) {
2762             if (!JSValueIsArray(context, payloadBase64Value))
2763                 return;
2764
2765             JSObjectRef payloadBase64 = JSValueToObject(context, payloadBase64Value, nullptr);
2766             static auto lengthProperty = adopt(JSStringCreateWithUTF8CString("length"));
2767             JSValueRef payloadBase64LengthValue = JSObjectGetProperty(context, payloadBase64, lengthProperty.get(), nullptr);
2768             if (!JSValueIsNumber(context, payloadBase64LengthValue))
2769                 return;
2770
2771             auto payloadBase64s = adoptWK(WKMutableArrayCreate());
2772             auto payloadBase64Length = static_cast<size_t>(JSValueToNumber(context, payloadBase64LengthValue, nullptr));
2773             for (size_t i = 0; i < payloadBase64Length; ++i) {
2774                 JSValueRef payloadBase64Value = JSObjectGetPropertyAtIndex(context, payloadBase64, i, nullptr);
2775                 if (!JSValueIsString(context, payloadBase64Value))
2776                     continue;
2777                 WKArrayAppendItem(payloadBase64s.get(), toWK(adopt(JSValueToStringCopy(context, payloadBase64Value, 0)).get()).get());
2778             }
2779
2780             nfcKeys.append(adoptWK(WKStringCreateWithUTF8CString("PayloadBase64")));
2781             nfcValues.append(payloadBase64s);
2782         }
2783
2784         JSRetainPtr<JSStringRef> multipleTagsPropertyName(Adopt, JSStringCreateWithUTF8CString("multipleTags"));
2785         JSValueRef multipleTagsValue = JSObjectGetProperty(context, nfc, multipleTagsPropertyName.get(), 0);
2786         if (!JSValueIsUndefined(context, multipleTagsValue) && !JSValueIsNull(context, multipleTagsValue)) {
2787             if (!JSValueIsBoolean(context, multipleTagsValue))
2788                 return;
2789             bool multipleTags = JSValueToBoolean(context, multipleTagsValue);
2790             nfcKeys.append(adoptWK(WKStringCreateWithUTF8CString("MultipleTags")));
2791             nfcValues.append(adoptWK(WKBooleanCreate(multipleTags)).get());
2792         }
2793
2794         Vector<WKStringRef> rawNfcKeys;
2795         Vector<WKTypeRef> rawNfcValues;
2796         rawNfcKeys.resize(nfcKeys.size());
2797         rawNfcValues.resize(nfcValues.size());
2798         for (size_t i = 0; i < nfcKeys.size(); ++i) {
2799             rawNfcKeys[i] = nfcKeys[i].get();
2800             rawNfcValues[i] = nfcValues[i].get();
2801         }
2802
2803         configurationKeys.append(adoptWK(WKStringCreateWithUTF8CString("Nfc")));
2804         configurationValues.append(adoptWK(WKDictionaryCreate(rawNfcKeys.data(), rawNfcValues.data(), rawNfcKeys.size())));
2805     }
2806
2807     Vector<WKStringRef> rawConfigurationKeys;
2808     Vector<WKTypeRef> rawConfigurationValues;
2809     rawConfigurationKeys.resize(configurationKeys.size());
2810     rawConfigurationValues.resize(configurationValues.size());
2811     for (size_t i = 0; i < configurationKeys.size(); ++i) {
2812         rawConfigurationKeys[i] = configurationKeys[i].get();
2813         rawConfigurationValues[i] = configurationValues[i].get();
2814     }
2815
2816     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetWebAuthenticationMockConfiguration"));
2817     WKRetainPtr<WKDictionaryRef> messageBody = adoptWK(WKDictionaryCreate(rawConfigurationKeys.data(), rawConfigurationValues.data(), rawConfigurationKeys.size()));
2818     
2819     WKBundlePostSynchronousMessage(injectedBundle.bundle(), messageName.get(), messageBody.get(), nullptr);
2820 }
2821
2822 void TestRunner::addTestKeyToKeychain(JSStringRef privateKeyBase64, JSStringRef attrLabel, JSStringRef applicationTagBase64)
2823 {
2824     Vector<WKRetainPtr<WKStringRef>> keys;
2825     Vector<WKRetainPtr<WKTypeRef>> values;
2826
2827     keys.append(adoptWK(WKStringCreateWithUTF8CString("PrivateKey")));
2828     values.append(toWK(privateKeyBase64));
2829
2830     keys.append(adoptWK(WKStringCreateWithUTF8CString("AttrLabel")));
2831     values.append(toWK(attrLabel));
2832
2833     keys.append(adoptWK(WKStringCreateWithUTF8CString("ApplicationTag")));
2834     values.append(toWK(applicationTagBase64));
2835
2836     Vector<WKStringRef> rawKeys;
2837     Vector<WKTypeRef> rawValues;
2838     rawKeys.resize(keys.size());
2839     rawValues.resize(values.size());
2840
2841     for (size_t i = 0; i < keys.size(); ++i) {
2842         rawKeys[i] = keys[i].get();
2843         rawValues[i] = values[i].get();
2844     }
2845
2846     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("AddTestKeyToKeychain"));
2847     WKRetainPtr<WKDictionaryRef> messageBody = adoptWK(WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
2848
2849     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
2850 }
2851
2852 void TestRunner::cleanUpKeychain(JSStringRef attrLabel, JSStringRef applicationTagBase64)
2853 {
2854     Vector<WKRetainPtr<WKStringRef>> keys;
2855     Vector<WKRetainPtr<WKTypeRef>> values;
2856
2857     keys.append(adoptWK(WKStringCreateWithUTF8CString("AttrLabel")));
2858     values.append(toWK(attrLabel));
2859
2860     if (applicationTagBase64) {
2861         keys.append(adoptWK(WKStringCreateWithUTF8CString("ApplicationTag")));
2862         values.append(toWK(applicationTagBase64));
2863     }
2864
2865     Vector<WKStringRef> rawKeys;
2866     Vector<WKTypeRef> rawValues;
2867     rawKeys.resize(keys.size());
2868     rawValues.resize(values.size());
2869
2870     for (size_t i = 0; i < keys.size(); ++i) {
2871         rawKeys[i] = keys[i].get();
2872         rawValues[i] = values[i].get();
2873     }
2874
2875     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("CleanUpKeychain"));
2876     WKRetainPtr<WKDictionaryRef> messageBody = adoptWK(WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
2877
2878     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
2879 }
2880
2881 bool TestRunner::keyExistsInKeychain(JSStringRef attrLabel, JSStringRef applicationTagBase64)
2882 {
2883     Vector<WKRetainPtr<WKStringRef>> keys;
2884     Vector<WKRetainPtr<WKTypeRef>> values;
2885
2886     keys.append(adoptWK(WKStringCreateWithUTF8CString("AttrLabel")));
2887     values.append(toWK(attrLabel));
2888
2889     keys.append(adoptWK(WKStringCreateWithUTF8CString("ApplicationTag")));
2890     values.append(toWK(applicationTagBase64));
2891
2892     Vector<WKStringRef> rawKeys;
2893     Vector<WKTypeRef> rawValues;
2894     rawKeys.resize(keys.size());
2895     rawValues.resize(values.size());
2896
2897     for (size_t i = 0; i < keys.size(); ++i) {
2898         rawKeys[i] = keys[i].get();
2899         rawValues[i] = values[i].get();
2900     }
2901
2902     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("KeyExistsInKeychain"));
2903     WKRetainPtr<WKDictionaryRef> messageBody = adoptWK(WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
2904
2905     WKTypeRef returnData = nullptr;
2906     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), &returnData);
2907     ASSERT(WKGetTypeID(returnData) == WKBooleanGetTypeID());
2908     return WKBooleanGetValue(adoptWK(static_cast<WKBooleanRef>(returnData)).get());
2909 }
2910
2911 void TestRunner::setCanHandleHTTPSServerTrustEvaluation(bool canHandle)
2912 {
2913     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetCanHandleHTTPSServerTrustEvaluation"));
2914     WKRetainPtr<WKBooleanRef> messageBody = adoptWK(WKBooleanCreate(canHandle));
2915     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
2916 }
2917
2918 bool TestRunner::canDoServerTrustEvaluationInNetworkProcess()
2919 {
2920     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("CanDoServerTrustEvaluationInNetworkProcess"));
2921     WKTypeRef returnData = nullptr;
2922     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), nullptr, &returnData);
2923     ASSERT(WKGetTypeID(returnData) == WKBooleanGetTypeID());
2924     return WKBooleanGetValue(adoptWK(static_cast<WKBooleanRef>(returnData)).get());
2925 }
2926
2927 unsigned long TestRunner::serverTrustEvaluationCallbackCallsCount()
2928 {
2929     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("ServerTrustEvaluationCallbackCallsCount"));
2930     WKTypeRef returnData = nullptr;
2931     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), nullptr, &returnData);
2932     ASSERT(WKGetTypeID(returnData) == WKUInt64GetTypeID());
2933     return WKUInt64GetValue(adoptWK(static_cast<WKUInt64Ref>(returnData)).get());
2934 }
2935
2936 void TestRunner::setShouldDismissJavaScriptAlertsAsynchronously(bool shouldDismissAsynchronously)
2937 {
2938     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("ShouldDismissJavaScriptAlertsAsynchronously"));
2939     WKRetainPtr<WKBooleanRef> messageBody = adoptWK(WKBooleanCreate(shouldDismissAsynchronously));
2940     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
2941 }
2942
2943 void TestRunner::abortModal()
2944 {
2945     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("AbortModal"));
2946     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), nullptr, nullptr);
2947 }
2948
2949 void TestRunner::dumpAdClickAttribution()
2950 {
2951     auto messageName = adoptWK(WKStringCreateWithUTF8CString("DumpAdClickAttribution"));
2952     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), nullptr, nullptr);
2953 }
2954
2955 void TestRunner::clearAdClickAttribution()
2956 {
2957     auto messageName = adoptWK(WKStringCreateWithUTF8CString("ClearAdClickAttribution"));
2958     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), nullptr, nullptr);
2959 }
2960
2961 void TestRunner::clearAdClickAttributionsThroughWebsiteDataRemoval()
2962 {
2963     auto messageName = adoptWK(WKStringCreateWithUTF8CString("ClearAdClickAttributionsThroughWebsiteDataRemoval"));
2964     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), nullptr, nullptr);
2965 }
2966
2967 void TestRunner::setAdClickAttributionOverrideTimerForTesting(bool value)
2968 {
2969     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetAdClickAttributionOverrideTimerForTesting"));
2970     WKRetainPtr<WKBooleanRef> messageBody = adoptWK(WKBooleanCreate(value));
2971     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get(), nullptr);
2972 }
2973
2974 void TestRunner::setAdClickAttributionConversionURLForTesting(JSStringRef urlString)
2975 {
2976     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetAdClickAttributionConversionURLForTesting"));
2977     auto wtfURLString = toWTFString(WKStringCreateWithJSString(urlString));
2978     WKRetainPtr<WKURLRef> messageBody = adoptWK(WKURLCreateWithUTF8CString(wtfURLString.utf8().data()));
2979     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get(), nullptr);
2980 }
2981
2982 void TestRunner::markAdClickAttributionsAsExpiredForTesting()
2983 {
2984     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("MarkAdClickAttributionsAsExpiredForTesting"));
2985     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), nullptr, nullptr);
2986 }
2987
2988 } // namespace WTR