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