Tools:
[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::displayAndTrackRepaints()
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::setSubtleCryptoEnabled(bool enabled)
350 {
351     WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitSubtleCryptoEnabled"));
352     auto& injectedBundle = InjectedBundle::singleton();
353     WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
354 }
355
356 void TestRunner::setMediaDevicesEnabled(bool enabled)
357 {
358     WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitMediaDevicesEnabled"));
359     auto& injectedBundle = InjectedBundle::singleton();
360     WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
361 }
362
363 void TestRunner::setWebRTCLegacyAPIEnabled(bool enabled)
364 {
365     WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitWebRTCLegacyAPIEnabled"));
366     auto& injectedBundle = InjectedBundle::singleton();
367     WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
368 }
369
370 void TestRunner::setModernMediaControlsEnabled(bool enabled)
371 {
372     WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitModernMediaControlsEnabled"));
373     auto& injectedBundle = InjectedBundle::singleton();
374     WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
375 }
376
377 void TestRunner::setWebGL2Enabled(bool enabled)
378 {
379     WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitWebGL2Enabled"));
380     auto& injectedBundle = InjectedBundle::singleton();
381     WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
382 }
383
384 void TestRunner::setWebGPUEnabled(bool enabled)
385 {
386     WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitWebGPUEnabled"));
387     auto& injectedBundle = InjectedBundle::singleton();
388     WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
389 }
390
391 void TestRunner::setWritableStreamAPIEnabled(bool enabled)
392 {
393     WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitWritableStreamAPIEnabled"));
394     auto& injectedBundle = InjectedBundle::singleton();
395     WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
396 }
397
398 void TestRunner::setReadableByteStreamAPIEnabled(bool enabled)
399 {
400     WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitReadableByteStreamAPIEnabled"));
401     auto& injectedBundle = InjectedBundle::singleton();
402     WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
403 }
404
405 void TestRunner::setEncryptedMediaAPIEnabled(bool enabled)
406 {
407     WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitEncryptedMediaAPIEnabled"));
408     auto& injectedBundle = InjectedBundle::singleton();
409     WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
410 }
411
412 void TestRunner::setAllowsAnySSLCertificate(bool enabled)
413 {
414     auto& injectedBundle = InjectedBundle::singleton();
415     injectedBundle.setAllowsAnySSLCertificate(enabled);
416
417     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetAllowsAnySSLCertificate"));
418     WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(enabled));
419     WKBundlePagePostSynchronousMessageForTesting(injectedBundle.page()->page(), messageName.get(), messageBody.get(), nullptr);
420 }
421
422 void TestRunner::setAllowUniversalAccessFromFileURLs(bool enabled)
423 {
424     auto& injectedBundle = InjectedBundle::singleton();
425     WKBundleSetAllowUniversalAccessFromFileURLs(injectedBundle.bundle(), injectedBundle.pageGroup(), enabled);
426 }
427
428 void TestRunner::setAllowFileAccessFromFileURLs(bool enabled)
429 {
430     auto& injectedBundle = InjectedBundle::singleton();
431     WKBundleSetAllowFileAccessFromFileURLs(injectedBundle.bundle(), injectedBundle.pageGroup(), enabled);
432 }
433
434 void TestRunner::setNeedsStorageAccessFromFileURLsQuirk(bool needsQuirk)
435 {
436     auto& injectedBundle = InjectedBundle::singleton();
437     WKBundleSetAllowStorageAccessFromFileURLS(injectedBundle.bundle(), injectedBundle.pageGroup(), needsQuirk);
438 }
439     
440 void TestRunner::setPluginsEnabled(bool enabled)
441 {
442     WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitPluginsEnabled"));
443     auto& injectedBundle = InjectedBundle::singleton();
444     WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
445 }
446
447 void TestRunner::setJavaScriptCanAccessClipboard(bool enabled)
448 {
449     auto& injectedBundle = InjectedBundle::singleton();
450     WKBundleSetJavaScriptCanAccessClipboard(injectedBundle.bundle(), injectedBundle.pageGroup(), enabled);
451 }
452
453 void TestRunner::setPrivateBrowsingEnabled(bool enabled)
454 {
455     auto& injectedBundle = InjectedBundle::singleton();
456     WKBundleSetPrivateBrowsingEnabled(injectedBundle.bundle(), injectedBundle.pageGroup(), enabled);
457 }
458
459 void TestRunner::setUseDashboardCompatibilityMode(bool enabled)
460 {
461 #if ENABLE(DASHBOARD_SUPPORT)
462     auto& injectedBundle = InjectedBundle::singleton();
463     WKBundleSetUseDashboardCompatibilityMode(injectedBundle.bundle(), injectedBundle.pageGroup(), enabled);
464 #endif
465 }
466     
467 void TestRunner::setPopupBlockingEnabled(bool enabled)
468 {
469     auto& injectedBundle = InjectedBundle::singleton();
470     WKBundleSetPopupBlockingEnabled(injectedBundle.bundle(), injectedBundle.pageGroup(), enabled);
471 }
472
473 void TestRunner::setAuthorAndUserStylesEnabled(bool enabled)
474 {
475     auto& injectedBundle = InjectedBundle::singleton();
476     WKBundleSetAuthorAndUserStylesEnabled(injectedBundle.bundle(), injectedBundle.pageGroup(), enabled);
477 }
478
479 void TestRunner::addOriginAccessWhitelistEntry(JSStringRef sourceOrigin, JSStringRef destinationProtocol, JSStringRef destinationHost, bool allowDestinationSubdomains)
480 {
481     WKBundleAddOriginAccessWhitelistEntry(InjectedBundle::singleton().bundle(), toWK(sourceOrigin).get(), toWK(destinationProtocol).get(), toWK(destinationHost).get(), allowDestinationSubdomains);
482 }
483
484 void TestRunner::removeOriginAccessWhitelistEntry(JSStringRef sourceOrigin, JSStringRef destinationProtocol, JSStringRef destinationHost, bool allowDestinationSubdomains)
485 {
486     WKBundleRemoveOriginAccessWhitelistEntry(InjectedBundle::singleton().bundle(), toWK(sourceOrigin).get(), toWK(destinationProtocol).get(), toWK(destinationHost).get(), allowDestinationSubdomains);
487 }
488
489 bool TestRunner::isPageBoxVisible(int pageIndex)
490 {
491     auto& injectedBundle = InjectedBundle::singleton();
492     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(injectedBundle.page()->page());
493     return WKBundleIsPageBoxVisible(injectedBundle.bundle(), mainFrame, pageIndex);
494 }
495
496 void TestRunner::setValueForUser(JSContextRef context, JSValueRef element, JSStringRef value)
497 {
498     if (!element || !JSValueIsObject(context, element))
499         return;
500
501     WKRetainPtr<WKBundleNodeHandleRef> nodeHandle(AdoptWK, WKBundleNodeHandleCreate(context, const_cast<JSObjectRef>(element)));
502     WKBundleNodeHandleSetHTMLInputElementValueForUser(nodeHandle.get(), toWK(value).get());
503 }
504
505 void TestRunner::setAudioResult(JSContextRef context, JSValueRef data)
506 {
507     auto& injectedBundle = InjectedBundle::singleton();
508     // FIXME (123058): Use a JSC API to get buffer contents once such is exposed.
509     WKRetainPtr<WKDataRef> audioData(AdoptWK, WKBundleCreateWKDataFromUInt8Array(injectedBundle.bundle(), context, data));
510     injectedBundle.setAudioResult(audioData.get());
511     m_whatToDump = Audio;
512     m_dumpPixels = false;
513 }
514
515 unsigned TestRunner::windowCount()
516 {
517     return InjectedBundle::singleton().pageCount();
518 }
519
520 void TestRunner::clearBackForwardList()
521 {
522     WKBundleBackForwardListClear(WKBundlePageGetBackForwardList(InjectedBundle::singleton().page()->page()));
523 }
524
525 // Object Creation
526
527 void TestRunner::makeWindowObject(JSContextRef context, JSObjectRef windowObject, JSValueRef* exception)
528 {
529     setProperty(context, windowObject, "testRunner", this, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete, exception);
530 }
531
532 void TestRunner::showWebInspector()
533 {
534     WKBundleInspectorShow(WKBundlePageGetInspector(InjectedBundle::singleton().page()->page()));
535 }
536
537 void TestRunner::closeWebInspector()
538 {
539     WKBundleInspectorClose(WKBundlePageGetInspector(InjectedBundle::singleton().page()->page()));
540 }
541
542 void TestRunner::evaluateInWebInspector(JSStringRef script)
543 {
544     WKRetainPtr<WKStringRef> scriptWK = toWK(script);
545     WKBundleInspectorEvaluateScriptForTest(WKBundlePageGetInspector(InjectedBundle::singleton().page()->page()), scriptWK.get());
546 }
547
548 typedef WTF::HashMap<unsigned, WKRetainPtr<WKBundleScriptWorldRef> > WorldMap;
549 static WorldMap& worldMap()
550 {
551     static WorldMap& map = *new WorldMap;
552     return map;
553 }
554
555 unsigned TestRunner::worldIDForWorld(WKBundleScriptWorldRef world)
556 {
557     WorldMap::const_iterator end = worldMap().end();
558     for (WorldMap::const_iterator it = worldMap().begin(); it != end; ++it) {
559         if (it->value == world)
560             return it->key;
561     }
562
563     return 0;
564 }
565
566 void TestRunner::evaluateScriptInIsolatedWorld(JSContextRef context, unsigned worldID, JSStringRef script)
567 {
568     // A worldID of 0 always corresponds to a new world. Any other worldID corresponds to a world
569     // that is created once and cached forever.
570     WKRetainPtr<WKBundleScriptWorldRef> world;
571     if (!worldID)
572         world.adopt(WKBundleScriptWorldCreateWorld());
573     else {
574         WKRetainPtr<WKBundleScriptWorldRef>& worldSlot = worldMap().add(worldID, nullptr).iterator->value;
575         if (!worldSlot)
576             worldSlot.adopt(WKBundleScriptWorldCreateWorld());
577         world = worldSlot;
578     }
579
580     WKBundleFrameRef frame = WKBundleFrameForJavaScriptContext(context);
581     if (!frame)
582         frame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
583
584     JSGlobalContextRef jsContext = WKBundleFrameGetJavaScriptContextForWorld(frame, world.get());
585     JSEvaluateScript(jsContext, script, 0, 0, 0, 0); 
586 }
587
588 void TestRunner::setPOSIXLocale(JSStringRef locale)
589 {
590     char localeBuf[32];
591     JSStringGetUTF8CString(locale, localeBuf, sizeof(localeBuf));
592     setlocale(LC_ALL, localeBuf);
593 }
594
595 void TestRunner::setTextDirection(JSStringRef direction)
596 {
597     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
598     return WKBundleFrameSetTextDirection(mainFrame, toWK(direction).get());
599 }
600     
601 void TestRunner::setShouldStayOnPageAfterHandlingBeforeUnload(bool shouldStayOnPage)
602 {
603     InjectedBundle::singleton().postNewBeforeUnloadReturnValue(!shouldStayOnPage);
604 }
605
606 void TestRunner::setDefersLoading(bool shouldDeferLoading)
607 {
608     WKBundlePageSetDefersLoading(InjectedBundle::singleton().page()->page(), shouldDeferLoading);
609 }
610
611 void TestRunner::setPageVisibility(JSStringRef state)
612 {
613     InjectedBundle::singleton().setHidden(JSStringIsEqualToUTF8CString(state, "hidden") || JSStringIsEqualToUTF8CString(state, "prerender"));
614 }
615
616 void TestRunner::resetPageVisibility()
617 {
618     InjectedBundle::singleton().setHidden(false);
619 }
620
621 typedef WTF::HashMap<unsigned, JSValueRef> CallbackMap;
622 static CallbackMap& callbackMap()
623 {
624     static CallbackMap& map = *new CallbackMap;
625     return map;
626 }
627
628 enum {
629     AddChromeInputFieldCallbackID = 1,
630     RemoveChromeInputFieldCallbackID,
631     FocusWebViewCallbackID,
632     SetBackingScaleFactorCallbackID,
633     DidBeginSwipeCallbackID,
634     WillEndSwipeCallbackID,
635     DidEndSwipeCallbackID,
636     DidRemoveSwipeSnapshotCallbackID,
637     StatisticsDidModifyDataRecordsCallbackID,
638     FirstUIScriptCallbackID = 100
639 };
640
641 static void cacheTestRunnerCallback(unsigned index, JSValueRef callback)
642 {
643     if (!callback)
644         return;
645
646     if (callbackMap().contains(index)) {
647         InjectedBundle::singleton().outputText(String::format("FAIL: Tried to install a second TestRunner callback for the same event (id %d)\n\n", index));
648         return;
649     }
650
651     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
652     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
653     JSValueProtect(context, callback);
654     callbackMap().add(index, callback);
655 }
656
657 static void callTestRunnerCallback(unsigned index, size_t argumentCount = 0, const JSValueRef arguments[] = nullptr)
658 {
659     if (!callbackMap().contains(index))
660         return;
661     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
662     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
663     JSObjectRef callback = JSValueToObject(context, callbackMap().take(index), 0);
664     JSObjectCallAsFunction(context, callback, JSContextGetGlobalObject(context), argumentCount, arguments, 0);
665     JSValueUnprotect(context, callback);
666 }
667
668 void TestRunner::clearTestRunnerCallbacks()
669 {
670     for (auto& iter : callbackMap()) {
671         WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
672         JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
673         JSObjectRef callback = JSValueToObject(context, iter.value, 0);
674         JSValueUnprotect(context, callback);
675     }
676
677     callbackMap().clear();
678 }
679
680 void TestRunner::accummulateLogsForChannel(JSStringRef)
681 {
682     // FIXME: Implement getting the call to all processes.
683 }
684
685 void TestRunner::addChromeInputField(JSValueRef callback)
686 {
687     cacheTestRunnerCallback(AddChromeInputFieldCallbackID, callback);
688     InjectedBundle::singleton().postAddChromeInputField();
689 }
690
691 void TestRunner::removeChromeInputField(JSValueRef callback)
692 {
693     cacheTestRunnerCallback(RemoveChromeInputFieldCallbackID, callback);
694     InjectedBundle::singleton().postRemoveChromeInputField();
695 }
696
697 void TestRunner::focusWebView(JSValueRef callback)
698 {
699     cacheTestRunnerCallback(FocusWebViewCallbackID, callback);
700     InjectedBundle::singleton().postFocusWebView();
701 }
702
703 void TestRunner::setBackingScaleFactor(double backingScaleFactor, JSValueRef callback)
704 {
705     cacheTestRunnerCallback(SetBackingScaleFactorCallbackID, callback);
706     InjectedBundle::singleton().postSetBackingScaleFactor(backingScaleFactor);
707 }
708
709 void TestRunner::setWindowIsKey(bool isKey)
710 {
711     InjectedBundle::singleton().postSetWindowIsKey(isKey);
712 }
713
714 void TestRunner::setViewSize(double width, double height)
715 {
716     InjectedBundle::singleton().postSetViewSize(width, height);
717 }
718
719 void TestRunner::callAddChromeInputFieldCallback()
720 {
721     callTestRunnerCallback(AddChromeInputFieldCallbackID);
722 }
723
724 void TestRunner::callRemoveChromeInputFieldCallback()
725 {
726     callTestRunnerCallback(RemoveChromeInputFieldCallbackID);
727 }
728
729 void TestRunner::callFocusWebViewCallback()
730 {
731     callTestRunnerCallback(FocusWebViewCallbackID);
732 }
733
734 void TestRunner::callSetBackingScaleFactorCallback()
735 {
736     callTestRunnerCallback(SetBackingScaleFactorCallbackID);
737 }
738
739 static inline bool toBool(JSStringRef value)
740 {
741     return JSStringIsEqualToUTF8CString(value, "true") || JSStringIsEqualToUTF8CString(value, "1");
742 }
743
744 void TestRunner::overridePreference(JSStringRef preference, JSStringRef value)
745 {
746     auto& injectedBundle = InjectedBundle::singleton();
747     // FIXME: handle non-boolean preferences.
748     WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), toWK(preference).get(), toBool(value));
749 }
750
751 void TestRunner::setAlwaysAcceptCookies(bool accept)
752 {
753     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetAlwaysAcceptCookies"));
754
755     WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(accept));
756
757     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
758 }
759
760 void TestRunner::setCookieStoragePartitioningEnabled(bool enabled)
761 {
762     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetCookieStoragePartitioningEnabled"));
763
764     WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(enabled));
765
766     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
767 }
768
769 double TestRunner::preciseTime()
770 {
771     return currentTime();
772 }
773
774 void TestRunner::setUserStyleSheetEnabled(bool enabled)
775 {
776     m_userStyleSheetEnabled = enabled;
777
778     WKRetainPtr<WKStringRef> emptyUrl = adoptWK(WKStringCreateWithUTF8CString(""));
779     WKStringRef location = enabled ? m_userStyleSheetLocation.get() : emptyUrl.get();
780     auto& injectedBundle = InjectedBundle::singleton();
781     WKBundleSetUserStyleSheetLocation(injectedBundle.bundle(), injectedBundle.pageGroup(), location);
782 }
783
784 void TestRunner::setUserStyleSheetLocation(JSStringRef location)
785 {
786     m_userStyleSheetLocation = adoptWK(WKStringCreateWithJSString(location));
787
788     if (m_userStyleSheetEnabled)
789         setUserStyleSheetEnabled(true);
790 }
791
792 void TestRunner::setSpatialNavigationEnabled(bool enabled)
793 {
794     auto& injectedBundle = InjectedBundle::singleton();
795     WKBundleSetSpatialNavigationEnabled(injectedBundle.bundle(), injectedBundle.pageGroup(), enabled);
796 }
797
798 void TestRunner::setTabKeyCyclesThroughElements(bool enabled)
799 {
800     auto& injectedBundle = InjectedBundle::singleton();
801     WKBundleSetTabKeyCyclesThroughElements(injectedBundle.bundle(), injectedBundle.page()->page(), enabled);
802 }
803
804 void TestRunner::setSerializeHTTPLoads()
805 {
806     // WK2 doesn't reorder loads.
807 }
808
809 void TestRunner::dispatchPendingLoadRequests()
810 {
811     // WK2 doesn't keep pending requests.
812 }
813
814 void TestRunner::setCacheModel(int model)
815 {
816     InjectedBundle::singleton().setCacheModel(model);
817 }
818
819 void TestRunner::setAsynchronousSpellCheckingEnabled(bool enabled)
820 {
821     auto& injectedBundle = InjectedBundle::singleton();
822     WKBundleSetAsynchronousSpellCheckingEnabled(injectedBundle.bundle(), injectedBundle.pageGroup(), enabled);
823 }
824
825 void TestRunner::grantWebNotificationPermission(JSStringRef origin)
826 {
827     WKRetainPtr<WKStringRef> originWK = toWK(origin);
828     auto& injectedBundle = InjectedBundle::singleton();
829     WKBundleSetWebNotificationPermission(injectedBundle.bundle(), injectedBundle.page()->page(), originWK.get(), true);
830 }
831
832 void TestRunner::denyWebNotificationPermission(JSStringRef origin)
833 {
834     WKRetainPtr<WKStringRef> originWK = toWK(origin);
835     auto& injectedBundle = InjectedBundle::singleton();
836     WKBundleSetWebNotificationPermission(injectedBundle.bundle(), injectedBundle.page()->page(), originWK.get(), false);
837 }
838
839 void TestRunner::removeAllWebNotificationPermissions()
840 {
841     auto& injectedBundle = InjectedBundle::singleton();
842     WKBundleRemoveAllWebNotificationPermissions(injectedBundle.bundle(), injectedBundle.page()->page());
843 }
844
845 void TestRunner::simulateWebNotificationClick(JSValueRef notification)
846 {
847     auto& injectedBundle = InjectedBundle::singleton();
848     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(injectedBundle.page()->page());
849     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
850     uint64_t notificationID = WKBundleGetWebNotificationID(injectedBundle.bundle(), context, notification);
851     injectedBundle.postSimulateWebNotificationClick(notificationID);
852 }
853
854 void TestRunner::setGeolocationPermission(bool enabled)
855 {
856     // FIXME: this should be done by frame.
857     InjectedBundle::singleton().setGeolocationPermission(enabled);
858 }
859
860 bool TestRunner::isGeolocationProviderActive()
861 {
862     return InjectedBundle::singleton().isGeolocationProviderActive();
863 }
864
865 void TestRunner::setMockGeolocationPosition(double latitude, double longitude, double accuracy, JSValueRef jsAltitude, JSValueRef jsAltitudeAccuracy, JSValueRef jsHeading, JSValueRef jsSpeed)
866 {
867     auto& injectedBundle = InjectedBundle::singleton();
868     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(injectedBundle.page()->page());
869     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
870
871     bool providesAltitude = false;
872     double altitude = 0.;
873     if (!JSValueIsUndefined(context, jsAltitude)) {
874         providesAltitude = true;
875         altitude = JSValueToNumber(context, jsAltitude, 0);
876     }
877
878     bool providesAltitudeAccuracy = false;
879     double altitudeAccuracy = 0.;
880     if (!JSValueIsUndefined(context, jsAltitudeAccuracy)) {
881         providesAltitudeAccuracy = true;
882         altitudeAccuracy = JSValueToNumber(context, jsAltitudeAccuracy, 0);
883     }
884
885     bool providesHeading = false;
886     double heading = 0.;
887     if (!JSValueIsUndefined(context, jsHeading)) {
888         providesHeading = true;
889         heading = JSValueToNumber(context, jsHeading, 0);
890     }
891
892     bool providesSpeed = false;
893     double speed = 0.;
894     if (!JSValueIsUndefined(context, jsSpeed)) {
895         providesSpeed = true;
896         speed = JSValueToNumber(context, jsSpeed, 0);
897     }
898
899     injectedBundle.setMockGeolocationPosition(latitude, longitude, accuracy, providesAltitude, altitude, providesAltitudeAccuracy, altitudeAccuracy, providesHeading, heading, providesSpeed, speed);
900 }
901
902 void TestRunner::setMockGeolocationPositionUnavailableError(JSStringRef message)
903 {
904     WKRetainPtr<WKStringRef> messageWK = toWK(message);
905     InjectedBundle::singleton().setMockGeolocationPositionUnavailableError(messageWK.get());
906 }
907
908 void TestRunner::setUserMediaPermission(bool enabled)
909 {
910     // FIXME: this should be done by frame.
911     InjectedBundle::singleton().setUserMediaPermission(enabled);
912 }
913
914 void TestRunner::setUserMediaPersistentPermissionForOrigin(bool permission, JSStringRef origin, JSStringRef parentOrigin)
915 {
916     WKRetainPtr<WKStringRef> originWK = toWK(origin);
917     WKRetainPtr<WKStringRef> parentOriginWK = toWK(parentOrigin);
918     InjectedBundle::singleton().setUserMediaPersistentPermissionForOrigin(permission, originWK.get(), parentOriginWK.get());
919 }
920
921 unsigned TestRunner::userMediaPermissionRequestCountForOrigin(JSStringRef origin, JSStringRef parentOrigin) const
922 {
923     WKRetainPtr<WKStringRef> originWK = toWK(origin);
924     WKRetainPtr<WKStringRef> parentOriginWK = toWK(parentOrigin);
925     return InjectedBundle::singleton().userMediaPermissionRequestCountForOrigin(originWK.get(), parentOriginWK.get());
926 }
927
928 void TestRunner::resetUserMediaPermissionRequestCountForOrigin(JSStringRef origin, JSStringRef parentOrigin)
929 {
930     WKRetainPtr<WKStringRef> originWK = toWK(origin);
931     WKRetainPtr<WKStringRef> parentOriginWK = toWK(parentOrigin);
932     InjectedBundle::singleton().resetUserMediaPermissionRequestCountForOrigin(originWK.get(), parentOriginWK.get());
933 }
934
935 bool TestRunner::callShouldCloseOnWebView()
936 {
937     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
938     return WKBundleFrameCallShouldCloseOnWebView(mainFrame);
939 }
940
941 void TestRunner::queueBackNavigation(unsigned howFarBackward)
942 {
943     InjectedBundle::singleton().queueBackNavigation(howFarBackward);
944 }
945
946 void TestRunner::queueForwardNavigation(unsigned howFarForward)
947 {
948     InjectedBundle::singleton().queueForwardNavigation(howFarForward);
949 }
950
951 void TestRunner::queueLoad(JSStringRef url, JSStringRef target, bool shouldOpenExternalURLs)
952 {
953     auto& injectedBundle = InjectedBundle::singleton();
954     WKRetainPtr<WKURLRef> baseURLWK(AdoptWK, WKBundleFrameCopyURL(WKBundlePageGetMainFrame(injectedBundle.page()->page())));
955     WKRetainPtr<WKURLRef> urlWK(AdoptWK, WKURLCreateWithBaseURL(baseURLWK.get(), toWTFString(toWK(url)).utf8().data()));
956     WKRetainPtr<WKStringRef> urlStringWK(AdoptWK, WKURLCopyString(urlWK.get()));
957
958     injectedBundle.queueLoad(urlStringWK.get(), toWK(target).get(), shouldOpenExternalURLs);
959 }
960
961 void TestRunner::queueLoadHTMLString(JSStringRef content, JSStringRef baseURL, JSStringRef unreachableURL)
962 {
963     WKRetainPtr<WKStringRef> contentWK = toWK(content);
964     WKRetainPtr<WKStringRef> baseURLWK = baseURL ? toWK(baseURL) : WKRetainPtr<WKStringRef>();
965     WKRetainPtr<WKStringRef> unreachableURLWK = unreachableURL ? toWK(unreachableURL) : WKRetainPtr<WKStringRef>();
966
967     InjectedBundle::singleton().queueLoadHTMLString(contentWK.get(), baseURLWK.get(), unreachableURLWK.get());
968 }
969
970 void TestRunner::queueReload()
971 {
972     InjectedBundle::singleton().queueReload();
973 }
974
975 void TestRunner::queueLoadingScript(JSStringRef script)
976 {
977     WKRetainPtr<WKStringRef> scriptWK = toWK(script);
978     InjectedBundle::singleton().queueLoadingScript(scriptWK.get());
979 }
980
981 void TestRunner::queueNonLoadingScript(JSStringRef script)
982 {
983     WKRetainPtr<WKStringRef> scriptWK = toWK(script);
984     InjectedBundle::singleton().queueNonLoadingScript(scriptWK.get());
985 }
986
987 void TestRunner::setRejectsProtectionSpaceAndContinueForAuthenticationChallenges(bool value)
988 {
989     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetRejectsProtectionSpaceAndContinueForAuthenticationChallenges"));
990     WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(value));
991     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
992 }
993     
994 void TestRunner::setHandlesAuthenticationChallenges(bool handlesAuthenticationChallenges)
995 {
996     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetHandlesAuthenticationChallenges"));
997     WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(handlesAuthenticationChallenges));
998     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
999 }
1000
1001 void TestRunner::setShouldLogCanAuthenticateAgainstProtectionSpace(bool value)
1002 {
1003     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetShouldLogCanAuthenticateAgainstProtectionSpace"));
1004     WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(value));
1005     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
1006 }
1007
1008 void TestRunner::setAuthenticationUsername(JSStringRef username)
1009 {
1010     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetAuthenticationUsername"));
1011     WKRetainPtr<WKStringRef> messageBody(AdoptWK, WKStringCreateWithJSString(username));
1012     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
1013 }
1014
1015 void TestRunner::setAuthenticationPassword(JSStringRef password)
1016 {
1017     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetAuthenticationPassword"));
1018     WKRetainPtr<WKStringRef> messageBody(AdoptWK, WKStringCreateWithJSString(password));
1019     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
1020 }
1021
1022 bool TestRunner::secureEventInputIsEnabled() const
1023 {
1024     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SecureEventInputIsEnabled"));
1025     WKTypeRef returnData = 0;
1026
1027     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), 0, &returnData);
1028     return WKBooleanGetValue(static_cast<WKBooleanRef>(returnData));
1029 }
1030
1031 void TestRunner::setBlockAllPlugins(bool shouldBlock)
1032 {
1033     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetBlockAllPlugins"));
1034     WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(shouldBlock));
1035     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
1036 }
1037
1038 JSValueRef TestRunner::failNextNewCodeBlock()
1039 {
1040     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
1041     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
1042     return JSC::failNextNewCodeBlock(context);
1043 }
1044
1045 JSValueRef TestRunner::numberOfDFGCompiles(JSValueRef theFunction)
1046 {
1047     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
1048     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
1049     return JSC::numberOfDFGCompiles(context, theFunction);
1050 }
1051
1052 JSValueRef TestRunner::neverInlineFunction(JSValueRef theFunction)
1053 {
1054     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
1055     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
1056     return JSC::setNeverInline(context, theFunction);
1057 }
1058
1059 void TestRunner::setShouldDecideNavigationPolicyAfterDelay(bool value)
1060 {
1061     m_shouldDecideNavigationPolicyAfterDelay = value;
1062     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetShouldDecideNavigationPolicyAfterDelay"));
1063     WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(value));
1064     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
1065 }
1066
1067 void TestRunner::setNavigationGesturesEnabled(bool value)
1068 {
1069     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetNavigationGesturesEnabled"));
1070     WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(value));
1071     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
1072 }
1073
1074 void TestRunner::setIgnoresViewportScaleLimits(bool value)
1075 {
1076     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetIgnoresViewportScaleLimits"));
1077     WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(value));
1078     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
1079 }
1080
1081 void TestRunner::setShouldDownloadUndisplayableMIMETypes(bool value)
1082 {
1083     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetShouldDownloadUndisplayableMIMETypes"));
1084     WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(value));
1085     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
1086 }
1087
1088 void TestRunner::terminateNetworkProcess()
1089 {
1090     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("TerminateNetworkProcess"));
1091     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), nullptr);
1092 }
1093
1094 static unsigned nextUIScriptCallbackID()
1095 {
1096     static unsigned callbackID = FirstUIScriptCallbackID;
1097     return callbackID++;
1098 }
1099
1100 void TestRunner::runUIScript(JSStringRef script, JSValueRef callback)
1101 {
1102     unsigned callbackID = nextUIScriptCallbackID();
1103     cacheTestRunnerCallback(callbackID, callback);
1104
1105     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("RunUIProcessScript"));
1106
1107     WKRetainPtr<WKMutableDictionaryRef> testDictionary(AdoptWK, WKMutableDictionaryCreate());
1108
1109     WKRetainPtr<WKStringRef> scriptKey(AdoptWK, WKStringCreateWithUTF8CString("Script"));
1110     WKRetainPtr<WKStringRef> scriptValue(AdoptWK, WKStringCreateWithJSString(script));
1111
1112     WKRetainPtr<WKStringRef> callbackIDKey(AdoptWK, WKStringCreateWithUTF8CString("CallbackID"));
1113     WKRetainPtr<WKUInt64Ref> callbackIDValue = adoptWK(WKUInt64Create(callbackID));
1114
1115     WKDictionarySetItem(testDictionary.get(), scriptKey.get(), scriptValue.get());
1116     WKDictionarySetItem(testDictionary.get(), callbackIDKey.get(), callbackIDValue.get());
1117
1118     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), testDictionary.get());
1119 }
1120
1121 void TestRunner::runUIScriptCallback(unsigned callbackID, JSStringRef result)
1122 {
1123     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
1124     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
1125
1126     JSValueRef resultValue = JSValueMakeString(context, result);
1127     callTestRunnerCallback(callbackID, 1, &resultValue);
1128 }
1129
1130 void TestRunner::installDidBeginSwipeCallback(JSValueRef callback)
1131 {
1132     cacheTestRunnerCallback(DidBeginSwipeCallbackID, callback);
1133 }
1134
1135 void TestRunner::installWillEndSwipeCallback(JSValueRef callback)
1136 {
1137     cacheTestRunnerCallback(WillEndSwipeCallbackID, callback);
1138 }
1139
1140 void TestRunner::installDidEndSwipeCallback(JSValueRef callback)
1141 {
1142     cacheTestRunnerCallback(DidEndSwipeCallbackID, callback);
1143 }
1144
1145 void TestRunner::installDidRemoveSwipeSnapshotCallback(JSValueRef callback)
1146 {
1147     cacheTestRunnerCallback(DidRemoveSwipeSnapshotCallbackID, callback);
1148 }
1149
1150 void TestRunner::callDidBeginSwipeCallback()
1151 {
1152     callTestRunnerCallback(DidBeginSwipeCallbackID);
1153 }
1154
1155 void TestRunner::callWillEndSwipeCallback()
1156 {
1157     callTestRunnerCallback(WillEndSwipeCallbackID);
1158 }
1159
1160 void TestRunner::callDidEndSwipeCallback()
1161 {
1162     callTestRunnerCallback(DidEndSwipeCallbackID);
1163 }
1164
1165 void TestRunner::callDidRemoveSwipeSnapshotCallback()
1166 {
1167     callTestRunnerCallback(DidRemoveSwipeSnapshotCallbackID);
1168 }
1169
1170 void TestRunner::setStatisticsPrevalentResource(JSStringRef hostName, bool value)
1171 {
1172     Vector<WKRetainPtr<WKStringRef>> keys;
1173     Vector<WKRetainPtr<WKTypeRef>> values;
1174
1175     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("HostName") });
1176     values.append({ AdoptWK, WKStringCreateWithJSString(hostName) });
1177     
1178     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("Value") });
1179     values.append({ AdoptWK, WKBooleanCreate(value) });
1180     
1181     Vector<WKStringRef> rawKeys;
1182     Vector<WKTypeRef> rawValues;
1183     rawKeys.resize(keys.size());
1184     rawValues.resize(values.size());
1185     
1186     for (size_t i = 0; i < keys.size(); ++i) {
1187         rawKeys[i] = keys[i].get();
1188         rawValues[i] = values[i].get();
1189     }
1190     
1191     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetStatisticsPrevalentResource"));
1192     WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1193
1194     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1195 }
1196
1197 bool TestRunner::isStatisticsPrevalentResource(JSStringRef hostName)
1198 {
1199     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("IsStatisticsPrevalentResource"));
1200     WKRetainPtr<WKStringRef> messageBody(AdoptWK, WKStringCreateWithJSString(hostName));
1201     WKTypeRef returnData = 0;
1202     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get(), &returnData);
1203     return WKBooleanGetValue(static_cast<WKBooleanRef>(returnData));
1204 }
1205
1206 void TestRunner::setStatisticsHasHadUserInteraction(JSStringRef hostName, bool value)
1207 {
1208     Vector<WKRetainPtr<WKStringRef>> keys;
1209     Vector<WKRetainPtr<WKTypeRef>> values;
1210     
1211     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("HostName") });
1212     values.append({ AdoptWK, WKStringCreateWithJSString(hostName) });
1213     
1214     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("Value") });
1215     values.append({ AdoptWK, WKBooleanCreate(value) });
1216     
1217     Vector<WKStringRef> rawKeys;
1218     Vector<WKTypeRef> rawValues;
1219     rawKeys.resize(keys.size());
1220     rawValues.resize(values.size());
1221     
1222     for (size_t i = 0; i < keys.size(); ++i) {
1223         rawKeys[i] = keys[i].get();
1224         rawValues[i] = values[i].get();
1225     }
1226     
1227     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetStatisticsHasHadUserInteraction"));
1228     WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1229     
1230     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1231 }
1232
1233 bool TestRunner::isStatisticsHasHadUserInteraction(JSStringRef hostName)
1234 {
1235     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("IsStatisticsHasHadUserInteraction"));
1236     WKRetainPtr<WKStringRef> messageBody(AdoptWK, WKStringCreateWithJSString(hostName));
1237     WKTypeRef returnData = 0;
1238     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get(), &returnData);
1239     return WKBooleanGetValue(static_cast<WKBooleanRef>(returnData));
1240 }
1241
1242 void TestRunner::setStatisticsSubframeUnderTopFrameOrigin(JSStringRef hostName, JSStringRef topFrameHostName)
1243 {
1244     Vector<WKRetainPtr<WKStringRef>> keys;
1245     Vector<WKRetainPtr<WKTypeRef>> values;
1246     
1247     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("HostName") });
1248     values.append({ AdoptWK, WKStringCreateWithJSString(hostName) });
1249     
1250     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("TopFrameHostName") });
1251     values.append({ AdoptWK, WKStringCreateWithJSString(topFrameHostName) });
1252     
1253     Vector<WKStringRef> rawKeys(keys.size());
1254     Vector<WKTypeRef> rawValues(values.size());
1255     
1256     for (size_t i = 0; i < keys.size(); ++i) {
1257         rawKeys[i] = keys[i].get();
1258         rawValues[i] = values[i].get();
1259     }
1260     
1261     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetStatisticsSubframeUnderTopFrameOrigin"));
1262     WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1263     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1264 }
1265
1266 void TestRunner::setStatisticsSubresourceUnderTopFrameOrigin(JSStringRef hostName, JSStringRef topFrameHostName)
1267 {
1268     Vector<WKRetainPtr<WKStringRef>> keys;
1269     Vector<WKRetainPtr<WKTypeRef>> values;
1270     
1271     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("HostName") });
1272     values.append({ AdoptWK, WKStringCreateWithJSString(hostName) });
1273     
1274     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("TopFrameHostName") });
1275     values.append({ AdoptWK, WKStringCreateWithJSString(topFrameHostName) });
1276     
1277     Vector<WKStringRef> rawKeys(keys.size());
1278     Vector<WKTypeRef> rawValues(values.size());
1279     
1280     for (size_t i = 0; i < keys.size(); ++i) {
1281         rawKeys[i] = keys[i].get();
1282         rawValues[i] = values[i].get();
1283     }
1284     
1285     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetStatisticsSubresourceUnderTopFrameOrigin"));
1286     WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1287     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1288 }
1289
1290 void TestRunner::setStatisticsSubresourceUniqueRedirectTo(JSStringRef hostName, JSStringRef hostNameRedirectedTo)
1291 {
1292     Vector<WKRetainPtr<WKStringRef>> keys;
1293     Vector<WKRetainPtr<WKTypeRef>> values;
1294     
1295     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("HostName") });
1296     values.append({ AdoptWK, WKStringCreateWithJSString(hostName) });
1297     
1298     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("HostNameRedirectedTo") });
1299     values.append({ AdoptWK, WKStringCreateWithJSString(hostNameRedirectedTo) });
1300     
1301     Vector<WKStringRef> rawKeys(keys.size());
1302     Vector<WKTypeRef> rawValues(values.size());
1303     
1304     for (size_t i = 0; i < keys.size(); ++i) {
1305         rawKeys[i] = keys[i].get();
1306         rawValues[i] = values[i].get();
1307     }
1308     
1309     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetStatisticsSubresourceUniqueRedirectTo"));
1310     WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1311     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1312 }
1313
1314 void TestRunner::setStatisticsTimeToLiveUserInteraction(double seconds)
1315 {
1316     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetStatisticsTimeToLiveUserInteraction"));
1317     WKRetainPtr<WKDoubleRef> messageBody(AdoptWK, WKDoubleCreate(seconds));
1318     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1319 }
1320
1321 void TestRunner::setStatisticsTimeToLiveCookiePartitionFree(double seconds)
1322 {
1323     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetStatisticsTimeToLiveCookiePartitionFree"));
1324     WKRetainPtr<WKDoubleRef> messageBody(AdoptWK, WKDoubleCreate(seconds));
1325     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1326 }
1327
1328 void TestRunner::installStatisticsDidModifyDataRecordsCallback(JSValueRef callback)
1329 {
1330     cacheTestRunnerCallback(StatisticsDidModifyDataRecordsCallbackID, callback);
1331 }
1332
1333 void TestRunner::statisticsDidModifyDataRecordsCallback()
1334 {
1335     callTestRunnerCallback(StatisticsDidModifyDataRecordsCallbackID);
1336 }
1337
1338 void TestRunner::statisticsFireDataModificationHandler()
1339 {
1340     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("StatisticsFireDataModificationHandler"));
1341     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), 0, nullptr);
1342 }
1343
1344 void TestRunner::statisticsFireShouldPartitionCookiesHandler()
1345 {
1346     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("StatisticsFireShouldPartitionCookiesHandler"));
1347     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), 0, nullptr);
1348 }
1349
1350 void TestRunner::statisticsFireShouldPartitionCookiesHandlerForOneDomain(JSStringRef hostName, bool value)
1351 {
1352     Vector<WKRetainPtr<WKStringRef>> keys;
1353     Vector<WKRetainPtr<WKTypeRef>> values;
1354     
1355     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("HostName") });
1356     values.append({ AdoptWK, WKStringCreateWithJSString(hostName) });
1357     
1358     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("Value") });
1359     values.append({ AdoptWK, WKBooleanCreate(value) });
1360     
1361     Vector<WKStringRef> rawKeys(keys.size());
1362     Vector<WKTypeRef> rawValues(values.size());
1363     
1364     for (size_t i = 0; i < keys.size(); ++i) {
1365         rawKeys[i] = keys[i].get();
1366         rawValues[i] = values[i].get();
1367     }
1368     
1369     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("StatisticsFireShouldPartitionCookiesHandlerForOneDomain"));
1370     WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1371     
1372     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1373 }
1374
1375 void TestRunner::setStatisticsNotifyPagesWhenDataRecordsWereScanned(bool value)
1376 {
1377     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("StatisticsNotifyPagesWhenDataRecordsWereScanned"));
1378     WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(value));
1379     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1380 }
1381
1382 void TestRunner::setStatisticsShouldClassifyResourcesBeforeDataRecordsRemoval(bool value)
1383 {
1384     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("StatisticsShouldClassifyResourcesBeforeDataRecordsRemoval"));
1385     WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(value));
1386     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1387 }
1388
1389 void TestRunner::setStatisticsMinimumTimeBetweeenDataRecordsRemoval(double seconds)
1390 {
1391     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetStatisticsMinimumTimeBetweeenDataRecordsRemoval"));
1392     WKRetainPtr<WKDoubleRef> messageBody(AdoptWK, WKDoubleCreate(seconds));
1393     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1394 }
1395
1396 void TestRunner::statisticsClearInMemoryAndPersistentStore()
1397 {
1398     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("StatisticsClearInMemoryAndPersistentStore"));
1399     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), 0, nullptr);
1400 }
1401
1402 void TestRunner::statisticsClearInMemoryAndPersistentStoreModifiedSinceHours(unsigned hours)
1403 {
1404     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("StatisticsClearInMemoryAndPersistentStoreModifiedSinceHours"));
1405     WKRetainPtr<WKTypeRef> messageBody(AdoptWK, WKUInt64Create(hours));
1406     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1407 }
1408
1409 void TestRunner::statisticsResetToConsistentState()
1410 {
1411     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("StatisticsResetToConsistentState"));
1412     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), 0, nullptr);
1413 }
1414
1415 #if PLATFORM(MAC)
1416 void TestRunner::connectMockGamepad(unsigned index)
1417 {
1418     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("ConnectMockGamepad"));
1419     WKRetainPtr<WKTypeRef> messageBody(AdoptWK, WKUInt64Create(index));
1420
1421     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1422 }
1423
1424 void TestRunner::disconnectMockGamepad(unsigned index)
1425 {
1426     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("DisconnectMockGamepad"));
1427     WKRetainPtr<WKTypeRef> messageBody(AdoptWK, WKUInt64Create(index));
1428
1429     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1430 }
1431
1432 void TestRunner::setMockGamepadDetails(unsigned index, JSStringRef gamepadID, unsigned axisCount, unsigned buttonCount)
1433 {
1434     Vector<WKRetainPtr<WKStringRef>> keys;
1435     Vector<WKRetainPtr<WKTypeRef>> values;
1436
1437     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("GamepadID") });
1438     values.append(toWK(gamepadID));
1439
1440     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("GamepadIndex") });
1441     values.append({ AdoptWK, WKUInt64Create(index) });
1442
1443     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("AxisCount") });
1444     values.append({ AdoptWK, WKUInt64Create(axisCount) });
1445
1446     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("ButtonCount") });
1447     values.append({ AdoptWK, WKUInt64Create(buttonCount) });
1448
1449     Vector<WKStringRef> rawKeys;
1450     Vector<WKTypeRef> rawValues;
1451     rawKeys.resize(keys.size());
1452     rawValues.resize(values.size());
1453
1454     for (size_t i = 0; i < keys.size(); ++i) {
1455         rawKeys[i] = keys[i].get();
1456         rawValues[i] = values[i].get();
1457     }
1458
1459     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetMockGamepadDetails"));
1460     WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1461
1462     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1463 }
1464
1465 void TestRunner::setMockGamepadAxisValue(unsigned index, unsigned axisIndex, double value)
1466 {
1467     Vector<WKRetainPtr<WKStringRef>> keys;
1468     Vector<WKRetainPtr<WKTypeRef>> values;
1469
1470     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("GamepadIndex") });
1471     values.append({ AdoptWK, WKUInt64Create(index) });
1472
1473     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("AxisIndex") });
1474     values.append({ AdoptWK, WKUInt64Create(axisIndex) });
1475
1476     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("Value") });
1477     values.append({ AdoptWK, WKDoubleCreate(value) });
1478
1479     Vector<WKStringRef> rawKeys;
1480     Vector<WKTypeRef> rawValues;
1481     rawKeys.resize(keys.size());
1482     rawValues.resize(values.size());
1483
1484     for (size_t i = 0; i < keys.size(); ++i) {
1485         rawKeys[i] = keys[i].get();
1486         rawValues[i] = values[i].get();
1487     }
1488
1489     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetMockGamepadAxisValue"));
1490     WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1491
1492     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1493 }
1494
1495 void TestRunner::setMockGamepadButtonValue(unsigned index, unsigned buttonIndex, double value)
1496 {
1497     Vector<WKRetainPtr<WKStringRef>> keys;
1498     Vector<WKRetainPtr<WKTypeRef>> values;
1499
1500     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("GamepadIndex") });
1501     values.append({ AdoptWK, WKUInt64Create(index) });
1502
1503     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("ButtonIndex") });
1504     values.append({ AdoptWK, WKUInt64Create(buttonIndex) });
1505
1506     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("Value") });
1507     values.append({ AdoptWK, WKDoubleCreate(value) });
1508
1509     Vector<WKStringRef> rawKeys;
1510     Vector<WKTypeRef> rawValues;
1511     rawKeys.resize(keys.size());
1512     rawValues.resize(values.size());
1513
1514     for (size_t i = 0; i < keys.size(); ++i) {
1515         rawKeys[i] = keys[i].get();
1516         rawValues[i] = values[i].get();
1517     }
1518
1519     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetMockGamepadButtonValue"));
1520     WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1521
1522     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1523 }
1524 #else
1525 void TestRunner::connectMockGamepad(unsigned)
1526 {
1527 }
1528
1529 void TestRunner::disconnectMockGamepad(unsigned)
1530 {
1531 }
1532
1533 void TestRunner::setMockGamepadDetails(unsigned, JSStringRef, unsigned, unsigned)
1534 {
1535 }
1536
1537 void TestRunner::setMockGamepadAxisValue(unsigned, unsigned, double)
1538 {
1539 }
1540
1541 void TestRunner::setMockGamepadButtonValue(unsigned, unsigned, double)
1542 {
1543 }
1544 #endif // PLATFORM(MAC)
1545
1546 void TestRunner::setOpenPanelFiles(JSValueRef filesValue)
1547 {
1548     WKBundlePageRef page = InjectedBundle::singleton().page()->page();
1549     JSContextRef context = WKBundleFrameGetJavaScriptContext(WKBundlePageGetMainFrame(page));
1550
1551     if (!JSValueIsArray(context, filesValue))
1552         return;
1553
1554     JSObjectRef files = JSValueToObject(context, filesValue, nullptr);
1555     static auto lengthProperty = JSRetainPtr<JSStringRef>(Adopt, JSStringCreateWithUTF8CString("length"));
1556     JSValueRef filesLengthValue = JSObjectGetProperty(context, files, lengthProperty.get(), nullptr);
1557     if (!JSValueIsNumber(context, filesLengthValue))
1558         return;
1559
1560     auto fileURLs = adoptWK(WKMutableArrayCreate());
1561     auto filesLength = static_cast<size_t>(JSValueToNumber(context, filesLengthValue, nullptr));
1562     for (size_t i = 0; i < filesLength; ++i) {
1563         JSValueRef fileValue = JSObjectGetPropertyAtIndex(context, files, i, nullptr);
1564         if (!JSValueIsString(context, fileValue))
1565             continue;
1566
1567         auto file = JSRetainPtr<JSStringRef>(Adopt, JSValueToStringCopy(context, fileValue, nullptr));
1568         size_t fileBufferSize = JSStringGetMaximumUTF8CStringSize(file.get()) + 1;
1569         auto fileBuffer = std::make_unique<char[]>(fileBufferSize);
1570         JSStringGetUTF8CString(file.get(), fileBuffer.get(), fileBufferSize);
1571
1572         WKArrayAppendItem(fileURLs.get(), adoptWK(WKURLCreateWithBaseURL(m_testURL.get(), fileBuffer.get())).get());
1573     }
1574
1575     static auto messageName = adoptWK(WKStringCreateWithUTF8CString("SetOpenPanelFileURLs"));
1576     WKBundlePagePostMessage(page, messageName.get(), fileURLs.get());
1577 }
1578
1579 } // namespace WTR