Unreviewed, rolling out r164073 and r164080.
[WebKit-https.git] / Tools / WebKitTestRunner / TestController.cpp
1 /*
2  * Copyright (C) 2010 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 <WebKit2/WKAuthenticationChallenge.h>
35 #include <WebKit2/WKAuthenticationDecisionListener.h>
36 #include <WebKit2/WKContextPrivate.h>
37 #include <WebKit2/WKCredential.h>
38 #include <WebKit2/WKIconDatabase.h>
39 #include <WebKit2/WKNotification.h>
40 #include <WebKit2/WKNotificationManager.h>
41 #include <WebKit2/WKNotificationPermissionRequest.h>
42 #include <WebKit2/WKNumber.h>
43 #include <WebKit2/WKPageGroup.h>
44 #include <WebKit2/WKPagePrivate.h>
45 #include <WebKit2/WKPreferencesPrivate.h>
46 #include <WebKit2/WKRetainPtr.h>
47 #include <algorithm>
48 #include <cstdio>
49 #include <ctype.h>
50 #include <stdlib.h>
51 #include <string>
52 #include <wtf/PassOwnPtr.h>
53 #include <wtf/text/CString.h>
54
55 #if PLATFORM(MAC)
56 #include <WebKit2/WKPagePrivateMac.h>
57 #endif
58
59 #if !PLATFORM(MAC)
60 #include <WebKit2/WKTextChecker.h>
61 #endif
62
63 namespace WTR {
64
65 const unsigned TestController::viewWidth = 800;
66 const unsigned TestController::viewHeight = 600;
67
68 const unsigned TestController::w3cSVGViewWidth = 480;
69 const unsigned TestController::w3cSVGViewHeight = 360;
70
71 // defaultLongTimeout + defaultShortTimeout should be less than 80,
72 // the default timeout value of the test harness so we can detect an
73 // unresponsive web process.
74 static const double defaultLongTimeout = 60;
75 static const double defaultShortTimeout = 15;
76 static const double defaultNoTimeout = -1;
77
78 static WKURLRef blankURL()
79 {
80     static WKURLRef staticBlankURL = WKURLCreateWithUTF8CString("about:blank");
81     return staticBlankURL;
82 }
83
84 static WKDataRef copyWebCryptoMasterKey(WKContextRef, const void*)
85 {
86     // Any 128 bit key would do, all we need for testing is to implement the callback.
87     return WKDataCreate((const uint8_t*)"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", 16);
88 }
89
90 static TestController* controller;
91
92 TestController& TestController::shared()
93 {
94     ASSERT(controller);
95     return *controller;
96 }
97
98 TestController::TestController(int argc, const char* argv[])
99     : m_verbose(false)
100     , m_printSeparators(false)
101     , m_usingServerMode(false)
102     , m_gcBetweenTests(false)
103     , m_shouldDumpPixelsForAllTests(false)
104     , m_state(Initial)
105     , m_doneResetting(false)
106     , m_longTimeout(defaultLongTimeout)
107     , m_shortTimeout(defaultShortTimeout)
108     , m_noTimeout(defaultNoTimeout)
109     , m_useWaitToDumpWatchdogTimer(true)
110     , m_forceNoTimeout(false)
111     , m_timeout(0)
112     , m_didPrintWebProcessCrashedMessage(false)
113     , m_shouldExitWhenWebProcessCrashes(true)
114     , m_beforeUnloadReturnValue(true)
115     , m_isGeolocationPermissionSet(false)
116     , m_isGeolocationPermissionAllowed(false)
117     , m_policyDelegateEnabled(false)
118     , m_policyDelegatePermissive(false)
119     , m_handlesAuthenticationChallenges(false)
120     , m_shouldBlockAllPlugins(false)
121     , m_forceComplexText(false)
122     , m_shouldUseAcceleratedDrawing(false)
123     , m_shouldUseRemoteLayerTree(false)
124 {
125     initialize(argc, argv);
126     controller = this;
127     run();
128     controller = 0;
129 }
130
131 TestController::~TestController()
132 {
133     WKIconDatabaseClose(WKContextGetIconDatabase(m_context.get()));
134
135     platformDestroy();
136 }
137
138 static WKRect getWindowFrame(WKPageRef page, const void* clientInfo)
139 {
140     PlatformWebView* view = static_cast<PlatformWebView*>(const_cast<void*>(clientInfo));
141     return view->windowFrame();
142 }
143
144 static void setWindowFrame(WKPageRef page, WKRect frame, const void* clientInfo)
145 {
146     PlatformWebView* view = static_cast<PlatformWebView*>(const_cast<void*>(clientInfo));
147     view->setWindowFrame(frame);
148 }
149
150 static bool runBeforeUnloadConfirmPanel(WKPageRef page, WKStringRef message, WKFrameRef frame, const void*)
151 {
152     printf("CONFIRM NAVIGATION: %s\n", toSTD(message).c_str());
153     return TestController::shared().beforeUnloadReturnValue();
154 }
155
156 void TestController::runModal(WKPageRef page, const void* clientInfo)
157 {
158     PlatformWebView* view = static_cast<PlatformWebView*>(const_cast<void*>(clientInfo));
159     view->setWindowIsKey(false);
160     runModal(view);
161     view->setWindowIsKey(true);
162 }
163
164 static void closeOtherPage(WKPageRef page, const void* clientInfo)
165 {
166     WKPageClose(page);
167     PlatformWebView* view = static_cast<PlatformWebView*>(const_cast<void*>(clientInfo));
168     delete view;
169 }
170
171 static void focus(WKPageRef page, const void* clientInfo)
172 {
173     PlatformWebView* view = static_cast<PlatformWebView*>(const_cast<void*>(clientInfo));
174     view->focus();
175     view->setWindowIsKey(true);
176 }
177
178 static void unfocus(WKPageRef page, const void* clientInfo)
179 {
180     PlatformWebView* view = static_cast<PlatformWebView*>(const_cast<void*>(clientInfo));
181     view->setWindowIsKey(false);
182 }
183
184 static void decidePolicyForGeolocationPermissionRequest(WKPageRef, WKFrameRef, WKSecurityOriginRef, WKGeolocationPermissionRequestRef permissionRequest, const void* clientInfo)
185 {
186     TestController::shared().handleGeolocationPermissionRequest(permissionRequest);
187 }
188
189 int TestController::getCustomTimeout()
190 {
191     return m_timeout;
192 }
193
194 WKPageRef TestController::createOtherPage(WKPageRef oldPage, WKURLRequestRef, WKDictionaryRef, WKEventModifiers, WKEventMouseButton, const void* clientInfo)
195 {
196     PlatformWebView* parentView = static_cast<PlatformWebView*>(const_cast<void*>(clientInfo));
197
198     PlatformWebView* view = new PlatformWebView(WKPageGetContext(oldPage), WKPageGetPageGroup(oldPage), oldPage, parentView->options());
199     WKPageRef newPage = view->page();
200
201     view->resizeTo(800, 600);
202
203     WKPageUIClientV2 otherPageUIClient = {
204         { 2, view },
205         0, // createNewPage_deprecatedForUseWithV0
206         0, // showPage
207         closeOtherPage,
208         0, // takeFocus
209         focus,
210         unfocus,
211         0, // runJavaScriptAlert
212         0, // runJavaScriptConfirm
213         0, // runJavaScriptPrompt
214         0, // setStatusText
215         0, // mouseDidMoveOverElement_deprecatedForUseWithV0
216         0, // missingPluginButtonClicked
217         0, // didNotHandleKeyEvent
218         0, // didNotHandleWheelEvent
219         0, // toolbarsAreVisible
220         0, // setToolbarsAreVisible
221         0, // menuBarIsVisible
222         0, // setMenuBarIsVisible
223         0, // statusBarIsVisible
224         0, // setStatusBarIsVisible
225         0, // isResizable
226         0, // setIsResizable
227         getWindowFrame,
228         setWindowFrame,
229         runBeforeUnloadConfirmPanel,
230         0, // didDraw
231         0, // pageDidScroll
232         0, // exceededDatabaseQuota
233         0, // runOpenPanel
234         decidePolicyForGeolocationPermissionRequest,
235         0, // headerHeight
236         0, // footerHeight
237         0, // drawHeader
238         0, // drawFooter
239         0, // printFrame
240         runModal,
241         0, // didCompleteRubberBandForMainFrame
242         0, // saveDataToFileInDownloadsFolder
243         0, // shouldInterruptJavaScript
244         createOtherPage,
245         0, // mouseDidMoveOverElement
246         0, // decidePolicyForNotificationPermissionRequest
247         0, // unavailablePluginButtonClicked_deprecatedForUseWithV1
248         0, // showColorPicker
249         0, // hideColorPicker
250         0, // unavailablePluginButtonClicked
251     };
252     WKPageSetPageUIClient(newPage, &otherPageUIClient.base);
253
254     view->didInitializeClients();
255
256     WKRetain(newPage);
257     return newPage;
258 }
259
260 const char* TestController::libraryPathForTesting()
261 {
262     // FIXME: This may not be sufficient to prevent interactions/crashes
263     // when running more than one copy of DumpRenderTree.
264     // See https://bugs.webkit.org/show_bug.cgi?id=10906
265     char* dumpRenderTreeTemp = getenv("DUMPRENDERTREE_TEMP");
266     if (dumpRenderTreeTemp)
267         return dumpRenderTreeTemp;
268     return platformLibraryPathForTesting();
269 }
270
271
272 void TestController::initialize(int argc, const char* argv[])
273 {
274     platformInitialize();
275
276     Options options(defaultLongTimeout, defaultShortTimeout);
277     OptionsHandler optionsHandler(options);
278
279     if (argc < 2) {
280         optionsHandler.printHelp();
281         exit(1);
282     }
283     if (!optionsHandler.parse(argc, argv))
284         exit(1);
285
286     m_longTimeout = options.longTimeout;
287     m_shortTimeout = options.shortTimeout;
288     m_useWaitToDumpWatchdogTimer = options.useWaitToDumpWatchdogTimer;
289     m_forceNoTimeout = options.forceNoTimeout;
290     m_verbose = options.verbose;
291     m_gcBetweenTests = options.gcBetweenTests;
292     m_shouldDumpPixelsForAllTests = options.shouldDumpPixelsForAllTests;
293     m_forceComplexText = options.forceComplexText;
294     m_shouldUseAcceleratedDrawing = options.shouldUseAcceleratedDrawing;
295     m_shouldUseRemoteLayerTree = options.shouldUseRemoteLayerTree;
296     m_paths = options.paths;
297
298     if (options.printSupportedFeatures) {
299         // FIXME: On Windows, DumpRenderTree uses this to expose whether it supports 3d
300         // transforms and accelerated compositing. When we support those features, we
301         // should match DRT's behavior.
302         exit(0);
303     }
304
305     m_usingServerMode = (m_paths.size() == 1 && m_paths[0] == "-");
306     if (m_usingServerMode)
307         m_printSeparators = true;
308     else
309         m_printSeparators = m_paths.size() > 1;
310
311     initializeInjectedBundlePath();
312     initializeTestPluginDirectory();
313
314     WKRetainPtr<WKStringRef> pageGroupIdentifier(AdoptWK, WKStringCreateWithUTF8CString("WebKitTestRunnerPageGroup"));
315     m_pageGroup.adopt(WKPageGroupCreateWithIdentifier(pageGroupIdentifier.get()));
316
317     m_context.adopt(WKContextCreateWithInjectedBundlePath(injectedBundlePath()));
318     m_geolocationProvider = adoptPtr(new GeolocationProviderMock(m_context.get()));
319
320 #if PLATFORM(IOS) || (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED > 1080)
321     WKContextSetUsesNetworkProcess(m_context.get(), true);
322     WKContextSetProcessModel(m_context.get(), kWKProcessModelMultipleSecondaryProcesses);
323 #endif
324
325     if (const char* dumpRenderTreeTemp = libraryPathForTesting()) {
326         String temporaryFolder = String::fromUTF8(dumpRenderTreeTemp);
327
328         // WebCore::pathByAppendingComponent is not used here because of the namespace,
329         // which leads us to this ugly #ifdef and file path concatenation.
330         const char separator = '/';
331
332         WKContextSetApplicationCacheDirectory(m_context.get(), toWK(temporaryFolder + separator + "ApplicationCache").get());
333         WKContextSetDatabaseDirectory(m_context.get(), toWK(temporaryFolder + separator + "Databases").get());
334         WKContextSetLocalStorageDirectory(m_context.get(), toWK(temporaryFolder + separator + "LocalStorage").get());
335         WKContextSetDiskCacheDirectory(m_context.get(), toWK(temporaryFolder + separator + "Cache").get());
336         WKContextSetCookieStorageDirectory(m_context.get(), toWK(temporaryFolder + separator + "Cookies").get());
337         WKContextSetIconDatabasePath(m_context.get(), toWK(temporaryFolder + separator + "IconDatabase" + separator + "WebpageIcons.db").get());
338     }
339
340     WKContextUseTestingNetworkSession(m_context.get());
341     WKContextSetCacheModel(m_context.get(), kWKCacheModelDocumentBrowser);
342
343     platformInitializeContext();
344
345     WKContextClientV1 contextClient = {
346         { 1, this },
347         nullptr, // plugInAutoStartOriginHashesChanged
348         nullptr, // networkProcessDidCrash,
349         nullptr, // plugInInformationBecameAvailable,
350         copyWebCryptoMasterKey
351     };
352     WKContextSetClient(m_context.get(), &contextClient.base);
353
354     WKContextInjectedBundleClientV1 injectedBundleClient = {
355         { 1, this },
356         didReceiveMessageFromInjectedBundle,
357         didReceiveSynchronousMessageFromInjectedBundle,
358         0 // getInjectedBundleInitializationUserData
359     };
360     WKContextSetInjectedBundleClient(m_context.get(), &injectedBundleClient.base);
361
362     WKNotificationManagerRef notificationManager = WKContextGetNotificationManager(m_context.get());
363     WKNotificationProviderV0 notificationKit = m_webNotificationProvider.provider();
364     WKNotificationManagerSetProvider(notificationManager, &notificationKit.base);
365
366     if (testPluginDirectory())
367         WKContextSetAdditionalPluginsDirectory(m_context.get(), testPluginDirectory());
368
369     if (m_forceComplexText)
370         WKContextSetAlwaysUsesComplexTextCodePath(m_context.get(), true);
371
372     // Some preferences (notably mock scroll bars setting) currently cannot be re-applied to an existing view, so we need to set them now.
373     resetPreferencesToConsistentValues();
374
375     WKRetainPtr<WKMutableDictionaryRef> viewOptions;
376     if (m_shouldUseRemoteLayerTree) {
377         viewOptions = adoptWK(WKMutableDictionaryCreate());
378         WKRetainPtr<WKStringRef> useRemoteLayerTreeKey = adoptWK(WKStringCreateWithUTF8CString("RemoteLayerTree"));
379         WKRetainPtr<WKBooleanRef> useRemoteLayerTreeValue = adoptWK(WKBooleanCreate(m_shouldUseRemoteLayerTree));
380         WKDictionarySetItem(viewOptions.get(), useRemoteLayerTreeKey.get(), useRemoteLayerTreeValue.get());
381     }
382
383     createWebViewWithOptions(viewOptions.get());
384 }
385
386 void TestController::createWebViewWithOptions(WKDictionaryRef options)
387 {
388     m_mainWebView = adoptPtr(new PlatformWebView(m_context.get(), m_pageGroup.get(), 0, options));
389     WKPageUIClientV2 pageUIClient = {
390         { 2, m_mainWebView.get() },
391         0, // createNewPage_deprecatedForUseWithV0
392         0, // showPage
393         0, // close
394         0, // takeFocus
395         focus,
396         unfocus,
397         0, // runJavaScriptAlert
398         0, // runJavaScriptConfirm
399         0, // runJavaScriptPrompt
400         0, // setStatusText
401         0, // mouseDidMoveOverElement_deprecatedForUseWithV0
402         0, // missingPluginButtonClicked
403         0, // didNotHandleKeyEvent
404         0, // didNotHandleWheelEvent
405         0, // toolbarsAreVisible
406         0, // setToolbarsAreVisible
407         0, // menuBarIsVisible
408         0, // setMenuBarIsVisible
409         0, // statusBarIsVisible
410         0, // setStatusBarIsVisible
411         0, // isResizable
412         0, // setIsResizable
413         getWindowFrame,
414         setWindowFrame,
415         runBeforeUnloadConfirmPanel,
416         0, // didDraw
417         0, // pageDidScroll
418         0, // exceededDatabaseQuota,
419         0, // runOpenPanel
420         decidePolicyForGeolocationPermissionRequest,
421         0, // headerHeight
422         0, // footerHeight
423         0, // drawHeader
424         0, // drawFooter
425         0, // printFrame
426         runModal,
427         0, // didCompleteRubberBandForMainFrame
428         0, // saveDataToFileInDownloadsFolder
429         0, // shouldInterruptJavaScript
430         createOtherPage,
431         0, // mouseDidMoveOverElement
432         decidePolicyForNotificationPermissionRequest, // decidePolicyForNotificationPermissionRequest
433         0, // unavailablePluginButtonClicked_deprecatedForUseWithV1
434         0, // showColorPicker
435         0, // hideColorPicker
436         unavailablePluginButtonClicked,
437     };
438     WKPageSetPageUIClient(m_mainWebView->page(), &pageUIClient.base);
439
440     WKPageLoaderClientV4 pageLoaderClient = {
441         { 4, this },
442         0, // didStartProvisionalLoadForFrame
443         0, // didReceiveServerRedirectForProvisionalLoadForFrame
444         0, // didFailProvisionalLoadWithErrorForFrame
445         didCommitLoadForFrame,
446         0, // didFinishDocumentLoadForFrame
447         didFinishLoadForFrame,
448         0, // didFailLoadWithErrorForFrame
449         0, // didSameDocumentNavigationForFrame
450         0, // didReceiveTitleForFrame
451         0, // didFirstLayoutForFrame
452         0, // didFirstVisuallyNonEmptyLayoutForFrame
453         0, // didRemoveFrameFromHierarchy
454         0, // didFailToInitializePlugin
455         0, // didDisplayInsecureContentForFrame
456         0, // canAuthenticateAgainstProtectionSpaceInFrame
457         didReceiveAuthenticationChallengeInFrame, // didReceiveAuthenticationChallengeInFrame
458         0, // didStartProgress
459         0, // didChangeProgress
460         0, // didFinishProgress
461         0, // didBecomeUnresponsive
462         0, // didBecomeResponsive
463         processDidCrash,
464         0, // didChangeBackForwardList
465         0, // shouldGoToBackForwardListItem
466         0, // didRunInsecureContentForFrame
467         0, // didDetectXSSForFrame
468         0, // didNewFirstVisuallyNonEmptyLayout_unavailable
469         0, // willGoToBackForwardListItem
470         0, // interactionOccurredWhileProcessUnresponsive
471         0, // pluginDidFail_deprecatedForUseWithV1
472         0, // didReceiveIntentForFrame
473         0, // registerIntentServiceForFrame
474         0, // didLayout
475         0, // pluginLoadPolicy_deprecatedForUseWithV2
476         0, // pluginDidFail
477         pluginLoadPolicy, // pluginLoadPolicy
478         0, // webGLLoadPolicy
479     };
480     WKPageSetPageLoaderClient(m_mainWebView->page(), &pageLoaderClient.base);
481
482     WKPagePolicyClientV1 pagePolicyClient = {
483         { 1, this },
484         0, // decidePolicyForNavigationAction_deprecatedForUseWithV0
485         0, // decidePolicyForNewWindowAction
486         0, // decidePolicyForResponse_deprecatedForUseWithV0
487         0, // unableToImplementPolicy
488         decidePolicyForNavigationAction,
489         decidePolicyForResponse,
490     };
491     WKPageSetPagePolicyClient(m_mainWebView->page(), &pagePolicyClient.base);
492
493     m_mainWebView->didInitializeClients();
494 }
495
496 void TestController::ensureViewSupportsOptions(WKDictionaryRef options)
497 {
498     if (m_mainWebView && !m_mainWebView->viewSupportsOptions(options)) {
499         WKPageSetPageUIClient(m_mainWebView->page(), 0);
500         WKPageSetPageLoaderClient(m_mainWebView->page(), 0);
501         WKPageSetPagePolicyClient(m_mainWebView->page(), 0);
502         WKPageClose(m_mainWebView->page());
503         
504         m_mainWebView = nullptr;
505
506         createWebViewWithOptions(options);
507         resetStateToConsistentValues();
508     }
509 }
510
511 void TestController::resetPreferencesToConsistentValues()
512 {
513     // Reset preferences
514     WKPreferencesRef preferences = WKPageGroupGetPreferences(m_pageGroup.get());
515     WKPreferencesResetTestRunnerOverrides(preferences);
516     WKPreferencesSetOfflineWebApplicationCacheEnabled(preferences, true);
517     WKPreferencesSetFontSmoothingLevel(preferences, kWKFontSmoothingLevelNoSubpixelAntiAliasing);
518     WKPreferencesSetXSSAuditorEnabled(preferences, false);
519     WKPreferencesSetWebAudioEnabled(preferences, true);
520     WKPreferencesSetDeveloperExtrasEnabled(preferences, true);
521     WKPreferencesSetJavaScriptExperimentsEnabled(preferences, true);
522     WKPreferencesSetJavaScriptCanOpenWindowsAutomatically(preferences, true);
523     WKPreferencesSetJavaScriptCanAccessClipboard(preferences, true);
524     WKPreferencesSetDOMPasteAllowed(preferences, true);
525     WKPreferencesSetUniversalAccessFromFileURLsAllowed(preferences, true);
526     WKPreferencesSetFileAccessFromFileURLsAllowed(preferences, true);
527 #if ENABLE(FULLSCREEN_API)
528     WKPreferencesSetFullScreenEnabled(preferences, true);
529 #endif
530     WKPreferencesSetPageCacheEnabled(preferences, false);
531     WKPreferencesSetAsynchronousPluginInitializationEnabled(preferences, false);
532     WKPreferencesSetAsynchronousPluginInitializationEnabledForAllPlugins(preferences, false);
533     WKPreferencesSetArtificialPluginInitializationDelayEnabled(preferences, false);
534     WKPreferencesSetTabToLinksEnabled(preferences, false);
535     WKPreferencesSetInteractiveFormValidationEnabled(preferences, true);
536     WKPreferencesSetMockScrollbarsEnabled(preferences, true);
537
538     static WKStringRef standardFontFamily = WKStringCreateWithUTF8CString("Times");
539     static WKStringRef cursiveFontFamily = WKStringCreateWithUTF8CString("Apple Chancery");
540     static WKStringRef fantasyFontFamily = WKStringCreateWithUTF8CString("Papyrus");
541     static WKStringRef fixedFontFamily = WKStringCreateWithUTF8CString("Courier");
542     static WKStringRef pictographFontFamily = WKStringCreateWithUTF8CString("Apple Color Emoji");
543     static WKStringRef sansSerifFontFamily = WKStringCreateWithUTF8CString("Helvetica");
544     static WKStringRef serifFontFamily = WKStringCreateWithUTF8CString("Times");
545
546     WKPreferencesSetStandardFontFamily(preferences, standardFontFamily);
547     WKPreferencesSetCursiveFontFamily(preferences, cursiveFontFamily);
548     WKPreferencesSetFantasyFontFamily(preferences, fantasyFontFamily);
549     WKPreferencesSetFixedFontFamily(preferences, fixedFontFamily);
550     WKPreferencesSetPictographFontFamily(preferences, pictographFontFamily);
551     WKPreferencesSetSansSerifFontFamily(preferences, sansSerifFontFamily);
552     WKPreferencesSetSerifFontFamily(preferences, serifFontFamily);
553     WKPreferencesSetScreenFontSubstitutionEnabled(preferences, true);
554     WKPreferencesSetAsynchronousSpellCheckingEnabled(preferences, false);
555 #if ENABLE(WEB_AUDIO)
556     WKPreferencesSetMediaSourceEnabled(preferences, true);
557 #endif
558
559     WKPreferencesSetAcceleratedDrawingEnabled(preferences, m_shouldUseAcceleratedDrawing);
560 }
561
562 bool TestController::resetStateToConsistentValues()
563 {
564     m_state = Resetting;
565
566     m_beforeUnloadReturnValue = true;
567
568     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("Reset"));
569     WKRetainPtr<WKMutableDictionaryRef> resetMessageBody = adoptWK(WKMutableDictionaryCreate());
570
571     WKRetainPtr<WKStringRef> shouldGCKey = adoptWK(WKStringCreateWithUTF8CString("ShouldGC"));
572     WKRetainPtr<WKBooleanRef> shouldGCValue = adoptWK(WKBooleanCreate(m_gcBetweenTests));
573     WKDictionarySetItem(resetMessageBody.get(), shouldGCKey.get(), shouldGCValue.get());
574
575     WKContextPostMessageToInjectedBundle(TestController::shared().context(), messageName.get(), resetMessageBody.get());
576
577     WKContextSetShouldUseFontSmoothing(TestController::shared().context(), false);
578
579     WKContextSetCacheModel(TestController::shared().context(), kWKCacheModelDocumentBrowser);
580
581     // FIXME: This function should also ensure that there is only one page open.
582
583     // Reset the EventSender for each test.
584     m_eventSenderProxy = adoptPtr(new EventSenderProxy(this));
585
586     // FIXME: Is this needed? Nothing in TestController changes preferences during tests, and if there is
587     // some other code doing this, it should probably be responsible for cleanup too.
588     resetPreferencesToConsistentValues();
589
590 #if !PLATFORM(MAC)
591     WKTextCheckerContinuousSpellCheckingEnabledStateChanged(true);
592 #endif
593
594     // in the case that a test using the chrome input field failed, be sure to clean up for the next test
595     m_mainWebView->removeChromeInputField();
596     m_mainWebView->focus();
597
598     // Re-set to the default backing scale factor by setting the custom scale factor to 0.
599     WKPageSetCustomBackingScaleFactor(m_mainWebView->page(), 0);
600
601 #if PLATFORM(EFL)
602     // EFL use a real window while other ports such as Qt don't.
603     // In EFL, we need to resize the window to the original size after calls to window.resizeTo.
604     WKRect rect = m_mainWebView->windowFrame();
605     m_mainWebView->setWindowFrame(WKRectMake(rect.origin.x, rect.origin.y, TestController::viewWidth, TestController::viewHeight));
606 #endif
607
608     // Reset notification permissions
609     m_webNotificationProvider.reset();
610
611     // Reset Geolocation permissions.
612     m_geolocationPermissionRequests.clear();
613     m_isGeolocationPermissionSet = false;
614     m_isGeolocationPermissionAllowed = false;
615
616     // Reset Custom Policy Delegate.
617     setCustomPolicyDelegate(false, false);
618
619     m_workQueueManager.clearWorkQueue();
620
621     m_handlesAuthenticationChallenges = false;
622     m_authenticationUsername = String();
623     m_authenticationPassword = String();
624
625     m_shouldBlockAllPlugins = false;
626
627     // Reset main page back to about:blank
628     m_doneResetting = false;
629
630     WKPageLoadURL(m_mainWebView->page(), blankURL());
631     runUntil(m_doneResetting, ShortTimeout);
632     return m_doneResetting;
633 }
634
635 struct TestCommand {
636     TestCommand() : shouldDumpPixels(false), timeout(0) { }
637
638     std::string pathOrURL;
639     bool shouldDumpPixels;
640     std::string expectedPixelHash;
641     int timeout;
642 };
643
644 class CommandTokenizer {
645 public:
646     explicit CommandTokenizer(const std::string& input)
647         : m_input(input)
648         , m_posNextSeparator(0)
649     {
650         pump();
651     }
652
653     bool hasNext() const;
654     std::string next();
655
656 private:
657     void pump();
658     static const char kSeparator = '\'';
659     const std::string& m_input;
660     std::string m_next;
661     size_t m_posNextSeparator;
662 };
663
664 void CommandTokenizer::pump()
665 {
666     if (m_posNextSeparator == std::string::npos || m_posNextSeparator == m_input.size()) {
667         m_next = std::string();
668         return;
669     }
670     size_t start = m_posNextSeparator ? m_posNextSeparator + 1 : 0;
671     m_posNextSeparator = m_input.find(kSeparator, start);
672     size_t size = m_posNextSeparator == std::string::npos ? std::string::npos : m_posNextSeparator - start;
673     m_next = std::string(m_input, start, size);
674 }
675
676 std::string CommandTokenizer::next()
677 {
678     ASSERT(hasNext());
679
680     std::string oldNext = m_next;
681     pump();
682     return oldNext;
683 }
684
685 bool CommandTokenizer::hasNext() const
686 {
687     return !m_next.empty();
688 }
689
690 NO_RETURN static void die(const std::string& inputLine)
691 {
692     fprintf(stderr, "Unexpected input line: %s\n", inputLine.c_str());
693     exit(1);
694 }
695
696 TestCommand parseInputLine(const std::string& inputLine)
697 {
698     TestCommand result;
699     CommandTokenizer tokenizer(inputLine);
700     if (!tokenizer.hasNext())
701         die(inputLine);
702
703     std::string arg = tokenizer.next();
704     result.pathOrURL = arg;
705     while (tokenizer.hasNext()) {
706         arg = tokenizer.next();
707         if (arg == std::string("--timeout")) {
708             std::string timeoutToken = tokenizer.next();
709             result.timeout = atoi(timeoutToken.c_str());
710         } else if (arg == std::string("-p") || arg == std::string("--pixel-test")) {
711             result.shouldDumpPixels = true;
712             if (tokenizer.hasNext())
713                 result.expectedPixelHash = tokenizer.next();
714         } else
715             die(inputLine);
716     }
717     return result;
718 }
719
720 bool TestController::runTest(const char* inputLine)
721 {
722     TestCommand command = parseInputLine(std::string(inputLine));
723
724     m_state = RunningTest;
725
726     m_currentInvocation = adoptPtr(new TestInvocation(command.pathOrURL));
727     if (command.shouldDumpPixels || m_shouldDumpPixelsForAllTests)
728         m_currentInvocation->setIsPixelTest(command.expectedPixelHash);
729     if (command.timeout > 0)
730         m_currentInvocation->setCustomTimeout(command.timeout);
731
732     m_currentInvocation->invoke();
733     m_currentInvocation.clear();
734
735     return true;
736 }
737
738 void TestController::runTestingServerLoop()
739 {
740     char filenameBuffer[2048];
741     while (fgets(filenameBuffer, sizeof(filenameBuffer), stdin)) {
742         char* newLineCharacter = strchr(filenameBuffer, '\n');
743         if (newLineCharacter)
744             *newLineCharacter = '\0';
745
746         if (strlen(filenameBuffer) == 0)
747             continue;
748
749         if (!runTest(filenameBuffer))
750             break;
751     }
752 }
753
754 void TestController::run()
755 {
756     if (!resetStateToConsistentValues()) {
757         TestInvocation::dumpWebProcessUnresponsiveness("<unknown> - TestController::run - Failed to reset state to consistent values\n");
758         return;
759     }
760
761     if (m_usingServerMode)
762         runTestingServerLoop();
763     else {
764         for (size_t i = 0; i < m_paths.size(); ++i) {
765             if (!runTest(m_paths[i].c_str()))
766                 break;
767         }
768     }
769 }
770
771 void TestController::runUntil(bool& done, TimeoutDuration timeoutDuration)
772 {
773     double timeout = m_noTimeout;
774     if (!m_forceNoTimeout) {
775         switch (timeoutDuration) {
776         case ShortTimeout:
777             timeout = m_shortTimeout;
778             break;
779         case LongTimeout:
780             timeout = m_longTimeout;
781             break;
782         case CustomTimeout:
783             timeout = m_timeout;
784             break;
785         case NoTimeout:
786         default:
787             timeout = m_noTimeout;
788             break;
789         }
790     }
791
792     platformRunUntil(done, timeout);
793 }
794
795 // WKContextInjectedBundleClient
796
797 void TestController::didReceiveMessageFromInjectedBundle(WKContextRef context, WKStringRef messageName, WKTypeRef messageBody, const void* clientInfo)
798 {
799     static_cast<TestController*>(const_cast<void*>(clientInfo))->didReceiveMessageFromInjectedBundle(messageName, messageBody);
800 }
801
802 void TestController::didReceiveSynchronousMessageFromInjectedBundle(WKContextRef context, WKStringRef messageName, WKTypeRef messageBody, WKTypeRef* returnData, const void* clientInfo)
803 {
804     *returnData = static_cast<TestController*>(const_cast<void*>(clientInfo))->didReceiveSynchronousMessageFromInjectedBundle(messageName, messageBody).leakRef();
805 }
806
807 void TestController::didReceiveKeyDownMessageFromInjectedBundle(WKDictionaryRef messageBodyDictionary, bool synchronous)
808 {
809     WKRetainPtr<WKStringRef> keyKey = adoptWK(WKStringCreateWithUTF8CString("Key"));
810     WKStringRef key = static_cast<WKStringRef>(WKDictionaryGetItemForKey(messageBodyDictionary, keyKey.get()));
811
812     WKRetainPtr<WKStringRef> modifiersKey = adoptWK(WKStringCreateWithUTF8CString("Modifiers"));
813     WKEventModifiers modifiers = static_cast<WKEventModifiers>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, modifiersKey.get()))));
814
815     WKRetainPtr<WKStringRef> locationKey = adoptWK(WKStringCreateWithUTF8CString("Location"));
816     unsigned location = static_cast<unsigned>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, locationKey.get()))));
817
818     if (synchronous)
819         WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), true);
820
821     m_eventSenderProxy->keyDown(key, modifiers, location);
822
823     if (synchronous)
824         WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false);
825 }
826
827 void TestController::didReceiveMessageFromInjectedBundle(WKStringRef messageName, WKTypeRef messageBody)
828 {
829     if (WKStringIsEqualToUTF8CString(messageName, "EventSender")) {
830         ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID());
831         WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody);
832
833         WKRetainPtr<WKStringRef> subMessageKey(AdoptWK, WKStringCreateWithUTF8CString("SubMessage"));
834         WKStringRef subMessageName = static_cast<WKStringRef>(WKDictionaryGetItemForKey(messageBodyDictionary, subMessageKey.get()));
835
836         if (WKStringIsEqualToUTF8CString(subMessageName, "MouseDown") || WKStringIsEqualToUTF8CString(subMessageName, "MouseUp")) {
837             WKRetainPtr<WKStringRef> buttonKey = adoptWK(WKStringCreateWithUTF8CString("Button"));
838             unsigned button = static_cast<unsigned>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, buttonKey.get()))));
839
840             WKRetainPtr<WKStringRef> modifiersKey = adoptWK(WKStringCreateWithUTF8CString("Modifiers"));
841             WKEventModifiers modifiers = static_cast<WKEventModifiers>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, modifiersKey.get()))));
842
843             // Forward to WebProcess
844             WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false);
845             if (WKStringIsEqualToUTF8CString(subMessageName, "MouseDown"))
846                 m_eventSenderProxy->mouseDown(button, modifiers);
847             else
848                 m_eventSenderProxy->mouseUp(button, modifiers);
849
850             return;
851         }
852
853         if (WKStringIsEqualToUTF8CString(subMessageName, "KeyDown")) {
854             didReceiveKeyDownMessageFromInjectedBundle(messageBodyDictionary, false);
855
856             return;
857         }
858
859         ASSERT_NOT_REACHED();
860     }
861
862     if (!m_currentInvocation)
863         return;
864
865     m_currentInvocation->didReceiveMessageFromInjectedBundle(messageName, messageBody);
866 }
867
868 WKRetainPtr<WKTypeRef> TestController::didReceiveSynchronousMessageFromInjectedBundle(WKStringRef messageName, WKTypeRef messageBody)
869 {
870     if (WKStringIsEqualToUTF8CString(messageName, "EventSender")) {
871         ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID());
872         WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody);
873
874         WKRetainPtr<WKStringRef> subMessageKey(AdoptWK, WKStringCreateWithUTF8CString("SubMessage"));
875         WKStringRef subMessageName = static_cast<WKStringRef>(WKDictionaryGetItemForKey(messageBodyDictionary, subMessageKey.get()));
876
877         if (WKStringIsEqualToUTF8CString(subMessageName, "KeyDown")) {
878             didReceiveKeyDownMessageFromInjectedBundle(messageBodyDictionary, true);
879
880             return 0;
881         }
882
883         if (WKStringIsEqualToUTF8CString(subMessageName, "MouseDown") || WKStringIsEqualToUTF8CString(subMessageName, "MouseUp")) {
884             WKRetainPtr<WKStringRef> buttonKey = adoptWK(WKStringCreateWithUTF8CString("Button"));
885             unsigned button = static_cast<unsigned>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, buttonKey.get()))));
886
887             WKRetainPtr<WKStringRef> modifiersKey = adoptWK(WKStringCreateWithUTF8CString("Modifiers"));
888             WKEventModifiers modifiers = static_cast<WKEventModifiers>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, modifiersKey.get()))));
889
890             // Forward to WebProcess
891             WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), true);
892             if (WKStringIsEqualToUTF8CString(subMessageName, "MouseDown"))
893                 m_eventSenderProxy->mouseDown(button, modifiers);
894             else
895                 m_eventSenderProxy->mouseUp(button, modifiers);
896             WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false);
897             return 0;
898         }
899
900         if (WKStringIsEqualToUTF8CString(subMessageName, "MouseMoveTo")) {
901             WKRetainPtr<WKStringRef> xKey = adoptWK(WKStringCreateWithUTF8CString("X"));
902             double x = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, xKey.get())));
903
904             WKRetainPtr<WKStringRef> yKey = adoptWK(WKStringCreateWithUTF8CString("Y"));
905             double y = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, yKey.get())));
906
907             // Forward to WebProcess
908             WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), true);
909             m_eventSenderProxy->mouseMoveTo(x, y);
910             WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false);
911             return 0;
912         }
913
914         if (WKStringIsEqualToUTF8CString(subMessageName, "MouseScrollBy")) {
915             WKRetainPtr<WKStringRef> xKey = adoptWK(WKStringCreateWithUTF8CString("X"));
916             double x = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, xKey.get())));
917
918             WKRetainPtr<WKStringRef> yKey = adoptWK(WKStringCreateWithUTF8CString("Y"));
919             double y = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, yKey.get())));
920
921             // Forward to WebProcess
922             WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), true);
923             m_eventSenderProxy->mouseScrollBy(x, y);
924             WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false);
925             return 0;
926         }
927
928         if (WKStringIsEqualToUTF8CString(subMessageName, "ContinuousMouseScrollBy")) {
929             WKRetainPtr<WKStringRef> xKey = adoptWK(WKStringCreateWithUTF8CString("X"));
930             double x = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, xKey.get())));
931
932             WKRetainPtr<WKStringRef> yKey = adoptWK(WKStringCreateWithUTF8CString("Y"));
933             double y = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, yKey.get())));
934
935             WKRetainPtr<WKStringRef> pagedKey = adoptWK(WKStringCreateWithUTF8CString("Paged"));
936             bool paged = static_cast<bool>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, pagedKey.get()))));
937
938             // Forward to WebProcess
939             WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), true);
940             m_eventSenderProxy->continuousMouseScrollBy(x, y, paged);
941             WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false);
942             return 0;
943         }
944
945         if (WKStringIsEqualToUTF8CString(subMessageName, "LeapForward")) {
946             WKRetainPtr<WKStringRef> timeKey = adoptWK(WKStringCreateWithUTF8CString("TimeInMilliseconds"));
947             unsigned time = static_cast<unsigned>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, timeKey.get()))));
948
949             m_eventSenderProxy->leapForward(time);
950             return 0;
951         }
952
953 #if ENABLE(TOUCH_EVENTS)
954         if (WKStringIsEqualToUTF8CString(subMessageName, "AddTouchPoint")) {
955             WKRetainPtr<WKStringRef> xKey = adoptWK(WKStringCreateWithUTF8CString("X"));
956             int x = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, xKey.get()))));
957
958             WKRetainPtr<WKStringRef> yKey = adoptWK(WKStringCreateWithUTF8CString("Y"));
959             int y = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, yKey.get()))));
960
961             m_eventSenderProxy->addTouchPoint(x, y);
962             return 0;
963         }
964
965         if (WKStringIsEqualToUTF8CString(subMessageName, "UpdateTouchPoint")) {
966             WKRetainPtr<WKStringRef> indexKey = adoptWK(WKStringCreateWithUTF8CString("Index"));
967             int index = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, indexKey.get()))));
968
969             WKRetainPtr<WKStringRef> xKey = adoptWK(WKStringCreateWithUTF8CString("X"));
970             int x = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, xKey.get()))));
971
972             WKRetainPtr<WKStringRef> yKey = adoptWK(WKStringCreateWithUTF8CString("Y"));
973             int y = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, yKey.get()))));
974
975             m_eventSenderProxy->updateTouchPoint(index, x, y);
976             return 0;
977         }
978
979         if (WKStringIsEqualToUTF8CString(subMessageName, "SetTouchModifier")) {
980             WKRetainPtr<WKStringRef> modifierKey = adoptWK(WKStringCreateWithUTF8CString("Modifier"));
981             WKEventModifiers modifier = static_cast<WKEventModifiers>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, modifierKey.get()))));
982
983             WKRetainPtr<WKStringRef> enableKey = adoptWK(WKStringCreateWithUTF8CString("Enable"));
984             bool enable = static_cast<bool>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, enableKey.get()))));
985
986             m_eventSenderProxy->setTouchModifier(modifier, enable);
987             return 0;
988         }
989
990         if (WKStringIsEqualToUTF8CString(subMessageName, "SetTouchPointRadius")) {
991             WKRetainPtr<WKStringRef> xKey = adoptWK(WKStringCreateWithUTF8CString("RadiusX"));
992             int x = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, xKey.get()))));
993
994             WKRetainPtr<WKStringRef> yKey = adoptWK(WKStringCreateWithUTF8CString("RadiusY"));
995             int y = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, yKey.get()))));
996
997             m_eventSenderProxy->setTouchPointRadius(x, y);
998             return 0;
999         }
1000
1001         if (WKStringIsEqualToUTF8CString(subMessageName, "TouchStart")) {
1002             WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), true);
1003             m_eventSenderProxy->touchStart();
1004             WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false);
1005             return 0;
1006         }
1007
1008         if (WKStringIsEqualToUTF8CString(subMessageName, "TouchMove")) {
1009             WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), true);
1010             m_eventSenderProxy->touchMove();
1011             WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false);
1012             return 0;
1013         }
1014
1015         if (WKStringIsEqualToUTF8CString(subMessageName, "TouchEnd")) {
1016             WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), true);
1017             m_eventSenderProxy->touchEnd();
1018             WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false);
1019             return 0;
1020         }
1021
1022         if (WKStringIsEqualToUTF8CString(subMessageName, "TouchCancel")) {
1023             WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), true);
1024             m_eventSenderProxy->touchCancel();
1025             WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false);
1026             return 0;
1027         }
1028
1029         if (WKStringIsEqualToUTF8CString(subMessageName, "ClearTouchPoints")) {
1030             m_eventSenderProxy->clearTouchPoints();
1031             return 0;
1032         }
1033
1034         if (WKStringIsEqualToUTF8CString(subMessageName, "ReleaseTouchPoint")) {
1035             WKRetainPtr<WKStringRef> indexKey = adoptWK(WKStringCreateWithUTF8CString("Index"));
1036             int index = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, indexKey.get()))));
1037             m_eventSenderProxy->releaseTouchPoint(index);
1038             return 0;
1039         }
1040
1041         if (WKStringIsEqualToUTF8CString(subMessageName, "CancelTouchPoint")) {
1042             WKRetainPtr<WKStringRef> indexKey = adoptWK(WKStringCreateWithUTF8CString("Index"));
1043             int index = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, indexKey.get()))));
1044             m_eventSenderProxy->cancelTouchPoint(index);
1045             return 0;
1046         }
1047 #endif
1048         ASSERT_NOT_REACHED();
1049     }
1050     return m_currentInvocation->didReceiveSynchronousMessageFromInjectedBundle(messageName, messageBody);
1051 }
1052
1053 // WKPageLoaderClient
1054
1055 void TestController::didCommitLoadForFrame(WKPageRef page, WKFrameRef frame, WKTypeRef, const void* clientInfo)
1056 {
1057     static_cast<TestController*>(const_cast<void*>(clientInfo))->didCommitLoadForFrame(page, frame);
1058 }
1059
1060 void TestController::didFinishLoadForFrame(WKPageRef page, WKFrameRef frame, WKTypeRef, const void* clientInfo)
1061 {
1062     static_cast<TestController*>(const_cast<void*>(clientInfo))->didFinishLoadForFrame(page, frame);
1063 }
1064
1065 void TestController::didReceiveAuthenticationChallengeInFrame(WKPageRef page, WKFrameRef frame, WKAuthenticationChallengeRef authenticationChallenge, const void *clientInfo)
1066 {
1067     static_cast<TestController*>(const_cast<void*>(clientInfo))->didReceiveAuthenticationChallengeInFrame(page, frame, authenticationChallenge);
1068 }
1069
1070 void TestController::processDidCrash(WKPageRef page, const void* clientInfo)
1071 {
1072     static_cast<TestController*>(const_cast<void*>(clientInfo))->processDidCrash();
1073 }
1074
1075 WKPluginLoadPolicy TestController::pluginLoadPolicy(WKPageRef page, WKPluginLoadPolicy currentPluginLoadPolicy, WKDictionaryRef pluginInformation, WKStringRef* unavailabilityDescription, const void* clientInfo)
1076 {
1077     return static_cast<TestController*>(const_cast<void*>(clientInfo))->pluginLoadPolicy(page, currentPluginLoadPolicy, pluginInformation, unavailabilityDescription);
1078 }
1079
1080 WKPluginLoadPolicy TestController::pluginLoadPolicy(WKPageRef, WKPluginLoadPolicy currentPluginLoadPolicy, WKDictionaryRef pluginInformation, WKStringRef* unavailabilityDescription)
1081 {
1082     if (m_shouldBlockAllPlugins)
1083         return kWKPluginLoadPolicyBlocked;
1084     return currentPluginLoadPolicy;
1085 }
1086
1087 void TestController::didCommitLoadForFrame(WKPageRef page, WKFrameRef frame)
1088 {
1089     if (!WKFrameIsMainFrame(frame))
1090         return;
1091
1092     mainWebView()->focus();
1093 }
1094
1095 void TestController::didFinishLoadForFrame(WKPageRef page, WKFrameRef frame)
1096 {
1097     if (m_state != Resetting)
1098         return;
1099
1100     if (!WKFrameIsMainFrame(frame))
1101         return;
1102
1103     WKRetainPtr<WKURLRef> wkURL(AdoptWK, WKFrameCopyURL(frame));
1104     if (!WKURLIsEqual(wkURL.get(), blankURL()))
1105         return;
1106
1107     m_doneResetting = true;
1108     shared().notifyDone();
1109 }
1110
1111 void TestController::didReceiveAuthenticationChallengeInFrame(WKPageRef page, WKFrameRef frame, WKAuthenticationChallengeRef authenticationChallenge)
1112 {
1113     String message;
1114     if (!m_handlesAuthenticationChallenges)
1115         message = "<unknown> - didReceiveAuthenticationChallenge - Simulating cancelled authentication sheet\n";
1116     else
1117         message = String::format("<unknown> - didReceiveAuthenticationChallenge - Responding with %s:%s\n", m_authenticationUsername.utf8().data(), m_authenticationPassword.utf8().data());
1118     m_currentInvocation->outputText(message);
1119
1120     WKAuthenticationDecisionListenerRef decisionListener = WKAuthenticationChallengeGetDecisionListener(authenticationChallenge);
1121     if (!m_handlesAuthenticationChallenges) {
1122         WKAuthenticationDecisionListenerUseCredential(decisionListener, 0);
1123         return;
1124     }
1125     WKRetainPtr<WKStringRef> username(AdoptWK, WKStringCreateWithUTF8CString(m_authenticationUsername.utf8().data()));
1126     WKRetainPtr<WKStringRef> password(AdoptWK, WKStringCreateWithUTF8CString(m_authenticationPassword.utf8().data()));
1127     WKRetainPtr<WKCredentialRef> credential(AdoptWK, WKCredentialCreate(username.get(), password.get(), kWKCredentialPersistenceForSession));
1128     WKAuthenticationDecisionListenerUseCredential(decisionListener, credential.get());
1129 }
1130
1131 void TestController::processDidCrash()
1132 {
1133     // This function can be called multiple times when crash logs are being saved on Windows, so
1134     // ensure we only print the crashed message once.
1135     if (!m_didPrintWebProcessCrashedMessage) {
1136 #if PLATFORM(MAC)
1137         pid_t pid = WKPageGetProcessIdentifier(m_mainWebView->page());
1138         fprintf(stderr, "#CRASHED - WebProcess (pid %ld)\n", static_cast<long>(pid));
1139 #else
1140         fputs("#CRASHED - WebProcess\n", stderr);
1141 #endif
1142         fflush(stderr);
1143         m_didPrintWebProcessCrashedMessage = true;
1144     }
1145
1146     if (m_shouldExitWhenWebProcessCrashes)
1147         exit(1);
1148 }
1149
1150 void TestController::simulateWebNotificationClick(uint64_t notificationID)
1151 {
1152     m_webNotificationProvider.simulateWebNotificationClick(notificationID);
1153 }
1154
1155 void TestController::setGeolocationPermission(bool enabled)
1156 {
1157     m_isGeolocationPermissionSet = true;
1158     m_isGeolocationPermissionAllowed = enabled;
1159     decidePolicyForGeolocationPermissionRequestIfPossible();
1160 }
1161
1162 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)
1163 {
1164     m_geolocationProvider->setPosition(latitude, longitude, accuracy, providesAltitude, altitude, providesAltitudeAccuracy, altitudeAccuracy, providesHeading, heading, providesSpeed, speed);
1165 }
1166
1167 void TestController::setMockGeolocationPositionUnavailableError(WKStringRef errorMessage)
1168 {
1169     m_geolocationProvider->setPositionUnavailableError(errorMessage);
1170 }
1171
1172 void TestController::handleGeolocationPermissionRequest(WKGeolocationPermissionRequestRef geolocationPermissionRequest)
1173 {
1174     m_geolocationPermissionRequests.append(geolocationPermissionRequest);
1175     decidePolicyForGeolocationPermissionRequestIfPossible();
1176 }
1177
1178 void TestController::setCustomPolicyDelegate(bool enabled, bool permissive)
1179 {
1180     m_policyDelegateEnabled = enabled;
1181     m_policyDelegatePermissive = permissive;
1182 }
1183
1184 void TestController::decidePolicyForGeolocationPermissionRequestIfPossible()
1185 {
1186     if (!m_isGeolocationPermissionSet)
1187         return;
1188
1189     for (size_t i = 0; i < m_geolocationPermissionRequests.size(); ++i) {
1190         WKGeolocationPermissionRequestRef permissionRequest = m_geolocationPermissionRequests[i].get();
1191         if (m_isGeolocationPermissionAllowed)
1192             WKGeolocationPermissionRequestAllow(permissionRequest);
1193         else
1194             WKGeolocationPermissionRequestDeny(permissionRequest);
1195     }
1196     m_geolocationPermissionRequests.clear();
1197 }
1198
1199 void TestController::decidePolicyForNotificationPermissionRequest(WKPageRef page, WKSecurityOriginRef origin, WKNotificationPermissionRequestRef request, const void*)
1200 {
1201     TestController::shared().decidePolicyForNotificationPermissionRequest(page, origin, request);
1202 }
1203
1204 void TestController::decidePolicyForNotificationPermissionRequest(WKPageRef, WKSecurityOriginRef, WKNotificationPermissionRequestRef request)
1205 {
1206     WKNotificationPermissionRequestAllow(request);
1207 }
1208
1209 void TestController::unavailablePluginButtonClicked(WKPageRef, WKPluginUnavailabilityReason, WKDictionaryRef, const void*)
1210 {
1211     printf("MISSING PLUGIN BUTTON PRESSED\n");
1212 }
1213
1214 void TestController::decidePolicyForNavigationAction(WKPageRef, WKFrameRef, WKFrameNavigationType, WKEventModifiers, WKEventMouseButton, WKFrameRef, WKURLRequestRef, WKFramePolicyListenerRef listener, WKTypeRef, const void* clientInfo)
1215 {
1216     static_cast<TestController*>(const_cast<void*>(clientInfo))->decidePolicyForNavigationAction(listener);
1217 }
1218
1219 void TestController::decidePolicyForNavigationAction(WKFramePolicyListenerRef listener)
1220 {
1221     if (m_policyDelegateEnabled && !m_policyDelegatePermissive) {
1222         WKFramePolicyListenerIgnore(listener);
1223         return;
1224     }
1225
1226     WKFramePolicyListenerUse(listener);
1227 }
1228
1229 void TestController::decidePolicyForResponse(WKPageRef, WKFrameRef frame, WKURLResponseRef response, WKURLRequestRef, bool canShowMIMEType, WKFramePolicyListenerRef listener, WKTypeRef, const void* clientInfo)
1230 {
1231     static_cast<TestController*>(const_cast<void*>(clientInfo))->decidePolicyForResponse(frame, response, listener);
1232 }
1233
1234 void TestController::decidePolicyForResponse(WKFrameRef frame, WKURLResponseRef response, WKFramePolicyListenerRef listener)
1235 {
1236     // Even though Response was already checked by WKBundlePagePolicyClient, the check did not include plugins
1237     // so we have to re-check again.
1238     WKRetainPtr<WKStringRef> wkMIMEType(AdoptWK, WKURLResponseCopyMIMEType(response));
1239     if (WKFrameCanShowMIMEType(frame, wkMIMEType.get())) {
1240         WKFramePolicyListenerUse(listener);
1241         return;
1242     }
1243
1244     WKFramePolicyListenerIgnore(listener);
1245 }
1246
1247 } // namespace WTR