Add a way to test file input without relying on drag and drop
[WebKit-https.git] / Tools / WebKitTestRunner / InjectedBundle / TestRunner.cpp
1 /*
2  * Copyright (C) 2010-2017 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "TestRunner.h"
28
29 #include "InjectedBundle.h"
30 #include "InjectedBundlePage.h"
31 #include "JSTestRunner.h"
32 #include "PlatformWebView.h"
33 #include "StringFunctions.h"
34 #include "TestController.h"
35 #include <JavaScriptCore/JSCTestRunnerUtils.h>
36 #include <WebCore/ResourceLoadObserver.h>
37 #include <WebKit/WKBundle.h>
38 #include <WebKit/WKBundleBackForwardList.h>
39 #include <WebKit/WKBundleFrame.h>
40 #include <WebKit/WKBundleFramePrivate.h>
41 #include <WebKit/WKBundleInspector.h>
42 #include <WebKit/WKBundleNodeHandlePrivate.h>
43 #include <WebKit/WKBundlePage.h>
44 #include <WebKit/WKBundlePagePrivate.h>
45 #include <WebKit/WKBundlePrivate.h>
46 #include <WebKit/WKBundleScriptWorld.h>
47 #include <WebKit/WKData.h>
48 #include <WebKit/WKPagePrivate.h>
49 #include <WebKit/WKRetainPtr.h>
50 #include <WebKit/WKSerializedScriptValue.h>
51 #include <WebKit/WebKit2_C.h>
52 #include <wtf/CurrentTime.h>
53 #include <wtf/HashMap.h>
54 #include <wtf/StdLibExtras.h>
55 #include <wtf/text/CString.h>
56 #include <wtf/text/StringBuilder.h>
57
58 namespace WTR {
59
60 Ref<TestRunner> TestRunner::create()
61 {
62     return adoptRef(*new TestRunner);
63 }
64
65 TestRunner::TestRunner()
66     : m_whatToDump(RenderTree)
67     , m_shouldDumpAllFrameScrollPositions(false)
68     , m_shouldDumpBackForwardListsForAllWindows(false)
69     , m_shouldAllowEditing(true)
70     , m_shouldCloseExtraWindows(false)
71     , m_dumpEditingCallbacks(false)
72     , m_dumpStatusCallbacks(false)
73     , m_dumpTitleChanges(false)
74     , m_dumpPixels(true)
75     , m_dumpSelectionRect(false)
76     , m_dumpFullScreenCallbacks(false)
77     , m_dumpFrameLoadCallbacks(false)
78     , m_dumpProgressFinishedCallback(false)
79     , m_dumpResourceLoadCallbacks(false)
80     , m_dumpResourceResponseMIMETypes(false)
81     , m_dumpWillCacheResponse(false)
82     , m_dumpApplicationCacheDelegateCallbacks(false)
83     , m_dumpDatabaseCallbacks(false)
84     , m_disallowIncreaseForApplicationCacheQuota(false)
85     , m_waitToDump(false)
86     , m_testRepaint(false)
87     , m_testRepaintSweepHorizontally(false)
88     , m_isPrinting(false)
89     , m_willSendRequestReturnsNull(false)
90     , m_willSendRequestReturnsNullOnRedirect(false)
91     , m_shouldStopProvisionalFrameLoads(false)
92     , m_policyDelegateEnabled(false)
93     , m_policyDelegatePermissive(false)
94     , m_globalFlag(false)
95     , m_customFullScreenBehavior(false)
96     , m_timeout(30000)
97     , m_databaseDefaultQuota(-1)
98     , m_databaseMaxQuota(-1)
99     , m_userStyleSheetEnabled(false)
100     , m_userStyleSheetLocation(adoptWK(WKStringCreateWithUTF8CString("")))
101 #if PLATFORM(GTK)
102     , m_waitToDumpWatchdogTimer(RunLoop::main(), this, &TestRunner::waitToDumpWatchdogTimerFired)
103 #endif
104 {
105     platformInitialize();
106 }
107
108 TestRunner::~TestRunner()
109 {
110 }
111
112 JSClassRef TestRunner::wrapperClass()
113 {
114     return JSTestRunner::testRunnerClass();
115 }
116
117 void TestRunner::display()
118 {
119     WKBundlePageRef page = InjectedBundle::singleton().page()->page();
120     WKBundlePageForceRepaint(page);
121     WKBundlePageSetTracksRepaints(page, true);
122     WKBundlePageResetTrackedRepaints(page);
123 }
124
125 void TestRunner::dumpAsText(bool dumpPixels)
126 {
127     if (m_whatToDump < MainFrameText)
128         m_whatToDump = MainFrameText;
129     m_dumpPixels = dumpPixels;
130 }
131
132 void TestRunner::setCustomPolicyDelegate(bool enabled, bool permissive)
133 {
134     m_policyDelegateEnabled = enabled;
135     m_policyDelegatePermissive = permissive;
136
137     InjectedBundle::singleton().setCustomPolicyDelegate(enabled, permissive);
138 }
139
140 void TestRunner::waitForPolicyDelegate()
141 {
142     setCustomPolicyDelegate(true);
143     waitUntilDone();
144 }
145
146 void TestRunner::waitUntilDownloadFinished()
147 {
148     m_shouldFinishAfterDownload = true;
149     waitUntilDone();
150 }
151
152 void TestRunner::waitUntilDone()
153 {
154     m_waitToDump = true;
155     if (InjectedBundle::singleton().useWaitToDumpWatchdogTimer())
156         initializeWaitToDumpWatchdogTimerIfNeeded();
157 }
158
159 void TestRunner::waitToDumpWatchdogTimerFired()
160 {
161     invalidateWaitToDumpWatchdogTimer();
162     auto& injectedBundle = InjectedBundle::singleton();
163 #if PLATFORM(COCOA)
164     char buffer[1024];
165     snprintf(buffer, sizeof(buffer), "#PID UNRESPONSIVE - %s (pid %d)\n", getprogname(), getpid());
166     injectedBundle.outputText(buffer);
167 #endif
168     injectedBundle.outputText("FAIL: Timed out waiting for notifyDone to be called\n\n");
169     injectedBundle.done();
170 }
171
172 void TestRunner::notifyDone()
173 {
174     auto& injectedBundle = InjectedBundle::singleton();
175     if (!injectedBundle.isTestRunning())
176         return;
177
178     if (m_waitToDump && !injectedBundle.topLoadingFrame())
179         injectedBundle.page()->dump();
180
181     // We don't call invalidateWaitToDumpWatchdogTimer() here, even if we continue to wait for a load to finish.
182     // The test is still subject to timeout checking - it is better to detect an async timeout inside WebKitTestRunner
183     // than to let webkitpy do that, because WebKitTestRunner will dump partial results.
184
185     m_waitToDump = false;
186 }
187
188 unsigned TestRunner::imageCountInGeneralPasteboard() const
189 {
190     return InjectedBundle::singleton().imageCountInGeneralPasteboard();
191 }
192
193 void TestRunner::addUserScript(JSStringRef source, bool runAtStart, bool allFrames)
194 {
195     WKRetainPtr<WKStringRef> sourceWK = toWK(source);
196
197     WKBundlePageAddUserScript(InjectedBundle::singleton().page()->page(), sourceWK.get(),
198         (runAtStart ? kWKInjectAtDocumentStart : kWKInjectAtDocumentEnd),
199         (allFrames ? kWKInjectInAllFrames : kWKInjectInTopFrameOnly));
200 }
201
202 void TestRunner::addUserStyleSheet(JSStringRef source, bool allFrames)
203 {
204     WKRetainPtr<WKStringRef> sourceWK = toWK(source);
205
206     WKBundlePageAddUserStyleSheet(InjectedBundle::singleton().page()->page(), sourceWK.get(),
207         (allFrames ? kWKInjectInAllFrames : kWKInjectInTopFrameOnly));
208 }
209
210 void TestRunner::keepWebHistory()
211 {
212     InjectedBundle::singleton().postSetAddsVisitedLinks(true);
213 }
214
215 void TestRunner::execCommand(JSStringRef name, JSStringRef argument)
216 {
217     WKBundlePageExecuteEditingCommand(InjectedBundle::singleton().page()->page(), toWK(name).get(), toWK(argument).get());
218 }
219
220 bool TestRunner::findString(JSStringRef target, JSValueRef optionsArrayAsValue)
221 {
222     WKFindOptions options = 0;
223
224     auto& injectedBundle = InjectedBundle::singleton();
225     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(injectedBundle.page()->page());
226     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
227     JSRetainPtr<JSStringRef> lengthPropertyName(Adopt, JSStringCreateWithUTF8CString("length"));
228     JSObjectRef optionsArray = JSValueToObject(context, optionsArrayAsValue, 0);
229     JSValueRef lengthValue = JSObjectGetProperty(context, optionsArray, lengthPropertyName.get(), 0);
230     if (!JSValueIsNumber(context, lengthValue))
231         return false;
232
233     size_t length = static_cast<size_t>(JSValueToNumber(context, lengthValue, 0));
234     for (size_t i = 0; i < length; ++i) {
235         JSValueRef value = JSObjectGetPropertyAtIndex(context, optionsArray, i, 0);
236         if (!JSValueIsString(context, value))
237             continue;
238
239         JSRetainPtr<JSStringRef> optionName(Adopt, JSValueToStringCopy(context, value, 0));
240
241         if (JSStringIsEqualToUTF8CString(optionName.get(), "CaseInsensitive"))
242             options |= kWKFindOptionsCaseInsensitive;
243         else if (JSStringIsEqualToUTF8CString(optionName.get(), "AtWordStarts"))
244             options |= kWKFindOptionsAtWordStarts;
245         else if (JSStringIsEqualToUTF8CString(optionName.get(), "TreatMedialCapitalAsWordStart"))
246             options |= kWKFindOptionsTreatMedialCapitalAsWordStart;
247         else if (JSStringIsEqualToUTF8CString(optionName.get(), "Backwards"))
248             options |= kWKFindOptionsBackwards;
249         else if (JSStringIsEqualToUTF8CString(optionName.get(), "WrapAround"))
250             options |= kWKFindOptionsWrapAround;
251         else if (JSStringIsEqualToUTF8CString(optionName.get(), "StartInSelection")) {
252             // FIXME: No kWKFindOptionsStartInSelection.
253         }
254     }
255
256     return WKBundlePageFindString(injectedBundle.page()->page(), toWK(target).get(), options);
257 }
258
259 void TestRunner::clearAllDatabases()
260 {
261     WKBundleClearAllDatabases(InjectedBundle::singleton().bundle());
262
263     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("DeleteAllIndexedDatabases"));
264     WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(true));
265
266     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
267 }
268
269 void TestRunner::setDatabaseQuota(uint64_t quota)
270 {
271     return WKBundleSetDatabaseQuota(InjectedBundle::singleton().bundle(), quota);
272 }
273
274 void TestRunner::clearAllApplicationCaches()
275 {
276     WKBundlePageClearApplicationCache(InjectedBundle::singleton().page()->page());
277 }
278
279 void TestRunner::clearApplicationCacheForOrigin(JSStringRef origin)
280 {
281     WKBundlePageClearApplicationCacheForOrigin(InjectedBundle::singleton().page()->page(), toWK(origin).get());
282 }
283
284 void TestRunner::setAppCacheMaximumSize(uint64_t size)
285 {
286     WKBundlePageSetAppCacheMaximumSize(InjectedBundle::singleton().page()->page(), size);
287 }
288
289 long long TestRunner::applicationCacheDiskUsageForOrigin(JSStringRef origin)
290 {
291     return WKBundlePageGetAppCacheUsageForOrigin(InjectedBundle::singleton().page()->page(), toWK(origin).get());
292 }
293
294 void TestRunner::disallowIncreaseForApplicationCacheQuota()
295 {
296     m_disallowIncreaseForApplicationCacheQuota = true;
297 }
298
299 static inline JSValueRef stringArrayToJS(JSContextRef context, WKArrayRef strings)
300 {
301     const size_t count = WKArrayGetSize(strings);
302
303     JSValueRef arrayResult = JSObjectMakeArray(context, 0, 0, 0);
304     JSObjectRef arrayObj = JSValueToObject(context, arrayResult, 0);
305     for (size_t i = 0; i < count; ++i) {
306         WKStringRef stringRef = static_cast<WKStringRef>(WKArrayGetItemAtIndex(strings, i));
307         JSRetainPtr<JSStringRef> stringJS = toJS(stringRef);
308         JSObjectSetPropertyAtIndex(context, arrayObj, i, JSValueMakeString(context, stringJS.get()), 0);
309     }
310
311     return arrayResult;
312 }
313
314 JSValueRef TestRunner::originsWithApplicationCache()
315 {
316     WKBundlePageRef page = InjectedBundle::singleton().page()->page();
317
318     WKRetainPtr<WKArrayRef> origins(AdoptWK, WKBundlePageCopyOriginsWithApplicationCache(page));
319
320     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(page);
321     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
322
323     return stringArrayToJS(context, origins.get());
324 }
325
326 bool TestRunner::isCommandEnabled(JSStringRef name)
327 {
328     return WKBundlePageIsEditingCommandEnabled(InjectedBundle::singleton().page()->page(), toWK(name).get());
329 }
330
331 void TestRunner::setCanOpenWindows(bool)
332 {
333     // The test plugins/get-url-with-blank-target.html requires that the embedding client forbid
334     // opening windows (by omitting a call to this function) so as to test that NPN_GetURL()
335     // with a blank target will return an error.
336     //
337     // It is not clear if we should implement this functionality or remove it and plugins/get-url-with-blank-target.html
338     // per the remark in <https://trac.webkit.org/changeset/64504/trunk/LayoutTests/platform/mac-wk2/Skipped>.
339     // For now, just ignore this setting.
340 }
341
342 void TestRunner::setXSSAuditorEnabled(bool enabled)
343 {
344     WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitXSSAuditorEnabled"));
345     auto& injectedBundle = InjectedBundle::singleton();
346     WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
347 }
348
349 void TestRunner::setShadowDOMEnabled(bool enabled)
350 {
351     WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitShadowDOMEnabled"));
352     auto& injectedBundle = InjectedBundle::singleton();
353     WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
354 }
355
356 void TestRunner::setCustomElementsEnabled(bool enabled)
357 {
358     WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitCustomElementsEnabled"));
359     auto& injectedBundle = InjectedBundle::singleton();
360     WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
361 }
362
363 void TestRunner::setSubtleCryptoEnabled(bool enabled)
364 {
365     WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitSubtleCryptoEnabled"));
366     auto& injectedBundle = InjectedBundle::singleton();
367     WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
368 }
369
370 void TestRunner::setMediaStreamEnabled(bool enabled)
371 {
372     WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitMediaStreamEnabled"));
373     auto& injectedBundle = InjectedBundle::singleton();
374     WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
375 }
376
377 void TestRunner::setPeerConnectionEnabled(bool enabled)
378 {
379     WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitPeerConnectionEnabled"));
380     auto& injectedBundle = InjectedBundle::singleton();
381     WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
382 }
383
384 void TestRunner::setModernMediaControlsEnabled(bool enabled)
385 {
386     WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitModernMediaControlsEnabled"));
387     auto& injectedBundle = InjectedBundle::singleton();
388     WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
389 }
390
391 void TestRunner::setWebGL2Enabled(bool enabled)
392 {
393     WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitWebGL2Enabled"));
394     auto& injectedBundle = InjectedBundle::singleton();
395     WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
396 }
397
398 void TestRunner::setFetchAPIEnabled(bool enabled)
399 {
400     WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitFetchAPIEnabled"));
401     auto& injectedBundle = InjectedBundle::singleton();
402     WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
403 }
404
405 void TestRunner::setDownloadAttributeEnabled(bool enabled)
406 {
407     WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitDownloadAttributeEnabled"));
408     auto& injectedBundle = InjectedBundle::singleton();
409     WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
410 }
411
412 void TestRunner::setEncryptedMediaAPIEnabled(bool enabled)
413 {
414     WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitEncryptedMediaAPIEnabled"));
415     auto& injectedBundle = InjectedBundle::singleton();
416     WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
417 }
418
419 void TestRunner::setAllowsAnySSLCertificate(bool enabled)
420 {
421     InjectedBundle::singleton().setAllowsAnySSLCertificate(enabled);
422 }
423
424 void TestRunner::setAllowUniversalAccessFromFileURLs(bool enabled)
425 {
426     auto& injectedBundle = InjectedBundle::singleton();
427     WKBundleSetAllowUniversalAccessFromFileURLs(injectedBundle.bundle(), injectedBundle.pageGroup(), enabled);
428 }
429
430 void TestRunner::setAllowFileAccessFromFileURLs(bool enabled)
431 {
432     auto& injectedBundle = InjectedBundle::singleton();
433     WKBundleSetAllowFileAccessFromFileURLs(injectedBundle.bundle(), injectedBundle.pageGroup(), enabled);
434 }
435
436 void TestRunner::setNeedsStorageAccessFromFileURLsQuirk(bool needsQuirk)
437 {
438     auto& injectedBundle = InjectedBundle::singleton();
439     WKBundleSetAllowStorageAccessFromFileURLS(injectedBundle.bundle(), injectedBundle.pageGroup(), needsQuirk);
440 }
441     
442 void TestRunner::setPluginsEnabled(bool enabled)
443 {
444     WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitPluginsEnabled"));
445     auto& injectedBundle = InjectedBundle::singleton();
446     WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
447 }
448
449 void TestRunner::setJavaScriptCanAccessClipboard(bool enabled)
450 {
451     auto& injectedBundle = InjectedBundle::singleton();
452     WKBundleSetJavaScriptCanAccessClipboard(injectedBundle.bundle(), injectedBundle.pageGroup(), enabled);
453 }
454
455 void TestRunner::setPrivateBrowsingEnabled(bool enabled)
456 {
457     auto& injectedBundle = InjectedBundle::singleton();
458     WKBundleSetPrivateBrowsingEnabled(injectedBundle.bundle(), injectedBundle.pageGroup(), enabled);
459 }
460
461 void TestRunner::setUseDashboardCompatibilityMode(bool enabled)
462 {
463 #if ENABLE(DASHBOARD_SUPPORT)
464     auto& injectedBundle = InjectedBundle::singleton();
465     WKBundleSetUseDashboardCompatibilityMode(injectedBundle.bundle(), injectedBundle.pageGroup(), enabled);
466 #endif
467 }
468     
469 void TestRunner::setPopupBlockingEnabled(bool enabled)
470 {
471     auto& injectedBundle = InjectedBundle::singleton();
472     WKBundleSetPopupBlockingEnabled(injectedBundle.bundle(), injectedBundle.pageGroup(), enabled);
473 }
474
475 void TestRunner::setAuthorAndUserStylesEnabled(bool enabled)
476 {
477     auto& injectedBundle = InjectedBundle::singleton();
478     WKBundleSetAuthorAndUserStylesEnabled(injectedBundle.bundle(), injectedBundle.pageGroup(), enabled);
479 }
480
481 void TestRunner::addOriginAccessWhitelistEntry(JSStringRef sourceOrigin, JSStringRef destinationProtocol, JSStringRef destinationHost, bool allowDestinationSubdomains)
482 {
483     WKBundleAddOriginAccessWhitelistEntry(InjectedBundle::singleton().bundle(), toWK(sourceOrigin).get(), toWK(destinationProtocol).get(), toWK(destinationHost).get(), allowDestinationSubdomains);
484 }
485
486 void TestRunner::removeOriginAccessWhitelistEntry(JSStringRef sourceOrigin, JSStringRef destinationProtocol, JSStringRef destinationHost, bool allowDestinationSubdomains)
487 {
488     WKBundleRemoveOriginAccessWhitelistEntry(InjectedBundle::singleton().bundle(), toWK(sourceOrigin).get(), toWK(destinationProtocol).get(), toWK(destinationHost).get(), allowDestinationSubdomains);
489 }
490
491 bool TestRunner::isPageBoxVisible(int pageIndex)
492 {
493     auto& injectedBundle = InjectedBundle::singleton();
494     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(injectedBundle.page()->page());
495     return WKBundleIsPageBoxVisible(injectedBundle.bundle(), mainFrame, pageIndex);
496 }
497
498 void TestRunner::setValueForUser(JSContextRef context, JSValueRef element, JSStringRef value)
499 {
500     if (!element || !JSValueIsObject(context, element))
501         return;
502
503     WKRetainPtr<WKBundleNodeHandleRef> nodeHandle(AdoptWK, WKBundleNodeHandleCreate(context, const_cast<JSObjectRef>(element)));
504     WKBundleNodeHandleSetHTMLInputElementValueForUser(nodeHandle.get(), toWK(value).get());
505 }
506
507 void TestRunner::setAudioResult(JSContextRef context, JSValueRef data)
508 {
509     auto& injectedBundle = InjectedBundle::singleton();
510     // FIXME (123058): Use a JSC API to get buffer contents once such is exposed.
511     WKRetainPtr<WKDataRef> audioData(AdoptWK, WKBundleCreateWKDataFromUInt8Array(injectedBundle.bundle(), context, data));
512     injectedBundle.setAudioResult(audioData.get());
513     m_whatToDump = Audio;
514     m_dumpPixels = false;
515 }
516
517 unsigned TestRunner::windowCount()
518 {
519     return InjectedBundle::singleton().pageCount();
520 }
521
522 void TestRunner::clearBackForwardList()
523 {
524     WKBundleBackForwardListClear(WKBundlePageGetBackForwardList(InjectedBundle::singleton().page()->page()));
525 }
526
527 // Object Creation
528
529 void TestRunner::makeWindowObject(JSContextRef context, JSObjectRef windowObject, JSValueRef* exception)
530 {
531     setProperty(context, windowObject, "testRunner", this, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete, exception);
532 }
533
534 void TestRunner::showWebInspector()
535 {
536     WKBundleInspectorShow(WKBundlePageGetInspector(InjectedBundle::singleton().page()->page()));
537 }
538
539 void TestRunner::closeWebInspector()
540 {
541     WKBundleInspectorClose(WKBundlePageGetInspector(InjectedBundle::singleton().page()->page()));
542 }
543
544 void TestRunner::evaluateInWebInspector(JSStringRef script)
545 {
546     WKRetainPtr<WKStringRef> scriptWK = toWK(script);
547     WKBundleInspectorEvaluateScriptForTest(WKBundlePageGetInspector(InjectedBundle::singleton().page()->page()), scriptWK.get());
548 }
549
550 typedef WTF::HashMap<unsigned, WKRetainPtr<WKBundleScriptWorldRef> > WorldMap;
551 static WorldMap& worldMap()
552 {
553     static WorldMap& map = *new WorldMap;
554     return map;
555 }
556
557 unsigned TestRunner::worldIDForWorld(WKBundleScriptWorldRef world)
558 {
559     WorldMap::const_iterator end = worldMap().end();
560     for (WorldMap::const_iterator it = worldMap().begin(); it != end; ++it) {
561         if (it->value == world)
562             return it->key;
563     }
564
565     return 0;
566 }
567
568 void TestRunner::evaluateScriptInIsolatedWorld(JSContextRef context, unsigned worldID, JSStringRef script)
569 {
570     // A worldID of 0 always corresponds to a new world. Any other worldID corresponds to a world
571     // that is created once and cached forever.
572     WKRetainPtr<WKBundleScriptWorldRef> world;
573     if (!worldID)
574         world.adopt(WKBundleScriptWorldCreateWorld());
575     else {
576         WKRetainPtr<WKBundleScriptWorldRef>& worldSlot = worldMap().add(worldID, nullptr).iterator->value;
577         if (!worldSlot)
578             worldSlot.adopt(WKBundleScriptWorldCreateWorld());
579         world = worldSlot;
580     }
581
582     WKBundleFrameRef frame = WKBundleFrameForJavaScriptContext(context);
583     if (!frame)
584         frame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
585
586     JSGlobalContextRef jsContext = WKBundleFrameGetJavaScriptContextForWorld(frame, world.get());
587     JSEvaluateScript(jsContext, script, 0, 0, 0, 0); 
588 }
589
590 void TestRunner::setPOSIXLocale(JSStringRef locale)
591 {
592     char localeBuf[32];
593     JSStringGetUTF8CString(locale, localeBuf, sizeof(localeBuf));
594     setlocale(LC_ALL, localeBuf);
595 }
596
597 void TestRunner::setTextDirection(JSStringRef direction)
598 {
599     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
600     return WKBundleFrameSetTextDirection(mainFrame, toWK(direction).get());
601 }
602     
603 void TestRunner::setShouldStayOnPageAfterHandlingBeforeUnload(bool shouldStayOnPage)
604 {
605     InjectedBundle::singleton().postNewBeforeUnloadReturnValue(!shouldStayOnPage);
606 }
607
608 void TestRunner::setDefersLoading(bool shouldDeferLoading)
609 {
610     WKBundlePageSetDefersLoading(InjectedBundle::singleton().page()->page(), shouldDeferLoading);
611 }
612
613 void TestRunner::setPageVisibility(JSStringRef state)
614 {
615     InjectedBundle::singleton().setHidden(JSStringIsEqualToUTF8CString(state, "hidden") || JSStringIsEqualToUTF8CString(state, "prerender"));
616 }
617
618 void TestRunner::resetPageVisibility()
619 {
620     InjectedBundle::singleton().setHidden(false);
621 }
622
623 typedef WTF::HashMap<unsigned, JSValueRef> CallbackMap;
624 static CallbackMap& callbackMap()
625 {
626     static CallbackMap& map = *new CallbackMap;
627     return map;
628 }
629
630 enum {
631     AddChromeInputFieldCallbackID = 1,
632     RemoveChromeInputFieldCallbackID,
633     FocusWebViewCallbackID,
634     SetBackingScaleFactorCallbackID,
635     DidBeginSwipeCallbackID,
636     WillEndSwipeCallbackID,
637     DidEndSwipeCallbackID,
638     DidRemoveSwipeSnapshotCallbackID,
639     StatisticsDidModifyDataRecordsCallbackID,
640     FirstUIScriptCallbackID = 100
641 };
642
643 static void cacheTestRunnerCallback(unsigned index, JSValueRef callback)
644 {
645     if (!callback)
646         return;
647
648     if (callbackMap().contains(index)) {
649         InjectedBundle::singleton().outputText(String::format("FAIL: Tried to install a second TestRunner callback for the same event (id %d)\n\n", index));
650         return;
651     }
652
653     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
654     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
655     JSValueProtect(context, callback);
656     callbackMap().add(index, callback);
657 }
658
659 static void callTestRunnerCallback(unsigned index, size_t argumentCount = 0, const JSValueRef arguments[] = nullptr)
660 {
661     if (!callbackMap().contains(index))
662         return;
663     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
664     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
665     JSObjectRef callback = JSValueToObject(context, callbackMap().take(index), 0);
666     JSObjectCallAsFunction(context, callback, JSContextGetGlobalObject(context), argumentCount, arguments, 0);
667     JSValueUnprotect(context, callback);
668 }
669
670 void TestRunner::clearTestRunnerCallbacks()
671 {
672     for (auto& iter : callbackMap()) {
673         WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
674         JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
675         JSObjectRef callback = JSValueToObject(context, iter.value, 0);
676         JSValueUnprotect(context, callback);
677     }
678
679     callbackMap().clear();
680 }
681
682 void TestRunner::accummulateLogsForChannel(JSStringRef)
683 {
684     // FIXME: Implement getting the call to all processes.
685 }
686
687 void TestRunner::addChromeInputField(JSValueRef callback)
688 {
689     cacheTestRunnerCallback(AddChromeInputFieldCallbackID, callback);
690     InjectedBundle::singleton().postAddChromeInputField();
691 }
692
693 void TestRunner::removeChromeInputField(JSValueRef callback)
694 {
695     cacheTestRunnerCallback(RemoveChromeInputFieldCallbackID, callback);
696     InjectedBundle::singleton().postRemoveChromeInputField();
697 }
698
699 void TestRunner::focusWebView(JSValueRef callback)
700 {
701     cacheTestRunnerCallback(FocusWebViewCallbackID, callback);
702     InjectedBundle::singleton().postFocusWebView();
703 }
704
705 void TestRunner::setBackingScaleFactor(double backingScaleFactor, JSValueRef callback)
706 {
707     cacheTestRunnerCallback(SetBackingScaleFactorCallbackID, callback);
708     InjectedBundle::singleton().postSetBackingScaleFactor(backingScaleFactor);
709 }
710
711 void TestRunner::setWindowIsKey(bool isKey)
712 {
713     InjectedBundle::singleton().postSetWindowIsKey(isKey);
714 }
715
716 void TestRunner::setViewSize(double width, double height)
717 {
718     InjectedBundle::singleton().postSetViewSize(width, height);
719 }
720
721 void TestRunner::callAddChromeInputFieldCallback()
722 {
723     callTestRunnerCallback(AddChromeInputFieldCallbackID);
724 }
725
726 void TestRunner::callRemoveChromeInputFieldCallback()
727 {
728     callTestRunnerCallback(RemoveChromeInputFieldCallbackID);
729 }
730
731 void TestRunner::callFocusWebViewCallback()
732 {
733     callTestRunnerCallback(FocusWebViewCallbackID);
734 }
735
736 void TestRunner::callSetBackingScaleFactorCallback()
737 {
738     callTestRunnerCallback(SetBackingScaleFactorCallbackID);
739 }
740
741 static inline bool toBool(JSStringRef value)
742 {
743     return JSStringIsEqualToUTF8CString(value, "true") || JSStringIsEqualToUTF8CString(value, "1");
744 }
745
746 void TestRunner::overridePreference(JSStringRef preference, JSStringRef value)
747 {
748     auto& injectedBundle = InjectedBundle::singleton();
749     // FIXME: handle non-boolean preferences.
750     WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), toWK(preference).get(), toBool(value));
751 }
752
753 void TestRunner::setAlwaysAcceptCookies(bool accept)
754 {
755     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetAlwaysAcceptCookies"));
756
757     WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(accept));
758
759     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
760 }
761
762 double TestRunner::preciseTime()
763 {
764     return currentTime();
765 }
766
767 void TestRunner::setUserStyleSheetEnabled(bool enabled)
768 {
769     m_userStyleSheetEnabled = enabled;
770
771     WKRetainPtr<WKStringRef> emptyUrl = adoptWK(WKStringCreateWithUTF8CString(""));
772     WKStringRef location = enabled ? m_userStyleSheetLocation.get() : emptyUrl.get();
773     auto& injectedBundle = InjectedBundle::singleton();
774     WKBundleSetUserStyleSheetLocation(injectedBundle.bundle(), injectedBundle.pageGroup(), location);
775 }
776
777 void TestRunner::setUserStyleSheetLocation(JSStringRef location)
778 {
779     m_userStyleSheetLocation = adoptWK(WKStringCreateWithJSString(location));
780
781     if (m_userStyleSheetEnabled)
782         setUserStyleSheetEnabled(true);
783 }
784
785 void TestRunner::setSpatialNavigationEnabled(bool enabled)
786 {
787     auto& injectedBundle = InjectedBundle::singleton();
788     WKBundleSetSpatialNavigationEnabled(injectedBundle.bundle(), injectedBundle.pageGroup(), enabled);
789 }
790
791 void TestRunner::setTabKeyCyclesThroughElements(bool enabled)
792 {
793     auto& injectedBundle = InjectedBundle::singleton();
794     WKBundleSetTabKeyCyclesThroughElements(injectedBundle.bundle(), injectedBundle.page()->page(), enabled);
795 }
796
797 void TestRunner::setSerializeHTTPLoads()
798 {
799     // WK2 doesn't reorder loads.
800 }
801
802 void TestRunner::dispatchPendingLoadRequests()
803 {
804     // WK2 doesn't keep pending requests.
805 }
806
807 void TestRunner::setCacheModel(int model)
808 {
809     InjectedBundle::singleton().setCacheModel(model);
810 }
811
812 void TestRunner::setAsynchronousSpellCheckingEnabled(bool enabled)
813 {
814     auto& injectedBundle = InjectedBundle::singleton();
815     WKBundleSetAsynchronousSpellCheckingEnabled(injectedBundle.bundle(), injectedBundle.pageGroup(), enabled);
816 }
817
818 void TestRunner::grantWebNotificationPermission(JSStringRef origin)
819 {
820     WKRetainPtr<WKStringRef> originWK = toWK(origin);
821     auto& injectedBundle = InjectedBundle::singleton();
822     WKBundleSetWebNotificationPermission(injectedBundle.bundle(), injectedBundle.page()->page(), originWK.get(), true);
823 }
824
825 void TestRunner::denyWebNotificationPermission(JSStringRef origin)
826 {
827     WKRetainPtr<WKStringRef> originWK = toWK(origin);
828     auto& injectedBundle = InjectedBundle::singleton();
829     WKBundleSetWebNotificationPermission(injectedBundle.bundle(), injectedBundle.page()->page(), originWK.get(), false);
830 }
831
832 void TestRunner::removeAllWebNotificationPermissions()
833 {
834     auto& injectedBundle = InjectedBundle::singleton();
835     WKBundleRemoveAllWebNotificationPermissions(injectedBundle.bundle(), injectedBundle.page()->page());
836 }
837
838 void TestRunner::simulateWebNotificationClick(JSValueRef notification)
839 {
840     auto& injectedBundle = InjectedBundle::singleton();
841     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(injectedBundle.page()->page());
842     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
843     uint64_t notificationID = WKBundleGetWebNotificationID(injectedBundle.bundle(), context, notification);
844     injectedBundle.postSimulateWebNotificationClick(notificationID);
845 }
846
847 void TestRunner::setGeolocationPermission(bool enabled)
848 {
849     // FIXME: this should be done by frame.
850     InjectedBundle::singleton().setGeolocationPermission(enabled);
851 }
852
853 bool TestRunner::isGeolocationProviderActive()
854 {
855     return InjectedBundle::singleton().isGeolocationProviderActive();
856 }
857
858 void TestRunner::setMockGeolocationPosition(double latitude, double longitude, double accuracy, JSValueRef jsAltitude, JSValueRef jsAltitudeAccuracy, JSValueRef jsHeading, JSValueRef jsSpeed)
859 {
860     auto& injectedBundle = InjectedBundle::singleton();
861     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(injectedBundle.page()->page());
862     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
863
864     bool providesAltitude = false;
865     double altitude = 0.;
866     if (!JSValueIsUndefined(context, jsAltitude)) {
867         providesAltitude = true;
868         altitude = JSValueToNumber(context, jsAltitude, 0);
869     }
870
871     bool providesAltitudeAccuracy = false;
872     double altitudeAccuracy = 0.;
873     if (!JSValueIsUndefined(context, jsAltitudeAccuracy)) {
874         providesAltitudeAccuracy = true;
875         altitudeAccuracy = JSValueToNumber(context, jsAltitudeAccuracy, 0);
876     }
877
878     bool providesHeading = false;
879     double heading = 0.;
880     if (!JSValueIsUndefined(context, jsHeading)) {
881         providesHeading = true;
882         heading = JSValueToNumber(context, jsHeading, 0);
883     }
884
885     bool providesSpeed = false;
886     double speed = 0.;
887     if (!JSValueIsUndefined(context, jsSpeed)) {
888         providesSpeed = true;
889         speed = JSValueToNumber(context, jsSpeed, 0);
890     }
891
892     injectedBundle.setMockGeolocationPosition(latitude, longitude, accuracy, providesAltitude, altitude, providesAltitudeAccuracy, altitudeAccuracy, providesHeading, heading, providesSpeed, speed);
893 }
894
895 void TestRunner::setMockGeolocationPositionUnavailableError(JSStringRef message)
896 {
897     WKRetainPtr<WKStringRef> messageWK = toWK(message);
898     InjectedBundle::singleton().setMockGeolocationPositionUnavailableError(messageWK.get());
899 }
900
901 void TestRunner::setUserMediaPermission(bool enabled)
902 {
903     // FIXME: this should be done by frame.
904     InjectedBundle::singleton().setUserMediaPermission(enabled);
905 }
906
907 void TestRunner::setUserMediaPersistentPermissionForOrigin(bool permission, JSStringRef origin, JSStringRef parentOrigin)
908 {
909     WKRetainPtr<WKStringRef> originWK = toWK(origin);
910     WKRetainPtr<WKStringRef> parentOriginWK = toWK(parentOrigin);
911     InjectedBundle::singleton().setUserMediaPersistentPermissionForOrigin(permission, originWK.get(), parentOriginWK.get());
912 }
913
914 unsigned TestRunner::userMediaPermissionRequestCountForOrigin(JSStringRef origin, JSStringRef parentOrigin) const
915 {
916     WKRetainPtr<WKStringRef> originWK = toWK(origin);
917     WKRetainPtr<WKStringRef> parentOriginWK = toWK(parentOrigin);
918     return InjectedBundle::singleton().userMediaPermissionRequestCountForOrigin(originWK.get(), parentOriginWK.get());
919 }
920
921 void TestRunner::resetUserMediaPermissionRequestCountForOrigin(JSStringRef origin, JSStringRef parentOrigin)
922 {
923     WKRetainPtr<WKStringRef> originWK = toWK(origin);
924     WKRetainPtr<WKStringRef> parentOriginWK = toWK(parentOrigin);
925     InjectedBundle::singleton().resetUserMediaPermissionRequestCountForOrigin(originWK.get(), parentOriginWK.get());
926 }
927
928 bool TestRunner::callShouldCloseOnWebView()
929 {
930     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
931     return WKBundleFrameCallShouldCloseOnWebView(mainFrame);
932 }
933
934 void TestRunner::queueBackNavigation(unsigned howFarBackward)
935 {
936     InjectedBundle::singleton().queueBackNavigation(howFarBackward);
937 }
938
939 void TestRunner::queueForwardNavigation(unsigned howFarForward)
940 {
941     InjectedBundle::singleton().queueForwardNavigation(howFarForward);
942 }
943
944 void TestRunner::queueLoad(JSStringRef url, JSStringRef target, bool shouldOpenExternalURLs)
945 {
946     auto& injectedBundle = InjectedBundle::singleton();
947     WKRetainPtr<WKURLRef> baseURLWK(AdoptWK, WKBundleFrameCopyURL(WKBundlePageGetMainFrame(injectedBundle.page()->page())));
948     WKRetainPtr<WKURLRef> urlWK(AdoptWK, WKURLCreateWithBaseURL(baseURLWK.get(), toWTFString(toWK(url)).utf8().data()));
949     WKRetainPtr<WKStringRef> urlStringWK(AdoptWK, WKURLCopyString(urlWK.get()));
950
951     injectedBundle.queueLoad(urlStringWK.get(), toWK(target).get(), shouldOpenExternalURLs);
952 }
953
954 void TestRunner::queueLoadHTMLString(JSStringRef content, JSStringRef baseURL, JSStringRef unreachableURL)
955 {
956     WKRetainPtr<WKStringRef> contentWK = toWK(content);
957     WKRetainPtr<WKStringRef> baseURLWK = baseURL ? toWK(baseURL) : WKRetainPtr<WKStringRef>();
958     WKRetainPtr<WKStringRef> unreachableURLWK = unreachableURL ? toWK(unreachableURL) : WKRetainPtr<WKStringRef>();
959
960     InjectedBundle::singleton().queueLoadHTMLString(contentWK.get(), baseURLWK.get(), unreachableURLWK.get());
961 }
962
963 void TestRunner::queueReload()
964 {
965     InjectedBundle::singleton().queueReload();
966 }
967
968 void TestRunner::queueLoadingScript(JSStringRef script)
969 {
970     WKRetainPtr<WKStringRef> scriptWK = toWK(script);
971     InjectedBundle::singleton().queueLoadingScript(scriptWK.get());
972 }
973
974 void TestRunner::queueNonLoadingScript(JSStringRef script)
975 {
976     WKRetainPtr<WKStringRef> scriptWK = toWK(script);
977     InjectedBundle::singleton().queueNonLoadingScript(scriptWK.get());
978 }
979
980 void TestRunner::setRejectsProtectionSpaceAndContinueForAuthenticationChallenges(bool value)
981 {
982     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetRejectsProtectionSpaceAndContinueForAuthenticationChallenges"));
983     WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(value));
984     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
985 }
986     
987 void TestRunner::setHandlesAuthenticationChallenges(bool handlesAuthenticationChallenges)
988 {
989     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetHandlesAuthenticationChallenges"));
990     WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(handlesAuthenticationChallenges));
991     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
992 }
993
994 void TestRunner::setShouldLogCanAuthenticateAgainstProtectionSpace(bool value)
995 {
996     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetShouldLogCanAuthenticateAgainstProtectionSpace"));
997     WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(value));
998     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
999 }
1000
1001 void TestRunner::setAuthenticationUsername(JSStringRef username)
1002 {
1003     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetAuthenticationUsername"));
1004     WKRetainPtr<WKStringRef> messageBody(AdoptWK, WKStringCreateWithJSString(username));
1005     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
1006 }
1007
1008 void TestRunner::setAuthenticationPassword(JSStringRef password)
1009 {
1010     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetAuthenticationPassword"));
1011     WKRetainPtr<WKStringRef> messageBody(AdoptWK, WKStringCreateWithJSString(password));
1012     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
1013 }
1014
1015 bool TestRunner::secureEventInputIsEnabled() const
1016 {
1017     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SecureEventInputIsEnabled"));
1018     WKTypeRef returnData = 0;
1019
1020     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), 0, &returnData);
1021     return WKBooleanGetValue(static_cast<WKBooleanRef>(returnData));
1022 }
1023
1024 void TestRunner::setBlockAllPlugins(bool shouldBlock)
1025 {
1026     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetBlockAllPlugins"));
1027     WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(shouldBlock));
1028     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
1029 }
1030
1031 JSValueRef TestRunner::failNextNewCodeBlock()
1032 {
1033     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
1034     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
1035     return JSC::failNextNewCodeBlock(context);
1036 }
1037
1038 JSValueRef TestRunner::numberOfDFGCompiles(JSValueRef theFunction)
1039 {
1040     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
1041     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
1042     return JSC::numberOfDFGCompiles(context, theFunction);
1043 }
1044
1045 JSValueRef TestRunner::neverInlineFunction(JSValueRef theFunction)
1046 {
1047     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
1048     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
1049     return JSC::setNeverInline(context, theFunction);
1050 }
1051
1052 void TestRunner::setShouldDecideNavigationPolicyAfterDelay(bool value)
1053 {
1054     m_shouldDecideNavigationPolicyAfterDelay = value;
1055     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetShouldDecideNavigationPolicyAfterDelay"));
1056     WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(value));
1057     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
1058 }
1059
1060 void TestRunner::setNavigationGesturesEnabled(bool value)
1061 {
1062     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetNavigationGesturesEnabled"));
1063     WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(value));
1064     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
1065 }
1066
1067 void TestRunner::setIgnoresViewportScaleLimits(bool value)
1068 {
1069     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetIgnoresViewportScaleLimits"));
1070     WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(value));
1071     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
1072 }
1073
1074 void TestRunner::setShouldDownloadUndisplayableMIMETypes(bool value)
1075 {
1076     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetShouldDownloadUndisplayableMIMETypes"));
1077     WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(value));
1078     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
1079 }
1080
1081 static unsigned nextUIScriptCallbackID()
1082 {
1083     static unsigned callbackID = FirstUIScriptCallbackID;
1084     return callbackID++;
1085 }
1086
1087 void TestRunner::runUIScript(JSStringRef script, JSValueRef callback)
1088 {
1089     unsigned callbackID = nextUIScriptCallbackID();
1090     cacheTestRunnerCallback(callbackID, callback);
1091
1092     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("RunUIProcessScript"));
1093
1094     WKRetainPtr<WKMutableDictionaryRef> testDictionary(AdoptWK, WKMutableDictionaryCreate());
1095
1096     WKRetainPtr<WKStringRef> scriptKey(AdoptWK, WKStringCreateWithUTF8CString("Script"));
1097     WKRetainPtr<WKStringRef> scriptValue(AdoptWK, WKStringCreateWithJSString(script));
1098
1099     WKRetainPtr<WKStringRef> callbackIDKey(AdoptWK, WKStringCreateWithUTF8CString("CallbackID"));
1100     WKRetainPtr<WKUInt64Ref> callbackIDValue = adoptWK(WKUInt64Create(callbackID));
1101
1102     WKDictionarySetItem(testDictionary.get(), scriptKey.get(), scriptValue.get());
1103     WKDictionarySetItem(testDictionary.get(), callbackIDKey.get(), callbackIDValue.get());
1104
1105     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), testDictionary.get());
1106 }
1107
1108 void TestRunner::runUIScriptCallback(unsigned callbackID, JSStringRef result)
1109 {
1110     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
1111     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
1112
1113     JSValueRef resultValue = JSValueMakeString(context, result);
1114     callTestRunnerCallback(callbackID, 1, &resultValue);
1115 }
1116
1117 void TestRunner::installDidBeginSwipeCallback(JSValueRef callback)
1118 {
1119     cacheTestRunnerCallback(DidBeginSwipeCallbackID, callback);
1120 }
1121
1122 void TestRunner::installWillEndSwipeCallback(JSValueRef callback)
1123 {
1124     cacheTestRunnerCallback(WillEndSwipeCallbackID, callback);
1125 }
1126
1127 void TestRunner::installDidEndSwipeCallback(JSValueRef callback)
1128 {
1129     cacheTestRunnerCallback(DidEndSwipeCallbackID, callback);
1130 }
1131
1132 void TestRunner::installDidRemoveSwipeSnapshotCallback(JSValueRef callback)
1133 {
1134     cacheTestRunnerCallback(DidRemoveSwipeSnapshotCallbackID, callback);
1135 }
1136
1137 void TestRunner::callDidBeginSwipeCallback()
1138 {
1139     callTestRunnerCallback(DidBeginSwipeCallbackID);
1140 }
1141
1142 void TestRunner::callWillEndSwipeCallback()
1143 {
1144     callTestRunnerCallback(WillEndSwipeCallbackID);
1145 }
1146
1147 void TestRunner::callDidEndSwipeCallback()
1148 {
1149     callTestRunnerCallback(DidEndSwipeCallbackID);
1150 }
1151
1152 void TestRunner::callDidRemoveSwipeSnapshotCallback()
1153 {
1154     callTestRunnerCallback(DidRemoveSwipeSnapshotCallbackID);
1155 }
1156
1157 void TestRunner::setStatisticsPrevalentResource(JSStringRef hostName, bool value)
1158 {
1159     Vector<WKRetainPtr<WKStringRef>> keys;
1160     Vector<WKRetainPtr<WKTypeRef>> values;
1161
1162     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("HostName") });
1163     values.append({ AdoptWK, WKStringCreateWithJSString(hostName) });
1164     
1165     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("Value") });
1166     values.append({ AdoptWK, WKBooleanCreate(value) });
1167     
1168     Vector<WKStringRef> rawKeys;
1169     Vector<WKTypeRef> rawValues;
1170     rawKeys.resize(keys.size());
1171     rawValues.resize(values.size());
1172     
1173     for (size_t i = 0; i < keys.size(); ++i) {
1174         rawKeys[i] = keys[i].get();
1175         rawValues[i] = values[i].get();
1176     }
1177     
1178     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetStatisticsPrevalentResource"));
1179     WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1180
1181     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1182 }
1183
1184 bool TestRunner::isStatisticsPrevalentResource(JSStringRef hostName)
1185 {
1186     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("IsStatisticsPrevalentResource"));
1187     WKRetainPtr<WKStringRef> messageBody(AdoptWK, WKStringCreateWithJSString(hostName));
1188     WKTypeRef returnData = 0;
1189     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get(), &returnData);
1190     return WKBooleanGetValue(static_cast<WKBooleanRef>(returnData));
1191 }
1192
1193 void TestRunner::setStatisticsHasHadUserInteraction(JSStringRef hostName, bool value)
1194 {
1195     Vector<WKRetainPtr<WKStringRef>> keys;
1196     Vector<WKRetainPtr<WKTypeRef>> values;
1197     
1198     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("HostName") });
1199     values.append({ AdoptWK, WKStringCreateWithJSString(hostName) });
1200     
1201     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("Value") });
1202     values.append({ AdoptWK, WKBooleanCreate(value) });
1203     
1204     Vector<WKStringRef> rawKeys;
1205     Vector<WKTypeRef> rawValues;
1206     rawKeys.resize(keys.size());
1207     rawValues.resize(values.size());
1208     
1209     for (size_t i = 0; i < keys.size(); ++i) {
1210         rawKeys[i] = keys[i].get();
1211         rawValues[i] = values[i].get();
1212     }
1213     
1214     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetStatisticsHasHadUserInteraction"));
1215     WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1216     
1217     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1218 }
1219
1220 bool TestRunner::isStatisticsHasHadUserInteraction(JSStringRef hostName)
1221 {
1222     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("IsStatisticsHasHadUserInteraction"));
1223     WKRetainPtr<WKStringRef> messageBody(AdoptWK, WKStringCreateWithJSString(hostName));
1224     WKTypeRef returnData = 0;
1225     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get(), &returnData);
1226     return WKBooleanGetValue(static_cast<WKBooleanRef>(returnData));
1227 }
1228
1229 void TestRunner::setStatisticsSubframeUnderTopFrameOrigin(JSStringRef hostName, JSStringRef topFrameHostName)
1230 {
1231     Vector<WKRetainPtr<WKStringRef>> keys;
1232     Vector<WKRetainPtr<WKTypeRef>> values;
1233     
1234     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("HostName") });
1235     values.append({ AdoptWK, WKStringCreateWithJSString(hostName) });
1236     
1237     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("TopFrameHostName") });
1238     values.append({ AdoptWK, WKStringCreateWithJSString(topFrameHostName) });
1239     
1240     Vector<WKStringRef> rawKeys(keys.size());
1241     Vector<WKTypeRef> rawValues(values.size());
1242     
1243     for (size_t i = 0; i < keys.size(); ++i) {
1244         rawKeys[i] = keys[i].get();
1245         rawValues[i] = values[i].get();
1246     }
1247     
1248     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetStatisticsSubframeUnderTopFrameOrigin"));
1249     WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1250     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1251 }
1252
1253 void TestRunner::setStatisticsSubresourceUnderTopFrameOrigin(JSStringRef hostName, JSStringRef topFrameHostName)
1254 {
1255     Vector<WKRetainPtr<WKStringRef>> keys;
1256     Vector<WKRetainPtr<WKTypeRef>> values;
1257     
1258     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("HostName") });
1259     values.append({ AdoptWK, WKStringCreateWithJSString(hostName) });
1260     
1261     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("TopFrameHostName") });
1262     values.append({ AdoptWK, WKStringCreateWithJSString(topFrameHostName) });
1263     
1264     Vector<WKStringRef> rawKeys(keys.size());
1265     Vector<WKTypeRef> rawValues(values.size());
1266     
1267     for (size_t i = 0; i < keys.size(); ++i) {
1268         rawKeys[i] = keys[i].get();
1269         rawValues[i] = values[i].get();
1270     }
1271     
1272     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetStatisticsSubresourceUnderTopFrameOrigin"));
1273     WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1274     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1275 }
1276
1277 void TestRunner::setStatisticsSubresourceUniqueRedirectTo(JSStringRef hostName, JSStringRef hostNameRedirectedTo)
1278 {
1279     Vector<WKRetainPtr<WKStringRef>> keys;
1280     Vector<WKRetainPtr<WKTypeRef>> values;
1281     
1282     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("HostName") });
1283     values.append({ AdoptWK, WKStringCreateWithJSString(hostName) });
1284     
1285     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("HostNameRedirectedTo") });
1286     values.append({ AdoptWK, WKStringCreateWithJSString(hostNameRedirectedTo) });
1287     
1288     Vector<WKStringRef> rawKeys(keys.size());
1289     Vector<WKTypeRef> rawValues(values.size());
1290     
1291     for (size_t i = 0; i < keys.size(); ++i) {
1292         rawKeys[i] = keys[i].get();
1293         rawValues[i] = values[i].get();
1294     }
1295     
1296     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetStatisticsSubresourceUniqueRedirectTo"));
1297     WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1298     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1299 }
1300
1301 void TestRunner::setStatisticsTimeToLiveUserInteraction(double seconds)
1302 {
1303     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetStatisticsTimeToLiveUserInteraction"));
1304     WKRetainPtr<WKDoubleRef> messageBody(AdoptWK, WKDoubleCreate(seconds));
1305     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1306 }
1307
1308 void TestRunner::installStatisticsDidModifyDataRecordsCallback(JSValueRef callback)
1309 {
1310     cacheTestRunnerCallback(StatisticsDidModifyDataRecordsCallbackID, callback);
1311 }
1312
1313 void TestRunner::statisticsDidModifyDataRecordsCallback()
1314 {
1315     callTestRunnerCallback(StatisticsDidModifyDataRecordsCallbackID);
1316 }
1317
1318 void TestRunner::statisticsFireDataModificationHandler()
1319 {
1320     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("StatisticsFireDataModificationHandler"));
1321     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), 0, nullptr);
1322 }
1323
1324 void TestRunner::setStatisticsNotifyPagesWhenDataRecordsWereScanned(bool value)
1325 {
1326     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("StatisticsNotifyPagesWhenDataRecordsWereScanned"));
1327     WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(value));
1328     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1329 }
1330
1331 void TestRunner::setStatisticsShouldClassifyResourcesBeforeDataRecordsRemoval(bool value)
1332 {
1333     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("StatisticsShouldClassifyResourcesBeforeDataRecordsRemoval"));
1334     WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(value));
1335     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1336 }
1337
1338 void TestRunner::setStatisticsMinimumTimeBetweeenDataRecordsRemoval(double seconds)
1339 {
1340     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetStatisticsMinimumTimeBetweeenDataRecordsRemoval"));
1341     WKRetainPtr<WKDoubleRef> messageBody(AdoptWK, WKDoubleCreate(seconds));
1342     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1343 }
1344     
1345 void TestRunner::statisticsResetToConsistentState()
1346 {
1347     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("StatisticsResetToConsistentState"));
1348     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), 0, nullptr);
1349 }
1350
1351 #if PLATFORM(MAC)
1352 void TestRunner::connectMockGamepad(unsigned index)
1353 {
1354     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("ConnectMockGamepad"));
1355     WKRetainPtr<WKTypeRef> messageBody(AdoptWK, WKUInt64Create(index));
1356
1357     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1358 }
1359
1360 void TestRunner::disconnectMockGamepad(unsigned index)
1361 {
1362     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("DisconnectMockGamepad"));
1363     WKRetainPtr<WKTypeRef> messageBody(AdoptWK, WKUInt64Create(index));
1364
1365     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1366 }
1367
1368 void TestRunner::setMockGamepadDetails(unsigned index, JSStringRef gamepadID, unsigned axisCount, unsigned buttonCount)
1369 {
1370     Vector<WKRetainPtr<WKStringRef>> keys;
1371     Vector<WKRetainPtr<WKTypeRef>> values;
1372
1373     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("GamepadID") });
1374     values.append(toWK(gamepadID));
1375
1376     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("GamepadIndex") });
1377     values.append({ AdoptWK, WKUInt64Create(index) });
1378
1379     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("AxisCount") });
1380     values.append({ AdoptWK, WKUInt64Create(axisCount) });
1381
1382     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("ButtonCount") });
1383     values.append({ AdoptWK, WKUInt64Create(buttonCount) });
1384
1385     Vector<WKStringRef> rawKeys;
1386     Vector<WKTypeRef> rawValues;
1387     rawKeys.resize(keys.size());
1388     rawValues.resize(values.size());
1389
1390     for (size_t i = 0; i < keys.size(); ++i) {
1391         rawKeys[i] = keys[i].get();
1392         rawValues[i] = values[i].get();
1393     }
1394
1395     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetMockGamepadDetails"));
1396     WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1397
1398     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1399 }
1400
1401 void TestRunner::setMockGamepadAxisValue(unsigned index, unsigned axisIndex, double value)
1402 {
1403     Vector<WKRetainPtr<WKStringRef>> keys;
1404     Vector<WKRetainPtr<WKTypeRef>> values;
1405
1406     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("GamepadIndex") });
1407     values.append({ AdoptWK, WKUInt64Create(index) });
1408
1409     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("AxisIndex") });
1410     values.append({ AdoptWK, WKUInt64Create(axisIndex) });
1411
1412     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("Value") });
1413     values.append({ AdoptWK, WKDoubleCreate(value) });
1414
1415     Vector<WKStringRef> rawKeys;
1416     Vector<WKTypeRef> rawValues;
1417     rawKeys.resize(keys.size());
1418     rawValues.resize(values.size());
1419
1420     for (size_t i = 0; i < keys.size(); ++i) {
1421         rawKeys[i] = keys[i].get();
1422         rawValues[i] = values[i].get();
1423     }
1424
1425     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetMockGamepadAxisValue"));
1426     WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1427
1428     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1429 }
1430
1431 void TestRunner::setMockGamepadButtonValue(unsigned index, unsigned buttonIndex, double value)
1432 {
1433     Vector<WKRetainPtr<WKStringRef>> keys;
1434     Vector<WKRetainPtr<WKTypeRef>> values;
1435
1436     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("GamepadIndex") });
1437     values.append({ AdoptWK, WKUInt64Create(index) });
1438
1439     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("ButtonIndex") });
1440     values.append({ AdoptWK, WKUInt64Create(buttonIndex) });
1441
1442     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("Value") });
1443     values.append({ AdoptWK, WKDoubleCreate(value) });
1444
1445     Vector<WKStringRef> rawKeys;
1446     Vector<WKTypeRef> rawValues;
1447     rawKeys.resize(keys.size());
1448     rawValues.resize(values.size());
1449
1450     for (size_t i = 0; i < keys.size(); ++i) {
1451         rawKeys[i] = keys[i].get();
1452         rawValues[i] = values[i].get();
1453     }
1454
1455     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetMockGamepadButtonValue"));
1456     WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1457
1458     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1459 }
1460 #else
1461 void TestRunner::connectMockGamepad(unsigned)
1462 {
1463 }
1464
1465 void TestRunner::disconnectMockGamepad(unsigned)
1466 {
1467 }
1468
1469 void TestRunner::setMockGamepadDetails(unsigned, JSStringRef, unsigned, unsigned)
1470 {
1471 }
1472
1473 void TestRunner::setMockGamepadAxisValue(unsigned, unsigned, double)
1474 {
1475 }
1476
1477 void TestRunner::setMockGamepadButtonValue(unsigned, unsigned, double)
1478 {
1479 }
1480 #endif // PLATFORM(MAC)
1481
1482 void TestRunner::setOpenPanelFiles(JSValueRef filesValue)
1483 {
1484     WKBundlePageRef page = InjectedBundle::singleton().page()->page();
1485     JSContextRef context = WKBundleFrameGetJavaScriptContext(WKBundlePageGetMainFrame(page));
1486
1487     if (!JSValueIsArray(context, filesValue))
1488         return;
1489
1490     JSObjectRef files = JSValueToObject(context, filesValue, nullptr);
1491     static auto lengthProperty = JSRetainPtr<JSStringRef>(Adopt, JSStringCreateWithUTF8CString("length"));
1492     JSValueRef filesLengthValue = JSObjectGetProperty(context, files, lengthProperty.get(), nullptr);
1493     if (!JSValueIsNumber(context, filesLengthValue))
1494         return;
1495
1496     auto fileURLs = adoptWK(WKMutableArrayCreate());
1497     auto filesLength = static_cast<size_t>(JSValueToNumber(context, filesLengthValue, nullptr));
1498     for (size_t i = 0; i < filesLength; ++i) {
1499         JSValueRef fileValue = JSObjectGetPropertyAtIndex(context, files, i, nullptr);
1500         if (!JSValueIsString(context, fileValue))
1501             continue;
1502
1503         auto file = JSRetainPtr<JSStringRef>(Adopt, JSValueToStringCopy(context, fileValue, nullptr));
1504         size_t fileBufferSize = JSStringGetMaximumUTF8CStringSize(file.get()) + 1;
1505         auto fileBuffer = std::make_unique<char[]>(fileBufferSize);
1506         JSStringGetUTF8CString(file.get(), fileBuffer.get(), fileBufferSize);
1507
1508         WKArrayAppendItem(fileURLs.get(), adoptWK(WKURLCreateWithBaseURL(m_testURL.get(), fileBuffer.get())).get());
1509     }
1510
1511     static auto messageName = adoptWK(WKStringCreateWithUTF8CString("SetOpenPanelFileURLs"));
1512     WKBundlePagePostMessage(page, messageName.get(), fileURLs.get());
1513 }
1514
1515 } // namespace WTR