heap-buffer-overflow on fast/loader/reload-zero-byte-plugin.html
[WebKit-https.git] / Tools / WebKitTestRunner / TestController.cpp
1 /*
2  * Copyright (C) 2010, 2014 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 <WebKit/WKAuthenticationChallenge.h>
35 #include <WebKit/WKAuthenticationDecisionListener.h>
36 #include <WebKit/WKContextConfigurationRef.h>
37 #include <WebKit/WKContextPrivate.h>
38 #include <WebKit/WKCookieManager.h>
39 #include <WebKit/WKCredential.h>
40 #include <WebKit/WKIconDatabase.h>
41 #include <WebKit/WKNotification.h>
42 #include <WebKit/WKNotificationManager.h>
43 #include <WebKit/WKNotificationPermissionRequest.h>
44 #include <WebKit/WKNumber.h>
45 #include <WebKit/WKPageGroup.h>
46 #include <WebKit/WKPagePrivate.h>
47 #include <WebKit/WKPreferencesRefPrivate.h>
48 #include <WebKit/WKProtectionSpace.h>
49 #include <WebKit/WKRetainPtr.h>
50 #include <algorithm>
51 #include <cstdio>
52 #include <ctype.h>
53 #include <stdlib.h>
54 #include <string>
55 #include <wtf/text/CString.h>
56
57 #if PLATFORM(COCOA)
58 #include <WebKit/WKPagePrivateMac.h>
59 #endif
60
61 #if !PLATFORM(COCOA)
62 #include <WebKit/WKTextChecker.h>
63 #endif
64
65 namespace WTR {
66
67 const unsigned TestController::viewWidth = 800;
68 const unsigned TestController::viewHeight = 600;
69
70 const unsigned TestController::w3cSVGViewWidth = 480;
71 const unsigned TestController::w3cSVGViewHeight = 360;
72
73 #if defined(__has_feature)
74 #if __has_feature(address_sanitizer)
75 const double TestController::shortTimeout = 10.0;
76 #else
77 const double TestController::shortTimeout = 5.0;
78 #endif
79 #else
80 const double TestController::shortTimeout = 5.0;
81 #endif
82
83 const double TestController::noTimeout = -1;
84
85 static WKURLRef blankURL()
86 {
87     static WKURLRef staticBlankURL = WKURLCreateWithUTF8CString("about:blank");
88     return staticBlankURL;
89 }
90
91 static WKDataRef copyWebCryptoMasterKey(WKContextRef, const void*)
92 {
93     // Any 128 bit key would do, all we need for testing is to implement the callback.
94     return WKDataCreate((const uint8_t*)"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", 16);
95 }
96
97 static TestController* controller;
98
99 TestController& TestController::shared()
100 {
101     ASSERT(controller);
102     return *controller;
103 }
104
105 TestController::TestController(int argc, const char* argv[])
106     : m_verbose(false)
107     , m_printSeparators(false)
108     , m_usingServerMode(false)
109     , m_gcBetweenTests(false)
110     , m_shouldDumpPixelsForAllTests(false)
111     , m_state(Initial)
112     , m_doneResetting(false)
113     , m_useWaitToDumpWatchdogTimer(true)
114     , m_forceNoTimeout(false)
115     , m_didPrintWebProcessCrashedMessage(false)
116     , m_shouldExitWhenWebProcessCrashes(true)
117     , m_beforeUnloadReturnValue(true)
118     , m_isGeolocationPermissionSet(false)
119     , m_isGeolocationPermissionAllowed(false)
120     , m_policyDelegateEnabled(false)
121     , m_policyDelegatePermissive(false)
122     , m_handlesAuthenticationChallenges(false)
123     , m_shouldBlockAllPlugins(false)
124     , m_forceComplexText(false)
125     , m_shouldUseAcceleratedDrawing(false)
126     , m_shouldUseRemoteLayerTree(false)
127     , m_shouldLogHistoryClientCallbacks(false)
128 {
129     initialize(argc, argv);
130     controller = this;
131     run();
132     controller = 0;
133 }
134
135 TestController::~TestController()
136 {
137     WKIconDatabaseClose(WKContextGetIconDatabase(m_context.get()));
138
139     platformDestroy();
140 }
141
142 static WKRect getWindowFrame(WKPageRef page, const void* clientInfo)
143 {
144     PlatformWebView* view = static_cast<PlatformWebView*>(const_cast<void*>(clientInfo));
145     return view->windowFrame();
146 }
147
148 static void setWindowFrame(WKPageRef page, WKRect frame, const void* clientInfo)
149 {
150     PlatformWebView* view = static_cast<PlatformWebView*>(const_cast<void*>(clientInfo));
151     view->setWindowFrame(frame);
152 }
153
154 static bool runBeforeUnloadConfirmPanel(WKPageRef page, WKStringRef message, WKFrameRef frame, const void*)
155 {
156     printf("CONFIRM NAVIGATION: %s\n", toSTD(message).c_str());
157     return TestController::shared().beforeUnloadReturnValue();
158 }
159
160 void TestController::runModal(WKPageRef page, const void* clientInfo)
161 {
162     PlatformWebView* view = static_cast<PlatformWebView*>(const_cast<void*>(clientInfo));
163     view->setWindowIsKey(false);
164     runModal(view);
165     view->setWindowIsKey(true);
166 }
167
168 static void closeOtherPage(WKPageRef page, const void* clientInfo)
169 {
170     WKPageClose(page);
171     PlatformWebView* view = static_cast<PlatformWebView*>(const_cast<void*>(clientInfo));
172     delete view;
173 }
174
175 static void focus(WKPageRef page, const void* clientInfo)
176 {
177     PlatformWebView* view = static_cast<PlatformWebView*>(const_cast<void*>(clientInfo));
178     view->focus();
179     view->setWindowIsKey(true);
180 }
181
182 static void unfocus(WKPageRef page, const void* clientInfo)
183 {
184     PlatformWebView* view = static_cast<PlatformWebView*>(const_cast<void*>(clientInfo));
185     view->setWindowIsKey(false);
186 }
187
188 static void decidePolicyForGeolocationPermissionRequest(WKPageRef, WKFrameRef, WKSecurityOriginRef, WKGeolocationPermissionRequestRef permissionRequest, const void* clientInfo)
189 {
190     TestController::shared().handleGeolocationPermissionRequest(permissionRequest);
191 }
192
193 static void decidePolicyForUserMediaPermissionRequest(WKPageRef, WKFrameRef, WKSecurityOriginRef, WKUserMediaPermissionRequestRef permissionRequest, const void* clientInfo)
194 {
195     TestController::shared().handleUserMediaPermissionRequest(permissionRequest);
196 }
197
198 WKPageRef TestController::createOtherPage(WKPageRef oldPage, WKURLRequestRef, WKDictionaryRef, WKEventModifiers, WKEventMouseButton, const void* clientInfo)
199 {
200     PlatformWebView* parentView = static_cast<PlatformWebView*>(const_cast<void*>(clientInfo));
201
202     PlatformWebView* view = new PlatformWebView(WKPageGetContext(oldPage), WKPageGetPageGroup(oldPage), oldPage, parentView->options());
203     WKPageRef newPage = view->page();
204
205     view->resizeTo(800, 600);
206
207     WKPageUIClientV5 otherPageUIClient = {
208         { 5, view },
209         0, // createNewPage_deprecatedForUseWithV0
210         0, // showPage
211         closeOtherPage,
212         0, // takeFocus
213         focus,
214         unfocus,
215         0, // runJavaScriptAlert
216         0, // runJavaScriptConfirm
217         0, // runJavaScriptPrompt
218         0, // setStatusText
219         0, // mouseDidMoveOverElement_deprecatedForUseWithV0
220         0, // missingPluginButtonClicked
221         0, // didNotHandleKeyEvent
222         0, // didNotHandleWheelEvent
223         0, // toolbarsAreVisible
224         0, // setToolbarsAreVisible
225         0, // menuBarIsVisible
226         0, // setMenuBarIsVisible
227         0, // statusBarIsVisible
228         0, // setStatusBarIsVisible
229         0, // isResizable
230         0, // setIsResizable
231         getWindowFrame,
232         setWindowFrame,
233         runBeforeUnloadConfirmPanel,
234         0, // didDraw
235         0, // pageDidScroll
236         0, // exceededDatabaseQuota
237         0, // runOpenPanel
238         decidePolicyForGeolocationPermissionRequest,
239         0, // headerHeight
240         0, // footerHeight
241         0, // drawHeader
242         0, // drawFooter
243         0, // printFrame
244         runModal,
245         0, // didCompleteRubberBandForMainFrame
246         0, // saveDataToFileInDownloadsFolder
247         0, // shouldInterruptJavaScript
248         createOtherPage,
249         0, // mouseDidMoveOverElement
250         0, // decidePolicyForNotificationPermissionRequest
251         0, // unavailablePluginButtonClicked_deprecatedForUseWithV1
252         0, // showColorPicker
253         0, // hideColorPicker
254         0, // unavailablePluginButtonClicked
255         0, // pinnedStateDidChange
256         0, // didBeginTrackingPotentialLongMousePress
257         0, // didRecognizeLongMousePress
258         0, // didCancelTrackingPotentialLongMousePress
259         0, // isPlayingAudioDidChange
260         decidePolicyForUserMediaPermissionRequest,
261     };
262     WKPageSetPageUIClient(newPage, &otherPageUIClient.base);
263
264     WKPageLoaderClientV5 pageLoaderClient = {
265         { 5, &TestController::shared() },
266         0, // didStartProvisionalLoadForFrame
267         0, // didReceiveServerRedirectForProvisionalLoadForFrame
268         0, // didFailProvisionalLoadWithErrorForFrame
269         0, // didCommitLoadForFrame,
270         0, // didFinishDocumentLoadForFrame
271         0, // didFinishLoadForFrame,
272         0, // didFailLoadWithErrorForFrame
273         0, // didSameDocumentNavigationForFrame
274         0, // didReceiveTitleForFrame
275         0, // didFirstLayoutForFrame
276         0, // didFirstVisuallyNonEmptyLayoutForFrame
277         0, // didRemoveFrameFromHierarchy
278         0, // didFailToInitializePlugin
279         0, // didDisplayInsecureContentForFrame
280         canAuthenticateAgainstProtectionSpaceInFrame,
281         didReceiveAuthenticationChallengeInFrame,
282         0, // didStartProgress
283         0, // didChangeProgress
284         0, // didFinishProgress
285         0, // didBecomeUnresponsive
286         0, // didBecomeResponsive
287         processDidCrash,
288         0, // didChangeBackForwardList
289         0, // shouldGoToBackForwardListItem
290         0, // didRunInsecureContentForFrame
291         0, // didDetectXSSForFrame
292         0, // didNewFirstVisuallyNonEmptyLayout_unavailable
293         0, // willGoToBackForwardListItem
294         0, // interactionOccurredWhileProcessUnresponsive
295         0, // pluginDidFail_deprecatedForUseWithV1
296         0, // didReceiveIntentForFrame
297         0, // registerIntentServiceForFrame
298         0, // didLayout
299         0, // pluginLoadPolicy_deprecatedForUseWithV2
300         0, // pluginDidFail
301         pluginLoadPolicy, // pluginLoadPolicy
302         0, // webGLLoadPolicy
303         0, // resolveWebGLLoadPolicy
304         0, // shouldKeepCurrentBackForwardListItemInList
305     };
306     WKPageSetPageLoaderClient(view->page(), &pageLoaderClient.base);
307
308     WKPagePolicyClientV1 pagePolicyClient = {
309         { 1, &TestController::shared() },
310         0, // decidePolicyForNavigationAction_deprecatedForUseWithV0
311         0, // decidePolicyForNewWindowAction
312         0, // decidePolicyForResponse_deprecatedForUseWithV0
313         0, // unableToImplementPolicy
314         decidePolicyForNavigationAction,
315         decidePolicyForResponse,
316     };
317     WKPageSetPagePolicyClient(view->page(), &pagePolicyClient.base);
318
319     view->didInitializeClients();
320
321     WKRetain(newPage);
322     return newPage;
323 }
324
325 const char* TestController::libraryPathForTesting()
326 {
327     // FIXME: This may not be sufficient to prevent interactions/crashes
328     // when running more than one copy of DumpRenderTree.
329     // See https://bugs.webkit.org/show_bug.cgi?id=10906
330     char* dumpRenderTreeTemp = getenv("DUMPRENDERTREE_TEMP");
331     if (dumpRenderTreeTemp)
332         return dumpRenderTreeTemp;
333     return platformLibraryPathForTesting();
334 }
335
336
337 void TestController::initialize(int argc, const char* argv[])
338 {
339     platformInitialize();
340
341     Options options;
342     OptionsHandler optionsHandler(options);
343
344     if (argc < 2) {
345         optionsHandler.printHelp();
346         exit(1);
347     }
348     if (!optionsHandler.parse(argc, argv))
349         exit(1);
350
351     m_useWaitToDumpWatchdogTimer = options.useWaitToDumpWatchdogTimer;
352     m_forceNoTimeout = options.forceNoTimeout;
353     m_verbose = options.verbose;
354     m_gcBetweenTests = options.gcBetweenTests;
355     m_shouldDumpPixelsForAllTests = options.shouldDumpPixelsForAllTests;
356     m_forceComplexText = options.forceComplexText;
357     m_shouldUseAcceleratedDrawing = options.shouldUseAcceleratedDrawing;
358     m_shouldUseRemoteLayerTree = options.shouldUseRemoteLayerTree;
359     m_paths = options.paths;
360
361     if (options.printSupportedFeatures) {
362         // FIXME: On Windows, DumpRenderTree uses this to expose whether it supports 3d
363         // transforms and accelerated compositing. When we support those features, we
364         // should match DRT's behavior.
365         exit(0);
366     }
367
368     m_usingServerMode = (m_paths.size() == 1 && m_paths[0] == "-");
369     if (m_usingServerMode)
370         m_printSeparators = true;
371     else
372         m_printSeparators = m_paths.size() > 1;
373
374     initializeInjectedBundlePath();
375     initializeTestPluginDirectory();
376
377     WKRetainPtr<WKStringRef> pageGroupIdentifier(AdoptWK, WKStringCreateWithUTF8CString("WebKitTestRunnerPageGroup"));
378     m_pageGroup.adopt(WKPageGroupCreateWithIdentifier(pageGroupIdentifier.get()));
379
380     auto configuration = adoptWK(WKContextConfigurationCreate());
381     WKContextConfigurationSetInjectedBundlePath(configuration.get(), injectedBundlePath());
382
383     if (const char* dumpRenderTreeTemp = libraryPathForTesting()) {
384         String temporaryFolder = String::fromUTF8(dumpRenderTreeTemp);
385
386         const char separator = '/';
387
388         WKContextConfigurationSetIndexedDBDatabaseDirectory(configuration.get(), toWK(temporaryFolder + separator + "Databases" + separator + "IndexedDB").get());
389         WKContextConfigurationSetLocalStorageDirectory(configuration.get(), toWK(temporaryFolder + separator + "LocalStorage").get());
390         WKContextConfigurationSetWebSQLDatabaseDirectory(configuration.get(), toWK(temporaryFolder + separator + "Databases" + separator + "WebSQL").get());
391     }
392
393     m_context = adoptWK(WKContextCreateWithConfiguration(configuration.get()));
394     m_geolocationProvider = std::make_unique<GeolocationProviderMock>(m_context.get());
395
396 #if PLATFORM(IOS) || (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED > 1080) || PLATFORM(GTK)
397     WKContextSetUsesNetworkProcess(m_context.get(), true);
398     WKContextSetProcessModel(m_context.get(), kWKProcessModelMultipleSecondaryProcesses);
399 #endif
400
401     if (const char* dumpRenderTreeTemp = libraryPathForTesting()) {
402         String temporaryFolder = String::fromUTF8(dumpRenderTreeTemp);
403
404         const char separator = '/';
405
406         // FIXME: These should be migrated to WKContextConfigurationRef.
407         WKContextSetApplicationCacheDirectory(m_context.get(), toWK(temporaryFolder + separator + "ApplicationCache").get());
408         WKContextSetDiskCacheDirectory(m_context.get(), toWK(temporaryFolder + separator + "Cache").get());
409         WKContextSetCookieStorageDirectory(m_context.get(), toWK(temporaryFolder + separator + "Cookies").get());
410         // Disable icon database to avoid fetching <http://127.0.0.1:8000/favicon.ico> and making tests flaky.
411         // Invividual tests can enable it using testRunner.setIconDatabaseEnabled, although it's not currently supported in WebKitTestRunner.
412         WKContextSetIconDatabasePath(m_context.get(), toWK(emptyString()).get());
413     }
414
415     WKContextUseTestingNetworkSession(m_context.get());
416     WKContextSetCacheModel(m_context.get(), kWKCacheModelDocumentBrowser);
417
418     platformInitializeContext();
419
420     WKContextClientV1 contextClient = {
421         { 1, this },
422         nullptr, // plugInAutoStartOriginHashesChanged
423         nullptr, // networkProcessDidCrash,
424         nullptr, // plugInInformationBecameAvailable,
425         copyWebCryptoMasterKey
426     };
427     WKContextSetClient(m_context.get(), &contextClient.base);
428
429     WKContextInjectedBundleClientV1 injectedBundleClient = {
430         { 1, this },
431         didReceiveMessageFromInjectedBundle,
432         didReceiveSynchronousMessageFromInjectedBundle,
433         0 // getInjectedBundleInitializationUserData
434     };
435     WKContextSetInjectedBundleClient(m_context.get(), &injectedBundleClient.base);
436
437     WKContextHistoryClientV0 historyClient = {
438         { 0, this },
439         didNavigateWithNavigationData,
440         didPerformClientRedirect,
441         didPerformServerRedirect,
442         didUpdateHistoryTitle,
443         0, // populateVisitedLinks
444     };
445     WKContextSetHistoryClient(m_context.get(), &historyClient.base);
446
447     WKNotificationManagerRef notificationManager = WKContextGetNotificationManager(m_context.get());
448     WKNotificationProviderV0 notificationKit = m_webNotificationProvider.provider();
449     WKNotificationManagerSetProvider(notificationManager, &notificationKit.base);
450
451     if (testPluginDirectory())
452         WKContextSetAdditionalPluginsDirectory(m_context.get(), testPluginDirectory());
453
454     if (m_forceComplexText)
455         WKContextSetAlwaysUsesComplexTextCodePath(m_context.get(), true);
456
457     // Some preferences (notably mock scroll bars setting) currently cannot be re-applied to an existing view, so we need to set them now.
458     resetPreferencesToConsistentValues();
459
460     WKRetainPtr<WKMutableDictionaryRef> viewOptions;
461     if (m_shouldUseRemoteLayerTree) {
462         viewOptions = adoptWK(WKMutableDictionaryCreate());
463         WKRetainPtr<WKStringRef> useRemoteLayerTreeKey = adoptWK(WKStringCreateWithUTF8CString("RemoteLayerTree"));
464         WKRetainPtr<WKBooleanRef> useRemoteLayerTreeValue = adoptWK(WKBooleanCreate(m_shouldUseRemoteLayerTree));
465         WKDictionarySetItem(viewOptions.get(), useRemoteLayerTreeKey.get(), useRemoteLayerTreeValue.get());
466     }
467
468     createWebViewWithOptions(viewOptions.get());
469 }
470
471 void TestController::createWebViewWithOptions(WKDictionaryRef options)
472 {
473     m_mainWebView = std::make_unique<PlatformWebView>(m_context.get(), m_pageGroup.get(), nullptr, options);
474     WKPageUIClientV5 pageUIClient = {
475         { 5, m_mainWebView.get() },
476         0, // createNewPage_deprecatedForUseWithV0
477         0, // showPage
478         0, // close
479         0, // takeFocus
480         focus,
481         unfocus,
482         0, // runJavaScriptAlert
483         0, // runJavaScriptConfirm
484         0, // runJavaScriptPrompt
485         0, // setStatusText
486         0, // mouseDidMoveOverElement_deprecatedForUseWithV0
487         0, // missingPluginButtonClicked
488         0, // didNotHandleKeyEvent
489         0, // didNotHandleWheelEvent
490         0, // toolbarsAreVisible
491         0, // setToolbarsAreVisible
492         0, // menuBarIsVisible
493         0, // setMenuBarIsVisible
494         0, // statusBarIsVisible
495         0, // setStatusBarIsVisible
496         0, // isResizable
497         0, // setIsResizable
498         getWindowFrame,
499         setWindowFrame,
500         runBeforeUnloadConfirmPanel,
501         0, // didDraw
502         0, // pageDidScroll
503         0, // exceededDatabaseQuota,
504         0, // runOpenPanel
505         decidePolicyForGeolocationPermissionRequest,
506         0, // headerHeight
507         0, // footerHeight
508         0, // drawHeader
509         0, // drawFooter
510         0, // printFrame
511         runModal,
512         0, // didCompleteRubberBandForMainFrame
513         0, // saveDataToFileInDownloadsFolder
514         0, // shouldInterruptJavaScript
515         createOtherPage,
516         0, // mouseDidMoveOverElement
517         decidePolicyForNotificationPermissionRequest, // decidePolicyForNotificationPermissionRequest
518         0, // unavailablePluginButtonClicked_deprecatedForUseWithV1
519         0, // showColorPicker
520         0, // hideColorPicker
521         unavailablePluginButtonClicked,
522         0, // pinnedStateDidChange
523         0, // didBeginTrackingPotentialLongMousePress
524         0, // didRecognizeLongMousePress
525         0, // didCancelTrackingPotentialLongMousePress
526         0, // isPlayingAudioDidChange
527         decidePolicyForUserMediaPermissionRequest,
528     };
529     WKPageSetPageUIClient(m_mainWebView->page(), &pageUIClient.base);
530
531     WKPageLoaderClientV5 pageLoaderClient = {
532         { 5, this },
533         0, // didStartProvisionalLoadForFrame
534         0, // didReceiveServerRedirectForProvisionalLoadForFrame
535         0, // didFailProvisionalLoadWithErrorForFrame
536         didCommitLoadForFrame,
537         0, // didFinishDocumentLoadForFrame
538         didFinishLoadForFrame,
539         0, // didFailLoadWithErrorForFrame
540         0, // didSameDocumentNavigationForFrame
541         0, // didReceiveTitleForFrame
542         0, // didFirstLayoutForFrame
543         0, // didFirstVisuallyNonEmptyLayoutForFrame
544         0, // didRemoveFrameFromHierarchy
545         0, // didFailToInitializePlugin
546         0, // didDisplayInsecureContentForFrame
547         canAuthenticateAgainstProtectionSpaceInFrame,
548         didReceiveAuthenticationChallengeInFrame,
549         0, // didStartProgress
550         0, // didChangeProgress
551         0, // didFinishProgress
552         0, // didBecomeUnresponsive
553         0, // didBecomeResponsive
554         processDidCrash,
555         0, // didChangeBackForwardList
556         0, // shouldGoToBackForwardListItem
557         0, // didRunInsecureContentForFrame
558         0, // didDetectXSSForFrame
559         0, // didNewFirstVisuallyNonEmptyLayout_unavailable
560         0, // willGoToBackForwardListItem
561         0, // interactionOccurredWhileProcessUnresponsive
562         0, // pluginDidFail_deprecatedForUseWithV1
563         0, // didReceiveIntentForFrame
564         0, // registerIntentServiceForFrame
565         0, // didLayout
566         0, // pluginLoadPolicy_deprecatedForUseWithV2
567         0, // pluginDidFail
568         pluginLoadPolicy, // pluginLoadPolicy
569         0, // webGLLoadPolicy
570         0, // resolveWebGLLoadPolicy
571         0, // shouldKeepCurrentBackForwardListItemInList
572     };
573     WKPageSetPageLoaderClient(m_mainWebView->page(), &pageLoaderClient.base);
574
575     WKPagePolicyClientV1 pagePolicyClient = {
576         { 1, this },
577         0, // decidePolicyForNavigationAction_deprecatedForUseWithV0
578         0, // decidePolicyForNewWindowAction
579         0, // decidePolicyForResponse_deprecatedForUseWithV0
580         0, // unableToImplementPolicy
581         decidePolicyForNavigationAction,
582         decidePolicyForResponse,
583     };
584     WKPageSetPagePolicyClient(m_mainWebView->page(), &pagePolicyClient.base);
585
586     m_mainWebView->didInitializeClients();
587
588     // Generally, the tests should default to running at 1x. updateWindowScaleForTest() will adjust the scale to
589     // something else for specific tests that need to run at a different window scale.
590     m_mainWebView->changeWindowScaleIfNeeded(1);
591 }
592
593 void TestController::ensureViewSupportsOptions(WKDictionaryRef options)
594 {
595     if (m_mainWebView && !m_mainWebView->viewSupportsOptions(options)) {
596         WKPageSetPageUIClient(m_mainWebView->page(), 0);
597         WKPageSetPageLoaderClient(m_mainWebView->page(), 0);
598         WKPageSetPagePolicyClient(m_mainWebView->page(), 0);
599         WKPageClose(m_mainWebView->page());
600         
601         m_mainWebView = nullptr;
602
603         createWebViewWithOptions(options);
604         resetStateToConsistentValues();
605     }
606 }
607
608 void TestController::resetPreferencesToConsistentValues()
609 {
610     // Reset preferences
611     WKPreferencesRef preferences = WKPageGroupGetPreferences(m_pageGroup.get());
612     WKPreferencesResetTestRunnerOverrides(preferences);
613     WKPreferencesSetOfflineWebApplicationCacheEnabled(preferences, true);
614     WKPreferencesSetFontSmoothingLevel(preferences, kWKFontSmoothingLevelNoSubpixelAntiAliasing);
615     WKPreferencesSetXSSAuditorEnabled(preferences, false);
616     WKPreferencesSetWebAudioEnabled(preferences, true);
617     WKPreferencesSetMediaStreamEnabled(preferences, true);
618     WKPreferencesSetDeveloperExtrasEnabled(preferences, true);
619     WKPreferencesSetJavaScriptExperimentsEnabled(preferences, true);
620     WKPreferencesSetJavaScriptCanOpenWindowsAutomatically(preferences, true);
621     WKPreferencesSetJavaScriptCanAccessClipboard(preferences, true);
622     WKPreferencesSetDOMPasteAllowed(preferences, true);
623     WKPreferencesSetUniversalAccessFromFileURLsAllowed(preferences, true);
624     WKPreferencesSetFileAccessFromFileURLsAllowed(preferences, true);
625 #if ENABLE(FULLSCREEN_API)
626     WKPreferencesSetFullScreenEnabled(preferences, true);
627 #endif
628     WKPreferencesSetPageCacheEnabled(preferences, false);
629     WKPreferencesSetAsynchronousPluginInitializationEnabled(preferences, false);
630     WKPreferencesSetAsynchronousPluginInitializationEnabledForAllPlugins(preferences, false);
631     WKPreferencesSetArtificialPluginInitializationDelayEnabled(preferences, false);
632     WKPreferencesSetTabToLinksEnabled(preferences, false);
633     WKPreferencesSetInteractiveFormValidationEnabled(preferences, true);
634     WKPreferencesSetMockScrollbarsEnabled(preferences, true);
635
636     static WKStringRef defaultTextEncoding = WKStringCreateWithUTF8CString("ISO-8859-1");
637     WKPreferencesSetDefaultTextEncodingName(preferences, defaultTextEncoding);
638
639     static WKStringRef standardFontFamily = WKStringCreateWithUTF8CString("Times");
640     static WKStringRef cursiveFontFamily = WKStringCreateWithUTF8CString("Apple Chancery");
641     static WKStringRef fantasyFontFamily = WKStringCreateWithUTF8CString("Papyrus");
642     static WKStringRef fixedFontFamily = WKStringCreateWithUTF8CString("Courier");
643     static WKStringRef pictographFontFamily = WKStringCreateWithUTF8CString("Apple Color Emoji");
644     static WKStringRef sansSerifFontFamily = WKStringCreateWithUTF8CString("Helvetica");
645     static WKStringRef serifFontFamily = WKStringCreateWithUTF8CString("Times");
646
647     WKPreferencesSetStandardFontFamily(preferences, standardFontFamily);
648     WKPreferencesSetCursiveFontFamily(preferences, cursiveFontFamily);
649     WKPreferencesSetFantasyFontFamily(preferences, fantasyFontFamily);
650     WKPreferencesSetFixedFontFamily(preferences, fixedFontFamily);
651     WKPreferencesSetPictographFontFamily(preferences, pictographFontFamily);
652     WKPreferencesSetSansSerifFontFamily(preferences, sansSerifFontFamily);
653     WKPreferencesSetSerifFontFamily(preferences, serifFontFamily);
654     WKPreferencesSetAsynchronousSpellCheckingEnabled(preferences, false);
655 #if ENABLE(WEB_AUDIO)
656     WKPreferencesSetMediaSourceEnabled(preferences, true);
657 #endif
658
659     WKPreferencesSetAcceleratedDrawingEnabled(preferences, m_shouldUseAcceleratedDrawing);
660
661     WKCookieManagerDeleteAllCookies(WKContextGetCookieManager(m_context.get()));
662
663     platformResetPreferencesToConsistentValues();
664 }
665
666 bool TestController::resetStateToConsistentValues()
667 {
668     m_state = Resetting;
669
670     m_beforeUnloadReturnValue = true;
671
672     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("Reset"));
673     WKRetainPtr<WKMutableDictionaryRef> resetMessageBody = adoptWK(WKMutableDictionaryCreate());
674
675     WKRetainPtr<WKStringRef> shouldGCKey = adoptWK(WKStringCreateWithUTF8CString("ShouldGC"));
676     WKRetainPtr<WKBooleanRef> shouldGCValue = adoptWK(WKBooleanCreate(m_gcBetweenTests));
677     WKDictionarySetItem(resetMessageBody.get(), shouldGCKey.get(), shouldGCValue.get());
678
679     WKContextPostMessageToInjectedBundle(TestController::shared().context(), messageName.get(), resetMessageBody.get());
680
681     WKContextSetShouldUseFontSmoothing(TestController::shared().context(), false);
682
683     WKContextSetCacheModel(TestController::shared().context(), kWKCacheModelDocumentBrowser);
684
685     // FIXME: This function should also ensure that there is only one page open.
686
687     // Reset the EventSender for each test.
688     m_eventSenderProxy = std::make_unique<EventSenderProxy>(this);
689
690     // FIXME: Is this needed? Nothing in TestController changes preferences during tests, and if there is
691     // some other code doing this, it should probably be responsible for cleanup too.
692     resetPreferencesToConsistentValues();
693
694 #if !PLATFORM(COCOA)
695     WKTextCheckerContinuousSpellCheckingEnabledStateChanged(true);
696 #endif
697
698     // in the case that a test using the chrome input field failed, be sure to clean up for the next test
699     m_mainWebView->removeChromeInputField();
700     m_mainWebView->focus();
701
702     // Re-set to the default backing scale factor by setting the custom scale factor to 0.
703     WKPageSetCustomBackingScaleFactor(m_mainWebView->page(), 0);
704
705 #if PLATFORM(EFL)
706     // EFL use a real window while other ports such as Qt don't.
707     // In EFL, we need to resize the window to the original size after calls to window.resizeTo.
708     WKRect rect = m_mainWebView->windowFrame();
709     m_mainWebView->setWindowFrame(WKRectMake(rect.origin.x, rect.origin.y, TestController::viewWidth, TestController::viewHeight));
710 #endif
711
712     // Reset notification permissions
713     m_webNotificationProvider.reset();
714
715     // Reset Geolocation permissions.
716     m_geolocationPermissionRequests.clear();
717     m_isGeolocationPermissionSet = false;
718     m_isGeolocationPermissionAllowed = false;
719
720     // Reset UserMedia permissions.
721     m_userMediaPermissionRequests.clear();
722     m_isUserMediaPermissionSet = false;
723     m_isUserMediaPermissionAllowed = false;
724
725     // Reset Custom Policy Delegate.
726     setCustomPolicyDelegate(false, false);
727
728     m_workQueueManager.clearWorkQueue();
729
730     m_handlesAuthenticationChallenges = false;
731     m_authenticationUsername = String();
732     m_authenticationPassword = String();
733
734     m_shouldBlockAllPlugins = false;
735
736     m_shouldLogHistoryClientCallbacks = false;
737
738     // Reset main page back to about:blank
739     m_doneResetting = false;
740
741     WKPageLoadURL(m_mainWebView->page(), blankURL());
742     runUntil(m_doneResetting, shortTimeout);
743     return m_doneResetting;
744 }
745
746 void TestController::terminateWebContentProcess()
747 {
748     WKPageTerminate(m_mainWebView->page());
749 }
750
751 void TestController::reattachPageToWebProcess()
752 {
753     // Loading a web page is the only way to reattach an existing page to a process.
754     m_doneResetting = false;
755     WKPageLoadURL(m_mainWebView->page(), blankURL());
756     runUntil(m_doneResetting, shortTimeout);
757 }
758
759 void TestController::updateWebViewSizeForTest(const TestInvocation& test)
760 {
761     bool isSVGW3CTest = strstr(test.pathOrURL(), "svg/W3C-SVG-1.1") || strstr(test.pathOrURL(), "svg\\W3C-SVG-1.1");
762
763     unsigned width = viewWidth;
764     unsigned height = viewHeight;
765     if (isSVGW3CTest) {
766         width = w3cSVGViewWidth;
767         height = w3cSVGViewHeight;
768     }
769
770     mainWebView()->resizeTo(width, height);
771 }
772
773 void TestController::updateWindowScaleForTest(const TestInvocation& test)
774 {
775     WTF::String localPathOrUrl = String(test.pathOrURL());
776     bool needsHighDPIWindow = localPathOrUrl.findIgnoringCase("/hidpi-") != notFound;
777     mainWebView()->changeWindowScaleIfNeeded(needsHighDPIWindow ? 2 : 1);
778 }
779
780 // FIXME: move into relevant platformConfigureViewForTest()?
781 static bool shouldUseFixedLayout(const char* pathOrURL)
782 {
783 #if ENABLE(CSS_DEVICE_ADAPTATION)
784     if (strstr(pathOrURL, "device-adapt/") || strstr(pathOrURL, "device-adapt\\"))
785         return true;
786 #endif
787
788 #if USE(TILED_BACKING_STORE) && PLATFORM(EFL)
789     if (strstr(pathOrURL, "sticky/") || strstr(pathOrURL, "sticky\\"))
790         return true;
791 #endif
792     return false;
793
794     UNUSED_PARAM(pathOrURL);
795 }
796
797 void TestController::updateLayoutTypeForTest(const TestInvocation& test)
798 {
799     auto viewOptions = adoptWK(WKMutableDictionaryCreate());
800     auto useFixedLayoutKey = adoptWK(WKStringCreateWithUTF8CString("UseFixedLayout"));
801     auto useFixedLayoutValue = adoptWK(WKBooleanCreate(shouldUseFixedLayout(test.pathOrURL())));
802     WKDictionarySetItem(viewOptions.get(), useFixedLayoutKey.get(), useFixedLayoutValue.get());
803
804     ensureViewSupportsOptions(viewOptions.get());
805 }
806
807 #if !PLATFORM(COCOA)
808 void TestController::platformConfigureViewForTest(const TestInvocation&)
809 {
810 }
811
812 void TestController::platformResetPreferencesToConsistentValues()
813 {
814 }
815 #endif
816
817 void TestController::configureViewForTest(const TestInvocation& test)
818 {
819     updateWebViewSizeForTest(test);
820     updateWindowScaleForTest(test);
821     updateLayoutTypeForTest(test);
822
823     platformConfigureViewForTest(test);
824 }
825
826 struct TestCommand {
827     TestCommand() : shouldDumpPixels(false), timeout(0) { }
828
829     std::string pathOrURL;
830     bool shouldDumpPixels;
831     std::string expectedPixelHash;
832     int timeout;
833 };
834
835 class CommandTokenizer {
836 public:
837     explicit CommandTokenizer(const std::string& input)
838         : m_input(input)
839         , m_posNextSeparator(0)
840     {
841         pump();
842     }
843
844     bool hasNext() const;
845     std::string next();
846
847 private:
848     void pump();
849     static const char kSeparator = '\'';
850     const std::string& m_input;
851     std::string m_next;
852     size_t m_posNextSeparator;
853 };
854
855 void CommandTokenizer::pump()
856 {
857     if (m_posNextSeparator == std::string::npos || m_posNextSeparator == m_input.size()) {
858         m_next = std::string();
859         return;
860     }
861     size_t start = m_posNextSeparator ? m_posNextSeparator + 1 : 0;
862     m_posNextSeparator = m_input.find(kSeparator, start);
863     size_t size = m_posNextSeparator == std::string::npos ? std::string::npos : m_posNextSeparator - start;
864     m_next = std::string(m_input, start, size);
865 }
866
867 std::string CommandTokenizer::next()
868 {
869     ASSERT(hasNext());
870
871     std::string oldNext = m_next;
872     pump();
873     return oldNext;
874 }
875
876 bool CommandTokenizer::hasNext() const
877 {
878     return !m_next.empty();
879 }
880
881 NO_RETURN static void die(const std::string& inputLine)
882 {
883     fprintf(stderr, "Unexpected input line: %s\n", inputLine.c_str());
884     exit(1);
885 }
886
887 TestCommand parseInputLine(const std::string& inputLine)
888 {
889     TestCommand result;
890     CommandTokenizer tokenizer(inputLine);
891     if (!tokenizer.hasNext())
892         die(inputLine);
893
894     std::string arg = tokenizer.next();
895     result.pathOrURL = arg;
896     while (tokenizer.hasNext()) {
897         arg = tokenizer.next();
898         if (arg == std::string("--timeout")) {
899             std::string timeoutToken = tokenizer.next();
900             result.timeout = atoi(timeoutToken.c_str());
901         } else if (arg == std::string("-p") || arg == std::string("--pixel-test")) {
902             result.shouldDumpPixels = true;
903             if (tokenizer.hasNext())
904                 result.expectedPixelHash = tokenizer.next();
905         } else
906             die(inputLine);
907     }
908     return result;
909 }
910
911 bool TestController::runTest(const char* inputLine)
912 {
913     TestCommand command = parseInputLine(std::string(inputLine));
914
915     m_state = RunningTest;
916
917     m_currentInvocation = std::make_unique<TestInvocation>(command.pathOrURL);
918     if (command.shouldDumpPixels || m_shouldDumpPixelsForAllTests)
919         m_currentInvocation->setIsPixelTest(command.expectedPixelHash);
920     if (command.timeout > 0)
921         m_currentInvocation->setCustomTimeout(command.timeout);
922
923     platformWillRunTest(*m_currentInvocation);
924
925     m_currentInvocation->invoke();
926     m_currentInvocation = nullptr;
927
928     return true;
929 }
930
931 void TestController::runTestingServerLoop()
932 {
933     char filenameBuffer[2048];
934     while (fgets(filenameBuffer, sizeof(filenameBuffer), stdin)) {
935         char* newLineCharacter = strchr(filenameBuffer, '\n');
936         if (newLineCharacter)
937             *newLineCharacter = '\0';
938
939         if (strlen(filenameBuffer) == 0)
940             continue;
941
942         if (!runTest(filenameBuffer))
943             break;
944     }
945 }
946
947 void TestController::run()
948 {
949     if (!resetStateToConsistentValues()) {
950         TestInvocation::dumpWebProcessUnresponsiveness("<unknown> - TestController::run - Failed to reset state to consistent values\n");
951         return;
952     }
953
954     if (m_usingServerMode)
955         runTestingServerLoop();
956     else {
957         for (size_t i = 0; i < m_paths.size(); ++i) {
958             if (!runTest(m_paths[i].c_str()))
959                 break;
960         }
961     }
962 }
963
964 void TestController::runUntil(bool& done, double timeout)
965 {
966     if (m_forceNoTimeout)
967         timeout = noTimeout;
968
969     platformRunUntil(done, timeout);
970 }
971
972 // WKContextInjectedBundleClient
973
974 void TestController::didReceiveMessageFromInjectedBundle(WKContextRef context, WKStringRef messageName, WKTypeRef messageBody, const void* clientInfo)
975 {
976     static_cast<TestController*>(const_cast<void*>(clientInfo))->didReceiveMessageFromInjectedBundle(messageName, messageBody);
977 }
978
979 void TestController::didReceiveSynchronousMessageFromInjectedBundle(WKContextRef context, WKStringRef messageName, WKTypeRef messageBody, WKTypeRef* returnData, const void* clientInfo)
980 {
981     *returnData = static_cast<TestController*>(const_cast<void*>(clientInfo))->didReceiveSynchronousMessageFromInjectedBundle(messageName, messageBody).leakRef();
982 }
983
984 void TestController::didReceiveKeyDownMessageFromInjectedBundle(WKDictionaryRef messageBodyDictionary, bool synchronous)
985 {
986     WKRetainPtr<WKStringRef> keyKey = adoptWK(WKStringCreateWithUTF8CString("Key"));
987     WKStringRef key = static_cast<WKStringRef>(WKDictionaryGetItemForKey(messageBodyDictionary, keyKey.get()));
988
989     WKRetainPtr<WKStringRef> modifiersKey = adoptWK(WKStringCreateWithUTF8CString("Modifiers"));
990     WKEventModifiers modifiers = static_cast<WKEventModifiers>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, modifiersKey.get()))));
991
992     WKRetainPtr<WKStringRef> locationKey = adoptWK(WKStringCreateWithUTF8CString("Location"));
993     unsigned location = static_cast<unsigned>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, locationKey.get()))));
994
995     if (synchronous)
996         WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), true);
997
998     m_eventSenderProxy->keyDown(key, modifiers, location);
999
1000     if (synchronous)
1001         WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false);
1002 }
1003
1004 void TestController::didReceiveMessageFromInjectedBundle(WKStringRef messageName, WKTypeRef messageBody)
1005 {
1006     if (WKStringIsEqualToUTF8CString(messageName, "EventSender")) {
1007         ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID());
1008         WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody);
1009
1010         WKRetainPtr<WKStringRef> subMessageKey(AdoptWK, WKStringCreateWithUTF8CString("SubMessage"));
1011         WKStringRef subMessageName = static_cast<WKStringRef>(WKDictionaryGetItemForKey(messageBodyDictionary, subMessageKey.get()));
1012
1013         if (WKStringIsEqualToUTF8CString(subMessageName, "MouseDown") || WKStringIsEqualToUTF8CString(subMessageName, "MouseUp")) {
1014             WKRetainPtr<WKStringRef> buttonKey = adoptWK(WKStringCreateWithUTF8CString("Button"));
1015             unsigned button = static_cast<unsigned>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, buttonKey.get()))));
1016
1017             WKRetainPtr<WKStringRef> modifiersKey = adoptWK(WKStringCreateWithUTF8CString("Modifiers"));
1018             WKEventModifiers modifiers = static_cast<WKEventModifiers>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, modifiersKey.get()))));
1019
1020             // Forward to WebProcess
1021             WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false);
1022             if (WKStringIsEqualToUTF8CString(subMessageName, "MouseDown"))
1023                 m_eventSenderProxy->mouseDown(button, modifiers);
1024             else
1025                 m_eventSenderProxy->mouseUp(button, modifiers);
1026
1027             return;
1028         }
1029
1030         if (WKStringIsEqualToUTF8CString(subMessageName, "KeyDown")) {
1031             didReceiveKeyDownMessageFromInjectedBundle(messageBodyDictionary, false);
1032
1033             return;
1034         }
1035
1036         if (WKStringIsEqualToUTF8CString(subMessageName, "MouseScrollByWithWheelAndMomentumPhases")) {
1037             WKRetainPtr<WKStringRef> xKey = adoptWK(WKStringCreateWithUTF8CString("X"));
1038             double x = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, xKey.get())));
1039             
1040             WKRetainPtr<WKStringRef> yKey = adoptWK(WKStringCreateWithUTF8CString("Y"));
1041             double y = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, yKey.get())));
1042             
1043             WKRetainPtr<WKStringRef> phaseKey = adoptWK(WKStringCreateWithUTF8CString("Phase"));
1044             int phase = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, phaseKey.get()))));
1045             WKRetainPtr<WKStringRef> momentumKey = adoptWK(WKStringCreateWithUTF8CString("Momentum"));
1046             int momentum = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, momentumKey.get()))));
1047             
1048             // Forward to WebProcess
1049             WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false);
1050             m_eventSenderProxy->mouseScrollByWithWheelAndMomentumPhases(x, y, phase, momentum);
1051
1052             return;
1053         }
1054
1055         ASSERT_NOT_REACHED();
1056     }
1057
1058     if (!m_currentInvocation)
1059         return;
1060
1061     m_currentInvocation->didReceiveMessageFromInjectedBundle(messageName, messageBody);
1062 }
1063
1064 WKRetainPtr<WKTypeRef> TestController::didReceiveSynchronousMessageFromInjectedBundle(WKStringRef messageName, WKTypeRef messageBody)
1065 {
1066     if (WKStringIsEqualToUTF8CString(messageName, "EventSender")) {
1067         ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID());
1068         WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody);
1069
1070         WKRetainPtr<WKStringRef> subMessageKey(AdoptWK, WKStringCreateWithUTF8CString("SubMessage"));
1071         WKStringRef subMessageName = static_cast<WKStringRef>(WKDictionaryGetItemForKey(messageBodyDictionary, subMessageKey.get()));
1072
1073         if (WKStringIsEqualToUTF8CString(subMessageName, "KeyDown")) {
1074             didReceiveKeyDownMessageFromInjectedBundle(messageBodyDictionary, true);
1075
1076             return 0;
1077         }
1078
1079         if (WKStringIsEqualToUTF8CString(subMessageName, "MouseDown") || WKStringIsEqualToUTF8CString(subMessageName, "MouseUp")) {
1080             WKRetainPtr<WKStringRef> buttonKey = adoptWK(WKStringCreateWithUTF8CString("Button"));
1081             unsigned button = static_cast<unsigned>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, buttonKey.get()))));
1082
1083             WKRetainPtr<WKStringRef> modifiersKey = adoptWK(WKStringCreateWithUTF8CString("Modifiers"));
1084             WKEventModifiers modifiers = static_cast<WKEventModifiers>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, modifiersKey.get()))));
1085
1086             // Forward to WebProcess
1087             WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), true);
1088             if (WKStringIsEqualToUTF8CString(subMessageName, "MouseDown"))
1089                 m_eventSenderProxy->mouseDown(button, modifiers);
1090             else
1091                 m_eventSenderProxy->mouseUp(button, modifiers);
1092             WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false);
1093             return 0;
1094         }
1095
1096         if (WKStringIsEqualToUTF8CString(subMessageName, "MouseMoveTo")) {
1097             WKRetainPtr<WKStringRef> xKey = adoptWK(WKStringCreateWithUTF8CString("X"));
1098             double x = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, xKey.get())));
1099
1100             WKRetainPtr<WKStringRef> yKey = adoptWK(WKStringCreateWithUTF8CString("Y"));
1101             double y = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, yKey.get())));
1102
1103             // Forward to WebProcess
1104             WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), true);
1105             m_eventSenderProxy->mouseMoveTo(x, y);
1106             WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false);
1107             return 0;
1108         }
1109
1110         if (WKStringIsEqualToUTF8CString(subMessageName, "MouseScrollBy")) {
1111             WKRetainPtr<WKStringRef> xKey = adoptWK(WKStringCreateWithUTF8CString("X"));
1112             double x = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, xKey.get())));
1113
1114             WKRetainPtr<WKStringRef> yKey = adoptWK(WKStringCreateWithUTF8CString("Y"));
1115             double y = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, yKey.get())));
1116
1117             // Forward to WebProcess
1118             WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), true);
1119             m_eventSenderProxy->mouseScrollBy(x, y);
1120             WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false);
1121             return 0;
1122         }
1123
1124         if (WKStringIsEqualToUTF8CString(subMessageName, "MouseScrollByWithWheelAndMomentumPhases")) {
1125             WKRetainPtr<WKStringRef> xKey = adoptWK(WKStringCreateWithUTF8CString("X"));
1126             double x = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, xKey.get())));
1127             
1128             WKRetainPtr<WKStringRef> yKey = adoptWK(WKStringCreateWithUTF8CString("Y"));
1129             double y = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, yKey.get())));
1130             
1131             WKRetainPtr<WKStringRef> phaseKey = adoptWK(WKStringCreateWithUTF8CString("Phase"));
1132             int phase = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, phaseKey.get()))));
1133             WKRetainPtr<WKStringRef> momentumKey = adoptWK(WKStringCreateWithUTF8CString("Momentum"));
1134             int momentum = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, momentumKey.get()))));
1135
1136             // Forward to WebProcess
1137             WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), true);
1138             m_eventSenderProxy->mouseScrollByWithWheelAndMomentumPhases(x, y, phase, momentum);
1139             WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false);
1140             return 0;
1141         }
1142         
1143         if (WKStringIsEqualToUTF8CString(subMessageName, "ContinuousMouseScrollBy")) {
1144             WKRetainPtr<WKStringRef> xKey = adoptWK(WKStringCreateWithUTF8CString("X"));
1145             double x = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, xKey.get())));
1146
1147             WKRetainPtr<WKStringRef> yKey = adoptWK(WKStringCreateWithUTF8CString("Y"));
1148             double y = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, yKey.get())));
1149
1150             WKRetainPtr<WKStringRef> pagedKey = adoptWK(WKStringCreateWithUTF8CString("Paged"));
1151             bool paged = static_cast<bool>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, pagedKey.get()))));
1152
1153             // Forward to WebProcess
1154             WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), true);
1155             m_eventSenderProxy->continuousMouseScrollBy(x, y, paged);
1156             WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false);
1157             return 0;
1158         }
1159
1160         if (WKStringIsEqualToUTF8CString(subMessageName, "LeapForward")) {
1161             WKRetainPtr<WKStringRef> timeKey = adoptWK(WKStringCreateWithUTF8CString("TimeInMilliseconds"));
1162             unsigned time = static_cast<unsigned>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, timeKey.get()))));
1163
1164             m_eventSenderProxy->leapForward(time);
1165             return 0;
1166         }
1167
1168 #if ENABLE(TOUCH_EVENTS)
1169         if (WKStringIsEqualToUTF8CString(subMessageName, "AddTouchPoint")) {
1170             WKRetainPtr<WKStringRef> xKey = adoptWK(WKStringCreateWithUTF8CString("X"));
1171             int x = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, xKey.get()))));
1172
1173             WKRetainPtr<WKStringRef> yKey = adoptWK(WKStringCreateWithUTF8CString("Y"));
1174             int y = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, yKey.get()))));
1175
1176             m_eventSenderProxy->addTouchPoint(x, y);
1177             return 0;
1178         }
1179
1180         if (WKStringIsEqualToUTF8CString(subMessageName, "UpdateTouchPoint")) {
1181             WKRetainPtr<WKStringRef> indexKey = adoptWK(WKStringCreateWithUTF8CString("Index"));
1182             int index = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, indexKey.get()))));
1183
1184             WKRetainPtr<WKStringRef> xKey = adoptWK(WKStringCreateWithUTF8CString("X"));
1185             int x = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, xKey.get()))));
1186
1187             WKRetainPtr<WKStringRef> yKey = adoptWK(WKStringCreateWithUTF8CString("Y"));
1188             int y = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, yKey.get()))));
1189
1190             m_eventSenderProxy->updateTouchPoint(index, x, y);
1191             return 0;
1192         }
1193
1194         if (WKStringIsEqualToUTF8CString(subMessageName, "SetTouchModifier")) {
1195             WKRetainPtr<WKStringRef> modifierKey = adoptWK(WKStringCreateWithUTF8CString("Modifier"));
1196             WKEventModifiers modifier = static_cast<WKEventModifiers>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, modifierKey.get()))));
1197
1198             WKRetainPtr<WKStringRef> enableKey = adoptWK(WKStringCreateWithUTF8CString("Enable"));
1199             bool enable = static_cast<bool>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, enableKey.get()))));
1200
1201             m_eventSenderProxy->setTouchModifier(modifier, enable);
1202             return 0;
1203         }
1204
1205         if (WKStringIsEqualToUTF8CString(subMessageName, "SetTouchPointRadius")) {
1206             WKRetainPtr<WKStringRef> xKey = adoptWK(WKStringCreateWithUTF8CString("RadiusX"));
1207             int x = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, xKey.get()))));
1208
1209             WKRetainPtr<WKStringRef> yKey = adoptWK(WKStringCreateWithUTF8CString("RadiusY"));
1210             int y = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, yKey.get()))));
1211
1212             m_eventSenderProxy->setTouchPointRadius(x, y);
1213             return 0;
1214         }
1215
1216         if (WKStringIsEqualToUTF8CString(subMessageName, "TouchStart")) {
1217             WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), true);
1218             m_eventSenderProxy->touchStart();
1219             WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false);
1220             return 0;
1221         }
1222
1223         if (WKStringIsEqualToUTF8CString(subMessageName, "TouchMove")) {
1224             WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), true);
1225             m_eventSenderProxy->touchMove();
1226             WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false);
1227             return 0;
1228         }
1229
1230         if (WKStringIsEqualToUTF8CString(subMessageName, "TouchEnd")) {
1231             WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), true);
1232             m_eventSenderProxy->touchEnd();
1233             WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false);
1234             return 0;
1235         }
1236
1237         if (WKStringIsEqualToUTF8CString(subMessageName, "TouchCancel")) {
1238             WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), true);
1239             m_eventSenderProxy->touchCancel();
1240             WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false);
1241             return 0;
1242         }
1243
1244         if (WKStringIsEqualToUTF8CString(subMessageName, "ClearTouchPoints")) {
1245             m_eventSenderProxy->clearTouchPoints();
1246             return 0;
1247         }
1248
1249         if (WKStringIsEqualToUTF8CString(subMessageName, "ReleaseTouchPoint")) {
1250             WKRetainPtr<WKStringRef> indexKey = adoptWK(WKStringCreateWithUTF8CString("Index"));
1251             int index = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, indexKey.get()))));
1252             m_eventSenderProxy->releaseTouchPoint(index);
1253             return 0;
1254         }
1255
1256         if (WKStringIsEqualToUTF8CString(subMessageName, "CancelTouchPoint")) {
1257             WKRetainPtr<WKStringRef> indexKey = adoptWK(WKStringCreateWithUTF8CString("Index"));
1258             int index = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, indexKey.get()))));
1259             m_eventSenderProxy->cancelTouchPoint(index);
1260             return 0;
1261         }
1262 #endif
1263         ASSERT_NOT_REACHED();
1264     }
1265     return m_currentInvocation->didReceiveSynchronousMessageFromInjectedBundle(messageName, messageBody);
1266 }
1267
1268 // WKPageLoaderClient
1269
1270 void TestController::didCommitLoadForFrame(WKPageRef page, WKFrameRef frame, WKTypeRef, const void* clientInfo)
1271 {
1272     static_cast<TestController*>(const_cast<void*>(clientInfo))->didCommitLoadForFrame(page, frame);
1273 }
1274
1275 void TestController::didFinishLoadForFrame(WKPageRef page, WKFrameRef frame, WKTypeRef, const void* clientInfo)
1276 {
1277     static_cast<TestController*>(const_cast<void*>(clientInfo))->didFinishLoadForFrame(page, frame);
1278 }
1279
1280 bool TestController::canAuthenticateAgainstProtectionSpaceInFrame(WKPageRef, WKFrameRef, WKProtectionSpaceRef protectionSpace, const void*)
1281 {
1282     WKProtectionSpaceAuthenticationScheme authenticationScheme = WKProtectionSpaceGetAuthenticationScheme(protectionSpace);
1283
1284     if (authenticationScheme == kWKProtectionSpaceAuthenticationSchemeServerTrustEvaluationRequested) {
1285         std::string host = toSTD(adoptWK(WKProtectionSpaceCopyHost(protectionSpace)).get());
1286         return host == "localhost" || host == "127.0.0.1";
1287     }
1288
1289     return authenticationScheme <= kWKProtectionSpaceAuthenticationSchemeHTTPDigest;
1290 }
1291
1292 void TestController::didReceiveAuthenticationChallengeInFrame(WKPageRef page, WKFrameRef frame, WKAuthenticationChallengeRef authenticationChallenge, const void *clientInfo)
1293 {
1294     static_cast<TestController*>(const_cast<void*>(clientInfo))->didReceiveAuthenticationChallengeInFrame(page, frame, authenticationChallenge);
1295 }
1296
1297 void TestController::processDidCrash(WKPageRef page, const void* clientInfo)
1298 {
1299     static_cast<TestController*>(const_cast<void*>(clientInfo))->processDidCrash();
1300 }
1301
1302 WKPluginLoadPolicy TestController::pluginLoadPolicy(WKPageRef page, WKPluginLoadPolicy currentPluginLoadPolicy, WKDictionaryRef pluginInformation, WKStringRef* unavailabilityDescription, const void* clientInfo)
1303 {
1304     return static_cast<TestController*>(const_cast<void*>(clientInfo))->pluginLoadPolicy(page, currentPluginLoadPolicy, pluginInformation, unavailabilityDescription);
1305 }
1306
1307 WKPluginLoadPolicy TestController::pluginLoadPolicy(WKPageRef, WKPluginLoadPolicy currentPluginLoadPolicy, WKDictionaryRef pluginInformation, WKStringRef* unavailabilityDescription)
1308 {
1309     if (m_shouldBlockAllPlugins)
1310         return kWKPluginLoadPolicyBlocked;
1311     return currentPluginLoadPolicy;
1312 }
1313
1314 void TestController::didCommitLoadForFrame(WKPageRef page, WKFrameRef frame)
1315 {
1316     if (!WKFrameIsMainFrame(frame))
1317         return;
1318
1319     mainWebView()->focus();
1320 }
1321
1322 void TestController::didFinishLoadForFrame(WKPageRef page, WKFrameRef frame)
1323 {
1324     if (m_state != Resetting)
1325         return;
1326
1327     if (!WKFrameIsMainFrame(frame))
1328         return;
1329
1330     WKRetainPtr<WKURLRef> wkURL(AdoptWK, WKFrameCopyURL(frame));
1331     if (!WKURLIsEqual(wkURL.get(), blankURL()))
1332         return;
1333
1334     m_doneResetting = true;
1335     shared().notifyDone();
1336 }
1337
1338 void TestController::didReceiveAuthenticationChallengeInFrame(WKPageRef page, WKFrameRef frame, WKAuthenticationChallengeRef authenticationChallenge)
1339 {
1340     WKProtectionSpaceRef protectionSpace = WKAuthenticationChallengeGetProtectionSpace(authenticationChallenge);
1341     WKAuthenticationDecisionListenerRef decisionListener = WKAuthenticationChallengeGetDecisionListener(authenticationChallenge);
1342
1343     if (WKProtectionSpaceGetAuthenticationScheme(protectionSpace) == kWKProtectionSpaceAuthenticationSchemeServerTrustEvaluationRequested) {
1344         // Any non-empty credential signals to accept the server trust. Since the cross-platform API
1345         // doesn't expose a way to create a credential from server trust, we use a password credential.
1346
1347         WKRetainPtr<WKCredentialRef> credential = adoptWK(WKCredentialCreate(toWK("accept server trust").get(), toWK("").get(), kWKCredentialPersistenceNone));
1348         WKAuthenticationDecisionListenerUseCredential(decisionListener, credential.get());
1349         return;
1350     }
1351
1352     std::string host = toSTD(adoptWK(WKProtectionSpaceCopyHost(protectionSpace)).get());
1353     int port = WKProtectionSpaceGetPort(protectionSpace);
1354     String message = String::format("%s:%d - didReceiveAuthenticationChallenge - ", host.c_str(), port);
1355     if (!m_handlesAuthenticationChallenges)
1356         message.append("Simulating cancelled authentication sheet\n");
1357     else
1358         message.append(String::format("Responding with %s:%s\n", m_authenticationUsername.utf8().data(), m_authenticationPassword.utf8().data()));
1359     m_currentInvocation->outputText(message);
1360
1361     if (!m_handlesAuthenticationChallenges) {
1362         WKAuthenticationDecisionListenerUseCredential(decisionListener, 0);
1363         return;
1364     }
1365     WKRetainPtr<WKStringRef> username(AdoptWK, WKStringCreateWithUTF8CString(m_authenticationUsername.utf8().data()));
1366     WKRetainPtr<WKStringRef> password(AdoptWK, WKStringCreateWithUTF8CString(m_authenticationPassword.utf8().data()));
1367     WKRetainPtr<WKCredentialRef> credential(AdoptWK, WKCredentialCreate(username.get(), password.get(), kWKCredentialPersistenceForSession));
1368     WKAuthenticationDecisionListenerUseCredential(decisionListener, credential.get());
1369 }
1370
1371 void TestController::processDidCrash()
1372 {
1373     // This function can be called multiple times when crash logs are being saved on Windows, so
1374     // ensure we only print the crashed message once.
1375     if (!m_didPrintWebProcessCrashedMessage) {
1376 #if PLATFORM(COCOA)
1377         pid_t pid = WKPageGetProcessIdentifier(m_mainWebView->page());
1378         // FIXME: Find a way to not hardcode the process name.
1379 #if PLATFORM(IOS)
1380         const char* processName = "com.apple.WebKit.WebContent";
1381 #elif PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED > 1080
1382         const char* processName = "com.apple.WebKit.WebContent.Development";
1383 #else
1384         const char* processName = "WebProcess";
1385 #endif
1386         fprintf(stderr, "#CRASHED - %s (pid %ld)\n", processName, static_cast<long>(pid));
1387 #else
1388         fputs("#CRASHED - WebProcess\n", stderr);
1389 #endif
1390         fflush(stderr);
1391         m_didPrintWebProcessCrashedMessage = true;
1392     }
1393
1394     if (m_shouldExitWhenWebProcessCrashes)
1395         exit(1);
1396 }
1397
1398 void TestController::simulateWebNotificationClick(uint64_t notificationID)
1399 {
1400     m_webNotificationProvider.simulateWebNotificationClick(notificationID);
1401 }
1402
1403 void TestController::setGeolocationPermission(bool enabled)
1404 {
1405     m_isGeolocationPermissionSet = true;
1406     m_isGeolocationPermissionAllowed = enabled;
1407     decidePolicyForGeolocationPermissionRequestIfPossible();
1408 }
1409
1410 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)
1411 {
1412     m_geolocationProvider->setPosition(latitude, longitude, accuracy, providesAltitude, altitude, providesAltitudeAccuracy, altitudeAccuracy, providesHeading, heading, providesSpeed, speed);
1413 }
1414
1415 void TestController::setMockGeolocationPositionUnavailableError(WKStringRef errorMessage)
1416 {
1417     m_geolocationProvider->setPositionUnavailableError(errorMessage);
1418 }
1419
1420 void TestController::handleGeolocationPermissionRequest(WKGeolocationPermissionRequestRef geolocationPermissionRequest)
1421 {
1422     m_geolocationPermissionRequests.append(geolocationPermissionRequest);
1423     decidePolicyForGeolocationPermissionRequestIfPossible();
1424 }
1425
1426 void TestController::setUserMediaPermission(bool enabled)
1427 {
1428     m_isUserMediaPermissionSet = true;
1429     m_isUserMediaPermissionAllowed = enabled;
1430     decidePolicyForUserMediaPermissionRequestIfPossible();
1431 }
1432
1433 void TestController::handleUserMediaPermissionRequest(WKUserMediaPermissionRequestRef userMediaPermissionRequest)
1434 {
1435     m_userMediaPermissionRequests.append(userMediaPermissionRequest);
1436     decidePolicyForUserMediaPermissionRequestIfPossible();
1437 }
1438
1439 void TestController::decidePolicyForUserMediaPermissionRequestIfPossible()
1440 {
1441     if (!m_isUserMediaPermissionSet)
1442         return;
1443
1444     for (auto& request : m_userMediaPermissionRequests) {
1445         if (m_isUserMediaPermissionAllowed)
1446             WKUserMediaPermissionRequestAllow(request.get());
1447         else
1448             WKUserMediaPermissionRequestDeny(request.get());
1449     }
1450     m_userMediaPermissionRequests.clear();
1451 }
1452
1453 void TestController::setCustomPolicyDelegate(bool enabled, bool permissive)
1454 {
1455     m_policyDelegateEnabled = enabled;
1456     m_policyDelegatePermissive = permissive;
1457 }
1458
1459 void TestController::decidePolicyForGeolocationPermissionRequestIfPossible()
1460 {
1461     if (!m_isGeolocationPermissionSet)
1462         return;
1463
1464     for (size_t i = 0; i < m_geolocationPermissionRequests.size(); ++i) {
1465         WKGeolocationPermissionRequestRef permissionRequest = m_geolocationPermissionRequests[i].get();
1466         if (m_isGeolocationPermissionAllowed)
1467             WKGeolocationPermissionRequestAllow(permissionRequest);
1468         else
1469             WKGeolocationPermissionRequestDeny(permissionRequest);
1470     }
1471     m_geolocationPermissionRequests.clear();
1472 }
1473
1474 void TestController::decidePolicyForNotificationPermissionRequest(WKPageRef page, WKSecurityOriginRef origin, WKNotificationPermissionRequestRef request, const void*)
1475 {
1476     TestController::shared().decidePolicyForNotificationPermissionRequest(page, origin, request);
1477 }
1478
1479 void TestController::decidePolicyForNotificationPermissionRequest(WKPageRef, WKSecurityOriginRef, WKNotificationPermissionRequestRef request)
1480 {
1481     WKNotificationPermissionRequestAllow(request);
1482 }
1483
1484 void TestController::unavailablePluginButtonClicked(WKPageRef, WKPluginUnavailabilityReason, WKDictionaryRef, const void*)
1485 {
1486     printf("MISSING PLUGIN BUTTON PRESSED\n");
1487 }
1488
1489 void TestController::decidePolicyForNavigationAction(WKPageRef, WKFrameRef, WKFrameNavigationType, WKEventModifiers, WKEventMouseButton, WKFrameRef, WKURLRequestRef, WKFramePolicyListenerRef listener, WKTypeRef, const void* clientInfo)
1490 {
1491     static_cast<TestController*>(const_cast<void*>(clientInfo))->decidePolicyForNavigationAction(listener);
1492 }
1493
1494 void TestController::decidePolicyForNavigationAction(WKFramePolicyListenerRef listener)
1495 {
1496     if (m_policyDelegateEnabled && !m_policyDelegatePermissive) {
1497         WKFramePolicyListenerIgnore(listener);
1498         return;
1499     }
1500
1501     WKFramePolicyListenerUse(listener);
1502 }
1503
1504 void TestController::decidePolicyForResponse(WKPageRef, WKFrameRef frame, WKURLResponseRef response, WKURLRequestRef, bool canShowMIMEType, WKFramePolicyListenerRef listener, WKTypeRef, const void* clientInfo)
1505 {
1506     static_cast<TestController*>(const_cast<void*>(clientInfo))->decidePolicyForResponse(frame, response, listener);
1507 }
1508
1509 void TestController::decidePolicyForResponse(WKFrameRef frame, WKURLResponseRef response, WKFramePolicyListenerRef listener)
1510 {
1511     // Even though Response was already checked by WKBundlePagePolicyClient, the check did not include plugins
1512     // so we have to re-check again.
1513     WKRetainPtr<WKStringRef> wkMIMEType(AdoptWK, WKURLResponseCopyMIMEType(response));
1514     if (WKFrameCanShowMIMEType(frame, wkMIMEType.get())) {
1515         WKFramePolicyListenerUse(listener);
1516         return;
1517     }
1518
1519     WKFramePolicyListenerIgnore(listener);
1520 }
1521
1522 void TestController::didNavigateWithNavigationData(WKContextRef, WKPageRef, WKNavigationDataRef navigationData, WKFrameRef frame, const void* clientInfo)
1523 {
1524     static_cast<TestController*>(const_cast<void*>(clientInfo))->didNavigateWithNavigationData(navigationData, frame);
1525 }
1526
1527 void TestController::didNavigateWithNavigationData(WKNavigationDataRef navigationData, WKFrameRef)
1528 {
1529     if (m_state != RunningTest)
1530         return;
1531
1532     if (!m_shouldLogHistoryClientCallbacks)
1533         return;
1534
1535     // URL
1536     WKRetainPtr<WKURLRef> urlWK = adoptWK(WKNavigationDataCopyURL(navigationData));
1537     WKRetainPtr<WKStringRef> urlStringWK = adoptWK(WKURLCopyString(urlWK.get()));
1538     // Title
1539     WKRetainPtr<WKStringRef> titleWK = adoptWK(WKNavigationDataCopyTitle(navigationData));
1540     // HTTP method
1541     WKRetainPtr<WKURLRequestRef> requestWK = adoptWK(WKNavigationDataCopyOriginalRequest(navigationData));
1542     WKRetainPtr<WKStringRef> methodWK = adoptWK(WKURLRequestCopyHTTPMethod(requestWK.get()));
1543
1544     // FIXME: Determine whether the navigation was successful / a client redirect rather than hard-coding the message here.
1545     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",
1546         toSTD(urlStringWK).c_str(), toSTD(titleWK).c_str(), toSTD(methodWK).c_str()));
1547 }
1548
1549 void TestController::didPerformClientRedirect(WKContextRef, WKPageRef, WKURLRef sourceURL, WKURLRef destinationURL, WKFrameRef frame, const void* clientInfo)
1550 {
1551     static_cast<TestController*>(const_cast<void*>(clientInfo))->didPerformClientRedirect(sourceURL, destinationURL, frame);
1552 }
1553
1554 void TestController::didPerformClientRedirect(WKURLRef sourceURL, WKURLRef destinationURL, WKFrameRef)
1555 {
1556     if (m_state != RunningTest)
1557         return;
1558
1559     if (!m_shouldLogHistoryClientCallbacks)
1560         return;
1561
1562     WKRetainPtr<WKStringRef> sourceStringWK = adoptWK(WKURLCopyString(sourceURL));
1563     WKRetainPtr<WKStringRef> destinationStringWK = adoptWK(WKURLCopyString(destinationURL));
1564
1565     m_currentInvocation->outputText(String::format("WebView performed a client redirect from \"%s\" to \"%s\".\n", toSTD(sourceStringWK).c_str(), toSTD(destinationStringWK).c_str()));
1566 }
1567
1568 void TestController::didPerformServerRedirect(WKContextRef, WKPageRef, WKURLRef sourceURL, WKURLRef destinationURL, WKFrameRef frame, const void* clientInfo)
1569 {
1570     static_cast<TestController*>(const_cast<void*>(clientInfo))->didPerformServerRedirect(sourceURL, destinationURL, frame);
1571 }
1572
1573 void TestController::didPerformServerRedirect(WKURLRef sourceURL, WKURLRef destinationURL, WKFrameRef)
1574 {
1575     if (m_state != RunningTest)
1576         return;
1577
1578     if (!m_shouldLogHistoryClientCallbacks)
1579         return;
1580
1581     WKRetainPtr<WKStringRef> sourceStringWK = adoptWK(WKURLCopyString(sourceURL));
1582     WKRetainPtr<WKStringRef> destinationStringWK = adoptWK(WKURLCopyString(destinationURL));
1583
1584     m_currentInvocation->outputText(String::format("WebView performed a server redirect from \"%s\" to \"%s\".\n", toSTD(sourceStringWK).c_str(), toSTD(destinationStringWK).c_str()));
1585 }
1586
1587 void TestController::didUpdateHistoryTitle(WKContextRef, WKPageRef, WKStringRef title, WKURLRef URL, WKFrameRef frame, const void* clientInfo)
1588 {
1589     static_cast<TestController*>(const_cast<void*>(clientInfo))->didUpdateHistoryTitle(title, URL, frame);
1590 }
1591
1592 void TestController::didUpdateHistoryTitle(WKStringRef title, WKURLRef URL, WKFrameRef)
1593 {
1594     if (m_state != RunningTest)
1595         return;
1596
1597     if (!m_shouldLogHistoryClientCallbacks)
1598         return;
1599
1600     WKRetainPtr<WKStringRef> urlStringWK(AdoptWK, WKURLCopyString(URL));
1601     m_currentInvocation->outputText(String::format("WebView updated the title for history URL \"%s\" to \"%s\".\n", toSTD(urlStringWK).c_str(), toSTD(title).c_str()));
1602 }
1603
1604 } // namespace WTR