2 * Copyright (C) 2010, 2014 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
27 #include "TestController.h"
29 #include "EventSenderProxy.h"
31 #include "PlatformWebView.h"
32 #include "StringFunctions.h"
33 #include "TestInvocation.h"
34 #include <WebKit2/WKAuthenticationChallenge.h>
35 #include <WebKit2/WKAuthenticationDecisionListener.h>
36 #include <WebKit2/WKContextPrivate.h>
37 #include <WebKit2/WKCredential.h>
38 #include <WebKit2/WKIconDatabase.h>
39 #include <WebKit2/WKNotification.h>
40 #include <WebKit2/WKNotificationManager.h>
41 #include <WebKit2/WKNotificationPermissionRequest.h>
42 #include <WebKit2/WKNumber.h>
43 #include <WebKit2/WKPageGroup.h>
44 #include <WebKit2/WKPagePrivate.h>
45 #include <WebKit2/WKPreferencesRefPrivate.h>
46 #include <WebKit2/WKRetainPtr.h>
52 #include <wtf/PassOwnPtr.h>
53 #include <wtf/text/CString.h>
56 #include <WebKit2/WKPagePrivateMac.h>
60 #include <WebKit2/WKTextChecker.h>
65 const unsigned TestController::viewWidth = 800;
66 const unsigned TestController::viewHeight = 600;
68 const unsigned TestController::w3cSVGViewWidth = 480;
69 const unsigned TestController::w3cSVGViewHeight = 360;
71 // defaultLongTimeout + defaultShortTimeout should be less than 80,
72 // the default timeout value of the test harness so we can detect an
73 // unresponsive web process.
74 static const double defaultLongTimeout = 60;
75 static const double defaultShortTimeout = 15;
76 static const double defaultNoTimeout = -1;
78 static WKURLRef blankURL()
80 static WKURLRef staticBlankURL = WKURLCreateWithUTF8CString("about:blank");
81 return staticBlankURL;
84 static WKDataRef copyWebCryptoMasterKey(WKContextRef, const void*)
86 // Any 128 bit key would do, all we need for testing is to implement the callback.
87 return WKDataCreate((const uint8_t*)"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", 16);
90 static TestController* controller;
92 TestController& TestController::shared()
98 TestController::TestController(int argc, const char* argv[])
100 , m_printSeparators(false)
101 , m_usingServerMode(false)
102 , m_gcBetweenTests(false)
103 , m_shouldDumpPixelsForAllTests(false)
105 , m_doneResetting(false)
106 , m_longTimeout(defaultLongTimeout)
107 , m_shortTimeout(defaultShortTimeout)
108 , m_noTimeout(defaultNoTimeout)
109 , m_useWaitToDumpWatchdogTimer(true)
110 , m_forceNoTimeout(false)
112 , m_didPrintWebProcessCrashedMessage(false)
113 , m_shouldExitWhenWebProcessCrashes(true)
114 , m_beforeUnloadReturnValue(true)
115 , m_isGeolocationPermissionSet(false)
116 , m_isGeolocationPermissionAllowed(false)
117 , m_policyDelegateEnabled(false)
118 , m_policyDelegatePermissive(false)
119 , m_handlesAuthenticationChallenges(false)
120 , m_shouldBlockAllPlugins(false)
121 , m_forceComplexText(false)
122 , m_shouldUseAcceleratedDrawing(false)
123 , m_shouldUseRemoteLayerTree(false)
124 , m_shouldLogHistoryClientCallbacks(false)
128 int infd = open("/tmp/WebKitTestRunner_IN", O_RDWR);
129 dup2(infd, STDIN_FILENO);
130 int outfd = open("/tmp/WebKitTestRunner_OUT", O_RDWR);
131 dup2(outfd, STDOUT_FILENO);
132 int errfd = open("/tmp/WebKitTestRunner_ERROR", O_RDWR | O_NONBLOCK);
133 dup2(errfd, STDERR_FILENO);
136 initialize(argc, argv);
142 TestController::~TestController()
144 WKIconDatabaseClose(WKContextGetIconDatabase(m_context.get()));
149 static WKRect getWindowFrame(WKPageRef page, const void* clientInfo)
151 PlatformWebView* view = static_cast<PlatformWebView*>(const_cast<void*>(clientInfo));
152 return view->windowFrame();
155 static void setWindowFrame(WKPageRef page, WKRect frame, const void* clientInfo)
157 PlatformWebView* view = static_cast<PlatformWebView*>(const_cast<void*>(clientInfo));
158 view->setWindowFrame(frame);
161 static bool runBeforeUnloadConfirmPanel(WKPageRef page, WKStringRef message, WKFrameRef frame, const void*)
163 printf("CONFIRM NAVIGATION: %s\n", toSTD(message).c_str());
164 return TestController::shared().beforeUnloadReturnValue();
167 void TestController::runModal(WKPageRef page, const void* clientInfo)
169 PlatformWebView* view = static_cast<PlatformWebView*>(const_cast<void*>(clientInfo));
170 view->setWindowIsKey(false);
172 view->setWindowIsKey(true);
175 static void closeOtherPage(WKPageRef page, const void* clientInfo)
178 PlatformWebView* view = static_cast<PlatformWebView*>(const_cast<void*>(clientInfo));
182 static void focus(WKPageRef page, const void* clientInfo)
184 PlatformWebView* view = static_cast<PlatformWebView*>(const_cast<void*>(clientInfo));
186 view->setWindowIsKey(true);
189 static void unfocus(WKPageRef page, const void* clientInfo)
191 PlatformWebView* view = static_cast<PlatformWebView*>(const_cast<void*>(clientInfo));
192 view->setWindowIsKey(false);
195 static void decidePolicyForGeolocationPermissionRequest(WKPageRef, WKFrameRef, WKSecurityOriginRef, WKGeolocationPermissionRequestRef permissionRequest, const void* clientInfo)
197 TestController::shared().handleGeolocationPermissionRequest(permissionRequest);
200 int TestController::getCustomTimeout()
205 WKPageRef TestController::createOtherPage(WKPageRef oldPage, WKURLRequestRef, WKDictionaryRef, WKEventModifiers, WKEventMouseButton, const void* clientInfo)
207 PlatformWebView* parentView = static_cast<PlatformWebView*>(const_cast<void*>(clientInfo));
209 PlatformWebView* view = new PlatformWebView(WKPageGetContext(oldPage), WKPageGetPageGroup(oldPage), oldPage, parentView->options());
210 WKPageRef newPage = view->page();
212 view->resizeTo(800, 600);
214 WKPageUIClientV2 otherPageUIClient = {
216 0, // createNewPage_deprecatedForUseWithV0
222 0, // runJavaScriptAlert
223 0, // runJavaScriptConfirm
224 0, // runJavaScriptPrompt
226 0, // mouseDidMoveOverElement_deprecatedForUseWithV0
227 0, // missingPluginButtonClicked
228 0, // didNotHandleKeyEvent
229 0, // didNotHandleWheelEvent
230 0, // toolbarsAreVisible
231 0, // setToolbarsAreVisible
232 0, // menuBarIsVisible
233 0, // setMenuBarIsVisible
234 0, // statusBarIsVisible
235 0, // setStatusBarIsVisible
240 runBeforeUnloadConfirmPanel,
243 0, // exceededDatabaseQuota
245 decidePolicyForGeolocationPermissionRequest,
252 0, // didCompleteRubberBandForMainFrame
253 0, // saveDataToFileInDownloadsFolder
254 0, // shouldInterruptJavaScript
256 0, // mouseDidMoveOverElement
257 0, // decidePolicyForNotificationPermissionRequest
258 0, // unavailablePluginButtonClicked_deprecatedForUseWithV1
259 0, // showColorPicker
260 0, // hideColorPicker
261 0, // unavailablePluginButtonClicked
263 WKPageSetPageUIClient(newPage, &otherPageUIClient.base);
265 view->didInitializeClients();
271 const char* TestController::libraryPathForTesting()
273 // FIXME: This may not be sufficient to prevent interactions/crashes
274 // when running more than one copy of DumpRenderTree.
275 // See https://bugs.webkit.org/show_bug.cgi?id=10906
276 char* dumpRenderTreeTemp = getenv("DUMPRENDERTREE_TEMP");
277 if (dumpRenderTreeTemp)
278 return dumpRenderTreeTemp;
279 return platformLibraryPathForTesting();
283 void TestController::initialize(int argc, const char* argv[])
285 platformInitialize();
287 Options options(defaultLongTimeout, defaultShortTimeout);
288 OptionsHandler optionsHandler(options);
291 optionsHandler.printHelp();
294 if (!optionsHandler.parse(argc, argv))
297 m_longTimeout = options.longTimeout;
298 m_shortTimeout = options.shortTimeout;
299 m_useWaitToDumpWatchdogTimer = options.useWaitToDumpWatchdogTimer;
300 m_forceNoTimeout = options.forceNoTimeout;
301 m_verbose = options.verbose;
302 m_gcBetweenTests = options.gcBetweenTests;
303 m_shouldDumpPixelsForAllTests = options.shouldDumpPixelsForAllTests;
304 m_forceComplexText = options.forceComplexText;
305 m_shouldUseAcceleratedDrawing = options.shouldUseAcceleratedDrawing;
306 m_shouldUseRemoteLayerTree = options.shouldUseRemoteLayerTree;
307 m_paths = options.paths;
309 if (options.printSupportedFeatures) {
310 // FIXME: On Windows, DumpRenderTree uses this to expose whether it supports 3d
311 // transforms and accelerated compositing. When we support those features, we
312 // should match DRT's behavior.
316 m_usingServerMode = (m_paths.size() == 1 && m_paths[0] == "-");
317 if (m_usingServerMode)
318 m_printSeparators = true;
320 m_printSeparators = m_paths.size() > 1;
322 initializeInjectedBundlePath();
323 initializeTestPluginDirectory();
325 WKRetainPtr<WKStringRef> pageGroupIdentifier(AdoptWK, WKStringCreateWithUTF8CString("WebKitTestRunnerPageGroup"));
326 m_pageGroup.adopt(WKPageGroupCreateWithIdentifier(pageGroupIdentifier.get()));
328 m_context.adopt(WKContextCreateWithInjectedBundlePath(injectedBundlePath()));
329 m_geolocationProvider = adoptPtr(new GeolocationProviderMock(m_context.get()));
331 #if PLATFORM(IOS) || (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED > 1080)
332 WKContextSetUsesNetworkProcess(m_context.get(), true);
333 WKContextSetProcessModel(m_context.get(), kWKProcessModelMultipleSecondaryProcesses);
336 if (const char* dumpRenderTreeTemp = libraryPathForTesting()) {
337 String temporaryFolder = String::fromUTF8(dumpRenderTreeTemp);
339 // WebCore::pathByAppendingComponent is not used here because of the namespace,
340 // which leads us to this ugly #ifdef and file path concatenation.
341 const char separator = '/';
343 WKContextSetApplicationCacheDirectory(m_context.get(), toWK(temporaryFolder + separator + "ApplicationCache").get());
344 WKContextSetDatabaseDirectory(m_context.get(), toWK(temporaryFolder + separator + "Databases").get());
345 WKContextSetLocalStorageDirectory(m_context.get(), toWK(temporaryFolder + separator + "LocalStorage").get());
346 WKContextSetDiskCacheDirectory(m_context.get(), toWK(temporaryFolder + separator + "Cache").get());
347 WKContextSetCookieStorageDirectory(m_context.get(), toWK(temporaryFolder + separator + "Cookies").get());
348 WKContextSetIconDatabasePath(m_context.get(), toWK(temporaryFolder + separator + "IconDatabase" + separator + "WebpageIcons.db").get());
351 WKContextUseTestingNetworkSession(m_context.get());
352 WKContextSetCacheModel(m_context.get(), kWKCacheModelDocumentBrowser);
354 platformInitializeContext();
356 WKContextClientV1 contextClient = {
358 nullptr, // plugInAutoStartOriginHashesChanged
359 nullptr, // networkProcessDidCrash,
360 nullptr, // plugInInformationBecameAvailable,
361 copyWebCryptoMasterKey
363 WKContextSetClient(m_context.get(), &contextClient.base);
365 WKContextInjectedBundleClientV1 injectedBundleClient = {
367 didReceiveMessageFromInjectedBundle,
368 didReceiveSynchronousMessageFromInjectedBundle,
369 0 // getInjectedBundleInitializationUserData
371 WKContextSetInjectedBundleClient(m_context.get(), &injectedBundleClient.base);
373 WKContextHistoryClientV0 historyClient = {
375 didNavigateWithNavigationData,
376 didPerformClientRedirect,
377 didPerformServerRedirect,
378 didUpdateHistoryTitle,
379 0, // populateVisitedLinks
381 WKContextSetHistoryClient(m_context.get(), &historyClient.base);
383 WKNotificationManagerRef notificationManager = WKContextGetNotificationManager(m_context.get());
384 WKNotificationProviderV0 notificationKit = m_webNotificationProvider.provider();
385 WKNotificationManagerSetProvider(notificationManager, ¬ificationKit.base);
387 if (testPluginDirectory())
388 WKContextSetAdditionalPluginsDirectory(m_context.get(), testPluginDirectory());
390 if (m_forceComplexText)
391 WKContextSetAlwaysUsesComplexTextCodePath(m_context.get(), true);
393 // Some preferences (notably mock scroll bars setting) currently cannot be re-applied to an existing view, so we need to set them now.
394 resetPreferencesToConsistentValues();
396 WKRetainPtr<WKMutableDictionaryRef> viewOptions;
397 if (m_shouldUseRemoteLayerTree) {
398 viewOptions = adoptWK(WKMutableDictionaryCreate());
399 WKRetainPtr<WKStringRef> useRemoteLayerTreeKey = adoptWK(WKStringCreateWithUTF8CString("RemoteLayerTree"));
400 WKRetainPtr<WKBooleanRef> useRemoteLayerTreeValue = adoptWK(WKBooleanCreate(m_shouldUseRemoteLayerTree));
401 WKDictionarySetItem(viewOptions.get(), useRemoteLayerTreeKey.get(), useRemoteLayerTreeValue.get());
404 createWebViewWithOptions(viewOptions.get());
407 void TestController::createWebViewWithOptions(WKDictionaryRef options)
409 m_mainWebView = adoptPtr(new PlatformWebView(m_context.get(), m_pageGroup.get(), 0, options));
410 WKPageUIClientV2 pageUIClient = {
411 { 2, m_mainWebView.get() },
412 0, // createNewPage_deprecatedForUseWithV0
418 0, // runJavaScriptAlert
419 0, // runJavaScriptConfirm
420 0, // runJavaScriptPrompt
422 0, // mouseDidMoveOverElement_deprecatedForUseWithV0
423 0, // missingPluginButtonClicked
424 0, // didNotHandleKeyEvent
425 0, // didNotHandleWheelEvent
426 0, // toolbarsAreVisible
427 0, // setToolbarsAreVisible
428 0, // menuBarIsVisible
429 0, // setMenuBarIsVisible
430 0, // statusBarIsVisible
431 0, // setStatusBarIsVisible
436 runBeforeUnloadConfirmPanel,
439 0, // exceededDatabaseQuota,
441 decidePolicyForGeolocationPermissionRequest,
448 0, // didCompleteRubberBandForMainFrame
449 0, // saveDataToFileInDownloadsFolder
450 0, // shouldInterruptJavaScript
452 0, // mouseDidMoveOverElement
453 decidePolicyForNotificationPermissionRequest, // decidePolicyForNotificationPermissionRequest
454 0, // unavailablePluginButtonClicked_deprecatedForUseWithV1
455 0, // showColorPicker
456 0, // hideColorPicker
457 unavailablePluginButtonClicked,
459 WKPageSetPageUIClient(m_mainWebView->page(), &pageUIClient.base);
461 WKPageLoaderClientV4 pageLoaderClient = {
463 0, // didStartProvisionalLoadForFrame
464 0, // didReceiveServerRedirectForProvisionalLoadForFrame
465 0, // didFailProvisionalLoadWithErrorForFrame
466 didCommitLoadForFrame,
467 0, // didFinishDocumentLoadForFrame
468 didFinishLoadForFrame,
469 0, // didFailLoadWithErrorForFrame
470 0, // didSameDocumentNavigationForFrame
471 0, // didReceiveTitleForFrame
472 0, // didFirstLayoutForFrame
473 0, // didFirstVisuallyNonEmptyLayoutForFrame
474 0, // didRemoveFrameFromHierarchy
475 0, // didFailToInitializePlugin
476 0, // didDisplayInsecureContentForFrame
477 0, // canAuthenticateAgainstProtectionSpaceInFrame
478 didReceiveAuthenticationChallengeInFrame, // didReceiveAuthenticationChallengeInFrame
479 0, // didStartProgress
480 0, // didChangeProgress
481 0, // didFinishProgress
482 0, // didBecomeUnresponsive
483 0, // didBecomeResponsive
485 0, // didChangeBackForwardList
486 0, // shouldGoToBackForwardListItem
487 0, // didRunInsecureContentForFrame
488 0, // didDetectXSSForFrame
489 0, // didNewFirstVisuallyNonEmptyLayout_unavailable
490 0, // willGoToBackForwardListItem
491 0, // interactionOccurredWhileProcessUnresponsive
492 0, // pluginDidFail_deprecatedForUseWithV1
493 0, // didReceiveIntentForFrame
494 0, // registerIntentServiceForFrame
496 0, // pluginLoadPolicy_deprecatedForUseWithV2
498 pluginLoadPolicy, // pluginLoadPolicy
499 0, // webGLLoadPolicy
500 0, // resolveWebGLLoadPolicy
502 WKPageSetPageLoaderClient(m_mainWebView->page(), &pageLoaderClient.base);
504 WKPagePolicyClientV1 pagePolicyClient = {
506 0, // decidePolicyForNavigationAction_deprecatedForUseWithV0
507 0, // decidePolicyForNewWindowAction
508 0, // decidePolicyForResponse_deprecatedForUseWithV0
509 0, // unableToImplementPolicy
510 decidePolicyForNavigationAction,
511 decidePolicyForResponse,
513 WKPageSetPagePolicyClient(m_mainWebView->page(), &pagePolicyClient.base);
515 m_mainWebView->didInitializeClients();
518 void TestController::ensureViewSupportsOptions(WKDictionaryRef options)
520 if (m_mainWebView && !m_mainWebView->viewSupportsOptions(options)) {
521 WKPageSetPageUIClient(m_mainWebView->page(), 0);
522 WKPageSetPageLoaderClient(m_mainWebView->page(), 0);
523 WKPageSetPagePolicyClient(m_mainWebView->page(), 0);
524 WKPageClose(m_mainWebView->page());
526 m_mainWebView = nullptr;
528 createWebViewWithOptions(options);
529 resetStateToConsistentValues();
533 void TestController::resetPreferencesToConsistentValues()
536 WKPreferencesRef preferences = WKPageGroupGetPreferences(m_pageGroup.get());
537 WKPreferencesResetTestRunnerOverrides(preferences);
538 WKPreferencesSetOfflineWebApplicationCacheEnabled(preferences, true);
539 WKPreferencesSetFontSmoothingLevel(preferences, kWKFontSmoothingLevelNoSubpixelAntiAliasing);
540 WKPreferencesSetXSSAuditorEnabled(preferences, false);
541 WKPreferencesSetWebAudioEnabled(preferences, true);
542 WKPreferencesSetDeveloperExtrasEnabled(preferences, true);
543 WKPreferencesSetJavaScriptExperimentsEnabled(preferences, true);
544 WKPreferencesSetJavaScriptCanOpenWindowsAutomatically(preferences, true);
545 WKPreferencesSetJavaScriptCanAccessClipboard(preferences, true);
546 WKPreferencesSetDOMPasteAllowed(preferences, true);
547 WKPreferencesSetUniversalAccessFromFileURLsAllowed(preferences, true);
548 WKPreferencesSetFileAccessFromFileURLsAllowed(preferences, true);
549 #if ENABLE(FULLSCREEN_API)
550 WKPreferencesSetFullScreenEnabled(preferences, true);
552 WKPreferencesSetPageCacheEnabled(preferences, false);
553 WKPreferencesSetAsynchronousPluginInitializationEnabled(preferences, false);
554 WKPreferencesSetAsynchronousPluginInitializationEnabledForAllPlugins(preferences, false);
555 WKPreferencesSetArtificialPluginInitializationDelayEnabled(preferences, false);
556 WKPreferencesSetTabToLinksEnabled(preferences, false);
557 WKPreferencesSetInteractiveFormValidationEnabled(preferences, true);
558 WKPreferencesSetMockScrollbarsEnabled(preferences, true);
560 static WKStringRef standardFontFamily = WKStringCreateWithUTF8CString("Times");
561 static WKStringRef cursiveFontFamily = WKStringCreateWithUTF8CString("Apple Chancery");
562 static WKStringRef fantasyFontFamily = WKStringCreateWithUTF8CString("Papyrus");
563 static WKStringRef fixedFontFamily = WKStringCreateWithUTF8CString("Courier");
564 static WKStringRef pictographFontFamily = WKStringCreateWithUTF8CString("Apple Color Emoji");
565 static WKStringRef sansSerifFontFamily = WKStringCreateWithUTF8CString("Helvetica");
566 static WKStringRef serifFontFamily = WKStringCreateWithUTF8CString("Times");
568 WKPreferencesSetStandardFontFamily(preferences, standardFontFamily);
569 WKPreferencesSetCursiveFontFamily(preferences, cursiveFontFamily);
570 WKPreferencesSetFantasyFontFamily(preferences, fantasyFontFamily);
571 WKPreferencesSetFixedFontFamily(preferences, fixedFontFamily);
572 WKPreferencesSetPictographFontFamily(preferences, pictographFontFamily);
573 WKPreferencesSetSansSerifFontFamily(preferences, sansSerifFontFamily);
574 WKPreferencesSetSerifFontFamily(preferences, serifFontFamily);
575 WKPreferencesSetScreenFontSubstitutionEnabled(preferences, true);
576 WKPreferencesSetAsynchronousSpellCheckingEnabled(preferences, false);
577 #if ENABLE(WEB_AUDIO)
578 WKPreferencesSetMediaSourceEnabled(preferences, true);
581 WKPreferencesSetAcceleratedDrawingEnabled(preferences, m_shouldUseAcceleratedDrawing);
584 bool TestController::resetStateToConsistentValues()
588 m_beforeUnloadReturnValue = true;
590 WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("Reset"));
591 WKRetainPtr<WKMutableDictionaryRef> resetMessageBody = adoptWK(WKMutableDictionaryCreate());
593 WKRetainPtr<WKStringRef> shouldGCKey = adoptWK(WKStringCreateWithUTF8CString("ShouldGC"));
594 WKRetainPtr<WKBooleanRef> shouldGCValue = adoptWK(WKBooleanCreate(m_gcBetweenTests));
595 WKDictionarySetItem(resetMessageBody.get(), shouldGCKey.get(), shouldGCValue.get());
597 WKContextPostMessageToInjectedBundle(TestController::shared().context(), messageName.get(), resetMessageBody.get());
599 WKContextSetShouldUseFontSmoothing(TestController::shared().context(), false);
601 WKContextSetCacheModel(TestController::shared().context(), kWKCacheModelDocumentBrowser);
603 // FIXME: This function should also ensure that there is only one page open.
605 // Reset the EventSender for each test.
606 m_eventSenderProxy = adoptPtr(new EventSenderProxy(this));
608 // FIXME: Is this needed? Nothing in TestController changes preferences during tests, and if there is
609 // some other code doing this, it should probably be responsible for cleanup too.
610 resetPreferencesToConsistentValues();
613 WKTextCheckerContinuousSpellCheckingEnabledStateChanged(true);
616 // in the case that a test using the chrome input field failed, be sure to clean up for the next test
617 m_mainWebView->removeChromeInputField();
618 m_mainWebView->focus();
620 // Re-set to the default backing scale factor by setting the custom scale factor to 0.
621 WKPageSetCustomBackingScaleFactor(m_mainWebView->page(), 0);
624 // EFL use a real window while other ports such as Qt don't.
625 // In EFL, we need to resize the window to the original size after calls to window.resizeTo.
626 WKRect rect = m_mainWebView->windowFrame();
627 m_mainWebView->setWindowFrame(WKRectMake(rect.origin.x, rect.origin.y, TestController::viewWidth, TestController::viewHeight));
630 // Reset notification permissions
631 m_webNotificationProvider.reset();
633 // Reset Geolocation permissions.
634 m_geolocationPermissionRequests.clear();
635 m_isGeolocationPermissionSet = false;
636 m_isGeolocationPermissionAllowed = false;
638 // Reset Custom Policy Delegate.
639 setCustomPolicyDelegate(false, false);
641 m_workQueueManager.clearWorkQueue();
643 m_handlesAuthenticationChallenges = false;
644 m_authenticationUsername = String();
645 m_authenticationPassword = String();
647 m_shouldBlockAllPlugins = false;
649 m_shouldLogHistoryClientCallbacks = false;
651 // Reset main page back to about:blank
652 m_doneResetting = false;
654 WKPageLoadURL(m_mainWebView->page(), blankURL());
655 runUntil(m_doneResetting, ShortTimeout);
656 return m_doneResetting;
660 TestCommand() : shouldDumpPixels(false), timeout(0) { }
662 std::string pathOrURL;
663 bool shouldDumpPixels;
664 std::string expectedPixelHash;
668 class CommandTokenizer {
670 explicit CommandTokenizer(const std::string& input)
672 , m_posNextSeparator(0)
677 bool hasNext() const;
682 static const char kSeparator = '\'';
683 const std::string& m_input;
685 size_t m_posNextSeparator;
688 void CommandTokenizer::pump()
690 if (m_posNextSeparator == std::string::npos || m_posNextSeparator == m_input.size()) {
691 m_next = std::string();
694 size_t start = m_posNextSeparator ? m_posNextSeparator + 1 : 0;
695 m_posNextSeparator = m_input.find(kSeparator, start);
696 size_t size = m_posNextSeparator == std::string::npos ? std::string::npos : m_posNextSeparator - start;
697 m_next = std::string(m_input, start, size);
700 std::string CommandTokenizer::next()
704 std::string oldNext = m_next;
709 bool CommandTokenizer::hasNext() const
711 return !m_next.empty();
714 NO_RETURN static void die(const std::string& inputLine)
716 fprintf(stderr, "Unexpected input line: %s\n", inputLine.c_str());
720 TestCommand parseInputLine(const std::string& inputLine)
723 CommandTokenizer tokenizer(inputLine);
724 if (!tokenizer.hasNext())
727 std::string arg = tokenizer.next();
728 result.pathOrURL = arg;
729 while (tokenizer.hasNext()) {
730 arg = tokenizer.next();
731 if (arg == std::string("--timeout")) {
732 std::string timeoutToken = tokenizer.next();
733 result.timeout = atoi(timeoutToken.c_str());
734 } else if (arg == std::string("-p") || arg == std::string("--pixel-test")) {
735 result.shouldDumpPixels = true;
736 if (tokenizer.hasNext())
737 result.expectedPixelHash = tokenizer.next();
744 bool TestController::runTest(const char* inputLine)
746 TestCommand command = parseInputLine(std::string(inputLine));
748 m_state = RunningTest;
750 m_currentInvocation = adoptPtr(new TestInvocation(command.pathOrURL));
751 if (command.shouldDumpPixels || m_shouldDumpPixelsForAllTests)
752 m_currentInvocation->setIsPixelTest(command.expectedPixelHash);
753 if (command.timeout > 0)
754 m_currentInvocation->setCustomTimeout(command.timeout);
756 m_currentInvocation->invoke();
757 m_currentInvocation.clear();
762 void TestController::runTestingServerLoop()
764 char filenameBuffer[2048];
765 while (fgets(filenameBuffer, sizeof(filenameBuffer), stdin)) {
766 char* newLineCharacter = strchr(filenameBuffer, '\n');
767 if (newLineCharacter)
768 *newLineCharacter = '\0';
770 if (strlen(filenameBuffer) == 0)
773 if (!runTest(filenameBuffer))
778 void TestController::run()
780 if (!resetStateToConsistentValues()) {
781 TestInvocation::dumpWebProcessUnresponsiveness("<unknown> - TestController::run - Failed to reset state to consistent values\n");
785 if (m_usingServerMode)
786 runTestingServerLoop();
788 for (size_t i = 0; i < m_paths.size(); ++i) {
789 if (!runTest(m_paths[i].c_str()))
795 void TestController::runUntil(bool& done, TimeoutDuration timeoutDuration)
797 double timeout = m_noTimeout;
798 if (!m_forceNoTimeout) {
799 switch (timeoutDuration) {
801 timeout = m_shortTimeout;
804 timeout = m_longTimeout;
811 timeout = m_noTimeout;
816 platformRunUntil(done, timeout);
819 // WKContextInjectedBundleClient
821 void TestController::didReceiveMessageFromInjectedBundle(WKContextRef context, WKStringRef messageName, WKTypeRef messageBody, const void* clientInfo)
823 static_cast<TestController*>(const_cast<void*>(clientInfo))->didReceiveMessageFromInjectedBundle(messageName, messageBody);
826 void TestController::didReceiveSynchronousMessageFromInjectedBundle(WKContextRef context, WKStringRef messageName, WKTypeRef messageBody, WKTypeRef* returnData, const void* clientInfo)
828 *returnData = static_cast<TestController*>(const_cast<void*>(clientInfo))->didReceiveSynchronousMessageFromInjectedBundle(messageName, messageBody).leakRef();
831 void TestController::didReceiveKeyDownMessageFromInjectedBundle(WKDictionaryRef messageBodyDictionary, bool synchronous)
833 WKRetainPtr<WKStringRef> keyKey = adoptWK(WKStringCreateWithUTF8CString("Key"));
834 WKStringRef key = static_cast<WKStringRef>(WKDictionaryGetItemForKey(messageBodyDictionary, keyKey.get()));
836 WKRetainPtr<WKStringRef> modifiersKey = adoptWK(WKStringCreateWithUTF8CString("Modifiers"));
837 WKEventModifiers modifiers = static_cast<WKEventModifiers>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, modifiersKey.get()))));
839 WKRetainPtr<WKStringRef> locationKey = adoptWK(WKStringCreateWithUTF8CString("Location"));
840 unsigned location = static_cast<unsigned>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, locationKey.get()))));
843 WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), true);
845 m_eventSenderProxy->keyDown(key, modifiers, location);
848 WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false);
851 void TestController::didReceiveMessageFromInjectedBundle(WKStringRef messageName, WKTypeRef messageBody)
853 if (WKStringIsEqualToUTF8CString(messageName, "EventSender")) {
854 ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID());
855 WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody);
857 WKRetainPtr<WKStringRef> subMessageKey(AdoptWK, WKStringCreateWithUTF8CString("SubMessage"));
858 WKStringRef subMessageName = static_cast<WKStringRef>(WKDictionaryGetItemForKey(messageBodyDictionary, subMessageKey.get()));
860 if (WKStringIsEqualToUTF8CString(subMessageName, "MouseDown") || WKStringIsEqualToUTF8CString(subMessageName, "MouseUp")) {
861 WKRetainPtr<WKStringRef> buttonKey = adoptWK(WKStringCreateWithUTF8CString("Button"));
862 unsigned button = static_cast<unsigned>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, buttonKey.get()))));
864 WKRetainPtr<WKStringRef> modifiersKey = adoptWK(WKStringCreateWithUTF8CString("Modifiers"));
865 WKEventModifiers modifiers = static_cast<WKEventModifiers>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, modifiersKey.get()))));
867 // Forward to WebProcess
868 WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false);
869 if (WKStringIsEqualToUTF8CString(subMessageName, "MouseDown"))
870 m_eventSenderProxy->mouseDown(button, modifiers);
872 m_eventSenderProxy->mouseUp(button, modifiers);
877 if (WKStringIsEqualToUTF8CString(subMessageName, "KeyDown")) {
878 didReceiveKeyDownMessageFromInjectedBundle(messageBodyDictionary, false);
883 if (WKStringIsEqualToUTF8CString(subMessageName, "MouseScrollByWithWheelAndMomentumPhases")) {
884 WKRetainPtr<WKStringRef> xKey = adoptWK(WKStringCreateWithUTF8CString("X"));
885 double x = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, xKey.get())));
887 WKRetainPtr<WKStringRef> yKey = adoptWK(WKStringCreateWithUTF8CString("Y"));
888 double y = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, yKey.get())));
890 WKRetainPtr<WKStringRef> phaseKey = adoptWK(WKStringCreateWithUTF8CString("Phase"));
891 int phase = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, phaseKey.get()))));
892 WKRetainPtr<WKStringRef> momentumKey = adoptWK(WKStringCreateWithUTF8CString("Momentum"));
893 int momentum = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, momentumKey.get()))));
895 // Forward to WebProcess
896 WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false);
897 m_eventSenderProxy->mouseScrollByWithWheelAndMomentumPhases(x, y, phase, momentum);
902 ASSERT_NOT_REACHED();
905 if (!m_currentInvocation)
908 m_currentInvocation->didReceiveMessageFromInjectedBundle(messageName, messageBody);
911 WKRetainPtr<WKTypeRef> TestController::didReceiveSynchronousMessageFromInjectedBundle(WKStringRef messageName, WKTypeRef messageBody)
913 if (WKStringIsEqualToUTF8CString(messageName, "EventSender")) {
914 ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID());
915 WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody);
917 WKRetainPtr<WKStringRef> subMessageKey(AdoptWK, WKStringCreateWithUTF8CString("SubMessage"));
918 WKStringRef subMessageName = static_cast<WKStringRef>(WKDictionaryGetItemForKey(messageBodyDictionary, subMessageKey.get()));
920 if (WKStringIsEqualToUTF8CString(subMessageName, "KeyDown")) {
921 didReceiveKeyDownMessageFromInjectedBundle(messageBodyDictionary, true);
926 if (WKStringIsEqualToUTF8CString(subMessageName, "MouseDown") || WKStringIsEqualToUTF8CString(subMessageName, "MouseUp")) {
927 WKRetainPtr<WKStringRef> buttonKey = adoptWK(WKStringCreateWithUTF8CString("Button"));
928 unsigned button = static_cast<unsigned>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, buttonKey.get()))));
930 WKRetainPtr<WKStringRef> modifiersKey = adoptWK(WKStringCreateWithUTF8CString("Modifiers"));
931 WKEventModifiers modifiers = static_cast<WKEventModifiers>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, modifiersKey.get()))));
933 // Forward to WebProcess
934 WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), true);
935 if (WKStringIsEqualToUTF8CString(subMessageName, "MouseDown"))
936 m_eventSenderProxy->mouseDown(button, modifiers);
938 m_eventSenderProxy->mouseUp(button, modifiers);
939 WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false);
943 if (WKStringIsEqualToUTF8CString(subMessageName, "MouseMoveTo")) {
944 WKRetainPtr<WKStringRef> xKey = adoptWK(WKStringCreateWithUTF8CString("X"));
945 double x = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, xKey.get())));
947 WKRetainPtr<WKStringRef> yKey = adoptWK(WKStringCreateWithUTF8CString("Y"));
948 double y = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, yKey.get())));
950 // Forward to WebProcess
951 WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), true);
952 m_eventSenderProxy->mouseMoveTo(x, y);
953 WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false);
957 if (WKStringIsEqualToUTF8CString(subMessageName, "MouseScrollBy")) {
958 WKRetainPtr<WKStringRef> xKey = adoptWK(WKStringCreateWithUTF8CString("X"));
959 double x = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, xKey.get())));
961 WKRetainPtr<WKStringRef> yKey = adoptWK(WKStringCreateWithUTF8CString("Y"));
962 double y = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, yKey.get())));
964 // Forward to WebProcess
965 WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), true);
966 m_eventSenderProxy->mouseScrollBy(x, y);
967 WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false);
971 if (WKStringIsEqualToUTF8CString(subMessageName, "MouseScrollByWithWheelAndMomentumPhases")) {
972 WKRetainPtr<WKStringRef> xKey = adoptWK(WKStringCreateWithUTF8CString("X"));
973 double x = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, xKey.get())));
975 WKRetainPtr<WKStringRef> yKey = adoptWK(WKStringCreateWithUTF8CString("Y"));
976 double y = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, yKey.get())));
978 WKRetainPtr<WKStringRef> phaseKey = adoptWK(WKStringCreateWithUTF8CString("Phase"));
979 int phase = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, phaseKey.get()))));
980 WKRetainPtr<WKStringRef> momentumKey = adoptWK(WKStringCreateWithUTF8CString("Momentum"));
981 int momentum = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, momentumKey.get()))));
983 // Forward to WebProcess
984 WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), true);
985 m_eventSenderProxy->mouseScrollByWithWheelAndMomentumPhases(x, y, phase, momentum);
986 WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false);
990 if (WKStringIsEqualToUTF8CString(subMessageName, "ContinuousMouseScrollBy")) {
991 WKRetainPtr<WKStringRef> xKey = adoptWK(WKStringCreateWithUTF8CString("X"));
992 double x = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, xKey.get())));
994 WKRetainPtr<WKStringRef> yKey = adoptWK(WKStringCreateWithUTF8CString("Y"));
995 double y = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, yKey.get())));
997 WKRetainPtr<WKStringRef> pagedKey = adoptWK(WKStringCreateWithUTF8CString("Paged"));
998 bool paged = static_cast<bool>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, pagedKey.get()))));
1000 // Forward to WebProcess
1001 WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), true);
1002 m_eventSenderProxy->continuousMouseScrollBy(x, y, paged);
1003 WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false);
1007 if (WKStringIsEqualToUTF8CString(subMessageName, "LeapForward")) {
1008 WKRetainPtr<WKStringRef> timeKey = adoptWK(WKStringCreateWithUTF8CString("TimeInMilliseconds"));
1009 unsigned time = static_cast<unsigned>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, timeKey.get()))));
1011 m_eventSenderProxy->leapForward(time);
1015 #if ENABLE(TOUCH_EVENTS)
1016 if (WKStringIsEqualToUTF8CString(subMessageName, "AddTouchPoint")) {
1017 WKRetainPtr<WKStringRef> xKey = adoptWK(WKStringCreateWithUTF8CString("X"));
1018 int x = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, xKey.get()))));
1020 WKRetainPtr<WKStringRef> yKey = adoptWK(WKStringCreateWithUTF8CString("Y"));
1021 int y = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, yKey.get()))));
1023 m_eventSenderProxy->addTouchPoint(x, y);
1027 if (WKStringIsEqualToUTF8CString(subMessageName, "UpdateTouchPoint")) {
1028 WKRetainPtr<WKStringRef> indexKey = adoptWK(WKStringCreateWithUTF8CString("Index"));
1029 int index = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, indexKey.get()))));
1031 WKRetainPtr<WKStringRef> xKey = adoptWK(WKStringCreateWithUTF8CString("X"));
1032 int x = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, xKey.get()))));
1034 WKRetainPtr<WKStringRef> yKey = adoptWK(WKStringCreateWithUTF8CString("Y"));
1035 int y = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, yKey.get()))));
1037 m_eventSenderProxy->updateTouchPoint(index, x, y);
1041 if (WKStringIsEqualToUTF8CString(subMessageName, "SetTouchModifier")) {
1042 WKRetainPtr<WKStringRef> modifierKey = adoptWK(WKStringCreateWithUTF8CString("Modifier"));
1043 WKEventModifiers modifier = static_cast<WKEventModifiers>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, modifierKey.get()))));
1045 WKRetainPtr<WKStringRef> enableKey = adoptWK(WKStringCreateWithUTF8CString("Enable"));
1046 bool enable = static_cast<bool>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, enableKey.get()))));
1048 m_eventSenderProxy->setTouchModifier(modifier, enable);
1052 if (WKStringIsEqualToUTF8CString(subMessageName, "SetTouchPointRadius")) {
1053 WKRetainPtr<WKStringRef> xKey = adoptWK(WKStringCreateWithUTF8CString("RadiusX"));
1054 int x = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, xKey.get()))));
1056 WKRetainPtr<WKStringRef> yKey = adoptWK(WKStringCreateWithUTF8CString("RadiusY"));
1057 int y = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, yKey.get()))));
1059 m_eventSenderProxy->setTouchPointRadius(x, y);
1063 if (WKStringIsEqualToUTF8CString(subMessageName, "TouchStart")) {
1064 WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), true);
1065 m_eventSenderProxy->touchStart();
1066 WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false);
1070 if (WKStringIsEqualToUTF8CString(subMessageName, "TouchMove")) {
1071 WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), true);
1072 m_eventSenderProxy->touchMove();
1073 WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false);
1077 if (WKStringIsEqualToUTF8CString(subMessageName, "TouchEnd")) {
1078 WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), true);
1079 m_eventSenderProxy->touchEnd();
1080 WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false);
1084 if (WKStringIsEqualToUTF8CString(subMessageName, "TouchCancel")) {
1085 WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), true);
1086 m_eventSenderProxy->touchCancel();
1087 WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false);
1091 if (WKStringIsEqualToUTF8CString(subMessageName, "ClearTouchPoints")) {
1092 m_eventSenderProxy->clearTouchPoints();
1096 if (WKStringIsEqualToUTF8CString(subMessageName, "ReleaseTouchPoint")) {
1097 WKRetainPtr<WKStringRef> indexKey = adoptWK(WKStringCreateWithUTF8CString("Index"));
1098 int index = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, indexKey.get()))));
1099 m_eventSenderProxy->releaseTouchPoint(index);
1103 if (WKStringIsEqualToUTF8CString(subMessageName, "CancelTouchPoint")) {
1104 WKRetainPtr<WKStringRef> indexKey = adoptWK(WKStringCreateWithUTF8CString("Index"));
1105 int index = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, indexKey.get()))));
1106 m_eventSenderProxy->cancelTouchPoint(index);
1110 ASSERT_NOT_REACHED();
1112 return m_currentInvocation->didReceiveSynchronousMessageFromInjectedBundle(messageName, messageBody);
1115 // WKPageLoaderClient
1117 void TestController::didCommitLoadForFrame(WKPageRef page, WKFrameRef frame, WKTypeRef, const void* clientInfo)
1119 static_cast<TestController*>(const_cast<void*>(clientInfo))->didCommitLoadForFrame(page, frame);
1122 void TestController::didFinishLoadForFrame(WKPageRef page, WKFrameRef frame, WKTypeRef, const void* clientInfo)
1124 static_cast<TestController*>(const_cast<void*>(clientInfo))->didFinishLoadForFrame(page, frame);
1127 void TestController::didReceiveAuthenticationChallengeInFrame(WKPageRef page, WKFrameRef frame, WKAuthenticationChallengeRef authenticationChallenge, const void *clientInfo)
1129 static_cast<TestController*>(const_cast<void*>(clientInfo))->didReceiveAuthenticationChallengeInFrame(page, frame, authenticationChallenge);
1132 void TestController::processDidCrash(WKPageRef page, const void* clientInfo)
1134 static_cast<TestController*>(const_cast<void*>(clientInfo))->processDidCrash();
1137 WKPluginLoadPolicy TestController::pluginLoadPolicy(WKPageRef page, WKPluginLoadPolicy currentPluginLoadPolicy, WKDictionaryRef pluginInformation, WKStringRef* unavailabilityDescription, const void* clientInfo)
1139 return static_cast<TestController*>(const_cast<void*>(clientInfo))->pluginLoadPolicy(page, currentPluginLoadPolicy, pluginInformation, unavailabilityDescription);
1142 WKPluginLoadPolicy TestController::pluginLoadPolicy(WKPageRef, WKPluginLoadPolicy currentPluginLoadPolicy, WKDictionaryRef pluginInformation, WKStringRef* unavailabilityDescription)
1144 if (m_shouldBlockAllPlugins)
1145 return kWKPluginLoadPolicyBlocked;
1146 return currentPluginLoadPolicy;
1149 void TestController::didCommitLoadForFrame(WKPageRef page, WKFrameRef frame)
1151 if (!WKFrameIsMainFrame(frame))
1154 mainWebView()->focus();
1157 void TestController::didFinishLoadForFrame(WKPageRef page, WKFrameRef frame)
1159 if (m_state != Resetting)
1162 if (!WKFrameIsMainFrame(frame))
1165 WKRetainPtr<WKURLRef> wkURL(AdoptWK, WKFrameCopyURL(frame));
1166 if (!WKURLIsEqual(wkURL.get(), blankURL()))
1169 m_doneResetting = true;
1170 shared().notifyDone();
1173 void TestController::didReceiveAuthenticationChallengeInFrame(WKPageRef page, WKFrameRef frame, WKAuthenticationChallengeRef authenticationChallenge)
1176 if (!m_handlesAuthenticationChallenges)
1177 message = "<unknown> - didReceiveAuthenticationChallenge - Simulating cancelled authentication sheet\n";
1179 message = String::format("<unknown> - didReceiveAuthenticationChallenge - Responding with %s:%s\n", m_authenticationUsername.utf8().data(), m_authenticationPassword.utf8().data());
1180 m_currentInvocation->outputText(message);
1182 WKAuthenticationDecisionListenerRef decisionListener = WKAuthenticationChallengeGetDecisionListener(authenticationChallenge);
1183 if (!m_handlesAuthenticationChallenges) {
1184 WKAuthenticationDecisionListenerUseCredential(decisionListener, 0);
1187 WKRetainPtr<WKStringRef> username(AdoptWK, WKStringCreateWithUTF8CString(m_authenticationUsername.utf8().data()));
1188 WKRetainPtr<WKStringRef> password(AdoptWK, WKStringCreateWithUTF8CString(m_authenticationPassword.utf8().data()));
1189 WKRetainPtr<WKCredentialRef> credential(AdoptWK, WKCredentialCreate(username.get(), password.get(), kWKCredentialPersistenceForSession));
1190 WKAuthenticationDecisionListenerUseCredential(decisionListener, credential.get());
1193 void TestController::processDidCrash()
1195 // This function can be called multiple times when crash logs are being saved on Windows, so
1196 // ensure we only print the crashed message once.
1197 if (!m_didPrintWebProcessCrashedMessage) {
1199 pid_t pid = WKPageGetProcessIdentifier(m_mainWebView->page());
1200 fprintf(stderr, "#CRASHED - WebProcess (pid %ld)\n", static_cast<long>(pid));
1202 fputs("#CRASHED - WebProcess\n", stderr);
1205 m_didPrintWebProcessCrashedMessage = true;
1208 if (m_shouldExitWhenWebProcessCrashes)
1212 void TestController::simulateWebNotificationClick(uint64_t notificationID)
1214 m_webNotificationProvider.simulateWebNotificationClick(notificationID);
1217 void TestController::setGeolocationPermission(bool enabled)
1219 m_isGeolocationPermissionSet = true;
1220 m_isGeolocationPermissionAllowed = enabled;
1221 decidePolicyForGeolocationPermissionRequestIfPossible();
1224 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)
1226 m_geolocationProvider->setPosition(latitude, longitude, accuracy, providesAltitude, altitude, providesAltitudeAccuracy, altitudeAccuracy, providesHeading, heading, providesSpeed, speed);
1229 void TestController::setMockGeolocationPositionUnavailableError(WKStringRef errorMessage)
1231 m_geolocationProvider->setPositionUnavailableError(errorMessage);
1234 void TestController::handleGeolocationPermissionRequest(WKGeolocationPermissionRequestRef geolocationPermissionRequest)
1236 m_geolocationPermissionRequests.append(geolocationPermissionRequest);
1237 decidePolicyForGeolocationPermissionRequestIfPossible();
1240 void TestController::setCustomPolicyDelegate(bool enabled, bool permissive)
1242 m_policyDelegateEnabled = enabled;
1243 m_policyDelegatePermissive = permissive;
1246 void TestController::decidePolicyForGeolocationPermissionRequestIfPossible()
1248 if (!m_isGeolocationPermissionSet)
1251 for (size_t i = 0; i < m_geolocationPermissionRequests.size(); ++i) {
1252 WKGeolocationPermissionRequestRef permissionRequest = m_geolocationPermissionRequests[i].get();
1253 if (m_isGeolocationPermissionAllowed)
1254 WKGeolocationPermissionRequestAllow(permissionRequest);
1256 WKGeolocationPermissionRequestDeny(permissionRequest);
1258 m_geolocationPermissionRequests.clear();
1261 void TestController::decidePolicyForNotificationPermissionRequest(WKPageRef page, WKSecurityOriginRef origin, WKNotificationPermissionRequestRef request, const void*)
1263 TestController::shared().decidePolicyForNotificationPermissionRequest(page, origin, request);
1266 void TestController::decidePolicyForNotificationPermissionRequest(WKPageRef, WKSecurityOriginRef, WKNotificationPermissionRequestRef request)
1268 WKNotificationPermissionRequestAllow(request);
1271 void TestController::unavailablePluginButtonClicked(WKPageRef, WKPluginUnavailabilityReason, WKDictionaryRef, const void*)
1273 printf("MISSING PLUGIN BUTTON PRESSED\n");
1276 void TestController::decidePolicyForNavigationAction(WKPageRef, WKFrameRef, WKFrameNavigationType, WKEventModifiers, WKEventMouseButton, WKFrameRef, WKURLRequestRef, WKFramePolicyListenerRef listener, WKTypeRef, const void* clientInfo)
1278 static_cast<TestController*>(const_cast<void*>(clientInfo))->decidePolicyForNavigationAction(listener);
1281 void TestController::decidePolicyForNavigationAction(WKFramePolicyListenerRef listener)
1283 if (m_policyDelegateEnabled && !m_policyDelegatePermissive) {
1284 WKFramePolicyListenerIgnore(listener);
1288 WKFramePolicyListenerUse(listener);
1291 void TestController::decidePolicyForResponse(WKPageRef, WKFrameRef frame, WKURLResponseRef response, WKURLRequestRef, bool canShowMIMEType, WKFramePolicyListenerRef listener, WKTypeRef, const void* clientInfo)
1293 static_cast<TestController*>(const_cast<void*>(clientInfo))->decidePolicyForResponse(frame, response, listener);
1296 void TestController::decidePolicyForResponse(WKFrameRef frame, WKURLResponseRef response, WKFramePolicyListenerRef listener)
1298 // Even though Response was already checked by WKBundlePagePolicyClient, the check did not include plugins
1299 // so we have to re-check again.
1300 WKRetainPtr<WKStringRef> wkMIMEType(AdoptWK, WKURLResponseCopyMIMEType(response));
1301 if (WKFrameCanShowMIMEType(frame, wkMIMEType.get())) {
1302 WKFramePolicyListenerUse(listener);
1306 WKFramePolicyListenerIgnore(listener);
1309 void TestController::didNavigateWithNavigationData(WKContextRef, WKPageRef, WKNavigationDataRef navigationData, WKFrameRef frame, const void* clientInfo)
1311 static_cast<TestController*>(const_cast<void*>(clientInfo))->didNavigateWithNavigationData(navigationData, frame);
1314 void TestController::didNavigateWithNavigationData(WKNavigationDataRef navigationData, WKFrameRef)
1316 if (m_state != RunningTest)
1319 if (!m_shouldLogHistoryClientCallbacks)
1323 WKRetainPtr<WKURLRef> urlWK = adoptWK(WKNavigationDataCopyURL(navigationData));
1324 WKRetainPtr<WKStringRef> urlStringWK = adoptWK(WKURLCopyString(urlWK.get()));
1326 WKRetainPtr<WKStringRef> titleWK = adoptWK(WKNavigationDataCopyTitle(navigationData));
1328 WKRetainPtr<WKURLRequestRef> requestWK = adoptWK(WKNavigationDataCopyOriginalRequest(navigationData));
1329 WKRetainPtr<WKStringRef> methodWK = adoptWK(WKURLRequestCopyHTTPMethod(requestWK.get()));
1331 // FIXME: Determine whether the navigation was successful / a client redirect rather than hard-coding the message here.
1332 m_currentInvocation->outputText(String::format("WebView navigated to url \"%s\" with title \"%s\" with HTTP equivalent method \"%s\". The navigation was successful and was not a client redirect.\n",
1333 toSTD(urlStringWK).c_str(), toSTD(titleWK).c_str(), toSTD(methodWK).c_str()));
1336 void TestController::didPerformClientRedirect(WKContextRef, WKPageRef, WKURLRef sourceURL, WKURLRef destinationURL, WKFrameRef frame, const void* clientInfo)
1338 static_cast<TestController*>(const_cast<void*>(clientInfo))->didPerformClientRedirect(sourceURL, destinationURL, frame);
1341 void TestController::didPerformClientRedirect(WKURLRef sourceURL, WKURLRef destinationURL, WKFrameRef)
1343 if (m_state != RunningTest)
1346 if (!m_shouldLogHistoryClientCallbacks)
1349 WKRetainPtr<WKStringRef> sourceStringWK = adoptWK(WKURLCopyString(sourceURL));
1350 WKRetainPtr<WKStringRef> destinationStringWK = adoptWK(WKURLCopyString(destinationURL));
1352 m_currentInvocation->outputText(String::format("WebView performed a client redirect from \"%s\" to \"%s\".\n", toSTD(sourceStringWK).c_str(), toSTD(destinationStringWK).c_str()));
1355 void TestController::didPerformServerRedirect(WKContextRef, WKPageRef, WKURLRef sourceURL, WKURLRef destinationURL, WKFrameRef frame, const void* clientInfo)
1357 static_cast<TestController*>(const_cast<void*>(clientInfo))->didPerformServerRedirect(sourceURL, destinationURL, frame);
1360 void TestController::didPerformServerRedirect(WKURLRef sourceURL, WKURLRef destinationURL, WKFrameRef)
1362 if (m_state != RunningTest)
1365 if (!m_shouldLogHistoryClientCallbacks)
1368 WKRetainPtr<WKStringRef> sourceStringWK = adoptWK(WKURLCopyString(sourceURL));
1369 WKRetainPtr<WKStringRef> destinationStringWK = adoptWK(WKURLCopyString(destinationURL));
1371 m_currentInvocation->outputText(String::format("WebView performed a server redirect from \"%s\" to \"%s\".\n", toSTD(sourceStringWK).c_str(), toSTD(destinationStringWK).c_str()));
1374 void TestController::didUpdateHistoryTitle(WKContextRef, WKPageRef, WKStringRef title, WKURLRef URL, WKFrameRef frame, const void* clientInfo)
1376 static_cast<TestController*>(const_cast<void*>(clientInfo))->didUpdateHistoryTitle(title, URL, frame);
1379 void TestController::didUpdateHistoryTitle(WKStringRef title, WKURLRef URL, WKFrameRef)
1381 if (m_state != RunningTest)
1384 if (!m_shouldLogHistoryClientCallbacks)
1387 WKRetainPtr<WKStringRef> urlStringWK(AdoptWK, WKURLCopyString(URL));
1388 m_currentInvocation->outputText(String::format("WebView updated the title for history URL \"%s\" to \"%s\".\n", toSTD(urlStringWK).c_str(), toSTD(title).c_str()));