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