824a5f684316937034e86c14903177bbccb6fed6
[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::terminateNetworkProcess()
1298 {
1299     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("TerminateNetworkProcess"));
1300     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), nullptr, nullptr);
1301 }
1302
1303 void TestRunner::terminateServiceWorkerProcess()
1304 {
1305     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("TerminateServiceWorkerProcess"));
1306     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), nullptr, nullptr);
1307 }
1308
1309 static unsigned nextUIScriptCallbackID()
1310 {
1311     static unsigned callbackID = FirstUIScriptCallbackID;
1312     return callbackID++;
1313 }
1314
1315 void TestRunner::runUIScript(JSStringRef script, JSValueRef callback)
1316 {
1317     unsigned callbackID = nextUIScriptCallbackID();
1318     cacheTestRunnerCallback(callbackID, callback);
1319
1320     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("RunUIProcessScript"));
1321
1322     WKRetainPtr<WKMutableDictionaryRef> testDictionary(AdoptWK, WKMutableDictionaryCreate());
1323
1324     WKRetainPtr<WKStringRef> scriptKey(AdoptWK, WKStringCreateWithUTF8CString("Script"));
1325     WKRetainPtr<WKStringRef> scriptValue(AdoptWK, WKStringCreateWithJSString(script));
1326
1327     WKRetainPtr<WKStringRef> callbackIDKey(AdoptWK, WKStringCreateWithUTF8CString("CallbackID"));
1328     WKRetainPtr<WKUInt64Ref> callbackIDValue = adoptWK(WKUInt64Create(callbackID));
1329
1330     WKDictionarySetItem(testDictionary.get(), scriptKey.get(), scriptValue.get());
1331     WKDictionarySetItem(testDictionary.get(), callbackIDKey.get(), callbackIDValue.get());
1332
1333     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), testDictionary.get());
1334 }
1335
1336 void TestRunner::runUIScriptCallback(unsigned callbackID, JSStringRef result)
1337 {
1338     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
1339     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
1340
1341     JSValueRef resultValue = JSValueMakeString(context, result);
1342     callTestRunnerCallback(callbackID, 1, &resultValue);
1343 }
1344
1345 void TestRunner::installDidBeginSwipeCallback(JSValueRef callback)
1346 {
1347     cacheTestRunnerCallback(DidBeginSwipeCallbackID, callback);
1348 }
1349
1350 void TestRunner::installWillEndSwipeCallback(JSValueRef callback)
1351 {
1352     cacheTestRunnerCallback(WillEndSwipeCallbackID, callback);
1353 }
1354
1355 void TestRunner::installDidEndSwipeCallback(JSValueRef callback)
1356 {
1357     cacheTestRunnerCallback(DidEndSwipeCallbackID, callback);
1358 }
1359
1360 void TestRunner::installDidRemoveSwipeSnapshotCallback(JSValueRef callback)
1361 {
1362     cacheTestRunnerCallback(DidRemoveSwipeSnapshotCallbackID, callback);
1363 }
1364
1365 void TestRunner::callDidBeginSwipeCallback()
1366 {
1367     callTestRunnerCallback(DidBeginSwipeCallbackID);
1368 }
1369
1370 void TestRunner::callWillEndSwipeCallback()
1371 {
1372     callTestRunnerCallback(WillEndSwipeCallbackID);
1373 }
1374
1375 void TestRunner::callDidEndSwipeCallback()
1376 {
1377     callTestRunnerCallback(DidEndSwipeCallbackID);
1378 }
1379
1380 void TestRunner::callDidRemoveSwipeSnapshotCallback()
1381 {
1382     callTestRunnerCallback(DidRemoveSwipeSnapshotCallbackID);
1383 }
1384
1385 void TestRunner::setStatisticsDebugMode(bool value, JSValueRef completionHandler)
1386 {
1387     cacheTestRunnerCallback(SetStatisticsDebugModeCallbackID, completionHandler);
1388
1389     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetStatisticsDebugMode"));
1390     WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(value));
1391     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1392
1393 }
1394
1395 void TestRunner::statisticsCallDidSetDebugModeCallback()
1396 {
1397     callTestRunnerCallback(SetStatisticsDebugModeCallbackID);
1398 }
1399
1400 void TestRunner::setStatisticsPrevalentResourceForDebugMode(JSStringRef hostName, JSValueRef completionHandler)
1401 {
1402     cacheTestRunnerCallback(SetStatisticsPrevalentResourceForDebugModeCallbackID, completionHandler);
1403     
1404     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetStatisticsPrevalentResourceForDebugMode"));
1405     WKRetainPtr<WKStringRef> messageBody(AdoptWK, WKStringCreateWithJSString(hostName));
1406     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1407 }
1408
1409 void TestRunner::statisticsCallDidSetPrevalentResourceForDebugModeCallback()
1410 {
1411     callTestRunnerCallback(SetStatisticsPrevalentResourceForDebugModeCallbackID);
1412 }
1413
1414 void TestRunner::setStatisticsLastSeen(JSStringRef hostName, double seconds, JSValueRef completionHandler)
1415 {
1416     cacheTestRunnerCallback(SetStatisticsLastSeenCallbackID, completionHandler);
1417
1418     Vector<WKRetainPtr<WKStringRef>> keys;
1419     Vector<WKRetainPtr<WKTypeRef>> values;
1420     
1421     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("HostName") });
1422     values.append({ AdoptWK, WKStringCreateWithJSString(hostName) });
1423     
1424     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("Value") });
1425     values.append({ AdoptWK, WKDoubleCreate(seconds) });
1426     
1427     Vector<WKStringRef> rawKeys(keys.size());
1428     Vector<WKTypeRef> rawValues(values.size());
1429     
1430     for (size_t i = 0; i < keys.size(); ++i) {
1431         rawKeys[i] = keys[i].get();
1432         rawValues[i] = values[i].get();
1433     }
1434     
1435     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetStatisticsLastSeen"));
1436     WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1437     
1438     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1439 }
1440
1441 void TestRunner::statisticsCallDidSetLastSeenCallback()
1442 {
1443     callTestRunnerCallback(SetStatisticsLastSeenCallbackID);
1444 }
1445
1446 void TestRunner::setStatisticsPrevalentResource(JSStringRef hostName, bool value, JSValueRef completionHandler)
1447 {
1448     cacheTestRunnerCallback(SetStatisticsPrevalentResourceCallbackID, completionHandler);
1449
1450     Vector<WKRetainPtr<WKStringRef>> keys;
1451     Vector<WKRetainPtr<WKTypeRef>> values;
1452
1453     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("HostName") });
1454     values.append({ AdoptWK, WKStringCreateWithJSString(hostName) });
1455     
1456     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("Value") });
1457     values.append({ AdoptWK, WKBooleanCreate(value) });
1458     
1459     Vector<WKStringRef> rawKeys;
1460     Vector<WKTypeRef> rawValues;
1461     rawKeys.resize(keys.size());
1462     rawValues.resize(values.size());
1463     
1464     for (size_t i = 0; i < keys.size(); ++i) {
1465         rawKeys[i] = keys[i].get();
1466         rawValues[i] = values[i].get();
1467     }
1468     
1469     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetStatisticsPrevalentResource"));
1470     WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1471
1472     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1473 }
1474
1475 void TestRunner::statisticsCallDidSetPrevalentResourceCallback()
1476 {
1477     callTestRunnerCallback(SetStatisticsPrevalentResourceCallbackID);
1478 }
1479
1480 void TestRunner::setStatisticsVeryPrevalentResource(JSStringRef hostName, bool value, JSValueRef completionHandler)
1481 {
1482     cacheTestRunnerCallback(SetStatisticsVeryPrevalentResourceCallbackID, completionHandler);
1483
1484     Vector<WKRetainPtr<WKStringRef>> keys;
1485     Vector<WKRetainPtr<WKTypeRef>> values;
1486     
1487     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("HostName") });
1488     values.append({ AdoptWK, WKStringCreateWithJSString(hostName) });
1489     
1490     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("Value") });
1491     values.append({ AdoptWK, WKBooleanCreate(value) });
1492     
1493     Vector<WKStringRef> rawKeys;
1494     Vector<WKTypeRef> rawValues;
1495     rawKeys.resize(keys.size());
1496     rawValues.resize(values.size());
1497     
1498     for (size_t i = 0; i < keys.size(); ++i) {
1499         rawKeys[i] = keys[i].get();
1500         rawValues[i] = values[i].get();
1501     }
1502     
1503     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetStatisticsVeryPrevalentResource"));
1504     WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1505     
1506     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1507 }
1508
1509 void TestRunner::statisticsCallDidSetVeryPrevalentResourceCallback()
1510 {
1511     callTestRunnerCallback(SetStatisticsVeryPrevalentResourceCallbackID);
1512 }
1513     
1514 void TestRunner::dumpResourceLoadStatistics()
1515 {
1516     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("dumpResourceLoadStatistics"));
1517     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), nullptr, nullptr);
1518 }
1519
1520 bool TestRunner::isStatisticsPrevalentResource(JSStringRef hostName)
1521 {
1522     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("IsStatisticsPrevalentResource"));
1523     WKRetainPtr<WKStringRef> messageBody(AdoptWK, WKStringCreateWithJSString(hostName));
1524     WKTypeRef returnData = nullptr;
1525     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get(), &returnData);
1526     ASSERT(WKGetTypeID(returnData) == WKBooleanGetTypeID());
1527     return WKBooleanGetValue(adoptWK(static_cast<WKBooleanRef>(returnData)).get());
1528 }
1529
1530 bool TestRunner::isStatisticsVeryPrevalentResource(JSStringRef hostName)
1531 {
1532     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("IsStatisticsVeryPrevalentResource"));
1533     WKRetainPtr<WKStringRef> messageBody(AdoptWK, WKStringCreateWithJSString(hostName));
1534     WKTypeRef returnData = nullptr;
1535     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get(), &returnData);
1536     ASSERT(WKGetTypeID(returnData) == WKBooleanGetTypeID());
1537     return WKBooleanGetValue(adoptWK(static_cast<WKBooleanRef>(returnData)).get());
1538 }
1539
1540 bool TestRunner::isStatisticsRegisteredAsSubresourceUnder(JSStringRef subresourceHost, JSStringRef topFrameHost)
1541 {
1542     Vector<WKRetainPtr<WKStringRef>> keys;
1543     Vector<WKRetainPtr<WKTypeRef>> values;
1544     
1545     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("SubresourceHost") });
1546     values.append({ AdoptWK, WKStringCreateWithJSString(subresourceHost) });
1547     
1548     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("TopFrameHost") });
1549     values.append({ AdoptWK, WKStringCreateWithJSString(topFrameHost) });
1550     
1551     Vector<WKStringRef> rawKeys(keys.size());
1552     Vector<WKTypeRef> rawValues(values.size());
1553     
1554     for (size_t i = 0; i < keys.size(); ++i) {
1555         rawKeys[i] = keys[i].get();
1556         rawValues[i] = values[i].get();
1557     }
1558     
1559     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("IsStatisticsRegisteredAsSubresourceUnder"));
1560     WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1561     WKTypeRef returnData = nullptr;
1562     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get(), &returnData);
1563     ASSERT(WKGetTypeID(returnData) == WKBooleanGetTypeID());
1564     return WKBooleanGetValue(adoptWK(static_cast<WKBooleanRef>(returnData)).get());
1565 }
1566
1567 bool TestRunner::isStatisticsRegisteredAsSubFrameUnder(JSStringRef subFrameHost, JSStringRef topFrameHost)
1568 {
1569     Vector<WKRetainPtr<WKStringRef>> keys;
1570     Vector<WKRetainPtr<WKTypeRef>> values;
1571
1572     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("SubFrameHost") });
1573     values.append({ AdoptWK, WKStringCreateWithJSString(subFrameHost) });
1574     
1575     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("TopFrameHost") });
1576     values.append({ AdoptWK, WKStringCreateWithJSString(topFrameHost) });
1577     
1578     Vector<WKStringRef> rawKeys(keys.size());
1579     Vector<WKTypeRef> rawValues(values.size());
1580
1581     for (size_t i = 0; i < keys.size(); ++i) {
1582         rawKeys[i] = keys[i].get();
1583         rawValues[i] = values[i].get();
1584     }
1585
1586     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("IsStatisticsRegisteredAsSubFrameUnder"));
1587     WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1588     WKTypeRef returnData = nullptr;
1589     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get(), &returnData);
1590     ASSERT(WKGetTypeID(returnData) == WKBooleanGetTypeID());
1591     return WKBooleanGetValue(adoptWK(static_cast<WKBooleanRef>(returnData)).get());
1592 }
1593
1594 bool TestRunner::isStatisticsRegisteredAsRedirectingTo(JSStringRef hostRedirectedFrom, JSStringRef hostRedirectedTo)
1595 {
1596     Vector<WKRetainPtr<WKStringRef>> keys;
1597     Vector<WKRetainPtr<WKTypeRef>> values;
1598     
1599     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("HostRedirectedFrom") });
1600     values.append({ AdoptWK, WKStringCreateWithJSString(hostRedirectedFrom) });
1601     
1602     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("HostRedirectedTo") });
1603     values.append({ AdoptWK, WKStringCreateWithJSString(hostRedirectedTo) });
1604     
1605     Vector<WKStringRef> rawKeys(keys.size());
1606     Vector<WKTypeRef> rawValues(values.size());
1607
1608     for (size_t i = 0; i < keys.size(); ++i) {
1609         rawKeys[i] = keys[i].get();
1610         rawValues[i] = values[i].get();
1611     }
1612     
1613     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("IsStatisticsRegisteredAsRedirectingTo"));
1614     WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1615     WKTypeRef returnData = nullptr;
1616     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get(), &returnData);
1617     ASSERT(WKGetTypeID(returnData) == WKBooleanGetTypeID());
1618     return WKBooleanGetValue(adoptWK(static_cast<WKBooleanRef>(returnData)).get());
1619 }
1620
1621 void TestRunner::setStatisticsHasHadUserInteraction(JSStringRef hostName, bool value, JSValueRef completionHandler)
1622 {
1623     cacheTestRunnerCallback(SetStatisticsHasHadUserInteractionCallbackID, completionHandler);
1624
1625     Vector<WKRetainPtr<WKStringRef>> keys;
1626     Vector<WKRetainPtr<WKTypeRef>> values;
1627     
1628     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("HostName") });
1629     values.append({ AdoptWK, WKStringCreateWithJSString(hostName) });
1630     
1631     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("Value") });
1632     values.append({ AdoptWK, WKBooleanCreate(value) });
1633     
1634     Vector<WKStringRef> rawKeys;
1635     Vector<WKTypeRef> rawValues;
1636     rawKeys.resize(keys.size());
1637     rawValues.resize(values.size());
1638     
1639     for (size_t i = 0; i < keys.size(); ++i) {
1640         rawKeys[i] = keys[i].get();
1641         rawValues[i] = values[i].get();
1642     }
1643     
1644     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetStatisticsHasHadUserInteraction"));
1645     WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1646     
1647     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1648 }
1649
1650 void TestRunner::statisticsCallDidSetHasHadUserInteractionCallback()
1651 {
1652     callTestRunnerCallback(SetStatisticsHasHadUserInteractionCallbackID);
1653 }
1654
1655 bool TestRunner::isStatisticsHasHadUserInteraction(JSStringRef hostName)
1656 {
1657     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("IsStatisticsHasHadUserInteraction"));
1658     WKRetainPtr<WKStringRef> messageBody(AdoptWK, WKStringCreateWithJSString(hostName));
1659     WKTypeRef returnData = nullptr;
1660     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get(), &returnData);
1661     ASSERT(WKGetTypeID(returnData) == WKBooleanGetTypeID());
1662     return WKBooleanGetValue(adoptWK(static_cast<WKBooleanRef>(returnData)).get());
1663 }
1664
1665 void TestRunner::setStatisticsGrandfathered(JSStringRef hostName, bool value)
1666 {
1667     Vector<WKRetainPtr<WKStringRef>> keys;
1668     Vector<WKRetainPtr<WKTypeRef>> values;
1669     
1670     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("HostName") });
1671     values.append({ AdoptWK, WKStringCreateWithJSString(hostName) });
1672     
1673     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("Value") });
1674     values.append({ AdoptWK, WKBooleanCreate(value) });
1675     
1676     Vector<WKStringRef> rawKeys;
1677     Vector<WKTypeRef> rawValues;
1678     rawKeys.resize(keys.size());
1679     rawValues.resize(values.size());
1680     
1681     for (size_t i = 0; i < keys.size(); ++i) {
1682         rawKeys[i] = keys[i].get();
1683         rawValues[i] = values[i].get();
1684     }
1685     
1686     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetStatisticsGrandfathered"));
1687     WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1688     
1689     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1690 }
1691     
1692 bool TestRunner::isStatisticsGrandfathered(JSStringRef hostName)
1693 {
1694     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("IsStatisticsGrandfathered"));
1695     WKRetainPtr<WKStringRef> messageBody(AdoptWK, WKStringCreateWithJSString(hostName));
1696     WKTypeRef returnData = nullptr;
1697     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get(), &returnData);
1698     ASSERT(WKGetTypeID(returnData) == WKBooleanGetTypeID());
1699     return WKBooleanGetValue(adoptWK(static_cast<WKBooleanRef>(returnData)).get());
1700 }
1701
1702 void TestRunner::setStatisticsSubframeUnderTopFrameOrigin(JSStringRef hostName, JSStringRef topFrameHostName)
1703 {
1704     Vector<WKRetainPtr<WKStringRef>> keys;
1705     Vector<WKRetainPtr<WKTypeRef>> values;
1706     
1707     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("HostName") });
1708     values.append({ AdoptWK, WKStringCreateWithJSString(hostName) });
1709     
1710     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("TopFrameHostName") });
1711     values.append({ AdoptWK, WKStringCreateWithJSString(topFrameHostName) });
1712     
1713     Vector<WKStringRef> rawKeys(keys.size());
1714     Vector<WKTypeRef> rawValues(values.size());
1715     
1716     for (size_t i = 0; i < keys.size(); ++i) {
1717         rawKeys[i] = keys[i].get();
1718         rawValues[i] = values[i].get();
1719     }
1720     
1721     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetStatisticsSubframeUnderTopFrameOrigin"));
1722     WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1723     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1724 }
1725
1726 void TestRunner::setStatisticsSubresourceUnderTopFrameOrigin(JSStringRef hostName, JSStringRef topFrameHostName)
1727 {
1728     Vector<WKRetainPtr<WKStringRef>> keys;
1729     Vector<WKRetainPtr<WKTypeRef>> values;
1730     
1731     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("HostName") });
1732     values.append({ AdoptWK, WKStringCreateWithJSString(hostName) });
1733     
1734     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("TopFrameHostName") });
1735     values.append({ AdoptWK, WKStringCreateWithJSString(topFrameHostName) });
1736     
1737     Vector<WKStringRef> rawKeys(keys.size());
1738     Vector<WKTypeRef> rawValues(values.size());
1739     
1740     for (size_t i = 0; i < keys.size(); ++i) {
1741         rawKeys[i] = keys[i].get();
1742         rawValues[i] = values[i].get();
1743     }
1744     
1745     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetStatisticsSubresourceUnderTopFrameOrigin"));
1746     WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1747     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1748 }
1749
1750 void TestRunner::setStatisticsSubresourceUniqueRedirectTo(JSStringRef hostName, JSStringRef hostNameRedirectedTo)
1751 {
1752     Vector<WKRetainPtr<WKStringRef>> keys;
1753     Vector<WKRetainPtr<WKTypeRef>> values;
1754     
1755     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("HostName") });
1756     values.append({ AdoptWK, WKStringCreateWithJSString(hostName) });
1757     
1758     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("HostNameRedirectedTo") });
1759     values.append({ AdoptWK, WKStringCreateWithJSString(hostNameRedirectedTo) });
1760     
1761     Vector<WKStringRef> rawKeys(keys.size());
1762     Vector<WKTypeRef> rawValues(values.size());
1763     
1764     for (size_t i = 0; i < keys.size(); ++i) {
1765         rawKeys[i] = keys[i].get();
1766         rawValues[i] = values[i].get();
1767     }
1768     
1769     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetStatisticsSubresourceUniqueRedirectTo"));
1770     WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1771     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1772 }
1773
1774
1775 void TestRunner::setStatisticsSubresourceUniqueRedirectFrom(JSStringRef hostName, JSStringRef hostNameRedirectedFrom)
1776 {
1777     Vector<WKRetainPtr<WKStringRef>> keys;
1778     Vector<WKRetainPtr<WKTypeRef>> values;
1779     
1780     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("HostName") });
1781     values.append({ AdoptWK, WKStringCreateWithJSString(hostName) });
1782     
1783     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("HostNameRedirectedFrom") });
1784     values.append({ AdoptWK, WKStringCreateWithJSString(hostNameRedirectedFrom) });
1785     
1786     Vector<WKStringRef> rawKeys(keys.size());
1787     Vector<WKTypeRef> rawValues(values.size());
1788     
1789     for (size_t i = 0; i < keys.size(); ++i) {
1790         rawKeys[i] = keys[i].get();
1791         rawValues[i] = values[i].get();
1792     }
1793     
1794     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetStatisticsSubresourceUniqueRedirectFrom"));
1795     WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1796     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1797 }
1798
1799 void TestRunner::setStatisticsTopFrameUniqueRedirectTo(JSStringRef hostName, JSStringRef hostNameRedirectedTo)
1800 {
1801     Vector<WKRetainPtr<WKStringRef>> keys;
1802     Vector<WKRetainPtr<WKTypeRef>> values;
1803     
1804     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("HostName") });
1805     values.append({ AdoptWK, WKStringCreateWithJSString(hostName) });
1806     
1807     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("HostNameRedirectedTo") });
1808     values.append({ AdoptWK, WKStringCreateWithJSString(hostNameRedirectedTo) });
1809     
1810     Vector<WKStringRef> rawKeys(keys.size());
1811     Vector<WKTypeRef> rawValues(values.size());
1812     
1813     for (size_t i = 0; i < keys.size(); ++i) {
1814         rawKeys[i] = keys[i].get();
1815         rawValues[i] = values[i].get();
1816     }
1817     
1818     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetStatisticsTopFrameUniqueRedirectTo"));
1819     WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1820     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1821 }
1822
1823 void TestRunner::setStatisticsTopFrameUniqueRedirectFrom(JSStringRef hostName, JSStringRef hostNameRedirectedFrom)
1824 {
1825     Vector<WKRetainPtr<WKStringRef>> keys;
1826     Vector<WKRetainPtr<WKTypeRef>> values;
1827     
1828     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("HostName") });
1829     values.append({ AdoptWK, WKStringCreateWithJSString(hostName) });
1830     
1831     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("HostNameRedirectedFrom") });
1832     values.append({ AdoptWK, WKStringCreateWithJSString(hostNameRedirectedFrom) });
1833     
1834     Vector<WKStringRef> rawKeys(keys.size());
1835     Vector<WKTypeRef> rawValues(values.size());
1836     
1837     for (size_t i = 0; i < keys.size(); ++i) {
1838         rawKeys[i] = keys[i].get();
1839         rawValues[i] = values[i].get();
1840     }
1841     
1842     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetStatisticsTopFrameUniqueRedirectFrom"));
1843     WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1844     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1845 }
1846
1847
1848 void TestRunner::setStatisticsTimeToLiveUserInteraction(double seconds)
1849 {
1850     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetStatisticsTimeToLiveUserInteraction"));
1851     WKRetainPtr<WKDoubleRef> messageBody(AdoptWK, WKDoubleCreate(seconds));
1852     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1853 }
1854
1855 void TestRunner::installStatisticsDidModifyDataRecordsCallback(JSValueRef callback)
1856 {
1857     cacheTestRunnerCallback(StatisticsDidModifyDataRecordsCallbackID, callback);
1858 }
1859
1860 void TestRunner::statisticsDidModifyDataRecordsCallback()
1861 {
1862     callTestRunnerCallback(StatisticsDidModifyDataRecordsCallbackID);
1863 }
1864
1865 void TestRunner::installStatisticsDidScanDataRecordsCallback(JSValueRef callback)
1866 {
1867     cacheTestRunnerCallback(StatisticsDidScanDataRecordsCallbackID, callback);
1868
1869     bool notifyPagesWhenDataRecordsWereScanned = !!callback;
1870
1871     // Setting a callback implies we expect to receive callbacks. So register for them.
1872     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("StatisticsNotifyPagesWhenDataRecordsWereScanned"));
1873     WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(notifyPagesWhenDataRecordsWereScanned));
1874     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1875 }
1876
1877 void TestRunner::statisticsDidScanDataRecordsCallback()
1878 {
1879     callTestRunnerCallback(StatisticsDidScanDataRecordsCallbackID);
1880 }
1881
1882 void TestRunner::installStatisticsDidRunTelemetryCallback(JSValueRef callback)
1883 {
1884     cacheTestRunnerCallback(StatisticsDidRunTelemetryCallbackID, callback);
1885 }
1886     
1887 void TestRunner::statisticsDidRunTelemetryCallback(unsigned totalPrevalentResources, unsigned totalPrevalentResourcesWithUserInteraction, unsigned top3SubframeUnderTopFrameOrigins)
1888 {
1889     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
1890     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
1891     
1892     StringBuilder stringBuilder;
1893     stringBuilder.appendLiteral("{ \"totalPrevalentResources\" : ");
1894     stringBuilder.appendNumber(totalPrevalentResources);
1895     stringBuilder.appendLiteral(", \"totalPrevalentResourcesWithUserInteraction\" : ");
1896     stringBuilder.appendNumber(totalPrevalentResourcesWithUserInteraction);
1897     stringBuilder.appendLiteral(", \"top3SubframeUnderTopFrameOrigins\" : ");
1898     stringBuilder.appendNumber(top3SubframeUnderTopFrameOrigins);
1899     stringBuilder.appendLiteral(" }");
1900     
1901     JSValueRef result = JSValueMakeFromJSONString(context, adopt(JSStringCreateWithUTF8CString(stringBuilder.toString().utf8().data())).get());
1902
1903     callTestRunnerCallback(StatisticsDidRunTelemetryCallbackID, 1, &result);
1904 }
1905
1906 void TestRunner::statisticsNotifyObserver()
1907 {
1908     InjectedBundle::singleton().statisticsNotifyObserver();
1909 }
1910
1911 void TestRunner::statisticsProcessStatisticsAndDataRecords()
1912 {
1913     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("StatisticsProcessStatisticsAndDataRecords"));
1914     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), nullptr, nullptr);
1915 }
1916
1917 void TestRunner::statisticsUpdateCookieBlocking(JSValueRef completionHandler)
1918 {
1919     cacheTestRunnerCallback(StatisticsDidSetBlockCookiesForHostCallbackID, completionHandler);
1920
1921     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("StatisticsUpdateCookieBlocking"));
1922     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), nullptr, nullptr);
1923 }
1924
1925 void TestRunner::statisticsCallDidSetBlockCookiesForHostCallback()
1926 {
1927     callTestRunnerCallback(StatisticsDidSetBlockCookiesForHostCallbackID);
1928 }
1929
1930 void TestRunner::statisticsSubmitTelemetry()
1931 {
1932     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("StatisticsSubmitTelemetry"));
1933     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), nullptr, nullptr);
1934 }
1935
1936 void TestRunner::setStatisticsNotifyPagesWhenDataRecordsWereScanned(bool value)
1937 {
1938     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("StatisticsNotifyPagesWhenDataRecordsWereScanned"));
1939     WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(value));
1940     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1941 }
1942
1943 void TestRunner::setStatisticsShouldClassifyResourcesBeforeDataRecordsRemoval(bool value)
1944 {
1945     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("StatisticsShouldClassifyResourcesBeforeDataRecordsRemoval"));
1946     WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(value));
1947     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1948 }
1949
1950 void TestRunner::setStatisticsNotifyPagesWhenTelemetryWasCaptured(bool value)
1951 {
1952     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("StatisticsNotifyPagesWhenTelemetryWasCaptured"));
1953     WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(value));
1954     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1955 }
1956
1957 void TestRunner::setStatisticsMinimumTimeBetweenDataRecordsRemoval(double seconds)
1958 {
1959     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetStatisticsMinimumTimeBetweenDataRecordsRemoval"));
1960     WKRetainPtr<WKDoubleRef> messageBody(AdoptWK, WKDoubleCreate(seconds));
1961     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1962 }
1963
1964 void TestRunner::setStatisticsGrandfatheringTime(double seconds)
1965 {
1966     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetStatisticsGrandfatheringTime"));
1967     WKRetainPtr<WKDoubleRef> messageBody(AdoptWK, WKDoubleCreate(seconds));
1968     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1969 }
1970
1971 void TestRunner::setStatisticsMaxStatisticsEntries(unsigned entries)
1972 {
1973     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetMaxStatisticsEntries"));
1974     WKRetainPtr<WKTypeRef> messageBody(AdoptWK, WKUInt64Create(entries));
1975     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1976 }
1977     
1978 void TestRunner::setStatisticsPruneEntriesDownTo(unsigned entries)
1979 {
1980     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetPruneEntriesDownTo"));
1981     WKRetainPtr<WKTypeRef> messageBody(AdoptWK, WKUInt64Create(entries));
1982     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1983 }
1984     
1985 void TestRunner::statisticsClearInMemoryAndPersistentStore(JSValueRef callback)
1986 {
1987     cacheTestRunnerCallback(StatisticsDidClearThroughWebsiteDataRemovalCallbackID, callback);
1988
1989     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("StatisticsClearInMemoryAndPersistentStore"));
1990     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), nullptr, nullptr);
1991 }
1992
1993 void TestRunner::statisticsClearInMemoryAndPersistentStoreModifiedSinceHours(unsigned hours, JSValueRef callback)
1994 {
1995     cacheTestRunnerCallback(StatisticsDidClearThroughWebsiteDataRemovalCallbackID, callback);
1996
1997     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("StatisticsClearInMemoryAndPersistentStoreModifiedSinceHours"));
1998     WKRetainPtr<WKTypeRef> messageBody(AdoptWK, WKUInt64Create(hours));
1999     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
2000 }
2001
2002 void TestRunner::statisticsClearThroughWebsiteDataRemoval(JSValueRef callback)
2003 {
2004     cacheTestRunnerCallback(StatisticsDidClearThroughWebsiteDataRemovalCallbackID, callback);
2005     
2006     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("StatisticsClearThroughWebsiteDataRemoval"));
2007     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), nullptr, nullptr);
2008 }
2009
2010 void TestRunner::statisticsDeleteCookiesForHost(JSStringRef hostName, bool includeHttpOnlyCookies)
2011 {
2012     Vector<WKRetainPtr<WKStringRef>> keys;
2013     Vector<WKRetainPtr<WKTypeRef>> values;
2014
2015     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("HostName") });
2016     values.append({ AdoptWK, WKStringCreateWithJSString(hostName) });
2017
2018     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("IncludeHttpOnlyCookies") });
2019     values.append({ AdoptWK, WKBooleanCreate(includeHttpOnlyCookies) });
2020
2021     Vector<WKStringRef> rawKeys;
2022     Vector<WKTypeRef> rawValues;
2023     rawKeys.resize(keys.size());
2024     rawValues.resize(values.size());
2025
2026     for (size_t i = 0; i < keys.size(); ++i) {
2027         rawKeys[i] = keys[i].get();
2028         rawValues[i] = values[i].get();
2029     }
2030
2031     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("StatisticsDeleteCookiesForHost"));
2032     WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
2033     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
2034 }
2035
2036 void TestRunner::setStatisticsCacheMaxAgeCap(double seconds)
2037 {
2038     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetStatisticsCacheMaxAgeCap"));
2039     WKRetainPtr<WKDoubleRef> messageBody(AdoptWK, WKDoubleCreate(seconds));
2040     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
2041 }
2042
2043 void TestRunner::statisticsCallClearThroughWebsiteDataRemovalCallback()
2044 {
2045     callTestRunnerCallback(StatisticsDidClearThroughWebsiteDataRemovalCallbackID);
2046 }
2047
2048 void TestRunner::statisticsResetToConsistentState(JSValueRef completionHandler)
2049 {
2050     cacheTestRunnerCallback(StatisticsDidResetToConsistentStateCallbackID, completionHandler);
2051     
2052     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("StatisticsResetToConsistentState"));
2053     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), nullptr, nullptr);
2054 }
2055
2056 void TestRunner::statisticsCallDidResetToConsistentStateCallback()
2057 {
2058     callTestRunnerCallback(StatisticsDidResetToConsistentStateCallbackID);
2059 }
2060
2061 void TestRunner::installTextDidChangeInTextFieldCallback(JSValueRef callback)
2062 {
2063     cacheTestRunnerCallback(TextDidChangeInTextFieldCallbackID, callback);
2064 }
2065
2066 void TestRunner::textDidChangeInTextFieldCallback()
2067 {
2068     callTestRunnerCallback(TextDidChangeInTextFieldCallbackID);
2069 }
2070
2071 void TestRunner::installTextFieldDidBeginEditingCallback(JSValueRef callback)
2072 {
2073     cacheTestRunnerCallback(TextFieldDidBeginEditingCallbackID, callback);
2074 }
2075
2076 void TestRunner::textFieldDidBeginEditingCallback()
2077 {
2078     callTestRunnerCallback(TextFieldDidBeginEditingCallbackID);
2079 }
2080
2081 void TestRunner::installTextFieldDidEndEditingCallback(JSValueRef callback)
2082 {
2083     cacheTestRunnerCallback(TextFieldDidEndEditingCallbackID, callback);
2084 }
2085
2086 void TestRunner::textFieldDidEndEditingCallback()
2087 {
2088     callTestRunnerCallback(TextFieldDidEndEditingCallbackID);
2089 }
2090
2091 void TestRunner::setStorageAccessAPIEnabled(bool enabled)
2092 {
2093     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetStorageAccessAPIEnabled"));
2094     
2095     WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(enabled));
2096     
2097     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
2098 }
2099
2100 void TestRunner::getAllStorageAccessEntries(JSValueRef callback)
2101 {
2102     cacheTestRunnerCallback(AllStorageAccessEntriesCallbackID, callback);
2103     
2104     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("GetAllStorageAccessEntries"));
2105     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), nullptr, nullptr);
2106 }
2107
2108 void TestRunner::callDidReceiveAllStorageAccessEntriesCallback(Vector<String>& domains)
2109 {
2110     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
2111     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
2112     
2113     StringBuilder stringBuilder;
2114     stringBuilder.appendLiteral("[");
2115     bool firstDomain = true;
2116     for (auto& domain : domains) {
2117         if (firstDomain)
2118             firstDomain = false;
2119         else
2120             stringBuilder.appendLiteral(", ");
2121         stringBuilder.appendLiteral("\"");
2122         stringBuilder.append(domain);
2123         stringBuilder.appendLiteral("\"");
2124     }
2125     stringBuilder.appendLiteral("]");
2126     
2127     JSValueRef result = JSValueMakeFromJSONString(context, adopt(JSStringCreateWithUTF8CString(stringBuilder.toString().utf8().data())).get());
2128
2129     callTestRunnerCallback(AllStorageAccessEntriesCallbackID, 1, &result);
2130 }
2131
2132 void TestRunner::addMockMediaDevice(JSStringRef persistentId, JSStringRef label, const char* type)
2133 {
2134     Vector<WKRetainPtr<WKStringRef>> keys;
2135     Vector<WKRetainPtr<WKTypeRef>> values;
2136
2137     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("PersistentID") });
2138     values.append(toWK(persistentId));
2139
2140     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("Label") });
2141     values.append(toWK(label));
2142
2143     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("Type") });
2144     values.append({ AdoptWK, WKStringCreateWithUTF8CString(type) });
2145
2146     Vector<WKStringRef> rawKeys;
2147     Vector<WKTypeRef> rawValues;
2148     rawKeys.resize(keys.size());
2149     rawValues.resize(values.size());
2150
2151     for (size_t i = 0; i < keys.size(); ++i) {
2152         rawKeys[i] = keys[i].get();
2153         rawValues[i] = values[i].get();
2154     }
2155
2156     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("AddMockMediaDevice"));
2157     WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
2158
2159     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
2160 }
2161
2162 void TestRunner::addMockCameraDevice(JSStringRef persistentId, JSStringRef label)
2163 {
2164     addMockMediaDevice(persistentId, label, "camera");
2165 }
2166
2167 void TestRunner::addMockMicrophoneDevice(JSStringRef persistentId, JSStringRef label)
2168 {
2169     addMockMediaDevice(persistentId, label, "microphone");
2170 }
2171
2172 void TestRunner::addMockScreenDevice(JSStringRef persistentId, JSStringRef label)
2173 {
2174     addMockMediaDevice(persistentId, label, "screen");
2175 }
2176
2177 void TestRunner::clearMockMediaDevices()
2178 {
2179     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("ClearMockMediaDevices"));
2180     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), nullptr, nullptr);
2181 }
2182
2183 void TestRunner::removeMockMediaDevice(JSStringRef persistentId)
2184 {
2185     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("RemoveMockMediaDevice"));
2186     WKRetainPtr<WKTypeRef> messageBody(toWK(persistentId));
2187
2188     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
2189 }
2190
2191 void TestRunner::resetMockMediaDevices()
2192 {
2193     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("ResetMockMediaDevices"));
2194     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), nullptr, nullptr);
2195 }
2196
2197 #if PLATFORM(MAC)
2198 void TestRunner::connectMockGamepad(unsigned index)
2199 {
2200     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("ConnectMockGamepad"));
2201     WKRetainPtr<WKTypeRef> messageBody(AdoptWK, WKUInt64Create(index));
2202
2203     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
2204 }
2205
2206 void TestRunner::disconnectMockGamepad(unsigned index)
2207 {
2208     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("DisconnectMockGamepad"));
2209     WKRetainPtr<WKTypeRef> messageBody(AdoptWK, WKUInt64Create(index));
2210
2211     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
2212 }
2213
2214 void TestRunner::setMockGamepadDetails(unsigned index, JSStringRef gamepadID, unsigned axisCount, unsigned buttonCount)
2215 {
2216     Vector<WKRetainPtr<WKStringRef>> keys;
2217     Vector<WKRetainPtr<WKTypeRef>> values;
2218
2219     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("GamepadID") });
2220     values.append(toWK(gamepadID));
2221
2222     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("GamepadIndex") });
2223     values.append({ AdoptWK, WKUInt64Create(index) });
2224
2225     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("AxisCount") });
2226     values.append({ AdoptWK, WKUInt64Create(axisCount) });
2227
2228     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("ButtonCount") });
2229     values.append({ AdoptWK, WKUInt64Create(buttonCount) });
2230
2231     Vector<WKStringRef> rawKeys;
2232     Vector<WKTypeRef> rawValues;
2233     rawKeys.resize(keys.size());
2234     rawValues.resize(values.size());
2235
2236     for (size_t i = 0; i < keys.size(); ++i) {
2237         rawKeys[i] = keys[i].get();
2238         rawValues[i] = values[i].get();
2239     }
2240
2241     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetMockGamepadDetails"));
2242     WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
2243
2244     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
2245 }
2246
2247 void TestRunner::setMockGamepadAxisValue(unsigned index, unsigned axisIndex, double value)
2248 {
2249     Vector<WKRetainPtr<WKStringRef>> keys;
2250     Vector<WKRetainPtr<WKTypeRef>> values;
2251
2252     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("GamepadIndex") });
2253     values.append({ AdoptWK, WKUInt64Create(index) });
2254
2255     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("AxisIndex") });
2256     values.append({ AdoptWK, WKUInt64Create(axisIndex) });
2257
2258     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("Value") });
2259     values.append({ AdoptWK, WKDoubleCreate(value) });
2260
2261     Vector<WKStringRef> rawKeys;
2262     Vector<WKTypeRef> rawValues;
2263     rawKeys.resize(keys.size());
2264     rawValues.resize(values.size());
2265
2266     for (size_t i = 0; i < keys.size(); ++i) {
2267         rawKeys[i] = keys[i].get();
2268         rawValues[i] = values[i].get();
2269     }
2270
2271     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetMockGamepadAxisValue"));
2272     WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
2273
2274     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
2275 }
2276
2277 void TestRunner::setMockGamepadButtonValue(unsigned index, unsigned buttonIndex, double value)
2278 {
2279     Vector<WKRetainPtr<WKStringRef>> keys;
2280     Vector<WKRetainPtr<WKTypeRef>> values;
2281
2282     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("GamepadIndex") });
2283     values.append({ AdoptWK, WKUInt64Create(index) });
2284
2285     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("ButtonIndex") });
2286     values.append({ AdoptWK, WKUInt64Create(buttonIndex) });
2287
2288     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("Value") });
2289     values.append({ AdoptWK, WKDoubleCreate(value) });
2290
2291     Vector<WKStringRef> rawKeys;
2292     Vector<WKTypeRef> rawValues;
2293     rawKeys.resize(keys.size());
2294     rawValues.resize(values.size());
2295
2296     for (size_t i = 0; i < keys.size(); ++i) {
2297         rawKeys[i] = keys[i].get();
2298         rawValues[i] = values[i].get();
2299     }
2300
2301     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetMockGamepadButtonValue"));
2302     WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
2303
2304     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
2305 }
2306 #else
2307 void TestRunner::connectMockGamepad(unsigned)
2308 {
2309 }
2310
2311 void TestRunner::disconnectMockGamepad(unsigned)
2312 {
2313 }
2314
2315 void TestRunner::setMockGamepadDetails(unsigned, JSStringRef, unsigned, unsigned)
2316 {
2317 }
2318
2319 void TestRunner::setMockGamepadAxisValue(unsigned, unsigned, double)
2320 {
2321 }
2322
2323 void TestRunner::setMockGamepadButtonValue(unsigned, unsigned, double)
2324 {
2325 }
2326 #endif // PLATFORM(MAC)
2327
2328 void TestRunner::setOpenPanelFiles(JSValueRef filesValue)
2329 {
2330     WKBundlePageRef page = InjectedBundle::singleton().page()->page();
2331     JSContextRef context = WKBundleFrameGetJavaScriptContext(WKBundlePageGetMainFrame(page));
2332
2333     if (!JSValueIsArray(context, filesValue))
2334         return;
2335
2336     JSObjectRef files = JSValueToObject(context, filesValue, nullptr);
2337     static auto lengthProperty = adopt(JSStringCreateWithUTF8CString("length"));
2338     JSValueRef filesLengthValue = JSObjectGetProperty(context, files, lengthProperty.get(), nullptr);
2339     if (!JSValueIsNumber(context, filesLengthValue))
2340         return;
2341
2342     auto fileURLs = adoptWK(WKMutableArrayCreate());
2343     auto filesLength = static_cast<size_t>(JSValueToNumber(context, filesLengthValue, nullptr));
2344     for (size_t i = 0; i < filesLength; ++i) {
2345         JSValueRef fileValue = JSObjectGetPropertyAtIndex(context, files, i, nullptr);
2346         if (!JSValueIsString(context, fileValue))
2347             continue;
2348
2349         auto file = adopt(JSValueToStringCopy(context, fileValue, nullptr));
2350         size_t fileBufferSize = JSStringGetMaximumUTF8CStringSize(file.get()) + 1;
2351         auto fileBuffer = std::make_unique<char[]>(fileBufferSize);
2352         JSStringGetUTF8CString(file.get(), fileBuffer.get(), fileBufferSize);
2353
2354         WKArrayAppendItem(fileURLs.get(), adoptWK(WKURLCreateWithBaseURL(m_testURL.get(), fileBuffer.get())).get());
2355     }
2356
2357     static auto messageName = adoptWK(WKStringCreateWithUTF8CString("SetOpenPanelFileURLs"));
2358     WKBundlePagePostMessage(page, messageName.get(), fileURLs.get());
2359 }
2360
2361 void TestRunner::removeAllSessionCredentials(JSValueRef callback)
2362 {
2363     cacheTestRunnerCallback(DidRemoveAllSessionCredentialsCallbackID, callback);
2364     
2365     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("RemoveAllSessionCredentials"));
2366     WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(true));
2367     
2368     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
2369 }
2370
2371 void TestRunner::callDidRemoveAllSessionCredentialsCallback()
2372 {
2373     callTestRunnerCallback(DidRemoveAllSessionCredentialsCallbackID);
2374 }
2375
2376 void TestRunner::clearDOMCache(JSStringRef origin)
2377 {
2378     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("ClearDOMCache"));
2379     WKRetainPtr<WKStringRef> messageBody(AdoptWK, WKStringCreateWithJSString(origin));
2380     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
2381 }
2382
2383 void TestRunner::clearDOMCaches()
2384 {
2385     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("ClearDOMCaches"));
2386     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), nullptr, nullptr);
2387 }
2388
2389 bool TestRunner::hasDOMCache(JSStringRef origin)
2390 {
2391     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("HasDOMCache"));
2392     WKRetainPtr<WKStringRef> messageBody(AdoptWK, WKStringCreateWithJSString(origin));
2393     WKTypeRef returnData = nullptr;
2394     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get(), &returnData);
2395     ASSERT(WKGetTypeID(returnData) == WKBooleanGetTypeID());
2396     return WKBooleanGetValue(adoptWK(static_cast<WKBooleanRef>(returnData)).get());
2397 }
2398
2399 uint64_t TestRunner::domCacheSize(JSStringRef origin)
2400 {
2401     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("DOMCacheSize"));
2402     WKRetainPtr<WKStringRef> messageBody(AdoptWK, WKStringCreateWithJSString(origin));
2403     WKTypeRef returnData = nullptr;
2404     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get(), &returnData);
2405     return WKUInt64GetValue(static_cast<WKUInt64Ref>(returnData));
2406 }
2407
2408 void TestRunner::allowCacheStorageQuotaIncrease()
2409 {
2410     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("AllowCacheStorageQuotaIncrease"));
2411     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), nullptr, nullptr);
2412 }
2413
2414 void TestRunner::getApplicationManifestThen(JSValueRef callback)
2415 {
2416     cacheTestRunnerCallback(GetApplicationManifestCallbackID, callback);
2417     
2418     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("GetApplicationManifest"));
2419     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), nullptr, nullptr);
2420 }
2421
2422 void TestRunner::didGetApplicationManifest()
2423 {
2424     callTestRunnerCallback(GetApplicationManifestCallbackID);
2425 }
2426
2427 size_t TestRunner::userScriptInjectedCount() const
2428 {
2429     return InjectedBundle::singleton().userScriptInjectedCount();
2430 }
2431
2432 void TestRunner::injectUserScript(JSStringRef script)
2433 {
2434     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("InjectUserScript"));
2435     WKRetainPtr<WKStringRef> messageBody(AdoptWK, WKStringCreateWithJSString(script));
2436     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get(), nullptr);
2437 }
2438
2439 void TestRunner::sendDisplayConfigurationChangedMessageForTesting()
2440 {
2441     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SendDisplayConfigurationChangedMessageForTesting"));
2442     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), nullptr, nullptr);
2443 }
2444
2445 // WebAuthN
2446 void TestRunner::setWebAuthenticationMockConfiguration(JSValueRef configurationValue)
2447 {
2448     auto& injectedBundle = InjectedBundle::singleton();
2449     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(injectedBundle.page()->page());
2450     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
2451     if (!JSValueIsObject(context, configurationValue))
2452         return;
2453     JSObjectRef configuration = JSValueToObject(context, configurationValue, 0);
2454
2455     Vector<WKRetainPtr<WKStringRef>> configurationKeys;
2456     Vector<WKRetainPtr<WKTypeRef>> configurationValues;
2457
2458     JSRetainPtr<JSStringRef> silentFailurePropertyName(Adopt, JSStringCreateWithUTF8CString("silentFailure"));
2459     JSValueRef silentFailureValue = JSObjectGetProperty(context, configuration, silentFailurePropertyName.get(), 0);
2460     if (!JSValueIsUndefined(context, silentFailureValue)) {
2461         if (!JSValueIsBoolean(context, silentFailureValue))
2462             return;
2463         bool silentFailure = JSValueToBoolean(context, silentFailureValue);
2464         configurationKeys.append({ AdoptWK, WKStringCreateWithUTF8CString("SilentFailure") });
2465         configurationValues.append(adoptWK(WKBooleanCreate(silentFailure)).get());
2466     }
2467
2468     JSRetainPtr<JSStringRef> localPropertyName(Adopt, JSStringCreateWithUTF8CString("local"));
2469     JSValueRef localValue = JSObjectGetProperty(context, configuration, localPropertyName.get(), 0);
2470     if (!JSValueIsUndefined(context, localValue) && !JSValueIsNull(context, localValue)) {
2471         if (!JSValueIsObject(context, localValue))
2472             return;
2473         JSObjectRef local = JSValueToObject(context, localValue, 0);
2474
2475         JSRetainPtr<JSStringRef> acceptAuthenticationPropertyName(Adopt, JSStringCreateWithUTF8CString("acceptAuthentication"));
2476         JSValueRef acceptAuthenticationValue = JSObjectGetProperty(context, local, acceptAuthenticationPropertyName.get(), 0);
2477         if (!JSValueIsBoolean(context, acceptAuthenticationValue))
2478             return;
2479         bool acceptAuthentication = JSValueToBoolean(context, acceptAuthenticationValue);
2480
2481         JSRetainPtr<JSStringRef> acceptAttestationPropertyName(Adopt, JSStringCreateWithUTF8CString("acceptAttestation"));
2482         JSValueRef acceptAttestationValue = JSObjectGetProperty(context, local, acceptAttestationPropertyName.get(), 0);
2483         if (!JSValueIsBoolean(context, acceptAttestationValue))
2484             return;
2485         bool acceptAttestation = JSValueToBoolean(context, acceptAttestationValue);
2486
2487         Vector<WKRetainPtr<WKStringRef>> localKeys;
2488         Vector<WKRetainPtr<WKTypeRef>> localValues;
2489         localKeys.append({ AdoptWK, WKStringCreateWithUTF8CString("AcceptAuthentication") });
2490         localValues.append(adoptWK(WKBooleanCreate(acceptAuthentication)).get());
2491         localKeys.append({ AdoptWK, WKStringCreateWithUTF8CString("AcceptAttestation") });
2492         localValues.append(adoptWK(WKBooleanCreate(acceptAttestation)).get());
2493
2494         if (acceptAttestation) {
2495             JSRetainPtr<JSStringRef> privateKeyBase64PropertyName(Adopt, JSStringCreateWithUTF8CString("privateKeyBase64"));
2496             JSValueRef privateKeyBase64Value = JSObjectGetProperty(context, local, privateKeyBase64PropertyName.get(), 0);
2497             if (!JSValueIsString(context, privateKeyBase64Value))
2498                 return;
2499
2500             JSRetainPtr<JSStringRef> userCertificateBase64PropertyName(Adopt, JSStringCreateWithUTF8CString("userCertificateBase64"));
2501             JSValueRef userCertificateBase64Value = JSObjectGetProperty(context, local, userCertificateBase64PropertyName.get(), 0);
2502             if (!JSValueIsString(context, userCertificateBase64Value))
2503                 return;
2504
2505             JSRetainPtr<JSStringRef> intermediateCACertificateBase64PropertyName(Adopt, JSStringCreateWithUTF8CString("intermediateCACertificateBase64"));
2506             JSValueRef intermediateCACertificateBase64Value = JSObjectGetProperty(context, local, intermediateCACertificateBase64PropertyName.get(), 0);
2507             if (!JSValueIsString(context, intermediateCACertificateBase64Value))
2508             return;
2509
2510             localKeys.append({ AdoptWK, WKStringCreateWithUTF8CString("PrivateKeyBase64") });
2511             localValues.append(toWK(adopt(JSValueToStringCopy(context, privateKeyBase64Value, 0)).get()));
2512             localKeys.append({ AdoptWK, WKStringCreateWithUTF8CString("UserCertificateBase64") });
2513             localValues.append(toWK(adopt(JSValueToStringCopy(context, userCertificateBase64Value, 0)).get()));
2514             localKeys.append({ AdoptWK, WKStringCreateWithUTF8CString("IntermediateCACertificateBase64") });
2515             localValues.append(toWK(adopt(JSValueToStringCopy(context, intermediateCACertificateBase64Value, 0)).get()));
2516         }
2517
2518         Vector<WKStringRef> rawLocalKeys;
2519         Vector<WKTypeRef> rawLocalValues;
2520         rawLocalKeys.resize(localKeys.size());
2521         rawLocalValues.resize(localValues.size());
2522         for (size_t i = 0; i < localKeys.size(); ++i) {
2523             rawLocalKeys[i] = localKeys[i].get();
2524             rawLocalValues[i] = localValues[i].get();
2525         }
2526
2527         configurationKeys.append({ AdoptWK, WKStringCreateWithUTF8CString("Local") });
2528         configurationValues.append({ AdoptWK, WKDictionaryCreate(rawLocalKeys.data(), rawLocalValues.data(), rawLocalKeys.size()) });
2529     }
2530
2531     JSRetainPtr<JSStringRef> hidPropertyName(Adopt, JSStringCreateWithUTF8CString("hid"));
2532     JSValueRef hidValue = JSObjectGetProperty(context, configuration, hidPropertyName.get(), 0);
2533     if (!JSValueIsUndefined(context, hidValue) && !JSValueIsNull(context, hidValue)) {
2534         if (!JSValueIsObject(context, hidValue))
2535             return;
2536         JSObjectRef hid = JSValueToObject(context, hidValue, 0);
2537
2538         JSRetainPtr<JSStringRef> stagePropertyName(Adopt, JSStringCreateWithUTF8CString("stage"));
2539         JSValueRef stageValue = JSObjectGetProperty(context, hid, stagePropertyName.get(), 0);
2540         if (!JSValueIsString(context, stageValue))
2541             return;
2542
2543         JSRetainPtr<JSStringRef> subStagePropertyName(Adopt, JSStringCreateWithUTF8CString("subStage"));
2544         JSValueRef subStageValue = JSObjectGetProperty(context, hid, subStagePropertyName.get(), 0);
2545         if (!JSValueIsString(context, subStageValue))
2546             return;
2547
2548         JSRetainPtr<JSStringRef> errorPropertyName(Adopt, JSStringCreateWithUTF8CString("error"));
2549         JSValueRef errorValue = JSObjectGetProperty(context, hid, errorPropertyName.get(), 0);
2550         if (!JSValueIsString(context, errorValue))
2551             return;
2552
2553         Vector<WKRetainPtr<WKStringRef>> hidKeys;
2554         Vector<WKRetainPtr<WKTypeRef>> hidValues;
2555         hidKeys.append({ AdoptWK, WKStringCreateWithUTF8CString("Stage") });
2556         hidValues.append(toWK(adopt(JSValueToStringCopy(context, stageValue, 0)).get()));
2557         hidKeys.append({ AdoptWK, WKStringCreateWithUTF8CString("SubStage") });
2558         hidValues.append(toWK(adopt(JSValueToStringCopy(context, subStageValue, 0)).get()));
2559         hidKeys.append({ AdoptWK, WKStringCreateWithUTF8CString("Error") });
2560         hidValues.append(toWK(adopt(JSValueToStringCopy(context, errorValue, 0)).get()));
2561
2562         JSRetainPtr<JSStringRef> payloadBase64PropertyName(Adopt, JSStringCreateWithUTF8CString("payloadBase64"));
2563         JSValueRef payloadBase64Value = JSObjectGetProperty(context, hid, payloadBase64PropertyName.get(), 0);
2564         if (!JSValueIsUndefined(context, payloadBase64Value) && !JSValueIsNull(context, payloadBase64Value)) {
2565             if (!JSValueIsArray(context, payloadBase64Value))
2566                 return;
2567
2568             JSObjectRef payloadBase64 = JSValueToObject(context, payloadBase64Value, nullptr);
2569             static auto lengthProperty = adopt(JSStringCreateWithUTF8CString("length"));
2570             JSValueRef payloadBase64LengthValue = JSObjectGetProperty(context, payloadBase64, lengthProperty.get(), nullptr);
2571             if (!JSValueIsNumber(context, payloadBase64LengthValue))
2572                 return;
2573
2574             auto payloadBase64s = adoptWK(WKMutableArrayCreate());
2575             auto payloadBase64Length = static_cast<size_t>(JSValueToNumber(context, payloadBase64LengthValue, nullptr));
2576             for (size_t i = 0; i < payloadBase64Length; ++i) {
2577                 JSValueRef payloadBase64Value = JSObjectGetPropertyAtIndex(context, payloadBase64, i, nullptr);
2578                 if (!JSValueIsString(context, payloadBase64Value))
2579                     continue;
2580                 WKArrayAppendItem(payloadBase64s.get(), toWK(adopt(JSValueToStringCopy(context, payloadBase64Value, 0)).get()).get());
2581             }
2582
2583             hidKeys.append({ AdoptWK, WKStringCreateWithUTF8CString("PayloadBase64") });
2584             hidValues.append(payloadBase64s);
2585         }
2586
2587         JSRetainPtr<JSStringRef> isU2fPropertyName(Adopt, JSStringCreateWithUTF8CString("isU2f"));
2588         JSValueRef isU2fValue = JSObjectGetProperty(context, hid, isU2fPropertyName.get(), 0);
2589         if (!JSValueIsUndefined(context, isU2fValue) && !JSValueIsNull(context, isU2fValue)) {
2590             if (!JSValueIsBoolean(context, isU2fValue))
2591                 return;
2592             bool isU2f = JSValueToBoolean(context, isU2fValue);
2593             hidKeys.append({ AdoptWK, WKStringCreateWithUTF8CString("IsU2f") });
2594             hidValues.append(adoptWK(WKBooleanCreate(isU2f)).get());
2595         }
2596
2597         JSRetainPtr<JSStringRef> keepAlivePropertyName(Adopt, JSStringCreateWithUTF8CString("keepAlive"));
2598         JSValueRef keepAliveValue = JSObjectGetProperty(context, hid, keepAlivePropertyName.get(), 0);
2599         if (!JSValueIsUndefined(context, keepAliveValue) && !JSValueIsNull(context, keepAliveValue)) {
2600             if (!JSValueIsBoolean(context, keepAliveValue))
2601                 return;
2602             bool keepAlive = JSValueToBoolean(context, keepAliveValue);
2603             hidKeys.append({ AdoptWK, WKStringCreateWithUTF8CString("KeepAlive") });
2604             hidValues.append(adoptWK(WKBooleanCreate(keepAlive)).get());
2605         }
2606
2607         JSRetainPtr<JSStringRef> fastDataArrivalPropertyName(Adopt, JSStringCreateWithUTF8CString("fastDataArrival"));
2608         JSValueRef fastDataArrivalValue = JSObjectGetProperty(context, hid, fastDataArrivalPropertyName.get(), 0);
2609         if (!JSValueIsUndefined(context, fastDataArrivalValue) && !JSValueIsNull(context, fastDataArrivalValue)) {
2610             if (!JSValueIsBoolean(context, fastDataArrivalValue))
2611                 return;
2612             bool fastDataArrival = JSValueToBoolean(context, fastDataArrivalValue);
2613             hidKeys.append({ AdoptWK, WKStringCreateWithUTF8CString("FastDataArrival") });
2614             hidValues.append(adoptWK(WKBooleanCreate(fastDataArrival)).get());
2615         }
2616
2617         JSRetainPtr<JSStringRef> continueAfterErrorDataPropertyName(Adopt, JSStringCreateWithUTF8CString("continueAfterErrorData"));
2618         JSValueRef continueAfterErrorDataValue = JSObjectGetProperty(context, hid, continueAfterErrorDataPropertyName.get(), 0);
2619         if (!JSValueIsUndefined(context, continueAfterErrorDataValue) && !JSValueIsNull(context, continueAfterErrorDataValue)) {
2620             if (!JSValueIsBoolean(context, continueAfterErrorDataValue))
2621                 return;
2622             bool continueAfterErrorData = JSValueToBoolean(context, continueAfterErrorDataValue);
2623             hidKeys.append({ AdoptWK, WKStringCreateWithUTF8CString("ContinueAfterErrorData") });
2624             hidValues.append(adoptWK(WKBooleanCreate(continueAfterErrorData)).get());
2625         }
2626
2627         Vector<WKStringRef> rawHidKeys;
2628         Vector<WKTypeRef> rawHidValues;
2629         rawHidKeys.resize(hidKeys.size());
2630         rawHidValues.resize(hidValues.size());
2631         for (size_t i = 0; i < hidKeys.size(); ++i) {
2632             rawHidKeys[i] = hidKeys[i].get();
2633             rawHidValues[i] = hidValues[i].get();
2634         }
2635
2636         configurationKeys.append({ AdoptWK, WKStringCreateWithUTF8CString("Hid") });
2637         configurationValues.append({ AdoptWK, WKDictionaryCreate(rawHidKeys.data(), rawHidValues.data(), rawHidKeys.size()) });
2638     }
2639
2640     Vector<WKStringRef> rawConfigurationKeys;
2641     Vector<WKTypeRef> rawConfigurationValues;
2642     rawConfigurationKeys.resize(configurationKeys.size());
2643     rawConfigurationValues.resize(configurationValues.size());
2644     for (size_t i = 0; i < configurationKeys.size(); ++i) {
2645         rawConfigurationKeys[i] = configurationKeys[i].get();
2646         rawConfigurationValues[i] = configurationValues[i].get();
2647     }
2648
2649     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetWebAuthenticationMockConfiguration"));
2650     WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawConfigurationKeys.data(), rawConfigurationValues.data(), rawConfigurationKeys.size()));
2651     
2652     WKBundlePostSynchronousMessage(injectedBundle.bundle(), messageName.get(), messageBody.get(), nullptr);
2653 }
2654
2655 void TestRunner::addTestKeyToKeychain(JSStringRef privateKeyBase64, JSStringRef attrLabel, JSStringRef applicationTagBase64)
2656 {
2657     Vector<WKRetainPtr<WKStringRef>> keys;
2658     Vector<WKRetainPtr<WKTypeRef>> values;
2659
2660     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("PrivateKey") });
2661     values.append(toWK(privateKeyBase64));
2662
2663     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("AttrLabel") });
2664     values.append(toWK(attrLabel));
2665
2666     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("ApplicationTag") });
2667     values.append(toWK(applicationTagBase64));
2668
2669     Vector<WKStringRef> rawKeys;
2670     Vector<WKTypeRef> rawValues;
2671     rawKeys.resize(keys.size());
2672     rawValues.resize(values.size());
2673
2674     for (size_t i = 0; i < keys.size(); ++i) {
2675         rawKeys[i] = keys[i].get();
2676         rawValues[i] = values[i].get();
2677     }
2678
2679     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("AddTestKeyToKeychain"));
2680     WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
2681
2682     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
2683 }
2684
2685 void TestRunner::cleanUpKeychain(JSStringRef attrLabel)
2686 {
2687     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("CleanUpKeychain"));
2688     WKRetainPtr<WKStringRef> messageBody(AdoptWK, WKStringCreateWithJSString(attrLabel));
2689
2690     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
2691 }
2692
2693 bool TestRunner::keyExistsInKeychain(JSStringRef attrLabel, JSStringRef applicationTagBase64)
2694 {
2695     Vector<WKRetainPtr<WKStringRef>> keys;
2696     Vector<WKRetainPtr<WKTypeRef>> values;
2697
2698     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("AttrLabel") });
2699     values.append(toWK(attrLabel));
2700
2701     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("ApplicationTag") });
2702     values.append(toWK(applicationTagBase64));
2703
2704     Vector<WKStringRef> rawKeys;
2705     Vector<WKTypeRef> rawValues;
2706     rawKeys.resize(keys.size());
2707     rawValues.resize(values.size());
2708
2709     for (size_t i = 0; i < keys.size(); ++i) {
2710         rawKeys[i] = keys[i].get();
2711         rawValues[i] = values[i].get();
2712     }
2713
2714     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("KeyExistsInKeychain"));
2715     WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
2716
2717     WKTypeRef returnData = nullptr;
2718     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), &returnData);
2719     ASSERT(WKGetTypeID(returnData) == WKBooleanGetTypeID());
2720     return WKBooleanGetValue(adoptWK(static_cast<WKBooleanRef>(returnData)).get());
2721 }
2722
2723 void TestRunner::setCanHandleHTTPSServerTrustEvaluation(bool canHandle)
2724 {
2725     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetCanHandleHTTPSServerTrustEvaluation"));
2726     WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(canHandle));
2727     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
2728 }
2729
2730 bool TestRunner::canDoServerTrustEvaluationInNetworkProcess()
2731 {
2732     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("CanDoServerTrustEvaluationInNetworkProcess"));
2733     WKTypeRef returnData = nullptr;
2734     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), nullptr, &returnData);
2735     ASSERT(WKGetTypeID(returnData) == WKBooleanGetTypeID());
2736     return WKBooleanGetValue(adoptWK(static_cast<WKBooleanRef>(returnData)).get());
2737 }
2738
2739 unsigned long TestRunner::serverTrustEvaluationCallbackCallsCount()
2740 {
2741     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("ServerTrustEvaluationCallbackCallsCount"));
2742     WKTypeRef returnData = nullptr;
2743     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), nullptr, &returnData);
2744     ASSERT(WKGetTypeID(returnData) == WKUInt64GetTypeID());
2745     return WKUInt64GetValue(adoptWK(static_cast<WKUInt64Ref>(returnData)).get());
2746 }
2747
2748 void TestRunner::setShouldDismissJavaScriptAlertsAsynchronously(bool shouldDismissAsynchronously)
2749 {
2750     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("ShouldDismissJavaScriptAlertsAsynchronously"));
2751     WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(shouldDismissAsynchronously));
2752     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
2753 }
2754
2755 void TestRunner::dumpAdClickAttribution()
2756 {
2757     auto messageName = adoptWK(WKStringCreateWithUTF8CString("dumpAdClickAttribution"));
2758     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), nullptr, nullptr);
2759 }
2760
2761 void TestRunner::clearAdClickAttribution()
2762 {
2763     auto messageName = adoptWK(WKStringCreateWithUTF8CString("clearAdClickAttribution"));
2764     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), nullptr, nullptr);
2765 }
2766
2767 } // namespace WTR