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