Streamline JSRetainPtr, fix leaks of JSString and JSGlobalContext
[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/HashMap.h>
53 #include <wtf/StdLibExtras.h>
54 #include <wtf/text/CString.h>
55 #include <wtf/text/StringBuilder.h>
56
57 namespace WTR {
58
59 Ref<TestRunner> TestRunner::create()
60 {
61     return adoptRef(*new TestRunner);
62 }
63
64 TestRunner::TestRunner()
65     : m_shouldDumpAllFrameScrollPositions(false)
66     , m_shouldDumpBackForwardListsForAllWindows(false)
67     , m_shouldAllowEditing(true)
68     , m_shouldCloseExtraWindows(false)
69     , m_dumpEditingCallbacks(false)
70     , m_dumpStatusCallbacks(false)
71     , m_dumpTitleChanges(false)
72     , m_dumpSelectionRect(false)
73     , m_dumpFullScreenCallbacks(false)
74     , m_dumpProgressFinishedCallback(false)
75     , m_dumpResourceLoadCallbacks(false)
76     , m_dumpResourceResponseMIMETypes(false)
77     , m_dumpWillCacheResponse(false)
78     , m_dumpApplicationCacheDelegateCallbacks(false)
79     , m_dumpDatabaseCallbacks(false)
80     , m_disallowIncreaseForApplicationCacheQuota(false)
81     , m_testRepaint(false)
82     , m_testRepaintSweepHorizontally(false)
83     , m_isPrinting(false)
84     , m_willSendRequestReturnsNull(false)
85     , m_willSendRequestReturnsNullOnRedirect(false)
86     , m_shouldStopProvisionalFrameLoads(false)
87     , m_policyDelegateEnabled(false)
88     , m_policyDelegatePermissive(false)
89     , m_globalFlag(false)
90     , m_customFullScreenBehavior(false)
91     , m_timeout(30000)
92     , m_databaseDefaultQuota(-1)
93     , m_databaseMaxQuota(-1)
94     , m_userStyleSheetEnabled(false)
95     , m_userStyleSheetLocation(adoptWK(WKStringCreateWithUTF8CString("")))
96 #if PLATFORM(GTK) || PLATFORM(WPE)
97     , m_waitToDumpWatchdogTimer(RunLoop::main(), this, &TestRunner::waitToDumpWatchdogTimerFired)
98 #endif
99 {
100     platformInitialize();
101 }
102
103 TestRunner::~TestRunner()
104 {
105 }
106
107 JSClassRef TestRunner::wrapperClass()
108 {
109     return JSTestRunner::testRunnerClass();
110 }
111
112 void TestRunner::display()
113 {
114     WKBundlePageRef page = InjectedBundle::singleton().page()->page();
115     WKBundlePageForceRepaint(page);
116 }
117
118 void TestRunner::displayAndTrackRepaints()
119 {
120     WKBundlePageRef page = InjectedBundle::singleton().page()->page();
121     WKBundlePageForceRepaint(page);
122     WKBundlePageSetTracksRepaints(page, true);
123     WKBundlePageResetTrackedRepaints(page);
124 }
125
126 bool TestRunner::shouldDumpPixels() const
127 {
128     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("GetDumpPixels"));
129     WKTypeRef result = 0;
130     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), 0, &result);
131     ASSERT(WKGetTypeID(result) == WKBooleanGetTypeID());
132     return WKBooleanGetValue(static_cast<WKBooleanRef>(result));
133 }
134
135 void TestRunner::setDumpPixels(bool dumpPixels)
136 {
137     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetDumpPixels"));
138     WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(dumpPixels));
139     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
140 }
141
142 void TestRunner::dumpAsText(bool dumpPixels)
143 {
144     if (whatToDump() < WhatToDump::MainFrameText)
145         setWhatToDump(WhatToDump::MainFrameText);
146     setDumpPixels(dumpPixels);
147 }
148     
149 WhatToDump TestRunner::whatToDump() const
150 {
151     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("GetWhatToDump"));
152     WKTypeRef result = 0;
153     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), 0, &result);
154     ASSERT(WKGetTypeID(result) == WKUInt64GetTypeID());
155     auto uint64value = WKUInt64GetValue(static_cast<WKUInt64Ref>(result));
156     return static_cast<WhatToDump>(uint64value);
157 }
158
159 void TestRunner::setWhatToDump(WhatToDump whatToDump)
160 {
161     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetWhatToDump"));
162     WKRetainPtr<WKUInt64Ref> messageBody(AdoptWK, WKUInt64Create(static_cast<uint64_t>(whatToDump)));
163     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
164 }
165
166 void TestRunner::setCustomPolicyDelegate(bool enabled, bool permissive)
167 {
168     m_policyDelegateEnabled = enabled;
169     m_policyDelegatePermissive = permissive;
170
171     InjectedBundle::singleton().setCustomPolicyDelegate(enabled, permissive);
172 }
173
174 void TestRunner::waitForPolicyDelegate()
175 {
176     setCustomPolicyDelegate(true);
177     waitUntilDone();
178 }
179
180 void TestRunner::waitUntilDownloadFinished()
181 {
182     m_shouldFinishAfterDownload = true;
183     waitUntilDone();
184 }
185
186 void TestRunner::waitUntilDone()
187 {
188     auto& injectedBundle = InjectedBundle::singleton();
189     RELEASE_ASSERT(injectedBundle.isTestRunning());
190
191     setWaitUntilDone(true);
192     // FIXME: Watchdog timer should be moved to UI process in order to take the elapsed time in anotehr process into account.
193     if (injectedBundle.useWaitToDumpWatchdogTimer())
194         initializeWaitToDumpWatchdogTimerIfNeeded();
195 }
196
197 void TestRunner::setWaitUntilDone(bool value)
198 {
199     WKRetainPtr<WKStringRef> messsageName(AdoptWK, WKStringCreateWithUTF8CString("SetWaitUntilDone"));
200     WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(value));
201     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messsageName.get(), messageBody.get(), nullptr);
202 }
203
204 bool TestRunner::shouldWaitUntilDone() const
205 {
206     WKRetainPtr<WKStringRef> messsageName(AdoptWK, WKStringCreateWithUTF8CString("GetWaitUntilDone"));
207     WKTypeRef result = 0;
208     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messsageName.get(), 0, &result);
209     ASSERT(WKGetTypeID(result) == WKBooleanGetTypeID());
210     return WKBooleanGetValue(static_cast<WKBooleanRef>(result));
211 }
212
213 void TestRunner::waitToDumpWatchdogTimerFired()
214 {
215     invalidateWaitToDumpWatchdogTimer();
216     auto& injectedBundle = InjectedBundle::singleton();
217 #if PLATFORM(COCOA)
218     char buffer[1024];
219     snprintf(buffer, sizeof(buffer), "#PID UNRESPONSIVE - %s (pid %d)\n", getprogname(), getpid());
220     injectedBundle.outputText(buffer);
221 #endif
222     injectedBundle.outputText("FAIL: Timed out waiting for notifyDone to be called\n\n");
223     injectedBundle.done();
224 }
225
226 void TestRunner::notifyDone()
227 {
228     auto& injectedBundle = InjectedBundle::singleton();
229     if (!injectedBundle.isTestRunning())
230         return;
231
232     if (shouldWaitUntilDone() && !injectedBundle.topLoadingFrame())
233         injectedBundle.page()->dump();
234
235     // We don't call invalidateWaitToDumpWatchdogTimer() here, even if we continue to wait for a load to finish.
236     // The test is still subject to timeout checking - it is better to detect an async timeout inside WebKitTestRunner
237     // than to let webkitpy do that, because WebKitTestRunner will dump partial results.
238
239     setWaitUntilDone(false);
240 }
241
242 void TestRunner::forceImmediateCompletion()
243 {
244     auto& injectedBundle = InjectedBundle::singleton();
245     if (!injectedBundle.isTestRunning())
246         return;
247
248     if (shouldWaitUntilDone() && injectedBundle.page())
249         injectedBundle.page()->dump();
250
251     setWaitUntilDone(false);
252 }
253
254 void TestRunner::setShouldDumpFrameLoadCallbacks(bool value)
255 {
256     WKRetainPtr<WKStringRef> messsageName(AdoptWK, WKStringCreateWithUTF8CString("SetDumpFrameLoadCallbacks"));
257     WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(value));
258     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messsageName.get(), messageBody.get(), nullptr);
259 }
260
261 bool TestRunner::shouldDumpFrameLoadCallbacks()
262 {
263     WKRetainPtr<WKStringRef> messsageName(AdoptWK, WKStringCreateWithUTF8CString("GetDumpFrameLoadCallbacks"));
264     WKTypeRef result = 0;
265     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messsageName.get(), 0, &result);
266     ASSERT(WKGetTypeID(result) == WKBooleanGetTypeID());
267     return WKBooleanGetValue(static_cast<WKBooleanRef>(result));
268 }
269
270 unsigned TestRunner::imageCountInGeneralPasteboard() const
271 {
272     return InjectedBundle::singleton().imageCountInGeneralPasteboard();
273 }
274
275 void TestRunner::addUserScript(JSStringRef source, bool runAtStart, bool allFrames)
276 {
277     WKRetainPtr<WKStringRef> sourceWK = toWK(source);
278
279     WKBundlePageAddUserScript(InjectedBundle::singleton().page()->page(), sourceWK.get(),
280         (runAtStart ? kWKInjectAtDocumentStart : kWKInjectAtDocumentEnd),
281         (allFrames ? kWKInjectInAllFrames : kWKInjectInTopFrameOnly));
282 }
283
284 void TestRunner::addUserStyleSheet(JSStringRef source, bool allFrames)
285 {
286     WKRetainPtr<WKStringRef> sourceWK = toWK(source);
287
288     WKBundlePageAddUserStyleSheet(InjectedBundle::singleton().page()->page(), sourceWK.get(),
289         (allFrames ? kWKInjectInAllFrames : kWKInjectInTopFrameOnly));
290 }
291
292 void TestRunner::keepWebHistory()
293 {
294     InjectedBundle::singleton().postSetAddsVisitedLinks(true);
295 }
296
297 void TestRunner::execCommand(JSStringRef name, JSStringRef showUI, JSStringRef value)
298 {
299     WKBundlePageExecuteEditingCommand(InjectedBundle::singleton().page()->page(), toWK(name).get(), toWK(value).get());
300 }
301
302 bool TestRunner::findString(JSStringRef target, JSValueRef optionsArrayAsValue)
303 {
304     WKFindOptions options = 0;
305
306     auto& injectedBundle = InjectedBundle::singleton();
307     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(injectedBundle.page()->page());
308     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
309     auto lengthPropertyName = adopt(JSStringCreateWithUTF8CString("length"));
310     JSObjectRef optionsArray = JSValueToObject(context, optionsArrayAsValue, 0);
311     JSValueRef lengthValue = JSObjectGetProperty(context, optionsArray, lengthPropertyName.get(), 0);
312     if (!JSValueIsNumber(context, lengthValue))
313         return false;
314
315     size_t length = static_cast<size_t>(JSValueToNumber(context, lengthValue, 0));
316     for (size_t i = 0; i < length; ++i) {
317         JSValueRef value = JSObjectGetPropertyAtIndex(context, optionsArray, i, 0);
318         if (!JSValueIsString(context, value))
319             continue;
320
321         auto optionName = adopt(JSValueToStringCopy(context, value, 0));
322
323         if (JSStringIsEqualToUTF8CString(optionName.get(), "CaseInsensitive"))
324             options |= kWKFindOptionsCaseInsensitive;
325         else if (JSStringIsEqualToUTF8CString(optionName.get(), "AtWordStarts"))
326             options |= kWKFindOptionsAtWordStarts;
327         else if (JSStringIsEqualToUTF8CString(optionName.get(), "TreatMedialCapitalAsWordStart"))
328             options |= kWKFindOptionsTreatMedialCapitalAsWordStart;
329         else if (JSStringIsEqualToUTF8CString(optionName.get(), "Backwards"))
330             options |= kWKFindOptionsBackwards;
331         else if (JSStringIsEqualToUTF8CString(optionName.get(), "WrapAround"))
332             options |= kWKFindOptionsWrapAround;
333         else if (JSStringIsEqualToUTF8CString(optionName.get(), "StartInSelection")) {
334             // FIXME: No kWKFindOptionsStartInSelection.
335         }
336     }
337
338     return WKBundlePageFindString(injectedBundle.page()->page(), toWK(target).get(), options);
339 }
340
341 void TestRunner::clearAllDatabases()
342 {
343     WKBundleClearAllDatabases(InjectedBundle::singleton().bundle());
344
345     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("DeleteAllIndexedDatabases"));
346     WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(true));
347
348     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
349 }
350
351 void TestRunner::setDatabaseQuota(uint64_t quota)
352 {
353     return WKBundleSetDatabaseQuota(InjectedBundle::singleton().bundle(), quota);
354 }
355
356 void TestRunner::clearAllApplicationCaches()
357 {
358     WKBundlePageClearApplicationCache(InjectedBundle::singleton().page()->page());
359 }
360
361 void TestRunner::clearApplicationCacheForOrigin(JSStringRef origin)
362 {
363     WKBundlePageClearApplicationCacheForOrigin(InjectedBundle::singleton().page()->page(), toWK(origin).get());
364 }
365
366 void TestRunner::setAppCacheMaximumSize(uint64_t size)
367 {
368     WKBundlePageSetAppCacheMaximumSize(InjectedBundle::singleton().page()->page(), size);
369 }
370
371 long long TestRunner::applicationCacheDiskUsageForOrigin(JSStringRef origin)
372 {
373     return WKBundlePageGetAppCacheUsageForOrigin(InjectedBundle::singleton().page()->page(), toWK(origin).get());
374 }
375
376 void TestRunner::disallowIncreaseForApplicationCacheQuota()
377 {
378     m_disallowIncreaseForApplicationCacheQuota = true;
379 }
380
381 static inline JSValueRef stringArrayToJS(JSContextRef context, WKArrayRef strings)
382 {
383     const size_t count = WKArrayGetSize(strings);
384
385     JSValueRef arrayResult = JSObjectMakeArray(context, 0, 0, 0);
386     JSObjectRef arrayObj = JSValueToObject(context, arrayResult, 0);
387     for (size_t i = 0; i < count; ++i) {
388         WKStringRef stringRef = static_cast<WKStringRef>(WKArrayGetItemAtIndex(strings, i));
389         JSRetainPtr<JSStringRef> stringJS = toJS(stringRef);
390         JSObjectSetPropertyAtIndex(context, arrayObj, i, JSValueMakeString(context, stringJS.get()), 0);
391     }
392
393     return arrayResult;
394 }
395
396 JSValueRef TestRunner::originsWithApplicationCache()
397 {
398     WKBundlePageRef page = InjectedBundle::singleton().page()->page();
399
400     WKRetainPtr<WKArrayRef> origins(AdoptWK, WKBundlePageCopyOriginsWithApplicationCache(page));
401
402     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(page);
403     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
404
405     return stringArrayToJS(context, origins.get());
406 }
407
408 bool TestRunner::isCommandEnabled(JSStringRef name)
409 {
410     return WKBundlePageIsEditingCommandEnabled(InjectedBundle::singleton().page()->page(), toWK(name).get());
411 }
412
413 void TestRunner::setCanOpenWindows(bool)
414 {
415     // The test plugins/get-url-with-blank-target.html requires that the embedding client forbid
416     // opening windows (by omitting a call to this function) so as to test that NPN_GetURL()
417     // with a blank target will return an error.
418     //
419     // It is not clear if we should implement this functionality or remove it and plugins/get-url-with-blank-target.html
420     // per the remark in <https://trac.webkit.org/changeset/64504/trunk/LayoutTests/platform/mac-wk2/Skipped>.
421     // For now, just ignore this setting.
422 }
423
424 void TestRunner::setXSSAuditorEnabled(bool enabled)
425 {
426     WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitXSSAuditorEnabled"));
427     auto& injectedBundle = InjectedBundle::singleton();
428     WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
429 }
430
431 void TestRunner::setMediaDevicesEnabled(bool enabled)
432 {
433     WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitMediaDevicesEnabled"));
434     auto& injectedBundle = InjectedBundle::singleton();
435     WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
436 }
437
438 void TestRunner::setMDNSICECandidatesEnabled(bool enabled)
439 {
440     WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitMDNSICECandidatesEnabled"));
441     auto& injectedBundle = InjectedBundle::singleton();
442     WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
443 }
444
445 void TestRunner::setWebRTCUnifiedPlanEnabled(bool enabled)
446 {
447     WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitWebRTCUnifiedPlanEnabled"));
448     auto& injectedBundle = InjectedBundle::singleton();
449     WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
450 }
451
452 void TestRunner::setCustomUserAgent(JSStringRef userAgent)
453 {
454     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetCustomUserAgent"));
455     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), toWK(userAgent).get(), nullptr);
456 }
457
458 void TestRunner::setWebAPIStatisticsEnabled(bool enabled)
459 {
460     WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitWebAPIStatisticsEnabled"));
461     auto& injectedBundle = InjectedBundle::singleton();
462     WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
463 }
464
465 void TestRunner::setModernMediaControlsEnabled(bool enabled)
466 {
467     WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitModernMediaControlsEnabled"));
468     auto& injectedBundle = InjectedBundle::singleton();
469     WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
470 }
471
472 void TestRunner::setWebGL2Enabled(bool enabled)
473 {
474     WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitWebGL2Enabled"));
475     auto& injectedBundle = InjectedBundle::singleton();
476     WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
477 }
478
479 void TestRunner::setWebGPUEnabled(bool enabled)
480 {
481     WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitWebGPUEnabled"));
482     auto& injectedBundle = InjectedBundle::singleton();
483     WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
484 }
485
486 void TestRunner::setWritableStreamAPIEnabled(bool enabled)
487 {
488     WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitWritableStreamAPIEnabled"));
489     auto& injectedBundle = InjectedBundle::singleton();
490     WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
491 }
492
493 void TestRunner::setReadableByteStreamAPIEnabled(bool enabled)
494 {
495     WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitReadableByteStreamAPIEnabled"));
496     auto& injectedBundle = InjectedBundle::singleton();
497     WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
498 }
499
500 void TestRunner::setEncryptedMediaAPIEnabled(bool enabled)
501 {
502     WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitEncryptedMediaAPIEnabled"));
503     auto& injectedBundle = InjectedBundle::singleton();
504     WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
505 }
506
507 void TestRunner::setAllowsAnySSLCertificate(bool enabled)
508 {
509     auto& injectedBundle = InjectedBundle::singleton();
510     injectedBundle.setAllowsAnySSLCertificate(enabled);
511
512     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetAllowsAnySSLCertificate"));
513     WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(enabled));
514     WKBundlePagePostSynchronousMessageForTesting(injectedBundle.page()->page(), messageName.get(), messageBody.get(), nullptr);
515 }
516
517 void TestRunner::setAllowUniversalAccessFromFileURLs(bool enabled)
518 {
519     auto& injectedBundle = InjectedBundle::singleton();
520     WKBundleSetAllowUniversalAccessFromFileURLs(injectedBundle.bundle(), injectedBundle.pageGroup(), enabled);
521 }
522
523 void TestRunner::setAllowFileAccessFromFileURLs(bool enabled)
524 {
525     auto& injectedBundle = InjectedBundle::singleton();
526     WKBundleSetAllowFileAccessFromFileURLs(injectedBundle.bundle(), injectedBundle.pageGroup(), enabled);
527 }
528
529 void TestRunner::setNeedsStorageAccessFromFileURLsQuirk(bool needsQuirk)
530 {
531     auto& injectedBundle = InjectedBundle::singleton();
532     WKBundleSetAllowStorageAccessFromFileURLS(injectedBundle.bundle(), injectedBundle.pageGroup(), needsQuirk);
533 }
534     
535 void TestRunner::setPluginsEnabled(bool enabled)
536 {
537     WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitPluginsEnabled"));
538     auto& injectedBundle = InjectedBundle::singleton();
539     WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
540 }
541
542 void TestRunner::setJavaScriptCanAccessClipboard(bool enabled)
543 {
544     auto& injectedBundle = InjectedBundle::singleton();
545     WKBundleSetJavaScriptCanAccessClipboard(injectedBundle.bundle(), injectedBundle.pageGroup(), enabled);
546 }
547
548 void TestRunner::setPrivateBrowsingEnabled(bool enabled)
549 {
550     auto& injectedBundle = InjectedBundle::singleton();
551     WKBundleSetPrivateBrowsingEnabled(injectedBundle.bundle(), injectedBundle.pageGroup(), enabled);
552 }
553
554 void TestRunner::setUseDashboardCompatibilityMode(bool enabled)
555 {
556 #if ENABLE(DASHBOARD_SUPPORT)
557     auto& injectedBundle = InjectedBundle::singleton();
558     WKBundleSetUseDashboardCompatibilityMode(injectedBundle.bundle(), injectedBundle.pageGroup(), enabled);
559 #else
560     UNUSED_PARAM(enabled);
561 #endif
562 }
563     
564 void TestRunner::setPopupBlockingEnabled(bool enabled)
565 {
566     auto& injectedBundle = InjectedBundle::singleton();
567     WKBundleSetPopupBlockingEnabled(injectedBundle.bundle(), injectedBundle.pageGroup(), enabled);
568 }
569
570 void TestRunner::setAuthorAndUserStylesEnabled(bool enabled)
571 {
572     auto& injectedBundle = InjectedBundle::singleton();
573     WKBundleSetAuthorAndUserStylesEnabled(injectedBundle.bundle(), injectedBundle.pageGroup(), enabled);
574 }
575
576 void TestRunner::addOriginAccessWhitelistEntry(JSStringRef sourceOrigin, JSStringRef destinationProtocol, JSStringRef destinationHost, bool allowDestinationSubdomains)
577 {
578     WKBundleAddOriginAccessWhitelistEntry(InjectedBundle::singleton().bundle(), toWK(sourceOrigin).get(), toWK(destinationProtocol).get(), toWK(destinationHost).get(), allowDestinationSubdomains);
579 }
580
581 void TestRunner::removeOriginAccessWhitelistEntry(JSStringRef sourceOrigin, JSStringRef destinationProtocol, JSStringRef destinationHost, bool allowDestinationSubdomains)
582 {
583     WKBundleRemoveOriginAccessWhitelistEntry(InjectedBundle::singleton().bundle(), toWK(sourceOrigin).get(), toWK(destinationProtocol).get(), toWK(destinationHost).get(), allowDestinationSubdomains);
584 }
585
586 bool TestRunner::isPageBoxVisible(int pageIndex)
587 {
588     auto& injectedBundle = InjectedBundle::singleton();
589     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(injectedBundle.page()->page());
590     return WKBundleIsPageBoxVisible(injectedBundle.bundle(), mainFrame, pageIndex);
591 }
592
593 void TestRunner::setValueForUser(JSContextRef context, JSValueRef element, JSStringRef value)
594 {
595     if (!element || !JSValueIsObject(context, element))
596         return;
597
598     WKRetainPtr<WKBundleNodeHandleRef> nodeHandle(AdoptWK, WKBundleNodeHandleCreate(context, const_cast<JSObjectRef>(element)));
599     WKBundleNodeHandleSetHTMLInputElementValueForUser(nodeHandle.get(), toWK(value).get());
600 }
601
602 void TestRunner::setAudioResult(JSContextRef context, JSValueRef data)
603 {
604     auto& injectedBundle = InjectedBundle::singleton();
605     // FIXME (123058): Use a JSC API to get buffer contents once such is exposed.
606     WKRetainPtr<WKDataRef> audioData(AdoptWK, WKBundleCreateWKDataFromUInt8Array(injectedBundle.bundle(), context, data));
607     injectedBundle.setAudioResult(audioData.get());
608     setWhatToDump(WhatToDump::Audio);
609     setDumpPixels(false);
610 }
611
612 unsigned TestRunner::windowCount()
613 {
614     return InjectedBundle::singleton().pageCount();
615 }
616
617 void TestRunner::clearBackForwardList()
618 {
619     WKBundleBackForwardListClear(WKBundlePageGetBackForwardList(InjectedBundle::singleton().page()->page()));
620 }
621
622 // Object Creation
623
624 void TestRunner::makeWindowObject(JSContextRef context, JSObjectRef windowObject, JSValueRef* exception)
625 {
626     setProperty(context, windowObject, "testRunner", this, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete, exception);
627 }
628
629 void TestRunner::showWebInspector()
630 {
631     WKBundleInspectorShow(WKBundlePageGetInspector(InjectedBundle::singleton().page()->page()));
632 }
633
634 void TestRunner::closeWebInspector()
635 {
636     WKBundleInspectorClose(WKBundlePageGetInspector(InjectedBundle::singleton().page()->page()));
637 }
638
639 void TestRunner::evaluateInWebInspector(JSStringRef script)
640 {
641     WKRetainPtr<WKStringRef> scriptWK = toWK(script);
642     WKBundleInspectorEvaluateScriptForTest(WKBundlePageGetInspector(InjectedBundle::singleton().page()->page()), scriptWK.get());
643 }
644
645 typedef WTF::HashMap<unsigned, WKRetainPtr<WKBundleScriptWorldRef> > WorldMap;
646 static WorldMap& worldMap()
647 {
648     static WorldMap& map = *new WorldMap;
649     return map;
650 }
651
652 unsigned TestRunner::worldIDForWorld(WKBundleScriptWorldRef world)
653 {
654     WorldMap::const_iterator end = worldMap().end();
655     for (WorldMap::const_iterator it = worldMap().begin(); it != end; ++it) {
656         if (it->value == world)
657             return it->key;
658     }
659
660     return 0;
661 }
662
663 void TestRunner::evaluateScriptInIsolatedWorld(JSContextRef context, unsigned worldID, JSStringRef script)
664 {
665     // A worldID of 0 always corresponds to a new world. Any other worldID corresponds to a world
666     // that is created once and cached forever.
667     WKRetainPtr<WKBundleScriptWorldRef> world;
668     if (!worldID)
669         world.adopt(WKBundleScriptWorldCreateWorld());
670     else {
671         WKRetainPtr<WKBundleScriptWorldRef>& worldSlot = worldMap().add(worldID, nullptr).iterator->value;
672         if (!worldSlot)
673             worldSlot.adopt(WKBundleScriptWorldCreateWorld());
674         world = worldSlot;
675     }
676
677     WKBundleFrameRef frame = WKBundleFrameForJavaScriptContext(context);
678     if (!frame)
679         frame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
680
681     JSGlobalContextRef jsContext = WKBundleFrameGetJavaScriptContextForWorld(frame, world.get());
682     JSEvaluateScript(jsContext, script, 0, 0, 0, 0); 
683 }
684
685 void TestRunner::setPOSIXLocale(JSStringRef locale)
686 {
687     char localeBuf[32];
688     JSStringGetUTF8CString(locale, localeBuf, sizeof(localeBuf));
689     setlocale(LC_ALL, localeBuf);
690 }
691
692 void TestRunner::setTextDirection(JSStringRef direction)
693 {
694     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
695     return WKBundleFrameSetTextDirection(mainFrame, toWK(direction).get());
696 }
697     
698 void TestRunner::setShouldStayOnPageAfterHandlingBeforeUnload(bool shouldStayOnPage)
699 {
700     InjectedBundle::singleton().postNewBeforeUnloadReturnValue(!shouldStayOnPage);
701 }
702
703 void TestRunner::setDefersLoading(bool shouldDeferLoading)
704 {
705     WKBundlePageSetDefersLoading(InjectedBundle::singleton().page()->page(), shouldDeferLoading);
706 }
707
708 bool TestRunner::didReceiveServerRedirectForProvisionalNavigation() const
709 {
710     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("DidReceiveServerRedirectForProvisionalNavigation"));
711     WKTypeRef returnData = 0;
712
713     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), 0, &returnData);
714     return WKBooleanGetValue(static_cast<WKBooleanRef>(returnData));
715 }
716
717 void TestRunner::clearDidReceiveServerRedirectForProvisionalNavigation()
718 {
719     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("ClearDidReceiveServerRedirectForProvisionalNavigation"));
720     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), 0, nullptr);
721 }
722
723 void TestRunner::setPageVisibility(JSStringRef state)
724 {
725     InjectedBundle::singleton().setHidden(JSStringIsEqualToUTF8CString(state, "hidden") || JSStringIsEqualToUTF8CString(state, "prerender"));
726 }
727
728 void TestRunner::resetPageVisibility()
729 {
730     InjectedBundle::singleton().setHidden(false);
731 }
732
733 typedef WTF::HashMap<unsigned, JSValueRef> CallbackMap;
734 static CallbackMap& callbackMap()
735 {
736     static CallbackMap& map = *new CallbackMap;
737     return map;
738 }
739
740 enum {
741     AddChromeInputFieldCallbackID = 1,
742     RemoveChromeInputFieldCallbackID,
743     FocusWebViewCallbackID,
744     SetBackingScaleFactorCallbackID,
745     DidBeginSwipeCallbackID,
746     WillEndSwipeCallbackID,
747     DidEndSwipeCallbackID,
748     DidRemoveSwipeSnapshotCallbackID,
749     SetStatisticsDebugModeCallbackID,
750     SetStatisticsPrevalentResourceForDebugModeCallbackID,
751     SetStatisticsLastSeenCallbackID,
752     SetStatisticsPrevalentResourceCallbackID,
753     SetStatisticsVeryPrevalentResourceCallbackID,
754     SetStatisticsHasHadUserInteractionCallbackID,
755     StatisticsDidModifyDataRecordsCallbackID,
756     StatisticsDidScanDataRecordsCallbackID,
757     StatisticsDidRunTelemetryCallbackID,
758     StatisticsDidClearThroughWebsiteDataRemovalCallbackID,
759     StatisticsDidResetToConsistentStateCallbackID,
760     StatisticsDidSetBlockCookiesForHostCallbackID,
761     AllStorageAccessEntriesCallbackID,
762     DidRemoveAllSessionCredentialsCallbackID,
763     GetApplicationManifestCallbackID,
764     TextDidChangeInTextFieldCallbackID,
765     TextFieldDidBeginEditingCallbackID,
766     TextFieldDidEndEditingCallbackID,
767     FirstUIScriptCallbackID = 100
768 };
769
770 static void cacheTestRunnerCallback(unsigned index, JSValueRef callback)
771 {
772     if (!callback)
773         return;
774
775     if (callbackMap().contains(index)) {
776         InjectedBundle::singleton().outputText(String::format("FAIL: Tried to install a second TestRunner callback for the same event (id %d)\n\n", index));
777         return;
778     }
779
780     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
781     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
782     JSValueProtect(context, callback);
783     callbackMap().add(index, callback);
784 }
785
786 static void callTestRunnerCallback(unsigned index, size_t argumentCount = 0, const JSValueRef arguments[] = nullptr)
787 {
788     if (!callbackMap().contains(index))
789         return;
790     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
791     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
792     JSObjectRef callback = JSValueToObject(context, callbackMap().take(index), 0);
793     JSObjectCallAsFunction(context, callback, JSContextGetGlobalObject(context), argumentCount, arguments, 0);
794     JSValueUnprotect(context, callback);
795 }
796
797 void TestRunner::clearTestRunnerCallbacks()
798 {
799     for (auto& iter : callbackMap()) {
800         WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
801         JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
802         JSObjectRef callback = JSValueToObject(context, iter.value, 0);
803         JSValueUnprotect(context, callback);
804     }
805
806     callbackMap().clear();
807 }
808
809 void TestRunner::accummulateLogsForChannel(JSStringRef)
810 {
811     // FIXME: Implement getting the call to all processes.
812 }
813
814 void TestRunner::addChromeInputField(JSValueRef callback)
815 {
816     cacheTestRunnerCallback(AddChromeInputFieldCallbackID, callback);
817     InjectedBundle::singleton().postAddChromeInputField();
818 }
819
820 void TestRunner::removeChromeInputField(JSValueRef callback)
821 {
822     cacheTestRunnerCallback(RemoveChromeInputFieldCallbackID, callback);
823     InjectedBundle::singleton().postRemoveChromeInputField();
824 }
825
826 void TestRunner::focusWebView(JSValueRef callback)
827 {
828     cacheTestRunnerCallback(FocusWebViewCallbackID, callback);
829     InjectedBundle::singleton().postFocusWebView();
830 }
831
832 void TestRunner::setBackingScaleFactor(double backingScaleFactor, JSValueRef callback)
833 {
834     cacheTestRunnerCallback(SetBackingScaleFactorCallbackID, callback);
835     InjectedBundle::singleton().postSetBackingScaleFactor(backingScaleFactor);
836 }
837
838 void TestRunner::setWindowIsKey(bool isKey)
839 {
840     InjectedBundle::singleton().postSetWindowIsKey(isKey);
841 }
842
843 void TestRunner::setViewSize(double width, double height)
844 {
845     InjectedBundle::singleton().postSetViewSize(width, height);
846 }
847
848 void TestRunner::callAddChromeInputFieldCallback()
849 {
850     callTestRunnerCallback(AddChromeInputFieldCallbackID);
851 }
852
853 void TestRunner::callRemoveChromeInputFieldCallback()
854 {
855     callTestRunnerCallback(RemoveChromeInputFieldCallbackID);
856 }
857
858 void TestRunner::callFocusWebViewCallback()
859 {
860     callTestRunnerCallback(FocusWebViewCallbackID);
861 }
862
863 void TestRunner::callSetBackingScaleFactorCallback()
864 {
865     callTestRunnerCallback(SetBackingScaleFactorCallbackID);
866 }
867
868 static inline bool toBool(JSStringRef value)
869 {
870     return JSStringIsEqualToUTF8CString(value, "true") || JSStringIsEqualToUTF8CString(value, "1");
871 }
872
873 void TestRunner::overridePreference(JSStringRef preference, JSStringRef value)
874 {
875     auto& injectedBundle = InjectedBundle::singleton();
876     // FIXME: handle non-boolean preferences.
877     WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), toWK(preference).get(), toBool(value));
878 }
879
880 void TestRunner::setAlwaysAcceptCookies(bool accept)
881 {
882     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetAlwaysAcceptCookies"));
883
884     WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(accept));
885
886     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
887 }
888
889 double TestRunner::preciseTime()
890 {
891     return WallTime::now().secondsSinceEpoch().seconds();
892 }
893
894 void TestRunner::setUserStyleSheetEnabled(bool enabled)
895 {
896     m_userStyleSheetEnabled = enabled;
897
898     WKRetainPtr<WKStringRef> emptyUrl = adoptWK(WKStringCreateWithUTF8CString(""));
899     WKStringRef location = enabled ? m_userStyleSheetLocation.get() : emptyUrl.get();
900     auto& injectedBundle = InjectedBundle::singleton();
901     WKBundleSetUserStyleSheetLocation(injectedBundle.bundle(), injectedBundle.pageGroup(), location);
902 }
903
904 void TestRunner::setUserStyleSheetLocation(JSStringRef location)
905 {
906     m_userStyleSheetLocation = adoptWK(WKStringCreateWithJSString(location));
907
908     if (m_userStyleSheetEnabled)
909         setUserStyleSheetEnabled(true);
910 }
911
912 void TestRunner::setSpatialNavigationEnabled(bool enabled)
913 {
914     auto& injectedBundle = InjectedBundle::singleton();
915     WKBundleSetSpatialNavigationEnabled(injectedBundle.bundle(), injectedBundle.pageGroup(), enabled);
916 }
917
918 void TestRunner::setTabKeyCyclesThroughElements(bool enabled)
919 {
920     auto& injectedBundle = InjectedBundle::singleton();
921     WKBundleSetTabKeyCyclesThroughElements(injectedBundle.bundle(), injectedBundle.page()->page(), enabled);
922 }
923
924 void TestRunner::setSerializeHTTPLoads()
925 {
926     // WK2 doesn't reorder loads.
927 }
928
929 void TestRunner::dispatchPendingLoadRequests()
930 {
931     // WK2 doesn't keep pending requests.
932 }
933
934 void TestRunner::setCacheModel(int model)
935 {
936     InjectedBundle::singleton().setCacheModel(model);
937 }
938
939 void TestRunner::setAsynchronousSpellCheckingEnabled(bool enabled)
940 {
941     auto& injectedBundle = InjectedBundle::singleton();
942     WKBundleSetAsynchronousSpellCheckingEnabled(injectedBundle.bundle(), injectedBundle.pageGroup(), enabled);
943 }
944
945 void TestRunner::grantWebNotificationPermission(JSStringRef origin)
946 {
947     WKRetainPtr<WKStringRef> originWK = toWK(origin);
948     auto& injectedBundle = InjectedBundle::singleton();
949     WKBundleSetWebNotificationPermission(injectedBundle.bundle(), injectedBundle.page()->page(), originWK.get(), true);
950 }
951
952 void TestRunner::denyWebNotificationPermission(JSStringRef origin)
953 {
954     WKRetainPtr<WKStringRef> originWK = toWK(origin);
955     auto& injectedBundle = InjectedBundle::singleton();
956     WKBundleSetWebNotificationPermission(injectedBundle.bundle(), injectedBundle.page()->page(), originWK.get(), false);
957 }
958
959 void TestRunner::removeAllWebNotificationPermissions()
960 {
961     auto& injectedBundle = InjectedBundle::singleton();
962     WKBundleRemoveAllWebNotificationPermissions(injectedBundle.bundle(), injectedBundle.page()->page());
963 }
964
965 void TestRunner::simulateWebNotificationClick(JSValueRef notification)
966 {
967     auto& injectedBundle = InjectedBundle::singleton();
968     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(injectedBundle.page()->page());
969     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
970     uint64_t notificationID = WKBundleGetWebNotificationID(injectedBundle.bundle(), context, notification);
971     injectedBundle.postSimulateWebNotificationClick(notificationID);
972 }
973
974 void TestRunner::setGeolocationPermission(bool enabled)
975 {
976     // FIXME: this should be done by frame.
977     InjectedBundle::singleton().setGeolocationPermission(enabled);
978 }
979
980 bool TestRunner::isGeolocationProviderActive()
981 {
982     return InjectedBundle::singleton().isGeolocationProviderActive();
983 }
984
985 void TestRunner::setMockGeolocationPosition(double latitude, double longitude, double accuracy, JSValueRef jsAltitude, JSValueRef jsAltitudeAccuracy, JSValueRef jsHeading, JSValueRef jsSpeed, JSValueRef jsFloorLevel)
986 {
987     auto& injectedBundle = InjectedBundle::singleton();
988     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(injectedBundle.page()->page());
989     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
990
991     bool providesAltitude = false;
992     double altitude = 0.;
993     if (!JSValueIsUndefined(context, jsAltitude)) {
994         providesAltitude = true;
995         altitude = JSValueToNumber(context, jsAltitude, 0);
996     }
997
998     bool providesAltitudeAccuracy = false;
999     double altitudeAccuracy = 0.;
1000     if (!JSValueIsUndefined(context, jsAltitudeAccuracy)) {
1001         providesAltitudeAccuracy = true;
1002         altitudeAccuracy = JSValueToNumber(context, jsAltitudeAccuracy, 0);
1003     }
1004
1005     bool providesHeading = false;
1006     double heading = 0.;
1007     if (!JSValueIsUndefined(context, jsHeading)) {
1008         providesHeading = true;
1009         heading = JSValueToNumber(context, jsHeading, 0);
1010     }
1011
1012     bool providesSpeed = false;
1013     double speed = 0.;
1014     if (!JSValueIsUndefined(context, jsSpeed)) {
1015         providesSpeed = true;
1016         speed = JSValueToNumber(context, jsSpeed, 0);
1017     }
1018
1019     bool providesFloorLevel = false;
1020     double floorLevel = 0.;
1021     if (!JSValueIsUndefined(context, jsFloorLevel)) {
1022         providesFloorLevel = true;
1023         floorLevel = JSValueToNumber(context, jsFloorLevel, 0);
1024     }
1025
1026     injectedBundle.setMockGeolocationPosition(latitude, longitude, accuracy, providesAltitude, altitude, providesAltitudeAccuracy, altitudeAccuracy, providesHeading, heading, providesSpeed, speed, providesFloorLevel, floorLevel);
1027 }
1028
1029 void TestRunner::setMockGeolocationPositionUnavailableError(JSStringRef message)
1030 {
1031     WKRetainPtr<WKStringRef> messageWK = toWK(message);
1032     InjectedBundle::singleton().setMockGeolocationPositionUnavailableError(messageWK.get());
1033 }
1034
1035 void TestRunner::setUserMediaPermission(bool enabled)
1036 {
1037     // FIXME: this should be done by frame.
1038     InjectedBundle::singleton().setUserMediaPermission(enabled);
1039 }
1040
1041 void TestRunner::resetUserMediaPermission()
1042 {
1043     // FIXME: this should be done by frame.
1044     InjectedBundle::singleton().resetUserMediaPermission();
1045 }
1046
1047 void TestRunner::setUserMediaPersistentPermissionForOrigin(bool permission, JSStringRef origin, JSStringRef parentOrigin)
1048 {
1049     WKRetainPtr<WKStringRef> originWK = toWK(origin);
1050     WKRetainPtr<WKStringRef> parentOriginWK = toWK(parentOrigin);
1051     InjectedBundle::singleton().setUserMediaPersistentPermissionForOrigin(permission, originWK.get(), parentOriginWK.get());
1052 }
1053
1054 unsigned TestRunner::userMediaPermissionRequestCountForOrigin(JSStringRef origin, JSStringRef parentOrigin) const
1055 {
1056     WKRetainPtr<WKStringRef> originWK = toWK(origin);
1057     WKRetainPtr<WKStringRef> parentOriginWK = toWK(parentOrigin);
1058     return InjectedBundle::singleton().userMediaPermissionRequestCountForOrigin(originWK.get(), parentOriginWK.get());
1059 }
1060
1061 void TestRunner::resetUserMediaPermissionRequestCountForOrigin(JSStringRef origin, JSStringRef parentOrigin)
1062 {
1063     WKRetainPtr<WKStringRef> originWK = toWK(origin);
1064     WKRetainPtr<WKStringRef> parentOriginWK = toWK(parentOrigin);
1065     InjectedBundle::singleton().resetUserMediaPermissionRequestCountForOrigin(originWK.get(), parentOriginWK.get());
1066 }
1067
1068 bool TestRunner::callShouldCloseOnWebView()
1069 {
1070     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
1071     return WKBundleFrameCallShouldCloseOnWebView(mainFrame);
1072 }
1073
1074 void TestRunner::queueBackNavigation(unsigned howFarBackward)
1075 {
1076     InjectedBundle::singleton().queueBackNavigation(howFarBackward);
1077 }
1078
1079 void TestRunner::queueForwardNavigation(unsigned howFarForward)
1080 {
1081     InjectedBundle::singleton().queueForwardNavigation(howFarForward);
1082 }
1083
1084 void TestRunner::queueLoad(JSStringRef url, JSStringRef target, bool shouldOpenExternalURLs)
1085 {
1086     auto& injectedBundle = InjectedBundle::singleton();
1087     WKRetainPtr<WKURLRef> baseURLWK(AdoptWK, WKBundleFrameCopyURL(WKBundlePageGetMainFrame(injectedBundle.page()->page())));
1088     WKRetainPtr<WKURLRef> urlWK(AdoptWK, WKURLCreateWithBaseURL(baseURLWK.get(), toWTFString(toWK(url)).utf8().data()));
1089     WKRetainPtr<WKStringRef> urlStringWK(AdoptWK, WKURLCopyString(urlWK.get()));
1090
1091     injectedBundle.queueLoad(urlStringWK.get(), toWK(target).get(), shouldOpenExternalURLs);
1092 }
1093
1094 void TestRunner::queueLoadHTMLString(JSStringRef content, JSStringRef baseURL, JSStringRef unreachableURL)
1095 {
1096     WKRetainPtr<WKStringRef> contentWK = toWK(content);
1097     WKRetainPtr<WKStringRef> baseURLWK = baseURL ? toWK(baseURL) : WKRetainPtr<WKStringRef>();
1098     WKRetainPtr<WKStringRef> unreachableURLWK = unreachableURL ? toWK(unreachableURL) : WKRetainPtr<WKStringRef>();
1099
1100     InjectedBundle::singleton().queueLoadHTMLString(contentWK.get(), baseURLWK.get(), unreachableURLWK.get());
1101 }
1102
1103 void TestRunner::queueReload()
1104 {
1105     InjectedBundle::singleton().queueReload();
1106 }
1107
1108 void TestRunner::queueLoadingScript(JSStringRef script)
1109 {
1110     WKRetainPtr<WKStringRef> scriptWK = toWK(script);
1111     InjectedBundle::singleton().queueLoadingScript(scriptWK.get());
1112 }
1113
1114 void TestRunner::queueNonLoadingScript(JSStringRef script)
1115 {
1116     WKRetainPtr<WKStringRef> scriptWK = toWK(script);
1117     InjectedBundle::singleton().queueNonLoadingScript(scriptWK.get());
1118 }
1119
1120 void TestRunner::setRejectsProtectionSpaceAndContinueForAuthenticationChallenges(bool value)
1121 {
1122     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetRejectsProtectionSpaceAndContinueForAuthenticationChallenges"));
1123     WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(value));
1124     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
1125 }
1126     
1127 void TestRunner::setHandlesAuthenticationChallenges(bool handlesAuthenticationChallenges)
1128 {
1129     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetHandlesAuthenticationChallenges"));
1130     WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(handlesAuthenticationChallenges));
1131     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
1132 }
1133
1134 void TestRunner::setShouldLogCanAuthenticateAgainstProtectionSpace(bool value)
1135 {
1136     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetShouldLogCanAuthenticateAgainstProtectionSpace"));
1137     WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(value));
1138     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
1139 }
1140
1141 void TestRunner::setShouldLogDownloadCallbacks(bool value)
1142 {
1143     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetShouldLogDownloadCallbacks"));
1144     WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(value));
1145     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
1146 }
1147
1148 void TestRunner::setAuthenticationUsername(JSStringRef username)
1149 {
1150     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetAuthenticationUsername"));
1151     WKRetainPtr<WKStringRef> messageBody(AdoptWK, WKStringCreateWithJSString(username));
1152     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
1153 }
1154
1155 void TestRunner::setAuthenticationPassword(JSStringRef password)
1156 {
1157     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetAuthenticationPassword"));
1158     WKRetainPtr<WKStringRef> messageBody(AdoptWK, WKStringCreateWithJSString(password));
1159     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
1160 }
1161
1162 bool TestRunner::secureEventInputIsEnabled() const
1163 {
1164     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SecureEventInputIsEnabled"));
1165     WKTypeRef returnData = 0;
1166
1167     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), 0, &returnData);
1168     return WKBooleanGetValue(static_cast<WKBooleanRef>(returnData));
1169 }
1170
1171 void TestRunner::setBlockAllPlugins(bool shouldBlock)
1172 {
1173     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetBlockAllPlugins"));
1174     WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(shouldBlock));
1175     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
1176 }
1177
1178 void TestRunner::setPluginSupportedMode(JSStringRef mode)
1179 {
1180     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetPluginSupportedMode"));
1181     WKRetainPtr<WKStringRef> messageBody(AdoptWK, WKStringCreateWithJSString(mode));
1182     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
1183 }
1184
1185 JSValueRef TestRunner::failNextNewCodeBlock()
1186 {
1187     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
1188     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
1189     return JSC::failNextNewCodeBlock(context);
1190 }
1191
1192 JSValueRef TestRunner::numberOfDFGCompiles(JSValueRef theFunction)
1193 {
1194     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
1195     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
1196     return JSC::numberOfDFGCompiles(context, theFunction);
1197 }
1198
1199 JSValueRef TestRunner::neverInlineFunction(JSValueRef theFunction)
1200 {
1201     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
1202     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
1203     return JSC::setNeverInline(context, theFunction);
1204 }
1205
1206 void TestRunner::setShouldDecideNavigationPolicyAfterDelay(bool value)
1207 {
1208     m_shouldDecideNavigationPolicyAfterDelay = value;
1209     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetShouldDecideNavigationPolicyAfterDelay"));
1210     WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(value));
1211     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
1212 }
1213
1214 void TestRunner::setShouldDecideResponsePolicyAfterDelay(bool value)
1215 {
1216     m_shouldDecideResponsePolicyAfterDelay = value;
1217     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetShouldDecideResponsePolicyAfterDelay"));
1218     WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(value));
1219     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
1220 }
1221
1222 void TestRunner::setNavigationGesturesEnabled(bool value)
1223 {
1224     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetNavigationGesturesEnabled"));
1225     WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(value));
1226     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
1227 }
1228
1229 void TestRunner::setIgnoresViewportScaleLimits(bool value)
1230 {
1231     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetIgnoresViewportScaleLimits"));
1232     WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(value));
1233     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
1234 }
1235
1236 void TestRunner::setShouldDownloadUndisplayableMIMETypes(bool value)
1237 {
1238     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetShouldDownloadUndisplayableMIMETypes"));
1239     WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(value));
1240     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
1241 }
1242
1243 void TestRunner::terminateNetworkProcess()
1244 {
1245     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("TerminateNetworkProcess"));
1246     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), nullptr, nullptr);
1247 }
1248
1249 void TestRunner::terminateServiceWorkerProcess()
1250 {
1251     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("TerminateServiceWorkerProcess"));
1252     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), nullptr, nullptr);
1253 }
1254
1255 void TestRunner::terminateStorageProcess()
1256 {
1257     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("TerminateStorageProcess"));
1258     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), nullptr, nullptr);
1259 }
1260
1261 static unsigned nextUIScriptCallbackID()
1262 {
1263     static unsigned callbackID = FirstUIScriptCallbackID;
1264     return callbackID++;
1265 }
1266
1267 void TestRunner::runUIScript(JSStringRef script, JSValueRef callback)
1268 {
1269     unsigned callbackID = nextUIScriptCallbackID();
1270     cacheTestRunnerCallback(callbackID, callback);
1271
1272     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("RunUIProcessScript"));
1273
1274     WKRetainPtr<WKMutableDictionaryRef> testDictionary(AdoptWK, WKMutableDictionaryCreate());
1275
1276     WKRetainPtr<WKStringRef> scriptKey(AdoptWK, WKStringCreateWithUTF8CString("Script"));
1277     WKRetainPtr<WKStringRef> scriptValue(AdoptWK, WKStringCreateWithJSString(script));
1278
1279     WKRetainPtr<WKStringRef> callbackIDKey(AdoptWK, WKStringCreateWithUTF8CString("CallbackID"));
1280     WKRetainPtr<WKUInt64Ref> callbackIDValue = adoptWK(WKUInt64Create(callbackID));
1281
1282     WKDictionarySetItem(testDictionary.get(), scriptKey.get(), scriptValue.get());
1283     WKDictionarySetItem(testDictionary.get(), callbackIDKey.get(), callbackIDValue.get());
1284
1285     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), testDictionary.get());
1286 }
1287
1288 void TestRunner::runUIScriptCallback(unsigned callbackID, JSStringRef result)
1289 {
1290     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
1291     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
1292
1293     JSValueRef resultValue = JSValueMakeString(context, result);
1294     callTestRunnerCallback(callbackID, 1, &resultValue);
1295 }
1296
1297 void TestRunner::installDidBeginSwipeCallback(JSValueRef callback)
1298 {
1299     cacheTestRunnerCallback(DidBeginSwipeCallbackID, callback);
1300 }
1301
1302 void TestRunner::installWillEndSwipeCallback(JSValueRef callback)
1303 {
1304     cacheTestRunnerCallback(WillEndSwipeCallbackID, callback);
1305 }
1306
1307 void TestRunner::installDidEndSwipeCallback(JSValueRef callback)
1308 {
1309     cacheTestRunnerCallback(DidEndSwipeCallbackID, callback);
1310 }
1311
1312 void TestRunner::installDidRemoveSwipeSnapshotCallback(JSValueRef callback)
1313 {
1314     cacheTestRunnerCallback(DidRemoveSwipeSnapshotCallbackID, callback);
1315 }
1316
1317 void TestRunner::callDidBeginSwipeCallback()
1318 {
1319     callTestRunnerCallback(DidBeginSwipeCallbackID);
1320 }
1321
1322 void TestRunner::callWillEndSwipeCallback()
1323 {
1324     callTestRunnerCallback(WillEndSwipeCallbackID);
1325 }
1326
1327 void TestRunner::callDidEndSwipeCallback()
1328 {
1329     callTestRunnerCallback(DidEndSwipeCallbackID);
1330 }
1331
1332 void TestRunner::callDidRemoveSwipeSnapshotCallback()
1333 {
1334     callTestRunnerCallback(DidRemoveSwipeSnapshotCallbackID);
1335 }
1336
1337 void TestRunner::setStatisticsDebugMode(bool value, JSValueRef completionHandler)
1338 {
1339     cacheTestRunnerCallback(SetStatisticsDebugModeCallbackID, completionHandler);
1340
1341     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetStatisticsDebugMode"));
1342     WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(value));
1343     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1344
1345 }
1346
1347 void TestRunner::statisticsCallDidSetDebugModeCallback()
1348 {
1349     callTestRunnerCallback(SetStatisticsDebugModeCallbackID);
1350 }
1351
1352 void TestRunner::setStatisticsPrevalentResourceForDebugMode(JSStringRef hostName, JSValueRef completionHandler)
1353 {
1354     cacheTestRunnerCallback(SetStatisticsPrevalentResourceForDebugModeCallbackID, completionHandler);
1355     
1356     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetStatisticsPrevalentResourceForDebugMode"));
1357     WKRetainPtr<WKStringRef> messageBody(AdoptWK, WKStringCreateWithJSString(hostName));
1358     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1359 }
1360
1361 void TestRunner::statisticsCallDidSetPrevalentResourceForDebugModeCallback()
1362 {
1363     callTestRunnerCallback(SetStatisticsPrevalentResourceForDebugModeCallbackID);
1364 }
1365
1366 void TestRunner::setStatisticsLastSeen(JSStringRef hostName, double seconds, JSValueRef completionHandler)
1367 {
1368     cacheTestRunnerCallback(SetStatisticsLastSeenCallbackID, completionHandler);
1369
1370     Vector<WKRetainPtr<WKStringRef>> keys;
1371     Vector<WKRetainPtr<WKTypeRef>> values;
1372     
1373     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("HostName") });
1374     values.append({ AdoptWK, WKStringCreateWithJSString(hostName) });
1375     
1376     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("Value") });
1377     values.append({ AdoptWK, WKDoubleCreate(seconds) });
1378     
1379     Vector<WKStringRef> rawKeys(keys.size());
1380     Vector<WKTypeRef> rawValues(values.size());
1381     
1382     for (size_t i = 0; i < keys.size(); ++i) {
1383         rawKeys[i] = keys[i].get();
1384         rawValues[i] = values[i].get();
1385     }
1386     
1387     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetStatisticsLastSeen"));
1388     WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1389     
1390     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1391 }
1392
1393 void TestRunner::statisticsCallDidSetLastSeenCallback()
1394 {
1395     callTestRunnerCallback(SetStatisticsLastSeenCallbackID);
1396 }
1397
1398 void TestRunner::setStatisticsPrevalentResource(JSStringRef hostName, bool value, JSValueRef completionHandler)
1399 {
1400     cacheTestRunnerCallback(SetStatisticsPrevalentResourceCallbackID, completionHandler);
1401
1402     Vector<WKRetainPtr<WKStringRef>> keys;
1403     Vector<WKRetainPtr<WKTypeRef>> values;
1404
1405     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("HostName") });
1406     values.append({ AdoptWK, WKStringCreateWithJSString(hostName) });
1407     
1408     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("Value") });
1409     values.append({ AdoptWK, WKBooleanCreate(value) });
1410     
1411     Vector<WKStringRef> rawKeys;
1412     Vector<WKTypeRef> rawValues;
1413     rawKeys.resize(keys.size());
1414     rawValues.resize(values.size());
1415     
1416     for (size_t i = 0; i < keys.size(); ++i) {
1417         rawKeys[i] = keys[i].get();
1418         rawValues[i] = values[i].get();
1419     }
1420     
1421     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetStatisticsPrevalentResource"));
1422     WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1423
1424     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1425 }
1426
1427 void TestRunner::statisticsCallDidSetPrevalentResourceCallback()
1428 {
1429     callTestRunnerCallback(SetStatisticsPrevalentResourceCallbackID);
1430 }
1431
1432 void TestRunner::setStatisticsVeryPrevalentResource(JSStringRef hostName, bool value, JSValueRef completionHandler)
1433 {
1434     cacheTestRunnerCallback(SetStatisticsVeryPrevalentResourceCallbackID, completionHandler);
1435
1436     Vector<WKRetainPtr<WKStringRef>> keys;
1437     Vector<WKRetainPtr<WKTypeRef>> values;
1438     
1439     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("HostName") });
1440     values.append({ AdoptWK, WKStringCreateWithJSString(hostName) });
1441     
1442     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("Value") });
1443     values.append({ AdoptWK, WKBooleanCreate(value) });
1444     
1445     Vector<WKStringRef> rawKeys;
1446     Vector<WKTypeRef> rawValues;
1447     rawKeys.resize(keys.size());
1448     rawValues.resize(values.size());
1449     
1450     for (size_t i = 0; i < keys.size(); ++i) {
1451         rawKeys[i] = keys[i].get();
1452         rawValues[i] = values[i].get();
1453     }
1454     
1455     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetStatisticsVeryPrevalentResource"));
1456     WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1457     
1458     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1459 }
1460
1461 void TestRunner::statisticsCallDidSetVeryPrevalentResourceCallback()
1462 {
1463     callTestRunnerCallback(SetStatisticsVeryPrevalentResourceCallbackID);
1464 }
1465     
1466 void TestRunner::dumpResourceLoadStatistics()
1467 {
1468     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("dumpResourceLoadStatistics"));
1469     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), nullptr, nullptr);
1470 }
1471
1472 bool TestRunner::isStatisticsPrevalentResource(JSStringRef hostName)
1473 {
1474     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("IsStatisticsPrevalentResource"));
1475     WKRetainPtr<WKStringRef> messageBody(AdoptWK, WKStringCreateWithJSString(hostName));
1476     WKTypeRef returnData = 0;
1477     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get(), &returnData);
1478     return WKBooleanGetValue(static_cast<WKBooleanRef>(returnData));
1479 }
1480
1481 bool TestRunner::isStatisticsVeryPrevalentResource(JSStringRef hostName)
1482 {
1483     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("IsStatisticsVeryPrevalentResource"));
1484     WKRetainPtr<WKStringRef> messageBody(AdoptWK, WKStringCreateWithJSString(hostName));
1485     WKTypeRef returnData = 0;
1486     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get(), &returnData);
1487     return WKBooleanGetValue(static_cast<WKBooleanRef>(returnData));
1488 }
1489
1490 bool TestRunner::isStatisticsRegisteredAsSubresourceUnder(JSStringRef subresourceHost, JSStringRef topFrameHost)
1491 {
1492     Vector<WKRetainPtr<WKStringRef>> keys;
1493     Vector<WKRetainPtr<WKTypeRef>> values;
1494     
1495     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("SubresourceHost") });
1496     values.append({ AdoptWK, WKStringCreateWithJSString(subresourceHost) });
1497     
1498     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("TopFrameHost") });
1499     values.append({ AdoptWK, WKStringCreateWithJSString(topFrameHost) });
1500     
1501     Vector<WKStringRef> rawKeys(keys.size());
1502     Vector<WKTypeRef> rawValues(values.size());
1503     
1504     for (size_t i = 0; i < keys.size(); ++i) {
1505         rawKeys[i] = keys[i].get();
1506         rawValues[i] = values[i].get();
1507     }
1508     
1509     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("IsStatisticsRegisteredAsSubresourceUnder"));
1510     WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1511     WKTypeRef returnData = 0;
1512     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get(), &returnData);
1513     return WKBooleanGetValue(static_cast<WKBooleanRef>(returnData));
1514 }
1515
1516 bool TestRunner::isStatisticsRegisteredAsSubFrameUnder(JSStringRef subFrameHost, JSStringRef topFrameHost)
1517 {
1518     Vector<WKRetainPtr<WKStringRef>> keys;
1519     Vector<WKRetainPtr<WKTypeRef>> values;
1520
1521     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("SubFrameHost") });
1522     values.append({ AdoptWK, WKStringCreateWithJSString(subFrameHost) });
1523     
1524     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("TopFrameHost") });
1525     values.append({ AdoptWK, WKStringCreateWithJSString(topFrameHost) });
1526     
1527     Vector<WKStringRef> rawKeys(keys.size());
1528     Vector<WKTypeRef> rawValues(values.size());
1529
1530     for (size_t i = 0; i < keys.size(); ++i) {
1531         rawKeys[i] = keys[i].get();
1532         rawValues[i] = values[i].get();
1533     }
1534
1535     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("IsStatisticsRegisteredAsSubFrameUnder"));
1536     WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1537     WKTypeRef returnData = 0;
1538     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get(), &returnData);
1539     return WKBooleanGetValue(static_cast<WKBooleanRef>(returnData));
1540 }
1541
1542 bool TestRunner::isStatisticsRegisteredAsRedirectingTo(JSStringRef hostRedirectedFrom, JSStringRef hostRedirectedTo)
1543 {
1544     Vector<WKRetainPtr<WKStringRef>> keys;
1545     Vector<WKRetainPtr<WKTypeRef>> values;
1546     
1547     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("HostRedirectedFrom") });
1548     values.append({ AdoptWK, WKStringCreateWithJSString(hostRedirectedFrom) });
1549     
1550     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("HostRedirectedTo") });
1551     values.append({ AdoptWK, WKStringCreateWithJSString(hostRedirectedTo) });
1552     
1553     Vector<WKStringRef> rawKeys(keys.size());
1554     Vector<WKTypeRef> rawValues(values.size());
1555
1556     for (size_t i = 0; i < keys.size(); ++i) {
1557         rawKeys[i] = keys[i].get();
1558         rawValues[i] = values[i].get();
1559     }
1560     
1561     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("IsStatisticsRegisteredAsRedirectingTo"));
1562     WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1563     WKTypeRef returnData = 0;
1564     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get(), &returnData);
1565     return WKBooleanGetValue(static_cast<WKBooleanRef>(returnData));
1566 }
1567
1568 void TestRunner::setStatisticsHasHadUserInteraction(JSStringRef hostName, bool value, JSValueRef completionHandler)
1569 {
1570     cacheTestRunnerCallback(SetStatisticsHasHadUserInteractionCallbackID, completionHandler);
1571
1572     Vector<WKRetainPtr<WKStringRef>> keys;
1573     Vector<WKRetainPtr<WKTypeRef>> values;
1574     
1575     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("HostName") });
1576     values.append({ AdoptWK, WKStringCreateWithJSString(hostName) });
1577     
1578     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("Value") });
1579     values.append({ AdoptWK, WKBooleanCreate(value) });
1580     
1581     Vector<WKStringRef> rawKeys;
1582     Vector<WKTypeRef> rawValues;
1583     rawKeys.resize(keys.size());
1584     rawValues.resize(values.size());
1585     
1586     for (size_t i = 0; i < keys.size(); ++i) {
1587         rawKeys[i] = keys[i].get();
1588         rawValues[i] = values[i].get();
1589     }
1590     
1591     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetStatisticsHasHadUserInteraction"));
1592     WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1593     
1594     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1595 }
1596
1597 void TestRunner::statisticsCallDidSetHasHadUserInteractionCallback()
1598 {
1599     callTestRunnerCallback(SetStatisticsHasHadUserInteractionCallbackID);
1600 }
1601
1602 bool TestRunner::isStatisticsHasHadUserInteraction(JSStringRef hostName)
1603 {
1604     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("IsStatisticsHasHadUserInteraction"));
1605     WKRetainPtr<WKStringRef> messageBody(AdoptWK, WKStringCreateWithJSString(hostName));
1606     WKTypeRef returnData = 0;
1607     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get(), &returnData);
1608     return WKBooleanGetValue(static_cast<WKBooleanRef>(returnData));
1609 }
1610
1611 void TestRunner::setStatisticsGrandfathered(JSStringRef hostName, bool value)
1612 {
1613     Vector<WKRetainPtr<WKStringRef>> keys;
1614     Vector<WKRetainPtr<WKTypeRef>> values;
1615     
1616     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("HostName") });
1617     values.append({ AdoptWK, WKStringCreateWithJSString(hostName) });
1618     
1619     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("Value") });
1620     values.append({ AdoptWK, WKBooleanCreate(value) });
1621     
1622     Vector<WKStringRef> rawKeys;
1623     Vector<WKTypeRef> rawValues;
1624     rawKeys.resize(keys.size());
1625     rawValues.resize(values.size());
1626     
1627     for (size_t i = 0; i < keys.size(); ++i) {
1628         rawKeys[i] = keys[i].get();
1629         rawValues[i] = values[i].get();
1630     }
1631     
1632     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetStatisticsGrandfathered"));
1633     WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1634     
1635     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1636 }
1637     
1638 bool TestRunner::isStatisticsGrandfathered(JSStringRef hostName)
1639 {
1640     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("IsStatisticsGrandfathered"));
1641     WKRetainPtr<WKStringRef> messageBody(AdoptWK, WKStringCreateWithJSString(hostName));
1642     WKTypeRef returnData = 0;
1643     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get(), &returnData);
1644     return WKBooleanGetValue(static_cast<WKBooleanRef>(returnData));
1645 }
1646
1647 void TestRunner::setStatisticsSubframeUnderTopFrameOrigin(JSStringRef hostName, JSStringRef topFrameHostName)
1648 {
1649     Vector<WKRetainPtr<WKStringRef>> keys;
1650     Vector<WKRetainPtr<WKTypeRef>> values;
1651     
1652     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("HostName") });
1653     values.append({ AdoptWK, WKStringCreateWithJSString(hostName) });
1654     
1655     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("TopFrameHostName") });
1656     values.append({ AdoptWK, WKStringCreateWithJSString(topFrameHostName) });
1657     
1658     Vector<WKStringRef> rawKeys(keys.size());
1659     Vector<WKTypeRef> rawValues(values.size());
1660     
1661     for (size_t i = 0; i < keys.size(); ++i) {
1662         rawKeys[i] = keys[i].get();
1663         rawValues[i] = values[i].get();
1664     }
1665     
1666     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetStatisticsSubframeUnderTopFrameOrigin"));
1667     WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1668     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1669 }
1670
1671 void TestRunner::setStatisticsSubresourceUnderTopFrameOrigin(JSStringRef hostName, JSStringRef topFrameHostName)
1672 {
1673     Vector<WKRetainPtr<WKStringRef>> keys;
1674     Vector<WKRetainPtr<WKTypeRef>> values;
1675     
1676     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("HostName") });
1677     values.append({ AdoptWK, WKStringCreateWithJSString(hostName) });
1678     
1679     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("TopFrameHostName") });
1680     values.append({ AdoptWK, WKStringCreateWithJSString(topFrameHostName) });
1681     
1682     Vector<WKStringRef> rawKeys(keys.size());
1683     Vector<WKTypeRef> rawValues(values.size());
1684     
1685     for (size_t i = 0; i < keys.size(); ++i) {
1686         rawKeys[i] = keys[i].get();
1687         rawValues[i] = values[i].get();
1688     }
1689     
1690     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetStatisticsSubresourceUnderTopFrameOrigin"));
1691     WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1692     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1693 }
1694
1695 void TestRunner::setStatisticsSubresourceUniqueRedirectTo(JSStringRef hostName, JSStringRef hostNameRedirectedTo)
1696 {
1697     Vector<WKRetainPtr<WKStringRef>> keys;
1698     Vector<WKRetainPtr<WKTypeRef>> values;
1699     
1700     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("HostName") });
1701     values.append({ AdoptWK, WKStringCreateWithJSString(hostName) });
1702     
1703     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("HostNameRedirectedTo") });
1704     values.append({ AdoptWK, WKStringCreateWithJSString(hostNameRedirectedTo) });
1705     
1706     Vector<WKStringRef> rawKeys(keys.size());
1707     Vector<WKTypeRef> rawValues(values.size());
1708     
1709     for (size_t i = 0; i < keys.size(); ++i) {
1710         rawKeys[i] = keys[i].get();
1711         rawValues[i] = values[i].get();
1712     }
1713     
1714     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetStatisticsSubresourceUniqueRedirectTo"));
1715     WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1716     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1717 }
1718
1719
1720 void TestRunner::setStatisticsSubresourceUniqueRedirectFrom(JSStringRef hostName, JSStringRef hostNameRedirectedFrom)
1721 {
1722     Vector<WKRetainPtr<WKStringRef>> keys;
1723     Vector<WKRetainPtr<WKTypeRef>> values;
1724     
1725     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("HostName") });
1726     values.append({ AdoptWK, WKStringCreateWithJSString(hostName) });
1727     
1728     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("HostNameRedirectedFrom") });
1729     values.append({ AdoptWK, WKStringCreateWithJSString(hostNameRedirectedFrom) });
1730     
1731     Vector<WKStringRef> rawKeys(keys.size());
1732     Vector<WKTypeRef> rawValues(values.size());
1733     
1734     for (size_t i = 0; i < keys.size(); ++i) {
1735         rawKeys[i] = keys[i].get();
1736         rawValues[i] = values[i].get();
1737     }
1738     
1739     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetStatisticsSubresourceUniqueRedirectFrom"));
1740     WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1741     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1742 }
1743
1744 void TestRunner::setStatisticsTopFrameUniqueRedirectTo(JSStringRef hostName, JSStringRef hostNameRedirectedTo)
1745 {
1746     Vector<WKRetainPtr<WKStringRef>> keys;
1747     Vector<WKRetainPtr<WKTypeRef>> values;
1748     
1749     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("HostName") });
1750     values.append({ AdoptWK, WKStringCreateWithJSString(hostName) });
1751     
1752     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("HostNameRedirectedTo") });
1753     values.append({ AdoptWK, WKStringCreateWithJSString(hostNameRedirectedTo) });
1754     
1755     Vector<WKStringRef> rawKeys(keys.size());
1756     Vector<WKTypeRef> rawValues(values.size());
1757     
1758     for (size_t i = 0; i < keys.size(); ++i) {
1759         rawKeys[i] = keys[i].get();
1760         rawValues[i] = values[i].get();
1761     }
1762     
1763     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetStatisticsTopFrameUniqueRedirectTo"));
1764     WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1765     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1766 }
1767
1768 void TestRunner::setStatisticsTopFrameUniqueRedirectFrom(JSStringRef hostName, JSStringRef hostNameRedirectedFrom)
1769 {
1770     Vector<WKRetainPtr<WKStringRef>> keys;
1771     Vector<WKRetainPtr<WKTypeRef>> values;
1772     
1773     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("HostName") });
1774     values.append({ AdoptWK, WKStringCreateWithJSString(hostName) });
1775     
1776     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("HostNameRedirectedFrom") });
1777     values.append({ AdoptWK, WKStringCreateWithJSString(hostNameRedirectedFrom) });
1778     
1779     Vector<WKStringRef> rawKeys(keys.size());
1780     Vector<WKTypeRef> rawValues(values.size());
1781     
1782     for (size_t i = 0; i < keys.size(); ++i) {
1783         rawKeys[i] = keys[i].get();
1784         rawValues[i] = values[i].get();
1785     }
1786     
1787     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetStatisticsTopFrameUniqueRedirectFrom"));
1788     WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
1789     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1790 }
1791
1792
1793 void TestRunner::setStatisticsTimeToLiveUserInteraction(double seconds)
1794 {
1795     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetStatisticsTimeToLiveUserInteraction"));
1796     WKRetainPtr<WKDoubleRef> messageBody(AdoptWK, WKDoubleCreate(seconds));
1797     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1798 }
1799
1800 void TestRunner::installStatisticsDidModifyDataRecordsCallback(JSValueRef callback)
1801 {
1802     cacheTestRunnerCallback(StatisticsDidModifyDataRecordsCallbackID, callback);
1803 }
1804
1805 void TestRunner::statisticsDidModifyDataRecordsCallback()
1806 {
1807     callTestRunnerCallback(StatisticsDidModifyDataRecordsCallbackID);
1808 }
1809
1810 void TestRunner::installStatisticsDidScanDataRecordsCallback(JSValueRef callback)
1811 {
1812     cacheTestRunnerCallback(StatisticsDidScanDataRecordsCallbackID, callback);
1813 }
1814
1815 void TestRunner::statisticsDidScanDataRecordsCallback()
1816 {
1817     callTestRunnerCallback(StatisticsDidScanDataRecordsCallbackID);
1818 }
1819
1820 void TestRunner::installStatisticsDidRunTelemetryCallback(JSValueRef callback)
1821 {
1822     cacheTestRunnerCallback(StatisticsDidRunTelemetryCallbackID, callback);
1823 }
1824     
1825 void TestRunner::statisticsDidRunTelemetryCallback(unsigned totalPrevalentResources, unsigned totalPrevalentResourcesWithUserInteraction, unsigned top3SubframeUnderTopFrameOrigins)
1826 {
1827     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
1828     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
1829     
1830     StringBuilder stringBuilder;
1831     stringBuilder.appendLiteral("{ \"totalPrevalentResources\" : ");
1832     stringBuilder.appendNumber(totalPrevalentResources);
1833     stringBuilder.appendLiteral(", \"totalPrevalentResourcesWithUserInteraction\" : ");
1834     stringBuilder.appendNumber(totalPrevalentResourcesWithUserInteraction);
1835     stringBuilder.appendLiteral(", \"top3SubframeUnderTopFrameOrigins\" : ");
1836     stringBuilder.appendNumber(top3SubframeUnderTopFrameOrigins);
1837     stringBuilder.appendLiteral(" }");
1838     
1839     JSValueRef result = JSValueMakeFromJSONString(context, adopt(JSStringCreateWithUTF8CString(stringBuilder.toString().utf8().data())).get());
1840
1841     callTestRunnerCallback(StatisticsDidRunTelemetryCallbackID, 1, &result);
1842 }
1843
1844 void TestRunner::statisticsNotifyObserver()
1845 {
1846     InjectedBundle::singleton().statisticsNotifyObserver();
1847 }
1848
1849 void TestRunner::statisticsProcessStatisticsAndDataRecords()
1850 {
1851     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("StatisticsProcessStatisticsAndDataRecords"));
1852     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), 0, nullptr);
1853 }
1854
1855 void TestRunner::statisticsUpdateCookieBlocking(JSValueRef completionHandler)
1856 {
1857     cacheTestRunnerCallback(StatisticsDidSetBlockCookiesForHostCallbackID, completionHandler);
1858
1859     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("StatisticsUpdateCookieBlocking"));
1860     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), 0, nullptr);
1861 }
1862
1863 void TestRunner::statisticsCallDidSetBlockCookiesForHostCallback()
1864 {
1865     callTestRunnerCallback(StatisticsDidSetBlockCookiesForHostCallbackID);
1866 }
1867
1868 void TestRunner::statisticsSubmitTelemetry()
1869 {
1870     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("StatisticsSubmitTelemetry"));
1871     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), 0, nullptr);
1872 }
1873
1874 void TestRunner::setStatisticsNotifyPagesWhenDataRecordsWereScanned(bool value)
1875 {
1876     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("StatisticsNotifyPagesWhenDataRecordsWereScanned"));
1877     WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(value));
1878     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1879 }
1880
1881 void TestRunner::setStatisticsShouldClassifyResourcesBeforeDataRecordsRemoval(bool value)
1882 {
1883     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("StatisticsShouldClassifyResourcesBeforeDataRecordsRemoval"));
1884     WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(value));
1885     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1886 }
1887
1888 void TestRunner::setStatisticsNotifyPagesWhenTelemetryWasCaptured(bool value)
1889 {
1890     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("StatisticsNotifyPagesWhenTelemetryWasCaptured"));
1891     WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(value));
1892     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1893 }
1894
1895 void TestRunner::setStatisticsMinimumTimeBetweenDataRecordsRemoval(double seconds)
1896 {
1897     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetStatisticsMinimumTimeBetweenDataRecordsRemoval"));
1898     WKRetainPtr<WKDoubleRef> messageBody(AdoptWK, WKDoubleCreate(seconds));
1899     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1900 }
1901
1902 void TestRunner::setStatisticsGrandfatheringTime(double seconds)
1903 {
1904     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetStatisticsGrandfatheringTime"));
1905     WKRetainPtr<WKDoubleRef> messageBody(AdoptWK, WKDoubleCreate(seconds));
1906     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1907 }
1908
1909 void TestRunner::setStatisticsMaxStatisticsEntries(unsigned entries)
1910 {
1911     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetMaxStatisticsEntries"));
1912     WKRetainPtr<WKTypeRef> messageBody(AdoptWK, WKUInt64Create(entries));
1913     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1914 }
1915     
1916 void TestRunner::setStatisticsPruneEntriesDownTo(unsigned entries)
1917 {
1918     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetPruneEntriesDownTo"));
1919     WKRetainPtr<WKTypeRef> messageBody(AdoptWK, WKUInt64Create(entries));
1920     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1921 }
1922     
1923 void TestRunner::statisticsClearInMemoryAndPersistentStore(JSValueRef callback)
1924 {
1925     cacheTestRunnerCallback(StatisticsDidClearThroughWebsiteDataRemovalCallbackID, callback);
1926
1927     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("StatisticsClearInMemoryAndPersistentStore"));
1928     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), 0, nullptr);
1929 }
1930
1931 void TestRunner::statisticsClearInMemoryAndPersistentStoreModifiedSinceHours(unsigned hours, JSValueRef callback)
1932 {
1933     cacheTestRunnerCallback(StatisticsDidClearThroughWebsiteDataRemovalCallbackID, callback);
1934
1935     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("StatisticsClearInMemoryAndPersistentStoreModifiedSinceHours"));
1936     WKRetainPtr<WKTypeRef> messageBody(AdoptWK, WKUInt64Create(hours));
1937     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
1938 }
1939
1940 void TestRunner::statisticsClearThroughWebsiteDataRemoval(JSValueRef callback)
1941 {
1942     cacheTestRunnerCallback(StatisticsDidClearThroughWebsiteDataRemovalCallbackID, callback);
1943     
1944     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("StatisticsClearThroughWebsiteDataRemoval"));
1945     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), 0, nullptr);
1946 }
1947
1948 void TestRunner::statisticsCallClearThroughWebsiteDataRemovalCallback()
1949 {
1950     callTestRunnerCallback(StatisticsDidClearThroughWebsiteDataRemovalCallbackID);
1951 }
1952
1953 void TestRunner::statisticsResetToConsistentState(JSValueRef completionHandler)
1954 {
1955     cacheTestRunnerCallback(StatisticsDidResetToConsistentStateCallbackID, completionHandler);
1956     
1957     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("StatisticsResetToConsistentState"));
1958     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), 0, nullptr);
1959 }
1960
1961 void TestRunner::statisticsCallDidResetToConsistentStateCallback()
1962 {
1963     callTestRunnerCallback(StatisticsDidResetToConsistentStateCallbackID);
1964 }
1965
1966 void TestRunner::installTextDidChangeInTextFieldCallback(JSValueRef callback)
1967 {
1968     cacheTestRunnerCallback(TextDidChangeInTextFieldCallbackID, callback);
1969 }
1970
1971 void TestRunner::textDidChangeInTextFieldCallback()
1972 {
1973     callTestRunnerCallback(TextDidChangeInTextFieldCallbackID);
1974 }
1975
1976 void TestRunner::installTextFieldDidBeginEditingCallback(JSValueRef callback)
1977 {
1978     cacheTestRunnerCallback(TextFieldDidBeginEditingCallbackID, callback);
1979 }
1980
1981 void TestRunner::textFieldDidBeginEditingCallback()
1982 {
1983     callTestRunnerCallback(TextFieldDidBeginEditingCallbackID);
1984 }
1985
1986 void TestRunner::installTextFieldDidEndEditingCallback(JSValueRef callback)
1987 {
1988     cacheTestRunnerCallback(TextFieldDidEndEditingCallbackID, callback);
1989 }
1990
1991 void TestRunner::textFieldDidEndEditingCallback()
1992 {
1993     callTestRunnerCallback(TextFieldDidEndEditingCallbackID);
1994 }
1995
1996 void TestRunner::setStorageAccessAPIEnabled(bool enabled)
1997 {
1998     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetStorageAccessAPIEnabled"));
1999     
2000     WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(enabled));
2001     
2002     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
2003 }
2004
2005 void TestRunner::getAllStorageAccessEntries(JSValueRef callback)
2006 {
2007     cacheTestRunnerCallback(AllStorageAccessEntriesCallbackID, callback);
2008     
2009     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("GetAllStorageAccessEntries"));
2010     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), 0, nullptr);
2011 }
2012
2013 void TestRunner::callDidReceiveAllStorageAccessEntriesCallback(Vector<String>& domains)
2014 {
2015     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
2016     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
2017     
2018     StringBuilder stringBuilder;
2019     stringBuilder.appendLiteral("[");
2020     bool firstDomain = true;
2021     for (auto& domain : domains) {
2022         if (firstDomain)
2023             firstDomain = false;
2024         else
2025             stringBuilder.appendLiteral(", ");
2026         stringBuilder.appendLiteral("\"");
2027         stringBuilder.append(domain);
2028         stringBuilder.appendLiteral("\"");
2029     }
2030     stringBuilder.appendLiteral("]");
2031     
2032     JSValueRef result = JSValueMakeFromJSONString(context, adopt(JSStringCreateWithUTF8CString(stringBuilder.toString().utf8().data())).get());
2033
2034     callTestRunnerCallback(AllStorageAccessEntriesCallbackID, 1, &result);
2035 }
2036
2037 void TestRunner::addMockMediaDevice(JSStringRef persistentId, JSStringRef label, const char* type)
2038 {
2039     Vector<WKRetainPtr<WKStringRef>> keys;
2040     Vector<WKRetainPtr<WKTypeRef>> values;
2041
2042     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("PersistentID") });
2043     values.append(toWK(persistentId));
2044
2045     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("Label") });
2046     values.append(toWK(label));
2047
2048     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("Type") });
2049     values.append({ AdoptWK, WKStringCreateWithUTF8CString(type) });
2050
2051     Vector<WKStringRef> rawKeys;
2052     Vector<WKTypeRef> rawValues;
2053     rawKeys.resize(keys.size());
2054     rawValues.resize(values.size());
2055
2056     for (size_t i = 0; i < keys.size(); ++i) {
2057         rawKeys[i] = keys[i].get();
2058         rawValues[i] = values[i].get();
2059     }
2060
2061     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("AddMockMediaDevice"));
2062     WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
2063
2064     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
2065 }
2066
2067 void TestRunner::addMockCameraDevice(JSStringRef persistentId, JSStringRef label)
2068 {
2069     addMockMediaDevice(persistentId, label, "camera");
2070 }
2071
2072 void TestRunner::addMockMicrophoneDevice(JSStringRef persistentId, JSStringRef label)
2073 {
2074     addMockMediaDevice(persistentId, label, "microphone");
2075 }
2076
2077 void TestRunner::addMockScreenDevice(JSStringRef persistentId, JSStringRef label)
2078 {
2079     addMockMediaDevice(persistentId, label, "screen");
2080 }
2081
2082 void TestRunner::clearMockMediaDevices()
2083 {
2084     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("ClearMockMediaDevices"));
2085     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), nullptr, nullptr);
2086 }
2087
2088 void TestRunner::removeMockMediaDevice(JSStringRef persistentId)
2089 {
2090     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("RemoveMockMediaDevice"));
2091     WKRetainPtr<WKTypeRef> messageBody(toWK(persistentId));
2092
2093     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
2094 }
2095
2096 void TestRunner::resetMockMediaDevices()
2097 {
2098     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("ResetMockMediaDevices"));
2099     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), nullptr, nullptr);
2100 }
2101
2102 #if PLATFORM(MAC)
2103 void TestRunner::connectMockGamepad(unsigned index)
2104 {
2105     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("ConnectMockGamepad"));
2106     WKRetainPtr<WKTypeRef> messageBody(AdoptWK, WKUInt64Create(index));
2107
2108     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
2109 }
2110
2111 void TestRunner::disconnectMockGamepad(unsigned index)
2112 {
2113     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("DisconnectMockGamepad"));
2114     WKRetainPtr<WKTypeRef> messageBody(AdoptWK, WKUInt64Create(index));
2115
2116     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
2117 }
2118
2119 void TestRunner::setMockGamepadDetails(unsigned index, JSStringRef gamepadID, unsigned axisCount, unsigned buttonCount)
2120 {
2121     Vector<WKRetainPtr<WKStringRef>> keys;
2122     Vector<WKRetainPtr<WKTypeRef>> values;
2123
2124     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("GamepadID") });
2125     values.append(toWK(gamepadID));
2126
2127     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("GamepadIndex") });
2128     values.append({ AdoptWK, WKUInt64Create(index) });
2129
2130     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("AxisCount") });
2131     values.append({ AdoptWK, WKUInt64Create(axisCount) });
2132
2133     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("ButtonCount") });
2134     values.append({ AdoptWK, WKUInt64Create(buttonCount) });
2135
2136     Vector<WKStringRef> rawKeys;
2137     Vector<WKTypeRef> rawValues;
2138     rawKeys.resize(keys.size());
2139     rawValues.resize(values.size());
2140
2141     for (size_t i = 0; i < keys.size(); ++i) {
2142         rawKeys[i] = keys[i].get();
2143         rawValues[i] = values[i].get();
2144     }
2145
2146     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetMockGamepadDetails"));
2147     WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
2148
2149     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
2150 }
2151
2152 void TestRunner::setMockGamepadAxisValue(unsigned index, unsigned axisIndex, double value)
2153 {
2154     Vector<WKRetainPtr<WKStringRef>> keys;
2155     Vector<WKRetainPtr<WKTypeRef>> values;
2156
2157     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("GamepadIndex") });
2158     values.append({ AdoptWK, WKUInt64Create(index) });
2159
2160     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("AxisIndex") });
2161     values.append({ AdoptWK, WKUInt64Create(axisIndex) });
2162
2163     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("Value") });
2164     values.append({ AdoptWK, WKDoubleCreate(value) });
2165
2166     Vector<WKStringRef> rawKeys;
2167     Vector<WKTypeRef> rawValues;
2168     rawKeys.resize(keys.size());
2169     rawValues.resize(values.size());
2170
2171     for (size_t i = 0; i < keys.size(); ++i) {
2172         rawKeys[i] = keys[i].get();
2173         rawValues[i] = values[i].get();
2174     }
2175
2176     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetMockGamepadAxisValue"));
2177     WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
2178
2179     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
2180 }
2181
2182 void TestRunner::setMockGamepadButtonValue(unsigned index, unsigned buttonIndex, double value)
2183 {
2184     Vector<WKRetainPtr<WKStringRef>> keys;
2185     Vector<WKRetainPtr<WKTypeRef>> values;
2186
2187     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("GamepadIndex") });
2188     values.append({ AdoptWK, WKUInt64Create(index) });
2189
2190     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("ButtonIndex") });
2191     values.append({ AdoptWK, WKUInt64Create(buttonIndex) });
2192
2193     keys.append({ AdoptWK, WKStringCreateWithUTF8CString("Value") });
2194     values.append({ AdoptWK, WKDoubleCreate(value) });
2195
2196     Vector<WKStringRef> rawKeys;
2197     Vector<WKTypeRef> rawValues;
2198     rawKeys.resize(keys.size());
2199     rawValues.resize(values.size());
2200
2201     for (size_t i = 0; i < keys.size(); ++i) {
2202         rawKeys[i] = keys[i].get();
2203         rawValues[i] = values[i].get();
2204     }
2205
2206     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetMockGamepadButtonValue"));
2207     WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
2208
2209     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
2210 }
2211 #else
2212 void TestRunner::connectMockGamepad(unsigned)
2213 {
2214 }
2215
2216 void TestRunner::disconnectMockGamepad(unsigned)
2217 {
2218 }
2219
2220 void TestRunner::setMockGamepadDetails(unsigned, JSStringRef, unsigned, unsigned)
2221 {
2222 }
2223
2224 void TestRunner::setMockGamepadAxisValue(unsigned, unsigned, double)
2225 {
2226 }
2227
2228 void TestRunner::setMockGamepadButtonValue(unsigned, unsigned, double)
2229 {
2230 }
2231 #endif // PLATFORM(MAC)
2232
2233 void TestRunner::setOpenPanelFiles(JSValueRef filesValue)
2234 {
2235     WKBundlePageRef page = InjectedBundle::singleton().page()->page();
2236     JSContextRef context = WKBundleFrameGetJavaScriptContext(WKBundlePageGetMainFrame(page));
2237
2238     if (!JSValueIsArray(context, filesValue))
2239         return;
2240
2241     JSObjectRef files = JSValueToObject(context, filesValue, nullptr);
2242     static auto lengthProperty = adopt(JSStringCreateWithUTF8CString("length"));
2243     JSValueRef filesLengthValue = JSObjectGetProperty(context, files, lengthProperty.get(), nullptr);
2244     if (!JSValueIsNumber(context, filesLengthValue))
2245         return;
2246
2247     auto fileURLs = adoptWK(WKMutableArrayCreate());
2248     auto filesLength = static_cast<size_t>(JSValueToNumber(context, filesLengthValue, nullptr));
2249     for (size_t i = 0; i < filesLength; ++i) {
2250         JSValueRef fileValue = JSObjectGetPropertyAtIndex(context, files, i, nullptr);
2251         if (!JSValueIsString(context, fileValue))
2252             continue;
2253
2254         auto file = adopt(JSValueToStringCopy(context, fileValue, nullptr));
2255         size_t fileBufferSize = JSStringGetMaximumUTF8CStringSize(file.get()) + 1;
2256         auto fileBuffer = std::make_unique<char[]>(fileBufferSize);
2257         JSStringGetUTF8CString(file.get(), fileBuffer.get(), fileBufferSize);
2258
2259         WKArrayAppendItem(fileURLs.get(), adoptWK(WKURLCreateWithBaseURL(m_testURL.get(), fileBuffer.get())).get());
2260     }
2261
2262     static auto messageName = adoptWK(WKStringCreateWithUTF8CString("SetOpenPanelFileURLs"));
2263     WKBundlePagePostMessage(page, messageName.get(), fileURLs.get());
2264 }
2265
2266 void TestRunner::removeAllSessionCredentials(JSValueRef callback)
2267 {
2268     cacheTestRunnerCallback(DidRemoveAllSessionCredentialsCallbackID, callback);
2269     
2270     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("RemoveAllSessionCredentials"));
2271     WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(true));
2272     
2273     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
2274 }
2275
2276 void TestRunner::callDidRemoveAllSessionCredentialsCallback()
2277 {
2278     callTestRunnerCallback(DidRemoveAllSessionCredentialsCallbackID);
2279 }
2280
2281 void TestRunner::clearDOMCache(JSStringRef origin)
2282 {
2283     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("ClearDOMCache"));
2284     WKRetainPtr<WKStringRef> messageBody(AdoptWK, WKStringCreateWithJSString(origin));
2285     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
2286 }
2287
2288 void TestRunner::clearDOMCaches()
2289 {
2290     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("ClearDOMCaches"));
2291     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), nullptr, nullptr);
2292 }
2293
2294 bool TestRunner::hasDOMCache(JSStringRef origin)
2295 {
2296     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("HasDOMCache"));
2297     WKRetainPtr<WKStringRef> messageBody(AdoptWK, WKStringCreateWithJSString(origin));
2298     WKTypeRef returnData = 0;
2299     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get(), &returnData);
2300     return WKBooleanGetValue(static_cast<WKBooleanRef>(returnData));
2301 }
2302
2303 uint64_t TestRunner::domCacheSize(JSStringRef origin)
2304 {
2305     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("DOMCacheSize"));
2306     WKRetainPtr<WKStringRef> messageBody(AdoptWK, WKStringCreateWithJSString(origin));
2307     WKTypeRef returnData = 0;
2308     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get(), &returnData);
2309     return WKUInt64GetValue(static_cast<WKUInt64Ref>(returnData));
2310 }
2311
2312 void TestRunner::getApplicationManifestThen(JSValueRef callback)
2313 {
2314     cacheTestRunnerCallback(GetApplicationManifestCallbackID, callback);
2315     
2316     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("GetApplicationManifest"));
2317     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), nullptr, nullptr);
2318 }
2319
2320 void TestRunner::didGetApplicationManifest()
2321 {
2322     callTestRunnerCallback(GetApplicationManifestCallbackID);
2323 }
2324
2325 size_t TestRunner::userScriptInjectedCount() const
2326 {
2327     return InjectedBundle::singleton().userScriptInjectedCount();
2328 }
2329
2330 void TestRunner::injectUserScript(JSStringRef script)
2331 {
2332     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("InjectUserScript"));
2333     WKRetainPtr<WKStringRef> messageBody(AdoptWK, WKStringCreateWithJSString(script));
2334     WKTypeRef returnData = 0;
2335     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get(), &returnData);
2336 }
2337
2338 void TestRunner::sendDisplayConfigurationChangedMessageForTesting()
2339 {
2340     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SendDisplayConfigurationChangedMessageForTesting"));
2341     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), nullptr, nullptr);
2342 }
2343
2344 } // namespace WTR