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