[EFL] [WK2] fast/dom/vertical-scrollbar-in-rtl.html makes fast/regions tests flaky
[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     // Resize the window to original size. This is needed after calls to window.resizeTo.
568     WKRect rect = m_mainWebView->windowFrame();
569     m_mainWebView->setWindowFrame(WKRectMake(rect.origin.x, rect.origin.y, 800, 600));
570
571     // Reset notification permissions
572     m_webNotificationProvider.reset();
573
574     // Reset Geolocation permissions.
575     m_geolocationPermissionRequests.clear();
576     m_isGeolocationPermissionSet = false;
577     m_isGeolocationPermissionAllowed = false;
578
579     // Reset Custom Policy Delegate.
580     setCustomPolicyDelegate(false, false);
581
582     m_workQueueManager.clearWorkQueue();
583
584     // Reset main page back to about:blank
585     m_doneResetting = false;
586
587     WKPageLoadURL(m_mainWebView->page(), blankURL());
588     runUntil(m_doneResetting, ShortTimeout);
589     return m_doneResetting;
590 }
591
592 struct TestCommand {
593     TestCommand() : shouldDumpPixels(false) { }
594
595     std::string pathOrURL;
596     bool shouldDumpPixels;
597     std::string expectedPixelHash;
598 };
599
600 class CommandTokenizer {
601 public:
602     explicit CommandTokenizer(const std::string& input)
603         : m_input(input)
604         , m_posNextSeparator(0)
605     {
606         pump();
607     }
608
609     bool hasNext() const;
610     std::string next();
611
612 private:
613     void pump();
614     static const char kSeparator = '\'';
615     const std::string& m_input;
616     std::string m_next;
617     size_t m_posNextSeparator;
618 };
619
620 void CommandTokenizer::pump()
621 {
622     if (m_posNextSeparator == std::string::npos || m_posNextSeparator == m_input.size()) {
623         m_next = std::string();
624         return;
625     }
626     size_t start = m_posNextSeparator ? m_posNextSeparator + 1 : 0;
627     m_posNextSeparator = m_input.find(kSeparator, start);
628     size_t size = m_posNextSeparator == std::string::npos ? std::string::npos : m_posNextSeparator - start;
629     m_next = std::string(m_input, start, size);
630 }
631
632 std::string CommandTokenizer::next()
633 {
634     ASSERT(hasNext());
635
636     std::string oldNext = m_next;
637     pump();
638     return oldNext;
639 }
640
641 bool CommandTokenizer::hasNext() const
642 {
643     return !m_next.empty();
644 }
645
646 NO_RETURN static void die(const std::string& inputLine)
647 {
648     fprintf(stderr, "Unexpected input line: %s\n", inputLine.c_str());
649     exit(1);
650 }
651
652 TestCommand parseInputLine(const std::string& inputLine)
653 {
654     TestCommand result;
655     CommandTokenizer tokenizer(inputLine);
656     if (!tokenizer.hasNext())
657         die(inputLine);
658
659     result.pathOrURL = tokenizer.next();
660     if (!tokenizer.hasNext())
661         return result;
662
663     std::string arg = tokenizer.next();
664     if (arg != std::string("-p") && arg != std::string("--pixel-test"))
665         die(inputLine);
666     result.shouldDumpPixels = true;
667
668     if (tokenizer.hasNext())
669         result.expectedPixelHash = tokenizer.next();
670
671     return result;
672 }
673
674 bool TestController::runTest(const char* inputLine)
675 {
676     TestCommand command = parseInputLine(std::string(inputLine));
677
678     m_state = RunningTest;
679
680     m_currentInvocation = adoptPtr(new TestInvocation(command.pathOrURL));
681     if (command.shouldDumpPixels || m_shouldDumpPixelsForAllTests)
682         m_currentInvocation->setIsPixelTest(command.expectedPixelHash);
683
684     m_currentInvocation->invoke();
685     m_currentInvocation.clear();
686
687     return true;
688 }
689
690 void TestController::runTestingServerLoop()
691 {
692     char filenameBuffer[2048];
693     while (fgets(filenameBuffer, sizeof(filenameBuffer), stdin)) {
694         char* newLineCharacter = strchr(filenameBuffer, '\n');
695         if (newLineCharacter)
696             *newLineCharacter = '\0';
697
698         if (strlen(filenameBuffer) == 0)
699             continue;
700
701         if (!runTest(filenameBuffer))
702             break;
703     }
704 }
705
706 void TestController::run()
707 {
708     if (!resetStateToConsistentValues()) {
709         m_currentInvocation->dumpWebProcessUnresponsiveness();
710         return;
711     }
712
713     if (m_usingServerMode)
714         runTestingServerLoop();
715     else {
716         for (size_t i = 0; i < m_paths.size(); ++i) {
717             if (!runTest(m_paths[i].c_str()))
718                 break;
719         }
720     }
721 }
722
723 void TestController::runUntil(bool& done, TimeoutDuration timeoutDuration)
724 {
725     double timeout = m_noTimeout;
726     if (!m_forceNoTimeout) {
727         switch (timeoutDuration) {
728         case ShortTimeout:
729             timeout = m_shortTimeout;
730             break;
731         case LongTimeout:
732             timeout = m_longTimeout;
733             break;
734         case NoTimeout:
735         default:
736             timeout = m_noTimeout;
737             break;
738         }
739     }
740
741     platformRunUntil(done, timeout);
742 }
743
744 // WKContextInjectedBundleClient
745
746 void TestController::didReceiveMessageFromInjectedBundle(WKContextRef context, WKStringRef messageName, WKTypeRef messageBody, const void* clientInfo)
747 {
748     static_cast<TestController*>(const_cast<void*>(clientInfo))->didReceiveMessageFromInjectedBundle(messageName, messageBody);
749 }
750
751 void TestController::didReceiveSynchronousMessageFromInjectedBundle(WKContextRef context, WKStringRef messageName, WKTypeRef messageBody, WKTypeRef* returnData, const void* clientInfo)
752 {
753     *returnData = static_cast<TestController*>(const_cast<void*>(clientInfo))->didReceiveSynchronousMessageFromInjectedBundle(messageName, messageBody).leakRef();
754 }
755
756 void TestController::didReceiveMessageFromInjectedBundle(WKStringRef messageName, WKTypeRef messageBody)
757 {
758 #if PLATFORM(MAC) || PLATFORM(QT) || PLATFORM(GTK) || PLATFORM(EFL)
759     if (WKStringIsEqualToUTF8CString(messageName, "EventSender")) {
760         ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID());
761         WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody);
762
763         WKRetainPtr<WKStringRef> subMessageKey(AdoptWK, WKStringCreateWithUTF8CString("SubMessage"));
764         WKStringRef subMessageName = static_cast<WKStringRef>(WKDictionaryGetItemForKey(messageBodyDictionary, subMessageKey.get()));
765
766         if (WKStringIsEqualToUTF8CString(subMessageName, "MouseDown") || WKStringIsEqualToUTF8CString(subMessageName, "MouseUp")) {
767             WKRetainPtr<WKStringRef> buttonKey = adoptWK(WKStringCreateWithUTF8CString("Button"));
768             unsigned button = static_cast<unsigned>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, buttonKey.get()))));
769
770             WKRetainPtr<WKStringRef> modifiersKey = adoptWK(WKStringCreateWithUTF8CString("Modifiers"));
771             WKEventModifiers modifiers = static_cast<WKEventModifiers>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, modifiersKey.get()))));
772
773             // Forward to WebProcess
774             WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false);
775             if (WKStringIsEqualToUTF8CString(subMessageName, "MouseDown"))
776                 m_eventSenderProxy->mouseDown(button, modifiers);
777             else
778                 m_eventSenderProxy->mouseUp(button, modifiers);
779
780             return;
781         }
782         ASSERT_NOT_REACHED();
783     }
784 #endif
785
786     if (!m_currentInvocation)
787         return;
788
789     m_currentInvocation->didReceiveMessageFromInjectedBundle(messageName, messageBody);
790 }
791
792 WKRetainPtr<WKTypeRef> TestController::didReceiveSynchronousMessageFromInjectedBundle(WKStringRef messageName, WKTypeRef messageBody)
793 {
794 #if PLATFORM(MAC) || PLATFORM(QT) || PLATFORM(GTK) || PLATFORM(EFL)
795     if (WKStringIsEqualToUTF8CString(messageName, "EventSender")) {
796         ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID());
797         WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody);
798
799         WKRetainPtr<WKStringRef> subMessageKey(AdoptWK, WKStringCreateWithUTF8CString("SubMessage"));
800         WKStringRef subMessageName = static_cast<WKStringRef>(WKDictionaryGetItemForKey(messageBodyDictionary, subMessageKey.get()));
801
802         if (WKStringIsEqualToUTF8CString(subMessageName, "KeyDown")) {
803             WKRetainPtr<WKStringRef> keyKey = adoptWK(WKStringCreateWithUTF8CString("Key"));
804             WKStringRef key = static_cast<WKStringRef>(WKDictionaryGetItemForKey(messageBodyDictionary, keyKey.get()));
805
806             WKRetainPtr<WKStringRef> modifiersKey = adoptWK(WKStringCreateWithUTF8CString("Modifiers"));
807             WKEventModifiers modifiers = static_cast<WKEventModifiers>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, modifiersKey.get()))));
808
809             WKRetainPtr<WKStringRef> locationKey = adoptWK(WKStringCreateWithUTF8CString("Location"));
810             unsigned location = static_cast<unsigned>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, locationKey.get()))));
811
812             // Forward to WebProcess
813             WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), true);
814             m_eventSenderProxy->keyDown(key, modifiers, location);
815             WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false);
816             return 0;
817         }
818
819         if (WKStringIsEqualToUTF8CString(subMessageName, "MouseDown") || WKStringIsEqualToUTF8CString(subMessageName, "MouseUp")) {
820             WKRetainPtr<WKStringRef> buttonKey = adoptWK(WKStringCreateWithUTF8CString("Button"));
821             unsigned button = static_cast<unsigned>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, buttonKey.get()))));
822
823             WKRetainPtr<WKStringRef> modifiersKey = adoptWK(WKStringCreateWithUTF8CString("Modifiers"));
824             WKEventModifiers modifiers = static_cast<WKEventModifiers>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, modifiersKey.get()))));
825
826             // Forward to WebProcess
827             WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), true);
828             if (WKStringIsEqualToUTF8CString(subMessageName, "MouseDown"))
829                 m_eventSenderProxy->mouseDown(button, modifiers);
830             else
831                 m_eventSenderProxy->mouseUp(button, modifiers);
832             WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false);
833             return 0;
834         }
835
836         if (WKStringIsEqualToUTF8CString(subMessageName, "MouseMoveTo")) {
837             WKRetainPtr<WKStringRef> xKey = adoptWK(WKStringCreateWithUTF8CString("X"));
838             double x = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, xKey.get())));
839
840             WKRetainPtr<WKStringRef> yKey = adoptWK(WKStringCreateWithUTF8CString("Y"));
841             double y = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, yKey.get())));
842
843             // Forward to WebProcess
844             WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), true);
845             m_eventSenderProxy->mouseMoveTo(x, y);
846             WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false);
847             return 0;
848         }
849
850         if (WKStringIsEqualToUTF8CString(subMessageName, "MouseScrollBy")) {
851             WKRetainPtr<WKStringRef> xKey = adoptWK(WKStringCreateWithUTF8CString("X"));
852             double x = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, xKey.get())));
853
854             WKRetainPtr<WKStringRef> yKey = adoptWK(WKStringCreateWithUTF8CString("Y"));
855             double y = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, yKey.get())));
856
857             // Forward to WebProcess
858             WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), true);
859             m_eventSenderProxy->mouseScrollBy(x, y);
860             WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false);
861             return 0;
862         }
863
864         if (WKStringIsEqualToUTF8CString(subMessageName, "ContinuousMouseScrollBy")) {
865             WKRetainPtr<WKStringRef> xKey = adoptWK(WKStringCreateWithUTF8CString("X"));
866             double x = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, xKey.get())));
867
868             WKRetainPtr<WKStringRef> yKey = adoptWK(WKStringCreateWithUTF8CString("Y"));
869             double y = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, yKey.get())));
870
871             WKRetainPtr<WKStringRef> pagedKey = adoptWK(WKStringCreateWithUTF8CString("Paged"));
872             bool paged = static_cast<bool>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, pagedKey.get()))));
873
874             // Forward to WebProcess
875             WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), true);
876             m_eventSenderProxy->continuousMouseScrollBy(x, y, paged);
877             WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false);
878             return 0;
879         }
880
881         if (WKStringIsEqualToUTF8CString(subMessageName, "LeapForward")) {
882             WKRetainPtr<WKStringRef> timeKey = adoptWK(WKStringCreateWithUTF8CString("TimeInMilliseconds"));
883             unsigned time = static_cast<unsigned>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, timeKey.get()))));
884
885             m_eventSenderProxy->leapForward(time);
886             return 0;
887         }
888
889 #if ENABLE(TOUCH_EVENTS)
890         if (WKStringIsEqualToUTF8CString(subMessageName, "AddTouchPoint")) {
891             WKRetainPtr<WKStringRef> xKey = adoptWK(WKStringCreateWithUTF8CString("X"));
892             int x = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, xKey.get()))));
893
894             WKRetainPtr<WKStringRef> yKey = adoptWK(WKStringCreateWithUTF8CString("Y"));
895             int y = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, yKey.get()))));
896
897             m_eventSenderProxy->addTouchPoint(x, y);
898             return 0;
899         }
900
901         if (WKStringIsEqualToUTF8CString(subMessageName, "UpdateTouchPoint")) {
902             WKRetainPtr<WKStringRef> indexKey = adoptWK(WKStringCreateWithUTF8CString("Index"));
903             int index = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, indexKey.get()))));
904
905             WKRetainPtr<WKStringRef> xKey = adoptWK(WKStringCreateWithUTF8CString("X"));
906             int x = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, xKey.get()))));
907
908             WKRetainPtr<WKStringRef> yKey = adoptWK(WKStringCreateWithUTF8CString("Y"));
909             int y = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, yKey.get()))));
910
911             m_eventSenderProxy->updateTouchPoint(index, x, y);
912             return 0;
913         }
914
915         if (WKStringIsEqualToUTF8CString(subMessageName, "SetTouchModifier")) {
916             WKRetainPtr<WKStringRef> modifierKey = adoptWK(WKStringCreateWithUTF8CString("Modifier"));
917             WKEventModifiers modifier = static_cast<WKEventModifiers>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, modifierKey.get()))));
918
919             WKRetainPtr<WKStringRef> enableKey = adoptWK(WKStringCreateWithUTF8CString("Enable"));
920             bool enable = static_cast<bool>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, enableKey.get()))));
921
922             m_eventSenderProxy->setTouchModifier(modifier, enable);
923             return 0;
924         }
925
926         if (WKStringIsEqualToUTF8CString(subMessageName, "SetTouchPointRadius")) {
927             WKRetainPtr<WKStringRef> xKey = adoptWK(WKStringCreateWithUTF8CString("RadiusX"));
928             int x = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, xKey.get()))));
929
930             WKRetainPtr<WKStringRef> yKey = adoptWK(WKStringCreateWithUTF8CString("RadiusY"));
931             int y = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, yKey.get()))));
932
933             m_eventSenderProxy->setTouchPointRadius(x, y);
934             return 0;
935         }
936
937         if (WKStringIsEqualToUTF8CString(subMessageName, "TouchStart")) {
938             WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), true);
939             m_eventSenderProxy->touchStart();
940             WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false);
941             return 0;
942         }
943
944         if (WKStringIsEqualToUTF8CString(subMessageName, "TouchMove")) {
945             WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), true);
946             m_eventSenderProxy->touchMove();
947             WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false);
948             return 0;
949         }
950
951         if (WKStringIsEqualToUTF8CString(subMessageName, "TouchEnd")) {
952             WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), true);
953             m_eventSenderProxy->touchEnd();
954             WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false);
955             return 0;
956         }
957
958         if (WKStringIsEqualToUTF8CString(subMessageName, "TouchCancel")) {
959             WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), true);
960             m_eventSenderProxy->touchCancel();
961             WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false);
962             return 0;
963         }
964
965         if (WKStringIsEqualToUTF8CString(subMessageName, "ClearTouchPoints")) {
966             m_eventSenderProxy->clearTouchPoints();
967             return 0;
968         }
969
970         if (WKStringIsEqualToUTF8CString(subMessageName, "ReleaseTouchPoint")) {
971             WKRetainPtr<WKStringRef> indexKey = adoptWK(WKStringCreateWithUTF8CString("Index"));
972             int index = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, indexKey.get()))));
973             m_eventSenderProxy->releaseTouchPoint(index);
974             return 0;
975         }
976
977         if (WKStringIsEqualToUTF8CString(subMessageName, "CancelTouchPoint")) {
978             WKRetainPtr<WKStringRef> indexKey = adoptWK(WKStringCreateWithUTF8CString("Index"));
979             int index = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, indexKey.get()))));
980             m_eventSenderProxy->cancelTouchPoint(index);
981             return 0;
982         }
983 #endif
984         ASSERT_NOT_REACHED();
985     }
986 #endif
987     return m_currentInvocation->didReceiveSynchronousMessageFromInjectedBundle(messageName, messageBody);
988 }
989
990 // WKPageLoaderClient
991
992 void TestController::didCommitLoadForFrame(WKPageRef page, WKFrameRef frame, WKTypeRef, const void* clientInfo)
993 {
994     static_cast<TestController*>(const_cast<void*>(clientInfo))->didCommitLoadForFrame(page, frame);
995 }
996
997 void TestController::didFinishLoadForFrame(WKPageRef page, WKFrameRef frame, WKTypeRef, const void* clientInfo)
998 {
999     static_cast<TestController*>(const_cast<void*>(clientInfo))->didFinishLoadForFrame(page, frame);
1000 }
1001
1002 void TestController::processDidCrash(WKPageRef page, const void* clientInfo)
1003 {
1004     static_cast<TestController*>(const_cast<void*>(clientInfo))->processDidCrash();
1005 }
1006
1007 void TestController::didCommitLoadForFrame(WKPageRef page, WKFrameRef frame)
1008 {
1009     if (!WKFrameIsMainFrame(frame))
1010         return;
1011
1012     mainWebView()->focus();
1013 }
1014
1015 void TestController::didFinishLoadForFrame(WKPageRef page, WKFrameRef frame)
1016 {
1017     if (m_state != Resetting)
1018         return;
1019
1020     if (!WKFrameIsMainFrame(frame))
1021         return;
1022
1023     WKRetainPtr<WKURLRef> wkURL(AdoptWK, WKFrameCopyURL(frame));
1024     if (!WKURLIsEqual(wkURL.get(), blankURL()))
1025         return;
1026
1027     m_doneResetting = true;
1028     shared().notifyDone();
1029 }
1030
1031 void TestController::processDidCrash()
1032 {
1033     // This function can be called multiple times when crash logs are being saved on Windows, so
1034     // ensure we only print the crashed message once.
1035     if (!m_didPrintWebProcessCrashedMessage) {
1036 #if PLATFORM(MAC)
1037         pid_t pid = WKPageGetProcessIdentifier(m_mainWebView->page());
1038         fprintf(stderr, "#CRASHED - WebProcess (pid %ld)\n", static_cast<long>(pid));
1039 #else
1040         fputs("#CRASHED - WebProcess\n", stderr);
1041 #endif
1042         fflush(stderr);
1043         m_didPrintWebProcessCrashedMessage = true;
1044     }
1045
1046     if (m_shouldExitWhenWebProcessCrashes)
1047         exit(1);
1048 }
1049
1050 void TestController::simulateWebNotificationClick(uint64_t notificationID)
1051 {
1052     m_webNotificationProvider.simulateWebNotificationClick(notificationID);
1053 }
1054
1055 void TestController::setGeolocationPermission(bool enabled)
1056 {
1057     m_isGeolocationPermissionSet = true;
1058     m_isGeolocationPermissionAllowed = enabled;
1059     decidePolicyForGeolocationPermissionRequestIfPossible();
1060 }
1061
1062 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)
1063 {
1064     m_geolocationProvider->setPosition(latitude, longitude, accuracy, providesAltitude, altitude, providesAltitudeAccuracy, altitudeAccuracy, providesHeading, heading, providesSpeed, speed);
1065 }
1066
1067 void TestController::setMockGeolocationPositionUnavailableError(WKStringRef errorMessage)
1068 {
1069     m_geolocationProvider->setPositionUnavailableError(errorMessage);
1070 }
1071
1072 void TestController::handleGeolocationPermissionRequest(WKGeolocationPermissionRequestRef geolocationPermissionRequest)
1073 {
1074     m_geolocationPermissionRequests.append(geolocationPermissionRequest);
1075     decidePolicyForGeolocationPermissionRequestIfPossible();
1076 }
1077
1078 void TestController::setCustomPolicyDelegate(bool enabled, bool permissive)
1079 {
1080     m_policyDelegateEnabled = enabled;
1081     m_policyDelegatePermissive = permissive;
1082 }
1083
1084 void TestController::decidePolicyForGeolocationPermissionRequestIfPossible()
1085 {
1086     if (!m_isGeolocationPermissionSet)
1087         return;
1088
1089     for (size_t i = 0; i < m_geolocationPermissionRequests.size(); ++i) {
1090         WKGeolocationPermissionRequestRef permissionRequest = m_geolocationPermissionRequests[i].get();
1091         if (m_isGeolocationPermissionAllowed)
1092             WKGeolocationPermissionRequestAllow(permissionRequest);
1093         else
1094             WKGeolocationPermissionRequestDeny(permissionRequest);
1095     }
1096     m_geolocationPermissionRequests.clear();
1097 }
1098
1099 void TestController::decidePolicyForNotificationPermissionRequest(WKPageRef page, WKSecurityOriginRef origin, WKNotificationPermissionRequestRef request, const void*)
1100 {
1101     TestController::shared().decidePolicyForNotificationPermissionRequest(page, origin, request);
1102 }
1103
1104 void TestController::decidePolicyForNotificationPermissionRequest(WKPageRef, WKSecurityOriginRef, WKNotificationPermissionRequestRef request)
1105 {
1106     WKNotificationPermissionRequestAllow(request);
1107 }
1108
1109 void TestController::decidePolicyForNavigationAction(WKPageRef, WKFrameRef, WKFrameNavigationType, WKEventModifiers, WKEventMouseButton, WKURLRequestRef, WKFramePolicyListenerRef listener, WKTypeRef, const void* clientInfo)
1110 {
1111     static_cast<TestController*>(const_cast<void*>(clientInfo))->decidePolicyForNavigationAction(listener);
1112 }
1113
1114 void TestController::decidePolicyForNavigationAction(WKFramePolicyListenerRef listener)
1115 {
1116     if (m_policyDelegateEnabled && !m_policyDelegatePermissive) {
1117         WKFramePolicyListenerIgnore(listener);
1118         return;
1119     }
1120
1121     WKFramePolicyListenerUse(listener);
1122 }
1123
1124 void TestController::decidePolicyForResponse(WKPageRef, WKFrameRef frame, WKURLResponseRef response, WKURLRequestRef, WKFramePolicyListenerRef listener, WKTypeRef, const void* clientInfo)
1125 {
1126     static_cast<TestController*>(const_cast<void*>(clientInfo))->decidePolicyForResponse(frame, response, listener);
1127 }
1128
1129 void TestController::decidePolicyForResponse(WKFrameRef frame, WKURLResponseRef response, WKFramePolicyListenerRef listener)
1130 {
1131     // Even though Response was already checked by WKBundlePagePolicyClient, the check did not include plugins
1132     // so we have to re-check again.
1133     WKRetainPtr<WKStringRef> wkMIMEType(AdoptWK, WKURLResponseCopyMIMEType(response));
1134     if (WKFrameCanShowMIMEType(frame, wkMIMEType.get())) {
1135         WKFramePolicyListenerUse(listener);
1136         return;
1137     }
1138
1139     WKFramePolicyListenerIgnore(listener);
1140 }
1141
1142 } // namespace WTR