WK2 Gamepad layout test support.
[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/WKRetainPtr.h>
48 #include <WebKit/WKSerializedScriptValue.h>
49 #include <WebKit/WebKit2_C.h>
50 #include <wtf/CurrentTime.h>
51 #include <wtf/HashMap.h>
52 #include <wtf/StdLibExtras.h>
53 #include <wtf/text/CString.h>
54 #include <wtf/text/StringBuilder.h>
55
56 namespace WTR {
57
58 PassRefPtr<TestRunner> TestRunner::create()
59 {
60     return adoptRef(new TestRunner);
61 }
62
63 TestRunner::TestRunner()
64     : m_whatToDump(RenderTree)
65     , m_shouldDumpAllFrameScrollPositions(false)
66     , m_shouldDumpBackForwardListsForAllWindows(false)
67     , m_shouldAllowEditing(true)
68     , m_shouldCloseExtraWindows(false)
69     , m_dumpEditingCallbacks(false)
70     , m_dumpStatusCallbacks(false)
71     , m_dumpTitleChanges(false)
72     , m_dumpPixels(true)
73     , m_dumpSelectionRect(false)
74     , m_dumpFullScreenCallbacks(false)
75     , m_dumpFrameLoadCallbacks(false)
76     , m_dumpProgressFinishedCallback(false)
77     , m_dumpResourceLoadCallbacks(false)
78     , m_dumpResourceResponseMIMETypes(false)
79     , m_dumpWillCacheResponse(false)
80     , m_dumpApplicationCacheDelegateCallbacks(false)
81     , m_dumpDatabaseCallbacks(false)
82     , m_disallowIncreaseForApplicationCacheQuota(false)
83     , m_waitToDump(false)
84     , m_testRepaint(false)
85     , m_testRepaintSweepHorizontally(false)
86     , m_isPrinting(false)
87     , m_willSendRequestReturnsNull(false)
88     , m_willSendRequestReturnsNullOnRedirect(false)
89     , m_shouldStopProvisionalFrameLoads(false)
90     , m_policyDelegateEnabled(false)
91     , m_policyDelegatePermissive(false)
92     , m_globalFlag(false)
93     , m_customFullScreenBehavior(false)
94     , m_timeout(30000)
95     , m_databaseDefaultQuota(-1)
96     , m_databaseMaxQuota(-1)
97     , m_userStyleSheetEnabled(false)
98     , m_userStyleSheetLocation(adoptWK(WKStringCreateWithUTF8CString("")))
99 #if PLATFORM(GTK)
100     , m_waitToDumpWatchdogTimer(RunLoop::main(), this, &TestRunner::waitToDumpWatchdogTimerFired)
101 #endif
102 {
103     platformInitialize();
104 }
105
106 TestRunner::~TestRunner()
107 {
108 }
109
110 JSClassRef TestRunner::wrapperClass()
111 {
112     return JSTestRunner::testRunnerClass();
113 }
114
115 void TestRunner::display()
116 {
117     WKBundlePageRef page = InjectedBundle::singleton().page()->page();
118     WKBundlePageForceRepaint(page);
119     WKBundlePageSetTracksRepaints(page, true);
120     WKBundlePageResetTrackedRepaints(page);
121 }
122
123 void TestRunner::dumpAsText(bool dumpPixels)
124 {
125     if (m_whatToDump < MainFrameText)
126         m_whatToDump = MainFrameText;
127     m_dumpPixels = dumpPixels;
128 }
129
130 void TestRunner::setCustomPolicyDelegate(bool enabled, bool permissive)
131 {
132     m_policyDelegateEnabled = enabled;
133     m_policyDelegatePermissive = permissive;
134
135     InjectedBundle::singleton().setCustomPolicyDelegate(enabled, permissive);
136 }
137
138 void TestRunner::waitForPolicyDelegate()
139 {
140     setCustomPolicyDelegate(true);
141     waitUntilDone();
142 }
143
144 void TestRunner::waitUntilDownloadFinished()
145 {
146     m_shouldFinishAfterDownload = true;
147     waitUntilDone();
148 }
149
150 void TestRunner::waitUntilDone()
151 {
152     m_waitToDump = true;
153     if (InjectedBundle::singleton().useWaitToDumpWatchdogTimer())
154         initializeWaitToDumpWatchdogTimerIfNeeded();
155 }
156
157 void TestRunner::waitToDumpWatchdogTimerFired()
158 {
159     invalidateWaitToDumpWatchdogTimer();
160     auto& injectedBundle = InjectedBundle::singleton();
161     injectedBundle.outputText("FAIL: Timed out waiting for notifyDone to be called\n\n");
162     injectedBundle.done();
163 }
164
165 void TestRunner::notifyDone()
166 {
167     auto& injectedBundle = InjectedBundle::singleton();
168     if (!injectedBundle.isTestRunning())
169         return;
170
171     if (m_waitToDump && !injectedBundle.topLoadingFrame())
172         injectedBundle.page()->dump();
173
174     // We don't call invalidateWaitToDumpWatchdogTimer() here, even if we continue to wait for a load to finish.
175     // The test is still subject to timeout checking - it is better to detect an async timeout inside WebKitTestRunner
176     // than to let webkitpy do that, because WebKitTestRunner will dump partial results.
177
178     m_waitToDump = false;
179 }
180
181 unsigned TestRunner::imageCountInGeneralPasteboard() const
182 {
183     return InjectedBundle::singleton().imageCountInGeneralPasteboard();
184 }
185
186 void TestRunner::addUserScript(JSStringRef source, bool runAtStart, bool allFrames)
187 {
188     WKRetainPtr<WKStringRef> sourceWK = toWK(source);
189
190     WKBundlePageAddUserScript(InjectedBundle::singleton().page()->page(), sourceWK.get(),
191         (runAtStart ? kWKInjectAtDocumentStart : kWKInjectAtDocumentEnd),
192         (allFrames ? kWKInjectInAllFrames : kWKInjectInTopFrameOnly));
193 }
194
195 void TestRunner::addUserStyleSheet(JSStringRef source, bool allFrames)
196 {
197     WKRetainPtr<WKStringRef> sourceWK = toWK(source);
198
199     WKBundlePageAddUserStyleSheet(InjectedBundle::singleton().page()->page(), sourceWK.get(),
200         (allFrames ? kWKInjectInAllFrames : kWKInjectInTopFrameOnly));
201 }
202
203 void TestRunner::keepWebHistory()
204 {
205     InjectedBundle::singleton().postSetAddsVisitedLinks(true);
206 }
207
208 void TestRunner::execCommand(JSStringRef name, JSStringRef argument)
209 {
210     WKBundlePageExecuteEditingCommand(InjectedBundle::singleton().page()->page(), toWK(name).get(), toWK(argument).get());
211 }
212
213 bool TestRunner::findString(JSStringRef target, JSValueRef optionsArrayAsValue)
214 {
215     WKFindOptions options = 0;
216
217     auto& injectedBundle = InjectedBundle::singleton();
218     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(injectedBundle.page()->page());
219     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
220     JSRetainPtr<JSStringRef> lengthPropertyName(Adopt, JSStringCreateWithUTF8CString("length"));
221     JSObjectRef optionsArray = JSValueToObject(context, optionsArrayAsValue, 0);
222     JSValueRef lengthValue = JSObjectGetProperty(context, optionsArray, lengthPropertyName.get(), 0);
223     if (!JSValueIsNumber(context, lengthValue))
224         return false;
225
226     size_t length = static_cast<size_t>(JSValueToNumber(context, lengthValue, 0));
227     for (size_t i = 0; i < length; ++i) {
228         JSValueRef value = JSObjectGetPropertyAtIndex(context, optionsArray, i, 0);
229         if (!JSValueIsString(context, value))
230             continue;
231
232         JSRetainPtr<JSStringRef> optionName(Adopt, JSValueToStringCopy(context, value, 0));
233
234         if (JSStringIsEqualToUTF8CString(optionName.get(), "CaseInsensitive"))
235             options |= kWKFindOptionsCaseInsensitive;
236         else if (JSStringIsEqualToUTF8CString(optionName.get(), "AtWordStarts"))
237             options |= kWKFindOptionsAtWordStarts;
238         else if (JSStringIsEqualToUTF8CString(optionName.get(), "TreatMedialCapitalAsWordStart"))
239             options |= kWKFindOptionsTreatMedialCapitalAsWordStart;
240         else if (JSStringIsEqualToUTF8CString(optionName.get(), "Backwards"))
241             options |= kWKFindOptionsBackwards;
242         else if (JSStringIsEqualToUTF8CString(optionName.get(), "WrapAround"))
243             options |= kWKFindOptionsWrapAround;
244         else if (JSStringIsEqualToUTF8CString(optionName.get(), "StartInSelection")) {
245             // FIXME: No kWKFindOptionsStartInSelection.
246         }
247     }
248
249     return WKBundlePageFindString(injectedBundle.page()->page(), toWK(target).get(), options);
250 }
251
252 void TestRunner::clearAllDatabases()
253 {
254     WKBundleClearAllDatabases(InjectedBundle::singleton().bundle());
255
256     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("DeleteAllIndexedDatabases"));
257     WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(true));
258
259     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
260 }
261
262 void TestRunner::setDatabaseQuota(uint64_t quota)
263 {
264     return WKBundleSetDatabaseQuota(InjectedBundle::singleton().bundle(), quota);
265 }
266
267 void TestRunner::clearAllApplicationCaches()
268 {
269     WKBundlePageClearApplicationCache(InjectedBundle::singleton().page()->page());
270 }
271
272 void TestRunner::clearApplicationCacheForOrigin(JSStringRef origin)
273 {
274     WKBundlePageClearApplicationCacheForOrigin(InjectedBundle::singleton().page()->page(), toWK(origin).get());
275 }
276
277 void TestRunner::setAppCacheMaximumSize(uint64_t size)
278 {
279     WKBundlePageSetAppCacheMaximumSize(InjectedBundle::singleton().page()->page(), size);
280 }
281
282 long long TestRunner::applicationCacheDiskUsageForOrigin(JSStringRef origin)
283 {
284     return WKBundlePageGetAppCacheUsageForOrigin(InjectedBundle::singleton().page()->page(), toWK(origin).get());
285 }
286
287 void TestRunner::disallowIncreaseForApplicationCacheQuota()
288 {
289     m_disallowIncreaseForApplicationCacheQuota = true;
290 }
291
292 static inline JSValueRef stringArrayToJS(JSContextRef context, WKArrayRef strings)
293 {
294     const size_t count = WKArrayGetSize(strings);
295
296     JSValueRef arrayResult = JSObjectMakeArray(context, 0, 0, 0);
297     JSObjectRef arrayObj = JSValueToObject(context, arrayResult, 0);
298     for (size_t i = 0; i < count; ++i) {
299         WKStringRef stringRef = static_cast<WKStringRef>(WKArrayGetItemAtIndex(strings, i));
300         JSRetainPtr<JSStringRef> stringJS = toJS(stringRef);
301         JSObjectSetPropertyAtIndex(context, arrayObj, i, JSValueMakeString(context, stringJS.get()), 0);
302     }
303
304     return arrayResult;
305 }
306
307 JSValueRef TestRunner::originsWithApplicationCache()
308 {
309     WKBundlePageRef page = InjectedBundle::singleton().page()->page();
310
311     WKRetainPtr<WKArrayRef> origins(AdoptWK, WKBundlePageCopyOriginsWithApplicationCache(page));
312
313     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(page);
314     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
315
316     return stringArrayToJS(context, origins.get());
317 }
318
319 bool TestRunner::isCommandEnabled(JSStringRef name)
320 {
321     return WKBundlePageIsEditingCommandEnabled(InjectedBundle::singleton().page()->page(), toWK(name).get());
322 }
323
324 void TestRunner::setCanOpenWindows(bool)
325 {
326     // It's not clear if or why any tests require opening windows be forbidden.
327     // For now, just ignore this setting, and if we find later it's needed we can add it.
328 }
329
330 void TestRunner::setXSSAuditorEnabled(bool enabled)
331 {
332     WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitXSSAuditorEnabled"));
333     auto& injectedBundle = InjectedBundle::singleton();
334     WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
335 }
336
337 void TestRunner::setShadowDOMEnabled(bool enabled)
338 {
339     WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitShadowDOMEnabled"));
340     auto& injectedBundle = InjectedBundle::singleton();
341     WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
342 }
343
344 void TestRunner::setCustomElementsEnabled(bool enabled)
345 {
346     WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitCustomElementsEnabled"));
347     auto& injectedBundle = InjectedBundle::singleton();
348     WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
349 }
350
351 void TestRunner::setDOMIteratorEnabled(bool enabled)
352 {
353     WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitDOMIteratorEnabled"));
354     auto& injectedBundle = InjectedBundle::singleton();
355     WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
356 }
357
358 void TestRunner::setWebGL2Enabled(bool enabled)
359 {
360     WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitWebGL2Enabled"));
361     auto& injectedBundle = InjectedBundle::singleton();
362     WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
363 }
364
365 void TestRunner::setFetchAPIEnabled(bool enabled)
366 {
367     WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitFetchAPIEnabled"));
368     auto& injectedBundle = InjectedBundle::singleton();
369     WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
370 }
371
372 void TestRunner::setDownloadAttributeEnabled(bool enabled)
373 {
374     WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitDownloadAttributeEnabled"));
375     auto& injectedBundle = InjectedBundle::singleton();
376     WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
377 }
378
379 void TestRunner::setAllowsAnySSLCertificate(bool enabled)
380 {
381     InjectedBundle::singleton().setAllowsAnySSLCertificate(enabled);
382 }
383
384 void TestRunner::setAllowUniversalAccessFromFileURLs(bool enabled)
385 {
386     auto& injectedBundle = InjectedBundle::singleton();
387     WKBundleSetAllowUniversalAccessFromFileURLs(injectedBundle.bundle(), injectedBundle.pageGroup(), enabled);
388 }
389
390 void TestRunner::setAllowFileAccessFromFileURLs(bool enabled)
391 {
392     auto& injectedBundle = InjectedBundle::singleton();
393     WKBundleSetAllowFileAccessFromFileURLs(injectedBundle.bundle(), injectedBundle.pageGroup(), enabled);
394 }
395
396 void TestRunner::setPluginsEnabled(bool enabled)
397 {
398     auto& injectedBundle = InjectedBundle::singleton();
399     WKBundleSetPluginsEnabled(injectedBundle.bundle(), injectedBundle.pageGroup(), enabled);
400 }
401
402 void TestRunner::setJavaScriptCanAccessClipboard(bool enabled)
403 {
404     auto& injectedBundle = InjectedBundle::singleton();
405      WKBundleSetJavaScriptCanAccessClipboard(injectedBundle.bundle(), injectedBundle.pageGroup(), enabled);
406 }
407
408 void TestRunner::setPrivateBrowsingEnabled(bool enabled)
409 {
410     auto& injectedBundle = InjectedBundle::singleton();
411      WKBundleSetPrivateBrowsingEnabled(injectedBundle.bundle(), injectedBundle.pageGroup(), enabled);
412 }
413
414 void TestRunner::setPopupBlockingEnabled(bool enabled)
415 {
416     auto& injectedBundle = InjectedBundle::singleton();
417      WKBundleSetPopupBlockingEnabled(injectedBundle.bundle(), injectedBundle.pageGroup(), enabled);
418 }
419
420 void TestRunner::setAuthorAndUserStylesEnabled(bool enabled)
421 {
422     auto& injectedBundle = InjectedBundle::singleton();
423      WKBundleSetAuthorAndUserStylesEnabled(injectedBundle.bundle(), injectedBundle.pageGroup(), enabled);
424 }
425
426 void TestRunner::addOriginAccessWhitelistEntry(JSStringRef sourceOrigin, JSStringRef destinationProtocol, JSStringRef destinationHost, bool allowDestinationSubdomains)
427 {
428     WKBundleAddOriginAccessWhitelistEntry(InjectedBundle::singleton().bundle(), toWK(sourceOrigin).get(), toWK(destinationProtocol).get(), toWK(destinationHost).get(), allowDestinationSubdomains);
429 }
430
431 void TestRunner::removeOriginAccessWhitelistEntry(JSStringRef sourceOrigin, JSStringRef destinationProtocol, JSStringRef destinationHost, bool allowDestinationSubdomains)
432 {
433     WKBundleRemoveOriginAccessWhitelistEntry(InjectedBundle::singleton().bundle(), toWK(sourceOrigin).get(), toWK(destinationProtocol).get(), toWK(destinationHost).get(), allowDestinationSubdomains);
434 }
435
436 bool TestRunner::isPageBoxVisible(int pageIndex)
437 {
438     auto& injectedBundle = InjectedBundle::singleton();
439     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(injectedBundle.page()->page());
440     return WKBundleIsPageBoxVisible(injectedBundle.bundle(), mainFrame, pageIndex);
441 }
442
443 void TestRunner::setValueForUser(JSContextRef context, JSValueRef element, JSStringRef value)
444 {
445     if (!element || !JSValueIsObject(context, element))
446         return;
447
448     WKRetainPtr<WKBundleNodeHandleRef> nodeHandle(AdoptWK, WKBundleNodeHandleCreate(context, const_cast<JSObjectRef>(element)));
449     WKBundleNodeHandleSetHTMLInputElementValueForUser(nodeHandle.get(), toWK(value).get());
450 }
451
452 void TestRunner::setAudioResult(JSContextRef context, JSValueRef data)
453 {
454     auto& injectedBundle = InjectedBundle::singleton();
455     // FIXME (123058): Use a JSC API to get buffer contents once such is exposed.
456     WKRetainPtr<WKDataRef> audioData(AdoptWK, WKBundleCreateWKDataFromUInt8Array(injectedBundle.bundle(), context, data));
457     injectedBundle.setAudioResult(audioData.get());
458     m_whatToDump = Audio;
459     m_dumpPixels = false;
460 }
461
462 unsigned TestRunner::windowCount()
463 {
464     return InjectedBundle::singleton().pageCount();
465 }
466
467 void TestRunner::clearBackForwardList()
468 {
469     WKBundleBackForwardListClear(WKBundlePageGetBackForwardList(InjectedBundle::singleton().page()->page()));
470 }
471
472 // Object Creation
473
474 void TestRunner::makeWindowObject(JSContextRef context, JSObjectRef windowObject, JSValueRef* exception)
475 {
476     setProperty(context, windowObject, "testRunner", this, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete, exception);
477 }
478
479 void TestRunner::showWebInspector()
480 {
481     WKBundleInspectorShow(WKBundlePageGetInspector(InjectedBundle::singleton().page()->page()));
482 }
483
484 void TestRunner::closeWebInspector()
485 {
486     WKBundleInspectorClose(WKBundlePageGetInspector(InjectedBundle::singleton().page()->page()));
487 }
488
489 void TestRunner::evaluateInWebInspector(JSStringRef script)
490 {
491     WKRetainPtr<WKStringRef> scriptWK = toWK(script);
492     WKBundleInspectorEvaluateScriptForTest(WKBundlePageGetInspector(InjectedBundle::singleton().page()->page()), scriptWK.get());
493 }
494
495 typedef WTF::HashMap<unsigned, WKRetainPtr<WKBundleScriptWorldRef> > WorldMap;
496 static WorldMap& worldMap()
497 {
498     static WorldMap& map = *new WorldMap;
499     return map;
500 }
501
502 unsigned TestRunner::worldIDForWorld(WKBundleScriptWorldRef world)
503 {
504     WorldMap::const_iterator end = worldMap().end();
505     for (WorldMap::const_iterator it = worldMap().begin(); it != end; ++it) {
506         if (it->value == world)
507             return it->key;
508     }
509
510     return 0;
511 }
512
513 void TestRunner::evaluateScriptInIsolatedWorld(JSContextRef context, unsigned worldID, JSStringRef script)
514 {
515     // A worldID of 0 always corresponds to a new world. Any other worldID corresponds to a world
516     // that is created once and cached forever.
517     WKRetainPtr<WKBundleScriptWorldRef> world;
518     if (!worldID)
519         world.adopt(WKBundleScriptWorldCreateWorld());
520     else {
521         WKRetainPtr<WKBundleScriptWorldRef>& worldSlot = worldMap().add(worldID, nullptr).iterator->value;
522         if (!worldSlot)
523             worldSlot.adopt(WKBundleScriptWorldCreateWorld());
524         world = worldSlot;
525     }
526
527     WKBundleFrameRef frame = WKBundleFrameForJavaScriptContext(context);
528     if (!frame)
529         frame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
530
531     JSGlobalContextRef jsContext = WKBundleFrameGetJavaScriptContextForWorld(frame, world.get());
532     JSEvaluateScript(jsContext, script, 0, 0, 0, 0); 
533 }
534
535 void TestRunner::setPOSIXLocale(JSStringRef locale)
536 {
537     char localeBuf[32];
538     JSStringGetUTF8CString(locale, localeBuf, sizeof(localeBuf));
539     setlocale(LC_ALL, localeBuf);
540 }
541
542 void TestRunner::setTextDirection(JSStringRef direction)
543 {
544     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
545     return WKBundleFrameSetTextDirection(mainFrame, toWK(direction).get());
546 }
547     
548 void TestRunner::setShouldStayOnPageAfterHandlingBeforeUnload(bool shouldStayOnPage)
549 {
550     InjectedBundle::singleton().postNewBeforeUnloadReturnValue(!shouldStayOnPage);
551 }
552
553 void TestRunner::setDefersLoading(bool shouldDeferLoading)
554 {
555     WKBundlePageSetDefersLoading(InjectedBundle::singleton().page()->page(), shouldDeferLoading);
556 }
557
558 void TestRunner::setPageVisibility(JSStringRef state)
559 {
560     InjectedBundle::singleton().setHidden(JSStringIsEqualToUTF8CString(state, "hidden") || JSStringIsEqualToUTF8CString(state, "prerender"));
561 }
562
563 void TestRunner::resetPageVisibility()
564 {
565     InjectedBundle::singleton().setHidden(false);
566 }
567
568 typedef WTF::HashMap<unsigned, JSValueRef> CallbackMap;
569 static CallbackMap& callbackMap()
570 {
571     static CallbackMap& map = *new CallbackMap;
572     return map;
573 }
574
575 enum {
576     AddChromeInputFieldCallbackID = 1,
577     RemoveChromeInputFieldCallbackID,
578     FocusWebViewCallbackID,
579     SetBackingScaleFactorCallbackID,
580     DidBeginSwipeCallbackID,
581     WillEndSwipeCallbackID,
582     DidEndSwipeCallbackID,
583     DidRemoveSwipeSnapshotCallbackID,
584     FirstUIScriptCallbackID = 100
585 };
586
587 static void cacheTestRunnerCallback(unsigned index, JSValueRef callback)
588 {
589     if (!callback)
590         return;
591
592     if (callbackMap().contains(index)) {
593         InjectedBundle::singleton().outputText(String::format("FAIL: Tried to install a second TestRunner callback for the same event (id %d)\n\n", index));
594         return;
595     }
596
597     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
598     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
599     JSValueProtect(context, callback);
600     callbackMap().add(index, callback);
601 }
602
603 static void callTestRunnerCallback(unsigned index, size_t argumentCount = 0, const JSValueRef arguments[] = nullptr)
604 {
605     if (!callbackMap().contains(index))
606         return;
607     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
608     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
609     JSObjectRef callback = JSValueToObject(context, callbackMap().take(index), 0);
610     JSObjectCallAsFunction(context, callback, JSContextGetGlobalObject(context), argumentCount, arguments, 0);
611     JSValueUnprotect(context, callback);
612 }
613
614 void TestRunner::clearTestRunnerCallbacks()
615 {
616     for (auto& iter : callbackMap()) {
617         WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
618         JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
619         JSObjectRef callback = JSValueToObject(context, iter.value, 0);
620         JSValueUnprotect(context, callback);
621     }
622
623     callbackMap().clear();
624 }
625
626 void TestRunner::accummulateLogsForChannel(JSStringRef)
627 {
628     // FIXME: Implement getting the call to all processes.
629 }
630
631 void TestRunner::addChromeInputField(JSValueRef callback)
632 {
633     cacheTestRunnerCallback(AddChromeInputFieldCallbackID, callback);
634     InjectedBundle::singleton().postAddChromeInputField();
635 }
636
637 void TestRunner::removeChromeInputField(JSValueRef callback)
638 {
639     cacheTestRunnerCallback(RemoveChromeInputFieldCallbackID, callback);
640     InjectedBundle::singleton().postRemoveChromeInputField();
641 }
642
643 void TestRunner::focusWebView(JSValueRef callback)
644 {
645     cacheTestRunnerCallback(FocusWebViewCallbackID, callback);
646     InjectedBundle::singleton().postFocusWebView();
647 }
648
649 void TestRunner::setBackingScaleFactor(double backingScaleFactor, JSValueRef callback)
650 {
651     cacheTestRunnerCallback(SetBackingScaleFactorCallbackID, callback);
652     InjectedBundle::singleton().postSetBackingScaleFactor(backingScaleFactor);
653 }
654
655 void TestRunner::setWindowIsKey(bool isKey)
656 {
657     InjectedBundle::singleton().postSetWindowIsKey(isKey);
658 }
659
660 void TestRunner::setViewSize(double width, double height)
661 {
662     InjectedBundle::singleton().postSetViewSize(width, height);
663 }
664
665 void TestRunner::callAddChromeInputFieldCallback()
666 {
667     callTestRunnerCallback(AddChromeInputFieldCallbackID);
668 }
669
670 void TestRunner::callRemoveChromeInputFieldCallback()
671 {
672     callTestRunnerCallback(RemoveChromeInputFieldCallbackID);
673 }
674
675 void TestRunner::callFocusWebViewCallback()
676 {
677     callTestRunnerCallback(FocusWebViewCallbackID);
678 }
679
680 void TestRunner::callSetBackingScaleFactorCallback()
681 {
682     callTestRunnerCallback(SetBackingScaleFactorCallbackID);
683 }
684
685 static inline bool toBool(JSStringRef value)
686 {
687     return JSStringIsEqualToUTF8CString(value, "true") || JSStringIsEqualToUTF8CString(value, "1");
688 }
689
690 void TestRunner::overridePreference(JSStringRef preference, JSStringRef value)
691 {
692     auto& injectedBundle = InjectedBundle::singleton();
693     // FIXME: handle non-boolean preferences.
694     WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), toWK(preference).get(), toBool(value));
695 }
696
697 void TestRunner::setAlwaysAcceptCookies(bool accept)
698 {
699     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetAlwaysAcceptCookies"));
700
701     WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(accept));
702
703     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
704 }
705
706 double TestRunner::preciseTime()
707 {
708     return currentTime();
709 }
710
711 void TestRunner::setUserStyleSheetEnabled(bool enabled)
712 {
713     m_userStyleSheetEnabled = enabled;
714
715     WKRetainPtr<WKStringRef> emptyUrl = adoptWK(WKStringCreateWithUTF8CString(""));
716     WKStringRef location = enabled ? m_userStyleSheetLocation.get() : emptyUrl.get();
717     auto& injectedBundle = InjectedBundle::singleton();
718     WKBundleSetUserStyleSheetLocation(injectedBundle.bundle(), injectedBundle.pageGroup(), location);
719 }
720
721 void TestRunner::setUserStyleSheetLocation(JSStringRef location)
722 {
723     m_userStyleSheetLocation = adoptWK(WKStringCreateWithJSString(location));
724
725     if (m_userStyleSheetEnabled)
726         setUserStyleSheetEnabled(true);
727 }
728
729 void TestRunner::setSpatialNavigationEnabled(bool enabled)
730 {
731     auto& injectedBundle = InjectedBundle::singleton();
732     WKBundleSetSpatialNavigationEnabled(injectedBundle.bundle(), injectedBundle.pageGroup(), enabled);
733 }
734
735 void TestRunner::setTabKeyCyclesThroughElements(bool enabled)
736 {
737     auto& injectedBundle = InjectedBundle::singleton();
738     WKBundleSetTabKeyCyclesThroughElements(injectedBundle.bundle(), injectedBundle.page()->page(), enabled);
739 }
740
741 void TestRunner::setSerializeHTTPLoads()
742 {
743     // WK2 doesn't reorder loads.
744 }
745
746 void TestRunner::dispatchPendingLoadRequests()
747 {
748     // WK2 doesn't keep pending requests.
749 }
750
751 void TestRunner::setCacheModel(int model)
752 {
753     InjectedBundle::singleton().setCacheModel(model);
754 }
755
756 void TestRunner::setAsynchronousSpellCheckingEnabled(bool enabled)
757 {
758     auto& injectedBundle = InjectedBundle::singleton();
759     WKBundleSetAsynchronousSpellCheckingEnabled(injectedBundle.bundle(), injectedBundle.pageGroup(), enabled);
760 }
761
762 void TestRunner::grantWebNotificationPermission(JSStringRef origin)
763 {
764     WKRetainPtr<WKStringRef> originWK = toWK(origin);
765     auto& injectedBundle = InjectedBundle::singleton();
766     WKBundleSetWebNotificationPermission(injectedBundle.bundle(), injectedBundle.page()->page(), originWK.get(), true);
767 }
768
769 void TestRunner::denyWebNotificationPermission(JSStringRef origin)
770 {
771     WKRetainPtr<WKStringRef> originWK = toWK(origin);
772     auto& injectedBundle = InjectedBundle::singleton();
773     WKBundleSetWebNotificationPermission(injectedBundle.bundle(), injectedBundle.page()->page(), originWK.get(), false);
774 }
775
776 void TestRunner::removeAllWebNotificationPermissions()
777 {
778     auto& injectedBundle = InjectedBundle::singleton();
779     WKBundleRemoveAllWebNotificationPermissions(injectedBundle.bundle(), injectedBundle.page()->page());
780 }
781
782 void TestRunner::simulateWebNotificationClick(JSValueRef notification)
783 {
784     auto& injectedBundle = InjectedBundle::singleton();
785     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(injectedBundle.page()->page());
786     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
787     uint64_t notificationID = WKBundleGetWebNotificationID(injectedBundle.bundle(), context, notification);
788     injectedBundle.postSimulateWebNotificationClick(notificationID);
789 }
790
791 void TestRunner::setGeolocationPermission(bool enabled)
792 {
793     // FIXME: this should be done by frame.
794     InjectedBundle::singleton().setGeolocationPermission(enabled);
795 }
796
797 bool TestRunner::isGeolocationProviderActive()
798 {
799     return InjectedBundle::singleton().isGeolocationProviderActive();
800 }
801
802 void TestRunner::setMockGeolocationPosition(double latitude, double longitude, double accuracy, JSValueRef jsAltitude, JSValueRef jsAltitudeAccuracy, JSValueRef jsHeading, JSValueRef jsSpeed)
803 {
804     auto& injectedBundle = InjectedBundle::singleton();
805     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(injectedBundle.page()->page());
806     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
807
808     bool providesAltitude = false;
809     double altitude = 0.;
810     if (!JSValueIsUndefined(context, jsAltitude)) {
811         providesAltitude = true;
812         altitude = JSValueToNumber(context, jsAltitude, 0);
813     }
814
815     bool providesAltitudeAccuracy = false;
816     double altitudeAccuracy = 0.;
817     if (!JSValueIsUndefined(context, jsAltitudeAccuracy)) {
818         providesAltitudeAccuracy = true;
819         altitudeAccuracy = JSValueToNumber(context, jsAltitudeAccuracy, 0);
820     }
821
822     bool providesHeading = false;
823     double heading = 0.;
824     if (!JSValueIsUndefined(context, jsHeading)) {
825         providesHeading = true;
826         heading = JSValueToNumber(context, jsHeading, 0);
827     }
828
829     bool providesSpeed = false;
830     double speed = 0.;
831     if (!JSValueIsUndefined(context, jsSpeed)) {
832         providesSpeed = true;
833         speed = JSValueToNumber(context, jsSpeed, 0);
834     }
835
836     injectedBundle.setMockGeolocationPosition(latitude, longitude, accuracy, providesAltitude, altitude, providesAltitudeAccuracy, altitudeAccuracy, providesHeading, heading, providesSpeed, speed);
837 }
838
839 void TestRunner::setMockGeolocationPositionUnavailableError(JSStringRef message)
840 {
841     WKRetainPtr<WKStringRef> messageWK = toWK(message);
842     InjectedBundle::singleton().setMockGeolocationPositionUnavailableError(messageWK.get());
843 }
844
845 void TestRunner::setUserMediaPermission(bool enabled)
846 {
847     // FIXME: this should be done by frame.
848     InjectedBundle::singleton().setUserMediaPermission(enabled);
849 }
850
851 void TestRunner::setUserMediaPermissionForOrigin(bool permission, JSStringRef origin, JSStringRef parentOrigin)
852 {
853     WKRetainPtr<WKStringRef> originWK = toWK(origin);
854     WKRetainPtr<WKStringRef> parentOriginWK = toWK(parentOrigin);
855     InjectedBundle::singleton().setUserMediaPermissionForOrigin(permission, originWK.get(), parentOriginWK.get());
856 }
857
858 bool TestRunner::callShouldCloseOnWebView()
859 {
860     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
861     return WKBundleFrameCallShouldCloseOnWebView(mainFrame);
862 }
863
864 void TestRunner::queueBackNavigation(unsigned howFarBackward)
865 {
866     InjectedBundle::singleton().queueBackNavigation(howFarBackward);
867 }
868
869 void TestRunner::queueForwardNavigation(unsigned howFarForward)
870 {
871     InjectedBundle::singleton().queueForwardNavigation(howFarForward);
872 }
873
874 void TestRunner::queueLoad(JSStringRef url, JSStringRef target, bool shouldOpenExternalURLs)
875 {
876     auto& injectedBundle = InjectedBundle::singleton();
877     WKRetainPtr<WKURLRef> baseURLWK(AdoptWK, WKBundleFrameCopyURL(WKBundlePageGetMainFrame(injectedBundle.page()->page())));
878     WKRetainPtr<WKURLRef> urlWK(AdoptWK, WKURLCreateWithBaseURL(baseURLWK.get(), toWTFString(toWK(url)).utf8().data()));
879     WKRetainPtr<WKStringRef> urlStringWK(AdoptWK, WKURLCopyString(urlWK.get()));
880
881     injectedBundle.queueLoad(urlStringWK.get(), toWK(target).get(), shouldOpenExternalURLs);
882 }
883
884 void TestRunner::queueLoadHTMLString(JSStringRef content, JSStringRef baseURL, JSStringRef unreachableURL)
885 {
886     WKRetainPtr<WKStringRef> contentWK = toWK(content);
887     WKRetainPtr<WKStringRef> baseURLWK = baseURL ? toWK(baseURL) : WKRetainPtr<WKStringRef>();
888     WKRetainPtr<WKStringRef> unreachableURLWK = unreachableURL ? toWK(unreachableURL) : WKRetainPtr<WKStringRef>();
889
890     InjectedBundle::singleton().queueLoadHTMLString(contentWK.get(), baseURLWK.get(), unreachableURLWK.get());
891 }
892
893 void TestRunner::queueReload()
894 {
895     InjectedBundle::singleton().queueReload();
896 }
897
898 void TestRunner::queueLoadingScript(JSStringRef script)
899 {
900     WKRetainPtr<WKStringRef> scriptWK = toWK(script);
901     InjectedBundle::singleton().queueLoadingScript(scriptWK.get());
902 }
903
904 void TestRunner::queueNonLoadingScript(JSStringRef script)
905 {
906     WKRetainPtr<WKStringRef> scriptWK = toWK(script);
907     InjectedBundle::singleton().queueNonLoadingScript(scriptWK.get());
908 }
909
910 void TestRunner::setRejectsProtectionSpaceAndContinueForAuthenticationChallenges(bool value)
911 {
912     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetRejectsProtectionSpaceAndContinueForAuthenticationChallenges"));
913     WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(value));
914     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
915 }
916     
917 void TestRunner::setHandlesAuthenticationChallenges(bool handlesAuthenticationChallenges)
918 {
919     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetHandlesAuthenticationChallenges"));
920     WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(handlesAuthenticationChallenges));
921     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
922 }
923
924 void TestRunner::setShouldLogCanAuthenticateAgainstProtectionSpace(bool value)
925 {
926     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetShouldLogCanAuthenticateAgainstProtectionSpace"));
927     WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(value));
928     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
929 }
930
931 void TestRunner::setAuthenticationUsername(JSStringRef username)
932 {
933     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetAuthenticationUsername"));
934     WKRetainPtr<WKStringRef> messageBody(AdoptWK, WKStringCreateWithJSString(username));
935     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
936 }
937
938 void TestRunner::setAuthenticationPassword(JSStringRef password)
939 {
940     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetAuthenticationPassword"));
941     WKRetainPtr<WKStringRef> messageBody(AdoptWK, WKStringCreateWithJSString(password));
942     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
943 }
944
945 bool TestRunner::secureEventInputIsEnabled() const
946 {
947     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SecureEventInputIsEnabled"));
948     WKTypeRef returnData = 0;
949
950     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), 0, &returnData);
951     return WKBooleanGetValue(static_cast<WKBooleanRef>(returnData));
952 }
953
954 void TestRunner::setBlockAllPlugins(bool shouldBlock)
955 {
956     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetBlockAllPlugins"));
957     WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(shouldBlock));
958     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
959 }
960
961 JSValueRef TestRunner::failNextNewCodeBlock()
962 {
963     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
964     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
965     return JSC::failNextNewCodeBlock(context);
966 }
967
968 JSValueRef TestRunner::numberOfDFGCompiles(JSValueRef theFunction)
969 {
970     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
971     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
972     return JSC::numberOfDFGCompiles(context, theFunction);
973 }
974
975 JSValueRef TestRunner::neverInlineFunction(JSValueRef theFunction)
976 {
977     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
978     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
979     return JSC::setNeverInline(context, theFunction);
980 }
981
982 void TestRunner::setShouldDecideNavigationPolicyAfterDelay(bool value)
983 {
984     m_shouldDecideNavigationPolicyAfterDelay = value;
985     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetShouldDecideNavigationPolicyAfterDelay"));
986     WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(value));
987     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
988 }
989
990 void TestRunner::setNavigationGesturesEnabled(bool value)
991 {
992     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetNavigationGesturesEnabled"));
993     WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(value));
994     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
995 }
996
997 void TestRunner::setIgnoresViewportScaleLimits(bool value)
998 {
999     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetIgnoresViewportScaleLimits"));
1000     WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(value));
1001     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
1002 }
1003
1004 static unsigned nextUIScriptCallbackID()
1005 {
1006     static unsigned callbackID = FirstUIScriptCallbackID;
1007     return callbackID++;
1008 }
1009
1010 void TestRunner::runUIScript(JSStringRef script, JSValueRef callback)
1011 {
1012     unsigned callbackID = nextUIScriptCallbackID();
1013     cacheTestRunnerCallback(callbackID, callback);
1014
1015     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("RunUIProcessScript"));
1016
1017     WKRetainPtr<WKMutableDictionaryRef> testDictionary(AdoptWK, WKMutableDictionaryCreate());
1018
1019     WKRetainPtr<WKStringRef> scriptKey(AdoptWK, WKStringCreateWithUTF8CString("Script"));
1020     WKRetainPtr<WKStringRef> scriptValue(AdoptWK, WKStringCreateWithJSString(script));
1021
1022     WKRetainPtr<WKStringRef> callbackIDKey(AdoptWK, WKStringCreateWithUTF8CString("CallbackID"));
1023     WKRetainPtr<WKUInt64Ref> callbackIDValue = adoptWK(WKUInt64Create(callbackID));
1024
1025     WKDictionarySetItem(testDictionary.get(), scriptKey.get(), scriptValue.get());
1026     WKDictionarySetItem(testDictionary.get(), callbackIDKey.get(), callbackIDValue.get());
1027
1028     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), testDictionary.get());
1029 }
1030
1031 void TestRunner::runUIScriptCallback(unsigned callbackID, JSStringRef result)
1032 {
1033     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
1034     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
1035
1036     JSValueRef resultValue = JSValueMakeString(context, result);
1037     callTestRunnerCallback(callbackID, 1, &resultValue);
1038 }
1039
1040 void TestRunner::installDidBeginSwipeCallback(JSValueRef callback)
1041 {
1042     cacheTestRunnerCallback(DidBeginSwipeCallbackID, callback);
1043 }
1044
1045 void TestRunner::installWillEndSwipeCallback(JSValueRef callback)
1046 {
1047     cacheTestRunnerCallback(WillEndSwipeCallbackID, callback);
1048 }
1049
1050 void TestRunner::installDidEndSwipeCallback(JSValueRef callback)
1051 {
1052     cacheTestRunnerCallback(DidEndSwipeCallbackID, callback);
1053 }
1054
1055 void TestRunner::installDidRemoveSwipeSnapshotCallback(JSValueRef callback)
1056 {
1057     cacheTestRunnerCallback(DidRemoveSwipeSnapshotCallbackID, callback);
1058 }
1059
1060 void TestRunner::callDidBeginSwipeCallback()
1061 {
1062     callTestRunnerCallback(DidBeginSwipeCallbackID);
1063 }
1064
1065 void TestRunner::callWillEndSwipeCallback()
1066 {
1067     callTestRunnerCallback(WillEndSwipeCallbackID);
1068 }
1069
1070 void TestRunner::callDidEndSwipeCallback()
1071 {
1072     callTestRunnerCallback(DidEndSwipeCallbackID);
1073 }
1074
1075 void TestRunner::callDidRemoveSwipeSnapshotCallback()
1076 {
1077     callTestRunnerCallback(DidRemoveSwipeSnapshotCallbackID);
1078 }
1079
1080 #if PLATFORM(MAC)
1081 void TestRunner::connectMockGamepad(unsigned index)
1082 {
1083     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("ConnectMockGamepad"));
1084     WKRetainPtr<WKTypeRef> messageBody(AdoptWK, WKUInt64Create(index));
1085
1086     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1087 }
1088
1089 void TestRunner::disconnectMockGamepad(unsigned index)
1090 {
1091     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("DisconnectMockGamepad"));
1092     WKRetainPtr<WKTypeRef> messageBody(AdoptWK, WKUInt64Create(index));
1093
1094     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1095 }
1096
1097 void TestRunner::setMockGamepadDetails(unsigned index, JSStringRef gamepadID, unsigned axisCount, unsigned buttonCount)
1098 {
1099     Vector<WKRetainPtr<WKStringRef>> keys;
1100     Vector<WKRetainPtr<WKTypeRef>> values;
1101
1102     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("GamepadID") });
1103     values.append(toWK(gamepadID));
1104
1105     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("GamepadIndex") });
1106     values.append({ AdoptWK, WKUInt64Create(index) });
1107
1108     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("AxisCount") });
1109     values.append({ AdoptWK, WKUInt64Create(axisCount) });
1110
1111     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("ButtonCount") });
1112     values.append({ AdoptWK, WKUInt64Create(buttonCount) });
1113
1114     Vector<WKStringRef> rawKeys;
1115     Vector<WKTypeRef> rawValues;
1116     rawKeys.resize(keys.size());
1117     rawValues.resize(values.size());
1118
1119     for (size_t i = 0; i < keys.size(); ++i) {
1120         rawKeys[i] = keys[i].get();
1121         rawValues[i] = values[i].get();
1122     }
1123
1124     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetMockGamepadDetails"));
1125     WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1126
1127     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1128 }
1129
1130 void TestRunner::setMockGamepadAxisValue(unsigned index, unsigned axisIndex, double value)
1131 {
1132     Vector<WKRetainPtr<WKStringRef>> keys;
1133     Vector<WKRetainPtr<WKTypeRef>> values;
1134
1135     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("GamepadIndex") });
1136     values.append({ AdoptWK, WKUInt64Create(index) });
1137
1138     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("AxisIndex") });
1139     values.append({ AdoptWK, WKUInt64Create(axisIndex) });
1140
1141     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("Value") });
1142     values.append({ AdoptWK, WKDoubleCreate(value) });
1143
1144     Vector<WKStringRef> rawKeys;
1145     Vector<WKTypeRef> rawValues;
1146     rawKeys.resize(keys.size());
1147     rawValues.resize(values.size());
1148
1149     for (size_t i = 0; i < keys.size(); ++i) {
1150         rawKeys[i] = keys[i].get();
1151         rawValues[i] = values[i].get();
1152     }
1153
1154     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetMockGamepadAxisValue"));
1155     WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1156
1157     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1158 }
1159
1160 void TestRunner::setMockGamepadButtonValue(unsigned index, unsigned buttonIndex, double value)
1161 {
1162     Vector<WKRetainPtr<WKStringRef>> keys;
1163     Vector<WKRetainPtr<WKTypeRef>> values;
1164
1165     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("GamepadIndex") });
1166     values.append({ AdoptWK, WKUInt64Create(index) });
1167
1168     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("ButtonIndex") });
1169     values.append({ AdoptWK, WKUInt64Create(buttonIndex) });
1170
1171     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("Value") });
1172     values.append({ AdoptWK, WKDoubleCreate(value) });
1173
1174     Vector<WKStringRef> rawKeys;
1175     Vector<WKTypeRef> rawValues;
1176     rawKeys.resize(keys.size());
1177     rawValues.resize(values.size());
1178
1179     for (size_t i = 0; i < keys.size(); ++i) {
1180         rawKeys[i] = keys[i].get();
1181         rawValues[i] = values[i].get();
1182     }
1183
1184     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetMockGamepadButtonValue"));
1185     WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1186
1187     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1188 }
1189 #else
1190 void TestRunner::connectMockGamepad(unsigned)
1191 {
1192 }
1193
1194 void TestRunner::disconnectMockGamepad(unsigned)
1195 {
1196 }
1197
1198 void TestRunner::setMockGamepadDetails(unsigned, JSStringRef, unsigned, unsigned)
1199 {
1200 }
1201
1202 void TestRunner::setMockGamepadAxisValue(unsigned, unsigned, double)
1203 {
1204 }
1205
1206 void TestRunner::setMockGamepadButtonValue(unsigned, unsigned, double)
1207 {
1208 }
1209 #endif // PLATFORM(MAC)
1210
1211 } // namespace WTR