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