diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
commit | 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch) | |
tree | 46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebKit2/UIProcess/WebPageProxy.cpp | |
parent | 32761a6cee1d0dee366b885b7b9c777e67885688 (diff) | |
download | WebKitGtk-tarball-master.tar.gz |
webkitgtk-2.16.5HEADwebkitgtk-2.16.5master
Diffstat (limited to 'Source/WebKit2/UIProcess/WebPageProxy.cpp')
-rw-r--r-- | Source/WebKit2/UIProcess/WebPageProxy.cpp | 4453 |
1 files changed, 3433 insertions, 1020 deletions
diff --git a/Source/WebKit2/UIProcess/WebPageProxy.cpp b/Source/WebKit2/UIProcess/WebPageProxy.cpp index bb8578dc7..721bd41f2 100644 --- a/Source/WebKit2/UIProcess/WebPageProxy.cpp +++ b/Source/WebKit2/UIProcess/WebPageProxy.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010, 2011 Apple Inc. All rights reserved. + * Copyright (C) 2010, 2011, 2015-2016 Apple Inc. All rights reserved. * Copyright (C) 2012 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -28,8 +28,27 @@ #include "WebPageProxy.h" #include "APIArray.h" +#include "APIContextMenuClient.h" +#include "APIFindClient.h" +#include "APIFindMatchesClient.h" +#include "APIFormClient.h" +#include "APIFrameInfo.h" +#include "APIFullscreenClient.h" +#include "APIGeometry.h" +#include "APIHistoryClient.h" +#include "APIHitTestResult.h" +#include "APIIconLoadingClient.h" +#include "APILegacyContextHistoryClient.h" #include "APILoaderClient.h" +#include "APINavigation.h" +#include "APINavigationAction.h" +#include "APINavigationClient.h" +#include "APINavigationResponse.h" +#include "APIOpenPanelParameters.h" +#include "APIPageConfiguration.h" #include "APIPolicyClient.h" +#include "APISecurityOrigin.h" +#include "APIUIClient.h" #include "APIURLRequest.h" #include "AuthenticationChallengeProxy.h" #include "AuthenticationDecisionListener.h" @@ -38,29 +57,30 @@ #include "DrawingAreaProxy.h" #include "DrawingAreaProxyMessages.h" #include "EventDispatcherMessages.h" -#include "FindIndicator.h" +#include "LoadParameters.h" #include "Logging.h" +#include "NativeWebGestureEvent.h" #include "NativeWebKeyboardEvent.h" #include "NativeWebMouseEvent.h" #include "NativeWebWheelEvent.h" #include "NavigationActionData.h" +#include "NetworkProcessMessages.h" #include "NotificationPermissionRequest.h" #include "NotificationPermissionRequestManager.h" #include "PageClient.h" #include "PluginInformation.h" #include "PluginProcessManager.h" #include "PrintInfo.h" -#include "SessionState.h" #include "TextChecker.h" #include "TextCheckerState.h" +#include "UserMediaPermissionRequestProxy.h" #include "WKContextPrivate.h" +#include "WebAutomationSession.h" #include "WebBackForwardList.h" #include "WebBackForwardListItem.h" #include "WebCertificateInfo.h" -#include "WebColorPickerResultListenerProxy.h" -#include "WebContext.h" +#include "WebContextMenuItem.h" #include "WebContextMenuProxy.h" -#include "WebContextUserMessageCoders.h" #include "WebCoreArgumentCoders.h" #include "WebEditCommandProxy.h" #include "WebEvent.h" @@ -69,8 +89,10 @@ #include "WebFramePolicyListenerProxy.h" #include "WebFullScreenManagerProxy.h" #include "WebFullScreenManagerProxyMessages.h" +#include "WebImage.h" #include "WebInspectorProxy.h" -#include "WebInspectorProxyMessages.h" +#include "WebInspectorUtilities.h" +#include "WebNavigationState.h" #include "WebNotificationManagerProxy.h" #include "WebOpenPanelResultListenerProxy.h" #include "WebPageCreationParameters.h" @@ -78,41 +100,42 @@ #include "WebPageGroupData.h" #include "WebPageMessages.h" #include "WebPageProxyMessages.h" +#include "WebPaymentCoordinatorProxy.h" #include "WebPopupItem.h" #include "WebPopupMenuProxy.h" #include "WebPreferences.h" #include "WebProcessMessages.h" +#include "WebProcessPool.h" #include "WebProcessProxy.h" #include "WebProtectionSpace.h" -#include "WebSecurityOrigin.h" +#include "WebUserContentControllerProxy.h" +#include "WebsiteDataStore.h" +#include <WebCore/BitmapImage.h> +#include <WebCore/DiagnosticLoggingClient.h> #include <WebCore/DragController.h> #include <WebCore/DragData.h> -#include <WebCore/DragSession.h> +#include <WebCore/EventNames.h> #include <WebCore/FloatRect.h> #include <WebCore/FocusDirection.h> +#include <WebCore/JSDOMBinding.h> +#include <WebCore/JSDOMExceptionHandling.h> #include <WebCore/MIMETypeRegistry.h> #include <WebCore/RenderEmbeddedObject.h> +#include <WebCore/SerializedCryptoKeyWrap.h> #include <WebCore/TextCheckerClient.h> +#include <WebCore/TextIndicator.h> +#include <WebCore/URL.h> +#include <WebCore/ValidationBubble.h> #include <WebCore/WindowFeatures.h> -#include <wtf/NeverDestroyed.h> #include <stdio.h> +#include <wtf/NeverDestroyed.h> +#include <wtf/text/StringBuilder.h> +#include <wtf/text/StringView.h> #if ENABLE(ASYNC_SCROLLING) #include "RemoteScrollingCoordinatorProxy.h" #endif -#if USE(COORDINATED_GRAPHICS) -#include "CoordinatedLayerTreeHostProxyMessages.h" -#endif - -#if PLATFORM(GTK) -#include "ArgumentCodersGtk.h" -#endif - -#if USE(SOUP) && !ENABLE(CUSTOM_PROTOCOLS) -#include "WebSoupRequestManagerProxy.h" -#endif - #if ENABLE(VIBRATION) #include "WebVibrationProxy.h" #endif @@ -121,24 +144,52 @@ #include <wtf/RefCountedLeakCounter.h> #endif -#if ENABLE(NETWORK_PROCESS) -#include "NetworkProcessMessages.h" +#if PLATFORM(COCOA) +#include "RemoteLayerTreeDrawingAreaProxy.h" +#include "RemoteLayerTreeScrollingPerformanceData.h" +#include "ViewSnapshotStore.h" +#include "WebVideoFullscreenManagerProxy.h" +#include "WebVideoFullscreenManagerProxyMessages.h" +#include <WebCore/MachSendRight.h> +#include <WebCore/RunLoopObserver.h> +#include <WebCore/TextIndicatorWindow.h> #endif -#if PLATFORM(MAC) -#include "ViewSnapshotStore.h" +#if PLATFORM(GTK) +#include "WebSelectionData.h" #endif #if USE(CAIRO) #include <WebCore/CairoUtilities.h> #endif +#if ENABLE(WIRELESS_PLAYBACK_TARGET) && !PLATFORM(IOS) +#include <WebCore/MediaPlaybackTarget.h> +#include <WebCore/WebMediaSessionManager.h> +#endif + +#if ENABLE(MEDIA_SESSION) +#include "WebMediaSessionFocusManager.h" +#include "WebMediaSessionMetadata.h" +#include <WebCore/MediaSessionMetadata.h> +#endif + +#if PLATFORM(IOS) || (PLATFORM(MAC) && ENABLE(VIDEO_PRESENTATION_MODE)) +#include "WebPlaybackSessionManagerProxy.h" +#endif + +#if ENABLE(MEDIA_STREAM) +#include <WebCore/MediaConstraintsImpl.h> +#endif + // This controls what strategy we use for mouse wheel coalescing. #define MERGE_WHEEL_EVENTS 1 #define MESSAGE_CHECK(assertion) MESSAGE_CHECK_BASE(assertion, m_process->connection()) #define MESSAGE_CHECK_URL(url) MESSAGE_CHECK_BASE(m_process->checkURLReceivedFromWebProcess(url), m_process->connection()) +#define RELEASE_LOG_IF_ALLOWED(...) RELEASE_LOG_IF(isAlwaysOnLoggingAllowed(), ProcessSuspension, __VA_ARGS__) + using namespace WebCore; // Represents the number of wheel events we can hold in the queue before we start pushing them preemptively. @@ -164,37 +215,37 @@ public: RefPtr<Messages::WebPageProxy::ExceededDatabaseQuota::DelayedReply> reply; }; - static ExceededDatabaseQuotaRecords& shared(); + static ExceededDatabaseQuotaRecords& singleton(); - PassOwnPtr<Record> createRecord(uint64_t frameID, String originIdentifier, + std::unique_ptr<Record> createRecord(uint64_t frameID, String originIdentifier, String databaseName, String displayName, uint64_t currentQuota, uint64_t currentOriginUsage, uint64_t currentDatabaseUsage, uint64_t expectedUsage, PassRefPtr<Messages::WebPageProxy::ExceededDatabaseQuota::DelayedReply>); - void add(PassOwnPtr<Record>); - bool areBeingProcessed() const { return m_currentRecord; } + void add(std::unique_ptr<Record>); + bool areBeingProcessed() const { return !!m_currentRecord; } Record* next(); private: ExceededDatabaseQuotaRecords() { } ~ExceededDatabaseQuotaRecords() { } - Deque<OwnPtr<Record>> m_records; - OwnPtr<Record> m_currentRecord; + Deque<std::unique_ptr<Record>> m_records; + std::unique_ptr<Record> m_currentRecord; }; -ExceededDatabaseQuotaRecords& ExceededDatabaseQuotaRecords::shared() +ExceededDatabaseQuotaRecords& ExceededDatabaseQuotaRecords::singleton() { static NeverDestroyed<ExceededDatabaseQuotaRecords> records; return records; } -PassOwnPtr<ExceededDatabaseQuotaRecords::Record> ExceededDatabaseQuotaRecords::createRecord( +std::unique_ptr<ExceededDatabaseQuotaRecords::Record> ExceededDatabaseQuotaRecords::createRecord( uint64_t frameID, String originIdentifier, String databaseName, String displayName, uint64_t currentQuota, uint64_t currentOriginUsage, uint64_t currentDatabaseUsage, uint64_t expectedUsage, PassRefPtr<Messages::WebPageProxy::ExceededDatabaseQuota::DelayedReply> reply) { - OwnPtr<Record> record = adoptPtr(new Record); + auto record = std::make_unique<Record>(); record->frameID = frameID; record->originIdentifier = originIdentifier; record->databaseName = databaseName; @@ -204,17 +255,17 @@ PassOwnPtr<ExceededDatabaseQuotaRecords::Record> ExceededDatabaseQuotaRecords::c record->currentDatabaseUsage = currentDatabaseUsage; record->expectedUsage = expectedUsage; record->reply = reply; - return record.release(); + return record; } -void ExceededDatabaseQuotaRecords::add(PassOwnPtr<ExceededDatabaseQuotaRecords::Record> record) +void ExceededDatabaseQuotaRecords::add(std::unique_ptr<ExceededDatabaseQuotaRecords::Record> record) { - m_records.append(record); + m_records.append(WTFMove(record)); } ExceededDatabaseQuotaRecords::Record* ExceededDatabaseQuotaRecords::next() { - m_currentRecord.clear(); + m_currentRecord = nullptr; if (!m_records.isEmpty()) m_currentRecord = m_records.takeFirst(); return m_currentRecord.get(); @@ -243,40 +294,85 @@ static const char* webKeyboardEventTypeString(WebEvent::Type type) } #endif // !LOG_DISABLED -PassRefPtr<WebPageProxy> WebPageProxy::create(PageClient& pageClient, WebProcessProxy& process, uint64_t pageID, const WebPageConfiguration& configuration) +class PageClientProtector { + WTF_MAKE_NONCOPYABLE(PageClientProtector); +public: + PageClientProtector(PageClient& pageClient) + : m_pageClient(pageClient) + { + m_pageClient.refView(); + } + + ~PageClientProtector() + { + m_pageClient.derefView(); + } + +private: + PageClient& m_pageClient; +}; + +Ref<WebPageProxy> WebPageProxy::create(PageClient& pageClient, WebProcessProxy& process, uint64_t pageID, Ref<API::PageConfiguration>&& configuration) { - return adoptRef(new WebPageProxy(pageClient, process, pageID, configuration)); + return adoptRef(*new WebPageProxy(pageClient, process, pageID, WTFMove(configuration))); } -WebPageProxy::WebPageProxy(PageClient& pageClient, WebProcessProxy& process, uint64_t pageID, const WebPageConfiguration& configuration) +WebPageProxy::WebPageProxy(PageClient& pageClient, WebProcessProxy& process, uint64_t pageID, Ref<API::PageConfiguration>&& configuration) : m_pageClient(pageClient) + , m_configuration(WTFMove(configuration)) , m_loaderClient(std::make_unique<API::LoaderClient>()) , m_policyClient(std::make_unique<API::PolicyClient>()) + , m_formClient(std::make_unique<API::FormClient>()) + , m_uiClient(std::make_unique<API::UIClient>()) + , m_findClient(std::make_unique<API::FindClient>()) + , m_findMatchesClient(std::make_unique<API::FindMatchesClient>()) + , m_diagnosticLoggingClient(std::make_unique<API::DiagnosticLoggingClient>()) +#if ENABLE(CONTEXT_MENUS) + , m_contextMenuClient(std::make_unique<API::ContextMenuClient>()) +#endif + , m_navigationState(std::make_unique<WebNavigationState>()) , m_process(process) - , m_pageGroup(*configuration.pageGroup) + , m_pageGroup(*m_configuration->pageGroup()) + , m_preferences(*m_configuration->preferences()) + , m_userContentController(*m_configuration->userContentController()) + , m_visitedLinkStore(*m_configuration->visitedLinkStore()) + , m_websiteDataStore(m_configuration->websiteDataStore()->websiteDataStore()) , m_mainFrame(nullptr) , m_userAgent(standardUserAgent()) + , m_overrideContentSecurityPolicy { m_configuration->overrideContentSecurityPolicy() } + , m_treatsSHA1CertificatesAsInsecure(m_configuration->treatsSHA1SignedCertificatesAsInsecure()) +#if ENABLE(FULLSCREEN_API) + , m_fullscreenClient(std::make_unique<API::FullscreenClient>()) +#endif , m_geolocationPermissionRequestManager(*this) , m_notificationPermissionRequestManager(*this) - , m_viewState(ViewState::NoFlags) + , m_activityState(ActivityState::NoFlags) + , m_viewWasEverInWindow(false) +#if PLATFORM(IOS) + , m_alwaysRunsAtForegroundPriority(m_configuration->alwaysRunsAtForegroundPriority()) +#endif + , m_initialCapitalizationEnabled(m_configuration->initialCapitalizationEnabled()) , m_backForwardList(WebBackForwardList::create(*this)) - , m_loadStateAtProcessExit(FrameLoadState::State::Finished) - , m_temporarilyClosedComposition(false) + , m_maintainsInactiveSelection(false) + , m_waitsForPaintAfterViewDidMoveToWindow(m_configuration->waitsForPaintAfterViewDidMoveToWindow()) + , m_isEditable(false) , m_textZoomFactor(1) , m_pageZoomFactor(1) , m_pageScaleFactor(1) + , m_pluginZoomFactor(1) + , m_pluginScaleFactor(1) , m_intrinsicDeviceScaleFactor(1) , m_customDeviceScaleFactor(0) - , m_layerHostingMode(LayerHostingModeDefault) + , m_topContentInset(0) + , m_layerHostingMode(LayerHostingMode::InProcess) , m_drawsBackground(true) - , m_drawsTransparentBackground(false) - , m_areMemoryCacheClientCallsEnabled(true) , m_useFixedLayout(false) , m_suppressScrollbarAnimations(false) , m_paginationMode(Pagination::Unpaginated) , m_paginationBehavesLikeColumns(false) , m_pageLength(0) , m_gapBetweenPages(0) + , m_paginationLineGridEnabled(false) , m_isValid(true) , m_isClosed(false) , m_canRunModal(false) @@ -292,47 +388,76 @@ WebPageProxy::WebPageProxy(PageClient& pageClient, WebProcessProxy& process, uin , m_syncNavigationActionPolicyAction(PolicyUse) , m_syncNavigationActionPolicyDownloadID(0) , m_processingMouseMoveEvent(false) -#if ENABLE(TOUCH_EVENTS) - , m_needTouchEvents(false) -#endif , m_pageID(pageID) - , m_session(*configuration.session) + , m_sessionID(m_configuration->sessionID()) , m_isPageSuspended(false) -#if PLATFORM(MAC) + , m_addsVisitedLinks(true) + , m_controlledByAutomation(m_configuration->isControlledByAutomation()) +#if ENABLE(REMOTE_INSPECTOR) + , m_allowsRemoteInspection(true) +#endif +#if PLATFORM(COCOA) , m_isSmartInsertDeleteEnabled(TextChecker::isSmartInsertDeleteEnabled()) #endif +#if PLATFORM(GTK) + , m_backgroundColor(Color::white) +#endif , m_spellDocumentTag(0) , m_hasSpellDocumentTag(false) , m_pendingLearnOrIgnoreWordMessageCount(0) + , m_mainFrameHasCustomContentProvider(false) +#if ENABLE(DRAG_SUPPORT) + , m_currentDragOperation(DragOperationNone) + , m_currentDragIsOverFileInput(false) + , m_currentDragNumberOfFilesToBeAccepted(0) +#endif + , m_pageLoadState(*this) + , m_delegatesScrolling(false) , m_mainFrameHasHorizontalScrollbar(false) , m_mainFrameHasVerticalScrollbar(false) , m_canShortCircuitHorizontalWheelEvents(true) - , m_mainFrameIsPinnedToLeftSide(false) - , m_mainFrameIsPinnedToRightSide(false) - , m_mainFrameIsPinnedToTopSide(false) - , m_mainFrameIsPinnedToBottomSide(false) - , m_useLegacyImplicitRubberBandControl(false) + , m_mainFrameIsPinnedToLeftSide(true) + , m_mainFrameIsPinnedToRightSide(true) + , m_mainFrameIsPinnedToTopSide(true) + , m_mainFrameIsPinnedToBottomSide(true) + , m_shouldUseImplicitRubberBandControl(false) , m_rubberBandsAtLeft(true) , m_rubberBandsAtRight(true) , m_rubberBandsAtTop(true) , m_rubberBandsAtBottom(true) + , m_enableVerticalRubberBanding(true) + , m_enableHorizontalRubberBanding(true) , m_backgroundExtendsBeyondPage(false) - , m_mainFrameInViewSourceMode(false) , m_shouldRecordNavigationSnapshots(false) + , m_isShowingNavigationGestureSnapshot(false) , m_pageCount(0) , m_renderTreeSize(0) - , m_shouldSendEventsSynchronously(false) + , m_sessionRestorationRenderTreeSize(0) + , m_hitRenderTreeSizeThreshold(false) , m_suppressVisibilityUpdates(false) , m_autoSizingShouldExpandToViewHeight(false) , m_mediaVolume(1) , m_mayStartMediaWhenInWindow(true) - , m_waitingForDidUpdateViewState(false) + , m_waitingForDidUpdateActivityState(false) +#if PLATFORM(COCOA) + , m_scrollPerformanceDataCollectionEnabled(false) +#endif , m_scrollPinningBehavior(DoNotPin) -{ - updateViewState(); - -#if HAVE(LAYER_HOSTING_IN_WINDOW_SERVER) - m_layerHostingMode = m_viewState & ViewState::IsInWindow ? m_pageClient.viewLayerHostingMode() : LayerHostingModeInWindowServer; + , m_navigationID(0) + , m_configurationPreferenceValues(m_configuration->preferenceValues()) + , m_potentiallyChangedActivityStateFlags(ActivityState::NoFlags) + , m_activityStateChangeWantsSynchronousReply(false) + , m_weakPtrFactory(this) +{ + m_webProcessLifetimeTracker.addObserver(m_visitedLinkStore); + m_webProcessLifetimeTracker.addObserver(m_websiteDataStore); + + updateActivityState(); + updateThrottleState(); + updateHiddenPageThrottlingAutoIncreases(); + +#if HAVE(OUT_OF_PROCESS_LAYER_HOSTING) + m_layerHostingMode = m_activityState & ActivityState::IsInWindow ? m_pageClient.viewLayerHostingMode() : LayerHostingMode::OutOfProcess; #endif platformInitialize(); @@ -341,37 +466,59 @@ WebPageProxy::WebPageProxy(PageClient& pageClient, WebProcessProxy& process, uin webPageProxyCounter.increment(); #endif - WebContext::statistics().wkPageCount++; + WebProcessPool::statistics().wkPageCount++; + m_preferences->addPage(*this); m_pageGroup->addPage(this); -#if ENABLE(INSPECTOR) m_inspector = WebInspectorProxy::create(this); -#endif #if ENABLE(FULLSCREEN_API) m_fullScreenManager = WebFullScreenManagerProxy::create(*this, m_pageClient.fullScreenManagerProxyClient()); #endif +#if PLATFORM(IOS) && HAVE(AVKIT) || (PLATFORM(MAC) && ENABLE(VIDEO_PRESENTATION_MODE)) + m_playbackSessionManager = WebPlaybackSessionManagerProxy::create(*this); + m_videoFullscreenManager = WebVideoFullscreenManagerProxy::create(*this, *m_playbackSessionManager); +#endif #if ENABLE(VIBRATION) m_vibration = WebVibrationProxy::create(this); #endif +#if ENABLE(APPLE_PAY) + m_paymentCoordinator = std::make_unique<WebPaymentCoordinatorProxy>(*this); +#endif + m_process->addMessageReceiver(Messages::WebPageProxy::messageReceiverName(), m_pageID, *this); - // FIXME: If we ever expose the session storage size as a preference, we need to pass it here. - m_process->context().storageManager().createSessionStorageNamespace(m_pageID, m_process->isValid() ? m_process->connection() : 0, std::numeric_limits<unsigned>::max()); - setSession(*configuration.session); + if (m_sessionID.isEphemeral()) { + m_process->processPool().sendToNetworkingProcess(Messages::NetworkProcess::EnsurePrivateBrowsingSession(m_sessionID)); + m_process->processPool().sendToAllProcesses(Messages::WebProcess::EnsurePrivateBrowsingSession(m_sessionID)); + } + +#if PLATFORM(COCOA) + const CFIndex activityStateChangeRunLoopOrder = (CFIndex)RunLoopObserver::WellKnownRunLoopOrders::CoreAnimationCommit - 1; + m_activityStateChangeDispatcher = std::make_unique<RunLoopObserver>(activityStateChangeRunLoopOrder, [this] { + this->dispatchActivityStateChange(); + }); +#endif } WebPageProxy::~WebPageProxy() { + ASSERT(m_process->webPage(m_pageID) != this); +#if !ASSERT_DISABLED + for (WebPageProxy* page : m_process->pages()) + ASSERT(page != this); +#endif + if (!m_isClosed) close(); - WebContext::statistics().wkPageCount--; + WebProcessPool::statistics().wkPageCount--; if (m_hasSpellDocumentTag) TextChecker::closeSpellDocumentWithTag(m_spellDocumentTag); + m_preferences->removePage(*this); m_pageGroup->removePage(this); #ifndef NDEBUG @@ -379,7 +526,12 @@ WebPageProxy::~WebPageProxy() #endif } -PlatformProcessIdentifier WebPageProxy::processIdentifier() const +const API::PageConfiguration& WebPageProxy::configuration() const +{ + return m_configuration.get(); +} + +pid_t WebPageProxy::processIdentifier() const { if (m_isClosed) return 0; @@ -396,20 +548,26 @@ bool WebPageProxy::isValid() const return m_isValid; } -PassRefPtr<API::Array> WebPageProxy::relatedPages() const +void WebPageProxy::setPreferences(WebPreferences& preferences) { - // pages() returns a list of pages in WebProcess, so this page may or may not be among them - a client can use a reference to WebPageProxy after the page has closed. - Vector<WebPageProxy*> pages = m_process->pages(); + if (&preferences == m_preferences.ptr()) + return; - Vector<RefPtr<API::Object>> result; - result.reserveInitialCapacity(pages.size()); + m_preferences->removePage(*this); + m_preferences = preferences; + m_preferences->addPage(*this); - for (const auto& page : pages) { - if (page != this) - result.uncheckedAppend(page); - } + preferencesDidChange(); +} + +void WebPageProxy::setHistoryClient(std::unique_ptr<API::HistoryClient> historyClient) +{ + m_historyClient = WTFMove(historyClient); +} - return API::Array::create(std::move(result)); +void WebPageProxy::setNavigationClient(std::unique_ptr<API::NavigationClient> navigationClient) +{ + m_navigationClient = WTFMove(navigationClient); } void WebPageProxy::setLoaderClient(std::unique_ptr<API::LoaderClient> loaderClient) @@ -419,7 +577,7 @@ void WebPageProxy::setLoaderClient(std::unique_ptr<API::LoaderClient> loaderClie return; } - m_loaderClient = std::move(loaderClient); + m_loaderClient = WTFMove(loaderClient); } void WebPageProxy::setPolicyClient(std::unique_ptr<API::PolicyClient> policyClient) @@ -429,65 +587,158 @@ void WebPageProxy::setPolicyClient(std::unique_ptr<API::PolicyClient> policyClie return; } - m_policyClient = std::move(policyClient); + m_policyClient = WTFMove(policyClient); } -void WebPageProxy::initializeFormClient(const WKPageFormClientBase* formClient) +void WebPageProxy::setFormClient(std::unique_ptr<API::FormClient> formClient) { - m_formClient.initialize(formClient); + if (!formClient) { + m_formClient = std::make_unique<API::FormClient>(); + return; + } + + m_formClient = WTFMove(formClient); } -void WebPageProxy::initializeUIClient(const WKPageUIClientBase* client) +void WebPageProxy::setUIClient(std::unique_ptr<API::UIClient> uiClient) { + if (!uiClient) { + m_uiClient = std::make_unique<API::UIClient>(); + return; + } + + m_uiClient = WTFMove(uiClient); + if (!isValid()) return; - m_uiClient.initialize(client); + m_process->send(Messages::WebPage::SetCanRunBeforeUnloadConfirmPanel(m_uiClient->canRunBeforeUnloadConfirmPanel()), m_pageID); + setCanRunModal(m_uiClient->canRunModal()); +} - m_process->send(Messages::WebPage::SetCanRunBeforeUnloadConfirmPanel(m_uiClient.canRunBeforeUnloadConfirmPanel()), m_pageID); - setCanRunModal(m_uiClient.canRunModal()); +void WebPageProxy::setIconLoadingClient(std::unique_ptr<API::IconLoadingClient> iconLoadingClient) +{ + bool hasClient = iconLoadingClient.get(); + if (!iconLoadingClient) + m_iconLoadingClient = std::make_unique<API::IconLoadingClient>(); + else + m_iconLoadingClient = WTFMove(iconLoadingClient); + + if (!isValid()) + return; + + m_process->send(Messages::WebPage::SetUseIconLoadingClient(hasClient), m_pageID); } -void WebPageProxy::initializeFindClient(const WKPageFindClientBase* client) +void WebPageProxy::setFindClient(std::unique_ptr<API::FindClient> findClient) { - m_findClient.initialize(client); + if (!findClient) { + m_findClient = std::make_unique<API::FindClient>(); + return; + } + + m_findClient = WTFMove(findClient); } -void WebPageProxy::initializeFindMatchesClient(const WKPageFindMatchesClientBase* client) +void WebPageProxy::setFindMatchesClient(std::unique_ptr<API::FindMatchesClient> findMatchesClient) { - m_findMatchesClient.initialize(client); + if (!findMatchesClient) { + m_findMatchesClient = std::make_unique<API::FindMatchesClient>(); + return; + } + + m_findMatchesClient = WTFMove(findMatchesClient); +} + +void WebPageProxy::setDiagnosticLoggingClient(std::unique_ptr<API::DiagnosticLoggingClient> diagnosticLoggingClient) +{ + if (!diagnosticLoggingClient) { + m_diagnosticLoggingClient = std::make_unique<API::DiagnosticLoggingClient>(); + return; + } + + m_diagnosticLoggingClient = WTFMove(diagnosticLoggingClient); } #if ENABLE(CONTEXT_MENUS) -void WebPageProxy::initializeContextMenuClient(const WKPageContextMenuClientBase* client) +void WebPageProxy::setContextMenuClient(std::unique_ptr<API::ContextMenuClient> contextMenuClient) { - m_contextMenuClient.initialize(client); + if (!contextMenuClient) { + m_contextMenuClient = std::make_unique<API::ContextMenuClient>(); + return; + } + + m_contextMenuClient = WTFMove(contextMenuClient); } #endif +void WebPageProxy::setInjectedBundleClient(const WKPageInjectedBundleClientBase* client) +{ + if (!client) { + m_injectedBundleClient = nullptr; + return; + } + + m_injectedBundleClient = std::make_unique<WebPageInjectedBundleClient>(); + m_injectedBundleClient->initialize(client); +} + +void WebPageProxy::handleMessage(IPC::Connection& connection, const String& messageName, const WebKit::UserData& messageBody) +{ + ASSERT(m_process->connection() == &connection); + + if (!m_injectedBundleClient) + return; + + m_injectedBundleClient->didReceiveMessageFromInjectedBundle(this, messageName, m_process->transformHandlesToObjects(messageBody.object()).get()); +} + +void WebPageProxy::handleSynchronousMessage(IPC::Connection& connection, const String& messageName, const UserData& messageBody, UserData& returnUserData) +{ + ASSERT(m_process->connection() == &connection); + + if (!m_injectedBundleClient) + return; + + RefPtr<API::Object> returnData; + m_injectedBundleClient->didReceiveSynchronousMessageFromInjectedBundle(this, messageName, m_process->transformHandlesToObjects(messageBody.object()).get(), returnData); + returnUserData = UserData(m_process->transformObjectsToHandles(returnData.get())); +} + void WebPageProxy::reattachToWebProcess() { + ASSERT(!m_isClosed); ASSERT(!isValid()); - ASSERT(!m_process->isValid()); - ASSERT(!m_process->isLaunching()); - - updateViewState(); + ASSERT(m_process->state() == WebProcessProxy::State::Terminated); m_isValid = true; + m_wasKilledForBeingUnresponsiveWhileInBackground = false; + m_process->removeWebPage(m_pageID); + m_process->removeMessageReceiver(Messages::WebPageProxy::messageReceiverName(), m_pageID); - if (m_process->context().processModel() == ProcessModelSharedSecondaryProcess) - m_process = m_process->context().ensureSharedWebProcess(); - else - m_process = m_process->context().createNewWebProcessRespectingProcessCountLimit(); + m_process = m_process->processPool().createNewWebProcessRespectingProcessCountLimit(); + + ASSERT(m_process->state() != ChildProcessProxy::State::Terminated); + if (m_process->state() == ChildProcessProxy::State::Running) + processDidFinishLaunching(); m_process->addExistingWebPage(this, m_pageID); m_process->addMessageReceiver(Messages::WebPageProxy::messageReceiverName(), m_pageID, *this); -#if ENABLE(INSPECTOR) + updateActivityState(); + updateThrottleState(); + m_inspector = WebInspectorProxy::create(this); -#endif #if ENABLE(FULLSCREEN_API) m_fullScreenManager = WebFullScreenManagerProxy::create(*this, m_pageClient.fullScreenManagerProxyClient()); #endif +#if PLATFORM(IOS) && HAVE(AVKIT) || (PLATFORM(MAC) && ENABLE(VIDEO_PRESENTATION_MODE)) + m_playbackSessionManager = WebPlaybackSessionManagerProxy::create(*this); + m_videoFullscreenManager = WebVideoFullscreenManagerProxy::create(*this, *m_playbackSessionManager); +#endif + +#if ENABLE(APPLE_PAY) + m_paymentCoordinator = std::make_unique<WebPaymentCoordinatorProxy>(*this); +#endif initializeWebPage(); @@ -495,28 +746,46 @@ void WebPageProxy::reattachToWebProcess() m_drawingArea->waitForBackingStoreUpdateOnNextPaint(); } -void WebPageProxy::reattachToWebProcessWithItem(WebBackForwardListItem* item) +RefPtr<API::Navigation> WebPageProxy::reattachToWebProcessForReload() { - if (item && item != m_backForwardList->currentItem()) - m_backForwardList->goToItem(item); + if (m_isClosed) + return nullptr; + ASSERT(!isValid()); reattachToWebProcess(); - if (!item) - return; + if (!m_backForwardList->currentItem()) + return nullptr; + + auto navigation = m_navigationState->createReloadNavigation(); - m_process->send(Messages::WebPage::GoToBackForwardItem(item->itemID()), m_pageID); - m_process->responsivenessTimer()->start(); + // We allow stale content when reloading a WebProcess that's been killed or crashed. + m_process->send(Messages::WebPage::GoToBackForwardItem(navigation->navigationID(), m_backForwardList->currentItem()->itemID()), m_pageID); + m_process->responsivenessTimer().start(); + + return WTFMove(navigation); } -void WebPageProxy::setSession(API::Session& session) +RefPtr<API::Navigation> WebPageProxy::reattachToWebProcessWithItem(WebBackForwardListItem* item) { - m_session = session; - m_process->send(Messages::WebPage::SetSessionID(session.getID()), m_pageID); + if (m_isClosed) + return nullptr; -#if ENABLE(NETWORK_PROCESS) - m_process->context().sendToNetworkingProcess(Messages::NetworkProcess::EnsurePrivateBrowsingSession(session.getID())); -#endif + ASSERT(!isValid()); + reattachToWebProcess(); + + if (!item) + return nullptr; + + if (item != m_backForwardList->currentItem()) + m_backForwardList->goToItem(item); + + auto navigation = m_navigationState->createBackForwardNavigation(); + + m_process->send(Messages::WebPage::GoToBackForwardItem(navigation->navigationID(), item->itemID()), m_pageID); + m_process->responsivenessTimer().start(); + + return WTFMove(navigation); } void WebPageProxy::initializeWebPage() @@ -531,59 +800,86 @@ void WebPageProxy::initializeWebPage() ASSERT(m_drawingArea); #if ENABLE(ASYNC_SCROLLING) - if (m_drawingArea->type() == DrawingAreaTypeRemoteLayerTree) + if (m_drawingArea->type() == DrawingAreaTypeRemoteLayerTree) { m_scrollingCoordinatorProxy = std::make_unique<RemoteScrollingCoordinatorProxy>(*this); +#if PLATFORM(IOS) + // On iOS, main frame scrolls are sent in terms of visible rect updates. + m_scrollingCoordinatorProxy->setPropagatesMainFrameScrolls(false); +#endif + } #endif #if ENABLE(INSPECTOR_SERVER) - if (pageGroup().preferences()->developerExtrasEnabled()) + if (m_preferences->developerExtrasEnabled()) inspector()->enableRemoteInspection(); #endif process().send(Messages::WebProcess::CreateWebPage(m_pageID, creationParameters()), 0); -#if PLATFORM(MAC) - send(Messages::WebPage::SetSmartInsertDeleteEnabled(m_isSmartInsertDeleteEnabled)); -#endif + m_needsToFinishInitializingWebPageAfterProcessLaunch = true; + finishInitializingWebPageAfterProcessLaunch(); } -bool WebPageProxy::isProcessSuppressible() const +void WebPageProxy::finishInitializingWebPageAfterProcessLaunch() { - return (m_viewState & ViewState::IsVisuallyIdle) && m_pageGroup->preferences()->pageVisibilityBasedProcessSuppressionEnabled(); + if (!m_needsToFinishInitializingWebPageAfterProcessLaunch) + return; + if (m_process->state() != WebProcessProxy::State::Running) + return; + + m_needsToFinishInitializingWebPageAfterProcessLaunch = false; + + m_process->addWebUserContentControllerProxy(m_userContentController); + m_process->addVisitedLinkStore(m_visitedLinkStore); } void WebPageProxy::close() { - if (!isValid()) + if (m_isClosed) return; m_isClosed = true; + if (m_activePopupMenu) + m_activePopupMenu->cancelTracking(); + +#if ENABLE(CONTEXT_MENUS) + m_activeContextMenu = nullptr; +#endif + m_backForwardList->pageClosed(); m_pageClient.pageClosed(); m_process->disconnectFramesFromPage(this); - resetState(); + resetState(ResetStateReason::PageInvalidated); - m_loaderClient = nullptr; - m_policyClient = nullptr; - m_formClient.initialize(0); - m_uiClient.initialize(0); -#if PLATFORM(EFL) - m_uiPopupMenuClient.initialize(0); -#endif - m_findClient.initialize(0); - m_findMatchesClient.initialize(0); + m_loaderClient = std::make_unique<API::LoaderClient>(); + m_navigationClient = nullptr; + m_policyClient = std::make_unique<API::PolicyClient>(); + m_formClient = std::make_unique<API::FormClient>(); + m_uiClient = std::make_unique<API::UIClient>(); + m_findClient = std::make_unique<API::FindClient>(); + m_findMatchesClient = std::make_unique<API::FindMatchesClient>(); + m_diagnosticLoggingClient = std::make_unique<API::DiagnosticLoggingClient>(); #if ENABLE(CONTEXT_MENUS) - m_contextMenuClient.initialize(0); + m_contextMenuClient = std::make_unique<API::ContextMenuClient>(); #endif + m_webProcessLifetimeTracker.pageWasInvalidated(); + m_process->send(Messages::WebPage::Close(), m_pageID); m_process->removeWebPage(m_pageID); m_process->removeMessageReceiver(Messages::WebPageProxy::messageReceiverName(), m_pageID); - m_process->context().storageManager().destroySessionStorageNamespace(m_pageID); - m_process->context().supplement<WebNotificationManagerProxy>()->clearNotifications(this); + m_process->processPool().supplement<WebNotificationManagerProxy>()->clearNotifications(this); + + // Null out related WebPageProxy to avoid leaks. + m_configuration->setRelatedPage(nullptr); + +#if PLATFORM(IOS) + // Make sure we don't hold a process assertion after getting closed. + m_activityToken = nullptr; +#endif } bool WebPageProxy::tryClose() @@ -591,8 +887,13 @@ bool WebPageProxy::tryClose() if (!isValid()) return true; + // Close without delay if the process allows it. Our goal is to terminate + // the process, so we check a per-process status bit. + if (m_process->isSuddenTerminationEnabled()) + return true; + m_process->send(Messages::WebPage::TryClose(), m_pageID); - m_process->responsivenessTimer()->start(); + m_process->responsivenessTimer().start(); return false; } @@ -604,17 +905,26 @@ bool WebPageProxy::maybeInitializeSandboxExtensionHandle(const URL& url, Sandbox if (m_process->hasAssumedReadAccessToURL(url)) return false; -#if ENABLE(INSPECTOR) // Inspector resources are in a directory with assumed access. - ASSERT_WITH_SECURITY_IMPLICATION(!WebInspectorProxy::isInspectorPage(*this)); -#endif + ASSERT_WITH_SECURITY_IMPLICATION(!WebKit::isInspectorPage(*this)); SandboxExtension::createHandle("/", SandboxExtension::ReadOnly, sandboxExtensionHandle); return true; } -void WebPageProxy::loadRequest(const ResourceRequest& request, API::Object* userData) +#if !PLATFORM(COCOA) +void WebPageProxy::addPlatformLoadParameters(LoadParameters&) { +} +#endif + +RefPtr<API::Navigation> WebPageProxy::loadRequest(const ResourceRequest& request, ShouldOpenExternalURLsPolicy shouldOpenExternalURLsPolicy, API::Object* userData) +{ + if (m_isClosed) + return nullptr; + + auto navigation = m_navigationState->createLoadRequestNavigation(request); + auto transaction = m_pageLoadState.transaction(); m_pageLoadState.setPendingAPIRequestURL(transaction, request.url()); @@ -622,22 +932,33 @@ void WebPageProxy::loadRequest(const ResourceRequest& request, API::Object* user if (!isValid()) reattachToWebProcess(); - SandboxExtension::Handle sandboxExtensionHandle; - bool createdExtension = maybeInitializeSandboxExtensionHandle(request.url(), sandboxExtensionHandle); + LoadParameters loadParameters; + loadParameters.navigationID = navigation->navigationID(); + loadParameters.request = request; + loadParameters.shouldOpenExternalURLsPolicy = (uint64_t)shouldOpenExternalURLsPolicy; + loadParameters.userData = UserData(process().transformObjectsToHandles(userData).get()); + bool createdExtension = maybeInitializeSandboxExtensionHandle(request.url(), loadParameters.sandboxExtensionHandle); if (createdExtension) m_process->willAcquireUniversalFileReadSandboxExtension(); - m_process->send(Messages::WebPage::LoadRequest(request, sandboxExtensionHandle, WebContextUserMessageEncoder(userData, process())), m_pageID); - m_process->responsivenessTimer()->start(); + addPlatformLoadParameters(loadParameters); + + m_process->send(Messages::WebPage::LoadRequest(loadParameters), m_pageID); + m_process->responsivenessTimer().start(); + + return WTFMove(navigation); } -void WebPageProxy::loadFile(const String& fileURLString, const String& resourceDirectoryURLString, API::Object* userData) +RefPtr<API::Navigation> WebPageProxy::loadFile(const String& fileURLString, const String& resourceDirectoryURLString, API::Object* userData) { + if (m_isClosed) + return nullptr; + if (!isValid()) reattachToWebProcess(); URL fileURL = URL(URL(), fileURLString); if (!fileURL.isLocalFile()) - return; + return nullptr; URL resourceDirectoryURL; if (resourceDirectoryURLString.isNull()) @@ -645,71 +966,187 @@ void WebPageProxy::loadFile(const String& fileURLString, const String& resourceD else { resourceDirectoryURL = URL(URL(), resourceDirectoryURLString); if (!resourceDirectoryURL.isLocalFile()) - return; + return nullptr; } + auto navigation = m_navigationState->createLoadRequestNavigation(ResourceRequest(fileURL)); + + auto transaction = m_pageLoadState.transaction(); + + m_pageLoadState.setPendingAPIRequestURL(transaction, fileURLString); + String resourceDirectoryPath = resourceDirectoryURL.fileSystemPath(); - SandboxExtension::Handle sandboxExtensionHandle; - SandboxExtension::createHandle(resourceDirectoryPath, SandboxExtension::ReadOnly, sandboxExtensionHandle); + LoadParameters loadParameters; + loadParameters.navigationID = navigation->navigationID(); + loadParameters.request = fileURL; + loadParameters.shouldOpenExternalURLsPolicy = (uint64_t)ShouldOpenExternalURLsPolicy::ShouldNotAllow; + loadParameters.userData = UserData(process().transformObjectsToHandles(userData).get()); + SandboxExtension::createHandle(resourceDirectoryPath, SandboxExtension::ReadOnly, loadParameters.sandboxExtensionHandle); + addPlatformLoadParameters(loadParameters); + m_process->assumeReadAccessToBaseURL(resourceDirectoryURL); - m_process->send(Messages::WebPage::LoadRequest(fileURL, sandboxExtensionHandle, WebContextUserMessageEncoder(userData, process())), m_pageID); - m_process->responsivenessTimer()->start(); + m_process->send(Messages::WebPage::LoadRequest(loadParameters), m_pageID); + m_process->responsivenessTimer().start(); + + return WTFMove(navigation); } -void WebPageProxy::loadData(API::Data* data, const String& MIMEType, const String& encoding, const String& baseURL, API::Object* userData) +RefPtr<API::Navigation> WebPageProxy::loadData(API::Data* data, const String& MIMEType, const String& encoding, const String& baseURL, API::Object* userData) { + if (m_isClosed) + return nullptr; + + auto navigation = m_navigationState->createLoadDataNavigation(); + + auto transaction = m_pageLoadState.transaction(); + + m_pageLoadState.setPendingAPIRequestURL(transaction, !baseURL.isEmpty() ? baseURL : blankURL().string()); + if (!isValid()) reattachToWebProcess(); + LoadParameters loadParameters; + loadParameters.navigationID = navigation->navigationID(); + loadParameters.data = data->dataReference(); + loadParameters.MIMEType = MIMEType; + loadParameters.encodingName = encoding; + loadParameters.baseURLString = baseURL; + loadParameters.userData = UserData(process().transformObjectsToHandles(userData).get()); + addPlatformLoadParameters(loadParameters); + m_process->assumeReadAccessToBaseURL(baseURL); - m_process->send(Messages::WebPage::LoadData(data->dataReference(), MIMEType, encoding, baseURL, WebContextUserMessageEncoder(userData, process())), m_pageID); - m_process->responsivenessTimer()->start(); + m_process->send(Messages::WebPage::LoadData(loadParameters), m_pageID); + m_process->responsivenessTimer().start(); + + return WTFMove(navigation); } -void WebPageProxy::loadHTMLString(const String& htmlString, const String& baseURL, API::Object* userData) +// FIXME: Get rid of loadHTMLString and just use loadData instead. +RefPtr<API::Navigation> WebPageProxy::loadHTMLString(const String& htmlString, const String& baseURL, API::Object* userData) { + if (m_isClosed) + return nullptr; + + auto navigation = m_navigationState->createLoadDataNavigation(); + + auto transaction = m_pageLoadState.transaction(); + + m_pageLoadState.setPendingAPIRequestURL(transaction, !baseURL.isEmpty() ? baseURL : blankURL().string()); + if (!isValid()) reattachToWebProcess(); + LoadParameters loadParameters; + loadParameters.navigationID = navigation->navigationID(); + loadParameters.string = htmlString; + loadParameters.MIMEType = ASCIILiteral("text/html"); + loadParameters.baseURLString = baseURL; + loadParameters.userData = UserData(process().transformObjectsToHandles(userData).get()); + addPlatformLoadParameters(loadParameters); + m_process->assumeReadAccessToBaseURL(baseURL); - m_process->send(Messages::WebPage::LoadHTMLString(htmlString, baseURL, WebContextUserMessageEncoder(userData, process())), m_pageID); - m_process->responsivenessTimer()->start(); + m_process->send(Messages::WebPage::LoadString(loadParameters), m_pageID); + m_process->responsivenessTimer().start(); + + return WTFMove(navigation); } void WebPageProxy::loadAlternateHTMLString(const String& htmlString, const String& baseURL, const String& unreachableURL, API::Object* userData) { + // When the UIProcess is in the process of handling a failing provisional load, do not attempt to + // start a second alternative HTML load as this will prevent the page load state from being + // handled properly. + if (m_isClosed || m_isLoadingAlternateHTMLStringForFailingProvisionalLoad) + return; + + if (!m_failingProvisionalLoadURL.isEmpty()) + m_isLoadingAlternateHTMLStringForFailingProvisionalLoad = true; + if (!isValid()) reattachToWebProcess(); auto transaction = m_pageLoadState.transaction(); + m_pageLoadState.setPendingAPIRequestURL(transaction, unreachableURL); m_pageLoadState.setUnreachableURL(transaction, unreachableURL); if (m_mainFrame) m_mainFrame->setUnreachableURL(unreachableURL); + LoadParameters loadParameters; + loadParameters.navigationID = 0; + loadParameters.string = htmlString; + loadParameters.baseURLString = baseURL; + loadParameters.unreachableURLString = unreachableURL; + loadParameters.provisionalLoadErrorURLString = m_failingProvisionalLoadURL; + loadParameters.userData = UserData(process().transformObjectsToHandles(userData).get()); + addPlatformLoadParameters(loadParameters); + m_process->assumeReadAccessToBaseURL(baseURL); - m_process->send(Messages::WebPage::LoadAlternateHTMLString(htmlString, baseURL, unreachableURL, WebContextUserMessageEncoder(userData, process())), m_pageID); - m_process->responsivenessTimer()->start(); + m_process->assumeReadAccessToBaseURL(unreachableURL); + m_process->send(Messages::WebPage::LoadAlternateHTMLString(loadParameters), m_pageID); + m_process->responsivenessTimer().start(); } void WebPageProxy::loadPlainTextString(const String& string, API::Object* userData) { + if (m_isClosed) + return; + if (!isValid()) reattachToWebProcess(); - m_process->send(Messages::WebPage::LoadPlainTextString(string, WebContextUserMessageEncoder(userData, process())), m_pageID); - m_process->responsivenessTimer()->start(); + auto transaction = m_pageLoadState.transaction(); + m_pageLoadState.setPendingAPIRequestURL(transaction, blankURL().string()); + + LoadParameters loadParameters; + loadParameters.navigationID = 0; + loadParameters.string = string; + loadParameters.MIMEType = ASCIILiteral("text/plain"); + loadParameters.userData = UserData(process().transformObjectsToHandles(userData).get()); + addPlatformLoadParameters(loadParameters); + + m_process->send(Messages::WebPage::LoadString(loadParameters), m_pageID); + m_process->responsivenessTimer().start(); } void WebPageProxy::loadWebArchiveData(API::Data* webArchiveData, API::Object* userData) { + if (m_isClosed) + return; + if (!isValid()) reattachToWebProcess(); - m_process->send(Messages::WebPage::LoadWebArchiveData(webArchiveData->dataReference(), WebContextUserMessageEncoder(userData, process())), m_pageID); - m_process->responsivenessTimer()->start(); + auto transaction = m_pageLoadState.transaction(); + m_pageLoadState.setPendingAPIRequestURL(transaction, blankURL().string()); + + LoadParameters loadParameters; + loadParameters.navigationID = 0; + loadParameters.data = webArchiveData->dataReference(); + loadParameters.MIMEType = ASCIILiteral("application/x-webarchive"); + loadParameters.encodingName = ASCIILiteral("utf-16"); + loadParameters.userData = UserData(process().transformObjectsToHandles(userData).get()); + addPlatformLoadParameters(loadParameters); + + m_process->send(Messages::WebPage::LoadData(loadParameters), m_pageID); + m_process->responsivenessTimer().start(); +} + +void WebPageProxy::navigateToPDFLinkWithSimulatedClick(const String& url, IntPoint documentPoint, IntPoint screenPoint) +{ + if (m_isClosed) + return; + + if (WebCore::protocolIsJavaScript(url)) + return; + + if (!isValid()) + reattachToWebProcess(); + + m_process->send(Messages::WebPage::NavigateToPDFLinkWithSimulatedClick(url, documentPoint, screenPoint), m_pageID); + m_process->responsivenessTimer().start(); } void WebPageProxy::stopLoading() @@ -718,15 +1155,18 @@ void WebPageProxy::stopLoading() return; m_process->send(Messages::WebPage::StopLoading(), m_pageID); - m_process->responsivenessTimer()->start(); + m_process->responsivenessTimer().start(); } -void WebPageProxy::reload(bool reloadFromOrigin) +RefPtr<API::Navigation> WebPageProxy::reload(bool reloadFromOrigin, bool contentBlockersEnabled) { SandboxExtension::Handle sandboxExtensionHandle; - if (m_backForwardList->currentItem()) { - String url = m_backForwardList->currentItem()->url(); + String url = m_pageLoadState.activeURL(); + if (url.isEmpty() && m_backForwardList->currentItem()) + url = m_backForwardList->currentItem()->url(); + + if (!url.isEmpty()) { auto transaction = m_pageLoadState.transaction(); m_pageLoadState.setPendingAPIRequestURL(transaction, url); @@ -736,82 +1176,101 @@ void WebPageProxy::reload(bool reloadFromOrigin) m_process->willAcquireUniversalFileReadSandboxExtension(); } - if (!isValid()) { - reattachToWebProcessWithItem(m_backForwardList->currentItem()); + if (!isValid()) + return reattachToWebProcessForReload(); + + auto navigation = m_navigationState->createReloadNavigation(); + + m_process->send(Messages::WebPage::Reload(navigation->navigationID(), reloadFromOrigin, contentBlockersEnabled, sandboxExtensionHandle), m_pageID); + m_process->responsivenessTimer().start(); + + return WTFMove(navigation); +} + +void WebPageProxy::recordAutomaticNavigationSnapshot() +{ + if (m_suppressAutomaticNavigationSnapshotting) return; - } - m_process->send(Messages::WebPage::Reload(reloadFromOrigin, sandboxExtensionHandle), m_pageID); - m_process->responsivenessTimer()->start(); + if (WebBackForwardListItem* item = m_backForwardList->currentItem()) + recordNavigationSnapshot(*item); } -void WebPageProxy::recordNavigationSnapshot() +void WebPageProxy::recordNavigationSnapshot(WebBackForwardListItem& item) { if (!m_shouldRecordNavigationSnapshots) return; -#if PLATFORM(MAC) && !PLATFORM(IOS) - ViewSnapshotStore::shared().recordSnapshot(*this); +#if PLATFORM(COCOA) + ViewSnapshotStore::singleton().recordSnapshot(*this, item); +#else + UNUSED_PARAM(item); #endif } -void WebPageProxy::goForward() +RefPtr<API::Navigation> WebPageProxy::goForward() { WebBackForwardListItem* forwardItem = m_backForwardList->forwardItem(); if (!forwardItem) - return; - - recordNavigationSnapshot(); + return nullptr; auto transaction = m_pageLoadState.transaction(); m_pageLoadState.setPendingAPIRequestURL(transaction, forwardItem->url()); - if (!isValid()) { - reattachToWebProcessWithItem(forwardItem); - return; - } + if (!isValid()) + return reattachToWebProcessWithItem(forwardItem); - m_process->send(Messages::WebPage::GoForward(forwardItem->itemID()), m_pageID); - m_process->responsivenessTimer()->start(); + RefPtr<API::Navigation> navigation; + if (!m_backForwardList->currentItem()->itemIsInSameDocument(*forwardItem)) + navigation = m_navigationState->createBackForwardNavigation(); + + m_process->send(Messages::WebPage::GoForward(navigation ? navigation->navigationID() : 0, forwardItem->itemID()), m_pageID); + m_process->responsivenessTimer().start(); + + return navigation; } -void WebPageProxy::goBack() +RefPtr<API::Navigation> WebPageProxy::goBack() { WebBackForwardListItem* backItem = m_backForwardList->backItem(); if (!backItem) - return; - - recordNavigationSnapshot(); + return nullptr; auto transaction = m_pageLoadState.transaction(); m_pageLoadState.setPendingAPIRequestURL(transaction, backItem->url()); - if (!isValid()) { - reattachToWebProcessWithItem(backItem); - return; - } + if (!isValid()) + return reattachToWebProcessWithItem(backItem); + + RefPtr<API::Navigation> navigation; + if (!m_backForwardList->currentItem()->itemIsInSameDocument(*backItem)) + navigation = m_navigationState->createBackForwardNavigation(); + + m_process->send(Messages::WebPage::GoBack(navigation ? navigation->navigationID() : 0, backItem->itemID()), m_pageID); + m_process->responsivenessTimer().start(); - m_process->send(Messages::WebPage::GoBack(backItem->itemID()), m_pageID); - m_process->responsivenessTimer()->start(); + return navigation; } -void WebPageProxy::goToBackForwardItem(WebBackForwardListItem* item) +RefPtr<API::Navigation> WebPageProxy::goToBackForwardItem(WebBackForwardListItem* item) { - if (!isValid()) { - reattachToWebProcessWithItem(item); - return; - } + if (!isValid()) + return reattachToWebProcessWithItem(item); - recordNavigationSnapshot(); - auto transaction = m_pageLoadState.transaction(); m_pageLoadState.setPendingAPIRequestURL(transaction, item->url()); - m_process->send(Messages::WebPage::GoToBackForwardItem(item->itemID()), m_pageID); - m_process->responsivenessTimer()->start(); + RefPtr<API::Navigation> navigation; + if (!m_backForwardList->currentItem()->itemIsInSameDocument(*item)) + navigation = m_navigationState->createBackForwardNavigation(); + + m_process->send(Messages::WebPage::GoToBackForwardItem(navigation ? navigation->navigationID() : 0, item->itemID()), m_pageID); + m_process->responsivenessTimer().start(); + + return navigation; } void WebPageProxy::tryRestoreScrollPosition() @@ -822,20 +1281,31 @@ void WebPageProxy::tryRestoreScrollPosition() m_process->send(Messages::WebPage::TryRestoreScrollPosition(), m_pageID); } -void WebPageProxy::didChangeBackForwardList(WebBackForwardListItem* added, Vector<RefPtr<API::Object>>* removed) +void WebPageProxy::didChangeBackForwardList(WebBackForwardListItem* added, Vector<RefPtr<WebBackForwardListItem>> removed) { - m_loaderClient->didChangeBackForwardList(this, added, removed); + PageClientProtector protector(m_pageClient); + + m_loaderClient->didChangeBackForwardList(*this, added, WTFMove(removed)); + + auto transaction = m_pageLoadState.transaction(); + + m_pageLoadState.setCanGoBack(transaction, m_backForwardList->backItem()); + m_pageLoadState.setCanGoForward(transaction, m_backForwardList->forwardItem()); } -void WebPageProxy::willGoToBackForwardListItem(uint64_t itemID, IPC::MessageDecoder& decoder) +void WebPageProxy::willGoToBackForwardListItem(uint64_t itemID, const UserData& userData) { - RefPtr<API::Object> userData; - WebContextUserMessageDecoder messageDecoder(userData, process()); - if (!decoder.decode(messageDecoder)) - return; + PageClientProtector protector(m_pageClient); if (WebBackForwardListItem* item = m_process->webBackForwardItem(itemID)) - m_loaderClient->willGoToBackForwardListItem(this, item, userData.get()); + m_loaderClient->willGoToBackForwardListItem(*this, item, m_process->transformHandlesToObjects(userData.object()).get()); +} + +bool WebPageProxy::shouldKeepCurrentBackForwardListItemInList(WebBackForwardListItem* item) +{ + PageClientProtector protector(m_pageClient); + + return m_loaderClient->shouldKeepCurrentBackForwardListItemInList(*this, item); } bool WebPageProxy::canShowMIMEType(const String& mimeType) @@ -845,20 +1315,56 @@ bool WebPageProxy::canShowMIMEType(const String& mimeType) #if ENABLE(NETSCAPE_PLUGIN_API) String newMimeType = mimeType; - PluginModuleInfo plugin = m_process->context().pluginInfoStore().findPlugin(newMimeType, URL()); - if (!plugin.path.isNull() && m_pageGroup->preferences()->pluginsEnabled()) + PluginModuleInfo plugin = m_process->processPool().pluginInfoStore().findPlugin(newMimeType, URL()); + if (!plugin.path.isNull() && m_preferences->pluginsEnabled()) return true; #endif // ENABLE(NETSCAPE_PLUGIN_API) -#if PLATFORM(MAC) +#if PLATFORM(COCOA) // On Mac, we can show PDFs. - if (MIMETypeRegistry::isPDFOrPostScriptMIMEType(mimeType) && !WebContext::omitPDFSupport()) + if (MIMETypeRegistry::isPDFOrPostScriptMIMEType(mimeType) && !WebProcessPool::omitPDFSupport()) return true; -#endif // PLATFORM(MAC) +#endif // PLATFORM(COCOA) return false; } +void WebPageProxy::setControlledByAutomation(bool controlled) +{ + if (m_controlledByAutomation == controlled) + return; + + m_controlledByAutomation = controlled; + + if (isValid()) + m_process->send(Messages::WebPage::SetControlledByAutomation(controlled), m_pageID); +} + +#if ENABLE(REMOTE_INSPECTOR) +void WebPageProxy::setAllowsRemoteInspection(bool allow) +{ + if (m_allowsRemoteInspection == allow) + return; + + m_allowsRemoteInspection = allow; + + if (isValid()) + m_process->send(Messages::WebPage::SetAllowsRemoteInspection(allow), m_pageID); +} + +void WebPageProxy::setRemoteInspectionNameOverride(const String& name) +{ + if (m_remoteInspectionNameOverride == name) + return; + + m_remoteInspectionNameOverride = name; + + if (isValid()) + m_process->send(Messages::WebPage::SetRemoteInspectionNameOverride(m_remoteInspectionNameOverride), m_pageID); +} + +#endif + void WebPageProxy::setDrawsBackground(bool drawsBackground) { if (m_drawsBackground == drawsBackground) @@ -870,15 +1376,23 @@ void WebPageProxy::setDrawsBackground(bool drawsBackground) m_process->send(Messages::WebPage::SetDrawsBackground(drawsBackground), m_pageID); } -void WebPageProxy::setDrawsTransparentBackground(bool drawsTransparentBackground) +void WebPageProxy::setTopContentInset(float contentInset) { - if (m_drawsTransparentBackground == drawsTransparentBackground) + if (m_topContentInset == contentInset) return; - m_drawsTransparentBackground = drawsTransparentBackground; + m_topContentInset = contentInset; - if (isValid()) - m_process->send(Messages::WebPage::SetDrawsTransparentBackground(drawsTransparentBackground), m_pageID); + if (!isValid()) + return; +#if HAVE(COREANIMATION_FENCES) + MachSendRight fence = m_drawingArea->createFence(); + + auto fenceAttachment = IPC::Attachment(fence.leakSendRight(), MACH_MSG_TYPE_MOVE_SEND); + m_process->send(Messages::WebPage::SetTopContentInsetFenced(contentInset, fenceAttachment), m_pageID); +#else + m_process->send(Messages::WebPage::SetTopContentInset(contentInset), m_pageID); +#endif } void WebPageProxy::setUnderlayColor(const Color& color) @@ -896,7 +1410,7 @@ void WebPageProxy::viewWillStartLiveResize() { if (!isValid()) return; -#if ENABLE(INPUT_TYPE_COLOR_POPOVER) +#if ENABLE(INPUT_TYPE_COLOR_POPOVER) && ENABLE(INPUT_TYPE_COLOR) if (m_colorPicker) endColorPicker(); #endif @@ -910,102 +1424,269 @@ void WebPageProxy::viewWillEndLiveResize() m_process->send(Messages::WebPage::ViewWillEndLiveResize(), m_pageID); } -void WebPageProxy::setViewNeedsDisplay(const IntRect& rect) +void WebPageProxy::setViewNeedsDisplay(const Region& region) { - m_pageClient.setViewNeedsDisplay(rect); + m_pageClient.setViewNeedsDisplay(region); } -void WebPageProxy::displayView() +void WebPageProxy::requestScroll(const FloatPoint& scrollPosition, const IntPoint& scrollOrigin, bool isProgrammaticScroll) { - m_pageClient.displayView(); + m_pageClient.requestScroll(scrollPosition, scrollOrigin, isProgrammaticScroll); } -bool WebPageProxy::canScrollView() +void WebPageProxy::setSuppressVisibilityUpdates(bool flag) { - return m_pageClient.canScrollView(); + if (m_suppressVisibilityUpdates == flag) + return; + m_suppressVisibilityUpdates = flag; + + if (!m_suppressVisibilityUpdates) { +#if PLATFORM(COCOA) + m_activityStateChangeDispatcher->schedule(); +#else + dispatchActivityStateChange(); +#endif + } +} + +void WebPageProxy::updateActivityState(ActivityState::Flags flagsToUpdate) +{ + m_activityState &= ~flagsToUpdate; + if (flagsToUpdate & ActivityState::IsFocused && m_pageClient.isViewFocused()) + m_activityState |= ActivityState::IsFocused; + if (flagsToUpdate & ActivityState::WindowIsActive && m_pageClient.isViewWindowActive()) + m_activityState |= ActivityState::WindowIsActive; + if (flagsToUpdate & ActivityState::IsVisible && m_pageClient.isViewVisible()) + m_activityState |= ActivityState::IsVisible; + if (flagsToUpdate & ActivityState::IsVisibleOrOccluded && m_pageClient.isViewVisibleOrOccluded()) + m_activityState |= ActivityState::IsVisibleOrOccluded; + if (flagsToUpdate & ActivityState::IsInWindow && m_pageClient.isViewInWindow()) + m_activityState |= ActivityState::IsInWindow; + if (flagsToUpdate & ActivityState::IsVisuallyIdle && m_pageClient.isVisuallyIdle()) + m_activityState |= ActivityState::IsVisuallyIdle; + if (flagsToUpdate & ActivityState::IsAudible && m_mediaState & MediaProducer::IsPlayingAudio && !(m_mutedState & MediaProducer::AudioIsMuted)) + m_activityState |= ActivityState::IsAudible; + if (flagsToUpdate & ActivityState::IsLoading && m_pageLoadState.isLoading()) + m_activityState |= ActivityState::IsLoading; +} + +void WebPageProxy::activityStateDidChange(ActivityState::Flags mayHaveChanged, bool wantsSynchronousReply, ActivityStateChangeDispatchMode dispatchMode) +{ + m_potentiallyChangedActivityStateFlags |= mayHaveChanged; + m_activityStateChangeWantsSynchronousReply = m_activityStateChangeWantsSynchronousReply || wantsSynchronousReply; + + if (m_suppressVisibilityUpdates && dispatchMode != ActivityStateChangeDispatchMode::Immediate) + return; + +#if PLATFORM(COCOA) + bool isNewlyInWindow = !isInWindow() && (mayHaveChanged & ActivityState::IsInWindow) && m_pageClient.isViewInWindow(); + if (dispatchMode == ActivityStateChangeDispatchMode::Immediate || isNewlyInWindow) { + dispatchActivityStateChange(); + return; + } + m_activityStateChangeDispatcher->schedule(); +#else + UNUSED_PARAM(dispatchMode); + dispatchActivityStateChange(); +#endif } -void WebPageProxy::scrollView(const IntRect& scrollRect, const IntSize& scrollOffset) +void WebPageProxy::viewDidLeaveWindow() { - m_pageClient.scrollView(scrollRect, scrollOffset); +#if ENABLE(INPUT_TYPE_COLOR_POPOVER) && ENABLE(INPUT_TYPE_COLOR) + // When leaving the current page, close the popover color well. + if (m_colorPicker) + endColorPicker(); +#endif +#if PLATFORM(IOS) && HAVE(AVKIT) || (PLATFORM(MAC) && ENABLE(VIDEO_PRESENTATION_MODE)) + // When leaving the current page, close the video fullscreen. + if (m_videoFullscreenManager) + m_videoFullscreenManager->requestHideAndExitFullscreen(); +#endif } -void WebPageProxy::updateViewState(ViewState::Flags flagsToUpdate) +void WebPageProxy::viewDidEnterWindow() { - m_viewState &= ~flagsToUpdate; - if (flagsToUpdate & ViewState::IsFocused && m_pageClient.isViewFocused()) - m_viewState |= ViewState::IsFocused; - if (flagsToUpdate & ViewState::WindowIsActive && m_pageClient.isViewWindowActive()) - m_viewState |= ViewState::WindowIsActive; - if (flagsToUpdate & ViewState::IsVisible && m_pageClient.isViewVisible()) - m_viewState |= ViewState::IsVisible; - if (flagsToUpdate & ViewState::IsInWindow && m_pageClient.isViewInWindow()) - m_viewState |= ViewState::IsInWindow; - if (flagsToUpdate & ViewState::IsVisuallyIdle && m_pageClient.isVisuallyIdle()) - m_viewState |= ViewState::IsVisuallyIdle; + LayerHostingMode layerHostingMode = m_pageClient.viewLayerHostingMode(); + if (m_layerHostingMode != layerHostingMode) { + m_layerHostingMode = layerHostingMode; + m_process->send(Messages::WebPage::SetLayerHostingMode(layerHostingMode), m_pageID); + } } -void WebPageProxy::viewStateDidChange(ViewState::Flags mayHaveChanged, WantsReplyOrNot wantsReply) +void WebPageProxy::reloadAfterBeingKilledInBackground() { - if (!isValid()) + ASSERT(!isValid()); + + RELEASE_LOG_IF_ALLOWED("%p - Reloading tab that was killed in the background", this); + + // Only report as a crash if the page was ever visible, otherwise silently reload. + if (m_hasEverBeenVisible) + processDidCrash(); + else + reattachToWebProcessForReload(); +} + +void WebPageProxy::dispatchActivityStateChange() +{ +#if PLATFORM(COCOA) + m_activityStateChangeDispatcher->invalidate(); +#endif + + if (!isValid()) { + if (m_potentiallyChangedActivityStateFlags & ActivityState::IsVisible && m_wasKilledForBeingUnresponsiveWhileInBackground) + reloadAfterBeingKilledInBackground(); return; + } - // If the visibility state may have changed, then so may the visually idle. - if (mayHaveChanged & ViewState::IsVisible) - mayHaveChanged |= ViewState::IsVisuallyIdle; + // If the visibility state may have changed, then so may the visually idle & occluded agnostic state. + if (m_potentiallyChangedActivityStateFlags & ActivityState::IsVisible) + m_potentiallyChangedActivityStateFlags |= ActivityState::IsVisibleOrOccluded | ActivityState::IsVisuallyIdle; // Record the prior view state, update the flags that may have changed, // and check which flags have actually changed. - ViewState::Flags previousViewState = m_viewState; - updateViewState(mayHaveChanged); - ViewState::Flags changed = m_viewState ^ previousViewState; - - if (changed) - m_process->send(Messages::WebPage::SetViewState(m_viewState, wantsReply == WantsReplyOrNot::DoesWantReply), m_pageID); - - if (changed & ViewState::IsVisuallyIdle) - m_process->pageSuppressibilityChanged(this); - - // If we've started the responsiveness timer as part of telling the web process to update the backing store - // state, it might not send back a reply (since it won't paint anything if the web page is hidden) so we - // stop the unresponsiveness timer here. - if ((changed & ViewState::IsVisible) && !isViewVisible()) - m_process->responsivenessTimer()->stop(); - - if ((mayHaveChanged & ViewState::IsInWindow) && (m_viewState & ViewState::IsInWindow)) { - LayerHostingMode layerHostingMode = m_pageClient.viewLayerHostingMode(); - if (m_layerHostingMode != layerHostingMode) { - m_layerHostingMode = layerHostingMode; - m_process->send(Messages::WebPage::SetLayerHostingMode(layerHostingMode), m_pageID); + ActivityState::Flags previousActivityState = m_activityState; + updateActivityState(m_potentiallyChangedActivityStateFlags); + ActivityState::Flags changed = m_activityState ^ previousActivityState; + + bool isNowInWindow = (changed & ActivityState::IsInWindow) && isInWindow(); + // We always want to wait for the Web process to reply if we've been in-window before and are coming back in-window. + if (m_viewWasEverInWindow && isNowInWindow) { + if (m_drawingArea->hasVisibleContent() && m_waitsForPaintAfterViewDidMoveToWindow && !m_shouldSkipWaitingForPaintAfterNextViewDidMoveToWindow) + m_activityStateChangeWantsSynchronousReply = true; + m_shouldSkipWaitingForPaintAfterNextViewDidMoveToWindow = false; + } + + // Don't wait synchronously if the view state is not visible. (This matters in particular on iOS, where a hidden page may be suspended.) + if (!(m_activityState & ActivityState::IsVisible)) + m_activityStateChangeWantsSynchronousReply = false; + + if (changed || m_activityStateChangeWantsSynchronousReply || !m_nextActivityStateChangeCallbacks.isEmpty()) + m_process->send(Messages::WebPage::SetActivityState(m_activityState, m_activityStateChangeWantsSynchronousReply, m_nextActivityStateChangeCallbacks), m_pageID); + + m_nextActivityStateChangeCallbacks.clear(); + + // This must happen after the SetActivityState message is sent, to ensure the page visibility event can fire. + updateThrottleState(); + +#if ENABLE(POINTER_LOCK) + if (((changed & ActivityState::IsVisible) && !isViewVisible()) || ((changed & ActivityState::WindowIsActive) && !m_pageClient.isViewWindowActive()) + || ((changed & ActivityState::IsFocused) && !(m_activityState & ActivityState::IsFocused))) + requestPointerUnlock(); +#endif + + if (changed & ActivityState::IsVisible) { + if (isViewVisible()) { + m_hasEverBeenVisible = true; + m_visiblePageToken = m_process->visiblePageToken(); + } else { + m_visiblePageToken = nullptr; + + // If we've started the responsiveness timer as part of telling the web process to update the backing store + // state, it might not send back a reply (since it won't paint anything if the web page is hidden) so we + // stop the unresponsiveness timer here. + m_process->responsivenessTimer().stop(); } } -#if ENABLE(INPUT_TYPE_COLOR_POPOVER) - if ((mayHaveChanged & ViewState::IsInWindow) && !(m_viewState & ViewState::IsInWindow)) { - // When leaving the current page, close the popover color well. - if (m_colorPicker) - endColorPicker(); + if (changed & ActivityState::IsInWindow) { + if (isInWindow()) + viewDidEnterWindow(); + else + viewDidLeaveWindow(); } -#endif updateBackingStoreDiscardableState(); + + if (m_activityStateChangeWantsSynchronousReply) + waitForDidUpdateActivityState(); + + m_potentiallyChangedActivityStateFlags = ActivityState::NoFlags; + m_activityStateChangeWantsSynchronousReply = false; + m_viewWasEverInWindow |= isNowInWindow; } -void WebPageProxy::waitForDidUpdateViewState() +bool WebPageProxy::isAlwaysOnLoggingAllowed() const { - // If we have previously timed out with no response from the WebProcess, don't block the UIProcess again until it starts responding. - if (m_waitingForDidUpdateViewState) + return sessionID().isAlwaysOnLoggingAllowed(); +} + +void WebPageProxy::updateThrottleState() +{ + bool processSuppressionEnabled = m_preferences->pageVisibilityBasedProcessSuppressionEnabled(); + + // If process suppression is not enabled take a token on the process pool to disable suppression of support processes. + if (!processSuppressionEnabled) + m_preventProcessSuppressionCount = m_process->processPool().processSuppressionDisabledForPageCount(); + else if (!m_preventProcessSuppressionCount) + m_preventProcessSuppressionCount = nullptr; + + if (m_activityState & ActivityState::IsVisuallyIdle) + m_pageIsUserObservableCount = nullptr; + else if (!m_pageIsUserObservableCount) + m_pageIsUserObservableCount = m_process->processPool().userObservablePageCount(); + +#if PLATFORM(IOS) + if (!isViewVisible() && !m_alwaysRunsAtForegroundPriority) { + if (m_activityToken) { + RELEASE_LOG_IF_ALLOWED("%p - UIProcess is releasing a foreground assertion because the view is no longer visible", this); + m_activityToken = nullptr; + } + } else if (!m_activityToken) { + if (isViewVisible()) + RELEASE_LOG_IF_ALLOWED("%p - UIProcess is taking a foreground assertion because the view is visible", this); + else + RELEASE_LOG_IF_ALLOWED("%p - UIProcess is taking a foreground assertion even though the view is not visible because m_alwaysRunsAtForegroundPriority is true", this); + m_activityToken = m_process->throttler().foregroundActivityToken(); + } +#endif +} + +void WebPageProxy::updateHiddenPageThrottlingAutoIncreases() +{ + if (!m_preferences->hiddenPageDOMTimerThrottlingAutoIncreases()) + m_hiddenPageDOMTimerThrottlingAutoIncreasesCount = nullptr; + else if (!m_hiddenPageDOMTimerThrottlingAutoIncreasesCount) + m_hiddenPageDOMTimerThrottlingAutoIncreasesCount = m_process->processPool().hiddenPageThrottlingAutoIncreasesCount(); +} + +void WebPageProxy::layerHostingModeDidChange() +{ + if (!isValid()) return; + LayerHostingMode layerHostingMode = m_pageClient.viewLayerHostingMode(); + if (m_layerHostingMode == layerHostingMode) + return; + + m_layerHostingMode = layerHostingMode; + m_process->send(Messages::WebPage::SetLayerHostingMode(layerHostingMode), m_pageID); +} + +void WebPageProxy::waitForDidUpdateActivityState() +{ if (!isValid()) return; - m_waitingForDidUpdateViewState = true; + if (m_process->state() != WebProcessProxy::State::Running) + return; + + // If we have previously timed out with no response from the WebProcess, don't block the UIProcess again until it starts responding. + if (m_waitingForDidUpdateActivityState) + return; - if (!m_process->isLaunching()) { - auto viewStateUpdateTimeout = std::chrono::milliseconds(250); - m_process->connection()->waitForAndDispatchImmediately<Messages::WebPageProxy::DidUpdateViewState>(m_pageID, viewStateUpdateTimeout); +#if PLATFORM(IOS) + // Hail Mary check. Should not be possible (dispatchActivityStateChange should force async if not visible, + // and if visible we should be holding an assertion) - but we should never block on a suspended process. + if (!m_activityToken) { + ASSERT_NOT_REACHED(); + return; } +#endif + + m_waitingForDidUpdateActivityState = true; + + m_drawingArea->waitForDidUpdateActivityState(); } IntSize WebPageProxy::viewSize() const @@ -1013,36 +1694,39 @@ IntSize WebPageProxy::viewSize() const return m_pageClient.viewSize(); } -void WebPageProxy::setInitialFocus(bool forward, bool isKeyboardEventValid, const WebKeyboardEvent& keyboardEvent) +void WebPageProxy::setInitialFocus(bool forward, bool isKeyboardEventValid, const WebKeyboardEvent& keyboardEvent, std::function<void (CallbackBase::Error)> callbackFunction) { - if (!isValid()) + if (!isValid()) { + callbackFunction(CallbackBase::Error::OwnerWasInvalidated); return; - m_process->send(Messages::WebPage::SetInitialFocus(forward, isKeyboardEventValid, keyboardEvent), m_pageID); + } + + uint64_t callbackID = m_callbacks.put(WTFMove(callbackFunction), m_process->throttler().backgroundActivityToken()); + m_process->send(Messages::WebPage::SetInitialFocus(forward, isKeyboardEventValid, keyboardEvent, callbackID), m_pageID); } -void WebPageProxy::setWindowResizerSize(const IntSize& windowResizerSize) +void WebPageProxy::clearSelection() { if (!isValid()) return; - m_process->send(Messages::WebPage::SetWindowResizerSize(windowResizerSize), m_pageID); + m_process->send(Messages::WebPage::ClearSelection(), m_pageID); } - -void WebPageProxy::clearSelection() + +void WebPageProxy::restoreSelectionInFocusedEditableElement() { if (!isValid()) return; - m_process->send(Messages::WebPage::ClearSelection(), m_pageID); + m_process->send(Messages::WebPage::RestoreSelectionInFocusedEditableElement(), m_pageID); } -void WebPageProxy::validateCommand(const String& commandName, PassRefPtr<ValidateCommandCallback> callback) +void WebPageProxy::validateCommand(const String& commandName, std::function<void (const String&, bool, int32_t, CallbackBase::Error)> callbackFunction) { if (!isValid()) { - callback->invalidate(); + callbackFunction(String(), false, 0, CallbackBase::Error::Unknown); return; } - uint64_t callbackID = callback->callbackID(); - m_validateCommandCallbacks.set(callbackID, callback.get()); + uint64_t callbackID = m_callbacks.put(WTFMove(callbackFunction), m_process->throttler().backgroundActivityToken()); m_process->send(Messages::WebPage::ValidateCommand(commandName, callbackID), m_pageID); } @@ -1051,7 +1735,7 @@ void WebPageProxy::setMaintainsInactiveSelection(bool newValue) m_maintainsInactiveSelection = newValue; } -void WebPageProxy::executeEditCommand(const String& commandName) +void WebPageProxy::executeEditCommand(const String& commandName, const String& argument) { static NeverDestroyed<String> ignoreSpellingCommandName(ASCIILiteral("ignoreSpelling")); @@ -1061,16 +1745,27 @@ void WebPageProxy::executeEditCommand(const String& commandName) if (commandName == ignoreSpellingCommandName) ++m_pendingLearnOrIgnoreWordMessageCount; - m_process->send(Messages::WebPage::ExecuteEditCommand(commandName), m_pageID); + m_process->send(Messages::WebPage::ExecuteEditCommand(commandName, argument), m_pageID); } - -#if USE(TILED_BACKING_STORE) -void WebPageProxy::commitPageTransitionViewport() + +void WebPageProxy::setEditable(bool editable) { + if (editable == m_isEditable) + return; if (!isValid()) return; - process().send(Messages::WebPage::CommitPageTransitionViewport(), m_pageID); + m_isEditable = editable; + m_process->send(Messages::WebPage::SetEditable(editable), m_pageID); +} + +#if !PLATFORM(IOS) +void WebPageProxy::didCommitLayerTree(const RemoteLayerTreeTransaction&) +{ +} + +void WebPageProxy::layerTreeCommitComplete() +{ } #endif @@ -1096,9 +1791,9 @@ void WebPageProxy::dragExited(DragData& dragData, const String& dragStorageName) performDragControllerAction(DragControllerActionExited, dragData, dragStorageName, sandboxExtensionHandle, sandboxExtensionHandleEmptyArray); } -void WebPageProxy::performDrag(DragData& dragData, const String& dragStorageName, const SandboxExtension::Handle& sandboxExtensionHandle, const SandboxExtension::HandleArray& sandboxExtensionsForUpload) +void WebPageProxy::performDragOperation(DragData& dragData, const String& dragStorageName, const SandboxExtension::Handle& sandboxExtensionHandle, const SandboxExtension::HandleArray& sandboxExtensionsForUpload) { - performDragControllerAction(DragControllerActionPerformDrag, dragData, dragStorageName, sandboxExtensionHandle, sandboxExtensionsForUpload); + performDragControllerAction(DragControllerActionPerformDragOperation, dragData, dragStorageName, sandboxExtensionHandle, sandboxExtensionsForUpload); } void WebPageProxy::performDragControllerAction(DragControllerAction action, DragData& dragData, const String& dragStorageName, const SandboxExtension::Handle& sandboxExtensionHandle, const SandboxExtension::HandleArray& sandboxExtensionsForUpload) @@ -1106,31 +1801,38 @@ void WebPageProxy::performDragControllerAction(DragControllerAction action, Drag if (!isValid()) return; #if PLATFORM(GTK) - String url = dragData.asURL(nullptr); + UNUSED_PARAM(dragStorageName); + UNUSED_PARAM(sandboxExtensionHandle); + UNUSED_PARAM(sandboxExtensionsForUpload); + + String url = dragData.asURL(); if (!url.isEmpty()) m_process->assumeReadAccessToBaseURL(url); - m_process->send(Messages::WebPage::PerformDragControllerAction(action, dragData), m_pageID); + + ASSERT(dragData.platformData()); + WebSelectionData selection(*dragData.platformData()); + m_process->send(Messages::WebPage::PerformDragControllerAction(action, dragData.clientPosition(), dragData.globalPosition(), dragData.draggingSourceOperationMask(), selection, dragData.flags()), m_pageID); #else - m_process->send(Messages::WebPage::PerformDragControllerAction(action, dragData.clientPosition(), dragData.globalPosition(), dragData.draggingSourceOperationMask(), dragStorageName, dragData.flags(), sandboxExtensionHandle, sandboxExtensionsForUpload), m_pageID); + m_process->send(Messages::WebPage::PerformDragControllerAction(action, dragData, sandboxExtensionHandle, sandboxExtensionsForUpload), m_pageID); #endif } -void WebPageProxy::didPerformDragControllerAction(WebCore::DragSession dragSession) +void WebPageProxy::didPerformDragControllerAction(uint64_t dragOperation, bool mouseIsOverFileInput, unsigned numberOfItemsToBeAccepted) { - m_currentDragSession = dragSession; + MESSAGE_CHECK(dragOperation <= DragOperationDelete); + + m_currentDragOperation = static_cast<DragOperation>(dragOperation); + m_currentDragIsOverFileInput = mouseIsOverFileInput; + m_currentDragNumberOfFilesToBeAccepted = numberOfItemsToBeAccepted; } #if PLATFORM(GTK) -void WebPageProxy::startDrag(const DragData& dragData, const ShareableBitmap::Handle& dragImageHandle) +void WebPageProxy::startDrag(WebSelectionData&& selection, uint64_t dragOperation, const ShareableBitmap::Handle& dragImageHandle) { - RefPtr<ShareableBitmap> dragImage = 0; - if (!dragImageHandle.isNull()) { - dragImage = ShareableBitmap::create(dragImageHandle); - if (!dragImage) - return; - } + RefPtr<ShareableBitmap> dragImage = !dragImageHandle.isNull() ? ShareableBitmap::create(dragImageHandle) : nullptr; + m_pageClient.startDrag(WTFMove(selection.selectionData), static_cast<WebCore::DragOperation>(dragOperation), WTFMove(dragImage)); - m_pageClient.startDrag(dragData, dragImage.release()); + m_process->send(Messages::WebPage::DidStartDrag(), m_pageID); } #endif @@ -1140,6 +1842,12 @@ void WebPageProxy::dragEnded(const IntPoint& clientPosition, const IntPoint& glo return; m_process->send(Messages::WebPage::DragEnded(clientPosition, globalPosition, operation), m_pageID); } + +void WebPageProxy::dragCancelled() +{ + if (isValid()) + m_process->send(Messages::WebPage::DragCancelled(), m_pageID); +} #endif // ENABLE(DRAG_SUPPORT) void WebPageProxy::handleMouseEvent(const NativeWebMouseEvent& event) @@ -1147,12 +1855,15 @@ void WebPageProxy::handleMouseEvent(const NativeWebMouseEvent& event) if (!isValid()) return; + if (m_pageClient.windowIsFrontWindowUnderMouse(event)) + setToolTip(String()); + // NOTE: This does not start the responsiveness timer because mouse move should not indicate interaction. if (event.type() != WebEvent::MouseMove) - m_process->responsivenessTimer()->start(); + m_process->responsivenessTimer().start(); else { if (m_processingMouseMoveEvent) { - m_nextMouseMoveEvent = adoptPtr(new NativeWebMouseEvent(event)); + m_nextMouseMoveEvent = std::make_unique<NativeWebMouseEvent>(event); return; } @@ -1164,14 +1875,9 @@ void WebPageProxy::handleMouseEvent(const NativeWebMouseEvent& event) // we fake a mouse up event by using this stored down event. This event gets cleared // when the mouse up message is received from WebProcess. if (event.type() == WebEvent::MouseDown) - m_currentlyProcessedMouseDownEvent = adoptPtr(new NativeWebMouseEvent(event)); + m_currentlyProcessedMouseDownEvent = std::make_unique<NativeWebMouseEvent>(event); - if (m_shouldSendEventsSynchronously) { - bool handled = false; - m_process->sendSync(Messages::WebPage::MouseEventSyncForTesting(event), Messages::WebPage::MouseEventSyncForTesting::Reply(handled), m_pageID); - didReceiveEvent(event.type(), handled); - } else - m_process->send(Messages::WebPage::MouseEvent(event), m_pageID); + m_process->send(Messages::WebPage::MouseEvent(event), m_pageID); } #if MERGE_WHEEL_EVENTS @@ -1185,7 +1891,7 @@ static bool canCoalesce(const WebWheelEvent& a, const WebWheelEvent& b) return false; if (a.granularity() != b.granularity()) return false; -#if PLATFORM(MAC) +#if PLATFORM(COCOA) if (a.phase() != b.phase()) return false; if (a.momentumPhase() != b.momentumPhase()) @@ -1204,7 +1910,7 @@ static WebWheelEvent coalesce(const WebWheelEvent& a, const WebWheelEvent& b) FloatSize mergedDelta = a.delta() + b.delta(); FloatSize mergedWheelTicks = a.wheelTicks() + b.wheelTicks(); -#if PLATFORM(MAC) +#if PLATFORM(COCOA) FloatSize mergedUnacceleratedScrollingDelta = a.unacceleratedScrollingDelta() + b.unacceleratedScrollingDelta(); return WebWheelEvent(WebEvent::Wheel, b.position(), b.globalPosition(), mergedDelta, mergedWheelTicks, b.granularity(), b.directionInvertedFromDevice(), b.phase(), b.momentumPhase(), b.hasPreciseScrollingDeltas(), b.scrollCount(), mergedUnacceleratedScrollingDelta, b.modifiers(), b.timestamp()); @@ -1248,6 +1954,8 @@ void WebPageProxy::handleWheelEvent(const NativeWebWheelEvent& event) if (!isValid()) return; + hideValidationMessage(); + if (!m_currentlyProcessedWheelEvents.isEmpty()) { m_wheelEventQueue.append(event); if (m_wheelEventQueue.size() < wheelEventQueueSizeThreshold) @@ -1260,40 +1968,35 @@ void WebPageProxy::handleWheelEvent(const NativeWebWheelEvent& event) return; } - OwnPtr<Vector<NativeWebWheelEvent>> coalescedWheelEvent = adoptPtr(new Vector<NativeWebWheelEvent>); + auto coalescedWheelEvent = std::make_unique<Vector<NativeWebWheelEvent>>(); coalescedWheelEvent->append(event); - m_currentlyProcessedWheelEvents.append(coalescedWheelEvent.release()); + m_currentlyProcessedWheelEvents.append(WTFMove(coalescedWheelEvent)); sendWheelEvent(event); } void WebPageProxy::processNextQueuedWheelEvent() { - OwnPtr<Vector<NativeWebWheelEvent>> nextCoalescedEvent = adoptPtr(new Vector<NativeWebWheelEvent>); + auto nextCoalescedEvent = std::make_unique<Vector<NativeWebWheelEvent>>(); WebWheelEvent nextWheelEvent = coalescedWheelEvent(m_wheelEventQueue, *nextCoalescedEvent.get()); - m_currentlyProcessedWheelEvents.append(nextCoalescedEvent.release()); + m_currentlyProcessedWheelEvents.append(WTFMove(nextCoalescedEvent)); sendWheelEvent(nextWheelEvent); } void WebPageProxy::sendWheelEvent(const WebWheelEvent& event) { - m_process->responsivenessTimer()->start(); - - if (m_shouldSendEventsSynchronously) { - bool handled = false; - m_process->sendSync(Messages::WebPage::WheelEventSyncForTesting(event), Messages::WebPage::WheelEventSyncForTesting::Reply(handled), m_pageID); - didReceiveEvent(event.type(), handled); - return; - } - m_process->send( Messages::EventDispatcher::WheelEvent( m_pageID, event, - m_useLegacyImplicitRubberBandControl ? !m_backForwardList->backItem() : rubberBandsAtLeft(), - m_useLegacyImplicitRubberBandControl ? !m_backForwardList->forwardItem() : rubberBandsAtRight(), + shouldUseImplicitRubberBandControl() ? !m_backForwardList->backItem() : rubberBandsAtLeft(), + shouldUseImplicitRubberBandControl() ? !m_backForwardList->forwardItem() : rubberBandsAtRight(), rubberBandsAtTop(), rubberBandsAtBottom() ), 0); + + // Manually ping the web process to check for responsiveness since our wheel + // event will dispatch to a non-main thread, which always responds. + m_process->isResponsive(nullptr); } void WebPageProxy::handleKeyboardEvent(const NativeWebKeyboardEvent& event) @@ -1305,25 +2008,37 @@ void WebPageProxy::handleKeyboardEvent(const NativeWebKeyboardEvent& event) m_keyEventQueue.append(event); - m_process->responsivenessTimer()->start(); - if (m_shouldSendEventsSynchronously) { - bool handled = false; - m_process->sendSync(Messages::WebPage::KeyEventSyncForTesting(event), Messages::WebPage::KeyEventSyncForTesting::Reply(handled), m_pageID); - didReceiveEvent(event.type(), handled); - } else if (m_keyEventQueue.size() == 1) // Otherwise, sent from DidReceiveEvent message handler. + m_process->responsivenessTimer().start(); + if (m_keyEventQueue.size() == 1) { // Otherwise, sent from DidReceiveEvent message handler. + LOG(KeyHandling, " UI process: sent keyEvent from handleKeyboardEvent"); m_process->send(Messages::WebPage::KeyEvent(event), m_pageID); + } +} + +WebPreferencesStore WebPageProxy::preferencesStore() const +{ + if (m_configurationPreferenceValues.isEmpty()) + return m_preferences->store(); + + WebPreferencesStore store = m_preferences->store(); + for (const auto& preference : m_configurationPreferenceValues) + store.m_values.set(preference.key, preference.value); + + return store; } #if ENABLE(NETSCAPE_PLUGIN_API) void WebPageProxy::findPlugin(const String& mimeType, uint32_t processType, const String& urlString, const String& frameURLString, const String& pageURLString, bool allowOnlyApplicationPlugins, uint64_t& pluginProcessToken, String& newMimeType, uint32_t& pluginLoadPolicy, String& unavailabilityDescription) { + PageClientProtector protector(m_pageClient); + MESSAGE_CHECK_URL(urlString); - newMimeType = mimeType.lower(); + newMimeType = mimeType.convertToASCIILowercase(); pluginLoadPolicy = PluginModuleLoadNormally; PluginData::AllowedPluginTypes allowedPluginTypes = allowOnlyApplicationPlugins ? PluginData::OnlyApplicationPlugins : PluginData::AllPlugins; - PluginModuleInfo plugin = m_process->context().pluginInfoStore().findPlugin(newMimeType, URL(URL(), urlString), allowedPluginTypes); + PluginModuleInfo plugin = m_process->processPool().pluginInfoStore().findPlugin(newMimeType, URL(URL(), urlString), allowedPluginTypes); if (!plugin.path) { pluginProcessToken = 0; return; @@ -1331,9 +2046,12 @@ void WebPageProxy::findPlugin(const String& mimeType, uint32_t processType, cons pluginLoadPolicy = PluginInfoStore::defaultLoadPolicyForPlugin(plugin); -#if PLATFORM(MAC) - RefPtr<ImmutableDictionary> pluginInformation = createPluginInformationDictionary(plugin, frameURLString, String(), pageURLString, String(), String()); - pluginLoadPolicy = m_loaderClient->pluginLoadPolicy(this, static_cast<PluginModuleLoadPolicy>(pluginLoadPolicy), pluginInformation.get(), unavailabilityDescription); +#if PLATFORM(COCOA) + RefPtr<API::Dictionary> pluginInformation = createPluginInformationDictionary(plugin, frameURLString, String(), pageURLString, String(), String()); + if (m_navigationClient) + pluginLoadPolicy = m_navigationClient->decidePolicyForPluginLoad(*this, static_cast<PluginModuleLoadPolicy>(pluginLoadPolicy), pluginInformation.get(), unavailabilityDescription); + else + pluginLoadPolicy = m_loaderClient->pluginLoadPolicy(*this, static_cast<PluginModuleLoadPolicy>(pluginLoadPolicy), pluginInformation.get(), unavailabilityDescription); #else UNUSED_PARAM(frameURLString); UNUSED_PARAM(pageURLString); @@ -1349,34 +2067,178 @@ void WebPageProxy::findPlugin(const String& mimeType, uint32_t processType, cons pluginProcessSandboxPolicy = PluginProcessSandboxPolicyUnsandboxed; break; - case PluginModuleBlocked: + case PluginModuleBlockedForSecurity: + case PluginModuleBlockedForCompatibility: pluginProcessToken = 0; return; } - pluginProcessToken = PluginProcessManager::shared().pluginProcessToken(plugin, static_cast<PluginProcessType>(processType), pluginProcessSandboxPolicy); + pluginProcessToken = PluginProcessManager::singleton().pluginProcessToken(plugin, static_cast<PluginProcessType>(processType), pluginProcessSandboxPolicy); } #endif // ENABLE(NETSCAPE_PLUGIN_API) #if ENABLE(TOUCH_EVENTS) + +static TrackingType mergeTrackingTypes(TrackingType a, TrackingType b) +{ + if (static_cast<uintptr_t>(b) > static_cast<uintptr_t>(a)) + return b; + return a; +} + +void WebPageProxy::updateTouchEventTracking(const WebTouchEvent& touchStartEvent) +{ +#if ENABLE(ASYNC_SCROLLING) + const EventNames& names = eventNames(); + for (auto& touchPoint : touchStartEvent.touchPoints()) { + IntPoint location = touchPoint.location(); + auto updateTrackingType = [this, location](TrackingType& trackingType, const AtomicString& eventName) { + if (trackingType == TrackingType::Synchronous) + return; + + TrackingType trackingTypeForLocation = m_scrollingCoordinatorProxy->eventTrackingTypeForPoint(eventName, location); + + trackingType = mergeTrackingTypes(trackingType, trackingTypeForLocation); + }; + updateTrackingType(m_touchEventTracking.touchForceChangedTracking, names.touchforcechangeEvent); + updateTrackingType(m_touchEventTracking.touchStartTracking, names.touchstartEvent); + updateTrackingType(m_touchEventTracking.touchMoveTracking, names.touchmoveEvent); + updateTrackingType(m_touchEventTracking.touchEndTracking, names.touchendEvent); + } +#else + UNUSED_PARAM(touchStartEvent); + m_touchEventTracking.touchForceChangedTracking = TrackingType::Synchronous; + m_touchEventTracking.touchStartTracking = TrackingType::Synchronous; + m_touchEventTracking.touchMoveTracking = TrackingType::Synchronous; + m_touchEventTracking.touchEndTracking = TrackingType::Synchronous; +#endif // ENABLE(ASYNC_SCROLLING) +} + +TrackingType WebPageProxy::touchEventTrackingType(const WebTouchEvent& touchStartEvent) const +{ + // We send all events if any type is needed, we just do it asynchronously for the types that are not tracked. + // + // Touch events define a sequence with strong dependencies. For example, we can expect + // a TouchMove to only appear after a TouchStart, and the ids of the touch points is consistent between + // the two. + // + // WebCore should not have to set up its state correctly after some events were dismissed. + // For example, we don't want to send a TouchMoved without a TouchPressed. + // We send everything, WebCore updates its internal state and dispatch what is needed to the page. + TrackingType globalTrackingType = m_touchEventTracking.isTrackingAnything() ? TrackingType::Asynchronous : TrackingType::NotTracking; + + globalTrackingType = mergeTrackingTypes(globalTrackingType, m_touchEventTracking.touchForceChangedTracking); + for (auto& touchPoint : touchStartEvent.touchPoints()) { + switch (touchPoint.state()) { + case WebPlatformTouchPoint::TouchReleased: + globalTrackingType = mergeTrackingTypes(globalTrackingType, m_touchEventTracking.touchEndTracking); + break; + case WebPlatformTouchPoint::TouchPressed: + globalTrackingType = mergeTrackingTypes(globalTrackingType, m_touchEventTracking.touchStartTracking); + break; + case WebPlatformTouchPoint::TouchMoved: + case WebPlatformTouchPoint::TouchStationary: + globalTrackingType = mergeTrackingTypes(globalTrackingType, m_touchEventTracking.touchMoveTracking); + break; + case WebPlatformTouchPoint::TouchCancelled: + globalTrackingType = mergeTrackingTypes(globalTrackingType, TrackingType::Asynchronous); + break; + } + } + + return globalTrackingType; +} + +#endif + +#if ENABLE(MAC_GESTURE_EVENTS) +void WebPageProxy::handleGestureEvent(const NativeWebGestureEvent& event) +{ + if (!isValid()) + return; + + m_gestureEventQueue.append(event); + // FIXME: Consider doing some coalescing here. + m_process->responsivenessTimer().start(); + + m_process->send(Messages::EventDispatcher::GestureEvent(m_pageID, event), 0); +} +#endif + +#if ENABLE(IOS_TOUCH_EVENTS) +void WebPageProxy::handleTouchEventSynchronously(NativeWebTouchEvent& event) +{ + if (!isValid()) + return; + + if (event.type() == WebEvent::TouchStart) { + updateTouchEventTracking(event); + m_layerTreeTransactionIdAtLastTouchStart = downcast<RemoteLayerTreeDrawingAreaProxy>(*drawingArea()).lastCommittedLayerTreeTransactionID(); + } + + TrackingType touchEventsTrackingType = touchEventTrackingType(event); + if (touchEventsTrackingType == TrackingType::NotTracking) + return; + + if (touchEventsTrackingType == TrackingType::Asynchronous) { + // We can end up here if a native gesture has not started but the event handlers are passive. + // + // The client of WebPageProxy asks the event to be sent synchronously since the touch event + // can prevent a native gesture. + // But, here we know that all events handlers that can handle this events are passive. + // We can use asynchronous dispatch and pretend to the client that the page does nothing with the events. + event.setCanPreventNativeGestures(false); + handleTouchEventAsynchronously(event); + didReceiveEvent(event.type(), false); + return; + } + + m_process->responsivenessTimer().start(); + bool handled = false; + m_process->sendSync(Messages::WebPage::TouchEventSync(event), Messages::WebPage::TouchEventSync::Reply(handled), m_pageID); + didReceiveEvent(event.type(), handled); + m_pageClient.doneWithTouchEvent(event, handled); + m_process->responsivenessTimer().stop(); + + if (event.allTouchPointsAreReleased()) + m_touchEventTracking.reset(); +} + +void WebPageProxy::handleTouchEventAsynchronously(const NativeWebTouchEvent& event) +{ + if (!isValid()) + return; + + TrackingType touchEventsTrackingType = touchEventTrackingType(event); + if (touchEventsTrackingType == TrackingType::NotTracking) + return; + + m_process->send(Messages::EventDispatcher::TouchEvent(m_pageID, event), 0); + + if (event.allTouchPointsAreReleased()) + m_touchEventTracking.reset(); +} + +#elif ENABLE(TOUCH_EVENTS) void WebPageProxy::handleTouchEvent(const NativeWebTouchEvent& event) { if (!isValid()) return; + if (event.type() == WebEvent::TouchStart) + updateTouchEventTracking(event); + + if (touchEventTrackingType(event) == TrackingType::NotTracking) + return; + // If the page is suspended, which should be the case during panning, pinching // and animation on the page itself (kinetic scrolling, tap to zoom) etc, then // we do not send any of the events to the page even if is has listeners. - if (m_needTouchEvents && !m_isPageSuspended) { + if (!m_isPageSuspended) { m_touchEventQueue.append(event); - m_process->responsivenessTimer()->start(); - if (m_shouldSendEventsSynchronously) { - bool handled = false; - m_process->sendSync(Messages::WebPage::TouchEventSyncForTesting(event), Messages::WebPage::TouchEventSyncForTesting::Reply(handled), m_pageID); - didReceiveEvent(event.type(), handled); - } else - m_process->send(Messages::WebPage::TouchEvent(event), m_pageID); + m_process->responsivenessTimer().start(); + m_process->send(Messages::WebPage::TouchEvent(event), m_pageID); } else { if (m_touchEventQueue.isEmpty()) { bool isEventHandled = false; @@ -1388,8 +2250,11 @@ void WebPageProxy::handleTouchEvent(const NativeWebTouchEvent& event) lastEvent.deferredTouchEvents.append(event); } } + + if (event.allTouchPointsAreReleased()) + m_touchEventTracking.reset(); } -#endif +#endif // ENABLE(TOUCH_EVENTS) void WebPageProxy::scrollBy(ScrollDirection direction, ScrollGranularity granularity) { @@ -1407,7 +2272,7 @@ void WebPageProxy::centerSelectionInVisibleArea() m_process->send(Messages::WebPage::CenterSelectionInVisibleArea(), m_pageID); } -void WebPageProxy::receivedPolicyDecision(PolicyAction action, WebFrameProxy* frame, uint64_t listenerID) +void WebPageProxy::receivedPolicyDecision(PolicyAction action, WebFrameProxy& frame, uint64_t listenerID, API::Navigation* navigation, const WebsitePolicies& websitePolicies) { if (!isValid()) return; @@ -1417,15 +2282,19 @@ void WebPageProxy::receivedPolicyDecision(PolicyAction action, WebFrameProxy* fr if (action == PolicyIgnore) m_pageLoadState.clearPendingAPIRequestURL(transaction); - uint64_t downloadID = 0; +#if ENABLE(DOWNLOAD_ATTRIBUTE) + if (m_syncNavigationActionHasDownloadAttribute && action == PolicyUse) + action = PolicyDownload; +#endif + + DownloadID downloadID = { }; if (action == PolicyDownload) { // Create a download proxy. - DownloadProxy* download = m_process->context().createDownloadProxy(); + // FIXME: We should ensure that the downloadRequest is never empty. + const ResourceRequest& downloadRequest = m_decidePolicyForResponseRequest ? *m_decidePolicyForResponseRequest : ResourceRequest(); + DownloadProxy* download = m_process->processPool().createDownloadProxy(downloadRequest); downloadID = download->downloadID(); -#if PLATFORM(EFL) || PLATFORM(GTK) - // Our design does not suppport downloads without a WebPage. handleDownloadRequest(download); -#endif } // If we received a policy decision while in decidePolicyForResponse the decision will @@ -1443,10 +2312,11 @@ void WebPageProxy::receivedPolicyDecision(PolicyAction action, WebFrameProxy* fr m_syncNavigationActionPolicyActionIsValid = true; m_syncNavigationActionPolicyAction = action; m_syncNavigationActionPolicyDownloadID = downloadID; + m_syncNavigationActionPolicyWebsitePolicies = websitePolicies; return; } - m_process->send(Messages::WebPage::DidReceivePolicyDecision(frame->frameID(), listenerID, action, downloadID), m_pageID); + m_process->send(Messages::WebPage::DidReceivePolicyDecision(frame.frameID(), listenerID, action, navigation ? navigation->navigationID() : 0, downloadID), m_pageID); } void WebPageProxy::setUserAgent(const String& userAgent) @@ -1524,7 +2394,7 @@ void WebPageProxy::setCustomTextEncodingName(const String& encodingName) m_process->send(Messages::WebPage::SetCustomTextEncodingName(encodingName), m_pageID); } -void WebPageProxy::terminateProcess() +void WebPageProxy::terminateProcess(TerminationReason terminationReason) { // NOTE: This uses a check of m_isValid rather than calling isValid() since // we want this to run even for pages being closed or that already closed. @@ -1533,20 +2403,68 @@ void WebPageProxy::terminateProcess() m_process->requestTermination(); resetStateAfterProcessExited(); + m_wasKilledForBeingUnresponsiveWhileInBackground = terminationReason == TerminationReason::UnresponsiveWhileInBackground; } -#if !USE(CF) -PassRefPtr<API::Data> WebPageProxy::sessionStateData(WebPageProxySessionStateFilterCallback, void* /*context*/) const +SessionState WebPageProxy::sessionState(const std::function<bool (WebBackForwardListItem&)>& filter) const { - // FIXME: Return session state data for saving Page state. - return 0; + SessionState sessionState; + + sessionState.backForwardListState = m_backForwardList->backForwardListState(filter); + + String provisionalURLString = m_pageLoadState.pendingAPIRequestURL(); + if (provisionalURLString.isEmpty()) + provisionalURLString = m_pageLoadState.provisionalURL(); + + if (!provisionalURLString.isEmpty()) + sessionState.provisionalURL = URL(URL(), provisionalURLString); + + sessionState.renderTreeSize = renderTreeSize(); + return sessionState; } -void WebPageProxy::restoreFromSessionStateData(API::Data*) +RefPtr<API::Navigation> WebPageProxy::restoreFromSessionState(SessionState sessionState, bool navigate) { - // FIXME: Restore the Page from the passed in session state data. + m_sessionRestorationRenderTreeSize = 0; + m_hitRenderTreeSizeThreshold = false; + + bool hasBackForwardList = !!sessionState.backForwardListState.currentIndex; + + if (hasBackForwardList) { + m_backForwardList->restoreFromState(WTFMove(sessionState.backForwardListState)); + + for (const auto& entry : m_backForwardList->entries()) + process().registerNewWebBackForwardListItem(entry.get()); + + process().send(Messages::WebPage::RestoreSession(m_backForwardList->itemStates()), m_pageID); + + auto transaction = m_pageLoadState.transaction(); + m_pageLoadState.setCanGoBack(transaction, m_backForwardList->backItem()); + m_pageLoadState.setCanGoForward(transaction, m_backForwardList->forwardItem()); + + // The back / forward list was restored from a sessionState so we don't want to snapshot the current + // page when navigating away. Suppress navigation snapshotting until the next load has committed + m_suppressAutomaticNavigationSnapshotting = true; + } + + // FIXME: Navigating should be separate from state restoration. + if (navigate) { + m_sessionRestorationRenderTreeSize = sessionState.renderTreeSize; + if (!m_sessionRestorationRenderTreeSize) + m_hitRenderTreeSizeThreshold = true; // If we didn't get data on renderTreeSize, just don't fire the milestone. + + if (!sessionState.provisionalURL.isNull()) + return loadRequest(sessionState.provisionalURL); + + if (hasBackForwardList) { + // FIXME: Do we have to null check the back forward list item here? + if (WebBackForwardListItem* item = m_backForwardList->currentItem()) + return goToBackForwardItem(item); + } + } + + return nullptr; } -#endif bool WebPageProxy::supportsTextZoom() const { @@ -1577,6 +2495,8 @@ void WebPageProxy::setPageZoomFactor(double zoomFactor) if (m_pageZoomFactor == zoomFactor) return; + hideValidationMessage(); + m_pageZoomFactor = zoomFactor; m_process->send(Messages::WebPage::SetPageZoomFactor(m_pageZoomFactor), m_pageID); } @@ -1589,13 +2509,35 @@ void WebPageProxy::setPageAndTextZoomFactors(double pageZoomFactor, double textZ if (m_pageZoomFactor == pageZoomFactor && m_textZoomFactor == textZoomFactor) return; + hideValidationMessage(); + m_pageZoomFactor = pageZoomFactor; m_textZoomFactor = textZoomFactor; m_process->send(Messages::WebPage::SetPageAndTextZoomFactors(m_pageZoomFactor, m_textZoomFactor), m_pageID); } +double WebPageProxy::pageZoomFactor() const +{ + // Zoom factor for non-PDF pages persists across page loads. We maintain a separate member variable for PDF + // zoom which ensures that we don't use the PDF zoom for a normal page. + if (m_mainFramePluginHandlesPageScaleGesture) + return m_pluginZoomFactor; + return m_pageZoomFactor; +} + +double WebPageProxy::pageScaleFactor() const +{ + // PDF documents use zoom and scale factors to size themselves appropriately in the window. We store them + // separately but decide which to return based on the main frame. + if (m_mainFramePluginHandlesPageScaleGesture) + return m_pluginScaleFactor; + return m_pageScaleFactor; +} + void WebPageProxy::scalePage(double scale, const IntPoint& origin) { + ASSERT(scale > 0); + if (!isValid()) return; @@ -1603,6 +2545,28 @@ void WebPageProxy::scalePage(double scale, const IntPoint& origin) m_process->send(Messages::WebPage::ScalePage(scale, origin), m_pageID); } +void WebPageProxy::scalePageInViewCoordinates(double scale, const IntPoint& centerInViewCoordinates) +{ + ASSERT(scale > 0); + + if (!isValid()) + return; + + m_pageScaleFactor = scale; + m_process->send(Messages::WebPage::ScalePageInViewCoordinates(scale, centerInViewCoordinates), m_pageID); +} + +void WebPageProxy::scaleView(double scale) +{ + ASSERT(scale > 0); + + if (!isValid()) + return; + + m_viewScaleFactor = scale; + m_process->send(Messages::WebPage::ScaleView(scale), m_pageID); +} + void WebPageProxy::setIntrinsicDeviceScaleFactor(float scaleFactor) { if (m_intrinsicDeviceScaleFactor == scaleFactor) @@ -1651,6 +2615,14 @@ void WebPageProxy::setCustomDeviceScaleFactor(float customScaleFactor) m_drawingArea->deviceScaleFactorDidChange(); } +void WebPageProxy::accessibilitySettingsDidChange() +{ + if (!isValid()) + return; + + m_process->send(Messages::WebPage::AccessibilitySettingsDidChange(), m_pageID); +} + void WebPageProxy::setUseFixedLayout(bool fixed) { if (!isValid()) @@ -1683,17 +2655,14 @@ void WebPageProxy::listenForLayoutMilestones(WebCore::LayoutMilestones milestone { if (!isValid()) return; + + if (milestones == m_observedLayoutMilestones) + return; + m_observedLayoutMilestones = milestones; m_process->send(Messages::WebPage::ListenForLayoutMilestones(milestones), m_pageID); } -void WebPageProxy::setVisibilityStatePrerender() -{ - if (!isValid()) - return; - m_process->send(Messages::WebPage::SetVisibilityStatePrerender(), m_pageID); -} - void WebPageProxy::setSuppressScrollbarAnimations(bool suppressAnimations) { if (!isValid()) @@ -1745,6 +2714,40 @@ void WebPageProxy::setRubberBandsAtBottom(bool rubberBandsAtBottom) { m_rubberBandsAtBottom = rubberBandsAtBottom; } + +void WebPageProxy::setEnableVerticalRubberBanding(bool enableVerticalRubberBanding) +{ + if (enableVerticalRubberBanding == m_enableVerticalRubberBanding) + return; + + m_enableVerticalRubberBanding = enableVerticalRubberBanding; + + if (!isValid()) + return; + m_process->send(Messages::WebPage::SetEnableVerticalRubberBanding(enableVerticalRubberBanding), m_pageID); +} + +bool WebPageProxy::verticalRubberBandingIsEnabled() const +{ + return m_enableVerticalRubberBanding; +} + +void WebPageProxy::setEnableHorizontalRubberBanding(bool enableHorizontalRubberBanding) +{ + if (enableHorizontalRubberBanding == m_enableHorizontalRubberBanding) + return; + + m_enableHorizontalRubberBanding = enableHorizontalRubberBanding; + + if (!isValid()) + return; + m_process->send(Messages::WebPage::SetEnableHorizontalRubberBanding(enableHorizontalRubberBanding), m_pageID); +} + +bool WebPageProxy::horizontalRubberBandingIsEnabled() const +{ + return m_enableHorizontalRubberBanding; +} void WebPageProxy::setBackgroundExtendsBeyondPage(bool backgroundExtendsBeyondPage) { @@ -1811,26 +2814,31 @@ void WebPageProxy::setGapBetweenPages(double gap) m_process->send(Messages::WebPage::SetGapBetweenPages(gap), m_pageID); } +void WebPageProxy::setPaginationLineGridEnabled(bool lineGridEnabled) +{ + if (lineGridEnabled == m_paginationLineGridEnabled) + return; + + m_paginationLineGridEnabled = lineGridEnabled; + + if (!isValid()) + return; + m_process->send(Messages::WebPage::SetPaginationLineGridEnabled(lineGridEnabled), m_pageID); +} + void WebPageProxy::pageScaleFactorDidChange(double scaleFactor) { m_pageScaleFactor = scaleFactor; } -void WebPageProxy::pageZoomFactorDidChange(double zoomFactor) +void WebPageProxy::pluginScaleFactorDidChange(double pluginScaleFactor) { - m_pageZoomFactor = zoomFactor; + m_pluginScaleFactor = pluginScaleFactor; } -void WebPageProxy::setMemoryCacheClientCallsEnabled(bool memoryCacheClientCallsEnabled) +void WebPageProxy::pluginZoomFactorDidChange(double pluginZoomFactor) { - if (!isValid()) - return; - - if (m_areMemoryCacheClientCallsEnabled == memoryCacheClientCallsEnabled) - return; - - m_areMemoryCacheClientCallsEnabled = memoryCacheClientCallsEnabled; - m_process->send(Messages::WebPage::SetMemoryCacheMessagesEnabled(memoryCacheClientCallsEnabled), m_pageID); + m_pluginZoomFactor = pluginZoomFactor; } void WebPageProxy::findStringMatches(const String& string, FindOptions options, unsigned maxMatchCount) @@ -1871,137 +2879,154 @@ void WebPageProxy::countStringMatches(const String& string, FindOptions options, m_process->send(Messages::WebPage::CountStringMatches(string, options, maxMatchCount), m_pageID); } -void WebPageProxy::runJavaScriptInMainFrame(const String& script, PassRefPtr<ScriptValueCallback> prpCallback) +void WebPageProxy::runJavaScriptInMainFrame(const String& script, std::function<void (API::SerializedScriptValue*, bool hadException, const ExceptionDetails&, CallbackBase::Error)> callbackFunction) { - RefPtr<ScriptValueCallback> callback = prpCallback; if (!isValid()) { - callback->invalidate(); + callbackFunction(nullptr, false, { }, CallbackBase::Error::Unknown); return; } - uint64_t callbackID = callback->callbackID(); - m_scriptValueCallbacks.set(callbackID, callback.get()); + uint64_t callbackID = m_callbacks.put(WTFMove(callbackFunction), m_process->throttler().backgroundActivityToken()); m_process->send(Messages::WebPage::RunJavaScriptInMainFrame(script, callbackID), m_pageID); } -void WebPageProxy::getRenderTreeExternalRepresentation(PassRefPtr<StringCallback> prpCallback) +void WebPageProxy::getRenderTreeExternalRepresentation(std::function<void (const String&, CallbackBase::Error)> callbackFunction) { - RefPtr<StringCallback> callback = prpCallback; if (!isValid()) { - callback->invalidate(); + callbackFunction(String(), CallbackBase::Error::Unknown); return; } - uint64_t callbackID = callback->callbackID(); - m_stringCallbacks.set(callbackID, callback.get()); + uint64_t callbackID = m_callbacks.put(WTFMove(callbackFunction), m_process->throttler().backgroundActivityToken()); m_process->send(Messages::WebPage::GetRenderTreeExternalRepresentation(callbackID), m_pageID); } -void WebPageProxy::getSourceForFrame(WebFrameProxy* frame, PassRefPtr<StringCallback> prpCallback) +void WebPageProxy::getSourceForFrame(WebFrameProxy* frame, std::function<void (const String&, CallbackBase::Error)> callbackFunction) { - RefPtr<StringCallback> callback = prpCallback; if (!isValid()) { - callback->invalidate(); + callbackFunction(String(), CallbackBase::Error::Unknown); return; } - uint64_t callbackID = callback->callbackID(); + uint64_t callbackID = m_callbacks.put(WTFMove(callbackFunction), m_process->throttler().backgroundActivityToken()); m_loadDependentStringCallbackIDs.add(callbackID); - m_stringCallbacks.set(callbackID, callback.get()); m_process->send(Messages::WebPage::GetSourceForFrame(frame->frameID(), callbackID), m_pageID); } -void WebPageProxy::getContentsAsString(PassRefPtr<StringCallback> prpCallback) +void WebPageProxy::getContentsAsString(std::function<void (const String&, CallbackBase::Error)> callbackFunction) { - RefPtr<StringCallback> callback = prpCallback; if (!isValid()) { - callback->invalidate(); + callbackFunction(String(), CallbackBase::Error::Unknown); return; } - uint64_t callbackID = callback->callbackID(); + uint64_t callbackID = m_callbacks.put(WTFMove(callbackFunction), m_process->throttler().backgroundActivityToken()); m_loadDependentStringCallbackIDs.add(callbackID); - m_stringCallbacks.set(callbackID, callback.get()); m_process->send(Messages::WebPage::GetContentsAsString(callbackID), m_pageID); } +void WebPageProxy::getBytecodeProfile(std::function<void (const String&, CallbackBase::Error)> callbackFunction) +{ + if (!isValid()) { + callbackFunction(String(), CallbackBase::Error::Unknown); + return; + } + + uint64_t callbackID = m_callbacks.put(WTFMove(callbackFunction), m_process->throttler().backgroundActivityToken()); + m_loadDependentStringCallbackIDs.add(callbackID); + m_process->send(Messages::WebPage::GetBytecodeProfile(callbackID), m_pageID); +} + +void WebPageProxy::getSamplingProfilerOutput(std::function<void (const String&, CallbackBase::Error)> callbackFunction) +{ + if (!isValid()) { + callbackFunction(String(), CallbackBase::Error::Unknown); + return; + } + + uint64_t callbackID = m_callbacks.put(WTFMove(callbackFunction), m_process->throttler().backgroundActivityToken()); + m_loadDependentStringCallbackIDs.add(callbackID); + m_process->send(Messages::WebPage::GetSamplingProfilerOutput(callbackID), m_pageID); +} + +void WebPageProxy::isWebProcessResponsive(std::function<void (bool isWebProcessResponsive)> callbackFunction) +{ + if (!isValid()) { + RunLoop::main().dispatch([callbackFunction = WTFMove(callbackFunction)] { + bool isWebProcessResponsive = true; + callbackFunction(isWebProcessResponsive); + }); + return; + } + + m_process->isResponsive(callbackFunction); +} + #if ENABLE(MHTML) -void WebPageProxy::getContentsAsMHTMLData(PassRefPtr<DataCallback> prpCallback, bool useBinaryEncoding) +void WebPageProxy::getContentsAsMHTMLData(std::function<void (API::Data*, CallbackBase::Error)> callbackFunction) { - RefPtr<DataCallback> callback = prpCallback; if (!isValid()) { - callback->invalidate(); + callbackFunction(nullptr, CallbackBase::Error::Unknown); return; } - uint64_t callbackID = callback->callbackID(); - m_dataCallbacks.set(callbackID, callback.get()); - m_process->send(Messages::WebPage::GetContentsAsMHTMLData(callbackID, useBinaryEncoding), m_pageID); + uint64_t callbackID = m_callbacks.put(WTFMove(callbackFunction), m_process->throttler().backgroundActivityToken()); + m_process->send(Messages::WebPage::GetContentsAsMHTMLData(callbackID), m_pageID); } #endif -void WebPageProxy::getSelectionOrContentsAsString(PassRefPtr<StringCallback> prpCallback) +void WebPageProxy::getSelectionOrContentsAsString(std::function<void (const String&, CallbackBase::Error)> callbackFunction) { - RefPtr<StringCallback> callback = prpCallback; if (!isValid()) { - callback->invalidate(); + callbackFunction(String(), CallbackBase::Error::Unknown); return; } - uint64_t callbackID = callback->callbackID(); - m_stringCallbacks.set(callbackID, callback.get()); + uint64_t callbackID = m_callbacks.put(WTFMove(callbackFunction), m_process->throttler().backgroundActivityToken()); m_process->send(Messages::WebPage::GetSelectionOrContentsAsString(callbackID), m_pageID); } -void WebPageProxy::getSelectionAsWebArchiveData(PassRefPtr<DataCallback> prpCallback) +void WebPageProxy::getSelectionAsWebArchiveData(std::function<void (API::Data*, CallbackBase::Error)> callbackFunction) { - RefPtr<DataCallback> callback = prpCallback; if (!isValid()) { - callback->invalidate(); + callbackFunction(nullptr, CallbackBase::Error::Unknown); return; } - uint64_t callbackID = callback->callbackID(); - m_dataCallbacks.set(callbackID, callback.get()); + uint64_t callbackID = m_callbacks.put(WTFMove(callbackFunction), m_process->throttler().backgroundActivityToken()); m_process->send(Messages::WebPage::GetSelectionAsWebArchiveData(callbackID), m_pageID); } -void WebPageProxy::getMainResourceDataOfFrame(WebFrameProxy* frame, PassRefPtr<DataCallback> prpCallback) +void WebPageProxy::getMainResourceDataOfFrame(WebFrameProxy* frame, std::function<void (API::Data*, CallbackBase::Error)> callbackFunction) { - RefPtr<DataCallback> callback = prpCallback; - if (!isValid()) { - callback->invalidate(); + if (!isValid() || !frame) { + callbackFunction(nullptr, CallbackBase::Error::Unknown); return; } - uint64_t callbackID = callback->callbackID(); - m_dataCallbacks.set(callbackID, callback.get()); + uint64_t callbackID = m_callbacks.put(WTFMove(callbackFunction), m_process->throttler().backgroundActivityToken()); m_process->send(Messages::WebPage::GetMainResourceDataOfFrame(frame->frameID(), callbackID), m_pageID); } -void WebPageProxy::getResourceDataFromFrame(WebFrameProxy* frame, API::URL* resourceURL, PassRefPtr<DataCallback> prpCallback) +void WebPageProxy::getResourceDataFromFrame(WebFrameProxy* frame, API::URL* resourceURL, std::function<void (API::Data*, CallbackBase::Error)> callbackFunction) { - RefPtr<DataCallback> callback = prpCallback; if (!isValid()) { - callback->invalidate(); + callbackFunction(nullptr, CallbackBase::Error::Unknown); return; } - uint64_t callbackID = callback->callbackID(); - m_dataCallbacks.set(callbackID, callback.get()); + uint64_t callbackID = m_callbacks.put(WTFMove(callbackFunction), m_process->throttler().backgroundActivityToken()); m_process->send(Messages::WebPage::GetResourceDataFromFrame(frame->frameID(), resourceURL->string(), callbackID), m_pageID); } -void WebPageProxy::getWebArchiveOfFrame(WebFrameProxy* frame, PassRefPtr<DataCallback> prpCallback) +void WebPageProxy::getWebArchiveOfFrame(WebFrameProxy* frame, std::function<void (API::Data*, CallbackBase::Error)> callbackFunction) { - RefPtr<DataCallback> callback = prpCallback; if (!isValid()) { - callback->invalidate(); + callbackFunction(nullptr, CallbackBase::Error::Unknown); return; } - uint64_t callbackID = callback->callbackID(); - m_dataCallbacks.set(callbackID, callback.get()); + uint64_t callbackID = m_callbacks.put(WTFMove(callbackFunction), m_process->throttler().backgroundActivityToken()); m_process->send(Messages::WebPage::GetWebArchiveOfFrame(frame->frameID(), callbackID), m_pageID); } @@ -2009,27 +3034,57 @@ void WebPageProxy::forceRepaint(PassRefPtr<VoidCallback> prpCallback) { RefPtr<VoidCallback> callback = prpCallback; if (!isValid()) { - callback->invalidate(); + // FIXME: If the page is invalid we should not call the callback. It'd be better to just return false from forceRepaint. + callback->invalidate(CallbackBase::Error::OwnerWasInvalidated); return; } - uint64_t callbackID = callback->callbackID(); - m_voidCallbacks.set(callbackID, callback.get()); + std::function<void (CallbackBase::Error)> didForceRepaintCallback = [this, callback](CallbackBase::Error error) { + if (error != CallbackBase::Error::None) { + callback->invalidate(error); + return; + } + + if (!isValid()) { + callback->invalidate(CallbackBase::Error::OwnerWasInvalidated); + return; + } + + callAfterNextPresentationUpdate([callback](CallbackBase::Error error) { + if (error != CallbackBase::Error::None) { + callback->invalidate(error); + return; + } + + callback->performCallback(); + }); + }; + + uint64_t callbackID = m_callbacks.put(didForceRepaintCallback, m_process->throttler().backgroundActivityToken()); m_drawingArea->waitForBackingStoreUpdateOnNextPaint(); m_process->send(Messages::WebPage::ForceRepaint(callbackID), m_pageID); } +static OptionSet<IPC::SendOption> printingSendOptions(bool isPerformingDOMPrintOperation) +{ + if (isPerformingDOMPrintOperation) + return IPC::SendOption::DispatchMessageEvenWhenWaitingForSyncReply; + + return { }; +} + void WebPageProxy::preferencesDidChange() { if (!isValid()) return; #if ENABLE(INSPECTOR_SERVER) - if (m_pageGroup->preferences()->developerExtrasEnabled()) + if (m_preferences->developerExtrasEnabled()) inspector()->enableRemoteInspection(); #endif - m_process->pagePreferencesChanged(this); + updateThrottleState(); + updateHiddenPageThrottlingAutoIncreases(); m_pageClient.preferencesDidChange(); @@ -2038,11 +3093,13 @@ void WebPageProxy::preferencesDidChange() // even if nothing changed in UI process, so that overrides get removed. // Preferences need to be updated during synchronous printing to make "print backgrounds" preference work when toggled from a print dialog checkbox. - m_process->send(Messages::WebPage::PreferencesDidChange(pageGroup().preferences()->store()), m_pageID, m_isPerformingDOMPrintOperation ? IPC::DispatchMessageEvenWhenWaitingForSyncReply : 0); + m_process->send(Messages::WebPage::PreferencesDidChange(preferencesStore()), m_pageID, printingSendOptions(m_isPerformingDOMPrintOperation)); } void WebPageProxy::didCreateMainFrame(uint64_t frameID) { + PageClientProtector protector(m_pageClient); + MESSAGE_CHECK(!m_mainFrame); MESSAGE_CHECK(m_process->canCreateFrame(frameID)); @@ -2054,6 +3111,8 @@ void WebPageProxy::didCreateMainFrame(uint64_t frameID) void WebPageProxy::didCreateSubframe(uint64_t frameID) { + PageClientProtector protector(m_pageClient); + MESSAGE_CHECK(m_mainFrame); MESSAGE_CHECK(m_process->canCreateFrame(frameID)); @@ -2070,69 +3129,103 @@ double WebPageProxy::estimatedProgress() const void WebPageProxy::didStartProgress() { + PageClientProtector protector(m_pageClient); + auto transaction = m_pageLoadState.transaction(); m_pageLoadState.didStartProgress(transaction); m_pageLoadState.commitChanges(); - m_loaderClient->didStartProgress(this); + m_loaderClient->didStartProgress(*this); } void WebPageProxy::didChangeProgress(double value) { + PageClientProtector protector(m_pageClient); + auto transaction = m_pageLoadState.transaction(); m_pageLoadState.didChangeProgress(transaction, value); m_pageLoadState.commitChanges(); - m_loaderClient->didChangeProgress(this); + m_loaderClient->didChangeProgress(*this); } void WebPageProxy::didFinishProgress() { + PageClientProtector protector(m_pageClient); + auto transaction = m_pageLoadState.transaction(); m_pageLoadState.didFinishProgress(transaction); m_pageLoadState.commitChanges(); - m_loaderClient->didFinishProgress(this); + m_loaderClient->didFinishProgress(*this); } -void WebPageProxy::didStartProvisionalLoadForFrame(uint64_t frameID, const String& url, const String& unreachableURL, IPC::MessageDecoder& decoder) +void WebPageProxy::setNetworkRequestsInProgress(bool networkRequestsInProgress) { auto transaction = m_pageLoadState.transaction(); + m_pageLoadState.setNetworkRequestsInProgress(transaction, networkRequestsInProgress); +} - m_pageLoadState.clearPendingAPIRequestURL(transaction); +void WebPageProxy::hasInsecureContent(HasInsecureContent& hasInsecureContent) +{ + hasInsecureContent = m_pageLoadState.committedHasInsecureContent() ? HasInsecureContent::Yes : HasInsecureContent::No; +} - RefPtr<API::Object> userData; - WebContextUserMessageDecoder messageDecoder(userData, process()); - if (!decoder.decode(messageDecoder)) - return; +void WebPageProxy::didDestroyNavigation(uint64_t navigationID) +{ + PageClientProtector protector(m_pageClient); + + // FIXME: Message check the navigationID. + m_navigationState->didDestroyNavigation(navigationID); +} + +void WebPageProxy::didStartProvisionalLoadForFrame(uint64_t frameID, uint64_t navigationID, const String& url, const String& unreachableURL, const UserData& userData) +{ + PageClientProtector protector(m_pageClient); + + auto transaction = m_pageLoadState.transaction(); + + m_pageLoadState.clearPendingAPIRequestURL(transaction); WebFrameProxy* frame = m_process->webFrame(frameID); MESSAGE_CHECK(frame); MESSAGE_CHECK_URL(url); + // FIXME: We should message check that navigationID is not zero here, but it's currently zero for some navigations through the page cache. + RefPtr<API::Navigation> navigation; + if (frame->isMainFrame() && navigationID) + navigation = &navigationState().navigation(navigationID); + if (frame->isMainFrame()) { - recordNavigationSnapshot(); m_pageLoadState.didStartProvisionalLoad(transaction, url, unreachableURL); + m_pageClient.didStartProvisionalLoadForMainFrame(); + hideValidationMessage(); } frame->setUnreachableURL(unreachableURL); frame->didStartProvisionalLoad(url); m_pageLoadState.commitChanges(); - m_loaderClient->didStartProvisionalLoadForFrame(this, frame, userData.get()); + if (m_navigationClient) { + if (frame->isMainFrame()) + m_navigationClient->didStartProvisionalNavigation(*this, navigation.get(), m_process->transformHandlesToObjects(userData.object()).get()); + } else + m_loaderClient->didStartProvisionalLoadForFrame(*this, *frame, navigation.get(), m_process->transformHandlesToObjects(userData.object()).get()); } -void WebPageProxy::didReceiveServerRedirectForProvisionalLoadForFrame(uint64_t frameID, const String& url, IPC::MessageDecoder& decoder) +void WebPageProxy::didReceiveServerRedirectForProvisionalLoadForFrame(uint64_t frameID, uint64_t navigationID, const String& url, const UserData& userData) { - RefPtr<API::Object> userData; - WebContextUserMessageDecoder messageDecoder(userData, process()); - if (!decoder.decode(messageDecoder)) - return; + PageClientProtector protector(m_pageClient); WebFrameProxy* frame = m_process->webFrame(frameID); MESSAGE_CHECK(frame); MESSAGE_CHECK_URL(url); + // FIXME: We should message check that navigationID is not zero here, but it's currently zero for some navigations through the page cache. + RefPtr<API::Navigation> navigation; + if (frame->isMainFrame() && navigationID) + navigation = &navigationState().navigation(navigationID); + auto transaction = m_pageLoadState.transaction(); if (frame->isMainFrame()) @@ -2141,28 +3234,69 @@ void WebPageProxy::didReceiveServerRedirectForProvisionalLoadForFrame(uint64_t f frame->didReceiveServerRedirectForProvisionalLoad(url); m_pageLoadState.commitChanges(); - m_loaderClient->didReceiveServerRedirectForProvisionalLoadForFrame(this, frame, userData.get()); + if (m_navigationClient) { + if (frame->isMainFrame()) + m_navigationClient->didReceiveServerRedirectForProvisionalNavigation(*this, navigation.get(), m_process->transformHandlesToObjects(userData.object()).get()); + } else + m_loaderClient->didReceiveServerRedirectForProvisionalLoadForFrame(*this, *frame, navigation.get(), m_process->transformHandlesToObjects(userData.object()).get()); } -void WebPageProxy::didFailProvisionalLoadForFrame(uint64_t frameID, const ResourceError& error, IPC::MessageDecoder& decoder) +void WebPageProxy::didChangeProvisionalURLForFrame(uint64_t frameID, uint64_t, const String& url) { - RefPtr<API::Object> userData; - WebContextUserMessageDecoder messageDecoder(userData, process()); - if (!decoder.decode(messageDecoder)) - return; + PageClientProtector protector(m_pageClient); WebFrameProxy* frame = m_process->webFrame(frameID); MESSAGE_CHECK(frame); + MESSAGE_CHECK(frame->frameLoadState().state() == FrameLoadState::State::Provisional); + MESSAGE_CHECK_URL(url); auto transaction = m_pageLoadState.transaction(); + // Internally, we handle this the same way we handle a server redirect. There are no client callbacks + // for this, but if this is the main frame, clients may observe a change to the page's URL. if (frame->isMainFrame()) + m_pageLoadState.didReceiveServerRedirectForProvisionalLoad(transaction, url); + + frame->didReceiveServerRedirectForProvisionalLoad(url); +} + +void WebPageProxy::didFailProvisionalLoadForFrame(uint64_t frameID, const SecurityOriginData& frameSecurityOrigin, uint64_t navigationID, const String& provisionalURL, const ResourceError& error, const UserData& userData) +{ + PageClientProtector protector(m_pageClient); + + WebFrameProxy* frame = m_process->webFrame(frameID); + MESSAGE_CHECK(frame); + + // FIXME: We should message check that navigationID is not zero here, but it's currently zero for some navigations through the page cache. + RefPtr<API::Navigation> navigation; + if (frame->isMainFrame() && navigationID) + navigation = navigationState().takeNavigation(navigationID); + + auto transaction = m_pageLoadState.transaction(); + + if (frame->isMainFrame()) { m_pageLoadState.didFailProvisionalLoad(transaction); + m_pageClient.didFailProvisionalLoadForMainFrame(); + } frame->didFailProvisionalLoad(); m_pageLoadState.commitChanges(); - m_loaderClient->didFailProvisionalLoadWithErrorForFrame(this, frame, error, userData.get()); + + ASSERT(!m_failingProvisionalLoadURL); + m_failingProvisionalLoadURL = provisionalURL; + + if (m_navigationClient) { + if (frame->isMainFrame()) + m_navigationClient->didFailProvisionalNavigationWithError(*this, *frame, navigation.get(), error, m_process->transformHandlesToObjects(userData.object()).get()); + else { + // FIXME: Get the main frame's current navigation. + m_navigationClient->didFailProvisionalLoadInSubframeWithError(*this, *frame, frameSecurityOrigin, nullptr, error, m_process->transformHandlesToObjects(userData.object()).get()); + } + } else + m_loaderClient->didFailProvisionalLoadWithErrorForFrame(*this, *frame, navigation.get(), error, m_process->transformHandlesToObjects(userData.object()).get()); + + m_failingProvisionalLoadURL = { }; } void WebPageProxy::clearLoadDependentCallbacks() @@ -2172,138 +3306,232 @@ void WebPageProxy::clearLoadDependentCallbacks() m_loadDependentStringCallbackIDs.clear(); for (size_t i = 0; i < callbackIDsCopy.size(); ++i) { - RefPtr<StringCallback> callback = m_stringCallbacks.take(callbackIDsCopy[i]); + auto callback = m_callbacks.take<StringCallback>(callbackIDsCopy[i]); if (callback) callback->invalidate(); } } -void WebPageProxy::didCommitLoadForFrame(uint64_t frameID, const String& mimeType, uint32_t opaqueFrameLoadType, const WebCore::CertificateInfo& certificateInfo, IPC::MessageDecoder& decoder) +void WebPageProxy::didCommitLoadForFrame(uint64_t frameID, uint64_t navigationID, const String& mimeType, bool frameHasCustomContentProvider, uint32_t opaqueFrameLoadType, const WebCore::CertificateInfo& certificateInfo, bool containsPluginDocument, std::optional<HasInsecureContent> hasInsecureContent, const UserData& userData) { - RefPtr<API::Object> userData; - WebContextUserMessageDecoder messageDecoder(userData, process()); - if (!decoder.decode(messageDecoder)) - return; + PageClientProtector protector(m_pageClient); WebFrameProxy* frame = m_process->webFrame(frameID); MESSAGE_CHECK(frame); - auto transaction = m_pageLoadState.transaction(); + // FIXME: We should message check that navigationID is not zero here, but it's currently zero for some navigations through the page cache. + RefPtr<API::Navigation> navigation; + if (frame->isMainFrame() && navigationID) + navigation = &navigationState().navigation(navigationID); +#if PLATFORM(IOS) if (frame->isMainFrame()) { - m_pageLoadState.didCommitLoad(transaction); - m_pageClient.didCommitLoadForMainFrame(); + m_hasReceivedLayerTreeTransactionAfterDidCommitLoad = false; + m_firstLayerTreeTransactionIdAfterDidCommitLoad = downcast<RemoteLayerTreeDrawingAreaProxy>(*drawingArea()).nextLayerTreeTransactionID(); } +#endif + + auto transaction = m_pageLoadState.transaction(); + Ref<WebCertificateInfo> webCertificateInfo = WebCertificateInfo::create(certificateInfo); + bool markPageInsecure = hasInsecureContent ? hasInsecureContent.value() == HasInsecureContent::Yes : m_treatsSHA1CertificatesAsInsecure && certificateInfo.containsNonRootSHA1SignedCertificate(); + + if (frame->isMainFrame()) { + m_pageLoadState.didCommitLoad(transaction, webCertificateInfo, markPageInsecure); + m_suppressAutomaticNavigationSnapshotting = false; + } else if (markPageInsecure) + m_pageLoadState.didDisplayOrRunInsecureContent(transaction); #if USE(APPKIT) // FIXME (bug 59111): didCommitLoadForFrame comes too late when restoring a page from b/f cache, making us disable secure event mode in password fields. // FIXME: A load going on in one frame shouldn't affect text editing in other frames on the page. m_pageClient.resetSecureInputState(); - dismissCorrectionPanel(ReasonForDismissingAlternativeTextIgnored); - m_pageClient.dismissDictionaryLookupPanel(); + m_pageClient.dismissContentRelativeChildWindows(); #endif clearLoadDependentCallbacks(); - frame->didCommitLoad(mimeType, certificateInfo); + frame->didCommitLoad(mimeType, webCertificateInfo, containsPluginDocument); + + if (frame->isMainFrame()) { + m_mainFrameHasCustomContentProvider = frameHasCustomContentProvider; + + if (m_mainFrameHasCustomContentProvider) { + // Always assume that the main frame is pinned here, since the custom representation view will handle + // any wheel events and dispatch them to the WKView when necessary. + m_mainFrameIsPinnedToLeftSide = true; + m_mainFrameIsPinnedToRightSide = true; + m_mainFrameIsPinnedToTopSide = true; + m_mainFrameIsPinnedToBottomSide = true; + + m_uiClient->pinnedStateDidChange(*this); + } + m_pageClient.didCommitLoadForMainFrame(mimeType, frameHasCustomContentProvider); + } // Even if WebPage has the default pageScaleFactor (and therefore doesn't reset it), // WebPageProxy's cache of the value can get out of sync (e.g. in the case where a // plugin is handling page scaling itself) so we should reset it to the default // for standard main frame loads. - if (frame->isMainFrame() && static_cast<FrameLoadType>(opaqueFrameLoadType) == FrameLoadTypeStandard) - m_pageScaleFactor = 1; + if (frame->isMainFrame()) { + if (static_cast<FrameLoadType>(opaqueFrameLoadType) == FrameLoadType::Standard) { + m_pageScaleFactor = 1; + m_pluginScaleFactor = 1; + m_mainFramePluginHandlesPageScaleGesture = false; + } + } + +#if ENABLE(POINTER_LOCK) + if (frame->isMainFrame()) + requestPointerUnlock(); +#endif m_pageLoadState.commitChanges(); - m_loaderClient->didCommitLoadForFrame(this, frame, userData.get()); + if (m_navigationClient) { + if (frame->isMainFrame()) + m_navigationClient->didCommitNavigation(*this, navigation.get(), m_process->transformHandlesToObjects(userData.object()).get()); + } else + m_loaderClient->didCommitLoadForFrame(*this, *frame, navigation.get(), m_process->transformHandlesToObjects(userData.object()).get()); } -void WebPageProxy::didFinishDocumentLoadForFrame(uint64_t frameID, IPC::MessageDecoder& decoder) +void WebPageProxy::didFinishDocumentLoadForFrame(uint64_t frameID, uint64_t navigationID, const UserData& userData) { - RefPtr<API::Object> userData; - WebContextUserMessageDecoder messageDecoder(userData, process()); - if (!decoder.decode(messageDecoder)) - return; + PageClientProtector protector(m_pageClient); WebFrameProxy* frame = m_process->webFrame(frameID); MESSAGE_CHECK(frame); - m_loaderClient->didFinishDocumentLoadForFrame(this, frame, userData.get()); + // FIXME: We should message check that navigationID is not zero here, but it's currently zero for some navigations through the page cache. + RefPtr<API::Navigation> navigation; + if (frame->isMainFrame() && navigationID) + navigation = &navigationState().navigation(navigationID); + + if (m_navigationClient) { + if (frame->isMainFrame()) + m_navigationClient->didFinishDocumentLoad(*this, navigation.get(), m_process->transformHandlesToObjects(userData.object()).get()); + } else + m_loaderClient->didFinishDocumentLoadForFrame(*this, *frame, navigation.get(), m_process->transformHandlesToObjects(userData.object()).get()); } -void WebPageProxy::didFinishLoadForFrame(uint64_t frameID, IPC::MessageDecoder& decoder) +void WebPageProxy::didFinishLoadForFrame(uint64_t frameID, uint64_t navigationID, const UserData& userData) { - RefPtr<API::Object> userData; - WebContextUserMessageDecoder messageDecoder(userData, process()); - if (!decoder.decode(messageDecoder)) - return; + PageClientProtector protector(m_pageClient); WebFrameProxy* frame = m_process->webFrame(frameID); MESSAGE_CHECK(frame); + // FIXME: We should message check that navigationID is not zero here, but it's currently zero for some navigations through the page cache. + RefPtr<API::Navigation> navigation; + if (frame->isMainFrame() && navigationID) + navigation = &navigationState().navigation(navigationID); + auto transaction = m_pageLoadState.transaction(); - if (frame->isMainFrame()) + bool isMainFrame = frame->isMainFrame(); + if (isMainFrame) m_pageLoadState.didFinishLoad(transaction); + if (isMainFrame && m_controlledByAutomation) { + if (auto* automationSession = process().processPool().automationSession()) + automationSession->navigationOccurredForPage(*this); + } + frame->didFinishLoad(); m_pageLoadState.commitChanges(); - m_loaderClient->didFinishLoadForFrame(this, frame, userData.get()); + if (m_navigationClient) { + if (isMainFrame) + m_navigationClient->didFinishNavigation(*this, navigation.get(), m_process->transformHandlesToObjects(userData.object()).get()); + } else + m_loaderClient->didFinishLoadForFrame(*this, *frame, navigation.get(), m_process->transformHandlesToObjects(userData.object()).get()); + + if (isMainFrame) + m_pageClient.didFinishLoadForMainFrame(); + + m_isLoadingAlternateHTMLStringForFailingProvisionalLoad = false; } -void WebPageProxy::didFailLoadForFrame(uint64_t frameID, const ResourceError& error, IPC::MessageDecoder& decoder) +void WebPageProxy::didFailLoadForFrame(uint64_t frameID, uint64_t navigationID, const ResourceError& error, const UserData& userData) { - RefPtr<API::Object> userData; - WebContextUserMessageDecoder messageDecoder(userData, process()); - if (!decoder.decode(messageDecoder)) - return; + PageClientProtector protector(m_pageClient); WebFrameProxy* frame = m_process->webFrame(frameID); MESSAGE_CHECK(frame); + // FIXME: We should message check that navigationID is not zero here, but it's currently zero for some navigations through the page cache. + RefPtr<API::Navigation> navigation; + if (frame->isMainFrame() && navigationID) + navigation = &navigationState().navigation(navigationID); + clearLoadDependentCallbacks(); auto transaction = m_pageLoadState.transaction(); - if (frame->isMainFrame()) + bool isMainFrame = frame->isMainFrame(); + + if (isMainFrame) m_pageLoadState.didFailLoad(transaction); + if (isMainFrame && m_controlledByAutomation) { + if (auto* automationSession = process().processPool().automationSession()) + automationSession->navigationOccurredForPage(*this); + } + frame->didFailLoad(); m_pageLoadState.commitChanges(); - m_loaderClient->didFailLoadWithErrorForFrame(this, frame, error, userData.get()); + if (m_navigationClient) { + if (frame->isMainFrame()) + m_navigationClient->didFailNavigationWithError(*this, *frame, navigation.get(), error, m_process->transformHandlesToObjects(userData.object()).get()); + } else + m_loaderClient->didFailLoadWithErrorForFrame(*this, *frame, navigation.get(), error, m_process->transformHandlesToObjects(userData.object()).get()); + + if (isMainFrame) + m_pageClient.didFailLoadForMainFrame(); } -void WebPageProxy::didSameDocumentNavigationForFrame(uint64_t frameID, uint32_t opaqueSameDocumentNavigationType, const String& url, IPC::MessageDecoder& decoder) +void WebPageProxy::didSameDocumentNavigationForFrame(uint64_t frameID, uint64_t navigationID, uint32_t opaqueSameDocumentNavigationType, const String& url, const UserData& userData) { - RefPtr<API::Object> userData; - WebContextUserMessageDecoder messageDecoder(userData, process()); - if (!decoder.decode(messageDecoder)) - return; + PageClientProtector protector(m_pageClient); WebFrameProxy* frame = m_process->webFrame(frameID); MESSAGE_CHECK(frame); MESSAGE_CHECK_URL(url); + // FIXME: We should message check that navigationID is not zero here, but it's currently zero for some navigations through the page cache. + RefPtr<API::Navigation> navigation; + if (frame->isMainFrame() && navigationID) + navigation = &navigationState().navigation(navigationID); + auto transaction = m_pageLoadState.transaction(); - if (frame->isMainFrame()) + bool isMainFrame = frame->isMainFrame(); + if (isMainFrame) m_pageLoadState.didSameDocumentNavigation(transaction, url); + if (isMainFrame && m_controlledByAutomation) { + if (auto* automationSession = process().processPool().automationSession()) + automationSession->navigationOccurredForPage(*this); + } + m_pageLoadState.clearPendingAPIRequestURL(transaction); frame->didSameDocumentNavigation(url); m_pageLoadState.commitChanges(); - m_loaderClient->didSameDocumentNavigationForFrame(this, frame, static_cast<SameDocumentNavigationType>(opaqueSameDocumentNavigationType), userData.get()); + + SameDocumentNavigationType navigationType = static_cast<SameDocumentNavigationType>(opaqueSameDocumentNavigationType); + if (m_navigationClient) { + if (isMainFrame) + m_navigationClient->didSameDocumentNavigation(*this, navigation.get(), navigationType, m_process->transformHandlesToObjects(userData.object()).get()); + } else + m_loaderClient->didSameDocumentNavigationForFrame(*this, *frame, navigation.get(), navigationType, m_process->transformHandlesToObjects(userData.object()).get()); + + if (isMainFrame) + m_pageClient.didSameDocumentNavigationForMainFrame(navigationType); } -void WebPageProxy::didReceiveTitleForFrame(uint64_t frameID, const String& title, IPC::MessageDecoder& decoder) +void WebPageProxy::didReceiveTitleForFrame(uint64_t frameID, const String& title, const UserData& userData) { - RefPtr<API::Object> userData; - WebContextUserMessageDecoder messageDecoder(userData, process()); - if (!decoder.decode(messageDecoder)) - return; + PageClientProtector protector(m_pageClient); WebFrameProxy* frame = m_process->webFrame(frameID); MESSAGE_CHECK(frame); @@ -2316,64 +3544,50 @@ void WebPageProxy::didReceiveTitleForFrame(uint64_t frameID, const String& title frame->didChangeTitle(title); m_pageLoadState.commitChanges(); - m_loaderClient->didReceiveTitleForFrame(this, title, frame, userData.get()); + m_loaderClient->didReceiveTitleForFrame(*this, title, *frame, m_process->transformHandlesToObjects(userData.object()).get()); } -void WebPageProxy::didFirstLayoutForFrame(uint64_t frameID, IPC::MessageDecoder& decoder) +void WebPageProxy::didFirstLayoutForFrame(uint64_t frameID, const UserData& userData) { - RefPtr<API::Object> userData; - WebContextUserMessageDecoder messageDecoder(userData, process()); - if (!decoder.decode(messageDecoder)) - return; + PageClientProtector protector(m_pageClient); WebFrameProxy* frame = m_process->webFrame(frameID); MESSAGE_CHECK(frame); - m_loaderClient->didFirstLayoutForFrame(this, frame, userData.get()); + m_loaderClient->didFirstLayoutForFrame(*this, *frame, m_process->transformHandlesToObjects(userData.object()).get()); } -void WebPageProxy::didFirstVisuallyNonEmptyLayoutForFrame(uint64_t frameID, IPC::MessageDecoder& decoder) +void WebPageProxy::didFirstVisuallyNonEmptyLayoutForFrame(uint64_t frameID, const UserData& userData) { - RefPtr<API::Object> userData; - WebContextUserMessageDecoder messageDecoder(userData, process()); - if (!decoder.decode(messageDecoder)) - return; + PageClientProtector protector(m_pageClient); WebFrameProxy* frame = m_process->webFrame(frameID); MESSAGE_CHECK(frame); - m_loaderClient->didFirstVisuallyNonEmptyLayoutForFrame(this, frame, userData.get()); + m_loaderClient->didFirstVisuallyNonEmptyLayoutForFrame(*this, *frame, m_process->transformHandlesToObjects(userData.object()).get()); + + if (frame->isMainFrame()) + m_pageClient.didFirstVisuallyNonEmptyLayoutForMainFrame(); } -void WebPageProxy::didLayout(uint32_t layoutMilestones, IPC::MessageDecoder& decoder) +void WebPageProxy::didLayoutForCustomContentProvider() { - RefPtr<API::Object> userData; - WebContextUserMessageDecoder messageDecoder(userData, process()); - if (!decoder.decode(messageDecoder)) - return; - - m_loaderClient->didLayout(this, static_cast<LayoutMilestones>(layoutMilestones), userData.get()); + didReachLayoutMilestone(DidFirstLayout | DidFirstVisuallyNonEmptyLayout | DidHitRelevantRepaintedObjectsAreaThreshold); } -void WebPageProxy::didRemoveFrameFromHierarchy(uint64_t frameID, IPC::MessageDecoder& decoder) +void WebPageProxy::didReachLayoutMilestone(uint32_t layoutMilestones) { - RefPtr<API::Object> userData; - WebContextUserMessageDecoder messageDecoder(userData, process()); - if (!decoder.decode(messageDecoder)) - return; + PageClientProtector protector(m_pageClient); - WebFrameProxy* frame = m_process->webFrame(frameID); - MESSAGE_CHECK(frame); - - m_loaderClient->didRemoveFrameFromHierarchy(this, frame, userData.get()); + if (m_navigationClient) + m_navigationClient->renderingProgressDidChange(*this, static_cast<LayoutMilestones>(layoutMilestones)); + else + m_loaderClient->didReachLayoutMilestone(*this, static_cast<LayoutMilestones>(layoutMilestones)); } -void WebPageProxy::didDisplayInsecureContentForFrame(uint64_t frameID, IPC::MessageDecoder& decoder) +void WebPageProxy::didDisplayInsecureContentForFrame(uint64_t frameID, const UserData& userData) { - RefPtr<API::Object> userData; - WebContextUserMessageDecoder messageDecoder(userData, process()); - if (!decoder.decode(messageDecoder)) - return; + PageClientProtector protector(m_pageClient); WebFrameProxy* frame = m_process->webFrame(frameID); MESSAGE_CHECK(frame); @@ -2382,15 +3596,12 @@ void WebPageProxy::didDisplayInsecureContentForFrame(uint64_t frameID, IPC::Mess m_pageLoadState.didDisplayOrRunInsecureContent(transaction); m_pageLoadState.commitChanges(); - m_loaderClient->didDisplayInsecureContentForFrame(this, frame, userData.get()); + m_loaderClient->didDisplayInsecureContentForFrame(*this, *frame, m_process->transformHandlesToObjects(userData.object()).get()); } -void WebPageProxy::didRunInsecureContentForFrame(uint64_t frameID, IPC::MessageDecoder& decoder) +void WebPageProxy::didRunInsecureContentForFrame(uint64_t frameID, const UserData& userData) { - RefPtr<API::Object> userData; - WebContextUserMessageDecoder messageDecoder(userData, process()); - if (!decoder.decode(messageDecoder)) - return; + PageClientProtector protector(m_pageClient); WebFrameProxy* frame = m_process->webFrame(frameID); MESSAGE_CHECK(frame); @@ -2399,24 +3610,28 @@ void WebPageProxy::didRunInsecureContentForFrame(uint64_t frameID, IPC::MessageD m_pageLoadState.didDisplayOrRunInsecureContent(transaction); m_pageLoadState.commitChanges(); - m_loaderClient->didRunInsecureContentForFrame(this, frame, userData.get()); + m_loaderClient->didRunInsecureContentForFrame(*this, *frame, m_process->transformHandlesToObjects(userData.object()).get()); } -void WebPageProxy::didDetectXSSForFrame(uint64_t frameID, IPC::MessageDecoder& decoder) +void WebPageProxy::didDetectXSSForFrame(uint64_t frameID, const UserData& userData) { - RefPtr<API::Object> userData; - WebContextUserMessageDecoder messageDecoder(userData, process()); - if (!decoder.decode(messageDecoder)) - return; + PageClientProtector protector(m_pageClient); WebFrameProxy* frame = m_process->webFrame(frameID); MESSAGE_CHECK(frame); - m_loaderClient->didDetectXSSForFrame(this, frame, userData.get()); + m_loaderClient->didDetectXSSForFrame(*this, *frame, m_process->transformHandlesToObjects(userData.object()).get()); +} + +void WebPageProxy::mainFramePluginHandlesPageScaleGestureDidChange(bool mainFramePluginHandlesPageScaleGesture) +{ + m_mainFramePluginHandlesPageScaleGesture = mainFramePluginHandlesPageScaleGesture; } void WebPageProxy::frameDidBecomeFrameSet(uint64_t frameID, bool value) { + PageClientProtector protector(m_pageClient); + WebFrameProxy* frame = m_process->webFrame(frameID); MESSAGE_CHECK(frame); @@ -2425,12 +3640,9 @@ void WebPageProxy::frameDidBecomeFrameSet(uint64_t frameID, bool value) m_frameSetLargestFrame = value ? m_mainFrame : 0; } -void WebPageProxy::decidePolicyForNavigationAction(uint64_t frameID, const NavigationActionData& navigationActionData, uint64_t originatingFrameID, const WebCore::ResourceRequest& originalRequest, const ResourceRequest& request, uint64_t listenerID, IPC::MessageDecoder& decoder, bool& receivedPolicyAction, uint64_t& policyAction, uint64_t& downloadID) +void WebPageProxy::decidePolicyForNavigationAction(uint64_t frameID, const SecurityOriginData& frameSecurityOrigin, uint64_t navigationID, const NavigationActionData& navigationActionData, uint64_t originatingFrameID, const SecurityOriginData& originatingFrameSecurityOrigin, const WebCore::ResourceRequest& originalRequest, const ResourceRequest& request, uint64_t listenerID, const UserData& userData, bool& receivedPolicyAction, uint64_t& newNavigationID, uint64_t& policyAction, DownloadID& downloadID, WebsitePolicies& websitePolicies) { - RefPtr<API::Object> userData; - WebContextUserMessageDecoder messageDecoder(userData, process()); - if (!decoder.decode(messageDecoder)) - return; + PageClientProtector protector(m_pageClient); auto transaction = m_pageLoadState.transaction(); @@ -2444,15 +3656,51 @@ void WebPageProxy::decidePolicyForNavigationAction(uint64_t frameID, const Navig WebFrameProxy* originatingFrame = m_process->webFrame(originatingFrameID); - RefPtr<WebFramePolicyListenerProxy> listener = frame->setUpPolicyListenerProxy(listenerID); + Ref<WebFramePolicyListenerProxy> listener = frame->setUpPolicyListenerProxy(listenerID); + if (!navigationID && frame->isMainFrame()) { + auto navigation = m_navigationState->createLoadRequestNavigation(request); + newNavigationID = navigation->navigationID(); + listener->setNavigation(WTFMove(navigation)); + } + +#if ENABLE(CONTENT_FILTERING) + if (frame->didHandleContentFilterUnblockNavigation(request)) { + receivedPolicyAction = true; + policyAction = PolicyIgnore; + return; + } +#endif ASSERT(!m_inDecidePolicyForNavigationAction); m_inDecidePolicyForNavigationAction = true; m_syncNavigationActionPolicyActionIsValid = false; +#if ENABLE(DOWNLOAD_ATTRIBUTE) + m_syncNavigationActionHasDownloadAttribute = !navigationActionData.downloadAttribute.isNull(); +#endif + + if (m_navigationClient) { + RefPtr<API::FrameInfo> destinationFrameInfo; + RefPtr<API::FrameInfo> sourceFrameInfo; - m_policyClient->decidePolicyForNavigationAction(this, frame, navigationActionData, originatingFrame, originalRequest, request, listener.get(), userData.get()); + if (frame) + destinationFrameInfo = API::FrameInfo::create(*frame, frameSecurityOrigin.securityOrigin()); + if (originatingFrame == frame) + sourceFrameInfo = destinationFrameInfo; + else if (originatingFrame) + sourceFrameInfo = API::FrameInfo::create(*originatingFrame, originatingFrameSecurityOrigin.securityOrigin()); + + auto userInitiatedActivity = m_process->userInitiatedActivity(navigationActionData.userGestureTokenIdentifier); + bool shouldOpenAppLinks = !m_shouldSuppressAppLinksInNextNavigationPolicyDecision && (!destinationFrameInfo || destinationFrameInfo->isMainFrame()) && !hostsAreEqual(URL(ParsedURLString, m_mainFrame->url()), request.url()) && navigationActionData.navigationType != WebCore::NavigationType::BackForward; + + auto navigationAction = API::NavigationAction::create(navigationActionData, sourceFrameInfo.get(), destinationFrameInfo.get(), request, originalRequest.url(), shouldOpenAppLinks, WTFMove(userInitiatedActivity)); + + m_navigationClient->decidePolicyForNavigationAction(*this, navigationAction.get(), WTFMove(listener), m_process->transformHandlesToObjects(userData.object()).get()); + } else + m_policyClient->decidePolicyForNavigationAction(*this, frame, navigationActionData, originatingFrame, originalRequest, request, WTFMove(listener), m_process->transformHandlesToObjects(userData.object()).get()); + + m_shouldSuppressAppLinksInNextNavigationPolicyDecision = false; m_inDecidePolicyForNavigationAction = false; // Check if we received a policy decision already. If we did, we can just pass it back. @@ -2460,51 +3708,64 @@ void WebPageProxy::decidePolicyForNavigationAction(uint64_t frameID, const Navig if (m_syncNavigationActionPolicyActionIsValid) { policyAction = m_syncNavigationActionPolicyAction; downloadID = m_syncNavigationActionPolicyDownloadID; + websitePolicies = m_syncNavigationActionPolicyWebsitePolicies; } } -void WebPageProxy::decidePolicyForNewWindowAction(uint64_t frameID, const NavigationActionData& navigationActionData, const ResourceRequest& request, const String& frameName, uint64_t listenerID, IPC::MessageDecoder& decoder) +void WebPageProxy::decidePolicyForNewWindowAction(uint64_t frameID, const SecurityOriginData& frameSecurityOrigin, const NavigationActionData& navigationActionData, const ResourceRequest& request, const String& frameName, uint64_t listenerID, const UserData& userData) { - RefPtr<API::Object> userData; - WebContextUserMessageDecoder messageDecoder(userData, process()); - if (!decoder.decode(messageDecoder)) - return; + PageClientProtector protector(m_pageClient); WebFrameProxy* frame = m_process->webFrame(frameID); MESSAGE_CHECK(frame); MESSAGE_CHECK_URL(request.url()); - RefPtr<WebFramePolicyListenerProxy> listener = frame->setUpPolicyListenerProxy(listenerID); + Ref<WebFramePolicyListenerProxy> listener = frame->setUpPolicyListenerProxy(listenerID); - m_policyClient->decidePolicyForNewWindowAction(this, frame, navigationActionData.navigationType, navigationActionData.modifiers, navigationActionData.mouseButton, request, frameName, listener.get(), userData.get()); + if (m_navigationClient) { + RefPtr<API::FrameInfo> sourceFrameInfo; + if (frame) + sourceFrameInfo = API::FrameInfo::create(*frame, frameSecurityOrigin.securityOrigin()); + + auto userInitiatedActivity = m_process->userInitiatedActivity(navigationActionData.userGestureTokenIdentifier); + bool shouldOpenAppLinks = !hostsAreEqual(URL(ParsedURLString, m_mainFrame->url()), request.url()); + auto navigationAction = API::NavigationAction::create(navigationActionData, sourceFrameInfo.get(), nullptr, request, request.url(), shouldOpenAppLinks, WTFMove(userInitiatedActivity)); + + m_navigationClient->decidePolicyForNavigationAction(*this, navigationAction.get(), WTFMove(listener), m_process->transformHandlesToObjects(userData.object()).get()); + + } else + m_policyClient->decidePolicyForNewWindowAction(*this, *frame, navigationActionData, request, frameName, WTFMove(listener), m_process->transformHandlesToObjects(userData.object()).get()); } -void WebPageProxy::decidePolicyForResponse(uint64_t frameID, const ResourceResponse& response, const ResourceRequest& request, bool canShowMIMEType, uint64_t listenerID, IPC::MessageDecoder& decoder) +void WebPageProxy::decidePolicyForResponse(uint64_t frameID, const SecurityOriginData& frameSecurityOrigin, const ResourceResponse& response, const ResourceRequest& request, bool canShowMIMEType, uint64_t listenerID, const UserData& userData) { - RefPtr<API::Object> userData; - WebContextUserMessageDecoder messageDecoder(userData, process()); - if (!decoder.decode(messageDecoder)) - return; + PageClientProtector protector(m_pageClient); WebFrameProxy* frame = m_process->webFrame(frameID); MESSAGE_CHECK(frame); MESSAGE_CHECK_URL(request.url()); MESSAGE_CHECK_URL(response.url()); - RefPtr<WebFramePolicyListenerProxy> listener = frame->setUpPolicyListenerProxy(listenerID); + Ref<WebFramePolicyListenerProxy> listener = frame->setUpPolicyListenerProxy(listenerID); - m_policyClient->decidePolicyForResponse(this, frame, response, request, canShowMIMEType, listener.get(), userData.get()); + if (m_navigationClient) { + auto navigationResponse = API::NavigationResponse::create(API::FrameInfo::create(*frame, frameSecurityOrigin.securityOrigin()).get(), request, response, canShowMIMEType); + m_navigationClient->decidePolicyForNavigationResponse(*this, navigationResponse.get(), WTFMove(listener), m_process->transformHandlesToObjects(userData.object()).get()); + } else + m_policyClient->decidePolicyForResponse(*this, *frame, response, request, canShowMIMEType, WTFMove(listener), m_process->transformHandlesToObjects(userData.object()).get()); } -void WebPageProxy::decidePolicyForResponseSync(uint64_t frameID, const ResourceResponse& response, const ResourceRequest& request, bool canShowMIMEType, uint64_t listenerID, IPC::MessageDecoder& decoder, bool& receivedPolicyAction, uint64_t& policyAction, uint64_t& downloadID) +void WebPageProxy::decidePolicyForResponseSync(uint64_t frameID, const SecurityOriginData& frameSecurityOrigin, const ResourceResponse& response, const ResourceRequest& request, bool canShowMIMEType, uint64_t listenerID, const UserData& userData, bool& receivedPolicyAction, uint64_t& policyAction, DownloadID& downloadID) { + PageClientProtector protector(m_pageClient); + ASSERT(!m_inDecidePolicyForResponseSync); m_inDecidePolicyForResponseSync = true; m_decidePolicyForResponseRequest = &request; m_syncMimeTypePolicyActionIsValid = false; - decidePolicyForResponse(frameID, response, request, canShowMIMEType, listenerID, decoder); + decidePolicyForResponse(frameID, frameSecurityOrigin, response, request, canShowMIMEType, listenerID, userData); m_inDecidePolicyForResponseSync = false; m_decidePolicyForResponseRequest = 0; @@ -2517,44 +3778,118 @@ void WebPageProxy::decidePolicyForResponseSync(uint64_t frameID, const ResourceR } } -void WebPageProxy::unableToImplementPolicy(uint64_t frameID, const ResourceError& error, IPC::MessageDecoder& decoder) +void WebPageProxy::unableToImplementPolicy(uint64_t frameID, const ResourceError& error, const UserData& userData) { - RefPtr<API::Object> userData; - WebContextUserMessageDecoder messageDecoder(userData, process()); - if (!decoder.decode(messageDecoder)) - return; - + PageClientProtector protector(m_pageClient); + WebFrameProxy* frame = m_process->webFrame(frameID); MESSAGE_CHECK(frame); - m_policyClient->unableToImplementPolicy(this, frame, error, userData.get()); + m_policyClient->unableToImplementPolicy(*this, *frame, error, m_process->transformHandlesToObjects(userData.object()).get()); } // FormClient -void WebPageProxy::willSubmitForm(uint64_t frameID, uint64_t sourceFrameID, const Vector<std::pair<String, String>>& textFieldValues, uint64_t listenerID, IPC::MessageDecoder& decoder) +void WebPageProxy::willSubmitForm(uint64_t frameID, uint64_t sourceFrameID, const Vector<std::pair<String, String>>& textFieldValues, uint64_t listenerID, const UserData& userData) { - RefPtr<API::Object> userData; - WebContextUserMessageDecoder messageDecoder(userData, process()); - if (!decoder.decode(messageDecoder)) - return; - WebFrameProxy* frame = m_process->webFrame(frameID); MESSAGE_CHECK(frame); WebFrameProxy* sourceFrame = m_process->webFrame(sourceFrameID); MESSAGE_CHECK(sourceFrame); - RefPtr<WebFormSubmissionListenerProxy> listener = frame->setUpFormSubmissionListenerProxy(listenerID); - if (!m_formClient.willSubmitForm(this, frame, sourceFrame, textFieldValues, userData.get(), listener.get())) - listener->continueSubmission(); + Ref<WebFormSubmissionListenerProxy> listener = frame->setUpFormSubmissionListenerProxy(listenerID); + m_formClient->willSubmitForm(*this, *frame, *sourceFrame, textFieldValues, m_process->transformHandlesToObjects(userData.object()).get(), listener.get()); +} + +void WebPageProxy::didNavigateWithNavigationData(const WebNavigationDataStore& store, uint64_t frameID) +{ + PageClientProtector protector(m_pageClient); + + WebFrameProxy* frame = m_process->webFrame(frameID); + MESSAGE_CHECK(frame); + MESSAGE_CHECK(frame->page() == this); + + if (m_historyClient) { + if (frame->isMainFrame()) + m_historyClient->didNavigateWithNavigationData(*this, store); + } else + m_loaderClient->didNavigateWithNavigationData(*this, store, *frame); + process().processPool().historyClient().didNavigateWithNavigationData(process().processPool(), *this, store, *frame); +} + +void WebPageProxy::didPerformClientRedirect(const String& sourceURLString, const String& destinationURLString, uint64_t frameID) +{ + PageClientProtector protector(m_pageClient); + + if (sourceURLString.isEmpty() || destinationURLString.isEmpty()) + return; + + WebFrameProxy* frame = m_process->webFrame(frameID); + MESSAGE_CHECK(frame); + MESSAGE_CHECK(frame->page() == this); + + MESSAGE_CHECK_URL(sourceURLString); + MESSAGE_CHECK_URL(destinationURLString); + + if (m_historyClient) { + if (frame->isMainFrame()) + m_historyClient->didPerformClientRedirect(*this, sourceURLString, destinationURLString); + } else + m_loaderClient->didPerformClientRedirect(*this, sourceURLString, destinationURLString, *frame); + process().processPool().historyClient().didPerformClientRedirect(process().processPool(), *this, sourceURLString, destinationURLString, *frame); +} + +void WebPageProxy::didPerformServerRedirect(const String& sourceURLString, const String& destinationURLString, uint64_t frameID) +{ + PageClientProtector protector(m_pageClient); + + if (sourceURLString.isEmpty() || destinationURLString.isEmpty()) + return; + + WebFrameProxy* frame = m_process->webFrame(frameID); + MESSAGE_CHECK(frame); + MESSAGE_CHECK(frame->page() == this); + + MESSAGE_CHECK_URL(sourceURLString); + MESSAGE_CHECK_URL(destinationURLString); + + if (m_historyClient) { + if (frame->isMainFrame()) + m_historyClient->didPerformServerRedirect(*this, sourceURLString, destinationURLString); + } else + m_loaderClient->didPerformServerRedirect(*this, sourceURLString, destinationURLString, *frame); + process().processPool().historyClient().didPerformServerRedirect(process().processPool(), *this, sourceURLString, destinationURLString, *frame); +} + +void WebPageProxy::didUpdateHistoryTitle(const String& title, const String& url, uint64_t frameID) +{ + PageClientProtector protector(m_pageClient); + + WebFrameProxy* frame = m_process->webFrame(frameID); + MESSAGE_CHECK(frame); + MESSAGE_CHECK(frame->page() == this); + + MESSAGE_CHECK_URL(url); + + if (m_historyClient) { + if (frame->isMainFrame()) + m_historyClient->didUpdateHistoryTitle(*this, title, url); + } else + m_loaderClient->didUpdateHistoryTitle(*this, title, url, *frame); + process().processPool().historyClient().didUpdateHistoryTitle(process().processPool(), *this, title, url, *frame); } // UIClient -void WebPageProxy::createNewPage(const ResourceRequest& request, const WindowFeatures& windowFeatures, uint32_t opaqueModifiers, int32_t opaqueMouseButton, uint64_t& newPageID, WebPageCreationParameters& newPageParameters) +void WebPageProxy::createNewPage(uint64_t frameID, const SecurityOriginData& securityOriginData, const ResourceRequest& request, const WindowFeatures& windowFeatures, const NavigationActionData& navigationActionData, uint64_t& newPageID, WebPageCreationParameters& newPageParameters) { - RefPtr<WebPageProxy> newPage = m_uiClient.createNewPage(this, request, windowFeatures, static_cast<WebEvent::Modifiers>(opaqueModifiers), static_cast<WebMouseEvent::Button>(opaqueMouseButton)); + WebFrameProxy* frame = m_process->webFrame(frameID); + MESSAGE_CHECK(frame); + + auto mainFrameURL = m_mainFrame->url(); + + RefPtr<WebPageProxy> newPage = m_uiClient->createNewPage(this, frame, securityOriginData, request, windowFeatures, navigationActionData); if (!newPage) { newPageID = 0; return; @@ -2562,93 +3897,107 @@ void WebPageProxy::createNewPage(const ResourceRequest& request, const WindowFea newPageID = newPage->pageID(); newPageParameters = newPage->creationParameters(); - process().context().storageManager().cloneSessionStorageNamespace(m_pageID, newPage->pageID()); + + WebsiteDataStore::cloneSessionData(*this, *newPage); + newPage->m_shouldSuppressAppLinksInNextNavigationPolicyDecision = hostsAreEqual(URL(ParsedURLString, mainFrameURL), request.url()); } void WebPageProxy::showPage() { - m_uiClient.showPage(this); + m_uiClient->showPage(this); +} + +void WebPageProxy::fullscreenMayReturnToInline() +{ + m_uiClient->fullscreenMayReturnToInline(this); +} + +void WebPageProxy::didEnterFullscreen() +{ + m_uiClient->didEnterFullscreen(this); +} + +void WebPageProxy::didExitFullscreen() +{ + m_uiClient->didExitFullscreen(this); } void WebPageProxy::closePage(bool stopResponsivenessTimer) { if (stopResponsivenessTimer) - m_process->responsivenessTimer()->stop(); + m_process->responsivenessTimer().stop(); m_pageClient.clearAllEditCommands(); - m_uiClient.close(this); + m_uiClient->close(this); } -void WebPageProxy::runJavaScriptAlert(uint64_t frameID, const String& message) +void WebPageProxy::runJavaScriptAlert(uint64_t frameID, const SecurityOriginData& securityOrigin, const String& message, Ref<Messages::WebPageProxy::RunJavaScriptAlert::DelayedReply>&& reply) { WebFrameProxy* frame = m_process->webFrame(frameID); MESSAGE_CHECK(frame); // Since runJavaScriptAlert() can spin a nested run loop we need to turn off the responsiveness timer. - m_process->responsivenessTimer()->stop(); + m_process->responsivenessTimer().stop(); - m_uiClient.runJavaScriptAlert(this, message, frame); + m_uiClient->runJavaScriptAlert(this, message, frame, securityOrigin, [reply = WTFMove(reply)] { + reply->send(); + }); } -void WebPageProxy::runJavaScriptConfirm(uint64_t frameID, const String& message, bool& result) +void WebPageProxy::runJavaScriptConfirm(uint64_t frameID, const SecurityOriginData& securityOrigin, const String& message, Ref<Messages::WebPageProxy::RunJavaScriptConfirm::DelayedReply>&& reply) { WebFrameProxy* frame = m_process->webFrame(frameID); MESSAGE_CHECK(frame); // Since runJavaScriptConfirm() can spin a nested run loop we need to turn off the responsiveness timer. - m_process->responsivenessTimer()->stop(); + m_process->responsivenessTimer().stop(); - result = m_uiClient.runJavaScriptConfirm(this, message, frame); + m_uiClient->runJavaScriptConfirm(this, message, frame, securityOrigin, [reply = WTFMove(reply)](bool result) { + reply->send(result); + }); } -void WebPageProxy::runJavaScriptPrompt(uint64_t frameID, const String& message, const String& defaultValue, String& result) +void WebPageProxy::runJavaScriptPrompt(uint64_t frameID, const SecurityOriginData& securityOrigin, const String& message, const String& defaultValue, RefPtr<Messages::WebPageProxy::RunJavaScriptPrompt::DelayedReply> reply) { WebFrameProxy* frame = m_process->webFrame(frameID); MESSAGE_CHECK(frame); // Since runJavaScriptPrompt() can spin a nested run loop we need to turn off the responsiveness timer. - m_process->responsivenessTimer()->stop(); - - result = m_uiClient.runJavaScriptPrompt(this, message, defaultValue, frame); -} - -void WebPageProxy::shouldInterruptJavaScript(bool& result) -{ - // Since shouldInterruptJavaScript() can spin a nested run loop we need to turn off the responsiveness timer. - m_process->responsivenessTimer()->stop(); + m_process->responsivenessTimer().stop(); - result = m_uiClient.shouldInterruptJavaScript(this); + m_uiClient->runJavaScriptPrompt(this, message, defaultValue, frame, securityOrigin, [reply](const String& result) { reply->send(result); }); } void WebPageProxy::setStatusText(const String& text) { - m_uiClient.setStatusText(this, text); + m_uiClient->setStatusText(this, text); } -void WebPageProxy::mouseDidMoveOverElement(const WebHitTestResult::Data& hitTestResultData, uint32_t opaqueModifiers, IPC::MessageDecoder& decoder) +void WebPageProxy::mouseDidMoveOverElement(const WebHitTestResultData& hitTestResultData, uint32_t opaqueModifiers, const UserData& userData) { - RefPtr<API::Object> userData; - WebContextUserMessageDecoder messageDecoder(userData, process()); - if (!decoder.decode(messageDecoder)) - return; + m_lastMouseMoveHitTestResult = API::HitTestResult::create(hitTestResultData); WebEvent::Modifiers modifiers = static_cast<WebEvent::Modifiers>(opaqueModifiers); - m_uiClient.mouseDidMoveOverElement(this, hitTestResultData, modifiers, userData.get()); + m_uiClient->mouseDidMoveOverElement(this, hitTestResultData, modifiers, m_process->transformHandlesToObjects(userData.object()).get()); } -void WebPageProxy::connectionWillOpen(IPC::Connection* connection) +void WebPageProxy::connectionWillOpen(IPC::Connection& connection) { - ASSERT(connection == m_process->connection()); + ASSERT(&connection == m_process->connection()); - m_process->context().storageManager().setAllowedSessionStorageNamespaceConnection(m_pageID, connection); + m_webProcessLifetimeTracker.connectionWillOpen(connection); } -void WebPageProxy::connectionWillClose(IPC::Connection* connection) +void WebPageProxy::webProcessWillShutDown() { - ASSERT_UNUSED(connection, connection == m_process->connection()); + m_webProcessLifetimeTracker.webProcessWillShutDown(); +} - m_process->context().storageManager().setAllowedSessionStorageNamespaceConnection(m_pageID, 0); +void WebPageProxy::processDidFinishLaunching() +{ + ASSERT(m_process->state() == WebProcessProxy::State::Running); + finishInitializingWebPageAfterProcessLaunch(); } #if ENABLE(NETSCAPE_PLUGIN_API) @@ -2659,9 +4008,9 @@ void WebPageProxy::unavailablePluginButtonClicked(uint32_t opaquePluginUnavailab MESSAGE_CHECK_URL(frameURLString); MESSAGE_CHECK_URL(pageURLString); - RefPtr<ImmutableDictionary> pluginInformation; + RefPtr<API::Dictionary> pluginInformation; String newMimeType = mimeType; - PluginModuleInfo plugin = m_process->context().pluginInfoStore().findPlugin(newMimeType, URL(URL(), pluginURLString)); + PluginModuleInfo plugin = m_process->processPool().pluginInfoStore().findPlugin(newMimeType, URL(URL(), pluginURLString)); pluginInformation = createPluginInformationDictionary(plugin, frameURLString, mimeType, pageURLString, pluginspageAttributeURLString, pluginURLString); WKPluginUnavailabilityReason pluginUnavailabilityReason = kWKPluginUnavailabilityReasonPluginMissing; @@ -2679,105 +4028,104 @@ void WebPageProxy::unavailablePluginButtonClicked(uint32_t opaquePluginUnavailab ASSERT_NOT_REACHED(); } - m_uiClient.unavailablePluginButtonClicked(this, pluginUnavailabilityReason, pluginInformation.get()); + m_uiClient->unavailablePluginButtonClicked(this, pluginUnavailabilityReason, pluginInformation.get()); } #endif // ENABLE(NETSCAPE_PLUGIN_API) #if ENABLE(WEBGL) void WebPageProxy::webGLPolicyForURL(const String& url, uint32_t& loadPolicy) { - loadPolicy = static_cast<uint32_t>(m_loaderClient->webGLLoadPolicy(this, url)); + loadPolicy = static_cast<uint32_t>(m_loaderClient->webGLLoadPolicy(*this, url)); +} + +void WebPageProxy::resolveWebGLPolicyForURL(const String& url, uint32_t& loadPolicy) +{ + loadPolicy = static_cast<uint32_t>(m_loaderClient->resolveWebGLLoadPolicy(*this, url)); } #endif // ENABLE(WEBGL) void WebPageProxy::setToolbarsAreVisible(bool toolbarsAreVisible) { - m_uiClient.setToolbarsAreVisible(this, toolbarsAreVisible); + m_uiClient->setToolbarsAreVisible(this, toolbarsAreVisible); } void WebPageProxy::getToolbarsAreVisible(bool& toolbarsAreVisible) { - toolbarsAreVisible = m_uiClient.toolbarsAreVisible(this); + toolbarsAreVisible = m_uiClient->toolbarsAreVisible(this); } void WebPageProxy::setMenuBarIsVisible(bool menuBarIsVisible) { - m_uiClient.setMenuBarIsVisible(this, menuBarIsVisible); + m_uiClient->setMenuBarIsVisible(this, menuBarIsVisible); } void WebPageProxy::getMenuBarIsVisible(bool& menuBarIsVisible) { - menuBarIsVisible = m_uiClient.menuBarIsVisible(this); + menuBarIsVisible = m_uiClient->menuBarIsVisible(this); } void WebPageProxy::setStatusBarIsVisible(bool statusBarIsVisible) { - m_uiClient.setStatusBarIsVisible(this, statusBarIsVisible); + m_uiClient->setStatusBarIsVisible(this, statusBarIsVisible); } void WebPageProxy::getStatusBarIsVisible(bool& statusBarIsVisible) { - statusBarIsVisible = m_uiClient.statusBarIsVisible(this); + statusBarIsVisible = m_uiClient->statusBarIsVisible(this); } void WebPageProxy::setIsResizable(bool isResizable) { - m_uiClient.setIsResizable(this, isResizable); + m_uiClient->setIsResizable(this, isResizable); } void WebPageProxy::getIsResizable(bool& isResizable) { - isResizable = m_uiClient.isResizable(this); + isResizable = m_uiClient->isResizable(this); } void WebPageProxy::setWindowFrame(const FloatRect& newWindowFrame) { - m_uiClient.setWindowFrame(this, m_pageClient.convertToDeviceSpace(newWindowFrame)); + m_uiClient->setWindowFrame(this, m_pageClient.convertToDeviceSpace(newWindowFrame)); } void WebPageProxy::getWindowFrame(FloatRect& newWindowFrame) { - newWindowFrame = m_pageClient.convertToUserSpace(m_uiClient.windowFrame(this)); + newWindowFrame = m_pageClient.convertToUserSpace(m_uiClient->windowFrame(this)); } -void WebPageProxy::screenToWindow(const IntPoint& screenPoint, IntPoint& windowPoint) +void WebPageProxy::screenToRootView(const IntPoint& screenPoint, IntPoint& windowPoint) { - windowPoint = m_pageClient.screenToWindow(screenPoint); + windowPoint = m_pageClient.screenToRootView(screenPoint); } -void WebPageProxy::windowToScreen(const IntRect& viewRect, IntRect& result) +void WebPageProxy::rootViewToScreen(const IntRect& viewRect, IntRect& result) { - result = m_pageClient.windowToScreen(viewRect); + result = m_pageClient.rootViewToScreen(viewRect); } -void WebPageProxy::runBeforeUnloadConfirmPanel(const String& message, uint64_t frameID, bool& shouldClose) +#if PLATFORM(IOS) +void WebPageProxy::accessibilityScreenToRootView(const IntPoint& screenPoint, IntPoint& windowPoint) { - WebFrameProxy* frame = m_process->webFrame(frameID); - MESSAGE_CHECK(frame); - - // Since runBeforeUnloadConfirmPanel() can spin a nested run loop we need to turn off the responsiveness timer. - m_process->responsivenessTimer()->stop(); - - shouldClose = m_uiClient.runBeforeUnloadConfirmPanel(this, message, frame); + windowPoint = m_pageClient.accessibilityScreenToRootView(screenPoint); } -#if USE(TILED_BACKING_STORE) -void WebPageProxy::pageDidRequestScroll(const IntPoint& point) +void WebPageProxy::rootViewToAccessibilityScreen(const IntRect& viewRect, IntRect& result) { - m_pageClient.pageDidRequestScroll(point); + result = m_pageClient.rootViewToAccessibilityScreen(viewRect); } +#endif -void WebPageProxy::pageTransitionViewportReady() +void WebPageProxy::runBeforeUnloadConfirmPanel(const String& message, uint64_t frameID, RefPtr<Messages::WebPageProxy::RunBeforeUnloadConfirmPanel::DelayedReply> reply) { - m_pageClient.pageTransitionViewportReady(); -} + WebFrameProxy* frame = m_process->webFrame(frameID); + MESSAGE_CHECK(frame); -void WebPageProxy::didRenderFrame(const WebCore::IntSize& contentsSize, const WebCore::IntRect& coveredRect) -{ - m_pageClient.didRenderFrame(contentsSize, coveredRect); -} + // Since runBeforeUnloadConfirmPanel() can spin a nested run loop we need to turn off the responsiveness timer. + m_process->responsivenessTimer().stop(); -#endif + m_uiClient->runBeforeUnloadConfirmPanel(this, message, frame, [reply](bool result) { reply->send(result); }); +} void WebPageProxy::didChangeViewportProperties(const ViewportAttributes& attr) { @@ -2786,30 +4134,37 @@ void WebPageProxy::didChangeViewportProperties(const ViewportAttributes& attr) void WebPageProxy::pageDidScroll() { - m_uiClient.pageDidScroll(this); -#if !PLATFORM(IOS) && PLATFORM(MAC) - dismissCorrectionPanel(ReasonForDismissingAlternativeTextIgnored); + m_uiClient->pageDidScroll(this); + +#if PLATFORM(IOS) + // Do not hide the validation message if the scrolling was caused by the keyboard showing up. + if (m_isKeyboardAnimatingIn) + return; #endif + hideValidationMessage(); } -void WebPageProxy::runOpenPanel(uint64_t frameID, const FileChooserSettings& settings) +void WebPageProxy::runOpenPanel(uint64_t frameID, const SecurityOriginData& frameSecurityOrigin, const FileChooserSettings& settings) { if (m_openPanelResultListener) { m_openPanelResultListener->invalidate(); - m_openPanelResultListener = 0; + m_openPanelResultListener = nullptr; } WebFrameProxy* frame = m_process->webFrame(frameID); MESSAGE_CHECK(frame); - RefPtr<WebOpenPanelParameters> parameters = WebOpenPanelParameters::create(settings); + Ref<API::OpenPanelParameters> parameters = API::OpenPanelParameters::create(settings); m_openPanelResultListener = WebOpenPanelResultListenerProxy::create(this); // Since runOpenPanel() can spin a nested run loop we need to turn off the responsiveness timer. - m_process->responsivenessTimer()->stop(); + m_process->responsivenessTimer().stop(); - if (!m_uiClient.runOpenPanel(this, frame, parameters.get(), m_openPanelResultListener.get())) - didCancelForOpenPanel(); + + if (!m_uiClient->runOpenPanel(this, frame, frameSecurityOrigin, parameters.ptr(), m_openPanelResultListener.get())) { + if (!m_pageClient.handleRunOpenPanel(this, frame, parameters.ptr(), m_openPanelResultListener.get())) + didCancelForOpenPanel(); + } } void WebPageProxy::printFrame(uint64_t frameID) @@ -2820,7 +4175,7 @@ void WebPageProxy::printFrame(uint64_t frameID) WebFrameProxy* frame = m_process->webFrame(frameID); MESSAGE_CHECK(frame); - m_uiClient.printFrame(this, frame); + m_uiClient->printFrame(this, frame); endPrinting(); // Send a message synchronously while m_isPerformingDOMPrintOperation is still true. m_isPerformingDOMPrintOperation = false; @@ -2844,6 +4199,39 @@ void WebPageProxy::setMediaVolume(float volume) m_process->send(Messages::WebPage::SetMediaVolume(volume), m_pageID); } +void WebPageProxy::setMuted(WebCore::MediaProducer::MutedStateFlags state) +{ + if (m_mutedState == state) + return; + + m_mutedState = state; + + if (!isValid()) + return; + + m_process->send(Messages::WebPage::SetMuted(state), m_pageID); + + activityStateDidChange(ActivityState::IsAudible); +} + +#if ENABLE(MEDIA_SESSION) +void WebPageProxy::handleMediaEvent(MediaEventType eventType) +{ + if (!isValid()) + return; + + m_process->send(Messages::WebPage::HandleMediaEvent(eventType), m_pageID); +} + +void WebPageProxy::setVolumeOfMediaElement(double volume, uint64_t elementID) +{ + if (!isValid()) + return; + + m_process->send(Messages::WebPage::SetVolumeOfMediaElement(volume, elementID), m_pageID); +} +#endif + void WebPageProxy::setMayStartMediaWhenInWindow(bool mayStartMedia) { if (mayStartMedia == m_mayStartMediaWhenInWindow) @@ -2857,26 +4245,15 @@ void WebPageProxy::setMayStartMediaWhenInWindow(bool mayStartMedia) process().send(Messages::WebPage::SetMayStartMediaWhenInWindow(mayStartMedia), m_pageID); } -#if PLATFORM(EFL) || PLATFORM(GTK) void WebPageProxy::handleDownloadRequest(DownloadProxy* download) { m_pageClient.handleDownloadRequest(download); } -#endif // PLATFORM(EFL) || PLATFORM(GTK) -#if PLATFORM(EFL) || PLATFORM(IOS) void WebPageProxy::didChangeContentSize(const IntSize& size) { m_pageClient.didChangeContentSize(size); } -#endif - -#if ENABLE(TOUCH_EVENTS) -void WebPageProxy::needTouchEvents(bool needTouchEvents) -{ - m_needTouchEvents = needTouchEvents; -} -#endif #if ENABLE(INPUT_TYPE_COLOR) void WebPageProxy::showColorPicker(const WebCore::Color& initialColor, const IntRect& elementRect) @@ -2884,7 +4261,7 @@ void WebPageProxy::showColorPicker(const WebCore::Color& initialColor, const Int #if ENABLE(INPUT_TYPE_COLOR_POPOVER) // A new popover color well needs to be created (and the previous one destroyed) for // each activation of a color element. - m_colorPicker = 0; + m_colorPicker = nullptr; #endif if (!m_colorPicker) m_colorPicker = m_pageClient.createColorPicker(this, initialColor, elementRect); @@ -2918,40 +4295,80 @@ void WebPageProxy::didEndColorPicker() if (!isValid()) return; +#if ENABLE(INPUT_TYPE_COLOR) if (m_colorPicker) { m_colorPicker->invalidate(); m_colorPicker = nullptr; } +#endif m_process->send(Messages::WebPage::DidEndColorPicker(), m_pageID); } #endif -void WebPageProxy::didDraw() -{ - m_uiClient.didDraw(this); -} - // Inspector - -#if ENABLE(INSPECTOR) - -WebInspectorProxy* WebPageProxy::inspector() +WebInspectorProxy* WebPageProxy::inspector() const { if (isClosed() || !isValid()) return 0; return m_inspector.get(); } -#endif - #if ENABLE(FULLSCREEN_API) WebFullScreenManagerProxy* WebPageProxy::fullScreenManager() { return m_fullScreenManager.get(); } + +void WebPageProxy::setFullscreenClient(std::unique_ptr<API::FullscreenClient> client) +{ + m_fullscreenClient = WTFMove(client); +} +#endif + +#if (PLATFORM(IOS) && HAVE(AVKIT)) || (PLATFORM(MAC) && ENABLE(VIDEO_PRESENTATION_MODE)) +WebPlaybackSessionManagerProxy* WebPageProxy::playbackSessionManager() +{ + return m_playbackSessionManager.get(); +} + +WebVideoFullscreenManagerProxy* WebPageProxy::videoFullscreenManager() +{ + return m_videoFullscreenManager.get(); +} +#endif + +#if PLATFORM(IOS) +bool WebPageProxy::allowsMediaDocumentInlinePlayback() const +{ + return m_allowsMediaDocumentInlinePlayback; +} + +void WebPageProxy::setAllowsMediaDocumentInlinePlayback(bool allows) +{ + if (m_allowsMediaDocumentInlinePlayback == allows) + return; + m_allowsMediaDocumentInlinePlayback = allows; + + m_process->send(Messages::WebPage::SetAllowsMediaDocumentInlinePlayback(allows), m_pageID); +} #endif +void WebPageProxy::setHasHadSelectionChangesFromUserInteraction(bool hasHadUserSelectionChanges) +{ + m_hasHadSelectionChangesFromUserInteraction = hasHadUserSelectionChanges; +} + +void WebPageProxy::setNeedsHiddenContentEditableQuirk(bool needsHiddenContentEditableQuirk) +{ + m_needsHiddenContentEditableQuirk = needsHiddenContentEditableQuirk; +} + +void WebPageProxy::setNeedsPlainTextQuirk(bool needsPlainTextQuirk) +{ + m_needsPlainTextQuirk = needsPlainTextQuirk; +} + // BackForwardList void WebPageProxy::backForwardAddItem(uint64_t itemID) @@ -2987,40 +4404,10 @@ void WebPageProxy::backForwardForwardListCount(int32_t& count) count = m_backForwardList->forwardListCount(); } -void WebPageProxy::editorStateChanged(const EditorState& editorState) +void WebPageProxy::compositionWasCanceled() { -#if PLATFORM(MAC) - bool couldChangeSecureInputState = m_editorState.isInPasswordField != editorState.isInPasswordField || m_editorState.selectionIsNone; - bool closedComposition = !editorState.shouldIgnoreCompositionSelectionChange && !editorState.hasComposition && (m_editorState.hasComposition || m_temporarilyClosedComposition); - m_temporarilyClosedComposition = editorState.shouldIgnoreCompositionSelectionChange && (m_temporarilyClosedComposition || m_editorState.hasComposition) && !editorState.hasComposition; -#endif - - m_editorState = editorState; - -#if PLATFORM(MAC) - // Selection being none is a temporary state when editing. Flipping secure input state too quickly was causing trouble (not fully understood). - if (couldChangeSecureInputState && !editorState.selectionIsNone) - m_pageClient.updateSecureInputState(); - - if (editorState.shouldIgnoreCompositionSelectionChange) - return; - - if (closedComposition) - m_pageClient.notifyInputContextAboutDiscardedComposition(); - if (editorState.hasComposition) { - // Abandon the current inline input session if selection changed for any other reason but an input method changing the composition. - // FIXME: This logic should be in WebCore, no need to round-trip to UI process to cancel the composition. - cancelComposition(); - m_pageClient.notifyInputContextAboutDiscardedComposition(); - } -#if PLATFORM(IOS) - else { - // We need to notify the client on iOS to make sure the selection is redrawn. - notifyRevealedSelection(); - } -#endif -#elif PLATFORM(EFL) || PLATFORM(GTK) - m_pageClient.updateTextInputState(); +#if PLATFORM(COCOA) + m_pageClient.notifyInputContextAboutDiscardedComposition(); #endif } @@ -3030,6 +4417,13 @@ void WebPageProxy::registerEditCommandForUndo(uint64_t commandID, uint32_t editA { registerEditCommand(WebEditCommandProxy::create(commandID, static_cast<EditAction>(editAction), this), Undo); } + +void WebPageProxy::registerInsertionUndoGrouping() +{ +#if USE(INSERTION_UNDO_GROUPING) + m_pageClient.registerInsertionUndoGrouping(); +#endif +} void WebPageProxy::canUndoRedo(uint32_t action, bool& result) { @@ -3049,51 +4443,65 @@ void WebPageProxy::clearAllEditCommands() void WebPageProxy::didCountStringMatches(const String& string, uint32_t matchCount) { - m_findClient.didCountStringMatches(this, string, matchCount); + m_findClient->didCountStringMatches(this, string, matchCount); } void WebPageProxy::didGetImageForFindMatch(const ShareableBitmap::Handle& contentImageHandle, uint32_t matchIndex) { - m_findMatchesClient.didGetImageForMatchResult(this, WebImage::create(ShareableBitmap::create(contentImageHandle)).get(), matchIndex); + auto bitmap = ShareableBitmap::create(contentImageHandle); + if (!bitmap) { + ASSERT_NOT_REACHED(); + return; + } + m_findMatchesClient->didGetImageForMatchResult(this, WebImage::create(bitmap.releaseNonNull()).ptr(), matchIndex); } -void WebPageProxy::setFindIndicator(const FloatRect& selectionRectInWindowCoordinates, const Vector<FloatRect>& textRectsInSelectionRectCoordinates, float contentImageScaleFactor, const ShareableBitmap::Handle& contentImageHandle, bool fadeOut, bool animate) +void WebPageProxy::setTextIndicator(const TextIndicatorData& indicatorData, uint64_t lifetime) { - RefPtr<FindIndicator> findIndicator = FindIndicator::create(selectionRectInWindowCoordinates, textRectsInSelectionRectCoordinates, contentImageScaleFactor, contentImageHandle); - m_pageClient.setFindIndicator(findIndicator.release(), fadeOut, animate); + // FIXME: Make TextIndicatorWindow a platform-independent presentational thing ("TextIndicatorPresentation"?). +#if PLATFORM(COCOA) + m_pageClient.setTextIndicator(TextIndicator::create(indicatorData), static_cast<TextIndicatorWindowLifetime>(lifetime)); +#else + ASSERT_NOT_REACHED(); +#endif } -void WebPageProxy::didFindString(const String& string, uint32_t matchCount) +void WebPageProxy::clearTextIndicator() { - m_findClient.didFindString(this, string, matchCount); +#if PLATFORM(COCOA) + m_pageClient.clearTextIndicator(TextIndicatorWindowDismissalAnimation::FadeOut); +#else + ASSERT_NOT_REACHED(); +#endif } -void WebPageProxy::didFindStringMatches(const String& string, Vector<Vector<WebCore::IntRect>> matchRects, int32_t firstIndexAfterSelection) +void WebPageProxy::setTextIndicatorAnimationProgress(float progress) { - Vector<RefPtr<API::Object>> matches; - matches.reserveInitialCapacity(matchRects.size()); - - for (const auto& rects : matchRects) { - Vector<RefPtr<API::Object>> apiRects; - apiRects.reserveInitialCapacity(rects.size()); - - for (const auto& rect : rects) - apiRects.uncheckedAppend(API::Rect::create(toAPI(rect))); +#if PLATFORM(COCOA) + m_pageClient.setTextIndicatorAnimationProgress(progress); +#else + ASSERT_NOT_REACHED(); +#endif +} - matches.uncheckedAppend(API::Array::create(std::move(apiRects))); - } +void WebPageProxy::didFindString(const String& string, const Vector<WebCore::IntRect>& matchRects, uint32_t matchCount, int32_t matchIndex) +{ + m_findClient->didFindString(this, string, matchRects, matchCount, matchIndex); +} - m_findMatchesClient.didFindStringMatches(this, string, API::Array::create(std::move(matches)).get(), firstIndexAfterSelection); +void WebPageProxy::didFindStringMatches(const String& string, const Vector<Vector<WebCore::IntRect>>& matchRects, int32_t firstIndexAfterSelection) +{ + m_findMatchesClient->didFindStringMatches(this, string, matchRects, firstIndexAfterSelection); } void WebPageProxy::didFailToFindString(const String& string) { - m_findClient.didFailToFindString(this, string); + m_findClient->didFailToFindString(this, string); } -bool WebPageProxy::sendMessage(std::unique_ptr<IPC::MessageEncoder> encoder, unsigned messageSendFlags) +bool WebPageProxy::sendMessage(std::unique_ptr<IPC::Encoder> encoder, OptionSet<IPC::SendOption> sendOptions) { - return m_process->sendMessage(std::move(encoder), messageSendFlags); + return m_process->sendMessage(WTFMove(encoder), sendOptions); } IPC::Connection* WebPageProxy::messageSenderConnection() @@ -3123,7 +4531,7 @@ NativeWebMouseEvent* WebPageProxy::currentlyProcessedMouseDownEvent() void WebPageProxy::postMessageToInjectedBundle(const String& messageName, API::Object* messageBody) { - process().send(Messages::WebPage::PostInjectedBundleMessage(messageName, WebContextUserMessageEncoder(messageBody, process())), m_pageID); + process().send(Messages::WebPage::PostInjectedBundleMessage(messageName, UserData(process().transformObjectsToHandles(messageBody).get())), m_pageID); } #if PLATFORM(GTK) @@ -3136,36 +4544,22 @@ void WebPageProxy::failedToShowPopupMenu() void WebPageProxy::showPopupMenu(const IntRect& rect, uint64_t textDirection, const Vector<WebPopupItem>& items, int32_t selectedIndex, const PlatformPopupMenuData& data) { if (m_activePopupMenu) { -#if PLATFORM(EFL) - m_uiPopupMenuClient.hidePopupMenu(this); -#else m_activePopupMenu->hidePopupMenu(); -#endif m_activePopupMenu->invalidate(); - m_activePopupMenu = 0; + m_activePopupMenu = nullptr; } - m_activePopupMenu = m_pageClient.createPopupMenuProxy(this); + m_activePopupMenu = m_pageClient.createPopupMenuProxy(*this); if (!m_activePopupMenu) return; // Since showPopupMenu() can spin a nested run loop we need to turn off the responsiveness timer. - m_process->responsivenessTimer()->stop(); - -#if PLATFORM(EFL) - UNUSED_PARAM(data); - m_uiPopupMenuClient.showPopupMenu(this, m_activePopupMenu.get(), rect, static_cast<TextDirection>(textDirection), m_pageScaleFactor, items, selectedIndex); -#else - RefPtr<WebPopupMenuProxy> protectedActivePopupMenu = m_activePopupMenu; - - protectedActivePopupMenu->showPopupMenu(rect, static_cast<TextDirection>(textDirection), m_pageScaleFactor, items, data, selectedIndex); + m_process->responsivenessTimer().stop(); - // Since Efl doesn't use a nested mainloop to show the popup and get the answer, we need to keep the client pointer valid. - // FIXME: The above comment doesn't make any sense since this code is compiled out for EFL. - protectedActivePopupMenu->invalidate(); - protectedActivePopupMenu = 0; -#endif + // Showing a popup menu runs a nested runloop, which can handle messages that cause |this| to get closed. + Ref<WebPageProxy> protect(*this); + m_activePopupMenu->showPopupMenu(rect, static_cast<TextDirection>(textDirection), m_pageScaleFactor, items, data, selectedIndex); } void WebPageProxy::hidePopupMenu() @@ -3173,65 +4567,46 @@ void WebPageProxy::hidePopupMenu() if (!m_activePopupMenu) return; -#if PLATFORM(EFL) - m_uiPopupMenuClient.hidePopupMenu(this); -#else m_activePopupMenu->hidePopupMenu(); -#endif m_activePopupMenu->invalidate(); - m_activePopupMenu = 0; + m_activePopupMenu = nullptr; } #if ENABLE(CONTEXT_MENUS) -void WebPageProxy::showContextMenu(const IntPoint& menuLocation, const WebHitTestResult::Data& hitTestResultData, const Vector<WebContextMenuItemData>& proposedItems, IPC::MessageDecoder& decoder) +void WebPageProxy::showContextMenu(const ContextMenuContextData& contextMenuContextData, const UserData& userData) { - internalShowContextMenu(menuLocation, hitTestResultData, proposedItems, decoder); + // Showing a context menu runs a nested runloop, which can handle messages that cause |this| to get closed. + Ref<WebPageProxy> protect(*this); + + internalShowContextMenu(contextMenuContextData, userData); // No matter the result of internalShowContextMenu, always notify the WebProcess that the menu is hidden so it starts handling mouse events again. m_process->send(Messages::WebPage::ContextMenuHidden(), m_pageID); } -void WebPageProxy::internalShowContextMenu(const IntPoint& menuLocation, const WebHitTestResult::Data& hitTestResultData, const Vector<WebContextMenuItemData>& proposedItems, IPC::MessageDecoder& decoder) +void WebPageProxy::internalShowContextMenu(const ContextMenuContextData& contextMenuContextData, const UserData& userData) { - RefPtr<API::Object> userData; - WebContextUserMessageDecoder messageDecoder(userData, process()); - if (!decoder.decode(messageDecoder)) - return; - - m_activeContextMenuHitTestResultData = hitTestResultData; - - if (!m_contextMenuClient.hideContextMenu(this) && m_activeContextMenu) { - m_activeContextMenu->hideContextMenu(); - m_activeContextMenu = 0; - } + m_activeContextMenuContextData = contextMenuContextData; - m_activeContextMenu = m_pageClient.createContextMenuProxy(this); + m_activeContextMenu = m_pageClient.createContextMenuProxy(*this, contextMenuContextData, userData); if (!m_activeContextMenu) return; // Since showContextMenu() can spin a nested run loop we need to turn off the responsiveness timer. - m_process->responsivenessTimer()->stop(); - - // Give the PageContextMenuClient one last swipe at changing the menu. - Vector<WebContextMenuItemData> items; - if (!m_contextMenuClient.getContextMenuFromProposedMenu(this, proposedItems, items, hitTestResultData, userData.get())) { - if (!m_contextMenuClient.showContextMenu(this, menuLocation, proposedItems)) - m_activeContextMenu->showContextMenu(menuLocation, proposedItems); - } else if (!m_contextMenuClient.showContextMenu(this, menuLocation, items)) - m_activeContextMenu->showContextMenu(menuLocation, items); - - m_contextMenuClient.contextMenuDismissed(this); + m_process->responsivenessTimer().stop(); + + m_activeContextMenu->show(); } void WebPageProxy::contextMenuItemSelected(const WebContextMenuItemData& item) { // Application custom items don't need to round-trip through to WebCore in the WebProcess. if (item.action() >= ContextMenuItemBaseApplicationTag) { - m_contextMenuClient.customContextMenuItemSelected(this, item); + m_contextMenuClient->customContextMenuItemSelected(*this, item); return; } -#if PLATFORM(MAC) +#if PLATFORM(COCOA) if (item.action() == ContextMenuItemTagSmartCopyPaste) { setSmartInsertDeleteEnabled(!isSmartInsertDeleteEnabled()); return; @@ -3267,15 +4642,16 @@ void WebPageProxy::contextMenuItemSelected(const WebContextMenuItemData& item) } #endif if (item.action() == ContextMenuItemTagDownloadImageToDisk) { - m_process->context().download(this, URL(URL(), m_activeContextMenuHitTestResultData.absoluteImageURL)); + m_process->processPool().download(this, URL(URL(), m_activeContextMenuContextData.webHitTestResultData().absoluteImageURL)); return; } if (item.action() == ContextMenuItemTagDownloadLinkToDisk) { - m_process->context().download(this, URL(URL(), m_activeContextMenuHitTestResultData.absoluteLinkURL)); + auto& hitTestResult = m_activeContextMenuContextData.webHitTestResultData(); + m_process->processPool().download(this, URL(URL(), hitTestResult.absoluteLinkURL), hitTestResult.linkSuggestedFilename); return; } if (item.action() == ContextMenuItemTagDownloadMediaToDisk) { - m_process->context().download(this, URL(URL(), m_activeContextMenuHitTestResultData.absoluteMediaURL)); + m_process->processPool().download(this, URL(URL(), m_activeContextMenuContextData.webHitTestResultData().absoluteMediaURL)); return; } if (item.action() == ContextMenuItemTagCheckSpellingWhileTyping) { @@ -3299,14 +4675,20 @@ void WebPageProxy::contextMenuItemSelected(const WebContextMenuItemData& item) m_process->send(Messages::WebPage::DidSelectItemFromActiveContextMenu(item), m_pageID); } + +void WebPageProxy::handleContextMenuKeyEvent() +{ + m_process->send(Messages::WebPage::ContextMenuForKeyEvent(), m_pageID); +} #endif // ENABLE(CONTEXT_MENUS) -void WebPageProxy::didChooseFilesForOpenPanel(const Vector<String>& fileURLs) +#if PLATFORM(IOS) +void WebPageProxy::didChooseFilesForOpenPanelWithDisplayStringAndIcon(const Vector<String>& fileURLs, const String& displayString, const API::Data* iconData) { if (!isValid()) return; -#if ENABLE(WEB_PROCESS_SANDBOX) +#if ENABLE(SANDBOX_EXTENSIONS) // FIXME: The sandbox extensions should be sent with the DidChooseFilesForOpenPanel message. This // is gated on a way of passing SandboxExtension::Handles in a Vector. for (size_t i = 0; i < fileURLs.size(); ++i) { @@ -3316,10 +4698,38 @@ void WebPageProxy::didChooseFilesForOpenPanel(const Vector<String>& fileURLs) } #endif + m_process->send(Messages::WebPage::DidChooseFilesForOpenPanelWithDisplayStringAndIcon(fileURLs, displayString, iconData ? iconData->dataReference() : IPC::DataReference()), m_pageID); + + m_openPanelResultListener->invalidate(); + m_openPanelResultListener = nullptr; +} +#endif + +void WebPageProxy::didChooseFilesForOpenPanel(const Vector<String>& fileURLs) +{ + if (!isValid()) + return; + +#if ENABLE(SANDBOX_EXTENSIONS) + // FIXME: The sandbox extensions should be sent with the DidChooseFilesForOpenPanel message. This + // is gated on a way of passing SandboxExtension::Handles in a Vector. + for (size_t i = 0; i < fileURLs.size(); ++i) { + SandboxExtension::Handle sandboxExtensionHandle; + bool createdExtension = SandboxExtension::createHandle(fileURLs[i], SandboxExtension::ReadOnly, sandboxExtensionHandle); + if (!createdExtension) { + // This can legitimately fail if a directory containing the file is deleted after the file was chosen. + // We also have reports of cases where this likely fails for some unknown reason, <rdar://problem/10156710>. + WTFLogAlways("WebPageProxy::didChooseFilesForOpenPanel: could not create a sandbox extension for '%s'\n", fileURLs[i].utf8().data()); + continue; + } + m_process->send(Messages::WebPage::ExtendSandboxForFileFromOpenPanel(sandboxExtensionHandle), m_pageID); + } +#endif + m_process->send(Messages::WebPage::DidChooseFilesForOpenPanel(fileURLs), m_pageID); m_openPanelResultListener->invalidate(); - m_openPanelResultListener = 0; + m_openPanelResultListener = nullptr; } void WebPageProxy::didCancelForOpenPanel() @@ -3330,7 +4740,7 @@ void WebPageProxy::didCancelForOpenPanel() m_process->send(Messages::WebPage::DidCancelForOpenPanel(), m_pageID); m_openPanelResultListener->invalidate(); - m_openPanelResultListener = 0; + m_openPanelResultListener = nullptr; } void WebPageProxy::advanceToNextMisspelling(bool startBeforeSelection) @@ -3381,20 +4791,20 @@ int64_t WebPageProxy::spellDocumentTag() } #if USE(UNIFIED_TEXT_CHECKING) -void WebPageProxy::checkTextOfParagraph(const String& text, uint64_t checkingTypes, Vector<TextCheckingResult>& results) +void WebPageProxy::checkTextOfParagraph(const String& text, uint64_t checkingTypes, int32_t insertionPoint, Vector<TextCheckingResult>& results) { - results = TextChecker::checkTextOfParagraph(spellDocumentTag(), text.deprecatedCharacters(), text.length(), checkingTypes); + results = TextChecker::checkTextOfParagraph(spellDocumentTag(), text, insertionPoint, checkingTypes, m_initialCapitalizationEnabled); } #endif void WebPageProxy::checkSpellingOfString(const String& text, int32_t& misspellingLocation, int32_t& misspellingLength) { - TextChecker::checkSpellingOfString(spellDocumentTag(), text.deprecatedCharacters(), text.length(), misspellingLocation, misspellingLength); + TextChecker::checkSpellingOfString(spellDocumentTag(), text, misspellingLocation, misspellingLength); } void WebPageProxy::checkGrammarOfString(const String& text, Vector<GrammarDetail>& grammarDetails, int32_t& badGrammarLocation, int32_t& badGrammarLength) { - TextChecker::checkGrammarOfString(spellDocumentTag(), text.deprecatedCharacters(), text.length(), grammarDetails, badGrammarLocation, badGrammarLength); + TextChecker::checkGrammarOfString(spellDocumentTag(), text, grammarDetails, badGrammarLocation, badGrammarLength); } void WebPageProxy::spellingUIIsShowing(bool& isShowing) @@ -3412,9 +4822,9 @@ void WebPageProxy::updateSpellingUIWithGrammarString(const String& badGrammarPhr TextChecker::updateSpellingUIWithGrammarString(spellDocumentTag(), badGrammarPhrase, grammarDetail); } -void WebPageProxy::getGuessesForWord(const String& word, const String& context, Vector<String>& guesses) +void WebPageProxy::getGuessesForWord(const String& word, const String& context, int32_t insertionPoint, Vector<String>& guesses) { - TextChecker::getGuessesForWord(spellDocumentTag(), word, context, guesses); + TextChecker::getGuessesForWord(spellDocumentTag(), word, context, insertionPoint, guesses, m_initialCapitalizationEnabled); } void WebPageProxy::learnWord(const String& word) @@ -3433,9 +4843,9 @@ void WebPageProxy::ignoreWord(const String& word) TextChecker::ignoreWord(spellDocumentTag(), word); } -void WebPageProxy::requestCheckingOfString(uint64_t requestID, const TextCheckingRequestData& request) +void WebPageProxy::requestCheckingOfString(uint64_t requestID, const TextCheckingRequestData& request, int32_t insertionPoint) { - TextChecker::requestCheckingOfString(TextCheckerCompletion::create(requestID, request, this)); + TextChecker::requestCheckingOfString(TextCheckerCompletion::create(requestID, request, this), insertionPoint); } void WebPageProxy::didFinishCheckingText(uint64_t requestID, const Vector<WebCore::TextCheckingResult>& result) @@ -3452,14 +4862,14 @@ void WebPageProxy::didCancelCheckingText(uint64_t requestID) void WebPageProxy::setFocus(bool focused) { if (focused) - m_uiClient.focus(this); + m_uiClient->focus(this); else - m_uiClient.unfocus(this); + m_uiClient->unfocus(this); } void WebPageProxy::takeFocus(uint32_t direction) { - m_uiClient.takeFocus(this, (static_cast<FocusDirection>(direction) == FocusDirectionForward) ? kWKFocusDirectionForward : kWKFocusDirectionBackward); + m_uiClient->takeFocus(this, (static_cast<FocusDirection>(direction) == FocusDirectionForward) ? kWKFocusDirectionForward : kWKFocusDirectionBackward); } void WebPageProxy::setToolTip(const String& toolTip) @@ -3489,11 +4899,14 @@ void WebPageProxy::didReceiveEvent(uint32_t opaqueType, bool handled) switch (type) { case WebEvent::NoType: case WebEvent::MouseMove: + case WebEvent::Wheel: break; case WebEvent::MouseDown: case WebEvent::MouseUp: - case WebEvent::Wheel: + case WebEvent::MouseForceChanged: + case WebEvent::MouseForceDown: + case WebEvent::MouseForceUp: case WebEvent::KeyDown: case WebEvent::KeyUp: case WebEvent::RawKeyDown: @@ -3504,7 +4917,12 @@ void WebPageProxy::didReceiveEvent(uint32_t opaqueType, bool handled) case WebEvent::TouchEnd: case WebEvent::TouchCancel: #endif - m_process->responsivenessTimer()->stop(); +#if ENABLE(MAC_GESTURE_EVENTS) + case WebEvent::GestureStart: + case WebEvent::GestureChange: + case WebEvent::GestureEnd: +#endif + m_process->responsivenessTimer().stop(); break; } @@ -3513,29 +4931,29 @@ void WebPageProxy::didReceiveEvent(uint32_t opaqueType, bool handled) break; case WebEvent::MouseMove: m_processingMouseMoveEvent = false; - if (m_nextMouseMoveEvent) { - handleMouseEvent(*m_nextMouseMoveEvent); - m_nextMouseMoveEvent = nullptr; - } + if (m_nextMouseMoveEvent) + handleMouseEvent(*std::exchange(m_nextMouseMoveEvent, nullptr)); break; case WebEvent::MouseDown: break; case WebEvent::MouseUp: m_currentlyProcessedMouseDownEvent = nullptr; break; + case WebEvent::MouseForceChanged: + case WebEvent::MouseForceDown: + case WebEvent::MouseForceUp: + break; case WebEvent::Wheel: { MESSAGE_CHECK(!m_currentlyProcessedWheelEvents.isEmpty()); - OwnPtr<Vector<NativeWebWheelEvent>> oldestCoalescedEvent = m_currentlyProcessedWheelEvents.takeFirst(); + std::unique_ptr<Vector<NativeWebWheelEvent>> oldestCoalescedEvent = m_currentlyProcessedWheelEvents.takeFirst(); // FIXME: Dispatch additional events to the didNotHandleWheelEvent client function. if (!handled) { - if (m_uiClient.implementsDidNotHandleWheelEvent()) - m_uiClient.didNotHandleWheelEvent(this, oldestCoalescedEvent->last()); -#if PLATFORM(MAC) + if (m_uiClient->implementsDidNotHandleWheelEvent()) + m_uiClient->didNotHandleWheelEvent(this, oldestCoalescedEvent->last()); m_pageClient.wheelEventWasNotHandledByWebCore(oldestCoalescedEvent->last()); -#endif } if (!m_wheelEventQueue.isEmpty()) @@ -3547,25 +4965,55 @@ void WebPageProxy::didReceiveEvent(uint32_t opaqueType, bool handled) case WebEvent::KeyUp: case WebEvent::RawKeyDown: case WebEvent::Char: { - LOG(KeyHandling, "WebPageProxy::didReceiveEvent: %s", webKeyboardEventTypeString(type)); + LOG(KeyHandling, "WebPageProxy::didReceiveEvent: %s (queue empty %d)", webKeyboardEventTypeString(type), m_keyEventQueue.isEmpty()); MESSAGE_CHECK(!m_keyEventQueue.isEmpty()); NativeWebKeyboardEvent event = m_keyEventQueue.takeFirst(); MESSAGE_CHECK(type == event.type()); - if (!m_keyEventQueue.isEmpty()) + if (!m_keyEventQueue.isEmpty()) { + LOG(KeyHandling, " UI process: sent keyEvent from didReceiveEvent"); m_process->send(Messages::WebPage::KeyEvent(m_keyEventQueue.first()), m_pageID); + } else { + if (auto* automationSession = process().processPool().automationSession()) + automationSession->keyboardEventsFlushedForPage(*this); + } + + // The call to doneWithKeyEvent may close this WebPage. + // Protect against this being destroyed. + Ref<WebPageProxy> protect(*this); m_pageClient.doneWithKeyEvent(event, handled); if (handled) break; - if (m_uiClient.implementsDidNotHandleKeyEvent()) - m_uiClient.didNotHandleKeyEvent(this, event); + if (m_uiClient->implementsDidNotHandleKeyEvent()) + m_uiClient->didNotHandleKeyEvent(this, event); break; } -#if ENABLE(TOUCH_EVENTS) +#if ENABLE(MAC_GESTURE_EVENTS) + case WebEvent::GestureStart: + case WebEvent::GestureChange: + case WebEvent::GestureEnd: { + MESSAGE_CHECK(!m_gestureEventQueue.isEmpty()); + NativeWebGestureEvent event = m_gestureEventQueue.takeFirst(); + + MESSAGE_CHECK(type == event.type()); + + if (!handled) + m_pageClient.gestureEventWasNotHandledByWebCore(event); + break; + } + break; +#endif +#if ENABLE(IOS_TOUCH_EVENTS) + case WebEvent::TouchStart: + case WebEvent::TouchMove: + case WebEvent::TouchEnd: + case WebEvent::TouchCancel: + break; +#elif ENABLE(TOUCH_EVENTS) case WebEvent::TouchStart: case WebEvent::TouchMove: case WebEvent::TouchEnd: @@ -3588,12 +5036,12 @@ void WebPageProxy::didReceiveEvent(uint32_t opaqueType, bool handled) void WebPageProxy::stopResponsivenessTimer() { - m_process->responsivenessTimer()->stop(); + m_process->responsivenessTimer().stop(); } void WebPageProxy::voidCallback(uint64_t callbackID) { - RefPtr<VoidCallback> callback = m_voidCallbacks.take(callbackID); + auto callback = m_callbacks.take<VoidCallback>(callbackID); if (!callback) { // FIXME: Log error or assert. return; @@ -3604,18 +5052,18 @@ void WebPageProxy::voidCallback(uint64_t callbackID) void WebPageProxy::dataCallback(const IPC::DataReference& dataReference, uint64_t callbackID) { - RefPtr<DataCallback> callback = m_dataCallbacks.take(callbackID); + auto callback = m_callbacks.take<DataCallback>(callbackID); if (!callback) { // FIXME: Log error or assert. return; } - callback->performCallbackWithReturnValue(API::Data::create(dataReference.data(), dataReference.size()).get()); + callback->performCallbackWithReturnValue(API::Data::create(dataReference.data(), dataReference.size()).ptr()); } void WebPageProxy::imageCallback(const ShareableBitmap::Handle& bitmapHandle, uint64_t callbackID) { - RefPtr<ImageCallback> callback = m_imageCallbacks.take(callbackID); + auto callback = m_callbacks.take<ImageCallback>(callbackID); if (!callback) { // FIXME: Log error or assert. return; @@ -3626,7 +5074,7 @@ void WebPageProxy::imageCallback(const ShareableBitmap::Handle& bitmapHandle, ui void WebPageProxy::stringCallback(const String& resultString, uint64_t callbackID) { - RefPtr<StringCallback> callback = m_stringCallbacks.take(callbackID); + auto callback = m_callbacks.take<StringCallback>(callbackID); if (!callback) { // FIXME: Log error or assert. // this can validly happen if a load invalidated the callback, though @@ -3638,11 +5086,30 @@ void WebPageProxy::stringCallback(const String& resultString, uint64_t callbackI callback->performCallbackWithReturnValue(resultString.impl()); } -void WebPageProxy::scriptValueCallback(const IPC::DataReference& dataReference, uint64_t callbackID) +void WebPageProxy::invalidateStringCallback(uint64_t callbackID) { - RefPtr<ScriptValueCallback> callback = m_scriptValueCallbacks.take(callbackID); + auto callback = m_callbacks.take<StringCallback>(callbackID); if (!callback) { // FIXME: Log error or assert. + // this can validly happen if a load invalidated the callback, though + return; + } + + m_loadDependentStringCallbackIDs.remove(callbackID); + + callback->invalidate(); +} + +void WebPageProxy::scriptValueCallback(const IPC::DataReference& dataReference, bool hadException, const ExceptionDetails& details, uint64_t callbackID) +{ + auto callback = m_callbacks.take<ScriptValueCallback>(callbackID); + if (!callback) { + // FIXME: Log error or assert. + return; + } + + if (dataReference.isEmpty()) { + callback->performCallbackWithReturnValue(nullptr, hadException, details); return; } @@ -3650,12 +5117,12 @@ void WebPageProxy::scriptValueCallback(const IPC::DataReference& dataReference, data.reserveInitialCapacity(dataReference.size()); data.append(dataReference.data(), dataReference.size()); - callback->performCallbackWithReturnValue(data.size() ? WebSerializedScriptValue::adopt(data).get() : 0); + callback->performCallbackWithReturnValue(API::SerializedScriptValue::adopt(WTFMove(data)).ptr(), hadException, details); } void WebPageProxy::computedPagesCallback(const Vector<IntRect>& pageRects, double totalScaleFactorForPrinting, uint64_t callbackID) { - RefPtr<ComputedPagesCallback> callback = m_computedPagesCallbacks.take(callbackID); + auto callback = m_callbacks.take<ComputedPagesCallback>(callbackID); if (!callback) { // FIXME: Log error or assert. return; @@ -3666,7 +5133,7 @@ void WebPageProxy::computedPagesCallback(const Vector<IntRect>& pageRects, doubl void WebPageProxy::validateCommandCallback(const String& commandName, bool isEnabled, int state, uint64_t callbackID) { - RefPtr<ValidateCommandCallback> callback = m_validateCommandCallbacks.take(callbackID); + auto callback = m_callbacks.take<ValidateCommandCallback>(callbackID); if (!callback) { // FIXME: Log error or assert. return; @@ -3675,24 +5142,106 @@ void WebPageProxy::validateCommandCallback(const String& commandName, bool isEna callback->performCallbackWithReturnValue(commandName.impl(), isEnabled, state); } +void WebPageProxy::unsignedCallback(uint64_t result, uint64_t callbackID) +{ + auto callback = m_callbacks.take<UnsignedCallback>(callbackID); + if (!callback) { + // FIXME: Log error or assert. + // this can validly happen if a load invalidated the callback, though + return; + } + + callback->performCallbackWithReturnValue(result); +} + +void WebPageProxy::editingRangeCallback(const EditingRange& range, uint64_t callbackID) +{ + MESSAGE_CHECK(range.isValid()); + + auto callback = m_callbacks.take<EditingRangeCallback>(callbackID); + if (!callback) { + // FIXME: Log error or assert. + // this can validly happen if a load invalidated the callback, though + return; + } + + callback->performCallbackWithReturnValue(range); +} + +#if PLATFORM(COCOA) +void WebPageProxy::machSendRightCallback(const MachSendRight& sendRight, uint64_t callbackID) +{ + auto callback = m_callbacks.take<MachSendRightCallback>(callbackID); + if (!callback) + return; + + callback->performCallbackWithReturnValue(sendRight); +} +#endif + +void WebPageProxy::logDiagnosticMessage(const String& message, const String& description, WebCore::ShouldSample shouldSample) +{ + if (!DiagnosticLoggingClient::shouldLogAfterSampling(shouldSample)) + return; + + m_diagnosticLoggingClient->logDiagnosticMessage(this, message, description); +} + +void WebPageProxy::logDiagnosticMessageWithResult(const String& message, const String& description, uint32_t result, WebCore::ShouldSample shouldSample) +{ + if (!DiagnosticLoggingClient::shouldLogAfterSampling(shouldSample)) + return; + + m_diagnosticLoggingClient->logDiagnosticMessageWithResult(this, message, description, static_cast<WebCore::DiagnosticLoggingResultType>(result)); +} + +void WebPageProxy::logDiagnosticMessageWithValue(const String& message, const String& description, double value, unsigned significantFigures, ShouldSample shouldSample) +{ + if (!DiagnosticLoggingClient::shouldLogAfterSampling(shouldSample)) + return; + + m_diagnosticLoggingClient->logDiagnosticMessageWithValue(this, message, description, String::number(value, significantFigures)); +} + +void WebPageProxy::logDiagnosticMessageWithEnhancedPrivacy(const String& message, const String& description, ShouldSample shouldSample) +{ + if (!DiagnosticLoggingClient::shouldLogAfterSampling(shouldSample)) + return; + + m_diagnosticLoggingClient->logDiagnosticMessageWithEnhancedPrivacy(this, message, description); +} + +void WebPageProxy::rectForCharacterRangeCallback(const IntRect& rect, const EditingRange& actualRange, uint64_t callbackID) +{ + MESSAGE_CHECK(actualRange.isValid()); + + auto callback = m_callbacks.take<RectForCharacterRangeCallback>(callbackID); + if (!callback) { + // FIXME: Log error or assert. + // this can validly happen if a load invalidated the callback, though + return; + } + + callback->performCallbackWithReturnValue(rect, actualRange); +} + #if PLATFORM(GTK) void WebPageProxy::printFinishedCallback(const ResourceError& printError, uint64_t callbackID) { - RefPtr<PrintFinishedCallback> callback = m_printFinishedCallbacks.take(callbackID); + auto callback = m_callbacks.take<PrintFinishedCallback>(callbackID); if (!callback) { // FIXME: Log error or assert. return; } - RefPtr<API::Error> error = API::Error::create(printError); - callback->performCallbackWithReturnValue(error.get()); + callback->performCallbackWithReturnValue(API::Error::create(printError).ptr()); } #endif void WebPageProxy::focusedFrameChanged(uint64_t frameID) { if (!frameID) { - m_focusedFrame = 0; + m_focusedFrame = nullptr; return; } @@ -3705,7 +5254,7 @@ void WebPageProxy::focusedFrameChanged(uint64_t frameID) void WebPageProxy::frameSetLargestFrameChanged(uint64_t frameID) { if (!frameID) { - m_frameSetLargestFrame = 0; + m_frameSetLargestFrame = nullptr; return; } @@ -3722,53 +5271,93 @@ void WebPageProxy::processDidBecomeUnresponsive() updateBackingStoreDiscardableState(); - m_loaderClient->processDidBecomeUnresponsive(this); + if (m_navigationClient) + m_navigationClient->processDidBecomeUnresponsive(*this); + else + m_loaderClient->processDidBecomeUnresponsive(*this); } -void WebPageProxy::interactionOccurredWhileProcessUnresponsive() +void WebPageProxy::processDidBecomeResponsive() { if (!isValid()) return; + + updateBackingStoreDiscardableState(); - m_loaderClient->interactionOccurredWhileProcessUnresponsive(this); + if (m_navigationClient) + m_navigationClient->processDidBecomeResponsive(*this); + else + m_loaderClient->processDidBecomeResponsive(*this); } -void WebPageProxy::processDidBecomeResponsive() +void WebPageProxy::willChangeProcessIsResponsive() { - if (!isValid()) - return; - - updateBackingStoreDiscardableState(); + m_pageLoadState.willChangeProcessIsResponsive(); +} - m_loaderClient->processDidBecomeResponsive(this); +void WebPageProxy::didChangeProcessIsResponsive() +{ + m_pageLoadState.didChangeProcessIsResponsive(); } void WebPageProxy::processDidCrash() { ASSERT(m_isValid); + // There is a nested transaction in resetStateAfterProcessExited() that we don't want to commit before the client call. + PageLoadState::Transaction transaction = m_pageLoadState.transaction(); + resetStateAfterProcessExited(); - auto transaction = m_pageLoadState.transaction(); + navigationState().clearAllNavigations(); - m_pageLoadState.reset(transaction); + if (m_navigationClient) + m_navigationClient->processDidCrash(*this); + else + m_loaderClient->processDidCrash(*this); - m_pageClient.processDidCrash(); + if (m_controlledByAutomation) { + if (auto* automationSession = process().processPool().automationSession()) + automationSession->terminate(); + } +} + +#if PLATFORM(IOS) +void WebPageProxy::processWillBecomeSuspended() +{ + if (!isValid()) + return; + + m_hasNetworkRequestsOnSuspended = m_pageLoadState.networkRequestsInProgress(); + if (m_hasNetworkRequestsOnSuspended) + setNetworkRequestsInProgress(false); +} + +void WebPageProxy::processWillBecomeForeground() +{ + if (!isValid()) + return; - m_loaderClient->processDidCrash(this); + if (m_hasNetworkRequestsOnSuspended) { + setNetworkRequestsInProgress(true); + m_hasNetworkRequestsOnSuspended = false; + } } +#endif -void WebPageProxy::resetState() +void WebPageProxy::resetState(ResetStateReason resetStateReason) { m_mainFrame = nullptr; +#if PLATFORM(COCOA) + m_scrollingPerformanceData = nullptr; +#endif m_drawingArea = nullptr; + hideValidationMessage(); -#if ENABLE(INSPECTOR) if (m_inspector) { m_inspector->invalidate(); m_inspector = nullptr; } -#endif #if ENABLE(FULLSCREEN_API) if (m_fullScreenManager) { @@ -3786,6 +5375,10 @@ void WebPageProxy::resetState() m_openPanelResultListener = nullptr; } +#if ENABLE(TOUCH_EVENTS) + m_touchEventTracking.reset(); +#endif + #if ENABLE(INPUT_TYPE_COLOR) if (m_colorPicker) { m_colorPicker->invalidate(); @@ -3797,6 +5390,10 @@ void WebPageProxy::resetState() m_geolocationPermissionRequestManager.invalidateRequests(); #endif +#if ENABLE(MEDIA_STREAM) + m_userMediaPermissionRequestManager = nullptr; +#endif + m_notificationPermissionRequestManager.invalidateRequests(); m_toolTip = String(); @@ -3804,38 +5401,70 @@ void WebPageProxy::resetState() m_mainFrameHasHorizontalScrollbar = false; m_mainFrameHasVerticalScrollbar = false; - m_mainFrameIsPinnedToLeftSide = false; - m_mainFrameIsPinnedToRightSide = false; - m_mainFrameIsPinnedToTopSide = false; - m_mainFrameIsPinnedToBottomSide = false; + m_mainFrameIsPinnedToLeftSide = true; + m_mainFrameIsPinnedToRightSide = true; + m_mainFrameIsPinnedToTopSide = true; + m_mainFrameIsPinnedToBottomSide = true; m_visibleScrollerThumbRect = IntRect(); - invalidateCallbackMap(m_voidCallbacks); - invalidateCallbackMap(m_dataCallbacks); - invalidateCallbackMap(m_imageCallbacks); - invalidateCallbackMap(m_stringCallbacks); - m_loadDependentStringCallbackIDs.clear(); - invalidateCallbackMap(m_scriptValueCallbacks); - invalidateCallbackMap(m_computedPagesCallbacks); - invalidateCallbackMap(m_validateCommandCallbacks); +#if (PLATFORM(IOS) && HAVE(AVKIT)) || (PLATFORM(MAC) && ENABLE(VIDEO_PRESENTATION_MODE)) + if (m_playbackSessionManager) { + m_playbackSessionManager->invalidate(); + m_playbackSessionManager = nullptr; + } + if (m_videoFullscreenManager) { + m_videoFullscreenManager->invalidate(); + m_videoFullscreenManager = nullptr; + } +#endif + #if PLATFORM(IOS) - invalidateCallbackMap(m_gestureCallbacks); - invalidateCallbackMap(m_touchesCallbacks); - invalidateCallbackMap(m_autocorrectionCallbacks); - invalidateCallbackMap(m_autocorrectionContextCallbacks); + m_firstLayerTreeTransactionIdAfterDidCommitLoad = 0; + m_lastVisibleContentRectUpdate = VisibleContentRectUpdateInfo(); + m_dynamicViewportSizeUpdateWaitingForTarget = false; + m_dynamicViewportSizeUpdateWaitingForLayerTreeCommit = false; + m_dynamicViewportSizeUpdateLayerTreeTransactionID = 0; + m_layerTreeTransactionIdAtLastTouchStart = 0; + m_hasNetworkRequestsOnSuspended = false; + m_isKeyboardAnimatingIn = false; + m_isScrollingOrZooming = false; #endif -#if PLATFORM(GTK) - invalidateCallbackMap(m_printFinishedCallbacks); + +#if ENABLE(WIRELESS_PLAYBACK_TARGET) && !PLATFORM(IOS) + m_pageClient.mediaSessionManager().removeAllPlaybackTargetPickerClients(*this); +#endif + +#if ENABLE(APPLE_PAY) + m_paymentCoordinator = nullptr; #endif + CallbackBase::Error error; + switch (resetStateReason) { + case ResetStateReason::PageInvalidated: + error = CallbackBase::Error::OwnerWasInvalidated; + break; + + case ResetStateReason::WebProcessExited: + error = CallbackBase::Error::ProcessExited; + break; + } + + m_callbacks.invalidate(error); + m_loadDependentStringCallbackIDs.clear(); + Vector<WebEditCommandProxy*> editCommandVector; copyToVector(m_editCommandSet, editCommandVector); m_editCommandSet.clear(); for (size_t i = 0, size = editCommandVector.size(); i < size; ++i) editCommandVector[i]->invalidate(); - m_activePopupMenu = 0; + m_activePopupMenu = nullptr; + m_mediaState = MediaProducer::IsNotPlaying; + +#if ENABLE(POINTER_LOCK) + requestPointerUnlock(); +#endif } void WebPageProxy::resetStateAfterProcessExited() @@ -3843,18 +5472,25 @@ void WebPageProxy::resetStateAfterProcessExited() if (!isValid()) return; - m_process->removeMessageReceiver(Messages::WebPageProxy::messageReceiverName(), m_pageID); + // FIXME: It's weird that resetStateAfterProcessExited() is called even though the process is launching. + ASSERT(m_process->state() == WebProcessProxy::State::Launching || m_process->state() == WebProcessProxy::State::Terminated); + +#if PLATFORM(IOS) + m_activityToken = nullptr; +#endif + m_pageIsUserObservableCount = nullptr; + m_visiblePageToken = nullptr; m_isValid = false; m_isPageSuspended = false; - m_waitingForDidUpdateViewState = false; - if (m_mainFrame) { - m_urlAtProcessExit = m_mainFrame->url(); - m_loadStateAtProcessExit = m_mainFrame->frameLoadState().m_state; - } + m_needsToFinishInitializingWebPageAfterProcessLaunch = false; + + m_editorState = EditorState(); - resetState(); + m_pageClient.processDidExit(); + + resetState(ResetStateReason::WebProcessExited); m_pageClient.clearAllEditCommands(); m_pendingLearnOrIgnoreWordMessageCount = 0; @@ -3869,19 +5505,18 @@ void WebPageProxy::resetStateAfterProcessExited() m_processingMouseMoveEvent = false; -#if ENABLE(TOUCH_EVENTS) - m_needTouchEvents = false; +#if ENABLE(TOUCH_EVENTS) && !ENABLE(IOS_TOUCH_EVENTS) m_touchEventQueue.clear(); #endif - // FIXME: Reset m_editorState. - // FIXME: Notify input methods about abandoned composition. - m_temporarilyClosedComposition = false; - -#if !PLATFORM(IOS) && PLATFORM(MAC) - dismissCorrectionPanel(ReasonForDismissingAlternativeTextIgnored); - m_pageClient.dismissDictionaryLookupPanel(); +#if PLATFORM(MAC) + m_pageClient.dismissContentRelativeChildWindows(); #endif + + PageLoadState::Transaction transaction = m_pageLoadState.transaction(); + m_pageLoadState.reset(transaction); + + m_process->responsivenessTimer().processTerminated(); } WebPageCreationParameters WebPageProxy::creationParameters() @@ -3889,14 +5524,13 @@ WebPageCreationParameters WebPageProxy::creationParameters() WebPageCreationParameters parameters; parameters.viewSize = m_pageClient.viewSize(); - parameters.viewState = m_viewState; + parameters.activityState = m_activityState; parameters.drawingAreaType = m_drawingArea->type(); - parameters.store = m_pageGroup->preferences()->store(); + parameters.store = preferencesStore(); parameters.pageGroupData = m_pageGroup->data(); parameters.drawsBackground = m_drawsBackground; - parameters.drawsTransparentBackground = m_drawsTransparentBackground; + parameters.isEditable = m_isEditable; parameters.underlayColor = m_underlayColor; - parameters.areMemoryCacheClientCallsEnabled = m_areMemoryCacheClientCallsEnabled; parameters.useFixedLayout = m_useFixedLayout; parameters.fixedLayoutSize = m_fixedLayoutSize; parameters.suppressScrollbarAnimations = m_suppressScrollbarAnimations; @@ -3904,28 +5538,63 @@ WebPageCreationParameters WebPageProxy::creationParameters() parameters.paginationBehavesLikeColumns = m_paginationBehavesLikeColumns; parameters.pageLength = m_pageLength; parameters.gapBetweenPages = m_gapBetweenPages; + parameters.paginationLineGridEnabled = m_paginationLineGridEnabled; parameters.userAgent = userAgent(); - parameters.sessionState = SessionState(m_backForwardList->entries(), m_backForwardList->currentIndex()); - parameters.highestUsedBackForwardItemID = WebBackForwardListItem::highedUsedItemID(); - parameters.canRunBeforeUnloadConfirmPanel = m_uiClient.canRunBeforeUnloadConfirmPanel(); + parameters.itemStates = m_backForwardList->itemStates(); + parameters.sessionID = m_sessionID; + parameters.highestUsedBackForwardItemID = WebBackForwardListItem::highestUsedItemID(); + parameters.userContentControllerID = m_userContentController->identifier(); + parameters.visitedLinkTableID = m_visitedLinkStore->identifier(); + parameters.websiteDataStoreID = m_websiteDataStore->identifier(); + parameters.canRunBeforeUnloadConfirmPanel = m_uiClient->canRunBeforeUnloadConfirmPanel(); parameters.canRunModal = m_canRunModal; parameters.deviceScaleFactor = deviceScaleFactor(); + parameters.viewScaleFactor = m_viewScaleFactor; + parameters.topContentInset = m_topContentInset; parameters.mediaVolume = m_mediaVolume; + parameters.muted = m_mutedState; parameters.mayStartMediaWhenInWindow = m_mayStartMediaWhenInWindow; parameters.minimumLayoutSize = m_minimumLayoutSize; parameters.autoSizingShouldExpandToViewHeight = m_autoSizingShouldExpandToViewHeight; parameters.scrollPinningBehavior = m_scrollPinningBehavior; + if (m_scrollbarOverlayStyle) + parameters.scrollbarOverlayStyle = m_scrollbarOverlayStyle.value(); + else + parameters.scrollbarOverlayStyle = std::nullopt; parameters.backgroundExtendsBeyondPage = m_backgroundExtendsBeyondPage; parameters.layerHostingMode = m_layerHostingMode; - -#if PLATFORM(MAC) && !PLATFORM(IOS) + parameters.controlledByAutomation = m_controlledByAutomation; +#if ENABLE(REMOTE_INSPECTOR) + parameters.allowsRemoteInspection = m_allowsRemoteInspection; + parameters.remoteInspectionNameOverride = m_remoteInspectionNameOverride; +#endif +#if PLATFORM(MAC) parameters.colorSpace = m_pageClient.colorSpace(); #endif +#if PLATFORM(IOS) + parameters.screenSize = screenSize(); + parameters.availableScreenSize = availableScreenSize(); + parameters.textAutosizingWidth = textAutosizingWidth(); + parameters.mimeTypesWithCustomContentProviders = m_pageClient.mimeTypesWithCustomContentProviders(); + parameters.ignoresViewportScaleLimits = m_forceAlwaysUserScalable; +#endif + +#if PLATFORM(MAC) + parameters.appleMailPaginationQuirkEnabled = appleMailPaginationQuirkEnabled(); +#else + parameters.appleMailPaginationQuirkEnabled = false; +#endif +#if PLATFORM(COCOA) + parameters.smartInsertDeleteEnabled = m_isSmartInsertDeleteEnabled; +#endif + parameters.shouldScaleViewToFitDocument = m_shouldScaleViewToFitDocument; + parameters.userInterfaceLayoutDirection = m_pageClient.userInterfaceLayoutDirection(); + parameters.observedLayoutMilestones = m_observedLayoutMilestones; + parameters.overrideContentSecurityPolicy = m_overrideContentSecurityPolicy; return parameters; } -#if USE(ACCELERATED_COMPOSITING) void WebPageProxy::enterAcceleratedCompositingMode(const LayerTreeContext& layerTreeContext) { m_pageClient.enterAcceleratedCompositingMode(layerTreeContext); @@ -3940,21 +5609,37 @@ void WebPageProxy::updateAcceleratedCompositingMode(const LayerTreeContext& laye { m_pageClient.updateAcceleratedCompositingMode(layerTreeContext); } -#endif // USE(ACCELERATED_COMPOSITING) void WebPageProxy::backForwardClear() { m_backForwardList->clear(); } -void WebPageProxy::canAuthenticateAgainstProtectionSpaceInFrame(uint64_t frameID, const ProtectionSpace& coreProtectionSpace, bool& canAuthenticate) +#if ENABLE(GAMEPAD) + +void WebPageProxy::gamepadActivity(const Vector<GamepadData>& gamepadDatas, bool shouldMakeGamepadsVisible) { + m_process->send(Messages::WebPage::GamepadActivity(gamepadDatas, shouldMakeGamepadsVisible), m_pageID); +} + +#endif + +void WebPageProxy::canAuthenticateAgainstProtectionSpace(uint64_t loaderID, uint64_t frameID, const ProtectionSpace& coreProtectionSpace) +{ +#if USE(PROTECTION_SPACE_AUTH_CALLBACK) WebFrameProxy* frame = m_process->webFrame(frameID); MESSAGE_CHECK(frame); RefPtr<WebProtectionSpace> protectionSpace = WebProtectionSpace::create(coreProtectionSpace); - canAuthenticate = m_loaderClient->canAuthenticateAgainstProtectionSpaceInFrame(this, frame, protectionSpace.get()); + bool canAuthenticate; + if (m_navigationClient) + canAuthenticate = m_navigationClient->canAuthenticateAgainstProtectionSpace(*this, protectionSpace.get()); + else + canAuthenticate = m_loaderClient->canAuthenticateAgainstProtectionSpaceInFrame(*this, *frame, protectionSpace.get()); + + m_process->processPool().sendToNetworkingProcess(Messages::NetworkProcess::ContinueCanAuthenticateAgainstProtectionSpace(loaderID, canAuthenticate)); +#endif } void WebPageProxy::didReceiveAuthenticationChallenge(uint64_t frameID, const AuthenticationChallenge& coreChallenge, uint64_t challengeID) @@ -3970,16 +5655,19 @@ void WebPageProxy::didReceiveAuthenticationChallengeProxy(uint64_t frameID, Pass MESSAGE_CHECK(frame); RefPtr<AuthenticationChallengeProxy> authenticationChallenge = prpAuthenticationChallenge; - m_loaderClient->didReceiveAuthenticationChallengeInFrame(this, frame, authenticationChallenge.get()); + if (m_navigationClient) + m_navigationClient->didReceiveAuthenticationChallenge(*this, authenticationChallenge.get()); + else + m_loaderClient->didReceiveAuthenticationChallengeInFrame(*this, *frame, authenticationChallenge.get()); } void WebPageProxy::exceededDatabaseQuota(uint64_t frameID, const String& originIdentifier, const String& databaseName, const String& displayName, uint64_t currentQuota, uint64_t currentOriginUsage, uint64_t currentDatabaseUsage, uint64_t expectedUsage, PassRefPtr<Messages::WebPageProxy::ExceededDatabaseQuota::DelayedReply> reply) { - ExceededDatabaseQuotaRecords& records = ExceededDatabaseQuotaRecords::shared(); - OwnPtr<ExceededDatabaseQuotaRecords::Record> newRecord = records.createRecord(frameID, + ExceededDatabaseQuotaRecords& records = ExceededDatabaseQuotaRecords::singleton(); + std::unique_ptr<ExceededDatabaseQuotaRecords::Record> newRecord = records.createRecord(frameID, originIdentifier, databaseName, displayName, currentQuota, currentOriginUsage, currentDatabaseUsage, expectedUsage, reply); - records.add(newRecord.release()); + records.add(WTFMove(newRecord)); if (records.areBeingProcessed()) return; @@ -3989,27 +5677,33 @@ void WebPageProxy::exceededDatabaseQuota(uint64_t frameID, const String& originI WebFrameProxy* frame = m_process->webFrame(record->frameID); MESSAGE_CHECK(frame); - RefPtr<WebSecurityOrigin> origin = WebSecurityOrigin::createFromDatabaseIdentifier(record->originIdentifier); - - uint64_t newQuota = m_uiClient.exceededDatabaseQuota(this, frame, origin.get(), + RefPtr<API::SecurityOrigin> origin = API::SecurityOrigin::create(SecurityOriginData::fromDatabaseIdentifier(record->originIdentifier)->securityOrigin()); + auto currentReply = record->reply; + m_uiClient->exceededDatabaseQuota(this, frame, origin.get(), record->databaseName, record->displayName, record->currentQuota, - record->currentOriginUsage, record->currentDatabaseUsage, record->expectedUsage); + record->currentOriginUsage, record->currentDatabaseUsage, record->expectedUsage, + [currentReply](unsigned long long newQuota) { currentReply->send(newQuota); }); - record->reply->send(newQuota); record = records.next(); } } +void WebPageProxy::reachedApplicationCacheOriginQuota(const String& originIdentifier, uint64_t currentQuota, uint64_t totalBytesNeeded, PassRefPtr<Messages::WebPageProxy::ReachedApplicationCacheOriginQuota::DelayedReply> reply) +{ + Ref<SecurityOrigin> securityOrigin = SecurityOriginData::fromDatabaseIdentifier(originIdentifier)->securityOrigin(); + m_uiClient->reachedApplicationCacheOriginQuota(this, securityOrigin.get(), currentQuota, totalBytesNeeded, [reply](unsigned long long newQuota) { reply->send(newQuota); }); +} + void WebPageProxy::requestGeolocationPermissionForFrame(uint64_t geolocationID, uint64_t frameID, String originIdentifier) { WebFrameProxy* frame = m_process->webFrame(frameID); MESSAGE_CHECK(frame); // FIXME: Geolocation should probably be using toString() as its string representation instead of databaseIdentifier(). - RefPtr<WebSecurityOrigin> origin = WebSecurityOrigin::createFromDatabaseIdentifier(originIdentifier); + RefPtr<API::SecurityOrigin> origin = API::SecurityOrigin::create(SecurityOriginData::fromDatabaseIdentifier(originIdentifier)->securityOrigin()); RefPtr<GeolocationPermissionRequestProxy> request = m_geolocationPermissionRequestManager.createRequest(geolocationID); - if (m_uiClient.decidePolicyForGeolocationPermissionRequest(this, frame, origin.get(), request.get())) + if (m_uiClient->decidePolicyForGeolocationPermissionRequest(this, frame, origin.get(), request.get())) return; if (m_pageClient.decidePolicyForGeolocationPermissionRequest(*frame, *origin, *request)) @@ -4018,70 +5712,119 @@ void WebPageProxy::requestGeolocationPermissionForFrame(uint64_t geolocationID, request->deny(); } +#if ENABLE(MEDIA_STREAM) +UserMediaPermissionRequestManagerProxy& WebPageProxy::userMediaPermissionRequestManager() +{ + if (m_userMediaPermissionRequestManager) + return *m_userMediaPermissionRequestManager; + + m_userMediaPermissionRequestManager = std::make_unique<UserMediaPermissionRequestManagerProxy>(*this); + return *m_userMediaPermissionRequestManager; +} +#endif + +void WebPageProxy::requestUserMediaPermissionForFrame(uint64_t userMediaID, uint64_t frameID, String userMediaDocumentOriginIdentifier, String topLevelDocumentOriginIdentifier, const WebCore::MediaConstraintsData& audioConstraintsData, const WebCore::MediaConstraintsData& videoConstraintsData) +{ +#if ENABLE(MEDIA_STREAM) + MESSAGE_CHECK(m_process->webFrame(frameID)); + + userMediaPermissionRequestManager().requestUserMediaPermissionForFrame(userMediaID, frameID, userMediaDocumentOriginIdentifier, topLevelDocumentOriginIdentifier, audioConstraintsData, videoConstraintsData); +#else + UNUSED_PARAM(userMediaID); + UNUSED_PARAM(frameID); + UNUSED_PARAM(userMediaDocumentOriginIdentifier); + UNUSED_PARAM(topLevelDocumentOriginIdentifier); + UNUSED_PARAM(audioConstraintsData); + UNUSED_PARAM(videoConstraintsData); +#endif +} + +void WebPageProxy::enumerateMediaDevicesForFrame(uint64_t userMediaID, uint64_t frameID, String userMediaDocumentOriginIdentifier, String topLevelDocumentOriginIdentifier) +{ +#if ENABLE(MEDIA_STREAM) + WebFrameProxy* frame = m_process->webFrame(frameID); + MESSAGE_CHECK(frame); + + userMediaPermissionRequestManager().enumerateMediaDevicesForFrame(userMediaID, frameID, userMediaDocumentOriginIdentifier, topLevelDocumentOriginIdentifier); +#else + UNUSED_PARAM(userMediaID); + UNUSED_PARAM(frameID); + UNUSED_PARAM(userMediaDocumentOriginIdentifier); + UNUSED_PARAM(topLevelDocumentOriginIdentifier); +#endif +} + +void WebPageProxy::clearUserMediaState() +{ +#if ENABLE(MEDIA_STREAM) + userMediaPermissionRequestManager().clearCachedState(); +#endif +} + void WebPageProxy::requestNotificationPermission(uint64_t requestID, const String& originString) { if (!isRequestIDValid(requestID)) return; - RefPtr<WebSecurityOrigin> origin = WebSecurityOrigin::createFromString(originString); + RefPtr<API::SecurityOrigin> origin = API::SecurityOrigin::createFromString(originString); RefPtr<NotificationPermissionRequest> request = m_notificationPermissionRequestManager.createRequest(requestID); - if (!m_uiClient.decidePolicyForNotificationPermissionRequest(this, origin.get(), request.get())) + if (!m_uiClient->decidePolicyForNotificationPermissionRequest(this, origin.get(), request.get())) request->deny(); } void WebPageProxy::showNotification(const String& title, const String& body, const String& iconURL, const String& tag, const String& lang, const String& dir, const String& originString, uint64_t notificationID) { - m_process->context().supplement<WebNotificationManagerProxy>()->show(this, title, body, iconURL, tag, lang, dir, originString, notificationID); + m_process->processPool().supplement<WebNotificationManagerProxy>()->show(this, title, body, iconURL, tag, lang, dir, originString, notificationID); } void WebPageProxy::cancelNotification(uint64_t notificationID) { - m_process->context().supplement<WebNotificationManagerProxy>()->cancel(this, notificationID); + m_process->processPool().supplement<WebNotificationManagerProxy>()->cancel(this, notificationID); } void WebPageProxy::clearNotifications(const Vector<uint64_t>& notificationIDs) { - m_process->context().supplement<WebNotificationManagerProxy>()->clearNotifications(this, notificationIDs); + m_process->processPool().supplement<WebNotificationManagerProxy>()->clearNotifications(this, notificationIDs); } void WebPageProxy::didDestroyNotification(uint64_t notificationID) { - m_process->context().supplement<WebNotificationManagerProxy>()->didDestroyNotification(this, notificationID); + m_process->processPool().supplement<WebNotificationManagerProxy>()->didDestroyNotification(this, notificationID); } float WebPageProxy::headerHeight(WebFrameProxy* frame) { if (frame->isDisplayingPDFDocument()) return 0; - return m_uiClient.headerHeight(this, frame); + return m_uiClient->headerHeight(this, frame); } float WebPageProxy::footerHeight(WebFrameProxy* frame) { if (frame->isDisplayingPDFDocument()) return 0; - return m_uiClient.footerHeight(this, frame); + return m_uiClient->footerHeight(this, frame); } void WebPageProxy::drawHeader(WebFrameProxy* frame, const FloatRect& rect) { if (frame->isDisplayingPDFDocument()) return; - m_uiClient.drawHeader(this, frame, rect); + m_uiClient->drawHeader(this, frame, rect); } void WebPageProxy::drawFooter(WebFrameProxy* frame, const FloatRect& rect) { if (frame->isDisplayingPDFDocument()) return; - m_uiClient.drawFooter(this, frame, rect); + m_uiClient->drawFooter(this, frame, rect); } void WebPageProxy::runModal() { // Since runModal() can (and probably will) spin a nested run loop we need to turn off the responsiveness timer. - m_process->responsivenessTimer()->stop(); + m_process->responsivenessTimer().stop(); // Our Connection's run loop might have more messages waiting to be handled after this RunModal message. // To make sure they are handled inside of the the nested modal run loop we must first signal the Connection's @@ -4089,7 +5832,7 @@ void WebPageProxy::runModal() // See http://webkit.org/b/89590 for more discussion. m_process->connection()->wakeUpRunLoop(); - m_uiClient.runModal(this); + m_uiClient->runModal(this); } void WebPageProxy::notifyScrollerThumbIsVisibleInRect(const IntRect& scrollerThumb) @@ -4100,7 +5843,7 @@ void WebPageProxy::notifyScrollerThumbIsVisibleInRect(const IntRect& scrollerThu void WebPageProxy::recommendedScrollbarStyleDidChange(int32_t newStyle) { #if USE(APPKIT) - m_pageClient.recommendedScrollbarStyleDidChange(newStyle); + m_pageClient.recommendedScrollbarStyleDidChange(static_cast<WebCore::ScrollbarStyle>(newStyle)); #else UNUSED_PARAM(newStyle); #endif @@ -4118,6 +5861,8 @@ void WebPageProxy::didChangeScrollOffsetPinningForMainFrame(bool pinnedToLeftSid m_mainFrameIsPinnedToRightSide = pinnedToRightSide; m_mainFrameIsPinnedToTopSide = pinnedToTopSide; m_mainFrameIsPinnedToBottomSide = pinnedToBottomSide; + + m_uiClient->pinnedStateDidChange(*this); } void WebPageProxy::didChangePageCount(unsigned pageCount) @@ -4125,19 +5870,24 @@ void WebPageProxy::didChangePageCount(unsigned pageCount) m_pageCount = pageCount; } +void WebPageProxy::pageExtendedBackgroundColorDidChange(const Color& backgroundColor) +{ + m_pageExtendedBackgroundColor = backgroundColor; +} + #if ENABLE(NETSCAPE_PLUGIN_API) void WebPageProxy::didFailToInitializePlugin(const String& mimeType, const String& frameURLString, const String& pageURLString) { - m_loaderClient->didFailToInitializePlugin(this, createPluginInformationDictionary(mimeType, frameURLString, pageURLString).get()); + m_loaderClient->didFailToInitializePlugin(*this, createPluginInformationDictionary(mimeType, frameURLString, pageURLString).ptr()); } void WebPageProxy::didBlockInsecurePluginVersion(const String& mimeType, const String& pluginURLString, const String& frameURLString, const String& pageURLString, bool replacementObscured) { - RefPtr<ImmutableDictionary> pluginInformation; + RefPtr<API::Dictionary> pluginInformation; -#if PLATFORM(MAC) && ENABLE(NETSCAPE_PLUGIN_API) +#if PLATFORM(COCOA) && ENABLE(NETSCAPE_PLUGIN_API) String newMimeType = mimeType; - PluginModuleInfo plugin = m_process->context().pluginInfoStore().findPlugin(newMimeType, URL(URL(), pluginURLString)); + PluginModuleInfo plugin = m_process->processPool().pluginInfoStore().findPlugin(newMimeType, URL(URL(), pluginURLString)); pluginInformation = createPluginInformationDictionary(plugin, frameURLString, mimeType, pageURLString, String(), String(), replacementObscured); #else UNUSED_PARAM(mimeType); @@ -4147,7 +5897,7 @@ void WebPageProxy::didBlockInsecurePluginVersion(const String& mimeType, const S UNUSED_PARAM(replacementObscured); #endif - m_loaderClient->didBlockInsecurePluginVersion(this, pluginInformation.get()); + m_loaderClient->didBlockInsecurePluginVersion(*this, pluginInformation.get()); } #endif // ENABLE(NETSCAPE_PLUGIN_API) @@ -4156,8 +5906,19 @@ bool WebPageProxy::willHandleHorizontalScrollEvents() const return !m_canShortCircuitHorizontalWheelEvents; } +void WebPageProxy::updateWebsitePolicies(const WebsitePolicies& websitePolicies) +{ + m_process->send(Messages::WebPage::UpdateWebsitePolicies(websitePolicies), m_pageID); +} + +void WebPageProxy::didFinishLoadingDataForCustomContentProvider(const String& suggestedFilename, const IPC::DataReference& dataReference) +{ + m_pageClient.didFinishLoadingDataForCustomContentProvider(suggestedFilename, dataReference); +} + void WebPageProxy::backForwardRemovedItem(uint64_t itemID) { + m_process->removeBackForwardItem(itemID); m_process->send(Messages::WebPage::DidRemoveBackForwardItem(itemID), m_pageID); } @@ -4169,7 +5930,7 @@ void WebPageProxy::setCanRunModal(bool canRunModal) // It's only possible to change the state for a WebPage which // already qualifies for running modal child web pages, otherwise // there's no other possibility than not allowing it. - m_canRunModal = m_uiClient.canRunModal() && canRunModal; + m_canRunModal = m_uiClient->canRunModal() && canRunModal; m_process->send(Messages::WebPage::SetCanRunModal(m_canRunModal), m_pageID); } @@ -4184,7 +5945,7 @@ void WebPageProxy::beginPrinting(WebFrameProxy* frame, const PrintInfo& printInf return; m_isInPrintingMode = true; - m_process->send(Messages::WebPage::BeginPrinting(frame->frameID(), printInfo), m_pageID, m_isPerformingDOMPrintOperation ? IPC::DispatchMessageEvenWhenWaitingForSyncReply : 0); + m_process->send(Messages::WebPage::BeginPrinting(frame->frameID(), printInfo), m_pageID, printingSendOptions(m_isPerformingDOMPrintOperation)); } void WebPageProxy::endPrinting() @@ -4193,7 +5954,7 @@ void WebPageProxy::endPrinting() return; m_isInPrintingMode = false; - m_process->send(Messages::WebPage::EndPrinting(), m_pageID, m_isPerformingDOMPrintOperation ? IPC::DispatchMessageEvenWhenWaitingForSyncReply : 0); + m_process->send(Messages::WebPage::EndPrinting(), m_pageID, printingSendOptions(m_isPerformingDOMPrintOperation)); } void WebPageProxy::computePagesForPrinting(WebFrameProxy* frame, const PrintInfo& printInfo, PassRefPtr<ComputedPagesCallback> prpCallback) @@ -4205,12 +5966,12 @@ void WebPageProxy::computePagesForPrinting(WebFrameProxy* frame, const PrintInfo } uint64_t callbackID = callback->callbackID(); - m_computedPagesCallbacks.set(callbackID, callback.get()); + m_callbacks.put(callback); m_isInPrintingMode = true; - m_process->send(Messages::WebPage::ComputePagesForPrinting(frame->frameID(), printInfo, callbackID), m_pageID, m_isPerformingDOMPrintOperation ? IPC::DispatchMessageEvenWhenWaitingForSyncReply : 0); + m_process->send(Messages::WebPage::ComputePagesForPrinting(frame->frameID(), printInfo, callbackID), m_pageID, printingSendOptions(m_isPerformingDOMPrintOperation)); } -#if PLATFORM(MAC) +#if PLATFORM(COCOA) void WebPageProxy::drawRectToImage(WebFrameProxy* frame, const PrintInfo& printInfo, const IntRect& rect, const WebCore::IntSize& imageSize, PassRefPtr<ImageCallback> prpCallback) { RefPtr<ImageCallback> callback = prpCallback; @@ -4220,8 +5981,8 @@ void WebPageProxy::drawRectToImage(WebFrameProxy* frame, const PrintInfo& printI } uint64_t callbackID = callback->callbackID(); - m_imageCallbacks.set(callbackID, callback.get()); - m_process->send(Messages::WebPage::DrawRectToImage(frame->frameID(), printInfo, rect, imageSize, callbackID), m_pageID, m_isPerformingDOMPrintOperation ? IPC::DispatchMessageEvenWhenWaitingForSyncReply : 0); + m_callbacks.put(callback); + m_process->send(Messages::WebPage::DrawRectToImage(frame->frameID(), printInfo, rect, imageSize, callbackID), m_pageID, printingSendOptions(m_isPerformingDOMPrintOperation)); } void WebPageProxy::drawPagesToPDF(WebFrameProxy* frame, const PrintInfo& printInfo, uint32_t first, uint32_t count, PassRefPtr<DataCallback> prpCallback) @@ -4233,8 +5994,8 @@ void WebPageProxy::drawPagesToPDF(WebFrameProxy* frame, const PrintInfo& printIn } uint64_t callbackID = callback->callbackID(); - m_dataCallbacks.set(callbackID, callback.get()); - m_process->send(Messages::WebPage::DrawPagesToPDF(frame->frameID(), printInfo, first, count, callbackID), m_pageID, m_isPerformingDOMPrintOperation ? IPC::DispatchMessageEvenWhenWaitingForSyncReply : 0); + m_callbacks.put(callback); + m_process->send(Messages::WebPage::DrawPagesToPDF(frame->frameID(), printInfo, first, count, callbackID), m_pageID, printingSendOptions(m_isPerformingDOMPrintOperation)); } #elif PLATFORM(GTK) void WebPageProxy::drawPagesForPrinting(WebFrameProxy* frame, const PrintInfo& printInfo, PassRefPtr<PrintFinishedCallback> didPrintCallback) @@ -4246,9 +6007,9 @@ void WebPageProxy::drawPagesForPrinting(WebFrameProxy* frame, const PrintInfo& p } uint64_t callbackID = callback->callbackID(); - m_printFinishedCallbacks.set(callbackID, callback.get()); + m_callbacks.put(callback); m_isInPrintingMode = true; - m_process->send(Messages::WebPage::DrawPagesForPrinting(frame->frameID(), printInfo, callbackID), m_pageID, m_isPerformingDOMPrintOperation ? IPC::DispatchMessageEvenWhenWaitingForSyncReply : 0); + m_process->send(Messages::WebPage::DrawPagesForPrinting(frame->frameID(), printInfo, callbackID), m_pageID, printingSendOptions(m_isPerformingDOMPrintOperation)); } #endif @@ -4258,7 +6019,7 @@ void WebPageProxy::updateBackingStoreDiscardableState() bool isDiscardable; - if (!m_process->responsivenessTimer()->isResponsive()) + if (!m_process->responsivenessTimer().isResponsive()) isDiscardable = false; else isDiscardable = !m_pageClient.isViewWindowActive() || !isViewVisible(); @@ -4268,7 +6029,7 @@ void WebPageProxy::updateBackingStoreDiscardableState() void WebPageProxy::saveDataToFileInDownloadsFolder(const String& suggestedFilename, const String& mimeType, const String& originatingURLString, API::Data* data) { - m_uiClient.saveDataToFileInDownloadsFolder(this, suggestedFilename, mimeType, originatingURLString, data); + m_uiClient->saveDataToFileInDownloadsFolder(this, suggestedFilename, mimeType, originatingURLString, data); } void WebPageProxy::savePDFToFileInDownloadsFolder(const String& suggestedFilename, const String& originatingURLString, const IPC::DataReference& dataReference) @@ -4276,9 +6037,8 @@ void WebPageProxy::savePDFToFileInDownloadsFolder(const String& suggestedFilenam if (!suggestedFilename.endsWith(".pdf", false)) return; - RefPtr<API::Data> data = API::Data::create(dataReference.data(), dataReference.size()); - - saveDataToFileInDownloadsFolder(suggestedFilename, "application/pdf", originatingURLString, data.get()); + saveDataToFileInDownloadsFolder(suggestedFilename, "application/pdf", originatingURLString, + API::Data::create(dataReference.data(), dataReference.size()).ptr()); } void WebPageProxy::setMinimumLayoutSize(const IntSize& minimumLayoutSize) @@ -4291,7 +6051,7 @@ void WebPageProxy::setMinimumLayoutSize(const IntSize& minimumLayoutSize) if (!isValid()) return; - m_process->send(Messages::WebPage::SetMinimumLayoutSize(minimumLayoutSize), m_pageID, 0); + m_process->send(Messages::WebPage::SetMinimumLayoutSize(minimumLayoutSize), m_pageID); m_drawingArea->minimumLayoutSizeDidChange(); #if USE(APPKIT) @@ -4310,10 +6070,44 @@ void WebPageProxy::setAutoSizingShouldExpandToViewHeight(bool shouldExpand) if (!isValid()) return; - m_process->send(Messages::WebPage::SetAutoSizingShouldExpandToViewHeight(shouldExpand), m_pageID, 0); + m_process->send(Messages::WebPage::SetAutoSizingShouldExpandToViewHeight(shouldExpand), m_pageID); } -#if !PLATFORM(IOS) && PLATFORM(MAC) +#if USE(AUTOMATIC_TEXT_REPLACEMENT) + +void WebPageProxy::toggleSmartInsertDelete() +{ + if (TextChecker::isTestingMode()) + TextChecker::setSmartInsertDeleteEnabled(!TextChecker::isSmartInsertDeleteEnabled()); +} + +void WebPageProxy::toggleAutomaticQuoteSubstitution() +{ + if (TextChecker::isTestingMode()) + TextChecker::setAutomaticQuoteSubstitutionEnabled(!TextChecker::state().isAutomaticQuoteSubstitutionEnabled); +} + +void WebPageProxy::toggleAutomaticLinkDetection() +{ + if (TextChecker::isTestingMode()) + TextChecker::setAutomaticLinkDetectionEnabled(!TextChecker::state().isAutomaticLinkDetectionEnabled); +} + +void WebPageProxy::toggleAutomaticDashSubstitution() +{ + if (TextChecker::isTestingMode()) + TextChecker::setAutomaticDashSubstitutionEnabled(!TextChecker::state().isAutomaticDashSubstitutionEnabled); +} + +void WebPageProxy::toggleAutomaticTextReplacement() +{ + if (TextChecker::isTestingMode()) + TextChecker::setAutomaticTextReplacementEnabled(!TextChecker::state().isAutomaticTextReplacementEnabled); +} + +#endif + +#if PLATFORM(MAC) void WebPageProxy::substitutionsPanelIsShowing(bool& isShowing) { @@ -4335,15 +6129,15 @@ void WebPageProxy::dismissCorrectionPanelSoon(int32_t reason, String& result) result = m_pageClient.dismissCorrectionPanelSoon((ReasonForDismissingAlternativeText)reason); } -void WebPageProxy::recordAutocorrectionResponse(int32_t responseType, const String& replacedString, const String& replacementString) +void WebPageProxy::recordAutocorrectionResponse(int32_t response, const String& replacedString, const String& replacementString) { - m_pageClient.recordAutocorrectionResponse((AutocorrectionResponseType)responseType, replacedString, replacementString); + m_pageClient.recordAutocorrectionResponse(static_cast<AutocorrectionResponse>(response), replacedString, replacementString); } void WebPageProxy::handleAlternativeTextUIResult(const String& result) { if (!isClosed()) - m_process->send(Messages::WebPage::HandleAlternativeTextUIResult(result), m_pageID, 0); + m_process->send(Messages::WebPage::HandleAlternativeTextUIResult(result), m_pageID); } #if USE(DICTATION_ALTERNATIVES) @@ -4363,19 +6157,17 @@ void WebPageProxy::dictationAlternatives(uint64_t dictationContext, Vector<Strin } #endif -#endif // !PLATFORM(IOS) && PLATFORM(MAC) - -#if PLATFORM(MAC) -RetainPtr<CGImageRef> WebPageProxy::takeViewSnapshot() +void WebPageProxy::setEditableElementIsFocused(bool editableElementIsFocused) { - return m_pageClient.takeViewSnapshot(); + m_pageClient.setEditableElementIsFocused(editableElementIsFocused); } -#endif -#if USE(SOUP) && !ENABLE(CUSTOM_PROTOCOLS) -void WebPageProxy::didReceiveURIRequest(String uriString, uint64_t requestID) +#endif // PLATFORM(MAC) + +#if PLATFORM(COCOA) +PassRefPtr<ViewSnapshot> WebPageProxy::takeViewSnapshot() { - m_process->context().supplement<WebSoupRequestManagerProxy>()->didReceiveURIRequest(uriString, this, requestID); + return m_pageClient.takeViewSnapshot(); } #endif @@ -4406,17 +6198,6 @@ void WebPageProxy::cancelComposition() } #endif // PLATFORM(GTK) -void WebPageProxy::setMainFrameInViewSourceMode(bool mainFrameInViewSourceMode) -{ - if (m_mainFrameInViewSourceMode == mainFrameInViewSourceMode) - return; - - m_mainFrameInViewSourceMode = mainFrameInViewSourceMode; - - if (isValid()) - m_process->send(Messages::WebPage::SetMainFrameInViewSourceMode(mainFrameInViewSourceMode), m_pageID); -} - void WebPageProxy::didSaveToPageCache() { m_process->didSaveToPageCache(); @@ -4433,4 +6214,636 @@ void WebPageProxy::setScrollPinningBehavior(ScrollPinningBehavior pinning) m_process->send(Messages::WebPage::SetScrollPinningBehavior(pinning), m_pageID); } +void WebPageProxy::setOverlayScrollbarStyle(std::optional<WebCore::ScrollbarOverlayStyle> scrollbarStyle) +{ + if (!m_scrollbarOverlayStyle && !scrollbarStyle) + return; + + if ((m_scrollbarOverlayStyle && scrollbarStyle) && m_scrollbarOverlayStyle.value() == scrollbarStyle.value()) + return; + + m_scrollbarOverlayStyle = scrollbarStyle; + + std::optional<uint32_t> scrollbarStyleForMessage; + if (scrollbarStyle) + scrollbarStyleForMessage = static_cast<ScrollbarOverlayStyle>(scrollbarStyle.value()); + + if (isValid()) + m_process->send(Messages::WebPage::SetScrollbarOverlayStyle(scrollbarStyleForMessage), m_pageID); +} + +#if ENABLE(SUBTLE_CRYPTO) +void WebPageProxy::wrapCryptoKey(const Vector<uint8_t>& key, bool& succeeded, Vector<uint8_t>& wrappedKey) +{ + PageClientProtector protector(m_pageClient); + + Vector<uint8_t> masterKey; + + if (m_navigationClient) { + if (RefPtr<API::Data> keyData = m_navigationClient->webCryptoMasterKey(*this)) + masterKey = keyData->dataReference().vector(); + } else if (!getDefaultWebCryptoMasterKey(masterKey)) { + succeeded = false; + return; + } + + succeeded = wrapSerializedCryptoKey(masterKey, key, wrappedKey); +} + +void WebPageProxy::unwrapCryptoKey(const Vector<uint8_t>& wrappedKey, bool& succeeded, Vector<uint8_t>& key) +{ + PageClientProtector protector(m_pageClient); + + Vector<uint8_t> masterKey; + + if (m_navigationClient) { + if (RefPtr<API::Data> keyData = m_navigationClient->webCryptoMasterKey(*this)) + masterKey = keyData->dataReference().vector(); + } else if (!getDefaultWebCryptoMasterKey(masterKey)) { + succeeded = false; + return; + } + + succeeded = unwrapSerializedCryptoKey(masterKey, wrappedKey, key); +} +#endif + +void WebPageProxy::addMIMETypeWithCustomContentProvider(const String& mimeType) +{ + m_process->send(Messages::WebPage::AddMIMETypeWithCustomContentProvider(mimeType), m_pageID); +} + +#if PLATFORM(COCOA) + +void WebPageProxy::insertTextAsync(const String& text, const EditingRange& replacementRange, bool registerUndoGroup, EditingRangeIsRelativeTo editingRangeIsRelativeTo, bool suppressSelectionUpdate) +{ + if (!isValid()) + return; + + process().send(Messages::WebPage::InsertTextAsync(text, replacementRange, registerUndoGroup, static_cast<uint32_t>(editingRangeIsRelativeTo), suppressSelectionUpdate), m_pageID); +} + +void WebPageProxy::getMarkedRangeAsync(std::function<void (EditingRange, CallbackBase::Error)> callbackFunction) +{ + if (!isValid()) { + callbackFunction(EditingRange(), CallbackBase::Error::Unknown); + return; + } + + uint64_t callbackID = m_callbacks.put(WTFMove(callbackFunction), m_process->throttler().backgroundActivityToken()); + process().send(Messages::WebPage::GetMarkedRangeAsync(callbackID), m_pageID); +} + +void WebPageProxy::getSelectedRangeAsync(std::function<void (EditingRange, CallbackBase::Error)> callbackFunction) +{ + if (!isValid()) { + callbackFunction(EditingRange(), CallbackBase::Error::Unknown); + return; + } + + uint64_t callbackID = m_callbacks.put(WTFMove(callbackFunction), m_process->throttler().backgroundActivityToken()); + process().send(Messages::WebPage::GetSelectedRangeAsync(callbackID), m_pageID); +} + +void WebPageProxy::characterIndexForPointAsync(const WebCore::IntPoint& point, std::function<void (uint64_t, CallbackBase::Error)> callbackFunction) +{ + if (!isValid()) { + callbackFunction(0, CallbackBase::Error::Unknown); + return; + } + + uint64_t callbackID = m_callbacks.put(WTFMove(callbackFunction), m_process->throttler().backgroundActivityToken()); + process().send(Messages::WebPage::CharacterIndexForPointAsync(point, callbackID), m_pageID); +} + +void WebPageProxy::firstRectForCharacterRangeAsync(const EditingRange& range, std::function<void (const WebCore::IntRect&, const EditingRange&, CallbackBase::Error)> callbackFunction) +{ + if (!isValid()) { + callbackFunction(WebCore::IntRect(), EditingRange(), CallbackBase::Error::Unknown); + return; + } + + uint64_t callbackID = m_callbacks.put(WTFMove(callbackFunction), m_process->throttler().backgroundActivityToken()); + process().send(Messages::WebPage::FirstRectForCharacterRangeAsync(range, callbackID), m_pageID); +} + +void WebPageProxy::setCompositionAsync(const String& text, Vector<CompositionUnderline> underlines, const EditingRange& selectionRange, const EditingRange& replacementRange) +{ + if (!isValid()) { + // If this fails, we should call -discardMarkedText on input context to notify the input method. + // This will happen naturally later, as part of reloading the page. + return; + } + + process().send(Messages::WebPage::SetCompositionAsync(text, underlines, selectionRange, replacementRange), m_pageID); +} + +void WebPageProxy::confirmCompositionAsync() +{ + if (!isValid()) + return; + + process().send(Messages::WebPage::ConfirmCompositionAsync(), m_pageID); +} + +void WebPageProxy::setScrollPerformanceDataCollectionEnabled(bool enabled) +{ + if (enabled == m_scrollPerformanceDataCollectionEnabled) + return; + + m_scrollPerformanceDataCollectionEnabled = enabled; + + if (m_scrollPerformanceDataCollectionEnabled && !m_scrollingPerformanceData) + m_scrollingPerformanceData = std::make_unique<RemoteLayerTreeScrollingPerformanceData>(downcast<RemoteLayerTreeDrawingAreaProxy>(*m_drawingArea)); + else if (!m_scrollPerformanceDataCollectionEnabled) + m_scrollingPerformanceData = nullptr; +} +#endif + +void WebPageProxy::takeSnapshot(IntRect rect, IntSize bitmapSize, SnapshotOptions options, std::function<void (const ShareableBitmap::Handle&, CallbackBase::Error)> callbackFunction) +{ + if (!isValid()) { + callbackFunction(ShareableBitmap::Handle(), CallbackBase::Error::Unknown); + return; + } + + uint64_t callbackID = m_callbacks.put(WTFMove(callbackFunction), m_process->throttler().backgroundActivityToken()); + m_process->send(Messages::WebPage::TakeSnapshot(rect, bitmapSize, options, callbackID), m_pageID); +} + +void WebPageProxy::navigationGestureDidBegin() +{ + PageClientProtector protector(m_pageClient); + + m_isShowingNavigationGestureSnapshot = true; + m_pageClient.navigationGestureDidBegin(); + + if (m_navigationClient) + m_navigationClient->didBeginNavigationGesture(*this); + else + m_loaderClient->navigationGestureDidBegin(*this); +} + +void WebPageProxy::navigationGestureWillEnd(bool willNavigate, WebBackForwardListItem& item) +{ + PageClientProtector protector(m_pageClient); + + m_pageClient.navigationGestureWillEnd(willNavigate, item); + + if (m_navigationClient) + m_navigationClient->willEndNavigationGesture(*this, willNavigate, item); + else + m_loaderClient->navigationGestureWillEnd(*this, willNavigate, item); +} + +void WebPageProxy::navigationGestureDidEnd(bool willNavigate, WebBackForwardListItem& item) +{ + PageClientProtector protector(m_pageClient); + + m_pageClient.navigationGestureDidEnd(willNavigate, item); + + if (m_navigationClient) + m_navigationClient->didEndNavigationGesture(*this, willNavigate, item); + else + m_loaderClient->navigationGestureDidEnd(*this, willNavigate, item); +} + +void WebPageProxy::navigationGestureDidEnd() +{ + PageClientProtector protector(m_pageClient); + + m_pageClient.navigationGestureDidEnd(); +} + +void WebPageProxy::willRecordNavigationSnapshot(WebBackForwardListItem& item) +{ + PageClientProtector protector(m_pageClient); + + m_pageClient.willRecordNavigationSnapshot(item); +} + +void WebPageProxy::navigationGestureSnapshotWasRemoved() +{ + m_isShowingNavigationGestureSnapshot = false; + + m_pageClient.didRemoveNavigationGestureSnapshot(); + + if (m_navigationClient) + m_navigationClient->didRemoveNavigationGestureSnapshot(*this); +} + +void WebPageProxy::isPlayingMediaDidChange(MediaProducer::MediaStateFlags state, uint64_t sourceElementID) +{ +#if ENABLE(MEDIA_SESSION) + WebMediaSessionFocusManager* focusManager = process().processPool().supplement<WebMediaSessionFocusManager>(); + ASSERT(focusManager); + focusManager->updatePlaybackAttributesFromMediaState(this, sourceElementID, state); +#endif + + if (state == m_mediaState) + return; + +#if ENABLE(MEDIA_STREAM) + WebCore::MediaProducer::MediaStateFlags oldMediaStateHasActiveCapture = m_mediaState & (WebCore::MediaProducer::HasActiveAudioCaptureDevice | WebCore::MediaProducer::HasActiveVideoCaptureDevice); + WebCore::MediaProducer::MediaStateFlags newMediaStateHasActiveCapture = state & (WebCore::MediaProducer::HasActiveAudioCaptureDevice | WebCore::MediaProducer::HasActiveVideoCaptureDevice); +#endif + + MediaProducer::MediaStateFlags playingMediaMask = MediaProducer::IsPlayingAudio | MediaProducer::IsPlayingVideo; + MediaProducer::MediaStateFlags oldState = m_mediaState; + m_mediaState = state; + +#if ENABLE(MEDIA_STREAM) + if (!oldMediaStateHasActiveCapture && newMediaStateHasActiveCapture) { + m_uiClient->didBeginCaptureSession(); + userMediaPermissionRequestManager().startedCaptureSession(); + } else if (oldMediaStateHasActiveCapture && !newMediaStateHasActiveCapture) { + m_uiClient->didEndCaptureSession(); + userMediaPermissionRequestManager().endedCaptureSession(); + } +#endif + + activityStateDidChange(ActivityState::IsAudible); + + playingMediaMask |= MediaProducer::HasActiveAudioCaptureDevice | MediaProducer::HasActiveVideoCaptureDevice; + if ((oldState & playingMediaMask) != (m_mediaState & playingMediaMask)) + m_uiClient->isPlayingAudioDidChange(*this); +#if PLATFORM(MAC) + if ((oldState & MediaProducer::HasAudioOrVideo) != (m_mediaState & MediaProducer::HasAudioOrVideo)) + videoControlsManagerDidChange(); +#endif +} + +#if PLATFORM(MAC) +void WebPageProxy::videoControlsManagerDidChange() +{ + m_pageClient.videoControlsManagerDidChange(); +} + +bool WebPageProxy::hasActiveVideoForControlsManager() const +{ +#if ENABLE(VIDEO_PRESENTATION_MODE) + return m_playbackSessionManager && m_playbackSessionManager->controlsManagerInterface(); +#else + return false; +#endif +} + +void WebPageProxy::requestControlledElementID() const +{ +#if ENABLE(VIDEO_PRESENTATION_MODE) + if (m_playbackSessionManager) + m_playbackSessionManager->requestControlledElementID(); +#endif +} + +void WebPageProxy::handleControlledElementIDResponse(const String& identifier) const +{ + m_pageClient.handleControlledElementIDResponse(identifier); +} + +bool WebPageProxy::isPlayingVideoInEnhancedFullscreen() const +{ +#if ENABLE(VIDEO_PRESENTATION_MODE) + return m_videoFullscreenManager && m_videoFullscreenManager->isPlayingVideoInEnhancedFullscreen(); +#else + return false; +#endif +} +#endif + +#if PLATFORM(COCOA) +void WebPageProxy::requestActiveNowPlayingSessionInfo() +{ + m_process->send(Messages::WebPage::RequestActiveNowPlayingSessionInfo(), m_pageID); +} + +void WebPageProxy::handleActiveNowPlayingSessionInfoResponse(bool hasActiveSession, const String& title, double duration, double elapsedTime) const +{ + m_pageClient.handleActiveNowPlayingSessionInfoResponse(hasActiveSession, title, duration, elapsedTime); +} +#endif + +#if ENABLE(MEDIA_SESSION) +void WebPageProxy::hasMediaSessionWithActiveMediaElementsDidChange(bool state) +{ + m_hasMediaSessionWithActiveMediaElements = state; +} + +void WebPageProxy::mediaSessionMetadataDidChange(const WebCore::MediaSessionMetadata& metadata) +{ + Ref<WebMediaSessionMetadata> webMetadata = WebMediaSessionMetadata::create(metadata); + m_uiClient->mediaSessionMetadataDidChange(*this, webMetadata.ptr()); +} + +void WebPageProxy::focusedContentMediaElementDidChange(uint64_t elementID) +{ + WebMediaSessionFocusManager* focusManager = process().processPool().supplement<WebMediaSessionFocusManager>(); + ASSERT(focusManager); + focusManager->setFocusedMediaElement(*this, elementID); +} +#endif + +void WebPageProxy::didPlayMediaPreventedFromPlayingWithoutUserGesture() +{ + m_uiClient->didPlayMediaPreventedFromPlayingWithoutUserGesture(*this); +} + +#if PLATFORM(MAC) +void WebPageProxy::removeNavigationGestureSnapshot() +{ + m_pageClient.removeNavigationGestureSnapshot(); +} + +void WebPageProxy::performImmediateActionHitTestAtLocation(FloatPoint point) +{ + m_process->send(Messages::WebPage::PerformImmediateActionHitTestAtLocation(point), m_pageID); +} + +void WebPageProxy::immediateActionDidUpdate() +{ + m_process->send(Messages::WebPage::ImmediateActionDidUpdate(), m_pageID); +} + +void WebPageProxy::immediateActionDidCancel() +{ + m_process->send(Messages::WebPage::ImmediateActionDidCancel(), m_pageID); +} + +void WebPageProxy::immediateActionDidComplete() +{ + m_process->send(Messages::WebPage::ImmediateActionDidComplete(), m_pageID); +} + +void WebPageProxy::didPerformImmediateActionHitTest(const WebHitTestResultData& result, bool contentPreventsDefault, const UserData& userData) +{ + m_pageClient.didPerformImmediateActionHitTest(result, contentPreventsDefault, m_process->transformHandlesToObjects(userData.object()).get()); +} + +void* WebPageProxy::immediateActionAnimationControllerForHitTestResult(RefPtr<API::HitTestResult> hitTestResult, uint64_t type, RefPtr<API::Object> userData) +{ + return m_pageClient.immediateActionAnimationControllerForHitTestResult(hitTestResult, type, userData); +} + +void WebPageProxy::installActivityStateChangeCompletionHandler(void (^completionHandler)()) +{ + if (!isValid()) { + completionHandler(); + return; + } + + auto copiedCompletionHandler = Block_copy(completionHandler); + auto voidCallback = VoidCallback::create([copiedCompletionHandler] (CallbackBase::Error) { + copiedCompletionHandler(); + Block_release(copiedCompletionHandler); + }, m_process->throttler().backgroundActivityToken()); + uint64_t callbackID = m_callbacks.put(WTFMove(voidCallback)); + m_nextActivityStateChangeCallbacks.append(callbackID); +} + +void WebPageProxy::handleAcceptedCandidate(WebCore::TextCheckingResult acceptedCandidate) +{ + m_process->send(Messages::WebPage::HandleAcceptedCandidate(acceptedCandidate), m_pageID); +} + +void WebPageProxy::didHandleAcceptedCandidate() +{ + m_pageClient.didHandleAcceptedCandidate(); +} + +void WebPageProxy::setHeaderBannerHeightForTesting(int height) +{ + m_process->send(Messages::WebPage::SetHeaderBannerHeightForTesting(height), m_pageID); +} + +void WebPageProxy::setFooterBannerHeightForTesting(int height) +{ + m_process->send(Messages::WebPage::SetFooterBannerHeightForTesting(height), m_pageID); +} + +#endif + +void WebPageProxy::imageOrMediaDocumentSizeChanged(const WebCore::IntSize& newSize) +{ + m_uiClient->imageOrMediaDocumentSizeChanged(newSize); +} + +void WebPageProxy::setShouldDispatchFakeMouseMoveEvents(bool shouldDispatchFakeMouseMoveEvents) +{ + m_process->send(Messages::WebPage::SetShouldDispatchFakeMouseMoveEvents(shouldDispatchFakeMouseMoveEvents), m_pageID); +} + +void WebPageProxy::handleAutoFillButtonClick(const UserData& userData) +{ + m_uiClient->didClickAutoFillButton(*this, m_process->transformHandlesToObjects(userData.object()).get()); +} + +#if ENABLE(WIRELESS_PLAYBACK_TARGET) && !PLATFORM(IOS) +void WebPageProxy::addPlaybackTargetPickerClient(uint64_t contextId) +{ + m_pageClient.mediaSessionManager().addPlaybackTargetPickerClient(*this, contextId); +} + +void WebPageProxy::removePlaybackTargetPickerClient(uint64_t contextId) +{ + m_pageClient.mediaSessionManager().removePlaybackTargetPickerClient(*this, contextId); +} + +void WebPageProxy::showPlaybackTargetPicker(uint64_t contextId, const WebCore::FloatRect& rect, bool hasVideo) +{ + m_pageClient.mediaSessionManager().showPlaybackTargetPicker(*this, contextId, m_pageClient.rootViewToScreen(IntRect(rect)), hasVideo); +} + +void WebPageProxy::playbackTargetPickerClientStateDidChange(uint64_t contextId, WebCore::MediaProducer::MediaStateFlags state) +{ + m_pageClient.mediaSessionManager().clientStateDidChange(*this, contextId, state); +} + +void WebPageProxy::setMockMediaPlaybackTargetPickerEnabled(bool enabled) +{ + m_pageClient.mediaSessionManager().setMockMediaPlaybackTargetPickerEnabled(enabled); +} + +void WebPageProxy::setMockMediaPlaybackTargetPickerState(const String& name, WebCore::MediaPlaybackTargetContext::State state) +{ + m_pageClient.mediaSessionManager().setMockMediaPlaybackTargetPickerState(name, state); +} + +void WebPageProxy::setPlaybackTarget(uint64_t contextId, Ref<MediaPlaybackTarget>&& target) +{ + if (!isValid()) + return; + + m_process->send(Messages::WebPage::PlaybackTargetSelected(contextId, target->targetContext()), m_pageID); +} + +void WebPageProxy::externalOutputDeviceAvailableDidChange(uint64_t contextId, bool available) +{ + if (!isValid()) + return; + + m_process->send(Messages::WebPage::PlaybackTargetAvailabilityDidChange(contextId, available), m_pageID); +} + +void WebPageProxy::setShouldPlayToPlaybackTarget(uint64_t contextId, bool shouldPlay) +{ + if (!isValid()) + return; + + m_process->send(Messages::WebPage::SetShouldPlayToPlaybackTarget(contextId, shouldPlay), m_pageID); +} +#endif + +void WebPageProxy::didChangeBackgroundColor() +{ + m_pageClient.didChangeBackgroundColor(); +} + +void WebPageProxy::clearWheelEventTestTrigger() +{ + if (!isValid()) + return; + + m_process->send(Messages::WebPage::ClearWheelEventTestTrigger(), m_pageID); +} + +void WebPageProxy::callAfterNextPresentationUpdate(std::function<void (CallbackBase::Error)> callback) +{ + if (!isValid() || !m_drawingArea) { + callback(CallbackBase::Error::OwnerWasInvalidated); + return; + } + + m_drawingArea->dispatchAfterEnsuringDrawing(callback); +} + +void WebPageProxy::setShouldScaleViewToFitDocument(bool shouldScaleViewToFitDocument) +{ + if (m_shouldScaleViewToFitDocument == shouldScaleViewToFitDocument) + return; + + m_shouldScaleViewToFitDocument = shouldScaleViewToFitDocument; + + if (!isValid()) + return; + + m_process->send(Messages::WebPage::SetShouldScaleViewToFitDocument(shouldScaleViewToFitDocument), m_pageID); +} + +void WebPageProxy::didRestoreScrollPosition() +{ + m_pageClient.didRestoreScrollPosition(); +} + +void WebPageProxy::getLoadDecisionForIcon(const WebCore::LinkIcon& icon, uint64_t loadIdentifier) +{ + if (!m_iconLoadingClient) + return; + + m_iconLoadingClient->getLoadDecisionForIcon(icon, [this, protectedThis = RefPtr<WebPageProxy>(this), loadIdentifier](std::function<void (API::Data*, CallbackBase::Error)> callbackFunction) { + if (!isValid()) { + if (callbackFunction) + callbackFunction(nullptr, CallbackBase::Error::Unknown); + return; + } + + bool decision = (bool)callbackFunction; + uint64_t newCallbackIdentifier = decision ? m_callbacks.put(WTFMove(callbackFunction), m_process->throttler().backgroundActivityToken()) : 0; + + m_process->send(Messages::WebPage::DidGetLoadDecisionForIcon(decision, loadIdentifier, newCallbackIdentifier), m_pageID); + }); +} + +void WebPageProxy::finishedLoadingIcon(uint64_t callbackIdentifier, const IPC::DataReference& data) +{ + dataCallback(data, callbackIdentifier); +} + +void WebPageProxy::setResourceCachingDisabled(bool disabled) +{ + if (m_isResourceCachingDisabled == disabled) + return; + + m_isResourceCachingDisabled = disabled; + + if (!isValid()) + return; + + m_process->send(Messages::WebPage::SetResourceCachingDisabled(disabled), m_pageID); +} + +WebCore::UserInterfaceLayoutDirection WebPageProxy::userInterfaceLayoutDirection() +{ + return m_pageClient.userInterfaceLayoutDirection(); +} + +void WebPageProxy::setUserInterfaceLayoutDirection(WebCore::UserInterfaceLayoutDirection userInterfaceLayoutDirection) +{ + if (!isValid()) + return; + + m_process->send(Messages::WebPage::SetUserInterfaceLayoutDirection(static_cast<uint32_t>(userInterfaceLayoutDirection)), m_pageID); +} + +void WebPageProxy::hideValidationMessage() +{ +#if PLATFORM(COCOA) + m_validationBubble = nullptr; +#endif +} + +#if ENABLE(POINTER_LOCK) +void WebPageProxy::requestPointerLock() +{ + ASSERT(!m_isPointerLockPending); + ASSERT(!m_isPointerLocked); + m_isPointerLockPending = true; + + if (!isViewVisible() || !(m_activityState & ActivityState::IsFocused)) { + didDenyPointerLock(); + return; + } + m_uiClient->requestPointerLock(this); +} + +void WebPageProxy::didAllowPointerLock() +{ + ASSERT(m_isPointerLockPending && !m_isPointerLocked); + m_isPointerLocked = true; + m_isPointerLockPending = false; +#if PLATFORM(MAC) + CGDisplayHideCursor(CGMainDisplayID()); + CGAssociateMouseAndMouseCursorPosition(false); +#endif + m_process->send(Messages::WebPage::DidAcquirePointerLock(), m_pageID); +} + +void WebPageProxy::didDenyPointerLock() +{ + ASSERT(m_isPointerLockPending && !m_isPointerLocked); + m_isPointerLockPending = false; + m_process->send(Messages::WebPage::DidNotAcquirePointerLock(), m_pageID); +} + +void WebPageProxy::requestPointerUnlock() +{ + if (m_isPointerLocked) { +#if PLATFORM(MAC) + CGAssociateMouseAndMouseCursorPosition(true); + CGDisplayShowCursor(CGMainDisplayID()); +#endif + m_uiClient->didLosePointerLock(this); + m_process->send(Messages::WebPage::DidLosePointerLock(), m_pageID); + } + + if (m_isPointerLockPending) { + m_uiClient->didLosePointerLock(this); + m_process->send(Messages::WebPage::DidNotAcquirePointerLock(), m_pageID); + } + + m_isPointerLocked = false; + m_isPointerLockPending = false; +} +#endif + + } // namespace WebKit |