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