Resource Load Statistics: Grandfather domains for existing data records
[WebKit-https.git] / Tools / WebKitTestRunner / TestController.cpp
1 /*
2  * Copyright (C) 2010, 2014-2017 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "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 <WebKit/WKArray.h>
36 #include <WebKit/WKAuthenticationChallenge.h>
37 #include <WebKit/WKAuthenticationDecisionListener.h>
38 #include <WebKit/WKContextConfigurationRef.h>
39 #include <WebKit/WKContextPrivate.h>
40 #include <WebKit/WKCookieManager.h>
41 #include <WebKit/WKCredential.h>
42 #include <WebKit/WKFrameHandleRef.h>
43 #include <WebKit/WKFrameInfoRef.h>
44 #include <WebKit/WKIconDatabase.h>
45 #include <WebKit/WKNavigationResponseRef.h>
46 #include <WebKit/WKNotification.h>
47 #include <WebKit/WKNotificationManager.h>
48 #include <WebKit/WKNotificationPermissionRequest.h>
49 #include <WebKit/WKNumber.h>
50 #include <WebKit/WKOpenPanelResultListener.h>
51 #include <WebKit/WKPageGroup.h>
52 #include <WebKit/WKPageInjectedBundleClient.h>
53 #include <WebKit/WKPagePrivate.h>
54 #include <WebKit/WKPluginInformation.h>
55 #include <WebKit/WKPreferencesRefPrivate.h>
56 #include <WebKit/WKProtectionSpace.h>
57 #include <WebKit/WKResourceLoadStatisticsManager.h>
58 #include <WebKit/WKRetainPtr.h>
59 #include <WebKit/WKSecurityOriginRef.h>
60 #include <WebKit/WKTextChecker.h>
61 #include <WebKit/WKUserMediaPermissionCheck.h>
62 #include <algorithm>
63 #include <cstdio>
64 #include <ctype.h>
65 #include <fstream>
66 #include <runtime/InitializeThreading.h>
67 #include <stdlib.h>
68 #include <string>
69 #include <unistd.h>
70 #include <wtf/CryptographicallyRandomNumber.h>
71 #include <wtf/HexNumber.h>
72 #include <wtf/MainThread.h>
73 #include <wtf/RefCounted.h>
74 #include <wtf/RunLoop.h>
75 #include <wtf/SetForScope.h>
76 #include <wtf/UUID.h>
77 #include <wtf/text/CString.h>
78 #include <wtf/text/WTFString.h>
79
80 #if PLATFORM(COCOA)
81 #include <WebKit/WKContextPrivateMac.h>
82 #include <WebKit/WKPagePrivateMac.h>
83 #endif
84
85 namespace WTR {
86
87 const unsigned TestController::viewWidth = 800;
88 const unsigned TestController::viewHeight = 600;
89
90 const unsigned TestController::w3cSVGViewWidth = 480;
91 const unsigned TestController::w3cSVGViewHeight = 360;
92
93 const double TestController::defaultShortTimeout = 5.0;
94
95 const double TestController::noTimeout = -1;
96
97 static WKURLRef blankURL()
98 {
99     static WKURLRef staticBlankURL = WKURLCreateWithUTF8CString("about:blank");
100     return staticBlankURL;
101 }
102
103 static WKDataRef copyWebCryptoMasterKey(WKPageRef, const void*)
104 {
105     // Any 128 bit key would do, all we need for testing is to implement the callback.
106     return WKDataCreate((const uint8_t*)"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", 16);
107 }
108
109 static TestController* controller;
110
111 TestController& TestController::singleton()
112 {
113     ASSERT(controller);
114     return *controller;
115 }
116
117 TestController::TestController(int argc, const char* argv[])
118 {
119     initialize(argc, argv);
120     controller = this;
121     run();
122     controller = 0;
123 }
124
125 TestController::~TestController()
126 {
127     // The context will be null if WebKitTestRunner was in server mode, but ran no tests.
128     if (m_context)
129         WKIconDatabaseClose(WKContextGetIconDatabase(m_context.get()));
130
131     platformDestroy();
132 }
133
134 static WKRect getWindowFrame(WKPageRef page, const void* clientInfo)
135 {
136     PlatformWebView* view = static_cast<PlatformWebView*>(const_cast<void*>(clientInfo));
137     return view->windowFrame();
138 }
139
140 static void setWindowFrame(WKPageRef page, WKRect frame, const void* clientInfo)
141 {
142     PlatformWebView* view = static_cast<PlatformWebView*>(const_cast<void*>(clientInfo));
143     view->setWindowFrame(frame);
144 }
145
146 static bool runBeforeUnloadConfirmPanel(WKPageRef page, WKStringRef message, WKFrameRef frame, const void*)
147 {
148     printf("CONFIRM NAVIGATION: %s\n", toSTD(message).c_str());
149     return TestController::singleton().beforeUnloadReturnValue();
150 }
151
152 static void runOpenPanel(WKPageRef page, WKFrameRef frame, WKOpenPanelParametersRef parameters, WKOpenPanelResultListenerRef resultListenerRef, const void*)
153 {
154     printf("OPEN FILE PANEL\n");
155     WKArrayRef fileURLs = TestController::singleton().openPanelFileURLs();
156     if (!fileURLs || !WKArrayGetSize(fileURLs)) {
157         WKOpenPanelResultListenerCancel(resultListenerRef);
158         return;
159     }
160
161     if (WKOpenPanelParametersGetAllowsMultipleFiles(parameters)) {
162         WKOpenPanelResultListenerChooseFiles(resultListenerRef, fileURLs);
163         return;
164     }
165
166     WKTypeRef firstItem = WKArrayGetItemAtIndex(fileURLs, 0);
167     WKOpenPanelResultListenerChooseFiles(resultListenerRef, adoptWK(WKArrayCreate(&firstItem, 1)).get());
168 }
169
170 void TestController::runModal(WKPageRef page, const void* clientInfo)
171 {
172     PlatformWebView* view = static_cast<PlatformWebView*>(const_cast<void*>(clientInfo));
173     view->setWindowIsKey(false);
174     runModal(view);
175     view->setWindowIsKey(true);
176 }
177
178 static void closeOtherPage(WKPageRef page, const void* clientInfo)
179 {
180     WKPageClose(page);
181     PlatformWebView* view = static_cast<PlatformWebView*>(const_cast<void*>(clientInfo));
182     delete view;
183 }
184
185 static void focus(WKPageRef page, const void* clientInfo)
186 {
187     PlatformWebView* view = static_cast<PlatformWebView*>(const_cast<void*>(clientInfo));
188     view->focus();
189     view->setWindowIsKey(true);
190 }
191
192 static void unfocus(WKPageRef page, const void* clientInfo)
193 {
194     PlatformWebView* view = static_cast<PlatformWebView*>(const_cast<void*>(clientInfo));
195     view->setWindowIsKey(false);
196 }
197
198 static void decidePolicyForGeolocationPermissionRequest(WKPageRef, WKFrameRef, WKSecurityOriginRef, WKGeolocationPermissionRequestRef permissionRequest, const void* clientInfo)
199 {
200     TestController::singleton().handleGeolocationPermissionRequest(permissionRequest);
201 }
202
203 static void decidePolicyForUserMediaPermissionRequest(WKPageRef, WKFrameRef frame, WKSecurityOriginRef userMediaDocumentOrigin, WKSecurityOriginRef topLevelDocumentOrigin, WKUserMediaPermissionRequestRef permissionRequest, const void* clientInfo)
204 {
205     TestController::singleton().handleUserMediaPermissionRequest(frame, userMediaDocumentOrigin, topLevelDocumentOrigin, permissionRequest);
206 }
207
208 static void checkUserMediaPermissionForOrigin(WKPageRef, WKFrameRef frame, WKSecurityOriginRef userMediaDocumentOrigin, WKSecurityOriginRef topLevelDocumentOrigin, WKUserMediaPermissionCheckRef checkRequest, const void*)
209 {
210     TestController::singleton().handleCheckOfUserMediaPermissionForOrigin(frame, userMediaDocumentOrigin, topLevelDocumentOrigin, checkRequest);
211 }
212
213 static void requestPointerLock(WKPageRef page, const void*)
214 {
215     WKPageDidAllowPointerLock(page);
216 }
217
218 WKPageRef TestController::createOtherPage(WKPageRef oldPage, WKPageConfigurationRef configuration, WKNavigationActionRef navigationAction, WKWindowFeaturesRef windowFeatures, const void *clientInfo)
219 {
220     PlatformWebView* parentView = static_cast<PlatformWebView*>(const_cast<void*>(clientInfo));
221
222     PlatformWebView* view = platformCreateOtherPage(parentView, configuration, parentView->options());
223     WKPageRef newPage = view->page();
224
225     view->resizeTo(800, 600);
226
227     WKPageUIClientV8 otherPageUIClient = {
228         { 8, view },
229         0, // createNewPage_deprecatedForUseWithV0
230         0, // showPage
231         closeOtherPage,
232         0, // takeFocus
233         focus,
234         unfocus,
235         0, // runJavaScriptAlert_deprecatedForUseWithV0
236         0, // runJavaScriptAlert_deprecatedForUseWithV0
237         0, // runJavaScriptAlert_deprecatedForUseWithV0
238         0, // setStatusText
239         0, // mouseDidMoveOverElement_deprecatedForUseWithV0
240         0, // missingPluginButtonClicked
241         0, // didNotHandleKeyEvent
242         0, // didNotHandleWheelEvent
243         0, // toolbarsAreVisible
244         0, // setToolbarsAreVisible
245         0, // menuBarIsVisible
246         0, // setMenuBarIsVisible
247         0, // statusBarIsVisible
248         0, // setStatusBarIsVisible
249         0, // isResizable
250         0, // setIsResizable
251         getWindowFrame,
252         setWindowFrame,
253         runBeforeUnloadConfirmPanel,
254         0, // didDraw
255         0, // pageDidScroll
256         0, // exceededDatabaseQuota
257         runOpenPanel,
258         decidePolicyForGeolocationPermissionRequest,
259         0, // headerHeight
260         0, // footerHeight
261         0, // drawHeader
262         0, // drawFooter
263         0, // printFrame
264         runModal,
265         0, // didCompleteRubberBandForMainFrame
266         0, // saveDataToFileInDownloadsFolder
267         0, // shouldInterruptJavaScript
268         0, // createNewPage_deprecatedForUseWithV1
269         0, // mouseDidMoveOverElement
270         0, // decidePolicyForNotificationPermissionRequest
271         0, // unavailablePluginButtonClicked_deprecatedForUseWithV1
272         0, // showColorPicker
273         0, // hideColorPicker
274         0, // unavailablePluginButtonClicked
275         0, // pinnedStateDidChange
276         0, // didBeginTrackingPotentialLongMousePress
277         0, // didRecognizeLongMousePress
278         0, // didCancelTrackingPotentialLongMousePress
279         0, // isPlayingAudioDidChange
280         decidePolicyForUserMediaPermissionRequest,
281         0, // didClickAutofillButton
282         0, // runJavaScriptAlert
283         0, // runJavaScriptConfirm
284         0, // runJavaScriptPrompt
285         0, // mediaSessionMetadataDidChange
286         createOtherPage,
287         0, // runJavaScriptAlert
288         0, // runJavaScriptConfirm
289         0, // runJavaScriptPrompt
290         checkUserMediaPermissionForOrigin,
291         0, // runBeforeUnloadConfirmPanel
292         0, // fullscreenMayReturnToInline
293         requestPointerLock,
294         0,
295     };
296     WKPageSetPageUIClient(newPage, &otherPageUIClient.base);
297     
298     WKPageNavigationClientV0 pageNavigationClient = {
299         { 0, &TestController::singleton() },
300         decidePolicyForNavigationAction,
301         decidePolicyForNavigationResponse,
302         decidePolicyForPluginLoad,
303         0, // didStartProvisionalNavigation
304         0, // didReceiveServerRedirectForProvisionalNavigation
305         0, // didFailProvisionalNavigation
306         0, // didCommitNavigation
307         0, // didFinishNavigation
308         0, // didFailNavigation
309         0, // didFailProvisionalLoadInSubframe
310         0, // didFinishDocumentLoad
311         0, // didSameDocumentNavigation
312         0, // renderingProgressDidChange
313         canAuthenticateAgainstProtectionSpace,
314         didReceiveAuthenticationChallenge,
315         processDidCrash,
316         copyWebCryptoMasterKey,
317         didBeginNavigationGesture,
318         willEndNavigationGesture,
319         didEndNavigationGesture,
320         didRemoveNavigationGestureSnapshot
321     };
322     WKPageSetPageNavigationClient(newPage, &pageNavigationClient.base);
323
324     view->didInitializeClients();
325
326     TestController::singleton().updateWindowScaleForTest(view, *TestController::singleton().m_currentInvocation);
327
328     WKRetain(newPage);
329     return newPage;
330 }
331
332 const char* TestController::libraryPathForTesting()
333 {
334     // FIXME: This may not be sufficient to prevent interactions/crashes
335     // when running more than one copy of DumpRenderTree.
336     // See https://bugs.webkit.org/show_bug.cgi?id=10906
337     char* dumpRenderTreeTemp = getenv("DUMPRENDERTREE_TEMP");
338     if (dumpRenderTreeTemp)
339         return dumpRenderTreeTemp;
340     return platformLibraryPathForTesting();
341 }
342
343 void TestController::initialize(int argc, const char* argv[])
344 {
345     JSC::initializeThreading();
346     RunLoop::initializeMainRunLoop();
347
348     platformInitialize();
349
350     Options options;
351     OptionsHandler optionsHandler(options);
352
353     if (argc < 2) {
354         optionsHandler.printHelp();
355         exit(1);
356     }
357     if (!optionsHandler.parse(argc, argv))
358         exit(1);
359
360     m_useWaitToDumpWatchdogTimer = options.useWaitToDumpWatchdogTimer;
361     m_forceNoTimeout = options.forceNoTimeout;
362     m_verbose = options.verbose;
363     m_gcBetweenTests = options.gcBetweenTests;
364     m_shouldDumpPixelsForAllTests = options.shouldDumpPixelsForAllTests;
365     m_forceComplexText = options.forceComplexText;
366     m_shouldUseAcceleratedDrawing = options.shouldUseAcceleratedDrawing;
367     m_shouldUseRemoteLayerTree = options.shouldUseRemoteLayerTree;
368     m_paths = options.paths;
369     m_allowedHosts = options.allowedHosts;
370     m_shouldShowWebView = options.shouldShowWebView;
371
372     if (options.printSupportedFeatures) {
373         // FIXME: On Windows, DumpRenderTree uses this to expose whether it supports 3d
374         // transforms and accelerated compositing. When we support those features, we
375         // should match DRT's behavior.
376         exit(0);
377     }
378
379     m_usingServerMode = (m_paths.size() == 1 && m_paths[0] == "-");
380     if (m_usingServerMode)
381         m_printSeparators = true;
382     else
383         m_printSeparators = m_paths.size() > 1;
384
385     initializeInjectedBundlePath();
386     initializeTestPluginDirectory();
387
388 #if PLATFORM(MAC)
389     WebCoreTestSupport::installMockGamepadProvider();
390 #endif
391     WKRetainPtr<WKStringRef> pageGroupIdentifier(AdoptWK, WKStringCreateWithUTF8CString("WebKitTestRunnerPageGroup"));
392     m_pageGroup.adopt(WKPageGroupCreateWithIdentifier(pageGroupIdentifier.get()));
393 }
394
395 WKRetainPtr<WKContextConfigurationRef> TestController::generateContextConfiguration() const
396 {
397     auto configuration = adoptWK(WKContextConfigurationCreate());
398     WKContextConfigurationSetInjectedBundlePath(configuration.get(), injectedBundlePath());
399     WKContextConfigurationSetFullySynchronousModeIsAllowedForTesting(configuration.get(), true);
400
401     if (const char* dumpRenderTreeTemp = libraryPathForTesting()) {
402         String temporaryFolder = String::fromUTF8(dumpRenderTreeTemp);
403
404         const char separator = '/';
405
406         WKContextConfigurationSetApplicationCacheDirectory(configuration.get(), toWK(temporaryFolder + separator + "ApplicationCache").get());
407         WKContextConfigurationSetDiskCacheDirectory(configuration.get(), toWK(temporaryFolder + separator + "Cache").get());
408         WKContextConfigurationSetIndexedDBDatabaseDirectory(configuration.get(), toWK(temporaryFolder + separator + "Databases" + separator + "IndexedDB").get());
409         WKContextConfigurationSetLocalStorageDirectory(configuration.get(), toWK(temporaryFolder + separator + "LocalStorage").get());
410         WKContextConfigurationSetWebSQLDatabaseDirectory(configuration.get(), toWK(temporaryFolder + separator + "Databases" + separator + "WebSQL").get());
411         WKContextConfigurationSetMediaKeysStorageDirectory(configuration.get(), toWK(temporaryFolder + separator + "MediaKeys").get());
412     }
413     return configuration;
414 }
415
416 WKRetainPtr<WKPageConfigurationRef> TestController::generatePageConfiguration(WKContextConfigurationRef configuration)
417 {
418     m_context = platformAdjustContext(adoptWK(WKContextCreateWithConfiguration(configuration)).get(), configuration);
419
420     m_geolocationProvider = std::make_unique<GeolocationProviderMock>(m_context.get());
421
422     if (const char* dumpRenderTreeTemp = libraryPathForTesting()) {
423         String temporaryFolder = String::fromUTF8(dumpRenderTreeTemp);
424
425         // FIXME: This should be migrated to WKContextConfigurationRef.
426         // Disable icon database to avoid fetching <http://127.0.0.1:8000/favicon.ico> and making tests flaky.
427         // Invividual tests can enable it using testRunner.setIconDatabaseEnabled, although it's not currently supported in WebKitTestRunner.
428         WKContextSetIconDatabasePath(m_context.get(), toWK(emptyString()).get());
429     }
430
431     WKContextSetDiskCacheSpeculativeValidationEnabled(m_context.get(), true);
432     WKContextUseTestingNetworkSession(m_context.get());
433     WKContextSetCacheModel(m_context.get(), kWKCacheModelDocumentBrowser);
434
435     platformInitializeContext();
436
437     WKContextInjectedBundleClientV1 injectedBundleClient = {
438         { 1, this },
439         didReceiveMessageFromInjectedBundle,
440         didReceiveSynchronousMessageFromInjectedBundle,
441         getInjectedBundleInitializationUserData,
442     };
443     WKContextSetInjectedBundleClient(m_context.get(), &injectedBundleClient.base);
444
445     WKContextClientV2 contextClient = {
446         { 2, this },
447         0, // plugInAutoStartOriginHashesChanged
448         networkProcessDidCrash,
449         0, // plugInInformationBecameAvailable
450         0, // copyWebCryptoMasterKey
451         databaseProcessDidCrash,
452     };
453     WKContextSetClient(m_context.get(), &contextClient.base);
454
455     WKContextHistoryClientV0 historyClient = {
456         { 0, this },
457         didNavigateWithNavigationData,
458         didPerformClientRedirect,
459         didPerformServerRedirect,
460         didUpdateHistoryTitle,
461         0, // populateVisitedLinks
462     };
463     WKContextSetHistoryClient(m_context.get(), &historyClient.base);
464
465     WKNotificationManagerRef notificationManager = WKContextGetNotificationManager(m_context.get());
466     WKNotificationProviderV0 notificationKit = m_webNotificationProvider.provider();
467     WKNotificationManagerSetProvider(notificationManager, &notificationKit.base);
468
469     if (testPluginDirectory())
470         WKContextSetAdditionalPluginsDirectory(m_context.get(), testPluginDirectory());
471
472     if (m_forceComplexText)
473         WKContextSetAlwaysUsesComplexTextCodePath(m_context.get(), true);
474
475     auto pageConfiguration = adoptWK(WKPageConfigurationCreate());
476     WKPageConfigurationSetContext(pageConfiguration.get(), m_context.get());
477     WKPageConfigurationSetPageGroup(pageConfiguration.get(), m_pageGroup.get());
478     WKPageConfigurationSetUserContentController(pageConfiguration.get(), adoptWK(WKUserContentControllerCreate()).get());
479     return pageConfiguration;
480 }
481
482 void TestController::createWebViewWithOptions(const TestOptions& options)
483 {
484     auto contextConfiguration = generateContextConfiguration();
485
486     WKRetainPtr<WKMutableArrayRef> overrideLanguages = adoptWK(WKMutableArrayCreate());
487     for (auto& language : options.overrideLanguages)
488         WKArrayAppendItem(overrideLanguages.get(), adoptWK(WKStringCreateWithUTF8CString(language.utf8().data())).get());
489     WKContextConfigurationSetOverrideLanguages(contextConfiguration.get(), overrideLanguages.get());
490
491     auto configuration = generatePageConfiguration(contextConfiguration.get());
492
493     // Some preferences (notably mock scroll bars setting) currently cannot be re-applied to an existing view, so we need to set them now.
494     // FIXME: Migrate these preferences to WKContextConfigurationRef.
495     resetPreferencesToConsistentValues(options);
496
497     platformCreateWebView(configuration.get(), options);
498     WKPageUIClientV8 pageUIClient = {
499         { 8, m_mainWebView.get() },
500         0, // createNewPage_deprecatedForUseWithV0
501         0, // showPage
502         0, // close
503         0, // takeFocus
504         focus,
505         unfocus,
506         0, // runJavaScriptAlert_deprecatedForUseWithV0
507         0, // runJavaScriptAlert_deprecatedForUseWithV0
508         0, // runJavaScriptAlert_deprecatedForUseWithV0
509         0, // setStatusText
510         0, // mouseDidMoveOverElement_deprecatedForUseWithV0
511         0, // missingPluginButtonClicked
512         0, // didNotHandleKeyEvent
513         0, // didNotHandleWheelEvent
514         0, // toolbarsAreVisible
515         0, // setToolbarsAreVisible
516         0, // menuBarIsVisible
517         0, // setMenuBarIsVisible
518         0, // statusBarIsVisible
519         0, // setStatusBarIsVisible
520         0, // isResizable
521         0, // setIsResizable
522         getWindowFrame,
523         setWindowFrame,
524         runBeforeUnloadConfirmPanel,
525         0, // didDraw
526         0, // pageDidScroll
527         0, // exceededDatabaseQuota,
528         runOpenPanel,
529         decidePolicyForGeolocationPermissionRequest,
530         0, // headerHeight
531         0, // footerHeight
532         0, // drawHeader
533         0, // drawFooter
534         0, // printFrame
535         runModal,
536         0, // didCompleteRubberBandForMainFrame
537         0, // saveDataToFileInDownloadsFolder
538         0, // shouldInterruptJavaScript
539         0, // createNewPage_deprecatedForUseWithV1
540         0, // mouseDidMoveOverElement
541         decidePolicyForNotificationPermissionRequest, // decidePolicyForNotificationPermissionRequest
542         0, // unavailablePluginButtonClicked_deprecatedForUseWithV1
543         0, // showColorPicker
544         0, // hideColorPicker
545         unavailablePluginButtonClicked,
546         0, // pinnedStateDidChange
547         0, // didBeginTrackingPotentialLongMousePress
548         0, // didRecognizeLongMousePress
549         0, // didCancelTrackingPotentialLongMousePress
550         0, // isPlayingAudioDidChange
551         decidePolicyForUserMediaPermissionRequest,
552         0, // didClickAutofillButton
553         0, // runJavaScriptAlert
554         0, // runJavaScriptConfirm
555         0, // runJavaScriptPrompt
556         0, // mediaSessionMetadataDidChange
557         createOtherPage,
558         0, // runJavaScriptAlert
559         0, // runJavaScriptConfirm
560         0, // runJavaScriptPrompt
561         checkUserMediaPermissionForOrigin,
562         0, // runBeforeUnloadConfirmPanel
563         0, // fullscreenMayReturnToInline
564         requestPointerLock,
565         0,
566     };
567     WKPageSetPageUIClient(m_mainWebView->page(), &pageUIClient.base);
568
569     WKPageNavigationClientV0 pageNavigationClient = {
570         { 0, this },
571         decidePolicyForNavigationAction,
572         decidePolicyForNavigationResponse,
573         decidePolicyForPluginLoad,
574         0, // didStartProvisionalNavigation
575         0, // didReceiveServerRedirectForProvisionalNavigation
576         0, // didFailProvisionalNavigation
577         didCommitNavigation,
578         didFinishNavigation,
579         0, // didFailNavigation
580         0, // didFailProvisionalLoadInSubframe
581         0, // didFinishDocumentLoad
582         0, // didSameDocumentNavigation
583         0, // renderingProgressDidChange
584         canAuthenticateAgainstProtectionSpace,
585         didReceiveAuthenticationChallenge,
586         processDidCrash,
587         copyWebCryptoMasterKey,
588         didBeginNavigationGesture,
589         willEndNavigationGesture,
590         didEndNavigationGesture,
591         didRemoveNavigationGestureSnapshot
592     };
593     WKPageSetPageNavigationClient(m_mainWebView->page(), &pageNavigationClient.base);
594
595     WKContextDownloadClientV0 downloadClient = {
596         { 0, this },
597         downloadDidStart,
598         0, // didReceiveAuthenticationChallenge
599         0, // didReceiveResponse
600         0, // didReceiveData
601         0, // shouldDecodeSourceDataOfMIMEType
602         decideDestinationWithSuggestedFilename,
603         0, // didCreateDestination
604         downloadDidFinish,
605         downloadDidFail,
606         downloadDidCancel,
607         0 // processDidCrash;
608     };
609     WKContextSetDownloadClient(context(), &downloadClient.base);
610     
611     // this should just be done on the page?
612     WKPageInjectedBundleClientV0 injectedBundleClient = {
613         { 0, this },
614         didReceivePageMessageFromInjectedBundle,
615         didReceiveSynchronousPageMessageFromInjectedBundle
616     };
617     WKPageSetPageInjectedBundleClient(m_mainWebView->page(), &injectedBundleClient.base);
618
619     m_mainWebView->didInitializeClients();
620
621     // Generally, the tests should default to running at 1x. updateWindowScaleForTest() will adjust the scale to
622     // something else for specific tests that need to run at a different window scale.
623     m_mainWebView->changeWindowScaleIfNeeded(1);
624 }
625
626 void TestController::ensureViewSupportsOptionsForTest(const TestInvocation& test)
627 {
628     auto options = test.options();
629
630     if (m_mainWebView) {
631         if (m_mainWebView->viewSupportsOptions(options))
632             return;
633
634         WKPageSetPageUIClient(m_mainWebView->page(), nullptr);
635         WKPageSetPageNavigationClient(m_mainWebView->page(), nullptr);
636         WKPageClose(m_mainWebView->page());
637
638         m_mainWebView = nullptr;
639     }
640
641     createWebViewWithOptions(options);
642
643     if (!resetStateToConsistentValues(options))
644         TestInvocation::dumpWebProcessUnresponsiveness("<unknown> - TestController::run - Failed to reset state to consistent values\n");
645 }
646
647 void TestController::resetPreferencesToConsistentValues(const TestOptions& options)
648 {
649     // Reset preferences
650     WKPreferencesRef preferences = platformPreferences();
651     WKPreferencesResetTestRunnerOverrides(preferences);
652     WKPreferencesEnableAllExperimentalFeatures(preferences);
653     WKPreferencesSetPageVisibilityBasedProcessSuppressionEnabled(preferences, false);
654     WKPreferencesSetOfflineWebApplicationCacheEnabled(preferences, true);
655     WKPreferencesSetFontSmoothingLevel(preferences, kWKFontSmoothingLevelNoSubpixelAntiAliasing);
656     WKPreferencesSetSubpixelAntialiasedLayerTextEnabled(preferences, false);
657     WKPreferencesSetXSSAuditorEnabled(preferences, false);
658     WKPreferencesSetWebAudioEnabled(preferences, true);
659     WKPreferencesSetMediaDevicesEnabled(preferences, true);
660     WKPreferencesSetWebRTCLegacyAPIEnabled(preferences, true);
661     WKPreferencesSetDeveloperExtrasEnabled(preferences, true);
662     WKPreferencesSetJavaScriptRuntimeFlags(preferences, kWKJavaScriptRuntimeFlagsAllEnabled);
663     WKPreferencesSetJavaScriptCanOpenWindowsAutomatically(preferences, true);
664     WKPreferencesSetJavaScriptCanAccessClipboard(preferences, true);
665     WKPreferencesSetDOMPasteAllowed(preferences, true);
666     WKPreferencesSetUniversalAccessFromFileURLsAllowed(preferences, true);
667     WKPreferencesSetFileAccessFromFileURLsAllowed(preferences, true);
668 #if ENABLE(FULLSCREEN_API)
669     WKPreferencesSetFullScreenEnabled(preferences, true);
670 #endif
671     WKPreferencesSetPageCacheEnabled(preferences, false);
672     WKPreferencesSetAsynchronousPluginInitializationEnabled(preferences, false);
673     WKPreferencesSetAsynchronousPluginInitializationEnabledForAllPlugins(preferences, false);
674     WKPreferencesSetArtificialPluginInitializationDelayEnabled(preferences, false);
675     WKPreferencesSetTabToLinksEnabled(preferences, false);
676     WKPreferencesSetInteractiveFormValidationEnabled(preferences, true);
677
678     WKPreferencesSetMockScrollbarsEnabled(preferences, options.useMockScrollbars);
679     WKPreferencesSetNeedsSiteSpecificQuirks(preferences, options.needsSiteSpecificQuirks);
680     WKPreferencesSetIntersectionObserverEnabled(preferences, options.enableIntersectionObserver);
681     WKPreferencesSetModernMediaControlsEnabled(preferences, options.enableModernMediaControls);
682     WKPreferencesSetCredentialManagementEnabled(preferences, options.enableCredentialManagement);
683
684     static WKStringRef defaultTextEncoding = WKStringCreateWithUTF8CString("ISO-8859-1");
685     WKPreferencesSetDefaultTextEncodingName(preferences, defaultTextEncoding);
686
687     static WKStringRef standardFontFamily = WKStringCreateWithUTF8CString("Times");
688     static WKStringRef cursiveFontFamily = WKStringCreateWithUTF8CString("Apple Chancery");
689     static WKStringRef fantasyFontFamily = WKStringCreateWithUTF8CString("Papyrus");
690     static WKStringRef fixedFontFamily = WKStringCreateWithUTF8CString("Courier");
691     static WKStringRef pictographFontFamily = WKStringCreateWithUTF8CString("Apple Color Emoji");
692     static WKStringRef sansSerifFontFamily = WKStringCreateWithUTF8CString("Helvetica");
693     static WKStringRef serifFontFamily = WKStringCreateWithUTF8CString("Times");
694
695     WKPreferencesSetMinimumFontSize(preferences, 0);
696     WKPreferencesSetStandardFontFamily(preferences, standardFontFamily);
697     WKPreferencesSetCursiveFontFamily(preferences, cursiveFontFamily);
698     WKPreferencesSetFantasyFontFamily(preferences, fantasyFontFamily);
699     WKPreferencesSetFixedFontFamily(preferences, fixedFontFamily);
700     WKPreferencesSetPictographFontFamily(preferences, pictographFontFamily);
701     WKPreferencesSetSansSerifFontFamily(preferences, sansSerifFontFamily);
702     WKPreferencesSetSerifFontFamily(preferences, serifFontFamily);
703     WKPreferencesSetAsynchronousSpellCheckingEnabled(preferences, false);
704 #if ENABLE(WEB_AUDIO)
705     WKPreferencesSetMediaSourceEnabled(preferences, true);
706 #endif
707
708     WKPreferencesSetHiddenPageDOMTimerThrottlingEnabled(preferences, false);
709     WKPreferencesSetHiddenPageCSSAnimationSuspensionEnabled(preferences, false);
710
711     WKPreferencesSetAcceleratedDrawingEnabled(preferences, m_shouldUseAcceleratedDrawing);
712     // FIXME: We should be testing the default.
713     WKPreferencesSetStorageBlockingPolicy(preferences, kWKAllowAllStorage);
714
715     WKPreferencesSetResourceTimingEnabled(preferences, true);
716
717     WKPreferencesSetMediaPlaybackAllowsInline(preferences, true);
718     WKPreferencesSetInlineMediaPlaybackRequiresPlaysInlineAttribute(preferences, false);
719
720     WKCookieManagerDeleteAllCookies(WKContextGetCookieManager(m_context.get()));
721
722     WKPreferencesSetMockCaptureDevicesEnabled(preferences, true);
723     
724     WKPreferencesSetLargeImageAsyncDecodingEnabled(preferences, false);
725
726     platformResetPreferencesToConsistentValues();
727 }
728
729 bool TestController::resetStateToConsistentValues(const TestOptions& options)
730 {
731     SetForScope<State> changeState(m_state, Resetting);
732     m_beforeUnloadReturnValue = true;
733
734     // This setting differs between the antique and modern Mac WebKit2 API.
735     // For now, maintain the antique behavior, because some tests depend on it!
736     // FIXME: We should be testing the default.
737     WKPageSetBackgroundExtendsBeyondPage(m_mainWebView->page(), false);
738
739     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("Reset"));
740     WKRetainPtr<WKMutableDictionaryRef> resetMessageBody = adoptWK(WKMutableDictionaryCreate());
741
742     WKRetainPtr<WKStringRef> shouldGCKey = adoptWK(WKStringCreateWithUTF8CString("ShouldGC"));
743     WKRetainPtr<WKBooleanRef> shouldGCValue = adoptWK(WKBooleanCreate(m_gcBetweenTests));
744     WKDictionarySetItem(resetMessageBody.get(), shouldGCKey.get(), shouldGCValue.get());
745
746     WKRetainPtr<WKStringRef> allowedHostsKey = adoptWK(WKStringCreateWithUTF8CString("AllowedHosts"));
747     WKRetainPtr<WKMutableArrayRef> allowedHostsValue = adoptWK(WKMutableArrayCreate());
748     for (auto& host : m_allowedHosts) {
749         WKRetainPtr<WKStringRef> wkHost = adoptWK(WKStringCreateWithUTF8CString(host.c_str()));
750         WKArrayAppendItem(allowedHostsValue.get(), wkHost.get());
751     }
752     WKDictionarySetItem(resetMessageBody.get(), allowedHostsKey.get(), allowedHostsValue.get());
753
754     WKPagePostMessageToInjectedBundle(TestController::singleton().mainWebView()->page(), messageName.get(), resetMessageBody.get());
755
756     WKContextSetShouldUseFontSmoothing(TestController::singleton().context(), false);
757
758     WKContextSetCacheModel(TestController::singleton().context(), kWKCacheModelDocumentBrowser);
759
760     WKContextClearCachedCredentials(TestController::singleton().context());
761
762     // FIXME: This function should also ensure that there is only one page open.
763
764     // Reset the EventSender for each test.
765     m_eventSenderProxy = std::make_unique<EventSenderProxy>(this);
766
767     // FIXME: Is this needed? Nothing in TestController changes preferences during tests, and if there is
768     // some other code doing this, it should probably be responsible for cleanup too.
769     resetPreferencesToConsistentValues(options);
770
771 #if !PLATFORM(COCOA) && !PLATFORM(WPE)
772     WKTextCheckerContinuousSpellCheckingEnabledStateChanged(true);
773 #endif
774
775     // Make sure the view is in the window (a test can unparent it).
776     m_mainWebView->addToWindow();
777
778     // In the case that a test using the chrome input field failed, be sure to clean up for the next test.
779     m_mainWebView->removeChromeInputField();
780     m_mainWebView->focus();
781
782     // Re-set to the default backing scale factor by setting the custom scale factor to 0.
783     WKPageSetCustomBackingScaleFactor(m_mainWebView->page(), 0);
784
785     WKPageClearWheelEventTestTrigger(m_mainWebView->page());
786
787     WKPageSetMuted(m_mainWebView->page(), true);
788
789     WKPageClearUserMediaState(m_mainWebView->page());
790
791     // Reset notification permissions
792     m_webNotificationProvider.reset();
793
794     // Reset Geolocation permissions.
795     m_geolocationPermissionRequests.clear();
796     m_isGeolocationPermissionSet = false;
797     m_isGeolocationPermissionAllowed = false;
798
799     // Reset UserMedia permissions.
800     m_userMediaPermissionRequests.clear();
801     m_cachedUserMediaPermissions.clear();
802     m_isUserMediaPermissionSet = false;
803     m_isUserMediaPermissionAllowed = false;
804
805     // Reset Custom Policy Delegate.
806     setCustomPolicyDelegate(false, false);
807
808     m_shouldDownloadUndisplayableMIMETypes = false;
809
810     m_workQueueManager.clearWorkQueue();
811
812     m_rejectsProtectionSpaceAndContinueForAuthenticationChallenges = false;
813     m_handlesAuthenticationChallenges = false;
814     m_authenticationUsername = String();
815     m_authenticationPassword = String();
816
817     m_shouldBlockAllPlugins = false;
818
819     m_shouldLogHistoryClientCallbacks = false;
820     m_shouldLogCanAuthenticateAgainstProtectionSpace = false;
821
822     setHidden(false);
823
824     platformResetStateToConsistentValues();
825
826     // Reset main page back to about:blank
827     m_doneResetting = false;
828
829     m_shouldDecideNavigationPolicyAfterDelay = false;
830
831     setNavigationGesturesEnabled(false);
832     
833     setIgnoresViewportScaleLimits(options.ignoresViewportScaleLimits);
834
835     m_openPanelFileURLs = nullptr;
836
837     WKPageLoadURL(m_mainWebView->page(), blankURL());
838     runUntil(m_doneResetting, m_currentInvocation->shortTimeout());
839     return m_doneResetting;
840 }
841
842 void TestController::terminateWebContentProcess()
843 {
844     WKPageTerminate(m_mainWebView->page());
845 }
846
847 void TestController::reattachPageToWebProcess()
848 {
849     // Loading a web page is the only way to reattach an existing page to a process.
850     m_doneResetting = false;
851     WKPageLoadURL(m_mainWebView->page(), blankURL());
852     runUntil(m_doneResetting, m_currentInvocation->shortTimeout());
853 }
854
855 const char* TestController::webProcessName()
856 {
857     // FIXME: Find a way to not hardcode the process name.
858 #if PLATFORM(COCOA)
859     return "com.apple.WebKit.WebContent.Development";
860 #else
861     return "WebProcess";
862 #endif
863 }
864
865 const char* TestController::networkProcessName()
866 {
867     // FIXME: Find a way to not hardcode the process name.
868 #if PLATFORM(COCOA)
869     return "com.apple.WebKit.Networking.Development";
870 #else
871     return "NetworkProcess";
872 #endif
873 }
874
875 const char* TestController::databaseProcessName()
876 {
877     // FIXME: Find a way to not hardcode the process name.
878 #if PLATFORM(COCOA)
879     return "com.apple.WebKit.Databases.Development";
880 #else
881     return "DatabaseProcess";
882 #endif
883 }
884
885 void TestController::setAllowsAnySSLCertificate(bool allows)
886 {
887     WKContextSetAllowsAnySSLCertificateForWebSocketTesting(platformContext(), allows);
888 }
889
890 static std::string testPath(WKURLRef url)
891 {
892     auto scheme = adoptWK(WKURLCopyScheme(url));
893     if (WKStringIsEqualToUTF8CStringIgnoringCase(scheme.get(), "file")) {
894         auto path = adoptWK(WKURLCopyPath(url));
895         auto buffer = std::vector<char>(WKStringGetMaximumUTF8CStringSize(path.get()));
896         auto length = WKStringGetUTF8CString(path.get(), buffer.data(), buffer.size());
897         return std::string(buffer.data(), length);
898     }
899     return std::string();
900 }
901
902 static WKURLRef createTestURL(const char* pathOrURL)
903 {
904     if (strstr(pathOrURL, "http://") || strstr(pathOrURL, "https://") || strstr(pathOrURL, "file://"))
905         return WKURLCreateWithUTF8CString(pathOrURL);
906
907     // Creating from filesytem path.
908     size_t length = strlen(pathOrURL);
909     if (!length)
910         return 0;
911
912     const char separator = '/';
913     bool isAbsolutePath = pathOrURL[0] == separator;
914     const char* filePrefix = "file://";
915     static const size_t prefixLength = strlen(filePrefix);
916
917     std::unique_ptr<char[]> buffer;
918     if (isAbsolutePath) {
919         buffer = std::make_unique<char[]>(prefixLength + length + 1);
920         strcpy(buffer.get(), filePrefix);
921         strcpy(buffer.get() + prefixLength, pathOrURL);
922     } else {
923         buffer = std::make_unique<char[]>(prefixLength + PATH_MAX + length + 2); // 1 for the separator
924         strcpy(buffer.get(), filePrefix);
925         if (!getcwd(buffer.get() + prefixLength, PATH_MAX))
926             return 0;
927         size_t numCharacters = strlen(buffer.get());
928         buffer[numCharacters] = separator;
929         strcpy(buffer.get() + numCharacters + 1, pathOrURL);
930     }
931
932     return WKURLCreateWithUTF8CString(buffer.get());
933 }
934
935 static bool parseBooleanTestHeaderValue(const std::string& value)
936 {
937     if (value == "true")
938         return true;
939     if (value == "false")
940         return false;
941
942     LOG_ERROR("Found unexpected value '%s' for boolean option. Expected 'true' or 'false'.", value.c_str());
943     return false;
944 }
945
946 static void updateTestOptionsFromTestHeader(TestOptions& testOptions, const std::string& pathOrURL, const std::string& absolutePath)
947 {
948     std::string filename = absolutePath;
949     if (filename.empty()) {
950         // Gross. Need to reduce conversions between all the string types and URLs.
951         WKRetainPtr<WKURLRef> wkURL(AdoptWK, createTestURL(pathOrURL.c_str()));
952         filename = testPath(wkURL.get());
953     }
954
955     if (filename.empty())
956         return;
957
958     std::string options;
959     std::ifstream testFile(filename.data());
960     if (!testFile.good())
961         return;
962     getline(testFile, options);
963     std::string beginString("webkit-test-runner [ ");
964     std::string endString(" ]");
965     size_t beginLocation = options.find(beginString);
966     if (beginLocation == std::string::npos)
967         return;
968     size_t endLocation = options.find(endString, beginLocation);
969     if (endLocation == std::string::npos) {
970         LOG_ERROR("Could not find end of test header in %s", filename.c_str());
971         return;
972     }
973     std::string pairString = options.substr(beginLocation + beginString.size(), endLocation - (beginLocation + beginString.size()));
974     size_t pairStart = 0;
975     while (pairStart < pairString.size()) {
976         size_t pairEnd = pairString.find(" ", pairStart);
977         if (pairEnd == std::string::npos)
978             pairEnd = pairString.size();
979         size_t equalsLocation = pairString.find("=", pairStart);
980         if (equalsLocation == std::string::npos) {
981             LOG_ERROR("Malformed option in test header (could not find '=' character) in %s", filename.c_str());
982             break;
983         }
984         auto key = pairString.substr(pairStart, equalsLocation - pairStart);
985         auto value = pairString.substr(equalsLocation + 1, pairEnd - (equalsLocation + 1));
986         if (key == "language")
987             String(value.c_str()).split(",", false, testOptions.overrideLanguages);
988         if (key == "useThreadedScrolling")
989             testOptions.useThreadedScrolling = parseBooleanTestHeaderValue(value);
990         if (key == "useFlexibleViewport")
991             testOptions.useFlexibleViewport = parseBooleanTestHeaderValue(value);
992         if (key == "useDataDetection")
993             testOptions.useDataDetection = parseBooleanTestHeaderValue(value);
994         if (key == "useMockScrollbars")
995             testOptions.useMockScrollbars = parseBooleanTestHeaderValue(value);
996         if (key == "needsSiteSpecificQuirks")
997             testOptions.needsSiteSpecificQuirks = parseBooleanTestHeaderValue(value);
998         if (key == "ignoresViewportScaleLimits")
999             testOptions.ignoresViewportScaleLimits = parseBooleanTestHeaderValue(value);
1000         if (key == "useCharacterSelectionGranularity")
1001             testOptions.useCharacterSelectionGranularity = parseBooleanTestHeaderValue(value);
1002         if (key == "enableIntersectionObserver")
1003             testOptions.enableIntersectionObserver = parseBooleanTestHeaderValue(value);
1004         if (key == "enableModernMediaControls")
1005             testOptions.enableModernMediaControls = parseBooleanTestHeaderValue(value);
1006         if (key == "enablePointerLock")
1007             testOptions.enablePointerLock = parseBooleanTestHeaderValue(value);
1008         if (key == "enableCredentialManagement")
1009             testOptions.enableCredentialManagement = parseBooleanTestHeaderValue(value);
1010         pairStart = pairEnd + 1;
1011     }
1012 }
1013
1014 TestOptions TestController::testOptionsForTest(const TestCommand& command) const
1015 {
1016     TestOptions options(command.pathOrURL);
1017
1018     options.useRemoteLayerTree = m_shouldUseRemoteLayerTree;
1019     options.shouldShowWebView = m_shouldShowWebView;
1020
1021     updatePlatformSpecificTestOptionsForTest(options, command.pathOrURL);
1022     updateTestOptionsFromTestHeader(options, command.pathOrURL, command.absolutePath);
1023
1024     return options;
1025 }
1026
1027 void TestController::updateWebViewSizeForTest(const TestInvocation& test)
1028 {
1029     unsigned width = viewWidth;
1030     unsigned height = viewHeight;
1031     if (test.options().isSVGTest) {
1032         width = w3cSVGViewWidth;
1033         height = w3cSVGViewHeight;
1034     }
1035
1036     mainWebView()->resizeTo(width, height);
1037 }
1038
1039 void TestController::updateWindowScaleForTest(PlatformWebView* view, const TestInvocation& test)
1040 {
1041     view->changeWindowScaleIfNeeded(test.options().deviceScaleFactor);
1042 }
1043
1044 void TestController::configureViewForTest(const TestInvocation& test)
1045 {
1046     ensureViewSupportsOptionsForTest(test);
1047     updateWebViewSizeForTest(test);
1048     updateWindowScaleForTest(mainWebView(), test);
1049
1050     platformConfigureViewForTest(test);
1051 }
1052
1053 class CommandTokenizer {
1054 public:
1055     explicit CommandTokenizer(const std::string& input)
1056         : m_input(input)
1057         , m_posNextSeparator(0)
1058     {
1059         pump();
1060     }
1061
1062     bool hasNext() const;
1063     std::string next();
1064
1065 private:
1066     void pump();
1067     static const char kSeparator = '\'';
1068     const std::string& m_input;
1069     std::string m_next;
1070     size_t m_posNextSeparator;
1071 };
1072
1073 void CommandTokenizer::pump()
1074 {
1075     if (m_posNextSeparator == std::string::npos || m_posNextSeparator == m_input.size()) {
1076         m_next = std::string();
1077         return;
1078     }
1079     size_t start = m_posNextSeparator ? m_posNextSeparator + 1 : 0;
1080     m_posNextSeparator = m_input.find(kSeparator, start);
1081     size_t size = m_posNextSeparator == std::string::npos ? std::string::npos : m_posNextSeparator - start;
1082     m_next = std::string(m_input, start, size);
1083 }
1084
1085 std::string CommandTokenizer::next()
1086 {
1087     ASSERT(hasNext());
1088
1089     std::string oldNext = m_next;
1090     pump();
1091     return oldNext;
1092 }
1093
1094 bool CommandTokenizer::hasNext() const
1095 {
1096     return !m_next.empty();
1097 }
1098
1099 NO_RETURN static void die(const std::string& inputLine)
1100 {
1101     fprintf(stderr, "Unexpected input line: %s\n", inputLine.c_str());
1102     exit(1);
1103 }
1104
1105 TestCommand parseInputLine(const std::string& inputLine)
1106 {
1107     TestCommand result;
1108     CommandTokenizer tokenizer(inputLine);
1109     if (!tokenizer.hasNext())
1110         die(inputLine);
1111
1112     std::string arg = tokenizer.next();
1113     result.pathOrURL = arg;
1114     while (tokenizer.hasNext()) {
1115         arg = tokenizer.next();
1116         if (arg == std::string("--timeout")) {
1117             std::string timeoutToken = tokenizer.next();
1118             result.timeout = atoi(timeoutToken.c_str());
1119         } else if (arg == std::string("-p") || arg == std::string("--pixel-test")) {
1120             result.shouldDumpPixels = true;
1121             if (tokenizer.hasNext())
1122                 result.expectedPixelHash = tokenizer.next();
1123         } else if (arg == std::string("--dump-jsconsolelog-in-stderr"))
1124             result.dumpJSConsoleLogInStdErr = true;
1125         else if (arg == std::string("--absolutePath"))
1126             result.absolutePath = tokenizer.next();
1127         else
1128             die(inputLine);
1129     }
1130     return result;
1131 }
1132
1133 bool TestController::runTest(const char* inputLine)
1134 {
1135     WKTextCheckerSetTestingMode(true);
1136     TestCommand command = parseInputLine(std::string(inputLine));
1137
1138     m_state = RunningTest;
1139     
1140     TestOptions options = testOptionsForTest(command);
1141
1142     WKRetainPtr<WKURLRef> wkURL(AdoptWK, createTestURL(command.pathOrURL.c_str()));
1143     m_currentInvocation = std::make_unique<TestInvocation>(wkURL.get(), options);
1144
1145     if (command.shouldDumpPixels || m_shouldDumpPixelsForAllTests)
1146         m_currentInvocation->setIsPixelTest(command.expectedPixelHash);
1147     if (command.timeout > 0)
1148         m_currentInvocation->setCustomTimeout(command.timeout);
1149     m_currentInvocation->setDumpJSConsoleLogInStdErr(command.dumpJSConsoleLogInStdErr);
1150
1151     platformWillRunTest(*m_currentInvocation);
1152
1153     m_currentInvocation->invoke();
1154     m_currentInvocation = nullptr;
1155
1156     return true;
1157 }
1158
1159 void TestController::runTestingServerLoop()
1160 {
1161     char filenameBuffer[2048];
1162     while (fgets(filenameBuffer, sizeof(filenameBuffer), stdin)) {
1163         char* newLineCharacter = strchr(filenameBuffer, '\n');
1164         if (newLineCharacter)
1165             *newLineCharacter = '\0';
1166
1167         if (strlen(filenameBuffer) == 0)
1168             continue;
1169
1170         if (!runTest(filenameBuffer))
1171             break;
1172     }
1173 }
1174
1175 void TestController::run()
1176 {
1177     if (m_usingServerMode)
1178         runTestingServerLoop();
1179     else {
1180         for (size_t i = 0; i < m_paths.size(); ++i) {
1181             if (!runTest(m_paths[i].c_str()))
1182                 break;
1183         }
1184     }
1185 }
1186
1187 void TestController::runUntil(bool& done, double timeout)
1188 {
1189     if (m_forceNoTimeout)
1190         timeout = noTimeout;
1191
1192     platformRunUntil(done, timeout);
1193 }
1194
1195 // WKContextInjectedBundleClient
1196
1197 void TestController::didReceiveMessageFromInjectedBundle(WKContextRef context, WKStringRef messageName, WKTypeRef messageBody, const void* clientInfo)
1198 {
1199     static_cast<TestController*>(const_cast<void*>(clientInfo))->didReceiveMessageFromInjectedBundle(messageName, messageBody);
1200 }
1201
1202 void TestController::didReceiveSynchronousMessageFromInjectedBundle(WKContextRef context, WKStringRef messageName, WKTypeRef messageBody, WKTypeRef* returnData, const void* clientInfo)
1203 {
1204     *returnData = static_cast<TestController*>(const_cast<void*>(clientInfo))->didReceiveSynchronousMessageFromInjectedBundle(messageName, messageBody).leakRef();
1205 }
1206
1207 WKTypeRef TestController::getInjectedBundleInitializationUserData(WKContextRef, const void* clientInfo)
1208 {
1209     return static_cast<TestController*>(const_cast<void*>(clientInfo))->getInjectedBundleInitializationUserData().leakRef();
1210 }
1211
1212 // WKPageInjectedBundleClient
1213
1214 void TestController::didReceivePageMessageFromInjectedBundle(WKPageRef page, WKStringRef messageName, WKTypeRef messageBody, const void* clientInfo)
1215 {
1216     static_cast<TestController*>(const_cast<void*>(clientInfo))->didReceiveMessageFromInjectedBundle(messageName, messageBody);
1217 }
1218
1219 void TestController::didReceiveSynchronousPageMessageFromInjectedBundle(WKPageRef page, WKStringRef messageName, WKTypeRef messageBody, WKTypeRef* returnData, const void* clientInfo)
1220 {
1221     *returnData = static_cast<TestController*>(const_cast<void*>(clientInfo))->didReceiveSynchronousMessageFromInjectedBundle(messageName, messageBody).leakRef();
1222 }
1223
1224 void TestController::networkProcessDidCrash(WKContextRef context, const void *clientInfo)
1225 {
1226     static_cast<TestController*>(const_cast<void*>(clientInfo))->networkProcessDidCrash();
1227 }
1228
1229 void TestController::databaseProcessDidCrash(WKContextRef context, const void *clientInfo)
1230 {
1231     static_cast<TestController*>(const_cast<void*>(clientInfo))->databaseProcessDidCrash();
1232 }
1233
1234 void TestController::didReceiveKeyDownMessageFromInjectedBundle(WKDictionaryRef messageBodyDictionary, bool synchronous)
1235 {
1236     WKRetainPtr<WKStringRef> keyKey = adoptWK(WKStringCreateWithUTF8CString("Key"));
1237     WKStringRef key = static_cast<WKStringRef>(WKDictionaryGetItemForKey(messageBodyDictionary, keyKey.get()));
1238
1239     WKRetainPtr<WKStringRef> modifiersKey = adoptWK(WKStringCreateWithUTF8CString("Modifiers"));
1240     WKEventModifiers modifiers = static_cast<WKEventModifiers>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, modifiersKey.get()))));
1241
1242     WKRetainPtr<WKStringRef> locationKey = adoptWK(WKStringCreateWithUTF8CString("Location"));
1243     unsigned location = static_cast<unsigned>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, locationKey.get()))));
1244
1245     m_eventSenderProxy->keyDown(key, modifiers, location);
1246 }
1247
1248 void TestController::didReceiveMessageFromInjectedBundle(WKStringRef messageName, WKTypeRef messageBody)
1249 {
1250     if (WKStringIsEqualToUTF8CString(messageName, "EventSender")) {
1251         if (m_state != RunningTest)
1252             return;
1253
1254         ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID());
1255         WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody);
1256
1257         WKRetainPtr<WKStringRef> subMessageKey(AdoptWK, WKStringCreateWithUTF8CString("SubMessage"));
1258         WKStringRef subMessageName = static_cast<WKStringRef>(WKDictionaryGetItemForKey(messageBodyDictionary, subMessageKey.get()));
1259
1260         if (WKStringIsEqualToUTF8CString(subMessageName, "MouseDown") || WKStringIsEqualToUTF8CString(subMessageName, "MouseUp")) {
1261             WKRetainPtr<WKStringRef> buttonKey = adoptWK(WKStringCreateWithUTF8CString("Button"));
1262             unsigned button = static_cast<unsigned>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, buttonKey.get()))));
1263
1264             WKRetainPtr<WKStringRef> modifiersKey = adoptWK(WKStringCreateWithUTF8CString("Modifiers"));
1265             WKEventModifiers modifiers = static_cast<WKEventModifiers>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, modifiersKey.get()))));
1266
1267             // Forward to WebProcess
1268             if (WKStringIsEqualToUTF8CString(subMessageName, "MouseDown"))
1269                 m_eventSenderProxy->mouseDown(button, modifiers);
1270             else
1271                 m_eventSenderProxy->mouseUp(button, modifiers);
1272
1273             return;
1274         }
1275
1276         if (WKStringIsEqualToUTF8CString(subMessageName, "KeyDown")) {
1277             didReceiveKeyDownMessageFromInjectedBundle(messageBodyDictionary, false);
1278
1279             return;
1280         }
1281
1282         if (WKStringIsEqualToUTF8CString(subMessageName, "MouseScrollBy")) {
1283             WKRetainPtr<WKStringRef> xKey = adoptWK(WKStringCreateWithUTF8CString("X"));
1284             double x = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, xKey.get())));
1285
1286             WKRetainPtr<WKStringRef> yKey = adoptWK(WKStringCreateWithUTF8CString("Y"));
1287             double y = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, yKey.get())));
1288
1289             // Forward to WebProcess
1290             m_eventSenderProxy->mouseScrollBy(x, y);
1291             return;
1292         }
1293
1294         if (WKStringIsEqualToUTF8CString(subMessageName, "MouseScrollByWithWheelAndMomentumPhases")) {
1295             WKRetainPtr<WKStringRef> xKey = adoptWK(WKStringCreateWithUTF8CString("X"));
1296             double x = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, xKey.get())));
1297             
1298             WKRetainPtr<WKStringRef> yKey = adoptWK(WKStringCreateWithUTF8CString("Y"));
1299             double y = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, yKey.get())));
1300             
1301             WKRetainPtr<WKStringRef> phaseKey = adoptWK(WKStringCreateWithUTF8CString("Phase"));
1302             int phase = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, phaseKey.get()))));
1303             WKRetainPtr<WKStringRef> momentumKey = adoptWK(WKStringCreateWithUTF8CString("Momentum"));
1304             int momentum = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, momentumKey.get()))));
1305             
1306             // Forward to WebProcess
1307             m_eventSenderProxy->mouseScrollByWithWheelAndMomentumPhases(x, y, phase, momentum);
1308
1309             return;
1310         }
1311
1312         ASSERT_NOT_REACHED();
1313     }
1314
1315     if (!m_currentInvocation)
1316         return;
1317
1318     m_currentInvocation->didReceiveMessageFromInjectedBundle(messageName, messageBody);
1319 }
1320
1321 WKRetainPtr<WKTypeRef> TestController::didReceiveSynchronousMessageFromInjectedBundle(WKStringRef messageName, WKTypeRef messageBody)
1322 {
1323     if (WKStringIsEqualToUTF8CString(messageName, "EventSender")) {
1324         if (m_state != RunningTest)
1325             return nullptr;
1326
1327         ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID());
1328         WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody);
1329
1330         WKRetainPtr<WKStringRef> subMessageKey(AdoptWK, WKStringCreateWithUTF8CString("SubMessage"));
1331         WKStringRef subMessageName = static_cast<WKStringRef>(WKDictionaryGetItemForKey(messageBodyDictionary, subMessageKey.get()));
1332
1333         if (WKStringIsEqualToUTF8CString(subMessageName, "KeyDown")) {
1334             didReceiveKeyDownMessageFromInjectedBundle(messageBodyDictionary, true);
1335
1336             return 0;
1337         }
1338
1339         if (WKStringIsEqualToUTF8CString(subMessageName, "MouseDown") || WKStringIsEqualToUTF8CString(subMessageName, "MouseUp")) {
1340             WKRetainPtr<WKStringRef> buttonKey = adoptWK(WKStringCreateWithUTF8CString("Button"));
1341             unsigned button = static_cast<unsigned>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, buttonKey.get()))));
1342
1343             WKRetainPtr<WKStringRef> modifiersKey = adoptWK(WKStringCreateWithUTF8CString("Modifiers"));
1344             WKEventModifiers modifiers = static_cast<WKEventModifiers>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, modifiersKey.get()))));
1345
1346             // Forward to WebProcess
1347             if (WKStringIsEqualToUTF8CString(subMessageName, "MouseDown"))
1348                 m_eventSenderProxy->mouseDown(button, modifiers);
1349             else
1350                 m_eventSenderProxy->mouseUp(button, modifiers);
1351             return 0;
1352         }
1353
1354         if (WKStringIsEqualToUTF8CString(subMessageName, "MouseMoveTo")) {
1355             WKRetainPtr<WKStringRef> xKey = adoptWK(WKStringCreateWithUTF8CString("X"));
1356             double x = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, xKey.get())));
1357
1358             WKRetainPtr<WKStringRef> yKey = adoptWK(WKStringCreateWithUTF8CString("Y"));
1359             double y = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, yKey.get())));
1360
1361             // Forward to WebProcess
1362             m_eventSenderProxy->mouseMoveTo(x, y);
1363             return 0;
1364         }
1365
1366 #if PLATFORM(MAC)
1367         if (WKStringIsEqualToUTF8CString(subMessageName, "MouseForceClick")) {
1368             m_eventSenderProxy->mouseForceClick();
1369             return 0;
1370         }
1371
1372         if (WKStringIsEqualToUTF8CString(subMessageName, "StartAndCancelMouseForceClick")) {
1373             m_eventSenderProxy->startAndCancelMouseForceClick();
1374             return 0;
1375         }
1376
1377         if (WKStringIsEqualToUTF8CString(subMessageName, "MouseForceDown")) {
1378             m_eventSenderProxy->mouseForceDown();
1379             return 0;
1380         }
1381
1382         if (WKStringIsEqualToUTF8CString(subMessageName, "MouseForceUp")) {
1383             m_eventSenderProxy->mouseForceUp();
1384             return 0;
1385         }
1386
1387         if (WKStringIsEqualToUTF8CString(subMessageName, "MouseForceChanged")) {
1388             WKRetainPtr<WKStringRef> forceKey = adoptWK(WKStringCreateWithUTF8CString("Force"));
1389             double force = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, forceKey.get())));
1390
1391             m_eventSenderProxy->mouseForceChanged(force);
1392             return 0;
1393         }
1394 #endif // PLATFORM(MAC)
1395
1396         if (WKStringIsEqualToUTF8CString(subMessageName, "ContinuousMouseScrollBy")) {
1397             WKRetainPtr<WKStringRef> xKey = adoptWK(WKStringCreateWithUTF8CString("X"));
1398             double x = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, xKey.get())));
1399
1400             WKRetainPtr<WKStringRef> yKey = adoptWK(WKStringCreateWithUTF8CString("Y"));
1401             double y = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, yKey.get())));
1402
1403             WKRetainPtr<WKStringRef> pagedKey = adoptWK(WKStringCreateWithUTF8CString("Paged"));
1404             bool paged = static_cast<bool>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, pagedKey.get()))));
1405
1406             // Forward to WebProcess
1407             m_eventSenderProxy->continuousMouseScrollBy(x, y, paged);
1408             return 0;
1409         }
1410
1411         if (WKStringIsEqualToUTF8CString(subMessageName, "LeapForward")) {
1412             WKRetainPtr<WKStringRef> timeKey = adoptWK(WKStringCreateWithUTF8CString("TimeInMilliseconds"));
1413             unsigned time = static_cast<unsigned>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, timeKey.get()))));
1414
1415             m_eventSenderProxy->leapForward(time);
1416             return 0;
1417         }
1418
1419 #if ENABLE(TOUCH_EVENTS)
1420         if (WKStringIsEqualToUTF8CString(subMessageName, "AddTouchPoint")) {
1421             WKRetainPtr<WKStringRef> xKey = adoptWK(WKStringCreateWithUTF8CString("X"));
1422             int x = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, xKey.get()))));
1423
1424             WKRetainPtr<WKStringRef> yKey = adoptWK(WKStringCreateWithUTF8CString("Y"));
1425             int y = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, yKey.get()))));
1426
1427             m_eventSenderProxy->addTouchPoint(x, y);
1428             return 0;
1429         }
1430
1431         if (WKStringIsEqualToUTF8CString(subMessageName, "UpdateTouchPoint")) {
1432             WKRetainPtr<WKStringRef> indexKey = adoptWK(WKStringCreateWithUTF8CString("Index"));
1433             int index = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, indexKey.get()))));
1434
1435             WKRetainPtr<WKStringRef> xKey = adoptWK(WKStringCreateWithUTF8CString("X"));
1436             int x = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, xKey.get()))));
1437
1438             WKRetainPtr<WKStringRef> yKey = adoptWK(WKStringCreateWithUTF8CString("Y"));
1439             int y = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, yKey.get()))));
1440
1441             m_eventSenderProxy->updateTouchPoint(index, x, y);
1442             return 0;
1443         }
1444
1445         if (WKStringIsEqualToUTF8CString(subMessageName, "SetTouchModifier")) {
1446             WKRetainPtr<WKStringRef> modifierKey = adoptWK(WKStringCreateWithUTF8CString("Modifier"));
1447             WKEventModifiers modifier = static_cast<WKEventModifiers>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, modifierKey.get()))));
1448
1449             WKRetainPtr<WKStringRef> enableKey = adoptWK(WKStringCreateWithUTF8CString("Enable"));
1450             bool enable = static_cast<bool>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, enableKey.get()))));
1451
1452             m_eventSenderProxy->setTouchModifier(modifier, enable);
1453             return 0;
1454         }
1455
1456         if (WKStringIsEqualToUTF8CString(subMessageName, "SetTouchPointRadius")) {
1457             WKRetainPtr<WKStringRef> xKey = adoptWK(WKStringCreateWithUTF8CString("RadiusX"));
1458             int x = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, xKey.get()))));
1459
1460             WKRetainPtr<WKStringRef> yKey = adoptWK(WKStringCreateWithUTF8CString("RadiusY"));
1461             int y = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, yKey.get()))));
1462
1463             m_eventSenderProxy->setTouchPointRadius(x, y);
1464             return 0;
1465         }
1466
1467         if (WKStringIsEqualToUTF8CString(subMessageName, "TouchStart")) {
1468             m_eventSenderProxy->touchStart();
1469             return 0;
1470         }
1471
1472         if (WKStringIsEqualToUTF8CString(subMessageName, "TouchMove")) {
1473             m_eventSenderProxy->touchMove();
1474             return 0;
1475         }
1476
1477         if (WKStringIsEqualToUTF8CString(subMessageName, "TouchEnd")) {
1478             m_eventSenderProxy->touchEnd();
1479             return 0;
1480         }
1481
1482         if (WKStringIsEqualToUTF8CString(subMessageName, "TouchCancel")) {
1483             m_eventSenderProxy->touchCancel();
1484             return 0;
1485         }
1486
1487         if (WKStringIsEqualToUTF8CString(subMessageName, "ClearTouchPoints")) {
1488             m_eventSenderProxy->clearTouchPoints();
1489             return 0;
1490         }
1491
1492         if (WKStringIsEqualToUTF8CString(subMessageName, "ReleaseTouchPoint")) {
1493             WKRetainPtr<WKStringRef> indexKey = adoptWK(WKStringCreateWithUTF8CString("Index"));
1494             int index = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, indexKey.get()))));
1495             m_eventSenderProxy->releaseTouchPoint(index);
1496             return 0;
1497         }
1498
1499         if (WKStringIsEqualToUTF8CString(subMessageName, "CancelTouchPoint")) {
1500             WKRetainPtr<WKStringRef> indexKey = adoptWK(WKStringCreateWithUTF8CString("Index"));
1501             int index = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, indexKey.get()))));
1502             m_eventSenderProxy->cancelTouchPoint(index);
1503             return 0;
1504         }
1505 #endif
1506         ASSERT_NOT_REACHED();
1507     }
1508     return m_currentInvocation->didReceiveSynchronousMessageFromInjectedBundle(messageName, messageBody);
1509 }
1510
1511 WKRetainPtr<WKTypeRef> TestController::getInjectedBundleInitializationUserData()
1512 {
1513     return nullptr;
1514 }
1515
1516 // WKContextClient
1517
1518 void TestController::networkProcessDidCrash()
1519 {
1520     pid_t pid = WKContextGetNetworkProcessIdentifier(m_context.get());
1521     fprintf(stderr, "#CRASHED - %s (pid %ld)\n", networkProcessName(), static_cast<long>(pid));
1522     exit(1);
1523 }
1524
1525 void TestController::databaseProcessDidCrash()
1526 {
1527     pid_t pid = WKContextGetDatabaseProcessIdentifier(m_context.get());
1528     fprintf(stderr, "#CRASHED - %s (pid %ld)\n", databaseProcessName(), static_cast<long>(pid));
1529     exit(1);
1530 }
1531
1532 // WKPageNavigationClient
1533
1534 void TestController::didCommitNavigation(WKPageRef page, WKNavigationRef navigation, WKTypeRef, const void* clientInfo)
1535 {
1536     static_cast<TestController*>(const_cast<void*>(clientInfo))->didCommitNavigation(page, navigation);
1537 }
1538
1539 void TestController::didFinishNavigation(WKPageRef page, WKNavigationRef navigation, WKTypeRef, const void* clientInfo)
1540 {
1541     static_cast<TestController*>(const_cast<void*>(clientInfo))->didFinishNavigation(page, navigation);
1542 }
1543
1544 bool TestController::canAuthenticateAgainstProtectionSpace(WKPageRef page, WKProtectionSpaceRef protectionSpace, const void* clientInfo)
1545 {
1546     return static_cast<TestController*>(const_cast<void*>(clientInfo))->canAuthenticateAgainstProtectionSpace(page, protectionSpace);
1547 }
1548
1549 void TestController::didReceiveAuthenticationChallenge(WKPageRef page, WKAuthenticationChallengeRef authenticationChallenge, const void *clientInfo)
1550 {
1551     static_cast<TestController*>(const_cast<void*>(clientInfo))->didReceiveAuthenticationChallenge(page, /*frame,*/ authenticationChallenge);
1552 }
1553
1554 void TestController::processDidCrash(WKPageRef page, const void* clientInfo)
1555 {
1556     static_cast<TestController*>(const_cast<void*>(clientInfo))->processDidCrash();
1557 }
1558
1559 void TestController::didBeginNavigationGesture(WKPageRef page, const void *clientInfo)
1560 {
1561     static_cast<TestController*>(const_cast<void*>(clientInfo))->didBeginNavigationGesture(page);
1562 }
1563
1564 void TestController::willEndNavigationGesture(WKPageRef page, WKBackForwardListItemRef backForwardListItem, const void *clientInfo)
1565 {
1566     static_cast<TestController*>(const_cast<void*>(clientInfo))->willEndNavigationGesture(page, backForwardListItem);
1567 }
1568
1569 void TestController::didEndNavigationGesture(WKPageRef page, WKBackForwardListItemRef backForwardListItem, const void *clientInfo)
1570 {
1571     static_cast<TestController*>(const_cast<void*>(clientInfo))->didEndNavigationGesture(page, backForwardListItem);
1572 }
1573
1574 void TestController::didRemoveNavigationGestureSnapshot(WKPageRef page, const void *clientInfo)
1575 {
1576     static_cast<TestController*>(const_cast<void*>(clientInfo))->didRemoveNavigationGestureSnapshot(page);
1577 }
1578
1579 WKPluginLoadPolicy TestController::decidePolicyForPluginLoad(WKPageRef page, WKPluginLoadPolicy currentPluginLoadPolicy, WKDictionaryRef pluginInformation, WKStringRef* unavailabilityDescription, const void* clientInfo)
1580 {
1581     return static_cast<TestController*>(const_cast<void*>(clientInfo))->decidePolicyForPluginLoad(page, currentPluginLoadPolicy, pluginInformation, unavailabilityDescription);
1582 }
1583
1584 WKPluginLoadPolicy TestController::decidePolicyForPluginLoad(WKPageRef, WKPluginLoadPolicy currentPluginLoadPolicy, WKDictionaryRef pluginInformation, WKStringRef* unavailabilityDescription)
1585 {
1586     if (m_shouldBlockAllPlugins)
1587         return kWKPluginLoadPolicyBlocked;
1588
1589 #if PLATFORM(MAC)
1590     WKStringRef bundleIdentifier = (WKStringRef)WKDictionaryGetItemForKey(pluginInformation, WKPluginInformationBundleIdentifierKey());
1591     if (!bundleIdentifier)
1592         return currentPluginLoadPolicy;
1593
1594     if (WKStringIsEqualToUTF8CString(bundleIdentifier, "com.apple.QuickTime Plugin.plugin"))
1595         return currentPluginLoadPolicy;
1596
1597     if (WKStringIsEqualToUTF8CString(bundleIdentifier, "com.apple.testnetscapeplugin"))
1598         return currentPluginLoadPolicy;
1599
1600     RELEASE_ASSERT_NOT_REACHED(); // Please don't use any other plug-ins in tests, as they will not be installed on all machines.
1601 #else
1602     return currentPluginLoadPolicy;
1603 #endif
1604 }
1605
1606 void TestController::didCommitNavigation(WKPageRef page, WKNavigationRef navigation)
1607 {
1608     mainWebView()->focus();
1609 }
1610
1611 bool TestController::canAuthenticateAgainstProtectionSpace(WKPageRef page, WKProtectionSpaceRef protectionSpace)
1612 {
1613     if (m_shouldLogCanAuthenticateAgainstProtectionSpace)
1614         m_currentInvocation->outputText("canAuthenticateAgainstProtectionSpace\n");
1615     WKProtectionSpaceAuthenticationScheme authenticationScheme = WKProtectionSpaceGetAuthenticationScheme(protectionSpace);
1616     
1617     if (authenticationScheme == kWKProtectionSpaceAuthenticationSchemeServerTrustEvaluationRequested) {
1618         std::string host = toSTD(adoptWK(WKProtectionSpaceCopyHost(protectionSpace)).get());
1619         return host == "localhost" || host == "127.0.0.1";
1620     }
1621     
1622     return authenticationScheme <= kWKProtectionSpaceAuthenticationSchemeHTTPDigest;
1623 }
1624
1625 void TestController::didFinishNavigation(WKPageRef page, WKNavigationRef navigation)
1626 {
1627     if (m_state != Resetting)
1628         return;
1629
1630     WKRetainPtr<WKURLRef> wkURL(AdoptWK, WKFrameCopyURL(WKPageGetMainFrame(page)));
1631     if (!WKURLIsEqual(wkURL.get(), blankURL()))
1632         return;
1633
1634     m_doneResetting = true;
1635     singleton().notifyDone();
1636 }
1637
1638 void TestController::didReceiveAuthenticationChallenge(WKPageRef page, WKAuthenticationChallengeRef authenticationChallenge)
1639 {
1640     WKProtectionSpaceRef protectionSpace = WKAuthenticationChallengeGetProtectionSpace(authenticationChallenge);
1641     WKAuthenticationDecisionListenerRef decisionListener = WKAuthenticationChallengeGetDecisionListener(authenticationChallenge);
1642
1643     if (WKProtectionSpaceGetAuthenticationScheme(protectionSpace) == kWKProtectionSpaceAuthenticationSchemeServerTrustEvaluationRequested) {
1644         // Any non-empty credential signals to accept the server trust. Since the cross-platform API
1645         // doesn't expose a way to create a credential from server trust, we use a password credential.
1646
1647         WKRetainPtr<WKCredentialRef> credential = adoptWK(WKCredentialCreate(toWK("accept server trust").get(), toWK("").get(), kWKCredentialPersistenceNone));
1648         WKAuthenticationDecisionListenerUseCredential(decisionListener, credential.get());
1649         return;
1650     }
1651
1652     if (m_rejectsProtectionSpaceAndContinueForAuthenticationChallenges) {
1653         m_currentInvocation->outputText("Simulating reject protection space and continue for authentication challenge\n");
1654         WKAuthenticationDecisionListenerRejectProtectionSpaceAndContinue(decisionListener);
1655         return;
1656     }
1657
1658     std::string host = toSTD(adoptWK(WKProtectionSpaceCopyHost(protectionSpace)).get());
1659     int port = WKProtectionSpaceGetPort(protectionSpace);
1660     String message = String::format("%s:%d - didReceiveAuthenticationChallenge - ", host.c_str(), port);
1661     if (!m_handlesAuthenticationChallenges)
1662         message.append("Simulating cancelled authentication sheet\n");
1663     else
1664         message.append(String::format("Responding with %s:%s\n", m_authenticationUsername.utf8().data(), m_authenticationPassword.utf8().data()));
1665     m_currentInvocation->outputText(message);
1666
1667     if (!m_handlesAuthenticationChallenges) {
1668         WKAuthenticationDecisionListenerUseCredential(decisionListener, 0);
1669         return;
1670     }
1671     WKRetainPtr<WKStringRef> username(AdoptWK, WKStringCreateWithUTF8CString(m_authenticationUsername.utf8().data()));
1672     WKRetainPtr<WKStringRef> password(AdoptWK, WKStringCreateWithUTF8CString(m_authenticationPassword.utf8().data()));
1673     WKRetainPtr<WKCredentialRef> credential(AdoptWK, WKCredentialCreate(username.get(), password.get(), kWKCredentialPersistenceForSession));
1674     WKAuthenticationDecisionListenerUseCredential(decisionListener, credential.get());
1675 }
1676
1677     
1678 // WKContextDownloadClient
1679
1680 void TestController::downloadDidStart(WKContextRef context, WKDownloadRef download, const void* clientInfo)
1681 {
1682     static_cast<TestController*>(const_cast<void*>(clientInfo))->downloadDidStart(context, download);
1683 }
1684     
1685 WKStringRef TestController::decideDestinationWithSuggestedFilename(WKContextRef context, WKDownloadRef download, WKStringRef filename, bool* allowOverwrite, const void* clientInfo)
1686 {
1687     return static_cast<TestController*>(const_cast<void*>(clientInfo))->decideDestinationWithSuggestedFilename(context, download, filename, allowOverwrite);
1688 }
1689
1690 void TestController::downloadDidFinish(WKContextRef context, WKDownloadRef download, const void* clientInfo)
1691 {
1692     static_cast<TestController*>(const_cast<void*>(clientInfo))->downloadDidFinish(context, download);
1693 }
1694
1695 void TestController::downloadDidFail(WKContextRef context, WKDownloadRef download, WKErrorRef error, const void* clientInfo)
1696 {
1697     static_cast<TestController*>(const_cast<void*>(clientInfo))->downloadDidFail(context, download, error);
1698 }
1699
1700 void TestController::downloadDidCancel(WKContextRef context, WKDownloadRef download, const void* clientInfo)
1701 {
1702     static_cast<TestController*>(const_cast<void*>(clientInfo))->downloadDidCancel(context, download);
1703 }
1704
1705 void TestController::downloadDidStart(WKContextRef context, WKDownloadRef download)
1706 {
1707     m_currentInvocation->outputText("Download started.\n");
1708 }
1709
1710 WKStringRef TestController::decideDestinationWithSuggestedFilename(WKContextRef, WKDownloadRef, WKStringRef filename, bool*& allowOverwrite)
1711 {
1712     String suggestedFilename = toWTFString(filename);
1713
1714     StringBuilder builder;
1715     builder.append("Downloading URL with suggested filename \"");
1716     builder.append(suggestedFilename);
1717     builder.append("\"\n");
1718
1719     m_currentInvocation->outputText(builder.toString());
1720
1721     const char* dumpRenderTreeTemp = libraryPathForTesting();
1722     if (!dumpRenderTreeTemp)
1723         return nullptr;
1724
1725     *allowOverwrite = true;
1726     String temporaryFolder = String::fromUTF8(dumpRenderTreeTemp);
1727     if (suggestedFilename.isEmpty())
1728         suggestedFilename = "Unknown";
1729
1730     return toWK(temporaryFolder + "/" + suggestedFilename).leakRef();
1731 }
1732
1733 void TestController::downloadDidFinish(WKContextRef, WKDownloadRef)
1734 {
1735     m_currentInvocation->outputText("Download completed.\n");
1736     m_currentInvocation->notifyDownloadDone();
1737 }
1738
1739 void TestController::downloadDidFail(WKContextRef, WKDownloadRef, WKErrorRef error)
1740 {
1741     String message = String::format("Download failed.\n");
1742     m_currentInvocation->outputText(message);
1743     
1744     WKRetainPtr<WKStringRef> errorDomain = adoptWK(WKErrorCopyDomain(error));
1745     WKRetainPtr<WKStringRef> errorDescription = adoptWK(WKErrorCopyLocalizedDescription(error));
1746     int errorCode = WKErrorGetErrorCode(error);
1747
1748     StringBuilder errorBuilder;
1749     errorBuilder.append("Failed: ");
1750     errorBuilder.append(toWTFString(errorDomain));
1751     errorBuilder.append(", code=");
1752     errorBuilder.appendNumber(errorCode);
1753     errorBuilder.append(", description=");
1754     errorBuilder.append(toWTFString(errorDescription));
1755     errorBuilder.append("\n");
1756
1757     m_currentInvocation->outputText(errorBuilder.toString());
1758     m_currentInvocation->notifyDownloadDone();
1759 }
1760
1761 void TestController::downloadDidCancel(WKContextRef, WKDownloadRef)
1762 {
1763     m_currentInvocation->outputText("Download cancelled.\n");
1764     m_currentInvocation->notifyDownloadDone();
1765 }
1766
1767 void TestController::processDidCrash()
1768 {
1769     // This function can be called multiple times when crash logs are being saved on Windows, so
1770     // ensure we only print the crashed message once.
1771     if (!m_didPrintWebProcessCrashedMessage) {
1772         pid_t pid = WKPageGetProcessIdentifier(m_mainWebView->page());
1773         fprintf(stderr, "#CRASHED - %s (pid %ld)\n", webProcessName(), static_cast<long>(pid));
1774         fflush(stderr);
1775         m_didPrintWebProcessCrashedMessage = true;
1776     }
1777
1778     if (m_shouldExitWhenWebProcessCrashes)
1779         exit(1);
1780 }
1781
1782 void TestController::didBeginNavigationGesture(WKPageRef)
1783 {
1784     m_currentInvocation->didBeginSwipe();
1785 }
1786
1787 void TestController::willEndNavigationGesture(WKPageRef, WKBackForwardListItemRef)
1788 {
1789     m_currentInvocation->willEndSwipe();
1790 }
1791
1792 void TestController::didEndNavigationGesture(WKPageRef, WKBackForwardListItemRef)
1793 {
1794     m_currentInvocation->didEndSwipe();
1795 }
1796
1797 void TestController::didRemoveNavigationGestureSnapshot(WKPageRef)
1798 {
1799     m_currentInvocation->didRemoveSwipeSnapshot();
1800 }
1801
1802 void TestController::simulateWebNotificationClick(uint64_t notificationID)
1803 {
1804     m_webNotificationProvider.simulateWebNotificationClick(mainWebView()->page(), notificationID);
1805 }
1806
1807 void TestController::setGeolocationPermission(bool enabled)
1808 {
1809     m_isGeolocationPermissionSet = true;
1810     m_isGeolocationPermissionAllowed = enabled;
1811     decidePolicyForGeolocationPermissionRequestIfPossible();
1812 }
1813
1814 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)
1815 {
1816     m_geolocationProvider->setPosition(latitude, longitude, accuracy, providesAltitude, altitude, providesAltitudeAccuracy, altitudeAccuracy, providesHeading, heading, providesSpeed, speed);
1817 }
1818
1819 void TestController::setMockGeolocationPositionUnavailableError(WKStringRef errorMessage)
1820 {
1821     m_geolocationProvider->setPositionUnavailableError(errorMessage);
1822 }
1823
1824 void TestController::handleGeolocationPermissionRequest(WKGeolocationPermissionRequestRef geolocationPermissionRequest)
1825 {
1826     m_geolocationPermissionRequests.append(geolocationPermissionRequest);
1827     decidePolicyForGeolocationPermissionRequestIfPossible();
1828 }
1829
1830 bool TestController::isGeolocationProviderActive() const
1831 {
1832     return m_geolocationProvider->isActive();
1833 }
1834
1835 static String originUserVisibleName(WKSecurityOriginRef origin)
1836 {
1837     if (!origin)
1838         return emptyString();
1839
1840     std::string host = toSTD(adoptWK(WKSecurityOriginCopyHost(origin))).c_str();
1841     std::string protocol = toSTD(adoptWK(WKSecurityOriginCopyProtocol(origin))).c_str();
1842
1843     if (!host.length() || !protocol.length())
1844         return emptyString();
1845
1846     unsigned short port = WKSecurityOriginGetPort(origin);
1847     if (port)
1848         return String::format("%s://%s:%d", protocol.c_str(), host.c_str(), port);
1849
1850     return String::format("%s://%s", protocol.c_str(), host.c_str());
1851 }
1852
1853 static String userMediaOriginHash(WKSecurityOriginRef userMediaDocumentOrigin, WKSecurityOriginRef topLevelDocumentOrigin)
1854 {
1855     String userMediaDocumentOriginString = originUserVisibleName(userMediaDocumentOrigin);
1856     String topLevelDocumentOriginString = originUserVisibleName(topLevelDocumentOrigin);
1857
1858     if (topLevelDocumentOriginString.isEmpty())
1859         return userMediaDocumentOriginString;
1860
1861     return String::format("%s-%s", userMediaDocumentOriginString.utf8().data(), topLevelDocumentOriginString.utf8().data());
1862 }
1863
1864 static String userMediaOriginHash(WKStringRef userMediaDocumentOriginString, WKStringRef topLevelDocumentOriginString)
1865 {
1866     auto userMediaDocumentOrigin = adoptWK(WKSecurityOriginCreateFromString(userMediaDocumentOriginString));
1867     if (!WKStringGetLength(topLevelDocumentOriginString))
1868         return userMediaOriginHash(userMediaDocumentOrigin.get(), nullptr);
1869
1870     auto topLevelDocumentOrigin = adoptWK(WKSecurityOriginCreateFromString(topLevelDocumentOriginString));
1871     return userMediaOriginHash(userMediaDocumentOrigin.get(), topLevelDocumentOrigin.get());
1872 }
1873
1874 void TestController::setUserMediaPermission(bool enabled)
1875 {
1876     m_isUserMediaPermissionSet = true;
1877     m_isUserMediaPermissionAllowed = enabled;
1878     decidePolicyForUserMediaPermissionRequestIfPossible();
1879 }
1880
1881 class OriginSettings : public RefCounted<OriginSettings> {
1882 public:
1883     explicit OriginSettings()
1884     {
1885     }
1886
1887     bool persistentPermission() const { return m_persistentPermission; }
1888     void setPersistentPermission(bool permission) { m_persistentPermission = permission; }
1889
1890     String persistentSalt() const { return m_persistentSalt; }
1891     void setPersistentSalt(const String& salt) { m_persistentSalt = salt; }
1892
1893     HashMap<uint64_t, String>& ephemeralSalts() { return m_ephemeralSalts; }
1894
1895     void incrementRequestCount() { ++m_requestCount; }
1896     void resetRequestCount() { m_requestCount = 0; }
1897     unsigned requestCount() const { return m_requestCount; }
1898
1899 private:
1900     HashMap<uint64_t, String> m_ephemeralSalts;
1901     String m_persistentSalt;
1902     unsigned m_requestCount { 0 };
1903     bool m_persistentPermission { false };
1904 };
1905
1906 String TestController::saltForOrigin(WKFrameRef frame, String originHash)
1907 {
1908     auto& settings = settingsForOrigin(originHash);
1909     auto& ephemeralSalts = settings.ephemeralSalts();
1910     auto frameInfo = adoptWK(WKFrameCreateFrameInfo(frame));
1911     auto frameHandle = WKFrameInfoGetFrameHandleRef(frameInfo.get());
1912     uint64_t frameIdentifier = WKFrameHandleGetFrameID(frameHandle);
1913     String frameSalt = ephemeralSalts.get(frameIdentifier);
1914
1915     if (settings.persistentPermission()) {
1916         if (frameSalt.length())
1917             return frameSalt;
1918
1919         if (!settings.persistentSalt().length())
1920             settings.setPersistentSalt(createCanonicalUUIDString());
1921
1922         return settings.persistentSalt();
1923     }
1924
1925     if (!frameSalt.length()) {
1926         frameSalt = createCanonicalUUIDString();
1927         ephemeralSalts.add(frameIdentifier, frameSalt);
1928     }
1929
1930     return frameSalt;
1931 }
1932
1933 void TestController::setUserMediaPersistentPermissionForOrigin(bool permission, WKStringRef userMediaDocumentOriginString, WKStringRef topLevelDocumentOriginString)
1934 {
1935     auto originHash = userMediaOriginHash(userMediaDocumentOriginString, topLevelDocumentOriginString);
1936     auto& settings = settingsForOrigin(originHash);
1937     settings.setPersistentPermission(permission);
1938 }
1939
1940 void TestController::handleCheckOfUserMediaPermissionForOrigin(WKFrameRef frame, WKSecurityOriginRef userMediaDocumentOrigin, WKSecurityOriginRef topLevelDocumentOrigin, const WKUserMediaPermissionCheckRef& checkRequest)
1941 {
1942     auto originHash = userMediaOriginHash(userMediaDocumentOrigin, topLevelDocumentOrigin);
1943     auto salt = saltForOrigin(frame, originHash);
1944     WKRetainPtr<WKStringRef> saltString = adoptWK(WKStringCreateWithUTF8CString(salt.utf8().data()));
1945
1946     WKUserMediaPermissionCheckSetUserMediaAccessInfo(checkRequest, saltString.get(), settingsForOrigin(originHash).persistentPermission());
1947 }
1948
1949 void TestController::handleUserMediaPermissionRequest(WKFrameRef frame, WKSecurityOriginRef userMediaDocumentOrigin, WKSecurityOriginRef topLevelDocumentOrigin, WKUserMediaPermissionRequestRef request)
1950 {
1951     auto originHash = userMediaOriginHash(userMediaDocumentOrigin, topLevelDocumentOrigin);
1952     m_userMediaPermissionRequests.append(std::make_pair(originHash, request));
1953     decidePolicyForUserMediaPermissionRequestIfPossible();
1954 }
1955
1956 OriginSettings& TestController::settingsForOrigin(const String& originHash)
1957 {
1958     RefPtr<OriginSettings> settings = m_cachedUserMediaPermissions.get(originHash);
1959     if (!settings) {
1960         settings = adoptRef(*new OriginSettings());
1961         m_cachedUserMediaPermissions.add(originHash, settings);
1962     }
1963
1964     return *settings;
1965 }
1966
1967 unsigned TestController::userMediaPermissionRequestCountForOrigin(WKStringRef userMediaDocumentOriginString, WKStringRef topLevelDocumentOriginString)
1968 {
1969     auto originHash = userMediaOriginHash(userMediaDocumentOriginString, topLevelDocumentOriginString);
1970     return settingsForOrigin(originHash).requestCount();
1971 }
1972
1973 void TestController::resetUserMediaPermissionRequestCountForOrigin(WKStringRef userMediaDocumentOriginString, WKStringRef topLevelDocumentOriginString)
1974 {
1975     auto originHash = userMediaOriginHash(userMediaDocumentOriginString, topLevelDocumentOriginString);
1976     settingsForOrigin(originHash).resetRequestCount();
1977 }
1978
1979 void TestController::decidePolicyForUserMediaPermissionRequestIfPossible()
1980 {
1981     if (!m_isUserMediaPermissionSet)
1982         return;
1983
1984     for (auto& pair : m_userMediaPermissionRequests) {
1985         auto originHash = pair.first;
1986         auto request = pair.second.get();
1987
1988         auto& settings = settingsForOrigin(originHash);
1989         settings.incrementRequestCount();
1990
1991         if (!m_isUserMediaPermissionAllowed && !settings.persistentPermission()) {
1992             WKUserMediaPermissionRequestDeny(request, kWKPermissionDenied);
1993             continue;
1994         }
1995
1996         WKRetainPtr<WKArrayRef> audioDeviceUIDs = adoptWK(WKUserMediaPermissionRequestAudioDeviceUIDs(request));
1997         WKRetainPtr<WKArrayRef> videoDeviceUIDs = adoptWK(WKUserMediaPermissionRequestVideoDeviceUIDs(request));
1998
1999         if (!WKArrayGetSize(videoDeviceUIDs.get()) && !WKArrayGetSize(audioDeviceUIDs.get())) {
2000             WKUserMediaPermissionRequestDeny(request, kWKNoConstraints);
2001             continue;
2002         }
2003
2004         WKRetainPtr<WKStringRef> videoDeviceUID;
2005         if (WKArrayGetSize(videoDeviceUIDs.get()))
2006             videoDeviceUID = reinterpret_cast<WKStringRef>(WKArrayGetItemAtIndex(videoDeviceUIDs.get(), 0));
2007         else
2008             videoDeviceUID = adoptWK(WKStringCreateWithUTF8CString(""));
2009
2010         WKRetainPtr<WKStringRef> audioDeviceUID;
2011         if (WKArrayGetSize(audioDeviceUIDs.get()))
2012             audioDeviceUID = reinterpret_cast<WKStringRef>(WKArrayGetItemAtIndex(audioDeviceUIDs.get(), 0));
2013         else
2014             audioDeviceUID = adoptWK(WKStringCreateWithUTF8CString(""));
2015
2016         WKUserMediaPermissionRequestAllow(request, audioDeviceUID.get(), videoDeviceUID.get());
2017     }
2018     m_userMediaPermissionRequests.clear();
2019 }
2020
2021 void TestController::setCustomPolicyDelegate(bool enabled, bool permissive)
2022 {
2023     m_policyDelegateEnabled = enabled;
2024     m_policyDelegatePermissive = permissive;
2025 }
2026
2027 void TestController::decidePolicyForGeolocationPermissionRequestIfPossible()
2028 {
2029     if (!m_isGeolocationPermissionSet)
2030         return;
2031
2032     for (size_t i = 0; i < m_geolocationPermissionRequests.size(); ++i) {
2033         WKGeolocationPermissionRequestRef permissionRequest = m_geolocationPermissionRequests[i].get();
2034         if (m_isGeolocationPermissionAllowed)
2035             WKGeolocationPermissionRequestAllow(permissionRequest);
2036         else
2037             WKGeolocationPermissionRequestDeny(permissionRequest);
2038     }
2039     m_geolocationPermissionRequests.clear();
2040 }
2041
2042 void TestController::decidePolicyForNotificationPermissionRequest(WKPageRef page, WKSecurityOriginRef origin, WKNotificationPermissionRequestRef request, const void*)
2043 {
2044     TestController::singleton().decidePolicyForNotificationPermissionRequest(page, origin, request);
2045 }
2046
2047 void TestController::decidePolicyForNotificationPermissionRequest(WKPageRef, WKSecurityOriginRef, WKNotificationPermissionRequestRef request)
2048 {
2049     WKNotificationPermissionRequestAllow(request);
2050 }
2051
2052 void TestController::unavailablePluginButtonClicked(WKPageRef, WKPluginUnavailabilityReason, WKDictionaryRef, const void*)
2053 {
2054     printf("MISSING PLUGIN BUTTON PRESSED\n");
2055 }
2056
2057 void TestController::decidePolicyForNavigationAction(WKPageRef, WKNavigationActionRef navigationAction, WKFramePolicyListenerRef listener, WKTypeRef, const void* clientInfo)
2058 {
2059     static_cast<TestController*>(const_cast<void*>(clientInfo))->decidePolicyForNavigationAction(listener);
2060 }
2061
2062 void TestController::decidePolicyForNavigationAction(WKFramePolicyListenerRef listener)
2063 {
2064     WKRetainPtr<WKFramePolicyListenerRef> retainedListener { listener };
2065     const bool shouldIgnore { m_policyDelegateEnabled && !m_policyDelegatePermissive };
2066     auto decisionFunction = [shouldIgnore, retainedListener]() {
2067         if (shouldIgnore)
2068             WKFramePolicyListenerIgnore(retainedListener.get());
2069         else
2070             WKFramePolicyListenerUse(retainedListener.get());
2071     };
2072
2073     if (m_shouldDecideNavigationPolicyAfterDelay)
2074         RunLoop::main().dispatch(WTFMove(decisionFunction));
2075     else
2076         decisionFunction();
2077 }
2078
2079 void TestController::decidePolicyForNavigationResponse(WKPageRef, WKNavigationResponseRef navigationResponse, WKFramePolicyListenerRef listener, WKTypeRef, const void* clientInfo)
2080 {
2081     static_cast<TestController*>(const_cast<void*>(clientInfo))->decidePolicyForNavigationResponse(navigationResponse, listener);
2082 }
2083
2084 void TestController::decidePolicyForNavigationResponse(WKNavigationResponseRef navigationResponse, WKFramePolicyListenerRef listener)
2085 {
2086     // Even though Response was already checked by WKBundlePagePolicyClient, the check did not include plugins
2087     // so we have to re-check again.
2088     if (WKNavigationResponseCanShowMIMEType(navigationResponse)) {
2089         WKFramePolicyListenerUse(listener);
2090         return;
2091     }
2092
2093     if (m_shouldDownloadUndisplayableMIMETypes)
2094         WKFramePolicyListenerDownload(listener);
2095     else
2096         WKFramePolicyListenerIgnore(listener);
2097 }
2098
2099 void TestController::didNavigateWithNavigationData(WKContextRef, WKPageRef, WKNavigationDataRef navigationData, WKFrameRef frame, const void* clientInfo)
2100 {
2101     static_cast<TestController*>(const_cast<void*>(clientInfo))->didNavigateWithNavigationData(navigationData, frame);
2102 }
2103
2104 void TestController::didNavigateWithNavigationData(WKNavigationDataRef navigationData, WKFrameRef)
2105 {
2106     if (m_state != RunningTest)
2107         return;
2108
2109     if (!m_shouldLogHistoryClientCallbacks)
2110         return;
2111
2112     // URL
2113     WKRetainPtr<WKURLRef> urlWK = adoptWK(WKNavigationDataCopyURL(navigationData));
2114     WKRetainPtr<WKStringRef> urlStringWK = adoptWK(WKURLCopyString(urlWK.get()));
2115     // Title
2116     WKRetainPtr<WKStringRef> titleWK = adoptWK(WKNavigationDataCopyTitle(navigationData));
2117     // HTTP method
2118     WKRetainPtr<WKURLRequestRef> requestWK = adoptWK(WKNavigationDataCopyOriginalRequest(navigationData));
2119     WKRetainPtr<WKStringRef> methodWK = adoptWK(WKURLRequestCopyHTTPMethod(requestWK.get()));
2120
2121     // FIXME: Determine whether the navigation was successful / a client redirect rather than hard-coding the message here.
2122     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",
2123         toSTD(urlStringWK).c_str(), toSTD(titleWK).c_str(), toSTD(methodWK).c_str()));
2124 }
2125
2126 void TestController::didPerformClientRedirect(WKContextRef, WKPageRef, WKURLRef sourceURL, WKURLRef destinationURL, WKFrameRef frame, const void* clientInfo)
2127 {
2128     static_cast<TestController*>(const_cast<void*>(clientInfo))->didPerformClientRedirect(sourceURL, destinationURL, frame);
2129 }
2130
2131 void TestController::didPerformClientRedirect(WKURLRef sourceURL, WKURLRef destinationURL, WKFrameRef)
2132 {
2133     if (m_state != RunningTest)
2134         return;
2135
2136     if (!m_shouldLogHistoryClientCallbacks)
2137         return;
2138
2139     WKRetainPtr<WKStringRef> sourceStringWK = adoptWK(WKURLCopyString(sourceURL));
2140     WKRetainPtr<WKStringRef> destinationStringWK = adoptWK(WKURLCopyString(destinationURL));
2141
2142     m_currentInvocation->outputText(String::format("WebView performed a client redirect from \"%s\" to \"%s\".\n", toSTD(sourceStringWK).c_str(), toSTD(destinationStringWK).c_str()));
2143 }
2144
2145 void TestController::didPerformServerRedirect(WKContextRef, WKPageRef, WKURLRef sourceURL, WKURLRef destinationURL, WKFrameRef frame, const void* clientInfo)
2146 {
2147     static_cast<TestController*>(const_cast<void*>(clientInfo))->didPerformServerRedirect(sourceURL, destinationURL, frame);
2148 }
2149
2150 void TestController::didPerformServerRedirect(WKURLRef sourceURL, WKURLRef destinationURL, WKFrameRef)
2151 {
2152     if (m_state != RunningTest)
2153         return;
2154
2155     if (!m_shouldLogHistoryClientCallbacks)
2156         return;
2157
2158     WKRetainPtr<WKStringRef> sourceStringWK = adoptWK(WKURLCopyString(sourceURL));
2159     WKRetainPtr<WKStringRef> destinationStringWK = adoptWK(WKURLCopyString(destinationURL));
2160
2161     m_currentInvocation->outputText(String::format("WebView performed a server redirect from \"%s\" to \"%s\".\n", toSTD(sourceStringWK).c_str(), toSTD(destinationStringWK).c_str()));
2162 }
2163
2164 void TestController::didUpdateHistoryTitle(WKContextRef, WKPageRef, WKStringRef title, WKURLRef URL, WKFrameRef frame, const void* clientInfo)
2165 {
2166     static_cast<TestController*>(const_cast<void*>(clientInfo))->didUpdateHistoryTitle(title, URL, frame);
2167 }
2168
2169 void TestController::didUpdateHistoryTitle(WKStringRef title, WKURLRef URL, WKFrameRef)
2170 {
2171     if (m_state != RunningTest)
2172         return;
2173
2174     if (!m_shouldLogHistoryClientCallbacks)
2175         return;
2176
2177     WKRetainPtr<WKStringRef> urlStringWK(AdoptWK, WKURLCopyString(URL));
2178     m_currentInvocation->outputText(String::format("WebView updated the title for history URL \"%s\" to \"%s\".\n", toSTD(urlStringWK).c_str(), toSTD(title).c_str()));
2179 }
2180
2181 void TestController::setNavigationGesturesEnabled(bool value)
2182 {
2183     m_mainWebView->setNavigationGesturesEnabled(value);
2184 }
2185
2186 void TestController::setIgnoresViewportScaleLimits(bool ignoresViewportScaleLimits)
2187 {
2188     WKPageSetIgnoresViewportScaleLimits(m_mainWebView->page(), ignoresViewportScaleLimits);
2189 }
2190
2191 void TestController::setStatisticsPrevalentResource(WKStringRef hostName, bool value)
2192 {
2193     WKResourceLoadStatisticsManagerSetPrevalentResource(hostName, value);
2194 }
2195
2196 bool TestController::isStatisticsPrevalentResource(WKStringRef hostName)
2197 {
2198     return WKResourceLoadStatisticsManagerIsPrevalentResource(hostName);
2199 }
2200
2201 void TestController::setStatisticsHasHadUserInteraction(WKStringRef hostName, bool value)
2202 {
2203     WKResourceLoadStatisticsManagerSetHasHadUserInteraction(hostName, value);
2204 }
2205
2206 bool TestController::isStatisticsHasHadUserInteraction(WKStringRef hostName)
2207 {
2208     return WKResourceLoadStatisticsManagerIsHasHadUserInteraction(hostName);
2209 }
2210
2211 void TestController::setStatisticsGrandfathered(WKStringRef hostName, bool value)
2212 {
2213     WKResourceLoadStatisticsManagerSetGrandfathered(hostName, value);
2214 }
2215
2216 bool TestController::isStatisticsGrandfathered(WKStringRef hostName)
2217 {
2218     return WKResourceLoadStatisticsManagerIsGrandfathered(hostName);
2219 }
2220
2221 void TestController::setStatisticsSubframeUnderTopFrameOrigin(WKStringRef hostName, WKStringRef topFrameHostName)
2222 {
2223     WKResourceLoadStatisticsManagerSetSubframeUnderTopFrameOrigin(hostName, topFrameHostName);
2224 }
2225
2226 void TestController::setStatisticsSubresourceUnderTopFrameOrigin(WKStringRef hostName, WKStringRef topFrameHostName)
2227 {
2228     WKResourceLoadStatisticsManagerSetSubresourceUnderTopFrameOrigin(hostName, topFrameHostName);
2229 }
2230     
2231 void TestController::setStatisticsSubresourceUniqueRedirectTo(WKStringRef hostName, WKStringRef hostNameRedirectedTo)
2232 {
2233     WKResourceLoadStatisticsManagerSetSubresourceUniqueRedirectTo(hostName, hostNameRedirectedTo);
2234 }
2235
2236 void TestController::setStatisticsTimeToLiveUserInteraction(double seconds)
2237 {
2238     WKResourceLoadStatisticsManagerSetTimeToLiveUserInteraction(seconds);
2239 }
2240
2241 void TestController::setStatisticsTimeToLiveCookiePartitionFree(double seconds)
2242 {
2243     WKResourceLoadStatisticsManagerSetTimeToLiveCookiePartitionFree(seconds);
2244 }
2245
2246 void TestController::statisticsFireDataModificationHandler()
2247 {
2248     WKResourceLoadStatisticsManagerFireDataModificationHandler();
2249 }
2250     
2251 void TestController::statisticsFireShouldPartitionCookiesHandler()
2252 {
2253     WKResourceLoadStatisticsManagerFireShouldPartitionCookiesHandler();
2254 }
2255
2256 void TestController::statisticsFireShouldPartitionCookiesHandlerForOneDomain(WKStringRef hostName, bool value)
2257 {
2258     WKResourceLoadStatisticsManagerFireShouldPartitionCookiesHandlerForOneDomain(hostName, value);
2259 }
2260
2261 void TestController::setStatisticsNotifyPagesWhenDataRecordsWereScanned(bool value)
2262 {
2263     WKResourceLoadStatisticsManagerSetNotifyPagesWhenDataRecordsWereScanned(value);
2264 }
2265     
2266 void TestController::setStatisticsShouldClassifyResourcesBeforeDataRecordsRemoval(bool value)
2267 {
2268     WKResourceLoadStatisticsManagerSetShouldClassifyResourcesBeforeDataRecordsRemoval(value);
2269 }
2270
2271 void TestController::setStatisticsMinimumTimeBetweeenDataRecordsRemoval(double seconds)
2272 {
2273     WKResourceLoadStatisticsManagerSetMinimumTimeBetweeenDataRecordsRemoval(seconds);
2274 }
2275
2276 void TestController::setStatisticsGrandfatheringTime(double seconds)
2277 {
2278     WKResourceLoadStatisticsManagerSetGrandfatheringTime(seconds);
2279 }
2280
2281 void TestController::statisticsClearInMemoryAndPersistentStore()
2282 {
2283     WKResourceLoadStatisticsManagerClearInMemoryAndPersistentStore();
2284 }
2285
2286 void TestController::statisticsClearInMemoryAndPersistentStoreModifiedSinceHours(unsigned hours)
2287 {
2288     WKResourceLoadStatisticsManagerClearInMemoryAndPersistentStoreModifiedSinceHours(hours);
2289 }
2290     
2291 void TestController::statisticsResetToConsistentState()
2292 {
2293     WKResourceLoadStatisticsManagerResetToConsistentState();
2294 }
2295
2296 void TestController::terminateNetworkProcess()
2297 {
2298     WKContextTerminateNetworkProcess(platformContext());
2299 }
2300
2301 #if !PLATFORM(COCOA)
2302 void TestController::platformWillRunTest(const TestInvocation&)
2303 {
2304 }
2305
2306 void TestController::platformCreateWebView(WKPageConfigurationRef configuration, const TestOptions& options)
2307 {
2308     m_mainWebView = std::make_unique<PlatformWebView>(configuration, options);
2309 }
2310
2311 PlatformWebView* TestController::platformCreateOtherPage(PlatformWebView* parentView, WKPageConfigurationRef configuration, const TestOptions& options)
2312 {
2313     return new PlatformWebView(configuration, options);
2314 }
2315
2316 WKContextRef TestController::platformAdjustContext(WKContextRef context, WKContextConfigurationRef contextConfiguration)
2317 {
2318     return context;
2319 }
2320
2321 void TestController::platformResetStateToConsistentValues()
2322 {
2323
2324 }
2325
2326 unsigned TestController::imageCountInGeneralPasteboard() const
2327 {
2328     return 0;
2329 }
2330
2331 #endif
2332
2333 } // namespace WTR