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>
55 static const double defaultLongTimeout = 30;
56 static const double defaultShortTimeout = 15;
57 static const double defaultNoTimeout = -1;
59 static WKURLRef blankURL()
61 static WKURLRef staticBlankURL = WKURLCreateWithUTF8CString("about:blank");
62 return staticBlankURL;
65 static TestController* controller;
67 TestController& TestController::shared()
73 TestController::TestController(int argc, const char* argv[])
74 : m_dumpPixelsForAllTests(false)
76 , m_printSeparators(false)
77 , m_usingServerMode(false)
78 , m_gcBetweenTests(false)
80 , m_doneResetting(false)
81 , m_longTimeout(defaultLongTimeout)
82 , m_shortTimeout(defaultShortTimeout)
83 , m_noTimeout(defaultNoTimeout)
84 , m_useWaitToDumpWatchdogTimer(true)
85 , m_forceNoTimeout(false)
86 , m_didPrintWebProcessCrashedMessage(false)
87 , m_shouldExitWhenWebProcessCrashes(true)
88 , m_beforeUnloadReturnValue(true)
89 #if PLATFORM(MAC) || PLATFORM(QT) || PLATFORM(GTK) || PLATFORM(EFL)
90 , m_eventSenderProxy(new EventSenderProxy(this))
93 initialize(argc, argv);
99 TestController::~TestController()
103 static WKRect getWindowFrameMainPage(WKPageRef page, const void* clientInfo)
105 PlatformWebView* view = static_cast<TestController*>(const_cast<void*>(clientInfo))->mainWebView();
106 return view->windowFrame();
109 static void setWindowFrameMainPage(WKPageRef page, WKRect frame, const void* clientInfo)
111 PlatformWebView* view = static_cast<TestController*>(const_cast<void*>(clientInfo))->mainWebView();
112 view->setWindowFrame(frame);
115 static WKRect getWindowFrameOtherPage(WKPageRef page, const void* clientInfo)
117 PlatformWebView* view = static_cast<PlatformWebView*>(const_cast<void*>(clientInfo));
118 return view->windowFrame();
121 static void setWindowFrameOtherPage(WKPageRef page, WKRect frame, const void* clientInfo)
123 PlatformWebView* view = static_cast<PlatformWebView*>(const_cast<void*>(clientInfo));
124 view->setWindowFrame(frame);
127 static bool runBeforeUnloadConfirmPanel(WKPageRef page, WKStringRef message, WKFrameRef frame, const void *clientInfo)
129 TestController* testController = static_cast<TestController*>(const_cast<void*>(clientInfo));
130 printf("CONFIRM NAVIGATION: %s\n", toSTD(message).c_str());
131 return testController->beforeUnloadReturnValue();
134 #if ENABLE(TIZEN_SQL_DATABASE)
135 static bool exceededDatabaseQuota(WKPageRef, WKFrameRef, WKSecurityOriginRef, WKStringRef, unsigned long long, const void*)
140 static unsigned long long exceededDatabaseQuota(WKPageRef, WKFrameRef, WKSecurityOriginRef, WKStringRef, WKStringRef, unsigned long long, unsigned long long, unsigned long long, unsigned long long, const void*)
142 static const unsigned long long defaultQuota = 5 * 1024 * 1024;
147 void TestController::runModal(WKPageRef page, const void* clientInfo)
149 PlatformWebView* view = static_cast<PlatformWebView*>(const_cast<void*>(clientInfo));
150 view->setWindowIsKey(false);
152 view->setWindowIsKey(true);
155 static void closeOtherPage(WKPageRef page, const void* clientInfo)
158 PlatformWebView* view = static_cast<PlatformWebView*>(const_cast<void*>(clientInfo));
162 static void focus(WKPageRef page, const void* clientInfo)
164 PlatformWebView* view = static_cast<PlatformWebView*>(const_cast<void*>(clientInfo));
165 view->setWindowIsKey(true);
168 static void unfocus(WKPageRef page, const void* clientInfo)
170 PlatformWebView* view = static_cast<PlatformWebView*>(const_cast<void*>(clientInfo));
171 view->setWindowIsKey(false);
174 WKPageRef TestController::createOtherPage(WKPageRef oldPage, WKURLRequestRef, WKDictionaryRef, WKEventModifiers, WKEventMouseButton, const void*)
176 PlatformWebView* view = new PlatformWebView(WKPageGetContext(oldPage), WKPageGetPageGroup(oldPage));
177 WKPageRef newPage = view->page();
179 view->resizeTo(800, 600);
181 WKPageUIClient otherPageUIClient = {
182 kWKPageUIClientCurrentVersion,
184 0, // createNewPage_deprecatedForUseWithV0
190 0, // runJavaScriptAlert
191 0, // runJavaScriptConfirm
192 0, // runJavaScriptPrompt
194 0, // mouseDidMoveOverElement_deprecatedForUseWithV0
195 0, // missingPluginButtonClicked
196 0, // didNotHandleKeyEvent
197 0, // didNotHandleWheelEvent
198 0, // toolbarsAreVisible
199 0, // setToolbarsAreVisible
200 0, // menuBarIsVisible
201 0, // setMenuBarIsVisible
202 0, // statusBarIsVisible
203 0, // setStatusBarIsVisible
206 getWindowFrameOtherPage,
207 setWindowFrameOtherPage,
208 runBeforeUnloadConfirmPanel,
211 exceededDatabaseQuota,
213 0, // decidePolicyForGeolocationPermissionRequest
220 0, // didCompleteRubberBandForMainFrame
221 0, // saveDataToFileInDownloadsFolder
222 0, // shouldInterruptJavaScript
224 0, // mouseDidMoveOverElement
225 0, // decidePolicyForNotificationPermissionRequest
226 0, // unavailablePluginButtonClicked
228 WKPageSetPageUIClient(newPage, &otherPageUIClient);
234 const char* TestController::libraryPathForTesting()
236 // FIXME: This may not be sufficient to prevent interactions/crashes
237 // when running more than one copy of DumpRenderTree.
238 // See https://bugs.webkit.org/show_bug.cgi?id=10906
239 char* dumpRenderTreeTemp = getenv("DUMPRENDERTREE_TEMP");
240 if (dumpRenderTreeTemp)
241 return dumpRenderTreeTemp;
242 return platformLibraryPathForTesting();
246 void TestController::initialize(int argc, const char* argv[])
248 platformInitialize();
251 fputs("Usage: WebKitTestRunner [options] filename [filename2..n]\n", stderr);
252 // FIXME: Refactor option parsing to allow us to print
253 // an auto-generated list of options.
257 bool printSupportedFeatures = false;
259 for (int i = 1; i < argc; ++i) {
260 std::string argument(argv[i]);
262 if (argument == "--timeout" && i + 1 < argc) {
263 m_longTimeout = atoi(argv[++i]);
264 // Scale up the short timeout to match.
265 m_shortTimeout = defaultShortTimeout * m_longTimeout / defaultLongTimeout;
269 if (argument == "--no-timeout") {
270 m_useWaitToDumpWatchdogTimer = false;
274 if (argument == "--no-timeout-at-all") {
275 m_useWaitToDumpWatchdogTimer = false;
276 m_forceNoTimeout = true;
280 if (argument == "--pixel-tests") {
281 m_dumpPixelsForAllTests = true;
284 if (argument == "--verbose") {
288 if (argument == "--gc-between-tests") {
289 m_gcBetweenTests = true;
292 if (argument == "--print-supported-features") {
293 printSupportedFeatures = true;
297 // Skip any other arguments that begin with '--'.
298 if (argument.length() >= 2 && argument[0] == '-' && argument[1] == '-')
301 m_paths.push_back(argument);
304 if (printSupportedFeatures) {
305 // FIXME: On Windows, DumpRenderTree uses this to expose whether it supports 3d
306 // transforms and accelerated compositing. When we support those features, we
307 // should match DRT's behavior.
311 m_usingServerMode = (m_paths.size() == 1 && m_paths[0] == "-");
312 if (m_usingServerMode)
313 m_printSeparators = true;
315 m_printSeparators = m_paths.size() > 1;
317 initializeInjectedBundlePath();
318 initializeTestPluginDirectory();
320 WKRetainPtr<WKStringRef> pageGroupIdentifier(AdoptWK, WKStringCreateWithUTF8CString("WebKitTestRunnerPageGroup"));
321 m_pageGroup.adopt(WKPageGroupCreateWithIdentifier(pageGroupIdentifier.get()));
323 m_context.adopt(WKContextCreateWithInjectedBundlePath(injectedBundlePath()));
325 const char* path = libraryPathForTesting();
327 Vector<char> databaseDirectory(strlen(path) + strlen("/Databases") + 1);
328 sprintf(databaseDirectory.data(), "%s%s", path, "/Databases");
329 WKRetainPtr<WKStringRef> databaseDirectoryWK(AdoptWK, WKStringCreateWithUTF8CString(databaseDirectory.data()));
330 WKContextSetDatabaseDirectory(m_context.get(), databaseDirectoryWK.get());
333 platformInitializeContext();
335 WKContextInjectedBundleClient injectedBundleClient = {
336 kWKContextInjectedBundleClientCurrentVersion,
338 didReceiveMessageFromInjectedBundle,
339 didReceiveSynchronousMessageFromInjectedBundle,
340 0 // getInjectedBundleInitializationUserData
342 WKContextSetInjectedBundleClient(m_context.get(), &injectedBundleClient);
344 if (testPluginDirectory())
345 WKContextSetAdditionalPluginsDirectory(m_context.get(), testPluginDirectory());
347 m_mainWebView = adoptPtr(new PlatformWebView(m_context.get(), m_pageGroup.get()));
349 WKPageUIClient pageUIClient = {
350 kWKPageUIClientCurrentVersion,
352 0, // createNewPage_deprecatedForUseWithV0
358 0, // runJavaScriptAlert
359 0, // runJavaScriptConfirm
360 0, // runJavaScriptPrompt
362 0, // mouseDidMoveOverElement_deprecatedForUseWithV0
363 0, // missingPluginButtonClicked
364 0, // didNotHandleKeyEvent
365 0, // didNotHandleWheelEvent
366 0, // toolbarsAreVisible
367 0, // setToolbarsAreVisible
368 0, // menuBarIsVisible
369 0, // setMenuBarIsVisible
370 0, // statusBarIsVisible
371 0, // setStatusBarIsVisible
374 getWindowFrameMainPage,
375 setWindowFrameMainPage,
376 runBeforeUnloadConfirmPanel,
379 exceededDatabaseQuota,
381 0, // decidePolicyForGeolocationPermissionRequest
388 0, // didCompleteRubberBandForMainFrame
389 0, // saveDataToFileInDownloadsFolder
390 0, // shouldInterruptJavaScript
392 0, // mouseDidMoveOverElement
393 0, // decidePolicyForNotificationPermissionRequest
394 0, // unavailablePluginButtonClicked
396 WKPageSetPageUIClient(m_mainWebView->page(), &pageUIClient);
398 WKPageLoaderClient pageLoaderClient = {
399 kWKPageLoaderClientCurrentVersion,
401 0, // didStartProvisionalLoadForFrame
402 0, // didReceiveServerRedirectForProvisionalLoadForFrame
403 0, // didFailProvisionalLoadWithErrorForFrame
404 didCommitLoadForFrame,
405 0, // didFinishDocumentLoadForFrame
406 didFinishLoadForFrame,
407 0, // didFailLoadWithErrorForFrame
408 0, // didSameDocumentNavigationForFrame
409 0, // didReceiveTitleForFrame
410 0, // didFirstLayoutForFrame
411 0, // didFirstVisuallyNonEmptyLayoutForFrame
412 0, // didRemoveFrameFromHierarchy
413 0, // didFailToInitializePlugin
414 0, // didDisplayInsecureContentForFrame
415 0, // canAuthenticateAgainstProtectionSpaceInFrame
416 0, // didReceiveAuthenticationChallengeInFrame
417 0, // didStartProgress
418 0, // didChangeProgress
419 0, // didFinishProgress
420 0, // didBecomeUnresponsive
421 0, // didBecomeResponsive
423 0, // didChangeBackForwardList
424 0, // shouldGoToBackForwardListItem
425 0, // didRunInsecureContentForFrame
426 0, // didDetectXSSForFrame
427 0, // didNewFirstVisuallyNonEmptyLayout
428 0, // willGoToBackForwardListItem
429 0, // interactionOccurredWhileProcessUnresponsive
431 0, // didReceiveIntentForFrame
432 0, // registerIntentServiceForFrame
434 WKPageSetPageLoaderClient(m_mainWebView->page(), &pageLoaderClient);
437 bool TestController::resetStateToConsistentValues()
441 m_beforeUnloadReturnValue = true;
443 WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("Reset"));
444 WKRetainPtr<WKMutableDictionaryRef> resetMessageBody = adoptWK(WKMutableDictionaryCreate());
446 WKRetainPtr<WKStringRef> shouldGCKey = adoptWK(WKStringCreateWithUTF8CString("ShouldGC"));
447 WKRetainPtr<WKBooleanRef> shouldGCValue = adoptWK(WKBooleanCreate(m_gcBetweenTests));
448 WKDictionaryAddItem(resetMessageBody.get(), shouldGCKey.get(), shouldGCValue.get());
450 WKContextPostMessageToInjectedBundle(TestController::shared().context(), messageName.get(), resetMessageBody.get());
452 WKContextSetShouldUseFontSmoothing(TestController::shared().context(), false);
454 WKContextSetCacheModel(TestController::shared().context(), kWKCacheModelDocumentBrowser);
456 // FIXME: This function should also ensure that there is only one page open.
459 WKPreferencesRef preferences = WKPageGroupGetPreferences(m_pageGroup.get());
460 WKPreferencesResetTestRunnerOverrides(preferences);
461 WKPreferencesSetOfflineWebApplicationCacheEnabled(preferences, true);
462 WKPreferencesSetFontSmoothingLevel(preferences, kWKFontSmoothingLevelNoSubpixelAntiAliasing);
463 WKPreferencesSetXSSAuditorEnabled(preferences, false);
464 WKPreferencesSetWebAudioEnabled(preferences, true);
465 WKPreferencesSetDeveloperExtrasEnabled(preferences, true);
466 WKPreferencesSetJavaScriptExperimentsEnabled(preferences, true);
467 WKPreferencesSetJavaScriptCanOpenWindowsAutomatically(preferences, true);
468 WKPreferencesSetJavaScriptCanAccessClipboard(preferences, true);
469 WKPreferencesSetDOMPasteAllowed(preferences, true);
470 WKPreferencesSetUniversalAccessFromFileURLsAllowed(preferences, true);
471 WKPreferencesSetFileAccessFromFileURLsAllowed(preferences, true);
472 #if ENABLE(FULLSCREEN_API)
473 WKPreferencesSetFullScreenEnabled(preferences, true);
475 WKPreferencesSetPageCacheEnabled(preferences, false);
477 // [Qt][WK2]REGRESSION(r104881):It broke hundreds of tests
478 // FIXME: https://bugs.webkit.org/show_bug.cgi?id=76247
480 WKPreferencesSetMockScrollbarsEnabled(preferences, true);
484 static WKStringRef standardFontFamily = WKStringCreateWithUTF8CString("Times");
485 static WKStringRef cursiveFontFamily = WKStringCreateWithUTF8CString("Apple Chancery");
486 static WKStringRef fantasyFontFamily = WKStringCreateWithUTF8CString("Papyrus");
487 static WKStringRef fixedFontFamily = WKStringCreateWithUTF8CString("Courier");
488 static WKStringRef pictographFontFamily = WKStringCreateWithUTF8CString("Apple Color Emoji");
489 static WKStringRef sansSerifFontFamily = WKStringCreateWithUTF8CString("Helvetica");
490 static WKStringRef serifFontFamily = WKStringCreateWithUTF8CString("Times");
492 WKPreferencesSetStandardFontFamily(preferences, standardFontFamily);
493 WKPreferencesSetCursiveFontFamily(preferences, cursiveFontFamily);
494 WKPreferencesSetFantasyFontFamily(preferences, fantasyFontFamily);
495 WKPreferencesSetFixedFontFamily(preferences, fixedFontFamily);
496 WKPreferencesSetPictographFontFamily(preferences, pictographFontFamily);
497 WKPreferencesSetSansSerifFontFamily(preferences, sansSerifFontFamily);
498 WKPreferencesSetSerifFontFamily(preferences, serifFontFamily);
500 WKPreferencesSetInspectorUsesWebKitUserInterface(preferences, true);
502 WKTextCheckerContinuousSpellCheckingEnabledStateChanged(true);
505 #if ENABLE(TIZEN_WEBKIT2_ASYNCHRONOUS_SPELLCHECKING)
506 WKPreferencesSetAsynchronousSpellCheckingEnabled(preferences, false);
509 // in the case that a test using the chrome input field failed, be sure to clean up for the next test
510 m_mainWebView->removeChromeInputField();
511 m_mainWebView->focus();
513 // Re-set to the default backing scale factor by setting the custom scale factor to 0.
514 WKPageSetCustomBackingScaleFactor(m_mainWebView->page(), 0);
516 // Reset main page back to about:blank
517 m_doneResetting = false;
519 WKPageLoadURL(m_mainWebView->page(), blankURL());
520 runUntil(m_doneResetting, ShortTimeout);
521 return m_doneResetting;
524 bool TestController::runTest(const char* test)
526 if (!resetStateToConsistentValues()) {
528 pid_t pid = WKPageGetProcessIdentifier(m_mainWebView->page());
529 fprintf(stderr, "#PROCESS UNRESPONSIVE - WebProcess (pid %ld)\n", static_cast<long>(pid));
531 fputs("#PROCESS UNRESPONSIVE - WebProcess\n", stderr);
537 bool dumpPixelsTest = m_dumpPixelsForAllTests;
538 std::string command(test);
539 std::string pathOrURL = command;
540 std::string expectedPixelHash;
541 size_t firstSeparatorPos = command.find_first_of('\'');
542 size_t secondSeparatorPos = command.find_first_of('\'', firstSeparatorPos + 1);
543 if (firstSeparatorPos != std::string::npos) {
544 pathOrURL = std::string(command, 0, firstSeparatorPos);
545 size_t pixelHashPos = firstSeparatorPos + 1;
547 // NRWT passes --pixel-test if we should dump pixels for the test.
548 const std::string expectedPixelTestArg("--pixel-test");
549 std::string argTest = std::string(command, firstSeparatorPos + 1, expectedPixelTestArg.size());
550 if (argTest == expectedPixelTestArg) {
551 dumpPixelsTest = true;
552 pixelHashPos = secondSeparatorPos == std::string::npos ? std::string::npos : secondSeparatorPos + 1;
554 if (pixelHashPos != std::string::npos && pixelHashPos < command.size())
555 expectedPixelHash = std::string(command, pixelHashPos);
558 m_state = RunningTest;
560 m_currentInvocation = adoptPtr(new TestInvocation(pathOrURL));
562 m_currentInvocation->setIsPixelTest(expectedPixelHash);
564 m_currentInvocation->invoke();
565 m_currentInvocation.clear();
570 void TestController::runTestingServerLoop()
572 char filenameBuffer[2048];
573 while (fgets(filenameBuffer, sizeof(filenameBuffer), stdin)) {
574 char* newLineCharacter = strchr(filenameBuffer, '\n');
575 if (newLineCharacter)
576 *newLineCharacter = '\0';
578 if (strlen(filenameBuffer) == 0)
581 if (!runTest(filenameBuffer))
586 void TestController::run()
588 if (m_usingServerMode)
589 runTestingServerLoop();
591 for (size_t i = 0; i < m_paths.size(); ++i) {
592 if (!runTest(m_paths[i].c_str()))
598 void TestController::runUntil(bool& done, TimeoutDuration timeoutDuration)
600 double timeout = m_noTimeout;
601 if (!m_forceNoTimeout) {
602 switch (timeoutDuration) {
604 timeout = m_shortTimeout;
607 timeout = m_longTimeout;
611 timeout = m_noTimeout;
616 platformRunUntil(done, timeout);
619 // WKContextInjectedBundleClient
621 void TestController::didReceiveMessageFromInjectedBundle(WKContextRef context, WKStringRef messageName, WKTypeRef messageBody, const void* clientInfo)
623 static_cast<TestController*>(const_cast<void*>(clientInfo))->didReceiveMessageFromInjectedBundle(messageName, messageBody);
626 void TestController::didReceiveSynchronousMessageFromInjectedBundle(WKContextRef context, WKStringRef messageName, WKTypeRef messageBody, WKTypeRef* returnData, const void* clientInfo)
628 *returnData = static_cast<TestController*>(const_cast<void*>(clientInfo))->didReceiveSynchronousMessageFromInjectedBundle(messageName, messageBody).leakRef();
631 void TestController::didReceiveMessageFromInjectedBundle(WKStringRef messageName, WKTypeRef messageBody)
633 if (!m_currentInvocation)
635 m_currentInvocation->didReceiveMessageFromInjectedBundle(messageName, messageBody);
638 WKRetainPtr<WKTypeRef> TestController::didReceiveSynchronousMessageFromInjectedBundle(WKStringRef messageName, WKTypeRef messageBody)
640 #if PLATFORM(MAC) || PLATFORM(QT) || PLATFORM(GTK) || PLATFORM(EFL)
641 if (WKStringIsEqualToUTF8CString(messageName, "EventSender")) {
642 ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID());
643 WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody);
645 WKRetainPtr<WKStringRef> subMessageKey(AdoptWK, WKStringCreateWithUTF8CString("SubMessage"));
646 WKStringRef subMessageName = static_cast<WKStringRef>(WKDictionaryGetItemForKey(messageBodyDictionary, subMessageKey.get()));
648 if (WKStringIsEqualToUTF8CString(subMessageName, "KeyDown")) {
649 WKRetainPtr<WKStringRef> keyKey = adoptWK(WKStringCreateWithUTF8CString("Key"));
650 WKStringRef key = static_cast<WKStringRef>(WKDictionaryGetItemForKey(messageBodyDictionary, keyKey.get()));
652 WKRetainPtr<WKStringRef> modifiersKey = adoptWK(WKStringCreateWithUTF8CString("Modifiers"));
653 WKEventModifiers modifiers = static_cast<WKEventModifiers>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, modifiersKey.get()))));
655 WKRetainPtr<WKStringRef> locationKey = adoptWK(WKStringCreateWithUTF8CString("Location"));
656 unsigned location = static_cast<unsigned>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, locationKey.get()))));
658 // Forward to WebProcess
659 WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), true);
660 m_eventSenderProxy->keyDown(key, modifiers, location);
661 WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false);
665 if (WKStringIsEqualToUTF8CString(subMessageName, "MouseDown") || WKStringIsEqualToUTF8CString(subMessageName, "MouseUp")) {
666 WKRetainPtr<WKStringRef> buttonKey = adoptWK(WKStringCreateWithUTF8CString("Button"));
667 unsigned button = static_cast<unsigned>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, buttonKey.get()))));
669 WKRetainPtr<WKStringRef> modifiersKey = adoptWK(WKStringCreateWithUTF8CString("Modifiers"));
670 WKEventModifiers modifiers = static_cast<WKEventModifiers>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, modifiersKey.get()))));
672 // Forward to WebProcess
673 WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), true);
674 if (WKStringIsEqualToUTF8CString(subMessageName, "MouseDown"))
675 m_eventSenderProxy->mouseDown(button, modifiers);
677 m_eventSenderProxy->mouseUp(button, modifiers);
678 WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false);
682 if (WKStringIsEqualToUTF8CString(subMessageName, "MouseMoveTo")) {
683 WKRetainPtr<WKStringRef> xKey = adoptWK(WKStringCreateWithUTF8CString("X"));
684 double x = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, xKey.get())));
686 WKRetainPtr<WKStringRef> yKey = adoptWK(WKStringCreateWithUTF8CString("Y"));
687 double y = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, yKey.get())));
689 // Forward to WebProcess
690 WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), true);
691 m_eventSenderProxy->mouseMoveTo(x, y);
692 WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false);
696 if (WKStringIsEqualToUTF8CString(subMessageName, "MouseScrollBy")) {
697 WKRetainPtr<WKStringRef> xKey = adoptWK(WKStringCreateWithUTF8CString("X"));
698 double x = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, xKey.get())));
700 WKRetainPtr<WKStringRef> yKey = adoptWK(WKStringCreateWithUTF8CString("Y"));
701 double y = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, yKey.get())));
703 // Forward to WebProcess
704 WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), true);
705 m_eventSenderProxy->mouseScrollBy(x, y);
706 WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false);
710 if (WKStringIsEqualToUTF8CString(subMessageName, "LeapForward")) {
711 WKRetainPtr<WKStringRef> timeKey = adoptWK(WKStringCreateWithUTF8CString("TimeInMilliseconds"));
712 unsigned time = static_cast<unsigned>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, timeKey.get()))));
714 m_eventSenderProxy->leapForward(time);
718 #if ENABLE(TOUCH_EVENTS)
719 if (WKStringIsEqualToUTF8CString(subMessageName, "AddTouchPoint")) {
720 WKRetainPtr<WKStringRef> xKey = adoptWK(WKStringCreateWithUTF8CString("X"));
721 int x = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, xKey.get()))));
723 WKRetainPtr<WKStringRef> yKey = adoptWK(WKStringCreateWithUTF8CString("Y"));
724 int y = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, yKey.get()))));
726 m_eventSenderProxy->addTouchPoint(x, y);
730 if (WKStringIsEqualToUTF8CString(subMessageName, "UpdateTouchPoint")) {
731 WKRetainPtr<WKStringRef> indexKey = adoptWK(WKStringCreateWithUTF8CString("Index"));
732 int index = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, indexKey.get()))));
734 WKRetainPtr<WKStringRef> xKey = adoptWK(WKStringCreateWithUTF8CString("X"));
735 int x = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, xKey.get()))));
737 WKRetainPtr<WKStringRef> yKey = adoptWK(WKStringCreateWithUTF8CString("Y"));
738 int y = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, yKey.get()))));
740 m_eventSenderProxy->updateTouchPoint(index, x, y);
744 if (WKStringIsEqualToUTF8CString(subMessageName, "SetTouchModifier")) {
745 WKRetainPtr<WKStringRef> modifierKey = adoptWK(WKStringCreateWithUTF8CString("Modifier"));
746 WKEventModifiers modifier = static_cast<WKEventModifiers>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, modifierKey.get()))));
748 WKRetainPtr<WKStringRef> enableKey = adoptWK(WKStringCreateWithUTF8CString("Enable"));
749 bool enable = static_cast<bool>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, enableKey.get()))));
751 m_eventSenderProxy->setTouchModifier(modifier, enable);
755 if (WKStringIsEqualToUTF8CString(subMessageName, "SetTouchPointRadius")) {
756 WKRetainPtr<WKStringRef> xKey = adoptWK(WKStringCreateWithUTF8CString("RadiusX"));
757 int x = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, xKey.get()))));
759 WKRetainPtr<WKStringRef> yKey = adoptWK(WKStringCreateWithUTF8CString("RadiusY"));
760 int y = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, yKey.get()))));
762 m_eventSenderProxy->setTouchPointRadius(x, y);
766 if (WKStringIsEqualToUTF8CString(subMessageName, "TouchStart")) {
767 WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), true);
768 m_eventSenderProxy->touchStart();
769 WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false);
773 if (WKStringIsEqualToUTF8CString(subMessageName, "TouchMove")) {
774 WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), true);
775 m_eventSenderProxy->touchMove();
776 WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false);
780 if (WKStringIsEqualToUTF8CString(subMessageName, "TouchEnd")) {
781 WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), true);
782 m_eventSenderProxy->touchEnd();
783 WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false);
787 if (WKStringIsEqualToUTF8CString(subMessageName, "TouchCancel")) {
788 WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), true);
789 m_eventSenderProxy->touchCancel();
790 WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false);
794 if (WKStringIsEqualToUTF8CString(subMessageName, "ClearTouchPoints")) {
795 m_eventSenderProxy->clearTouchPoints();
799 if (WKStringIsEqualToUTF8CString(subMessageName, "ReleaseTouchPoint")) {
800 WKRetainPtr<WKStringRef> indexKey = adoptWK(WKStringCreateWithUTF8CString("Index"));
801 int index = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, indexKey.get()))));
802 m_eventSenderProxy->releaseTouchPoint(index);
806 if (WKStringIsEqualToUTF8CString(subMessageName, "CancelTouchPoint")) {
807 WKRetainPtr<WKStringRef> indexKey = adoptWK(WKStringCreateWithUTF8CString("Index"));
808 int index = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, indexKey.get()))));
809 m_eventSenderProxy->cancelTouchPoint(index);
813 ASSERT_NOT_REACHED();
816 return m_currentInvocation->didReceiveSynchronousMessageFromInjectedBundle(messageName, messageBody);
819 // WKPageLoaderClient
821 void TestController::didCommitLoadForFrame(WKPageRef page, WKFrameRef frame, WKTypeRef, const void* clientInfo)
823 static_cast<TestController*>(const_cast<void*>(clientInfo))->didCommitLoadForFrame(page, frame);
826 void TestController::didFinishLoadForFrame(WKPageRef page, WKFrameRef frame, WKTypeRef, const void* clientInfo)
828 static_cast<TestController*>(const_cast<void*>(clientInfo))->didFinishLoadForFrame(page, frame);
831 void TestController::processDidCrash(WKPageRef page, const void* clientInfo)
833 static_cast<TestController*>(const_cast<void*>(clientInfo))->processDidCrash();
836 void TestController::didCommitLoadForFrame(WKPageRef page, WKFrameRef frame)
838 if (!WKFrameIsMainFrame(frame))
841 mainWebView()->focus();
844 void TestController::didFinishLoadForFrame(WKPageRef page, WKFrameRef frame)
846 if (m_state != Resetting)
849 if (!WKFrameIsMainFrame(frame))
852 WKRetainPtr<WKURLRef> wkURL(AdoptWK, WKFrameCopyURL(frame));
853 if (!WKURLIsEqual(wkURL.get(), blankURL()))
856 m_doneResetting = true;
857 shared().notifyDone();
860 void TestController::processDidCrash()
862 // This function can be called multiple times when crash logs are being saved on Windows, so
863 // ensure we only print the crashed message once.
864 if (!m_didPrintWebProcessCrashedMessage) {
866 pid_t pid = WKPageGetProcessIdentifier(m_mainWebView->page());
867 fprintf(stderr, "#CRASHED - WebProcess (pid %ld)\n", static_cast<long>(pid));
869 fputs("#CRASHED - WebProcess\n", stderr);
872 m_didPrintWebProcessCrashedMessage = true;
875 if (m_shouldExitWhenWebProcessCrashes)