2 * Copyright (C) 2010 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 "PlatformWebView.h"
30 #include "StringFunctions.h"
31 #include "TestInvocation.h"
32 #include <WebKit2/WKContextPrivate.h>
33 #include <WebKit2/WKNumber.h>
34 #include <WebKit2/WKPageGroup.h>
35 #include <WebKit2/WKPagePrivate.h>
36 #include <WebKit2/WKPreferencesPrivate.h>
37 #include <WebKit2/WKRetainPtr.h>
39 #include <wtf/PassOwnPtr.h>
42 #include <WebKit2/WKPagePrivateMac.h>
45 #if PLATFORM(MAC) || PLATFORM(QT) || PLATFORM(GTK) || PLATFORM(EFL)
46 #include "EventSenderProxy.h"
50 #include <WebKit2/WKTextChecker.h>
53 #if ENABLE(TIZEN_WEBKIT2_EFL_WTR)
54 #include <WebKit2/WKPreferencesTizen.h>
59 static const double defaultLongTimeout = 30;
60 static const double defaultShortTimeout = 15;
61 static const double defaultNoTimeout = -1;
63 static WKURLRef blankURL()
65 static WKURLRef staticBlankURL = WKURLCreateWithUTF8CString("about:blank");
66 return staticBlankURL;
69 static TestController* controller;
71 TestController& TestController::shared()
77 TestController::TestController(int argc, const char* argv[])
78 : m_dumpPixelsForAllTests(false)
80 , m_printSeparators(false)
81 , m_usingServerMode(false)
82 , m_gcBetweenTests(false)
84 , m_doneResetting(false)
85 , m_longTimeout(defaultLongTimeout)
86 , m_shortTimeout(defaultShortTimeout)
87 , m_noTimeout(defaultNoTimeout)
88 , m_useWaitToDumpWatchdogTimer(true)
89 , m_forceNoTimeout(false)
90 , m_didPrintWebProcessCrashedMessage(false)
91 , m_shouldExitWhenWebProcessCrashes(true)
92 , m_beforeUnloadReturnValue(true)
93 #if PLATFORM(MAC) || PLATFORM(QT) || PLATFORM(GTK) || PLATFORM(EFL)
94 , m_eventSenderProxy(new EventSenderProxy(this))
97 initialize(argc, argv);
103 TestController::~TestController()
107 static WKRect getWindowFrameMainPage(WKPageRef page, const void* clientInfo)
109 PlatformWebView* view = static_cast<TestController*>(const_cast<void*>(clientInfo))->mainWebView();
110 return view->windowFrame();
113 static void setWindowFrameMainPage(WKPageRef page, WKRect frame, const void* clientInfo)
115 PlatformWebView* view = static_cast<TestController*>(const_cast<void*>(clientInfo))->mainWebView();
116 view->setWindowFrame(frame);
119 static WKRect getWindowFrameOtherPage(WKPageRef page, const void* clientInfo)
121 PlatformWebView* view = static_cast<PlatformWebView*>(const_cast<void*>(clientInfo));
122 return view->windowFrame();
125 static void setWindowFrameOtherPage(WKPageRef page, WKRect frame, const void* clientInfo)
127 PlatformWebView* view = static_cast<PlatformWebView*>(const_cast<void*>(clientInfo));
128 view->setWindowFrame(frame);
131 static bool runBeforeUnloadConfirmPanel(WKPageRef page, WKStringRef message, WKFrameRef frame, const void *clientInfo)
133 TestController* testController = static_cast<TestController*>(const_cast<void*>(clientInfo));
134 printf("CONFIRM NAVIGATION: %s\n", toSTD(message).c_str());
135 return testController->beforeUnloadReturnValue();
138 #if ENABLE(TIZEN_SQL_DATABASE)
139 static bool exceededDatabaseQuota(WKPageRef, WKFrameRef, WKSecurityOriginRef, WKStringRef, unsigned long long, const void*)
144 static unsigned long long exceededDatabaseQuota(WKPageRef, WKFrameRef, WKSecurityOriginRef, WKStringRef, WKStringRef, unsigned long long, unsigned long long, unsigned long long, unsigned long long, const void*)
146 static const unsigned long long defaultQuota = 5 * 1024 * 1024;
151 void TestController::runModal(WKPageRef page, const void* clientInfo)
153 PlatformWebView* view = static_cast<PlatformWebView*>(const_cast<void*>(clientInfo));
154 view->setWindowIsKey(false);
156 view->setWindowIsKey(true);
159 static void closeOtherPage(WKPageRef page, const void* clientInfo)
162 PlatformWebView* view = static_cast<PlatformWebView*>(const_cast<void*>(clientInfo));
166 static void focus(WKPageRef page, const void* clientInfo)
168 PlatformWebView* view = static_cast<PlatformWebView*>(const_cast<void*>(clientInfo));
169 view->setWindowIsKey(true);
172 static void unfocus(WKPageRef page, const void* clientInfo)
174 PlatformWebView* view = static_cast<PlatformWebView*>(const_cast<void*>(clientInfo));
175 view->setWindowIsKey(false);
178 WKPageRef TestController::createOtherPage(WKPageRef oldPage, WKURLRequestRef, WKDictionaryRef, WKEventModifiers, WKEventMouseButton, const void*)
180 PlatformWebView* view = new PlatformWebView(WKPageGetContext(oldPage), WKPageGetPageGroup(oldPage));
181 WKPageRef newPage = view->page();
183 view->resizeTo(800, 600);
185 WKPageUIClient otherPageUIClient = {
186 kWKPageUIClientCurrentVersion,
188 0, // createNewPage_deprecatedForUseWithV0
194 0, // runJavaScriptAlert
195 0, // runJavaScriptConfirm
196 0, // runJavaScriptPrompt
198 0, // mouseDidMoveOverElement_deprecatedForUseWithV0
199 0, // missingPluginButtonClicked
200 0, // didNotHandleKeyEvent
201 0, // didNotHandleWheelEvent
202 0, // toolbarsAreVisible
203 0, // setToolbarsAreVisible
204 0, // menuBarIsVisible
205 0, // setMenuBarIsVisible
206 0, // statusBarIsVisible
207 0, // setStatusBarIsVisible
210 getWindowFrameOtherPage,
211 setWindowFrameOtherPage,
212 runBeforeUnloadConfirmPanel,
215 exceededDatabaseQuota,
217 0, // decidePolicyForGeolocationPermissionRequest
224 0, // didCompleteRubberBandForMainFrame
225 0, // saveDataToFileInDownloadsFolder
226 0, // shouldInterruptJavaScript
228 0, // mouseDidMoveOverElement
229 0, // decidePolicyForNotificationPermissionRequest
230 0, // unavailablePluginButtonClicked
232 WKPageSetPageUIClient(newPage, &otherPageUIClient);
238 const char* TestController::libraryPathForTesting()
240 // FIXME: This may not be sufficient to prevent interactions/crashes
241 // when running more than one copy of DumpRenderTree.
242 // See https://bugs.webkit.org/show_bug.cgi?id=10906
243 char* dumpRenderTreeTemp = getenv("DUMPRENDERTREE_TEMP");
244 if (dumpRenderTreeTemp)
245 return dumpRenderTreeTemp;
246 return platformLibraryPathForTesting();
250 void TestController::initialize(int argc, const char* argv[])
252 platformInitialize();
255 fputs("Usage: WebKitTestRunner [options] filename [filename2..n]\n", stderr);
256 // FIXME: Refactor option parsing to allow us to print
257 // an auto-generated list of options.
261 bool printSupportedFeatures = false;
263 for (int i = 1; i < argc; ++i) {
264 std::string argument(argv[i]);
266 if (argument == "--timeout" && i + 1 < argc) {
267 m_longTimeout = atoi(argv[++i]);
268 // Scale up the short timeout to match.
269 m_shortTimeout = defaultShortTimeout * m_longTimeout / defaultLongTimeout;
273 if (argument == "--no-timeout") {
274 m_useWaitToDumpWatchdogTimer = false;
278 if (argument == "--no-timeout-at-all") {
279 m_useWaitToDumpWatchdogTimer = false;
280 m_forceNoTimeout = true;
284 if (argument == "--pixel-tests") {
285 m_dumpPixelsForAllTests = true;
288 if (argument == "--verbose") {
292 if (argument == "--gc-between-tests") {
293 m_gcBetweenTests = true;
296 if (argument == "--print-supported-features") {
297 printSupportedFeatures = true;
301 // Skip any other arguments that begin with '--'.
302 if (argument.length() >= 2 && argument[0] == '-' && argument[1] == '-')
305 m_paths.push_back(argument);
308 if (printSupportedFeatures) {
309 // FIXME: On Windows, DumpRenderTree uses this to expose whether it supports 3d
310 // transforms and accelerated compositing. When we support those features, we
311 // should match DRT's behavior.
315 m_usingServerMode = (m_paths.size() == 1 && m_paths[0] == "-");
316 if (m_usingServerMode)
317 m_printSeparators = true;
319 m_printSeparators = m_paths.size() > 1;
321 initializeInjectedBundlePath();
322 initializeTestPluginDirectory();
324 WKRetainPtr<WKStringRef> pageGroupIdentifier(AdoptWK, WKStringCreateWithUTF8CString("WebKitTestRunnerPageGroup"));
325 m_pageGroup.adopt(WKPageGroupCreateWithIdentifier(pageGroupIdentifier.get()));
327 m_context.adopt(WKContextCreateWithInjectedBundlePath(injectedBundlePath()));
329 const char* path = libraryPathForTesting();
331 Vector<char> databaseDirectory(strlen(path) + strlen("/Databases") + 1);
332 sprintf(databaseDirectory.data(), "%s%s", path, "/Databases");
333 WKRetainPtr<WKStringRef> databaseDirectoryWK(AdoptWK, WKStringCreateWithUTF8CString(databaseDirectory.data()));
334 WKContextSetDatabaseDirectory(m_context.get(), databaseDirectoryWK.get());
337 platformInitializeContext();
339 WKContextInjectedBundleClient injectedBundleClient = {
340 kWKContextInjectedBundleClientCurrentVersion,
342 didReceiveMessageFromInjectedBundle,
343 didReceiveSynchronousMessageFromInjectedBundle,
344 0 // getInjectedBundleInitializationUserData
346 WKContextSetInjectedBundleClient(m_context.get(), &injectedBundleClient);
348 if (testPluginDirectory())
349 WKContextSetAdditionalPluginsDirectory(m_context.get(), testPluginDirectory());
351 m_mainWebView = adoptPtr(new PlatformWebView(m_context.get(), m_pageGroup.get()));
353 WKPageUIClient pageUIClient = {
354 kWKPageUIClientCurrentVersion,
356 0, // createNewPage_deprecatedForUseWithV0
362 0, // runJavaScriptAlert
363 0, // runJavaScriptConfirm
364 0, // runJavaScriptPrompt
366 0, // mouseDidMoveOverElement_deprecatedForUseWithV0
367 0, // missingPluginButtonClicked
368 0, // didNotHandleKeyEvent
369 0, // didNotHandleWheelEvent
370 0, // toolbarsAreVisible
371 0, // setToolbarsAreVisible
372 0, // menuBarIsVisible
373 0, // setMenuBarIsVisible
374 0, // statusBarIsVisible
375 0, // setStatusBarIsVisible
378 getWindowFrameMainPage,
379 setWindowFrameMainPage,
380 runBeforeUnloadConfirmPanel,
383 exceededDatabaseQuota,
385 0, // decidePolicyForGeolocationPermissionRequest
392 0, // didCompleteRubberBandForMainFrame
393 0, // saveDataToFileInDownloadsFolder
394 0, // shouldInterruptJavaScript
396 0, // mouseDidMoveOverElement
397 0, // decidePolicyForNotificationPermissionRequest
398 0, // unavailablePluginButtonClicked
400 WKPageSetPageUIClient(m_mainWebView->page(), &pageUIClient);
402 WKPageLoaderClient pageLoaderClient = {
403 kWKPageLoaderClientCurrentVersion,
405 0, // didStartProvisionalLoadForFrame
406 0, // didReceiveServerRedirectForProvisionalLoadForFrame
407 0, // didFailProvisionalLoadWithErrorForFrame
408 didCommitLoadForFrame,
409 0, // didFinishDocumentLoadForFrame
410 didFinishLoadForFrame,
411 0, // didFailLoadWithErrorForFrame
412 0, // didSameDocumentNavigationForFrame
413 0, // didReceiveTitleForFrame
414 0, // didFirstLayoutForFrame
415 0, // didFirstVisuallyNonEmptyLayoutForFrame
416 0, // didRemoveFrameFromHierarchy
417 0, // didFailToInitializePlugin
418 0, // didDisplayInsecureContentForFrame
419 0, // canAuthenticateAgainstProtectionSpaceInFrame
420 0, // didReceiveAuthenticationChallengeInFrame
421 0, // didStartProgress
422 0, // didChangeProgress
423 0, // didFinishProgress
424 0, // didBecomeUnresponsive
425 0, // didBecomeResponsive
427 0, // didChangeBackForwardList
428 0, // shouldGoToBackForwardListItem
429 0, // didRunInsecureContentForFrame
430 0, // didDetectXSSForFrame
431 0, // didNewFirstVisuallyNonEmptyLayout
432 0, // willGoToBackForwardListItem
433 0, // interactionOccurredWhileProcessUnresponsive
435 0, // didReceiveIntentForFrame
436 0, // registerIntentServiceForFrame
438 WKPageSetPageLoaderClient(m_mainWebView->page(), &pageLoaderClient);
441 bool TestController::resetStateToConsistentValues()
445 m_beforeUnloadReturnValue = true;
447 WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("Reset"));
448 WKRetainPtr<WKMutableDictionaryRef> resetMessageBody = adoptWK(WKMutableDictionaryCreate());
450 WKRetainPtr<WKStringRef> shouldGCKey = adoptWK(WKStringCreateWithUTF8CString("ShouldGC"));
451 WKRetainPtr<WKBooleanRef> shouldGCValue = adoptWK(WKBooleanCreate(m_gcBetweenTests));
452 WKDictionaryAddItem(resetMessageBody.get(), shouldGCKey.get(), shouldGCValue.get());
454 WKContextPostMessageToInjectedBundle(TestController::shared().context(), messageName.get(), resetMessageBody.get());
456 WKContextSetShouldUseFontSmoothing(TestController::shared().context(), false);
458 WKContextSetCacheModel(TestController::shared().context(), kWKCacheModelDocumentBrowser);
460 // FIXME: This function should also ensure that there is only one page open.
463 WKPreferencesRef preferences = WKPageGroupGetPreferences(m_pageGroup.get());
464 WKPreferencesResetTestRunnerOverrides(preferences);
465 WKPreferencesSetOfflineWebApplicationCacheEnabled(preferences, true);
466 WKPreferencesSetFontSmoothingLevel(preferences, kWKFontSmoothingLevelNoSubpixelAntiAliasing);
467 WKPreferencesSetXSSAuditorEnabled(preferences, false);
468 WKPreferencesSetWebAudioEnabled(preferences, true);
469 WKPreferencesSetDeveloperExtrasEnabled(preferences, true);
470 WKPreferencesSetJavaScriptExperimentsEnabled(preferences, true);
471 WKPreferencesSetJavaScriptCanOpenWindowsAutomatically(preferences, true);
472 WKPreferencesSetJavaScriptCanAccessClipboard(preferences, true);
473 WKPreferencesSetDOMPasteAllowed(preferences, true);
474 WKPreferencesSetUniversalAccessFromFileURLsAllowed(preferences, true);
475 WKPreferencesSetFileAccessFromFileURLsAllowed(preferences, true);
476 #if ENABLE(FULLSCREEN_API)
477 WKPreferencesSetFullScreenEnabled(preferences, true);
479 WKPreferencesSetPageCacheEnabled(preferences, false);
481 // [Qt][WK2]REGRESSION(r104881):It broke hundreds of tests
482 // FIXME: https://bugs.webkit.org/show_bug.cgi?id=76247
484 WKPreferencesSetMockScrollbarsEnabled(preferences, true);
488 static WKStringRef standardFontFamily = WKStringCreateWithUTF8CString("Times");
489 static WKStringRef cursiveFontFamily = WKStringCreateWithUTF8CString("Apple Chancery");
490 static WKStringRef fantasyFontFamily = WKStringCreateWithUTF8CString("Papyrus");
491 static WKStringRef fixedFontFamily = WKStringCreateWithUTF8CString("Courier");
492 static WKStringRef pictographFontFamily = WKStringCreateWithUTF8CString("Apple Color Emoji");
493 static WKStringRef sansSerifFontFamily = WKStringCreateWithUTF8CString("Helvetica");
494 static WKStringRef serifFontFamily = WKStringCreateWithUTF8CString("Times");
496 WKPreferencesSetStandardFontFamily(preferences, standardFontFamily);
497 WKPreferencesSetCursiveFontFamily(preferences, cursiveFontFamily);
498 WKPreferencesSetFantasyFontFamily(preferences, fantasyFontFamily);
499 WKPreferencesSetFixedFontFamily(preferences, fixedFontFamily);
500 WKPreferencesSetPictographFontFamily(preferences, pictographFontFamily);
501 WKPreferencesSetSansSerifFontFamily(preferences, sansSerifFontFamily);
502 WKPreferencesSetSerifFontFamily(preferences, serifFontFamily);
504 WKPreferencesSetInspectorUsesWebKitUserInterface(preferences, true);
506 WKTextCheckerContinuousSpellCheckingEnabledStateChanged(true);
509 #if ENABLE(TIZEN_WEBKIT2_ASYNCHRONOUS_SPELLCHECKING)
510 WKPreferencesSetAsynchronousSpellCheckingEnabled(preferences, false);
513 #if ENABLE(TIZEN_WEBKIT2_EFL_WTR)
514 WKPreferencesSetEnableDefaultKeypad(preferences, false);
517 // in the case that a test using the chrome input field failed, be sure to clean up for the next test
518 m_mainWebView->removeChromeInputField();
519 m_mainWebView->focus();
521 // Re-set to the default backing scale factor by setting the custom scale factor to 0.
522 WKPageSetCustomBackingScaleFactor(m_mainWebView->page(), 0);
524 // Reset main page back to about:blank
525 m_doneResetting = false;
527 WKPageLoadURL(m_mainWebView->page(), blankURL());
528 runUntil(m_doneResetting, ShortTimeout);
529 return m_doneResetting;
532 bool TestController::runTest(const char* test)
534 if (!resetStateToConsistentValues()) {
536 pid_t pid = WKPageGetProcessIdentifier(m_mainWebView->page());
537 fprintf(stderr, "#PROCESS UNRESPONSIVE - WebProcess (pid %ld)\n", static_cast<long>(pid));
539 fputs("#PROCESS UNRESPONSIVE - WebProcess\n", stderr);
545 bool dumpPixelsTest = m_dumpPixelsForAllTests;
546 std::string command(test);
547 std::string pathOrURL = command;
548 std::string expectedPixelHash;
549 size_t firstSeparatorPos = command.find_first_of('\'');
550 size_t secondSeparatorPos = command.find_first_of('\'', firstSeparatorPos + 1);
551 if (firstSeparatorPos != std::string::npos) {
552 pathOrURL = std::string(command, 0, firstSeparatorPos);
553 size_t pixelHashPos = firstSeparatorPos + 1;
555 // NRWT passes --pixel-test if we should dump pixels for the test.
556 const std::string expectedPixelTestArg("--pixel-test");
557 std::string argTest = std::string(command, firstSeparatorPos + 1, expectedPixelTestArg.size());
558 if (argTest == expectedPixelTestArg) {
559 dumpPixelsTest = true;
560 pixelHashPos = secondSeparatorPos == std::string::npos ? std::string::npos : secondSeparatorPos + 1;
562 if (pixelHashPos != std::string::npos && pixelHashPos < command.size())
563 expectedPixelHash = std::string(command, pixelHashPos);
566 m_state = RunningTest;
568 m_currentInvocation = adoptPtr(new TestInvocation(pathOrURL));
570 m_currentInvocation->setIsPixelTest(expectedPixelHash);
572 m_currentInvocation->invoke();
573 m_currentInvocation.clear();
578 void TestController::runTestingServerLoop()
580 char filenameBuffer[2048];
581 while (fgets(filenameBuffer, sizeof(filenameBuffer), stdin)) {
582 char* newLineCharacter = strchr(filenameBuffer, '\n');
583 if (newLineCharacter)
584 *newLineCharacter = '\0';
586 if (strlen(filenameBuffer) == 0)
589 if (!runTest(filenameBuffer))
594 void TestController::run()
596 if (m_usingServerMode)
597 runTestingServerLoop();
599 for (size_t i = 0; i < m_paths.size(); ++i) {
600 if (!runTest(m_paths[i].c_str()))
606 void TestController::runUntil(bool& done, TimeoutDuration timeoutDuration)
608 double timeout = m_noTimeout;
609 if (!m_forceNoTimeout) {
610 switch (timeoutDuration) {
612 timeout = m_shortTimeout;
615 timeout = m_longTimeout;
619 timeout = m_noTimeout;
624 platformRunUntil(done, timeout);
627 // WKContextInjectedBundleClient
629 void TestController::didReceiveMessageFromInjectedBundle(WKContextRef context, WKStringRef messageName, WKTypeRef messageBody, const void* clientInfo)
631 static_cast<TestController*>(const_cast<void*>(clientInfo))->didReceiveMessageFromInjectedBundle(messageName, messageBody);
634 void TestController::didReceiveSynchronousMessageFromInjectedBundle(WKContextRef context, WKStringRef messageName, WKTypeRef messageBody, WKTypeRef* returnData, const void* clientInfo)
636 *returnData = static_cast<TestController*>(const_cast<void*>(clientInfo))->didReceiveSynchronousMessageFromInjectedBundle(messageName, messageBody).leakRef();
639 void TestController::didReceiveMessageFromInjectedBundle(WKStringRef messageName, WKTypeRef messageBody)
641 if (!m_currentInvocation)
643 m_currentInvocation->didReceiveMessageFromInjectedBundle(messageName, messageBody);
646 WKRetainPtr<WKTypeRef> TestController::didReceiveSynchronousMessageFromInjectedBundle(WKStringRef messageName, WKTypeRef messageBody)
648 #if PLATFORM(MAC) || PLATFORM(QT) || PLATFORM(GTK) || PLATFORM(EFL)
649 if (WKStringIsEqualToUTF8CString(messageName, "EventSender")) {
650 ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID());
651 WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody);
653 WKRetainPtr<WKStringRef> subMessageKey(AdoptWK, WKStringCreateWithUTF8CString("SubMessage"));
654 WKStringRef subMessageName = static_cast<WKStringRef>(WKDictionaryGetItemForKey(messageBodyDictionary, subMessageKey.get()));
656 if (WKStringIsEqualToUTF8CString(subMessageName, "KeyDown")) {
657 WKRetainPtr<WKStringRef> keyKey = adoptWK(WKStringCreateWithUTF8CString("Key"));
658 WKStringRef key = static_cast<WKStringRef>(WKDictionaryGetItemForKey(messageBodyDictionary, keyKey.get()));
660 WKRetainPtr<WKStringRef> modifiersKey = adoptWK(WKStringCreateWithUTF8CString("Modifiers"));
661 WKEventModifiers modifiers = static_cast<WKEventModifiers>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, modifiersKey.get()))));
663 WKRetainPtr<WKStringRef> locationKey = adoptWK(WKStringCreateWithUTF8CString("Location"));
664 unsigned location = static_cast<unsigned>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, locationKey.get()))));
666 // Forward to WebProcess
667 WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), true);
668 m_eventSenderProxy->keyDown(key, modifiers, location);
669 WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false);
673 if (WKStringIsEqualToUTF8CString(subMessageName, "MouseDown") || WKStringIsEqualToUTF8CString(subMessageName, "MouseUp")) {
674 WKRetainPtr<WKStringRef> buttonKey = adoptWK(WKStringCreateWithUTF8CString("Button"));
675 unsigned button = static_cast<unsigned>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, buttonKey.get()))));
677 WKRetainPtr<WKStringRef> modifiersKey = adoptWK(WKStringCreateWithUTF8CString("Modifiers"));
678 WKEventModifiers modifiers = static_cast<WKEventModifiers>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, modifiersKey.get()))));
680 // Forward to WebProcess
681 WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), true);
682 if (WKStringIsEqualToUTF8CString(subMessageName, "MouseDown"))
683 m_eventSenderProxy->mouseDown(button, modifiers);
685 m_eventSenderProxy->mouseUp(button, modifiers);
686 WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false);
690 if (WKStringIsEqualToUTF8CString(subMessageName, "MouseMoveTo")) {
691 WKRetainPtr<WKStringRef> xKey = adoptWK(WKStringCreateWithUTF8CString("X"));
692 double x = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, xKey.get())));
694 WKRetainPtr<WKStringRef> yKey = adoptWK(WKStringCreateWithUTF8CString("Y"));
695 double y = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, yKey.get())));
697 // Forward to WebProcess
698 WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), true);
699 m_eventSenderProxy->mouseMoveTo(x, y);
700 WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false);
704 if (WKStringIsEqualToUTF8CString(subMessageName, "MouseScrollBy")) {
705 WKRetainPtr<WKStringRef> xKey = adoptWK(WKStringCreateWithUTF8CString("X"));
706 double x = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, xKey.get())));
708 WKRetainPtr<WKStringRef> yKey = adoptWK(WKStringCreateWithUTF8CString("Y"));
709 double y = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, yKey.get())));
711 // Forward to WebProcess
712 WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), true);
713 m_eventSenderProxy->mouseScrollBy(x, y);
714 WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false);
718 if (WKStringIsEqualToUTF8CString(subMessageName, "LeapForward")) {
719 WKRetainPtr<WKStringRef> timeKey = adoptWK(WKStringCreateWithUTF8CString("TimeInMilliseconds"));
720 unsigned time = static_cast<unsigned>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, timeKey.get()))));
722 m_eventSenderProxy->leapForward(time);
726 #if ENABLE(TOUCH_EVENTS)
727 if (WKStringIsEqualToUTF8CString(subMessageName, "AddTouchPoint")) {
728 WKRetainPtr<WKStringRef> xKey = adoptWK(WKStringCreateWithUTF8CString("X"));
729 int x = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, xKey.get()))));
731 WKRetainPtr<WKStringRef> yKey = adoptWK(WKStringCreateWithUTF8CString("Y"));
732 int y = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, yKey.get()))));
734 m_eventSenderProxy->addTouchPoint(x, y);
738 if (WKStringIsEqualToUTF8CString(subMessageName, "UpdateTouchPoint")) {
739 WKRetainPtr<WKStringRef> indexKey = adoptWK(WKStringCreateWithUTF8CString("Index"));
740 int index = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, indexKey.get()))));
742 WKRetainPtr<WKStringRef> xKey = adoptWK(WKStringCreateWithUTF8CString("X"));
743 int x = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, xKey.get()))));
745 WKRetainPtr<WKStringRef> yKey = adoptWK(WKStringCreateWithUTF8CString("Y"));
746 int y = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, yKey.get()))));
748 m_eventSenderProxy->updateTouchPoint(index, x, y);
752 if (WKStringIsEqualToUTF8CString(subMessageName, "SetTouchModifier")) {
753 WKRetainPtr<WKStringRef> modifierKey = adoptWK(WKStringCreateWithUTF8CString("Modifier"));
754 WKEventModifiers modifier = static_cast<WKEventModifiers>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, modifierKey.get()))));
756 WKRetainPtr<WKStringRef> enableKey = adoptWK(WKStringCreateWithUTF8CString("Enable"));
757 bool enable = static_cast<bool>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, enableKey.get()))));
759 m_eventSenderProxy->setTouchModifier(modifier, enable);
763 if (WKStringIsEqualToUTF8CString(subMessageName, "SetTouchPointRadius")) {
764 WKRetainPtr<WKStringRef> xKey = adoptWK(WKStringCreateWithUTF8CString("RadiusX"));
765 int x = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, xKey.get()))));
767 WKRetainPtr<WKStringRef> yKey = adoptWK(WKStringCreateWithUTF8CString("RadiusY"));
768 int y = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, yKey.get()))));
770 m_eventSenderProxy->setTouchPointRadius(x, y);
774 if (WKStringIsEqualToUTF8CString(subMessageName, "TouchStart")) {
775 WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), true);
776 m_eventSenderProxy->touchStart();
777 WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false);
781 if (WKStringIsEqualToUTF8CString(subMessageName, "TouchMove")) {
782 WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), true);
783 m_eventSenderProxy->touchMove();
784 WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false);
788 if (WKStringIsEqualToUTF8CString(subMessageName, "TouchEnd")) {
789 WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), true);
790 m_eventSenderProxy->touchEnd();
791 WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false);
795 if (WKStringIsEqualToUTF8CString(subMessageName, "TouchCancel")) {
796 WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), true);
797 m_eventSenderProxy->touchCancel();
798 WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false);
802 if (WKStringIsEqualToUTF8CString(subMessageName, "ClearTouchPoints")) {
803 m_eventSenderProxy->clearTouchPoints();
807 if (WKStringIsEqualToUTF8CString(subMessageName, "ReleaseTouchPoint")) {
808 WKRetainPtr<WKStringRef> indexKey = adoptWK(WKStringCreateWithUTF8CString("Index"));
809 int index = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, indexKey.get()))));
810 m_eventSenderProxy->releaseTouchPoint(index);
814 if (WKStringIsEqualToUTF8CString(subMessageName, "CancelTouchPoint")) {
815 WKRetainPtr<WKStringRef> indexKey = adoptWK(WKStringCreateWithUTF8CString("Index"));
816 int index = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, indexKey.get()))));
817 m_eventSenderProxy->cancelTouchPoint(index);
821 ASSERT_NOT_REACHED();
824 return m_currentInvocation->didReceiveSynchronousMessageFromInjectedBundle(messageName, messageBody);
827 // WKPageLoaderClient
829 void TestController::didCommitLoadForFrame(WKPageRef page, WKFrameRef frame, WKTypeRef, const void* clientInfo)
831 static_cast<TestController*>(const_cast<void*>(clientInfo))->didCommitLoadForFrame(page, frame);
834 void TestController::didFinishLoadForFrame(WKPageRef page, WKFrameRef frame, WKTypeRef, const void* clientInfo)
836 static_cast<TestController*>(const_cast<void*>(clientInfo))->didFinishLoadForFrame(page, frame);
839 void TestController::processDidCrash(WKPageRef page, const void* clientInfo)
841 static_cast<TestController*>(const_cast<void*>(clientInfo))->processDidCrash();
844 void TestController::didCommitLoadForFrame(WKPageRef page, WKFrameRef frame)
846 if (!WKFrameIsMainFrame(frame))
849 mainWebView()->focus();
852 void TestController::didFinishLoadForFrame(WKPageRef page, WKFrameRef frame)
854 if (m_state != Resetting)
857 if (!WKFrameIsMainFrame(frame))
860 WKRetainPtr<WKURLRef> wkURL(AdoptWK, WKFrameCopyURL(frame));
861 if (!WKURLIsEqual(wkURL.get(), blankURL()))
864 m_doneResetting = true;
865 shared().notifyDone();
868 void TestController::processDidCrash()
870 // This function can be called multiple times when crash logs are being saved on Windows, so
871 // ensure we only print the crashed message once.
872 if (!m_didPrintWebProcessCrashedMessage) {
874 pid_t pid = WKPageGetProcessIdentifier(m_mainWebView->page());
875 fprintf(stderr, "#CRASHED - WebProcess (pid %ld)\n", static_cast<long>(pid));
877 fputs("#CRASHED - WebProcess\n", stderr);
880 m_didPrintWebProcessCrashedMessage = true;
883 if (m_shouldExitWhenWebProcessCrashes)