Annotate MediaStream and WebRTC idl with EnabledAtRuntime flag
[WebKit-https.git] / Tools / WebKitTestRunner / InjectedBundle / TestRunner.cpp
1 /*
2  * Copyright (C) 2010-2016 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 <WebKit/WKBundle.h>
37 #include <WebKit/WKBundleBackForwardList.h>
38 #include <WebKit/WKBundleFrame.h>
39 #include <WebKit/WKBundleFramePrivate.h>
40 #include <WebKit/WKBundleInspector.h>
41 #include <WebKit/WKBundleNodeHandlePrivate.h>
42 #include <WebKit/WKBundlePage.h>
43 #include <WebKit/WKBundlePagePrivate.h>
44 #include <WebKit/WKBundlePrivate.h>
45 #include <WebKit/WKBundleScriptWorld.h>
46 #include <WebKit/WKData.h>
47 #include <WebKit/WKPagePrivate.h>
48 #include <WebKit/WKRetainPtr.h>
49 #include <WebKit/WKSerializedScriptValue.h>
50 #include <WebKit/WebKit2_C.h>
51 #include <wtf/CurrentTime.h>
52 #include <wtf/HashMap.h>
53 #include <wtf/StdLibExtras.h>
54 #include <wtf/text/CString.h>
55 #include <wtf/text/StringBuilder.h>
56
57 namespace WTR {
58
59 Ref<TestRunner> TestRunner::create()
60 {
61     return adoptRef(*new TestRunner);
62 }
63
64 TestRunner::TestRunner()
65     : m_whatToDump(RenderTree)
66     , m_shouldDumpAllFrameScrollPositions(false)
67     , m_shouldDumpBackForwardListsForAllWindows(false)
68     , m_shouldAllowEditing(true)
69     , m_shouldCloseExtraWindows(false)
70     , m_dumpEditingCallbacks(false)
71     , m_dumpStatusCallbacks(false)
72     , m_dumpTitleChanges(false)
73     , m_dumpPixels(true)
74     , m_dumpSelectionRect(false)
75     , m_dumpFullScreenCallbacks(false)
76     , m_dumpFrameLoadCallbacks(false)
77     , m_dumpProgressFinishedCallback(false)
78     , m_dumpResourceLoadCallbacks(false)
79     , m_dumpResourceResponseMIMETypes(false)
80     , m_dumpWillCacheResponse(false)
81     , m_dumpApplicationCacheDelegateCallbacks(false)
82     , m_dumpDatabaseCallbacks(false)
83     , m_disallowIncreaseForApplicationCacheQuota(false)
84     , m_waitToDump(false)
85     , m_testRepaint(false)
86     , m_testRepaintSweepHorizontally(false)
87     , m_isPrinting(false)
88     , m_willSendRequestReturnsNull(false)
89     , m_willSendRequestReturnsNullOnRedirect(false)
90     , m_shouldStopProvisionalFrameLoads(false)
91     , m_policyDelegateEnabled(false)
92     , m_policyDelegatePermissive(false)
93     , m_globalFlag(false)
94     , m_customFullScreenBehavior(false)
95     , m_timeout(30000)
96     , m_databaseDefaultQuota(-1)
97     , m_databaseMaxQuota(-1)
98     , m_userStyleSheetEnabled(false)
99     , m_userStyleSheetLocation(adoptWK(WKStringCreateWithUTF8CString("")))
100 #if PLATFORM(GTK)
101     , m_waitToDumpWatchdogTimer(RunLoop::main(), this, &TestRunner::waitToDumpWatchdogTimerFired)
102 #endif
103 {
104     platformInitialize();
105 }
106
107 TestRunner::~TestRunner()
108 {
109 }
110
111 JSClassRef TestRunner::wrapperClass()
112 {
113     return JSTestRunner::testRunnerClass();
114 }
115
116 void TestRunner::display()
117 {
118     WKBundlePageRef page = InjectedBundle::singleton().page()->page();
119     WKBundlePageForceRepaint(page);
120     WKBundlePageSetTracksRepaints(page, true);
121     WKBundlePageResetTrackedRepaints(page);
122 }
123
124 void TestRunner::dumpAsText(bool dumpPixels)
125 {
126     if (m_whatToDump < MainFrameText)
127         m_whatToDump = MainFrameText;
128     m_dumpPixels = dumpPixels;
129 }
130
131 void TestRunner::setCustomPolicyDelegate(bool enabled, bool permissive)
132 {
133     m_policyDelegateEnabled = enabled;
134     m_policyDelegatePermissive = permissive;
135
136     InjectedBundle::singleton().setCustomPolicyDelegate(enabled, permissive);
137 }
138
139 void TestRunner::waitForPolicyDelegate()
140 {
141     setCustomPolicyDelegate(true);
142     waitUntilDone();
143 }
144
145 void TestRunner::waitUntilDownloadFinished()
146 {
147     m_shouldFinishAfterDownload = true;
148     waitUntilDone();
149 }
150
151 void TestRunner::waitUntilDone()
152 {
153     m_waitToDump = true;
154     if (InjectedBundle::singleton().useWaitToDumpWatchdogTimer())
155         initializeWaitToDumpWatchdogTimerIfNeeded();
156 }
157
158 void TestRunner::waitToDumpWatchdogTimerFired()
159 {
160     invalidateWaitToDumpWatchdogTimer();
161     auto& injectedBundle = InjectedBundle::singleton();
162 #if PLATFORM(COCOA)
163     char buffer[1024];
164     snprintf(buffer, sizeof(buffer), "#PID UNRESPONSIVE - %s (pid %d)\n", getprogname(), getpid());
165     injectedBundle.outputText(buffer);
166 #endif
167     injectedBundle.outputText("FAIL: Timed out waiting for notifyDone to be called\n\n");
168     injectedBundle.done();
169 }
170
171 void TestRunner::notifyDone()
172 {
173     auto& injectedBundle = InjectedBundle::singleton();
174     if (!injectedBundle.isTestRunning())
175         return;
176
177     if (m_waitToDump && !injectedBundle.topLoadingFrame())
178         injectedBundle.page()->dump();
179
180     // We don't call invalidateWaitToDumpWatchdogTimer() here, even if we continue to wait for a load to finish.
181     // The test is still subject to timeout checking - it is better to detect an async timeout inside WebKitTestRunner
182     // than to let webkitpy do that, because WebKitTestRunner will dump partial results.
183
184     m_waitToDump = false;
185 }
186
187 unsigned TestRunner::imageCountInGeneralPasteboard() const
188 {
189     return InjectedBundle::singleton().imageCountInGeneralPasteboard();
190 }
191
192 void TestRunner::addUserScript(JSStringRef source, bool runAtStart, bool allFrames)
193 {
194     WKRetainPtr<WKStringRef> sourceWK = toWK(source);
195
196     WKBundlePageAddUserScript(InjectedBundle::singleton().page()->page(), sourceWK.get(),
197         (runAtStart ? kWKInjectAtDocumentStart : kWKInjectAtDocumentEnd),
198         (allFrames ? kWKInjectInAllFrames : kWKInjectInTopFrameOnly));
199 }
200
201 void TestRunner::addUserStyleSheet(JSStringRef source, bool allFrames)
202 {
203     WKRetainPtr<WKStringRef> sourceWK = toWK(source);
204
205     WKBundlePageAddUserStyleSheet(InjectedBundle::singleton().page()->page(), sourceWK.get(),
206         (allFrames ? kWKInjectInAllFrames : kWKInjectInTopFrameOnly));
207 }
208
209 void TestRunner::keepWebHistory()
210 {
211     InjectedBundle::singleton().postSetAddsVisitedLinks(true);
212 }
213
214 void TestRunner::execCommand(JSStringRef name, JSStringRef argument)
215 {
216     WKBundlePageExecuteEditingCommand(InjectedBundle::singleton().page()->page(), toWK(name).get(), toWK(argument).get());
217 }
218
219 bool TestRunner::findString(JSStringRef target, JSValueRef optionsArrayAsValue)
220 {
221     WKFindOptions options = 0;
222
223     auto& injectedBundle = InjectedBundle::singleton();
224     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(injectedBundle.page()->page());
225     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
226     JSRetainPtr<JSStringRef> lengthPropertyName(Adopt, JSStringCreateWithUTF8CString("length"));
227     JSObjectRef optionsArray = JSValueToObject(context, optionsArrayAsValue, 0);
228     JSValueRef lengthValue = JSObjectGetProperty(context, optionsArray, lengthPropertyName.get(), 0);
229     if (!JSValueIsNumber(context, lengthValue))
230         return false;
231
232     size_t length = static_cast<size_t>(JSValueToNumber(context, lengthValue, 0));
233     for (size_t i = 0; i < length; ++i) {
234         JSValueRef value = JSObjectGetPropertyAtIndex(context, optionsArray, i, 0);
235         if (!JSValueIsString(context, value))
236             continue;
237
238         JSRetainPtr<JSStringRef> optionName(Adopt, JSValueToStringCopy(context, value, 0));
239
240         if (JSStringIsEqualToUTF8CString(optionName.get(), "CaseInsensitive"))
241             options |= kWKFindOptionsCaseInsensitive;
242         else if (JSStringIsEqualToUTF8CString(optionName.get(), "AtWordStarts"))
243             options |= kWKFindOptionsAtWordStarts;
244         else if (JSStringIsEqualToUTF8CString(optionName.get(), "TreatMedialCapitalAsWordStart"))
245             options |= kWKFindOptionsTreatMedialCapitalAsWordStart;
246         else if (JSStringIsEqualToUTF8CString(optionName.get(), "Backwards"))
247             options |= kWKFindOptionsBackwards;
248         else if (JSStringIsEqualToUTF8CString(optionName.get(), "WrapAround"))
249             options |= kWKFindOptionsWrapAround;
250         else if (JSStringIsEqualToUTF8CString(optionName.get(), "StartInSelection")) {
251             // FIXME: No kWKFindOptionsStartInSelection.
252         }
253     }
254
255     return WKBundlePageFindString(injectedBundle.page()->page(), toWK(target).get(), options);
256 }
257
258 void TestRunner::clearAllDatabases()
259 {
260     WKBundleClearAllDatabases(InjectedBundle::singleton().bundle());
261
262     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("DeleteAllIndexedDatabases"));
263     WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(true));
264
265     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
266 }
267
268 void TestRunner::setDatabaseQuota(uint64_t quota)
269 {
270     return WKBundleSetDatabaseQuota(InjectedBundle::singleton().bundle(), quota);
271 }
272
273 void TestRunner::clearAllApplicationCaches()
274 {
275     WKBundlePageClearApplicationCache(InjectedBundle::singleton().page()->page());
276 }
277
278 void TestRunner::clearApplicationCacheForOrigin(JSStringRef origin)
279 {
280     WKBundlePageClearApplicationCacheForOrigin(InjectedBundle::singleton().page()->page(), toWK(origin).get());
281 }
282
283 void TestRunner::setAppCacheMaximumSize(uint64_t size)
284 {
285     WKBundlePageSetAppCacheMaximumSize(InjectedBundle::singleton().page()->page(), size);
286 }
287
288 long long TestRunner::applicationCacheDiskUsageForOrigin(JSStringRef origin)
289 {
290     return WKBundlePageGetAppCacheUsageForOrigin(InjectedBundle::singleton().page()->page(), toWK(origin).get());
291 }
292
293 void TestRunner::disallowIncreaseForApplicationCacheQuota()
294 {
295     m_disallowIncreaseForApplicationCacheQuota = true;
296 }
297
298 static inline JSValueRef stringArrayToJS(JSContextRef context, WKArrayRef strings)
299 {
300     const size_t count = WKArrayGetSize(strings);
301
302     JSValueRef arrayResult = JSObjectMakeArray(context, 0, 0, 0);
303     JSObjectRef arrayObj = JSValueToObject(context, arrayResult, 0);
304     for (size_t i = 0; i < count; ++i) {
305         WKStringRef stringRef = static_cast<WKStringRef>(WKArrayGetItemAtIndex(strings, i));
306         JSRetainPtr<JSStringRef> stringJS = toJS(stringRef);
307         JSObjectSetPropertyAtIndex(context, arrayObj, i, JSValueMakeString(context, stringJS.get()), 0);
308     }
309
310     return arrayResult;
311 }
312
313 JSValueRef TestRunner::originsWithApplicationCache()
314 {
315     WKBundlePageRef page = InjectedBundle::singleton().page()->page();
316
317     WKRetainPtr<WKArrayRef> origins(AdoptWK, WKBundlePageCopyOriginsWithApplicationCache(page));
318
319     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(page);
320     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
321
322     return stringArrayToJS(context, origins.get());
323 }
324
325 bool TestRunner::isCommandEnabled(JSStringRef name)
326 {
327     return WKBundlePageIsEditingCommandEnabled(InjectedBundle::singleton().page()->page(), toWK(name).get());
328 }
329
330 void TestRunner::setCanOpenWindows(bool)
331 {
332     // It's not clear if or why any tests require opening windows be forbidden.
333     // For now, just ignore this setting, and if we find later it's needed we can add it.
334 }
335
336 void TestRunner::setXSSAuditorEnabled(bool enabled)
337 {
338     WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitXSSAuditorEnabled"));
339     auto& injectedBundle = InjectedBundle::singleton();
340     WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
341 }
342
343 void TestRunner::setShadowDOMEnabled(bool enabled)
344 {
345     WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitShadowDOMEnabled"));
346     auto& injectedBundle = InjectedBundle::singleton();
347     WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
348 }
349
350 void TestRunner::setCustomElementsEnabled(bool enabled)
351 {
352     WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitCustomElementsEnabled"));
353     auto& injectedBundle = InjectedBundle::singleton();
354     WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
355 }
356
357 void TestRunner::setSubtleCryptoEnabled(bool enabled)
358 {
359     WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitSubtleCryptoEnabled"));
360     auto& injectedBundle = InjectedBundle::singleton();
361     WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
362 }
363
364 void TestRunner::setMediaStreamEnabled(bool enabled)
365 {
366     WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitMediaStreamEnabled"));
367     auto& injectedBundle = InjectedBundle::singleton();
368     WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
369 }
370
371 void TestRunner::setPeerConnectionEnabled(bool enabled)
372 {
373     WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitPeerConnectionEnabled"));
374     auto& injectedBundle = InjectedBundle::singleton();
375     WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
376 }
377
378 void TestRunner::setDOMIteratorEnabled(bool enabled)
379 {
380     WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitDOMIteratorEnabled"));
381     auto& injectedBundle = InjectedBundle::singleton();
382     WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
383 }
384
385 void TestRunner::setModernMediaControlsEnabled(bool enabled)
386 {
387     WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitModernMediaControlsEnabled"));
388     auto& injectedBundle = InjectedBundle::singleton();
389     WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
390 }
391
392 void TestRunner::setWebGL2Enabled(bool enabled)
393 {
394     WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitWebGL2Enabled"));
395     auto& injectedBundle = InjectedBundle::singleton();
396     WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
397 }
398
399 void TestRunner::setFetchAPIEnabled(bool enabled)
400 {
401     WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitFetchAPIEnabled"));
402     auto& injectedBundle = InjectedBundle::singleton();
403     WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
404 }
405
406 void TestRunner::setDownloadAttributeEnabled(bool enabled)
407 {
408     WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitDownloadAttributeEnabled"));
409     auto& injectedBundle = InjectedBundle::singleton();
410     WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
411 }
412
413 void TestRunner::setES6ModulesEnabled(bool enabled)
414 {
415     WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitES6ModulesEnabled"));
416     auto& injectedBundle = InjectedBundle::singleton();
417     WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
418 }
419
420 void TestRunner::setEncryptedMediaAPIEnabled(bool enabled)
421 {
422     WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitEncryptedMediaAPIEnabled"));
423     auto& injectedBundle = InjectedBundle::singleton();
424     WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
425 }
426
427 void TestRunner::setAllowsAnySSLCertificate(bool enabled)
428 {
429     InjectedBundle::singleton().setAllowsAnySSLCertificate(enabled);
430 }
431
432 void TestRunner::setAllowUniversalAccessFromFileURLs(bool enabled)
433 {
434     auto& injectedBundle = InjectedBundle::singleton();
435     WKBundleSetAllowUniversalAccessFromFileURLs(injectedBundle.bundle(), injectedBundle.pageGroup(), enabled);
436 }
437
438 void TestRunner::setAllowFileAccessFromFileURLs(bool enabled)
439 {
440     auto& injectedBundle = InjectedBundle::singleton();
441     WKBundleSetAllowFileAccessFromFileURLs(injectedBundle.bundle(), injectedBundle.pageGroup(), enabled);
442 }
443
444 void TestRunner::setNeedsStorageAccessFromFileURLsQuirk(bool needsQuirk)
445 {
446     auto& injectedBundle = InjectedBundle::singleton();
447     WKBundleSetAllowStorageAccessFromFileURLS(injectedBundle.bundle(), injectedBundle.pageGroup(), needsQuirk);
448 }
449     
450 void TestRunner::setPluginsEnabled(bool enabled)
451 {
452     WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitPluginsEnabled"));
453     auto& injectedBundle = InjectedBundle::singleton();
454     WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
455 }
456
457 void TestRunner::setJavaScriptCanAccessClipboard(bool enabled)
458 {
459     auto& injectedBundle = InjectedBundle::singleton();
460     WKBundleSetJavaScriptCanAccessClipboard(injectedBundle.bundle(), injectedBundle.pageGroup(), enabled);
461 }
462
463 void TestRunner::setPrivateBrowsingEnabled(bool enabled)
464 {
465     auto& injectedBundle = InjectedBundle::singleton();
466     WKBundleSetPrivateBrowsingEnabled(injectedBundle.bundle(), injectedBundle.pageGroup(), enabled);
467 }
468
469 void TestRunner::setUseDashboardCompatibilityMode(bool enabled)
470 {
471 #if ENABLE(DASHBOARD_SUPPORT)
472     auto& injectedBundle = InjectedBundle::singleton();
473     WKBundleSetUseDashboardCompatibilityMode(injectedBundle.bundle(), injectedBundle.pageGroup(), enabled);
474 #endif
475 }
476     
477 void TestRunner::setPopupBlockingEnabled(bool enabled)
478 {
479     auto& injectedBundle = InjectedBundle::singleton();
480     WKBundleSetPopupBlockingEnabled(injectedBundle.bundle(), injectedBundle.pageGroup(), enabled);
481 }
482
483 void TestRunner::setAuthorAndUserStylesEnabled(bool enabled)
484 {
485     auto& injectedBundle = InjectedBundle::singleton();
486     WKBundleSetAuthorAndUserStylesEnabled(injectedBundle.bundle(), injectedBundle.pageGroup(), enabled);
487 }
488
489 void TestRunner::addOriginAccessWhitelistEntry(JSStringRef sourceOrigin, JSStringRef destinationProtocol, JSStringRef destinationHost, bool allowDestinationSubdomains)
490 {
491     WKBundleAddOriginAccessWhitelistEntry(InjectedBundle::singleton().bundle(), toWK(sourceOrigin).get(), toWK(destinationProtocol).get(), toWK(destinationHost).get(), allowDestinationSubdomains);
492 }
493
494 void TestRunner::removeOriginAccessWhitelistEntry(JSStringRef sourceOrigin, JSStringRef destinationProtocol, JSStringRef destinationHost, bool allowDestinationSubdomains)
495 {
496     WKBundleRemoveOriginAccessWhitelistEntry(InjectedBundle::singleton().bundle(), toWK(sourceOrigin).get(), toWK(destinationProtocol).get(), toWK(destinationHost).get(), allowDestinationSubdomains);
497 }
498
499 bool TestRunner::isPageBoxVisible(int pageIndex)
500 {
501     auto& injectedBundle = InjectedBundle::singleton();
502     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(injectedBundle.page()->page());
503     return WKBundleIsPageBoxVisible(injectedBundle.bundle(), mainFrame, pageIndex);
504 }
505
506 void TestRunner::setValueForUser(JSContextRef context, JSValueRef element, JSStringRef value)
507 {
508     if (!element || !JSValueIsObject(context, element))
509         return;
510
511     WKRetainPtr<WKBundleNodeHandleRef> nodeHandle(AdoptWK, WKBundleNodeHandleCreate(context, const_cast<JSObjectRef>(element)));
512     WKBundleNodeHandleSetHTMLInputElementValueForUser(nodeHandle.get(), toWK(value).get());
513 }
514
515 void TestRunner::setAudioResult(JSContextRef context, JSValueRef data)
516 {
517     auto& injectedBundle = InjectedBundle::singleton();
518     // FIXME (123058): Use a JSC API to get buffer contents once such is exposed.
519     WKRetainPtr<WKDataRef> audioData(AdoptWK, WKBundleCreateWKDataFromUInt8Array(injectedBundle.bundle(), context, data));
520     injectedBundle.setAudioResult(audioData.get());
521     m_whatToDump = Audio;
522     m_dumpPixels = false;
523 }
524
525 unsigned TestRunner::windowCount()
526 {
527     return InjectedBundle::singleton().pageCount();
528 }
529
530 void TestRunner::clearBackForwardList()
531 {
532     WKBundleBackForwardListClear(WKBundlePageGetBackForwardList(InjectedBundle::singleton().page()->page()));
533 }
534
535 // Object Creation
536
537 void TestRunner::makeWindowObject(JSContextRef context, JSObjectRef windowObject, JSValueRef* exception)
538 {
539     setProperty(context, windowObject, "testRunner", this, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete, exception);
540 }
541
542 void TestRunner::showWebInspector()
543 {
544     WKBundleInspectorShow(WKBundlePageGetInspector(InjectedBundle::singleton().page()->page()));
545 }
546
547 void TestRunner::closeWebInspector()
548 {
549     WKBundleInspectorClose(WKBundlePageGetInspector(InjectedBundle::singleton().page()->page()));
550 }
551
552 void TestRunner::evaluateInWebInspector(JSStringRef script)
553 {
554     WKRetainPtr<WKStringRef> scriptWK = toWK(script);
555     WKBundleInspectorEvaluateScriptForTest(WKBundlePageGetInspector(InjectedBundle::singleton().page()->page()), scriptWK.get());
556 }
557
558 typedef WTF::HashMap<unsigned, WKRetainPtr<WKBundleScriptWorldRef> > WorldMap;
559 static WorldMap& worldMap()
560 {
561     static WorldMap& map = *new WorldMap;
562     return map;
563 }
564
565 unsigned TestRunner::worldIDForWorld(WKBundleScriptWorldRef world)
566 {
567     WorldMap::const_iterator end = worldMap().end();
568     for (WorldMap::const_iterator it = worldMap().begin(); it != end; ++it) {
569         if (it->value == world)
570             return it->key;
571     }
572
573     return 0;
574 }
575
576 void TestRunner::evaluateScriptInIsolatedWorld(JSContextRef context, unsigned worldID, JSStringRef script)
577 {
578     // A worldID of 0 always corresponds to a new world. Any other worldID corresponds to a world
579     // that is created once and cached forever.
580     WKRetainPtr<WKBundleScriptWorldRef> world;
581     if (!worldID)
582         world.adopt(WKBundleScriptWorldCreateWorld());
583     else {
584         WKRetainPtr<WKBundleScriptWorldRef>& worldSlot = worldMap().add(worldID, nullptr).iterator->value;
585         if (!worldSlot)
586             worldSlot.adopt(WKBundleScriptWorldCreateWorld());
587         world = worldSlot;
588     }
589
590     WKBundleFrameRef frame = WKBundleFrameForJavaScriptContext(context);
591     if (!frame)
592         frame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
593
594     JSGlobalContextRef jsContext = WKBundleFrameGetJavaScriptContextForWorld(frame, world.get());
595     JSEvaluateScript(jsContext, script, 0, 0, 0, 0); 
596 }
597
598 void TestRunner::setPOSIXLocale(JSStringRef locale)
599 {
600     char localeBuf[32];
601     JSStringGetUTF8CString(locale, localeBuf, sizeof(localeBuf));
602     setlocale(LC_ALL, localeBuf);
603 }
604
605 void TestRunner::setTextDirection(JSStringRef direction)
606 {
607     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
608     return WKBundleFrameSetTextDirection(mainFrame, toWK(direction).get());
609 }
610     
611 void TestRunner::setShouldStayOnPageAfterHandlingBeforeUnload(bool shouldStayOnPage)
612 {
613     InjectedBundle::singleton().postNewBeforeUnloadReturnValue(!shouldStayOnPage);
614 }
615
616 void TestRunner::setDefersLoading(bool shouldDeferLoading)
617 {
618     WKBundlePageSetDefersLoading(InjectedBundle::singleton().page()->page(), shouldDeferLoading);
619 }
620
621 void TestRunner::setPageVisibility(JSStringRef state)
622 {
623     InjectedBundle::singleton().setHidden(JSStringIsEqualToUTF8CString(state, "hidden") || JSStringIsEqualToUTF8CString(state, "prerender"));
624 }
625
626 void TestRunner::resetPageVisibility()
627 {
628     InjectedBundle::singleton().setHidden(false);
629 }
630
631 typedef WTF::HashMap<unsigned, JSValueRef> CallbackMap;
632 static CallbackMap& callbackMap()
633 {
634     static CallbackMap& map = *new CallbackMap;
635     return map;
636 }
637
638 enum {
639     AddChromeInputFieldCallbackID = 1,
640     RemoveChromeInputFieldCallbackID,
641     FocusWebViewCallbackID,
642     SetBackingScaleFactorCallbackID,
643     DidBeginSwipeCallbackID,
644     WillEndSwipeCallbackID,
645     DidEndSwipeCallbackID,
646     DidRemoveSwipeSnapshotCallbackID,
647     FirstUIScriptCallbackID = 100
648 };
649
650 static void cacheTestRunnerCallback(unsigned index, JSValueRef callback)
651 {
652     if (!callback)
653         return;
654
655     if (callbackMap().contains(index)) {
656         InjectedBundle::singleton().outputText(String::format("FAIL: Tried to install a second TestRunner callback for the same event (id %d)\n\n", index));
657         return;
658     }
659
660     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
661     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
662     JSValueProtect(context, callback);
663     callbackMap().add(index, callback);
664 }
665
666 static void callTestRunnerCallback(unsigned index, size_t argumentCount = 0, const JSValueRef arguments[] = nullptr)
667 {
668     if (!callbackMap().contains(index))
669         return;
670     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
671     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
672     JSObjectRef callback = JSValueToObject(context, callbackMap().take(index), 0);
673     JSObjectCallAsFunction(context, callback, JSContextGetGlobalObject(context), argumentCount, arguments, 0);
674     JSValueUnprotect(context, callback);
675 }
676
677 void TestRunner::clearTestRunnerCallbacks()
678 {
679     for (auto& iter : callbackMap()) {
680         WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
681         JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
682         JSObjectRef callback = JSValueToObject(context, iter.value, 0);
683         JSValueUnprotect(context, callback);
684     }
685
686     callbackMap().clear();
687 }
688
689 void TestRunner::accummulateLogsForChannel(JSStringRef)
690 {
691     // FIXME: Implement getting the call to all processes.
692 }
693
694 void TestRunner::addChromeInputField(JSValueRef callback)
695 {
696     cacheTestRunnerCallback(AddChromeInputFieldCallbackID, callback);
697     InjectedBundle::singleton().postAddChromeInputField();
698 }
699
700 void TestRunner::removeChromeInputField(JSValueRef callback)
701 {
702     cacheTestRunnerCallback(RemoveChromeInputFieldCallbackID, callback);
703     InjectedBundle::singleton().postRemoveChromeInputField();
704 }
705
706 void TestRunner::focusWebView(JSValueRef callback)
707 {
708     cacheTestRunnerCallback(FocusWebViewCallbackID, callback);
709     InjectedBundle::singleton().postFocusWebView();
710 }
711
712 void TestRunner::setBackingScaleFactor(double backingScaleFactor, JSValueRef callback)
713 {
714     cacheTestRunnerCallback(SetBackingScaleFactorCallbackID, callback);
715     InjectedBundle::singleton().postSetBackingScaleFactor(backingScaleFactor);
716 }
717
718 void TestRunner::setWindowIsKey(bool isKey)
719 {
720     InjectedBundle::singleton().postSetWindowIsKey(isKey);
721 }
722
723 void TestRunner::setViewSize(double width, double height)
724 {
725     InjectedBundle::singleton().postSetViewSize(width, height);
726 }
727
728 void TestRunner::callAddChromeInputFieldCallback()
729 {
730     callTestRunnerCallback(AddChromeInputFieldCallbackID);
731 }
732
733 void TestRunner::callRemoveChromeInputFieldCallback()
734 {
735     callTestRunnerCallback(RemoveChromeInputFieldCallbackID);
736 }
737
738 void TestRunner::callFocusWebViewCallback()
739 {
740     callTestRunnerCallback(FocusWebViewCallbackID);
741 }
742
743 void TestRunner::callSetBackingScaleFactorCallback()
744 {
745     callTestRunnerCallback(SetBackingScaleFactorCallbackID);
746 }
747
748 static inline bool toBool(JSStringRef value)
749 {
750     return JSStringIsEqualToUTF8CString(value, "true") || JSStringIsEqualToUTF8CString(value, "1");
751 }
752
753 void TestRunner::overridePreference(JSStringRef preference, JSStringRef value)
754 {
755     auto& injectedBundle = InjectedBundle::singleton();
756     // FIXME: handle non-boolean preferences.
757     WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), toWK(preference).get(), toBool(value));
758 }
759
760 void TestRunner::setAlwaysAcceptCookies(bool accept)
761 {
762     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetAlwaysAcceptCookies"));
763
764     WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(accept));
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 static unsigned nextUIScriptCallbackID()
1089 {
1090     static unsigned callbackID = FirstUIScriptCallbackID;
1091     return callbackID++;
1092 }
1093
1094 void TestRunner::runUIScript(JSStringRef script, JSValueRef callback)
1095 {
1096     unsigned callbackID = nextUIScriptCallbackID();
1097     cacheTestRunnerCallback(callbackID, callback);
1098
1099     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("RunUIProcessScript"));
1100
1101     WKRetainPtr<WKMutableDictionaryRef> testDictionary(AdoptWK, WKMutableDictionaryCreate());
1102
1103     WKRetainPtr<WKStringRef> scriptKey(AdoptWK, WKStringCreateWithUTF8CString("Script"));
1104     WKRetainPtr<WKStringRef> scriptValue(AdoptWK, WKStringCreateWithJSString(script));
1105
1106     WKRetainPtr<WKStringRef> callbackIDKey(AdoptWK, WKStringCreateWithUTF8CString("CallbackID"));
1107     WKRetainPtr<WKUInt64Ref> callbackIDValue = adoptWK(WKUInt64Create(callbackID));
1108
1109     WKDictionarySetItem(testDictionary.get(), scriptKey.get(), scriptValue.get());
1110     WKDictionarySetItem(testDictionary.get(), callbackIDKey.get(), callbackIDValue.get());
1111
1112     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), testDictionary.get());
1113 }
1114
1115 void TestRunner::runUIScriptCallback(unsigned callbackID, JSStringRef result)
1116 {
1117     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
1118     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
1119
1120     JSValueRef resultValue = JSValueMakeString(context, result);
1121     callTestRunnerCallback(callbackID, 1, &resultValue);
1122 }
1123
1124 void TestRunner::installDidBeginSwipeCallback(JSValueRef callback)
1125 {
1126     cacheTestRunnerCallback(DidBeginSwipeCallbackID, callback);
1127 }
1128
1129 void TestRunner::installWillEndSwipeCallback(JSValueRef callback)
1130 {
1131     cacheTestRunnerCallback(WillEndSwipeCallbackID, callback);
1132 }
1133
1134 void TestRunner::installDidEndSwipeCallback(JSValueRef callback)
1135 {
1136     cacheTestRunnerCallback(DidEndSwipeCallbackID, callback);
1137 }
1138
1139 void TestRunner::installDidRemoveSwipeSnapshotCallback(JSValueRef callback)
1140 {
1141     cacheTestRunnerCallback(DidRemoveSwipeSnapshotCallbackID, callback);
1142 }
1143
1144 void TestRunner::callDidBeginSwipeCallback()
1145 {
1146     callTestRunnerCallback(DidBeginSwipeCallbackID);
1147 }
1148
1149 void TestRunner::callWillEndSwipeCallback()
1150 {
1151     callTestRunnerCallback(WillEndSwipeCallbackID);
1152 }
1153
1154 void TestRunner::callDidEndSwipeCallback()
1155 {
1156     callTestRunnerCallback(DidEndSwipeCallbackID);
1157 }
1158
1159 void TestRunner::callDidRemoveSwipeSnapshotCallback()
1160 {
1161     callTestRunnerCallback(DidRemoveSwipeSnapshotCallbackID);
1162 }
1163
1164 #if PLATFORM(MAC)
1165 void TestRunner::connectMockGamepad(unsigned index)
1166 {
1167     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("ConnectMockGamepad"));
1168     WKRetainPtr<WKTypeRef> messageBody(AdoptWK, WKUInt64Create(index));
1169
1170     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1171 }
1172
1173 void TestRunner::disconnectMockGamepad(unsigned index)
1174 {
1175     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("DisconnectMockGamepad"));
1176     WKRetainPtr<WKTypeRef> messageBody(AdoptWK, WKUInt64Create(index));
1177
1178     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1179 }
1180
1181 void TestRunner::setMockGamepadDetails(unsigned index, JSStringRef gamepadID, unsigned axisCount, unsigned buttonCount)
1182 {
1183     Vector<WKRetainPtr<WKStringRef>> keys;
1184     Vector<WKRetainPtr<WKTypeRef>> values;
1185
1186     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("GamepadID") });
1187     values.append(toWK(gamepadID));
1188
1189     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("GamepadIndex") });
1190     values.append({ AdoptWK, WKUInt64Create(index) });
1191
1192     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("AxisCount") });
1193     values.append({ AdoptWK, WKUInt64Create(axisCount) });
1194
1195     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("ButtonCount") });
1196     values.append({ AdoptWK, WKUInt64Create(buttonCount) });
1197
1198     Vector<WKStringRef> rawKeys;
1199     Vector<WKTypeRef> rawValues;
1200     rawKeys.resize(keys.size());
1201     rawValues.resize(values.size());
1202
1203     for (size_t i = 0; i < keys.size(); ++i) {
1204         rawKeys[i] = keys[i].get();
1205         rawValues[i] = values[i].get();
1206     }
1207
1208     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetMockGamepadDetails"));
1209     WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1210
1211     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1212 }
1213
1214 void TestRunner::setMockGamepadAxisValue(unsigned index, unsigned axisIndex, double value)
1215 {
1216     Vector<WKRetainPtr<WKStringRef>> keys;
1217     Vector<WKRetainPtr<WKTypeRef>> values;
1218
1219     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("GamepadIndex") });
1220     values.append({ AdoptWK, WKUInt64Create(index) });
1221
1222     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("AxisIndex") });
1223     values.append({ AdoptWK, WKUInt64Create(axisIndex) });
1224
1225     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("Value") });
1226     values.append({ AdoptWK, WKDoubleCreate(value) });
1227
1228     Vector<WKStringRef> rawKeys;
1229     Vector<WKTypeRef> rawValues;
1230     rawKeys.resize(keys.size());
1231     rawValues.resize(values.size());
1232
1233     for (size_t i = 0; i < keys.size(); ++i) {
1234         rawKeys[i] = keys[i].get();
1235         rawValues[i] = values[i].get();
1236     }
1237
1238     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetMockGamepadAxisValue"));
1239     WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1240
1241     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1242 }
1243
1244 void TestRunner::setMockGamepadButtonValue(unsigned index, unsigned buttonIndex, double value)
1245 {
1246     Vector<WKRetainPtr<WKStringRef>> keys;
1247     Vector<WKRetainPtr<WKTypeRef>> values;
1248
1249     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("GamepadIndex") });
1250     values.append({ AdoptWK, WKUInt64Create(index) });
1251
1252     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("ButtonIndex") });
1253     values.append({ AdoptWK, WKUInt64Create(buttonIndex) });
1254
1255     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("Value") });
1256     values.append({ AdoptWK, WKDoubleCreate(value) });
1257
1258     Vector<WKStringRef> rawKeys;
1259     Vector<WKTypeRef> rawValues;
1260     rawKeys.resize(keys.size());
1261     rawValues.resize(values.size());
1262
1263     for (size_t i = 0; i < keys.size(); ++i) {
1264         rawKeys[i] = keys[i].get();
1265         rawValues[i] = values[i].get();
1266     }
1267
1268     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetMockGamepadButtonValue"));
1269     WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1270
1271     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1272 }
1273 #else
1274 void TestRunner::connectMockGamepad(unsigned)
1275 {
1276 }
1277
1278 void TestRunner::disconnectMockGamepad(unsigned)
1279 {
1280 }
1281
1282 void TestRunner::setMockGamepadDetails(unsigned, JSStringRef, unsigned, unsigned)
1283 {
1284 }
1285
1286 void TestRunner::setMockGamepadAxisValue(unsigned, unsigned, double)
1287 {
1288 }
1289
1290 void TestRunner::setMockGamepadButtonValue(unsigned, unsigned, double)
1291 {
1292 }
1293 #endif // PLATFORM(MAC)
1294
1295 } // namespace WTR