[CSSOM View] Handle the scrollingElement in Element::scroll(Left/Top/Width/Height/To)
[WebKit-https.git] / Tools / WebKitTestRunner / TestController.cpp
1 /*
2  * Copyright (C) 2010-2018 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 "TestController.h"
28
29 #include "EventSenderProxy.h"
30 #include "Options.h"
31 #include "PlatformWebView.h"
32 #include "StringFunctions.h"
33 #include "TestInvocation.h"
34 #include "WebCoreTestSupport.h"
35 #include <JavaScriptCore/InitializeThreading.h>
36 #include <WebKit/WKArray.h>
37 #include <WebKit/WKAuthenticationChallenge.h>
38 #include <WebKit/WKAuthenticationDecisionListener.h>
39 #include <WebKit/WKContextConfigurationRef.h>
40 #include <WebKit/WKContextPrivate.h>
41 #include <WebKit/WKCookieManager.h>
42 #include <WebKit/WKCredential.h>
43 #include <WebKit/WKFrameHandleRef.h>
44 #include <WebKit/WKFrameInfoRef.h>
45 #include <WebKit/WKIconDatabase.h>
46 #include <WebKit/WKMockDisplay.h>
47 #include <WebKit/WKMockMediaDevice.h>
48 #include <WebKit/WKNavigationResponseRef.h>
49 #include <WebKit/WKNotification.h>
50 #include <WebKit/WKNotificationManager.h>
51 #include <WebKit/WKNotificationPermissionRequest.h>
52 #include <WebKit/WKNumber.h>
53 #include <WebKit/WKOpenPanelResultListener.h>
54 #include <WebKit/WKPageGroup.h>
55 #include <WebKit/WKPageInjectedBundleClient.h>
56 #include <WebKit/WKPagePrivate.h>
57 #include <WebKit/WKPluginInformation.h>
58 #include <WebKit/WKPreferencesRefPrivate.h>
59 #include <WebKit/WKProtectionSpace.h>
60 #include <WebKit/WKRetainPtr.h>
61 #include <WebKit/WKSecurityOriginRef.h>
62 #include <WebKit/WKTextChecker.h>
63 #include <WebKit/WKUserMediaPermissionCheck.h>
64 #include <WebKit/WKWebsiteDataStoreRef.h>
65 #include <algorithm>
66 #include <cstdio>
67 #include <ctype.h>
68 #include <fstream>
69 #include <stdlib.h>
70 #include <string>
71 #include <unistd.h>
72 #include <wtf/AutodrainedPool.h>
73 #include <wtf/CryptographicallyRandomNumber.h>
74 #include <wtf/HexNumber.h>
75 #include <wtf/MainThread.h>
76 #include <wtf/ProcessPrivilege.h>
77 #include <wtf/RefCounted.h>
78 #include <wtf/RunLoop.h>
79 #include <wtf/SetForScope.h>
80 #include <wtf/UUID.h>
81 #include <wtf/text/CString.h>
82 #include <wtf/text/WTFString.h>
83
84 #if PLATFORM(COCOA)
85 #include <WebKit/WKContextPrivateMac.h>
86 #include <WebKit/WKPagePrivateMac.h>
87 #endif
88
89 namespace WTR {
90
91 const unsigned TestController::viewWidth = 800;
92 const unsigned TestController::viewHeight = 600;
93
94 const unsigned TestController::w3cSVGViewWidth = 480;
95 const unsigned TestController::w3cSVGViewHeight = 360;
96
97 const WTF::Seconds TestController::defaultShortTimeout = 5_s;
98 const WTF::Seconds TestController::noTimeout = -1_s;
99
100 static WKURLRef blankURL()
101 {
102     static WKURLRef staticBlankURL = WKURLCreateWithUTF8CString("about:blank");
103     return staticBlankURL;
104 }
105
106 static WKDataRef copyWebCryptoMasterKey(WKPageRef, const void*)
107 {
108     // Any 128 bit key would do, all we need for testing is to implement the callback.
109     return WKDataCreate((const uint8_t*)"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", 16);
110 }
111
112 static WKStringRef copySignedPublicKeyAndChallengeString(WKPageRef, const void*)
113 {
114     // Any fake response would do, all we need for testing is to implement the callback.
115     return WKStringCreateWithUTF8CString("MIHFMHEwXDANBgkqhkiG9w0BAQEFAANLADBIAkEAnX0TILJrOMUue%2BPtwBRE6XfV%0AWtKQbsshxk5ZhcUwcwyvcnIq9b82QhJdoACdD34rqfCAIND46fXKQUnb0mvKzQID%0AAQABFhFNb3ppbGxhSXNNeUZyaWVuZDANBgkqhkiG9w0BAQQFAANBAAKv2Eex2n%2FS%0Ar%2F7iJNroWlSzSMtTiQTEB%2BADWHGj9u1xrUrOilq%2Fo2cuQxIfZcNZkYAkWP4DubqW%0Ai0%2F%2FrgBvmco%3D");
116 }
117
118 AsyncTask* AsyncTask::m_currentTask;
119
120 bool AsyncTask::run()
121 {
122     m_currentTask = this;
123     m_task();
124     TestController::singleton().runUntil(m_taskDone, m_timeout);
125     m_currentTask = nullptr;
126     return m_taskDone;
127 }
128
129 AsyncTask* AsyncTask::currentTask()
130 {
131     return m_currentTask;
132 }
133
134 static TestController* controller;
135
136 TestController& TestController::singleton()
137 {
138     ASSERT(controller);
139     return *controller;
140 }
141
142 TestController::TestController(int argc, const char* argv[])
143 {
144     initialize(argc, argv);
145     controller = this;
146     run();
147     controller = nullptr;
148 }
149
150 TestController::~TestController()
151 {
152     // The context will be null if WebKitTestRunner was in server mode, but ran no tests.
153     if (m_context)
154         WKIconDatabaseClose(WKContextGetIconDatabase(m_context.get()));
155
156     platformDestroy();
157 }
158
159 static WKRect getWindowFrame(WKPageRef page, const void* clientInfo)
160 {
161     PlatformWebView* view = static_cast<PlatformWebView*>(const_cast<void*>(clientInfo));
162     return view->windowFrame();
163 }
164
165 static void setWindowFrame(WKPageRef page, WKRect frame, const void* clientInfo)
166 {
167     PlatformWebView* view = static_cast<PlatformWebView*>(const_cast<void*>(clientInfo));
168     view->setWindowFrame(frame);
169 }
170
171 static bool runBeforeUnloadConfirmPanel(WKPageRef page, WKStringRef message, WKFrameRef frame, const void*)
172 {
173     printf("CONFIRM NAVIGATION: %s\n", toSTD(message).c_str());
174     return TestController::singleton().beforeUnloadReturnValue();
175 }
176
177 static void runOpenPanel(WKPageRef page, WKFrameRef frame, WKOpenPanelParametersRef parameters, WKOpenPanelResultListenerRef resultListenerRef, const void*)
178 {
179     printf("OPEN FILE PANEL\n");
180     if (WKOpenPanelParametersGetAllowsDirectories(parameters))
181         printf("-> DIRECTORIES ARE ALLOWED\n");
182     WKArrayRef fileURLs = TestController::singleton().openPanelFileURLs();
183     if (!fileURLs || !WKArrayGetSize(fileURLs)) {
184         WKOpenPanelResultListenerCancel(resultListenerRef);
185         return;
186     }
187
188     if (WKOpenPanelParametersGetAllowsMultipleFiles(parameters)) {
189         WKOpenPanelResultListenerChooseFiles(resultListenerRef, fileURLs);
190         return;
191     }
192
193     WKTypeRef firstItem = WKArrayGetItemAtIndex(fileURLs, 0);
194     WKOpenPanelResultListenerChooseFiles(resultListenerRef, adoptWK(WKArrayCreate(&firstItem, 1)).get());
195 }
196
197 void TestController::runModal(WKPageRef page, const void* clientInfo)
198 {
199     PlatformWebView* view = static_cast<PlatformWebView*>(const_cast<void*>(clientInfo));
200     view->setWindowIsKey(false);
201     runModal(view);
202     view->setWindowIsKey(true);
203 }
204
205 static void closeOtherPage(WKPageRef page, const void* clientInfo)
206 {
207     WKPageClose(page);
208     PlatformWebView* view = static_cast<PlatformWebView*>(const_cast<void*>(clientInfo));
209     delete view;
210 }
211
212 static void focus(WKPageRef page, const void* clientInfo)
213 {
214     PlatformWebView* view = static_cast<PlatformWebView*>(const_cast<void*>(clientInfo));
215     view->focus();
216     view->setWindowIsKey(true);
217 }
218
219 static void unfocus(WKPageRef page, const void* clientInfo)
220 {
221     PlatformWebView* view = static_cast<PlatformWebView*>(const_cast<void*>(clientInfo));
222     view->setWindowIsKey(false);
223 }
224
225 static void decidePolicyForGeolocationPermissionRequest(WKPageRef, WKFrameRef, WKSecurityOriginRef, WKGeolocationPermissionRequestRef permissionRequest, const void* clientInfo)
226 {
227     TestController::singleton().handleGeolocationPermissionRequest(permissionRequest);
228 }
229
230 static void decidePolicyForUserMediaPermissionRequest(WKPageRef, WKFrameRef frame, WKSecurityOriginRef userMediaDocumentOrigin, WKSecurityOriginRef topLevelDocumentOrigin, WKUserMediaPermissionRequestRef permissionRequest, const void* clientInfo)
231 {
232     TestController::singleton().handleUserMediaPermissionRequest(frame, userMediaDocumentOrigin, topLevelDocumentOrigin, permissionRequest);
233 }
234
235 static void checkUserMediaPermissionForOrigin(WKPageRef, WKFrameRef frame, WKSecurityOriginRef userMediaDocumentOrigin, WKSecurityOriginRef topLevelDocumentOrigin, WKUserMediaPermissionCheckRef checkRequest, const void*)
236 {
237     TestController::singleton().handleCheckOfUserMediaPermissionForOrigin(frame, userMediaDocumentOrigin, topLevelDocumentOrigin, checkRequest);
238 }
239
240 static void requestPointerLock(WKPageRef page, const void*)
241 {
242     WKPageDidAllowPointerLock(page);
243 }
244
245 WKPageRef TestController::createOtherPage(WKPageRef oldPage, WKPageConfigurationRef configuration, WKNavigationActionRef navigationAction, WKWindowFeaturesRef windowFeatures, const void *clientInfo)
246 {
247     PlatformWebView* parentView = static_cast<PlatformWebView*>(const_cast<void*>(clientInfo));
248
249     PlatformWebView* view = platformCreateOtherPage(parentView, configuration, parentView->options());
250     WKPageRef newPage = view->page();
251
252     view->resizeTo(800, 600);
253
254     WKPageUIClientV8 otherPageUIClient = {
255         { 8, view },
256         0, // createNewPage_deprecatedForUseWithV0
257         0, // showPage
258         closeOtherPage,
259         0, // takeFocus
260         focus,
261         unfocus,
262         0, // runJavaScriptAlert_deprecatedForUseWithV0
263         0, // runJavaScriptAlert_deprecatedForUseWithV0
264         0, // runJavaScriptAlert_deprecatedForUseWithV0
265         0, // setStatusText
266         0, // mouseDidMoveOverElement_deprecatedForUseWithV0
267         0, // missingPluginButtonClicked
268         0, // didNotHandleKeyEvent
269         0, // didNotHandleWheelEvent
270         0, // toolbarsAreVisible
271         0, // setToolbarsAreVisible
272         0, // menuBarIsVisible
273         0, // setMenuBarIsVisible
274         0, // statusBarIsVisible
275         0, // setStatusBarIsVisible
276         0, // isResizable
277         0, // setIsResizable
278         getWindowFrame,
279         setWindowFrame,
280         runBeforeUnloadConfirmPanel,
281         0, // didDraw
282         0, // pageDidScroll
283         0, // exceededDatabaseQuota
284         runOpenPanel,
285         decidePolicyForGeolocationPermissionRequest,
286         0, // headerHeight
287         0, // footerHeight
288         0, // drawHeader
289         0, // drawFooter
290         0, // printFrame
291         runModal,
292         0, // didCompleteRubberBandForMainFrame
293         0, // saveDataToFileInDownloadsFolder
294         0, // shouldInterruptJavaScript
295         0, // createNewPage_deprecatedForUseWithV1
296         0, // mouseDidMoveOverElement
297         0, // decidePolicyForNotificationPermissionRequest
298         0, // unavailablePluginButtonClicked_deprecatedForUseWithV1
299         0, // showColorPicker
300         0, // hideColorPicker
301         0, // unavailablePluginButtonClicked
302         0, // pinnedStateDidChange
303         0, // didBeginTrackingPotentialLongMousePress
304         0, // didRecognizeLongMousePress
305         0, // didCancelTrackingPotentialLongMousePress
306         0, // isPlayingAudioDidChange
307         decidePolicyForUserMediaPermissionRequest,
308         0, // didClickAutofillButton
309         0, // runJavaScriptAlert
310         0, // runJavaScriptConfirm
311         0, // runJavaScriptPrompt
312         0, // mediaSessionMetadataDidChange
313         createOtherPage,
314         0, // runJavaScriptAlert
315         0, // runJavaScriptConfirm
316         0, // runJavaScriptPrompt
317         checkUserMediaPermissionForOrigin,
318         0, // runBeforeUnloadConfirmPanel
319         0, // fullscreenMayReturnToInline
320         requestPointerLock,
321         0,
322     };
323     WKPageSetPageUIClient(newPage, &otherPageUIClient.base);
324     
325     WKPageNavigationClientV3 pageNavigationClient = {
326         { 3, &TestController::singleton() },
327         decidePolicyForNavigationAction,
328         decidePolicyForNavigationResponse,
329         decidePolicyForPluginLoad,
330         0, // didStartProvisionalNavigation
331         didReceiveServerRedirectForProvisionalNavigation,
332         0, // didFailProvisionalNavigation
333         0, // didCommitNavigation
334         0, // didFinishNavigation
335         0, // didFailNavigation
336         0, // didFailProvisionalLoadInSubframe
337         0, // didFinishDocumentLoad
338         0, // didSameDocumentNavigation
339         0, // renderingProgressDidChange
340         canAuthenticateAgainstProtectionSpace,
341         didReceiveAuthenticationChallenge,
342         processDidCrash,
343         copyWebCryptoMasterKey,
344         didBeginNavigationGesture,
345         willEndNavigationGesture,
346         didEndNavigationGesture,
347         didRemoveNavigationGestureSnapshot,
348         0, // webProcessDidTerminate
349         0, // contentRuleListNotification
350         copySignedPublicKeyAndChallengeString
351     };
352     WKPageSetPageNavigationClient(newPage, &pageNavigationClient.base);
353
354     view->didInitializeClients();
355
356     TestController::singleton().updateWindowScaleForTest(view, *TestController::singleton().m_currentInvocation);
357
358     WKRetain(newPage);
359     return newPage;
360 }
361
362 const char* TestController::libraryPathForTesting()
363 {
364     // FIXME: This may not be sufficient to prevent interactions/crashes
365     // when running more than one copy of DumpRenderTree.
366     // See https://bugs.webkit.org/show_bug.cgi?id=10906
367     char* dumpRenderTreeTemp = getenv("DUMPRENDERTREE_TEMP");
368     if (dumpRenderTreeTemp)
369         return dumpRenderTreeTemp;
370     return platformLibraryPathForTesting();
371 }
372
373 void TestController::initialize(int argc, const char* argv[])
374 {
375     JSC::initializeThreading();
376     RunLoop::initializeMainRunLoop();
377     WTF::setProcessPrivileges(allPrivileges());
378
379     platformInitialize();
380
381     Options options;
382     OptionsHandler optionsHandler(options);
383
384     if (argc < 2) {
385         optionsHandler.printHelp();
386         exit(1);
387     }
388     if (!optionsHandler.parse(argc, argv))
389         exit(1);
390
391     m_useWaitToDumpWatchdogTimer = options.useWaitToDumpWatchdogTimer;
392     m_forceNoTimeout = options.forceNoTimeout;
393     m_verbose = options.verbose;
394     m_gcBetweenTests = options.gcBetweenTests;
395     m_shouldDumpPixelsForAllTests = options.shouldDumpPixelsForAllTests;
396     m_forceComplexText = options.forceComplexText;
397     m_shouldUseAcceleratedDrawing = options.shouldUseAcceleratedDrawing;
398     m_shouldUseRemoteLayerTree = options.shouldUseRemoteLayerTree;
399     m_paths = options.paths;
400     m_allowedHosts = options.allowedHosts;
401     m_shouldShowWebView = options.shouldShowWebView;
402     m_shouldShowTouches = options.shouldShowTouches;
403     m_checkForWorldLeaks = options.checkForWorldLeaks;
404     m_allowAnyHTTPSCertificateForAllowedHosts = options.allowAnyHTTPSCertificateForAllowedHosts;
405
406     if (options.printSupportedFeatures) {
407         // FIXME: On Windows, DumpRenderTree uses this to expose whether it supports 3d
408         // transforms and accelerated compositing. When we support those features, we
409         // should match DRT's behavior.
410         exit(0);
411     }
412
413     m_usingServerMode = (m_paths.size() == 1 && m_paths[0] == "-");
414     if (m_usingServerMode)
415         m_printSeparators = true;
416     else
417         m_printSeparators = m_paths.size() > 1;
418
419     initializeInjectedBundlePath();
420     initializeTestPluginDirectory();
421
422 #if PLATFORM(MAC)
423     WebCoreTestSupport::installMockGamepadProvider();
424 #endif
425
426     WKRetainPtr<WKStringRef> pageGroupIdentifier(AdoptWK, WKStringCreateWithUTF8CString("WebKitTestRunnerPageGroup"));
427     m_pageGroup.adopt(WKPageGroupCreateWithIdentifier(pageGroupIdentifier.get()));
428 }
429
430 WKRetainPtr<WKContextConfigurationRef> TestController::generateContextConfiguration() const
431 {
432     auto configuration = adoptWK(WKContextConfigurationCreate());
433     WKContextConfigurationSetInjectedBundlePath(configuration.get(), injectedBundlePath());
434     WKContextConfigurationSetFullySynchronousModeIsAllowedForTesting(configuration.get(), true);
435
436     if (const char* dumpRenderTreeTemp = libraryPathForTesting()) {
437         String temporaryFolder = String::fromUTF8(dumpRenderTreeTemp);
438
439         const char separator = '/';
440
441         WKContextConfigurationSetApplicationCacheDirectory(configuration.get(), toWK(temporaryFolder + separator + "ApplicationCache").get());
442         WKContextConfigurationSetDiskCacheDirectory(configuration.get(), toWK(temporaryFolder + separator + "Cache").get());
443         WKContextConfigurationSetIndexedDBDatabaseDirectory(configuration.get(), toWK(temporaryFolder + separator + "Databases" + separator + "IndexedDB").get());
444         WKContextConfigurationSetLocalStorageDirectory(configuration.get(), toWK(temporaryFolder + separator + "LocalStorage").get());
445         WKContextConfigurationSetWebSQLDatabaseDirectory(configuration.get(), toWK(temporaryFolder + separator + "Databases" + separator + "WebSQL").get());
446         WKContextConfigurationSetMediaKeysStorageDirectory(configuration.get(), toWK(temporaryFolder + separator + "MediaKeys").get());
447         WKContextConfigurationSetResourceLoadStatisticsDirectory(configuration.get(), toWK(temporaryFolder + separator + "ResourceLoadStatistics").get());
448     }
449     return configuration;
450 }
451
452 WKRetainPtr<WKPageConfigurationRef> TestController::generatePageConfiguration(WKContextConfigurationRef configuration)
453 {
454     m_context = platformAdjustContext(adoptWK(WKContextCreateWithConfiguration(configuration)).get(), configuration);
455
456     m_geolocationProvider = std::make_unique<GeolocationProviderMock>(m_context.get());
457
458     if (const char* dumpRenderTreeTemp = libraryPathForTesting()) {
459         String temporaryFolder = String::fromUTF8(dumpRenderTreeTemp);
460
461         // FIXME: This should be migrated to WKContextConfigurationRef.
462         // Disable icon database to avoid fetching <http://127.0.0.1:8000/favicon.ico> and making tests flaky.
463         // Invividual tests can enable it using testRunner.setIconDatabaseEnabled, although it's not currently supported in WebKitTestRunner.
464         WKContextSetIconDatabasePath(m_context.get(), toWK(emptyString()).get());
465     }
466
467     WKContextSetDiskCacheSpeculativeValidationEnabled(m_context.get(), true);
468     WKContextUseTestingNetworkSession(m_context.get());
469     WKContextSetCacheModel(m_context.get(), kWKCacheModelDocumentBrowser);
470
471     platformInitializeContext();
472
473     WKContextInjectedBundleClientV1 injectedBundleClient = {
474         { 1, this },
475         didReceiveMessageFromInjectedBundle,
476         didReceiveSynchronousMessageFromInjectedBundle,
477         getInjectedBundleInitializationUserData,
478     };
479     WKContextSetInjectedBundleClient(m_context.get(), &injectedBundleClient.base);
480
481     WKContextClientV2 contextClient = {
482         { 2, this },
483         0, // plugInAutoStartOriginHashesChanged
484         networkProcessDidCrash,
485         0, // plugInInformationBecameAvailable
486         0, // copyWebCryptoMasterKey
487         databaseProcessDidCrash,
488     };
489     WKContextSetClient(m_context.get(), &contextClient.base);
490
491     WKContextHistoryClientV0 historyClient = {
492         { 0, this },
493         didNavigateWithNavigationData,
494         didPerformClientRedirect,
495         didPerformServerRedirect,
496         didUpdateHistoryTitle,
497         0, // populateVisitedLinks
498     };
499     WKContextSetHistoryClient(m_context.get(), &historyClient.base);
500
501     WKNotificationManagerRef notificationManager = WKContextGetNotificationManager(m_context.get());
502     WKNotificationProviderV0 notificationKit = m_webNotificationProvider.provider();
503     WKNotificationManagerSetProvider(notificationManager, &notificationKit.base);
504
505     if (testPluginDirectory())
506         WKContextSetAdditionalPluginsDirectory(m_context.get(), testPluginDirectory());
507
508     if (m_forceComplexText)
509         WKContextSetAlwaysUsesComplexTextCodePath(m_context.get(), true);
510
511     auto pageConfiguration = adoptWK(WKPageConfigurationCreate());
512     WKPageConfigurationSetContext(pageConfiguration.get(), m_context.get());
513     WKPageConfigurationSetPageGroup(pageConfiguration.get(), m_pageGroup.get());
514     WKPageConfigurationSetUserContentController(pageConfiguration.get(), adoptWK(WKUserContentControllerCreate()).get());
515     return pageConfiguration;
516 }
517
518 void TestController::createWebViewWithOptions(const TestOptions& options)
519 {
520     auto contextConfiguration = generateContextConfiguration();
521
522     WKRetainPtr<WKMutableArrayRef> overrideLanguages = adoptWK(WKMutableArrayCreate());
523     for (auto& language : options.overrideLanguages)
524         WKArrayAppendItem(overrideLanguages.get(), adoptWK(WKStringCreateWithUTF8CString(language.utf8().data())).get());
525     WKContextConfigurationSetOverrideLanguages(contextConfiguration.get(), overrideLanguages.get());
526
527     if (options.shouldEnableProcessSwapOnNavigation()) {
528         WKContextConfigurationSetProcessSwapsOnNavigation(contextConfiguration.get(), true);
529         if (options.enableProcessSwapOnWindowOpen)
530             WKContextConfigurationSetProcessSwapsOnWindowOpenWithOpener(contextConfiguration.get(), true);
531     }
532
533     auto configuration = generatePageConfiguration(contextConfiguration.get());
534
535     // Some preferences (notably mock scroll bars setting) currently cannot be re-applied to an existing view, so we need to set them now.
536     // FIXME: Migrate these preferences to WKContextConfigurationRef.
537     resetPreferencesToConsistentValues(options);
538
539     platformCreateWebView(configuration.get(), options);
540     WKPageUIClientV8 pageUIClient = {
541         { 8, m_mainWebView.get() },
542         0, // createNewPage_deprecatedForUseWithV0
543         0, // showPage
544         0, // close
545         0, // takeFocus
546         focus,
547         unfocus,
548         0, // runJavaScriptAlert_deprecatedForUseWithV0
549         0, // runJavaScriptAlert_deprecatedForUseWithV0
550         0, // runJavaScriptAlert_deprecatedForUseWithV0
551         0, // setStatusText
552         0, // mouseDidMoveOverElement_deprecatedForUseWithV0
553         0, // missingPluginButtonClicked
554         0, // didNotHandleKeyEvent
555         0, // didNotHandleWheelEvent
556         0, // toolbarsAreVisible
557         0, // setToolbarsAreVisible
558         0, // menuBarIsVisible
559         0, // setMenuBarIsVisible
560         0, // statusBarIsVisible
561         0, // setStatusBarIsVisible
562         0, // isResizable
563         0, // setIsResizable
564         getWindowFrame,
565         setWindowFrame,
566         runBeforeUnloadConfirmPanel,
567         0, // didDraw
568         0, // pageDidScroll
569         0, // exceededDatabaseQuota,
570         runOpenPanel,
571         decidePolicyForGeolocationPermissionRequest,
572         0, // headerHeight
573         0, // footerHeight
574         0, // drawHeader
575         0, // drawFooter
576         0, // printFrame
577         runModal,
578         0, // didCompleteRubberBandForMainFrame
579         0, // saveDataToFileInDownloadsFolder
580         0, // shouldInterruptJavaScript
581         0, // createNewPage_deprecatedForUseWithV1
582         0, // mouseDidMoveOverElement
583         decidePolicyForNotificationPermissionRequest, // decidePolicyForNotificationPermissionRequest
584         0, // unavailablePluginButtonClicked_deprecatedForUseWithV1
585         0, // showColorPicker
586         0, // hideColorPicker
587         unavailablePluginButtonClicked,
588         0, // pinnedStateDidChange
589         0, // didBeginTrackingPotentialLongMousePress
590         0, // didRecognizeLongMousePress
591         0, // didCancelTrackingPotentialLongMousePress
592         0, // isPlayingAudioDidChange
593         decidePolicyForUserMediaPermissionRequest,
594         0, // didClickAutofillButton
595         0, // runJavaScriptAlert
596         0, // runJavaScriptConfirm
597         0, // runJavaScriptPrompt
598         0, // mediaSessionMetadataDidChange
599         createOtherPage,
600         0, // runJavaScriptAlert
601         0, // runJavaScriptConfirm
602         0, // runJavaScriptPrompt
603         checkUserMediaPermissionForOrigin,
604         0, // runBeforeUnloadConfirmPanel
605         0, // fullscreenMayReturnToInline
606         requestPointerLock,
607         0,
608     };
609     WKPageSetPageUIClient(m_mainWebView->page(), &pageUIClient.base);
610
611     WKPageNavigationClientV3 pageNavigationClient = {
612         { 3, this },
613         decidePolicyForNavigationAction,
614         decidePolicyForNavigationResponse,
615         decidePolicyForPluginLoad,
616         0, // didStartProvisionalNavigation
617         didReceiveServerRedirectForProvisionalNavigation,
618         0, // didFailProvisionalNavigation
619         didCommitNavigation,
620         didFinishNavigation,
621         0, // didFailNavigation
622         0, // didFailProvisionalLoadInSubframe
623         0, // didFinishDocumentLoad
624         0, // didSameDocumentNavigation
625         0, // renderingProgressDidChange
626         canAuthenticateAgainstProtectionSpace,
627         didReceiveAuthenticationChallenge,
628         processDidCrash,
629         copyWebCryptoMasterKey,
630         didBeginNavigationGesture,
631         willEndNavigationGesture,
632         didEndNavigationGesture,
633         didRemoveNavigationGestureSnapshot,
634         0, // webProcessDidTerminate
635         0, // contentRuleListNotification
636         copySignedPublicKeyAndChallengeString
637     };
638     WKPageSetPageNavigationClient(m_mainWebView->page(), &pageNavigationClient.base);
639
640     WKContextDownloadClientV1 downloadClient = {
641         { 1, this },
642         downloadDidStart,
643         0, // didReceiveAuthenticationChallenge
644         0, // didReceiveResponse
645         0, // didReceiveData
646         0, // shouldDecodeSourceDataOfMIMEType
647         decideDestinationWithSuggestedFilename,
648         0, // didCreateDestination
649         downloadDidFinish,
650         downloadDidFail,
651         downloadDidCancel,
652         0, // processDidCrash;
653         downloadDidReceiveServerRedirectToURL
654     };
655     WKContextSetDownloadClient(context(), &downloadClient.base);
656     
657     // this should just be done on the page?
658     WKPageInjectedBundleClientV0 injectedBundleClient = {
659         { 0, this },
660         didReceivePageMessageFromInjectedBundle,
661         didReceiveSynchronousPageMessageFromInjectedBundle
662     };
663     WKPageSetPageInjectedBundleClient(m_mainWebView->page(), &injectedBundleClient.base);
664
665     m_mainWebView->didInitializeClients();
666
667     // Generally, the tests should default to running at 1x. updateWindowScaleForTest() will adjust the scale to
668     // something else for specific tests that need to run at a different window scale.
669     m_mainWebView->changeWindowScaleIfNeeded(1);
670 }
671
672 void TestController::ensureViewSupportsOptionsForTest(const TestInvocation& test)
673 {
674     auto options = test.options();
675
676     if (m_mainWebView) {
677         if (m_mainWebView->viewSupportsOptions(options))
678             return;
679
680         willDestroyWebView();
681
682         WKPageSetPageUIClient(m_mainWebView->page(), nullptr);
683         WKPageSetPageNavigationClient(m_mainWebView->page(), nullptr);
684         WKPageClose(m_mainWebView->page());
685
686         m_mainWebView = nullptr;
687     }
688
689     createWebViewWithOptions(options);
690
691     if (!resetStateToConsistentValues(options, ResetStage::BeforeTest))
692         TestInvocation::dumpWebProcessUnresponsiveness("<unknown> - TestController::run - Failed to reset state to consistent values\n");
693 }
694
695 void TestController::resetPreferencesToConsistentValues(const TestOptions& options)
696 {
697     // Reset preferences
698     WKPreferencesRef preferences = platformPreferences();
699     WKPreferencesResetTestRunnerOverrides(preferences);
700     WKPreferencesEnableAllExperimentalFeatures(preferences);
701     WKPreferencesSetProcessSwapOnNavigationEnabled(preferences, options.shouldEnableProcessSwapOnNavigation());
702     WKPreferencesSetPageVisibilityBasedProcessSuppressionEnabled(preferences, false);
703     WKPreferencesSetOfflineWebApplicationCacheEnabled(preferences, true);
704     WKPreferencesSetFontSmoothingLevel(preferences, kWKFontSmoothingLevelNoSubpixelAntiAliasing);
705     WKPreferencesSetSubpixelAntialiasedLayerTextEnabled(preferences, false);
706     WKPreferencesSetXSSAuditorEnabled(preferences, false);
707     WKPreferencesSetWebAudioEnabled(preferences, true);
708     WKPreferencesSetMediaDevicesEnabled(preferences, true);
709     WKPreferencesSetWebRTCMDNSICECandidatesEnabled(preferences, false);
710     WKPreferencesSetDeveloperExtrasEnabled(preferences, true);
711     WKPreferencesSetJavaScriptRuntimeFlags(preferences, kWKJavaScriptRuntimeFlagsAllEnabled);
712     WKPreferencesSetJavaScriptCanOpenWindowsAutomatically(preferences, true);
713     WKPreferencesSetJavaScriptCanAccessClipboard(preferences, true);
714     WKPreferencesSetDOMPasteAllowed(preferences, true);
715     WKPreferencesSetUniversalAccessFromFileURLsAllowed(preferences, true);
716     WKPreferencesSetFileAccessFromFileURLsAllowed(preferences, true);
717 #if ENABLE(FULLSCREEN_API)
718     WKPreferencesSetFullScreenEnabled(preferences, true);
719 #endif
720     WKPreferencesSetPageCacheEnabled(preferences, false);
721     WKPreferencesSetAsynchronousPluginInitializationEnabled(preferences, false);
722     WKPreferencesSetAsynchronousPluginInitializationEnabledForAllPlugins(preferences, false);
723     WKPreferencesSetArtificialPluginInitializationDelayEnabled(preferences, false);
724     WKPreferencesSetTabToLinksEnabled(preferences, false);
725     WKPreferencesSetInteractiveFormValidationEnabled(preferences, true);
726     WKPreferencesSetDataTransferItemsEnabled(preferences, true);
727     WKPreferencesSetCustomPasteboardDataEnabled(preferences, true);
728
729     WKPreferencesSetMockScrollbarsEnabled(preferences, options.useMockScrollbars);
730     WKPreferencesSetNeedsSiteSpecificQuirks(preferences, options.needsSiteSpecificQuirks);
731     WKPreferencesSetAttachmentElementEnabled(preferences, options.enableAttachmentElement);
732     WKPreferencesSetMenuItemElementEnabled(preferences, options.enableMenuItemElement);
733     WKPreferencesSetModernMediaControlsEnabled(preferences, options.enableModernMediaControls);
734     WKPreferencesSetWebAuthenticationEnabled(preferences, options.enableWebAuthentication);
735     WKPreferencesSetIsSecureContextAttributeEnabled(preferences, options.enableIsSecureContextAttribute);
736     WKPreferencesSetAllowCrossOriginSubresourcesToAskForCredentials(preferences, options.allowCrossOriginSubresourcesToAskForCredentials);
737     WKPreferencesSetWebAnimationsCSSIntegrationEnabled(preferences, options.enableWebAnimationsCSSIntegration);
738     WKPreferencesSetColorFilterEnabled(preferences, options.enableColorFilter);
739     WKPreferencesSetPunchOutWhiteBackgroundsInDarkMode(preferences, options.punchOutWhiteBackgroundsInDarkMode);
740
741     static WKStringRef defaultTextEncoding = WKStringCreateWithUTF8CString("ISO-8859-1");
742     WKPreferencesSetDefaultTextEncodingName(preferences, defaultTextEncoding);
743
744     static WKStringRef standardFontFamily = WKStringCreateWithUTF8CString("Times");
745     static WKStringRef cursiveFontFamily = WKStringCreateWithUTF8CString("Apple Chancery");
746     static WKStringRef fantasyFontFamily = WKStringCreateWithUTF8CString("Papyrus");
747     static WKStringRef fixedFontFamily = WKStringCreateWithUTF8CString("Courier");
748     static WKStringRef pictographFontFamily = WKStringCreateWithUTF8CString("Apple Color Emoji");
749     static WKStringRef sansSerifFontFamily = WKStringCreateWithUTF8CString("Helvetica");
750     static WKStringRef serifFontFamily = WKStringCreateWithUTF8CString("Times");
751
752     WKPreferencesSetMinimumFontSize(preferences, 0);
753     WKPreferencesSetStandardFontFamily(preferences, standardFontFamily);
754     WKPreferencesSetCursiveFontFamily(preferences, cursiveFontFamily);
755     WKPreferencesSetFantasyFontFamily(preferences, fantasyFontFamily);
756     WKPreferencesSetFixedFontFamily(preferences, fixedFontFamily);
757     WKPreferencesSetPictographFontFamily(preferences, pictographFontFamily);
758     WKPreferencesSetSansSerifFontFamily(preferences, sansSerifFontFamily);
759     WKPreferencesSetSerifFontFamily(preferences, serifFontFamily);
760     WKPreferencesSetAsynchronousSpellCheckingEnabled(preferences, false);
761 #if ENABLE(MEDIA_SOURCE)
762     WKPreferencesSetMediaSourceEnabled(preferences, true);
763     WKPreferencesSetSourceBufferChangeTypeEnabled(preferences, true);
764 #endif
765
766     WKPreferencesSetHiddenPageDOMTimerThrottlingEnabled(preferences, false);
767     WKPreferencesSetHiddenPageCSSAnimationSuspensionEnabled(preferences, false);
768
769     WKPreferencesSetAcceleratedDrawingEnabled(preferences, m_shouldUseAcceleratedDrawing || options.useAcceleratedDrawing);
770     // FIXME: We should be testing the default.
771     WKPreferencesSetStorageBlockingPolicy(preferences, kWKAllowAllStorage);
772
773     WKPreferencesSetFetchAPIKeepAliveEnabled(preferences, true);
774     WKPreferencesSetResourceTimingEnabled(preferences, true);
775     WKPreferencesSetUserTimingEnabled(preferences, true);
776     WKPreferencesSetMediaPreloadingEnabled(preferences, true);
777     WKPreferencesSetMediaPlaybackAllowsInline(preferences, true);
778     WKPreferencesSetInlineMediaPlaybackRequiresPlaysInlineAttribute(preferences, false);
779     WKPreferencesSetBeaconAPIEnabled(preferences, true);
780     WKPreferencesSetDirectoryUploadEnabled(preferences, true);
781
782     WKCookieManagerDeleteAllCookies(WKContextGetCookieManager(m_context.get()));
783
784     WKPreferencesSetMockCaptureDevicesEnabled(preferences, true);
785     
786     WKPreferencesSetLargeImageAsyncDecodingEnabled(preferences, false);
787
788     WKPreferencesSetInspectorAdditionsEnabled(preferences, options.enableInspectorAdditions);
789
790     WKPreferencesSetStorageAccessAPIEnabled(preferences, true);
791     
792     WKPreferencesSetAccessibilityObjectModelEnabled(preferences, true);
793     WKPreferencesSetAriaReflectionEnabled(preferences, true);
794     WKPreferencesSetCSSOMViewScrollingAPIEnabled(preferences, true);
795     WKPreferencesSetMediaCapabilitiesEnabled(preferences, true);
796
797     WKPreferencesSetCrossOriginWindowPolicyEnabled(preferences, true);
798     WKPreferencesSetRestrictedHTTPResponseAccess(preferences, true);
799
800     WKPreferencesSetServerTimingEnabled(preferences, true);
801
802     platformResetPreferencesToConsistentValues();
803 }
804
805 bool TestController::resetStateToConsistentValues(const TestOptions& options, ResetStage resetStage)
806 {
807     SetForScope<State> changeState(m_state, Resetting);
808     m_beforeUnloadReturnValue = true;
809
810     // This setting differs between the antique and modern Mac WebKit2 API.
811     // For now, maintain the antique behavior, because some tests depend on it!
812     // FIXME: We should be testing the default.
813     WKPageSetBackgroundExtendsBeyondPage(m_mainWebView->page(), false);
814
815     WKPageSetCustomUserAgent(m_mainWebView->page(), nullptr);
816
817     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("Reset"));
818     WKRetainPtr<WKMutableDictionaryRef> resetMessageBody = adoptWK(WKMutableDictionaryCreate());
819
820     WKRetainPtr<WKStringRef> shouldGCKey = adoptWK(WKStringCreateWithUTF8CString("ShouldGC"));
821     WKRetainPtr<WKBooleanRef> shouldGCValue = adoptWK(WKBooleanCreate(m_gcBetweenTests));
822     WKDictionarySetItem(resetMessageBody.get(), shouldGCKey.get(), shouldGCValue.get());
823
824     WKRetainPtr<WKStringRef> allowedHostsKey = adoptWK(WKStringCreateWithUTF8CString("AllowedHosts"));
825     WKRetainPtr<WKMutableArrayRef> allowedHostsValue = adoptWK(WKMutableArrayCreate());
826     for (auto& host : m_allowedHosts) {
827         WKRetainPtr<WKStringRef> wkHost = adoptWK(WKStringCreateWithUTF8CString(host.c_str()));
828         WKArrayAppendItem(allowedHostsValue.get(), wkHost.get());
829     }
830     WKDictionarySetItem(resetMessageBody.get(), allowedHostsKey.get(), allowedHostsValue.get());
831
832     if (options.jscOptions.length()) {
833         WKRetainPtr<WKStringRef> jscOptionsKey = adoptWK(WKStringCreateWithUTF8CString("JSCOptions"));
834         WKRetainPtr<WKStringRef> jscOptionsValue = adoptWK(WKStringCreateWithUTF8CString(options.jscOptions.c_str()));
835         WKDictionarySetItem(resetMessageBody.get(), jscOptionsKey.get(), jscOptionsValue.get());
836     }
837
838     WKPagePostMessageToInjectedBundle(TestController::singleton().mainWebView()->page(), messageName.get(), resetMessageBody.get());
839
840     WKContextSetShouldUseFontSmoothing(TestController::singleton().context(), false);
841
842     WKContextSetCacheModel(TestController::singleton().context(), kWKCacheModelDocumentBrowser);
843
844     WKContextClearCachedCredentials(TestController::singleton().context());
845
846     clearServiceWorkerRegistrations();
847     clearDOMCaches();
848
849     WKContextSetAllowsAnySSLCertificateForServiceWorkerTesting(platformContext(), true);
850
851     // FIXME: This function should also ensure that there is only one page open.
852
853     // Reset the EventSender for each test.
854     m_eventSenderProxy = std::make_unique<EventSenderProxy>(this);
855
856     // FIXME: Is this needed? Nothing in TestController changes preferences during tests, and if there is
857     // some other code doing this, it should probably be responsible for cleanup too.
858     resetPreferencesToConsistentValues(options);
859
860 #if !PLATFORM(COCOA) && !PLATFORM(WPE)
861     WKTextCheckerContinuousSpellCheckingEnabledStateChanged(true);
862 #endif
863
864     // Make sure the view is in the window (a test can unparent it).
865     m_mainWebView->addToWindow();
866
867     // In the case that a test using the chrome input field failed, be sure to clean up for the next test.
868     m_mainWebView->removeChromeInputField();
869     m_mainWebView->focus();
870
871     // Re-set to the default backing scale factor by setting the custom scale factor to 0.
872     WKPageSetCustomBackingScaleFactor(m_mainWebView->page(), 0);
873
874     WKPageClearWheelEventTestTrigger(m_mainWebView->page());
875
876     WKPageSetMuted(m_mainWebView->page(), true);
877
878     WKPageClearUserMediaState(m_mainWebView->page());
879
880     // Reset notification permissions
881     m_webNotificationProvider.reset();
882
883     // Reset Geolocation permissions.
884     m_geolocationPermissionRequests.clear();
885     m_isGeolocationPermissionSet = false;
886     m_isGeolocationPermissionAllowed = false;
887
888     // Reset UserMedia permissions.
889     m_userMediaPermissionRequests.clear();
890     m_cachedUserMediaPermissions.clear();
891     setUserMediaPermission(true);
892
893     // Reset Custom Policy Delegate.
894     setCustomPolicyDelegate(false, false);
895
896     m_shouldDownloadUndisplayableMIMETypes = false;
897
898     m_workQueueManager.clearWorkQueue();
899
900     m_rejectsProtectionSpaceAndContinueForAuthenticationChallenges = false;
901     m_handlesAuthenticationChallenges = false;
902     m_authenticationUsername = String();
903     m_authenticationPassword = String();
904
905     setBlockAllPlugins(false);
906     setPluginSupportedMode({ });
907
908     m_shouldLogDownloadCallbacks = false;
909     m_shouldLogHistoryClientCallbacks = false;
910     m_shouldLogCanAuthenticateAgainstProtectionSpace = false;
911
912     setHidden(false);
913
914     platformResetStateToConsistentValues();
915
916     m_shouldDecideNavigationPolicyAfterDelay = false;
917     m_shouldDecideResponsePolicyAfterDelay = false;
918
919     setNavigationGesturesEnabled(false);
920     
921     setIgnoresViewportScaleLimits(options.ignoresViewportScaleLimits);
922
923     m_openPanelFileURLs = nullptr;
924     
925     statisticsResetToConsistentState();
926
927     m_didReceiveServerRedirectForProvisionalNavigation = false;
928
929     // Reset main page back to about:blank
930     m_doneResetting = false;
931     WKPageLoadURL(m_mainWebView->page(), blankURL());
932     runUntil(m_doneResetting, m_currentInvocation->shortTimeout());
933     if (!m_doneResetting)
934         return false;
935     
936     if (resetStage == ResetStage::AfterTest)
937         updateLiveDocumentsAfterTest();
938
939     return m_doneResetting;
940 }
941
942 void TestController::updateLiveDocumentsAfterTest()
943 {
944     if (!m_checkForWorldLeaks)
945         return;
946
947     AsyncTask([]() {
948         // After each test, we update the list of live documents so that we can detect when an abandoned document first showed up.
949         WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("GetLiveDocuments"));
950         WKPagePostMessageToInjectedBundle(TestController::singleton().mainWebView()->page(), messageName.get(), nullptr);
951     }, 5_s).run();
952 }
953
954 void TestController::checkForWorldLeaks()
955 {
956     if (!m_checkForWorldLeaks || !TestController::singleton().mainWebView())
957         return;
958
959     AsyncTask([]() {
960         // This runs at the end of a series of tests. It clears caches, runs a GC and then fetches the list of documents.
961         WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("CheckForWorldLeaks"));
962         WKPagePostMessageToInjectedBundle(TestController::singleton().mainWebView()->page(), messageName.get(), nullptr);
963     }, 20_s).run();
964 }
965
966 void TestController::findAndDumpWorldLeaks()
967 {
968     if (!m_checkForWorldLeaks)
969         return;
970
971     checkForWorldLeaks();
972
973     StringBuilder builder;
974     
975     if (m_abandonedDocumentInfo.size()) {
976         for (const auto& it : m_abandonedDocumentInfo) {
977             auto documentURL = it.value.abandonedDocumentURL;
978             if (documentURL.isEmpty())
979                 documentURL = "(no url)";
980             builder.append("TEST: ");
981             builder.append(it.value.testURL);
982             builder.append('\n');
983             builder.append("ABANDONED DOCUMENT: ");
984             builder.append(documentURL);
985             builder.append('\n');
986         }
987     } else
988         builder.append("no abandoned documents");
989
990     String result = builder.toString();
991     printf("Content-Type: text/plain\n");
992     printf("Content-Length: %u\n", result.length());
993     fwrite(result.utf8().data(), 1, result.length(), stdout);
994     printf("#EOF\n");
995     fprintf(stderr, "#EOF\n");
996     fflush(stdout);
997     fflush(stderr);
998 }
999
1000 void TestController::willDestroyWebView()
1001 {
1002     // Before we kill the web view, look for abandoned documents before that web process goes away.
1003     checkForWorldLeaks();
1004 }
1005
1006 void TestController::terminateWebContentProcess()
1007 {
1008     WKPageTerminate(m_mainWebView->page());
1009 }
1010
1011 void TestController::reattachPageToWebProcess()
1012 {
1013     // Loading a web page is the only way to reattach an existing page to a process.
1014     SetForScope<State> changeState(m_state, Resetting);
1015     m_doneResetting = false;
1016     WKPageLoadURL(m_mainWebView->page(), blankURL());
1017     runUntil(m_doneResetting, noTimeout);
1018 }
1019
1020 const char* TestController::webProcessName()
1021 {
1022     // FIXME: Find a way to not hardcode the process name.
1023 #if PLATFORM(IOS) && !PLATFORM(IOS_SIMULATOR)
1024     return "com.apple.WebKit.WebContent";
1025 #elif PLATFORM(COCOA)
1026     return "com.apple.WebKit.WebContent.Development";
1027 #elif PLATFORM(GTK)
1028     return "WebKitWebProcess";
1029 #elif PLATFORM(WPE)
1030     return "WPEWebProcess";
1031 #else
1032     return "WebProcess";
1033 #endif
1034 }
1035
1036 const char* TestController::networkProcessName()
1037 {
1038     // FIXME: Find a way to not hardcode the process name.
1039 #if PLATFORM(IOS) && !PLATFORM(IOS_SIMULATOR)
1040     return "com.apple.WebKit.Networking";
1041 #elif PLATFORM(COCOA)
1042     return "com.apple.WebKit.Networking.Development";
1043 #elif PLATFORM(GTK)
1044     return "WebKitNetworkProcess";
1045 #elif PLATFORM(WPE)
1046     return "WPENetworkProcess";
1047 #else
1048     return "NetworkProcess";
1049 #endif
1050 }
1051
1052 const char* TestController::databaseProcessName()
1053 {
1054     // FIXME: Find a way to not hardcode the process name.
1055 #if PLATFORM(IOS) && !PLATFORM(IOS_SIMULATOR)
1056 #if !PLATFORM(WATCHOS) && !PLATFORM(APPLETV) && __IPHONE_OS_VERSION_MIN_REQUIRED < 110300
1057     return "com.apple.WebKit.Databases";
1058 #else
1059     return "com.apple.WebKit.Storage";
1060 #endif
1061 #elif PLATFORM(COCOA)
1062     return "com.apple.WebKit.Storage.Development";
1063 #elif PLATFORM(GTK)
1064     return "WebKitStorageProcess";
1065 #elif PLATFORM(WPE)
1066     return "WPEStorageProcess";
1067 #else
1068     return "DatabaseProcess";
1069 #endif
1070 }
1071
1072 void TestController::setAllowsAnySSLCertificate(bool allows)
1073 {
1074     WKContextSetAllowsAnySSLCertificateForWebSocketTesting(platformContext(), allows);
1075 }
1076
1077 static std::string testPath(WKURLRef url)
1078 {
1079     auto scheme = adoptWK(WKURLCopyScheme(url));
1080     if (WKStringIsEqualToUTF8CStringIgnoringCase(scheme.get(), "file")) {
1081         auto path = adoptWK(WKURLCopyPath(url));
1082         auto buffer = std::vector<char>(WKStringGetMaximumUTF8CStringSize(path.get()));
1083         auto length = WKStringGetUTF8CString(path.get(), buffer.data(), buffer.size());
1084         return std::string(buffer.data(), length);
1085     }
1086     return std::string();
1087 }
1088
1089 static WKURLRef createTestURL(const char* pathOrURL)
1090 {
1091     if (strstr(pathOrURL, "http://") || strstr(pathOrURL, "https://") || strstr(pathOrURL, "file://"))
1092         return WKURLCreateWithUTF8CString(pathOrURL);
1093
1094     // Creating from filesytem path.
1095     size_t length = strlen(pathOrURL);
1096     if (!length)
1097         return 0;
1098
1099     const char separator = '/';
1100     bool isAbsolutePath = pathOrURL[0] == separator;
1101     const char* filePrefix = "file://";
1102     static const size_t prefixLength = strlen(filePrefix);
1103
1104     std::unique_ptr<char[]> buffer;
1105     if (isAbsolutePath) {
1106         buffer = std::make_unique<char[]>(prefixLength + length + 1);
1107         strcpy(buffer.get(), filePrefix);
1108         strcpy(buffer.get() + prefixLength, pathOrURL);
1109     } else {
1110         buffer = std::make_unique<char[]>(prefixLength + PATH_MAX + length + 2); // 1 for the separator
1111         strcpy(buffer.get(), filePrefix);
1112         if (!getcwd(buffer.get() + prefixLength, PATH_MAX))
1113             return 0;
1114         size_t numCharacters = strlen(buffer.get());
1115         buffer[numCharacters] = separator;
1116         strcpy(buffer.get() + numCharacters + 1, pathOrURL);
1117     }
1118
1119     return WKURLCreateWithUTF8CString(buffer.get());
1120 }
1121
1122 static bool parseBooleanTestHeaderValue(const std::string& value)
1123 {
1124     if (value == "true")
1125         return true;
1126     if (value == "false")
1127         return false;
1128
1129     LOG_ERROR("Found unexpected value '%s' for boolean option. Expected 'true' or 'false'.", value.c_str());
1130     return false;
1131 }
1132
1133 static std::string parseStringTestHeaderValueAsRelativePath(const std::string& value, const std::string& pathOrURL)
1134 {
1135     WKRetainPtr<WKURLRef> baseURL(AdoptWK, createTestURL(pathOrURL.c_str()));
1136     WKRetainPtr<WKURLRef> relativeURL(AdoptWK, WKURLCreateWithBaseURL(baseURL.get(), value.c_str()));
1137     return toSTD(adoptWK(WKURLCopyPath(relativeURL.get())));
1138 }
1139
1140 static void updateTestOptionsFromTestHeader(TestOptions& testOptions, const std::string& pathOrURL, const std::string& absolutePath)
1141 {
1142     std::string filename = absolutePath;
1143     if (filename.empty()) {
1144         // Gross. Need to reduce conversions between all the string types and URLs.
1145         WKRetainPtr<WKURLRef> wkURL(AdoptWK, createTestURL(pathOrURL.c_str()));
1146         filename = testPath(wkURL.get());
1147     }
1148
1149     if (filename.empty())
1150         return;
1151
1152     std::string options;
1153     std::ifstream testFile(filename.data());
1154     if (!testFile.good())
1155         return;
1156     getline(testFile, options);
1157     std::string beginString("webkit-test-runner [ ");
1158     std::string endString(" ]");
1159     size_t beginLocation = options.find(beginString);
1160     if (beginLocation == std::string::npos)
1161         return;
1162     size_t endLocation = options.find(endString, beginLocation);
1163     if (endLocation == std::string::npos) {
1164         LOG_ERROR("Could not find end of test header in %s", filename.c_str());
1165         return;
1166     }
1167     std::string pairString = options.substr(beginLocation + beginString.size(), endLocation - (beginLocation + beginString.size()));
1168     size_t pairStart = 0;
1169     while (pairStart < pairString.size()) {
1170         size_t pairEnd = pairString.find(" ", pairStart);
1171         if (pairEnd == std::string::npos)
1172             pairEnd = pairString.size();
1173         size_t equalsLocation = pairString.find("=", pairStart);
1174         if (equalsLocation == std::string::npos) {
1175             LOG_ERROR("Malformed option in test header (could not find '=' character) in %s", filename.c_str());
1176             break;
1177         }
1178         auto key = pairString.substr(pairStart, equalsLocation - pairStart);
1179         auto value = pairString.substr(equalsLocation + 1, pairEnd - (equalsLocation + 1));
1180         if (key == "language")
1181             testOptions.overrideLanguages = String(value.c_str()).split(',');
1182         else if (key == "useThreadedScrolling")
1183             testOptions.useThreadedScrolling = parseBooleanTestHeaderValue(value);
1184         else if (key == "useAcceleratedDrawing")
1185             testOptions.useAcceleratedDrawing = parseBooleanTestHeaderValue(value);
1186         else if (key == "useFlexibleViewport")
1187             testOptions.useFlexibleViewport = parseBooleanTestHeaderValue(value);
1188         else if (key == "useDataDetection")
1189             testOptions.useDataDetection = parseBooleanTestHeaderValue(value);
1190         else if (key == "useMockScrollbars")
1191             testOptions.useMockScrollbars = parseBooleanTestHeaderValue(value);
1192         else if (key == "needsSiteSpecificQuirks")
1193             testOptions.needsSiteSpecificQuirks = parseBooleanTestHeaderValue(value);
1194         else if (key == "ignoresViewportScaleLimits")
1195             testOptions.ignoresViewportScaleLimits = parseBooleanTestHeaderValue(value);
1196         else if (key == "useCharacterSelectionGranularity")
1197             testOptions.useCharacterSelectionGranularity = parseBooleanTestHeaderValue(value);
1198         else if (key == "enableAttachmentElement")
1199             testOptions.enableAttachmentElement = parseBooleanTestHeaderValue(value);
1200         else if (key == "enableIntersectionObserver")
1201             testOptions.enableIntersectionObserver = parseBooleanTestHeaderValue(value);
1202         else if (key == "enableMenuItemElement")
1203             testOptions.enableMenuItemElement = parseBooleanTestHeaderValue(value);
1204         else if (key == "enableModernMediaControls")
1205             testOptions.enableModernMediaControls = parseBooleanTestHeaderValue(value);
1206         else if (key == "enablePointerLock")
1207             testOptions.enablePointerLock = parseBooleanTestHeaderValue(value);
1208         else if (key == "enableWebAuthentication")
1209             testOptions.enableWebAuthentication = parseBooleanTestHeaderValue(value);
1210         else if (key == "enableIsSecureContextAttribute")
1211             testOptions.enableIsSecureContextAttribute = parseBooleanTestHeaderValue(value);
1212         else if (key == "enableInspectorAdditions")
1213             testOptions.enableInspectorAdditions = parseBooleanTestHeaderValue(value);
1214         else if (key == "dumpJSConsoleLogInStdErr")
1215             testOptions.dumpJSConsoleLogInStdErr = parseBooleanTestHeaderValue(value);
1216         else if (key == "applicationManifest")
1217             testOptions.applicationManifest = parseStringTestHeaderValueAsRelativePath(value, pathOrURL);
1218         else if (key == "allowCrossOriginSubresourcesToAskForCredentials")
1219             testOptions.allowCrossOriginSubresourcesToAskForCredentials = parseBooleanTestHeaderValue(value);
1220         else if (key == "enableWebAnimationsCSSIntegration")
1221             testOptions.enableWebAnimationsCSSIntegration = parseBooleanTestHeaderValue(value);
1222         else if (key == "enableProcessSwapOnNavigation")
1223             testOptions.enableProcessSwapOnNavigation = parseBooleanTestHeaderValue(value);
1224         else if (key == "enableProcessSwapOnWindowOpen")
1225             testOptions.enableProcessSwapOnWindowOpen = parseBooleanTestHeaderValue(value);
1226         else if (key == "enableColorFilter")
1227             testOptions.enableColorFilter = parseBooleanTestHeaderValue(value);
1228         else if (key == "punchOutWhiteBackgroundsInDarkMode")
1229             testOptions.punchOutWhiteBackgroundsInDarkMode = parseBooleanTestHeaderValue(value);
1230         else if (key == "jscOptions")
1231             testOptions.jscOptions = value;
1232         else if (key == "runSingly")
1233             testOptions.runSingly = parseBooleanTestHeaderValue(value);
1234         pairStart = pairEnd + 1;
1235     }
1236 }
1237
1238 TestOptions TestController::testOptionsForTest(const TestCommand& command) const
1239 {
1240     TestOptions options(command.pathOrURL);
1241
1242     options.useRemoteLayerTree = m_shouldUseRemoteLayerTree;
1243     options.shouldShowWebView = m_shouldShowWebView;
1244
1245     updatePlatformSpecificTestOptionsForTest(options, command.pathOrURL);
1246     updateTestOptionsFromTestHeader(options, command.pathOrURL, command.absolutePath);
1247     platformAddTestOptions(options);
1248
1249     return options;
1250 }
1251
1252 void TestController::updateWebViewSizeForTest(const TestInvocation& test)
1253 {
1254     unsigned width = viewWidth;
1255     unsigned height = viewHeight;
1256     if (test.options().isSVGTest) {
1257         width = w3cSVGViewWidth;
1258         height = w3cSVGViewHeight;
1259     }
1260
1261     mainWebView()->resizeTo(width, height);
1262 }
1263
1264 void TestController::updateWindowScaleForTest(PlatformWebView* view, const TestInvocation& test)
1265 {
1266     view->changeWindowScaleIfNeeded(test.options().deviceScaleFactor);
1267 }
1268
1269 void TestController::configureViewForTest(const TestInvocation& test)
1270 {
1271     ensureViewSupportsOptionsForTest(test);
1272     updateWebViewSizeForTest(test);
1273     updateWindowScaleForTest(mainWebView(), test);
1274
1275     platformConfigureViewForTest(test);
1276 }
1277
1278 class CommandTokenizer {
1279 public:
1280     explicit CommandTokenizer(const std::string& input)
1281         : m_input(input)
1282         , m_posNextSeparator(0)
1283     {
1284         pump();
1285     }
1286
1287     bool hasNext() const;
1288     std::string next();
1289
1290 private:
1291     void pump();
1292     static const char kSeparator = '\'';
1293     const std::string& m_input;
1294     std::string m_next;
1295     size_t m_posNextSeparator;
1296 };
1297
1298 void CommandTokenizer::pump()
1299 {
1300     if (m_posNextSeparator == std::string::npos || m_posNextSeparator == m_input.size()) {
1301         m_next = std::string();
1302         return;
1303     }
1304     size_t start = m_posNextSeparator ? m_posNextSeparator + 1 : 0;
1305     m_posNextSeparator = m_input.find(kSeparator, start);
1306     size_t size = m_posNextSeparator == std::string::npos ? std::string::npos : m_posNextSeparator - start;
1307     m_next = std::string(m_input, start, size);
1308 }
1309
1310 std::string CommandTokenizer::next()
1311 {
1312     ASSERT(hasNext());
1313
1314     std::string oldNext = m_next;
1315     pump();
1316     return oldNext;
1317 }
1318
1319 bool CommandTokenizer::hasNext() const
1320 {
1321     return !m_next.empty();
1322 }
1323
1324 NO_RETURN static void die(const std::string& inputLine)
1325 {
1326     fprintf(stderr, "Unexpected input line: %s\n", inputLine.c_str());
1327     exit(1);
1328 }
1329
1330 static TestCommand parseInputLine(const std::string& inputLine)
1331 {
1332     TestCommand result;
1333     CommandTokenizer tokenizer(inputLine);
1334     if (!tokenizer.hasNext())
1335         die(inputLine);
1336
1337     std::string arg = tokenizer.next();
1338     result.pathOrURL = arg;
1339     while (tokenizer.hasNext()) {
1340         arg = tokenizer.next();
1341         if (arg == std::string("--timeout")) {
1342             std::string timeoutToken = tokenizer.next();
1343             result.timeout = Seconds::fromMilliseconds(atoi(timeoutToken.c_str()));
1344         } else if (arg == std::string("-p") || arg == std::string("--pixel-test")) {
1345             result.shouldDumpPixels = true;
1346             if (tokenizer.hasNext())
1347                 result.expectedPixelHash = tokenizer.next();
1348         } else if (arg == std::string("--dump-jsconsolelog-in-stderr"))
1349             result.dumpJSConsoleLogInStdErr = true;
1350         else if (arg == std::string("--absolutePath"))
1351             result.absolutePath = tokenizer.next();
1352         else
1353             die(inputLine);
1354     }
1355     return result;
1356 }
1357
1358 bool TestController::runTest(const char* inputLine)
1359 {
1360     AutodrainedPool pool;
1361     
1362     WKTextCheckerSetTestingMode(true);
1363     TestCommand command = parseInputLine(std::string(inputLine));
1364
1365     m_state = RunningTest;
1366     
1367     TestOptions options = testOptionsForTest(command);
1368
1369     WKRetainPtr<WKURLRef> wkURL(AdoptWK, createTestURL(command.pathOrURL.c_str()));
1370     m_currentInvocation = std::make_unique<TestInvocation>(wkURL.get(), options);
1371
1372     if (command.shouldDumpPixels || m_shouldDumpPixelsForAllTests)
1373         m_currentInvocation->setIsPixelTest(command.expectedPixelHash);
1374
1375     if (command.timeout > 0_s)
1376         m_currentInvocation->setCustomTimeout(command.timeout);
1377
1378     m_currentInvocation->setDumpJSConsoleLogInStdErr(command.dumpJSConsoleLogInStdErr || options.dumpJSConsoleLogInStdErr);
1379
1380     platformWillRunTest(*m_currentInvocation);
1381
1382     m_currentInvocation->invoke();
1383     m_currentInvocation = nullptr;
1384
1385     return true;
1386 }
1387
1388 bool TestController::waitForCompletion(const WTF::Function<void ()>& function, WTF::Seconds timeout)
1389 {
1390     m_doneResetting = false;
1391     function();
1392     runUntil(m_doneResetting, timeout);
1393     return !m_doneResetting;
1394 }
1395
1396 bool TestController::handleControlCommand(const char* command)
1397 {
1398     if (!strcmp("#CHECK FOR WORLD LEAKS", command)) {
1399         if (!m_checkForWorldLeaks) {
1400             WTFLogAlways("WebKitTestRunner asked to check for world leaks, but was not run with --world-leaks");
1401             return true;
1402         }
1403         findAndDumpWorldLeaks();
1404         return true;
1405     }
1406     return false;
1407 }
1408
1409 void TestController::runTestingServerLoop()
1410 {
1411     char filenameBuffer[2048];
1412     while (fgets(filenameBuffer, sizeof(filenameBuffer), stdin)) {
1413         char* newLineCharacter = strchr(filenameBuffer, '\n');
1414         if (newLineCharacter)
1415             *newLineCharacter = '\0';
1416
1417         if (strlen(filenameBuffer) == 0)
1418             continue;
1419
1420         if (handleControlCommand(filenameBuffer))
1421             continue;
1422
1423         if (!runTest(filenameBuffer))
1424             break;
1425     }
1426 }
1427
1428 void TestController::run()
1429 {
1430     if (m_usingServerMode)
1431         runTestingServerLoop();
1432     else {
1433         for (size_t i = 0; i < m_paths.size(); ++i) {
1434             if (!runTest(m_paths[i].c_str()))
1435                 break;
1436         }
1437         if (m_checkForWorldLeaks)
1438             findAndDumpWorldLeaks();
1439     }
1440 }
1441
1442 void TestController::runUntil(bool& done, WTF::Seconds timeout)
1443 {
1444     if (m_forceNoTimeout)
1445         timeout = noTimeout;
1446
1447     platformRunUntil(done, timeout);
1448 }
1449
1450 // WKContextInjectedBundleClient
1451
1452 void TestController::didReceiveMessageFromInjectedBundle(WKContextRef context, WKStringRef messageName, WKTypeRef messageBody, const void* clientInfo)
1453 {
1454     static_cast<TestController*>(const_cast<void*>(clientInfo))->didReceiveMessageFromInjectedBundle(messageName, messageBody);
1455 }
1456
1457 void TestController::didReceiveSynchronousMessageFromInjectedBundle(WKContextRef context, WKStringRef messageName, WKTypeRef messageBody, WKTypeRef* returnData, const void* clientInfo)
1458 {
1459     *returnData = static_cast<TestController*>(const_cast<void*>(clientInfo))->didReceiveSynchronousMessageFromInjectedBundle(messageName, messageBody).leakRef();
1460 }
1461
1462 WKTypeRef TestController::getInjectedBundleInitializationUserData(WKContextRef, const void* clientInfo)
1463 {
1464     return static_cast<TestController*>(const_cast<void*>(clientInfo))->getInjectedBundleInitializationUserData().leakRef();
1465 }
1466
1467 // WKPageInjectedBundleClient
1468
1469 void TestController::didReceivePageMessageFromInjectedBundle(WKPageRef page, WKStringRef messageName, WKTypeRef messageBody, const void* clientInfo)
1470 {
1471     static_cast<TestController*>(const_cast<void*>(clientInfo))->didReceiveMessageFromInjectedBundle(messageName, messageBody);
1472 }
1473
1474 void TestController::didReceiveSynchronousPageMessageFromInjectedBundle(WKPageRef page, WKStringRef messageName, WKTypeRef messageBody, WKTypeRef* returnData, const void* clientInfo)
1475 {
1476     *returnData = static_cast<TestController*>(const_cast<void*>(clientInfo))->didReceiveSynchronousMessageFromInjectedBundle(messageName, messageBody).leakRef();
1477 }
1478
1479 void TestController::networkProcessDidCrash(WKContextRef context, const void *clientInfo)
1480 {
1481     static_cast<TestController*>(const_cast<void*>(clientInfo))->networkProcessDidCrash();
1482 }
1483
1484 void TestController::databaseProcessDidCrash(WKContextRef context, const void *clientInfo)
1485 {
1486     static_cast<TestController*>(const_cast<void*>(clientInfo))->databaseProcessDidCrash();
1487 }
1488
1489 void TestController::didReceiveKeyDownMessageFromInjectedBundle(WKDictionaryRef messageBodyDictionary, bool synchronous)
1490 {
1491     WKRetainPtr<WKStringRef> keyKey = adoptWK(WKStringCreateWithUTF8CString("Key"));
1492     WKStringRef key = static_cast<WKStringRef>(WKDictionaryGetItemForKey(messageBodyDictionary, keyKey.get()));
1493
1494     WKRetainPtr<WKStringRef> modifiersKey = adoptWK(WKStringCreateWithUTF8CString("Modifiers"));
1495     WKEventModifiers modifiers = static_cast<WKEventModifiers>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, modifiersKey.get()))));
1496
1497     WKRetainPtr<WKStringRef> locationKey = adoptWK(WKStringCreateWithUTF8CString("Location"));
1498     unsigned location = static_cast<unsigned>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, locationKey.get()))));
1499
1500     m_eventSenderProxy->keyDown(key, modifiers, location);
1501 }
1502
1503 void TestController::didReceiveLiveDocumentsList(WKArrayRef liveDocumentList)
1504 {
1505     auto numDocuments = WKArrayGetSize(liveDocumentList);
1506
1507     HashMap<uint64_t, String> documentInfo;
1508     for (size_t i = 0; i < numDocuments; ++i) {
1509         WKTypeRef item = WKArrayGetItemAtIndex(liveDocumentList, i);
1510         if (item && WKGetTypeID(item) == WKDictionaryGetTypeID()) {
1511             WKDictionaryRef liveDocumentItem = static_cast<WKDictionaryRef>(item);
1512
1513             WKRetainPtr<WKStringRef> idKey(AdoptWK, WKStringCreateWithUTF8CString("id"));
1514             WKUInt64Ref documentID = static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(liveDocumentItem, idKey.get()));
1515
1516             WKRetainPtr<WKStringRef> urlKey(AdoptWK, WKStringCreateWithUTF8CString("url"));
1517             WKStringRef documentURL = static_cast<WKStringRef>(WKDictionaryGetItemForKey(liveDocumentItem, urlKey.get()));
1518
1519             documentInfo.add(WKUInt64GetValue(documentID), toWTFString(documentURL));
1520         }
1521     }
1522
1523     if (!documentInfo.size()) {
1524         m_abandonedDocumentInfo.clear();
1525         return;
1526     }
1527
1528     // Remove any documents which are no longer live.
1529     m_abandonedDocumentInfo.removeIf([&](auto& keyAndValue) {
1530         return !documentInfo.contains(keyAndValue.key);
1531     });
1532     
1533     // Add newly abandoned documents.
1534     String currentTestURL = m_currentInvocation ? toWTFString(adoptWK(WKURLCopyString(m_currentInvocation->url()))) : "no test";
1535     for (const auto& it : documentInfo)
1536         m_abandonedDocumentInfo.add(it.key, AbandonedDocumentInfo(currentTestURL, it.value));
1537 }
1538
1539 void TestController::didReceiveMessageFromInjectedBundle(WKStringRef messageName, WKTypeRef messageBody)
1540 {
1541     if (WKStringIsEqualToUTF8CString(messageName, "LiveDocuments")) {
1542         ASSERT(WKGetTypeID(messageBody) == WKArrayGetTypeID());
1543         didReceiveLiveDocumentsList(static_cast<WKArrayRef>(messageBody));
1544         AsyncTask::currentTask()->taskComplete();
1545         return;
1546     }
1547
1548     if (WKStringIsEqualToUTF8CString(messageName, "EventSender")) {
1549         if (m_state != RunningTest)
1550             return;
1551
1552         ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID());
1553         WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody);
1554
1555         WKRetainPtr<WKStringRef> subMessageKey(AdoptWK, WKStringCreateWithUTF8CString("SubMessage"));
1556         WKStringRef subMessageName = static_cast<WKStringRef>(WKDictionaryGetItemForKey(messageBodyDictionary, subMessageKey.get()));
1557
1558         if (WKStringIsEqualToUTF8CString(subMessageName, "MouseDown") || WKStringIsEqualToUTF8CString(subMessageName, "MouseUp")) {
1559             WKRetainPtr<WKStringRef> buttonKey = adoptWK(WKStringCreateWithUTF8CString("Button"));
1560             unsigned button = static_cast<unsigned>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, buttonKey.get()))));
1561
1562             WKRetainPtr<WKStringRef> modifiersKey = adoptWK(WKStringCreateWithUTF8CString("Modifiers"));
1563             WKEventModifiers modifiers = static_cast<WKEventModifiers>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, modifiersKey.get()))));
1564
1565             // Forward to WebProcess
1566             if (WKStringIsEqualToUTF8CString(subMessageName, "MouseDown"))
1567                 m_eventSenderProxy->mouseDown(button, modifiers);
1568             else
1569                 m_eventSenderProxy->mouseUp(button, modifiers);
1570
1571             return;
1572         }
1573
1574         if (WKStringIsEqualToUTF8CString(subMessageName, "KeyDown")) {
1575             didReceiveKeyDownMessageFromInjectedBundle(messageBodyDictionary, false);
1576             return;
1577         }
1578
1579         if (WKStringIsEqualToUTF8CString(subMessageName, "MouseScrollBy")) {
1580             WKRetainPtr<WKStringRef> xKey = adoptWK(WKStringCreateWithUTF8CString("X"));
1581             double x = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, xKey.get())));
1582
1583             WKRetainPtr<WKStringRef> yKey = adoptWK(WKStringCreateWithUTF8CString("Y"));
1584             double y = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, yKey.get())));
1585
1586             // Forward to WebProcess
1587             m_eventSenderProxy->mouseScrollBy(x, y);
1588             return;
1589         }
1590
1591         if (WKStringIsEqualToUTF8CString(subMessageName, "MouseScrollByWithWheelAndMomentumPhases")) {
1592             WKRetainPtr<WKStringRef> xKey = adoptWK(WKStringCreateWithUTF8CString("X"));
1593             double x = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, xKey.get())));
1594             
1595             WKRetainPtr<WKStringRef> yKey = adoptWK(WKStringCreateWithUTF8CString("Y"));
1596             double y = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, yKey.get())));
1597             
1598             WKRetainPtr<WKStringRef> phaseKey = adoptWK(WKStringCreateWithUTF8CString("Phase"));
1599             int phase = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, phaseKey.get()))));
1600             WKRetainPtr<WKStringRef> momentumKey = adoptWK(WKStringCreateWithUTF8CString("Momentum"));
1601             int momentum = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, momentumKey.get()))));
1602             
1603             // Forward to WebProcess
1604             m_eventSenderProxy->mouseScrollByWithWheelAndMomentumPhases(x, y, phase, momentum);
1605
1606             return;
1607         }
1608
1609         ASSERT_NOT_REACHED();
1610     }
1611
1612     if (!m_currentInvocation)
1613         return;
1614
1615     m_currentInvocation->didReceiveMessageFromInjectedBundle(messageName, messageBody);
1616 }
1617
1618 WKRetainPtr<WKTypeRef> TestController::didReceiveSynchronousMessageFromInjectedBundle(WKStringRef messageName, WKTypeRef messageBody)
1619 {
1620     if (WKStringIsEqualToUTF8CString(messageName, "EventSender")) {
1621         if (m_state != RunningTest)
1622             return nullptr;
1623
1624         ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID());
1625         WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody);
1626
1627         WKRetainPtr<WKStringRef> subMessageKey(AdoptWK, WKStringCreateWithUTF8CString("SubMessage"));
1628         WKStringRef subMessageName = static_cast<WKStringRef>(WKDictionaryGetItemForKey(messageBodyDictionary, subMessageKey.get()));
1629
1630         if (WKStringIsEqualToUTF8CString(subMessageName, "KeyDown")) {
1631             didReceiveKeyDownMessageFromInjectedBundle(messageBodyDictionary, true);
1632
1633             return 0;
1634         }
1635
1636         if (WKStringIsEqualToUTF8CString(subMessageName, "MouseDown") || WKStringIsEqualToUTF8CString(subMessageName, "MouseUp")) {
1637             WKRetainPtr<WKStringRef> buttonKey = adoptWK(WKStringCreateWithUTF8CString("Button"));
1638             unsigned button = static_cast<unsigned>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, buttonKey.get()))));
1639
1640             WKRetainPtr<WKStringRef> modifiersKey = adoptWK(WKStringCreateWithUTF8CString("Modifiers"));
1641             WKEventModifiers modifiers = static_cast<WKEventModifiers>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, modifiersKey.get()))));
1642
1643             // Forward to WebProcess
1644             if (WKStringIsEqualToUTF8CString(subMessageName, "MouseDown"))
1645                 m_eventSenderProxy->mouseDown(button, modifiers);
1646             else
1647                 m_eventSenderProxy->mouseUp(button, modifiers);
1648             return 0;
1649         }
1650
1651         if (WKStringIsEqualToUTF8CString(subMessageName, "MouseMoveTo")) {
1652             WKRetainPtr<WKStringRef> xKey = adoptWK(WKStringCreateWithUTF8CString("X"));
1653             double x = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, xKey.get())));
1654
1655             WKRetainPtr<WKStringRef> yKey = adoptWK(WKStringCreateWithUTF8CString("Y"));
1656             double y = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, yKey.get())));
1657
1658             // Forward to WebProcess
1659             m_eventSenderProxy->mouseMoveTo(x, y);
1660             return 0;
1661         }
1662
1663 #if PLATFORM(MAC)
1664         if (WKStringIsEqualToUTF8CString(subMessageName, "MouseForceClick")) {
1665             m_eventSenderProxy->mouseForceClick();
1666             return 0;
1667         }
1668
1669         if (WKStringIsEqualToUTF8CString(subMessageName, "StartAndCancelMouseForceClick")) {
1670             m_eventSenderProxy->startAndCancelMouseForceClick();
1671             return 0;
1672         }
1673
1674         if (WKStringIsEqualToUTF8CString(subMessageName, "MouseForceDown")) {
1675             m_eventSenderProxy->mouseForceDown();
1676             return 0;
1677         }
1678
1679         if (WKStringIsEqualToUTF8CString(subMessageName, "MouseForceUp")) {
1680             m_eventSenderProxy->mouseForceUp();
1681             return 0;
1682         }
1683
1684         if (WKStringIsEqualToUTF8CString(subMessageName, "MouseForceChanged")) {
1685             WKRetainPtr<WKStringRef> forceKey = adoptWK(WKStringCreateWithUTF8CString("Force"));
1686             double force = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, forceKey.get())));
1687
1688             m_eventSenderProxy->mouseForceChanged(force);
1689             return 0;
1690         }
1691 #endif // PLATFORM(MAC)
1692
1693         if (WKStringIsEqualToUTF8CString(subMessageName, "ContinuousMouseScrollBy")) {
1694             WKRetainPtr<WKStringRef> xKey = adoptWK(WKStringCreateWithUTF8CString("X"));
1695             double x = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, xKey.get())));
1696
1697             WKRetainPtr<WKStringRef> yKey = adoptWK(WKStringCreateWithUTF8CString("Y"));
1698             double y = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, yKey.get())));
1699
1700             WKRetainPtr<WKStringRef> pagedKey = adoptWK(WKStringCreateWithUTF8CString("Paged"));
1701             bool paged = static_cast<bool>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, pagedKey.get()))));
1702
1703             // Forward to WebProcess
1704             m_eventSenderProxy->continuousMouseScrollBy(x, y, paged);
1705             return 0;
1706         }
1707
1708         if (WKStringIsEqualToUTF8CString(subMessageName, "LeapForward")) {
1709             WKRetainPtr<WKStringRef> timeKey = adoptWK(WKStringCreateWithUTF8CString("TimeInMilliseconds"));
1710             unsigned time = static_cast<unsigned>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, timeKey.get()))));
1711
1712             m_eventSenderProxy->leapForward(time);
1713             return 0;
1714         }
1715
1716 #if ENABLE(TOUCH_EVENTS)
1717         if (WKStringIsEqualToUTF8CString(subMessageName, "AddTouchPoint")) {
1718             WKRetainPtr<WKStringRef> xKey = adoptWK(WKStringCreateWithUTF8CString("X"));
1719             int x = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, xKey.get()))));
1720
1721             WKRetainPtr<WKStringRef> yKey = adoptWK(WKStringCreateWithUTF8CString("Y"));
1722             int y = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, yKey.get()))));
1723
1724             m_eventSenderProxy->addTouchPoint(x, y);
1725             return 0;
1726         }
1727
1728         if (WKStringIsEqualToUTF8CString(subMessageName, "UpdateTouchPoint")) {
1729             WKRetainPtr<WKStringRef> indexKey = adoptWK(WKStringCreateWithUTF8CString("Index"));
1730             int index = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, indexKey.get()))));
1731
1732             WKRetainPtr<WKStringRef> xKey = adoptWK(WKStringCreateWithUTF8CString("X"));
1733             int x = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, xKey.get()))));
1734
1735             WKRetainPtr<WKStringRef> yKey = adoptWK(WKStringCreateWithUTF8CString("Y"));
1736             int y = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, yKey.get()))));
1737
1738             m_eventSenderProxy->updateTouchPoint(index, x, y);
1739             return 0;
1740         }
1741
1742         if (WKStringIsEqualToUTF8CString(subMessageName, "SetTouchModifier")) {
1743             WKRetainPtr<WKStringRef> modifierKey = adoptWK(WKStringCreateWithUTF8CString("Modifier"));
1744             WKEventModifiers modifier = static_cast<WKEventModifiers>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, modifierKey.get()))));
1745
1746             WKRetainPtr<WKStringRef> enableKey = adoptWK(WKStringCreateWithUTF8CString("Enable"));
1747             bool enable = static_cast<bool>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, enableKey.get()))));
1748
1749             m_eventSenderProxy->setTouchModifier(modifier, enable);
1750             return 0;
1751         }
1752
1753         if (WKStringIsEqualToUTF8CString(subMessageName, "SetTouchPointRadius")) {
1754             WKRetainPtr<WKStringRef> xKey = adoptWK(WKStringCreateWithUTF8CString("RadiusX"));
1755             int x = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, xKey.get()))));
1756
1757             WKRetainPtr<WKStringRef> yKey = adoptWK(WKStringCreateWithUTF8CString("RadiusY"));
1758             int y = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, yKey.get()))));
1759
1760             m_eventSenderProxy->setTouchPointRadius(x, y);
1761             return 0;
1762         }
1763
1764         if (WKStringIsEqualToUTF8CString(subMessageName, "TouchStart")) {
1765             m_eventSenderProxy->touchStart();
1766             return 0;
1767         }
1768
1769         if (WKStringIsEqualToUTF8CString(subMessageName, "TouchMove")) {
1770             m_eventSenderProxy->touchMove();
1771             return 0;
1772         }
1773
1774         if (WKStringIsEqualToUTF8CString(subMessageName, "TouchEnd")) {
1775             m_eventSenderProxy->touchEnd();
1776             return 0;
1777         }
1778
1779         if (WKStringIsEqualToUTF8CString(subMessageName, "TouchCancel")) {
1780             m_eventSenderProxy->touchCancel();
1781             return 0;
1782         }
1783
1784         if (WKStringIsEqualToUTF8CString(subMessageName, "ClearTouchPoints")) {
1785             m_eventSenderProxy->clearTouchPoints();
1786             return 0;
1787         }
1788
1789         if (WKStringIsEqualToUTF8CString(subMessageName, "ReleaseTouchPoint")) {
1790             WKRetainPtr<WKStringRef> indexKey = adoptWK(WKStringCreateWithUTF8CString("Index"));
1791             int index = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, indexKey.get()))));
1792             m_eventSenderProxy->releaseTouchPoint(index);
1793             return 0;
1794         }
1795
1796         if (WKStringIsEqualToUTF8CString(subMessageName, "CancelTouchPoint")) {
1797             WKRetainPtr<WKStringRef> indexKey = adoptWK(WKStringCreateWithUTF8CString("Index"));
1798             int index = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, indexKey.get()))));
1799             m_eventSenderProxy->cancelTouchPoint(index);
1800             return 0;
1801         }
1802 #endif
1803         ASSERT_NOT_REACHED();
1804     }
1805     return m_currentInvocation->didReceiveSynchronousMessageFromInjectedBundle(messageName, messageBody);
1806 }
1807
1808 WKRetainPtr<WKTypeRef> TestController::getInjectedBundleInitializationUserData()
1809 {
1810     return nullptr;
1811 }
1812
1813 // WKContextClient
1814
1815 void TestController::networkProcessDidCrash()
1816 {
1817     pid_t pid = WKContextGetNetworkProcessIdentifier(m_context.get());
1818     fprintf(stderr, "#CRASHED - %s (pid %ld)\n", networkProcessName(), static_cast<long>(pid));
1819     exit(1);
1820 }
1821
1822 void TestController::databaseProcessDidCrash()
1823 {
1824     pid_t pid = WKContextGetDatabaseProcessIdentifier(m_context.get());
1825     fprintf(stderr, "#CRASHED - %s (pid %ld)\n", databaseProcessName(), static_cast<long>(pid));
1826     exit(1);
1827 }
1828
1829 // WKPageNavigationClient
1830
1831 void TestController::didCommitNavigation(WKPageRef page, WKNavigationRef navigation, WKTypeRef, const void* clientInfo)
1832 {
1833     static_cast<TestController*>(const_cast<void*>(clientInfo))->didCommitNavigation(page, navigation);
1834 }
1835
1836 void TestController::didFinishNavigation(WKPageRef page, WKNavigationRef navigation, WKTypeRef, const void* clientInfo)
1837 {
1838     static_cast<TestController*>(const_cast<void*>(clientInfo))->didFinishNavigation(page, navigation);
1839 }
1840
1841 void TestController::didReceiveServerRedirectForProvisionalNavigation(WKPageRef page, WKNavigationRef navigation, WKTypeRef userData, const void* clientInfo)
1842 {
1843     static_cast<TestController*>(const_cast<void*>(clientInfo))->didReceiveServerRedirectForProvisionalNavigation(page, navigation, userData);
1844 }
1845
1846 bool TestController::canAuthenticateAgainstProtectionSpace(WKPageRef page, WKProtectionSpaceRef protectionSpace, const void* clientInfo)
1847 {
1848     return static_cast<TestController*>(const_cast<void*>(clientInfo))->canAuthenticateAgainstProtectionSpace(page, protectionSpace);
1849 }
1850
1851 void TestController::didReceiveAuthenticationChallenge(WKPageRef page, WKAuthenticationChallengeRef authenticationChallenge, const void *clientInfo)
1852 {
1853     static_cast<TestController*>(const_cast<void*>(clientInfo))->didReceiveAuthenticationChallenge(page, /*frame,*/ authenticationChallenge);
1854 }
1855
1856 void TestController::processDidCrash(WKPageRef page, const void* clientInfo)
1857 {
1858     static_cast<TestController*>(const_cast<void*>(clientInfo))->processDidCrash();
1859 }
1860
1861 void TestController::didBeginNavigationGesture(WKPageRef page, const void *clientInfo)
1862 {
1863     static_cast<TestController*>(const_cast<void*>(clientInfo))->didBeginNavigationGesture(page);
1864 }
1865
1866 void TestController::willEndNavigationGesture(WKPageRef page, WKBackForwardListItemRef backForwardListItem, const void *clientInfo)
1867 {
1868     static_cast<TestController*>(const_cast<void*>(clientInfo))->willEndNavigationGesture(page, backForwardListItem);
1869 }
1870
1871 void TestController::didEndNavigationGesture(WKPageRef page, WKBackForwardListItemRef backForwardListItem, const void *clientInfo)
1872 {
1873     static_cast<TestController*>(const_cast<void*>(clientInfo))->didEndNavigationGesture(page, backForwardListItem);
1874 }
1875
1876 void TestController::didRemoveNavigationGestureSnapshot(WKPageRef page, const void *clientInfo)
1877 {
1878     static_cast<TestController*>(const_cast<void*>(clientInfo))->didRemoveNavigationGestureSnapshot(page);
1879 }
1880
1881 WKPluginLoadPolicy TestController::decidePolicyForPluginLoad(WKPageRef page, WKPluginLoadPolicy currentPluginLoadPolicy, WKDictionaryRef pluginInformation, WKStringRef* unavailabilityDescription, const void* clientInfo)
1882 {
1883     return static_cast<TestController*>(const_cast<void*>(clientInfo))->decidePolicyForPluginLoad(page, currentPluginLoadPolicy, pluginInformation, unavailabilityDescription);
1884 }
1885
1886 WKPluginLoadPolicy TestController::decidePolicyForPluginLoad(WKPageRef, WKPluginLoadPolicy currentPluginLoadPolicy, WKDictionaryRef pluginInformation, WKStringRef* unavailabilityDescription)
1887 {
1888     if (m_shouldBlockAllPlugins)
1889         return kWKPluginLoadPolicyBlocked;
1890
1891 #if PLATFORM(MAC)
1892     WKStringRef bundleIdentifier = (WKStringRef)WKDictionaryGetItemForKey(pluginInformation, WKPluginInformationBundleIdentifierKey());
1893     if (!bundleIdentifier)
1894         return currentPluginLoadPolicy;
1895
1896     if (WKStringIsEqualToUTF8CString(bundleIdentifier, "com.apple.QuickTime Plugin.plugin"))
1897         return currentPluginLoadPolicy;
1898
1899     if (WKStringIsEqualToUTF8CString(bundleIdentifier, "com.apple.testnetscapeplugin"))
1900         return currentPluginLoadPolicy;
1901
1902     RELEASE_ASSERT_NOT_REACHED(); // Please don't use any other plug-ins in tests, as they will not be installed on all machines.
1903 #else
1904     return currentPluginLoadPolicy;
1905 #endif
1906 }
1907
1908 void TestController::setBlockAllPlugins(bool shouldBlock)
1909 {
1910     m_shouldBlockAllPlugins = shouldBlock;
1911
1912 #if PLATFORM(MAC)
1913     auto policy = shouldBlock ? kWKPluginLoadClientPolicyBlock : kWKPluginLoadClientPolicyAllow;
1914
1915     WKRetainPtr<WKStringRef> nameNetscape = adoptWK(WKStringCreateWithUTF8CString("com.apple.testnetscapeplugin"));
1916     WKRetainPtr<WKStringRef> nameFlash = adoptWK(WKStringCreateWithUTF8CString("com.macromedia.Flash Player.plugin"));
1917     WKRetainPtr<WKStringRef> emptyString = adoptWK(WKStringCreateWithUTF8CString(""));
1918     WKContextSetPluginLoadClientPolicy(m_context.get(), policy, emptyString.get(), nameNetscape.get(), emptyString.get());
1919     WKContextSetPluginLoadClientPolicy(m_context.get(), policy, emptyString.get(), nameFlash.get(), emptyString.get());
1920 #endif
1921 }
1922
1923 void TestController::setPluginSupportedMode(const String& mode)
1924 {
1925     if (m_unsupportedPluginMode == mode)
1926         return;
1927
1928     m_unsupportedPluginMode = mode;
1929     if (m_unsupportedPluginMode.isEmpty()) {
1930         WKContextClearSupportedPlugins(m_context.get());
1931         return;
1932     }
1933
1934     WKRetainPtr<WKMutableArrayRef> emptyArray = adoptWK(WKMutableArrayCreate());
1935     WKRetainPtr<WKStringRef> allOrigins = adoptWK(WKStringCreateWithUTF8CString(""));
1936     WKRetainPtr<WKStringRef> specificOrigin = adoptWK(WKStringCreateWithUTF8CString("localhost"));
1937
1938     WKRetainPtr<WKStringRef> pdfName = adoptWK(WKStringCreateWithUTF8CString("My personal PDF"));
1939     WKContextAddSupportedPlugin(m_context.get(), allOrigins.get(), pdfName.get(), emptyArray.get(), emptyArray.get());
1940
1941     WKRetainPtr<WKStringRef> nameNetscape = adoptWK(WKStringCreateWithUTF8CString("com.apple.testnetscapeplugin"));
1942     WKRetainPtr<WKStringRef> mimeTypeNetscape = adoptWK(WKStringCreateWithUTF8CString("application/x-webkit-test-netscape"));
1943     WKRetainPtr<WKMutableArrayRef> mimeTypesNetscape = adoptWK(WKMutableArrayCreate());
1944     WKArrayAppendItem(mimeTypesNetscape.get(), mimeTypeNetscape.get());
1945
1946     WKRetainPtr<WKStringRef> namePdf = adoptWK(WKStringCreateWithUTF8CString("WebKit built-in PDF"));
1947
1948     if (m_unsupportedPluginMode == "allOrigins") {
1949         WKContextAddSupportedPlugin(m_context.get(), allOrigins.get(), nameNetscape.get(), mimeTypesNetscape.get(), emptyArray.get());
1950         WKContextAddSupportedPlugin(m_context.get(), allOrigins.get(), namePdf.get(), emptyArray.get(), emptyArray.get());
1951         return;
1952     }
1953
1954     if (m_unsupportedPluginMode == "specificOrigin") {
1955         WKContextAddSupportedPlugin(m_context.get(), specificOrigin.get(), nameNetscape.get(), mimeTypesNetscape.get(), emptyArray.get());
1956         WKContextAddSupportedPlugin(m_context.get(), specificOrigin.get(), namePdf.get(), emptyArray.get(), emptyArray.get());
1957         return;
1958     }
1959 }
1960
1961 void TestController::didCommitNavigation(WKPageRef page, WKNavigationRef navigation)
1962 {
1963     mainWebView()->focus();
1964 }
1965
1966 void TestController::didReceiveServerRedirectForProvisionalNavigation(WKPageRef page, WKNavigationRef navigation, WKTypeRef userData)
1967 {
1968     m_didReceiveServerRedirectForProvisionalNavigation = true;
1969     return;
1970 }
1971
1972 static const char* toString(WKProtectionSpaceAuthenticationScheme scheme)
1973 {
1974     switch (scheme) {
1975     case kWKProtectionSpaceAuthenticationSchemeDefault:
1976         return "ProtectionSpaceAuthenticationSchemeDefault";
1977     case kWKProtectionSpaceAuthenticationSchemeHTTPBasic:
1978         return "ProtectionSpaceAuthenticationSchemeHTTPBasic";
1979     case kWKProtectionSpaceAuthenticationSchemeHTMLForm:
1980         return "ProtectionSpaceAuthenticationSchemeHTMLForm";
1981     case kWKProtectionSpaceAuthenticationSchemeNTLM:
1982         return "ProtectionSpaceAuthenticationSchemeNTLM";
1983     case kWKProtectionSpaceAuthenticationSchemeNegotiate:
1984         return "ProtectionSpaceAuthenticationSchemeNegotiate";
1985     case kWKProtectionSpaceAuthenticationSchemeClientCertificateRequested:
1986         return "ProtectionSpaceAuthenticationSchemeClientCertificateRequested";
1987     case kWKProtectionSpaceAuthenticationSchemeServerTrustEvaluationRequested:
1988         return "ProtectionSpaceAuthenticationSchemeServerTrustEvaluationRequested";
1989     case kWKProtectionSpaceAuthenticationSchemeOAuth:
1990         return "ProtectionSpaceAuthenticationSchemeOAuth";
1991     case kWKProtectionSpaceAuthenticationSchemeUnknown:
1992         return "ProtectionSpaceAuthenticationSchemeUnknown";
1993     }
1994     ASSERT_NOT_REACHED();
1995     return "ProtectionSpaceAuthenticationSchemeUnknown";
1996 }
1997
1998 bool TestController::canAuthenticateAgainstProtectionSpace(WKPageRef page, WKProtectionSpaceRef protectionSpace)
1999 {
2000     if (m_shouldLogCanAuthenticateAgainstProtectionSpace)
2001         m_currentInvocation->outputText("canAuthenticateAgainstProtectionSpace\n");
2002     WKProtectionSpaceAuthenticationScheme authenticationScheme = WKProtectionSpaceGetAuthenticationScheme(protectionSpace);
2003     
2004     if (authenticationScheme == kWKProtectionSpaceAuthenticationSchemeServerTrustEvaluationRequested) {
2005         std::string host = toSTD(adoptWK(WKProtectionSpaceCopyHost(protectionSpace)).get());
2006         return host == "localhost" || host == "127.0.0.1" || (m_allowAnyHTTPSCertificateForAllowedHosts && m_allowedHosts.find(host) != m_allowedHosts.end());
2007     }
2008     
2009     return authenticationScheme <= kWKProtectionSpaceAuthenticationSchemeHTTPDigest || authenticationScheme == kWKProtectionSpaceAuthenticationSchemeOAuth;
2010 }
2011
2012 void TestController::didFinishNavigation(WKPageRef page, WKNavigationRef navigation)
2013 {
2014     if (m_state != Resetting)
2015         return;
2016
2017     WKRetainPtr<WKURLRef> wkURL(AdoptWK, WKFrameCopyURL(WKPageGetMainFrame(page)));
2018     if (!WKURLIsEqual(wkURL.get(), blankURL()))
2019         return;
2020
2021     m_doneResetting = true;
2022     singleton().notifyDone();
2023 }
2024
2025 void TestController::didReceiveAuthenticationChallenge(WKPageRef page, WKAuthenticationChallengeRef authenticationChallenge)
2026 {
2027     WKProtectionSpaceRef protectionSpace = WKAuthenticationChallengeGetProtectionSpace(authenticationChallenge);
2028     WKAuthenticationDecisionListenerRef decisionListener = WKAuthenticationChallengeGetDecisionListener(authenticationChallenge);
2029     WKProtectionSpaceAuthenticationScheme authenticationScheme = WKProtectionSpaceGetAuthenticationScheme(protectionSpace);
2030
2031     if (authenticationScheme == kWKProtectionSpaceAuthenticationSchemeServerTrustEvaluationRequested) {
2032         // Any non-empty credential signals to accept the server trust. Since the cross-platform API
2033         // doesn't expose a way to create a credential from server trust, we use a password credential.
2034
2035         WKRetainPtr<WKCredentialRef> credential = adoptWK(WKCredentialCreate(toWK("accept server trust").get(), toWK("").get(), kWKCredentialPersistenceNone));
2036         WKAuthenticationDecisionListenerUseCredential(decisionListener, credential.get());
2037         return;
2038     }
2039
2040     if (m_rejectsProtectionSpaceAndContinueForAuthenticationChallenges) {
2041         m_currentInvocation->outputText("Simulating reject protection space and continue for authentication challenge\n");
2042         WKAuthenticationDecisionListenerRejectProtectionSpaceAndContinue(decisionListener);
2043         return;
2044     }
2045
2046     std::string host = toSTD(adoptWK(WKProtectionSpaceCopyHost(protectionSpace)).get());
2047     int port = WKProtectionSpaceGetPort(protectionSpace);
2048     String message = String::format("%s:%d - didReceiveAuthenticationChallenge - %s - ", host.c_str(), port, toString(authenticationScheme));
2049     if (!m_handlesAuthenticationChallenges)
2050         message.append("Simulating cancelled authentication sheet\n");
2051     else
2052         message.append(String::format("Responding with %s:%s\n", m_authenticationUsername.utf8().data(), m_authenticationPassword.utf8().data()));
2053     m_currentInvocation->outputText(message);
2054
2055     if (!m_handlesAuthenticationChallenges) {
2056         WKAuthenticationDecisionListenerUseCredential(decisionListener, 0);
2057         return;
2058     }
2059     WKRetainPtr<WKStringRef> username(AdoptWK, WKStringCreateWithUTF8CString(m_authenticationUsername.utf8().data()));
2060     WKRetainPtr<WKStringRef> password(AdoptWK, WKStringCreateWithUTF8CString(m_authenticationPassword.utf8().data()));
2061     WKRetainPtr<WKCredentialRef> credential(AdoptWK, WKCredentialCreate(username.get(), password.get(), kWKCredentialPersistenceForSession));
2062     WKAuthenticationDecisionListenerUseCredential(decisionListener, credential.get());
2063 }
2064
2065     
2066 // WKContextDownloadClient
2067
2068 void TestController::downloadDidStart(WKContextRef context, WKDownloadRef download, const void* clientInfo)
2069 {
2070     static_cast<TestController*>(const_cast<void*>(clientInfo))->downloadDidStart(context, download);
2071 }
2072     
2073 WKStringRef TestController::decideDestinationWithSuggestedFilename(WKContextRef context, WKDownloadRef download, WKStringRef filename, bool* allowOverwrite, const void* clientInfo)
2074 {
2075     return static_cast<TestController*>(const_cast<void*>(clientInfo))->decideDestinationWithSuggestedFilename(context, download, filename, allowOverwrite);
2076 }
2077
2078 void TestController::downloadDidFinish(WKContextRef context, WKDownloadRef download, const void* clientInfo)
2079 {
2080     static_cast<TestController*>(const_cast<void*>(clientInfo))->downloadDidFinish(context, download);
2081 }
2082
2083 void TestController::downloadDidFail(WKContextRef context, WKDownloadRef download, WKErrorRef error, const void* clientInfo)
2084 {
2085     static_cast<TestController*>(const_cast<void*>(clientInfo))->downloadDidFail(context, download, error);
2086 }
2087
2088 void TestController::downloadDidCancel(WKContextRef context, WKDownloadRef download, const void* clientInfo)
2089 {
2090     static_cast<TestController*>(const_cast<void*>(clientInfo))->downloadDidCancel(context, download);
2091 }
2092
2093 void TestController::downloadDidReceiveServerRedirectToURL(WKContextRef context, WKDownloadRef download, WKURLRef url, const void* clientInfo)
2094 {
2095     static_cast<TestController*>(const_cast<void*>(clientInfo))->downloadDidReceiveServerRedirectToURL(context, download, url);
2096 }
2097
2098 void TestController::downloadDidStart(WKContextRef context, WKDownloadRef download)
2099 {
2100     if (m_shouldLogDownloadCallbacks)
2101         m_currentInvocation->outputText("Download started.\n");
2102 }
2103
2104 WKStringRef TestController::decideDestinationWithSuggestedFilename(WKContextRef, WKDownloadRef, WKStringRef filename, bool*& allowOverwrite)
2105 {
2106     String suggestedFilename = toWTFString(filename);
2107
2108     if (m_shouldLogDownloadCallbacks) {
2109         StringBuilder builder;
2110         builder.append("Downloading URL with suggested filename \"");
2111         builder.append(suggestedFilename);
2112         builder.append("\"\n");
2113         m_currentInvocation->outputText(builder.toString());
2114     }
2115
2116     const char* dumpRenderTreeTemp = libraryPathForTesting();
2117     if (!dumpRenderTreeTemp)
2118         return nullptr;
2119
2120     *allowOverwrite = true;
2121     String temporaryFolder = String::fromUTF8(dumpRenderTreeTemp);
2122     if (suggestedFilename.isEmpty())
2123         suggestedFilename = "Unknown";
2124
2125     return toWK(temporaryFolder + "/" + suggestedFilename).leakRef();
2126 }
2127
2128 void TestController::downloadDidFinish(WKContextRef, WKDownloadRef)
2129 {
2130     if (m_shouldLogDownloadCallbacks)
2131         m_currentInvocation->outputText("Download completed.\n");
2132     m_currentInvocation->notifyDownloadDone();
2133 }
2134
2135 void TestController::downloadDidReceiveServerRedirectToURL(WKContextRef, WKDownloadRef, WKURLRef url)
2136 {
2137     if (m_shouldLogDownloadCallbacks) {
2138         StringBuilder builder;
2139         builder.appendLiteral("Download was redirected to \"");
2140         WKRetainPtr<WKStringRef> urlStringWK = adoptWK(WKURLCopyString(url));
2141         builder.append(toSTD(urlStringWK).c_str());
2142         builder.appendLiteral("\".\n");
2143         m_currentInvocation->outputText(builder.toString());
2144     }
2145 }
2146
2147 void TestController::downloadDidFail(WKContextRef, WKDownloadRef, WKErrorRef error)
2148 {
2149     if (m_shouldLogDownloadCallbacks) {
2150         String message = String::format("Download failed.\n");
2151         m_currentInvocation->outputText(message);
2152
2153         WKRetainPtr<WKStringRef> errorDomain = adoptWK(WKErrorCopyDomain(error));
2154         WKRetainPtr<WKStringRef> errorDescription = adoptWK(WKErrorCopyLocalizedDescription(error));
2155         int errorCode = WKErrorGetErrorCode(error);
2156
2157         StringBuilder errorBuilder;
2158         errorBuilder.append("Failed: ");
2159         errorBuilder.append(toWTFString(errorDomain));
2160         errorBuilder.append(", code=");
2161         errorBuilder.appendNumber(errorCode);
2162         errorBuilder.append(", description=");
2163         errorBuilder.append(toWTFString(errorDescription));
2164         errorBuilder.append("\n");
2165
2166         m_currentInvocation->outputText(errorBuilder.toString());
2167     }
2168     m_currentInvocation->notifyDownloadDone();
2169 }
2170
2171 void TestController::downloadDidCancel(WKContextRef, WKDownloadRef)
2172 {
2173     if (m_shouldLogDownloadCallbacks)
2174         m_currentInvocation->outputText("Download cancelled.\n");
2175     m_currentInvocation->notifyDownloadDone();
2176 }
2177
2178 void TestController::processDidCrash()
2179 {
2180     // This function can be called multiple times when crash logs are being saved on Windows, so
2181     // ensure we only print the crashed message once.
2182     if (!m_didPrintWebProcessCrashedMessage) {
2183         pid_t pid = WKPageGetProcessIdentifier(m_mainWebView->page());
2184         fprintf(stderr, "#CRASHED - %s (pid %ld)\n", webProcessName(), static_cast<long>(pid));
2185         fflush(stderr);
2186         m_didPrintWebProcessCrashedMessage = true;
2187     }
2188
2189     if (m_shouldExitWhenWebProcessCrashes)
2190         exit(1);
2191 }
2192
2193 void TestController::didBeginNavigationGesture(WKPageRef)
2194 {
2195     m_currentInvocation->didBeginSwipe();
2196 }
2197
2198 void TestController::willEndNavigationGesture(WKPageRef, WKBackForwardListItemRef)
2199 {
2200     m_currentInvocation->willEndSwipe();
2201 }
2202
2203 void TestController::didEndNavigationGesture(WKPageRef, WKBackForwardListItemRef)
2204 {
2205     m_currentInvocation->didEndSwipe();
2206 }
2207
2208 void TestController::didRemoveNavigationGestureSnapshot(WKPageRef)
2209 {
2210     m_currentInvocation->didRemoveSwipeSnapshot();
2211 }
2212
2213 void TestController::simulateWebNotificationClick(uint64_t notificationID)
2214 {
2215     m_webNotificationProvider.simulateWebNotificationClick(mainWebView()->page(), notificationID);
2216 }
2217
2218 void TestController::setGeolocationPermission(bool enabled)
2219 {
2220     m_isGeolocationPermissionSet = true;
2221     m_isGeolocationPermissionAllowed = enabled;
2222     decidePolicyForGeolocationPermissionRequestIfPossible();
2223 }
2224
2225 void TestController::setMockGeolocationPosition(double latitude, double longitude, double accuracy, bool providesAltitude, double altitude, bool providesAltitudeAccuracy, double altitudeAccuracy, bool providesHeading, double heading, bool providesSpeed, double speed, bool providesFloorLevel, double floorLevel)
2226 {
2227     m_geolocationProvider->setPosition(latitude, longitude, accuracy, providesAltitude, altitude, providesAltitudeAccuracy, altitudeAccuracy, providesHeading, heading, providesSpeed, speed, providesFloorLevel, floorLevel);
2228 }
2229
2230 void TestController::setMockGeolocationPositionUnavailableError(WKStringRef errorMessage)
2231 {
2232     m_geolocationProvider->setPositionUnavailableError(errorMessage);
2233 }
2234
2235 void TestController::handleGeolocationPermissionRequest(WKGeolocationPermissionRequestRef geolocationPermissionRequest)
2236 {
2237     m_geolocationPermissionRequests.append(geolocationPermissionRequest);
2238     decidePolicyForGeolocationPermissionRequestIfPossible();
2239 }
2240
2241 bool TestController::isGeolocationProviderActive() const
2242 {
2243     return m_geolocationProvider->isActive();
2244 }
2245
2246 static String originUserVisibleName(WKSecurityOriginRef origin)
2247 {
2248     if (!origin)
2249         return emptyString();
2250
2251     std::string host = toSTD(adoptWK(WKSecurityOriginCopyHost(origin))).c_str();
2252     std::string protocol = toSTD(adoptWK(WKSecurityOriginCopyProtocol(origin))).c_str();
2253
2254     if (!host.length() || !protocol.length())
2255         return emptyString();
2256
2257     unsigned short port = WKSecurityOriginGetPort(origin);
2258     if (port)
2259         return String::format("%s://%s:%d", protocol.c_str(), host.c_str(), port);
2260
2261     return String::format("%s://%s", protocol.c_str(), host.c_str());
2262 }
2263
2264 static String userMediaOriginHash(WKSecurityOriginRef userMediaDocumentOrigin, WKSecurityOriginRef topLevelDocumentOrigin)
2265 {
2266     String userMediaDocumentOriginString = originUserVisibleName(userMediaDocumentOrigin);
2267     String topLevelDocumentOriginString = originUserVisibleName(topLevelDocumentOrigin);
2268
2269     if (topLevelDocumentOriginString.isEmpty())
2270         return userMediaDocumentOriginString;
2271
2272     return String::format("%s-%s", userMediaDocumentOriginString.utf8().data(), topLevelDocumentOriginString.utf8().data());
2273 }
2274
2275 static String userMediaOriginHash(WKStringRef userMediaDocumentOriginString, WKStringRef topLevelDocumentOriginString)
2276 {
2277     auto userMediaDocumentOrigin = adoptWK(WKSecurityOriginCreateFromString(userMediaDocumentOriginString));
2278     if (!WKStringGetLength(topLevelDocumentOriginString))
2279         return userMediaOriginHash(userMediaDocumentOrigin.get(), nullptr);
2280
2281     auto topLevelDocumentOrigin = adoptWK(WKSecurityOriginCreateFromString(topLevelDocumentOriginString));
2282     return userMediaOriginHash(userMediaDocumentOrigin.get(), topLevelDocumentOrigin.get());
2283 }
2284
2285 void TestController::setUserMediaPermission(bool enabled)
2286 {
2287     m_isUserMediaPermissionSet = true;
2288     m_isUserMediaPermissionAllowed = enabled;
2289     decidePolicyForUserMediaPermissionRequestIfPossible();
2290 }
2291
2292 void TestController::resetUserMediaPermission()
2293 {
2294     m_isUserMediaPermissionSet = false;
2295 }
2296
2297 class OriginSettings : public RefCounted<OriginSettings> {
2298 public:
2299     explicit OriginSettings()
2300     {
2301     }
2302
2303     bool persistentPermission() const { return m_persistentPermission; }
2304     void setPersistentPermission(bool permission) { m_persistentPermission = permission; }
2305
2306     String persistentSalt() const { return m_persistentSalt; }
2307     void setPersistentSalt(const String& salt) { m_persistentSalt = salt; }
2308
2309     HashMap<uint64_t, String>& ephemeralSalts() { return m_ephemeralSalts; }
2310
2311     void incrementRequestCount() { ++m_requestCount; }
2312     void resetRequestCount() { m_requestCount = 0; }
2313     unsigned requestCount() const { return m_requestCount; }
2314
2315 private:
2316     HashMap<uint64_t, String> m_ephemeralSalts;
2317     String m_persistentSalt;
2318     unsigned m_requestCount { 0 };
2319     bool m_persistentPermission { false };
2320 };
2321
2322 String TestController::saltForOrigin(WKFrameRef frame, String originHash)
2323 {
2324     auto& settings = settingsForOrigin(originHash);
2325     auto& ephemeralSalts = settings.ephemeralSalts();
2326     auto frameInfo = adoptWK(WKFrameCreateFrameInfo(frame));
2327     auto frameHandle = WKFrameInfoGetFrameHandleRef(frameInfo.get());
2328     uint64_t frameIdentifier = WKFrameHandleGetFrameID(frameHandle);
2329     String frameSalt = ephemeralSalts.get(frameIdentifier);
2330
2331     if (settings.persistentPermission()) {
2332         if (frameSalt.length())
2333             return frameSalt;
2334
2335         if (!settings.persistentSalt().length())
2336             settings.setPersistentSalt(createCanonicalUUIDString());
2337
2338         return settings.persistentSalt();
2339     }
2340
2341     if (!frameSalt.length()) {
2342         frameSalt = createCanonicalUUIDString();
2343         ephemeralSalts.add(frameIdentifier, frameSalt);
2344     }
2345
2346     return frameSalt;
2347 }
2348
2349 void TestController::setUserMediaPersistentPermissionForOrigin(bool permission, WKStringRef userMediaDocumentOriginString, WKStringRef topLevelDocumentOriginString)
2350 {
2351     auto originHash = userMediaOriginHash(userMediaDocumentOriginString, topLevelDocumentOriginString);
2352     auto& settings = settingsForOrigin(originHash);
2353     settings.setPersistentPermission(permission);
2354 }
2355
2356 void TestController::handleCheckOfUserMediaPermissionForOrigin(WKFrameRef frame, WKSecurityOriginRef userMediaDocumentOrigin, WKSecurityOriginRef topLevelDocumentOrigin, const WKUserMediaPermissionCheckRef& checkRequest)
2357 {
2358     auto originHash = userMediaOriginHash(userMediaDocumentOrigin, topLevelDocumentOrigin);
2359     auto salt = saltForOrigin(frame, originHash);
2360     WKRetainPtr<WKStringRef> saltString = adoptWK(WKStringCreateWithUTF8CString(salt.utf8().data()));
2361
2362     WKUserMediaPermissionCheckSetUserMediaAccessInfo(checkRequest, saltString.get(), settingsForOrigin(originHash).persistentPermission());
2363 }
2364
2365 void TestController::handleUserMediaPermissionRequest(WKFrameRef frame, WKSecurityOriginRef userMediaDocumentOrigin, WKSecurityOriginRef topLevelDocumentOrigin, WKUserMediaPermissionRequestRef request)
2366 {
2367     auto originHash = userMediaOriginHash(userMediaDocumentOrigin, topLevelDocumentOrigin);
2368     m_userMediaPermissionRequests.append(std::make_pair(originHash, request));
2369     decidePolicyForUserMediaPermissionRequestIfPossible();
2370 }
2371
2372 OriginSettings& TestController::settingsForOrigin(const String& originHash)
2373 {
2374     RefPtr<OriginSettings> settings = m_cachedUserMediaPermissions.get(originHash);
2375     if (!settings) {
2376         settings = adoptRef(*new OriginSettings());
2377         m_cachedUserMediaPermissions.add(originHash, settings);
2378     }
2379
2380     return *settings;
2381 }
2382
2383 unsigned TestController::userMediaPermissionRequestCountForOrigin(WKStringRef userMediaDocumentOriginString, WKStringRef topLevelDocumentOriginString)
2384 {
2385     auto originHash = userMediaOriginHash(userMediaDocumentOriginString, topLevelDocumentOriginString);
2386     return settingsForOrigin(originHash).requestCount();
2387 }
2388
2389 void TestController::resetUserMediaPermissionRequestCountForOrigin(WKStringRef userMediaDocumentOriginString, WKStringRef topLevelDocumentOriginString)
2390 {
2391     auto originHash = userMediaOriginHash(userMediaDocumentOriginString, topLevelDocumentOriginString);
2392     settingsForOrigin(originHash).resetRequestCount();
2393 }
2394
2395 void TestController::decidePolicyForUserMediaPermissionRequestIfPossible()
2396 {
2397     if (!m_isUserMediaPermissionSet)
2398         return;
2399
2400     for (auto& pair : m_userMediaPermissionRequests) {
2401         auto originHash = pair.first;
2402         auto request = pair.second.get();
2403
2404         auto& settings = settingsForOrigin(originHash);
2405         settings.incrementRequestCount();
2406
2407         if (!m_isUserMediaPermissionAllowed && !settings.persistentPermission()) {
2408             WKUserMediaPermissionRequestDeny(request, kWKPermissionDenied);
2409             continue;
2410         }
2411
2412         WKRetainPtr<WKArrayRef> audioDeviceUIDs = adoptWK(WKUserMediaPermissionRequestAudioDeviceUIDs(request));
2413         WKRetainPtr<WKArrayRef> videoDeviceUIDs = adoptWK(WKUserMediaPermissionRequestVideoDeviceUIDs(request));
2414
2415         if (!WKArrayGetSize(videoDeviceUIDs.get()) && !WKArrayGetSize(audioDeviceUIDs.get())) {
2416             WKUserMediaPermissionRequestDeny(request, kWKNoConstraints);
2417             continue;
2418         }
2419
2420         WKRetainPtr<WKStringRef> videoDeviceUID;
2421         if (WKArrayGetSize(videoDeviceUIDs.get()))
2422             videoDeviceUID = reinterpret_cast<WKStringRef>(WKArrayGetItemAtIndex(videoDeviceUIDs.get(), 0));
2423         else
2424             videoDeviceUID = adoptWK(WKStringCreateWithUTF8CString(""));
2425
2426         WKRetainPtr<WKStringRef> audioDeviceUID;
2427         if (WKArrayGetSize(audioDeviceUIDs.get()))
2428             audioDeviceUID = reinterpret_cast<WKStringRef>(WKArrayGetItemAtIndex(audioDeviceUIDs.get(), 0));
2429         else
2430             audioDeviceUID = adoptWK(WKStringCreateWithUTF8CString(""));
2431
2432         WKUserMediaPermissionRequestAllow(request, audioDeviceUID.get(), videoDeviceUID.get());
2433     }
2434     m_userMediaPermissionRequests.clear();
2435 }
2436
2437 void TestController::setCustomPolicyDelegate(bool enabled, bool permissive)
2438 {
2439     m_policyDelegateEnabled = enabled;
2440     m_policyDelegatePermissive = permissive;
2441 }
2442
2443 void TestController::decidePolicyForGeolocationPermissionRequestIfPossible()
2444 {
2445     if (!m_isGeolocationPermissionSet)
2446         return;
2447
2448     for (size_t i = 0; i < m_geolocationPermissionRequests.size(); ++i) {
2449         WKGeolocationPermissionRequestRef permissionRequest = m_geolocationPermissionRequests[i].get();
2450         if (m_isGeolocationPermissionAllowed)
2451             WKGeolocationPermissionRequestAllow(permissionRequest);
2452         else
2453             WKGeolocationPermissionRequestDeny(permissionRequest);
2454     }
2455     m_geolocationPermissionRequests.clear();
2456 }
2457
2458 void TestController::decidePolicyForNotificationPermissionRequest(WKPageRef page, WKSecurityOriginRef origin, WKNotificationPermissionRequestRef request, const void*)
2459 {
2460     TestController::singleton().decidePolicyForNotificationPermissionRequest(page, origin, request);
2461 }
2462
2463 void TestController::decidePolicyForNotificationPermissionRequest(WKPageRef, WKSecurityOriginRef, WKNotificationPermissionRequestRef request)
2464 {
2465     WKNotificationPermissionRequestAllow(request);
2466 }
2467
2468 void TestController::unavailablePluginButtonClicked(WKPageRef, WKPluginUnavailabilityReason, WKDictionaryRef, const void*)
2469 {
2470     printf("MISSING PLUGIN BUTTON PRESSED\n");
2471 }
2472
2473 void TestController::decidePolicyForNavigationAction(WKPageRef, WKNavigationActionRef navigationAction, WKFramePolicyListenerRef listener, WKTypeRef, const void* clientInfo)
2474 {
2475     static_cast<TestController*>(const_cast<void*>(clientInfo))->decidePolicyForNavigationAction(listener);
2476 }
2477
2478 void TestController::decidePolicyForNavigationAction(WKFramePolicyListenerRef listener)
2479 {
2480     WKRetainPtr<WKFramePolicyListenerRef> retainedListener { listener };
2481     const bool shouldIgnore { m_policyDelegateEnabled && !m_policyDelegatePermissive };
2482     auto decisionFunction = [shouldIgnore, retainedListener]() {
2483         if (shouldIgnore)
2484             WKFramePolicyListenerIgnore(retainedListener.get());
2485         else
2486             WKFramePolicyListenerUse(retainedListener.get());
2487     };
2488
2489     if (m_shouldDecideNavigationPolicyAfterDelay)
2490         RunLoop::main().dispatch(WTFMove(decisionFunction));
2491     else
2492         decisionFunction();
2493 }
2494
2495 void TestController::decidePolicyForNavigationResponse(WKPageRef, WKNavigationResponseRef navigationResponse, WKFramePolicyListenerRef listener, WKTypeRef, const void* clientInfo)
2496 {
2497     static_cast<TestController*>(const_cast<void*>(clientInfo))->decidePolicyForNavigationResponse(navigationResponse, listener);
2498 }
2499
2500 void TestController::decidePolicyForNavigationResponse(WKNavigationResponseRef navigationResponse, WKFramePolicyListenerRef listener)
2501 {
2502     WKRetainPtr<WKNavigationResponseRef> retainedNavigationResponse { navigationResponse };
2503     WKRetainPtr<WKFramePolicyListenerRef> retainedListener { listener };
2504
2505     bool shouldDownloadUndisplayableMIMETypes = m_shouldDownloadUndisplayableMIMETypes;
2506     auto decisionFunction = [shouldDownloadUndisplayableMIMETypes, retainedNavigationResponse, retainedListener]() {
2507         // Even though Response was already checked by WKBundlePagePolicyClient, the check did not include plugins
2508         // so we have to re-check again.
2509         if (WKNavigationResponseCanShowMIMEType(retainedNavigationResponse.get())) {
2510             WKFramePolicyListenerUse(retainedListener.get());
2511             return;
2512         }
2513
2514         if (shouldDownloadUndisplayableMIMETypes)
2515             WKFramePolicyListenerDownload(retainedListener.get());
2516         else
2517             WKFramePolicyListenerIgnore(retainedListener.get());
2518     };
2519
2520     if (m_shouldDecideResponsePolicyAfterDelay)
2521         RunLoop::main().dispatch(WTFMove(decisionFunction));
2522     else
2523         decisionFunction();
2524 }
2525
2526 void TestController::didNavigateWithNavigationData(WKContextRef, WKPageRef, WKNavigationDataRef navigationData, WKFrameRef frame, const void* clientInfo)
2527 {
2528     static_cast<TestController*>(const_cast<void*>(clientInfo))->didNavigateWithNavigationData(navigationData, frame);
2529 }
2530
2531 void TestController::didNavigateWithNavigationData(WKNavigationDataRef navigationData, WKFrameRef)
2532 {
2533     if (m_state != RunningTest)
2534         return;
2535
2536     if (!m_shouldLogHistoryClientCallbacks)
2537         return;
2538
2539     // URL
2540     WKRetainPtr<WKURLRef> urlWK = adoptWK(WKNavigationDataCopyURL(navigationData));
2541     WKRetainPtr<WKStringRef> urlStringWK = adoptWK(WKURLCopyString(urlWK.get()));
2542     // Title
2543     WKRetainPtr<WKStringRef> titleWK = adoptWK(WKNavigationDataCopyTitle(navigationData));
2544     // HTTP method
2545     WKRetainPtr<WKURLRequestRef> requestWK = adoptWK(WKNavigationDataCopyOriginalRequest(navigationData));
2546     WKRetainPtr<WKStringRef> methodWK = adoptWK(WKURLRequestCopyHTTPMethod(requestWK.get()));
2547
2548     // FIXME: Determine whether the navigation was successful / a client redirect rather than hard-coding the message here.
2549     m_currentInvocation->outputText(String::format("WebView navigated to url \"%s\" with title \"%s\" with HTTP equivalent method \"%s\".  The navigation was successful and was not a client redirect.\n",
2550         toSTD(urlStringWK).c_str(), toSTD(titleWK).c_str(), toSTD(methodWK).c_str()));
2551 }
2552
2553 void TestController::didPerformClientRedirect(WKContextRef, WKPageRef, WKURLRef sourceURL, WKURLRef destinationURL, WKFrameRef frame, const void* clientInfo)
2554 {
2555     static_cast<TestController*>(const_cast<void*>(clientInfo))->didPerformClientRedirect(sourceURL, destinationURL, frame);
2556 }
2557
2558 void TestController::didPerformClientRedirect(WKURLRef sourceURL, WKURLRef destinationURL, WKFrameRef)
2559 {
2560     if (m_state != RunningTest)
2561         return;
2562
2563     if (!m_shouldLogHistoryClientCallbacks)
2564         return;
2565
2566     WKRetainPtr<WKStringRef> sourceStringWK = adoptWK(WKURLCopyString(sourceURL));
2567     WKRetainPtr<WKStringRef> destinationStringWK = adoptWK(WKURLCopyString(destinationURL));
2568
2569     m_currentInvocation->outputText(String::format("WebView performed a client redirect from \"%s\" to \"%s\".\n", toSTD(sourceStringWK).c_str(), toSTD(destinationStringWK).c_str()));
2570 }
2571
2572 void TestController::didPerformServerRedirect(WKContextRef, WKPageRef, WKURLRef sourceURL, WKURLRef destinationURL, WKFrameRef frame, const void* clientInfo)
2573 {
2574     static_cast<TestController*>(const_cast<void*>(clientInfo))->didPerformServerRedirect(sourceURL, destinationURL, frame);
2575 }
2576
2577 void TestController::didPerformServerRedirect(WKURLRef sourceURL, WKURLRef destinationURL, WKFrameRef)
2578 {
2579     if (m_state != RunningTest)
2580         return;
2581
2582     if (!m_shouldLogHistoryClientCallbacks)
2583         return;
2584
2585     WKRetainPtr<WKStringRef> sourceStringWK = adoptWK(WKURLCopyString(sourceURL));
2586     WKRetainPtr<WKStringRef> destinationStringWK = adoptWK(WKURLCopyString(destinationURL));
2587
2588     m_currentInvocation->outputText(String::format("WebView performed a server redirect from \"%s\" to \"%s\".\n", toSTD(sourceStringWK).c_str(), toSTD(destinationStringWK).c_str()));
2589 }
2590
2591 void TestController::didUpdateHistoryTitle(WKContextRef, WKPageRef, WKStringRef title, WKURLRef URL, WKFrameRef frame, const void* clientInfo)
2592 {
2593     static_cast<TestController*>(const_cast<void*>(clientInfo))->didUpdateHistoryTitle(title, URL, frame);
2594 }
2595
2596 void TestController::didUpdateHistoryTitle(WKStringRef title, WKURLRef URL, WKFrameRef)
2597 {
2598     if (m_state != RunningTest)
2599         return;
2600
2601     if (!m_shouldLogHistoryClientCallbacks)
2602         return;
2603
2604     WKRetainPtr<WKStringRef> urlStringWK(AdoptWK, WKURLCopyString(URL));
2605     m_currentInvocation->outputText(String::format("WebView updated the title for history URL \"%s\" to \"%s\".\n", toSTD(urlStringWK).c_str(), toSTD(title).c_str()));
2606 }
2607
2608 void TestController::setNavigationGesturesEnabled(bool value)
2609 {
2610     m_mainWebView->setNavigationGesturesEnabled(value);
2611 }
2612
2613 void TestController::setIgnoresViewportScaleLimits(bool ignoresViewportScaleLimits)
2614 {
2615     WKPageSetIgnoresViewportScaleLimits(m_mainWebView->page(), ignoresViewportScaleLimits);
2616 }
2617
2618 void TestController::terminateNetworkProcess()
2619 {
2620     WKContextTerminateNetworkProcess(platformContext());
2621 }
2622
2623 void TestController::terminateServiceWorkerProcess()
2624 {
2625     WKContextTerminateServiceWorkerProcess(platformContext());
2626 }
2627
2628 void TestController::terminateStorageProcess()
2629 {
2630     WKContextTerminateStorageProcess(platformContext());
2631 }
2632
2633 #if !PLATFORM(COCOA)
2634 void TestController::platformWillRunTest(const TestInvocation&)
2635 {
2636 }
2637
2638 void TestController::platformCreateWebView(WKPageConfigurationRef configuration, const TestOptions& options)
2639 {
2640     m_mainWebView = std::make_unique<PlatformWebView>(configuration, options);
2641 }
2642
2643 PlatformWebView* TestController::platformCreateOtherPage(PlatformWebView* parentView, WKPageConfigurationRef configuration, const TestOptions& options)
2644 {
2645     return new PlatformWebView(configuration, options);
2646 }
2647
2648 WKContextRef TestController::platformAdjustContext(WKContextRef context, WKContextConfigurationRef contextConfiguration)
2649 {
2650     auto* dataStore = WKContextGetWebsiteDataStore(context);
2651     WKWebsiteDataStoreSetResourceLoadStatisticsEnabled(dataStore, true);
2652
2653     if (const char* dumpRenderTreeTemp = libraryPathForTesting()) {
2654         String temporaryFolder = String::fromUTF8(dumpRenderTreeTemp);
2655         const char separator = '/';
2656
2657         WKWebsiteDataStoreSetServiceWorkerRegistrationDirectory(dataStore, toWK(temporaryFolder + separator + "ServiceWorkers").get());
2658     }
2659
2660     return context;
2661 }
2662
2663 void TestController::platformResetStateToConsistentValues()
2664 {
2665 }
2666
2667 unsigned TestController::imageCountInGeneralPasteboard() const
2668 {
2669     return 0;
2670 }
2671
2672 void TestController::removeAllSessionCredentials()
2673 {
2674 }
2675
2676 void TestController::getAllStorageAccessEntries()
2677 {
2678 }
2679
2680 #endif
2681
2682 struct ClearServiceWorkerRegistrationsCallbackContext {
2683     explicit ClearServiceWorkerRegistrationsCallbackContext(TestController& controller)
2684         : testController(controller)
2685     {
2686     }
2687
2688     TestController& testController;
2689     bool done { false };
2690 };
2691
2692 static void clearServiceWorkerRegistrationsCallback(void* userData)
2693 {
2694     auto* context = static_cast<ClearServiceWorkerRegistrationsCallbackContext*>(userData);
2695     context->done = true;
2696     context->testController.notifyDone();
2697 }
2698
2699 void TestController::clearServiceWorkerRegistrations()
2700 {
2701     auto websiteDataStore = WKContextGetWebsiteDataStore(platformContext());
2702     ClearServiceWorkerRegistrationsCallbackContext context(*this);
2703
2704     WKWebsiteDataStoreRemoveAllServiceWorkerRegistrations(websiteDataStore, &context, clearServiceWorkerRegistrationsCallback);
2705     runUntil(context.done, noTimeout);
2706 }
2707
2708 struct ClearDOMCacheCallbackContext {
2709     explicit ClearDOMCacheCallbackContext(TestController& controller)
2710         : testController(controller)
2711     {
2712     }
2713
2714     TestController& testController;
2715     bool done { false };
2716 };
2717
2718 static void clearDOMCacheCallback(void* userData)
2719 {
2720     auto* context = static_cast<ClearDOMCacheCallbackContext*>(userData);
2721     context->done = true;
2722     context->testController.notifyDone();
2723 }
2724
2725 void TestController::clearDOMCache(WKStringRef origin)
2726 {
2727     auto websiteDataStore = WKContextGetWebsiteDataStore(platformContext());
2728     ClearDOMCacheCallbackContext context(*this);
2729
2730     auto cacheOrigin = adoptWK(WKSecurityOriginCreateFromString(origin));
2731     WKWebsiteDataStoreRemoveFetchCacheForOrigin(websiteDataStore, cacheOrigin.get(), &context, clearDOMCacheCallback);
2732     runUntil(context.done, noTimeout);
2733 }
2734
2735 void TestController::clearDOMCaches()
2736 {
2737     auto websiteDataStore = WKContextGetWebsiteDataStore(platformContext());
2738     ClearDOMCacheCallbackContext context(*this);
2739
2740     WKWebsiteDataStoreRemoveAllFetchCaches(websiteDataStore, &context, clearDOMCacheCallback);
2741     runUntil(context.done, noTimeout);
2742 }
2743
2744 struct FetchCacheOriginsCallbackContext {
2745     FetchCacheOriginsCallbackContext(TestController& controller, WKStringRef origin)
2746         : testController(controller)
2747         , origin(origin)
2748     {
2749     }
2750
2751     TestController& testController;
2752     WKStringRef origin;
2753
2754     bool done { false };
2755     bool result { false };
2756 };
2757
2758 static void fetchCacheOriginsCallback(WKArrayRef origins, void* userData)
2759 {
2760     auto* context = static_cast<FetchCacheOriginsCallbackContext*>(userData);
2761     context->done = true;
2762
2763     auto size = WKArrayGetSize(origins);
2764     for (size_t index = 0; index < size && !context->result; ++index) {
2765         WKSecurityOriginRef securityOrigin = reinterpret_cast<WKSecurityOriginRef>(WKArrayGetItemAtIndex(origins, index));
2766         if (WKStringIsEqual(context->origin, adoptWK(WKSecurityOriginCopyToString(securityOrigin)).get()))
2767             context->result = true;
2768     }
2769     context->testController.notifyDone();
2770 }
2771
2772 bool TestController::hasDOMCache(WKStringRef origin)
2773 {
2774     auto* dataStore = WKContextGetWebsiteDataStore(platformContext());
2775     FetchCacheOriginsCallbackContext context(*this, origin);
2776     WKWebsiteDataStoreGetFetchCacheOrigins(dataStore, &context, fetchCacheOriginsCallback);
2777     runUntil(context.done, noTimeout);
2778     return context.result;
2779 }
2780
2781 struct FetchCacheSizeForOriginCallbackContext {
2782     explicit FetchCacheSizeForOriginCallbackContext(TestController& controller)
2783         : testController(controller)
2784     {
2785     }
2786
2787     TestController& testController;
2788
2789     bool done { false };
2790     uint64_t result { 0 };
2791 };
2792
2793 static void fetchCacheSizeForOriginCallback(uint64_t size, void* userData)
2794 {
2795     auto* context = static_cast<FetchCacheSizeForOriginCallbackContext*>(userData);
2796     context->done = true;
2797     context->result = size;
2798     context->testController.notifyDone();
2799 }
2800
2801 uint64_t TestController::domCacheSize(WKStringRef origin)
2802 {
2803     auto* dataStore = WKContextGetWebsiteDataStore(platformContext());
2804     FetchCacheSizeForOriginCallbackContext context(*this);
2805     WKWebsiteDataStoreGetFetchCacheSizeForOrigin(dataStore, origin, &context, fetchCacheSizeForOriginCallback);
2806     runUntil(context.done, noTimeout);
2807     return context.result;
2808 }
2809
2810 struct ResourceStatisticsCallbackContext {
2811     explicit ResourceStatisticsCallbackContext(TestController& controller)
2812         : testController(controller)
2813     {
2814     }
2815
2816     TestController& testController;
2817     bool done { false };
2818     bool result { false };
2819     WKRetainPtr<WKStringRef> resourceLoadStatisticsRepresentation;
2820 };
2821     
2822 static void resourceStatisticsStringResultCallback(WKStringRef resourceLoadStatisticsRepresentation, void* userData)
2823 {
2824     auto* context = static_cast<ResourceStatisticsCallbackContext*>(userData);
2825     context->resourceLoadStatisticsRepresentation = resourceLoadStatisticsRepresentation;
2826     context->done = true;
2827     context->testController.notifyDone();
2828 }
2829
2830 static void resourceStatisticsVoidResultCallback(void* userData)
2831 {
2832     auto* context = static_cast<ResourceStatisticsCallbackContext*>(userData);
2833     context->done = true;
2834     context->testController.notifyDone();
2835 }
2836
2837 static void resourceStatisticsBooleanResultCallback(bool result, void* userData)
2838 {
2839     auto* context = static_cast<ResourceStatisticsCallbackContext*>(userData);
2840     context->result = result;
2841     context->done = true;
2842     context->testController.notifyDone();
2843 }
2844
2845 void TestController::setStatisticsDebugMode(bool value)
2846 {
2847     auto* dataStore = WKContextGetWebsiteDataStore(platformContext());
2848     ResourceStatisticsCallbackContext context(*this);
2849     WKWebsiteDataStoreSetResourceLoadStatisticsDebugModeWithCompletionHandler(dataStore, value, &context, resourceStatisticsVoidResultCallback);
2850     runUntil(context.done, noTimeout);
2851     m_currentInvocation->didSetStatisticsDebugMode();
2852 }
2853
2854 void TestController::setStatisticsPrevalentResourceForDebugMode(WKStringRef hostName)
2855 {
2856     auto* dataStore = WKContextGetWebsiteDataStore(platformContext());
2857     ResourceStatisticsCallbackContext context(*this);
2858     WKWebsiteDataStoreSetResourceLoadStatisticsPrevalentResourceForDebugMode(dataStore, hostName, &context, resourceStatisticsVoidResultCallback);
2859     runUntil(context.done, noTimeout);
2860     m_currentInvocation->didSetPrevalentResourceForDebugMode();
2861 }
2862
2863 void TestController::setStatisticsLastSeen(WKStringRef host, double seconds)
2864 {
2865     auto* dataStore = WKContextGetWebsiteDataStore(platformContext());
2866     ResourceStatisticsCallbackContext context(*this);
2867     WKWebsiteDataStoreSetStatisticsLastSeen(dataStore, host, seconds, &context, resourceStatisticsVoidResultCallback);
2868     runUntil(context.done, noTimeout);
2869     m_currentInvocation->didSetLastSeen();
2870 }
2871
2872 void TestController::setStatisticsPrevalentResource(WKStringRef host, bool value)
2873 {
2874     auto* dataStore = WKContextGetWebsiteDataStore(platformContext());
2875     ResourceStatisticsCallbackContext context(*this);
2876     WKWebsiteDataStoreSetStatisticsPrevalentResource(dataStore, host, value, &context, resourceStatisticsVoidResultCallback);
2877     runUntil(context.done, noTimeout);
2878     m_currentInvocation->didSetPrevalentResource();
2879 }
2880
2881 void TestController::setStatisticsVeryPrevalentResource(WKStringRef host, bool value)
2882 {
2883     auto* dataStore = WKContextGetWebsiteDataStore(platformContext());
2884     ResourceStatisticsCallbackContext context(*this);
2885     WKWebsiteDataStoreSetStatisticsVeryPrevalentResource(dataStore, host, value, &context, resourceStatisticsVoidResultCallback);
2886     runUntil(context.done, noTimeout);
2887     m_currentInvocation->didSetVeryPrevalentResource();
2888 }
2889     
2890 String TestController::dumpResourceLoadStatistics()
2891 {
2892     auto* dataStore = WKContextGetWebsiteDataStore(platformContext());
2893     ResourceStatisticsCallbackContext context(*this);
2894     WKWebsiteDataStoreDumpResourceLoadStatistics(dataStore, &context, resourceStatisticsStringResultCallback);
2895     runUntil(context.done, noTimeout);
2896     return toWTFString(context.resourceLoadStatisticsRepresentation.get());
2897 }
2898
2899 bool TestController::isStatisticsPrevalentResource(WKStringRef host)
2900 {
2901     auto* dataStore = WKContextGetWebsiteDataStore(platformContext());
2902     ResourceStatisticsCallbackContext context(*this);
2903     WKWebsiteDataStoreIsStatisticsPrevalentResource(dataStore, host, &context, resourceStatisticsBooleanResultCallback);
2904     runUntil(context.done, noTimeout);
2905     return context.result;
2906 }
2907
2908 bool TestController::isStatisticsVeryPrevalentResource(WKStringRef host)
2909 {
2910     auto* dataStore = WKContextGetWebsiteDataStore(platformContext());
2911     ResourceStatisticsCallbackContext context(*this);
2912     WKWebsiteDataStoreIsStatisticsVeryPrevalentResource(dataStore, host, &context, resourceStatisticsBooleanResultCallback);
2913     runUntil(context.done, noTimeout);
2914     return context.result;
2915 }
2916
2917 bool TestController::isStatisticsRegisteredAsSubresourceUnder(WKStringRef subresourceHost, WKStringRef topFrameHost)
2918 {
2919     auto* dataStore = WKContextGetWebsiteDataStore(platformContext());
2920     ResourceStatisticsCallbackContext context(*this);
2921     WKWebsiteDataStoreIsStatisticsRegisteredAsSubresourceUnder(dataStore, subresourceHost, topFrameHost, &context, resourceStatisticsBooleanResultCallback);
2922     runUntil(context.done, noTimeout);
2923     return context.result;
2924 }
2925
2926 bool TestController::isStatisticsRegisteredAsSubFrameUnder(WKStringRef subFrameHost, WKStringRef topFrameHost)
2927 {
2928     auto* dataStore = WKContextGetWebsiteDataStore(platformContext());
2929     ResourceStatisticsCallbackContext context(*this);
2930     WKWebsiteDataStoreIsStatisticsRegisteredAsSubFrameUnder(dataStore, subFrameHost, topFrameHost, &context, resourceStatisticsBooleanResultCallback);
2931     runUntil(context.done, noTimeout);
2932     return context.result;
2933 }
2934
2935 bool TestController::isStatisticsRegisteredAsRedirectingTo(WKStringRef hostRedirectedFrom, WKStringRef hostRedirectedTo)
2936 {
2937     auto* dataStore = WKContextGetWebsiteDataStore(platformContext());
2938     ResourceStatisticsCallbackContext context(*this);
2939     WKWebsiteDataStoreIsStatisticsRegisteredAsRedirectingTo(dataStore, hostRedirectedFrom, hostRedirectedTo, &context, resourceStatisticsBooleanResultCallback);
2940     runUntil(context.done, noTimeout);
2941     return context.result;
2942 }
2943
2944 void TestController::setStatisticsHasHadUserInteraction(WKStringRef host, bool value)
2945 {
2946     auto* dataStore = WKContextGetWebsiteDataStore(platformContext());
2947     ResourceStatisticsCallbackContext context(*this);
2948     WKWebsiteDataStoreSetStatisticsHasHadUserInteraction(dataStore, host, value, &context, resourceStatisticsVoidResultCallback);
2949     runUntil(context.done, noTimeout);
2950     m_currentInvocation->didSetHasHadUserInteraction();
2951 }
2952
2953 bool TestController::isStatisticsHasHadUserInteraction(WKStringRef host)
2954 {
2955     auto* dataStore = WKContextGetWebsiteDataStore(platformContext());
2956     ResourceStatisticsCallbackContext context(*this);
2957     WKWebsiteDataStoreIsStatisticsHasHadUserInteraction(dataStore, host, &context, resourceStatisticsBooleanResultCallback);
2958     runUntil(context.done, noTimeout);
2959     return context.result;
2960 }
2961
2962 void TestController::setStatisticsGrandfathered(WKStringRef host, bool value)
2963 {
2964     auto* dataStore = WKContextGetWebsiteDataStore(platformContext());
2965     WKWebsiteDataStoreSetStatisticsGrandfathered(dataStore, host, value);
2966 }
2967
2968 bool TestController::isStatisticsGrandfathered(WKStringRef host)
2969 {
2970     auto* dataStore = WKContextGetWebsiteDataStore(platformContext());
2971     ResourceStatisticsCallbackContext context(*this);
2972     WKWebsiteDataStoreIsStatisticsGrandfathered(dataStore, host, &context, resourceStatisticsBooleanResultCallback);
2973     runUntil(context.done, noTimeout);
2974     return context.result;
2975 }
2976
2977 void TestController::setStatisticsSubframeUnderTopFrameOrigin(WKStringRef host, WKStringRef topFrameHost)
2978 {
2979     auto* dataStore = WKContextGetWebsiteDataStore(platformContext());
2980     WKWebsiteDataStoreSetStatisticsSubframeUnderTopFrameOrigin(dataStore, host, topFrameHost);
2981 }
2982
2983 void TestController::setStatisticsSubresourceUnderTopFrameOrigin(WKStringRef host, WKStringRef topFrameHost)
2984 {
2985     auto* dataStore = WKContextGetWebsiteDataStore(platformContext());
2986     WKWebsiteDataStoreSetStatisticsSubresourceUnderTopFrameOrigin(dataStore, host, topFrameHost);
2987 }
2988
2989 void TestController::setStatisticsSubresourceUniqueRedirectTo(WKStringRef host, WKStringRef hostRedirectedTo)
2990 {
2991     auto* dataStore = WKContextGetWebsiteDataStore(platformContext());
2992     WKWebsiteDataStoreSetStatisticsSubresourceUniqueRedirectTo(dataStore, host, hostRedirectedTo);
2993 }
2994
2995 void TestController::setStatisticsSubresourceUniqueRedirectFrom(WKStringRef host, WKStringRef hostRedirectedFrom)
2996 {
2997     auto* dataStore = WKContextGetWebsiteDataStore(platformContext());
2998     WKWebsiteDataStoreSetStatisticsSubresourceUniqueRedirectFrom(dataStore, host, hostRedirectedFrom);
2999 }
3000
3001 void TestController::setStatisticsTopFrameUniqueRedirectTo(WKStringRef host, WKStringRef hostRedirectedTo)
3002 {
3003     auto* dataStore = WKContextGetWebsiteDataStore(platformContext());
3004     WKWebsiteDataStoreSetStatisticsTopFrameUniqueRedirectTo(dataStore, host, hostRedirectedTo);
3005 }
3006
3007 void TestController::setStatisticsTopFrameUniqueRedirectFrom(WKStringRef host, WKStringRef hostRedirectedFrom)
3008 {
3009     auto* dataStore = WKContextGetWebsiteDataStore(platformContext());
3010     WKWebsiteDataStoreSetStatisticsTopFrameUniqueRedirectFrom(dataStore, host, hostRedirectedFrom);
3011 }
3012
3013 void TestController::setStatisticsTimeToLiveUserInteraction(double seconds)
3014 {
3015     auto* dataStore = WKContextGetWebsiteDataStore(platformContext());
3016     WKWebsiteDataStoreSetStatisticsTimeToLiveUserInteraction(dataStore, seconds);
3017 }
3018
3019 void TestController::statisticsProcessStatisticsAndDataRecords()
3020 {
3021     auto* dataStore = WKContextGetWebsiteDataStore(platformContext());
3022     WKWebsiteDataStoreStatisticsProcessStatisticsAndDataRecords(dataStore);
3023 }
3024
3025 void TestController::statisticsUpdateCookieBlocking()
3026 {
3027     auto* dataStore = WKContextGetWebsiteDataStore(platformContext());
3028     ResourceStatisticsCallbackContext context(*this);
3029     WKWebsiteDataStoreStatisticsUpdateCookieBlocking(dataStore, &context, resourceStatisticsVoidResultCallback);
3030     runUntil(context.done, noTimeout);
3031     m_currentInvocation->didSetBlockCookiesForHost();
3032 }
3033
3034 void TestController::statisticsSubmitTelemetry()
3035 {
3036     auto* dataStore = WKContextGetWebsiteDataStore(platformContext());
3037     WKWebsiteDataStoreStatisticsSubmitTelemetry(dataStore);
3038 }
3039
3040 void TestController::setStatisticsNotifyPagesWhenDataRecordsWereScanned(bool value)
3041 {
3042     auto* dataStore = WKContextGetWebsiteDataStore(platformContext());
3043     WKWebsiteDataStoreSetStatisticsNotifyPagesWhenDataRecordsWereScanned(dataStore, value);
3044 }
3045
3046 void TestController::setStatisticsShouldClassifyResourcesBeforeDataRecordsRemoval(bool value)
3047 {
3048     auto* dataStore = WKContextGetWebsiteDataStore(platformContext());
3049     WKWebsiteDataStoreSetStatisticsShouldClassifyResourcesBeforeDataRecordsRemoval(dataStore, value);
3050 }
3051
3052 void TestController::setStatisticsNotifyPagesWhenTelemetryWasCaptured(bool value)
3053 {
3054     auto* dataStore = WKContextGetWebsiteDataStore(platformContext());
3055     WKWebsiteDataStoreSetStatisticsNotifyPagesWhenTelemetryWasCaptured(dataStore, value);
3056 }
3057
3058 void TestController::setStatisticsMinimumTimeBetweenDataRecordsRemoval(double seconds)
3059 {
3060     auto* dataStore = WKContextGetWebsiteDataStore(platformContext());
3061     WKWebsiteDataStoreSetStatisticsMinimumTimeBetweenDataRecordsRemoval(dataStore, seconds);
3062 }
3063
3064 void TestController::setStatisticsGrandfatheringTime(double seconds)
3065 {
3066     auto* dataStore = WKContextGetWebsiteDataStore(platformContext());
3067     WKWebsiteDataStoreSetStatisticsGrandfatheringTime(dataStore, seconds);
3068 }
3069
3070 void TestController::setStatisticsMaxStatisticsEntries(unsigned entries)
3071 {
3072     auto* dataStore = WKContextGetWebsiteDataStore(platformContext());
3073     WKWebsiteDataStoreSetStatisticsMaxStatisticsEntries(dataStore, entries);
3074 }
3075
3076 void TestController::setStatisticsPruneEntriesDownTo(unsigned entries)
3077 {
3078     auto* dataStore = WKContextGetWebsiteDataStore(platformContext());
3079     WKWebsiteDataStoreSetStatisticsPruneEntriesDownTo(dataStore, entries);
3080 }
3081
3082 void TestController::statisticsClearInMemoryAndPersistentStore()
3083 {
3084     auto* dataStore = WKContextGetWebsiteDataStore(platformContext());
3085     ResourceStatisticsCallbackContext context(*this);
3086     WKWebsiteDataStoreStatisticsClearInMemoryAndPersistentStore(dataStore, &context, resourceStatisticsVoidResultCallback);
3087     runUntil(context.done, noTimeout);
3088     m_currentInvocation->didClearStatisticsThroughWebsiteDataRemoval();
3089 }
3090
3091 void TestController::statisticsClearInMemoryAndPersistentStoreModifiedSinceHours(unsigned hours)
3092 {
3093     auto* dataStore = WKContextGetWebsiteDataStore(platformContext());
3094     ResourceStatisticsCallbackContext context(*this);
3095     WKWebsiteDataStoreStatisticsClearInMemoryAndPersistentStoreModifiedSinceHours(dataStore, hours, &context, resourceStatisticsVoidResultCallback);
3096     runUntil(context.done, noTimeout);
3097     m_currentInvocation->didClearStatisticsThroughWebsiteDataRemoval();
3098 }
3099
3100 void TestController::statisticsClearThroughWebsiteDataRemoval()
3101 {
3102     auto* dataStore = WKContextGetWebsiteDataStore(platformContext());
3103     ResourceStatisticsCallbackContext context(*this);
3104     WKWebsiteDataStoreStatisticsClearThroughWebsiteDataRemoval(dataStore, &context, resourceStatisticsVoidResultCallback);
3105     runUntil(context.done, noTimeout);
3106     m_currentInvocation->didClearStatisticsThroughWebsiteDataRemoval();
3107 }
3108
3109 void TestController::statisticsResetToConsistentState()
3110 {
3111     auto* dataStore = WKContextGetWebsiteDataStore(platformContext());
3112     ResourceStatisticsCallbackContext context(*this);
3113     WKWebsiteDataStoreStatisticsResetToConsistentState(dataStore, &context, resourceStatisticsVoidResultCallback);
3114     runUntil(context.done, noTimeout);
3115     m_currentInvocation->didResetStatisticsToConsistentState();
3116 }
3117
3118 void TestController::addMockMediaDevice(WKStringRef persistentID, WKStringRef label, WKStringRef type)
3119 {
3120     WKAddMockMediaDevice(platformContext(), persistentID, label, type);
3121 }
3122
3123 void TestController::clearMockMediaDevices()
3124 {
3125     WKClearMockMediaDevices(platformContext());
3126 }
3127
3128 void TestController::removeMockMediaDevice(WKStringRef persistentID)
3129 {
3130     WKRemoveMockMediaDevice(platformContext(), persistentID);
3131 }
3132
3133 void TestController::resetMockMediaDevices()
3134 {
3135     WKResetMockMediaDevices(platformContext());
3136 }
3137
3138 #if !PLATFORM(COCOA)
3139 void TestController::platformAddTestOptions(TestOptions&) const
3140 {
3141 }
3142
3143 void TestController::injectUserScript(WKStringRef)
3144 {
3145 }
3146
3147 #endif
3148
3149 void TestController::sendDisplayConfigurationChangedMessageForTesting()
3150 {
3151     WKSendDisplayConfigurationChangedMessageForTesting(platformContext());
3152 }
3153
3154 } // namespace WTR