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