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