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