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