Multiple File Input Icon Set Regardless of File List
[WebKit-https.git] / Tools / WebKitTestRunner / TestController.cpp
index 10aebcf..196792f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010-2018 Apple Inc. All rights reserved.
+ * Copyright (C) 2010-2019 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -45,6 +45,7 @@
 #include <WebKit/WKIconDatabase.h>
 #include <WebKit/WKMockDisplay.h>
 #include <WebKit/WKMockMediaDevice.h>
+#include <WebKit/WKNavigationActionRef.h>
 #include <WebKit/WKNavigationResponseRef.h>
 #include <WebKit/WKNotification.h>
 #include <WebKit/WKNotificationManager.h>
@@ -60,6 +61,7 @@
 #include <WebKit/WKRetainPtr.h>
 #include <WebKit/WKSecurityOriginRef.h>
 #include <WebKit/WKTextChecker.h>
+#include <WebKit/WKURL.h>
 #include <WebKit/WKUserContentControllerRef.h>
 #include <WebKit/WKUserContentExtensionStoreRef.h>
 #include <WebKit/WKUserMediaPermissionCheck.h>
@@ -198,13 +200,29 @@ static void runOpenPanel(WKPageRef page, WKFrameRef frame, WKOpenPanelParameters
         WKOpenPanelResultListenerCancel(resultListenerRef);
         return;
     }
+    
+    WKTypeRef firstItem = WKArrayGetItemAtIndex(fileURLs, 0);
+    
+#if PLATFORM(IOS_FAMILY)
+    WKStringRef displayString = WKURLCopyLastPathComponent(static_cast<WKURLRef>(firstItem));
+    WKDataRef mediaIcon = TestController::singleton().openPanelFileURLsMediaIcon();
+    
+    if (mediaIcon) {
+        if (WKOpenPanelParametersGetAllowsMultipleFiles(parameters)) {
+            WKOpenPanelResultListenerChooseMediaFiles(resultListenerRef, fileURLs, displayString, mediaIcon);
+            return;
+        }
+        
+        WKOpenPanelResultListenerChooseMediaFiles(resultListenerRef, adoptWK(WKArrayCreate(&firstItem, 1)).get(), displayString, mediaIcon);
+        return;
+    }
+#endif
 
     if (WKOpenPanelParametersGetAllowsMultipleFiles(parameters)) {
         WKOpenPanelResultListenerChooseFiles(resultListenerRef, fileURLs);
         return;
     }
 
-    WKTypeRef firstItem = WKArrayGetItemAtIndex(fileURLs, 0);
     WKOpenPanelResultListenerChooseFiles(resultListenerRef, adoptWK(WKArrayCreate(&firstItem, 1)).get());
 }
 
@@ -261,6 +279,17 @@ static void requestPointerLock(WKPageRef page, const void*)
     WKPageDidAllowPointerLock(page);
 }
 
+static void printFrame(WKPageRef page, WKFrameRef frame, const void*)
+{
+    WKPageBeginPrinting(page, frame, WKPrintInfo { 1, 21, 29.7f });
+    WKPageEndPrinting(page);
+}
+
+static bool shouldAllowDeviceOrientationAndMotionAccess(WKPageRef, WKSecurityOriginRef origin, const void*)
+{
+    return TestController::singleton().handleDeviceOrientationAndMotionAccessRequest(origin);
+}
+
 WKPageRef TestController::createOtherPage(WKPageRef, WKPageConfigurationRef configuration, WKNavigationActionRef navigationAction, WKWindowFeaturesRef windowFeatures, const void *clientInfo)
 {
     PlatformWebView* parentView = static_cast<PlatformWebView*>(const_cast<void*>(clientInfo));
@@ -314,7 +343,7 @@ WKPageRef TestController::createOtherPage(PlatformWebView* parentView, WKPageCon
         0, // footerHeight
         0, // drawHeader
         0, // drawFooter
-        0, // printFrame
+        printFrame,
         runModal,
         0, // didCompleteRubberBandForMainFrame
         0, // saveDataToFileInDownloadsFolder
@@ -450,17 +479,30 @@ void TestController::initialize(int argc, const char* argv[])
     WebCoreTestSupport::installMockGamepadProvider();
 #endif
 
-    WKRetainPtr<WKStringRef> pageGroupIdentifier(AdoptWK, WKStringCreateWithUTF8CString("WebKitTestRunnerPageGroup"));
+    WKRetainPtr<WKStringRef> pageGroupIdentifier = adoptWK(WKStringCreateWithUTF8CString("WebKitTestRunnerPageGroup"));
     m_pageGroup.adopt(WKPageGroupCreateWithIdentifier(pageGroupIdentifier.get()));
+
+    m_eventSenderProxy = std::make_unique<EventSenderProxy>(this);
 }
 
-WKRetainPtr<WKContextConfigurationRef> TestController::generateContextConfiguration(const TestOptions& options) const
+WKRetainPtr<WKContextConfigurationRef> TestController::generateContextConfiguration(const TestOptions::ContextOptions& options) const
 {
     auto configuration = adoptWK(WKContextConfigurationCreate());
     WKContextConfigurationSetInjectedBundlePath(configuration.get(), injectedBundlePath());
     WKContextConfigurationSetFullySynchronousModeIsAllowedForTesting(configuration.get(), true);
     WKContextConfigurationSetIgnoreSynchronousMessagingTimeoutsForTesting(configuration.get(), options.ignoreSynchronousMessagingTimeouts);
 
+    WKRetainPtr<WKMutableArrayRef> overrideLanguages = adoptWK(WKMutableArrayCreate());
+    for (auto& language : options.overrideLanguages)
+        WKArrayAppendItem(overrideLanguages.get(), adoptWK(WKStringCreateWithUTF8CString(language.utf8().data())).get());
+    WKContextConfigurationSetOverrideLanguages(configuration.get(), overrideLanguages.get());
+
+    if (options.shouldEnableProcessSwapOnNavigation()) {
+        WKContextConfigurationSetProcessSwapsOnNavigation(configuration.get(), true);
+        if (options.enableProcessSwapOnWindowOpen)
+            WKContextConfigurationSetProcessSwapsOnWindowOpenWithOpener(configuration.get(), true);
+    }
+
     if (const char* dumpRenderTreeTemp = libraryPathForTesting()) {
         String temporaryFolder = String::fromUTF8(dumpRenderTreeTemp);
 
@@ -475,29 +517,33 @@ WKRetainPtr<WKContextConfigurationRef> TestController::generateContextConfigurat
     return configuration;
 }
 
-WKRetainPtr<WKPageConfigurationRef> TestController::generatePageConfiguration(WKContextConfigurationRef configuration)
+WKRetainPtr<WKPageConfigurationRef> TestController::generatePageConfiguration(const TestOptions& options)
 {
-    m_context = platformAdjustContext(adoptWK(WKContextCreateWithConfiguration(configuration)).get(), configuration);
+    if (!m_context || !m_contextOptions->hasSameInitializationOptions(options.contextOptions)) {
+        auto contextConfiguration = generateContextConfiguration(options.contextOptions);
+        m_context = platformAdjustContext(adoptWK(WKContextCreateWithConfiguration(contextConfiguration.get())).get(), contextConfiguration.get());
+        m_contextOptions = options.contextOptions;
 
-    m_geolocationProvider = std::make_unique<GeolocationProviderMock>(m_context.get());
+        m_geolocationProvider = std::make_unique<GeolocationProviderMock>(m_context.get());
 
-    if (const char* dumpRenderTreeTemp = libraryPathForTesting()) {
-        String temporaryFolder = String::fromUTF8(dumpRenderTreeTemp);
+        if (const char* dumpRenderTreeTemp = libraryPathForTesting()) {
+            String temporaryFolder = String::fromUTF8(dumpRenderTreeTemp);
 
-        // FIXME: This should be migrated to WKContextConfigurationRef.
-        // Disable icon database to avoid fetching <http://127.0.0.1:8000/favicon.ico> and making tests flaky.
-        // Invividual tests can enable it using testRunner.setIconDatabaseEnabled, although it's not currently supported in WebKitTestRunner.
-        WKContextSetIconDatabasePath(m_context.get(), toWK(emptyString()).get());
-    }
+            // FIXME: This should be migrated to WKContextConfigurationRef.
+            // Disable icon database to avoid fetching <http://127.0.0.1:8000/favicon.ico> and making tests flaky.
+            // Invividual tests can enable it using testRunner.setIconDatabaseEnabled, although it's not currently supported in WebKitTestRunner.
+            WKContextSetIconDatabasePath(m_context.get(), toWK(emptyString()).get());
+        }
 
-    WKContextSetDiskCacheSpeculativeValidationEnabled(m_context.get(), true);
-    WKContextUseTestingNetworkSession(m_context.get());
-    WKContextSetCacheModel(m_context.get(), kWKCacheModelDocumentBrowser);
+        WKContextSetDiskCacheSpeculativeValidationEnabled(m_context.get(), true);
+        WKContextUseTestingNetworkSession(m_context.get());
+        WKContextSetCacheModel(m_context.get(), kWKCacheModelDocumentBrowser);
 
-    auto* websiteDataStore = WKContextGetWebsiteDataStore(m_context.get());
-    WKWebsiteDataStoreSetCacheStoragePerOriginQuota(websiteDataStore, 400 * 1024);
-    
-    platformInitializeContext();
+        auto* websiteDataStore = WKContextGetWebsiteDataStore(m_context.get());
+        WKWebsiteDataStoreSetPerOriginStorageQuota(websiteDataStore, 400 * 1024);
+
+        platformInitializeContext();
+    }
 
     WKContextInjectedBundleClientV1 injectedBundleClient = {
         { 1, this },
@@ -547,28 +593,15 @@ WKRetainPtr<WKPageConfigurationRef> TestController::generatePageConfiguration(WK
 
 void TestController::createWebViewWithOptions(const TestOptions& options)
 {
-    auto contextConfiguration = generateContextConfiguration(options);
-
-    WKRetainPtr<WKMutableArrayRef> overrideLanguages = adoptWK(WKMutableArrayCreate());
-    for (auto& language : options.overrideLanguages)
-        WKArrayAppendItem(overrideLanguages.get(), adoptWK(WKStringCreateWithUTF8CString(language.utf8().data())).get());
-    WKContextConfigurationSetOverrideLanguages(contextConfiguration.get(), overrideLanguages.get());
-
-    if (options.shouldEnableProcessSwapOnNavigation()) {
-        WKContextConfigurationSetProcessSwapsOnNavigation(contextConfiguration.get(), true);
-        if (options.enableProcessSwapOnWindowOpen)
-            WKContextConfigurationSetProcessSwapsOnWindowOpenWithOpener(contextConfiguration.get(), true);
-    }
-
-    auto configuration = generatePageConfiguration(contextConfiguration.get());
+    auto configuration = generatePageConfiguration(options);
 
     // Some preferences (notably mock scroll bars setting) currently cannot be re-applied to an existing view, so we need to set them now.
     // FIXME: Migrate these preferences to WKContextConfigurationRef.
     resetPreferencesToConsistentValues(options);
 
     platformCreateWebView(configuration.get(), options);
-    WKPageUIClientV8 pageUIClient = {
-        { 8, m_mainWebView.get() },
+    WKPageUIClientV13 pageUIClient = {
+        { 13, m_mainWebView.get() },
         0, // createNewPage_deprecatedForUseWithV0
         0, // showPage
         0, // close
@@ -597,13 +630,13 @@ void TestController::createWebViewWithOptions(const TestOptions& options)
         0, // didDraw
         0, // pageDidScroll
         0, // exceededDatabaseQuota,
-        runOpenPanel,
+        options.shouldHandleRunOpenPanel ? runOpenPanel : 0,
         decidePolicyForGeolocationPermissionRequest,
         0, // headerHeight
         0, // footerHeight
         0, // drawHeader
         0, // drawFooter
-        0, // printFrame
+        printFrame,
         runModal,
         0, // didCompleteRubberBandForMainFrame
         0, // saveDataToFileInDownloadsFolder
@@ -634,7 +667,13 @@ void TestController::createWebViewWithOptions(const TestOptions& options)
         0, // runBeforeUnloadConfirmPanel
         0, // fullscreenMayReturnToInline
         requestPointerLock,
-        0,
+        0, // didLosePointerLock
+        0, // handleAutoplayEvent
+        0, // hasVideoInPictureInPictureDidChange
+        0, // didExceedBackgroundResourceLimitWhileInForeground
+        0, // didResignInputElementStrongPasswordAppearance
+        0, // requestStorageAccessConfirm
+        shouldAllowDeviceOrientationAndMotionAccess
     };
     WKPageSetPageUIClient(m_mainWebView->page(), &pageUIClient.base);
 
@@ -733,10 +772,18 @@ void TestController::resetPreferencesToConsistentValues(const TestOptions& optio
         WKPreferencesSetExperimentalFeatureForKey(preferences, experimentalFeature.value, toWK(experimentalFeature.key).get());
 
     WKPreferencesResetAllInternalDebugFeatures(preferences);
+
+    // Set internal features that have different default values for testing.
+    static WKStringRef asyncOverflowScrollingFeature = WKStringCreateWithUTF8CString("AsyncOverflowScrollingEnabled");
+    WKPreferencesSetInternalDebugFeatureForKey(preferences, false, asyncOverflowScrollingFeature);
+
+    static WKStringRef asyncFrameScrollingFeature = WKStringCreateWithUTF8CString("AsyncFrameScrollingEnabled");
+    WKPreferencesSetInternalDebugFeatureForKey(preferences, false, asyncFrameScrollingFeature);
+
     for (const auto& internalDebugFeature : options.internalDebugFeatures)
         WKPreferencesSetInternalDebugFeatureForKey(preferences, internalDebugFeature.value, toWK(internalDebugFeature.key).get());
 
-    WKPreferencesSetProcessSwapOnNavigationEnabled(preferences, options.shouldEnableProcessSwapOnNavigation());
+    WKPreferencesSetProcessSwapOnNavigationEnabled(preferences, options.contextOptions.shouldEnableProcessSwapOnNavigation());
     WKPreferencesSetPageVisibilityBasedProcessSuppressionEnabled(preferences, false);
     WKPreferencesSetOfflineWebApplicationCacheEnabled(preferences, true);
     WKPreferencesSetSubpixelAntialiasedLayerTextEnabled(preferences, false);
@@ -836,6 +883,10 @@ void TestController::resetPreferencesToConsistentValues(const TestOptions& optio
 
     WKPreferencesSetWebSQLDisabled(preferences, false);
 
+    WKPreferencesSetMediaPlaybackRequiresUserGesture(preferences, false);
+    WKPreferencesSetVideoPlaybackRequiresUserGesture(preferences, false);
+    WKPreferencesSetAudioPlaybackRequiresUserGesture(preferences, false);
+
     platformResetPreferencesToConsistentValues();
 }
 
@@ -880,6 +931,9 @@ bool TestController::resetStateToConsistentValues(const TestOptions& options, Re
 
     WKContextClearCachedCredentials(TestController::singleton().context());
 
+    auto websiteDataStore = WKContextGetWebsiteDataStore(TestController::singleton().context());
+    WKWebsiteDataStoreClearAllDeviceOrientationPermissions(websiteDataStore);
+
     ClearIndexedDatabases();
     setIDBPerOriginQuota(50 * MB);
 
@@ -940,6 +994,8 @@ bool TestController::resetStateToConsistentValues(const TestOptions& options, Re
 
     m_shouldDownloadUndisplayableMIMETypes = false;
 
+    m_shouldAllowDeviceOrientationAndMotionAccess = false;
+
     m_workQueueManager.clearWorkQueue();
 
     m_rejectsProtectionSpaceAndContinueForAuthenticationChallenges = false;
@@ -966,6 +1022,9 @@ bool TestController::resetStateToConsistentValues(const TestOptions& options, Re
     setIgnoresViewportScaleLimits(options.ignoresViewportScaleLimits);
 
     m_openPanelFileURLs = nullptr;
+#if PLATFORM(IOS_FAMILY)
+    m_openPanelFileURLsMediaIcon = nullptr;
+#endif
     
     statisticsResetToConsistentState();
     
@@ -1012,6 +1071,41 @@ void TestController::checkForWorldLeaks()
     }, 20_s).run();
 }
 
+void TestController::dumpResponse(const String& result)
+{
+    unsigned resultLength = result.length();
+    printf("Content-Type: text/plain\n");
+    printf("Content-Length: %u\n", resultLength);
+    fwrite(result.utf8().data(), 1, resultLength, stdout);
+    printf("#EOF\n");
+    fprintf(stderr, "#EOF\n");
+    fflush(stdout);
+    fflush(stderr);
+}
+
+void TestController::findAndDumpWebKitProcessIdentifiers()
+{
+    StringBuilder builder;
+
+#if PLATFORM(COCOA)
+    builder.append(TestController::webProcessName());
+    builder.appendLiteral(": ");
+    pid_t webContentPID = WKPageGetProcessIdentifier(TestController::singleton().mainWebView()->page());
+    builder.appendNumber(webContentPID);
+    builder.append('\n');
+
+    builder.append(TestController::networkProcessName());
+    builder.appendLiteral(": ");
+    pid_t networkingPID = WKContextGetNetworkProcessIdentifier(m_context.get());
+    builder.appendNumber(networkingPID);
+    builder.append('\n');
+#else
+    builder.append('\n');
+#endif
+
+    dumpResponse(builder.toString());
+}
+
 void TestController::findAndDumpWorldLeaks()
 {
     if (!m_checkForWorldLeaks)
@@ -1034,16 +1128,9 @@ void TestController::findAndDumpWorldLeaks()
             builder.append('\n');
         }
     } else
-        builder.append("no abandoned documents");
+        builder.append("no abandoned documents\n");
 
-    String result = builder.toString();
-    printf("Content-Type: text/plain\n");
-    printf("Content-Length: %u\n", result.length());
-    fwrite(result.utf8().data(), 1, result.length(), stdout);
-    printf("#EOF\n");
-    fprintf(stderr, "#EOF\n");
-    fflush(stdout);
-    fflush(stderr);
+    dumpResponse(builder.toString());
 }
 
 void TestController::willDestroyWebView()
@@ -1172,8 +1259,8 @@ static bool parseBooleanTestHeaderValue(const std::string& value)
 
 static std::string parseStringTestHeaderValueAsRelativePath(const std::string& value, const std::string& pathOrURL)
 {
-    WKRetainPtr<WKURLRef> baseURL(AdoptWK, createTestURL(pathOrURL.c_str()));
-    WKRetainPtr<WKURLRef> relativeURL(AdoptWK, WKURLCreateWithBaseURL(baseURL.get(), value.c_str()));
+    WKRetainPtr<WKURLRef> baseURL = adoptWK(createTestURL(pathOrURL.c_str()));
+    WKRetainPtr<WKURLRef> relativeURL = adoptWK(WKURLCreateWithBaseURL(baseURL.get(), value.c_str()));
     return toSTD(adoptWK(WKURLCopyPath(relativeURL.get())));
 }
 
@@ -1182,7 +1269,7 @@ static void updateTestOptionsFromTestHeader(TestOptions& testOptions, const std:
     std::string filename = absolutePath;
     if (filename.empty()) {
         // Gross. Need to reduce conversions between all the string types and URLs.
-        WKRetainPtr<WKURLRef> wkURL(AdoptWK, createTestURL(pathOrURL.c_str()));
+        WKRetainPtr<WKURLRef> wkURL = adoptWK(createTestURL(pathOrURL.c_str()));
         filename = testPath(wkURL.get());
     }
 
@@ -1229,7 +1316,7 @@ static void updateTestOptionsFromTestHeader(TestOptions& testOptions, const std:
         }
 
         if (key == "language")
-            testOptions.overrideLanguages = String(value.c_str()).split(',');
+            testOptions.contextOptions.overrideLanguages = String(value.c_str()).split(',');
         else if (key == "useThreadedScrolling")
             testOptions.useThreadedScrolling = parseBooleanTestHeaderValue(value);
         else if (key == "useAcceleratedDrawing")
@@ -1273,9 +1360,9 @@ static void updateTestOptionsFromTestHeader(TestOptions& testOptions, const std:
         else if (key == "domPasteAllowed")
             testOptions.domPasteAllowed = parseBooleanTestHeaderValue(value);
         else if (key == "enableProcessSwapOnNavigation")
-            testOptions.enableProcessSwapOnNavigation = parseBooleanTestHeaderValue(value);
+            testOptions.contextOptions.enableProcessSwapOnNavigation = parseBooleanTestHeaderValue(value);
         else if (key == "enableProcessSwapOnWindowOpen")
-            testOptions.enableProcessSwapOnWindowOpen = parseBooleanTestHeaderValue(value);
+            testOptions.contextOptions.enableProcessSwapOnWindowOpen = parseBooleanTestHeaderValue(value);
         else if (key == "enableColorFilter")
             testOptions.enableColorFilter = parseBooleanTestHeaderValue(value);
         else if (key == "punchOutWhiteBackgroundsInDarkMode")
@@ -1294,10 +1381,16 @@ static void updateTestOptionsFromTestHeader(TestOptions& testOptions, const std:
             testOptions.editable = parseBooleanTestHeaderValue(value);
         else if (key == "enableUndoManagerAPI")
             testOptions.enableUndoManagerAPI = parseBooleanTestHeaderValue(value);
+        else if (key == "shouldHandleRunOpenPanel")
+            testOptions.shouldHandleRunOpenPanel = parseBooleanTestHeaderValue(value);
+        else if (key == "shouldPresentPopovers")
+            testOptions.shouldPresentPopovers = parseBooleanTestHeaderValue(value);
         else if (key == "contentInset.top")
             testOptions.contentInsetTop = std::stod(value);
         else if (key == "ignoreSynchronousMessagingTimeouts")
-            testOptions.ignoreSynchronousMessagingTimeouts = parseBooleanTestHeaderValue(value);
+            testOptions.contextOptions.ignoreSynchronousMessagingTimeouts = parseBooleanTestHeaderValue(value);
+        else if (key == "shouldUseModernCompatibilityMode")
+            testOptions.shouldUseModernCompatibilityMode = parseBooleanTestHeaderValue(value);
         pairStart = pairEnd + 1;
     }
 }
@@ -1542,7 +1635,7 @@ bool TestController::runTest(const char* inputLine)
     
     TestOptions options = testOptionsForTest(command);
 
-    WKRetainPtr<WKURLRef> wkURL(AdoptWK, createTestURL(command.pathOrURL.c_str()));
+    WKRetainPtr<WKURLRef> wkURL = adoptWK(createTestURL(command.pathOrURL.c_str()));
     m_currentInvocation = std::make_unique<TestInvocation>(wkURL.get(), options);
 
     if (command.shouldDumpPixels || m_shouldDumpPixelsForAllTests)
@@ -1571,14 +1664,19 @@ bool TestController::waitForCompletion(const WTF::Function<void ()>& function, W
 
 bool TestController::handleControlCommand(const char* command)
 {
-    if (!strcmp("#CHECK FOR WORLD LEAKS", command)) {
-        if (!m_checkForWorldLeaks) {
+    if (!strncmp("#CHECK FOR WORLD LEAKS", command, 22)) {
+        if (m_checkForWorldLeaks)
+            findAndDumpWorldLeaks();
+        else
             WTFLogAlways("WebKitTestRunner asked to check for world leaks, but was not run with --world-leaks");
-            return true;
-        }
-        findAndDumpWorldLeaks();
         return true;
     }
+
+    if (!strncmp("#LIST CHILD PROCESSES", command, 21)) {
+        findAndDumpWebKitProcessIdentifiers();
+        return true;
+    }
+
     return false;
 }
 
@@ -1681,10 +1779,10 @@ void TestController::didReceiveLiveDocumentsList(WKArrayRef liveDocumentList)
         if (item && WKGetTypeID(item) == WKDictionaryGetTypeID()) {
             WKDictionaryRef liveDocumentItem = static_cast<WKDictionaryRef>(item);
 
-            WKRetainPtr<WKStringRef> idKey(AdoptWK, WKStringCreateWithUTF8CString("id"));
+            WKRetainPtr<WKStringRef> idKey = adoptWK(WKStringCreateWithUTF8CString("id"));
             WKUInt64Ref documentID = static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(liveDocumentItem, idKey.get()));
 
-            WKRetainPtr<WKStringRef> urlKey(AdoptWK, WKStringCreateWithUTF8CString("url"));
+            WKRetainPtr<WKStringRef> urlKey = adoptWK(WKStringCreateWithUTF8CString("url"));
             WKStringRef documentURL = static_cast<WKStringRef>(WKDictionaryGetItemForKey(liveDocumentItem, urlKey.get()));
 
             documentInfo.add(WKUInt64GetValue(documentID), toWTFString(documentURL));
@@ -1723,7 +1821,7 @@ void TestController::didReceiveMessageFromInjectedBundle(WKStringRef messageName
         ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID());
         WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody);
 
-        WKRetainPtr<WKStringRef> subMessageKey(AdoptWK, WKStringCreateWithUTF8CString("SubMessage"));
+        WKRetainPtr<WKStringRef> subMessageKey = adoptWK(WKStringCreateWithUTF8CString("SubMessage"));
         WKStringRef subMessageName = static_cast<WKStringRef>(WKDictionaryGetItemForKey(messageBodyDictionary, subMessageKey.get()));
 
         if (WKStringIsEqualToUTF8CString(subMessageName, "MouseDown") || WKStringIsEqualToUTF8CString(subMessageName, "MouseUp")) {
@@ -1795,7 +1893,7 @@ WKRetainPtr<WKTypeRef> TestController::didReceiveSynchronousMessageFromInjectedB
         ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID());
         WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody);
 
-        WKRetainPtr<WKStringRef> subMessageKey(AdoptWK, WKStringCreateWithUTF8CString("SubMessage"));
+        WKRetainPtr<WKStringRef> subMessageKey = adoptWK(WKStringCreateWithUTF8CString("SubMessage"));
         WKStringRef subMessageName = static_cast<WKStringRef>(WKDictionaryGetItemForKey(messageBodyDictionary, subMessageKey.get()));
 
         if (WKStringIsEqualToUTF8CString(subMessageName, "KeyDown")) {
@@ -2178,7 +2276,7 @@ void TestController::didFinishNavigation(WKPageRef page, WKNavigationRef navigat
     if (m_state != Resetting)
         return;
 
-    WKRetainPtr<WKURLRef> wkURL(AdoptWK, WKFrameCopyURL(WKPageGetMainFrame(page)));
+    WKRetainPtr<WKURLRef> wkURL = adoptWK(WKFrameCopyURL(WKPageGetMainFrame(page)));
     if (!WKURLIsEqual(wkURL.get(), blankURL()))
         return;
 
@@ -2222,9 +2320,9 @@ void TestController::didReceiveAuthenticationChallenge(WKPageRef page, WKAuthent
         WKAuthenticationDecisionListenerUseCredential(decisionListener, 0);
         return;
     }
-    WKRetainPtr<WKStringRef> username(AdoptWK, WKStringCreateWithUTF8CString(m_authenticationUsername.utf8().data()));
-    WKRetainPtr<WKStringRef> password(AdoptWK, WKStringCreateWithUTF8CString(m_authenticationPassword.utf8().data()));
-    WKRetainPtr<WKCredentialRef> credential(AdoptWK, WKCredentialCreate(username.get(), password.get(), kWKCredentialPersistenceForSession));
+    WKRetainPtr<WKStringRef> username = adoptWK(WKStringCreateWithUTF8CString(m_authenticationUsername.utf8().data()));
+    WKRetainPtr<WKStringRef> password = adoptWK(WKStringCreateWithUTF8CString(m_authenticationPassword.utf8().data()));
+    WKRetainPtr<WKCredentialRef> credential = adoptWK(WKCredentialCreate(username.get(), password.get(), kWKCredentialPersistenceForSession));
     WKAuthenticationDecisionListenerUseCredential(decisionListener, credential.get());
 }
 
@@ -2545,6 +2643,12 @@ void TestController::handleCheckOfUserMediaPermissionForOrigin(WKFrameRef frame,
     WKUserMediaPermissionCheckSetUserMediaAccessInfo(checkRequest, saltString.get(), settingsForOrigin(originHash).persistentPermission());
 }
 
+bool TestController::handleDeviceOrientationAndMotionAccessRequest(WKSecurityOriginRef origin)
+{
+    m_currentInvocation->outputText(makeString("Received device orientation & motion access request for security origin \"", originUserVisibleName(origin), "\".\n"));
+    return m_shouldAllowDeviceOrientationAndMotionAccess;
+}
+
 void TestController::handleUserMediaPermissionRequest(WKFrameRef frame, WKSecurityOriginRef userMediaDocumentOrigin, WKSecurityOriginRef topLevelDocumentOrigin, WKUserMediaPermissionRequestRef request)
 {
     auto originHash = userMediaOriginHash(userMediaDocumentOrigin, topLevelDocumentOrigin);
@@ -2655,16 +2759,19 @@ void TestController::unavailablePluginButtonClicked(WKPageRef, WKPluginUnavailab
 
 void TestController::decidePolicyForNavigationAction(WKPageRef, WKNavigationActionRef navigationAction, WKFramePolicyListenerRef listener, WKTypeRef, const void* clientInfo)
 {
-    static_cast<TestController*>(const_cast<void*>(clientInfo))->decidePolicyForNavigationAction(listener);
+    static_cast<TestController*>(const_cast<void*>(clientInfo))->decidePolicyForNavigationAction(navigationAction, listener);
 }
 
-void TestController::decidePolicyForNavigationAction(WKFramePolicyListenerRef listener)
+void TestController::decidePolicyForNavigationAction(WKNavigationActionRef navigationAction, WKFramePolicyListenerRef listener)
 {
     WKRetainPtr<WKFramePolicyListenerRef> retainedListener { listener };
+    WKRetainPtr<WKNavigationActionRef> retainedNavigationAction { navigationAction };
     const bool shouldIgnore { m_policyDelegateEnabled && !m_policyDelegatePermissive };
-    auto decisionFunction = [shouldIgnore, retainedListener]() {
+    auto decisionFunction = [shouldIgnore, retainedListener, retainedNavigationAction]() {
         if (shouldIgnore)
             WKFramePolicyListenerIgnore(retainedListener.get());
+        else if (WKNavigationActionShouldPerformDownload(retainedNavigationAction.get()))
+            WKFramePolicyListenerDownload(retainedListener.get());
         else
             WKFramePolicyListenerUse(retainedListener.get());
     };
@@ -3015,7 +3122,7 @@ uint64_t TestController::domCacheSize(WKStringRef origin)
 }
 
 #if !PLATFORM(COCOA)
-void TestController::allowCacheStorageQuotaIncrease()
+void TestController::setAllowStorageQuotaIncrease(bool)
 {
     // FIXME: To implement.
 }
@@ -3230,16 +3337,28 @@ void TestController::setStatisticsTopFrameUniqueRedirectFrom(WKStringRef host, W
     WKWebsiteDataStoreSetStatisticsTopFrameUniqueRedirectFrom(dataStore, host, hostRedirectedFrom);
 }
 
+void TestController::setStatisticsCrossSiteLoadWithLinkDecoration(WKStringRef fromHost, WKStringRef toHost)
+{
+    auto* dataStore = WKContextGetWebsiteDataStore(platformContext());
+    ResourceStatisticsCallbackContext context(*this);
+    WKWebsiteDataStoreSetStatisticsCrossSiteLoadWithLinkDecoration(dataStore, fromHost, toHost, &context, resourceStatisticsVoidResultCallback);
+    runUntil(context.done, noTimeout);
+}
+
 void TestController::setStatisticsTimeToLiveUserInteraction(double seconds)
 {
     auto* dataStore = WKContextGetWebsiteDataStore(platformContext());
-    WKWebsiteDataStoreSetStatisticsTimeToLiveUserInteraction(dataStore, seconds);
+    ResourceStatisticsCallbackContext context(*this);
+    WKWebsiteDataStoreSetStatisticsTimeToLiveUserInteraction(dataStore, seconds, &context, resourceStatisticsVoidResultCallback);
+    runUntil(context.done, noTimeout);
 }
 
 void TestController::statisticsProcessStatisticsAndDataRecords()
 {
     auto* dataStore = WKContextGetWebsiteDataStore(platformContext());
-    WKWebsiteDataStoreStatisticsProcessStatisticsAndDataRecords(dataStore);
+    ResourceStatisticsCallbackContext context(*this);
+    WKWebsiteDataStoreStatisticsProcessStatisticsAndDataRecords(dataStore, &context, resourceStatisticsVoidResultCallback);
+    runUntil(context.done, noTimeout);
 }
 
 void TestController::statisticsUpdateCookieBlocking()
@@ -3263,6 +3382,14 @@ void TestController::setStatisticsNotifyPagesWhenDataRecordsWereScanned(bool val
     WKWebsiteDataStoreSetStatisticsNotifyPagesWhenDataRecordsWereScanned(dataStore, value);
 }
 
+void TestController::setStatisticsIsRunningTest(bool value)
+{
+    auto* dataStore = WKContextGetWebsiteDataStore(platformContext());
+    ResourceStatisticsCallbackContext context(*this);
+    WKWebsiteDataStoreSetStatisticsIsRunningTest(dataStore, value, &context, resourceStatisticsVoidResultCallback);
+    runUntil(context.done, noTimeout);
+}
+
 void TestController::setStatisticsShouldClassifyResourcesBeforeDataRecordsRemoval(bool value)
 {
     auto* dataStore = WKContextGetWebsiteDataStore(platformContext());
@@ -3326,6 +3453,23 @@ void TestController::statisticsClearThroughWebsiteDataRemoval()
     m_currentInvocation->didClearStatisticsThroughWebsiteDataRemoval();
 }
 
+void TestController::statisticsDeleteCookiesForHost(WKStringRef host, bool includeHttpOnlyCookies)
+{
+    auto* dataStore = WKContextGetWebsiteDataStore(platformContext());
+    ResourceStatisticsCallbackContext context(*this);
+    WKWebsiteDataStoreStatisticsDeleteCookiesForTesting(dataStore, host, includeHttpOnlyCookies, &context, resourceStatisticsVoidResultCallback);
+    runUntil(context.done, noTimeout);
+}
+
+bool TestController::isStatisticsHasLocalStorage(WKStringRef host)
+{
+    auto* dataStore = WKContextGetWebsiteDataStore(platformContext());
+    ResourceStatisticsCallbackContext context(*this);
+    WKWebsiteDataStoreStatisticsHasLocalStorage(dataStore, host, &context, resourceStatisticsBooleanResultCallback);
+    runUntil(context.done, noTimeout);
+    return context.result;
+}
+
 void TestController::setStatisticsCacheMaxAgeCap(double seconds)
 {
     auto* dataStore = WKContextGetWebsiteDataStore(platformContext());
@@ -3390,6 +3534,14 @@ bool TestController::canDoServerTrustEvaluationInNetworkProcess() const
     return false;
 }
 
+void TestController::installCustomMenuAction(const String&, bool)
+{
+}
+
+void TestController::setAllowedMenuActions(const Vector<String>&)
+{
+}
+
 #endif
 
 void TestController::sendDisplayConfigurationChangedMessageForTesting()
@@ -3453,4 +3605,18 @@ void TestController::clearAdClickAttribution()
     runUntil(callbackContext.done, noTimeout);
 }
 
+void TestController::setAdClickAttributionOverrideTimerForTesting(bool value)
+{
+    AdClickAttributionVoidCallbackContext callbackContext(*this);
+    WKPageSetAdClickAttributionOverrideTimerForTesting(m_mainWebView->page(), value, adClickAttributionVoidCallback, &callbackContext);
+    runUntil(callbackContext.done, noTimeout);
+}
+
+void TestController::setAdClickAttributionConversionURLForTesting(WKURLRef url)
+{
+    AdClickAttributionVoidCallbackContext callbackContext(*this);
+    WKPageSetAdClickAttributionConversionURLForTesting(m_mainWebView->page(), url, adClickAttributionVoidCallback, &callbackContext);
+    runUntil(callbackContext.done, noTimeout);
+}
+
 } // namespace WTR