| /* |
| * Copyright (C) 2010 Apple Inc. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' |
| * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
| * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS |
| * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
| * THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include "config.h" |
| #include "TestController.h" |
| |
| #include "PlatformWebView.h" |
| #include "StringFunctions.h" |
| #include "TestInvocation.h" |
| #include <WebKit2/WKContextPrivate.h> |
| #include <WebKit2/WKNotification.h> |
| #include <WebKit2/WKNotificationManager.h> |
| #include <WebKit2/WKNotificationPermissionRequest.h> |
| #include <WebKit2/WKNumber.h> |
| #include <WebKit2/WKPageGroup.h> |
| #include <WebKit2/WKPagePrivate.h> |
| #include <WebKit2/WKPreferencesPrivate.h> |
| #include <WebKit2/WKRetainPtr.h> |
| #include <algorithm> |
| #include <cstdio> |
| #include <ctype.h> |
| #include <stdlib.h> |
| #include <string> |
| #include <wtf/PassOwnPtr.h> |
| |
| #if PLATFORM(MAC) |
| #include <WebKit2/WKPagePrivateMac.h> |
| #endif |
| |
| #if PLATFORM(MAC) || PLATFORM(QT) || PLATFORM(GTK) || PLATFORM(EFL) |
| #include "EventSenderProxy.h" |
| #endif |
| |
| namespace WTR { |
| |
| // defaultLongTimeout + defaultShortTimeout should be less than 80, |
| // the default timeout value of the test harness so we can detect an |
| // unresponsive web process. |
| static const double defaultLongTimeout = 60; |
| static const double defaultShortTimeout = 15; |
| static const double defaultNoTimeout = -1; |
| |
| static WKURLRef blankURL() |
| { |
| static WKURLRef staticBlankURL = WKURLCreateWithUTF8CString("about:blank"); |
| return staticBlankURL; |
| } |
| |
| static TestController* controller; |
| |
| TestController& TestController::shared() |
| { |
| ASSERT(controller); |
| return *controller; |
| } |
| |
| TestController::TestController(int argc, const char* argv[]) |
| : m_verbose(false) |
| , m_printSeparators(false) |
| , m_usingServerMode(false) |
| , m_gcBetweenTests(false) |
| , m_state(Initial) |
| , m_doneResetting(false) |
| , m_longTimeout(defaultLongTimeout) |
| , m_shortTimeout(defaultShortTimeout) |
| , m_noTimeout(defaultNoTimeout) |
| , m_useWaitToDumpWatchdogTimer(true) |
| , m_forceNoTimeout(false) |
| , m_didPrintWebProcessCrashedMessage(false) |
| , m_shouldExitWhenWebProcessCrashes(true) |
| , m_beforeUnloadReturnValue(true) |
| , m_isGeolocationPermissionSet(false) |
| , m_isGeolocationPermissionAllowed(false) |
| , m_policyDelegateEnabled(false) |
| , m_policyDelegatePermissive(false) |
| #if PLATFORM(MAC) || PLATFORM(QT) || PLATFORM(GTK) || PLATFORM(EFL) |
| , m_eventSenderProxy(new EventSenderProxy(this)) |
| #endif |
| { |
| initialize(argc, argv); |
| controller = this; |
| run(); |
| controller = 0; |
| } |
| |
| TestController::~TestController() |
| { |
| } |
| |
| static WKRect getWindowFrame(WKPageRef page, const void* clientInfo) |
| { |
| PlatformWebView* view = static_cast<PlatformWebView*>(const_cast<void*>(clientInfo)); |
| return view->windowFrame(); |
| } |
| |
| static void setWindowFrame(WKPageRef page, WKRect frame, const void* clientInfo) |
| { |
| PlatformWebView* view = static_cast<PlatformWebView*>(const_cast<void*>(clientInfo)); |
| view->setWindowFrame(frame); |
| } |
| |
| static bool runBeforeUnloadConfirmPanel(WKPageRef page, WKStringRef message, WKFrameRef frame, const void*) |
| { |
| printf("CONFIRM NAVIGATION: %s\n", toSTD(message).c_str()); |
| return TestController::shared().beforeUnloadReturnValue(); |
| } |
| |
| static unsigned long long exceededDatabaseQuota(WKPageRef, WKFrameRef, WKSecurityOriginRef, WKStringRef, WKStringRef, unsigned long long, unsigned long long, unsigned long long, unsigned long long, const void*) |
| { |
| static const unsigned long long defaultQuota = 5 * 1024 * 1024; |
| return defaultQuota; |
| } |
| |
| |
| void TestController::runModal(WKPageRef page, const void* clientInfo) |
| { |
| PlatformWebView* view = static_cast<PlatformWebView*>(const_cast<void*>(clientInfo)); |
| view->setWindowIsKey(false); |
| runModal(view); |
| view->setWindowIsKey(true); |
| } |
| |
| static void closeOtherPage(WKPageRef page, const void* clientInfo) |
| { |
| WKPageClose(page); |
| PlatformWebView* view = static_cast<PlatformWebView*>(const_cast<void*>(clientInfo)); |
| delete view; |
| } |
| |
| static void focus(WKPageRef page, const void* clientInfo) |
| { |
| PlatformWebView* view = static_cast<PlatformWebView*>(const_cast<void*>(clientInfo)); |
| view->focus(); |
| view->setWindowIsKey(true); |
| } |
| |
| static void unfocus(WKPageRef page, const void* clientInfo) |
| { |
| PlatformWebView* view = static_cast<PlatformWebView*>(const_cast<void*>(clientInfo)); |
| view->setWindowIsKey(false); |
| } |
| |
| static void decidePolicyForGeolocationPermissionRequest(WKPageRef, WKFrameRef, WKSecurityOriginRef, WKGeolocationPermissionRequestRef permissionRequest, const void* clientInfo) |
| { |
| TestController::shared().handleGeolocationPermissionRequest(permissionRequest); |
| } |
| |
| WKPageRef TestController::createOtherPage(WKPageRef oldPage, WKURLRequestRef, WKDictionaryRef, WKEventModifiers, WKEventMouseButton, const void*) |
| { |
| PlatformWebView* view = new PlatformWebView(WKPageGetContext(oldPage), WKPageGetPageGroup(oldPage)); |
| WKPageRef newPage = view->page(); |
| |
| view->resizeTo(800, 600); |
| |
| WKPageUIClient otherPageUIClient = { |
| kWKPageUIClientCurrentVersion, |
| view, |
| 0, // createNewPage_deprecatedForUseWithV0 |
| 0, // showPage |
| closeOtherPage, |
| 0, // takeFocus |
| focus, |
| unfocus, |
| 0, // runJavaScriptAlert |
| 0, // runJavaScriptConfirm |
| 0, // runJavaScriptPrompt |
| 0, // setStatusText |
| 0, // mouseDidMoveOverElement_deprecatedForUseWithV0 |
| 0, // missingPluginButtonClicked |
| 0, // didNotHandleKeyEvent |
| 0, // didNotHandleWheelEvent |
| 0, // toolbarsAreVisible |
| 0, // setToolbarsAreVisible |
| 0, // menuBarIsVisible |
| 0, // setMenuBarIsVisible |
| 0, // statusBarIsVisible |
| 0, // setStatusBarIsVisible |
| 0, // isResizable |
| 0, // setIsResizable |
| getWindowFrame, |
| setWindowFrame, |
| runBeforeUnloadConfirmPanel, |
| 0, // didDraw |
| 0, // pageDidScroll |
| exceededDatabaseQuota, |
| 0, // runOpenPanel |
| decidePolicyForGeolocationPermissionRequest, |
| 0, // headerHeight |
| 0, // footerHeight |
| 0, // drawHeader |
| 0, // drawFooter |
| 0, // printFrame |
| runModal, |
| 0, // didCompleteRubberBandForMainFrame |
| 0, // saveDataToFileInDownloadsFolder |
| 0, // shouldInterruptJavaScript |
| createOtherPage, |
| 0, // mouseDidMoveOverElement |
| 0, // decidePolicyForNotificationPermissionRequest |
| 0, // unavailablePluginButtonClicked |
| 0, // showColorPicker |
| 0, // hideColorPicker |
| }; |
| WKPageSetPageUIClient(newPage, &otherPageUIClient); |
| |
| WKRetain(newPage); |
| return newPage; |
| } |
| |
| const char* TestController::libraryPathForTesting() |
| { |
| // FIXME: This may not be sufficient to prevent interactions/crashes |
| // when running more than one copy of DumpRenderTree. |
| // See https://bugs.webkit.org/show_bug.cgi?id=10906 |
| char* dumpRenderTreeTemp = getenv("DUMPRENDERTREE_TEMP"); |
| if (dumpRenderTreeTemp) |
| return dumpRenderTreeTemp; |
| return platformLibraryPathForTesting(); |
| } |
| |
| |
| void TestController::initialize(int argc, const char* argv[]) |
| { |
| platformInitialize(); |
| |
| if (argc < 2) { |
| fputs("Usage: WebKitTestRunner [options] filename [filename2..n]\n", stderr); |
| // FIXME: Refactor option parsing to allow us to print |
| // an auto-generated list of options. |
| exit(1); |
| } |
| |
| bool printSupportedFeatures = false; |
| |
| for (int i = 1; i < argc; ++i) { |
| std::string argument(argv[i]); |
| |
| if (argument == "--timeout" && i + 1 < argc) { |
| m_longTimeout = atoi(argv[++i]); |
| // Scale up the short timeout to match. |
| m_shortTimeout = defaultShortTimeout * m_longTimeout / defaultLongTimeout; |
| continue; |
| } |
| |
| if (argument == "--no-timeout") { |
| m_useWaitToDumpWatchdogTimer = false; |
| continue; |
| } |
| |
| if (argument == "--no-timeout-at-all") { |
| m_useWaitToDumpWatchdogTimer = false; |
| m_forceNoTimeout = true; |
| continue; |
| } |
| |
| if (argument == "--verbose") { |
| m_verbose = true; |
| continue; |
| } |
| if (argument == "--gc-between-tests") { |
| m_gcBetweenTests = true; |
| continue; |
| } |
| if (argument == "--print-supported-features") { |
| printSupportedFeatures = true; |
| break; |
| } |
| |
| // Skip any other arguments that begin with '--'. |
| if (argument.length() >= 2 && argument[0] == '-' && argument[1] == '-') |
| continue; |
| |
| m_paths.push_back(argument); |
| } |
| |
| if (printSupportedFeatures) { |
| // FIXME: On Windows, DumpRenderTree uses this to expose whether it supports 3d |
| // transforms and accelerated compositing. When we support those features, we |
| // should match DRT's behavior. |
| exit(0); |
| } |
| |
| m_usingServerMode = (m_paths.size() == 1 && m_paths[0] == "-"); |
| if (m_usingServerMode) |
| m_printSeparators = true; |
| else |
| m_printSeparators = m_paths.size() > 1; |
| |
| initializeInjectedBundlePath(); |
| initializeTestPluginDirectory(); |
| |
| WKRetainPtr<WKStringRef> pageGroupIdentifier(AdoptWK, WKStringCreateWithUTF8CString("WebKitTestRunnerPageGroup")); |
| m_pageGroup.adopt(WKPageGroupCreateWithIdentifier(pageGroupIdentifier.get())); |
| |
| m_context.adopt(WKContextCreateWithInjectedBundlePath(injectedBundlePath())); |
| m_geolocationProvider = adoptPtr(new GeolocationProviderMock(m_context.get())); |
| |
| const char* path = libraryPathForTesting(); |
| if (path) { |
| Vector<char> databaseDirectory(strlen(path) + strlen("/Databases") + 1); |
| sprintf(databaseDirectory.data(), "%s%s", path, "/Databases"); |
| WKRetainPtr<WKStringRef> databaseDirectoryWK(AdoptWK, WKStringCreateWithUTF8CString(databaseDirectory.data())); |
| WKContextSetDatabaseDirectory(m_context.get(), databaseDirectoryWK.get()); |
| } |
| |
| platformInitializeContext(); |
| |
| WKContextInjectedBundleClient injectedBundleClient = { |
| kWKContextInjectedBundleClientCurrentVersion, |
| this, |
| didReceiveMessageFromInjectedBundle, |
| didReceiveSynchronousMessageFromInjectedBundle, |
| 0 // getInjectedBundleInitializationUserData |
| }; |
| WKContextSetInjectedBundleClient(m_context.get(), &injectedBundleClient); |
| |
| WKNotificationManagerRef notificationManager = WKContextGetNotificationManager(m_context.get()); |
| WKNotificationProvider notificationKit = m_webNotificationProvider.provider(); |
| WKNotificationManagerSetProvider(notificationManager, ¬ificationKit); |
| |
| if (testPluginDirectory()) |
| WKContextSetAdditionalPluginsDirectory(m_context.get(), testPluginDirectory()); |
| |
| m_mainWebView = adoptPtr(new PlatformWebView(m_context.get(), m_pageGroup.get())); |
| |
| WKPageUIClient pageUIClient = { |
| kWKPageUIClientCurrentVersion, |
| m_mainWebView.get(), |
| 0, // createNewPage_deprecatedForUseWithV0 |
| 0, // showPage |
| 0, // close |
| 0, // takeFocus |
| focus, |
| unfocus, |
| 0, // runJavaScriptAlert |
| 0, // runJavaScriptConfirm |
| 0, // runJavaScriptPrompt |
| 0, // setStatusText |
| 0, // mouseDidMoveOverElement_deprecatedForUseWithV0 |
| 0, // missingPluginButtonClicked |
| 0, // didNotHandleKeyEvent |
| 0, // didNotHandleWheelEvent |
| 0, // toolbarsAreVisible |
| 0, // setToolbarsAreVisible |
| 0, // menuBarIsVisible |
| 0, // setMenuBarIsVisible |
| 0, // statusBarIsVisible |
| 0, // setStatusBarIsVisible |
| 0, // isResizable |
| 0, // setIsResizable |
| getWindowFrame, |
| setWindowFrame, |
| runBeforeUnloadConfirmPanel, |
| 0, // didDraw |
| 0, // pageDidScroll |
| exceededDatabaseQuota, |
| 0, // runOpenPanel |
| decidePolicyForGeolocationPermissionRequest, |
| 0, // headerHeight |
| 0, // footerHeight |
| 0, // drawHeader |
| 0, // drawFooter |
| 0, // printFrame |
| runModal, |
| 0, // didCompleteRubberBandForMainFrame |
| 0, // saveDataToFileInDownloadsFolder |
| 0, // shouldInterruptJavaScript |
| createOtherPage, |
| 0, // mouseDidMoveOverElement |
| decidePolicyForNotificationPermissionRequest, // decidePolicyForNotificationPermissionRequest |
| 0, // unavailablePluginButtonClicked |
| 0, // showColorPicker |
| 0, // hideColorPicker |
| }; |
| WKPageSetPageUIClient(m_mainWebView->page(), &pageUIClient); |
| |
| WKPageLoaderClient pageLoaderClient = { |
| kWKPageLoaderClientCurrentVersion, |
| this, |
| 0, // didStartProvisionalLoadForFrame |
| 0, // didReceiveServerRedirectForProvisionalLoadForFrame |
| 0, // didFailProvisionalLoadWithErrorForFrame |
| didCommitLoadForFrame, |
| 0, // didFinishDocumentLoadForFrame |
| didFinishLoadForFrame, |
| 0, // didFailLoadWithErrorForFrame |
| 0, // didSameDocumentNavigationForFrame |
| 0, // didReceiveTitleForFrame |
| 0, // didFirstLayoutForFrame |
| 0, // didFirstVisuallyNonEmptyLayoutForFrame |
| 0, // didRemoveFrameFromHierarchy |
| 0, // didFailToInitializePlugin |
| 0, // didDisplayInsecureContentForFrame |
| 0, // canAuthenticateAgainstProtectionSpaceInFrame |
| 0, // didReceiveAuthenticationChallengeInFrame |
| 0, // didStartProgress |
| 0, // didChangeProgress |
| 0, // didFinishProgress |
| 0, // didBecomeUnresponsive |
| 0, // didBecomeResponsive |
| processDidCrash, |
| 0, // didChangeBackForwardList |
| 0, // shouldGoToBackForwardListItem |
| 0, // didRunInsecureContentForFrame |
| 0, // didDetectXSSForFrame |
| 0, // didNewFirstVisuallyNonEmptyLayout |
| 0, // willGoToBackForwardListItem |
| 0, // interactionOccurredWhileProcessUnresponsive |
| 0, // pluginDidFail |
| 0, // didReceiveIntentForFrame |
| 0, // registerIntentServiceForFrame |
| 0, // didLayout |
| }; |
| WKPageSetPageLoaderClient(m_mainWebView->page(), &pageLoaderClient); |
| |
| WKPagePolicyClient pagePolicyClient = { |
| kWKPagePolicyClientCurrentVersion, |
| this, |
| decidePolicyForNavigationAction, |
| 0, // decidePolicyForNewWindowAction |
| 0, // decidePolicyForResponse |
| 0, // unableToImplementPolicy |
| }; |
| WKPageSetPagePolicyClient(m_mainWebView->page(), &pagePolicyClient); |
| } |
| |
| bool TestController::resetStateToConsistentValues() |
| { |
| m_state = Resetting; |
| |
| m_beforeUnloadReturnValue = true; |
| |
| WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("Reset")); |
| WKRetainPtr<WKMutableDictionaryRef> resetMessageBody = adoptWK(WKMutableDictionaryCreate()); |
| |
| WKRetainPtr<WKStringRef> shouldGCKey = adoptWK(WKStringCreateWithUTF8CString("ShouldGC")); |
| WKRetainPtr<WKBooleanRef> shouldGCValue = adoptWK(WKBooleanCreate(m_gcBetweenTests)); |
| WKDictionaryAddItem(resetMessageBody.get(), shouldGCKey.get(), shouldGCValue.get()); |
| |
| WKContextPostMessageToInjectedBundle(TestController::shared().context(), messageName.get(), resetMessageBody.get()); |
| |
| WKContextSetShouldUseFontSmoothing(TestController::shared().context(), false); |
| |
| WKContextSetCacheModel(TestController::shared().context(), kWKCacheModelDocumentBrowser); |
| |
| // FIXME: This function should also ensure that there is only one page open. |
| |
| // Reset preferences |
| WKPreferencesRef preferences = WKPageGroupGetPreferences(m_pageGroup.get()); |
| WKPreferencesResetTestRunnerOverrides(preferences); |
| WKPreferencesSetOfflineWebApplicationCacheEnabled(preferences, true); |
| WKPreferencesSetFontSmoothingLevel(preferences, kWKFontSmoothingLevelNoSubpixelAntiAliasing); |
| WKPreferencesSetXSSAuditorEnabled(preferences, false); |
| WKPreferencesSetWebAudioEnabled(preferences, true); |
| WKPreferencesSetDeveloperExtrasEnabled(preferences, true); |
| WKPreferencesSetJavaScriptExperimentsEnabled(preferences, true); |
| WKPreferencesSetJavaScriptCanOpenWindowsAutomatically(preferences, true); |
| WKPreferencesSetJavaScriptCanAccessClipboard(preferences, true); |
| WKPreferencesSetDOMPasteAllowed(preferences, true); |
| WKPreferencesSetUniversalAccessFromFileURLsAllowed(preferences, true); |
| WKPreferencesSetFileAccessFromFileURLsAllowed(preferences, true); |
| #if ENABLE(FULLSCREEN_API) |
| WKPreferencesSetFullScreenEnabled(preferences, true); |
| #endif |
| WKPreferencesSetPageCacheEnabled(preferences, false); |
| WKPreferencesSetAsynchronousPluginInitializationEnabled(preferences, false); |
| WKPreferencesSetAsynchronousPluginInitializationEnabledForAllPlugins(preferences, false); |
| WKPreferencesSetArtificialPluginInitializationDelayEnabled(preferences, false); |
| WKPreferencesSetTabToLinksEnabled(preferences, false); |
| WKPreferencesSetInteractiveFormValidationEnabled(preferences, true); |
| WKPreferencesSetMockScrollbarsEnabled(preferences, true); |
| |
| #if !PLATFORM(QT) |
| static WKStringRef standardFontFamily = WKStringCreateWithUTF8CString("Times"); |
| static WKStringRef cursiveFontFamily = WKStringCreateWithUTF8CString("Apple Chancery"); |
| static WKStringRef fantasyFontFamily = WKStringCreateWithUTF8CString("Papyrus"); |
| static WKStringRef fixedFontFamily = WKStringCreateWithUTF8CString("Courier"); |
| static WKStringRef pictographFontFamily = WKStringCreateWithUTF8CString("Apple Color Emoji"); |
| static WKStringRef sansSerifFontFamily = WKStringCreateWithUTF8CString("Helvetica"); |
| static WKStringRef serifFontFamily = WKStringCreateWithUTF8CString("Times"); |
| |
| WKPreferencesSetStandardFontFamily(preferences, standardFontFamily); |
| WKPreferencesSetCursiveFontFamily(preferences, cursiveFontFamily); |
| WKPreferencesSetFantasyFontFamily(preferences, fantasyFontFamily); |
| WKPreferencesSetFixedFontFamily(preferences, fixedFontFamily); |
| WKPreferencesSetPictographFontFamily(preferences, pictographFontFamily); |
| WKPreferencesSetSansSerifFontFamily(preferences, sansSerifFontFamily); |
| WKPreferencesSetSerifFontFamily(preferences, serifFontFamily); |
| #endif |
| WKPreferencesSetScreenFontSubstitutionEnabled(preferences, true); |
| WKPreferencesSetInspectorUsesWebKitUserInterface(preferences, true); |
| |
| // in the case that a test using the chrome input field failed, be sure to clean up for the next test |
| m_mainWebView->removeChromeInputField(); |
| m_mainWebView->focus(); |
| |
| // Re-set to the default backing scale factor by setting the custom scale factor to 0. |
| WKPageSetCustomBackingScaleFactor(m_mainWebView->page(), 0); |
| |
| // Reset notification permissions |
| m_webNotificationProvider.reset(); |
| |
| // Reset Geolocation permissions. |
| m_geolocationPermissionRequests.clear(); |
| m_isGeolocationPermissionSet = false; |
| m_isGeolocationPermissionAllowed = false; |
| |
| // Reset Custom Policy Delegate. |
| setCustomPolicyDelegate(false, false); |
| |
| // Reset main page back to about:blank |
| m_doneResetting = false; |
| |
| WKPageLoadURL(m_mainWebView->page(), blankURL()); |
| runUntil(m_doneResetting, ShortTimeout); |
| return m_doneResetting; |
| } |
| |
| struct TestCommand { |
| TestCommand() : shouldDumpPixels(false) { } |
| |
| std::string pathOrURL; |
| bool shouldDumpPixels; |
| std::string expectedPixelHash; |
| }; |
| |
| class CommandTokenizer { |
| public: |
| explicit CommandTokenizer(const std::string& input) |
| : m_input(input) |
| , m_posNextSeparator(0) |
| { |
| pump(); |
| } |
| |
| bool hasNext() const; |
| std::string next(); |
| |
| private: |
| void pump(); |
| static const char kSeparator = '\''; |
| const std::string& m_input; |
| std::string m_next; |
| size_t m_posNextSeparator; |
| }; |
| |
| void CommandTokenizer::pump() |
| { |
| if (m_posNextSeparator == std::string::npos || m_posNextSeparator == m_input.size()) { |
| m_next = std::string(); |
| return; |
| } |
| size_t start = m_posNextSeparator ? m_posNextSeparator + 1 : 0; |
| m_posNextSeparator = m_input.find(kSeparator, start); |
| size_t size = m_posNextSeparator == std::string::npos ? std::string::npos : m_posNextSeparator - start; |
| m_next = std::string(m_input, start, size); |
| } |
| |
| std::string CommandTokenizer::next() |
| { |
| ASSERT(hasNext()); |
| |
| std::string oldNext = m_next; |
| pump(); |
| return oldNext; |
| } |
| |
| bool CommandTokenizer::hasNext() const |
| { |
| return !m_next.empty(); |
| } |
| |
| NO_RETURN static void die(const std::string& inputLine) |
| { |
| fprintf(stderr, "Unexpected input line: %s\n", inputLine.c_str()); |
| exit(1); |
| } |
| |
| TestCommand parseInputLine(const std::string& inputLine) |
| { |
| TestCommand result; |
| CommandTokenizer tokenizer(inputLine); |
| if (!tokenizer.hasNext()) |
| die(inputLine); |
| |
| result.pathOrURL = tokenizer.next(); |
| if (!tokenizer.hasNext()) |
| return result; |
| |
| std::string arg = tokenizer.next(); |
| if (arg != std::string("-p") && arg != std::string("--pixel-test")) |
| die(inputLine); |
| result.shouldDumpPixels = true; |
| |
| if (tokenizer.hasNext()) |
| result.expectedPixelHash = tokenizer.next(); |
| |
| return result; |
| } |
| |
| bool TestController::runTest(const char* inputLine) |
| { |
| TestCommand command = parseInputLine(std::string(inputLine)); |
| |
| m_state = RunningTest; |
| |
| m_currentInvocation = adoptPtr(new TestInvocation(command.pathOrURL)); |
| if (command.shouldDumpPixels) |
| m_currentInvocation->setIsPixelTest(command.expectedPixelHash); |
| |
| m_currentInvocation->invoke(); |
| m_currentInvocation.clear(); |
| |
| return true; |
| } |
| |
| void TestController::runTestingServerLoop() |
| { |
| char filenameBuffer[2048]; |
| while (fgets(filenameBuffer, sizeof(filenameBuffer), stdin)) { |
| char* newLineCharacter = strchr(filenameBuffer, '\n'); |
| if (newLineCharacter) |
| *newLineCharacter = '\0'; |
| |
| if (strlen(filenameBuffer) == 0) |
| continue; |
| |
| if (!runTest(filenameBuffer)) |
| break; |
| } |
| } |
| |
| void TestController::run() |
| { |
| if (!resetStateToConsistentValues()) { |
| TestInvocation::dumpWebProcessUnresponsiveness("Failed to reset to consistent state before the first test"); |
| return; |
| } |
| |
| if (m_usingServerMode) |
| runTestingServerLoop(); |
| else { |
| for (size_t i = 0; i < m_paths.size(); ++i) { |
| if (!runTest(m_paths[i].c_str())) |
| break; |
| } |
| } |
| } |
| |
| void TestController::runUntil(bool& done, TimeoutDuration timeoutDuration) |
| { |
| double timeout = m_noTimeout; |
| if (!m_forceNoTimeout) { |
| switch (timeoutDuration) { |
| case ShortTimeout: |
| timeout = m_shortTimeout; |
| break; |
| case LongTimeout: |
| timeout = m_longTimeout; |
| break; |
| case NoTimeout: |
| default: |
| timeout = m_noTimeout; |
| break; |
| } |
| } |
| |
| platformRunUntil(done, timeout); |
| } |
| |
| // WKContextInjectedBundleClient |
| |
| void TestController::didReceiveMessageFromInjectedBundle(WKContextRef context, WKStringRef messageName, WKTypeRef messageBody, const void* clientInfo) |
| { |
| static_cast<TestController*>(const_cast<void*>(clientInfo))->didReceiveMessageFromInjectedBundle(messageName, messageBody); |
| } |
| |
| void TestController::didReceiveSynchronousMessageFromInjectedBundle(WKContextRef context, WKStringRef messageName, WKTypeRef messageBody, WKTypeRef* returnData, const void* clientInfo) |
| { |
| *returnData = static_cast<TestController*>(const_cast<void*>(clientInfo))->didReceiveSynchronousMessageFromInjectedBundle(messageName, messageBody).leakRef(); |
| } |
| |
| void TestController::didReceiveMessageFromInjectedBundle(WKStringRef messageName, WKTypeRef messageBody) |
| { |
| #if PLATFORM(MAC) || PLATFORM(QT) || PLATFORM(GTK) || PLATFORM(EFL) |
| if (WKStringIsEqualToUTF8CString(messageName, "EventSender")) { |
| ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID()); |
| WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody); |
| |
| WKRetainPtr<WKStringRef> subMessageKey(AdoptWK, WKStringCreateWithUTF8CString("SubMessage")); |
| WKStringRef subMessageName = static_cast<WKStringRef>(WKDictionaryGetItemForKey(messageBodyDictionary, subMessageKey.get())); |
| |
| if (WKStringIsEqualToUTF8CString(subMessageName, "MouseDown") || WKStringIsEqualToUTF8CString(subMessageName, "MouseUp")) { |
| WKRetainPtr<WKStringRef> buttonKey = adoptWK(WKStringCreateWithUTF8CString("Button")); |
| unsigned button = static_cast<unsigned>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, buttonKey.get())))); |
| |
| WKRetainPtr<WKStringRef> modifiersKey = adoptWK(WKStringCreateWithUTF8CString("Modifiers")); |
| WKEventModifiers modifiers = static_cast<WKEventModifiers>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, modifiersKey.get())))); |
| |
| // Forward to WebProcess |
| WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false); |
| if (WKStringIsEqualToUTF8CString(subMessageName, "MouseDown")) |
| m_eventSenderProxy->mouseDown(button, modifiers); |
| else |
| m_eventSenderProxy->mouseUp(button, modifiers); |
| |
| return; |
| } |
| ASSERT_NOT_REACHED(); |
| } |
| #endif |
| |
| if (!m_currentInvocation) |
| return; |
| |
| m_currentInvocation->didReceiveMessageFromInjectedBundle(messageName, messageBody); |
| } |
| |
| WKRetainPtr<WKTypeRef> TestController::didReceiveSynchronousMessageFromInjectedBundle(WKStringRef messageName, WKTypeRef messageBody) |
| { |
| #if PLATFORM(MAC) || PLATFORM(QT) || PLATFORM(GTK) || PLATFORM(EFL) |
| if (WKStringIsEqualToUTF8CString(messageName, "EventSender")) { |
| ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID()); |
| WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody); |
| |
| WKRetainPtr<WKStringRef> subMessageKey(AdoptWK, WKStringCreateWithUTF8CString("SubMessage")); |
| WKStringRef subMessageName = static_cast<WKStringRef>(WKDictionaryGetItemForKey(messageBodyDictionary, subMessageKey.get())); |
| |
| if (WKStringIsEqualToUTF8CString(subMessageName, "KeyDown")) { |
| WKRetainPtr<WKStringRef> keyKey = adoptWK(WKStringCreateWithUTF8CString("Key")); |
| WKStringRef key = static_cast<WKStringRef>(WKDictionaryGetItemForKey(messageBodyDictionary, keyKey.get())); |
| |
| WKRetainPtr<WKStringRef> modifiersKey = adoptWK(WKStringCreateWithUTF8CString("Modifiers")); |
| WKEventModifiers modifiers = static_cast<WKEventModifiers>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, modifiersKey.get())))); |
| |
| WKRetainPtr<WKStringRef> locationKey = adoptWK(WKStringCreateWithUTF8CString("Location")); |
| unsigned location = static_cast<unsigned>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, locationKey.get())))); |
| |
| // Forward to WebProcess |
| WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), true); |
| m_eventSenderProxy->keyDown(key, modifiers, location); |
| WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false); |
| return 0; |
| } |
| |
| if (WKStringIsEqualToUTF8CString(subMessageName, "MouseDown") || WKStringIsEqualToUTF8CString(subMessageName, "MouseUp")) { |
| WKRetainPtr<WKStringRef> buttonKey = adoptWK(WKStringCreateWithUTF8CString("Button")); |
| unsigned button = static_cast<unsigned>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, buttonKey.get())))); |
| |
| WKRetainPtr<WKStringRef> modifiersKey = adoptWK(WKStringCreateWithUTF8CString("Modifiers")); |
| WKEventModifiers modifiers = static_cast<WKEventModifiers>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, modifiersKey.get())))); |
| |
| // Forward to WebProcess |
| WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), true); |
| if (WKStringIsEqualToUTF8CString(subMessageName, "MouseDown")) |
| m_eventSenderProxy->mouseDown(button, modifiers); |
| else |
| m_eventSenderProxy->mouseUp(button, modifiers); |
| WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false); |
| return 0; |
| } |
| |
| if (WKStringIsEqualToUTF8CString(subMessageName, "MouseMoveTo")) { |
| WKRetainPtr<WKStringRef> xKey = adoptWK(WKStringCreateWithUTF8CString("X")); |
| double x = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, xKey.get()))); |
| |
| WKRetainPtr<WKStringRef> yKey = adoptWK(WKStringCreateWithUTF8CString("Y")); |
| double y = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, yKey.get()))); |
| |
| // Forward to WebProcess |
| WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), true); |
| m_eventSenderProxy->mouseMoveTo(x, y); |
| WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false); |
| return 0; |
| } |
| |
| if (WKStringIsEqualToUTF8CString(subMessageName, "MouseScrollBy")) { |
| WKRetainPtr<WKStringRef> xKey = adoptWK(WKStringCreateWithUTF8CString("X")); |
| double x = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, xKey.get()))); |
| |
| WKRetainPtr<WKStringRef> yKey = adoptWK(WKStringCreateWithUTF8CString("Y")); |
| double y = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, yKey.get()))); |
| |
| // Forward to WebProcess |
| WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), true); |
| m_eventSenderProxy->mouseScrollBy(x, y); |
| WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false); |
| return 0; |
| } |
| |
| if (WKStringIsEqualToUTF8CString(subMessageName, "ContinuousMouseScrollBy")) { |
| WKRetainPtr<WKStringRef> xKey = adoptWK(WKStringCreateWithUTF8CString("X")); |
| double x = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, xKey.get()))); |
| |
| WKRetainPtr<WKStringRef> yKey = adoptWK(WKStringCreateWithUTF8CString("Y")); |
| double y = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, yKey.get()))); |
| |
| WKRetainPtr<WKStringRef> pagedKey = adoptWK(WKStringCreateWithUTF8CString("Paged")); |
| bool paged = static_cast<bool>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, pagedKey.get())))); |
| |
| // Forward to WebProcess |
| WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), true); |
| m_eventSenderProxy->continuousMouseScrollBy(x, y, paged); |
| WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false); |
| return 0; |
| } |
| |
| if (WKStringIsEqualToUTF8CString(subMessageName, "LeapForward")) { |
| WKRetainPtr<WKStringRef> timeKey = adoptWK(WKStringCreateWithUTF8CString("TimeInMilliseconds")); |
| unsigned time = static_cast<unsigned>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, timeKey.get())))); |
| |
| m_eventSenderProxy->leapForward(time); |
| return 0; |
| } |
| |
| #if ENABLE(TOUCH_EVENTS) |
| if (WKStringIsEqualToUTF8CString(subMessageName, "AddTouchPoint")) { |
| WKRetainPtr<WKStringRef> xKey = adoptWK(WKStringCreateWithUTF8CString("X")); |
| int x = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, xKey.get())))); |
| |
| WKRetainPtr<WKStringRef> yKey = adoptWK(WKStringCreateWithUTF8CString("Y")); |
| int y = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, yKey.get())))); |
| |
| m_eventSenderProxy->addTouchPoint(x, y); |
| return 0; |
| } |
| |
| if (WKStringIsEqualToUTF8CString(subMessageName, "UpdateTouchPoint")) { |
| WKRetainPtr<WKStringRef> indexKey = adoptWK(WKStringCreateWithUTF8CString("Index")); |
| int index = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, indexKey.get())))); |
| |
| WKRetainPtr<WKStringRef> xKey = adoptWK(WKStringCreateWithUTF8CString("X")); |
| int x = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, xKey.get())))); |
| |
| WKRetainPtr<WKStringRef> yKey = adoptWK(WKStringCreateWithUTF8CString("Y")); |
| int y = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, yKey.get())))); |
| |
| m_eventSenderProxy->updateTouchPoint(index, x, y); |
| return 0; |
| } |
| |
| if (WKStringIsEqualToUTF8CString(subMessageName, "SetTouchModifier")) { |
| WKRetainPtr<WKStringRef> modifierKey = adoptWK(WKStringCreateWithUTF8CString("Modifier")); |
| WKEventModifiers modifier = static_cast<WKEventModifiers>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, modifierKey.get())))); |
| |
| WKRetainPtr<WKStringRef> enableKey = adoptWK(WKStringCreateWithUTF8CString("Enable")); |
| bool enable = static_cast<bool>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, enableKey.get())))); |
| |
| m_eventSenderProxy->setTouchModifier(modifier, enable); |
| return 0; |
| } |
| |
| if (WKStringIsEqualToUTF8CString(subMessageName, "SetTouchPointRadius")) { |
| WKRetainPtr<WKStringRef> xKey = adoptWK(WKStringCreateWithUTF8CString("RadiusX")); |
| int x = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, xKey.get())))); |
| |
| WKRetainPtr<WKStringRef> yKey = adoptWK(WKStringCreateWithUTF8CString("RadiusY")); |
| int y = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, yKey.get())))); |
| |
| m_eventSenderProxy->setTouchPointRadius(x, y); |
| return 0; |
| } |
| |
| if (WKStringIsEqualToUTF8CString(subMessageName, "TouchStart")) { |
| WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), true); |
| m_eventSenderProxy->touchStart(); |
| WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false); |
| return 0; |
| } |
| |
| if (WKStringIsEqualToUTF8CString(subMessageName, "TouchMove")) { |
| WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), true); |
| m_eventSenderProxy->touchMove(); |
| WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false); |
| return 0; |
| } |
| |
| if (WKStringIsEqualToUTF8CString(subMessageName, "TouchEnd")) { |
| WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), true); |
| m_eventSenderProxy->touchEnd(); |
| WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false); |
| return 0; |
| } |
| |
| if (WKStringIsEqualToUTF8CString(subMessageName, "TouchCancel")) { |
| WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), true); |
| m_eventSenderProxy->touchCancel(); |
| WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false); |
| return 0; |
| } |
| |
| if (WKStringIsEqualToUTF8CString(subMessageName, "ClearTouchPoints")) { |
| m_eventSenderProxy->clearTouchPoints(); |
| return 0; |
| } |
| |
| if (WKStringIsEqualToUTF8CString(subMessageName, "ReleaseTouchPoint")) { |
| WKRetainPtr<WKStringRef> indexKey = adoptWK(WKStringCreateWithUTF8CString("Index")); |
| int index = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, indexKey.get())))); |
| m_eventSenderProxy->releaseTouchPoint(index); |
| return 0; |
| } |
| |
| if (WKStringIsEqualToUTF8CString(subMessageName, "CancelTouchPoint")) { |
| WKRetainPtr<WKStringRef> indexKey = adoptWK(WKStringCreateWithUTF8CString("Index")); |
| int index = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, indexKey.get())))); |
| m_eventSenderProxy->cancelTouchPoint(index); |
| return 0; |
| } |
| #endif |
| ASSERT_NOT_REACHED(); |
| } |
| #endif |
| return m_currentInvocation->didReceiveSynchronousMessageFromInjectedBundle(messageName, messageBody); |
| } |
| |
| // WKPageLoaderClient |
| |
| void TestController::didCommitLoadForFrame(WKPageRef page, WKFrameRef frame, WKTypeRef, const void* clientInfo) |
| { |
| static_cast<TestController*>(const_cast<void*>(clientInfo))->didCommitLoadForFrame(page, frame); |
| } |
| |
| void TestController::didFinishLoadForFrame(WKPageRef page, WKFrameRef frame, WKTypeRef, const void* clientInfo) |
| { |
| static_cast<TestController*>(const_cast<void*>(clientInfo))->didFinishLoadForFrame(page, frame); |
| } |
| |
| void TestController::processDidCrash(WKPageRef page, const void* clientInfo) |
| { |
| static_cast<TestController*>(const_cast<void*>(clientInfo))->processDidCrash(); |
| } |
| |
| void TestController::didCommitLoadForFrame(WKPageRef page, WKFrameRef frame) |
| { |
| if (!WKFrameIsMainFrame(frame)) |
| return; |
| |
| mainWebView()->focus(); |
| } |
| |
| void TestController::didFinishLoadForFrame(WKPageRef page, WKFrameRef frame) |
| { |
| if (m_state != Resetting) |
| return; |
| |
| if (!WKFrameIsMainFrame(frame)) |
| return; |
| |
| WKRetainPtr<WKURLRef> wkURL(AdoptWK, WKFrameCopyURL(frame)); |
| if (!WKURLIsEqual(wkURL.get(), blankURL())) |
| return; |
| |
| m_doneResetting = true; |
| shared().notifyDone(); |
| } |
| |
| void TestController::processDidCrash() |
| { |
| // This function can be called multiple times when crash logs are being saved on Windows, so |
| // ensure we only print the crashed message once. |
| if (!m_didPrintWebProcessCrashedMessage) { |
| #if PLATFORM(MAC) |
| pid_t pid = WKPageGetProcessIdentifier(m_mainWebView->page()); |
| fprintf(stderr, "#CRASHED - WebProcess (pid %ld)\n", static_cast<long>(pid)); |
| #else |
| fputs("#CRASHED - WebProcess\n", stderr); |
| #endif |
| fflush(stderr); |
| m_didPrintWebProcessCrashedMessage = true; |
| } |
| |
| if (m_shouldExitWhenWebProcessCrashes) |
| exit(1); |
| } |
| |
| void TestController::simulateWebNotificationClick(uint64_t notificationID) |
| { |
| m_webNotificationProvider.simulateWebNotificationClick(notificationID); |
| } |
| |
| void TestController::setGeolocationPermission(bool enabled) |
| { |
| m_isGeolocationPermissionSet = true; |
| m_isGeolocationPermissionAllowed = enabled; |
| decidePolicyForGeolocationPermissionRequestIfPossible(); |
| } |
| |
| 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) |
| { |
| m_geolocationProvider->setPosition(latitude, longitude, accuracy, providesAltitude, altitude, providesAltitudeAccuracy, altitudeAccuracy, providesHeading, heading, providesSpeed, speed); |
| } |
| |
| void TestController::setMockGeolocationPositionUnavailableError(WKStringRef errorMessage) |
| { |
| m_geolocationProvider->setPositionUnavailableError(errorMessage); |
| } |
| |
| void TestController::handleGeolocationPermissionRequest(WKGeolocationPermissionRequestRef geolocationPermissionRequest) |
| { |
| m_geolocationPermissionRequests.append(geolocationPermissionRequest); |
| decidePolicyForGeolocationPermissionRequestIfPossible(); |
| } |
| |
| void TestController::setCustomPolicyDelegate(bool enabled, bool permissive) |
| { |
| m_policyDelegateEnabled = enabled; |
| m_policyDelegatePermissive = permissive; |
| } |
| |
| void TestController::decidePolicyForGeolocationPermissionRequestIfPossible() |
| { |
| if (!m_isGeolocationPermissionSet) |
| return; |
| |
| for (size_t i = 0; i < m_geolocationPermissionRequests.size(); ++i) { |
| WKGeolocationPermissionRequestRef permissionRequest = m_geolocationPermissionRequests[i].get(); |
| if (m_isGeolocationPermissionAllowed) |
| WKGeolocationPermissionRequestAllow(permissionRequest); |
| else |
| WKGeolocationPermissionRequestDeny(permissionRequest); |
| } |
| m_geolocationPermissionRequests.clear(); |
| } |
| |
| void TestController::decidePolicyForNotificationPermissionRequest(WKPageRef page, WKSecurityOriginRef origin, WKNotificationPermissionRequestRef request, const void*) |
| { |
| TestController::shared().decidePolicyForNotificationPermissionRequest(page, origin, request); |
| } |
| |
| void TestController::decidePolicyForNotificationPermissionRequest(WKPageRef, WKSecurityOriginRef, WKNotificationPermissionRequestRef request) |
| { |
| WKNotificationPermissionRequestAllow(request); |
| } |
| |
| void TestController::decidePolicyForNavigationAction(WKPageRef, WKFrameRef, WKFrameNavigationType, WKEventModifiers, WKEventMouseButton, WKURLRequestRef, WKFramePolicyListenerRef listener, WKTypeRef, const void* clientInfo) |
| { |
| static_cast<TestController*>(const_cast<void*>(clientInfo))->decidePolicyForNavigationAction(listener); |
| } |
| |
| void TestController::decidePolicyForNavigationAction(WKFramePolicyListenerRef listener) |
| { |
| if (m_policyDelegateEnabled && !m_policyDelegatePermissive) { |
| WKFramePolicyListenerIgnore(listener); |
| return; |
| } |
| |
| WKFramePolicyListenerUse(listener); |
| } |
| |
| } // namespace WTR |