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