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