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