2 * Copyright (C) 2010, 2014-2015 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 <WebKit/WKArray.h>
35 #include <WebKit/WKAuthenticationChallenge.h>
36 #include <WebKit/WKAuthenticationDecisionListener.h>
37 #include <WebKit/WKContextConfigurationRef.h>
38 #include <WebKit/WKContextPrivate.h>
39 #include <WebKit/WKCookieManager.h>
40 #include <WebKit/WKCredential.h>
41 #include <WebKit/WKIconDatabase.h>
42 #include <WebKit/WKNavigationResponseRef.h>
43 #include <WebKit/WKNotification.h>
44 #include <WebKit/WKNotificationManager.h>
45 #include <WebKit/WKNotificationPermissionRequest.h>
46 #include <WebKit/WKNumber.h>
47 #include <WebKit/WKPageGroup.h>
48 #include <WebKit/WKPageInjectedBundleClient.h>
49 #include <WebKit/WKPagePrivate.h>
50 #include <WebKit/WKPluginInformation.h>
51 #include <WebKit/WKPreferencesRefPrivate.h>
52 #include <WebKit/WKProtectionSpace.h>
53 #include <WebKit/WKRetainPtr.h>
58 #include <runtime/InitializeThreading.h>
61 #include <wtf/MainThread.h>
62 #include <wtf/RunLoop.h>
63 #include <wtf/TemporaryChange.h>
64 #include <wtf/text/CString.h>
65 #include <wtf/text/WTFString.h>
68 #include <WebKit/WKContextPrivateMac.h>
69 #include <WebKit/WKPagePrivateMac.h>
73 #include <WebKit/WKTextChecker.h>
78 const unsigned TestController::viewWidth = 800;
79 const unsigned TestController::viewHeight = 600;
81 const unsigned TestController::w3cSVGViewWidth = 480;
82 const unsigned TestController::w3cSVGViewHeight = 360;
85 const double TestController::shortTimeout = 10.0;
87 const double TestController::shortTimeout = 5.0;
90 const double TestController::noTimeout = -1;
92 static WKURLRef blankURL()
94 static WKURLRef staticBlankURL = WKURLCreateWithUTF8CString("about:blank");
95 return staticBlankURL;
98 static WKDataRef copyWebCryptoMasterKey(WKPageRef, const void*)
100 // Any 128 bit key would do, all we need for testing is to implement the callback.
101 return WKDataCreate((const uint8_t*)"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", 16);
104 static TestController* controller;
106 TestController& TestController::singleton()
112 TestController::TestController(int argc, const char* argv[])
114 , m_printSeparators(false)
115 , m_usingServerMode(false)
116 , m_gcBetweenTests(false)
117 , m_shouldDumpPixelsForAllTests(false)
119 , m_doneResetting(false)
120 , m_useWaitToDumpWatchdogTimer(true)
121 , m_forceNoTimeout(false)
122 , m_didPrintWebProcessCrashedMessage(false)
123 , m_shouldExitWhenWebProcessCrashes(true)
124 , m_beforeUnloadReturnValue(true)
125 , m_isGeolocationPermissionSet(false)
126 , m_isGeolocationPermissionAllowed(false)
127 , m_policyDelegateEnabled(false)
128 , m_policyDelegatePermissive(false)
129 , m_handlesAuthenticationChallenges(false)
130 , m_shouldBlockAllPlugins(false)
131 , m_forceComplexText(false)
132 , m_shouldUseAcceleratedDrawing(false)
133 , m_shouldUseRemoteLayerTree(false)
134 , m_shouldLogHistoryClientCallbacks(false)
135 , m_shouldShowWebView(false)
137 initialize(argc, argv);
143 TestController::~TestController()
145 WKIconDatabaseClose(WKContextGetIconDatabase(m_context.get()));
150 static WKRect getWindowFrame(WKPageRef page, const void* clientInfo)
152 PlatformWebView* view = static_cast<PlatformWebView*>(const_cast<void*>(clientInfo));
153 return view->windowFrame();
156 static void setWindowFrame(WKPageRef page, WKRect frame, const void* clientInfo)
158 PlatformWebView* view = static_cast<PlatformWebView*>(const_cast<void*>(clientInfo));
159 view->setWindowFrame(frame);
162 static bool runBeforeUnloadConfirmPanel(WKPageRef page, WKStringRef message, WKFrameRef frame, const void*)
164 printf("CONFIRM NAVIGATION: %s\n", toSTD(message).c_str());
165 return TestController::singleton().beforeUnloadReturnValue();
168 void TestController::runModal(WKPageRef page, const void* clientInfo)
170 PlatformWebView* view = static_cast<PlatformWebView*>(const_cast<void*>(clientInfo));
171 view->setWindowIsKey(false);
173 view->setWindowIsKey(true);
176 static void closeOtherPage(WKPageRef page, const void* clientInfo)
179 PlatformWebView* view = static_cast<PlatformWebView*>(const_cast<void*>(clientInfo));
183 static void focus(WKPageRef page, const void* clientInfo)
185 PlatformWebView* view = static_cast<PlatformWebView*>(const_cast<void*>(clientInfo));
187 view->setWindowIsKey(true);
190 static void unfocus(WKPageRef page, const void* clientInfo)
192 PlatformWebView* view = static_cast<PlatformWebView*>(const_cast<void*>(clientInfo));
193 view->setWindowIsKey(false);
196 static void decidePolicyForGeolocationPermissionRequest(WKPageRef, WKFrameRef, WKSecurityOriginRef, WKGeolocationPermissionRequestRef permissionRequest, const void* clientInfo)
198 TestController::singleton().handleGeolocationPermissionRequest(permissionRequest);
201 static void decidePolicyForUserMediaPermissionRequest(WKPageRef, WKFrameRef, WKSecurityOriginRef, WKUserMediaPermissionRequestRef permissionRequest, const void* clientInfo)
203 TestController::singleton().handleUserMediaPermissionRequest(permissionRequest);
206 WKPageRef TestController::createOtherPage(WKPageRef oldPage, WKPageConfigurationRef configuration, WKNavigationActionRef navigationAction, WKWindowFeaturesRef windowFeatures, const void *clientInfo)
208 PlatformWebView* parentView = static_cast<PlatformWebView*>(const_cast<void*>(clientInfo));
210 PlatformWebView* view = platformCreateOtherPage(parentView, configuration, parentView->options());
211 WKPageRef newPage = view->page();
213 view->resizeTo(800, 600);
215 WKPageUIClientV6 otherPageUIClient = {
217 0, // createNewPage_deprecatedForUseWithV0
223 0, // runJavaScriptAlert_deprecatedForUseWithV0
224 0, // runJavaScriptAlert_deprecatedForUseWithV0
225 0, // runJavaScriptAlert_deprecatedForUseWithV0
227 0, // mouseDidMoveOverElement_deprecatedForUseWithV0
228 0, // missingPluginButtonClicked
229 0, // didNotHandleKeyEvent
230 0, // didNotHandleWheelEvent
231 0, // toolbarsAreVisible
232 0, // setToolbarsAreVisible
233 0, // menuBarIsVisible
234 0, // setMenuBarIsVisible
235 0, // statusBarIsVisible
236 0, // setStatusBarIsVisible
241 runBeforeUnloadConfirmPanel,
244 0, // exceededDatabaseQuota
246 decidePolicyForGeolocationPermissionRequest,
253 0, // didCompleteRubberBandForMainFrame
254 0, // saveDataToFileInDownloadsFolder
255 0, // shouldInterruptJavaScript
256 0, // createNewPage_deprecatedForUseWithV1
257 0, // mouseDidMoveOverElement
258 0, // decidePolicyForNotificationPermissionRequest
259 0, // unavailablePluginButtonClicked_deprecatedForUseWithV1
260 0, // showColorPicker
261 0, // hideColorPicker
262 0, // unavailablePluginButtonClicked
263 0, // pinnedStateDidChange
264 0, // didBeginTrackingPotentialLongMousePress
265 0, // didRecognizeLongMousePress
266 0, // didCancelTrackingPotentialLongMousePress
267 0, // isPlayingAudioDidChange
268 decidePolicyForUserMediaPermissionRequest,
269 0, // didClickAutofillButton
270 0, // runJavaScriptAlert
271 0, // runJavaScriptConfirm
272 0, // runJavaScriptPrompt
273 0, // mediaSessionMetadataDidChange
276 WKPageSetPageUIClient(newPage, &otherPageUIClient.base);
278 WKPageNavigationClientV0 pageNavigationClient = {
279 { 0, &TestController::singleton() },
280 decidePolicyForNavigationAction,
281 decidePolicyForNavigationResponse,
282 decidePolicyForPluginLoad,
283 0, // didStartProvisionalNavigation
284 0, // didReceiveServerRedirectForProvisionalNavigation
285 0, // didFailProvisionalNavigation
286 0, // didCommitNavigation
287 0, // didFinishNavigation
288 0, // didFailNavigation
289 0, // didFailProvisionalLoadInSubframe
290 0, // didFinishDocumentLoad
291 0, // didSameDocumentNavigation
292 0, // renderingProgressDidChange
293 canAuthenticateAgainstProtectionSpace,
294 didReceiveAuthenticationChallenge,
296 copyWebCryptoMasterKey,
297 didBeginNavigationGesture,
298 willEndNavigationGesture,
299 didEndNavigationGesture,
300 didRemoveNavigationGestureSnapshot
302 WKPageSetPageNavigationClient(newPage, &pageNavigationClient.base);
304 view->didInitializeClients();
306 TestController::singleton().updateWindowScaleForTest(view, *TestController::singleton().m_currentInvocation);
312 const char* TestController::libraryPathForTesting()
314 // FIXME: This may not be sufficient to prevent interactions/crashes
315 // when running more than one copy of DumpRenderTree.
316 // See https://bugs.webkit.org/show_bug.cgi?id=10906
317 char* dumpRenderTreeTemp = getenv("DUMPRENDERTREE_TEMP");
318 if (dumpRenderTreeTemp)
319 return dumpRenderTreeTemp;
320 return platformLibraryPathForTesting();
323 void TestController::initialize(int argc, const char* argv[])
325 JSC::initializeThreading();
326 WTF::initializeMainThread();
327 RunLoop::initializeMainRunLoop();
329 platformInitialize();
332 OptionsHandler optionsHandler(options);
335 optionsHandler.printHelp();
338 if (!optionsHandler.parse(argc, argv))
341 m_useWaitToDumpWatchdogTimer = options.useWaitToDumpWatchdogTimer;
342 m_forceNoTimeout = options.forceNoTimeout;
343 m_verbose = options.verbose;
344 m_gcBetweenTests = options.gcBetweenTests;
345 m_shouldDumpPixelsForAllTests = options.shouldDumpPixelsForAllTests;
346 m_forceComplexText = options.forceComplexText;
347 m_shouldUseAcceleratedDrawing = options.shouldUseAcceleratedDrawing;
348 m_shouldUseRemoteLayerTree = options.shouldUseRemoteLayerTree;
349 m_paths = options.paths;
350 m_allowedHosts = options.allowedHosts;
351 m_shouldShowWebView = options.shouldShowWebView;
353 if (options.printSupportedFeatures) {
354 // FIXME: On Windows, DumpRenderTree uses this to expose whether it supports 3d
355 // transforms and accelerated compositing. When we support those features, we
356 // should match DRT's behavior.
360 m_usingServerMode = (m_paths.size() == 1 && m_paths[0] == "-");
361 if (m_usingServerMode)
362 m_printSeparators = true;
364 m_printSeparators = m_paths.size() > 1;
366 initializeInjectedBundlePath();
367 initializeTestPluginDirectory();
369 WKRetainPtr<WKStringRef> pageGroupIdentifier(AdoptWK, WKStringCreateWithUTF8CString("WebKitTestRunnerPageGroup"));
370 m_pageGroup.adopt(WKPageGroupCreateWithIdentifier(pageGroupIdentifier.get()));
372 auto configuration = adoptWK(WKContextConfigurationCreate());
373 WKContextConfigurationSetInjectedBundlePath(configuration.get(), injectedBundlePath());
374 WKContextConfigurationSetFullySynchronousModeIsAllowedForTesting(configuration.get(), true);
376 if (const char* dumpRenderTreeTemp = libraryPathForTesting()) {
377 String temporaryFolder = String::fromUTF8(dumpRenderTreeTemp);
379 const char separator = '/';
381 WKContextConfigurationSetApplicationCacheDirectory(configuration.get(), toWK(temporaryFolder + separator + "ApplicationCache").get());
382 WKContextConfigurationSetDiskCacheDirectory(configuration.get(), toWK(temporaryFolder + separator + "Cache").get());
383 WKContextConfigurationSetIndexedDBDatabaseDirectory(configuration.get(), toWK(temporaryFolder + separator + "Databases" + separator + "IndexedDB").get());
384 WKContextConfigurationSetLocalStorageDirectory(configuration.get(), toWK(temporaryFolder + separator + "LocalStorage").get());
385 WKContextConfigurationSetWebSQLDatabaseDirectory(configuration.get(), toWK(temporaryFolder + separator + "Databases" + separator + "WebSQL").get());
386 WKContextConfigurationSetMediaKeysStorageDirectory(configuration.get(), toWK(temporaryFolder + separator + "MediaKeys").get());
388 m_context = platformAdjustContext(adoptWK(WKContextCreateWithConfiguration(configuration.get())).get(), configuration.get());
390 m_geolocationProvider = std::make_unique<GeolocationProviderMock>(m_context.get());
393 WKContextSetUsesNetworkProcess(m_context.get(), false);
394 WKContextSetProcessModel(m_context.get(), kWKProcessModelSharedSecondaryProcess);
397 if (const char* dumpRenderTreeTemp = libraryPathForTesting()) {
398 String temporaryFolder = String::fromUTF8(dumpRenderTreeTemp);
400 // FIXME: This should be migrated to WKContextConfigurationRef.
401 // Disable icon database to avoid fetching <http://127.0.0.1:8000/favicon.ico> and making tests flaky.
402 // Invividual tests can enable it using testRunner.setIconDatabaseEnabled, although it's not currently supported in WebKitTestRunner.
403 WKContextSetIconDatabasePath(m_context.get(), toWK(emptyString()).get());
406 WKContextUseTestingNetworkSession(m_context.get());
407 WKContextSetCacheModel(m_context.get(), kWKCacheModelDocumentBrowser);
409 platformInitializeContext();
411 WKContextInjectedBundleClientV1 injectedBundleClient = {
413 didReceiveMessageFromInjectedBundle,
414 didReceiveSynchronousMessageFromInjectedBundle,
415 0 // getInjectedBundleInitializationUserData
417 WKContextSetInjectedBundleClient(m_context.get(), &injectedBundleClient.base);
419 WKContextClientV1 contextClient = {
421 0, // plugInAutoStartOriginHashesChanged
422 networkProcessDidCrash,
423 0, // plugInInformationBecameAvailable
424 0, // copyWebCryptoMasterKey
426 WKContextSetClient(m_context.get(), &contextClient.base);
428 WKContextHistoryClientV0 historyClient = {
430 didNavigateWithNavigationData,
431 didPerformClientRedirect,
432 didPerformServerRedirect,
433 didUpdateHistoryTitle,
434 0, // populateVisitedLinks
436 WKContextSetHistoryClient(m_context.get(), &historyClient.base);
438 WKNotificationManagerRef notificationManager = WKContextGetNotificationManager(m_context.get());
439 WKNotificationProviderV0 notificationKit = m_webNotificationProvider.provider();
440 WKNotificationManagerSetProvider(notificationManager, ¬ificationKit.base);
442 if (testPluginDirectory())
443 WKContextSetAdditionalPluginsDirectory(m_context.get(), testPluginDirectory());
445 if (m_forceComplexText)
446 WKContextSetAlwaysUsesComplexTextCodePath(m_context.get(), true);
448 m_configuration = adoptWK(WKPageConfigurationCreate());
449 WKPageConfigurationSetContext(m_configuration.get(), m_context.get());
450 WKPageConfigurationSetPageGroup(m_configuration.get(), m_pageGroup.get());
451 WKPageConfigurationSetUserContentController(m_configuration.get(), adoptWK(WKUserContentControllerCreate()).get());
453 // Some preferences (notably mock scroll bars setting) currently cannot be re-applied to an existing view, so we need to set them now.
454 resetPreferencesToConsistentValues();
457 void TestController::createWebViewWithOptions(const ViewOptions& options)
459 platformCreateWebView(m_configuration.get(), options);
460 WKPageUIClientV6 pageUIClient = {
461 { 6, m_mainWebView.get() },
462 0, // createNewPage_deprecatedForUseWithV0
468 0, // runJavaScriptAlert_deprecatedForUseWithV0
469 0, // runJavaScriptAlert_deprecatedForUseWithV0
470 0, // runJavaScriptAlert_deprecatedForUseWithV0
472 0, // mouseDidMoveOverElement_deprecatedForUseWithV0
473 0, // missingPluginButtonClicked
474 0, // didNotHandleKeyEvent
475 0, // didNotHandleWheelEvent
476 0, // toolbarsAreVisible
477 0, // setToolbarsAreVisible
478 0, // menuBarIsVisible
479 0, // setMenuBarIsVisible
480 0, // statusBarIsVisible
481 0, // setStatusBarIsVisible
486 runBeforeUnloadConfirmPanel,
489 0, // exceededDatabaseQuota,
491 decidePolicyForGeolocationPermissionRequest,
498 0, // didCompleteRubberBandForMainFrame
499 0, // saveDataToFileInDownloadsFolder
500 0, // shouldInterruptJavaScript
501 0, // createNewPage_deprecatedForUseWithV1
502 0, // mouseDidMoveOverElement
503 decidePolicyForNotificationPermissionRequest, // decidePolicyForNotificationPermissionRequest
504 0, // unavailablePluginButtonClicked_deprecatedForUseWithV1
505 0, // showColorPicker
506 0, // hideColorPicker
507 unavailablePluginButtonClicked,
508 0, // pinnedStateDidChange
509 0, // didBeginTrackingPotentialLongMousePress
510 0, // didRecognizeLongMousePress
511 0, // didCancelTrackingPotentialLongMousePress
512 0, // isPlayingAudioDidChange
513 decidePolicyForUserMediaPermissionRequest,
514 0, // didClickAutofillButton
515 0, // runJavaScriptAlert
516 0, // runJavaScriptConfirm
517 0, // runJavaScriptPrompt
518 0, // mediaSessionMetadataDidChange
521 WKPageSetPageUIClient(m_mainWebView->page(), &pageUIClient.base);
523 WKPageNavigationClientV0 pageNavigationClient = {
525 decidePolicyForNavigationAction,
526 decidePolicyForNavigationResponse,
527 decidePolicyForPluginLoad,
528 0, // didStartProvisionalNavigation
529 0, // didReceiveServerRedirectForProvisionalNavigation
530 0, // didFailProvisionalNavigation
533 0, // didFailNavigation
534 0, // didFailProvisionalLoadInSubframe
535 0, // didFinishDocumentLoad
536 0, // didSameDocumentNavigation
537 0, // renderingProgressDidChange
538 canAuthenticateAgainstProtectionSpace,
539 didReceiveAuthenticationChallenge,
541 copyWebCryptoMasterKey,
542 didBeginNavigationGesture,
543 willEndNavigationGesture,
544 didEndNavigationGesture,
545 didRemoveNavigationGestureSnapshot
547 WKPageSetPageNavigationClient(m_mainWebView->page(), &pageNavigationClient.base);
550 // this should just be done on the page?
551 WKPageInjectedBundleClientV0 injectedBundleClient = {
553 didReceivePageMessageFromInjectedBundle,
554 didReceiveSynchronousPageMessageFromInjectedBundle
556 WKPageSetPageInjectedBundleClient(m_mainWebView->page(), &injectedBundleClient.base);
558 m_mainWebView->didInitializeClients();
560 // Generally, the tests should default to running at 1x. updateWindowScaleForTest() will adjust the scale to
561 // something else for specific tests that need to run at a different window scale.
562 m_mainWebView->changeWindowScaleIfNeeded(1);
565 void TestController::ensureViewSupportsOptionsForTest(const TestInvocation& test)
567 auto viewOptions = viewOptionsForTest(test);
570 if (m_mainWebView->viewSupportsOptions(viewOptions))
573 WKPageSetPageUIClient(m_mainWebView->page(), nullptr);
574 WKPageSetPageNavigationClient(m_mainWebView->page(), nullptr);
575 WKPageClose(m_mainWebView->page());
577 m_mainWebView = nullptr;
580 createWebViewWithOptions(viewOptions);
582 if (!resetStateToConsistentValues())
583 TestInvocation::dumpWebProcessUnresponsiveness("<unknown> - TestController::run - Failed to reset state to consistent values\n");
586 void TestController::resetPreferencesToConsistentValues()
589 WKPreferencesRef preferences = platformPreferences();
590 WKPreferencesResetTestRunnerOverrides(preferences);
591 WKPreferencesSetPageVisibilityBasedProcessSuppressionEnabled(preferences, false);
592 WKPreferencesSetOfflineWebApplicationCacheEnabled(preferences, true);
593 WKPreferencesSetFontSmoothingLevel(preferences, kWKFontSmoothingLevelNoSubpixelAntiAliasing);
594 WKPreferencesSetAntialiasedFontDilationEnabled(preferences, false);
595 WKPreferencesSetXSSAuditorEnabled(preferences, false);
596 WKPreferencesSetWebAudioEnabled(preferences, true);
597 WKPreferencesSetMediaStreamEnabled(preferences, true);
598 WKPreferencesSetDeveloperExtrasEnabled(preferences, true);
599 WKPreferencesSetJavaScriptRuntimeFlags(preferences, kWKJavaScriptRuntimeFlagsAllEnabled);
600 WKPreferencesSetJavaScriptCanOpenWindowsAutomatically(preferences, true);
601 WKPreferencesSetJavaScriptCanAccessClipboard(preferences, true);
602 WKPreferencesSetDOMPasteAllowed(preferences, true);
603 WKPreferencesSetUniversalAccessFromFileURLsAllowed(preferences, true);
604 WKPreferencesSetFileAccessFromFileURLsAllowed(preferences, true);
605 #if ENABLE(FULLSCREEN_API)
606 WKPreferencesSetFullScreenEnabled(preferences, true);
608 WKPreferencesSetPageCacheEnabled(preferences, false);
609 WKPreferencesSetAsynchronousPluginInitializationEnabled(preferences, false);
610 WKPreferencesSetAsynchronousPluginInitializationEnabledForAllPlugins(preferences, false);
611 WKPreferencesSetArtificialPluginInitializationDelayEnabled(preferences, false);
612 WKPreferencesSetTabToLinksEnabled(preferences, false);
613 WKPreferencesSetInteractiveFormValidationEnabled(preferences, true);
614 WKPreferencesSetMockScrollbarsEnabled(preferences, true);
616 static WKStringRef defaultTextEncoding = WKStringCreateWithUTF8CString("ISO-8859-1");
617 WKPreferencesSetDefaultTextEncodingName(preferences, defaultTextEncoding);
619 static WKStringRef standardFontFamily = WKStringCreateWithUTF8CString("Times");
620 static WKStringRef cursiveFontFamily = WKStringCreateWithUTF8CString("Apple Chancery");
621 static WKStringRef fantasyFontFamily = WKStringCreateWithUTF8CString("Papyrus");
622 static WKStringRef fixedFontFamily = WKStringCreateWithUTF8CString("Courier");
623 static WKStringRef pictographFontFamily = WKStringCreateWithUTF8CString("Apple Color Emoji");
624 static WKStringRef sansSerifFontFamily = WKStringCreateWithUTF8CString("Helvetica");
625 static WKStringRef serifFontFamily = WKStringCreateWithUTF8CString("Times");
627 WKPreferencesSetStandardFontFamily(preferences, standardFontFamily);
628 WKPreferencesSetCursiveFontFamily(preferences, cursiveFontFamily);
629 WKPreferencesSetFantasyFontFamily(preferences, fantasyFontFamily);
630 WKPreferencesSetFixedFontFamily(preferences, fixedFontFamily);
631 WKPreferencesSetPictographFontFamily(preferences, pictographFontFamily);
632 WKPreferencesSetSansSerifFontFamily(preferences, sansSerifFontFamily);
633 WKPreferencesSetSerifFontFamily(preferences, serifFontFamily);
634 WKPreferencesSetAsynchronousSpellCheckingEnabled(preferences, false);
635 #if ENABLE(WEB_AUDIO)
636 WKPreferencesSetMediaSourceEnabled(preferences, true);
639 WKPreferencesSetHiddenPageDOMTimerThrottlingEnabled(preferences, false);
640 WKPreferencesSetHiddenPageCSSAnimationSuspensionEnabled(preferences, false);
642 WKPreferencesSetAcceleratedDrawingEnabled(preferences, m_shouldUseAcceleratedDrawing);
643 // FIXME: We should be testing the default.
644 WKPreferencesSetStorageBlockingPolicy(preferences, kWKAllowAllStorage);
646 WKPreferencesSetMediaPlaybackAllowsInline(preferences, true);
647 WKPreferencesSetInlineMediaPlaybackRequiresPlaysInlineAttribute(preferences, false);
649 WKCookieManagerDeleteAllCookies(WKContextGetCookieManager(m_context.get()));
651 platformResetPreferencesToConsistentValues();
654 bool TestController::resetStateToConsistentValues()
656 TemporaryChange<State> changeState(m_state, Resetting);
657 m_beforeUnloadReturnValue = true;
659 // This setting differs between the antique and modern Mac WebKit2 API.
660 // For now, maintain the antique behavior, because some tests depend on it!
661 // FIXME: We should be testing the default.
662 WKPageSetBackgroundExtendsBeyondPage(m_mainWebView->page(), false);
664 WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("Reset"));
665 WKRetainPtr<WKMutableDictionaryRef> resetMessageBody = adoptWK(WKMutableDictionaryCreate());
667 WKRetainPtr<WKStringRef> shouldGCKey = adoptWK(WKStringCreateWithUTF8CString("ShouldGC"));
668 WKRetainPtr<WKBooleanRef> shouldGCValue = adoptWK(WKBooleanCreate(m_gcBetweenTests));
669 WKDictionarySetItem(resetMessageBody.get(), shouldGCKey.get(), shouldGCValue.get());
671 WKRetainPtr<WKStringRef> allowedHostsKey = adoptWK(WKStringCreateWithUTF8CString("AllowedHosts"));
672 WKRetainPtr<WKMutableArrayRef> allowedHostsValue = adoptWK(WKMutableArrayCreate());
673 for (auto& host : m_allowedHosts) {
674 WKRetainPtr<WKStringRef> wkHost = adoptWK(WKStringCreateWithUTF8CString(host.c_str()));
675 WKArrayAppendItem(allowedHostsValue.get(), wkHost.get());
677 WKDictionarySetItem(resetMessageBody.get(), allowedHostsKey.get(), allowedHostsValue.get());
679 WKPagePostMessageToInjectedBundle(TestController::singleton().mainWebView()->page(), messageName.get(), resetMessageBody.get());
681 WKContextSetShouldUseFontSmoothing(TestController::singleton().context(), false);
683 WKContextSetCacheModel(TestController::singleton().context(), kWKCacheModelDocumentBrowser);
685 // FIXME: This function should also ensure that there is only one page open.
687 // Reset the EventSender for each test.
688 m_eventSenderProxy = std::make_unique<EventSenderProxy>(this);
690 // FIXME: Is this needed? Nothing in TestController changes preferences during tests, and if there is
691 // some other code doing this, it should probably be responsible for cleanup too.
692 resetPreferencesToConsistentValues();
695 WKTextCheckerContinuousSpellCheckingEnabledStateChanged(true);
698 // In the case that a test using the chrome input field failed, be sure to clean up for the next test.
699 m_mainWebView->removeChromeInputField();
700 m_mainWebView->focus();
702 // Re-set to the default backing scale factor by setting the custom scale factor to 0.
703 WKPageSetCustomBackingScaleFactor(m_mainWebView->page(), 0);
705 WKPageClearWheelEventTestTrigger(m_mainWebView->page());
708 // EFL use a real window while other ports such as Qt don't.
709 // In EFL, we need to resize the window to the original size after calls to window.resizeTo.
710 WKRect rect = m_mainWebView->windowFrame();
711 m_mainWebView->setWindowFrame(WKRectMake(rect.origin.x, rect.origin.y, TestController::viewWidth, TestController::viewHeight));
714 // Reset notification permissions
715 m_webNotificationProvider.reset();
717 // Reset Geolocation permissions.
718 m_geolocationPermissionRequests.clear();
719 m_isGeolocationPermissionSet = false;
720 m_isGeolocationPermissionAllowed = false;
722 // Reset UserMedia permissions.
723 m_userMediaPermissionRequests.clear();
724 m_isUserMediaPermissionSet = false;
725 m_isUserMediaPermissionAllowed = false;
727 // Reset Custom Policy Delegate.
728 setCustomPolicyDelegate(false, false);
730 m_workQueueManager.clearWorkQueue();
732 m_handlesAuthenticationChallenges = false;
733 m_authenticationUsername = String();
734 m_authenticationPassword = String();
736 m_shouldBlockAllPlugins = false;
738 m_shouldLogHistoryClientCallbacks = false;
742 platformResetStateToConsistentValues();
744 // Reset main page back to about:blank
745 m_doneResetting = false;
747 m_shouldDecideNavigationPolicyAfterDelay = false;
749 setNavigationGesturesEnabled(false);
751 WKPageLoadURL(m_mainWebView->page(), blankURL());
752 runUntil(m_doneResetting, shortTimeout);
753 return m_doneResetting;
756 void TestController::terminateWebContentProcess()
758 WKPageTerminate(m_mainWebView->page());
761 void TestController::reattachPageToWebProcess()
763 // Loading a web page is the only way to reattach an existing page to a process.
764 m_doneResetting = false;
765 WKPageLoadURL(m_mainWebView->page(), blankURL());
766 runUntil(m_doneResetting, shortTimeout);
769 const char* TestController::webProcessName()
771 // FIXME: Find a way to not hardcode the process name.
773 return "com.apple.WebKit.WebContent.Development";
779 const char* TestController::networkProcessName()
781 // FIXME: Find a way to not hardcode the process name.
783 return "com.apple.WebKit.Networking.Development";
785 return "NetworkProcess";
789 static bool shouldUseFixedLayout(const TestInvocation& test)
791 #if ENABLE(CSS_DEVICE_ADAPTATION)
792 if (test.urlContains("device-adapt/") || test.urlContains("device-adapt\\"))
799 static std::string testPath(const WKURLRef url)
801 auto scheme = adoptWK(WKURLCopyScheme(url));
802 if (WKStringIsEqualToUTF8CStringIgnoringCase(scheme.get(), "file")) {
803 auto path = adoptWK(WKURLCopyPath(url));
804 auto buffer = std::vector<char>(WKStringGetMaximumUTF8CStringSize(path.get()));
805 auto length = WKStringGetUTF8CString(path.get(), buffer.data(), buffer.size());
806 return std::string(buffer.data(), length);
808 return std::string();
811 static void updateViewOptionsFromTestHeader(ViewOptions& viewOptions, const TestInvocation& test)
813 std::string filename = testPath(test.url());
814 if (filename.empty())
818 std::ifstream testFile(filename.data());
819 if (!testFile.good())
821 getline(testFile, options);
822 std::string beginString("webkit-test-runner [ ");
823 std::string endString(" ]");
824 size_t beginLocation = options.find(beginString);
825 if (beginLocation == std::string::npos)
827 size_t endLocation = options.find(endString, beginLocation);
828 if (endLocation == std::string::npos) {
829 LOG_ERROR("Could not find end of test header in %s", filename.c_str());
832 std::string pairString = options.substr(beginLocation + beginString.size(), endLocation - (beginLocation + beginString.size()));
833 size_t pairStart = 0;
834 while (pairStart < pairString.size()) {
835 size_t pairEnd = pairString.find(" ", pairStart);
836 if (pairEnd == std::string::npos)
837 pairEnd = pairString.size();
838 size_t equalsLocation = pairString.find("=", pairStart);
839 if (equalsLocation == std::string::npos) {
840 LOG_ERROR("Malformed option in test header (could not find '=' character) in %s", filename.c_str());
843 auto key = pairString.substr(pairStart, equalsLocation - pairStart);
844 auto value = pairString.substr(equalsLocation + 1, pairEnd - (equalsLocation + 1));
845 // Options processing to modify viewOptions goes here.
846 pairStart = pairEnd + 1;
850 ViewOptions TestController::viewOptionsForTest(const TestInvocation& test) const
852 ViewOptions viewOptions;
854 viewOptions.useRemoteLayerTree = m_shouldUseRemoteLayerTree;
855 viewOptions.shouldShowWebView = m_shouldShowWebView;
856 viewOptions.useFixedLayout = shouldUseFixedLayout(test);
858 updateViewOptionsFromTestHeader(viewOptions, test);
860 updatePlatformSpecificViewOptionsForTest(viewOptions, test);
865 void TestController::updateWebViewSizeForTest(const TestInvocation& test)
867 bool isSVGW3CTest = test.urlContains("svg/W3C-SVG-1.1") || test.urlContains("svg\\W3C-SVG-1.1");
869 unsigned width = viewWidth;
870 unsigned height = viewHeight;
872 width = w3cSVGViewWidth;
873 height = w3cSVGViewHeight;
876 mainWebView()->resizeTo(width, height);
879 void TestController::updateWindowScaleForTest(PlatformWebView* view, const TestInvocation& test)
881 bool needsHighDPIWindow = test.urlContains("/hidpi-");
882 view->changeWindowScaleIfNeeded(needsHighDPIWindow ? 2 : 1);
885 void TestController::configureViewForTest(const TestInvocation& test)
887 ensureViewSupportsOptionsForTest(test);
888 updateWebViewSizeForTest(test);
889 updateWindowScaleForTest(mainWebView(), test);
891 platformConfigureViewForTest(test);
895 TestCommand() : shouldDumpPixels(false), timeout(0) { }
897 std::string pathOrURL;
898 bool shouldDumpPixels;
899 std::string expectedPixelHash;
903 class CommandTokenizer {
905 explicit CommandTokenizer(const std::string& input)
907 , m_posNextSeparator(0)
912 bool hasNext() const;
917 static const char kSeparator = '\'';
918 const std::string& m_input;
920 size_t m_posNextSeparator;
923 void CommandTokenizer::pump()
925 if (m_posNextSeparator == std::string::npos || m_posNextSeparator == m_input.size()) {
926 m_next = std::string();
929 size_t start = m_posNextSeparator ? m_posNextSeparator + 1 : 0;
930 m_posNextSeparator = m_input.find(kSeparator, start);
931 size_t size = m_posNextSeparator == std::string::npos ? std::string::npos : m_posNextSeparator - start;
932 m_next = std::string(m_input, start, size);
935 std::string CommandTokenizer::next()
939 std::string oldNext = m_next;
944 bool CommandTokenizer::hasNext() const
946 return !m_next.empty();
949 NO_RETURN static void die(const std::string& inputLine)
951 fprintf(stderr, "Unexpected input line: %s\n", inputLine.c_str());
955 TestCommand parseInputLine(const std::string& inputLine)
958 CommandTokenizer tokenizer(inputLine);
959 if (!tokenizer.hasNext())
962 std::string arg = tokenizer.next();
963 result.pathOrURL = arg;
964 while (tokenizer.hasNext()) {
965 arg = tokenizer.next();
966 if (arg == std::string("--timeout")) {
967 std::string timeoutToken = tokenizer.next();
968 result.timeout = atoi(timeoutToken.c_str());
969 } else if (arg == std::string("-p") || arg == std::string("--pixel-test")) {
970 result.shouldDumpPixels = true;
971 if (tokenizer.hasNext())
972 result.expectedPixelHash = tokenizer.next();
979 bool TestController::runTest(const char* inputLine)
981 TestCommand command = parseInputLine(std::string(inputLine));
983 m_state = RunningTest;
985 m_currentInvocation = std::make_unique<TestInvocation>(command.pathOrURL);
986 if (command.shouldDumpPixels || m_shouldDumpPixelsForAllTests)
987 m_currentInvocation->setIsPixelTest(command.expectedPixelHash);
988 if (command.timeout > 0)
989 m_currentInvocation->setCustomTimeout(command.timeout);
991 platformWillRunTest(*m_currentInvocation);
993 m_currentInvocation->invoke();
994 m_currentInvocation = nullptr;
999 void TestController::runTestingServerLoop()
1001 char filenameBuffer[2048];
1002 while (fgets(filenameBuffer, sizeof(filenameBuffer), stdin)) {
1003 char* newLineCharacter = strchr(filenameBuffer, '\n');
1004 if (newLineCharacter)
1005 *newLineCharacter = '\0';
1007 if (strlen(filenameBuffer) == 0)
1010 if (!runTest(filenameBuffer))
1015 void TestController::run()
1017 if (m_usingServerMode)
1018 runTestingServerLoop();
1020 for (size_t i = 0; i < m_paths.size(); ++i) {
1021 if (!runTest(m_paths[i].c_str()))
1027 void TestController::runUntil(bool& done, double timeout)
1029 if (m_forceNoTimeout)
1030 timeout = noTimeout;
1032 platformRunUntil(done, timeout);
1035 // WKContextInjectedBundleClient
1037 void TestController::didReceiveMessageFromInjectedBundle(WKContextRef context, WKStringRef messageName, WKTypeRef messageBody, const void* clientInfo)
1039 static_cast<TestController*>(const_cast<void*>(clientInfo))->didReceiveMessageFromInjectedBundle(messageName, messageBody);
1042 void TestController::didReceiveSynchronousMessageFromInjectedBundle(WKContextRef context, WKStringRef messageName, WKTypeRef messageBody, WKTypeRef* returnData, const void* clientInfo)
1044 *returnData = static_cast<TestController*>(const_cast<void*>(clientInfo))->didReceiveSynchronousMessageFromInjectedBundle(messageName, messageBody).leakRef();
1047 // WKPageInjectedBundleClient
1049 void TestController::didReceivePageMessageFromInjectedBundle(WKPageRef page, WKStringRef messageName, WKTypeRef messageBody, const void* clientInfo)
1051 static_cast<TestController*>(const_cast<void*>(clientInfo))->didReceiveMessageFromInjectedBundle(messageName, messageBody);
1054 void TestController::didReceiveSynchronousPageMessageFromInjectedBundle(WKPageRef page, WKStringRef messageName, WKTypeRef messageBody, WKTypeRef* returnData, const void* clientInfo)
1056 *returnData = static_cast<TestController*>(const_cast<void*>(clientInfo))->didReceiveSynchronousMessageFromInjectedBundle(messageName, messageBody).leakRef();
1059 void TestController::networkProcessDidCrash(WKContextRef context, const void *clientInfo)
1061 static_cast<TestController*>(const_cast<void*>(clientInfo))->networkProcessDidCrash();
1064 void TestController::didReceiveKeyDownMessageFromInjectedBundle(WKDictionaryRef messageBodyDictionary, bool synchronous)
1066 WKRetainPtr<WKStringRef> keyKey = adoptWK(WKStringCreateWithUTF8CString("Key"));
1067 WKStringRef key = static_cast<WKStringRef>(WKDictionaryGetItemForKey(messageBodyDictionary, keyKey.get()));
1069 WKRetainPtr<WKStringRef> modifiersKey = adoptWK(WKStringCreateWithUTF8CString("Modifiers"));
1070 WKEventModifiers modifiers = static_cast<WKEventModifiers>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, modifiersKey.get()))));
1072 WKRetainPtr<WKStringRef> locationKey = adoptWK(WKStringCreateWithUTF8CString("Location"));
1073 unsigned location = static_cast<unsigned>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, locationKey.get()))));
1075 m_eventSenderProxy->keyDown(key, modifiers, location);
1078 void TestController::didReceiveMessageFromInjectedBundle(WKStringRef messageName, WKTypeRef messageBody)
1080 if (WKStringIsEqualToUTF8CString(messageName, "EventSender")) {
1081 if (m_state != RunningTest)
1084 ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID());
1085 WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody);
1087 WKRetainPtr<WKStringRef> subMessageKey(AdoptWK, WKStringCreateWithUTF8CString("SubMessage"));
1088 WKStringRef subMessageName = static_cast<WKStringRef>(WKDictionaryGetItemForKey(messageBodyDictionary, subMessageKey.get()));
1090 if (WKStringIsEqualToUTF8CString(subMessageName, "MouseDown") || WKStringIsEqualToUTF8CString(subMessageName, "MouseUp")) {
1091 WKRetainPtr<WKStringRef> buttonKey = adoptWK(WKStringCreateWithUTF8CString("Button"));
1092 unsigned button = static_cast<unsigned>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, buttonKey.get()))));
1094 WKRetainPtr<WKStringRef> modifiersKey = adoptWK(WKStringCreateWithUTF8CString("Modifiers"));
1095 WKEventModifiers modifiers = static_cast<WKEventModifiers>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, modifiersKey.get()))));
1097 // Forward to WebProcess
1098 if (WKStringIsEqualToUTF8CString(subMessageName, "MouseDown"))
1099 m_eventSenderProxy->mouseDown(button, modifiers);
1101 m_eventSenderProxy->mouseUp(button, modifiers);
1106 if (WKStringIsEqualToUTF8CString(subMessageName, "KeyDown")) {
1107 didReceiveKeyDownMessageFromInjectedBundle(messageBodyDictionary, false);
1112 if (WKStringIsEqualToUTF8CString(subMessageName, "MouseScrollBy")) {
1113 WKRetainPtr<WKStringRef> xKey = adoptWK(WKStringCreateWithUTF8CString("X"));
1114 double x = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, xKey.get())));
1116 WKRetainPtr<WKStringRef> yKey = adoptWK(WKStringCreateWithUTF8CString("Y"));
1117 double y = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, yKey.get())));
1119 // Forward to WebProcess
1120 m_eventSenderProxy->mouseScrollBy(x, y);
1124 if (WKStringIsEqualToUTF8CString(subMessageName, "MouseScrollByWithWheelAndMomentumPhases")) {
1125 WKRetainPtr<WKStringRef> xKey = adoptWK(WKStringCreateWithUTF8CString("X"));
1126 double x = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, xKey.get())));
1128 WKRetainPtr<WKStringRef> yKey = adoptWK(WKStringCreateWithUTF8CString("Y"));
1129 double y = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, yKey.get())));
1131 WKRetainPtr<WKStringRef> phaseKey = adoptWK(WKStringCreateWithUTF8CString("Phase"));
1132 int phase = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, phaseKey.get()))));
1133 WKRetainPtr<WKStringRef> momentumKey = adoptWK(WKStringCreateWithUTF8CString("Momentum"));
1134 int momentum = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, momentumKey.get()))));
1136 // Forward to WebProcess
1137 m_eventSenderProxy->mouseScrollByWithWheelAndMomentumPhases(x, y, phase, momentum);
1142 if (WKStringIsEqualToUTF8CString(subMessageName, "SwipeGestureWithWheelAndMomentumPhases")) {
1143 WKRetainPtr<WKStringRef> xKey = adoptWK(WKStringCreateWithUTF8CString("X"));
1144 double x = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, xKey.get())));
1146 WKRetainPtr<WKStringRef> yKey = adoptWK(WKStringCreateWithUTF8CString("Y"));
1147 double y = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, yKey.get())));
1149 WKRetainPtr<WKStringRef> phaseKey = adoptWK(WKStringCreateWithUTF8CString("Phase"));
1150 int phase = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, phaseKey.get()))));
1151 WKRetainPtr<WKStringRef> momentumKey = adoptWK(WKStringCreateWithUTF8CString("Momentum"));
1152 int momentum = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, momentumKey.get()))));
1154 m_eventSenderProxy->swipeGestureWithWheelAndMomentumPhases(x, y, phase, momentum);
1159 ASSERT_NOT_REACHED();
1162 if (!m_currentInvocation)
1165 m_currentInvocation->didReceiveMessageFromInjectedBundle(messageName, messageBody);
1168 WKRetainPtr<WKTypeRef> TestController::didReceiveSynchronousMessageFromInjectedBundle(WKStringRef messageName, WKTypeRef messageBody)
1170 if (WKStringIsEqualToUTF8CString(messageName, "EventSender")) {
1171 if (m_state != RunningTest)
1174 ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID());
1175 WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody);
1177 WKRetainPtr<WKStringRef> subMessageKey(AdoptWK, WKStringCreateWithUTF8CString("SubMessage"));
1178 WKStringRef subMessageName = static_cast<WKStringRef>(WKDictionaryGetItemForKey(messageBodyDictionary, subMessageKey.get()));
1180 if (WKStringIsEqualToUTF8CString(subMessageName, "KeyDown")) {
1181 didReceiveKeyDownMessageFromInjectedBundle(messageBodyDictionary, true);
1186 if (WKStringIsEqualToUTF8CString(subMessageName, "MouseDown") || WKStringIsEqualToUTF8CString(subMessageName, "MouseUp")) {
1187 WKRetainPtr<WKStringRef> buttonKey = adoptWK(WKStringCreateWithUTF8CString("Button"));
1188 unsigned button = static_cast<unsigned>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, buttonKey.get()))));
1190 WKRetainPtr<WKStringRef> modifiersKey = adoptWK(WKStringCreateWithUTF8CString("Modifiers"));
1191 WKEventModifiers modifiers = static_cast<WKEventModifiers>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, modifiersKey.get()))));
1193 // Forward to WebProcess
1194 if (WKStringIsEqualToUTF8CString(subMessageName, "MouseDown"))
1195 m_eventSenderProxy->mouseDown(button, modifiers);
1197 m_eventSenderProxy->mouseUp(button, modifiers);
1201 if (WKStringIsEqualToUTF8CString(subMessageName, "MouseMoveTo")) {
1202 WKRetainPtr<WKStringRef> xKey = adoptWK(WKStringCreateWithUTF8CString("X"));
1203 double x = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, xKey.get())));
1205 WKRetainPtr<WKStringRef> yKey = adoptWK(WKStringCreateWithUTF8CString("Y"));
1206 double y = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, yKey.get())));
1208 // Forward to WebProcess
1209 m_eventSenderProxy->mouseMoveTo(x, y);
1214 if (WKStringIsEqualToUTF8CString(subMessageName, "MouseForceClick")) {
1215 m_eventSenderProxy->mouseForceClick();
1219 if (WKStringIsEqualToUTF8CString(subMessageName, "StartAndCancelMouseForceClick")) {
1220 m_eventSenderProxy->startAndCancelMouseForceClick();
1224 if (WKStringIsEqualToUTF8CString(subMessageName, "MouseForceDown")) {
1225 m_eventSenderProxy->mouseForceDown();
1229 if (WKStringIsEqualToUTF8CString(subMessageName, "MouseForceUp")) {
1230 m_eventSenderProxy->mouseForceUp();
1234 if (WKStringIsEqualToUTF8CString(subMessageName, "MouseForceChanged")) {
1235 WKRetainPtr<WKStringRef> forceKey = adoptWK(WKStringCreateWithUTF8CString("Force"));
1236 double force = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, forceKey.get())));
1238 m_eventSenderProxy->mouseForceChanged(force);
1241 #endif // PLATFORM(MAC)
1243 if (WKStringIsEqualToUTF8CString(subMessageName, "ContinuousMouseScrollBy")) {
1244 WKRetainPtr<WKStringRef> xKey = adoptWK(WKStringCreateWithUTF8CString("X"));
1245 double x = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, xKey.get())));
1247 WKRetainPtr<WKStringRef> yKey = adoptWK(WKStringCreateWithUTF8CString("Y"));
1248 double y = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, yKey.get())));
1250 WKRetainPtr<WKStringRef> pagedKey = adoptWK(WKStringCreateWithUTF8CString("Paged"));
1251 bool paged = static_cast<bool>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, pagedKey.get()))));
1253 // Forward to WebProcess
1254 m_eventSenderProxy->continuousMouseScrollBy(x, y, paged);
1258 if (WKStringIsEqualToUTF8CString(subMessageName, "LeapForward")) {
1259 WKRetainPtr<WKStringRef> timeKey = adoptWK(WKStringCreateWithUTF8CString("TimeInMilliseconds"));
1260 unsigned time = static_cast<unsigned>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, timeKey.get()))));
1262 m_eventSenderProxy->leapForward(time);
1266 #if ENABLE(TOUCH_EVENTS)
1267 if (WKStringIsEqualToUTF8CString(subMessageName, "AddTouchPoint")) {
1268 WKRetainPtr<WKStringRef> xKey = adoptWK(WKStringCreateWithUTF8CString("X"));
1269 int x = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, xKey.get()))));
1271 WKRetainPtr<WKStringRef> yKey = adoptWK(WKStringCreateWithUTF8CString("Y"));
1272 int y = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, yKey.get()))));
1274 m_eventSenderProxy->addTouchPoint(x, y);
1278 if (WKStringIsEqualToUTF8CString(subMessageName, "UpdateTouchPoint")) {
1279 WKRetainPtr<WKStringRef> indexKey = adoptWK(WKStringCreateWithUTF8CString("Index"));
1280 int index = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, indexKey.get()))));
1282 WKRetainPtr<WKStringRef> xKey = adoptWK(WKStringCreateWithUTF8CString("X"));
1283 int x = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, xKey.get()))));
1285 WKRetainPtr<WKStringRef> yKey = adoptWK(WKStringCreateWithUTF8CString("Y"));
1286 int y = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, yKey.get()))));
1288 m_eventSenderProxy->updateTouchPoint(index, x, y);
1292 if (WKStringIsEqualToUTF8CString(subMessageName, "SetTouchModifier")) {
1293 WKRetainPtr<WKStringRef> modifierKey = adoptWK(WKStringCreateWithUTF8CString("Modifier"));
1294 WKEventModifiers modifier = static_cast<WKEventModifiers>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, modifierKey.get()))));
1296 WKRetainPtr<WKStringRef> enableKey = adoptWK(WKStringCreateWithUTF8CString("Enable"));
1297 bool enable = static_cast<bool>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, enableKey.get()))));
1299 m_eventSenderProxy->setTouchModifier(modifier, enable);
1303 if (WKStringIsEqualToUTF8CString(subMessageName, "SetTouchPointRadius")) {
1304 WKRetainPtr<WKStringRef> xKey = adoptWK(WKStringCreateWithUTF8CString("RadiusX"));
1305 int x = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, xKey.get()))));
1307 WKRetainPtr<WKStringRef> yKey = adoptWK(WKStringCreateWithUTF8CString("RadiusY"));
1308 int y = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, yKey.get()))));
1310 m_eventSenderProxy->setTouchPointRadius(x, y);
1314 if (WKStringIsEqualToUTF8CString(subMessageName, "TouchStart")) {
1315 m_eventSenderProxy->touchStart();
1319 if (WKStringIsEqualToUTF8CString(subMessageName, "TouchMove")) {
1320 m_eventSenderProxy->touchMove();
1324 if (WKStringIsEqualToUTF8CString(subMessageName, "TouchEnd")) {
1325 m_eventSenderProxy->touchEnd();
1329 if (WKStringIsEqualToUTF8CString(subMessageName, "TouchCancel")) {
1330 m_eventSenderProxy->touchCancel();
1334 if (WKStringIsEqualToUTF8CString(subMessageName, "ClearTouchPoints")) {
1335 m_eventSenderProxy->clearTouchPoints();
1339 if (WKStringIsEqualToUTF8CString(subMessageName, "ReleaseTouchPoint")) {
1340 WKRetainPtr<WKStringRef> indexKey = adoptWK(WKStringCreateWithUTF8CString("Index"));
1341 int index = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, indexKey.get()))));
1342 m_eventSenderProxy->releaseTouchPoint(index);
1346 if (WKStringIsEqualToUTF8CString(subMessageName, "CancelTouchPoint")) {
1347 WKRetainPtr<WKStringRef> indexKey = adoptWK(WKStringCreateWithUTF8CString("Index"));
1348 int index = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, indexKey.get()))));
1349 m_eventSenderProxy->cancelTouchPoint(index);
1353 ASSERT_NOT_REACHED();
1355 return m_currentInvocation->didReceiveSynchronousMessageFromInjectedBundle(messageName, messageBody);
1360 void TestController::networkProcessDidCrash()
1363 pid_t pid = WKContextGetNetworkProcessIdentifier(m_context.get());
1364 fprintf(stderr, "#CRASHED - %s (pid %ld)\n", networkProcessName(), static_cast<long>(pid));
1366 fprintf(stderr, "#CRASHED - %s\n", networkProcessName());
1371 // WKPageNavigationClient
1373 void TestController::didCommitNavigation(WKPageRef page, WKNavigationRef navigation, WKTypeRef, const void* clientInfo)
1375 static_cast<TestController*>(const_cast<void*>(clientInfo))->didCommitNavigation(page, navigation);
1378 void TestController::didFinishNavigation(WKPageRef page, WKNavigationRef navigation, WKTypeRef, const void* clientInfo)
1380 static_cast<TestController*>(const_cast<void*>(clientInfo))->didFinishNavigation(page, navigation);
1383 bool TestController::canAuthenticateAgainstProtectionSpace(WKPageRef, WKProtectionSpaceRef protectionSpace, const void*)
1385 WKProtectionSpaceAuthenticationScheme authenticationScheme = WKProtectionSpaceGetAuthenticationScheme(protectionSpace);
1387 if (authenticationScheme == kWKProtectionSpaceAuthenticationSchemeServerTrustEvaluationRequested) {
1388 std::string host = toSTD(adoptWK(WKProtectionSpaceCopyHost(protectionSpace)).get());
1389 return host == "localhost" || host == "127.0.0.1";
1392 return authenticationScheme <= kWKProtectionSpaceAuthenticationSchemeHTTPDigest;
1395 void TestController::didReceiveAuthenticationChallenge(WKPageRef page, WKAuthenticationChallengeRef authenticationChallenge, const void *clientInfo)
1397 static_cast<TestController*>(const_cast<void*>(clientInfo))->didReceiveAuthenticationChallenge(page, /*frame,*/ authenticationChallenge);
1400 void TestController::processDidCrash(WKPageRef page, const void* clientInfo)
1402 static_cast<TestController*>(const_cast<void*>(clientInfo))->processDidCrash();
1405 void TestController::didBeginNavigationGesture(WKPageRef page, const void *clientInfo)
1407 static_cast<TestController*>(const_cast<void*>(clientInfo))->didBeginNavigationGesture(page);
1410 void TestController::willEndNavigationGesture(WKPageRef page, WKBackForwardListItemRef backForwardListItem, const void *clientInfo)
1412 static_cast<TestController*>(const_cast<void*>(clientInfo))->willEndNavigationGesture(page, backForwardListItem);
1415 void TestController::didEndNavigationGesture(WKPageRef page, WKBackForwardListItemRef backForwardListItem, const void *clientInfo)
1417 static_cast<TestController*>(const_cast<void*>(clientInfo))->didEndNavigationGesture(page, backForwardListItem);
1420 void TestController::didRemoveNavigationGestureSnapshot(WKPageRef page, const void *clientInfo)
1422 static_cast<TestController*>(const_cast<void*>(clientInfo))->didRemoveNavigationGestureSnapshot(page);
1425 WKPluginLoadPolicy TestController::decidePolicyForPluginLoad(WKPageRef page, WKPluginLoadPolicy currentPluginLoadPolicy, WKDictionaryRef pluginInformation, WKStringRef* unavailabilityDescription, const void* clientInfo)
1427 return static_cast<TestController*>(const_cast<void*>(clientInfo))->decidePolicyForPluginLoad(page, currentPluginLoadPolicy, pluginInformation, unavailabilityDescription);
1430 WKPluginLoadPolicy TestController::decidePolicyForPluginLoad(WKPageRef, WKPluginLoadPolicy currentPluginLoadPolicy, WKDictionaryRef pluginInformation, WKStringRef* unavailabilityDescription)
1432 if (m_shouldBlockAllPlugins)
1433 return kWKPluginLoadPolicyBlocked;
1436 WKStringRef bundleIdentifier = (WKStringRef)WKDictionaryGetItemForKey(pluginInformation, WKPluginInformationBundleIdentifierKey());
1437 if (!bundleIdentifier)
1438 return currentPluginLoadPolicy;
1440 if (WKStringIsEqualToUTF8CString(bundleIdentifier, "com.apple.QuickTime Plugin.plugin"))
1441 return currentPluginLoadPolicy;
1443 if (WKStringIsEqualToUTF8CString(bundleIdentifier, "com.apple.testnetscapeplugin"))
1444 return currentPluginLoadPolicy;
1446 RELEASE_ASSERT_NOT_REACHED(); // Please don't use any other plug-ins in tests, as they will not be installed on all machines.
1448 return currentPluginLoadPolicy;
1452 void TestController::didCommitNavigation(WKPageRef page, WKNavigationRef navigation)
1454 mainWebView()->focus();
1457 void TestController::didFinishNavigation(WKPageRef page, WKNavigationRef navigation)
1459 if (m_state != Resetting)
1462 WKRetainPtr<WKURLRef> wkURL(AdoptWK, WKFrameCopyURL(WKPageGetMainFrame(page)));
1463 if (!WKURLIsEqual(wkURL.get(), blankURL()))
1466 m_doneResetting = true;
1467 singleton().notifyDone();
1470 void TestController::didReceiveAuthenticationChallenge(WKPageRef page, WKAuthenticationChallengeRef authenticationChallenge)
1472 WKProtectionSpaceRef protectionSpace = WKAuthenticationChallengeGetProtectionSpace(authenticationChallenge);
1473 WKAuthenticationDecisionListenerRef decisionListener = WKAuthenticationChallengeGetDecisionListener(authenticationChallenge);
1475 if (WKProtectionSpaceGetAuthenticationScheme(protectionSpace) == kWKProtectionSpaceAuthenticationSchemeServerTrustEvaluationRequested) {
1476 // Any non-empty credential signals to accept the server trust. Since the cross-platform API
1477 // doesn't expose a way to create a credential from server trust, we use a password credential.
1479 WKRetainPtr<WKCredentialRef> credential = adoptWK(WKCredentialCreate(toWK("accept server trust").get(), toWK("").get(), kWKCredentialPersistenceNone));
1480 WKAuthenticationDecisionListenerUseCredential(decisionListener, credential.get());
1484 std::string host = toSTD(adoptWK(WKProtectionSpaceCopyHost(protectionSpace)).get());
1485 int port = WKProtectionSpaceGetPort(protectionSpace);
1486 String message = String::format("%s:%d - didReceiveAuthenticationChallenge - ", host.c_str(), port);
1487 if (!m_handlesAuthenticationChallenges)
1488 message.append("Simulating cancelled authentication sheet\n");
1490 message.append(String::format("Responding with %s:%s\n", m_authenticationUsername.utf8().data(), m_authenticationPassword.utf8().data()));
1491 m_currentInvocation->outputText(message);
1493 if (!m_handlesAuthenticationChallenges) {
1494 WKAuthenticationDecisionListenerUseCredential(decisionListener, 0);
1497 WKRetainPtr<WKStringRef> username(AdoptWK, WKStringCreateWithUTF8CString(m_authenticationUsername.utf8().data()));
1498 WKRetainPtr<WKStringRef> password(AdoptWK, WKStringCreateWithUTF8CString(m_authenticationPassword.utf8().data()));
1499 WKRetainPtr<WKCredentialRef> credential(AdoptWK, WKCredentialCreate(username.get(), password.get(), kWKCredentialPersistenceForSession));
1500 WKAuthenticationDecisionListenerUseCredential(decisionListener, credential.get());
1503 void TestController::processDidCrash()
1505 // This function can be called multiple times when crash logs are being saved on Windows, so
1506 // ensure we only print the crashed message once.
1507 if (!m_didPrintWebProcessCrashedMessage) {
1509 pid_t pid = WKPageGetProcessIdentifier(m_mainWebView->page());
1510 fprintf(stderr, "#CRASHED - %s (pid %ld)\n", webProcessName(), static_cast<long>(pid));
1512 fprintf(stderr, "#CRASHED - %s\n", webProcessName());
1515 m_didPrintWebProcessCrashedMessage = true;
1518 if (m_shouldExitWhenWebProcessCrashes)
1522 void TestController::didBeginNavigationGesture(WKPageRef)
1524 m_currentInvocation->didBeginSwipe();
1527 void TestController::willEndNavigationGesture(WKPageRef, WKBackForwardListItemRef)
1529 m_currentInvocation->willEndSwipe();
1532 void TestController::didEndNavigationGesture(WKPageRef, WKBackForwardListItemRef)
1534 m_currentInvocation->didEndSwipe();
1537 void TestController::didRemoveNavigationGestureSnapshot(WKPageRef)
1539 m_currentInvocation->didRemoveSwipeSnapshot();
1542 void TestController::simulateWebNotificationClick(uint64_t notificationID)
1544 m_webNotificationProvider.simulateWebNotificationClick(notificationID);
1547 void TestController::setGeolocationPermission(bool enabled)
1549 m_isGeolocationPermissionSet = true;
1550 m_isGeolocationPermissionAllowed = enabled;
1551 decidePolicyForGeolocationPermissionRequestIfPossible();
1554 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)
1556 m_geolocationProvider->setPosition(latitude, longitude, accuracy, providesAltitude, altitude, providesAltitudeAccuracy, altitudeAccuracy, providesHeading, heading, providesSpeed, speed);
1559 void TestController::setMockGeolocationPositionUnavailableError(WKStringRef errorMessage)
1561 m_geolocationProvider->setPositionUnavailableError(errorMessage);
1564 void TestController::handleGeolocationPermissionRequest(WKGeolocationPermissionRequestRef geolocationPermissionRequest)
1566 m_geolocationPermissionRequests.append(geolocationPermissionRequest);
1567 decidePolicyForGeolocationPermissionRequestIfPossible();
1570 bool TestController::isGeolocationProviderActive() const
1572 return m_geolocationProvider->isActive();
1575 void TestController::setUserMediaPermission(bool enabled)
1577 m_isUserMediaPermissionSet = true;
1578 m_isUserMediaPermissionAllowed = enabled;
1579 decidePolicyForUserMediaPermissionRequestIfPossible();
1582 void TestController::handleUserMediaPermissionRequest(WKUserMediaPermissionRequestRef userMediaPermissionRequest)
1584 m_userMediaPermissionRequests.append(userMediaPermissionRequest);
1585 decidePolicyForUserMediaPermissionRequestIfPossible();
1588 void TestController::decidePolicyForUserMediaPermissionRequestIfPossible()
1590 if (!m_isUserMediaPermissionSet)
1593 for (auto& request : m_userMediaPermissionRequests) {
1594 if (m_isUserMediaPermissionAllowed) {
1595 if (WKArrayGetSize(WKUserMediaPermissionRequestDeviceNamesVideo(request.get())) || WKArrayGetSize(WKUserMediaPermissionRequestDeviceNamesAudio(request.get())))
1596 WKUserMediaPermissionRequestAllow(request.get(), WKUserMediaPermissionRequestFirstVideoDeviceUID(request.get()), WKUserMediaPermissionRequestFirstAudioDeviceUID(request.get()));
1598 WKUserMediaPermissionRequestDeny(request.get());
1600 m_userMediaPermissionRequests.clear();
1603 void TestController::setCustomPolicyDelegate(bool enabled, bool permissive)
1605 m_policyDelegateEnabled = enabled;
1606 m_policyDelegatePermissive = permissive;
1609 void TestController::decidePolicyForGeolocationPermissionRequestIfPossible()
1611 if (!m_isGeolocationPermissionSet)
1614 for (size_t i = 0; i < m_geolocationPermissionRequests.size(); ++i) {
1615 WKGeolocationPermissionRequestRef permissionRequest = m_geolocationPermissionRequests[i].get();
1616 if (m_isGeolocationPermissionAllowed)
1617 WKGeolocationPermissionRequestAllow(permissionRequest);
1619 WKGeolocationPermissionRequestDeny(permissionRequest);
1621 m_geolocationPermissionRequests.clear();
1624 void TestController::decidePolicyForNotificationPermissionRequest(WKPageRef page, WKSecurityOriginRef origin, WKNotificationPermissionRequestRef request, const void*)
1626 TestController::singleton().decidePolicyForNotificationPermissionRequest(page, origin, request);
1629 void TestController::decidePolicyForNotificationPermissionRequest(WKPageRef, WKSecurityOriginRef, WKNotificationPermissionRequestRef request)
1631 WKNotificationPermissionRequestAllow(request);
1634 void TestController::unavailablePluginButtonClicked(WKPageRef, WKPluginUnavailabilityReason, WKDictionaryRef, const void*)
1636 printf("MISSING PLUGIN BUTTON PRESSED\n");
1639 void TestController::decidePolicyForNavigationAction(WKPageRef, WKNavigationActionRef navigationAction, WKFramePolicyListenerRef listener, WKTypeRef, const void* clientInfo)
1641 static_cast<TestController*>(const_cast<void*>(clientInfo))->decidePolicyForNavigationAction(listener);
1644 void TestController::decidePolicyForNavigationAction(WKFramePolicyListenerRef listener)
1646 WKRetainPtr<WKFramePolicyListenerRef> retainedListener { listener };
1647 const bool shouldIgnore { m_policyDelegateEnabled && !m_policyDelegatePermissive };
1648 std::function<void()> decisionFunction = [shouldIgnore, retainedListener]() {
1650 WKFramePolicyListenerIgnore(retainedListener.get());
1652 WKFramePolicyListenerUse(retainedListener.get());
1655 if (m_shouldDecideNavigationPolicyAfterDelay)
1656 RunLoop::main().dispatch(decisionFunction);
1661 void TestController::decidePolicyForNavigationResponse(WKPageRef, WKNavigationResponseRef navigationResponse, WKFramePolicyListenerRef listener, WKTypeRef, const void* clientInfo)
1663 static_cast<TestController*>(const_cast<void*>(clientInfo))->decidePolicyForNavigationResponse(navigationResponse, listener);
1666 void TestController::decidePolicyForNavigationResponse(WKNavigationResponseRef navigationResponse, WKFramePolicyListenerRef listener)
1668 // Even though Response was already checked by WKBundlePagePolicyClient, the check did not include plugins
1669 // so we have to re-check again.
1670 if (WKNavigationResponseCanShowMIMEType(navigationResponse)) {
1671 WKFramePolicyListenerUse(listener);
1675 WKFramePolicyListenerIgnore(listener);
1678 void TestController::didNavigateWithNavigationData(WKContextRef, WKPageRef, WKNavigationDataRef navigationData, WKFrameRef frame, const void* clientInfo)
1680 static_cast<TestController*>(const_cast<void*>(clientInfo))->didNavigateWithNavigationData(navigationData, frame);
1683 void TestController::didNavigateWithNavigationData(WKNavigationDataRef navigationData, WKFrameRef)
1685 if (m_state != RunningTest)
1688 if (!m_shouldLogHistoryClientCallbacks)
1692 WKRetainPtr<WKURLRef> urlWK = adoptWK(WKNavigationDataCopyURL(navigationData));
1693 WKRetainPtr<WKStringRef> urlStringWK = adoptWK(WKURLCopyString(urlWK.get()));
1695 WKRetainPtr<WKStringRef> titleWK = adoptWK(WKNavigationDataCopyTitle(navigationData));
1697 WKRetainPtr<WKURLRequestRef> requestWK = adoptWK(WKNavigationDataCopyOriginalRequest(navigationData));
1698 WKRetainPtr<WKStringRef> methodWK = adoptWK(WKURLRequestCopyHTTPMethod(requestWK.get()));
1700 // FIXME: Determine whether the navigation was successful / a client redirect rather than hard-coding the message here.
1701 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",
1702 toSTD(urlStringWK).c_str(), toSTD(titleWK).c_str(), toSTD(methodWK).c_str()));
1705 void TestController::didPerformClientRedirect(WKContextRef, WKPageRef, WKURLRef sourceURL, WKURLRef destinationURL, WKFrameRef frame, const void* clientInfo)
1707 static_cast<TestController*>(const_cast<void*>(clientInfo))->didPerformClientRedirect(sourceURL, destinationURL, frame);
1710 void TestController::didPerformClientRedirect(WKURLRef sourceURL, WKURLRef destinationURL, WKFrameRef)
1712 if (m_state != RunningTest)
1715 if (!m_shouldLogHistoryClientCallbacks)
1718 WKRetainPtr<WKStringRef> sourceStringWK = adoptWK(WKURLCopyString(sourceURL));
1719 WKRetainPtr<WKStringRef> destinationStringWK = adoptWK(WKURLCopyString(destinationURL));
1721 m_currentInvocation->outputText(String::format("WebView performed a client redirect from \"%s\" to \"%s\".\n", toSTD(sourceStringWK).c_str(), toSTD(destinationStringWK).c_str()));
1724 void TestController::didPerformServerRedirect(WKContextRef, WKPageRef, WKURLRef sourceURL, WKURLRef destinationURL, WKFrameRef frame, const void* clientInfo)
1726 static_cast<TestController*>(const_cast<void*>(clientInfo))->didPerformServerRedirect(sourceURL, destinationURL, frame);
1729 void TestController::didPerformServerRedirect(WKURLRef sourceURL, WKURLRef destinationURL, WKFrameRef)
1731 if (m_state != RunningTest)
1734 if (!m_shouldLogHistoryClientCallbacks)
1737 WKRetainPtr<WKStringRef> sourceStringWK = adoptWK(WKURLCopyString(sourceURL));
1738 WKRetainPtr<WKStringRef> destinationStringWK = adoptWK(WKURLCopyString(destinationURL));
1740 m_currentInvocation->outputText(String::format("WebView performed a server redirect from \"%s\" to \"%s\".\n", toSTD(sourceStringWK).c_str(), toSTD(destinationStringWK).c_str()));
1743 void TestController::didUpdateHistoryTitle(WKContextRef, WKPageRef, WKStringRef title, WKURLRef URL, WKFrameRef frame, const void* clientInfo)
1745 static_cast<TestController*>(const_cast<void*>(clientInfo))->didUpdateHistoryTitle(title, URL, frame);
1748 void TestController::didUpdateHistoryTitle(WKStringRef title, WKURLRef URL, WKFrameRef)
1750 if (m_state != RunningTest)
1753 if (!m_shouldLogHistoryClientCallbacks)
1756 WKRetainPtr<WKStringRef> urlStringWK(AdoptWK, WKURLCopyString(URL));
1757 m_currentInvocation->outputText(String::format("WebView updated the title for history URL \"%s\" to \"%s\".\n", toSTD(urlStringWK).c_str(), toSTD(title).c_str()));
1760 void TestController::setNavigationGesturesEnabled(bool value)
1762 m_mainWebView->setNavigationGesturesEnabled(value);
1765 #if !PLATFORM(COCOA)
1766 void TestController::platformWillRunTest(const TestInvocation&)
1770 void TestController::platformCreateWebView(WKPageConfigurationRef configuration, const ViewOptions& options)
1772 m_mainWebView = std::make_unique<PlatformWebView>(configuration, options);
1775 PlatformWebView* TestController::platformCreateOtherPage(PlatformWebView* parentView, WKPageConfigurationRef configuration, const ViewOptions& options)
1777 return new PlatformWebView(configuration, options);
1780 WKContextRef TestController::platformAdjustContext(WKContextRef context, WKContextConfigurationRef contextConfiguration)
1785 void TestController::platformResetStateToConsistentValues()